13e12c5d1SDavid du Colombier #include <u.h>
23e12c5d1SDavid du Colombier #include <libc.h>
33e12c5d1SDavid du Colombier #include <bio.h>
43e12c5d1SDavid du Colombier #include <fcall.h>
53e12c5d1SDavid du Colombier
63e12c5d1SDavid du Colombier typedef struct NDir NDir;
73e12c5d1SDavid du Colombier struct NDir
83e12c5d1SDavid du Colombier {
99a747e4fSDavid du Colombier Dir *d;
103e12c5d1SDavid du Colombier char *prefix;
113e12c5d1SDavid du Colombier };
123e12c5d1SDavid du Colombier
133e12c5d1SDavid du Colombier int errs = 0;
143e12c5d1SDavid du Colombier int dflag;
153e12c5d1SDavid du Colombier int lflag;
169a747e4fSDavid du Colombier int mflag;
173e12c5d1SDavid du Colombier int nflag;
183e12c5d1SDavid du Colombier int pflag;
193e12c5d1SDavid du Colombier int qflag;
209a747e4fSDavid du Colombier int Qflag;
213e12c5d1SDavid du Colombier int rflag;
223e12c5d1SDavid du Colombier int sflag;
233e12c5d1SDavid du Colombier int tflag;
24e44fe4caSDavid du Colombier int Tflag;
253e12c5d1SDavid du Colombier int uflag;
26219b2ee8SDavid du Colombier int Fflag;
273e12c5d1SDavid du Colombier int ndirbuf;
283e12c5d1SDavid du Colombier int ndir;
293e12c5d1SDavid du Colombier NDir* dirbuf;
303e12c5d1SDavid du Colombier int ls(char*, int);
313e12c5d1SDavid du Colombier int compar(NDir*, NDir*);
323e12c5d1SDavid du Colombier char* asciitime(long);
333e12c5d1SDavid du Colombier char* darwx(long);
343e12c5d1SDavid du Colombier void rwx(long, char*);
353e12c5d1SDavid du Colombier void growto(long);
363e12c5d1SDavid du Colombier void dowidths(Dir*);
373e12c5d1SDavid du Colombier void format(Dir*, char*);
383e12c5d1SDavid du Colombier void output(void);
39b4ed3b92SDavid du Colombier char* xcleanname(char*);
403e12c5d1SDavid du Colombier ulong clk;
417dd7cddfSDavid du Colombier int swidth; /* max width of -s size */
427dd7cddfSDavid du Colombier int qwidth; /* max width of -q version */
437dd7cddfSDavid du Colombier int vwidth; /* max width of dev */
447dd7cddfSDavid du Colombier int uwidth; /* max width of userid */
459a747e4fSDavid du Colombier int mwidth; /* max width of muid */
46*07c32395SDavid du Colombier int lwidth; /* max width of length */
47*07c32395SDavid du Colombier int gwidth; /* max width of groupid */
483e12c5d1SDavid du Colombier Biobuf bin;
493e12c5d1SDavid du Colombier
503e12c5d1SDavid du Colombier void
main(int argc,char * argv[])513e12c5d1SDavid du Colombier main(int argc, char *argv[])
523e12c5d1SDavid du Colombier {
536b6b9ac8SDavid du Colombier int i;
543e12c5d1SDavid du Colombier
553e12c5d1SDavid du Colombier Binit(&bin, 1, OWRITE);
563e12c5d1SDavid du Colombier ARGBEGIN{
57219b2ee8SDavid du Colombier case 'F': Fflag++; break;
583e12c5d1SDavid du Colombier case 'd': dflag++; break;
593e12c5d1SDavid du Colombier case 'l': lflag++; break;
609a747e4fSDavid du Colombier case 'm': mflag++; break;
613e12c5d1SDavid du Colombier case 'n': nflag++; break;
623e12c5d1SDavid du Colombier case 'p': pflag++; break;
633e12c5d1SDavid du Colombier case 'q': qflag++; break;
649a747e4fSDavid du Colombier case 'Q': Qflag++; break;
653e12c5d1SDavid du Colombier case 'r': rflag++; break;
663e12c5d1SDavid du Colombier case 's': sflag++; break;
673e12c5d1SDavid du Colombier case 't': tflag++; break;
68e44fe4caSDavid du Colombier case 'T': Tflag++; break;
693e12c5d1SDavid du Colombier case 'u': uflag++; break;
70e44fe4caSDavid du Colombier default: fprint(2, "usage: ls [-dlmnpqrstuFQT] [file ...]\n");
713e12c5d1SDavid du Colombier exits("usage");
723e12c5d1SDavid du Colombier }ARGEND
733e12c5d1SDavid du Colombier
74d9306527SDavid du Colombier doquote = needsrcquote;
759a747e4fSDavid du Colombier quotefmtinstall();
769a747e4fSDavid du Colombier fmtinstall('M', dirmodefmt);
773e12c5d1SDavid du Colombier
786b6b9ac8SDavid du Colombier if(lflag)
796b6b9ac8SDavid du Colombier clk = time(0);
803e12c5d1SDavid du Colombier if(argc == 0)
813e12c5d1SDavid du Colombier errs = ls(".", 0);
823e12c5d1SDavid du Colombier else for(i=0; i<argc; i++)
833e12c5d1SDavid du Colombier errs |= ls(argv[i], 1);
843e12c5d1SDavid du Colombier output();
853e12c5d1SDavid du Colombier exits(errs? "errors" : 0);
863e12c5d1SDavid du Colombier }
873e12c5d1SDavid du Colombier
883e12c5d1SDavid du Colombier int
ls(char * s,int multi)893e12c5d1SDavid du Colombier ls(char *s, int multi)
903e12c5d1SDavid du Colombier {
913e12c5d1SDavid du Colombier int fd;
923e12c5d1SDavid du Colombier long i, n;
933e12c5d1SDavid du Colombier char *p;
949a747e4fSDavid du Colombier Dir *db;
953e12c5d1SDavid du Colombier
969a747e4fSDavid du Colombier db = dirstat(s);
979a747e4fSDavid du Colombier if(db == nil){
983e12c5d1SDavid du Colombier error:
99219b2ee8SDavid du Colombier fprint(2, "ls: %s: %r\n", s);
1003e12c5d1SDavid du Colombier return 1;
1013e12c5d1SDavid du Colombier }
102dc5a79c1SDavid du Colombier if((db->qid.type&QTDIR) && dflag==0){
10364df97a2SDavid du Colombier free(db);
1043e12c5d1SDavid du Colombier output();
1053e12c5d1SDavid du Colombier fd = open(s, OREAD);
1063e12c5d1SDavid du Colombier if(fd == -1)
1073e12c5d1SDavid du Colombier goto error;
1089a747e4fSDavid du Colombier n = dirreadall(fd, &db);
1099a747e4fSDavid du Colombier if(n < 0)
1109a747e4fSDavid du Colombier goto error;
111b4ed3b92SDavid du Colombier xcleanname(s);
1123e12c5d1SDavid du Colombier growto(ndir+n);
1133e12c5d1SDavid du Colombier for(i=0; i<n; i++){
1149a747e4fSDavid du Colombier dirbuf[ndir+i].d = db+i;
1153e12c5d1SDavid du Colombier dirbuf[ndir+i].prefix = multi? s : 0;
1163e12c5d1SDavid du Colombier }
1173e12c5d1SDavid du Colombier ndir += n;
1183e12c5d1SDavid du Colombier close(fd);
1193e12c5d1SDavid du Colombier output();
1203e12c5d1SDavid du Colombier }else{
1213e12c5d1SDavid du Colombier growto(ndir+1);
1229a747e4fSDavid du Colombier dirbuf[ndir].d = db;
1233e12c5d1SDavid du Colombier dirbuf[ndir].prefix = 0;
124b4ed3b92SDavid du Colombier xcleanname(s);
1253e12c5d1SDavid du Colombier p = utfrrune(s, '/');
1263e12c5d1SDavid du Colombier if(p){
1273e12c5d1SDavid du Colombier dirbuf[ndir].prefix = s;
1283e12c5d1SDavid du Colombier *p = 0;
1293e12c5d1SDavid du Colombier }
1303e12c5d1SDavid du Colombier ndir++;
1313e12c5d1SDavid du Colombier }
1323e12c5d1SDavid du Colombier return 0;
1333e12c5d1SDavid du Colombier }
1343e12c5d1SDavid du Colombier
1353e12c5d1SDavid du Colombier void
output(void)1363e12c5d1SDavid du Colombier output(void)
1373e12c5d1SDavid du Colombier {
1383e12c5d1SDavid du Colombier int i;
1393e12c5d1SDavid du Colombier char buf[4096];
1403e12c5d1SDavid du Colombier char *s;
1413e12c5d1SDavid du Colombier
1423e12c5d1SDavid du Colombier if(!nflag)
1433e12c5d1SDavid du Colombier qsort(dirbuf, ndir, sizeof dirbuf[0], (int (*)(void*, void*))compar);
1443e12c5d1SDavid du Colombier for(i=0; i<ndir; i++)
1459a747e4fSDavid du Colombier dowidths(dirbuf[i].d);
1463e12c5d1SDavid du Colombier for(i=0; i<ndir; i++) {
1473e12c5d1SDavid du Colombier if(!pflag && (s = dirbuf[i].prefix)) {
1483e12c5d1SDavid du Colombier if(strcmp(s, "/") ==0) /* / is a special case */
1493e12c5d1SDavid du Colombier s = "";
1509a747e4fSDavid du Colombier sprint(buf, "%s/%s", s, dirbuf[i].d->name);
1519a747e4fSDavid du Colombier format(dirbuf[i].d, buf);
1523e12c5d1SDavid du Colombier } else
1539a747e4fSDavid du Colombier format(dirbuf[i].d, dirbuf[i].d->name);
1543e12c5d1SDavid du Colombier }
1553e12c5d1SDavid du Colombier ndir = 0;
1563e12c5d1SDavid du Colombier Bflush(&bin);
1573e12c5d1SDavid du Colombier }
1583e12c5d1SDavid du Colombier
1593e12c5d1SDavid du Colombier void
dowidths(Dir * db)1603e12c5d1SDavid du Colombier dowidths(Dir *db)
1613e12c5d1SDavid du Colombier {
1629a747e4fSDavid du Colombier char buf[256];
1633e12c5d1SDavid du Colombier int n;
1643e12c5d1SDavid du Colombier
1653e12c5d1SDavid du Colombier if(sflag) {
1667dd7cddfSDavid du Colombier n = sprint(buf, "%llud", (db->length+1023)/1024);
1673e12c5d1SDavid du Colombier if(n > swidth)
1683e12c5d1SDavid du Colombier swidth = n;
1693e12c5d1SDavid du Colombier }
1703e12c5d1SDavid du Colombier if(qflag) {
1717dd7cddfSDavid du Colombier n = sprint(buf, "%lud", db->qid.vers);
1723e12c5d1SDavid du Colombier if(n > qwidth)
1733e12c5d1SDavid du Colombier qwidth = n;
1743e12c5d1SDavid du Colombier }
1759a747e4fSDavid du Colombier if(mflag) {
176*07c32395SDavid du Colombier n = snprint(buf, sizeof buf, "[%q]", db->muid);
1779a747e4fSDavid du Colombier if(n > mwidth)
1789a747e4fSDavid du Colombier mwidth = n;
1799a747e4fSDavid du Colombier }
1803e12c5d1SDavid du Colombier if(lflag) {
1817dd7cddfSDavid du Colombier n = sprint(buf, "%ud", db->dev);
1823e12c5d1SDavid du Colombier if(n > vwidth)
1833e12c5d1SDavid du Colombier vwidth = n;
184*07c32395SDavid du Colombier n = sprint(buf, "%q", db->uid);
1853e12c5d1SDavid du Colombier if(n > uwidth)
1863e12c5d1SDavid du Colombier uwidth = n;
187*07c32395SDavid du Colombier n = sprint(buf, "%q", db->gid);
188*07c32395SDavid du Colombier if(n > gwidth)
189*07c32395SDavid du Colombier gwidth = n;
1907dd7cddfSDavid du Colombier n = sprint(buf, "%llud", db->length);
191*07c32395SDavid du Colombier if(n > lwidth)
192*07c32395SDavid du Colombier lwidth = n;
1933e12c5d1SDavid du Colombier }
1943e12c5d1SDavid du Colombier }
1953e12c5d1SDavid du Colombier
196219b2ee8SDavid du Colombier char*
fileflag(Dir * db)197219b2ee8SDavid du Colombier fileflag(Dir *db)
198219b2ee8SDavid du Colombier {
199219b2ee8SDavid du Colombier if(Fflag == 0)
200219b2ee8SDavid du Colombier return "";
2019a747e4fSDavid du Colombier if(QTDIR & db->qid.type)
202219b2ee8SDavid du Colombier return "/";
203219b2ee8SDavid du Colombier if(0111 & db->mode)
204219b2ee8SDavid du Colombier return "*";
205219b2ee8SDavid du Colombier return "";
206219b2ee8SDavid du Colombier }
207219b2ee8SDavid du Colombier
2083e12c5d1SDavid du Colombier void
format(Dir * db,char * name)2093e12c5d1SDavid du Colombier format(Dir *db, char *name)
2103e12c5d1SDavid du Colombier {
2119a747e4fSDavid du Colombier int i;
2129a747e4fSDavid du Colombier
2133e12c5d1SDavid du Colombier if(sflag)
2147dd7cddfSDavid du Colombier Bprint(&bin, "%*llud ",
2153e12c5d1SDavid du Colombier swidth, (db->length+1023)/1024);
2169a747e4fSDavid du Colombier if(mflag){
217*07c32395SDavid du Colombier Bprint(&bin, "[%q] ", db->muid);
2189a747e4fSDavid du Colombier for(i=2+strlen(db->muid); i<mwidth; i++)
2199a747e4fSDavid du Colombier Bprint(&bin, " ");
2209a747e4fSDavid du Colombier }
2213e12c5d1SDavid du Colombier if(qflag)
2229a747e4fSDavid du Colombier Bprint(&bin, "(%.16llux %*lud %.2ux) ",
2233e12c5d1SDavid du Colombier db->qid.path,
2249a747e4fSDavid du Colombier qwidth, db->qid.vers,
2259a747e4fSDavid du Colombier db->qid.type);
226e44fe4caSDavid du Colombier if(Tflag)
227e44fe4caSDavid du Colombier Bprint(&bin, "%c ", (db->mode&DMTMP)? 't': '-');
228e44fe4caSDavid du Colombier
2293e12c5d1SDavid du Colombier if(lflag)
230*07c32395SDavid du Colombier Bprint(&bin, "%M %C %*ud %*q %*q %*llud %s ",
2313e12c5d1SDavid du Colombier db->mode, db->type,
2323e12c5d1SDavid du Colombier vwidth, db->dev,
2333e12c5d1SDavid du Colombier -uwidth, db->uid,
234*07c32395SDavid du Colombier -gwidth, db->gid,
235*07c32395SDavid du Colombier lwidth, db->length,
2364d61b946SDavid du Colombier asciitime(uflag? db->atime: db->mtime));
2374d61b946SDavid du Colombier Bprint(&bin, Qflag? "%s%s\n": "%q%s\n", name, fileflag(db));
2383e12c5d1SDavid du Colombier }
2393e12c5d1SDavid du Colombier
2403e12c5d1SDavid du Colombier void
growto(long n)2413e12c5d1SDavid du Colombier growto(long n)
2423e12c5d1SDavid du Colombier {
2433e12c5d1SDavid du Colombier if(n <= ndirbuf)
2443e12c5d1SDavid du Colombier return;
2453e12c5d1SDavid du Colombier ndirbuf = n;
2463e12c5d1SDavid du Colombier dirbuf=(NDir *)realloc(dirbuf, ndirbuf*sizeof(NDir));
2473e12c5d1SDavid du Colombier if(dirbuf == 0){
2483e12c5d1SDavid du Colombier fprint(2, "ls: malloc fail\n");
2493e12c5d1SDavid du Colombier exits("malloc fail");
2503e12c5d1SDavid du Colombier }
2513e12c5d1SDavid du Colombier }
2523e12c5d1SDavid du Colombier
2533e12c5d1SDavid du Colombier int
compar(NDir * a,NDir * b)2543e12c5d1SDavid du Colombier compar(NDir *a, NDir *b)
2553e12c5d1SDavid du Colombier {
2563e12c5d1SDavid du Colombier long i;
2579a747e4fSDavid du Colombier Dir *ad, *bd;
2589a747e4fSDavid du Colombier
2599a747e4fSDavid du Colombier ad = a->d;
2609a747e4fSDavid du Colombier bd = b->d;
2613e12c5d1SDavid du Colombier
2623e12c5d1SDavid du Colombier if(tflag){
2633e12c5d1SDavid du Colombier if(uflag)
2649a747e4fSDavid du Colombier i = bd->atime-ad->atime;
2653e12c5d1SDavid du Colombier else
2669a747e4fSDavid du Colombier i = bd->mtime-ad->mtime;
2673e12c5d1SDavid du Colombier }else{
2683e12c5d1SDavid du Colombier if(a->prefix && b->prefix){
2693e12c5d1SDavid du Colombier i = strcmp(a->prefix, b->prefix);
2703e12c5d1SDavid du Colombier if(i == 0)
2719a747e4fSDavid du Colombier i = strcmp(ad->name, bd->name);
2723e12c5d1SDavid du Colombier }else if(a->prefix){
2739a747e4fSDavid du Colombier i = strcmp(a->prefix, bd->name);
2743e12c5d1SDavid du Colombier if(i == 0)
2753e12c5d1SDavid du Colombier i = 1; /* a is longer than b */
2763e12c5d1SDavid du Colombier }else if(b->prefix){
2779a747e4fSDavid du Colombier i = strcmp(ad->name, b->prefix);
2783e12c5d1SDavid du Colombier if(i == 0)
2793e12c5d1SDavid du Colombier i = -1; /* b is longer than a */
2803e12c5d1SDavid du Colombier }else
2819a747e4fSDavid du Colombier i = strcmp(ad->name, bd->name);
2823e12c5d1SDavid du Colombier }
2833e12c5d1SDavid du Colombier if(i == 0)
2843e12c5d1SDavid du Colombier i = (a<b? -1 : 1);
2853e12c5d1SDavid du Colombier if(rflag)
286219b2ee8SDavid du Colombier i = -i;
2873e12c5d1SDavid du Colombier return i;
2883e12c5d1SDavid du Colombier }
2893e12c5d1SDavid du Colombier
2903e12c5d1SDavid du Colombier char*
asciitime(long l)2913e12c5d1SDavid du Colombier asciitime(long l)
2923e12c5d1SDavid du Colombier {
2933e12c5d1SDavid du Colombier static char buf[32];
2943e12c5d1SDavid du Colombier char *t;
2953e12c5d1SDavid du Colombier
2963e12c5d1SDavid du Colombier t = ctime(l);
2973e12c5d1SDavid du Colombier /* 6 months in the past or a day in the future */
2983e12c5d1SDavid du Colombier if(l<clk-180L*24*60*60 || clk+24L*60*60<l){
2993e12c5d1SDavid du Colombier memmove(buf, t+4, 7); /* month and day */
3003e12c5d1SDavid du Colombier memmove(buf+7, t+23, 5); /* year */
3013e12c5d1SDavid du Colombier }else
3023e12c5d1SDavid du Colombier memmove(buf, t+4, 12); /* skip day of week */
3033e12c5d1SDavid du Colombier buf[12] = 0;
3043e12c5d1SDavid du Colombier return buf;
3053e12c5d1SDavid du Colombier }
3069a747e4fSDavid du Colombier
307b4ed3b92SDavid du Colombier /*
308b4ed3b92SDavid du Colombier * Compress slashes, remove trailing slash. Don't worry about . and ..
309b4ed3b92SDavid du Colombier */
310b4ed3b92SDavid du Colombier char*
xcleanname(char * name)311b4ed3b92SDavid du Colombier xcleanname(char *name)
312b4ed3b92SDavid du Colombier {
313b4ed3b92SDavid du Colombier char *r, *w;
314b4ed3b92SDavid du Colombier
315b4ed3b92SDavid du Colombier for(r=w=name; *r; r++){
316b4ed3b92SDavid du Colombier if(*r=='/' && r>name && *(r-1)=='/')
317b4ed3b92SDavid du Colombier continue;
318*07c32395SDavid du Colombier if(w != r)
319*07c32395SDavid du Colombier *w = *r;
320*07c32395SDavid du Colombier w++;
321b4ed3b92SDavid du Colombier }
322d6ef7babSDavid du Colombier *w = 0;
323b4ed3b92SDavid du Colombier while(w-1>name && *(w-1)=='/')
324b4ed3b92SDavid du Colombier *--w = 0;
325b4ed3b92SDavid du Colombier return name;
326b4ed3b92SDavid du Colombier }
327