function.c (0da30e9aa76c5df66cd092f30b904824b0594ccc) function.c (841484cd4291e19802fb976f22b28d5dc6706468)
1/*-
2 * Copyright (c) 1990, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Cimarron D. Taylor of the University of California, Berkeley.
7 *
8 * Redistribution and use in source and binary forms, with or without

--- 39 unchanged lines hidden (view full) ---

48#include <errno.h>
49#include <fnmatch.h>
50#include <fts.h>
51#include <grp.h>
52#include <pwd.h>
53#include <stdio.h>
54#include <stdlib.h>
55#include <string.h>
1/*-
2 * Copyright (c) 1990, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Cimarron D. Taylor of the University of California, Berkeley.
7 *
8 * Redistribution and use in source and binary forms, with or without

--- 39 unchanged lines hidden (view full) ---

48#include <errno.h>
49#include <fnmatch.h>
50#include <fts.h>
51#include <grp.h>
52#include <pwd.h>
53#include <stdio.h>
54#include <stdlib.h>
55#include <string.h>
56#include <tzfile.h>
57#include <unistd.h>
58
59#include "find.h"
60
61#define COMPARE(a, b) { \
62 switch (plan->flags) { \
63 case F_EQUAL: \
64 return (a == b); \

--- 7 unchanged lines hidden (view full) ---

72}
73
74static PLAN *palloc __P((enum ntype, int (*) __P((PLAN *, FTSENT *))));
75
76/*
77 * find_parsenum --
78 * Parse a string of the form [+-]# and return the value.
79 */
56#include <unistd.h>
57
58#include "find.h"
59
60#define COMPARE(a, b) { \
61 switch (plan->flags) { \
62 case F_EQUAL: \
63 return (a == b); \

--- 7 unchanged lines hidden (view full) ---

71}
72
73static PLAN *palloc __P((enum ntype, int (*) __P((PLAN *, FTSENT *))));
74
75/*
76 * find_parsenum --
77 * Parse a string of the form [+-]# and return the value.
78 */
80static long
79static long long
81find_parsenum(plan, option, vp, endch)
82 PLAN *plan;
83 char *option, *vp, *endch;
84{
80find_parsenum(plan, option, vp, endch)
81 PLAN *plan;
82 char *option, *vp, *endch;
83{
85 long value;
84 long long value;
86 char *endchar, *str; /* Pointer to character ending conversion. */
85 char *endchar, *str; /* Pointer to character ending conversion. */
87
86
88 /* Determine comparison from leading + or -. */
89 str = vp;
90 switch (*str) {
91 case '+':
92 ++str;
93 plan->flags = F_GREATER;
94 break;
95 case '-':
96 ++str;
97 plan->flags = F_LESSTHAN;
98 break;
99 default:
100 plan->flags = F_EQUAL;
101 break;
102 }
87 /* Determine comparison from leading + or -. */
88 str = vp;
89 switch (*str) {
90 case '+':
91 ++str;
92 plan->flags = F_GREATER;
93 break;
94 case '-':
95 ++str;
96 plan->flags = F_LESSTHAN;
97 break;
98 default:
99 plan->flags = F_EQUAL;
100 break;
101 }
103
102
104 /*
103 /*
105 * Convert the string with strtol(). Note, if strtol() returns zero
104 * Convert the string with strtoq(). Note, if strtoq() returns zero
106 * and endchar points to the beginning of the string we know we have
107 * a syntax error.
108 */
105 * and endchar points to the beginning of the string we know we have
106 * a syntax error.
107 */
109 value = strtol(str, &endchar, 10);
108 value = strtoq(str, &endchar, 10);
110 if (value == 0 && endchar == str)
111 errx(1, "%s: %s: illegal numeric value", option, vp);
112 if (endchar[0] && (endch == NULL || endchar[0] != *endch))
113 errx(1, "%s: %s: illegal trailing character", option, vp);
114 if (endch)
115 *endch = endchar[0];
116 return (value);
117}

--- 17 unchanged lines hidden (view full) ---

135int
136f_atime(plan, entry)
137 PLAN *plan;
138 FTSENT *entry;
139{
140 extern time_t now;
141
142 COMPARE((now - entry->fts_statp->st_atime +
109 if (value == 0 && endchar == str)
110 errx(1, "%s: %s: illegal numeric value", option, vp);
111 if (endchar[0] && (endch == NULL || endchar[0] != *endch))
112 errx(1, "%s: %s: illegal trailing character", option, vp);
113 if (endch)
114 *endch = endchar[0];
115 return (value);
116}

--- 17 unchanged lines hidden (view full) ---

134int
135f_atime(plan, entry)
136 PLAN *plan;
137 FTSENT *entry;
138{
139 extern time_t now;
140
141 COMPARE((now - entry->fts_statp->st_atime +
143 SECSPERDAY - 1) / SECSPERDAY, plan->t_data);
142 86400 - 1) / 86400, plan->t_data);
144}
143}
145
144
146PLAN *
147c_atime(arg)
148 char *arg;
149{
150 PLAN *new;
151
152 ftsoptions &= ~FTS_NOSTAT;
153

--- 11 unchanged lines hidden (view full) ---

165int
166f_ctime(plan, entry)
167 PLAN *plan;
168 FTSENT *entry;
169{
170 extern time_t now;
171
172 COMPARE((now - entry->fts_statp->st_ctime +
145PLAN *
146c_atime(arg)
147 char *arg;
148{
149 PLAN *new;
150
151 ftsoptions &= ~FTS_NOSTAT;
152

--- 11 unchanged lines hidden (view full) ---

164int
165f_ctime(plan, entry)
166 PLAN *plan;
167 FTSENT *entry;
168{
169 extern time_t now;
170
171 COMPARE((now - entry->fts_statp->st_ctime +
173 SECSPERDAY - 1) / SECSPERDAY, plan->t_data);
172 86400 - 1) / 86400, plan->t_data);
174}
173}
175
174
176PLAN *
177c_ctime(arg)
178 char *arg;
179{
180 PLAN *new;
181
182 ftsoptions &= ~FTS_NOSTAT;
183

--- 12 unchanged lines hidden (view full) ---

196 */
197int
198f_always_true(plan, entry)
199 PLAN *plan;
200 FTSENT *entry;
201{
202 return (1);
203}
175PLAN *
176c_ctime(arg)
177 char *arg;
178{
179 PLAN *new;
180
181 ftsoptions &= ~FTS_NOSTAT;
182

--- 12 unchanged lines hidden (view full) ---

195 */
196int
197f_always_true(plan, entry)
198 PLAN *plan;
199 FTSENT *entry;
200{
201 return (1);
202}
204
203
205PLAN *
206c_depth()
207{
208 isdepth = 1;
209
210 return (palloc(N_DEPTH, f_always_true));
211}
204PLAN *
205c_depth()
206{
207 isdepth = 1;
208
209 return (palloc(N_DEPTH, f_always_true));
210}
212
211
213/*
214 * [-exec | -ok] utility [arg ... ] ; functions --
215 *
216 * True if the executed utility returns a zero value as exit status.
217 * The end of the primary expression is delimited by a semicolon. If
218 * "{}" occurs anywhere, it gets replaced by the current pathname.
219 * The current directory for the execution of utility is the same as
220 * the current directory when the find utility was started.

--- 14 unchanged lines hidden (view full) ---

235 for (cnt = 0; plan->e_argv[cnt]; ++cnt)
236 if (plan->e_len[cnt])
237 brace_subst(plan->e_orig[cnt], &plan->e_argv[cnt],
238 entry->fts_path, plan->e_len[cnt]);
239
240 if (plan->flags == F_NEEDOK && !queryuser(plan->e_argv))
241 return (0);
242
212/*
213 * [-exec | -ok] utility [arg ... ] ; functions --
214 *
215 * True if the executed utility returns a zero value as exit status.
216 * The end of the primary expression is delimited by a semicolon. If
217 * "{}" occurs anywhere, it gets replaced by the current pathname.
218 * The current directory for the execution of utility is the same as
219 * the current directory when the find utility was started.

--- 14 unchanged lines hidden (view full) ---

234 for (cnt = 0; plan->e_argv[cnt]; ++cnt)
235 if (plan->e_len[cnt])
236 brace_subst(plan->e_orig[cnt], &plan->e_argv[cnt],
237 entry->fts_path, plan->e_len[cnt]);
238
239 if (plan->flags == F_NEEDOK && !queryuser(plan->e_argv))
240 return (0);
241
242 /* make sure find output is interspersed correctly with subprocesses */
243 fflush(stdout);
244
243 switch (pid = vfork()) {
244 case -1:
245 err(1, "fork");
246 /* NOTREACHED */
247 case 0:
248 if (fchdir(dotfd)) {
249 warn("chdir");
250 _exit(1);
251 }
252 execvp(plan->e_argv[0], plan->e_argv);
253 warn("%s", plan->e_argv[0]);
254 _exit(1);
255 }
256 pid = waitpid(pid, &status, 0);
257 return (pid != -1 && WIFEXITED(status) && !WEXITSTATUS(status));
258}
245 switch (pid = vfork()) {
246 case -1:
247 err(1, "fork");
248 /* NOTREACHED */
249 case 0:
250 if (fchdir(dotfd)) {
251 warn("chdir");
252 _exit(1);
253 }
254 execvp(plan->e_argv[0], plan->e_argv);
255 warn("%s", plan->e_argv[0]);
256 _exit(1);
257 }
258 pid = waitpid(pid, &status, 0);
259 return (pid != -1 && WIFEXITED(status) && !WEXITSTATUS(status));
260}
259
261
260/*
261 * c_exec --
262 * build three parallel arrays, one with pointers to the strings passed
263 * on the command line, one with (possibly duplicated) pointers to the
264 * argv array, and one with integer values that are lengths of the
265 * strings, but also flags meaning that the string has to be massaged.
266 */
267PLAN *
268c_exec(argvp, isok)
269 char ***argvp;
270 int isok;
271{
272 PLAN *new; /* node returned */
273 register int cnt;
274 register char **argv, **ap, *p;
275
276 isoutput = 1;
262/*
263 * c_exec --
264 * build three parallel arrays, one with pointers to the strings passed
265 * on the command line, one with (possibly duplicated) pointers to the
266 * argv array, and one with integer values that are lengths of the
267 * strings, but also flags meaning that the string has to be massaged.
268 */
269PLAN *
270c_exec(argvp, isok)
271 char ***argvp;
272 int isok;
273{
274 PLAN *new; /* node returned */
275 register int cnt;
276 register char **argv, **ap, *p;
277
278 isoutput = 1;
277
279
278 new = palloc(N_EXEC, f_exec);
279 if (isok)
280 new->flags = F_NEEDOK;
281
282 for (ap = argv = *argvp;; ++ap) {
283 if (!*ap)
284 errx(1,
285 "%s: no terminating \";\"", isok ? "-ok" : "-exec");

--- 19 unchanged lines hidden (view full) ---

305 new->e_len[cnt] = 0;
306 }
307 }
308 new->e_argv[cnt] = new->e_orig[cnt] = NULL;
309
310 *argvp = argv + 1;
311 return (new);
312}
280 new = palloc(N_EXEC, f_exec);
281 if (isok)
282 new->flags = F_NEEDOK;
283
284 for (ap = argv = *argvp;; ++ap) {
285 if (!*ap)
286 errx(1,
287 "%s: no terminating \";\"", isok ? "-ok" : "-exec");

--- 19 unchanged lines hidden (view full) ---

307 new->e_len[cnt] = 0;
308 }
309 }
310 new->e_argv[cnt] = new->e_orig[cnt] = NULL;
311
312 *argvp = argv + 1;
313 return (new);
314}
313
315
314/*
315 * -follow functions --
316 *
317 * Always true, causes symbolic links to be followed on a global
318 * basis.
319 */
320PLAN *
321c_follow()
322{
323 ftsoptions &= ~FTS_PHYSICAL;
324 ftsoptions |= FTS_LOGICAL;
325
326 return (palloc(N_FOLLOW, f_always_true));
327}
316/*
317 * -follow functions --
318 *
319 * Always true, causes symbolic links to be followed on a global
320 * basis.
321 */
322PLAN *
323c_follow()
324{
325 ftsoptions &= ~FTS_PHYSICAL;
326 ftsoptions |= FTS_LOGICAL;
327
328 return (palloc(N_FOLLOW, f_always_true));
329}
328
330
329/*
330 * -fstype functions --
331 *
332 * True if the file is of a certain type.
333 */
334int
335f_fstype(plan, entry)
336 PLAN *plan;

--- 18 unchanged lines hidden (view full) ---

355 if ((p = strrchr(entry->fts_accpath, '/')) != NULL)
356 ++p;
357 else
358 p = entry->fts_accpath;
359 save[0] = p[0];
360 p[0] = '.';
361 save[1] = p[1];
362 p[1] = '\0';
331/*
332 * -fstype functions --
333 *
334 * True if the file is of a certain type.
335 */
336int
337f_fstype(plan, entry)
338 PLAN *plan;

--- 18 unchanged lines hidden (view full) ---

357 if ((p = strrchr(entry->fts_accpath, '/')) != NULL)
358 ++p;
359 else
360 p = entry->fts_accpath;
361 save[0] = p[0];
362 p[0] = '.';
363 save[1] = p[1];
364 p[1] = '\0';
363
364 } else
365
366 } else
365 p = NULL;
366
367 if (statfs(entry->fts_accpath, &sb))
368 err(1, "%s", entry->fts_accpath);
369
370 if (p) {
371 p[0] = save[0];
372 p[1] = save[1];

--- 5 unchanged lines hidden (view full) ---

378 * Further tests may need both of these values, so
379 * always copy both of them.
380 */
381 val = sb.f_flags;
382 val = sb.f_type;
383 }
384 switch (plan->flags) {
385 case F_MTFLAG:
367 p = NULL;
368
369 if (statfs(entry->fts_accpath, &sb))
370 err(1, "%s", entry->fts_accpath);
371
372 if (p) {
373 p[0] = save[0];
374 p[1] = save[1];

--- 5 unchanged lines hidden (view full) ---

380 * Further tests may need both of these values, so
381 * always copy both of them.
382 */
383 val = sb.f_flags;
384 val = sb.f_type;
385 }
386 switch (plan->flags) {
387 case F_MTFLAG:
386 return (val & plan->mt_data);
388 return (val & plan->mt_data);
387 case F_MTTYPE:
388 return (val == plan->mt_data);
389 default:
390 abort();
391 }
392}
389 case F_MTTYPE:
390 return (val == plan->mt_data);
391 default:
392 abort();
393 }
394}
393
395
394PLAN *
395c_fstype(arg)
396 char *arg;
397{
398 register PLAN *new;
399 struct vfsconf vfc;
400
401 ftsoptions &= ~FTS_NOSTAT;
396PLAN *
397c_fstype(arg)
398 char *arg;
399{
400 register PLAN *new;
401 struct vfsconf vfc;
402
403 ftsoptions &= ~FTS_NOSTAT;
402
404
403 new = palloc(N_FSTYPE, f_fstype);
404
405 /*
406 * Check first for a filesystem name.
407 */
408 if (getvfsbyname(arg, &vfc) == 0) {
409 new->flags = F_MTTYPE;
410 new->mt_data = vfc.vfc_typenum;

--- 14 unchanged lines hidden (view full) ---

425 new->mt_data = MNT_RDONLY;
426 return (new);
427 }
428 break;
429 }
430 errx(1, "%s: unknown file type", arg);
431 /* NOTREACHED */
432}
405 new = palloc(N_FSTYPE, f_fstype);
406
407 /*
408 * Check first for a filesystem name.
409 */
410 if (getvfsbyname(arg, &vfc) == 0) {
411 new->flags = F_MTTYPE;
412 new->mt_data = vfc.vfc_typenum;

--- 14 unchanged lines hidden (view full) ---

427 new->mt_data = MNT_RDONLY;
428 return (new);
429 }
430 break;
431 }
432 errx(1, "%s: unknown file type", arg);
433 /* NOTREACHED */
434}
433
435
434/*
435 * -group gname functions --
436 *
437 * True if the file belongs to the group gname. If gname is numeric and
438 * an equivalent of the getgrnam() function does not return a valid group
439 * name, gname is taken as a group ID.
440 */
441int
442f_group(plan, entry)
443 PLAN *plan;
444 FTSENT *entry;
445{
446 return (entry->fts_statp->st_gid == plan->g_data);
447}
436/*
437 * -group gname functions --
438 *
439 * True if the file belongs to the group gname. If gname is numeric and
440 * an equivalent of the getgrnam() function does not return a valid group
441 * name, gname is taken as a group ID.
442 */
443int
444f_group(plan, entry)
445 PLAN *plan;
446 FTSENT *entry;
447{
448 return (entry->fts_statp->st_gid == plan->g_data);
449}
448
450
449PLAN *
450c_group(gname)
451 char *gname;
452{
453 PLAN *new;
454 struct group *g;
455 gid_t gid;
451PLAN *
452c_group(gname)
453 char *gname;
454{
455 PLAN *new;
456 struct group *g;
457 gid_t gid;
456
458
457 ftsoptions &= ~FTS_NOSTAT;
458
459 g = getgrnam(gname);
460 if (g == NULL) {
461 gid = atoi(gname);
462 if (gid == 0 && gname[0] != '0')
463 errx(1, "-group: %s: no such group", gname);
464 } else
465 gid = g->gr_gid;
459 ftsoptions &= ~FTS_NOSTAT;
460
461 g = getgrnam(gname);
462 if (g == NULL) {
463 gid = atoi(gname);
464 if (gid == 0 && gname[0] != '0')
465 errx(1, "-group: %s: no such group", gname);
466 } else
467 gid = g->gr_gid;
466
468
467 new = palloc(N_GROUP, f_group);
468 new->g_data = gid;
469 return (new);
470}
471
472/*
473 * -inum n functions --
474 *
475 * True if the file has inode # n.
476 */
477int
478f_inum(plan, entry)
479 PLAN *plan;
480 FTSENT *entry;
481{
482 COMPARE(entry->fts_statp->st_ino, plan->i_data);
483}
469 new = palloc(N_GROUP, f_group);
470 new->g_data = gid;
471 return (new);
472}
473
474/*
475 * -inum n functions --
476 *
477 * True if the file has inode # n.
478 */
479int
480f_inum(plan, entry)
481 PLAN *plan;
482 FTSENT *entry;
483{
484 COMPARE(entry->fts_statp->st_ino, plan->i_data);
485}
484
486
485PLAN *
486c_inum(arg)
487 char *arg;
488{
489 PLAN *new;
487PLAN *
488c_inum(arg)
489 char *arg;
490{
491 PLAN *new;
490
492
491 ftsoptions &= ~FTS_NOSTAT;
493 ftsoptions &= ~FTS_NOSTAT;
492
494
493 new = palloc(N_INUM, f_inum);
494 new->i_data = find_parsenum(new, "-inum", arg, NULL);
495 return (new);
496}
495 new = palloc(N_INUM, f_inum);
496 new->i_data = find_parsenum(new, "-inum", arg, NULL);
497 return (new);
498}
497
499
498/*
499 * -links n functions --
500 *
501 * True if the file has n links.
502 */
503int
504f_links(plan, entry)
505 PLAN *plan;
506 FTSENT *entry;
507{
508 COMPARE(entry->fts_statp->st_nlink, plan->l_data);
509}
500/*
501 * -links n functions --
502 *
503 * True if the file has n links.
504 */
505int
506f_links(plan, entry)
507 PLAN *plan;
508 FTSENT *entry;
509{
510 COMPARE(entry->fts_statp->st_nlink, plan->l_data);
511}
510
512
511PLAN *
512c_links(arg)
513 char *arg;
514{
515 PLAN *new;
513PLAN *
514c_links(arg)
515 char *arg;
516{
517 PLAN *new;
516
518
517 ftsoptions &= ~FTS_NOSTAT;
519 ftsoptions &= ~FTS_NOSTAT;
518
520
519 new = palloc(N_LINKS, f_links);
520 new->l_data = (nlink_t)find_parsenum(new, "-links", arg, NULL);
521 return (new);
522}
521 new = palloc(N_LINKS, f_links);
522 new->l_data = (nlink_t)find_parsenum(new, "-links", arg, NULL);
523 return (new);
524}
523
525
524/*
525 * -ls functions --
526 *
527 * Always true - prints the current entry to stdout in "ls" format.
528 */
529int
530f_ls(plan, entry)
531 PLAN *plan;
532 FTSENT *entry;
533{
534 printlong(entry->fts_path, entry->fts_accpath, entry->fts_statp);
535 return (1);
536}
526/*
527 * -ls functions --
528 *
529 * Always true - prints the current entry to stdout in "ls" format.
530 */
531int
532f_ls(plan, entry)
533 PLAN *plan;
534 FTSENT *entry;
535{
536 printlong(entry->fts_path, entry->fts_accpath, entry->fts_statp);
537 return (1);
538}
537
539
538PLAN *
539c_ls()
540{
541 ftsoptions &= ~FTS_NOSTAT;
542 isoutput = 1;
540PLAN *
541c_ls()
542{
543 ftsoptions &= ~FTS_NOSTAT;
544 isoutput = 1;
543
545
544 return (palloc(N_LS, f_ls));
545}
546
547/*
548 * -mtime n functions --
549 *
550 * True if the difference between the file modification time and the
551 * current time is n 24 hour periods.
552 */
553int
554f_mtime(plan, entry)
555 PLAN *plan;
556 FTSENT *entry;
557{
558 extern time_t now;
559
546 return (palloc(N_LS, f_ls));
547}
548
549/*
550 * -mtime n functions --
551 *
552 * True if the difference between the file modification time and the
553 * current time is n 24 hour periods.
554 */
555int
556f_mtime(plan, entry)
557 PLAN *plan;
558 FTSENT *entry;
559{
560 extern time_t now;
561
560 COMPARE((now - entry->fts_statp->st_mtime + SECSPERDAY - 1) /
561 SECSPERDAY, plan->t_data);
562 COMPARE((now - entry->fts_statp->st_mtime + 86400 - 1) /
563 86400, plan->t_data);
562}
564}
563
565
564PLAN *
565c_mtime(arg)
566 char *arg;
567{
568 PLAN *new;
569
570 ftsoptions &= ~FTS_NOSTAT;
571

--- 11 unchanged lines hidden (view full) ---

583 */
584int
585f_name(plan, entry)
586 PLAN *plan;
587 FTSENT *entry;
588{
589 return (!fnmatch(plan->c_data, entry->fts_name, 0));
590}
566PLAN *
567c_mtime(arg)
568 char *arg;
569{
570 PLAN *new;
571
572 ftsoptions &= ~FTS_NOSTAT;
573

--- 11 unchanged lines hidden (view full) ---

585 */
586int
587f_name(plan, entry)
588 PLAN *plan;
589 FTSENT *entry;
590{
591 return (!fnmatch(plan->c_data, entry->fts_name, 0));
592}
591
593
592PLAN *
593c_name(pattern)
594 char *pattern;
595{
596 PLAN *new;
597
598 new = palloc(N_NAME, f_name);
599 new->c_data = pattern;
600 return (new);
601}
594PLAN *
595c_name(pattern)
596 char *pattern;
597{
598 PLAN *new;
599
600 new = palloc(N_NAME, f_name);
601 new->c_data = pattern;
602 return (new);
603}
602
604
603/*
604 * -newer file functions --
605 *
606 * True if the current file has been modified more recently
607 * then the modification time of the file named by the pathname
608 * file.
609 */
610int
611f_newer(plan, entry)
612 PLAN *plan;
613 FTSENT *entry;
614{
615 return (entry->fts_statp->st_mtime > plan->t_data);
616}
605/*
606 * -newer file functions --
607 *
608 * True if the current file has been modified more recently
609 * then the modification time of the file named by the pathname
610 * file.
611 */
612int
613f_newer(plan, entry)
614 PLAN *plan;
615 FTSENT *entry;
616{
617 return (entry->fts_statp->st_mtime > plan->t_data);
618}
617
619
618PLAN *
619c_newer(filename)
620 char *filename;
621{
622 PLAN *new;
623 struct stat sb;
620PLAN *
621c_newer(filename)
622 char *filename;
623{
624 PLAN *new;
625 struct stat sb;
624
626
625 ftsoptions &= ~FTS_NOSTAT;
626
627 if (stat(filename, &sb))
628 err(1, "%s", filename);
629 new = palloc(N_NEWER, f_newer);
630 new->t_data = sb.st_mtime;
631 return (new);
632}
627 ftsoptions &= ~FTS_NOSTAT;
628
629 if (stat(filename, &sb))
630 err(1, "%s", filename);
631 new = palloc(N_NEWER, f_newer);
632 new->t_data = sb.st_mtime;
633 return (new);
634}
633
635
634/*
635 * -nogroup functions --
636 *
637 * True if file belongs to a user ID for which the equivalent
638 * of the getgrnam() 9.2.1 [POSIX.1] function returns NULL.
639 */
640int
641f_nogroup(plan, entry)
642 PLAN *plan;
643 FTSENT *entry;
644{
645 char *group_from_gid();
646
647 return (group_from_gid(entry->fts_statp->st_gid, 1) ? 0 : 1);
648}
636/*
637 * -nogroup functions --
638 *
639 * True if file belongs to a user ID for which the equivalent
640 * of the getgrnam() 9.2.1 [POSIX.1] function returns NULL.
641 */
642int
643f_nogroup(plan, entry)
644 PLAN *plan;
645 FTSENT *entry;
646{
647 char *group_from_gid();
648
649 return (group_from_gid(entry->fts_statp->st_gid, 1) ? 0 : 1);
650}
649
651
650PLAN *
651c_nogroup()
652{
653 ftsoptions &= ~FTS_NOSTAT;
654
655 return (palloc(N_NOGROUP, f_nogroup));
656}
652PLAN *
653c_nogroup()
654{
655 ftsoptions &= ~FTS_NOSTAT;
656
657 return (palloc(N_NOGROUP, f_nogroup));
658}
657
659
658/*
659 * -nouser functions --
660 *
661 * True if file belongs to a user ID for which the equivalent
662 * of the getpwuid() 9.2.2 [POSIX.1] function returns NULL.
663 */
664int
665f_nouser(plan, entry)
666 PLAN *plan;
667 FTSENT *entry;
668{
669 char *user_from_uid();
670
671 return (user_from_uid(entry->fts_statp->st_uid, 1) ? 0 : 1);
672}
660/*
661 * -nouser functions --
662 *
663 * True if file belongs to a user ID for which the equivalent
664 * of the getpwuid() 9.2.2 [POSIX.1] function returns NULL.
665 */
666int
667f_nouser(plan, entry)
668 PLAN *plan;
669 FTSENT *entry;
670{
671 char *user_from_uid();
672
673 return (user_from_uid(entry->fts_statp->st_uid, 1) ? 0 : 1);
674}
673
675
674PLAN *
675c_nouser()
676{
677 ftsoptions &= ~FTS_NOSTAT;
678
679 return (palloc(N_NOUSER, f_nouser));
680}
676PLAN *
677c_nouser()
678{
679 ftsoptions &= ~FTS_NOSTAT;
680
681 return (palloc(N_NOUSER, f_nouser));
682}
681
683
682/*
683 * -path functions --
684 *
685 * True if the path of the filename being examined
686 * matches pattern using Pattern Matching Notation S3.14
687 */
688int
689f_path(plan, entry)
690 PLAN *plan;
691 FTSENT *entry;
692{
693 return (!fnmatch(plan->c_data, entry->fts_path, 0));
694}
684/*
685 * -path functions --
686 *
687 * True if the path of the filename being examined
688 * matches pattern using Pattern Matching Notation S3.14
689 */
690int
691f_path(plan, entry)
692 PLAN *plan;
693 FTSENT *entry;
694{
695 return (!fnmatch(plan->c_data, entry->fts_path, 0));
696}
695
697
696PLAN *
697c_path(pattern)
698 char *pattern;
699{
700 PLAN *new;
701
702 new = palloc(N_NAME, f_path);
703 new->c_data = pattern;
704 return (new);
705}
698PLAN *
699c_path(pattern)
700 char *pattern;
701{
702 PLAN *new;
703
704 new = palloc(N_NAME, f_path);
705 new->c_data = pattern;
706 return (new);
707}
706
708
707/*
708 * -perm functions --
709 *
710 * The mode argument is used to represent file mode bits. If it starts
711 * with a leading digit, it's treated as an octal mode, otherwise as a
712 * symbolic mode.
713 */
714int

--- 6 unchanged lines hidden (view full) ---

721 mode = entry->fts_statp->st_mode &
722 (S_ISUID|S_ISGID|S_ISTXT|S_IRWXU|S_IRWXG|S_IRWXO);
723 if (plan->flags == F_ATLEAST)
724 return ((plan->m_data | mode) == mode);
725 else
726 return (mode == plan->m_data);
727 /* NOTREACHED */
728}
709/*
710 * -perm functions --
711 *
712 * The mode argument is used to represent file mode bits. If it starts
713 * with a leading digit, it's treated as an octal mode, otherwise as a
714 * symbolic mode.
715 */
716int

--- 6 unchanged lines hidden (view full) ---

723 mode = entry->fts_statp->st_mode &
724 (S_ISUID|S_ISGID|S_ISTXT|S_IRWXU|S_IRWXG|S_IRWXO);
725 if (plan->flags == F_ATLEAST)
726 return ((plan->m_data | mode) == mode);
727 else
728 return (mode == plan->m_data);
729 /* NOTREACHED */
730}
729
731
730PLAN *
731c_perm(perm)
732 char *perm;
733{
734 PLAN *new;
735 mode_t *set;
736
737 ftsoptions &= ~FTS_NOSTAT;

--- 6 unchanged lines hidden (view full) ---

744 }
745
746 if ((set = setmode(perm)) == NULL)
747 err(1, "-perm: %s: illegal mode string", perm);
748
749 new->m_data = getmode(set, 0);
750 return (new);
751}
732PLAN *
733c_perm(perm)
734 char *perm;
735{
736 PLAN *new;
737 mode_t *set;
738
739 ftsoptions &= ~FTS_NOSTAT;

--- 6 unchanged lines hidden (view full) ---

746 }
747
748 if ((set = setmode(perm)) == NULL)
749 err(1, "-perm: %s: illegal mode string", perm);
750
751 new->m_data = getmode(set, 0);
752 return (new);
753}
752
754
753/*
754 * -print functions --
755 *
756 * Always true, causes the current pathame to be written to
757 * standard output.
758 */
759int
760f_print(plan, entry)
761 PLAN *plan;
762 FTSENT *entry;
763{
755/*
756 * -print functions --
757 *
758 * Always true, causes the current pathame to be written to
759 * standard output.
760 */
761int
762f_print(plan, entry)
763 PLAN *plan;
764 FTSENT *entry;
765{
764 (void)printf("%s\n", entry->fts_path);
766 (void)puts(entry->fts_path);
765 return (1);
766}
767 return (1);
768}
767
769
768PLAN *
769c_print()
770{
771 isoutput = 1;
772
773 return (palloc(N_PRINT, f_print));
774}
770PLAN *
771c_print()
772{
773 isoutput = 1;
774
775 return (palloc(N_PRINT, f_print));
776}
775
777
776/*
778/*
779 * -print0 functions --
780 *
781 * Always true, causes the current pathame to be written to
782 * standard output followed by a NUL character
783 */
784int
785f_print0(plan, entry)
786 PLAN *plan;
787 FTSENT *entry;
788{
789 fputs(entry->fts_path, stdout);
790 fputc('\0', stdout);
791 return (1);
792}
793
794PLAN *
795c_print0()
796{
797 isoutput = 1;
798
799 return (palloc(N_PRINT0, f_print0));
800}
801
802/*
777 * -prune functions --
778 *
779 * Prune a portion of the hierarchy.
780 */
781int
782f_prune(plan, entry)
783 PLAN *plan;
784 FTSENT *entry;
785{
786 extern FTS *tree;
787
788 if (fts_set(tree, entry, FTS_SKIP))
789 err(1, "%s", entry->fts_path);
790 return (1);
791}
803 * -prune functions --
804 *
805 * Prune a portion of the hierarchy.
806 */
807int
808f_prune(plan, entry)
809 PLAN *plan;
810 FTSENT *entry;
811{
812 extern FTS *tree;
813
814 if (fts_set(tree, entry, FTS_SKIP))
815 err(1, "%s", entry->fts_path);
816 return (1);
817}
792
818
793PLAN *
794c_prune()
795{
796 return (palloc(N_PRUNE, f_prune));
797}
819PLAN *
820c_prune()
821{
822 return (palloc(N_PRUNE, f_prune));
823}
798
824
799/*
800 * -size n[c] functions --
801 *
802 * True if the file size in bytes, divided by an implementation defined
803 * value and rounded up to the next integer, is n. If n is followed by
804 * a c, the size is in bytes.
805 */
806#define FIND_SIZE 512

--- 5 unchanged lines hidden (view full) ---

812 FTSENT *entry;
813{
814 off_t size;
815
816 size = divsize ? (entry->fts_statp->st_size + FIND_SIZE - 1) /
817 FIND_SIZE : entry->fts_statp->st_size;
818 COMPARE(size, plan->o_data);
819}
825/*
826 * -size n[c] functions --
827 *
828 * True if the file size in bytes, divided by an implementation defined
829 * value and rounded up to the next integer, is n. If n is followed by
830 * a c, the size is in bytes.
831 */
832#define FIND_SIZE 512

--- 5 unchanged lines hidden (view full) ---

838 FTSENT *entry;
839{
840 off_t size;
841
842 size = divsize ? (entry->fts_statp->st_size + FIND_SIZE - 1) /
843 FIND_SIZE : entry->fts_statp->st_size;
844 COMPARE(size, plan->o_data);
845}
820
846
821PLAN *
822c_size(arg)
823 char *arg;
824{
825 PLAN *new;
826 char endch;
847PLAN *
848c_size(arg)
849 char *arg;
850{
851 PLAN *new;
852 char endch;
827
853
828 ftsoptions &= ~FTS_NOSTAT;
829
830 new = palloc(N_SIZE, f_size);
831 endch = 'c';
832 new->o_data = find_parsenum(new, "-size", arg, &endch);
833 if (endch == 'c')
834 divsize = 0;
835 return (new);
836}
854 ftsoptions &= ~FTS_NOSTAT;
855
856 new = palloc(N_SIZE, f_size);
857 endch = 'c';
858 new->o_data = find_parsenum(new, "-size", arg, &endch);
859 if (endch == 'c')
860 divsize = 0;
861 return (new);
862}
837
863
838/*
839 * -type c functions --
840 *
841 * True if the type of the file is c, where c is b, c, d, p, f or w
842 * for block special file, character special file, directory, FIFO,
843 * regular file or whiteout respectively.
844 */
845int
846f_type(plan, entry)
847 PLAN *plan;
848 FTSENT *entry;
849{
850 return ((entry->fts_statp->st_mode & S_IFMT) == plan->m_data);
851}
864/*
865 * -type c functions --
866 *
867 * True if the type of the file is c, where c is b, c, d, p, f or w
868 * for block special file, character special file, directory, FIFO,
869 * regular file or whiteout respectively.
870 */
871int
872f_type(plan, entry)
873 PLAN *plan;
874 FTSENT *entry;
875{
876 return ((entry->fts_statp->st_mode & S_IFMT) == plan->m_data);
877}
852
878
853PLAN *
854c_type(typestring)
855 char *typestring;
856{
857 PLAN *new;
858 mode_t mask;
879PLAN *
880c_type(typestring)
881 char *typestring;
882{
883 PLAN *new;
884 mode_t mask;
859
885
860 ftsoptions &= ~FTS_NOSTAT;
861
862 switch (typestring[0]) {
863 case 'b':
864 mask = S_IFBLK;
865 break;
866 case 'c':
867 mask = S_IFCHR;

--- 17 unchanged lines hidden (view full) ---

885 case 'w':
886 mask = S_IFWHT;
887 ftsoptions |= FTS_WHITEOUT;
888 break;
889#endif /* FTS_WHITEOUT */
890 default:
891 errx(1, "-type: %s: unknown type", typestring);
892 }
886 ftsoptions &= ~FTS_NOSTAT;
887
888 switch (typestring[0]) {
889 case 'b':
890 mask = S_IFBLK;
891 break;
892 case 'c':
893 mask = S_IFCHR;

--- 17 unchanged lines hidden (view full) ---

911 case 'w':
912 mask = S_IFWHT;
913 ftsoptions |= FTS_WHITEOUT;
914 break;
915#endif /* FTS_WHITEOUT */
916 default:
917 errx(1, "-type: %s: unknown type", typestring);
918 }
893
919
894 new = palloc(N_TYPE, f_type);
895 new->m_data = mask;
896 return (new);
897}
920 new = palloc(N_TYPE, f_type);
921 new->m_data = mask;
922 return (new);
923}
898
924
899/*
925/*
926 * -delete functions --
927 *
928 * True always. Makes it's best shot and continues on regardless.
929 */
930int
931f_delete(plan, entry)
932 PLAN *plan;
933 FTSENT *entry;
934{
935 /* ignore these from fts */
936 if (strcmp(entry->fts_accpath, ".") == 0 ||
937 strcmp(entry->fts_accpath, "..") == 0)
938 return (1);
939
940 /* sanity check */
941 if (isdepth == 0 || /* depth off */
942 (ftsoptions & FTS_NOSTAT) || /* not stat()ing */
943 !(ftsoptions & FTS_PHYSICAL) || /* physical off */
944 (ftsoptions & FTS_LOGICAL)) /* or finally, logical on */
945 errx(1, "-delete: insecure options got turned on");
946
947 /* Potentially unsafe - do not accept relative paths whatsoever */
948 if (strchr(entry->fts_accpath, '/') != NULL)
949 errx(1, "-delete: %s: relative path potentially not safe",
950 entry->fts_accpath);
951
952 /* Turn off user immutable bits if running as root */
953 if ((entry->fts_statp->st_flags & (UF_APPEND|UF_IMMUTABLE)) &&
954 !(entry->fts_statp->st_flags & (SF_APPEND|SF_IMMUTABLE)) &&
955 geteuid() == 0)
956 chflags(entry->fts_accpath,
957 entry->fts_statp->st_flags &= ~(UF_APPEND|UF_IMMUTABLE));
958
959 /* rmdir directories, unlink everything else */
960 if (S_ISDIR(entry->fts_statp->st_mode)) {
961 if (rmdir(entry->fts_accpath) < 0 && errno != ENOTEMPTY)
962 warn("-delete: rmdir(%s)", entry->fts_path);
963 } else {
964 if (unlink(entry->fts_accpath) < 0)
965 warn("-delete: unlink(%s)", entry->fts_path);
966 }
967
968 /* "succeed" */
969 return (1);
970}
971
972PLAN *
973c_delete()
974{
975
976 ftsoptions &= ~FTS_NOSTAT; /* no optimise */
977 ftsoptions |= FTS_PHYSICAL; /* disable -follow */
978 ftsoptions &= ~FTS_LOGICAL; /* disable -follow */
979 isoutput = 1; /* possible output */
980 isdepth = 1; /* -depth implied */
981
982 return (palloc(N_DELETE, f_delete));
983}
984
985/*
900 * -user uname functions --
901 *
902 * True if the file belongs to the user uname. If uname is numeric and
903 * an equivalent of the getpwnam() S9.2.2 [POSIX.1] function does not
904 * return a valid user name, uname is taken as a user ID.
905 */
906int
907f_user(plan, entry)
908 PLAN *plan;
909 FTSENT *entry;
910{
911 return (entry->fts_statp->st_uid == plan->u_data);
912}
986 * -user uname functions --
987 *
988 * True if the file belongs to the user uname. If uname is numeric and
989 * an equivalent of the getpwnam() S9.2.2 [POSIX.1] function does not
990 * return a valid user name, uname is taken as a user ID.
991 */
992int
993f_user(plan, entry)
994 PLAN *plan;
995 FTSENT *entry;
996{
997 return (entry->fts_statp->st_uid == plan->u_data);
998}
913
999
914PLAN *
915c_user(username)
916 char *username;
917{
918 PLAN *new;
919 struct passwd *p;
920 uid_t uid;
1000PLAN *
1001c_user(username)
1002 char *username;
1003{
1004 PLAN *new;
1005 struct passwd *p;
1006 uid_t uid;
921
1007
922 ftsoptions &= ~FTS_NOSTAT;
923
924 p = getpwnam(username);
925 if (p == NULL) {
926 uid = atoi(username);
927 if (uid == 0 && username[0] != '0')
928 errx(1, "-user: %s: no such user", username);
929 } else
930 uid = p->pw_uid;
931
932 new = palloc(N_USER, f_user);
933 new->u_data = uid;
934 return (new);
935}
1008 ftsoptions &= ~FTS_NOSTAT;
1009
1010 p = getpwnam(username);
1011 if (p == NULL) {
1012 uid = atoi(username);
1013 if (uid == 0 && username[0] != '0')
1014 errx(1, "-user: %s: no such user", username);
1015 } else
1016 uid = p->pw_uid;
1017
1018 new = palloc(N_USER, f_user);
1019 new->u_data = uid;
1020 return (new);
1021}
936
1022
937/*
938 * -xdev functions --
939 *
940 * Always true, causes find not to decend past directories that have a
941 * different device ID (st_dev, see stat() S5.6.2 [POSIX.1])
942 */
943PLAN *
944c_xdev()

--- 15 unchanged lines hidden (view full) ---

960{
961 register PLAN *p;
962 register int state;
963
964 for (p = plan->p_data[0];
965 p && (state = (p->eval)(p, entry)); p = p->next);
966 return (state);
967}
1023/*
1024 * -xdev functions --
1025 *
1026 * Always true, causes find not to decend past directories that have a
1027 * different device ID (st_dev, see stat() S5.6.2 [POSIX.1])
1028 */
1029PLAN *
1030c_xdev()

--- 15 unchanged lines hidden (view full) ---

1046{
1047 register PLAN *p;
1048 register int state;
1049
1050 for (p = plan->p_data[0];
1051 p && (state = (p->eval)(p, entry)); p = p->next);
1052 return (state);
1053}
968
1054
969/*
970 * N_OPENPAREN and N_CLOSEPAREN nodes are temporary place markers. They are
971 * eliminated during phase 2 of find_formplan() --- the '(' node is converted
972 * to a N_EXPR node containing the expression and the ')' node is discarded.
973 */
974PLAN *
975c_openparen()
976{
977 return (palloc(N_OPENPAREN, (int (*)())-1));
978}
1055/*
1056 * N_OPENPAREN and N_CLOSEPAREN nodes are temporary place markers. They are
1057 * eliminated during phase 2 of find_formplan() --- the '(' node is converted
1058 * to a N_EXPR node containing the expression and the ')' node is discarded.
1059 */
1060PLAN *
1061c_openparen()
1062{
1063 return (palloc(N_OPENPAREN, (int (*)())-1));
1064}
979
1065
980PLAN *
981c_closeparen()
982{
983 return (palloc(N_CLOSEPAREN, (int (*)())-1));
984}
1066PLAN *
1067c_closeparen()
1068{
1069 return (palloc(N_CLOSEPAREN, (int (*)())-1));
1070}
985
1071
986/*
987 * ! expression functions --
988 *
989 * Negation of a primary; the unary NOT operator.
990 */
991int
992f_not(plan, entry)
993 PLAN *plan;
994 FTSENT *entry;
995{
996 register PLAN *p;
997 register int state;
998
999 for (p = plan->p_data[0];
1000 p && (state = (p->eval)(p, entry)); p = p->next);
1001 return (!state);
1002}
1072/*
1073 * ! expression functions --
1074 *
1075 * Negation of a primary; the unary NOT operator.
1076 */
1077int
1078f_not(plan, entry)
1079 PLAN *plan;
1080 FTSENT *entry;
1081{
1082 register PLAN *p;
1083 register int state;
1084
1085 for (p = plan->p_data[0];
1086 p && (state = (p->eval)(p, entry)); p = p->next);
1087 return (!state);
1088}
1003
1089
1004PLAN *
1005c_not()
1006{
1007 return (palloc(N_NOT, f_not));
1008}
1090PLAN *
1091c_not()
1092{
1093 return (palloc(N_NOT, f_not));
1094}
1009
1095
1010/*
1011 * expression -o expression functions --
1012 *
1013 * Alternation of primaries; the OR operator. The second expression is
1014 * not evaluated if the first expression is true.
1015 */
1016int
1017f_or(plan, entry)

--- 38 unchanged lines hidden ---
1096/*
1097 * expression -o expression functions --
1098 *
1099 * Alternation of primaries; the OR operator. The second expression is
1100 * not evaluated if the first expression is true.
1101 */
1102int
1103f_or(plan, entry)

--- 38 unchanged lines hidden ---