예제 #1
0
파일: fileio.c 프로젝트: vathpela/systemd
static int load_env_file_push_pairs(
                const char *filename, unsigned line,
                const char *key, char *value,
                void *userdata,
                int *n_pushed) {
        char ***m = userdata;
        int r;

        r = check_utf8ness_and_warn(filename, line, key, value);
        if (r < 0)
                return r;

        r = strv_extend(m, key);
        if (r < 0)
                return -ENOMEM;

        if (!value) {
                r = strv_extend(m, "");
                if (r < 0)
                        return -ENOMEM;
        } else {
                r = strv_push(m, value);
                if (r < 0)
                        return r;
        }

        if (n_pushed)
                (*n_pushed)++;

        return 0;
}
예제 #2
0
파일: slice.c 프로젝트: ajeddeloh/systemd
static int slice_enumerate(Manager *m) {
        Unit *u;
        int r;

        assert(m);

        u = manager_get_unit(m, SPECIAL_ROOT_SLICE);
        if (!u) {
                u = unit_new(m, sizeof(Slice));
                if (!u)
                        return log_oom();

                r = unit_add_name(u, SPECIAL_ROOT_SLICE);
                if (r < 0) {
                        unit_free(u);
                        return log_error_errno(r, "Failed to add -.slice name");
                }
        }

        u->default_dependencies = false;
        u->no_gc = true;
        SLICE(u)->deserialized_state = SLICE_ACTIVE;

        if (!u->description)
                u->description = strdup("Root Slice");
        if (!u->documentation)
                (void) strv_extend(&u->documentation, "man:systemd.special(7)");

        unit_add_to_load_queue(u);
        unit_add_to_dbus_queue(u);

        return 0;
}
예제 #3
0
파일: scope.c 프로젝트: OpenDZ/systemd
static int scope_load_init_scope(Unit *u) {
        assert(u);

        if (!unit_has_name(u, SPECIAL_INIT_SCOPE))
                return 0;

        u->transient = true;
        u->perpetual = true;

        /* init.scope is a bit special, as it has to stick around forever. Because of its special semantics we
         * synthesize it here, instead of relying on the unit file on disk. */

        u->default_dependencies = false;
        u->ignore_on_isolate = true;

        SCOPE(u)->kill_context.kill_signal = SIGRTMIN+14;

        /* Prettify things, if we can. */
        if (!u->description)
                u->description = strdup("System and Service Manager");
        if (!u->documentation)
                (void) strv_extend(&u->documentation, "man:systemd(1)");

        return 1;
}
예제 #4
0
static int list_dependencies_one(sd_bus *bus, const char *name, unsigned int level, char ***units,
                                 unsigned int branches) {
        _cleanup_strv_free_ char **deps = NULL;
        char **c;
        int r = 0;
        usec_t service_longest = 0;
        int to_print = 0;
        struct unit_times *times;
        struct boot_times *boot;

        if (strv_extend(units, name))
                return log_oom();

        r = list_dependencies_get_dependencies(bus, name, &deps);
        if (r < 0)
                return r;

        qsort_safe(deps, strv_length(deps), sizeof (char*), list_dependencies_compare);

        r = acquire_boot_times(bus, &boot);
        if (r < 0)
                return r;

        STRV_FOREACH(c, deps) {
                times = hashmap_get(unit_times_hashmap, *c);
                if (times
                    && times->activated
                    && times->activated <= boot->finish_time
                    && (times->activated >= service_longest
                        || service_longest == 0)) {
                        service_longest = times->activated;
                        break;
                }
        }
예제 #5
0
int config_parse_syscall_filter(
                const char *unit,
                const char *filename,
                unsigned line,
                const char *section,
                unsigned section_line,
                const char *lvalue,
                int ltype,
                const char *rvalue,
                void *data,
                void *userdata) {

        Settings *settings = data;
        bool negative;
        const char *items;
        int r;

        assert(filename);
        assert(lvalue);
        assert(rvalue);

        negative = rvalue[0] == '~';
        items = negative ? rvalue + 1 : rvalue;

        for (;;) {
                _cleanup_free_ char *word = NULL;

                r = extract_first_word(&items, &word, NULL, 0);
                if (r == 0)
                        break;
                if (r == -ENOMEM)
                        return log_oom();
                if (r < 0) {
                        log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse SystemCallFilter= parameter %s, ignoring: %m", rvalue);
                        return 0;
                }

                if (negative)
                        r = strv_extend(&settings->syscall_blacklist, word);
                else
                        r = strv_extend(&settings->syscall_whitelist, word);
                if (r < 0)
                        return log_oom();
        }

        return 0;
}
예제 #6
0
static int iterate_dir(
                const char *path,
                UnitDependency dependency,
                dependency_consumer_t consumer,
                void *arg,
                char ***strv) {

        _cleanup_closedir_ DIR *d = NULL;
        int r;

        assert(path);

        /* The config directories are special, since the order of the
         * drop-ins matters */
        if (dependency < 0)  {
                r = strv_extend(strv, path);
                if (r < 0)
                        return log_oom();

                return 0;
        }

        assert(consumer);

        d = opendir(path);
        if (!d) {
                if (errno == ENOENT)
                        return 0;

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

        for (;;) {
                struct dirent *de;
                _cleanup_free_ char *f = NULL;

                errno = 0;
                de = readdir(d);
                if (!de && errno != 0)
                        return log_error_errno(errno, "Failed to read directory %s: %m", path);

                if (!de)
                        break;

                if (hidden_file(de->d_name))
                        continue;

                f = strjoin(path, "/", de->d_name, NULL);
                if (!f)
                        return log_oom();

                r = consumer(dependency, de->d_name, f, arg);
                if (r < 0)
                        return r;
        }

        return 0;
}
예제 #7
0
int strv_extend_strv(char ***a, char **b) {
        int r;
        char **s;

        STRV_FOREACH(s, b) {
                r = strv_extend(a, *s);
                if (r < 0)
                        return r;
        }
예제 #8
0
파일: fileio.c 프로젝트: achanda/systemd
static int load_env_file_push_pairs(
                const char *filename, unsigned line,
                const char *key, char *value,
                void *userdata,
                int *n_pushed) {
        char ***m = userdata;
        int r;

        if (!utf8_is_valid(key)) {
                _cleanup_free_ char *t = utf8_escape_invalid(key);

                log_error("%s:%u: invalid UTF-8 for key '%s', ignoring.", strna(filename), line, t);
                return -EINVAL;
        }

        if (value && !utf8_is_valid(value)) {
                _cleanup_free_ char *t = utf8_escape_invalid(value);

                log_error("%s:%u: invalid UTF-8 value for key %s: '%s', ignoring.", strna(filename), line, key, t);
                return -EINVAL;
        }

        r = strv_extend(m, key);
        if (r < 0)
                return -ENOMEM;

        if (!value) {
                r = strv_extend(m, "");
                if (r < 0)
                        return -ENOMEM;
        } else {
                r = strv_push(m, value);
                if (r < 0)
                        return r;
        }

        if (n_pushed)
                (*n_pushed)++;

        return 0;
}
예제 #9
0
static int parse_proc_cmdline_item(const char *key, const char *value) {
    int r;

    if (STR_IN_SET(key, "luks", "rd.luks") && value) {

        r = parse_boolean(value);
        if (r < 0)
            log_warning("Failed to parse luks switch %s. Ignoring.", value);
        else
            arg_enabled = r;

    } else if (STR_IN_SET(key, "luks.crypttab", "rd.luks.crypttab") && value) {

        r = parse_boolean(value);
        if (r < 0)
            log_warning("Failed to parse luks crypttab switch %s. Ignoring.", value);
        else
            arg_read_crypttab = r;

    } else if (STR_IN_SET(key, "luks.uuid", "rd.luks.uuid") && value) {

        if (strv_extend(&arg_disks, value) < 0)
            return log_oom();

    } else if (STR_IN_SET(key, "luks.options", "rd.luks.options") && value) {

        if (strv_extend(&arg_options, value) < 0)
            return log_oom();

    } else if (STR_IN_SET(key, "luks.key", "rd.luks.key") && value) {

        free(arg_keyfile);
        arg_keyfile = strdup(value);
        if (!arg_keyfile)
            return log_oom();

    } else if (startswith(key, "luks.") || startswith(key, "rd.luks."))
        log_warning("Unknown kernel switch %s. Ignoring.", key);

    return 0;
}
예제 #10
0
int config_parse_strv(const char *unit,
                      const char *filename,
                      unsigned line,
                      const char *section,
                      unsigned section_line,
                      const char *lvalue,
                      int ltype,
                      const char *rvalue,
                      void *data,
                      void *userdata) {

        char *** sv = data, *w, *state;
        size_t l;
        int r;

        assert(filename);
        assert(lvalue);
        assert(rvalue);
        assert(data);

        if (isempty(rvalue)) {
                char **empty;

                /* Empty assignment resets the list. As a special rule
                 * we actually fill in a real empty array here rather
                 * than NULL, since some code wants to know if
                 * something was set at all... */
                empty = strv_new(NULL, NULL);
                if (!empty)
                        return log_oom();

                strv_free(*sv);
                *sv = empty;
                return 0;
        }

        FOREACH_WORD_QUOTED(w, l, rvalue, state) {
                _cleanup_free_ char *n;

                n = cunescape_length(w, l);
                if (!n)
                        return log_oom();

                if (!utf8_is_valid(n)) {
                        log_syntax(unit, LOG_ERR, filename, line, EINVAL,
                                   "String is not UTF-8 clean, ignoring: %s", rvalue);
                        continue;
                }

                r = strv_extend(sv, n);
                if (r < 0)
                        return log_oom();
        }
예제 #11
0
static int parse_argv(int argc, char *argv[]) {

    enum {
        ARG_VERSION = 0x100,
    };

    static const struct option options[] = {
        { "help",            no_argument,       NULL, 'h'         },
        { "version",         no_argument,       NULL, ARG_VERSION },
        { "quiet",           no_argument,       NULL, 'q'         },
        { "interface",       required_argument, NULL, 'i'         },
        {}
    };

    int c;

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

    while ((c = getopt_long(argc, argv, "+hiq", options, NULL)) >= 0)

        switch (c) {

        case 'h':
            help();
            return 0;

        case 'q':
            arg_quiet = true;
            break;

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

        case 'i':
            if (strv_extend(&arg_interfaces, optarg) < 0)
                return log_oom();

            break;

        case '?':
            return -EINVAL;

        default:
            assert_not_reached("Unhandled option");
        }

    return 1;
}
예제 #12
0
파일: logger.c 프로젝트: sebras/util-linux
static void add_structured_data_param(struct list_head *ls, const char *param)
{
	struct structured_data *sd;

	if (list_empty(ls))
		errx(EXIT_FAILURE, _("--sd-id was not specified for --sd-param %s"), param);

	assert(param);

	sd = list_last_entry(ls, struct structured_data, sds);

	if (strv_extend(&sd->params,  param))
		err_oom();
}
예제 #13
0
파일: scope.c 프로젝트: arthur-c/systemd
static void scope_enumerate(Manager *m) {
        Unit *u;
        int r;

        assert(m);

        /* Let's unconditionally add the "init.scope" special unit
         * that encapsulates PID 1. Note that PID 1 already is in the
         * cgroup for this, we hence just need to allocate the object
         * for it and that's it. */

        u = manager_get_unit(m, SPECIAL_INIT_SCOPE);
        if (!u) {
                u = unit_new(m, sizeof(Scope));
                if (!u) {
                        log_oom();
                        return;
                }

                r = unit_add_name(u, SPECIAL_INIT_SCOPE);
                if (r < 0)  {
                        unit_free(u);
                        log_error_errno(r, "Failed to add init.scope name");
                        return;
                }
        }

        u->transient = true;
        u->default_dependencies = false;
        u->no_gc = true;
        u->ignore_on_isolate = true;
        u->refuse_manual_start = true;
        u->refuse_manual_stop = true;
        SCOPE(u)->deserialized_state = SCOPE_RUNNING;
        SCOPE(u)->kill_context.kill_signal = SIGRTMIN+14;

        /* Prettify things, if we can. */
        if (!u->description)
                u->description = strdup("System and Service Manager");
        if (!u->documentation)
                (void) strv_extend(&u->documentation, "man:systemd(1)");

        unit_add_to_load_queue(u);
        unit_add_to_dbus_queue(u);
}
static int spawn_getter(const char *getter, const char *url) {
    int r;
    _cleanup_strv_free_ char **words = NULL;

    assert(getter);
    r = strv_split_quoted(&words, getter, false);
    if (r < 0)
        return log_error_errno(r, "Failed to split getter option: %m");

    r = strv_extend(&words, url);
    if (r < 0)
        return log_error_errno(r, "Failed to create command line: %m");

    r = spawn_child(words[0], words);
    if (r < 0)
        log_error_errno(errno, "Failed to spawn getter %s: %m", getter);

    return r;
}
예제 #15
0
static int prop_map_sessions_strv(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
        const char *name;
        int r;

        assert(bus);
        assert(m);

        r = sd_bus_message_enter_container(m, 'a', "(so)");
        if (r < 0)
                return r;

        while ((r = sd_bus_message_read(m, "(so)", &name, NULL)) > 0) {
                r = strv_extend(userdata, name);
                if (r < 0)
                        return r;
        }
        if (r < 0)
                return r;

        return sd_bus_message_exit_container(m);
}
예제 #16
0
static int parse_argv(int argc, char *argv[]) {

        enum {
                ARG_VERSION = 0x100,
                ARG_NO_PAGER,
                ARG_ADJUST_SYSTEM_CLOCK,
                ARG_NO_ASK_PASSWORD,
                ARG_MONITOR,
                ARG_VALUE,
        };

        static const struct option options[] = {
                { "help",                no_argument,       NULL, 'h'                     },
                { "version",             no_argument,       NULL, ARG_VERSION             },
                { "no-pager",            no_argument,       NULL, ARG_NO_PAGER            },
                { "host",                required_argument, NULL, 'H'                     },
                { "machine",             required_argument, NULL, 'M'                     },
                { "no-ask-password",     no_argument,       NULL, ARG_NO_ASK_PASSWORD     },
                { "adjust-system-clock", no_argument,       NULL, ARG_ADJUST_SYSTEM_CLOCK },
                { "monitor",             no_argument,       NULL, ARG_MONITOR             },
                { "property",            required_argument, NULL, 'p'                     },
                { "all",                 no_argument,       NULL, 'a'                     },
                { "value",               no_argument,       NULL, ARG_VALUE               },
                {}
        };

        int c, r;

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

        while ((c = getopt_long(argc, argv, "hH:M:p:a", options, NULL)) >= 0)

                switch (c) {

                case 'h':
                        return help();

                case ARG_VERSION:
                        return version();

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

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

                case ARG_NO_ASK_PASSWORD:
                        arg_ask_password = false;
                        break;

                case ARG_ADJUST_SYSTEM_CLOCK:
                        arg_adjust_system_clock = true;
                        break;

                case ARG_NO_PAGER:
                        arg_pager_flags |= PAGER_DISABLE;
                        break;

                case ARG_MONITOR:
                        arg_monitor = true;
                        break;

                case 'p': {
                        r = strv_extend(&arg_property, optarg);
                        if (r < 0)
                                return log_oom();

                        /* If the user asked for a particular
                         * property, show it to him, even if it is
                         * empty. */
                        arg_all = true;
                        break;
                }

                case 'a':
                        arg_all = true;
                        break;

                case ARG_VALUE:
                        arg_value = true;
                        break;

                case '?':
                        return -EINVAL;

                default:
                        assert_not_reached("Unhandled option");
                }

        return 1;
}
예제 #17
0
static int parse_argv(int argc, char *argv[]) {

        enum {
                ARG_VERSION = 0x100,
                ARG_NO_ASK_PASSWORD,
                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,
                ARG_TTY,
                ARG_ON_ACTIVE,
                ARG_ON_BOOT,
                ARG_ON_STARTUP,
                ARG_ON_UNIT_ACTIVE,
                ARG_ON_UNIT_INACTIVE,
                ARG_ON_CALENDAR,
                ARG_TIMER_PROPERTY,
                ARG_NO_BLOCK,
        };

        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'                  },
                { "tty",               no_argument,       NULL, 't'                  },
                { "quiet",             no_argument,       NULL, 'q'                  },
                { "on-active",         required_argument, NULL, ARG_ON_ACTIVE        },
                { "on-boot",           required_argument, NULL, ARG_ON_BOOT          },
                { "on-startup",        required_argument, NULL, ARG_ON_STARTUP       },
                { "on-unit-active",    required_argument, NULL, ARG_ON_UNIT_ACTIVE   },
                { "on-unit-inactive",  required_argument, NULL, ARG_ON_UNIT_INACTIVE },
                { "on-calendar",       required_argument, NULL, ARG_ON_CALENDAR      },
                { "timer-property",    required_argument, NULL, ARG_TIMER_PROPERTY   },
                { "no-block",          no_argument,       NULL, ARG_NO_BLOCK         },
                { "no-ask-password",   no_argument,       NULL, ARG_NO_ASK_PASSWORD },
                {},
        };

        int r, c;

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

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

                switch (c) {

                case 'h':
                        help();
                        return 0;

                case ARG_NO_ASK_PASSWORD:
                        arg_ask_password = false;
                        break;

                case ARG_VERSION:
                        return version();

                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_MACHINE;
                        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 't':
                        arg_pty = true;
                        break;

                case 'q':
                        arg_quiet = true;
                        break;

                case ARG_ON_ACTIVE:

                        r = parse_sec(optarg, &arg_on_active);
                        if (r < 0) {
                                log_error("Failed to parse timer value: %s", optarg);
                                return r;
                        }

                        break;

                case ARG_ON_BOOT:

                        r = parse_sec(optarg, &arg_on_boot);
                        if (r < 0) {
                                log_error("Failed to parse timer value: %s", optarg);
                                return r;
                        }

                        break;

                case ARG_ON_STARTUP:

                        r = parse_sec(optarg, &arg_on_startup);
                        if (r < 0) {
                                log_error("Failed to parse timer value: %s", optarg);
                                return r;
                        }

                        break;

                case ARG_ON_UNIT_ACTIVE:

                        r = parse_sec(optarg, &arg_on_unit_active);
                        if (r < 0) {
                                log_error("Failed to parse timer value: %s", optarg);
                                return r;
                        }

                        break;

                case ARG_ON_UNIT_INACTIVE:

                        r = parse_sec(optarg, &arg_on_unit_inactive);
                        if (r < 0) {
                                log_error("Failed to parse timer value: %s", optarg);
                                return r;
                        }

                        break;

                case ARG_ON_CALENDAR: {
                        CalendarSpec *spec = NULL;

                        r = calendar_spec_from_string(optarg, &spec);
                        if (r < 0) {
                                log_error("Invalid calendar spec: %s", optarg);
                                return r;
                        }

                        calendar_spec_free(spec);
                        arg_on_calendar = optarg;
                        break;
                }

                case ARG_TIMER_PROPERTY:

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

                        break;

                case ARG_NO_BLOCK:
                        arg_no_block = true;
                        break;

                case '?':
                        return -EINVAL;

                default:
                        assert_not_reached("Unhandled option");
                }

        if ((optind >= argc) && (!arg_unit || !with_timer())) {
                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;
        }

        if (arg_pty && (with_timer() || arg_scope)) {
                log_error("--pty is not compatible in timer or --scope mode.");
                return -EINVAL;
        }

        if (arg_pty && arg_transport == BUS_TRANSPORT_REMOTE) {
                log_error("--pty is only supported when connecting to the local system or containers.");
                return -EINVAL;
        }

        if (arg_scope && with_timer()) {
                log_error("Timer options are not supported in --scope mode.");
                return -EINVAL;
        }

        if (arg_timer_property && !with_timer()) {
                log_error("--timer-property= has no effect without any other timer options.");
                return -EINVAL;
        }

        return 1;
}
예제 #18
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;
}
예제 #19
0
파일: fileio.c 프로젝트: banada/systemd
int load_env_file(const char *fname, char ***rl) {

        _cleanup_fclose_ FILE *f;
        _cleanup_strv_free_ char **m = NULL;
        _cleanup_free_ char *c = NULL;

        assert(fname);
        assert(rl);

        /* This reads an environment file, but will not complain about
         * any invalid assignments, that needs to be done by the
         * caller */

        f = fopen(fname, "re");
        if (!f)
                return -errno;

        while (!feof(f)) {
                char l[LINE_MAX], *p, *cs, *b;

                if (!fgets(l, sizeof(l), f)) {
                        if (ferror(f))
                                return -errno;

                        /* The previous line was a continuation line?
                         * Let's process it now, before we leave the
                         * loop */
                        if (c)
                                goto process;

                        break;
                }

                /* Is this a continuation line? If so, just append
                 * this to c, and go to next line right-away */
                cs = endswith(l, "\\\n");
                if (cs) {
                        *cs = '\0';
                        b = strappend(c, l);
                        if (!b)
                                return -ENOMEM;

                        free(c);
                        c = b;
                        continue;
                }

                /* If the previous line was a continuation line,
                 * append the current line to it */
                if (c) {
                        b = strappend(c, l);
                        if (!b)
                                return -ENOMEM;

                        free(c);
                        c = b;
                }

        process:
                p = strstrip(c ? c : l);

                if (*p && !strchr(COMMENTS, *p)) {
                        _cleanup_free_ char *u;
                        int k;

                        u = normalize_env_assignment(p);
                        if (!u)
                                return -ENOMEM;

                        k = strv_extend(&m, u);
                        if (k < 0)
                                return -ENOMEM;
                }

                free(c);
                c = NULL;
        }

        *rl = m;
        m = NULL;

        return 0;
}
예제 #20
0
        STRV_FOREACH(filename, filenames) {
                char *t;

                t = dirname_malloc(*filename);
                if (!t)
                        return -ENOMEM;

                r = strv_consume(&ans, t);
                if (r < 0)
                        return r;
        }

        assert_se(strv_uniq(ans));

        r = strv_extend(&ans, "");
        if (r < 0)
                return r;

        *var = strv_join(ans, ":");
        if (!*var)
                return -ENOMEM;

        return 0;
}

static int verify_socket(Unit *u) {
        int r;

        assert(u);
예제 #21
0
파일: run.c 프로젝트: Mathnerd314/systemd
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;
}
예제 #22
0
static int parse_proc_cmdline(char ***arg_proc_cmdline_disks, char ***arg_proc_cmdline_options, char **arg_proc_cmdline_keyfile) {
        _cleanup_free_ char *line = NULL;
        char *w = NULL, *state = NULL;
        int r;
        size_t l;

        if (detect_container(NULL) > 0)
                return 0;

        r = read_one_line_file("/proc/cmdline", &line);
        if (r < 0) {
                log_warning("Failed to read /proc/cmdline, ignoring: %s", strerror(-r));
                return 0;
        }

        FOREACH_WORD_QUOTED(w, l, line, state) {
                _cleanup_free_ char *word = NULL;

                word = strndup(w, l);
                if (!word)
                        return log_oom();

                if (startswith(word, "luks=")) {
                        r = parse_boolean(word + 5);
                        if (r < 0)
                                log_warning("Failed to parse luks switch %s. Ignoring.", word + 5);
                        else
                                arg_enabled = r;

                } else if (startswith(word, "rd.luks=")) {

                        if (in_initrd()) {
                                r = parse_boolean(word + 8);
                                if (r < 0)
                                        log_warning("Failed to parse luks switch %s. Ignoring.", word + 8);
                                else
                                        arg_enabled = r;
                        }

                } else if (startswith(word, "luks.crypttab=")) {
                        r = parse_boolean(word + 14);
                        if (r < 0)
                                log_warning("Failed to parse luks crypttab switch %s. Ignoring.", word + 14);
                        else
                                arg_read_crypttab = r;

                } else if (startswith(word, "rd.luks.crypttab=")) {

                        if (in_initrd()) {
                                r = parse_boolean(word + 17);
                                if (r < 0)
                                        log_warning("Failed to parse luks crypttab switch %s. Ignoring.", word + 17);
                                else
                                        arg_read_crypttab = r;
                        }

                } else if (startswith(word, "luks.uuid=")) {
                        if (strv_extend(arg_proc_cmdline_disks, word + 10) < 0)
                                return log_oom();

                } else if (startswith(word, "rd.luks.uuid=")) {

                        if (in_initrd()) {
                                if (strv_extend(arg_proc_cmdline_disks, word + 13) < 0)
                                        return log_oom();
                        }

                } else if (startswith(word, "luks.options=")) {
                        if (strv_extend(arg_proc_cmdline_options, word + 13) < 0)
                                return log_oom();

                } else if (startswith(word, "rd.luks.options=")) {

                        if (in_initrd()) {
                                if (strv_extend(arg_proc_cmdline_options, word + 16) < 0)
                                        return log_oom();
                        }

                } else if (startswith(word, "luks.key=")) {
                        if (*arg_proc_cmdline_keyfile)
                                free(*arg_proc_cmdline_keyfile);
                        *arg_proc_cmdline_keyfile = strdup(word + 9);
                        if (!*arg_proc_cmdline_keyfile)
                                return log_oom();

                } else if (startswith(word, "rd.luks.key=")) {

                        if (in_initrd()) {
                                if (*arg_proc_cmdline_keyfile)
                                        free(*arg_proc_cmdline_keyfile);
                                *arg_proc_cmdline_keyfile = strdup(word + 12);
                                if (!*arg_proc_cmdline_keyfile)
                                        return log_oom();
                        }

                } else if (startswith(word, "luks.") ||
                           (in_initrd() && startswith(word, "rd.luks."))) {

                        log_warning("Unknown kernel switch %s. Ignoring.", word);
                }
        }
예제 #23
0
int main(int argc, char *argv[]) {
    _cleanup_strv_free_ char **disks_done = NULL;
    _cleanup_fclose_ FILE *f = NULL;
    unsigned n = 0;
    int r = EXIT_FAILURE, r2 = EXIT_FAILURE;
    char **i;

    if (argc > 1 && argc != 4) {
        log_error("This program takes three or no arguments.");
        return EXIT_FAILURE;
    }

    if (argc > 1)
        arg_dest = argv[1];

    log_set_target(LOG_TARGET_SAFE);
    log_parse_environment();
    log_open();

    umask(0022);

    if (parse_proc_cmdline(parse_proc_cmdline_item) < 0)
        goto cleanup;

    if (!arg_enabled) {
        r = r2 = EXIT_SUCCESS;
        goto cleanup;
    }

    strv_uniq(arg_disks);

    if (arg_read_crypttab) {
        struct stat st;

        f = fopen("/etc/crypttab", "re");
        if (!f) {
            if (errno == ENOENT)
                r = EXIT_SUCCESS;
            else
                log_error("Failed to open /etc/crypttab: %m");

            goto next;
        }

        if (fstat(fileno(f), &st) < 0) {
            log_error("Failed to stat /etc/crypttab: %m");
            goto next;
        }

        /* If we readd support for specifying passphrases
         * directly in crypttabe we should upgrade the warning
         * below, though possibly only if a passphrase is
         * specified directly. */
        if (st.st_mode & 0005)
            log_debug("/etc/crypttab is world-readable. This is usually not a good idea.");

        for (;;) {
            char line[LINE_MAX], *l;
            _cleanup_free_ char *name = NULL, *device = NULL, *password = NULL, *options = NULL;
            int k;

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

            n++;

            l = strstrip(line);
            if (*l == '#' || *l == 0)
                continue;

            k = sscanf(l, "%ms %ms %ms %ms", &name, &device, &password, &options);
            if (k < 2 || k > 4) {
                log_error("Failed to parse /etc/crypttab:%u, ignoring.", n);
                continue;
            }

            /*
              If options are specified on the kernel commandline, let them override
              the ones from crypttab.
            */
            STRV_FOREACH(i, arg_options) {
                _cleanup_free_ char *proc_uuid = NULL, *proc_options = NULL;
                const char *p = *i;

                k = sscanf(p, "%m[0-9a-fA-F-]=%ms", &proc_uuid, &proc_options);
                if (k == 2 && streq(proc_uuid, device + 5)) {
                    free(options);
                    options = strdup(p);
                    if (!proc_options) {
                        log_oom();
                        goto cleanup;
                    }
                }
            }

            if (arg_disks) {
                /*
                  If luks UUIDs are specified on the kernel command line, use them as a filter
                  for /etc/crypttab and only generate units for those.
                */
                STRV_FOREACH(i, arg_disks) {
                    _cleanup_free_ char *proc_device = NULL, *proc_name = NULL;
                    const char *p = *i;

                    if (startswith(p, "luks-"))
                        p += 5;

                    proc_name = strappend("luks-", p);
                    proc_device = strappend("UUID=", p);

                    if (!proc_name || !proc_device) {
                        log_oom();
                        goto cleanup;
                    }

                    if (streq(proc_device, device) || streq(proc_name, name)) {
                        if (create_disk(name, device, password, options) < 0)
                            goto cleanup;

                        if (strv_extend(&disks_done, p) < 0) {
                            log_oom();
                            goto cleanup;
                        }
                    }
                }
            } else if (create_disk(name, device, password, options) < 0)
예제 #24
0
파일: localectl.c 프로젝트: ariscop/systemd
static int list_x11_keymaps(sd_bus *bus, char **args, unsigned n) {
        _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;

        if (n > 2) {
                log_error("Too many arguments.");
                return -EINVAL;
        }

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

        if (streq(args[0], "list-x11-keymap-models"))
                look_for = MODELS;
        else if (streq(args[0], "list-x11-keymap-layouts"))
                look_for = LAYOUTS;
        else if (streq(args[0], "list-x11-keymap-variants"))
                look_for = VARIANTS;
        else if (streq(args[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 (n > 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, args[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);

        pager_open_if_enabled();

        strv_print(list);
        return 0;
}
예제 #25
0
파일: journalctl.c 프로젝트: kwirk/systemd
static int parse_argv(int argc, char *argv[]) {

        enum {
                ARG_VERSION = 0x100,
                ARG_NO_PAGER,
                ARG_NO_TAIL,
                ARG_NEW_ID128,
                ARG_ROOT,
                ARG_HEADER,
                ARG_FULL,
                ARG_SETUP_KEYS,
                ARG_INTERVAL,
                ARG_VERIFY,
                ARG_VERIFY_KEY,
                ARG_DISK_USAGE,
                ARG_SINCE,
                ARG_UNTIL,
                ARG_USER_UNIT,
                ARG_LIST_CATALOG,
                ARG_DUMP_CATALOG,
                ARG_UPDATE_CATALOG
        };

        static const struct option options[] = {
                { "help",         no_argument,       NULL, 'h'              },
                { "version" ,     no_argument,       NULL, ARG_VERSION      },
                { "no-pager",     no_argument,       NULL, ARG_NO_PAGER     },
                { "pager-end",    no_argument,       NULL, 'e'              },
                { "follow",       no_argument,       NULL, 'f'              },
                { "output",       required_argument, NULL, 'o'              },
                { "all",          no_argument,       NULL, 'a'              },
                { "full",         no_argument,       NULL, ARG_FULL         },
                { "lines",        optional_argument, NULL, 'n'              },
                { "no-tail",      no_argument,       NULL, ARG_NO_TAIL      },
                { "new-id128",    no_argument,       NULL, ARG_NEW_ID128    },
                { "quiet",        no_argument,       NULL, 'q'              },
                { "merge",        no_argument,       NULL, 'm'              },
                { "this-boot",    no_argument,       NULL, 'b'              },
                { "directory",    required_argument, NULL, 'D'              },
                { "root",         required_argument, NULL, ARG_ROOT         },
                { "header",       no_argument,       NULL, ARG_HEADER       },
                { "priority",     required_argument, NULL, 'p'              },
                { "setup-keys",   no_argument,       NULL, ARG_SETUP_KEYS   },
                { "interval",     required_argument, NULL, ARG_INTERVAL     },
                { "verify",       no_argument,       NULL, ARG_VERIFY       },
                { "verify-key",   required_argument, NULL, ARG_VERIFY_KEY   },
                { "disk-usage",   no_argument,       NULL, ARG_DISK_USAGE   },
                { "cursor",       required_argument, NULL, 'c'              },
                { "since",        required_argument, NULL, ARG_SINCE        },
                { "until",        required_argument, NULL, ARG_UNTIL        },
                { "unit",         required_argument, NULL, 'u'              },
                { "user-unit",    required_argument, NULL, ARG_USER_UNIT    },
                { "field",        required_argument, NULL, 'F'              },
                { "catalog",      no_argument,       NULL, 'x'              },
                { "list-catalog", no_argument,       NULL, ARG_LIST_CATALOG },
                { "dump-catalog", no_argument,       NULL, ARG_DUMP_CATALOG },
                { "update-catalog",no_argument,      NULL, ARG_UPDATE_CATALOG },
                { "reverse",      no_argument,       NULL, 'r'              },
                { NULL,           0,                 NULL, 0                }
        };

        int c, r;

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

        while ((c = getopt_long(argc, argv, "hefo:an::qmbD:p:c:u:F:xr", options, NULL)) >= 0) {

                switch (c) {

                case 'h':
                        help();
                        return 0;

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

                case ARG_NO_PAGER:
                        arg_no_pager = true;
                        break;

                case 'e':
                        arg_pager_end = true;

                        if (arg_lines < 0)
                                arg_lines = 1000;

                        break;

                case 'f':
                        arg_follow = true;
                        break;

                case 'o':
                        arg_output = output_mode_from_string(optarg);
                        if (arg_output < 0) {
                                log_error("Unknown output format '%s'.", optarg);
                                return -EINVAL;
                        }

                        if (arg_output == OUTPUT_EXPORT ||
                            arg_output == OUTPUT_JSON ||
                            arg_output == OUTPUT_JSON_PRETTY ||
                            arg_output == OUTPUT_JSON_SSE ||
                            arg_output == OUTPUT_CAT)
                                arg_quiet = true;

                        break;

                case ARG_FULL:
                        arg_full = true;
                        break;

                case 'a':
                        arg_all = true;
                        break;

                case 'n':
                        if (optarg) {
                                r = safe_atoi(optarg, &arg_lines);
                                if (r < 0 || arg_lines < 0) {
                                        log_error("Failed to parse lines '%s'", optarg);
                                        return -EINVAL;
                                }
                        } else {
                                int n;

                                /* Hmm, no argument? Maybe the next
                                 * word on the command line is
                                 * supposed to be the argument? Let's
                                 * see if there is one, and is
                                 * parsable as a positive
                                 * integer... */

                                if (optind < argc &&
                                    safe_atoi(argv[optind], &n) >= 0 &&
                                    n >= 0) {

                                        arg_lines = n;
                                        optind++;
                                } else
                                        arg_lines = 10;
                        }

                        break;

                case ARG_NO_TAIL:
                        arg_no_tail = true;
                        break;

                case ARG_NEW_ID128:
                        arg_action = ACTION_NEW_ID128;
                        break;

                case 'q':
                        arg_quiet = true;
                        break;

                case 'm':
                        arg_merge = true;
                        break;

                case 'b':
                        arg_this_boot = true;
                        break;

                case 'D':
                        arg_directory = optarg;
                        break;

                case ARG_ROOT:
                        arg_root = optarg;
                        break;

                case 'c':
                        arg_cursor = optarg;
                        break;

                case ARG_HEADER:
                        arg_action = ACTION_PRINT_HEADER;
                        break;

                case ARG_VERIFY:
                        arg_action = ACTION_VERIFY;
                        break;

                case ARG_DISK_USAGE:
                        arg_action = ACTION_DISK_USAGE;
                        break;

#ifdef HAVE_GCRYPT
                case ARG_SETUP_KEYS:
                        arg_action = ACTION_SETUP_KEYS;
                        break;


                case ARG_VERIFY_KEY:
                        arg_action = ACTION_VERIFY;
                        arg_verify_key = optarg;
                        arg_merge = false;
                        break;

                case ARG_INTERVAL:
                        r = parse_sec(optarg, &arg_interval);
                        if (r < 0 || arg_interval <= 0) {
                                log_error("Failed to parse sealing key change interval: %s", optarg);
                                return -EINVAL;
                        }
                        break;
#else
                case ARG_SETUP_KEYS:
                case ARG_VERIFY_KEY:
                case ARG_INTERVAL:
                        log_error("Forward-secure sealing not available.");
                        return -ENOTSUP;
#endif

                case 'p': {
                        const char *dots;

                        dots = strstr(optarg, "..");
                        if (dots) {
                                char *a;
                                int from, to, i;

                                /* a range */
                                a = strndup(optarg, dots - optarg);
                                if (!a)
                                        return log_oom();

                                from = log_level_from_string(a);
                                to = log_level_from_string(dots + 2);
                                free(a);

                                if (from < 0 || to < 0) {
                                        log_error("Failed to parse log level range %s", optarg);
                                        return -EINVAL;
                                }

                                arg_priorities = 0;

                                if (from < to) {
                                        for (i = from; i <= to; i++)
                                                arg_priorities |= 1 << i;
                                } else {
                                        for (i = to; i <= from; i++)
                                                arg_priorities |= 1 << i;
                                }

                        } else {
                                int p, i;

                                p = log_level_from_string(optarg);
                                if (p < 0) {
                                        log_error("Unknown log level %s", optarg);
                                        return -EINVAL;
                                }

                                arg_priorities = 0;

                                for (i = 0; i <= p; i++)
                                        arg_priorities |= 1 << i;
                        }

                        break;
                }

                case ARG_SINCE:
                        r = parse_timestamp(optarg, &arg_since);
                        if (r < 0) {
                                log_error("Failed to parse timestamp: %s", optarg);
                                return -EINVAL;
                        }
                        arg_since_set = true;
                        break;

                case ARG_UNTIL:
                        r = parse_timestamp(optarg, &arg_until);
                        if (r < 0) {
                                log_error("Failed to parse timestamp: %s", optarg);
                                return -EINVAL;
                        }
                        arg_until_set = true;
                        break;

                case 'u':
                        r = strv_extend(&arg_system_units, optarg);
                        if (r < 0)
                                return log_oom();
                        break;

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

                case '?':
                        return -EINVAL;

                case 'F':
                        arg_field = optarg;
                        break;

                case 'x':
                        arg_catalog = true;
                        break;

                case ARG_LIST_CATALOG:
                        arg_action = ACTION_LIST_CATALOG;
                        break;

                case ARG_DUMP_CATALOG:
                        arg_action = ACTION_DUMP_CATALOG;
                        break;

                case ARG_UPDATE_CATALOG:
                        arg_action = ACTION_UPDATE_CATALOG;
                        break;

                case 'r':
                        arg_reverse = true;
                        break;

                default:
                        log_error("Unknown option code %c", c);
                        return -EINVAL;
                }
        }

        if (arg_follow && !arg_no_tail && arg_lines < 0)
                arg_lines = 10;

        if (arg_since_set && arg_until_set && arg_since > arg_until) {
                log_error("--since= must be before --until=.");
                return -EINVAL;
        }

        if (arg_cursor && arg_since_set) {
                log_error("Please specify either --since= or --cursor=, not both.");
                return -EINVAL;
        }

        if (arg_follow && arg_reverse) {
                log_error("Please specify either --reverse= or --follow=, not both.");
                return -EINVAL;
        }

        return 1;
}