X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Fsystemctl.c;h=4768fb20ad24053ab1b5eeda33818a2863c4af41;hp=ffbe4db541ebe0be9f67c5eccd6c252e405b7bee;hb=be8088a2fb41467f66978f86b11bf47c546f24ed;hpb=8a0867d6c5b47c8697d1ddd815116a548433c718 diff --git a/src/systemctl.c b/src/systemctl.c index ffbe4db54..4768fb20a 100644 --- a/src/systemctl.c +++ b/src/systemctl.c @@ -32,6 +32,7 @@ #include #include #include +#include #include @@ -60,7 +61,7 @@ static const char *arg_type = NULL; static char **arg_property = NULL; static bool arg_all = false; static bool arg_fail = false; -static bool arg_session = false; +static bool arg_user = false; static bool arg_global = false; static bool arg_immediate = false; static bool arg_no_block = false; @@ -73,6 +74,7 @@ static bool arg_quiet = false; static bool arg_full = false; static bool arg_force = false; static bool arg_defaults = false; +static bool arg_ask_password = false; static char **arg_wall = NULL; static const char *arg_kill_who = NULL; static const char *arg_kill_mode = NULL; @@ -118,6 +120,47 @@ static bool on_tty(void) { return t; } +static void spawn_ask_password_agent(void) { + pid_t parent, child; + + /* We check STDIN here, not STDOUT, since this is about input, + * not output */ + if (!isatty(STDIN_FILENO)) + return; + + if (!arg_ask_password) + return; + + parent = getpid(); + + /* Spawns a temporary TTY agent, making sure it goes away when + * we go away */ + + if ((child = fork()) < 0) + return; + + if (child == 0) { + /* In the child */ + + const char * const args[] = { + SYSTEMD_TTY_ASK_PASSWORD_AGENT_BINARY_PATH, + "--watch", + NULL + }; + + if (prctl(PR_SET_PDEATHSIG, SIGTERM) < 0) + _exit(EXIT_FAILURE); + + /* Check whether our parent died before we were able + * to set the death signal */ + if (getppid() != parent) + _exit(EXIT_SUCCESS); + + execv(args[0], (char **) args); + _exit(EXIT_FAILURE); + } +} + static const char *ansi_highlight(bool b) { if (!on_tty()) @@ -215,7 +258,7 @@ static void warn_wall(enum action action) { } if (*p) { - utmp_wall(p); + utmp_wall(p, NULL); free(p); return; } @@ -226,7 +269,7 @@ static void warn_wall(enum action action) { if (!table[action]) return; - utmp_wall(table[action]); + utmp_wall(table[action], NULL); } struct unit_info { @@ -1119,7 +1162,7 @@ static int wait_for_jobs(DBusConnection *bus, Set *s) { ; if (!arg_quiet && d.failed) - log_error("Job failed, see system logs for details."); + log_error("Job failed. See system logs and 'systemctl status' for details."); r = d.failed ? -EIO : 0; @@ -1191,7 +1234,7 @@ static int start_unit_one( if (need_daemon_reload(bus, name)) log_warning("Unit file of created job changed on disk, 'systemctl %s daemon-reload' recommended.", - arg_session ? "--session" : "--system"); + arg_user ? "--user" : "--system"); if (!arg_no_block) { char *p; @@ -1269,6 +1312,8 @@ static int start_unit(DBusConnection *bus, char **args, unsigned n) { assert(bus); + spawn_ask_password_agent(); + if (arg_action == ACTION_SYSTEMCTL) { method = streq(args[0], "stop") ? "StopUnit" : @@ -1775,9 +1820,9 @@ static void print_status_info(UnitStatusInfo *i) { if (i->sysfs_path) printf("\t Device: %s\n", i->sysfs_path); - else if (i->where) + if (i->where) printf("\t Where: %s\n", i->where); - else if (i->what) + if (i->what) printf("\t What: %s\n", i->what); if (i->accept) @@ -1892,7 +1937,7 @@ static void print_status_info(UnitStatusInfo *i) { printf("\n%sWarning:%s Unit file changed on disk, 'systemctl %s daemon-reload' recommended.\n", ansi_highlight(true), ansi_highlight(false), - arg_session ? "--session" : "--system"); + arg_user ? "--user" : "--system"); } static int status_property(const char *name, DBusMessageIter *iter, UnitStatusInfo *i) { @@ -2293,7 +2338,7 @@ static int print_property(const char *name, DBusMessageIter *iter) { return 0; } -static int show_one(DBusConnection *bus, const char *path, bool show_properties, bool *new_line) { +static int show_one(const char *verb, DBusConnection *bus, const char *path, bool show_properties, bool *new_line) { DBusMessage *m = NULL, *reply = NULL; const char *interface = ""; int r; @@ -2393,7 +2438,8 @@ static int show_one(DBusConnection *bus, const char *path, bool show_properties, print_status_info(&info); if (!streq_ptr(info.active_state, "active") && - !streq_ptr(info.active_state, "reloading")) + !streq_ptr(info.active_state, "reloading") && + streq(verb, "status")) /* According to LSB: "program not running" */ r = 3; @@ -2432,7 +2478,7 @@ static int show(DBusConnection *bus, char **args, unsigned n) { /* If not argument is specified inspect the manager * itself */ - ret = show_one(bus, "/org/freedesktop/systemd1", show_properties, &new_line); + ret = show_one(args[0], bus, "/org/freedesktop/systemd1", show_properties, &new_line); goto finish; } @@ -2566,7 +2612,7 @@ static int show(DBusConnection *bus, char **args, unsigned n) { goto finish; } - if ((r = show_one(bus, path, show_properties, &new_line)) != 0) + if ((r = show_one(args[0], bus, path, show_properties, &new_line)) != 0) ret = r; dbus_message_unref(m); @@ -3841,6 +3887,68 @@ static int install_info_apply(const char *verb, LookupPaths *paths, InstallInfo } if (!f) { +#if defined(TARGET_FEDORA) && defined (HAVE_SYSV_COMPAT) + + if (endswith(i->name, ".service")) { + char *sysv; + bool exists; + + if (asprintf(&sysv, SYSTEM_SYSVINIT_PATH "/%s", i->name) < 0) { + log_error("Out of memory"); + return -ENOMEM; + } + + sysv[strlen(sysv) - sizeof(".service") + 1] = 0; + exists = access(sysv, F_OK) >= 0; + + if (exists) { + pid_t pid; + siginfo_t status; + + const char *argv[] = { + "/sbin/chkconfig", + NULL, + NULL, + NULL + }; + + log_info("%s is not a native service, redirecting to /sbin/chkconfig.", i->name); + + argv[1] = file_name_from_path(sysv); + argv[2] = + streq(verb, "enable") ? "on" : + streq(verb, "disable") ? "off" : NULL; + + log_info("Executing %s %s %s", argv[0], argv[1], strempty(argv[2])); + + if ((pid = fork()) < 0) { + log_error("Failed to fork: %m"); + free(sysv); + return -errno; + } else if (pid == 0) { + execv(argv[0], (char**) argv); + _exit(EXIT_FAILURE); + } + + free(sysv); + + if ((r = wait_for_terminate(pid, &status)) < 0) + return r; + + if (status.si_code == CLD_EXITED) { + if (status.si_status == 0 && (streq(verb, "enable") || streq(verb, "disable"))) + n_symlinks ++; + + return status.si_status == 0 ? 0 : -EINVAL; + } else + return -EPROTO; + } + + free(sysv); + } + +#endif + log_error("Couldn't find %s.", i->name); return -ENOENT; } @@ -3874,13 +3982,13 @@ static int install_info_apply(const char *verb, LookupPaths *paths, InstallInfo static char *get_config_path(void) { - if (arg_session && arg_global) - return strdup(SESSION_CONFIG_UNIT_PATH); + if (arg_user && arg_global) + return strdup(USER_CONFIG_UNIT_PATH); - if (arg_session) { + if (arg_user) { char *p; - if (session_config_home(&p) < 0) + if (user_config_home(&p) < 0) return NULL; return p; @@ -3901,7 +4009,7 @@ static int enable_unit(DBusConnection *bus, char **args, unsigned n) { dbus_error_init(&error); zero(paths); - if ((r = lookup_paths_init(&paths, arg_session ? MANAGER_SESSION : MANAGER_SYSTEM)) < 0) { + if ((r = lookup_paths_init(&paths, arg_user ? MANAGER_USER : MANAGER_SYSTEM)) < 0) { log_error("Failed to determine lookup paths: %s", strerror(-r)); goto finish; } @@ -3965,9 +4073,9 @@ static int enable_unit(DBusConnection *bus, char **args, unsigned n) { /* Don't try to reload anything when updating a unit globally */ !arg_global && /* Don't try to reload anything if we are called for system changes but the system wasn't booted with systemd */ - (arg_session || sd_booted() > 0) && + (arg_user || sd_booted() > 0) && /* Don't try to reload anything if we are running in a chroot environment */ - (arg_session || running_in_chroot() <= 0) ) { + (arg_user || running_in_chroot() <= 0) ) { int q; if ((q = daemon_reload(bus, args, n)) < 0) @@ -4002,14 +4110,16 @@ static int systemctl_help(void) { " pending\n" " -q --quiet Suppress output\n" " --no-block Do not wait until operation finished\n" - " --system Connect to system bus\n" - " --session Connect to session bus\n" + " --system Connect to system manager\n" + " --user Connect to user service manager\n" " --order When generating graph for dot, show only order\n" " --require When generating graph for dot, show only requirement\n" " --no-wall Don't send wall message before halt/power-off/reboot\n" " --global Enable/disable unit files globally\n" " --no-reload When enabling/disabling unit files, don't reload daemon\n" " configuration\n" + " --no-ask-password\n" + " Do not ask for system passwords\n" " --kill-mode=MODE How to send signal\n" " --kill-who=WHO Who to send signal to\n" " -s --signal=SIGNAL Which signal to send\n" @@ -4058,7 +4168,7 @@ static int systemctl_help(void) { " poweroff Shut down and power-off the system\n" " reboot Shut down and reboot the system\n" " kexec Shut down and reboot the system with kexec\n" - " exit Ask for session termination\n", + " exit Ask for user instance termination\n", program_invocation_short_name); return 0; @@ -4135,7 +4245,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) { enum { ARG_FAIL = 0x100, ARG_VERSION, - ARG_SESSION, + ARG_USER, ARG_SYSTEM, ARG_GLOBAL, ARG_NO_BLOCK, @@ -4146,7 +4256,8 @@ static int systemctl_parse_argv(int argc, char *argv[]) { ARG_NO_RELOAD, ARG_DEFAULTS, ARG_KILL_MODE, - ARG_KILL_WHO + ARG_KILL_WHO, + ARG_NO_ASK_PASSWORD }; static const struct option options[] = { @@ -4157,7 +4268,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) { { "all", no_argument, NULL, 'a' }, { "full", no_argument, NULL, ARG_FULL }, { "fail", no_argument, NULL, ARG_FAIL }, - { "session", no_argument, NULL, ARG_SESSION }, + { "user", no_argument, NULL, ARG_USER }, { "system", no_argument, NULL, ARG_SYSTEM }, { "global", no_argument, NULL, ARG_GLOBAL }, { "no-block", no_argument, NULL, ARG_NO_BLOCK }, @@ -4171,6 +4282,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) { { "kill-mode", required_argument, NULL, ARG_KILL_MODE }, { "kill-who", required_argument, NULL, ARG_KILL_WHO }, { "signal", required_argument, NULL, 's' }, + { "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD }, { NULL, 0, NULL, 0 } }; @@ -4179,6 +4291,9 @@ static int systemctl_parse_argv(int argc, char *argv[]) { assert(argc >= 0); assert(argv); + /* Only when running as systemctl we ask for passwords */ + arg_ask_password = true; + while ((c = getopt_long(argc, argv, "ht:p:aqfs:", options, NULL)) >= 0) { switch (c) { @@ -4221,12 +4336,12 @@ static int systemctl_parse_argv(int argc, char *argv[]) { arg_fail = true; break; - case ARG_SESSION: - arg_session = true; + case ARG_USER: + arg_user = true; break; case ARG_SYSTEM: - arg_session = false; + arg_user = false; break; case ARG_NO_BLOCK: @@ -4263,7 +4378,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) { case ARG_GLOBAL: arg_global = true; - arg_session = true; + arg_user = true; break; case ARG_DEFAULTS: @@ -4285,6 +4400,10 @@ static int systemctl_parse_argv(int argc, char *argv[]) { } break; + case ARG_NO_ASK_PASSWORD: + arg_ask_password = false; + break; + case '?': return -EINVAL; @@ -5180,7 +5299,7 @@ int main(int argc, char*argv[]) { goto finish; } - bus_connect(arg_session ? DBUS_BUS_SESSION : DBUS_BUS_SYSTEM, &bus, &private_bus, &error); + bus_connect(arg_user ? DBUS_BUS_SESSION : DBUS_BUS_SYSTEM, &bus, &private_bus, &error); switch (arg_action) {