13e12c5d1SDavid du Colombier #include <u.h> 23e12c5d1SDavid du Colombier #include <libc.h> 33e12c5d1SDavid du Colombier #include <bio.h> 4*219b2ee8SDavid du Colombier #include <auth.h> 53e12c5d1SDavid du Colombier #include <fcall.h> 63e12c5d1SDavid du Colombier 73e12c5d1SDavid du Colombier typedef struct NDir NDir; 83e12c5d1SDavid du Colombier struct NDir 93e12c5d1SDavid du Colombier { 103e12c5d1SDavid du Colombier Dir; 113e12c5d1SDavid du Colombier char *prefix; 123e12c5d1SDavid du Colombier }; 133e12c5d1SDavid du Colombier 143e12c5d1SDavid du Colombier int errs = 0; 153e12c5d1SDavid du Colombier int dflag; 163e12c5d1SDavid du Colombier int lflag; 173e12c5d1SDavid du Colombier int nflag; 183e12c5d1SDavid du Colombier int pflag; 193e12c5d1SDavid du Colombier int qflag; 203e12c5d1SDavid du Colombier int rflag; 213e12c5d1SDavid du Colombier int sflag; 223e12c5d1SDavid du Colombier int tflag; 233e12c5d1SDavid du Colombier int uflag; 24*219b2ee8SDavid du Colombier int Fflag; 253e12c5d1SDavid du Colombier int ndirbuf; 263e12c5d1SDavid du Colombier int ndir; 273e12c5d1SDavid du Colombier NDir* dirbuf; 283e12c5d1SDavid du Colombier int ls(char*, int); 293e12c5d1SDavid du Colombier int compar(NDir*, NDir*); 303e12c5d1SDavid du Colombier char* asciitime(long); 313e12c5d1SDavid du Colombier char* darwx(long); 323e12c5d1SDavid du Colombier void rwx(long, char*); 333e12c5d1SDavid du Colombier void growto(long); 343e12c5d1SDavid du Colombier void dowidths(Dir*); 353e12c5d1SDavid du Colombier void format(Dir*, char*); 363e12c5d1SDavid du Colombier void output(void); 373e12c5d1SDavid du Colombier ulong clk; 383e12c5d1SDavid du Colombier int swidth; 393e12c5d1SDavid du Colombier int qwidth; 403e12c5d1SDavid du Colombier int vwidth; 413e12c5d1SDavid du Colombier int uwidth; 423e12c5d1SDavid du Colombier int glwidth; 433e12c5d1SDavid du Colombier Biobuf bin; 443e12c5d1SDavid du Colombier 453e12c5d1SDavid du Colombier #define HUNK 50 463e12c5d1SDavid du Colombier 473e12c5d1SDavid du Colombier void 483e12c5d1SDavid du Colombier main(int argc, char *argv[]) 493e12c5d1SDavid du Colombier { 503e12c5d1SDavid du Colombier int i, fd; 513e12c5d1SDavid du Colombier char buf[64]; 523e12c5d1SDavid du Colombier 533e12c5d1SDavid du Colombier Binit(&bin, 1, OWRITE); 543e12c5d1SDavid du Colombier ARGBEGIN{ 55*219b2ee8SDavid du Colombier case 'F': Fflag++; break; 563e12c5d1SDavid du Colombier case 'd': dflag++; break; 573e12c5d1SDavid du Colombier case 'l': lflag++; break; 583e12c5d1SDavid du Colombier case 'n': nflag++; break; 593e12c5d1SDavid du Colombier case 'p': pflag++; break; 603e12c5d1SDavid du Colombier case 'q': qflag++; break; 613e12c5d1SDavid du Colombier case 'r': rflag++; break; 623e12c5d1SDavid du Colombier case 's': sflag++; break; 633e12c5d1SDavid du Colombier case 't': tflag++; break; 643e12c5d1SDavid du Colombier case 'u': uflag++; break; 65*219b2ee8SDavid du Colombier default: fprint(2, "usage: ls [-dlnpqrstuF] [file ...]\n"); 663e12c5d1SDavid du Colombier exits("usage"); 673e12c5d1SDavid du Colombier }ARGEND 683e12c5d1SDavid du Colombier 693e12c5d1SDavid du Colombier fmtinstall('M', dirmodeconv); 703e12c5d1SDavid du Colombier 713e12c5d1SDavid du Colombier if(lflag){ 723e12c5d1SDavid du Colombier fd = open("/dev/time", OREAD); 733e12c5d1SDavid du Colombier if(fd<0 || read(fd, buf, sizeof buf-1)<=0) 743e12c5d1SDavid du Colombier fprint(2, "ls: can't open /dev/time\n"); 753e12c5d1SDavid du Colombier close(fd); 763e12c5d1SDavid du Colombier clk = strtoul(buf, 0, 0); 773e12c5d1SDavid du Colombier } 783e12c5d1SDavid du Colombier if(argc == 0) 793e12c5d1SDavid du Colombier errs = ls(".", 0); 803e12c5d1SDavid du Colombier else for(i=0; i<argc; i++) 813e12c5d1SDavid du Colombier errs |= ls(argv[i], 1); 823e12c5d1SDavid du Colombier output(); 833e12c5d1SDavid du Colombier exits(errs? "errors" : 0); 843e12c5d1SDavid du Colombier } 853e12c5d1SDavid du Colombier 863e12c5d1SDavid du Colombier int 873e12c5d1SDavid du Colombier ls(char *s, int multi) 883e12c5d1SDavid du Colombier { 893e12c5d1SDavid du Colombier int fd; 903e12c5d1SDavid du Colombier long i, n; 913e12c5d1SDavid du Colombier char *p; 923e12c5d1SDavid du Colombier Dir db[HUNK]; 933e12c5d1SDavid du Colombier 943e12c5d1SDavid du Colombier for(;;) { 953e12c5d1SDavid du Colombier p = utfrrune(s, '/'); 963e12c5d1SDavid du Colombier if(p == 0 || p[1] != 0 || p == s) 973e12c5d1SDavid du Colombier break; 983e12c5d1SDavid du Colombier *p = 0; 993e12c5d1SDavid du Colombier } 1003e12c5d1SDavid du Colombier if(dirstat(s, db)==-1){ 1013e12c5d1SDavid du Colombier error: 102*219b2ee8SDavid du Colombier fprint(2, "ls: %s: %r\n", s); 1033e12c5d1SDavid du Colombier return 1; 1043e12c5d1SDavid du Colombier } 1053e12c5d1SDavid du Colombier if(db[0].qid.path&CHDIR && dflag==0){ 1063e12c5d1SDavid du Colombier output(); 1073e12c5d1SDavid du Colombier fd = open(s, OREAD); 1083e12c5d1SDavid du Colombier if(fd == -1) 1093e12c5d1SDavid du Colombier goto error; 1103e12c5d1SDavid du Colombier while((n=dirread(fd, db, sizeof db)) > 0){ 1113e12c5d1SDavid du Colombier n /= sizeof(Dir); 1123e12c5d1SDavid du Colombier growto(ndir+n); 1133e12c5d1SDavid du Colombier for(i=0; i<n; i++){ 1143e12c5d1SDavid du Colombier memmove(dirbuf+ndir+i, db+i, sizeof(Dir)); 1153e12c5d1SDavid du Colombier dirbuf[ndir+i].prefix = multi? s : 0; 1163e12c5d1SDavid du Colombier } 1173e12c5d1SDavid du Colombier ndir += n; 1183e12c5d1SDavid du Colombier } 1193e12c5d1SDavid du Colombier close(fd); 1203e12c5d1SDavid du Colombier output(); 1213e12c5d1SDavid du Colombier }else{ 1223e12c5d1SDavid du Colombier growto(ndir+1); 1233e12c5d1SDavid du Colombier memmove(dirbuf+ndir, db, sizeof(Dir)); 1243e12c5d1SDavid du Colombier dirbuf[ndir].prefix = 0; 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 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 swidth = 0; /* max width of -s size */ 1453e12c5d1SDavid du Colombier qwidth = 0; /* max width of -q version */ 1463e12c5d1SDavid du Colombier vwidth = 0; /* max width of dev */ 1473e12c5d1SDavid du Colombier uwidth = 0; /* max width of userid */ 1483e12c5d1SDavid du Colombier glwidth = 0; /* max width of groupid and length */ 1493e12c5d1SDavid du Colombier for(i=0; i<ndir; i++) 1503e12c5d1SDavid du Colombier dowidths(&dirbuf[i]); 1513e12c5d1SDavid du Colombier for(i=0; i<ndir; i++) { 1523e12c5d1SDavid du Colombier if(!pflag && (s = dirbuf[i].prefix)) { 1533e12c5d1SDavid du Colombier if(strcmp(s, "/") ==0) /* / is a special case */ 1543e12c5d1SDavid du Colombier s = ""; 1553e12c5d1SDavid du Colombier sprint(buf, "%s/%s", s, dirbuf[i].name); 1563e12c5d1SDavid du Colombier format(&dirbuf[i], buf); 1573e12c5d1SDavid du Colombier } else 1583e12c5d1SDavid du Colombier format(&dirbuf[i], dirbuf[i].name); 1593e12c5d1SDavid du Colombier } 1603e12c5d1SDavid du Colombier ndir = 0; 1613e12c5d1SDavid du Colombier Bflush(&bin); 1623e12c5d1SDavid du Colombier } 1633e12c5d1SDavid du Colombier 1643e12c5d1SDavid du Colombier void 1653e12c5d1SDavid du Colombier dowidths(Dir *db) 1663e12c5d1SDavid du Colombier { 1673e12c5d1SDavid du Colombier char buf[100]; 1683e12c5d1SDavid du Colombier int n; 1693e12c5d1SDavid du Colombier 1703e12c5d1SDavid du Colombier if(sflag) { 1713e12c5d1SDavid du Colombier sprint(buf, "%ld", (db->length+1023)/1024); 1723e12c5d1SDavid du Colombier n = strlen(buf); 1733e12c5d1SDavid du Colombier if(n > swidth) 1743e12c5d1SDavid du Colombier swidth = n; 1753e12c5d1SDavid du Colombier } 1763e12c5d1SDavid du Colombier if(qflag) { 1773e12c5d1SDavid du Colombier sprint(buf, "%ld", db->qid.vers); 1783e12c5d1SDavid du Colombier n = strlen(buf); 1793e12c5d1SDavid du Colombier if(n > qwidth) 1803e12c5d1SDavid du Colombier qwidth = n; 1813e12c5d1SDavid du Colombier } 1823e12c5d1SDavid du Colombier if(lflag) { 1833e12c5d1SDavid du Colombier sprint(buf, "%d", db->dev); 1843e12c5d1SDavid du Colombier n = strlen(buf); 1853e12c5d1SDavid du Colombier if(n > vwidth) 1863e12c5d1SDavid du Colombier vwidth = n; 1873e12c5d1SDavid du Colombier n = strlen(db->uid); 1883e12c5d1SDavid du Colombier if(n > uwidth) 1893e12c5d1SDavid du Colombier uwidth = n; 1903e12c5d1SDavid du Colombier sprint(buf, "%ld", db->length); 1913e12c5d1SDavid du Colombier n = strlen(buf) + strlen(db->gid); 1923e12c5d1SDavid du Colombier if(n > glwidth) 1933e12c5d1SDavid du Colombier glwidth = n; 1943e12c5d1SDavid du Colombier } 1953e12c5d1SDavid du Colombier } 1963e12c5d1SDavid du Colombier 197*219b2ee8SDavid du Colombier char* 198*219b2ee8SDavid du Colombier fileflag(Dir *db) 199*219b2ee8SDavid du Colombier { 200*219b2ee8SDavid du Colombier if(Fflag == 0) 201*219b2ee8SDavid du Colombier return ""; 202*219b2ee8SDavid du Colombier if(CHDIR & db->qid.path) 203*219b2ee8SDavid du Colombier return "/"; 204*219b2ee8SDavid du Colombier if(0111 & db->mode) 205*219b2ee8SDavid du Colombier return "*"; 206*219b2ee8SDavid du Colombier return ""; 207*219b2ee8SDavid du Colombier } 208*219b2ee8SDavid du Colombier 2093e12c5d1SDavid du Colombier void 2103e12c5d1SDavid du Colombier format(Dir *db, char *name) 2113e12c5d1SDavid du Colombier { 2123e12c5d1SDavid du Colombier if(sflag) 2133e12c5d1SDavid du Colombier Bprint(&bin, "%*ld ", 2143e12c5d1SDavid du Colombier swidth, (db->length+1023)/1024); 2153e12c5d1SDavid du Colombier if(qflag) 2163e12c5d1SDavid du Colombier Bprint(&bin, "%.8lux %*lud ", 2173e12c5d1SDavid du Colombier db->qid.path, 2183e12c5d1SDavid du Colombier qwidth, db->qid.vers); 2193e12c5d1SDavid du Colombier if(lflag) 220*219b2ee8SDavid du Colombier Bprint(&bin, "%M %C %*d %*s %s %*ld %s %s\n", 2213e12c5d1SDavid du Colombier db->mode, db->type, 2223e12c5d1SDavid du Colombier vwidth, db->dev, 2233e12c5d1SDavid du Colombier -uwidth, db->uid, 2243e12c5d1SDavid du Colombier db->gid, 2253e12c5d1SDavid du Colombier glwidth-strlen(db->gid), db->length, 2263e12c5d1SDavid du Colombier asciitime(uflag? db->atime : db->mtime), name); 2273e12c5d1SDavid du Colombier else 228*219b2ee8SDavid du Colombier Bprint(&bin, "%s%s\n", name, fileflag(db)); 2293e12c5d1SDavid du Colombier } 2303e12c5d1SDavid du Colombier 2313e12c5d1SDavid du Colombier void 2323e12c5d1SDavid du Colombier growto(long n) 2333e12c5d1SDavid du Colombier { 2343e12c5d1SDavid du Colombier if(n <= ndirbuf) 2353e12c5d1SDavid du Colombier return; 2363e12c5d1SDavid du Colombier ndirbuf = n; 2373e12c5d1SDavid du Colombier dirbuf=(NDir *)realloc(dirbuf, ndirbuf*sizeof(NDir)); 2383e12c5d1SDavid du Colombier if(dirbuf == 0){ 2393e12c5d1SDavid du Colombier fprint(2, "ls: malloc fail\n"); 2403e12c5d1SDavid du Colombier exits("malloc fail"); 2413e12c5d1SDavid du Colombier } 2423e12c5d1SDavid du Colombier } 2433e12c5d1SDavid du Colombier 2443e12c5d1SDavid du Colombier int 2453e12c5d1SDavid du Colombier compar(NDir *a, NDir *b) 2463e12c5d1SDavid du Colombier { 2473e12c5d1SDavid du Colombier long i; 2483e12c5d1SDavid du Colombier 2493e12c5d1SDavid du Colombier if(tflag){ 2503e12c5d1SDavid du Colombier if(uflag) 2513e12c5d1SDavid du Colombier i = b->atime-a->atime; 2523e12c5d1SDavid du Colombier else 2533e12c5d1SDavid du Colombier i = b->mtime-a->mtime; 2543e12c5d1SDavid du Colombier }else{ 2553e12c5d1SDavid du Colombier if(a->prefix && b->prefix){ 2563e12c5d1SDavid du Colombier i = strcmp(a->prefix, b->prefix); 2573e12c5d1SDavid du Colombier if(i == 0) 2583e12c5d1SDavid du Colombier i = strcmp(a->name, b->name); 2593e12c5d1SDavid du Colombier }else if(a->prefix){ 2603e12c5d1SDavid du Colombier i = strcmp(a->prefix, b->name); 2613e12c5d1SDavid du Colombier if(i == 0) 2623e12c5d1SDavid du Colombier i = 1; /* a is longer than b */ 2633e12c5d1SDavid du Colombier }else if(b->prefix){ 2643e12c5d1SDavid du Colombier i = strcmp(a->name, b->prefix); 2653e12c5d1SDavid du Colombier if(i == 0) 2663e12c5d1SDavid du Colombier i = -1; /* b is longer than a */ 2673e12c5d1SDavid du Colombier }else 2683e12c5d1SDavid du Colombier i = strcmp(a->name, b->name); 2693e12c5d1SDavid du Colombier } 2703e12c5d1SDavid du Colombier if(i == 0) 2713e12c5d1SDavid du Colombier i = (a<b? -1 : 1); 2723e12c5d1SDavid du Colombier if(rflag) 273*219b2ee8SDavid du Colombier i = -i; 2743e12c5d1SDavid du Colombier return i; 2753e12c5d1SDavid du Colombier } 2763e12c5d1SDavid du Colombier 2773e12c5d1SDavid du Colombier char* 2783e12c5d1SDavid du Colombier asciitime(long l) 2793e12c5d1SDavid du Colombier { 2803e12c5d1SDavid du Colombier static char buf[32]; 2813e12c5d1SDavid du Colombier char *t; 2823e12c5d1SDavid du Colombier 2833e12c5d1SDavid du Colombier t = ctime(l); 2843e12c5d1SDavid du Colombier /* 6 months in the past or a day in the future */ 2853e12c5d1SDavid du Colombier if(l<clk-180L*24*60*60 || clk+24L*60*60<l){ 2863e12c5d1SDavid du Colombier memmove(buf, t+4, 7); /* month and day */ 2873e12c5d1SDavid du Colombier memmove(buf+7, t+23, 5); /* year */ 2883e12c5d1SDavid du Colombier }else 2893e12c5d1SDavid du Colombier memmove(buf, t+4, 12); /* skip day of week */ 2903e12c5d1SDavid du Colombier buf[12] = 0; 2913e12c5d1SDavid du Colombier return buf; 2923e12c5d1SDavid du Colombier } 293