static int add_dbus(const char *path, const char *fname, const char *type) {
        _cleanup_free_ char *name = NULL, *exec = NULL, *user = NULL, *service = NULL;

        ConfigTableItem table[] = {
                { "D-BUS Service", "Name", config_parse_string, 0, &name },
                { "D-BUS Service", "Exec", config_parse_string, 0, &exec },
                { "D-BUS Service", "User", config_parse_string, 0, &user },
                { "D-BUS Service", "SystemdService", config_parse_string, 0, &service },
        };

        _cleanup_fclose_ FILE *f = NULL;
        _cleanup_free_ char *p = NULL;
        int r;

        assert(path);
        assert(fname);

        p = strjoin(path, "/", fname, NULL);
        if (!p)
                return log_oom();

        f = fopen(p, "re");
        if (!f) {
                if (errno == -ENOENT)
                        return 0;

                log_error("Failed to read %s: %m", p);
                return -errno;
        }

        r = config_parse(NULL, p, f, "D-BUS Service\0", config_item_table_lookup, table, true, false, NULL);
        if (r < 0)
                return r;

        if (!name) {
                log_warning("Activation file %s lacks name setting, ignoring.", p);
                return 0;
        }

        if (!service_name_is_valid(name)) {
                log_warning("Bus service name %s is not valid, ignoring.", name);
                return 0;
        }

        if (streq(name, "org.freedesktop.systemd1")) {
                log_debug("Skipping %s, identified as systemd.", p);
                return 0;
        }

        if (service) {
                if (!unit_name_is_valid(service, TEMPLATE_INVALID)) {
                        log_warning("Unit name %s is not valid, ignoring.", service);
                        return 0;
                }
                if (!endswith(service, ".service")) {
                        log_warning("Bus names can only activate services, ignoring %s.", p);
                        return 0;
                }
        } else {
                if (streq(exec, "/bin/false") || !exec) {
                        log_warning("Neither service name nor binary path specified, ignoring %s.", p);
                        return 0;
                }

                if (exec[0] != '/') {
                        log_warning("Exec= in %s does not start with an absolute path, ignoring.", p);
                        return 0;
                }
        }

        return create_dbus_files(p, name, service, exec, user, type);
}
Exemple #2
0
static int add_boot(const char *what) {
        _cleanup_blkid_free_probe_ blkid_probe b = NULL;
        const char *fstype = NULL, *uuid = NULL;
        sd_id128_t id, type_id;
        int r;

        assert(what);

        if (!is_efi_boot()) {
                log_debug("Not an EFI boot, ignoring /boot.");
                return 0;
        }

        if (in_initrd()) {
                log_debug("In initrd, ignoring /boot.");
                return 0;
        }

        if (detect_container() > 0) {
                log_debug("In a container, ignoring /boot.");
                return 0;
        }

        /* We create an .automount which is not overridden by the .mount from the fstab generator. */
        if (fstab_is_mount_point("/boot")) {
                log_debug("/boot specified in fstab, ignoring.");
                return 0;
        }

        if (path_is_busy("/boot")) {
                log_debug("/boot already populated, ignoring.");
                return 0;
        }

        r = efi_loader_get_device_part_uuid(&id);
        if (r == -ENOENT) {
                log_debug("EFI loader partition unknown.");
                return 0;
        }

        if (r < 0) {
                log_error_errno(r, "Failed to read ESP partition UUID: %m");
                return r;
        }

        errno = 0;
        b = blkid_new_probe_from_filename(what);
        if (!b) {
                if (errno == 0)
                        return log_oom();
                return log_error_errno(errno, "Failed to allocate prober: %m");
        }

        blkid_probe_enable_partitions(b, 1);
        blkid_probe_set_partitions_flags(b, BLKID_PARTS_ENTRY_DETAILS);

        errno = 0;
        r = blkid_do_safeprobe(b);
        if (r == -2 || r == 1) /* no result or uncertain */
                return 0;
        else if (r != 0)
                return log_error_errno(errno ?: EIO, "Failed to probe %s: %m", what);

        (void) blkid_probe_lookup_value(b, "TYPE", &fstype, NULL);
        if (!streq_ptr(fstype, "vfat")) {
                log_debug("Partition for /boot is not a FAT filesystem, ignoring.");
                return 0;
        }

        errno = 0;
        r = blkid_probe_lookup_value(b, "PART_ENTRY_UUID", &uuid, NULL);
        if (r != 0) {
                log_debug_errno(errno, "Partition for /boot does not have a UUID, ignoring.");
                return 0;
        }

        if (sd_id128_from_string(uuid, &type_id) < 0) {
                log_debug("Partition for /boot does not have a valid UUID, ignoring.");
                return 0;
        }

        if (!sd_id128_equal(type_id, id)) {
                log_debug("Partition for /boot does not appear to be the partition we are booted from.");
                return 0;
        }

        r = add_automount("boot",
                       what,
                       "/boot",
                       "vfat",
                       true,
                       "umask=0077",
                       "EFI System Partition Automount",
                       120 * USEC_PER_SEC);

        return r;
}
Exemple #3
0
static int add_cryptsetup(const char *id, const char *what, bool rw, char **device) {
        _cleanup_free_ char *e = NULL, *n = NULL, *p = NULL, *d = NULL, *to = NULL;
        _cleanup_fclose_ FILE *f = NULL;
        char *from, *ret;
        int r;

        assert(id);
        assert(what);
        assert(device);

        r = unit_name_from_path(what, ".device", &d);
        if (r < 0)
                return log_error_errno(r, "Failed to generate unit name: %m");

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

        r = unit_name_build("systemd-cryptsetup", e, ".service", &n);
        if (r < 0)
                return log_error_errno(r, "Failed to generate unit name: %m");

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

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

        fprintf(f,
                "# Automatically generated by systemd-gpt-auto-generator\n\n"
                "[Unit]\n"
                "Description=Cryptography Setup for %%I\n"
                "Documentation=man:systemd-gpt-auto-generator(8) man:[email protected](8)\n"
                "DefaultDependencies=no\n"
                "Conflicts=umount.target\n"
                "BindsTo=dev-mapper-%%i.device %s\n"
                "Before=umount.target cryptsetup.target\n"
                "After=%s\n"
                "IgnoreOnIsolate=true\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'\n"
                "ExecStop=" SYSTEMD_CRYPTSETUP_PATH " detach '%s'\n",
                d, d,
                id, what, rw ? "" : "read-only",
                id);

        r = fflush_and_check(f);
        if (r < 0)
                return log_error_errno(r, "Failed to write file %s: %m", p);

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

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

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

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

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

        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)
                return log_error_errno(errno, "Failed to create symlink %s: %m", to);

        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-gpt-auto-generator\n\n"
                        "[Unit]\n"
                        "JobTimeoutSec=0\n",
                        WRITE_STRING_FILE_CREATE); /* the binary handles timeouts anyway */
        if (r < 0)
                return log_error_errno(r, "Failed to write device drop-in: %m");

        ret = strappend("/dev/mapper/", id);
        if (!ret)
                return log_oom();

        *device = ret;
        return 0;
}
Exemple #4
0
static int curl_glue_socket_callback(CURLM *curl, curl_socket_t s, int action, void *userdata, void *socketp) {
        sd_event_source *io;
        CurlGlue *g = userdata;
        uint32_t events = 0;
        int r;

        assert(curl);
        assert(g);

        io = hashmap_get(g->ios, FD_TO_PTR(s));

        if (action == CURL_POLL_REMOVE) {
                if (io) {
                        int fd;

                        fd = sd_event_source_get_io_fd(io);
                        assert(fd >= 0);

                        sd_event_source_set_enabled(io, SD_EVENT_OFF);
                        sd_event_source_unref(io);

                        hashmap_remove(g->ios, FD_TO_PTR(s));
                        hashmap_remove(g->translate_fds, FD_TO_PTR(fd));

                        safe_close(fd);
                }

                return 0;
        }

        r = hashmap_ensure_allocated(&g->ios, &trivial_hash_ops);
        if (r < 0) {
                log_oom();
                return -1;
        }

        r = hashmap_ensure_allocated(&g->translate_fds, &trivial_hash_ops);
        if (r < 0) {
                log_oom();
                return -1;
        }

        if (action == CURL_POLL_IN)
                events = EPOLLIN;
        else if (action == CURL_POLL_OUT)
                events = EPOLLOUT;
        else if (action == CURL_POLL_INOUT)
                events = EPOLLIN|EPOLLOUT;

        if (io) {
                if (sd_event_source_set_io_events(io, events) < 0)
                        return -1;

                if (sd_event_source_set_enabled(io, SD_EVENT_ON) < 0)
                        return -1;
        } else {
                _cleanup_close_ int fd = -1;

                /* When curl needs to remove an fd from us it closes
                 * the fd first, and only then calls into us. This is
                 * nasty, since we cannot pass the fd on to epoll()
                 * anymore. Hence, duplicate the fds here, and keep a
                 * copy for epoll which we control after use. */

                fd = fcntl(s, F_DUPFD_CLOEXEC, 3);
                if (fd < 0)
                        return -1;

                if (sd_event_add_io(g->event, &io, fd, events, curl_glue_on_io, g) < 0)
                        return -1;

                (void) sd_event_source_set_description(io, "curl-io");

                r = hashmap_put(g->ios, FD_TO_PTR(s), io);
                if (r < 0) {
                        log_oom();
                        sd_event_source_unref(io);
                        return -1;
                }

                r = hashmap_put(g->translate_fds, FD_TO_PTR(fd), FD_TO_PTR(s));
                if (r < 0) {
                        log_oom();
                        hashmap_remove(g->ios, FD_TO_PTR(s));
                        sd_event_source_unref(io);
                        return -1;
                }

                fd = -1;
        }

        return 0;
}
Exemple #5
0
static int add_mount(
                const char *id,
                const char *what,
                const char *where,
                const char *fstype,
                bool rw,
                const char *options,
                const char *description,
                const char *post) {

        _cleanup_free_ char *unit = NULL, *lnk = NULL, *crypto_what = NULL, *p = NULL;
        _cleanup_fclose_ FILE *f = NULL;
        int r;

        assert(id);
        assert(what);
        assert(where);
        assert(description);

        log_debug("Adding %s: %s %s", where, what, strna(fstype));

        if (streq_ptr(fstype, "crypto_LUKS")) {

                r = add_cryptsetup(id, what, rw, &crypto_what);
                if (r < 0)
                        return r;

                what = crypto_what;
                fstype = NULL;
        }

        r = unit_name_from_path(where, ".mount", &unit);
        if (r < 0)
                return log_error_errno(r, "Failed to generate unit name: %m");

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

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

        fprintf(f,
                "# Automatically generated by systemd-gpt-auto-generator\n\n"
                "[Unit]\n"
                "Description=%s\n"
                "Documentation=man:systemd-gpt-auto-generator(8)\n",
                description);

        if (post)
                fprintf(f, "Before=%s\n", post);

        r = generator_write_fsck_deps(f, arg_dest, what, where, fstype);
        if (r < 0)
                return r;

        fprintf(f,
                "\n"
                "[Mount]\n"
                "What=%s\n"
                "Where=%s\n",
                what, where);

        if (fstype)
                fprintf(f, "Type=%s\n", fstype);

        if (options)
                fprintf(f, "Options=%s,%s\n", options, rw ? "rw" : "ro");
        else
                fprintf(f, "Options=%s\n", rw ? "rw" : "ro");

        r = fflush_and_check(f);
        if (r < 0)
                return log_error_errno(r, "Failed to write unit file %s: %m", p);

        if (post) {
                lnk = strjoin(arg_dest, "/", post, ".requires/", unit, NULL);
                if (!lnk)
                        return log_oom();

                mkdir_parents_label(lnk, 0755);
                if (symlink(p, lnk) < 0)
                        return log_error_errno(errno, "Failed to create symlink %s: %m", lnk);
        }

        return 0;
}
Exemple #6
0
int change_uid_gid(const char *user, char **_home) {
        char line[LINE_MAX], *x, *u, *g, *h;
        const char *word, *state;
        _cleanup_free_ uid_t *uids = NULL;
        _cleanup_free_ char *home = NULL;
        _cleanup_fclose_ FILE *f = NULL;
        _cleanup_close_ int fd = -1;
        unsigned n_uids = 0;
        size_t sz = 0, l;
        uid_t uid;
        gid_t gid;
        pid_t pid;
        int r;

        assert(_home);

        if (!user || streq(user, "root") || streq(user, "0")) {
                /* Reset everything fully to 0, just in case */

                r = reset_uid_gid();
                if (r < 0)
                        return log_error_errno(r, "Failed to become root: %m");

                *_home = NULL;
                return 0;
        }

        /* First, get user credentials */
        fd = spawn_getent("passwd", user, &pid);
        if (fd < 0)
                return fd;

        f = fdopen(fd, "r");
        if (!f)
                return log_oom();
        fd = -1;

        if (!fgets(line, sizeof(line), f)) {

                if (!ferror(f)) {
                        log_error("Failed to resolve user %s.", user);
                        return -ESRCH;
                }

                log_error_errno(errno, "Failed to read from getent: %m");
                return -errno;
        }

        truncate_nl(line);

        wait_for_terminate_and_warn("getent passwd", pid, true);

        x = strchr(line, ':');
        if (!x) {
                log_error("/etc/passwd entry has invalid user field.");
                return -EIO;
        }

        u = strchr(x+1, ':');
        if (!u) {
                log_error("/etc/passwd entry has invalid password field.");
                return -EIO;
        }

        u++;
        g = strchr(u, ':');
        if (!g) {
                log_error("/etc/passwd entry has invalid UID field.");
                return -EIO;
        }

        *g = 0;
        g++;
        x = strchr(g, ':');
        if (!x) {
                log_error("/etc/passwd entry has invalid GID field.");
                return -EIO;
        }

        *x = 0;
        h = strchr(x+1, ':');
        if (!h) {
                log_error("/etc/passwd entry has invalid GECOS field.");
                return -EIO;
        }

        h++;
        x = strchr(h, ':');
        if (!x) {
                log_error("/etc/passwd entry has invalid home directory field.");
                return -EIO;
        }

        *x = 0;

        r = parse_uid(u, &uid);
        if (r < 0) {
                log_error("Failed to parse UID of user.");
                return -EIO;
        }

        r = parse_gid(g, &gid);
        if (r < 0) {
                log_error("Failed to parse GID of user.");
                return -EIO;
        }

        home = strdup(h);
        if (!home)
                return log_oom();

        /* Second, get group memberships */
        fd = spawn_getent("initgroups", user, &pid);
        if (fd < 0)
                return fd;

        fclose(f);
        f = fdopen(fd, "r");
        if (!f)
                return log_oom();
        fd = -1;

        if (!fgets(line, sizeof(line), f)) {
                if (!ferror(f)) {
                        log_error("Failed to resolve user %s.", user);
                        return -ESRCH;
                }

                log_error_errno(errno, "Failed to read from getent: %m");
                return -errno;
        }

        truncate_nl(line);

        wait_for_terminate_and_warn("getent initgroups", pid, true);

        /* Skip over the username and subsequent separator whitespace */
        x = line;
        x += strcspn(x, WHITESPACE);
        x += strspn(x, WHITESPACE);

        FOREACH_WORD(word, l, x, state) {
                char c[l+1];

                memcpy(c, word, l);
                c[l] = 0;

                if (!GREEDY_REALLOC(uids, sz, n_uids+1))
                        return log_oom();

                r = parse_uid(c, &uids[n_uids++]);
                if (r < 0) {
                        log_error("Failed to parse group data from getent.");
                        return -EIO;
                }
        }
Exemple #7
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:
                        puts(PACKAGE_STRING);
                        puts(SYSTEMD_FEATURES);
                        return 0;

                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, "/")) {
                                free(arg_root);
                                arg_root = NULL;
                        }

                        break;

                case ARG_LOCALE:
                        if (!locale_is_valid(optarg)) {
                                log_error("Locale %s is not valid.", optarg);
                                return -EINVAL;
                        }

                        free(arg_locale);
                        arg_locale = strdup(optarg);
                        if (!arg_locale)
                                return log_oom();

                        break;

                case ARG_LOCALE_MESSAGES:
                        if (!locale_is_valid(optarg)) {
                                log_error("Locale %s is not valid.", optarg);
                                return -EINVAL;
                        }

                        free(arg_locale_messages);
                        arg_locale_messages = strdup(optarg);
                        if (!arg_locale_messages)
                                return log_oom();

                        break;

                case ARG_TIMEZONE:
                        if (!timezone_is_valid(optarg)) {
                                log_error("Timezone %s is not valid.", optarg);
                                return -EINVAL;
                        }

                        free(arg_timezone);
                        arg_timezone = strdup(optarg);
                        if (!arg_timezone)
                                return log_oom();

                        break;

                case ARG_ROOT_PASSWORD:
                        free(arg_root_password);
                        arg_root_password = strdup(optarg);
                        if (!arg_root_password)
                                return log_oom();

                        break;

                case ARG_ROOT_PASSWORD_FILE:
                        free(arg_root_password);
                        arg_root_password  = NULL;

                        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)) {
                                log_error("Host name %s is not valid.", optarg);
                                return -EINVAL;
                        }

                        free(arg_hostname);
                        arg_hostname = strdup(optarg);
                        if (!arg_hostname)
                                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;
}
Exemple #8
0
static int add_swap(const char *what, struct mntent *me) {
        _cleanup_free_ char *name = NULL, *unit = NULL, *lnk = NULL;
        _cleanup_fclose_ FILE *f = NULL;
        bool noauto;
        int r, pri = -1;

        assert(what);
        assert(me);

        r = mount_find_pri(me, &pri);
        if (r < 0) {
                log_error("Failed to parse priority");
                return pri;
        }

        noauto = !!hasmntopt(me, "noauto");

        name = unit_name_from_path(what, ".swap");
        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 swap 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=/etc/fstab\n\n"
                "[Swap]\n"
                "What=%s\n",
                what);

        if (pri >= 0)
                fprintf(f,
                        "Priority=%i\n",
                        pri);

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

        if (!noauto) {
                lnk = strjoin(arg_dest, "/" SPECIAL_SWAP_TARGET ".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;
                }
        }

        return 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,
                *filtered = NULL;
        _cleanup_fclose_ FILE *f = NULL;
        bool noauto, nofail, tmp, swap;
        char *from;
        int r;

        assert(name);
        assert(device);

        noauto = fstab_test_yes_no_option(options, "noauto\0" "auto\0");
        nofail = fstab_test_yes_no_option(options, "nofail\0" "fail\0");
        tmp = fstab_test_option(options, "tmp\0");
        swap = fstab_test_option(options, "swap\0");

        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();

        r = unit_name_build("systemd-cryptsetup", e, ".service", &n);
        if (r < 0)
                return log_error_errno(r, "Failed to generate unit name: %m");

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

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

        r = unit_name_from_path(u, ".device", &d);
        if (r < 0)
                return log_error_errno(r, "Failed to generate unit name: %m");

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

        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=cryptsetup-pre.target\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 (!path_equal(uu, "/dev/null")) {

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

                                        r = unit_name_from_path(uu, ".device", &dd);
                                        if (r < 0)
                                                return log_error_errno(r, "Failed to generate unit name: %m");

                                        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);

        r = generator_write_timeouts(arg_dest, device, name, options, &filtered);
        if (r < 0)
                return r;

        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(filtered),
                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);

        r = fflush_and_check(f);
        if (r < 0)
                return log_error_errno(r, "Failed to write file %s: %m", p);

        from = strjoina("../", 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)
                        return log_error_errno(errno, "Failed to create symlink %s: %m", to);

                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)
                        return log_error_errno(errno, "Failed to create symlink %s: %m", to);
        }

        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)
                return log_error_errno(errno, "Failed to create symlink %s: %m", to);

        if (!noauto && !nofail) {
                _cleanup_free_ char *dmname;
                dmname = strjoin("dev-mapper-", e, ".device", NULL);
                if (!dmname)
                        return log_oom();

                r = write_drop_in(arg_dest, dmname, 90, "device-timeout",
                                  "# Automatically generated by systemd-cryptsetup-generator \n\n"
                                  "[Unit]\nJobTimeoutSec=0");
                if (r < 0)
                        return log_error_errno(r, "Failed to write device drop-in: %m");
        }

        return 0;
}
Exemple #10
0
static int add_mount(
                const char *what,
                const char *where,
                const char *type,
                const char *opts,
                int passno,
                bool noauto,
                bool nofail,
                bool automount,
                const char *post,
                const char *source) {
        _cleanup_free_ char
                *name = NULL, *unit = NULL, *lnk = NULL,
                *automount_name = NULL, *automount_unit = NULL;
        _cleanup_fclose_ FILE *f = NULL;

        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",
              source);

        if (post && !noauto && !nofail && !automount)
                fprintf(f,
                        "Before=%s\n",
                        post);

        if (passno > 0) {
                if (streq(where, "/")) {
                        lnk = strjoin(arg_dest, "/", SPECIAL_LOCAL_FS_TARGET, ".wants/", "systemd-fsck-root.service", NULL);
                        if (!lnk)
                                return log_oom();

                        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,
                                "Requires=%s\n"
                                "After=%s\n",
                                fsck,
                                fsck);
                }
        }


        fprintf(f,
                "\n"
                "[Mount]\n"
                "What=%s\n"
                "Where=%s\n"
                "Type=%s\n",
                what,
                where,
                type);

        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) {
                if (post) {
                        free(lnk);
                        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 (automount && !path_equal(where, "/")) {
                automount_name = unit_name_from_path(where, ".automount");
                if (!automount_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",
                        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;
}
Exemple #11
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;
}
Exemple #12
0
int decompress_stream_lz4(int fdf, int fdt, off_t max_bytes) {

#ifdef HAVE_LZ4
        _cleanup_free_ char *buf = NULL, *out = NULL;
        size_t buf_size = 0;
        LZ4_streamDecode_t lz4_data = {};
        le32_t header;
        size_t total_in = sizeof(header), total_out = 0;

        assert(fdf >= 0);
        assert(fdt >= 0);

        out = malloc(4*LZ4_BUFSIZE);
        if (!out)
                return log_oom();

        for (;;) {
                ssize_t m;
                int r;

                r = loop_read_exact(fdf, &header, sizeof(header), false);
                if (r < 0)
                        return r;

                m = le32toh(header);
                if (m == 0)
                        break;

                /* We refuse to use a bigger decompression buffer than
                 * the one used for compression by 4 times. This means
                 * that compression buffer size can be enlarged 4
                 * times. This can be changed, but old binaries might
                 * not accept buffers compressed by newer binaries then.
                 */
                if (m > LZ4_COMPRESSBOUND(LZ4_BUFSIZE * 4)) {
                        log_error("Compressed stream block too big: %zd bytes", m);
                        return -EBADMSG;
                }

                total_in += sizeof(header) + m;

                if (!GREEDY_REALLOC(buf, buf_size, m))
                        return log_oom();

                r = loop_read_exact(fdf, buf, m, false);
                if (r < 0)
                        return r;

                r = LZ4_decompress_safe_continue(&lz4_data, buf, out, m, 4*LZ4_BUFSIZE);
                if (r <= 0)
                        log_error("LZ4 decompression failed.");

                total_out += r;

                if (max_bytes != -1 && total_out > (size_t) max_bytes) {
                        log_debug("Decompressed stream longer than %zd bytes", max_bytes);
                        return -EFBIG;
                }

                r = loop_write(fdt, out, r, false);
                if (r < 0)
                        return r;
        }

        log_debug("LZ4 decompression finished (%zu -> %zu bytes, %.1f%%)",
                  total_in, total_out,
                  (double) total_out / total_in * 100);

        return 0;
#else
        log_error("Cannot decompress file. Compiled without LZ4 support.");
        return -EPROTONOSUPPORT;
#endif
}
Exemple #13
0
int compress_stream_lz4(int fdf, int fdt, off_t max_bytes) {

#ifdef HAVE_LZ4

        _cleanup_free_ char *buf1 = NULL, *buf2 = NULL, *out = NULL;
        char *buf;
        LZ4_stream_t lz4_data = {};
        le32_t header;
        size_t total_in = 0, total_out = sizeof(header);
        ssize_t n;

        assert(fdf >= 0);
        assert(fdt >= 0);

        buf1 = malloc(LZ4_BUFSIZE);
        buf2 = malloc(LZ4_BUFSIZE);
        out = malloc(LZ4_COMPRESSBOUND(LZ4_BUFSIZE));
        if (!buf1 || !buf2 || !out)
                return log_oom();

        buf = buf1;
        for (;;) {
                size_t m;
                int r;

                m = LZ4_BUFSIZE;
                if (max_bytes != -1 && m > (size_t) max_bytes - total_in)
                        m = max_bytes - total_in;

                n = read(fdf, buf, m);
                if (n < 0)
                        return -errno;
                if (n == 0)
                        break;

                total_in += n;

                r = LZ4_compress_continue(&lz4_data, buf, out, n);
                if (r == 0) {
                        log_error("LZ4 compression failed.");
                        return -EBADMSG;
                }

                header = htole32(r);
                errno = 0;

                n = write(fdt, &header, sizeof(header));
                if (n < 0)
                        return -errno;
                if (n != sizeof(header))
                        return errno ? -errno : -EIO;

                n = loop_write(fdt, out, r, false);
                if (n < 0)
                        return n;

                total_out += sizeof(header) + r;

                buf = buf == buf1 ? buf2 : buf1;
        }

        header = htole32(0);
        n = write(fdt, &header, sizeof(header));
        if (n < 0)
                return -errno;
        if (n != sizeof(header))
                return errno ? -errno : -EIO;

        log_debug("LZ4 compression finished (%zu -> %zu bytes, %.1f%%)",
                  total_in, total_out,
                  (double) total_out / total_in * 100);

        return 0;
#else
        return -EPROTONOSUPPORT;
#endif
}
Exemple #14
0
static int create_dbus_files(
                const char *path,
                const char *name,
                const char *service,
                const char *exec,
                const char *user,
                const char *type) {

        _cleanup_free_ char *b = NULL, *s = NULL, *lnk = NULL;
        _cleanup_fclose_ FILE *f = NULL;

        assert(path);
        assert(name);
        assert(service || exec);

        if (!service) {
                _cleanup_free_ char *a = NULL;

                s = strjoin("dbus-", name, ".service", NULL);
                if (!s)
                        return log_oom();

                a = strjoin(arg_dest_late, "/", s, NULL);
                if (!a)
                        return log_oom();

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

                fprintf(f,
                        "# Automatically generated by systemd-dbus1-generator\n\n"
                        "[Unit]\n"
                        "SourcePath=%s\n"
                        "Description=DBUS1: %s\n"
                        "Documentation=man:systemd-dbus1-generator(8)\n\n"
                        "[Service]\n"
                        "ExecStart=%s\n"
                        "Type=dbus\n"
                        "BusName=%s\n",
                        path,
                        name,
                        exec,
                        name);

                if (user)
                        fprintf(f, "User=%s\n", user);


                if (type) {
                        fprintf(f, "Environment=DBUS_STARTER_BUS_TYPE=%s\n", type);

                        if (streq(type, "system"))
                                fprintf(f, "Environment=DBUS_STARTER_ADDRESS=" DEFAULT_SYSTEM_BUS_PATH "\n");
                        else if (streq(type, "session")) {
                                char *run;

                                run = getenv("XDG_RUNTIME_DIR");
                                if (!run) {
                                        log_error("XDG_RUNTIME_DIR not set.");
                                        return -EINVAL;
                                }

                                fprintf(f, "Environment=DBUS_STARTER_ADDRESS="KERNEL_USER_BUS_FMT ";" UNIX_USER_BUS_FMT "\n",
                                        getuid(), run);
                        }
                }

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

                service = s;
        }

        b = strjoin(arg_dest_late, "/", name, ".busname", NULL);
        if (!b)
                return log_oom();

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

        fprintf(f,
                "# Automatically generated by systemd-dbus1-generator\n\n"
                "[Unit]\n"
                "SourcePath=%s\n"
                "Description=DBUS1: %s\n"
                "Documentation=man:systemd-dbus1-generator(8)\n\n"
                "[BusName]\n"
                "Name=%s\n"
                "Service=%s\n"
                "AllowWorld=talk\n",
                path,
                name,
                name,
                service);

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

        lnk = strjoin(arg_dest_late, "/" SPECIAL_BUSNAMES_TARGET ".wants/", name, ".busname", NULL);
        if (!lnk)
                return log_oom();

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

        return 0;
}
Exemple #15
0
static int modeset_new(Modeset **out) {
        _cleanup_(modeset_freep) Modeset *m = NULL;
        int r;

        assert(out);

        m = new0(Modeset, 1);
        if (!m)
                return log_oom();

        r = sd_pid_get_session(getpid(), &m->session);
        if (r < 0)
                return log_error_errno(r, "Cannot retrieve logind session: %m");

        r = sd_session_get_seat(m->session, &m->seat);
        if (r < 0)
                return log_error_errno(r, "Cannot retrieve seat of logind session: %m");

        m->my_tty = is_my_tty(m->session);
        m->managed = m->my_tty && geteuid() > 0;

        m->r = rand() % 0xff;
        m->g = rand() % 0xff;
        m->b = rand() % 0xff;
        m->r_up = m->g_up = m->b_up = true;

        r = sd_event_default(&m->event);
        if (r < 0)
                return r;

        r = sd_bus_open_system(&m->bus);
        if (r < 0)
                return r;

        r = sd_bus_attach_event(m->bus, m->event, SD_EVENT_PRIORITY_NORMAL);
        if (r < 0)
                return r;

        r = sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, -1);
        if (r < 0)
                return r;

        r = sd_event_add_signal(m->event, NULL, SIGTERM, NULL, NULL);
        if (r < 0)
                return r;

        r = sd_event_add_signal(m->event, NULL, SIGINT, NULL, NULL);
        if (r < 0)
                return r;

        r = sd_event_add_exit(m->event, &m->exit_src, modeset_exit_fn, m);
        if (r < 0)
                return r;

        /* schedule before sd-bus close */
        r = sd_event_source_set_priority(m->exit_src, -10);
        if (r < 0)
                return r;

        r = sysview_context_new(&m->sysview,
                                SYSVIEW_CONTEXT_SCAN_LOGIND |
                                SYSVIEW_CONTEXT_SCAN_DRM,
                                m->event,
                                m->bus,
                                NULL);
        if (r < 0)
                return r;

        r = grdev_context_new(&m->grdev, m->event, m->bus);
        if (r < 0)
                return r;

        *out = m;
        m = NULL;
        return 0;
}
Exemple #16
0
int catalog_import_file(Hashmap *h, struct strbuf *sb, const char *path) {
        _cleanup_fclose_ FILE *f = NULL;
        _cleanup_free_ char *payload = NULL;
        unsigned n = 0;
        sd_id128_t id;
        _cleanup_free_ char *deflang = NULL, *lang = NULL;
        bool got_id = false, empty_line = true;
        int r;

        assert(h);
        assert(sb);
        assert(path);

        f = fopen(path, "re");
        if (!f)
                return log_error_errno(errno, "Failed to open file %s: %m", path);

        r = catalog_file_lang(path, &deflang);
        if (r < 0)
                log_error_errno(errno, "Failed to determine language for file %s: %m", path);
        if (r == 1)
                log_debug("File %s has language %s.", path, deflang);

        for (;;) {
                char line[LINE_MAX];
                size_t a, b, c;
                char *t;

                if (!fgets(line, sizeof(line), f)) {
                        if (feof(f))
                                break;

                        log_error_errno(errno, "Failed to read file %s: %m", path);
                        return -errno;
                }

                n++;

                truncate_nl(line);

                if (line[0] == 0) {
                        empty_line = true;
                        continue;
                }

                if (strchr(COMMENTS "\n", line[0]))
                        continue;

                if (empty_line &&
                    strlen(line) >= 2+1+32 &&
                    line[0] == '-' &&
                    line[1] == '-' &&
                    line[2] == ' ' &&
                    (line[2+1+32] == ' ' || line[2+1+32] == '\0')) {

                        bool with_language;
                        sd_id128_t jd;

                        /* New entry */

                        with_language = line[2+1+32] != '\0';
                        line[2+1+32] = '\0';

                        if (sd_id128_from_string(line + 2 + 1, &jd) >= 0) {

                                if (got_id) {
                                        r = finish_item(h, sb, id, lang ?: deflang, payload);
                                        if (r < 0)
                                                return r;

                                        lang = mfree(lang);
                                }

                                if (with_language) {
                                        t = strstrip(line + 2 + 1 + 32 + 1);

                                        r = catalog_entry_lang(path, n, t, deflang, &lang);
                                        if (r < 0)
                                                return r;
                                }

                                got_id = true;
                                empty_line = false;
                                id = jd;

                                if (payload)
                                        payload[0] = '\0';

                                continue;
                        }
                }

                /* Payload */
                if (!got_id) {
                        log_error("[%s:%u] Got payload before ID.", path, n);
                        return -EINVAL;
                }

                a = payload ? strlen(payload) : 0;
                b = strlen(line);

                c = a + (empty_line ? 1 : 0) + b + 1 + 1;
                t = realloc(payload, c);
                if (!t)
                        return log_oom();

                if (empty_line) {
                        t[a] = '\n';
                        memcpy(t + a + 1, line, b);
                        t[a+b+1] = '\n';
                        t[a+b+2] = 0;
                } else {
                        memcpy(t + a, line, b);
                        t[a+b] = '\n';
                        t[a+b+1] = 0;
                }

                payload = t;
                empty_line = false;
        }
Exemple #17
0
/* Go through the file and parse each line */
int config_parse(const char *unit,
                 const char *filename,
                 FILE *f,
                 const char *sections,
                 ConfigItemLookup lookup,
                 const void *table,
                 bool relaxed,
                 bool allow_include,
                 bool warn,
                 void *userdata) {

        _cleanup_free_ char *section = NULL, *continuation = NULL;
        _cleanup_fclose_ FILE *ours = NULL;
        unsigned line = 0, section_line = 0;
        bool section_ignored = false;
        int r;

        assert(filename);
        assert(lookup);

        if (!f) {
                f = ours = fopen(filename, "re");
                if (!f) {
                        /* Only log on request, except for ENOENT,
                         * since we return 0 to the caller. */
                        if (warn || errno == ENOENT)
                                log_full(errno == ENOENT ? LOG_DEBUG : LOG_ERR,
                                         "Failed to open configuration file '%s': %m", filename);
                        return errno == ENOENT ? 0 : -errno;
                }
        }

        fd_warn_permissions(filename, fileno(f));

        while (!feof(f)) {
                char l[LINE_MAX], *p, *c = NULL, *e;
                bool escaped = false;

                if (!fgets(l, sizeof(l), f)) {
                        if (feof(f))
                                break;

                        log_error("Failed to read configuration file '%s': %m", filename);
                        return -errno;
                }

                truncate_nl(l);

                if (continuation) {
                        c = strappend(continuation, l);
                        if (!c) {
                                if (warn)
                                        log_oom();
                                return -ENOMEM;
                        }

                        free(continuation);
                        continuation = NULL;
                        p = c;
                } else
                        p = l;

                for (e = p; *e; e++) {
                        if (escaped)
                                escaped = false;
                        else if (*e == '\\')
                                escaped = true;
                }

                if (escaped) {
                        *(e-1) = ' ';

                        if (c)
                                continuation = c;
                        else {
                                continuation = strdup(l);
                                if (!continuation) {
                                        if (warn)
                                                log_oom();
                                        return -ENOMEM;
                                }
                        }

                        continue;
                }

                r = parse_line(unit,
                               filename,
                               ++line,
                               sections,
                               lookup,
                               table,
                               relaxed,
                               allow_include,
                               &section,
                               &section_line,
                               &section_ignored,
                               p,
                               userdata);
                free(c);

                if (r < 0) {
                        if (warn)
                                log_warning("Failed to parse file '%s': %s",
                                            filename, strerror(-r));
                        return r;
                }
        }

        return 0;
}
Exemple #18
0
int parse_sleep_config(const char *verb, char ***_modes, char ***_states) {

        _cleanup_strv_free_ char
                **suspend_mode = NULL, **suspend_state = NULL,
                **hibernate_mode = NULL, **hibernate_state = NULL,
                **hybrid_mode = NULL, **hybrid_state = NULL;
        char **modes, **states;

        const ConfigTableItem items[] = {
                { "Sleep",   "SuspendMode",      config_parse_strv,  0, &suspend_mode  },
                { "Sleep",   "SuspendState",     config_parse_strv,  0, &suspend_state },
                { "Sleep",   "HibernateMode",    config_parse_strv,  0, &hibernate_mode  },
                { "Sleep",   "HibernateState",   config_parse_strv,  0, &hibernate_state },
                { "Sleep",   "HybridSleepMode",  config_parse_strv,  0, &hybrid_mode  },
                { "Sleep",   "HybridSleepState", config_parse_strv,  0, &hybrid_state },
                {}
        };

        config_parse_many(PKGSYSCONFDIR "/sleep.conf",
                          CONF_DIRS_NULSTR("systemd/sleep.conf"),
                          "Sleep\0", config_item_table_lookup, items,
                          false, NULL);

        if (streq(verb, "suspend")) {
                /* empty by default */
                USE(modes, suspend_mode);

                if (suspend_state)
                        USE(states, suspend_state);
                else
                        states = strv_new("mem", "standby", "freeze", NULL);

        } else if (streq(verb, "hibernate")) {
                if (hibernate_mode)
                        USE(modes, hibernate_mode);
                else
                        modes = strv_new("platform", "shutdown", NULL);

                if (hibernate_state)
                        USE(states, hibernate_state);
                else
                        states = strv_new("disk", NULL);

        } else if (streq(verb, "hybrid-sleep")) {
                if (hybrid_mode)
                        USE(modes, hybrid_mode);
                else
                        modes = strv_new("suspend", "platform", "shutdown", NULL);

                if (hybrid_state)
                        USE(states, hybrid_state);
                else
                        states = strv_new("disk", NULL);

        } else
                assert_not_reached("what verb");

        if ((!modes && !streq(verb, "suspend")) || !states) {
                strv_free(modes);
                strv_free(states);
                return log_oom();
        }

        *_modes = modes;
        *_states = states;
        return 0;
}
Exemple #19
0
static int verify_esp(const char *p, uint32_t *part, uint64_t *pstart, uint64_t *psize, sd_id128_t *uuid) {
        struct statfs sfs;
        struct stat st, st2;
        _cleanup_free_ char *t = NULL;
        _cleanup_blkid_free_probe_ blkid_probe b = NULL;
        int r;
        const char *v, *t2;

        if (statfs(p, &sfs) < 0)
                return log_error_errno(errno, "Failed to check file system type of \"%s\": %m", p);

        if (sfs.f_type != 0x4d44) {
                log_error("File system \"%s\" is not a FAT EFI System Partition (ESP) file system.", p);
                return -ENODEV;
        }

        if (stat(p, &st) < 0)
                return log_error_errno(errno, "Failed to determine block device node of \"%s\": %m", p);

        if (major(st.st_dev) == 0) {
                log_error("Block device node of %p is invalid.", p);
                return -ENODEV;
        }

        t2 = strjoina(p, "/..");
        r = stat(t2, &st2);
        if (r < 0)
                return log_error_errno(errno, "Failed to determine block device node of parent of \"%s\": %m", p);

        if (st.st_dev == st2.st_dev) {
                log_error("Directory \"%s\" is not the root of the EFI System Partition (ESP) file system.", p);
                return -ENODEV;
        }

        r = asprintf(&t, "/dev/block/%u:%u", major(st.st_dev), minor(st.st_dev));
        if (r < 0)
                return log_oom();

        errno = 0;
        b = blkid_new_probe_from_filename(t);
        if (!b) {
                if (errno == 0)
                        return log_oom();

                return log_error_errno(errno, "Failed to open file system \"%s\": %m", p);
        }

        blkid_probe_enable_superblocks(b, 1);
        blkid_probe_set_superblocks_flags(b, BLKID_SUBLKS_TYPE);
        blkid_probe_enable_partitions(b, 1);
        blkid_probe_set_partitions_flags(b, BLKID_PARTS_ENTRY_DETAILS);

        errno = 0;
        r = blkid_do_safeprobe(b);
        if (r == -2) {
                log_error("File system \"%s\" is ambigious.", p);
                return -ENODEV;
        } else if (r == 1) {
                log_error("File system \"%s\" does not contain a label.", p);
                return -ENODEV;
        } else if (r != 0) {
                r = errno ? -errno : -EIO;
                return log_error_errno(r, "Failed to probe file system \"%s\": %m", p);
        }

        errno = 0;
        r = blkid_probe_lookup_value(b, "TYPE", &v, NULL);
        if (r != 0) {
                r = errno ? -errno : -EIO;
                return log_error_errno(r, "Failed to probe file system type \"%s\": %m", p);
        }

        if (!streq(v, "vfat")) {
                log_error("File system \"%s\" is not FAT.", p);
                return -ENODEV;
        }

        errno = 0;
        r = blkid_probe_lookup_value(b, "PART_ENTRY_SCHEME", &v, NULL);
        if (r != 0) {
                r = errno ? -errno : -EIO;
                return log_error_errno(r, "Failed to probe partition scheme \"%s\": %m", p);
        }

        if (!streq(v, "gpt")) {
                log_error("File system \"%s\" is not on a GPT partition table.", p);
                return -ENODEV;
        }

        errno = 0;
        r = blkid_probe_lookup_value(b, "PART_ENTRY_TYPE", &v, NULL);
        if (r != 0) {
                r = errno ? -errno : -EIO;
                return log_error_errno(r, "Failed to probe partition type UUID \"%s\": %m", p);
        }

        if (!streq(v, "c12a7328-f81f-11d2-ba4b-00a0c93ec93b")) {
                log_error("File system \"%s\" has wrong type for an EFI System Partition (ESP).", p);
                return -ENODEV;
        }

        errno = 0;
        r = blkid_probe_lookup_value(b, "PART_ENTRY_UUID", &v, NULL);
        if (r != 0) {
                r = errno ? -errno : -EIO;
                return log_error_errno(r, "Failed to probe partition entry UUID \"%s\": %m", p);
        }

        r = sd_id128_from_string(v, uuid);
        if (r < 0) {
                log_error("Partition \"%s\" has invalid UUID \"%s\".", p, v);
                return -EIO;
        }

        errno = 0;
        r = blkid_probe_lookup_value(b, "PART_ENTRY_NUMBER", &v, NULL);
        if (r != 0) {
                r = errno ? -errno : -EIO;
                return log_error_errno(r, "Failed to probe partition number \"%s\": m", p);
        }
        *part = strtoul(v, NULL, 10);

        errno = 0;
        r = blkid_probe_lookup_value(b, "PART_ENTRY_OFFSET", &v, NULL);
        if (r != 0) {
                r = errno ? -errno : -EIO;
                return log_error_errno(r, "Failed to probe partition offset \"%s\": %m", p);
        }
        *pstart = strtoul(v, NULL, 10);

        errno = 0;
        r = blkid_probe_lookup_value(b, "PART_ENTRY_SIZE", &v, NULL);
        if (r != 0) {
                r = errno ? -errno : -EIO;
                return log_error_errno(r, "Failed to probe partition size \"%s\": %m", p);
        }
        *psize = strtoul(v, NULL, 10);

        return 0;
}
Exemple #20
0
static int parse_argv(int argc, char *argv[]) {

        enum {
                ARG_VERSION = 0x100,
                ARG_USER,
                ARG_SYSTEM,
                ARG_SCOPE,
                ARG_UNIT,
                ARG_DESCRIPTION,
                ARG_SLICE,
                ARG_SEND_SIGHUP,
                ARG_EXEC_USER,
                ARG_EXEC_GROUP,
                ARG_SERVICE_TYPE,
                ARG_NICE,
                ARG_SETENV
        };

        static const struct option options[] = {
                { "help",              no_argument,       NULL, 'h'              },
                { "version",           no_argument,       NULL, ARG_VERSION      },
                { "user",              no_argument,       NULL, ARG_USER         },
                { "system",            no_argument,       NULL, ARG_SYSTEM       },
                { "scope",             no_argument,       NULL, ARG_SCOPE        },
                { "unit",              required_argument, NULL, ARG_UNIT         },
                { "description",       required_argument, NULL, ARG_DESCRIPTION  },
                { "slice",             required_argument, NULL, ARG_SLICE        },
                { "remain-after-exit", no_argument,       NULL, 'r'              },
                { "send-sighup",       no_argument,       NULL, ARG_SEND_SIGHUP  },
                { "host",              required_argument, NULL, 'H'              },
                { "machine",           required_argument, NULL, 'M'              },
                { "service-type",      required_argument, NULL, ARG_SERVICE_TYPE },
                { "uid",               required_argument, NULL, ARG_EXEC_USER    },
                { "gid",               required_argument, NULL, ARG_EXEC_GROUP   },
                { "nice",              required_argument, NULL, ARG_NICE         },
                { "setenv",            required_argument, NULL, ARG_SETENV       },
                { "property",          required_argument, NULL, 'p'              },
                {},
        };

        int r, c;

        assert(argc >= 0);
        assert(argv);

        while ((c = getopt_long(argc, argv, "+hrH:M:p:", options, NULL)) >= 0) {

                switch (c) {

                case 'h':
                        return help();

                case ARG_VERSION:
                        puts(PACKAGE_STRING);
                        puts(SYSTEMD_FEATURES);
                        return 0;

                case ARG_USER:
                        arg_user = true;
                        break;

                case ARG_SYSTEM:
                        arg_user = false;
                        break;

                case ARG_SCOPE:
                        arg_scope = true;
                        break;

                case ARG_UNIT:
                        arg_unit = optarg;
                        break;

                case ARG_DESCRIPTION:
                        arg_description = optarg;
                        break;

                case ARG_SLICE:
                        arg_slice = optarg;
                        break;

                case ARG_SEND_SIGHUP:
                        arg_send_sighup = true;
                        break;

                case 'r':
                        arg_remain_after_exit = true;
                        break;

                case 'H':
                        arg_transport = BUS_TRANSPORT_REMOTE;
                        arg_host = optarg;
                        break;

                case 'M':
                        arg_transport = BUS_TRANSPORT_CONTAINER;
                        arg_host = optarg;
                        break;

                case ARG_SERVICE_TYPE:
                        arg_service_type = optarg;
                        break;

                case ARG_EXEC_USER:
                        arg_exec_user = optarg;
                        break;

                case ARG_EXEC_GROUP:
                        arg_exec_group = optarg;
                        break;

                case ARG_NICE:
                        r = safe_atoi(optarg, &arg_nice);
                        if (r < 0 || arg_nice < PRIO_MIN || arg_nice >= PRIO_MAX) {
                                log_error("Failed to parse nice value");
                                return -EINVAL;
                        }

                        arg_nice_set = true;
                        break;

                case ARG_SETENV:

                        if (strv_extend(&arg_environment, optarg) < 0)
                                return log_oom();

                        break;

                case 'p':

                        if (strv_extend(&arg_property, optarg) < 0)
                                return log_oom();

                        break;

                case '?':
                        return -EINVAL;

                default:
                        assert_not_reached("Unhandled option");
                }
        }

        if (optind >= argc) {
                log_error("Command line to execute required.");
                return -EINVAL;
        }

        if (arg_user && arg_transport != BUS_TRANSPORT_LOCAL) {
                log_error("Execution in user context is not supported on non-local systems.");
                return -EINVAL;
        }

        if (arg_scope && arg_transport != BUS_TRANSPORT_LOCAL) {
                log_error("Scope execution is not supported on non-local systems.");
                return -EINVAL;
        }

        if (arg_scope && (arg_remain_after_exit || arg_service_type)) {
                log_error("--remain-after-exit and --service-type= are not supported in --scope mode.");
                return -EINVAL;
        }

        return 1;
}
Exemple #21
0
int mount_cgroup_controllers(char ***join_controllers) {
        _cleanup_set_free_free_ Set *controllers = NULL;
        int r;

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

        controllers = set_new(&string_hash_ops);
        if (!controllers)
                return log_oom();

        r = cg_kernel_controllers(controllers);
        if (r < 0)
                return log_error_errno(r, "Failed to enumerate cgroup controllers: %m");

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

                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)) {
                                        _cleanup_free_ char *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;
                }

                where = strappend("/sys/fs/cgroup/", options);
                if (!where)
                        return log_oom();

                p.where = where;
                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++) {
                                _cleanup_free_ char *t = NULL;

                                t = strappend("/sys/fs/cgroup/", *i);
                                if (!t)
                                        return log_oom();

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

        /* Now that we mounted everything, let's make the tmpfs the
         * cgroup file systems are mounted into read-only. */
        (void) mount("tmpfs", "/sys/fs/cgroup", "tmpfs", MS_REMOUNT|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_STRICTATIME|MS_RDONLY, "mode=755");

        return 0;
}

#if defined(HAVE_SELINUX) || defined(HAVE_SMACK)
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;
};
#endif

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

        for (i = 0; i < ELEMENTSOF(mount_table); i ++) {
                int j;

                j = mount_one(mount_table + i, loaded_policy);
                if (r == 0)
                        r = j;
        }

        if (r < 0)
                return r;

#if defined(HAVE_SELINUX) || defined(HAVE_SMACK)
        /* 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));
        }
#endif

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

        /* 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_errno(errno, "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;
}
Exemple #22
0
static int parse_argv(int argc, char *argv[]) {

        enum {
                ARG_VERSION = 0x100,
                ARG_ADDRESS,
                ARG_CONFIGURATION,
                ARG_MACHINE,
        };

        static const struct option options[] = {
                { "help",            no_argument,       NULL, 'h'                 },
                { "version",         no_argument,       NULL, ARG_VERSION         },
                { "address",         required_argument, NULL, ARG_ADDRESS         },
                { "configuration",   required_argument, NULL, ARG_CONFIGURATION   },
                { "machine",         required_argument, NULL, ARG_MACHINE         },
                {},
        };

        int c, r;

        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_ADDRESS:
                        r = free_and_strdup(&arg_address, optarg);
                        if (r < 0)
                                return log_oom();
                        break;

                case ARG_CONFIGURATION:
                        r = strv_extend(&arg_configuration, optarg);
                        if (r < 0)
                                return log_oom();
                        break;

                case ARG_MACHINE: {
                        _cleanup_free_ char *e = NULL;
                        char *a;

                        e = bus_address_escape(optarg);
                        if (!e)
                                return log_oom();

                        a = strjoin("x-machine-kernel:machine=", e, ";x-machine-unix:machine=", e, NULL);
                        if (!a)
                                return log_oom();

                        free(arg_address);
                        arg_address = a;

                        break;
                }

                case '?':
                        return -EINVAL;

                default:
                        assert_not_reached("Unhandled option");
                }

        if (argc > optind) {
                log_error("Too many arguments");
                return -EINVAL;
        }

        if (!arg_address) {
                arg_address = strdup(DEFAULT_SYSTEM_BUS_ADDRESS);
                if (!arg_address)
                        return log_oom();
        }

        return 1;
}
Exemple #23
0
int main(int argc, char *argv[]) {
        struct udev *udev = NULL;
        struct udev_device *device = NULL;
        _cleanup_free_ char *saved = NULL;
        int r;

        if (argc != 3) {
                log_error("This program requires two arguments.");
                return EXIT_FAILURE;
        }

        log_set_target(LOG_TARGET_AUTO);
        log_parse_environment();
        log_open();

        umask(0022);

        r = mkdir_p("/var/lib/backlight", 0755);
        if (r < 0) {
                log_error("Failed to create backlight directory: %s", strerror(-r));
                goto finish;
        }

        udev = udev_new();
        if (!udev) {
                r = log_oom();
                goto finish;
        }

        errno = 0;
        device = udev_device_new_from_subsystem_sysname(udev, "backlight", argv[2]);
        if (!device) {
                if (errno != 0) {
                        log_error("Failed to get backlight device: %m");
                        r = -errno;
                } else
                        r = log_oom();

                goto finish;
        }

        if (!streq_ptr(udev_device_get_subsystem(device), "backlight")) {
                log_error("Not a backlight device: %s", argv[2]);
                r = -ENODEV;
                goto finish;
        }

        saved = strappend("/var/lib/backlight/", udev_device_get_sysname(device));
        if (!saved) {
                r = log_oom();
                goto finish;
        }

        if (streq(argv[1], "load")) {
                _cleanup_free_ char *value = NULL;

                r = read_one_line_file(saved, &value);
                if (r < 0) {

                        if (r == -ENOENT) {
                                r = 0;
                                goto finish;
                        }

                        log_error("Failed to read %s: %s", saved, strerror(-r));
                        goto finish;
                }

                r = udev_device_set_sysattr_value(device, "brightness", value);
                if (r < 0) {
                        log_error("Failed to write system attribute: %s", strerror(-r));
                        goto finish;
                }

        } else if (streq(argv[1], "save")) {
                const char *value;

                value = udev_device_get_sysattr_value(device, "brightness");
                if (!value) {
                        log_error("Failed to read system attribute: %s", strerror(-r));
                        goto finish;
                }

                r = write_string_file(saved, value);
                if (r < 0) {
                        log_error("Failed to write %s: %s", saved, strerror(-r));
                        goto finish;
                }

        } else {
                log_error("Unknown verb %s.", argv[1]);
                r = -EINVAL;
                goto finish;
        }

finish:
        if (device)
                udev_device_unref(device);

        if (udev)
                udev_unref(udev);

        return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;

}
Exemple #24
0
static int pull_tar(int argc, char *argv[], void *userdata) {
        _cleanup_(tar_pull_unrefp) TarPull *pull = NULL;
        _cleanup_event_unref_ sd_event *event = NULL;
        const char *url, *local;
        _cleanup_free_ char *l = NULL, *ll = NULL;
        int r;

        url = argv[1];
        if (!http_url_is_valid(url)) {
                log_error("URL '%s' is not valid.", url);
                return -EINVAL;
        }

        if (argc >= 3)
                local = argv[2];
        else {
                r = import_url_last_component(url, &l);
                if (r < 0)
                        return log_error_errno(r, "Failed get final component of URL: %m");

                local = l;
        }

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

        if (local) {
                r = tar_strip_suffixes(local, &ll);
                if (r < 0)
                        return log_oom();

                local = ll;

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

                if (!arg_force) {
                        r = image_find(local, NULL);
                        if (r < 0)
                                return log_error_errno(r, "Failed to check whether image '%s' exists: %m", local);
                        else if (r > 0) {
                                log_error_errno(EEXIST, "Image '%s' already exists.", local);
                                return -EEXIST;
                        }
                }

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

        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, NULL, SIGTERM, SIGINT, -1) >= 0);
        (void) sd_event_add_signal(event, NULL, SIGTERM, interrupt_signal_handler,  NULL);
        (void) sd_event_add_signal(event, NULL, SIGINT, interrupt_signal_handler, NULL);

        r = tar_pull_new(&pull, event, arg_image_root, on_tar_finished, event);
        if (r < 0)
                return log_error_errno(r, "Failed to allocate puller: %m");

        r = tar_pull_start(pull, url, local, arg_force, arg_verify, arg_settings);
        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 -r;
}
Exemple #25
0
static int add_automount(
                const char *id,
                const char *what,
                const char *where,
                const char *fstype,
                bool rw,
                const char *options,
                const char *description,
                usec_t timeout) {

        _cleanup_free_ char *unit = NULL, *lnk = NULL;
        _cleanup_free_ char *opt, *p = NULL;
        _cleanup_fclose_ FILE *f = NULL;
        int r;

        assert(id);
        assert(where);
        assert(description);

        if (options)
                opt = strjoin(options, ",noauto", NULL);
        else
                opt = strdup("noauto");
        if (!opt)
                return log_oom();

        r = add_mount(id,
                      what,
                      where,
                      fstype,
                      rw,
                      opt,
                      description,
                      NULL);
        if (r < 0)
                return r;

        r = unit_name_from_path(where, ".automount", &unit);
        if (r < 0)
                return log_error_errno(r, "Failed to generate unit name: %m");

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

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

        fprintf(f,
                "# Automatically generated by systemd-gpt-auto-generator\n\n"
                "[Unit]\n"
                "Description=%s\n"
                "Documentation=man:systemd-gpt-auto-generator(8)\n"
                "[Automount]\n"
                "Where=%s\n"
                "TimeoutIdleSec=%lld\n",
                description,
                where,
                (unsigned long long)timeout / USEC_PER_SEC);

        r = fflush_and_check(f);
        if (r < 0)
                return log_error_errno(r, "Failed to write unit file %s: %m", p);

        lnk = strjoin(arg_dest, "/" SPECIAL_LOCAL_FS_TARGET ".wants/", unit, NULL);
        if (!lnk)
                return log_oom();
        mkdir_parents_label(lnk, 0755);

        if (symlink(p, lnk) < 0)
                return log_error_errno(errno, "Failed to create symlink %s: %m", lnk);

        return 0;
}
Exemple #26
0
static int import_tar(int argc, char *argv[], void *userdata) {
        _cleanup_(tar_import_unrefp) TarImport *import = NULL;
        _cleanup_event_unref_ sd_event *event = NULL;
        const char *path = NULL, *local = NULL;
        _cleanup_free_ char *ll = NULL;
        _cleanup_close_ int open_fd = -1;
        int r, fd;

        if (argc >= 2)
                path = argv[1];
        if (isempty(path) || streq(path, "-"))
                path = NULL;

        if (argc >= 3)
                local = argv[2];
        else if (path)
                local = basename(path);
        if (isempty(local) || streq(local, "-"))
                local = NULL;

        if (local) {
                r = tar_strip_suffixes(local, &ll);
                if (r < 0)
                        return log_oom();

                local = ll;

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

                if (!arg_force) {
                        r = image_find(local, NULL);
                        if (r < 0)
                                return log_error_errno(r, "Failed to check whether image '%s' exists: %m", local);
                        else if (r > 0) {
                                log_error_errno(EEXIST, "Image '%s' already exists.", local);
                                return -EEXIST;
                        }
                }
        } else
                local = "imported";

        if (path) {
                open_fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY);
                if (open_fd < 0)
                        return log_error_errno(errno, "Failed to open tar image to import: %m");

                fd = open_fd;

                log_info("Importing '%s', saving as '%s'.", path, local);
        } else {
                _cleanup_free_ char *pretty = NULL;

                fd = STDIN_FILENO;

                (void) readlink_malloc("/proc/self/fd/0", &pretty);
                log_info("Importing '%s', saving as '%s'.", strna(pretty), local);
        }

        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, interrupt_signal_handler,  NULL);
        sd_event_add_signal(event, NULL, SIGINT, interrupt_signal_handler, NULL);

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

        r = tar_import_start(import, fd, local, arg_force, arg_read_only);
        if (r < 0)
                return log_error_errno(r, "Failed to import 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 -r;
}
Exemple #27
0
static int enumerate_partitions(dev_t devnum) {

        _cleanup_udev_enumerate_unref_ struct udev_enumerate *e = NULL;
        _cleanup_udev_device_unref_ struct udev_device *d = NULL;
        _cleanup_blkid_free_probe_ blkid_probe b = NULL;
        _cleanup_udev_unref_ struct udev *udev = NULL;
        _cleanup_free_ char *boot = NULL, *home = NULL, *srv = NULL;
        struct udev_list_entry *first, *item;
        struct udev_device *parent = NULL;
        const char *name, *node, *pttype, *devtype;
        int boot_nr = -1, home_nr = -1, srv_nr = -1;
        bool home_rw = true, srv_rw = true;
        blkid_partlist pl;
        int r, k;
        dev_t pn;

        udev = udev_new();
        if (!udev)
                return log_oom();

        d = udev_device_new_from_devnum(udev, 'b', devnum);
        if (!d)
                return log_oom();

        name = udev_device_get_devnode(d);
        if (!name)
                name = udev_device_get_syspath(d);
        if (!name) {
                log_debug("Device %u:%u does not have a name, ignoring.",
                          major(devnum), minor(devnum));
                return 0;
        }

        parent = udev_device_get_parent(d);
        if (!parent) {
                log_debug("%s: not a partitioned device, ignoring.", name);
                return 0;
        }

        /* Does it have a devtype? */
        devtype = udev_device_get_devtype(parent);
        if (!devtype) {
                log_debug("%s: parent doesn't have a device type, ignoring.", name);
                return 0;
        }

        /* Is this a disk or a partition? We only care for disks... */
        if (!streq(devtype, "disk")) {
                log_debug("%s: parent isn't a raw disk, ignoring.", name);
                return 0;
        }

        /* Does it have a device node? */
        node = udev_device_get_devnode(parent);
        if (!node) {
                log_debug("%s: parent device does not have device node, ignoring.", name);
                return 0;
        }

        log_debug("%s: root device %s.", name, node);

        pn = udev_device_get_devnum(parent);
        if (major(pn) == 0)
                return 0;

        errno = 0;
        b = blkid_new_probe_from_filename(node);
        if (!b) {
                if (errno == 0)
                        return log_oom();

                return log_error_errno(errno, "%s: failed to allocate prober: %m", node);
        }

        blkid_probe_enable_partitions(b, 1);
        blkid_probe_set_partitions_flags(b, BLKID_PARTS_ENTRY_DETAILS);

        errno = 0;
        r = blkid_do_safeprobe(b);
        if (r == 1)
                return 0; /* no results */
        else if (r == -2) {
                log_warning("%s: probe gave ambiguous results, ignoring.", node);
                return 0;
        } else if (r != 0)
                return log_error_errno(errno ?: EIO, "%s: failed to probe: %m", node);

        errno = 0;
        r = blkid_probe_lookup_value(b, "PTTYPE", &pttype, NULL);
        if (r != 0) {
                if (errno == 0)
                        return 0; /* No partition table found. */

                return log_error_errno(errno, "%s: failed to determine partition table type: %m", node);
        }

        /* We only do this all for GPT... */
        if (!streq_ptr(pttype, "gpt")) {
                log_debug("%s: not a GPT partition table, ignoring.", node);
                return 0;
        }

        errno = 0;
        pl = blkid_probe_get_partitions(b);
        if (!pl) {
                if (errno == 0)
                        return log_oom();

                return log_error_errno(errno, "%s: failed to list partitions: %m", node);
        }

        e = udev_enumerate_new(udev);
        if (!e)
                return log_oom();

        r = udev_enumerate_add_match_parent(e, parent);
        if (r < 0)
                return log_oom();

        r = udev_enumerate_add_match_subsystem(e, "block");
        if (r < 0)
                return log_oom();

        r = udev_enumerate_scan_devices(e);
        if (r < 0)
                return log_error_errno(r, "%s: failed to enumerate partitions: %m", node);

        first = udev_enumerate_get_list_entry(e);
        udev_list_entry_foreach(item, first) {
                _cleanup_udev_device_unref_ struct udev_device *q;
                unsigned long long flags;
                const char *stype, *subnode;
                sd_id128_t type_id;
                blkid_partition pp;
                dev_t qn;
                int nr;

                q = udev_device_new_from_syspath(udev, udev_list_entry_get_name(item));
                if (!q)
                        continue;

                qn = udev_device_get_devnum(q);
                if (major(qn) == 0)
                        continue;

                if (qn == devnum)
                        continue;

                if (qn == pn)
                        continue;

                subnode = udev_device_get_devnode(q);
                if (!subnode)
                        continue;

                pp = blkid_partlist_devno_to_partition(pl, qn);
                if (!pp)
                        continue;

                nr = blkid_partition_get_partno(pp);
                if (nr < 0)
                        continue;

                stype = blkid_partition_get_type_string(pp);
                if (!stype)
                        continue;

                if (sd_id128_from_string(stype, &type_id) < 0)
                        continue;

                flags = blkid_partition_get_flags(pp);

                if (sd_id128_equal(type_id, GPT_SWAP)) {

                        if (flags & GPT_FLAG_NO_AUTO)
                                continue;

                        if (flags & GPT_FLAG_READ_ONLY) {
                                log_debug("%s marked as read-only swap partition, which is bogus. Ignoring.", subnode);
                                continue;
                        }

                        k = add_swap(subnode);
                        if (k < 0)
                                r = k;

                } else if (sd_id128_equal(type_id, GPT_ESP)) {

                        /* We only care for the first /boot partition */
                        if (boot && nr >= boot_nr)
                                continue;

                        /* Note that we do not honour the "no-auto"
                         * flag for the ESP, as it is often unset, to
                         * hide it from Windows. */

                        boot_nr = nr;

                        r = free_and_strdup(&boot, subnode);
                        if (r < 0)
                                return log_oom();

                } else if (sd_id128_equal(type_id, GPT_HOME)) {

                        if (flags & GPT_FLAG_NO_AUTO)
                                continue;

                        /* We only care for the first /home partition */
                        if (home && nr >= home_nr)
                                continue;

                        home_nr = nr;
                        home_rw = !(flags & GPT_FLAG_READ_ONLY),

                        r = free_and_strdup(&home, subnode);
                        if (r < 0)
                                return log_oom();

                } else if (sd_id128_equal(type_id, GPT_SRV)) {

                        if (flags & GPT_FLAG_NO_AUTO)
                                continue;

                        /* We only care for the first /srv partition */
                        if (srv && nr >= srv_nr)
                                continue;

                        srv_nr = nr;
                        srv_rw = !(flags & GPT_FLAG_READ_ONLY),

                        r = free_and_strdup(&srv, subnode);
                        if (r < 0)
                                return log_oom();
                }
        }
Exemple #28
0
static int list_x11_keymaps(int argc, char **argv, void *userdata) {
        _cleanup_fclose_ FILE *f = NULL;
        _cleanup_strv_free_ char **list = NULL;
        char line[LINE_MAX];
        enum {
                NONE,
                MODELS,
                LAYOUTS,
                VARIANTS,
                OPTIONS
        } state = NONE, look_for;
        int r;

        f = fopen("/usr/share/X11/xkb/rules/base.lst", "re");
        if (!f)
                return log_error_errno(errno, "Failed to open keyboard mapping list. %m");

        if (streq(argv[0], "list-x11-keymap-models"))
                look_for = MODELS;
        else if (streq(argv[0], "list-x11-keymap-layouts"))
                look_for = LAYOUTS;
        else if (streq(argv[0], "list-x11-keymap-variants"))
                look_for = VARIANTS;
        else if (streq(argv[0], "list-x11-keymap-options"))
                look_for = OPTIONS;
        else
                assert_not_reached("Wrong parameter");

        FOREACH_LINE(line, f, break) {
                char *l, *w;

                l = strstrip(line);

                if (isempty(l))
                        continue;

                if (l[0] == '!') {
                        if (startswith(l, "! model"))
                                state = MODELS;
                        else if (startswith(l, "! layout"))
                                state = LAYOUTS;
                        else if (startswith(l, "! variant"))
                                state = VARIANTS;
                        else if (startswith(l, "! option"))
                                state = OPTIONS;
                        else
                                state = NONE;

                        continue;
                }

                if (state != look_for)
                        continue;

                w = l + strcspn(l, WHITESPACE);

                if (argc > 1) {
                        char *e;

                        if (*w == 0)
                                continue;

                        *w = 0;
                        w++;
                        w += strspn(w, WHITESPACE);

                        e = strchr(w, ':');
                        if (!e)
                                continue;

                        *e = 0;

                        if (!streq(w, argv[1]))
                                continue;
                } else
                        *w = 0;

                r = strv_extend(&list, l);
                if (r < 0)
                        return log_oom();
        }

        if (strv_isempty(list)) {
                log_error("Couldn't find any entries.");
                return -ENOENT;
        }

        strv_sort(list);
        strv_uniq(list);

        (void) pager_open(arg_no_pager, false);

        strv_print(list);
        return 0;
}
Exemple #29
0
int main(int argc, char *argv[]) {
        _cleanup_close_ int seed_fd = -1, random_fd = -1;
        _cleanup_free_ void* buf = NULL;
        size_t buf_size = 0;
        ssize_t k;
        int r;
        FILE *f;
        bool refresh_seed_file = true;

        if (argc != 2) {
                log_error("This program requires one argument.");
                return EXIT_FAILURE;
        }

        log_set_target(LOG_TARGET_AUTO);
        log_parse_environment();
        log_open();

        umask(0022);

        /* Read pool size, if possible */
        f = fopen("/proc/sys/kernel/random/poolsize", "re");
        if (f) {
                if (fscanf(f, "%zu", &buf_size) > 0)
                        /* poolsize is in bits on 2.6, but we want bytes */
                        buf_size /= 8;

                fclose(f);
        }

        if (buf_size <= POOL_SIZE_MIN)
                buf_size = POOL_SIZE_MIN;

        buf = malloc(buf_size);
        if (!buf) {
                r = log_oom();
                goto finish;
        }

        r = mkdir_parents_label(RANDOM_SEED, 0755);
        if (r < 0) {
                log_error_errno(r, "Failed to create directory " RANDOM_SEED_DIR ": %m");
                goto finish;
        }

        /* When we load the seed we read it and write it to the device
         * and then immediately update the saved seed with new data,
         * to make sure the next boot gets seeded differently. */

        if (streq(argv[1], "load")) {

                seed_fd = open(RANDOM_SEED, O_RDWR|O_CLOEXEC|O_NOCTTY|O_CREAT, 0600);
                if (seed_fd < 0) {
                        seed_fd = open(RANDOM_SEED, O_RDONLY|O_CLOEXEC|O_NOCTTY);
                        if (seed_fd < 0) {
                                r = log_error_errno(errno, "Failed to open " RANDOM_SEED ": %m");
                                goto finish;
                        }

                        refresh_seed_file = false;
                }

                random_fd = open("/dev/urandom", O_RDWR|O_CLOEXEC|O_NOCTTY, 0600);
                if (random_fd < 0) {
                        random_fd = open("/dev/urandom", O_WRONLY|O_CLOEXEC|O_NOCTTY, 0600);
                        if (random_fd < 0) {
                                r = log_error_errno(errno, "Failed to open /dev/urandom: %m");
                                goto finish;
                        }
                }

                k = loop_read(seed_fd, buf, buf_size, false);
                if (k < 0)
                        r = log_error_errno(k, "Failed to read seed from " RANDOM_SEED ": %m");
                else if (k == 0)
                        log_debug("Seed file " RANDOM_SEED " not yet initialized, proceeding.");
                else {
                        (void) lseek(seed_fd, 0, SEEK_SET);

                        r = loop_write(random_fd, buf, (size_t) k, false);
                        if (r < 0)
                                log_error_errno(r, "Failed to write seed to /dev/urandom: %m");
                }

        } else if (streq(argv[1], "save")) {

                seed_fd = open(RANDOM_SEED, O_WRONLY|O_CLOEXEC|O_NOCTTY|O_CREAT, 0600);
                if (seed_fd < 0) {
                        r = log_error_errno(errno, "Failed to open " RANDOM_SEED ": %m");
                        goto finish;
                }

                random_fd = open("/dev/urandom", O_RDONLY|O_CLOEXEC|O_NOCTTY);
                if (random_fd < 0) {
                        r = log_error_errno(errno, "Failed to open /dev/urandom: %m");
                        goto finish;
                }

        } else {
                log_error("Unknown verb '%s'.", argv[1]);
                r = -EINVAL;
                goto finish;
        }

        if (refresh_seed_file) {

                /* This is just a safety measure. Given that we are root and
                 * most likely created the file ourselves the mode and owner
                 * should be correct anyway. */
                (void) fchmod(seed_fd, 0600);
                (void) fchown(seed_fd, 0, 0);

                k = loop_read(random_fd, buf, buf_size, false);
                if (k < 0) {
                        r = log_error_errno(k, "Failed to read new seed from /dev/urandom: %m");
                        goto finish;
                }
                if (k == 0) {
                        log_error("Got EOF while reading from /dev/urandom.");
                        r = -EIO;
                        goto finish;
                }

                r = loop_write(seed_fd, buf, (size_t) k, false);
                if (r < 0)
                        log_error_errno(r, "Failed to write new random seed file: %m");
        }

finish:
        return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}
Exemple #30
0
static int list_images(int argc, char *argv[], void *userdata) {
        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
        _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
        _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
        _cleanup_(table_unrefp) Table *table = NULL;
        int r;

        r = acquire_bus(&bus);
        if (r < 0)
                return r;

        r = sd_bus_call_method(
                        bus,
                        "org.freedesktop.portable1",
                        "/org/freedesktop/portable1",
                        "org.freedesktop.portable1.Manager",
                        "ListImages",
                        &error,
                        &reply,
                        NULL);
        if (r < 0)
                return log_error_errno(r, "Failed to list images: %s", bus_error_message(&error, r));

        table = table_new("name", "type", "ro", "crtime", "mtime", "usage", "state");
        if (!table)
                return log_oom();

        r = sd_bus_message_enter_container(reply, 'a', "(ssbtttso)");
        if (r < 0)
                return bus_log_parse_error(r);

        for (;;) {
                const char *name, *type, *state;
                uint64_t crtime, mtime, usage;
                TableCell *cell;
                bool ro_bool;
                int ro_int;

                r = sd_bus_message_read(reply, "(ssbtttso)", &name, &type, &ro_int, &crtime, &mtime, &usage, &state, NULL);
                if (r < 0)
                        return bus_log_parse_error(r);
                if (r == 0)
                        break;

                r = table_add_many(table,
                                   TABLE_STRING, name,
                                   TABLE_STRING, type);
                if (r < 0)
                        return log_error_errno(r, "Failed to add row to table: %m");

                ro_bool = ro_int;
                r = table_add_cell(table, &cell, TABLE_BOOLEAN, &ro_bool);
                if (r < 0)
                        return log_error_errno(r, "Failed to add row to table: %m");

                if (ro_bool) {
                        r = table_set_color(table, cell, ansi_highlight_red());
                        if (r < 0)
                                return log_error_errno(r, "Failed to set table cell color: %m");
                }

                r = table_add_many(table,
                                   TABLE_TIMESTAMP, crtime,
                                   TABLE_TIMESTAMP, mtime,
                                   TABLE_SIZE, usage);
                if (r < 0)
                        return log_error_errno(r, "Failed to add row to table: %m");

                r = table_add_cell(table, &cell, TABLE_STRING, state);
                if (r < 0)
                        return log_error_errno(r, "Failed to add row to table: %m");

                if (!streq(state, "detached")) {
                        r = table_set_color(table, cell, ansi_highlight_green());
                        if (r < 0)
                                return log_error_errno(r, "Failed to set table cell color: %m");
                }
        }

        r = sd_bus_message_exit_container(reply);
        if (r < 0)
                return bus_log_parse_error(r);

        if (table_get_rows(table) > 1) {
                r = table_set_sort(table, (size_t) 0, (size_t) -1);
                if (r < 0)
                        return log_error_errno(r, "Failed to sort table: %m");

                table_set_header(table, arg_legend);

                r = table_print(table, NULL);
                if (r < 0)
                        return log_error_errno(r, "Failed to show table: %m");
        }

        if (arg_legend) {
                if (table_get_rows(table) > 1)
                        printf("\n%zu images listed.\n", table_get_rows(table) - 1);
                else
                        printf("No images.\n");
        }

        return 0;
}