Beispiel #1
0
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;
}
Beispiel #2
0
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;
}
Beispiel #3
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;
}
Beispiel #4
0
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;
}
Beispiel #5
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
Beispiel #6
0
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;
}
Beispiel #7
0
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;
}
Beispiel #8
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));
        }
Beispiel #9
0
        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));
        }
Beispiel #10
0
bool mount_point_ignore(const char *path) {
        const char *i;

        NULSTR_FOREACH(i, ignore_paths)
                if (path_equal(path, i))
                        return true;

        return false;
}
Beispiel #11
0
        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));
        }
Beispiel #12
0
/*
 * 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;
}
Beispiel #13
0
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;
}
Beispiel #15
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;
  }
Beispiel #16
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/");
}
Beispiel #17
0
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);
}
Beispiel #18
0
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);
}
Beispiel #19
0
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));
        }
}
Beispiel #20
0
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));
        }
Beispiel #21
0
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));
        }
}
Beispiel #22
0
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));
}
Beispiel #23
0
        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 ++;
        }
Beispiel #24
0
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
Beispiel #25
0
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);
}
Beispiel #26
0
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;
}
Beispiel #27
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;
}
Beispiel #28
0
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;
}
Beispiel #30
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;
}