static int mount_one(const MountPoint *p, bool relabel) { int r; assert(p); if (p->condition_fn && !p->condition_fn()) return 0; /* Relabel first, just in case */ if (relabel) (void) label_fix(p->where, true, true); r = path_is_mount_point(p->where, NULL, AT_SYMLINK_FOLLOW); if (r < 0 && r != -ENOENT) { log_full_errno((p->mode & MNT_FATAL) ? LOG_ERR : LOG_DEBUG, r, "Failed to determine whether %s is a mount point: %m", p->where); return (p->mode & MNT_FATAL) ? r : 0; } if (r > 0) return 0; /* Skip securityfs in a container */ if (!(p->mode & MNT_IN_CONTAINER) && detect_container() > 0) return 0; /* The access mode here doesn't really matter too much, since * the mounted file system will take precedence anyway. */ if (relabel) (void) mkdir_p_label(p->where, 0755); else (void) mkdir_p(p->where, 0755); log_debug("Mounting %s to %s of type %s with options %s.", p->what, p->where, p->type, strna(p->options)); if (mount(p->what, p->where, p->type, p->flags, p->options) < 0) { log_full_errno((p->mode & MNT_FATAL) ? LOG_ERR : LOG_DEBUG, errno, "Failed to mount %s at %s: %m", p->type, p->where); return (p->mode & MNT_FATAL) ? -errno : 0; } /* Relabel again, since we now mounted something fresh here */ if (relabel) (void) label_fix(p->where, false, false); return 1; }
static int builtin_uaccess(struct udev_device *dev, int argc, char *argv[], bool test) { int r; const char *path = NULL, *seat; bool changed_acl = false; uid_t uid; umask(0022); /* don't muck around with ACLs when the system is not running systemd */ if (!logind_running()) return 0; path = udev_device_get_devnode(dev); seat = udev_device_get_property_value(dev, "ID_SEAT"); if (!seat) seat = "seat0"; r = sd_seat_get_active(seat, NULL, &uid); if (r == -ENXIO || r == -ENODATA) { /* No active session on this seat */ r = 0; goto finish; } else if (r < 0) { log_error("Failed to determine active user on seat %s.", seat); goto finish; } r = devnode_acl(path, true, false, 0, true, uid); if (r < 0) { log_full_errno(r == -ENOENT ? LOG_DEBUG : LOG_ERR, r, "Failed to apply ACL on %s: %m", path); goto finish; } changed_acl = true; r = 0; finish: if (path && !changed_acl) { int k; /* Better be safe than sorry and reset ACL */ k = devnode_acl(path, true, false, 0, false, 0); if (k < 0) { log_full_errno(errno == ENOENT ? LOG_DEBUG : LOG_ERR, k, "Failed to apply ACL on %s: %m", path); if (r >= 0) r = k; } } return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; }
static int find_device( const struct rfkill_event *event, sd_device **ret) { _cleanup_(sd_device_unrefp) sd_device *device = NULL; _cleanup_free_ char *sysname = NULL; const char *name; int r; assert(event); assert(ret); if (asprintf(&sysname, "rfkill%i", event->idx) < 0) return log_oom(); r = sd_device_new_from_subsystem_sysname(&device, "rfkill", sysname); if (r < 0) return log_full_errno(IN_SET(r, -ENOENT, -ENXIO, -ENODEV) ? LOG_DEBUG : LOG_ERR, r, "Failed to open device '%s': %m", sysname); r = sd_device_get_sysattr_value(device, "name", &name); if (r < 0) return log_debug_errno(r, "Device has no name, ignoring: %m"); log_debug("Operating on rfkill device '%s'.", name); *ret = TAKE_PTR(device); return 0; }
static int chown_cgroup_path(const char *path, uid_t uid_shift) { _cleanup_close_ int fd = -1; const char *fn; fd = open(path, O_RDONLY|O_CLOEXEC|O_DIRECTORY); if (fd < 0) return -errno; FOREACH_STRING(fn, ".", "cgroup.clone_children", "cgroup.controllers", "cgroup.events", "cgroup.procs", "cgroup.stat", "cgroup.subtree_control", "cgroup.threads", "notify_on_release", "tasks") if (fchownat(fd, fn, uid_shift, uid_shift, 0) < 0) log_full_errno(errno == ENOENT ? LOG_DEBUG : LOG_WARNING, errno, "Failed to chown \"%s/%s\", ignoring: %m", path, fn); return 0; }
int ima_setup(void) { #ifdef HAVE_IMA _cleanup_fclose_ FILE *input = NULL; _cleanup_close_ int imafd = -1; unsigned lineno = 0; char line[page_size()]; if (access(IMA_SECFS_DIR, F_OK) < 0) { log_debug("IMA support is disabled in the kernel, ignoring."); return 0; } if (access(IMA_SECFS_POLICY, W_OK) < 0) { log_warning("Another IMA custom policy has already been loaded, ignoring."); return 0; } imafd = open(IMA_SECFS_POLICY, O_WRONLY|O_CLOEXEC); if (imafd < 0) { log_error_errno(errno, "Failed to open the IMA kernel interface "IMA_SECFS_POLICY", ignoring: %m"); return 0; } /* attempt to write the name of the policy file into sysfs file */ if (write(imafd, IMA_POLICY_PATH, strlen(IMA_POLICY_PATH)) > 0) goto done; /* fall back to copying the policy line-by-line */ input = fopen(IMA_POLICY_PATH, "re"); if (!input) { log_full_errno(errno == ENOENT ? LOG_DEBUG : LOG_WARNING, errno, "Failed to open the IMA custom policy file "IMA_POLICY_PATH", ignoring: %m"); return 0; } close(imafd); imafd = open(IMA_SECFS_POLICY, O_WRONLY|O_CLOEXEC); if (imafd < 0) { log_error_errno(errno, "Failed to open the IMA kernel interface "IMA_SECFS_POLICY", ignoring: %m"); return 0; } FOREACH_LINE(line, input, return log_error_errno(errno, "Failed to read the IMA custom policy file "IMA_POLICY_PATH": %m")) { size_t len; len = strlen(line); lineno++; if (len > 0 && write(imafd, line, len) < 0) return log_error_errno(errno, "Failed to load the IMA custom policy file "IMA_POLICY_PATH"%u: %m", lineno); } done: log_info("Successfully loaded the IMA custom policy "IMA_POLICY_PATH"."); #endif /* HAVE_IMA */ return 0; }
int chown_cgroup(pid_t pid, uid_t uid_shift) { _cleanup_free_ char *path = NULL, *fs = NULL; _cleanup_close_ int fd = -1; const char *fn; int r; r = cg_pid_get_path(NULL, pid, &path); if (r < 0) return log_error_errno(r, "Failed to get container cgroup path: %m"); r = cg_get_path(SYSTEMD_CGROUP_CONTROLLER, path, NULL, &fs); if (r < 0) return log_error_errno(r, "Failed to get file system path for container cgroup: %m"); fd = open(fs, O_RDONLY|O_CLOEXEC|O_DIRECTORY); if (fd < 0) return log_error_errno(errno, "Failed to open %s: %m", fs); FOREACH_STRING(fn, ".", "tasks", "notify_on_release", "cgroup.procs", "cgroup.events", "cgroup.clone_children", "cgroup.controllers", "cgroup.subtree_control") if (fchownat(fd, fn, uid_shift, uid_shift, 0) < 0) log_full_errno(errno == ENOENT ? LOG_DEBUG : LOG_WARNING, errno, "Failed to chown() cgroup file %s, ignoring: %m", fn); return 0; }
static int access_init(sd_bus_error *error) { if (!mac_selinux_use()) return 0; if (initialized) return 1; if (avc_open(NULL, 0) != 0) { int enforce, saved_errno = errno; enforce = security_getenforce(); log_full_errno(enforce != 0 ? LOG_ERR : LOG_WARNING, saved_errno, "Failed to open the SELinux AVC: %m"); /* If enforcement isn't on, then let's suppress this * error, and just don't do any AVC checks. The * warning we printed is hence all the admin will * see. */ if (enforce == 0) return 0; /* Return an access denied error, if we couldn't load * the AVC but enforcing mode was on, or we couldn't * determine whether it is one. */ return sd_bus_error_setf(error, SD_BUS_ERROR_ACCESS_DENIED, "Failed to open the SELinux AVC: %s", strerror(saved_errno)); } selinux_set_callback(SELINUX_CB_AUDIT, (union selinux_callback) audit_callback); selinux_set_callback(SELINUX_CB_LOG, (union selinux_callback) log_callback); initialized = true; return 1; }
static int test_unit_file_get_set(void) { int r; Hashmap *h; Iterator i; UnitFileList *p; h = hashmap_new(&string_hash_ops); assert_se(h); r = unit_file_get_list(UNIT_FILE_SYSTEM, NULL, h, NULL, NULL); if (IN_SET(r, -EPERM, -EACCES)) { log_notice_errno(r, "Skipping test: unit_file_get_list: %m"); return EXIT_TEST_SKIP; } log_full_errno(r == 0 ? LOG_INFO : LOG_ERR, r, "unit_file_get_list: %m"); if (r < 0) return EXIT_FAILURE; HASHMAP_FOREACH(p, h, i) printf("%s = %s\n", p->path, unit_file_state_to_string(p->state)); unit_file_list_free(h); return 0; }
static int fake_filesystems(void) { static const struct fakefs { const char *src; const char *target; const char *error; bool ignore_mount_error; } fakefss[] = { { "test/tmpfs/sys", "/sys", "failed to mount test /sys", false }, { "test/tmpfs/dev", "/dev", "failed to mount test /dev", false }, { "test/run", "/run", "failed to mount test /run", false }, { "test/run", "/etc/udev/rules.d", "failed to mount empty /etc/udev/rules.d", true }, { "test/run", UDEVLIBEXECDIR "/rules.d", "failed to mount empty " UDEVLIBEXECDIR "/rules.d", true }, }; unsigned int i; if (unshare(CLONE_NEWNS) < 0) return log_error_errno(errno, "failed to call unshare(): %m"); if (mount(NULL, "/", NULL, MS_PRIVATE|MS_REC, NULL) < 0) return log_error_errno(errno, "failed to mount / as private: %m"); for (i = 0; i < ELEMENTSOF(fakefss); i++) { if (mount(fakefss[i].src, fakefss[i].target, NULL, MS_BIND, NULL) < 0) { log_full_errno(fakefss[i].ignore_mount_error ? LOG_DEBUG : LOG_ERR, errno, "%s: %m", fakefss[i].error); if (!fakefss[i].ignore_mount_error) return -errno; } } return 0; }
static int context_read_data(Context *c) { int r; struct utsname u; assert(c); context_reset(c); assert_se(uname(&u) >= 0); c->data[PROP_KERNEL_NAME] = strdup(u.sysname); c->data[PROP_KERNEL_RELEASE] = strdup(u.release); c->data[PROP_KERNEL_VERSION] = strdup(u.version); if (!c->data[PROP_KERNEL_NAME] || !c->data[PROP_KERNEL_RELEASE] || !c->data[PROP_KERNEL_VERSION]) return -ENOMEM; c->data[PROP_HOSTNAME] = gethostname_malloc(); if (!c->data[PROP_HOSTNAME]) return -ENOMEM; r = read_etc_hostname(NULL, &c->data[PROP_STATIC_HOSTNAME]); if (r < 0 && r != -ENOENT) return r; r = parse_env_file(NULL, "/etc/machine-info", "PRETTY_HOSTNAME", &c->data[PROP_PRETTY_HOSTNAME], "ICON_NAME", &c->data[PROP_ICON_NAME], "CHASSIS", &c->data[PROP_CHASSIS], "DEPLOYMENT", &c->data[PROP_DEPLOYMENT], "LOCATION", &c->data[PROP_LOCATION]); if (r < 0 && r != -ENOENT) return r; r = parse_os_release(NULL, "PRETTY_NAME", &c->data[PROP_OS_PRETTY_NAME], "CPE_NAME", &c->data[PROP_OS_CPE_NAME], "HOME_URL", &c->data[PROP_HOME_URL], NULL); if (r < 0 && r != -ENOENT) return r; r = id128_read("/sys/class/dmi/id/product_uuid", ID128_UUID, &c->uuid); if (r < 0) log_full_errno(r == -ENOENT ? LOG_DEBUG : LOG_WARNING, r, "Failed to read product UUID, ignoring: %m"); else if (sd_id128_is_null(c->uuid) || sd_id128_is_allf(c->uuid)) log_debug("DMI product UUID " SD_ID128_FORMAT_STR " is all 0x00 or all 0xFF, ignoring.", SD_ID128_FORMAT_VAL(c->uuid)); else c->has_uuid = true; return 0; }
int main(int argc, char *argv[]) { uid_t uid; int r; const char* name = argv[1] ?: "nfsnobody"; r = get_user_creds(&name, &uid, NULL, NULL, NULL); if (r < 0) { log_full_errno(r == -ESRCH ? LOG_NOTICE : LOG_ERR, r, "Failed to resolve \"%s\": %m", name); return r == -ESRCH ? EXIT_TEST_SKIP : EXIT_FAILURE; } r = clean_ipc_by_uid(uid); return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; }
static int apply_all(Hashmap *sysctl_options) { char *property, *value; Iterator i; int r = 0; HASHMAP_FOREACH_KEY(value, property, sysctl_options, i) { int k; k = sysctl_write(property, value); if (k < 0) { log_full_errno(k == -ENOENT ? LOG_INFO : LOG_WARNING, k, "Couldn't write '%s' to '%s', ignoring: %m", value, property); if (r == 0 && k != -ENOENT) r = k; } }
static void print_welcome(void) { _cleanup_free_ char *pretty_name = NULL; static bool done = false; int r; if (done) return; r = parse_os_release(arg_root, "PRETTY_NAME", &pretty_name, NULL); if (r < 0) log_full_errno(r == -ENOENT ? LOG_DEBUG : LOG_WARNING, r, "Failed to read os-release file, ignoring: %m"); printf("\nWelcome to your new installation of %s!\nPlease configure a few basic system settings:\n\n", isempty(pretty_name) ? "Linux" : pretty_name); press_any_key(); done = true; }
static int test_boot_timestamps(void) { char s[MAX(FORMAT_TIMESPAN_MAX, FORMAT_TIMESTAMP_MAX)]; int r; dual_timestamp fw, l, k; dual_timestamp_from_monotonic(&k, 0); r = boot_timestamps(NULL, &fw, &l); if (r < 0) { bool ok = r == -ENOENT || (getuid() != 0 && r == -EACCES); log_full_errno(ok ? LOG_DEBUG : LOG_ERR, r, "Failed to read variables: %m"); return ok ? 0 : r; } log_info("Firmware began %s before kernel.", format_timespan(s, sizeof(s), fw.monotonic, 0)); log_info("Loader began %s before kernel.", format_timespan(s, sizeof(s), l.monotonic, 0)); log_info("Firmware began %s.", format_timestamp(s, sizeof(s), fw.realtime)); log_info("Loader began %s.", format_timestamp(s, sizeof(s), l.realtime)); log_info("Kernel began %s.", format_timestamp(s, sizeof(s), k.realtime)); return 1; }
static int test_efi_loader(void) { usec_t loader_start; usec_t loader_exit; char ts_start[FORMAT_TIMESPAN_MAX]; char ts_exit[FORMAT_TIMESPAN_MAX]; char ts_span[FORMAT_TIMESPAN_MAX]; int r; r = efi_loader_get_boot_usec(&loader_start, &loader_exit); if (r < 0) { bool ok = r == -ENOENT || (getuid() != 0 && r == -EACCES); log_full_errno(ok ? LOG_DEBUG : LOG_ERR, r, "Failed to read EFI loader data: %m"); return ok ? 0 : r; } log_info("EFI Loader: start=%s exit=%s duration=%s", format_timespan(ts_start, sizeof(ts_start), loader_start, USEC_PER_MSEC), format_timespan(ts_exit, sizeof(ts_exit), loader_exit, USEC_PER_MSEC), format_timespan(ts_span, sizeof(ts_span), loader_exit - loader_start, USEC_PER_MSEC)); return 1; }
int kmod_setup(void) { #ifdef HAVE_KMOD static const struct { const char *module; const char *path; bool warn_if_unavailable:1; bool warn_if_module:1; bool (*condition_fn)(void); } kmod_table[] = { /* auto-loading on use doesn't work before udev is up */ { "autofs4", "/sys/class/misc/autofs", true, false, NULL }, /* early configure of ::1 on the loopback device */ { "ipv6", "/sys/module/ipv6", false, true, NULL }, /* this should never be a module */ { "unix", "/proc/net/unix", true, true, NULL }, /* IPC is needed before we bring up any other services */ { "kdbus", "/sys/fs/kdbus", false, false, is_kdbus_wanted }, #ifdef HAVE_LIBIPTC /* netfilter is needed by networkd, nspawn among others, and cannot be autoloaded */ { "ip_tables", "/proc/net/ip_tables_names", false, false, NULL }, #endif }; struct kmod_ctx *ctx = NULL; unsigned int i; int r; if (have_effective_cap(CAP_SYS_MODULE) == 0) return 0; for (i = 0; i < ELEMENTSOF(kmod_table); i++) { struct kmod_module *mod; if (kmod_table[i].path && access(kmod_table[i].path, F_OK) >= 0) continue; if (kmod_table[i].condition_fn && !kmod_table[i].condition_fn()) continue; if (kmod_table[i].warn_if_module) log_debug("Your kernel apparently lacks built-in %s support. Might be " "a good idea to compile it in. We'll now try to work around " "this by loading the module...", kmod_table[i].module); if (!ctx) { ctx = kmod_new(NULL, NULL); if (!ctx) return log_oom(); kmod_set_log_fn(ctx, systemd_kmod_log, NULL); kmod_load_resources(ctx); } r = kmod_module_new_from_name(ctx, kmod_table[i].module, &mod); if (r < 0) { log_error("Failed to lookup module '%s'", kmod_table[i].module); continue; } r = kmod_module_probe_insert_module(mod, KMOD_PROBE_APPLY_BLACKLIST, NULL, NULL, NULL, NULL); if (r == 0) log_debug("Inserted module '%s'", kmod_module_get_name(mod)); else if (r == KMOD_PROBE_APPLY_BLACKLIST) log_info("Module '%s' is blacklisted", kmod_module_get_name(mod)); else { bool print_warning = kmod_table[i].warn_if_unavailable || (r < 0 && r != -ENOENT); log_full_errno(print_warning ? LOG_WARNING : LOG_DEBUG, r, "Failed to insert module '%s': %m", kmod_module_get_name(mod)); } kmod_module_unref(mod); } if (ctx) kmod_unref(ctx); #endif return 0; }
int main(int argc, char *argv[]) { _cleanup_close_ int seed_fd = -1, random_fd = -1; _cleanup_free_ void* buf = NULL; size_t buf_size = 0; ssize_t k; int r, open_rw_error; FILE *f; bool refresh_seed_file = true; if (argc != 2) { log_error("This program requires one argument."); return EXIT_FAILURE; } log_set_target(LOG_TARGET_AUTO); log_parse_environment(); log_open(); umask(0022); /* Read pool size, if possible */ f = fopen("/proc/sys/kernel/random/poolsize", "re"); if (f) { if (fscanf(f, "%zu", &buf_size) > 0) /* poolsize is in bits on 2.6, but we want bytes */ buf_size /= 8; fclose(f); } if (buf_size <= POOL_SIZE_MIN) buf_size = POOL_SIZE_MIN; buf = malloc(buf_size); if (!buf) { r = log_oom(); goto finish; } r = mkdir_parents_label(RANDOM_SEED, 0755); if (r < 0) { log_error_errno(r, "Failed to create directory " RANDOM_SEED_DIR ": %m"); goto finish; } /* When we load the seed we read it and write it to the device * and then immediately update the saved seed with new data, * to make sure the next boot gets seeded differently. */ if (streq(argv[1], "load")) { seed_fd = open(RANDOM_SEED, O_RDWR|O_CLOEXEC|O_NOCTTY|O_CREAT, 0600); open_rw_error = -errno; if (seed_fd < 0) { refresh_seed_file = false; seed_fd = open(RANDOM_SEED, O_RDONLY|O_CLOEXEC|O_NOCTTY); if (seed_fd < 0) { bool missing = errno == ENOENT; log_full_errno(missing ? LOG_DEBUG : LOG_ERR, open_rw_error, "Failed to open " RANDOM_SEED " for writing: %m"); r = log_full_errno(missing ? LOG_DEBUG : LOG_ERR, errno, "Failed to open " RANDOM_SEED " for reading: %m"); if (missing) r = 0; goto finish; } } random_fd = open("/dev/urandom", O_RDWR|O_CLOEXEC|O_NOCTTY, 0600); if (random_fd < 0) { random_fd = open("/dev/urandom", O_WRONLY|O_CLOEXEC|O_NOCTTY, 0600); if (random_fd < 0) { r = log_error_errno(errno, "Failed to open /dev/urandom: %m"); goto finish; } } k = loop_read(seed_fd, buf, buf_size, false); if (k < 0) r = log_error_errno(k, "Failed to read seed from " RANDOM_SEED ": %m"); else if (k == 0) { r = 0; log_debug("Seed file " RANDOM_SEED " not yet initialized, proceeding."); } else { (void) lseek(seed_fd, 0, SEEK_SET); r = loop_write(random_fd, buf, (size_t) k, false); if (r < 0) log_error_errno(r, "Failed to write seed to /dev/urandom: %m"); } } else if (streq(argv[1], "save")) { seed_fd = open(RANDOM_SEED, O_WRONLY|O_CLOEXEC|O_NOCTTY|O_CREAT, 0600); if (seed_fd < 0) { r = log_error_errno(errno, "Failed to open " RANDOM_SEED ": %m"); goto finish; } random_fd = open("/dev/urandom", O_RDONLY|O_CLOEXEC|O_NOCTTY); if (random_fd < 0) { r = log_error_errno(errno, "Failed to open /dev/urandom: %m"); goto finish; } } else { log_error("Unknown verb '%s'.", argv[1]); r = -EINVAL; goto finish; } if (refresh_seed_file) { /* This is just a safety measure. Given that we are root and * most likely created the file ourselves the mode and owner * should be correct anyway. */ (void) fchmod(seed_fd, 0600); (void) fchown(seed_fd, 0, 0); k = loop_read(random_fd, buf, buf_size, false); if (k < 0) { r = log_error_errno(k, "Failed to read new seed from /dev/urandom: %m"); goto finish; } if (k == 0) { log_error("Got EOF while reading from /dev/urandom."); r = -EIO; goto finish; } r = loop_write(seed_fd, buf, (size_t) k, false); if (r < 0) log_error_errno(r, "Failed to write new random seed file: %m"); } finish: return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; }
static int fsck_progress_socket(void) { static const union sockaddr_union sa = { .un.sun_family = AF_UNIX, .un.sun_path = "/run/systemd/fsck.progress", }; int fd, r; fd = socket(AF_UNIX, SOCK_STREAM, 0); if (fd < 0) return log_warning_errno(errno, "socket(): %m"); if (connect(fd, &sa.sa, SOCKADDR_UN_LEN(sa.un)) < 0) { r = log_full_errno(errno == ECONNREFUSED || errno == ENOENT ? LOG_DEBUG : LOG_WARNING, errno, "Failed to connect to progress socket %s, ignoring: %m", sa.un.sun_path); safe_close(fd); return r; } return fd; } int main(int argc, char *argv[]) { _cleanup_close_pair_ int progress_pipe[2] = { -1, -1 }; _cleanup_(sd_device_unrefp) sd_device *dev = NULL; const char *device, *type; bool root_directory; siginfo_t status; struct stat st; int r; pid_t pid; if (argc > 2) { log_error("This program expects one or no arguments."); return EXIT_FAILURE; } log_set_target(LOG_TARGET_AUTO); log_parse_environment(); log_open(); umask(0022); r = parse_proc_cmdline(parse_proc_cmdline_item); if (r < 0) log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m"); test_files(); if (!arg_force && arg_skip) { r = 0; goto finish; } if (argc > 1) { device = argv[1]; if (stat(device, &st) < 0) { r = log_error_errno(errno, "Failed to stat %s: %m", device); goto finish; } if (!S_ISBLK(st.st_mode)) { log_error("%s is not a block device.", device); r = -EINVAL; goto finish; } r = sd_device_new_from_devnum(&dev, 'b', st.st_rdev); if (r < 0) { log_error_errno(r, "Failed to detect device %s: %m", device); goto finish; } root_directory = false; } else { struct timespec times[2]; /* Find root device */ if (stat("/", &st) < 0) { r = log_error_errno(errno, "Failed to stat() the root directory: %m"); goto finish; } /* Virtual root devices don't need an fsck */ if (major(st.st_dev) == 0) { log_debug("Root directory is virtual or btrfs, skipping check."); r = 0; goto finish; } /* check if we are already writable */ times[0] = st.st_atim; times[1] = st.st_mtim; if (utimensat(AT_FDCWD, "/", times, 0) == 0) { log_info("Root directory is writable, skipping check."); r = 0; goto finish; } r = sd_device_new_from_devnum(&dev, 'b', st.st_dev); if (r < 0) { log_error_errno(r, "Failed to detect root device: %m"); goto finish; } r = sd_device_get_devname(dev, &device); if (r < 0) { log_error_errno(r, "Failed to detect device node of root directory: %m"); goto finish; } root_directory = true; } r = sd_device_get_property_value(dev, "ID_FS_TYPE", &type); if (r >= 0) { r = fsck_exists(type); if (r < 0) log_warning_errno(r, "Couldn't detect if fsck.%s may be used for %s, proceeding: %m", type, device); else if (r == 0) { log_info("fsck.%s doesn't exist, not checking file system on %s.", type, device); goto finish; } } if (arg_show_progress) { if (pipe(progress_pipe) < 0) { r = log_error_errno(errno, "pipe(): %m"); goto finish; } } pid = fork(); if (pid < 0) { r = log_error_errno(errno, "fork(): %m"); goto finish; } if (pid == 0) { char dash_c[sizeof("-C")-1 + DECIMAL_STR_MAX(int) + 1]; int progress_socket = -1; const char *cmdline[9]; int i = 0; /* Child */ (void) reset_all_signal_handlers(); (void) reset_signal_mask(); assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0); /* Close the reading side of the progress pipe */ progress_pipe[0] = safe_close(progress_pipe[0]); /* Try to connect to a progress management daemon, if there is one */ progress_socket = fsck_progress_socket(); if (progress_socket >= 0) { /* If this worked we close the progress pipe early, and just use the socket */ progress_pipe[1] = safe_close(progress_pipe[1]); xsprintf(dash_c, "-C%i", progress_socket); } else if (progress_pipe[1] >= 0) { /* Otherwise if we have the progress pipe to our own local handle, we use it */ xsprintf(dash_c, "-C%i", progress_pipe[1]); } else dash_c[0] = 0; cmdline[i++] = "/sbin/fsck"; cmdline[i++] = arg_repair; cmdline[i++] = "-T"; /* * Since util-linux v2.25 fsck uses /run/fsck/<diskname>.lock files. * The previous versions use flock for the device and conflict with * udevd, see https://bugs.freedesktop.org/show_bug.cgi?id=79576#c5 */ cmdline[i++] = "-l"; if (!root_directory) cmdline[i++] = "-M"; if (arg_force) cmdline[i++] = "-f"; if (!isempty(dash_c)) cmdline[i++] = dash_c; cmdline[i++] = device; cmdline[i++] = NULL; execv(cmdline[0], (char**) cmdline); _exit(FSCK_OPERATIONAL_ERROR); } progress_pipe[1] = safe_close(progress_pipe[1]); (void) process_progress(progress_pipe[0]); progress_pipe[0] = -1; r = wait_for_terminate(pid, &status); if (r < 0) { log_error_errno(r, "waitid(): %m"); goto finish; } if (status.si_code != CLD_EXITED || (status.si_status & ~1)) { if (status.si_code == CLD_KILLED || status.si_code == CLD_DUMPED) log_error("fsck terminated by signal %s.", signal_to_string(status.si_status)); else if (status.si_code == CLD_EXITED) log_error("fsck failed with error code %i.", status.si_status); else log_error("fsck failed due to unknown reason."); r = -EINVAL; if (status.si_code == CLD_EXITED && (status.si_status & FSCK_SYSTEM_SHOULD_REBOOT) && root_directory) /* System should be rebooted. */ start_target(SPECIAL_REBOOT_TARGET, "replace-irreversibly"); else if (status.si_code == CLD_EXITED && (status.si_status & (FSCK_SYSTEM_SHOULD_REBOOT | FSCK_ERRORS_LEFT_UNCORRECTED))) /* Some other problem */ start_target(SPECIAL_EMERGENCY_TARGET, "replace"); else { log_warning("Ignoring error."); r = 0; } } else r = 0; if (status.si_code == CLD_EXITED && (status.si_status & FSCK_ERROR_CORRECTED)) (void) touch("/run/systemd/quotacheck"); finish: return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; }
int main(int argc, char *argv[]) { _cleanup_close_ int seed_fd = -1, random_fd = -1; bool read_seed_file, write_seed_file; _cleanup_free_ void* buf = NULL; size_t buf_size = 0; struct stat st; ssize_t k; FILE *f; int r; if (argc != 2) { log_error("This program requires one argument."); return EXIT_FAILURE; } log_set_target(LOG_TARGET_AUTO); log_parse_environment(); log_open(); umask(0022); /* Read pool size, if possible */ f = fopen("/proc/sys/kernel/random/poolsize", "re"); if (f) { if (fscanf(f, "%zu", &buf_size) > 0) /* poolsize is in bits on 2.6, but we want bytes */ buf_size /= 8; fclose(f); } if (buf_size < POOL_SIZE_MIN) buf_size = POOL_SIZE_MIN; r = mkdir_parents_label(RANDOM_SEED, 0755); if (r < 0) { log_error_errno(r, "Failed to create directory " RANDOM_SEED_DIR ": %m"); goto finish; } /* When we load the seed we read it and write it to the device and then immediately update the saved seed with * new data, to make sure the next boot gets seeded differently. */ if (streq(argv[1], "load")) { int open_rw_error; seed_fd = open(RANDOM_SEED, O_RDWR|O_CLOEXEC|O_NOCTTY|O_CREAT, 0600); open_rw_error = -errno; if (seed_fd < 0) { write_seed_file = false; seed_fd = open(RANDOM_SEED, O_RDONLY|O_CLOEXEC|O_NOCTTY); if (seed_fd < 0) { bool missing = errno == ENOENT; log_full_errno(missing ? LOG_DEBUG : LOG_ERR, open_rw_error, "Failed to open " RANDOM_SEED " for writing: %m"); r = log_full_errno(missing ? LOG_DEBUG : LOG_ERR, errno, "Failed to open " RANDOM_SEED " for reading: %m"); if (missing) r = 0; goto finish; } } else write_seed_file = true; random_fd = open("/dev/urandom", O_RDWR|O_CLOEXEC|O_NOCTTY, 0600); if (random_fd < 0) { write_seed_file = false; random_fd = open("/dev/urandom", O_WRONLY|O_CLOEXEC|O_NOCTTY, 0600); if (random_fd < 0) { r = log_error_errno(errno, "Failed to open /dev/urandom: %m"); goto finish; } } read_seed_file = true; } else if (streq(argv[1], "save")) { random_fd = open("/dev/urandom", O_RDONLY|O_CLOEXEC|O_NOCTTY); if (random_fd < 0) { r = log_error_errno(errno, "Failed to open /dev/urandom: %m"); goto finish; } seed_fd = open(RANDOM_SEED, O_WRONLY|O_CLOEXEC|O_NOCTTY|O_CREAT, 0600); if (seed_fd < 0) { r = log_error_errno(errno, "Failed to open " RANDOM_SEED ": %m"); goto finish; } read_seed_file = false; write_seed_file = true; } else { log_error("Unknown verb '%s'.", argv[1]); r = -EINVAL; goto finish; } if (fstat(seed_fd, &st) < 0) { r = log_error_errno(errno, "Failed to stat() seed file " RANDOM_SEED ": %m"); goto finish; } /* If the seed file is larger than what we expect, then honour the existing size and save/restore as much as it says */ if ((uint64_t) st.st_size > buf_size) buf_size = MIN(st.st_size, POOL_SIZE_MAX); buf = malloc(buf_size); if (!buf) { r = log_oom(); goto finish; } if (read_seed_file) { sd_id128_t mid; int z; k = loop_read(seed_fd, buf, buf_size, false); if (k < 0) r = log_error_errno(k, "Failed to read seed from " RANDOM_SEED ": %m"); else if (k == 0) { r = 0; log_debug("Seed file " RANDOM_SEED " not yet initialized, proceeding."); } else { (void) lseek(seed_fd, 0, SEEK_SET); r = loop_write(random_fd, buf, (size_t) k, false); if (r < 0) log_error_errno(r, "Failed to write seed to /dev/urandom: %m"); } /* Let's also write the machine ID into the random seed. Why? As an extra protection against "golden * images" that are put together sloppily, i.e. images which are duplicated on multiple systems but * where the random seed file is not properly reset. Frequently the machine ID is properly reset on * those systems however (simply because it's easier to notice, if it isn't due to address clashes and * so on, while random seed equivalence is generally not noticed easily), hence let's simply write the * machined ID into the random pool too. */ z = sd_id128_get_machine(&mid); if (z < 0) log_debug_errno(z, "Failed to get machine ID, ignoring: %m"); else { z = loop_write(random_fd, &mid, sizeof(mid), false); if (z < 0) log_debug_errno(z, "Failed to write machine ID to /dev/urandom, ignoring: %m"); } } if (write_seed_file) { /* This is just a safety measure. Given that we are root and * most likely created the file ourselves the mode and owner * should be correct anyway. */ (void) fchmod(seed_fd, 0600); (void) fchown(seed_fd, 0, 0); k = loop_read(random_fd, buf, buf_size, false); if (k < 0) { r = log_error_errno(k, "Failed to read new seed from /dev/urandom: %m"); goto finish; } if (k == 0) { log_error("Got EOF while reading from /dev/urandom."); r = -EIO; goto finish; } r = loop_write(seed_fd, buf, (size_t) k, false); if (r < 0) log_error_errno(r, "Failed to write new random seed file: %m"); } finish: return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; }
/* 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, ConfigParseFlags flags, void *userdata) { _cleanup_free_ char *section = NULL, *continuation = NULL; _cleanup_fclose_ FILE *ours = NULL; unsigned line = 0, section_line = 0; bool section_ignored = false; 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 ((flags & CONFIG_PARSE_WARN) || errno == ENOENT) log_full_errno(errno == ENOENT ? LOG_DEBUG : LOG_ERR, errno, "Failed to open configuration file '%s': %m", filename); return errno == ENOENT ? 0 : -errno; } } fd_warn_permissions(filename, fileno(f)); for (;;) { _cleanup_free_ char *buf = NULL; bool escaped = false; char *l, *p, *e; r = read_line(f, LONG_LINE_MAX, &buf); if (r == 0) break; if (r == -ENOBUFS) { if (flags & CONFIG_PARSE_WARN) log_error_errno(r, "%s:%u: Line too long", filename, line); return r; } if (r < 0) { if (CONFIG_PARSE_WARN) log_error_errno(r, "%s:%u: Error while reading configuration file: %m", filename, line); return r; } l = buf; if (!(flags & CONFIG_PARSE_REFUSE_BOM)) { char *q; q = startswith(buf, UTF8_BYTE_ORDER_MARK); if (q) { l = q; flags |= CONFIG_PARSE_REFUSE_BOM; } } if (continuation) { if (strlen(continuation) + strlen(l) > LONG_LINE_MAX) { if (flags & CONFIG_PARSE_WARN) log_error("%s:%u: Continuation line too long", filename, line); return -ENOBUFS; } if (!strextend(&continuation, l, NULL)) { if (flags & CONFIG_PARSE_WARN) log_oom(); return -ENOMEM; } p = continuation; } else p = l; for (e = p; *e; e++) { if (escaped) escaped = false; else if (*e == '\\') escaped = true; } if (escaped) { *(e-1) = ' '; if (!continuation) { continuation = strdup(l); if (!continuation) { if (flags & CONFIG_PARSE_WARN) log_oom(); return -ENOMEM; } } continue; } r = parse_line(unit, filename, ++line, sections, lookup, table, flags, §ion, §ion_line, §ion_ignored, p, userdata); if (r < 0) { if (flags & CONFIG_PARSE_WARN) log_warning_errno(r, "%s:%u: Failed to parse file: %m", filename, line); return r; } continuation = mfree(continuation); } if (continuation) { r = parse_line(unit, filename, ++line, sections, lookup, table, flags, §ion, §ion_line, §ion_ignored, continuation, userdata); if (r < 0) { if (flags & CONFIG_PARSE_WARN) log_warning_errno(r, "%s:%u: Failed to parse file: %m", filename, line); return r; } } return 0; }