aboutsummaryrefslogtreecommitdiff
path: root/toys/posix/ls.c
diff options
context:
space:
mode:
Diffstat (limited to 'toys/posix/ls.c')
-rw-r--r--toys/posix/ls.c109
1 files changed, 46 insertions, 63 deletions
diff --git a/toys/posix/ls.c b/toys/posix/ls.c
index 35d1034a..ae0466bf 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
@@ -55,6 +47,7 @@ config LS_COLOR
#define FOR_ls
#include "toys.h"
+#include "lib/lsm.h"
// test sst output (suid/sticky in ls flaglist)
@@ -63,7 +56,7 @@ config LS_COLOR
GLOBALS(
char *color;
- struct dirtree *files;
+ struct dirtree *files, *singledir;
unsigned screen_width;
int nl_title;
@@ -129,44 +122,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 +147,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 +180,32 @@ static int filter(struct dirtree *new)
return 0;
}
+ if (flags & FLAG_Z) {
+ if (!CFG_TOYBOX_LSM_NONE) {
+ // In theory we can just openat(O_PATH|O_NOFOLLOW) and getcontext() on
+ // that filehandle, but the kernel won't let us read this "metadata"
+ // unless we have permission to read the data, so we do these elaborate
+ // bug workarounds instead.
+ if (S_ISLNK(new->st.st_mode) && !(toys.optflags & FLAG_L)) {
+ char *path;
+
+ // Wouldn't it be nice if the lsm functions worked like openat(),
+ // fchmodat(), mknodat(), readlinkat()... but no, this is 1990's tech.
+ path = dirtree_path(new, 0);
+ lsm_lget_context(path, (char **)&new->extra);
+ free(path);
+ } else {
+ // Why O_NONBLOCK? No idea. Why not O_PATH|O_NOFOLLOW? Because reasons.
+ int fd = openat(dirtree_parentfd(new), new->name,
+ O_RDONLY|O_NONBLOCK|O_NOATIME);
+
+ if (fd != -1) 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 +284,19 @@ 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;
+ // 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)) {
- dt->extra = 1;
- listfiles(open(dt->name, 0), dt);
+ listfiles(open(dt->name, 0), TT.singledir = dt);
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 +311,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 +332,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 +424,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 +434,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,11 +477,10 @@ 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(sort);