mirror of
https://github.com/troglobit/finit.git
synced 2026-10-16 10:39:35 +00:00
tmpfiles: apply mode and owner of e and f/F entries through an fd
Same treatment as d/D got: e went through fisdir() and a path based chmod/chown, f/F did the chmod/chown by path after closing the file. Both now work on the open fd, so the mode and owner end up on the directory or file that was just checked or written. f/F use open(2) directly, which lets a plain f rely on O_EXCL for create-if-missing instead of the earlier stat(). Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
This commit is contained in:
3 files changed
+68
-47
No files matched your search
+45
-37
@@ -24,6 +24,7 @@
|
|||||||
#include "config.h" /* Generated by configure script */
|
#include "config.h" /* Generated by configure script */
|
||||||
|
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
|
#include <fcntl.h>
|
||||||
#include <ftw.h>
|
#include <ftw.h>
|
||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
#include <glob.h>
|
#include <glob.h>
|
||||||
@@ -595,58 +596,65 @@ static void tmpfiles(char *line)
|
|||||||
umask(omask);
|
umask(omask);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'e':
|
case 'e': {
|
||||||
|
int uid, gid;
|
||||||
|
|
||||||
if (glob(path, GLOB_NOESCAPE, NULL, &gl))
|
if (glob(path, GLOB_NOESCAPE, NULL, &gl))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
uid = parse_uid(user);
|
||||||
|
gid = parse_gid(group);
|
||||||
|
if (gid < 0)
|
||||||
|
gid = 0;
|
||||||
|
|
||||||
for (size_t i = 0; i < gl.gl_pathc; i++) {
|
for (size_t i = 0; i < gl.gl_pathc; i++) {
|
||||||
char *p = gl.gl_pathv[i];
|
char *p = gl.gl_pathv[i];
|
||||||
int uid, gid;
|
|
||||||
|
|
||||||
/* e only adjusts existing directories */
|
/* skip non-directories */
|
||||||
if (!fisdir(p))
|
if (dirperm(p, mode, uid, gid) && errno != ENOTDIR)
|
||||||
continue;
|
warn("Failed setting mode/owner on %s", p);
|
||||||
|
|
||||||
uid = parse_uid(user);
|
|
||||||
gid = parse_gid(group);
|
|
||||||
if (gid < 0)
|
|
||||||
gid = 0;
|
|
||||||
|
|
||||||
if (mode)
|
|
||||||
chmod(p, mode);
|
|
||||||
if (uid >= 0 && chown(p, uid, gid))
|
|
||||||
warn("Failed chown(%s, %d, %d)", p, uid, gid);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case 'f':
|
case 'f':
|
||||||
case 'F':
|
case 'F': {
|
||||||
mkparent(path, 0755);
|
int flags = O_WRONLY | O_CREAT | O_NOFOLLOW | O_CLOEXEC;
|
||||||
|
int fd, uid, gid;
|
||||||
|
|
||||||
if (type[1] == '+' || type[0] == 'F') {
|
if (type[1] == '+' || type[0] == 'F') {
|
||||||
/* f+/F will create or truncate the file */
|
flags |= O_TRUNC; /* create or truncate */
|
||||||
fp = fopen(path, "w+");
|
|
||||||
} else {
|
} else {
|
||||||
/* f will create the file if it doesn't exist */
|
if (!strc)
|
||||||
if (strc)
|
break; /* create only if missing */
|
||||||
fp = fopen(path, "w");
|
flags |= O_EXCL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fp) {
|
mkparent(path, 0755);
|
||||||
int uid, gid;
|
fd = open(path, flags, 0666);
|
||||||
|
if (fd < 0) {
|
||||||
write_arg(fp, arg);
|
if (errno != EEXIST)
|
||||||
rc = fclose(fp);
|
warn("Failed creating %s", path);
|
||||||
|
break;
|
||||||
/* Apply mode and ownership */
|
|
||||||
if (mode)
|
|
||||||
chmod(path, mode);
|
|
||||||
uid = parse_uid(user);
|
|
||||||
gid = parse_gid(group);
|
|
||||||
if (gid < 0)
|
|
||||||
gid = 0;
|
|
||||||
if (uid >= 0 && chown(path, uid, gid))
|
|
||||||
warn("Failed chown(%s, %d, %d)", path, uid, gid);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fp = fdopen(fd, "w");
|
||||||
|
if (!fp) {
|
||||||
|
close(fd);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
write_arg(fp, arg);
|
||||||
|
|
||||||
|
uid = parse_uid(user);
|
||||||
|
gid = parse_gid(group);
|
||||||
|
if (gid < 0)
|
||||||
|
gid = 0;
|
||||||
|
if (fdperm(fd, mode, uid, gid))
|
||||||
|
warn("Failed setting mode/owner on %s", path);
|
||||||
|
|
||||||
|
rc = fclose(fp);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case 'l': /* Finit extension, like 'L' but only if target exists */
|
case 'l': /* Finit extension, like 'L' but only if target exists */
|
||||||
if (!arg) {
|
if (!arg) {
|
||||||
paste(buf, sizeof(buf), "/usr/share/factory", path);
|
paste(buf, sizeof(buf), "/usr/share/factory", path);
|
||||||
|
|||||||
+22
-10
@@ -282,25 +282,37 @@ int getcgroup(char *buf, size_t len)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Set mode and owner on a directory that may already exist. Works on
|
* Set mode and owner on an open fd, only what differs is touched, the
|
||||||
* an fd opened with O_NOFOLLOW | O_DIRECTORY, so the change lands on
|
* file may be immutable. mode 0 skips the chmod, uid -1 the chown.
|
||||||
* the directory itself and not on whatever a link at @path points to.
|
*/
|
||||||
* Only what differs is touched, the directory may be immutable.
|
int fdperm(int fd, mode_t mode, uid_t uid, gid_t gid)
|
||||||
|
{
|
||||||
|
struct stat st;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
rc = fstat(fd, &st);
|
||||||
|
if (!rc && mode && (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);
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Same for a directory that may already exist. Opened with
|
||||||
|
* O_NOFOLLOW | O_DIRECTORY, so the change lands on the directory
|
||||||
|
* itself and not on whatever a link at @path points to.
|
||||||
*/
|
*/
|
||||||
int dirperm(const char *path, mode_t mode, uid_t uid, gid_t gid)
|
int dirperm(const char *path, mode_t mode, uid_t uid, gid_t gid)
|
||||||
{
|
{
|
||||||
struct stat st;
|
|
||||||
int fd, rc;
|
int fd, rc;
|
||||||
|
|
||||||
fd = open(path, O_RDONLY | O_DIRECTORY | O_NOFOLLOW | O_CLOEXEC);
|
fd = open(path, O_RDONLY | O_DIRECTORY | O_NOFOLLOW | O_CLOEXEC);
|
||||||
if (fd < 0)
|
if (fd < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
rc = fstat(fd, &st);
|
rc = fdperm(fd, mode, uid, gid);
|
||||||
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);
|
close(fd);
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
|
|||||||
@@ -68,6 +68,7 @@ int getgroup (const char *group);
|
|||||||
int getcuser (char *buf, size_t len);
|
int getcuser (char *buf, size_t len);
|
||||||
int getcgroup (char *buf, size_t len);
|
int getcgroup (char *buf, size_t len);
|
||||||
|
|
||||||
|
int fdperm (int fd, mode_t mode, uid_t uid, gid_t gid);
|
||||||
int dirperm (const char *path, mode_t mode, uid_t uid, gid_t gid);
|
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 mksubsys (const char *dir, mode_t mode, char *user, char *group);
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user