fix up flags; document options better; get rid of f_modetime;
[unix-history] / usr / src / bin / ls / ls.c
CommitLineData
bcf1365c 1/*
9ffe97fe
KB
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 the above copyright notice and this paragraph are
10 * duplicated in all such forms and that any documentation,
11 * advertising materials, and other materials related to such
12 * distribution and use acknowledge that the software was developed
13 * by the University of California, Berkeley. The name of the
14 * University may not be used to endorse or promote products derived
15 * from this software without specific prior written permission.
16 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
bcf1365c 19 */
9ffe97fe
KB
20
21#ifndef lint
22char copyright[] =
23"@(#) Copyright (c) 1989 The Regents of the University of California.\n\
24 All rights reserved.\n";
25#endif /* not lint */
26
27#ifndef lint
38eeee6d 28static char sccsid[] = "@(#)ls.c 5.16 (Berkeley) %G%";
9ffe97fe
KB
29#endif /* not lint */
30
2fd18a0a 31#include <sys/param.h>
9ffe97fe 32#include <sys/stat.h>
2fd18a0a 33#include <dirent.h>
9ffe97fe 34#include <strings.h>
9ffe97fe
KB
35#include <errno.h>
36#include <stdio.h>
b3f77fd1 37#include "ls.h"
2fd18a0a 38
b3f77fd1
KB
39int lstat(), strlen(), prablelen();
40char *emalloc();
bcf1365c 41
2fd18a0a 42int qflg, Aflg, Cflg, Fflg, Lflg, Rflg, Sflg;
547b0031 43
9ffe97fe 44/* flags */
9ffe97fe 45int f_accesstime; /* use time of last access */
38eeee6d 46int f_firsttime = 1; /* to control recursion */
9ffe97fe 47int f_group; /* show group ownership of a file */
38eeee6d 48int f_ignorelink; /* indirect through symbolic link operands */
9ffe97fe 49int f_inode; /* print inode */
38eeee6d
KB
50int f_listalldot; /* list . and .. as well */
51int f_listdir; /* list actual directory, not contents */
52int f_listdot; /* list files beginning with . */
9ffe97fe
KB
53int f_longform; /* long listing format */
54int f_nonprint; /* show unprintables as ? */
9ffe97fe 55int f_recursive; /* ls subdirectories also */
38eeee6d
KB
56int f_reversesort; /* reverse whatever sort is used */
57int f_singlecol; /* use single column output */
9ffe97fe 58int f_size; /* list size in short listing */
38eeee6d
KB
59int f_specialdir; /* force params to be directories */
60int f_statustime; /* use time of last mode change */
9ffe97fe 61int f_timesort; /* sort by time vice name */
38eeee6d 62int f_type; /* add type character for non-regular files */
2fd18a0a 63
9ffe97fe
KB
64main(argc, argv)
65 int argc;
66 char **argv;
547b0031 67{
9ffe97fe
KB
68 extern int optind, stat();
69 int ch;
70 int namecmp(), revnamecmp(), acccmp(), revacccmp();
71 int modcmp(), revmodcmp(), statcmp(), revstatcmp();
2fd18a0a 72
38eeee6d
KB
73 /*
74 * terminal defaults to -C -q
75 * non-terminal defaults to -1
76 */
547b0031 77 if (isatty(1)) {
9ffe97fe 78 f_nonprint = 1;
2fd18a0a 79 lengthfcn = prablelen;
9ffe97fe
KB
80 } else
81 f_singlecol = 1;
2fd18a0a 82
38eeee6d 83 /* root is -A automatically */
9ffe97fe 84 if (!getuid())
b3f77fd1 85 f_listdot = 1;
9ffe97fe
KB
86
87 while ((ch = getopt(argc, argv, "1ACFLRacdfgilqrstu")) != EOF) {
88 switch (ch) {
38eeee6d
KB
89 /*
90 * -1, -C and -l all override each other
91 * so shell aliasing works right
92 */
9ffe97fe
KB
93 case '1':
94 f_singlecol = 1;
38eeee6d 95 f_longform = 0;
2fd18a0a 96 break;
9ffe97fe 97 case 'C':
38eeee6d
KB
98 f_longform = f_singlecol = 0;
99 break;
100 case 'l':
101 f_longform = 1;
9ffe97fe
KB
102 f_singlecol = 0;
103 break;
38eeee6d
KB
104 /* -c and -u override each other */
105 case 'c':
106 f_statustime = 1;
107 f_accesstime = 0;
108 break;
109 case 'u':
110 f_accesstime = 1;
111 f_statustime = 0;
112 break;
9ffe97fe
KB
113 case 'F':
114 f_type = 1;
115 break;
116 case 'L':
38eeee6d 117 f_ignorelink = 1;
9ffe97fe
KB
118 break;
119 case 'R':
120 f_recursive = 1;
9ffe97fe
KB
121 break;
122 case 'a':
b3f77fd1 123 f_listalldot = 1;
9ffe97fe 124 /* FALLTHROUGH */
2fd18a0a 125 case 'A':
b3f77fd1 126 f_listdot = 1;
2fd18a0a 127 break;
1c52c7b1
JB
128 case 'S':
129 Sflg++; /* fall into... */
547b0031 130 case 'd':
9ffe97fe 131 f_listdir = 1;
2fd18a0a 132 break;
ec0c22c1 133 case 'f':
9ffe97fe 134 f_specialdir = 1;
2fd18a0a 135 break;
547b0031 136 case 'g':
9ffe97fe 137 f_group = 1;
2fd18a0a 138 break;
ec0c22c1 139 case 'i':
9ffe97fe 140 f_inode = 1;
2fd18a0a 141 break;
ec0c22c1 142 case 'q':
9ffe97fe 143 f_nonprint = 1;
2fd18a0a
KB
144 lengthfcn = prablelen;
145 break;
547b0031 146 case 'r':
9ffe97fe 147 f_reversesort = 1;
2fd18a0a 148 break;
ec0c22c1 149 case 's':
9ffe97fe 150 f_size = 1;
2fd18a0a 151 break;
547b0031 152 case 't':
9ffe97fe 153 f_timesort = 1;
2fd18a0a 154 break;
ec0c22c1 155 default:
2fd18a0a 156 case '?':
9ffe97fe 157 usage();
2955376b 158 }
9ffe97fe 159 }
b3f77fd1
KB
160 argc -= optind;
161 argv += optind;
9ffe97fe 162
be4f2604 163 /* -f turns off -F, -R, -l, -t, -s, -r, turns on -a */
9ffe97fe 164 if (f_specialdir) {
be4f2604
KB
165 f_longform = f_recursive = f_reversesort = f_size =
166 f_timesort = f_type = 0;
b3f77fd1 167 f_listdot = f_listalldot = 1;
9ffe97fe
KB
168 }
169
b3f77fd1
KB
170 /* -d turns off -R */
171 if (f_listdir)
172 f_recursive = 0;
173
174 /* if will need to stat files */
175 needstat = f_longform || f_recursive || f_timesort || f_size ||
176 f_inode || f_type;
177
9ffe97fe
KB
178 /* select a sort function */
179 if (f_reversesort) {
180 if (!f_timesort)
181 sortfcn = revnamecmp;
182 else if (f_accesstime)
183 sortfcn = revacccmp;
9ffe97fe
KB
184 else if (f_statustime)
185 sortfcn = revstatcmp;
38eeee6d
KB
186 else /* use modification time */
187 sortfcn = revmodcmp;
2fd18a0a 188 } else {
9ffe97fe
KB
189 if (!f_timesort)
190 sortfcn = namecmp;
191 else if (f_accesstime)
192 sortfcn = acccmp;
9ffe97fe
KB
193 else if (f_statustime)
194 sortfcn = statcmp;
38eeee6d
KB
195 else /* use modification time */
196 sortfcn = modcmp;
9ffe97fe
KB
197 }
198
b3f77fd1
KB
199 if (argc)
200 args(argc, argv);
201 else
202 curdir();
9ffe97fe 203 exit(0);
547b0031
BJ
204}
205
b3f77fd1 206curdir()
547b0031 207{
b3f77fd1
KB
208 LS local, *stats;
209 int num;
210 char *names;
9ffe97fe 211
38eeee6d 212 if (lstat(local.name = ".", &local.lstat)) {
b3f77fd1
KB
213 (void)fprintf(stderr, "ls: .: %s\n", strerror(errno));
214 exit(1);
2fd18a0a 215 }
b3f77fd1
KB
216 if (num = buildstats(&local, &stats, &names))
217 ls(stats, num);
2fd18a0a
KB
218}
219
be4f2604
KB
220static char path[MAXPATHLEN + 1];
221static char *endofpath = path;
222
b3f77fd1
KB
223args(argc, argv)
224 int argc;
225 char **argv;
2fd18a0a 226{
b3f77fd1
KB
227 register LS *dstats, *rstats;
228 register int cnt, dircnt, regcnt;
229 struct stat sb;
230 LS *stats;
38eeee6d 231 int num, (*statfcn)(), stat(), lstat();
b3f77fd1
KB
232 char *names;
233
234 dstats = rstats = NULL;
38eeee6d 235 statfcn = f_ignorelink ? stat : lstat;
b3f77fd1
KB
236 for (dircnt = regcnt = 0; *argv; ++argv) {
237 if (statfcn(*argv, &sb)) {
238 (void)fprintf(stderr, "ls: %s: %s\n",
239 *argv, strerror(errno));
240 if (errno == ENOENT)
241 continue;
242 exit(1);
9ffe97fe 243 }
b3f77fd1
KB
244 if (!f_specialdir && !f_listdir && S_ISDIR(sb.st_mode)) {
245 if (!dstats)
246 dstats = (LS *)emalloc((u_int)argc *
247 (sizeof(LS)));
248 dstats[dircnt].name = *argv;
249 dstats[dircnt].lstat = sb;
250 ++dircnt;
251 }
252 else {
253 if (!rstats)
254 rstats = (LS *)emalloc((u_int)argc *
255 (sizeof(LS)));
256 rstats[regcnt].name = *argv;
257 rstats[regcnt].lstat = sb;
258 ++regcnt;
9ffe97fe 259 }
9ffe97fe 260 }
b3f77fd1
KB
261 if (regcnt) {
262 if (f_specialdir) {
263 for (cnt = 0; cnt < regcnt; ++cnt) {
264 if (num = buildstats(rstats++, &stats, &names))
265 ls(stats, num);
266 (void)free((char *)stats);
267 (void)free((char *)names);
9ffe97fe 268 }
b3f77fd1
KB
269 } else
270 ls(rstats, regcnt);
271 if (dircnt)
272 (void)putchar('\n');
547b0031 273 }
b3f77fd1 274 if (dircnt) {
be4f2604
KB
275 register char *p;
276
b3f77fd1
KB
277 if (dircnt > 1)
278 qsort((char *)dstats, dircnt, sizeof(LS), sortfcn);
be4f2604
KB
279 for (cnt = 0; cnt < dircnt; ++cnt) {
280 for (endofpath = path, p = dstats->name;
281 *endofpath = *p++; ++endofpath);
b3f77fd1 282 ls_dir(dstats++, cnt, regcnt || dircnt > 1);
be4f2604 283 }
547b0031 284 }
b3f77fd1
KB
285#ifdef whybother
286 (void)free((char *)rstats);
287 (void)free((char *)dstats);
288#endif
547b0031
BJ
289}
290
b3f77fd1
KB
291ls(stats, num)
292 LS *stats;
293 register int num;
547b0031 294{
be4f2604 295 register char *p, *savedpath;
b3f77fd1 296 LS *lp;
9ffe97fe 297
b3f77fd1
KB
298 if (num > 1 && !f_specialdir)
299 qsort((char *)stats, num, sizeof(LS), sortfcn);
9ffe97fe 300
b3f77fd1 301 printdir(stats, num);
547b0031 302
be4f2604
KB
303 if (f_recursive) {
304 savedpath = endofpath;
b3f77fd1
KB
305 for (lp = stats; num--; ++lp) {
306 if (!S_ISDIR(lp->lstat.st_mode))
307 continue;
308 p = lp->name;
309 if (p[0] == '.' && (!p[1] || p[1] == '.' && !p[2]))
310 continue;
be4f2604
KB
311 if (endofpath != path && endofpath[-1] != '/')
312 *endofpath++ = '/';
313 for (; *endofpath = *p++; ++endofpath);
b3f77fd1 314 ls_dir(lp, 1, 1);
be4f2604 315 *(endofpath = savedpath) = '\0';
b3f77fd1 316 }
be4f2604 317 }
547b0031
BJ
318}
319
b3f77fd1
KB
320ls_dir(lp, newline, tag)
321 LS *lp;
322 int newline, tag;
2fd18a0a 323{
b3f77fd1
KB
324 LS *stats;
325 int num;
be4f2604 326 char *names;
b3f77fd1
KB
327
328 if (newline)
329 (void)putchar('\n');
330 if (tag)
331 (void)printf("%s:\n", path);
332
333 if (chdir(lp->name)) {
334 (void)fprintf(stderr, "ls: %s: %s\n",
335 lp->name, strerror(errno));
336 return;
2fd18a0a 337 }
b3f77fd1
KB
338 if (num = buildstats(lp, &stats, &names))
339 ls(stats, num);
b3f77fd1
KB
340 (void)free((char *)stats);
341 (void)free((char *)names);
342 if (chdir("..")) {
343 (void)fprintf(stderr, "ls: ..: %s\n", strerror(errno));
344 exit(1);
2fd18a0a 345 }
547b0031
BJ
346}
347
b3f77fd1
KB
348static
349buildstats(lp, s_stats, s_names)
350 LS *lp, **s_stats;
351 char **s_names;
547b0031 352{
b3f77fd1
KB
353 register int cnt, maxentry;
354 register char *p, *names;
355 struct dirent *entry;
356 LS *stats;
357 DIR *dirp;
547b0031 358
b3f77fd1
KB
359 /* make this big so we don't realloc often */
360#define DEFNUM 256
361 maxentry = DEFNUM;
362 *s_stats = stats = (LS *)emalloc((u_int)DEFNUM * sizeof(LS));
363 *s_names = names = emalloc((u_int)lp->lstat.st_size);
9ffe97fe 364
b3f77fd1
KB
365 if (!(dirp = opendir(f_specialdir ? lp->name : "."))) {
366 (void)fprintf(stderr, "ls: %s: %s\n",
367 lp->name, strerror(errno));
368 return(0);
9ffe97fe 369 }
b3f77fd1
KB
370 for (cnt = 0; entry = readdir(dirp);) {
371 p = entry->d_name;
372 if (p[0] == '.') {
373 if (!f_listdot)
374 continue;
375 if (!f_listalldot && (!p[1] || p[1] == '.' && !p[2]))
376 continue;
377 }
378 if (cnt == maxentry) {
379 maxentry += DEFNUM;
380 if (!(stats = (LS *)realloc((char *)stats,
381 (u_int)maxentry * sizeof(LS))))
382 nomem();
383 }
38eeee6d 384 if (needstat && lstat(entry->d_name, &stats[cnt].lstat)) {
b3f77fd1
KB
385 (void)fprintf(stderr, "ls: %s: %s\n",
386 entry->d_name, strerror(errno));
387 if (errno == ENOENT)
388 continue;
389 exit(1);
390 }
391 stats[cnt].name = names;
392 bcopy(entry->d_name, names, (int)entry->d_namlen);
393 names += entry->d_namlen;
394 *names++ = '\0';
395 ++cnt;
2fd18a0a 396 }
be4f2604 397 closedir(dirp);
b3f77fd1 398 return(cnt);
547b0031 399}