|
DataMuseum.dkPresents historical artifacts from the history of: Commodore CBM-900 |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about Commodore CBM-900 Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - download
Length: 10540 (0x292c) Types: TextFile Notes: UNIX file Names: »ls.c«
└─⟦f27320a65⟧ Bits:30001972 Commodore 900 hard disk image with partial source code └─⟦f4b8d8c84⟧ UNIX Filesystem └─⟦this⟧ »cmd/ls.c«
/* * List structure */ #include <stdio.h> #include <canon.h> #include <time.h> #include <stat.h> #include <dir.h> #include <pwd.h> #include <grp.h> #define BSIZE BUFSIZ /* Disc blocking factor for `-s' */ #define NBN 128 /* Number of blocks in an indirect block */ #define ND 10 /* Number of direct blocks */ #define NI 1 /* Number of indirect blocks */ #define NII 1 /* Number of double indirect blocks */ #define NIII 1 /* Number of triple indirect blocks */ #define MTIME 0 /* Use modify time */ #define ATIME 1 /* Use access time */ #define CTIME 2 /* Use create time */ #define OLD (60L*60*24*365) /* old form of dates (seconds) */ int aflag; /* List all entries (including "." & "..") */ int dflag; /* Treat directories like files */ int fflag; /* Force something to look like a directory */ int gflag; /* Print gid vs. uid */ int iflag; /* Give i-number */ int lflag; /* Longer format */ int rflag; /* Reverse order of sort */ int sflag; /* Print size in bytes */ int tflag = MTIME; /* Which time to display and sort on */ int sortflg; /* On for sort by time, 0 for by name */ int myuid; /* User id for selecting .* suppression */ time_t curtime; char obuf[BUFSIZ]; char namebuf[200]; /* Buffer for constructing names */ char dirbuf[BSIZE]; /* Buffer for reading directories */ char *deflist[] = { ".", NULL }; struct ls { char ls_dname[DIRSIZ+1]; char *ls_name; ino_t ls_ino; short ls_mode; short ls_uid; /* Uid or gid */ short ls_nlink; size_t ls_size; dev_t ls_rdev; /* Real device */ time_t ls_time; /* One of atime, mtime, ctime */ }; struct ls *saved; /* Array of saved info */ struct ls *savep; struct ls *asavep; /* Pointer for argument storage */ size_t dirsize; /* Size of directory */ int (*qcomp)(); int qtcomp(); int qncomp(); int qdncomp(); char *getuname(); main(argc, argv) char *argv[]; { register char *ap; register int es; setbuf(stdout, obuf); while (argc>1 && *argv[1]=='-') { for (ap=&argv[1][1]; *ap; ap++) switch (*ap) { case 'a': aflag = 1; break; case 'c': tflag = CTIME; break; case 'd': dflag = 1; break; case 'f': aflag = fflag = 1; lflag = sflag = 0; break; case 'g': gflag = 1; break; case 'i': iflag = 1; break; case 'l': lflag = 1; break; case 'r': rflag = 1; break; case 's': sflag = 1; break; case 't': sortflg = 1; break; case 'u': tflag = ATIME; break; default: usage(); } argc--; argv++; } time(&curtime); myuid = getuid(); if (sortflg) qcomp = qtcomp; else qcomp = qncomp; if (argc > 1) es = ls(argv+1, argc-1); else es = ls(deflist, 1); exit(es); } /* * Do `ls' on one file or * directory. * `narg' is the number of names * in `flist' to determine special * output format. */ ls(flist, narg) register char **flist; int narg; { register int estat = 0; register struct ls *lsp; register struct ls *arena; struct stat sb; if ((arena = (struct ls *)malloc(narg*sizeof(struct ls))) == NULL) { fprintf(stderr, "ls: out of memory for arguments\n"); exit(1); } asavep = arena; for ( ; *flist!=NULL; flist++) { if (stat(*flist, &sb) < 0) { perror(*flist); estat = 1; continue; } astore(*flist, &sb); } qsort(arena, asavep-arena, sizeof(struct ls), qcomp); if (qcomp == qncomp) qcomp = qdncomp; for (lsp = arena; lsp < asavep; lsp++) { if (fflag) continue; if ((lsp->ls_mode&S_IFMT)==S_IFDIR && !dflag) continue; prstuff(lsp->ls_name, lsp); } for (lsp = arena; lsp < asavep; lsp++) { if (dflag || (lsp->ls_mode&S_IFMT)!=S_IFDIR) continue; dirsize = lsp->ls_size; if (narg > 1) printf("\n%s:\n", lsp->ls_name); lsdir(lsp->ls_name); } return (estat); } prstuff(file, lsp) char *file; register struct ls *lsp; { register char *cp; register spcl = 0; if (iflag) printf("%5u ", lsp->ls_ino); if (sflag) { prsize(lsp); putchar(' '); } if (lflag) { switch (lsp->ls_mode & S_IFMT) { case S_IFREG: putchar('-'); break; case S_IFDIR: putchar('d'); break; case S_IFCHR: putchar('c'); spcl++; break; case S_IFBLK: putchar('b'); spcl++; break; case S_IFPIP: putchar('p'); break; case S_IFMPB: case S_IFMPC: putchar('m'); spcl++; break; default: putchar('x'); } prmode((lsp->ls_mode>>6)&07, lsp->ls_mode&S_ISUID); prmode((lsp->ls_mode>>3)&07, lsp->ls_mode&S_ISGID); prmode(lsp->ls_mode&07, 0); if (lsp->ls_mode & S_ISVTX) putchar('t'); else putchar(' '); printf("%2d ", lsp->ls_nlink); cp = getuname(lsp->ls_uid); if (cp == NULL) printf("%-8d ", lsp->ls_uid); else printf("%-8s ", cp); if (!spcl) printf("%7ld", lsp->ls_size); else printf("%3d %3d", major(lsp->ls_rdev), minor(lsp->ls_rdev)); prtime(&lsp->ls_time); } printf("%s", file); putchar('\n'); } /* * Print out a filesize from a ls store buffer. * This size (in BSIZE units or blocks) takes * into account indirect blocks. * However this should be done in a more general manner. */ prsize(lsp) register struct ls *lsp; { long blocks, size; register ftype; size = 0; ftype = lsp->ls_mode & S_IFMT; if (ftype==S_IFREG || ftype==S_IFDIR || ftype==S_IFPIP) { size = blocks = (lsp->ls_size+BSIZE-1)/BSIZE; if (blocks > ND) { size++; blocks -= ND; if (blocks > NBN*NI) { blocks -= NBN*NI; size += 2 + blocks/NBN; } } } printf("%4ld", size); return (size); } /* * Print a time (if it is older than * one year) print the year instead * of the mm:ss part. */ prtime(tp) register time_t *tp; { register struct tm *tmp; register char *cp; time_t tdiff; cp = asctime(tmp = localtime(tp)); if ((tdiff = curtime-*tp)>OLD || tdiff<0) { cp[10] = '\0'; printf(" %s %d ", cp, tmp->tm_year+1900); } else { cp[16] = '\0'; printf(" %s ", cp); } } /* * Print 'rwx' type modes out. */ prmode(m, suid) int m; int suid; { m <<= 6; putchar(m&S_IREAD ? 'r' : '-'); putchar(m&S_IWRITE ? 'w' : '-'); if (suid) putchar('s'); else putchar(m&S_IEXEC ? 'x' : '-'); } /* * Get a user name. Either look * in password or group file depending * on `gflag'. */ char * getuname(uid) short uid; { register struct passwd *pwp; register struct group *grp; static id = -1; static char *name; if (uid == id) return (name); id = uid; name = NULL; if (gflag) { if ((grp=getgrgid( uid)) != NULL) name = grp->gr_name; } else { if ((pwp=getpwuid( uid)) != NULL) name = pwp->pw_name; } return (name); } /* * List out the files in a directory * If ``fflag'' is set, it may not be * but consider it one anyway. */ lsdir(dir) char *dir; { int fd; struct stat sb; struct ls ls; register char *np1, *np2; register int n; register struct direct *dp; register int nb; char curname[DIRSIZ+1]; unsigned size; if ((fd = open(dir, 0)) < 0) { fprintf(stderr, "%s: cannot read\n", dir); return; } if (!fflag) { size = dirsize/sizeof (struct direct) * sizeof (struct ls); if ((saved = malloc(size)) == NULL) { fprintf(stderr, "Out of memory\n"); exit (1); } savep = saved; } while ((nb = read(fd, dirbuf, sizeof (dirbuf))) > 0) for (dp=dirbuf; dp<&dirbuf[nb]; dp++) { if (dp->d_ino == 0) continue; np1 = dp->d_name; if (aflag == 0 && *np1++ == '.') { if (myuid != 0) continue; if (*np1=='\0' || (*np1++=='.' && *np1=='\0')) continue; } if (iflag) { sb.st_ino = dp->d_ino; canino(sb.st_ino); } np2 = curname; np1 = dp->d_name; n = DIRSIZ; do { *np2++ = *np1++; } while (--n); *np2 = '\0'; if (lflag || sflag || tflag || sortflg) { np2 = namebuf; np1 = dir; while (*np2++ = *np1++) ; --np2; *np2++ = '/'; np1 = curname; while (*np2++ = *np1++) ; if (stat(namebuf, &sb) < 0) { fprintf(stderr, "%s: cannot stat\n", curname); continue; } } if (fflag) { convert(&sb, &ls); prstuff(curname, &ls); } else store(curname, &sb); } if (!fflag) output(); close(fd); } /* * Store data away for intra-directory * sorting. */ store(name, sbp) char *name; register struct stat *sbp; { register struct ls *lsp; lsp = savep++; strncpy(lsp->ls_dname, name, DIRSIZ+1); convert(sbp, lsp); } /* * Store each argument away for inter-directory * sorting. */ astore(name, sbp) char *name; register struct stat *sbp; { register struct ls *lsp; lsp = asavep++; if ((lsp->ls_name = malloc(strlen(name)+sizeof(char))) == NULL) { fprintf(stderr, "ls: out of space for argument names\n"); exit(1); } strcpy(lsp->ls_name, name); convert(sbp, lsp); } /* * Convert a stat buffer into an ls store * buffer. */ convert(sbp, lsp) register struct stat *sbp; register struct ls *lsp; { lsp->ls_ino = sbp->st_ino; lsp->ls_mode = sbp->st_mode; lsp->ls_nlink = sbp->st_nlink; lsp->ls_uid = gflag ? sbp->st_gid : sbp->st_uid; lsp->ls_size = sbp->st_size; lsp->ls_rdev = sbp->st_rdev; if (tflag == CTIME) lsp->ls_time = sbp->st_ctime; else if (tflag == MTIME) lsp->ls_time = sbp->st_mtime; else if (tflag == ATIME) lsp->ls_time = sbp->st_atime; } /* * Sort, output and free up space from * the current directory being considered. */ output() { register struct ls *lsp, *lse; register unsigned nel; nel = savep-saved; qsort(saved, nel, sizeof (struct ls), qcomp); for (lsp=saved, lse=savep; lsp < lse; lsp++) prstuff(lsp->ls_dname, lsp); free(saved); } /* * The following are the two qsort comparison * routines -- one for sorting by times, one for * sorting by names. They can be used in both * the argument sort and each directory sort. */ /* * Sort by time (either access, modify, or create setup elsewhere) * (forward or backward). */ qtcomp(lsp1, lsp2) register struct ls *lsp1, *lsp2; { register int rval = 0; if (lsp1->ls_time < lsp2->ls_time) rval++; else if (lsp1->ls_time > lsp2->ls_time) rval--; if (rflag) return (-rval); return (rval); } /* * Sort by directory name. * (forward or reverse). */ qdncomp(lsp1, lsp2) struct ls *lsp1, *lsp2; { register int rval; rval = strncmp(lsp1->ls_dname, lsp2->ls_dname, DIRSIZ); if (rflag) return (-rval); return (rval); } /* * Sort by full pathname. * (forward or reverse). */ qncomp(lsp1, lsp2) struct ls *lsp1, *lsp2; { register int rval; rval = strcmp(lsp1->ls_name, lsp2->ls_name); if (rflag) return (-rval); return (rval); } usage() { fprintf(stderr, "Usage: ls [-acdfgilrstu] [files ...]\n"); exit(1); }