static int plgfs_test_super(struct super_block *sb, void *data) { struct plgfs_mnt_cfg *cfg; struct plgfs_sb_info *sbi; int i; cfg = (struct plgfs_mnt_cfg *)data; sbi = plgfs_sbi(sb); if (sbi->pdev) { if (sbi->pdev->bdev_hidden != cfg->bdev) return 0; } else if (!path_equal(&sbi->path_hidden, &cfg->path)) return 0; cfg->flags |= PLGFS_OPT_DIFF_PLGS; if (sbi->plgs_nr != cfg->plgs_nr) return 0; for (i = 0; i < cfg->plgs_nr; i++) { if (sbi->plgs[i] != cfg->plgs[i]) return 0; } cfg->flags &= ~PLGFS_OPT_DIFF_PLGS; return 1; }
int get_user_creds_clean( const char **username, uid_t *uid, gid_t *gid, const char **home, const char **shell) { int r; /* Like get_user_creds(), but resets home/shell to NULL if they don't contain anything relevant. */ r = get_user_creds(username, uid, gid, home, shell); if (r < 0) return r; if (shell && (isempty(*shell) || PATH_IN_SET(*shell, "/bin/nologin", "/sbin/nologin", "/usr/bin/nologin", "/usr/sbin/nologin"))) *shell = NULL; if (home && (isempty(*home) || path_equal(*home, "/"))) *home = NULL; return 0; }
int rm_rf(const char *path, RemoveFlags flags) { int fd, r; struct statfs s; assert(path); /* We refuse to clean the root file system with this * call. This is extra paranoia to never cause a really * seriously broken system. */ if (path_equal(path, "/")) { log_error("Attempted to remove entire root file system, and we can't allow that."); return -EPERM; } if ((flags & (REMOVE_SUBVOLUME|REMOVE_ROOT|REMOVE_PHYSICAL)) == (REMOVE_SUBVOLUME|REMOVE_ROOT|REMOVE_PHYSICAL)) { /* Try to remove as subvolume first */ r = btrfs_subvol_remove(path, BTRFS_REMOVE_RECURSIVE|BTRFS_REMOVE_QUOTA); if (r >= 0) return r; if (r != -ENOTTY && r != -EINVAL && r != -ENOTDIR) return r; /* Not btrfs or not a subvolume */ } fd = open(path, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW|O_NOATIME); if (fd < 0) { if (errno != ENOTDIR && errno != ELOOP) return -errno; if (!(flags & REMOVE_PHYSICAL)) { if (statfs(path, &s) < 0) return -errno; if (is_physical_fs(&s)) { log_error("Attempted to remove disk file system, and we can't allow that."); return -EPERM; } } if ((flags & REMOVE_ROOT) && !(flags & REMOVE_ONLY_DIRECTORIES)) if (unlink(path) < 0 && errno != ENOENT) return -errno; return 0; } r = rm_rf_children(fd, flags, NULL); if (flags & REMOVE_ROOT) { if (rmdir(path) < 0) { if (r == 0 && errno != ENOENT) r = -errno; } } return r; }
static int automount_verify(Automount *a) { bool b; char *e; assert(a); if (UNIT(a)->load_state != UNIT_LOADED) return 0; if (path_equal(a->where, "/")) { log_error_unit(UNIT(a)->id, "Cannot have an automount unit for the root directory. Refusing."); return -EINVAL; } e = unit_name_from_path(a->where, ".automount"); if (!e) return -ENOMEM; b = unit_has_name(UNIT(a), e); free(e); if (!b) { log_error_unit(UNIT(a)->id, "%s's Where setting doesn't match unit name. Refusing.", UNIT(a)->id); return -EINVAL; } return 0; }
static int device_update_unit(Manager *m, struct udev_device *dev, const char *path, bool main) { const char *sysfs, *model; Unit *u = NULL; int r; bool delete; assert(m); if (!(sysfs = udev_device_get_syspath(dev))) return -ENOMEM; if ((r = device_find_escape_name(m, path, &u)) < 0) return r; if (u && DEVICE(u)->sysfs && !path_equal(DEVICE(u)->sysfs, sysfs)) return -EEXIST; if (!u) { delete = true; u = unit_new(m, sizeof(Device)); if (!u) return -ENOMEM; r = device_add_escaped_name(u, path); if (r < 0) goto fail; unit_add_to_load_queue(u); } else
static void drop_duplicates(MountEntry *m, unsigned *n) { MountEntry *f, *t, *previous; assert(m); assert(n); /* Drops duplicate entries. Expects that the array is properly ordered already. */ for (f = m, t = m, previous = NULL; f < m + *n; f++) { /* The first one wins (which is the one with the more restrictive mode), see mount_path_compare() * above. */ if (previous && path_equal(mount_entry_path(f), mount_entry_path(previous))) { log_debug("%s is duplicate.", mount_entry_path(f)); previous->read_only = previous->read_only || mount_entry_read_only(f); /* Propagate the read-only flag to the remaining entry */ mount_entry_done(f); continue; } *t = *f; previous = t; t++; } *n = t - m; }
static int automount_verify(Automount *a) { _cleanup_free_ char *e = NULL; int r; assert(a); if (UNIT(a)->load_state != UNIT_LOADED) return 0; if (path_equal(a->where, "/")) { log_unit_error(UNIT(a), "Cannot have an automount unit for the root directory. Refusing."); return -EINVAL; } r = unit_name_from_path(a->where, ".automount", &e); if (r < 0) return log_unit_error(UNIT(a), "Failed to generate unit name from path: %m"); if (!unit_has_name(UNIT(a), e)) { log_unit_error(UNIT(a), "Where= setting doesn't match unit name. Refusing."); return -EINVAL; } return 0; }
STRV_FOREACH_PAIR(link, p, links) { _cleanup_free_ char *target = NULL; char *f = strappenda(original_dir, *p); char *l = strappenda(copy_dir, *link); assert_se(readlink_and_canonicalize(l, &target) == 0); assert_se(path_equal(f, target)); }
STRV_FOREACH_PAIR(link, p, links) { _cleanup_free_ char *target, *f, *l; assert_se(f = strjoin(original_dir, *p)); assert_se(l = strjoin(copy_dir, *link)); assert_se(chase_symlinks(l, NULL, 0, &target) == 1); assert_se(path_equal(f, target)); }
bool mount_point_ignore(const char *path) { const char *i; NULSTR_FOREACH(i, ignore_paths) if (path_equal(path, i)) return true; return false; }
STRV_FOREACH_PAIR(link, p, links) { _cleanup_free_ char *target = NULL, *f, *l; assert_se((f = strjoin(original_dir, *p))); assert_se((l = strjoin(copy_dir, *link))); assert_se(readlink_and_canonicalize(l, NULL, &target) == 0); assert_se(path_equal(f, target)); }
/* * Whenever we do any sort of path lookup, we must make sure we are in * the namespace of our southbound fs. This is a simple check that our * task struct has the right context. */ int in_southbound_context(struct task_struct *tsk) { int err; mutex_lock(&ftfs_southbound_lock); task_lock(tsk); err = path_equal(&tsk->fs->root, &ftfs_fs->root); task_unlock(tsk); mutex_unlock(&ftfs_southbound_lock); return err; }
Archive* FileSystem::getArchive (const std::string& archiveName) { for (ArchiveEntryList::iterator i = g_archives.begin(); i != g_archives.end(); ++i) { if (i->is_pakfile) { if (path_equal(i->name, archiveName)) { return i->archive; } } } return 0; }
int device_path_parse_major_minor(const char *path, mode_t *ret_mode, dev_t *ret_devno) { mode_t mode; dev_t devno; int r; /* Tries to extract the major/minor directly from the device path if we can. Handles /dev/block/ and /dev/char/ * paths, as well out synthetic inaccessible device nodes. Never goes to disk. Returns -ENODEV if the device * path cannot be parsed like this. */ if (path_equal(path, "/run/systemd/inaccessible/chr")) { mode = S_IFCHR; devno = makedev(0, 0); } else if (path_equal(path, "/run/systemd/inaccessible/blk")) { mode = S_IFBLK; devno = makedev(0, 0); } else { const char *w; w = path_startswith(path, "/dev/block/"); if (w) mode = S_IFBLK; else { w = path_startswith(path, "/dev/char/"); if (!w) return -ENODEV; mode = S_IFCHR; } r = parse_dev(w, &devno); if (r < 0) return r; } if (ret_mode) *ret_mode = mode; if (ret_devno) *ret_devno = devno; return 0; }
Archive* getArchive(const char* archiveName, bool pakonly) { for(archives_t::iterator i = g_archives.begin(); i != g_archives.end(); ++i) { if(pakonly && !(*i).is_pakfile) continue; if(path_equal((*i).name.c_str(), archiveName)) return (*i).archive; } return 0; }
bool mount_point_is_api(const char *path) { unsigned i; /* Checks if this mount point is considered "API", and hence * should be ignored */ for (i = 0; i < ELEMENTSOF(mount_table); i ++) if (path_equal(path, mount_table[i].where)) return true; return path_startswith(path, "/sys/fs/cgroup/"); }
static int equivalent(const char *a, const char *b) { _cleanup_free_ char *x = NULL, *y = NULL; x = canonicalize_file_name(a); if (!x) return -errno; y = canonicalize_file_name(b); if (!y) return -errno; return path_equal(x, y); }
static int equivalent(const char *a, const char *b) { _cleanup_free_ char *x = NULL, *y = NULL; int r; r = chase_symlinks(a, NULL, 0, &x); if (r < 0) return r; r = chase_symlinks(b, NULL, 0, &y); if (r < 0) return r; return path_equal(x, y); }
static void test_u_n_f_p_one(const char *path, const char *suffix, const char *expected, int ret) { _cleanup_free_ char *t = NULL; assert_se(unit_name_from_path(path, suffix, &t) == ret); puts(strna(t)); assert_se(streq_ptr(t, expected)); if (t) { _cleanup_free_ char *k = NULL; assert_se(unit_name_to_path(t, &k) == 0); puts(strna(k)); assert_se(path_equal(k, isempty(path) ? "/" : path)); } }
static void test_mnt_id(void) { _cleanup_fclose_ FILE *f = NULL; Hashmap *h; Iterator i; char *p; void *k; int r; log_info("/* %s */", __func__); assert_se(f = fopen("/proc/self/mountinfo", "re")); assert_se(h = hashmap_new(&trivial_hash_ops)); for (;;) { _cleanup_free_ char *line = NULL, *path = NULL; int mnt_id; r = read_line(f, LONG_LINE_MAX, &line); if (r == 0) break; assert_se(r > 0); assert_se(sscanf(line, "%i %*s %*s %*s %ms", &mnt_id, &path) == 2); log_debug("mountinfo: %s → %i", path, mnt_id); assert_se(hashmap_put(h, INT_TO_PTR(mnt_id), path) >= 0); path = NULL; } HASHMAP_FOREACH_KEY(p, k, h, i) { int mnt_id = PTR_TO_INT(k), mnt_id2; r = path_get_mnt_id(p, &mnt_id2); if (r < 0) { log_debug_errno(r, "Failed to get the mnt id of %s: %m\n", p); continue; } log_debug("mnt ids of %s are %i, %i\n", p, mnt_id, mnt_id2); if (mnt_id == mnt_id2) continue; /* The ids don't match? If so, then there are two mounts on the same path, let's check if * that's really the case */ char *t = hashmap_get(h, INT_TO_PTR(mnt_id2)); log_debug("the other path for mnt id %i is %s\n", mnt_id2, t); assert_se(path_equal(p, t)); }
static void test_u_n_f_p_i_one(const char *pattern, const char *path, const char *suffix, const char *expected, int ret) { _cleanup_free_ char *t = NULL; assert_se(unit_name_from_path_instance(pattern, path, suffix, &t) == ret); puts(strna(t)); assert_se(streq_ptr(t, expected)); if (t) { _cleanup_free_ char *k = NULL, *v = NULL; assert_se(unit_name_to_instance(t, &k) > 0); assert_se(unit_name_path_unescape(k, &v) == 0); assert_se(path_equal(v, isempty(path) ? "/" : path)); } }
static void test_get_user_creds_one(const char *id, const char *name, uid_t uid, gid_t gid, const char *home, const char *shell) { const char *rhome = NULL; const char *rshell = NULL; uid_t ruid = UID_INVALID; gid_t rgid = GID_INVALID; int r; log_info("/* %s(\"%s\", \"%s\", "UID_FMT", "GID_FMT", \"%s\", \"%s\") */", __func__, id, name, uid, gid, home, shell); r = get_user_creds(&id, &ruid, &rgid, &rhome, &rshell, 0); log_info_errno(r, "got \"%s\", "UID_FMT", "GID_FMT", \"%s\", \"%s\": %m", id, ruid, rgid, strnull(rhome), strnull(rshell)); if (!synthesize_nobody() && streq(name, NOBODY_USER_NAME)) { log_info("(skipping detailed tests because nobody is not synthesized)"); return; } assert_se(r == 0); assert_se(streq_ptr(id, name)); assert_se(ruid == uid); assert_se(rgid == gid); assert_se(path_equal(rhome, home)); assert_se(path_equal(rshell, shell)); }
HASHMAP_FOREACH(f, top, i) { char *o; o = hashmap_get(bottom, path_get_file_name(f)); assert(o); if (path_equal(o, f)) { notify_override_unchanged(f); continue; } k = found_override(f, o); if (k < 0) r = k; n_found ++; }
static int device_setup_unit(Manager *m, struct udev_device *dev, const char *path, bool main) { _cleanup_free_ char *e = NULL; const char *sysfs = NULL; Unit *u = NULL; bool delete; int r; assert(m); assert(path); if (dev) { sysfs = udev_device_get_syspath(dev); if (!sysfs) return 0; } r = unit_name_from_path(path, ".device", &e); if (r < 0) return log_error_errno(r, "Failed to generate unit name from device path: %m"); u = manager_get_unit(m, e); /* The device unit can still be present even if the device was * unplugged: a mount unit can reference it hence preventing * the GC to have garbaged it. That's desired since the device * unit may have a dependency on the mount unit which was * added during the loading of the later. */ if (dev && u && DEVICE(u)->state == DEVICE_PLUGGED) { /* This unit is in plugged state: we're sure it's * attached to a device. */ if (!path_equal(DEVICE(u)->sysfs, sysfs)) { log_unit_debug(u, "Dev %s appeared twice with different sysfs paths %s and %s", e, DEVICE(u)->sysfs, sysfs); return -EEXIST; } } if (!u) { delete = true; r = unit_new_for_name(m, sizeof(Device), e, &u); if (r < 0) goto fail; unit_add_to_load_queue(u); } else
int mount_systemd_cgroup_writable( const char *dest, CGroupUnified unified_requested) { _cleanup_free_ char *own_cgroup_path = NULL; const char *root, *own; int r; assert(dest); r = cg_pid_get_path(NULL, 0, &own_cgroup_path); if (r < 0) return log_error_errno(r, "Failed to determine our own cgroup path: %m"); /* If we are living in the top-level, then there's nothing to do... */ if (path_equal(own_cgroup_path, "/")) return 0; if (unified_requested >= CGROUP_UNIFIED_ALL) { root = prefix_roota(dest, "/sys/fs/cgroup"); own = strjoina(root, own_cgroup_path); } else { if (unified_requested >= CGROUP_UNIFIED_SYSTEMD) { root = prefix_roota(dest, "/sys/fs/cgroup/unified"); own = strjoina(root, own_cgroup_path); r = mount_systemd_cgroup_writable_one(root, own); if (r < 0) return r; } root = prefix_roota(dest, "/sys/fs/cgroup/systemd"); own = strjoina(root, own_cgroup_path); } return mount_systemd_cgroup_writable_one(root, own); }
int main(int argc, char*argv[]) { char *path; char *c, *p; assert_se(cg_create(SYSTEMD_CGROUP_CONTROLLER, "/test-a") == 0); assert_se(cg_create(SYSTEMD_CGROUP_CONTROLLER, "/test-a") == 0); assert_se(cg_create(SYSTEMD_CGROUP_CONTROLLER, "/test-b") == 0); assert_se(cg_create(SYSTEMD_CGROUP_CONTROLLER, "/test-b/test-c") == 0); assert_se(cg_create_and_attach(SYSTEMD_CGROUP_CONTROLLER, "/test-b", 0) == 0); assert_se(cg_get_by_pid(SYSTEMD_CGROUP_CONTROLLER, getpid(), &path) == 0); assert_se(streq(path, "/test-b")); free(path); assert_se(cg_attach(SYSTEMD_CGROUP_CONTROLLER, "/test-a", 0) == 0); assert_se(cg_get_by_pid(SYSTEMD_CGROUP_CONTROLLER, getpid(), &path) == 0); assert_se(path_equal(path, "/test-a")); free(path); assert_se(cg_create_and_attach(SYSTEMD_CGROUP_CONTROLLER, "/test-b/test-d", 0) == 0); assert_se(cg_get_by_pid(SYSTEMD_CGROUP_CONTROLLER, getpid(), &path) == 0); assert_se(path_equal(path, "/test-b/test-d")); free(path); assert_se(cg_get_path(SYSTEMD_CGROUP_CONTROLLER, "/test-b/test-d", NULL, &path) == 0); assert_se(path_equal(path, "/sys/fs/cgroup/systemd/test-b/test-d")); free(path); assert_se(cg_is_empty(SYSTEMD_CGROUP_CONTROLLER, "/test-a", false) > 0); assert_se(cg_is_empty(SYSTEMD_CGROUP_CONTROLLER, "/test-b", false) > 0); assert_se(cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, "/test-a", false) > 0); assert_se(cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, "/test-b", false) == 0); assert_se(cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, "/test-a", 0, false, false, false, NULL) == 0); assert_se(cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, "/test-b", 0, false, false, false, NULL) > 0); assert_se(cg_migrate_recursive(SYSTEMD_CGROUP_CONTROLLER, "/test-b", SYSTEMD_CGROUP_CONTROLLER, "/test-a", false, false) > 0); assert_se(cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, "/test-a", false) == 0); assert_se(cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, "/test-b", false) > 0); assert_se(cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, "/test-a", 0, false, false, false, NULL) > 0); assert_se(cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, "/test-b", 0, false, false, false, NULL) == 0); cg_trim(SYSTEMD_CGROUP_CONTROLLER, "/", false); assert_se(cg_delete(SYSTEMD_CGROUP_CONTROLLER, "/test-b") < 0); assert_se(cg_delete(SYSTEMD_CGROUP_CONTROLLER, "/test-a") >= 0); assert_se(cg_split_spec("foobar:/", &c, &p) == 0); assert(streq(c, "foobar")); assert(streq(p, "/")); free(c); free(p); assert_se(cg_split_spec("foobar:", &c, &p) < 0); assert_se(cg_split_spec("foobar:asdfd", &c, &p) < 0); assert_se(cg_split_spec(":///", &c, &p) < 0); assert_se(cg_split_spec(":", &c, &p) < 0); assert_se(cg_split_spec("", &c, &p) < 0); assert_se(cg_split_spec("fo/obar:/", &c, &p) < 0); assert_se(cg_split_spec("/", &c, &p) >= 0); assert(c == NULL); assert(streq(p, "/")); free(p); assert_se(cg_split_spec("foo", &c, &p) >= 0); assert(streq(c, "foo")); assert(p == NULL); free(c); return 0; }
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: free(arg_root); arg_root = path_make_absolute_cwd(optarg); if (!arg_root) return log_oom(); path_kill_slashes(arg_root); if (path_equal(arg_root, "/")) arg_root = mfree(arg_root); 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 switch_root(const char *new_root, const char *oldroot, bool detach_oldroot, unsigned long mountflags) { /* Don't try to unmount/move the old "/", there's no way to do it. */ static const char move_mounts[] = "/dev\0" "/proc\0" "/sys\0" "/run\0"; _cleanup_close_ int old_root_fd = -1; struct stat new_root_stat; bool old_root_remove; const char *i, *temporary_old_root; if (path_equal(new_root, "/")) return 0; temporary_old_root = strappenda(new_root, oldroot); mkdir_p_label(temporary_old_root, 0755); old_root_remove = in_initrd(); if (stat(new_root, &new_root_stat) < 0) { log_error("Failed to stat directory %s: %m", new_root); return -errno; } /* Work-around for kernel design: the kernel refuses switching * root if any file systems are mounted MS_SHARED. Hence * remount them MS_PRIVATE here as a work-around. * * https://bugzilla.redhat.com/show_bug.cgi?id=847418 */ if (mount(NULL, "/", NULL, MS_REC|MS_PRIVATE, NULL) < 0) log_warning("Failed to make \"/\" private mount: %m"); NULSTR_FOREACH(i, move_mounts) { char new_mount[PATH_MAX]; struct stat sb; snprintf(new_mount, sizeof(new_mount), "%s%s", new_root, i); char_array_0(new_mount); mkdir_p_label(new_mount, 0755); if ((stat(new_mount, &sb) < 0) || sb.st_dev != new_root_stat.st_dev) { /* Mount point seems to be mounted already or * stat failed. Unmount the old mount * point. */ if (umount2(i, MNT_DETACH) < 0) log_warning("Failed to unmount %s: %m", i); continue; } if (mount(i, new_mount, NULL, mountflags, NULL) < 0) { if (mountflags & MS_MOVE) { log_error("Failed to move mount %s to %s, forcing unmount: %m", i, new_mount); if (umount2(i, MNT_FORCE) < 0) log_warning("Failed to unmount %s: %m", i); } if (mountflags & MS_BIND) log_error("Failed to bind mount %s to %s: %m", i, new_mount); } }
static int add_mount( const char *what, const char *where, const char *type, const char *opts, int passno, bool noauto, bool nofail, bool automount, bool isbind, const char *pre, const char *pre2, const char *online, const char *post, const char *source) { _cleanup_free_ char *name = NULL, *unit = NULL, *lnk = NULL, *device = NULL, *automount_name = NULL, *automount_unit = NULL; _cleanup_fclose_ FILE *f = NULL; int r; assert(what); assert(where); assert(type); assert(opts); assert(source); if (streq(type, "autofs")) return 0; if (!is_path(where)) { log_warning("Mount point %s is not a valid path, ignoring.", where); return 0; } if (mount_point_is_api(where) || mount_point_ignore(where)) return 0; name = unit_name_from_path(where, ".mount"); if (!name) return log_oom(); 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 mount unit file %s, as it already exists. Duplicate entry in /etc/fstab?", unit); else log_error("Failed to create unit file %s: %m", unit); return -errno; } fprintf(f, "# Automatically generated by systemd-fstab-generator\n\n" "[Unit]\n" "SourcePath=%s\n" "DefaultDependencies=no\n", source); if (!path_equal(where, "/")) { if (pre) fprintf(f, "After=%s\n", pre); if (pre2) fprintf(f, "After=%s\n", pre2); if (online) fprintf(f, "After=%s\n" "Wants=%s\n", online, online); fprintf(f, "Conflicts=" SPECIAL_UMOUNT_TARGET "\n" "Before=" SPECIAL_UMOUNT_TARGET "\n"); } if (post && !noauto && !nofail && !automount) fprintf(f, "Before=%s\n", post); fprintf(f, "\n" "[Mount]\n" "What=%s\n" "Where=%s\n" "Type=%s\n" "FsckPassNo=%i\n", what, where, type, passno); if (!isempty(opts) && !streq(opts, "defaults")) fprintf(f, "Options=%s\n", opts); fflush(f); if (ferror(f)) { log_error("Failed to write unit file %s: %m", unit); return -errno; } if (!noauto) { /* don't start network mounts automatically, we do that via ifupdown hooks for now */ if (post && !streq(post, SPECIAL_REMOTE_FS_TARGET)) { lnk = strjoin(arg_dest, "/", post, nofail || automount ? ".wants/" : ".requires/", name, NULL); if (!lnk) return log_oom(); mkdir_parents_label(lnk, 0755); if (symlink(unit, lnk) < 0) { log_error("Failed to create symlink %s: %m", lnk); return -errno; } } if (!isbind && !path_equal(where, "/")) { r = device_name(what, &device); if (r < 0) return r; if (r > 0) { free(lnk); lnk = strjoin(arg_dest, "/", device, ".wants/", name, NULL); if (!lnk) return log_oom(); mkdir_parents_label(lnk, 0755); if (symlink(unit, lnk) < 0) { log_error("Failed to create symlink %s: %m", lnk); return -errno; } } } } if (automount && !path_equal(where, "/")) { automount_name = unit_name_from_path(where, ".automount"); if (!name) return log_oom(); automount_unit = strjoin(arg_dest, "/", automount_name, NULL); if (!automount_unit) return log_oom(); fclose(f); f = fopen(automount_unit, "wxe"); if (!f) { log_error("Failed to create unit file %s: %m", automount_unit); return -errno; } fprintf(f, "# Automatically generated by systemd-fstab-generator\n\n" "[Unit]\n" "SourcePath=%s\n" "DefaultDependencies=no\n" "Conflicts=" SPECIAL_UMOUNT_TARGET "\n" "Before=" SPECIAL_UMOUNT_TARGET "\n", source); if (post) fprintf(f, "Before= %s\n", post); fprintf(f, "[Automount]\n" "Where=%s\n", where); fflush(f); if (ferror(f)) { log_error("Failed to write unit file %s: %m", automount_unit); return -errno; } free(lnk); lnk = strjoin(arg_dest, "/", post, nofail ? ".wants/" : ".requires/", automount_name, NULL); if (!lnk) return log_oom(); mkdir_parents_label(lnk, 0755); if (symlink(automount_unit, lnk) < 0) { log_error("Failed to create symlink %s: %m", lnk); return -errno; } } return 0; }
int main(int argc, char *argv[]) { int ret = EXIT_FAILURE; _cleanup_endmntent_ FILE *f = NULL; struct mntent* me; Hashmap *pids = NULL; if (argc > 1) { log_error("This program takes no argument."); return EXIT_FAILURE; } log_set_target(LOG_TARGET_AUTO); log_parse_environment(); log_open(); umask(0022); f = setmntent("/etc/fstab", "r"); if (!f) { if (errno == ENOENT) return EXIT_SUCCESS; log_error("Failed to open /etc/fstab: %m"); return EXIT_FAILURE; } pids = hashmap_new(trivial_hash_func, trivial_compare_func); if (!pids) { log_error("Failed to allocate set"); goto finish; } ret = EXIT_SUCCESS; while ((me = getmntent(f))) { pid_t pid; int k; char *s; /* Remount the root fs, /usr and all API VFS */ if (!mount_point_is_api(me->mnt_dir) && !path_equal(me->mnt_dir, "/") && !path_equal(me->mnt_dir, "/usr")) continue; log_debug("Remounting %s", me->mnt_dir); pid = fork(); if (pid < 0) { log_error("Failed to fork: %m"); ret = EXIT_FAILURE; continue; } if (pid == 0) { const char *arguments[5]; /* Child */ arguments[0] = "/bin/mount"; arguments[1] = me->mnt_dir; arguments[2] = "-o"; arguments[3] = "remount"; arguments[4] = NULL; execv("/bin/mount", (char **) arguments); log_error("Failed to execute /bin/mount: %m"); _exit(EXIT_FAILURE); } /* Parent */ s = strdup(me->mnt_dir); if (!s) { log_oom(); ret = EXIT_FAILURE; continue; } k = hashmap_put(pids, UINT_TO_PTR(pid), s); if (k < 0) { log_error("Failed to add PID to set: %s", strerror(-k)); ret = EXIT_FAILURE; continue; } } while (!hashmap_isempty(pids)) { siginfo_t si = {}; char *s; if (waitid(P_ALL, 0, &si, WEXITED) < 0) { if (errno == EINTR) continue; log_error("waitid() failed: %m"); ret = EXIT_FAILURE; break; } s = hashmap_remove(pids, UINT_TO_PTR(si.si_pid)); if (s) { if (!is_clean_exit(si.si_code, si.si_status, NULL)) { if (si.si_code == CLD_EXITED) log_error("/bin/mount for %s exited with exit status %i.", s, si.si_status); else log_error("/bin/mount for %s terminated by signal %s.", s, signal_to_string(si.si_status)); ret = EXIT_FAILURE; } free(s); } } finish: if (pids) hashmap_free_free(pids); return ret; }