mirror of
https://github.com/troglobit/finit.git
synced 2026-10-01 05:22:48 +07:00
tmpfiles: set mode and owner of d/D directories through an fd
makedir() swallows EEXIST, so the chmod branch for directories that
already existed never ran, while chown() ran every time. On finix
/var/empty is immutable, which gave a warning on every boot even
though the owner was already correct.
mksubsys() is the original of this code and has the same shape, the
dbus plugin uses it for /tmp/dbus. Both now go through dirperm(),
which opens the directory and uses fstat/fchmod/fchown on the fd,
changing only what differs. A failed chown in mksubsys() is a warning
now rather than err(1), PID 1 should not exit over a directory it
cannot adjust.
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
(cherry picked from commit 3a72d1263c)
This commit is contained in:
+5
-5
@@ -557,11 +557,11 @@ static void tmpfiles(char *line)
|
||||
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);
|
||||
if (!mode)
|
||||
mode = 0755;
|
||||
rc = makedir(path, mode);
|
||||
if (!rc && dirperm(path, mode, uid, gid))
|
||||
warn("Failed setting mode/owner on %s", path);
|
||||
}
|
||||
umask(omask);
|
||||
break;
|
||||
|
||||
+29
-5
@@ -25,6 +25,7 @@
|
||||
|
||||
#include <ctype.h> /* isprint() */
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <grp.h>
|
||||
#include <pwd.h>
|
||||
#ifdef HAVE_MNTENT_H
|
||||
@@ -374,6 +375,32 @@ int rmrf(const char *path)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set mode and owner on a directory that may already exist. Works on
|
||||
* an fd opened with O_NOFOLLOW | O_DIRECTORY, so the change lands on
|
||||
* the directory itself and not on whatever a link at @path points to.
|
||||
* Only what differs is touched, the directory may be immutable. uid
|
||||
* -1 skips the chown.
|
||||
*/
|
||||
int dirperm(const char *path, mode_t mode, uid_t uid, gid_t gid)
|
||||
{
|
||||
struct stat st;
|
||||
int fd, rc;
|
||||
|
||||
fd = open(path, O_RDONLY | O_DIRECTORY | O_NOFOLLOW | O_CLOEXEC);
|
||||
if (fd < 0)
|
||||
return -1;
|
||||
|
||||
rc = fstat(fd, &st);
|
||||
if (!rc && (st.st_mode & 07777) != mode)
|
||||
rc = fchmod(fd, mode);
|
||||
if (!rc && uid != (uid_t)-1 && (st.st_uid != uid || st.st_gid != gid))
|
||||
rc = fchown(fd, uid, gid);
|
||||
close(fd);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* Like mksubsys() but with the ids already resolved, uid -1 skips the
|
||||
* chown. Parents are created 0755, only the leaf gets @mode.
|
||||
@@ -386,11 +413,8 @@ int mksubsysd(const char *dir, mode_t mode, uid_t uid, gid_t gid)
|
||||
omask = umask(0);
|
||||
|
||||
rc = mkpath(dir, 0755);
|
||||
if (!rc) {
|
||||
rc = chmod(dir, mode);
|
||||
if (!rc && uid != (uid_t)-1 && chown(dir, uid, gid))
|
||||
err(1, "Failed chown(%s, %d, %d)", dir, (int)uid, (int)gid);
|
||||
}
|
||||
if (!rc && dirperm(dir, mode, uid, gid))
|
||||
warn("Failed setting mode/owner on %s", dir);
|
||||
|
||||
umask(omask);
|
||||
|
||||
|
||||
@@ -71,6 +71,7 @@ int getgroup (const char *group);
|
||||
int getcuser (char *buf, size_t len);
|
||||
int getcgroup (char *buf, size_t len);
|
||||
|
||||
int dirperm (const char *path, mode_t mode, uid_t uid, gid_t gid);
|
||||
int mksubsys (const char *dir, mode_t mode, char *user, char *group);
|
||||
int mksubsysd (const char *dir, mode_t mode, uid_t uid, gid_t gid);
|
||||
int chownr (const char *path, uid_t uid, gid_t gid);
|
||||
|
||||
Reference in New Issue
Block a user