Nspawn arguments parsing and man page update#4319
Conversation
The documentation says lists "yes", "no", "pick", and numeric arguments. But parse_boolean was attempted first, so various numeric arguments were misinterpreted. In particular, this fixes --private-users=0 to mean the same thing as --private-users=0:65536. While at it, use strndupa to avoid some error handling. Also give a better error for an empty UID range. I think it's likely that people will use --private-users=0:0 thinking that the argument means UID:GID.
man/systemd-nspawn.xml
Outdated
| <para>Note that <option>-U</option> is the default if the <filename>[email protected]</filename> template unit | ||
| file is used.</para> | ||
|
|
||
| <para>Note: it is possible to undo the effect of <option>--private-users-chown</option> (or <option>-U</option>) |
There was a problem hiding this comment.
@keszybz , thanks! I'll test this PR tomorrow.
I think it's not clear what does undo the effect of --private-users-chown (or -U) mean. The full redo is:
machinectl stop cont(or^]]])systemd-nspawn --private-users=0machinectl stop cont(or]]])systemd-nspawn (without -U)
There was a problem hiding this comment.
BTW: I think it would be great to run something
systemd-nspawn --uidshift ... --dont-spawn-container
Similar to fuidshift :-)
There was a problem hiding this comment.
Considering how simple this is, I don't see a good reason not to do this. I only wonder what the best way to expose this would be. IMHO it should be a separate command-like option that would take the same argument as --private-users. I'm only not sure whether this should be in systemd-nspawn or in one of the other tools.
There was a problem hiding this comment.
I'm only not sure whether this should be in systemd-nspawn or in one of the other tools
Maybe, systemd-fuidshift ? :-)
| arg_uid_shift = UID_INVALID; | ||
| arg_uid_range = UINT32_C(0x10000); | ||
| } else if (r > 0) { | ||
| } else if (!optarg || streq(optarg, "yes")) { |
There was a problem hiding this comment.
Indeed. --private-users=0 works fine. Thanks!
But --private-users=[y|n|true|false|t|f|on|off] is not working. I'm not sure we should break this.
Looks good otherwise
There was a problem hiding this comment.
The man page explicitly lists "yes" and "no". It does not say "a boolean". I think that accepting all kind of booleans except for the numerical ones would only increase chances of confusion.
There was a problem hiding this comment.
We do this "extended" boolean logic all the time, I think we should do the same here. i.e. first parse the parameter as something other, and if that fails as true boolean with our usual parse_boolean() call... I'd agree with @evverx, we should also be able to use --private-users=true here...
Now that [email protected] includes -U, more users might be interested in this tidbit ;)
d6d7b16 to
6265bde
Compare
This is definitely unrelated to this PR (and logs are OK, hm). I'm merging. |
poettering
left a comment
There was a problem hiding this comment.
Hmm, I added three more comments. The strndupa() issue really matters and needs fixing.
| arg_uid_shift = UID_INVALID; | ||
| arg_uid_range = UINT32_C(0x10000); | ||
| } else if (r > 0) { | ||
| } else if (!optarg || streq(optarg, "yes")) { |
There was a problem hiding this comment.
We do this "extended" boolean logic all the time, I think we should do the same here. i.e. first parse the parameter as something other, and if that fails as true boolean with our usual parse_boolean() call... I'd agree with @evverx, we should also be able to use --private-users=true here...
| if (!buffer) | ||
| return log_oom(); | ||
| shift = buffer; | ||
| shift = strndupa(optarg, range - optarg); |
There was a problem hiding this comment.
This is no OK, you may not call strndupa() (which means alloca()) in a loop, but we are in a while loop around getopt...
| if (r < 0) | ||
| return log_error_errno(r, "Failed to parse UID range '%s': %m", range); | ||
| if (arg_uid_range == 0) | ||
| return log_error_errno(EINVAL, "UID range cannot be 0."); |
There was a problem hiding this comment.
So far we tried to log about error numbers we receive from some call, but not about error numbers we generate (never forget that log_error_errno() attaches an ERRNO= field to the journal entry for the msg). I think this should hence be written as:
if (arg_uid_range == 0) {
log_error("UID range cannot be 0.");
return -EINVAL;
}There was a problem hiding this comment.
Is this a reason why do we use so many:
log_*(...)
return -*
in nspawn?
There was a problem hiding this comment.
@evverx well, depends. basically, I think we should never do log_error_errno() and then specify a literal as first argument. That's all. Because in that case we are generating the error code, not receiving it. And I doubt we should log about that. It's the caller which should (or should not) log about the error code then...
There was a problem hiding this comment.
It's not so obvious. I think it would be useful to add this rule to the CODING_STYLE
There was a problem hiding this comment.
I know we have this rule, but I'm not convinced it's right. After all
return log_error_errno(EINVAL, "…");
is much more concise and thus much clearer then
{
log_error("…");
return -EINVAL;
}
I'd say that the practicality of the short form beats the purity of the long one.
Indeed, instead of setting this rule in stone, I'd rather rescind it, and allow judicious use of the shortened form with the hardcoded return errno. The only time where it should not be imo allowed, would be when the errno value makes no sense (i..e. when we return ESRCH or ENOMEDIUM because we need to pass some state to the caller and we use a fake errno that is special-cased in the caller).
No description provided.