Beispiel #1
0
int write_env_file(const char *fname, char **l) {
        _cleanup_fclose_ FILE *f = NULL;
        _cleanup_free_ char *p = NULL;
        char **i;
        int r;

        assert(fname);

        r = fopen_temporary(fname, &f, &p);
        if (r < 0)
                return r;

        fchmod_umask(fileno(f), 0644);

        STRV_FOREACH(i, l)
                write_env_var(f, *i);

        r = fflush_and_check(f);
        if (r >= 0) {
                if (rename(p, fname) >= 0)
                        return 0;

                r = -errno;
        }

        unlink(p);
        return r;
}
Beispiel #2
0
static int write_resolv_conf_contents(FILE *f, OrderedSet *dns, OrderedSet *domains) {
        Iterator i;

        fputs_unlocked("# This file is managed by man:systemd-resolved(8). Do not edit.\n#\n"
                       "# This is a dynamic resolv.conf file for connecting local clients directly to\n"
                       "# all known DNS servers.\n#\n"
                       "# Third party programs must not access this file directly, but only through the\n"
                       "# symlink at /etc/resolv.conf. To manage man:resolv.conf(5) in a different way,\n"
                       "# replace this symlink by a static file or a different symlink.\n#\n"
                       "# See man:systemd-resolved.service(8) for details about the supported modes of\n"
                       "# operation for /etc/resolv.conf.\n\n", f);

        if (ordered_set_isempty(dns))
                fputs_unlocked("# No DNS servers known.\n", f);
        else {
                unsigned count = 0;
                DnsServer *s;

                ORDERED_SET_FOREACH(s, dns, i)
                        write_resolv_conf_server(s, f, &count);
        }

        if (!ordered_set_isempty(domains))
                write_resolv_conf_search(domains, f);

        return fflush_and_check(f);
}
Beispiel #3
0
int write_string_stream_ts(
                FILE *f,
                const char *line,
                WriteStringFileFlags flags,
                struct timespec *ts) {

        assert(f);
        assert(line);

        fputs(line, f);
        if (!(flags & WRITE_STRING_FILE_AVOID_NEWLINE) && !endswith(line, "\n"))
                fputc('\n', f);

        if (ts) {
                struct timespec twice[2] = {*ts, *ts};

                if (futimens(fileno(f), twice) < 0)
                        return -errno;
        }

        if (flags & WRITE_STRING_FILE_SYNC)
                return fflush_sync_and_check(f);
        else
                return fflush_and_check(f);
}
Beispiel #4
0
int calendar_spec_to_string(const CalendarSpec *c, char **p) {
        char *buf = NULL;
        size_t sz = 0;
        FILE *f;
        int r;

        assert(c);
        assert(p);

        f = open_memstream(&buf, &sz);
        if (!f)
                return -ENOMEM;

        if (c->weekdays_bits > 0 && c->weekdays_bits <= BITS_WEEKDAYS) {
                format_weekdays(f, c);
                fputc(' ', f);
        }

        format_chain(f, 4, c->year, false);
        fputc('-', f);
        format_chain(f, 2, c->month, false);
        fputc(c->end_of_month ? '~' : '-', f);
        format_chain(f, 2, c->day, false);
        fputc(' ', f);
        format_chain(f, 2, c->hour, false);
        fputc(':', f);
        format_chain(f, 2, c->minute, false);
        fputc(':', f);
        format_chain(f, 2, c->microsecond, true);

        if (c->utc)
                fputs(" UTC", f);
        else if (IN_SET(c->dst, 0, 1)) {

                /* If daylight saving is explicitly on or off, let's show the used timezone. */

                tzset();

                if (!isempty(tzname[c->dst])) {
                        fputc(' ', f);
                        fputs(tzname[c->dst], f);
                }
        }

        r = fflush_and_check(f);
        if (r < 0) {
                free(buf);
                fclose(f);
                return r;
        }

        fclose(f);

        *p = buf;
        return 0;
}
Beispiel #5
0
int write_string_stream(FILE *f, const char *line, bool enforce_newline) {

        assert(f);
        assert(line);

        fputs(line, f);
        if (enforce_newline && !endswith(line, "\n"))
                fputc('\n', f);

        return fflush_and_check(f);
}
Beispiel #6
0
static int write_fsck_sysroot_service(const char *dir, const char *what) {
        _cleanup_free_ char *device = NULL, *escaped = NULL, *escaped2 = NULL;
        _cleanup_fclose_ FILE *f = NULL;
        const char *unit;
        int r;

        escaped = specifier_escape(what);
        if (!escaped)
                return log_oom();

        escaped2 = cescape(escaped);
        if (!escaped2)
                return log_oom();

        unit = strjoina(dir, "/systemd-fsck-root.service");
        log_debug("Creating %s", unit);

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

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

        fprintf(f,
                "# Automatically generated by %1$s\n\n"
                "[Unit]\n"
                "Description=File System Check on %2$s\n"
                "Documentation=man:systemd-fsck-root.service(8)\n"
                "DefaultDependencies=no\n"
                "BindsTo=%3$s\n"
                "After=initrd-root-device.target local-fs-pre.target %3$s\n"
                "Before=shutdown.target\n"
                "\n"
                "[Service]\n"
                "Type=oneshot\n"
                "RemainAfterExit=yes\n"
                "ExecStart=" SYSTEMD_FSCK_PATH " %4$s\n"
                "TimeoutSec=0\n",
                program_invocation_short_name,
                escaped,
                device,
                escaped2);

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

        return 0;
}
Beispiel #7
0
int write_string_stream_ts(
                FILE *f,
                const char *line,
                WriteStringFileFlags flags,
                struct timespec *ts) {

        bool needs_nl;
        int r;

        assert(f);
        assert(line);

        if (ferror(f))
                return -EIO;

        needs_nl = !(flags & WRITE_STRING_FILE_AVOID_NEWLINE) && !endswith(line, "\n");

        if (needs_nl && (flags & WRITE_STRING_FILE_DISABLE_BUFFER)) {
                /* If STDIO buffering was disabled, then let's append the newline character to the string itself, so
                 * that the write goes out in one go, instead of two */

                line = strjoina(line, "\n");
                needs_nl = false;
        }

        if (fputs(line, f) == EOF)
                return -errno;

        if (needs_nl)
                if (fputc('\n', f) == EOF)
                        return -errno;

        if (flags & WRITE_STRING_FILE_SYNC)
                r = fflush_sync_and_check(f);
        else
                r = fflush_and_check(f);
        if (r < 0)
                return r;

        if (ts) {
                struct timespec twice[2] = {*ts, *ts};

                if (futimens(fileno(f), twice) < 0)
                        return -errno;
        }

        return 0;
}
Beispiel #8
0
static int write_root_shadow(const char *path, const struct spwd *p) {
        _cleanup_fclose_ FILE *f = NULL;
        assert(path);
        assert(p);

        RUN_WITH_UMASK(0777)
                f = fopen(path, "wex");
        if (!f)
                return -errno;

        errno = 0;
        if (putspent(p, f) != 0)
                return errno ? -errno : -EIO;

        return fflush_and_check(f);
}
Beispiel #9
0
int calendar_spec_to_string(const CalendarSpec *c, char **p) {
        char *buf = NULL;
        size_t sz = 0;
        FILE *f;
        int r;

        assert(c);
        assert(p);

        f = open_memstream(&buf, &sz);
        if (!f)
                return -ENOMEM;

        if (c->weekdays_bits > 0 && c->weekdays_bits <= BITS_WEEKDAYS) {
                format_weekdays(f, c);
                fputc(' ', f);
        }

        format_chain(f, 4, c->year);
        fputc('-', f);
        format_chain(f, 2, c->month);
        fputc('-', f);
        format_chain(f, 2, c->day);
        fputc(' ', f);
        format_chain(f, 2, c->hour);
        fputc(':', f);
        format_chain(f, 2, c->minute);
        fputc(':', f);
        format_chain(f, 2, c->second);

        if (c->utc)
                fputs(" UTC", f);

        r = fflush_and_check(f);
        if (r < 0) {
                free(buf);
                fclose(f);
                return r;
        }

        fclose(f);

        *p = buf;
        return 0;
}
Beispiel #10
0
static int add_swap(const char *path) {
        _cleanup_free_ char *name = NULL, *unit = NULL, *lnk = NULL;
        _cleanup_fclose_ FILE *f = NULL;
        int r;

        assert(path);

        log_debug("Adding swap: %s", path);

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

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

        f = fopen(unit, "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=Swap Partition\n"
                "Documentation=man:systemd-gpt-auto-generator(8)\n\n"
                "[Swap]\n"
                "What=%s\n",
                path);

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

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

        return 0;
}
static int write_stub_resolv_conf_contents(FILE *f, OrderedSet *dns, OrderedSet *domains) {
        fputs_unlocked("# This file is managed by man:systemd-resolved(8). Do not edit.\n"
                       "#\n"
                       "# This is a dynamic resolv.conf file for connecting local clients to the\n"
                       "# internal DNS stub resolver of systemd-resolved. This file lists all\n"
                       "# configured search domains.\n"
                       "#\n"
                       "# Run \"resolvectl status\" to see details about the uplink DNS servers\n"
                       "# currently in use.\n"
                       "#\n"
                       "# Third party programs must not access this file directly, but only through the\n"
                       "# symlink at /etc/resolv.conf. To manage man:resolv.conf(5) in a different way,\n"
                       "# replace this symlink by a static file or a different symlink.\n"
                       "#\n"
                       "# See man:systemd-resolved.service(8) for details about the supported modes of\n"
                       "# operation for /etc/resolv.conf.\n"
                       "\n"
                       "nameserver 127.0.0.53\n", f);

        if (!ordered_set_isempty(domains))
                write_resolv_conf_search(domains, f);

        return fflush_and_check(f);
}
Beispiel #12
0
static int stdout_stream_save(StdoutStream *s) {
        _cleanup_free_ char *temp_path = NULL;
        _cleanup_fclose_ FILE *f = NULL;
        int r;

        assert(s);

        if (s->state != STDOUT_STREAM_RUNNING)
                return 0;

        if (!s->state_file) {
                struct stat st;

                r = fstat(s->fd, &st);
                if (r < 0)
                        return log_warning_errno(errno, "Failed to stat connected stream: %m");

                /* We use device and inode numbers as identifier for the stream */
                if (asprintf(&s->state_file, "/run/systemd/journal/streams/%lu:%lu", (unsigned long) st.st_dev, (unsigned long) st.st_ino) < 0)
                        return log_oom();
        }

        mkdir_p("/run/systemd/journal/streams", 0755);

        r = fopen_temporary(s->state_file, &f, &temp_path);
        if (r < 0)
                goto fail;

        fprintf(f,
                "# This is private data. Do not parse\n"
                "PRIORITY=%i\n"
                "LEVEL_PREFIX=%i\n"
                "FORWARD_TO_SYSLOG=%i\n"
                "FORWARD_TO_KMSG=%i\n"
                "FORWARD_TO_CONSOLE=%i\n"
                "STREAM_ID=%s\n",
                s->priority,
                s->level_prefix,
                s->forward_to_syslog,
                s->forward_to_kmsg,
                s->forward_to_console,
                s->id_field + strlen("_STREAM_ID="));

        if (!isempty(s->identifier)) {
                _cleanup_free_ char *escaped;

                escaped = cescape(s->identifier);
                if (!escaped) {
                        r = -ENOMEM;
                        goto fail;
                }

                fprintf(f, "IDENTIFIER=%s\n", escaped);
        }

        if (!isempty(s->unit_id)) {
                _cleanup_free_ char *escaped;

                escaped = cescape(s->unit_id);
                if (!escaped) {
                        r = -ENOMEM;
                        goto fail;
                }

                fprintf(f, "UNIT=%s\n", escaped);
        }

        r = fflush_and_check(f);
        if (r < 0)
                goto fail;

        if (rename(temp_path, s->state_file) < 0) {
                r = -errno;
                goto fail;
        }

        if (!s->fdstore && !s->in_notify_queue) {
                LIST_PREPEND(stdout_stream_notify_queue, s->server->stdout_streams_notify_queue, s);
                s->in_notify_queue = true;

                if (s->server->notify_event_source) {
                        r = sd_event_source_set_enabled(s->server->notify_event_source, SD_EVENT_ON);
                        if (r < 0)
                                log_warning_errno(r, "Failed to enable notify event source: %m");
                }
        }

        return 0;

fail:
        (void) unlink(s->state_file);

        if (temp_path)
                (void) unlink(temp_path);

        return log_error_errno(r, "Failed to save stream data %s: %m", s->state_file);
}
Beispiel #13
0
int generator_hook_up_mkfs(
                const char *dir,
                const char *what,
                const char *where,
                const char *type) {

        _cleanup_free_ char *node = NULL, *unit = NULL, *escaped = NULL, *where_unit = NULL;
        _cleanup_fclose_ FILE *f = NULL;
        const char *unit_file;
        int r;

        node = fstab_node_to_udev_node(what);
        if (!node)
                return log_oom();

        /* Nothing to work on. */
        if (!is_device_path(node)) {
                log_error("Cannot format something that is not a device node: %s", node);
                return -EINVAL;
        }

        if (!type || streq(type, "auto")) {
                log_error("Cannot format partition %s, filesystem type is not specified", node);
                return -EINVAL;
        }

        r = unit_name_from_path_instance("systemd-mkfs", node, ".service", &unit);
        if (r < 0)
                return log_error_errno(r, "Failed to make unit instance name from path \"%s\": %m",
                                       node);

        unit_file = strjoina(dir, "/", unit);
        log_debug("Creating %s", unit_file);

        escaped = cescape(node);
        if (!escaped)
                return log_oom();

        r = unit_name_from_path(where, ".mount", &where_unit);
        if (r < 0)
                return log_error_errno(r, "Failed to make unit name from path \"%s\": %m",
                                       where);

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

        fprintf(f,
                "# Automatically generated by %s\n\n"
                "[Unit]\n"
                "Description=Make File System on %%f\n"
                "Documentation=man:[email protected](8)\n"
                "DefaultDependencies=no\n"
                "BindsTo=%%i.device\n"
                "After=%%i.device\n"
                /* fsck might or might not be used, so let's be safe and order
                 * ourselves before both [email protected] and the mount unit. */
                "Before=systemd-fsck@%%i.service\n"
                "Before=%s\n"
                "Before=shutdown.target\n"
                "\n"
                "[Service]\n"
                "Type=oneshot\n"
                "RemainAfterExit=yes\n"
                "ExecStart="SYSTEMD_MAKEFS_PATH " %s %s\n"
                "TimeoutSec=0\n",
                program_invocation_short_name,
                where_unit,
                type,
                escaped);
        // XXX: what about local-fs-pre.target?

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

        return generator_add_symlink(dir, where_unit, "requires", unit);
}
Beispiel #14
0
int generator_hook_up_mkswap(
                const char *dir,
                const char *what) {

        _cleanup_free_ char *node = NULL, *unit = NULL, *escaped = NULL, *where_unit = NULL;
        _cleanup_fclose_ FILE *f = NULL;
        const char *unit_file;
        int r;

        node = fstab_node_to_udev_node(what);
        if (!node)
                return log_oom();

        /* Nothing to work on. */
        if (!is_device_path(node)) {
                log_error("Cannot format something that is not a device node: %s", node);
                return -EINVAL;
        }

        r = unit_name_from_path_instance("systemd-mkswap", node, ".service", &unit);
        if (r < 0)
                return log_error_errno(r, "Failed to make unit instance name from path \"%s\": %m",
                                       node);

        unit_file = strjoina(dir, "/", unit);
        log_debug("Creating %s", unit_file);

        escaped = cescape(node);
        if (!escaped)
                return log_oom();

        r = unit_name_from_path(what, ".swap", &where_unit);
        if (r < 0)
                return log_error_errno(r, "Failed to make unit name from path \"%s\": %m",
                                       what);

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

        fprintf(f,
                "# Automatically generated by %s\n\n"
                "[Unit]\n"
                "Description=Make Swap on %%f\n"
                "Documentation=man:[email protected](8)\n"
                "DefaultDependencies=no\n"
                "BindsTo=%%i.device\n"
                "After=%%i.device\n"
                "Before=%s\n"
                "Before=shutdown.target\n"
                "\n"
                "[Service]\n"
                "Type=oneshot\n"
                "RemainAfterExit=yes\n"
                "ExecStart="SYSTEMD_MAKEFS_PATH " swap %s\n"
                "TimeoutSec=0\n",
                program_invocation_short_name,
                where_unit,
                escaped);

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

        return generator_add_symlink(dir, where_unit, "requires", unit);
}
Beispiel #15
0
static int x11_write_data(Context *c) {
        _cleanup_fclose_ FILE *f = NULL;
        _cleanup_free_ char *temp_path = NULL;
        int r;

        if (isempty(c->x11_layout) &&
            isempty(c->x11_model) &&
            isempty(c->x11_variant) &&
            isempty(c->x11_options)) {

                if (unlink("/etc/X11/xorg.conf.d/00-keyboard.conf") < 0)
                        return errno == ENOENT ? 0 : -errno;

                return 0;
        }

        mkdir_p_label("/etc/X11/xorg.conf.d", 0755);

        r = fopen_temporary("/etc/X11/xorg.conf.d/00-keyboard.conf", &f, &temp_path);
        if (r < 0)
                return r;

        fchmod(fileno(f), 0644);

        fputs("# Read and parsed by systemd-localed. It's probably wise not to edit this file\n"
              "# manually too freely.\n"
              "Section \"InputClass\"\n"
              "        Identifier \"system-keyboard\"\n"
              "        MatchIsKeyboard \"on\"\n", f);

        if (!isempty(c->x11_layout))
                fprintf(f, "        Option \"XkbLayout\" \"%s\"\n", c->x11_layout);

        if (!isempty(c->x11_model))
                fprintf(f, "        Option \"XkbModel\" \"%s\"\n", c->x11_model);

        if (!isempty(c->x11_variant))
                fprintf(f, "        Option \"XkbVariant\" \"%s\"\n", c->x11_variant);

        if (!isempty(c->x11_options))
                fprintf(f, "        Option \"XkbOptions\" \"%s\"\n", c->x11_options);

        fputs("EndSection\n", f);

        r = fflush_and_check(f);
        if (r < 0)
                goto fail;

        if (rename(temp_path, "/etc/X11/xorg.conf.d/00-keyboard.conf") < 0) {
                r = -errno;
                goto fail;
        }

        return 0;

fail:
        (void) unlink("/etc/X11/xorg.conf.d/00-keyboard.conf");

        if (temp_path)
                (void) unlink(temp_path);

        return r;
}
Beispiel #16
0
static int add_swap(
                const char *what,
                struct mntent *me,
                MountpointFlags flags) {

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

        assert(what);
        assert(me);

        if (access("/proc/swaps", F_OK) < 0) {
                log_info("Swap not supported, ignoring fstab swap entry for %s.", what);
                return 0;
        }

        if (detect_container() > 0) {
                log_info("Running in a container, ignoring fstab swap entry for %s.", what);
                return 0;
        }

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

        r = generator_open_unit_file(arg_dest, "/etc/fstab", name, &f);
        if (r < 0)
                return r;

        fputs("# Automatically generated by systemd-fstab-generator\n\n"
              "[Unit]\n"
              "SourcePath=/etc/fstab\n"
              "Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n\n"
              "[Swap]\n", f);

        r = write_what(f, what);
        if (r < 0)
                return r;

        r = write_options(f, me->mnt_opts);
        if (r < 0)
                return r;

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

        /* use what as where, to have a nicer error message */
        r = generator_write_timeouts(arg_dest, what, what, me->mnt_opts, NULL);
        if (r < 0)
                return r;

        if (flags & MAKEFS) {
                r = generator_hook_up_mkswap(arg_dest, what);
                if (r < 0)
                        return r;
        }

        if (flags & GROWFS)
                /* TODO: swap devices must be wiped and recreated */
                log_warning("%s: growing swap devices is currently unsupported.", what);

        if (!(flags & NOAUTO)) {
                r = generator_add_symlink(arg_dest, SPECIAL_SWAP_TARGET,
                                          (flags & NOFAIL) ? "wants" : "requires", name);
                if (r < 0)
                        return r;
        }

        return 0;
}
Beispiel #17
0
static int create_device(void) {
        _cleanup_free_ char *u = NULL, *v = NULL, *d = NULL, *e = NULL, *u_escaped = NULL, *v_escaped = NULL, *root_hash_escaped = NULL;
        _cleanup_fclose_ FILE *f = NULL;
        const char *to;
        int r;

        /* If all three pieces of information are missing, then verity is turned off */
        if (!arg_root_hash && !arg_data_what && !arg_hash_what)
                return 0;

        /* if one of them is missing however, the data is simply incomplete and this is an error */
        if (!arg_root_hash)
                log_error("Verity information incomplete, root hash unspecified.");
        if (!arg_data_what)
                log_error("Verity information incomplete, root data device unspecified.");
        if (!arg_hash_what)
                log_error("Verity information incomplete, root hash device unspecified.");

        if (!arg_root_hash || !arg_data_what || !arg_hash_what)
                return -EINVAL;

        log_debug("Using root verity data device %s,\n"
                  "                  hash device %s,\n"
                  "                and root hash %s.", arg_data_what, arg_hash_what, arg_root_hash);

        u = fstab_node_to_udev_node(arg_data_what);
        if (!u)
                return log_oom();
        v = fstab_node_to_udev_node(arg_hash_what);
        if (!v)
                return log_oom();

        u_escaped = specifier_escape(u);
        if (!u_escaped)
                return log_oom();
        v_escaped = specifier_escape(v);
        if (!v_escaped)
                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");
        r = unit_name_from_path(v, ".device", &e);
        if (r < 0)
                return log_error_errno(r, "Failed to generate unit name: %m");

        root_hash_escaped = specifier_escape(arg_root_hash);
        if (!root_hash_escaped)
                return log_oom();

        r = generator_open_unit_file(arg_dest, NULL, SYSTEMD_VERITYSETUP_SERVICE, &f);
        if (r < 0)
                return r;

        fprintf(f,
                "[Unit]\n"
                "Description=Integrity Protection Setup for %%I\n"
                "Documentation=man:systemd-veritysetup-generator(8) man:[email protected](8)\n"
                "SourcePath=/proc/cmdline\n"
                "DefaultDependencies=no\n"
                "Conflicts=umount.target\n"
                "BindsTo=%s %s\n"
                "IgnoreOnIsolate=true\n"
                "After=cryptsetup-pre.target %s %s\n"
                "Before=cryptsetup.target umount.target\n"
                "\n[Service]\n"
                "Type=oneshot\n"
                "RemainAfterExit=yes\n"
                "ExecStart=" ROOTLIBEXECDIR "/systemd-veritysetup attach root '%s' '%s' '%s'\n"
                "ExecStop=" ROOTLIBEXECDIR "/systemd-veritysetup detach root\n",
                d, e,
                d, e,
                u_escaped, v_escaped, root_hash_escaped);

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

        to = strjoina(arg_dest, "/cryptsetup.target.requires/" SYSTEMD_VERITYSETUP_SERVICE);

        (void) mkdir_parents(to, 0755);
        if (symlink("../" SYSTEMD_VERITYSETUP_SERVICE, to) < 0)
                return log_error_errno(errno, "Failed to create symlink %s: %m", to);

        return 0;
}
static int add_swap(
                const char *what,
                struct mntent *me,
                bool noauto,
                bool nofail) {

        _cleanup_free_ char *name = NULL, *unit = NULL, *lnk = NULL, *filtered = NULL;
        _cleanup_fclose_ FILE *f = NULL;
        int r, pri = -1;
        const char *opts;

        assert(what);
        assert(me);

        if (access("/proc/swaps", F_OK) < 0) {
                log_info("Swap not supported, ignoring fstab swap entry for %s.", what);
                return 0;
        }

        if (detect_container(NULL) > 0) {
                log_info("Running in a container, ignoring fstab swap entry for %s.", what);
                return 0;
        }

        opts = me->mnt_opts;
        r = fstab_find_pri(opts, &pri);
        if (r < 0) {
                log_error_errno(r, "Failed to parse priority, ignoring: %m");

                /* Remove invalid pri field */
                r = fstab_filter_options(opts, "pri\0", NULL, NULL, &filtered);
                if (r < 0)
                        return log_error_errno(r, "Failed to parse options: %m");
                opts = filtered;
        }

        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_errno(errno, "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"
                "Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n\n"
                "[Swap]\n"
                "What=%s\n",
                what);

        /* Note that we currently pass the priority field twice, once
         * in Priority=, and once in Options= */
        if (pri >= 0)
                fprintf(f, "Priority=%i\n", pri);

        if (!isempty(opts) && !streq(opts, "defaults"))
                fprintf(f, "Options=%s\n", opts);

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

        /* use what as where, to have a nicer error message */
        r = generator_write_timeouts(arg_dest, what, what, opts, NULL);
        if (r < 0)
                return r;

        if (!noauto) {
                lnk = strjoin(arg_dest, "/" SPECIAL_SWAP_TARGET,
                              nofail ? ".wants/" : ".requires/", name, NULL);
                if (!lnk)
                        return log_oom();

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

        return 0;
}
Beispiel #19
0
static int copy_file(const char *from, const char *to, bool force) {
        _cleanup_fclose_ FILE *f = NULL, *g = NULL;
        char *p;
        int r;
        struct timespec t[2];
        struct stat st;

        assert(from);
        assert(to);

        f = fopen(from, "re");
        if (!f)
                return log_error_errno(errno, "Failed to open \"%s\" for reading: %m", from);

        if (!force) {
                /* If this is an update, then let's compare versions first */
                r = version_check(fileno(f), from, to);
                if (r < 0)
                        return r;
        }

        p = strjoina(to, "~");
        g = fopen(p, "wxe");
        if (!g) {
                /* Directory doesn't exist yet? Then let's skip this... */
                if (!force && errno == ENOENT)
                        return 0;

                return log_error_errno(errno, "Failed to open \"%s\" for writing: %m", to);
        }

        rewind(f);
        do {
                size_t k;
                uint8_t buf[32*1024];

                k = fread(buf, 1, sizeof(buf), f);
                if (ferror(f)) {
                        r = log_error_errno(EIO, "Failed to read \"%s\": %m", from);
                        goto error;
                }

                if (k == 0)
                        break;

                fwrite(buf, 1, k, g);
                if (ferror(g)) {
                        r = log_error_errno(EIO, "Failed to write \"%s\": %m", to);
                        goto error;
                }
        } while (!feof(f));

        r = fflush_and_check(g);
        if (r < 0) {
                log_error_errno(r, "Failed to write \"%s\": %m", to);
                goto error;
        }

        r = fstat(fileno(f), &st);
        if (r < 0) {
                r = log_error_errno(errno, "Failed to get file timestamps of \"%s\": %m", from);
                goto error;
        }

        t[0] = st.st_atim;
        t[1] = st.st_mtim;

        r = futimens(fileno(g), t);
        if (r < 0) {
                r = log_error_errno(errno, "Failed to set file timestamps on \"%s\": %m", p);
                goto error;
        }

        if (rename(p, to) < 0) {
                r = log_error_errno(errno, "Failed to rename \"%s\" to \"%s\": %m", p, to);
                goto error;
        }

        log_info("Copied \"%s\" to \"%s\".", from, to);
        return 0;

error:
        (void) unlink(p);
        return r;
}
Beispiel #20
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, *e = NULL,
                *filtered = NULL, *u_escaped = NULL, *password_escaped = NULL, *filtered_escaped = NULL, *name_escaped = NULL;
        _cleanup_fclose_ FILE *f = NULL;
        const char *dmname;
        bool noauto, nofail, tmp, swap, netdev;
        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");
        netdev = fstab_test_option(options, "_netdev\0");

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

        name_escaped = specifier_escape(name);
        if (!name_escaped)
                return log_oom();

        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);
        if (!p)
                return log_oom();

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

        u_escaped = specifier_escape(u);
        if (!u_escaped)
                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");

        password_escaped = specifier_escape(password);
        if (!password_escaped)
                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-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"
                "IgnoreOnIsolate=true\n"
                "After=%s\n",
                netdev ? "remote-fs-pre.target" : "cryptsetup-pre.target");

        if (!nofail)
                fprintf(f,
                        "Before=%s\n",
                        netdev ? "remote-cryptsetup.target" : "cryptsetup.target");

        if (password) {
                if (STR_IN_SET(password, "/dev/urandom", "/dev/random", "/dev/hw_random"))
                        fputs_unlocked("After=systemd-random-seed.service\n", f);
                else if (!STR_IN_SET(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 (path_startswith(uu, "/dev/")) {
                                        _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_escaped);
                        }
                }
        }

        if (path_startswith(u, "/dev/")) {
                fprintf(f,
                        "BindsTo=%s\n"
                        "After=%s\n"
                        "Before=umount.target\n",
                        d, d);

                if (swap)
                        fputs_unlocked("Before=dev-mapper-%i.swap\n",
                                       f);
        } else
                fprintf(f,
                        "RequiresMountsFor=%s\n",
                        u_escaped);


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

        filtered_escaped = specifier_escape(filtered);
        if (!filtered_escaped)
                return log_oom();

        fprintf(f,
                "\n[Service]\n"
                "Type=oneshot\n"
                "RemainAfterExit=yes\n"
                "TimeoutSec=0\n" /* the binary handles timeouts anyway */
                "KeyringMode=shared\n" /* make sure we can share cached keys among instances */
                "ExecStart=" SYSTEMD_CRYPTSETUP_PATH " attach '%s' '%s' '%s' '%s'\n"
                "ExecStop=" SYSTEMD_CRYPTSETUP_PATH " detach '%s'\n",
                name_escaped, u_escaped, strempty(password_escaped), strempty(filtered_escaped),
                name_escaped);

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

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

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

        if (!noauto) {
                r = generator_add_symlink(arg_dest, d, "wants", n);
                if (r < 0)
                        return r;

                r = generator_add_symlink(arg_dest,
                                          netdev ? "remote-cryptsetup.target" : "cryptsetup.target",
                                          nofail ? "wants" : "requires", n);
                if (r < 0)
                        return r;
        }

        dmname = strjoina("dev-mapper-", e, ".device");
        r = generator_add_symlink(arg_dest, dmname, "requires", n);
        if (r < 0)
                return r;

        if (!noauto && !nofail) {
                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;
}
Beispiel #21
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;
        int r;

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

                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_ADDRESS "\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_ADDRESS_FMT ";" UNIX_USER_BUS_ADDRESS_FMT "\n",
                                        getuid(), run);
                        }
                }

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

                f = safe_fclose(f);

                service = s;
        }

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

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

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

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

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

        return 0;
}
Beispiel #22
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;
}
Beispiel #23
0
static int add_swap(
    const char *what,
    struct mntent *me,
    bool noauto,
    bool nofail) {

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

    assert(what);
    assert(me);

    if (access("/proc/swaps", F_OK) < 0) {
        log_info("Swap not supported, ignoring fstab swap entry for %s.", what);
        return 0;
    }

    if (detect_container() > 0) {
        log_info("Running in a container, ignoring fstab swap entry for %s.", what);
        return 0;
    }

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

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

    f = fopen(unit, "wxe");
    if (!f)
        return log_error_errno(errno,
                               errno == EEXIST ?
                               "Failed to create swap unit file %s, as it already exists. Duplicate entry in /etc/fstab?" :
                               "Failed to create unit file %s: %m",
                               unit);

    fprintf(f,
            "# Automatically generated by systemd-fstab-generator\n\n"
            "[Unit]\n"
            "SourcePath=/etc/fstab\n"
            "Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n\n"
            "[Swap]\n"
            "What=%s\n",
            what);

    if (!isempty(me->mnt_opts) && !streq(me->mnt_opts, "defaults"))
        fprintf(f, "Options=%s\n", me->mnt_opts);

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

    /* use what as where, to have a nicer error message */
    r = generator_write_timeouts(arg_dest, what, what, me->mnt_opts, NULL);
    if (r < 0)
        return r;

    if (!noauto) {
        lnk = strjoin(arg_dest, "/" SPECIAL_SWAP_TARGET,
                      nofail ? ".wants/" : ".requires/", name, NULL);
        if (!lnk)
            return log_oom();

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

    return 0;
}
Beispiel #24
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;
}
Beispiel #25
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;
}
Beispiel #26
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;
}
Beispiel #27
0
static opcode_status_ty
spawn(string_list_ty *args, string_ty *input, int *pid_p,
    string_ty *host_binding, opcode_context_ty *ocp)
{
    size_t          j;
    int             fd;
    string_ty       *iname;
    int             pid;
    opcode_status_ty status;
    static char     **argv;
    static size_t   argvlen;
    string_list_ty  cmd;
    sub_context_ty  *scp;
    char            *shell;

    trace(("spawn()\n{\n"));
    assert(args);

    /*
     * build the input file, if required
     */
    status = opcode_status_error;
    fd = -1;
    iname = 0;
    if (input)
    {
        /*
         * He has given a string to be used as input to the command,
         * so write it out to a file, and then redirect the input.
         */
        iname = temporary_filename();
        fd = open(iname->str_text, O_RDWR | O_CREAT | O_TRUNC, 0666);
        if (fd < 0)
            fatal_intl_open(iname->str_text);
        if (unlink(iname->str_text))
        {
            error_intl_unlink(iname->str_text);
            goto done;
        }
        if
        (
            write(fd, input->str_text, input->str_length) < 0
        ||
            lseek(fd, 0L, SEEK_SET)
        )
        {
            error_intl_write(iname->str_text);
            goto done;
        }
    }

    /*
     * See if there is a host_binding in effect.
     */
    if (host_binding)
    {
        static string_ty *key;
        string_list_ty  *slp;
        string_ty       *s;
        string_ty       *rcmd;
        string_ty       *rcmdq;
        string_ty       *result_fn;
        FILE            *result_fp;
        string_ty       *cwd;
        string_ty       *script_fn;
        FILE            *script_fp;

        /*
         * Work out the name of the remote shell command.
         */
        if (!key)
            key = str_from_c("parallel_rsh");
        slp = id_var_search(ocp, key);
        if (slp)
            string_list_copy_constructor(&cmd, slp);
        else
        {
            static string_ty *rsh;

            if (!rsh)
                rsh = str_from_c(CONF_REMOTE_SHELL);
            string_list_constructor(&cmd);
            string_list_append(&cmd, rsh);
        }

        /*
         * Add the name of the host.
         */
        string_list_append(&cmd, host_binding);

        /*
         * The remote end will need to change directory to where
         * we are now, since it is *highly* unlikely that we are
         * in our home directory.
         */
        cwd = os_curdir(); /* do not str_free this */

        /*
         * We are going to create a small shell script contining
         * the command to be executed.  This deals with various
         * weird and obscure $SHELL settings, and it also deals
         * with command lines so long that rsh barfs.
         *
         * Yes, there is a potential race condition here.
         * Between writing the script and executing it, we
         * could be tricked into executing something else.
         * Especially if there is a symlink lying in wait.
         */
        script_fn = dot_temporary_filename();
        script_fp = fopen_and_check(script_fn->str_text, "w");

        /*
         * what shell are we using
         */
        shell = getenv("SHELL");
        if (!shell || !*shell)
            shell = CONF_SHELL;
        fprintf(script_fp, "#!%s\n", shell);

        /*
         * Now write the actual command to the script file.
         */
        rcmd = wl2str(args, 0, args->nstrings, (char *)0);
        fprintf(script_fp, "%s\n", rcmd->str_text);
        str_free(rcmd);

        fflush_and_check(script_fp, script_fn->str_text);
        fclose_and_check(script_fp, script_fn->str_text);
        chmod_and_check(script_fn->str_text, 0755);

        /*
         * This is the result file.  It is where the remote
         * command will stash its exit status.    We seed it with
         * failure in case the rsh fails altogether.
         *
         * And, yes, there is a race conditon and we could be
         * lied to if they are quick.
         */
        result_fn = dot_temporary_filename();
        result_fp = fopen_and_check(result_fn->str_text, "w");
        fprintf(result_fp, "42\n");
        fflush_and_check(result_fp, result_fn->str_text);
        fclose_and_check(result_fp, result_fn->str_text);

        /*
         * Because rsh(1) always returns an exit status of zero,
         * we have to make other arrangements to obtain the exit
         * status.
         *
         * We actually need to be a more devious, so that we can
         * get the exit status back.  Write it to a temporary
         * file server side, then read and remove it client side.
         *
         * This is the server side command.  It gets quoted
         * again to protect it from the client side shell.
         *
         * We use sh explicitly, because the shell at the other
         * end could be csh, tcsh, or something even stranger,
         * and we need to guarantee the command will execute
         * exactly the way we need.
         */
        rcmd =
            str_format
            (
                "sh -c 'cd %s && sh %s %s/%s; echo $? > %s/%s'",
                cwd->str_text,
                (option_test(OPTION_ERROK) ? "-c" : "-ce"),
                cwd->str_text,
                script_fn->str_text,
                cwd->str_text,
                result_fn->str_text
            );
        rcmdq = str_quote_shell(rcmd);
        str_free(rcmd);
        string_list_append(&cmd, rcmdq);
        str_free(rcmdq);

        /*
         * This is the rest of the server side command.
         *
         * On some systems this gives ``Text file busy'' errors,
         * as if the script file has yet to be released by
         * the kernel.    Since we *aren't* executing it when the
         * RM command runs, I have no idea how to avoid this
         * (other than ignoring it with -f).  Maybe this is some
         * kind of NFS latency?
         */
        s =
            str_format
            (
                "&& exit `cat %s;rm -f %s %s`",
                result_fn->str_text,
                result_fn->str_text,
                script_fn->str_text
            );
        string_list_append(&cmd, s);
        str_free(s);
        str_free(result_fn);
        str_free(script_fn);

        /*
         * Because the command has a semicolon and back quotes,
         * we need to hand it to a shell (as alluded to above).
         * Assemble into a single string.
         */
        rcmd = wl2str(&cmd, 0, cmd.nstrings, (char *)0);
        string_list_destructor(&cmd);

        /*
         * Build the final command to be executed.
         * It even cleans up after itself.
         */
        s = str_from_c("sh");
        string_list_append(&cmd, s);
        str_free(s);
        s = str_from_c("-c");
        string_list_append(&cmd, s);
        str_free(s);
        string_list_append(&cmd, rcmd);
        str_free(rcmd);
    }
    else
    {
        /*
         * build the command
         */
        if (os_execute_magic_characters_list(args))
        {
            string_ty       *str;

            /*
             * what shell are we using
             */
            shell = getenv("SHELL");
            if (!shell || !*shell)
                shell = CONF_SHELL;

            string_list_constructor(&cmd);
            str = str_from_c(shell);
            string_list_append(&cmd, str);
            str_free(str);
            if (option_test(OPTION_ERROK))
                str = str_from_c("-c");
            else
                str = str_from_c("-ce");
            string_list_append(&cmd, str);
            str_free(str);
            str = wl2str(args, 0, args->nstrings - 1, (char *)0);
            string_list_append(&cmd, str);
            str_free(str);
        }
        else
            string_list_copy_constructor(&cmd, args);
    }

    /*
     * build the argv array
     */
    if (!argv)
    {
        argvlen = cmd.nstrings + 1;
        argv = mem_alloc(argvlen * sizeof(char *));
    }
    else if (argvlen < cmd.nstrings + 1)
    {
        argvlen = cmd.nstrings + 1;
        argv = mem_change_size(argv, argvlen * sizeof(char *));
    }
    if (cmd.nstrings == 0)
    {
        string_list_destructor(&cmd);
        status = opcode_status_success;
        goto done;
    }
    for (j = 0; j < cmd.nstrings; ++j)
        argv[j] = cmd.string[j]->str_text;
    argv[cmd.nstrings] = 0;

    /*
     * spawn the child process
     */
    switch (pid = fork())
    {
    case -1:
        scp = sub_context_new();
        sub_errno_set(scp);
        error_intl(scp, i18n("fork(): $errno"));
        sub_context_delete(scp);
        break;

    case 0:
        /*
         * child
         */
        if (fd >= 0)
        {
            if (close(0) && errno != EBADF)
            {
                string_ty       *fn0;
                int             err;

                err = errno;
                scp = sub_context_new();
                fn0 = subst_intl(scp, "standard input");
                /* re-use substitution context */
                sub_errno_setx(scp, err);
                sub_var_set_string(scp, "File_Name", fn0);
                fatal_intl
                (
                    scp,
                    i18n("close $filename: $errno")
                );
                /* NOTREACHED */
                sub_context_delete(scp);
                str_free(fn0);
            }
            if (dup(fd) < 0)
            {
                scp = sub_context_new();
                sub_errno_set(scp);
                fatal_intl(scp, i18n("dup(): $errno"));
                /* NOTREACHED */
                sub_context_delete(scp);
            }
            close(fd);
        }
        if (argv[0][0] == '/')
            execv(argv[0], argv);
        else
            execvp(argv[0], argv);
        scp = sub_context_new();
        sub_errno_set(scp);
        sub_var_set_charstar(scp, "File_Name", argv[0]);
        fatal_intl(scp, i18n("exec $filename: $errno"));
        /* NOTREACHED */
        sub_context_delete(scp);

    default:
        /*
         * parent
         */
        if (fd >= 0)
        {
            close(fd);
            fd = -1;
        }
        string_list_destructor(&cmd);
        status = opcode_status_wait;
        trace(("pid = %d;\n", pid));
        *pid_p = pid;
        break;
    }
    done:
    if (fd >= 0)
        close(fd);
    if (iname)
        str_free(iname);
    trace(("return %s;\n", opcode_status_name(status)));
    trace(("}\n"));
    return status;
}