Commit | Line | Data |
---|---|---|
3b600ead TL |
1 | /* |
2 | * list file or directory | |
3 | */ | |
4 | ||
5 | #include <sys/param.h> | |
6 | #include <sys/stat.h> | |
7 | #include <sys/dir.h> | |
8 | #include <stdio.h> | |
9 | ||
10 | #define NFILES 1024 | |
11 | FILE *pwdf, *dirf; | |
12 | char stdbuf[BUFSIZ]; | |
13 | ||
14 | struct lbuf { | |
15 | union { | |
16 | char lname[15]; | |
17 | char *namep; | |
18 | } ln; | |
19 | char ltype; | |
20 | short lnum; | |
21 | short lflags; | |
22 | short lnl; | |
23 | short luid; | |
24 | short lgid; | |
25 | long lsize; | |
26 | long lmtime; | |
27 | }; | |
28 | ||
29 | int aflg, dflg, lflg, sflg, tflg, uflg, iflg, fflg, gflg, cflg; | |
30 | int rflg = 1; | |
31 | long year; | |
32 | int flags; | |
33 | int lastuid = -1; | |
34 | char tbuf[16]; | |
35 | long tblocks; | |
36 | int statreq; | |
37 | struct lbuf *flist[NFILES]; | |
38 | struct lbuf **lastp = flist; | |
39 | struct lbuf **firstp = flist; | |
40 | char *dotp = "."; | |
41 | ||
42 | char *makename(); | |
43 | struct lbuf *gstat(); | |
44 | char *ctime(); | |
45 | long nblock(); | |
46 | ||
47 | #define ISARG 0100000 | |
48 | ||
49 | main(argc, argv) | |
50 | char *argv[]; | |
51 | { | |
52 | int i; | |
53 | register struct lbuf *ep, **ep1; | |
54 | register struct lbuf **slastp; | |
55 | struct lbuf **epp; | |
56 | struct lbuf lb; | |
57 | char *t; | |
58 | int compar(); | |
59 | ||
60 | setbuf(stdout, stdbuf); | |
61 | time(&lb.lmtime); | |
62 | year = lb.lmtime - 6L*30L*24L*60L*60L; /* 6 months ago */ | |
63 | if (--argc > 0 && *argv[1] == '-') { | |
64 | argv++; | |
65 | while (*++*argv) switch (**argv) { | |
66 | ||
67 | case 'a': | |
68 | aflg++; | |
69 | continue; | |
70 | ||
71 | case 's': | |
72 | sflg++; | |
73 | statreq++; | |
74 | continue; | |
75 | ||
76 | case 'd': | |
77 | dflg++; | |
78 | continue; | |
79 | ||
80 | case 'g': | |
81 | gflg++; | |
82 | continue; | |
83 | ||
84 | case 'l': | |
85 | lflg++; | |
86 | statreq++; | |
87 | continue; | |
88 | ||
89 | case 'r': | |
90 | rflg = -1; | |
91 | continue; | |
92 | ||
93 | case 't': | |
94 | tflg++; | |
95 | statreq++; | |
96 | continue; | |
97 | ||
98 | case 'u': | |
99 | uflg++; | |
100 | continue; | |
101 | ||
102 | case 'c': | |
103 | cflg++; | |
104 | continue; | |
105 | ||
106 | case 'i': | |
107 | iflg++; | |
108 | continue; | |
109 | ||
110 | case 'f': | |
111 | fflg++; | |
112 | continue; | |
113 | ||
114 | default: | |
115 | continue; | |
116 | } | |
117 | argc--; | |
118 | } | |
119 | if (fflg) { | |
120 | aflg++; | |
121 | lflg = 0; | |
122 | sflg = 0; | |
123 | tflg = 0; | |
124 | statreq = 0; | |
125 | } | |
126 | if(lflg) { | |
127 | t = "/etc/passwd"; | |
128 | if(gflg) | |
129 | t = "/etc/group"; | |
130 | pwdf = fopen(t, "r"); | |
131 | } | |
132 | if (argc==0) { | |
133 | argc++; | |
134 | argv = &dotp - 1; | |
135 | } | |
136 | for (i=0; i < argc; i++) { | |
137 | if ((ep = gstat(*++argv, 1))==NULL) | |
138 | continue; | |
139 | ep->ln.namep = *argv; | |
140 | ep->lflags |= ISARG; | |
141 | } | |
142 | qsort(firstp, lastp - firstp, sizeof *lastp, compar); | |
143 | slastp = lastp; | |
144 | for (epp=firstp; epp<slastp; epp++) { | |
145 | ep = *epp; | |
146 | if (ep->ltype=='d' && dflg==0 || fflg) { | |
147 | if (argc>1) | |
148 | printf("\n%s:\n", ep->ln.namep); | |
149 | lastp = slastp; | |
150 | readdir(ep->ln.namep); | |
151 | if (fflg==0) | |
152 | qsort(slastp,lastp - slastp,sizeof *lastp,compar); | |
153 | if (lflg || sflg) | |
154 | printf("total %D\n", tblocks); | |
155 | for (ep1=slastp; ep1<lastp; ep1++) | |
156 | pentry(*ep1); | |
157 | } else | |
158 | pentry(ep); | |
159 | } | |
160 | exit(0); | |
161 | } | |
162 | ||
163 | pentry(ap) | |
164 | struct lbuf *ap; | |
165 | { | |
166 | struct { char dminor, dmajor;}; | |
167 | register t; | |
168 | register struct lbuf *p; | |
169 | register char *cp; | |
170 | ||
171 | p = ap; | |
172 | if (p->lnum == -1) | |
173 | return; | |
174 | if (iflg) | |
175 | printf("%5d ", p->lnum); | |
176 | if (sflg) | |
177 | printf("%4D ", nblock(p->lsize)); | |
178 | if (lflg) { | |
179 | putchar(p->ltype); | |
180 | pmode(p->lflags); | |
181 | printf("%2d ", p->lnl); | |
182 | t = p->luid; | |
183 | if(gflg) | |
184 | t = p->lgid; | |
185 | if (getname(t, tbuf)==0) | |
186 | printf("%-6.6s", tbuf); | |
187 | else | |
188 | printf("%-6d", t); | |
189 | if (p->ltype=='b' || p->ltype=='c') | |
190 | printf("%3d,%3d", major((int)p->lsize), minor((int)p->lsize)); | |
191 | else | |
192 | printf("%7ld", p->lsize); | |
193 | cp = ctime(&p->lmtime); | |
194 | if(p->lmtime < year) | |
195 | printf(" %-7.7s %-4.4s ", cp+4, cp+20); else | |
196 | printf(" %-12.12s ", cp+4); | |
197 | } | |
198 | if (p->lflags&ISARG) | |
199 | printf("%s\n", p->ln.namep); | |
200 | else | |
201 | printf("%.14s\n", p->ln.lname); | |
202 | } | |
203 | ||
204 | getname(uid, buf) | |
205 | int uid; | |
206 | char buf[]; | |
207 | { | |
208 | int j, c, n, i; | |
209 | ||
210 | if (uid==lastuid) | |
211 | return(0); | |
212 | if(pwdf == NULL) | |
213 | return(-1); | |
214 | rewind(pwdf); | |
215 | lastuid = -1; | |
216 | do { | |
217 | i = 0; | |
218 | j = 0; | |
219 | n = 0; | |
220 | while((c=fgetc(pwdf)) != '\n') { | |
221 | if (c==EOF) | |
222 | return(-1); | |
223 | if (c==':') { | |
224 | j++; | |
225 | c = '0'; | |
226 | } | |
227 | if (j==0) | |
228 | buf[i++] = c; | |
229 | if (j==2) | |
230 | n = n*10 + c - '0'; | |
231 | } | |
232 | } while (n != uid); | |
233 | buf[i++] = '\0'; | |
234 | lastuid = uid; | |
235 | return(0); | |
236 | } | |
237 | ||
238 | long | |
239 | nblock(size) | |
240 | long size; | |
241 | { | |
242 | return((size+511)>>9); | |
243 | } | |
244 | ||
245 | int m1[] = { 1, S_IREAD>>0, 'r', '-' }; | |
246 | int m2[] = { 1, S_IWRITE>>0, 'w', '-' }; | |
247 | int m3[] = { 2, S_ISUID, 's', S_IEXEC>>0, 'x', '-' }; | |
248 | int m4[] = { 1, S_IREAD>>3, 'r', '-' }; | |
249 | int m5[] = { 1, S_IWRITE>>3, 'w', '-' }; | |
250 | int m6[] = { 2, S_ISGID, 's', S_IEXEC>>3, 'x', '-' }; | |
251 | int m7[] = { 1, S_IREAD>>6, 'r', '-' }; | |
252 | int m8[] = { 1, S_IWRITE>>6, 'w', '-' }; | |
253 | int m9[] = { 2, S_ISVTX, 't', S_IEXEC>>6, 'x', '-' }; | |
254 | ||
255 | int *m[] = { m1, m2, m3, m4, m5, m6, m7, m8, m9}; | |
256 | ||
257 | pmode(aflag) | |
258 | { | |
259 | register int **mp; | |
260 | ||
261 | flags = aflag; | |
262 | for (mp = &m[0]; mp < &m[sizeof(m)/sizeof(m[0])];) | |
263 | select(*mp++); | |
264 | } | |
265 | ||
266 | select(pairp) | |
267 | register int *pairp; | |
268 | { | |
269 | register int n; | |
270 | ||
271 | n = *pairp++; | |
272 | while (--n>=0 && (flags&*pairp++)==0) | |
273 | pairp++; | |
274 | putchar(*pairp); | |
275 | } | |
276 | ||
277 | char * | |
278 | makename(dir, file) | |
279 | char *dir, *file; | |
280 | { | |
281 | static char dfile[100]; | |
282 | register char *dp, *fp; | |
283 | register int i; | |
284 | ||
285 | dp = dfile; | |
286 | fp = dir; | |
287 | while (*fp) | |
288 | *dp++ = *fp++; | |
289 | *dp++ = '/'; | |
290 | fp = file; | |
291 | for (i=0; i<DIRSIZ; i++) | |
292 | *dp++ = *fp++; | |
293 | *dp = 0; | |
294 | return(dfile); | |
295 | } | |
296 | ||
297 | readdir(dir) | |
298 | char *dir; | |
299 | { | |
300 | static struct direct dentry; | |
301 | register int j; | |
302 | register struct lbuf *ep; | |
303 | ||
304 | if ((dirf = fopen(dir, "r")) == NULL) { | |
305 | printf("%s unreadable\n", dir); | |
306 | return; | |
307 | } | |
308 | tblocks = 0; | |
309 | for(;;) { | |
310 | if (fread((char *)&dentry, sizeof(dentry), 1, dirf) != 1) | |
311 | break; | |
312 | if (dentry.d_ino==0 | |
313 | || aflg==0 && dentry.d_name[0]=='.' && (dentry.d_name[1]=='\0' | |
314 | || dentry.d_name[1]=='.' && dentry.d_name[2]=='\0')) | |
315 | continue; | |
316 | ep = gstat(makename(dir, dentry.d_name), 0); | |
317 | if (ep==NULL) | |
318 | continue; | |
319 | if (ep->lnum != -1) | |
320 | ep->lnum = dentry.d_ino; | |
321 | for (j=0; j<DIRSIZ; j++) | |
322 | ep->ln.lname[j] = dentry.d_name[j]; | |
323 | } | |
324 | fclose(dirf); | |
325 | } | |
326 | ||
327 | struct lbuf * | |
328 | gstat(file, argfl) | |
329 | char *file; | |
330 | { | |
331 | struct stat statb; | |
332 | register struct lbuf *rep; | |
333 | static int nomocore; | |
334 | ||
335 | if (nomocore) | |
336 | return(NULL); | |
337 | rep = (struct lbuf *)malloc(sizeof(struct lbuf)); | |
338 | if (rep==NULL) { | |
339 | fprintf(stderr, "ls: out of memory\n"); | |
340 | nomocore = 1; | |
341 | return(NULL); | |
342 | } | |
343 | if (lastp >= &flist[NFILES]) { | |
344 | static int msg; | |
345 | lastp--; | |
346 | if (msg==0) { | |
347 | fprintf(stderr, "ls: too many files\n"); | |
348 | msg++; | |
349 | } | |
350 | } | |
351 | *lastp++ = rep; | |
352 | rep->lflags = 0; | |
353 | rep->lnum = 0; | |
354 | rep->ltype = '-'; | |
355 | if (argfl || statreq) { | |
356 | if (stat(file, &statb)<0) { | |
357 | printf("%s not found\n", file); | |
358 | statb.st_ino = -1; | |
359 | statb.st_size = 0; | |
360 | statb.st_mode = 0; | |
361 | if (argfl) { | |
362 | lastp--; | |
363 | return(0); | |
364 | } | |
365 | } | |
366 | rep->lnum = statb.st_ino; | |
367 | rep->lsize = statb.st_size; | |
368 | switch(statb.st_mode&S_IFMT) { | |
369 | ||
370 | case S_IFDIR: | |
371 | rep->ltype = 'd'; | |
372 | break; | |
373 | ||
374 | case S_IFBLK: | |
375 | rep->ltype = 'b'; | |
376 | rep->lsize = statb.st_rdev; | |
377 | break; | |
378 | ||
379 | case S_IFCHR: | |
380 | rep->ltype = 'c'; | |
381 | rep->lsize = statb.st_rdev; | |
382 | break; | |
383 | } | |
384 | rep->lflags = statb.st_mode & ~S_IFMT; | |
385 | rep->luid = statb.st_uid; | |
386 | rep->lgid = statb.st_gid; | |
387 | rep->lnl = statb.st_nlink; | |
388 | if(uflg) | |
389 | rep->lmtime = statb.st_atime; | |
390 | else if (cflg) | |
391 | rep->lmtime = statb.st_ctime; | |
392 | else | |
393 | rep->lmtime = statb.st_mtime; | |
394 | tblocks += nblock(statb.st_size); | |
395 | } | |
396 | return(rep); | |
397 | } | |
398 | ||
399 | compar(pp1, pp2) | |
400 | struct lbuf **pp1, **pp2; | |
401 | { | |
402 | register struct lbuf *p1, *p2; | |
403 | ||
404 | p1 = *pp1; | |
405 | p2 = *pp2; | |
406 | if (dflg==0) { | |
407 | if (p1->lflags&ISARG && p1->ltype=='d') { | |
408 | if (!(p2->lflags&ISARG && p2->ltype=='d')) | |
409 | return(1); | |
410 | } else { | |
411 | if (p2->lflags&ISARG && p2->ltype=='d') | |
412 | return(-1); | |
413 | } | |
414 | } | |
415 | if (tflg) { | |
416 | if(p2->lmtime == p1->lmtime) | |
417 | return(0); | |
418 | if(p2->lmtime > p1->lmtime) | |
419 | return(rflg); | |
420 | return(-rflg); | |
421 | } | |
422 | return(rflg * strcmp(p1->lflags&ISARG? p1->ln.namep: p1->ln.lname, | |
423 | p2->lflags&ISARG? p2->ln.namep: p2->ln.lname)); | |
424 | } |