diff --git a/man/homectl.xml b/man/homectl.xml index 82ea2e3943..a59efd7112 100644 --- a/man/homectl.xml +++ b/man/homectl.xml @@ -256,20 +256,21 @@ - + - Takes one of this, other, - any or auto. Some user record settings can be defined to match - only specific machines, or all machines but one, or all machines. With this switch it is possibly to - control to which machines to apply the settings appearing on the command line after it. If - this is specified the setting will only apply to the local system (positive - match), if other it will apply to all but the local system (negative match), if - any it will apply to all systems (unless there's a matching positive or negative - per-machine setting). If auto returns to the default logic: whether a setting - applies by default to the local system or all systems depends on the option in question. + Option takes one of this, + other, any or auto. Some user record + settings can be defined to match only specific machines, or all machines but one, or all machines. + With this switch it is possibly to control to which machines to apply the settings appearing on the + command line after it. If this is specified the setting will only apply to the + local system (positive match), if other it will apply to all but the local system + (negative match), if any it will apply to all systems (unless there's a matching + positive or negative per-machine setting). If auto returns to the default logic: + whether a setting applies by default to the local system or all systems depends on the option in + question. Note that only some user record settings can be conditioned like this. This option has no effect on the others and is ignored there. This option may appear multiple times in a single command diff --git a/src/cgtop/cgtop.c b/src/cgtop/cgtop.c index bb1b256902..60181caffc 100644 --- a/src/cgtop/cgtop.c +++ b/src/cgtop/cgtop.c @@ -702,13 +702,18 @@ static int help(void) { "Show top control groups by their resource usage.\n\n" " -h --help Show this help\n" " --version Show package version\n" - " -p --order=path Order by path\n" - " -t --order=tasks Order by number of tasks/processes\n" - " -c --order=cpu Order by CPU load (default)\n" - " -m --order=memory Order by memory load\n" - " -i --order=io Order by IO load\n" + + " --order=path|tasks|cpu|memory|io\n" + " Order by specified property\n" + " -p Same as --order=path, order by path\n" + " -t Same as --order=tasks, order by number of\n" + " tasks/processes\n" + " -c Same as --order=cpu, order by CPU load\n" + " -m Same as --order=memory, order by memory load\n" + " -i Same as --order=io, order by IO load\n" " -r --raw Provide raw (not human-readable) numbers\n" - " --cpu=percentage Show CPU usage as percentage (default)\n" + " --cpu[=percentage]\n" + " Show CPU usage as percentage (default)\n" " --cpu=time Show CPU usage as time\n" " -P Count userspace processes instead of tasks (excl. kernel)\n" " -k Count all processes instead of tasks (incl. kernel)\n" diff --git a/src/cryptenroll/cryptenroll.c b/src/cryptenroll/cryptenroll.c index 86d57e964f..2a914a9b49 100644 --- a/src/cryptenroll/cryptenroll.c +++ b/src/cryptenroll/cryptenroll.c @@ -169,6 +169,58 @@ static int determine_default_node(void) { return 0; } +static int parse_wipe_slot(const char *arg) { + int r; + + assert(arg); + + if (isempty(arg)) { + arg_wipe_slots_mask = 0; + arg_wipe_slots_scope = WIPE_EXPLICIT; + return 0; + } + + for (const char *p = arg;;) { + _cleanup_free_ char *slot = NULL; + + r = extract_first_word(&p, &slot, ",", EXTRACT_DONT_COALESCE_SEPARATORS); + if (r == 0) + return 0; + if (r < 0) + return log_error_errno(r, "Failed to parse slot list: %s", arg); + + if (streq(slot, "all")) + arg_wipe_slots_scope = WIPE_ALL; + else if (streq(slot, "empty")) { + if (arg_wipe_slots_scope != WIPE_ALL) /* if "all" was specified before, that wins */ + arg_wipe_slots_scope = WIPE_EMPTY_PASSPHRASE; + } else if (streq(slot, "password")) + arg_wipe_slots_mask |= 1U << ENROLL_PASSWORD; + else if (streq(slot, "recovery")) + arg_wipe_slots_mask |= 1U << ENROLL_RECOVERY; + else if (streq(slot, "pkcs11")) + arg_wipe_slots_mask |= 1U << ENROLL_PKCS11; + else if (streq(slot, "fido2")) + arg_wipe_slots_mask |= 1U << ENROLL_FIDO2; + else if (streq(slot, "tpm2")) + arg_wipe_slots_mask |= 1U << ENROLL_TPM2; + else { + unsigned n; + + r = safe_atou(slot, &n); + if (r < 0) + return log_error_errno(r, "Failed to parse slot index: %s", slot); + if (n > INT_MAX) + return log_error_errno(SYNTHETIC_ERRNO(ERANGE), "Slot index out of range: %u", n); + + if (!GREEDY_REALLOC(arg_wipe_slots, arg_n_wipe_slots + 1)) + return log_oom(); + + arg_wipe_slots[arg_n_wipe_slots++] = (int) n; + } + } +} + static int help(void) { _cleanup_free_ char *link = NULL; int r; @@ -580,62 +632,16 @@ static int parse_argv(int argc, char *argv[]) { break; - case ARG_WIPE_SLOT: { - const char *p = optarg; - - if (isempty(optarg)) { - arg_wipe_slots_mask = 0; - arg_wipe_slots_scope = WIPE_EXPLICIT; - break; - } - - for (;;) { - _cleanup_free_ char *slot = NULL; - unsigned n; - - r = extract_first_word(&p, &slot, ",", EXTRACT_DONT_COALESCE_SEPARATORS); - if (r == 0) - break; - if (r < 0) - return log_error_errno(r, "Failed to parse slot list: %s", optarg); - - if (streq(slot, "all")) - arg_wipe_slots_scope = WIPE_ALL; - else if (streq(slot, "empty")) { - if (arg_wipe_slots_scope != WIPE_ALL) /* if "all" was specified before, that wins */ - arg_wipe_slots_scope = WIPE_EMPTY_PASSPHRASE; - } else if (streq(slot, "password")) - arg_wipe_slots_mask |= 1U << ENROLL_PASSWORD; - else if (streq(slot, "recovery")) - arg_wipe_slots_mask |= 1U << ENROLL_RECOVERY; - else if (streq(slot, "pkcs11")) - arg_wipe_slots_mask |= 1U << ENROLL_PKCS11; - else if (streq(slot, "fido2")) - arg_wipe_slots_mask |= 1U << ENROLL_FIDO2; - else if (streq(slot, "tpm2")) - arg_wipe_slots_mask |= 1U << ENROLL_TPM2; - else { - r = safe_atou(slot, &n); - if (r < 0) - return log_error_errno(r, "Failed to parse slot index: %s", slot); - if (n > INT_MAX) - return log_error_errno(SYNTHETIC_ERRNO(ERANGE), "Slot index out of range: %u", n); - - if (!GREEDY_REALLOC(arg_wipe_slots, arg_n_wipe_slots + 1)) - return log_oom(); - - arg_wipe_slots[arg_n_wipe_slots++] = (int) n; - } - } - break; - } - - case ARG_LIST_DEVICES: - r = blockdev_list(BLOCKDEV_LIST_SHOW_SYMLINKS|BLOCKDEV_LIST_REQUIRE_LUKS, /* ret_devices= */ NULL, /* ret_n_devices= */ NULL); + case ARG_WIPE_SLOT: + r = parse_wipe_slot(optarg); if (r < 0) return r; + break; - return 0; + case ARG_LIST_DEVICES: + return blockdev_list(BLOCKDEV_LIST_SHOW_SYMLINKS|BLOCKDEV_LIST_REQUIRE_LUKS, + /* ret_devices= */ NULL, + /* ret_n_devices= */ NULL); case '?': return -EINVAL; diff --git a/src/home/homectl.c b/src/home/homectl.c index c6a3d4b3eb..2b92ab6481 100644 --- a/src/home/homectl.c +++ b/src/home/homectl.c @@ -106,8 +106,6 @@ static int arg_fido2_cred_alg = 0; #endif static bool arg_recovery_key = false; static sd_json_format_flags_t arg_json_format_flags = SD_JSON_FORMAT_OFF; -static bool arg_and_resize = false; -static bool arg_and_change_password = false; static ExportFormat arg_export_format = EXPORT_FORMAT_FULL; static uint64_t arg_capability_bounding_set = CAP_MASK_UNSET; static uint64_t arg_capability_ambient_set = CAP_MASK_UNSET; @@ -1922,6 +1920,9 @@ static int update_home(int argc, char *argv[], void *userdata) { } else username = NULL; + bool and_change_password = !strv_isempty(arg_pkcs11_token_uri) || !strv_isempty(arg_fido2_device); + bool and_resize = arg_disk_size != UINT64_MAX || arg_disk_size_relative != UINT64_MAX; + r = acquire_bus(&bus); if (r < 0) return r; @@ -1953,7 +1954,7 @@ static int update_home(int argc, char *argv[], void *userdata) { /* If we do multiple operations, let's output things more verbosely, since otherwise the repeated * authentication might be confusing. */ - if (arg_and_resize || arg_and_change_password) + if (and_resize || and_change_password) log_info("Updating home directory."); if (arg_offline) @@ -1988,7 +1989,7 @@ static int update_home(int argc, char *argv[], void *userdata) { r = sd_bus_call(bus, m, HOME_SLOW_BUS_CALL_TIMEOUT_USEC, &error, NULL); if (r < 0) { - if (arg_and_change_password && + if (and_change_password && sd_bus_error_has_name(&error, BUS_ERROR_BAD_PASSWORD_AND_NO_TOKEN)) /* In the generic handler we'd ask for a password in this case, but when * changing passwords that's not sufficient, as we need to acquire all keys @@ -2002,13 +2003,13 @@ static int update_home(int argc, char *argv[], void *userdata) { break; } - if (arg_and_resize) + if (and_resize) log_info("Resizing home."); (void) home_record_reset_human_interaction_permission(hr); /* Also sync down disk size to underlying LUKS/fscrypt/quota */ - while (arg_and_resize) { + while (and_resize) { _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; @@ -2027,7 +2028,7 @@ static int update_home(int argc, char *argv[], void *userdata) { r = sd_bus_call(bus, m, HOME_SLOW_BUS_CALL_TIMEOUT_USEC, &error, NULL); if (r < 0) { - if (arg_and_change_password && + if (and_change_password && sd_bus_error_has_name(&error, BUS_ERROR_BAD_PASSWORD_AND_NO_TOKEN)) return log_error_errno(r, "Security token not inserted, refusing."); @@ -2038,13 +2039,13 @@ static int update_home(int argc, char *argv[], void *userdata) { break; } - if (arg_and_change_password) + if (and_change_password) log_info("Synchronizing passwords and encryption keys."); (void) home_record_reset_human_interaction_permission(hr); /* Also sync down passwords to underlying LUKS/fscrypt */ - while (arg_and_change_password) { + while (and_change_password) { _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; @@ -4156,8 +4157,6 @@ static int parse_argv(int argc, char *argv[]) { ARG_FIDO2_WITH_UP, ARG_FIDO2_WITH_UV, ARG_RECOVERY_KEY, - ARG_AND_RESIZE, - ARG_AND_CHANGE_PASSWORD, ARG_DROP_CACHES, ARG_LUKS_EXTRA_MOUNT_OPTIONS, ARG_AUTO_RESIZE_MODE, @@ -4266,8 +4265,6 @@ static int parse_argv(int argc, char *argv[]) { { "fido2-with-user-presence", required_argument, NULL, ARG_FIDO2_WITH_UP }, { "fido2-with-user-verification", required_argument, NULL, ARG_FIDO2_WITH_UV }, { "recovery-key", required_argument, NULL, ARG_RECOVERY_KEY }, - { "and-resize", required_argument, NULL, ARG_AND_RESIZE }, - { "and-change-password", required_argument, NULL, ARG_AND_CHANGE_PASSWORD }, { "drop-caches", required_argument, NULL, ARG_DROP_CACHES }, { "luks-extra-mount-options", required_argument, NULL, ARG_LUKS_EXTRA_MOUNT_OPTIONS }, { "auto-resize-mode", required_argument, NULL, ARG_AUTO_RESIZE_MODE }, @@ -4800,14 +4797,6 @@ static int parse_argv(int argc, char *argv[]) { break; - case ARG_AND_RESIZE: - arg_and_resize = true; - break; - - case ARG_AND_CHANGE_PASSWORD: - arg_and_change_password = true; - break; - case ARG_DROP_CACHES: r = parse_boolean_field(match_identity ?: &arg_identity_extra, "dropCaches", optarg); if (r < 0) @@ -5008,12 +4997,6 @@ static int parse_argv(int argc, char *argv[]) { } } - if (!strv_isempty(arg_pkcs11_token_uri) || !strv_isempty(arg_fido2_device)) - arg_and_change_password = true; - - if (arg_disk_size != UINT64_MAX || arg_disk_size_relative != UINT64_MAX) - arg_and_resize = true; - if (!strv_isempty(arg_languages)) { char **additional; diff --git a/src/import/importctl.c b/src/import/importctl.c index d131943413..eddddb86d1 100644 --- a/src/import/importctl.c +++ b/src/import/importctl.c @@ -1035,12 +1035,15 @@ static int help(int argc, char *argv[], void *userdata) { " --format=xz|gzip|bzip2|zstd\n" " Desired output format for export\n" " --force Install image even if already exists\n" - " -m --class=machine Install as machine image\n" - " -P --class=portable Install as portable service image\n" - " -S --class=sysext Install as system extension image\n" - " -C --class=confext Install as configuration extension image\n" + " --class=TYPE Install as the specified TYPE\n" + " -m Install as --class=machine, machine image\n" + " -P Install as --class=portable,\n" + " portable service image\n" + " -S Install as --class=sysext, system extension image\n" + " -C Install as --class=confext,\n" + " configuration extension image\n" " --keep-download=BOOL Control whether to keep pristine copy of download\n" - " -N Shortcut for --keep-download=no\n" + " -N Same as --keep-download=no\n" "\nSee the %2$s for details.\n", program_invocation_short_name, link, diff --git a/src/journal-remote/journal-upload.c b/src/journal-remote/journal-upload.c index decb6df5da..c6123146a5 100644 --- a/src/journal-remote/journal-upload.c +++ b/src/journal-remote/journal-upload.c @@ -776,8 +776,6 @@ static int parse_argv(int argc, char *argv[]) { assert(argc >= 0); assert(argv); - opterr = 0; - while ((c = getopt_long(argc, argv, "hu:mM:D:", options, NULL)) >= 0) switch (c) { case 'h': @@ -882,14 +880,7 @@ static int parse_argv(int argc, char *argv[]) { break; case '?': - return log_error_errno(SYNTHETIC_ERRNO(EINVAL), - "Unknown option %s.", - argv[optind - 1]); - - case ':': - return log_error_errno(SYNTHETIC_ERRNO(EINVAL), - "Missing argument to %s.", - argv[optind - 1]); + return -EINVAL; default: assert_not_reached(); diff --git a/src/mount/mount-tool.c b/src/mount/mount-tool.c index 7dd45aacea..24b93e1239 100644 --- a/src/mount/mount-tool.c +++ b/src/mount/mount-tool.c @@ -141,7 +141,8 @@ static int help(void) { " --fsck=no Don't run file system check before mount\n" " --description=TEXT Description for unit\n" " -p --property=NAME=VALUE Set mount unit property\n" - " -A --automount=BOOL Create an auto-mount point\n" + " --automount=BOOL Create an automount point\n" + " -A Same as --automount=yes\n" " --timeout-idle-sec=SEC Specify automount idle timeout\n" " --automount-property=NAME=VALUE\n" " Set automount unit property\n" diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index d2adc64931..1c0ab6e712 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -292,6 +292,71 @@ STATIC_DESTRUCTOR_REGISTER(arg_settings_filename, freep); STATIC_DESTRUCTOR_REGISTER(arg_image_policy, image_policy_freep); STATIC_DESTRUCTOR_REGISTER(arg_background, freep); +static int parse_private_users( + const char *s, + UserNamespaceMode *ret_userns_mode, + uid_t *ret_uid_shift, + uid_t *ret_uid_range) { + + int boolean, r; + + assert(ret_userns_mode); + assert(ret_uid_shift); + assert(ret_uid_range); + + if (!s) + boolean = true; + else if (!in_charset(s, DIGITS)) + /* do *not* parse numbers as booleans */ + boolean = parse_boolean(s); + else + boolean = -1; + + if (boolean == 0) { + /* no: User namespacing off */ + *ret_userns_mode = USER_NAMESPACE_NO; + *ret_uid_shift = UID_INVALID; + *ret_uid_range = UINT32_C(0x10000); + + } else if (boolean > 0) { + /* yes: User namespacing on, UID range is read from root dir */ + *ret_userns_mode = USER_NAMESPACE_FIXED; + *ret_uid_shift = UID_INVALID; + *ret_uid_range = UINT32_C(0x10000); + + } else if (streq(s, "pick")) { + /* pick: User namespacing on, UID range is picked randomly */ + *ret_userns_mode = USER_NAMESPACE_PICK; /* Note that arg_userns_ownership is + * implied by USER_NAMESPACE_PICK + * further down. */ + *ret_uid_shift = UID_INVALID; + *ret_uid_range = UINT32_C(0x10000); + + } else if (streq(s, "identity")) { + /* identity: User namespaces on, UID range is map of the 0…0xFFFF range to + * itself, i.e. we don't actually map anything, but do take benefit of + * isolation of capability sets. */ + *ret_userns_mode = USER_NAMESPACE_FIXED; + *ret_uid_shift = 0; + *ret_uid_range = UINT32_C(0x10000); + + } else if (streq(optarg, "managed")) { + /* managed: User namespace on, and acquire it from systemd-nsresourced */ + *ret_userns_mode = USER_NAMESPACE_MANAGED; + *ret_uid_shift = UID_INVALID; + *ret_uid_range = UINT32_C(0x10000); + + } else { + /* anything else: User namespacing on, UID range is explicitly configured */ + r = parse_userns_uid_range(optarg, ret_uid_shift, ret_uid_range); + if (r < 0) + return r; + *ret_userns_mode = USER_NAMESPACE_FIXED; + } + + return 0; +} + static int help(void) { _cleanup_free_ char *link = NULL; int r; @@ -942,31 +1007,23 @@ static int parse_argv(int argc, char *argv[]) { } case 'M': - if (isempty(optarg)) - arg_machine = mfree(arg_machine); - else { - if (!hostname_is_valid(optarg, 0)) - return log_error_errno(SYNTHETIC_ERRNO(EINVAL), - "Invalid machine name: %s", optarg); + if (!isempty(optarg) && !hostname_is_valid(optarg, /* flags= */ 0)) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), + "Invalid machine name: %s", optarg); - r = free_and_strdup(&arg_machine, optarg); - if (r < 0) - return log_oom(); - } + r = free_and_strdup_warn(&arg_machine, optarg); + if (r < 0) + return r; break; case ARG_HOSTNAME: - if (isempty(optarg)) - arg_hostname = mfree(arg_hostname); - else { - if (!hostname_is_valid(optarg, 0)) - return log_error_errno(SYNTHETIC_ERRNO(EINVAL), - "Invalid hostname: %s", optarg); + if (!isempty(optarg) && !hostname_is_valid(optarg, /* flags= */ 0)) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), + "Invalid hostname: %s", optarg); - r = free_and_strdup(&arg_hostname, optarg); - if (r < 0) - return log_oom(); - } + r = free_and_strdup_warn(&arg_hostname, optarg); + if (r < 0) + return r; arg_settings_mask |= SETTING_HOSTNAME; break; @@ -1141,58 +1198,13 @@ static int parse_argv(int argc, char *argv[]) { break; - case ARG_PRIVATE_USERS: { - int boolean; - - if (!optarg) - boolean = true; - else if (!in_charset(optarg, DIGITS)) - /* do *not* parse numbers as booleans */ - boolean = parse_boolean(optarg); - else - boolean = -1; - - if (boolean == 0) { - /* no: User namespacing off */ - arg_userns_mode = USER_NAMESPACE_NO; - arg_uid_shift = UID_INVALID; - arg_uid_range = UINT32_C(0x10000); - } else if (boolean > 0) { - /* yes: User namespacing on, UID range is read from root dir */ - arg_userns_mode = USER_NAMESPACE_FIXED; - arg_uid_shift = UID_INVALID; - arg_uid_range = UINT32_C(0x10000); - } else if (streq(optarg, "pick")) { - /* pick: User namespacing on, UID range is picked randomly */ - arg_userns_mode = USER_NAMESPACE_PICK; /* Note that arg_userns_ownership is - * implied by USER_NAMESPACE_PICK - * further down. */ - arg_uid_shift = UID_INVALID; - arg_uid_range = UINT32_C(0x10000); - - } else if (streq(optarg, "identity")) { - /* identity: User namespaces on, UID range is map of the 0…0xFFFF range to - * itself, i.e. we don't actually map anything, but do take benefit of - * isolation of capability sets. */ - arg_userns_mode = USER_NAMESPACE_FIXED; - arg_uid_shift = 0; - arg_uid_range = UINT32_C(0x10000); - } else if (streq(optarg, "managed")) { - /* managed: User namespace on, and acquire it from systemd-nsresourced */ - arg_userns_mode = USER_NAMESPACE_MANAGED; - arg_uid_shift = UID_INVALID; - arg_uid_range = UINT32_C(0x10000); - } else { - /* anything else: User namespacing on, UID range is explicitly configured */ - r = parse_userns_uid_range(optarg, &arg_uid_shift, &arg_uid_range); - if (r < 0) - return r; - arg_userns_mode = USER_NAMESPACE_FIXED; - } + case ARG_PRIVATE_USERS: + r = parse_private_users(optarg, &arg_userns_mode, &arg_uid_shift, &arg_uid_range); + if (r < 0) + return r; arg_settings_mask |= SETTING_USERNS; break; - } case 'U': if (userns_supported()) { diff --git a/src/path/path-tool.c b/src/path/path-tool.c index 227468dfe8..62eade3b05 100644 --- a/src/path/path-tool.c +++ b/src/path/path-tool.c @@ -250,13 +250,11 @@ static int run(int argc, char* argv[]) { if (r <= 0) return r; - if (argc > optind) { - r = 0; - for (int i = optind; i < argc; i++) - RET_GATHER(r, print_path(argv[i])); - } else - r = list_paths(); + if (optind >= argc) + return list_paths(); + for (int i = optind; i < argc; i++) + RET_GATHER(r, print_path(argv[i])); return r; } diff --git a/src/resolve/resolvconf-compat.c b/src/resolve/resolvconf-compat.c index 47abdc900f..d8e68d524a 100644 --- a/src/resolve/resolvconf-compat.c +++ b/src/resolve/resolvconf-compat.c @@ -14,6 +14,12 @@ #include "string-util.h" #include "strv.h" +typedef enum LookupType { + LOOKUP_TYPE_REGULAR, + LOOKUP_TYPE_PRIVATE, + LOOKUP_TYPE_EXCLUSIVE, /* -x */ +} LookupType; + static int resolvconf_help(void) { _cleanup_free_ char *link = NULL; int r; @@ -94,6 +100,75 @@ static int parse_search_domain(const char *string) { return 0; } +static int parse_stdin(LookupType lookup_type) { + int r; + + for (unsigned n = 0;;) { + _cleanup_free_ char *line = NULL; + const char *a; + + r = read_stripped_line(stdin, LONG_LINE_MAX, &line); + if (r < 0) + return log_error_errno(r, "Failed to read from stdin: %m"); + if (r == 0) + break; + n++; + + if (IN_SET(*line, '#', ';', 0)) + continue; + + a = first_word(line, "nameserver"); + if (a) { + (void) parse_nameserver(a); + continue; + } + + a = first_word(line, "domain"); + if (!a) + a = first_word(line, "search"); + if (a) { + (void) parse_search_domain(a); + continue; + } + + log_syntax(NULL, LOG_DEBUG, "stdin", n, 0, "Ignoring resolv.conf line: %s", line); + } + + switch (lookup_type) { + case LOOKUP_TYPE_REGULAR: + break; + + case LOOKUP_TYPE_PRIVATE: + arg_disable_default_route = true; + break; + + case LOOKUP_TYPE_EXCLUSIVE: + /* If -x mode is selected, let's preferably route non-suffixed lookups to this interface. + * This somewhat matches the original -x behaviour */ + + r = strv_extend(&arg_set_domain, "~."); + if (r < 0) + return log_oom(); + break; + + default: + assert_not_reached(); + } + + if (strv_isempty(arg_set_dns)) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), + "No DNS servers specified, refusing operation."); + + if (strv_isempty(arg_set_domain)) { + /* When no domain/search is set, clear the current domains. */ + r = strv_extend(&arg_set_domain, ""); + if (r < 0) + return log_oom(); + } + + return 0; +} + int resolvconf_parse_argv(int argc, char *argv[]) { enum { @@ -114,22 +189,18 @@ int resolvconf_parse_argv(int argc, char *argv[]) { {} }; - enum { - TYPE_REGULAR, - TYPE_PRIVATE, - TYPE_EXCLUSIVE, /* -x */ - } type = TYPE_REGULAR; - int c, r; assert(argc >= 0); assert(argv); /* openresolv checks these environment variables */ + LookupType lookup_type = LOOKUP_TYPE_REGULAR; + if (getenv("IF_EXCLUSIVE")) - type = TYPE_EXCLUSIVE; + lookup_type = LOOKUP_TYPE_EXCLUSIVE; if (getenv("IF_PRIVATE")) - type = TYPE_PRIVATE; + lookup_type = LOOKUP_TYPE_PRIVATE; arg_mode = _MODE_INVALID; @@ -153,11 +224,11 @@ int resolvconf_parse_argv(int argc, char *argv[]) { /* The exclusive/private/force stuff is an openresolv invention, we support in some skewed way */ case 'x': - type = TYPE_EXCLUSIVE; + lookup_type = LOOKUP_TYPE_EXCLUSIVE; break; case 'p': - type = TYPE_PRIVATE; + lookup_type = LOOKUP_TYPE_PRIVATE; break; case 'f': @@ -215,75 +286,12 @@ int resolvconf_parse_argv(int argc, char *argv[]) { r = ifname_resolvconf_mangle(argv[optind]); if (r <= 0) return r; - optind++; if (arg_mode == MODE_SET_LINK) { - unsigned n = 0; - - for (;;) { - _cleanup_free_ char *line = NULL; - const char *a; - - r = read_stripped_line(stdin, LONG_LINE_MAX, &line); - if (r < 0) - return log_error_errno(r, "Failed to read from stdin: %m"); - if (r == 0) - break; - - n++; - - if (IN_SET(*line, '#', ';', 0)) - continue; - - a = first_word(line, "nameserver"); - if (a) { - (void) parse_nameserver(a); - continue; - } - - a = first_word(line, "domain"); - if (!a) - a = first_word(line, "search"); - if (a) { - (void) parse_search_domain(a); - continue; - } - - log_syntax(NULL, LOG_DEBUG, "stdin", n, 0, "Ignoring resolv.conf line: %s", line); - } - - switch (type) { - case TYPE_REGULAR: - break; - - case TYPE_PRIVATE: - arg_disable_default_route = true; - break; - - case TYPE_EXCLUSIVE: - /* If -x mode is selected, let's preferably route non-suffixed lookups to this interface. This - * somewhat matches the original -x behaviour */ - - r = strv_extend(&arg_set_domain, "~."); - if (r < 0) - return log_oom(); - break; - - default: - assert_not_reached(); - } - - if (strv_isempty(arg_set_dns)) - return log_error_errno(SYNTHETIC_ERRNO(EINVAL), - "No DNS servers specified, refusing operation."); - - if (strv_isempty(arg_set_domain)) { - /* When no domain/search is set, clear the current domains. */ - r = strv_extend(&arg_set_domain, ""); - if (r < 0) - return log_oom(); - } + r = parse_stdin(lookup_type); + if (r < 0) + return r; } return 1; /* work to do */