Refactor ls(1)
This commit is contained in:
parent
9da1deaab9
commit
bec3c32dbd
415
ls.c
415
ls.c
|
@ -12,22 +12,16 @@
|
||||||
|
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
typedef struct {
|
struct entry {
|
||||||
char *name;
|
char *name;
|
||||||
mode_t mode, tmode;
|
mode_t mode, tmode;
|
||||||
nlink_t nlink;
|
nlink_t nlink;
|
||||||
uid_t uid;
|
uid_t uid;
|
||||||
gid_t gid;
|
gid_t gid;
|
||||||
off_t size;
|
off_t size;
|
||||||
time_t t;
|
time_t t;
|
||||||
ino_t ino;
|
ino_t ino;
|
||||||
} Entry;
|
};
|
||||||
|
|
||||||
static int entcmp(const void *, const void *);
|
|
||||||
static void ls(Entry *);
|
|
||||||
static void lsdir(const char *);
|
|
||||||
static void mkent(Entry *, char *, int, int);
|
|
||||||
static void output(Entry *);
|
|
||||||
|
|
||||||
static int aflag = 0;
|
static int aflag = 0;
|
||||||
static int cflag = 0;
|
static int cflag = 0;
|
||||||
|
@ -44,6 +38,196 @@ static int Uflag = 0;
|
||||||
static int first = 1;
|
static int first = 1;
|
||||||
static int many;
|
static int many;
|
||||||
|
|
||||||
|
static void
|
||||||
|
mkent(struct entry *ent, char *path, int dostat, int follow)
|
||||||
|
{
|
||||||
|
struct stat st;
|
||||||
|
|
||||||
|
ent->name = path;
|
||||||
|
if (!dostat)
|
||||||
|
return;
|
||||||
|
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;
|
||||||
|
ent->gid = st.st_gid;
|
||||||
|
ent->size = st.st_size;
|
||||||
|
ent->t = cflag ? st.st_ctime : 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 *
|
||||||
|
indicator(mode_t mode)
|
||||||
|
{
|
||||||
|
if (!Fflag)
|
||||||
|
return "";
|
||||||
|
|
||||||
|
if (S_ISLNK(mode))
|
||||||
|
return "@";
|
||||||
|
else if (S_ISDIR(mode))
|
||||||
|
return "/";
|
||||||
|
else if (S_ISFIFO(mode))
|
||||||
|
return "|";
|
||||||
|
else if (S_ISSOCK(mode))
|
||||||
|
return "=";
|
||||||
|
else if (mode & S_IXUSR || mode & S_IXGRP || mode & S_IXOTH)
|
||||||
|
return "*";
|
||||||
|
else
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
output(const struct entry *ent)
|
||||||
|
{
|
||||||
|
struct group *gr;
|
||||||
|
struct passwd *pw;
|
||||||
|
ssize_t len;
|
||||||
|
char buf[BUFSIZ], *fmt,
|
||||||
|
pwname[_SC_LOGIN_NAME_MAX], grname[_SC_LOGIN_NAME_MAX],
|
||||||
|
mode[] = "----------";
|
||||||
|
|
||||||
|
if (iflag)
|
||||||
|
printf("%lu ", (unsigned long)ent->ino);
|
||||||
|
if (!lflag) {
|
||||||
|
printf("%s%s\n", ent->name, indicator(ent->mode));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (S_ISREG(ent->mode))
|
||||||
|
mode[0] = '-';
|
||||||
|
else if (S_ISBLK(ent->mode))
|
||||||
|
mode[0] = 'b';
|
||||||
|
else if (S_ISCHR(ent->mode))
|
||||||
|
mode[0] = 'c';
|
||||||
|
else if (S_ISDIR(ent->mode))
|
||||||
|
mode[0] = 'd';
|
||||||
|
else if (S_ISFIFO(ent->mode))
|
||||||
|
mode[0] = 'p';
|
||||||
|
else if (S_ISLNK(ent->mode))
|
||||||
|
mode[0] = 'l';
|
||||||
|
else if (S_ISSOCK(ent->mode))
|
||||||
|
mode[0] = 's';
|
||||||
|
else
|
||||||
|
mode[0] = '?';
|
||||||
|
|
||||||
|
if (ent->mode & S_IRUSR) mode[1] = 'r';
|
||||||
|
if (ent->mode & S_IWUSR) mode[2] = 'w';
|
||||||
|
if (ent->mode & S_IXUSR) mode[3] = 'x';
|
||||||
|
if (ent->mode & S_IRGRP) mode[4] = 'r';
|
||||||
|
if (ent->mode & S_IWGRP) mode[5] = 'w';
|
||||||
|
if (ent->mode & S_IXGRP) mode[6] = 'x';
|
||||||
|
if (ent->mode & S_IROTH) mode[7] = 'r';
|
||||||
|
if (ent->mode & S_IWOTH) mode[8] = 'w';
|
||||||
|
if (ent->mode & S_IXOTH) mode[9] = 'x';
|
||||||
|
|
||||||
|
if (ent->mode & S_ISUID) mode[3] = (mode[3] == 'x') ? 's' : 'S';
|
||||||
|
if (ent->mode & S_ISGID) mode[6] = (mode[6] == 'x') ? 's' : 'S';
|
||||||
|
if (ent->mode & S_ISVTX) mode[9] = (mode[9] == 'x') ? 't' : 'T';
|
||||||
|
|
||||||
|
pw = getpwuid(ent->uid);
|
||||||
|
if (pw)
|
||||||
|
snprintf(pwname, LEN(pwname), "%s", pw->pw_name);
|
||||||
|
else
|
||||||
|
snprintf(pwname, LEN(pwname), "%d", ent->uid);
|
||||||
|
|
||||||
|
gr = getgrgid(ent->gid);
|
||||||
|
if (gr)
|
||||||
|
snprintf(grname, LEN(grname), "%s", gr->gr_name);
|
||||||
|
else
|
||||||
|
snprintf(grname, LEN(grname), "%d", ent->gid);
|
||||||
|
|
||||||
|
if (time(NULL) > ent->t + (180 * 24 * 60 * 60)) /* 6 months ago? */
|
||||||
|
fmt = "%b %d %Y";
|
||||||
|
else
|
||||||
|
fmt = "%b %d %H:%M";
|
||||||
|
|
||||||
|
strftime(buf, sizeof(buf), fmt, localtime(&ent->t));
|
||||||
|
printf("%s %4ld %-8.8s %-8.8s ", mode, (long)ent->nlink, pwname, grname);
|
||||||
|
if (hflag)
|
||||||
|
printf("%10s ", humansize((unsigned long)ent->size));
|
||||||
|
else
|
||||||
|
printf("%10lu ", (unsigned long)ent->size);
|
||||||
|
printf("%s %s%s", buf, ent->name, indicator(ent->mode));
|
||||||
|
if (S_ISLNK(ent->mode)) {
|
||||||
|
if ((len = readlink(ent->name, buf, sizeof(buf) - 1)) < 0)
|
||||||
|
eprintf("readlink %s:", ent->name);
|
||||||
|
buf[len] = '\0';
|
||||||
|
printf(" -> %s%s", buf, indicator(ent->tmode));
|
||||||
|
}
|
||||||
|
putchar('\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
entcmp(const void *va, const void *vb)
|
||||||
|
{
|
||||||
|
const struct entry *a = va, *b = vb;
|
||||||
|
|
||||||
|
if (tflag)
|
||||||
|
return b->t - a->t;
|
||||||
|
else
|
||||||
|
return strcmp(a->name, b->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
lsdir(const char *path)
|
||||||
|
{
|
||||||
|
DIR *dp;
|
||||||
|
struct entry ent, *ents = NULL;
|
||||||
|
struct dirent *d;
|
||||||
|
size_t i, n = 0;
|
||||||
|
char *cwd, *p;
|
||||||
|
|
||||||
|
cwd = agetcwd();
|
||||||
|
if (!(dp = opendir(path)))
|
||||||
|
eprintf("opendir %s:", path);
|
||||||
|
if (chdir(path) < 0)
|
||||||
|
eprintf("chdir %s:", path);
|
||||||
|
|
||||||
|
if (many) {
|
||||||
|
if (!first)
|
||||||
|
putchar('\n');
|
||||||
|
printf("%s:\n", path);
|
||||||
|
first = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
while ((d = readdir(dp))) {
|
||||||
|
if (d->d_name[0] == '.' && !aflag)
|
||||||
|
continue;
|
||||||
|
if (Uflag){
|
||||||
|
mkent(&ent, d->d_name, Fflag || lflag || iflag, Lflag);
|
||||||
|
output(&ent);
|
||||||
|
} else {
|
||||||
|
ents = erealloc(ents, ++n * sizeof(*ents));
|
||||||
|
p = estrdup(d->d_name);
|
||||||
|
mkent(&ents[n - 1], p, tflag || Fflag || lflag || iflag, Lflag);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
closedir(dp);
|
||||||
|
if (!Uflag){
|
||||||
|
qsort(ents, n, sizeof(*ents), entcmp);
|
||||||
|
for (i = 0; i < n; i++) {
|
||||||
|
output(&ents[rflag ? (n - i - 1) : i]);
|
||||||
|
free(ents[rflag ? (n - i - 1) : i].name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (chdir(cwd) < 0)
|
||||||
|
eprintf("chdir %s:", cwd);
|
||||||
|
free(ents);
|
||||||
|
free(cwd);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
ls(const struct entry *ent)
|
||||||
|
{
|
||||||
|
if ((S_ISDIR(ent->mode) || (S_ISLNK(ent->mode) &&
|
||||||
|
S_ISDIR(ent->tmode) && !Fflag && !lflag)) && !dflag)
|
||||||
|
lsdir(ent->name);
|
||||||
|
else
|
||||||
|
output(ent);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
usage(void)
|
usage(void)
|
||||||
{
|
{
|
||||||
|
@ -53,8 +237,8 @@ usage(void)
|
||||||
int
|
int
|
||||||
main(int argc, char *argv[])
|
main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
int i;
|
struct entry *ents;
|
||||||
Entry *ents;
|
size_t i;
|
||||||
|
|
||||||
ARGBEGIN {
|
ARGBEGIN {
|
||||||
case '1':
|
case '1':
|
||||||
|
@ -108,204 +292,9 @@ main(int argc, char *argv[])
|
||||||
|
|
||||||
for (i = 0; i < argc; i++)
|
for (i = 0; i < argc; i++)
|
||||||
mkent(&ents[i], argv[i], 1, Hflag || Lflag);
|
mkent(&ents[i], argv[i], 1, Hflag || Lflag);
|
||||||
qsort(ents, argc, sizeof *ents, entcmp);
|
qsort(ents, argc, sizeof(*ents), entcmp);
|
||||||
for (i = 0; i < argc; i++)
|
for (i = 0; i < argc; i++)
|
||||||
ls(&ents[rflag ? argc-i-1 : i]);
|
ls(&ents[rflag ? argc-i-1 : i]);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
|
||||||
entcmp(const void *va, const void *vb)
|
|
||||||
{
|
|
||||||
const Entry *a = va, *b = vb;
|
|
||||||
|
|
||||||
if (tflag)
|
|
||||||
return b->t - a->t;
|
|
||||||
else
|
|
||||||
return strcmp(a->name, b->name);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
ls(Entry *ent)
|
|
||||||
{
|
|
||||||
if ((S_ISDIR(ent->mode) || (S_ISLNK(ent->mode) && S_ISDIR(ent->tmode) && !Fflag && !lflag)) && !dflag) {
|
|
||||||
lsdir(ent->name);
|
|
||||||
} else {
|
|
||||||
output(ent);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
lsdir(const char *path)
|
|
||||||
{
|
|
||||||
char *cwd, *p;
|
|
||||||
long i, n = 0;
|
|
||||||
struct dirent *d;
|
|
||||||
DIR *dp;
|
|
||||||
Entry ent, *ents = NULL;
|
|
||||||
size_t sz;
|
|
||||||
|
|
||||||
cwd = agetcwd();
|
|
||||||
if (!(dp = opendir(path)))
|
|
||||||
eprintf("opendir %s:", path);
|
|
||||||
if (chdir(path) < 0)
|
|
||||||
eprintf("chdir %s:", path);
|
|
||||||
|
|
||||||
if (many) {
|
|
||||||
if (!first)
|
|
||||||
putchar('\n');
|
|
||||||
printf("%s:\n", path);
|
|
||||||
first = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
while ((d = readdir(dp))) {
|
|
||||||
if (d->d_name[0] == '.' && !aflag)
|
|
||||||
continue;
|
|
||||||
if (Uflag){
|
|
||||||
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, Lflag);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
closedir(dp);
|
|
||||||
if (!Uflag){
|
|
||||||
qsort(ents, n, sizeof *ents, entcmp);
|
|
||||||
for (i = 0; i < n; i++) {
|
|
||||||
output(&ents[rflag ? n-i-1 : i]);
|
|
||||||
free(ents[rflag ? n-i-1 : i].name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (chdir(cwd) < 0)
|
|
||||||
eprintf("chdir %s:", cwd);
|
|
||||||
free(ents);
|
|
||||||
free(cwd);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
mkent(Entry *ent, char *path, int dostat, int follow)
|
|
||||||
{
|
|
||||||
struct stat st;
|
|
||||||
|
|
||||||
ent->name = path;
|
|
||||||
if (!dostat)
|
|
||||||
return;
|
|
||||||
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;
|
|
||||||
ent->gid = st.st_gid;
|
|
||||||
ent->size = st.st_size;
|
|
||||||
ent->t = cflag ? st.st_ctime : 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 *
|
|
||||||
indicator(mode_t mode)
|
|
||||||
{
|
|
||||||
if (!Fflag)
|
|
||||||
return "";
|
|
||||||
|
|
||||||
if (S_ISLNK(mode))
|
|
||||||
return "@";
|
|
||||||
else if (S_ISDIR(mode))
|
|
||||||
return "/";
|
|
||||||
else if (S_ISFIFO(mode))
|
|
||||||
return "|";
|
|
||||||
else if (S_ISSOCK(mode))
|
|
||||||
return "=";
|
|
||||||
else if (mode & S_IXUSR ||
|
|
||||||
mode & S_IXGRP ||
|
|
||||||
mode & S_IXOTH)
|
|
||||||
return "*";
|
|
||||||
else
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
output(Entry *ent)
|
|
||||||
{
|
|
||||||
char buf[BUFSIZ], *fmt;
|
|
||||||
char mode[] = "----------";
|
|
||||||
ssize_t len;
|
|
||||||
struct group *gr;
|
|
||||||
struct passwd *pw;
|
|
||||||
char pwname[_SC_LOGIN_NAME_MAX];
|
|
||||||
char grname[_SC_LOGIN_NAME_MAX];
|
|
||||||
|
|
||||||
if (iflag)
|
|
||||||
printf("%lu ", (unsigned long)ent->ino);
|
|
||||||
if (!lflag) {
|
|
||||||
printf("%s%s\n", ent->name, indicator(ent->mode));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (S_ISREG(ent->mode))
|
|
||||||
mode[0] = '-';
|
|
||||||
else if (S_ISBLK(ent->mode))
|
|
||||||
mode[0] = 'b';
|
|
||||||
else if (S_ISCHR(ent->mode))
|
|
||||||
mode[0] = 'c';
|
|
||||||
else if (S_ISDIR(ent->mode))
|
|
||||||
mode[0] = 'd';
|
|
||||||
else if (S_ISFIFO(ent->mode))
|
|
||||||
mode[0] = 'p';
|
|
||||||
else if (S_ISLNK(ent->mode))
|
|
||||||
mode[0] = 'l';
|
|
||||||
else if (S_ISSOCK(ent->mode))
|
|
||||||
mode[0] = 's';
|
|
||||||
else
|
|
||||||
mode[0] = '?';
|
|
||||||
|
|
||||||
if (ent->mode & S_IRUSR) mode[1] = 'r';
|
|
||||||
if (ent->mode & S_IWUSR) mode[2] = 'w';
|
|
||||||
if (ent->mode & S_IXUSR) mode[3] = 'x';
|
|
||||||
if (ent->mode & S_IRGRP) mode[4] = 'r';
|
|
||||||
if (ent->mode & S_IWGRP) mode[5] = 'w';
|
|
||||||
if (ent->mode & S_IXGRP) mode[6] = 'x';
|
|
||||||
if (ent->mode & S_IROTH) mode[7] = 'r';
|
|
||||||
if (ent->mode & S_IWOTH) mode[8] = 'w';
|
|
||||||
if (ent->mode & S_IXOTH) mode[9] = 'x';
|
|
||||||
|
|
||||||
if (ent->mode & S_ISUID) mode[3] = (mode[3] == 'x') ? 's' : 'S';
|
|
||||||
if (ent->mode & S_ISGID) mode[6] = (mode[6] == 'x') ? 's' : 'S';
|
|
||||||
if (ent->mode & S_ISVTX) mode[9] = (mode[9] == 'x') ? 't' : 'T';
|
|
||||||
|
|
||||||
pw = getpwuid(ent->uid);
|
|
||||||
if (pw)
|
|
||||||
snprintf(pwname, sizeof(pwname), "%s", pw->pw_name);
|
|
||||||
else
|
|
||||||
snprintf(pwname, sizeof(pwname), "%d", ent->uid);
|
|
||||||
|
|
||||||
gr = getgrgid(ent->gid);
|
|
||||||
if (gr)
|
|
||||||
snprintf(grname, sizeof(grname), "%s", gr->gr_name);
|
|
||||||
else
|
|
||||||
snprintf(grname, sizeof(grname), "%d", ent->gid);
|
|
||||||
|
|
||||||
if (time(NULL) > ent->t + (180*24*60*60)) /* 6 months ago? */
|
|
||||||
fmt = "%b %d %Y";
|
|
||||||
else
|
|
||||||
fmt = "%b %d %H:%M";
|
|
||||||
|
|
||||||
strftime(buf, sizeof buf, fmt, localtime(&ent->t));
|
|
||||||
printf("%s %4ld %-8.8s %-8.8s ", mode, (long)ent->nlink, pwname, grname);
|
|
||||||
if (hflag)
|
|
||||||
printf("%10s ", humansize((unsigned long)ent->size));
|
|
||||||
else
|
|
||||||
printf("%10lu ", (unsigned long)ent->size);
|
|
||||||
printf("%s %s%s", buf, ent->name, indicator(ent->mode));
|
|
||||||
if (S_ISLNK(ent->mode)) {
|
|
||||||
if ((len = readlink(ent->name, buf, sizeof buf - 1)) < 0)
|
|
||||||
eprintf("readlink %s:", ent->name);
|
|
||||||
buf[len] = '\0';
|
|
||||||
printf(" -> %s%s", buf, indicator(ent->tmode));
|
|
||||||
}
|
|
||||||
putchar('\n');
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user