blob: 218503a416b7c6ed8b923d8c35a0d22e4d595ebc [file] [log] [blame]
Scott James Remnant13ffffe2006-08-31 04:33:39 +01001/* upstart
2 *
Scott James Remnantc5d3e1b2009-02-20 22:22:48 +00003 * Copyright © 2009 Canonical Ltd.
Scott James Remnant7d5b2ea2009-05-22 15:20:12 +02004 * Author: Scott James Remnant <scott@netsplit.com>.
Scott James Remnant13ffffe2006-08-31 04:33:39 +01005 *
Scott James Remnant0c0c5a52009-06-23 10:29:35 +01006 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2, as
Scott James Remnant75123022009-05-22 13:27:56 +02008 * published by the Free Software Foundation.
Scott James Remnant13ffffe2006-08-31 04:33:39 +01009 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
Scott James Remnant0c0c5a52009-06-23 10:29:35 +010015 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Scott James Remnant13ffffe2006-08-31 04:33:39 +010018 */
19
20#ifdef HAVE_CONFIG_H
21# include <config.h>
22#endif /* HAVE_CONFIG_H */
23
24
Scott James Remnant3aac7132009-07-08 19:02:56 +010025#include <sys/types.h>
26
Scott James Remnant13ffffe2006-08-31 04:33:39 +010027#include <stdio.h>
Scott James Remnant3aac7132009-07-08 19:02:56 +010028#include <signal.h>
Scott James Remnant13ffffe2006-08-31 04:33:39 +010029#include <stdlib.h>
30#include <string.h>
31#include <unistd.h>
32
33#include <nih/macros.h>
Scott James Remnantda100272007-01-06 20:24:18 +000034#include <nih/alloc.h>
Scott James Remnant13ffffe2006-08-31 04:33:39 +010035#include <nih/string.h>
36#include <nih/main.h>
37#include <nih/option.h>
38#include <nih/logging.h>
39#include <nih/error.h>
40
Scott James Remnant3aac7132009-07-08 19:02:56 +010041#include "sysv.h"
Scott James Remnant13ffffe2006-08-31 04:33:39 +010042
43
Scott James Remnant3aac7132009-07-08 19:02:56 +010044/* Prototypes for option functions */
45int env_option (NihOption *option, const char *arg);
46
47
48/**
49 * extra_env:
50 *
51 * Extra environment variables to append to the runlevel event.
52 **/
53char **extra_env = NULL;
54
55
56/**
57 * env_option:
58 * @option: NihOption invoked,
59 * @arg: argument to parse.
60 *
61 * This option setter is used to append @arg to the list of environment
62 * variables pointed to by the value member of option, which must be a
63 * pointer to a char **.
64 *
65 * The arg_name member of @option must not be NULL.
66 *
67 * Returns: zero on success, non-zero on error.
68 **/
69int
70env_option (NihOption *option,
71 const char *arg)
72{
73 char ***value;
74
75 nih_assert (option != NULL);
76 nih_assert (option->value != NULL);
77 nih_assert (arg != NULL);
78
79 value = (char ***)option->value;
80
81 NIH_MUST (nih_str_array_add (value, NULL, NULL, arg));
82
83 return 0;
84}
85
86
87#ifndef TEST
Scott James Remnant13ffffe2006-08-31 04:33:39 +010088/**
89 * options:
90 *
91 * Command-line options accepted.
92 **/
93static NihOption options[] = {
Scott James Remnant3aac7132009-07-08 19:02:56 +010094 { 'e', NULL, N_("set environment variable in the runlevel event"),
95 NULL, "KEY=VALUE", &extra_env, env_option },
Scott James Remnant13ffffe2006-08-31 04:33:39 +010096
Scott James Remnantc2ebba92009-07-08 22:43:49 +010097 /* Compatibility options, all ignored */
98 { 't', NULL, NULL, NULL, "SECONDS", NULL, NULL },
99
Scott James Remnant13ffffe2006-08-31 04:33:39 +0100100 NIH_OPTION_LAST
101};
102
103
104int
105main (int argc,
106 char *argv[])
107{
Scott James Remnant3aac7132009-07-08 19:02:56 +0100108 char **args;
109 int runlevel;
110 int ret;
Scott James Remnant13ffffe2006-08-31 04:33:39 +0100111
112 nih_main_init (argv[0]);
Scott James Remnant1ee0f482006-10-11 17:40:41 +0100113
Scott James Remnant17fec6e2006-09-09 05:05:42 +0100114 nih_option_set_usage ("RUNLEVEL");
Scott James Remnant4a5cd212006-10-13 12:59:15 +0100115 nih_option_set_synopsis (_("Change runlevel."));
Scott James Remnant462734c2006-10-13 13:36:00 +0100116 nih_option_set_help (
Scott James Remnant3aac7132009-07-08 19:02:56 +0100117 _("RUNLEVEL should be one of 0123456sS, where s and S are "
118 "considered identical.\n"
119 "\n"
120 "RUNLEVEL may also be Q or q to instruct the init daemon "
121 "to reload its configuration, this is rarely necessary "
122 "since the daemon watches its configuration for changes.\n"
123 "\n"
124 "RUNLEVEL may be U or u to instruct the init daemon to "
125 "re-execute itself, this is not recommended since Upstart "
126 "does not currently preserve its state.\n"));
Scott James Remnant13ffffe2006-08-31 04:33:39 +0100127
128 args = nih_option_parser (NULL, argc, argv, options, FALSE);
129 if (! args)
130 exit (1);
131
132 /* First argument must be a single character we know */
Scott James Remnant98af00b2009-07-09 00:22:25 +0100133 if (! args[0]) {
134 fprintf (stderr, _("%s: missing runlevel\n"), program_name);
135 nih_main_suggest_help ();
136 exit (1);
137 }
138 if ((! strchr ("0123456SsQqUu", args[0][0])) || args[0][1]) {
Scott James Remnantff63cf72006-08-31 04:39:34 +0100139 fprintf (stderr, _("%s: illegal runlevel: %s\n"),
Scott James Remnant13ffffe2006-08-31 04:33:39 +0100140 program_name, args[0]);
141 nih_main_suggest_help ();
142 exit (1);
143 }
144
145 /* Check we're root */
146 setuid (geteuid ());
147 if (getuid ()) {
Scott James Remnant31421b72007-03-08 23:53:05 +0000148 nih_fatal (_("Need to be root"));
Scott James Remnant13ffffe2006-08-31 04:33:39 +0100149 exit (1);
150 }
151
Scott James Remnant3aac7132009-07-08 19:02:56 +0100152 /* Send the appropriate message */
153 runlevel = args[0][0];
Scott James Remnant13ffffe2006-08-31 04:33:39 +0100154
Scott James Remnant3aac7132009-07-08 19:02:56 +0100155 switch (runlevel) {
Scott James Remnant52360ea2007-02-08 03:06:40 +0000156 case '0':
157 case '1':
Scott James Remnant13ffffe2006-08-31 04:33:39 +0100158 case '2':
159 case '3':
160 case '4':
161 case '5':
Scott James Remnant1889aa62006-09-09 03:41:53 +0100162 case '6':
Scott James Remnant3aac7132009-07-08 19:02:56 +0100163 ret = sysv_change_runlevel (runlevel, extra_env, NULL, NULL);
Scott James Remnant1889aa62006-09-09 03:41:53 +0100164 break;
Scott James Remnanta17917d2006-09-07 00:18:28 +0100165 case 'S':
166 case 's':
Scott James Remnant3aac7132009-07-08 19:02:56 +0100167 ret = sysv_change_runlevel ('S', extra_env, NULL, NULL);
Scott James Remnanta17917d2006-09-07 00:18:28 +0100168 break;
Scott James Remnant3aac7132009-07-08 19:02:56 +0100169 case 'Q':
170 case 'q':
171 ret = kill (1, SIGHUP);
172 if (ret < 0)
173 nih_error_raise_system ();
174 break;
175 case 'U':
176 case 'u':
Scott James Remnantc80b09f2009-07-08 22:48:03 +0100177 ret = kill (1, SIGTERM);
Scott James Remnant3aac7132009-07-08 19:02:56 +0100178 if (ret < 0)
179 nih_error_raise_system ();
180 break;
Scott James Remnantb175de82009-07-09 12:50:19 +0100181 default:
182 nih_assert_not_reached ();
Scott James Remnant13ffffe2006-08-31 04:33:39 +0100183 }
184
Scott James Remnant3aac7132009-07-08 19:02:56 +0100185 if (ret < 0) {
Scott James Remnant13ffffe2006-08-31 04:33:39 +0100186 NihError *err;
187
188 err = nih_error_get ();
Scott James Remnant3aac7132009-07-08 19:02:56 +0100189 nih_error ("%s", err->message);
190 nih_free (err);
Scott James Remnant13ffffe2006-08-31 04:33:39 +0100191
Scott James Remnant13ffffe2006-08-31 04:33:39 +0100192 exit (1);
193 }
194
195 return 0;
196}
Scott James Remnant3aac7132009-07-08 19:02:56 +0100197#endif