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>
This commit is contained in:
+5
-5
@@ -586,11 +586,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;
|
||||
|
||||
+28
-4
@@ -25,6 +25,7 @@
|
||||
|
||||
#include <ctype.h> /* isprint() */
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <grp.h>
|
||||
#include <pwd.h>
|
||||
#ifdef HAVE_MNTENT_H
|
||||
@@ -280,6 +281,31 @@ int getcgroup(char *buf, size_t len)
|
||||
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.
|
||||
*/
|
||||
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 && (st.st_uid != uid || st.st_gid != gid))
|
||||
rc = fchown(fd, uid, gid);
|
||||
close(fd);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int mksubsys(const char *dir, mode_t mode, char *user, char *group)
|
||||
{
|
||||
mode_t omask;
|
||||
@@ -295,10 +321,8 @@ int mksubsys(const char *dir, mode_t mode, char *user, char *group)
|
||||
gid = 0;
|
||||
|
||||
rc = makedir(dir, mode);
|
||||
if (rc && errno == EEXIST)
|
||||
rc = chmod(dir, mode);
|
||||
if (chown(dir, uid, gid))
|
||||
err(1, "Failed chown(%s, %d, %d)", dir, uid, gid);
|
||||
if (!rc && dirperm(dir, mode, uid, gid))
|
||||
warn("Failed setting mode/owner on %s", dir);
|
||||
}
|
||||
|
||||
umask(omask);
|
||||
|
||||
@@ -68,6 +68,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 fnread (char *buf, size_t len, char *fmt, ...) __attribute__ ((format (printf, 3, 4)));
|
||||
|
||||
Reference in New Issue
Block a user