Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F131608526
D52590.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
10 KB
Referenced Files
None
Subscribers
None
D52590.diff
View Options
diff --git a/usr.sbin/pw/cpdir.c b/usr.sbin/pw/cpdir.c
--- a/usr.sbin/pw/cpdir.c
+++ b/usr.sbin/pw/cpdir.c
@@ -40,49 +40,48 @@
gid_t gid, int flags)
{
char *p, lnk[MAXPATHLEN];
- int len, homefd, srcfd, destfd;
+ int len, srcfd, destfd;
ssize_t sz;
struct stat st;
struct dirent *e;
DIR *d;
+ mode_t pumask;
if (*dir == '/')
dir++;
+ pumask = umask(0);
+ umask(pumask);
+
if (mkdirat(rootfd, dir, mode) != 0) {
- mode_t pumask;
if (errno != EEXIST) {
warn("mkdir(%s)", dir);
return;
}
- pumask = umask(0);
- umask(pumask);
-
if (fchmodat(rootfd, dir, mode & ~pumask,
AT_SYMLINK_NOFOLLOW) == -1)
warn("chmod(%s)", dir);
}
-
if (fchownat(rootfd, dir, uid, gid, AT_SYMLINK_NOFOLLOW) == -1)
warn("chown(%s)", dir);
-
if (flags > 0 && chflagsat(rootfd, dir, flags,
AT_SYMLINK_NOFOLLOW) == -1)
warn("chflags(%s)", dir);
+ metalog_emit(dir, (mode | S_IFDIR) & ~pumask, uid, gid, flags);
if (skelfd == -1)
return;
- homefd = openat(rootfd, dir, O_DIRECTORY);
if ((d = fdopendir(skelfd)) == NULL) {
close(skelfd);
- close(homefd);
return;
}
while ((e = readdir(d)) != NULL) {
+ char path[MAXPATHLEN];
+
if (strcmp(e->d_name, ".") == 0 || strcmp(e->d_name, "..") == 0)
continue;
@@ -92,19 +91,32 @@
if (strncmp(p, "dot.", 4) == 0) /* Conversion */
p += 3;
+ (void)snprintf(path, sizeof(path), "%s/%s", dir, p);
if (S_ISDIR(st.st_mode)) {
- copymkdir(homefd, p, openat(skelfd, e->d_name, O_DIRECTORY),
- st.st_mode & _DEF_DIRMODE, uid, gid, st.st_flags);
+ int fd;
+
+ fd = openat(skelfd, e->d_name, O_DIRECTORY);
+ if (fd == -1) {
+ warn("openat(%s)", e->d_name);
+ continue;
+ }
+ copymkdir(rootfd, path, fd, st.st_mode & _DEF_DIRMODE,
+ uid, gid, st.st_flags);
continue;
}
if (S_ISLNK(st.st_mode) &&
- (len = readlinkat(skelfd, e->d_name, lnk, sizeof(lnk) -1))
+ (len = readlinkat(skelfd, e->d_name, lnk, sizeof(lnk) - 1))
!= -1) {
lnk[len] = '\0';
- symlinkat(lnk, homefd, p);
- fchownat(homefd, p, uid, gid, AT_SYMLINK_NOFOLLOW);
+ if (symlinkat(lnk, rootfd, path) != 0)
+ warn("symlink(%s)", path);
+ else if (fchownat(rootfd, path, uid, gid,
+ AT_SYMLINK_NOFOLLOW) != 0)
+ warn("chown(%s)", path);
+ metalog_emit_symlink(path, lnk, st.st_mode & ~pumask,
+ uid, gid);
continue;
}
@@ -113,7 +125,7 @@
if ((srcfd = openat(skelfd, e->d_name, O_RDONLY)) == -1)
continue;
- destfd = openat(homefd, p, O_RDWR | O_CREAT | O_EXCL,
+ destfd = openat(rootfd, path, O_RDWR | O_CREAT | O_EXCL,
st.st_mode);
if (destfd == -1) {
close(srcfd);
@@ -135,6 +147,7 @@
warn("chown(%s)", p);
if (fchflags(destfd, st.st_flags) != 0)
warn("chflags(%s)", p);
+ metalog_emit(path, st.st_mode & ~pumask, uid, gid, st.st_flags);
close(destfd);
}
closedir(d);
diff --git a/usr.sbin/pw/pw.h b/usr.sbin/pw/pw.h
--- a/usr.sbin/pw/pw.h
+++ b/usr.sbin/pw/pw.h
@@ -70,6 +70,11 @@
struct userconf *read_userconfig(char const * file);
int write_userconfig(struct userconf *cnf, char const * file);
+void metalog_emit(const char *path, mode_t mode, uid_t uid, gid_t gid,
+ int flags);
+void metalog_emit_symlink(const char *path, const char *target, mode_t mode,
+ uid_t uid, gid_t gid);
+
int pw_group_add(int argc, char **argv, char *name);
int pw_group_del(int argc, char **argv, char *name);
int pw_group_mod(int argc, char **argv, char *name);
diff --git a/usr.sbin/pw/pw.8 b/usr.sbin/pw/pw.8
--- a/usr.sbin/pw/pw.8
+++ b/usr.sbin/pw/pw.8
@@ -30,6 +30,7 @@
.Nd create, remove, modify & display system users and groups
.Sh SYNOPSIS
.Nm
+.Op Fl M Ar metalog
.Op Fl R Ar rootdir
.Op Fl V Ar etcdir
.Cm useradd
@@ -464,6 +465,21 @@
This can be overridden by the
.Fl d
option on the command line, if desired.
+.It Fl M Ar metalog
+Specify a path to a
+.Xr mtree 5
+metalog file.
+.Nm
+will add entries for all files added to a user's home directory.
+This is useful when building images as a non-root user, as the
+metalog can be used as input to
+.Xr tar 1
+or
+.Xr makefs 8 .
+Note that this option must precede the
+.Ql useradd
+string on the command line, otherwise it will be interpreted as the mode
+option.
.It Fl M Ar mode
Create the user's home directory with the specified
.Ar mode ,
diff --git a/usr.sbin/pw/pw.c b/usr.sbin/pw/pw.c
--- a/usr.sbin/pw/pw.c
+++ b/usr.sbin/pw/pw.c
@@ -132,7 +132,11 @@
while (argc > 1) {
if (*argv[1] == '-') {
/*
- * Special case, allow pw -V<dir> <operation> [args] for scripts etc.
+ * Special case, allow pw -V<dir> <operation> [args] for
+ * scripts etc.
+ *
+ * The -M option before the keyword is handled
+ * differently from -M after a keyword.
*/
arg = argv[1][1];
if (arg == 'V' || arg == 'R') {
@@ -164,6 +168,23 @@
"%s%s", optarg, arg == 'R' ?
_PATH_PWD : "");
conf.altroot = true;
+ } else if (mode == -1 && which == -1 && arg == 'M') {
+ int fd;
+
+ optarg = &argv[1][2];
+ if (*optarg == '\0') {
+ optarg = argv[2];
+ ++argv;
+ --argc;
+ }
+ fd = open(optarg,
+ O_WRONLY | O_APPEND | O_CREAT | O_CLOEXEC,
+ 0644);
+ if (fd == -1)
+ errx(EX_OSERR,
+ "Cannot open metalog `%s'",
+ optarg);
+ conf.metalog = fdopen(fd, "ae");
} else
break;
} else if (mode == -1 && (tmp = getindex(Modes, argv[1])) != -1)
@@ -195,6 +216,10 @@
if (conf.rootfd == -1)
errx(EXIT_FAILURE, "Unable to open '%s'", conf.rootdir);
+ if (conf.metalog != NULL && (which != W_USER || mode != M_ADD))
+ errx(EXIT_FAILURE,
+ "metalog can only be specified with 'useradd'");
+
return (cmdfunc[which][mode](argc, argv, arg1));
}
@@ -233,10 +258,11 @@
static const char *help[W_NUM][M_NUM] =
{
{
- "usage: pw useradd [name] [switches]\n"
+ "usage: pw [-M metalog] useradd [name] [switches]\n"
"\t-V etcdir alternate /etc location\n"
"\t-R rootdir alternate root directory\n"
"\t-C config configuration file\n"
+ "\t-M metalog mtree file, must precede 'useradd'\n"
"\t-q quiet operation\n"
" Adding users:\n"
"\t-n name login name\n"
diff --git a/usr.sbin/pw/pw_user.c b/usr.sbin/pw/pw_user.c
--- a/usr.sbin/pw/pw_user.c
+++ b/usr.sbin/pw/pw_user.c
@@ -86,10 +86,13 @@
{
struct stat st;
char *dirs, *tmp;
+ mode_t pumask;
+
+ pumask = umask(0);
+ umask(pumask);
if (*dir != '/')
errx(EX_DATAERR, "invalid base directory for home '%s'", dir);
-
dir++;
if (fstatat(dfd, dir, &st, 0) != -1) {
@@ -120,6 +123,9 @@
dirs);
if (fchownat(dfd, dirs, 0, 0, 0) != 0)
warn("chown(%s)", dirs);
+ metalog_emit(dir,
+ (_DEF_DIRMODE | S_IFDIR) & ~pumask, 0, 0,
+ 0);
}
*tmp = '/';
}
@@ -129,6 +135,7 @@
err(EX_OSFILE, "'%s' (home parent) is not a directory", dirs);
if (fchownat(dfd, dirs, 0, 0, 0) != 0)
warn("chown(%s)", dirs);
+ metalog_emit(dirs, (_DEF_DIRMODE | S_IFDIR) & ~pumask, 0, 0, 0);
}
free(dirs);
diff --git a/usr.sbin/pw/pw_utils.c b/usr.sbin/pw/pw_utils.c
--- a/usr.sbin/pw/pw_utils.c
+++ b/usr.sbin/pw/pw_utils.c
@@ -92,3 +92,49 @@
errx(i, "make exited with status %d", i);
return (i);
}
+
+static void
+metalog_emit_record(const char *path, const char *target, mode_t mode,
+ uid_t uid, gid_t gid, int flags)
+{
+ const char *flagstr, *type;
+ int error;
+
+ if (conf.metalog == NULL)
+ return;
+
+ if (target != NULL)
+ type = "link";
+ else if (S_ISDIR(mode))
+ type = "dir";
+ else if (S_ISREG(mode))
+ type = "file";
+ else
+ errx(1, "metalog_emit: unhandled file type for %s", path);
+
+ flagstr = fflagstostr(flags &
+ (UF_IMMUTABLE | UF_APPEND | SF_IMMUTABLE | SF_APPEND));
+ if (flagstr == NULL)
+ errx(1, "metalog_emit: fflagstostr failed");
+
+ error = fprintf(conf.metalog,
+ "./%s type=%s mode=0%03o uid=%u gid=%u%s%s%s%s\n",
+ path, type, mode & ACCESSPERMS, uid, gid,
+ target != NULL ? " link=" : "", target != NULL ? target : "",
+ *flagstr != '\0' ? " flags=" : "", *flagstr != '\0' ? flagstr : "");
+ if (error < 0)
+ errx(1, "metalog_emit: write error");
+}
+
+void
+metalog_emit(const char *path, mode_t mode, uid_t uid, gid_t gid, int flags)
+{
+ metalog_emit_record(path, NULL, mode, uid, gid, flags);
+}
+
+void
+metalog_emit_symlink(const char *path, const char *target, mode_t mode,
+ uid_t uid, gid_t gid)
+{
+ metalog_emit_record(path, target, mode, uid, gid, 0);
+}
diff --git a/usr.sbin/pw/pwupd.h b/usr.sbin/pw/pwupd.h
--- a/usr.sbin/pw/pwupd.h
+++ b/usr.sbin/pw/pwupd.h
@@ -76,6 +76,7 @@
struct pwconf {
char rootdir[MAXPATHLEN];
char etcpath[MAXPATHLEN];
+ FILE *metalog;
int fd;
int rootfd;
bool altroot;
diff --git a/usr.sbin/pw/tests/pw_useradd_test.sh b/usr.sbin/pw/tests/pw_useradd_test.sh
--- a/usr.sbin/pw/tests/pw_useradd_test.sh
+++ b/usr.sbin/pw/tests/pw_useradd_test.sh
@@ -1,4 +1,3 @@
-
# Import helper functions
. $(atf_get_srcdir)/helper_functions.shin
@@ -357,15 +356,28 @@
echo "c" > ${HOME}/skel/c/d/dot.c
mkdir ${HOME}/home
ln -sf /nonexistent ${HOME}/skel/c/foo
- atf_check -s exit:0 ${RPW} useradd foo -k /skel -m
+ atf_check -s exit:0 ${RPW} -M METALOG useradd foo -k /skel -m
test -d ${HOME}/home/foo || atf_fail "Directory not created"
test -f ${HOME}/home/foo/.a || atf_fail "File not created"
atf_check -o file:${HOME}/skel/.a -s exit:0 cat ${HOME}/home/foo/.a
atf_check -o file:${HOME}/skel/b -s exit:0 cat ${HOME}/home/foo/b
- test -d ${HOME}/home/foo/c || atf_fail "Dotted directory in skel not copied"
- test -d ${HOME}/home/foo/.plop || atf_fail "Directory in skell not created"
+ test -d ${HOME}/home/foo/c || atf_fail "Directory in skel not copied"
+ test -d ${HOME}/home/foo/.plop || atf_fail "Dotted directory in skel not created"
atf_check -o inline:"/nonexistent\n" -s ignore readlink -f ${HOME}/home/foo/c/foo
atf_check -o file:${HOME}/skel/c/d/dot.c -s exit:0 cat ${HOME}/home/foo/c/d/.c
+
+ cat <<__EOF__ >METALOG.expected
+./home/foo type=dir mode=0755 uid=1001 gid=1001
+./home/foo/.a type=file mode=0644 uid=1001 gid=1001
+./home/foo/.plop type=dir mode=0755 uid=1001 gid=1001
+./home/foo/b type=file mode=0644 uid=1001 gid=1001
+./home/foo/c type=dir mode=0755 uid=1001 gid=1001
+./home/foo/c/d type=dir mode=0755 uid=1001 gid=1001
+./home/foo/c/d/.c type=file mode=0644 uid=1001 gid=1001
+./home/foo/c/foo type=link mode=0755 uid=1001 gid=1001 link=/nonexistent
+__EOF__
+ atf_check -o save:METALOG.out sort METALOG
+ atf_check diff METALOG.out METALOG.expected
}
atf_test_case user_add_uid0
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Fri, Oct 10, 5:15 PM (14 h, 31 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
23539747
Default Alt Text
D52590.diff (10 KB)
Attached To
Mode
D52590: pw: Add a metalog output mode
Attached
Detach File
Event Timeline
Log In to Comment