diff --git a/man/systemd-tmpfiles.xml b/man/systemd-tmpfiles.xml index 5612b4803d..a6246844cb 100644 --- a/man/systemd-tmpfiles.xml +++ b/man/systemd-tmpfiles.xml @@ -148,6 +148,12 @@ + + + Ignore configuration lines pertaining to unknown users or groups. This option is + intended to be used in early boot before all users or groups have been created. + + Only apply rules with paths that start with diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c index 5232f17de7..518d8012da 100644 --- a/src/tmpfiles/tmpfiles.c +++ b/src/tmpfiles/tmpfiles.c @@ -200,6 +200,7 @@ static bool arg_cat_config = false; static RuntimeScope arg_runtime_scope = RUNTIME_SCOPE_SYSTEM; static OperationMask arg_operation = 0; static bool arg_boot = false; +static bool arg_graceful = false; static PagerFlags arg_pager_flags = 0; static char **arg_include_prefixes = NULL; @@ -1131,7 +1132,8 @@ static int parse_acls_from_arg(Item *item) { r = parse_acl(item->argument, &item->acl_access, &item->acl_access_exec, &item->acl_default, !item->append_or_force); if (r < 0) - log_warning_errno(r, "Failed to parse ACL \"%s\", ignoring: %m", item->argument); + log_full_errno(arg_graceful && IN_SET(r, -ENOENT, -ESRCH) ? LOG_DEBUG : LOG_WARNING, + r, "Failed to parse ACL \"%s\", ignoring: %m", item->argument); #else log_warning("ACLs are not supported, ignoring."); #endif @@ -3322,7 +3324,8 @@ static int parse_line( ItemArray *existing; OrderedHashmap *h; int r, pos; - bool append_or_force = false, boot = false, allow_failure = false, try_replace = false, unbase64 = false, from_cred = false; + bool append_or_force = false, boot = false, allow_failure = false, try_replace = false, + unbase64 = false, from_cred = false, missing_user_or_group = false; assert(fname); assert(line >= 1); @@ -3669,12 +3672,15 @@ static int parse_line( u = user; r = find_uid(u, &i.uid, uid_cache); - if (r < 0) { + if (r == -ESRCH && arg_graceful) { + log_syntax(NULL, LOG_DEBUG, fname, line, r, + "%s: user '%s' not found, not adjusting ownership.", i.path, u); + missing_user_or_group = true; + } else if (r < 0) { *invalid_config = true; return log_syntax(NULL, LOG_ERR, fname, line, r, "Failed to resolve user '%s': %m", u); - } - - i.uid_set = true; + } else + i.uid_set = true; } if (!empty_or_dash(group)) { @@ -3687,12 +3693,15 @@ static int parse_line( g = group; r = find_gid(g, &i.gid, gid_cache); - if (r < 0) { + if (r == -ESRCH && arg_graceful) { + log_syntax(NULL, LOG_DEBUG, fname, line, r, + "%s: group '%s' not found, not adjusting ownership.", i.path, g); + missing_user_or_group = true; + } else if (r < 0) { *invalid_config = true; - return log_syntax(NULL, LOG_ERR, fname, line, r, "Failed to resolve group '%s'.", g); - } - - i.gid_set = true; + return log_syntax(NULL, LOG_ERR, fname, line, r, "Failed to resolve group '%s': %m", g); + } else + i.gid_set = true; } if (!empty_or_dash(mode)) { @@ -3724,6 +3733,14 @@ static int parse_line( CREATE_SUBVOLUME_INHERIT_QUOTA, CREATE_SUBVOLUME_NEW_QUOTA) ? 0755 : 0644; + if (missing_user_or_group && (i.mode & ~0777) != 0) { + /* Refuse any special bits for nodes where we couldn't resolve the ownership properly. */ + mode_t adjusted = i.mode & 0777; + log_syntax(NULL, LOG_INFO, fname, line, 0, + "Changing mode 0%o to 0%o because of changed ownership.", i.mode, adjusted); + i.mode = adjusted; + } + if (!empty_or_dash(age)) { const char *a = age; _cleanup_free_ char *seconds = NULL, *age_by = NULL; @@ -3844,6 +3861,7 @@ static int help(void) { " --clean Clean up marked directories\n" " --remove Remove marked files/directories\n" " --boot Execute actions only safe at boot\n" + " --graceful Quitely ignore unknown users or groups\n" " --prefix=PATH Only apply rules with the specified prefix\n" " --exclude-prefix=PATH Ignore rules with the specified prefix\n" " -E Ignore rules prefixed with /dev, /proc, /run, /sys\n" @@ -3871,6 +3889,7 @@ static int parse_argv(int argc, char *argv[]) { ARG_CLEAN, ARG_REMOVE, ARG_BOOT, + ARG_GRACEFUL, ARG_PREFIX, ARG_EXCLUDE_PREFIX, ARG_ROOT, @@ -3889,6 +3908,7 @@ static int parse_argv(int argc, char *argv[]) { { "clean", no_argument, NULL, ARG_CLEAN }, { "remove", no_argument, NULL, ARG_REMOVE }, { "boot", no_argument, NULL, ARG_BOOT }, + { "graceful", no_argument, NULL, ARG_GRACEFUL }, { "prefix", required_argument, NULL, ARG_PREFIX }, { "exclude-prefix", required_argument, NULL, ARG_EXCLUDE_PREFIX }, { "root", required_argument, NULL, ARG_ROOT }, @@ -3938,6 +3958,10 @@ static int parse_argv(int argc, char *argv[]) { arg_boot = true; break; + case ARG_GRACEFUL: + arg_graceful = true; + break; + case ARG_PREFIX: if (strv_push(&arg_include_prefixes, optarg) < 0) return log_oom();