static int get_current_runlevel(Context *c) { static const struct { const int runlevel; const char *special; } table[] = { /* The first target of this list that is active or has * a job scheduled wins. We prefer runlevels 5 and 3 * here over the others, since these are the main * runlevels used on Fedora. It might make sense to * change the order on some distributions. */ { '5', SPECIAL_RUNLEVEL5_TARGET }, { '3', SPECIAL_RUNLEVEL3_TARGET }, { '4', SPECIAL_RUNLEVEL4_TARGET }, { '2', SPECIAL_RUNLEVEL2_TARGET }, { '1', SPECIAL_RESCUE_TARGET }, }; _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; int r; unsigned i; assert(c); for (i = 0; i < ELEMENTSOF(table); i++) { _cleanup_free_ char *state = NULL, *path = NULL; path = unit_dbus_path_from_name(table[i].special); if (!path) return log_oom(); r = sd_bus_get_property_string( c->bus, "org.freedesktop.systemd1", path, "org.freedesktop.systemd1.Unit", "ActiveState", &error, &state); if (r < 0) { log_warning("Failed to get state: %s", bus_error_message(&error, -r)); return r; } if (streq(state, "active") || streq(state, "reloading")) return table[i].runlevel; } return 0; }
static int show_unit_cgroup(sd_bus *bus, const char *interface, const char *unit, pid_t leader) { _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; _cleanup_free_ char *path = NULL; const char *cgroup; int r; unsigned c; assert(bus); assert(unit); if (arg_transport != BUS_TRANSPORT_LOCAL) return 0; path = unit_dbus_path_from_name(unit); if (!path) return -ENOMEM; r = sd_bus_get_property( bus, "org.freedesktop.systemd1", path, interface, "ControlGroup", &error, &reply, "s"); if (r < 0) return r; r = sd_bus_message_read(reply, "s", &cgroup); if (r < 0) return r; if (isempty(cgroup)) return 0; if (cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, cgroup, false) != 0 && leader <= 0) return 0; c = columns(); if (c > 18) c -= 18; else c = 0; show_cgroup_and_extra(SYSTEMD_CGROUP_CONTROLLER, cgroup, "\t\t ", c, false, &leader, leader > 0, get_output_flags()); return 0; }
static int get_cgroup_root(char **ret) { _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; _cleanup_free_ char *unit = NULL, *path = NULL; const char *m; int r; if (!arg_machine) { r = cg_get_root_path(ret); if (r == -ENOMEDIUM) return log_error_errno(r, "Failed to get root control group path: No cgroup filesystem mounted on /sys/fs/cgroup"); else if (r < 0) return log_error_errno(r, "Failed to get root control group path: %m"); return 0; } m = strjoina("/run/systemd/machines/", arg_machine); r = parse_env_file(m, NEWLINE, "SCOPE", &unit, NULL); if (r < 0) return log_error_errno(r, "Failed to load machine data: %m"); path = unit_dbus_path_from_name(unit); if (!path) return log_oom(); r = bus_connect_transport_systemd(BUS_TRANSPORT_LOCAL, NULL, false, &bus); if (r < 0) return log_error_errno(r, "Failed to create bus connection: %m"); r = sd_bus_get_property_string( bus, "org.freedesktop.systemd1", path, unit_dbus_interface_from_name(unit), "ControlGroup", &error, ret); if (r < 0) return log_error_errno(r, "Failed to query unit control group path: %s", bus_error_message(&error, r)); return 0; }
int main(int argc, char *argv[]) { int r = 0, retval = EXIT_FAILURE; int output_flags; _cleanup_free_ char *root = NULL; _cleanup_bus_close_unref_ sd_bus *bus = NULL; log_parse_environment(); log_open(); r = parse_argv(argc, argv); if (r < 0) goto finish; else if (r == 0) { retval = EXIT_SUCCESS; goto finish; } if (!arg_no_pager) { r = pager_open(false); if (r > 0) { if (arg_full == -1) arg_full = true; } } output_flags = arg_all * OUTPUT_SHOW_ALL | (arg_full > 0) * OUTPUT_FULL_WIDTH; r = bus_open_transport(BUS_TRANSPORT_LOCAL, NULL, false, &bus); if (r < 0) { log_error_errno(r, "Failed to create bus connection: %m"); goto finish; } if (optind < argc) { int i; for (i = optind; i < argc; i++) { int q; fprintf(stdout, "%s:\n", argv[i]); fflush(stdout); if (arg_machine) root = strjoin("machine/", arg_machine, "/", argv[i], NULL); else root = strdup(argv[i]); if (!root) return log_oom(); q = show_cgroup_by_path(root, NULL, 0, arg_kernel_threads, output_flags); if (q < 0) r = q; } } else { _cleanup_free_ char *p; p = get_current_dir_name(); if (!p) { log_error_errno(errno, "Cannot determine current working directory: %m"); goto finish; } if (path_startswith(p, "/sys/fs/cgroup") && !arg_machine) { printf("Working Directory %s:\n", p); r = show_cgroup_by_path(p, NULL, 0, arg_kernel_threads, output_flags); } else { if (arg_machine) { char *m; const char *cgroup; _cleanup_free_ char *scope = NULL; _cleanup_free_ char *path = NULL; _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; m = strjoina("/run/systemd/machines/", arg_machine); r = parse_env_file(m, NEWLINE, "SCOPE", &scope, NULL); if (r < 0) { log_error_errno(r, "Failed to get machine path: %m"); goto finish; } path = unit_dbus_path_from_name(scope); if (!path) { log_oom(); goto finish; } r = sd_bus_get_property( bus, "org.freedesktop.systemd1", path, "org.freedesktop.systemd1.Scope", "ControlGroup", &error, &reply, "s"); if (r < 0) { log_error("Failed to query ControlGroup: %s", bus_error_message(&error, -r)); goto finish; } r = sd_bus_message_read(reply, "s", &cgroup); if (r < 0) { bus_log_parse_error(r); goto finish; } root = strdup(cgroup); if (!root) { log_oom(); goto finish; } } else r = cg_get_root_path(&root); if (r < 0) { log_error_errno(r, "Failed to get %s path: %m", arg_machine ? "machine" : "root"); goto finish; } r = show_cgroup(SYSTEMD_CGROUP_CONTROLLER, root, NULL, 0, arg_kernel_threads, output_flags); } } if (r < 0) { log_error_errno(r, "Failed to list cgroup tree %s: %m", root); retval = EXIT_FAILURE; } else retval = EXIT_SUCCESS; finish: pager_close(); return retval; }
static int start_transient_service( sd_bus *bus, char **argv, int *retval) { _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *reply = NULL; _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; _cleanup_(bus_wait_for_jobs_freep) BusWaitForJobs *w = NULL; _cleanup_free_ char *service = NULL, *pty_path = NULL; _cleanup_close_ int master = -1; int r; assert(bus); assert(argv); assert(retval); if (arg_pty) { if (arg_transport == BUS_TRANSPORT_LOCAL) { master = posix_openpt(O_RDWR|O_NOCTTY|O_CLOEXEC|O_NDELAY); if (master < 0) return log_error_errno(errno, "Failed to acquire pseudo tty: %m"); r = ptsname_malloc(master, &pty_path); if (r < 0) return log_error_errno(r, "Failed to determine tty name: %m"); if (unlockpt(master) < 0) return log_error_errno(errno, "Failed to unlock tty: %m"); } else if (arg_transport == BUS_TRANSPORT_MACHINE) { _cleanup_(sd_bus_unrefp) sd_bus *system_bus = NULL; _cleanup_(sd_bus_message_unrefp) sd_bus_message *pty_reply = NULL; const char *s; r = sd_bus_default_system(&system_bus); if (r < 0) return log_error_errno(r, "Failed to connect to system bus: %m"); r = sd_bus_call_method(system_bus, "org.freedesktop.machine1", "/org/freedesktop/machine1", "org.freedesktop.machine1.Manager", "OpenMachinePTY", &error, &pty_reply, "s", arg_host); if (r < 0) { log_error("Failed to get machine PTY: %s", bus_error_message(&error, -r)); return r; } r = sd_bus_message_read(pty_reply, "hs", &master, &s); if (r < 0) return bus_log_parse_error(r); master = fcntl(master, F_DUPFD_CLOEXEC, 3); if (master < 0) return log_error_errno(errno, "Failed to duplicate master fd: %m"); pty_path = strdup(s); if (!pty_path) return log_oom(); } else assert_not_reached("Can't allocate tty via ssh"); } if (!arg_no_block) { r = bus_wait_for_jobs_new(bus, &w); if (r < 0) return log_error_errno(r, "Could not watch jobs: %m"); } if (arg_unit) { r = unit_name_mangle_with_suffix(arg_unit, UNIT_NAME_NOGLOB, ".service", &service); if (r < 0) return log_error_errno(r, "Failed to mangle unit name: %m"); } else { r = make_unit_name(bus, UNIT_SERVICE, &service); if (r < 0) return r; } r = sd_bus_message_new_method_call( bus, &m, "org.freedesktop.systemd1", "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "StartTransientUnit"); if (r < 0) return bus_log_create_error(r); r = sd_bus_message_set_allow_interactive_authorization(m, arg_ask_password); if (r < 0) return bus_log_create_error(r); /* Name and mode */ r = sd_bus_message_append(m, "ss", service, "fail"); if (r < 0) return bus_log_create_error(r); /* Properties */ r = sd_bus_message_open_container(m, 'a', "(sv)"); if (r < 0) return bus_log_create_error(r); r = transient_service_set_properties(m, argv, pty_path); if (r < 0) return bus_log_create_error(r); r = sd_bus_message_close_container(m); if (r < 0) return bus_log_create_error(r); /* Auxiliary units */ r = sd_bus_message_append(m, "a(sa(sv))", 0); if (r < 0) return bus_log_create_error(r); polkit_agent_open_if_enabled(); r = sd_bus_call(bus, m, 0, &error, &reply); if (r < 0) return log_error_errno(r, "Failed to start transient service unit: %s", bus_error_message(&error, r)); if (w) { const char *object; r = sd_bus_message_read(reply, "o", &object); if (r < 0) return bus_log_parse_error(r); r = bus_wait_for_jobs_one(w, object, arg_quiet); if (r < 0) return r; } if (!arg_quiet) log_info("Running as unit: %s", service); if (arg_wait || master >= 0) { _cleanup_(run_context_free) RunContext c = {}; c.bus = sd_bus_ref(bus); r = sd_event_default(&c.event); if (r < 0) return log_error_errno(r, "Failed to get event loop: %m"); if (master >= 0) { assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGWINCH, SIGTERM, SIGINT, -1) >= 0); (void) sd_event_add_signal(c.event, NULL, SIGINT, NULL, NULL); (void) sd_event_add_signal(c.event, NULL, SIGTERM, NULL, NULL); if (!arg_quiet) log_info("Press ^] three times within 1s to disconnect TTY."); r = pty_forward_new(c.event, master, PTY_FORWARD_IGNORE_INITIAL_VHANGUP, &c.forward); if (r < 0) return log_error_errno(r, "Failed to create PTY forwarder: %m"); pty_forward_set_handler(c.forward, pty_forward_handler, &c); } if (arg_wait) { _cleanup_free_ char *path = NULL; const char *mt; path = unit_dbus_path_from_name(service); if (!path) return log_oom(); mt = strjoina("type='signal'," "sender='org.freedesktop.systemd1'," "path='", path, "'," "interface='org.freedesktop.DBus.Properties'," "member='PropertiesChanged'"); r = sd_bus_add_match(bus, &c.match, mt, on_properties_changed, &c); if (r < 0) return log_error_errno(r, "Failed to add properties changed signal."); r = sd_bus_attach_event(bus, c.event, 0); if (r < 0) return log_error_errno(r, "Failed to attach bus to event loop."); } r = sd_event_loop(c.event); if (r < 0) return log_error_errno(r, "Failed to run event loop: %m"); if (c.forward) { char last_char = 0; r = pty_forward_get_last_char(c.forward, &last_char); if (r >= 0 && !arg_quiet && last_char != '\n') fputc('\n', stdout); } if (!arg_quiet) { if (!isempty(c.result)) log_info("Finished with result: %s", strna(c.result)); if (c.exit_code == CLD_EXITED) log_info("Main processes terminated with: code=%s/status=%i", sigchld_code_to_string(c.exit_code), c.exit_status); else if (c.exit_code > 0) log_info("Main processes terminated with: code=%s/status=%s", sigchld_code_to_string(c.exit_code), signal_to_string(c.exit_status)); if (c.inactive_enter_usec > 0 && c.inactive_enter_usec != USEC_INFINITY && c.inactive_exit_usec > 0 && c.inactive_exit_usec != USEC_INFINITY && c.inactive_enter_usec > c.inactive_exit_usec) { char ts[FORMAT_TIMESPAN_MAX]; log_info("Service runtime: %s", format_timespan(ts, sizeof(ts), c.inactive_enter_usec - c.inactive_exit_usec, USEC_PER_MSEC)); } if (c.cpu_usage_nsec > 0 && c.cpu_usage_nsec != NSEC_INFINITY) { char ts[FORMAT_TIMESPAN_MAX]; log_info("CPU time consumed: %s", format_timespan(ts, sizeof(ts), (c.cpu_usage_nsec + NSEC_PER_USEC - 1) / NSEC_PER_USEC, USEC_PER_MSEC)); } } /* Try to propagate the service's return value */ if (c.result && STR_IN_SET(c.result, "success", "exit-code") && c.exit_code == CLD_EXITED) *retval = c.exit_status; else *retval = EXIT_FAILURE; } return 0; }