X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Fsystemctl.c;h=dfa952ed46d5a31bbdd9af3861266ff7457c2eb3;hp=2c8c2cf61d5165036beffe54ec8784a67dc0a2e1;hb=7fc01d33196f329c24766795b7af66e598c3e65b;hpb=4bc5f808e4c4891451b83abbc85c4830b3788782 diff --git a/src/systemctl.c b/src/systemctl.c index 2c8c2cf61..dfa952ed4 100644 --- a/src/systemctl.c +++ b/src/systemctl.c @@ -121,7 +121,7 @@ static bool on_tty(void) { /* Note that this is invoked relatively early, before we start * the pager. That means the value we return reflects whether * we originally were started on a tty, not if we currently - * are. But this is intended, since we want color, and so on + * are. But this is intended, since we want colour and so on * when run in our own pager. */ if (_unlikely_(t < 0)) @@ -141,6 +141,9 @@ static void spawn_ask_password_agent(void) { if (!arg_ask_password) return; + if (arg_user) + return; + parent = getpid(); /* Spawns a temporary TTY agent, making sure it goes away when @@ -151,13 +154,16 @@ static void spawn_ask_password_agent(void) { if (child == 0) { /* In the child */ - const char * const args[] = { SYSTEMD_TTY_ASK_PASSWORD_AGENT_BINARY_PATH, "--watch", NULL }; + int fd; + bool stdout_is_tty, stderr_is_tty; + + /* Make sure the agent goes away when the parent dies */ if (prctl(PR_SET_PDEATHSIG, SIGTERM) < 0) _exit(EXIT_FAILURE); @@ -166,6 +172,35 @@ static void spawn_ask_password_agent(void) { if (getppid() != parent) _exit(EXIT_SUCCESS); + /* Don't leak fds to the agent */ + close_all_fds(NULL, 0); + + stdout_is_tty = isatty(STDOUT_FILENO); + stderr_is_tty = isatty(STDERR_FILENO); + + if (!stdout_is_tty || !stderr_is_tty) { + /* Detach from stdout/stderr. and reopen + * /dev/tty for them. This is important to + * ensure that when systemctl is started via + * popen() or a similar call that expects to + * read EOF we actually do generate EOF and + * not delay this indefinitely by because we + * keep an unused copy of stdin around. */ + if ((fd = open("/dev/tty", O_WRONLY)) < 0) { + log_error("Failed to open /dev/tty: %m"); + _exit(EXIT_FAILURE); + } + + if (!stdout_is_tty) + dup2(fd, STDOUT_FILENO); + + if (!stderr_is_tty) + dup2(fd, STDERR_FILENO); + + if (fd > 2) + close(fd); + } + execv(args[0], (char **) args); _exit(EXIT_FAILURE); } @@ -502,8 +537,10 @@ static int list_units(DBusConnection *bus, char **args, unsigned n) { c++; } - qsort(unit_infos, c, sizeof(struct unit_info), compare_unit_info); - output_units_list(unit_infos, c); + if (c > 0) { + qsort(unit_infos, c, sizeof(struct unit_info), compare_unit_info); + output_units_list(unit_infos, c); + } r = 0; @@ -1615,6 +1652,8 @@ finish: } typedef struct ExecStatusInfo { + char *name; + char *path; char **argv; @@ -1632,6 +1671,7 @@ typedef struct ExecStatusInfo { static void exec_status_info_free(ExecStatusInfo *i) { assert(i); + free(i->name); free(i->path); strv_free(i->argv); free(i); @@ -1844,15 +1884,31 @@ static void print_status_info(UnitStatusInfo *i) { LIST_FOREACH(exec, p, i->exec) { char *t; + bool good; /* Only show exited processes here */ if (p->code == 0) continue; t = strv_join(p->argv, " "); - printf("\t Process: %u (%s, code=%s, ", p->pid, strna(t), sigchld_code_to_string(p->code)); + printf("\t Process: %u %s=%s ", p->pid, p->name, strna(t)); free(t); +#ifdef HAVE_SYSV_COMPAT + if (i->is_sysv) + good = is_clean_exit_lsb(p->code, p->status); + else +#endif + good = is_clean_exit(p->code, p->status); + + if (!good) { + on = ansi_highlight(true); + off = ansi_highlight(false); + } else + on = off = ""; + + printf("%s(code=%s, ", on, sigchld_code_to_string(p->code)); + if (p->code == CLD_EXITED) { const char *c; @@ -1867,7 +1923,10 @@ static void print_status_info(UnitStatusInfo *i) { } else printf("signal=%s", signal_to_string(p->status)); - printf(")\n"); + + printf(")%s\n", off); + + on = off = NULL; if (i->main_pid == p->pid && i->start_timestamp == p->start_timestamp && @@ -2083,6 +2142,11 @@ static int status_property(const char *name, DBusMessageIter *iter, UnitStatusIn if (!(info = new0(ExecStatusInfo, 1))) return -ENOMEM; + if (!(info->name = strdup(name))) { + free(info); + return -ENOMEM; + } + if ((r = exec_status_info_deserialize(&sub, info)) < 0) { free(info); return r;