Annotation of 43BSDReno/bin/ls/ls.c, revision 1.1.1.1

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.