blob: 218503a416b7c6ed8b923d8c35a0d22e4d595ebc [file] [log] [blame]
/* upstart
*
* Copyright © 2009 Canonical Ltd.
* Author: Scott James Remnant <scott@netsplit.com>.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2, as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif /* HAVE_CONFIG_H */
#include <sys/types.h>
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <nih/macros.h>
#include <nih/alloc.h>
#include <nih/string.h>
#include <nih/main.h>
#include <nih/option.h>
#include <nih/logging.h>
#include <nih/error.h>
#include "sysv.h"
/* Prototypes for option functions */
int env_option (NihOption *option, const char *arg);
/**
* extra_env:
*
* Extra environment variables to append to the runlevel event.
**/
char **extra_env = NULL;
/**
* env_option:
* @option: NihOption invoked,
* @arg: argument to parse.
*
* This option setter is used to append @arg to the list of environment
* variables pointed to by the value member of option, which must be a
* pointer to a char **.
*
* The arg_name member of @option must not be NULL.
*
* Returns: zero on success, non-zero on error.
**/
int
env_option (NihOption *option,
const char *arg)
{
char ***value;
nih_assert (option != NULL);
nih_assert (option->value != NULL);
nih_assert (arg != NULL);
value = (char ***)option->value;
NIH_MUST (nih_str_array_add (value, NULL, NULL, arg));
return 0;
}
#ifndef TEST
/**
* options:
*
* Command-line options accepted.
**/
static NihOption options[] = {
{ 'e', NULL, N_("set environment variable in the runlevel event"),
NULL, "KEY=VALUE", &extra_env, env_option },
/* Compatibility options, all ignored */
{ 't', NULL, NULL, NULL, "SECONDS", NULL, NULL },
NIH_OPTION_LAST
};
int
main (int argc,
char *argv[])
{
char **args;
int runlevel;
int ret;
nih_main_init (argv[0]);
nih_option_set_usage ("RUNLEVEL");
nih_option_set_synopsis (_("Change runlevel."));
nih_option_set_help (
_("RUNLEVEL should be one of 0123456sS, where s and S are "
"considered identical.\n"
"\n"
"RUNLEVEL may also be Q or q to instruct the init daemon "
"to reload its configuration, this is rarely necessary "
"since the daemon watches its configuration for changes.\n"
"\n"
"RUNLEVEL may be U or u to instruct the init daemon to "
"re-execute itself, this is not recommended since Upstart "
"does not currently preserve its state.\n"));
args = nih_option_parser (NULL, argc, argv, options, FALSE);
if (! args)
exit (1);
/* First argument must be a single character we know */
if (! args[0]) {
fprintf (stderr, _("%s: missing runlevel\n"), program_name);
nih_main_suggest_help ();
exit (1);
}
if ((! strchr ("0123456SsQqUu", args[0][0])) || args[0][1]) {
fprintf (stderr, _("%s: illegal runlevel: %s\n"),
program_name, args[0]);
nih_main_suggest_help ();
exit (1);
}
/* Check we're root */
setuid (geteuid ());
if (getuid ()) {
nih_fatal (_("Need to be root"));
exit (1);
}
/* Send the appropriate message */
runlevel = args[0][0];
switch (runlevel) {
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
ret = sysv_change_runlevel (runlevel, extra_env, NULL, NULL);
break;
case 'S':
case 's':
ret = sysv_change_runlevel ('S', extra_env, NULL, NULL);
break;
case 'Q':
case 'q':
ret = kill (1, SIGHUP);
if (ret < 0)
nih_error_raise_system ();
break;
case 'U':
case 'u':
ret = kill (1, SIGTERM);
if (ret < 0)
nih_error_raise_system ();
break;
default:
nih_assert_not_reached ();
}
if (ret < 0) {
NihError *err;
err = nih_error_get ();
nih_error ("%s", err->message);
nih_free (err);
exit (1);
}
return 0;
}
#endif