#include <sys/socket.h>
#include <sys/stat.h>
#include <stddef.h>
+#include <sys/prctl.h>
#include <dbus/dbus.h>
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;
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;
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())
}
if (*p) {
- utmp_wall(p);
+ utmp_wall(p, NULL);
free(p);
return;
}
if (!table[action])
return;
- utmp_wall(table[action]);
+ utmp_wall(table[action], NULL);
}
struct unit_info {
;
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;
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;
assert(bus);
+ spawn_ask_password_agent();
+
if (arg_action == ACTION_SYSTEMCTL) {
method =
streq(args[0], "stop") ? "StopUnit" :
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)
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) {
}
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;
}
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;
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;
}
/* 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)
" 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"
" 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;
enum {
ARG_FAIL = 0x100,
ARG_VERSION,
- ARG_SESSION,
+ ARG_USER,
ARG_SYSTEM,
ARG_GLOBAL,
ARG_NO_BLOCK,
ARG_NO_RELOAD,
ARG_DEFAULTS,
ARG_KILL_MODE,
- ARG_KILL_WHO
+ ARG_KILL_WHO,
+ ARG_NO_ASK_PASSWORD
};
static const struct option options[] = {
{ "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 },
{ "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 }
};
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) {
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:
case ARG_GLOBAL:
arg_global = true;
- arg_session = true;
+ arg_user = true;
break;
case ARG_DEFAULTS:
}
break;
+ case ARG_NO_ASK_PASSWORD:
+ arg_ask_password = false;
+ break;
+
case '?':
return -EINVAL;
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) {