* Copyright (c) 1990 The Regents of the University of California.
* This code is derived from software contributed to Berkeley by
* Cimarron D. Taylor of the University of California, Berkeley.
* %sccs.include.redist.c%
static char sccsid
[] = "@(#)function.c 5.8 (Berkeley) %G%";
#define COMPARE(a, b) { \
new = (PLAN *)emalloc(sizeof(PLAN)); \
* Parse a string of the form [+-]# and return the value.
find_parsenum(plan
, option
, str
, endch
)
char *option
, *str
, *endch
;
char *endchar
; /* pointer to character ending conversion */
/* determine comparison from leading + or - */
plan
->flags
= FIND_GREATER
;
plan
->flags
= FIND_LESSTHAN
;
plan
->flags
= FIND_EQUAL
;
* convert the string with strtol(). Note, if strtol() returns zero
* and endchar points to the beginning of the string we know we have
value
= strtol(str
, &endchar
, 10);
if (!value
&& endchar
== str
||
endchar
[0] && (!endch
|| endchar
[0] != *endch
))
bad_arg(option
, "illegal numeric value");
* True if the difference between the file access time and the
* current time is n 24 hour periods.
COMPARE((now
- entry
->fts_statb
.st_atime
+
SECSPERDAY
- 1) / SECSPERDAY
, plan
->t_data
);
ftsoptions
&= ~FTS_NOSTAT
;
new->t_data
= find_parsenum(new, "-atime", arg
, (char *)NULL
);
* True if the difference between the last change of file
* status information and the current time is n 24 hour periods.
COMPARE((now
- entry
->fts_statb
.st_ctime
+
SECSPERDAY
- 1) / SECSPERDAY
, plan
->t_data
);
ftsoptions
&= ~FTS_NOSTAT
;
new->t_data
= find_parsenum(new, "-ctime", arg
, (char *)NULL
);
* Always true, causes descent of the directory hierarchy to be done
* so that all entries in a directory are acted on before the directory
f_always_true(plan
, entry
)
NEW(T_DEPTH
, f_always_true
);
* [-exec | -ok] utility [arg ... ] ; functions --
* True if the executed utility returns a zero value as exit status.
* The end of the primary expression is delimited by a semicolon. If
* "{}" occurs anywhere, it gets replaced by the current pathname.
* The current directory for the execution of utility is the same as
* the current directory when the find utility was started.
* The primary -ok is different in that it requests affirmation of the
* user before executing the utility.
for (cnt
= 0; plan
->e_argv
[cnt
]; ++cnt
)
find_subst(plan
->e_orig
[cnt
], &plan
->e_argv
[cnt
],
entry
->fts_path
, plan
->e_len
[cnt
]);
if (plan
->flags
&& !find_queryuser(plan
->e_argv
))
(void)fprintf(stderr
, "find: fork: %s.\n", strerror(errno
));
execvp(plan
->e_argv
[0], plan
->e_argv
);
"find: %s: %s.\n", plan
->e_argv
[0], strerror(errno
));
pid
= waitpid(pid
, &pstat
, 0);
return(pid
!= -1 && !pstat
.w_status
);
* build three parallel arrays, one with pointers to the strings passed
* on the command line, one with (possibly duplicated) pointers to the
* argv array, and one with integer values that are lengths of the
* strings, but also flags meaning that the string has to be massaged.
PLAN
*new; /* node returned */
register char **argv
, **ap
, *p
;
ftsoptions
|= FTS_NOCHDIR
;
for (ap
= argv
= *argvp
;; ++ap
) {
bad_arg(isok
? "-ok" : "-exec", "no terminating \";\"");
new->e_argv
= (char **)emalloc((u_int
)cnt
* sizeof(char *));
new->e_orig
= (char **)emalloc((u_int
)cnt
* sizeof(char *));
new->e_len
= (int *)emalloc((u_int
)cnt
* sizeof(u_char
));
for (argv
= *argvp
, cnt
= 0; argv
< ap
; ++argv
, ++cnt
) {
new->e_orig
[cnt
] = *argv
;
if (p
[0] == '{' && p
[1] == '}') {
new->e_argv
[cnt
] = emalloc((u_int
)1024);
new->e_argv
[cnt
] = *argv
;
new->e_argv
[cnt
] = new->e_orig
[cnt
] = NULL
;
* Always true, causes symbolic links to be followed on a global
ftsoptions
&= ~FTS_PHYSICAL
;
ftsoptions
|= FTS_LOGICAL
;
NEW(T_FOLLOW
, f_always_true
);
* True if the file is of a certain type.
static dev_t curdev
; /* need a guaranteed illegal dev value */
/* only check when we cross mount point */
if (first
|| curdev
!= entry
->fts_statb
.st_dev
) {
curdev
= entry
->fts_statb
.st_dev
;
if (statfs(entry
->fts_accpath
, &sb
)) {
(void)fprintf(stderr
, "find: %s: %s.\n",
entry
->fts_accpath
, strerror(errno
));
val
= plan
->flags
== MOUNT_NONE
? sb
.f_flags
: sb
.f_type
;
return(plan
->flags
== MOUNT_NONE
?
val
& MNT_LOCAL
: val
== plan
->flags
);
ftsoptions
&= ~FTS_NOSTAT
;
if (!strcmp(arg
, "local")) {
if (!strcmp(arg
, "mfs")) {
if (!strcmp(arg
, "nfs")) {
if (!strcmp(arg
, "pc")) {
if (!strcmp(arg
, "ufs")) {
(void)fprintf(stderr
, "find: unknown file type %s.\n", arg
);
* -group gname functions --
* True if the file belongs to the group gname. If gname is numeric and
* an equivalent of the getgrnam() function does not return a valid group
* name, gname is taken as a group ID.
return(entry
->fts_statb
.st_gid
== plan
->g_data
);
ftsoptions
&= ~FTS_NOSTAT
;
if (gid
== 0 && gname
[0] != '0')
bad_arg("-group", "no such group");
* True if the file has inode # n.
COMPARE(entry
->fts_statb
.st_ino
, plan
->i_data
);
ftsoptions
&= ~FTS_NOSTAT
;
new->i_data
= find_parsenum(new, "-inum", arg
, (char *)NULL
);
* True if the file has n links.
COMPARE(entry
->fts_statb
.st_nlink
, plan
->l_data
);
ftsoptions
&= ~FTS_NOSTAT
;
new->l_data
= find_parsenum(new, "-links", arg
, (char *)NULL
);
* Always true - prints the current entry to stdout in "ls" format.
printlong(entry
->fts_path
, entry
->fts_accpath
, &entry
->fts_statb
);
ftsoptions
&= ~FTS_NOSTAT
;
* True if the basename of the filename being examined
* matches pattern using Pattern Matching Notation S3.14
return(fnmatch(plan
->c_data
, entry
->fts_name
, FNM_QUOTE
));
* -newer file functions --
* True if the current file has been modified more recently
* then the modification time of the file named by the pathname
return(entry
->fts_statb
.st_mtime
> plan
->t_data
);
ftsoptions
&= ~FTS_NOSTAT
;
if (stat(filename
, &sb
)) {
(void)fprintf(stderr
, "find: %s: %s.\n",
filename
, strerror(errno
));
new->t_data
= sb
.st_mtime
;
* True if file belongs to a user ID for which the equivalent
* of the getgrnam() 9.2.1 [POSIX.1] function returns NULL.
return(group_from_gid(entry
->fts_statb
.st_gid
, 1));
ftsoptions
&= ~FTS_NOSTAT
;
NEW(T_NOGROUP
, f_nogroup
);
* True if file belongs to a user ID for which the equivalent
* of the getpwuid() 9.2.2 [POSIX.1] function returns NULL.
return(user_from_uid(entry
->fts_statb
.st_uid
, 1));
ftsoptions
&= ~FTS_NOSTAT
;
* The mode argument is used to represent file mode bits. If it starts
* with a leading digit, it's treated as an octal mode, otherwise as a
mode
= entry
->fts_statb
.st_mode
&
(S_ISUID
|S_ISGID
|S_ISTXT
|S_IRWXU
|S_IRWXG
|S_IRWXO
);
return((plan
->m_data
| mode
) == mode
);
return(mode
== plan
->m_data
);
ftsoptions
&= ~FTS_NOSTAT
;
if ((set
= setmode(perm
)) == NULL
)
bad_arg("-perm", "illegal mode string");
new->m_data
= getmode(set
, 0);
* Always true, causes the current pathame to be written to
(void)printf("%s\n", entry
->fts_path
);
* Prune a portion of the hierarchy.
if (ftsset(tree
, entry
, FTS_SKIP
)) {
"find: %s: %s.\n", entry
->fts_path
, strerror(errno
));
* -size n[c] functions --
* True if the file size in bytes, divided by an implementation defined
* value and rounded up to the next integer, is n. If n is followed by
* a c, the size is in bytes.
size
= divsize
? (entry
->fts_statb
.st_size
+ FIND_SIZE
- 1) /
FIND_SIZE
: entry
->fts_statb
.st_size
;
COMPARE(size
, plan
->o_data
);
ftsoptions
&= ~FTS_NOSTAT
;
new->o_data
= find_parsenum(new, "-size", arg
, &endch
);
* True if the type of the file is c, where c is b, c, d, p, or f for
* block special file, character special file, directory, FIFO, or
* regular file, respectively.
return((entry
->fts_statb
.st_mode
& S_IFMT
) == plan
->m_data
);
ftsoptions
&= ~FTS_NOSTAT
;
bad_arg("-type", "unknown type");
* -user uname functions --
* True if the file belongs to the user uname. If uname is numeric and
* an equivalent of the getpwnam() S9.2.2 [POSIX.1] function does not
* return a valid user name, uname is taken as a user ID.
return(entry
->fts_statb
.st_uid
== plan
->u_data
);
ftsoptions
&= ~FTS_NOSTAT
;
if (uid
== 0 && username
[0] != '0')
bad_arg("-user", "no such user");
* Always true, causes find not to decend past directories that have a
* different device ID (st_dev, see stat() S5.6.2 [POSIX.1])
ftsoptions
&= ~FTS_NOSTAT
;
NEW(T_XDEV
, f_always_true
);
* ( expression ) functions --
* True if expression is true.
for (p
= plan
->p_data
[0];
p
&& (state
= (p
->eval
)(p
, entry
)); p
= p
->next
);
* T_OPENPAREN and T_CLOSEPAREN nodes are temporary place markers. They are
* eliminated during phase 2 of find_formplan() --- the '(' node is converted
* to a T_EXPR node containing the expression and the ')' node is discarded.
NEW(T_OPENPAREN
, (int (*)())-1);
NEW(T_CLOSEPAREN
, (int (*)())-1);
* True if the difference between the file modification time and the
* current time is n 24 hour periods.
COMPARE((now
- entry
->fts_statb
.st_mtime
+ SECSPERDAY
- 1) /
SECSPERDAY
, plan
->t_data
);
ftsoptions
&= ~FTS_NOSTAT
;
new->t_data
= find_parsenum(new, "-mtime", arg
, (char *)NULL
);
* ! expression functions --
* Negation of a primary; the unary NOT operator.
for (p
= plan
->p_data
[0];
p
&& (state
= (p
->eval
)(p
, entry
)); p
= p
->next
);
* expression -o expression functions --
* Alternation of primaries; the OR operator. The second expression is
* not evaluated if the first expression is true.
for (p
= plan
->p_data
[0];
p
&& (state
= (p
->eval
)(p
, entry
)); p
= p
->next
);
for (p
= plan
->p_data
[1];
p
&& (state
= (p
->eval
)(p
, entry
)); p
= p
->next
);