in the file system. In this case, the UID/GID is read from the
path's owner/group. This is useful to create users whose UID/GID
match the owners of pre-existing files (such as SUID or SGID
- binaries).</para>
+ binaries).
+ The syntax <literal><replaceable>uid</replaceable>:<replaceable>gid</replaceable></literal> is also supported to
+ allow creating user and group pairs with different numeric UID and GID values. If a group with the indicated GID already exists it is not created.
+ </para>
<para>For <varname>m</varname> lines, this field should contain
the group name to add to a user to.</para>
uid_t uid;
bool gid_set:1;
+ bool gid_existing_ok:1;
bool uid_set:1;
bool todo_user:1;
return log_error_errno(r, "Failed to verify gid " GID_FMT ": %m", i->gid);
if (r == 0) {
log_debug("Suggested group ID " GID_FMT " for %s already used.", i->gid, i->name);
+ if (i->gid_existing_ok)
+ return 0;
i->gid_set = false;
}
}
path_kill_slashes(i->uid_path);
} else {
- r = parse_uid(resolved_id, &i->uid);
- if (r < 0) {
- log_error("Failed to parse UID: %s", id);
- return -EBADMSG;
+ _cleanup_free_ char *uid = NULL, *gid = NULL;
+ if (split_pair(resolved_id, ":", &uid, &gid) == 0) {
+ r = parse_gid(gid, &i->gid);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse GID: '%s': %m", id);
+ i->gid_set = true;
+ i->gid_existing_ok = true;
+ free_and_replace(resolved_id, uid);
}
+ r = parse_uid(resolved_id, &i->uid);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse UID: '%s': %m", id);
i->uid_set = true;
}
path_kill_slashes(i->gid_path);
} else {
r = parse_gid(resolved_id, &i->gid);
- if (r < 0) {
- log_error("Failed to parse GID: %s", id);
- return -EBADMSG;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse GID: '%s': %m", id);
i->gid_set = true;
}