aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorElliott Hughes <enh@google.com>2015-05-30 13:22:56 -0700
committerElliott Hughes <enh@google.com>2015-05-30 13:22:56 -0700
commit8bdb32495fe8f0a038fe0ac02905dc4f2d8c660b (patch)
tree49e568a3f7f35af6cee0f921757b811c0bdc9732
parent632d81c469358ec4f41a90474dcf93326839438a (diff)
parent2d66e6a23822a500ecf6610411941e99127129c8 (diff)
downloadtoybox-8bdb32495fe8f0a038fe0ac02905dc4f2d8c660b.tar.gz
Merge remote-tracking branch 'toybox/master' into HEAD
-rw-r--r--lib/lsm.h115
-rw-r--r--lib/portability.h25
-rw-r--r--toys.h1
-rw-r--r--toys/other/stat.c2
-rw-r--r--toys/posix/grep.c8
-rw-r--r--toys/posix/id.c53
-rw-r--r--toys/posix/ls.c125
-rw-r--r--toys/posix/mkdir.c19
8 files changed, 224 insertions, 124 deletions
diff --git a/lib/lsm.h b/lib/lsm.h
new file mode 100644
index 00000000..d7e7de9c
--- /dev/null
+++ b/lib/lsm.h
@@ -0,0 +1,115 @@
+/* lsm.h - header file for lib directory
+ *
+ * Copyright 2015 Rob Landley <rob@landley.net>
+ */
+
+#if CFG_TOYBOX_SELINUX
+#include <selinux/selinux.h>
+#else
+#define is_selinux_enabled() 0
+#define setfscreatecon(...) (-1)
+#define getcon(...) (-1)
+#define getfilecon(...) (-1)
+#define lgetfilecon(...) (-1)
+#define fgetfilecon(...) (-1)
+#define setfilecon(...) (-1)
+#define lsetfilecon(...) (-1)
+#define fsetfilecon(...) (-1)
+#endif
+
+#if CFG_TOYBOX_SMACK
+#include <sys/smack.h>
+#include <sys/xattr.h>
+#include <linux/xattr.h>
+#else
+#define XATTR_NAME_SMACK 0
+//ssize_t fgetxattr (int fd, char *name, void *value, size_t size);
+#define smack_smackfs_path(...) (-1)
+#define smack_new_label_from_self(...) (-1)
+#define smack_new_label_from_path(...) (-1)
+#define smack_new_label_from_file(...) (-1)
+#define smack_set_label_for_self(...) (-1)
+#define smack_set_label_for_path(...) (-1)
+#define smack_set_label_for_file(...) (-1)
+#endif
+
+// This turns into "return 0" when no LSM and lets code optimize out.
+static inline int lsm_enabled(void)
+{
+ if (CFG_TOYBOX_SMACK) return !!smack_smackfs_path();
+ else return is_selinux_enabled() == 1;
+}
+
+static inline char *lsm_name(void)
+{
+ if (CFG_TOYBOX_SMACK) return "Smack";
+ if (CFG_TOYBOX_SELINUX) return "SELinux";
+
+ return "LSM";
+}
+
+// Fetch this process's lsm context
+static inline char *lsm_context(void)
+{
+ int ok = 0;
+ char *result;
+
+ if (CFG_TOYBOX_SMACK) ok = smack_new_label_from_self(&result) > 0;
+ else ok = getcon(&result) == 0;
+
+ return ok ? result : strdup("?");
+}
+
+// Set default label to apply to newly created stuff (NULL to clear it)
+static inline int lsm_set_create(char *context)
+{
+ if (CFG_TOYBOX_SMACK) return smack_set_label_for_self(context);
+ else return setfscreatecon(context);
+}
+
+// Label a file, following symlinks
+static inline int lsm_set_context(char *filename, char *context)
+{
+ if (CFG_TOYBOX_SMACK)
+ return smack_set_label_for_path(filename, XATTR_NAME_SMACK, 1, context);
+ else return setfilecon(filename, context);
+}
+
+// Label a file, don't follow symlinks
+static inline int lsm_lset_context(char *filename, char *context)
+{
+ if (CFG_TOYBOX_SMACK)
+ return smack_set_label_for_path(filename, XATTR_NAME_SMACK, 0, context);
+ else return lsetfilecon(filename, context);
+}
+
+// Label a file by filehandle
+static inline int lsm_fset_context(int file, char *context)
+{
+ if (CFG_TOYBOX_SMACK)
+ return smack_set_label_for_file(file, XATTR_NAME_SMACK, context);
+ else return fsetfilecon(file, context);
+}
+
+// returns -1 in case of error or else the length of the context */
+// context can be NULL to get the length only */
+static inline int lsm_get_context(char *filename, char **context)
+{
+ if (CFG_TOYBOX_SMACK)
+ return smack_new_label_from_path(filename, XATTR_NAME_SMACK, 1, context);
+ else return getfilecon(filename, context);
+}
+
+static inline int lsm_lget_context(char *filename, char **context)
+{
+ if (CFG_TOYBOX_SMACK)
+ return smack_new_label_from_path(filename, XATTR_NAME_SMACK, 0, context);
+ else return lgetfilecon(filename, context);
+}
+
+static inline int lsm_fget_context(int file, char **context)
+{
+ if (CFG_TOYBOX_SMACK)
+ return smack_new_label_from_file(file, XATTR_NAME_SMACK, context);
+ return fgetfilecon(file, context);
+}
diff --git a/lib/portability.h b/lib/portability.h
index aa1ee488..f83cab60 100644
--- a/lib/portability.h
+++ b/lib/portability.h
@@ -225,6 +225,10 @@ ssize_t getline(char **lineptr, size_t *n, FILE *stream);
#define O_NOFOLLOW 0
#endif
+#ifndef O_NOATIME
+#define O_NOATIME 01000000
+#endif
+
#ifndef O_CLOEXEC
#define O_CLOEXEC 02000000
#endif
@@ -247,24 +251,3 @@ pid_t xfork(void);
//#define strncpy(...) @@strncpyisbadmmkay@@
//#define strncat(...) @@strncatisbadmmkay@@
-#if CFG_TOYBOX_SELINUX
-#include <selinux/selinux.h>
-#else
-#define is_selinux_enabled() 0
-int getcon(void* con);
-#endif
-
-#if CFG_TOYBOX_SMACK
-#include <sys/smack.h>
-#include <sys/xattr.h>
-#include <linux/xattr.h>
-#else
-#define smack_new_label_from_path(...) (-1)
-#define smack_set_label_for_path(...) (-1)
-#define smack_set_label_for_self(...) (-1)
-#define XATTR_NAME_SMACK ""
-#define SMACK_LABEL_LEN (1) /* for just ? */
-
-ssize_t fgetxattr (int fd, char *name, void *value, size_t size);
-#endif
-
diff --git a/toys.h b/toys.h
index 4b2d3736..79754257 100644
--- a/toys.h
+++ b/toys.h
@@ -68,6 +68,7 @@
#include <sys/sysinfo.h>
#include "lib/lib.h"
+#include "lib/lsm.h"
#include "toys/e2fs.h"
// Get list of function prototypes for all enabled command_main() functions.
diff --git a/toys/other/stat.c b/toys/other/stat.c
index a96c1def..d6db44dd 100644
--- a/toys/other/stat.c
+++ b/toys/other/stat.c
@@ -82,7 +82,7 @@ static void print_stat(char type)
if (!stat->st_size && filetype == S_IFREG) t = "regular empty file";
xprintf("%s", t);
} else if (type == 'g') xprintf("%lu", stat->st_gid);
- else if (type == 'G') xprintf("%8s", TT.user_name->pw_name);
+ else if (type == 'G') xprintf("%8s", TT.group_name->gr_name);
else if (type == 'h') xprintf("%lu", stat->st_nlink);
else if (type == 'i') xprintf("%llu", stat->st_ino);
else if (type == 'N') {
diff --git a/toys/posix/grep.c b/toys/posix/grep.c
index 61df08ea..6e383efc 100644
--- a/toys/posix/grep.c
+++ b/toys/posix/grep.c
@@ -269,7 +269,7 @@ static int do_grep_r(struct dirtree *new)
void grep_main(void)
{
- char **ss;
+ char **ss = toys.optargs;
// Handle egrep and fgrep
if (*toys.which->name == 'e' || (toys.optflags & FLAG_w))
@@ -277,9 +277,9 @@ void grep_main(void)
if (*toys.which->name == 'f') toys.optflags |= FLAG_F;
if (!TT.e && !TT.f) {
- if (!*toys.optargs) error_exit("no REGEX");
+ if (!*ss) error_exit("no REGEX");
TT.e = xzalloc(sizeof(struct arg_list));
- TT.e->arg = *(toys.optargs++);
+ TT.e->arg = *(ss++);
toys.optc--;
}
@@ -294,7 +294,7 @@ void grep_main(void)
}
if (toys.optflags & FLAG_r) {
- for (ss=toys.optargs; *ss; ss++) {
+ for (ss = *ss ? ss : (char *[]){".", 0}; *ss; ss++) {
if (!strcmp(*ss, "-")) do_grep(0, *ss);
else dirtree_read(*ss, do_grep_r);
}
diff --git a/toys/posix/id.c b/toys/posix/id.c
index 7ab489ef..aa43072f 100644
--- a/toys/posix/id.c
+++ b/toys/posix/id.c
@@ -6,7 +6,7 @@
*
* See http://opengroup.org/onlinepubs/9699919799/utilities/id.html
-USE_ID(NEWTOY(id, ">1"USE_ID_SELINUX("Z")"nGgru[!"USE_ID_SELINUX("Z")"Ggu]", TOYFLAG_USR|TOYFLAG_BIN))
+USE_ID(NEWTOY(id, ">1"USE_ID_Z("Z")"nGgru[!"USE_ID_Z("Z")"Ggu]", TOYFLAG_USR|TOYFLAG_BIN))
USE_GROUPS(NEWTOY(groups, NULL, TOYFLAG_USR|TOYFLAG_BIN))
USE_LOGNAME(NEWTOY(logname, ">0", TOYFLAG_USR|TOYFLAG_BIN))
USE_WHOAMI(OLDTOY(whoami, logname, TOYFLAG_USR|TOYFLAG_BIN))
@@ -25,14 +25,14 @@ config ID
-r Show real ID instead of effective ID
-u Show only the effective user ID
-config ID_SELINUX
+config ID_Z
bool
default y
- depends on ID && TOYBOX_SELINUX
+ depends on ID && !TOYBOX_LSM_NONE
help
usage: id [-Z]
- -Z Show only SELinux context
+ -Z Show only security context
config GROUPS
bool "groups"
@@ -60,15 +60,16 @@ config WHOAMI
*/
#define FOR_id
+#define FORCE_FLAGS
#include "toys.h"
GLOBALS(
- int do_u, do_n, do_G, do_Z, is_groups;
+ int is_groups;
)
static void s_or_u(char *s, unsigned u, int done)
{
- if (TT.do_n) printf("%s", s);
+ if (toys.optflags&FLAG_n) printf("%s", s);
else printf("%u", u);
if (done) {
xputc('\n');
@@ -101,12 +102,12 @@ void do_id(char *username)
i = flags & FLAG_r;
pw = xgetpwuid(i ? uid : euid);
- if (TT.do_u) s_or_u(pw->pw_name, pw->pw_uid, 1);
+ if (toys.optflags&FLAG_u) s_or_u(pw->pw_name, pw->pw_uid, 1);
grp = xgetgrgid(i ? gid : egid);
if (flags & FLAG_g) s_or_u(grp->gr_name, grp->gr_gid, 1);
- if (!TT.do_G && !TT.do_Z) {
+ if (!(toys.optflags&(FLAG_g|FLAG_Z))) {
showid("uid=", pw->pw_uid, pw->pw_name);
showid(" gid=", grp->gr_gid, grp->gr_name);
@@ -124,39 +125,35 @@ void do_id(char *username)
showid(" groups=", grp->gr_gid, grp->gr_name);
}
- if (!TT.do_Z) {
+ if (!(toys.optflags&FLAG_Z)) {
groups = (gid_t *)toybuf;
i = sizeof(toybuf)/sizeof(gid_t);
ngroups = username ? getgrouplist(username, gid, groups, &i)
: getgroups(i, groups);
if (ngroups<0) perror_exit(0);
- int show_separator = !TT.do_G;
+ int show_separator = !(toys.optflags&FLAG_G);
for (i = 0; i<ngroups; i++) {
- if (show_separator) xputc(TT.do_G ? ' ' : ',');
+ if (show_separator) xputc((toys.optflags&FLAG_G) ? ' ' : ',');
show_separator = 1;
if (!(grp = getgrgid(groups[i]))) perror_msg(0);
- else if (TT.do_G) s_or_u(grp->gr_name, grp->gr_gid, 0);
+ else if (toys.optflags&FLAG_G) s_or_u(grp->gr_name, grp->gr_gid, 0);
else if (grp->gr_gid != egid) showid("", grp->gr_gid, grp->gr_name);
else show_separator = 0; // Because we didn't show anything this time.
}
- if (TT.do_G) {
+ if (toys.optflags&FLAG_G) {
xputc('\n');
exit(0);
}
}
- if (CFG_TOYBOX_SELINUX) {
- char *context = NULL;
+ if (!CFG_TOYBOX_LSM_NONE) {
+ if (lsm_enabled()) {
+ char *context = lsm_context();
- if (is_selinux_enabled() < 1) {
- if (TT.do_Z)
- error_exit("SELinux disabled");
- } else if (getcon(&context) == 0) {
- if (!TT.do_Z) xputc(' ');
- printf("context=%s", context);
- }
- if (CFG_TOYBOX_FREE) free(context);
+ printf(" context=%s"+!!(toys.optflags&FLAG_Z), context);
+ if (CFG_TOYBOX_FREE) free(context);
+ } else if (toys.optflags&FLAG_Z) error_exit("%s disabled", lsm_name());
}
xputc('\n');
@@ -164,12 +161,6 @@ void do_id(char *username)
void id_main(void)
{
- // FLAG macros can be 0 if "id" command not enabled, so snapshot them here.
- if (FLAG_u) TT.do_u |= toys.optflags & FLAG_u;
- if (FLAG_n) TT.do_n |= toys.optflags & FLAG_n;
- if (FLAG_G) TT.do_G |= toys.optflags & FLAG_G;
- if (FLAG_Z) TT.do_Z |= toys.optflags & FLAG_Z;
-
if (toys.optc) while(*toys.optargs) do_id(*toys.optargs++);
else do_id(NULL);
}
@@ -177,12 +168,12 @@ void id_main(void)
void groups_main(void)
{
TT.is_groups = 1;
- TT.do_G = TT.do_n = 1;
+ toys.optflags = FLAG_G|FLAG_n;
id_main();
}
void logname_main(void)
{
- TT.do_u = TT.do_n = 1;
+ toys.optflags = FLAG_u|FLAG_n;
id_main();
}
diff --git a/toys/posix/ls.c b/toys/posix/ls.c
index 35d1034a..15796ff1 100644
--- a/toys/posix/ls.c
+++ b/toys/posix/ls.c
@@ -5,13 +5,13 @@
*
* See http://opengroup.org/onlinepubs/9699919799/utilities/ls.html
-USE_LS(NEWTOY(ls, USE_LS_COLOR("(color):;")USE_LS_Z("Z")"goACFHLRSacdfiklmnpqrstux1[-Cxm1][-Cxml][-Cxmo][-Cxmg][-cu][-ftS][-HL]", TOYFLAG_BIN|TOYFLAG_LOCALE))
+USE_LS(NEWTOY(ls, USE_LS_COLOR("(color):;")"ZgoACFHLRSacdfiklmnpqrstux1[-Cxm1][-Cxml][-Cxmo][-Cxmg][-cu][-ftS][-HL]", TOYFLAG_BIN|TOYFLAG_LOCALE))
config LS
bool "ls"
default y
help
- usage: ls [-ACFHLRSacdfiklmnpqrstux1] [directory...]
+ usage: ls [-ACFHLRSZacdfiklmnpqrstux1] [directory...]
list files
what to show:
@@ -22,6 +22,7 @@ config LS
-u use access time for timestamps -A list all files but . and ..
-H follow command line symlinks -L follow symlinks
-R recursively list files in subdirs -F append /dir *exe @sym |FIFO
+ -Z security context
output formats:
-1 list one file per line -C columns (sorted vertically)
@@ -32,15 +33,6 @@ config LS
sorting (default is alphabetical):
-f unsorted -r reverse -t timestamp -S size
-config LS_Z
- bool
- default y
- depends on LS && (TOYBOX_SELINUX || TOYBOX_SMACK)
- help
- usage: ls [-Z]
-
- -Z security context
-
config LS_COLOR
bool "ls --color"
default y
@@ -63,7 +55,7 @@ config LS_COLOR
GLOBALS(
char *color;
- struct dirtree *files;
+ struct dirtree *files, *singledir;
unsigned screen_width;
int nl_title;
@@ -129,44 +121,6 @@ static int numlen(long long ll)
return snprintf(0, 0, "%llu", ll);
}
-// measure/print SELinux/smack security label. (If pad=0, just measure.)
-static unsigned seclabel(struct dirtree *dt, int pad)
-{
- if (CFG_TOYBOX_SELINUX) {
- char* path = dirtree_path(dt, 0);
- char* label = 0;
- size_t len;
-
- lgetfilecon(path, &label);
- if (!label) {
- label = strdup("?");
- }
-
- len = strlen(label);
- if (pad) printf(" %*s "+(pad>0), pad, label);
-
- free(label);
- free(path);
- return len;
- } else if (CFG_TOYBOX_SMACK) {
- int fd = openat(dirtree_parentfd(dt), dt->name, O_PATH|O_NOFOLLOW);
- char buf[SMACK_LABEL_LEN+1];
- ssize_t len = 1;
-
- strcpy(buf, "?");
- if (fd != -1) {
- len = fgetxattr(fd, XATTR_NAME_SMACK, pad?buf:0, pad?SMACK_LABEL_LEN:0);
- close(fd);
-
- if (len<1 || len>SMACK_LABEL_LEN) len = 0;
- else buf[len] = 0;
- }
- if (pad) printf(" %*s "+(pad>0), pad, buf);
-
- return len;
- }
-}
-
// Figure out size of printable entry fields for display indent/wrap
static void entrylen(struct dirtree *dt, unsigned *len)
@@ -192,7 +146,7 @@ static void entrylen(struct dirtree *dt, unsigned *len)
}
len[6] = (flags & FLAG_s) ? numlen(st->st_blocks) : 0;
- len[7] = (CFG_LS_Z && (flags & FLAG_Z)) ? seclabel(dt, 0) : 0;
+ len[7] = (flags & FLAG_Z) ? strwidth((char *)dt->extra) : 0;
}
static int compare(void *a, void *b)
@@ -225,6 +179,42 @@ static int filter(struct dirtree *new)
return 0;
}
+ if (flags & FLAG_Z) {
+ if (!CFG_TOYBOX_LSM_NONE) {
+ int fd;
+
+ // Why not just openat(O_PATH|(O_NOFOLLOW*!!(toys.optflags&FLAG_L))) and
+ // lsm_fget_context() on that filehandle? Because the kernel is broken,
+ // and won't let us read this "metadata" from the filehandle unless we
+ // have permission to read the data. We _can_ read the same data in
+ // by path, we just can't do it through an O_PATH filehandle, because
+ // reasons. So as a bug workaround for the broken kernel, we do it
+ // both ways.
+ //
+ // The O_NONBLOCK is there to avoid triggering automounting (there's
+ // a rush of nostalgia for you) on directories we don't descend into,
+ // which O_PATH would have done for us but see "the kernel is broken".
+ if (S_ISSOCK(new->st.st_mode) ||
+ (S_ISLNK(new->st.st_mode) && !(toys.optflags & FLAG_L)) ||
+ -1 == (fd = openat(dirtree_parentfd(new), new->name,
+ O_RDONLY|O_NONBLOCK|O_NOATIME)))
+ {
+ char *path;
+
+ // Wouldn't it be nice if the lsm functions worked like openat(),
+ // fchmodat(), mknodat(), readlinkat() so we could do this without
+ // even O_PATH? But no, this is 1990's tech.
+ path = dirtree_path(new, 0);
+ lsm_lget_context(path, (char **)&new->extra);
+ free(path);
+ } else {
+ lsm_fget_context(fd, (char **)&new->extra);
+ close(fd);
+ }
+ }
+ if (CFG_TOYBOX_LSM_NONE || !new->extra) new->extra = (long)xstrdup("?");
+ }
+
if (flags & FLAG_u) new->st.st_mtime = new->st.st_atime;
if (flags & FLAG_c) new->st.st_mtime = new->st.st_ctime;
if (flags & FLAG_k) new->st.st_blocks = (new->st.st_blocks + 1) / 2;
@@ -303,18 +293,23 @@ static void listfiles(int dirfd, struct dirtree *indir)
memset(totals, 0, sizeof(totals));
- // Silently descend into single directory listed by itself on command line.
- // In this case only show dirname/total header when given -R.
+ // Top level directory was already populated by main()
if (!indir->parent) {
- if (!(dt = indir->child)) return;
- if (S_ISDIR(dt->st.st_mode) && !dt->next && !(flags & FLAG_d)) {
- dt->extra = 1;
- listfiles(open(dt->name, 0), dt);
+ // Silently descend into single directory listed by itself on command line.
+ // In this case only show dirname/total header when given -R.
+ dt = indir->child;
+ if (S_ISDIR(dt->st.st_mode) && !dt->next && !(flags&(FLAG_d|FLAG_R))) {
+ listfiles(open(dt->name, 0), TT.singledir = dt);
return;
}
+
+ // Do preprocessing (Dirtree didn't populate, so callback wasn't called.)
+ for (;dt; dt = dt->next) filter(dt);
+ if (flags == (FLAG_1|FLAG_f)) return;
} else {
// Read directory contents. We dup() the fd because this will close it.
+ // This reads/saves contents to display later, except for in "ls -1f" mode.
indir->data = dup(dirfd);
dirtree_recurse(indir, filter, DIRTREE_SYMFOLLOW*!!(flags&FLAG_L));
}
@@ -329,7 +324,7 @@ static void listfiles(int dirfd, struct dirtree *indir)
}
// Label directory if not top of tree, or if -R
- if (indir->parent && (!indir->extra || (flags & FLAG_R)))
+ if (indir->parent && (TT.singledir!=indir || (flags&FLAG_R)))
{
char *path = dirtree_path(indir, 0);
@@ -350,7 +345,7 @@ static void listfiles(int dirfd, struct dirtree *indir)
blocks += sort[ul]->st.st_blocks;
}
totpad = totals[1]+!!totals[1]+totals[6]+!!totals[6]+totals[7]+!!totals[7];
- if (flags & (FLAG_l|FLAG_o|FLAG_n|FLAG_g|FLAG_s) && indir->parent)
+ if ((flags&(FLAG_l|FLAG_o|FLAG_n|FLAG_g|FLAG_s)) && indir->parent)
xprintf("total %llu\n", blocks);
}
@@ -442,7 +437,8 @@ static void listfiles(int dirfd, struct dirtree *indir)
printf("%s% *ld %s%s%s%s", perm, totals[2]+1, (long)st->st_nlink,
usr, upad, grp, grpad);
- if (CFG_LS_Z && (flags & FLAG_Z)) seclabel(sort[next], -(int)totals[7]);
+ if (flags & FLAG_Z)
+ printf(" %*s ", -(int)totals[7], (char *)sort[next]->extra);
if (S_ISCHR(st->st_mode) || S_ISBLK(st->st_mode))
printf("% *d,% 4d", totals[5]-4, major(st->st_rdev),minor(st->st_rdev));
@@ -451,7 +447,8 @@ static void listfiles(int dirfd, struct dirtree *indir)
tm = localtime(&(st->st_mtime));
strftime(thyme, sizeof(thyme), "%F %H:%M", tm);
xprintf(" %s ", thyme);
- } else if (CFG_LS_Z && (flags & FLAG_Z)) seclabel(sort[next], totals[7]);
+ } else if (flags & FLAG_Z)
+ printf("%*s ", (int)totals[7], (char *)sort[next]->extra);
if (flags & FLAG_color) {
color = color_from_mode(st->st_mode);
@@ -493,12 +490,12 @@ static void listfiles(int dirfd, struct dirtree *indir)
// Free directory entries, recursing first if necessary.
for (ul = 0; ul<dtlen; free(sort[ul++])) {
- if ((flags & FLAG_d) || !S_ISDIR(sort[ul]->st.st_mode)
- || !dirtree_notdotdot(sort[ul])) continue;
+ if ((flags & FLAG_d) || !S_ISDIR(sort[ul]->st.st_mode)) continue;
// Recurse into dirs if at top of the tree or given -R
- if (!indir->parent || (flags & FLAG_R))
+ if (!indir->parent || ((flags&FLAG_R) && dirtree_notdotdot(sort[ul])))
listfiles(openat(dirfd, sort[ul]->name, 0), sort[ul]);
+ free((void *)sort[ul]->extra);
}
free(sort);
if (dirfd != AT_FDCWD) close(dirfd);
diff --git a/toys/posix/mkdir.c b/toys/posix/mkdir.c
index 739f961b..438e38ea 100644
--- a/toys/posix/mkdir.c
+++ b/toys/posix/mkdir.c
@@ -4,7 +4,7 @@
*
* See http://opengroup.org/onlinepubs/9699919799/utilities/mkdir.html
-USE_MKDIR(NEWTOY(mkdir, "<1vpm:", TOYFLAG_BIN|TOYFLAG_UMASK))
+USE_MKDIR(NEWTOY(mkdir, "<1"USE_MKDIR_Z("Z:")"vpm:", TOYFLAG_BIN|TOYFLAG_UMASK))
config MKDIR
bool "mkdir"
@@ -17,6 +17,15 @@ config MKDIR
-m set permissions of directory to mode.
-p make parent directories as needed.
-v verbose
+
+config MKDIR_Z
+ bool
+ default y
+ depends on MKDIR && !TOYBOX_LSM_NONE
+ help
+ usage: [-Z context]
+
+ -Z set security context
*/
#define FOR_mkdir
@@ -24,6 +33,7 @@ config MKDIR
GLOBALS(
char *arg_mode;
+ char *arg_context;
)
void mkdir_main(void)
@@ -31,12 +41,15 @@ void mkdir_main(void)
char **s;
mode_t mode = (0777&~toys.old_umask);
+ if (CFG_MKDIR_Z && (toys.optflags&FLAG_Z))
+ if (0>lsm_set_create(TT.arg_context))
+ error_exit("bad -Z '%s'", TT.arg_context);
if (TT.arg_mode) mode = string_to_mode(TT.arg_mode, 0777);
// Note, -p and -v flags line up with mkpathat() flags
-
- for (s=toys.optargs; *s; s++)
+ for (s=toys.optargs; *s; s++) {
if (mkpathat(AT_FDCWD, *s, mode, toys.optflags|1))
perror_msg("'%s'", *s);
+ }
}