|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1989 The Regents of the University of California. ! 3: * All rights reserved. ! 4: * ! 5: * This code is derived from software contributed to Berkeley by ! 6: * Michael Fischbein. ! 7: * ! 8: * Redistribution and use in source and binary forms are permitted ! 9: * provided that: (1) source distributions retain this entire copyright ! 10: * notice and comment, and (2) distributions including binaries display ! 11: * the following acknowledgement: ``This product includes software ! 12: * developed by the University of California, Berkeley and its contributors'' ! 13: * in the documentation or other materials provided with the distribution ! 14: * and in all advertising materials mentioning features or use of this ! 15: * software. Neither the name of the University nor the names of its ! 16: * contributors may be used to endorse or promote products derived ! 17: * from this software without specific prior written permission. ! 18: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR ! 19: * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED ! 20: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. ! 21: */ ! 22: ! 23: #ifndef lint ! 24: char copyright[] = ! 25: "@(#) Copyright (c) 1989 The Regents of the University of California.\n\ ! 26: All rights reserved.\n"; ! 27: #endif /* not lint */ ! 28: ! 29: #ifndef lint ! 30: static char sccsid[] = "@(#)ls.c 5.42 (Berkeley) 5/17/90"; ! 31: #endif /* not lint */ ! 32: ! 33: #include <sys/param.h> ! 34: #include <sys/stat.h> ! 35: #include <sys/ioctl.h> ! 36: #include <dirent.h> ! 37: #include <string.h> ! 38: #include <errno.h> ! 39: #include <stdio.h> ! 40: #include "ls.h" ! 41: ! 42: int (*sortfcn)(), (*printfcn)(); ! 43: int lstat(); ! 44: char *emalloc(); ! 45: ! 46: int termwidth = 80; /* default terminal width */ ! 47: ! 48: /* flags */ ! 49: int f_accesstime; /* use time of last access */ ! 50: int f_column; /* columnated format */ ! 51: int f_group; /* show group ownership of a file */ ! 52: int f_ignorelink; /* indirect through symbolic link operands */ ! 53: int f_inode; /* print inode */ ! 54: int f_kblocks; /* print size in kilobytes */ ! 55: int f_listalldot; /* list . and .. as well */ ! 56: int f_listdir; /* list actual directory, not contents */ ! 57: int f_listdot; /* list files beginning with . */ ! 58: int f_longform; /* long listing format */ ! 59: int f_needstat; /* if need to stat files */ ! 60: int f_newline; /* if precede with newline */ ! 61: int f_nonprint; /* show unprintables as ? */ ! 62: int f_nosort; /* don't sort output */ ! 63: int f_recursive; /* ls subdirectories also */ ! 64: int f_reversesort; /* reverse whatever sort is used */ ! 65: int f_singlecol; /* use single column output */ ! 66: int f_size; /* list size in short listing */ ! 67: int f_statustime; /* use time of last mode change */ ! 68: int f_dirname; /* if precede with directory name */ ! 69: int f_timesort; /* sort by time vice name */ ! 70: int f_total; /* if precede with "total" line */ ! 71: int f_type; /* add type character for non-regular files */ ! 72: ! 73: main(argc, argv) ! 74: int argc; ! 75: char **argv; ! 76: { ! 77: extern int optind, stat(); ! 78: struct winsize win; ! 79: int ch; ! 80: char *p, *getenv(); ! 81: int acccmp(), modcmp(), namecmp(), prcopy(), printcol(); ! 82: int printlong(), printscol(), revacccmp(), revmodcmp(), revnamecmp(); ! 83: int revstatcmp(), statcmp(); ! 84: ! 85: /* terminal defaults to -Cq, non-terminal defaults to -1 */ ! 86: if (isatty(1)) { ! 87: f_nonprint = 1; ! 88: if (ioctl(1, TIOCGWINSZ, &win) == -1 || !win.ws_col) { ! 89: if (p = getenv("COLUMNS")) ! 90: termwidth = atoi(p); ! 91: } ! 92: else ! 93: termwidth = win.ws_col; ! 94: f_column = 1; ! 95: } else ! 96: f_singlecol = 1; ! 97: ! 98: /* root is -A automatically */ ! 99: if (!getuid()) ! 100: f_listdot = 1; ! 101: ! 102: while ((ch = getopt(argc, argv, "1ACFLRacdfgiklqrstu")) != EOF) { ! 103: switch (ch) { ! 104: /* ! 105: * -1, -C and -l all override each other ! 106: * so shell aliasing works right ! 107: */ ! 108: case '1': ! 109: f_singlecol = 1; ! 110: f_column = f_longform = 0; ! 111: break; ! 112: case 'C': ! 113: f_column = 1; ! 114: f_longform = f_singlecol = 0; ! 115: break; ! 116: case 'l': ! 117: f_longform = 1; ! 118: f_column = f_singlecol = 0; ! 119: break; ! 120: /* -c and -u override each other */ ! 121: case 'c': ! 122: f_statustime = 1; ! 123: f_accesstime = 0; ! 124: break; ! 125: case 'u': ! 126: f_accesstime = 1; ! 127: f_statustime = 0; ! 128: break; ! 129: case 'F': ! 130: f_type = 1; ! 131: break; ! 132: case 'L': ! 133: f_ignorelink = 1; ! 134: break; ! 135: case 'R': ! 136: f_recursive = 1; ! 137: break; ! 138: case 'a': ! 139: f_listalldot = 1; ! 140: /* FALLTHROUGH */ ! 141: case 'A': ! 142: f_listdot = 1; ! 143: break; ! 144: case 'd': ! 145: f_listdir = 1; ! 146: break; ! 147: case 'f': ! 148: f_nosort = 1; ! 149: break; ! 150: case 'g': ! 151: f_group = 1; ! 152: break; ! 153: case 'i': ! 154: f_inode = 1; ! 155: break; ! 156: case 'k': ! 157: f_kblocks = 1; ! 158: break; ! 159: case 'q': ! 160: f_nonprint = 1; ! 161: break; ! 162: case 'r': ! 163: f_reversesort = 1; ! 164: break; ! 165: case 's': ! 166: f_size = 1; ! 167: break; ! 168: case 't': ! 169: f_timesort = 1; ! 170: break; ! 171: default: ! 172: case '?': ! 173: usage(); ! 174: } ! 175: } ! 176: argc -= optind; ! 177: argv += optind; ! 178: ! 179: /* -d turns off -R */ ! 180: if (f_listdir) ! 181: f_recursive = 0; ! 182: ! 183: /* if need to stat files */ ! 184: f_needstat = f_longform || f_recursive || f_timesort || ! 185: f_size || f_type; ! 186: ! 187: /* select a sort function */ ! 188: if (f_reversesort) { ! 189: if (!f_timesort) ! 190: sortfcn = revnamecmp; ! 191: else if (f_accesstime) ! 192: sortfcn = revacccmp; ! 193: else if (f_statustime) ! 194: sortfcn = revstatcmp; ! 195: else /* use modification time */ ! 196: sortfcn = revmodcmp; ! 197: } else { ! 198: if (!f_timesort) ! 199: sortfcn = namecmp; ! 200: else if (f_accesstime) ! 201: sortfcn = acccmp; ! 202: else if (f_statustime) ! 203: sortfcn = statcmp; ! 204: else /* use modification time */ ! 205: sortfcn = modcmp; ! 206: } ! 207: ! 208: /* select a print function */ ! 209: if (f_singlecol) ! 210: printfcn = printscol; ! 211: else if (f_longform) ! 212: printfcn = printlong; ! 213: else ! 214: printfcn = printcol; ! 215: ! 216: if (!argc) { ! 217: argc = 1; ! 218: argv[0] = "."; ! 219: argv[1] = NULL; ! 220: } ! 221: doargs(argc, argv); ! 222: exit(0); ! 223: } ! 224: ! 225: static char path[MAXPATHLEN + 1]; ! 226: static char *endofpath = path; ! 227: ! 228: doargs(argc, argv) ! 229: int argc; ! 230: char **argv; ! 231: { ! 232: register LS *dstatp, *rstatp; ! 233: register int cnt, dircnt, maxlen, regcnt; ! 234: LS *dstats, *rstats; ! 235: struct stat sb; ! 236: int (*statfcn)(), stat(), lstat(); ! 237: char top[MAXPATHLEN + 1]; ! 238: u_long blocks; ! 239: ! 240: /* ! 241: * walk through the operands, building separate arrays of LS ! 242: * structures for directory and non-directory files. ! 243: */ ! 244: dstats = rstats = NULL; ! 245: statfcn = (f_longform || f_listdir) && !f_ignorelink ? lstat : stat; ! 246: for (dircnt = regcnt = 0; *argv; ++argv) { ! 247: if (statfcn(*argv, &sb)) { ! 248: if (statfcn != stat || lstat(*argv, &sb)) { ! 249: (void)fprintf(stderr, "ls: %s: %s\n", *argv, ! 250: strerror(errno)); ! 251: if (errno == ENOENT) ! 252: continue; ! 253: exit(1); ! 254: } ! 255: } ! 256: if (S_ISDIR(sb.st_mode) && !f_listdir) { ! 257: if (!dstats) ! 258: dstatp = dstats = (LS *)emalloc((u_int)argc * ! 259: (sizeof(LS))); ! 260: dstatp->name = *argv; ! 261: dstatp->lstat = sb; ! 262: ++dstatp; ! 263: ++dircnt; ! 264: } ! 265: else { ! 266: if (!rstats) { ! 267: rstatp = rstats = (LS *)emalloc((u_int)argc * ! 268: (sizeof(LS))); ! 269: blocks = 0; ! 270: maxlen = -1; ! 271: } ! 272: rstatp->name = *argv; ! 273: rstatp->lstat = sb; ! 274: ! 275: /* save name length for -C format */ ! 276: rstatp->len = strlen(*argv); ! 277: ! 278: if (f_nonprint) ! 279: prcopy(*argv, *argv, rstatp->len); ! 280: ! 281: /* calculate number of blocks if -l/-s formats */ ! 282: if (f_longform || f_size) ! 283: blocks += sb.st_blocks; ! 284: ! 285: /* save max length if -C format */ ! 286: if (f_column && maxlen < rstatp->len) ! 287: maxlen = rstatp->len; ! 288: ! 289: ++rstatp; ! 290: ++regcnt; ! 291: } ! 292: } ! 293: /* display regular files */ ! 294: if (regcnt) { ! 295: rstats[0].lstat.st_btotal = blocks; ! 296: rstats[0].lstat.st_maxlen = maxlen; ! 297: displaydir(rstats, regcnt); ! 298: f_newline = f_dirname = 1; ! 299: } ! 300: /* display directories */ ! 301: if (dircnt) { ! 302: register char *p; ! 303: ! 304: f_total = 1; ! 305: if (dircnt > 1) { ! 306: (void)getwd(top); ! 307: qsort((char *)dstats, dircnt, sizeof(LS), sortfcn); ! 308: f_dirname = 1; ! 309: } ! 310: for (cnt = 0; cnt < dircnt; ++dstats) { ! 311: for (endofpath = path, p = dstats->name; ! 312: *endofpath = *p++; ++endofpath); ! 313: subdir(dstats); ! 314: f_newline = 1; ! 315: if (++cnt < dircnt && chdir(top)) { ! 316: (void)fprintf(stderr, "ls: %s: %s\n", ! 317: top, strerror(errno)); ! 318: exit(1); ! 319: } ! 320: } ! 321: } ! 322: } ! 323: ! 324: displaydir(stats, num) ! 325: LS *stats; ! 326: register int num; ! 327: { ! 328: register char *p, *savedpath; ! 329: LS *lp; ! 330: ! 331: if (num > 1 && !f_nosort) { ! 332: u_long save1, save2; ! 333: ! 334: save1 = stats[0].lstat.st_btotal; ! 335: save2 = stats[0].lstat.st_maxlen; ! 336: qsort((char *)stats, num, sizeof(LS), sortfcn); ! 337: stats[0].lstat.st_btotal = save1; ! 338: stats[0].lstat.st_maxlen = save2; ! 339: } ! 340: ! 341: printfcn(stats, num); ! 342: ! 343: if (f_recursive) { ! 344: savedpath = endofpath; ! 345: for (lp = stats; num--; ++lp) { ! 346: if (!S_ISDIR(lp->lstat.st_mode)) ! 347: continue; ! 348: p = lp->name; ! 349: if (p[0] == '.' && (!p[1] || p[1] == '.' && !p[2])) ! 350: continue; ! 351: if (endofpath != path && endofpath[-1] != '/') ! 352: *endofpath++ = '/'; ! 353: for (; *endofpath = *p++; ++endofpath); ! 354: f_newline = f_dirname = f_total = 1; ! 355: subdir(lp); ! 356: *(endofpath = savedpath) = '\0'; ! 357: } ! 358: } ! 359: } ! 360: ! 361: subdir(lp) ! 362: LS *lp; ! 363: { ! 364: LS *stats; ! 365: int num; ! 366: char *names; ! 367: ! 368: if (f_newline) ! 369: (void)putchar('\n'); ! 370: if (f_dirname) ! 371: (void)printf("%s:\n", path); ! 372: ! 373: if (chdir(lp->name)) { ! 374: (void)fprintf(stderr, "ls: %s: %s\n", lp->name, ! 375: strerror(errno)); ! 376: return; ! 377: } ! 378: if (num = tabdir(lp, &stats, &names)) { ! 379: displaydir(stats, num); ! 380: (void)free((char *)stats); ! 381: (void)free((char *)names); ! 382: } ! 383: if (chdir("..")) { ! 384: (void)fprintf(stderr, "ls: ..: %s\n", strerror(errno)); ! 385: exit(1); ! 386: } ! 387: } ! 388: ! 389: tabdir(lp, s_stats, s_names) ! 390: LS *lp, **s_stats; ! 391: char **s_names; ! 392: { ! 393: register DIR *dirp; ! 394: register int cnt, maxentry, maxlen; ! 395: register char *p, *names; ! 396: struct dirent *dp; ! 397: u_long blocks; ! 398: LS *stats; ! 399: ! 400: if (!(dirp = opendir("."))) { ! 401: (void)fprintf(stderr, "ls: %s: %s\n", lp->name, ! 402: strerror(errno)); ! 403: return(0); ! 404: } ! 405: blocks = maxentry = maxlen = 0; ! 406: stats = NULL; ! 407: for (cnt = 0; dp = readdir(dirp);) { ! 408: /* this does -A and -a */ ! 409: p = dp->d_name; ! 410: if (p[0] == '.') { ! 411: if (!f_listdot) ! 412: continue; ! 413: if (!f_listalldot && (!p[1] || p[1] == '.' && !p[2])) ! 414: continue; ! 415: } ! 416: if (cnt == maxentry) { ! 417: if (!maxentry) ! 418: *s_names = names = ! 419: emalloc((u_int)lp->lstat.st_size); ! 420: #define DEFNUM 256 ! 421: maxentry += DEFNUM; ! 422: if (!(*s_stats = stats = (LS *)realloc((char *)stats, ! 423: (u_int)maxentry * sizeof(LS)))) ! 424: nomem(); ! 425: } ! 426: if (f_needstat && lstat(dp->d_name, &stats[cnt].lstat)) { ! 427: /* ! 428: * don't exit -- this could be an NFS mount that has ! 429: * gone away. Flush stdout so the messages line up. ! 430: */ ! 431: (void)fflush(stdout); ! 432: (void)fprintf(stderr, "ls: %s: %s\n", ! 433: dp->d_name, strerror(errno)); ! 434: continue; ! 435: } ! 436: stats[cnt].name = names; ! 437: ! 438: if (f_nonprint) ! 439: prcopy(dp->d_name, names, (int)dp->d_namlen); ! 440: else ! 441: bcopy(dp->d_name, names, (int)dp->d_namlen); ! 442: names += dp->d_namlen; ! 443: *names++ = '\0'; ! 444: ! 445: /* ! 446: * get the inode from the directory, so the -f flag ! 447: * works right. ! 448: */ ! 449: stats[cnt].lstat.st_ino = dp->d_ino; ! 450: ! 451: /* save name length for -C format */ ! 452: stats[cnt].len = dp->d_namlen; ! 453: ! 454: /* calculate number of blocks if -l/-s formats */ ! 455: if (f_longform || f_size) ! 456: blocks += stats[cnt].lstat.st_blocks; ! 457: ! 458: /* save max length if -C format */ ! 459: if (f_column && maxlen < (int)dp->d_namlen) ! 460: maxlen = dp->d_namlen; ! 461: ++cnt; ! 462: } ! 463: (void)closedir(dirp); ! 464: ! 465: if (cnt) { ! 466: stats[0].lstat.st_btotal = blocks; ! 467: stats[0].lstat.st_maxlen = maxlen; ! 468: } else if (stats) { ! 469: (void)free((char *)stats); ! 470: (void)free((char *)names); ! 471: } ! 472: return(cnt); ! 473: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.