예제 #1
0
        STRV_FOREACH_PAIR(link, p, links) {
                char *f = strappenda(original_dir, *p);
                char *l = strappenda(original_dir, *link);

                assert_se(mkdir_parents(l, 0755) >= 0);
                assert_se(symlink(f, l) == 0);
        }
예제 #2
0
static int link_compatibility(const char *units) {
        const char *f, *t;

        f = strappenda(units, "/systemd-bus-proxyd.socket");
        t = strappenda(arg_dest, "/" SPECIAL_DBUS_SOCKET);
        mkdir_parents_label(t, 0755);
        if (symlink(f, t) < 0) {
                log_error("Failed to create symlink %s: %m", t);
                return -errno;
        }

        f = strappenda(units, "/systemd-bus-proxyd.socket");
        t = strappenda(arg_dest, "/" SPECIAL_SOCKETS_TARGET ".wants/systemd-bus-proxyd.socket");
        mkdir_parents_label(t, 0755);
        if (symlink(f, t) < 0) {
                log_error("Failed to create symlink %s: %m", t);
                return -errno;
        }

        t = strappenda(arg_dest, "/" SPECIAL_DBUS_SERVICE);
        if (symlink("/dev/null", t) < 0) {
                log_error("Failed to mask %s: %m", t);
                return -errno;
        }

        return 0;
}
예제 #3
0
static void test_conf_files_list(bool use_root) {
        char tmp_dir[] = "/tmp/test-conf-files-XXXXXX";
        _cleanup_strv_free_ char **found_files = NULL;
        const char *root_dir, *search_1, *search_2, *expect_a, *expect_b;

        setup_test_dir(tmp_dir,
                       "/dir1/a.conf",
                       "/dir2/a.conf",
                       "/dir2/b.conf",
                       NULL);

        if (use_root) {
                root_dir = tmp_dir;
                search_1 = "/dir1";
                search_2 = "/dir2";
        } else {
                root_dir = NULL;
                search_1 = strappenda(tmp_dir, "/dir1");
                search_2 = strappenda(tmp_dir, "/dir2");
        }

        expect_a = strappenda(tmp_dir, "/dir1/a.conf");
        expect_b = strappenda(tmp_dir, "/dir2/b.conf");

        assert_se(conf_files_list(&found_files, ".conf", root_dir, search_1, search_2, NULL) == 0);
        strv_print(found_files);

        assert_se(found_files);
        assert_se(streq_ptr(found_files[0], expect_a));
        assert_se(streq_ptr(found_files[1], expect_b));
        assert_se(found_files[2] == NULL);

        assert_se(rm_rf_dangerous(tmp_dir, false, true, false) == 0);
}
예제 #4
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));
        }
예제 #5
0
static int prompt_root_password(void) {
        const char *msg1, *msg2, *etc_shadow;
        int r;

        if (arg_root_password)
                return 0;

        if (!arg_prompt_root_password)
                return 0;

        etc_shadow = prefix_roota("/etc/shadow");
        if (faccessat(AT_FDCWD, etc_shadow, F_OK, AT_SYMLINK_NOFOLLOW) >= 0)
                return 0;

        print_welcome();
        putchar('\n');

        msg1 = strappenda(draw_special_char(DRAW_TRIANGULAR_BULLET), " Please enter a new root password (empty to skip): ");
        msg2 = strappenda(draw_special_char(DRAW_TRIANGULAR_BULLET), " Please enter new root password again: ");

        for (;;) {
                _cleanup_free_ char *a = NULL, *b = NULL;

                r = ask_password_tty(msg1, 0, false, NULL, &a);
                if (r < 0) {
                        log_error("Failed to query root password: %s", strerror(-r));
                        return r;
                }

                if (isempty(a)) {
                        log_warning("No password entered, skipping.");
                        break;
                }

                r = ask_password_tty(msg2, 0, false, NULL, &b);
                if (r < 0) {
                        log_error("Failed to query root password: %s", strerror(-r));
                        clear_string(a);
                        return r;
                }

                if (!streq(a, b)) {
                        log_error("Entered passwords did not match, please try again.");
                        clear_string(a);
                        clear_string(b);
                        continue;
                }

                clear_string(b);
                arg_root_password = a;
                a = NULL;
                break;
        }

        return 0;
}
예제 #6
0
static int link_busnames_target(const char *units) {
        const char *f, *t;

        f = strappenda(units, "/" SPECIAL_BUSNAMES_TARGET);
        t = strappenda(arg_dest, "/" SPECIAL_BASIC_TARGET ".wants/" SPECIAL_BUSNAMES_TARGET);

        mkdir_parents_label(t, 0755);
        if (symlink(f, t) < 0) {
                log_error("Failed to create symlink %s: %m", t);
                return -errno;
        }

        return 0;
}
static int generate_display_manager_alias(void) {

        _cleanup_free_ char *default_dm_path = NULL, *enabled_dm_unit = NULL;
        const char *default_dm = NULL, *in_mem_symlink = NULL, *target_unit_path = NULL;
        bool dm_service_exists = true;
        int r;

        r = read_full_file(default_dm_file, &default_dm_path, NULL);
        if (r < 0) {
                log_debug("No %s file, nothing to generate", default_dm_file);
                return 0;
        }
        default_dm = strstrip(basename(default_dm_path));

        r = readlink_value(dm_service_unit, &enabled_dm_unit);
        if (r < 0) {
                enabled_dm_unit = strdup("");
                dm_service_exists = false;
        }

        /* all is fine if the info matches */
        if (streq(strappenda(default_dm, ".service"), enabled_dm_unit))
                return 0;

        target_unit_path = strappenda(SYSTEM_DATA_UNIT_PATH, "/", default_dm, ".service");

        /* we only create the alias symlink for non sysvinit services */
        if (access(target_unit_path, F_OK) < 0 && (errno == ENOENT)) {
                /* if the dm service was already disabled, nothing to be done */
                if (!dm_service_exists) {
                        log_debug("No %s file, nothing to mask", dm_service_unit);
                        return 0;
                }
                log_warning("%s is not a systemd unit, we disable the systemd enabled display manager", target_unit_path);
                target_unit_path = "/dev/null";
        } else {
                log_warning("%s points at %s while the default systemd unit is %s. Reconfiguring %s as default.",
                            default_dm_file, default_dm, enabled_dm_unit, default_dm);
        }

        in_mem_symlink = strappenda(dest, "/display-manager.service");
        mkdir_parents_label(in_mem_symlink, 0755);
        if (symlink(target_unit_path, in_mem_symlink) < 0) {
                log_error("Failed to create symlink %s: %m", in_mem_symlink);
                return -errno;
        }

        return 0;
}
예제 #8
0
static int process_locale(void) {
        const char *etc_localeconf;
        char* locales[3];
        unsigned i = 0;
        int r;

        etc_localeconf = prefix_roota("/etc/locale.conf");
        if (faccessat(AT_FDCWD, etc_localeconf, F_OK, AT_SYMLINK_NOFOLLOW) >= 0)
                return 0;

        if (arg_copy_locale && arg_root) {

                mkdir_parents(etc_localeconf, 0755);
                r = copy_file("/etc/locale.conf", etc_localeconf, 0, 0644);
                if (r != -ENOENT) {
                        if (r < 0) {
                                log_error("Failed to copy %s: %s", etc_localeconf, strerror(-r));
                                return r;
                        }

                        log_info("%s copied.", etc_localeconf);
                        return 0;
                }
        }

        r = prompt_locale();
        if (r < 0)
                return r;

        if (!isempty(arg_locale))
                locales[i++] = strappenda("LANG=", arg_locale);
        if (!isempty(arg_locale_messages) && !streq(arg_locale_messages, arg_locale))
                locales[i++] = strappenda("LC_MESSAGES=", arg_locale_messages);

        if (i == 0)
                return 0;

        locales[i] = NULL;

        mkdir_parents(etc_localeconf, 0755);
        r = write_env_file(etc_localeconf, locales);
        if (r < 0) {
                log_error("Failed to write %s: %s", etc_localeconf, strerror(-r));
                return r;
        }

        log_info("%s written.", etc_localeconf);
        return 0;
}
예제 #9
0
파일: condition.c 프로젝트: klausi/systemd
static bool condition_test_needs_update(Condition *c) {
        const char *p;
        struct stat usr, other;

        assert(c);
        assert(c->parameter);
        assert(c->type == CONDITION_NEEDS_UPDATE);

        /* If the file system is read-only we shouldn't suggest an update */
        if (path_is_read_only_fs(c->parameter) > 0)
                return c->negate;

        /* Any other failure means we should allow the condition to be true,
         * so that we rather invoke too many update tools then too
         * few. */

        if (!path_is_absolute(c->parameter))
                return !c->negate;

        p = strappenda(c->parameter, "/.updated");
        if (lstat(p, &other) < 0)
                return !c->negate;

        if (lstat("/usr/", &usr) < 0)
                return !c->negate;

        return (usr.st_mtim.tv_sec > other.st_mtim.tv_sec ||
                (usr.st_mtim.tv_sec == other.st_mtim.tv_sec && usr.st_mtim.tv_nsec > other.st_mtim.tv_nsec)) == !c->negate;
}
예제 #10
0
static int add_fsck(FILE *f, const char *what, const char *where, const char *type, int passno) {
        assert(f);

        if (passno == 0)
                return 0;

        if (type && !streq(type, "auto")) {
                int r;
                const char *checker;

                checker = strappenda("/sbin/fsck.", type);
                r = access(checker, X_OK);
                if (r < 0) {
                        log_warning("Checking was requested for %s, but %s cannot be used: %m", what, checker);

                        /* treat missing check as essentially OK */
                        return errno == ENOENT ? 0 : -errno;
                }
        }

        if (streq(where, "/")) {
                char *lnk;

                lnk = strappenda(arg_dest, "/" SPECIAL_LOCAL_FS_TARGET ".wants/systemd-fsck-root.service");
                mkdir_parents_label(lnk, 0755);
                if (symlink("systemd-fsck-root.service", lnk) < 0) {
                        log_error("Failed to create symlink %s: %m", lnk);
                        return -errno;
                }
        } else {
                _cleanup_free_ char *fsck = NULL;

                fsck = unit_name_from_path_instance("systemd-fsck", what, ".service");
                if (!fsck)
                        return log_oom();

                fprintf(f,
                        "RequiresOverridable=%s\n"
                        "After=%s\n",
                        fsck,
                        fsck);
        }

        return 0;
}
예제 #11
0
void microhttpd_logger(void *arg, const char *fmt, va_list ap) {
        char *f;

        f = strappenda("microhttpd: ", fmt);

        DISABLE_WARNING_FORMAT_NONLITERAL;
        log_internalv(LOG_INFO, 0, NULL, 0, NULL, f, ap);
        REENABLE_WARNING;
}
예제 #12
0
        STRV_FOREACH(p, files) {
                _cleanup_free_ char *buf = NULL;
                size_t sz = 0;
                char *f = strappenda(copy_dir, *p);

                assert_se(access(f, F_OK) == 0);
                assert_se(read_full_file(f, &buf, &sz) == 0);
                assert_se(streq(buf, "file\n"));
        }
예제 #13
0
static void test_tmpdir(const char *id, const char *A, const char *B) {
        _cleanup_free_ char *a, *b;
        struct stat x, y;
        char *c, *d;

        assert_se(setup_tmp_dirs(id, &a, &b) == 0);
        assert_se(startswith(a, A));
        assert_se(startswith(b, B));

        assert_se(stat(a, &x) >= 0);
        assert_se(stat(b, &y) >= 0);

        assert_se(S_ISDIR(x.st_mode));
        assert_se(S_ISDIR(y.st_mode));

        assert_se((x.st_mode & 01777) == 0700);
        assert_se((y.st_mode & 01777) == 0700);

        c = strappenda(a, "/tmp");
        d = strappenda(b, "/tmp");

        assert_se(stat(c, &x) >= 0);
        assert_se(stat(d, &y) >= 0);

        assert_se(S_ISDIR(x.st_mode));
        assert_se(S_ISDIR(y.st_mode));

        assert_se((x.st_mode & 01777) == 01777);
        assert_se((y.st_mode & 01777) == 01777);

        assert_se(rmdir(c) >= 0);
        assert_se(rmdir(d) >= 0);

        assert_se(rmdir(a) >= 0);
        assert_se(rmdir(b) >= 0);
}
예제 #14
0
static int process_timezone(void) {
        const char *etc_localtime, *e;
        int r;

        etc_localtime = prefix_roota("/etc/localtime");
        if (faccessat(AT_FDCWD, etc_localtime, F_OK, AT_SYMLINK_NOFOLLOW) >= 0)
                return 0;

        if (arg_copy_timezone && arg_root) {
                _cleanup_free_ char *p = NULL;

                r = readlink_malloc("/etc/localtime", &p);
                if (r != -ENOENT) {
                        if (r < 0) {
                                log_error("Failed to read host timezone: %s", strerror(-r));
                                return r;
                        }

                        mkdir_parents(etc_localtime, 0755);
                        if (symlink(p, etc_localtime) < 0) {
                                log_error("Failed to create %s symlink: %m", etc_localtime);
                                return -errno;
                        }

                        log_info("%s copied.", etc_localtime);
                        return 0;
                }
        }

        r = prompt_timezone();
        if (r < 0)
                return r;

        if (isempty(arg_timezone))
                return 0;

        e = strappenda("../usr/share/zoneinfo/", arg_timezone);

        mkdir_parents(etc_localtime, 0755);
        if (symlink(e, etc_localtime) < 0) {
                log_error("Failed to create %s symlink: %m", etc_localtime);
                return -errno;
        }

        log_info("%s written", etc_localtime);
        return 0;
}
예제 #15
0
static int generate_symlink(void) {
        const char *p = NULL;

        if (access("/system-update", F_OK) < 0) {
                if (errno == ENOENT)
                        return 0;

                log_error_errno(errno, "Failed to check for system update: %m");
                return -EINVAL;
        }

        p = strappenda(arg_dest, "/default.target");
        if (symlink(SYSTEM_DATA_UNIT_PATH "/system-update.target", p) < 0)
                return log_error_errno(errno, "Failed to create symlink %s: %m", p);

        return 0;
}
예제 #16
0
static void test_copy_tree(void) {
        char original_dir[] = "/tmp/test-copy_tree/";
        char copy_dir[] = "/tmp/test-copy_tree-copy/";
        char **files = STRV_MAKE("file", "dir1/file", "dir1/dir2/file", "dir1/dir2/dir3/dir4/dir5/file");
        char **links = STRV_MAKE("link", "file",
                                 "link2", "dir1/file");
        char **p, **link;

        rm_rf_dangerous(copy_dir, false, true, false);
        rm_rf_dangerous(original_dir, false, true, false);

        STRV_FOREACH(p, files) {
                char *f = strappenda(original_dir, *p);

                assert_se(mkdir_parents(f, 0755) >= 0);
                assert_se(write_string_file(f, "file") == 0);
        }
예제 #17
0
/* read the 256 bytes PCI configuration space to check the multi-function bit */
static bool is_pci_multifunction(struct udev_device *dev) {
        _cleanup_fclose_ FILE *f = NULL;
        const char *filename;
        uint8_t config[64];

        filename = strappenda(udev_device_get_syspath(dev), "/config");
        f = fopen(filename, "re");
        if (!f)
                return false;
        if (fread(&config, sizeof(config), 1, f) != 1)
                return false;

        /* bit 0-6 header type, bit 7 multi/single function device */
        if ((config[PCI_HEADER_TYPE] & 0x80) != 0)
                return true;

        return false;
}
예제 #18
0
static int setup_test(Manager **m) {
        char **tests_path = STRV_MAKE("exists", "existsglobFOOBAR", "changed", "modified", "unit",
                                      "directorynotempty", "makedirectory");
        char **test_path;
        Manager *tmp;
        int r;

        assert_se(m);

        r = manager_new(SYSTEMD_USER, true, &tmp);
        if (IN_SET(r, -EPERM, -EACCES, -EADDRINUSE, -EHOSTDOWN, -ENOENT)) {
                printf("Skipping test: manager_new: %s", strerror(-r));
                return -EXIT_TEST_SKIP;
        }
        assert_se(r >= 0);
        assert_se(manager_startup(tmp, NULL, NULL) >= 0);

        STRV_FOREACH(test_path, tests_path) {
               rm_rf_dangerous(strappenda("/tmp/test-path_", *test_path), false, true, false);
        }
예제 #19
0
int main(int argc, char** argv) {
        const char *p = argv[1] ?: "/tmp";
        char *pattern = strappenda(p, "/systemd-test-XXXXXX");
        _cleanup_close_ int fd, fd2;
        _cleanup_free_ char *cmd, *cmd2;

        fd = open_tmpfile(p, O_RDWR|O_CLOEXEC);
        assert_se(fd >= 0);

        assert_se(asprintf(&cmd, "ls -l /proc/"PID_FMT"/fd/%d", getpid(), fd) > 0);
        system(cmd);

        fd2 = mkostemp_safe(pattern, O_RDWR|O_CLOEXEC);
        assert_se(fd >= 0);
        assert_se(unlink(pattern) == 0);

        assert_se(asprintf(&cmd2, "ls -l /proc/"PID_FMT"/fd/%d", getpid(), fd2) > 0);
        system(cmd2);

        return 0;
}
예제 #20
0
파일: busname.c 프로젝트: g33s3/systemmd
static int busname_verify(BusName *n) {
        char *e;

        assert(n);

        if (UNIT(n)->load_state != UNIT_LOADED)
                return 0;

        if (!service_name_is_valid(n->name)) {
                log_error_unit(UNIT(n)->id, "%s's Name= setting is not a valid service name Refusing.", UNIT(n)->id);
                return -EINVAL;
        }

        e = strappenda(n->name, ".busname");
        if (!unit_has_name(UNIT(n), e)) {
                log_error_unit(UNIT(n)->id, "%s's Name= setting doesn't match unit name. Refusing.", UNIT(n)->id);
                return -EINVAL;
        }

        return 0;
}
예제 #21
0
int button_open(Button *b) {
        char *p, name[256];
        int r;

        assert(b);

        if (b->fd >= 0) {
                close(b->fd);
                b->fd = -1;
        }

        p = strappenda("/dev/input/", b->name);

        b->fd = open(p, O_RDWR|O_CLOEXEC|O_NOCTTY|O_NONBLOCK);
        if (b->fd < 0) {
                log_warning("Failed to open %s: %m", b->name);
                return -errno;
        }

        if (ioctl(b->fd, EVIOCGNAME(sizeof(name)), name) < 0) {
                log_error("Failed to get input name: %m");
                r = -errno;
                goto fail;
        }

        r = sd_event_add_io(b->manager->event, &b->io_event_source, b->fd, EPOLLIN, button_dispatch, b);
        if (r < 0) {
                log_error("Failed to add button event: %s", strerror(-r));
                goto fail;
        }

        log_info("Watching system buttons on /dev/input/%s (%s)", b->name, name);

        return 0;

fail:
        close(b->fd);
        b->fd = -1;
        return r;
}
예제 #22
0
static int add_root_mount(void) {
        _cleanup_free_ char *what = NULL;
        const char *opts;

        if (isempty(arg_root_what)) {
                log_debug("Could not find a root= entry on the kernel commandline.");
                return 0;
        }

        what = fstab_node_to_udev_node(arg_root_what);
        if (!path_is_absolute(what)) {
                log_debug("Skipping entry what=%s where=/sysroot type=%s", what, strna(arg_root_fstype));
                return 0;
        }

        if (!arg_root_options)
                opts = arg_root_rw > 0 ? "rw" : "ro";
        else if (arg_root_rw >= 0 ||
                 (!mount_test_option(arg_root_options, "ro") &&
                  !mount_test_option(arg_root_options, "rw")))
                opts = strappenda(arg_root_options, ",", arg_root_rw > 0 ? "rw" : "ro");
        else
                opts = arg_root_options;

        log_debug("Found entry what=%s where=/sysroot type=%s", what, strna(arg_root_fstype));
        return add_mount(what,
                         "/sysroot",
                         arg_root_fstype,
                         opts,
                         1,
                         false,
                         false,
                         false,
                         SPECIAL_INITRD_ROOT_FS_TARGET,
                         "/proc/cmdline");
}
예제 #23
0
static int reply_query_state(DnsQuery *q) {
        _cleanup_free_ char *ip = NULL;
        const char *name;
        int r;

        if (q->request_hostname)
                name = q->request_hostname;
        else {
                r = in_addr_to_string(q->request_family, &q->request_address, &ip);
                if (r < 0)
                        return r;

                name = ip;
        }

        switch (q->state) {

        case DNS_TRANSACTION_NO_SERVERS:
                return sd_bus_reply_method_errorf(q->request, BUS_ERROR_NO_NAME_SERVERS, "No appropriate name servers or networks for name found");

        case DNS_TRANSACTION_TIMEOUT:
                return sd_bus_reply_method_errorf(q->request, SD_BUS_ERROR_TIMEOUT, "Query timed out");

        case DNS_TRANSACTION_ATTEMPTS_MAX_REACHED:
                return sd_bus_reply_method_errorf(q->request, SD_BUS_ERROR_TIMEOUT, "All attempts to contact name servers or networks failed");

        case DNS_TRANSACTION_INVALID_REPLY:
                return sd_bus_reply_method_errorf(q->request, BUS_ERROR_INVALID_REPLY, "Received invalid reply");

        case DNS_TRANSACTION_RESOURCES:
                return sd_bus_reply_method_errorf(q->request, BUS_ERROR_NO_RESOURCES, "Not enough resources");

        case DNS_TRANSACTION_ABORTED:
                return sd_bus_reply_method_errorf(q->request, BUS_ERROR_ABORTED, "Query aborted");

        case DNS_TRANSACTION_FAILURE: {
                _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;

                if (q->answer_rcode == DNS_RCODE_NXDOMAIN)
                        sd_bus_error_setf(&error, _BUS_ERROR_DNS "NXDOMAIN", "'%s' not found", name);
                else {
                        const char *rc, *n;
                        char p[3]; /* the rcode is 4 bits long */

                        rc = dns_rcode_to_string(q->answer_rcode);
                        if (!rc) {
                                sprintf(p, "%i", q->answer_rcode);
                                rc = p;
                        }

                        n = strappenda(_BUS_ERROR_DNS, rc);
                        sd_bus_error_setf(&error, n, "Could not resolve '%s', server or network returned error %s", name, rc);
                }

                return sd_bus_reply_method_error(q->request, &error);
        }

        case DNS_TRANSACTION_NULL:
        case DNS_TRANSACTION_PENDING:
        case DNS_TRANSACTION_SUCCESS:
        default:
                assert_not_reached("Impossible state");
        }
}
예제 #24
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;
}
예제 #25
0
int switch_root(const char *new_root) {

        /*  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;

        /* When using pivot_root() we assume that /mnt exists as place
         * we can temporarily move the old root to. As we immediately
         * unmount it from there it doesn't matter much which
         * directory we choose for this, but it should be more likely
         * than not that /mnt exists and is suitable as mount point
         * and is on the same fs as the old root dir */
        temporary_old_root = strappenda(new_root, "/mnt");

        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 a kernel bug: for some reason 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);

                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, MS_MOVE, NULL) < 0) {
                        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);
                }
        }
예제 #26
0
static int create_disk(
    const char *name,
    const char *device,
    const char *password,
    const char *options) {

    _cleanup_free_ char *p = NULL, *n = NULL, *d = NULL, *u = NULL, *to = NULL, *e = NULL;
    _cleanup_fclose_ FILE *f = NULL;
    bool noauto, nofail, tmp, swap;
    char *from;
    int r;

    assert(name);
    assert(device);

    noauto = has_option(options, "noauto");
    nofail = has_option(options, "nofail");
    tmp = has_option(options, "tmp");
    swap = has_option(options, "swap");

    if (tmp && swap) {
        log_error("Device '%s' cannot be both 'tmp' and 'swap'. Ignoring.", name);
        return -EINVAL;
    }

    e = unit_name_escape(name);
    if (!e)
        return log_oom();

    n = unit_name_build("systemd-cryptsetup", e, ".service");
    if (!n)
        return log_oom();

    p = strjoin(arg_dest, "/", n, NULL);
    if (!p)
        return log_oom();

    u = fstab_node_to_udev_node(device);
    if (!u)
        return log_oom();

    d = unit_name_from_path(u, ".device");
    if (!d)
        return log_oom();

    f = fopen(p, "wxe");
    if (!f) {
        log_error("Failed to create unit file %s: %m", p);
        return -errno;
    }

    fputs(
        "# Automatically generated by systemd-cryptsetup-generator\n\n"
        "[Unit]\n"
        "Description=Cryptography Setup for %I\n"
        "Documentation=man:crypttab(5) man:systemd-cryptsetup-generator(8) man:[email protected](8)\n"
        "SourcePath=/etc/crypttab\n"
        "DefaultDependencies=no\n"
        "Conflicts=umount.target\n"
        "BindsTo=dev-mapper-%i.device\n"
        "IgnoreOnIsolate=true\n"
        "After=systemd-readahead-collect.service systemd-readahead-replay.service\n",
        f);

    if (!nofail)
        fprintf(f,
                "Before=cryptsetup.target\n");

    if (password) {
        if (STR_IN_SET(password, "/dev/urandom", "/dev/random", "/dev/hw_random"))
            fputs("After=systemd-random-seed.service\n", f);
        else if (!streq(password, "-") && !streq(password, "none")) {
            _cleanup_free_ char *uu;

            uu = fstab_node_to_udev_node(password);
            if (!uu)
                return log_oom();

            if (is_device_path(uu)) {
                _cleanup_free_ char *dd;

                dd = unit_name_from_path(uu, ".device");
                if (!dd)
                    return log_oom();

                fprintf(f, "After=%1$s\nRequires=%1$s\n", dd);
            } else
                fprintf(f, "RequiresMountsFor=%s\n", password);
        }
    }

    if (is_device_path(u))
        fprintf(f,
                "BindsTo=%s\n"
                "After=%s\n"
                "Before=umount.target\n",
                d, d);
    else
        fprintf(f,
                "RequiresMountsFor=%s\n",
                u);

    fprintf(f,
            "\n[Service]\n"
            "Type=oneshot\n"
            "RemainAfterExit=yes\n"
            "TimeoutSec=0\n" /* the binary handles timeouts anyway */
            "ExecStart=" SYSTEMD_CRYPTSETUP_PATH " attach '%s' '%s' '%s' '%s'\n"
            "ExecStop=" SYSTEMD_CRYPTSETUP_PATH " detach '%s'\n",
            name, u, strempty(password), strempty(options),
            name);

    if (tmp)
        fprintf(f,
                "ExecStartPost=/sbin/mke2fs '/dev/mapper/%s'\n",
                name);

    if (swap)
        fprintf(f,
                "ExecStartPost=/sbin/mkswap '/dev/mapper/%s'\n",
                name);

    fflush(f);
    if (ferror(f)) {
        log_error("Failed to write file %s: %m", p);
        return -errno;
    }

    from = strappenda("../", n);

    if (!noauto) {

        to = strjoin(arg_dest, "/", d, ".wants/", n, NULL);
        if (!to)
            return log_oom();

        mkdir_parents_label(to, 0755);
        if (symlink(from, to) < 0) {
            log_error("Failed to create symlink %s: %m", to);
            return -errno;
        }

        free(to);
        if (!nofail)
            to = strjoin(arg_dest, "/cryptsetup.target.requires/", n, NULL);
        else
            to = strjoin(arg_dest, "/cryptsetup.target.wants/", n, NULL);
        if (!to)
            return log_oom();

        mkdir_parents_label(to, 0755);
        if (symlink(from, to) < 0) {
            log_error("Failed to create symlink %s: %m", to);
            return -errno;
        }
    }

    free(to);
    to = strjoin(arg_dest, "/dev-mapper-", e, ".device.requires/", n, NULL);
    if (!to)
        return log_oom();

    mkdir_parents_label(to, 0755);
    if (symlink(from, to) < 0) {
        log_error("Failed to create symlink %s: %m", to);
        return -errno;
    }

    if (!noauto && !nofail) {

        free(p);
        p = strjoin(arg_dest, "/dev-mapper-", e, ".device.d/50-job-timeout-sec-0.conf", NULL);
        if (!p)
            return log_oom();

        mkdir_parents_label(p, 0755);
        r = write_string_file(p,
                              "# Automatically generated by systemd-cryptsetup-generator\n\n"
                              "[Unit]\n"
                              "JobTimeoutSec=0\n"); /* the binary handles timeouts anyway */
        if (r < 0) {
            log_error("Failed to write device drop-in: %s", strerror(-r));
            return r;
        }
    }

    return 0;
}
예제 #27
0
파일: import.c 프로젝트: pwaller/systemd
static int pull_dck(int argc, char *argv[], void *userdata) {
        _cleanup_(dck_import_unrefp) DckImport *import = NULL;
        _cleanup_event_unref_ sd_event *event = NULL;
        const char *name, *tag, *local;
        int r;

        tag = strchr(argv[1], ':');
        if (tag) {
                name = strndupa(argv[1], tag - argv[1]);
                tag++;
        } else {
                name = argv[1];
                tag = "latest";
        }

        if (argc >= 3)
                local = argv[2];
        else {
                local = strchr(name, '/');
                if (local)
                        local++;
                else
                        local = name;
        }

        if (streq(local, "-") || isempty(local))
                local = NULL;

        if (!dck_name_is_valid(name)) {
                log_error("Remote name '%s' is not valid.", name);
                return -EINVAL;
        }

        if (!dck_tag_is_valid(tag)) {
                log_error("Tag name '%s' is not valid.", tag);
                return -EINVAL;
        }

        if (local) {
                const char *p;

                if (!machine_name_is_valid(tag)) {
                        log_error("Local image name '%s' is not valid.", local);
                        return -EINVAL;
                }

                p = strappenda("/var/lib/container/", local);
                if (laccess(p, F_OK) >= 0) {
                        if (!arg_force) {
                                log_info("Image '%s' already exists.", local);
                                return 0;
                        }
                } else if (errno != ENOENT)
                        return log_error_errno(errno, "Can't check if image '%s' already exists: %m", local);

                log_info("Pulling '%s' with tag '%s', saving as '%s'.", name, tag, local);
        } else
                log_info("Pulling '%s' with tag '%s'.", name, tag);

        r = sd_event_default(&event);
        if (r < 0)
                return log_error_errno(r, "Failed to allocate event loop: %m");

        assert_se(sigprocmask_many(SIG_BLOCK, SIGTERM, SIGINT, -1) == 0);
        sd_event_add_signal(event, NULL, SIGTERM, NULL,  NULL);
        sd_event_add_signal(event, NULL, SIGINT, NULL, NULL);

        r = dck_import_new(&import, event, on_finished, event);
        if (r < 0)
                return log_error_errno(r, "Failed to allocate importer: %m");

        r = dck_import_pull(import, name, tag, local, arg_force);
        if (r < 0)
                return log_error_errno(r, "Failed to pull image: %m");

        r = sd_event_loop(event);
        if (r < 0)
                return log_error_errno(r, "Failed to run event loop: %m");

        log_info("Exiting.");

        return 0;
}
예제 #28
0
파일: pager.c 프로젝트: chenyf/systemd
int pager_open(bool jump_to_end) {
        int fd[2];
        const char *pager;
        pid_t parent_pid;
        int r;

        if (pager_pid > 0)
                return 1;

        if ((pager = getenv("SYSTEMD_PAGER")) || (pager = getenv("PAGER")))
                if (!*pager || streq(pager, "cat"))
                        return 0;

        if (!on_tty())
                return 0;

        /* Determine and cache number of columns before we spawn the
         * pager so that we get the value from the actual tty */
        columns();

        if (pipe(fd) < 0) {
                log_error("Failed to create pager pipe: %m");
                return -errno;
        }

        parent_pid = getpid();

        pager_pid = fork();
        if (pager_pid < 0) {
                r = -errno;
                log_error("Failed to fork pager: %m");
                safe_close_pair(fd);
                return r;
        }

        /* In the child start the pager */
        if (pager_pid == 0) {
                const char* less_opts;

                dup2(fd[0], STDIN_FILENO);
                safe_close_pair(fd);

                less_opts = getenv("SYSTEMD_LESS");
                if (!less_opts)
                        less_opts = "FRSXMK";
                if (jump_to_end)
                        less_opts = strappenda(less_opts, " +G");
                setenv("LESS", less_opts, 1);

                /* Make sure the pager goes away when the parent dies */
                if (prctl(PR_SET_PDEATHSIG, SIGTERM) < 0)
                        _exit(EXIT_FAILURE);

                /* Check whether our parent died before we were able
                 * to set the death signal */
                if (getppid() != parent_pid)
                        _exit(EXIT_SUCCESS);

                if (pager) {
                        execlp(pager, pager, NULL);
                        execl("/bin/sh", "sh", "-c", pager, NULL);
                }

                /* Debian's alternatives command for pagers is
                 * called 'pager'. Note that we do not call
                 * sensible-pagers here, since that is just a
                 * shell script that implements a logic that
                 * is similar to this one anyway, but is
                 * Debian-specific. */
                execlp("pager", "pager", NULL);

                execlp("less", "less", NULL);
                execlp("more", "more", NULL);

                pager_fallback();
                /* not reached */
        }

        /* Return in the parent */
        if (dup2(fd[1], STDOUT_FILENO) < 0) {
                log_error("Failed to duplicate pager pipe: %m");
                return -errno;
        }

        safe_close_pair(fd);
        return 1;
}
예제 #29
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);

                }
        }
예제 #30
0
static int parse_fstab(const char *prefix, bool initrd) {
        char *fstab_path;
        _cleanup_endmntent_ FILE *f;
        int r = 0;
        struct mntent *me;

        fstab_path = strappenda(strempty(prefix), "/etc/fstab");
        f = setmntent(fstab_path, "r");
        if (!f) {
                if (errno == ENOENT)
                        return 0;

                log_error("Failed to open %s/etc/fstab: %m", strempty(prefix));
                return -errno;
        }

        while ((me = getmntent(f))) {
                _cleanup_free_ char *where = NULL, *what = NULL;
                int k;

                if (initrd && !mount_in_initrd(me))
                        continue;

                what = fstab_node_to_udev_node(me->mnt_fsname);
                where = strjoin(strempty(prefix), me->mnt_dir, NULL);
                if (!what || !where)
                        return log_oom();

                if (is_path(where))
                        path_kill_slashes(where);

                log_debug("Found entry what=%s where=%s type=%s", what, where, me->mnt_type);

                if (streq(me->mnt_type, "swap"))
                        k = add_swap(what, me);
                else {
                        bool noauto, nofail, automount;
                        const char *post;

                        noauto = !!hasmntopt(me, "noauto");
                        nofail = !!hasmntopt(me, "nofail");
                        automount =
                                  hasmntopt(me, "comment=systemd.automount") ||
                                  hasmntopt(me, "x-systemd.automount");

                        if (initrd) {
                                post = SPECIAL_INITRD_FS_TARGET;
                        } else if (mount_in_initrd(me)) {
                                post = SPECIAL_INITRD_ROOT_FS_TARGET;
                        } else if (mount_is_network(me)) {
                                post = SPECIAL_REMOTE_FS_TARGET;
                        } else {
                                post = SPECIAL_LOCAL_FS_TARGET;
                        }

                        k = add_mount(what, where, me->mnt_type, me->mnt_opts,
                                      me->mnt_passno, noauto, nofail, automount,
                                      post, fstab_path);
                }

                if (k < 0)
                        r = k;
        }

        return r;
}