Home | History | Annotate | Line # | Download | only in find
function.c revision 1.64.16.2
      1  1.64.16.2  daniel /*	$NetBSD: function.c,v 1.64.16.2 2007/07/19 07:49:31 daniel Exp $	*/
      2  1.64.16.2  daniel 
      3  1.64.16.2  daniel /*-
      4  1.64.16.2  daniel  * Copyright (c) 1990, 1993
      5  1.64.16.2  daniel  *	The Regents of the University of California.  All rights reserved.
      6  1.64.16.2  daniel  *
      7  1.64.16.2  daniel  * This code is derived from software contributed to Berkeley by
      8  1.64.16.2  daniel  * Cimarron D. Taylor of the University of California, Berkeley.
      9  1.64.16.2  daniel  *
     10  1.64.16.2  daniel  * Redistribution and use in source and binary forms, with or without
     11  1.64.16.2  daniel  * modification, are permitted provided that the following conditions
     12  1.64.16.2  daniel  * are met:
     13  1.64.16.2  daniel  * 1. Redistributions of source code must retain the above copyright
     14  1.64.16.2  daniel  *    notice, this list of conditions and the following disclaimer.
     15  1.64.16.2  daniel  * 2. Redistributions in binary form must reproduce the above copyright
     16  1.64.16.2  daniel  *    notice, this list of conditions and the following disclaimer in the
     17  1.64.16.2  daniel  *    documentation and/or other materials provided with the distribution.
     18  1.64.16.2  daniel  * 3. Neither the name of the University nor the names of its contributors
     19  1.64.16.2  daniel  *    may be used to endorse or promote products derived from this software
     20  1.64.16.2  daniel  *    without specific prior written permission.
     21  1.64.16.2  daniel  *
     22  1.64.16.2  daniel  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     23  1.64.16.2  daniel  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     24  1.64.16.2  daniel  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     25  1.64.16.2  daniel  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     26  1.64.16.2  daniel  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     27  1.64.16.2  daniel  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     28  1.64.16.2  daniel  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     29  1.64.16.2  daniel  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     30  1.64.16.2  daniel  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     31  1.64.16.2  daniel  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     32  1.64.16.2  daniel  * SUCH DAMAGE.
     33  1.64.16.2  daniel  */
     34  1.64.16.2  daniel 
     35  1.64.16.2  daniel #include <sys/cdefs.h>
     36  1.64.16.2  daniel #ifndef lint
     37  1.64.16.2  daniel #if 0
     38  1.64.16.2  daniel static char sccsid[] = "from: @(#)function.c	8.10 (Berkeley) 5/4/95";
     39  1.64.16.2  daniel #else
     40  1.64.16.2  daniel __RCSID("$NetBSD: function.c,v 1.64.16.2 2007/07/19 07:49:31 daniel Exp $");
     41  1.64.16.2  daniel #endif
     42  1.64.16.2  daniel #endif /* not lint */
     43  1.64.16.2  daniel 
     44  1.64.16.2  daniel #include <sys/param.h>
     45  1.64.16.2  daniel #include <sys/stat.h>
     46  1.64.16.2  daniel #include <sys/wait.h>
     47  1.64.16.2  daniel #include <sys/mount.h>
     48  1.64.16.2  daniel 
     49  1.64.16.2  daniel #include <dirent.h>
     50  1.64.16.2  daniel #include <err.h>
     51  1.64.16.2  daniel #include <errno.h>
     52  1.64.16.2  daniel #include <fnmatch.h>
     53  1.64.16.2  daniel #include <fts.h>
     54  1.64.16.2  daniel #include <grp.h>
     55  1.64.16.2  daniel #include <inttypes.h>
     56  1.64.16.2  daniel #include <limits.h>
     57  1.64.16.2  daniel #include <pwd.h>
     58  1.64.16.2  daniel #include <stdbool.h>
     59  1.64.16.2  daniel #include <stdio.h>
     60  1.64.16.2  daniel #include <stdlib.h>
     61  1.64.16.2  daniel #include <string.h>
     62  1.64.16.2  daniel #include <tzfile.h>
     63  1.64.16.2  daniel #include <unistd.h>
     64  1.64.16.2  daniel #include <util.h>
     65  1.64.16.2  daniel 
     66  1.64.16.2  daniel #include "find.h"
     67  1.64.16.2  daniel 
     68  1.64.16.2  daniel #define	COMPARE(a, b) {							\
     69  1.64.16.2  daniel 	switch (plan->flags) {						\
     70  1.64.16.2  daniel 	case F_EQUAL:							\
     71  1.64.16.2  daniel 		return (a == b);					\
     72  1.64.16.2  daniel 	case F_LESSTHAN:						\
     73  1.64.16.2  daniel 		return (a < b);						\
     74  1.64.16.2  daniel 	case F_GREATER:							\
     75  1.64.16.2  daniel 		return (a > b);						\
     76  1.64.16.2  daniel 	default:							\
     77  1.64.16.2  daniel 		abort();						\
     78  1.64.16.2  daniel 	}								\
     79  1.64.16.2  daniel }
     80  1.64.16.2  daniel 
     81  1.64.16.2  daniel static	int64_t	find_parsenum(PLAN *, const char *, const char *, char *);
     82  1.64.16.2  daniel static	void	run_f_exec(PLAN *);
     83  1.64.16.2  daniel 	int	f_always_true(PLAN *, FTSENT *);
     84  1.64.16.2  daniel 	int	f_amin(PLAN *, FTSENT *);
     85  1.64.16.2  daniel 	int	f_anewer(PLAN *, FTSENT *);
     86  1.64.16.2  daniel 	int	f_atime(PLAN *, FTSENT *);
     87  1.64.16.2  daniel 	int	f_cmin(PLAN *, FTSENT *);
     88  1.64.16.2  daniel 	int	f_cnewer(PLAN *, FTSENT *);
     89  1.64.16.2  daniel 	int	f_ctime(PLAN *, FTSENT *);
     90  1.64.16.2  daniel 	int	f_delete(PLAN *, FTSENT *);
     91  1.64.16.2  daniel 	int	f_empty(PLAN *, FTSENT *);
     92  1.64.16.2  daniel 	int	f_exec(PLAN *, FTSENT *);
     93  1.64.16.2  daniel 	int	f_execdir(PLAN *, FTSENT *);
     94  1.64.16.2  daniel 	int	f_false(PLAN *, FTSENT *);
     95  1.64.16.2  daniel 	int	f_flags(PLAN *, FTSENT *);
     96  1.64.16.2  daniel 	int	f_fprint(PLAN *, FTSENT *);
     97  1.64.16.2  daniel 	int	f_fstype(PLAN *, FTSENT *);
     98  1.64.16.2  daniel 	int	f_group(PLAN *, FTSENT *);
     99  1.64.16.2  daniel 	int	f_iname(PLAN *, FTSENT *);
    100  1.64.16.2  daniel 	int	f_inum(PLAN *, FTSENT *);
    101  1.64.16.2  daniel 	int	f_links(PLAN *, FTSENT *);
    102  1.64.16.2  daniel 	int	f_ls(PLAN *, FTSENT *);
    103  1.64.16.2  daniel 	int	f_mindepth(PLAN *, FTSENT *);
    104  1.64.16.2  daniel 	int	f_maxdepth(PLAN *, FTSENT *);
    105  1.64.16.2  daniel 	int	f_mmin(PLAN *, FTSENT *);
    106  1.64.16.2  daniel 	int	f_mtime(PLAN *, FTSENT *);
    107  1.64.16.2  daniel 	int	f_name(PLAN *, FTSENT *);
    108  1.64.16.2  daniel 	int	f_newer(PLAN *, FTSENT *);
    109  1.64.16.2  daniel 	int	f_nogroup(PLAN *, FTSENT *);
    110  1.64.16.2  daniel 	int	f_nouser(PLAN *, FTSENT *);
    111  1.64.16.2  daniel 	int	f_path(PLAN *, FTSENT *);
    112  1.64.16.2  daniel 	int	f_perm(PLAN *, FTSENT *);
    113  1.64.16.2  daniel 	int	f_print(PLAN *, FTSENT *);
    114  1.64.16.2  daniel 	int	f_print0(PLAN *, FTSENT *);
    115  1.64.16.2  daniel 	int	f_printx(PLAN *, FTSENT *);
    116  1.64.16.2  daniel 	int	f_prune(PLAN *, FTSENT *);
    117  1.64.16.2  daniel 	int	f_regex(PLAN *, FTSENT *);
    118  1.64.16.2  daniel 	int	f_size(PLAN *, FTSENT *);
    119  1.64.16.2  daniel 	int	f_type(PLAN *, FTSENT *);
    120  1.64.16.2  daniel 	int	f_user(PLAN *, FTSENT *);
    121  1.64.16.2  daniel 	int	f_not(PLAN *, FTSENT *);
    122  1.64.16.2  daniel 	int	f_or(PLAN *, FTSENT *);
    123  1.64.16.2  daniel static	PLAN   *c_regex_common(char ***, int, enum ntype, bool);
    124  1.64.16.2  daniel static	PLAN   *palloc(enum ntype, int (*)(PLAN *, FTSENT *));
    125  1.64.16.2  daniel 
    126  1.64.16.2  daniel extern int dotfd;
    127  1.64.16.2  daniel extern FTS *tree;
    128  1.64.16.2  daniel extern time_t now;
    129  1.64.16.2  daniel 
    130  1.64.16.2  daniel /*
    131  1.64.16.2  daniel  * find_parsenum --
    132  1.64.16.2  daniel  *	Parse a string of the form [+-]# and return the value.
    133  1.64.16.2  daniel  */
    134  1.64.16.2  daniel static int64_t
    135  1.64.16.2  daniel find_parsenum(PLAN *plan, const char *option, const char *vp, char *endch)
    136  1.64.16.2  daniel {
    137  1.64.16.2  daniel 	int64_t value;
    138  1.64.16.2  daniel 	const char *str;
    139  1.64.16.2  daniel 	char *endchar; /* Pointer to character ending conversion. */
    140  1.64.16.2  daniel 
    141  1.64.16.2  daniel 	/* Determine comparison from leading + or -. */
    142  1.64.16.2  daniel 	str = vp;
    143  1.64.16.2  daniel 	switch (*str) {
    144  1.64.16.2  daniel 	case '+':
    145  1.64.16.2  daniel 		++str;
    146  1.64.16.2  daniel 		plan->flags = F_GREATER;
    147  1.64.16.2  daniel 		break;
    148  1.64.16.2  daniel 	case '-':
    149  1.64.16.2  daniel 		++str;
    150  1.64.16.2  daniel 		plan->flags = F_LESSTHAN;
    151  1.64.16.2  daniel 		break;
    152  1.64.16.2  daniel 	default:
    153  1.64.16.2  daniel 		plan->flags = F_EQUAL;
    154  1.64.16.2  daniel 		break;
    155  1.64.16.2  daniel 	}
    156  1.64.16.2  daniel 
    157  1.64.16.2  daniel 	/*
    158  1.64.16.2  daniel 	 * Convert the string with strtol().  Note, if strtol() returns zero
    159  1.64.16.2  daniel 	 * and endchar points to the beginning of the string we know we have
    160  1.64.16.2  daniel 	 * a syntax error.
    161  1.64.16.2  daniel 	 */
    162  1.64.16.2  daniel 	value = strtoq(str, &endchar, 10);
    163  1.64.16.2  daniel 	if (value == 0 && endchar == str)
    164  1.64.16.2  daniel 		errx(1, "%s: %s: illegal numeric value", option, vp);
    165  1.64.16.2  daniel 	if (endchar[0] && (endch == NULL || endchar[0] != *endch))
    166  1.64.16.2  daniel 		errx(1, "%s: %s: illegal trailing character", option, vp);
    167  1.64.16.2  daniel 	if (endch)
    168  1.64.16.2  daniel 		*endch = endchar[0];
    169  1.64.16.2  daniel 	return (value);
    170  1.64.16.2  daniel }
    171  1.64.16.2  daniel 
    172  1.64.16.2  daniel /*
    173  1.64.16.2  daniel  * The value of n for the inode times (atime, ctime, and mtime) is a range,
    174  1.64.16.2  daniel  * i.e. n matches from (n - 1) to n 24 hour periods.  This interacts with
    175  1.64.16.2  daniel  * -n, such that "-mtime -1" would be less than 0 days, which isn't what the
    176  1.64.16.2  daniel  * user wanted.  Correct so that -1 is "less than 1".
    177  1.64.16.2  daniel  */
    178  1.64.16.2  daniel #define	TIME_CORRECT(p, ttype)						\
    179  1.64.16.2  daniel 	if ((p)->type == ttype && (p)->flags == F_LESSTHAN)		\
    180  1.64.16.2  daniel 		++((p)->t_data);
    181  1.64.16.2  daniel 
    182  1.64.16.2  daniel /*
    183  1.64.16.2  daniel  * -amin n functions --
    184  1.64.16.2  daniel  *
    185  1.64.16.2  daniel  *	True if the difference between the file access time and the
    186  1.64.16.2  daniel  *	current time is n 1 minute periods.
    187  1.64.16.2  daniel  */
    188  1.64.16.2  daniel int
    189  1.64.16.2  daniel f_amin(PLAN *plan, FTSENT *entry)
    190  1.64.16.2  daniel {
    191  1.64.16.2  daniel 	COMPARE((now - entry->fts_statp->st_atime +
    192  1.64.16.2  daniel 	    SECSPERMIN - 1) / SECSPERMIN, plan->t_data);
    193  1.64.16.2  daniel }
    194  1.64.16.2  daniel 
    195  1.64.16.2  daniel PLAN *
    196  1.64.16.2  daniel c_amin(char ***argvp, int isok)
    197  1.64.16.2  daniel {
    198  1.64.16.2  daniel 	char *arg = **argvp;
    199  1.64.16.2  daniel 	PLAN *new;
    200  1.64.16.2  daniel 
    201  1.64.16.2  daniel 	(*argvp)++;
    202  1.64.16.2  daniel 	ftsoptions &= ~FTS_NOSTAT;
    203  1.64.16.2  daniel 
    204  1.64.16.2  daniel 	new = palloc(N_AMIN, f_amin);
    205  1.64.16.2  daniel 	new->t_data = find_parsenum(new, "-amin", arg, NULL);
    206  1.64.16.2  daniel 	TIME_CORRECT(new, N_AMIN);
    207  1.64.16.2  daniel 	return (new);
    208  1.64.16.2  daniel }
    209  1.64.16.2  daniel 
    210  1.64.16.2  daniel /*
    211  1.64.16.2  daniel  * -anewer file functions --
    212  1.64.16.2  daniel  *
    213  1.64.16.2  daniel  *	True if the current file has been accessed more recently
    214  1.64.16.2  daniel  *	than the access time of the file named by the pathname
    215  1.64.16.2  daniel  *	file.
    216  1.64.16.2  daniel  */
    217  1.64.16.2  daniel int
    218  1.64.16.2  daniel f_anewer(plan, entry)
    219  1.64.16.2  daniel 	PLAN *plan;
    220  1.64.16.2  daniel 	FTSENT *entry;
    221  1.64.16.2  daniel {
    222  1.64.16.2  daniel 
    223  1.64.16.2  daniel 	return (entry->fts_statp->st_atime > plan->t_data);
    224  1.64.16.2  daniel }
    225  1.64.16.2  daniel 
    226  1.64.16.2  daniel PLAN *
    227  1.64.16.2  daniel c_anewer(char ***argvp, int isok)
    228  1.64.16.2  daniel {
    229  1.64.16.2  daniel 	char *filename = **argvp;
    230  1.64.16.2  daniel 	PLAN *new;
    231  1.64.16.2  daniel 	struct stat sb;
    232  1.64.16.2  daniel 
    233  1.64.16.2  daniel 	(*argvp)++;
    234  1.64.16.2  daniel 	ftsoptions &= ~FTS_NOSTAT;
    235  1.64.16.2  daniel 
    236  1.64.16.2  daniel 	if (stat(filename, &sb))
    237  1.64.16.2  daniel 		err(1, "%s", filename);
    238  1.64.16.2  daniel 	new = palloc(N_ANEWER, f_anewer);
    239  1.64.16.2  daniel 	new->t_data = sb.st_atime;
    240  1.64.16.2  daniel 	return (new);
    241  1.64.16.2  daniel }
    242  1.64.16.2  daniel 
    243  1.64.16.2  daniel /*
    244  1.64.16.2  daniel  * -atime n functions --
    245  1.64.16.2  daniel  *
    246  1.64.16.2  daniel  *	True if the difference between the file access time and the
    247  1.64.16.2  daniel  *	current time is n 24 hour periods.
    248  1.64.16.2  daniel  */
    249  1.64.16.2  daniel int
    250  1.64.16.2  daniel f_atime(PLAN *plan, FTSENT *entry)
    251  1.64.16.2  daniel {
    252  1.64.16.2  daniel 	COMPARE((now - entry->fts_statp->st_atime +
    253  1.64.16.2  daniel 	    SECSPERDAY - 1) / SECSPERDAY, plan->t_data);
    254  1.64.16.2  daniel }
    255  1.64.16.2  daniel 
    256  1.64.16.2  daniel PLAN *
    257  1.64.16.2  daniel c_atime(char ***argvp, int isok)
    258  1.64.16.2  daniel {
    259  1.64.16.2  daniel 	char *arg = **argvp;
    260  1.64.16.2  daniel 	PLAN *new;
    261  1.64.16.2  daniel 
    262  1.64.16.2  daniel 	(*argvp)++;
    263  1.64.16.2  daniel 	ftsoptions &= ~FTS_NOSTAT;
    264  1.64.16.2  daniel 
    265  1.64.16.2  daniel 	new = palloc(N_ATIME, f_atime);
    266  1.64.16.2  daniel 	new->t_data = find_parsenum(new, "-atime", arg, NULL);
    267  1.64.16.2  daniel 	TIME_CORRECT(new, N_ATIME);
    268  1.64.16.2  daniel 	return (new);
    269  1.64.16.2  daniel }
    270  1.64.16.2  daniel /*
    271  1.64.16.2  daniel  * -cmin n functions --
    272  1.64.16.2  daniel  *
    273  1.64.16.2  daniel  *	True if the difference between the last change of file
    274  1.64.16.2  daniel  *	status information and the current time is n 24 hour periods.
    275  1.64.16.2  daniel  */
    276  1.64.16.2  daniel int
    277  1.64.16.2  daniel f_cmin(PLAN *plan, FTSENT *entry)
    278  1.64.16.2  daniel {
    279  1.64.16.2  daniel 	COMPARE((now - entry->fts_statp->st_ctime +
    280  1.64.16.2  daniel 	    SECSPERMIN - 1) / SECSPERMIN, plan->t_data);
    281  1.64.16.2  daniel }
    282  1.64.16.2  daniel 
    283  1.64.16.2  daniel PLAN *
    284  1.64.16.2  daniel c_cmin(char ***argvp, int isok)
    285  1.64.16.2  daniel {
    286  1.64.16.2  daniel 	char *arg = **argvp;
    287  1.64.16.2  daniel 	PLAN *new;
    288  1.64.16.2  daniel 
    289  1.64.16.2  daniel 	(*argvp)++;
    290  1.64.16.2  daniel 	ftsoptions &= ~FTS_NOSTAT;
    291  1.64.16.2  daniel 
    292  1.64.16.2  daniel 	new = palloc(N_CMIN, f_cmin);
    293  1.64.16.2  daniel 	new->t_data = find_parsenum(new, "-cmin", arg, NULL);
    294  1.64.16.2  daniel 	TIME_CORRECT(new, N_CMIN);
    295  1.64.16.2  daniel 	return (new);
    296  1.64.16.2  daniel }
    297  1.64.16.2  daniel 
    298  1.64.16.2  daniel /*
    299  1.64.16.2  daniel  * -cnewer file functions --
    300  1.64.16.2  daniel  *
    301  1.64.16.2  daniel  *	True if the current file has been changed more recently
    302  1.64.16.2  daniel  *	than the changed time of the file named by the pathname
    303  1.64.16.2  daniel  *	file.
    304  1.64.16.2  daniel  */
    305  1.64.16.2  daniel int
    306  1.64.16.2  daniel f_cnewer(PLAN *plan, FTSENT *entry)
    307  1.64.16.2  daniel {
    308  1.64.16.2  daniel 
    309  1.64.16.2  daniel 	return (entry->fts_statp->st_ctime > plan->t_data);
    310  1.64.16.2  daniel }
    311  1.64.16.2  daniel 
    312  1.64.16.2  daniel PLAN *
    313  1.64.16.2  daniel c_cnewer(char ***argvp, int isok)
    314  1.64.16.2  daniel {
    315  1.64.16.2  daniel 	char *filename = **argvp;
    316  1.64.16.2  daniel 	PLAN *new;
    317  1.64.16.2  daniel 	struct stat sb;
    318  1.64.16.2  daniel 
    319  1.64.16.2  daniel 	(*argvp)++;
    320  1.64.16.2  daniel 	ftsoptions &= ~FTS_NOSTAT;
    321  1.64.16.2  daniel 
    322  1.64.16.2  daniel 	if (stat(filename, &sb))
    323  1.64.16.2  daniel 		err(1, "%s", filename);
    324  1.64.16.2  daniel 	new = palloc(N_CNEWER, f_cnewer);
    325  1.64.16.2  daniel 	new->t_data = sb.st_ctime;
    326  1.64.16.2  daniel 	return (new);
    327  1.64.16.2  daniel }
    328  1.64.16.2  daniel 
    329  1.64.16.2  daniel /*
    330  1.64.16.2  daniel  * -ctime n functions --
    331  1.64.16.2  daniel  *
    332  1.64.16.2  daniel  *	True if the difference between the last change of file
    333  1.64.16.2  daniel  *	status information and the current time is n 24 hour periods.
    334  1.64.16.2  daniel  */
    335  1.64.16.2  daniel int
    336  1.64.16.2  daniel f_ctime(PLAN *plan, FTSENT *entry)
    337  1.64.16.2  daniel {
    338  1.64.16.2  daniel 	COMPARE((now - entry->fts_statp->st_ctime +
    339  1.64.16.2  daniel 	    SECSPERDAY - 1) / SECSPERDAY, plan->t_data);
    340  1.64.16.2  daniel }
    341  1.64.16.2  daniel 
    342  1.64.16.2  daniel PLAN *
    343  1.64.16.2  daniel c_ctime(char ***argvp, int isok)
    344  1.64.16.2  daniel {
    345  1.64.16.2  daniel 	char *arg = **argvp;
    346  1.64.16.2  daniel 	PLAN *new;
    347  1.64.16.2  daniel 
    348  1.64.16.2  daniel 	(*argvp)++;
    349  1.64.16.2  daniel 	ftsoptions &= ~FTS_NOSTAT;
    350  1.64.16.2  daniel 
    351  1.64.16.2  daniel 	new = palloc(N_CTIME, f_ctime);
    352  1.64.16.2  daniel 	new->t_data = find_parsenum(new, "-ctime", arg, NULL);
    353  1.64.16.2  daniel 	TIME_CORRECT(new, N_CTIME);
    354  1.64.16.2  daniel 	return (new);
    355  1.64.16.2  daniel }
    356  1.64.16.2  daniel 
    357  1.64.16.2  daniel /*
    358  1.64.16.2  daniel  * -delete functions --
    359  1.64.16.2  daniel  *
    360  1.64.16.2  daniel  *	True always.  Makes its best shot and continues on regardless.
    361  1.64.16.2  daniel  */
    362  1.64.16.2  daniel int
    363  1.64.16.2  daniel f_delete(PLAN *plan __unused, FTSENT *entry)
    364  1.64.16.2  daniel {
    365  1.64.16.2  daniel 	/* ignore these from fts */
    366  1.64.16.2  daniel 	if (strcmp(entry->fts_accpath, ".") == 0 ||
    367  1.64.16.2  daniel 	    strcmp(entry->fts_accpath, "..") == 0)
    368  1.64.16.2  daniel 		return 1;
    369  1.64.16.2  daniel 
    370  1.64.16.2  daniel 	/* sanity check */
    371  1.64.16.2  daniel 	if (isdepth == 0 ||			/* depth off */
    372  1.64.16.2  daniel 	    (ftsoptions & FTS_NOSTAT) ||	/* not stat()ing */
    373  1.64.16.2  daniel 	    !(ftsoptions & FTS_PHYSICAL) ||	/* physical off */
    374  1.64.16.2  daniel 	    (ftsoptions & FTS_LOGICAL))		/* or finally, logical on */
    375  1.64.16.2  daniel 		errx(1, "-delete: insecure options got turned on");
    376  1.64.16.2  daniel 
    377  1.64.16.2  daniel 	/* Potentially unsafe - do not accept relative paths whatsoever */
    378  1.64.16.2  daniel 	if (strchr(entry->fts_accpath, '/') != NULL)
    379  1.64.16.2  daniel 		errx(1, "-delete: %s: relative path potentially not safe",
    380  1.64.16.2  daniel 			entry->fts_accpath);
    381  1.64.16.2  daniel 
    382  1.64.16.2  daniel 	/* Turn off user immutable bits if running as root */
    383  1.64.16.2  daniel 	if ((entry->fts_statp->st_flags & (UF_APPEND|UF_IMMUTABLE)) &&
    384  1.64.16.2  daniel 	    !(entry->fts_statp->st_flags & (SF_APPEND|SF_IMMUTABLE)) &&
    385  1.64.16.2  daniel 	    geteuid() == 0)
    386  1.64.16.2  daniel 		chflags(entry->fts_accpath,
    387  1.64.16.2  daniel 		       entry->fts_statp->st_flags &= ~(UF_APPEND|UF_IMMUTABLE));
    388  1.64.16.2  daniel 
    389  1.64.16.2  daniel 	/* rmdir directories, unlink everything else */
    390  1.64.16.2  daniel 	if (S_ISDIR(entry->fts_statp->st_mode)) {
    391  1.64.16.2  daniel 		if (rmdir(entry->fts_accpath) < 0 && errno != ENOTEMPTY)
    392  1.64.16.2  daniel 			warn("-delete: rmdir(%s)", entry->fts_path);
    393  1.64.16.2  daniel 	} else {
    394  1.64.16.2  daniel 		if (unlink(entry->fts_accpath) < 0)
    395  1.64.16.2  daniel 			warn("-delete: unlink(%s)", entry->fts_path);
    396  1.64.16.2  daniel 	}
    397  1.64.16.2  daniel 
    398  1.64.16.2  daniel 	/* "succeed" */
    399  1.64.16.2  daniel 	return 1;
    400  1.64.16.2  daniel }
    401  1.64.16.2  daniel 
    402  1.64.16.2  daniel PLAN *
    403  1.64.16.2  daniel c_delete(char ***argvp __unused, int isok)
    404  1.64.16.2  daniel {
    405  1.64.16.2  daniel 
    406  1.64.16.2  daniel 	ftsoptions &= ~FTS_NOSTAT;	/* no optimize */
    407  1.64.16.2  daniel 	ftsoptions |= FTS_PHYSICAL;	/* disable -follow */
    408  1.64.16.2  daniel 	ftsoptions &= ~FTS_LOGICAL;	/* disable -follow */
    409  1.64.16.2  daniel 	isoutput = 1;			/* possible output */
    410  1.64.16.2  daniel 	isdepth = 1;			/* -depth implied */
    411  1.64.16.2  daniel 
    412  1.64.16.2  daniel 	return palloc(N_DELETE, f_delete);
    413  1.64.16.2  daniel }
    414  1.64.16.2  daniel 
    415  1.64.16.2  daniel /*
    416  1.64.16.2  daniel  * -depth functions --
    417  1.64.16.2  daniel  *
    418  1.64.16.2  daniel  *	Always true, causes descent of the directory hierarchy to be done
    419  1.64.16.2  daniel  *	so that all entries in a directory are acted on before the directory
    420  1.64.16.2  daniel  *	itself.
    421  1.64.16.2  daniel  */
    422  1.64.16.2  daniel int
    423  1.64.16.2  daniel f_always_true(PLAN *plan, FTSENT *entry)
    424  1.64.16.2  daniel {
    425  1.64.16.2  daniel 
    426  1.64.16.2  daniel 	return (1);
    427  1.64.16.2  daniel }
    428  1.64.16.2  daniel 
    429  1.64.16.2  daniel PLAN *
    430  1.64.16.2  daniel c_depth(char ***argvp, int isok)
    431  1.64.16.2  daniel {
    432  1.64.16.2  daniel 	isdepth = 1;
    433  1.64.16.2  daniel 
    434  1.64.16.2  daniel 	return (palloc(N_DEPTH, f_always_true));
    435  1.64.16.2  daniel }
    436  1.64.16.2  daniel 
    437  1.64.16.2  daniel /*
    438  1.64.16.2  daniel  * -empty functions --
    439  1.64.16.2  daniel  *
    440  1.64.16.2  daniel  *	True if the file or directory is empty
    441  1.64.16.2  daniel  */
    442  1.64.16.2  daniel int
    443  1.64.16.2  daniel f_empty(PLAN *plan, FTSENT *entry)
    444  1.64.16.2  daniel {
    445  1.64.16.2  daniel 	if (S_ISREG(entry->fts_statp->st_mode) &&
    446  1.64.16.2  daniel 	    entry->fts_statp->st_size == 0)
    447  1.64.16.2  daniel 		return (1);
    448  1.64.16.2  daniel 	if (S_ISDIR(entry->fts_statp->st_mode)) {
    449  1.64.16.2  daniel 		struct dirent *dp;
    450  1.64.16.2  daniel 		int empty;
    451  1.64.16.2  daniel 		DIR *dir;
    452  1.64.16.2  daniel 
    453  1.64.16.2  daniel 		empty = 1;
    454  1.64.16.2  daniel 		dir = opendir(entry->fts_accpath);
    455  1.64.16.2  daniel 		if (dir == NULL)
    456  1.64.16.2  daniel 			err(1, "%s", entry->fts_accpath);
    457  1.64.16.2  daniel 		for (dp = readdir(dir); dp; dp = readdir(dir))
    458  1.64.16.2  daniel 			if (dp->d_name[0] != '.' ||
    459  1.64.16.2  daniel 			    (dp->d_name[1] != '\0' &&
    460  1.64.16.2  daniel 				(dp->d_name[1] != '.' || dp->d_name[2] != '\0'))) {
    461  1.64.16.2  daniel 				empty = 0;
    462  1.64.16.2  daniel 				break;
    463  1.64.16.2  daniel 			}
    464  1.64.16.2  daniel 		closedir(dir);
    465  1.64.16.2  daniel 		return (empty);
    466  1.64.16.2  daniel 	}
    467  1.64.16.2  daniel 	return (0);
    468  1.64.16.2  daniel }
    469  1.64.16.2  daniel 
    470  1.64.16.2  daniel PLAN *
    471  1.64.16.2  daniel c_empty(char ***argvp, int isok)
    472  1.64.16.2  daniel {
    473  1.64.16.2  daniel 	ftsoptions &= ~FTS_NOSTAT;
    474  1.64.16.2  daniel 
    475  1.64.16.2  daniel 	return (palloc(N_EMPTY, f_empty));
    476  1.64.16.2  daniel }
    477  1.64.16.2  daniel 
    478  1.64.16.2  daniel /*
    479  1.64.16.2  daniel  * [-exec | -ok] utility [arg ... ] ; functions --
    480  1.64.16.2  daniel  * [-exec | -ok] utility [arg ... ] {} + functions --
    481  1.64.16.2  daniel  *
    482  1.64.16.2  daniel  *	If the end of the primary expression is delimited by a
    483  1.64.16.2  daniel  *	semicolon: true if the executed utility returns a zero value
    484  1.64.16.2  daniel  *	as exit status.  If "{}" occurs anywhere, it gets replaced by
    485  1.64.16.2  daniel  *	the current pathname.
    486  1.64.16.2  daniel  *
    487  1.64.16.2  daniel  *	If the end of the primary expression is delimited by a plus
    488  1.64.16.2  daniel  *	sign: always true. Pathnames for which the primary is
    489  1.64.16.2  daniel  *	evaluated shall be aggregated into sets. The utility will be
    490  1.64.16.2  daniel  *	executed once per set, with "{}" replaced by the entire set of
    491  1.64.16.2  daniel  *	pathnames (as if xargs). "{}" must appear last.
    492  1.64.16.2  daniel  *
    493  1.64.16.2  daniel  *	The current directory for the execution of utility is the same
    494  1.64.16.2  daniel  *	as the current directory when the find utility was started.
    495  1.64.16.2  daniel  *
    496  1.64.16.2  daniel  *	The primary -ok is different in that it requests affirmation
    497  1.64.16.2  daniel  *	of the user before executing the utility.
    498  1.64.16.2  daniel  */
    499  1.64.16.2  daniel int
    500  1.64.16.2  daniel f_exec(PLAN *plan, FTSENT *entry)
    501  1.64.16.2  daniel {
    502  1.64.16.2  daniel 	int cnt, l;
    503  1.64.16.2  daniel 	pid_t pid;
    504  1.64.16.2  daniel 	int status;
    505  1.64.16.2  daniel 
    506  1.64.16.2  daniel 	if (plan->flags & F_PLUSSET) {
    507  1.64.16.2  daniel 		/*
    508  1.64.16.2  daniel 		 * Confirm sufficient buffer space, then copy the path
    509  1.64.16.2  daniel 		 * to the buffer.
    510  1.64.16.2  daniel 		 */
    511  1.64.16.2  daniel 		l = strlen(entry->fts_path);
    512  1.64.16.2  daniel 		if (plan->ep_p + l < plan->ep_ebp) {
    513  1.64.16.2  daniel 			plan->ep_bxp[plan->ep_narg++] =
    514  1.64.16.2  daniel 			    strcpy(plan->ep_p, entry->fts_path);
    515  1.64.16.2  daniel 			plan->ep_p += l + 1;
    516  1.64.16.2  daniel 
    517  1.64.16.2  daniel 			if (plan->ep_narg == plan->ep_maxargs)
    518  1.64.16.2  daniel 				run_f_exec(plan);
    519  1.64.16.2  daniel 		} else {
    520  1.64.16.2  daniel 			/*
    521  1.64.16.2  daniel 			 * Without sufficient space to copy in the next
    522  1.64.16.2  daniel 			 * argument, run the command to empty out the
    523  1.64.16.2  daniel 			 * buffer before re-attepting the copy.
    524  1.64.16.2  daniel 			 */
    525  1.64.16.2  daniel 			run_f_exec(plan);
    526  1.64.16.2  daniel 			if ((plan->ep_p + l < plan->ep_ebp)) {
    527  1.64.16.2  daniel 				plan->ep_bxp[plan->ep_narg++]
    528  1.64.16.2  daniel 				    = strcpy(plan->ep_p, entry->fts_path);
    529  1.64.16.2  daniel 				plan->ep_p += l + 1;
    530  1.64.16.2  daniel 			} else
    531  1.64.16.2  daniel 				errx(1, "insufficient space for argument");
    532  1.64.16.2  daniel 		}
    533  1.64.16.2  daniel 		return (1);
    534  1.64.16.2  daniel 	} else {
    535  1.64.16.2  daniel 		for (cnt = 0; plan->e_argv[cnt]; ++cnt)
    536  1.64.16.2  daniel 			if (plan->e_len[cnt])
    537  1.64.16.2  daniel 				brace_subst(plan->e_orig[cnt],
    538  1.64.16.2  daniel 				    &plan->e_argv[cnt],
    539  1.64.16.2  daniel 				    entry->fts_path,
    540  1.64.16.2  daniel 				    &plan->e_len[cnt]);
    541  1.64.16.2  daniel 		if (plan->flags & F_NEEDOK && !queryuser(plan->e_argv))
    542  1.64.16.2  daniel 			return (0);
    543  1.64.16.2  daniel 
    544  1.64.16.2  daniel 		/* Don't mix output of command with find output. */
    545  1.64.16.2  daniel 		fflush(stdout);
    546  1.64.16.2  daniel 		fflush(stderr);
    547  1.64.16.2  daniel 
    548  1.64.16.2  daniel 		switch (pid = vfork()) {
    549  1.64.16.2  daniel 		case -1:
    550  1.64.16.2  daniel 			err(1, "vfork");
    551  1.64.16.2  daniel 			/* NOTREACHED */
    552  1.64.16.2  daniel 		case 0:
    553  1.64.16.2  daniel 			if (fchdir(dotfd)) {
    554  1.64.16.2  daniel 				warn("chdir");
    555  1.64.16.2  daniel 				_exit(1);
    556  1.64.16.2  daniel 			}
    557  1.64.16.2  daniel 			execvp(plan->e_argv[0], plan->e_argv);
    558  1.64.16.2  daniel 			warn("%s", plan->e_argv[0]);
    559  1.64.16.2  daniel 			_exit(1);
    560  1.64.16.2  daniel 		}
    561  1.64.16.2  daniel 		pid = waitpid(pid, &status, 0);
    562  1.64.16.2  daniel 		return (pid != -1 && WIFEXITED(status)
    563  1.64.16.2  daniel 		    && !WEXITSTATUS(status));
    564  1.64.16.2  daniel 	}
    565  1.64.16.2  daniel }
    566  1.64.16.2  daniel 
    567  1.64.16.2  daniel static void
    568  1.64.16.2  daniel run_f_exec(PLAN *plan)
    569  1.64.16.2  daniel {
    570  1.64.16.2  daniel 	pid_t pid;
    571  1.64.16.2  daniel 	int rval, status;
    572  1.64.16.2  daniel 
    573  1.64.16.2  daniel 	/* Ensure arg list is null terminated. */
    574  1.64.16.2  daniel 	plan->ep_bxp[plan->ep_narg] = NULL;
    575  1.64.16.2  daniel 
    576  1.64.16.2  daniel 	/* Don't mix output of command with find output. */
    577  1.64.16.2  daniel 	fflush(stdout);
    578  1.64.16.2  daniel 	fflush(stderr);
    579  1.64.16.2  daniel 
    580  1.64.16.2  daniel 	switch (pid = vfork()) {
    581  1.64.16.2  daniel 	case -1:
    582  1.64.16.2  daniel 		err(1, "vfork");
    583  1.64.16.2  daniel 		/* NOTREACHED */
    584  1.64.16.2  daniel 	case 0:
    585  1.64.16.2  daniel 		if (fchdir(dotfd)) {
    586  1.64.16.2  daniel 			warn("chdir");
    587  1.64.16.2  daniel 			_exit(1);
    588  1.64.16.2  daniel 		}
    589  1.64.16.2  daniel 		execvp(plan->e_argv[0], plan->e_argv);
    590  1.64.16.2  daniel 		warn("%s", plan->e_argv[0]);
    591  1.64.16.2  daniel 		_exit(1);
    592  1.64.16.2  daniel 	}
    593  1.64.16.2  daniel 
    594  1.64.16.2  daniel 	/* Clear out the argument list. */
    595  1.64.16.2  daniel 	plan->ep_narg = 0;
    596  1.64.16.2  daniel 	plan->ep_bxp[plan->ep_narg] = NULL;
    597  1.64.16.2  daniel 	/* As well as the argument buffer. */
    598  1.64.16.2  daniel 	plan->ep_p = plan->ep_bbp;
    599  1.64.16.2  daniel 	*plan->ep_p = '\0';
    600  1.64.16.2  daniel 
    601  1.64.16.2  daniel 	pid = waitpid(pid, &status, 0);
    602  1.64.16.2  daniel 	if (WIFEXITED(status))
    603  1.64.16.2  daniel 		rval = WEXITSTATUS(status);
    604  1.64.16.2  daniel 	else
    605  1.64.16.2  daniel 		rval = -1;
    606  1.64.16.2  daniel 
    607  1.64.16.2  daniel 	/*
    608  1.64.16.2  daniel 	 * If we have a non-zero exit status, preserve it so find(1) can
    609  1.64.16.2  daniel 	 * later exit with it.
    610  1.64.16.2  daniel 	 */
    611  1.64.16.2  daniel 	if (rval)
    612  1.64.16.2  daniel 		plan->ep_rval = rval;
    613  1.64.16.2  daniel }
    614  1.64.16.2  daniel 
    615  1.64.16.2  daniel /*
    616  1.64.16.2  daniel  * c_exec --
    617  1.64.16.2  daniel  *	build three parallel arrays, one with pointers to the strings passed
    618  1.64.16.2  daniel  *	on the command line, one with (possibly duplicated) pointers to the
    619  1.64.16.2  daniel  *	argv array, and one with integer values that are lengths of the
    620  1.64.16.2  daniel  *	strings, but also flags meaning that the string has to be massaged.
    621  1.64.16.2  daniel  *
    622  1.64.16.2  daniel  *	If -exec ... {} +, use only the first array, but make it large
    623  1.64.16.2  daniel  *	enough to hold 5000 args (cf. src/usr.bin/xargs/xargs.c for a
    624  1.64.16.2  daniel  *	discussion), and then allocate ARG_MAX - 4K of space for args.
    625  1.64.16.2  daniel  */
    626  1.64.16.2  daniel PLAN *
    627  1.64.16.2  daniel c_exec(char ***argvp, int isok)
    628  1.64.16.2  daniel {
    629  1.64.16.2  daniel 	PLAN *new;			/* node returned */
    630  1.64.16.2  daniel 	int cnt, brace, lastbrace;
    631  1.64.16.2  daniel 	char **argv, **ap, *p;
    632  1.64.16.2  daniel 
    633  1.64.16.2  daniel 	isoutput = 1;
    634  1.64.16.2  daniel 
    635  1.64.16.2  daniel 	new = palloc(N_EXEC, f_exec);
    636  1.64.16.2  daniel 	if (isok)
    637  1.64.16.2  daniel 		new->flags |= F_NEEDOK;
    638  1.64.16.2  daniel 
    639  1.64.16.2  daniel 	/*
    640  1.64.16.2  daniel 	 * Terminate if we encounter an arg exacty equal to ";", or an
    641  1.64.16.2  daniel 	 * arg exacty equal to "+" following an arg exacty equal to
    642  1.64.16.2  daniel 	 * "{}".
    643  1.64.16.2  daniel 	 */
    644  1.64.16.2  daniel 	for (ap = argv = *argvp, brace = 0;; ++ap) {
    645  1.64.16.2  daniel 		if (!*ap)
    646  1.64.16.2  daniel 			errx(1, "%s: no terminating \";\" or \"+\"",
    647  1.64.16.2  daniel 			    isok ? "-ok" : "-exec");
    648  1.64.16.2  daniel 		lastbrace = brace;
    649  1.64.16.2  daniel 		if (strcmp(*ap, "{}") == 0)
    650  1.64.16.2  daniel 			brace = 1;
    651  1.64.16.2  daniel 		if (strcmp(*ap, ";") == 0)
    652  1.64.16.2  daniel 			break;
    653  1.64.16.2  daniel 		if (strcmp(*ap, "+") == 0 && lastbrace) {
    654  1.64.16.2  daniel 			new->flags |= F_PLUSSET;
    655  1.64.16.2  daniel 			break;
    656  1.64.16.2  daniel 		}
    657  1.64.16.2  daniel 	}
    658  1.64.16.2  daniel 
    659  1.64.16.2  daniel 	/*
    660  1.64.16.2  daniel 	 * POSIX says -ok ... {} + "need not be supported," and it does
    661  1.64.16.2  daniel 	 * not make much sense anyway.
    662  1.64.16.2  daniel 	 */
    663  1.64.16.2  daniel 	if (new->flags & F_NEEDOK && new->flags & F_PLUSSET)
    664  1.64.16.2  daniel 		errx(1, "-ok: terminating \"+\" not permitted.");
    665  1.64.16.2  daniel 
    666  1.64.16.2  daniel 	if (new->flags & F_PLUSSET) {
    667  1.64.16.2  daniel 		u_int c, bufsize;
    668  1.64.16.2  daniel 
    669  1.64.16.2  daniel 		cnt = ap - *argvp - 1;			/* units are words */
    670  1.64.16.2  daniel 		new->ep_maxargs = 5000;
    671  1.64.16.2  daniel 		new->e_argv = (char **)emalloc((u_int)(cnt + new->ep_maxargs)
    672  1.64.16.2  daniel 						* sizeof(char **));
    673  1.64.16.2  daniel 
    674  1.64.16.2  daniel 		/* We start stuffing arguments after the user's last one. */
    675  1.64.16.2  daniel 		new->ep_bxp = &new->e_argv[cnt];
    676  1.64.16.2  daniel 		new->ep_narg = 0;
    677  1.64.16.2  daniel 
    678  1.64.16.2  daniel 		/*
    679  1.64.16.2  daniel 		 * Count up the space of the user's arguments, and
    680  1.64.16.2  daniel 		 * subtract that from what we allocate.
    681  1.64.16.2  daniel 		 */
    682  1.64.16.2  daniel 		for (argv = *argvp, c = 0, cnt = 0;
    683  1.64.16.2  daniel 		     argv < ap;
    684  1.64.16.2  daniel 		     ++argv, ++cnt) {
    685  1.64.16.2  daniel 			c += strlen(*argv) + 1;
    686  1.64.16.2  daniel 			new->e_argv[cnt] = *argv;
    687  1.64.16.2  daniel 		}
    688  1.64.16.2  daniel 		bufsize = ARG_MAX - 4 * 1024 - c;
    689  1.64.16.2  daniel 
    690  1.64.16.2  daniel 
    691  1.64.16.2  daniel 		/*
    692  1.64.16.2  daniel 		 * Allocate, and then initialize current, base, and
    693  1.64.16.2  daniel 		 * end pointers.
    694  1.64.16.2  daniel 		 */
    695  1.64.16.2  daniel 		new->ep_p = new->ep_bbp = malloc(bufsize + 1);
    696  1.64.16.2  daniel 		new->ep_ebp = new->ep_bbp + bufsize - 1;
    697  1.64.16.2  daniel 		new->ep_rval = 0;
    698  1.64.16.2  daniel 	} else { /* !F_PLUSSET */
    699  1.64.16.2  daniel 		cnt = ap - *argvp + 1;
    700  1.64.16.2  daniel 		new->e_argv = (char **)emalloc((u_int)cnt * sizeof(char *));
    701  1.64.16.2  daniel 		new->e_orig = (char **)emalloc((u_int)cnt * sizeof(char *));
    702  1.64.16.2  daniel 		new->e_len = (int *)emalloc((u_int)cnt * sizeof(int));
    703  1.64.16.2  daniel 
    704  1.64.16.2  daniel 		for (argv = *argvp, cnt = 0; argv < ap; ++argv, ++cnt) {
    705  1.64.16.2  daniel 			new->e_orig[cnt] = *argv;
    706  1.64.16.2  daniel 			for (p = *argv; *p; ++p)
    707  1.64.16.2  daniel 				if (p[0] == '{' && p[1] == '}') {
    708  1.64.16.2  daniel 					new->e_argv[cnt] =
    709  1.64.16.2  daniel 						emalloc((u_int)MAXPATHLEN);
    710  1.64.16.2  daniel 					new->e_len[cnt] = MAXPATHLEN;
    711  1.64.16.2  daniel 					break;
    712  1.64.16.2  daniel 				}
    713  1.64.16.2  daniel 			if (!*p) {
    714  1.64.16.2  daniel 				new->e_argv[cnt] = *argv;
    715  1.64.16.2  daniel 				new->e_len[cnt] = 0;
    716  1.64.16.2  daniel 			}
    717  1.64.16.2  daniel 		}
    718  1.64.16.2  daniel 		new->e_orig[cnt] = NULL;
    719  1.64.16.2  daniel 	}
    720  1.64.16.2  daniel 
    721  1.64.16.2  daniel 	new->e_argv[cnt] = NULL;
    722  1.64.16.2  daniel 	*argvp = argv + 1;
    723  1.64.16.2  daniel 	return (new);
    724  1.64.16.2  daniel }
    725  1.64.16.2  daniel 
    726  1.64.16.2  daniel /*
    727  1.64.16.2  daniel  * -execdir utility [arg ... ] ; functions --
    728  1.64.16.2  daniel  *
    729  1.64.16.2  daniel  *	True if the executed utility returns a zero value as exit status.
    730  1.64.16.2  daniel  *	The end of the primary expression is delimited by a semicolon.  If
    731  1.64.16.2  daniel  *	"{}" occurs anywhere, it gets replaced by the unqualified pathname.
    732  1.64.16.2  daniel  *	The current directory for the execution of utility is the same as
    733  1.64.16.2  daniel  *	the directory where the file lives.
    734  1.64.16.2  daniel  */
    735  1.64.16.2  daniel int
    736  1.64.16.2  daniel f_execdir(PLAN *plan, FTSENT *entry)
    737  1.64.16.2  daniel {
    738  1.64.16.2  daniel 	int cnt;
    739  1.64.16.2  daniel 	pid_t pid;
    740  1.64.16.2  daniel 	int status;
    741  1.64.16.2  daniel 	char *file;
    742  1.64.16.2  daniel 
    743  1.64.16.2  daniel 	/* XXX - if file/dir ends in '/' this will not work -- can it? */
    744  1.64.16.2  daniel 	if ((file = strrchr(entry->fts_path, '/')))
    745  1.64.16.2  daniel 		file++;
    746  1.64.16.2  daniel 	else
    747  1.64.16.2  daniel 		file = entry->fts_path;
    748  1.64.16.2  daniel 
    749  1.64.16.2  daniel 	for (cnt = 0; plan->e_argv[cnt]; ++cnt)
    750  1.64.16.2  daniel 		if (plan->e_len[cnt])
    751  1.64.16.2  daniel 			brace_subst(plan->e_orig[cnt], &plan->e_argv[cnt],
    752  1.64.16.2  daniel 			    file, &plan->e_len[cnt]);
    753  1.64.16.2  daniel 
    754  1.64.16.2  daniel 	/* don't mix output of command with find output */
    755  1.64.16.2  daniel 	fflush(stdout);
    756  1.64.16.2  daniel 	fflush(stderr);
    757  1.64.16.2  daniel 
    758  1.64.16.2  daniel 	switch (pid = vfork()) {
    759  1.64.16.2  daniel 	case -1:
    760  1.64.16.2  daniel 		err(1, "fork");
    761  1.64.16.2  daniel 		/* NOTREACHED */
    762  1.64.16.2  daniel 	case 0:
    763  1.64.16.2  daniel 		execvp(plan->e_argv[0], plan->e_argv);
    764  1.64.16.2  daniel 		warn("%s", plan->e_argv[0]);
    765  1.64.16.2  daniel 		_exit(1);
    766  1.64.16.2  daniel 	}
    767  1.64.16.2  daniel 	pid = waitpid(pid, &status, 0);
    768  1.64.16.2  daniel 	return (pid != -1 && WIFEXITED(status) && !WEXITSTATUS(status));
    769  1.64.16.2  daniel }
    770  1.64.16.2  daniel 
    771  1.64.16.2  daniel /*
    772  1.64.16.2  daniel  * c_execdir --
    773  1.64.16.2  daniel  *	build three parallel arrays, one with pointers to the strings passed
    774  1.64.16.2  daniel  *	on the command line, one with (possibly duplicated) pointers to the
    775  1.64.16.2  daniel  *	argv array, and one with integer values that are lengths of the
    776  1.64.16.2  daniel  *	strings, but also flags meaning that the string has to be massaged.
    777  1.64.16.2  daniel  */
    778  1.64.16.2  daniel PLAN *
    779  1.64.16.2  daniel c_execdir(char ***argvp, int isok)
    780  1.64.16.2  daniel {
    781  1.64.16.2  daniel 	PLAN *new;			/* node returned */
    782  1.64.16.2  daniel 	int cnt;
    783  1.64.16.2  daniel 	char **argv, **ap, *p;
    784  1.64.16.2  daniel 
    785  1.64.16.2  daniel 	ftsoptions &= ~FTS_NOSTAT;
    786  1.64.16.2  daniel 	isoutput = 1;
    787  1.64.16.2  daniel 
    788  1.64.16.2  daniel 	new = palloc(N_EXECDIR, f_execdir);
    789  1.64.16.2  daniel 
    790  1.64.16.2  daniel 	for (ap = argv = *argvp;; ++ap) {
    791  1.64.16.2  daniel 		if (!*ap)
    792  1.64.16.2  daniel 			errx(1,
    793  1.64.16.2  daniel 			    "-execdir: no terminating \";\"");
    794  1.64.16.2  daniel 		if (**ap == ';')
    795  1.64.16.2  daniel 			break;
    796  1.64.16.2  daniel 	}
    797  1.64.16.2  daniel 
    798  1.64.16.2  daniel 	cnt = ap - *argvp + 1;
    799  1.64.16.2  daniel 	new->e_argv = (char **)emalloc((u_int)cnt * sizeof(char *));
    800  1.64.16.2  daniel 	new->e_orig = (char **)emalloc((u_int)cnt * sizeof(char *));
    801  1.64.16.2  daniel 	new->e_len = (int *)emalloc((u_int)cnt * sizeof(int));
    802  1.64.16.2  daniel 
    803  1.64.16.2  daniel 	for (argv = *argvp, cnt = 0; argv < ap; ++argv, ++cnt) {
    804  1.64.16.2  daniel 		new->e_orig[cnt] = *argv;
    805  1.64.16.2  daniel 		for (p = *argv; *p; ++p)
    806  1.64.16.2  daniel 			if (p[0] == '{' && p[1] == '}') {
    807  1.64.16.2  daniel 				new->e_argv[cnt] = emalloc((u_int)MAXPATHLEN);
    808  1.64.16.2  daniel 				new->e_len[cnt] = MAXPATHLEN;
    809  1.64.16.2  daniel 				break;
    810  1.64.16.2  daniel 			}
    811  1.64.16.2  daniel 		if (!*p) {
    812  1.64.16.2  daniel 			new->e_argv[cnt] = *argv;
    813  1.64.16.2  daniel 			new->e_len[cnt] = 0;
    814  1.64.16.2  daniel 		}
    815  1.64.16.2  daniel 	}
    816  1.64.16.2  daniel 	new->e_argv[cnt] = new->e_orig[cnt] = NULL;
    817  1.64.16.2  daniel 
    818  1.64.16.2  daniel 	*argvp = argv + 1;
    819  1.64.16.2  daniel 	return (new);
    820  1.64.16.2  daniel }
    821  1.64.16.2  daniel 
    822  1.64.16.2  daniel PLAN *
    823  1.64.16.2  daniel c_exit(char ***argvp, int isok)
    824  1.64.16.2  daniel {
    825  1.64.16.2  daniel 	char *arg = **argvp;
    826  1.64.16.2  daniel 	PLAN *new;
    827  1.64.16.2  daniel 
    828  1.64.16.2  daniel 	/* not technically true, but otherwise '-print' is implied */
    829  1.64.16.2  daniel 	isoutput = 1;
    830  1.64.16.2  daniel 
    831  1.64.16.2  daniel 	new = palloc(N_EXIT, f_always_true);
    832  1.64.16.2  daniel 
    833  1.64.16.2  daniel 	if (arg) {
    834  1.64.16.2  daniel 		(*argvp)++;
    835  1.64.16.2  daniel 		new->exit_val = find_parsenum(new, "-exit", arg, NULL);
    836  1.64.16.2  daniel 	} else
    837  1.64.16.2  daniel 		new->exit_val = 0;
    838  1.64.16.2  daniel 
    839  1.64.16.2  daniel 	return (new);
    840  1.64.16.2  daniel }
    841  1.64.16.2  daniel 
    842  1.64.16.2  daniel 
    843  1.64.16.2  daniel /*
    844  1.64.16.2  daniel  * -false function
    845  1.64.16.2  daniel  */
    846  1.64.16.2  daniel int
    847  1.64.16.2  daniel f_false(PLAN *plan, FTSENT *entry)
    848  1.64.16.2  daniel {
    849  1.64.16.2  daniel 
    850  1.64.16.2  daniel 	return (0);
    851  1.64.16.2  daniel }
    852  1.64.16.2  daniel 
    853  1.64.16.2  daniel PLAN *
    854  1.64.16.2  daniel c_false(char ***argvp, int isok)
    855  1.64.16.2  daniel {
    856  1.64.16.2  daniel 	return (palloc(N_FALSE, f_false));
    857  1.64.16.2  daniel }
    858  1.64.16.2  daniel 
    859  1.64.16.2  daniel 
    860  1.64.16.2  daniel /*
    861  1.64.16.2  daniel  * -flags [-]flags functions --
    862  1.64.16.2  daniel  */
    863  1.64.16.2  daniel int
    864  1.64.16.2  daniel f_flags(PLAN *plan, FTSENT *entry)
    865  1.64.16.2  daniel {
    866  1.64.16.2  daniel 	u_int32_t flags;
    867  1.64.16.2  daniel 
    868  1.64.16.2  daniel 	flags = entry->fts_statp->st_flags;
    869  1.64.16.2  daniel 	if (plan->flags == F_ATLEAST)
    870  1.64.16.2  daniel 		return ((plan->f_data | flags) == flags);
    871  1.64.16.2  daniel 	else
    872  1.64.16.2  daniel 		return (flags == plan->f_data);
    873  1.64.16.2  daniel 	/* NOTREACHED */
    874  1.64.16.2  daniel }
    875  1.64.16.2  daniel 
    876  1.64.16.2  daniel PLAN *
    877  1.64.16.2  daniel c_flags(char ***argvp, int isok)
    878  1.64.16.2  daniel {
    879  1.64.16.2  daniel 	char *flags = **argvp;
    880  1.64.16.2  daniel 	PLAN *new;
    881  1.64.16.2  daniel 	u_long flagset;
    882  1.64.16.2  daniel 
    883  1.64.16.2  daniel 	(*argvp)++;
    884  1.64.16.2  daniel 	ftsoptions &= ~FTS_NOSTAT;
    885  1.64.16.2  daniel 
    886  1.64.16.2  daniel 	new = palloc(N_FLAGS, f_flags);
    887  1.64.16.2  daniel 
    888  1.64.16.2  daniel 	if (*flags == '-') {
    889  1.64.16.2  daniel 		new->flags = F_ATLEAST;
    890  1.64.16.2  daniel 		++flags;
    891  1.64.16.2  daniel 	}
    892  1.64.16.2  daniel 
    893  1.64.16.2  daniel 	flagset = 0;
    894  1.64.16.2  daniel 	if ((strcmp(flags, "none") != 0) &&
    895  1.64.16.2  daniel 	    (string_to_flags(&flags, &flagset, NULL) != 0))
    896  1.64.16.2  daniel 		errx(1, "-flags: %s: illegal flags string", flags);
    897  1.64.16.2  daniel 	new->f_data = flagset;
    898  1.64.16.2  daniel 	return (new);
    899  1.64.16.2  daniel }
    900  1.64.16.2  daniel 
    901  1.64.16.2  daniel /*
    902  1.64.16.2  daniel  * -follow functions --
    903  1.64.16.2  daniel  *
    904  1.64.16.2  daniel  *	Always true, causes symbolic links to be followed on a global
    905  1.64.16.2  daniel  *	basis.
    906  1.64.16.2  daniel  */
    907  1.64.16.2  daniel PLAN *
    908  1.64.16.2  daniel c_follow(char ***argvp, int isok)
    909  1.64.16.2  daniel {
    910  1.64.16.2  daniel 	ftsoptions &= ~FTS_PHYSICAL;
    911  1.64.16.2  daniel 	ftsoptions |= FTS_LOGICAL;
    912  1.64.16.2  daniel 
    913  1.64.16.2  daniel 	return (palloc(N_FOLLOW, f_always_true));
    914  1.64.16.2  daniel }
    915  1.64.16.2  daniel 
    916  1.64.16.2  daniel /* -fprint functions --
    917  1.64.16.2  daniel  *
    918  1.64.16.2  daniel  *	Causes the current pathame to be written to the defined output file.
    919  1.64.16.2  daniel  */
    920  1.64.16.2  daniel int
    921  1.64.16.2  daniel f_fprint(PLAN *plan, FTSENT *entry)
    922  1.64.16.2  daniel {
    923  1.64.16.2  daniel 
    924  1.64.16.2  daniel 	if (-1 == fprintf(plan->fprint_file, "%s\n", entry->fts_path))
    925  1.64.16.2  daniel 		warn("fprintf");
    926  1.64.16.2  daniel 
    927  1.64.16.2  daniel 	return(1);
    928  1.64.16.2  daniel 
    929  1.64.16.2  daniel 	/* no descriptors are closed; they will be closed by
    930  1.64.16.2  daniel 	   operating system when this find command exits.  */
    931  1.64.16.2  daniel }
    932  1.64.16.2  daniel 
    933  1.64.16.2  daniel PLAN *
    934  1.64.16.2  daniel c_fprint(char ***argvp, int isok)
    935  1.64.16.2  daniel {
    936  1.64.16.2  daniel 	PLAN *new;
    937  1.64.16.2  daniel 
    938  1.64.16.2  daniel 	isoutput = 1; /* do not assume -print */
    939  1.64.16.2  daniel 
    940  1.64.16.2  daniel 	new = palloc(N_FPRINT, f_fprint);
    941  1.64.16.2  daniel 
    942  1.64.16.2  daniel 	if (NULL == (new->fprint_file = fopen(**argvp, "w")))
    943  1.64.16.2  daniel 		err(1, "-fprint: %s: cannot create file", **argvp);
    944  1.64.16.2  daniel 
    945  1.64.16.2  daniel 	(*argvp)++;
    946  1.64.16.2  daniel 	return (new);
    947  1.64.16.2  daniel }
    948  1.64.16.2  daniel 
    949  1.64.16.2  daniel /*
    950  1.64.16.2  daniel  * -fstype functions --
    951  1.64.16.2  daniel  *
    952  1.64.16.2  daniel  *	True if the file is of a certain type.
    953  1.64.16.2  daniel  */
    954  1.64.16.2  daniel int
    955  1.64.16.2  daniel f_fstype(PLAN *plan, FTSENT *entry)
    956  1.64.16.2  daniel {
    957  1.64.16.2  daniel 	static dev_t curdev;	/* need a guaranteed illegal dev value */
    958  1.64.16.2  daniel 	static int first = 1;
    959  1.64.16.2  daniel 	struct statvfs sb;
    960  1.64.16.2  daniel 	static short val;
    961  1.64.16.2  daniel 	static char fstype[sizeof(sb.f_fstypename)];
    962  1.64.16.2  daniel 	char *p, save[2];
    963  1.64.16.2  daniel 
    964  1.64.16.2  daniel 	memset(&save, 0, sizeof save);	/* XXX gcc */
    965  1.64.16.2  daniel 
    966  1.64.16.2  daniel 	/* Only check when we cross mount point. */
    967  1.64.16.2  daniel 	if (first || curdev != entry->fts_statp->st_dev) {
    968  1.64.16.2  daniel 		curdev = entry->fts_statp->st_dev;
    969  1.64.16.2  daniel 
    970  1.64.16.2  daniel 		/*
    971  1.64.16.2  daniel 		 * Statfs follows symlinks; find wants the link's file system,
    972  1.64.16.2  daniel 		 * not where it points.
    973  1.64.16.2  daniel 		 */
    974  1.64.16.2  daniel 		if (entry->fts_info == FTS_SL ||
    975  1.64.16.2  daniel 		    entry->fts_info == FTS_SLNONE) {
    976  1.64.16.2  daniel 			if ((p = strrchr(entry->fts_accpath, '/')) != NULL)
    977  1.64.16.2  daniel 				++p;
    978  1.64.16.2  daniel 			else
    979  1.64.16.2  daniel 				p = entry->fts_accpath;
    980  1.64.16.2  daniel 			save[0] = p[0];
    981  1.64.16.2  daniel 			p[0] = '.';
    982  1.64.16.2  daniel 			save[1] = p[1];
    983  1.64.16.2  daniel 			p[1] = '\0';
    984  1.64.16.2  daniel 
    985  1.64.16.2  daniel 		} else
    986  1.64.16.2  daniel 			p = NULL;
    987  1.64.16.2  daniel 
    988  1.64.16.2  daniel 		if (statvfs(entry->fts_accpath, &sb))
    989  1.64.16.2  daniel 			err(1, "%s", entry->fts_accpath);
    990  1.64.16.2  daniel 
    991  1.64.16.2  daniel 		if (p) {
    992  1.64.16.2  daniel 			p[0] = save[0];
    993  1.64.16.2  daniel 			p[1] = save[1];
    994  1.64.16.2  daniel 		}
    995  1.64.16.2  daniel 
    996  1.64.16.2  daniel 		first = 0;
    997  1.64.16.2  daniel 
    998  1.64.16.2  daniel 		/*
    999  1.64.16.2  daniel 		 * Further tests may need both of these values, so
   1000  1.64.16.2  daniel 		 * always copy both of them.
   1001  1.64.16.2  daniel 		 */
   1002  1.64.16.2  daniel 		val = sb.f_flag;
   1003  1.64.16.2  daniel 		strlcpy(fstype, sb.f_fstypename, sizeof(fstype));
   1004  1.64.16.2  daniel 	}
   1005  1.64.16.2  daniel 	switch (plan->flags) {
   1006  1.64.16.2  daniel 	case F_MTFLAG:
   1007  1.64.16.2  daniel 		return (val & plan->mt_data);
   1008  1.64.16.2  daniel 	case F_MTTYPE:
   1009  1.64.16.2  daniel 		return (strncmp(fstype, plan->c_data, sizeof(fstype)) == 0);
   1010  1.64.16.2  daniel 	default:
   1011  1.64.16.2  daniel 		abort();
   1012  1.64.16.2  daniel 	}
   1013  1.64.16.2  daniel }
   1014  1.64.16.2  daniel 
   1015  1.64.16.2  daniel PLAN *
   1016  1.64.16.2  daniel c_fstype(char ***argvp, int isok)
   1017  1.64.16.2  daniel {
   1018  1.64.16.2  daniel 	char *arg = **argvp;
   1019  1.64.16.2  daniel 	PLAN *new;
   1020  1.64.16.2  daniel 
   1021  1.64.16.2  daniel 	(*argvp)++;
   1022  1.64.16.2  daniel 	ftsoptions &= ~FTS_NOSTAT;
   1023  1.64.16.2  daniel 
   1024  1.64.16.2  daniel 	new = palloc(N_FSTYPE, f_fstype);
   1025  1.64.16.2  daniel 
   1026  1.64.16.2  daniel 	switch (*arg) {
   1027  1.64.16.2  daniel 	case 'l':
   1028  1.64.16.2  daniel 		if (!strcmp(arg, "local")) {
   1029  1.64.16.2  daniel 			new->flags = F_MTFLAG;
   1030  1.64.16.2  daniel 			new->mt_data = MNT_LOCAL;
   1031  1.64.16.2  daniel 			return (new);
   1032  1.64.16.2  daniel 		}
   1033  1.64.16.2  daniel 		break;
   1034  1.64.16.2  daniel 	case 'r':
   1035  1.64.16.2  daniel 		if (!strcmp(arg, "rdonly")) {
   1036  1.64.16.2  daniel 			new->flags = F_MTFLAG;
   1037  1.64.16.2  daniel 			new->mt_data = MNT_RDONLY;
   1038  1.64.16.2  daniel 			return (new);
   1039  1.64.16.2  daniel 		}
   1040  1.64.16.2  daniel 		break;
   1041  1.64.16.2  daniel 	}
   1042  1.64.16.2  daniel 
   1043  1.64.16.2  daniel 	new->flags = F_MTTYPE;
   1044  1.64.16.2  daniel 	new->c_data = arg;
   1045  1.64.16.2  daniel 	return (new);
   1046  1.64.16.2  daniel }
   1047  1.64.16.2  daniel 
   1048  1.64.16.2  daniel /*
   1049  1.64.16.2  daniel  * -group gname functions --
   1050  1.64.16.2  daniel  *
   1051  1.64.16.2  daniel  *	True if the file belongs to the group gname.  If gname is numeric and
   1052  1.64.16.2  daniel  *	an equivalent of the getgrnam() function does not return a valid group
   1053  1.64.16.2  daniel  *	name, gname is taken as a group ID.
   1054  1.64.16.2  daniel  */
   1055  1.64.16.2  daniel int
   1056  1.64.16.2  daniel f_group(PLAN *plan, FTSENT *entry)
   1057  1.64.16.2  daniel {
   1058  1.64.16.2  daniel 
   1059  1.64.16.2  daniel 	return (entry->fts_statp->st_gid == plan->g_data);
   1060  1.64.16.2  daniel }
   1061  1.64.16.2  daniel 
   1062  1.64.16.2  daniel PLAN *
   1063  1.64.16.2  daniel c_group(char ***argvp, int isok)
   1064  1.64.16.2  daniel {
   1065  1.64.16.2  daniel 	char *gname = **argvp;
   1066  1.64.16.2  daniel 	PLAN *new;
   1067  1.64.16.2  daniel 	struct group *g;
   1068  1.64.16.2  daniel 	gid_t gid;
   1069  1.64.16.2  daniel 
   1070  1.64.16.2  daniel 	(*argvp)++;
   1071  1.64.16.2  daniel 	ftsoptions &= ~FTS_NOSTAT;
   1072  1.64.16.2  daniel 
   1073  1.64.16.2  daniel 	g = getgrnam(gname);
   1074  1.64.16.2  daniel 	if (g == NULL) {
   1075  1.64.16.2  daniel 		gid = atoi(gname);
   1076  1.64.16.2  daniel 		if (gid == 0 && gname[0] != '0')
   1077  1.64.16.2  daniel 			errx(1, "-group: %s: no such group", gname);
   1078  1.64.16.2  daniel 	} else
   1079  1.64.16.2  daniel 		gid = g->gr_gid;
   1080  1.64.16.2  daniel 
   1081  1.64.16.2  daniel 	new = palloc(N_GROUP, f_group);
   1082  1.64.16.2  daniel 	new->g_data = gid;
   1083  1.64.16.2  daniel 	return (new);
   1084  1.64.16.2  daniel }
   1085  1.64.16.2  daniel 
   1086  1.64.16.2  daniel /*
   1087  1.64.16.2  daniel  * -inum n functions --
   1088  1.64.16.2  daniel  *
   1089  1.64.16.2  daniel  *	True if the file has inode # n.
   1090  1.64.16.2  daniel  */
   1091  1.64.16.2  daniel int
   1092  1.64.16.2  daniel f_inum(PLAN *plan, FTSENT *entry)
   1093  1.64.16.2  daniel {
   1094  1.64.16.2  daniel 
   1095  1.64.16.2  daniel 	COMPARE(entry->fts_statp->st_ino, plan->i_data);
   1096  1.64.16.2  daniel }
   1097  1.64.16.2  daniel 
   1098  1.64.16.2  daniel PLAN *
   1099  1.64.16.2  daniel c_inum(char ***argvp, int isok)
   1100  1.64.16.2  daniel {
   1101  1.64.16.2  daniel 	char *arg = **argvp;
   1102  1.64.16.2  daniel 	PLAN *new;
   1103  1.64.16.2  daniel 
   1104  1.64.16.2  daniel 	(*argvp)++;
   1105  1.64.16.2  daniel 	ftsoptions &= ~FTS_NOSTAT;
   1106  1.64.16.2  daniel 
   1107  1.64.16.2  daniel 	new = palloc(N_INUM, f_inum);
   1108  1.64.16.2  daniel 	new->i_data = find_parsenum(new, "-inum", arg, NULL);
   1109  1.64.16.2  daniel 	return (new);
   1110  1.64.16.2  daniel }
   1111  1.64.16.2  daniel 
   1112  1.64.16.2  daniel /*
   1113  1.64.16.2  daniel  * -links n functions --
   1114  1.64.16.2  daniel  *
   1115  1.64.16.2  daniel  *	True if the file has n links.
   1116  1.64.16.2  daniel  */
   1117  1.64.16.2  daniel int
   1118  1.64.16.2  daniel f_links(PLAN *plan, FTSENT *entry)
   1119  1.64.16.2  daniel {
   1120  1.64.16.2  daniel 
   1121  1.64.16.2  daniel 	COMPARE(entry->fts_statp->st_nlink, plan->l_data);
   1122  1.64.16.2  daniel }
   1123  1.64.16.2  daniel 
   1124  1.64.16.2  daniel PLAN *
   1125  1.64.16.2  daniel c_links(char ***argvp, int isok)
   1126  1.64.16.2  daniel {
   1127  1.64.16.2  daniel 	char *arg = **argvp;
   1128  1.64.16.2  daniel 	PLAN *new;
   1129  1.64.16.2  daniel 
   1130  1.64.16.2  daniel 	(*argvp)++;
   1131  1.64.16.2  daniel 	ftsoptions &= ~FTS_NOSTAT;
   1132  1.64.16.2  daniel 
   1133  1.64.16.2  daniel 	new = palloc(N_LINKS, f_links);
   1134  1.64.16.2  daniel 	new->l_data = (nlink_t)find_parsenum(new, "-links", arg, NULL);
   1135  1.64.16.2  daniel 	return (new);
   1136  1.64.16.2  daniel }
   1137  1.64.16.2  daniel 
   1138  1.64.16.2  daniel /*
   1139  1.64.16.2  daniel  * -ls functions --
   1140  1.64.16.2  daniel  *
   1141  1.64.16.2  daniel  *	Always true - prints the current entry to stdout in "ls" format.
   1142  1.64.16.2  daniel  */
   1143  1.64.16.2  daniel int
   1144  1.64.16.2  daniel f_ls(PLAN *plan, FTSENT *entry)
   1145  1.64.16.2  daniel {
   1146  1.64.16.2  daniel 
   1147  1.64.16.2  daniel 	printlong(entry->fts_path, entry->fts_accpath, entry->fts_statp);
   1148  1.64.16.2  daniel 	return (1);
   1149  1.64.16.2  daniel }
   1150  1.64.16.2  daniel 
   1151  1.64.16.2  daniel PLAN *
   1152  1.64.16.2  daniel c_ls(char ***argvp, int isok)
   1153  1.64.16.2  daniel {
   1154  1.64.16.2  daniel 
   1155  1.64.16.2  daniel 	ftsoptions &= ~FTS_NOSTAT;
   1156  1.64.16.2  daniel 	isoutput = 1;
   1157  1.64.16.2  daniel 
   1158  1.64.16.2  daniel 	return (palloc(N_LS, f_ls));
   1159  1.64.16.2  daniel }
   1160  1.64.16.2  daniel 
   1161  1.64.16.2  daniel /*
   1162  1.64.16.2  daniel  * - maxdepth n functions --
   1163  1.64.16.2  daniel  *
   1164  1.64.16.2  daniel  *	True if the current search depth is less than or equal to the
   1165  1.64.16.2  daniel  *	maximum depth specified
   1166  1.64.16.2  daniel  */
   1167  1.64.16.2  daniel int
   1168  1.64.16.2  daniel f_maxdepth(PLAN *plan, FTSENT *entry)
   1169  1.64.16.2  daniel {
   1170  1.64.16.2  daniel 	extern FTS *tree;
   1171  1.64.16.2  daniel 
   1172  1.64.16.2  daniel 	if (entry->fts_level >= plan->max_data)
   1173  1.64.16.2  daniel 		fts_set(tree, entry, FTS_SKIP);
   1174  1.64.16.2  daniel 	return (entry->fts_level <= plan->max_data);
   1175  1.64.16.2  daniel }
   1176  1.64.16.2  daniel 
   1177  1.64.16.2  daniel PLAN *
   1178  1.64.16.2  daniel c_maxdepth(char ***argvp, int isok)
   1179  1.64.16.2  daniel {
   1180  1.64.16.2  daniel 	char *arg = **argvp;
   1181  1.64.16.2  daniel 	PLAN *new;
   1182  1.64.16.2  daniel 
   1183  1.64.16.2  daniel 	(*argvp)++;
   1184  1.64.16.2  daniel 	new = palloc(N_MAXDEPTH, f_maxdepth);
   1185  1.64.16.2  daniel 	new->max_data = atoi(arg);
   1186  1.64.16.2  daniel 	return (new);
   1187  1.64.16.2  daniel }
   1188  1.64.16.2  daniel 
   1189  1.64.16.2  daniel /*
   1190  1.64.16.2  daniel  * - mindepth n functions --
   1191  1.64.16.2  daniel  *
   1192  1.64.16.2  daniel  *	True if the current search depth is greater than or equal to the
   1193  1.64.16.2  daniel  *	minimum depth specified
   1194  1.64.16.2  daniel  */
   1195  1.64.16.2  daniel int
   1196  1.64.16.2  daniel f_mindepth(PLAN *plan, FTSENT *entry)
   1197  1.64.16.2  daniel {
   1198  1.64.16.2  daniel 	return (entry->fts_level >= plan->min_data);
   1199  1.64.16.2  daniel }
   1200  1.64.16.2  daniel 
   1201  1.64.16.2  daniel PLAN *
   1202  1.64.16.2  daniel c_mindepth(char ***argvp, int isok)
   1203  1.64.16.2  daniel {
   1204  1.64.16.2  daniel 	char *arg = **argvp;
   1205  1.64.16.2  daniel 	PLAN *new;
   1206  1.64.16.2  daniel 
   1207  1.64.16.2  daniel 	(*argvp)++;
   1208  1.64.16.2  daniel 	new = palloc(N_MINDEPTH, f_mindepth);
   1209  1.64.16.2  daniel 	new->min_data = atoi(arg);
   1210  1.64.16.2  daniel 	return (new);
   1211  1.64.16.2  daniel }
   1212  1.64.16.2  daniel /*
   1213  1.64.16.2  daniel  * -mmin n functions --
   1214  1.64.16.2  daniel  *
   1215  1.64.16.2  daniel  *	True if the difference between the file modification time and the
   1216  1.64.16.2  daniel  *	current time is n 24 hour periods.
   1217  1.64.16.2  daniel  */
   1218  1.64.16.2  daniel int
   1219  1.64.16.2  daniel f_mmin(PLAN *plan, FTSENT *entry)
   1220  1.64.16.2  daniel {
   1221  1.64.16.2  daniel 	COMPARE((now - entry->fts_statp->st_mtime + SECSPERMIN - 1) /
   1222  1.64.16.2  daniel 	    SECSPERMIN, plan->t_data);
   1223  1.64.16.2  daniel }
   1224  1.64.16.2  daniel 
   1225  1.64.16.2  daniel PLAN *
   1226  1.64.16.2  daniel c_mmin(char ***argvp, int isok)
   1227  1.64.16.2  daniel {
   1228  1.64.16.2  daniel 	char *arg = **argvp;
   1229  1.64.16.2  daniel 	PLAN *new;
   1230  1.64.16.2  daniel 
   1231  1.64.16.2  daniel 	(*argvp)++;
   1232  1.64.16.2  daniel 	ftsoptions &= ~FTS_NOSTAT;
   1233  1.64.16.2  daniel 
   1234  1.64.16.2  daniel 	new = palloc(N_MMIN, f_mmin);
   1235  1.64.16.2  daniel 	new->t_data = find_parsenum(new, "-mmin", arg, NULL);
   1236  1.64.16.2  daniel 	TIME_CORRECT(new, N_MMIN);
   1237  1.64.16.2  daniel 	return (new);
   1238  1.64.16.2  daniel }
   1239  1.64.16.2  daniel /*
   1240  1.64.16.2  daniel  * -mtime n functions --
   1241  1.64.16.2  daniel  *
   1242  1.64.16.2  daniel  *	True if the difference between the file modification time and the
   1243  1.64.16.2  daniel  *	current time is n 24 hour periods.
   1244  1.64.16.2  daniel  */
   1245  1.64.16.2  daniel int
   1246  1.64.16.2  daniel f_mtime(PLAN *plan, FTSENT *entry)
   1247  1.64.16.2  daniel {
   1248  1.64.16.2  daniel 	COMPARE((now - entry->fts_statp->st_mtime + SECSPERDAY - 1) /
   1249  1.64.16.2  daniel 	    SECSPERDAY, plan->t_data);
   1250  1.64.16.2  daniel }
   1251  1.64.16.2  daniel 
   1252  1.64.16.2  daniel PLAN *
   1253  1.64.16.2  daniel c_mtime(char ***argvp, int isok)
   1254  1.64.16.2  daniel {
   1255  1.64.16.2  daniel 	char *arg = **argvp;
   1256  1.64.16.2  daniel 	PLAN *new;
   1257  1.64.16.2  daniel 
   1258  1.64.16.2  daniel 	(*argvp)++;
   1259  1.64.16.2  daniel 	ftsoptions &= ~FTS_NOSTAT;
   1260  1.64.16.2  daniel 
   1261  1.64.16.2  daniel 	new = palloc(N_MTIME, f_mtime);
   1262  1.64.16.2  daniel 	new->t_data = find_parsenum(new, "-mtime", arg, NULL);
   1263  1.64.16.2  daniel 	TIME_CORRECT(new, N_MTIME);
   1264  1.64.16.2  daniel 	return (new);
   1265  1.64.16.2  daniel }
   1266  1.64.16.2  daniel 
   1267  1.64.16.2  daniel /*
   1268  1.64.16.2  daniel  * -name functions --
   1269  1.64.16.2  daniel  *
   1270  1.64.16.2  daniel  *	True if the basename of the filename being examined
   1271  1.64.16.2  daniel  *	matches pattern using Pattern Matching Notation S3.14
   1272  1.64.16.2  daniel  */
   1273  1.64.16.2  daniel int
   1274  1.64.16.2  daniel f_name(PLAN *plan, FTSENT *entry)
   1275  1.64.16.2  daniel {
   1276  1.64.16.2  daniel 
   1277  1.64.16.2  daniel 	return (!fnmatch(plan->c_data, entry->fts_name, 0));
   1278  1.64.16.2  daniel }
   1279  1.64.16.2  daniel 
   1280  1.64.16.2  daniel PLAN *
   1281  1.64.16.2  daniel c_name(char ***argvp, int isok)
   1282  1.64.16.2  daniel {
   1283  1.64.16.2  daniel 	char *pattern = **argvp;
   1284  1.64.16.2  daniel 	PLAN *new;
   1285  1.64.16.2  daniel 
   1286  1.64.16.2  daniel 	(*argvp)++;
   1287  1.64.16.2  daniel 	new = palloc(N_NAME, f_name);
   1288  1.64.16.2  daniel 	new->c_data = pattern;
   1289  1.64.16.2  daniel 	return (new);
   1290  1.64.16.2  daniel }
   1291  1.64.16.2  daniel 
   1292  1.64.16.2  daniel /*
   1293  1.64.16.2  daniel  * -iname functions --
   1294  1.64.16.2  daniel  *
   1295  1.64.16.2  daniel  *	Similar to -name, but does case insensitive matching
   1296  1.64.16.2  daniel  *
   1297  1.64.16.2  daniel  */
   1298  1.64.16.2  daniel int
   1299  1.64.16.2  daniel f_iname(PLAN *plan, FTSENT *entry)
   1300  1.64.16.2  daniel {
   1301  1.64.16.2  daniel 	return (!fnmatch(plan->c_data, entry->fts_name, FNM_CASEFOLD));
   1302  1.64.16.2  daniel }
   1303  1.64.16.2  daniel 
   1304  1.64.16.2  daniel PLAN *
   1305  1.64.16.2  daniel c_iname(char ***argvp, int isok)
   1306  1.64.16.2  daniel {
   1307  1.64.16.2  daniel 	char *pattern = **argvp;
   1308  1.64.16.2  daniel 	PLAN *new;
   1309  1.64.16.2  daniel 
   1310  1.64.16.2  daniel 	(*argvp)++;
   1311  1.64.16.2  daniel 	new = palloc(N_INAME, f_iname);
   1312  1.64.16.2  daniel 	new->c_data = pattern;
   1313  1.64.16.2  daniel 	return (new);
   1314  1.64.16.2  daniel }
   1315  1.64.16.2  daniel 
   1316  1.64.16.2  daniel /*
   1317  1.64.16.2  daniel  * -newer file functions --
   1318  1.64.16.2  daniel  *
   1319  1.64.16.2  daniel  *	True if the current file has been modified more recently
   1320  1.64.16.2  daniel  *	than the modification time of the file named by the pathname
   1321  1.64.16.2  daniel  *	file.
   1322  1.64.16.2  daniel  */
   1323  1.64.16.2  daniel int
   1324  1.64.16.2  daniel f_newer(PLAN *plan, FTSENT *entry)
   1325  1.64.16.2  daniel {
   1326  1.64.16.2  daniel 
   1327  1.64.16.2  daniel 	return (entry->fts_statp->st_mtime > plan->t_data);
   1328  1.64.16.2  daniel }
   1329  1.64.16.2  daniel 
   1330  1.64.16.2  daniel PLAN *
   1331  1.64.16.2  daniel c_newer(char ***argvp, int isok)
   1332  1.64.16.2  daniel {
   1333  1.64.16.2  daniel 	char *filename = **argvp;
   1334  1.64.16.2  daniel 	PLAN *new;
   1335  1.64.16.2  daniel 	struct stat sb;
   1336  1.64.16.2  daniel 
   1337  1.64.16.2  daniel 	(*argvp)++;
   1338  1.64.16.2  daniel 	ftsoptions &= ~FTS_NOSTAT;
   1339  1.64.16.2  daniel 
   1340  1.64.16.2  daniel 	if (stat(filename, &sb))
   1341  1.64.16.2  daniel 		err(1, "%s", filename);
   1342  1.64.16.2  daniel 	new = palloc(N_NEWER, f_newer);
   1343  1.64.16.2  daniel 	new->t_data = sb.st_mtime;
   1344  1.64.16.2  daniel 	return (new);
   1345  1.64.16.2  daniel }
   1346  1.64.16.2  daniel 
   1347  1.64.16.2  daniel /*
   1348  1.64.16.2  daniel  * -nogroup functions --
   1349  1.64.16.2  daniel  *
   1350  1.64.16.2  daniel  *	True if file belongs to a user ID for which the equivalent
   1351  1.64.16.2  daniel  *	of the getgrnam() 9.2.1 [POSIX.1] function returns NULL.
   1352  1.64.16.2  daniel  */
   1353  1.64.16.2  daniel int
   1354  1.64.16.2  daniel f_nogroup(PLAN *plan, FTSENT *entry)
   1355  1.64.16.2  daniel {
   1356  1.64.16.2  daniel 
   1357  1.64.16.2  daniel 	return (group_from_gid(entry->fts_statp->st_gid, 1) ? 0 : 1);
   1358  1.64.16.2  daniel }
   1359  1.64.16.2  daniel 
   1360  1.64.16.2  daniel PLAN *
   1361  1.64.16.2  daniel c_nogroup(char ***argvp, int isok)
   1362  1.64.16.2  daniel {
   1363  1.64.16.2  daniel 	ftsoptions &= ~FTS_NOSTAT;
   1364  1.64.16.2  daniel 
   1365  1.64.16.2  daniel 	return (palloc(N_NOGROUP, f_nogroup));
   1366  1.64.16.2  daniel }
   1367  1.64.16.2  daniel 
   1368  1.64.16.2  daniel /*
   1369  1.64.16.2  daniel  * -nouser functions --
   1370  1.64.16.2  daniel  *
   1371  1.64.16.2  daniel  *	True if file belongs to a user ID for which the equivalent
   1372  1.64.16.2  daniel  *	of the getpwuid() 9.2.2 [POSIX.1] function returns NULL.
   1373  1.64.16.2  daniel  */
   1374  1.64.16.2  daniel int
   1375  1.64.16.2  daniel f_nouser(PLAN *plan, FTSENT *entry)
   1376  1.64.16.2  daniel {
   1377  1.64.16.2  daniel 
   1378  1.64.16.2  daniel 	return (user_from_uid(entry->fts_statp->st_uid, 1) ? 0 : 1);
   1379  1.64.16.2  daniel }
   1380  1.64.16.2  daniel 
   1381  1.64.16.2  daniel PLAN *
   1382  1.64.16.2  daniel c_nouser(char ***argvp, int isok)
   1383  1.64.16.2  daniel {
   1384  1.64.16.2  daniel 	ftsoptions &= ~FTS_NOSTAT;
   1385  1.64.16.2  daniel 
   1386  1.64.16.2  daniel 	return (palloc(N_NOUSER, f_nouser));
   1387  1.64.16.2  daniel }
   1388  1.64.16.2  daniel 
   1389  1.64.16.2  daniel /*
   1390  1.64.16.2  daniel  * -path functions --
   1391  1.64.16.2  daniel  *
   1392  1.64.16.2  daniel  *	True if the path of the filename being examined
   1393  1.64.16.2  daniel  *	matches pattern using Pattern Matching Notation S3.14
   1394  1.64.16.2  daniel  */
   1395  1.64.16.2  daniel int
   1396  1.64.16.2  daniel f_path(PLAN *plan, FTSENT *entry)
   1397  1.64.16.2  daniel {
   1398  1.64.16.2  daniel 
   1399  1.64.16.2  daniel 	return (!fnmatch(plan->c_data, entry->fts_path, 0));
   1400  1.64.16.2  daniel }
   1401  1.64.16.2  daniel 
   1402  1.64.16.2  daniel PLAN *
   1403  1.64.16.2  daniel c_path(char ***argvp, int isok)
   1404  1.64.16.2  daniel {
   1405  1.64.16.2  daniel 	char *pattern = **argvp;
   1406  1.64.16.2  daniel 	PLAN *new;
   1407  1.64.16.2  daniel 
   1408  1.64.16.2  daniel 	(*argvp)++;
   1409  1.64.16.2  daniel 	new = palloc(N_NAME, f_path);
   1410  1.64.16.2  daniel 	new->c_data = pattern;
   1411  1.64.16.2  daniel 	return (new);
   1412  1.64.16.2  daniel }
   1413  1.64.16.2  daniel 
   1414  1.64.16.2  daniel /*
   1415  1.64.16.2  daniel  * -perm functions --
   1416  1.64.16.2  daniel  *
   1417  1.64.16.2  daniel  *	The mode argument is used to represent file mode bits.  If it starts
   1418  1.64.16.2  daniel  *	with a leading digit, it's treated as an octal mode, otherwise as a
   1419  1.64.16.2  daniel  *	symbolic mode.
   1420  1.64.16.2  daniel  */
   1421  1.64.16.2  daniel int
   1422  1.64.16.2  daniel f_perm(PLAN *plan, FTSENT *entry)
   1423  1.64.16.2  daniel {
   1424  1.64.16.2  daniel 	mode_t mode;
   1425  1.64.16.2  daniel 
   1426  1.64.16.2  daniel 	mode = entry->fts_statp->st_mode &
   1427  1.64.16.2  daniel 	    (S_ISUID|S_ISGID|S_ISTXT|S_IRWXU|S_IRWXG|S_IRWXO);
   1428  1.64.16.2  daniel 	if (plan->flags == F_ATLEAST)
   1429  1.64.16.2  daniel 		return ((plan->m_data | mode) == mode);
   1430  1.64.16.2  daniel 	else
   1431  1.64.16.2  daniel 		return (mode == plan->m_data);
   1432  1.64.16.2  daniel 	/* NOTREACHED */
   1433  1.64.16.2  daniel }
   1434  1.64.16.2  daniel 
   1435  1.64.16.2  daniel PLAN *
   1436  1.64.16.2  daniel c_perm(char ***argvp, int isok)
   1437  1.64.16.2  daniel {
   1438  1.64.16.2  daniel 	char *perm = **argvp;
   1439  1.64.16.2  daniel 	PLAN *new;
   1440  1.64.16.2  daniel 	mode_t *set;
   1441  1.64.16.2  daniel 
   1442  1.64.16.2  daniel 	(*argvp)++;
   1443  1.64.16.2  daniel 	ftsoptions &= ~FTS_NOSTAT;
   1444  1.64.16.2  daniel 
   1445  1.64.16.2  daniel 	new = palloc(N_PERM, f_perm);
   1446  1.64.16.2  daniel 
   1447  1.64.16.2  daniel 	if (*perm == '-') {
   1448  1.64.16.2  daniel 		new->flags = F_ATLEAST;
   1449  1.64.16.2  daniel 		++perm;
   1450  1.64.16.2  daniel 	}
   1451  1.64.16.2  daniel 
   1452  1.64.16.2  daniel 	if ((set = setmode(perm)) == NULL)
   1453  1.64.16.2  daniel 		err(1, "-perm: Cannot set file mode `%s'", perm);
   1454  1.64.16.2  daniel 
   1455  1.64.16.2  daniel 	new->m_data = getmode(set, 0);
   1456  1.64.16.2  daniel 	free(set);
   1457  1.64.16.2  daniel 	return (new);
   1458  1.64.16.2  daniel }
   1459  1.64.16.2  daniel 
   1460  1.64.16.2  daniel /*
   1461  1.64.16.2  daniel  * -print functions --
   1462  1.64.16.2  daniel  *
   1463  1.64.16.2  daniel  *	Always true, causes the current pathame to be written to
   1464  1.64.16.2  daniel  *	standard output.
   1465  1.64.16.2  daniel  */
   1466  1.64.16.2  daniel int
   1467  1.64.16.2  daniel f_print(PLAN *plan, FTSENT *entry)
   1468  1.64.16.2  daniel {
   1469  1.64.16.2  daniel 
   1470  1.64.16.2  daniel 	(void)printf("%s\n", entry->fts_path);
   1471  1.64.16.2  daniel 	return (1);
   1472  1.64.16.2  daniel }
   1473  1.64.16.2  daniel 
   1474  1.64.16.2  daniel int
   1475  1.64.16.2  daniel f_print0(PLAN *plan, FTSENT *entry)
   1476  1.64.16.2  daniel {
   1477  1.64.16.2  daniel 
   1478  1.64.16.2  daniel 	(void)fputs(entry->fts_path, stdout);
   1479  1.64.16.2  daniel 	(void)fputc('\0', stdout);
   1480  1.64.16.2  daniel 	return (1);
   1481  1.64.16.2  daniel }
   1482  1.64.16.2  daniel 
   1483  1.64.16.2  daniel int
   1484  1.64.16.2  daniel f_printx(PLAN *plan, FTSENT *entry)
   1485  1.64.16.2  daniel {
   1486  1.64.16.2  daniel 	char *cp;
   1487  1.64.16.2  daniel 
   1488  1.64.16.2  daniel 	for (cp = entry->fts_path; *cp; cp++) {
   1489  1.64.16.2  daniel 		if (*cp == '\'' || *cp == '\"' || *cp == ' ' ||
   1490  1.64.16.2  daniel 		    *cp == '$'  || *cp == '`'  ||
   1491  1.64.16.2  daniel 		    *cp == '\t' || *cp == '\n' || *cp == '\\')
   1492  1.64.16.2  daniel 			fputc('\\', stdout);
   1493  1.64.16.2  daniel 
   1494  1.64.16.2  daniel 		fputc(*cp, stdout);
   1495  1.64.16.2  daniel 	}
   1496  1.64.16.2  daniel 
   1497  1.64.16.2  daniel 	fputc('\n', stdout);
   1498  1.64.16.2  daniel 	return (1);
   1499  1.64.16.2  daniel }
   1500  1.64.16.2  daniel 
   1501  1.64.16.2  daniel PLAN *
   1502  1.64.16.2  daniel c_print(char ***argvp, int isok)
   1503  1.64.16.2  daniel {
   1504  1.64.16.2  daniel 
   1505  1.64.16.2  daniel 	isoutput = 1;
   1506  1.64.16.2  daniel 
   1507  1.64.16.2  daniel 	return (palloc(N_PRINT, f_print));
   1508  1.64.16.2  daniel }
   1509  1.64.16.2  daniel 
   1510  1.64.16.2  daniel PLAN *
   1511  1.64.16.2  daniel c_print0(char ***argvp, int isok)
   1512  1.64.16.2  daniel {
   1513  1.64.16.2  daniel 
   1514  1.64.16.2  daniel 	isoutput = 1;
   1515  1.64.16.2  daniel 
   1516  1.64.16.2  daniel 	return (palloc(N_PRINT0, f_print0));
   1517  1.64.16.2  daniel }
   1518  1.64.16.2  daniel 
   1519  1.64.16.2  daniel PLAN *
   1520  1.64.16.2  daniel c_printx(char ***argvp, int isok)
   1521  1.64.16.2  daniel {
   1522  1.64.16.2  daniel 
   1523  1.64.16.2  daniel 	isoutput = 1;
   1524  1.64.16.2  daniel 
   1525  1.64.16.2  daniel 	return (palloc(N_PRINTX, f_printx));
   1526  1.64.16.2  daniel }
   1527  1.64.16.2  daniel 
   1528  1.64.16.2  daniel /*
   1529  1.64.16.2  daniel  * -prune functions --
   1530  1.64.16.2  daniel  *
   1531  1.64.16.2  daniel  *	Prune a portion of the hierarchy.
   1532  1.64.16.2  daniel  */
   1533  1.64.16.2  daniel int
   1534  1.64.16.2  daniel f_prune(PLAN *plan, FTSENT *entry)
   1535  1.64.16.2  daniel {
   1536  1.64.16.2  daniel 	if (fts_set(tree, entry, FTS_SKIP))
   1537  1.64.16.2  daniel 		err(1, "%s", entry->fts_path);
   1538  1.64.16.2  daniel 	return (1);
   1539  1.64.16.2  daniel }
   1540  1.64.16.2  daniel 
   1541  1.64.16.2  daniel PLAN *
   1542  1.64.16.2  daniel c_prune(char ***argvp, int isok)
   1543  1.64.16.2  daniel {
   1544  1.64.16.2  daniel 
   1545  1.64.16.2  daniel 	return (palloc(N_PRUNE, f_prune));
   1546  1.64.16.2  daniel }
   1547  1.64.16.2  daniel 
   1548  1.64.16.2  daniel /*
   1549  1.64.16.2  daniel  * -regex regexp (and related) functions --
   1550  1.64.16.2  daniel  *
   1551  1.64.16.2  daniel  *	True if the complete file path matches the regular expression regexp.
   1552  1.64.16.2  daniel  *	For -regex, regexp is a case-sensitive (basic) regular expression.
   1553  1.64.16.2  daniel  *	For -iregex, regexp is a case-insensitive (basic) regular expression.
   1554  1.64.16.2  daniel  */
   1555  1.64.16.2  daniel int
   1556  1.64.16.2  daniel f_regex(PLAN *plan, FTSENT *entry)
   1557  1.64.16.2  daniel {
   1558  1.64.16.2  daniel 
   1559  1.64.16.2  daniel 	return (regexec(&plan->regexp_data, entry->fts_path, 0, NULL, 0) == 0);
   1560  1.64.16.2  daniel }
   1561  1.64.16.2  daniel 
   1562  1.64.16.2  daniel static PLAN *
   1563  1.64.16.2  daniel c_regex_common(char ***argvp, int isok, enum ntype type, bool icase)
   1564  1.64.16.2  daniel {
   1565  1.64.16.2  daniel 	char errbuf[LINE_MAX];
   1566  1.64.16.2  daniel 	regex_t reg;
   1567  1.64.16.2  daniel 	char *regexp = **argvp;
   1568  1.64.16.2  daniel 	char *lineregexp;
   1569  1.64.16.2  daniel 	PLAN *new;
   1570  1.64.16.2  daniel 	int rv;
   1571  1.64.16.2  daniel 	size_t len;
   1572  1.64.16.2  daniel 
   1573  1.64.16.2  daniel 	(*argvp)++;
   1574  1.64.16.2  daniel 
   1575  1.64.16.2  daniel 	len = strlen(regexp) + 1 + 6;
   1576  1.64.16.2  daniel 	lineregexp = malloc(len);	/* max needed */
   1577  1.64.16.2  daniel 	if (lineregexp == NULL)
   1578  1.64.16.2  daniel 		err(1, NULL);
   1579  1.64.16.2  daniel 	snprintf(lineregexp, len, "^%s(%s%s)$",
   1580  1.64.16.2  daniel 	    (regcomp_flags & REG_EXTENDED) ? "" : "\\", regexp,
   1581  1.64.16.2  daniel 	    (regcomp_flags & REG_EXTENDED) ? "" : "\\");
   1582  1.64.16.2  daniel 	rv = regcomp(&reg, lineregexp, REG_NOSUB|regcomp_flags|
   1583  1.64.16.2  daniel 	    (icase ? REG_ICASE : 0));
   1584  1.64.16.2  daniel 	free(lineregexp);
   1585  1.64.16.2  daniel 	if (rv != 0) {
   1586  1.64.16.2  daniel 		regerror(rv, &reg, errbuf, sizeof errbuf);
   1587  1.64.16.2  daniel 		errx(1, "regexp %s: %s", regexp, errbuf);
   1588  1.64.16.2  daniel 	}
   1589  1.64.16.2  daniel 
   1590  1.64.16.2  daniel 	new = palloc(type, f_regex);
   1591  1.64.16.2  daniel 	new->regexp_data = reg;
   1592  1.64.16.2  daniel 	return (new);
   1593  1.64.16.2  daniel }
   1594  1.64.16.2  daniel 
   1595  1.64.16.2  daniel PLAN *
   1596  1.64.16.2  daniel c_regex(char ***argvp, int isok)
   1597  1.64.16.2  daniel {
   1598  1.64.16.2  daniel 
   1599  1.64.16.2  daniel 	return (c_regex_common(argvp, isok, N_REGEX, false));
   1600  1.64.16.2  daniel }
   1601  1.64.16.2  daniel 
   1602  1.64.16.2  daniel PLAN *
   1603  1.64.16.2  daniel c_iregex(char ***argvp, int isok)
   1604  1.64.16.2  daniel {
   1605  1.64.16.2  daniel 
   1606  1.64.16.2  daniel 	return (c_regex_common(argvp, isok, N_IREGEX, true));
   1607  1.64.16.2  daniel }
   1608  1.64.16.2  daniel 
   1609  1.64.16.2  daniel /*
   1610  1.64.16.2  daniel  * -size n[c] functions --
   1611  1.64.16.2  daniel  *
   1612  1.64.16.2  daniel  *	True if the file size in bytes, divided by an implementation defined
   1613  1.64.16.2  daniel  *	value and rounded up to the next integer, is n.  If n is followed by
   1614  1.64.16.2  daniel  *	a c, the size is in bytes.
   1615  1.64.16.2  daniel  */
   1616  1.64.16.2  daniel #define	FIND_SIZE	512
   1617  1.64.16.2  daniel static int divsize = 1;
   1618  1.64.16.2  daniel 
   1619  1.64.16.2  daniel int
   1620  1.64.16.2  daniel f_size(PLAN *plan, FTSENT *entry)
   1621  1.64.16.2  daniel {
   1622  1.64.16.2  daniel 	off_t size;
   1623  1.64.16.2  daniel 
   1624  1.64.16.2  daniel 	size = divsize ? (entry->fts_statp->st_size + FIND_SIZE - 1) /
   1625  1.64.16.2  daniel 	    FIND_SIZE : entry->fts_statp->st_size;
   1626  1.64.16.2  daniel 	COMPARE(size, plan->o_data);
   1627  1.64.16.2  daniel }
   1628  1.64.16.2  daniel 
   1629  1.64.16.2  daniel PLAN *
   1630  1.64.16.2  daniel c_size(char ***argvp, int isok)
   1631  1.64.16.2  daniel {
   1632  1.64.16.2  daniel 	char *arg = **argvp;
   1633  1.64.16.2  daniel 	PLAN *new;
   1634  1.64.16.2  daniel 	char endch;
   1635  1.64.16.2  daniel 
   1636  1.64.16.2  daniel 	(*argvp)++;
   1637  1.64.16.2  daniel 	ftsoptions &= ~FTS_NOSTAT;
   1638  1.64.16.2  daniel 
   1639  1.64.16.2  daniel 	new = palloc(N_SIZE, f_size);
   1640  1.64.16.2  daniel 	endch = 'c';
   1641  1.64.16.2  daniel 	new->o_data = find_parsenum(new, "-size", arg, &endch);
   1642  1.64.16.2  daniel 	if (endch == 'c')
   1643  1.64.16.2  daniel 		divsize = 0;
   1644  1.64.16.2  daniel 	return (new);
   1645  1.64.16.2  daniel }
   1646  1.64.16.2  daniel 
   1647  1.64.16.2  daniel /*
   1648  1.64.16.2  daniel  * -type c functions --
   1649  1.64.16.2  daniel  *
   1650  1.64.16.2  daniel  *	True if the type of the file is c, where c is b, c, d, p, f or w
   1651  1.64.16.2  daniel  *	for block special file, character special file, directory, FIFO,
   1652  1.64.16.2  daniel  *	regular file or whiteout respectively.
   1653  1.64.16.2  daniel  */
   1654  1.64.16.2  daniel int
   1655  1.64.16.2  daniel f_type(PLAN *plan, FTSENT *entry)
   1656  1.64.16.2  daniel {
   1657  1.64.16.2  daniel 
   1658  1.64.16.2  daniel 	return ((entry->fts_statp->st_mode & S_IFMT) == plan->m_data);
   1659  1.64.16.2  daniel }
   1660  1.64.16.2  daniel 
   1661  1.64.16.2  daniel PLAN *
   1662  1.64.16.2  daniel c_type(char ***argvp, int isok)
   1663  1.64.16.2  daniel {
   1664  1.64.16.2  daniel 	char *typestring = **argvp;
   1665  1.64.16.2  daniel 	PLAN *new;
   1666  1.64.16.2  daniel 	mode_t  mask = (mode_t)0;
   1667  1.64.16.2  daniel 
   1668  1.64.16.2  daniel 	(*argvp)++;
   1669  1.64.16.2  daniel 	ftsoptions &= ~FTS_NOSTAT;
   1670  1.64.16.2  daniel 
   1671  1.64.16.2  daniel 	switch (typestring[0]) {
   1672  1.64.16.2  daniel 	case 'b':
   1673  1.64.16.2  daniel 		mask = S_IFBLK;
   1674  1.64.16.2  daniel 		break;
   1675  1.64.16.2  daniel 	case 'c':
   1676  1.64.16.2  daniel 		mask = S_IFCHR;
   1677  1.64.16.2  daniel 		break;
   1678  1.64.16.2  daniel 	case 'd':
   1679  1.64.16.2  daniel 		mask = S_IFDIR;
   1680  1.64.16.2  daniel 		break;
   1681  1.64.16.2  daniel 	case 'f':
   1682  1.64.16.2  daniel 		mask = S_IFREG;
   1683  1.64.16.2  daniel 		break;
   1684  1.64.16.2  daniel 	case 'l':
   1685  1.64.16.2  daniel 		mask = S_IFLNK;
   1686  1.64.16.2  daniel 		break;
   1687  1.64.16.2  daniel 	case 'p':
   1688  1.64.16.2  daniel 		mask = S_IFIFO;
   1689  1.64.16.2  daniel 		break;
   1690  1.64.16.2  daniel 	case 's':
   1691  1.64.16.2  daniel 		mask = S_IFSOCK;
   1692  1.64.16.2  daniel 		break;
   1693  1.64.16.2  daniel #ifdef S_IFWHT
   1694  1.64.16.2  daniel 	case 'W':
   1695  1.64.16.2  daniel 	case 'w':
   1696  1.64.16.2  daniel 		mask = S_IFWHT;
   1697  1.64.16.2  daniel #ifdef FTS_WHITEOUT
   1698  1.64.16.2  daniel 		ftsoptions |= FTS_WHITEOUT;
   1699  1.64.16.2  daniel #endif
   1700  1.64.16.2  daniel 		break;
   1701  1.64.16.2  daniel #endif /* S_IFWHT */
   1702  1.64.16.2  daniel 	default:
   1703  1.64.16.2  daniel 		errx(1, "-type: %s: unknown type", typestring);
   1704  1.64.16.2  daniel 	}
   1705  1.64.16.2  daniel 
   1706  1.64.16.2  daniel 	new = palloc(N_TYPE, f_type);
   1707  1.64.16.2  daniel 	new->m_data = mask;
   1708  1.64.16.2  daniel 	return (new);
   1709  1.64.16.2  daniel }
   1710  1.64.16.2  daniel 
   1711  1.64.16.2  daniel /*
   1712  1.64.16.2  daniel  * -user uname functions --
   1713  1.64.16.2  daniel  *
   1714  1.64.16.2  daniel  *	True if the file belongs to the user uname.  If uname is numeric and
   1715  1.64.16.2  daniel  *	an equivalent of the getpwnam() S9.2.2 [POSIX.1] function does not
   1716  1.64.16.2  daniel  *	return a valid user name, uname is taken as a user ID.
   1717  1.64.16.2  daniel  */
   1718  1.64.16.2  daniel int
   1719  1.64.16.2  daniel f_user(PLAN *plan, FTSENT *entry)
   1720  1.64.16.2  daniel {
   1721  1.64.16.2  daniel 
   1722  1.64.16.2  daniel 	COMPARE(entry->fts_statp->st_uid, plan->u_data);
   1723  1.64.16.2  daniel }
   1724  1.64.16.2  daniel 
   1725  1.64.16.2  daniel PLAN *
   1726  1.64.16.2  daniel c_user(char ***argvp, int isok)
   1727  1.64.16.2  daniel {
   1728  1.64.16.2  daniel 	char *username = **argvp;
   1729  1.64.16.2  daniel 	PLAN *new;
   1730  1.64.16.2  daniel 	struct passwd *p;
   1731  1.64.16.2  daniel 	uid_t uid;
   1732  1.64.16.2  daniel 
   1733  1.64.16.2  daniel 	(*argvp)++;
   1734  1.64.16.2  daniel 	ftsoptions &= ~FTS_NOSTAT;
   1735  1.64.16.2  daniel 
   1736  1.64.16.2  daniel 	new = palloc(N_USER, f_user);
   1737  1.64.16.2  daniel 	p = getpwnam(username);
   1738  1.64.16.2  daniel 	if (p == NULL) {
   1739  1.64.16.2  daniel 		if (atoi(username) == 0 && username[0] != '0' &&
   1740  1.64.16.2  daniel 		    strcmp(username, "+0") && strcmp(username, "-0"))
   1741  1.64.16.2  daniel 			errx(1, "-user: %s: no such user", username);
   1742  1.64.16.2  daniel 		uid = find_parsenum(new, "-user", username, NULL);
   1743  1.64.16.2  daniel 
   1744  1.64.16.2  daniel 	} else {
   1745  1.64.16.2  daniel 		new->flags = F_EQUAL;
   1746  1.64.16.2  daniel 		uid = p->pw_uid;
   1747  1.64.16.2  daniel 	}
   1748  1.64.16.2  daniel 
   1749  1.64.16.2  daniel 	new->u_data = uid;
   1750  1.64.16.2  daniel 	return (new);
   1751  1.64.16.2  daniel }
   1752  1.64.16.2  daniel 
   1753  1.64.16.2  daniel /*
   1754  1.64.16.2  daniel  * -xdev functions --
   1755  1.64.16.2  daniel  *
   1756  1.64.16.2  daniel  *	Always true, causes find not to descend past directories that have a
   1757  1.64.16.2  daniel  *	different device ID (st_dev, see stat() S5.6.2 [POSIX.1])
   1758  1.64.16.2  daniel  */
   1759  1.64.16.2  daniel PLAN *
   1760  1.64.16.2  daniel c_xdev(char ***argvp, int isok)
   1761  1.64.16.2  daniel {
   1762  1.64.16.2  daniel 	ftsoptions |= FTS_XDEV;
   1763  1.64.16.2  daniel 
   1764  1.64.16.2  daniel 	return (palloc(N_XDEV, f_always_true));
   1765  1.64.16.2  daniel }
   1766  1.64.16.2  daniel 
   1767  1.64.16.2  daniel /*
   1768  1.64.16.2  daniel  * ( expression ) functions --
   1769  1.64.16.2  daniel  *
   1770  1.64.16.2  daniel  *	True if expression is true.
   1771  1.64.16.2  daniel  */
   1772  1.64.16.2  daniel int
   1773  1.64.16.2  daniel f_expr(PLAN *plan, FTSENT *entry)
   1774  1.64.16.2  daniel {
   1775  1.64.16.2  daniel 	PLAN *p;
   1776  1.64.16.2  daniel 	int state;
   1777  1.64.16.2  daniel 
   1778  1.64.16.2  daniel 	state = 0;
   1779  1.64.16.2  daniel 	for (p = plan->p_data[0];
   1780  1.64.16.2  daniel 	    p && (state = (p->eval)(p, entry)); p = p->next);
   1781  1.64.16.2  daniel 	return (state);
   1782  1.64.16.2  daniel }
   1783  1.64.16.2  daniel 
   1784  1.64.16.2  daniel /*
   1785  1.64.16.2  daniel  * N_OPENPAREN and N_CLOSEPAREN nodes are temporary place markers.  They are
   1786  1.64.16.2  daniel  * eliminated during phase 2 of find_formplan() --- the '(' node is converted
   1787  1.64.16.2  daniel  * to a N_EXPR node containing the expression and the ')' node is discarded.
   1788  1.64.16.2  daniel  */
   1789  1.64.16.2  daniel PLAN *
   1790  1.64.16.2  daniel c_openparen(char ***argvp, int isok)
   1791  1.64.16.2  daniel {
   1792  1.64.16.2  daniel 
   1793  1.64.16.2  daniel 	return (palloc(N_OPENPAREN, (int (*)(PLAN *, FTSENT *))-1));
   1794  1.64.16.2  daniel }
   1795  1.64.16.2  daniel 
   1796  1.64.16.2  daniel PLAN *
   1797  1.64.16.2  daniel c_closeparen(char ***argvp, int isok)
   1798  1.64.16.2  daniel {
   1799  1.64.16.2  daniel 
   1800  1.64.16.2  daniel 	return (palloc(N_CLOSEPAREN, (int (*)(PLAN *, FTSENT *))-1));
   1801  1.64.16.2  daniel }
   1802  1.64.16.2  daniel 
   1803  1.64.16.2  daniel /*
   1804  1.64.16.2  daniel  * ! expression functions --
   1805  1.64.16.2  daniel  *
   1806  1.64.16.2  daniel  *	Negation of a primary; the unary NOT operator.
   1807  1.64.16.2  daniel  */
   1808  1.64.16.2  daniel int
   1809  1.64.16.2  daniel f_not(PLAN *plan, FTSENT *entry)
   1810  1.64.16.2  daniel {
   1811  1.64.16.2  daniel 	PLAN *p;
   1812  1.64.16.2  daniel 	int state;
   1813  1.64.16.2  daniel 
   1814  1.64.16.2  daniel 	state = 0;
   1815  1.64.16.2  daniel 	for (p = plan->p_data[0];
   1816  1.64.16.2  daniel 	    p && (state = (p->eval)(p, entry)); p = p->next);
   1817  1.64.16.2  daniel 	return (!state);
   1818  1.64.16.2  daniel }
   1819  1.64.16.2  daniel 
   1820  1.64.16.2  daniel PLAN *
   1821  1.64.16.2  daniel c_not(char ***argvp, int isok)
   1822  1.64.16.2  daniel {
   1823  1.64.16.2  daniel 
   1824  1.64.16.2  daniel 	return (palloc(N_NOT, f_not));
   1825  1.64.16.2  daniel }
   1826  1.64.16.2  daniel 
   1827  1.64.16.2  daniel /*
   1828  1.64.16.2  daniel  * expression -o expression functions --
   1829  1.64.16.2  daniel  *
   1830  1.64.16.2  daniel  *	Alternation of primaries; the OR operator.  The second expression is
   1831  1.64.16.2  daniel  * not evaluated if the first expression is true.
   1832  1.64.16.2  daniel  */
   1833  1.64.16.2  daniel int
   1834  1.64.16.2  daniel f_or(PLAN *plan, FTSENT *entry)
   1835  1.64.16.2  daniel {
   1836  1.64.16.2  daniel 	PLAN *p;
   1837  1.64.16.2  daniel 	int state;
   1838  1.64.16.2  daniel 
   1839  1.64.16.2  daniel 	state = 0;
   1840  1.64.16.2  daniel 	for (p = plan->p_data[0];
   1841  1.64.16.2  daniel 	    p && (state = (p->eval)(p, entry)); p = p->next);
   1842  1.64.16.2  daniel 
   1843  1.64.16.2  daniel 	if (state)
   1844  1.64.16.2  daniel 		return (1);
   1845  1.64.16.2  daniel 
   1846  1.64.16.2  daniel 	for (p = plan->p_data[1];
   1847  1.64.16.2  daniel 	    p && (state = (p->eval)(p, entry)); p = p->next);
   1848  1.64.16.2  daniel 	return (state);
   1849  1.64.16.2  daniel }
   1850  1.64.16.2  daniel 
   1851  1.64.16.2  daniel PLAN *
   1852  1.64.16.2  daniel c_or(char ***argvp, int isok)
   1853  1.64.16.2  daniel {
   1854  1.64.16.2  daniel 
   1855  1.64.16.2  daniel 	return (palloc(N_OR, f_or));
   1856  1.64.16.2  daniel }
   1857  1.64.16.2  daniel 
   1858  1.64.16.2  daniel PLAN *
   1859  1.64.16.2  daniel c_null(char ***argvp, int isok)
   1860  1.64.16.2  daniel {
   1861  1.64.16.2  daniel 
   1862  1.64.16.2  daniel 	return (NULL);
   1863  1.64.16.2  daniel }
   1864  1.64.16.2  daniel 
   1865  1.64.16.2  daniel 
   1866  1.64.16.2  daniel /*
   1867  1.64.16.2  daniel  * plan_cleanup --
   1868  1.64.16.2  daniel  *	Check and see if the specified plan has any residual state,
   1869  1.64.16.2  daniel  *	and if so, clean it up as appropriate.
   1870  1.64.16.2  daniel  *
   1871  1.64.16.2  daniel  *	At the moment, only N_EXEC has state. Two kinds: 1)
   1872  1.64.16.2  daniel  * 	lists of files to feed to subprocesses 2) State on exit
   1873  1.64.16.2  daniel  *	statusses of past subprocesses.
   1874  1.64.16.2  daniel  */
   1875  1.64.16.2  daniel /* ARGSUSED1 */
   1876  1.64.16.2  daniel int
   1877  1.64.16.2  daniel plan_cleanup(PLAN *plan, void *arg)
   1878  1.64.16.2  daniel {
   1879  1.64.16.2  daniel 	if (plan->type==N_EXEC && plan->ep_narg)
   1880  1.64.16.2  daniel 		run_f_exec(plan);
   1881  1.64.16.2  daniel 
   1882  1.64.16.2  daniel 	return plan->ep_rval;		/* Passed save exit-status up chain */
   1883  1.64.16.2  daniel }
   1884  1.64.16.2  daniel 
   1885  1.64.16.2  daniel static PLAN *
   1886  1.64.16.2  daniel palloc(enum ntype t, int (*f)(PLAN *, FTSENT *))
   1887  1.64.16.2  daniel {
   1888  1.64.16.2  daniel 	PLAN *new;
   1889  1.64.16.2  daniel 
   1890  1.64.16.2  daniel 	if ((new = malloc(sizeof(PLAN))) == NULL)
   1891  1.64.16.2  daniel 		err(1, NULL);
   1892  1.64.16.2  daniel 	memset(new, 0, sizeof(PLAN));
   1893  1.64.16.2  daniel 	new->type = t;
   1894  1.64.16.2  daniel 	new->eval = f;
   1895  1.64.16.2  daniel 	return (new);
   1896  1.64.16.2  daniel }
   1897