sbase

suckless unix tools
git clone git://git.suckless.org/sbase
Log | Files | Refs | README | LICENSE

commit 46ea55a258084cc660eb93a39432c879cf70cb32
parent c4014b730e8ccd65c688fa61597353149ddbcf56
Author: Michael Forney <mforney@mforney.org>
Date:   Mon,  8 Dec 2014 01:33:52 +0000

ls: Handle symlinks to directories properly

Also, implement the -H and -L options.

Diffstat:
Mls.1 | 9++++++++-
Mls.c | 32++++++++++++++++++++------------
2 files changed, 28 insertions(+), 13 deletions(-)

diff --git a/ls.1 b/ls.1 @@ -3,7 +3,7 @@ ls \- list directory contents .SH SYNOPSIS .B ls -.RB [ \-adFiltU ] +.RB [ \-adFHhiLlrtU ] .RI [ file ...] .SH DESCRIPTION .B ls @@ -20,12 +20,19 @@ lists directories themselves, not their contents. .B \-F append a file type indicator to files. .TP +.B \-H +list information about the targets of symbolic links specified on the command +line instead of the links themselves. +.TP .B \-h show filesizes in human\-readable format. .TP .B \-i print the index number of each file. .TP +.B \-L +list information about the targets of symbolic links instead of the links +themselves. .B \-l lists detailed information about each file, including their type, permissions, links, owner, group, size, and modification time. diff --git a/ls.c b/ls.c @@ -14,7 +14,7 @@ typedef struct { char *name; - mode_t mode; + mode_t mode, tmode; nlink_t nlink; uid_t uid; gid_t gid; @@ -26,14 +26,16 @@ typedef struct { static int entcmp(const void *, const void *); static void ls(Entry *); static void lsdir(const char *); -static void mkent(Entry *, char *, int); +static void mkent(Entry *, char *, int, int); static void output(Entry *); static int aflag = 0; static int dflag = 0; static int Fflag = 0; +static int Hflag = 0; static int hflag = 0; static int iflag = 0; +static int Lflag = 0; static int lflag = 0; static int rflag = 0; static int tflag = 0; @@ -66,12 +68,18 @@ main(int argc, char *argv[]) case 'F': Fflag = 1; break; + case 'H': + Hflag = 1; + break; case 'h': hflag = 1; break; case 'i': iflag = 1; break; + case 'L': + Lflag = 1; + break; case 'l': lflag = 1; break; @@ -95,7 +103,7 @@ main(int argc, char *argv[]) ents = emalloc(argc * sizeof(*ents)); for (i = 0; i < argc; i++) - mkent(&ents[i], argv[i], 1); + mkent(&ents[i], argv[i], 1, Hflag || Lflag); qsort(ents, argc, sizeof *ents, entcmp); for (i = 0; i < argc; i++) ls(&ents[rflag ? argc-i-1 : i]); @@ -117,7 +125,7 @@ entcmp(const void *va, const void *vb) static void ls(Entry *ent) { - if (S_ISDIR(ent->mode) && !dflag) { + if ((S_ISDIR(ent->mode) || (S_ISLNK(ent->mode) && S_ISDIR(ent->tmode) && !Fflag && !lflag)) && !dflag) { lsdir(ent->name); } else { output(ent); @@ -151,13 +159,13 @@ lsdir(const char *path) if (d->d_name[0] == '.' && !aflag) continue; if (Uflag){ - mkent(&ent, d->d_name, Fflag || lflag || iflag); + mkent(&ent, d->d_name, Fflag || lflag || iflag, Lflag); output(&ent); } else { ents = erealloc(ents, ++n * sizeof *ents); p = emalloc((sz = strlen(d->d_name)+1)); memcpy(p, d->d_name, sz); - mkent(&ents[n-1], p, tflag || Fflag || lflag || iflag); + mkent(&ents[n-1], p, tflag || Fflag || lflag || iflag, Lflag); } } closedir(dp); @@ -175,15 +183,15 @@ lsdir(const char *path) } static void -mkent(Entry *ent, char *path, int dostat) +mkent(Entry *ent, char *path, int dostat, int follow) { struct stat st; ent->name = path; if (!dostat) return; - if (lstat(path, &st) < 0) - eprintf("lstat %s:", path); + if ((follow ? stat : lstat)(path, &st) < 0) + eprintf("%s %s:", follow ? "stat" : "lstat", path); ent->mode = st.st_mode; ent->nlink = st.st_nlink; ent->uid = st.st_uid; @@ -191,6 +199,8 @@ mkent(Entry *ent, char *path, int dostat) ent->size = st.st_size; ent->mtime = st.st_mtime; ent->ino = st.st_ino; + if (S_ISLNK(ent->mode)) + ent->tmode = stat(path, &st) == 0 ? st.st_mode : 0; } static char * @@ -225,7 +235,6 @@ output(Entry *ent) struct passwd *pw; char pwname[_SC_LOGIN_NAME_MAX]; char grname[_SC_LOGIN_NAME_MAX]; - Entry entlnk; if (iflag) printf("%lu ", (unsigned long)ent->ino); @@ -294,8 +303,7 @@ output(Entry *ent) if ((len = readlink(ent->name, buf, sizeof buf)) < 0) eprintf("readlink %s:", ent->name); buf[len] = '\0'; - mkent(&entlnk, buf, Fflag); - printf(" -> %s%s", buf, indicator(entlnk.mode)); + printf(" -> %s%s", buf, indicator(ent->tmode)); } putchar('\n'); }