Commit | Line | Data |
---|---|---|
b98da692 | 1 | #ifndef lint |
3fae70c0 | 2 | static char *sccsid = "@(#)find.c 4.23 (Berkeley) %G%"; |
b98da692 | 3 | #endif |
46b257b1 | 4 | |
365a571b | 5 | #include <sys/param.h> |
c08d5d47 BJ |
6 | #include <sys/dir.h> |
7 | #include <sys/stat.h> | |
d0e5d403 KB |
8 | #include <stdio.h> |
9 | #include "pathnames.h" | |
b98da692 | 10 | |
c08d5d47 BJ |
11 | #define A_DAY 86400L /* a day full of seconds */ |
12 | #define EQ(x, y) (strcmp(x, y)==0) | |
13 | ||
14 | int Randlast; | |
e8e4232e | 15 | char Pathname[MAXPATHLEN+1]; |
c08d5d47 | 16 | |
b98da692 S |
17 | #define MAXNODES 100 |
18 | ||
c08d5d47 BJ |
19 | struct anode { |
20 | int (*F)(); | |
21 | struct anode *L, *R; | |
b98da692 | 22 | } Node[MAXNODES]; |
c08d5d47 BJ |
23 | int Nn; /* number of nodes */ |
24 | char *Fname; | |
25 | long Now; | |
26 | int Argc, | |
27 | Ai, | |
28 | Pi; | |
29 | char **Argv; | |
30 | /* cpio stuff */ | |
31 | int Cpio; | |
32 | short *Buf, *Dbuf, *Wp; | |
33 | int Bufsize = 5120; | |
34 | int Wct = 2560; | |
35 | ||
36 | long Newer; | |
37 | ||
b98da692 | 38 | int Xdev = 1; /* true if SHOULD cross devices (file systems) */ |
f731b76e | 39 | int follow; /* true if SHOULD descend symlinked directories */ |
b98da692 S |
40 | struct stat Devstat; /* stats of each argument path's file system */ |
41 | ||
c08d5d47 BJ |
42 | struct stat Statb; |
43 | ||
44 | struct anode *exp(), | |
45 | *e1(), | |
46 | *e2(), | |
47 | *e3(), | |
48 | *mk(); | |
49 | char *nxtarg(); | |
b98da692 | 50 | char Home[MAXPATHLEN + 1]; |
c08d5d47 BJ |
51 | long Blocks; |
52 | char *rindex(); | |
53 | char *sbrk(); | |
46b257b1 KM |
54 | |
55 | /* | |
25d63f56 JK |
56 | * SEE ALSO: code.c, updatedb, bigram.c |
57 | * Usenix ;login:, Vol 8, No 1, February/March, 1983, p. 8. | |
46b257b1 KM |
58 | * |
59 | * REVISIONS: James A. Woods, Informatics General Corporation, | |
60 | * NASA Ames Research Center, 6/81. | |
61 | * | |
62 | * The second form searches a pre-computed filelist | |
63 | * (constructed nightly by /usr/lib/crontab) which is | |
9f796964 | 64 | * compressed by updatedb (v.i.z.) The effect of |
46b257b1 KM |
65 | * find <name> |
66 | * is similar to | |
67 | * find / +0 -name "*<name>*" -print | |
68 | * but much faster. | |
69 | * | |
70 | * 8/82 faster yet + incorporation of bigram coding -- jaw | |
71 | * | |
72 | * 1/83 incorporate glob-style matching -- jaw | |
73 | */ | |
74 | #define AMES 1 | |
75 | ||
76 | main(argc, argv) | |
77 | int argc; | |
78 | char *argv[]; | |
c08d5d47 BJ |
79 | { |
80 | struct anode *exlist; | |
81 | int paths; | |
82 | register char *cp, *sp = 0; | |
b98da692 | 83 | #ifdef SUID_PWD |
c08d5d47 | 84 | FILE *pwd, *popen(); |
b98da692 | 85 | #endif |
c08d5d47 | 86 | |
46b257b1 KM |
87 | #ifdef AMES |
88 | if (argc < 2) { | |
89 | fprintf(stderr, | |
90 | "Usage: find name, or find path-list predicate-list\n"); | |
91 | exit(1); | |
92 | } | |
93 | if (argc == 2) { | |
94 | fastfind(argv[1]); | |
95 | exit(0); | |
96 | } | |
97 | #endif | |
c08d5d47 | 98 | time(&Now); |
d0e5d403 KB |
99 | setpassent(1); |
100 | setgroupent(1); | |
b98da692 | 101 | #ifdef SUID_PWD |
c08d5d47 | 102 | pwd = popen("pwd", "r"); |
b98da692 | 103 | fgets(Home, sizeof Home, pwd); |
c08d5d47 BJ |
104 | pclose(pwd); |
105 | Home[strlen(Home) - 1] = '\0'; | |
b98da692 S |
106 | #else |
107 | if (getwd(Home) == NULL) { | |
108 | fprintf(stderr, "find: Can't get current working directory\n"); | |
109 | exit(1); | |
110 | } | |
111 | #endif | |
c08d5d47 BJ |
112 | Argc = argc; Argv = argv; |
113 | if(argc<3) { | |
114 | usage: fprintf(stderr, "Usage: find path-list predicate-list\n"); | |
115 | exit(1); | |
116 | } | |
117 | for(Ai = paths = 1; Ai < (argc-1); ++Ai, ++paths) | |
118 | if(*Argv[Ai] == '-' || EQ(Argv[Ai], "(") || EQ(Argv[Ai], "!")) | |
119 | break; | |
120 | if(paths == 1) /* no path-list */ | |
121 | goto usage; | |
122 | if(!(exlist = exp())) { /* parse and compile the arguments */ | |
123 | fprintf(stderr, "find: parsing error\n"); | |
124 | exit(1); | |
125 | } | |
126 | if(Ai<argc) { | |
127 | fprintf(stderr, "find: missing conjunction\n"); | |
128 | exit(1); | |
129 | } | |
130 | for(Pi = 1; Pi < paths; ++Pi) { | |
131 | sp = 0; | |
132 | chdir(Home); | |
133 | strcpy(Pathname, Argv[Pi]); | |
134 | if(cp = rindex(Pathname, '/')) { | |
135 | sp = cp + 1; | |
136 | *cp = '\0'; | |
137 | if(chdir(*Pathname? Pathname: "/") == -1) { | |
138 | fprintf(stderr, "find: bad starting directory\n"); | |
139 | exit(2); | |
140 | } | |
141 | *cp = '/'; | |
142 | } | |
143 | Fname = sp? sp: Pathname; | |
b98da692 S |
144 | if (!Xdev) |
145 | stat(Pathname, &Devstat); | |
c08d5d47 BJ |
146 | descend(Pathname, Fname, exlist); /* to find files that match */ |
147 | } | |
148 | if(Cpio) { | |
149 | strcpy(Pathname, "TRAILER!!!"); | |
150 | Statb.st_size = 0; | |
151 | cpio(); | |
152 | printf("%D blocks\n", Blocks*10); | |
153 | } | |
154 | exit(0); | |
155 | } | |
156 | ||
157 | /* compile time functions: priority is exp()<e1()<e2()<e3() */ | |
158 | ||
159 | struct anode *exp() { /* parse ALTERNATION (-o) */ | |
160 | int or(); | |
161 | register struct anode * p1; | |
162 | ||
163 | p1 = e1() /* get left operand */ ; | |
164 | if(EQ(nxtarg(), "-o")) { | |
165 | Randlast--; | |
166 | return(mk(or, p1, exp())); | |
167 | } | |
168 | else if(Ai <= Argc) --Ai; | |
169 | return(p1); | |
170 | } | |
171 | struct anode *e1() { /* parse CONCATENATION (formerly -a) */ | |
172 | int and(); | |
173 | register struct anode * p1; | |
174 | register char *a; | |
175 | ||
176 | p1 = e2(); | |
177 | a = nxtarg(); | |
178 | if(EQ(a, "-a")) { | |
179 | And: | |
180 | Randlast--; | |
181 | return(mk(and, p1, e1())); | |
182 | } else if(EQ(a, "(") || EQ(a, "!") || (*a=='-' && !EQ(a, "-o"))) { | |
183 | --Ai; | |
184 | goto And; | |
185 | } else if(Ai <= Argc) --Ai; | |
186 | return(p1); | |
187 | } | |
188 | struct anode *e2() { /* parse NOT (!) */ | |
189 | int not(); | |
190 | ||
191 | if(Randlast) { | |
192 | fprintf(stderr, "find: operand follows operand\n"); | |
193 | exit(1); | |
194 | } | |
195 | Randlast++; | |
196 | if(EQ(nxtarg(), "!")) | |
197 | return(mk(not, e3(), (struct anode *)0)); | |
198 | else if(Ai <= Argc) --Ai; | |
199 | return(e3()); | |
200 | } | |
201 | struct anode *e3() { /* parse parens and predicates */ | |
202 | int exeq(), ok(), glob(), mtime(), atime(), user(), | |
203 | group(), size(), perm(), links(), print(), | |
f731b76e | 204 | type(), ino(), cpio(), newer(), |
b98da692 | 205 | nouser(), nogroup(), ls(), dummy(); |
c08d5d47 BJ |
206 | struct anode *p1; |
207 | int i; | |
6543b56c JL |
208 | register char *a, *b; |
209 | register int s; | |
c08d5d47 BJ |
210 | |
211 | a = nxtarg(); | |
212 | if(EQ(a, "(")) { | |
213 | Randlast--; | |
214 | p1 = exp(); | |
215 | a = nxtarg(); | |
216 | if(!EQ(a, ")")) goto err; | |
217 | return(p1); | |
218 | } | |
219 | else if(EQ(a, "-print")) { | |
220 | return(mk(print, (struct anode *)0, (struct anode *)0)); | |
221 | } | |
b98da692 S |
222 | else if (EQ(a, "-nouser")) { |
223 | return (mk(nouser, (struct anode *)0, (struct anode *)0)); | |
224 | } | |
225 | else if (EQ(a, "-nogroup")) { | |
226 | return (mk(nogroup, (struct anode *)0, (struct anode *)0)); | |
227 | } | |
228 | else if (EQ(a, "-ls")) { | |
229 | return (mk(ls, (struct anode *)0, (struct anode *)0)); | |
230 | } | |
231 | else if (EQ(a, "-xdev")) { | |
232 | Xdev = 0; | |
233 | return (mk(dummy, (struct anode *)0, (struct anode *)0)); | |
234 | } | |
f731b76e MT |
235 | else if (EQ(a, "-follow")) { |
236 | follow=1; | |
237 | return mk(dummy, (struct anode *)0, (struct anode *)0); | |
238 | } | |
c08d5d47 BJ |
239 | b = nxtarg(); |
240 | s = *b; | |
241 | if(s=='+') b++; | |
242 | if(EQ(a, "-name")) | |
243 | return(mk(glob, (struct anode *)b, (struct anode *)0)); | |
244 | else if(EQ(a, "-mtime")) | |
245 | return(mk(mtime, (struct anode *)atoi(b), (struct anode *)s)); | |
246 | else if(EQ(a, "-atime")) | |
247 | return(mk(atime, (struct anode *)atoi(b), (struct anode *)s)); | |
248 | else if(EQ(a, "-user")) { | |
b98da692 | 249 | if((i=getuid(b)) == -1) { |
68791ee2 | 250 | if(gmatch(b, "[0-9]*")) |
c08d5d47 BJ |
251 | return mk(user, (struct anode *)atoi(b), (struct anode *)s); |
252 | fprintf(stderr, "find: cannot find -user name\n"); | |
253 | exit(1); | |
254 | } | |
255 | return(mk(user, (struct anode *)i, (struct anode *)s)); | |
256 | } | |
257 | else if(EQ(a, "-inum")) | |
258 | return(mk(ino, (struct anode *)atoi(b), (struct anode *)s)); | |
259 | else if(EQ(a, "-group")) { | |
b98da692 | 260 | if((i=getgid(b)) == -1) { |
85e30eca | 261 | if(gmatch(b, "[0-9]*")) |
c08d5d47 BJ |
262 | return mk(group, (struct anode *)atoi(b), (struct anode *)s); |
263 | fprintf(stderr, "find: cannot find -group name\n"); | |
264 | exit(1); | |
265 | } | |
266 | return(mk(group, (struct anode *)i, (struct anode *)s)); | |
267 | } else if(EQ(a, "-size")) | |
268 | return(mk(size, (struct anode *)atoi(b), (struct anode *)s)); | |
269 | else if(EQ(a, "-links")) | |
270 | return(mk(links, (struct anode *)atoi(b), (struct anode *)s)); | |
271 | else if(EQ(a, "-perm")) { | |
272 | for(i=0; *b ; ++b) { | |
273 | if(*b=='-') continue; | |
274 | i <<= 3; | |
275 | i = i + (*b - '0'); | |
276 | } | |
277 | return(mk(perm, (struct anode *)i, (struct anode *)s)); | |
278 | } | |
279 | else if(EQ(a, "-type")) { | |
280 | i = s=='d' ? S_IFDIR : | |
281 | s=='b' ? S_IFBLK : | |
282 | s=='c' ? S_IFCHR : | |
773a4280 KM |
283 | s=='f' ? S_IFREG : |
284 | s=='l' ? S_IFLNK : | |
e8e4232e | 285 | s=='s' ? S_IFSOCK : |
c08d5d47 BJ |
286 | 0; |
287 | return(mk(type, (struct anode *)i, (struct anode *)0)); | |
288 | } | |
289 | else if (EQ(a, "-exec")) { | |
290 | i = Ai - 1; | |
291 | while(!EQ(nxtarg(), ";")); | |
292 | return(mk(exeq, (struct anode *)i, (struct anode *)0)); | |
293 | } | |
294 | else if (EQ(a, "-ok")) { | |
295 | i = Ai - 1; | |
296 | while(!EQ(nxtarg(), ";")); | |
297 | return(mk(ok, (struct anode *)i, (struct anode *)0)); | |
298 | } | |
299 | else if(EQ(a, "-cpio")) { | |
300 | if((Cpio = creat(b, 0666)) < 0) { | |
301 | fprintf(stderr, "find: cannot create < %s >\n", s); | |
302 | exit(1); | |
303 | } | |
304 | Buf = (short *)sbrk(512); | |
305 | Wp = Dbuf = (short *)sbrk(5120); | |
306 | return(mk(cpio, (struct anode *)0, (struct anode *)0)); | |
307 | } | |
308 | else if(EQ(a, "-newer")) { | |
309 | if(stat(b, &Statb) < 0) { | |
310 | fprintf(stderr, "find: cannot access < %s >\n", b); | |
311 | exit(1); | |
312 | } | |
313 | Newer = Statb.st_mtime; | |
314 | return mk(newer, (struct anode *)0, (struct anode *)0); | |
315 | } | |
316 | err: fprintf(stderr, "find: bad option < %s >\n", a); | |
317 | exit(1); | |
318 | } | |
319 | struct anode *mk(f, l, r) | |
320 | int (*f)(); | |
321 | struct anode *l, *r; | |
322 | { | |
b98da692 S |
323 | if (Nn >= MAXNODES) { |
324 | fprintf(stderr, "find: Too many options\n"); | |
325 | exit(1); | |
326 | } | |
327 | ||
c08d5d47 BJ |
328 | Node[Nn].F = f; |
329 | Node[Nn].L = l; | |
330 | Node[Nn].R = r; | |
331 | return(&(Node[Nn++])); | |
332 | } | |
333 | ||
334 | char *nxtarg() { /* get next arg from command line */ | |
335 | static strikes = 0; | |
336 | ||
337 | if(strikes==3) { | |
338 | fprintf(stderr, "find: incomplete statement\n"); | |
339 | exit(1); | |
340 | } | |
341 | if(Ai>=Argc) { | |
342 | strikes++; | |
343 | Ai = Argc + 1; | |
344 | return(""); | |
345 | } | |
346 | return(Argv[Ai++]); | |
347 | } | |
348 | ||
349 | /* execution time functions */ | |
350 | and(p) | |
351 | register struct anode *p; | |
352 | { | |
353 | return(((*p->L->F)(p->L)) && ((*p->R->F)(p->R))?1:0); | |
354 | } | |
355 | or(p) | |
356 | register struct anode *p; | |
357 | { | |
358 | return(((*p->L->F)(p->L)) || ((*p->R->F)(p->R))?1:0); | |
359 | } | |
360 | not(p) | |
361 | register struct anode *p; | |
362 | { | |
363 | return( !((*p->L->F)(p->L))); | |
364 | } | |
365 | glob(p) | |
366 | register struct { int f; char *pat; } *p; | |
367 | { | |
368 | return(gmatch(Fname, p->pat)); | |
369 | } | |
b98da692 S |
370 | print(p) |
371 | struct anode *p; | |
c08d5d47 BJ |
372 | { |
373 | puts(Pathname); | |
374 | return(1); | |
375 | } | |
376 | mtime(p) | |
377 | register struct { int f, t, s; } *p; | |
378 | { | |
379 | return(scomp((int)((Now - Statb.st_mtime) / A_DAY), p->t, p->s)); | |
380 | } | |
381 | atime(p) | |
382 | register struct { int f, t, s; } *p; | |
383 | { | |
384 | return(scomp((int)((Now - Statb.st_atime) / A_DAY), p->t, p->s)); | |
385 | } | |
386 | user(p) | |
387 | register struct { int f, u, s; } *p; | |
388 | { | |
389 | return(scomp(Statb.st_uid, p->u, p->s)); | |
390 | } | |
b98da692 S |
391 | nouser(p) |
392 | struct anode *p; | |
393 | { | |
394 | char *getname(); | |
395 | ||
396 | return (getname(Statb.st_uid) == NULL); | |
397 | } | |
c08d5d47 BJ |
398 | ino(p) |
399 | register struct { int f, u, s; } *p; | |
400 | { | |
401 | return(scomp((int)Statb.st_ino, p->u, p->s)); | |
402 | } | |
403 | group(p) | |
404 | register struct { int f, u; } *p; | |
405 | { | |
406 | return(p->u == Statb.st_gid); | |
407 | } | |
b98da692 S |
408 | nogroup(p) |
409 | struct anode *p; | |
410 | { | |
411 | char *getgroup(); | |
412 | ||
413 | return (getgroup(Statb.st_gid) == NULL); | |
414 | } | |
c08d5d47 BJ |
415 | links(p) |
416 | register struct { int f, link, s; } *p; | |
417 | { | |
418 | return(scomp(Statb.st_nlink, p->link, p->s)); | |
419 | } | |
420 | size(p) | |
421 | register struct { int f, sz, s; } *p; | |
422 | { | |
423 | return(scomp((int)((Statb.st_size+511)>>9), p->sz, p->s)); | |
424 | } | |
425 | perm(p) | |
426 | register struct { int f, per, s; } *p; | |
427 | { | |
428 | register i; | |
429 | i = (p->s=='-') ? p->per : 07777; /* '-' means only arg bits */ | |
430 | return((Statb.st_mode & i & 07777) == p->per); | |
431 | } | |
432 | type(p) | |
433 | register struct { int f, per, s; } *p; | |
434 | { | |
435 | return((Statb.st_mode&S_IFMT)==p->per); | |
436 | } | |
437 | exeq(p) | |
438 | register struct { int f, com; } *p; | |
439 | { | |
440 | fflush(stdout); /* to flush possible `-print' */ | |
441 | return(doex(p->com)); | |
442 | } | |
443 | ok(p) | |
444 | struct { int f, com; } *p; | |
445 | { | |
446 | char c; int yes; | |
447 | yes = 0; | |
448 | fflush(stdout); /* to flush possible `-print' */ | |
449 | fprintf(stderr, "< %s ... %s > ? ", Argv[p->com], Pathname); | |
450 | fflush(stderr); | |
451 | if((c=getchar())=='y') yes = 1; | |
452 | while(c!='\n') c = getchar(); | |
453 | if(yes) return(doex(p->com)); | |
454 | return(0); | |
455 | } | |
456 | ||
457 | #define MKSHORT(v, lv) {U.l=1L;if(U.c[0]) U.l=lv, v[0]=U.s[1], v[1]=U.s[0]; else U.l=lv, v[0]=U.s[0], v[1]=U.s[1];} | |
458 | union { long l; short s[2]; char c[4]; } U; | |
459 | long mklong(v) | |
460 | short v[]; | |
461 | { | |
462 | U.l = 1; | |
463 | if(U.c[0] /* VAX */) | |
464 | U.s[0] = v[1], U.s[1] = v[0]; | |
465 | else | |
466 | U.s[0] = v[0], U.s[1] = v[1]; | |
467 | return U.l; | |
468 | } | |
b98da692 S |
469 | cpio(p) |
470 | struct anode *p; | |
c08d5d47 BJ |
471 | { |
472 | #define MAGIC 070707 | |
473 | struct header { | |
474 | short h_magic, | |
475 | h_dev, | |
476 | h_ino, | |
477 | h_mode, | |
478 | h_uid, | |
479 | h_gid, | |
480 | h_nlink, | |
481 | h_rdev; | |
482 | short h_mtime[2]; | |
483 | short h_namesize; | |
484 | short h_filesize[2]; | |
485 | char h_name[256]; | |
486 | } hdr; | |
487 | register ifile, ct; | |
488 | static long fsz; | |
489 | register i; | |
490 | ||
491 | hdr.h_magic = MAGIC; | |
492 | strcpy(hdr.h_name, !strncmp(Pathname, "./", 2)? Pathname+2: Pathname); | |
493 | hdr.h_namesize = strlen(hdr.h_name) + 1; | |
494 | hdr.h_uid = Statb.st_uid; | |
495 | hdr.h_gid = Statb.st_gid; | |
496 | hdr.h_dev = Statb.st_dev; | |
497 | hdr.h_ino = Statb.st_ino; | |
498 | hdr.h_mode = Statb.st_mode; | |
499 | MKSHORT(hdr.h_mtime, Statb.st_mtime); | |
500 | hdr.h_nlink = Statb.st_nlink; | |
501 | fsz = hdr.h_mode & S_IFREG? Statb.st_size: 0L; | |
502 | MKSHORT(hdr.h_filesize, fsz); | |
503 | hdr.h_rdev = Statb.st_rdev; | |
504 | if(EQ(hdr.h_name, "TRAILER!!!")) { | |
505 | bwrite((short *)&hdr, (sizeof hdr-256)+hdr.h_namesize); | |
506 | for(i = 0; i < 10; ++i) | |
507 | bwrite(Buf, 512); | |
508 | return; | |
509 | } | |
510 | if(!mklong(hdr.h_filesize)) | |
511 | return; | |
512 | if((ifile = open(Fname, 0)) < 0) { | |
513 | cerror: | |
514 | fprintf(stderr, "find: cannot copy < %s >\n", hdr.h_name); | |
515 | return; | |
516 | } | |
517 | bwrite((short *)&hdr, (sizeof hdr-256)+hdr.h_namesize); | |
518 | for(fsz = mklong(hdr.h_filesize); fsz > 0; fsz -= 512) { | |
519 | ct = fsz>512? 512: fsz; | |
520 | if(read(ifile, (char *)Buf, ct) < 0) | |
521 | goto cerror; | |
522 | bwrite(Buf, ct); | |
523 | } | |
524 | close(ifile); | |
525 | return; | |
526 | } | |
b98da692 S |
527 | newer(p) |
528 | struct anode *p; | |
c08d5d47 BJ |
529 | { |
530 | return Statb.st_mtime > Newer; | |
531 | } | |
b98da692 S |
532 | ls(p) |
533 | struct anode *p; | |
534 | { | |
535 | list(Pathname, &Statb); | |
536 | return (1); | |
537 | } | |
538 | dummy(p) | |
539 | struct anode *p; | |
540 | { | |
541 | /* dummy */ | |
542 | return (1); | |
543 | } | |
c08d5d47 BJ |
544 | |
545 | /* support functions */ | |
546 | scomp(a, b, s) /* funny signed compare */ | |
547 | register a, b; | |
548 | register char s; | |
549 | { | |
550 | if(s == '+') | |
551 | return(a > b); | |
552 | if(s == '-') | |
553 | return(a < (b * -1)); | |
554 | return(a == b); | |
555 | } | |
556 | ||
557 | doex(com) | |
558 | { | |
559 | register np; | |
560 | register char *na; | |
561 | static char *nargv[50]; | |
562 | static ccode; | |
ea68db4b | 563 | register int w, pid, omask; |
c08d5d47 BJ |
564 | |
565 | ccode = np = 0; | |
566 | while (na=Argv[com++]) { | |
b98da692 | 567 | if(np >= sizeof nargv / sizeof *nargv - 1) break; |
c08d5d47 BJ |
568 | if(strcmp(na, ";")==0) break; |
569 | if(strcmp(na, "{}")==0) nargv[np++] = Pathname; | |
570 | else nargv[np++] = na; | |
571 | } | |
572 | nargv[np] = 0; | |
573 | if (np==0) return(9); | |
b98da692 S |
574 | switch (pid = vfork()) { |
575 | case -1: | |
576 | perror("find: Can't fork"); | |
577 | exit(1); | |
578 | break; | |
579 | ||
580 | case 0: | |
c08d5d47 BJ |
581 | chdir(Home); |
582 | execvp(nargv[0], nargv, np); | |
ea68db4b KM |
583 | write(2, "find: Can't execute ", 20); |
584 | perror(nargv[0]); | |
585 | /* | |
586 | * Kill ourselves; our exit status will be a suicide | |
587 | * note indicating we couldn't do the "exec". | |
588 | */ | |
589 | kill(getpid(), SIGUSR1); | |
b98da692 S |
590 | break; |
591 | ||
592 | default: | |
ea68db4b | 593 | omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)); |
b98da692 S |
594 | while ((w = wait(&ccode)) != pid && w != -1) |
595 | ; | |
ea68db4b KM |
596 | (void) sigsetmask(omask); |
597 | if ((ccode & 0177) == SIGUSR1) | |
b98da692 | 598 | exit(1); |
b98da692 | 599 | return (ccode != 0 ? 0 : 1); |
c08d5d47 | 600 | } |
c08d5d47 BJ |
601 | } |
602 | ||
603 | getunum(f, s) char *f, *s; { /* find user/group name and return number */ | |
604 | register i; | |
605 | register char *sp; | |
606 | register c; | |
607 | char str[20]; | |
608 | FILE *pin; | |
609 | ||
610 | i = -1; | |
611 | pin = fopen(f, "r"); | |
612 | c = '\n'; /* prime with a CR */ | |
613 | do { | |
614 | if(c=='\n') { | |
615 | sp = str; | |
616 | while((c = *sp++ = getc(pin)) != ':') | |
617 | if(c == EOF) goto RET; | |
618 | *--sp = '\0'; | |
619 | if(EQ(str, s)) { | |
620 | while((c=getc(pin)) != ':') | |
621 | if(c == EOF) goto RET; | |
622 | sp = str; | |
623 | while((*sp = getc(pin)) != ':') sp++; | |
624 | *sp = '\0'; | |
625 | i = atoi(str); | |
626 | goto RET; | |
627 | } | |
628 | } | |
629 | } while((c = getc(pin)) != EOF); | |
630 | RET: | |
631 | fclose(pin); | |
632 | return(i); | |
633 | } | |
634 | ||
635 | descend(name, fname, exlist) | |
365a571b KM |
636 | struct anode *exlist; |
637 | char *name, *fname; | |
c08d5d47 | 638 | { |
365a571b | 639 | DIR *dir = NULL; |
c08d5d47 | 640 | register struct direct *dp; |
365a571b | 641 | register char *c1; |
c08d5d47 BJ |
642 | int rv = 0; |
643 | char *endofname; | |
644 | ||
f731b76e | 645 | if ((follow?stat(fname, &Statb):lstat(fname, &Statb))<0) { |
c08d5d47 BJ |
646 | fprintf(stderr, "find: bad status < %s >\n", name); |
647 | return(0); | |
648 | } | |
649 | (*exlist->F)(exlist); | |
b98da692 S |
650 | if((Statb.st_mode&S_IFMT)!=S_IFDIR || |
651 | !Xdev && Devstat.st_dev != Statb.st_dev) | |
c08d5d47 BJ |
652 | return(1); |
653 | ||
44ac974b KB |
654 | if (Statb.st_nlink == 2 && exlist->F == and && |
655 | exlist->L->F == type && ((int) (exlist->L->L)) == S_IFDIR) | |
656 | return(1); | |
657 | ||
365a571b KM |
658 | for (c1 = name; *c1; ++c1); |
659 | if (*(c1-1) == '/') | |
c08d5d47 BJ |
660 | --c1; |
661 | endofname = c1; | |
c08d5d47 | 662 | |
365a571b | 663 | if (chdir(fname) == -1) |
c08d5d47 | 664 | return(0); |
365a571b KM |
665 | if ((dir = opendir(".")) == NULL) { |
666 | fprintf(stderr, "find: cannot open < %s >\n", name); | |
667 | rv = 0; | |
668 | goto ret; | |
669 | } | |
670 | for (dp = readdir(dir); dp != NULL; dp = readdir(dir)) { | |
671 | if ((dp->d_name[0]=='.' && dp->d_name[1]=='\0') || | |
672 | (dp->d_name[0]=='.' && dp->d_name[1]=='.' && dp->d_name[2]=='\0')) | |
673 | continue; | |
674 | c1 = endofname; | |
675 | *c1++ = '/'; | |
676 | strcpy(c1, dp->d_name); | |
677 | Fname = endofname+1; | |
678 | if(!descend(name, Fname, exlist)) { | |
679 | *endofname = '\0'; | |
680 | chdir(Home); | |
681 | if(chdir(Pathname) == -1) { | |
682 | fprintf(stderr, "find: bad directory tree\n"); | |
683 | exit(1); | |
c08d5d47 BJ |
684 | } |
685 | } | |
686 | } | |
687 | rv = 1; | |
688 | ret: | |
689 | if(dir) | |
365a571b | 690 | closedir(dir); |
c08d5d47 BJ |
691 | if(chdir("..") == -1) { |
692 | *endofname = '\0'; | |
693 | fprintf(stderr, "find: bad directory <%s>\n", name); | |
694 | rv = 1; | |
695 | } | |
696 | return(rv); | |
697 | } | |
698 | ||
699 | gmatch(s, p) /* string match as in glob */ | |
700 | register char *s, *p; | |
701 | { | |
702 | if (*s=='.' && *p!='.') return(0); | |
703 | return amatch(s, p); | |
704 | } | |
705 | ||
706 | amatch(s, p) | |
707 | register char *s, *p; | |
708 | { | |
709 | register cc; | |
710 | int scc, k; | |
711 | int c, lc; | |
712 | ||
713 | scc = *s; | |
714 | lc = 077777; | |
715 | switch (c = *p) { | |
716 | ||
717 | case '[': | |
718 | k = 0; | |
719 | while (cc = *++p) { | |
720 | switch (cc) { | |
721 | ||
722 | case ']': | |
723 | if (k) | |
724 | return(amatch(++s, ++p)); | |
725 | else | |
726 | return(0); | |
727 | ||
728 | case '-': | |
6c57dc2b KM |
729 | cc = p[1]; |
730 | k |= lc <= scc && scc <= cc; | |
c08d5d47 BJ |
731 | } |
732 | if (scc==(lc=cc)) k++; | |
733 | } | |
734 | return(0); | |
735 | ||
736 | case '?': | |
737 | caseq: | |
738 | if(scc) return(amatch(++s, ++p)); | |
739 | return(0); | |
740 | case '*': | |
741 | return(umatch(s, ++p)); | |
742 | case 0: | |
743 | return(!scc); | |
744 | } | |
745 | if (c==scc) goto caseq; | |
746 | return(0); | |
747 | } | |
748 | ||
749 | umatch(s, p) | |
750 | register char *s, *p; | |
751 | { | |
752 | if(*p==0) return(1); | |
753 | while(*s) | |
754 | if (amatch(s++, p)) return(1); | |
755 | return(0); | |
756 | } | |
757 | ||
758 | bwrite(rp, c) | |
759 | register short *rp; | |
760 | register c; | |
761 | { | |
762 | register short *wp = Wp; | |
763 | ||
764 | c = (c+1) >> 1; | |
765 | while(c--) { | |
766 | if(!Wct) { | |
767 | again: | |
768 | if(write(Cpio, (char *)Dbuf, Bufsize)<0) { | |
769 | Cpio = chgreel(1, Cpio); | |
770 | goto again; | |
771 | } | |
772 | Wct = Bufsize >> 1; | |
773 | wp = Dbuf; | |
774 | ++Blocks; | |
775 | } | |
776 | *wp++ = *rp++; | |
777 | --Wct; | |
778 | } | |
779 | Wp = wp; | |
780 | } | |
781 | chgreel(x, fl) | |
782 | { | |
783 | register f; | |
784 | char str[22]; | |
785 | FILE *devtty; | |
786 | struct stat statb; | |
787 | extern errno; | |
788 | ||
789 | fprintf(stderr, "find: errno: %d, ", errno); | |
790 | fprintf(stderr, "find: can't %s\n", x? "write output": "read input"); | |
791 | fstat(fl, &statb); | |
792 | if((statb.st_mode&S_IFMT) != S_IFCHR) | |
793 | exit(1); | |
794 | again: | |
795 | fprintf(stderr, "If you want to go on, type device/file name %s\n", | |
796 | "when ready"); | |
d0e5d403 | 797 | devtty = fopen(_PATH_TTY, "r"); |
c08d5d47 BJ |
798 | fgets(str, 20, devtty); |
799 | str[strlen(str) - 1] = '\0'; | |
800 | if(!*str) | |
801 | exit(1); | |
802 | close(fl); | |
803 | if((f = open(str, x? 1: 0)) < 0) { | |
804 | fprintf(stderr, "That didn't work"); | |
805 | fclose(devtty); | |
806 | goto again; | |
807 | } | |
808 | return f; | |
809 | } | |
46b257b1 KM |
810 | |
811 | #ifdef AMES | |
812 | /* | |
813 | * 'fastfind' scans a file list for the full pathname of a file | |
814 | * given only a piece of the name. The list has been processed with | |
815 | * with "front-compression" and bigram coding. Front compression reduces | |
816 | * space by a factor of 4-5, bigram coding by a further 20-25%. | |
817 | * The codes are: | |
818 | * | |
819 | * 0-28 likeliest differential counts + offset to make nonnegative | |
25d63f56 JK |
820 | * 30 switch code for out-of-range count to follow in next word |
821 | * 128-255 bigram codes (128 most common, as determined by 'updatedb') | |
822 | * 32-127 single character (printable) ascii residue (ie, literal) | |
46b257b1 KM |
823 | * |
824 | * A novel two-tiered string search technique is employed: | |
825 | * | |
826 | * First, a metacharacter-free subpattern and partial pathname is | |
827 | * matched BACKWARDS to avoid full expansion of the pathname list. | |
828 | * The time savings is 40-50% over forward matching, which cannot efficiently | |
829 | * handle overlapped search patterns and compressed path residue. | |
830 | * | |
831 | * Then, the actual shell glob-style regular expression (if in this form) | |
832 | * is matched against the candidate pathnames using the slower routines | |
833 | * provided in the standard 'find'. | |
834 | */ | |
835 | ||
25d63f56 JK |
836 | #include "find.h" |
837 | ||
46b257b1 KM |
838 | #define YES 1 |
839 | #define NO 0 | |
46b257b1 KM |
840 | |
841 | fastfind ( pathpart ) | |
842 | char pathpart[]; | |
843 | { | |
844 | register char *p, *s; | |
845 | register int c; | |
846 | char *q, *index(), *patprep(); | |
25d63f56 | 847 | int count = 0, found = NO, globflag; |
46b257b1 KM |
848 | FILE *fp, *fopen(); |
849 | char *patend, *cutoff; | |
25d63f56 JK |
850 | char path[MAXPATHLEN]; |
851 | char bigram1[NBG], bigram2[NBG]; | |
46b257b1 | 852 | |
d0e5d403 | 853 | if ( (fp = fopen ( _PATH_FCODES, "r" )) == NULL ) { |
25d63f56 | 854 | perror( _PATH_FCODES ); |
46b257b1 KM |
855 | exit ( 1 ); |
856 | } | |
25d63f56 JK |
857 | for ( c = 0, p = bigram1, s = bigram2; c < NBG; c++ ) |
858 | p[c] = getc ( fp ), s[c] = getc ( fp ); | |
41a1140a | 859 | |
25d63f56 JK |
860 | p = pathpart; |
861 | globflag = index ( p, '*' ) || index ( p, '?' ) || index ( p, '[' ); | |
862 | patend = patprep ( p ); | |
46b257b1 | 863 | |
3fae70c0 | 864 | for ( c = getc ( fp ); c != EOF; ) { |
46b257b1 | 865 | |
25d63f56 | 866 | count += ( (c == SWITCH) ? getw ( fp ) : c ) - OFFSET; |
46b257b1 | 867 | |
25d63f56 JK |
868 | for ( p = path + count; (c = getc ( fp )) > SWITCH; ) /* overlay old path */ |
869 | if ( c < PARITY ) | |
46b257b1 | 870 | *p++ = c; |
25d63f56 JK |
871 | else { /* bigrams are parity-marked */ |
872 | c &= PARITY-1; | |
873 | *p++ = bigram1[c], *p++ = bigram2[c]; | |
874 | } | |
46b257b1 | 875 | *p-- = NULL; |
25d63f56 | 876 | cutoff = ( found ? path : path + count ); |
46b257b1 KM |
877 | |
878 | for ( found = NO, s = p; s >= cutoff; s-- ) | |
879 | if ( *s == *patend ) { /* fast first char check */ | |
880 | for ( p = patend - 1, q = s - 1; *p != NULL; p--, q-- ) | |
881 | if ( *q != *p ) | |
882 | break; | |
883 | if ( *p == NULL ) { /* success on fast match */ | |
884 | found = YES; | |
885 | if ( globflag == NO || amatch ( path, pathpart ) ) | |
886 | puts ( path ); | |
887 | break; | |
888 | } | |
889 | } | |
890 | } | |
891 | } | |
892 | ||
893 | /* | |
084103a7 KM |
894 | extract last glob-free subpattern in name for fast pre-match; |
895 | prepend '\0' for backwards match; return end of new pattern | |
46b257b1 KM |
896 | */ |
897 | static char globfree[100]; | |
898 | ||
899 | char * | |
084103a7 KM |
900 | patprep ( name ) |
901 | char *name; | |
46b257b1 | 902 | { |
084103a7 | 903 | register char *p, *endmark; |
46b257b1 KM |
904 | register char *subp = globfree; |
905 | ||
084103a7 KM |
906 | *subp++ = '\0'; |
907 | p = name + strlen ( name ) - 1; | |
908 | /* | |
909 | skip trailing metacharacters (and [] ranges) | |
910 | */ | |
911 | for ( ; p >= name; p-- ) | |
912 | if ( index ( "*?", *p ) == 0 ) | |
913 | break; | |
914 | if ( p < name ) | |
915 | p = name; | |
916 | if ( *p == ']' ) | |
917 | for ( p--; p >= name; p-- ) | |
918 | if ( *p == '[' ) { | |
919 | p--; | |
920 | break; | |
921 | } | |
922 | if ( p < name ) | |
923 | p = name; | |
924 | /* | |
925 | if pattern has only metacharacters, | |
926 | check every path (force '/' search) | |
927 | */ | |
928 | if ( (p == name) && index ( "?*[]", *p ) != 0 ) | |
929 | *subp++ = '/'; | |
930 | else { | |
931 | for ( endmark = p; p >= name; p-- ) | |
932 | if ( index ( "]*?", *p ) != 0 ) | |
933 | break; | |
934 | for ( ++p; (p <= endmark) && subp < (globfree + sizeof ( globfree )); ) | |
46b257b1 | 935 | *subp++ = *p++; |
084103a7 KM |
936 | } |
937 | *subp = '\0'; | |
46b257b1 KM |
938 | return ( --subp ); |
939 | } | |
940 | #endif | |
b98da692 S |
941 | |
942 | /* rest should be done with nameserver or database */ | |
943 | ||
944 | #include <pwd.h> | |
945 | #include <grp.h> | |
946 | #include <utmp.h> | |
947 | ||
948 | struct utmp utmp; | |
949 | #define NMAX (sizeof (utmp.ut_name)) | |
950 | #define SCPYN(a, b) strncpy(a, b, NMAX) | |
951 | ||
952 | #define NUID 64 | |
953 | #define NGID 300 | |
954 | ||
955 | struct ncache { | |
956 | int uid; | |
957 | char name[NMAX+1]; | |
958 | } nc[NUID]; | |
959 | char outrangename[NMAX+1]; | |
960 | int outrangeuid = -1; | |
961 | char groups[NGID][NMAX+1]; | |
962 | char outrangegroup[NMAX+1]; | |
963 | int outrangegid = -1; | |
964 | ||
965 | /* | |
966 | * This function assumes that the password file is hashed | |
967 | * (or some such) to allow fast access based on a name key. | |
968 | * If this isn't true, duplicate the code for getgroup(). | |
969 | */ | |
970 | char * | |
971 | getname(uid) | |
972 | { | |
973 | register struct passwd *pw; | |
974 | struct passwd *getpwent(); | |
975 | register int cp; | |
b98da692 | 976 | |
2d479d40 | 977 | #if (((NUID) & ((NUID) - 1)) != 0) |
b98da692 S |
978 | cp = uid % (NUID); |
979 | #else | |
980 | cp = uid & ((NUID) - 1); | |
981 | #endif | |
982 | if (uid >= 0 && nc[cp].uid == uid && nc[cp].name[0]) | |
983 | return (nc[cp].name); | |
984 | pw = getpwuid(uid); | |
985 | if (!pw) | |
986 | return (0); | |
987 | nc[cp].uid = uid; | |
988 | SCPYN(nc[cp].name, pw->pw_name); | |
989 | return (nc[cp].name); | |
990 | } | |
991 | ||
992 | char * | |
993 | getgroup(gid) | |
994 | { | |
995 | register struct group *gr; | |
996 | static init; | |
997 | struct group *getgrent(); | |
998 | ||
999 | if (gid >= 0 && gid < NGID && groups[gid][0]) | |
1000 | return (&groups[gid][0]); | |
1001 | if (gid >= 0 && gid == outrangegid) | |
1002 | return (outrangegroup); | |
1003 | rescan: | |
1004 | if (init == 2) { | |
1005 | if (gid < NGID) | |
1006 | return (0); | |
1007 | setgrent(); | |
1008 | while (gr = getgrent()) { | |
1009 | if (gr->gr_gid != gid) | |
1010 | continue; | |
1011 | outrangegid = gr->gr_gid; | |
1012 | SCPYN(outrangegroup, gr->gr_name); | |
1013 | endgrent(); | |
1014 | return (outrangegroup); | |
1015 | } | |
1016 | endgrent(); | |
1017 | return (0); | |
1018 | } | |
1019 | if (init == 0) | |
1020 | setgrent(), init = 1; | |
1021 | while (gr = getgrent()) { | |
1022 | if (gr->gr_gid < 0 || gr->gr_gid >= NGID) { | |
1023 | if (gr->gr_gid == gid) { | |
1024 | outrangegid = gr->gr_gid; | |
1025 | SCPYN(outrangegroup, gr->gr_name); | |
1026 | return (outrangegroup); | |
1027 | } | |
1028 | continue; | |
1029 | } | |
1030 | if (groups[gr->gr_gid][0]) | |
1031 | continue; | |
1032 | SCPYN(groups[gr->gr_gid], gr->gr_name); | |
1033 | if (gr->gr_gid == gid) | |
1034 | return (&groups[gid][0]); | |
1035 | } | |
1036 | init = 2; | |
1037 | goto rescan; | |
1038 | } | |
1039 | ||
1040 | int | |
1041 | getuid(username) | |
1042 | char *username; | |
1043 | { | |
1044 | register struct passwd *pw; | |
1045 | struct passwd *getpwnam(); | |
b98da692 S |
1046 | |
1047 | pw = getpwnam(username); | |
1048 | if (pw != NULL) | |
1049 | return (pw->pw_uid); | |
1050 | else | |
1051 | return (-1); | |
1052 | } | |
1053 | ||
1054 | int | |
1055 | getgid(groupname) | |
1056 | char *groupname; | |
1057 | { | |
1058 | register struct group *gr; | |
1059 | struct group *getgrnam(); | |
1060 | ||
1061 | gr = getgrnam(groupname); | |
1062 | if (gr != NULL) | |
1063 | return (gr->gr_gid); | |
1064 | else | |
1065 | return (-1); | |
1066 | } | |
1067 | ||
1068 | #define permoffset(who) ((who) * 3) | |
1069 | #define permission(who, type) ((type) >> permoffset(who)) | |
1070 | #define kbytes(bytes) (((bytes) + 1023) / 1024) | |
1071 | ||
1072 | list(file, stp) | |
1073 | char *file; | |
1074 | register struct stat *stp; | |
1075 | { | |
1076 | char pmode[32], uname[32], gname[32], fsize[32], ftime[32]; | |
1077 | char *getname(), *getgroup(), *ctime(); | |
1078 | static long special[] = { S_ISUID, 's', S_ISGID, 's', S_ISVTX, 't' }; | |
1079 | static time_t sixmonthsago = -1; | |
1080 | #ifdef S_IFLNK | |
1081 | char flink[MAXPATHLEN + 1]; | |
1082 | #endif | |
1083 | register int who; | |
1084 | register char *cp; | |
1085 | time_t now; | |
1086 | ||
1087 | if (file == NULL || stp == NULL) | |
1088 | return (-1); | |
1089 | ||
1090 | time(&now); | |
1091 | if (sixmonthsago == -1) | |
1092 | sixmonthsago = now - 6L*30L*24L*60L*60L; | |
1093 | ||
1094 | switch (stp->st_mode & S_IFMT) { | |
1095 | #ifdef S_IFDIR | |
1096 | case S_IFDIR: /* directory */ | |
1097 | pmode[0] = 'd'; | |
1098 | break; | |
1099 | #endif | |
1100 | #ifdef S_IFCHR | |
1101 | case S_IFCHR: /* character special */ | |
1102 | pmode[0] = 'c'; | |
1103 | break; | |
1104 | #endif | |
1105 | #ifdef S_IFBLK | |
1106 | case S_IFBLK: /* block special */ | |
1107 | pmode[0] = 'b'; | |
1108 | break; | |
1109 | #endif | |
1110 | #ifdef S_IFLNK | |
1111 | case S_IFLNK: /* symbolic link */ | |
1112 | pmode[0] = 'l'; | |
1113 | break; | |
1114 | #endif | |
1115 | #ifdef S_IFSOCK | |
1116 | case S_IFSOCK: /* socket */ | |
1117 | pmode[0] = 's'; | |
1118 | break; | |
1119 | #endif | |
1120 | #ifdef S_IFREG | |
1121 | case S_IFREG: /* regular */ | |
1122 | #endif | |
1123 | default: | |
1124 | pmode[0] = '-'; | |
1125 | break; | |
1126 | } | |
1127 | ||
1128 | for (who = 0; who < 3; who++) { | |
1129 | if (stp->st_mode & permission(who, S_IREAD)) | |
1130 | pmode[permoffset(who) + 1] = 'r'; | |
1131 | else | |
1132 | pmode[permoffset(who) + 1] = '-'; | |
1133 | ||
1134 | if (stp->st_mode & permission(who, S_IWRITE)) | |
1135 | pmode[permoffset(who) + 2] = 'w'; | |
1136 | else | |
1137 | pmode[permoffset(who) + 2] = '-'; | |
1138 | ||
1139 | if (stp->st_mode & special[who * 2]) | |
1140 | pmode[permoffset(who) + 3] = special[who * 2 + 1]; | |
1141 | else if (stp->st_mode & permission(who, S_IEXEC)) | |
1142 | pmode[permoffset(who) + 3] = 'x'; | |
1143 | else | |
1144 | pmode[permoffset(who) + 3] = '-'; | |
1145 | } | |
1146 | pmode[permoffset(who) + 1] = '\0'; | |
1147 | ||
1148 | cp = getname(stp->st_uid); | |
1149 | if (cp != NULL) | |
1150 | sprintf(uname, "%-9.9s", cp); | |
1151 | else | |
1152 | sprintf(uname, "%-9d", stp->st_uid); | |
1153 | ||
1154 | cp = getgroup(stp->st_gid); | |
1155 | if (cp != NULL) | |
1156 | sprintf(gname, "%-9.9s", cp); | |
1157 | else | |
1158 | sprintf(gname, "%-9d", stp->st_gid); | |
1159 | ||
1160 | if (pmode[0] == 'b' || pmode[0] == 'c') | |
1161 | sprintf(fsize, "%3d,%4d", | |
1162 | major(stp->st_rdev), minor(stp->st_rdev)); | |
1163 | else { | |
1164 | sprintf(fsize, "%8ld", stp->st_size); | |
1165 | #ifdef S_IFLNK | |
1166 | if (pmode[0] == 'l') { | |
b1e9ea21 JB |
1167 | /* |
1168 | * Need to get the tail of the file name, since we have | |
1169 | * already chdir()ed into the directory of the file | |
1170 | */ | |
1171 | cp = rindex(file, '/'); | |
1172 | if (cp == NULL) | |
1173 | cp = file; | |
1174 | else | |
1175 | cp++; | |
1176 | who = readlink(cp, flink, sizeof flink - 1); | |
b98da692 S |
1177 | if (who >= 0) |
1178 | flink[who] = '\0'; | |
b1e9ea21 JB |
1179 | else |
1180 | flink[0] = '\0'; | |
b98da692 S |
1181 | } |
1182 | #endif | |
1183 | } | |
1184 | ||
1185 | cp = ctime(&stp->st_mtime); | |
1186 | if (stp->st_mtime < sixmonthsago || stp->st_mtime > now) | |
1187 | sprintf(ftime, "%-7.7s %-4.4s", cp + 4, cp + 20); | |
1188 | else | |
1189 | sprintf(ftime, "%-12.12s", cp + 4); | |
1190 | ||
1191 | printf("%5lu %4ld %s %2d %s%s%s %s %s%s%s\n", | |
1192 | stp->st_ino, /* inode # */ | |
1193 | #ifdef S_IFSOCK | |
1194 | (long) kbytes(dbtob(stp->st_blocks)), /* kbytes */ | |
1195 | #else | |
1196 | (long) kbytes(stp->st_size), /* kbytes */ | |
1197 | #endif | |
1198 | pmode, /* protection */ | |
1199 | stp->st_nlink, /* # of links */ | |
1200 | uname, /* owner */ | |
1201 | gname, /* group */ | |
1202 | fsize, /* # of bytes */ | |
1203 | ftime, /* modify time */ | |
1204 | file, /* name */ | |
1205 | #ifdef S_IFLNK | |
1206 | (pmode[0] == 'l') ? " -> " : "", | |
1207 | (pmode[0] == 'l') ? flink : "" /* symlink */ | |
1208 | #else | |
1209 | "", | |
1210 | "" | |
1211 | #endif | |
1212 | ); | |
1213 | ||
1214 | return (0); | |
1215 | } |