|
|
1.1 ! root 1: /* ! 2: * ls.c ! 3: * 03/17/92 ! 4: * List structure ! 5: */ ! 6: ! 7: #include <stdio.h> ! 8: #include <canon.h> ! 9: #include <time.h> ! 10: #include <sys/stat.h> ! 11: #include <sys/dir.h> ! 12: #include <pwd.h> ! 13: #include <grp.h> ! 14: #include <string.h> ! 15: ! 16: #define BSIZE BUFSIZ /* Disc blocking factor for '-s' */ ! 17: #define NBN 128 /* Number of blocks in an indirect block */ ! 18: #define ND 10 /* Number of direct blocks */ ! 19: #define NI 1 /* Number of indirect blocks */ ! 20: #define NII 1 /* Number of double indirect blocks */ ! 21: #define NIII 1 /* Number of triple indirect blocks */ ! 22: ! 23: #define MTIME 0 /* Use modify time */ ! 24: #define ATIME 1 /* Use access time */ ! 25: #define CTIME 2 /* Use create time */ ! 26: ! 27: #define GAP 1 /* Space between Multi-column entries */ ! 28: #define MAXLEN 78 /* Maximum line length */ ! 29: #define MAXARG 512 /* Maximum # of args stored for -C sort */ ! 30: #define MAXDIR 128 /* Maximum # of subdirectories for -R */ ! 31: #define MAXWID 12 /* Default max width for columns */ ! 32: #define MAXNBUF 80 /* Maximum namebuf length */ ! 33: ! 34: #define OLD (60L*60*24*365) /* old form of dates (seconds) */ ! 35: ! 36: /* ! 37: * The following flags are mutually exclusive. ! 38: * The rightmost one on the command line wins. ! 39: */ ! 40: #define EXCLUDE_Clmnox Cflag = lflag = mflag = nflag = oflag = xflag = 0 ! 41: ! 42: int aflag; /* List all entries (including "." & "..") */ ! 43: int bflag; /* Print non-raphic chars in octal */ ! 44: int Cflag; /* Multicolumn, sorted down the columns */ ! 45: int dflag; /* Treat directories like files */ ! 46: int fflag; /* Force something to look like a directory */ ! 47: int Fflag; /* Print / after dirs, * after executables */ ! 48: int gflag; /* Print gid vs. uid */ ! 49: int iflag; /* Give i-number */ ! 50: int lflag; /* Longer format */ ! 51: int mflag; /* Stream format output */ ! 52: int nflag; /* Same as -l except GID and UID are #s */ ! 53: int oflag; /* Same as -l except group is not printed */ ! 54: int pflag; /* Print a / after directories */ ! 55: int qflag; /* Force non-graphic chars into ? mode */ ! 56: int Rflag; /* List directories recursively */ ! 57: int rflag; /* Reverse order of sort */ ! 58: int sflag; /* Print size in bytes */ ! 59: int tflag = MTIME; /* Which time to display and sort on */ ! 60: int xflag; /* Multicolumn, sort across the columns */ ! 61: int sortflg; /* On for sort by time, 0 for by name */ ! 62: int myuid; /* User id for selecting .* suppression */ ! 63: ! 64: int linesiz = 0; /* Keep track of how much printed for -m */ ! 65: int first = 1; /* First in stream format? */ ! 66: int maxwidth = MAXWID; /* Longest string in multi-column format */ ! 67: int ncols = 1; /* Number of columns */ ! 68: int nrows = 1; /* Number of rows */ ! 69: int offset = 0; /* How far to move pointer to print next entry*/ ! 70: int nlast = 0; /* Number of cols in last row */ ! 71: int ccol = 0; /* Current Column */ ! 72: time_t curtime; ! 73: ! 74: char obuf[BUFSIZ]; ! 75: ! 76: char *deflist[] = { ! 77: ".", ! 78: NULL ! 79: }; ! 80: ! 81: char *namelist[MAXARG]; /* store file names for column output */ ! 82: ! 83: typedef struct dlist{ ! 84: char *name; ! 85: fsize_t size; ! 86: } DLIST; ! 87: ! 88: typedef struct ls { ! 89: char ls_dname[DIRSIZ+1]; ! 90: char *ls_name; ! 91: char *ck_name; ! 92: ino_t ls_ino; ! 93: short ls_mode; ! 94: short ls_uid; ! 95: short ls_gid; ! 96: short ls_nlink; ! 97: fsize_t ls_size; ! 98: dev_t ls_rdev; /* Real device */ ! 99: time_t ls_time; /* One of atime, mtime, ctime */ ! 100: } LS; ! 101: ! 102: int (*qcomp)(); ! 103: int qtcomp(); ! 104: int qncomp(); ! 105: int qdncomp(); ! 106: ! 107: char *alloc(); ! 108: void fatal(); ! 109: char *getuname(); ! 110: char *getgname(); ! 111: char *getname(); ! 112: char *getflag(); ! 113: ! 114: main(argc, argv) ! 115: char *argv[]; ! 116: { ! 117: register char *ap; ! 118: register int es; ! 119: ! 120: setbuf(stdout, obuf); ! 121: ! 122: /* ! 123: * recognize variations on the name "ls" as implying which ! 124: * flags to set by default. ! 125: * basename flags ! 126: * l -l ! 127: * lc -C recognized, but conflicts with COHERENT /bin/lc ! 128: * lf -CF ! 129: * lr -CR ! 130: * lx -x ! 131: */ ! 132: if ((ap = strrchr(argv[0], '/')) == NULL) ! 133: ap = argv[0]; ! 134: else ! 135: ++ap; ! 136: if (streq(ap, "l")) ! 137: lflag = 1; ! 138: else if (streq(ap, "lc")) ! 139: Cflag = 1; ! 140: else if (streq(ap, "lf")) ! 141: Cflag = Fflag = 1; ! 142: else if (streq(ap, "lr")) ! 143: Cflag = Rflag = 1; ! 144: else if (streq(ap, "lx")) ! 145: xflag = 1; ! 146: ! 147: while (argc>1 && *argv[1]=='-') { ! 148: for (ap=&argv[1][1]; *ap; ap++) ! 149: switch (*ap) { ! 150: case 'a': ! 151: aflag = 1; ! 152: break; ! 153: ! 154: case 'b': ! 155: bflag = 1; ! 156: break; ! 157: ! 158: case 'c': ! 159: tflag = CTIME; ! 160: break; ! 161: ! 162: case 'C': ! 163: EXCLUDE_Clmnox; ! 164: Cflag = 1; ! 165: break; ! 166: ! 167: case 'd': ! 168: dflag = 1; ! 169: break; ! 170: ! 171: case 'F': ! 172: Fflag = 1; ! 173: break; ! 174: ! 175: case 'f': ! 176: aflag = fflag = 1; ! 177: break; ! 178: ! 179: case 'g': ! 180: gflag = 1; ! 181: break; ! 182: ! 183: case 'i': ! 184: iflag = 1; ! 185: break; ! 186: ! 187: case 'l': ! 188: EXCLUDE_Clmnox; ! 189: lflag = 1; ! 190: break; ! 191: ! 192: case 'm': ! 193: EXCLUDE_Clmnox; ! 194: mflag = 1; ! 195: break; ! 196: ! 197: case 'n': ! 198: EXCLUDE_Clmnox; ! 199: nflag = 1; ! 200: break; ! 201: ! 202: case 'o': ! 203: EXCLUDE_Clmnox; ! 204: oflag = 1; ! 205: break; ! 206: ! 207: case 'p': ! 208: pflag = 1; ! 209: break; ! 210: ! 211: case 'q': ! 212: qflag = 1; ! 213: break; ! 214: ! 215: case 'r': ! 216: rflag = 1; ! 217: break; ! 218: ! 219: case 'R': ! 220: Rflag = 1; ! 221: break; ! 222: ! 223: case 's': ! 224: sflag = 1; ! 225: break; ! 226: ! 227: case 't': ! 228: sortflg = 1; ! 229: break; ! 230: ! 231: case 'u': ! 232: tflag = ATIME; ! 233: break; ! 234: ! 235: case 'x': ! 236: EXCLUDE_Clmnox; ! 237: xflag = 1; ! 238: break; ! 239: ! 240: default: ! 241: usage(); ! 242: } ! 243: argc--; ! 244: argv++; ! 245: } ! 246: if (fflag) ! 247: lflag = sflag = 0; ! 248: time(&curtime); ! 249: myuid = getuid(); ! 250: qcomp = (sortflg) ? qtcomp : qncomp; ! 251: es = (argc > 1) ? ls(argv+1, argc-1) : ls(deflist, 1); ! 252: exit(es); ! 253: } ! 254: ! 255: /* ! 256: * Do 'ls' on one file or directory. ! 257: * 'narg' is the number of names in 'flist' ! 258: * to determine special output format. ! 259: */ ! 260: ls(flist, narg) ! 261: register char **flist; ! 262: int narg; ! 263: { ! 264: register int estat = 0; ! 265: register LS *lsp; ! 266: register LS *arena; ! 267: LS *asavep; ! 268: int Cargs = 0; ! 269: struct stat sb; ! 270: ! 271: arena = (LS *)alloc(narg*sizeof(LS),"arena"); ! 272: asavep = arena; ! 273: for ( ; *flist!=NULL; flist++) { ! 274: if (stat(*flist, &sb) < 0) { ! 275: perror(*flist); ! 276: estat = 1; ! 277: continue; ! 278: } ! 279: astore(*flist, &sb, asavep++); ! 280: } ! 281: qsort(arena, asavep-arena, sizeof(LS), qcomp); ! 282: if (qcomp == qncomp) ! 283: qcomp = qdncomp; ! 284: if (xflag || Cflag) ! 285: ncols = MAXLEN/(maxwidth+GAP); ! 286: ! 287: for (lsp = arena; lsp < asavep; lsp++) { ! 288: if (fflag) ! 289: continue; ! 290: if ((lsp->ls_mode & S_IFMT) == S_IFDIR && !dflag) ! 291: continue; ! 292: if (Cflag) ! 293: svname(lsp->ck_name,Cargs++); ! 294: else if (xflag) ! 295: prcolh(lsp->ck_name); ! 296: else ! 297: prstuff(lsp->ls_name, lsp); ! 298: } ! 299: if (Cflag && Cargs) ! 300: prnames(Cargs); ! 301: maxwidth = MAXWID; ! 302: linesiz = 0; ! 303: for (lsp = arena; lsp < asavep; lsp++) { ! 304: if (dflag || (lsp->ls_mode&S_IFMT)!=S_IFDIR) ! 305: continue; ! 306: if (narg > 1) ! 307: printf("\n%s:\n", lsp->ls_name); ! 308: lsdir(lsp->ls_name,lsp->ls_size); ! 309: freename(lsp); ! 310: } ! 311: free(arena); ! 312: if ((mflag && linesiz) || ((Cflag || xflag) && ccol)){ ! 313: putchar('\n'); ! 314: ccol = 0; ! 315: linesiz = 0; ! 316: } ! 317: return estat; ! 318: } ! 319: ! 320: /* ! 321: * Print for all options except -C and -x ! 322: */ ! 323: prstuff(file, lsp) ! 324: char *file; ! 325: register LS *lsp; ! 326: { ! 327: register char *cp; ! 328: register spcl = 0; ! 329: ! 330: if (iflag) ! 331: printf("%5u ", lsp->ls_ino); ! 332: if (sflag) { ! 333: prsize(lsp); ! 334: putchar(' '); ! 335: } ! 336: if (lflag || oflag || nflag) { ! 337: switch (lsp->ls_mode & S_IFMT) { ! 338: case S_IFREG: ! 339: putchar('-'); ! 340: break; ! 341: ! 342: case S_IFDIR: ! 343: putchar('d'); ! 344: break; ! 345: ! 346: case S_IFCHR: ! 347: putchar('c'); ! 348: spcl++; ! 349: break; ! 350: ! 351: case S_IFBLK: ! 352: putchar('b'); ! 353: spcl++; ! 354: break; ! 355: ! 356: case S_IFPIP: ! 357: putchar('p'); ! 358: break; ! 359: ! 360: case S_IFMPB: ! 361: case S_IFMPC: ! 362: putchar('m'); ! 363: spcl++; ! 364: break; ! 365: ! 366: default: ! 367: putchar('x'); ! 368: } ! 369: prmode((lsp->ls_mode>>6)&07, lsp->ls_mode&S_ISUID); ! 370: prmode((lsp->ls_mode>>3)&07, lsp->ls_mode&S_ISGID); ! 371: prmode(lsp->ls_mode&07, 0); ! 372: if (lsp->ls_mode & S_ISVTX) ! 373: putchar('t'); ! 374: else ! 375: putchar(' '); ! 376: printf("%2d ", lsp->ls_nlink); ! 377: if (!gflag){ ! 378: if (!nflag){ ! 379: cp = getuname(lsp->ls_uid); ! 380: if (cp == NULL) ! 381: printf("%-10d ", lsp->ls_uid); ! 382: else ! 383: printf("%-10s ", cp); ! 384: } else ! 385: printf("%-10d ", lsp->ls_uid); ! 386: } ! 387: if (!oflag){ ! 388: if (!nflag){ ! 389: cp = getgname(lsp->ls_gid); ! 390: if (cp == NULL) ! 391: printf("%-10d ", lsp->ls_gid); ! 392: else ! 393: printf("%-10s ", cp); ! 394: } else ! 395: printf("%-10d ", lsp->ls_gid); ! 396: } ! 397: if (!spcl) ! 398: printf("%7ld", lsp->ls_size); ! 399: else ! 400: printf("%3d %3d", major(lsp->ls_rdev), ! 401: minor(lsp->ls_rdev)); ! 402: prtime(&lsp->ls_time); ! 403: } ! 404: if (!mflag ){ ! 405: prname(file); ! 406: prflag(lsp->ls_mode); ! 407: putchar('\n'); ! 408: } ! 409: else ! 410: prstream(file,lsp->ls_mode); ! 411: } ! 412: ! 413: /* ! 414: * Print out a filesize from a ls store buffer. ! 415: * This size (in BSIZE units or blocks) takes ! 416: * into account indirect blocks. ! 417: * However this should be done in a more general manner. ! 418: */ ! 419: prsize(lsp) ! 420: register LS *lsp; ! 421: { ! 422: long blocks, size; ! 423: register ftype; ! 424: ! 425: size = 0; ! 426: ftype = lsp->ls_mode & S_IFMT; ! 427: if (ftype==S_IFREG || ftype==S_IFDIR || ftype==S_IFPIP) { ! 428: size = blocks = (lsp->ls_size+BSIZE-1)/BSIZE; ! 429: if (blocks > ND) { ! 430: size++; ! 431: blocks -= ND; ! 432: if (blocks > NBN*NI) { ! 433: blocks -= NBN*NI; ! 434: size += 2 + blocks/NBN; ! 435: } ! 436: } ! 437: } ! 438: printf("%4ld", size); ! 439: return size; ! 440: } ! 441: ! 442: /* ! 443: * Print a time (if it is older than ! 444: * one year) print the year instead ! 445: * of the mm:ss part. ! 446: */ ! 447: prtime(tp) ! 448: register time_t *tp; ! 449: { ! 450: register struct tm *tmp; ! 451: register struct tm *now; ! 452: register int thisyear; ! 453: register char *cp; ! 454: ! 455: now = localtime(&curtime); ! 456: thisyear = now->tm_year; ! 457: cp = asctime(tmp = localtime(tp)); ! 458: if (thisyear > tmp->tm_year) { ! 459: cp[10] = '\0'; ! 460: printf(" %s %d ", cp, tmp->tm_year+1900); ! 461: } else { ! 462: cp[16] = '\0'; ! 463: printf(" %s ", cp); ! 464: } ! 465: } ! 466: ! 467: /* ! 468: * Print 'rwx' type modes out. ! 469: */ ! 470: prmode(m, suid) ! 471: int m; ! 472: int suid; ! 473: { ! 474: m <<= 6; ! 475: putchar(m&S_IREAD ? 'r' : '-'); ! 476: putchar(m&S_IWRITE ? 'w' : '-'); ! 477: if (suid) ! 478: putchar('s'); ! 479: else ! 480: putchar(m&S_IEXEC ? 'x' : '-'); ! 481: } ! 482: ! 483: /* ! 484: * Get a user name. Either look ! 485: * in password or group file depending ! 486: * on 'gflag'. ! 487: */ ! 488: char * ! 489: getuname(uid) ! 490: short uid; ! 491: { ! 492: register struct passwd *pwp; ! 493: static id = -1; ! 494: static char *name; ! 495: ! 496: if (uid == id) ! 497: return name; ! 498: id = uid; ! 499: name = NULL; ! 500: if ((pwp=getpwuid( uid)) != NULL) ! 501: name = pwp->pw_name; ! 502: return name; ! 503: } ! 504: ! 505: /* ! 506: * Get group name. ! 507: * Look in group file . ! 508: */ ! 509: char * ! 510: getgname(uid) ! 511: short uid; ! 512: { ! 513: register struct group *grp; ! 514: static id = -1; ! 515: static char *name; ! 516: ! 517: if (uid == id) ! 518: return name; ! 519: id = uid; ! 520: name = NULL; ! 521: if ((grp=getgrgid( uid)) != NULL) ! 522: name = grp->gr_name; ! 523: return name; ! 524: } ! 525: ! 526: /* ! 527: * List out the files in a directory ! 528: * If 'fflag' is set, it may not be ! 529: * but consider it one anyway. ! 530: */ ! 531: lsdir(dir,dirsize) ! 532: char *dir; ! 533: fsize_t dirsize; ! 534: { ! 535: int fd, Cargs = 0, Rargs = 0; ! 536: struct stat sb; ! 537: LS *lsp; ! 538: register char *np1, *np2; ! 539: register int n; ! 540: register struct direct *dp; ! 541: register int nb; ! 542: unsigned size; ! 543: char *curname; ! 544: char *namebuf; /* Buffer for constructing names */ ! 545: char *dirbuf; /* Buffer for reading directories */ ! 546: DLIST **dirlist; ! 547: LS *dsaved; ! 548: LS *dsavep; ! 549: ! 550: if ((fd = open(dir, 0)) < 0) { ! 551: fprintf(stderr, "%s: cannot read\n", dir); ! 552: return; ! 553: } ! 554: if (!fflag) { ! 555: size = dirsize/sizeof (struct direct) * sizeof (LS); ! 556: dsaved = alloc(size,"dsaved"); ! 557: dsavep = dsaved; ! 558: } ! 559: if (Rflag) ! 560: dirlist = (char **)alloc(MAXDIR * sizeof(char *), "dirlist"); ! 561: dirbuf = alloc(BSIZE,"dirbuf"); ! 562: namebuf = alloc(MAXNBUF,"namebuf"); ! 563: curname = alloc(DIRSIZ+1,"curname"); ! 564: lsp = alloc(sizeof(LS),"lsp"); ! 565: if (mflag) ! 566: first = 1; /* For stream option */ ! 567: while ((nb = read(fd, dirbuf, BSIZE )) > 0) ! 568: for (dp=dirbuf; dp<(dirbuf+nb); dp++) { ! 569: if (dp->d_ino == 0) ! 570: continue; ! 571: np1 = dp->d_name; ! 572: if (aflag == 0 && *np1++ == '.') { ! 573: if (myuid != 0) ! 574: continue; ! 575: if (*np1=='\0' || (*np1++=='.' && *np1=='\0')) ! 576: continue; ! 577: } ! 578: if (iflag) { ! 579: sb.st_ino = dp->d_ino; ! 580: canino(sb.st_ino); ! 581: } ! 582: np2 = curname; ! 583: np1 = dp->d_name; ! 584: n = DIRSIZ; ! 585: do { ! 586: *np2++ = *np1++; ! 587: } while (--n); ! 588: *np2 = '\0'; ! 589: if (lflag || xflag || Cflag || sflag || tflag || Rflag || ! 590: sortflg || pflag || Fflag || oflag || nflag) { ! 591: np2 = namebuf; ! 592: np1 = dir; ! 593: while (*np2++ = *np1++) ! 594: ; ! 595: np2-=2; ! 596: if (*np2++ != '/') ! 597: *np2++ = '/'; ! 598: np1 = curname; ! 599: while (*np2++ = *np1++) ! 600: ; ! 601: if (stat(namebuf, &sb) < 0) { ! 602: fprintf(stderr, "%s: cannot stat\n", curname); ! 603: continue; ! 604: } ! 605: } ! 606: convert(&sb, lsp); ! 607: if (Rflag ! 608: && ((lsp->ls_mode & S_IFMT) == S_IFDIR) ! 609: && strcmp(curname, ".") != 0 ! 610: && strcmp(curname, "..") != 0 ) { ! 611: if (Rargs >= MAXDIR) ! 612: fatal("too many subdirectories"); ! 613: dirlist[Rargs] = alloc(sizeof(DLIST),"dirlist"); ! 614: dirlist[Rargs]->name = alloc(strlen(namebuf) + 1,"name"); ! 615: strcpy(dirlist[Rargs]->name,namebuf); ! 616: dirlist[Rargs++]->size = lsp->ls_size; ! 617: } else if (fflag) { ! 618: ncols = MAXLEN/(maxwidth+GAP); ! 619: if (Cflag) ! 620: svname(curname, Cargs++); ! 621: else if (xflag) ! 622: prcolh(curname); ! 623: else ! 624: prstuff(curname, lsp); ! 625: } else { ! 626: store(curname, &sb,dsavep++); ! 627: } ! 628: } ! 629: free(lsp); ! 630: free(curname); ! 631: free(namebuf); ! 632: free(dirbuf); ! 633: if (!fflag) { ! 634: ncols = MAXLEN/(maxwidth+GAP); ! 635: output(dsaved,dsavep); ! 636: } else if (Cflag && Cargs) ! 637: prnames(Cargs); ! 638: if (!fflag) ! 639: for (lsp = dsaved; lsp < dsavep; lsp++) ! 640: freename(lsp); ! 641: if ((mflag && linesiz) || ((Cflag || xflag) && ccol)){ ! 642: putchar('\n'); ! 643: ccol = 0; ! 644: linesiz = 0; ! 645: } ! 646: if (!fflag) ! 647: free(dsaved); ! 648: close(fd); ! 649: maxwidth = MAXWID; ! 650: if (Rflag && Rargs){ ! 651: for(n=0;n<Rargs;n++){ ! 652: putchar('\n'); ! 653: printf("%s:\n",dirlist[n]->name); ! 654: lsdir(dirlist[n]->name,dirlist[n]->size); ! 655: free(dirlist[n]->name); ! 656: } ! 657: for(n=0;n<Rargs;n++) ! 658: free(dirlist[n]); ! 659: } ! 660: if (Rflag) ! 661: free(dirlist); ! 662: } ! 663: ! 664: /* ! 665: * Store data away for intra-directory ! 666: * sorting. ! 667: */ ! 668: store(name, sbp,lsp) ! 669: char *name; ! 670: register struct stat *sbp; ! 671: register LS *lsp; ! 672: { ! 673: convert(sbp, lsp); ! 674: if (xflag || Cflag) ! 675: cstore(lsp,name); ! 676: strncpy(lsp->ls_dname, name, DIRSIZ+1); ! 677: } ! 678: ! 679: /* ! 680: * Store each argument away for inter-directory sorting. ! 681: * Sets lsp->ls_name to allocated name. ! 682: */ ! 683: astore(name, sbp,lsp) ! 684: char *name; ! 685: register struct stat *sbp; ! 686: register LS *lsp; ! 687: { ! 688: convert(sbp, lsp); ! 689: if (xflag || Cflag) ! 690: cstore(lsp,name); ! 691: lsp->ls_name = alloc(strlen(name)+1,"ls->name"); ! 692: strcpy(lsp->ls_name, name); ! 693: } ! 694: ! 695: /* ! 696: * Free allocated name fields. ! 697: */ ! 698: freename(lsp) register LS *lsp; ! 699: { ! 700: if (lsp->ls_name != NULL) ! 701: free(lsp->ls_name); ! 702: if (lsp->ck_name != NULL) ! 703: free(lsp->ck_name); ! 704: } ! 705: ! 706: /* ! 707: * Convert a stat buffer into an ls store ! 708: * buffer. ! 709: */ ! 710: convert(sbp, lsp) ! 711: register struct stat *sbp; ! 712: register LS *lsp; ! 713: { ! 714: lsp->ls_ino = sbp->st_ino; ! 715: lsp->ls_mode = sbp->st_mode; ! 716: lsp->ls_nlink = sbp->st_nlink; ! 717: lsp->ls_uid = sbp->st_uid; ! 718: lsp->ls_gid = sbp->st_gid; ! 719: lsp->ls_size = sbp->st_size; ! 720: lsp->ls_rdev = sbp->st_rdev; ! 721: if (tflag == CTIME) ! 722: lsp->ls_time = sbp->st_ctime; ! 723: else if (tflag == MTIME) ! 724: lsp->ls_time = sbp->st_mtime; ! 725: else if (tflag == ATIME) ! 726: lsp->ls_time = sbp->st_atime; ! 727: } ! 728: ! 729: /* ! 730: * Sort, output and free up space from ! 731: * the current directory being considered. ! 732: */ ! 733: output(start,stop) ! 734: LS *start; ! 735: LS *stop; ! 736: { ! 737: register LS *lsp, *lse; ! 738: register unsigned nel; ! 739: int Cargs = 0; ! 740: nel = stop - start; ! 741: qsort(start, nel, sizeof (LS), qcomp); ! 742: for (lsp=start, lse=stop; lsp < lse; lsp++){ ! 743: if (Cflag) ! 744: svname(lsp->ck_name,Cargs++); ! 745: else if (xflag) ! 746: prcolh(lsp->ck_name); ! 747: else ! 748: prstuff(lsp->ls_dname, lsp); ! 749: } ! 750: if (Cflag && Cargs) ! 751: prnames(Cargs); ! 752: } ! 753: ! 754: /* ! 755: * The following are the three qsort comparison routines: ! 756: * sort by time, sort by directory name, sort by full pathname. ! 757: * They can be used both in the argument sort and in each directory sort. ! 758: */ ! 759: ! 760: /* ! 761: * Sort by time (either access, modify, or create setup elsewhere) ! 762: * (forward or backward). ! 763: */ ! 764: qtcomp(lsp1, lsp2) ! 765: register LS *lsp1, *lsp2; ! 766: { ! 767: register int rval = 0; ! 768: ! 769: if (lsp1->ls_time < lsp2->ls_time) ! 770: rval++; ! 771: else if (lsp1->ls_time > lsp2->ls_time) ! 772: rval--; ! 773: return (rflag) ? -rval : rval; ! 774: } ! 775: ! 776: /* ! 777: * Sort by directory name. ! 778: * (forward or reverse). ! 779: */ ! 780: qdncomp(lsp1, lsp2) ! 781: LS *lsp1, *lsp2; ! 782: { ! 783: register int rval; ! 784: ! 785: rval = strncmp(lsp1->ls_dname, lsp2->ls_dname, DIRSIZ); ! 786: return (rflag) ? -rval : rval; ! 787: } ! 788: ! 789: /* ! 790: * Sort by full pathname. ! 791: * (forward or reverse). ! 792: */ ! 793: qncomp(lsp1, lsp2) ! 794: LS *lsp1, *lsp2; ! 795: { ! 796: register int rval; ! 797: ! 798: rval = strcmp(lsp1->ls_name, lsp2->ls_name); ! 799: return (rflag) ? -rval : rval; ! 800: } ! 801: ! 802: usage() ! 803: { ! 804: fprintf(stderr, "Usage: ls [-abcCdfFgilmnopqrRstux] [files ...]\n"); ! 805: exit(1); ! 806: } ! 807: ! 808: is_x(m) ! 809: int m; ! 810: { ! 811: m <<= 6; ! 812: return m&S_IEXEC; ! 813: } ! 814: ! 815: /* ! 816: * Print non-graphic chars in octal or '?' format ! 817: * or as they are depending on which flag is set. ! 818: */ ! 819: prname(s) ! 820: char *s; ! 821: { ! 822: if (bflag) { ! 823: while ( *s != '\0') ! 824: if ( *s >= ' ' && *s <= '~') ! 825: putchar(*s++); ! 826: else ! 827: printf("\\0%o",*s++); ! 828: } else if (qflag) { ! 829: while ( *s != '\0') ! 830: if ( *s >= ' ' && *s <= '~') ! 831: putchar(*s++); ! 832: else { ! 833: putchar('?'); ! 834: *s++; ! 835: } ! 836: } else ! 837: printf(s); ! 838: } ! 839: ! 840: /* ! 841: * Print in stream format for -m option ! 842: */ ! 843: prstream(s,m) ! 844: char *s; ! 845: short m; ! 846: { ! 847: register int sl; ! 848: ! 849: sl = strlen(s); ! 850: if ( (linesiz + sl) > MAXLEN ){ ! 851: putchar(','); ! 852: putchar('\n'); ! 853: prname(s); ! 854: linesiz = sl + prflag(m) + 1; ! 855: } ! 856: else if (!first) { ! 857: printf(", "); ! 858: prname(s); ! 859: linesiz += sl + prflag(m) + 2; ! 860: } else { ! 861: first = 0; ! 862: prname(s); ! 863: linesiz = sl + prflag(m); ! 864: } ! 865: } ! 866: ! 867: /* ! 868: * Prints flag if executable or directory and -F or -p flsg is set. ! 869: */ ! 870: prflag(m) ! 871: short m; ! 872: { ! 873: if (pflag) ! 874: if((m & S_IFMT) == S_IFDIR){ ! 875: putchar('/'); ! 876: return 1; ! 877: } ! 878: if (Fflag) { ! 879: if((m & S_IFMT) == S_IFDIR) { ! 880: putchar('/'); ! 881: return 1; ! 882: } else if (is_x(m>>6 & 07) ) { ! 883: putchar('*'); ! 884: return 1; ! 885: } else if( is_x(m>>3 & 07) ) { ! 886: putchar('*'); ! 887: return 1; ! 888: } else if( is_x(m & 07) ){ ! 889: putchar('*'); ! 890: return 1; ! 891: } ! 892: } ! 893: return 0; ! 894: } ! 895: ! 896: /* ! 897: * Returns flag if executable or directory and -F or -p flsg is set. ! 898: */ ! 899: char * ! 900: getflag(m) ! 901: short m; ! 902: { ! 903: if (pflag) { ! 904: if((m & S_IFMT) == S_IFDIR) ! 905: return "/"; ! 906: } ! 907: if (Fflag) { ! 908: if((m & S_IFMT) == S_IFDIR) ! 909: return "/"; ! 910: else if( is_x(m>>6 & 07) ) ! 911: return "*"; ! 912: else if( is_x(m>>3 & 07) ) ! 913: return "*"; ! 914: else if( is_x(m & 07) ) ! 915: return "*"; ! 916: } ! 917: return ""; ! 918: } ! 919: ! 920: /* ! 921: * Returns file name with non-graphic chars in octal or '?' format ! 922: * or as they are depending on which flag is set. ! 923: */ ! 924: char * ! 925: getname(s) ! 926: char *s; ! 927: { ! 928: char tmp[80]; ! 929: char *t; ! 930: int i = 0; ! 931: char buf[5]; ! 932: ! 933: t = tmp; ! 934: if (bflag){ ! 935: while (*s) { ! 936: if (*s >= ' ' && *s <= '~') { ! 937: *t++ = *s++; ! 938: } else { ! 939: sprintf(buf,"\\0%o",*s++); ! 940: while(buf[i] != '\0'){ ! 941: *t++ = buf[i]; ! 942: buf[i++] = '\0'; ! 943: } ! 944: i=0; ! 945: } ! 946: } ! 947: *t = '\0'; ! 948: } else if (qflag){ ! 949: while ( *s != '\0') ! 950: if ( *s >= ' ' && *s <= '~') ! 951: *t++ = *s++; ! 952: else{ ! 953: *t++ = '?'; ! 954: *s++; ! 955: } ! 956: *t = '\0'; ! 957: } else ! 958: strcpy(tmp,s); ! 959: return tmp; ! 960: } ! 961: ! 962: /* ! 963: * Prints name in multi-column format across the screen (-x option). ! 964: */ ! 965: prcolh(name) ! 966: char *name; ! 967: { ! 968: if ( ccol < ncols) ! 969: printf(name); ! 970: if ( ++ccol < ncols) ! 971: printf("%*s",maxwidth - strlen(name) + GAP,""); ! 972: else { ! 973: ccol = 0; ! 974: putchar('\n'); ! 975: } ! 976: } ! 977: ! 978: /* ! 979: * Sets chars in buffer to NULs. ! 980: */ ! 981: clear(s) ! 982: char *s; ! 983: { ! 984: while (*s != '\0') ! 985: *s++ = '\0'; ! 986: } ! 987: ! 988: /* ! 989: * Adds whatever information to file name as indicated by flags ! 990: * (i.e. iflag, sflag, bflag) and stores it in ck_name so its ! 991: * entire length can be recorded. Used for -x and -C. ! 992: * Sets lsp->ls_name to allocated name. ! 993: */ ! 994: cstore(lsp, name) ! 995: LS *lsp; ! 996: char *name; ! 997: { ! 998: register int sl; ! 999: char buf[80],tmp[80],tmp2[80]; ! 1000: ! 1001: clear(buf); clear(tmp); clear(tmp2); ! 1002: if ( sflag) ! 1003: sprintf(buf,"%3d",getsize(lsp)); ! 1004: if (iflag){ ! 1005: sprintf(tmp,"%5u ", lsp->ls_ino); ! 1006: strcat(buf,tmp); ! 1007: } ! 1008: strcpy(tmp2,getname(name)); ! 1009: strcat(buf,tmp2); ! 1010: if ( Fflag || pflag) ! 1011: strcat(buf,getflag(lsp->ls_mode)); ! 1012: sl = strlen(buf); ! 1013: if (maxwidth < sl) ! 1014: maxwidth = sl; ! 1015: lsp->ck_name = alloc(sl+1, "ck_name"); ! 1016: strcpy(lsp->ck_name,buf); ! 1017: } ! 1018: ! 1019: /* ! 1020: * Returns size of file. see prsize. ! 1021: */ ! 1022: getsize(lsp) ! 1023: register LS *lsp; ! 1024: { ! 1025: long blocks, size; ! 1026: register ftype; ! 1027: ! 1028: size = 0; ! 1029: ftype = lsp->ls_mode & S_IFMT; ! 1030: if (ftype==S_IFREG || ftype==S_IFDIR || ftype==S_IFPIP) { ! 1031: size = blocks = (lsp->ls_size+BSIZE-1)/BSIZE; ! 1032: if (blocks > ND) { ! 1033: size++; ! 1034: blocks -= ND; ! 1035: if (blocks > NBN*NI) { ! 1036: blocks -= NBN*NI; ! 1037: size += 2 + blocks/NBN; ! 1038: } ! 1039: } ! 1040: } ! 1041: return size; ! 1042: } ! 1043: ! 1044: /* ! 1045: * Save file name for -C option. ! 1046: * This allocates namelist[i], prnames() eventually frees it. ! 1047: */ ! 1048: svname(name,i) ! 1049: char *name; ! 1050: int i; ! 1051: { ! 1052: if (i >= MAXARG) ! 1053: fatal("more than %d files with -C option", MAXARG); ! 1054: namelist[i] = alloc(strlen(name)+1,"svname"); ! 1055: strcpy(namelist[i],name); ! 1056: } ! 1057: ! 1058: /* ! 1059: * Print names in multi-column format going down the screen (-C option). ! 1060: * Free the namelist members allocated by svname. ! 1061: */ ! 1062: prnames(Cargs) ! 1063: int Cargs; ! 1064: { ! 1065: register int nc, i, j, nl; ! 1066: ! 1067: ncols = MAXLEN/(maxwidth+GAP); ! 1068: nc = ncols; ! 1069: nlast = Cargs % ncols; ! 1070: nrows = Cargs/ncols + (nlast ? 1 : 0); ! 1071: offset = nrows -1; ! 1072: ! 1073: if (nlast == 0) ! 1074: nlast = ncols; ! 1075: nl = nlast; ! 1076: for(i=0; i < offset; i++){ ! 1077: for(j = i; j < Cargs;j+=offset+ (nl-- >0) ) ! 1078: prcolh(namelist[j]); ! 1079: nl = nlast; ! 1080: } ! 1081: while (nlast--){ ! 1082: prcolh(namelist[i]); ! 1083: i += nrows; ! 1084: } ! 1085: if (ccol){ ! 1086: putchar('\n'); ! 1087: ccol = 0; ! 1088: } ! 1089: for (i = 0; i < Cargs; i++) ! 1090: free(namelist[i]); ! 1091: } ! 1092: ! 1093: /* ! 1094: * Put message and die. ! 1095: */ ! 1096: /* VARARGS */ ! 1097: void ! 1098: fatal(s) char *s; ! 1099: { ! 1100: fprintf(stderr, "\nls: fatal: %r\n", &s); ! 1101: exit(1); ! 1102: } ! 1103: ! 1104: /* ! 1105: * Get space or die. ! 1106: */ ! 1107: char * ! 1108: alloc(n, msg) register int n; char *msg; ! 1109: { ! 1110: extern char *calloc(); ! 1111: register char *cp; ! 1112: ! 1113: if ((cp = calloc(n, 1)) == NULL) ! 1114: fatal("out of space: %s", msg); ! 1115: return cp; ! 1116: } ! 1117: ! 1118: /* end of ls.c */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.