|
|
1.1 ! root 1: #define UCB /* Controls output format for -F */ ! 2: /* #define UCB_PWHASH /* If have hashed password file */ ! 3: ! 4: /* ! 5: * ls - list file or directory ! 6: * ! 7: * Modified by Bill Joy UCB May/August 1977 ! 8: * Modified by Dave Presotto BTL Feb/80 ! 9: * Modified by Bill Joy and Mark Horton Summer 1980 ! 10: * ! 11: * this version of ls is designed for graphic terminals and to ! 12: * list directories with lots of files in them compactly. ! 13: * It supports three variants for listings: ! 14: * ! 15: * 1) Columnar output. ! 16: * 2) Stream output. ! 17: * 3) Old one per line format. ! 18: * ! 19: * Columnar output is the default. ! 20: * If, however, the standard output is not a teletype, the default ! 21: * is one-per-line. ! 22: * ! 23: * With columnar output, the items are sorted down the columns. ! 24: * We use columns only for a directory we are interpreting. ! 25: * Thus, in particular, we do not use columns for ! 26: * ! 27: * ls /usr/bin/p* ! 28: * ! 29: * This version of ls also prints non-printing characters as '?' if ! 30: * the standard output is a teletype. ! 31: * ! 32: * Flags relating to these and other new features are: ! 33: * ! 34: * -m force stream output. ! 35: * ! 36: * -1 force one entry per line, e.g. to a teletype ! 37: * ! 38: * -q force non-printings to be '?'s, e.g. to a file ! 39: * ! 40: * -C force columnar output, e.g. into a file ! 41: * ! 42: * -n like -l, but user/group id's in decimal rather than ! 43: * looking in /etc/passwd to save time ! 44: * ! 45: * -F turns on the "flagging" of executables and directories ! 46: * ! 47: * -R causes ls to recurse through the branches of the subtree ! 48: * ala find ! 49: */ ! 50: ! 51: #include <sys/param.h> ! 52: #include <sys/stat.h> ! 53: #include <sys/dir.h> ! 54: #include <stdio.h> ! 55: #include <ctype.h> ! 56: #include <pwd.h> ! 57: #include <grp.h> ! 58: #include <utmp.h> ! 59: ! 60: struct utmp utmp; ! 61: #define NMAX (sizeof utmp.ut_name) ! 62: ! 63: #define MAXFILEWIDTH 14 ! 64: #define NFILES 1024 ! 65: FILE *pwdf, *dirf; ! 66: ! 67: struct lbuf { ! 68: union { ! 69: char lname[15]; ! 70: char *namep; ! 71: } ln; ! 72: char ltype; ! 73: ino_t lnum; ! 74: short lflags; ! 75: short lnl; ! 76: short luid; ! 77: short lgid; ! 78: long lsize; ! 79: long lmtime; ! 80: }; ! 81: ! 82: struct dchain { ! 83: char *dc_name; /* the path name */ ! 84: struct dchain *dc_next; /* the next directory on the chain */ ! 85: }; ! 86: ! 87: struct dchain *dfirst; /* the start of the directory chain */ ! 88: struct dchain *cdfirst; /* the start of the current directory chain */ ! 89: struct dchain *dtemp; /* temporary used when linking */ ! 90: char *curdir; /* the current directory */ ! 91: ! 92: int aflg, bflg, dflg, lflg, sflg, tflg, uflg, iflg, fflg, gflg, cflg; ! 93: int Aflg, nflg, qflg, Fflg, Rflg, across, Cflg; ! 94: int nopad; ! 95: int tabflg; ! 96: int rflg = 1; ! 97: long year; ! 98: int flags; ! 99: long tblocks; ! 100: int statreq; ! 101: int xtraent; /* for those switches which print out a total */ ! 102: struct lbuf *flist[NFILES]; ! 103: struct lbuf **lastp = flist; ! 104: struct lbuf **firstp = flist; ! 105: char *dotp = "."; ! 106: ! 107: char *makename(); ! 108: struct lbuf *gstat(); ! 109: char *ctime(); ! 110: long nblock(); ! 111: char *getname(); ! 112: ! 113: #define ISARG 0100000 ! 114: int colwidth; ! 115: int filewidth; ! 116: int fixedwidth; ! 117: int outcol; ! 118: ! 119: char obuf[BUFSIZ]; ! 120: ! 121: main(argc, argv) ! 122: int argc; ! 123: char *argv[]; ! 124: { ! 125: #include <sgtty.h> ! 126: ! 127: int i, width; ! 128: register struct lbuf *ep; ! 129: register struct lbuf **slastp; ! 130: struct lbuf **epp; ! 131: struct lbuf lb; ! 132: char *t; ! 133: char *cp; ! 134: int compar(); ! 135: struct sgttyb sgbuf; ! 136: ! 137: Fflg = 0; ! 138: tabflg = 0; ! 139: Aflg = getuid() == 0; ! 140: setbuf(stdout, obuf); ! 141: lb.lmtime = time((long *) 0); ! 142: year = lb.lmtime - 6L*30L*24L*60L*60L; /* 6 months ago */ ! 143: qflg = gtty(1, &sgbuf) == 0; ! 144: ! 145: /* guarantee at least on column width */ ! 146: fixedwidth = 2; ! 147: ! 148: /* ! 149: * If the standard output is not a teletype, ! 150: * then we default to one-per-line format ! 151: * otherwise decide between stream and ! 152: * columnar based on our name. ! 153: */ ! 154: if (qflg) { ! 155: Cflg = 1; ! 156: if ((sgbuf.sg_flags & XTABS) == 0) ! 157: tabflg++; ! 158: for (cp = argv[0]; cp[0] && cp[1]; cp++) ! 159: continue; ! 160: /* ! 161: * Certain kinds of links (l, ll, lr, lf, lx) cause some ! 162: * various options to be turned on. ! 163: */ ! 164: switch (cp[0]) { ! 165: case 'l': ! 166: if (cp[-1] == 'l') { ! 167: /* ll => -l */ ! 168: lflg = 1; ! 169: statreq++; ! 170: xtraent++; ! 171: } else { ! 172: /* l => -m */ ! 173: nopad = 1; ! 174: Cflg = 0; ! 175: } ! 176: break; ! 177: case 'x': /* lx => -x */ ! 178: across = 1; ! 179: break; ! 180: case 'f': /* lf => -F */ ! 181: Fflg = 1; ! 182: break; ! 183: case 'r': /* lr => -R */ ! 184: Rflg = 1; ! 185: break; ! 186: } ! 187: } else { ! 188: tabflg++; ! 189: } ! 190: ! 191: while (--argc > 0 && *argv[1] == '-') { ! 192: argv++; ! 193: while (*++*argv) switch (**argv) { ! 194: /* ! 195: * C - force columnar output ! 196: */ ! 197: case 'C': ! 198: Cflg = 1; ! 199: nopad = 0; ! 200: continue; ! 201: /* ! 202: * m - force stream output ! 203: */ ! 204: case 'm': ! 205: Cflg = 0; ! 206: nopad = 1; ! 207: continue; ! 208: /* ! 209: * x - force sort across ! 210: */ ! 211: case 'x': ! 212: across = 1; ! 213: nopad = 0; ! 214: Cflg = 1; ! 215: continue; ! 216: /* ! 217: * q - force ?'s in output ! 218: */ ! 219: case 'q': ! 220: qflg = 1; ! 221: bflg = 0; ! 222: continue; ! 223: /* ! 224: * b - force octal value in output ! 225: */ ! 226: case 'b': ! 227: bflg = 1; ! 228: qflg = 0; ! 229: continue; ! 230: /* ! 231: * 1 - force 1/line in output ! 232: */ ! 233: case '1': ! 234: Cflg = 0; ! 235: nopad = 0; ! 236: continue; ! 237: /* STANDARD FLAGS */ ! 238: case 'a': ! 239: aflg++; ! 240: continue; ! 241: ! 242: case 'A': ! 243: Aflg = !Aflg; ! 244: continue; ! 245: ! 246: case 'c': ! 247: cflg++; ! 248: continue; ! 249: ! 250: case 's': ! 251: fixedwidth += 5; ! 252: sflg++; ! 253: statreq++; ! 254: xtraent++; ! 255: continue; ! 256: ! 257: case 'd': ! 258: dflg++; ! 259: continue; ! 260: ! 261: /* ! 262: * n - don't look in password file ! 263: */ ! 264: case 'n': ! 265: nflg++; ! 266: case 'l': ! 267: lflg++; ! 268: statreq++; ! 269: xtraent++; ! 270: continue; ! 271: ! 272: case 'r': ! 273: rflg = -1; ! 274: continue; ! 275: ! 276: case 't': ! 277: tflg++; ! 278: statreq++; ! 279: continue; ! 280: ! 281: case 'u': ! 282: uflg++; ! 283: continue; ! 284: ! 285: case 'i': ! 286: fixedwidth += 6; ! 287: iflg++; ! 288: continue; ! 289: ! 290: case 'f': ! 291: fflg++; ! 292: continue; ! 293: ! 294: case 'g': ! 295: gflg++; ! 296: continue; ! 297: ! 298: case 'F': ! 299: Fflg++; ! 300: continue; ! 301: ! 302: case 'R': ! 303: Rflg++; ! 304: continue; ! 305: ! 306: default: ! 307: fprintf (stderr, "usage: ls [-1ACFRabcdfgilmnqrstux] [files]\n"); ! 308: exit(1); ! 309: } ! 310: } ! 311: if (Fflg) ! 312: #ifdef UCB ! 313: fixedwidth++; ! 314: #else ! 315: fixedwidth += 2; ! 316: #endif ! 317: if (fflg) { ! 318: aflg++; ! 319: lflg = 0; ! 320: sflg = 0; ! 321: tflg = 0; ! 322: statreq = 0; ! 323: xtraent = 0; ! 324: } ! 325: if(lflg) { ! 326: Cflg = 0; ! 327: t = "/etc/passwd"; ! 328: if (gflg) ! 329: t = "/etc/group"; ! 330: nopad = 0; ! 331: fixedwidth = 70; ! 332: pwdf = fopen(t, "r"); ! 333: } ! 334: if (argc==0) { ! 335: argc++; ! 336: argv = &dotp - 1; ! 337: } ! 338: for (i=0; i < argc; i++) { ! 339: argv++; ! 340: if (Cflg) { ! 341: width = strlen (*argv); ! 342: if (width > filewidth) ! 343: filewidth = width; ! 344: } ! 345: if ((ep = gstat(*argv, 1))==NULL) ! 346: continue; ! 347: ep->ln.namep = *argv; ! 348: ep->lflags |= ISARG; ! 349: } ! 350: if (!Cflg) ! 351: filewidth = MAXFILEWIDTH; ! 352: else ! 353: colwidth = fixedwidth + filewidth; ! 354: qsort(firstp, lastp - firstp, sizeof *lastp, compar); ! 355: slastp = lastp; ! 356: /* For each argument user typed */ ! 357: for (epp=firstp; epp<slastp; epp++) { ! 358: ep = *epp; ! 359: if (ep->ltype=='d' && dflg==0 || fflg) ! 360: pdirectory(ep->ln.namep, (argc>1), slastp); ! 361: else ! 362: pentry(ep); ! 363: ! 364: /* -R: print subdirectories found */ ! 365: while (dfirst || cdfirst) { ! 366: /* Place direct subdirs on front in right order */ ! 367: while (cdfirst) { ! 368: /* reverse cdfirst onto front of dfirst */ ! 369: dtemp = cdfirst; ! 370: cdfirst = cdfirst -> dc_next; ! 371: dtemp -> dc_next = dfirst; ! 372: dfirst = dtemp; ! 373: } ! 374: /* take off first dir on dfirst & print it */ ! 375: dtemp = dfirst; ! 376: dfirst = dfirst->dc_next; ! 377: pdirectory (dtemp->dc_name, 1, firstp); ! 378: cfree (dtemp->dc_name); ! 379: cfree (dtemp); ! 380: } ! 381: } ! 382: if (outcol) ! 383: putc('\n', stdout); ! 384: fflush(stdout); ! 385: } ! 386: ! 387: /* ! 388: * pdirectory: print the directory name, labelling it if title is ! 389: * nonzero, using lp as the place to start reading in the dir. ! 390: */ ! 391: pdirectory (name, title, lp) ! 392: char *name; ! 393: int title; ! 394: struct lbuf **lp; ! 395: { ! 396: register struct dchain *dp; ! 397: register struct lbuf *ap; ! 398: register char *pname; ! 399: struct lbuf **app; ! 400: ! 401: filewidth = 0; ! 402: curdir = name; ! 403: if (title) ! 404: printf("\n%s:\n", name); ! 405: lastp = lp; ! 406: readdir(name); ! 407: if (!Cflg) ! 408: filewidth = MAXFILEWIDTH; ! 409: colwidth = fixedwidth + filewidth; ! 410: #ifdef notdef ! 411: /* Taken out because it appears this is done below in pem. */ ! 412: if (tabflg) { ! 413: if (colwidth <= 8) ! 414: colwidth = 8; ! 415: else ! 416: if (colwidth <= 16) ! 417: colwidth = 16; ! 418: } ! 419: #endif ! 420: if (fflg==0) ! 421: qsort(lp,lastp - lp,sizeof *lastp,compar); ! 422: if (Rflg) for (app=lastp-1; app>=lp; app--) { ! 423: ap = *app; ! 424: if (ap->ltype == 'd' && strcmp(ap->ln.lname, ".") && ! 425: strcmp(ap->ln.lname, "..")) { ! 426: dp = (struct dchain *) calloc(1, sizeof(struct dchain)); ! 427: pname = makename (curdir, ap->ln.lname); ! 428: dp->dc_name = (char *) calloc(1, strlen(pname)+1); ! 429: strcpy(dp->dc_name, pname); ! 430: dp -> dc_next = dfirst; ! 431: dfirst = dp; ! 432: } ! 433: } ! 434: if (lflg || sflg) ! 435: printf("total %D", tblocks); ! 436: pem(lp, lastp); ! 437: newline(); ! 438: } ! 439: ! 440: /* ! 441: * pem: print 'em. Print a list of files (e.g. a directory) bounded ! 442: * by slp and lp. ! 443: */ ! 444: pem(slp, lp) ! 445: register struct lbuf **slp, **lp; ! 446: { ! 447: int ncols, nrows, row, col; ! 448: register struct lbuf **ep; ! 449: ! 450: if (tabflg) { ! 451: if (colwidth <= 9) ! 452: colwidth = 8; ! 453: else ! 454: if (colwidth <= 17) ! 455: colwidth = 16; ! 456: } ! 457: ncols = 80 / colwidth; ! 458: if (ncols == 1 || Cflg == 0) { ! 459: for (ep = slp; ep < lp; ep++) ! 460: pentry(*ep); ! 461: return; ! 462: } ! 463: if (across) { ! 464: for (ep = slp; ep < lp; ep++) ! 465: pentry(*ep); ! 466: return; ! 467: } ! 468: if (xtraent) ! 469: slp--; ! 470: nrows = (lp - slp - 1) / ncols + 1; ! 471: for (row = 0; row < nrows; row++) { ! 472: col = row == 0 && xtraent; ! 473: for (; col < ncols; col++) { ! 474: ep = slp + (nrows * col) + row; ! 475: if (ep < lp) ! 476: pentry(*ep); ! 477: } ! 478: if (outcol) ! 479: printf("\n"); ! 480: } ! 481: } ! 482: ! 483: /* ! 484: * pputchar: like putchar but knows how to handle control chars. ! 485: * CAUTION: if you make ctrl chars print in ^x notation, or any ! 486: * other notation which is wider than one character, the column ! 487: * nature of things (such as files with 14 letter names) will be ! 488: * messed up. Weigh this carefully! ! 489: */ ! 490: pputchar(c) ! 491: char c; ! 492: { ! 493: char cc; ! 494: ! 495: switch (c) { ! 496: case '\t': ! 497: outcol = (outcol + 8) &~ 7; ! 498: break; ! 499: case '\n': ! 500: outcol = 0; ! 501: break; ! 502: default: ! 503: if (c < ' ' || c >= 0177) { ! 504: if (qflg) ! 505: c = '?'; ! 506: else if (bflg) { ! 507: outcol += 3; ! 508: putc ('\\', stdout); ! 509: cc = '0' + (c>>6 & 07); ! 510: putc (cc, stdout); ! 511: cc = '0' + (c>>3 & 07); ! 512: putc (cc, stdout); ! 513: c = '0' + (c & 07); ! 514: } ! 515: } ! 516: outcol++; ! 517: break; ! 518: } ! 519: putc(c, stdout); ! 520: } ! 521: ! 522: newline() ! 523: { ! 524: if (outcol) ! 525: putc('\n', stdout); ! 526: outcol = 0; ! 527: } ! 528: ! 529: /* ! 530: * column: get to the beginning of the next column. ! 531: */ ! 532: column() ! 533: { ! 534: ! 535: if (outcol == 0) ! 536: return; ! 537: if (nopad) { ! 538: putc(',', stdout); ! 539: outcol++; ! 540: if (outcol + colwidth + 2 > 80) { ! 541: putc('\n', stdout); ! 542: outcol = 0; ! 543: return; ! 544: } ! 545: putc(' ', stdout); ! 546: outcol++; ! 547: return; ! 548: } ! 549: if (Cflg == 0) { ! 550: putc('\n', stdout); ! 551: return; ! 552: } ! 553: if ((outcol / colwidth + 2) * colwidth > 80) { ! 554: putc('\n', stdout); ! 555: outcol = 0; ! 556: return; ! 557: } ! 558: if (tabflg && (colwidth <= 16)) { ! 559: if (colwidth > 8) ! 560: if ((outcol % 16) < 8) { ! 561: outcol += 8 - (outcol % 8); ! 562: putc ('\t', stdout); ! 563: } ! 564: outcol += 8 - (outcol % 8); ! 565: putc ('\t', stdout); ! 566: return; ! 567: } ! 568: do { ! 569: outcol++; ! 570: putc(' ', stdout); ! 571: } while (outcol % colwidth); ! 572: } ! 573: ! 574: ! 575: /* ! 576: * nblock: the number of 512 byte blocks a size byte file takes up. ! 577: * (Note: the number stays 512 no matter what BUFSIZ or the filesystem uses.) ! 578: */ ! 579: long ! 580: nblock(size) ! 581: long size; ! 582: { ! 583: return((size+511)>>9); ! 584: } ! 585: ! 586: /* ! 587: * This code handles the rwx- business. ! 588: * You figure it out. ! 589: */ ! 590: int m1[] = { 1, S_IREAD>>0, 'r', '-' }; ! 591: int m2[] = { 1, S_IWRITE>>0, 'w', '-' }; ! 592: int m3[] = { 2, S_ISUID, 's', S_IEXEC>>0, 'x', '-' }; ! 593: int m4[] = { 1, S_IREAD>>3, 'r', '-' }; ! 594: int m5[] = { 1, S_IWRITE>>3, 'w', '-' }; ! 595: int m6[] = { 2, S_ISGID, 's', S_IEXEC>>3, 'x', '-' }; ! 596: int m7[] = { 1, S_IREAD>>6, 'r', '-' }; ! 597: int m8[] = { 1, S_IWRITE>>6, 'w', '-' }; ! 598: int m9[] = { 2, S_ISVTX, 't', S_IEXEC>>6, 'x', '-' }; ! 599: ! 600: int *m[] = { m1, m2, m3, m4, m5, m6, m7, m8, m9}; ! 601: ! 602: pmode(aflag) ! 603: { ! 604: register int **mp; ! 605: ! 606: flags = aflag; ! 607: for (mp = &m[0]; mp < &m[sizeof(m)/sizeof(m[0])];) ! 608: select(*mp++); ! 609: } ! 610: ! 611: select(pairp) ! 612: register int *pairp; ! 613: { ! 614: register int n; ! 615: ! 616: n = *pairp++; ! 617: while (--n>=0 && (flags&*pairp++)==0) ! 618: pairp++; ! 619: pputchar(*pairp); ! 620: } ! 621: ! 622: /* ! 623: * returns cat(dir, "/", file), unless dir ends in /, when it doesn't // ! 624: */ ! 625: char * ! 626: makename(dir, file) ! 627: char *dir, *file; ! 628: { ! 629: static char dfile[100]; ! 630: register char *dp, *fp; ! 631: register int i; ! 632: ! 633: dp = dfile; ! 634: fp = dir; ! 635: while (*fp) ! 636: *dp++ = *fp++; ! 637: if (*(dp-1) != '/') ! 638: *dp++ = '/'; ! 639: fp = file; ! 640: for (i=0; i<DIRSIZ; i++) ! 641: *dp++ = *fp++; ! 642: *dp = 0; ! 643: return(dfile); ! 644: } ! 645: ! 646: /* ! 647: * readdir: read in the directory whose name is dir, ! 648: * starting at lastp. ! 649: */ ! 650: readdir(dir) ! 651: char *dir; ! 652: { ! 653: static struct direct dentry; ! 654: register int j, width; ! 655: register struct lbuf *ep; ! 656: ! 657: if ((dirf = fopen(dir, "r")) == NULL) { ! 658: printf("%s unreadable\n", dir); ! 659: return; ! 660: } ! 661: tblocks = 0; ! 662: for(;;) { ! 663: if (fread(&dentry, sizeof(dentry), 1, dirf) != 1) ! 664: break; ! 665: if (dentry.d_ino==0 || ! 666: aflg==0 && dentry.d_name[0]=='.' && ( ! 667: !Aflg || ! 668: dentry.d_name[1]=='\0' ! 669: || dentry.d_name[1]=='.' && dentry.d_name[2]=='\0')) ! 670: continue; ! 671: if (Cflg) { ! 672: width = strlen (dentry.d_name); ! 673: if (width > filewidth) ! 674: filewidth = width; ! 675: } ! 676: ep = gstat(makename(dir, dentry.d_name), Fflg || Rflg); ! 677: if (ep==NULL) ! 678: continue; ! 679: if (ep->lnum != -1) ! 680: ep->lnum = dentry.d_ino; ! 681: for (j=0; j<DIRSIZ; j++) ! 682: ep->ln.lname[j] = dentry.d_name[j]; ! 683: } ! 684: fclose(dirf); ! 685: } ! 686: ! 687: /* ! 688: * stat the given file and return an lbuf containing it. ! 689: * argfl is nonzero if a stat is required because the file is ! 690: * an argument, rather than having been found in a directory. ! 691: */ ! 692: struct lbuf * ! 693: gstat(file, argfl) ! 694: char *file; ! 695: { ! 696: struct stat statb; ! 697: register struct lbuf *rep; ! 698: static int nomocore; ! 699: ! 700: if (nomocore) ! 701: return(NULL); ! 702: rep = (struct lbuf *)malloc(sizeof(struct lbuf)); ! 703: if (rep==NULL) { ! 704: fprintf(stderr, "ls: out of memory\n"); ! 705: nomocore = 1; ! 706: return(NULL); ! 707: } ! 708: if (lastp >= &flist[NFILES]) { ! 709: static int msg; ! 710: lastp--; ! 711: if (msg==0) { ! 712: fprintf(stderr, "ls: too many files\n"); ! 713: msg++; ! 714: } ! 715: } ! 716: *lastp++ = rep; ! 717: rep->lflags = 0; ! 718: rep->lnum = 0; ! 719: rep->ltype = '-'; ! 720: if (argfl || statreq) { ! 721: if (stat(file, &statb)<0) { ! 722: printf("%s not found\n", file); ! 723: statb.st_ino = -1; ! 724: statb.st_size = 0; ! 725: statb.st_mode = 0; ! 726: if (argfl) { ! 727: lastp--; ! 728: return(0); ! 729: } ! 730: } ! 731: rep->lnum = statb.st_ino; ! 732: rep->lsize = statb.st_size; ! 733: switch(statb.st_mode&S_IFMT) { ! 734: ! 735: case S_IFDIR: ! 736: rep->ltype = 'd'; ! 737: break; ! 738: ! 739: case S_IFBLK: ! 740: rep->ltype = 'b'; ! 741: rep->lsize = statb.st_rdev; ! 742: break; ! 743: ! 744: case S_IFCHR: ! 745: rep->ltype = 'c'; ! 746: rep->lsize = statb.st_rdev; ! 747: break; ! 748: ! 749: case S_IFMPB: ! 750: rep->ltype = 'M'; ! 751: rep->lsize = statb.st_rdev; ! 752: break; ! 753: ! 754: case S_IFMPC: ! 755: rep->ltype = 'm'; ! 756: rep->lsize = statb.st_rdev; ! 757: break; ! 758: } ! 759: rep->lflags = statb.st_mode & ~S_IFMT; ! 760: rep->luid = statb.st_uid; ! 761: rep->lgid = statb.st_gid; ! 762: rep->lnl = statb.st_nlink; ! 763: if(uflg) ! 764: rep->lmtime = statb.st_atime; ! 765: else if (cflg) ! 766: rep->lmtime = statb.st_ctime; ! 767: else ! 768: rep->lmtime = statb.st_mtime; ! 769: tblocks += nblock(statb.st_size); ! 770: } ! 771: return(rep); ! 772: } ! 773: ! 774: /* ! 775: * decide whether to print pp1 before or after pp2, based on their ! 776: * names, various times, and the r flag. ! 777: */ ! 778: compar(pp1, pp2) ! 779: struct lbuf **pp1, **pp2; ! 780: { ! 781: register struct lbuf *p1, *p2; ! 782: ! 783: p1 = *pp1; ! 784: p2 = *pp2; ! 785: if (dflg==0) { ! 786: if (p1->lflags&ISARG && p1->ltype=='d') { ! 787: if (!(p2->lflags&ISARG && p2->ltype=='d')) ! 788: return(1); ! 789: } else { ! 790: if (p2->lflags&ISARG && p2->ltype=='d') ! 791: return(-1); ! 792: } ! 793: } ! 794: if (tflg) { ! 795: if(p2->lmtime == p1->lmtime) ! 796: return(0); ! 797: if(p2->lmtime > p1->lmtime) ! 798: return(rflg); ! 799: return(-rflg); ! 800: } ! 801: return(rflg * strcmp(p1->lflags&ISARG? p1->ln.namep: p1->ln.lname, ! 802: p2->lflags&ISARG? p2->ln.namep: p2->ln.lname)); ! 803: } ! 804: ! 805: /* ! 806: * print the entry pointed at by ap ! 807: */ ! 808: pentry(ap) ! 809: struct lbuf *ap; ! 810: { ! 811: struct { char dminor, dmajor;}; ! 812: register struct lbuf *p; ! 813: register char *cp; ! 814: char fname[100]; ! 815: char *pname; ! 816: struct passwd *getpwuid(); ! 817: struct passwd *pwptr; ! 818: struct group *getgrgid(); ! 819: struct group *grptr; ! 820: ! 821: fname[0] = 0; ! 822: p = ap; ! 823: if (p->lnum == -1) ! 824: return; ! 825: column(); ! 826: if (iflg) ! 827: if (nopad && !lflg) ! 828: printf("%d ", p->lnum); ! 829: else ! 830: printf("%5d ", p->lnum); ! 831: if (sflg) ! 832: if (nopad && !lflg) ! 833: printf("%D ", nblock(p->lsize)); ! 834: else ! 835: printf("%4D ", nblock(p->lsize)); ! 836: if (lflg) { ! 837: pputchar(p->ltype); ! 838: pmode(p->lflags); ! 839: printf("%2d ", p->lnl); ! 840: if(gflg) { ! 841: grptr = getgrgid(p->lgid); ! 842: if (nflg == 0 && grptr != 0) ! 843: printf("%-8.8s", grptr->gr_name); ! 844: else ! 845: printf("%-8d", p->lgid); ! 846: } else { ! 847: #ifndef UCB_PWHASH ! 848: char *name; ! 849: if (nflg == 0 && (name = getname(p->luid))) { ! 850: printf("%-8.8s", name); ! 851: } ! 852: #else ! 853: pwptr = getpwuid(p->luid); ! 854: if (nflg == 0 && pwptr != 0) ! 855: printf("%-8.8s", pwptr->pw_name); ! 856: #endif ! 857: else ! 858: printf("%-8d", p->luid); ! 859: } ! 860: switch (p->ltype) { ! 861: ! 862: case 'b': ! 863: case 'c': ! 864: case 'm': ! 865: case 'M': ! 866: printf("%3d,%3d", ! 867: major((int)p->lsize), minor((int)p->lsize)); ! 868: break; ! 869: default: ! 870: printf("%7ld", p->lsize); ! 871: } ! 872: cp = ctime(&p->lmtime); ! 873: if(p->lmtime < year) ! 874: printf(" %-7.7s %-4.4s ", cp+4, cp+20); else ! 875: printf(" %-12.12s ", cp+4); ! 876: } ! 877: #ifndef UCB ! 878: if (Fflg) { ! 879: if (p->ltype == 'd') ! 880: strcat (fname, "["); ! 881: else if (p->lflags & 0111) ! 882: strcat (fname, "*"); ! 883: else if (!nopad) ! 884: strcat (fname, " "); ! 885: } ! 886: #endif ! 887: if (p->lflags & ISARG) ! 888: strncat (fname, p->ln.namep, 98); ! 889: else ! 890: strncat (fname, p->ln.lname, 14); ! 891: #ifndef UCB ! 892: if (Fflg) { ! 893: if (p->ltype == 'd') ! 894: strcat (fname, "]"); ! 895: else if (!nopad) ! 896: strcat (fname, " "); ! 897: } ! 898: #else ! 899: if (Fflg) { ! 900: if (p->ltype == 'd') ! 901: strcat (fname, "/"); ! 902: else if (p->lflags & 0111) ! 903: strcat (fname, "*"); ! 904: else if (!nopad) ! 905: strcat (fname, " "); ! 906: } ! 907: #endif ! 908: printf ("%s", fname); ! 909: free(ap); ! 910: } ! 911: ! 912: /* char printf_id[] = "@(#) printf.c:2.2 6/5/79";*/ ! 913: ! 914: #include "varargs.h" ! 915: ! 916: /* ! 917: * This version of printf is compatible with the Version 7 C ! 918: * printf. The differences are only minor except that this ! 919: * printf assumes it is to print through pputchar. Version 7 ! 920: * printf is more general (and is much larger) and includes ! 921: * provisions for floating point. ! 922: */ ! 923: ! 924: #define MAXOCT 11 /* Maximum octal digits in a long */ ! 925: #define MAXINT 32767 /* largest normal length positive integer */ ! 926: #define BIG 1000000000 /* largest power of 10 less than an unsigned long */ ! 927: #define MAXDIGS 10 /* number of digits in BIG */ ! 928: ! 929: static int width, sign, fill; ! 930: ! 931: char *b_dconv(); ! 932: ! 933: printf(va_alist) ! 934: va_dcl ! 935: { ! 936: va_list ap; ! 937: register char *fmt; ! 938: char fcode; ! 939: int prec; ! 940: int length,mask1,nbits,n; ! 941: long int mask2, num; ! 942: register char *bptr; ! 943: char *ptr; ! 944: char buf[134]; ! 945: ! 946: va_start(ap); ! 947: fmt = va_arg(ap,char *); ! 948: for (;;) { ! 949: /* process format string first */ ! 950: while ((fcode = *fmt++)!='%') { ! 951: /* ordinary (non-%) character */ ! 952: if (fcode=='\0') ! 953: return; ! 954: pputchar(fcode); ! 955: } ! 956: /* length modifier: -1 for h, 1 for l, 0 for none */ ! 957: length = 0; ! 958: /* check for a leading - sign */ ! 959: sign = 0; ! 960: if (*fmt == '-') { ! 961: sign++; ! 962: fmt++; ! 963: } ! 964: /* a '0' may follow the - sign */ ! 965: /* this is the requested fill character */ ! 966: fill = 1; ! 967: if (*fmt == '0') { ! 968: fill--; ! 969: fmt++; ! 970: } ! 971: ! 972: /* Now comes a digit string which may be a '*' */ ! 973: if (*fmt == '*') { ! 974: width = va_arg(ap, int); ! 975: if (width < 0) { ! 976: width = -width; ! 977: sign = !sign; ! 978: } ! 979: fmt++; ! 980: } ! 981: else { ! 982: width = 0; ! 983: while (*fmt>='0' && *fmt<='9') ! 984: width = width * 10 + (*fmt++ - '0'); ! 985: } ! 986: ! 987: /* maybe a decimal point followed by more digits (or '*') */ ! 988: if (*fmt=='.') { ! 989: if (*++fmt == '*') { ! 990: prec = va_arg(ap, int); ! 991: fmt++; ! 992: } ! 993: else { ! 994: prec = 0; ! 995: while (*fmt>='0' && *fmt<='9') ! 996: prec = prec * 10 + (*fmt++ - '0'); ! 997: } ! 998: } ! 999: else ! 1000: prec = -1; ! 1001: ! 1002: /* ! 1003: * At this point, "sign" is nonzero if there was ! 1004: * a sign, "fill" is 0 if there was a leading ! 1005: * zero and 1 otherwise, "width" and "prec" ! 1006: * contain numbers corresponding to the digit ! 1007: * strings before and after the decimal point, ! 1008: * respectively, and "fmt" addresses the next ! 1009: * character after the whole mess. If there was ! 1010: * no decimal point, "prec" will be -1. ! 1011: */ ! 1012: switch (*fmt) { ! 1013: case 'L': ! 1014: case 'l': ! 1015: length = 2; ! 1016: /* no break!! */ ! 1017: case 'h': ! 1018: case 'H': ! 1019: length--; ! 1020: fmt++; ! 1021: break; ! 1022: } ! 1023: ! 1024: /* ! 1025: * At exit from the following switch, we will ! 1026: * emit the characters starting at "bptr" and ! 1027: * ending at "ptr"-1, unless fcode is '\0'. ! 1028: */ ! 1029: switch (fcode = *fmt++) { ! 1030: /* process characters and strings first */ ! 1031: case 'c': ! 1032: buf[0] = va_arg(ap, int); ! 1033: ptr = bptr = &buf[0]; ! 1034: if (buf[0] != '\0') ! 1035: ptr++; ! 1036: break; ! 1037: case 's': ! 1038: bptr = va_arg(ap,char *); ! 1039: if (bptr==0) ! 1040: bptr = "(null pointer)"; ! 1041: if (prec < 0) ! 1042: prec = MAXINT; ! 1043: for (n=0; *bptr++ && n < prec; n++) ; ! 1044: ptr = --bptr; ! 1045: bptr -= n; ! 1046: break; ! 1047: case 'O': ! 1048: length = 1; ! 1049: fcode = 'o'; ! 1050: /* no break */ ! 1051: case 'o': ! 1052: case 'X': ! 1053: case 'x': ! 1054: if (length > 0) ! 1055: num = va_arg(ap,long); ! 1056: else ! 1057: num = (unsigned)va_arg(ap,int); ! 1058: if (fcode=='o') { ! 1059: mask1 = 0x7; ! 1060: mask2 = 0x1fffffffL; ! 1061: nbits = 3; ! 1062: } ! 1063: else { ! 1064: mask1 = 0xf; ! 1065: mask2 = 0x0fffffffL; ! 1066: nbits = 4; ! 1067: } ! 1068: n = (num!=0); ! 1069: bptr = buf + MAXOCT + 3; ! 1070: /* shift and mask for speed */ ! 1071: do ! 1072: if (((int) num & mask1) < 10) ! 1073: *--bptr = ((int) num & mask1) + 060; ! 1074: else ! 1075: *--bptr = ((int) num & mask1) + 0127; ! 1076: while (num = (num >> nbits) & mask2); ! 1077: ! 1078: if (fcode=='o') { ! 1079: if (n) ! 1080: *--bptr = '0'; ! 1081: } ! 1082: else ! 1083: if (!sign && fill <= 0) { ! 1084: pputchar('0'); ! 1085: pputchar(fcode); ! 1086: width -= 2; ! 1087: } ! 1088: else { ! 1089: *--bptr = fcode; ! 1090: *--bptr = '0'; ! 1091: } ! 1092: ptr = buf + MAXOCT + 3; ! 1093: break; ! 1094: case 'D': ! 1095: case 'U': ! 1096: case 'I': ! 1097: length = 1; ! 1098: ! 1099: fcode = fcode + 'a' - 'A'; ! 1100: /* no break */ ! 1101: case 'd': ! 1102: case 'i': ! 1103: case 'u': ! 1104: if (length > 0) ! 1105: num = va_arg(ap,long); ! 1106: else { ! 1107: n = va_arg(ap,int); ! 1108: if (fcode=='u') ! 1109: num = (unsigned) n; ! 1110: else ! 1111: num = (long) n; ! 1112: } ! 1113: if (n = (fcode != 'u' && num < 0)) ! 1114: num = -num; ! 1115: /* now convert to digits */ ! 1116: bptr = b_dconv(num, buf); ! 1117: if (n) ! 1118: *--bptr = '-'; ! 1119: if (fill == 0) ! 1120: fill = -1; ! 1121: ptr = buf + MAXDIGS + 1; ! 1122: break; ! 1123: default: ! 1124: /* not a control character, ! 1125: * print it. ! 1126: */ ! 1127: ptr = bptr = &fcode; ! 1128: ptr++; ! 1129: break; ! 1130: } ! 1131: if (fcode != '\0') ! 1132: b_emit(bptr,ptr); ! 1133: } ! 1134: va_end(ap); ! 1135: } ! 1136: ! 1137: /* b_dconv converts the unsigned long integer "value" to ! 1138: * printable decimal and places it in "buffer", right-justified. ! 1139: * The value returned is the address of the first non-zero character, ! 1140: * or the address of the last character if all are zero. ! 1141: * The result is NOT null terminated, and is MAXDIGS characters long, ! 1142: * starting at buffer[1] (to allow for insertion of a sign). ! 1143: * ! 1144: * This program assumes it is running on 2's complement machine ! 1145: * with reasonable overflow treatment. ! 1146: */ ! 1147: char * ! 1148: b_dconv(value, buffer) ! 1149: long value; ! 1150: char *buffer; ! 1151: { ! 1152: register char *bp; ! 1153: register int svalue; ! 1154: int n; ! 1155: long lval; ! 1156: ! 1157: bp = buffer; ! 1158: ! 1159: /* zero is a special case */ ! 1160: if (value == 0) { ! 1161: bp += MAXDIGS; ! 1162: *bp = '0'; ! 1163: return(bp); ! 1164: } ! 1165: ! 1166: /* develop the leading digit of the value in "n" */ ! 1167: n = 0; ! 1168: while (value < 0) { ! 1169: value -= BIG; /* will eventually underflow */ ! 1170: n++; ! 1171: } ! 1172: while ((lval = value - BIG) >= 0) { ! 1173: value = lval; ! 1174: n++; ! 1175: } ! 1176: ! 1177: /* stash it in buffer[1] to allow for a sign */ ! 1178: bp[1] = n + '0'; ! 1179: /* ! 1180: * Now develop the rest of the digits. Since speed counts here, ! 1181: * we do it in two loops. The first gets "value" down until it ! 1182: * is no larger than MAXINT. The second one uses integer divides ! 1183: * rather than long divides to speed it up. ! 1184: */ ! 1185: bp += MAXDIGS + 1; ! 1186: while (value > MAXINT) { ! 1187: *--bp = (int)(value % 10) + '0'; ! 1188: value /= 10; ! 1189: } ! 1190: ! 1191: /* cannot lose precision */ ! 1192: svalue = value; ! 1193: while (svalue > 0) { ! 1194: *--bp = (svalue % 10) + '0'; ! 1195: svalue /= 10; ! 1196: } ! 1197: ! 1198: /* fill in intermediate zeroes if needed */ ! 1199: if (buffer[1] != '0') { ! 1200: while (bp > buffer + 2) ! 1201: *--bp = '0'; ! 1202: --bp; ! 1203: } ! 1204: return(bp); ! 1205: } ! 1206: ! 1207: /* ! 1208: * This program sends string "s" to pputchar. The character after ! 1209: * the end of "s" is given by "send". This allows the size of the ! 1210: * field to be computed; it is stored in "alen". "width" contains the ! 1211: * user specified length. If width<alen, the width will be taken to ! 1212: * be alen. "sign" is zero if the string is to be right-justified ! 1213: * in the field, nonzero if it is to be left-justified. "fill" is ! 1214: * 0 if the string is to be padded with '0', positive if it is to be ! 1215: * padded with ' ', and negative if an initial '-' should appear before ! 1216: * any padding in right-justification (to avoid printing "-3" as ! 1217: * "000-3" where "-0003" was intended). ! 1218: */ ! 1219: b_emit(s, send) ! 1220: register char *s; ! 1221: char *send; ! 1222: { ! 1223: char cfill; ! 1224: register int alen; ! 1225: int npad; ! 1226: ! 1227: alen = send - s; ! 1228: if (alen > width) ! 1229: width = alen; ! 1230: cfill = fill>0? ' ': '0'; ! 1231: ! 1232: /* we may want to print a leading '-' before anything */ ! 1233: if (*s == '-' && fill < 0) { ! 1234: pputchar(*s++); ! 1235: alen--; ! 1236: width--; ! 1237: } ! 1238: npad = width - alen; ! 1239: ! 1240: /* emit any leading pad characters */ ! 1241: if (!sign) ! 1242: while (--npad >= 0) ! 1243: pputchar(cfill); ! 1244: ! 1245: /* emit the string itself */ ! 1246: while (--alen >= 0) ! 1247: pputchar(*s++); ! 1248: ! 1249: /* emit trailing pad characters */ ! 1250: if (sign) ! 1251: while (--npad >= 0) ! 1252: pputchar(cfill); ! 1253: } ! 1254: ! 1255: #ifndef UCB_PWHASH ! 1256: #define NUID 2048 ! 1257: ! 1258: char names[NUID][NMAX+1]; ! 1259: ! 1260: char * ! 1261: getname(uid) ! 1262: { ! 1263: register struct passwd *pw; ! 1264: static init; ! 1265: struct passwd *getpwent(); ! 1266: ! 1267: if (uid >= 0 && uid < NUID && names[uid][0]) ! 1268: return (&names[uid][0]); ! 1269: if (init == 2) ! 1270: return (0); ! 1271: if (init == 0) ! 1272: setpwent(), init = 1; ! 1273: while (pw = getpwent()) { ! 1274: if (pw->pw_uid < 0 || pw->pw_uid >= NUID) ! 1275: continue; ! 1276: if (names[pw->pw_uid][0]) ! 1277: continue; ! 1278: strncpy(names[pw->pw_uid], pw->pw_name, NMAX); ! 1279: if (pw->pw_uid == uid) ! 1280: return (&names[uid][0]); ! 1281: } ! 1282: init = 2; ! 1283: endpwent(); ! 1284: return (0); ! 1285: } ! 1286: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.