1994-05-27 12:33:43 +00:00
|
|
|
/*-
|
|
|
|
* Copyright (c) 1990, 1993
|
|
|
|
* The Regents of the University of California. All rights reserved.
|
|
|
|
*
|
|
|
|
* This code is derived from software contributed to Berkeley by
|
|
|
|
* Cimarron D. Taylor of the University of California, Berkeley.
|
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
* are met:
|
|
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
|
|
* documentation and/or other materials provided with the distribution.
|
|
|
|
* 3. All advertising materials mentioning features or use of this software
|
|
|
|
* must display the following acknowledgement:
|
|
|
|
* This product includes software developed by the University of
|
|
|
|
* California, Berkeley and its contributors.
|
|
|
|
* 4. Neither the name of the University nor the names of its contributors
|
|
|
|
* may be used to endorse or promote products derived from this software
|
|
|
|
* without specific prior written permission.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
|
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
|
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
|
|
* SUCH DAMAGE.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef lint
|
2000-06-12 11:12:41 +00:00
|
|
|
#if 0
|
|
|
|
static const char sccsid[] = "@(#)function.c 8.10 (Berkeley) 5/4/95";
|
|
|
|
#else
|
|
|
|
static const char rcsid[] =
|
|
|
|
"$FreeBSD$";
|
|
|
|
#endif
|
1994-05-27 12:33:43 +00:00
|
|
|
#endif /* not lint */
|
|
|
|
|
|
|
|
#include <sys/param.h>
|
|
|
|
#include <sys/ucred.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <sys/wait.h>
|
|
|
|
#include <sys/mount.h>
|
2001-05-03 18:05:35 +00:00
|
|
|
#include <sys/timeb.h>
|
1994-05-27 12:33:43 +00:00
|
|
|
|
2001-01-23 11:16:50 +00:00
|
|
|
#include <dirent.h>
|
1994-05-27 12:33:43 +00:00
|
|
|
#include <err.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <fnmatch.h>
|
|
|
|
#include <fts.h>
|
|
|
|
#include <grp.h>
|
|
|
|
#include <pwd.h>
|
2001-02-23 16:20:55 +00:00
|
|
|
#include <regex.h>
|
1994-05-27 12:33:43 +00:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
|
|
|
|
#include "find.h"
|
|
|
|
|
2001-05-03 18:05:35 +00:00
|
|
|
time_t get_date __P((char *date, struct timeb *now));
|
|
|
|
|
1994-05-27 12:33:43 +00:00
|
|
|
#define COMPARE(a, b) { \
|
2001-05-03 18:05:35 +00:00
|
|
|
switch (plan->flags & F_ELG_MASK) { \
|
1994-05-27 12:33:43 +00:00
|
|
|
case F_EQUAL: \
|
|
|
|
return (a == b); \
|
|
|
|
case F_LESSTHAN: \
|
|
|
|
return (a < b); \
|
|
|
|
case F_GREATER: \
|
|
|
|
return (a > b); \
|
|
|
|
default: \
|
|
|
|
abort(); \
|
|
|
|
} \
|
|
|
|
}
|
|
|
|
|
2001-05-03 18:05:35 +00:00
|
|
|
static PLAN *
|
|
|
|
palloc(option)
|
|
|
|
OPTION *option;
|
|
|
|
{
|
|
|
|
PLAN *new;
|
|
|
|
|
|
|
|
if ((new = malloc(sizeof(PLAN))) == NULL)
|
|
|
|
err(1, NULL);
|
|
|
|
new->execute = option->execute;
|
|
|
|
new->flags = option->flags;
|
|
|
|
new->next = NULL;
|
|
|
|
return new;
|
|
|
|
}
|
1994-05-27 12:33:43 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* find_parsenum --
|
|
|
|
* Parse a string of the form [+-]# and return the value.
|
|
|
|
*/
|
1996-04-07 12:58:13 +00:00
|
|
|
static long long
|
1994-05-27 12:33:43 +00:00
|
|
|
find_parsenum(plan, option, vp, endch)
|
|
|
|
PLAN *plan;
|
|
|
|
char *option, *vp, *endch;
|
|
|
|
{
|
1996-04-07 12:58:13 +00:00
|
|
|
long long value;
|
1994-05-27 12:33:43 +00:00
|
|
|
char *endchar, *str; /* Pointer to character ending conversion. */
|
1995-05-30 06:41:30 +00:00
|
|
|
|
1994-05-27 12:33:43 +00:00
|
|
|
/* Determine comparison from leading + or -. */
|
|
|
|
str = vp;
|
|
|
|
switch (*str) {
|
|
|
|
case '+':
|
|
|
|
++str;
|
2001-05-03 18:05:35 +00:00
|
|
|
plan->flags |= F_GREATER;
|
1994-05-27 12:33:43 +00:00
|
|
|
break;
|
|
|
|
case '-':
|
|
|
|
++str;
|
2001-05-03 18:05:35 +00:00
|
|
|
plan->flags |= F_LESSTHAN;
|
1994-05-27 12:33:43 +00:00
|
|
|
break;
|
|
|
|
default:
|
2001-05-03 18:05:35 +00:00
|
|
|
plan->flags |= F_EQUAL;
|
1994-05-27 12:33:43 +00:00
|
|
|
break;
|
|
|
|
}
|
1995-05-30 06:41:30 +00:00
|
|
|
|
1994-05-27 12:33:43 +00:00
|
|
|
/*
|
1996-04-07 12:58:13 +00:00
|
|
|
* Convert the string with strtoq(). Note, if strtoq() returns zero
|
1994-05-27 12:33:43 +00:00
|
|
|
* and endchar points to the beginning of the string we know we have
|
|
|
|
* a syntax error.
|
|
|
|
*/
|
1996-04-07 12:58:13 +00:00
|
|
|
value = strtoq(str, &endchar, 10);
|
1994-05-27 12:33:43 +00:00
|
|
|
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);
|
|
|
|
if (endch)
|
|
|
|
*endch = endchar[0];
|
2001-05-03 18:05:35 +00:00
|
|
|
return value;
|
1994-05-27 12:33:43 +00:00
|
|
|
}
|
|
|
|
|
2001-05-03 18:05:35 +00:00
|
|
|
/*
|
|
|
|
* nextarg --
|
|
|
|
* Check that another argument still exists, return a pointer to it,
|
|
|
|
* and increment the argument vector pointer.
|
|
|
|
*/
|
|
|
|
static char *
|
|
|
|
nextarg(option, argvp)
|
|
|
|
OPTION *option;
|
|
|
|
char ***argvp;
|
|
|
|
{
|
|
|
|
char *arg;
|
|
|
|
|
|
|
|
if ((arg = **argvp) == 0)
|
|
|
|
errx(1, "%s: requires additional arguments", option->name);
|
|
|
|
(*argvp)++;
|
|
|
|
return arg;
|
|
|
|
} /* nextarg() */
|
|
|
|
|
1994-05-27 12:33:43 +00:00
|
|
|
/*
|
|
|
|
* 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".
|
|
|
|
*/
|
2001-05-03 18:05:35 +00:00
|
|
|
#define TIME_CORRECT(p) \
|
|
|
|
if (((p)->flags & F_ELG_MASK) == F_LESSTHAN) \
|
1994-05-27 12:33:43 +00:00
|
|
|
++((p)->t_data);
|
|
|
|
|
1997-10-13 21:06:22 +00:00
|
|
|
/*
|
2001-05-03 18:05:35 +00:00
|
|
|
* -[acm]min n functions --
|
1997-10-13 21:06:22 +00:00
|
|
|
*
|
2001-05-03 18:05:35 +00:00
|
|
|
* True if the difference between the
|
|
|
|
* file access time (-amin)
|
|
|
|
* last change of file status information (-cmin)
|
|
|
|
* file modification time (-mmin)
|
|
|
|
* and the current time is n min periods.
|
1997-10-13 21:06:22 +00:00
|
|
|
*/
|
|
|
|
int
|
2001-05-03 18:05:35 +00:00
|
|
|
f_Xmin(plan, entry)
|
1997-10-13 21:06:22 +00:00
|
|
|
PLAN *plan;
|
|
|
|
FTSENT *entry;
|
|
|
|
{
|
|
|
|
extern time_t now;
|
|
|
|
|
2001-05-03 18:05:35 +00:00
|
|
|
if (plan->flags & F_TIME_C) {
|
|
|
|
COMPARE((now - entry->fts_statp->st_ctime +
|
|
|
|
60 - 1) / 60, plan->t_data);
|
|
|
|
} else if (plan->flags & F_TIME_A) {
|
|
|
|
COMPARE((now - entry->fts_statp->st_atime +
|
|
|
|
60 - 1) / 60, plan->t_data);
|
|
|
|
} else {
|
|
|
|
COMPARE((now - entry->fts_statp->st_mtime +
|
|
|
|
60 - 1) / 60, plan->t_data);
|
|
|
|
}
|
1997-10-13 21:06:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
PLAN *
|
2001-05-03 18:05:35 +00:00
|
|
|
c_Xmin(option, argvp)
|
|
|
|
OPTION *option;
|
|
|
|
char ***argvp;
|
1997-10-13 21:06:22 +00:00
|
|
|
{
|
2001-05-03 18:05:35 +00:00
|
|
|
char *nmins;
|
1997-10-13 21:06:22 +00:00
|
|
|
PLAN *new;
|
|
|
|
|
2001-05-03 18:05:35 +00:00
|
|
|
nmins = nextarg(option, argvp);
|
1997-10-13 21:06:22 +00:00
|
|
|
ftsoptions &= ~FTS_NOSTAT;
|
|
|
|
|
2001-05-03 18:05:35 +00:00
|
|
|
new = palloc(option);
|
|
|
|
new->t_data = find_parsenum(new, option->name, nmins, NULL);
|
|
|
|
TIME_CORRECT(new);
|
|
|
|
return new;
|
1997-10-13 21:06:22 +00:00
|
|
|
}
|
|
|
|
|
1994-05-27 12:33:43 +00:00
|
|
|
/*
|
2001-05-03 18:05:35 +00:00
|
|
|
* -[acm]time n functions --
|
1994-05-27 12:33:43 +00:00
|
|
|
*
|
2001-05-03 18:05:35 +00:00
|
|
|
* True if the difference between the
|
|
|
|
* file access time (-atime)
|
|
|
|
* last change of file status information (-ctime)
|
|
|
|
* file modification time (-mtime)
|
|
|
|
* and the current time is n 24 hour periods.
|
1994-05-27 12:33:43 +00:00
|
|
|
*/
|
2001-05-03 18:05:35 +00:00
|
|
|
|
1994-05-27 12:33:43 +00:00
|
|
|
int
|
2001-05-03 18:05:35 +00:00
|
|
|
f_Xtime(plan, entry)
|
1994-05-27 12:33:43 +00:00
|
|
|
PLAN *plan;
|
|
|
|
FTSENT *entry;
|
|
|
|
{
|
|
|
|
extern time_t now;
|
|
|
|
|
2001-05-03 18:05:35 +00:00
|
|
|
if (plan->flags & F_TIME_C) {
|
|
|
|
COMPARE((now - entry->fts_statp->st_ctime +
|
|
|
|
86400 - 1) / 86400, plan->t_data);
|
|
|
|
} else if (plan->flags & F_TIME_A) {
|
|
|
|
COMPARE((now - entry->fts_statp->st_atime +
|
|
|
|
86400 - 1) / 86400, plan->t_data);
|
|
|
|
} else {
|
|
|
|
COMPARE((now - entry->fts_statp->st_mtime +
|
|
|
|
86400 - 1) / 86400, plan->t_data);
|
|
|
|
}
|
1994-05-27 12:33:43 +00:00
|
|
|
}
|
1995-05-30 06:41:30 +00:00
|
|
|
|
1994-05-27 12:33:43 +00:00
|
|
|
PLAN *
|
2001-05-03 18:05:35 +00:00
|
|
|
c_Xtime(option, argvp)
|
|
|
|
OPTION *option;
|
|
|
|
char ***argvp;
|
1994-05-27 12:33:43 +00:00
|
|
|
{
|
2001-05-03 18:05:35 +00:00
|
|
|
char *ndays;
|
1994-05-27 12:33:43 +00:00
|
|
|
PLAN *new;
|
|
|
|
|
2001-05-03 18:05:35 +00:00
|
|
|
ndays = nextarg(option, argvp);
|
1994-05-27 12:33:43 +00:00
|
|
|
ftsoptions &= ~FTS_NOSTAT;
|
|
|
|
|
2001-05-03 18:05:35 +00:00
|
|
|
new = palloc(option);
|
|
|
|
new->t_data = find_parsenum(new, option->name, ndays, NULL);
|
|
|
|
TIME_CORRECT(new);
|
|
|
|
return new;
|
1994-05-27 12:33:43 +00:00
|
|
|
}
|
1997-10-13 21:06:22 +00:00
|
|
|
|
|
|
|
/*
|
2001-05-03 18:05:35 +00:00
|
|
|
* -maxdepth/-mindepth n functions --
|
1997-10-13 21:06:22 +00:00
|
|
|
*
|
2001-05-03 18:05:35 +00:00
|
|
|
* Does the same as -prune if the level of the current file is
|
|
|
|
* greater/less than the specified maximum/minimum depth.
|
|
|
|
*
|
|
|
|
* Note that -maxdepth and -mindepth are handled specially in
|
|
|
|
* find_execute() so their f_* functions are set to f_always_true().
|
1997-10-13 21:06:22 +00:00
|
|
|
*/
|
|
|
|
PLAN *
|
2001-05-03 18:05:35 +00:00
|
|
|
c_mXXdepth(option, argvp)
|
|
|
|
OPTION *option;
|
|
|
|
char ***argvp;
|
1997-10-13 21:06:22 +00:00
|
|
|
{
|
2001-05-03 18:05:35 +00:00
|
|
|
char *dstr;
|
1997-10-13 21:06:22 +00:00
|
|
|
PLAN *new;
|
|
|
|
|
2001-05-03 18:05:35 +00:00
|
|
|
dstr = nextarg(option, argvp);
|
|
|
|
if (dstr[0] == '-')
|
|
|
|
/* all other errors handled by find_parsenum() */
|
|
|
|
errx(1, "%s: %s: value must be positive", option->name, dstr);
|
1997-10-13 21:06:22 +00:00
|
|
|
|
2001-05-03 18:05:35 +00:00
|
|
|
new = palloc(option);
|
|
|
|
if (option->flags & F_MAXDEPTH)
|
|
|
|
maxdepth = find_parsenum(new, option->name, dstr, NULL);
|
|
|
|
else
|
|
|
|
mindepth = find_parsenum(new, option->name, dstr, NULL);
|
|
|
|
return new;
|
1997-10-13 21:06:22 +00:00
|
|
|
}
|
|
|
|
|
1994-05-27 12:33:43 +00:00
|
|
|
/*
|
2001-05-03 18:05:35 +00:00
|
|
|
* -delete functions --
|
1994-05-27 12:33:43 +00:00
|
|
|
*
|
2001-05-03 18:05:35 +00:00
|
|
|
* True always. Makes its best shot and continues on regardless.
|
1994-05-27 12:33:43 +00:00
|
|
|
*/
|
|
|
|
int
|
2001-05-03 18:05:35 +00:00
|
|
|
f_delete(plan, entry)
|
1994-05-27 12:33:43 +00:00
|
|
|
PLAN *plan;
|
|
|
|
FTSENT *entry;
|
|
|
|
{
|
2001-05-03 18:05:35 +00:00
|
|
|
/* ignore these from fts */
|
|
|
|
if (strcmp(entry->fts_accpath, ".") == 0 ||
|
|
|
|
strcmp(entry->fts_accpath, "..") == 0)
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
/* sanity check */
|
|
|
|
if (isdepth == 0 || /* depth off */
|
|
|
|
(ftsoptions & FTS_NOSTAT) || /* not stat()ing */
|
|
|
|
!(ftsoptions & FTS_PHYSICAL) || /* physical off */
|
|
|
|
(ftsoptions & FTS_LOGICAL)) /* or finally, logical on */
|
|
|
|
errx(1, "-delete: insecure options got turned on");
|
|
|
|
|
|
|
|
/* Potentially unsafe - do not accept relative paths whatsoever */
|
|
|
|
if (strchr(entry->fts_accpath, '/') != NULL)
|
|
|
|
errx(1, "-delete: %s: relative path potentially not safe",
|
|
|
|
entry->fts_accpath);
|
1994-05-27 12:33:43 +00:00
|
|
|
|
2001-05-03 18:05:35 +00:00
|
|
|
/* Turn off user immutable bits if running as root */
|
|
|
|
if ((entry->fts_statp->st_flags & (UF_APPEND|UF_IMMUTABLE)) &&
|
|
|
|
!(entry->fts_statp->st_flags & (SF_APPEND|SF_IMMUTABLE)) &&
|
|
|
|
geteuid() == 0)
|
|
|
|
chflags(entry->fts_accpath,
|
|
|
|
entry->fts_statp->st_flags &= ~(UF_APPEND|UF_IMMUTABLE));
|
|
|
|
|
|
|
|
/* rmdir directories, unlink everything else */
|
|
|
|
if (S_ISDIR(entry->fts_statp->st_mode)) {
|
|
|
|
if (rmdir(entry->fts_accpath) < 0 && errno != ENOTEMPTY)
|
|
|
|
warn("-delete: rmdir(%s)", entry->fts_path);
|
|
|
|
} else {
|
|
|
|
if (unlink(entry->fts_accpath) < 0)
|
|
|
|
warn("-delete: unlink(%s)", entry->fts_path);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* "succeed" */
|
|
|
|
return 1;
|
1994-05-27 12:33:43 +00:00
|
|
|
}
|
1995-05-30 06:41:30 +00:00
|
|
|
|
1994-05-27 12:33:43 +00:00
|
|
|
PLAN *
|
2001-05-03 18:05:35 +00:00
|
|
|
c_delete(option, argvp)
|
|
|
|
OPTION *option;
|
|
|
|
char ***argvp;
|
1994-05-27 12:33:43 +00:00
|
|
|
{
|
|
|
|
|
2001-05-03 18:05:35 +00:00
|
|
|
ftsoptions &= ~FTS_NOSTAT; /* no optimise */
|
|
|
|
ftsoptions |= FTS_PHYSICAL; /* disable -follow */
|
|
|
|
ftsoptions &= ~FTS_LOGICAL; /* disable -follow */
|
|
|
|
isoutput = 1; /* possible output */
|
|
|
|
isdepth = 1; /* -depth implied */
|
1994-05-27 12:33:43 +00:00
|
|
|
|
2001-05-03 18:05:35 +00:00
|
|
|
return palloc(option);
|
1994-05-27 12:33:43 +00:00
|
|
|
}
|
|
|
|
|
1997-10-13 21:06:22 +00:00
|
|
|
|
1994-05-27 12:33:43 +00:00
|
|
|
/*
|
|
|
|
* -depth functions --
|
|
|
|
*
|
|
|
|
* Always true, causes descent of the directory hierarchy to be done
|
|
|
|
* so that all entries in a directory are acted on before the directory
|
|
|
|
* itself.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
f_always_true(plan, entry)
|
|
|
|
PLAN *plan;
|
|
|
|
FTSENT *entry;
|
|
|
|
{
|
2001-05-03 18:05:35 +00:00
|
|
|
return 1;
|
1994-05-27 12:33:43 +00:00
|
|
|
}
|
1995-05-30 06:41:30 +00:00
|
|
|
|
1994-05-27 12:33:43 +00:00
|
|
|
PLAN *
|
2001-05-03 18:05:35 +00:00
|
|
|
c_depth(option, argvp)
|
|
|
|
OPTION *option;
|
1994-05-27 12:33:43 +00:00
|
|
|
char ***argvp;
|
|
|
|
{
|
2001-05-03 18:05:35 +00:00
|
|
|
isdepth = 1;
|
1994-05-27 12:33:43 +00:00
|
|
|
|
2001-05-03 18:05:35 +00:00
|
|
|
return palloc(option);
|
1997-08-29 23:09:45 +00:00
|
|
|
}
|
|
|
|
|
2001-01-23 11:16:50 +00:00
|
|
|
/*
|
|
|
|
* -empty functions --
|
|
|
|
*
|
|
|
|
* True if the file or directory is empty
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
f_empty(plan, entry)
|
|
|
|
PLAN *plan;
|
|
|
|
FTSENT *entry;
|
|
|
|
{
|
2001-05-03 18:05:35 +00:00
|
|
|
if (S_ISREG(entry->fts_statp->st_mode) &&
|
|
|
|
entry->fts_statp->st_size == 0)
|
|
|
|
return 1;
|
2001-01-23 11:16:50 +00:00
|
|
|
if (S_ISDIR(entry->fts_statp->st_mode)) {
|
|
|
|
struct dirent *dp;
|
|
|
|
int empty;
|
|
|
|
DIR *dir;
|
|
|
|
|
|
|
|
empty = 1;
|
|
|
|
dir = opendir(entry->fts_accpath);
|
|
|
|
if (dir == NULL)
|
|
|
|
err(1, "%s", entry->fts_accpath);
|
|
|
|
for (dp = readdir(dir); dp; dp = readdir(dir))
|
|
|
|
if (dp->d_name[0] != '.' ||
|
|
|
|
(dp->d_name[1] != '\0' &&
|
|
|
|
(dp->d_name[1] != '.' || dp->d_name[2] != '\0'))) {
|
|
|
|
empty = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
closedir(dir);
|
2001-05-03 18:05:35 +00:00
|
|
|
return empty;
|
2001-01-23 11:16:50 +00:00
|
|
|
}
|
2001-05-03 18:05:35 +00:00
|
|
|
return 0;
|
2001-01-23 11:16:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
PLAN *
|
2001-05-03 18:05:35 +00:00
|
|
|
c_empty(option, argvp)
|
|
|
|
OPTION *option;
|
|
|
|
char ***argvp;
|
2001-01-23 11:16:50 +00:00
|
|
|
{
|
|
|
|
ftsoptions &= ~FTS_NOSTAT;
|
|
|
|
|
2001-05-03 18:05:35 +00:00
|
|
|
return palloc(option);
|
2001-01-23 11:16:50 +00:00
|
|
|
}
|
|
|
|
|
1997-08-29 23:09:45 +00:00
|
|
|
/*
|
2001-05-03 18:05:35 +00:00
|
|
|
* [-exec | -execdir | -ok] utility [arg ... ] ; functions --
|
1997-08-29 23:09:45 +00:00
|
|
|
*
|
|
|
|
* True if the executed utility returns a zero value as exit status.
|
|
|
|
* The end of the primary expression is delimited by a semicolon. If
|
2001-05-03 18:05:35 +00:00
|
|
|
* "{}" occurs anywhere, it gets replaced by the current pathname,
|
|
|
|
* or, in the case of -execdir, the current basename (filename
|
|
|
|
* without leading directory prefix). For -exec and -ok,
|
|
|
|
* the current directory for the execution of utility is the same as
|
|
|
|
* the current directory when the find utility was started, whereas
|
|
|
|
* for -execdir, it is the directory the file resides in.
|
|
|
|
*
|
|
|
|
* The primary -ok differs from -exec in that it requests affirmation
|
|
|
|
* of the user before executing the utility.
|
1997-08-29 23:09:45 +00:00
|
|
|
*/
|
|
|
|
int
|
2001-05-03 18:05:35 +00:00
|
|
|
f_exec(plan, entry)
|
1997-08-29 23:09:45 +00:00
|
|
|
register PLAN *plan;
|
|
|
|
FTSENT *entry;
|
|
|
|
{
|
2001-05-03 18:05:35 +00:00
|
|
|
extern int dotfd;
|
1997-08-29 23:09:45 +00:00
|
|
|
register int cnt;
|
|
|
|
pid_t pid;
|
|
|
|
int status;
|
|
|
|
char *file;
|
|
|
|
|
|
|
|
/* XXX - if file/dir ends in '/' this will not work -- can it? */
|
2001-05-03 18:05:35 +00:00
|
|
|
if ((plan->flags & F_EXECDIR) && \
|
|
|
|
(file = strrchr(entry->fts_path, '/')))
|
|
|
|
file++;
|
1997-08-29 23:09:45 +00:00
|
|
|
else
|
2001-05-03 18:05:35 +00:00
|
|
|
file = entry->fts_path;
|
1997-08-29 23:09:45 +00:00
|
|
|
|
|
|
|
for (cnt = 0; plan->e_argv[cnt]; ++cnt)
|
|
|
|
if (plan->e_len[cnt])
|
|
|
|
brace_subst(plan->e_orig[cnt], &plan->e_argv[cnt],
|
|
|
|
file, plan->e_len[cnt]);
|
|
|
|
|
2001-05-03 18:05:35 +00:00
|
|
|
if ((plan->flags & F_NEEDOK) && !queryuser(plan->e_argv))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* make sure find output is interspersed correctly with subprocesses */
|
1997-08-29 23:09:45 +00:00
|
|
|
fflush(stdout);
|
|
|
|
fflush(stderr);
|
|
|
|
|
1998-10-13 14:52:33 +00:00
|
|
|
switch (pid = fork()) {
|
1997-08-29 23:09:45 +00:00
|
|
|
case -1:
|
|
|
|
err(1, "fork");
|
|
|
|
/* NOTREACHED */
|
|
|
|
case 0:
|
2001-05-03 18:05:35 +00:00
|
|
|
/* change dir back from where we started */
|
|
|
|
if (!(plan->flags & F_EXECDIR) && fchdir(dotfd)) {
|
|
|
|
warn("chdir");
|
|
|
|
_exit(1);
|
|
|
|
}
|
1997-08-29 23:09:45 +00:00
|
|
|
execvp(plan->e_argv[0], plan->e_argv);
|
|
|
|
warn("%s", plan->e_argv[0]);
|
|
|
|
_exit(1);
|
|
|
|
}
|
|
|
|
pid = waitpid(pid, &status, 0);
|
|
|
|
return (pid != -1 && WIFEXITED(status) && !WEXITSTATUS(status));
|
|
|
|
}
|
2001-05-03 18:05:35 +00:00
|
|
|
|
1997-08-29 23:09:45 +00:00
|
|
|
/*
|
2001-05-03 18:05:35 +00:00
|
|
|
* c_exec, c_execdir, c_ok --
|
1997-08-29 23:09:45 +00:00
|
|
|
* 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 *
|
2001-05-03 18:05:35 +00:00
|
|
|
c_exec(option, argvp)
|
|
|
|
OPTION *option;
|
1997-08-29 23:09:45 +00:00
|
|
|
char ***argvp;
|
|
|
|
{
|
|
|
|
PLAN *new; /* node returned */
|
|
|
|
register int cnt;
|
|
|
|
register char **argv, **ap, *p;
|
|
|
|
|
2001-05-03 18:05:35 +00:00
|
|
|
/* XXX - was in c_execdir, but seems unnecessary!?
|
1997-08-29 23:09:45 +00:00
|
|
|
ftsoptions &= ~FTS_NOSTAT;
|
2001-05-03 18:05:35 +00:00
|
|
|
*/
|
1997-08-29 23:09:45 +00:00
|
|
|
isoutput = 1;
|
2001-05-03 18:05:35 +00:00
|
|
|
|
|
|
|
/* XXX - this is a change from the previous coding */
|
|
|
|
new = palloc(option);
|
1997-08-29 23:09:45 +00:00
|
|
|
|
|
|
|
for (ap = argv = *argvp;; ++ap) {
|
|
|
|
if (!*ap)
|
|
|
|
errx(1,
|
2001-05-03 18:05:35 +00:00
|
|
|
"%s: no terminating \";\"", option->name);
|
1997-08-29 23:09:45 +00:00
|
|
|
if (**ap == ';')
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
cnt = ap - *argvp + 1;
|
2001-07-24 14:12:05 +00:00
|
|
|
if ((new->e_argv = malloc((u_int)cnt * sizeof(char *))) == NULL)
|
|
|
|
err(1, (char *)NULL);
|
|
|
|
if ((new->e_orig = malloc((u_int)cnt * sizeof(char *))) == NULL)
|
|
|
|
err(1, (char *)NULL);
|
|
|
|
if ((new->e_len = malloc((u_int)cnt * sizeof(int))) == NULL)
|
|
|
|
err(1, (char *)NULL);
|
1997-08-29 23:09:45 +00:00
|
|
|
|
|
|
|
for (argv = *argvp, cnt = 0; argv < ap; ++argv, ++cnt) {
|
|
|
|
new->e_orig[cnt] = *argv;
|
|
|
|
for (p = *argv; *p; ++p)
|
|
|
|
if (p[0] == '{' && p[1] == '}') {
|
2001-07-24 14:12:05 +00:00
|
|
|
if ((new->e_argv[cnt] =
|
|
|
|
malloc((u_int)MAXPATHLEN)) == NULL)
|
|
|
|
err(1, (char *)NULL);
|
1997-08-29 23:09:45 +00:00
|
|
|
new->e_len[cnt] = MAXPATHLEN;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (!*p) {
|
|
|
|
new->e_argv[cnt] = *argv;
|
|
|
|
new->e_len[cnt] = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
new->e_argv[cnt] = new->e_orig[cnt] = NULL;
|
|
|
|
|
1994-05-27 12:33:43 +00:00
|
|
|
*argvp = argv + 1;
|
2001-05-03 18:05:35 +00:00
|
|
|
return new;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
f_flags(plan, entry)
|
|
|
|
PLAN *plan;
|
|
|
|
FTSENT *entry;
|
|
|
|
{
|
|
|
|
u_long flags;
|
|
|
|
|
|
|
|
flags = entry->fts_statp->st_flags &
|
|
|
|
(UF_NODUMP | UF_IMMUTABLE | UF_APPEND | UF_OPAQUE |
|
|
|
|
SF_ARCHIVED | SF_IMMUTABLE | SF_APPEND);
|
|
|
|
if (plan->flags & F_ATLEAST)
|
|
|
|
/* note that plan->fl_flags always is a subset of
|
|
|
|
plan->fl_mask */
|
|
|
|
return (flags & plan->fl_mask) == plan->fl_flags;
|
|
|
|
else if (plan->flags & F_ANY)
|
|
|
|
return flags & plan->fl_mask;
|
|
|
|
else
|
|
|
|
return flags == plan->fl_flags;
|
|
|
|
/* NOTREACHED */
|
|
|
|
}
|
|
|
|
|
|
|
|
PLAN *
|
|
|
|
c_flags(option, argvp)
|
|
|
|
OPTION *option;
|
|
|
|
char ***argvp;
|
|
|
|
{
|
|
|
|
char *flags_str;
|
|
|
|
PLAN *new;
|
|
|
|
u_long flags, notflags;
|
|
|
|
|
|
|
|
flags_str = nextarg(option, argvp);
|
|
|
|
ftsoptions &= ~FTS_NOSTAT;
|
|
|
|
|
|
|
|
new = palloc(option);
|
|
|
|
|
|
|
|
if (*flags_str == '-') {
|
|
|
|
new->flags |= F_ATLEAST;
|
|
|
|
flags_str++;
|
|
|
|
}
|
|
|
|
if (strtofflags(&flags_str, &flags, ¬flags) == 1)
|
|
|
|
errx(1, "%s: %s: illegal flags string", option->name, flags_str);
|
|
|
|
|
|
|
|
new->fl_flags = flags;
|
|
|
|
new->fl_mask = flags | notflags;
|
|
|
|
return new;
|
1994-05-27 12:33:43 +00:00
|
|
|
}
|
1995-05-30 06:41:30 +00:00
|
|
|
|
1994-05-27 12:33:43 +00:00
|
|
|
/*
|
|
|
|
* -follow functions --
|
|
|
|
*
|
|
|
|
* Always true, causes symbolic links to be followed on a global
|
|
|
|
* basis.
|
|
|
|
*/
|
|
|
|
PLAN *
|
2001-05-03 18:05:35 +00:00
|
|
|
c_follow(option, argvp)
|
|
|
|
OPTION *option;
|
|
|
|
char ***argvp;
|
1994-05-27 12:33:43 +00:00
|
|
|
{
|
|
|
|
ftsoptions &= ~FTS_PHYSICAL;
|
|
|
|
ftsoptions |= FTS_LOGICAL;
|
|
|
|
|
2001-05-03 18:05:35 +00:00
|
|
|
return palloc(option);
|
1994-05-27 12:33:43 +00:00
|
|
|
}
|
1995-05-30 06:41:30 +00:00
|
|
|
|
1994-05-27 12:33:43 +00:00
|
|
|
/*
|
|
|
|
* -fstype functions --
|
|
|
|
*
|
|
|
|
* True if the file is of a certain type.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
f_fstype(plan, entry)
|
|
|
|
PLAN *plan;
|
|
|
|
FTSENT *entry;
|
|
|
|
{
|
|
|
|
static dev_t curdev; /* need a guaranteed illegal dev value */
|
|
|
|
static int first = 1;
|
|
|
|
struct statfs sb;
|
1997-03-27 02:36:26 +00:00
|
|
|
static int val_type, val_flags;
|
1994-05-27 12:33:43 +00:00
|
|
|
char *p, save[2];
|
|
|
|
|
2001-05-03 18:05:35 +00:00
|
|
|
if ((plan->flags & F_MTMASK) == F_MTUNKNOWN)
|
|
|
|
return 0;
|
|
|
|
|
1994-05-27 12:33:43 +00:00
|
|
|
/* 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,
|
|
|
|
* not where it points.
|
|
|
|
*/
|
|
|
|
if (entry->fts_info == FTS_SL ||
|
|
|
|
entry->fts_info == FTS_SLNONE) {
|
|
|
|
if ((p = strrchr(entry->fts_accpath, '/')) != NULL)
|
|
|
|
++p;
|
|
|
|
else
|
|
|
|
p = entry->fts_accpath;
|
|
|
|
save[0] = p[0];
|
|
|
|
p[0] = '.';
|
|
|
|
save[1] = p[1];
|
|
|
|
p[1] = '\0';
|
1995-05-30 06:41:30 +00:00
|
|
|
} else
|
1994-05-27 12:33:43 +00:00
|
|
|
p = NULL;
|
|
|
|
|
|
|
|
if (statfs(entry->fts_accpath, &sb))
|
|
|
|
err(1, "%s", entry->fts_accpath);
|
|
|
|
|
|
|
|
if (p) {
|
|
|
|
p[0] = save[0];
|
|
|
|
p[1] = save[1];
|
|
|
|
}
|
|
|
|
|
|
|
|
first = 0;
|
1997-03-11 13:48:37 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Further tests may need both of these values, so
|
|
|
|
* always copy both of them.
|
|
|
|
*/
|
1997-03-27 02:36:26 +00:00
|
|
|
val_flags = sb.f_flags;
|
|
|
|
val_type = sb.f_type;
|
1994-05-27 12:33:43 +00:00
|
|
|
}
|
2001-05-03 18:05:35 +00:00
|
|
|
switch (plan->flags & F_MTMASK) {
|
1994-05-27 12:33:43 +00:00
|
|
|
case F_MTFLAG:
|
2001-05-03 18:05:35 +00:00
|
|
|
return val_flags & plan->mt_data;
|
1994-05-27 12:33:43 +00:00
|
|
|
case F_MTTYPE:
|
2001-05-03 18:05:35 +00:00
|
|
|
return val_type == plan->mt_data;
|
1994-05-27 12:33:43 +00:00
|
|
|
default:
|
|
|
|
abort();
|
|
|
|
}
|
|
|
|
}
|
1995-05-30 06:41:30 +00:00
|
|
|
|
1998-01-10 21:36:34 +00:00
|
|
|
#if !defined(__NetBSD__)
|
1994-05-27 12:33:43 +00:00
|
|
|
PLAN *
|
2001-05-03 18:05:35 +00:00
|
|
|
c_fstype(option, argvp)
|
|
|
|
OPTION *option;
|
|
|
|
char ***argvp;
|
1994-05-27 12:33:43 +00:00
|
|
|
{
|
2001-05-03 18:05:35 +00:00
|
|
|
char *fsname;
|
1994-05-27 12:33:43 +00:00
|
|
|
register PLAN *new;
|
1997-03-11 13:48:37 +00:00
|
|
|
struct vfsconf vfc;
|
2001-05-03 18:05:35 +00:00
|
|
|
|
|
|
|
fsname = nextarg(option, argvp);
|
1994-05-27 12:33:43 +00:00
|
|
|
ftsoptions &= ~FTS_NOSTAT;
|
1995-05-30 06:41:30 +00:00
|
|
|
|
2001-05-03 18:05:35 +00:00
|
|
|
new = palloc(option);
|
1997-03-11 13:48:37 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Check first for a filesystem name.
|
|
|
|
*/
|
2001-05-03 18:05:35 +00:00
|
|
|
if (getvfsbyname(fsname, &vfc) == 0) {
|
|
|
|
new->flags |= F_MTTYPE;
|
1997-03-11 13:48:37 +00:00
|
|
|
new->mt_data = vfc.vfc_typenum;
|
2001-05-03 18:05:35 +00:00
|
|
|
return new;
|
1997-03-11 13:48:37 +00:00
|
|
|
}
|
|
|
|
|
2001-05-03 18:05:35 +00:00
|
|
|
switch (*fsname) {
|
1994-05-27 12:33:43 +00:00
|
|
|
case 'l':
|
2001-05-03 18:05:35 +00:00
|
|
|
if (!strcmp(fsname, "local")) {
|
|
|
|
new->flags |= F_MTFLAG;
|
1994-05-27 12:33:43 +00:00
|
|
|
new->mt_data = MNT_LOCAL;
|
2001-05-03 18:05:35 +00:00
|
|
|
return new;
|
1994-05-27 12:33:43 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 'r':
|
2001-05-03 18:05:35 +00:00
|
|
|
if (!strcmp(fsname, "rdonly")) {
|
|
|
|
new->flags |= F_MTFLAG;
|
1994-05-27 12:33:43 +00:00
|
|
|
new->mt_data = MNT_RDONLY;
|
2001-05-03 18:05:35 +00:00
|
|
|
return new;
|
1994-05-27 12:33:43 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2001-05-03 18:05:35 +00:00
|
|
|
|
2000-07-28 20:02:42 +00:00
|
|
|
/*
|
|
|
|
* We need to make filesystem checks for filesystems
|
|
|
|
* that exists but aren't in the kernel work.
|
|
|
|
*/
|
2001-05-03 18:05:35 +00:00
|
|
|
fprintf(stderr, "Warning: Unknown filesystem type %s\n", fsname);
|
|
|
|
new->flags |= F_MTUNKNOWN;
|
|
|
|
return new;
|
1994-05-27 12:33:43 +00:00
|
|
|
}
|
2001-05-03 18:05:35 +00:00
|
|
|
#endif /* __NetBSD__ */
|
1995-05-30 06:41:30 +00:00
|
|
|
|
1994-05-27 12:33:43 +00:00
|
|
|
/*
|
|
|
|
* -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.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
f_group(plan, entry)
|
|
|
|
PLAN *plan;
|
|
|
|
FTSENT *entry;
|
|
|
|
{
|
2001-05-03 18:05:35 +00:00
|
|
|
return entry->fts_statp->st_gid == plan->g_data;
|
1994-05-27 12:33:43 +00:00
|
|
|
}
|
1995-05-30 06:41:30 +00:00
|
|
|
|
1994-05-27 12:33:43 +00:00
|
|
|
PLAN *
|
2001-05-03 18:05:35 +00:00
|
|
|
c_group(option, argvp)
|
|
|
|
OPTION *option;
|
|
|
|
char ***argvp;
|
1994-05-27 12:33:43 +00:00
|
|
|
{
|
2001-05-03 18:05:35 +00:00
|
|
|
char *gname;
|
1994-05-27 12:33:43 +00:00
|
|
|
PLAN *new;
|
|
|
|
struct group *g;
|
|
|
|
gid_t gid;
|
1995-05-30 06:41:30 +00:00
|
|
|
|
2001-05-03 18:05:35 +00:00
|
|
|
gname = nextarg(option, argvp);
|
1994-05-27 12:33:43 +00:00
|
|
|
ftsoptions &= ~FTS_NOSTAT;
|
|
|
|
|
|
|
|
g = getgrnam(gname);
|
|
|
|
if (g == NULL) {
|
|
|
|
gid = atoi(gname);
|
|
|
|
if (gid == 0 && gname[0] != '0')
|
2001-05-03 18:05:35 +00:00
|
|
|
errx(1, "%s: %s: no such group", option->name, gname);
|
1994-05-27 12:33:43 +00:00
|
|
|
} else
|
|
|
|
gid = g->gr_gid;
|
1995-05-30 06:41:30 +00:00
|
|
|
|
2001-05-03 18:05:35 +00:00
|
|
|
new = palloc(option);
|
1994-05-27 12:33:43 +00:00
|
|
|
new->g_data = gid;
|
2001-05-03 18:05:35 +00:00
|
|
|
return new;
|
1994-05-27 12:33:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* -inum n functions --
|
|
|
|
*
|
|
|
|
* True if the file has inode # n.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
f_inum(plan, entry)
|
|
|
|
PLAN *plan;
|
|
|
|
FTSENT *entry;
|
|
|
|
{
|
|
|
|
COMPARE(entry->fts_statp->st_ino, plan->i_data);
|
|
|
|
}
|
1995-05-30 06:41:30 +00:00
|
|
|
|
1994-05-27 12:33:43 +00:00
|
|
|
PLAN *
|
2001-05-03 18:05:35 +00:00
|
|
|
c_inum(option, argvp)
|
|
|
|
OPTION *option;
|
|
|
|
char ***argvp;
|
1994-05-27 12:33:43 +00:00
|
|
|
{
|
2001-05-03 18:05:35 +00:00
|
|
|
char *inum_str;
|
1994-05-27 12:33:43 +00:00
|
|
|
PLAN *new;
|
1995-05-30 06:41:30 +00:00
|
|
|
|
2001-05-03 18:05:35 +00:00
|
|
|
inum_str = nextarg(option, argvp);
|
1994-05-27 12:33:43 +00:00
|
|
|
ftsoptions &= ~FTS_NOSTAT;
|
1995-05-30 06:41:30 +00:00
|
|
|
|
2001-05-03 18:05:35 +00:00
|
|
|
new = palloc(option);
|
|
|
|
new->i_data = find_parsenum(new, option->name, inum_str, NULL);
|
|
|
|
return new;
|
1994-05-27 12:33:43 +00:00
|
|
|
}
|
1995-05-30 06:41:30 +00:00
|
|
|
|
1994-05-27 12:33:43 +00:00
|
|
|
/*
|
|
|
|
* -links n functions --
|
|
|
|
*
|
|
|
|
* True if the file has n links.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
f_links(plan, entry)
|
|
|
|
PLAN *plan;
|
|
|
|
FTSENT *entry;
|
|
|
|
{
|
|
|
|
COMPARE(entry->fts_statp->st_nlink, plan->l_data);
|
|
|
|
}
|
1995-05-30 06:41:30 +00:00
|
|
|
|
1994-05-27 12:33:43 +00:00
|
|
|
PLAN *
|
2001-05-03 18:05:35 +00:00
|
|
|
c_links(option, argvp)
|
|
|
|
OPTION *option;
|
|
|
|
char ***argvp;
|
1994-05-27 12:33:43 +00:00
|
|
|
{
|
2001-05-03 18:05:35 +00:00
|
|
|
char *nlinks;
|
1994-05-27 12:33:43 +00:00
|
|
|
PLAN *new;
|
1995-05-30 06:41:30 +00:00
|
|
|
|
2001-05-03 18:05:35 +00:00
|
|
|
nlinks = nextarg(option, argvp);
|
1994-05-27 12:33:43 +00:00
|
|
|
ftsoptions &= ~FTS_NOSTAT;
|
1995-05-30 06:41:30 +00:00
|
|
|
|
2001-05-03 18:05:35 +00:00
|
|
|
new = palloc(option);
|
|
|
|
new->l_data = (nlink_t)find_parsenum(new, option->name, nlinks, NULL);
|
|
|
|
return new;
|
1994-05-27 12:33:43 +00:00
|
|
|
}
|
1995-05-30 06:41:30 +00:00
|
|
|
|
1994-05-27 12:33:43 +00:00
|
|
|
/*
|
|
|
|
* -ls functions --
|
|
|
|
*
|
|
|
|
* Always true - prints the current entry to stdout in "ls" format.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
f_ls(plan, entry)
|
|
|
|
PLAN *plan;
|
|
|
|
FTSENT *entry;
|
|
|
|
{
|
|
|
|
printlong(entry->fts_path, entry->fts_accpath, entry->fts_statp);
|
2001-05-03 18:05:35 +00:00
|
|
|
return 1;
|
1994-05-27 12:33:43 +00:00
|
|
|
}
|
1995-05-30 06:41:30 +00:00
|
|
|
|
1994-05-27 12:33:43 +00:00
|
|
|
PLAN *
|
2001-05-03 18:05:35 +00:00
|
|
|
c_ls(option, argvp)
|
|
|
|
OPTION *option;
|
|
|
|
char ***argvp;
|
1994-05-27 12:33:43 +00:00
|
|
|
{
|
|
|
|
ftsoptions &= ~FTS_NOSTAT;
|
|
|
|
isoutput = 1;
|
1995-05-30 06:41:30 +00:00
|
|
|
|
2001-05-03 18:05:35 +00:00
|
|
|
return palloc(option);
|
1994-05-27 12:33:43 +00:00
|
|
|
}
|
|
|
|
|
2000-06-12 11:12:41 +00:00
|
|
|
/*
|
2001-05-03 18:05:35 +00:00
|
|
|
* -name functions --
|
1994-05-27 12:33:43 +00:00
|
|
|
*
|
|
|
|
* True if the basename of the filename being examined
|
|
|
|
* matches pattern using Pattern Matching Notation S3.14
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
f_name(plan, entry)
|
|
|
|
PLAN *plan;
|
|
|
|
FTSENT *entry;
|
|
|
|
{
|
2001-05-03 18:05:35 +00:00
|
|
|
return !fnmatch(plan->c_data, entry->fts_name,
|
|
|
|
plan->flags & F_IGNCASE ? FNM_CASEFOLD : 0);
|
1994-05-27 12:33:43 +00:00
|
|
|
}
|
1995-05-30 06:41:30 +00:00
|
|
|
|
1994-05-27 12:33:43 +00:00
|
|
|
PLAN *
|
2001-05-03 18:05:35 +00:00
|
|
|
c_name(option, argvp)
|
|
|
|
OPTION *option;
|
|
|
|
char ***argvp;
|
2001-02-23 16:20:55 +00:00
|
|
|
{
|
|
|
|
char *pattern;
|
|
|
|
PLAN *new;
|
|
|
|
|
2001-05-03 18:05:35 +00:00
|
|
|
pattern = nextarg(option, argvp);
|
|
|
|
new = palloc(option);
|
2001-02-23 16:20:55 +00:00
|
|
|
new->c_data = pattern;
|
2001-05-03 18:05:35 +00:00
|
|
|
return new;
|
2001-02-23 16:20:55 +00:00
|
|
|
}
|
|
|
|
|
1994-05-27 12:33:43 +00:00
|
|
|
/*
|
|
|
|
* -newer file functions --
|
|
|
|
*
|
|
|
|
* True if the current file has been modified more recently
|
|
|
|
* then the modification time of the file named by the pathname
|
|
|
|
* file.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
f_newer(plan, entry)
|
|
|
|
PLAN *plan;
|
|
|
|
FTSENT *entry;
|
|
|
|
{
|
2001-05-03 18:05:35 +00:00
|
|
|
if (plan->flags & F_TIME_C)
|
|
|
|
return entry->fts_statp->st_ctime > plan->t_data;
|
|
|
|
else if (plan->flags & F_TIME_A)
|
|
|
|
return entry->fts_statp->st_atime > plan->t_data;
|
|
|
|
else
|
|
|
|
return entry->fts_statp->st_mtime > plan->t_data;
|
1994-05-27 12:33:43 +00:00
|
|
|
}
|
1995-05-30 06:41:30 +00:00
|
|
|
|
1994-05-27 12:33:43 +00:00
|
|
|
PLAN *
|
2001-05-03 18:05:35 +00:00
|
|
|
c_newer(option, argvp)
|
|
|
|
OPTION *option;
|
|
|
|
char ***argvp;
|
1994-05-27 12:33:43 +00:00
|
|
|
{
|
2001-05-03 18:05:35 +00:00
|
|
|
char *fn_or_tspec;
|
1994-05-27 12:33:43 +00:00
|
|
|
PLAN *new;
|
|
|
|
struct stat sb;
|
1995-05-30 06:41:30 +00:00
|
|
|
|
2001-05-03 18:05:35 +00:00
|
|
|
fn_or_tspec = nextarg(option, argvp);
|
1994-05-27 12:33:43 +00:00
|
|
|
ftsoptions &= ~FTS_NOSTAT;
|
|
|
|
|
2001-05-03 18:05:35 +00:00
|
|
|
new = palloc(option);
|
|
|
|
/* compare against what */
|
|
|
|
if (option->flags & F_TIME2_T) {
|
|
|
|
new->t_data = get_date(fn_or_tspec, (struct timeb *) 0);
|
|
|
|
if (new->t_data == (time_t) -1)
|
|
|
|
errx(1, "Can't parse date/time: %s", fn_or_tspec);
|
|
|
|
} else {
|
|
|
|
if (stat(fn_or_tspec, &sb))
|
|
|
|
err(1, "%s", fn_or_tspec);
|
|
|
|
if (option->flags & F_TIME2_C)
|
|
|
|
new->t_data = sb.st_ctime;
|
|
|
|
else if (option->flags & F_TIME2_A)
|
|
|
|
new->t_data = sb.st_atime;
|
|
|
|
else
|
|
|
|
new->t_data = sb.st_mtime;
|
|
|
|
}
|
|
|
|
return new;
|
1994-05-27 12:33:43 +00:00
|
|
|
}
|
1995-05-30 06:41:30 +00:00
|
|
|
|
1994-05-27 12:33:43 +00:00
|
|
|
/*
|
|
|
|
* -nogroup functions --
|
|
|
|
*
|
|
|
|
* True if file belongs to a user ID for which the equivalent
|
|
|
|
* of the getgrnam() 9.2.1 [POSIX.1] function returns NULL.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
f_nogroup(plan, entry)
|
|
|
|
PLAN *plan;
|
|
|
|
FTSENT *entry;
|
|
|
|
{
|
2001-05-03 18:05:35 +00:00
|
|
|
return group_from_gid(entry->fts_statp->st_gid, 1) == NULL;
|
1994-05-27 12:33:43 +00:00
|
|
|
}
|
1995-05-30 06:41:30 +00:00
|
|
|
|
1994-05-27 12:33:43 +00:00
|
|
|
PLAN *
|
2001-05-03 18:05:35 +00:00
|
|
|
c_nogroup(option, argvp)
|
|
|
|
OPTION *option;
|
|
|
|
char ***argvp;
|
1994-05-27 12:33:43 +00:00
|
|
|
{
|
|
|
|
ftsoptions &= ~FTS_NOSTAT;
|
|
|
|
|
2001-05-03 18:05:35 +00:00
|
|
|
return palloc(option);
|
1994-05-27 12:33:43 +00:00
|
|
|
}
|
1995-05-30 06:41:30 +00:00
|
|
|
|
1994-05-27 12:33:43 +00:00
|
|
|
/*
|
|
|
|
* -nouser functions --
|
|
|
|
*
|
|
|
|
* True if file belongs to a user ID for which the equivalent
|
|
|
|
* of the getpwuid() 9.2.2 [POSIX.1] function returns NULL.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
f_nouser(plan, entry)
|
|
|
|
PLAN *plan;
|
|
|
|
FTSENT *entry;
|
|
|
|
{
|
2001-05-03 18:05:35 +00:00
|
|
|
return user_from_uid(entry->fts_statp->st_uid, 1) == NULL;
|
1994-05-27 12:33:43 +00:00
|
|
|
}
|
1995-05-30 06:41:30 +00:00
|
|
|
|
1994-05-27 12:33:43 +00:00
|
|
|
PLAN *
|
2001-05-03 18:05:35 +00:00
|
|
|
c_nouser(option, argvp)
|
|
|
|
OPTION *option;
|
|
|
|
char ***argvp;
|
1994-05-27 12:33:43 +00:00
|
|
|
{
|
|
|
|
ftsoptions &= ~FTS_NOSTAT;
|
|
|
|
|
2001-05-03 18:05:35 +00:00
|
|
|
return palloc(option);
|
1994-05-27 12:33:43 +00:00
|
|
|
}
|
1995-05-30 06:41:30 +00:00
|
|
|
|
1994-05-27 12:33:43 +00:00
|
|
|
/*
|
|
|
|
* -path functions --
|
|
|
|
*
|
|
|
|
* True if the path of the filename being examined
|
|
|
|
* matches pattern using Pattern Matching Notation S3.14
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
f_path(plan, entry)
|
|
|
|
PLAN *plan;
|
|
|
|
FTSENT *entry;
|
|
|
|
{
|
2001-05-03 18:05:35 +00:00
|
|
|
return !fnmatch(plan->c_data, entry->fts_path,
|
|
|
|
plan->flags & F_IGNCASE ? FNM_CASEFOLD : 0);
|
2001-02-23 16:20:55 +00:00
|
|
|
}
|
|
|
|
|
2001-05-03 18:05:35 +00:00
|
|
|
/* c_path is the same as c_name */
|
1995-05-30 06:41:30 +00:00
|
|
|
|
1994-05-27 12:33:43 +00:00
|
|
|
/*
|
|
|
|
* -perm functions --
|
|
|
|
*
|
|
|
|
* 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
|
|
|
|
* symbolic mode.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
f_perm(plan, entry)
|
|
|
|
PLAN *plan;
|
|
|
|
FTSENT *entry;
|
|
|
|
{
|
|
|
|
mode_t mode;
|
|
|
|
|
|
|
|
mode = entry->fts_statp->st_mode &
|
|
|
|
(S_ISUID|S_ISGID|S_ISTXT|S_IRWXU|S_IRWXG|S_IRWXO);
|
2001-05-03 18:05:35 +00:00
|
|
|
if (plan->flags & F_ATLEAST)
|
|
|
|
return (plan->m_data | mode) == mode;
|
1994-05-27 12:33:43 +00:00
|
|
|
else
|
2001-05-03 18:05:35 +00:00
|
|
|
return mode == plan->m_data;
|
1994-05-27 12:33:43 +00:00
|
|
|
/* NOTREACHED */
|
|
|
|
}
|
1995-05-30 06:41:30 +00:00
|
|
|
|
1994-05-27 12:33:43 +00:00
|
|
|
PLAN *
|
2001-05-03 18:05:35 +00:00
|
|
|
c_perm(option, argvp)
|
|
|
|
OPTION *option;
|
|
|
|
char ***argvp;
|
1994-05-27 12:33:43 +00:00
|
|
|
{
|
2001-05-03 18:05:35 +00:00
|
|
|
char *perm;
|
1994-05-27 12:33:43 +00:00
|
|
|
PLAN *new;
|
|
|
|
mode_t *set;
|
|
|
|
|
2001-05-03 18:05:35 +00:00
|
|
|
perm = nextarg(option, argvp);
|
1994-05-27 12:33:43 +00:00
|
|
|
ftsoptions &= ~FTS_NOSTAT;
|
|
|
|
|
2001-05-03 18:05:35 +00:00
|
|
|
new = palloc(option);
|
1994-05-27 12:33:43 +00:00
|
|
|
|
|
|
|
if (*perm == '-') {
|
2001-05-03 18:05:35 +00:00
|
|
|
new->flags |= F_ATLEAST;
|
1994-05-27 12:33:43 +00:00
|
|
|
++perm;
|
2000-06-12 10:36:52 +00:00
|
|
|
} else if (*perm == '+') {
|
2001-05-03 18:05:35 +00:00
|
|
|
new->flags |= F_ANY;
|
2000-06-12 10:36:52 +00:00
|
|
|
++perm;
|
1994-05-27 12:33:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if ((set = setmode(perm)) == NULL)
|
2001-05-03 18:05:35 +00:00
|
|
|
errx(1, "%s: %s: illegal mode string", option->name, perm);
|
1994-05-27 12:33:43 +00:00
|
|
|
|
|
|
|
new->m_data = getmode(set, 0);
|
1998-12-16 04:50:46 +00:00
|
|
|
free(set);
|
1999-12-19 15:43:19 +00:00
|
|
|
return new;
|
|
|
|
}
|
|
|
|
|
1994-05-27 12:33:43 +00:00
|
|
|
/*
|
|
|
|
* -print functions --
|
|
|
|
*
|
|
|
|
* Always true, causes the current pathame to be written to
|
|
|
|
* standard output.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
f_print(plan, entry)
|
|
|
|
PLAN *plan;
|
|
|
|
FTSENT *entry;
|
|
|
|
{
|
1995-10-16 18:32:35 +00:00
|
|
|
(void)puts(entry->fts_path);
|
2001-05-03 18:05:35 +00:00
|
|
|
return 1;
|
1994-05-27 12:33:43 +00:00
|
|
|
}
|
1995-05-30 06:41:30 +00:00
|
|
|
|
1994-05-27 12:33:43 +00:00
|
|
|
PLAN *
|
2001-05-03 18:05:35 +00:00
|
|
|
c_print(option, argvp)
|
|
|
|
OPTION *option;
|
|
|
|
char ***argvp;
|
1994-05-27 12:33:43 +00:00
|
|
|
{
|
|
|
|
isoutput = 1;
|
|
|
|
|
2001-05-03 18:05:35 +00:00
|
|
|
return palloc(option);
|
1994-05-27 12:33:43 +00:00
|
|
|
}
|
1995-05-30 06:41:30 +00:00
|
|
|
|
1995-05-09 19:02:06 +00:00
|
|
|
/*
|
|
|
|
* -print0 functions --
|
|
|
|
*
|
|
|
|
* Always true, causes the current pathame to be written to
|
|
|
|
* standard output followed by a NUL character
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
f_print0(plan, entry)
|
|
|
|
PLAN *plan;
|
|
|
|
FTSENT *entry;
|
|
|
|
{
|
|
|
|
fputs(entry->fts_path, stdout);
|
|
|
|
fputc('\0', stdout);
|
2001-05-03 18:05:35 +00:00
|
|
|
return 1;
|
1995-05-09 19:02:06 +00:00
|
|
|
}
|
1995-05-30 06:41:30 +00:00
|
|
|
|
2001-05-03 18:05:35 +00:00
|
|
|
/* c_print0 is the same as c_print */
|
1995-05-30 06:41:30 +00:00
|
|
|
|
1994-05-27 12:33:43 +00:00
|
|
|
/*
|
|
|
|
* -prune functions --
|
|
|
|
*
|
|
|
|
* Prune a portion of the hierarchy.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
f_prune(plan, entry)
|
|
|
|
PLAN *plan;
|
|
|
|
FTSENT *entry;
|
|
|
|
{
|
|
|
|
extern FTS *tree;
|
|
|
|
|
|
|
|
if (fts_set(tree, entry, FTS_SKIP))
|
|
|
|
err(1, "%s", entry->fts_path);
|
2001-05-03 18:05:35 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* c_prune == c_simple */
|
|
|
|
|
|
|
|
/*
|
|
|
|
* -regex functions --
|
|
|
|
*
|
|
|
|
* True if the whole path of the file matches pattern using
|
|
|
|
* regular expression.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
f_regex(plan, entry)
|
|
|
|
PLAN *plan;
|
|
|
|
FTSENT *entry;
|
|
|
|
{
|
|
|
|
char *str;
|
|
|
|
size_t len;
|
|
|
|
regex_t *pre;
|
|
|
|
regmatch_t pmatch;
|
|
|
|
int errcode;
|
|
|
|
char errbuf[LINE_MAX];
|
|
|
|
int matched;
|
|
|
|
|
|
|
|
pre = plan->re_data;
|
|
|
|
str = entry->fts_path;
|
|
|
|
len = strlen(str);
|
|
|
|
matched = 0;
|
|
|
|
|
|
|
|
pmatch.rm_so = 0;
|
|
|
|
pmatch.rm_eo = len;
|
|
|
|
|
|
|
|
errcode = regexec(pre, str, 1, &pmatch, REG_STARTEND);
|
|
|
|
|
|
|
|
if (errcode != 0 && errcode != REG_NOMATCH) {
|
|
|
|
regerror(errcode, pre, errbuf, sizeof errbuf);
|
|
|
|
errx(1, "%s: %s",
|
|
|
|
plan->flags & F_IGNCASE ? "-iregex" : "-regex", errbuf);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (errcode == 0 && pmatch.rm_so == 0 && pmatch.rm_eo == len)
|
|
|
|
matched = 1;
|
|
|
|
|
|
|
|
return matched;
|
1994-05-27 12:33:43 +00:00
|
|
|
}
|
1995-05-30 06:41:30 +00:00
|
|
|
|
1994-05-27 12:33:43 +00:00
|
|
|
PLAN *
|
2001-05-03 18:05:35 +00:00
|
|
|
c_regex(option, argvp)
|
|
|
|
OPTION *option;
|
|
|
|
char ***argvp;
|
1994-05-27 12:33:43 +00:00
|
|
|
{
|
2001-05-03 18:05:35 +00:00
|
|
|
PLAN *new;
|
|
|
|
char *pattern;
|
|
|
|
regex_t *pre;
|
|
|
|
int errcode;
|
|
|
|
char errbuf[LINE_MAX];
|
|
|
|
|
|
|
|
if ((pre = malloc(sizeof(regex_t))) == NULL)
|
|
|
|
err(1, NULL);
|
|
|
|
|
|
|
|
pattern = nextarg(option, argvp);
|
|
|
|
|
|
|
|
if ((errcode = regcomp(pre, pattern,
|
|
|
|
regexp_flags | (option->flags & F_IGNCASE ? REG_ICASE : 0))) != 0) {
|
|
|
|
regerror(errcode, pre, errbuf, sizeof errbuf);
|
|
|
|
errx(1, "%s: %s: %s",
|
|
|
|
option->flags & F_IGNCASE ? "-iregex" : "-regex",
|
|
|
|
pattern, errbuf);
|
|
|
|
}
|
|
|
|
|
|
|
|
new = palloc(option);
|
|
|
|
new->re_data = pre;
|
|
|
|
|
|
|
|
return new;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* c_simple covers c_prune, c_openparen, c_closeparen, c_not, c_or */
|
|
|
|
|
|
|
|
PLAN *
|
|
|
|
c_simple(option, argvp)
|
|
|
|
OPTION *option;
|
|
|
|
char ***argvp;
|
|
|
|
{
|
|
|
|
return palloc(option);
|
1994-05-27 12:33:43 +00:00
|
|
|
}
|
1995-05-30 06:41:30 +00:00
|
|
|
|
1994-05-27 12:33:43 +00:00
|
|
|
/*
|
|
|
|
* -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.
|
|
|
|
*/
|
|
|
|
#define FIND_SIZE 512
|
|
|
|
static int divsize = 1;
|
|
|
|
|
|
|
|
int
|
|
|
|
f_size(plan, entry)
|
|
|
|
PLAN *plan;
|
|
|
|
FTSENT *entry;
|
|
|
|
{
|
|
|
|
off_t size;
|
|
|
|
|
|
|
|
size = divsize ? (entry->fts_statp->st_size + FIND_SIZE - 1) /
|
|
|
|
FIND_SIZE : entry->fts_statp->st_size;
|
|
|
|
COMPARE(size, plan->o_data);
|
|
|
|
}
|
1995-05-30 06:41:30 +00:00
|
|
|
|
1994-05-27 12:33:43 +00:00
|
|
|
PLAN *
|
2001-05-03 18:05:35 +00:00
|
|
|
c_size(option, argvp)
|
|
|
|
OPTION *option;
|
|
|
|
char ***argvp;
|
1994-05-27 12:33:43 +00:00
|
|
|
{
|
2001-05-03 18:05:35 +00:00
|
|
|
char *size_str;
|
1994-05-27 12:33:43 +00:00
|
|
|
PLAN *new;
|
|
|
|
char endch;
|
1995-05-30 06:41:30 +00:00
|
|
|
|
2001-05-03 18:05:35 +00:00
|
|
|
size_str = nextarg(option, argvp);
|
1994-05-27 12:33:43 +00:00
|
|
|
ftsoptions &= ~FTS_NOSTAT;
|
|
|
|
|
2001-05-03 18:05:35 +00:00
|
|
|
new = palloc(option);
|
1994-05-27 12:33:43 +00:00
|
|
|
endch = 'c';
|
2001-05-03 18:05:35 +00:00
|
|
|
new->o_data = find_parsenum(new, option->name, size_str, &endch);
|
1994-05-27 12:33:43 +00:00
|
|
|
if (endch == 'c')
|
|
|
|
divsize = 0;
|
2001-05-03 18:05:35 +00:00
|
|
|
return new;
|
1994-05-27 12:33:43 +00:00
|
|
|
}
|
1995-05-30 06:41:30 +00:00
|
|
|
|
1994-05-27 12:33:43 +00:00
|
|
|
/*
|
|
|
|
* -type c functions --
|
|
|
|
*
|
1997-03-11 13:48:37 +00:00
|
|
|
* True if the type of the file is c, where c is b, c, d, p, f or w
|
|
|
|
* for block special file, character special file, directory, FIFO,
|
|
|
|
* regular file or whiteout respectively.
|
1994-05-27 12:33:43 +00:00
|
|
|
*/
|
|
|
|
int
|
|
|
|
f_type(plan, entry)
|
|
|
|
PLAN *plan;
|
|
|
|
FTSENT *entry;
|
|
|
|
{
|
2001-05-03 18:05:35 +00:00
|
|
|
return (entry->fts_statp->st_mode & S_IFMT) == plan->m_data;
|
1994-05-27 12:33:43 +00:00
|
|
|
}
|
1995-05-30 06:41:30 +00:00
|
|
|
|
1994-05-27 12:33:43 +00:00
|
|
|
PLAN *
|
2001-05-03 18:05:35 +00:00
|
|
|
c_type(option, argvp)
|
|
|
|
OPTION *option;
|
|
|
|
char ***argvp;
|
1994-05-27 12:33:43 +00:00
|
|
|
{
|
2001-05-03 18:05:35 +00:00
|
|
|
char *typestring;
|
1994-05-27 12:33:43 +00:00
|
|
|
PLAN *new;
|
|
|
|
mode_t mask;
|
1995-05-30 06:41:30 +00:00
|
|
|
|
2001-05-03 18:05:35 +00:00
|
|
|
typestring = nextarg(option, argvp);
|
1994-05-27 12:33:43 +00:00
|
|
|
ftsoptions &= ~FTS_NOSTAT;
|
|
|
|
|
|
|
|
switch (typestring[0]) {
|
|
|
|
case 'b':
|
|
|
|
mask = S_IFBLK;
|
|
|
|
break;
|
|
|
|
case 'c':
|
|
|
|
mask = S_IFCHR;
|
|
|
|
break;
|
|
|
|
case 'd':
|
|
|
|
mask = S_IFDIR;
|
|
|
|
break;
|
|
|
|
case 'f':
|
|
|
|
mask = S_IFREG;
|
|
|
|
break;
|
|
|
|
case 'l':
|
|
|
|
mask = S_IFLNK;
|
|
|
|
break;
|
|
|
|
case 'p':
|
|
|
|
mask = S_IFIFO;
|
|
|
|
break;
|
|
|
|
case 's':
|
|
|
|
mask = S_IFSOCK;
|
|
|
|
break;
|
1997-03-11 13:48:37 +00:00
|
|
|
#ifdef FTS_WHITEOUT
|
|
|
|
case 'w':
|
|
|
|
mask = S_IFWHT;
|
|
|
|
ftsoptions |= FTS_WHITEOUT;
|
|
|
|
break;
|
|
|
|
#endif /* FTS_WHITEOUT */
|
1994-05-27 12:33:43 +00:00
|
|
|
default:
|
2001-05-03 18:05:35 +00:00
|
|
|
errx(1, "%s: %s: unknown type", option->name, typestring);
|
1994-05-27 12:33:43 +00:00
|
|
|
}
|
1995-05-30 06:41:30 +00:00
|
|
|
|
2001-05-03 18:05:35 +00:00
|
|
|
new = palloc(option);
|
1994-05-27 12:33:43 +00:00
|
|
|
new->m_data = mask;
|
2001-05-03 18:05:35 +00:00
|
|
|
return new;
|
Implement a -delete option to find. The code is extremely paranoid and
goes to a fair degree of trouble to enable something like this to
be safe: cd /tmp && find . -mtime +7 -delete
It removes both files and directories. It does not attempt to remove
immutable files (an earlier version I showed to a few people did a chflags
and tried to blow away even immutable files. Too risky..)
It is thought to be safe because it forces the fts(3) driven descent to
only do "minimal risk" stuff. specifically, -follow is disabled, it does
checking to see that it chdir'ed to the directory it thought it was
going to, it will *not* pass a pathname with a '/' character in it to
unlink(), so it should be totally immune to symlink tree races. If it runs
into something "fishy", it bails out rather than blunder ahead.. It's better
to do that if somebody is trying to compromise security rather than risk
giving them an opportunity. Since the unlink()/rmdir() is being called
from within the current working directory during the tree descent, there
are no fork/exec overheads or races.
As a side effect of this paranoia, you cannot do a
"find /somewhere/dir -delete", as the last argument to rmdir() is
"/somewhere/dir", and the checking won't allow it. Besides, one would use
rm -rf for that case anyway. :-)
Reviewed by: pst (some time ago, but I've removed the immutable file
deletion code that he complained about since he last saw it)
1996-10-04 12:54:07 +00:00
|
|
|
}
|
|
|
|
|
1994-05-27 12:33:43 +00:00
|
|
|
/*
|
|
|
|
* -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.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
f_user(plan, entry)
|
|
|
|
PLAN *plan;
|
|
|
|
FTSENT *entry;
|
|
|
|
{
|
2001-05-03 18:05:35 +00:00
|
|
|
return entry->fts_statp->st_uid == plan->u_data;
|
1994-05-27 12:33:43 +00:00
|
|
|
}
|
1995-05-30 06:41:30 +00:00
|
|
|
|
1994-05-27 12:33:43 +00:00
|
|
|
PLAN *
|
2001-05-03 18:05:35 +00:00
|
|
|
c_user(option, argvp)
|
|
|
|
OPTION *option;
|
|
|
|
char ***argvp;
|
1994-05-27 12:33:43 +00:00
|
|
|
{
|
2001-05-03 18:05:35 +00:00
|
|
|
char *username;
|
1994-05-27 12:33:43 +00:00
|
|
|
PLAN *new;
|
|
|
|
struct passwd *p;
|
|
|
|
uid_t uid;
|
1995-05-30 06:41:30 +00:00
|
|
|
|
2001-05-03 18:05:35 +00:00
|
|
|
username = nextarg(option, argvp);
|
1994-05-27 12:33:43 +00:00
|
|
|
ftsoptions &= ~FTS_NOSTAT;
|
|
|
|
|
|
|
|
p = getpwnam(username);
|
|
|
|
if (p == NULL) {
|
|
|
|
uid = atoi(username);
|
|
|
|
if (uid == 0 && username[0] != '0')
|
2001-05-03 18:05:35 +00:00
|
|
|
errx(1, "%s: %s: no such user", option->name, username);
|
1994-05-27 12:33:43 +00:00
|
|
|
} else
|
|
|
|
uid = p->pw_uid;
|
|
|
|
|
2001-05-03 18:05:35 +00:00
|
|
|
new = palloc(option);
|
1994-05-27 12:33:43 +00:00
|
|
|
new->u_data = uid;
|
2001-05-03 18:05:35 +00:00
|
|
|
return new;
|
1994-05-27 12:33:43 +00:00
|
|
|
}
|
1995-05-30 06:41:30 +00:00
|
|
|
|
1994-05-27 12:33:43 +00:00
|
|
|
/*
|
|
|
|
* -xdev functions --
|
|
|
|
*
|
|
|
|
* Always true, causes find not to decend past directories that have a
|
|
|
|
* different device ID (st_dev, see stat() S5.6.2 [POSIX.1])
|
|
|
|
*/
|
|
|
|
PLAN *
|
2001-05-03 18:05:35 +00:00
|
|
|
c_xdev(option, argvp)
|
|
|
|
OPTION *option;
|
|
|
|
char ***argvp;
|
1994-05-27 12:33:43 +00:00
|
|
|
{
|
|
|
|
ftsoptions |= FTS_XDEV;
|
|
|
|
|
2001-05-03 18:05:35 +00:00
|
|
|
return palloc(option);
|
1994-05-27 12:33:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* ( expression ) functions --
|
|
|
|
*
|
|
|
|
* True if expression is true.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
f_expr(plan, entry)
|
|
|
|
PLAN *plan;
|
|
|
|
FTSENT *entry;
|
|
|
|
{
|
|
|
|
register PLAN *p;
|
2001-05-03 18:05:35 +00:00
|
|
|
register int state = 0;
|
1994-05-27 12:33:43 +00:00
|
|
|
|
|
|
|
for (p = plan->p_data[0];
|
2001-05-03 18:05:35 +00:00
|
|
|
p && (state = (p->execute)(p, entry)); p = p->next);
|
|
|
|
return state;
|
1994-05-27 12:33:43 +00:00
|
|
|
}
|
1995-05-30 06:41:30 +00:00
|
|
|
|
1994-05-27 12:33:43 +00:00
|
|
|
/*
|
2001-05-03 18:05:35 +00:00
|
|
|
* f_openparen and f_closeparen nodes are temporary place markers. They are
|
1994-05-27 12:33:43 +00:00
|
|
|
* eliminated during phase 2 of find_formplan() --- the '(' node is converted
|
2001-05-03 18:05:35 +00:00
|
|
|
* to a f_expr node containing the expression and the ')' node is discarded.
|
|
|
|
* The functions themselves are only used as constants.
|
1994-05-27 12:33:43 +00:00
|
|
|
*/
|
2001-05-03 18:05:35 +00:00
|
|
|
|
|
|
|
int
|
|
|
|
f_openparen(plan, entry)
|
|
|
|
PLAN *plan;
|
|
|
|
FTSENT *entry;
|
|
|
|
{
|
|
|
|
abort();
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
f_closeparen(plan, entry)
|
|
|
|
PLAN *plan;
|
|
|
|
FTSENT *entry;
|
1994-05-27 12:33:43 +00:00
|
|
|
{
|
2001-05-03 18:05:35 +00:00
|
|
|
abort();
|
1994-05-27 12:33:43 +00:00
|
|
|
}
|
1995-05-30 06:41:30 +00:00
|
|
|
|
2001-05-03 18:05:35 +00:00
|
|
|
/* c_openparen == c_simple */
|
|
|
|
/* c_closeparen == c_simple */
|
|
|
|
|
|
|
|
/*
|
|
|
|
* AND operator. Since AND is implicit, no node is allocated.
|
|
|
|
*/
|
1994-05-27 12:33:43 +00:00
|
|
|
PLAN *
|
2001-05-03 18:05:35 +00:00
|
|
|
c_and(option, argvp)
|
|
|
|
OPTION *option;
|
|
|
|
char ***argvp;
|
1994-05-27 12:33:43 +00:00
|
|
|
{
|
2001-05-03 18:05:35 +00:00
|
|
|
return NULL;
|
1994-05-27 12:33:43 +00:00
|
|
|
}
|
1995-05-30 06:41:30 +00:00
|
|
|
|
1994-05-27 12:33:43 +00:00
|
|
|
/*
|
|
|
|
* ! expression functions --
|
|
|
|
*
|
|
|
|
* Negation of a primary; the unary NOT operator.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
f_not(plan, entry)
|
|
|
|
PLAN *plan;
|
|
|
|
FTSENT *entry;
|
|
|
|
{
|
|
|
|
register PLAN *p;
|
2001-05-03 18:05:35 +00:00
|
|
|
register int state = 0;
|
1994-05-27 12:33:43 +00:00
|
|
|
|
|
|
|
for (p = plan->p_data[0];
|
2001-05-03 18:05:35 +00:00
|
|
|
p && (state = (p->execute)(p, entry)); p = p->next);
|
|
|
|
return !state;
|
1994-05-27 12:33:43 +00:00
|
|
|
}
|
1995-05-30 06:41:30 +00:00
|
|
|
|
2001-05-03 18:05:35 +00:00
|
|
|
/* c_not == c_simple */
|
1995-05-30 06:41:30 +00:00
|
|
|
|
1994-05-27 12:33:43 +00:00
|
|
|
/*
|
|
|
|
* expression -o expression functions --
|
|
|
|
*
|
|
|
|
* Alternation of primaries; the OR operator. The second expression is
|
|
|
|
* not evaluated if the first expression is true.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
f_or(plan, entry)
|
|
|
|
PLAN *plan;
|
|
|
|
FTSENT *entry;
|
|
|
|
{
|
|
|
|
register PLAN *p;
|
2001-05-03 18:05:35 +00:00
|
|
|
register int state = 0;
|
1994-05-27 12:33:43 +00:00
|
|
|
|
|
|
|
for (p = plan->p_data[0];
|
2001-05-03 18:05:35 +00:00
|
|
|
p && (state = (p->execute)(p, entry)); p = p->next);
|
1994-05-27 12:33:43 +00:00
|
|
|
|
|
|
|
if (state)
|
2001-05-03 18:05:35 +00:00
|
|
|
return 1;
|
1994-05-27 12:33:43 +00:00
|
|
|
|
|
|
|
for (p = plan->p_data[1];
|
2001-05-03 18:05:35 +00:00
|
|
|
p && (state = (p->execute)(p, entry)); p = p->next);
|
|
|
|
return state;
|
1994-05-27 12:33:43 +00:00
|
|
|
}
|
|
|
|
|
2001-05-03 18:05:35 +00:00
|
|
|
/* c_or == c_simple */
|