1/* parser.c -- convert the command line args into an expression tree. 2 Copyright (C) 1990, 1991, 1992, 1993, 1994, 2000, 2001, 2003, 3 2004, 2005, 2007 Free Software Foundation, Inc. 4 5 This program is free software: you can redistribute it and/or modify 6 it under the terms of the GNU General Public License as published by 7 the Free Software Foundation, either version 3 of the License, or 8 (at your option) any later version. 9 10 This program is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 GNU General Public License for more details. 14 15 You should have received a copy of the GNU General Public License 16 along with this program. If not, see <http://www.gnu.org/licenses/>. 17*/ 18 19 20#include "defs.h" 21#include <ctype.h> 22#include <pwd.h> 23#include <grp.h> 24#include <fnmatch.h> 25#include "modechange.h" 26#include "modetype.h" 27#include "xstrtol.h" 28#include "xalloc.h" 29#include "quote.h" 30#include "quotearg.h" 31#include "buildcmd.h" 32#include "nextelem.h" 33#include "stdio-safer.h" 34#include "regextype.h" 35#include "gnulib-version.h" 36 37#ifdef HAVE_FCNTL_H 38#include <fcntl.h> 39#else 40#include <sys/file.h> 41#endif 42 43/* The presence of unistd.h is assumed by gnulib these days, so we 44 * might as well assume it too. 45 */ 46/* We need <unistd.h> for isatty(). */ 47#include <unistd.h> 48 49#if ENABLE_NLS 50# include <libintl.h> 51# define _(Text) gettext (Text) 52#else 53# define _(Text) Text 54#endif 55#ifdef gettext_noop 56# define N_(String) gettext_noop (String) 57#else 58/* See locate.c for explanation as to why not use (String) */ 59# define N_(String) String 60#endif 61 62#if !defined (isascii) || defined (STDC_HEADERS) 63#ifdef isascii 64#undef isascii 65#endif 66#define isascii(c) 1 67#endif 68 69#define ISDIGIT(c) (isascii ((unsigned char)c) && isdigit ((unsigned char)c)) 70#define ISUPPER(c) (isascii ((unsigned char)c) && isupper ((unsigned char)c)) 71 72#ifndef HAVE_ENDGRENT 73#define endgrent() 74#endif 75#ifndef HAVE_ENDPWENT 76#define endpwent() 77#endif 78 79static boolean parse_amin PARAMS((const struct parser_table*, char *argv[], int *arg_ptr)); 80static boolean parse_and PARAMS((const struct parser_table*, char *argv[], int *arg_ptr)); 81static boolean parse_anewer PARAMS((const struct parser_table*, char *argv[], int *arg_ptr)); 82static boolean parse_atime PARAMS((const struct parser_table*, char *argv[], int *arg_ptr)); 83static boolean parse_cmin PARAMS((const struct parser_table*, char *argv[], int *arg_ptr)); 84static boolean parse_cnewer PARAMS((const struct parser_table*, char *argv[], int *arg_ptr)); 85static boolean parse_comma PARAMS((const struct parser_table*, char *argv[], int *arg_ptr)); 86static boolean parse_ctime PARAMS((const struct parser_table*, char *argv[], int *arg_ptr)); 87static boolean parse_daystart PARAMS((const struct parser_table*, char *argv[], int *arg_ptr)); 88static boolean parse_delete PARAMS((const struct parser_table*, char *argv[], int *arg_ptr)); 89static boolean parse_d PARAMS((const struct parser_table*, char *argv[], int *arg_ptr)); 90static boolean parse_depth PARAMS((const struct parser_table*, char *argv[], int *arg_ptr)); 91static boolean parse_empty PARAMS((const struct parser_table*, char *argv[], int *arg_ptr)); 92static boolean parse_exec PARAMS((const struct parser_table*, char *argv[], int *arg_ptr)); 93static boolean parse_execdir PARAMS((const struct parser_table*, char *argv[], int *arg_ptr)); 94static boolean parse_false PARAMS((const struct parser_table*, char *argv[], int *arg_ptr)); 95static boolean parse_fls PARAMS((const struct parser_table*, char *argv[], int *arg_ptr)); 96static boolean parse_fprintf PARAMS((const struct parser_table*, char *argv[], int *arg_ptr)); 97static boolean parse_follow PARAMS((const struct parser_table*, char *argv[], int *arg_ptr)); 98static boolean parse_fprint PARAMS((const struct parser_table*, char *argv[], int *arg_ptr)); 99static boolean parse_fprint0 PARAMS((const struct parser_table*, char *argv[], int *arg_ptr)); 100static boolean parse_fstype PARAMS((const struct parser_table*, char *argv[], int *arg_ptr)); 101static boolean parse_gid PARAMS((const struct parser_table*, char *argv[], int *arg_ptr)); 102static boolean parse_group PARAMS((const struct parser_table*, char *argv[], int *arg_ptr)); 103static boolean parse_help PARAMS((const struct parser_table*, char *argv[], int *arg_ptr)); 104static boolean parse_ilname PARAMS((const struct parser_table*, char *argv[], int *arg_ptr)); 105static boolean parse_iname PARAMS((const struct parser_table*, char *argv[], int *arg_ptr)); 106static boolean parse_inum PARAMS((const struct parser_table*, char *argv[], int *arg_ptr)); 107static boolean parse_ipath PARAMS((const struct parser_table*, char *argv[], int *arg_ptr)); 108static boolean parse_iregex PARAMS((const struct parser_table*, char *argv[], int *arg_ptr)); 109static boolean parse_iwholename PARAMS((const struct parser_table*, char *argv[], int *arg_ptr)); 110static boolean parse_links PARAMS((const struct parser_table*, char *argv[], int *arg_ptr)); 111static boolean parse_lname PARAMS((const struct parser_table*, char *argv[], int *arg_ptr)); 112static boolean parse_ls PARAMS((const struct parser_table*, char *argv[], int *arg_ptr)); 113static boolean parse_maxdepth PARAMS((const struct parser_table*, char *argv[], int *arg_ptr)); 114static boolean parse_mindepth PARAMS((const struct parser_table*, char *argv[], int *arg_ptr)); 115static boolean parse_mmin PARAMS((const struct parser_table*, char *argv[], int *arg_ptr)); 116static boolean parse_mtime PARAMS((const struct parser_table*, char *argv[], int *arg_ptr)); 117static boolean parse_name PARAMS((const struct parser_table*, char *argv[], int *arg_ptr)); 118static boolean parse_negate PARAMS((const struct parser_table*, char *argv[], int *arg_ptr)); 119static boolean parse_newer PARAMS((const struct parser_table*, char *argv[], int *arg_ptr)); 120static boolean parse_noleaf PARAMS((const struct parser_table*, char *argv[], int *arg_ptr)); 121static boolean parse_nogroup PARAMS((const struct parser_table*, char *argv[], int *arg_ptr)); 122static boolean parse_nouser PARAMS((const struct parser_table*, char *argv[], int *arg_ptr)); 123static boolean parse_nowarn PARAMS((const struct parser_table*, char *argv[], int *arg_ptr)); 124static boolean parse_ok PARAMS((const struct parser_table*, char *argv[], int *arg_ptr)); 125static boolean parse_okdir PARAMS((const struct parser_table*, char *argv[], int *arg_ptr)); 126static boolean parse_or PARAMS((const struct parser_table*, char *argv[], int *arg_ptr)); 127static boolean parse_path PARAMS((const struct parser_table*, char *argv[], int *arg_ptr)); 128static boolean parse_perm PARAMS((const struct parser_table*, char *argv[], int *arg_ptr)); 129static boolean parse_print0 PARAMS((const struct parser_table*, char *argv[], int *arg_ptr)); 130static boolean parse_printf PARAMS((const struct parser_table*, char *argv[], int *arg_ptr)); 131static boolean parse_prune PARAMS((const struct parser_table*, char *argv[], int *arg_ptr)); 132static boolean parse_regex PARAMS((const struct parser_table*, char *argv[], int *arg_ptr)); 133static boolean parse_regextype PARAMS((const struct parser_table*, char *argv[], int *arg_ptr)); 134static boolean parse_samefile PARAMS((const struct parser_table*, char *argv[], int *arg_ptr)); 135static boolean parse_size PARAMS((const struct parser_table*, char *argv[], int *arg_ptr)); 136static boolean parse_true PARAMS((const struct parser_table*, char *argv[], int *arg_ptr)); 137static boolean parse_type PARAMS((const struct parser_table*, char *argv[], int *arg_ptr)); 138static boolean parse_uid PARAMS((const struct parser_table*, char *argv[], int *arg_ptr)); 139static boolean parse_used PARAMS((const struct parser_table*, char *argv[], int *arg_ptr)); 140static boolean parse_user PARAMS((const struct parser_table*, char *argv[], int *arg_ptr)); 141static boolean parse_version PARAMS((const struct parser_table*, char *argv[], int *arg_ptr)); 142static boolean parse_wholename PARAMS((const struct parser_table*, char *argv[], int *arg_ptr)); 143static boolean parse_xdev PARAMS((const struct parser_table*, char *argv[], int *arg_ptr)); 144static boolean parse_ignore_race PARAMS((const struct parser_table*, char *argv[], int *arg_ptr)); 145static boolean parse_noignore_race PARAMS((const struct parser_table*, char *argv[], int *arg_ptr)); 146static boolean parse_warn PARAMS((const struct parser_table*, char *argv[], int *arg_ptr)); 147static boolean parse_xtype PARAMS((const struct parser_table*, char *argv[], int *arg_ptr)); 148static boolean parse_quit PARAMS((const struct parser_table*, char *argv[], int *arg_ptr)); 149 150 151 152boolean parse_print PARAMS((const struct parser_table*, char *argv[], int *arg_ptr)); 153 154 155 156static boolean insert_type PARAMS((char **argv, int *arg_ptr, const struct parser_table *entry, PRED_FUNC which_pred)); 157static boolean insert_regex PARAMS((char *argv[], int *arg_ptr, const struct parser_table *entry, int regex_options)); 158static boolean insert_fprintf PARAMS((FILE *fp, const struct parser_table *entry, PRED_FUNC func, char *argv[], int *arg_ptr)); 159 160static struct segment **make_segment PARAMS((struct segment **segment, char *format, int len, int kind)); 161static boolean insert_exec_ok PARAMS((const char *action, const struct parser_table *entry, char *argv[], int *arg_ptr)); 162static boolean get_num_days PARAMS((char *str, uintmax_t *num_days, enum comparison_type *comp_type)); 163static boolean insert_time PARAMS((char **argv, int *arg_ptr, const struct parser_table* entry, PRED_FUNC pred)); 164static boolean get_num PARAMS((char *str, uintmax_t *num, enum comparison_type *comp_type)); 165static boolean insert_num PARAMS((char *argv[], int *arg_ptr, const struct parser_table *entry)); 166static FILE *open_output_file PARAMS((char *path)); 167static boolean stream_is_tty(FILE *fp); 168 169#ifdef DEBUG 170char *find_pred_name PARAMS((PRED_FUNC pred_func)); 171#endif /* DEBUG */ 172 173 174#define PASTE(x,y) x##y 175#define STRINGIFY(s) #s 176 177#define PARSE_OPTION(what,suffix) \ 178 { (ARG_OPTION), (what), PASTE(parse_,suffix), NULL } 179 180#define PARSE_POSOPT(what,suffix) \ 181 { (ARG_POSITIONAL_OPTION), (what), PASTE(parse_,suffix), NULL } 182 183#define PARSE_TEST(what,suffix) \ 184 { (ARG_TEST), (what), PASTE(parse_,suffix), PASTE(pred_,suffix) } 185 186#define PARSE_TEST_NP(what,suffix) \ 187 { (ARG_TEST), (what), PASTE(parse_,suffix), NULL } 188 189#define PARSE_ACTION(what,suffix) \ 190 { (ARG_ACTION), (what), PASTE(parse_,suffix), PASTE(pred_,suffix) } 191 192#define PARSE_ACTION_NP(what,suffix) \ 193 { (ARG_ACTION), (what), PASTE(parse_,suffix), NULL } 194 195#define PARSE_PUNCTUATION(what,suffix) \ 196 { (ARG_PUNCTUATION), (what), PASTE(parse_,suffix), PASTE(pred_,suffix) } 197 198 199/* GNU find predicates that are not mentioned in POSIX.2 are marked `GNU'. 200 If they are in some Unix versions of find, they are marked `Unix'. */ 201 202static struct parser_table const parse_table[] = 203{ 204 PARSE_PUNCTUATION("!", negate), 205 PARSE_PUNCTUATION("not", negate), /* GNU */ 206 PARSE_PUNCTUATION("(", openparen), 207 PARSE_PUNCTUATION(")", closeparen), 208 PARSE_PUNCTUATION(",", comma), /* GNU */ 209 PARSE_PUNCTUATION("a", and), 210 PARSE_TEST ("amin", amin), /* GNU */ 211 PARSE_PUNCTUATION("and", and), /* GNU */ 212 PARSE_TEST ("anewer", anewer), /* GNU */ 213 PARSE_TEST ("atime", atime), 214 PARSE_TEST ("cmin", cmin), /* GNU */ 215 PARSE_TEST ("cnewer", cnewer), /* GNU */ 216 PARSE_TEST ("ctime", ctime), 217 PARSE_POSOPT ("daystart", daystart), /* GNU */ 218 PARSE_ACTION ("delete", delete), /* GNU, Mac OS, FreeBSD */ 219 PARSE_OPTION ("d", d), /* Mac OS X, FreeBSD, NetBSD, OpenBSD, but deprecated in favour of -depth */ 220 PARSE_OPTION ("depth", depth), 221 PARSE_TEST ("empty", empty), /* GNU */ 222 {ARG_ACTION, "exec", parse_exec, pred_exec}, /* POSIX */ 223 PARSE_ACTION ("execdir", execdir), /* *BSD, GNU */ 224 PARSE_ACTION ("fls", fls), /* GNU */ 225 PARSE_POSOPT ("follow", follow), /* GNU, Unix */ 226 PARSE_ACTION ("fprint", fprint), /* GNU */ 227 PARSE_ACTION ("fprint0", fprint0), /* GNU */ 228 {ARG_ACTION, "fprintf", parse_fprintf, pred_fprintf}, /* GNU */ 229 PARSE_TEST ("fstype", fstype), /* GNU, Unix */ 230 PARSE_TEST ("gid", gid), /* GNU */ 231 PARSE_TEST ("group", group), 232 PARSE_OPTION ("ignore_readdir_race", ignore_race), /* GNU */ 233 PARSE_TEST ("ilname", ilname), /* GNU */ 234 PARSE_TEST ("iname", iname), /* GNU */ 235 PARSE_TEST ("inum", inum), /* GNU, Unix */ 236 PARSE_TEST ("ipath", ipath), /* GNU, deprecated in favour of iwholename */ 237 PARSE_TEST_NP ("iregex", iregex), /* GNU */ 238 PARSE_TEST_NP ("iwholename", iwholename), /* GNU */ 239 PARSE_TEST ("links", links), 240 PARSE_TEST ("lname", lname), /* GNU */ 241 PARSE_ACTION ("ls", ls), /* GNU, Unix */ 242 PARSE_OPTION ("maxdepth", maxdepth), /* GNU */ 243 PARSE_OPTION ("mindepth", mindepth), /* GNU */ 244 PARSE_TEST ("mmin", mmin), /* GNU */ 245 PARSE_OPTION ("mount", xdev), /* Unix */ 246 PARSE_TEST ("mtime", mtime), 247 PARSE_TEST ("name", name), 248#ifdef UNIMPLEMENTED_UNIX 249 PARSE(ARG_UNIMPLEMENTED, "ncpio", ncpio), /* Unix */ 250#endif 251 PARSE_TEST ("newer", newer), 252 PARSE_OPTION ("noleaf", noleaf), /* GNU */ 253 PARSE_TEST ("nogroup", nogroup), 254 PARSE_TEST ("nouser", nouser), 255 PARSE_OPTION ("noignore_readdir_race", noignore_race), /* GNU */ 256 PARSE_OPTION ("nowarn", nowarn), /* GNU */ 257 PARSE_PUNCTUATION("o", or), 258 PARSE_PUNCTUATION("or", or), /* GNU */ 259 PARSE_ACTION ("ok", ok), 260 PARSE_ACTION ("okdir", okdir), /* GNU (-execdir is BSD) */ 261 PARSE_TEST ("path", path), /* GNU, HP-UX, GNU prefers wholename */ 262 PARSE_TEST ("perm", perm), 263 PARSE_ACTION ("print", print), 264 PARSE_ACTION ("print0", print0), /* GNU */ 265 {ARG_ACTION, "printf", parse_printf, NULL}, /* GNU */ 266 PARSE_ACTION ("prune", prune), 267 PARSE_ACTION ("quit", quit), /* GNU */ 268 PARSE_TEST ("regex", regex), /* GNU */ 269 PARSE_OPTION ("regextype", regextype), /* GNU */ 270 PARSE_TEST ("samefile", samefile), /* GNU */ 271 PARSE_TEST ("size", size), 272 PARSE_TEST ("type", type), 273 PARSE_TEST ("uid", uid), /* GNU */ 274 PARSE_TEST ("used", used), /* GNU */ 275 PARSE_TEST ("user", user), 276 PARSE_OPTION ("warn", warn), /* GNU */ 277 PARSE_TEST_NP ("wholename", wholename), /* GNU, replaces -path */ 278 PARSE_OPTION ("xdev", xdev), 279 PARSE_TEST ("xtype", xtype), /* GNU */ 280#ifdef UNIMPLEMENTED_UNIX 281 /* It's pretty ugly for find to know about archive formats. 282 Plus what it could do with cpio archives is very limited. 283 Better to leave it out. */ 284 PARSE(ARG_UNIMPLEMENTED, "cpio", cpio), /* Unix */ 285#endif 286 /* gnulib's stdbool.h might have made true and false into macros, 287 * so we can't leave named 'true' and 'false' tokens, so we have 288 * to expeant the relevant entries longhand. 289 */ 290 {ARG_TEST, "false", parse_false, pred_false}, /* GNU */ 291 {ARG_TEST, "true", parse_true, pred_true }, /* GNU */ 292 293 /* Various other cases that don't fit neatly into our macro scheme. */ 294 {ARG_TEST, "help", parse_help, NULL}, /* GNU */ 295 {ARG_TEST, "-help", parse_help, NULL}, /* GNU */ 296 {ARG_TEST, "version", parse_version, NULL}, /* GNU */ 297 {ARG_TEST, "-version", parse_version, NULL}, /* GNU */ 298 {0, 0, 0, 0} 299}; 300 301 302static const char *first_nonoption_arg = NULL; 303 304 305 306void 307parse_begin_user_args (char **args, int argno, const struct predicate *last, const struct predicate *predicates) 308{ 309 (void) args; 310 (void) argno; 311 (void) last; 312 (void) predicates; 313 first_nonoption_arg = NULL; 314} 315 316void 317parse_end_user_args (char **args, int argno, const struct predicate *last, const struct predicate *predicates) 318{ 319 /* does nothing */ 320 (void) args; 321 (void) argno; 322 (void) last; 323 (void) predicates; 324} 325 326 327 328 329/* Return a pointer to the parser function to invoke for predicate 330 SEARCH_NAME. 331 Return NULL if SEARCH_NAME is not a valid predicate name. */ 332 333const struct parser_table* 334find_parser (char *search_name) 335{ 336 int i; 337 const char *original_arg = search_name; 338 339 if (*search_name == '-') 340 search_name++; 341 for (i = 0; parse_table[i].parser_name != 0; i++) 342 { 343 if (strcmp (parse_table[i].parser_name, search_name) == 0) 344 { 345 /* If this is an option, but we have already had a 346 * non-option argument, the user may be under the 347 * impression that the behaviour of the option 348 * argument is conditional on some preceding 349 * tests. This might typically be the case with, 350 * for example, -maxdepth. 351 * 352 * The options -daystart and -follow are exempt 353 * from this treatment, since their positioning 354 * in the command line does have an effect on 355 * subsequent tests but not previous ones. That 356 * might be intentional on the part of the user. 357 */ 358 if (parse_table[i].type != ARG_POSITIONAL_OPTION) 359 { 360 /* Something other than -follow/-daystart. 361 * If this is an option, check if it followed 362 * a non-option and if so, issue a warning. 363 */ 364 if (parse_table[i].type == ARG_OPTION) 365 { 366 if ((first_nonoption_arg != NULL) 367 && options.warnings ) 368 { 369 /* option which follows a non-option */ 370 error (0, 0, 371 _("warning: you have specified the %s " 372 "option after a non-option argument %s, " 373 "but options are not positional (%s affects " 374 "tests specified before it as well as those " 375 "specified after it). Please specify options " 376 "before other arguments.\n"), 377 original_arg, 378 first_nonoption_arg, 379 original_arg); 380 } 381 } 382 else 383 { 384 /* Not an option or a positional option, 385 * so remember we've seen it in order to 386 * use it in a possible future warning message. 387 */ 388 if (first_nonoption_arg == NULL) 389 { 390 first_nonoption_arg = original_arg; 391 } 392 } 393 } 394 395 return &parse_table[i]; 396 } 397 } 398 return NULL; 399} 400 401/* The parsers are responsible to continue scanning ARGV for 402 their arguments. Each parser knows what is and isn't 403 allowed for itself. 404 405 ARGV is the argument array. 406 *ARG_PTR is the index to start at in ARGV, 407 updated to point beyond the last element consumed. 408 409 The predicate structure is updated with the new information. */ 410 411static boolean 412parse_amin (const struct parser_table* entry, char **argv, int *arg_ptr) 413{ 414 struct predicate *our_pred; 415 uintmax_t num; 416 enum comparison_type c_type; 417 time_t t; 418 419 if ((argv == NULL) || (argv[*arg_ptr] == NULL)) 420 return false; 421 if (!get_num_days (argv[*arg_ptr], &num, &c_type)) 422 return false; 423 t = options.cur_day_start + DAYSECS - num * 60; 424 our_pred = insert_primary (entry); 425 our_pred->args.info.kind = c_type; 426 our_pred->args.info.negative = t < 0; 427 our_pred->args.info.l_val = t; 428 (*arg_ptr)++; 429 return true; 430} 431 432static boolean 433parse_and (const struct parser_table* entry, char **argv, int *arg_ptr) 434{ 435 struct predicate *our_pred; 436 437 (void) argv; 438 (void) arg_ptr; 439 440 our_pred = get_new_pred (entry); 441 our_pred->pred_func = pred_and; 442#ifdef DEBUG 443 our_pred->p_name = find_pred_name (pred_and); 444#endif /* DEBUG */ 445 our_pred->p_type = BI_OP; 446 our_pred->p_prec = AND_PREC; 447 our_pred->need_stat = our_pred->need_type = false; 448 return true; 449} 450 451static boolean 452parse_anewer (const struct parser_table* entry, char **argv, int *arg_ptr) 453{ 454 struct predicate *our_pred; 455 struct stat stat_newer; 456 457 if ((argv == NULL) || (argv[*arg_ptr] == NULL)) 458 return false; 459 if ((*options.xstat) (argv[*arg_ptr], &stat_newer)) 460 error (1, errno, "%s", argv[*arg_ptr]); 461 our_pred = insert_primary (entry); 462 our_pred->args.time = stat_newer.st_mtime; 463 (*arg_ptr)++; 464 return true; 465} 466 467static boolean 468parse_atime (const struct parser_table* entry, char **argv, int *arg_ptr) 469{ 470 return insert_time (argv, arg_ptr, entry, pred_atime); 471} 472 473boolean 474parse_closeparen (const struct parser_table* entry, char **argv, int *arg_ptr) 475{ 476 struct predicate *our_pred; 477 478 (void) argv; 479 (void) arg_ptr; 480 481 our_pred = get_new_pred (entry); 482 our_pred->pred_func = pred_closeparen; 483#ifdef DEBUG 484 our_pred->p_name = find_pred_name (pred_closeparen); 485#endif /* DEBUG */ 486 our_pred->p_type = CLOSE_PAREN; 487 our_pred->p_prec = NO_PREC; 488 our_pred->need_stat = our_pred->need_type = false; 489 return true; 490} 491 492static boolean 493parse_cmin (const struct parser_table* entry, char **argv, int *arg_ptr) 494{ 495 struct predicate *our_pred; 496 uintmax_t num; 497 enum comparison_type c_type; 498 time_t t; 499 500 if ((argv == NULL) || (argv[*arg_ptr] == NULL)) 501 return false; 502 if (!get_num_days (argv[*arg_ptr], &num, &c_type)) 503 return false; 504 t = options.cur_day_start + DAYSECS - num * 60; 505 our_pred = insert_primary (entry); 506 our_pred->args.info.kind = c_type; 507 our_pred->args.info.negative = t < 0; 508 our_pred->args.info.l_val = t; 509 (*arg_ptr)++; 510 return true; 511} 512 513static boolean 514parse_cnewer (const struct parser_table* entry, char **argv, int *arg_ptr) 515{ 516 struct predicate *our_pred; 517 struct stat stat_newer; 518 519 if ((argv == NULL) || (argv[*arg_ptr] == NULL)) 520 return false; 521 if ((*options.xstat) (argv[*arg_ptr], &stat_newer)) 522 error (1, errno, "%s", argv[*arg_ptr]); 523 our_pred = insert_primary (entry); 524 our_pred->args.time = stat_newer.st_mtime; 525 (*arg_ptr)++; 526 return true; 527} 528 529static boolean 530parse_comma (const struct parser_table* entry, char **argv, int *arg_ptr) 531{ 532 struct predicate *our_pred; 533 534 (void) argv; 535 (void) arg_ptr; 536 537 our_pred = get_new_pred (entry); 538 our_pred->pred_func = pred_comma; 539#ifdef DEBUG 540 our_pred->p_name = find_pred_name (pred_comma); 541#endif /* DEBUG */ 542 our_pred->p_type = BI_OP; 543 our_pred->p_prec = COMMA_PREC; 544 our_pred->need_stat = our_pred->need_type = false; 545 return true; 546} 547 548static boolean 549parse_ctime (const struct parser_table* entry, char **argv, int *arg_ptr) 550{ 551 return insert_time (argv, arg_ptr, entry, pred_ctime); 552} 553 554static boolean 555parse_daystart (const struct parser_table* entry, char **argv, int *arg_ptr) 556{ 557 struct tm *local; 558 559 (void) entry; 560 (void) argv; 561 (void) arg_ptr; 562 563 if (options.full_days == false) 564 { 565 options.cur_day_start += DAYSECS; 566 local = localtime (&options.cur_day_start); 567 options.cur_day_start -= (local 568 ? (local->tm_sec + local->tm_min * 60 569 + local->tm_hour * 3600) 570 : options.cur_day_start % DAYSECS); 571 options.full_days = true; 572 } 573 return true; 574} 575 576static boolean 577parse_delete (const struct parser_table* entry, char *argv[], int *arg_ptr) 578{ 579 struct predicate *our_pred; 580 (void) argv; 581 (void) arg_ptr; 582 583 our_pred = insert_primary (entry); 584 our_pred->side_effects = our_pred->no_default_print = true; 585 /* -delete implies -depth */ 586 options.do_dir_first = false; 587 return true; 588} 589 590static boolean 591parse_depth (const struct parser_table* entry, char **argv, int *arg_ptr) 592{ 593 (void) entry; 594 (void) argv; 595 (void) arg_ptr; 596 597 options.do_dir_first = false; 598 return true; 599} 600 601static boolean 602parse_d (const struct parser_table* entry, char **argv, int *arg_ptr) 603{ 604 (void) argv; 605 (void) arg_ptr; 606 607 if (options.warnings) 608 { 609 error (0, 0, 610 _("warning: the -d option is deprecated; please use -depth instead, because the latter is a POSIX-compliant feature.")); 611 } 612 return parse_depth(entry, argv, arg_ptr); 613} 614 615static boolean 616parse_empty (const struct parser_table* entry, char **argv, int *arg_ptr) 617{ 618 (void) argv; 619 (void) arg_ptr; 620 621 insert_primary (entry); 622 return true; 623} 624 625static boolean 626parse_exec (const struct parser_table* entry, char **argv, int *arg_ptr) 627{ 628 return insert_exec_ok ("-exec", entry, argv, arg_ptr); 629} 630 631static boolean 632parse_execdir (const struct parser_table* entry, char **argv, int *arg_ptr) 633{ 634 return insert_exec_ok ("-execdir", entry, argv, arg_ptr); 635} 636 637static boolean 638parse_false (const struct parser_table* entry, char **argv, int *arg_ptr) 639{ 640 struct predicate *our_pred; 641 642 (void) argv; 643 (void) arg_ptr; 644 645 our_pred = insert_primary (entry); 646 our_pred->need_stat = our_pred->need_type = false; 647 our_pred->side_effects = our_pred->no_default_print = false; 648 return true; 649} 650 651static boolean 652parse_fls (const struct parser_table* entry, char **argv, int *arg_ptr) 653{ 654 struct predicate *our_pred; 655 656 if ((argv == NULL) || (argv[*arg_ptr] == NULL)) 657 return false; 658 our_pred = insert_primary (entry); 659 our_pred->args.stream = open_output_file (argv[*arg_ptr]); 660 our_pred->side_effects = our_pred->no_default_print = true; 661 (*arg_ptr)++; 662 return true; 663} 664 665static boolean 666parse_fprintf (const struct parser_table* entry, char **argv, int *arg_ptr) 667{ 668 FILE *fp; 669 670 if ((argv == NULL) || (argv[*arg_ptr] == NULL)) 671 return false; 672 if (argv[*arg_ptr + 1] == NULL) 673 { 674 /* Ensure we get "missing arg" message, not "invalid arg". */ 675 (*arg_ptr)++; 676 return false; 677 } 678 fp = open_output_file (argv[*arg_ptr]); 679 (*arg_ptr)++; 680 return insert_fprintf (fp, entry, pred_fprintf, argv, arg_ptr); 681} 682 683static boolean 684parse_follow (const struct parser_table* entry, char **argv, int *arg_ptr) 685{ 686 (void) entry; 687 (void) argv; 688 (void) arg_ptr; 689 690 set_follow_state(SYMLINK_ALWAYS_DEREF); 691 return true; 692} 693 694static boolean 695parse_fprint (const struct parser_table* entry, char **argv, int *arg_ptr) 696{ 697 struct predicate *our_pred; 698 699 if ((argv == NULL) || (argv[*arg_ptr] == NULL)) 700 return false; 701 our_pred = insert_primary (entry); 702 our_pred->args.printf_vec.segment = NULL; 703 our_pred->args.printf_vec.stream = open_output_file (argv[*arg_ptr]); 704 our_pred->args.printf_vec.dest_is_tty = stream_is_tty(our_pred->args.printf_vec.stream); 705 our_pred->args.printf_vec.quote_opts = clone_quoting_options (NULL); 706 our_pred->side_effects = our_pred->no_default_print = true; 707 our_pred->need_stat = our_pred->need_type = false; 708 (*arg_ptr)++; 709 return true; 710} 711 712static boolean 713parse_fprint0 (const struct parser_table* entry, char **argv, int *arg_ptr) 714{ 715 struct predicate *our_pred; 716 717 if ((argv == NULL) || (argv[*arg_ptr] == NULL)) 718 return false; 719 our_pred = insert_primary (entry); 720 our_pred->args.stream = open_output_file (argv[*arg_ptr]); 721 our_pred->side_effects = our_pred->no_default_print = true; 722 our_pred->need_stat = our_pred->need_type = false; 723 (*arg_ptr)++; 724 return true; 725} 726 727static boolean 728parse_fstype (const struct parser_table* entry, char **argv, int *arg_ptr) 729{ 730 struct predicate *our_pred; 731 732 if ((argv == NULL) || (argv[*arg_ptr] == NULL)) 733 return false; 734 our_pred = insert_primary (entry); 735 our_pred->args.str = argv[*arg_ptr]; 736 (*arg_ptr)++; 737 return true; 738} 739 740static boolean 741parse_gid (const struct parser_table* entry, char **argv, int *arg_ptr) 742{ 743 return insert_num (argv, arg_ptr, entry); 744} 745 746static boolean 747parse_group (const struct parser_table* entry, char **argv, int *arg_ptr) 748{ 749 struct group *cur_gr; 750 struct predicate *our_pred; 751 gid_t gid; 752 int gid_len; 753 754 if ((argv == NULL) || (argv[*arg_ptr] == NULL)) 755 return false; 756 cur_gr = getgrnam (argv[*arg_ptr]); 757 endgrent (); 758 if (cur_gr != NULL) 759 gid = cur_gr->gr_gid; 760 else 761 { 762 gid_len = strspn (argv[*arg_ptr], "0123456789"); 763 if ((gid_len == 0) || (argv[*arg_ptr][gid_len] != '\0')) 764 return false; 765 gid = atoi (argv[*arg_ptr]); 766 } 767 our_pred = insert_primary (entry); 768 our_pred->args.gid = gid; 769 (*arg_ptr)++; 770 return true; 771} 772 773static boolean 774parse_help (const struct parser_table* entry, char **argv, int *arg_ptr) 775{ 776 (void) entry; 777 (void) argv; 778 (void) arg_ptr; 779 780 printf (_("\ 781Usage: %s [path...] [expression]\n"), program_name); 782 puts (_("\n\ 783default path is the current directory; default expression is -print\n\ 784expression may consist of: operators, options, tests, and actions:\n")); 785 puts (_("\ 786operators (decreasing precedence; -and is implicit where no others are given):\n\ 787 ( EXPR ) ! EXPR -not EXPR EXPR1 -a EXPR2 EXPR1 -and EXPR2\n\ 788 EXPR1 -o EXPR2 EXPR1 -or EXPR2 EXPR1 , EXPR2\n")); 789 puts (_("\ 790positional options (always true): -daystart -follow -regextype\n\n\ 791normal options (always true, specified before other expressions):\n\ 792 -depth --help -maxdepth LEVELS -mindepth LEVELS -mount -noleaf\n\ 793 --version -xdev -ignore_readdir_race -noignore_readdir_race\n")); 794 puts (_("\ 795tests (N can be +N or -N or N): -amin N -anewer FILE -atime N -cmin N\n\ 796 -cnewer FILE -ctime N -empty -false -fstype TYPE -gid N -group NAME\n\ 797 -ilname PATTERN -iname PATTERN -inum N -iwholename PATTERN -iregex PATTERN\n\ 798 -links N -lname PATTERN -mmin N -mtime N -name PATTERN -newer FILE")); 799 puts (_("\ 800 -nouser -nogroup -path PATTERN -perm [+-]MODE -regex PATTERN\n\ 801 -wholename PATTERN -size N[bcwkMG] -true -type [bcdpflsD] -uid N\n\ 802 -used N -user NAME -xtype [bcdpfls]\n")); 803 puts (_("\ 804actions: -delete -print0 -printf FORMAT -fprintf FILE FORMAT -print \n\ 805 -fprint0 FILE -fprint FILE -ls -fls FILE -prune -quit\n\ 806 -exec COMMAND ; -exec COMMAND {} + -ok COMMAND ;\n\ 807 -execdir COMMAND ; -execdir COMMAND {} + -okdir COMMAND ;\n\ 808")); 809 puts (_("Report (and track progress on fixing) bugs via the findutils bug-reporting\n\ 810page at http://savannah.gnu.org/ or, if you have no web access, by sending\n\ 811email to <bug-findutils@gnu.org>.")); 812 exit (0); 813} 814 815static boolean 816parse_ilname (const struct parser_table* entry, char **argv, int *arg_ptr) 817{ 818 struct predicate *our_pred; 819 820 if ((argv == NULL) || (argv[*arg_ptr] == NULL)) 821 return false; 822 our_pred = insert_primary (entry); 823 our_pred->args.str = argv[*arg_ptr]; 824 (*arg_ptr)++; 825 return true; 826} 827 828 829/* sanity check the fnmatch() function to make sure 830 * it really is the GNU version. 831 */ 832static boolean 833fnmatch_sanitycheck(void) 834{ 835 /* fprintf(stderr, "Performing find sanity check..."); */ 836 if (0 != fnmatch("foo", "foo", 0) 837 || 0 == fnmatch("Foo", "foo", 0) 838 || 0 != fnmatch("Foo", "foo", FNM_CASEFOLD)) 839 { 840 error (1, 0, _("sanity check of the fnmatch() library function failed.")); 841 /* fprintf(stderr, "FAILED\n"); */ 842 return false; 843 } 844 845 /* fprintf(stderr, "OK\n"); */ 846 return true; 847} 848 849 850static boolean 851check_name_arg(const char *pred, const char *arg) 852{ 853 if (options.warnings && strchr(arg, '/')) 854 { 855 error(0, 0,_("warning: Unix filenames usually don't contain slashes (though pathnames do). That means that '%s %s' will probably evaluate to false all the time on this system. You might find the '-wholename' test more useful, or perhaps '-samefile'. Alternatively, if you are using GNU grep, you could use 'find ... -print0 | grep -FzZ %s'."), 856 pred, arg, arg); 857 } 858 return true; /* allow it anyway */ 859} 860 861 862 863static boolean 864parse_iname (const struct parser_table* entry, char **argv, int *arg_ptr) 865{ 866 struct predicate *our_pred; 867 868 if ((argv == NULL) || (argv[*arg_ptr] == NULL)) 869 return false; 870 if (!check_name_arg("-iname", argv[*arg_ptr])) 871 return false; 872 873 fnmatch_sanitycheck(); 874 875 our_pred = insert_primary (entry); 876 our_pred->need_stat = our_pred->need_type = false; 877 our_pred->args.str = argv[*arg_ptr]; 878 (*arg_ptr)++; 879 return true; 880} 881 882static boolean 883parse_inum (const struct parser_table* entry, char **argv, int *arg_ptr) 884{ 885 return insert_num (argv, arg_ptr, entry); 886} 887 888/* -ipath is deprecated (at RMS's request) in favour of 889 * -iwholename. See the node "GNU Manuals" in standards.texi 890 * for the rationale for this (basically, GNU prefers the use 891 * of the phrase "file name" to "path name" 892 */ 893static boolean 894parse_ipath (const struct parser_table* entry, char **argv, int *arg_ptr) 895{ 896 error (0, 0, 897 _("warning: the predicate -ipath is deprecated; please use -iwholename instead.")); 898 899 return parse_iwholename(entry, argv, arg_ptr); 900} 901 902static boolean 903parse_iwholename (const struct parser_table* entry, char **argv, int *arg_ptr) 904{ 905 struct predicate *our_pred; 906 907 if ((argv == NULL) || (argv[*arg_ptr] == NULL)) 908 return false; 909 910 fnmatch_sanitycheck(); 911 912 our_pred = insert_primary_withpred (entry, pred_ipath); 913 our_pred->need_stat = our_pred->need_type = false; 914 our_pred->args.str = argv[*arg_ptr]; 915 (*arg_ptr)++; 916 return true; 917} 918 919static boolean 920parse_iregex (const struct parser_table* entry, char **argv, int *arg_ptr) 921{ 922 return insert_regex (argv, arg_ptr, entry, RE_ICASE|options.regex_options); 923} 924 925static boolean 926parse_links (const struct parser_table* entry, char **argv, int *arg_ptr) 927{ 928 return insert_num (argv, arg_ptr, entry); 929} 930 931static boolean 932parse_lname (const struct parser_table* entry, char **argv, int *arg_ptr) 933{ 934 struct predicate *our_pred; 935 936 (void) argv; 937 (void) arg_ptr; 938 939 if ((argv == NULL) || (argv[*arg_ptr] == NULL)) 940 return false; 941 942 fnmatch_sanitycheck(); 943 944 our_pred = insert_primary (entry); 945 our_pred->args.str = argv[*arg_ptr]; 946 (*arg_ptr)++; 947 return true; 948} 949 950static boolean 951parse_ls (const struct parser_table* entry, char **argv, int *arg_ptr) 952{ 953 struct predicate *our_pred; 954 955 (void) &argv; 956 (void) &arg_ptr; 957 958 our_pred = insert_primary (entry); 959 our_pred->side_effects = our_pred->no_default_print = true; 960 return true; 961} 962 963static boolean 964parse_maxdepth (const struct parser_table* entry, char **argv, int *arg_ptr) 965{ 966 int depth_len; 967 (void) entry; 968 969 if ((argv == NULL) || (argv[*arg_ptr] == NULL)) 970 return false; 971 depth_len = strspn (argv[*arg_ptr], "0123456789"); 972 if ((depth_len == 0) || (argv[*arg_ptr][depth_len] != '\0')) 973 return false; 974 options.maxdepth = atoi (argv[*arg_ptr]); 975 if (options.maxdepth < 0) 976 return false; 977 (*arg_ptr)++; 978 return true; 979} 980 981static boolean 982parse_mindepth (const struct parser_table* entry, char **argv, int *arg_ptr) 983{ 984 int depth_len; 985 (void) entry; 986 987 if ((argv == NULL) || (argv[*arg_ptr] == NULL)) 988 return false; 989 depth_len = strspn (argv[*arg_ptr], "0123456789"); 990 if ((depth_len == 0) || (argv[*arg_ptr][depth_len] != '\0')) 991 return false; 992 options.mindepth = atoi (argv[*arg_ptr]); 993 if (options.mindepth < 0) 994 return false; 995 (*arg_ptr)++; 996 return true; 997} 998 999static boolean 1000parse_mmin (const struct parser_table* entry, char **argv, int *arg_ptr) 1001{ 1002 struct predicate *our_pred; 1003 uintmax_t num; 1004 enum comparison_type c_type; 1005 time_t t; 1006 1007 if ((argv == NULL) || (argv[*arg_ptr] == NULL)) 1008 return false; 1009 if (!get_num_days (argv[*arg_ptr], &num, &c_type)) 1010 return false; 1011 t = options.cur_day_start + DAYSECS - num * 60; 1012 our_pred = insert_primary (entry); 1013 our_pred->args.info.kind = c_type; 1014 our_pred->args.info.negative = t < 0; 1015 our_pred->args.info.l_val = t; 1016 (*arg_ptr)++; 1017 return true; 1018} 1019 1020static boolean 1021parse_mtime (const struct parser_table* entry, char **argv, int *arg_ptr) 1022{ 1023 return insert_time (argv, arg_ptr, entry, pred_mtime); 1024} 1025 1026static boolean 1027parse_name (const struct parser_table* entry, char **argv, int *arg_ptr) 1028{ 1029 struct predicate *our_pred; 1030 1031 (void) argv; 1032 (void) arg_ptr; 1033 1034 if ((argv == NULL) || (argv[*arg_ptr] == NULL)) 1035 return false; 1036 if (!check_name_arg("-name", argv[*arg_ptr])) 1037 return false; 1038 fnmatch_sanitycheck(); 1039 1040 our_pred = insert_primary (entry); 1041 our_pred->need_stat = our_pred->need_type = false; 1042 our_pred->args.str = argv[*arg_ptr]; 1043 (*arg_ptr)++; 1044 return true; 1045} 1046 1047static boolean 1048parse_negate (const struct parser_table* entry, char **argv, int *arg_ptr) 1049{ 1050 struct predicate *our_pred; 1051 1052 (void) &argv; 1053 (void) &arg_ptr; 1054 1055 our_pred = get_new_pred_chk_op (entry); 1056 our_pred->pred_func = pred_negate; 1057#ifdef DEBUG 1058 our_pred->p_name = find_pred_name (pred_negate); 1059#endif /* DEBUG */ 1060 our_pred->p_type = UNI_OP; 1061 our_pred->p_prec = NEGATE_PREC; 1062 our_pred->need_stat = our_pred->need_type = false; 1063 return true; 1064} 1065 1066static boolean 1067parse_newer (const struct parser_table* entry, char **argv, int *arg_ptr) 1068{ 1069 struct predicate *our_pred; 1070 struct stat stat_newer; 1071 1072 (void) argv; 1073 (void) arg_ptr; 1074 1075 if ((argv == NULL) || (argv[*arg_ptr] == NULL)) 1076 return false; 1077 if ((*options.xstat) (argv[*arg_ptr], &stat_newer)) 1078 error (1, errno, "%s", argv[*arg_ptr]); 1079 our_pred = insert_primary (entry); 1080 our_pred->args.time = stat_newer.st_mtime; 1081 (*arg_ptr)++; 1082 return true; 1083} 1084 1085static boolean 1086parse_noleaf (const struct parser_table* entry, char **argv, int *arg_ptr) 1087{ 1088 (void) &argv; 1089 (void) &arg_ptr; 1090 (void) entry; 1091 1092 options.no_leaf_check = true; 1093 return true; 1094} 1095 1096#ifdef CACHE_IDS 1097/* Arbitrary amount by which to increase size 1098 of `uid_unused' and `gid_unused'. */ 1099#define ALLOC_STEP 2048 1100 1101/* Boolean: if uid_unused[n] is nonzero, then UID n has no passwd entry. */ 1102char *uid_unused = NULL; 1103 1104/* Number of elements in `uid_unused'. */ 1105unsigned uid_allocated; 1106 1107/* Similar for GIDs and group entries. */ 1108char *gid_unused = NULL; 1109unsigned gid_allocated; 1110#endif 1111 1112static boolean 1113parse_nogroup (const struct parser_table* entry, char **argv, int *arg_ptr) 1114{ 1115 struct predicate *our_pred; 1116 1117 (void) &argv; 1118 (void) &arg_ptr; 1119 1120 our_pred = insert_primary (entry); 1121#ifdef CACHE_IDS 1122 if (gid_unused == NULL) 1123 { 1124 struct group *gr; 1125 1126 gid_allocated = ALLOC_STEP; 1127 gid_unused = xmalloc (gid_allocated); 1128 memset (gid_unused, 1, gid_allocated); 1129 setgrent (); 1130 while ((gr = getgrent ()) != NULL) 1131 { 1132 if ((unsigned) gr->gr_gid >= gid_allocated) 1133 { 1134 unsigned new_allocated = (unsigned) gr->gr_gid + ALLOC_STEP; 1135 gid_unused = xrealloc (gid_unused, new_allocated); 1136 memset (gid_unused + gid_allocated, 1, 1137 new_allocated - gid_allocated); 1138 gid_allocated = new_allocated; 1139 } 1140 gid_unused[(unsigned) gr->gr_gid] = 0; 1141 } 1142 endgrent (); 1143 } 1144#endif 1145 return true; 1146} 1147 1148static boolean 1149parse_nouser (const struct parser_table* entry, char **argv, int *arg_ptr) 1150{ 1151 struct predicate *our_pred; 1152 (void) argv; 1153 (void) arg_ptr; 1154 1155 1156 our_pred = insert_primary (entry); 1157#ifdef CACHE_IDS 1158 if (uid_unused == NULL) 1159 { 1160 struct passwd *pw; 1161 1162 uid_allocated = ALLOC_STEP; 1163 uid_unused = xmalloc (uid_allocated); 1164 memset (uid_unused, 1, uid_allocated); 1165 setpwent (); 1166 while ((pw = getpwent ()) != NULL) 1167 { 1168 if ((unsigned) pw->pw_uid >= uid_allocated) 1169 { 1170 unsigned new_allocated = (unsigned) pw->pw_uid + ALLOC_STEP; 1171 uid_unused = xrealloc (uid_unused, new_allocated); 1172 memset (uid_unused + uid_allocated, 1, 1173 new_allocated - uid_allocated); 1174 uid_allocated = new_allocated; 1175 } 1176 uid_unused[(unsigned) pw->pw_uid] = 0; 1177 } 1178 endpwent (); 1179 } 1180#endif 1181 return true; 1182} 1183 1184static boolean 1185parse_nowarn (const struct parser_table* entry, char **argv, int *arg_ptr) 1186{ 1187 (void) argv; 1188 (void) arg_ptr; 1189 (void) entry; 1190 1191 options.warnings = false; 1192 return true;; 1193} 1194 1195static boolean 1196parse_ok (const struct parser_table* entry, char **argv, int *arg_ptr) 1197{ 1198 return insert_exec_ok ("-ok", entry, argv, arg_ptr); 1199} 1200 1201static boolean 1202parse_okdir (const struct parser_table* entry, char **argv, int *arg_ptr) 1203{ 1204 return insert_exec_ok ("-okdir", entry, argv, arg_ptr); 1205} 1206 1207boolean 1208parse_openparen (const struct parser_table* entry, char **argv, int *arg_ptr) 1209{ 1210 struct predicate *our_pred; 1211 1212 (void) argv; 1213 (void) arg_ptr; 1214 1215 our_pred = get_new_pred_chk_op (entry); 1216 our_pred->pred_func = pred_openparen; 1217#ifdef DEBUG 1218 our_pred->p_name = find_pred_name (pred_openparen); 1219#endif /* DEBUG */ 1220 our_pred->p_type = OPEN_PAREN; 1221 our_pred->p_prec = NO_PREC; 1222 our_pred->need_stat = our_pred->need_type = false; 1223 return true; 1224} 1225 1226static boolean 1227parse_or (const struct parser_table* entry, char **argv, int *arg_ptr) 1228{ 1229 struct predicate *our_pred; 1230 1231 (void) argv; 1232 (void) arg_ptr; 1233 1234 our_pred = get_new_pred (entry); 1235 our_pred->pred_func = pred_or; 1236#ifdef DEBUG 1237 our_pred->p_name = find_pred_name (pred_or); 1238#endif /* DEBUG */ 1239 our_pred->p_type = BI_OP; 1240 our_pred->p_prec = OR_PREC; 1241 our_pred->need_stat = our_pred->need_type = false; 1242 return true; 1243} 1244 1245/* -path is deprecated (at RMS's request) in favour of 1246 * -iwholename. See the node "GNU Manuals" in standards.texi 1247 * for the rationale for this (basically, GNU prefers the use 1248 * of the phrase "file name" to "path name". 1249 * 1250 * We do not issue a warning that this usage is deprecated 1251 * since HPUX find supports this predicate also. 1252 */ 1253static boolean 1254parse_path (const struct parser_table* entry, char **argv, int *arg_ptr) 1255{ 1256 return parse_wholename(entry, argv, arg_ptr); 1257} 1258 1259static boolean 1260parse_wholename (const struct parser_table* entry, char **argv, int *arg_ptr) 1261{ 1262 struct predicate *our_pred; 1263 1264 if ((argv == NULL) || (argv[*arg_ptr] == NULL)) 1265 return false; 1266 our_pred = insert_primary_withpred (entry, pred_path); 1267 our_pred->need_stat = our_pred->need_type = false; 1268 our_pred->args.str = argv[*arg_ptr]; 1269 (*arg_ptr)++; 1270 return true; 1271} 1272 1273static boolean 1274parse_perm (const struct parser_table* entry, char **argv, int *arg_ptr) 1275{ 1276 mode_t perm_val[2]; 1277 int mode_start = 0; 1278 boolean havekind = false; 1279 enum permissions_type kind = PERM_EXACT; 1280 struct mode_change *change = NULL; 1281 struct predicate *our_pred; 1282 1283 if ((argv == NULL) || (argv[*arg_ptr] == NULL)) 1284 return false; 1285 1286 switch (argv[*arg_ptr][0]) 1287 { 1288 case '-': 1289 mode_start = 1; 1290 kind = PERM_AT_LEAST; 1291 havekind = true; 1292 break; 1293 1294 case '+': 1295 change = mode_compile (argv[*arg_ptr]); 1296 if (NULL == change) 1297 { 1298 /* Most likely the caller is an old script that is still 1299 * using the obsolete GNU syntax '-perm +MODE'. This old 1300 * syntax was withdrawn in favor of '-perm /MODE' because 1301 * it is incompatible with POSIX in some cases, but we 1302 * still support uses of it that are not incompatible with 1303 * POSIX. 1304 */ 1305 mode_start = 1; 1306 kind = PERM_ANY; 1307 } 1308 else 1309 { 1310 /* This is a POSIX-compatible usage */ 1311 mode_start = 0; 1312 kind = PERM_EXACT; 1313 } 1314 havekind = true; 1315 break; 1316 1317 case '/': /* GNU extension */ 1318 mode_start = 1; 1319 kind = PERM_ANY; 1320 havekind = true; 1321 break; 1322 1323 default: 1324 /* For example, '-perm 0644', which is valid and matches 1325 * only files whose mode is exactly 0644. 1326 * 1327 * We do nothing here, because mode_start and kind are already 1328 * correctly set. 1329 */ 1330 break; 1331 } 1332 1333 if (NULL == change) 1334 { 1335 change = mode_compile (argv[*arg_ptr] + mode_start); 1336 if (NULL == change) 1337 error (1, 0, _("invalid mode `%s'"), argv[*arg_ptr]); 1338 } 1339 perm_val[0] = mode_adjust (0, false, 0, change, NULL); 1340 perm_val[1] = mode_adjust (0, true, 0, change, NULL); 1341 free (change); 1342 1343 our_pred = insert_primary (entry); 1344 1345 if (havekind) 1346 { 1347 our_pred->args.perm.kind = kind; 1348 } 1349 else 1350 { 1351 1352 switch (argv[*arg_ptr][0]) 1353 { 1354 case '-': 1355 our_pred->args.perm.kind = PERM_AT_LEAST; 1356 break; 1357 case '+': 1358 our_pred->args.perm.kind = PERM_ANY; 1359 break; 1360 default: 1361 our_pred->args.perm.kind = PERM_EXACT; 1362 break; 1363 } 1364 } 1365 1366 if (('/' == argv[*arg_ptr][0]) && (0 == perm_val[0]) && (0 == perm_val[1])) 1367 { 1368 /* The meaning of -perm /000 will change in the future. 1369 * It currently matches no files, but like -perm -000 it 1370 * should match all files. 1371 */ 1372 error (0, 0, 1373 _("warning: you have specified a mode pattern %s which is " 1374 "equivalent to 000. The meaning of -perm /000 will soon be " 1375 "changed to be consistent with -perm -000; that is, at the " 1376 "moment it matches no files but it will soon be changed to " 1377 "match all files."), 1378 argv[*arg_ptr]); 1379 } 1380 1381 memcpy (our_pred->args.perm.val, perm_val, sizeof perm_val); 1382 (*arg_ptr)++; 1383 return true; 1384} 1385 1386boolean 1387parse_print (const struct parser_table* entry, char **argv, int *arg_ptr) 1388{ 1389 struct predicate *our_pred; 1390 1391 (void) argv; 1392 (void) arg_ptr; 1393 1394 our_pred = insert_primary (entry); 1395 /* -print has the side effect of printing. This prevents us 1396 from doing undesired multiple printing when the user has 1397 already specified -print. */ 1398 our_pred->side_effects = our_pred->no_default_print = true; 1399 our_pred->need_stat = our_pred->need_type = false; 1400 our_pred->args.printf_vec.segment = NULL; 1401 our_pred->args.printf_vec.stream = stdout; 1402 our_pred->args.printf_vec.dest_is_tty = stream_is_tty(stdout); 1403 our_pred->args.printf_vec.quote_opts = clone_quoting_options (NULL); 1404 1405 return true; 1406} 1407 1408static boolean 1409parse_print0 (const struct parser_table* entry, char **argv, int *arg_ptr) 1410{ 1411 struct predicate *our_pred; 1412 1413 (void) argv; 1414 (void) arg_ptr; 1415 1416 our_pred = insert_primary (entry); 1417 /* -print0 has the side effect of printing. This prevents us 1418 from doing undesired multiple printing when the user has 1419 already specified -print0. */ 1420 our_pred->side_effects = our_pred->no_default_print = true; 1421 our_pred->need_stat = our_pred->need_type = false; 1422 return true; 1423} 1424 1425static boolean 1426parse_printf (const struct parser_table* entry, char **argv, int *arg_ptr) 1427{ 1428 if ((argv == NULL) || (argv[*arg_ptr] == NULL)) 1429 return false; 1430 return insert_fprintf (stdout, entry, pred_fprintf, argv, arg_ptr); 1431} 1432 1433static boolean 1434parse_prune (const struct parser_table* entry, char **argv, int *arg_ptr) 1435{ 1436 struct predicate *our_pred; 1437 1438 (void) argv; 1439 (void) arg_ptr; 1440 1441 our_pred = insert_primary (entry); 1442 our_pred->need_stat = our_pred->need_type = false; 1443 /* -prune has a side effect that it does not descend into 1444 the current directory. */ 1445 our_pred->side_effects = true; 1446 our_pred->no_default_print = false; 1447 return true; 1448} 1449 1450static boolean 1451parse_quit (const struct parser_table* entry, char **argv, int *arg_ptr) 1452{ 1453 struct predicate *our_pred = insert_primary (entry); 1454 (void) argv; 1455 (void) arg_ptr; 1456 our_pred->need_stat = our_pred->need_type = false; 1457 our_pred->side_effects = true; /* Exiting is a side effect... */ 1458 our_pred->no_default_print = false; /* Don't inhibit the default print, though. */ 1459 return true; 1460} 1461 1462 1463static boolean 1464parse_regextype (const struct parser_table* entry, char **argv, int *arg_ptr) 1465{ 1466 if ((argv == NULL) || (argv[*arg_ptr] == NULL)) 1467 return false; 1468 1469 /* collect the regex type name */ 1470 options.regex_options = get_regex_type(argv[*arg_ptr]); 1471 (*arg_ptr)++; 1472 1473 return true; 1474} 1475 1476 1477static boolean 1478parse_regex (const struct parser_table* entry, char **argv, int *arg_ptr) 1479{ 1480 return insert_regex (argv, arg_ptr, entry, options.regex_options); 1481} 1482 1483static boolean 1484insert_regex (char **argv, int *arg_ptr, const struct parser_table *entry, int regex_options) 1485{ 1486 struct predicate *our_pred; 1487 struct re_pattern_buffer *re; 1488 const char *error_message; 1489 1490 if ((argv == NULL) || (argv[*arg_ptr] == NULL)) 1491 return false; 1492 our_pred = insert_primary_withpred (entry, pred_regex); 1493 our_pred->need_stat = our_pred->need_type = false; 1494 re = (struct re_pattern_buffer *) 1495 xmalloc (sizeof (struct re_pattern_buffer)); 1496 our_pred->args.regex = re; 1497 re->allocated = 100; 1498 re->buffer = (unsigned char *) xmalloc (re->allocated); 1499 re->fastmap = NULL; 1500 1501 re_set_syntax(regex_options); 1502 re->syntax = regex_options; 1503 re->translate = NULL; 1504 1505 error_message = re_compile_pattern (argv[*arg_ptr], strlen (argv[*arg_ptr]), 1506 re); 1507 if (error_message) 1508 error (1, 0, "%s", error_message); 1509 (*arg_ptr)++; 1510 return true; 1511} 1512 1513static boolean 1514parse_size (const struct parser_table* entry, char **argv, int *arg_ptr) 1515{ 1516 struct predicate *our_pred; 1517 uintmax_t num; 1518 enum comparison_type c_type; 1519 int blksize = 512; 1520 int len; 1521 1522 if ((argv == NULL) || (argv[*arg_ptr] == NULL)) 1523 return false; 1524 len = strlen (argv[*arg_ptr]); 1525 if (len == 0) 1526 error (1, 0, _("invalid null argument to -size")); 1527 switch (argv[*arg_ptr][len - 1]) 1528 { 1529 case 'b': 1530 blksize = 512; 1531 argv[*arg_ptr][len - 1] = '\0'; 1532 break; 1533 1534 case 'c': 1535 blksize = 1; 1536 argv[*arg_ptr][len - 1] = '\0'; 1537 break; 1538 1539 case 'k': 1540 blksize = 1024; 1541 argv[*arg_ptr][len - 1] = '\0'; 1542 break; 1543 1544 case 'M': /* Megabytes */ 1545 blksize = 1024*1024; 1546 argv[*arg_ptr][len - 1] = '\0'; 1547 break; 1548 1549 case 'G': /* Gigabytes */ 1550 blksize = 1024*1024*1024; 1551 argv[*arg_ptr][len - 1] = '\0'; 1552 break; 1553 1554 case 'w': 1555 blksize = 2; 1556 argv[*arg_ptr][len - 1] = '\0'; 1557 break; 1558 1559 case '0': 1560 case '1': 1561 case '2': 1562 case '3': 1563 case '4': 1564 case '5': 1565 case '6': 1566 case '7': 1567 case '8': 1568 case '9': 1569 break; 1570 1571 default: 1572 error (1, 0, _("invalid -size type `%c'"), argv[*arg_ptr][len - 1]); 1573 } 1574 if (!get_num (argv[*arg_ptr], &num, &c_type)) 1575 return false; 1576 our_pred = insert_primary (entry); 1577 our_pred->args.size.kind = c_type; 1578 our_pred->args.size.blocksize = blksize; 1579 our_pred->args.size.size = num; 1580 (*arg_ptr)++; 1581 return true; 1582} 1583 1584 1585static boolean 1586parse_samefile (const struct parser_table* entry, char **argv, int *arg_ptr) 1587{ 1588 struct predicate *our_pred; 1589 struct stat st; 1590 1591 if ((argv == NULL) || (argv[*arg_ptr] == NULL)) 1592 return false; 1593 if ((*options.xstat) (argv[*arg_ptr], &st)) 1594 error (1, errno, "%s", argv[*arg_ptr]); 1595 1596 our_pred = insert_primary (entry); 1597 our_pred->args.fileid.ino = st.st_ino; 1598 our_pred->args.fileid.dev = st.st_dev; 1599 our_pred->need_type = false; 1600 our_pred->need_stat = true; 1601 (*arg_ptr)++; 1602 return true; 1603} 1604 1605 1606static boolean 1607parse_true (const struct parser_table* entry, char **argv, int *arg_ptr) 1608{ 1609 struct predicate *our_pred; 1610 1611 (void) argv; 1612 (void) arg_ptr; 1613 1614 our_pred = insert_primary (entry); 1615 our_pred->need_stat = our_pred->need_type = false; 1616 return true; 1617} 1618 1619static boolean 1620parse_type (const struct parser_table* entry, char **argv, int *arg_ptr) 1621{ 1622 return insert_type (argv, arg_ptr, entry, pred_type); 1623} 1624 1625static boolean 1626parse_uid (const struct parser_table* entry, char **argv, int *arg_ptr) 1627{ 1628 return insert_num (argv, arg_ptr, entry); 1629} 1630 1631static boolean 1632parse_used (const struct parser_table* entry, char **argv, int *arg_ptr) 1633{ 1634 struct predicate *our_pred; 1635 uintmax_t num_days; 1636 enum comparison_type c_type; 1637 time_t t; 1638 1639 if ((argv == NULL) || (argv[*arg_ptr] == NULL)) 1640 return false; 1641 if (!get_num (argv[*arg_ptr], &num_days, &c_type)) 1642 return false; 1643 t = num_days * DAYSECS; 1644 our_pred = insert_primary (entry); 1645 our_pred->args.info.kind = c_type; 1646 our_pred->args.info.negative = t < 0; 1647 our_pred->args.info.l_val = t; 1648 (*arg_ptr)++; 1649 return true; 1650} 1651 1652static boolean 1653parse_user (const struct parser_table* entry, char **argv, int *arg_ptr) 1654{ 1655 struct passwd *cur_pwd; 1656 struct predicate *our_pred; 1657 uid_t uid; 1658 int uid_len; 1659 1660 if ((argv == NULL) || (argv[*arg_ptr] == NULL)) 1661 return false; 1662 cur_pwd = getpwnam (argv[*arg_ptr]); 1663 endpwent (); 1664 if (cur_pwd != NULL) 1665 uid = cur_pwd->pw_uid; 1666 else 1667 { 1668 uid_len = strspn (argv[*arg_ptr], "0123456789"); 1669 if ((uid_len == 0) || (argv[*arg_ptr][uid_len] != '\0')) 1670 return false; 1671 uid = atoi (argv[*arg_ptr]); 1672 } 1673 our_pred = insert_primary (entry); 1674 our_pred->args.uid = uid; 1675 (*arg_ptr)++; 1676 return true; 1677} 1678 1679static boolean 1680parse_version (const struct parser_table* entry, char **argv, int *arg_ptr) 1681{ 1682 extern char *version_string; 1683 int features = 0; 1684 1685 (void) argv; 1686 (void) arg_ptr; 1687 (void) entry; 1688 1689 fflush (stderr); 1690 printf (_("GNU find version %s\n"), version_string); 1691 printf (_("Built using GNU gnulib version %s\n"), gnulib_version); 1692 printf (_("Features enabled: ")); 1693 1694#if CACHE_IDS 1695 printf("CACHE_IDS "); 1696 ++features; 1697#endif 1698#if DEBUG 1699 printf("DEBUG "); 1700 ++features; 1701#endif 1702#if DEBUG_STAT 1703 printf("DEBUG_STAT "); 1704 ++features; 1705#endif 1706#if defined(USE_STRUCT_DIRENT_D_TYPE) && defined(HAVE_STRUCT_DIRENT_D_TYPE) 1707 printf("D_TYPE "); 1708 ++features; 1709#endif 1710#if defined(O_NOFOLLOW) 1711 printf("O_NOFOLLOW(%s) ", 1712 (options.open_nofollow_available ? "enabled" : "disabled")); 1713 ++features; 1714#endif 1715#if defined(LEAF_OPTIMISATION) 1716 printf("LEAF_OPTIMISATION "); 1717 ++features; 1718#endif 1719 if (0 == features) 1720 { 1721 /* For the moment, leave this as English in case someone wants 1722 to parse these strings. */ 1723 printf("none"); 1724 } 1725 printf("\n"); 1726 1727 exit (0); 1728} 1729 1730static boolean 1731parse_xdev (const struct parser_table* entry, char **argv, int *arg_ptr) 1732{ 1733 (void) argv; 1734 (void) arg_ptr; 1735 (void) entry; 1736 options.stay_on_filesystem = true; 1737 return true; 1738} 1739 1740static boolean 1741parse_ignore_race (const struct parser_table* entry, char **argv, int *arg_ptr) 1742{ 1743 (void) argv; 1744 (void) arg_ptr; 1745 (void) entry; 1746 options.ignore_readdir_race = true; 1747 return true; 1748} 1749 1750static boolean 1751parse_noignore_race (const struct parser_table* entry, char **argv, int *arg_ptr) 1752{ 1753 (void) argv; 1754 (void) arg_ptr; 1755 (void) entry; 1756 options.ignore_readdir_race = false; 1757 return true; 1758} 1759 1760static boolean 1761parse_warn (const struct parser_table* entry, char **argv, int *arg_ptr) 1762{ 1763 (void) argv; 1764 (void) arg_ptr; 1765 (void) entry; 1766 options.warnings = true; 1767 return true; 1768} 1769 1770static boolean 1771parse_xtype (const struct parser_table* entry, char **argv, int *arg_ptr) 1772{ 1773 (void) argv; 1774 (void) arg_ptr; 1775 return insert_type (argv, arg_ptr, entry, pred_xtype); 1776} 1777 1778static boolean 1779insert_type (char **argv, int *arg_ptr, const struct parser_table *entry, PRED_FUNC which_pred) 1780{ 1781 mode_t type_cell; 1782 struct predicate *our_pred; 1783 1784 if ((argv == NULL) || (argv[*arg_ptr] == NULL) 1785 || (strlen (argv[*arg_ptr]) != 1)) 1786 return false; 1787 switch (argv[*arg_ptr][0]) 1788 { 1789 case 'b': /* block special */ 1790 type_cell = S_IFBLK; 1791 break; 1792 case 'c': /* character special */ 1793 type_cell = S_IFCHR; 1794 break; 1795 case 'd': /* directory */ 1796 type_cell = S_IFDIR; 1797 break; 1798 case 'f': /* regular file */ 1799 type_cell = S_IFREG; 1800 break; 1801#ifdef S_IFLNK 1802 case 'l': /* symbolic link */ 1803 type_cell = S_IFLNK; 1804 break; 1805#endif 1806#ifdef S_IFIFO 1807 case 'p': /* pipe */ 1808 type_cell = S_IFIFO; 1809 break; 1810#endif 1811#ifdef S_IFSOCK 1812 case 's': /* socket */ 1813 type_cell = S_IFSOCK; 1814 break; 1815#endif 1816#ifdef S_IFDOOR 1817 case 'D': /* Solaris door */ 1818 type_cell = S_IFDOOR; 1819 break; 1820#endif 1821 default: /* None of the above ... nuke 'em. */ 1822 return false; 1823 } 1824 our_pred = insert_primary_withpred (entry, which_pred); 1825 1826 /* Figure out if we will need to stat the file, because if we don't 1827 * need to follow symlinks, we can avoid a stat call by using 1828 * struct dirent.d_type. 1829 */ 1830 if (which_pred == pred_xtype) 1831 { 1832 our_pred->need_stat = true; 1833 our_pred->need_type = false; 1834 } 1835 else 1836 { 1837 our_pred->need_stat = false; /* struct dirent is enough */ 1838 our_pred->need_type = true; 1839 } 1840 our_pred->args.type = type_cell; 1841 (*arg_ptr)++; /* Move on to next argument. */ 1842 return true; 1843} 1844 1845 1846/* Return true if the file accessed via FP is a terminal. 1847 */ 1848static boolean 1849stream_is_tty(FILE *fp) 1850{ 1851 int fd = fileno(fp); 1852 if (-1 == fd) 1853 { 1854 return false; /* not a valid stream */ 1855 } 1856 else 1857 { 1858 return isatty(fd) ? true : false; 1859 } 1860 1861} 1862 1863 1864 1865/* If true, we've determined that the current fprintf predicate 1866 uses stat information. */ 1867static boolean fprintf_stat_needed; 1868 1869/* XXX: do we need to pass FUNC to this function? */ 1870static boolean 1871insert_fprintf (FILE *fp, const struct parser_table *entry, PRED_FUNC func, char **argv, int *arg_ptr) 1872{ 1873 char *format; /* Beginning of unprocessed format string. */ 1874 register char *scan; /* Current address in scanning `format'. */ 1875 register char *scan2; /* Address inside of element being scanned. */ 1876 struct segment **segmentp; /* Address of current segment. */ 1877 struct predicate *our_pred; 1878 1879 format = argv[(*arg_ptr)++]; 1880 1881 fprintf_stat_needed = false; /* Might be overridden later. */ 1882 our_pred = insert_primary_withpred (entry, func); 1883 our_pred->side_effects = our_pred->no_default_print = true; 1884 our_pred->args.printf_vec.stream = fp; 1885 our_pred->args.printf_vec.dest_is_tty = stream_is_tty(fp); 1886 our_pred->args.printf_vec.quote_opts = clone_quoting_options (NULL); 1887 segmentp = &our_pred->args.printf_vec.segment; 1888 *segmentp = NULL; 1889 1890 for (scan = format; *scan; scan++) 1891 { 1892 if (*scan == '\\') 1893 { 1894 scan2 = scan + 1; 1895 if (*scan2 >= '0' && *scan2 <= '7') 1896 { 1897 register int n, i; 1898 1899 for (i = n = 0; i < 3 && (*scan2 >= '0' && *scan2 <= '7'); 1900 i++, scan2++) 1901 n = 8 * n + *scan2 - '0'; 1902 scan2--; 1903 *scan = n; 1904 } 1905 else 1906 { 1907 switch (*scan2) 1908 { 1909 case 'a': 1910 *scan = 7; 1911 break; 1912 case 'b': 1913 *scan = '\b'; 1914 break; 1915 case 'c': 1916 make_segment (segmentp, format, scan - format, KIND_STOP); 1917 our_pred->need_stat = fprintf_stat_needed; 1918 return true; 1919 case 'f': 1920 *scan = '\f'; 1921 break; 1922 case 'n': 1923 *scan = '\n'; 1924 break; 1925 case 'r': 1926 *scan = '\r'; 1927 break; 1928 case 't': 1929 *scan = '\t'; 1930 break; 1931 case 'v': 1932 *scan = '\v'; 1933 break; 1934 case '\\': 1935 /* *scan = '\\'; * it already is */ 1936 break; 1937 default: 1938 error (0, 0, 1939 _("warning: unrecognized escape `\\%c'"), *scan2); 1940 scan++; 1941 continue; 1942 } 1943 } 1944 segmentp = make_segment (segmentp, format, scan - format + 1, 1945 KIND_PLAIN); 1946 format = scan2 + 1; /* Move past the escape. */ 1947 scan = scan2; /* Incremented immediately by `for'. */ 1948 } 1949 else if (*scan == '%') 1950 { 1951 if (scan[1] == 0) 1952 { 1953 /* Trailing %. We don't like those. */ 1954 error (1, 0, _("error: %s at end of format string"), scan); 1955 } 1956 else if (scan[1] == '%') 1957 { 1958 segmentp = make_segment (segmentp, format, scan - format + 1, 1959 KIND_PLAIN); 1960 scan++; 1961 format = scan + 1; 1962 continue; 1963 } 1964 /* Scan past flags, width and precision, to verify kind. */ 1965 for (scan2 = scan; *++scan2 && strchr ("-+ #", *scan2);) 1966 /* Do nothing. */ ; 1967 while (ISDIGIT (*scan2)) 1968 scan2++; 1969 if (*scan2 == '.') 1970 for (scan2++; ISDIGIT (*scan2); scan2++) 1971 /* Do nothing. */ ; 1972 if (strchr ("abcdDfFgGhHiklmMnpPstuUyY", *scan2)) 1973 { 1974 segmentp = make_segment (segmentp, format, scan2 - format, 1975 (int) *scan2); 1976 scan = scan2; 1977 format = scan + 1; 1978 } 1979 else if (strchr ("ACT", *scan2) && scan2[1]) 1980 { 1981 segmentp = make_segment (segmentp, format, scan2 - format, 1982 *scan2 | (scan2[1] << 8)); 1983 scan = scan2 + 1; 1984 format = scan + 1; 1985 continue; 1986 } 1987 else 1988 { 1989 /* An unrecognized % escape. Print the char after the %. */ 1990 error (0, 0, _("warning: unrecognized format directive `%%%c'"), 1991 *scan2); 1992 segmentp = make_segment (segmentp, format, scan - format, 1993 KIND_PLAIN); 1994 format = scan + 1; 1995 continue; 1996 } 1997 } 1998 } 1999 2000 if (scan > format) 2001 make_segment (segmentp, format, scan - format, KIND_PLAIN); 2002 our_pred->need_type = false; 2003 our_pred->need_stat = fprintf_stat_needed; 2004 return true; 2005} 2006 2007/* Create a new fprintf segment in *SEGMENT, with type KIND, 2008 from the text in FORMAT, which has length LEN. 2009 Return the address of the `next' pointer of the new segment. */ 2010 2011static struct segment ** 2012make_segment (struct segment **segment, char *format, int len, int kind) 2013{ 2014 char *fmt; 2015 2016 *segment = (struct segment *) xmalloc (sizeof (struct segment)); 2017 2018 (*segment)->kind = kind; 2019 (*segment)->next = NULL; 2020 (*segment)->text_len = len; 2021 2022 fmt = (*segment)->text = xmalloc (len + sizeof "d"); 2023 strncpy (fmt, format, len); 2024 fmt += len; 2025 2026 switch (kind & 0xff) 2027 { 2028 case KIND_PLAIN: /* Plain text string, no % conversion. */ 2029 case KIND_STOP: /* Terminate argument, no newline. */ 2030 break; 2031 2032 case 'a': /* atime in `ctime' format */ 2033 case 'A': /* atime in user-specified strftime format */ 2034 case 'c': /* ctime in `ctime' format */ 2035 case 'C': /* ctime in user-specified strftime format */ 2036 case 'F': /* filesystem type */ 2037 case 'g': /* group name */ 2038 case 'i': /* inode number */ 2039 case 'l': /* object of symlink */ 2040 case 'M': /* mode in `ls -l' format (eg., "drwxr-xr-x") */ 2041 case 's': /* size in bytes */ 2042 case 't': /* mtime in `ctime' format */ 2043 case 'T': /* mtime in user-specified strftime format */ 2044 case 'u': /* user name */ 2045 case 'y': /* file type */ 2046 case 'Y': /* symlink pointed file type */ 2047 fprintf_stat_needed = true; 2048 /* FALLTHROUGH */ 2049 case 'f': /* basename of path */ 2050 case 'h': /* leading directories part of path */ 2051 case 'H': /* ARGV element file was found under */ 2052 case 'p': /* pathname */ 2053 case 'P': /* pathname with ARGV element stripped */ 2054 *fmt++ = 's'; 2055 break; 2056 2057 /* Numeric items that one might expect to honour 2058 * #, 0, + flags but which do not. 2059 */ 2060 case 'G': /* GID number */ 2061 case 'U': /* UID number */ 2062 case 'b': /* size in 512-byte blocks */ 2063 case 'D': /* Filesystem device on which the file exits */ 2064 case 'k': /* size in 1K blocks */ 2065 case 'n': /* number of links */ 2066 fprintf_stat_needed = true; 2067 *fmt++ = 's'; 2068 break; 2069 2070 /* Numeric items that DO honour #, 0, + flags. 2071 */ 2072 case 'd': /* depth in search tree (0 = ARGV element) */ 2073 *fmt++ = 'd'; 2074 break; 2075 2076 case 'm': /* mode as octal number (perms only) */ 2077 *fmt++ = 'o'; 2078 fprintf_stat_needed = true; 2079 break; 2080 } 2081 *fmt = '\0'; 2082 2083 return &(*segment)->next; 2084} 2085 2086static void 2087check_path_safety(const char *action) 2088{ 2089 const char *path = getenv("PATH"); 2090 char *s; 2091 s = next_element(path, 1); 2092 while ((s = next_element ((char *) NULL, 1)) != NULL) 2093 { 2094 if (0 == strcmp(s, ".")) 2095 { 2096 error(1, 0, _("The current directory is included in the PATH environment variable, which is insecure in combination with the %s action of find. Please remove the current directory from your $PATH (that is, remove \".\" or leading or trailing colons)"), 2097 action); 2098 } 2099 } 2100} 2101 2102 2103/* handles both exec and ok predicate */ 2104#if defined(NEW_EXEC) 2105/* handles both exec and ok predicate */ 2106static boolean 2107new_insert_exec_ok (const char *action, 2108 const struct parser_table *entry, 2109 char **argv, 2110 int *arg_ptr) 2111{ 2112 int start, end; /* Indexes in ARGV of start & end of cmd. */ 2113 int i; /* Index into cmd args */ 2114 int saw_braces; /* True if previous arg was '{}'. */ 2115 boolean allow_plus; /* True if + is a valid terminator */ 2116 int brace_count; /* Number of instances of {}. */ 2117 PRED_FUNC func = entry->pred_func; 2118 enum BC_INIT_STATUS bcstatus; 2119 2120 struct predicate *our_pred; 2121 struct exec_val *execp; /* Pointer for efficiency. */ 2122 2123 if ((argv == NULL) || (argv[*arg_ptr] == NULL)) 2124 return false; 2125 2126 our_pred = insert_primary_withpred (entry, func); 2127 our_pred->side_effects = our_pred->no_default_print = true; 2128 execp = &our_pred->args.exec_vec; 2129 2130 if ((func != pred_okdir) && (func != pred_ok)) 2131 { 2132 allow_plus = true; 2133 execp->close_stdin = false; 2134 } 2135 else 2136 { 2137 allow_plus = false; 2138 /* If find reads stdin (i.e. for -ok and similar), close stdin 2139 * in the child to prevent some script from consiming the output 2140 * intended for find. 2141 */ 2142 execp->close_stdin = true; 2143 } 2144 2145 2146 if ((func == pred_execdir) || (func == pred_okdir)) 2147 { 2148 options.ignore_readdir_race = false; 2149 check_path_safety(action); 2150 execp->use_current_dir = true; 2151 } 2152 else 2153 { 2154 execp->use_current_dir = false; 2155 } 2156 2157 our_pred->args.exec_vec.multiple = 0; 2158 2159 /* Count the number of args with path replacements, up until the ';'. 2160 * Also figure out if the command is terminated by ";" or by "+". 2161 */ 2162 start = *arg_ptr; 2163 for (end = start, saw_braces=0, brace_count=0; 2164 (argv[end] != NULL) 2165 && ((argv[end][0] != ';') || (argv[end][1] != '\0')); 2166 end++) 2167 { 2168 /* For -exec and -execdir, "{} +" can terminate the command. */ 2169 if ( allow_plus 2170 && argv[end][0] == '+' && argv[end][1] == 0 2171 && saw_braces) 2172 { 2173 our_pred->args.exec_vec.multiple = 1; 2174 break; 2175 } 2176 2177 saw_braces = 0; 2178 if (strstr (argv[end], "{}")) 2179 { 2180 saw_braces = 1; 2181 ++brace_count; 2182 2183 if (0 == end && (func == pred_execdir || func == pred_okdir)) 2184 { 2185 /* The POSIX standard says that {} replacement should 2186 * occur even in the utility name. This is insecure 2187 * since it means we will be executing a command whose 2188 * name is chosen according to whatever find finds in 2189 * the filesystem. That can be influenced by an 2190 * attacker. Hence for -execdir and -okdir this is not 2191 * allowed. We can specify this as those options are 2192 * not defined by POSIX. 2193 */ 2194 error(1, 0, _("You may not use {} within the utility name for -execdir and -okdir, because this is a potential security problem.")); 2195 } 2196 } 2197 } 2198 2199 /* Fail if no command given or no semicolon found. */ 2200 if ((end == start) || (argv[end] == NULL)) 2201 { 2202 *arg_ptr = end; 2203 free(our_pred); 2204 return false; 2205 } 2206 2207 if (our_pred->args.exec_vec.multiple && brace_count > 1) 2208 { 2209 2210 const char *suffix; 2211 if (func == pred_execdir) 2212 suffix = "dir"; 2213 else 2214 suffix = ""; 2215 2216 error(1, 0, 2217 _("Only one instance of {} is supported with -exec%s ... +"), 2218 suffix); 2219 } 2220 2221 /* We use a switch statement here so that 2222 * the compiler warns us when we forget to handle a 2223 * newly invented enum value. 2224 */ 2225 bcstatus = bc_init_controlinfo(&execp->ctl); 2226 switch (bcstatus) 2227 { 2228 case BC_INIT_ENV_TOO_BIG: 2229 error(1, 0, 2230 _("The environment is too large for exec().")); 2231 break; 2232 case BC_INIT_OK: 2233 /* Good news. Carry on. */ 2234 break; 2235 } 2236 bc_use_sensible_arg_max(&execp->ctl); 2237 2238 2239 execp->ctl.exec_callback = launch; 2240 2241 if (our_pred->args.exec_vec.multiple) 2242 { 2243 /* "+" terminator, so we can just append our arguments after the 2244 * command and initial arguments. 2245 */ 2246 execp->replace_vec = NULL; 2247 execp->ctl.replace_pat = NULL; 2248 execp->ctl.rplen = 0; 2249 execp->ctl.lines_per_exec = 0; /* no limit */ 2250 execp->ctl.args_per_exec = 0; /* no limit */ 2251 2252 /* remember how many arguments there are */ 2253 execp->ctl.initial_argc = (end-start) - 1; 2254 2255 /* execp->state = xmalloc(sizeof struct buildcmd_state); */ 2256 bc_init_state(&execp->ctl, &execp->state, execp); 2257 2258 /* Gather the initial arguments. Skip the {}. */ 2259 for (i=start; i<end-1; ++i) 2260 { 2261 bc_push_arg(&execp->ctl, &execp->state, 2262 argv[i], strlen(argv[i])+1, 2263 NULL, 0, 2264 1); 2265 } 2266 } 2267 else 2268 { 2269 /* Semicolon terminator - more than one {} is supported, so we 2270 * have to do brace-replacement. 2271 */ 2272 execp->num_args = end - start; 2273 2274 execp->ctl.replace_pat = "{}"; 2275 execp->ctl.rplen = strlen(execp->ctl.replace_pat); 2276 execp->ctl.lines_per_exec = 0; /* no limit */ 2277 execp->ctl.args_per_exec = 0; /* no limit */ 2278 execp->replace_vec = xmalloc(sizeof(char*)*execp->num_args); 2279 2280 2281 /* execp->state = xmalloc(sizeof(*(execp->state))); */ 2282 bc_init_state(&execp->ctl, &execp->state, execp); 2283 2284 /* Remember the (pre-replacement) arguments for later. */ 2285 for (i=0; i<execp->num_args; ++i) 2286 { 2287 execp->replace_vec[i] = argv[i+start]; 2288 } 2289 } 2290 2291 if (argv[end] == NULL) 2292 *arg_ptr = end; 2293 else 2294 *arg_ptr = end + 1; 2295 2296 return true; 2297} 2298#else 2299/* handles both exec and ok predicate */ 2300static boolean 2301old_insert_exec_ok (boolean (*func) (/* ??? */), char **argv, int *arg_ptr) 2302{ 2303 int start, end; /* Indexes in ARGV of start & end of cmd. */ 2304 int num_paths; /* Number of args with path replacements. */ 2305 int path_pos; /* Index in array of path replacements. */ 2306 int vec_pos; /* Index in array of args. */ 2307 struct predicate *our_pred; 2308 struct exec_val *execp; /* Pointer for efficiency. */ 2309 2310 if ((argv == NULL) || (argv[*arg_ptr] == NULL)) 2311 return false; 2312 2313 /* Count the number of args with path replacements, up until the ';'. */ 2314 start = *arg_ptr; 2315 for (end = start, num_paths = 0; 2316 (argv[end] != NULL) 2317 && ((argv[end][0] != ';') || (argv[end][1] != '\0')); 2318 end++) 2319 if (strstr (argv[end], "{}")) 2320 num_paths++; 2321 /* Fail if no command given or no semicolon found. */ 2322 if ((end == start) || (argv[end] == NULL)) 2323 { 2324 *arg_ptr = end; 2325 return false; 2326 } 2327 2328 our_pred = insert_primary (func); 2329 our_pred->side_effects = our_pred->no_default_print = true; 2330 execp = &our_pred->args.exec_vec; 2331 execp->usercontext = our_pred; 2332 execp->use_current_dir = false; 2333 execp->paths = 2334 (struct path_arg *) xmalloc (sizeof (struct path_arg) * (num_paths + 1)); 2335 execp->vec = (char **) xmalloc (sizeof (char *) * (end - start + 1)); 2336 /* Record the positions of all args, and the args with path replacements. */ 2337 for (end = start, path_pos = vec_pos = 0; 2338 (argv[end] != NULL) 2339 && ((argv[end][0] != ';') || (argv[end][1] != '\0')); 2340 end++) 2341 { 2342 register char *p; 2343 2344 execp->paths[path_pos].count = 0; 2345 for (p = argv[end]; *p; ++p) 2346 if (p[0] == '{' && p[1] == '}') 2347 { 2348 execp->paths[path_pos].count++; 2349 ++p; 2350 } 2351 if (execp->paths[path_pos].count) 2352 { 2353 execp->paths[path_pos].offset = vec_pos; 2354 execp->paths[path_pos].origarg = argv[end]; 2355 path_pos++; 2356 } 2357 execp->vec[vec_pos++] = argv[end]; 2358 } 2359 execp->paths[path_pos].offset = -1; 2360 execp->vec[vec_pos] = NULL; 2361 2362 if (argv[end] == NULL) 2363 *arg_ptr = end; 2364 else 2365 *arg_ptr = end + 1; 2366 return true; 2367} 2368#endif 2369 2370 2371 2372static boolean 2373insert_exec_ok (const char *action, const struct parser_table *entry, char **argv, int *arg_ptr) 2374{ 2375#if defined(NEW_EXEC) 2376 return new_insert_exec_ok(action, entry, argv, arg_ptr); 2377#else 2378 return old_insert_exec_ok(func, argv, arg_ptr); 2379#endif 2380} 2381 2382 2383 2384/* Get a number of days and comparison type. 2385 STR is the ASCII representation. 2386 Set *NUM_DAYS to the number of days, taken as being from 2387 the current moment (or possibly midnight). Thus the sense of the 2388 comparison type appears to be reversed. 2389 Set *COMP_TYPE to the kind of comparison that is requested. 2390 2391 Return true if all okay, false if input error. 2392 2393 Used by -atime, -ctime and -mtime (parsers) to 2394 get the appropriate information for a time predicate processor. */ 2395 2396static boolean 2397get_num_days (char *str, uintmax_t *num_days, enum comparison_type *comp_type) 2398{ 2399 boolean r = get_num (str, num_days, comp_type); 2400 if (r) 2401 switch (*comp_type) 2402 { 2403 case COMP_LT: *comp_type = COMP_GT; break; 2404 case COMP_GT: *comp_type = COMP_LT; break; 2405 default: break; 2406 } 2407 return r; 2408} 2409 2410/* Insert a time predicate PRED. 2411 ARGV is a pointer to the argument array. 2412 ARG_PTR is a pointer to an index into the array, incremented if 2413 all went well. 2414 2415 Return true if input is valid, false if not. 2416 2417 A new predicate node is assigned, along with an argument node 2418 obtained with malloc. 2419 2420 Used by -atime, -ctime, and -mtime parsers. */ 2421 2422static boolean 2423insert_time (char **argv, int *arg_ptr, const struct parser_table* entry, PRED_FUNC pred) 2424{ 2425 struct predicate *our_pred; 2426 uintmax_t num_days; 2427 enum comparison_type c_type; 2428 time_t t; 2429 2430 if ((argv == NULL) || (argv[*arg_ptr] == NULL)) 2431 return false; 2432 if (!get_num_days (argv[*arg_ptr], &num_days, &c_type)) 2433 return false; 2434 2435 /* Figure out the timestamp value we are looking for. */ 2436 t = ( options.cur_day_start - num_days * DAYSECS 2437 + ((c_type == COMP_GT) ? DAYSECS - 1 : 0)); 2438 2439 if (1) 2440 { 2441 /* We introduce a scope in which 'val' can be declared, for the 2442 * benefit of compilers that are really C89 compilers 2443 * which support intmax_t because config.h #defines it 2444 */ 2445 intmax_t val = ( (intmax_t)options.cur_day_start - num_days * DAYSECS 2446 + ((c_type == COMP_GT) ? DAYSECS - 1 : 0)); 2447 t = val; 2448 2449 /* Check for possibility of an overflow */ 2450 if ( (intmax_t)t != val ) 2451 { 2452 error (1, 0, "arithmetic overflow while converting %s days to a number of seconds", argv[*arg_ptr]); 2453 } 2454 } 2455 2456 our_pred = insert_primary_withpred (entry, pred); 2457 our_pred->args.info.kind = c_type; 2458 our_pred->args.info.negative = t < 0; 2459 our_pred->args.info.l_val = t; 2460 (*arg_ptr)++; 2461#ifdef DEBUG 2462 fprintf (stderr, "inserting %s\n", our_pred->p_name); 2463 fprintf (stderr, " type: %s %s ", 2464 (c_type == COMP_GT) ? "gt" : 2465 ((c_type == COMP_LT) ? "lt" : ((c_type == COMP_EQ) ? "eq" : "?")), 2466 (c_type == COMP_GT) ? " >" : 2467 ((c_type == COMP_LT) ? " <" : ((c_type == COMP_EQ) ? ">=" : " ?"))); 2468 t = our_pred->args.info.l_val; 2469 fprintf (stderr, "%ju %s", (uintmax_t) our_pred->args.info.l_val, ctime (&t)); 2470 if (c_type == COMP_EQ) 2471 { 2472 t = our_pred->args.info.l_val += DAYSECS; 2473 fprintf (stderr, " < %ju %s", 2474 (uintmax_t) our_pred->args.info.l_val, ctime (&t)); 2475 our_pred->args.info.l_val -= DAYSECS; 2476 } 2477#endif /* DEBUG */ 2478 return true; 2479} 2480 2481/* Get a number with comparison information. 2482 The sense of the comparison information is 'normal'; that is, 2483 '+' looks for a count > than the number and '-' less than. 2484 2485 STR is the ASCII representation of the number. 2486 Set *NUM to the number. 2487 Set *COMP_TYPE to the kind of comparison that is requested. 2488 2489 Return true if all okay, false if input error. */ 2490 2491static boolean 2492get_num (char *str, uintmax_t *num, enum comparison_type *comp_type) 2493{ 2494 if (str == NULL) 2495 return false; 2496 switch (str[0]) 2497 { 2498 case '+': 2499 *comp_type = COMP_GT; 2500 str++; 2501 break; 2502 case '-': 2503 *comp_type = COMP_LT; 2504 str++; 2505 break; 2506 default: 2507 *comp_type = COMP_EQ; 2508 break; 2509 } 2510 2511 return xstrtoumax (str, NULL, 10, num, "") == LONGINT_OK; 2512} 2513 2514/* Insert a number predicate. 2515 ARGV is a pointer to the argument array. 2516 *ARG_PTR is an index into ARGV, incremented if all went well. 2517 *PRED is the predicate processor to insert. 2518 2519 Return true if input is valid, false if error. 2520 2521 A new predicate node is assigned, along with an argument node 2522 obtained with malloc. 2523 2524 Used by -inum and -links parsers. */ 2525 2526static boolean 2527insert_num (char **argv, int *arg_ptr, const struct parser_table *entry) 2528{ 2529 struct predicate *our_pred; 2530 uintmax_t num; 2531 enum comparison_type c_type; 2532 2533 if ((argv == NULL) || (argv[*arg_ptr] == NULL)) 2534 return false; 2535 if (!get_num (argv[*arg_ptr], &num, &c_type)) 2536 return false; 2537 our_pred = insert_primary (entry); 2538 our_pred->args.info.kind = c_type; 2539 our_pred->args.info.l_val = num; 2540 (*arg_ptr)++; 2541#ifdef DEBUG 2542 fprintf (stderr, "inserting %s\n", our_pred->p_name); 2543 fprintf (stderr, " type: %s %s ", 2544 (c_type == COMP_GT) ? "gt" : 2545 ((c_type == COMP_LT) ? "lt" : ((c_type == COMP_EQ) ? "eq" : "?")), 2546 (c_type == COMP_GT) ? " >" : 2547 ((c_type == COMP_LT) ? " <" : ((c_type == COMP_EQ) ? " =" : " ?"))); 2548 fprintf (stderr, "%ju\n", our_pred->args.info.l_val); 2549#endif /* DEBUG */ 2550 return true; 2551} 2552 2553static FILE * 2554open_output_file (char *path) 2555{ 2556 FILE *f; 2557 2558 if (!strcmp (path, "/dev/stderr")) 2559 return stderr; 2560 else if (!strcmp (path, "/dev/stdout")) 2561 return stdout; 2562 f = fopen_safer (path, "w"); 2563 if (f == NULL) 2564 error (1, errno, "%s", path); 2565 return f; 2566} 2567