sbase/ls.c

293 lines
5.7 KiB
C
Raw Normal View History

2011-05-25 23:01:20 -04:00
/* See LICENSE file for copyright and license details. */
#include <dirent.h>
#include <errno.h>
#include <grp.h>
#include <pwd.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <sys/stat.h>
#include "util.h"
typedef struct {
char *name;
mode_t mode;
nlink_t nlink;
uid_t uid;
gid_t gid;
off_t size;
time_t mtime;
2013-09-27 10:32:50 -04:00
ino_t ino;
2011-05-25 23:01:20 -04:00
} Entry;
2013-07-18 15:14:53 -04:00
static int entcmp(const void *, const void *);
static void ls(Entry *);
2011-05-25 23:01:20 -04:00
static void lsdir(const char *);
2013-07-18 15:14:53 -04:00
static void mkent(Entry *, char *, bool);
2011-05-25 23:01:20 -04:00
static void output(Entry *);
static bool aflag = false;
2011-05-25 23:12:49 -04:00
static bool dflag = false;
2014-02-17 09:41:09 -05:00
static bool Fflag = false;
2013-09-27 10:32:50 -04:00
static bool iflag = false;
2011-05-25 23:01:20 -04:00
static bool lflag = false;
static bool rflag = false;
2011-05-25 23:01:20 -04:00
static bool tflag = false;
2013-07-18 15:14:53 -04:00
static bool Uflag = false;
2011-05-26 00:03:37 -04:00
static bool first = true;
2011-05-25 23:01:20 -04:00
static bool many;
2013-06-14 14:20:47 -04:00
static void
usage(void)
{
2014-02-17 09:41:09 -05:00
eprintf("usage: %s [-adFilrtU] [FILE...]\n", argv0);
2013-06-14 14:20:47 -04:00
}
2011-05-25 23:01:20 -04:00
int
main(int argc, char *argv[])
{
2013-07-18 15:14:53 -04:00
int i;
2011-06-15 20:13:46 -04:00
Entry *ents;
2011-05-25 23:01:20 -04:00
2013-06-14 14:20:47 -04:00
ARGBEGIN {
case 'a':
aflag = true;
break;
case 'd':
dflag = true;
break;
2014-02-17 09:41:09 -05:00
case 'F':
Fflag = true;
break;
2013-09-27 10:32:50 -04:00
case 'i':
iflag = true;
break;
2013-06-14 14:20:47 -04:00
case 'l':
lflag = true;
break;
case 'r':
rflag = true;
break;
2013-06-14 14:20:47 -04:00
case 't':
tflag = true;
break;
2013-07-18 15:14:53 -04:00
case 'U':
Uflag = true;
break;
2013-06-14 14:20:47 -04:00
default:
usage();
} ARGEND;
many = (argc > 1);
2013-07-18 15:14:53 -04:00
if(argc == 0)
*--argv = ".", argc++;
2013-06-14 14:20:47 -04:00
2013-07-18 15:14:53 -04:00
if(!(ents = malloc(argc * sizeof *ents)))
eprintf("malloc:");
for(i = 0; i < argc; i++)
mkent(&ents[i], argv[i], true);
qsort(ents, argc, sizeof *ents, entcmp);
for(i = 0; i < argc; i++)
ls(&ents[rflag ? argc-i-1 : i]);
2013-06-14 14:20:47 -04:00
return EXIT_SUCCESS;
2011-05-25 23:01:20 -04:00
}
static int
2013-07-18 15:14:53 -04:00
entcmp(const void *va, const void *vb)
2011-05-25 23:01:20 -04:00
{
2013-07-18 15:14:53 -04:00
const Entry *a = va, *b = vb;
2011-05-25 23:01:20 -04:00
if(tflag)
return b->mtime - a->mtime;
2011-05-25 23:01:20 -04:00
else
return strcmp(a->name, b->name);
2011-05-25 23:01:20 -04:00
}
static void
2013-07-18 15:14:53 -04:00
ls(Entry *ent)
2011-05-25 23:01:20 -04:00
{
2013-07-18 15:14:53 -04:00
if(S_ISDIR(ent->mode) && !dflag) {
lsdir(ent->name);
} else {
output(ent);
}
2011-05-25 23:01:20 -04:00
}
static void
2011-05-25 23:01:20 -04:00
lsdir(const char *path)
{
2011-05-25 23:17:06 -04:00
char *cwd, *p;
2011-05-25 23:01:20 -04:00
long i, n = 0;
struct dirent *d;
DIR *dp;
2013-07-18 15:14:53 -04:00
Entry ent, *ents = NULL;
size_t sz;
2011-05-25 23:01:20 -04:00
2011-05-25 23:17:06 -04:00
cwd = agetcwd();
2011-05-25 23:01:20 -04:00
if(!(dp = opendir(path)))
eprintf("opendir %s:", path);
2011-06-04 07:20:41 -04:00
if(chdir(path) == -1)
2011-05-25 23:01:20 -04:00
eprintf("chdir %s:", path);
2011-05-26 00:03:37 -04:00
if(many) {
if(!first)
putchar('\n');
2011-05-25 23:01:20 -04:00
printf("%s:\n", path);
2011-05-26 00:03:37 -04:00
first = false;
}
2013-07-18 15:14:53 -04:00
while((d = readdir(dp))) {
if(d->d_name[0] == '.' && !aflag)
continue;
if(Uflag){
2014-02-17 09:41:09 -05:00
mkent(&ent, d->d_name, Fflag || lflag || iflag);
2013-07-18 15:14:53 -04:00
output(&ent);
} else {
if(!(ents = realloc(ents, ++n * sizeof *ents)))
eprintf("realloc:");
if(!(p = malloc((sz = strlen(d->d_name)+1))))
2013-07-18 15:14:53 -04:00
eprintf("malloc:");
memcpy(p, d->d_name, sz);
2014-02-17 09:41:09 -05:00
mkent(&ents[n-1], p, tflag || Fflag || lflag || iflag);
2013-07-18 15:14:53 -04:00
}
}
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);
2013-07-18 15:14:53 -04:00
}
2011-05-25 23:01:20 -04:00
}
2011-06-04 07:20:41 -04:00
if(chdir(cwd) == -1)
2011-05-25 23:17:06 -04:00
eprintf("chdir %s:", cwd);
2011-05-25 23:01:20 -04:00
free(ents);
2011-05-25 23:17:06 -04:00
free(cwd);
2011-05-25 23:01:20 -04:00
}
static void
2013-07-18 15:14:53 -04:00
mkent(Entry *ent, char *path, bool dostat)
2011-05-25 23:01:20 -04:00
{
struct stat st;
2013-07-18 15:14:53 -04:00
ent->name = path;
if(!dostat)
return;
2011-06-04 07:20:41 -04:00
if(lstat(path, &st) == -1)
2011-05-25 23:01:20 -04:00
eprintf("lstat %s:", 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->mtime = st.st_mtime;
2013-09-27 10:32:50 -04:00
ent->ino = st.st_ino;
2011-05-25 23:01:20 -04:00
}
static char *
2014-02-17 09:41:09 -05:00
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
2011-05-25 23:01:20 -04:00
output(Entry *ent)
{
2011-05-27 18:56:43 -04:00
char buf[BUFSIZ], *fmt;
char mode[] = "----------";
2011-06-04 07:40:05 -04:00
ssize_t len;
2011-05-25 23:01:20 -04:00
struct group *gr;
struct passwd *pw;
char pwname[_SC_LOGIN_NAME_MAX];
char grname[_SC_LOGIN_NAME_MAX];
2014-02-17 09:41:09 -05:00
Entry entlnk;
2011-05-25 23:01:20 -04:00
2013-09-27 10:32:50 -04:00
if (iflag)
printf("%lu ", (unsigned long)ent->ino);
2011-05-25 23:01:20 -04:00
if(!lflag) {
2014-02-17 09:41:09 -05:00
printf("%s%s\n", ent->name, indicator(ent->mode));
2011-05-25 23:01:20 -04:00
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] = '?';
2011-05-27 18:56:43 -04: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-28 10:37:42 -04: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
errno = 0;
pw = getpwuid(ent->uid);
if(errno || !pw)
snprintf(pwname, sizeof(pwname), "%d", ent->uid);
else
snprintf(pwname, sizeof(pwname), "%s", pw->pw_name);
2011-05-25 23:01:20 -04:00
errno = 0;
gr = getgrgid(ent->gid);
if(errno || !gr)
snprintf(grname, sizeof(grname), "%d", ent->gid);
else
snprintf(grname, sizeof(grname), "%s", gr->gr_name);
2011-05-25 23:01:20 -04:00
if(time(NULL) > ent->mtime + (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";
strftime(buf, sizeof buf, fmt, localtime(&ent->mtime));
printf("%s %2ld %-4s %-5s %6lu %s %s%s", mode, (long)ent->nlink, pwname,
grname, (unsigned long)ent->size, buf, ent->name, indicator(ent->mode));
2011-06-04 07:40:05 -04:00
if(S_ISLNK(ent->mode)) {
if((len = readlink(ent->name, buf, sizeof buf)) == -1)
eprintf("readlink %s:", ent->name);
buf[len] = '\0';
2014-02-17 09:41:09 -05:00
mkent(&entlnk, buf, Fflag);
printf(" -> %s%s", buf, indicator(entlnk.mode));
2011-06-04 07:40:05 -04:00
}
putchar('\n');
2011-05-25 23:01:20 -04:00
}