Gentoo Archives: gentoo-commits

From: "Chris PeBenito (pebenito)" <pebenito@g.o>
To: gentoo-commits@l.g.o
Subject: [gentoo-commits] gentoo-x86 commit in sys-apps/findutils/files: findutils-4.3.12-selinux.diff
Date: Tue, 01 Apr 2008 15:54:09
Message-Id: E1Jgio3-0001Ct-B3@stork.gentoo.org
1 pebenito 08/04/01 15:53:51
2
3 Modified: findutils-4.3.12-selinux.diff
4 Log:
5 remove cruft from findutils selinux patch.
6 (Portage version: 2.1.4.4)
7
8 Revision Changes Path
9 1.2 sys-apps/findutils/files/findutils-4.3.12-selinux.diff
10
11 file : http://sources.gentoo.org/viewcvs.py/gentoo-x86/sys-apps/findutils/files/findutils-4.3.12-selinux.diff?rev=1.2&view=markup
12 plain: http://sources.gentoo.org/viewcvs.py/gentoo-x86/sys-apps/findutils/files/findutils-4.3.12-selinux.diff?rev=1.2&content-type=text/plain
13 diff : http://sources.gentoo.org/viewcvs.py/gentoo-x86/sys-apps/findutils/files/findutils-4.3.12-selinux.diff?r1=1.1&r2=1.2
14
15 Index: findutils-4.3.12-selinux.diff
16 ===================================================================
17 RCS file: /var/cvsroot/gentoo-x86/sys-apps/findutils/files/findutils-4.3.12-selinux.diff,v
18 retrieving revision 1.1
19 retrieving revision 1.2
20 diff -u -r1.1 -r1.2
21 --- findutils-4.3.12-selinux.diff 30 Jan 2008 14:02:05 -0000 1.1
22 +++ findutils-4.3.12-selinux.diff 1 Apr 2008 15:53:50 -0000 1.2
23 @@ -111,2037 +111,6 @@
24 .PP
25 A `%' character followed by any other character is discarded, but the
26 other character is printed (don't rely on this, as further format
27 -diff -purN findutils-4.3.12.orig/find/find.1.orig findutils-4.3.12/find/find.1.orig
28 ---- findutils-4.3.12.orig/find/find.1.orig 1969-12-31 19:00:00.000000000 -0500
29 -+++ findutils-4.3.12/find/find.1.orig 2007-12-19 14:53:14.000000000 -0500
30 -@@ -0,0 +1,2027 @@
31 -+.TH FIND 1 \" -*- nroff -*-
32 -+.SH NAME
33 -+find \- search for files in a directory hierarchy
34 -+.SH SYNOPSIS
35 -+.B find
36 -+[\-H] [\-L] [\-P] [\-D debugopts] [\-Olevel] [path...] [expression]
37 -+.SH DESCRIPTION
38 -+This manual page
39 -+documents the GNU version of
40 -+.BR find .
41 -+GNU
42 -+.B find
43 -+searches the directory tree rooted at each given file name by
44 -+evaluating the given expression from left to right, according to the
45 -+rules of precedence (see section OPERATORS), until the outcome is
46 -+known (the left hand side is false for \fIand\fR operations, true for
47 -+\fIor\fR), at which point
48 -+.B find
49 -+moves on to the next file name.
50 -+.PP
51 -+If you are using
52 -+.B find
53 -+in an environment where security is important (for example if you are
54 -+using it to seach directories that are writable by other users), you
55 -+should read the "Security Considerations" chapter of the findutils
56 -+documentation, which is called \fBFinding Files\fP and comes with
57 -+findutils. That document also includes a lot more detail
58 -+and discussion than this manual page, so you may find it a more useful
59 -+source of information.
60 -+.SH OPTIONS
61 -+The
62 -+.BR \-H ,
63 -+.B \-L
64 -+and
65 -+.B \-P
66 -+options control the treatment of symbolic
67 -+links. Command-line arguments following these are taken to be names
68 -+of files or directories to be examined, up to the first argument that
69 -+begins with `\-', or the argument `(' or `!'. That argument and any
70 -+following arguments are taken to be the expression describing what is
71 -+to be searched for. If no paths are given, the current directory is
72 -+used. If no expression is given, the expression
73 -+.B \-print
74 -+is used
75 -+(but you should probably consider using
76 -+.B \-print0
77 -+instead, anyway).
78 -+.PP
79 -+This manual page talks about `options' within the expression list.
80 -+These options control the behaviour of
81 -+.B find
82 -+but are specified immediately after the last path name. The five
83 -+`real' options
84 -+.BR \-H ,
85 -+.BR \-L ,
86 -+.BR \-P ,
87 -+.B \-D
88 -+and
89 -+.B \-O
90 -+must appear before
91 -+the first path name, if at all. A double dash
92 -+.B \-\-
93 -+can also be used
94 -+to signal that any remaining arguments are not options (though
95 -+ensuring that all start points begin with either `./' or `/' is
96 -+generally safer if you use wildcards in the list of start points).
97 -+.IP \-P
98 -+Never follow symbolic links. This is the default behaviour. When
99 -+.B find
100 -+examines or prints information a file, and the file is a symbolic
101 -+link, the information used shall be taken from the properties of the
102 -+symbolic link itself.
103 -+
104 -+.IP \-L
105 -+Follow symbolic links. When
106 -+.B find
107 -+examines or prints information about files, the information used shall
108 -+be taken from the properties of the file to which the link points, not
109 -+from the link itself (unless it is a broken symbolic link or
110 -+.B find
111 -+is unable to examine the file to which the link points). Use of this
112 -+option implies
113 -+.BR \-noleaf .
114 -+If you later use the
115 -+.B \-P
116 -+option,
117 -+.B \-noleaf
118 -+will still be in effect. If
119 -+.B \-L
120 -+is in effect and
121 -+.B find
122 -+discovers a symbolic link to a subdirectory during its search,
123 -+the subdirectory pointed to by the symbolic link will be searched.
124 -+.IP
125 -+When the
126 -+.B \-L
127 -+option is in effect, the
128 -+.B \-type
129 -+predicate will always
130 -+match against the type of the file that a symbolic link points to
131 -+rather than the link itself (unless the symbolic link is broken).
132 -+Using
133 -+.B \-L
134 -+causes the
135 -+.B \-lname
136 -+and
137 -+.B \-ilname
138 -+predicates always to return
139 -+false.
140 -+
141 -+.IP \-H
142 -+Do not follow symbolic links, except while processing the command
143 -+line arguments. When
144 -+.B find
145 -+examines or prints information about files, the information used
146 -+shall be taken from the properties of the symbolic link itself. The
147 -+only exception to this behaviour is when a file specified on the
148 -+command line is a symbolic link, and the link can be resolved. For
149 -+that situation, the information used is taken from whatever the link
150 -+points to (that is, the link is followed). The information about the
151 -+link itself is used as a fallback if the file pointed to by the
152 -+symbolic link cannot be examined. If
153 -+.B \-H
154 -+is in effect and one of the
155 -+paths specified on the command line is a symbolic link to a directory,
156 -+the contents of that directory will be examined (though of course
157 -+\-maxdepth 0 would prevent this).
158 -+.P
159 -+If more than one of
160 -+.BR \-H ,
161 -+.B \-L
162 -+and
163 -+.B \-P
164 -+is specified, each overrides the
165 -+others; the last one appearing on the command line takes effect.
166 -+Since it is the default, the
167 -+.B \-P
168 -+option should be considered to be in
169 -+effect unless either
170 -+.B \-H
171 -+or
172 -+.B \-L
173 -+is specified.
174 -+
175 -+GNU
176 -+.B find
177 -+frequently stats files during the processing of the command line
178 -+itself, before any searching has begun. These options also affect how
179 -+those arguments are processed. Specifically, there are a number of
180 -+tests that compare files listed on the command line against a file we
181 -+are currently considering. In each case, the file specified on the
182 -+command line will have been examined and some of its properties will
183 -+have been saved. If the named file is in fact a symbolic link, and
184 -+the
185 -+.B \-P
186 -+option is in effect (or if neither
187 -+.B \-H
188 -+nor
189 -+.B \-L
190 -+were specified), the information used for the comparison will be taken from
191 -+the properties of the symbolic link. Otherwise, it will be taken from
192 -+the properties of the file the link points to. If
193 -+.B find
194 -+cannot follow the link (for example because it has insufficient
195 -+privileges or the link points to a nonexistent file) the properties of
196 -+the link itself will be used.
197 -+.P
198 -+When the
199 -+.B \-H
200 -+or
201 -+.B \-L options are in effect, any symbolic links listed
202 -+as the argument of
203 -+.B \-newer
204 -+will be dereferenced, and the timestamp
205 -+will be taken from the file to which the symbolic link points. The
206 -+same consideration applies to
207 -+.BR \-newerXY ,
208 -+.B \-anewer
209 -+and
210 -+.BR \-cnewer .
211 -+
212 -+The
213 -+.B \-follow
214 -+option has a similar effect to
215 -+.BR \-L ,
216 -+though it takes
217 -+effect at the point where it appears (that is, if
218 -+.B \-L
219 -+is not used but
220 -+.B \-follow
221 -+is, any symbolic links appearing after
222 -+.B \-follow
223 -+on the
224 -+command line will be dereferenced, and those before it will not).
225 -+
226 -+.IP "\-D debugoptions"
227 -+Print diagnostic information; this can be helpful to diagnose problems
228 -+with why
229 -+.B find
230 -+is not doing what you want. The list of debug options should be comma
231 -+separated. Compatibility of the debug options is not guaranteed
232 -+between releases of findutils. For a complete list of valid debug
233 -+options, see the output of
234 -+.B find \-D
235 -+.BR help .
236 -+Valid debug options include
237 -+.RS
238 -+.IP help
239 -+Explain the debugging options
240 -+.IP tree
241 -+Show the expression tree in its original and optimised form.
242 -+.IP stat
243 -+Print messages as files are examined with the
244 -+.B stat
245 -+and
246 -+.B lstat
247 -+system calls. The
248 -+.B find
249 -+program tries to minimise such calls.
250 -+.IP opt
251 -+Prints diagnostic information relating to the optimisation of the
252 -+expression tree; see the \-O option.
253 -+.IP rates
254 -+Prints a summary indicating how often each predicate succeeded or
255 -+failed.
256 -+.RE
257 -+.IP \-Olevel
258 -+Enables query optimisation. The
259 -+.B find
260 -+program reorders tests to speed up execution while preserving the
261 -+overall effect; that is, predicates with side effects are not
262 -+reordered relative to each other. The optimisations performed at each
263 -+optimisation level are as follows.
264 -+.RS
265 -+.IP 0
266 -+Equivalent to optimisation level 1.
267 -+.IP 1
268 -+This is the default optimisation level and corresponds to the
269 -+traditional behaviour. Expressions are reordered so that tests based
270 -+only on the names of files (for example
271 -+.B \-name
272 -+and
273 -+.BR \-regex )
274 -+are performed first.
275 -+.IP 2
276 -+Any
277 -+.B \-type
278 -+or
279 -+.B \-xtype
280 -+tests are performed after any tests based only on the names of files,
281 -+but before any tests that require information from the inode. On many
282 -+modern versions of Unix, file types are returned by
283 -+.B readdir()
284 -+and so these predicates are faster to evaluate than predicates which
285 -+need to stat the file first.
286 -+.IP 3
287 -+At this optimisation level, the full cost-based query optimiser is
288 -+enabled. The order of tests is modified so that cheap (i.e. fast)
289 -+tests are performed first and more expensive ones are performed later,
290 -+if necessary. Within each cost band, predicates are evaluated earlier
291 -+or later according to whether they are likely to succeed or not. For
292 -+.BR \-o ,
293 -+predicates which are likely to succeed are evaluated earlier, and for
294 -+.BR \-a ,
295 -+predicates which are likely to fail are evaluated earlier.
296 -+.RE
297 -+.IP
298 -+The cost-based optimiser has a fixed idea of how likely any given test
299 -+is to succeed. In some cases the probability takes account of the
300 -+specific nature of the test (for example,
301 -+.B \-type f
302 -+is assumed to be more likely to succeed than
303 -+.BR "\-type c" ).
304 -+The cost-based optimiser is currently being evaluated. If it does
305 -+not actually improve the performance of
306 -+.BR find ,
307 -+it will be removed again. Conversely, optimisations that prove to be
308 -+reliable, robust and effective may be enabled at lower optimisation
309 -+levels over time. However, the default behaviour (i.e. optimisation
310 -+level 1) will not be changed in the 4.3.x release series. The
311 -+findutils test suite runs all the tests on
312 -+.B find
313 -+at each optimisation level and ensures that the result is the same.
314 -+.P
315 -+.SH EXPRESSIONS
316 -+The expression is made up of options (which affect overall operation
317 -+rather than the processing of a specific file, and always return
318 -+true), tests (which return a true or false value), and actions (which
319 -+have side effects and return a true or false value), all separated by
320 -+operators.
321 -+.B \-and
322 -+is assumed where the operator is omitted.
323 -+
324 -+If the expression contains no actions other than
325 -+.BR \-prune ,
326 -+.B \-print
327 -+is
328 -+performed on all files for which the expression is true.
329 -+
330 -+.SS OPTIONS
331 -+.P
332 -+All options always return true. Except for
333 -+.BR \-daystart ,
334 -+.B \-follow
335 -+and
336 -+.BR \-regextype ,
337 -+the options affect all tests, including tests specified
338 -+before the option. This is because the options are processed when the
339 -+command line is parsed, while the tests don't do anything until files
340 -+are examined. The
341 -+.BR \-daystart ,
342 -+.B \-follow
343 -+and
344 -+.B \-regextype
345 -+options are different in this respect, and have an effect only on tests which
346 -+appear later in the command line. Therefore, for clarity, it is best
347 -+to place them at the beginning of the expression. A warning is issued
348 -+if you don't do this.
349 -+
350 -+.IP \-d
351 -+A synonym for \-depth, for compatibility with FreeBSD, NetBSD, MacOS X and OpenBSD.
352 -+
353 -+.IP \-daystart
354 -+Measure times (for
355 -+.BR \-amin ,
356 -+.BR \-atime ,
357 -+.BR \-cmin ,
358 -+.BR \-ctime ,
359 -+.BR \-mmin ,
360 -+and
361 -+.BR \-mtime )
362 -+from the beginning of today rather than from 24 hours ago. This
363 -+option only affects tests which appear later on the command line.
364 -+
365 -+.IP \-depth
366 -+Process each directory's contents before the directory itself. The
367 -+\-delete action also implies
368 -+.BR \-depth .
369 -+
370 -+.IP \-follow
371 -+Deprecated; use the
372 -+.B \-L
373 -+option instead. Dereference symbolic links.
374 -+Implies
375 -+.BR \-noleaf .
376 -+The
377 -+.B \-follow
378 -+option affects only those tests which
379 -+appear after it on the command line. Unless the
380 -+.B \-H
381 -+or
382 -+.B \-L
383 -+option has
384 -+been specified, the position of the
385 -+.B \-follow
386 -+option changes the behaviour of the
387 -+.B \-newer
388 -+predicate; any files listed as the argument
389 -+of
390 -+.B \-newer
391 -+will be dereferenced if they are symbolic links. The same
392 -+consideration applies to
393 -+.BR \-newerXY ,
394 -+.B \-anewer
395 -+and
396 -+.BR \-cnewer .
397 -+Similarly, the
398 -+.B \-type
399 -+predicate will always match against the type of the file
400 -+that a symbolic link points to rather than the link itself. Using
401 -+.B \-follow
402 -+causes the
403 -+.B \-lname and
404 -+.B \-ilname
405 -+predicates always to return false.
406 -+
407 -+.IP "\-help, \-\-help"
408 -+Print a summary of the command-line usage of
409 -+.B find
410 -+and exit.
411 -+
412 -+.IP \-ignore_readdir_race
413 -+Normally, \fBfind\fR will emit an error message when it fails to stat a file.
414 -+If you give this option and a file is deleted between the time \fBfind\fR
415 -+reads the name of the file from the directory and the time it tries to stat
416 -+the file, no error message will be issued. This also applies to files
417 -+or directories whose names are given on the command line. This option takes
418 -+effect at the time the command line is read, which means that you cannot search
419 -+one part of the filesystem with this option on and part of it with this option
420 -+off (if you need to do that, you will need to issue two \fBfind\fR commands
421 -+instead, one with the option and one without it).
422 -+
423 -+.IP "\-maxdepth \fIlevels\fR"
424 -+Descend at most \fIlevels\fR (a non-negative integer) levels of
425 -+directories below the command line arguments.
426 -+.B \-maxdepth 0
427 -+ means only apply the tests and actions to the command line arguments.
428 -+
429 -+.IP "\-mindepth \fIlevels\fR"
430 -+Do not apply any tests or actions at levels less than \fIlevels\fR (a
431 -+non-negative integer).
432 -+.B \-mindepth 1
433 -+means process all files except the command line arguments.
434 -+
435 -+.IP \-mount
436 -+Don't descend directories on other filesystems. An alternate name for
437 -+.BR \-xdev ,
438 -+for compatibility with some other versions of
439 -+.BR find .
440 -+
441 -+.IP \-noignore_readdir_race
442 -+Turns off the effect of
443 -+.BR \-ignore_readdir_race .
444 -+
445 -+.IP "\-noleaf"
446 -+Do not optimize by assuming that directories contain 2 fewer
447 -+subdirectories than their hard link count. This option is needed when
448 -+searching filesystems that do not follow the Unix directory-link
449 -+convention, such as CD-ROM or MS-DOS filesystems or AFS volume mount
450 -+points. Each directory on a normal Unix filesystem has at least 2
451 -+hard links: its name and its `.' entry. Additionally, its
452 -+subdirectories (if any) each have a `..' entry linked to that
453 -+directory. When
454 -+.B find
455 -+is examining a directory, after it has statted 2 fewer subdirectories
456 -+than the directory's link count, it knows that the rest of the entries
457 -+in the directory are non-directories (`leaf' files in the directory
458 -+tree). If only the files' names need to be examined, there is no need
459 -+to stat them; this gives a significant increase in search speed.
460 -+
461 -+.IP "\-regextype \fItype\fR"
462 -+Changes the regular expression syntax understood by
463 -+.B \-regex
464 -+and
465 -+.B \-iregex
466 -+tests which occur later on the command line. Currently-implemented
467 -+types are emacs (this is the default), posix-awk, posix-basic,
468 -+posix-egrep and posix-extended.
469 -+
470 -+.IP "\-version, \-\-version"
471 -+Print the \fBfind\fR version number and exit.
472 -+
473 -+.IP "\-warn, \-nowarn"
474 -+Turn warning messages on or off. These warnings apply only to the
475 -+command line usage, not to any conditions that
476 -+.B find
477 -+might encounter when it searches directories. The default behaviour
478 -+corresponds to
479 -+.B \-warn
480 -+if standard input is a tty, and to
481 -+.B \-nowarn
482 -+otherwise.
483 -+
484 -+.IP \-xdev
485 -+Don't descend directories on other filesystems.
486 -+
487 -+.SS TESTS
488 -+Some tests, for example
489 -+.B \-newerXY
490 -+and
491 -+.BR -samefile ,
492 -+allow comparison between the file currently being examined and some
493 -+reference file specified on the command line. When these tests are
494 -+used, the interpretation of the reference file is determined by the
495 -+options
496 -+.BR \-H ,
497 -+.B \-L
498 -+and
499 -+.B \-P
500 -+and any previous
501 -+.BR \-follow ,
502 -+but the reference file is only examined once, at the time the command
503 -+line is parsed. If the reference file cannot be examined (for
504 -+example, the
505 -+.BR stat (2)
506 -+system call fails for it), an error message is issued, and
507 -+.B find
508 -+exits with a nonzero status.
509 -+.P
510 -+Numeric arguments can be specified as
511 -+.IP \fI+n\fP
512 -+for greater than
513 -+.IR n ,
514 -+.IP \fI\-n\fP
515 -+for less than
516 -+.IR n ,
517 -+.IP \fIn\fP
518 -+for exactly
519 -+.IR n .
520 -+.P
521 -+
522 -+.IP "\-amin \fIn\fR"
523 -+File was last accessed \fIn\fR minutes ago.
524 -+
525 -+.IP "\-anewer \fIfile\fR"
526 -+File was last accessed more recently than \fIfile\fR was modified. If
527 -+\fIfile\fR is a symbolic link and the
528 -+.B \-H
529 -+option or the
530 -+.B \-L
531 -+option is in effect, the access time of the file it points to is
532 -+always used.
533 -+
534 -+.IP "\-atime \fIn\fR"
535 -+File was last accessed \fIn\fR*24 hours ago.
536 -+When find figures out how many 24-hour periods ago the file
537 -+was last accessed, any fractional part is ignored, so to match
538 -+.B \-atime
539 -+.BR +1 ,
540 -+a file has to have been accessed at least
541 -+.I two
542 -+days ago.
543 -+
544 -+.IP "\-cmin \fIn\fR"
545 -+File's status was last changed \fIn\fR minutes ago.
546 -+
547 -+.IP "\-cnewer \fIfile\fR"
548 -+File's status was last changed more recently than \fIfile\fR was
549 -+modified. If \fIfile\fR is a symbolic link and the
550 -+.B \-H
551 -+option or the
552 -+.B \-L
553 -+option is in effect, the status-change time of the file it points
554 -+to is always used.
555 -+
556 -+.IP "\-ctime \fIn\fR"
557 -+File's status was last changed \fIn\fR*24 hours ago.
558 -+See the comments for
559 -+.B \-atime
560 -+to understand how rounding affects the interpretation of file status
561 -+change times.
562 -+
563 -+.IP \-empty
564 -+File is empty and is either a regular file or a directory.
565 -+
566 -+.IP \-executable
567 -+Matches files which are executable and directories which are
568 -+searchable (in a file name resolution sense). This takes into account
569 -+access control lists and other permissions artefacts which the
570 -+.B \-perm
571 -+test ignores. This test makes use of the
572 -+.BR access (2)
573 -+system call, and so can be fooled by NFS servers which do UID
574 -+mapping (or root-squashing), since many systems implement
575 -+.BR access (2)
576 -+in the client's kernel and so cannot make use of the UID mapping
577 -+information held on the server. Because this test is based only on
578 -+the result of the
579 -+.BR access (2)
580 -+system call, there is no guarantee that a file for which this test
581 -+succeeds can actually be executed.
582 -+
583 -+.IP \-false
584 -+Always false.
585 -+
586 -+.IP "\-fstype \fItype\fR"
587 -+File is on a filesystem of type \fItype\fR. The valid filesystem
588 -+types vary among different versions of Unix; an incomplete list of
589 -+filesystem types that are accepted on some version of Unix or another
590 -+is: ufs, 4.2, 4.3, nfs, tmp, mfs, S51K, S52K. You can use
591 -+.B \-printf
592 -+with the %F directive to see the types of your filesystems.
593 -+
594 -+.IP "\-gid \fIn\fR"
595 -+File's numeric group ID is \fIn\fR.
596 -+
597 -+.IP "\-group \fIgname\fR"
598 -+File belongs to group \fIgname\fR (numeric group ID allowed).
599 -+
600 -+.IP "\-ilname \fIpattern\fR"
601 -+Like
602 -+.BR \-lname ,
603 -+but the match is case insensitive.
604 -+If the
605 -+.B \-L
606 -+option or the
607 -+.B \-follow
608 -+option is in effect, this test returns false unless the symbolic link
609 -+is broken.
610 -+
611 -+.IP "\-iname \fIpattern\fR"
612 -+Like
613 -+.BR \-name ,
614 -+but the match is case insensitive. For example, the
615 -+patterns `fo*' and `F??' match the file names `Foo', `FOO', `foo',
616 -+`fOo', etc. In these patterns, unlike filename expansion by the
617 -+shell, an initial '.' can be matched by `*'. That is,
618 -+.B find \-name *bar
619 -+will match the file `.foobar'. Please note that you should quote
620 -+patterns as a matter of course, otherwise the shell will expand any
621 -+wildcard characters in them.
622 -+
623 -+.IP "\-inum \fIn\fR"
624 -+File has inode number \fIn\fR. It is normally easier to use the
625 -+.B \-samefile
626 -+test instead.
627 -+
628 -+.IP "\-ipath \fIpattern\fR"
629 -+Behaves in the same way as
630 -+.BR \-iwholename .
631 -+This option is deprecated, so please do not use it.
632 -+
633 -+.IP "\-iregex \fIpattern\fR"
634 -+Like
635 -+.BR \-regex ,
636 -+but the match is case insensitive.
637 -+
638 -+.IP "\-iwholename \fIpattern\fR"
639 -+Like
640 -+.BR \-wholename ,
641 -+but the match is case insensitive.
642 -+
643 -+.IP "\-links \fIn\fR"
644 -+File has \fIn\fR links.
645 -+
646 -+.IP "\-lname \fIpattern\fR"
647 -+File is a symbolic link whose contents match shell pattern
648 -+\fIpattern\fR. The metacharacters do not treat `/' or `.' specially.
649 -+If the
650 -+.B \-L
651 -+option or the
652 -+.B \-follow
653 -+option is in effect, this test returns false unless the symbolic link
654 -+is broken.
655 -+
656 -+.IP "\-mmin \fIn\fR"
657 -+File's data was last modified \fIn\fR minutes ago.
658 -+
659 -+.IP "\-mtime \fIn\fR"
660 -+File's data was last modified \fIn\fR*24 hours ago.
661 -+See the comments for
662 -+.B \-atime
663 -+to understand how rounding affects the interpretation of file
664 -+modification times.
665 -+
666 -+.IP "\-name \fIpattern\fR"
667 -+Base of file name (the path with the leading directories removed)
668 -+matches shell pattern \fIpattern\fR. The metacharacters (`*', `?',
669 -+and `[]') match a `.' at the start of the base name (this is a change
670 -+in findutils-4.2.2; see section STANDARDS CONFORMANCE below). To ignore a
671 -+directory and the files under it, use
672 -+.BR \-prune ;
673 -+see an example in the
674 -+description of
675 -+.BR \-path .
676 -+Braces are not recognised as being
677 -+special, despite the fact that some shells including Bash imbue braces
678 -+with a special meaning in shell patterns. The filename matching is
679 -+performed with the use of the
680 -+.BR fnmatch (3)
681 -+library function. Don't forget to enclose the pattern in quotes
682 -+in order to protect it from expansion by the shell.
683 -+
684 -+.IP "\-newer \fIfile\fR"
685 -+File was modified more recently than \fIfile\fR. If \fIfile\fR is a
686 -+symbolic link and the
687 -+.B \-H
688 -+option or the
689 -+.B \-L
690 -+option is in effect, the
691 -+modification time of the file it points to is always used.
692 -+
693 -+.IP "\-newerXY \fIreference\fR"
694 -+Compares the timestamp of the current file with \fIreference\fR.
695 -+The
696 -+.I reference
697 -+argument is normally the name of a file (and one of its timestamps is
698 -+used for the comparison) but it may also be a string describing an
699 -+absolute time.
700 -+.I X
701 -+and
702 -+.I Y
703 -+are placeholders for other letters, and these letters select which
704 -+time belonging to
705 -+how
706 -+.I reference
707 -+is used for the comparison.
708 -+.TS
709 -+ll
710 -+ll
711 -+ll
712 -+ll
713 -+llw(2i).
714 -+a The access time of the file \fIreference\fR
715 -+B The birth time of the file \fIreference\fR
716 -+c The inode status change time of \fIreference\fR
717 -+m The modification time of the file \fIreference\fR
718 -+t \fIreference\fR is interpreted directly as a time
719 -+.TE
720 -+
721 -+Some combinations are invalid; for example, it is invalid for
722 -+.I X
723 -+to be
724 -+.IR t .
725 -+Some combinations are not implemented on all systems; for example
726 -+.I B
727 -+is not supported on all systems. If an invalid or unsupported
728 -+combination of
729 -+.I XY
730 -+is specified, a fatal error results. Time specifications are
731 -+interpreted as for the argument to the
732 -+.B \-d
733 -+option of GNU
734 -+.BR date .
735 -+If you try to use the birth time of a reference file, and the birth
736 -+time cannot be determined, a fatal error message results. If you
737 -+specify a test which refers to the birth time of files being examined,
738 -+this test will fail for any files where the birth time is unknown.
739 -+
740 -+.IP \-nogroup
741 -+No group corresponds to file's numeric group ID.
742 -+
743 -+.IP \-nouser
744 -+No user corresponds to file's numeric user ID.
745 -+
746 -+.IP "\-path \fIpattern\fR"
747 -+File name matches shell pattern \fIpattern\fR. The metacharacters do
748 -+not treat `/' or `.' specially; so, for example,
749 -+.br
750 -+.in +1i
751 -+find . \-path "./sr*sc"
752 -+.br
753 -+.in -1i
754 -+will print an entry for a directory called `./src/misc' (if one
755 -+exists). To ignore a whole directory tree, use
756 -+.B \-prune
757 -+rather than
758 -+checking every file in the tree. For example, to skip the
759 -+directory `src/emacs' and all files and directories under it, and
760 -+print the names of the other files found, do something like this:
761 -+.br
762 -+.in +1i
763 -+find . \-path ./src/emacs \-prune \-o \-print
764 -+.br
765 -+.in -1i
766 -+Note that the pattern match test applies to the whole file name,
767 -+starting from one of the start points named on the command line. It
768 -+would only make sense to use an absolute path name here if the
769 -+relevant start point is also an absolute path. This means that this
770 -+command will never match anything:
771 -+.br
772 -+.in +1i
773 -+find bar \-path /foo/bar/myfile \-print
774 -+.br
775 -+.in -1i
776 -+The predicate
777 -+.B \-path
778 -+is also supported by HP-UX
779 -+.B find
780 -+and will be in a forthcoming version of the POSIX standard.
781 -+
782 -+.IP "\-perm \fImode\fR"
783 -+File's permission bits are exactly \fImode\fR (octal or symbolic).
784 -+Since an exact match is required, if you want to use this form for
785 -+symbolic modes, you may have to specify a rather complex mode string.
786 -+For example
787 -+.B \-perm g=w
788 -+will only match files which have mode 0020
789 -+(that is, ones for which group write permission is the only permission
790 -+set). It is more likely that you will want to use the `/' or `-'
791 -+forms, for example
792 -+.BR "\-perm \-g=w" ,
793 -+which matches any file with group write permission. See the
794 -+.B EXAMPLES
795 -+section for some illustrative examples.
796 -+
797 -+.IP "\-perm \-\fImode\fR"
798 -+All of the permission bits \fImode\fR are set for the file.
799 -+Symbolic modes are accepted in this form, and this is usually the way
800 -+in which would want to use them. You must specify `u', `g' or `o' if
801 -+you use a symbolic mode. See the
802 -+.B EXAMPLES
803 -+section for some illustrative examples.
804 -+
805 -+.IP "\-perm /\fImode\fR"
806 -+Any of the permission bits \fImode\fR are set for the file. Symbolic
807 -+modes are accepted in this form. You must specify `u', `g' or `o' if
808 -+you use a symbolic mode. See the
809 -+.B EXAMPLES
810 -+section for some illustrative examples. If no permission bits in
811 -+.I mode
812 -+are set, this test currently matches no files. However, it will soon
813 -+be changed to match any file (the idea is to be more consistent with
814 -+the behaviour of
815 -+.B \-perm
816 -+.BR \-000 ).
817 -+
818 -+.IP "\-perm +\fImode\fR"
819 -+Deprecated, old way of searching for files with any of the permission
820 -+bits in \fImode\fR set. You should use
821 -+.B \-perm \fI/mode\fR
822 -+instead. Trying to use the `+' syntax with symbolic modes will yield
823 -+surprising results. For example, `+u+x' is a valid symbolic mode
824 -+(equivalent to +u,+x, i.e. 0111) and will therefore not be evaluated
825 -+as
826 -+.B \-perm +\fImode\fR
827 -+but instead as the exact mode specifier
828 -+.B \-perm \fImode\fR
829 -+and so it matches files with exact permissions 0111 instead of files with any
830 -+execute bit set. If you found this paragraph confusing, you're not
831 -+alone - just use
832 -+.B \-perm /\fImode\fR.
833 -+This form of the
834 -+.B \-perm
835 -+test is deprecated because the POSIX specification requires the
836 -+interpretation of a leading `+' as being part of a symbolic mode, and
837 -+so we switched to using `/' instead.
838 -+
839 -+.IP \-readable
840 -+Matches files which are readable. This takes into account access
841 -+control lists and other permissions artefacts which the
842 -+.B \-perm
843 -+test ignores. This test makes use of the
844 -+.BR access (2)
845 -+system call, and so can be fooled by NFS servers which do UID
846 -+mapping (or root-squashing), since many systems implement
847 -+.BR access (2)
848 -+in the client's kernel and so cannot make use of the UID mapping
849 -+information held on the server.
850 -+
851 -+.IP "\-regex \fIpattern\fR"
852 -+File name matches regular expression \fIpattern\fR. This is a match
853 -+on the whole path, not a search. For example, to match a file named
854 -+`./fubar3', you can use the regular expression `.*bar.' or `.*b.*3',
855 -+but not `f.*r3'. The regular expressions understood by
856 -+.B find
857 -+are by default Emacs Regular Expressions, but this can be
858 -+changed with the
859 -+.B \-regextype
860 -+option.
861 -+
862 -+.IP "\-samefile \fIname\fR"
863 -+File refers to the same inode as \fIname\fR. When
864 -+.B \-L
865 -+is in effect, this can include symbolic links.
866 -+
867 -+.IP "\-size \fIn\fR[cwbkMG]"
868 -+File uses \fIn\fP units of space. The following suffixes
869 -+can be used:
870 -+.RS
871 -+.IP `b'
872 -+for 512-byte blocks (this is the default if no suffix is used)
873 -+.IP `c'
874 -+for bytes
875 -+.IP `w'
876 -+for two-byte words
877 -+.IP `k'
878 -+for Kilobytes (units of 1024 bytes)
879 -+.IP `M'
880 -+for Megabytes (units of 1048576 bytes)
881 -+.IP `G'
882 -+for Gigabytes (units of 1073741824 bytes)
883 -+.RE
884 -+.IP
885 -+The size does not count indirect blocks, but it does count blocks in
886 -+sparse files that are not actually allocated. Bear in mind that the
887 -+`%k' and `%b' format specifiers of
888 -+.B \-printf
889 -+handle sparse files
890 -+differently. The `b' suffix always denotes 512-byte blocks and never
891 -+1 Kilobyte blocks, which is different to the behaviour of
892 -+.BR \-ls .
893 -+
894 -+.IP \-true
895 -+Always true.
896 -+
897 -+.IP "\-type \fIc\fR"
898 -+File is of type \fIc\fR:
899 -+.RS
900 -+.IP b
901 -+block (buffered) special
902 -+.IP c
903 -+character (unbuffered) special
904 -+.IP d
905 -+directory
906 -+.IP p
907 -+named pipe (FIFO)
908 -+.IP f
909 -+regular file
910 -+.IP l
911 -+symbolic link; this is never true if the
912 -+.B \-L
913 -+option or the
914 -+.B \-follow
915 -+option is in effect, unless the symbolic link is broken. If you want
916 -+to search for symbolic links when
917 -+.B \-L
918 -+is in effect, use
919 -+.BR \-xtype .
920 -+.IP s
921 -+socket
922 -+.IP D
923 -+door (Solaris)
924 -+.RE
925 -+.IP "\-uid \fIn\fR"
926 -+File's numeric user ID is \fIn\fR.
927 -+
928 -+.IP "\-used \fIn\fR"
929 -+File was last accessed \fIn\fR days after its status was last changed.
930 -+
931 -+.IP "\-user \fIuname\fR"
932 -+File is owned by user \fIuname\fR (numeric user ID allowed).
933 -+
934 -+.IP "\-wholename \fIpattern\fR"
935 -+See \-path. This alternative is less portable than
936 -+.BR \-path .
937 -+
938 -+.IP "\-writable"
939 -+Matches files which are writable. This takes into account access
940 -+control lists and other permissions artefacts which the
941 -+.B \-perm
942 -+test ignores. This test makes use of the
943 -+.BR access (2)
944 -+system call, and so can be fooled by NFS servers which do UID
945 -+mapping (or root-squashing), since many systems implement
946 -+.BR access (2)
947 -+in the client's kernel and so cannot make use of the UID mapping
948 -+information held on the server.
949 -+
950 -+.IP "\-xtype \fIc\fR"
951 -+The same as
952 -+.B \-type
953 -+unless the file is a symbolic link. For symbolic
954 -+links: if the
955 -+.B \-H
956 -+or
957 -+.B \-P
958 -+option was specified, true if the file is a
959 -+link to a file of type \fIc\fR; if the
960 -+.B \-L
961 -+option has been given, true
962 -+if \fIc\fR is `l'. In other words, for symbolic links,
963 -+.B \-xtype
964 -+checks the type of the file that
965 -+.B \-type
966 -+does not check.
967 -+
968 -+.SS ACTIONS
969 -+.IP "\-delete\fR"
970 -+Delete files; true if removal succeeded. If the removal failed, an
971 -+error message is issued.
972 -+If
973 -+.B \-delete
974 -+fails,
975 -+.BR find 's
976 -+exit status will be nonzero
977 -+(when it eventually exits).
978 -+Use of
979 -+.B \-delete
980 -+automatically turns on the
981 -+.B \-depth
982 -+option.
983 -+
984 -+.BR Warnings :
985 -+Don't forget that the find command line is
986 -+evaluated as an expression, so putting
987 -+.B \-delete
988 -+first will make
989 -+.B find
990 -+try to delete everything below the starting points you specified.
991 -+When testing a
992 -+.B find
993 -+command line that you later intend to use with
994 -+.BR \-delete ,
995 -+you should explicitly specify
996 -+.B \-depth
997 -+in order to avoid later surprises. Because
998 -+.B \-delete
999 -+implies
1000 -+.BR \-depth ,
1001 -+you cannot usefully use
1002 -+.B \-prune
1003 -+and
1004 -+.B \-delete
1005 -+together.
1006 -+
1007 -+.IP "\-exec \fIcommand\fR ;"
1008 -+Execute \fIcommand\fR; true if 0 status is returned. All following
1009 -+arguments to
1010 -+.B find
1011 -+are taken to be arguments to the command until an argument consisting
1012 -+of `;' is encountered. The string `{}' is replaced by the current
1013 -+file name being processed everywhere it occurs in the arguments to the
1014 -+command, not just in arguments where it is alone, as in some versions
1015 -+of
1016 -+.BR find .
1017 -+Both of these constructions might need to be escaped (with a `\e') or
1018 -+quoted to protect them from expansion by the shell. See the
1019 -+.B EXAMPLES
1020 -+section for examples of the use of the
1021 -+.B \-exec
1022 -+option. The specified
1023 -+command is run once for each matched file.
1024 -+The command is executed in the starting directory. There are
1025 -+unavoidable security problems surrounding use of the
1026 -+.B \-exec
1027 -+action;
1028 -+you should use the
1029 -+.B \-execdir
1030 -+option instead.
1031 -+
1032 -+.IP "\-exec \fIcommand\fR {} +"
1033 -+This variant of the
1034 -+.B \-exec
1035 -+action runs the specified command on the
1036 -+selected files, but the command line is built by appending each
1037 -+selected file name at the end; the total number of invocations of the
1038 -+command will be much less than the number of matched files. The
1039 -+command line is built in much the same way that
1040 -+.B xargs
1041 -+builds its command lines. Only one instance of `{}' is allowed within
1042 -+the command. The command is executed in the starting directory.
1043 -+
1044 -+.IP "\-execdir \fIcommand\fR ;"
1045 -+.IP "\-execdir \fIcommand\fR {} +"
1046 -+Like
1047 -+.BR \-exec ,
1048 -+but the specified command is run from the subdirectory
1049 -+containing the matched file, which is not normally the directory in
1050 -+which you started
1051 -+.BR find .
1052 -+This a much more secure method for invoking commands, as it avoids
1053 -+race conditions during resolution of the paths to the matched files.
1054 -+As with the
1055 -+.B \-exec
1056 -+action, the `+' form of
1057 -+.B \-execdir
1058 -+will build a
1059 -+command line to process more than one matched file, but any given
1060 -+invocation of
1061 -+.I command
1062 -+will only list files that exist in the same subdirectory. If you use
1063 -+this option, you must ensure that your
1064 -+.B $PATH
1065 -+environment variable does not reference `.';
1066 -+otherwise, an attacker can run any commands they like by leaving an
1067 -+appropriately-named file in a directory in which you will run
1068 -+.BR \-execdir .
1069 -+The same applies to having entries in
1070 -+.B $PATH
1071 -+which are empty or which are not absolute directory names.
1072 -+
1073 -+.IP "\-fls \fIfile\fR"
1074 -+True; like
1075 -+.B \-ls
1076 -+but write to \fIfile\fR like
1077 -+.BR \-fprint .
1078 -+The output file is always created, even if the predicate is never
1079 -+matched.
1080 -+See the
1081 -+.B UNUSUAL FILENAMES
1082 -+section for information about how unusual characters in filenames are handled.
1083 -+
1084 -+.IP "\-fprint \fIfile\fR"
1085 -+True; print the full file name into file \fIfile\fR. If \fIfile\fR
1086 -+does not exist when \fBfind\fR is run, it is created; if it does
1087 -+exist, it is truncated. The file names ``/dev/stdout'' and
1088 -+``/dev/stderr'' are handled specially; they refer to the standard
1089 -+output and standard error output, respectively.
1090 -+The output file is always created, even if the predicate is never matched.
1091 -+See the
1092 -+.B UNUSUAL FILENAMES
1093 -+section for information about how unusual characters in filenames are handled.
1094 -+
1095 -+.IP "\-fprint0 \fIfile\fR"
1096 -+True; like
1097 -+.B \-print0
1098 -+but write to \fIfile\fR like
1099 -+.BR \-fprint .
1100 -+The output file is always created, even if the predicate is never matched.
1101 -+See the
1102 -+.B UNUSUAL FILENAMES
1103 -+section for information about how unusual characters in filenames are handled.
1104 -+
1105 -+.IP "\-fprintf \fIfile\fR \fIformat\fR"
1106 -+True; like
1107 -+.B \-printf
1108 -+but write to \fIfile\fR like
1109 -+.BR \-fprint .
1110 -+The output file is always created, even if the predicate is never matched.
1111 -+See the
1112 -+.B UNUSUAL FILENAMES
1113 -+section for information about how unusual characters in filenames are handled.
1114 -+
1115 -+.IP \-ls
1116 -+True; list current file in
1117 -+.B ls \-dils
1118 -+format on standard output.
1119 -+The block counts are of 1K blocks, unless the environment variable
1120 -+POSIXLY_CORRECT is set, in which case 512-byte blocks are used.
1121 -+See the
1122 -+.B UNUSUAL FILENAMES
1123 -+section for information about how unusual characters in filenames are handled.
1124 -+
1125 -+.IP "\-ok \fIcommand\fR ;"
1126 -+Like
1127 -+.B \-exec
1128 -+but ask the user first (on the standard input); if the
1129 -+response does not start with `y' or `Y', do not run the command, and
1130 -+return false. If the command is run, its standard input is redirected
1131 -+from
1132 -+.BR /dev/null .
1133 -+
1134 -+.IP "\-okdir \fIcommand\fR ;"
1135 -+Like
1136 -+.B \-execdir
1137 -+but ask the user first (on the standard input); if the
1138 -+response does not start with `y' or `Y', do not run the command, and
1139 -+return false. If the command is run, its standard input is redirected
1140 -+from
1141 -+.BR /dev/null .
1142 -+
1143 -+.IP \-print
1144 -+True; print the full file name on the standard output, followed by a
1145 -+newline. If you are piping the output of
1146 -+.B find
1147 -+into another program and there is the faintest possibility that the files
1148 -+which you are searching for might contain a newline, then you should
1149 -+seriously consider using the
1150 -+.B \-print0
1151 -+option instead of
1152 -+.BR \-print .
1153 -+See the
1154 -+.B UNUSUAL FILENAMES
1155 -+section for information about how unusual characters in filenames are handled.
1156 -+
1157 -+.IP \-print0
1158 -+True; print the full file name on the standard output, followed by a
1159 -+null character (instead of the newline character that
1160 -+.B \-print
1161 -+uses).
1162 -+This allows file names that contain newlines or other types of white
1163 -+space to be correctly interpreted by programs that process the
1164 -+\fBfind\fR output. This option corresponds to the
1165 -+.B \-0
1166 -+option of
1167 -+.BR xargs .
1168 -+
1169 -+.IP "\-printf \fIformat\fR"
1170 -+True; print \fIformat\fR on the standard output, interpreting `\e'
1171 -+escapes and `%' directives. Field widths and precisions can be
1172 -+specified as with the `printf' C function. Please note that many of
1173 -+the fields are printed as %s rather than %d, and this may mean that
1174 -+flags don't work as you might expect. This also means that the `\-'
1175 -+flag does work (it forces fields to be left-aligned). Unlike
1176 -+.BR \-print ,
1177 -+.B \-printf
1178 -+does not add a newline at the end of the string. The escapes
1179 -+and directives are:
1180 -+.RS
1181 -+.IP \ea
1182 -+Alarm bell.
1183 -+.IP \eb
1184 -+Backspace.
1185 -+.IP \ec
1186 -+Stop printing from this format immediately and flush the output.
1187 -+.IP \ef
1188 -+Form feed.
1189 -+.IP \en
1190 -+Newline.
1191 -+.IP \er
1192 -+Carriage return.
1193 -+.IP \et
1194 -+Horizontal tab.
1195 -+.IP \ev
1196 -+Vertical tab.
1197 -+.IP \e\0
1198 -+ASCII NUL.
1199 -+.IP \e\e
1200 -+A literal backslash (`\e').
1201 -+.IP \eNNN
1202 -+The character whose ASCII code is NNN (octal).
1203 -+.PP
1204 -+A `\e' character followed by any other character is treated as an
1205 -+ordinary character, so they both are printed.
1206 -+.IP %%
1207 -+A literal percent sign.
1208 -+.IP %a
1209 -+File's last access time in the format returned by the C `ctime' function.
1210 -+.IP %A\fIk\fP
1211 -+File's last access time in the format specified by \fIk\fR, which is
1212 -+either `@' or a directive for the C `strftime' function. The possible
1213 -+values for \fIk\fR are listed below; some of them might not be
1214 -+available on all systems, due to differences in `strftime' between
1215 -+systems.
1216 -+.RS
1217 -+.IP @
1218 -+seconds since Jan. 1, 1970, 00:00 GMT, with fractional part.
1219 -+.PP
1220 -+Time fields:
1221 -+.IP H
1222 -+hour (00..23)
1223 -+.IP I
1224 -+hour (01..12)
1225 -+.IP k
1226 -+hour ( 0..23)
1227 -+.IP l
1228 -+hour ( 1..12)
1229 -+.IP M
1230 -+minute (00..59)
1231 -+.IP p
1232 -+locale's AM or PM
1233 -+.IP r
1234 -+time, 12-hour (hh:mm:ss [AP]M)
1235 -+.IP S
1236 -+Second (00.00 .. 61.00). There is a fractional part.
1237 -+.IP T
1238 -+time, 24-hour (hh:mm:ss)
1239 -+.IP +
1240 -+Date and time, separated by `+', for example
1241 -+`2004\-04\-28+22:22:05.0'. This is a GNU extension. The time is
1242 -+given in the current timezone (which may be affected by setting the TZ
1243 -+environment variable). The seconds field includes a fractional part.
1244 -+.IP X
1245 -+locale's time representation (H:M:S)
1246 -+.IP Z
1247 -+time zone (e.g., EDT), or nothing if no time zone is determinable
1248 -+.PP
1249 -+Date fields:
1250 -+.IP a
1251 -+locale's abbreviated weekday name (Sun..Sat)
1252 -+.IP A
1253 -+locale's full weekday name, variable length (Sunday..Saturday)
1254 -+.IP b
1255 -+locale's abbreviated month name (Jan..Dec)
1256 -+.IP B
1257 -+locale's full month name, variable length (January..December)
1258 -+.IP c
1259 -+locale's date and time (Sat Nov 04 12:02:33 EST 1989). The format is
1260 -+the same as for
1261 -+.BR ctime (3)
1262 -+and so to preserve compatibility with that format, there is no fractional part
1263 -+in the seconds field.
1264 -+.IP d
1265 -+day of month (01..31)
1266 -+.IP D
1267 -+date (mm/dd/yy)
1268 -+.IP h
1269 -+same as b
1270 -+.IP j
1271 -+day of year (001..366)
1272 -+.IP m
1273 -+month (01..12)
1274 -+.IP U
1275 -+week number of year with Sunday as first day of week (00..53)
1276 -+.IP w
1277 -+day of week (0..6)
1278 -+.IP W
1279 -+week number of year with Monday as first day of week (00..53)
1280 -+.IP x
1281 -+locale's date representation (mm/dd/yy)
1282 -+.IP y
1283 -+last two digits of year (00..99)
1284 -+.IP Y
1285 -+year (1970...)
1286 -+.RE
1287 -+.IP %b
1288 -+The amount of disk space used for this file in 512-byte blocks. Since disk
1289 -+space is allocated in multiples of the filesystem block size this is usually
1290 -+greater than %s/512, but it can also be smaller if the file is a sparse file.
1291 -+.IP %c
1292 -+File's last status change time in the format returned by the C `ctime'
1293 -+function.
1294 -+.IP %C\fIk\fP
1295 -+File's last status change time in the format specified by \fIk\fR,
1296 -+which is the same as for %A.
1297 -+.IP %d
1298 -+File's depth in the directory tree; 0 means the file is a command line
1299 -+argument.
1300 -+.IP %D
1301 -+The device number on which the file exists (the st_dev field of struct
1302 -+stat), in decimal.
1303 -+.IP %f
1304 -+File's name with any leading directories removed (only the last element).
1305 -+.IP %F
1306 -+Type of the filesystem the file is on; this value can be used for
1307 -+\-fstype.
1308 -+.IP %g
1309 -+File's group name, or numeric group ID if the group has no name.
1310 -+.IP %G
1311 -+File's numeric group ID.
1312 -+.IP %h
1313 -+Leading directories of file's name (all but the last element).
1314 -+If the file name contains no slashes (since it is in the current
1315 -+directory) the %h specifier expands to ".".
1316 -+.IP %H
1317 -+Command line argument under which file was found.
1318 -+.IP %i
1319 -+File's inode number (in decimal).
1320 -+.IP %k
1321 -+The amount of disk space used for this file in 1K blocks. Since disk space is
1322 -+allocated in multiples of the filesystem block size this is usually greater
1323 -+than %s/1024, but it can also be smaller if the file is a sparse file.
1324 -+.IP %l
1325 -+Object of symbolic link (empty string if file is not a symbolic link).
1326 -+.IP %m
1327 -+File's permission bits (in octal). This option uses the `traditional'
1328 -+numbers which most Unix implementations use, but if your particular
1329 -+implementation uses an unusual ordering of octal permissions bits, you
1330 -+will see a difference between the actual value of the file's mode and
1331 -+the output of %m. Normally you will want to have a leading
1332 -+zero on this number, and to do this, you should use the
1333 -+.B #
1334 -+flag (as in, for example, `%#m').
1335 -+.IP %M
1336 -+File's permissions (in symbolic form, as for
1337 -+.BR ls ).
1338 -+This directive is supported in findutils 4.2.5 and later.
1339 -+.IP %n
1340 -+Number of hard links to file.
1341 -+.IP %p
1342 -+File's name.
1343 -+.IP %P
1344 -+File's name with the name of the command line argument under which
1345 -+it was found removed.
1346 -+.IP %s
1347 -+File's size in bytes.
1348 -+.IP %S
1349 -+File's sparseness. This is calculated as (BLOCKSIZE*st_blocks /
1350 -+st_size). The exact value you will get for an ordinary file of a
1351 -+certain length is system-dependent. However, normally sparse files
1352 -+will have values less than 1.0, and files which use indirect blocks
1353 -+may have a value which is greater than 1.0. The value used for
1354 -+BLOCKSIZE is system-dependent, but is usually 512 bytes. If the file
1355 -+size is zero, the value printed is undefined. On systems which lack
1356 -+support for st_blocks, a file's sparseness is assumed to be 1.0.
1357 -+.IP %t
1358 -+File's last modification time in the format returned by the C `ctime'
1359 -+function.
1360 -+.IP %T\fIk\fP
1361 -+File's last modification time in the format specified by \fIk\fR,
1362 -+which is the same as for %A.
1363 -+.IP %u
1364 -+File's user name, or numeric user ID if the user has no name.
1365 -+.IP %U
1366 -+File's numeric user ID.
1367 -+.IP %y
1368 -+File's type (like in
1369 -+.BR "ls \-l" ),
1370 -+U=unknown type (shouldn't happen)
1371 -+.IP %Y
1372 -+File's type (like %y), plus follow symlinks: L=loop, N=nonexistent
1373 -+.PP
1374 -+A `%' character followed by any other character is discarded, but the
1375 -+other character is printed (don't rely on this, as further format
1376 -+characters may be introduced). A `%' at the end of the format
1377 -+argument causes undefined behaviour since there is no following
1378 -+character. In some locales, it may hide your door keys, while in
1379 -+others it may remove the final page from the novel you are reading.
1380 -+
1381 -+The %m and %d directives support the
1382 -+.B #
1383 -+,
1384 -+.B 0
1385 -+and
1386 -+.B +
1387 -+flags, but the other directives do not, even if they
1388 -+print numbers. Numeric directives that do not support these flags
1389 -+include
1390 -+.BR G ,
1391 -+.BR U ,
1392 -+.BR b ,
1393 -+.BR D ,
1394 -+.B k
1395 -+and
1396 -+.BR n .
1397 -+The `\-' format flag is supported and changes the alignment of a field
1398 -+from right-justified (which is the default) to left-justified.
1399 -+.PP
1400 -+See the
1401 -+.B UNUSUAL FILENAMES
1402 -+section for information about how unusual characters in filenames are handled.
1403 -+
1404 -+
1405 -+.RE
1406 -+.IP \-prune
1407 -+True; if the file is a directory, do not descend into it. If
1408 -+.B \-depth
1409 -+is given, false; no effect. Because
1410 -+.B \-delete
1411 -+implies
1412 -+.BR \-depth ,
1413 -+you cannot usefully use
1414 -+.B \-prune
1415 -+and
1416 -+.B \-delete together.
1417 -+
1418 -+.IP "\-quit"
1419 -+Exit immediately. No child processes will be left running, but no more
1420 -+paths specified on the command line will be processed. For example,
1421 -+.B find /tmp/foo /tmp/bar \-print \-quit
1422 -+will print only
1423 -+.BR /tmp/foo .
1424 -+Any command lines which have been built up with
1425 -+.B \-execdir ... {} +
1426 -+will be invoked before
1427 -+.B find
1428 -+exits. The exit status may or may not be zero, depending on whether
1429 -+an error has already occurred.
1430 -+
1431 -+.SS UNUSUAL FILENAMES
1432 -+Many of the actions of
1433 -+.B find
1434 -+result in the printing of data which is under the control of other
1435 -+users. This includes file names, sizes, modification times and so
1436 -+forth. File names are a potential problem since they can contain any
1437 -+character except `\e0' and `/'. Unusual characters in file names can
1438 -+do unexpected and often undesirable things to your terminal (for
1439 -+example, changing the settings of your function keys on some
1440 -+terminals). Unusual characters are handled differently by various
1441 -+actions, as described below.
1442 -+
1443 -+.IP "\-print0, \-fprint0\"
1444 -+Always print the exact filename, unchanged, even if the output is
1445 -+going to a terminal.
1446 -+
1447 -+.IP "\-ls, \-fls"
1448 -+Unusual characters are always escaped. White space, backslash, and
1449 -+double quote characters are printed using C-style escaping (for
1450 -+example `\ef', `\e"'). Other unusual characters are printed using an
1451 -+octal escape. Other printable characters (for
1452 -+.B \-ls
1453 -+and
1454 -+.B \-fls
1455 -+these are the characters between octal 041 and 0176) are printed as-is.
1456 -+
1457 -+.IP "\-printf, \-fprintf"
1458 -+If the output is not going to a terminal, it is printed as-is.
1459 -+Otherwise, the result depends on which directive is in use. The
1460 -+directives %D, %F, %g, %G, %H, %Y, and %y expand to values which are
1461 -+not under control of files' owners, and so are printed as-is. The
1462 -+directives %a, %b, %c, %d, %i, %k, %m, %M, %n, %s, %t, %u and %U have
1463 -+values which are under the control of files' owners but which cannot
1464 -+be used to send arbitrary data to the terminal, and so these are
1465 -+printed as-is. The directives %f, %h, %l, %p and %P are quoted. This
1466 -+quoting is performed in the same way as for GNU
1467 -+.BR ls .
1468 -+This is not the same quoting mechanism as the one used for
1469 -+.B \-ls
1470 -+and
1471 -+.BR \-fls .
1472 -+If you are able to decide what format to use for the output of
1473 -+.B find
1474 -+then it is normally better to use `\e0' as a terminator
1475 -+than to use newline, as file names can contain white space and newline
1476 -+characters.
1477 -+
1478 -+.IP "\-print, \-fprint"
1479 -+Quoting is handled in the same way as for
1480 -+.B \-printf
1481 -+and
1482 -+.BR \-fprintf .
1483 -+If you are using
1484 -+.B find
1485 -+in a script or in a situation where the matched files might have
1486 -+arbitrary names, you should consider using
1487 -+.B \-print0
1488 -+instead of
1489 -+.BR \-print .
1490 -+.P
1491 -+The
1492 -+.B \-ok
1493 -+and
1494 -+.B \-okdir
1495 -+actions print the current filename as-is. This may change in a future release.
1496 -+.SS OPERATORS
1497 -+.P
1498 -+Listed in order of decreasing precedence:
1499 -+
1500 -+.IP "( \fIexpr\fR )"
1501 -+Force precedence. Since parentheses are special to the shell, you
1502 -+will normally need to quote them. Many of the examples in this manual
1503 -+page use backslashes for this purpose: `\e(...\e)' instead of `(...)'.
1504 -+
1505 -+.IP "! \fIexpr\fR"
1506 -+True if \fIexpr\fR is false. This character will also usually need
1507 -+protection from interpretation by the shell.
1508 -+
1509 -+.IP "\-not \fIexpr\fR"
1510 -+Same as ! \fIexpr\fR, but not POSIX compliant.
1511 -+
1512 -+.IP "\fIexpr1 expr2\fR"
1513 -+Two expressions in a row are taken to be joined with an
1514 -+implied "and"; \fIexpr2\fR is not evaluated if \fIexpr1\fR is false.
1515 -+
1516 -+.IP "\fIexpr1\fR \-a \fIexpr2\fR"
1517 -+Same as \fIexpr1 expr2\fR.
1518 -+
1519 -+.IP "\fIexpr1\fR \-and \fIexpr2\fR"
1520 -+Same as \fIexpr1 expr2\fR, but not POSIX compliant.
1521 -+
1522 -+.IP "\fIexpr1\fR \-o \fIexpr2\fR"
1523 -+Or; \fIexpr2\fR is not evaluated if \fIexpr1\fR is true.
1524 -+
1525 -+.IP "\fIexpr1\fR \-or \fIexpr2\fR"
1526 -+Same as \fIexpr1\fR
1527 -+.B \-o
1528 -+\fIexpr2\fR, but not POSIX compliant.
1529 -+
1530 -+.IP "\fIexpr1\fR , \fIexpr2\fR"
1531 -+List; both \fIexpr1\fR and \fIexpr2\fR are always evaluated. The
1532 -+value of \fIexpr1\fR is discarded; the value of the list is the value
1533 -+of \fIexpr2\fR. The comma operator can be useful for searching for
1534 -+several different types of thing, but traversing the filesystem
1535 -+hierarchy only once. The
1536 -+.B \-fprintf
1537 -+action can be used to list the various matched items into several
1538 -+different output files.
1539 -+
1540 -+
1541 -+.SH "STANDARDS CONFORMANCE"
1542 -+For closest compliance to the POSIX standard, you should set the
1543 -+POSIXLY_CORRECT environment variable. The following options are
1544 -+specified in the POSIX standard (IEEE Std 1003.1, 2003 Edition):
1545 -+
1546 -+.IP \fB\-H\fR
1547 -+This option is supported.
1548 -+
1549 -+.IP \fB\-L\fR
1550 -+This option is supported.
1551 -+
1552 -+.IP \fB\-name\fR
1553 -+This option is supported, but POSIX conformance depends on the
1554 -+POSIX conformance of the system's
1555 -+.BR fnmatch (3)
1556 -+library function. As of findutils-4.2.2, shell metacharacters
1557 -+(`*', `?' or `[]' for example) will match a leading `.', because
1558 -+IEEE PASC interpretation 126 requires this. This is a change from
1559 -+previous versions of findutils.
1560 -+
1561 -+.IP \fB\-type\fR
1562 -+Supported. POSIX specifies `b', `c', `d', `l', `p', `f' and `s'.
1563 -+GNU find also supports `D', representing a Door, where the OS provides these.
1564 -+
1565 -+.IP \fB\-ok\fR
1566 -+Supported. Interpretation of the response is not locale-dependent
1567 -+(see ENVIRONMENT VARIABLES).
1568 -+
1569 -+.IP \fB\-newer\fR
1570 -+Supported. If the file specified is a symbolic link, it is always
1571 -+dereferenced. This is a change from previous behaviour, which used to
1572 -+take the relevant time from the symbolic link; see the HISTORY section
1573 -+below.
1574 -+
1575 -+.IP \fB\-perm\fR
1576 -+Supported. If the POSIXLY_CORRECT environment variable is not set,
1577 -+some mode arguments (for example +a+x) which are not valid in POSIX
1578 -+are supported for backward-compatibility.
1579 -+
1580 -+.IP "Other predicates"
1581 -+The predicates
1582 -+.BR \-atime ,
1583 -+.BR \-ctime ,
1584 -+.BR \-depth ,
1585 -+.BR \-group ,
1586 -+.BR \-links ,
1587 -+.BR \-mtime ,
1588 -+.BR \-nogroup ,
1589 -+.BR \-nouser ,
1590 -+.BR \-print ,
1591 -+.BR \-prune ,
1592 -+.BR \-size ,
1593 -+.BR \-user
1594 -+and
1595 -+.B \-xdev
1596 -+are all supported.
1597 -+
1598 -+.P
1599 -+The POSIX standard specifies parentheses `(', `)', negation `!' and the
1600 -+`and' and `or' operators (
1601 -+.BR \-a ,
1602 -+.BR \-o ).
1603 -+.P
1604 -+All other options, predicates, expressions and so forth are extensions
1605 -+beyond the POSIX standard. Many of these extensions are not unique to
1606 -+GNU find, however.
1607 -+.P
1608 -+The POSIX standard requires that
1609 -+.B find
1610 -+detects loops:
1611 -+.IP
1612 -+The
1613 -+.B find
1614 -+utility shall detect infinite loops; that is, entering a
1615 -+previously visited directory that is an ancestor of the last file
1616 -+encountered. When it detects an infinite loop, find shall write a
1617 -+diagnostic message to standard error and shall either recover its
1618 -+position in the hierarchy or terminate.
1619 -+.P
1620 -+GNU
1621 -+.B find
1622 -+complies with these requirements. The link count of
1623 -+directories which contain entries which are hard links to an ancestor
1624 -+will often be lower than they otherwise should be. This can mean that
1625 -+GNU find will sometimes optimise away the visiting of a subdirectory
1626 -+which is actually a link to an ancestor. Since
1627 -+.B find
1628 -+does not actually enter such a subdirectory, it is allowed to avoid
1629 -+emitting a diagnostic message. Although this behaviour may be
1630 -+somewhat confusing, it is unlikely that anybody actually depends on
1631 -+this behaviour. If the leaf optimisation has been turned off with
1632 -+.BR \-noleaf ,
1633 -+the directory entry will always be examined and the diagnostic message
1634 -+will be issued where it is appropriate. Symbolic links cannot be used
1635 -+to create filesystem cycles as such, but if the
1636 -+.B \-L
1637 -+option or the
1638 -+.B \-follow
1639 -+option is in use, a diagnostic message is issued when
1640 -+.B find
1641 -+encounters a loop of symbolic links. As with loops containing hard
1642 -+links, the leaf optimisation will often mean that
1643 -+.B find
1644 -+knows that it doesn't need to call
1645 -+.I stat()
1646 -+or
1647 -+.I chdir()
1648 -+on the symbolic link, so this diagnostic is frequently not necessary.
1649 -+.P
1650 -+The
1651 -+.B \-d
1652 -+option is supported for compatibility with various BSD systems,
1653 -+but you should use the POSIX-compliant option
1654 -+.B \-depth
1655 -+instead.
1656 -+.P
1657 -+The POSIXLY_CORRECT environment variable does not affect the behaviour
1658 -+of the
1659 -+.B \-regex
1660 -+or
1661 -+.B \-iregex
1662 -+tests because those tests aren't specified in the POSIX standard.
1663 -+.SH "ENVIRONMENT VARIABLES"
1664 -+
1665 -+.IP LANG
1666 -+Provides a default value for the internationalization variables that
1667 -+are unset or null.
1668 -+
1669 -+.IP LC_ALL
1670 -+If set to a non-empty string value, override the values of all the
1671 -+other internationalization variables.
1672 -+
1673 -+.IP LC_COLLATE
1674 -+The POSIX standard specifies that this variable affects the pattern
1675 -+matching to be used for the
1676 -+.B \-name
1677 -+option. GNU find uses the
1678 -+.BR fnmatch (3)
1679 -+library function, and so support for `LC_COLLATE' depends on the
1680 -+system library.
1681 -+
1682 -+.IP
1683 -+POSIX also specifies that the `LC_COLLATE' environment
1684 -+variable affects the interpretation of the user's response to the
1685 -+query issued by
1686 -+.BR \-ok' ,
1687 -+but this is not the case for GNU find.
1688 -+
1689 -+.IP LC_CTYPE
1690 -+This variable affects the treatment of character classes used with
1691 -+the
1692 -+.B \-name
1693 -+test, if the system's
1694 -+.BR fnmatch (3)
1695 -+library function supports this. It has no effect on the behaviour
1696 -+of the
1697 -+.B \-ok
1698 -+expression.
1699 -+
1700 -+.IP LC_MESSAGES
1701 -+Determines the locale to be used for internationalised messages.
1702 -+
1703 -+.IP NLSPATH
1704 -+Determines the location of the internationalisation message catalogues.
1705 -+
1706 -+.IP PATH
1707 -+Affects the directories which are searched to find the executables
1708 -+invoked by
1709 -+.BR \-exec ,
1710 -+.BR \-execdir ,
1711 -+.B \-ok
1712 -+and
1713 -+.BR \-okdir .
1714 -+
1715 -+.IP POSIXLY_CORRECT
1716 -+Determines the block size used by
1717 -+.B \-ls
1718 -+and
1719 -+.BR \-fls .
1720 -+If
1721 -+.B POSIXLY_CORRECT
1722 -+is set, blocks are units of 512 bytes. Otherwise
1723 -+they are units of 1024 bytes.
1724 -+.IP
1725 -+Setting this variable also turns off
1726 -+warning messages (that is, implies
1727 -+.BR \-nowarn )
1728 -+by default, because POSIX requires that apart from
1729 -+the output for
1730 -+.BR \-ok ,
1731 -+all messages printed on stderr are diagnositcs and must result in a
1732 -+non-zero exit status.
1733 -+.IP
1734 -+When POSIXLY_CORRECT is not set,
1735 -+.B \-perm
1736 -++zzz
1737 -+is treated just like
1738 -+.B \-perm
1739 -+/zzz
1740 -+if
1741 -++zzz is not a valid symbolic mode. When POSIXLY_CORRECT is set, such
1742 -+constructs are treated as an error.
1743 -+
1744 -+.IP TZ
1745 -+Affects the time zone used for some of the time-related format
1746 -+directives of
1747 -+.B \-printf
1748 -+and
1749 -+.BR \-fprintf .
1750 -+.SH "EXAMPLES"
1751 -+.nf
1752 -+.B find /tmp \-name core \-type f \-print | xargs /bin/rm \-f
1753 -+
1754 -+.fi
1755 -+Find files named
1756 -+.B core
1757 -+in or below the directory
1758 -+.B /tmp
1759 -+and delete them. Note that this will work incorrectly if there are
1760 -+any filenames containing newlines, single or double quotes, or spaces.
1761 -+.P
1762 -+.B find /tmp \-name core \-type f \-print0 | xargs \-0 /bin/rm \-f
1763 -+
1764 -+.fi
1765 -+Find files named
1766 -+.B core
1767 -+in or below the directory
1768 -+.B /tmp
1769 -+and delete them, processing filenames in such a way that file or
1770 -+directory names containing single or double quotes, spaces or newlines
1771 -+are correctly handled. The
1772 -+.B \-name
1773 -+test comes before the
1774 -+.B \-type
1775 -+test in order to avoid having to call
1776 -+.B stat(2)
1777 -+on every file.
1778 -+
1779 -+.P
1780 -+.nf
1781 -+.B find . \-type f \-exec file \(aq{}\(aq \e\;
1782 -+
1783 -+.fi
1784 -+Runs `file' on every file in or below the current directory. Notice
1785 -+that the braces are enclosed in single quote marks to protect them
1786 -+from interpretation as shell script punctuation. The semicolon is
1787 -+similarly protected by the use of a backslash, though single quotes
1788 -+could have been used in that case also.
1789 -+
1790 -+.P
1791 -+.nf
1792 -+.B find / \e
1793 -+.B \e( \-perm \-4000 \-fprintf /root/suid.txt "%#m %u %p\en" \e) , \e
1794 -+.B \e( \-size +100M \-fprintf /root/big.txt "%\-10s %p\en" \e)
1795 -+
1796 -+.fi
1797 -+Traverse the filesystem just once, listing setuid files and
1798 -+directories into
1799 -+.B /root/suid.txt
1800 -+and large files into
1801 -+.BR /root/big.txt .
1802 -+
1803 -+.P
1804 -+.nf
1805 -+.B find $HOME \-mtime 0
1806 -+
1807 -+.fi
1808 -+Search for files in your home directory which have been modified in
1809 -+the last twenty-four hours. This command works this way because the
1810 -+time since each file was last modified is divided by 24 hours and any
1811 -+remainder is discarded. That means that to match
1812 -+.B \-mtime
1813 -+.BR 0 ,
1814 -+a file will have to have a modification in the past which is less than
1815 -+24 hours ago.
1816 -+
1817 -+.P
1818 -+.nf
1819 -+.B find /sbin /usr/sbin -executable \e! -readable \-print
1820 -+
1821 -+.fi
1822 -+Search for files which are executable but not readable.
1823 -+
1824 -+.P
1825 -+.nf
1826 -+.B find . \-perm 664
1827 -+
1828 -+.fi
1829 -+Search for files which have read and write permission for their owner,
1830 -+and group, but which other users can read but not write to. Files
1831 -+which meet these criteria but have other permissions bits set (for
1832 -+example if someone can execute the file) will not be matched.
1833 -+
1834 -+.P
1835 -+.nf
1836 -+.B find . \-perm \-664
1837 -+
1838 -+.fi
1839 -+Search for files which have read and write permission for their owner
1840 -+and group, and which other users can read, without regard to the
1841 -+presence of any extra permission bits (for example the executable
1842 -+bit). This will match a file which has mode 0777, for example.
1843 -+
1844 -+.P
1845 -+.nf
1846 -+.B find . \-perm /222
1847 -+
1848 -+.fi
1849 -+Search for files which are writable by somebody (their owner, or
1850 -+their group, or anybody else).
1851 -+
1852 -+.P
1853 -+.nf
1854 -+.B find . \-perm /220
1855 -+.B find . \-perm /u+w,g+w
1856 -+.B find . \-perm /u=w,g=w
1857 -+
1858 -+.fi
1859 -+All three of these commands do the same thing, but the first one uses
1860 -+the octal representation of the file mode, and the other two use the
1861 -+symbolic form. These commands all search for files which are
1862 -+writable by either their owner or their group. The files don't have
1863 -+to be writable by both the owner and group to be matched; either will
1864 -+do.
1865 -+
1866 -+.P
1867 -+.nf
1868 -+.B find . \-perm \-220
1869 -+.B find . \-perm \-g+w,u+w
1870 -+
1871 -+.fi
1872 -+Both these commands do the same thing; search for files which are
1873 -+writable by both their owner and their group.
1874 -+
1875 -+.P
1876 -+.nf
1877 -+.B find . \-perm \-444 \-perm /222 ! \-perm /111
1878 -+.B find . \-perm \-a+r \-perm /a+w ! \-perm /a+x
1879 -+
1880 -+.fi
1881 -+These two commands both search for files that are readable for
1882 -+everybody (
1883 -+.B \-perm \-444
1884 -+or
1885 -+.BR "\-perm \-a+r" ),
1886 -+have at least one write bit
1887 -+set (
1888 -+.B \-perm /222
1889 -+or
1890 -+.BR "\-perm /a+w" )
1891 -+but are not executable for anybody (
1892 -+.B ! \-perm /111
1893 -+and
1894 -+.B ! \-perm /a+x
1895 -+respectively).
1896 -+
1897 -+.P
1898 -+.nf
1899 -+.B cd /source-dir
1900 -+.B find . \-name .snapshot \-prune \-o \e( \e! \-name "*~" \-print0 \e)|
1901 -+.B cpio \-pmd0 /dest-dir
1902 -+
1903 -+.fi
1904 -+This command copies the contents of
1905 -+.B /source-dir
1906 -+to
1907 -+.BR /dest-dir ,
1908 -+but omits files and directories named
1909 -+.B .snapshot
1910 -+(and anything in them). It also omits files or directories whose name
1911 -+ends in
1912 -+.BR ~ ,
1913 -+but not their contents. The construct
1914 -+.B \-prune \-o \e( ... \-print0 \e)
1915 -+is quite common. The idea here is that the expression before
1916 -+.B \-prune
1917 -+matches things which are to be pruned. However, the
1918 -+.B \-prune
1919 -+action itself returns true, so the following
1920 -+.B \-o
1921 -+ensures that the right hand side is evaluated only for those
1922 -+directories which didn't get pruned (the contents of the pruned
1923 -+directories are not even visited, so their contents are irrelevant).
1924 -+The expression on the right hand side of the
1925 -+.B \-o
1926 -+is in parentheses only for clarity. It emphasises that the
1927 -+.B \-print0
1928 -+action takes place only for things that didn't have
1929 -+.B \-prune
1930 -+applied to them. Because the default `and' condition between tests
1931 -+binds more tightly than
1932 -+.BR \-o ,
1933 -+this is the default anyway, but the parentheses help to show
1934 -+what is going on.
1935 -+
1936 -+.SH EXIT STATUS
1937 -+.PP
1938 -+.B find
1939 -+exits with status 0 if all files are processed successfully, greater
1940 -+than 0 if errors occur. This is deliberately a very broad
1941 -+description, but if the return value is non-zero, you should not rely
1942 -+on the correctness of the results of
1943 -+.BR find .
1944 -+
1945 -+.SH "SEE ALSO"
1946 -+\fBlocate\fP(1), \fBlocatedb\fP(5), \fBupdatedb\fP(1), \fBxargs\fP(1),
1947 -+\fBchmod\fP(1), \fBfnmatch\fP(3), \fBregex\fP(7), \fBstat\fP(2),
1948 -+\fBlstat\fP(2), \fBls\fP(1), \fBprintf\fP(3), \fBstrftime\fP(3),
1949 -+\fBctime\fP(3), \fBFinding Files\fP (on-line in Info, or printed).
1950 -+.SH "HISTORY"
1951 -+As of findutils-4.2.2, shell metacharacters (`*', `?' or `[]' for
1952 -+example) used in filename patterns will match a leading `.', because
1953 -+IEEE POSIX interpretation 126 requires this.
1954 -+.P
1955 -+The syntax
1956 -+\.B \-perm +MODE
1957 -+was deprecated in findutils-4.2.21, in favour of
1958 -+\.B \-perm
1959 -+.BR /MODE .
1960 -+As of findutils-4.3.3,
1961 -+.B \-perm /000
1962 -+now matches all files instead of none.
1963 -+.P
1964 -+Nanosecond-resolution
1965 -+timestamps were implemented in findutils-4.3.3.
1966 -+.P
1967 -+As of findutils-4.3.11, the
1968 -+.B \-delete
1969 -+action sets
1970 -+.BR find 's
1971 -+exit status to a nonzero value when it fails.
1972 -+However,
1973 -+.B find
1974 -+will not exit immediately. Previously,
1975 -+.BR find 's
1976 -+exit status was unaffected by the failure of
1977 -+.BR \-delete .
1978 -+.TS
1979 -+l l l .
1980 -+Feature Added in Also occurs in
1981 -+\-newerXY 4.3.3 BSD
1982 -+\-D 4.3.1
1983 -+\-O 4.3.1
1984 -+\-readable 4.3.0
1985 -+\-writable 4.3.0
1986 -+\-executable 4.3.0
1987 -+\-regextype 4.2.24
1988 -+\-exec ... + 4.2.12 POSIX
1989 -+\-execdir 4.2.12 BSD
1990 -+\-okdir 4.2.12
1991 -+\-samefile 4.2.11
1992 -+\-H 4.2.5 POSIX
1993 -+\-L 4.2.5 POSIX
1994 -+\-P 4.2.5 BSD
1995 -+\-delete 4.2.3
1996 -+\-quit 4.2.3
1997 -+\-d 4.2.3 BSD
1998 -+\-wholename 4.2.0
1999 -+\-iwholename 4.2.0
2000 -+\-ignore_readdir_race 4.2.0
2001 -+\-fls 4.0
2002 -+\-ilname 3.8
2003 -+\-iname 3.8
2004 -+\-ipath 3.8
2005 -+\-iregex 3.8
2006 -+.TE
2007 -+.SH "NON-BUGS"
2008 -+.nf
2009 -+.B $ find . \-name *.c \-print
2010 -+find: paths must precede expression
2011 -+Usage: find [\-H] [\-L] [\-P] [\-Olevel] [\-D help|tree|search|stat|rates|opt|exec] [path...] [expression]
2012 -+.fi
2013 -+.P
2014 -+This happens because
2015 -+.I *.c
2016 -+has been expanded by the shell
2017 -+resulting in
2018 -+.B find
2019 -+actually receiving a command line like this:
2020 -+.nf
2021 -+
2022 -+.B find . \-name bigram.c code.c frcode.c locate.c \-print
2023 -+
2024 -+.fi
2025 -+That command is of course not going to work. Instead of doing things
2026 -+this way, you should enclose the pattern in quotes or escape the wildcard:
2027 -+.nf
2028 -+.B $ find . \-name \e*.c \-print
2029 -+.fi
2030 -+
2031 -+.SH "BUGS"
2032 -+.P
2033 -+There are security problems inherent in the behaviour that the POSIX
2034 -+standard specifies for
2035 -+.BR find ,
2036 -+which therefore cannot be fixed. For example, the
2037 -+.B \-exec
2038 -+action is
2039 -+inherently insecure, and
2040 -+.B \-execdir
2041 -+should be used instead.
2042 -+Please see \fBFinding Files\fP for more information.
2043 -+.P
2044 -+The environment variable
2045 -+.B LC_COLLATE
2046 -+has no effect on the
2047 -+.B \-ok
2048 -+action.
2049 -+.P
2050 -+The best way to report a bug is to use the form at
2051 -+http://savannah.gnu.org/bugs/?group=findutils.
2052 -+The reason for this is that you will then be able to track progress in
2053 -+fixing the problem. Other comments about \fBfind\fP(1) and about
2054 -+the findutils package in general can be sent to the
2055 -+.I bug\-findutils
2056 -+mailing list. To join the list, send email to
2057 -+.IR bug\-findutils\-request@×××.org .
2058 diff -purN findutils-4.3.12.orig/find/find.c findutils-4.3.12/find/find.c
2059 --- findutils-4.3.12.orig/find/find.c 2007-12-19 16:12:34.000000000 -0500
2060 +++ findutils-4.3.12/find/find.c 2008-01-30 08:46:05.754843619 -0500
2061 @@ -2154,7760 +123,304 @@
2062 boolean subdirs_unreliable; /* if true, cannot use dir link count as subdir limif (if false, it may STILL be unreliable) */
2063 unsigned int idx; /* Which entry are we on? */
2064 struct stat stat_buf;
2065 -diff -purN findutils-4.3.12.orig/find/find.c.orig findutils-4.3.12/find/find.c.orig
2066 ---- findutils-4.3.12.orig/find/find.c.orig 1969-12-31 19:00:00.000000000 -0500
2067 -+++ findutils-4.3.12/find/find.c.orig 2007-12-19 16:12:34.000000000 -0500
2068 -@@ -0,0 +1,1537 @@
2069 -+/* find -- search for files in a directory hierarchy
2070 -+ Copyright (C) 1990, 91, 92, 93, 94, 2000,
2071 -+ 2003, 2004, 2005, 2007 Free Software Foundation, Inc.
2072 -+
2073 -+ This program is free software: you can redistribute it and/or modify
2074 -+ it under the terms of the GNU General Public License as published by
2075 -+ the Free Software Foundation, either version 3 of the License, or
2076 -+ (at your option) any later version.
2077 -+
2078 -+ This program is distributed in the hope that it will be useful,
2079 -+ but WITHOUT ANY WARRANTY; without even the implied warranty of
2080 -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2081 -+ GNU General Public License for more details.
2082 -+
2083 -+ You should have received a copy of the GNU General Public License
2084 -+ along with this program. If not, see <http://www.gnu.org/licenses/>.
2085 -+*/
2086 -+/* GNU find was written by Eric Decker <cire@×××××.com>,
2087 -+ with enhancements by David MacKenzie <djm@×××.org>,
2088 -+ Jay Plett <jay@××××××××××××××××××××.us>,
2089 -+ and Tim Wood <axolotl!tim@××××.com>.
2090 -+ The idea for -print0 and xargs -0 came from
2091 -+ Dan Bernstein <brnstnd@×××××××××××××××.edu>.
2092 -+ Improvements have been made by James Youngman <jay@×××.org>.
2093 -+*/
2094 -+
2095 -+
2096 -+#include <config.h>
2097 -+#include "defs.h"
2098 -+
2099 -+#define USE_SAFE_CHDIR 1
2100 -+#undef STAT_MOUNTPOINTS
2101 -+
2102 -+
2103 -+#include <errno.h>
2104 -+#include <assert.h>
2105 -+
2106 -+#include <sys/stat.h>
2107 -+#include <fcntl.h>
2108 -+#include <openat.h>
2109 -+
2110 -+#include "xalloc.h"
2111 -+#include "human.h"
2112 -+#include "canonicalize.h"
2113 -+#include <modetype.h>
2114 -+
2115 -+#include "closein.h"
2116 -+#include "savedirinfo.h"
2117 -+#include "buildcmd.h"
2118 -+#include "dirname.h"
2119 -+#include "quote.h"
2120 -+#include "quotearg.h"
2121 -+#include "xgetcwd.h"
2122 -+#include "error.h"
2123 -+
2124 -+#ifdef HAVE_LOCALE_H
2125 -+#include <locale.h>
2126 -+#endif
2127 -+
2128 -+#if ENABLE_NLS
2129 -+# include <libintl.h>
2130 -+# define _(Text) gettext (Text)
2131 -+#else
2132 -+# define _(Text) Text
2133 -+#define textdomain(Domain)
2134 -+#define bindtextdomain(Package, Directory)
2135 -+#define ngettext(singular,plural,n) ((1==n) ? singular : plural)
2136 -+#endif
2137 -+#ifdef gettext_noop
2138 -+# define N_(String) gettext_noop (String)
2139 -+#else
2140 -+/* See locate.c for explanation as to why not use (String) */
2141 -+# define N_(String) String
2142 -+#endif
2143 -+
2144 -+#ifdef STAT_MOUNTPOINTS
2145 -+static void init_mounted_dev_list(int mandatory);
2146 -+#endif
2147 -+
2148 -+static void process_top_path PARAMS((char *pathname, mode_t mode));
2149 -+static int process_path PARAMS((char *pathname, char *name, boolean leaf, char *parent, mode_t type));
2150 -+static void process_dir PARAMS((char *pathname, char *name, int pathlen, const struct stat *statp, char *parent));
2151 -+
2152 -+
2153 -+
2154 -+/* Name this program was run with. */
2155 -+char *program_name;
2156 -+
2157 -+/* A file descriptor open to the initial working directory.
2158 -+ Doing it this way allows us to work when the i.w.d. has
2159 -+ unreadable parents. */
2160 -+int starting_desc;
2161 -+
2162 -+/* The stat buffer of the initial working directory. */
2163 -+static struct stat starting_stat_buf;
2164 -+
2165 -+enum ChdirSymlinkHandling
2166 -+ {
2167 -+ SymlinkHandleDefault, /* Normally the right choice */
2168 -+ SymlinkFollowOk /* see comment in process_top_path() */
2169 -+ };
2170 -+
2171 -+
2172 -+enum TraversalDirection
2173 -+ {
2174 -+ TraversingUp,
2175 -+ TraversingDown
2176 -+ };
2177 -+
2178 -+enum WdSanityCheckFatality
2179 -+ {
2180 -+ FATAL_IF_SANITY_CHECK_FAILS,
2181 -+ RETRY_IF_SANITY_CHECK_FAILS,
2182 -+ NON_FATAL_IF_SANITY_CHECK_FAILS
2183 -+ };
2184 -+
2185 -+
2186 -+int get_current_dirfd(void)
2187 -+{
2188 -+ return AT_FDCWD;
2189 -+}
2190 +diff -purN findutils-4.3.12.orig/find/parser.c findutils-4.3.12/find/parser.c
2191 +--- findutils-4.3.12.orig/find/parser.c 2007-12-19 16:12:34.000000000 -0500
2192 ++++ findutils-4.3.12/find/parser.c 2008-01-30 08:46:05.754843619 -0500
2193 +@@ -53,6 +53,13 @@
2194 + #include <unistd.h>
2195 + #include <sys/stat.h>
2196 +
2197 ++#ifdef WITH_SELINUX
2198 ++#include <selinux/selinux.h>
2199 ++int optionh_getfilecon(const char *name, security_context_t *p);
2200 ++int optionl_getfilecon(const char *name, security_context_t *p);
2201 ++int optionp_getfilecon(const char *name, security_context_t *p);
2202 ++#endif /*WITH_SELINUX*/
2203 +
2204 + #if ENABLE_NLS
2205 + # include <libintl.h>
2206 + # define _(Text) gettext (Text)
2207 +@@ -156,6 +163,9 @@ static boolean parse_noignore_race PARAM
2208 + static boolean parse_warn PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
2209 + static boolean parse_xtype PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
2210 + static boolean parse_quit PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
2211 ++#ifdef WITH_SELINUX
2212 ++static boolean parse_scontext PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
2213 ++#endif /*WITH_SELINUX*/
2214 +
2215 + boolean parse_print PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
2216 +
2217 +@@ -341,6 +351,8 @@ static struct parser_table const parse_t
2218 + {ARG_TEST, "-help", parse_help, NULL}, /* GNU */
2219 + {ARG_TEST, "version", parse_version, NULL}, /* GNU */
2220 + {ARG_TEST, "-version", parse_version, NULL}, /* GNU */
2221 ++ {ARG_TEST, "context", parse_scontext, pred_scontext}, /* SELinux */
2222 ++ {ARG_TEST, "-context", parse_scontext, pred_scontext}, /* SELinux */
2223 + {0, 0, 0, 0}
2224 + };
2225 +
2226 +@@ -452,10 +464,16 @@ set_follow_state(enum SymlinkOption opt)
2227 + case SYMLINK_ALWAYS_DEREF: /* -L */
2228 + options.xstat = optionl_stat;
2229 + options.no_leaf_check = true;
2230 ++#ifdef WITH_SELINUX
2231 ++ options.x_getfilecon = optionl_getfilecon;
2232 ++#endif /* WITH_SELINUX */
2233 + break;
2234 +
2235 + case SYMLINK_NEVER_DEREF: /* -P (default) */
2236 + options.xstat = optionp_stat;
2237 ++#ifdef WITH_SELINUX
2238 ++ options.x_getfilecon = optionp_getfilecon;
2239 ++#endif /* WITH_SELINUX */
2240 + /* Can't turn no_leaf_check off because the user might have specified
2241 + * -noleaf anyway
2242 + */
2243 +@@ -464,6 +482,9 @@ set_follow_state(enum SymlinkOption opt)
2244 + case SYMLINK_DEREF_ARGSONLY: /* -H */
2245 + options.xstat = optionh_stat;
2246 + options.no_leaf_check = true;
2247 ++#ifdef WITH_SELINUX
2248 ++ options.x_getfilecon = optionh_getfilecon;
2249 ++#endif /* WITH_SELINUX */
2250 + }
2251 + }
2252 + options.symlink_handling = opt;
2253 +@@ -667,6 +688,94 @@ collect_arg_stat_info(char **argv, int *
2254 +
2255 + The predicate structure is updated with the new information. */
2256 +
2257 ++#ifdef WITH_SELINUX
2258 +
2259 -+int
2260 -+main (int argc, char **argv)
2261 ++static int
2262 ++fallback_getfilecon(const char *name, security_context_t *p, int prev_rv)
2263 +{
2264 -+ int i;
2265 -+ int end_of_leading_options = 0; /* First arg after any -H/-L etc. */
2266 -+ struct predicate *eval_tree;
2267 -+
2268 -+ program_name = argv[0];
2269 -+ state.exit_status = 0;
2270 -+
2271 -+ /* Set the option defaults before we do the locale
2272 -+ * initialisation as check_nofollow() needs to be executed in the
2273 -+ * POSIX locale.
2274 ++ /* Our original getfilecon() call failed. Perhaps we can't follow a
2275 ++ * symbolic link. If that might be the problem, lgetfilecon() the link.
2276 ++ * Otherwise, admit defeat.
2277 + */
2278 -+ set_option_defaults(&options);
2279 -+
2280 -+#ifdef HAVE_SETLOCALE
2281 -+ setlocale (LC_ALL, "");
2282 -+#endif
2283 -+ bindtextdomain (PACKAGE, LOCALEDIR);
2284 -+ textdomain (PACKAGE);
2285 -+ atexit (close_stdin);
2286 -+
2287 -+ /* Check for -P, -H or -L options. */
2288 -+ end_of_leading_options = process_leading_options(argc, argv);
2289 -+
2290 -+ if (options.debug_options & DebugStat)
2291 -+ options.xstat = debug_stat;
2292 -+
2293 -+#ifdef DEBUG
2294 -+ fprintf (stderr, "cur_day_start = %s", ctime (&options.cur_day_start));
2295 -+#endif /* DEBUG */
2296 -+
2297 -+ /* state.cwd_dir_fd has to be initialised before we call build_expression_tree()
2298 -+ * because command-line parsing may lead us to stat some files.
2299 -+ */
2300 -+ state.cwd_dir_fd = AT_FDCWD;
2301 -+
2302 -+ /* We are now processing the part of the "find" command line
2303 -+ * after the -H/-L options (if any).
2304 -+ */
2305 -+ eval_tree = build_expression_tree(argc, argv, end_of_leading_options);
2306 -+
2307 -+
2308 -+ /* safely_chdir() needs to check that it has ended up in the right place.
2309 -+ * To avoid bailing out when something gets automounted, it checks if
2310 -+ * the target directory appears to have had a directory mounted on it as
2311 -+ * we chdir()ed. The problem with this is that in order to notice that
2312 -+ * a file system was mounted, we would need to lstat() all the mount points.
2313 -+ * That strategy loses if our machine is a client of a dead NFS server.
2314 -+ *
2315 -+ * Hence if safely_chdir() and wd_sanity_check() can manage without needing
2316 -+ * to know the mounted device list, we do that.
2317 -+ */
2318 -+ if (!options.open_nofollow_available)
2319 -+ {
2320 -+#ifdef STAT_MOUNTPOINTS
2321 -+ init_mounted_dev_list(0);
2322 -+#endif
2323 -+ }
2324 -+
2325 -+
2326 -+ starting_desc = open (".", O_RDONLY
2327 -+#if defined O_LARGEFILE
2328 -+ |O_LARGEFILE
2329 -+#endif
2330 -+ );
2331 -+ if (0 <= starting_desc && fchdir (starting_desc) != 0)
2332 -+ {
2333 -+ close (starting_desc);
2334 -+ starting_desc = -1;
2335 -+ }
2336 -+
2337 -+ if (starting_desc < 0)
2338 -+ {
2339 -+ starting_dir = xgetcwd ();
2340 -+ if (! starting_dir)
2341 -+ error (1, errno, _("cannot get current directory"));
2342 -+ }
2343 -+ set_stat_placeholders(&starting_stat_buf);
2344 -+ if ((*options.xstat) (".", &starting_stat_buf) != 0)
2345 -+ error (1, errno, _("cannot stat current directory"));
2346 -+
2347 -+ /* If no paths are given, default to ".". */
2348 -+ for (i = end_of_leading_options; i < argc && !looks_like_expression(argv[i], true); i++)
2349 -+ {
2350 -+ process_top_path (argv[i], 0);
2351 -+ }
2352 -+
2353 -+ /* If there were no path arguments, default to ".". */
2354 -+ if (i == end_of_leading_options)
2355 -+ {
2356 -+ /*
2357 -+ * We use a temporary variable here because some actions modify
2358 -+ * the path temporarily. Hence if we use a string constant,
2359 -+ * we get a coredump. The best example of this is if we say
2360 -+ * "find -printf %H" (note, not "find . -printf %H").
2361 -+ */
2362 -+ char defaultpath[2] = ".";
2363 -+ process_top_path (defaultpath, 0);
2364 -+ }
2365 -+
2366 -+ /* If "-exec ... {} +" has been used, there may be some
2367 -+ * partially-full command lines which have been built,
2368 -+ * but which are not yet complete. Execute those now.
2369 -+ */
2370 -+ show_success_rates(eval_tree);
2371 -+ cleanup();
2372 -+ return state.exit_status;
2373 -+}
2374 -+
2375 -+boolean is_fts_enabled(int *ftsoptions)
2376 -+{
2377 -+ /* this version of find (i.e. this main()) does not use fts. */
2378 -+ *ftsoptions = 0;
2379 -+ return false;
2380 -+}
2381 -+
2382 -+
2383 -+static char *
2384 -+specific_dirname(const char *dir)
2385 -+{
2386 -+ char dirbuf[1024];
2387 -+
2388 -+ if (0 == strcmp(".", dir))
2389 -+ {
2390 -+ /* OK, what's '.'? */
2391 -+ if (NULL != getcwd(dirbuf, sizeof(dirbuf)))
2392 -+ {
2393 -+ return strdup(dirbuf);
2394 -+ }
2395 -+ else
2396 -+ {
2397 -+ return strdup(dir);
2398 -+ }
2399 -+ }
2400 -+ else
2401 -+ {
2402 -+ char *result = canonicalize_filename_mode(dir, CAN_EXISTING);
2403 -+ if (NULL == result)
2404 -+ return strdup(dir);
2405 -+ else
2406 -+ return result;
2407 -+ }
2408 -+}
2409 -+
2410 -+
2411 -+
2412 -+/* Return non-zero if FS is the name of a file system that is likely to
2413 -+ * be automounted
2414 -+ */
2415 -+static int
2416 -+fs_likely_to_be_automounted(const char *fs)
2417 -+{
2418 -+ return ( (0==strcmp(fs, "nfs")) || (0==strcmp(fs, "autofs")) || (0==strcmp(fs, "subfs")));
2419 -+}
2420 -+
2421 -+
2422 -+
2423 -+#ifdef STAT_MOUNTPOINTS
2424 -+static dev_t *mounted_devices = NULL;
2425 -+static size_t num_mounted_devices = 0u;
2426 -+
2427 -+
2428 -+static void
2429 -+init_mounted_dev_list(int mandatory)
2430 -+{
2431 -+ assert (NULL == mounted_devices);
2432 -+ assert (0 == num_mounted_devices);
2433 -+ mounted_devices = get_mounted_devices(&num_mounted_devices);
2434 -+ if (mandatory && (NULL == mounted_devices))
2435 -+ {
2436 -+ error(1, 0, "Cannot read list of mounted devices.");
2437 -+ }
2438 -+}
2439 -+
2440 -+static void
2441 -+refresh_mounted_dev_list(void)
2442 -+{
2443 -+ if (mounted_devices)
2444 -+ {
2445 -+ free(mounted_devices);
2446 -+ mounted_devices = 0;
2447 -+ }
2448 -+ num_mounted_devices = 0u;
2449 -+ init_mounted_dev_list(1);
2450 -+}
2451 -+
2452 -+
2453 -+/* Search for device DEV in the array LIST, which is of size N. */
2454 -+static int
2455 -+dev_present(dev_t dev, const dev_t *list, size_t n)
2456 -+{
2457 -+ if (list)
2458 -+ {
2459 -+ while (n-- > 0u)
2460 -+ {
2461 -+ if ( (*list++) == dev )
2462 -+ return 1;
2463 -+ }
2464 -+ }
2465 -+ return 0;
2466 -+}
2467 -+
2468 -+enum MountPointStateChange
2469 -+ {
2470 -+ MountPointRecentlyMounted,
2471 -+ MountPointRecentlyUnmounted,
2472 -+ MountPointStateUnchanged
2473 -+ };
2474 -+
2475 -+
2476 -+
2477 -+static enum MountPointStateChange
2478 -+get_mount_state(dev_t newdev)
2479 -+{
2480 -+ int new_is_present, new_was_present;
2481 -+
2482 -+ new_was_present = dev_present(newdev, mounted_devices, num_mounted_devices);
2483 -+ refresh_mounted_dev_list();
2484 -+ new_is_present = dev_present(newdev, mounted_devices, num_mounted_devices);
2485 -+
2486 -+ if (new_was_present == new_is_present)
2487 -+ return MountPointStateUnchanged;
2488 -+ else if (new_is_present)
2489 -+ return MountPointRecentlyMounted;
2490 -+ else
2491 -+ return MountPointRecentlyUnmounted;
2492 -+}
2493 -+
2494 -+
2495 -+
2496 -+/* We stat()ed a directory, chdir()ed into it (we know this
2497 -+ * since direction is TraversingDown), stat()ed it again,
2498 -+ * and noticed that the device numbers are different. Check
2499 -+ * if the file system was recently mounted.
2500 -+ *
2501 -+ * If it was, it looks like chdir()ing into the directory
2502 -+ * caused a file system to be mounted. Maybe automount is
2503 -+ * running. Anyway, that's probably OK - but it happens
2504 -+ * only when we are moving downward.
2505 -+ *
2506 -+ * We also allow for the possibility that a similar thing
2507 -+ * has happened with the unmounting of a file system. This
2508 -+ * is much rarer, as it relies on an automounter timeout
2509 -+ * occurring at exactly the wrong moment.
2510 -+ */
2511 -+static enum WdSanityCheckFatality
2512 -+dirchange_is_fatal(const char *specific_what,
2513 -+ enum WdSanityCheckFatality isfatal,
2514 -+ int silent,
2515 -+ struct stat *newinfo)
2516 -+{
2517 -+ enum MountPointStateChange transition = get_mount_state(newinfo->st_dev);
2518 -+ switch (transition)
2519 -+ {
2520 -+ case MountPointRecentlyUnmounted:
2521 -+ isfatal = NON_FATAL_IF_SANITY_CHECK_FAILS;
2522 -+ if (!silent)
2523 -+ {
2524 -+ error (0, 0,
2525 -+ _("Warning: file system %s has recently been unmounted."),
2526 -+ safely_quote_err_filename(0, specific_what));
2527 -+ }
2528 -+ break;
2529 -+
2530 -+ case MountPointRecentlyMounted:
2531 -+ isfatal = NON_FATAL_IF_SANITY_CHECK_FAILS;
2532 -+ if (!silent)
2533 -+ {
2534 -+ error (0, 0,
2535 -+ _("Warning: file system %s has recently been mounted."),
2536 -+ safely_quote_err_filename(0, specific_what));
2537 -+ }
2538 -+ break;
2539 -+
2540 -+ case MountPointStateUnchanged:
2541 -+ /* leave isfatal as it is */
2542 -+ break;
2543 -+ }
2544 -+
2545 -+ return isfatal;
2546 -+}
2547 -+
2548 -+
2549 -+#endif
2550 -+
2551 -+
2552 -+
2553 -+/* Examine the results of the stat() of a directory from before we
2554 -+ * entered or left it, with the results of stat()ing it afterward. If
2555 -+ * these are different, the file system tree has been modified while we
2556 -+ * were traversing it. That might be an attempt to use a race
2557 -+ * condition to persuade find to do something it didn't intend
2558 -+ * (e.g. an attempt by an ordinary user to exploit the fact that root
2559 -+ * sometimes runs find on the whole file system). However, this can
2560 -+ * also happen if automount is running (certainly on Solaris). With
2561 -+ * automount, moving into a directory can cause a file system to be
2562 -+ * mounted there.
2563 -+ *
2564 -+ * To cope sensibly with this, we will raise an error if we see the
2565 -+ * device number change unless we are chdir()ing into a subdirectory,
2566 -+ * and the directory we moved into has been mounted or unmounted "recently".
2567 -+ * Here "recently" means since we started "find" or we last re-read
2568 -+ * the /etc/mnttab file.
2569 -+ *
2570 -+ * If the device number does not change but the inode does, that is a
2571 -+ * problem.
2572 -+ *
2573 -+ * If the device number and inode are both the same, we are happy.
2574 -+ *
2575 -+ * If a file system is (un)mounted as we chdir() into the directory, that
2576 -+ * may mean that we're now examining a section of the file system that might
2577 -+ * have been excluded from consideration (via -prune or -quit for example).
2578 -+ * Hence we print a warning message to indicate that the output of find
2579 -+ * might be inconsistent due to the change in the file system.
2580 -+ */
2581 -+static boolean
2582 -+wd_sanity_check(const char *thing_to_stat,
2583 -+ const char *progname,
2584 -+ const char *what,
2585 -+ dev_t old_dev,
2586 -+ ino_t old_ino,
2587 -+ struct stat *newinfo,
2588 -+ int parent,
2589 -+ int line_no,
2590 -+ enum TraversalDirection direction,
2591 -+ enum WdSanityCheckFatality isfatal,
2592 -+ boolean *changed) /* output parameter */
2593 -+{
2594 -+ const char *fstype;
2595 -+ char *specific_what = NULL;
2596 -+ int silent = 0;
2597 -+ const char *current_dir = ".";
2598 -+
2599 -+ *changed = false;
2600 -+
2601 -+ set_stat_placeholders(newinfo);
2602 -+ if ((*options.xstat) (current_dir, newinfo) != 0)
2603 -+ fatal_file_error(thing_to_stat);
2604 -+
2605 -+ if (old_dev != newinfo->st_dev)
2606 -+ {
2607 -+ *changed = true;
2608 -+ specific_what = specific_dirname(what);
2609 -+ fstype = filesystem_type(newinfo, current_dir);
2610 -+ silent = fs_likely_to_be_automounted(fstype);
2611 -+
2612 -+ /* This condition is rare, so once we are here it is
2613 -+ * reasonable to perform an expensive computation to
2614 -+ * determine if we should continue or fail.
2615 -+ */
2616 -+ if (TraversingDown == direction)
2617 -+ {
2618 -+#ifdef STAT_MOUNTPOINTS
2619 -+ isfatal = dirchange_is_fatal(specific_what,isfatal,silent,newinfo);
2620 -+#else
2621 -+ isfatal = RETRY_IF_SANITY_CHECK_FAILS;
2622 -+#endif
2623 -+ }
2624 -+
2625 -+ switch (isfatal)
2626 -+ {
2627 -+ case FATAL_IF_SANITY_CHECK_FAILS:
2628 -+ {
2629 -+ fstype = filesystem_type(newinfo, current_dir);
2630 -+ error (1, 0,
2631 -+ _("%1$s%2$s changed during execution of %3$s "
2632 -+ "(old device number %4$ld, new device number %5$ld, file system type is %6$s) [ref %7$ld]"),
2633 -+ safely_quote_err_filename(0, specific_what),
2634 -+ parent ? "/.." : "",
2635 -+ safely_quote_err_filename(1, progname),
2636 -+ (long) old_dev,
2637 -+ (long) newinfo->st_dev,
2638 -+ fstype,
2639 -+ (long)line_no);
2640 -+ /*NOTREACHED*/
2641 -+ return false;
2642 -+ }
2643 -+
2644 -+ case NON_FATAL_IF_SANITY_CHECK_FAILS:
2645 -+ {
2646 -+ /* Since the device has changed under us, the inode number
2647 -+ * will almost certainly also be different. However, we have
2648 -+ * already decided that this is not a problem. Hence we return
2649 -+ * without checking the inode number.
2650 -+ */
2651 -+ free(specific_what);
2652 -+ return true;
2653 -+ }
2654 -+
2655 -+ case RETRY_IF_SANITY_CHECK_FAILS:
2656 -+ return false;
2657 -+ }
2658 -+ }
2659 -+
2660 -+ /* Device number was the same, check if the inode has changed. */
2661 -+ if (old_ino != newinfo->st_ino)
2662 -+ {
2663 -+ *changed = true;
2664 -+ specific_what = specific_dirname(what);
2665 -+ fstype = filesystem_type(newinfo, current_dir);
2666 -+
2667 -+ error ((isfatal == FATAL_IF_SANITY_CHECK_FAILS) ? 1 : 0,
2668 -+ 0, /* no relevant errno value */
2669 -+ _("%1$s%2$s changed during execution of %3$s "
2670 -+ "(old inode number %4$ld, new inode number %5$ld, file system type is %5$s) [ref %7$ld]"),
2671 -+ safely_quote_err_filename(0, specific_what),
2672 -+ parent ? "/.." : "",
2673 -+ safely_quote_err_filename(1, progname),
2674 -+ (long) old_ino,
2675 -+ (long) newinfo->st_ino,
2676 -+ fstype,
2677 -+ (long)line_no);
2678 -+ free(specific_what);
2679 -+ return false;
2680 -+ }
2681 -+
2682 -+ return true;
2683 -+}
2684 -+
2685 -+enum SafeChdirStatus
2686 -+ {
2687 -+ SafeChdirOK,
2688 -+ SafeChdirFailSymlink,
2689 -+ SafeChdirFailNotDir,
2690 -+ SafeChdirFailStat,
2691 -+ SafeChdirFailWouldBeUnableToReturn,
2692 -+ SafeChdirFailChdirFailed,
2693 -+ SafeChdirFailNonexistent,
2694 -+ SafeChdirFailDestUnreadable
2695 -+ };
2696 -+
2697 -+/* Safely perform a change in directory. We do this by calling
2698 -+ * lstat() on the subdirectory, using chdir() to move into it, and
2699 -+ * then lstat()ing ".". We compare the results of the two stat calls
2700 -+ * to see if they are consistent. If not, we sound the alarm.
2701 -+ *
2702 -+ * If following_links() is true, we do follow symbolic links.
2703 -+ */
2704 -+static enum SafeChdirStatus
2705 -+safely_chdir_lstat(const char *dest,
2706 -+ enum TraversalDirection direction,
2707 -+ struct stat *statbuf_dest,
2708 -+ enum ChdirSymlinkHandling symlink_follow_option,
2709 -+ boolean *did_stat)
2710 -+{
2711 -+ struct stat statbuf_arrived;
2712 -+ int rv, dotfd=-1;
2713 -+ int saved_errno; /* specific_dirname() changes errno. */
2714 -+ boolean rv_set = false;
2715 -+ boolean statflag = false;
2716 -+ int tries = 0;
2717 -+ enum WdSanityCheckFatality isfatal = RETRY_IF_SANITY_CHECK_FAILS;
2718 -+
2719 -+ saved_errno = errno = 0;
2720 -+
2721 -+ dotfd = open(".", O_RDONLY
2722 -+#if defined O_LARGEFILE
2723 -+ |O_LARGEFILE
2724 -+#endif
2725 -+ );
2726 -+
2727 -+ /* We jump back to here if wd_sanity_check()
2728 -+ * recoverably triggers an alert.
2729 -+ */
2730 -+ retry:
2731 -+ ++tries;
2732 -+
2733 -+ if (dotfd >= 0)
2734 -+ {
2735 -+ /* Stat the directory we're going to. */
2736 -+ set_stat_placeholders(statbuf_dest);
2737 -+ if (0 == options.xstat(dest, statbuf_dest))
2738 -+ {
2739 -+ statflag = true;
2740 -+
2741 -+#ifdef S_ISLNK
2742 -+ /* symlink_follow_option might be set to SymlinkFollowOk, which
2743 -+ * would allow us to chdir() into a symbolic link. This is
2744 -+ * only useful for the case where the directory we're
2745 -+ * chdir()ing into is the basename of a command line
2746 -+ * argument, for example where "foo/bar/baz" is specified on
2747 -+ * the command line. When -P is in effect (the default),
2748 -+ * baz will not be followed if it is a symlink, but if bar
2749 -+ * is a symlink, it _should_ be followed. Hence we need the
2750 -+ * ability to override the policy set by following_links().
2751 -+ */
2752 -+ if (!following_links() && S_ISLNK(statbuf_dest->st_mode))
2753 -+ {
2754 -+ /* We're not supposed to be following links, but this is
2755 -+ * a link. Check symlink_follow_option to see if we should
2756 -+ * make a special exception.
2757 -+ */
2758 -+ if (symlink_follow_option == SymlinkFollowOk)
2759 -+ {
2760 -+ /* We need to re-stat() the file so that the
2761 -+ * sanity check can pass.
2762 -+ */
2763 -+ if (0 != stat(dest, statbuf_dest))
2764 -+ {
2765 -+ rv = SafeChdirFailNonexistent;
2766 -+ rv_set = true;
2767 -+ saved_errno = errno;
2768 -+ goto fail;
2769 -+ }
2770 -+ statflag = true;
2771 -+ }
2772 -+ else
2773 -+ {
2774 -+ /* Not following symlinks, so the attempt to
2775 -+ * chdir() into a symlink should be prevented.
2776 -+ */
2777 -+ rv = SafeChdirFailSymlink;
2778 -+ rv_set = true;
2779 -+ saved_errno = 0; /* silence the error message */
2780 -+ goto fail;
2781 -+ }
2782 -+ }
2783 -+#endif
2784 -+#ifdef S_ISDIR
2785 -+ /* Although the immediately following chdir() would detect
2786 -+ * the fact that this is not a directory for us, this would
2787 -+ * result in an extra system call that fails. Anybody
2788 -+ * examining the system-call trace should ideally not be
2789 -+ * concerned that something is actually failing.
2790 -+ */
2791 -+ if (!S_ISDIR(statbuf_dest->st_mode))
2792 -+ {
2793 -+ rv = SafeChdirFailNotDir;
2794 -+ rv_set = true;
2795 -+ saved_errno = 0; /* silence the error message */
2796 -+ goto fail;
2797 -+ }
2798 -+#endif
2799 -+
2800 -+ if (options.debug_options & DebugSearch)
2801 -+ fprintf(stderr, "safely_chdir(): chdir(\"%s\")\n", dest);
2802 -+
2803 -+ if (0 == chdir(dest))
2804 -+ {
2805 -+ /* check we ended up where we wanted to go */
2806 -+ boolean changed = false;
2807 -+ if (!wd_sanity_check(".", program_name, ".",
2808 -+ statbuf_dest->st_dev,
2809 -+ statbuf_dest->st_ino,
2810 -+ &statbuf_arrived,
2811 -+ 0, __LINE__, direction,
2812 -+ isfatal,
2813 -+ &changed))
2814 -+ {
2815 -+ /* Only allow one failure. */
2816 -+ if (RETRY_IF_SANITY_CHECK_FAILS == isfatal)
2817 -+ {
2818 -+ if (0 == fchdir(dotfd))
2819 -+ {
2820 -+ isfatal = FATAL_IF_SANITY_CHECK_FAILS;
2821 -+ goto retry;
2822 -+ }
2823 -+ else
2824 -+ {
2825 -+ /* Failed to return to original directory,
2826 -+ * but we know that the current working
2827 -+ * directory is not the one that we intend
2828 -+ * to be in. Since fchdir() failed, we
2829 -+ * can't recover from this and so this error
2830 -+ * is fatal.
2831 -+ */
2832 -+ error(1, errno,
2833 -+ "failed to return to parent directory");
2834 -+ }
2835 -+ }
2836 -+ else
2837 -+ {
2838 -+ /* XXX: not sure what to use as an excuse here. */
2839 -+ rv = SafeChdirFailNonexistent;
2840 -+ rv_set = true;
2841 -+ saved_errno = 0;
2842 -+ goto fail;
2843 -+ }
2844 -+ }
2845 -+
2846 -+ close(dotfd);
2847 -+ return SafeChdirOK;
2848 -+ }
2849 -+ else
2850 -+ {
2851 -+ saved_errno = errno;
2852 -+ if (ENOENT == saved_errno)
2853 -+ {
2854 -+ rv = SafeChdirFailNonexistent;
2855 -+ rv_set = true;
2856 -+ if (options.ignore_readdir_race)
2857 -+ errno = 0; /* don't issue err msg */
2858 -+ }
2859 -+ else if (ENOTDIR == saved_errno)
2860 -+ {
2861 -+ /* This can happen if the we stat a directory,
2862 -+ * and then file system activity changes it into
2863 -+ * a non-directory.
2864 -+ */
2865 -+ saved_errno = 0; /* don't issue err msg */
2866 -+ rv = SafeChdirFailNotDir;
2867 -+ rv_set = true;
2868 -+ }
2869 -+ else
2870 -+ {
2871 -+ rv = SafeChdirFailChdirFailed;
2872 -+ rv_set = true;
2873 -+ }
2874 -+ goto fail;
2875 -+ }
2876 -+ }
2877 -+ else
2878 -+ {
2879 -+ saved_errno = errno;
2880 -+ rv = SafeChdirFailStat;
2881 -+ rv_set = true;
2882 -+
2883 -+ if ( (ENOENT == saved_errno) || (0 == state.curdepth))
2884 -+ saved_errno = 0; /* don't issue err msg */
2885 -+ goto fail;
2886 -+ }
2887 -+ }
2888 -+ else
2889 -+ {
2890 -+ /* We do not have read permissions on "." */
2891 -+ rv = SafeChdirFailWouldBeUnableToReturn;
2892 -+ rv_set = true;
2893 -+ goto fail;
2894 -+ }
2895 -+
2896 -+ /* This is the success path, so we clear errno. The caller probably
2897 -+ * won't be calling error() anyway.
2898 -+ */
2899 -+ saved_errno = 0;
2900 -+
2901 -+ /* We use the same exit path for success or failure.
2902 -+ * which has occurred is recorded in RV.
2903 -+ */
2904 -+ fail:
2905 -+ /* We do not call error() as this would result in a duplicate error
2906 -+ * message when the caller does the same thing.
2907 -+ */
2908 -+ if (saved_errno)
2909 -+ errno = saved_errno;
2910 -+
2911 -+ if (dotfd >= 0)
2912 -+ {
2913 -+ close(dotfd);
2914 -+ dotfd = -1;
2915 -+ }
2916 -+
2917 -+ *did_stat = statflag;
2918 -+ assert (rv_set);
2919 -+ return rv;
2920 -+}
2921 -+
2922 -+#if defined O_NOFOLLOW
2923 -+/* Safely change working directory to the specified subdirectory. If
2924 -+ * we are not allowed to follow symbolic links, we use open() with
2925 -+ * O_NOFOLLOW, followed by fchdir(). This ensures that we don't
2926 -+ * follow symbolic links (of course, we do follow them if the -L
2927 -+ * option is in effect).
2928 -+ */
2929 -+static enum SafeChdirStatus
2930 -+safely_chdir_nofollow(const char *dest,
2931 -+ enum TraversalDirection direction,
2932 -+ struct stat *statbuf_dest,
2933 -+ enum ChdirSymlinkHandling symlink_follow_option,
2934 -+ boolean *did_stat)
2935 -+{
2936 -+ int extraflags, fd;
2937 -+
2938 -+ (void) direction;
2939 -+ (void) statbuf_dest;
2940 -+
2941 -+ extraflags = 0;
2942 -+ *did_stat = false;
2943 -+
2944 -+ switch (symlink_follow_option)
2945 -+ {
2946 -+ case SymlinkFollowOk:
2947 -+ extraflags = 0;
2948 -+ break;
2949 -+
2950 -+ case SymlinkHandleDefault:
2951 -+ if (following_links())
2952 -+ extraflags = 0;
2953 -+ else
2954 -+ extraflags = O_NOFOLLOW;
2955 -+ break;
2956 -+ }
2957 -+
2958 -+ errno = 0;
2959 -+ fd = open(dest, O_RDONLY
2960 -+#if defined O_LARGEFILE
2961 -+ |O_LARGEFILE
2962 -+#endif
2963 -+ |extraflags);
2964 -+ if (fd < 0)
2965 -+ {
2966 -+ switch (errno)
2967 -+ {
2968 -+ case ELOOP:
2969 -+ return SafeChdirFailSymlink; /* This is why we use O_NOFOLLOW */
2970 -+ case ENOENT:
2971 -+ return SafeChdirFailNonexistent;
2972 -+ default:
2973 -+ return SafeChdirFailDestUnreadable;
2974 -+ }
2975 -+ }
2976 -+
2977 -+ errno = 0;
2978 -+ if (0 == fchdir(fd))
2979 -+ {
2980 -+ close(fd);
2981 -+ return SafeChdirOK;
2982 -+ }
2983 -+ else
2984 -+ {
2985 -+ int saved_errno = errno;
2986 -+ close(fd);
2987 -+ errno = saved_errno;
2988 -+
2989 -+ switch (errno)
2990 -+ {
2991 -+ case ENOTDIR:
2992 -+ return SafeChdirFailNotDir;
2993 -+
2994 -+ case EACCES:
2995 -+ case EBADF: /* Shouldn't happen */
2996 -+ case EINTR:
2997 -+ case EIO:
2998 -+ default:
2999 -+ return SafeChdirFailChdirFailed;
3000 -+ }
3001 -+ }
3002 -+}
3003 -+#endif
3004 -+
3005 -+static enum SafeChdirStatus
3006 -+safely_chdir(const char *dest,
3007 -+ enum TraversalDirection direction,
3008 -+ struct stat *statbuf_dest,
3009 -+ enum ChdirSymlinkHandling symlink_follow_option,
3010 -+ boolean *did_stat)
3011 -+{
3012 -+ enum SafeChdirStatus result;
3013 -+
3014 -+ /* We're about to leave a directory. If there are any -execdir
3015 -+ * argument lists which have been built but have not yet been
3016 -+ * processed, do them now because they must be done in the same
3017 -+ * directory.
3018 -+ */
3019 -+ complete_pending_execdirs(get_current_dirfd());
3020 -+
3021 -+#if !defined(O_NOFOLLOW)
3022 -+ options.open_nofollow_available = false;
3023 -+#endif
3024 -+ if (options.open_nofollow_available)
3025 -+ {
3026 -+ result = safely_chdir_nofollow(dest, direction, statbuf_dest,
3027 -+ symlink_follow_option, did_stat);
3028 -+ if (SafeChdirFailDestUnreadable != result)
3029 -+ {
3030 -+ return result;
3031 -+ }
3032 -+ else
3033 -+ {
3034 -+ /* Savannah bug #15384: fall through to use safely_chdir_lstat
3035 -+ * if the directory is not readable.
3036 -+ */
3037 -+ /* Do nothing. */
3038 -+ }
3039 -+ }
3040 -+ /* Even if O_NOFOLLOW is available, we may need to use the alternative
3041 -+ * method, since parent of the start point may be executable but not
3042 -+ * readable.
3043 -+ */
3044 -+ return safely_chdir_lstat(dest, direction, statbuf_dest,
3045 -+ symlink_follow_option, did_stat);
3046 -+}
3047 -+
3048 -+
3049 -+
3050 -+/* Safely go back to the starting directory. */
3051 -+static void
3052 -+chdir_back (void)
3053 -+{
3054 -+ struct stat stat_buf;
3055 -+ boolean dummy;
3056 -+
3057 -+ if (starting_desc < 0)
3058 -+ {
3059 -+ if (options.debug_options & DebugSearch)
3060 -+ fprintf(stderr, "chdir_back(): chdir(\"%s\")\n", starting_dir);
3061 -+
3062 -+#ifdef STAT_MOUNTPOINTS
3063 -+ /* We will need the mounted device list. Get it now if we don't
3064 -+ * already have it.
3065 -+ */
3066 -+ if (NULL == mounted_devices)
3067 -+ init_mounted_dev_list(1);
3068 -+#endif
3069 -+
3070 -+ if (chdir (starting_dir) != 0)
3071 -+ fatal_file_error(starting_dir);
3072 -+
3073 -+ wd_sanity_check(starting_dir,
3074 -+ program_name,
3075 -+ starting_dir,
3076 -+ starting_stat_buf.st_dev,
3077 -+ starting_stat_buf.st_ino,
3078 -+ &stat_buf, 0, __LINE__,
3079 -+ TraversingUp,
3080 -+ FATAL_IF_SANITY_CHECK_FAILS,
3081 -+ &dummy);
3082 -+ }
3083 -+ else
3084 -+ {
3085 -+ if (options.debug_options & DebugSearch)
3086 -+ fprintf(stderr, "chdir_back(): chdir(<starting-point>)\n");
3087 -+
3088 -+ if (fchdir (starting_desc) != 0)
3089 -+ {
3090 -+ fatal_file_error(starting_dir);
3091 -+ }
3092 -+ }
3093 -+}
3094 -+
3095 -+/* Move to the parent of a given directory and then call a function,
3096 -+ * restoring the cwd. Don't bother changing directory if the
3097 -+ * specified directory is a child of "." or is the root directory.
3098 -+ */
3099 -+static void
3100 -+at_top (char *pathname,
3101 -+ mode_t mode,
3102 -+ struct stat *pstat,
3103 -+ void (*action)(char *pathname,
3104 -+ char *basename,
3105 -+ int mode,
3106 -+ struct stat *pstat))
3107 -+{
3108 -+ int dirchange;
3109 -+ char *parent_dir = dir_name (pathname);
3110 -+ char *base = last_component (pathname);
3111 -+
3112 -+ state.curdepth = 0;
3113 -+ state.starting_path_length = strlen (pathname);
3114 -+
3115 -+ if (0 == *base
3116 -+ || 0 == strcmp(parent_dir, "."))
3117 -+ {
3118 -+ dirchange = 0;
3119 -+ base = pathname;
3120 -+ }
3121 -+ else
3122 -+ {
3123 -+ enum TraversalDirection direction;
3124 -+ enum SafeChdirStatus chdir_status;
3125 -+ struct stat st;
3126 -+ boolean did_stat = false;
3127 -+
3128 -+ dirchange = 1;
3129 -+ if (0 == strcmp(base, ".."))
3130 -+ direction = TraversingUp;
3131 -+ else
3132 -+ direction = TraversingDown;
3133 -+
3134 -+ /* We pass SymlinkFollowOk to safely_chdir(), which allows it to
3135 -+ * chdir() into a symbolic link. This is only useful for the
3136 -+ * case where the directory we're chdir()ing into is the
3137 -+ * basename of a command line argument, for example where
3138 -+ * "foo/bar/baz" is specified on the command line. When -P is
3139 -+ * in effect (the default), baz will not be followed if it is a
3140 -+ * symlink, but if bar is a symlink, it _should_ be followed.
3141 -+ * Hence we need the ability to override the policy set by
3142 -+ * following_links().
3143 -+ */
3144 -+ chdir_status = safely_chdir(parent_dir, direction, &st, SymlinkFollowOk, &did_stat);
3145 -+ if (SafeChdirOK != chdir_status)
3146 -+ {
3147 -+ const char *what = (SafeChdirFailWouldBeUnableToReturn == chdir_status) ? "." : parent_dir;
3148 -+ if (errno)
3149 -+ error (0, errno, "%s",
3150 -+ safely_quote_err_filename(0, what));
3151 -+ else
3152 -+ error (0, 0, _("Failed to safely change directory into %s"),
3153 -+ safely_quote_err_filename(0, parent_dir));
3154 -+
3155 -+ /* We can't process this command-line argument. */
3156 -+ state.exit_status = 1;
3157 -+ return;
3158 -+ }
3159 -+ }
3160 -+
3161 -+ free (parent_dir);
3162 -+ parent_dir = NULL;
3163 -+
3164 -+ action(pathname, base, mode, pstat);
3165 -+
3166 -+ if (dirchange)
3167 -+ {
3168 -+ chdir_back();
3169 -+ }
3170 -+}
3171 -+
3172 -+
3173 -+static void do_process_top_dir(char *pathname,
3174 -+ char *base,
3175 -+ int mode,
3176 -+ struct stat *pstat)
3177 -+{
3178 -+ (void) pstat;
3179 -+
3180 -+ process_path (pathname, base, false, ".", mode);
3181 -+ complete_pending_execdirs(get_current_dirfd());
3182 -+}
3183 -+
3184 -+static void do_process_predicate(char *pathname,
3185 -+ char *base,
3186 -+ int mode,
3187 -+ struct stat *pstat)
3188 -+{
3189 -+ (void) mode;
3190 -+
3191 -+ state.rel_pathname = base; /* cwd_dir_fd was already set by safely_chdir */
3192 -+ apply_predicate (pathname, pstat, get_eval_tree());
3193 -+}
3194 -+
3195 -+
3196 -+
3197 -+
3198 -+/* Descend PATHNAME, which is a command-line argument.
3199 -+
3200 -+ Actions like -execdir assume that we are in the
3201 -+ parent directory of the file we're examining,
3202 -+ and on entry to this function our working directory
3203 -+ is whatever it was when find was invoked. Therefore
3204 -+ If PATHNAME is "." we just leave things as they are.
3205 -+ Otherwise, we figure out what the parent directory is,
3206 -+ and move to that.
3207 -+*/
3208 -+static void
3209 -+process_top_path (char *pathname, mode_t mode)
3210 -+{
3211 -+ at_top(pathname, mode, NULL, do_process_top_dir);
3212 -+}
3213 -+
3214 -+
3215 -+/* Info on each directory in the current tree branch, to avoid
3216 -+ getting stuck in symbolic link loops. */
3217 -+static struct dir_id *dir_ids = NULL;
3218 -+/* Entries allocated in `dir_ids'. */
3219 -+static int dir_alloc = 0;
3220 -+/* Index in `dir_ids' of directory currently being searched.
3221 -+ This is always the last valid entry. */
3222 -+static int dir_curr = -1;
3223 -+/* (Arbitrary) number of entries to grow `dir_ids' by. */
3224 -+#define DIR_ALLOC_STEP 32
3225 -+
3226 -+
3227 -+
3228 -+/* We've detected a file system loop. This is caused by one of
3229 -+ * two things:
3230 -+ *
3231 -+ * 1. Option -L is in effect and we've hit a symbolic link that
3232 -+ * points to an ancestor. This is harmless. We won't traverse the
3233 -+ * symbolic link.
3234 -+ *
3235 -+ * 2. We have hit a real cycle in the directory hierarchy. In this
3236 -+ * case, we issue a diagnostic message (POSIX requires this) and we
3237 -+ * skip that directory entry.
3238 -+ */
3239 -+static void
3240 -+issue_loop_warning(const char *name, const char *pathname, int level)
3241 -+{
3242 -+ struct stat stbuf_link;
3243 -+ if (lstat(name, &stbuf_link) != 0)
3244 -+ stbuf_link.st_mode = S_IFREG;
3245 -+
3246 -+ if (S_ISLNK(stbuf_link.st_mode))
3247 -+ {
3248 -+ error(0, 0,
3249 -+ _("Symbolic link %s is part of a loop in the directory hierarchy; we have already visited the directory to which it points."),
3250 -+ safely_quote_err_filename(0, pathname));
3251 -+ /* XXX: POSIX appears to require that the exit status be non-zero if a
3252 -+ * diagnostic is issued.
3253 -+ */
3254 -+ }
3255 -+ else
3256 -+ {
3257 -+ int distance = 1 + (dir_curr-level);
3258 -+ /* We have found an infinite loop. POSIX requires us to
3259 -+ * issue a diagnostic. Usually we won't get to here
3260 -+ * because when the leaf optimisation is on, it will cause
3261 -+ * the subdirectory to be skipped. If /a/b/c/d is a hard
3262 -+ * link to /a/b, then the link count of /a/b/c is 2,
3263 -+ * because the ".." entry of /b/b/c/d points to /a, not
3264 -+ * to /a/b/c.
3265 -+ */
3266 -+ error(0, 0,
3267 -+ ngettext(
3268 -+ "Filesystem loop detected; %1$s has the same device number and inode as "
3269 -+ "a directory which is %2$d level higher in the file system hierarchy",
3270 -+ "Filesystem loop detected; %1$s has the same device number and inode as "
3271 -+ "a directory which is %2$d levels higher in the file system hierarchy",
3272 -+ (long)distance),
3273 -+ safely_quote_err_filename(0, pathname),
3274 -+ distance);
3275 -+ }
3276 -+}
3277 -+
3278 -+
3279 -+
3280 -+/* Recursively descend path PATHNAME, applying the predicates.
3281 -+ LEAF is true if PATHNAME is known to be in a directory that has no
3282 -+ more unexamined subdirectories, and therefore it is not a directory.
3283 -+ Knowing this allows us to avoid calling stat as long as possible for
3284 -+ leaf files.
3285 -+
3286 -+ NAME is PATHNAME relative to the current directory. We access NAME
3287 -+ but print PATHNAME.
3288 -+
3289 -+ PARENT is the path of the parent of NAME, relative to find's
3290 -+ starting directory.
3291 -+
3292 -+ Return nonzero iff PATHNAME is a directory. */
3293 -+
3294 -+static int
3295 -+process_path (char *pathname, char *name, boolean leaf, char *parent,
3296 -+ mode_t mode)
3297 -+{
3298 -+ struct stat stat_buf;
3299 -+ static dev_t root_dev; /* Device ID of current argument pathname. */
3300 -+ int i;
3301 -+ struct predicate *eval_tree;
3302 -+
3303 -+ eval_tree = get_eval_tree();
3304 -+ /* Assume it is a non-directory initially. */
3305 -+ stat_buf.st_mode = 0;
3306 -+ state.rel_pathname = name;
3307 -+ state.type = 0;
3308 -+ state.have_stat = false;
3309 -+ state.have_type = false;
3310 -+
3311 -+ if (!digest_mode(mode, pathname, name, &stat_buf, leaf))
3312 -+ return 0;
3313 -+
3314 -+ if (!S_ISDIR (state.type))
3315 -+ {
3316 -+ if (state.curdepth >= options.mindepth)
3317 -+ apply_predicate (pathname, &stat_buf, eval_tree);
3318 -+ return 0;
3319 -+ }
3320 -+
3321 -+ /* From here on, we're working on a directory. */
3322 -+
3323 -+
3324 -+ /* Now we really need to stat the directory, even if we know the
3325 -+ * type, because we need information like struct stat.st_rdev.
3326 -+ */
3327 -+ if (get_statinfo(pathname, name, &stat_buf) != 0)
3328 -+ return 0;
3329 -+
3330 -+ state.have_stat = true;
3331 -+ mode = state.type = stat_buf.st_mode; /* use full info now that we have it. */
3332 -+ state.stop_at_current_level =
3333 -+ options.maxdepth >= 0
3334 -+ && state.curdepth >= options.maxdepth;
3335 -+
3336 -+ /* If we've already seen this directory on this branch,
3337 -+ don't descend it again. */
3338 -+ for (i = 0; i <= dir_curr; i++)
3339 -+ if (stat_buf.st_ino == dir_ids[i].ino &&
3340 -+ stat_buf.st_dev == dir_ids[i].dev)
3341 -+ {
3342 -+ state.stop_at_current_level = true;
3343 -+ issue_loop_warning(name, pathname, i);
3344 -+ }
3345 -+
3346 -+ if (dir_alloc <= ++dir_curr)
3347 -+ {
3348 -+ dir_alloc += DIR_ALLOC_STEP;
3349 -+ dir_ids = (struct dir_id *)
3350 -+ xrealloc ((char *) dir_ids, dir_alloc * sizeof (struct dir_id));
3351 -+ }
3352 -+ dir_ids[dir_curr].ino = stat_buf.st_ino;
3353 -+ dir_ids[dir_curr].dev = stat_buf.st_dev;
3354 -+
3355 -+ if (options.stay_on_filesystem)
3356 -+ {
3357 -+ if (state.curdepth == 0)
3358 -+ root_dev = stat_buf.st_dev;
3359 -+ else if (stat_buf.st_dev != root_dev)
3360 -+ state.stop_at_current_level = true;
3361 -+ }
3362 -+
3363 -+ if (options.do_dir_first && state.curdepth >= options.mindepth)
3364 -+ apply_predicate (pathname, &stat_buf, eval_tree);
3365 -+
3366 -+ if (options.debug_options & DebugSearch)
3367 -+ fprintf(stderr, "pathname = %s, stop_at_current_level = %d\n",
3368 -+ pathname, state.stop_at_current_level);
3369 -+
3370 -+ if (state.stop_at_current_level == false)
3371 -+ {
3372 -+ /* Scan directory on disk. */
3373 -+ process_dir (pathname, name, strlen (pathname), &stat_buf, parent);
3374 -+ }
3375 -+
3376 -+ if (options.do_dir_first == false && state.curdepth >= options.mindepth)
3377 -+ {
3378 -+ /* The fields in 'state' are now out of date. Correct them.
3379 -+ */
3380 -+ if (!digest_mode(mode, pathname, name, &stat_buf, leaf))
3381 -+ return 0;
3382 -+
3383 -+ if (0 == dir_curr)
3384 -+ {
3385 -+ at_top(pathname, mode, &stat_buf, do_process_predicate);
3386 -+ }
3387 -+ else
3388 -+ {
3389 -+ do_process_predicate(pathname, name, mode, &stat_buf);
3390 -+ }
3391 -+ }
3392 -+
3393 -+ dir_curr--;
3394 -+
3395 -+ return 1;
3396 -+}
3397 -+
3398 -+
3399 -+/* Scan directory PATHNAME and recurse through process_path for each entry.
3400 -+
3401 -+ PATHLEN is the length of PATHNAME.
3402 -+
3403 -+ NAME is PATHNAME relative to the current directory.
3404 -+
3405 -+ STATP is the results of *options.xstat on it.
3406 -+
3407 -+ PARENT is the path of the parent of NAME, relative to find's
3408 -+ starting directory. */
3409 -+
3410 -+static void
3411 -+process_dir (char *pathname, char *name, int pathlen, const struct stat *statp, char *parent)
3412 -+{
3413 -+ int subdirs_left; /* Number of unexamined subdirs in PATHNAME. */
3414 -+ boolean subdirs_unreliable; /* if true, cannot use dir link count as subdir limif (if false, it may STILL be unreliable) */
3415 -+ unsigned int idx; /* Which entry are we on? */
3416 -+ struct stat stat_buf;
3417 -+ size_t dircount = 0u;
3418 -+ struct savedir_dirinfo *dirinfo;
3419 -+#if 0
3420 -+ printf("process_dir: pathname=%s name=%s statp->st_nlink=%d st_ino=%d\n",
3421 -+ pathname,
3422 -+ name,
3423 -+ (int)statp->st_nlink,
3424 -+ (int)statp->st_ino);
3425 -+#endif
3426 -+ if (statp->st_nlink < 2)
3427 -+ {
3428 -+ subdirs_unreliable = true;
3429 -+ subdirs_left = 0;
3430 -+ }
3431 -+ else
3432 -+ {
3433 -+ subdirs_unreliable = false; /* not necessarily right */
3434 -+ subdirs_left = statp->st_nlink - 2; /* Account for name and ".". */
3435 -+ }
3436 -+
3437 -+ errno = 0;
3438 -+ dirinfo = xsavedir(name, 0);
3439 -+
3440 -+
3441 -+ if (dirinfo == NULL)
3442 -+ {
3443 -+ assert (errno != 0);
3444 -+ error (0, errno, "%s", safely_quote_err_filename(0, pathname));
3445 -+ state.exit_status = 1;
3446 -+ }
3447 -+ else
3448 -+ {
3449 -+ register char *namep; /* Current point in `name_space'. */
3450 -+ char *cur_path; /* Full path of each file to process. */
3451 -+ char *cur_name; /* Base name of each file to process. */
3452 -+ unsigned cur_path_size; /* Bytes allocated for `cur_path'. */
3453 -+ register unsigned file_len; /* Length of each path to process. */
3454 -+ register unsigned pathname_len; /* PATHLEN plus trailing '/'. */
3455 -+ boolean did_stat = false;
3456 -+
3457 -+ if (pathname[pathlen - 1] == '/')
3458 -+ pathname_len = pathlen + 1; /* For '\0'; already have '/'. */
3459 -+ else
3460 -+ pathname_len = pathlen + 2; /* For '/' and '\0'. */
3461 -+ cur_path_size = 0;
3462 -+ cur_path = NULL;
3463 -+
3464 -+ /* We're about to leave the directory. If there are any
3465 -+ * -execdir argument lists which have been built but have not
3466 -+ * yet been processed, do them now because they must be done in
3467 -+ * the same directory.
3468 -+ */
3469 -+ complete_pending_execdirs(get_current_dirfd());
3470 -+
3471 -+ if (strcmp (name, "."))
3472 -+ {
3473 -+ enum SafeChdirStatus status = safely_chdir (name, TraversingDown, &stat_buf, SymlinkHandleDefault, &did_stat);
3474 -+ switch (status)
3475 -+ {
3476 -+ case SafeChdirOK:
3477 -+ /* If there had been a change but wd_sanity_check()
3478 -+ * accepted it, we need to accept that on the
3479 -+ * way back up as well, so modify our record
3480 -+ * of what we think we should see later.
3481 -+ * If there was no change, the assignments are a no-op.
3482 -+ *
3483 -+ * However, before performing the assignment, we need to
3484 -+ * check that we have the stat information. If O_NOFOLLOW
3485 -+ * is available, safely_chdir() will not have needed to use
3486 -+ * stat(), and so stat_buf will just contain random data.
3487 -+ */
3488 -+ if (!did_stat)
3489 -+ {
3490 -+ /* If there is a link we need to follow it. Hence
3491 -+ * the direct call to stat() not through (options.xstat)
3492 -+ */
3493 -+ set_stat_placeholders(&stat_buf);
3494 -+ if (0 != stat(".", &stat_buf))
3495 -+ break; /* skip the assignment. */
3496 -+ }
3497 -+ dir_ids[dir_curr].dev = stat_buf.st_dev;
3498 -+ dir_ids[dir_curr].ino = stat_buf.st_ino;
3499 -+
3500 -+ break;
3501 -+
3502 -+ case SafeChdirFailWouldBeUnableToReturn:
3503 -+ error (0, errno, ".");
3504 -+ state.exit_status = 1;
3505 -+ break;
3506 -+
3507 -+ case SafeChdirFailNonexistent:
3508 -+ case SafeChdirFailDestUnreadable:
3509 -+ case SafeChdirFailStat:
3510 -+ case SafeChdirFailNotDir:
3511 -+ case SafeChdirFailChdirFailed:
3512 -+ error (0, errno, "%s",
3513 -+ safely_quote_err_filename(0, pathname));
3514 -+ state.exit_status = 1;
3515 -+ return;
3516 -+
3517 -+ case SafeChdirFailSymlink:
3518 -+ error (0, 0,
3519 -+ _("warning: not following the symbolic link %s"),
3520 -+ safely_quote_err_filename(0, pathname));
3521 -+ state.exit_status = 1;
3522 -+ return;
3523 -+ }
3524 -+ }
3525 -+
3526 -+ for (idx=0; idx < dirinfo->size; ++idx)
3527 -+ {
3528 -+ /* savedirinfo() may return dirinfo=NULL if extended information
3529 -+ * is not available.
3530 -+ */
3531 -+ mode_t mode = (dirinfo->entries[idx].flags & SavedirHaveFileType) ?
3532 -+ dirinfo->entries[idx].type_info : 0;
3533 -+ namep = dirinfo->entries[idx].name;
3534 -+
3535 -+ /* Append this directory entry's name to the path being searched. */
3536 -+ file_len = pathname_len + strlen (namep);
3537 -+ if (file_len > cur_path_size)
3538 -+ {
3539 -+ while (file_len > cur_path_size)
3540 -+ cur_path_size += 1024;
3541 -+ if (cur_path)
3542 -+ free (cur_path);
3543 -+ cur_path = xmalloc (cur_path_size);
3544 -+ strcpy (cur_path, pathname);
3545 -+ cur_path[pathname_len - 2] = '/';
3546 -+ }
3547 -+ cur_name = cur_path + pathname_len - 1;
3548 -+ strcpy (cur_name, namep);
3549 -+
3550 -+ state.curdepth++;
3551 -+ if (!options.no_leaf_check && !subdirs_unreliable)
3552 -+ {
3553 -+ if (mode && S_ISDIR(mode) && (subdirs_left == 0))
3554 -+ {
3555 -+ /* This is a subdirectory, but the number of directories we
3556 -+ * have found now exceeds the number we would expect given
3557 -+ * the hard link count on the parent. This is likely to be
3558 -+ * a bug in the file system driver (e.g. Linux's
3559 -+ * /proc file system) or may just be a fact that the OS
3560 -+ * doesn't really handle hard links with Unix semantics.
3561 -+ * In the latter case, -noleaf should be used routinely.
3562 -+ */
3563 -+ error(0, 0, _("WARNING: Hard link count is wrong for %1$s "
3564 -+ "(saw only st_nlink=%2$d but we already saw %3$d subdirectories): "
3565 -+ "this may be a bug in your file system driver. "
3566 -+ "Automatically turning on find's -noleaf option. "
3567 -+ "Earlier results may have failed to include directories "
3568 -+ "that should have been searched."),
3569 -+ safely_quote_err_filename(0, pathname),
3570 -+ statp->st_nlink,
3571 -+ dircount);
3572 -+ state.exit_status = 1; /* We know the result is wrong, now */
3573 -+ options.no_leaf_check = true; /* Don't make same
3574 -+ mistake again */
3575 -+ subdirs_unreliable = 1;
3576 -+ subdirs_left = 1; /* band-aid for this iteration. */
3577 -+ }
3578 -+
3579 -+ /* Normal case optimization. On normal Unix
3580 -+ file systems, a directory that has no subdirectories
3581 -+ has two links: its name, and ".". Any additional
3582 -+ links are to the ".." entries of its subdirectories.
3583 -+ Once we have processed as many subdirectories as
3584 -+ there are additional links, we know that the rest of
3585 -+ the entries are non-directories -- in other words,
3586 -+ leaf files. */
3587 -+ {
3588 -+ int count;
3589 -+ count = process_path (cur_path, cur_name,
3590 -+ subdirs_left == 0, pathname,
3591 -+ mode);
3592 -+ subdirs_left -= count;
3593 -+ dircount += count;
3594 -+ }
3595 -+ }
3596 -+ else
3597 -+ {
3598 -+ /* There might be weird (e.g., CD-ROM or MS-DOS) file systems
3599 -+ mounted, which don't have Unix-like directory link counts. */
3600 -+ process_path (cur_path, cur_name, false, pathname, mode);
3601 -+ }
3602 -+
3603 -+ state.curdepth--;
3604 -+ }
3605 -+
3606 -+
3607 -+ /* We're about to leave the directory. If there are any
3608 -+ * -execdir argument lists which have been built but have not
3609 -+ * yet been processed, do them now because they must be done in
3610 -+ * the same directory.
3611 -+ */
3612 -+ complete_pending_execdirs(get_current_dirfd());
3613 -+
3614 -+ if (strcmp (name, "."))
3615 -+ {
3616 -+ enum SafeChdirStatus status;
3617 -+ struct dir_id did;
3618 -+
3619 -+ /* We could go back and do the next command-line arg
3620 -+ instead, maybe using longjmp. */
3621 -+ char const *dir;
3622 -+ boolean deref = following_links() ? true : false;
3623 -+
3624 -+ if ( (state.curdepth>0) && !deref)
3625 -+ dir = "..";
3626 -+ else
3627 -+ {
3628 -+ chdir_back ();
3629 -+ dir = parent;
3630 -+ }
3631 -+
3632 -+ did_stat = false;
3633 -+ status = safely_chdir (dir, TraversingUp, &stat_buf, SymlinkHandleDefault, &did_stat);
3634 -+ switch (status)
3635 -+ {
3636 -+ case SafeChdirOK:
3637 -+ break;
3638 -+
3639 -+ case SafeChdirFailWouldBeUnableToReturn:
3640 -+ error (1, errno, ".");
3641 -+ return;
3642 -+
3643 -+ case SafeChdirFailNonexistent:
3644 -+ case SafeChdirFailDestUnreadable:
3645 -+ case SafeChdirFailStat:
3646 -+ case SafeChdirFailSymlink:
3647 -+ case SafeChdirFailNotDir:
3648 -+ case SafeChdirFailChdirFailed:
3649 -+ error (1, errno, "%s", safely_quote_err_filename(0, pathname));
3650 -+ return;
3651 -+ }
3652 -+
3653 -+ if (dir_curr > 0)
3654 -+ {
3655 -+ did.dev = dir_ids[dir_curr-1].dev;
3656 -+ did.ino = dir_ids[dir_curr-1].ino;
3657 -+ }
3658 -+ else
3659 -+ {
3660 -+ did.dev = starting_stat_buf.st_dev;
3661 -+ did.ino = starting_stat_buf.st_ino;
3662 -+ }
3663 -+ }
3664 -+
3665 -+ if (cur_path)
3666 -+ free (cur_path);
3667 -+ free_dirinfo(dirinfo);
3668 -+ }
3669 -+
3670 -+ if (subdirs_unreliable)
3671 -+ {
3672 -+ /* Make sure we hasn't used the variable subdirs_left if we knew
3673 -+ * we shouldn't do so.
3674 -+ */
3675 -+ assert (0 == subdirs_left || options.no_leaf_check);
3676 -+ }
3677 -+}
3678 -diff -purN findutils-4.3.12.orig/find/parser.c findutils-4.3.12/find/parser.c
3679 ---- findutils-4.3.12.orig/find/parser.c 2007-12-19 16:12:34.000000000 -0500
3680 -+++ findutils-4.3.12/find/parser.c 2008-01-30 08:46:05.754843619 -0500
3681 -@@ -53,6 +53,13 @@
3682 - #include <unistd.h>
3683 - #include <sys/stat.h>
3684 -
3685 -+#ifdef WITH_SELINUX
3686 -+#include <selinux/selinux.h>
3687 -+int optionh_getfilecon(const char *name, security_context_t *p);
3688 -+int optionl_getfilecon(const char *name, security_context_t *p);
3689 -+int optionp_getfilecon(const char *name, security_context_t *p);
3690 -+#endif /*WITH_SELINUX*/
3691 -+
3692 - #if ENABLE_NLS
3693 - # include <libintl.h>
3694 - # define _(Text) gettext (Text)
3695 -@@ -156,6 +163,9 @@ static boolean parse_noignore_race PARAM
3696 - static boolean parse_warn PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
3697 - static boolean parse_xtype PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
3698 - static boolean parse_quit PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
3699 -+#ifdef WITH_SELINUX
3700 -+static boolean parse_scontext PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
3701 -+#endif /*WITH_SELINUX*/
3702 -
3703 - boolean parse_print PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
3704 -
3705 -@@ -341,6 +351,8 @@ static struct parser_table const parse_t
3706 - {ARG_TEST, "-help", parse_help, NULL}, /* GNU */
3707 - {ARG_TEST, "version", parse_version, NULL}, /* GNU */
3708 - {ARG_TEST, "-version", parse_version, NULL}, /* GNU */
3709 -+ {ARG_TEST, "context", parse_scontext, pred_scontext}, /* SELinux */
3710 -+ {ARG_TEST, "-context", parse_scontext, pred_scontext}, /* SELinux */
3711 - {0, 0, 0, 0}
3712 - };
3713 -
3714 -@@ -452,10 +464,16 @@ set_follow_state(enum SymlinkOption opt)
3715 - case SYMLINK_ALWAYS_DEREF: /* -L */
3716 - options.xstat = optionl_stat;
3717 - options.no_leaf_check = true;
3718 -+#ifdef WITH_SELINUX
3719 -+ options.x_getfilecon = optionl_getfilecon;
3720 -+#endif /* WITH_SELINUX */
3721 - break;
3722 -
3723 - case SYMLINK_NEVER_DEREF: /* -P (default) */
3724 - options.xstat = optionp_stat;
3725 -+#ifdef WITH_SELINUX
3726 -+ options.x_getfilecon = optionp_getfilecon;
3727 -+#endif /* WITH_SELINUX */
3728 - /* Can't turn no_leaf_check off because the user might have specified
3729 - * -noleaf anyway
3730 - */
3731 -@@ -464,6 +482,9 @@ set_follow_state(enum SymlinkOption opt)
3732 - case SYMLINK_DEREF_ARGSONLY: /* -H */
3733 - options.xstat = optionh_stat;
3734 - options.no_leaf_check = true;
3735 -+#ifdef WITH_SELINUX
3736 -+ options.x_getfilecon = optionh_getfilecon;
3737 -+#endif /* WITH_SELINUX */
3738 - }
3739 - }
3740 - options.symlink_handling = opt;
3741 -@@ -667,6 +688,94 @@ collect_arg_stat_info(char **argv, int *
3742 -
3743 - The predicate structure is updated with the new information. */
3744 -
3745 -+#ifdef WITH_SELINUX
3746 -+
3747 -+static int
3748 -+fallback_getfilecon(const char *name, security_context_t *p, int prev_rv)
3749 -+{
3750 -+ /* Our original getfilecon() call failed. Perhaps we can't follow a
3751 -+ * symbolic link. If that might be the problem, lgetfilecon() the link.
3752 -+ * Otherwise, admit defeat.
3753 -+ */
3754 -+ switch (errno)
3755 -+ {
3756 -+ case ENOENT:
3757 -+ case ENOTDIR:
3758 -+#ifdef DEBUG_STAT
3759 -+ fprintf(stderr, "fallback_getfilecon(): getfilecon(%s) failed; falling back on lgetfilecon()\n", name);
3760 -+#endif
3761 -+ return lgetfilecon(name, p);
3762 -+
3763 -+ case EACCES:
3764 -+ case EIO:
3765 -+ case ELOOP:
3766 -+ case ENAMETOOLONG:
3767 -+#ifdef EOVERFLOW
3768 -+ case EOVERFLOW: /* EOVERFLOW is not #defined on UNICOS. */
3769 -+#endif
3770 -+ default:
3771 -+ return prev_rv;
3772 -+ }
3773 -+}
3774 -+
3775 -+
3776 -+/* optionh_getfilecon() implements the getfilecon operation when the
3777 -+ * -H option is in effect.
3778 -+ *
3779 -+ * If the item to be examined is a command-line argument, we follow
3780 -+ * symbolic links. If the getfilecon() call fails on the command-line
3781 -+ * item, we fall back on the properties of the symbolic link.
3782 -+ *
3783 -+ * If the item to be examined is not a command-line argument, we
3784 -+ * examine the link itself.
3785 -+ */
3786 -+int
3787 -+optionh_getfilecon(const char *name, security_context_t *p)
3788 -+{
3789 -+ if (0 == state.curdepth)
3790 -+ {
3791 -+ /* This file is from the command line; deference the link (if it
3792 -+ * is a link).
3793 -+ */
3794 -+ int rv = getfilecon(name, p);
3795 -+ if (0 == rv)
3796 -+ return 0; /* success */
3797 -+ else
3798 -+ return fallback_getfilecon(name, p, rv);
3799 -+ }
3800 -+ else
3801 -+ {
3802 -+ /* Not a file on the command line; do not derefernce the link.
3803 -+ */
3804 -+ return lgetfilecon(name, p);
3805 -+ }
3806 -+}
3807 -+
3808 -+/* optionl_getfilecon() implements the getfilecon operation when the
3809 -+ * -L option is in effect. That option makes us examine the thing the
3810 -+ * symbolic link points to, not the symbolic link itself.
3811 -+ */
3812 -+int
3813 -+optionl_getfilecon(const char *name, security_context_t *p)
3814 -+{
3815 -+ int rv = getfilecon(name, p);
3816 -+ if (0 == rv)
3817 -+ return 0; /* normal case. */
3818 -+ else
3819 -+ return fallback_getfilecon(name, p, rv);
3820 -+}
3821 -+
3822 -+/* optionp_getfilecon() implements the stat operation when the -P
3823 -+ * option is in effect (this is also the default). That option makes
3824 -+ * us examine the symbolic link itself, not the thing it points to.
3825 -+ */
3826 -+int
3827 -+optionp_getfilecon(const char *name, security_context_t *p)
3828 -+{
3829 -+ return lgetfilecon(name, p);
3830 -+}
3831 -+#endif /* WITH_SELINUX */
3832 -+
3833 -
3834 - static boolean
3835 - parse_and (const struct parser_table* entry, char **argv, int *arg_ptr)
3836 -@@ -1124,6 +1233,10 @@ tests (N can be +N or -N or N): -amin N
3837 - -readable -writable -executable\n\
3838 - -wholename PATTERN -size N[bcwkMG] -true -type [bcdpflsD] -uid N\n\
3839 - -used N -user NAME -xtype [bcdpfls]\n"));
3840 -+#ifdef WITH_SELINUX
3841 -+ puts (_("\
3842 -+ -context CONTEXT\n"));
3843 -+#endif /*WITH_SELINUX*/
3844 - puts (_("\
3845 - actions: -delete -print0 -printf FORMAT -fprintf FILE FORMAT -print \n\
3846 - -fprint0 FILE -fprint FILE -ls -fls FILE -prune -quit\n\
3847 -@@ -2522,6 +2635,29 @@ parse_version (const struct parser_table
3848 - exit (0);
3849 - }
3850 -
3851 -+#ifdef WITH_SELINUX
3852 -+
3853 -+static boolean
3854 -+parse_scontext ( const struct parser_table* entry, char **argv, int *arg_ptr)
3855 -+{
3856 -+ struct predicate *our_pred;
3857 -+
3858 -+ if ( (argv == NULL) || (argv[*arg_ptr] == NULL) )
3859 -+ return( false );
3860 -+
3861 -+ our_pred = insert_primary(entry);
3862 -+ our_pred->need_stat = false;
3863 -+#ifdef DEBUG
3864 -+ our_pred->p_name = find_pred_name (pred_scontext);
3865 -+#endif /*DEBUG*/
3866 -+ our_pred->args.scontext = argv[*arg_ptr];;
3867 -+
3868 -+ (*arg_ptr)++;
3869 -+ return( true );
3870 -+}
3871 -+
3872 -+#endif /*WITH_SELINUX*/
3873 -+
3874 - static boolean
3875 - parse_xdev (const struct parser_table* entry, char **argv, int *arg_ptr)
3876 - {
3877 -@@ -2773,7 +2909,11 @@ insert_fprintf (struct format_val *vec,
3878 - if (*scan2 == '.')
3879 - for (scan2++; ISDIGIT (*scan2); scan2++)
3880 - /* Do nothing. */ ;
3881 -+#ifdef WITH_SELINUX
3882 -+ if (strchr ("abcdDfFgGhHiklmMnpPsStuUyYZ", *scan2))
3883 -+#else
3884 - if (strchr ("abcdDfFgGhHiklmMnpPsStuUyY", *scan2))
3885 -+#endif
3886 - {
3887 - segmentp = make_segment (segmentp, format, scan2 - format,
3888 - KIND_FORMAT, *scan2, 0,
3889 -diff -purN findutils-4.3.12.orig/find/parser.c.orig findutils-4.3.12/find/parser.c.orig
3890 ---- findutils-4.3.12.orig/find/parser.c.orig 1969-12-31 19:00:00.000000000 -0500
3891 -+++ findutils-4.3.12/find/parser.c.orig 2007-12-19 16:12:34.000000000 -0500
3892 -@@ -0,0 +1,3502 @@
3893 -+/* parser.c -- convert the command line args into an expression tree.
3894 -+ Copyright (C) 1990, 1991, 1992, 1993, 1994, 2000, 2001, 2003,
3895 -+ 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
3896 -+
3897 -+ This program is free software: you can redistribute it and/or modify
3898 -+ it under the terms of the GNU General Public License as published by
3899 -+ the Free Software Foundation, either version 3 of the License, or
3900 -+ (at your option) any later version.
3901 -+
3902 -+ This program is distributed in the hope that it will be useful,
3903 -+ but WITHOUT ANY WARRANTY; without even the implied warranty of
3904 -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3905 -+ GNU General Public License for more details.
3906 -+
3907 -+ You should have received a copy of the GNU General Public License
3908 -+ along with this program. If not, see <http://www.gnu.org/licenses/>.
3909 -+*/
3910 -+
3911 -+#include <config.h>
3912 -+
3913 -+#include "defs.h"
3914 -+#include <ctype.h>
3915 -+#include <math.h>
3916 -+#include <assert.h>
3917 -+#include <pwd.h>
3918 -+#include <errno.h>
3919 -+#include <grp.h>
3920 -+#include <fnmatch.h>
3921 -+#include "modechange.h"
3922 -+#include "modetype.h"
3923 -+#include "xstrtol.h"
3924 -+#include "xalloc.h"
3925 -+#include "quote.h"
3926 -+#include "quotearg.h"
3927 -+#include "buildcmd.h"
3928 -+#include "nextelem.h"
3929 -+#include "stdio-safer.h"
3930 -+#include "regextype.h"
3931 -+#include "stat-time.h"
3932 -+#include "xstrtod.h"
3933 -+#include "fts_.h"
3934 -+#include "getdate.h"
3935 -+#include "error.h"
3936 -+#include "findutils-version.h"
3937 -+
3938 -+#include <fcntl.h>
3939 -+
3940 -+
3941 -+/* The presence of unistd.h is assumed by gnulib these days, so we
3942 -+ * might as well assume it too.
3943 -+ */
3944 -+/* We need <unistd.h> for isatty(). */
3945 -+#include <unistd.h>
3946 -+#include <sys/stat.h>
3947 -+
3948 -+#if ENABLE_NLS
3949 -+# include <libintl.h>
3950 -+# define _(Text) gettext (Text)
3951 -+#else
3952 -+# define _(Text) Text
3953 -+#endif
3954 -+#ifdef gettext_noop
3955 -+# define N_(String) gettext_noop (String)
3956 -+#else
3957 -+/* See locate.c for explanation as to why not use (String) */
3958 -+# define N_(String) String
3959 -+#endif
3960 -+
3961 -+#if !defined (isascii) || defined (STDC_HEADERS)
3962 -+#ifdef isascii
3963 -+#undef isascii
3964 -+#endif
3965 -+#define isascii(c) 1
3966 -+#endif
3967 -+
3968 -+#define ISDIGIT(c) (isascii ((unsigned char)c) && isdigit ((unsigned char)c))
3969 -+#define ISUPPER(c) (isascii ((unsigned char)c) && isupper ((unsigned char)c))
3970 -+
3971 -+#ifndef HAVE_ENDGRENT
3972 -+#define endgrent()
3973 -+#endif
3974 -+#ifndef HAVE_ENDPWENT
3975 -+#define endpwent()
3976 -+#endif
3977 -+
3978 -+static boolean parse_accesscheck PARAMS((const struct parser_table* entry, char **argv, int *arg_ptr));
3979 -+static boolean parse_amin PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
3980 -+static boolean parse_and PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
3981 -+static boolean parse_anewer PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
3982 -+static boolean parse_cmin PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
3983 -+static boolean parse_cnewer PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
3984 -+static boolean parse_comma PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
3985 -+static boolean parse_daystart PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
3986 -+static boolean parse_delete PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
3987 -+static boolean parse_d PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
3988 -+static boolean parse_depth PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
3989 -+static boolean parse_empty PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
3990 -+static boolean parse_exec PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
3991 -+static boolean parse_execdir PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
3992 -+static boolean parse_false PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
3993 -+static boolean parse_fls PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
3994 -+static boolean parse_fprintf PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
3995 -+static boolean parse_follow PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
3996 -+static boolean parse_fprint PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
3997 -+static boolean parse_fprint0 PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
3998 -+static boolean parse_fstype PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
3999 -+static boolean parse_gid PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
4000 -+static boolean parse_group PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
4001 -+static boolean parse_help PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
4002 -+static boolean parse_ilname PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
4003 -+static boolean parse_iname PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
4004 -+static boolean parse_inum PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
4005 -+static boolean parse_ipath PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
4006 -+static boolean parse_iregex PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
4007 -+static boolean parse_iwholename PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
4008 -+static boolean parse_links PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
4009 -+static boolean parse_lname PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
4010 -+static boolean parse_ls PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
4011 -+static boolean parse_maxdepth PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
4012 -+static boolean parse_mindepth PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
4013 -+static boolean parse_mmin PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
4014 -+static boolean parse_name PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
4015 -+static boolean parse_negate PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
4016 -+static boolean parse_newer PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
4017 -+static boolean parse_newerXY PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
4018 -+static boolean parse_noleaf PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
4019 -+static boolean parse_nogroup PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
4020 -+static boolean parse_nouser PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
4021 -+static boolean parse_nowarn PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
4022 -+static boolean parse_ok PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
4023 -+static boolean parse_okdir PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
4024 -+static boolean parse_or PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
4025 -+static boolean parse_path PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
4026 -+static boolean parse_perm PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
4027 -+static boolean parse_print0 PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
4028 -+static boolean parse_printf PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
4029 -+static boolean parse_prune PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
4030 -+static boolean parse_regex PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
4031 -+static boolean parse_regextype PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
4032 -+static boolean parse_samefile PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
4033 -+#if 0
4034 -+static boolean parse_show_control_chars PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
4035 -+#endif
4036 -+static boolean parse_size PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
4037 -+static boolean parse_time PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
4038 -+static boolean parse_true PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
4039 -+static boolean parse_type PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
4040 -+static boolean parse_uid PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
4041 -+static boolean parse_used PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
4042 -+static boolean parse_user PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
4043 -+static boolean parse_version PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
4044 -+static boolean parse_wholename PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
4045 -+static boolean parse_xdev PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
4046 -+static boolean parse_ignore_race PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
4047 -+static boolean parse_noignore_race PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
4048 -+static boolean parse_warn PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
4049 -+static boolean parse_xtype PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
4050 -+static boolean parse_quit PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
4051 -+
4052 -+boolean parse_print PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
4053 -+
4054 -+
4055 -+static boolean insert_type PARAMS((char **argv, int *arg_ptr,
4056 -+ const struct parser_table *entry,
4057 -+ PRED_FUNC which_pred));
4058 -+static boolean insert_regex PARAMS((char *argv[], int *arg_ptr,
4059 -+ const struct parser_table *entry,
4060 -+ int regex_options));
4061 -+static boolean insert_fprintf (struct format_val *vec,
4062 -+ const struct parser_table *entry,
4063 -+ PRED_FUNC func,
4064 -+ const char *format);
4065 -+
4066 -+static struct segment **make_segment PARAMS((struct segment **segment,
4067 -+ char *format, int len,
4068 -+ int kind, char format_char,
4069 -+ char aux_format_char,
4070 -+ struct predicate *pred));
4071 -+static boolean insert_exec_ok PARAMS((const char *action,
4072 -+ const struct parser_table *entry,
4073 -+ int dirfd,
4074 -+ char *argv[],
4075 -+ int *arg_ptr));
4076 -+static boolean get_comp_type PARAMS((const char **str,
4077 -+ enum comparison_type *comp_type));
4078 -+static boolean get_relative_timestamp PARAMS((const char *str,
4079 -+ struct time_val *tval,
4080 -+ time_t origin,
4081 -+ double sec_per_unit,
4082 -+ const char *overflowmessage));
4083 -+static boolean get_num PARAMS((const char *str,
4084 -+ uintmax_t *num,
4085 -+ enum comparison_type *comp_type));
4086 -+static struct predicate* insert_num PARAMS((char *argv[], int *arg_ptr,
4087 -+ const struct parser_table *entry));
4088 -+static void open_output_file (const char *path, struct format_val *p);
4089 -+static void open_stdout (struct format_val *p);
4090 -+static boolean stream_is_tty(FILE *fp);
4091 -+static boolean parse_noop PARAMS((const struct parser_table* entry,
4092 -+ char **argv, int *arg_ptr));
4093 -+
4094 -+#define PASTE(x,y) x##y
4095 -+#define STRINGIFY(s) #s
4096 -+
4097 -+#define PARSE_OPTION(what,suffix) \
4098 -+ { (ARG_OPTION), (what), PASTE(parse_,suffix), NULL }
4099 -+
4100 -+#define PARSE_POSOPT(what,suffix) \
4101 -+ { (ARG_POSITIONAL_OPTION), (what), PASTE(parse_,suffix), NULL }
4102 -+
4103 -+#define PARSE_TEST(what,suffix) \
4104 -+ { (ARG_TEST), (what), PASTE(parse_,suffix), PASTE(pred_,suffix) }
4105 -+
4106 -+#define PARSE_TEST_NP(what,suffix) \
4107 -+ { (ARG_TEST), (what), PASTE(parse_,suffix), NULL }
4108 -+
4109 -+#define PARSE_ACTION(what,suffix) \
4110 -+ { (ARG_ACTION), (what), PASTE(parse_,suffix), PASTE(pred_,suffix) }
4111 -+
4112 -+#define PARSE_ACTION_NP(what,suffix) \
4113 -+ { (ARG_ACTION), (what), PASTE(parse_,suffix), NULL }
4114 -+
4115 -+#define PARSE_PUNCTUATION(what,suffix) \
4116 -+ { (ARG_PUNCTUATION), (what), PASTE(parse_,suffix), PASTE(pred_,suffix) }
4117 -+
4118 -+
4119 -+/* Predicates we cannot handle in the usual way. If you add an entry
4120 -+ * to this table, double-check the switch statement in
4121 -+ * pred_sanity_check() to make sure that the new case is being
4122 -+ * correctly handled.
4123 -+ */
4124 -+static struct parser_table const parse_entry_newerXY =
4125 -+ {
4126 -+ ARG_SPECIAL_PARSE, "newerXY", parse_newerXY, pred_newerXY /* BSD */
4127 -+ };
4128 -+
4129 -+/* GNU find predicates that are not mentioned in POSIX.2 are marked `GNU'.
4130 -+ If they are in some Unix versions of find, they are marked `Unix'. */
4131 -+
4132 -+static struct parser_table const parse_table[] =
4133 -+{
4134 -+ PARSE_PUNCTUATION("!", negate), /* POSIX */
4135 -+ PARSE_PUNCTUATION("not", negate), /* GNU */
4136 -+ PARSE_PUNCTUATION("(", openparen), /* POSIX */
4137 -+ PARSE_PUNCTUATION(")", closeparen), /* POSIX */
4138 -+ PARSE_PUNCTUATION(",", comma), /* GNU */
4139 -+ PARSE_PUNCTUATION("a", and), /* POSIX */
4140 -+ PARSE_TEST ("amin", amin), /* GNU */
4141 -+ PARSE_PUNCTUATION("and", and), /* GNU */
4142 -+ PARSE_TEST ("anewer", anewer), /* GNU */
4143 -+ {ARG_TEST, "atime", parse_time, pred_atime}, /* POSIX */
4144 -+ PARSE_TEST ("cmin", cmin), /* GNU */
4145 -+ PARSE_TEST ("cnewer", cnewer), /* GNU */
4146 -+ {ARG_TEST, "ctime", parse_time, pred_ctime}, /* POSIX */
4147 -+ PARSE_POSOPT ("daystart", daystart), /* GNU */
4148 -+ PARSE_ACTION ("delete", delete), /* GNU, Mac OS, FreeBSD */
4149 -+ PARSE_OPTION ("d", d), /* Mac OS X, FreeBSD, NetBSD, OpenBSD, but deprecated in favour of -depth */
4150 -+ PARSE_OPTION ("depth", depth), /* POSIX */
4151 -+ PARSE_TEST ("empty", empty), /* GNU */
4152 -+ {ARG_ACTION, "exec", parse_exec, pred_exec}, /* POSIX */
4153 -+ {ARG_TEST, "executable", parse_accesscheck, pred_executable}, /* GNU, 4.3.0+ */
4154 -+ PARSE_ACTION ("execdir", execdir), /* *BSD, GNU */
4155 -+ PARSE_ACTION ("fls", fls), /* GNU */
4156 -+ PARSE_POSOPT ("follow", follow), /* GNU, Unix */
4157 -+ PARSE_ACTION ("fprint", fprint), /* GNU */
4158 -+ PARSE_ACTION ("fprint0", fprint0), /* GNU */
4159 -+ {ARG_ACTION, "fprintf", parse_fprintf, pred_fprintf}, /* GNU */
4160 -+ PARSE_TEST ("fstype", fstype), /* GNU, Unix */
4161 -+ PARSE_TEST ("gid", gid), /* GNU */
4162 -+ PARSE_TEST ("group", group), /* POSIX */
4163 -+ PARSE_OPTION ("ignore_readdir_race", ignore_race), /* GNU */
4164 -+ PARSE_TEST ("ilname", ilname), /* GNU */
4165 -+ PARSE_TEST ("iname", iname), /* GNU */
4166 -+ PARSE_TEST ("inum", inum), /* GNU, Unix */
4167 -+ PARSE_TEST ("ipath", ipath), /* GNU, deprecated in favour of iwholename */
4168 -+ PARSE_TEST_NP ("iregex", iregex), /* GNU */
4169 -+ PARSE_TEST_NP ("iwholename", iwholename), /* GNU */
4170 -+ PARSE_TEST ("links", links), /* POSIX */
4171 -+ PARSE_TEST ("lname", lname), /* GNU */
4172 -+ PARSE_ACTION ("ls", ls), /* GNU, Unix */
4173 -+ PARSE_OPTION ("maxdepth", maxdepth), /* GNU */
4174 -+ PARSE_OPTION ("mindepth", mindepth), /* GNU */
4175 -+ PARSE_TEST ("mmin", mmin), /* GNU */
4176 -+ PARSE_OPTION ("mount", xdev), /* Unix */
4177 -+ {ARG_TEST, "mtime", parse_time, pred_mtime}, /* POSIX */
4178 -+ PARSE_TEST ("name", name),
4179 -+#ifdef UNIMPLEMENTED_UNIX
4180 -+ PARSE(ARG_UNIMPLEMENTED, "ncpio", ncpio), /* Unix */
4181 -+#endif
4182 -+ PARSE_TEST ("newer", newer), /* POSIX */
4183 -+ {ARG_TEST, "atime", parse_time, pred_atime}, /* POSIX */
4184 -+ PARSE_OPTION ("noleaf", noleaf), /* GNU */
4185 -+ PARSE_TEST ("nogroup", nogroup), /* POSIX */
4186 -+ PARSE_TEST ("nouser", nouser), /* POSIX */
4187 -+ PARSE_OPTION ("noignore_readdir_race", noignore_race), /* GNU */
4188 -+ PARSE_POSOPT ("nowarn", nowarn), /* GNU */
4189 -+ PARSE_PUNCTUATION("o", or), /* POSIX */
4190 -+ PARSE_PUNCTUATION("or", or), /* GNU */
4191 -+ PARSE_ACTION ("ok", ok), /* POSIX */
4192 -+ PARSE_ACTION ("okdir", okdir), /* GNU (-execdir is BSD) */
4193 -+ PARSE_TEST ("path", path), /* GNU, HP-UX, RMS prefers wholename, but anyway soon POSIX */
4194 -+ PARSE_TEST ("perm", perm), /* POSIX */
4195 -+ PARSE_ACTION ("print", print), /* POSIX */
4196 -+ PARSE_ACTION ("print0", print0), /* GNU */
4197 -+ {ARG_ACTION, "printf", parse_printf, NULL}, /* GNU */
4198 -+ PARSE_ACTION ("prune", prune), /* POSIX */
4199 -+ PARSE_ACTION ("quit", quit), /* GNU */
4200 -+ {ARG_TEST, "readable", parse_accesscheck, pred_readable}, /* GNU, 4.3.0+ */
4201 -+ PARSE_TEST ("regex", regex), /* GNU */
4202 -+ PARSE_OPTION ("regextype", regextype), /* GNU */
4203 -+ PARSE_TEST ("samefile", samefile), /* GNU */
4204 -+#if 0
4205 -+ PARSE_OPTION ("show-control-chars", show_control_chars), /* GNU, 4.3.0+ */
4206 -+#endif
4207 -+ PARSE_TEST ("size", size), /* POSIX */
4208 -+ PARSE_TEST ("type", type), /* POSIX */
4209 -+ PARSE_TEST ("uid", uid), /* GNU */
4210 -+ PARSE_TEST ("used", used), /* GNU */
4211 -+ PARSE_TEST ("user", user), /* POSIX */
4212 -+ PARSE_OPTION ("warn", warn), /* GNU */
4213 -+ PARSE_TEST_NP ("wholename", wholename), /* GNU, replaced -path, but anyway -path will soon be in POSIX */
4214 -+ {ARG_TEST, "writable", parse_accesscheck, pred_writable}, /* GNU, 4.3.0+ */
4215 -+ PARSE_OPTION ("xdev", xdev), /* POSIX */
4216 -+ PARSE_TEST ("xtype", xtype), /* GNU */
4217 -+#ifdef UNIMPLEMENTED_UNIX
4218 -+ /* It's pretty ugly for find to know about archive formats.
4219 -+ Plus what it could do with cpio archives is very limited.
4220 -+ Better to leave it out. */
4221 -+ PARSE(ARG_UNIMPLEMENTED, "cpio", cpio), /* Unix */
4222 -+#endif
4223 -+ /* gnulib's stdbool.h might have made true and false into macros,
4224 -+ * so we can't leave named 'true' and 'false' tokens, so we have
4225 -+ * to expeant the relevant entries longhand.
4226 -+ */
4227 -+ {ARG_TEST, "false", parse_false, pred_false}, /* GNU */
4228 -+ {ARG_TEST, "true", parse_true, pred_true }, /* GNU */
4229 -+ {ARG_NOOP, "noop", NULL, pred_true }, /* GNU, internal use only */
4230 -+
4231 -+ /* Various other cases that don't fit neatly into our macro scheme. */
4232 -+ {ARG_TEST, "help", parse_help, NULL}, /* GNU */
4233 -+ {ARG_TEST, "-help", parse_help, NULL}, /* GNU */
4234 -+ {ARG_TEST, "version", parse_version, NULL}, /* GNU */
4235 -+ {ARG_TEST, "-version", parse_version, NULL}, /* GNU */
4236 -+ {0, 0, 0, 0}
4237 -+};
4238 -+
4239 -+
4240 -+static const char *first_nonoption_arg = NULL;
4241 -+static const struct parser_table *noop = NULL;
4242 -+
4243 -+
4244 -+void
4245 -+check_option_combinations(const struct predicate *p)
4246 -+{
4247 -+ enum { seen_delete=1u, seen_prune=2u };
4248 -+ unsigned int predicates = 0u;
4249 -+
4250 -+ while (p)
4251 -+ {
4252 -+ if (p->pred_func == pred_delete)
4253 -+ predicates |= seen_delete;
4254 -+ else if (p->pred_func == pred_prune)
4255 -+ predicates |= seen_prune;
4256 -+ p = p->pred_next;
4257 -+ }
4258 -+
4259 -+ if ((predicates & seen_prune) && (predicates & seen_delete))
4260 -+ {
4261 -+ /* The user specified both -delete and -prune. One might test
4262 -+ * this by first doing
4263 -+ * find dirs .... -prune ..... -print
4264 -+ * to fnd out what's going to get deleted, and then switch to
4265 -+ * find dirs .... -prune ..... -delete
4266 -+ * once we are happy. Unfortunately, the -delete action also
4267 -+ * implicitly turns on -depth, which will affect the behaviour
4268 -+ * of -prune (in fact, it makes it a no-op). In this case we
4269 -+ * would like to prevent unfortunate accidents, so we require
4270 -+ * the user to have explicitly used -depth.
4271 -+ *
4272 -+ * We only get away with this because the -delete predicate is not
4273 -+ * in POSIX. If it was, we couldn't issue a fatal error here.
4274 -+ */
4275 -+ if (!options.explicit_depth)
4276 -+ {
4277 -+ /* This fixes Savannah bug #20865. */
4278 -+ error (1, 0, _("The -delete action atomatically turns on -depth, "
4279 -+ "but -prune does nothing when -depth is in effect. "
4280 -+ "If you want to carry on anyway, just explicitly use "
4281 -+ "the -depth option."));
4282 -+ }
4283 -+ }
4284 -+}
4285 -+
4286 -+
4287 -+static const struct parser_table*
4288 -+get_noop(void)
4289 -+{
4290 -+ int i;
4291 -+ if (NULL == noop)
4292 -+ {
4293 -+ for (i = 0; parse_table[i].parser_name != 0; i++)
4294 -+ {
4295 -+ if (ARG_NOOP ==parse_table[i].type)
4296 -+ {
4297 -+ noop = &(parse_table[i]);
4298 -+ break;
4299 -+ }
4300 -+ }
4301 -+ }
4302 -+ return noop;
4303 -+}
4304 -+
4305 -+static int
4306 -+get_stat_Ytime(const struct stat *p,
4307 -+ char what,
4308 -+ struct timespec *ret)
4309 -+{
4310 -+ switch (what)
4311 -+ {
4312 -+ case 'a':
4313 -+ *ret = get_stat_atime(p);
4314 -+ return 1;
4315 -+ case 'B':
4316 -+ *ret = get_stat_birthtime(p);
4317 -+ return (ret->tv_nsec >= 0);
4318 -+ case 'c':
4319 -+ *ret = get_stat_ctime(p);
4320 -+ return 1;
4321 -+ case 'm':
4322 -+ *ret = get_stat_mtime(p);
4323 -+ return 1;
4324 -+ default:
4325 -+ assert (0);
4326 -+ abort();
4327 -+ }
4328 -+}
4329 -+
4330 -+void
4331 -+set_follow_state(enum SymlinkOption opt)
4332 -+{
4333 -+ if (options.debug_options & DebugStat)
4334 -+ {
4335 -+ /* For DebugStat, the choice is made at runtime within debug_stat()
4336 -+ * by checking the contents of the symlink_handling variable.
4337 -+ */
4338 -+ options.xstat = debug_stat;
4339 -+ }
4340 -+ else
4341 -+ {
4342 -+ switch (opt)
4343 -+ {
4344 -+ case SYMLINK_ALWAYS_DEREF: /* -L */
4345 -+ options.xstat = optionl_stat;
4346 -+ options.no_leaf_check = true;
4347 -+ break;
4348 -+
4349 -+ case SYMLINK_NEVER_DEREF: /* -P (default) */
4350 -+ options.xstat = optionp_stat;
4351 -+ /* Can't turn no_leaf_check off because the user might have specified
4352 -+ * -noleaf anyway
4353 -+ */
4354 -+ break;
4355 -+
4356 -+ case SYMLINK_DEREF_ARGSONLY: /* -H */
4357 -+ options.xstat = optionh_stat;
4358 -+ options.no_leaf_check = true;
4359 -+ }
4360 -+ }
4361 -+ options.symlink_handling = opt;
4362 -+}
4363 -+
4364 -+
4365 -+void
4366 -+parse_begin_user_args (char **args, int argno,
4367 -+ const struct predicate *last,
4368 -+ const struct predicate *predicates)
4369 -+{
4370 -+ (void) args;
4371 -+ (void) argno;
4372 -+ (void) last;
4373 -+ (void) predicates;
4374 -+ first_nonoption_arg = NULL;
4375 -+}
4376 -+
4377 -+void
4378 -+parse_end_user_args (char **args, int argno,
4379 -+ const struct predicate *last,
4380 -+ const struct predicate *predicates)
4381 -+{
4382 -+ /* does nothing */
4383 -+ (void) args;
4384 -+ (void) argno;
4385 -+ (void) last;
4386 -+ (void) predicates;
4387 -+}
4388 -+
4389 -+
4390 -+/* Check that it is legal to fid the given primary in its
4391 -+ * position and return it.
4392 -+ */
4393 -+const struct parser_table*
4394 -+found_parser(const char *original_arg, const struct parser_table *entry)
4395 -+{
4396 -+ /* If this is an option, but we have already had a
4397 -+ * non-option argument, the user may be under the
4398 -+ * impression that the behaviour of the option
4399 -+ * argument is conditional on some preceding
4400 -+ * tests. This might typically be the case with,
4401 -+ * for example, -maxdepth.
4402 -+ *
4403 -+ * The options -daystart and -follow are exempt
4404 -+ * from this treatment, since their positioning
4405 -+ * in the command line does have an effect on
4406 -+ * subsequent tests but not previous ones. That
4407 -+ * might be intentional on the part of the user.
4408 -+ */
4409 -+ if (entry->type != ARG_POSITIONAL_OPTION)
4410 -+ {
4411 -+ /* Something other than -follow/-daystart.
4412 -+ * If this is an option, check if it followed
4413 -+ * a non-option and if so, issue a warning.
4414 -+ */
4415 -+ if (entry->type == ARG_OPTION)
4416 -+ {
4417 -+ if ((first_nonoption_arg != NULL)
4418 -+ && options.warnings )
4419 -+ {
4420 -+ /* option which follows a non-option */
4421 -+ error (0, 0,
4422 -+ _("warning: you have specified the %1$s "
4423 -+ "option after a non-option argument %2$s, "
4424 -+ "but options are not positional (%3$s affects "
4425 -+ "tests specified before it as well as those "
4426 -+ "specified after it). Please specify options "
4427 -+ "before other arguments.\n"),
4428 -+ original_arg,
4429 -+ first_nonoption_arg,
4430 -+ original_arg);
4431 -+ }
4432 -+ }
4433 -+ else
4434 -+ {
4435 -+ /* Not an option or a positional option,
4436 -+ * so remember we've seen it in order to
4437 -+ * use it in a possible future warning message.
4438 -+ */
4439 -+ if (first_nonoption_arg == NULL)
4440 -+ {
4441 -+ first_nonoption_arg = original_arg;
4442 -+ }
4443 -+ }
4444 -+ }
4445 -+
4446 -+ return entry;
4447 -+}
4448 -+
4449 -+
4450 -+/* Return a pointer to the parser function to invoke for predicate
4451 -+ SEARCH_NAME.
4452 -+ Return NULL if SEARCH_NAME is not a valid predicate name. */
4453 -+
4454 -+const struct parser_table*
4455 -+find_parser (char *search_name)
4456 -+{
4457 -+ int i;
4458 -+ const char *original_arg = search_name;
4459 -+
4460 -+ /* Ugh. Special case -newerXY. */
4461 -+ if (0 == strncmp("-newer", search_name, 6)
4462 -+ && (8 == strlen(search_name)))
4463 -+ {
4464 -+ return found_parser(original_arg, &parse_entry_newerXY);
4465 -+ }
4466 -+
4467 -+ if (*search_name == '-')
4468 -+ search_name++;
4469 -+
4470 -+ for (i = 0; parse_table[i].parser_name != 0; i++)
4471 -+ {
4472 -+ if (strcmp (parse_table[i].parser_name, search_name) == 0)
4473 -+ {
4474 -+ return found_parser(original_arg, &parse_table[i]);
4475 -+ }
4476 -+ }
4477 -+ return NULL;
4478 -+}
4479 -+
4480 -+static float
4481 -+estimate_file_age_success_rate(float num_days)
4482 -+{
4483 -+ if (num_days < 0.1)
4484 -+ {
4485 -+ /* Assume 1% of files have timestamps in the future */
4486 -+ return 0.01f;
4487 -+ }
4488 -+ else if (num_days < 1)
4489 -+ {
4490 -+ /* Assume 30% of files have timestamps today */
4491 -+ return 0.3f;
4492 -+ }
4493 -+ else if (num_days > 100)
4494 -+ {
4495 -+ /* Assume 30% of files are very old */
4496 -+ return 0.3f;
4497 -+ }
4498 -+ else
4499 -+ {
4500 -+ /* Assume 39% of files are between 1 and 100 days old. */
4501 -+ return 0.39f;
4502 -+ }
4503 -+}
4504 -+
4505 -+static float
4506 -+estimate_timestamp_success_rate(time_t when)
4507 -+{
4508 -+ int num_days = (options.cur_day_start - when) / 86400;
4509 -+ return estimate_file_age_success_rate(num_days);
4510 -+}
4511 -+
4512 -+/* Collect an argument from the argument list, or
4513 -+ * return false.
4514 -+ */
4515 -+static boolean
4516 -+collect_arg(char **argv, int *arg_ptr, const char **collected_arg)
4517 -+{
4518 -+ if ((argv == NULL) || (argv[*arg_ptr] == NULL))
4519 -+ {
4520 -+ *collected_arg = NULL;
4521 -+ return false;
4522 -+ }
4523 -+ else
4524 -+ {
4525 -+ *collected_arg = argv[*arg_ptr];
4526 -+ (*arg_ptr)++;
4527 -+ return true;
4528 -+ }
4529 -+}
4530 -+
4531 -+static boolean
4532 -+collect_arg_stat_info(char **argv, int *arg_ptr, struct stat *p)
4533 -+{
4534 -+ const char *filename;
4535 -+ if (collect_arg(argv, arg_ptr, &filename))
4536 -+ {
4537 -+ if (0 == (options.xstat)(filename, p))
4538 -+ {
4539 -+ return true;
4540 -+ }
4541 -+ else
4542 -+ {
4543 -+ fatal_file_error(filename);
4544 -+ }
4545 -+ }
4546 -+ else
4547 -+ {
4548 -+ return false;
4549 -+ }
4550 -+}
4551 -+
4552 -+/* The parsers are responsible to continue scanning ARGV for
4553 -+ their arguments. Each parser knows what is and isn't
4554 -+ allowed for itself.
4555 -+
4556 -+ ARGV is the argument array.
4557 -+ *ARG_PTR is the index to start at in ARGV,
4558 -+ updated to point beyond the last element consumed.
4559 -+
4560 -+ The predicate structure is updated with the new information. */
4561 -+
4562 -+
4563 -+static boolean
4564 -+parse_and (const struct parser_table* entry, char **argv, int *arg_ptr)
4565 -+{
4566 -+ struct predicate *our_pred;
4567 -+
4568 -+ (void) argv;
4569 -+ (void) arg_ptr;
4570 -+
4571 -+ our_pred = get_new_pred (entry);
4572 -+ our_pred->pred_func = pred_and;
4573 -+ our_pred->p_type = BI_OP;
4574 -+ our_pred->p_prec = AND_PREC;
4575 -+ our_pred->need_stat = our_pred->need_type = false;
4576 -+ return true;
4577 -+}
4578 -+
4579 -+static boolean
4580 -+parse_anewer (const struct parser_table* entry, char **argv, int *arg_ptr)
4581 -+{
4582 -+ struct stat stat_newer;
4583 -+
4584 -+ set_stat_placeholders(&stat_newer);
4585 -+ if (collect_arg_stat_info(argv, arg_ptr, &stat_newer))
4586 -+ {
4587 -+ struct predicate *our_pred = insert_primary (entry);
4588 -+ our_pred->args.reftime.xval = XVAL_ATIME;
4589 -+ our_pred->args.reftime.ts = get_stat_mtime(&stat_newer);
4590 -+ our_pred->args.reftime.kind = COMP_GT;
4591 -+ our_pred->est_success_rate = estimate_timestamp_success_rate(stat_newer.st_mtime);
4592 -+ return true;
4593 -+ }
4594 -+ return false;
4595 -+}
4596 -+
4597 -+boolean
4598 -+parse_closeparen (const struct parser_table* entry, char **argv, int *arg_ptr)
4599 -+{
4600 -+ struct predicate *our_pred;
4601 -+
4602 -+ (void) argv;
4603 -+ (void) arg_ptr;
4604 -+
4605 -+ our_pred = get_new_pred (entry);
4606 -+ our_pred->pred_func = pred_closeparen;
4607 -+ our_pred->p_type = CLOSE_PAREN;
4608 -+ our_pred->p_prec = NO_PREC;
4609 -+ our_pred->need_stat = our_pred->need_type = false;
4610 -+ return true;
4611 -+}
4612 -+
4613 -+static boolean
4614 -+parse_cnewer (const struct parser_table* entry, char **argv, int *arg_ptr)
4615 -+{
4616 -+ struct stat stat_newer;
4617 -+
4618 -+ set_stat_placeholders(&stat_newer);
4619 -+ if (collect_arg_stat_info(argv, arg_ptr, &stat_newer))
4620 -+ {
4621 -+ struct predicate *our_pred = insert_primary (entry);
4622 -+ our_pred->args.reftime.xval = XVAL_CTIME; /* like -newercm */
4623 -+ our_pred->args.reftime.ts = get_stat_mtime(&stat_newer);
4624 -+ our_pred->args.reftime.kind = COMP_GT;
4625 -+ our_pred->est_success_rate = estimate_timestamp_success_rate(stat_newer.st_mtime);
4626 -+ return true;
4627 -+ }
4628 -+ return false;
4629 -+}
4630 -+
4631 -+static boolean
4632 -+parse_comma (const struct parser_table* entry, char **argv, int *arg_ptr)
4633 -+{
4634 -+ struct predicate *our_pred;
4635 -+
4636 -+ (void) argv;
4637 -+ (void) arg_ptr;
4638 -+
4639 -+ our_pred = get_new_pred (entry);
4640 -+ our_pred->pred_func = pred_comma;
4641 -+ our_pred->p_type = BI_OP;
4642 -+ our_pred->p_prec = COMMA_PREC;
4643 -+ our_pred->need_stat = our_pred->need_type = false;
4644 -+ our_pred->est_success_rate = 1.0f;
4645 -+ return true;
4646 -+}
4647 -+
4648 -+static boolean
4649 -+parse_daystart (const struct parser_table* entry, char **argv, int *arg_ptr)
4650 -+{
4651 -+ struct tm *local;
4652 -+
4653 -+ (void) entry;
4654 -+ (void) argv;
4655 -+ (void) arg_ptr;
4656 -+
4657 -+ if (options.full_days == false)
4658 -+ {
4659 -+ options.cur_day_start += DAYSECS;
4660 -+ local = localtime (&options.cur_day_start);
4661 -+ options.cur_day_start -= (local
4662 -+ ? (local->tm_sec + local->tm_min * 60
4663 -+ + local->tm_hour * 3600)
4664 -+ : options.cur_day_start % DAYSECS);
4665 -+ options.full_days = true;
4666 -+ }
4667 -+ return true;
4668 -+}
4669 -+
4670 -+static boolean
4671 -+parse_delete (const struct parser_table* entry, char *argv[], int *arg_ptr)
4672 -+{
4673 -+ struct predicate *our_pred;
4674 -+ (void) argv;
4675 -+ (void) arg_ptr;
4676 -+
4677 -+ our_pred = insert_primary (entry);
4678 -+ our_pred->side_effects = our_pred->no_default_print = true;
4679 -+ /* -delete implies -depth */
4680 -+ options.do_dir_first = false;
4681 -+
4682 -+ /* We do not need stat information because we check for the case
4683 -+ * (errno==EISDIR) in pred_delete.
4684 -+ */
4685 -+ our_pred->need_stat = our_pred->need_type = false;
4686 -+
4687 -+ our_pred->est_success_rate = 1.0f;
4688 -+ return true;
4689 -+}
4690 -+
4691 -+static boolean
4692 -+parse_depth (const struct parser_table* entry, char **argv, int *arg_ptr)
4693 -+{
4694 -+ (void) entry;
4695 -+ (void) argv;
4696 -+
4697 -+ options.do_dir_first = false;
4698 -+ options.explicit_depth = true;
4699 -+ return parse_noop(entry, argv, arg_ptr);
4700 -+}
4701 -+
4702 -+static boolean
4703 -+parse_d (const struct parser_table* entry, char **argv, int *arg_ptr)
4704 -+{
4705 -+ if (options.warnings)
4706 -+ {
4707 -+ error (0, 0,
4708 -+ _("warning: the -d option is deprecated; please use "
4709 -+ "-depth instead, because the latter is a "
4710 -+ "POSIX-compliant feature."));
4711 -+ }
4712 -+ return parse_depth(entry, argv, arg_ptr);
4713 -+}
4714 -+
4715 -+static boolean
4716 -+parse_empty (const struct parser_table* entry, char **argv, int *arg_ptr)
4717 -+{
4718 -+ struct predicate *our_pred;
4719 -+ (void) argv;
4720 -+ (void) arg_ptr;
4721 -+
4722 -+ our_pred = insert_primary (entry);
4723 -+ our_pred->est_success_rate = 0.01f; /* assume 1% of files are empty. */
4724 -+ return true;
4725 -+}
4726 -+
4727 -+static boolean
4728 -+parse_exec (const struct parser_table* entry, char **argv, int *arg_ptr)
4729 -+{
4730 -+ return insert_exec_ok ("-exec", entry, get_start_dirfd(), argv, arg_ptr);
4731 -+}
4732 -+
4733 -+static boolean
4734 -+parse_execdir (const struct parser_table* entry, char **argv, int *arg_ptr)
4735 -+{
4736 -+ return insert_exec_ok ("-execdir", entry, -1, argv, arg_ptr);
4737 -+}
4738 -+
4739 -+static boolean
4740 -+parse_false (const struct parser_table* entry, char **argv, int *arg_ptr)
4741 -+{
4742 -+ struct predicate *our_pred;
4743 -+
4744 -+ (void) argv;
4745 -+ (void) arg_ptr;
4746 -+
4747 -+ our_pred = insert_primary (entry);
4748 -+ our_pred->need_stat = our_pred->need_type = false;
4749 -+ our_pred->side_effects = our_pred->no_default_print = false;
4750 -+ our_pred->est_success_rate = 0.0f;
4751 -+ return true;
4752 -+}
4753 -+
4754 -+static boolean
4755 -+insert_fls (const struct parser_table* entry, const char *filename)
4756 -+{
4757 -+ struct predicate *our_pred = insert_primary (entry);
4758 -+ if (filename)
4759 -+ open_output_file (filename, &our_pred->args.printf_vec);
4760 -+ else
4761 -+ open_stdout (&our_pred->args.printf_vec);
4762 -+ our_pred->side_effects = our_pred->no_default_print = true;
4763 -+ our_pred->est_success_rate = 1.0f;
4764 -+ return true;
4765 -+}
4766 -+
4767 -+
4768 -+static boolean
4769 -+parse_fls (const struct parser_table* entry, char **argv, int *arg_ptr)
4770 -+{
4771 -+ const char *filename;
4772 -+ return collect_arg(argv, arg_ptr, &filename)
4773 -+ && insert_fls(entry, filename);
4774 -+}
4775 -+
4776 -+static boolean
4777 -+parse_follow (const struct parser_table* entry, char **argv, int *arg_ptr)
4778 -+{
4779 -+ set_follow_state(SYMLINK_ALWAYS_DEREF);
4780 -+ return parse_noop(entry, argv, arg_ptr);
4781 -+}
4782 -+
4783 -+static boolean
4784 -+parse_fprint (const struct parser_table* entry, char **argv, int *arg_ptr)
4785 -+{
4786 -+ struct predicate *our_pred;
4787 -+ const char *filename;
4788 -+ if (collect_arg(argv, arg_ptr, &filename))
4789 -+ {
4790 -+ our_pred = insert_primary (entry);
4791 -+ open_output_file (filename, &our_pred->args.printf_vec);
4792 -+ our_pred->side_effects = our_pred->no_default_print = true;
4793 -+ our_pred->need_stat = our_pred->need_type = false;
4794 -+ our_pred->est_success_rate = 1.0f;
4795 -+ return true;
4796 -+ }
4797 -+ else
4798 -+ {
4799 -+ return false;
4800 -+ }
4801 -+}
4802 -+
4803 -+static boolean
4804 -+insert_fprint(const struct parser_table* entry, const char *filename)
4805 -+{
4806 -+ struct predicate *our_pred = insert_primary (entry);
4807 -+ if (filename)
4808 -+ open_output_file (filename, &our_pred->args.printf_vec);
4809 -+ else
4810 -+ open_stdout (&our_pred->args.printf_vec);
4811 -+ our_pred->side_effects = our_pred->no_default_print = true;
4812 -+ our_pred->need_stat = our_pred->need_type = false;
4813 -+ our_pred->est_success_rate = 1.0f;
4814 -+ return true;
4815 -+}
4816 -+
4817 -+
4818 -+static boolean
4819 -+parse_fprint0 (const struct parser_table* entry, char **argv, int *arg_ptr)
4820 -+{
4821 -+ const char *filename;
4822 -+ if (collect_arg(argv, arg_ptr, &filename))
4823 -+ return insert_fprint(entry, filename);
4824 -+ else
4825 -+ return false;
4826 -+}
4827 -+
4828 -+static float estimate_fstype_success_rate(const char *fsname)
4829 -+{
4830 -+ struct stat dir_stat;
4831 -+ const char *dir = "/";
4832 -+ if (0 == stat(dir, &dir_stat))
4833 -+ {
4834 -+ const char *fstype = filesystem_type(&dir_stat, dir);
4835 -+ /* Assume most files are on the same file system type as the root fs. */
4836 -+ if (0 == strcmp(fsname, fstype))
4837 -+ return 0.7f;
4838 -+ else
4839 -+ return 0.3f;
4840 -+ }
4841 -+ return 1.0f;
4842 -+}
4843 -+
4844 -+
4845 -+static boolean
4846 -+parse_fstype (const struct parser_table* entry, char **argv, int *arg_ptr)
4847 -+{
4848 -+ const char *typename;
4849 -+ if (collect_arg(argv, arg_ptr, &typename))
4850 -+ {
4851 -+ struct predicate *our_pred = insert_primary (entry);
4852 -+ our_pred->args.str = typename;
4853 -+
4854 -+ /* This is an expensive operation, so although there are
4855 -+ * circumstances where it is selective, we ignore this fact
4856 -+ * because we probably don't want to promote this test to the
4857 -+ * front anyway.
4858 -+ */
4859 -+ our_pred->est_success_rate = estimate_fstype_success_rate(typename);
4860 -+ return true;
4861 -+ }
4862 -+ else
4863 -+ {
4864 -+ return false;
4865 -+ }
4866 -+}
4867 -+
4868 -+static boolean
4869 -+parse_gid (const struct parser_table* entry, char **argv, int *arg_ptr)
4870 -+{
4871 -+ struct predicate *p = insert_num (argv, arg_ptr, entry);
4872 -+ if (p)
4873 -+ {
4874 -+ p->est_success_rate = (p->args.numinfo.l_val < 100) ? 0.99 : 0.2;
4875 -+ return true;
4876 -+ }
4877 -+ else
4878 -+ {
4879 -+ return false;
4880 -+ }
4881 -+}
4882 -+
4883 -+
4884 -+static int
4885 -+safe_atoi (const char *s)
4886 -+{
4887 -+ long lval;
4888 -+ char *end;
4889 -+
4890 -+ errno = 0;
4891 -+ lval = strtol(s, &end, 10);
4892 -+ if ( (LONG_MAX == lval) || (LONG_MIN == lval) )
4893 -+ {
4894 -+ /* max/min possible value, or an error. */
4895 -+ if (errno == ERANGE)
4896 -+ {
4897 -+ /* too big, or too small. */
4898 -+ error(1, errno, "%s", s);
4899 -+ }
4900 -+ else
4901 -+ {
4902 -+ /* not a valid number */
4903 -+ error(1, errno, "%s", s);
4904 -+ }
4905 -+ /* Otherwise, we do a range chack against INT_MAX and INT_MIN
4906 -+ * below.
4907 -+ */
4908 -+ }
4909 -+
4910 -+ if (lval > INT_MAX || lval < INT_MIN)
4911 -+ {
4912 -+ /* The number was in range for long, but not int. */
4913 -+ errno = ERANGE;
4914 -+ error(1, errno, "%s", s);
4915 -+ }
4916 -+ else if (*end)
4917 -+ {
4918 -+ error(1, errno, "Unexpected suffix %s on %s",
4919 -+ quotearg_n_style(0, options.err_quoting_style, end),
4920 -+ quotearg_n_style(1, options.err_quoting_style, s));
4921 -+ }
4922 -+ else if (end == s)
4923 -+ {
4924 -+ error(1, errno, "Expected an integer: %s",
4925 -+ quotearg_n_style(0, options.err_quoting_style, s));
4926 -+ }
4927 -+ return (int)lval;
4928 -+}
4929 -+
4930 -+
4931 -+static boolean
4932 -+parse_group (const struct parser_table* entry, char **argv, int *arg_ptr)
4933 -+{
4934 -+ const char *groupname;
4935 -+
4936 -+ if (collect_arg(argv, arg_ptr, &groupname))
4937 -+ {
4938 -+ gid_t gid;
4939 -+ struct predicate *our_pred;
4940 -+ struct group *cur_gr = getgrnam(groupname);
4941 -+ endgrent();
4942 -+ if (cur_gr)
4943 -+ {
4944 -+ gid = cur_gr->gr_gid;
4945 -+ }
4946 -+ else
4947 -+ {
4948 -+ const int gid_len = strspn (groupname, "0123456789");
4949 -+ if (gid_len)
4950 -+ {
4951 -+ if (groupname[gid_len] == 0)
4952 -+ {
4953 -+ gid = safe_atoi (groupname);
4954 -+ }
4955 -+ else
4956 -+ {
4957 -+ /* XXX: no test in test suite for this */
4958 -+ error(1, 0, _("%1$s is not the name of an existing group and"
4959 -+ " it does not look like a numeric group ID "
4960 -+ "because it has the unexpected suffix %2$s"),
4961 -+ quotearg_n_style(0, options.err_quoting_style, groupname),
4962 -+ quotearg_n_style(1, options.err_quoting_style, groupname+gid_len));
4963 -+ return false;
4964 -+ }
4965 -+ }
4966 -+ else
4967 -+ {
4968 -+ if (*groupname)
4969 -+ {
4970 -+ /* XXX: no test in test suite for this */
4971 -+ error(1, 0, _("%s is not the name of an existing group"),
4972 -+ quotearg_n_style(0, options.err_quoting_style, groupname));
4973 -+ }
4974 -+ else
4975 -+ {
4976 -+ error(1, 0, _("argument to -group is empty, but should be a group name"));
4977 -+ }
4978 -+ return false;
4979 -+ }
4980 -+ }
4981 -+ our_pred = insert_primary (entry);
4982 -+ our_pred->args.gid = gid;
4983 -+ our_pred->est_success_rate = (our_pred->args.numinfo.l_val < 100) ? 0.99 : 0.2;
4984 -+ return true;
4985 -+ }
4986 -+ return false;
4987 -+}
4988 -+
4989 -+static boolean
4990 -+parse_help (const struct parser_table* entry, char **argv, int *arg_ptr)
4991 -+{
4992 -+ (void) entry;
4993 -+ (void) argv;
4994 -+ (void) arg_ptr;
4995 -+
4996 -+ usage(stdout, 0, NULL);
4997 -+ puts (_("\n\
4998 -+default path is the current directory; default expression is -print\n\
4999 -+expression may consist of: operators, options, tests, and actions:\n"));
5000 -+ puts (_("\
5001 -+operators (decreasing precedence; -and is implicit where no others are given):\n\
5002 -+ ( EXPR ) ! EXPR -not EXPR EXPR1 -a EXPR2 EXPR1 -and EXPR2\n\
5003 -+ EXPR1 -o EXPR2 EXPR1 -or EXPR2 EXPR1 , EXPR2\n"));
5004 -+ puts (_("\
5005 -+positional options (always true): -daystart -follow -regextype\n\n\
5006 -+normal options (always true, specified before other expressions):\n\
5007 -+ -depth --help -maxdepth LEVELS -mindepth LEVELS -mount -noleaf\n\
5008 -+ --version -xdev -ignore_readdir_race -noignore_readdir_race\n"));
5009 -+ puts (_("\
5010 -+tests (N can be +N or -N or N): -amin N -anewer FILE -atime N -cmin N\n\
5011 -+ -cnewer FILE -ctime N -empty -false -fstype TYPE -gid N -group NAME\n\
5012 -+ -ilname PATTERN -iname PATTERN -inum N -iwholename PATTERN -iregex PATTERN\n\
5013 -+ -links N -lname PATTERN -mmin N -mtime N -name PATTERN -newer FILE"));
5014 -+ puts (_("\
5015 -+ -nouser -nogroup -path PATTERN -perm [+-]MODE -regex PATTERN\n\
5016 -+ -readable -writable -executable\n\
5017 -+ -wholename PATTERN -size N[bcwkMG] -true -type [bcdpflsD] -uid N\n\
5018 -+ -used N -user NAME -xtype [bcdpfls]\n"));
5019 -+ puts (_("\
5020 -+actions: -delete -print0 -printf FORMAT -fprintf FILE FORMAT -print \n\
5021 -+ -fprint0 FILE -fprint FILE -ls -fls FILE -prune -quit\n\
5022 -+ -exec COMMAND ; -exec COMMAND {} + -ok COMMAND ;\n\
5023 -+ -execdir COMMAND ; -execdir COMMAND {} + -okdir COMMAND ;\n\
5024 -+"));
5025 -+ puts (_("Report (and track progress on fixing) bugs via the findutils bug-reporting\n\
5026 -+page at http://savannah.gnu.org/ or, if you have no web access, by sending\n\
5027 -+email to <bug-findutils@×××.org>."));
5028 -+ exit (0);
5029 -+}
5030 -+
5031 -+static float
5032 -+estimate_pattern_match_rate(const char *pattern, int is_regex)
5033 -+{
5034 -+ if (strpbrk(pattern, "*?[") || (is_regex && strpbrk(pattern, ".")))
5035 -+ {
5036 -+ /* A wildcard; assume the pattern matches most files. */
5037 -+ return 0.8f;
5038 -+ }
5039 -+ else
5040 -+ {
5041 -+ return 0.1f;
5042 -+ }
5043 -+}
5044 -+
5045 -+static boolean
5046 -+parse_ilname (const struct parser_table* entry, char **argv, int *arg_ptr)
5047 -+{
5048 -+ const char *name;
5049 -+ if (collect_arg(argv, arg_ptr, &name))
5050 -+ {
5051 -+ struct predicate *our_pred = insert_primary (entry);
5052 -+ our_pred->args.str = name;
5053 -+ /* Use the generic glob pattern estimator to figure out how many
5054 -+ * links will match, but bear in mind that most files won't be links.
5055 -+ */
5056 -+ our_pred->est_success_rate = 0.1 * estimate_pattern_match_rate(name, 0);
5057 -+ return true;
5058 -+ }
5059 -+ else
5060 -+ {
5061 -+ return false;
5062 -+ }
5063 -+}
5064 -+
5065 -+
5066 -+/* sanity check the fnmatch() function to make sure that case folding
5067 -+ * is supported (as opposed to just having the flag ignored).
5068 -+ */
5069 -+static boolean
5070 -+fnmatch_sanitycheck(void)
5071 -+{
5072 -+ static boolean checked = false;
5073 -+ if (!checked)
5074 -+ {
5075 -+ if (0 != fnmatch("foo", "foo", 0)
5076 -+ || 0 == fnmatch("Foo", "foo", 0)
5077 -+ || 0 != fnmatch("Foo", "foo", FNM_CASEFOLD))
5078 -+ {
5079 -+ error (1, 0, _("sanity check of the fnmatch() library function failed."));
5080 -+ return false;
5081 -+ }
5082 -+ checked = true;
5083 -+ }
5084 -+ return checked;
5085 -+}
5086 -+
5087 -+
5088 -+static boolean
5089 -+check_name_arg(const char *pred, const char *arg)
5090 -+{
5091 -+ if (options.warnings && strchr(arg, '/'))
5092 -+ {
5093 -+ error(0, 0,_("warning: Unix filenames usually don't contain slashes "
5094 -+ "(though pathnames do). That means that '%s %s' will "
5095 -+ "probably evaluate to false all the time on this system. "
5096 -+ "You might find the '-wholename' test more useful, or "
5097 -+ "perhaps '-samefile'. Alternatively, if you are using "
5098 -+ "GNU grep, you could "
5099 -+ "use 'find ... -print0 | grep -FzZ %s'."),
5100 -+ pred,
5101 -+ safely_quote_err_filename(0, arg),
5102 -+ safely_quote_err_filename(1, arg));
5103 -+ }
5104 -+ return true; /* allow it anyway */
5105 -+}
5106 -+
5107 -+
5108 -+
5109 -+static boolean
5110 -+parse_iname (const struct parser_table* entry, char **argv, int *arg_ptr)
5111 -+{
5112 -+ const char *name;
5113 -+ fnmatch_sanitycheck();
5114 -+ if (collect_arg(argv, arg_ptr, &name))
5115 -+ {
5116 -+ if (check_name_arg("-iname", name))
5117 -+ {
5118 -+ struct predicate *our_pred = insert_primary (entry);
5119 -+ our_pred->need_stat = our_pred->need_type = false;
5120 -+ our_pred->args.str = name;
5121 -+ our_pred->est_success_rate = estimate_pattern_match_rate(name, 0);
5122 -+ return true;
5123 -+ }
5124 -+ }
5125 -+ return false;
5126 -+}
5127 -+
5128 -+static boolean
5129 -+parse_inum (const struct parser_table* entry, char **argv, int *arg_ptr)
5130 -+{
5131 -+ struct predicate *p = insert_num (argv, arg_ptr, entry);
5132 -+ if (p)
5133 -+ {
5134 -+ /* inode number is exact match only, so very low proportions of
5135 -+ * files match
5136 -+ */
5137 -+ p->est_success_rate = 1e-6;
5138 -+ return true;
5139 -+ }
5140 -+ else
5141 -+ {
5142 -+ return false;
5143 -+ }
5144 -+}
5145 -+
5146 -+/* -ipath is deprecated (at RMS's request) in favour of
5147 -+ * -iwholename. See the node "GNU Manuals" in standards.texi
5148 -+ * for the rationale for this (basically, GNU prefers the use
5149 -+ * of the phrase "file name" to "path name"
5150 -+ */
5151 -+static boolean
5152 -+parse_ipath (const struct parser_table* entry, char **argv, int *arg_ptr)
5153 -+{
5154 -+ const char *name;
5155 -+
5156 -+ fnmatch_sanitycheck ();
5157 -+ if (collect_arg (argv, arg_ptr, &name))
5158 -+ {
5159 -+ struct predicate *our_pred = insert_primary_withpred (entry, pred_ipath);
5160 -+ our_pred->need_stat = our_pred->need_type = false;
5161 -+ our_pred->args.str = name;
5162 -+ our_pred->est_success_rate = estimate_pattern_match_rate (name, 0);
5163 -+ return true;
5164 -+ }
5165 -+ return false;
5166 -+}
5167 -+
5168 -+static boolean
5169 -+parse_iwholename (const struct parser_table* entry, char **argv, int *arg_ptr)
5170 -+{
5171 -+ return parse_ipath (entry, argv, arg_ptr);
5172 -+}
5173 -+
5174 -+static boolean
5175 -+parse_iregex (const struct parser_table* entry, char **argv, int *arg_ptr)
5176 -+{
5177 -+ return insert_regex (argv, arg_ptr, entry, RE_ICASE|options.regex_options);
5178 -+}
5179 -+
5180 -+static boolean
5181 -+parse_links (const struct parser_table* entry, char **argv, int *arg_ptr)
5182 -+{
5183 -+ struct predicate *p = insert_num (argv, arg_ptr, entry);
5184 -+ if (p)
5185 -+ {
5186 -+ if (p->args.numinfo.l_val == 1)
5187 -+ p->est_success_rate = 0.99;
5188 -+ else if (p->args.numinfo.l_val == 2)
5189 -+ p->est_success_rate = 0.01;
5190 -+ else
5191 -+ p->est_success_rate = 1e-3;
5192 -+ return true;
5193 -+ }
5194 -+ else
5195 -+ {
5196 -+ return false;
5197 -+ }
5198 -+}
5199 -+
5200 -+static boolean
5201 -+parse_lname (const struct parser_table* entry, char **argv, int *arg_ptr)
5202 -+{
5203 -+ const char *name;
5204 -+ fnmatch_sanitycheck();
5205 -+ if (collect_arg(argv, arg_ptr, &name))
5206 -+ {
5207 -+ struct predicate *our_pred = insert_primary (entry);
5208 -+ our_pred->args.str = name;
5209 -+ our_pred->est_success_rate = 0.1 * estimate_pattern_match_rate(name, 0);
5210 -+ return true;
5211 -+ }
5212 -+ return false;
5213 -+}
5214 -+
5215 -+static boolean
5216 -+parse_ls (const struct parser_table* entry, char **argv, int *arg_ptr)
5217 -+{
5218 -+ (void) &argv;
5219 -+ (void) &arg_ptr;
5220 -+ return insert_fls(entry, NULL);
5221 -+}
5222 -+
5223 -+static boolean
5224 -+insert_depthspec(const struct parser_table* entry, char **argv, int *arg_ptr,
5225 -+ int *limitptr)
5226 -+{
5227 -+ const char *depthstr;
5228 -+ int depth_len;
5229 -+ const char *predicate = argv[(*arg_ptr)-1];
5230 -+ if (collect_arg(argv, arg_ptr, &depthstr))
5231 -+ {
5232 -+ depth_len = strspn (depthstr, "0123456789");
5233 -+ if ((depth_len > 0) && (depthstr[depth_len] == 0))
5234 -+ {
5235 -+ (*limitptr) = safe_atoi (depthstr);
5236 -+ if (*limitptr >= 0)
5237 -+ {
5238 -+ return parse_noop(entry, argv, arg_ptr);
5239 -+ }
5240 -+ }
5241 -+ error(1, 0, _("Expected a positive decimal integer argument to %1$s, but got %2$s"),
5242 -+ predicate,
5243 -+ quotearg_n_style(0, options.err_quoting_style, depthstr));
5244 -+ return false;
5245 -+ }
5246 -+ /* missing argument */
5247 -+ return false;
5248 -+}
5249 -+
5250 -+
5251 -+static boolean
5252 -+parse_maxdepth (const struct parser_table* entry, char **argv, int *arg_ptr)
5253 -+{
5254 -+ return insert_depthspec(entry, argv, arg_ptr, &options.maxdepth);
5255 -+}
5256 -+
5257 -+static boolean
5258 -+parse_mindepth (const struct parser_table* entry, char **argv, int *arg_ptr)
5259 -+{
5260 -+ return insert_depthspec(entry, argv, arg_ptr, &options.mindepth);
5261 -+}
5262 -+
5263 -+
5264 -+static boolean
5265 -+do_parse_xmin (const struct parser_table* entry,
5266 -+ char **argv,
5267 -+ int *arg_ptr,
5268 -+ enum xval xv)
5269 -+{
5270 -+ const char *minutes;
5271 -+
5272 -+ if (collect_arg(argv, arg_ptr, &minutes))
5273 -+ {
5274 -+ struct time_val tval;
5275 -+ tval.xval = xv;
5276 -+ if (get_relative_timestamp(minutes, &tval,
5277 -+ options.cur_day_start + DAYSECS, 60,
5278 -+ "arithmetic overflow while converting %s "
5279 -+ "minutes to a number of seconds"))
5280 -+ {
5281 -+ struct predicate *our_pred = insert_primary (entry);
5282 -+ our_pred->args.reftime = tval;
5283 -+ our_pred->est_success_rate = estimate_timestamp_success_rate(tval.ts.tv_sec);
5284 -+ return true;
5285 -+ }
5286 -+ }
5287 -+ return false;
5288 -+}
5289 -+static boolean
5290 -+parse_amin (const struct parser_table* entry, char **argv, int *arg_ptr)
5291 -+{
5292 -+ return do_parse_xmin(entry, argv, arg_ptr, XVAL_ATIME);
5293 -+}
5294 -+
5295 -+static boolean
5296 -+parse_cmin (const struct parser_table* entry, char **argv, int *arg_ptr)
5297 -+{
5298 -+ return do_parse_xmin(entry, argv, arg_ptr, XVAL_CTIME);
5299 -+}
5300 -+
5301 -+
5302 -+static boolean
5303 -+parse_mmin (const struct parser_table* entry, char **argv, int *arg_ptr)
5304 -+{
5305 -+ return do_parse_xmin(entry, argv, arg_ptr, XVAL_MTIME);
5306 -+}
5307 -+
5308 -+static boolean
5309 -+parse_name (const struct parser_table* entry, char **argv, int *arg_ptr)
5310 -+{
5311 -+ const char *name;
5312 -+ if (collect_arg(argv, arg_ptr, &name))
5313 -+ {
5314 -+ fnmatch_sanitycheck();
5315 -+ if (check_name_arg("-name", name))
5316 -+ {
5317 -+ struct predicate *our_pred = insert_primary (entry);
5318 -+ our_pred->need_stat = our_pred->need_type = false;
5319 -+ our_pred->args.str = name;
5320 -+ our_pred->est_success_rate = estimate_pattern_match_rate(name, 0);
5321 -+ return true;
5322 -+ }
5323 -+ }
5324 -+ return false;
5325 -+}
5326 -+
5327 -+static boolean
5328 -+parse_negate (const struct parser_table* entry, char **argv, int *arg_ptr)
5329 -+{
5330 -+ struct predicate *our_pred;
5331 -+
5332 -+ (void) &argv;
5333 -+ (void) &arg_ptr;
5334 -+
5335 -+ our_pred = get_new_pred_chk_op (entry);
5336 -+ our_pred->pred_func = pred_negate;
5337 -+ our_pred->p_type = UNI_OP;
5338 -+ our_pred->p_prec = NEGATE_PREC;
5339 -+ our_pred->need_stat = our_pred->need_type = false;
5340 -+ return true;
5341 -+}
5342 -+
5343 -+static boolean
5344 -+parse_newer (const struct parser_table* entry, char **argv, int *arg_ptr)
5345 -+{
5346 -+ struct predicate *our_pred;
5347 -+ struct stat stat_newer;
5348 -+
5349 -+ set_stat_placeholders(&stat_newer);
5350 -+ if (collect_arg_stat_info(argv, arg_ptr, &stat_newer))
5351 -+ {
5352 -+ our_pred = insert_primary (entry);
5353 -+ our_pred->args.reftime.ts = get_stat_mtime(&stat_newer);
5354 -+ our_pred->args.reftime.xval = XVAL_MTIME;
5355 -+ our_pred->args.reftime.kind = COMP_GT;
5356 -+ our_pred->est_success_rate = estimate_timestamp_success_rate(stat_newer.st_mtime);
5357 -+ return true;
5358 -+ }
5359 -+ return false;
5360 -+}
5361 -+
5362 -+
5363 -+static boolean
5364 -+parse_newerXY (const struct parser_table* entry, char **argv, int *arg_ptr)
5365 -+{
5366 -+ (void) argv;
5367 -+ (void) arg_ptr;
5368 -+
5369 -+ if ((argv == NULL) || (argv[*arg_ptr] == NULL))
5370 -+ {
5371 -+ return false;
5372 -+ }
5373 -+ else if (8u != strlen(argv[*arg_ptr]))
5374 -+ {
5375 -+ return false;
5376 -+ }
5377 -+ else
5378 -+ {
5379 -+ char x, y;
5380 -+ const char validchars[] = "aBcmt";
5381 -+
5382 -+ assert (0 == strncmp("-newer", argv[*arg_ptr], 6));
5383 -+ x = argv[*arg_ptr][6];
5384 -+ y = argv[*arg_ptr][7];
5385 -+
5386 -+
5387 -+#if !defined(HAVE_STRUCT_STAT_ST_BIRTHTIME) && !defined(HAVE_STRUCT_STAT_ST_BIRTHTIMENSEC) && !defined(HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC_TV_NSEC)
5388 -+ if ('B' == x || 'B' == y)
5389 -+ {
5390 -+ error(0, 0,
5391 -+ _("This system does not provide a way to find the birth time of a file."));
5392 -+ return 0;
5393 -+ }
5394 -+#endif
5395 -+
5396 -+ /* -newertY (for any Y) is invalid. */
5397 -+ if (x == 't'
5398 -+ || 0 == strchr(validchars, x)
5399 -+ || 0 == strchr( validchars, y))
5400 -+ {
5401 -+ return false;
5402 -+ }
5403 -+ else
5404 -+ {
5405 -+ struct predicate *our_pred;
5406 -+
5407 -+ /* Because this item is ARG_SPECIAL_PARSE, we have to advance arg_ptr
5408 -+ * past the test name (for most other tests, this is already done)
5409 -+ */
5410 -+ (*arg_ptr)++;
5411 -+
5412 -+ our_pred = insert_primary (entry);
5413 -+
5414 -+
5415 -+ switch (x)
5416 -+ {
5417 -+ case 'a':
5418 -+ our_pred->args.reftime.xval = XVAL_ATIME;
5419 -+ break;
5420 -+ case 'B':
5421 -+ our_pred->args.reftime.xval = XVAL_BIRTHTIME;
5422 -+ break;
5423 -+ case 'c':
5424 -+ our_pred->args.reftime.xval = XVAL_CTIME;
5425 -+ break;
5426 -+ case 'm':
5427 -+ our_pred->args.reftime.xval = XVAL_MTIME;
5428 -+ break;
5429 -+ default:
5430 -+ assert (strchr(validchars, x));
5431 -+ assert (0);
5432 -+ }
5433 -+
5434 -+ if ('t' == y)
5435 -+ {
5436 -+ if (!get_date(&our_pred->args.reftime.ts,
5437 -+ argv[*arg_ptr],
5438 -+ &options.start_time))
5439 -+ {
5440 -+ error(1, 0,
5441 -+ _("I cannot figure out how to interpret %s as a date or time"),
5442 -+ quotearg_n_style(0, options.err_quoting_style, argv[*arg_ptr]));
5443 -+ }
5444 -+ }
5445 -+ else
5446 -+ {
5447 -+ struct stat stat_newer;
5448 -+
5449 -+ /* Stat the named file. */
5450 -+ set_stat_placeholders(&stat_newer);
5451 -+ if ((*options.xstat) (argv[*arg_ptr], &stat_newer))
5452 -+ fatal_file_error(argv[*arg_ptr]);
5453 -+
5454 -+ if (!get_stat_Ytime(&stat_newer, y, &our_pred->args.reftime.ts))
5455 -+ {
5456 -+ /* We cannot extract a timestamp from the struct stat. */
5457 -+ error(1, 0, _("Cannot obtain birth time of file %s"),
5458 -+ safely_quote_err_filename(0, argv[*arg_ptr]));
5459 -+ }
5460 -+ }
5461 -+ our_pred->args.reftime.kind = COMP_GT;
5462 -+ our_pred->est_success_rate = estimate_timestamp_success_rate(our_pred->args.reftime.ts.tv_sec);
5463 -+ (*arg_ptr)++;
5464 -+
5465 -+ assert (our_pred->pred_func != NULL);
5466 -+ assert (our_pred->pred_func == pred_newerXY);
5467 -+ assert (our_pred->need_stat);
5468 -+ return true;
5469 -+ }
5470 -+ }
5471 -+}
5472 -+
5473 -+
5474 -+static boolean
5475 -+parse_noleaf (const struct parser_table* entry, char **argv, int *arg_ptr)
5476 -+{
5477 -+ options.no_leaf_check = true;
5478 -+ return parse_noop(entry, argv, arg_ptr);
5479 -+}
5480 -+
5481 -+#ifdef CACHE_IDS
5482 -+/* Arbitrary amount by which to increase size
5483 -+ of `uid_unused' and `gid_unused'. */
5484 -+#define ALLOC_STEP 2048
5485 -+
5486 -+/* Boolean: if uid_unused[n] is nonzero, then UID n has no passwd entry. */
5487 -+char *uid_unused = NULL;
5488 -+
5489 -+/* Number of elements in `uid_unused'. */
5490 -+unsigned uid_allocated;
5491 -+
5492 -+/* Similar for GIDs and group entries. */
5493 -+char *gid_unused = NULL;
5494 -+unsigned gid_allocated;
5495 -+#endif
5496 -+
5497 -+static boolean
5498 -+parse_nogroup (const struct parser_table* entry, char **argv, int *arg_ptr)
5499 -+{
5500 -+ struct predicate *our_pred;
5501 -+
5502 -+ (void) &argv;
5503 -+ (void) &arg_ptr;
5504 -+
5505 -+ our_pred = insert_primary (entry);
5506 -+ our_pred->est_success_rate = 1e-4;
5507 -+#ifdef CACHE_IDS
5508 -+ if (gid_unused == NULL)
5509 -+ {
5510 -+ struct group *gr;
5511 -+
5512 -+ gid_allocated = ALLOC_STEP;
5513 -+ gid_unused = xmalloc (gid_allocated);
5514 -+ memset (gid_unused, 1, gid_allocated);
5515 -+ setgrent ();
5516 -+ while ((gr = getgrent ()) != NULL)
5517 -+ {
5518 -+ if ((unsigned) gr->gr_gid >= gid_allocated)
5519 -+ {
5520 -+ unsigned new_allocated = (unsigned) gr->gr_gid + ALLOC_STEP;
5521 -+ gid_unused = xrealloc (gid_unused, new_allocated);
5522 -+ memset (gid_unused + gid_allocated, 1,
5523 -+ new_allocated - gid_allocated);
5524 -+ gid_allocated = new_allocated;
5525 -+ }
5526 -+ gid_unused[(unsigned) gr->gr_gid] = 0;
5527 -+ }
5528 -+ endgrent ();
5529 -+ }
5530 -+#endif
5531 -+ return true;
5532 -+}
5533 -+
5534 -+static boolean
5535 -+parse_nouser (const struct parser_table* entry, char **argv, int *arg_ptr)
5536 -+{
5537 -+ struct predicate *our_pred;
5538 -+ (void) argv;
5539 -+ (void) arg_ptr;
5540 -+
5541 -+
5542 -+ our_pred = insert_primary (entry);
5543 -+ our_pred->est_success_rate = 1e-3;
5544 -+#ifdef CACHE_IDS
5545 -+ if (uid_unused == NULL)
5546 -+ {
5547 -+ struct passwd *pw;
5548 -+
5549 -+ uid_allocated = ALLOC_STEP;
5550 -+ uid_unused = xmalloc (uid_allocated);
5551 -+ memset (uid_unused, 1, uid_allocated);
5552 -+ setpwent ();
5553 -+ while ((pw = getpwent ()) != NULL)
5554 -+ {
5555 -+ if ((unsigned) pw->pw_uid >= uid_allocated)
5556 -+ {
5557 -+ unsigned new_allocated = (unsigned) pw->pw_uid + ALLOC_STEP;
5558 -+ uid_unused = xrealloc (uid_unused, new_allocated);
5559 -+ memset (uid_unused + uid_allocated, 1,
5560 -+ new_allocated - uid_allocated);
5561 -+ uid_allocated = new_allocated;
5562 -+ }
5563 -+ uid_unused[(unsigned) pw->pw_uid] = 0;
5564 -+ }
5565 -+ endpwent ();
5566 -+ }
5567 -+#endif
5568 -+ return true;
5569 -+}
5570 -+
5571 -+static boolean
5572 -+parse_nowarn (const struct parser_table* entry, char **argv, int *arg_ptr)
5573 -+{
5574 -+ options.warnings = false;
5575 -+ return parse_noop(entry, argv, arg_ptr);
5576 -+}
5577 -+
5578 -+static boolean
5579 -+parse_ok (const struct parser_table* entry, char **argv, int *arg_ptr)
5580 -+{
5581 -+ return insert_exec_ok ("-ok", entry, get_start_dirfd(), argv, arg_ptr);
5582 -+}
5583 -+
5584 -+static boolean
5585 -+parse_okdir (const struct parser_table* entry, char **argv, int *arg_ptr)
5586 -+{
5587 -+ return insert_exec_ok ("-okdir", entry, -1, argv, arg_ptr);
5588 -+}
5589 -+
5590 -+boolean
5591 -+parse_openparen (const struct parser_table* entry, char **argv, int *arg_ptr)
5592 -+{
5593 -+ struct predicate *our_pred;
5594 -+
5595 -+ (void) argv;
5596 -+ (void) arg_ptr;
5597 -+
5598 -+ our_pred = get_new_pred_chk_op (entry);
5599 -+ our_pred->pred_func = pred_openparen;
5600 -+ our_pred->p_type = OPEN_PAREN;
5601 -+ our_pred->p_prec = NO_PREC;
5602 -+ our_pred->need_stat = our_pred->need_type = false;
5603 -+ return true;
5604 -+}
5605 -+
5606 -+static boolean
5607 -+parse_or (const struct parser_table* entry, char **argv, int *arg_ptr)
5608 -+{
5609 -+ struct predicate *our_pred;
5610 -+
5611 -+ (void) argv;
5612 -+ (void) arg_ptr;
5613 -+
5614 -+ our_pred = get_new_pred (entry);
5615 -+ our_pred->pred_func = pred_or;
5616 -+ our_pred->p_type = BI_OP;
5617 -+ our_pred->p_prec = OR_PREC;
5618 -+ our_pred->need_stat = our_pred->need_type = false;
5619 -+ return true;
5620 -+}
5621 -+
5622 -+/* For some time, -path was deprecated (at RMS's request) in favour of
5623 -+ * -iwholename. See the node "GNU Manuals" in standards.texi for the
5624 -+ * rationale for this (basically, GNU prefers the use of the phrase
5625 -+ * "file name" to "path name".
5626 -+ *
5627 -+ * We do not issue a warning that this usage is deprecated
5628 -+ * since
5629 -+ * (a) HPUX find supports this predicate also and
5630 -+ * (b) it will soon be in POSIX anyway.
5631 -+ */
5632 -+static boolean
5633 -+parse_path (const struct parser_table* entry, char **argv, int *arg_ptr)
5634 -+{
5635 -+ const char *name;
5636 -+ if (collect_arg(argv, arg_ptr, &name))
5637 -+ {
5638 -+ struct predicate *our_pred = insert_primary_withpred (entry, pred_path);
5639 -+ our_pred->need_stat = our_pred->need_type = false;
5640 -+ our_pred->args.str = name;
5641 -+ our_pred->est_success_rate = estimate_pattern_match_rate (name, 0);
5642 -+ return true;
5643 -+ }
5644 -+ return false;
5645 -+}
5646 -+
5647 -+static boolean
5648 -+parse_wholename (const struct parser_table* entry, char **argv, int *arg_ptr)
5649 -+{
5650 -+ return parse_path (entry, argv, arg_ptr);
5651 -+}
5652 -+
5653 -+static void
5654 -+non_posix_mode(const char *mode)
5655 -+{
5656 -+ if (options.posixly_correct)
5657 -+ {
5658 -+ error (1, 0, _("Mode %s is not valid when POSIXLY_CORRECT is on."),
5659 -+ quotearg_n_style(0, options.err_quoting_style, mode));
5660 -+ }
5661 -+}
5662 -+
5663 -+
5664 -+static boolean
5665 -+parse_perm (const struct parser_table* entry, char **argv, int *arg_ptr)
5666 -+{
5667 -+ mode_t perm_val[2];
5668 -+ float rate;
5669 -+ int mode_start = 0;
5670 -+ boolean havekind = false;
5671 -+ enum permissions_type kind = PERM_EXACT;
5672 -+ struct mode_change *change = NULL;
5673 -+ struct predicate *our_pred;
5674 -+ const char *perm_expr;
5675 -+
5676 -+ if (!collect_arg(argv, arg_ptr, &perm_expr))
5677 -+ return false;
5678 -+
5679 -+ switch (perm_expr[0])
5680 -+ {
5681 -+ case '-':
5682 -+ mode_start = 1;
5683 -+ kind = PERM_AT_LEAST;
5684 -+ havekind = true;
5685 -+ rate = 0.2;
5686 -+ break;
5687 -+
5688 -+ case '+':
5689 -+ change = mode_compile (perm_expr);
5690 -+ if (NULL == change)
5691 -+ {
5692 -+ /* Most likely the caller is an old script that is still
5693 -+ * using the obsolete GNU syntax '-perm +MODE'. This old
5694 -+ * syntax was withdrawn in favor of '-perm /MODE' because
5695 -+ * it is incompatible with POSIX in some cases, but we
5696 -+ * still support uses of it that are not incompatible with
5697 -+ * POSIX.
5698 -+ *
5699 -+ * Example: POSIXLY_CORRECT=y find -perm +a+x
5700 -+ */
5701 -+ non_posix_mode(perm_expr);
5702 -+
5703 -+ /* support the previous behaviour. */
5704 -+ mode_start = 1;
5705 -+ kind = PERM_ANY;
5706 -+ rate = 0.3;
5707 -+ }
5708 -+ else
5709 -+ {
5710 -+ /* This is a POSIX-compatible usage */
5711 -+ mode_start = 0;
5712 -+ kind = PERM_EXACT;
5713 -+ rate = 0.1;
5714 -+ }
5715 -+ havekind = true;
5716 -+ break;
5717 -+
5718 -+ case '/': /* GNU extension */
5719 -+ non_posix_mode(perm_expr);
5720 -+ mode_start = 1;
5721 -+ kind = PERM_ANY;
5722 -+ havekind = true;
5723 -+ rate = 0.3;
5724 -+ break;
5725 -+
5726 -+ default:
5727 -+ /* For example, '-perm 0644', which is valid and matches
5728 -+ * only files whose mode is exactly 0644.
5729 -+ */
5730 -+ mode_start = 0;
5731 -+ kind = PERM_EXACT;
5732 -+ havekind = true;
5733 -+ rate = 0.01;
5734 -+ break;
5735 -+ }
5736 -+
5737 -+ if (NULL == change)
5738 -+ {
5739 -+ change = mode_compile (perm_expr + mode_start);
5740 -+ if (NULL == change)
5741 -+ error (1, 0, _("invalid mode %s"
5742 -+ /* TRANSLATORS: the argument is a
5743 -+ * file permission string like 'u=rw,go='
5744 -+ */),
5745 -+ quotearg_n_style(0, options.err_quoting_style, perm_expr));
5746 -+ }
5747 -+ perm_val[0] = mode_adjust (0, false, 0, change, NULL);
5748 -+ perm_val[1] = mode_adjust (0, true, 0, change, NULL);
5749 -+ free (change);
5750 -+
5751 -+ if (('/' == perm_expr[0]) && (0 == perm_val[0]) && (0 == perm_val[1]))
5752 -+ {
5753 -+ /* The meaning of -perm /000 will change in the future. It
5754 -+ * currently matches no files, but like -perm -000 it should
5755 -+ * match all files.
5756 -+ *
5757 -+ * Starting in 2005, we used to issue a warning message
5758 -+ * informing the user that the behaviour would change in the
5759 -+ * future. We have now changed the behaviour and issue a
5760 -+ * warning message that the behaviour recently changed.
5761 -+ */
5762 -+ error (0, 0,
5763 -+ _("warning: you have specified a mode pattern %s (which is "
5764 -+ "equivalent to /000). The meaning of -perm /000 has now been "
5765 -+ "changed to be consistent with -perm -000; that is, while it "
5766 -+ "used to match no files, it now matches all files."),
5767 -+ perm_expr);
5768 -+
5769 -+ kind = PERM_AT_LEAST;
5770 -+ havekind = true;
5771 -+
5772 -+ /* The "magic" number below is just the fraction of files on my
5773 -+ * own system that "-type l -xtype l" fails for (i.e. unbroken symlinks).
5774 -+ * Actual totals are 1472 and 1073833.
5775 -+ */
5776 -+ rate = 0.9986; /* probably matches anything but a broken symlink */
5777 -+ }
5778 -+
5779 -+ our_pred = insert_primary (entry);
5780 -+ our_pred->est_success_rate = rate;
5781 -+ if (havekind)
5782 -+ {
5783 -+ our_pred->args.perm.kind = kind;
5784 -+ }
5785 -+ else
5786 -+ {
5787 -+
5788 -+ switch (perm_expr[0])
5789 -+ {
5790 -+ case '-':
5791 -+ our_pred->args.perm.kind = PERM_AT_LEAST;
5792 -+ break;
5793 -+ case '+':
5794 -+ our_pred->args.perm.kind = PERM_ANY;
5795 -+ break;
5796 -+ default:
5797 -+ our_pred->args.perm.kind = PERM_EXACT;
5798 -+ break;
5799 -+ }
5800 -+ }
5801 -+ memcpy (our_pred->args.perm.val, perm_val, sizeof perm_val);
5802 -+ return true;
5803 -+}
5804 -+
5805 -+boolean
5806 -+parse_print (const struct parser_table* entry, char **argv, int *arg_ptr)
5807 -+{
5808 -+ struct predicate *our_pred;
5809 -+
5810 -+ (void) argv;
5811 -+ (void) arg_ptr;
5812 -+
5813 -+ our_pred = insert_primary (entry);
5814 -+ /* -print has the side effect of printing. This prevents us
5815 -+ from doing undesired multiple printing when the user has
5816 -+ already specified -print. */
5817 -+ our_pred->side_effects = our_pred->no_default_print = true;
5818 -+ our_pred->need_stat = our_pred->need_type = false;
5819 -+ open_stdout(&our_pred->args.printf_vec);
5820 -+ return true;
5821 -+}
5822 -+
5823 -+static boolean
5824 -+parse_print0 (const struct parser_table* entry, char **argv, int *arg_ptr)
5825 -+{
5826 -+ return insert_fprint(entry, NULL);
5827 -+}
5828 -+
5829 -+static boolean
5830 -+parse_printf (const struct parser_table* entry, char **argv, int *arg_ptr)
5831 -+{
5832 -+ const char *format;
5833 -+ if (collect_arg(argv, arg_ptr, &format))
5834 -+ {
5835 -+ struct format_val fmt;
5836 -+ open_stdout(&fmt);
5837 -+ return insert_fprintf (&fmt, entry, pred_fprintf, format);
5838 -+ }
5839 -+ return false;
5840 -+}
5841 -+
5842 -+static boolean
5843 -+parse_fprintf (const struct parser_table* entry, char **argv, int *arg_ptr)
5844 -+{
5845 -+ const char *format, *filename;
5846 -+ if (collect_arg(argv, arg_ptr, &filename))
5847 -+ {
5848 -+ if (collect_arg(argv, arg_ptr, &format))
5849 -+ {
5850 -+ struct format_val fmt;
5851 -+ open_output_file (filename, &fmt);
5852 -+ return insert_fprintf (&fmt, entry, pred_fprintf, format);
5853 -+ }
5854 -+ }
5855 -+ return false;
5856 -+}
5857 -+
5858 -+static boolean
5859 -+parse_prune (const struct parser_table* entry, char **argv, int *arg_ptr)
5860 -+{
5861 -+ struct predicate *our_pred;
5862 -+
5863 -+ (void) argv;
5864 -+ (void) arg_ptr;
5865 -+
5866 -+ our_pred = insert_primary (entry);
5867 -+ our_pred->need_stat = our_pred->need_type = false;
5868 -+ /* -prune has a side effect that it does not descend into
5869 -+ the current directory. */
5870 -+ our_pred->side_effects = true;
5871 -+ our_pred->no_default_print = false;
5872 -+ return true;
5873 -+}
5874 -+
5875 -+static boolean
5876 -+parse_quit (const struct parser_table* entry, char **argv, int *arg_ptr)
5877 -+{
5878 -+ struct predicate *our_pred = insert_primary (entry);
5879 -+ (void) argv;
5880 -+ (void) arg_ptr;
5881 -+ our_pred->need_stat = our_pred->need_type = false;
5882 -+ our_pred->side_effects = true; /* Exiting is a side effect... */
5883 -+ our_pred->no_default_print = false; /* Don't inhibit the default print, though. */
5884 -+ our_pred->est_success_rate = 1.0f;
5885 -+ return true;
5886 -+}
5887 -+
5888 -+
5889 -+static boolean
5890 -+parse_regextype (const struct parser_table* entry, char **argv, int *arg_ptr)
5891 -+{
5892 -+ const char *type_name;
5893 -+ if (collect_arg(argv, arg_ptr, &type_name))
5894 -+ {
5895 -+ /* collect the regex type name */
5896 -+ options.regex_options = get_regex_type(type_name);
5897 -+ return parse_noop(entry, argv, arg_ptr);
5898 -+ }
5899 -+ return false;
5900 -+}
5901 -+
5902 -+
5903 -+static boolean
5904 -+parse_regex (const struct parser_table* entry, char **argv, int *arg_ptr)
5905 -+{
5906 -+ return insert_regex (argv, arg_ptr, entry, options.regex_options);
5907 -+}
5908 -+
5909 -+static boolean
5910 -+insert_regex (char **argv,
5911 -+ int *arg_ptr,
5912 -+ const struct parser_table *entry,
5913 -+ int regex_options)
5914 -+{
5915 -+ const char *rx;
5916 -+ if (collect_arg(argv, arg_ptr, &rx))
5917 -+ {
5918 -+ struct re_pattern_buffer *re;
5919 -+ const char *error_message;
5920 -+ struct predicate *our_pred = insert_primary_withpred (entry, pred_regex);
5921 -+ our_pred->need_stat = our_pred->need_type = false;
5922 -+ re = xmalloc (sizeof (struct re_pattern_buffer));
5923 -+ our_pred->args.regex = re;
5924 -+ re->allocated = 100;
5925 -+ re->buffer = xmalloc (re->allocated);
5926 -+ re->fastmap = NULL;
5927 -+
5928 -+ re_set_syntax(regex_options);
5929 -+ re->syntax = regex_options;
5930 -+ re->translate = NULL;
5931 -+
5932 -+ error_message = re_compile_pattern (rx, strlen(rx), re);
5933 -+ if (error_message)
5934 -+ error (1, 0, "%s", error_message);
5935 -+ our_pred->est_success_rate = estimate_pattern_match_rate(rx, 1);
5936 -+ return true;
5937 -+ }
5938 -+ return false;
5939 -+}
5940 -+
5941 -+static boolean
5942 -+parse_size (const struct parser_table* entry, char **argv, int *arg_ptr)
5943 -+{
5944 -+ struct predicate *our_pred;
5945 -+ uintmax_t num;
5946 -+ char suffix;
5947 -+ enum comparison_type c_type;
5948 -+
5949 -+ int blksize = 512;
5950 -+ int len;
5951 -+
5952 -+ /* XXX: cannot (yet) convert to ue collect_arg() as this
5953 -+ * function modifies the args in-place.
5954 -+ */
5955 -+ if ((argv == NULL) || (argv[*arg_ptr] == NULL))
5956 -+ return false;
5957 -+
5958 -+ len = strlen (argv[*arg_ptr]);
5959 -+ if (len == 0)
5960 -+ error (1, 0, _("invalid null argument to -size"));
5961 -+
5962 -+ suffix = argv[*arg_ptr][len - 1];
5963 -+ switch (suffix)
5964 -+ {
5965 -+ case 'b':
5966 -+ blksize = 512;
5967 -+ argv[*arg_ptr][len - 1] = '\0';
5968 -+ break;
5969 -+
5970 -+ case 'c':
5971 -+ blksize = 1;
5972 -+ argv[*arg_ptr][len - 1] = '\0';
5973 -+ break;
5974 -+
5975 -+ case 'k':
5976 -+ blksize = 1024;
5977 -+ argv[*arg_ptr][len - 1] = '\0';
5978 -+ break;
5979 -+
5980 -+ case 'M': /* Megabytes */
5981 -+ blksize = 1024*1024;
5982 -+ argv[*arg_ptr][len - 1] = '\0';
5983 -+ break;
5984 -+
5985 -+ case 'G': /* Gigabytes */
5986 -+ blksize = 1024*1024*1024;
5987 -+ argv[*arg_ptr][len - 1] = '\0';
5988 -+ break;
5989 -+
5990 -+ case 'w':
5991 -+ blksize = 2;
5992 -+ argv[*arg_ptr][len - 1] = '\0';
5993 -+ break;
5994 -+
5995 -+ case '0':
5996 -+ case '1':
5997 -+ case '2':
5998 -+ case '3':
5999 -+ case '4':
6000 -+ case '5':
6001 -+ case '6':
6002 -+ case '7':
6003 -+ case '8':
6004 -+ case '9':
6005 -+ break;
6006 -+
6007 -+ default:
6008 -+ error (1, 0, _("invalid -size type `%c'"), argv[*arg_ptr][len - 1]);
6009 -+ }
6010 -+ /* TODO: accept fractional megabytes etc. ? */
6011 -+ if (!get_num (argv[*arg_ptr], &num, &c_type))
6012 -+ {
6013 -+ error(1, 0,
6014 -+ _("Invalid argument `%s%c' to -size"),
6015 -+ argv[*arg_ptr], (int)suffix);
6016 -+ return false;
6017 -+ }
6018 -+ our_pred = insert_primary (entry);
6019 -+ our_pred->args.size.kind = c_type;
6020 -+ our_pred->args.size.blocksize = blksize;
6021 -+ our_pred->args.size.size = num;
6022 -+ our_pred->need_stat = true;
6023 -+ our_pred->need_type = false;
6024 -+
6025 -+ if (COMP_GT == c_type)
6026 -+ our_pred->est_success_rate = (num*blksize > 20480) ? 0.1 : 0.9;
6027 -+ else if (COMP_LT == c_type)
6028 -+ our_pred->est_success_rate = (num*blksize > 20480) ? 0.9 : 0.1;
6029 -+ else
6030 -+ our_pred->est_success_rate = 0.01;
6031 -+
6032 -+ (*arg_ptr)++;
6033 -+ return true;
6034 -+}
6035 -+
6036 -+
6037 -+static boolean
6038 -+parse_samefile (const struct parser_table* entry, char **argv, int *arg_ptr)
6039 -+{
6040 -+ /* General idea: stat the file, remember device and inode numbers.
6041 -+ * If a candidate file matches those, it's the same file.
6042 -+ */
6043 -+ struct predicate *our_pred;
6044 -+ struct stat st, fst;
6045 -+ int fd, openflags;
6046 -+
6047 -+ set_stat_placeholders(&st);
6048 -+ if (!collect_arg_stat_info(argv, arg_ptr, &st))
6049 -+ return false;
6050 -+
6051 -+ set_stat_placeholders(&fst);
6052 -+ /* POSIX systems are free to re-use the inode number of a deleted
6053 -+ * file. To ensure that we are not fooled by inode reuse, we hold
6054 -+ * the file open if we can. This would prevent the system reusing
6055 -+ * the file.
6056 -+ */
6057 -+ fd = -3; /* means, uninitialised */
6058 -+ openflags = O_RDONLY;
6059 -+
6060 -+ if (options.symlink_handling == SYMLINK_NEVER_DEREF)
6061 -+ {
6062 -+ if (options.open_nofollow_available)
6063 -+ {
6064 -+ assert (O_NOFOLLOW != 0);
6065 -+ openflags |= O_NOFOLLOW;
6066 -+ fd = -1; /* safe to open it. */
6067 -+ }
6068 -+ else
6069 -+ {
6070 -+ if (S_ISLNK(st.st_mode))
6071 -+ {
6072 -+ /* no way to ensure that a symlink will not be followed
6073 -+ * by open(2), so fall back on using lstat(). Accept
6074 -+ * the risk that the named file will be deleted and
6075 -+ * replaced with another having the same inode.
6076 -+ *
6077 -+ * Avoid opening the file.
6078 -+ */
6079 -+ fd = -2; /* Do not open it */
6080 -+ }
6081 -+ else
6082 -+ {
6083 -+ fd = -1;
6084 -+ /* Race condition here: the file might become a symlink here. */
6085 -+ }
6086 -+ }
6087 -+ }
6088 -+ else
6089 -+ {
6090 -+ /* We want to dereference the symlink anyway */
6091 -+ fd = -1; /* safe to open it without O_NOFOLLOW */
6092 -+ }
6093 -+
6094 -+ assert (fd != -3); /* check we made a decision */
6095 -+ if (fd == -1)
6096 -+ {
6097 -+ /* Race condition here. The file might become a
6098 -+ * symbolic link in between out call to stat and
6099 -+ * the call to open.
6100 -+ */
6101 -+ fd = open(argv[*arg_ptr], openflags);
6102 -+
6103 -+ if (fd >= 0)
6104 -+ {
6105 -+ /* We stat the file again here to prevent a race condition
6106 -+ * between the first stat and the call to open(2).
6107 -+ */
6108 -+ if (0 != fstat(fd, &fst))
6109 -+ {
6110 -+ fatal_file_error(argv[*arg_ptr]);
6111 -+ }
6112 -+ else
6113 -+ {
6114 -+ /* Worry about the race condition. If the file became a
6115 -+ * symlink after our first stat and before our call to
6116 -+ * open, fst may contain the stat information for the
6117 -+ * destination of the link, not the link itself.
6118 -+ */
6119 -+ if ((*options.xstat) (argv[*arg_ptr], &st))
6120 -+ fatal_file_error(argv[*arg_ptr]);
6121 -+
6122 -+ if ((options.symlink_handling == SYMLINK_NEVER_DEREF)
6123 -+ && (!options.open_nofollow_available))
6124 -+ {
6125 -+ if (S_ISLNK(st.st_mode))
6126 -+ {
6127 -+ /* We lost the race. Leave the data in st. The
6128 -+ * file descriptor points to the wrong thing.
6129 -+ */
6130 -+ close(fd);
6131 -+ fd = -1;
6132 -+ }
6133 -+ else
6134 -+ {
6135 -+ /* Several possibilities here:
6136 -+ * 1. There was no race
6137 -+ * 2. The file changed into a symlink after the stat and
6138 -+ * before the open, and then back into a non-symlink
6139 -+ * before the second stat.
6140 -+ *
6141 -+ * In case (1) there is no problem. In case (2),
6142 -+ * the stat() and fstat() calls will have returned
6143 -+ * different data. O_NOFOLLOW was not available,
6144 -+ * so the open() call may have followed a symlink
6145 -+ * even if the -P option is in effect.
6146 -+ */
6147 -+ if ((st.st_dev == fst.st_dev)
6148 -+ && (st.st_ino == fst.st_ino))
6149 -+ {
6150 -+ /* No race. No need to copy fst to st,
6151 -+ * since they should be identical (modulo
6152 -+ * differences in padding bytes).
6153 -+ */
6154 -+ }
6155 -+ else
6156 -+ {
6157 -+ /* We lost the race. Leave the data in st. The
6158 -+ * file descriptor points to the wrong thing.
6159 -+ */
6160 -+ close(fd);
6161 -+ fd = -1;
6162 -+ }
6163 -+ }
6164 -+ }
6165 -+ else
6166 -+ {
6167 -+ st = fst;
6168 -+ }
6169 -+ }
6170 -+ }
6171 -+ }
6172 -+
6173 -+ our_pred = insert_primary (entry);
6174 -+ our_pred->args.samefileid.ino = st.st_ino;
6175 -+ our_pred->args.samefileid.dev = st.st_dev;
6176 -+ our_pred->args.samefileid.fd = fd;
6177 -+ our_pred->need_type = false;
6178 -+ our_pred->need_stat = true;
6179 -+ our_pred->est_success_rate = 0.01f;
6180 -+ return true;
6181 -+}
6182 -+
6183 -+#if 0
6184 -+/* This function is commented out partly because support for it is
6185 -+ * uneven.
6186 -+ */
6187 -+static boolean
6188 -+parse_show_control_chars (const struct parser_table* entry,
6189 -+ char **argv,
6190 -+ int *arg_ptr)
6191 -+{
6192 -+ const char *arg;
6193 -+ const char *errmsg = _("The -show-control-chars option takes "
6194 -+ "a single argument which "
6195 -+ "must be 'literal' or 'safe'");
6196 -+
6197 -+ if ((argv == NULL) || (argv[*arg_ptr] == NULL))
6198 -+ {
6199 -+ error (1, errno, "%s", errmsg);
6200 -+ return false;
6201 -+ }
6202 -+ else
6203 -+ {
6204 -+ arg = argv[*arg_ptr];
6205 -+
6206 -+ if (0 == strcmp("literal", arg))
6207 -+ {
6208 -+ options.literal_control_chars = true;
6209 -+ }
6210 -+ else if (0 == strcmp("safe", arg))
6211 -+ {
6212 -+ options.literal_control_chars = false;
6213 -+ }
6214 -+ else
6215 -+ {
6216 -+ error (1, errno, "%s", errmsg);
6217 -+ return false;
6218 -+ }
6219 -+ (*arg_ptr)++; /* consume the argument. */
6220 -+ return true;
6221 -+ }
6222 -+}
6223 -+#endif
6224 -+
6225 -+
6226 -+static boolean
6227 -+parse_true (const struct parser_table* entry, char **argv, int *arg_ptr)
6228 -+{
6229 -+ struct predicate *our_pred;
6230 -+
6231 -+ (void) argv;
6232 -+ (void) arg_ptr;
6233 -+
6234 -+ our_pred = insert_primary (entry);
6235 -+ our_pred->need_stat = our_pred->need_type = false;
6236 -+ our_pred->est_success_rate = 1.0f;
6237 -+ return true;
6238 -+}
6239 -+
6240 -+static boolean
6241 -+parse_noop (const struct parser_table* entry, char **argv, int *arg_ptr)
6242 -+{
6243 -+ (void) entry;
6244 -+ return parse_true(get_noop(), argv, arg_ptr);
6245 -+}
6246 -+
6247 -+static boolean
6248 -+parse_accesscheck (const struct parser_table* entry, char **argv, int *arg_ptr)
6249 -+{
6250 -+ struct predicate *our_pred;
6251 -+ (void) argv;
6252 -+ (void) arg_ptr;
6253 -+ our_pred = insert_primary (entry);
6254 -+ our_pred->need_stat = our_pred->need_type = false;
6255 -+ our_pred->side_effects = our_pred->no_default_print = false;
6256 -+ if (pred_is(our_pred, pred_executable))
6257 -+ our_pred->est_success_rate = 0.2;
6258 -+ else
6259 -+ our_pred->est_success_rate = 0.9;
6260 -+ return true;
6261 -+}
6262 -+
6263 -+static boolean
6264 -+parse_type (const struct parser_table* entry, char **argv, int *arg_ptr)
6265 -+{
6266 -+ return insert_type (argv, arg_ptr, entry, pred_type);
6267 -+}
6268 -+
6269 -+static boolean
6270 -+parse_uid (const struct parser_table* entry, char **argv, int *arg_ptr)
6271 -+{
6272 -+ struct predicate *p = insert_num (argv, arg_ptr, entry);
6273 -+ if (p)
6274 -+ {
6275 -+ p->est_success_rate = (p->args.numinfo.l_val < 100) ? 0.99 : 0.2;
6276 -+ return true;
6277 -+ }
6278 -+ else
6279 -+ {
6280 -+ return false;
6281 -+ }
6282 -+}
6283 -+
6284 -+static boolean
6285 -+parse_used (const struct parser_table* entry, char **argv, int *arg_ptr)
6286 -+{
6287 -+ struct predicate *our_pred;
6288 -+ struct time_val tval;
6289 -+ const char *offset_str;
6290 -+ const char *errmsg = "arithmetic overflow while converting %s days to a number of seconds";
6291 -+
6292 -+ if (collect_arg(argv, arg_ptr, &offset_str))
6293 -+ {
6294 -+ /* The timespec is actually a delta value, so we use an origin of 0. */
6295 -+ if (get_relative_timestamp(offset_str, &tval, 0, DAYSECS, errmsg))
6296 -+ {
6297 -+ our_pred = insert_primary (entry);
6298 -+ our_pred->args.reftime = tval;
6299 -+ our_pred->est_success_rate = estimate_file_age_success_rate(tval.ts.tv_sec / DAYSECS);
6300 -+ return true;
6301 -+ }
6302 -+ else
6303 -+ {
6304 -+ error(1, 0, _("Invalid argument %s to -used"), offset_str);
6305 -+ return false;
6306 -+ }
6307 -+ }
6308 -+ else
6309 -+ {
6310 -+ return false; /* missing argument */
6311 -+ }
6312 -+}
6313 -+
6314 -+static boolean
6315 -+parse_user (const struct parser_table* entry, char **argv, int *arg_ptr)
6316 -+{
6317 -+ const char *username;
6318 -+
6319 -+ if (collect_arg(argv, arg_ptr, &username))
6320 -+ {
6321 -+ struct predicate *our_pred;
6322 -+ uid_t uid;
6323 -+ struct passwd *cur_pwd = getpwnam(username);
6324 -+ endpwent();
6325 -+ if (cur_pwd != NULL)
6326 -+ {
6327 -+ uid = cur_pwd->pw_uid;
6328 -+ }
6329 -+ else
6330 -+ {
6331 -+ int uid_len = strspn (username, "0123456789");
6332 -+ if (uid_len && (username[uid_len]==0))
6333 -+ uid = safe_atoi (username);
6334 -+ else
6335 -+ return false;
6336 -+ }
6337 -+ our_pred = insert_primary (entry);
6338 -+ our_pred->args.uid = uid;
6339 -+ our_pred->est_success_rate = (our_pred->args.uid < 100) ? 0.99 : 0.2;
6340 -+ return true;
6341 -+ }
6342 -+ return false;
6343 -+}
6344 -+
6345 -+static boolean
6346 -+parse_version (const struct parser_table* entry, char **argv, int *arg_ptr)
6347 -+{
6348 -+ int features = 0;
6349 -+ int flags;
6350 -+
6351 -+ (void) argv;
6352 -+ (void) arg_ptr;
6353 -+ (void) entry;
6354 -+
6355 -+ display_findutils_version("find");
6356 -+ printf (_("Features enabled: "));
6357 -+
6358 -+#if CACHE_IDS
6359 -+ printf("CACHE_IDS ");
6360 -+ ++features;
6361 -+#endif
6362 -+#if DEBUG
6363 -+ printf("DEBUG ");
6364 -+ ++features;
6365 -+#endif
6366 -+#if DEBUG_STAT
6367 -+ printf("DEBUG_STAT ");
6368 -+ ++features;
6369 -+#endif
6370 -+#if defined USE_STRUCT_DIRENT_D_TYPE && defined HAVE_STRUCT_DIRENT_D_TYPE
6371 -+ printf("D_TYPE ");
6372 -+ ++features;
6373 -+#endif
6374 -+#if defined O_NOFOLLOW
6375 -+ printf("O_NOFOLLOW(%s) ",
6376 -+ (options.open_nofollow_available ? "enabled" : "disabled"));
6377 -+ ++features;
6378 -+#endif
6379 -+#if defined LEAF_OPTIMISATION
6380 -+ printf("LEAF_OPTIMISATION ");
6381 -+ ++features;
6382 -+#endif
6383 -+
6384 -+ flags = 0;
6385 -+ if (is_fts_enabled(&flags))
6386 -+ {
6387 -+ int nflags = 0;
6388 -+ printf("FTS(");
6389 -+ ++features;
6390 -+
6391 -+ if (flags & FTS_CWDFD)
6392 -+ {
6393 -+ if (nflags)
6394 -+ {
6395 -+ printf(",");
6396 -+ }
6397 -+ printf("FTS_CWDFD");
6398 -+ ++nflags;
6399 -+ }
6400 -+ printf(") ");
6401 -+ }
6402 -+
6403 -+ printf("CBO(level=%d) ", (int)(options.optimisation_level));
6404 -+ ++features;
6405 -+
6406 -+ if (0 == features)
6407 -+ {
6408 -+ /* For the moment, leave this as English in case someone wants
6409 -+ to parse these strings. */
6410 -+ printf("none");
6411 -+ }
6412 -+ printf("\n");
6413 -+
6414 -+ exit (0);
6415 -+}
6416 -+
6417 -+static boolean
6418 -+parse_xdev (const struct parser_table* entry, char **argv, int *arg_ptr)
6419 -+{
6420 -+ options.stay_on_filesystem = true;
6421 -+ return parse_noop(entry, argv, arg_ptr);
6422 -+}
6423 -+
6424 -+static boolean
6425 -+parse_ignore_race (const struct parser_table* entry, char **argv, int *arg_ptr)
6426 -+{
6427 -+ options.ignore_readdir_race = true;
6428 -+ return parse_noop(entry, argv, arg_ptr);
6429 -+}
6430 -+
6431 -+static boolean
6432 -+parse_noignore_race (const struct parser_table* entry, char **argv, int *arg_ptr)
6433 -+{
6434 -+ options.ignore_readdir_race = false;
6435 -+ return parse_noop(entry, argv, arg_ptr);
6436 -+}
6437 -+
6438 -+static boolean
6439 -+parse_warn (const struct parser_table* entry, char **argv, int *arg_ptr)
6440 -+{
6441 -+ options.warnings = true;
6442 -+ return parse_noop(entry, argv, arg_ptr);
6443 -+}
6444 -+
6445 -+static boolean
6446 -+parse_xtype (const struct parser_table* entry, char **argv, int *arg_ptr)
6447 -+{
6448 -+ return insert_type (argv, arg_ptr, entry, pred_xtype);
6449 -+}
6450 -+
6451 -+static boolean
6452 -+insert_type (char **argv, int *arg_ptr,
6453 -+ const struct parser_table *entry,
6454 -+ PRED_FUNC which_pred)
6455 -+{
6456 -+ mode_t type_cell;
6457 -+ struct predicate *our_pred;
6458 -+ float rate = 0.5;
6459 -+ const char *typeletter;
6460 -+
6461 -+ if (collect_arg(argv, arg_ptr, &typeletter))
6462 -+ {
6463 -+ if (strlen(typeletter) != 1u)
6464 -+ {
6465 -+ error(1, 0, _("Arguments to -type should contain only one letter"));
6466 -+ return false;
6467 -+ }
6468 -+
6469 -+ switch (typeletter[0])
6470 -+ {
6471 -+ case 'b': /* block special */
6472 -+ type_cell = S_IFBLK;
6473 -+ rate = 0.01f;
6474 -+ break;
6475 -+ case 'c': /* character special */
6476 -+ type_cell = S_IFCHR;
6477 -+ rate = 0.01f;
6478 -+ break;
6479 -+ case 'd': /* directory */
6480 -+ type_cell = S_IFDIR;
6481 -+ rate = 0.4f;
6482 -+ break;
6483 -+ case 'f': /* regular file */
6484 -+ type_cell = S_IFREG;
6485 -+ rate = 0.95f;
6486 -+ break;
6487 -+#ifdef S_IFLNK
6488 -+ case 'l': /* symbolic link */
6489 -+ type_cell = S_IFLNK;
6490 -+ rate = 0.1f;
6491 -+ break;
6492 -+#endif
6493 -+#ifdef S_IFIFO
6494 -+ case 'p': /* pipe */
6495 -+ type_cell = S_IFIFO;
6496 -+ rate = 0.01f;
6497 -+ break;
6498 -+#endif
6499 -+#ifdef S_IFSOCK
6500 -+ case 's': /* socket */
6501 -+ type_cell = S_IFSOCK;
6502 -+ rate = 0.01f;
6503 -+ break;
6504 -+#endif
6505 -+#ifdef S_IFDOOR
6506 -+ case 'D': /* Solaris door */
6507 -+ type_cell = S_IFDOOR;
6508 -+ rate = 0.01f;
6509 -+ break;
6510 -+#endif
6511 -+ default: /* None of the above ... nuke 'em. */
6512 -+ error(1, 0, _("Unknown argument to -type: %c"), (*typeletter));
6513 -+ return false;
6514 -+ }
6515 -+ our_pred = insert_primary_withpred (entry, which_pred);
6516 -+ our_pred->est_success_rate = rate;
6517 -+
6518 -+ /* Figure out if we will need to stat the file, because if we don't
6519 -+ * need to follow symlinks, we can avoid a stat call by using
6520 -+ * struct dirent.d_type.
6521 -+ */
6522 -+ if (which_pred == pred_xtype)
6523 -+ {
6524 -+ our_pred->need_stat = true;
6525 -+ our_pred->need_type = false;
6526 -+ }
6527 -+ else
6528 -+ {
6529 -+ our_pred->need_stat = false; /* struct dirent is enough */
6530 -+ our_pred->need_type = true;
6531 -+ }
6532 -+ our_pred->args.type = type_cell;
6533 -+ return true;
6534 -+ }
6535 -+ return false;
6536 -+}
6537 -+
6538 -+
6539 -+/* Return true if the file accessed via FP is a terminal.
6540 -+ */
6541 -+static boolean
6542 -+stream_is_tty(FILE *fp)
6543 -+{
6544 -+ int fd = fileno(fp);
6545 -+ if (-1 == fd)
6546 -+ {
6547 -+ return false; /* not a valid stream */
6548 -+ }
6549 -+ else
6550 -+ {
6551 -+ return isatty(fd) ? true : false;
6552 -+ }
6553 -+
6554 -+}
6555 -+
6556 -+
6557 -+
6558 -+
6559 -+/* XXX: do we need to pass FUNC to this function? */
6560 -+static boolean
6561 -+insert_fprintf (struct format_val *vec,
6562 -+ const struct parser_table *entry, PRED_FUNC func,
6563 -+ const char *format_const)
6564 -+{
6565 -+ char *format = (char*)format_const; /* XXX: casting away constness */
6566 -+ register char *scan; /* Current address in scanning `format'. */
6567 -+ register char *scan2; /* Address inside of element being scanned. */
6568 -+ struct segment **segmentp; /* Address of current segment. */
6569 -+ struct predicate *our_pred;
6570 -+
6571 -+ our_pred = insert_primary_withpred (entry, func);
6572 -+ our_pred->side_effects = our_pred->no_default_print = true;
6573 -+ our_pred->args.printf_vec = *vec;
6574 -+ our_pred->need_type = false;
6575 -+ our_pred->need_stat = false;
6576 -+ our_pred->p_cost = NeedsNothing;
6577 -+
6578 -+ segmentp = &our_pred->args.printf_vec.segment;
6579 -+ *segmentp = NULL;
6580 -+
6581 -+ for (scan = format; *scan; scan++)
6582 -+ {
6583 -+ if (*scan == '\\')
6584 -+ {
6585 -+ scan2 = scan + 1;
6586 -+ if (*scan2 >= '0' && *scan2 <= '7')
6587 -+ {
6588 -+ register int n, i;
6589 -+
6590 -+ for (i = n = 0; i < 3 && (*scan2 >= '0' && *scan2 <= '7');
6591 -+ i++, scan2++)
6592 -+ n = 8 * n + *scan2 - '0';
6593 -+ scan2--;
6594 -+ *scan = n;
6595 -+ }
6596 -+ else
6597 -+ {
6598 -+ switch (*scan2)
6599 -+ {
6600 -+ case 'a':
6601 -+ *scan = 7;
6602 -+ break;
6603 -+ case 'b':
6604 -+ *scan = '\b';
6605 -+ break;
6606 -+ case 'c':
6607 -+ make_segment (segmentp, format, scan - format,
6608 -+ KIND_STOP, 0, 0,
6609 -+ our_pred);
6610 -+ if (our_pred->need_stat && (our_pred->p_cost < NeedsStatInfo))
6611 -+ our_pred->p_cost = NeedsStatInfo;
6612 -+ return true;
6613 -+ case 'f':
6614 -+ *scan = '\f';
6615 -+ break;
6616 -+ case 'n':
6617 -+ *scan = '\n';
6618 -+ break;
6619 -+ case 'r':
6620 -+ *scan = '\r';
6621 -+ break;
6622 -+ case 't':
6623 -+ *scan = '\t';
6624 -+ break;
6625 -+ case 'v':
6626 -+ *scan = '\v';
6627 -+ break;
6628 -+ case '\\':
6629 -+ /* *scan = '\\'; * it already is */
6630 -+ break;
6631 -+ default:
6632 -+ error (0, 0,
6633 -+ _("warning: unrecognized escape `\\%c'"), *scan2);
6634 -+ scan++;
6635 -+ continue;
6636 -+ }
6637 -+ }
6638 -+ segmentp = make_segment (segmentp, format, scan - format + 1,
6639 -+ KIND_PLAIN, 0, 0,
6640 -+ our_pred);
6641 -+ format = scan2 + 1; /* Move past the escape. */
6642 -+ scan = scan2; /* Incremented immediately by `for'. */
6643 -+ }
6644 -+ else if (*scan == '%')
6645 -+ {
6646 -+ if (scan[1] == 0)
6647 -+ {
6648 -+ /* Trailing %. We don't like those. */
6649 -+ error (1, 0, _("error: %s at end of format string"), scan);
6650 -+ }
6651 -+ else if (scan[1] == '%')
6652 -+ {
6653 -+ segmentp = make_segment (segmentp, format, scan - format + 1,
6654 -+ KIND_PLAIN, 0, 0,
6655 -+ our_pred);
6656 -+ scan++;
6657 -+ format = scan + 1;
6658 -+ continue;
6659 -+ }
6660 -+ /* Scan past flags, width and precision, to verify kind. */
6661 -+ for (scan2 = scan; *++scan2 && strchr ("-+ #", *scan2);)
6662 -+ /* Do nothing. */ ;
6663 -+ while (ISDIGIT (*scan2))
6664 -+ scan2++;
6665 -+ if (*scan2 == '.')
6666 -+ for (scan2++; ISDIGIT (*scan2); scan2++)
6667 -+ /* Do nothing. */ ;
6668 -+ if (strchr ("abcdDfFgGhHiklmMnpPsStuUyY", *scan2))
6669 -+ {
6670 -+ segmentp = make_segment (segmentp, format, scan2 - format,
6671 -+ KIND_FORMAT, *scan2, 0,
6672 -+ our_pred);
6673 -+ scan = scan2;
6674 -+ format = scan + 1;
6675 -+ }
6676 -+ else if (strchr ("ABCT", *scan2) && scan2[1])
6677 -+ {
6678 -+ segmentp = make_segment (segmentp, format, scan2 - format,
6679 -+ KIND_FORMAT, scan2[0], scan2[1],
6680 -+ our_pred);
6681 -+ scan = scan2 + 1;
6682 -+ format = scan + 1;
6683 -+ continue;
6684 -+ }
6685 -+ else
6686 -+ {
6687 -+ /* An unrecognized % escape. Print the char after the %. */
6688 -+ error (0, 0, _("warning: unrecognized format directive `%%%c'"),
6689 -+ *scan2);
6690 -+ segmentp = make_segment (segmentp, format, scan - format,
6691 -+ KIND_PLAIN, 0, 0,
6692 -+ our_pred);
6693 -+ format = scan + 1;
6694 -+ continue;
6695 -+ }
6696 -+ }
6697 -+ }
6698 -+
6699 -+ if (scan > format)
6700 -+ make_segment (segmentp, format, scan - format, KIND_PLAIN, 0, 0,
6701 -+ our_pred);
6702 -+ return true;
6703 -+}
6704 -+
6705 -+/* Create a new fprintf segment in *SEGMENT, with type KIND,
6706 -+ from the text in FORMAT, which has length LEN.
6707 -+ Return the address of the `next' pointer of the new segment. */
6708 -+
6709 -+static struct segment **
6710 -+make_segment (struct segment **segment,
6711 -+ char *format,
6712 -+ int len,
6713 -+ int kind,
6714 -+ char format_char,
6715 -+ char aux_format_char,
6716 -+ struct predicate *pred)
6717 -+{
6718 -+ enum EvaluationCost mycost = NeedsNothing;
6719 -+ char *fmt;
6720 -+
6721 -+ *segment = xmalloc (sizeof (struct segment));
6722 -+
6723 -+ (*segment)->segkind = kind;
6724 -+ (*segment)->format_char[0] = format_char;
6725 -+ (*segment)->format_char[1] = aux_format_char;
6726 -+ (*segment)->next = NULL;
6727 -+ (*segment)->text_len = len;
6728 -+
6729 -+ fmt = (*segment)->text = xmalloc (len + sizeof "d");
6730 -+ strncpy (fmt, format, len);
6731 -+ fmt += len;
6732 -+
6733 -+ switch (kind)
6734 -+ {
6735 -+ case KIND_PLAIN: /* Plain text string, no % conversion. */
6736 -+ case KIND_STOP: /* Terminate argument, no newline. */
6737 -+ assert (0 == format_char);
6738 -+ assert (0 == aux_format_char);
6739 -+ *fmt = '\0';
6740 -+ if (mycost > pred->p_cost)
6741 -+ pred->p_cost = NeedsNothing;
6742 -+ return &(*segment)->next;
6743 -+ break;
6744 -+ }
6745 -+
6746 -+ assert (kind == KIND_FORMAT);
6747 -+ switch (format_char)
6748 -+ {
6749 -+ case 'l': /* object of symlink */
6750 -+ pred->need_stat = true;
6751 -+ mycost = NeedsLinkName;
6752 -+ *fmt++ = 's';
6753 -+ break;
6754 -+
6755 -+ case 'y': /* file type */
6756 -+ pred->need_type = true;
6757 -+ mycost = NeedsType;
6758 -+ *fmt++ = 's';
6759 -+ break;
6760 -+
6761 -+ case 'a': /* atime in `ctime' format */
6762 -+ case 'A': /* atime in user-specified strftime format */
6763 -+ case 'B': /* birth time in user-specified strftime format */
6764 -+ case 'c': /* ctime in `ctime' format */
6765 -+ case 'C': /* ctime in user-specified strftime format */
6766 -+ case 'F': /* file system type */
6767 -+ case 'g': /* group name */
6768 -+ case 'i': /* inode number */
6769 -+ case 'M': /* mode in `ls -l' format (eg., "drwxr-xr-x") */
6770 -+ case 's': /* size in bytes */
6771 -+ case 't': /* mtime in `ctime' format */
6772 -+ case 'T': /* mtime in user-specified strftime format */
6773 -+ case 'u': /* user name */
6774 -+ pred->need_stat = true;
6775 -+ mycost = NeedsStatInfo;
6776 -+ *fmt++ = 's';
6777 -+ break;
6778 -+
6779 -+ case 'S': /* sparseness */
6780 -+ pred->need_stat = true;
6781 -+ mycost = NeedsStatInfo;
6782 -+ *fmt++ = 'g';
6783 -+ break;
6784 -+
6785 -+ case 'Y': /* symlink pointed file type */
6786 -+ pred->need_stat = true;
6787 -+ mycost = NeedsType; /* true for amortised effect */
6788 -+ *fmt++ = 's';
6789 -+ break;
6790 -+
6791 -+ case 'f': /* basename of path */
6792 -+ case 'h': /* leading directories part of path */
6793 -+ case 'p': /* pathname */
6794 -+ case 'P': /* pathname with ARGV element stripped */
6795 -+ *fmt++ = 's';
6796 -+ break;
6797 -+
6798 -+ case 'H': /* ARGV element file was found under */
6799 -+ *fmt++ = 's';
6800 -+ break;
6801 -+
6802 -+ /* Numeric items that one might expect to honour
6803 -+ * #, 0, + flags but which do not.
6804 -+ */
6805 -+ case 'G': /* GID number */
6806 -+ case 'U': /* UID number */
6807 -+ case 'b': /* size in 512-byte blocks (NOT birthtime in ctime fmt)*/
6808 -+ case 'D': /* Filesystem device on which the file exits */
6809 -+ case 'k': /* size in 1K blocks */
6810 -+ case 'n': /* number of links */
6811 -+ pred->need_stat = true;
6812 -+ mycost = NeedsStatInfo;
6813 -+ *fmt++ = 's';
6814 -+ break;
6815 -+
6816 -+ /* Numeric items that DO honour #, 0, + flags.
6817 -+ */
6818 -+ case 'd': /* depth in search tree (0 = ARGV element) */
6819 -+ *fmt++ = 'd';
6820 -+ break;
6821 -+
6822 -+ case 'm': /* mode as octal number (perms only) */
6823 -+ *fmt++ = 'o';
6824 -+ pred->need_stat = true;
6825 -+ mycost = NeedsStatInfo;
6826 -+ break;
6827 -+
6828 -+ case '{':
6829 -+ case '[':
6830 -+ case '(':
6831 -+ error (1, 0,
6832 -+ _("error: the format directive `%%%c' is reserved for future use"),
6833 -+ (int)kind);
6834 -+ /*NOTREACHED*/
6835 -+ break;
6836 -+ }
6837 -+ *fmt = '\0';
6838 -+
6839 -+ if (mycost > pred->p_cost)
6840 -+ pred->p_cost = mycost;
6841 -+ return &(*segment)->next;
6842 -+}
6843 -+
6844 -+static void
6845 -+check_path_safety(const char *action, char **argv)
6846 -+{
6847 -+ char *s;
6848 -+ const char *path = getenv("PATH");
6849 -+ if (NULL == path)
6850 -+ {
6851 -+ /* $PATH is not set. Assume the OS default is safe.
6852 -+ * That may not be true on Windows, but I'm not aware
6853 -+ * of a way to get Windows to avoid searching the
6854 -+ * current directory anyway.
6855 -+ */
6856 -+ return;
6857 -+ }
6858 -+
6859 -+ (void)argv;
6860 -+
6861 -+ s = next_element(path, 1);
6862 -+ while ((s = next_element ((char *) NULL, 1)) != NULL)
6863 -+ {
6864 -+ if (0 == strcmp(s, "."))
6865 -+ {
6866 -+ error(1, 0, _("The current directory is included in the PATH "
6867 -+ "environment variable, which is insecure in "
6868 -+ "combination with the %s action of find. "
6869 -+ "Please remove the current directory from your "
6870 -+ "$PATH (that is, remove \".\" or leading or trailing "
6871 -+ "colons)"),
6872 -+ action);
6873 -+ }
6874 -+ else if ('/' != s[0])
6875 -+ {
6876 -+ /* Relative paths are also dangerous in $PATH. */
6877 -+ error(1, 0, _("The relative path %1$s is included in the PATH "
6878 -+ "environment variable, which is insecure in "
6879 -+ "combination with the %2$s action of find. "
6880 -+ "Please remove that entry from $PATH"),
6881 -+ safely_quote_err_filename(0, s),
6882 -+ action);
6883 -+ }
6884 -+ }
6885 -+}
6886 -+
6887 -+
6888 -+/* handles both exec and ok predicate */
6889 -+static boolean
6890 -+new_insert_exec_ok (const char *action,
6891 -+ const struct parser_table *entry,
6892 -+ int dirfd,
6893 -+ char **argv,
6894 -+ int *arg_ptr)
6895 -+{
6896 -+ int start, end; /* Indexes in ARGV of start & end of cmd. */
6897 -+ int i; /* Index into cmd args */
6898 -+ int saw_braces; /* True if previous arg was '{}'. */
6899 -+ boolean allow_plus; /* True if + is a valid terminator */
6900 -+ int brace_count; /* Number of instances of {}. */
6901 -+ PRED_FUNC func = entry->pred_func;
6902 -+ enum BC_INIT_STATUS bcstatus;
6903 -+
6904 -+ struct predicate *our_pred;
6905 -+ struct exec_val *execp; /* Pointer for efficiency. */
6906 -+
6907 -+ if ((argv == NULL) || (argv[*arg_ptr] == NULL))
6908 -+ return false;
6909 -+
6910 -+ our_pred = insert_primary_withpred (entry, func);
6911 -+ our_pred->side_effects = our_pred->no_default_print = true;
6912 -+ our_pred->need_type = our_pred->need_stat = false;
6913 -+
6914 -+ execp = &our_pred->args.exec_vec;
6915 -+
6916 -+ if ((func != pred_okdir) && (func != pred_ok))
6917 -+ {
6918 -+ allow_plus = true;
6919 -+ execp->close_stdin = false;
6920 -+ }
6921 -+ else
6922 -+ {
6923 -+ allow_plus = false;
6924 -+ /* If find reads stdin (i.e. for -ok and similar), close stdin
6925 -+ * in the child to prevent some script from consiming the output
6926 -+ * intended for find.
6927 -+ */
6928 -+ execp->close_stdin = true;
6929 -+ }
6930 -+
6931 -+
6932 -+ if ((func == pred_execdir) || (func == pred_okdir))
6933 -+ {
6934 -+ options.ignore_readdir_race = false;
6935 -+ check_path_safety(action, argv);
6936 -+ execp->use_current_dir = true;
6937 -+ }
6938 -+ else
6939 -+ {
6940 -+ execp->use_current_dir = false;
6941 -+ }
6942 -+
6943 -+ our_pred->args.exec_vec.multiple = 0;
6944 -+
6945 -+ /* Count the number of args with path replacements, up until the ';'.
6946 -+ * Also figure out if the command is terminated by ";" or by "+".
6947 -+ */
6948 -+ start = *arg_ptr;
6949 -+ for (end = start, saw_braces=0, brace_count=0;
6950 -+ (argv[end] != NULL)
6951 -+ && ((argv[end][0] != ';') || (argv[end][1] != '\0'));
6952 -+ end++)
6953 -+ {
6954 -+ /* For -exec and -execdir, "{} +" can terminate the command. */
6955 -+ if ( allow_plus
6956 -+ && argv[end][0] == '+' && argv[end][1] == 0
6957 -+ && saw_braces)
6958 -+ {
6959 -+ our_pred->args.exec_vec.multiple = 1;
6960 -+ break;
6961 -+ }
6962 -+
6963 -+ saw_braces = 0;
6964 -+ if (mbsstr (argv[end], "{}"))
6965 -+ {
6966 -+ saw_braces = 1;
6967 -+ ++brace_count;
6968 -+
6969 -+ if (0 == end && (func == pred_execdir || func == pred_okdir))
6970 -+ {
6971 -+ /* The POSIX standard says that {} replacement should
6972 -+ * occur even in the utility name. This is insecure
6973 -+ * since it means we will be executing a command whose
6974 -+ * name is chosen according to whatever find finds in
6975 -+ * the file system. That can be influenced by an
6976 -+ * attacker. Hence for -execdir and -okdir this is not
6977 -+ * allowed. We can specify this as those options are
6978 -+ * not defined by POSIX.
6979 -+ */
6980 -+ error(1, 0, _("You may not use {} within the utility name for "
6981 -+ "-execdir and -okdir, because this is a potential "
6982 -+ "security problem."));
6983 -+ }
6984 -+ }
6985 -+ }
6986 -+
6987 -+ /* Fail if no command given or no semicolon found. */
6988 -+ if ((end == start) || (argv[end] == NULL))
6989 -+ {
6990 -+ *arg_ptr = end;
6991 -+ free(our_pred);
6992 -+ return false;
6993 -+ }
6994 -+
6995 -+ if (our_pred->args.exec_vec.multiple && brace_count > 1)
6996 -+ {
6997 -+
6998 -+ const char *suffix;
6999 -+ if (func == pred_execdir)
7000 -+ suffix = "dir";
7001 -+ else
7002 -+ suffix = "";
7003 -+
7004 -+ error(1, 0,
7005 -+ _("Only one instance of {} is supported with -exec%s ... +"),
7006 -+ suffix);
7007 -+ }
7008 -+
7009 -+ /* We use a switch statement here so that the compiler warns us when
7010 -+ * we forget to handle a newly invented enum value.
7011 -+ *
7012 -+ * Like xargs, we allow 2KiB of headroom for the launched utility to
7013 -+ * export its own environment variables before calling something
7014 -+ * else.
7015 -+ */
7016 -+ bcstatus = bc_init_controlinfo(&execp->ctl, 2048u);
7017 -+ switch (bcstatus)
7018 -+ {
7019 -+ case BC_INIT_ENV_TOO_BIG:
7020 -+ case BC_INIT_CANNOT_ACCOMODATE_HEADROOM:
7021 -+ error(1, 0,
7022 -+ _("The environment is too large for exec()."));
7023 -+ break;
7024 -+ case BC_INIT_OK:
7025 -+ /* Good news. Carry on. */
7026 -+ break;
7027 -+ }
7028 -+ bc_use_sensible_arg_max(&execp->ctl);
7029 -+
7030 -+
7031 -+ execp->ctl.exec_callback = launch;
7032 -+
7033 -+ if (our_pred->args.exec_vec.multiple)
7034 -+ {
7035 -+ /* "+" terminator, so we can just append our arguments after the
7036 -+ * command and initial arguments.
7037 -+ */
7038 -+ execp->replace_vec = NULL;
7039 -+ execp->ctl.replace_pat = NULL;
7040 -+ execp->ctl.rplen = 0;
7041 -+ execp->ctl.lines_per_exec = 0; /* no limit */
7042 -+ execp->ctl.args_per_exec = 0; /* no limit */
7043 -+
7044 -+ /* remember how many arguments there are */
7045 -+ execp->ctl.initial_argc = (end-start) - 1;
7046 -+
7047 -+ /* execp->state = xmalloc(sizeof struct buildcmd_state); */
7048 -+ bc_init_state(&execp->ctl, &execp->state, execp);
7049 -+
7050 -+ /* Gather the initial arguments. Skip the {}. */
7051 -+ for (i=start; i<end-1; ++i)
7052 -+ {
7053 -+ bc_push_arg(&execp->ctl, &execp->state,
7054 -+ argv[i], strlen(argv[i])+1,
7055 -+ NULL, 0,
7056 -+ 1);
7057 -+ }
7058 -+ }
7059 -+ else
7060 -+ {
7061 -+ /* Semicolon terminator - more than one {} is supported, so we
7062 -+ * have to do brace-replacement.
7063 -+ */
7064 -+ execp->num_args = end - start;
7065 -+
7066 -+ execp->ctl.replace_pat = "{}";
7067 -+ execp->ctl.rplen = strlen(execp->ctl.replace_pat);
7068 -+ execp->ctl.lines_per_exec = 0; /* no limit */
7069 -+ execp->ctl.args_per_exec = 0; /* no limit */
7070 -+ execp->replace_vec = xmalloc(sizeof(char*)*execp->num_args);
7071 -+
7072 -+
7073 -+ /* execp->state = xmalloc(sizeof(*(execp->state))); */
7074 -+ bc_init_state(&execp->ctl, &execp->state, execp);
7075 -+
7076 -+ /* Remember the (pre-replacement) arguments for later. */
7077 -+ for (i=0; i<execp->num_args; ++i)
7078 -+ {
7079 -+ execp->replace_vec[i] = argv[i+start];
7080 -+ }
7081 -+ }
7082 -+
7083 -+ if (argv[end] == NULL)
7084 -+ *arg_ptr = end;
7085 -+ else
7086 -+ *arg_ptr = end + 1;
7087 -+
7088 -+ return true;
7089 -+}
7090 -+
7091 -+
7092 -+
7093 -+static boolean
7094 -+insert_exec_ok (const char *action,
7095 -+ const struct parser_table *entry,
7096 -+ int dirfd,
7097 -+ char **argv,
7098 -+ int *arg_ptr)
7099 -+{
7100 -+ return new_insert_exec_ok(action, entry, dirfd, argv, arg_ptr);
7101 -+}
7102 -+
7103 -+
7104 -+
7105 -+/* Get a timestamp and comparison type.
7106 -+
7107 -+ STR is the ASCII representation.
7108 -+ Set *NUM_DAYS to the number of days/minutes/whatever, taken as being
7109 -+ relative to ORIGIN (usually the current moment or midnight).
7110 -+ Thus the sense of the comparison type appears to be reversed.
7111 -+ Set *COMP_TYPE to the kind of comparison that is requested.
7112 -+ Issue OVERFLOWMESSAGE if overflow occurs.
7113 -+ Return true if all okay, false if input error.
7114 -+
7115 -+ Used by -atime, -ctime and -mtime (parsers) to
7116 -+ get the appropriate information for a time predicate processor. */
7117 -+
7118 -+static boolean
7119 -+get_relative_timestamp (const char *str,
7120 -+ struct time_val *result,
7121 -+ time_t origin,
7122 -+ double sec_per_unit,
7123 -+ const char *overflowmessage)
7124 -+{
7125 -+ uintmax_t checkval;
7126 -+ double offset, seconds, f;
7127 -+
7128 -+ if (get_comp_type(&str, &result->kind))
7129 -+ {
7130 -+ /* Invert the sense of the comparison */
7131 -+ switch (result->kind)
7132 -+ {
7133 -+ case COMP_LT: result->kind = COMP_GT; break;
7134 -+ case COMP_GT: result->kind = COMP_LT; break;
7135 -+ default: break;
7136 -+ }
7137 -+
7138 -+ /* Convert the ASCII number into floating-point. */
7139 -+ if (xstrtod(str, NULL, &offset, strtod))
7140 -+ {
7141 -+ /* Separate the floating point number the user specified
7142 -+ * (which is a number of days, or minutes, etc) into an
7143 -+ * integral number of seconds (SECONDS) and a fraction (F).
7144 -+ */
7145 -+ f = modf(offset * sec_per_unit, &seconds);
7146 -+
7147 -+ result->ts.tv_sec = origin - seconds;
7148 -+ result->ts.tv_nsec = fabs(f * 1e9);
7149 -+
7150 -+ /* Check for overflow. */
7151 -+ checkval = (uintmax_t)origin - seconds;
7152 -+ if (checkval != result->ts.tv_sec)
7153 -+ {
7154 -+ /* an overflow has occurred. */
7155 -+ error (1, 0, overflowmessage, str);
7156 -+ }
7157 -+ return true;
7158 -+ }
7159 -+ else
7160 -+ {
7161 -+ /* Conversion from ASCII to double failed. */
7162 -+ return false;
7163 -+ }
7164 -+ }
7165 -+ else
7166 -+ {
7167 -+ return false;
7168 -+ }
7169 -+}
7170 -+
7171 -+/* Insert a time predicate based on the information in ENTRY.
7172 -+ ARGV is a pointer to the argument array.
7173 -+ ARG_PTR is a pointer to an index into the array, incremented if
7174 -+ all went well.
7175 -+
7176 -+ Return true if input is valid, false if not.
7177 -+
7178 -+ A new predicate node is assigned, along with an argument node
7179 -+ obtained with malloc.
7180 -+
7181 -+ Used by -atime, -ctime, and -mtime parsers. */
7182 -+
7183 -+static boolean
7184 -+parse_time (const struct parser_table* entry, char *argv[], int *arg_ptr)
7185 -+{
7186 -+ struct predicate *our_pred;
7187 -+ struct time_val tval;
7188 -+ enum comparison_type comp;
7189 -+ const char *timearg, *orig_timearg;
7190 -+ const char *errmsg = "arithmetic overflow while converting %s "
7191 -+ "days to a number of seconds";
7192 -+ time_t origin;
7193 -+
7194 -+ if (!collect_arg(argv, arg_ptr, &timearg))
7195 -+ return false;
7196 -+ orig_timearg = timearg;
7197 -+
7198 -+ /* Decide the origin by previewing the comparison type. */
7199 -+ origin = options.cur_day_start;
7200 -+
7201 -+ if (get_comp_type(&timearg, &comp))
7202 -+ {
7203 -+ /* Remember, we invert the sense of the comparison, so this tests
7204 -+ * against COMP_LT instead of COMP_GT...
7205 -+ */
7206 -+ if (COMP_LT == comp)
7207 -+ {
7208 -+ uintmax_t expected = origin + (DAYSECS-1);
7209 -+ origin += (DAYSECS-1);
7210 -+ if (origin != expected)
7211 -+ {
7212 -+ error(1, 0,
7213 -+ _("arithmetic overflow when trying to calculate the end of today"));
7214 -+ }
7215 -+ }
7216 -+ }
7217 -+ /* We discard the value of comp here, as get_relative_timestamp
7218 -+ * will set tval.kind. For that to work, we have to restore
7219 -+ * timearg so that it points to the +/- prefix, if any. get_comp_type()
7220 -+ * will have advanced timearg, so we restore it.
7221 -+ */
7222 -+ timearg = orig_timearg;
7223 -+
7224 -+ if (!get_relative_timestamp(timearg, &tval, origin, DAYSECS, errmsg))
7225 -+ return false;
7226 -+
7227 -+ our_pred = insert_primary (entry);
7228 -+ our_pred->args.reftime = tval;
7229 -+ our_pred->est_success_rate = estimate_timestamp_success_rate(tval.ts.tv_sec);
7230 -+
7231 -+ if (options.debug_options & DebugExpressionTree)
7232 -+ {
7233 -+ time_t t;
7234 -+
7235 -+ fprintf (stderr, "inserting %s\n", our_pred->p_name);
7236 -+ fprintf (stderr, " type: %s %s ",
7237 -+ (tval.kind == COMP_GT) ? "gt" :
7238 -+ ((tval.kind == COMP_LT) ? "lt" : ((tval.kind == COMP_EQ) ? "eq" : "?")),
7239 -+ (tval.kind == COMP_GT) ? " >" :
7240 -+ ((tval.kind == COMP_LT) ? " <" : ((tval.kind == COMP_EQ) ? ">=" : " ?")));
7241 -+ t = our_pred->args.reftime.ts.tv_sec;
7242 -+ fprintf (stderr, "%ju %s",
7243 -+ (uintmax_t) our_pred->args.reftime.ts.tv_sec,
7244 -+ ctime (&t));
7245 -+ if (tval.kind == COMP_EQ)
7246 -+ {
7247 -+ t = our_pred->args.reftime.ts.tv_sec + DAYSECS;
7248 -+ fprintf (stderr, " < %ju %s",
7249 -+ (uintmax_t) t, ctime (&t));
7250 -+ }
7251 -+ }
7252 -+
7253 -+ return true;
7254 -+}
7255 -+
7256 -+/* Get the comparison type prefix (if any) from a number argument.
7257 -+ The prefix is at *STR.
7258 -+ Set *COMP_TYPE to the kind of comparison that is requested.
7259 -+ Advance *STR beyond any initial comparison prefix.
7260 -+
7261 -+ Return true if all okay, false if input error. */
7262 -+static boolean
7263 -+get_comp_type(const char **str, enum comparison_type *comp_type)
7264 -+{
7265 -+ switch (**str)
7266 -+ {
7267 -+ case '+':
7268 -+ *comp_type = COMP_GT;
7269 -+ (*str)++;
7270 -+ break;
7271 -+ case '-':
7272 -+ *comp_type = COMP_LT;
7273 -+ (*str)++;
7274 -+ break;
7275 -+ default:
7276 -+ *comp_type = COMP_EQ;
7277 -+ break;
7278 -+ }
7279 -+ return true;
7280 -+}
7281 -+
7282 -+
7283 -+
7284 -+
7285 -+
7286 -+/* Get a number with comparison information.
7287 -+ The sense of the comparison information is 'normal'; that is,
7288 -+ '+' looks for a count > than the number and '-' less than.
7289 -+
7290 -+ STR is the ASCII representation of the number.
7291 -+ Set *NUM to the number.
7292 -+ Set *COMP_TYPE to the kind of comparison that is requested.
7293 -+
7294 -+ Return true if all okay, false if input error. */
7295 -+
7296 -+static boolean
7297 -+get_num (const char *str,
7298 -+ uintmax_t *num,
7299 -+ enum comparison_type *comp_type)
7300 -+{
7301 -+ char *pend;
7302 -+
7303 -+ if (str == NULL)
7304 -+ return false;
7305 -+
7306 -+ /* Figure out the comparison type if the caller accepts one. */
7307 -+ if (comp_type)
7308 -+ {
7309 -+ if (!get_comp_type(&str, comp_type))
7310 -+ return false;
7311 -+ }
7312 -+
7313 -+ return xstrtoumax (str, &pend, 10, num, "") == LONGINT_OK;
7314 -+}
7315 -+
7316 -+/* Insert a number predicate.
7317 -+ ARGV is a pointer to the argument array.
7318 -+ *ARG_PTR is an index into ARGV, incremented if all went well.
7319 -+ *PRED is the predicate processor to insert.
7320 -+
7321 -+ Return true if input is valid, false if error.
7322 -+
7323 -+ A new predicate node is assigned, along with an argument node
7324 -+ obtained with malloc.
7325 -+
7326 -+ Used by -inum and -links parsers. */
7327 -+
7328 -+static struct predicate *
7329 -+insert_num (char **argv, int *arg_ptr, const struct parser_table *entry)
7330 -+{
7331 -+ const char *numstr;
7332 -+
7333 -+ if (collect_arg(argv, arg_ptr, &numstr))
7334 -+ {
7335 -+ uintmax_t num;
7336 -+ enum comparison_type c_type;
7337 -+
7338 -+ if (get_num (numstr, &num, &c_type))
7339 -+ {
7340 -+ struct predicate *our_pred = insert_primary (entry);
7341 -+ our_pred->args.numinfo.kind = c_type;
7342 -+ our_pred->args.numinfo.l_val = num;
7343 -+
7344 -+ if (options.debug_options & DebugExpressionTree)
7345 -+ {
7346 -+ fprintf (stderr, "inserting %s\n", our_pred->p_name);
7347 -+ fprintf (stderr, " type: %s %s ",
7348 -+ (c_type == COMP_GT) ? "gt" :
7349 -+ ((c_type == COMP_LT) ? "lt" : ((c_type == COMP_EQ) ? "eq" : "?")),
7350 -+ (c_type == COMP_GT) ? " >" :
7351 -+ ((c_type == COMP_LT) ? " <" : ((c_type == COMP_EQ) ? " =" : " ?")));
7352 -+ fprintf (stderr, "%ju\n", our_pred->args.numinfo.l_val);
7353 -+ }
7354 -+ return our_pred;
7355 -+ }
7356 -+ }
7357 -+ return NULL;
7358 -+}
7359 -+
7360 -+static void
7361 -+open_output_file (const char *path, struct format_val *p)
7362 -+{
7363 -+ p->segment = NULL;
7364 -+ p->quote_opts = clone_quoting_options (NULL);
7365 -+
7366 -+ if (!strcmp (path, "/dev/stderr"))
7367 -+ {
7368 -+ p->stream = stderr;
7369 -+ p->filename = _("standard error");
7370 -+ }
7371 -+ else if (!strcmp (path, "/dev/stdout"))
7372 -+ {
7373 -+ p->stream = stdout;
7374 -+ p->filename = _("standard output");
7375 -+ }
7376 -+ else
7377 -+ {
7378 -+ p->stream = fopen_safer (path, "w");
7379 -+ p->filename = path;
7380 -+
7381 -+ if (p->stream == NULL)
7382 -+ {
7383 -+ fatal_file_error(path);
7384 -+ }
7385 -+ }
7386 -+
7387 -+ p->dest_is_tty = stream_is_tty(p->stream);
7388 -+}
7389 -+
7390 -+static void
7391 -+open_stdout (struct format_val *p)
7392 -+{
7393 -+ open_output_file("/dev/stdout", p);
7394 -+}
7395 -diff -purN findutils-4.3.12.orig/find/pred.c findutils-4.3.12/find/pred.c
7396 ---- findutils-4.3.12.orig/find/pred.c 2007-12-19 16:12:34.000000000 -0500
7397 -+++ findutils-4.3.12/find/pred.c 2008-01-30 08:46:05.758843847 -0500
7398 -@@ -47,6 +47,14 @@
7399 - #include "error.h"
7400 - #include "verify.h"
7401 -
7402 -+#ifdef WITH_SELINUX
7403 -+#include <selinux/selinux.h>
7404 -+#endif /*WITH_SELINUX*/
7405 -+
7406 -+#ifndef FNM_CASEFOLD
7407 -+#define FNM_CASEFOLD (1<<4)
7408 -+#endif /*FNM_CASEFOLD*/
7409 -+
7410 - #if ENABLE_NLS
7411 - # include <libintl.h>
7412 - # define _(Text) gettext (Text)
7413 -@@ -229,6 +237,9 @@ struct pred_assoc pred_table[] =
7414 - {pred_user, "user "},
7415 - {pred_writable, "writable "},
7416 - {pred_xtype, "xtype "},
7417 -+#ifdef WITH_SELINUX
7418 -+ {pred_scontext, "context"},
7419 -+#endif /*WITH_SELINUX*/
7420 - {0, "none "}
7421 - };
7422 - #endif
7423 -@@ -1045,6 +1056,26 @@ do_fprintf(struct format_val *dest,
7424 - mode_to_filetype(stat_buf->st_mode & S_IFMT));
7425 - }
7426 - break;
7427 -+#ifdef WITH_SELINUX
7428 -+ case 'Z': /* SELinux security context */
7429 -+ {
7430 -+ security_context_t scontext;
7431 -+ int rv;
7432 -+ rv = (*options.x_getfilecon)(state.rel_pathname, &scontext);
7433 -+
7434 -+ if ( rv < 0 ) {
7435 -+ fprintf(stderr, "getfileconf(%s): %s",
7436 -+ pathname, strerror(errno));
7437 -+ fflush(stderr);
7438 -+ }
7439 -+ else {
7440 -+ segment->text[segment->text_len] = 's';
7441 -+ checked_fprintf (dest, segment->text, scontext);
7442 -+ freecon(scontext);
7443 -+ }
7444 -+ }
7445 -+ break ;
7446 -+#endif /* WITH_SELINUX */
7447 - }
7448 - /* end of KIND_FORMAT case */
7449 - break;
7450 -@@ -1838,6 +1869,31 @@ pred_xtype (const char *pathname, struct
7451 - */
7452 - return (pred_type (pathname, &sbuf, pred_ptr));
7453 - }
7454 -+
7455 -+
7456 -+#ifdef WITH_SELINUX
7457 -+
7458 -+boolean
7459 -+pred_scontext (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
7460 -+{
7461 -+ int rv;
7462 -+ security_context_t scontext;
7463 -+
7464 -+ rv = (* options.x_getfilecon)(state.rel_pathname, &scontext);
7465 -+
7466 -+ if ( rv < 0 ) {
7467 -+ (void) fprintf(stderr, "getfilecon(%s): %s\n", pathname, strerror(errno));
7468 -+ (void) fflush(stderr);
7469 -+ return ( false );
7470 -+ }
7471 -+
7472 -+ rv = (fnmatch(pred_ptr->args.scontext, scontext,0)==0);
7473 -+ freecon(scontext);
7474 -+ return rv;
7475 -+}
7476 -+
7477 -+#endif /*WITH_SELINUX*/
7478 -+
7479 -
7480 - /* 1) fork to get a child; parent remembers the child pid
7481 - 2) child execs the command requested
7482 -diff -purN findutils-4.3.12.orig/find/pred.c.orig findutils-4.3.12/find/pred.c.orig
7483 ---- findutils-4.3.12.orig/find/pred.c.orig 1969-12-31 19:00:00.000000000 -0500
7484 -+++ findutils-4.3.12/find/pred.c.orig 2007-12-19 16:12:34.000000000 -0500
7485 -@@ -0,0 +1,2405 @@
7486 -+/* pred.c -- execute the expression tree.
7487 -+ Copyright (C) 1990, 1991, 1992, 1993, 1994, 2000, 2003,
7488 -+ 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
7489 -+
7490 -+ This program is free software: you can redistribute it and/or modify
7491 -+ it under the terms of the GNU General Public License as published by
7492 -+ the Free Software Foundation, either version 3 of the License, or
7493 -+ (at your option) any later version.
7494 -+
7495 -+ This program is distributed in the hope that it will be useful,
7496 -+ but WITHOUT ANY WARRANTY; without even the implied warranty of
7497 -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
7498 -+ GNU General Public License for more details.
7499 -+
7500 -+ You should have received a copy of the GNU General Public License
7501 -+ along with this program. If not, see <http://www.gnu.org/licenses/>.
7502 -+*/
7503 -+
7504 -+#include <config.h>
7505 -+#include "defs.h"
7506 -+
7507 -+#include <fnmatch.h>
7508 -+#include <signal.h>
7509 -+#include <math.h>
7510 -+#include <pwd.h>
7511 -+#include <grp.h>
7512 -+#include <sys/types.h>
7513 -+#include <sys/stat.h>
7514 -+#include <errno.h>
7515 -+#include <assert.h>
7516 -+#include <stdarg.h>
7517 -+#include <fcntl.h>
7518 -+#include <locale.h>
7519 -+#include <openat.h>
7520 -+#include "xalloc.h"
7521 -+#include "dirname.h"
7522 -+#include "human.h"
7523 -+#include "modetype.h"
7524 -+#include "filemode.h"
7525 -+#include "wait.h"
7526 -+#include "printquoted.h"
7527 -+#include "buildcmd.h"
7528 -+#include "yesno.h"
7529 -+#include "listfile.h"
7530 -+#include "stat-time.h"
7531 -+#include "dircallback.h"
7532 -+#include "error.h"
7533 -+#include "verify.h"
7534 -+
7535 -+#if ENABLE_NLS
7536 -+# include <libintl.h>
7537 -+# define _(Text) gettext (Text)
7538 -+#else
7539 -+# define _(Text) Text
7540 -+#endif
7541 -+#ifdef gettext_noop
7542 -+# define N_(String) gettext_noop (String)
7543 -+#else
7544 -+/* See locate.c for explanation as to why not use (String) */
7545 -+# define N_(String) String
7546 -+#endif
7547 -+
7548 -+#if !defined(SIGCHLD) && defined(SIGCLD)
7549 -+#define SIGCHLD SIGCLD
7550 -+#endif
7551 -+
7552 -+
7553 -+
7554 -+#if HAVE_DIRENT_H
7555 -+# include <dirent.h>
7556 -+# define NAMLEN(dirent) strlen((dirent)->d_name)
7557 -+#else
7558 -+# define dirent direct
7559 -+# define NAMLEN(dirent) (dirent)->d_namlen
7560 -+# if HAVE_SYS_NDIR_H
7561 -+# include <sys/ndir.h>
7562 -+# endif
7563 -+# if HAVE_SYS_DIR_H
7564 -+# include <sys/dir.h>
7565 -+# endif
7566 -+# if HAVE_NDIR_H
7567 -+# include <ndir.h>
7568 -+# endif
7569 -+#endif
7570 -+
7571 -+#ifdef CLOSEDIR_VOID
7572 -+/* Fake a return value. */
7573 -+#define CLOSEDIR(d) (closedir (d), 0)
7574 -+#else
7575 -+#define CLOSEDIR(d) closedir (d)
7576 -+#endif
7577 -+
7578 -+
7579 -+
7580 -+
7581 -+/* Get or fake the disk device blocksize.
7582 -+ Usually defined by sys/param.h (if at all). */
7583 -+#ifndef DEV_BSIZE
7584 -+# ifdef BSIZE
7585 -+# define DEV_BSIZE BSIZE
7586 -+# else /* !BSIZE */
7587 -+# define DEV_BSIZE 4096
7588 -+# endif /* !BSIZE */
7589 -+#endif /* !DEV_BSIZE */
7590 -+
7591 -+/* Extract or fake data from a `struct stat'.
7592 -+ ST_BLKSIZE: Preferred I/O blocksize for the file, in bytes.
7593 -+ ST_NBLOCKS: Number of blocks in the file, including indirect blocks.
7594 -+ ST_NBLOCKSIZE: Size of blocks used when calculating ST_NBLOCKS. */
7595 -+#ifndef HAVE_STRUCT_STAT_ST_BLOCKS
7596 -+# define ST_BLKSIZE(statbuf) DEV_BSIZE
7597 -+# if defined _POSIX_SOURCE || !defined BSIZE /* fileblocks.c uses BSIZE. */
7598 -+# define ST_NBLOCKS(statbuf) \
7599 -+ (S_ISREG ((statbuf).st_mode) \
7600 -+ || S_ISDIR ((statbuf).st_mode) \
7601 -+ ? (statbuf).st_size / ST_NBLOCKSIZE + ((statbuf).st_size % ST_NBLOCKSIZE != 0) : 0)
7602 -+# else /* !_POSIX_SOURCE && BSIZE */
7603 -+# define ST_NBLOCKS(statbuf) \
7604 -+ (S_ISREG ((statbuf).st_mode) \
7605 -+ || S_ISDIR ((statbuf).st_mode) \
7606 -+ ? st_blocks ((statbuf).st_size) : 0)
7607 -+# endif /* !_POSIX_SOURCE && BSIZE */
7608 -+#else /* HAVE_STRUCT_STAT_ST_BLOCKS */
7609 -+/* Some systems, like Sequents, return st_blksize of 0 on pipes. */
7610 -+# define ST_BLKSIZE(statbuf) ((statbuf).st_blksize > 0 \
7611 -+ ? (statbuf).st_blksize : DEV_BSIZE)
7612 -+# if defined hpux || defined __hpux__ || defined __hpux
7613 -+/* HP-UX counts st_blocks in 1024-byte units.
7614 -+ This loses when mixing HP-UX and BSD file systems with NFS. */
7615 -+# define ST_NBLOCKSIZE 1024
7616 -+# else /* !hpux */
7617 -+# if defined _AIX && defined _I386
7618 -+/* AIX PS/2 counts st_blocks in 4K units. */
7619 -+# define ST_NBLOCKSIZE (4 * 1024)
7620 -+# else /* not AIX PS/2 */
7621 -+# if defined _CRAY
7622 -+# define ST_NBLOCKS(statbuf) \
7623 -+ (S_ISREG ((statbuf).st_mode) \
7624 -+ || S_ISDIR ((statbuf).st_mode) \
7625 -+ ? (statbuf).st_blocks * ST_BLKSIZE(statbuf)/ST_NBLOCKSIZE : 0)
7626 -+# endif /* _CRAY */
7627 -+# endif /* not AIX PS/2 */
7628 -+# endif /* !hpux */
7629 -+#endif /* HAVE_STRUCT_STAT_ST_BLOCKS */
7630 -+
7631 -+#ifndef ST_NBLOCKS
7632 -+# define ST_NBLOCKS(statbuf) \
7633 -+ (S_ISREG ((statbuf).st_mode) \
7634 -+ || S_ISDIR ((statbuf).st_mode) \
7635 -+ ? (statbuf).st_blocks : 0)
7636 -+#endif
7637 -+
7638 -+#ifndef ST_NBLOCKSIZE
7639 -+# define ST_NBLOCKSIZE 512
7640 -+#endif
7641 -+
7642 -+
7643 -+#undef MAX
7644 -+#define MAX(a, b) ((a) > (b) ? (a) : (b))
7645 -+
7646 -+static boolean match_lname PARAMS((const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr, boolean ignore_case));
7647 -+
7648 -+static char *format_date PARAMS((struct timespec ts, int kind));
7649 -+static char *ctime_format PARAMS((struct timespec ts));
7650 -+
7651 -+#ifdef DEBUG
7652 -+struct pred_assoc
7653 -+{
7654 -+ PRED_FUNC pred_func;
7655 -+ char *pred_name;
7656 -+};
7657 -+
7658 -+struct pred_assoc pred_table[] =
7659 -+{
7660 -+ {pred_amin, "amin "},
7661 -+ {pred_and, "and "},
7662 -+ {pred_anewer, "anewer "},
7663 -+ {pred_atime, "atime "},
7664 -+ {pred_closeparen, ") "},
7665 -+ {pred_cmin, "cmin "},
7666 -+ {pred_cnewer, "cnewer "},
7667 -+ {pred_comma, ", "},
7668 -+ {pred_ctime, "ctime "},
7669 -+ {pred_delete, "delete "},
7670 -+ {pred_empty, "empty "},
7671 -+ {pred_exec, "exec "},
7672 -+ {pred_execdir, "execdir "},
7673 -+ {pred_executable, "executable "},
7674 -+ {pred_false, "false "},
7675 -+ {pred_fprint, "fprint "},
7676 -+ {pred_fprint0, "fprint0 "},
7677 -+ {pred_fprintf, "fprintf "},
7678 -+ {pred_fstype, "fstype "},
7679 -+ {pred_gid, "gid "},
7680 -+ {pred_group, "group "},
7681 -+ {pred_ilname, "ilname "},
7682 -+ {pred_iname, "iname "},
7683 -+ {pred_inum, "inum "},
7684 -+ {pred_ipath, "ipath "},
7685 -+ {pred_links, "links "},
7686 -+ {pred_lname, "lname "},
7687 -+ {pred_ls, "ls "},
7688 -+ {pred_mmin, "mmin "},
7689 -+ {pred_mtime, "mtime "},
7690 -+ {pred_name, "name "},
7691 -+ {pred_negate, "not "},
7692 -+ {pred_newer, "newer "},
7693 -+ {pred_newerXY, "newerXY "},
7694 -+ {pred_nogroup, "nogroup "},
7695 -+ {pred_nouser, "nouser "},
7696 -+ {pred_ok, "ok "},
7697 -+ {pred_okdir, "okdir "},
7698 -+ {pred_openparen, "( "},
7699 -+ {pred_or, "or "},
7700 -+ {pred_path, "path "},
7701 -+ {pred_perm, "perm "},
7702 -+ {pred_print, "print "},
7703 -+ {pred_print0, "print0 "},
7704 -+ {pred_prune, "prune "},
7705 -+ {pred_quit, "quit "},
7706 -+ {pred_readable, "readable "},
7707 -+ {pred_regex, "regex "},
7708 -+ {pred_samefile,"samefile "},
7709 -+ {pred_size, "size "},
7710 -+ {pred_true, "true "},
7711 -+ {pred_type, "type "},
7712 -+ {pred_uid, "uid "},
7713 -+ {pred_used, "used "},
7714 -+ {pred_user, "user "},
7715 -+ {pred_writable, "writable "},
7716 -+ {pred_xtype, "xtype "},
7717 -+ {0, "none "}
7718 -+};
7719 -+#endif
7720 -+
7721 -+/* Returns ts1 - ts2 */
7722 -+static double ts_difference(struct timespec ts1,
7723 -+ struct timespec ts2)
7724 -+{
7725 -+ double d = difftime(ts1.tv_sec, ts2.tv_sec)
7726 -+ + (1.0e-9 * (ts1.tv_nsec - ts2.tv_nsec));
7727 -+ return d;
7728 -+}
7729 -+
7730 -+
7731 -+static int
7732 -+compare_ts(struct timespec ts1,
7733 -+ struct timespec ts2)
7734 -+{
7735 -+ if ((ts1.tv_sec == ts2.tv_sec) &&
7736 -+ (ts1.tv_nsec == ts2.tv_nsec))
7737 -+ {
7738 -+ return 0;
7739 -+ }
7740 -+ else
7741 -+ {
7742 -+ double diff = ts_difference(ts1, ts2);
7743 -+ return diff < 0.0 ? -1 : +1;
7744 -+ }
7745 -+}
7746 -+
7747 -+/* Predicate processing routines.
7748 -+
7749 -+ PATHNAME is the full pathname of the file being checked.
7750 -+ *STAT_BUF contains information about PATHNAME.
7751 -+ *PRED_PTR contains information for applying the predicate.
7752 -+
7753 -+ Return true if the file passes this predicate, false if not. */
7754 -+
7755 -+
7756 -+/* pred_timewindow
7757 -+ *
7758 -+ * Returns true if THE_TIME is
7759 -+ * COMP_GT: after the specified time
7760 -+ * COMP_LT: before the specified time
7761 -+ * COMP_EQ: less than WINDOW seconds after the specified time.
7762 -+ */
7763 -+static boolean
7764 -+pred_timewindow(struct timespec ts, struct predicate const *pred_ptr, int window)
7765 -+{
7766 -+ switch (pred_ptr->args.reftime.kind)
7767 -+ {
7768 -+ case COMP_GT:
7769 -+ return compare_ts(ts, pred_ptr->args.reftime.ts) > 0;
7770 -+
7771 -+ case COMP_LT:
7772 -+ return compare_ts(ts, pred_ptr->args.reftime.ts) < 0;
7773 -+
7774 -+ case COMP_EQ:
7775 -+ {
7776 -+ double delta = ts_difference(ts, pred_ptr->args.reftime.ts);
7777 -+ return (delta >= 0.0 && delta < window);
7778 -+ }
7779 -+ }
7780 -+ assert (0);
7781 -+ abort ();
7782 -+}
7783 -+
7784 -+
7785 -+boolean
7786 -+pred_amin (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
7787 -+{
7788 -+ (void) &pathname;
7789 -+ return pred_timewindow(get_stat_atime(stat_buf), pred_ptr, 60);
7790 -+}
7791 -+
7792 -+boolean
7793 -+pred_and (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
7794 -+{
7795 -+ if (pred_ptr->pred_left == NULL
7796 -+ || apply_predicate(pathname, stat_buf, pred_ptr->pred_left))
7797 -+ {
7798 -+ return apply_predicate(pathname, stat_buf, pred_ptr->pred_right);
7799 -+ }
7800 -+ else
7801 -+ return false;
7802 -+}
7803 -+
7804 -+boolean
7805 -+pred_anewer (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
7806 -+{
7807 -+ (void) &pathname;
7808 -+ assert (COMP_GT == pred_ptr->args.reftime.kind);
7809 -+ return compare_ts(get_stat_atime(stat_buf), pred_ptr->args.reftime.ts) > 0;
7810 -+}
7811 -+
7812 -+boolean
7813 -+pred_atime (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
7814 -+{
7815 -+ (void) &pathname;
7816 -+ return pred_timewindow(get_stat_atime(stat_buf), pred_ptr, DAYSECS);
7817 -+}
7818 -+
7819 -+boolean
7820 -+pred_closeparen (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
7821 -+{
7822 -+ (void) &pathname;
7823 -+ (void) &stat_buf;
7824 -+ (void) &pred_ptr;
7825 -+
7826 -+ return true;
7827 -+}
7828 -+
7829 -+boolean
7830 -+pred_cmin (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
7831 -+{
7832 -+ (void) pathname;
7833 -+ return pred_timewindow(get_stat_ctime(stat_buf), pred_ptr, 60);
7834 -+}
7835 -+
7836 -+boolean
7837 -+pred_cnewer (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
7838 -+{
7839 -+ (void) pathname;
7840 -+
7841 -+ assert (COMP_GT == pred_ptr->args.reftime.kind);
7842 -+ return compare_ts(get_stat_ctime(stat_buf), pred_ptr->args.reftime.ts) > 0;
7843 -+}
7844 -+
7845 -+boolean
7846 -+pred_comma (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
7847 -+{
7848 -+ if (pred_ptr->pred_left != NULL)
7849 -+ {
7850 -+ apply_predicate(pathname, stat_buf,pred_ptr->pred_left);
7851 -+ }
7852 -+ return apply_predicate(pathname, stat_buf, pred_ptr->pred_right);
7853 -+}
7854 -+
7855 -+boolean
7856 -+pred_ctime (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
7857 -+{
7858 -+ (void) &pathname;
7859 -+ return pred_timewindow(get_stat_ctime(stat_buf), pred_ptr, DAYSECS);
7860 -+}
7861 -+
7862 -+static boolean
7863 -+perform_delete(int flags)
7864 -+{
7865 -+ return 0 == unlinkat(state.cwd_dir_fd, state.rel_pathname, flags);
7866 -+}
7867 -+
7868 -+
7869 -+boolean
7870 -+pred_delete (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
7871 -+{
7872 -+ (void) pred_ptr;
7873 -+ (void) stat_buf;
7874 -+ if (strcmp (state.rel_pathname, "."))
7875 -+ {
7876 -+ int flags=0;
7877 -+ if (state.have_stat && S_ISDIR(stat_buf->st_mode))
7878 -+ flags |= AT_REMOVEDIR;
7879 -+ if (perform_delete(flags))
7880 -+ {
7881 -+ return true;
7882 -+ }
7883 -+ else
7884 -+ {
7885 -+ if (EISDIR == errno)
7886 -+ {
7887 -+ if ((flags & AT_REMOVEDIR) == 0)
7888 -+ {
7889 -+ /* unlink() operation failed because we should have done rmdir(). */
7890 -+ flags |= AT_REMOVEDIR;
7891 -+ if (perform_delete(flags))
7892 -+ return true;
7893 -+ }
7894 -+ }
7895 -+ }
7896 -+ error (0, errno, _("cannot delete %s"
7897 -+ /* TRANSLATORS: the argument is either a
7898 -+ * file or a directory, but we do not know which.
7899 -+ * Mail bug-findutils@×××.org if you cannot correctly
7900 -+ * translate the string without knowing.
7901 -+ */),
7902 -+ safely_quote_err_filename(0, pathname));
7903 -+ /* Previously I had believed that having the -delete action
7904 -+ * return false provided the user with control over whether an
7905 -+ * error message is issued. While this is true, the policy of
7906 -+ * not affecting the exit status is contrary to the POSIX
7907 -+ * requirement that diagnostic messages are accompanied by a
7908 -+ * nonzero exit status. While -delete is not a POSIX option and
7909 -+ * we can therefore opt not to follow POSIX in this case, that
7910 -+ * seems somewhat arbitrary and confusing. So, as of
7911 -+ * findutils-4.3.11, we also set the exit status in this case.
7912 -+ */
7913 -+ state.exit_status = 1;
7914 -+ return false;
7915 -+ }
7916 -+ else
7917 -+ {
7918 -+ /* nothing to do. */
7919 -+ return true;
7920 -+ }
7921 -+}
7922 -+
7923 -+boolean
7924 -+pred_empty (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
7925 -+{
7926 -+ (void) pathname;
7927 -+ (void) pred_ptr;
7928 -+
7929 -+ if (S_ISDIR (stat_buf->st_mode))
7930 -+ {
7931 -+ int fd;
7932 -+ DIR *d;
7933 -+ struct dirent *dp;
7934 -+ boolean empty = true;
7935 -+
7936 -+ errno = 0;
7937 -+ if ((fd = openat(state.cwd_dir_fd, state.rel_pathname, O_RDONLY
7938 -+#if defined O_LARGEFILE
7939 -+ |O_LARGEFILE
7940 -+#endif
7941 -+ )) < 0)
7942 -+ {
7943 -+ error (0, errno, "%s", safely_quote_err_filename(0, pathname));
7944 -+ state.exit_status = 1;
7945 -+ return false;
7946 -+ }
7947 -+ d = fdopendir (fd);
7948 -+ if (d == NULL)
7949 -+ {
7950 -+ error (0, errno, "%s", safely_quote_err_filename(0, pathname));
7951 -+ state.exit_status = 1;
7952 -+ return false;
7953 -+ }
7954 -+ for (dp = readdir (d); dp; dp = readdir (d))
7955 -+ {
7956 -+ if (dp->d_name[0] != '.'
7957 -+ || (dp->d_name[1] != '\0'
7958 -+ && (dp->d_name[1] != '.' || dp->d_name[2] != '\0')))
7959 -+ {
7960 -+ empty = false;
7961 -+ break;
7962 -+ }
7963 -+ }
7964 -+ if (CLOSEDIR (d))
7965 -+ {
7966 -+ error (0, errno, "%s", safely_quote_err_filename(0, pathname));
7967 -+ state.exit_status = 1;
7968 -+ return false;
7969 -+ }
7970 -+ return (empty);
7971 -+ }
7972 -+ else if (S_ISREG (stat_buf->st_mode))
7973 -+ return (stat_buf->st_size == 0);
7974 -+ else
7975 -+ return (false);
7976 -+}
7977 -+
7978 -+static boolean
7979 -+new_impl_pred_exec (int dirfd, const char *pathname,
7980 -+ struct stat *stat_buf,
7981 -+ struct predicate *pred_ptr,
7982 -+ const char *prefix, size_t pfxlen)
7983 -+{
7984 -+ struct exec_val *execp = &pred_ptr->args.exec_vec;
7985 -+ size_t len = strlen(pathname);
7986 -+
7987 -+ (void) stat_buf;
7988 -+ execp->dirfd = dirfd;
7989 -+ if (execp->multiple)
7990 -+ {
7991 -+ /* Push the argument onto the current list.
7992 -+ * The command may or may not be run at this point,
7993 -+ * depending on the command line length limits.
7994 -+ */
7995 -+ bc_push_arg(&execp->ctl,
7996 -+ &execp->state,
7997 -+ pathname, len+1,
7998 -+ prefix, pfxlen,
7999 -+ 0);
8000 -+
8001 -+ /* remember that there are pending execdirs. */
8002 -+ state.execdirs_outstanding = true;
8003 -+
8004 -+ /* POSIX: If the primary expression is punctuated by a plus
8005 -+ * sign, the primary shall always evaluate as true
8006 -+ */
8007 -+ return true;
8008 -+ }
8009 -+ else
8010 -+ {
8011 -+ int i;
8012 -+
8013 -+ for (i=0; i<execp->num_args; ++i)
8014 -+ {
8015 -+ bc_do_insert(&execp->ctl,
8016 -+ &execp->state,
8017 -+ execp->replace_vec[i],
8018 -+ strlen(execp->replace_vec[i]),
8019 -+ prefix, pfxlen,
8020 -+ pathname, len,
8021 -+ 0);
8022 -+ }
8023 -+
8024 -+ /* Actually invoke the command. */
8025 -+ return execp->ctl.exec_callback(&execp->ctl,
8026 -+ &execp->state);
8027 -+ }
8028 -+}
8029 -+
8030 -+
8031 -+boolean
8032 -+pred_exec (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
8033 -+{
8034 -+ return new_impl_pred_exec(get_start_dirfd(),
8035 -+ pathname, stat_buf, pred_ptr, NULL, 0);
8036 -+}
8037 -+
8038 -+boolean
8039 -+pred_execdir (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
8040 -+{
8041 -+ const char *prefix = (state.rel_pathname[0] == '/') ? NULL : "./";
8042 -+ (void) &pathname;
8043 -+ return new_impl_pred_exec (get_current_dirfd(),
8044 -+ state.rel_pathname, stat_buf, pred_ptr,
8045 -+ prefix, (prefix ? 2 : 0));
8046 -+}
8047 -+
8048 -+boolean
8049 -+pred_false (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
8050 -+{
8051 -+ (void) &pathname;
8052 -+ (void) &stat_buf;
8053 -+ (void) &pred_ptr;
8054 -+
8055 -+
8056 -+ return (false);
8057 -+}
8058 -+
8059 -+boolean
8060 -+pred_fls (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
8061 -+{
8062 -+ FILE * stream = pred_ptr->args.printf_vec.stream;
8063 -+ list_file (pathname, state.cwd_dir_fd, state.rel_pathname, stat_buf,
8064 -+ options.start_time.tv_sec,
8065 -+ options.output_block_size,
8066 -+ pred_ptr->literal_control_chars, stream);
8067 -+ return true;
8068 -+}
8069 -+
8070 -+boolean
8071 -+pred_fprint (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
8072 -+{
8073 -+ (void) &pathname;
8074 -+ (void) &stat_buf;
8075 -+
8076 -+ print_quoted(pred_ptr->args.printf_vec.stream,
8077 -+ pred_ptr->args.printf_vec.quote_opts,
8078 -+ pred_ptr->args.printf_vec.dest_is_tty,
8079 -+ "%s\n",
8080 -+ pathname);
8081 -+ return true;
8082 -+}
8083 -+
8084 -+boolean
8085 -+pred_fprint0 (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
8086 -+{
8087 -+ FILE * fp = pred_ptr->args.printf_vec.stream;
8088 -+
8089 -+ (void) &stat_buf;
8090 -+
8091 -+ fputs (pathname, fp);
8092 -+ putc (0, fp);
8093 -+ return true;
8094 -+}
8095 -+
8096 -+
8097 -+
8098 -+static char*
8099 -+mode_to_filetype(mode_t m)
8100 -+{
8101 -+#define HANDLE_TYPE(t,letter) if (m==t) { return letter; }
8102 -+#ifdef S_IFREG
8103 -+ HANDLE_TYPE(S_IFREG, "f"); /* regular file */
8104 -+#endif
8105 -+#ifdef S_IFDIR
8106 -+ HANDLE_TYPE(S_IFDIR, "d"); /* directory */
8107 -+#endif
8108 -+#ifdef S_IFLNK
8109 -+ HANDLE_TYPE(S_IFLNK, "l"); /* symbolic link */
8110 -+#endif
8111 -+#ifdef S_IFSOCK
8112 -+ HANDLE_TYPE(S_IFSOCK, "s"); /* Unix domain socket */
8113 -+#endif
8114 -+#ifdef S_IFBLK
8115 -+ HANDLE_TYPE(S_IFBLK, "b"); /* block device */
8116 -+#endif
8117 -+#ifdef S_IFCHR
8118 -+ HANDLE_TYPE(S_IFCHR, "c"); /* character device */
8119 -+#endif
8120 -+#ifdef S_IFIFO
8121 -+ HANDLE_TYPE(S_IFIFO, "p"); /* FIFO */
8122 -+#endif
8123 -+#ifdef S_IFDOOR
8124 -+ HANDLE_TYPE(S_IFDOOR, "D"); /* Door (e.g. on Solaris) */
8125 -+#endif
8126 -+ return "U"; /* Unknown */
8127 -+}
8128 -+
8129 -+static double
8130 -+file_sparseness(const struct stat *p)
8131 -+{
8132 -+#if defined HAVE_STRUCT_STAT_ST_BLOCKS
8133 -+ if (0 == p->st_size)
8134 -+ {
8135 -+ if (0 == p->st_blocks)
8136 -+ return 1.0;
8137 -+ else
8138 -+ return p->st_blocks < 0 ? -HUGE_VAL : HUGE_VAL;
8139 -+ }
8140 -+ else
8141 -+ {
8142 -+ double blklen = file_blocksize(p) * (double)p->st_blocks;
8143 -+ return blklen / p->st_size;
8144 -+ }
8145 -+#else
8146 -+ return 1.0;
8147 -+#endif
8148 -+}
8149 -+
8150 -+
8151 -+
8152 -+static void
8153 -+checked_fprintf(struct format_val *dest, const char *fmt, ...)
8154 -+{
8155 -+ int rv;
8156 -+ va_list ap;
8157 -+
8158 -+ va_start(ap, fmt);
8159 -+ rv = vfprintf(dest->stream, fmt, ap);
8160 -+ if (rv < 0)
8161 -+ nonfatal_file_error(dest->filename);
8162 -+}
8163 -+
8164 -+
8165 -+static void
8166 -+checked_print_quoted (struct format_val *dest,
8167 -+ const char *format, const char *s)
8168 -+{
8169 -+ int rv = print_quoted(dest->stream, dest->quote_opts, dest->dest_is_tty,
8170 -+ format, s);
8171 -+ if (rv < 0)
8172 -+ nonfatal_file_error(dest->filename);
8173 -+}
8174 -+
8175 -+
8176 -+static void
8177 -+checked_fwrite(void *p, size_t siz, size_t nmemb, struct format_val *dest)
8178 -+{
8179 -+ int items_written = fwrite(p, siz, nmemb, dest->stream);
8180 -+ if (items_written < nmemb)
8181 -+ nonfatal_file_error(dest->filename);
8182 -+}
8183 -+
8184 -+static void
8185 -+checked_fflush(struct format_val *dest)
8186 -+{
8187 -+ if (0 != fflush(dest->stream))
8188 -+ {
8189 -+ nonfatal_file_error(dest->filename);
8190 -+ }
8191 -+}
8192 -+
8193 -+static void
8194 -+do_fprintf(struct format_val *dest,
8195 -+ struct segment *segment,
8196 -+ const char *pathname,
8197 -+ const struct stat *stat_buf)
8198 -+{
8199 -+ char hbuf[LONGEST_HUMAN_READABLE + 1];
8200 -+ const char *cp;
8201 -+
8202 -+ switch (segment->segkind)
8203 -+ {
8204 -+ case KIND_PLAIN: /* Plain text string (no % conversion). */
8205 -+ /* trusted */
8206 -+ checked_fwrite(segment->text, 1, segment->text_len, dest);
8207 -+ break;
8208 -+
8209 -+ case KIND_STOP: /* Terminate argument and flush output. */
8210 -+ /* trusted */
8211 -+ checked_fwrite(segment->text, 1, segment->text_len, dest);
8212 -+ checked_fflush(dest);
8213 -+ break;
8214 -+
8215 -+ case KIND_FORMAT:
8216 -+ switch (segment->format_char[0])
8217 -+ {
8218 -+ case 'a': /* atime in `ctime' format. */
8219 -+ /* UNTRUSTED, probably unexploitable */
8220 -+ checked_fprintf (dest, segment->text, ctime_format (get_stat_atime(stat_buf)));
8221 -+ break;
8222 -+ case 'b': /* size in 512-byte blocks */
8223 -+ /* UNTRUSTED, probably unexploitable */
8224 -+ checked_fprintf (dest, segment->text,
8225 -+ human_readable ((uintmax_t) ST_NBLOCKS (*stat_buf),
8226 -+ hbuf, human_ceiling,
8227 -+ ST_NBLOCKSIZE, 512));
8228 -+ break;
8229 -+ case 'c': /* ctime in `ctime' format */
8230 -+ /* UNTRUSTED, probably unexploitable */
8231 -+ checked_fprintf (dest, segment->text, ctime_format (get_stat_ctime(stat_buf)));
8232 -+ break;
8233 -+ case 'd': /* depth in search tree */
8234 -+ /* UNTRUSTED, probably unexploitable */
8235 -+ checked_fprintf (dest, segment->text, state.curdepth);
8236 -+ break;
8237 -+ case 'D': /* Device on which file exists (stat.st_dev) */
8238 -+ /* trusted */
8239 -+ checked_fprintf (dest, segment->text,
8240 -+ human_readable ((uintmax_t) stat_buf->st_dev, hbuf,
8241 -+ human_ceiling, 1, 1));
8242 -+ break;
8243 -+ case 'f': /* base name of path */
8244 -+ /* sanitised */
8245 -+ {
8246 -+ char *base = base_name (pathname);
8247 -+ checked_print_quoted (dest, segment->text, base);
8248 -+ free (base);
8249 -+ }
8250 -+ break;
8251 -+ case 'F': /* file system type */
8252 -+ /* trusted */
8253 -+ checked_print_quoted (dest, segment->text, filesystem_type (stat_buf, pathname));
8254 -+ break;
8255 -+ case 'g': /* group name */
8256 -+ /* trusted */
8257 -+ /* (well, the actual group is selected by the user but
8258 -+ * its name was selected by the system administrator)
8259 -+ */
8260 -+ {
8261 -+ struct group *g;
8262 -+
8263 -+ g = getgrgid (stat_buf->st_gid);
8264 -+ if (g)
8265 -+ {
8266 -+ segment->text[segment->text_len] = 's';
8267 -+ checked_fprintf (dest, segment->text, g->gr_name);
8268 -+ break;
8269 -+ }
8270 -+ else
8271 -+ {
8272 -+ /* Do nothing. */
8273 -+ /*FALLTHROUGH*/
8274 -+ }
8275 -+ }
8276 -+ /*FALLTHROUGH*/ /*...sometimes, so 'G' case.*/
8277 -+
8278 -+ case 'G': /* GID number */
8279 -+ /* UNTRUSTED, probably unexploitable */
8280 -+ checked_fprintf (dest, segment->text,
8281 -+ human_readable ((uintmax_t) stat_buf->st_gid, hbuf,
8282 -+ human_ceiling, 1, 1));
8283 -+ break;
8284 -+ case 'h': /* leading directories part of path */
8285 -+ /* sanitised */
8286 -+ {
8287 -+ cp = strrchr (pathname, '/');
8288 -+ if (cp == NULL) /* No leading directories. */
8289 -+ {
8290 -+ /* If there is no slash in the pathname, we still
8291 -+ * print the string because it contains characters
8292 -+ * other than just '%s'. The %h expands to ".".
8293 -+ */
8294 -+ checked_print_quoted (dest, segment->text, ".");
8295 -+ }
8296 -+ else
8297 -+ {
8298 -+ char *s = strdup(pathname);
8299 -+ s[cp - pathname] = 0;
8300 -+ checked_print_quoted (dest, segment->text, s);
8301 -+ free(s);
8302 -+ }
8303 -+ }
8304 -+ break;
8305 -+
8306 -+ case 'H': /* ARGV element file was found under */
8307 -+ /* trusted */
8308 -+ {
8309 -+ char *s = xmalloc(state.starting_path_length+1);
8310 -+ memcpy(s, pathname, state.starting_path_length);
8311 -+ s[state.starting_path_length] = 0;
8312 -+ checked_fprintf (dest, segment->text, s);
8313 -+ free(s);
8314 -+ }
8315 -+ break;
8316 -+
8317 -+ case 'i': /* inode number */
8318 -+ /* UNTRUSTED, but not exploitable I think */
8319 -+ checked_fprintf (dest, segment->text,
8320 -+ human_readable ((uintmax_t) stat_buf->st_ino, hbuf,
8321 -+ human_ceiling,
8322 -+ 1, 1));
8323 -+ break;
8324 -+ case 'k': /* size in 1K blocks */
8325 -+ /* UNTRUSTED, but not exploitable I think */
8326 -+ checked_fprintf (dest, segment->text,
8327 -+ human_readable ((uintmax_t) ST_NBLOCKS (*stat_buf),
8328 -+ hbuf, human_ceiling,
8329 -+ ST_NBLOCKSIZE, 1024));
8330 -+ break;
8331 -+ case 'l': /* object of symlink */
8332 -+ /* sanitised */
8333 -+#ifdef S_ISLNK
8334 -+ {
8335 -+ char *linkname = 0;
8336 -+
8337 -+ if (S_ISLNK (stat_buf->st_mode))
8338 -+ {
8339 -+ linkname = get_link_name_at (pathname, state.cwd_dir_fd, state.rel_pathname);
8340 -+ if (linkname == 0)
8341 -+ state.exit_status = 1;
8342 -+ }
8343 -+ if (linkname)
8344 -+ {
8345 -+ checked_print_quoted (dest, segment->text, linkname);
8346 -+ free (linkname);
8347 -+ }
8348 -+ else
8349 -+ {
8350 -+ /* We still need to honour the field width etc., so this is
8351 -+ * not a no-op.
8352 -+ */
8353 -+ checked_print_quoted (dest, segment->text, "");
8354 -+ }
8355 -+ }
8356 -+#endif /* S_ISLNK */
8357 -+ break;
8358 -+
8359 -+ case 'M': /* mode as 10 chars (eg., "-rwxr-x--x" */
8360 -+ /* UNTRUSTED, probably unexploitable */
8361 -+ {
8362 -+ char modestring[16] ;
8363 -+ filemodestring (stat_buf, modestring);
8364 -+ modestring[10] = '\0';
8365 -+ checked_fprintf (dest, segment->text, modestring);
8366 -+ }
8367 -+ break;
8368 -+
8369 -+ case 'm': /* mode as octal number (perms only) */
8370 -+ /* UNTRUSTED, probably unexploitable */
8371 -+ {
8372 -+ /* Output the mode portably using the traditional numbers,
8373 -+ even if the host unwisely uses some other numbering
8374 -+ scheme. But help the compiler in the common case where
8375 -+ the host uses the traditional numbering scheme. */
8376 -+ mode_t m = stat_buf->st_mode;
8377 -+ boolean traditional_numbering_scheme =
8378 -+ (S_ISUID == 04000 && S_ISGID == 02000 && S_ISVTX == 01000
8379 -+ && S_IRUSR == 00400 && S_IWUSR == 00200 && S_IXUSR == 00100
8380 -+ && S_IRGRP == 00040 && S_IWGRP == 00020 && S_IXGRP == 00010
8381 -+ && S_IROTH == 00004 && S_IWOTH == 00002 && S_IXOTH == 00001);
8382 -+ checked_fprintf (dest, segment->text,
8383 -+ (traditional_numbering_scheme
8384 -+ ? m & MODE_ALL
8385 -+ : ((m & S_ISUID ? 04000 : 0)
8386 -+ | (m & S_ISGID ? 02000 : 0)
8387 -+ | (m & S_ISVTX ? 01000 : 0)
8388 -+ | (m & S_IRUSR ? 00400 : 0)
8389 -+ | (m & S_IWUSR ? 00200 : 0)
8390 -+ | (m & S_IXUSR ? 00100 : 0)
8391 -+ | (m & S_IRGRP ? 00040 : 0)
8392 -+ | (m & S_IWGRP ? 00020 : 0)
8393 -+ | (m & S_IXGRP ? 00010 : 0)
8394 -+ | (m & S_IROTH ? 00004 : 0)
8395 -+ | (m & S_IWOTH ? 00002 : 0)
8396 -+ | (m & S_IXOTH ? 00001 : 0))));
8397 -+ }
8398 -+ break;
8399 -+
8400 -+ case 'n': /* number of links */
8401 -+ /* UNTRUSTED, probably unexploitable */
8402 -+ checked_fprintf (dest, segment->text,
8403 -+ human_readable ((uintmax_t) stat_buf->st_nlink,
8404 -+ hbuf,
8405 -+ human_ceiling,
8406 -+ 1, 1));
8407 -+ break;
8408 -+
8409 -+ case 'p': /* pathname */
8410 -+ /* sanitised */
8411 -+ checked_print_quoted (dest, segment->text, pathname);
8412 -+ break;
8413 -+
8414 -+ case 'P': /* pathname with ARGV element stripped */
8415 -+ /* sanitised */
8416 -+ if (state.curdepth > 0)
8417 -+ {
8418 -+ cp = pathname + state.starting_path_length;
8419 -+ if (*cp == '/')
8420 -+ /* Move past the slash between the ARGV element
8421 -+ and the rest of the pathname. But if the ARGV element
8422 -+ ends in a slash, we didn't add another, so we've
8423 -+ already skipped past it. */
8424 -+ cp++;
8425 -+ }
8426 -+ else
8427 -+ {
8428 -+ cp = "";
8429 -+ }
8430 -+ checked_print_quoted (dest, segment->text, cp);
8431 -+ break;
8432 -+
8433 -+ case 's': /* size in bytes */
8434 -+ /* UNTRUSTED, probably unexploitable */
8435 -+ checked_fprintf (dest, segment->text,
8436 -+ human_readable ((uintmax_t) stat_buf->st_size,
8437 -+ hbuf, human_ceiling, 1, 1));
8438 -+ break;
8439 -+
8440 -+ case 'S': /* sparseness */
8441 -+ /* UNTRUSTED, probably unexploitable */
8442 -+ checked_fprintf (dest, segment->text, file_sparseness(stat_buf));;
8443 -+ break;
8444 -+
8445 -+ case 't': /* mtime in `ctime' format */
8446 -+ /* UNTRUSTED, probably unexploitable */
8447 -+ checked_fprintf (dest, segment->text,
8448 -+ ctime_format (get_stat_mtime(stat_buf)));
8449 -+ break;
8450 -+
8451 -+ case 'u': /* user name */
8452 -+ /* trusted */
8453 -+ /* (well, the actual user is selected by the user on systems
8454 -+ * where chown is not restricted, but the user name was
8455 -+ * selected by the system administrator)
8456 -+ */
8457 -+ {
8458 -+ struct passwd *p;
8459 -+
8460 -+ p = getpwuid (stat_buf->st_uid);
8461 -+ if (p)
8462 -+ {
8463 -+ segment->text[segment->text_len] = 's';
8464 -+ checked_fprintf (dest, segment->text, p->pw_name);
8465 -+ break;
8466 -+ }
8467 -+ /* else fallthru */
8468 -+ }
8469 -+ /* FALLTHROUGH*/ /* .. to case U */
8470 -+
8471 -+ case 'U': /* UID number */
8472 -+ /* UNTRUSTED, probably unexploitable */
8473 -+ checked_fprintf (dest, segment->text,
8474 -+ human_readable ((uintmax_t) stat_buf->st_uid, hbuf,
8475 -+ human_ceiling, 1, 1));
8476 -+ break;
8477 -+
8478 -+ /* %Y: type of file system entry like `ls -l`:
8479 -+ * (d,-,l,s,p,b,c,n) n=nonexistent(symlink)
8480 -+ */
8481 -+ case 'Y': /* in case of symlink */
8482 -+ /* trusted */
8483 -+ {
8484 -+#ifdef S_ISLNK
8485 -+ if (S_ISLNK (stat_buf->st_mode))
8486 -+ {
8487 -+ struct stat sbuf;
8488 -+ /* If we would normally follow links, do not do so.
8489 -+ * If we would normally not follow links, do so.
8490 -+ */
8491 -+ if ((following_links() ? lstat : stat)
8492 -+ (state.rel_pathname, &sbuf) != 0)
8493 -+ {
8494 -+ if ( errno == ENOENT )
8495 -+ {
8496 -+ checked_fprintf (dest, segment->text, "N");
8497 -+ break;
8498 -+ }
8499 -+ else if ( errno == ELOOP )
8500 -+ {
8501 -+ checked_fprintf (dest, segment->text, "L");
8502 -+ break;
8503 -+ }
8504 -+ else
8505 -+ {
8506 -+ checked_fprintf (dest, segment->text, "?");
8507 -+ error (0, errno, "%s",
8508 -+ safely_quote_err_filename(0, pathname));
8509 -+ /* exit_status = 1;
8510 -+ return ; */
8511 -+ break;
8512 -+ }
8513 -+ }
8514 -+ checked_fprintf (dest, segment->text,
8515 -+ mode_to_filetype(sbuf.st_mode & S_IFMT));
8516 -+ }
8517 -+#endif /* S_ISLNK */
8518 -+ else
8519 -+ {
8520 -+ checked_fprintf (dest, segment->text,
8521 -+ mode_to_filetype(stat_buf->st_mode & S_IFMT));
8522 -+ }
8523 -+ }
8524 -+ break;
8525 -+
8526 -+ case 'y':
8527 -+ /* trusted */
8528 -+ {
8529 -+ checked_fprintf (dest, segment->text,
8530 -+ mode_to_filetype(stat_buf->st_mode & S_IFMT));
8531 -+ }
8532 -+ break;
8533 -+ }
8534 -+ /* end of KIND_FORMAT case */
8535 -+ break;
8536 -+ }
8537 -+}
8538 -+
8539 -+boolean
8540 -+pred_fprintf (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
8541 -+{
8542 -+ struct format_val *dest = &pred_ptr->args.printf_vec;
8543 -+ struct segment *segment;
8544 -+
8545 -+ for (segment = dest->segment; segment; segment = segment->next)
8546 -+ {
8547 -+ if ( (KIND_FORMAT == segment->segkind) && segment->format_char[1]) /* Component of date. */
8548 -+ {
8549 -+ struct timespec ts;
8550 -+ int valid = 0;
8551 -+
8552 -+ switch (segment->format_char[0])
8553 -+ {
8554 -+ case 'A':
8555 -+ ts = get_stat_atime(stat_buf);
8556 -+ valid = 1;
8557 -+ break;
8558 -+ case 'B':
8559 -+ ts = get_stat_birthtime(stat_buf);
8560 -+ if ('@' == segment->format_char[1])
8561 -+ valid = 1;
8562 -+ else
8563 -+ valid = (ts.tv_nsec >= 0);
8564 -+ break;
8565 -+ case 'C':
8566 -+ ts = get_stat_ctime(stat_buf);
8567 -+ valid = 1;
8568 -+ break;
8569 -+ case 'T':
8570 -+ ts = get_stat_mtime(stat_buf);
8571 -+ valid = 1;
8572 -+ break;
8573 -+ default:
8574 -+ assert (0);
8575 -+ abort ();
8576 -+ }
8577 -+ /* We trust the output of format_date not to contain
8578 -+ * nasty characters, though the value of the date
8579 -+ * is itself untrusted data.
8580 -+ */
8581 -+ if (valid)
8582 -+ {
8583 -+ /* trusted */
8584 -+ checked_fprintf (dest, segment->text,
8585 -+ format_date (ts, segment->format_char[1]));
8586 -+ }
8587 -+ else
8588 -+ {
8589 -+ /* The specified timestamp is not available, output
8590 -+ * nothing for the timestamp, but use the rest (so that
8591 -+ * for example find foo -printf '[%Bs] %p\n' can print
8592 -+ * "[] foo").
8593 -+ */
8594 -+ /* trusted */
8595 -+ checked_fprintf (dest, segment->text, "");
8596 -+ }
8597 -+ }
8598 -+ else
8599 -+ {
8600 -+ /* Print a segment which is not a date. */
8601 -+ do_fprintf(dest, segment, pathname, stat_buf);
8602 -+ }
8603 -+ }
8604 -+ return true;
8605 -+}
8606 -+
8607 -+boolean
8608 -+pred_fstype (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
8609 -+{
8610 -+ (void) pathname;
8611 -+
8612 -+ if (strcmp (filesystem_type (stat_buf, pathname), pred_ptr->args.str) == 0)
8613 -+ return true;
8614 -+ else
8615 -+ return false;
8616 -+}
8617 -+
8618 -+boolean
8619 -+pred_gid (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
8620 -+{
8621 -+ (void) pathname;
8622 -+
8623 -+ switch (pred_ptr->args.numinfo.kind)
8624 -+ {
8625 -+ case COMP_GT:
8626 -+ if (stat_buf->st_gid > pred_ptr->args.numinfo.l_val)
8627 -+ return (true);
8628 -+ break;
8629 -+ case COMP_LT:
8630 -+ if (stat_buf->st_gid < pred_ptr->args.numinfo.l_val)
8631 -+ return (true);
8632 -+ break;
8633 -+ case COMP_EQ:
8634 -+ if (stat_buf->st_gid == pred_ptr->args.numinfo.l_val)
8635 -+ return (true);
8636 -+ break;
8637 -+ }
8638 -+ return (false);
8639 -+}
8640 -+
8641 -+boolean
8642 -+pred_group (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
8643 -+{
8644 -+ (void) pathname;
8645 -+
8646 -+ if (pred_ptr->args.gid == stat_buf->st_gid)
8647 -+ return (true);
8648 -+ else
8649 -+ return (false);
8650 -+}
8651 -+
8652 -+boolean
8653 -+pred_ilname (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
8654 -+{
8655 -+ return match_lname (pathname, stat_buf, pred_ptr, true);
8656 -+}
8657 -+
8658 -+/* Common code between -name, -iname. PATHNAME is being visited, STR
8659 -+ is name to compare basename against, and FLAGS are passed to
8660 -+ fnmatch. Recall that 'find / -name /' is one of the few times where a '/'
8661 -+ in the -name must actually find something. */
8662 -+static boolean
8663 -+pred_name_common (const char *pathname, const char *str, int flags)
8664 -+{
8665 -+ char *p;
8666 -+ boolean b;
8667 -+ /* We used to use last_component() here, but that would not allow us to modify the
8668 -+ * input string, which is const. We could optimise by duplicating the string only
8669 -+ * if we need to modify it, and I'll do that if there is a measurable
8670 -+ * performance difference on a machine built after 1990...
8671 -+ */
8672 -+ char *base = base_name (pathname);
8673 -+ /* remove trailing slashes, but leave "/" or "//foo" unchanged. */
8674 -+ strip_trailing_slashes(base);
8675 -+
8676 -+ /* FNM_PERIOD is not used here because POSIX requires that it not be.
8677 -+ * See http://standards.ieee.org/reading/ieee/interp/1003-2-92_int/pasc-1003.2-126.html
8678 -+ */
8679 -+ b = fnmatch (str, base, flags) == 0;
8680 -+ free (base);
8681 -+ return b;
8682 -+}
8683 -+
8684 -+boolean
8685 -+pred_iname (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
8686 -+{
8687 -+ (void) stat_buf;
8688 -+ return pred_name_common (pathname, pred_ptr->args.str, FNM_CASEFOLD);
8689 -+}
8690 -+
8691 -+boolean
8692 -+pred_inum (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
8693 -+{
8694 -+ (void) pathname;
8695 -+
8696 -+ switch (pred_ptr->args.numinfo.kind)
8697 -+ {
8698 -+ case COMP_GT:
8699 -+ if (stat_buf->st_ino > pred_ptr->args.numinfo.l_val)
8700 -+ return (true);
8701 -+ break;
8702 -+ case COMP_LT:
8703 -+ if (stat_buf->st_ino < pred_ptr->args.numinfo.l_val)
8704 -+ return (true);
8705 -+ break;
8706 -+ case COMP_EQ:
8707 -+ if (stat_buf->st_ino == pred_ptr->args.numinfo.l_val)
8708 -+ return (true);
8709 -+ break;
8710 -+ }
8711 -+ return (false);
8712 -+}
8713 -+
8714 -+boolean
8715 -+pred_ipath (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
8716 -+{
8717 -+ (void) stat_buf;
8718 -+
8719 -+ if (fnmatch (pred_ptr->args.str, pathname, FNM_CASEFOLD) == 0)
8720 -+ return (true);
8721 -+ return (false);
8722 -+}
8723 -+
8724 -+boolean
8725 -+pred_links (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
8726 -+{
8727 -+ (void) pathname;
8728 -+
8729 -+ switch (pred_ptr->args.numinfo.kind)
8730 -+ {
8731 -+ case COMP_GT:
8732 -+ if (stat_buf->st_nlink > pred_ptr->args.numinfo.l_val)
8733 -+ return (true);
8734 -+ break;
8735 -+ case COMP_LT:
8736 -+ if (stat_buf->st_nlink < pred_ptr->args.numinfo.l_val)
8737 -+ return (true);
8738 -+ break;
8739 -+ case COMP_EQ:
8740 -+ if (stat_buf->st_nlink == pred_ptr->args.numinfo.l_val)
8741 -+ return (true);
8742 -+ break;
8743 -+ }
8744 -+ return (false);
8745 -+}
8746 -+
8747 -+boolean
8748 -+pred_lname (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
8749 -+{
8750 -+ return match_lname (pathname, stat_buf, pred_ptr, false);
8751 -+}
8752 -+
8753 -+static boolean
8754 -+match_lname (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr, boolean ignore_case)
8755 -+{
8756 -+ boolean ret = false;
8757 -+#ifdef S_ISLNK
8758 -+ if (S_ISLNK (stat_buf->st_mode))
8759 -+ {
8760 -+ char *linkname = get_link_name_at (pathname, state.cwd_dir_fd, state.rel_pathname);
8761 -+ if (linkname)
8762 -+ {
8763 -+ if (fnmatch (pred_ptr->args.str, linkname,
8764 -+ ignore_case ? FNM_CASEFOLD : 0) == 0)
8765 -+ ret = true;
8766 -+ free (linkname);
8767 -+ }
8768 -+ }
8769 -+#endif /* S_ISLNK */
8770 -+ return ret;
8771 -+}
8772 -+
8773 -+boolean
8774 -+pred_ls (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
8775 -+{
8776 -+ return pred_fls(pathname, stat_buf, pred_ptr);
8777 -+}
8778 -+
8779 -+boolean
8780 -+pred_mmin (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
8781 -+{
8782 -+ (void) &pathname;
8783 -+ return pred_timewindow(get_stat_mtime(stat_buf), pred_ptr, 60);
8784 -+}
8785 -+
8786 -+boolean
8787 -+pred_mtime (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
8788 -+{
8789 -+ (void) pathname;
8790 -+ return pred_timewindow(get_stat_mtime(stat_buf), pred_ptr, DAYSECS);
8791 -+}
8792 -+
8793 -+boolean
8794 -+pred_name (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
8795 -+{
8796 -+ (void) stat_buf;
8797 -+ return pred_name_common (pathname, pred_ptr->args.str, 0);
8798 -+}
8799 -+
8800 -+boolean
8801 -+pred_negate (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
8802 -+{
8803 -+ return !apply_predicate(pathname, stat_buf, pred_ptr->pred_right);
8804 -+}
8805 -+
8806 -+boolean
8807 -+pred_newer (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
8808 -+{
8809 -+ (void) pathname;
8810 -+
8811 -+ assert (COMP_GT == pred_ptr->args.reftime.kind);
8812 -+ return compare_ts(get_stat_mtime(stat_buf), pred_ptr->args.reftime.ts) > 0;
8813 -+}
8814 -+
8815 -+boolean
8816 -+pred_newerXY (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
8817 -+{
8818 -+ struct timespec ts;
8819 -+ boolean collected = false;
8820 -+
8821 -+ assert (COMP_GT == pred_ptr->args.reftime.kind);
8822 -+
8823 -+ switch (pred_ptr->args.reftime.xval)
8824 -+ {
8825 -+ case XVAL_TIME:
8826 -+ assert (pred_ptr->args.reftime.xval != XVAL_TIME);
8827 -+ return false;
8828 -+
8829 -+ case XVAL_ATIME:
8830 -+ ts = get_stat_atime(stat_buf);
8831 -+ collected = true;
8832 -+ break;
8833 -+
8834 -+ case XVAL_BIRTHTIME:
8835 -+ ts = get_stat_birthtime(stat_buf);
8836 -+ collected = true;
8837 -+ if (ts.tv_nsec < 0);
8838 -+ {
8839 -+ /* XXX: Cannot determine birth time. Warn once. */
8840 -+ error(0, 0, _("Warning: cannot determine birth time of file %s"),
8841 -+ safely_quote_err_filename(0, pathname));
8842 -+ return false;
8843 -+ }
8844 -+ break;
8845 -+
8846 -+ case XVAL_CTIME:
8847 -+ ts = get_stat_ctime(stat_buf);
8848 -+ collected = true;
8849 -+ break;
8850 -+
8851 -+ case XVAL_MTIME:
8852 -+ ts = get_stat_mtime(stat_buf);
8853 -+ collected = true;
8854 -+ break;
8855 -+ }
8856 -+
8857 -+ assert (collected);
8858 -+ return compare_ts(ts, pred_ptr->args.reftime.ts) > 0;
8859 -+}
8860 -+
8861 -+boolean
8862 -+pred_nogroup (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
8863 -+{
8864 -+ (void) pathname;
8865 -+ (void) pred_ptr;
8866 -+
8867 -+#ifdef CACHE_IDS
8868 -+ extern char *gid_unused;
8869 -+
8870 -+ return gid_unused[(unsigned) stat_buf->st_gid];
8871 -+#else
8872 -+ return getgrgid (stat_buf->st_gid) == NULL;
8873 -+#endif
8874 -+}
8875 -+
8876 -+boolean
8877 -+pred_nouser (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
8878 -+{
8879 -+#ifdef CACHE_IDS
8880 -+ extern char *uid_unused;
8881 -+#endif
8882 -+
8883 -+ (void) pathname;
8884 -+ (void) pred_ptr;
8885 -+
8886 -+#ifdef CACHE_IDS
8887 -+ return uid_unused[(unsigned) stat_buf->st_uid];
8888 -+#else
8889 -+ return getpwuid (stat_buf->st_uid) == NULL;
8890 -+#endif
8891 -+}
8892 -+
8893 -+
8894 -+static boolean
8895 -+is_ok(const char *program, const char *arg)
8896 -+{
8897 -+ fflush (stdout);
8898 -+ /* The draft open standard requires that, in the POSIX locale,
8899 -+ the last non-blank character of this prompt be '?'.
8900 -+ The exact format is not specified.
8901 -+ This standard does not have requirements for locales other than POSIX
8902 -+ */
8903 -+ /* XXX: printing UNTRUSTED data here. */
8904 -+ fprintf (stderr, _("< %s ... %s > ? "
8905 -+ /* TRANSLATORS: we would like, if possible, the final non-blank
8906 -+ * character of this string to be '?', but it is not
8907 -+ * wholly essential. */
8908 -+ ), program, arg);
8909 -+ fflush (stderr);
8910 -+ return yesno();
8911 -+}
8912 -+
8913 -+boolean
8914 -+pred_ok (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
8915 -+{
8916 -+ if (is_ok(pred_ptr->args.exec_vec.replace_vec[0], pathname))
8917 -+ return new_impl_pred_exec (get_start_dirfd(),
8918 -+ pathname, stat_buf, pred_ptr, NULL, 0);
8919 -+ else
8920 -+ return false;
8921 -+}
8922 -+
8923 -+boolean
8924 -+pred_okdir (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
8925 -+{
8926 -+ const char *prefix = (state.rel_pathname[0] == '/') ? NULL : "./";
8927 -+ if (is_ok(pred_ptr->args.exec_vec.replace_vec[0], pathname))
8928 -+ return new_impl_pred_exec (get_current_dirfd(),
8929 -+ state.rel_pathname, stat_buf, pred_ptr,
8930 -+ prefix, (prefix ? 2 : 0));
8931 -+ else
8932 -+ return false;
8933 -+}
8934 -+
8935 -+boolean
8936 -+pred_openparen (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
8937 -+{
8938 -+ (void) pathname;
8939 -+ (void) stat_buf;
8940 -+ (void) pred_ptr;
8941 -+ return true;
8942 -+}
8943 -+
8944 -+boolean
8945 -+pred_or (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
8946 -+{
8947 -+ if (pred_ptr->pred_left == NULL
8948 -+ || !apply_predicate(pathname, stat_buf, pred_ptr->pred_left))
8949 -+ {
8950 -+ return apply_predicate(pathname, stat_buf, pred_ptr->pred_right);
8951 -+ }
8952 -+ else
8953 -+ return true;
8954 -+}
8955 -+
8956 -+boolean
8957 -+pred_path (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
8958 -+{
8959 -+ (void) stat_buf;
8960 -+ if (fnmatch (pred_ptr->args.str, pathname, 0) == 0)
8961 -+ return (true);
8962 -+ return (false);
8963 -+}
8964 -+
8965 -+boolean
8966 -+pred_perm (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
8967 -+{
8968 -+ mode_t mode = stat_buf->st_mode;
8969 -+ mode_t perm_val = pred_ptr->args.perm.val[S_ISDIR (mode) != 0];
8970 -+ (void) pathname;
8971 -+ switch (pred_ptr->args.perm.kind)
8972 -+ {
8973 -+ case PERM_AT_LEAST:
8974 -+ return (mode & perm_val) == perm_val;
8975 -+ break;
8976 -+
8977 -+ case PERM_ANY:
8978 -+ /* True if any of the bits set in the mask are also set in the file's mode.
8979 -+ *
8980 -+ *
8981 -+ * Otherwise, if onum is prefixed by a hyphen, the primary shall
8982 -+ * evaluate as true if at least all of the bits specified in
8983 -+ * onum that are also set in the octal mask 07777 are set.
8984 -+ *
8985 -+ * Eric Blake's interpretation is that the mode argument is zero,
8986 -+
8987 -+ */
8988 -+ if (0 == perm_val)
8989 -+ return true; /* Savannah bug 14748; we used to return false */
8990 -+ else
8991 -+ return (mode & perm_val) != 0;
8992 -+ break;
8993 -+
8994 -+ case PERM_EXACT:
8995 -+ return (mode & MODE_ALL) == perm_val;
8996 -+ break;
8997 -+
8998 -+ default:
8999 -+ abort ();
9000 -+ break;
9001 -+ }
9002 -+}
9003 -+
9004 -+
9005 -+struct access_check_args
9006 -+{
9007 -+ const char *filename;
9008 -+ int access_type;
9009 -+ int cb_errno;
9010 -+};
9011 -+
9012 -+
9013 -+static int
9014 -+access_callback(void *context)
9015 -+{
9016 -+ int rv;
9017 -+ struct access_check_args *args = context;
9018 -+ if ((rv = access(args->filename, args->access_type)) < 0)
9019 -+ args->cb_errno = errno;
9020 -+ return rv;
9021 -+}
9022 -+
9023 -+static int
9024 -+can_access(int access_type)
9025 -+{
9026 -+ struct access_check_args args;
9027 -+ args.filename = state.rel_pathname;
9028 -+ args.access_type = access_type;
9029 -+ args.cb_errno = 0;
9030 -+ return 0 == run_in_dir(state.cwd_dir_fd, access_callback, &args);
9031 -+}
9032 -+
9033 -+
9034 -+boolean
9035 -+pred_executable (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
9036 -+{
9037 -+ (void) pathname;
9038 -+ (void) stat_buf;
9039 -+ (void) pred_ptr;
9040 -+
9041 -+ return can_access(X_OK);
9042 -+}
9043 -+
9044 -+boolean
9045 -+pred_readable (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
9046 -+{
9047 -+ (void) pathname;
9048 -+ (void) stat_buf;
9049 -+ (void) pred_ptr;
9050 -+
9051 -+ return can_access(R_OK);
9052 -+}
9053 -+
9054 -+boolean
9055 -+pred_writable (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
9056 -+{
9057 -+ (void) pathname;
9058 -+ (void) stat_buf;
9059 -+ (void) pred_ptr;
9060 -+
9061 -+ return can_access(W_OK);
9062 -+}
9063 -+
9064 -+boolean
9065 -+pred_print (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
9066 -+{
9067 -+ (void) stat_buf;
9068 -+ (void) pred_ptr;
9069 -+
9070 -+ print_quoted(pred_ptr->args.printf_vec.stream,
9071 -+ pred_ptr->args.printf_vec.quote_opts,
9072 -+ pred_ptr->args.printf_vec.dest_is_tty,
9073 -+ "%s\n", pathname);
9074 -+ return true;
9075 -+}
9076 -+
9077 -+boolean
9078 -+pred_print0 (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
9079 -+{
9080 -+ return pred_fprint0(pathname, stat_buf, pred_ptr);
9081 -+}
9082 -+
9083 -+boolean
9084 -+pred_prune (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
9085 -+{
9086 -+ (void) pathname;
9087 -+ (void) pred_ptr;
9088 -+
9089 -+ if (options.do_dir_first == true && /* no effect with -depth */
9090 -+ stat_buf != NULL &&
9091 -+ S_ISDIR(stat_buf->st_mode))
9092 -+ state.stop_at_current_level = true;
9093 -+
9094 -+ /* findutils used to return options.do_dir_first here, so that -prune
9095 -+ * returns true only if -depth is not in effect. But POSIX requires
9096 -+ * that -prune always evaluate as true.
9097 -+ */
9098 -+ return true;
9099 -+}
9100 -+
9101 -+boolean
9102 -+pred_quit (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
9103 -+{
9104 -+ (void) pathname;
9105 -+ (void) stat_buf;
9106 -+ (void) pred_ptr;
9107 -+
9108 -+ /* Run any cleanups. This includes executing any command lines
9109 -+ * we have partly built but not executed.
9110 -+ */
9111 -+ cleanup();
9112 -+
9113 -+ /* Since -exec and friends don't leave child processes running in the
9114 -+ * background, there is no need to wait for them here.
9115 -+ */
9116 -+ exit(state.exit_status); /* 0 for success, etc. */
9117 -+}
9118 -+
9119 -+boolean
9120 -+pred_regex (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
9121 -+{
9122 -+ int len = strlen (pathname);
9123 -+(void) stat_buf;
9124 -+ if (re_match (pred_ptr->args.regex, pathname, len, 0,
9125 -+ (struct re_registers *) NULL) == len)
9126 -+ return (true);
9127 -+ return (false);
9128 -+}
9129 -+
9130 -+boolean
9131 -+pred_size (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
9132 -+{
9133 -+ uintmax_t f_val;
9134 -+
9135 -+ (void) pathname;
9136 -+ f_val = ((stat_buf->st_size / pred_ptr->args.size.blocksize)
9137 -+ + (stat_buf->st_size % pred_ptr->args.size.blocksize != 0));
9138 -+ switch (pred_ptr->args.size.kind)
9139 -+ {
9140 -+ case COMP_GT:
9141 -+ if (f_val > pred_ptr->args.size.size)
9142 -+ return (true);
9143 -+ break;
9144 -+ case COMP_LT:
9145 -+ if (f_val < pred_ptr->args.size.size)
9146 -+ return (true);
9147 -+ break;
9148 -+ case COMP_EQ:
9149 -+ if (f_val == pred_ptr->args.size.size)
9150 -+ return (true);
9151 -+ break;
9152 -+ }
9153 -+ return (false);
9154 -+}
9155 -+
9156 -+boolean
9157 -+pred_samefile (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
9158 -+{
9159 -+ /* Potential optimisation: because of the loop protection, we always
9160 -+ * know the device of the current directory, hence the device number
9161 -+ * of the file we're currently considering. If -L is not in effect,
9162 -+ * and the device number of the file we're looking for is not the
9163 -+ * same as the device number of the current directory, this
9164 -+ * predicate cannot return true. Hence there would be no need to
9165 -+ * stat the file we're looking at.
9166 -+ */
9167 -+ (void) pathname;
9168 -+
9169 -+ /* We will often still have an fd open on the file under consideration,
9170 -+ * but that's just to ensure inode number stability by maintaining
9171 -+ * a reference to it; we don't need the file for anything else.
9172 -+ */
9173 -+ return stat_buf->st_ino == pred_ptr->args.samefileid.ino
9174 -+ && stat_buf->st_dev == pred_ptr->args.samefileid.dev;
9175 -+}
9176 -+
9177 -+boolean
9178 -+pred_true (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
9179 -+{
9180 -+ (void) pathname;
9181 -+ (void) stat_buf;
9182 -+ (void) pred_ptr;
9183 -+ return true;
9184 -+}
9185 -+
9186 -+boolean
9187 -+pred_type (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
9188 -+{
9189 -+ mode_t mode;
9190 -+ mode_t type = pred_ptr->args.type;
9191 -+
9192 -+ assert (state.have_type);
9193 -+
9194 -+ if (0 == state.type)
9195 -+ {
9196 -+ /* This can sometimes happen with broken NFS servers.
9197 -+ * See Savannah bug #16378.
9198 -+ */
9199 -+ return false;
9200 -+ }
9201 -+
9202 -+ (void) pathname;
9203 -+
9204 -+ if (state.have_stat)
9205 -+ mode = stat_buf->st_mode;
9206 -+ else
9207 -+ mode = state.type;
9208 -+
9209 -+#ifndef S_IFMT
9210 -+ /* POSIX system; check `mode' the slow way. */
9211 -+ if ((S_ISBLK (mode) && type == S_IFBLK)
9212 -+ || (S_ISCHR (mode) && type == S_IFCHR)
9213 -+ || (S_ISDIR (mode) && type == S_IFDIR)
9214 -+ || (S_ISREG (mode) && type == S_IFREG)
9215 -+#ifdef S_IFLNK
9216 -+ || (S_ISLNK (mode) && type == S_IFLNK)
9217 -+#endif
9218 -+#ifdef S_IFIFO
9219 -+ || (S_ISFIFO (mode) && type == S_IFIFO)
9220 -+#endif
9221 -+#ifdef S_IFSOCK
9222 -+ || (S_ISSOCK (mode) && type == S_IFSOCK)
9223 -+#endif
9224 -+#ifdef S_IFDOOR
9225 -+ || (S_ISDOOR (mode) && type == S_IFDOOR)
9226 -+#endif
9227 -+ )
9228 -+#else /* S_IFMT */
9229 -+ /* Unix system; check `mode' the fast way. */
9230 -+ if ((mode & S_IFMT) == type)
9231 -+#endif /* S_IFMT */
9232 -+ return (true);
9233 -+ else
9234 -+ return (false);
9235 -+}
9236 -+
9237 -+boolean
9238 -+pred_uid (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
9239 -+{
9240 -+ (void) pathname;
9241 -+ switch (pred_ptr->args.numinfo.kind)
9242 -+ {
9243 -+ case COMP_GT:
9244 -+ if (stat_buf->st_uid > pred_ptr->args.numinfo.l_val)
9245 -+ return (true);
9246 -+ break;
9247 -+ case COMP_LT:
9248 -+ if (stat_buf->st_uid < pred_ptr->args.numinfo.l_val)
9249 -+ return (true);
9250 -+ break;
9251 -+ case COMP_EQ:
9252 -+ if (stat_buf->st_uid == pred_ptr->args.numinfo.l_val)
9253 -+ return (true);
9254 -+ break;
9255 -+ }
9256 -+ return (false);
9257 -+}
9258 -+
9259 -+boolean
9260 -+pred_used (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
9261 -+{
9262 -+ struct timespec delta, at, ct;
9263 -+
9264 -+ (void) pathname;
9265 -+
9266 -+ /* TODO: this needs to be retested carefully (manually, if necessary) */
9267 -+ at = get_stat_atime(stat_buf);
9268 -+ ct = get_stat_ctime(stat_buf);
9269 -+ delta.tv_sec = at.tv_sec - ct.tv_sec;
9270 -+ delta.tv_nsec = at.tv_nsec - ct.tv_nsec;
9271 -+ if (delta.tv_nsec < 0)
9272 -+ {
9273 -+ delta.tv_nsec += 1000000000;
9274 -+ delta.tv_sec -= 1;
9275 -+ }
9276 -+ return pred_timewindow(delta, pred_ptr, DAYSECS);
9277 -+}
9278 -+
9279 -+boolean
9280 -+pred_user (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
9281 -+{
9282 -+ (void) pathname;
9283 -+ if (pred_ptr->args.uid == stat_buf->st_uid)
9284 -+ return (true);
9285 -+ else
9286 -+ return (false);
9287 -+}
9288 -+
9289 -+boolean
9290 -+pred_xtype (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
9291 -+{
9292 -+ struct stat sbuf; /* local copy, not stat_buf because we're using a different stat method */
9293 -+ int (*ystat) (const char*, struct stat *p);
9294 -+
9295 -+ /* If we would normally stat the link itself, stat the target instead.
9296 -+ * If we would normally follow the link, stat the link itself instead.
9297 -+ */
9298 -+ if (following_links())
9299 -+ ystat = optionp_stat;
9300 -+ else
9301 -+ ystat = optionl_stat;
9302 -+
9303 -+ set_stat_placeholders(&sbuf);
9304 -+ if ((*ystat) (state.rel_pathname, &sbuf) != 0)
9305 -+ {
9306 -+ if (following_links() && errno == ENOENT)
9307 -+ {
9308 -+ /* If we failed to follow the symlink,
9309 -+ * fall back on looking at the symlink itself.
9310 -+ */
9311 -+ /* Mimic behavior of ls -lL. */
9312 -+ return (pred_type (pathname, stat_buf, pred_ptr));
9313 -+ }
9314 -+ else
9315 -+ {
9316 -+ error (0, errno, "%s", safely_quote_err_filename(0, pathname));
9317 -+ state.exit_status = 1;
9318 -+ }
9319 -+ return false;
9320 -+ }
9321 -+ /* Now that we have our stat() information, query it in the same
9322 -+ * way that -type does.
9323 -+ */
9324 -+ return (pred_type (pathname, &sbuf, pred_ptr));
9325 -+}
9326 -+
9327 -+/* 1) fork to get a child; parent remembers the child pid
9328 -+ 2) child execs the command requested
9329 -+ 3) parent waits for child; checks for proper pid of child
9330 -+
9331 -+ Possible returns:
9332 -+
9333 -+ ret errno status(h) status(l)
9334 -+
9335 -+ pid x signal# 0177 stopped
9336 -+ pid x exit arg 0 term by _exit
9337 -+ pid x 0 signal # term by signal
9338 -+ -1 EINTR parent got signal
9339 -+ -1 other some other kind of error
9340 -+
9341 -+ Return true only if the pid matches, status(l) is
9342 -+ zero, and the exit arg (status high) is 0.
9343 -+ Otherwise return false, possibly printing an error message. */
9344 -+
9345 -+
9346 -+static boolean
9347 -+prep_child_for_exec (boolean close_stdin, int dirfd)
9348 -+{
9349 -+ boolean ok = true;
9350 -+ if (close_stdin)
9351 -+ {
9352 -+ const char inputfile[] = "/dev/null";
9353 -+
9354 -+ if (close(0) < 0)
9355 -+ {
9356 -+ error(0, errno, _("Cannot close standard input"));
9357 -+ ok = false;
9358 -+ }
9359 -+ else
9360 -+ {
9361 -+ if (open(inputfile, O_RDONLY
9362 -+#if defined O_LARGEFILE
9363 -+ |O_LARGEFILE
9364 -+#endif
9365 -+ ) < 0)
9366 -+ {
9367 -+ /* This is not entirely fatal, since
9368 -+ * executing the child with a closed
9369 -+ * stdin is almost as good as executing it
9370 -+ * with its stdin attached to /dev/null.
9371 -+ */
9372 -+ error (0, errno, "%s", safely_quote_err_filename(0, inputfile));
9373 -+ /* do not set ok=false, it is OK to continue anyway. */
9374 -+ }
9375 -+ }
9376 -+ }
9377 -+
9378 -+ /* Even if DebugSearch is set, don't announce our change of
9379 -+ * directory, since we're not going to emit a subsequent
9380 -+ * announcement of a call to stat() anyway, as we're about to exec
9381 -+ * something.
9382 -+ */
9383 -+ if (dirfd != AT_FDCWD)
9384 -+ {
9385 -+ assert (dirfd >= 0);
9386 -+ if (0 != fchdir(dirfd))
9387 -+ {
9388 -+ /* If we cannot execute our command in the correct directory,
9389 -+ * we should not execute it at all.
9390 -+ */
9391 -+ error(0, errno, _("Failed to change directory"));
9392 -+ ok = false;
9393 -+ }
9394 -+ }
9395 -+ return ok;
9396 -+}
9397 -+
9398 -+
9399 -+
9400 -+int
9401 -+launch (const struct buildcmd_control *ctl,
9402 -+ struct buildcmd_state *buildstate)
9403 -+{
9404 -+ int wait_status;
9405 -+ pid_t child_pid;
9406 -+ static int first_time = 1;
9407 -+ const struct exec_val *execp = buildstate->usercontext;
9408 -+
9409 -+ if (!execp->use_current_dir)
9410 -+ {
9411 -+ assert (starting_desc >= 0);
9412 -+ assert (execp->dirfd == starting_desc);
9413 -+ }
9414 -+
9415 -+
9416 -+ /* Null terminate the arg list. */
9417 -+ bc_push_arg (ctl, buildstate, (char *) NULL, 0, NULL, 0, false);
9418 -+
9419 -+ /* Make sure output of command doesn't get mixed with find output. */
9420 -+ fflush (stdout);
9421 -+ fflush (stderr);
9422 -+
9423 -+ /* Make sure to listen for the kids. */
9424 -+ if (first_time)
9425 -+ {
9426 -+ first_time = 0;
9427 -+ signal (SIGCHLD, SIG_DFL);
9428 -+ }
9429 -+
9430 -+ child_pid = fork ();
9431 -+ if (child_pid == -1)
9432 -+ error (1, errno, _("cannot fork"));
9433 -+ if (child_pid == 0)
9434 -+ {
9435 -+ /* We are the child. */
9436 -+ assert (starting_desc >= 0);
9437 -+ if (!prep_child_for_exec(execp->close_stdin, execp->dirfd))
9438 -+ {
9439 -+ _exit(1);
9440 -+ }
9441 -+
9442 -+ execvp (buildstate->cmd_argv[0], buildstate->cmd_argv);
9443 -+ error (0, errno, "%s",
9444 -+ safely_quote_err_filename(0, buildstate->cmd_argv[0]));
9445 -+ _exit (1);
9446 -+ }
9447 -+
9448 -+
9449 -+ /* In parent; set up for next time. */
9450 -+ bc_clear_args(ctl, buildstate);
9451 -+
9452 -+
9453 -+ while (waitpid (child_pid, &wait_status, 0) == (pid_t) -1)
9454 -+ {
9455 -+ if (errno != EINTR)
9456 -+ {
9457 -+ error (0, errno, _("error waiting for %s"),
9458 -+ safely_quote_err_filename(0, buildstate->cmd_argv[0]));
9459 -+ state.exit_status = 1;
9460 -+ return 0; /* FAIL */
9461 -+ }
9462 -+ }
9463 -+
9464 -+ if (WIFSIGNALED (wait_status))
9465 ++ switch (errno)
9466 + {
9467 -+ error (0, 0, _("%1$s terminated by signal %2$d"),
9468 -+ quotearg_n_style(0, options.err_quoting_style,
9469 -+ buildstate->cmd_argv[0]),
9470 -+ WTERMSIG (wait_status));
9471 -+
9472 -+ if (execp->multiple)
9473 -+ {
9474 -+ /* -exec \; just returns false if the invoked command fails.
9475 -+ * -exec {} + returns true if the invoked command fails, but
9476 -+ * sets the program exit status.
9477 -+ */
9478 -+ state.exit_status = 1;
9479 -+ }
9480 -+
9481 -+ return 1; /* OK */
9482 -+ }
9483 ++ case ENOENT:
9484 ++ case ENOTDIR:
9485 ++#ifdef DEBUG_STAT
9486 ++ fprintf(stderr, "fallback_getfilecon(): getfilecon(%s) failed; falling back on lgetfilecon()\n", name);
9487 ++#endif
9488 ++ return lgetfilecon(name, p);
9489 +
9490 -+ if (0 == WEXITSTATUS (wait_status))
9491 -+ {
9492 -+ return 1; /* OK */
9493 -+ }
9494 -+ else
9495 -+ {
9496 -+ if (execp->multiple)
9497 -+ {
9498 -+ /* -exec \; just returns false if the invoked command fails.
9499 -+ * -exec {} + returns true if the invoked command fails, but
9500 -+ * sets the program exit status.
9501 -+ */
9502 -+ state.exit_status = 1;
9503 -+ }
9504 -+ return 0; /* FAIL */
9505 ++ case EACCES:
9506 ++ case EIO:
9507 ++ case ELOOP:
9508 ++ case ENAMETOOLONG:
9509 ++#ifdef EOVERFLOW
9510 ++ case EOVERFLOW: /* EOVERFLOW is not #defined on UNICOS. */
9511 ++#endif
9512 ++ default:
9513 ++ return prev_rv;
9514 + }
9515 -+
9516 +}
9517 +
9518 -+
9519 -+/* Return a static string formatting the time WHEN according to the
9520 -+ * strftime format character KIND.
9521 ++
9522 ++/* optionh_getfilecon() implements the getfilecon operation when the
9523 ++ * -H option is in effect.
9524 ++ *
9525 ++ * If the item to be examined is a command-line argument, we follow
9526 ++ * symbolic links. If the getfilecon() call fails on the command-line
9527 ++ * item, we fall back on the properties of the symbolic link.
9528 + *
9529 -+ * This function contains a number of assertions. These look like
9530 -+ * runtime checks of the results of computations, which would be a
9531 -+ * problem since external events should not be tested for with
9532 -+ * "assert" (instead you should use "if"). However, they are not
9533 -+ * really runtime checks. The assertions actually exist to verify
9534 -+ * that the various buffers are correctly sized.
9535 ++ * If the item to be examined is not a command-line argument, we
9536 ++ * examine the link itself.
9537 + */
9538 -+static char *
9539 -+format_date (struct timespec ts, int kind)
9540 ++int
9541 ++optionh_getfilecon(const char *name, security_context_t *p)
9542 +{
9543 -+ /* In theory, we use an extra 10 characters for 9 digits of
9544 -+ * nanoseconds and 1 for the decimal point. However, the real
9545 -+ * world is more complex than that.
9546 -+ *
9547 -+ * For example, some systems return junk in the tv_nsec part of
9548 -+ * st_birthtime. An example of this is the NetBSD-4.0-RELENG kernel
9549 -+ * (at Sat Mar 24 18:46:46 2007) running a NetBSD-3.1-RELEASE
9550 -+ * runtime and examining files on an msdos filesytem. So for that
9551 -+ * reason we set NS_BUF_LEN to 32, which is simply "long enough" as
9552 -+ * opposed to "exactly the right size". Note that the behaviour of
9553 -+ * NetBSD appears to be a result of the use of uninitialised data,
9554 -+ * as it's not 100% reproducible (more like 25%).
9555 -+ */
9556 -+ enum {
9557 -+ NS_BUF_LEN = 32,
9558 -+ DATE_LEN_PERCENT_APLUS=21 /* length of result of %A+ (it's longer than %c)*/
9559 -+ };
9560 -+ static char buf[128u+10u + MAX(DATE_LEN_PERCENT_APLUS,
9561 -+ MAX (LONGEST_HUMAN_READABLE + 2, NS_BUF_LEN+64+200))];
9562 -+ char ns_buf[NS_BUF_LEN]; /* -.9999999990 (- sign can happen!)*/
9563 -+ int charsprinted, need_ns_suffix;
9564 -+ struct tm *tm;
9565 -+ char fmt[6];
9566 -+
9567 -+ /* human_readable() assumes we pass a buffer which is at least as
9568 -+ * long as LONGEST_HUMAN_READABLE. We use an assertion here to
9569 -+ * ensure that no nasty unsigned overflow happend in our calculation
9570 -+ * of the size of buf. Do the assertion here rather than in the
9571 -+ * code for %@ so that we find the problem quickly if it exists. If
9572 -+ * you want to submit a patch to move this into the if statement, go
9573 -+ * ahead, I'll apply it. But include performance timings
9574 -+ * demonstrating that the performance difference is actually
9575 -+ * measurable.
9576 -+ */
9577 -+ verify (sizeof(buf) >= LONGEST_HUMAN_READABLE);
9578 -+
9579 -+ charsprinted = 0;
9580 -+ need_ns_suffix = 0;
9581 -+
9582 -+ /* Format the main part of the time. */
9583 -+ if (kind == '+')
9584 -+ {
9585 -+ strcpy (fmt, "%F+%T");
9586 -+ need_ns_suffix = 1;
9587 -+ }
9588 -+ else
9589 -+ {
9590 -+ fmt[0] = '%';
9591 -+ fmt[1] = kind;
9592 -+ fmt[2] = '\0';
9593 -+
9594 -+ /* %a, %c, and %t are handled in ctime_format() */
9595 -+ switch (kind)
9596 -+ {
9597 -+ case 'S':
9598 -+ case 'T':
9599 -+ case 'X':
9600 -+ case '@':
9601 -+ need_ns_suffix = 1;
9602 -+ break;
9603 -+ default:
9604 -+ need_ns_suffix = 0;
9605 -+ break;
9606 -+ }
9607 -+ }
9608 -+
9609 -+ if (need_ns_suffix)
9610 -+ {
9611 -+ /* Format the nanoseconds part. Leave a trailing zero to
9612 -+ * discourage people from writing scripts which extract the
9613 -+ * fractional part of the timestamp by using column offsets.
9614 -+ * The reason for discouraging this is that in the future, the
9615 -+ * granularity may not be nanoseconds.
9616 -+ */
9617 -+ ns_buf[0] = 0;
9618 -+ charsprinted = snprintf(ns_buf, NS_BUF_LEN, ".%09ld0", (long int)ts.tv_nsec);
9619 -+ assert (charsprinted < NS_BUF_LEN);
9620 -+ }
9621 -+
9622 -+ if (kind != '@'
9623 -+ && (tm = localtime (&ts.tv_sec))
9624 -+ && strftime (buf, sizeof buf, fmt, tm))
9625 ++ if (0 == state.curdepth)
9626 + {
9627 -+ /* For %AS, %CS, %TS, add the fractional part of the seconds
9628 -+ * information.
9629 ++ /* This file is from the command line; deference the link (if it
9630 ++ * is a link).
9631 + */
9632 -+ if (need_ns_suffix)
9633 -+ {
9634 -+ assert ((sizeof buf - strlen(buf)) > strlen(ns_buf));
9635 -+ strcat(buf, ns_buf);
9636 -+ }
9637 -+ return buf;
9638 ++ int rv = getfilecon(name, p);
9639 ++ if (0 == rv)
9640 ++ return 0; /* success */
9641 ++ else
9642 ++ return fallback_getfilecon(name, p, rv);
9643 + }
9644 + else
9645 + {
9646 -+ uintmax_t w = ts.tv_sec;
9647 -+ size_t used, len, remaining;
9648 -+
9649 -+ /* XXX: note that we are negating an unsigned type which is the
9650 -+ * widest possible unsigned type.
9651 -+ */
9652 -+ char *p = human_readable (ts.tv_sec < 0 ? -w : w, buf + 1,
9653 -+ human_ceiling, 1, 1);
9654 -+ assert (p > buf);
9655 -+ assert (p < (buf + (sizeof buf)));
9656 -+ if (ts.tv_sec < 0)
9657 -+ *--p = '-'; /* XXX: Ugh, relying on internal details of human_readable(). */
9658 -+
9659 -+ /* Add the nanoseconds part. Because we cannot enforce a
9660 -+ * particlar implementation of human_readable, we cannot assume
9661 -+ * any particular value for (p-buf). So we need to be careful
9662 -+ * that there is enough space remaining in the buffer.
9663 ++ /* Not a file on the command line; do not derefernce the link.
9664 + */
9665 -+ if (need_ns_suffix)
9666 -+ {
9667 -+ len = strlen(p);
9668 -+ used = (p-buf) + len; /* Offset into buf of current end */
9669 -+ assert (sizeof buf > used); /* Ensure we can perform subtraction safely. */
9670 -+ remaining = sizeof buf - used - 1u; /* allow space for NUL */
9671 -+
9672 -+ if (strlen(ns_buf) >= remaining)
9673 -+ {
9674 -+ error(0, 0,
9675 -+ "charsprinted=%ld but remaining=%lu: ns_buf=%s",
9676 -+ (long)charsprinted, (unsigned long)remaining, ns_buf);
9677 -+ }
9678 -+ assert (strlen(ns_buf) < remaining);
9679 -+ strcat(p, ns_buf);
9680 -+ }
9681 -+ return p;
9682 -+ }
9683 -+}
9684 -+
9685 -+static const char *weekdays[] =
9686 -+ {
9687 -+ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
9688 -+ };
9689 -+static char * months[] =
9690 -+ {
9691 -+ "Jan", "Feb", "Mar", "Apr", "May", "Jun",
9692 -+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
9693 -+ };
9694 -+
9695 -+
9696 -+static char *
9697 -+ctime_format (struct timespec ts)
9698 -+{
9699 -+ const struct tm * ptm;
9700 -+#define TIME_BUF_LEN 1024u
9701 -+ static char resultbuf[TIME_BUF_LEN];
9702 -+ int nout;
9703 -+
9704 -+ ptm = localtime(&ts.tv_sec);
9705 -+ if (ptm)
9706 -+ {
9707 -+ assert (ptm->tm_wday >= 0);
9708 -+ assert (ptm->tm_wday < 7);
9709 -+ assert (ptm->tm_mon >= 0);
9710 -+ assert (ptm->tm_mon < 12);
9711 -+ assert (ptm->tm_hour >= 0);
9712 -+ assert (ptm->tm_hour < 24);
9713 -+ assert (ptm->tm_min < 60);
9714 -+ assert (ptm->tm_sec <= 61); /* allows 2 leap seconds. */
9715 -+
9716 -+ /* wkday mon mday hh:mm:ss.nnnnnnnnn yyyy */
9717 -+ nout = snprintf(resultbuf, TIME_BUF_LEN,
9718 -+ "%3s %3s %2d %02d:%02d:%02d.%010ld %04d",
9719 -+ weekdays[ptm->tm_wday],
9720 -+ months[ptm->tm_mon],
9721 -+ ptm->tm_mday,
9722 -+ ptm->tm_hour,
9723 -+ ptm->tm_min,
9724 -+ ptm->tm_sec,
9725 -+ (long int)ts.tv_nsec,
9726 -+ 1900 + ptm->tm_year);
9727 -+
9728 -+ assert (nout < TIME_BUF_LEN);
9729 -+ return resultbuf;
9730 -+ }
9731 -+ else
9732 -+ {
9733 -+ /* The time cannot be represented as a struct tm.
9734 -+ Output it as an integer. */
9735 -+ return format_date (ts, '@');
9736 ++ return lgetfilecon(name, p);
9737 + }
9738 +}
9739 +
9740 -+/* Copy STR into BUF and trim blanks from the end of BUF.
9741 -+ Return BUF. */
9742 -+
9743 -+static char *
9744 -+blank_rtrim (str, buf)
9745 -+ char *str;
9746 -+ char *buf;
9747 ++/* optionl_getfilecon() implements the getfilecon operation when the
9748 ++ * -L option is in effect. That option makes us examine the thing the
9749 ++ * symbolic link points to, not the symbolic link itself.
9750 ++ */
9751 ++int
9752 ++optionl_getfilecon(const char *name, security_context_t *p)
9753 +{
9754 -+ int i;
9755 -+
9756 -+ if (str == NULL)
9757 -+ return (NULL);
9758 -+ strcpy (buf, str);
9759 -+ i = strlen (buf) - 1;
9760 -+ while ((i >= 0) && ((buf[i] == ' ') || buf[i] == '\t'))
9761 -+ i--;
9762 -+ buf[++i] = '\0';
9763 -+ return (buf);
9764 ++ int rv = getfilecon(name, p);
9765 ++ if (0 == rv)
9766 ++ return 0; /* normal case. */
9767 ++ else
9768 ++ return fallback_getfilecon(name, p, rv);
9769 +}
9770 +
9771 -+/* Print out the predicate list starting at NODE. */
9772 -+void
9773 -+print_list (FILE *fp, struct predicate *node)
9774 ++/* optionp_getfilecon() implements the stat operation when the -P
9775 ++ * option is in effect (this is also the default). That option makes
9776 ++ * us examine the symbolic link itself, not the thing it points to.
9777 ++ */
9778 ++int
9779 ++optionp_getfilecon(const char *name, security_context_t *p)
9780 +{
9781 -+ struct predicate *cur;
9782 -+ char name[256];
9783 -+
9784 -+ cur = node;
9785 -+ while (cur != NULL)
9786 -+ {
9787 -+ fprintf (fp, "[%s] ", blank_rtrim (cur->p_name, name));
9788 -+ cur = cur->pred_next;
9789 -+ }
9790 -+ fprintf (fp, "\n");
9791 ++ return lgetfilecon(name, p);
9792 +}
9793 -+
9794 -+/* Print out the predicate list starting at NODE. */
9795 -+static void
9796 -+print_parenthesised(FILE *fp, struct predicate *node)
9797 -+{
9798 -+ int parens = 0;
9799 ++#endif /* WITH_SELINUX */
9800 +
9801 -+ if (node)
9802 -+ {
9803 -+ if ((pred_is(node, pred_or) || pred_is(node, pred_and))
9804 -+ && node->pred_left == NULL)
9805 -+ {
9806 -+ /* We print "<nothing> or X" as just "X"
9807 -+ * We print "<nothing> and X" as just "X"
9808 -+ */
9809 -+ print_parenthesised(fp, node->pred_right);
9810 -+ }
9811 -+ else
9812 -+ {
9813 -+ if (node->pred_left || node->pred_right)
9814 -+ parens = 1;
9815 +
9816 + static boolean
9817 + parse_and (const struct parser_table* entry, char **argv, int *arg_ptr)
9818 +@@ -1124,6 +1233,10 @@ tests (N can be +N or -N or N): -amin N
9819 + -readable -writable -executable\n\
9820 + -wholename PATTERN -size N[bcwkMG] -true -type [bcdpflsD] -uid N\n\
9821 + -used N -user NAME -xtype [bcdpfls]\n"));
9822 ++#ifdef WITH_SELINUX
9823 ++ puts (_("\
9824 ++ -context CONTEXT\n"));
9825 ++#endif /*WITH_SELINUX*/
9826 + puts (_("\
9827 + actions: -delete -print0 -printf FORMAT -fprintf FILE FORMAT -print \n\
9828 + -fprint0 FILE -fprint FILE -ls -fls FILE -prune -quit\n\
9829 +@@ -2522,6 +2635,29 @@ parse_version (const struct parser_table
9830 + exit (0);
9831 + }
9832 +
9833 ++#ifdef WITH_SELINUX
9834 +
9835 -+ if (parens)
9836 -+ fprintf(fp, "%s", " ( ");
9837 -+ print_optlist(fp, node);
9838 -+ if (parens)
9839 -+ fprintf(fp, "%s", " ) ");
9840 -+ }
9841 -+ }
9842 -+}
9843 -+
9844 -+void
9845 -+print_optlist (FILE *fp, const struct predicate *p)
9846 -+{
9847 -+ if (p)
9848 -+ {
9849 -+ print_parenthesised(fp, p->pred_left);
9850 -+ fprintf (fp,
9851 -+ "%s%s",
9852 -+ p->need_stat ? "[call stat] " : "",
9853 -+ p->need_type ? "[need type] " : "");
9854 -+ print_predicate(fp, p);
9855 -+ fprintf(fp, " [%g] ", p->est_success_rate);
9856 -+ if (options.debug_options & DebugSuccessRates)
9857 -+ {
9858 -+ fprintf(fp, "[%ld/%ld", p->perf.successes, p->perf.visits);
9859 -+ if (p->perf.visits)
9860 -+ {
9861 -+ double real_rate = (double)p->perf.successes / (double)p->perf.visits;
9862 -+ fprintf(fp, "=%g] ", real_rate);
9863 -+ }
9864 -+ else
9865 -+ {
9866 -+ fprintf(fp, "=_] ");
9867 -+ }
9868 -+ }
9869 -+ print_parenthesised(fp, p->pred_right);
9870 -+ }
9871 -+}
9872 -+
9873 -+void show_success_rates(const struct predicate *p)
9874 ++static boolean
9875 ++parse_scontext ( const struct parser_table* entry, char **argv, int *arg_ptr)
9876 +{
9877 -+ if (options.debug_options & DebugSuccessRates)
9878 -+ {
9879 -+ fprintf(stderr, "Predicate success rates after completion:\n");
9880 -+ print_optlist(stderr, p);
9881 -+ fprintf(stderr, "\n");
9882 -+ }
9883 -+}
9884 ++ struct predicate *our_pred;
9885 +
9886 ++ if ( (argv == NULL) || (argv[*arg_ptr] == NULL) )
9887 ++ return( false );
9888 +
9889 ++ our_pred = insert_primary(entry);
9890 ++ our_pred->need_stat = false;
9891 ++#ifdef DEBUG
9892 ++ our_pred->p_name = find_pred_name (pred_scontext);
9893 ++#endif /*DEBUG*/
9894 ++ our_pred->args.scontext = argv[*arg_ptr];;
9895 +
9896 -+
9897 -+#ifdef _NDEBUG
9898 -+/* If _NDEBUG is defined, the assertions will do nothing. Hence
9899 -+ * there is no point in having a function body for pred_sanity_check()
9900 -+ * if that preprocessor macro is defined.
9901 -+ */
9902 -+void
9903 -+pred_sanity_check(const struct predicate *predicates)
9904 -+{
9905 -+ /* Do nothing, since assert is a no-op with _NDEBUG set */
9906 -+ return;
9907 ++ (*arg_ptr)++;
9908 ++ return( true );
9909 +}
9910 ++
9911 ++#endif /*WITH_SELINUX*/
9912 ++
9913 + static boolean
9914 + parse_xdev (const struct parser_table* entry, char **argv, int *arg_ptr)
9915 + {
9916 +@@ -2773,7 +2909,11 @@ insert_fprintf (struct format_val *vec,
9917 + if (*scan2 == '.')
9918 + for (scan2++; ISDIGIT (*scan2); scan2++)
9919 + /* Do nothing. */ ;
9920 ++#ifdef WITH_SELINUX
9921 ++ if (strchr ("abcdDfFgGhHiklmMnpPsStuUyYZ", *scan2))
9922 +#else
9923 -+void
9924 -+pred_sanity_check(const struct predicate *predicates)
9925 -+{
9926 -+ const struct predicate *p;
9927 + if (strchr ("abcdDfFgGhHiklmMnpPsStuUyY", *scan2))
9928 ++#endif
9929 + {
9930 + segmentp = make_segment (segmentp, format, scan2 - format,
9931 + KIND_FORMAT, *scan2, 0,
9932 +diff -purN findutils-4.3.12.orig/find/pred.c findutils-4.3.12/find/pred.c
9933 +--- findutils-4.3.12.orig/find/pred.c 2007-12-19 16:12:34.000000000 -0500
9934 ++++ findutils-4.3.12/find/pred.c 2008-01-30 08:46:05.758843847 -0500
9935 +@@ -47,6 +47,14 @@
9936 + #include "error.h"
9937 + #include "verify.h"
9938 +
9939 ++#ifdef WITH_SELINUX
9940 ++#include <selinux/selinux.h>
9941 ++#endif /*WITH_SELINUX*/
9942 ++
9943 ++#ifndef FNM_CASEFOLD
9944 ++#define FNM_CASEFOLD (1<<4)
9945 ++#endif /*FNM_CASEFOLD*/
9946 ++
9947 + #if ENABLE_NLS
9948 + # include <libintl.h>
9949 + # define _(Text) gettext (Text)
9950 +@@ -229,6 +237,9 @@ struct pred_assoc pred_table[] =
9951 + {pred_user, "user "},
9952 + {pred_writable, "writable "},
9953 + {pred_xtype, "xtype "},
9954 ++#ifdef WITH_SELINUX
9955 ++ {pred_scontext, "context"},
9956 ++#endif /*WITH_SELINUX*/
9957 + {0, "none "}
9958 + };
9959 + #endif
9960 +@@ -1045,6 +1056,26 @@ do_fprintf(struct format_val *dest,
9961 + mode_to_filetype(stat_buf->st_mode & S_IFMT));
9962 + }
9963 + break;
9964 ++#ifdef WITH_SELINUX
9965 ++ case 'Z': /* SELinux security context */
9966 ++ {
9967 ++ security_context_t scontext;
9968 ++ int rv;
9969 ++ rv = (*options.x_getfilecon)(state.rel_pathname, &scontext);
9970 ++
9971 ++ if ( rv < 0 ) {
9972 ++ fprintf(stderr, "getfileconf(%s): %s",
9973 ++ pathname, strerror(errno));
9974 ++ fflush(stderr);
9975 ++ }
9976 ++ else {
9977 ++ segment->text[segment->text_len] = 's';
9978 ++ checked_fprintf (dest, segment->text, scontext);
9979 ++ freecon(scontext);
9980 ++ }
9981 ++ }
9982 ++ break ;
9983 ++#endif /* WITH_SELINUX */
9984 + }
9985 + /* end of KIND_FORMAT case */
9986 + break;
9987 +@@ -1838,6 +1869,31 @@ pred_xtype (const char *pathname, struct
9988 + */
9989 + return (pred_type (pathname, &sbuf, pred_ptr));
9990 + }
9991 +
9992 -+ for (p=predicates; p != NULL; p=p->pred_next)
9993 -+ {
9994 -+ /* All predicates must do something. */
9995 -+ assert (p->pred_func != NULL);
9996 +
9997 -+ /* All predicates must have a parser table entry. */
9998 -+ assert (p->parser_entry != NULL);
9999 -+
10000 -+ /* If the parser table tells us that just one predicate function is
10001 -+ * possible, verify that that is still the one that is in effect.
10002 -+ * If the parser has NULL for the predicate function, that means that
10003 -+ * the parse_xxx function fills it in, so we can't check it.
10004 -+ */
10005 -+ if (p->parser_entry->pred_func)
10006 -+ {
10007 -+ assert (p->parser_entry->pred_func == p->pred_func);
10008 -+ }
10009 -+
10010 -+ switch (p->parser_entry->type)
10011 -+ {
10012 -+ /* Options all take effect during parsing, so there should
10013 -+ * be no predicate entries corresponding to them. Hence we
10014 -+ * should not see any ARG_OPTION or ARG_POSITIONAL_OPTION
10015 -+ * items.
10016 -+ *
10017 -+ * This is a silly way of coding this test, but it prevents
10018 -+ * a compiler warning (i.e. otherwise it would think that
10019 -+ * there would be case statements missing).
10020 -+ */
10021 -+ case ARG_OPTION:
10022 -+ case ARG_POSITIONAL_OPTION:
10023 -+ assert (p->parser_entry->type != ARG_OPTION);
10024 -+ assert (p->parser_entry->type != ARG_POSITIONAL_OPTION);
10025 -+ break;
10026 -+
10027 -+ case ARG_ACTION:
10028 -+ assert(p->side_effects); /* actions have side effects. */
10029 -+ if (!pred_is(p, pred_prune) && !pred_is(p, pred_quit))
10030 -+ {
10031 -+ /* actions other than -prune and -quit should
10032 -+ * inhibit the default -print
10033 -+ */
10034 -+ assert (p->no_default_print);
10035 -+ }
10036 -+ break;
10037 ++#ifdef WITH_SELINUX
10038 +
10039 -+ /* We happen to know that the only user of ARG_SPECIAL_PARSE
10040 -+ * is a test, so handle it like ARG_TEST.
10041 -+ */
10042 -+ case ARG_SPECIAL_PARSE:
10043 -+ case ARG_TEST:
10044 -+ case ARG_PUNCTUATION:
10045 -+ case ARG_NOOP:
10046 -+ /* Punctuation and tests should have no side
10047 -+ * effects and not inhibit default print.
10048 -+ */
10049 -+ assert (!p->no_default_print);
10050 -+ assert (!p->side_effects);
10051 -+ break;
10052 -+ }
10053 -+ }
10054 ++boolean
10055 ++pred_scontext (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
10056 ++{
10057 ++ int rv;
10058 ++ security_context_t scontext;
10059 ++
10060 ++ rv = (* options.x_getfilecon)(state.rel_pathname, &scontext);
10061 ++
10062 ++ if ( rv < 0 ) {
10063 ++ (void) fprintf(stderr, "getfilecon(%s): %s\n", pathname, strerror(errno));
10064 ++ (void) fflush(stderr);
10065 ++ return ( false );
10066 ++ }
10067 ++
10068 ++ rv = (fnmatch(pred_ptr->args.scontext, scontext,0)==0);
10069 ++ freecon(scontext);
10070 ++ return rv;
10071 +}
10072 -+#endif
10073 ++
10074 ++#endif /*WITH_SELINUX*/
10075 ++
10076 +
10077 + /* 1) fork to get a child; parent remembers the child pid
10078 + 2) child execs the command requested
10079 diff -purN findutils-4.3.12.orig/find/tree.c findutils-4.3.12/find/tree.c
10080 --- findutils-4.3.12.orig/find/tree.c 2007-12-19 16:12:34.000000000 -0500
10081 +++ findutils-4.3.12/find/tree.c 2008-01-30 08:46:05.758843847 -0500
10082
10083
10084
10085 --
10086 gentoo-commits@l.g.o mailing list