示例#1
0
static Set *new_matches(void) {
        Set *set;
        char *tmp;
        int r;

        set = set_new(NULL);
        if (!set) {
                log_oom();
                return NULL;
        }

        tmp = strdup("MESSAGE_ID=fc2e22bc6ee647b6b90729ab34a250b1");
        if (!tmp) {
                log_oom();
                set_free(set);
                return NULL;
        }

        r = set_consume(set, tmp);
        if (r < 0) {
                log_error_errno(r, "failed to add to set: %m");
                set_free(set);
                return NULL;
        }

        return set;
}
示例#2
0
static int add_locales_from_libdir (Set *locales) {
        _cleanup_closedir_ DIR *dir = NULL;
        struct dirent *entry;
        int r;

        dir = opendir("/usr/lib/locale");
        if (!dir)
                return errno == ENOENT ? 0 : -errno;

        FOREACH_DIRENT(entry, dir, return -errno) {
                char *z;

                dirent_ensure_type(dir, entry);

                if (entry->d_type != DT_DIR)
                        continue;

                z = strdup(entry->d_name);
                if (!z)
                        return -ENOMEM;

                r = set_consume(locales, z);
                if (r < 0 && r != -EEXIST)
                        return r;
        }

        return 0;
}
示例#3
0
static Set *new_matches(void) {
        Set *set;
        char *tmp;
        int r;

        set = set_new(trivial_hash_func, trivial_compare_func);
        if (!set) {
                log_oom();
                return NULL;
        }

        tmp = strdup("MESSAGE_ID=fc2e22bc6ee647b6b90729ab34a250b1");
        if (!tmp) {
                log_oom();
                set_free(set);
                return NULL;
        }

        r = set_consume(set, tmp);
        if (r < 0) {
                log_error("failed to add to set: %s", strerror(-r));
                set_free(set);
                return NULL;
        }

        return set;
}
示例#4
0
static int nftw_cb(
                const char *fpath,
                const struct stat *sb,
                int tflag,
                struct FTW *ftwbuf) {

        char *p, *e;
        int r;

        if (tflag != FTW_F)
                return 0;

        if (!endswith(fpath, ".map") &&
            !endswith(fpath, ".map.gz"))
                return 0;

        p = strdup(basename(fpath));
        if (!p)
                return FTW_STOP;

        e = endswith(p, ".map");
        if (e)
                *e = 0;

        e = endswith(p, ".map.gz");
        if (e)
                *e = 0;

        r = set_consume(keymaps, p);
        if (r < 0 && r != -EEXIST)
                return r;

        return 0;
}
示例#5
0
static int add_match(Set *set, const char *match) {
        _cleanup_free_ char *p = NULL;
        char *pattern = NULL;
        const char* prefix;
        pid_t pid;
        int r;

        if (strchr(match, '='))
                prefix = "";
        else if (strchr(match, '/')) {
                r = path_make_absolute_cwd(match, &p);
                if (r < 0)
                        goto fail;
                match = p;
                prefix = "COREDUMP_EXE=";
        } else if (parse_pid(match, &pid) >= 0)
                prefix = "COREDUMP_PID=";
        else
                prefix = "COREDUMP_COMM=";

        pattern = strjoin(prefix, match, NULL);
        if (!pattern) {
                r = -ENOMEM;
                goto fail;
        }

        log_debug("Adding pattern: %s", pattern);
        r = set_consume(set, pattern);
        if (r < 0)
                goto fail;

        return 0;
fail:
        return log_error_errno(r, "Failed to add match: %m");
}
示例#6
0
文件: set.c 项目: chenyf/systemd
int set_put_strdup(Set *s, const char *p) {
        char *c;
        int r;

        assert(s);
        assert(p);

        c = strdup(p);
        if (!c)
                return -ENOMEM;

        r = set_consume(s, c);
        if (r == -EEXIST)
                return 0;

        return r;
}
示例#7
0
static int add_locales_from_libdir (Set *locales) {
        _cleanup_closedir_ DIR *dir;
        struct dirent *entry;
        int r;

        dir = opendir("/usr/lib/locale");
        if (!dir) {
                log_error("Failed to open locale directory: %m");
                return -errno;
        }

        errno = 0;
        while ((entry = readdir(dir))) {
                char *z;

                if (entry->d_type != DT_DIR)
                        continue;

                if (ignore_file(entry->d_name))
                        continue;

                z = strdup(entry->d_name);
                if (!z)
                        return log_oom();

                r = set_consume(locales, z);
                if (r < 0 && r != -EEXIST) {
                        log_error("Failed to add locale: %s", strerror(-r));
                        return r;
                }

                errno = 0;
        }

        if (errno > 0) {
                log_error("Failed to read locale directory: %m");
                return -errno;
        }

        return 0;
}
示例#8
0
static int add_match(Set *set, const char *match) {
        int r = -ENOMEM;
        unsigned pid;
        const char* prefix;
        char *pattern = NULL;
        _cleanup_free_ char *p = NULL;

        if (strchr(match, '='))
                prefix = "";
        else if (strchr(match, '/')) {
                p = path_make_absolute_cwd(match);
                if (!p)
                        goto fail;

                match = p;
                prefix = "COREDUMP_EXE=";
        }
        else if (safe_atou(match, &pid) == 0)
                prefix = "COREDUMP_PID=";
        else
                prefix = "COREDUMP_COMM=";

        pattern = strjoin(prefix, match, NULL);
        if (!pattern)
                goto fail;

        log_debug("Adding pattern: %s", pattern);
        r = set_consume(set, pattern);
        if (r < 0) {
                log_error("Failed to add pattern '%s': %s",
                          pattern, strerror(-r));
                goto fail;
        }

        return 0;
fail:
        log_error("Failed to add match: %s", strerror(-r));
        return r;
}
示例#9
0
static int nftw_cb(
                const char *fpath,
                const struct stat *sb,
                int tflag,
                struct FTW *ftwbuf) {

        char *p, *e;
        int r;

        if (tflag != FTW_F)
                return 0;

        if (!endswith(fpath, ".map") &&
            !endswith(fpath, ".map.gz"))
                return 0;

        p = strdup(basename(fpath));
        if (!p)
                return log_oom();

        e = endswith(p, ".map");
        if (e)
                *e = 0;

        e = endswith(p, ".map.gz");
        if (e)
                *e = 0;

        r = set_consume(keymaps, p);
        if (r < 0 && r != -EEXIST) {
                log_error("Can't add keymap: %s", strerror(-r));
                return r;
        }

        return 0;
}
示例#10
0
int mount_cgroup_controllers(char ***join_controllers) {
    int r;
    char buf[LINE_MAX];
    _cleanup_set_free_free_ Set *controllers = NULL;
    _cleanup_fclose_ FILE *f;

    /* Mount all available cgroup controllers that are built into the kernel. */

    f = fopen("/proc/cgroups", "re");
    if (!f) {
        log_error("Failed to enumerate cgroup controllers: %m");
        return 0;
    }

    controllers = set_new(string_hash_func, string_compare_func);
    if (!controllers)
        return log_oom();

    /* Ignore the header line */
    (void) fgets(buf, sizeof(buf), f);

    for (;;) {
        char *controller;
        int enabled = 0;

        if (fscanf(f, "%ms %*i %*i %i", &controller, &enabled) != 2) {

            if (feof(f))
                break;

            log_error("Failed to parse /proc/cgroups.");
            return -EIO;
        }

        if (!enabled) {
            free(controller);
            continue;
        }

        r = set_consume(controllers, controller);
        if (r < 0) {
            log_error("Failed to add controller to set.");
            return r;
        }
    }

    for (;;) {
        MountPoint p = {
            .what = "cgroup",
            .type = "cgroup",
            .flags = MS_NOSUID|MS_NOEXEC|MS_NODEV,
            .mode = MNT_IN_CONTAINER,
        };
        char ***k = NULL;
        _cleanup_free_ char *options = NULL, *controller;

        controller = set_steal_first(controllers);
        if (!controller)
            break;

        if (join_controllers)
            for (k = join_controllers; *k; k++)
                if (strv_find(*k, controller))
                    break;

        if (k && *k) {
            char **i, **j;

            for (i = *k, j = *k; *i; i++) {

                if (!streq(*i, controller)) {
                    char _cleanup_free_ *t;

                    t = set_remove(controllers, *i);
                    if (!t) {
                        free(*i);
                        continue;
                    }
                }

                *(j++) = *i;
            }

            *j = NULL;

            options = strv_join(*k, ",");
            if (!options)
                return log_oom();
        } else {
            options = controller;
            controller = NULL;
        }

        p.where = strappenda("/sys/fs/cgroup/", options);
        p.options = options;

        r = mount_one(&p, true);
        if (r < 0)
            return r;

        if (r > 0 && k && *k) {
            char **i;

            for (i = *k; *i; i++) {
                char *t = strappenda("/sys/fs/cgroup/", *i);

                r = symlink(options, t);
                if (r < 0 && errno != EEXIST) {
                    log_error("Failed to create symlink %s: %m", t);
                    return -errno;
                }
            }
        }
    }

    return 0;
}

static int nftw_cb(
    const char *fpath,
    const struct stat *sb,
    int tflag,
    struct FTW *ftwbuf) {

    /* No need to label /dev twice in a row... */
    if (_unlikely_(ftwbuf->level == 0))
        return FTW_CONTINUE;

    label_fix(fpath, false, false);

    /* /run/initramfs is static data and big, no need to
     * dynamically relabel its contents at boot... */
    if (_unlikely_(ftwbuf->level == 1 &&
                   tflag == FTW_D &&
                   streq(fpath, "/run/initramfs")))
        return FTW_SKIP_SUBTREE;

    return FTW_CONTINUE;
};

int mount_setup(bool loaded_policy) {
    int r;
    unsigned i;

    for (i = 0; i < ELEMENTSOF(mount_table); i ++) {
        r = mount_one(mount_table + i, true);

        if (r < 0)
            return r;
    }

    /* Nodes in devtmpfs and /run need to be manually updated for
     * the appropriate labels, after mounting. The other virtual
     * API file systems like /sys and /proc do not need that, they
     * use the same label for all their files. */
    if (loaded_policy) {
        usec_t before_relabel, after_relabel;
        char timespan[FORMAT_TIMESPAN_MAX];

        before_relabel = now(CLOCK_MONOTONIC);

        nftw("/dev", nftw_cb, 64, FTW_MOUNT|FTW_PHYS|FTW_ACTIONRETVAL);
        nftw("/run", nftw_cb, 64, FTW_MOUNT|FTW_PHYS|FTW_ACTIONRETVAL);

        after_relabel = now(CLOCK_MONOTONIC);

        log_info("Relabelled /dev and /run in %s.",
                 format_timespan(timespan, sizeof(timespan), after_relabel - before_relabel, 0));
    }

    /* Create a few default symlinks, which are normally created
     * by udevd, but some scripts might need them before we start
     * udevd. */
    dev_setup(NULL);

    /* Mark the root directory as shared in regards to mount
     * propagation. The kernel defaults to "private", but we think
     * it makes more sense to have a default of "shared" so that
     * nspawn and the container tools work out of the box. If
     * specific setups need other settings they can reset the
     * propagation mode to private if needed. */
    if (detect_container(NULL) <= 0)
        if (mount(NULL, "/", NULL, MS_REC|MS_SHARED, NULL) < 0)
            log_warning("Failed to set up the root directory for shared mount propagation: %m");

    /* Create a few directories we always want around, Note that
     * sd_booted() checks for /run/systemd/system, so this mkdir
     * really needs to stay for good, otherwise software that
     * copied sd-daemon.c into their sources will misdetect
     * systemd. */
    mkdir_label("/run/systemd", 0755);
    mkdir_label("/run/systemd/system", 0755);
    mkdir_label("/run/systemd/inaccessible", 0000);

    return 0;
}
示例#11
0
static int add_locales_from_archive(Set *locales) {
        /* Stolen from glibc... */

        struct locarhead {
                uint32_t magic;
                /* Serial number.  */
                uint32_t serial;
                /* Name hash table.  */
                uint32_t namehash_offset;
                uint32_t namehash_used;
                uint32_t namehash_size;
                /* String table.  */
                uint32_t string_offset;
                uint32_t string_used;
                uint32_t string_size;
                /* Table with locale records.  */
                uint32_t locrectab_offset;
                uint32_t locrectab_used;
                uint32_t locrectab_size;
                /* MD5 sum hash table.  */
                uint32_t sumhash_offset;
                uint32_t sumhash_used;
                uint32_t sumhash_size;
        };

        struct namehashent {
                /* Hash value of the name.  */
                uint32_t hashval;
                /* Offset of the name in the string table.  */
                uint32_t name_offset;
                /* Offset of the locale record.  */
                uint32_t locrec_offset;
        };

        const struct locarhead *h;
        const struct namehashent *e;
        const void *p = MAP_FAILED;
        _cleanup_close_ int fd = -1;
        size_t sz = 0;
        struct stat st;
        size_t i;
        int r;

        fd = open("/usr/lib/locale/locale-archive", O_RDONLY|O_NOCTTY|O_CLOEXEC);
        if (fd < 0)
                return errno == ENOENT ? 0 : -errno;

        if (fstat(fd, &st) < 0)
                return -errno;

        if (!S_ISREG(st.st_mode))
                return -EBADMSG;

        if (st.st_size < (off_t) sizeof(struct locarhead))
                return -EBADMSG;

        p = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0);
        if (p == MAP_FAILED)
                return -errno;

        h = (const struct locarhead *) p;
        if (h->magic != 0xde020109 ||
            h->namehash_offset + h->namehash_size > st.st_size ||
            h->string_offset + h->string_size > st.st_size ||
            h->locrectab_offset + h->locrectab_size > st.st_size ||
            h->sumhash_offset + h->sumhash_size > st.st_size) {
                r = -EBADMSG;
                goto finish;
        }

        e = (const struct namehashent*) ((const uint8_t*) p + h->namehash_offset);
        for (i = 0; i < h->namehash_size; i++) {
                char *z;

                if (e[i].locrec_offset == 0)
                        continue;

                if (!utf8_is_valid((char*) p + e[i].name_offset))
                        continue;

                z = strdup((char*) p + e[i].name_offset);
                if (!z) {
                        r = -ENOMEM;
                        goto finish;
                }

                r = set_consume(locales, z);
                if (r < 0)
                        goto finish;
        }

        r = 0;

 finish:
        if (p != MAP_FAILED)
                munmap((void*) p, sz);

        return r;
}
示例#12
0
文件: mount-util.c 项目: dm0-/systemd
/* Use this function only if you do not have direct access to /proc/self/mountinfo but the caller can open it
 * for you. This is the case when /proc is masked or not mounted. Otherwise, use bind_remount_recursive. */
int bind_remount_recursive_with_mountinfo(
                const char *prefix,
                unsigned long new_flags,
                unsigned long flags_mask,
                char **blacklist,
                FILE *proc_self_mountinfo) {

        _cleanup_set_free_free_ Set *done = NULL;
        _cleanup_free_ char *cleaned = NULL;
        int r;

        assert(proc_self_mountinfo);

        /* Recursively remount a directory (and all its submounts) read-only or read-write. If the directory is already
         * mounted, we reuse the mount and simply mark it MS_BIND|MS_RDONLY (or remove the MS_RDONLY for read-write
         * operation). If it isn't we first make it one. Afterwards we apply MS_BIND|MS_RDONLY (or remove MS_RDONLY) to
         * all submounts we can access, too. When mounts are stacked on the same mount point we only care for each
         * individual "top-level" mount on each point, as we cannot influence/access the underlying mounts anyway. We
         * do not have any effect on future submounts that might get propagated, they migt be writable. This includes
         * future submounts that have been triggered via autofs.
         *
         * If the "blacklist" parameter is specified it may contain a list of subtrees to exclude from the
         * remount operation. Note that we'll ignore the blacklist for the top-level path. */

        cleaned = strdup(prefix);
        if (!cleaned)
                return -ENOMEM;

        path_simplify(cleaned, false);

        done = set_new(&path_hash_ops);
        if (!done)
                return -ENOMEM;

        for (;;) {
                _cleanup_set_free_free_ Set *todo = NULL;
                bool top_autofs = false;
                char *x;
                unsigned long orig_flags;

                todo = set_new(&path_hash_ops);
                if (!todo)
                        return -ENOMEM;

                rewind(proc_self_mountinfo);

                for (;;) {
                        _cleanup_free_ char *path = NULL, *p = NULL, *type = NULL;
                        int k;

                        k = fscanf(proc_self_mountinfo,
                                   "%*s "       /* (1) mount id */
                                   "%*s "       /* (2) parent id */
                                   "%*s "       /* (3) major:minor */
                                   "%*s "       /* (4) root */
                                   "%ms "       /* (5) mount point */
                                   "%*s"        /* (6) mount options (superblock) */
                                   "%*[^-]"     /* (7) optional fields */
                                   "- "         /* (8) separator */
                                   "%ms "       /* (9) file system type */
                                   "%*s"        /* (10) mount source */
                                   "%*s"        /* (11) mount options (bind mount) */
                                   "%*[^\n]",   /* some rubbish at the end */
                                   &path,
                                   &type);
                        if (k != 2) {
                                if (k == EOF)
                                        break;

                                continue;
                        }

                        r = cunescape(path, UNESCAPE_RELAX, &p);
                        if (r < 0)
                                return r;

                        if (!path_startswith(p, cleaned))
                                continue;

                        /* Ignore this mount if it is blacklisted, but only if it isn't the top-level mount we shall
                         * operate on. */
                        if (!path_equal(cleaned, p)) {
                                bool blacklisted = false;
                                char **i;

                                STRV_FOREACH(i, blacklist) {

                                        if (path_equal(*i, cleaned))
                                                continue;

                                        if (!path_startswith(*i, cleaned))
                                                continue;

                                        if (path_startswith(p, *i)) {
                                                blacklisted = true;
                                                log_debug("Not remounting %s blacklisted by %s, called for %s", p, *i, cleaned);
                                                break;
                                        }
                                }
                                if (blacklisted)
                                        continue;
                        }

                        /* Let's ignore autofs mounts.  If they aren't
                         * triggered yet, we want to avoid triggering
                         * them, as we don't make any guarantees for
                         * future submounts anyway.  If they are
                         * already triggered, then we will find
                         * another entry for this. */
                        if (streq(type, "autofs")) {
                                top_autofs = top_autofs || path_equal(cleaned, p);
                                continue;
                        }

                        if (!set_contains(done, p)) {
                                r = set_consume(todo, p);
                                p = NULL;
                                if (r == -EEXIST)
                                        continue;
                                if (r < 0)
                                        return r;
                        }
                }

                /* If we have no submounts to process anymore and if
                 * the root is either already done, or an autofs, we
                 * are done */
                if (set_isempty(todo) &&
                    (top_autofs || set_contains(done, cleaned)))
                        return 0;

                if (!set_contains(done, cleaned) &&
                    !set_contains(todo, cleaned)) {
                        /* The prefix directory itself is not yet a mount, make it one. */
                        if (mount(cleaned, cleaned, NULL, MS_BIND|MS_REC, NULL) < 0)
                                return -errno;

                        orig_flags = 0;
                        (void) get_mount_flags(cleaned, &orig_flags);
                        orig_flags &= ~MS_RDONLY;

                        if (mount(NULL, cleaned, NULL, (orig_flags & ~flags_mask)|MS_BIND|MS_REMOUNT|new_flags, NULL) < 0)
                                return -errno;

                        log_debug("Made top-level directory %s a mount point.", prefix);

                        r = set_put_strdup(done, cleaned);
                        if (r < 0)
                                return r;
                }

                while ((x = set_steal_first(todo))) {

                        r = set_consume(done, x);
                        if (IN_SET(r, 0, -EEXIST))
                                continue;
                        if (r < 0)
                                return r;

                        /* Deal with mount points that are obstructed by a later mount */
                        r = path_is_mount_point(x, NULL, 0);
                        if (IN_SET(r, 0, -ENOENT))
                                continue;
                        if (IN_SET(r, -EACCES, -EPERM)) {
                                /* Even if root user invoke this, submounts under private FUSE or NFS mount points
                                 * may not be acceessed. E.g.,
                                 *
                                 * $ bindfs --no-allow-other ~/mnt/mnt ~/mnt/mnt
                                 * $ bindfs --no-allow-other ~/mnt ~/mnt
                                 *
                                 * Then, root user cannot access the mount point ~/mnt/mnt.
                                 * In such cases, the submounts are ignored, as we have no way to manage them. */
                                log_debug_errno(r, "Failed to determine '%s' is mount point or not, ignoring: %m", x);
                                continue;
                        }
                        if (r < 0)
                                return r;

                        /* Try to reuse the original flag set */
                        orig_flags = 0;
                        (void) get_mount_flags(x, &orig_flags);
                        orig_flags &= ~MS_RDONLY;

                        if (mount(NULL, x, NULL, (orig_flags & ~flags_mask)|MS_BIND|MS_REMOUNT|new_flags, NULL) < 0)
                                return -errno;

                        log_debug("Remounted %s read-only.", x);
                }
        }
int devnode_acl_all(struct udev *udev,
                    const char *seat,
                    bool flush,
                    bool del, uid_t old_uid,
                    bool add, uid_t new_uid) {

    _cleanup_udev_enumerate_unref_ struct udev_enumerate *e = NULL;
    struct udev_list_entry *item = NULL, *first = NULL;
    _cleanup_set_free_free_ Set *nodes = NULL;
    _cleanup_closedir_ DIR *dir = NULL;
    struct dirent *dent;
    Iterator i;
    char *n;
    int r;

    assert(udev);

    nodes = set_new(&string_hash_ops);
    if (!nodes)
        return -ENOMEM;

    e = udev_enumerate_new(udev);
    if (!e)
        return -ENOMEM;

    if (isempty(seat))
        seat = "seat0";

    /* We can only match by one tag in libudev. We choose
     * "uaccess" for that. If we could match for two tags here we
     * could add the seat name as second match tag, but this would
     * be hardly optimizable in libudev, and hence checking the
     * second tag manually in our loop is a good solution. */
    r = udev_enumerate_add_match_tag(e, "uaccess");
    if (r < 0)
        return r;

    r = udev_enumerate_add_match_is_initialized(e);
    if (r < 0)
        return r;

    r = udev_enumerate_scan_devices(e);
    if (r < 0)
        return r;

    first = udev_enumerate_get_list_entry(e);
    udev_list_entry_foreach(item, first) {
        _cleanup_udev_device_unref_ struct udev_device *d = NULL;
        const char *node, *sn;

        d = udev_device_new_from_syspath(udev, udev_list_entry_get_name(item));
        if (!d)
            return -ENOMEM;

        sn = udev_device_get_property_value(d, "ID_SEAT");
        if (isempty(sn))
            sn = "seat0";

        if (!streq(seat, sn))
            continue;

        node = udev_device_get_devnode(d);
        /* In case people mistag devices with nodes, we need to ignore this */
        if (!node)
            continue;

        n = strdup(node);
        if (!n)
            return -ENOMEM;

        log_debug("Found udev node %s for seat %s", n, seat);
        r = set_consume(nodes, n);
        if (r < 0)
            return r;
    }
示例#14
0
static void test_struct(void) {
        Prioq *q;
        Set *s;
        unsigned previous = 0, i;
        int r;

        srand(0);

        q = prioq_new(test_compare);
        assert_se(q);

        s = set_new(test_hash, test_compare);
        assert_se(s);

        for (i = 0; i < SET_SIZE; i++) {
                struct test *t;

                t = new0(struct test, 1);
                assert_se(t);
                t->value = (unsigned) rand();

                r = prioq_put(q, t, &t->idx);
                assert_se(r >= 0);

                if (i % 4 == 0) {
                        r = set_consume(s, t);
                        assert_se(r >= 0);
                }
        }

        for (;;) {
                struct test *t;

                t = set_steal_first(s);
                if (!t)
                        break;

                r = prioq_remove(q, t, &t->idx);
                assert_se(r > 0);

                free(t);
        }

        for (i = 0; i < SET_SIZE * 3 / 4; i++) {
                struct test *t;

                assert_se(prioq_size(q) == (SET_SIZE * 3 / 4) - i);

                t = prioq_pop(q);
                assert_se(t);

                assert_se(previous <= t->value);
                previous = t->value;
                free(t);
        }

        assert_se(prioq_isempty(q));
        prioq_free(q);

        assert_se(set_isempty(s));
        set_free(s);
}