Fixes for option parsing (#40641)

Preparatory work split out of #40624.
This commit is contained in:
Yu Watanabe
2026-02-14 04:58:50 +09:00
committed by GitHub
10 changed files with 271 additions and 263 deletions
+11 -10
View File
@@ -256,20 +256,21 @@
</varlistentry>
<varlistentry>
<term><option>--match=</option></term>
<term><option>--match=this|other|any|auto</option></term>
<term><option>-A</option></term>
<term><option>-N</option></term>
<term><option>-T</option></term>
<listitem><para>Takes one of <literal>this</literal>, <literal>other</literal>,
<literal>any</literal> or <literal>auto</literal>. 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
<literal>this</literal> is specified the setting will only apply to the local system (positive
match), if <literal>other</literal> it will apply to all but the local system (negative match), if
<literal>any</literal> it will apply to all systems (unless there's a matching positive or negative
per-machine setting). If <literal>auto</literal> returns to the default logic: whether a setting
applies by default to the local system or all systems depends on the option in question.</para>
<listitem><para>Option <option>--match=</option> takes one of <literal>this</literal>,
<literal>other</literal>, <literal>any</literal> or <literal>auto</literal>. 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 <literal>this</literal> is specified the setting will only apply to the
local system (positive match), if <literal>other</literal> it will apply to all but the local system
(negative match), if <literal>any</literal> it will apply to all systems (unless there's a matching
positive or negative per-machine setting). If <literal>auto</literal> returns to the default logic:
whether a setting applies by default to the local system or all systems depends on the option in
question.</para>
<para>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
+11 -6
View File
@@ -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"
+59 -53
View File
@@ -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;
+10 -27
View File
@@ -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;
+8 -5
View File
@@ -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,
+1 -10
View File
@@ -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();
+2 -1
View File
@@ -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"
+81 -69
View File
@@ -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()) {
+4 -6
View File
@@ -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;
}
+84 -76
View File
@@ -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 */