Fixes for option parsing (#40641)
Preparatory work split out of #40624.
This commit is contained in:
+11
-10
@@ -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
@@ -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"
|
||||
|
||||
@@ -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
@@ -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;
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
@@ -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()) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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 */
|
||||
|
||||
Reference in New Issue
Block a user