This is parser.c in view mode; [Download] [Up]
/* parser.c -- convert the command line args into an expression tree. Copyright (C) 1987, 1990, 1991 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include <ctype.h> #include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <pwd.h> #include <grp.h> #ifndef isascii #define isascii(c) 1 #endif #define ISDIGIT(c) (isascii (c) && isdigit (c)) #define ISUPPER(c) (isascii (c) && isupper (c)) #ifdef HAVE_UNISTD_H #include <unistd.h> #endif #ifndef _POSIX_VERSION /* POSIX.1 header files should declare these. */ struct group *getgrnam (); struct passwd *getpwnam (); #endif #ifdef CACHE_IDS /* These two aren't specified by POSIX.1. */ struct group *getgrent (); struct passwd *getpwent (); #endif #include "modechange.h" #include "defs.h" #include "modetype.h" #ifndef S_IFLNK #define lstat stat #endif char *strstr (); int lstat (); int stat (); #ifndef atol /* for Linux */ long atol (); #endif struct tm *localtime (); #ifdef _POSIX_SOURCE #define endgrent() #define endpwent() #else void endgrent (); void endpwent (); #endif static boolean parse_amin (); static boolean parse_and (); static boolean parse_anewer (); static boolean parse_atime (); boolean parse_close (); static boolean parse_cmin (); static boolean parse_cnewer (); static boolean parse_comma (); static boolean parse_ctime (); static boolean parse_daystart (); static boolean parse_depth (); static boolean parse_empty (); static boolean parse_exec (); static boolean parse_false (); static boolean parse_follow (); static boolean parse_fprint (); static boolean parse_fprint0 (); static boolean parse_fprintf (); static boolean parse_fstype (); static boolean parse_gid (); static boolean parse_group (); static boolean parse_ilname (); static boolean parse_iname (); static boolean parse_inum (); static boolean parse_ipath (); static boolean parse_iregex (); static boolean parse_links (); static boolean parse_lname (); static boolean parse_ls (); static boolean parse_maxdepth (); static boolean parse_mindepth (); static boolean parse_mmin (); static boolean parse_mtime (); static boolean parse_name (); static boolean parse_negate (); static boolean parse_newer (); static boolean parse_noleaf (); static boolean parse_nogroup (); static boolean parse_nouser (); static boolean parse_ok (); boolean parse_open (); static boolean parse_or (); static boolean parse_path (); static boolean parse_perm (); boolean parse_print (); static boolean parse_print0 (); static boolean parse_printf (); static boolean parse_prune (); static boolean parse_regex (); static boolean parse_size (); static boolean parse_true (); static boolean parse_type (); static boolean parse_uid (); static boolean parse_used (); static boolean parse_user (); static boolean parse_version (); static boolean parse_xdev (); static boolean parse_xtype (); boolean pred_amin (); boolean pred_and (); boolean pred_anewer (); boolean pred_atime (); boolean pred_close (); boolean pred_cmin (); boolean pred_cnewer (); boolean pred_comma (); boolean pred_ctime (); /* no pred_daystart */ /* no pred_depth */ boolean pred_empty (); boolean pred_exec (); boolean pred_false (); /* no pred_follow */ boolean pred_fprint (); boolean pred_fprint0 (); boolean pred_fprintf (); boolean pred_fstype (); boolean pred_gid (); boolean pred_group (); boolean pred_ilname (); boolean pred_iname (); boolean pred_inum (); boolean pred_ipath (); /* no pred_iregex */ boolean pred_links (); boolean pred_lname (); boolean pred_ls (); /* no pred_maxdepth */ /* no pred_mindepth */ boolean pred_mmin (); boolean pred_mtime (); boolean pred_name (); boolean pred_negate (); boolean pred_newer (); /* no pred_noleaf */ boolean pred_nogroup (); boolean pred_nouser (); boolean pred_ok (); boolean pred_open (); boolean pred_or (); boolean pred_path (); boolean pred_perm (); boolean pred_print (); boolean pred_print0 (); /* no pred_printf */ boolean pred_prune (); boolean pred_regex (); boolean pred_size (); boolean pred_true (); boolean pred_type (); boolean pred_uid (); boolean pred_used (); boolean pred_user (); /* no pred_version */ /* no pred_xdev */ boolean pred_xtype (); static boolean get_num (); static boolean get_num_days (); static boolean insert_exec_ok (); static boolean insert_fprintf (); static boolean insert_num (); static boolean insert_regex (); static boolean insert_time (); static boolean insert_type (); static FILE *open_output_file (); static struct segment **make_segment (); #ifdef DEBUG char *find_pred_name (); #endif /* DEBUG */ struct parser_table_t { char *parser_name; PFB parser_func; }; /* GNU find predicates that are not mentioned in POSIX.2 are marked `GNU'. If they are in some Unix versions of find, they are marked `Unix'. */ static struct parser_table_t const parse_table[] = { {"!", parse_negate}, {"not", parse_negate}, /* GNU */ {"(", parse_open}, {")", parse_close}, {",", parse_comma}, /* GNU */ {"a", parse_and}, {"amin", parse_amin}, /* GNU */ {"and", parse_and}, /* GNU */ {"anewer", parse_anewer}, /* GNU */ {"atime", parse_atime}, {"cmin", parse_cmin}, /* GNU */ {"cnewer", parse_cnewer}, /* GNU */ #ifdef UNIMPLEMENTED_UNIX /* It's pretty ugly for find to know about archive formats. Plus what it could do with cpio archives is very limited. Better to leave it out. */ {"cpio", parse_cpio}, /* Unix */ #endif {"ctime", parse_ctime}, {"daystart", parse_daystart}, /* GNU */ {"depth", parse_depth}, {"empty", parse_empty}, /* GNU */ {"exec", parse_exec}, {"false", parse_false}, /* GNU */ {"follow", parse_follow}, /* GNU, Unix */ {"fprint", parse_fprint}, /* GNU */ {"fprint0", parse_fprint0}, /* GNU */ {"fprintf", parse_fprintf}, /* GNU */ {"fstype", parse_fstype}, /* GNU, Unix */ {"gid", parse_gid}, /* GNU */ {"group", parse_group}, {"ilname", parse_ilname}, /* GNU */ {"iname", parse_iname}, /* GNU */ {"inum", parse_inum}, /* GNU, Unix */ {"ipath", parse_ipath}, /* GNU */ {"iregex", parse_iregex}, /* GNU */ {"links", parse_links}, {"lname", parse_lname}, /* GNU */ {"ls", parse_ls}, /* GNU, Unix */ {"maxdepth", parse_maxdepth}, /* GNU */ {"mindepth", parse_mindepth}, /* GNU */ {"mmin", parse_mmin}, /* GNU */ {"mtime", parse_mtime}, {"name", parse_name}, #ifdef UNIMPLEMENTED_UNIX {"ncpio", parse_ncpio}, /* Unix */ #endif {"newer", parse_newer}, {"noleaf", parse_noleaf}, /* GNU */ {"nogroup", parse_nogroup}, {"nouser", parse_nouser}, {"o", parse_or}, {"or", parse_or}, /* GNU */ {"ok", parse_ok}, {"path", parse_path}, /* GNU, HP-UX */ {"perm", parse_perm}, {"print", parse_print}, {"print0", parse_print0}, /* GNU */ {"printf", parse_printf}, /* GNU */ {"prune", parse_prune}, {"regex", parse_regex}, /* GNU */ {"size", parse_size}, {"true", parse_true}, /* GNU */ {"type", parse_type}, {"uid", parse_uid}, /* GNU */ {"used", parse_used}, /* GNU */ {"user", parse_user}, {"version", parse_version}, /* GNU */ {"xdev", parse_xdev}, {"xtype", parse_xtype}, /* GNU */ {0, 0} }; /* Return a pointer to the parser function to invoke for predicate SEARCH_NAME. Return NULL if SEARCH_NAME is not a valid predicate name. */ PFB find_parser (search_name) char *search_name; { int i; if (*search_name == '-') search_name++; for (i = 0; parse_table[i].parser_name != 0; i++) if (strcmp (parse_table[i].parser_name, search_name) == 0) return (parse_table[i].parser_func); return (NULL); } /* The parsers are responsible to continue scanning ARGV for their arguments. Each parser knows what is and isn't allowed for itself. ARGV is the argument array. *ARG_PTR is the index to start at in ARGV, updated to point beyond the last element consumed. The predicate structure is updated with the new information. */ static boolean parse_amin (argv, arg_ptr) char *argv[]; int *arg_ptr; { struct predicate *our_pred; unsigned long num; enum comparison_type c_type; if ((argv == NULL) || (argv[*arg_ptr] == NULL)) return (false); if (!get_num_days (argv[*arg_ptr], &num, &c_type)) return (false); our_pred = insert_victim (pred_amin); our_pred->args.info.kind = c_type; our_pred->args.info.l_val = cur_day_start + DAYSECS - num * 60; (*arg_ptr)++; return (true); } static boolean parse_and (argv, arg_ptr) char *argv[]; int *arg_ptr; { struct predicate *our_pred; our_pred = get_new_pred (); our_pred->pred_func = pred_and; #ifdef DEBUG our_pred->p_name = find_pred_name (pred_and); #endif /* DEBUG */ our_pred->p_type = BI_OP; our_pred->p_prec = AND_PREC; our_pred->need_stat = false; return (true); } static boolean parse_anewer (argv, arg_ptr) char *argv[]; int *arg_ptr; { struct predicate *our_pred; struct stat stat_newer; if ((argv == NULL) || (argv[*arg_ptr] == NULL)) return (false); if ((*xstat) (argv[*arg_ptr], &stat_newer)) error (1, errno, "%s", argv[*arg_ptr]); our_pred = insert_victim (pred_anewer); our_pred->args.time = stat_newer.st_mtime; (*arg_ptr)++; return (true); } static boolean parse_atime (argv, arg_ptr) char *argv[]; int *arg_ptr; { return (insert_time (argv, arg_ptr, pred_atime)); } boolean parse_close (argv, arg_ptr) char *argv[]; int *arg_ptr; { struct predicate *our_pred; our_pred = get_new_pred (); our_pred->pred_func = pred_close; #ifdef DEBUG our_pred->p_name = find_pred_name (pred_close); #endif /* DEBUG */ our_pred->p_type = CLOSE_PAREN; our_pred->p_prec = NO_PREC; our_pred->need_stat = false; return (true); } static boolean parse_cmin (argv, arg_ptr) char *argv[]; int *arg_ptr; { struct predicate *our_pred; unsigned long num; enum comparison_type c_type; if ((argv == NULL) || (argv[*arg_ptr] == NULL)) return (false); if (!get_num_days (argv[*arg_ptr], &num, &c_type)) return (false); our_pred = insert_victim (pred_cmin); our_pred->args.info.kind = c_type; our_pred->args.info.l_val = cur_day_start + DAYSECS - num * 60; (*arg_ptr)++; return (true); } static boolean parse_cnewer (argv, arg_ptr) char *argv[]; int *arg_ptr; { struct predicate *our_pred; struct stat stat_newer; if ((argv == NULL) || (argv[*arg_ptr] == NULL)) return (false); if ((*xstat) (argv[*arg_ptr], &stat_newer)) error (1, errno, "%s", argv[*arg_ptr]); our_pred = insert_victim (pred_cnewer); our_pred->args.time = stat_newer.st_mtime; (*arg_ptr)++; return (true); } static boolean parse_comma (argv, arg_ptr) char *argv[]; int *arg_ptr; { struct predicate *our_pred; our_pred = get_new_pred (); our_pred->pred_func = pred_comma; #ifdef DEBUG our_pred->p_name = find_pred_name (pred_comma); #endif /* DEBUG */ our_pred->p_type = BI_OP; our_pred->p_prec = COMMA_PREC; our_pred->need_stat = false; return (true); } static boolean parse_ctime (argv, arg_ptr) char *argv[]; int *arg_ptr; { return (insert_time (argv, arg_ptr, pred_ctime)); } static boolean parse_daystart (argv, arg_ptr) char *argv[]; int *arg_ptr; { struct tm *local; if (full_days == false) { cur_day_start += DAYSECS; local = localtime (&cur_day_start); cur_day_start -= local->tm_sec + local->tm_min * 60 + local->tm_hour * 3600; full_days = true; } return (true); } static boolean parse_depth (argv, arg_ptr) char *argv[]; int *arg_ptr; { do_dir_first = false; return (true); } static boolean parse_empty (argv, arg_ptr) char *argv[]; int *arg_ptr; { insert_victim (pred_empty); return (true); } static boolean parse_exec (argv, arg_ptr) char *argv[]; int *arg_ptr; { return (insert_exec_ok (pred_exec, argv, arg_ptr)); } static boolean parse_false (argv, arg_ptr) char *argv[]; int *arg_ptr; { struct predicate *our_pred; our_pred = insert_victim (pred_false); our_pred->need_stat = false; return (true); } static boolean parse_fprintf (argv, arg_ptr) char *argv[]; int *arg_ptr; { FILE *fp; if ((argv == NULL) || (argv[*arg_ptr] == NULL)) return (false); if (argv[*arg_ptr + 1] == NULL) { /* Ensure we get "missing arg" message, not "invalid arg". */ (*arg_ptr)++; return (false); } fp = open_output_file (argv[*arg_ptr]); (*arg_ptr)++; return (insert_fprintf (fp, pred_fprintf, argv, arg_ptr)); } static boolean parse_follow (argv, arg_ptr) char *argv[]; int *arg_ptr; { xstat = stat; no_leaf_check = true; return (true); } static boolean parse_fprint (argv, arg_ptr) char *argv[]; int *arg_ptr; { struct predicate *our_pred; if ((argv == NULL) || (argv[*arg_ptr] == NULL)) return (false); our_pred = insert_victim (pred_fprint); our_pred->args.stream = open_output_file (argv[*arg_ptr]); our_pred->side_effects = true; our_pred->need_stat = false; (*arg_ptr)++; return (true); } static boolean parse_fprint0 (argv, arg_ptr) char *argv[]; int *arg_ptr; { struct predicate *our_pred; if ((argv == NULL) || (argv[*arg_ptr] == NULL)) return (false); our_pred = insert_victim (pred_fprint0); our_pred->args.stream = open_output_file (argv[*arg_ptr]); our_pred->side_effects = true; our_pred->need_stat = false; (*arg_ptr)++; return (true); } static boolean parse_fstype (argv, arg_ptr) char *argv[]; int *arg_ptr; { struct predicate *our_pred; if ((argv == NULL) || (argv[*arg_ptr] == NULL)) return (false); our_pred = insert_victim (pred_fstype); our_pred->args.str = argv[*arg_ptr]; (*arg_ptr)++; return (true); } static boolean parse_gid (argv, arg_ptr) char *argv[]; int *arg_ptr; { return (insert_num (argv, arg_ptr, pred_gid)); } static boolean parse_group (argv, arg_ptr) char *argv[]; int *arg_ptr; { struct group *cur_gr; struct predicate *our_pred; int gid, gid_len; if ((argv == NULL) || (argv[*arg_ptr] == NULL)) return (false); cur_gr = getgrnam (argv[*arg_ptr]); endgrent (); if (cur_gr != NULL) gid = cur_gr->gr_gid; else { gid_len = strspn (argv[*arg_ptr], "0123456789"); if ((gid_len == 0) || (argv[*arg_ptr][gid_len] != '\0')) return (false); gid = atoi (argv[*arg_ptr]); } our_pred = insert_victim (pred_group); our_pred->args.gid = (short) gid; (*arg_ptr)++; return (true); } static boolean parse_ilname (argv, arg_ptr) char *argv[]; int *arg_ptr; { struct predicate *our_pred; if ((argv == NULL) || (argv[*arg_ptr] == NULL)) return (false); our_pred = insert_victim (pred_ilname); our_pred->args.str = argv[*arg_ptr]; (*arg_ptr)++; return (true); } static boolean parse_iname (argv, arg_ptr) char *argv[]; int *arg_ptr; { struct predicate *our_pred; if ((argv == NULL) || (argv[*arg_ptr] == NULL)) return (false); our_pred = insert_victim (pred_iname); our_pred->need_stat = false; our_pred->args.str = argv[*arg_ptr]; (*arg_ptr)++; return (true); } static boolean parse_inum (argv, arg_ptr) char *argv[]; int *arg_ptr; { return (insert_num (argv, arg_ptr, pred_inum)); } static boolean parse_ipath (argv, arg_ptr) char *argv[]; int *arg_ptr; { struct predicate *our_pred; if ((argv == NULL) || (argv[*arg_ptr] == NULL)) return (false); our_pred = insert_victim (pred_ipath); our_pred->need_stat = false; our_pred->args.str = argv[*arg_ptr]; (*arg_ptr)++; return (true); } static boolean parse_iregex (argv, arg_ptr) char *argv[]; int *arg_ptr; { return insert_regex (argv, arg_ptr, true); } static boolean parse_links (argv, arg_ptr) char *argv[]; int *arg_ptr; { return (insert_num (argv, arg_ptr, pred_links)); } static boolean parse_lname (argv, arg_ptr) char *argv[]; int *arg_ptr; { struct predicate *our_pred; if ((argv == NULL) || (argv[*arg_ptr] == NULL)) return (false); our_pred = insert_victim (pred_lname); our_pred->args.str = argv[*arg_ptr]; (*arg_ptr)++; return (true); } static boolean parse_ls (argv, arg_ptr) char *argv[]; int *arg_ptr; { struct predicate *our_pred; our_pred = insert_victim (pred_ls); our_pred->side_effects = true; return (true); } static boolean parse_maxdepth (argv, arg_ptr) char *argv[]; int *arg_ptr; { int depth_len; if ((argv == NULL) || (argv[*arg_ptr] == NULL)) return (false); depth_len = strspn (argv[*arg_ptr], "0123456789"); if ((depth_len == 0) || (argv[*arg_ptr][depth_len] != '\0')) return (false); maxdepth = atoi (argv[*arg_ptr]); if (maxdepth < 0) return (false); (*arg_ptr)++; return (true); } static boolean parse_mindepth (argv, arg_ptr) char *argv[]; int *arg_ptr; { int depth_len; if ((argv == NULL) || (argv[*arg_ptr] == NULL)) return (false); depth_len = strspn (argv[*arg_ptr], "0123456789"); if ((depth_len == 0) || (argv[*arg_ptr][depth_len] != '\0')) return (false); mindepth = atoi (argv[*arg_ptr]); if (mindepth < 0) return (false); (*arg_ptr)++; return (true); } static boolean parse_mmin (argv, arg_ptr) char *argv[]; int *arg_ptr; { struct predicate *our_pred; unsigned long num; enum comparison_type c_type; if ((argv == NULL) || (argv[*arg_ptr] == NULL)) return (false); if (!get_num_days (argv[*arg_ptr], &num, &c_type)) return (false); our_pred = insert_victim (pred_mmin); our_pred->args.info.kind = c_type; our_pred->args.info.l_val = cur_day_start + DAYSECS - num * 60; (*arg_ptr)++; return (true); } static boolean parse_mtime (argv, arg_ptr) char *argv[]; int *arg_ptr; { return (insert_time (argv, arg_ptr, pred_mtime)); } static boolean parse_name (argv, arg_ptr) char *argv[]; int *arg_ptr; { struct predicate *our_pred; if ((argv == NULL) || (argv[*arg_ptr] == NULL)) return (false); our_pred = insert_victim (pred_name); our_pred->need_stat = false; our_pred->args.str = argv[*arg_ptr]; (*arg_ptr)++; return (true); } static boolean parse_negate (argv, arg_ptr) char *argv[]; int *arg_ptr; { struct predicate *our_pred; our_pred = get_new_pred_chk_op (); our_pred->pred_func = pred_negate; #ifdef DEBUG our_pred->p_name = find_pred_name (pred_negate); #endif /* DEBUG */ our_pred->p_type = UNI_OP; our_pred->p_prec = NEGATE_PREC; our_pred->need_stat = false; return (true); } static boolean parse_newer (argv, arg_ptr) char *argv[]; int *arg_ptr; { struct predicate *our_pred; struct stat stat_newer; if ((argv == NULL) || (argv[*arg_ptr] == NULL)) return (false); if ((*xstat) (argv[*arg_ptr], &stat_newer)) error (1, errno, "%s", argv[*arg_ptr]); our_pred = insert_victim (pred_newer); our_pred->args.time = stat_newer.st_mtime; (*arg_ptr)++; return (true); } static boolean parse_noleaf (argv, arg_ptr) char *argv[]; int *arg_ptr; { no_leaf_check = true; return true; } #ifdef CACHE_IDS /* Arbitrary amount by which to increase size of `uid_unused' and `gid_unused'. */ #define ALLOC_STEP 2048 /* Boolean: if uid_unused[n] is nonzero, then UID n has no passwd entry. */ char *uid_unused = NULL; /* Number of elements in `uid_unused'. */ unsigned uid_allocated; /* Similar for GIDs and group entries. */ char *gid_unused = NULL; unsigned gid_allocated; #endif static boolean parse_nogroup (argv, arg_ptr) char *argv[]; int *arg_ptr; { struct predicate *our_pred; our_pred = insert_victim (pred_nogroup); #ifdef CACHE_IDS if (gid_unused == NULL) { struct group *gr; gid_allocated = ALLOC_STEP; gid_unused = xmalloc (gid_allocated); memset (gid_unused, 1, gid_allocated); setgrent (); while ((gr = getgrent ()) != NULL) { if ((unsigned) gr->gr_gid >= gid_allocated) { unsigned new_allocated = gr->gr_gid + ALLOC_STEP; gid_unused = xrealloc (gid_unused, new_allocated); memset (gid_unused + gid_allocated, 1, new_allocated - gid_allocated); gid_allocated = new_allocated; } gid_unused[(unsigned) gr->gr_gid] = 0; } endgrent (); } #endif return (true); } static boolean parse_nouser (argv, arg_ptr) char *argv[]; int *arg_ptr; { struct predicate *our_pred; our_pred = insert_victim (pred_nouser); #ifdef CACHE_IDS if (uid_unused == NULL) { struct passwd *pw; uid_allocated = ALLOC_STEP; uid_unused = xmalloc (uid_allocated); memset (uid_unused, 1, uid_allocated); setpwent (); while ((pw = getpwent ()) != NULL) { if ((unsigned) pw->pw_uid >= uid_allocated) { unsigned new_allocated = pw->pw_uid + ALLOC_STEP; uid_unused = xrealloc (uid_unused, new_allocated); memset (uid_unused + uid_allocated, 1, new_allocated - uid_allocated); uid_allocated = new_allocated; } uid_unused[(unsigned) pw->pw_uid] = 0; } endpwent (); } #endif return (true); } static boolean parse_ok (argv, arg_ptr) char *argv[]; int *arg_ptr; { return (insert_exec_ok (pred_ok, argv, arg_ptr)); } boolean parse_open (argv, arg_ptr) char *argv[]; int *arg_ptr; { struct predicate *our_pred; our_pred = get_new_pred_chk_op (); our_pred->pred_func = pred_open; #ifdef DEBUG our_pred->p_name = find_pred_name (pred_open); #endif /* DEBUG */ our_pred->p_type = OPEN_PAREN; our_pred->p_prec = NO_PREC; our_pred->need_stat = false; return (true); } static boolean parse_or (argv, arg_ptr) char *argv[]; int *arg_ptr; { struct predicate *our_pred; our_pred = get_new_pred (); our_pred->pred_func = pred_or; #ifdef DEBUG our_pred->p_name = find_pred_name (pred_or); #endif /* DEBUG */ our_pred->p_type = BI_OP; our_pred->p_prec = OR_PREC; our_pred->need_stat = false; return (true); } static boolean parse_path (argv, arg_ptr) char *argv[]; int *arg_ptr; { struct predicate *our_pred; if ((argv == NULL) || (argv[*arg_ptr] == NULL)) return (false); our_pred = insert_victim (pred_path); our_pred->need_stat = false; our_pred->args.str = argv[*arg_ptr]; (*arg_ptr)++; return (true); } static boolean parse_perm (argv, arg_ptr) char *argv[]; int *arg_ptr; { unsigned long perm_val; int mode_start = 0; struct mode_change *change; struct predicate *our_pred; if ((argv == NULL) || (argv[*arg_ptr] == NULL)) return (false); switch (argv[*arg_ptr][0]) { case '-': case '+': mode_start = 1; break; default: /* empty */ break; } change = mode_compile (argv[*arg_ptr] + mode_start, MODE_MASK_PLUS); if (change == MODE_INVALID) error (1, 0, "invalid mode `%s'", argv[*arg_ptr]); else if (change == MODE_MEMORY_EXHAUSTED) error (1, 0, "virtual memory exhausted"); perm_val = mode_adjust (0, change); mode_free (change); our_pred = insert_victim (pred_perm); switch (argv[*arg_ptr][0]) { case '-': /* Set magic flag to indicate true if at least the given bits are set. */ our_pred->args.perm = (perm_val & 07777) | 010000; break; case '+': /* Set magic flag to indicate true if any of the given bits are set. */ our_pred->args.perm = (perm_val & 07777) | 020000; break; default: /* True if exactly the given bits are set. */ our_pred->args.perm = (perm_val & 07777); break; } (*arg_ptr)++; return (true); } boolean parse_print (argv, arg_ptr) char *argv[]; int *arg_ptr; { struct predicate *our_pred; our_pred = insert_victim (pred_print); /* -print has the side effect of printing. This prevents us from doing undesired multiple printing when the user has already specified -print. */ our_pred->side_effects = true; our_pred->need_stat = false; return (true); } static boolean parse_print0 (argv, arg_ptr) char *argv[]; int *arg_ptr; { struct predicate *our_pred; our_pred = insert_victim (pred_print0); /* -print0 has the side effect of printing. This prevents us from doing undesired multiple printing when the user has already specified -print0. */ our_pred->side_effects = true; our_pred->need_stat = false; return (true); } static boolean parse_printf (argv, arg_ptr) char *argv[]; int *arg_ptr; { if ((argv == NULL) || (argv[*arg_ptr] == NULL)) return (false); return (insert_fprintf (stdout, pred_fprintf, argv, arg_ptr)); } static boolean parse_prune (argv, arg_ptr) char *argv[]; int *arg_ptr; { struct predicate *our_pred; our_pred = insert_victim (pred_prune); our_pred->need_stat = false; return (true); } static boolean parse_regex (argv, arg_ptr) char *argv[]; int *arg_ptr; { return insert_regex (argv, arg_ptr, false); } static boolean insert_regex (argv, arg_ptr, ignore_case) char *argv[]; int *arg_ptr; boolean ignore_case; { struct predicate *our_pred; struct re_pattern_buffer *re; const char *error_message; if ((argv == NULL) || (argv[*arg_ptr] == NULL)) return (false); our_pred = insert_victim (pred_regex); our_pred->need_stat = false; re = (struct re_pattern_buffer *) xmalloc (sizeof (struct re_pattern_buffer)); our_pred->args.regex = re; re->allocated = 100; re->buffer = (unsigned char *) xmalloc (re->allocated); re->fastmap = NULL; if (ignore_case) { unsigned i; re->translate = xmalloc (256); /* Map uppercase characters to corresponding lowercase ones. */ for (i = 0; i < 256; i++) re->translate[i] = ISUPPER (i) ? tolower (i) : i; } else re->translate = NULL; error_message = re_compile_pattern (argv[*arg_ptr], strlen (argv[*arg_ptr]), re); if (error_message) error (1, 0, "%s", error_message); (*arg_ptr)++; return (true); } static boolean parse_size (argv, arg_ptr) char *argv[]; int *arg_ptr; { struct predicate *our_pred; unsigned long num; enum comparison_type c_type; int blksize = 512; int len; if ((argv == NULL) || (argv[*arg_ptr] == NULL)) return (false); len = strlen (argv[*arg_ptr]); if (len == 0) error (1, 0, "invalid null argument to -size"); switch (argv[*arg_ptr][len - 1]) { case 'c': blksize = 1; argv[*arg_ptr][len - 1] = '\0'; break; case 'k': blksize = 1024; argv[*arg_ptr][len - 1] = '\0'; break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': break; default: error (1, 0, "invalid -size type `%c'", argv[*arg_ptr][len - 1]); } if (!get_num (argv[*arg_ptr], &num, &c_type)) return (false); our_pred = insert_victim (pred_size); our_pred->args.size.kind = c_type; our_pred->args.size.blocksize = blksize; our_pred->args.size.size = num; (*arg_ptr)++; return (true); } static boolean parse_true (argv, arg_ptr) char *argv[]; int *arg_ptr; { struct predicate *our_pred; our_pred = insert_victim (pred_true); our_pred->need_stat = false; return (true); } static boolean parse_type (argv, arg_ptr) char *argv[]; int *arg_ptr; { return insert_type (argv, arg_ptr, pred_type); } static boolean parse_uid (argv, arg_ptr) char *argv[]; int *arg_ptr; { return (insert_num (argv, arg_ptr, pred_uid)); } static boolean parse_used (argv, arg_ptr) char *argv[]; int *arg_ptr; { struct predicate *our_pred; unsigned long num_days; enum comparison_type c_type; if ((argv == NULL) || (argv[*arg_ptr] == NULL)) return (false); if (!get_num (argv[*arg_ptr], &num_days, &c_type)) return (false); our_pred = insert_victim (pred_used); our_pred->args.info.kind = c_type; our_pred->args.info.l_val = num_days * DAYSECS; (*arg_ptr)++; return (true); } static boolean parse_user (argv, arg_ptr) char *argv[]; int *arg_ptr; { struct passwd *cur_pwd; struct predicate *our_pred; int uid, uid_len; if ((argv == NULL) || (argv[*arg_ptr] == NULL)) return (false); cur_pwd = getpwnam (argv[*arg_ptr]); endpwent (); if (cur_pwd != NULL) uid = cur_pwd->pw_uid; else { uid_len = strspn (argv[*arg_ptr], "0123456789"); if ((uid_len == 0) || (argv[*arg_ptr][uid_len] != '\0')) return (false); uid = atoi (argv[*arg_ptr]); } our_pred = insert_victim (pred_user); our_pred->args.uid = (short) uid; (*arg_ptr)++; return (true); } static boolean parse_version (argv, arg_ptr) char *argv[]; int *arg_ptr; { extern char *version_string; fflush (stdout); fprintf (stderr, "%s", version_string); fflush (stderr); return true; } static boolean parse_xdev (argv, arg_ptr) char *argv[]; int *arg_ptr; { stay_on_filesystem = true; return true; } static boolean parse_xtype (argv, arg_ptr) char *argv[]; int *arg_ptr; { return insert_type (argv, arg_ptr, pred_xtype); } static boolean insert_type (argv, arg_ptr, which_pred) char *argv[]; int *arg_ptr; boolean (*which_pred) (); { unsigned long type_cell; struct predicate *our_pred; if ((argv == NULL) || (argv[*arg_ptr] == NULL) || (strlen (argv[*arg_ptr]) != 1)) return (false); switch (argv[*arg_ptr][0]) { case 'b': /* block special */ type_cell = S_IFBLK; break; case 'c': /* character special */ type_cell = S_IFCHR; break; case 'd': /* directory */ type_cell = S_IFDIR; break; case 'f': /* regular file */ type_cell = S_IFREG; break; #ifdef S_IFLNK case 'l': /* symbolic link */ type_cell = S_IFLNK; break; #endif #ifdef S_IFIFO case 'p': /* pipe */ type_cell = S_IFIFO; break; #endif #ifdef S_IFSOCK case 's': /* socket */ type_cell = S_IFSOCK; break; #endif default: /* None of the above ... nuke 'em. */ return (false); } our_pred = insert_victim (which_pred); our_pred->args.type = type_cell; (*arg_ptr)++; /* Move on to next argument. */ return (true); } /* If true, we've determined that the current fprintf predicate uses stat information. */ static boolean fprintf_stat_needed; static boolean insert_fprintf (fp, func, argv, arg_ptr) FILE *fp; boolean (*func) (); char *argv[]; int *arg_ptr; { char *format; /* Beginning of unprocessed format string. */ register char *scan; /* Current address in scanning `format'. */ register char *scan2; /* Address inside of element being scanned. */ struct segment **segmentp; /* Address of current segment. */ struct predicate *our_pred; format = argv[(*arg_ptr)++]; fprintf_stat_needed = false; /* Might be overridden later. */ our_pred = insert_victim (func); our_pred->side_effects = true; our_pred->args.printf_vec.stream = fp; segmentp = &our_pred->args.printf_vec.segment; *segmentp = NULL; for (scan = format; *scan; scan++) { if (*scan == '\\') { scan2 = scan + 1; if (*scan2 >= '0' && *scan2 <= '7') { register int n, i; for (i = n = 0; i < 3 && (*scan2 >= '0' && *scan2 <= '7'); i++, scan2++) n = 8 * n + *scan2 - '0'; scan2--; *scan = n; } else { switch (*scan2) { case 'a': *scan = 7; break; case 'b': *scan = '\b'; break; case 'c': make_segment (segmentp, format, scan - format, KIND_STOP); return (true); case 'f': *scan = '\f'; break; case 'n': *scan = '\n'; break; case 'r': *scan = '\r'; break; case 't': *scan = '\t'; break; case 'v': *scan = '\v'; break; case '\\': /* *scan = '\\'; * it already is */ break; default: scan++; continue; } } segmentp = make_segment (segmentp, format, scan - format + 1, KIND_PLAIN); format = scan2 + 1; /* Move past the escape. */ scan = scan2; /* Incremented immediately by `for'. */ } else if (*scan == '%') { if (scan[1] == '%') { segmentp = make_segment (segmentp, format, scan - format + 1, KIND_PLAIN); scan++; format = scan + 1; continue; } /* Scan past flags, width and precision, to verify kind. */ for (scan2 = scan; *++scan2 && index ("-+ #", *scan2);) /* Do nothing. */ ; while (ISDIGIT (*scan2)) scan2++; if (*scan2 == '.') for (scan2++; ISDIGIT (*scan2); scan2++) /* Do nothing. */ ; if (index ("abcdfFgGhHiklmnpPstuU", *scan2)) { segmentp = make_segment (segmentp, format, scan2 - format, (int) *scan2); scan = scan2; format = scan + 1; } else if (index ("ACT", *scan2) && scan2[1]) { segmentp = make_segment (segmentp, format, scan2 - format, *scan2 | (scan2[1] << 8)); scan = scan2 + 1; format = scan + 1; continue; } else { /* An unrecognized % escape. Print the char after the %. */ segmentp = make_segment (segmentp, format, scan - format, KIND_PLAIN); format = scan + 1; continue; } } } if (scan > format) make_segment (segmentp, format, scan - format, KIND_PLAIN); our_pred->need_stat = fprintf_stat_needed; return (true); } /* Create a new fprintf segment in *SEGMENT, with type KIND, from the text in FORMAT, which has length LEN. Return the address of the `next' pointer of the new segment. */ static struct segment ** make_segment (segment, format, len, kind) struct segment **segment; char *format; int len, kind; { char *fmt; *segment = (struct segment *) xmalloc (sizeof (struct segment)); (*segment)->kind = kind; (*segment)->next = NULL; (*segment)->text_len = len; fmt = (*segment)->text = xmalloc (len + 3); /* room for "ld\0" */ strncpy (fmt, format, len); fmt += len; switch (kind & 0xff) { case KIND_PLAIN: /* Plain text string, no % conversion. */ case KIND_STOP: /* Terminate argument, no newline. */ break; case 'a': /* atime in `ctime' format */ case 'c': /* ctime in `ctime' format */ case 'F': /* filesystem type */ case 'g': /* group name */ case 'l': /* object of symlink */ case 't': /* mtime in `ctime' format */ case 'u': /* user name */ case 'A': /* atime in user-specified strftime format */ case 'C': /* ctime in user-specified strftime format */ case 'T': /* mtime in user-specified strftime format */ fprintf_stat_needed = true; /* FALLTHROUGH */ case 'f': /* basename of path */ case 'h': /* leading directories part of path */ case 'H': /* ARGV element file was found under */ case 'p': /* pathname */ case 'P': /* pathname with ARGV element stripped */ *fmt++ = 's'; break; case 'b': /* size in 512-byte blocks */ case 'k': /* size in 1K blocks */ case 's': /* size in bytes */ *fmt++ = 'l'; /*FALLTHROUGH*/ case 'n': /* number of links */ fprintf_stat_needed = true; /* FALLTHROUGH */ case 'd': /* depth in search tree (0 = ARGV element) */ *fmt++ = 'd'; break; case 'i': /* inode number */ *fmt++ = 'l'; /*FALLTHROUGH*/ case 'G': /* GID number */ case 'U': /* UID number */ *fmt++ = 'u'; fprintf_stat_needed = true; break; case 'm': /* mode as octal number (perms only) */ *fmt++ = 'o'; fprintf_stat_needed = true; break; } *fmt = '\0'; return (&(*segment)->next); } static boolean insert_exec_ok (func, argv, arg_ptr) boolean (*func) (); char *argv[]; int *arg_ptr; { int start, end; /* Indexes in ARGV of start & end of cmd. */ int num_paths; /* Number of args with path replacements. */ int path_pos; /* Index in array of path replacements. */ int vec_pos; /* Index in array of args. */ struct predicate *our_pred; struct exec_val *execp; /* Pointer for efficiency. */ if ((argv == NULL) || (argv[*arg_ptr] == NULL)) return (false); /* Count the number of args with path replacements, up until the ';'. */ start = *arg_ptr; for (end = start, num_paths = 0; (argv[end] != NULL) && ((argv[end][0] != ';') || (argv[end][1] != '\0')); end++) if (strstr (argv[end], "{}")) num_paths++; /* Fail if no command given or no semicolon found. */ if ((end == start) || (argv[end] == NULL)) { *arg_ptr = end; return (false); } our_pred = insert_victim (func); our_pred->side_effects = true; execp = &our_pred->args.exec_vec; execp->paths = (struct path_arg *) xmalloc (sizeof (struct path_arg) * (num_paths + 1)); execp->vec = (char **) xmalloc (sizeof (char *) * (end - start + 1)); /* Record the positions of all args, and the args with path replacements. */ for (end = start, path_pos = vec_pos = 0; (argv[end] != NULL) && ((argv[end][0] != ';') || (argv[end][1] != '\0')); end++) { register char *p; execp->paths[path_pos].count = 0; for (p = argv[end]; *p; ++p) if (p[0] == '{' && p[1] == '}') { execp->paths[path_pos].count++; ++p; } if (execp->paths[path_pos].count) { execp->paths[path_pos].offset = vec_pos; execp->paths[path_pos].origarg = argv[end]; path_pos++; } execp->vec[vec_pos++] = argv[end]; } execp->paths[path_pos].offset = -1; execp->vec[vec_pos] = NULL; if (argv[end] == NULL) *arg_ptr = end; else *arg_ptr = end + 1; return (true); } /* Get a number of days and comparison type. STR is the ASCII representation. Set *NUM_DAYS to the number of days, taken as being from the current moment (or possibly midnight). Thus the sense of the comparison type appears to be reversed. Set *COMP_TYPE to the kind of comparison that is requested. Return true if all okay, false if input error. Used by -atime, -ctime and -mtime (parsers) to get the appropriate information for a time predicate processor. */ static boolean get_num_days (str, num_days, comp_type) char *str; unsigned long *num_days; enum comparison_type *comp_type; { int len_days; /* length of field */ if (str == NULL) return (false); switch (str[0]) { case '+': *comp_type = COMP_LT; str++; break; case '-': *comp_type = COMP_GT; str++; break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': *comp_type = COMP_EQ; break; default: return (false); } /* We know the first char has been reasonable. Find the number of days to play with. */ len_days = strspn (str, "0123456789"); if ((len_days == 0) || (str[len_days] != '\0')) return (false); *num_days = (unsigned long) atol (str); return (true); } /* Insert a time predicate PRED. ARGV is a pointer to the argument array. ARG_PTR is a pointer to an index into the array, incremented if all went well. Return true if input is valid, false if not. A new predicate node is assigned, along with an argument node obtained with malloc. Used by -atime, -ctime, and -mtime parsers. */ static boolean insert_time (argv, arg_ptr, pred) char *argv[]; int *arg_ptr; PFB pred; { struct predicate *our_pred; unsigned long num_days; enum comparison_type c_type; if ((argv == NULL) || (argv[*arg_ptr] == NULL)) return (false); if (!get_num_days (argv[*arg_ptr], &num_days, &c_type)) return (false); our_pred = insert_victim (pred); our_pred->args.info.kind = c_type; our_pred->args.info.l_val = cur_day_start - num_days * DAYSECS + ((c_type == COMP_GT) ? DAYSECS - 1 : 0); (*arg_ptr)++; #ifdef DEBUG printf ("inserting %s\n", our_pred->p_name); printf (" type: %s %s ", (c_type == COMP_GT) ? "gt" : ((c_type == COMP_LT) ? "lt" : ((c_type == COMP_EQ) ? "eq" : "?")), (c_type == COMP_GT) ? " >" : ((c_type == COMP_LT) ? " <" : ((c_type == COMP_EQ) ? ">=" : " ?"))); printf ("%ld %s", our_pred->args.info.l_val, ctime (&our_pred->args.info.l_val)); if (c_type == COMP_EQ) { our_pred->args.info.l_val += DAYSECS; printf (" < %ld %s", our_pred->args.info.l_val, ctime (&our_pred->args.info.l_val)); our_pred->args.info.l_val -= DAYSECS; } #endif /* DEBUG */ return (true); } /* Get a number with comparision information. The sense of the comparision information is 'normal'; that is, '+' looks for inums or links > than the number and '-' less than. STR is the ASCII representation of the number. Set *NUM to the number. Set *COMP_TYPE to the kind of comparison that is requested. Return true if all okay, false if input error. Used by the -inum and -links predicate parsers. */ static boolean get_num (str, num, comp_type) char *str; unsigned long *num; enum comparison_type *comp_type; { int len_num; /* Length of field. */ if (str == NULL) return (false); switch (str[0]) { case '+': *comp_type = COMP_GT; str++; break; case '-': *comp_type = COMP_LT; str++; break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': *comp_type = COMP_EQ; break; default: return (false); } /* We know the first char has been reasonable. Find the number of days to play with. */ len_num = strspn (str, "0123456789"); if ((len_num == 0) || (str[len_num] != '\0')) return (false); *num = (unsigned long) atol (str); return (true); } /* Insert a number predicate. ARGV is a pointer to the argument array. *ARG_PTR is an index into ARGV, incremented if all went well. *PRED is the predicate processor to insert. Return true if input is valid, false if error. A new predicate node is assigned, along with an argument node obtained with malloc. Used by -inum and -links parsers. */ static boolean insert_num (argv, arg_ptr, pred) char *argv[]; int *arg_ptr; PFB pred; { struct predicate *our_pred; unsigned long num; enum comparison_type c_type; if ((argv == NULL) || (argv[*arg_ptr] == NULL)) return (false); if (!get_num (argv[*arg_ptr], &num, &c_type)) return (false); our_pred = insert_victim (pred); our_pred->args.info.kind = c_type; our_pred->args.info.l_val = num; (*arg_ptr)++; #ifdef DEBUG printf ("inserting %s\n", our_pred->p_name); printf (" type: %s %s ", (c_type == COMP_GT) ? "gt" : ((c_type == COMP_LT) ? "lt" : ((c_type == COMP_EQ) ? "eq" : "?")), (c_type == COMP_GT) ? " >" : ((c_type == COMP_LT) ? " <" : ((c_type == COMP_EQ) ? " =" : " ?"))); printf ("%ld\n", our_pred->args.info.l_val); #endif /* DEBUG */ return (true); } static FILE * open_output_file (path) char *path; { FILE *f; if (!strcmp (path, "/dev/stderr")) return (stderr); else if (!strcmp (path, "/dev/stdout")) return (stdout); f = fopen (path, "w"); if (f == NULL) error (1, errno, "%s", path); return (f); }
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.