* 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.26 (Berkeley) %G%";
#define COMPARE(a, b) { \
static PLAN
*palloc
__P((enum ntype
, int (*) __P((PLAN
*, FTSENT
*))));
* Parse a string of the form [+-]# and return the value.
find_parsenum(plan
, option
, vp
, endch
)
char *option
, *vp
, *endch
;
char *endchar
, *str
; /* Pointer to character ending conversion. */
/* Determine comparison from leading + or -. */
plan
->flags
= F_LESSTHAN
;
* 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
== 0 && endchar
== str
)
errx(1, "%s: %s: illegal numeric value", option
, vp
);
if (endchar
[0] && (endch
== NULL
|| endchar
[0] != *endch
))
errx(1, "%s: %s: illegal trailing character", option
, vp
);
* The value of n for the inode times (atime, ctime, and mtime) is a range,
* i.e. n matches from (n - 1) to n 24 hour periods. This interacts with
* -n, such that "-mtime -1" would be less than 0 days, which isn't what the
* user wanted. Correct so that -1 is "less than 1".
#define TIME_CORRECT(p, ttype) \
if ((p)->type == ttype && (p)->flags == F_LESSTHAN) \
* True if the difference between the file access time and the
* current time is n 24 hour periods.
COMPARE((now
- entry
->fts_statp
->st_atime
+
SECSPERDAY
- 1) / SECSPERDAY
, plan
->t_data
);
ftsoptions
&= ~FTS_NOSTAT
;
new = palloc(N_ATIME
, f_atime
);
new->t_data
= find_parsenum(new, "-atime", arg
, NULL
);
TIME_CORRECT(new, N_ATIME
);
* 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_statp
->st_ctime
+
SECSPERDAY
- 1) / SECSPERDAY
, plan
->t_data
);
ftsoptions
&= ~FTS_NOSTAT
;
new = palloc(N_CTIME
, f_ctime
);
new->t_data
= find_parsenum(new, "-ctime", arg
, NULL
);
TIME_CORRECT(new, N_CTIME
);
* 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
)
return (palloc(N_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
)
brace_subst(plan
->e_orig
[cnt
], &plan
->e_argv
[cnt
],
entry
->fts_path
, plan
->e_len
[cnt
]);
if (plan
->flags
== F_NEEDOK
&& !queryuser(plan
->e_argv
))
execvp(plan
->e_argv
[0], plan
->e_argv
);
warn("%s", plan
->e_argv
[0]);
pid
= waitpid(pid
, &status
, 0);
return (pid
!= -1 && WIFEXITED(status
) && !WEXITSTATUS(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
;
new = palloc(N_EXEC
, f_exec
);
for (ap
= argv
= *argvp
;; ++ap
) {
"%s: no terminating \";\"", isok
? "-ok" : "-exec");
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(int));
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
)MAXPATHLEN
);
new->e_len
[cnt
] = MAXPATHLEN
;
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
;
return (palloc(N_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_statp
->st_dev
) {
curdev
= entry
->fts_statp
->st_dev
;
* Statfs follows symlinks; find wants the link's file system,
if (entry
->fts_info
== FTS_SL
||
entry
->fts_info
== FTS_SLNONE
) {
if (p
= strrchr(entry
->fts_accpath
, '/'))
if (statfs(entry
->fts_accpath
, &sb
))
err(1, "%s", entry
->fts_accpath
);
return (val
& plan
->mt_data
);
return (val
== plan
->mt_data
);
ftsoptions
&= ~FTS_NOSTAT
;
new = palloc(N_FSTYPE
, f_fstype
);
if (!strcmp(arg
, "local")) {
new->mt_data
= MNT_LOCAL
;
if (!strcmp(arg
, "mfs")) {
new->mt_data
= MOUNT_MFS
;
if (!strcmp(arg
, "nfs")) {
new->mt_data
= MOUNT_NFS
;
if (!strcmp(arg
, "pc")) {
if (!strcmp(arg
, "rdonly")) {
new->mt_data
= MNT_RDONLY
;
if (!strcmp(arg
, "ufs")) {
new->mt_data
= MOUNT_UFS
;
errx(1, "%s: unknown file type", 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_statp
->st_gid
== plan
->g_data
);
ftsoptions
&= ~FTS_NOSTAT
;
if (gid
== 0 && gname
[0] != '0')
errx(1, "-group: %s: no such group", gname
);
new = palloc(N_GROUP
, f_group
);
* True if the file has inode # n.
COMPARE(entry
->fts_statp
->st_ino
, plan
->i_data
);
ftsoptions
&= ~FTS_NOSTAT
;
new = palloc(N_INUM
, f_inum
);
new->i_data
= find_parsenum(new, "-inum", arg
, NULL
);
* True if the file has n links.
COMPARE(entry
->fts_statp
->st_nlink
, plan
->l_data
);
ftsoptions
&= ~FTS_NOSTAT
;
new = palloc(N_LINKS
, f_links
);
new->l_data
= (nlink_t
)find_parsenum(new, "-links", arg
, NULL
);
* Always true - prints the current entry to stdout in "ls" format.
printlong(entry
->fts_path
, entry
->fts_accpath
, entry
->fts_statp
);
ftsoptions
&= ~FTS_NOSTAT
;
return (palloc(N_LS
, f_ls
));
* True if the difference between the file modification time and the
* current time is n 24 hour periods.
COMPARE((now
- entry
->fts_statp
->st_mtime
+ SECSPERDAY
- 1) /
SECSPERDAY
, plan
->t_data
);
ftsoptions
&= ~FTS_NOSTAT
;
new = palloc(N_MTIME
, f_mtime
);
new->t_data
= find_parsenum(new, "-mtime", arg
, NULL
);
TIME_CORRECT(new, N_MTIME
);
* 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
, 0));
new = palloc(N_NAME
, f_name
);
* -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_statp
->st_mtime
> plan
->t_data
);
ftsoptions
&= ~FTS_NOSTAT
;
new = palloc(N_NEWER
, f_newer
);
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_statp
->st_gid
, 1) ? 1 : 0);
ftsoptions
&= ~FTS_NOSTAT
;
return (palloc(N_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_statp
->st_uid
, 1) ? 1 : 0);
ftsoptions
&= ~FTS_NOSTAT
;
return (palloc(N_NOUSER
, f_nouser
));
* True if the path of the filename being examined
* matches pattern using Pattern Matching Notation S3.14
return (!fnmatch(plan
->c_data
, entry
->fts_path
, 0));
new = palloc(N_NAME
, f_path
);
* 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_statp
->st_mode
&
(S_ISUID
|S_ISGID
|S_ISTXT
|S_IRWXU
|S_IRWXG
|S_IRWXO
);
if (plan
->flags
== F_ATLEAST
)
return ((plan
->m_data
| mode
) == mode
);
return (mode
== plan
->m_data
);
ftsoptions
&= ~FTS_NOSTAT
;
new = palloc(N_PERM
, f_perm
);
if ((set
= setmode(perm
)) == NULL
)
err(1, "-perm: %s: illegal mode string", perm
);
new->m_data
= getmode(set
, 0);
* Always true, causes the current pathame to be written to
(void)printf("%s\n", entry
->fts_path
);
return (palloc(N_PRINT
, f_print
));
* Prune a portion of the hierarchy.
if (fts_set(tree
, entry
, FTS_SKIP
))
err(1, "%s", entry
->fts_path
);
return (palloc(N_PRUNE
, f_prune
));
* -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_statp
->st_size
+ FIND_SIZE
- 1) /
FIND_SIZE
: entry
->fts_statp
->st_size
;
COMPARE(size
, plan
->o_data
);
ftsoptions
&= ~FTS_NOSTAT
;
new = palloc(N_SIZE
, f_size
);
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_statp
->st_mode
& S_IFMT
) == plan
->m_data
);
ftsoptions
&= ~FTS_NOSTAT
;
errx(1, "-type: %s: unknown type", typestring
);
new = palloc(N_TYPE
, f_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_statp
->st_uid
== plan
->u_data
);
ftsoptions
&= ~FTS_NOSTAT
;
if (uid
== 0 && username
[0] != '0')
errx(1, "-user: %s: no such user", username
);
new = palloc(N_USER
, f_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])
return (palloc(N_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
);
* N_OPENPAREN and N_CLOSEPAREN nodes are temporary place markers. They are
* eliminated during phase 2 of find_formplan() --- the '(' node is converted
* to a N_EXPR node containing the expression and the ')' node is discarded.
return (palloc(N_OPENPAREN
, (int (*)())-1));
return (palloc(N_CLOSEPAREN
, (int (*)())-1));
* ! 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
);
return (palloc(N_NOT
, f_not
));
* 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
);
return (palloc(N_OR
, f_or
));
int (*f
) __P((PLAN
*, FTSENT
*));
if (new = malloc(sizeof(PLAN
))) {