From 25bcde12d4856fad888810d2e2886f3cb4c09513 Mon Sep 17 00:00:00 2001 From: Aaron Andersen Date: Fri, 16 Jan 2026 16:49:37 -0500 Subject: [PATCH] tmpfiles: add support for numeric uid/gid in config files Add parse_uid() and parse_gid() helper functions that support both numeric IDs and name lookups. Update the d/D directory creation handlers to use these new functions. This allows config files to specify ownership using numeric UIDs and GIDs instead of only usernames and group names, matching systemd-tmpfiles behavior. --- src/tmpfiles.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 59 insertions(+), 2 deletions(-) diff --git a/src/tmpfiles.c b/src/tmpfiles.c index c2badc5d..6d7a01ae 100644 --- a/src/tmpfiles.c +++ b/src/tmpfiles.c @@ -304,6 +304,46 @@ static time_t parse_age(const char *age) return val; } +/** + * Parse user string - supports both names and numeric UIDs. + * Returns UID on success, -1 on failure. + */ +static int parse_uid(const char *user) +{ + long val; + + if (!user || !user[0]) + return 0; + + /* Check if it's a numeric UID */ + val = atonum(user); + if (val >= 0) + return val; + + /* Not numeric, look up by name */ + return getuser(user, NULL); +} + +/** + * Parse group string - supports both names and numeric GIDs. + * Returns GID on success, -1 on failure. + */ +static int parse_gid(const char *group) +{ + long val; + + if (!group || !group[0]) + return 0; + + /* Check if it's a numeric GID */ + val = atonum(group); + if (val >= 0) + return val; + + /* Not numeric, look up by name */ + return getgroup(group); +} + /* Globals for do_clean() callback - nftw doesn't support user data */ static time_t clean_age; static time_t clean_now; @@ -512,10 +552,27 @@ static void tmpfiles(char *line) rc = 0; break; case 'd': - case 'D': + case 'D': { + int uid, gid; + mode_t omask; + mkparent(path, 0755); - rc = mksubsys(path, mode ?: 0755, user, group); + omask = umask(0); + uid = parse_uid(user); + if (uid >= 0) { + gid = parse_gid(group); + if (gid < 0) + gid = 0; + + rc = makedir(path, mode ?: 0755); + if (rc && errno == EEXIST) + rc = chmod(path, mode ?: 0755); + if (chown(path, uid, gid)) + warn("Failed chown(%s, %d, %d)", path, uid, gid); + } + umask(omask); break; + } case 'e': if (glob(path, GLOB_NOESCAPE, NULL, &gl)) break;