Annotation of coherent/d/bin/ls.c, revision 1.1.1.1

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 4096            /* 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 */

unix.superglobalmegacorp.com

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