static int status_entries(const char *esp_path, sd_id128_t partition) { int r; _cleanup_(boot_config_free) BootConfig config = {}; printf("Default Boot Entry:\n"); r = boot_entries_load_config(esp_path, &config); if (r < 0) return log_error_errno(r, "Failed to load bootspec config from \"%s/loader\": %m", esp_path); if (config.default_entry < 0) printf("%zu entries, no entry suitable as default", config.n_entries); else { const BootEntry *e = &config.entries[config.default_entry]; printf(" title: %s\n", boot_entry_title(e)); if (e->version) printf(" version: %s\n", e->version); if (e->kernel) printf(" linux: %s\n", e->kernel); if (!strv_isempty(e->initrd)) { _cleanup_free_ char *t; t = strv_join(e->initrd, " "); if (!t) return log_oom(); printf(" initrd: %s\n", t); } if (!strv_isempty(e->options)) { _cleanup_free_ char *t; t = strv_join(e->options, " "); if (!t) return log_oom(); printf(" options: %s\n", t); } if (e->device_tree) printf(" devicetree: %s\n", e->device_tree); puts(""); } return 0; }
static void test_strv_join(void) { _cleanup_free_ char *p = NULL, *q = NULL, *r = NULL, *s = NULL, *t = NULL, *v = NULL, *w = NULL; p = strv_join((char **)input_table_multiple, ", "); assert_se(p); assert_se(streq(p, "one, two, three")); q = strv_join((char **)input_table_multiple, ";"); assert_se(q); assert_se(streq(q, "one;two;three")); r = strv_join((char **)input_table_multiple, NULL); assert_se(r); assert_se(streq(r, "one two three")); s = strv_join((char **)input_table_one, ", "); assert_se(s); assert_se(streq(s, "one")); t = strv_join((char **)input_table_none, ", "); assert_se(t); assert_se(streq(t, "")); v = strv_join((char **)input_table_two_empties, ", "); assert_se(v); assert_se(streq(v, ", ")); w = strv_join((char **)input_table_one_empty, ", "); assert_se(w); assert_se(streq(w, "")); }
static char *strdup_structured_data(struct structured_data *sd) { char *res, *tmp; if (strv_isempty(sd->params)) return NULL; xasprintf(&res, "[%s %s]", sd->id, (tmp = strv_join(sd->params, " "))); free(tmp); return res; }
static int determine_matches(const char *image, char **l, bool allow_any, char ***ret) { _cleanup_strv_free_ char **k = NULL; int r; /* Determine the matches to apply. If the list is empty we derive the match from the image name. If the list * contains exactly the "-" we return a wildcard list (which is the empty list), but only if this is expressly * permitted. */ if (strv_isempty(l)) { char *prefix; r = extract_prefix(image, &prefix); if (r < 0) return log_error_errno(r, "Failed to extract prefix of image name '%s': %m", image); if (!arg_quiet) log_info("(Matching unit files with prefix '%s'.)", prefix); r = strv_consume(&k, prefix); if (r < 0) return log_oom(); } else if (strv_equal(l, STRV_MAKE("-"))) { if (!allow_any) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Refusing all unit file match."); if (!arg_quiet) log_info("(Matching all unit files.)"); } else { k = strv_copy(l); if (!k) return log_oom(); if (!arg_quiet) { _cleanup_free_ char *joined = NULL; joined = strv_join(k, "', '"); if (!joined) return log_oom(); log_info("(Matching unit files with prefixes '%s'.)", joined); } } *ret = TAKE_PTR(k); return 0; }
static void test_strv_unquote(const char *quoted, char **list) { _cleanup_strv_free_ char **s; _cleanup_free_ char *j; unsigned i = 0; char **t; int r; r = strv_split_extract(&s, quoted, WHITESPACE, EXTRACT_QUOTES); assert_se(r == (int) strv_length(list)); assert_se(s); j = strv_join(s, " | "); assert_se(j); puts(j); STRV_FOREACH(t, s) assert_se(streq(list[i++], *t)); assert_se(list[i] == NULL); }
int mount_cgroup_controllers(char ***join_controllers) { int r; char buf[LINE_MAX]; _cleanup_set_free_free_ Set *controllers = NULL; _cleanup_fclose_ FILE *f; /* Mount all available cgroup controllers that are built into the kernel. */ f = fopen("/proc/cgroups", "re"); if (!f) { log_error("Failed to enumerate cgroup controllers: %m"); return 0; } controllers = set_new(string_hash_func, string_compare_func); if (!controllers) return log_oom(); /* Ignore the header line */ (void) fgets(buf, sizeof(buf), f); for (;;) { char *controller; int enabled = 0; if (fscanf(f, "%ms %*i %*i %i", &controller, &enabled) != 2) { if (feof(f)) break; log_error("Failed to parse /proc/cgroups."); return -EIO; } if (!enabled) { free(controller); continue; } r = set_consume(controllers, controller); if (r < 0) { log_error("Failed to add controller to set."); return r; } } for (;;) { MountPoint p = { .what = "cgroup", .type = "cgroup", .flags = MS_NOSUID|MS_NOEXEC|MS_NODEV, .mode = MNT_IN_CONTAINER, }; char ***k = NULL; _cleanup_free_ char *options = NULL, *controller; controller = set_steal_first(controllers); if (!controller) break; if (join_controllers) for (k = join_controllers; *k; k++) if (strv_find(*k, controller)) break; if (k && *k) { char **i, **j; for (i = *k, j = *k; *i; i++) { if (!streq(*i, controller)) { char _cleanup_free_ *t; t = set_remove(controllers, *i); if (!t) { free(*i); continue; } } *(j++) = *i; } *j = NULL; options = strv_join(*k, ","); if (!options) return log_oom(); } else { options = controller; controller = NULL; } p.where = strappenda("/sys/fs/cgroup/", options); p.options = options; r = mount_one(&p, true); if (r < 0) return r; if (r > 0 && k && *k) { char **i; for (i = *k; *i; i++) { char *t = strappenda("/sys/fs/cgroup/", *i); r = symlink(options, t); if (r < 0 && errno != EEXIST) { log_error("Failed to create symlink %s: %m", t); return -errno; } } } } return 0; } static int nftw_cb( const char *fpath, const struct stat *sb, int tflag, struct FTW *ftwbuf) { /* No need to label /dev twice in a row... */ if (_unlikely_(ftwbuf->level == 0)) return FTW_CONTINUE; label_fix(fpath, false, false); /* /run/initramfs is static data and big, no need to * dynamically relabel its contents at boot... */ if (_unlikely_(ftwbuf->level == 1 && tflag == FTW_D && streq(fpath, "/run/initramfs"))) return FTW_SKIP_SUBTREE; return FTW_CONTINUE; }; int mount_setup(bool loaded_policy) { int r; unsigned i; for (i = 0; i < ELEMENTSOF(mount_table); i ++) { r = mount_one(mount_table + i, true); if (r < 0) return r; } /* Nodes in devtmpfs and /run need to be manually updated for * the appropriate labels, after mounting. The other virtual * API file systems like /sys and /proc do not need that, they * use the same label for all their files. */ if (loaded_policy) { usec_t before_relabel, after_relabel; char timespan[FORMAT_TIMESPAN_MAX]; before_relabel = now(CLOCK_MONOTONIC); nftw("/dev", nftw_cb, 64, FTW_MOUNT|FTW_PHYS|FTW_ACTIONRETVAL); nftw("/run", nftw_cb, 64, FTW_MOUNT|FTW_PHYS|FTW_ACTIONRETVAL); after_relabel = now(CLOCK_MONOTONIC); log_info("Relabelled /dev and /run in %s.", format_timespan(timespan, sizeof(timespan), after_relabel - before_relabel, 0)); } /* Create a few default symlinks, which are normally created * by udevd, but some scripts might need them before we start * udevd. */ dev_setup(NULL); /* Mark the root directory as shared in regards to mount * propagation. The kernel defaults to "private", but we think * it makes more sense to have a default of "shared" so that * nspawn and the container tools work out of the box. If * specific setups need other settings they can reset the * propagation mode to private if needed. */ if (detect_container(NULL) <= 0) if (mount(NULL, "/", NULL, MS_REC|MS_SHARED, NULL) < 0) log_warning("Failed to set up the root directory for shared mount propagation: %m"); /* Create a few directories we always want around, Note that * sd_booted() checks for /run/systemd/system, so this mkdir * really needs to stay for good, otherwise software that * copied sd-daemon.c into their sources will misdetect * systemd. */ mkdir_label("/run/systemd", 0755); mkdir_label("/run/systemd/system", 0755); mkdir_label("/run/systemd/inaccessible", 0000); return 0; }
static int rename_service(sd_bus *a, sd_bus *b) { _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL; _cleanup_free_ char *p = NULL, *name = NULL; const char *comm; char **cmdline; uid_t uid; pid_t pid; int r; assert(a); assert(b); r = sd_bus_get_owner_creds(b, SD_BUS_CREDS_EUID|SD_BUS_CREDS_PID|SD_BUS_CREDS_CMDLINE|SD_BUS_CREDS_COMM|SD_BUS_CREDS_AUGMENT, &creds); if (r < 0) return r; r = sd_bus_creds_get_euid(creds, &uid); if (r < 0) return r; r = sd_bus_creds_get_pid(creds, &pid); if (r < 0) return r; r = sd_bus_creds_get_cmdline(creds, &cmdline); if (r < 0) return r; r = sd_bus_creds_get_comm(creds, &comm); if (r < 0) return r; name = uid_to_name(uid); if (!name) return -ENOMEM; p = strv_join(cmdline, " "); if (!p) return -ENOMEM; /* The status string gets the full command line ... */ sd_notifyf(false, "STATUS=Processing requests from client PID "PID_FMT" (%s); UID "UID_FMT" (%s)", pid, p, uid, name); /* ... and the argv line only the short comm */ if (arg_command_line_buffer) { size_t m, w; m = strlen(arg_command_line_buffer); w = snprintf(arg_command_line_buffer, m, "[PID "PID_FMT"/%s; UID "UID_FMT"/%s]", pid, comm, uid, name); if (m > w) memzero(arg_command_line_buffer + w, m - w); } log_debug("Running on behalf of PID "PID_FMT" (%s), UID "UID_FMT" (%s), %s", pid, p, uid, name, a->unique_name); return 0; }
int main(int argc, char* argv[]) { _cleanup_free_ char *status = NULL, *cpid = NULL, *n = NULL; _cleanup_strv_free_ char **final_env = NULL; char* our_env[4]; unsigned i = 0; int r; log_parse_environment(); log_open(); r = parse_argv(argc, argv); if (r <= 0) goto finish; if (arg_booted) return sd_booted() <= 0; if (arg_ready) our_env[i++] = (char*) "READY=1"; if (arg_status) { status = strappend("STATUS=", arg_status); if (!status) { r = log_oom(); goto finish; } our_env[i++] = status; } if (arg_pid > 0) { if (asprintf(&cpid, "MAINPID="PID_FMT, arg_pid) < 0) { r = log_oom(); goto finish; } our_env[i++] = cpid; } our_env[i++] = NULL; final_env = strv_env_merge(2, our_env, argv + optind); if (!final_env) { r = log_oom(); goto finish; } if (strv_length(final_env) <= 0) { r = 0; goto finish; } n = strv_join(final_env, "\n"); if (!n) { r = log_oom(); goto finish; } r = sd_pid_notify(arg_pid ? arg_pid : getppid(), false, n); if (r < 0) { log_error_errno(r, "Failed to notify init system: %m"); goto finish; } else if (r == 0) { log_error("No status data could be sent: $NOTIFY_SOCKET was not set"); r = -EOPNOTSUPP; } finish: return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; }
int main(int argc, char* argv[]) { /* The small core field we allocate on the stack, to keep things simple */ char *core_pid = NULL, *core_uid = NULL, *core_gid = NULL, *core_signal = NULL, *core_session = NULL, *core_exe = NULL, *core_comm = NULL, *core_cmdline = NULL, *core_cgroup = NULL, *core_cwd = NULL, *core_root = NULL, *core_unit = NULL, *core_slice = NULL; /* The larger ones we allocate on the heap */ _cleanup_free_ char *core_timestamp = NULL, *core_message = NULL, *coredump_data = NULL, *core_owner_uid = NULL, *core_open_fds = NULL, *core_proc_status = NULL, *core_proc_maps = NULL, *core_proc_limits = NULL, *core_proc_cgroup = NULL, *core_environ = NULL; _cleanup_free_ char *exe = NULL, *comm = NULL, *filename = NULL; const char *info[_INFO_LEN]; _cleanup_close_ int coredump_fd = -1; struct iovec iovec[26]; uint64_t coredump_size; int r, j = 0; uid_t uid, owner_uid; gid_t gid; pid_t pid; char *t; const char *p; /* Make sure we never enter a loop */ prctl(PR_SET_DUMPABLE, 0); /* First, log to a safe place, since we don't know what * crashed and it might be journald which we'd rather not log * to then. */ log_set_target(LOG_TARGET_KMSG); log_open(); if (argc < INFO_COMM + 1) { log_error("Not enough arguments passed from kernel (%d, expected %d).", argc - 1, INFO_COMM + 1 - 1); r = -EINVAL; goto finish; } /* Ignore all parse errors */ parse_config(); log_debug("Selected storage '%s'.", coredump_storage_to_string(arg_storage)); log_debug("Selected compression %s.", yes_no(arg_compress)); r = parse_uid(argv[INFO_UID + 1], &uid); if (r < 0) { log_error("Failed to parse UID."); goto finish; } r = parse_pid(argv[INFO_PID + 1], &pid); if (r < 0) { log_error("Failed to parse PID."); goto finish; } r = parse_gid(argv[INFO_GID + 1], &gid); if (r < 0) { log_error("Failed to parse GID."); goto finish; } if (get_process_comm(pid, &comm) < 0) { log_warning("Failed to get COMM, falling back to the command line."); comm = strv_join(argv + INFO_COMM + 1, " "); } if (get_process_exe(pid, &exe) < 0) log_warning("Failed to get EXE."); info[INFO_PID] = argv[INFO_PID + 1]; info[INFO_UID] = argv[INFO_UID + 1]; info[INFO_GID] = argv[INFO_GID + 1]; info[INFO_SIGNAL] = argv[INFO_SIGNAL + 1]; info[INFO_TIMESTAMP] = argv[INFO_TIMESTAMP + 1]; info[INFO_COMM] = comm; info[INFO_EXE] = exe; if (cg_pid_get_unit(pid, &t) >= 0) { if (streq(t, SPECIAL_JOURNALD_SERVICE)) { free(t); /* If we are journald, we cut things short, * don't write to the journal, but still * create a coredump. */ if (arg_storage != COREDUMP_STORAGE_NONE) arg_storage = COREDUMP_STORAGE_EXTERNAL; r = save_external_coredump(info, uid, &filename, &coredump_fd, &coredump_size); if (r < 0) goto finish; r = maybe_remove_external_coredump(filename, coredump_size); if (r < 0) goto finish; log_info("Detected coredump of the journal daemon itself, diverted to %s.", filename); goto finish; } core_unit = strjoina("COREDUMP_UNIT=", t); free(t); } else if (cg_pid_get_user_unit(pid, &t) >= 0) { core_unit = strjoina("COREDUMP_USER_UNIT=", t); free(t); } if (core_unit) IOVEC_SET_STRING(iovec[j++], core_unit); /* OK, now we know it's not the journal, hence we can make use * of it now. */ log_set_target(LOG_TARGET_JOURNAL_OR_KMSG); log_open(); core_pid = strjoina("COREDUMP_PID=", info[INFO_PID]); IOVEC_SET_STRING(iovec[j++], core_pid); core_uid = strjoina("COREDUMP_UID=", info[INFO_UID]); IOVEC_SET_STRING(iovec[j++], core_uid); core_gid = strjoina("COREDUMP_GID=", info[INFO_GID]); IOVEC_SET_STRING(iovec[j++], core_gid); core_signal = strjoina("COREDUMP_SIGNAL=", info[INFO_SIGNAL]); IOVEC_SET_STRING(iovec[j++], core_signal); if (sd_pid_get_session(pid, &t) >= 0) { core_session = strjoina("COREDUMP_SESSION=", t); free(t); IOVEC_SET_STRING(iovec[j++], core_session); } if (sd_pid_get_owner_uid(pid, &owner_uid) >= 0) { r = asprintf(&core_owner_uid, "COREDUMP_OWNER_UID=" UID_FMT, owner_uid); if (r > 0) IOVEC_SET_STRING(iovec[j++], core_owner_uid); } if (sd_pid_get_slice(pid, &t) >= 0) { core_slice = strjoina("COREDUMP_SLICE=", t); free(t); IOVEC_SET_STRING(iovec[j++], core_slice); } if (comm) { core_comm = strjoina("COREDUMP_COMM=", comm); IOVEC_SET_STRING(iovec[j++], core_comm); } if (exe) { core_exe = strjoina("COREDUMP_EXE=", exe); IOVEC_SET_STRING(iovec[j++], core_exe); } if (get_process_cmdline(pid, 0, false, &t) >= 0) { core_cmdline = strjoina("COREDUMP_CMDLINE=", t); free(t); IOVEC_SET_STRING(iovec[j++], core_cmdline); } if (cg_pid_get_path_shifted(pid, NULL, &t) >= 0) { core_cgroup = strjoina("COREDUMP_CGROUP=", t); free(t); IOVEC_SET_STRING(iovec[j++], core_cgroup); } if (compose_open_fds(pid, &t) >= 0) { core_open_fds = strappend("COREDUMP_OPEN_FDS=", t); free(t); if (core_open_fds) IOVEC_SET_STRING(iovec[j++], core_open_fds); } p = procfs_file_alloca(pid, "status"); if (read_full_file(p, &t, NULL) >= 0) { core_proc_status = strappend("COREDUMP_PROC_STATUS=", t); free(t); if (core_proc_status) IOVEC_SET_STRING(iovec[j++], core_proc_status); } p = procfs_file_alloca(pid, "maps"); if (read_full_file(p, &t, NULL) >= 0) { core_proc_maps = strappend("COREDUMP_PROC_MAPS=", t); free(t); if (core_proc_maps) IOVEC_SET_STRING(iovec[j++], core_proc_maps); } p = procfs_file_alloca(pid, "limits"); if (read_full_file(p, &t, NULL) >= 0) { core_proc_limits = strappend("COREDUMP_PROC_LIMITS=", t); free(t); if (core_proc_limits) IOVEC_SET_STRING(iovec[j++], core_proc_limits); } p = procfs_file_alloca(pid, "cgroup"); if (read_full_file(p, &t, NULL) >=0) { core_proc_cgroup = strappend("COREDUMP_PROC_CGROUP=", t); free(t); if (core_proc_cgroup) IOVEC_SET_STRING(iovec[j++], core_proc_cgroup); } if (get_process_cwd(pid, &t) >= 0) { core_cwd = strjoina("COREDUMP_CWD=", t); free(t); IOVEC_SET_STRING(iovec[j++], core_cwd); } if (get_process_root(pid, &t) >= 0) { core_root = strjoina("COREDUMP_ROOT=", t); free(t); IOVEC_SET_STRING(iovec[j++], core_root); } if (get_process_environ(pid, &t) >= 0) { core_environ = strappend("COREDUMP_ENVIRON=", t); free(t); if (core_environ) IOVEC_SET_STRING(iovec[j++], core_environ); } core_timestamp = strjoin("COREDUMP_TIMESTAMP=", info[INFO_TIMESTAMP], "000000", NULL); if (core_timestamp) IOVEC_SET_STRING(iovec[j++], core_timestamp); IOVEC_SET_STRING(iovec[j++], "MESSAGE_ID=fc2e22bc6ee647b6b90729ab34a250b1"); IOVEC_SET_STRING(iovec[j++], "PRIORITY=2"); /* Vacuum before we write anything again */ coredump_vacuum(-1, arg_keep_free, arg_max_use); /* Always stream the coredump to disk, if that's possible */ r = save_external_coredump(info, uid, &filename, &coredump_fd, &coredump_size); if (r < 0) /* skip whole core dumping part */ goto log; /* If we don't want to keep the coredump on disk, remove it * now, as later on we will lack the privileges for * it. However, we keep the fd to it, so that we can still * process it and log it. */ r = maybe_remove_external_coredump(filename, coredump_size); if (r < 0) goto finish; if (r == 0) { const char *coredump_filename; coredump_filename = strjoina("COREDUMP_FILENAME=", filename); IOVEC_SET_STRING(iovec[j++], coredump_filename); } /* Vacuum again, but exclude the coredump we just created */ coredump_vacuum(coredump_fd, arg_keep_free, arg_max_use); /* Now, let's drop privileges to become the user who owns the * segfaulted process and allocate the coredump memory under * the user's uid. This also ensures that the credentials * journald will see are the ones of the coredumping user, * thus making sure the user gets access to the core * dump. Let's also get rid of all capabilities, if we run as * root, we won't need them anymore. */ r = drop_privileges(uid, gid, 0); if (r < 0) { log_error_errno(r, "Failed to drop privileges: %m"); goto finish; } #ifdef HAVE_ELFUTILS /* Try to get a strack trace if we can */ if (coredump_size <= arg_process_size_max) { _cleanup_free_ char *stacktrace = NULL; r = coredump_make_stack_trace(coredump_fd, exe, &stacktrace); if (r >= 0) core_message = strjoin("MESSAGE=Process ", info[INFO_PID], " (", comm, ") of user ", info[INFO_UID], " dumped core.\n\n", stacktrace, NULL); else if (r == -EINVAL) log_warning("Failed to generate stack trace: %s", dwfl_errmsg(dwfl_errno())); else log_warning_errno(r, "Failed to generate stack trace: %m"); } if (!core_message) #endif log: core_message = strjoin("MESSAGE=Process ", info[INFO_PID], " (", comm, ") of user ", info[INFO_UID], " dumped core.", NULL); if (core_message) IOVEC_SET_STRING(iovec[j++], core_message); /* Optionally store the entire coredump in the journal */ if (IN_SET(arg_storage, COREDUMP_STORAGE_JOURNAL, COREDUMP_STORAGE_BOTH) && coredump_size <= arg_journal_size_max) { size_t sz = 0; /* Store the coredump itself in the journal */ r = allocate_journal_field(coredump_fd, (size_t) coredump_size, &coredump_data, &sz); if (r >= 0) { iovec[j].iov_base = coredump_data; iovec[j].iov_len = sz; j++; } } r = sd_journal_sendv(iovec, j); if (r < 0) log_error_errno(r, "Failed to log coredump: %m"); finish: return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; }
static void test_login(void) { _cleanup_close_pair_ int pair[2] = { -1, -1 }; _cleanup_free_ char *pp = NULL, *qq = NULL; int r, k; uid_t u, u2; char *seat, *type, *class, *display, *remote_user, *remote_host, *display_session; char *session; char *state; char *session2; char *t; char **seats, **sessions, **machines; uid_t *uids; unsigned n; struct pollfd pollfd; sd_login_monitor *m = NULL; assert_se(sd_pid_get_session(0, &session) == 0); printf("session = %s\n", session); assert_se(sd_pid_get_owner_uid(0, &u2) == 0); printf("user = "******"\n", u2); display_session = NULL; r = sd_uid_get_display(u2, &display_session); assert_se(r >= 0 || r == -ENXIO); printf("user's display session = %s\n", strna(display_session)); free(display_session); assert_se(socketpair(AF_UNIX, SOCK_STREAM, 0, pair) == 0); sd_peer_get_session(pair[0], &pp); sd_peer_get_session(pair[1], &qq); assert_se(streq_ptr(pp, qq)); r = sd_uid_get_sessions(u2, false, &sessions); assert_se(r >= 0); assert_se(r == (int) strv_length(sessions)); assert_se(t = strv_join(sessions, ", ")); strv_free(sessions); printf("sessions = %s\n", t); free(t); assert_se(r == sd_uid_get_sessions(u2, false, NULL)); r = sd_uid_get_seats(u2, false, &seats); assert_se(r >= 0); assert_se(r == (int) strv_length(seats)); assert_se(t = strv_join(seats, ", ")); strv_free(seats); printf("seats = %s\n", t); free(t); assert_se(r == sd_uid_get_seats(u2, false, NULL)); r = sd_session_is_active(session); assert_se(r >= 0); printf("active = %s\n", yes_no(r)); r = sd_session_is_remote(session); assert_se(r >= 0); printf("remote = %s\n", yes_no(r)); r = sd_session_get_state(session, &state); assert_se(r >= 0); printf("state = %s\n", state); free(state); assert_se(sd_session_get_uid(session, &u) >= 0); printf("uid = "UID_FMT"\n", u); assert_se(u == u2); assert_se(sd_session_get_type(session, &type) >= 0); printf("type = %s\n", type); free(type); assert_se(sd_session_get_class(session, &class) >= 0); printf("class = %s\n", class); free(class); display = NULL; r = sd_session_get_display(session, &display); assert_se(r >= 0 || r == -ENXIO); printf("display = %s\n", strna(display)); free(display); remote_user = NULL; r = sd_session_get_remote_user(session, &remote_user); assert_se(r >= 0 || r == -ENXIO); printf("remote_user = %s\n", strna(remote_user)); free(remote_user); remote_host = NULL; r = sd_session_get_remote_host(session, &remote_host); assert_se(r >= 0 || r == -ENXIO); printf("remote_host = %s\n", strna(remote_host)); free(remote_host); assert_se(sd_session_get_seat(session, &seat) >= 0); printf("seat = %s\n", seat); r = sd_seat_can_multi_session(seat); assert_se(r >= 0); printf("can do multi session = %s\n", yes_no(r)); r = sd_seat_can_tty(seat); assert_se(r >= 0); printf("can do tty = %s\n", yes_no(r)); r = sd_seat_can_graphical(seat); assert_se(r >= 0); printf("can do graphical = %s\n", yes_no(r)); assert_se(sd_uid_get_state(u, &state) >= 0); printf("state = %s\n", state); assert_se(sd_uid_is_on_seat(u, 0, seat) > 0); k = sd_uid_is_on_seat(u, 1, seat); assert_se(k >= 0); assert_se(!!r == !!r); assert_se(sd_seat_get_active(seat, &session2, &u2) >= 0); printf("session2 = %s\n", session2); printf("uid2 = "UID_FMT"\n", u2); r = sd_seat_get_sessions(seat, &sessions, &uids, &n); assert_se(r >= 0); printf("n_sessions = %i\n", r); assert_se(r == (int) strv_length(sessions)); assert_se(t = strv_join(sessions, ", ")); strv_free(sessions); printf("sessions = %s\n", t); free(t); printf("uids ="); for (k = 0; k < (int) n; k++) printf(" "UID_FMT, uids[k]); printf("\n"); free(uids); assert_se(sd_seat_get_sessions(seat, NULL, NULL, NULL) == r); free(session); free(state); free(session2); free(seat); r = sd_get_seats(&seats); assert_se(r >= 0); assert_se(r == (int) strv_length(seats)); assert_se(t = strv_join(seats, ", ")); strv_free(seats); printf("n_seats = %i\n", r); printf("seats = %s\n", t); free(t); assert_se(sd_get_seats(NULL) == r); r = sd_seat_get_active(NULL, &t, NULL); assert_se(r >= 0); printf("active session on current seat = %s\n", t); free(t); r = sd_get_sessions(&sessions); assert_se(r >= 0); assert_se(r == (int) strv_length(sessions)); assert_se(t = strv_join(sessions, ", ")); strv_free(sessions); printf("n_sessions = %i\n", r); printf("sessions = %s\n", t); free(t); assert_se(sd_get_sessions(NULL) == r); r = sd_get_uids(&uids); assert_se(r >= 0); printf("uids ="); for (k = 0; k < r; k++) printf(" "UID_FMT, uids[k]); printf("\n"); free(uids); printf("n_uids = %i\n", r); assert_se(sd_get_uids(NULL) == r); r = sd_get_machine_names(&machines); assert_se(r >= 0); assert_se(r == (int) strv_length(machines)); assert_se(t = strv_join(machines, ", ")); strv_free(machines); printf("n_machines = %i\n", r); printf("machines = %s\n", t); free(t); r = sd_login_monitor_new("session", &m); assert_se(r >= 0); for (n = 0; n < 5; n++) { usec_t timeout, nw; zero(pollfd); assert_se((pollfd.fd = sd_login_monitor_get_fd(m)) >= 0); assert_se((pollfd.events = sd_login_monitor_get_events(m)) >= 0); assert_se(sd_login_monitor_get_timeout(m, &timeout) >= 0); nw = now(CLOCK_MONOTONIC); r = poll(&pollfd, 1, timeout == (uint64_t) -1 ? -1 : timeout > nw ? (int) ((timeout - nw) / 1000) : 0); assert_se(r >= 0); sd_login_monitor_flush(m); printf("Wake!\n"); } sd_login_monitor_unref(m); }
static int parse_argv(int argc, char *argv[]) { enum { ARG_ICON = 0x100, ARG_TIMEOUT, ARG_ECHO, ARG_NO_TTY, ARG_ACCEPT_CACHED, ARG_MULTIPLE, ARG_ID, ARG_KEYNAME, ARG_NO_OUTPUT, }; static const struct option options[] = { { "help", no_argument, NULL, 'h' }, { "icon", required_argument, NULL, ARG_ICON }, { "timeout", required_argument, NULL, ARG_TIMEOUT }, { "echo", no_argument, NULL, ARG_ECHO }, { "no-tty", no_argument, NULL, ARG_NO_TTY }, { "accept-cached", no_argument, NULL, ARG_ACCEPT_CACHED }, { "multiple", no_argument, NULL, ARG_MULTIPLE }, { "id", required_argument, NULL, ARG_ID }, { "keyname", required_argument, NULL, ARG_KEYNAME }, { "no-output", no_argument, NULL, ARG_NO_OUTPUT }, {} }; int c; assert(argc >= 0); assert(argv); while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) switch (c) { case 'h': help(); return 0; case ARG_ICON: arg_icon = optarg; break; case ARG_TIMEOUT: if (parse_sec(optarg, &arg_timeout) < 0) { log_error("Failed to parse --timeout parameter %s", optarg); return -EINVAL; } break; case ARG_ECHO: arg_flags |= ASK_PASSWORD_ECHO; break; case ARG_NO_TTY: arg_flags |= ASK_PASSWORD_NO_TTY; break; case ARG_ACCEPT_CACHED: arg_flags |= ASK_PASSWORD_ACCEPT_CACHED; break; case ARG_MULTIPLE: arg_multiple = true; break; case ARG_ID: arg_id = optarg; break; case ARG_KEYNAME: arg_keyname = optarg; break; case ARG_NO_OUTPUT: arg_no_output = true; break; case '?': return -EINVAL; default: assert_not_reached("Unhandled option"); } if (argc > optind) { arg_message = strv_join(argv + optind, " "); if (!arg_message) return log_oom(); } return 1; }
int mount_cgroup_controllers(char ***join_controllers) { int r; FILE *f; char buf[LINE_MAX]; Set *controllers; /* Mount all available cgroup controllers that are built into the kernel. */ f = fopen("/proc/cgroups", "re"); if (!f) { log_error("Failed to enumerate cgroup controllers: %m"); return 0; } controllers = set_new(string_hash_func, string_compare_func); if (!controllers) { r = log_oom(); goto finish; } /* Ignore the header line */ (void) fgets(buf, sizeof(buf), f); for (;;) { char *controller; int enabled = 0; if (fscanf(f, "%ms %*i %*i %i", &controller, &enabled) != 2) { if (feof(f)) break; log_error("Failed to parse /proc/cgroups."); r = -EIO; goto finish; } if (!enabled) { free(controller); continue; } r = set_put(controllers, controller); if (r < 0) { log_error("Failed to add controller to set."); free(controller); goto finish; } } for (;;) { MountPoint p; char *controller, *where, *options; char ***k = NULL; controller = set_steal_first(controllers); if (!controller) break; if (join_controllers) for (k = join_controllers; *k; k++) if (strv_find(*k, controller)) break; if (k && *k) { char **i, **j; for (i = *k, j = *k; *i; i++) { if (!streq(*i, controller)) { char *t; t = set_remove(controllers, *i); if (!t) { free(*i); continue; } free(t); } *(j++) = *i; } *j = NULL; options = strv_join(*k, ","); if (!options) { free(controller); r = log_oom(); goto finish; } } else { options = controller; controller = NULL; } where = strappend("/sys/fs/cgroup/", options); if (!where) { free(options); r = log_oom(); goto finish; } zero(p); p.what = "cgroup"; p.where = where; p.type = "cgroup"; p.options = options; p.flags = MS_NOSUID|MS_NOEXEC|MS_NODEV; p.mode = MNT_IN_CONTAINER; r = mount_one(&p, true); free(controller); free(where); if (r < 0) { free(options); goto finish; } if (r > 0 && k && *k) { char **i; for (i = *k; *i; i++) { char *t; t = strappend("/sys/fs/cgroup/", *i); if (!t) { r = log_oom(); free(options); goto finish; } r = symlink(options, t); free(t); if (r < 0 && errno != EEXIST) { log_error("Failed to create symlink: %m"); r = -errno; free(options); goto finish; } } } free(options); } r = 0; finish: set_free_free(controllers); fclose(f); return r; }
int lookup_paths_init( LookupPaths *p, SystemdRunningAs running_as, bool personal, const char *generator, const char *generator_early, const char *generator_late) { const char *e; assert(p); /* First priority is whatever has been passed to us via env * vars */ e = getenv("SYSTEMD_UNIT_PATH"); if (e) { p->unit_path = path_split_and_make_absolute(e); if (!p->unit_path) return -ENOMEM; } else p->unit_path = NULL; if (strv_isempty(p->unit_path)) { /* Nothing is set, so let's figure something out. */ strv_free(p->unit_path); /* For the user units we include share/ in the search * path in order to comply with the XDG basedir * spec. For the system stuff we avoid such * nonsense. OTOH we include /lib in the search path * for the system stuff but avoid it for user * stuff. */ if (running_as == SYSTEMD_USER) { if (personal) p->unit_path = user_dirs(generator, generator_early, generator_late); else p->unit_path = strv_new( /* If you modify this you also want to modify * systemduserunitpath= in systemd.pc.in, and * the arrays in user_dirs() above! */ STRV_IFNOTNULL(generator_early), USER_CONFIG_UNIT_PATH, "/etc/systemd/user", "/run/systemd/user", STRV_IFNOTNULL(generator), "/usr/local/lib/systemd/user", "/usr/local/share/systemd/user", USER_DATA_UNIT_PATH, "/usr/lib/systemd/user", "/usr/share/systemd/user", STRV_IFNOTNULL(generator_late), NULL); if (!p->unit_path) return -ENOMEM; } else { p->unit_path = strv_new( /* If you modify this you also want to modify * systemdsystemunitpath= in systemd.pc.in! */ STRV_IFNOTNULL(generator_early), SYSTEM_CONFIG_UNIT_PATH, "/etc/systemd/system", "/run/systemd/system", STRV_IFNOTNULL(generator), "/usr/local/lib/systemd/system", SYSTEM_DATA_UNIT_PATH, "/usr/lib/systemd/system", #ifdef HAVE_SPLIT_USR "/lib/systemd/system", #endif STRV_IFNOTNULL(generator_late), NULL); if (!p->unit_path) return -ENOMEM; } } if (!path_strv_canonicalize(p->unit_path)) return -ENOMEM; strv_uniq(p->unit_path); if (!strv_isempty(p->unit_path)) { _cleanup_free_ char *t = strv_join(p->unit_path, "\n\t"); if (!t) return -ENOMEM; log_debug("Looking for unit files in (higher priority first):\n\t%s", t); } else { log_debug("Ignoring unit files."); strv_free(p->unit_path); p->unit_path = NULL; } if (running_as == SYSTEMD_SYSTEM) { #ifdef HAVE_SYSV_COMPAT /* /etc/init.d/ compatibility does not matter to users */ e = getenv("SYSTEMD_SYSVINIT_PATH"); if (e) { p->sysvinit_path = path_split_and_make_absolute(e); if (!p->sysvinit_path) return -ENOMEM; } else p->sysvinit_path = NULL; if (strv_isempty(p->sysvinit_path)) { strv_free(p->sysvinit_path); p->sysvinit_path = strv_new( SYSTEM_SYSVINIT_PATH, /* /etc/init.d/ */ NULL); if (!p->sysvinit_path) return -ENOMEM; } e = getenv("SYSTEMD_SYSVRCND_PATH"); if (e) { p->sysvrcnd_path = path_split_and_make_absolute(e); if (!p->sysvrcnd_path) return -ENOMEM; } else p->sysvrcnd_path = NULL; if (strv_isempty(p->sysvrcnd_path)) { strv_free(p->sysvrcnd_path); p->sysvrcnd_path = strv_new( SYSTEM_SYSVRCND_PATH, /* /etc/rcN.d/ */ NULL); if (!p->sysvrcnd_path) return -ENOMEM; } if (!path_strv_canonicalize(p->sysvinit_path)) return -ENOMEM; if (!path_strv_canonicalize(p->sysvrcnd_path)) return -ENOMEM; strv_uniq(p->sysvinit_path); strv_uniq(p->sysvrcnd_path); if (!strv_isempty(p->sysvinit_path)) { _cleanup_free_ char *t = strv_join(p->sysvinit_path, "\n\t"); if (!t) return -ENOMEM; log_debug("Looking for SysV init scripts in:\n\t%s", t); } else { log_debug("Ignoring SysV init scripts."); strv_free(p->sysvinit_path); p->sysvinit_path = NULL; } if (!strv_isempty(p->sysvrcnd_path)) { _cleanup_free_ char *t = strv_join(p->sysvrcnd_path, "\n\t"); if (!t) return -ENOMEM; log_debug("Looking for SysV rcN.d links in:\n\t%s", t); } else { log_debug("Ignoring SysV rcN.d links."); strv_free(p->sysvrcnd_path); p->sysvrcnd_path = NULL; } #else log_debug("SysV init scripts and rcN.d links support disabled"); #endif } return 0; }
/* This function communicates with the kernel to check whether or not it should allow the access. If the machine is in permissive mode it will return ok. Audit messages will still be generated if the access would be denied in enforcing mode. */ int mac_selinux_generic_access_check( sd_bus_message *message, const char *path, const char *permission, sd_bus_error *error) { _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL; const char *tclass = NULL, *scon = NULL; struct audit_info audit_info = {}; _cleanup_free_ char *cl = NULL; char *fcon = NULL; char **cmdline = NULL; int r = 0; assert(message); assert(permission); assert(error); r = access_init(error); if (r <= 0) return r; r = sd_bus_query_sender_creds( message, SD_BUS_CREDS_PID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_EGID| SD_BUS_CREDS_CMDLINE|SD_BUS_CREDS_AUDIT_LOGIN_UID| SD_BUS_CREDS_SELINUX_CONTEXT| SD_BUS_CREDS_AUGMENT /* get more bits from /proc */, &creds); if (r < 0) goto finish; /* The SELinux context is something we really should have * gotten directly from the message or sender, and not be an * augmented field. If it was augmented we cannot use it for * authorization, since this is racy and vulnerable. Let's add * an extra check, just in case, even though this really * shouldn't be possible. */ assert_return((sd_bus_creds_get_augmented_mask(creds) & SD_BUS_CREDS_SELINUX_CONTEXT) == 0, -EPERM); r = sd_bus_creds_get_selinux_context(creds, &scon); if (r < 0) goto finish; if (path) { /* Get the file context of the unit file */ r = getfilecon_raw(path, &fcon); if (r < 0) { r = sd_bus_error_setf(error, SD_BUS_ERROR_ACCESS_DENIED, "Failed to get file context on %s.", path); goto finish; } tclass = "service"; } else { r = getcon_raw(&fcon); if (r < 0) { r = sd_bus_error_setf(error, SD_BUS_ERROR_ACCESS_DENIED, "Failed to get current context."); goto finish; } tclass = "system"; } sd_bus_creds_get_cmdline(creds, &cmdline); cl = strv_join(cmdline, " "); audit_info.creds = creds; audit_info.path = path; audit_info.cmdline = cl; r = selinux_check_access(scon, fcon, tclass, permission, &audit_info); if (r < 0) r = sd_bus_error_setf(error, SD_BUS_ERROR_ACCESS_DENIED, "SELinux policy denies access."); log_debug("SELinux access check scon=%s tcon=%s tclass=%s perm=%s path=%s cmdline=%s: %i", scon, fcon, tclass, permission, path, cl, r); finish: freecon(fcon); if (r < 0 && security_getenforce() != 1) { sd_bus_error_free(error); r = 0; } return r; }
/* This function communicates with the kernel to check whether or not it should allow the access. If the machine is in permissive mode it will return ok. Audit messages will still be generated if the access would be denied in enforcing mode. */ int mac_selinux_generic_access_check( sd_bus_message *message, bool system, const char *path, const char *permission, sd_bus_error *error) { #ifdef HAVE_SELINUX _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL; const char *tclass = NULL, *scon = NULL; struct audit_info audit_info = {}; _cleanup_free_ char *cl = NULL; security_context_t fcon = NULL; char **cmdline = NULL; int r = 0; assert(message); assert(permission); assert(error); if (!mac_selinux_use()) return 0; r = mac_selinux_access_init(error); if (r < 0) return r; r = sd_bus_query_sender_creds( message, SD_BUS_CREDS_PID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_EGID| SD_BUS_CREDS_CMDLINE|SD_BUS_CREDS_AUDIT_LOGIN_UID| SD_BUS_CREDS_SELINUX_CONTEXT| SD_BUS_CREDS_AUGMENT /* get more bits from /proc */, &creds); if (r < 0) goto finish; r = sd_bus_creds_get_selinux_context(creds, &scon); if (r < 0) goto finish; tclass = "service"; if (path && !system) { /* Get the file context of the unit file */ r = getfilecon_raw(path, &fcon); if (r < 0) { r = sd_bus_error_setf(error, SD_BUS_ERROR_ACCESS_DENIED, "Failed to get file context on %s.", path); goto finish; } } else { r = getcon_raw(&fcon); if (r < 0) { r = sd_bus_error_setf(error, SD_BUS_ERROR_ACCESS_DENIED, "Failed to get current context."); goto finish; } if (system) tclass = "system"; } sd_bus_creds_get_cmdline(creds, &cmdline); cl = strv_join(cmdline, " "); audit_info.creds = creds; audit_info.path = path; audit_info.cmdline = cl; r = selinux_check_access(scon, fcon, tclass, permission, &audit_info); if (r < 0) r = sd_bus_error_setf(error, SD_BUS_ERROR_ACCESS_DENIED, "SELinux policy denies access."); log_debug("SELinux access check scon=%s tcon=%s tclass=%s perm=%s path=%s cmdline=%s: %i", scon, fcon, tclass, permission, path, cl, r); finish: freecon(fcon); if (r < 0 && security_getenforce() != 1) { sd_bus_error_free(error); r = 0; } return r; #else return 0; #endif }
int main(int argc, char* argv[]) { _cleanup_free_ char *status = NULL, *cpid = NULL, *n = NULL; _cleanup_strv_free_ char **final_env = NULL; char* our_env[4]; unsigned i = 0; int r; log_parse_environment(); log_open(); r = parse_argv(argc, argv); if (r <= 0) goto finish; if (arg_booted) return sd_booted() <= 0; if (arg_readahead) { r = sd_readahead(arg_readahead); if (r < 0) { log_error("Failed to issue read-ahead control command: %s", strerror(-r)); goto finish; } } if (arg_ready) our_env[i++] = (char*) "READY=1"; if (arg_status) { status = strappend("STATUS=", arg_status); if (!status) { r = log_oom(); goto finish; } our_env[i++] = status; } if (arg_pid > 0) { if (asprintf(&cpid, "MAINPID="PID_FMT, arg_pid) < 0) { r = log_oom(); goto finish; } our_env[i++] = cpid; } our_env[i++] = NULL; final_env = strv_env_merge(2, our_env, argv + optind); if (!final_env) { r = log_oom(); goto finish; } if (strv_length(final_env) <= 0) { r = 0; goto finish; } n = strv_join(final_env, "\n"); if (!n) { r = log_oom(); goto finish; } r = sd_pid_notify(arg_pid, false, n); if (r < 0) { log_error_errno(r, "Failed to notify init system: %m"); goto finish; } if (r == 0) r = -ENOTSUP; finish: return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; }
int main(int argc, char* argv[]) { int r, k; uid_t u, u2; char *seat, *type, *class, *display; char *session; char *state; char *session2; char *t; char **seats, **sessions; uid_t *uids; unsigned n; struct pollfd pollfd; sd_login_monitor *m; assert_se(sd_pid_get_session(0, &session) == 0); printf("session = %s\n", session); assert_se(sd_pid_get_owner_uid(0, &u2) == 0); printf("user = %lu\n", (unsigned long) u2); r = sd_uid_get_sessions(u2, false, &sessions); assert_se(r >= 0); assert_se(r == (int) strv_length(sessions)); assert_se(t = strv_join(sessions, ", ")); strv_free(sessions); printf("sessions = %s\n", t); free(t); assert_se(r == sd_uid_get_sessions(u2, false, NULL)); r = sd_uid_get_seats(u2, false, &seats); assert_se(r >= 0); assert_se(r == (int) strv_length(seats)); assert_se(t = strv_join(seats, ", ")); strv_free(seats); printf("seats = %s\n", t); free(t); assert_se(r == sd_uid_get_seats(u2, false, NULL)); r = sd_session_is_active(session); assert_se(r >= 0); printf("active = %s\n", yes_no(r)); r = sd_session_get_state(session, &state); assert_se(r >= 0); printf("state = %s\n", state); free(state); assert_se(sd_session_get_uid(session, &u) >= 0); printf("uid = %lu\n", (unsigned long) u); assert_se(u == u2); assert_se(sd_session_get_type(session, &type) >= 0); printf("type = %s\n", type); free(type); assert_se(sd_session_get_class(session, &class) >= 0); printf("class = %s\n", class); free(class); assert_se(sd_session_get_display(session, &display) >= 0); printf("display = %s\n", display); free(display); assert_se(sd_session_get_seat(session, &seat) >= 0); printf("seat = %s\n", seat); r = sd_seat_can_multi_session(seat); assert_se(r >= 0); printf("can do multi session = %s\n", yes_no(r)); r = sd_seat_can_tty(seat); assert_se(r >= 0); printf("can do tty = %s\n", yes_no(r)); r = sd_seat_can_graphical(seat); assert_se(r >= 0); printf("can do graphical = %s\n", yes_no(r)); assert_se(sd_uid_get_state(u, &state) >= 0); printf("state = %s\n", state); assert_se(sd_uid_is_on_seat(u, 0, seat) > 0); k = sd_uid_is_on_seat(u, 1, seat); assert_se(k >= 0); assert_se(!!r == !!r); assert_se(sd_seat_get_active(seat, &session2, &u2) >= 0); printf("session2 = %s\n", session2); printf("uid2 = %lu\n", (unsigned long) u2); r = sd_seat_get_sessions(seat, &sessions, &uids, &n); assert_se(r >= 0); printf("n_sessions = %i\n", r); assert_se(r == (int) strv_length(sessions)); assert_se(t = strv_join(sessions, ", ")); strv_free(sessions); printf("sessions = %s\n", t); free(t); printf("uids ="); for (k = 0; k < (int) n; k++) printf(" %lu", (unsigned long) uids[k]); printf("\n"); free(uids); assert_se(sd_seat_get_sessions(seat, NULL, NULL, NULL) == r); free(session); free(state); free(session2); free(seat); r = sd_get_seats(&seats); assert_se(r >= 0); assert_se(r == (int) strv_length(seats)); assert_se(t = strv_join(seats, ", ")); strv_free(seats); printf("n_seats = %i\n", r); printf("seats = %s\n", t); free(t); assert_se(sd_get_seats(NULL) == r); r = sd_seat_get_active(NULL, &t, NULL); assert_se(r >= 0); printf("active session on current seat = %s\n", t); free(t); r = sd_get_sessions(&sessions); assert_se(r >= 0); assert_se(r == (int) strv_length(sessions)); assert_se(t = strv_join(sessions, ", ")); strv_free(sessions); printf("n_sessions = %i\n", r); printf("sessions = %s\n", t); free(t); assert_se(sd_get_sessions(NULL) == r); r = sd_get_uids(&uids); assert_se(r >= 0); printf("uids ="); for (k = 0; k < r; k++) printf(" %lu", (unsigned long) uids[k]); printf("\n"); free(uids); printf("n_uids = %i\n", r); assert_se(sd_get_uids(NULL) == r); r = sd_login_monitor_new("session", &m); assert_se(r >= 0); zero(pollfd); pollfd.fd = sd_login_monitor_get_fd(m); pollfd.events = POLLIN; for (n = 0; n < 5; n++) { r = poll(&pollfd, 1, -1); assert_se(r >= 0); sd_login_monitor_flush(m); printf("Wake!\n"); } sd_login_monitor_unref(m); return 0; }
int main(int argc, char* argv[]) { char* our_env[4], **final_env = NULL; unsigned i = 0; char *status = NULL, *cpid = NULL, *n = NULL; int r, retval = EXIT_FAILURE; log_parse_environment(); log_open(); r = parse_argv(argc, argv); if (r <= 0) { retval = r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; goto finish; } if (arg_booted) return sd_booted() <= 0; if (arg_readahead) { if ((r = sd_readahead(arg_readahead)) < 0) { log_error("Failed to issue read-ahead control command: %s", strerror(-r)); goto finish; } } if (arg_ready) our_env[i++] = (char*) "READY=1"; if (arg_status) { if (!(status = strappend("STATUS=", arg_status))) { log_error("Failed to allocate STATUS string."); goto finish; } our_env[i++] = status; } if (arg_pid > 0) { if (asprintf(&cpid, "MAINPID=%lu", (unsigned long) arg_pid) < 0) { log_error("Failed to allocate MAINPID string."); goto finish; } our_env[i++] = cpid; } our_env[i++] = NULL; if (!(final_env = strv_env_merge(2, our_env, argv + optind))) { log_error("Failed to merge string sets."); goto finish; } if (strv_length(final_env) <= 0) { retval = EXIT_SUCCESS; goto finish; } if (!(n = strv_join(final_env, "\n"))) { log_error("Failed to concatenate strings."); goto finish; } if ((r = sd_notify(false, n)) < 0) { log_error("Failed to notify init system: %s", strerror(-r)); goto finish; } retval = r <= 0 ? EXIT_FAILURE : EXIT_SUCCESS; finish: free(status); free(cpid); free(n); strv_free(final_env); return retval; }
int mount_cgroup_controllers(char ***join_controllers) { _cleanup_set_free_free_ Set *controllers = NULL; int r; if (!cg_is_legacy_wanted()) return 0; /* Mount all available cgroup controllers that are built into the kernel. */ controllers = set_new(&string_hash_ops); if (!controllers) return log_oom(); r = cg_kernel_controllers(controllers); if (r < 0) return log_error_errno(r, "Failed to enumerate cgroup controllers: %m"); for (;;) { _cleanup_free_ char *options = NULL, *controller = NULL, *where = NULL; MountPoint p = { .what = "cgroup", .type = "cgroup", .flags = MS_NOSUID|MS_NOEXEC|MS_NODEV, .mode = MNT_IN_CONTAINER, }; char ***k = NULL; controller = set_steal_first(controllers); if (!controller) break; if (join_controllers) for (k = join_controllers; *k; k++) if (strv_find(*k, controller)) break; if (k && *k) { char **i, **j; for (i = *k, j = *k; *i; i++) { if (!streq(*i, controller)) { _cleanup_free_ char *t; t = set_remove(controllers, *i); if (!t) { free(*i); continue; } } *(j++) = *i; } *j = NULL; options = strv_join(*k, ","); if (!options) return log_oom(); } else { options = controller; controller = NULL; } where = strappend("/sys/fs/cgroup/", options); if (!where) return log_oom(); p.where = where; p.options = options; r = mount_one(&p, true); if (r < 0) return r; if (r > 0 && k && *k) { char **i; for (i = *k; *i; i++) { _cleanup_free_ char *t = NULL; t = strappend("/sys/fs/cgroup/", *i); if (!t) return log_oom(); r = symlink(options, t); if (r < 0 && errno != EEXIST) return log_error_errno(errno, "Failed to create symlink %s: %m", t); #ifdef SMACK_RUN_LABEL r = mac_smack_copy(t, options); if (r < 0 && r != -EOPNOTSUPP) return log_error_errno(r, "Failed to copy smack label from %s to %s: %m", options, t); #endif } } } /* Now that we mounted everything, let's make the tmpfs the * cgroup file systems are mounted into read-only. */ (void) mount("tmpfs", "/sys/fs/cgroup", "tmpfs", MS_REMOUNT|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_STRICTATIME|MS_RDONLY, "mode=755"); return 0; } #if defined(HAVE_SELINUX) || defined(HAVE_SMACK) static int nftw_cb( const char *fpath, const struct stat *sb, int tflag, struct FTW *ftwbuf) { /* No need to label /dev twice in a row... */ if (_unlikely_(ftwbuf->level == 0)) return FTW_CONTINUE; label_fix(fpath, false, false); /* /run/initramfs is static data and big, no need to * dynamically relabel its contents at boot... */ if (_unlikely_(ftwbuf->level == 1 && tflag == FTW_D && streq(fpath, "/run/initramfs"))) return FTW_SKIP_SUBTREE; return FTW_CONTINUE; }; #endif int mount_setup(bool loaded_policy) { unsigned i; int r = 0; for (i = 0; i < ELEMENTSOF(mount_table); i ++) { int j; j = mount_one(mount_table + i, loaded_policy); if (j != 0 && r >= 0) r = j; } if (r < 0) return r; #if defined(HAVE_SELINUX) || defined(HAVE_SMACK) /* Nodes in devtmpfs and /run need to be manually updated for * the appropriate labels, after mounting. The other virtual * API file systems like /sys and /proc do not need that, they * use the same label for all their files. */ if (loaded_policy) { usec_t before_relabel, after_relabel; char timespan[FORMAT_TIMESPAN_MAX]; before_relabel = now(CLOCK_MONOTONIC); nftw("/dev", nftw_cb, 64, FTW_MOUNT|FTW_PHYS|FTW_ACTIONRETVAL); nftw("/run", nftw_cb, 64, FTW_MOUNT|FTW_PHYS|FTW_ACTIONRETVAL); after_relabel = now(CLOCK_MONOTONIC); log_info("Relabelled /dev and /run in %s.", format_timespan(timespan, sizeof(timespan), after_relabel - before_relabel, 0)); } #endif /* Create a few default symlinks, which are normally created * by udevd, but some scripts might need them before we start * udevd. */ dev_setup(NULL, UID_INVALID, GID_INVALID); /* Mark the root directory as shared in regards to mount * propagation. The kernel defaults to "private", but we think * it makes more sense to have a default of "shared" so that * nspawn and the container tools work out of the box. If * specific setups need other settings they can reset the * propagation mode to private if needed. */ if (detect_container() <= 0) if (mount(NULL, "/", NULL, MS_REC|MS_SHARED, NULL) < 0) log_warning_errno(errno, "Failed to set up the root directory for shared mount propagation: %m"); /* Create a few directories we always want around, Note that * sd_booted() checks for /run/systemd/system, so this mkdir * really needs to stay for good, otherwise software that * copied sd-daemon.c into their sources will misdetect * systemd. */ mkdir_label("/run/systemd", 0755); mkdir_label("/run/systemd/system", 0755); mkdir_label("/run/systemd/inaccessible", 0000); return 0; }
int main(int argc, char *argv[]) { int r, exit_code = 0; DBusConnection *bus = NULL; DBusError error; int fd = -1; dbus_error_init(&error); log_parse_environment(); log_open(); r = parse_argv(argc, argv); if (r <= 0) goto finish; bus = dbus_bus_get_private(DBUS_BUS_SYSTEM, &error); if (!bus) { log_error("Failed to connect to bus: %s", bus_error_message(&error)); r = -EIO; goto finish; } if (arg_action == ACTION_LIST) { r = print_inhibitors(bus, &error); if (r < 0) { log_error("Failed to list inhibitors: %s", bus_error_message_or_strerror(&error, -r)); goto finish; } } else { char *w = NULL; pid_t pid; if (!arg_who) arg_who = w = strv_join(argv + optind, " "); fd = inhibit(bus, &error); free(w); if (fd < 0) { log_error("Failed to inhibit: %s", bus_error_message_or_strerror(&error, -r)); r = fd; goto finish; } pid = fork(); if (pid < 0) { log_error("Failed to fork: %m"); r = -errno; goto finish; } if (pid == 0) { /* Child */ close_nointr_nofail(fd); execvp(argv[optind], argv + optind); log_error("Failed to execute %s: %m", argv[optind]); _exit(EXIT_FAILURE); } r = wait_for_terminate_and_warn(argv[optind], pid); if (r >= 0) exit_code = r; } finish: if (bus) { dbus_connection_close(bus); dbus_connection_unref(bus); } dbus_error_free(&error); if (fd >= 0) close_nointr_nofail(fd); return r < 0 ? EXIT_FAILURE : exit_code; }
int main(int argc, char *argv[]) { _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; _cleanup_bus_close_unref_ sd_bus *bus = NULL; int r; log_parse_environment(); log_open(); r = parse_argv(argc, argv); if (r < 0) return EXIT_FAILURE; if (r == 0) return EXIT_SUCCESS; r = sd_bus_default_system(&bus); if (r < 0) { log_error("Failed to connect to bus: %s", strerror(-r)); return EXIT_FAILURE; } if (arg_action == ACTION_LIST) { r = print_inhibitors(bus, &error); if (r < 0) { log_error("Failed to list inhibitors: %s", bus_error_message(&error, -r)); return EXIT_FAILURE; } } else { _cleanup_close_ int fd = -1; _cleanup_free_ char *w = NULL; pid_t pid; if (!arg_who) arg_who = w = strv_join(argv + optind, " "); fd = inhibit(bus, &error); if (fd < 0) { log_error("Failed to inhibit: %s", bus_error_message(&error, -r)); return EXIT_FAILURE; } pid = fork(); if (pid < 0) { log_error("Failed to fork: %m"); return EXIT_FAILURE; } if (pid == 0) { /* Child */ close_all_fds(NULL, 0); execvp(argv[optind], argv + optind); log_error("Failed to execute %s: %m", argv[optind]); _exit(EXIT_FAILURE); } r = wait_for_terminate_and_warn(argv[optind], pid); return r < 0 ? EXIT_FAILURE : r; } return 0; }
static void test_login(void) { int r, k; uid_t u, u2; char *seat, *type, *class, *display; char *session; char *state; char *session2; char *t; char **seats, **sessions, **machines; uid_t *uids; unsigned n; struct pollfd pollfd; sd_login_monitor *m; assert_se(sd_pid_get_session(0, &session) == 0); printf("session = %s\n", session); assert_se(sd_pid_get_owner_uid(0, &u2) == 0); printf("user = %lu\n", (unsigned long) u2); r = sd_uid_get_sessions(u2, false, &sessions); assert_se(r >= 0); assert_se(r == (int) strv_length(sessions)); assert_se(t = strv_join(sessions, ", ")); strv_free(sessions); printf("sessions = %s\n", t); free(t); assert_se(r == sd_uid_get_sessions(u2, false, NULL)); r = sd_uid_get_seats(u2, false, &seats); assert_se(r >= 0); assert_se(r == (int) strv_length(seats)); assert_se(t = strv_join(seats, ", ")); strv_free(seats); printf("seats = %s\n", t); free(t); assert_se(r == sd_uid_get_seats(u2, false, NULL)); r = sd_session_is_active(session); assert_se(r >= 0); printf("active = %s\n", yes_no(r)); r = sd_session_get_state(session, &state); assert_se(r >= 0); printf("state = %s\n", state); free(state); assert_se(sd_session_get_uid(session, &u) >= 0); printf("uid = %lu\n", (unsigned long) u); assert_se(u == u2); assert_se(sd_session_get_type(session, &type) >= 0); printf("type = %s\n", type); free(type); assert_se(sd_session_get_class(session, &class) >= 0); printf("class = %s\n", class); free(class); assert_se(sd_session_get_display(session, &display) >= 0); printf("display = %s\n", display); free(display); assert_se(sd_session_get_seat(session, &seat) >= 0); printf("seat = %s\n", seat); r = sd_seat_can_multi_session(seat); assert_se(r >= 0); printf("can do multi session = %s\n", yes_no(r)); r = sd_seat_can_tty(seat); assert_se(r >= 0); printf("can do tty = %s\n", yes_no(r)); r = sd_seat_can_graphical(seat); assert_se(r >= 0); printf("can do graphical = %s\n", yes_no(r)); assert_se(sd_uid_get_state(u, &state) >= 0); printf("state = %s\n", state); assert_se(sd_uid_is_on_seat(u, 0, seat) > 0); k = sd_uid_is_on_seat(u, 1, seat); assert_se(k >= 0); assert_se(!!r == !!r); assert_se(sd_seat_get_active(seat, &session2, &u2) >= 0); printf("session2 = %s\n", session2); printf("uid2 = %lu\n", (unsigned long) u2); r = sd_seat_get_sessions(seat, &sessions, &uids, &n); assert_se(r >= 0); printf("n_sessions = %i\n", r); assert_se(r == (int) strv_length(sessions)); assert_se(t = strv_join(sessions, ", ")); strv_free(sessions); printf("sessions = %s\n", t); free(t); printf("uids ="); for (k = 0; k < (int) n; k++) printf(" %lu", (unsigned long) uids[k]); printf("\n"); free(uids); assert_se(sd_seat_get_sessions(seat, NULL, NULL, NULL) == r); free(session); free(state); free(session2); free(seat); r = sd_get_seats(&seats); assert_se(r >= 0); assert_se(r == (int) strv_length(seats)); assert_se(t = strv_join(seats, ", ")); strv_free(seats); printf("n_seats = %i\n", r); printf("seats = %s\n", t); free(t); assert_se(sd_get_seats(NULL) == r); r = sd_seat_get_active(NULL, &t, NULL); assert_se(r >= 0); printf("active session on current seat = %s\n", t); free(t); r = sd_get_sessions(&sessions); assert_se(r >= 0); assert_se(r == (int) strv_length(sessions)); assert_se(t = strv_join(sessions, ", ")); strv_free(sessions); printf("n_sessions = %i\n", r); printf("sessions = %s\n", t); free(t); assert_se(sd_get_sessions(NULL) == r); r = sd_get_uids(&uids); assert_se(r >= 0); printf("uids ="); for (k = 0; k < r; k++) printf(" %lu", (unsigned long) uids[k]); printf("\n"); free(uids); printf("n_uids = %i\n", r); assert_se(sd_get_uids(NULL) == r); r = sd_get_machine_names(&machines); assert_se(r >= 0); assert_se(r == (int) strv_length(machines)); assert_se(t = strv_join(machines, ", ")); strv_free(machines); printf("n_machines = %i\n", r); printf("machines = %s\n", t); free(t); r = sd_login_monitor_new("session", &m); assert_se(r >= 0); for (n = 0; n < 5; n++) { usec_t timeout, nw; zero(pollfd); assert_se((pollfd.fd = sd_login_monitor_get_fd(m)) >= 0); assert_se((pollfd.events = sd_login_monitor_get_events(m)) >= 0); assert_se(sd_login_monitor_get_timeout(m, &timeout) >= 0); nw = now(CLOCK_MONOTONIC); r = poll(&pollfd, 1, timeout == (uint64_t) -1 ? -1 : timeout > nw ? (int) ((timeout - nw) / 1000) : 0); assert_se(r >= 0); sd_login_monitor_flush(m); printf("Wake!\n"); } sd_login_monitor_unref(m); }
int lookup_paths_init( LookupPaths *p, SystemdRunningAs running_as, bool personal, const char *root_dir, const char *generator, const char *generator_early, const char *generator_late) { const char *e; bool append = false; /* Add items from SYSTEMD_UNIT_PATH before normal directories */ assert(p); /* First priority is whatever has been passed to us via env * vars */ e = getenv("SYSTEMD_UNIT_PATH"); if (e) { if (endswith(e, ":")) { e = strndupa(e, strlen(e) - 1); append = true; } /* FIXME: empty components in other places should be * rejected. */ p->unit_path = path_split_and_make_absolute(e); if (!p->unit_path) return -ENOMEM; } else p->unit_path = NULL; if (!p->unit_path || append) { /* Let's figure something out. */ _cleanup_strv_free_ char **unit_path; int r; /* For the user units we include share/ in the search * path in order to comply with the XDG basedir spec. * For the system stuff we avoid such nonsense. OTOH * we include /lib in the search path for the system * stuff but avoid it for user stuff. */ if (running_as == SYSTEMD_USER) { if (personal) unit_path = user_dirs(generator, generator_early, generator_late); else unit_path = strv_new( /* If you modify this you also want to modify * systemduserunitpath= in systemd.pc.in, and * the arrays in user_dirs() above! */ STRV_IFNOTNULL(generator_early), USER_CONFIG_UNIT_PATH, "/etc/systemd/user", "/run/systemd/user", STRV_IFNOTNULL(generator), "/usr/local/lib/systemd/user", "/usr/local/share/systemd/user", USER_DATA_UNIT_PATH, "/usr/lib/systemd/user", "/usr/share/systemd/user", STRV_IFNOTNULL(generator_late), NULL); } else unit_path = strv_new( /* If you modify this you also want to modify * systemdsystemunitpath= in systemd.pc.in! */ STRV_IFNOTNULL(generator_early), SYSTEM_CONFIG_UNIT_PATH, "/etc/systemd/system", "/run/systemd/system", STRV_IFNOTNULL(generator), "/usr/local/lib/systemd/system", SYSTEM_DATA_UNIT_PATH, "/usr/lib/systemd/system", #ifdef HAVE_SPLIT_USR "/lib/systemd/system", #endif STRV_IFNOTNULL(generator_late), NULL); if (!unit_path) return -ENOMEM; r = strv_extend_strv(&p->unit_path, unit_path); if (r < 0) return r; } if (!path_strv_resolve_uniq(p->unit_path, root_dir)) return -ENOMEM; if (!strv_isempty(p->unit_path)) { _cleanup_free_ char *t = strv_join(p->unit_path, "\n\t"); if (!t) return -ENOMEM; log_debug("Looking for unit files in (higher priority first):\n\t%s", t); } else { log_debug("Ignoring unit files."); strv_free(p->unit_path); p->unit_path = NULL; } if (running_as == SYSTEMD_SYSTEM) { #ifdef HAVE_SYSV_COMPAT /* /etc/init.d/ compatibility does not matter to users */ e = getenv("SYSTEMD_SYSVINIT_PATH"); if (e) { p->sysvinit_path = path_split_and_make_absolute(e); if (!p->sysvinit_path) return -ENOMEM; } else p->sysvinit_path = NULL; if (strv_isempty(p->sysvinit_path)) { strv_free(p->sysvinit_path); p->sysvinit_path = strv_new( SYSTEM_SYSVINIT_PATH, /* /etc/init.d/ */ NULL); if (!p->sysvinit_path) return -ENOMEM; } e = getenv("SYSTEMD_SYSVRCND_PATH"); if (e) { p->sysvrcnd_path = path_split_and_make_absolute(e); if (!p->sysvrcnd_path) return -ENOMEM; } else p->sysvrcnd_path = NULL; if (strv_isempty(p->sysvrcnd_path)) { strv_free(p->sysvrcnd_path); p->sysvrcnd_path = strv_new( SYSTEM_SYSVRCND_PATH, /* /etc/rcN.d/ */ NULL); if (!p->sysvrcnd_path) return -ENOMEM; } if (!path_strv_resolve_uniq(p->sysvinit_path, root_dir)) return -ENOMEM; if (!path_strv_resolve_uniq(p->sysvrcnd_path, root_dir)) return -ENOMEM; if (!strv_isempty(p->sysvinit_path)) { _cleanup_free_ char *t = strv_join(p->sysvinit_path, "\n\t"); if (!t) return -ENOMEM; log_debug("Looking for SysV init scripts in:\n\t%s", t); } else { log_debug("Ignoring SysV init scripts."); strv_free(p->sysvinit_path); p->sysvinit_path = NULL; } if (!strv_isempty(p->sysvrcnd_path)) { _cleanup_free_ char *t = strv_join(p->sysvrcnd_path, "\n\t"); if (!t) return -ENOMEM; log_debug("Looking for SysV rcN.d links in:\n\t%s", t); } else { log_debug("Ignoring SysV rcN.d links."); strv_free(p->sysvrcnd_path); p->sysvrcnd_path = NULL; } #else log_debug("SysV init scripts and rcN.d links support disabled"); #endif } return 0; }
int main(int argc, char* argv[]) { _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; _cleanup_free_ char *description = NULL, *command = NULL; int r, retval = EXIT_SUCCESS; log_parse_environment(); log_open(); r = parse_argv(argc, argv); if (r <= 0) goto finish; if (argc > optind && arg_transport == BUS_TRANSPORT_LOCAL) { /* Patch in an absolute path */ r = find_binary(argv[optind], &command); if (r < 0) { log_error_errno(r, "Failed to find executable %s: %m", argv[optind]); goto finish; } argv[optind] = command; } if (!arg_description) { description = strv_join(argv + optind, " "); if (!description) { r = log_oom(); goto finish; } if (arg_unit && isempty(description)) { r = free_and_strdup(&description, arg_unit); if (r < 0) goto finish; } arg_description = description; } /* If --wait is used connect via the bus, unconditionally, as ref/unref is not supported via the limited direct * connection */ if (arg_wait) r = bus_connect_transport(arg_transport, arg_host, arg_user, &bus); else r = bus_connect_transport_systemd(arg_transport, arg_host, arg_user, &bus); if (r < 0) { log_error_errno(r, "Failed to create bus connection: %m"); goto finish; } if (arg_scope) r = start_transient_scope(bus, argv + optind); else if (with_timer()) r = start_transient_timer(bus, argv + optind); else r = start_transient_service(bus, argv + optind, &retval); finish: strv_free(arg_environment); strv_free(arg_property); strv_free(arg_timer_property); return r < 0 ? EXIT_FAILURE : retval; }