void server_process_native_file( Server *s, int fd, const struct ucred *ucred, const struct timeval *tv, const char *label, size_t label_len) { struct stat st; bool sealed; int r; /* Data is in the passed fd, since it didn't fit in a * datagram. */ assert(s); assert(fd >= 0); /* If it's a memfd, check if it is sealed. If so, we can just * use map it and use it, and do not need to copy the data * out. */ sealed = memfd_get_sealed(fd) > 0; if (!sealed && (!ucred || ucred->uid != 0)) { _cleanup_free_ char *sl = NULL, *k = NULL; const char *e; /* If this is not a sealed memfd, and the peer is unknown or * unprivileged, then verify the path. */ if (asprintf(&sl, "/proc/self/fd/%i", fd) < 0) { log_oom(); return; } r = readlink_malloc(sl, &k); if (r < 0) { log_error_errno(r, "readlink(%s) failed: %m", sl); return; } e = path_startswith(k, "/dev/shm/"); if (!e) e = path_startswith(k, "/tmp/"); if (!e) e = path_startswith(k, "/var/tmp/"); if (!e) { log_error("Received file outside of allowed directories. Refusing."); return; } if (!filename_is_valid(e)) { log_error("Received file in subdirectory of allowed directories. Refusing."); return; } } if (fstat(fd, &st) < 0) { log_error_errno(errno, "Failed to stat passed file, ignoring: %m"); return; } if (!S_ISREG(st.st_mode)) { log_error("File passed is not regular. Ignoring."); return; } if (st.st_size <= 0) return; if (st.st_size > ENTRY_SIZE_MAX) { log_error("File passed too large. Ignoring."); return; } if (sealed) { void *p; size_t ps; /* The file is sealed, we can just map it and use it. */ ps = PAGE_ALIGN(st.st_size); p = mmap(NULL, ps, PROT_READ, MAP_PRIVATE, fd, 0); if (p == MAP_FAILED) { log_error_errno(errno, "Failed to map memfd, ignoring: %m"); return; } server_process_native_message(s, p, st.st_size, ucred, tv, label, label_len); assert_se(munmap(p, ps) >= 0); } else { _cleanup_free_ void *p = NULL; struct statvfs vfs; ssize_t n; if (fstatvfs(fd, &vfs) < 0) { log_error_errno(errno, "Failed to stat file system of passed file, ignoring: %m"); return; } /* Refuse operating on file systems that have * mandatory locking enabled, see: * * https://github.com/systemd/systemd/issues/1822 */ if (vfs.f_flag & ST_MANDLOCK) { log_error("Received file descriptor from file system with mandatory locking enable, refusing."); return; } /* Make the fd non-blocking. On regular files this has * the effect of bypassing mandatory locking. Of * course, this should normally not be necessary given * the check above, but let's better be safe than * sorry, after all NFS is pretty confusing regarding * file system flags, and we better don't trust it, * and so is SMB. */ r = fd_nonblock(fd, true); if (r < 0) { log_error_errno(r, "Failed to make fd non-blocking, ignoring: %m"); return; } /* The file is not sealed, we can't map the file here, since * clients might then truncate it and trigger a SIGBUS for * us. So let's stupidly read it */ p = malloc(st.st_size); if (!p) { log_oom(); return; } n = pread(fd, p, st.st_size, 0); if (n < 0) log_error_errno(errno, "Failed to read file, ignoring: %m"); else if (n > 0) server_process_native_message(s, p, n, ucred, tv, label, label_len); } }
static int get_gateway_description( sd_netlink *rtnl, sd_hwdb *hwdb, int ifindex, int family, union in_addr_union *gateway, char **gateway_description) { _cleanup_netlink_message_unref_ sd_netlink_message *req = NULL, *reply = NULL; sd_netlink_message *m; int r; assert(rtnl); assert(ifindex >= 0); assert(family == AF_INET || family == AF_INET6); assert(gateway); assert(gateway_description); r = sd_rtnl_message_new_neigh(rtnl, &req, RTM_GETNEIGH, ifindex, family); if (r < 0) return r; r = sd_netlink_message_request_dump(req, true); if (r < 0) return r; r = sd_netlink_call(rtnl, req, 0, &reply); if (r < 0) return r; for (m = reply; m; m = sd_netlink_message_next(m)) { union in_addr_union gw = {}; struct ether_addr mac = {}; uint16_t type; int ifi, fam; r = sd_netlink_message_get_errno(m); if (r < 0) { log_error_errno(r, "got error: %m"); continue; } r = sd_netlink_message_get_type(m, &type); if (r < 0) { log_error_errno(r, "could not get type: %m"); continue; } if (type != RTM_NEWNEIGH) { log_error("type is not RTM_NEWNEIGH"); continue; } r = sd_rtnl_message_neigh_get_family(m, &fam); if (r < 0) { log_error_errno(r, "could not get family: %m"); continue; } if (fam != family) { log_error("family is not correct"); continue; } r = sd_rtnl_message_neigh_get_ifindex(m, &ifi); if (r < 0) { log_error_errno(r, "could not get ifindex: %m"); continue; } if (ifindex > 0 && ifi != ifindex) continue; switch (fam) { case AF_INET: r = sd_netlink_message_read_in_addr(m, NDA_DST, &gw.in); if (r < 0) continue; break; case AF_INET6: r = sd_netlink_message_read_in6_addr(m, NDA_DST, &gw.in6); if (r < 0) continue; break; default: continue; } if (!in_addr_equal(fam, &gw, gateway)) continue; r = sd_netlink_message_read_ether_addr(m, NDA_LLADDR, &mac); if (r < 0) continue; r = ieee_oui(hwdb, &mac, gateway_description); if (r < 0) continue; return 0; } return -ENODATA; }
static int parse_argv(int argc, char *argv[]) { enum { ARG_VERSION = 0x100, ARG_ROOT, ARG_LOCALE, ARG_LOCALE_MESSAGES, ARG_TIMEZONE, ARG_HOSTNAME, ARG_MACHINE_ID, ARG_ROOT_PASSWORD, ARG_ROOT_PASSWORD_FILE, ARG_PROMPT, ARG_PROMPT_LOCALE, ARG_PROMPT_TIMEZONE, ARG_PROMPT_HOSTNAME, ARG_PROMPT_ROOT_PASSWORD, ARG_COPY, ARG_COPY_LOCALE, ARG_COPY_TIMEZONE, ARG_COPY_ROOT_PASSWORD, ARG_SETUP_MACHINE_ID, }; static const struct option options[] = { { "help", no_argument, NULL, 'h' }, { "version", no_argument, NULL, ARG_VERSION }, { "root", required_argument, NULL, ARG_ROOT }, { "locale", required_argument, NULL, ARG_LOCALE }, { "locale-messages", required_argument, NULL, ARG_LOCALE_MESSAGES }, { "timezone", required_argument, NULL, ARG_TIMEZONE }, { "hostname", required_argument, NULL, ARG_HOSTNAME }, { "machine-id", required_argument, NULL, ARG_MACHINE_ID }, { "root-password", required_argument, NULL, ARG_ROOT_PASSWORD }, { "root-password-file", required_argument, NULL, ARG_ROOT_PASSWORD_FILE }, { "prompt", no_argument, NULL, ARG_PROMPT }, { "prompt-locale", no_argument, NULL, ARG_PROMPT_LOCALE }, { "prompt-timezone", no_argument, NULL, ARG_PROMPT_TIMEZONE }, { "prompt-hostname", no_argument, NULL, ARG_PROMPT_HOSTNAME }, { "prompt-root-password", no_argument, NULL, ARG_PROMPT_ROOT_PASSWORD }, { "copy", no_argument, NULL, ARG_COPY }, { "copy-locale", no_argument, NULL, ARG_COPY_LOCALE }, { "copy-timezone", no_argument, NULL, ARG_COPY_TIMEZONE }, { "copy-root-password", no_argument, NULL, ARG_COPY_ROOT_PASSWORD }, { "setup-machine-id", no_argument, NULL, ARG_SETUP_MACHINE_ID }, {} }; int r, 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_VERSION: return version(); case ARG_ROOT: r = parse_path_argument_and_warn(optarg, true, &arg_root); if (r < 0) return r; break; case ARG_LOCALE: if (!locale_is_valid(optarg)) { log_error("Locale %s is not valid.", optarg); return -EINVAL; } r = free_and_strdup(&arg_locale, optarg); if (r < 0) return log_oom(); break; case ARG_LOCALE_MESSAGES: if (!locale_is_valid(optarg)) { log_error("Locale %s is not valid.", optarg); return -EINVAL; } r = free_and_strdup(&arg_locale_messages, optarg); if (r < 0) return log_oom(); break; case ARG_TIMEZONE: if (!timezone_is_valid(optarg)) { log_error("Timezone %s is not valid.", optarg); return -EINVAL; } r = free_and_strdup(&arg_timezone, optarg); if (r < 0) return log_oom(); break; case ARG_ROOT_PASSWORD: r = free_and_strdup(&arg_root_password, optarg); if (r < 0) return log_oom(); break; case ARG_ROOT_PASSWORD_FILE: arg_root_password = mfree(arg_root_password); r = read_one_line_file(optarg, &arg_root_password); if (r < 0) return log_error_errno(r, "Failed to read %s: %m", optarg); break; case ARG_HOSTNAME: if (!hostname_is_valid(optarg, true)) { log_error("Host name %s is not valid.", optarg); return -EINVAL; } hostname_cleanup(optarg); r = free_and_strdup(&arg_hostname, optarg); if (r < 0) return log_oom(); break; case ARG_MACHINE_ID: if (sd_id128_from_string(optarg, &arg_machine_id) < 0) { log_error("Failed to parse machine id %s.", optarg); return -EINVAL; } break; case ARG_PROMPT: arg_prompt_locale = arg_prompt_timezone = arg_prompt_hostname = arg_prompt_root_password = true; break; case ARG_PROMPT_LOCALE: arg_prompt_locale = true; break; case ARG_PROMPT_TIMEZONE: arg_prompt_timezone = true; break; case ARG_PROMPT_HOSTNAME: arg_prompt_hostname = true; break; case ARG_PROMPT_ROOT_PASSWORD: arg_prompt_root_password = true; break; case ARG_COPY: arg_copy_locale = arg_copy_timezone = arg_copy_root_password = true; break; case ARG_COPY_LOCALE: arg_copy_locale = true; break; case ARG_COPY_TIMEZONE: arg_copy_timezone = true; break; case ARG_COPY_ROOT_PASSWORD: arg_copy_root_password = true; break; case ARG_SETUP_MACHINE_ID: r = sd_id128_randomize(&arg_machine_id); if (r < 0) return log_error_errno(r, "Failed to generate randomized machine ID: %m"); break; case '?': return -EINVAL; default: assert_not_reached("Unhandled option"); } return 1; }
int main(int argc, char *argv[]) { Server server; int r = EXIT_FAILURE, n; if (getppid() != 1) { log_error("This program should be invoked by init only."); return EXIT_FAILURE; } if (argc > 1) { log_error("This program does not take arguments."); return EXIT_FAILURE; } log_set_target(LOG_TARGET_AUTO); log_parse_environment(); log_open(); umask(0022); n = sd_listen_fds(true); if (n < 0) { log_error_errno(r, "Failed to read listening file descriptors from environment: %m"); return EXIT_FAILURE; } if (n <= 0 || n > SERVER_FD_MAX) { log_error("No or too many file descriptors passed."); return EXIT_FAILURE; } if (server_init(&server, (unsigned) n) < 0) return EXIT_FAILURE; log_debug("systemd-initctl running as pid "PID_FMT, getpid()); sd_notify(false, "READY=1\n" "STATUS=Processing requests..."); while (!server.quit) { struct epoll_event event; int k; k = epoll_wait(server.epoll_fd, &event, 1, TIMEOUT_MSEC); if (k < 0) { if (errno == EINTR) continue; log_error_errno(errno, "epoll_wait() failed: %m"); goto fail; } if (k <= 0) break; if (process_event(&server, &event) < 0) goto fail; } r = EXIT_SUCCESS; log_debug("systemd-initctl stopped as pid "PID_FMT, getpid()); fail: sd_notify(false, "STOPPING=1\n" "STATUS=Shutting down..."); server_done(&server); return r; }
static int resolve_host(sd_bus *bus, const char *name) { _cleanup_(sd_bus_message_unrefp) sd_bus_message *req = NULL, *reply = NULL; _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; const char *canonical = NULL; char ifname[IF_NAMESIZE] = ""; unsigned c = 0; int r; uint64_t flags; usec_t ts; assert(name); if (arg_ifindex > 0 && !if_indextoname(arg_ifindex, ifname)) return log_error_errno(errno, "Failed to resolve interface name for index %i: %m", arg_ifindex); log_debug("Resolving %s (family %s, interface %s).", name, af_to_name(arg_family) ?: "*", isempty(ifname) ? "*" : ifname); r = sd_bus_message_new_method_call( bus, &req, "org.freedesktop.resolve1", "/org/freedesktop/resolve1", "org.freedesktop.resolve1.Manager", "ResolveHostname"); if (r < 0) return bus_log_create_error(r); r = sd_bus_message_append(req, "isit", arg_ifindex, name, arg_family, arg_flags); if (r < 0) return bus_log_create_error(r); ts = now(CLOCK_MONOTONIC); r = sd_bus_call(bus, req, DNS_CALL_TIMEOUT_USEC, &error, &reply); if (r < 0) return log_error_errno(r, "%s: resolve call failed: %s", name, bus_error_message(&error, r)); ts = now(CLOCK_MONOTONIC) - ts; r = sd_bus_message_enter_container(reply, 'a', "(iiay)"); if (r < 0) return bus_log_parse_error(r); while ((r = sd_bus_message_enter_container(reply, 'r', "iiay")) > 0) { _cleanup_free_ char *pretty = NULL; int ifindex, family; const void *a; size_t sz; assert_cc(sizeof(int) == sizeof(int32_t)); r = sd_bus_message_read(reply, "ii", &ifindex, &family); if (r < 0) return bus_log_parse_error(r); r = sd_bus_message_read_array(reply, 'y', &a, &sz); if (r < 0) return bus_log_parse_error(r); r = sd_bus_message_exit_container(reply); if (r < 0) return bus_log_parse_error(r); if (!IN_SET(family, AF_INET, AF_INET6)) { log_debug("%s: skipping entry with family %d (%s)", name, family, af_to_name(family) ?: "unknown"); continue; } if (sz != FAMILY_ADDRESS_SIZE(family)) { log_error("%s: systemd-resolved returned address of invalid size %zu for family %s", name, sz, af_to_name(family) ?: "unknown"); return -EINVAL; }
static int shovel(PTYForward *f) { ssize_t k; assert(f); while ((f->stdin_readable && f->in_buffer_full <= 0) || (f->master_writable && f->in_buffer_full > 0) || (f->master_readable && f->out_buffer_full <= 0) || (f->stdout_writable && f->out_buffer_full > 0)) { if (f->stdin_readable && f->in_buffer_full < LINE_MAX) { k = read(STDIN_FILENO, f->in_buffer + f->in_buffer_full, LINE_MAX - f->in_buffer_full); if (k < 0) { if (errno == EAGAIN) f->stdin_readable = false; else if (errno == EIO || errno == EPIPE || errno == ECONNRESET) { f->stdin_readable = false; f->stdin_hangup = true; f->stdin_event_source = sd_event_source_unref(f->stdin_event_source); } else { log_error_errno(errno, "read(): %m"); return sd_event_exit(f->event, EXIT_FAILURE); } } else if (k == 0) { /* EOF on stdin */ f->stdin_readable = false; f->stdin_hangup = true; f->stdin_event_source = sd_event_source_unref(f->stdin_event_source); } else { /* Check if ^] has been * pressed three times within * one second. If we get this * we quite immediately. */ if (look_for_escape(f, f->in_buffer + f->in_buffer_full, k)) return sd_event_exit(f->event, EXIT_FAILURE); f->in_buffer_full += (size_t) k; } } if (f->master_writable && f->in_buffer_full > 0) { k = write(f->master, f->in_buffer, f->in_buffer_full); if (k < 0) { if (errno == EAGAIN || errno == EIO) f->master_writable = false; else if (errno == EPIPE || errno == ECONNRESET) { f->master_writable = f->master_readable = false; f->master_hangup = true; f->master_event_source = sd_event_source_unref(f->master_event_source); } else { log_error_errno(errno, "write(): %m"); return sd_event_exit(f->event, EXIT_FAILURE); } } else { assert(f->in_buffer_full >= (size_t) k); memmove(f->in_buffer, f->in_buffer + k, f->in_buffer_full - k); f->in_buffer_full -= k; } } if (f->master_readable && f->out_buffer_full < LINE_MAX) { k = read(f->master, f->out_buffer + f->out_buffer_full, LINE_MAX - f->out_buffer_full); if (k < 0) { /* Note that EIO on the master device * might be cause by vhangup() or * temporary closing of everything on * the other side, we treat it like * EAGAIN here and try again, unless * repeat is off. */ if (errno == EAGAIN || (errno == EIO && f->repeat)) f->master_readable = false; else if (errno == EPIPE || errno == ECONNRESET || errno == EIO) { f->master_readable = f->master_writable = false; f->master_hangup = true; f->master_event_source = sd_event_source_unref(f->master_event_source); } else { log_error_errno(errno, "read(): %m"); return sd_event_exit(f->event, EXIT_FAILURE); } } else f->out_buffer_full += (size_t) k; } if (f->stdout_writable && f->out_buffer_full > 0) { k = write(STDOUT_FILENO, f->out_buffer, f->out_buffer_full); if (k < 0) { if (errno == EAGAIN) f->stdout_writable = false; else if (errno == EIO || errno == EPIPE || errno == ECONNRESET) { f->stdout_writable = false; f->stdout_hangup = true; f->stdout_event_source = sd_event_source_unref(f->stdout_event_source); } else { log_error_errno(errno, "write(): %m"); return sd_event_exit(f->event, EXIT_FAILURE); } } else { if (k > 0) { f->last_char = f->out_buffer[k-1]; f->last_char_set = true; } assert(f->out_buffer_full >= (size_t) k); memmove(f->out_buffer, f->out_buffer + k, f->out_buffer_full - k); f->out_buffer_full -= k; } } } if (f->stdin_hangup || f->stdout_hangup || f->master_hangup) { /* Exit the loop if any side hung up and if there's * nothing more to write or nothing we could write. */ if ((f->out_buffer_full <= 0 || f->stdout_hangup) && (f->in_buffer_full <= 0 || f->master_hangup)) return sd_event_exit(f->event, EXIT_SUCCESS); } return 0; }
static void request_process(Server *s, const struct init_request *req) { assert(s); assert(req); if (req->magic != INIT_MAGIC) { log_error("Got initctl request with invalid magic. Ignoring."); return; } switch (req->cmd) { case INIT_CMD_RUNLVL: if (!isprint(req->runlevel)) log_error("Got invalid runlevel. Ignoring."); else switch (req->runlevel) { /* we are async anyway, so just use kill for reexec/reload */ case 'u': case 'U': if (kill(1, SIGTERM) < 0) log_error_errno(errno, "kill() failed: %m"); /* The bus connection will be * terminated if PID 1 is reexecuted, * hence let's just exit here, and * rely on that we'll be restarted on * the next request */ s->quit = true; break; case 'q': case 'Q': if (kill(1, SIGHUP) < 0) log_error_errno(errno, "kill() failed: %m"); break; default: change_runlevel(s, req->runlevel); } return; case INIT_CMD_POWERFAIL: case INIT_CMD_POWERFAILNOW: case INIT_CMD_POWEROK: log_warning("Received UPS/power initctl request. This is not implemented in systemd. Upgrade your UPS daemon!"); return; case INIT_CMD_CHANGECONS: log_warning("Received console change initctl request. This is not implemented in systemd."); return; case INIT_CMD_SETENV: case INIT_CMD_UNSETENV: log_warning("Received environment initctl request. This is not implemented in systemd."); return; default: log_warning("Received unknown initctl request. Ignoring."); return; } }
int main(int argc, char *argv[]) { int r; Hashmap *a = NULL, *b = NULL; unsigned iteration = 0; usec_t last_refresh = 0; bool quit = false, immediate_refresh = false; _cleanup_free_ char *root = NULL; CGroupMask mask; log_parse_environment(); log_open(); r = cg_mask_supported(&mask); if (r < 0) { log_error_errno(r, "Failed to determine supported controllers: %m"); goto finish; } arg_count = (mask & CGROUP_MASK_PIDS) ? COUNT_PIDS : COUNT_USERSPACE_PROCESSES; r = parse_argv(argc, argv); if (r <= 0) goto finish; r = cg_get_root_path(&root); if (r < 0) { log_error_errno(r, "Failed to get root control group path: %m"); goto finish; } a = hashmap_new(&string_hash_ops); b = hashmap_new(&string_hash_ops); if (!a || !b) { r = log_oom(); goto finish; } signal(SIGWINCH, columns_lines_cache_reset); if (arg_iterations == (unsigned) -1) arg_iterations = on_tty() ? 0 : 1; while (!quit) { Hashmap *c; usec_t t; char key; char h[FORMAT_TIMESPAN_MAX]; t = now(CLOCK_MONOTONIC); if (t >= last_refresh + arg_delay || immediate_refresh) { r = refresh(root, a, b, iteration++); if (r < 0) { log_error_errno(r, "Failed to refresh: %m"); goto finish; } group_hashmap_clear(b); c = a; a = b; b = c; last_refresh = t; immediate_refresh = false; } display(b); if (arg_iterations && iteration >= arg_iterations) break; if (!on_tty()) /* non-TTY: Empty newline as delimiter between polls */ fputs("\n", stdout); fflush(stdout); if (arg_batch) (void) usleep(last_refresh + arg_delay - t); else { r = read_one_char(stdin, &key, last_refresh + arg_delay - t, NULL); if (r == -ETIMEDOUT) continue; if (r < 0) { log_error_errno(r, "Couldn't read key: %m"); goto finish; } } if (on_tty()) { /* TTY: Clear any user keystroke */ fputs("\r \r", stdout); fflush(stdout); } if (arg_batch) continue; switch (key) { case ' ': immediate_refresh = true; break; case 'q': quit = true; break; case 'p': arg_order = ORDER_PATH; break; case 't': arg_order = ORDER_TASKS; break; case 'c': arg_order = ORDER_CPU; break; case 'm': arg_order = ORDER_MEMORY; break; case 'i': arg_order = ORDER_IO; break; case '%': arg_cpu_type = arg_cpu_type == CPU_TIME ? CPU_PERCENT : CPU_TIME; break; case 'k': arg_count = arg_count != COUNT_ALL_PROCESSES ? COUNT_ALL_PROCESSES : COUNT_PIDS; fprintf(stdout, "\nCounting: %s.", counting_what()); fflush(stdout); sleep(1); break; case 'P': arg_count = arg_count != COUNT_USERSPACE_PROCESSES ? COUNT_USERSPACE_PROCESSES : COUNT_PIDS; fprintf(stdout, "\nCounting: %s.", counting_what()); fflush(stdout); sleep(1); break; case 'r': if (arg_count == COUNT_PIDS) fprintf(stdout, "\n\aCannot toggle recursive counting, not available in task counting mode."); else { arg_recursive = !arg_recursive; fprintf(stdout, "\nRecursive process counting: %s", yes_no(arg_recursive)); } fflush(stdout); sleep(1); break; case '+': if (arg_delay < USEC_PER_SEC) arg_delay += USEC_PER_MSEC*250; else arg_delay += USEC_PER_SEC; fprintf(stdout, "\nIncreased delay to %s.", format_timespan(h, sizeof(h), arg_delay, 0)); fflush(stdout); sleep(1); break; case '-': if (arg_delay <= USEC_PER_MSEC*500) arg_delay = USEC_PER_MSEC*250; else if (arg_delay < USEC_PER_MSEC*1250) arg_delay -= USEC_PER_MSEC*250; else arg_delay -= USEC_PER_SEC; fprintf(stdout, "\nDecreased delay to %s.", format_timespan(h, sizeof(h), arg_delay, 0)); fflush(stdout); sleep(1); break; case '?': case 'h': fprintf(stdout, "\t<" ON "p" OFF "> By path; <" ON "t" OFF "> By tasks/procs; <" ON "c" OFF "> By CPU; <" ON "m" OFF "> By memory; <" ON "i" OFF "> By I/O\n" "\t<" ON "+" OFF "> Inc. delay; <" ON "-" OFF "> Dec. delay; <" ON "%%" OFF "> Toggle time; <" ON "SPACE" OFF "> Refresh\n" "\t<" ON "P" OFF "> Toggle count userspace processes; <" ON "k" OFF "> Toggle count all processes\n" "\t<" ON "r" OFF "> Count processes recursively; <" ON "q" OFF "> Quit"); fflush(stdout); sleep(3); break; default: if (key < ' ') fprintf(stdout, "\nUnknown key '\\x%x'. Ignoring.", key); else fprintf(stdout, "\nUnknown key '%c'. Ignoring.", key); fflush(stdout); sleep(1); break; } } r = 0; finish: group_hashmap_free(a); group_hashmap_free(b); return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; }
static int node_permissions_apply(struct udev_device *dev, bool apply, mode_t mode, uid_t uid, gid_t gid, struct udev_list *seclabel_list) { const char *devnode = udev_device_get_devnode(dev); dev_t devnum = udev_device_get_devnum(dev); struct stat stats; struct udev_list_entry *entry; int err = 0; if (streq(udev_device_get_subsystem(dev), "block")) mode |= S_IFBLK; else mode |= S_IFCHR; if (lstat(devnode, &stats) != 0) { err = -errno; log_debug_errno(errno, "can not stat() node '%s' (%m)", devnode); goto out; } if (((stats.st_mode & S_IFMT) != (mode & S_IFMT)) || (stats.st_rdev != devnum)) { err = -EEXIST; log_debug("found node '%s' with non-matching devnum %s, skip handling", udev_device_get_devnode(dev), udev_device_get_id_filename(dev)); goto out; } if (apply) { bool selinux = false; bool smack = false; if ((stats.st_mode & 0777) != (mode & 0777) || stats.st_uid != uid || stats.st_gid != gid) { log_debug("set permissions %s, %#o, uid=%u, gid=%u", devnode, mode, uid, gid); err = chmod(devnode, mode); if (err < 0) log_warning_errno(errno, "setting mode of %s to %#o failed: %m", devnode, mode); err = chown(devnode, uid, gid); if (err < 0) log_warning_errno(errno, "setting owner of %s to uid=%u, gid=%u failed: %m", devnode, uid, gid); } else { log_debug("preserve permissions %s, %#o, uid=%u, gid=%u", devnode, mode, uid, gid); } /* apply SECLABEL{$module}=$label */ udev_list_entry_foreach(entry, udev_list_get_entry(seclabel_list)) { const char *name, *label; int r; name = udev_list_entry_get_name(entry); label = udev_list_entry_get_value(entry); if (streq(name, "selinux")) { selinux = true; r = mac_selinux_apply(devnode, label); if (r < 0) log_error_errno(r, "SECLABEL: failed to set SELinux label '%s': %m", label); else log_debug("SECLABEL: set SELinux label '%s'", label); } else if (streq(name, "smack")) { smack = true; r = mac_smack_apply(devnode, label); if (r < 0) log_error_errno(r, "SECLABEL: failed to set SMACK label '%s': %m", label); else log_debug("SECLABEL: set SMACK label '%s'", label); } else log_error("SECLABEL: unknown subsystem, ignoring '%s'='%s'", name, label); } /* set the defaults */ if (!selinux) mac_selinux_fix(devnode, true, false); if (!smack) mac_smack_apply(devnode, NULL); } /* always update timestamp when we re-use the node, like on media change events */ utimensat(AT_FDCWD, devnode, NULL, 0); out: return err; }
int allocate_scope( sd_bus *bus, const char *machine_name, pid_t pid, const char *slice, CustomMount *mounts, unsigned n_mounts, int kill_signal, char **properties, sd_bus_message *properties_message) { _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 *scope = NULL; const char *description, *object; int r; assert(bus); r = bus_wait_for_jobs_new(bus, &w); if (r < 0) return log_error_errno(r, "Could not watch job: %m"); r = unit_name_mangle_with_suffix(machine_name, 0, ".scope", &scope); if (r < 0) return log_error_errno(r, "Failed to mangle scope name: %m"); 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_append(m, "ss", scope, "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); description = strjoina("Container ", machine_name); r = sd_bus_message_append(m, "(sv)(sv)(sv)(sv)(sv)(sv)", "PIDs", "au", 1, pid, "Description", "s", description, "Delegate", "b", 1, "CollectMode", "s", "inactive-or-failed", "AddRef", "b", 1, "Slice", "s", isempty(slice) ? SPECIAL_MACHINE_SLICE : slice); if (r < 0) return bus_log_create_error(r); r = append_controller_property(bus, m); if (r < 0) return r; if (properties_message) { r = sd_bus_message_copy(m, properties_message, true); if (r < 0) return bus_log_create_error(r); } r = append_machine_properties( m, mounts, n_mounts, kill_signal); if (r < 0) return r; r = bus_append_unit_property_assignment_many(m, UNIT_SCOPE, properties); if (r < 0) return r; r = sd_bus_message_close_container(m); if (r < 0) return bus_log_create_error(r); /* No auxiliary units */ r = sd_bus_message_append( m, "a(sa(sv))", 0); if (r < 0) return bus_log_create_error(r); r = sd_bus_call(bus, m, 0, &error, &reply); if (r < 0) return log_error_errno(r, "Failed to allocate scope: %s", bus_error_message(&error, r)); 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, false); if (r < 0) return r; return 0; }
/* Go through the file and parse each line */ int config_parse(const char *unit, const char *filename, FILE *f, const char *sections, ConfigItemLookup lookup, const void *table, bool relaxed, bool allow_include, bool warn, void *userdata) { _cleanup_free_ char *section = NULL, *continuation = NULL; _cleanup_fclose_ FILE *ours = NULL; unsigned line = 0, section_line = 0; bool section_ignored = false, allow_bom = true; int r; assert(filename); assert(lookup); if (!f) { f = ours = fopen(filename, "re"); if (!f) { /* Only log on request, except for ENOENT, * since we return 0 to the caller. */ if (warn || errno == ENOENT) log_full(errno == ENOENT ? LOG_DEBUG : LOG_ERR, "Failed to open configuration file '%s': %m", filename); return errno == ENOENT ? 0 : -errno; } } fd_warn_permissions(filename, fileno(f)); for (;;) { char buf[LINE_MAX], *l, *p, *c = NULL, *e; bool escaped = false; if (!fgets(buf, sizeof buf, f)) { if (feof(f)) break; return log_error_errno(errno, "Failed to read configuration file '%s': %m", filename); } l = buf; if (allow_bom && startswith(l, UTF8_BYTE_ORDER_MARK)) l += strlen(UTF8_BYTE_ORDER_MARK); allow_bom = false; truncate_nl(l); if (continuation) { c = strappend(continuation, l); if (!c) { if (warn) log_oom(); return -ENOMEM; } continuation = mfree(continuation); p = c; } else p = l; for (e = p; *e; e++) { if (escaped) escaped = false; else if (*e == '\\') escaped = true; } if (escaped) { *(e-1) = ' '; if (c) continuation = c; else { continuation = strdup(l); if (!continuation) { if (warn) log_oom(); return -ENOMEM; } } continue; } r = parse_line(unit, filename, ++line, sections, lookup, table, relaxed, allow_include, §ion, §ion_line, §ion_ignored, p, userdata); free(c); if (r < 0) { if (warn) log_warning_errno(r, "Failed to parse file '%s': %m", filename); return r; } } return 0; }
static int append_machine_properties( sd_bus_message *m, CustomMount *mounts, unsigned n_mounts, int kill_signal) { unsigned j; int r; assert(m); r = sd_bus_message_append(m, "(sv)", "DevicePolicy", "s", "closed"); if (r < 0) return bus_log_create_error(r); /* If you make changes here, also make sure to update [email protected], to keep the device policies in * sync regardless if we are run with or without the --keep-unit switch. */ r = sd_bus_message_append(m, "(sv)", "DeviceAllow", "a(ss)", 2, /* Allow the container to * access and create the API * device nodes, so that * PrivateDevices= in the * container can work * fine */ "/dev/net/tun", "rwm", /* Allow the container * access to ptys. However, * do not permit the * container to ever create * these device nodes. */ "char-pts", "rw"); if (r < 0) return bus_log_create_error(r); for (j = 0; j < n_mounts; j++) { CustomMount *cm = mounts + j; if (cm->type != CUSTOM_MOUNT_BIND) continue; r = is_device_node(cm->source); if (r == -ENOENT) { /* The bind source might only appear as the image is put together, hence don't complain */ log_debug_errno(r, "Bind mount source %s not found, ignoring: %m", cm->source); continue; } if (r < 0) return log_error_errno(r, "Failed to stat %s: %m", cm->source); if (r) { r = sd_bus_message_append(m, "(sv)", "DeviceAllow", "a(ss)", 1, cm->source, cm->read_only ? "r" : "rw"); if (r < 0) return log_error_errno(r, "Failed to append message arguments: %m"); } } if (kill_signal != 0) { r = sd_bus_message_append(m, "(sv)", "KillSignal", "i", kill_signal); if (r < 0) return bus_log_create_error(r); r = sd_bus_message_append(m, "(sv)", "KillMode", "s", "mixed"); if (r < 0) return bus_log_create_error(r); } return 0; }
int register_machine( sd_bus *bus, const char *machine_name, pid_t pid, const char *directory, sd_id128_t uuid, int local_ifindex, const char *slice, CustomMount *mounts, unsigned n_mounts, int kill_signal, char **properties, sd_bus_message *properties_message, bool keep_unit, const char *service) { _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; int r; assert(bus); if (keep_unit) { r = sd_bus_call_method( bus, "org.freedesktop.machine1", "/org/freedesktop/machine1", "org.freedesktop.machine1.Manager", "RegisterMachineWithNetwork", &error, NULL, "sayssusai", machine_name, SD_BUS_MESSAGE_APPEND_ID128(uuid), service, "container", (uint32_t) pid, strempty(directory), local_ifindex > 0 ? 1 : 0, local_ifindex); } else { _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; r = sd_bus_message_new_method_call( bus, &m, "org.freedesktop.machine1", "/org/freedesktop/machine1", "org.freedesktop.machine1.Manager", "CreateMachineWithNetwork"); if (r < 0) return bus_log_create_error(r); r = sd_bus_message_append( m, "sayssusai", machine_name, SD_BUS_MESSAGE_APPEND_ID128(uuid), service, "container", (uint32_t) pid, strempty(directory), local_ifindex > 0 ? 1 : 0, local_ifindex); if (r < 0) return bus_log_create_error(r); r = sd_bus_message_open_container(m, 'a', "(sv)"); if (r < 0) return bus_log_create_error(r); if (!isempty(slice)) { r = sd_bus_message_append(m, "(sv)", "Slice", "s", slice); if (r < 0) return bus_log_create_error(r); } r = append_controller_property(bus, m); if (r < 0) return r; r = append_machine_properties( m, mounts, n_mounts, kill_signal); if (r < 0) return r; if (properties_message) { r = sd_bus_message_copy(m, properties_message, true); if (r < 0) return bus_log_create_error(r); } r = bus_append_unit_property_assignment_many(m, UNIT_SERVICE, properties); if (r < 0) return r; r = sd_bus_message_close_container(m); if (r < 0) return bus_log_create_error(r); r = sd_bus_call(bus, m, 0, &error, NULL); } if (r < 0) return log_error_errno(r, "Failed to register machine: %s", bus_error_message(&error, r)); return 0; }
static int add_swap( const char *what, struct mntent *me, bool noauto, bool nofail) { _cleanup_free_ char *name = NULL, *unit = NULL, *lnk = NULL; _cleanup_fclose_ FILE *f = NULL; int r; assert(what); assert(me); if (access("/proc/swaps", F_OK) < 0) { log_info("Swap not supported, ignoring fstab swap entry for %s.", what); return 0; } if (detect_container() > 0) { log_info("Running in a container, ignoring fstab swap entry for %s.", what); return 0; } r = unit_name_from_path(what, ".swap", &name); if (r < 0) return log_error_errno(r, "Failed to generate unit name: %m"); unit = strjoin(arg_dest, "/", name, NULL); if (!unit) return log_oom(); f = fopen(unit, "wxe"); if (!f) { if (errno == EEXIST) log_error("Failed to create swap unit file %s, as it already exists. Duplicate entry in /etc/fstab?", unit); else log_error_errno(errno, "Failed to create unit file %s: %m", unit); return -errno; } fprintf(f, "# Automatically generated by systemd-fstab-generator\n\n" "[Unit]\n" "SourcePath=/etc/fstab\n" "Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n\n" "[Swap]\n" "What=%s\n", what); if (!isempty(me->mnt_opts) && !streq(me->mnt_opts, "defaults")) fprintf(f, "Options=%s\n", me->mnt_opts); r = fflush_and_check(f); if (r < 0) return log_error_errno(r, "Failed to write unit file %s: %m", unit); /* use what as where, to have a nicer error message */ r = generator_write_timeouts(arg_dest, what, what, me->mnt_opts, NULL); if (r < 0) return r; if (!noauto) { lnk = strjoin(arg_dest, "/" SPECIAL_SWAP_TARGET, nofail ? ".wants/" : ".requires/", name, NULL); if (!lnk) return log_oom(); mkdir_parents_label(lnk, 0755); if (symlink(unit, lnk) < 0) return log_error_errno(errno, "Failed to create symlink %s: %m", lnk); } return 0; }
static int import_tar(int argc, char *argv[], void *userdata) { _cleanup_(tar_import_unrefp) TarImport *import = NULL; _cleanup_event_unref_ sd_event *event = NULL; const char *path = NULL, *local = NULL; _cleanup_free_ char *ll = NULL; _cleanup_close_ int open_fd = -1; int r, fd; if (argc >= 2) path = argv[1]; if (isempty(path) || streq(path, "-")) path = NULL; if (argc >= 3) local = argv[2]; else if (path) local = basename(path); if (isempty(local) || streq(local, "-")) local = NULL; if (local) { r = tar_strip_suffixes(local, &ll); if (r < 0) return log_oom(); local = ll; if (!machine_name_is_valid(local)) { log_error("Local image name '%s' is not valid.", local); return -EINVAL; } if (!arg_force) { r = image_find(local, NULL); if (r < 0) return log_error_errno(r, "Failed to check whether image '%s' exists: %m", local); else if (r > 0) { log_error_errno(EEXIST, "Image '%s' already exists.", local); return -EEXIST; } } } else local = "imported"; if (path) { open_fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY); if (open_fd < 0) return log_error_errno(errno, "Failed to open tar image to import: %m"); fd = open_fd; log_info("Importing '%s', saving as '%s'.", path, local); } else { _cleanup_free_ char *pretty = NULL; fd = STDIN_FILENO; (void) readlink_malloc("/proc/self/fd/0", &pretty); log_info("Importing '%s', saving as '%s'.", strna(pretty), local); } r = sd_event_default(&event); if (r < 0) return log_error_errno(r, "Failed to allocate event loop: %m"); assert_se(sigprocmask_many(SIG_BLOCK, SIGTERM, SIGINT, -1) == 0); sd_event_add_signal(event, NULL, SIGTERM, interrupt_signal_handler, NULL); sd_event_add_signal(event, NULL, SIGINT, interrupt_signal_handler, NULL); r = tar_import_new(&import, event, arg_image_root, on_tar_finished, event); if (r < 0) return log_error_errno(r, "Failed to allocate importer: %m"); r = tar_import_start(import, fd, local, arg_force, arg_read_only); if (r < 0) return log_error_errno(r, "Failed to import image: %m"); r = sd_event_loop(event); if (r < 0) return log_error_errno(r, "Failed to run event loop: %m"); log_info("Exiting."); return -r; }
static int node_symlink(struct udev_device *dev, const char *node, const char *slink) { struct stat stats; char target[UTIL_PATH_SIZE]; char *s; size_t l; char slink_tmp[UTIL_PATH_SIZE + 32]; int i = 0; int tail = 0; int err = 0; /* use relative link */ target[0] = '\0'; while (node[i] && (node[i] == slink[i])) { if (node[i] == '/') tail = i+1; i++; } s = target; l = sizeof(target); while (slink[i] != '\0') { if (slink[i] == '/') l = strpcpy(&s, l, "../"); i++; } l = strscpy(s, l, &node[tail]); if (l == 0) { err = -EINVAL; goto exit; } /* preserve link with correct target, do not replace node of other device */ if (lstat(slink, &stats) == 0) { if (S_ISBLK(stats.st_mode) || S_ISCHR(stats.st_mode)) { log_error("conflicting device node '%s' found, link to '%s' will not be created", slink, node); goto exit; } else if (S_ISLNK(stats.st_mode)) { char buf[UTIL_PATH_SIZE]; int len; len = readlink(slink, buf, sizeof(buf)); if (len > 0 && len < (int)sizeof(buf)) { buf[len] = '\0'; if (streq(target, buf)) { log_debug("preserve already existing symlink '%s' to '%s'", slink, target); label_fix(slink, true, false); utimensat(AT_FDCWD, slink, NULL, AT_SYMLINK_NOFOLLOW); goto exit; } } } } else { log_debug("creating symlink '%s' to '%s'", slink, target); do { err = mkdir_parents_label(slink, 0755); if (err != 0 && err != -ENOENT) break; mac_selinux_create_file_prepare(slink, S_IFLNK); err = symlink(target, slink); if (err != 0) err = -errno; mac_selinux_create_file_clear(); } while (err == -ENOENT); if (err == 0) goto exit; } log_debug("atomically replace '%s'", slink); strscpyl(slink_tmp, sizeof(slink_tmp), slink, ".tmp-", udev_device_get_id_filename(dev), NULL); unlink(slink_tmp); do { err = mkdir_parents_label(slink_tmp, 0755); if (err != 0 && err != -ENOENT) break; mac_selinux_create_file_prepare(slink_tmp, S_IFLNK); err = symlink(target, slink_tmp); if (err != 0) err = -errno; mac_selinux_create_file_clear(); } while (err == -ENOENT); if (err != 0) { log_error_errno(errno, "symlink '%s' '%s' failed: %m", target, slink_tmp); goto exit; } err = rename(slink_tmp, slink); if (err != 0) { log_error_errno(errno, "rename '%s' '%s' failed: %m", slink_tmp, slink); unlink(slink_tmp); } exit: return err; }
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) { #ifdef SMACK_RUN_LABEL _cleanup_free_ char *src; src = strappend("/sys/fs/cgroup/", options); if (!src) return log_oom(); r = mac_smack_copy(t, src); if (r < 0 && r != -EOPNOTSUPP) return log_error_errno(r, "Failed to copy smack label from %s to %s: %m", src, t); #endif } else if (errno != EEXIST) return log_error_errno(errno, "Failed to create symlink %s: %m", t); } } } /* 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) { int r = 0; r = mount_points_setup(ELEMENTSOF(mount_table), loaded_policy); 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("/dev/shm", 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; }
static int method_set_static_hostname(sd_bus_message *m, void *userdata, sd_bus_error *error) { Context *c = userdata; const char *name; int interactive; int r; assert(m); assert(c); r = sd_bus_message_read(m, "sb", &name, &interactive); if (r < 0) return r; name = empty_to_null(name); if (streq_ptr(name, c->data[PROP_STATIC_HOSTNAME])) return sd_bus_reply_method_return(m, NULL); r = bus_verify_polkit_async( m, CAP_SYS_ADMIN, "org.freedesktop.hostname1.set-static-hostname", NULL, interactive, UID_INVALID, &c->polkit_registry, error); if (r < 0) return r; if (r == 0) return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */ if (isempty(name)) c->data[PROP_STATIC_HOSTNAME] = mfree(c->data[PROP_STATIC_HOSTNAME]); else { char *h; if (!hostname_is_valid(name, false)) return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid static hostname '%s'", name); h = strdup(name); if (!h) return -ENOMEM; free(c->data[PROP_STATIC_HOSTNAME]); c->data[PROP_STATIC_HOSTNAME] = h; } r = context_update_kernel_hostname(c); if (r < 0) { log_error_errno(r, "Failed to set host name: %m"); return sd_bus_error_set_errnof(error, r, "Failed to set hostname: %m"); } r = context_write_data_static_hostname(c); if (r < 0) { log_error_errno(r, "Failed to write static host name: %m"); return sd_bus_error_set_errnof(error, r, "Failed to set static hostname: %m"); } log_info("Changed static host name to '%s'", strna(c->data[PROP_STATIC_HOSTNAME])); (void) sd_bus_emit_properties_changed(sd_bus_message_get_bus(m), "/org/freedesktop/hostname1", "org.freedesktop.hostname1", "StaticHostname", NULL); return sd_bus_reply_method_return(m, NULL); }
static int manager_connect_bus(Manager *m) { _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; int r; assert(m); assert(!m->bus); r = sd_bus_default_system(&m->bus); if (r < 0) return log_error_errno(r, "Failed to connect to system bus: %m"); r = sd_bus_add_object_vtable(m->bus, NULL, "/org/freedesktop/machine1", "org.freedesktop.machine1.Manager", manager_vtable, m); if (r < 0) return log_error_errno(r, "Failed to add manager object vtable: %m"); r = sd_bus_add_fallback_vtable(m->bus, NULL, "/org/freedesktop/machine1/machine", "org.freedesktop.machine1.Machine", machine_vtable, machine_object_find, m); if (r < 0) return log_error_errno(r, "Failed to add machine object vtable: %m"); r = sd_bus_add_node_enumerator(m->bus, NULL, "/org/freedesktop/machine1/machine", machine_node_enumerator, m); if (r < 0) return log_error_errno(r, "Failed to add machine enumerator: %m"); r = sd_bus_add_fallback_vtable(m->bus, NULL, "/org/freedesktop/machine1/image", "org.freedesktop.machine1.Image", image_vtable, image_object_find, m); if (r < 0) return log_error_errno(r, "Failed to add image object vtable: %m"); r = sd_bus_add_node_enumerator(m->bus, NULL, "/org/freedesktop/machine1/image", image_node_enumerator, m); if (r < 0) return log_error_errno(r, "Failed to add image enumerator: %m"); r = sd_bus_add_match(m->bus, NULL, "type='signal'," "sender='org.freedesktop.systemd1'," "interface='org.freedesktop.systemd1.Manager'," "member='JobRemoved'," "path='/org/freedesktop/systemd1'", match_job_removed, m); if (r < 0) return log_error_errno(r, "Failed to add match for JobRemoved: %m"); r = sd_bus_add_match(m->bus, NULL, "type='signal'," "sender='org.freedesktop.systemd1'," "interface='org.freedesktop.systemd1.Manager'," "member='UnitRemoved'," "path='/org/freedesktop/systemd1'", match_unit_removed, m); if (r < 0) return log_error_errno(r, "Failed to add match for UnitRemoved: %m"); r = sd_bus_add_match(m->bus, NULL, "type='signal'," "sender='org.freedesktop.systemd1'," "interface='org.freedesktop.DBus.Properties'," "member='PropertiesChanged'," "arg0='org.freedesktop.systemd1.Unit'", match_properties_changed, m); if (r < 0) return log_error_errno(r, "Failed to add match for PropertiesChanged: %m"); r = sd_bus_add_match(m->bus, NULL, "type='signal'," "sender='org.freedesktop.systemd1'," "interface='org.freedesktop.systemd1.Manager'," "member='Reloading'," "path='/org/freedesktop/systemd1'", match_reloading, m); if (r < 0) return log_error_errno(r, "Failed to add match for Reloading: %m"); r = sd_bus_call_method( m->bus, "org.freedesktop.systemd1", "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "Subscribe", &error, NULL, NULL); if (r < 0) { log_error("Failed to enable subscription: %s", bus_error_message(&error, r)); return r; } r = sd_bus_request_name(m->bus, "org.freedesktop.machine1", 0); if (r < 0) return log_error_errno(r, "Failed to register name: %m"); r = sd_bus_attach_event(m->bus, m->event, 0); if (r < 0) return log_error_errno(r, "Failed to attach bus to event loop: %m"); return 0; }
static int set_machine_info(Context *c, sd_bus_message *m, int prop, sd_bus_message_handler_t cb, sd_bus_error *error) { int interactive; const char *name; int r; assert(c); assert(m); r = sd_bus_message_read(m, "sb", &name, &interactive); if (r < 0) return r; name = empty_to_null(name); if (streq_ptr(name, c->data[prop])) return sd_bus_reply_method_return(m, NULL); /* Since the pretty hostname should always be changed at the * same time as the static one, use the same policy action for * both... */ r = bus_verify_polkit_async( m, CAP_SYS_ADMIN, prop == PROP_PRETTY_HOSTNAME ? "org.freedesktop.hostname1.set-static-hostname" : "org.freedesktop.hostname1.set-machine-info", NULL, interactive, UID_INVALID, &c->polkit_registry, error); if (r < 0) return r; if (r == 0) return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */ if (isempty(name)) c->data[prop] = mfree(c->data[prop]); else { char *h; /* The icon name might ultimately be used as file * name, so better be safe than sorry */ if (prop == PROP_ICON_NAME && !filename_is_valid(name)) return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid icon name '%s'", name); if (prop == PROP_PRETTY_HOSTNAME && string_has_cc(name, NULL)) return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid pretty host name '%s'", name); if (prop == PROP_CHASSIS && !valid_chassis(name)) return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid chassis '%s'", name); if (prop == PROP_DEPLOYMENT && !valid_deployment(name)) return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid deployment '%s'", name); if (prop == PROP_LOCATION && string_has_cc(name, NULL)) return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid location '%s'", name); h = strdup(name); if (!h) return -ENOMEM; free(c->data[prop]); c->data[prop] = h; } r = context_write_data_machine_info(c); if (r < 0) { log_error_errno(r, "Failed to write machine info: %m"); return sd_bus_error_set_errnof(error, r, "Failed to write machine info: %m"); } log_info("Changed %s to '%s'", prop == PROP_PRETTY_HOSTNAME ? "pretty host name" : prop == PROP_DEPLOYMENT ? "deployment" : prop == PROP_LOCATION ? "location" : prop == PROP_CHASSIS ? "chassis" : "icon name", strna(c->data[prop])); (void) sd_bus_emit_properties_changed( sd_bus_message_get_bus(m), "/org/freedesktop/hostname1", "org.freedesktop.hostname1", prop == PROP_PRETTY_HOSTNAME ? "PrettyHostname" : prop == PROP_DEPLOYMENT ? "Deployment" : prop == PROP_LOCATION ? "Location" : prop == PROP_CHASSIS ? "Chassis" : "IconName" , NULL); return sd_bus_reply_method_return(m, NULL); }
static int server_init(Server *s, unsigned n_sockets) { int r; unsigned i; assert(s); assert(n_sockets > 0); zero(*s); s->epoll_fd = epoll_create1(EPOLL_CLOEXEC); if (s->epoll_fd < 0) { r = log_error_errno(errno, "Failed to create epoll object: %m"); goto fail; } for (i = 0; i < n_sockets; i++) { struct epoll_event ev; Fifo *f; int fd; fd = SD_LISTEN_FDS_START+i; r = sd_is_fifo(fd, NULL); if (r < 0) { log_error_errno(r, "Failed to determine file descriptor type: %m"); goto fail; } if (!r) { log_error("Wrong file descriptor type."); r = -EINVAL; goto fail; } f = new0(Fifo, 1); if (!f) { r = -ENOMEM; log_error_errno(errno, "Failed to create fifo object: %m"); goto fail; } f->fd = -1; zero(ev); ev.events = EPOLLIN; ev.data.ptr = f; if (epoll_ctl(s->epoll_fd, EPOLL_CTL_ADD, fd, &ev) < 0) { r = -errno; fifo_free(f); log_error_errno(errno, "Failed to add fifo fd to epoll object: %m"); goto fail; } f->fd = fd; LIST_PREPEND(fifo, s->fifos, f); f->server = s; s->n_fifos ++; } r = bus_connect_system_systemd(&s->bus); if (r < 0) { log_error_errno(r, "Failed to get D-Bus connection: %m"); r = -EIO; goto fail; } return 0; fail: server_done(s); return r; }
static void automount_enter_waiting(Automount *a) { _cleanup_close_ int ioctl_fd = -1; int p[2] = { -1, -1 }; char name[sizeof("systemd-")-1 + DECIMAL_STR_MAX(pid_t) + 1]; char options[sizeof("fd=,pgrp=,minproto=5,maxproto=5,direct")-1 + DECIMAL_STR_MAX(int) + DECIMAL_STR_MAX(gid_t) + 1]; bool mounted = false; int r, dev_autofs_fd; struct stat st; assert(a); assert(a->pipe_fd < 0); assert(a->where); set_clear(a->tokens); r = unit_fail_if_symlink(UNIT(a), a->where); if (r < 0) goto fail; (void) mkdir_p_label(a->where, 0555); unit_warn_if_dir_nonempty(UNIT(a), a->where); dev_autofs_fd = open_dev_autofs(UNIT(a)->manager); if (dev_autofs_fd < 0) { r = dev_autofs_fd; goto fail; } if (pipe2(p, O_NONBLOCK|O_CLOEXEC) < 0) { r = -errno; goto fail; } xsprintf(options, "fd=%i,pgrp="PID_FMT",minproto=5,maxproto=5,direct", p[1], getpgrp()); xsprintf(name, "systemd-"PID_FMT, getpid_cached()); if (mount(name, a->where, "autofs", 0, options) < 0) { r = -errno; goto fail; } mounted = true; p[1] = safe_close(p[1]); if (stat(a->where, &st) < 0) { r = -errno; goto fail; } ioctl_fd = open_ioctl_fd(dev_autofs_fd, a->where, st.st_dev); if (ioctl_fd < 0) { r = ioctl_fd; goto fail; } r = autofs_protocol(dev_autofs_fd, ioctl_fd); if (r < 0) goto fail; r = autofs_set_timeout(dev_autofs_fd, ioctl_fd, a->timeout_idle_usec); if (r < 0) goto fail; r = sd_event_add_io(UNIT(a)->manager->event, &a->pipe_event_source, p[0], EPOLLIN, automount_dispatch_io, a); if (r < 0) goto fail; (void) sd_event_source_set_description(a->pipe_event_source, "automount-io"); a->pipe_fd = p[0]; a->dev_id = st.st_dev; automount_set_state(a, AUTOMOUNT_WAITING); return; fail: log_unit_error_errno(UNIT(a), r, "Failed to initialize automounter: %m"); safe_close_pair(p); if (mounted) { r = repeat_unmount(a->where, MNT_DETACH); if (r < 0) log_error_errno(r, "Failed to unmount, ignoring: %m"); } automount_enter_dead(a, AUTOMOUNT_FAILURE_RESOURCES); }
int change_uid_gid(const char *user, char **_home) { char line[LINE_MAX], *x, *u, *g, *h; const char *word, *state; _cleanup_free_ uid_t *uids = NULL; _cleanup_free_ char *home = NULL; _cleanup_fclose_ FILE *f = NULL; _cleanup_close_ int fd = -1; unsigned n_uids = 0; size_t sz = 0, l; uid_t uid; gid_t gid; pid_t pid; int r; assert(_home); if (!user || streq(user, "root") || streq(user, "0")) { /* Reset everything fully to 0, just in case */ r = reset_uid_gid(); if (r < 0) return log_error_errno(r, "Failed to become root: %m"); *_home = NULL; return 0; } /* First, get user credentials */ fd = spawn_getent("passwd", user, &pid); if (fd < 0) return fd; f = fdopen(fd, "r"); if (!f) return log_oom(); fd = -1; if (!fgets(line, sizeof(line), f)) { if (!ferror(f)) { log_error("Failed to resolve user %s.", user); return -ESRCH; } log_error_errno(errno, "Failed to read from getent: %m"); return -errno; } truncate_nl(line); wait_for_terminate_and_warn("getent passwd", pid, true); x = strchr(line, ':'); if (!x) { log_error("/etc/passwd entry has invalid user field."); return -EIO; } u = strchr(x+1, ':'); if (!u) { log_error("/etc/passwd entry has invalid password field."); return -EIO; } u++; g = strchr(u, ':'); if (!g) { log_error("/etc/passwd entry has invalid UID field."); return -EIO; } *g = 0; g++; x = strchr(g, ':'); if (!x) { log_error("/etc/passwd entry has invalid GID field."); return -EIO; } *x = 0; h = strchr(x+1, ':'); if (!h) { log_error("/etc/passwd entry has invalid GECOS field."); return -EIO; } h++; x = strchr(h, ':'); if (!x) { log_error("/etc/passwd entry has invalid home directory field."); return -EIO; } *x = 0; r = parse_uid(u, &uid); if (r < 0) { log_error("Failed to parse UID of user."); return -EIO; } r = parse_gid(g, &gid); if (r < 0) { log_error("Failed to parse GID of user."); return -EIO; } home = strdup(h); if (!home) return log_oom(); /* Second, get group memberships */ fd = spawn_getent("initgroups", user, &pid); if (fd < 0) return fd; fclose(f); f = fdopen(fd, "r"); if (!f) return log_oom(); fd = -1; if (!fgets(line, sizeof(line), f)) { if (!ferror(f)) { log_error("Failed to resolve user %s.", user); return -ESRCH; } log_error_errno(errno, "Failed to read from getent: %m"); return -errno; } truncate_nl(line); wait_for_terminate_and_warn("getent initgroups", pid, true); /* Skip over the username and subsequent separator whitespace */ x = line; x += strcspn(x, WHITESPACE); x += strspn(x, WHITESPACE); FOREACH_WORD(word, l, x, state) { char c[l+1]; memcpy(c, word, l); c[l] = 0; if (!GREEDY_REALLOC(uids, sz, n_uids+1)) return log_oom(); r = parse_uid(c, &uids[n_uids++]); if (r < 0) { log_error("Failed to parse group data from getent."); return -EIO; } }
static int process_root_password(void) { static const char table[] = "abcdefghijklmnopqrstuvwxyz" "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "0123456789" "./"; struct spwd item = { .sp_namp = (char*) "root", .sp_min = -1, .sp_max = -1, .sp_warn = -1, .sp_inact = -1, .sp_expire = -1, .sp_flag = (unsigned long) -1, /* this appears to be what everybody does ... */ }; _cleanup_close_ int lock = -1; char salt[3+16+1+1]; uint8_t raw[16]; unsigned i; char *j; const char *etc_shadow; int r; etc_shadow = prefix_roota(arg_root, "/etc/shadow"); if (faccessat(AT_FDCWD, etc_shadow, F_OK, AT_SYMLINK_NOFOLLOW) >= 0) return 0; mkdir_parents(etc_shadow, 0755); lock = take_etc_passwd_lock(arg_root); if (lock < 0) return lock; if (arg_copy_root_password && arg_root) { struct spwd *p; errno = 0; p = getspnam("root"); if (p || errno != ENOENT) { if (!p) { if (!errno) errno = EIO; return log_error_errno(errno, "Failed to find shadow entry for root: %m"); } r = write_root_shadow(etc_shadow, p); if (r < 0) return log_error_errno(r, "Failed to write %s: %m", etc_shadow); log_info("%s copied.", etc_shadow); return 0; } } r = prompt_root_password(); if (r < 0) return r; if (!arg_root_password) return 0; r = dev_urandom(raw, 16); if (r < 0) return log_error_errno(r, "Failed to get salt: %m"); /* We only bother with SHA512 hashed passwords, the rest is legacy, and we don't do legacy. */ assert_cc(sizeof(table) == 64 + 1); j = stpcpy(salt, "$6$"); for (i = 0; i < 16; i++) j[i] = table[raw[i] & 63]; j[i++] = '$'; j[i] = 0; errno = 0; item.sp_pwdp = crypt(arg_root_password, salt); if (!item.sp_pwdp) { if (!errno) errno = EINVAL; return log_error_errno(errno, "Failed to encrypt password: %m"); } item.sp_lstchg = (long) (now(CLOCK_REALTIME) / USEC_PER_DAY); r = write_root_shadow(etc_shadow, &item); if (r < 0) return log_error_errno(r, "Failed to write %s: %m", etc_shadow); log_info("%s written.", etc_shadow); return 0; } static void help(void) { printf("%s [OPTIONS...]\n\n" "Configures basic settings of the system.\n\n" " -h --help Show this help\n" " --version Show package version\n" " --root=PATH Operate on an alternate filesystem root\n" " --locale=LOCALE Set primary locale (LANG=)\n" " --locale-messages=LOCALE Set message locale (LC_MESSAGES=)\n" " --timezone=TIMEZONE Set timezone\n" " --hostname=NAME Set host name\n" " --machine-ID=ID Set machine ID\n" " --root-password=PASSWORD Set root password\n" " --root-password-file=FILE Set root password from file\n" " --prompt-locale Prompt the user for locale settings\n" " --prompt-timezone Prompt the user for timezone\n" " --prompt-hostname Prompt the user for hostname\n" " --prompt-root-password Prompt the user for root password\n" " --prompt Prompt for all of the above\n" " --copy-locale Copy locale from host\n" " --copy-timezone Copy timezone from host\n" " --copy-root-password Copy root password from host\n" " --copy Copy locale, timezone, root password\n" " --setup-machine-id Generate a new random machine ID\n" , program_invocation_short_name); }
int main(int argc, char *argv[]) { int r; int fd; fd = open("/", O_RDONLY|O_CLOEXEC|O_DIRECTORY); if (fd < 0) log_error_errno(errno, "Failed to open root directory: %m"); else { BtrfsSubvolInfo info; BtrfsQuotaInfo quota; char ts[FORMAT_TIMESTAMP_MAX], bs[FORMAT_BYTES_MAX]; r = btrfs_subvol_get_info_fd(fd, &info); if (r < 0) log_error_errno(r, "Failed to get subvolume info: %m"); else { log_info("otime: %s", format_timestamp(ts, sizeof(ts), info.otime)); log_info("read-only (search): %s", yes_no(info.read_only)); } r = btrfs_subvol_get_quota_fd(fd, "a); if (r < 0) log_error_errno(r, "Failed to get quota info: %m"); else { log_info("referred: %s", strna(format_bytes(bs, sizeof(bs), quota.referred))); log_info("exclusive: %s", strna(format_bytes(bs, sizeof(bs), quota.exclusive))); log_info("referred_max: %s", strna(format_bytes(bs, sizeof(bs), quota.referred_max))); log_info("exclusive_max: %s", strna(format_bytes(bs, sizeof(bs), quota.exclusive_max))); } r = btrfs_subvol_get_read_only_fd(fd); if (r < 0) log_error_errno(r, "Failed to get read only flag: %m"); else log_info("read-only (ioctl): %s", yes_no(r)); safe_close(fd); } r = btrfs_subvol_make("/xxxtest"); if (r < 0) log_error_errno(r, "Failed to make subvolume: %m"); r = write_string_file("/xxxtest/afile", "ljsadhfljasdkfhlkjdsfha"); if (r < 0) log_error_errno(r, "Failed to write file: %m"); r = btrfs_subvol_snapshot("/xxxtest", "/xxxtest2", false, false); if (r < 0) log_error_errno(r, "Failed to make snapshot: %m"); r = btrfs_subvol_snapshot("/xxxtest", "/xxxtest3", true, false); if (r < 0) log_error_errno(r, "Failed to make snapshot: %m"); r = btrfs_subvol_remove("/xxxtest"); if (r < 0) log_error_errno(r, "Failed to remove subvolume: %m"); r = btrfs_subvol_remove("/xxxtest2"); if (r < 0) log_error_errno(r, "Failed to remove subvolume: %m"); r = btrfs_subvol_remove("/xxxtest3"); if (r < 0) log_error_errno(r, "Failed to remove subvolume: %m"); r = btrfs_subvol_snapshot("/etc", "/etc2", true, true); if (r < 0) log_error_errno(r, "Failed to make snapshot: %m"); r = btrfs_subvol_remove("/etc2"); if (r < 0) log_error_errno(r, "Failed to remove subvolume: %m"); return 0; }
static int list_links(int argc, char *argv[], void *userdata) { _cleanup_netlink_message_unref_ sd_netlink_message *req = NULL, *reply = NULL; _cleanup_netlink_unref_ sd_netlink *rtnl = NULL; _cleanup_free_ LinkInfo *links = NULL; int r, c, i; pager_open_if_enabled(); r = sd_netlink_open(&rtnl); if (r < 0) return log_error_errno(r, "Failed to connect to netlink: %m"); r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, 0); if (r < 0) return rtnl_log_create_error(r); r = sd_netlink_message_request_dump(req, true); if (r < 0) return rtnl_log_create_error(r); r = sd_netlink_call(rtnl, req, 0, &reply); if (r < 0) return log_error_errno(r, "Failed to enumerate links: %m"); if (arg_legend) printf("%3s %-16s %-18s %-11s %-10s\n", "IDX", "LINK", "TYPE", "OPERATIONAL", "SETUP"); c = decode_and_sort_links(reply, &links); if (c < 0) return rtnl_log_parse_error(c); for (i = 0; i < c; i++) { _cleanup_free_ char *setup_state = NULL, *operational_state = NULL; _cleanup_device_unref_ sd_device *d = NULL; const char *on_color_operational, *off_color_operational, *on_color_setup, *off_color_setup; char devid[2 + DECIMAL_STR_MAX(int)]; _cleanup_free_ char *t = NULL; sd_network_link_get_operational_state(links[i].ifindex, &operational_state); operational_state_to_color(operational_state, &on_color_operational, &off_color_operational); sd_network_link_get_setup_state(links[i].ifindex, &setup_state); setup_state_to_color(setup_state, &on_color_setup, &off_color_setup); sprintf(devid, "n%i", links[i].ifindex); (void)sd_device_new_from_device_id(&d, devid); link_get_type_string(links[i].iftype, d, &t); printf("%3i %-16s %-18s %s%-11s%s %s%-10s%s\n", links[i].ifindex, links[i].name, strna(t), on_color_operational, strna(operational_state), off_color_operational, on_color_setup, strna(setup_state), off_color_setup); } if (arg_legend) printf("\n%i links listed.\n", c); return 0; }