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