2011-05-25 23:01:20 -04:00
|
|
|
/* See LICENSE file for copyright and license details. */
|
2015-02-14 15:02:41 -05:00
|
|
|
#include <sys/stat.h>
|
2015-10-04 07:10:28 -04:00
|
|
|
#include <sys/types.h>
|
2015-02-14 15:02:41 -05:00
|
|
|
|
2011-05-25 23:01:20 -04:00
|
|
|
#include <dirent.h>
|
|
|
|
#include <grp.h>
|
|
|
|
#include <pwd.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <time.h>
|
|
|
|
#include <unistd.h>
|
2014-11-13 12:29:30 -05:00
|
|
|
|
2015-02-17 12:59:01 -05:00
|
|
|
#include "utf.h"
|
2011-05-25 23:01:20 -04:00
|
|
|
#include "util.h"
|
|
|
|
|
2015-02-16 13:20:06 -05:00
|
|
|
struct entry {
|
|
|
|
char *name;
|
|
|
|
mode_t mode, tmode;
|
2011-05-25 23:01:20 -04:00
|
|
|
nlink_t nlink;
|
2015-02-16 13:20:06 -05:00
|
|
|
uid_t uid;
|
|
|
|
gid_t gid;
|
|
|
|
off_t size;
|
2015-11-01 12:12:46 -05:00
|
|
|
struct timespec t;
|
2015-06-12 14:03:04 -04:00
|
|
|
dev_t dev;
|
2015-10-04 07:10:28 -04:00
|
|
|
dev_t rdev;
|
2015-06-12 14:03:04 -04:00
|
|
|
ino_t ino, tino;
|
2015-02-16 13:20:06 -05:00
|
|
|
};
|
2011-05-25 23:01:20 -04:00
|
|
|
|
2015-06-12 14:03:04 -04:00
|
|
|
static struct {
|
|
|
|
dev_t dev;
|
|
|
|
ino_t ino;
|
2015-09-06 16:33:41 -04:00
|
|
|
} tree[PATH_MAX];
|
2015-06-12 14:03:04 -04:00
|
|
|
|
2016-02-18 06:06:21 -05:00
|
|
|
static int ret = 0;
|
2015-02-21 04:30:08 -05:00
|
|
|
static int Aflag = 0;
|
2014-11-13 15:24:47 -05:00
|
|
|
static int aflag = 0;
|
2015-01-20 11:50:37 -05:00
|
|
|
static int cflag = 0;
|
2014-11-13 15:24:47 -05:00
|
|
|
static int dflag = 0;
|
|
|
|
static int Fflag = 0;
|
2015-03-18 14:26:42 -04:00
|
|
|
static int fflag = 0;
|
2014-12-07 20:33:52 -05:00
|
|
|
static int Hflag = 0;
|
2014-11-13 15:24:47 -05:00
|
|
|
static int hflag = 0;
|
|
|
|
static int iflag = 0;
|
2014-12-07 20:33:52 -05:00
|
|
|
static int Lflag = 0;
|
2014-11-13 15:24:47 -05:00
|
|
|
static int lflag = 0;
|
2015-02-22 06:55:38 -05:00
|
|
|
static int nflag = 0;
|
2015-02-19 13:48:15 -05:00
|
|
|
static int pflag = 0;
|
2015-02-17 12:59:01 -05:00
|
|
|
static int qflag = 0;
|
2015-02-21 05:45:15 -05:00
|
|
|
static int Rflag = 0;
|
2014-11-13 15:24:47 -05:00
|
|
|
static int rflag = 0;
|
|
|
|
static int Uflag = 0;
|
2015-02-18 11:29:46 -05:00
|
|
|
static int uflag = 0;
|
2014-11-13 15:24:47 -05:00
|
|
|
static int first = 1;
|
2015-06-12 14:51:51 -04:00
|
|
|
static char sort = 0;
|
2016-05-14 21:56:52 -04:00
|
|
|
static int showdirs;
|
2011-05-25 23:01:20 -04:00
|
|
|
|
2015-06-12 13:38:07 -04:00
|
|
|
static void ls(const char *, const struct entry *, int);
|
2015-02-21 05:45:15 -05:00
|
|
|
|
2013-06-14 14:20:47 -04:00
|
|
|
static void
|
2015-02-16 13:20:06 -05:00
|
|
|
mkent(struct entry *ent, char *path, int dostat, int follow)
|
2011-05-25 23:01:20 -04:00
|
|
|
{
|
|
|
|
struct stat st;
|
|
|
|
|
2015-02-16 13:20:06 -05:00
|
|
|
ent->name = path;
|
2014-11-13 12:29:30 -05:00
|
|
|
if (!dostat)
|
2013-07-18 15:14:53 -04:00
|
|
|
return;
|
2014-12-07 20:33:52 -05:00
|
|
|
if ((follow ? stat : lstat)(path, &st) < 0)
|
|
|
|
eprintf("%s %s:", follow ? "stat" : "lstat", path);
|
2015-02-16 13:20:06 -05:00
|
|
|
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;
|
2015-02-18 11:29:46 -05:00
|
|
|
if (cflag)
|
2015-11-01 12:12:46 -05:00
|
|
|
ent->t = st.st_ctim;
|
2015-02-18 11:29:46 -05:00
|
|
|
else if (uflag)
|
2015-11-01 12:12:46 -05:00
|
|
|
ent->t = st.st_atim;
|
2015-02-18 11:29:46 -05:00
|
|
|
else
|
2015-11-01 12:12:46 -05:00
|
|
|
ent->t = st.st_mtim;
|
2015-06-12 14:03:04 -04:00
|
|
|
ent->dev = st.st_dev;
|
2015-10-04 07:10:28 -04:00
|
|
|
ent->rdev = st.st_rdev;
|
2015-02-16 13:20:06 -05:00
|
|
|
ent->ino = st.st_ino;
|
2015-06-12 14:03:04 -04:00
|
|
|
if (S_ISLNK(ent->mode)) {
|
|
|
|
if (stat(path, &st) == 0) {
|
|
|
|
ent->tmode = st.st_mode;
|
|
|
|
ent->dev = st.st_dev;
|
|
|
|
ent->tino = st.st_ino;
|
|
|
|
} else {
|
|
|
|
ent->tmode = ent->tino = 0;
|
|
|
|
}
|
|
|
|
}
|
2011-05-25 23:01:20 -04:00
|
|
|
}
|
|
|
|
|
2014-06-01 08:59:47 -04:00
|
|
|
static char *
|
2014-02-17 09:41:09 -05:00
|
|
|
indicator(mode_t mode)
|
|
|
|
{
|
2015-02-19 13:48:15 -05:00
|
|
|
if (pflag || Fflag)
|
|
|
|
if (S_ISDIR(mode))
|
|
|
|
return "/";
|
2014-02-17 09:41:09 -05:00
|
|
|
|
2015-02-19 13:48:15 -05:00
|
|
|
if (Fflag) {
|
|
|
|
if (S_ISLNK(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 "*";
|
|
|
|
}
|
|
|
|
|
|
|
|
return "";
|
2014-02-17 09:41:09 -05:00
|
|
|
}
|
|
|
|
|
2016-10-06 05:16:32 -04:00
|
|
|
static void
|
|
|
|
printname(const char *name)
|
2016-10-05 17:43:30 -04:00
|
|
|
{
|
2016-10-06 05:16:32 -04:00
|
|
|
const char *c;
|
2016-10-05 17:43:30 -04:00
|
|
|
Rune r;
|
|
|
|
size_t l;
|
|
|
|
|
2016-10-06 05:16:32 -04:00
|
|
|
for (c = name; *c; c += l) {
|
|
|
|
l = chartorune(&r, c);
|
|
|
|
if (!qflag || isprintrune(r))
|
|
|
|
fwrite(c, 1, l, stdout);
|
|
|
|
else
|
|
|
|
putchar('?');
|
2016-10-05 17:43:30 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-06-01 08:59:47 -04:00
|
|
|
static void
|
2015-02-16 13:20:06 -05:00
|
|
|
output(const struct entry *ent)
|
2011-05-25 23:01:20 -04:00
|
|
|
{
|
|
|
|
struct group *gr;
|
|
|
|
struct passwd *pw;
|
2016-03-27 08:49:45 -04:00
|
|
|
struct tm *tm;
|
2015-02-16 13:20:06 -05:00
|
|
|
ssize_t len;
|
2016-10-05 17:43:30 -04:00
|
|
|
char *fmt, buf[BUFSIZ], pwname[_SC_LOGIN_NAME_MAX],
|
2016-10-06 05:16:32 -04:00
|
|
|
grname[_SC_LOGIN_NAME_MAX], mode[] = "----------";
|
2011-05-25 23:01:20 -04:00
|
|
|
|
2013-09-27 10:32:50 -04:00
|
|
|
if (iflag)
|
|
|
|
printf("%lu ", (unsigned long)ent->ino);
|
2014-11-13 12:29:30 -05:00
|
|
|
if (!lflag) {
|
2016-10-06 05:16:32 -04:00
|
|
|
printname(ent->name);
|
|
|
|
puts(indicator(ent->mode));
|
|
|
|
return;
|
2011-05-25 23:01:20 -04:00
|
|
|
}
|
2014-11-13 12:29:30 -05:00
|
|
|
if (S_ISREG(ent->mode))
|
2011-05-25 23:01:20 -04:00
|
|
|
mode[0] = '-';
|
2014-11-13 12:29:30 -05:00
|
|
|
else if (S_ISBLK(ent->mode))
|
2011-05-25 23:01:20 -04:00
|
|
|
mode[0] = 'b';
|
2014-11-13 12:29:30 -05:00
|
|
|
else if (S_ISCHR(ent->mode))
|
2011-05-25 23:01:20 -04:00
|
|
|
mode[0] = 'c';
|
2014-11-13 12:29:30 -05:00
|
|
|
else if (S_ISDIR(ent->mode))
|
2011-05-25 23:01:20 -04:00
|
|
|
mode[0] = 'd';
|
2014-11-13 12:29:30 -05:00
|
|
|
else if (S_ISFIFO(ent->mode))
|
2011-05-25 23:01:20 -04:00
|
|
|
mode[0] = 'p';
|
2014-11-13 12:29:30 -05:00
|
|
|
else if (S_ISLNK(ent->mode))
|
2011-05-25 23:01:20 -04:00
|
|
|
mode[0] = 'l';
|
2014-11-13 12:29:30 -05:00
|
|
|
else if (S_ISSOCK(ent->mode))
|
2011-05-25 23:01:20 -04:00
|
|
|
mode[0] = 's';
|
|
|
|
else
|
|
|
|
mode[0] = '?';
|
|
|
|
|
2014-11-13 12:29:30 -05:00
|
|
|
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';
|
2011-05-27 18:56:43 -04:00
|
|
|
|
2014-11-13 12:29:30 -05:00
|
|
|
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';
|
2011-05-25 23:01:20 -04:00
|
|
|
|
2015-02-22 06:55:38 -05:00
|
|
|
if (!nflag && (pw = getpwuid(ent->uid)))
|
2015-09-06 16:35:14 -04:00
|
|
|
snprintf(pwname, sizeof(pwname), "%s", pw->pw_name);
|
2014-12-21 16:58:09 -05:00
|
|
|
else
|
2015-09-06 16:35:14 -04:00
|
|
|
snprintf(pwname, sizeof(pwname), "%d", ent->uid);
|
2011-05-25 23:01:20 -04:00
|
|
|
|
2015-02-22 06:55:38 -05:00
|
|
|
if (!nflag && (gr = getgrgid(ent->gid)))
|
2015-09-06 16:35:14 -04:00
|
|
|
snprintf(grname, sizeof(grname), "%s", gr->gr_name);
|
2014-12-21 16:58:09 -05:00
|
|
|
else
|
2015-09-06 16:35:14 -04:00
|
|
|
snprintf(grname, sizeof(grname), "%d", ent->gid);
|
2011-05-25 23:01:20 -04:00
|
|
|
|
2015-11-01 12:12:46 -05:00
|
|
|
if (time(NULL) > ent->t.tv_sec + (180 * 24 * 60 * 60)) /* 6 months ago? */
|
2011-06-04 07:40:05 -04:00
|
|
|
fmt = "%b %d %Y";
|
2011-05-25 23:01:20 -04:00
|
|
|
else
|
|
|
|
fmt = "%b %d %H:%M";
|
|
|
|
|
2016-03-27 08:49:45 -04:00
|
|
|
if ((tm = localtime(&ent->t.tv_sec)))
|
|
|
|
strftime(buf, sizeof(buf), fmt, tm);
|
|
|
|
else
|
|
|
|
snprintf(buf, sizeof(buf), "%lld", (long long)(ent->t.tv_sec));
|
2014-10-19 05:48:04 -04:00
|
|
|
printf("%s %4ld %-8.8s %-8.8s ", mode, (long)ent->nlink, pwname, grname);
|
2015-02-22 06:55:38 -05:00
|
|
|
|
2015-10-04 07:10:28 -04:00
|
|
|
if (S_ISBLK(ent->mode) || S_ISCHR(ent->mode))
|
|
|
|
printf("%4u, %4u ", major(ent->rdev), minor(ent->rdev));
|
|
|
|
else if (hflag)
|
2015-04-24 18:27:20 -04:00
|
|
|
printf("%10s ", humansize(ent->size));
|
2014-10-19 05:48:04 -04:00
|
|
|
else
|
|
|
|
printf("%10lu ", (unsigned long)ent->size);
|
2016-10-06 05:16:32 -04:00
|
|
|
printf("%s ", buf);
|
|
|
|
printname(ent->name);
|
|
|
|
fputs(indicator(ent->mode), stdout);
|
2014-11-13 12:29:30 -05:00
|
|
|
if (S_ISLNK(ent->mode)) {
|
2015-02-16 13:20:06 -05:00
|
|
|
if ((len = readlink(ent->name, buf, sizeof(buf) - 1)) < 0)
|
2011-06-04 07:40:05 -04:00
|
|
|
eprintf("readlink %s:", ent->name);
|
|
|
|
buf[len] = '\0';
|
2014-12-07 20:33:52 -05:00
|
|
|
printf(" -> %s%s", buf, indicator(ent->tmode));
|
2011-06-04 07:40:05 -04:00
|
|
|
}
|
|
|
|
putchar('\n');
|
2011-05-25 23:01:20 -04:00
|
|
|
}
|
2015-02-16 13:20:06 -05:00
|
|
|
|
|
|
|
static int
|
|
|
|
entcmp(const void *va, const void *vb)
|
|
|
|
{
|
2015-03-18 14:26:42 -04:00
|
|
|
int cmp = 0;
|
2015-02-16 13:20:06 -05:00
|
|
|
const struct entry *a = va, *b = vb;
|
|
|
|
|
2015-06-12 14:51:51 -04:00
|
|
|
switch (sort) {
|
|
|
|
case 'S':
|
2015-03-18 14:26:42 -04:00
|
|
|
cmp = b->size - a->size;
|
2015-06-12 14:51:51 -04:00
|
|
|
break;
|
|
|
|
case 't':
|
2015-11-01 12:12:46 -05:00
|
|
|
if (!(cmp = b->t.tv_sec - a->t.tv_sec))
|
|
|
|
cmp = b->t.tv_nsec - a->t.tv_nsec;
|
2015-06-12 14:51:51 -04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!cmp)
|
|
|
|
cmp = strcmp(a->name, b->name);
|
2015-03-18 14:26:42 -04:00
|
|
|
|
2015-06-12 14:51:51 -04:00
|
|
|
return rflag ? 0 - cmp : cmp;
|
2015-02-16 13:20:06 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2015-06-12 13:38:07 -04:00
|
|
|
lsdir(const char *path, const struct entry *dir)
|
2015-02-16 13:20:06 -05:00
|
|
|
{
|
|
|
|
DIR *dp;
|
2015-06-12 13:38:07 -04:00
|
|
|
struct entry *ent, *ents = NULL;
|
2015-02-16 13:20:06 -05:00
|
|
|
struct dirent *d;
|
2015-06-12 09:09:32 -04:00
|
|
|
size_t i, n = 0;
|
2016-10-06 05:16:32 -04:00
|
|
|
char prefix[PATH_MAX];
|
2015-02-16 13:20:06 -05:00
|
|
|
|
2016-02-18 06:06:21 -05:00
|
|
|
if (!(dp = opendir(dir->name))) {
|
|
|
|
ret = 1;
|
2016-02-18 06:48:10 -05:00
|
|
|
weprintf("opendir %s%s:", path, dir->name);
|
2017-08-22 00:51:37 -04:00
|
|
|
return;
|
2016-02-18 06:06:21 -05:00
|
|
|
}
|
2015-06-12 13:38:07 -04:00
|
|
|
if (chdir(dir->name) < 0)
|
|
|
|
eprintf("chdir %s:", dir->name);
|
2015-02-16 13:20:06 -05:00
|
|
|
|
|
|
|
while ((d = readdir(dp))) {
|
2015-02-21 04:30:08 -05:00
|
|
|
if (d->d_name[0] == '.' && !aflag && !Aflag)
|
2015-02-16 13:20:06 -05:00
|
|
|
continue;
|
2015-02-21 04:30:08 -05:00
|
|
|
else if (Aflag)
|
2015-06-12 13:38:07 -04:00
|
|
|
if (strcmp(d->d_name, ".") == 0 ||
|
|
|
|
strcmp(d->d_name, "..") == 0)
|
2015-02-21 04:30:08 -05:00
|
|
|
continue;
|
2015-06-12 13:38:07 -04:00
|
|
|
|
|
|
|
ents = ereallocarray(ents, ++n, sizeof(*ents));
|
|
|
|
mkent(&ents[n - 1], estrdup(d->d_name), Fflag || iflag ||
|
2015-06-12 14:51:51 -04:00
|
|
|
lflag || pflag || Rflag || sort, Lflag);
|
2015-02-16 13:20:06 -05:00
|
|
|
}
|
2015-06-12 13:38:07 -04:00
|
|
|
|
2015-02-16 13:20:06 -05:00
|
|
|
closedir(dp);
|
2015-06-12 13:38:07 -04:00
|
|
|
|
|
|
|
if (!Uflag)
|
2015-02-16 13:20:06 -05:00
|
|
|
qsort(ents, n, sizeof(*ents), entcmp);
|
2015-06-12 13:38:07 -04:00
|
|
|
|
2016-10-05 17:43:30 -04:00
|
|
|
if (path[0] || showdirs) {
|
2016-10-06 05:16:32 -04:00
|
|
|
fputs(path, stdout);
|
|
|
|
printname(dir->name);
|
|
|
|
puts(":");
|
2016-10-05 17:43:30 -04:00
|
|
|
}
|
2015-06-12 13:38:07 -04:00
|
|
|
for (i = 0; i < n; i++)
|
2015-06-12 14:51:51 -04:00
|
|
|
output(&ents[i]);
|
2015-06-12 13:38:07 -04:00
|
|
|
|
|
|
|
if (Rflag) {
|
|
|
|
if (snprintf(prefix, PATH_MAX, "%s%s/", path, dir->name) >=
|
|
|
|
PATH_MAX)
|
|
|
|
eprintf("path too long: %s%s\n", path, dir->name);
|
|
|
|
|
2015-02-16 13:20:06 -05:00
|
|
|
for (i = 0; i < n; i++) {
|
2015-06-12 14:51:51 -04:00
|
|
|
ent = &ents[i];
|
2015-06-12 13:38:07 -04:00
|
|
|
if (strcmp(ent->name, ".") == 0 ||
|
|
|
|
strcmp(ent->name, "..") == 0)
|
|
|
|
continue;
|
|
|
|
if (S_ISLNK(ent->mode) && S_ISDIR(ent->tmode) && !Lflag)
|
|
|
|
continue;
|
|
|
|
|
2016-05-14 21:56:53 -04:00
|
|
|
ls(prefix, ent, 1);
|
2015-02-16 13:20:06 -05:00
|
|
|
}
|
|
|
|
}
|
2015-06-12 13:38:07 -04:00
|
|
|
|
|
|
|
for (i = 0; i < n; ++i)
|
|
|
|
free(ents[i].name);
|
2015-02-16 13:20:06 -05:00
|
|
|
free(ents);
|
|
|
|
}
|
|
|
|
|
2015-06-12 14:03:04 -04:00
|
|
|
static int
|
|
|
|
visit(const struct entry *ent)
|
|
|
|
{
|
|
|
|
dev_t dev;
|
|
|
|
ino_t ino;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
dev = ent->dev;
|
|
|
|
ino = S_ISLNK(ent->mode) ? ent->tino : ent->ino;
|
|
|
|
|
2016-02-18 09:16:25 -05:00
|
|
|
for (i = 0; i < PATH_MAX && tree[i].ino; ++i) {
|
2015-06-12 14:03:04 -04:00
|
|
|
if (ino == tree[i].ino && dev == tree[i].dev)
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
tree[i].ino = ino;
|
|
|
|
tree[i].dev = dev;
|
2015-09-06 16:33:41 -04:00
|
|
|
|
2015-06-12 14:03:04 -04:00
|
|
|
return i;
|
|
|
|
}
|
|
|
|
|
2015-02-16 13:20:06 -05:00
|
|
|
static void
|
2015-06-12 13:38:07 -04:00
|
|
|
ls(const char *path, const struct entry *ent, int listdir)
|
2015-02-16 13:20:06 -05:00
|
|
|
{
|
2015-06-12 14:03:04 -04:00
|
|
|
int treeind;
|
2015-06-12 13:38:07 -04:00
|
|
|
char cwd[PATH_MAX];
|
|
|
|
|
|
|
|
if (!listdir) {
|
2015-02-16 13:20:06 -05:00
|
|
|
output(ent);
|
2015-06-12 13:38:07 -04:00
|
|
|
} else if (S_ISDIR(ent->mode) ||
|
|
|
|
(S_ISLNK(ent->mode) && S_ISDIR(ent->tmode))) {
|
2015-06-12 14:03:04 -04:00
|
|
|
if ((treeind = visit(ent)) < 0) {
|
2016-02-18 06:46:48 -05:00
|
|
|
ret = 1;
|
|
|
|
weprintf("%s%s: Already visited\n", path, ent->name);
|
2015-06-12 14:03:04 -04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-06-12 13:38:07 -04:00
|
|
|
if (!getcwd(cwd, PATH_MAX))
|
|
|
|
eprintf("getcwd:");
|
|
|
|
|
|
|
|
if (first)
|
2016-05-14 21:56:53 -04:00
|
|
|
first = 0;
|
2015-06-12 13:38:07 -04:00
|
|
|
else
|
|
|
|
putchar('\n');
|
|
|
|
|
|
|
|
lsdir(path, ent);
|
2015-06-12 14:03:04 -04:00
|
|
|
tree[treeind].ino = 0;
|
2015-06-12 13:38:07 -04:00
|
|
|
|
|
|
|
if (chdir(cwd) < 0)
|
|
|
|
eprintf("chdir %s:", cwd);
|
|
|
|
}
|
2015-02-16 13:20:06 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
usage(void)
|
|
|
|
{
|
2015-09-06 16:36:21 -04:00
|
|
|
eprintf("usage: %s [-1AacdFfHhiLlnpqRrtUu] [file ...]\n", argv0);
|
2015-02-16 13:20:06 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
main(int argc, char *argv[])
|
|
|
|
{
|
2015-11-01 12:12:25 -05:00
|
|
|
struct entry ent, *dents, *fents;
|
2016-05-14 21:56:51 -04:00
|
|
|
size_t i, ds, fs;
|
2015-02-16 13:20:06 -05:00
|
|
|
|
|
|
|
ARGBEGIN {
|
|
|
|
case '1':
|
2016-03-02 05:28:18 -05:00
|
|
|
/* force output to 1 entry per line */
|
|
|
|
qflag = 1;
|
2015-02-16 13:20:06 -05:00
|
|
|
break;
|
2015-02-21 04:30:08 -05:00
|
|
|
case 'A':
|
|
|
|
Aflag = 1;
|
|
|
|
break;
|
2015-02-16 13:20:06 -05:00
|
|
|
case 'a':
|
|
|
|
aflag = 1;
|
|
|
|
break;
|
|
|
|
case 'c':
|
|
|
|
cflag = 1;
|
2015-02-18 11:29:46 -05:00
|
|
|
uflag = 0;
|
2015-02-16 13:20:06 -05:00
|
|
|
break;
|
|
|
|
case 'd':
|
|
|
|
dflag = 1;
|
|
|
|
break;
|
2015-03-18 14:26:42 -04:00
|
|
|
case 'f':
|
|
|
|
aflag = 1;
|
|
|
|
fflag = 1;
|
|
|
|
Uflag = 1;
|
|
|
|
break;
|
2015-02-16 13:20:06 -05:00
|
|
|
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;
|
2015-02-22 06:55:38 -05:00
|
|
|
case 'n':
|
|
|
|
lflag = 1;
|
|
|
|
nflag = 1;
|
|
|
|
break;
|
2015-02-19 13:48:15 -05:00
|
|
|
case 'p':
|
|
|
|
pflag = 1;
|
|
|
|
break;
|
2015-02-17 12:59:01 -05:00
|
|
|
case 'q':
|
|
|
|
qflag = 1;
|
|
|
|
break;
|
2015-02-21 05:45:15 -05:00
|
|
|
case 'R':
|
|
|
|
Rflag = 1;
|
|
|
|
break;
|
2015-02-16 13:20:06 -05:00
|
|
|
case 'r':
|
2015-06-12 14:51:51 -04:00
|
|
|
rflag = 1;
|
2015-03-18 14:26:42 -04:00
|
|
|
break;
|
|
|
|
case 'S':
|
2015-06-12 14:51:51 -04:00
|
|
|
sort = 'S';
|
2015-02-16 13:20:06 -05:00
|
|
|
break;
|
|
|
|
case 't':
|
2015-06-12 14:51:51 -04:00
|
|
|
sort = 't';
|
2015-02-16 13:20:06 -05:00
|
|
|
break;
|
|
|
|
case 'U':
|
|
|
|
Uflag = 1;
|
|
|
|
break;
|
2015-02-18 11:29:46 -05:00
|
|
|
case 'u':
|
|
|
|
uflag = 1;
|
|
|
|
cflag = 0;
|
|
|
|
break;
|
2015-02-16 13:20:06 -05:00
|
|
|
default:
|
|
|
|
usage();
|
2015-11-01 05:16:49 -05:00
|
|
|
} ARGEND
|
2015-02-16 13:20:06 -05:00
|
|
|
|
2015-06-12 10:22:46 -04:00
|
|
|
switch (argc) {
|
|
|
|
case 0: /* fallthrough */
|
|
|
|
*--argv = ".", ++argc;
|
2015-08-31 12:02:10 -04:00
|
|
|
case 1:
|
2015-11-01 12:12:25 -05:00
|
|
|
mkent(&ent, argv[0], 1, Hflag || Lflag);
|
|
|
|
ls("", &ent, (!dflag && S_ISDIR(ent.mode)) ||
|
2016-05-14 21:56:53 -04:00
|
|
|
(S_ISLNK(ent.mode) && S_ISDIR(ent.tmode) &&
|
|
|
|
!(dflag || Fflag || lflag)));
|
2015-06-12 13:38:07 -04:00
|
|
|
|
2015-06-12 10:22:46 -04:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
for (i = ds = fs = 0, fents = dents = NULL; i < argc; ++i) {
|
2015-11-01 12:12:25 -05:00
|
|
|
mkent(&ent, argv[i], 1, Hflag || Lflag);
|
2015-11-01 12:23:27 -05:00
|
|
|
|
2015-11-01 12:12:25 -05:00
|
|
|
if ((!dflag && S_ISDIR(ent.mode)) ||
|
2016-05-14 21:56:53 -04:00
|
|
|
(S_ISLNK(ent.mode) && S_ISDIR(ent.tmode) &&
|
|
|
|
!(dflag || Fflag || lflag))) {
|
2015-11-01 12:12:25 -05:00
|
|
|
dents = ereallocarray(dents, ++ds, sizeof(*dents));
|
|
|
|
memcpy(&dents[ds - 1], &ent, sizeof(ent));
|
2015-06-12 10:22:46 -04:00
|
|
|
} else {
|
2015-11-01 12:12:25 -05:00
|
|
|
fents = ereallocarray(fents, ++fs, sizeof(*fents));
|
|
|
|
memcpy(&fents[fs - 1], &ent, sizeof(ent));
|
2015-06-12 10:22:46 -04:00
|
|
|
}
|
|
|
|
}
|
2015-08-31 12:02:10 -04:00
|
|
|
|
2016-05-14 21:56:52 -04:00
|
|
|
showdirs = ds > 1 || (ds && fs);
|
|
|
|
|
2015-11-01 12:23:27 -05:00
|
|
|
qsort(fents, fs, sizeof(ent), entcmp);
|
|
|
|
qsort(dents, ds, sizeof(ent), entcmp);
|
2015-02-16 13:20:06 -05:00
|
|
|
|
2015-06-12 10:22:46 -04:00
|
|
|
for (i = 0; i < fs; ++i)
|
2015-11-01 12:12:25 -05:00
|
|
|
ls("", &fents[i], 0);
|
|
|
|
free(fents);
|
2015-06-12 10:22:46 -04:00
|
|
|
if (fs && ds)
|
|
|
|
putchar('\n');
|
|
|
|
for (i = 0; i < ds; ++i)
|
2015-11-01 12:12:25 -05:00
|
|
|
ls("", &dents[i], 1);
|
|
|
|
free(dents);
|
2015-06-12 10:22:46 -04:00
|
|
|
}
|
2015-02-16 13:20:06 -05:00
|
|
|
|
2016-02-18 06:06:21 -05:00
|
|
|
return (fshut(stdout, "<stdout>") | ret);
|
2015-02-16 13:20:06 -05:00
|
|
|
}
|