Changeset 2725 in MondoRescue for branches/2.2.9/mindi-busybox/findutils
- Timestamp:
- Feb 25, 2011, 9:26:54 PM (14 years ago)
- Location:
- branches/2.2.9/mindi-busybox/findutils
- Files:
-
- 2 added
- 5 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/2.2.9/mindi-busybox/findutils/Config.in
r1765 r2725 1 # DO NOT EDIT. This file is generated from Config.src 1 2 # 2 3 # For a description of the syntax of this configuration file, … … 8 9 config FIND 9 10 bool "find" 10 default n11 default y 11 12 help 12 13 find is used to search your system to find specified files. 13 14 14 15 config FEATURE_FIND_PRINT0 15 bool "Enable -print0 option"16 default y 17 depends on FIND 18 help 19 Causes output names to be separated by a nullcharacter20 rather than a newline. 16 bool "Enable -print0: NUL-terminated output" 17 default y 18 depends on FIND 19 help 20 Causes output names to be separated by a NUL character 21 rather than a newline. This allows names that contain 21 22 newlines and other whitespace to be more easily 22 23 interpreted by other programs. 23 24 24 25 config FEATURE_FIND_MTIME 25 bool "Enable modified time matching (-mtime) option"26 bool "Enable -mtime: modified time matching" 26 27 default y 27 28 depends on FIND … … 31 32 32 33 config FEATURE_FIND_MMIN 33 bool "Enable modified time matching (-mmin) option"34 bool "Enable -mmin: modified time matching by minutes" 34 35 default y 35 36 depends on FIND … … 39 40 40 41 config FEATURE_FIND_PERM 41 bool "Enable permissions matching (-perm) option"42 bool "Enable -perm: permissions matching" 42 43 default y 43 44 depends on FIND … … 46 47 47 48 config FEATURE_FIND_TYPE 48 bool "Enable filetype matching (-type) option"49 bool "Enable -type: file type matching (file/dir/link/...)" 49 50 default y 50 51 depends on FIND … … 54 55 55 56 config FEATURE_FIND_XDEV 56 bool "Enable stay in filesystem (-xdev) option"57 bool "Enable -xdev: 'stay in filesystem'" 57 58 default y 58 59 depends on FIND … … 61 62 62 63 config FEATURE_FIND_MAXDEPTH 63 bool "Enable -maxdepth N option"64 bool "Enable -maxdepth N" 64 65 default y 65 66 depends on FIND … … 68 69 69 70 config FEATURE_FIND_NEWER 70 bool "Enable -newer option for comparing file mtimes"71 bool "Enable -newer: compare file modification times" 71 72 default y 72 73 depends on FIND … … 76 77 77 78 config FEATURE_FIND_INUM 78 bool "Enable inode number matching (-inum) option"79 bool "Enable -inum: inode number matching" 79 80 default y 80 81 depends on FIND … … 83 84 84 85 config FEATURE_FIND_EXEC 85 bool "Enable (-exec) option allowing execution ofcommands"86 bool "Enable -exec: execute commands" 86 87 default y 87 88 depends on FIND … … 91 92 92 93 config FEATURE_FIND_USER 93 bool "Enable username/uid matching (-user) option"94 bool "Enable -user: username/uid matching" 94 95 default y 95 96 depends on FIND … … 98 99 99 100 config FEATURE_FIND_GROUP 100 bool "Enable group/gid matching (-group) option"101 bool "Enable -group: group/gid matching" 101 102 default y 102 103 depends on FIND … … 114 115 115 116 config FEATURE_FIND_DEPTH 116 bool "Enable the -depth option"117 bool "Enable -depth" 117 118 default y 118 119 depends on FIND … … 128 129 129 130 config FEATURE_FIND_SIZE 130 bool "Enable (-size) option allowing matching for file size"131 bool "Enable -size: file size matching" 131 132 default y 132 133 depends on FIND … … 135 136 136 137 config FEATURE_FIND_PRUNE 137 bool "Enable (-prune) option allowing toexclude subdirectories"138 bool "Enable -prune: exclude subdirectories" 138 139 default y 139 140 depends on FIND … … 143 144 144 145 config FEATURE_FIND_DELETE 145 bool "Enable -delete option allowing to delete files"146 default n146 bool "Enable -delete: delete files/dirs" 147 default y 147 148 depends on FIND && FEATURE_FIND_DEPTH 148 149 help 149 Support the 'find -delete' option for deleting files and direc otries.150 Support the 'find -delete' option for deleting files and directories. 150 151 WARNING: This option can do much harm if used wrong. Busybox will not 151 152 try to protect the user from doing stupid things. Use with care. 152 153 153 154 config FEATURE_FIND_PATH 154 bool "Enable -path option allowing to match pathname patterns"155 bool "Enable -path: match pathname with shell pattern" 155 156 default y 156 157 depends on FIND … … 159 160 160 161 config FEATURE_FIND_REGEX 161 bool "Enable -regex: match pathname toregex"162 bool "Enable -regex: match pathname with regex" 162 163 default y 163 164 depends on FIND … … 166 167 167 168 config FEATURE_FIND_CONTEXT 168 bool "Enable (-context) option for matching security context"169 bool "Enable -context: security context matching" 169 170 default n 170 171 depends on FIND && SELINUX … … 172 173 Support the 'find -context' option for matching security context. 173 174 175 config FEATURE_FIND_LINKS 176 bool "Enable -links: link count matching" 177 default y 178 depends on FIND 179 help 180 Support the 'find -links' option for matching number of links. 174 181 config GREP 175 182 bool "grep" 176 default n183 default y 177 184 help 178 185 grep is used to search files for a specified pattern. 179 186 180 187 config FEATURE_GREP_EGREP_ALIAS 181 bool " Supportextended regular expressions (egrep & grep -E)"188 bool "Enable extended regular expressions (egrep & grep -E)" 182 189 default y 183 190 depends on GREP 184 191 help 185 Enabled support for extended regular expressions. 192 Enabled support for extended regular expressions. Extended 186 193 regular expressions allow for alternation (foo|bar), grouping, 187 194 and various repetition operators. … … 194 201 fgrep sees the search pattern as a normal string rather than 195 202 regular expressions. 196 grep -F is always builtin, this just creates the fgrep alias.203 grep -F always works, this just creates the fgrep alias. 197 204 198 205 config FEATURE_GREP_CONTEXT … … 204 211 context surrounding our matching lines. 205 212 Print the specified number of context lines (-C). 206 207 213 config XARGS 208 214 bool "xargs" 209 default n210 help 211 xargs is used to execute a specified command on215 default y 216 help 217 xargs is used to execute a specified command for 212 218 every item from standard input. 213 219 214 220 config FEATURE_XARGS_SUPPORT_CONFIRMATION 215 bool "Enable prompt and confirmation option -p"216 default n217 depends on XARGS 218 help 219 Support prompt the user aboutwhether to run each command221 bool "Enable -p: prompt and confirmation" 222 default y 223 depends on XARGS 224 help 225 Support -p: prompt the user whether to run each command 220 226 line and read a line from the terminal. 221 227 222 228 config FEATURE_XARGS_SUPPORT_QUOTES 223 bool "Enable support single and double quotes and backslash" 224 default n 225 depends on XARGS 226 help 227 Default xargs unsupport single and double quotes 228 and backslash for can use aruments with spaces. 229 bool "Enable single and double quotes and backslash" 230 default y 231 depends on XARGS 232 help 233 Support quoting in the input. 229 234 230 235 config FEATURE_XARGS_SUPPORT_TERMOPT 231 bool "Enable support options -x"232 default n233 depends on XARGS 234 help 235 Enable support exit if thesize (see the -s or -n option)236 bool "Enable -x: exit if -s or -n is exceeded" 237 default y 238 depends on XARGS 239 help 240 Support -x: exit if the command size (see the -s or -n option) 236 241 is exceeded. 237 242 238 243 config FEATURE_XARGS_SUPPORT_ZERO_TERM 239 bool "Enable null terminated option -0"240 default n241 depends on XARGS 242 help 243 Enable input filenames are terminated by a nullcharacter244 instead of bywhitespace, and the quotes and backslash244 bool "Enable -0: NUL-terminated input" 245 default y 246 depends on XARGS 247 help 248 Support -0: input items are terminated by a NUL character 249 instead of whitespace, and the quotes and backslash 245 250 are not special. 246 251 -
branches/2.2.9/mindi-busybox/findutils/Kbuild
r1765 r2725 1 # DO NOT EDIT. This file is generated from Kbuild.src 1 2 # Makefile for busybox 2 3 # 3 4 # Copyright (C) 1999-2005 by Erik Andersen <andersen@codepoet.org> 4 5 # 5 # Licensed under the GPL v2, see the file LICENSE in this tarball.6 # Licensed under GPLv2, see file LICENSE in this source tree. 6 7 7 8 lib-y:= 8 lib-$(CONFIG_FIND) += find.o 9 lib-$(CONFIG_GREP) += grep.o 10 lib-$(CONFIG_XARGS) += xargs.o 9 10 lib-$(CONFIG_FIND) += find.o 11 lib-$(CONFIG_GREP) += grep.o 12 lib-$(CONFIG_XARGS) += xargs.o -
branches/2.2.9/mindi-busybox/findutils/find.c
r1765 r2725 8 8 * Matt Kraai <kraai@alumni.carnegiemellon.edu>. 9 9 * 10 * Licensed under the GPL version 2, see the file LICENSE in this tarball.10 * Licensed under GPLv2, see file LICENSE in this source tree. 11 11 */ 12 12 … … 54 54 */ 55 55 56 //applet:IF_FIND(APPLET_NOEXEC(find, find, _BB_DIR_USR_BIN, _BB_SUID_DROP, find)) 57 58 //kbuild:lib-$(CONFIG_FIND) += find.o 59 60 //config:config FIND 61 //config: bool "find" 62 //config: default y 63 //config: help 64 //config: find is used to search your system to find specified files. 65 //config: 66 //config:config FEATURE_FIND_PRINT0 67 //config: bool "Enable -print0: NUL-terminated output" 68 //config: default y 69 //config: depends on FIND 70 //config: help 71 //config: Causes output names to be separated by a NUL character 72 //config: rather than a newline. This allows names that contain 73 //config: newlines and other whitespace to be more easily 74 //config: interpreted by other programs. 75 //config: 76 //config:config FEATURE_FIND_MTIME 77 //config: bool "Enable -mtime: modified time matching" 78 //config: default y 79 //config: depends on FIND 80 //config: help 81 //config: Allow searching based on the modification time of 82 //config: files, in days. 83 //config: 84 //config:config FEATURE_FIND_MMIN 85 //config: bool "Enable -mmin: modified time matching by minutes" 86 //config: default y 87 //config: depends on FIND 88 //config: help 89 //config: Allow searching based on the modification time of 90 //config: files, in minutes. 91 //config: 92 //config:config FEATURE_FIND_PERM 93 //config: bool "Enable -perm: permissions matching" 94 //config: default y 95 //config: depends on FIND 96 //config: help 97 //config: Enable searching based on file permissions. 98 //config: 99 //config:config FEATURE_FIND_TYPE 100 //config: bool "Enable -type: file type matching (file/dir/link/...)" 101 //config: default y 102 //config: depends on FIND 103 //config: help 104 //config: Enable searching based on file type (file, 105 //config: directory, socket, device, etc.). 106 //config: 107 //config:config FEATURE_FIND_XDEV 108 //config: bool "Enable -xdev: 'stay in filesystem'" 109 //config: default y 110 //config: depends on FIND 111 //config: help 112 //config: This option allows find to restrict searches to a single filesystem. 113 //config: 114 //config:config FEATURE_FIND_MAXDEPTH 115 //config: bool "Enable -maxdepth N" 116 //config: default y 117 //config: depends on FIND 118 //config: help 119 //config: This option enables -maxdepth N option. 120 //config: 121 //config:config FEATURE_FIND_NEWER 122 //config: bool "Enable -newer: compare file modification times" 123 //config: default y 124 //config: depends on FIND 125 //config: help 126 //config: Support the 'find -newer' option for finding any files which have 127 //config: a modified time that is more recent than the specified FILE. 128 //config: 129 //config:config FEATURE_FIND_INUM 130 //config: bool "Enable -inum: inode number matching" 131 //config: default y 132 //config: depends on FIND 133 //config: help 134 //config: Support the 'find -inum' option for searching by inode number. 135 //config: 136 //config:config FEATURE_FIND_EXEC 137 //config: bool "Enable -exec: execute commands" 138 //config: default y 139 //config: depends on FIND 140 //config: help 141 //config: Support the 'find -exec' option for executing commands based upon 142 //config: the files matched. 143 //config: 144 //config:config FEATURE_FIND_USER 145 //config: bool "Enable -user: username/uid matching" 146 //config: default y 147 //config: depends on FIND 148 //config: help 149 //config: Support the 'find -user' option for searching by username or uid. 150 //config: 151 //config:config FEATURE_FIND_GROUP 152 //config: bool "Enable -group: group/gid matching" 153 //config: default y 154 //config: depends on FIND 155 //config: help 156 //config: Support the 'find -group' option for searching by group name or gid. 157 //config: 158 //config:config FEATURE_FIND_NOT 159 //config: bool "Enable the 'not' (!) operator" 160 //config: default y 161 //config: depends on FIND 162 //config: help 163 //config: Support the '!' operator to invert the test results. 164 //config: If 'Enable full-blown desktop' is enabled, then will also support 165 //config: the non-POSIX notation '-not'. 166 //config: 167 //config:config FEATURE_FIND_DEPTH 168 //config: bool "Enable -depth" 169 //config: default y 170 //config: depends on FIND 171 //config: help 172 //config: Process each directory's contents before the directory itself. 173 //config: 174 //config:config FEATURE_FIND_PAREN 175 //config: bool "Enable parens in options" 176 //config: default y 177 //config: depends on FIND 178 //config: help 179 //config: Enable usage of parens '(' to specify logical order of arguments. 180 //config: 181 //config:config FEATURE_FIND_SIZE 182 //config: bool "Enable -size: file size matching" 183 //config: default y 184 //config: depends on FIND 185 //config: help 186 //config: Support the 'find -size' option for searching by file size. 187 //config: 188 //config:config FEATURE_FIND_PRUNE 189 //config: bool "Enable -prune: exclude subdirectories" 190 //config: default y 191 //config: depends on FIND 192 //config: help 193 //config: If the file is a directory, dont descend into it. Useful for 194 //config: exclusion .svn and CVS directories. 195 //config: 196 //config:config FEATURE_FIND_DELETE 197 //config: bool "Enable -delete: delete files/dirs" 198 //config: default y 199 //config: depends on FIND && FEATURE_FIND_DEPTH 200 //config: help 201 //config: Support the 'find -delete' option for deleting files and directories. 202 //config: WARNING: This option can do much harm if used wrong. Busybox will not 203 //config: try to protect the user from doing stupid things. Use with care. 204 //config: 205 //config:config FEATURE_FIND_PATH 206 //config: bool "Enable -path: match pathname with shell pattern" 207 //config: default y 208 //config: depends on FIND 209 //config: help 210 //config: The -path option matches whole pathname instead of just filename. 211 //config: 212 //config:config FEATURE_FIND_REGEX 213 //config: bool "Enable -regex: match pathname with regex" 214 //config: default y 215 //config: depends on FIND 216 //config: help 217 //config: The -regex option matches whole pathname against regular expression. 218 //config: 219 //config:config FEATURE_FIND_CONTEXT 220 //config: bool "Enable -context: security context matching" 221 //config: default n 222 //config: depends on FIND && SELINUX 223 //config: help 224 //config: Support the 'find -context' option for matching security context. 225 //config: 226 //config:config FEATURE_FIND_LINKS 227 //config: bool "Enable -links: link count matching" 228 //config: default y 229 //config: depends on FIND 230 //config: help 231 //config: Support the 'find -links' option for matching number of links. 232 56 233 #include <fnmatch.h> 57 234 #include "libbb.h" … … 63 240 64 241 65 USE_FEATURE_FIND_XDEV(static dev_t *xdev_dev;) 66 USE_FEATURE_FIND_XDEV(static int xdev_count;) 67 68 typedef int (*action_fp)(const char *fileName, struct stat *statbuf, void *); 242 typedef int (*action_fp)(const char *fileName, const struct stat *statbuf, void *) FAST_FUNC; 69 243 70 244 typedef struct { … … 74 248 #endif 75 249 } action; 76 #define ACTS(name, arg...) typedef struct { action a; arg; } action_##name; 77 #define ACTF(name) static int func_##name(const char *fileName, struct stat *statbuf, action_##name* ap) 78 ACTS(print) 79 ACTS(name, const char *pattern;) 80 USE_FEATURE_FIND_PATH( ACTS(path, const char *pattern;)) 81 USE_FEATURE_FIND_REGEX( ACTS(regex, regex_t compiled_pattern;)) 82 USE_FEATURE_FIND_PRINT0( ACTS(print0)) 83 USE_FEATURE_FIND_TYPE( ACTS(type, int type_mask;)) 84 USE_FEATURE_FIND_PERM( ACTS(perm, char perm_char; mode_t perm_mask;)) 85 USE_FEATURE_FIND_MTIME( ACTS(mtime, char mtime_char; unsigned mtime_days;)) 86 USE_FEATURE_FIND_MMIN( ACTS(mmin, char mmin_char; unsigned mmin_mins;)) 87 USE_FEATURE_FIND_NEWER( ACTS(newer, time_t newer_mtime;)) 88 USE_FEATURE_FIND_INUM( ACTS(inum, ino_t inode_num;)) 89 USE_FEATURE_FIND_USER( ACTS(user, uid_t uid;)) 90 USE_FEATURE_FIND_SIZE( ACTS(size, char size_char; off_t size;)) 91 USE_FEATURE_FIND_CONTEXT(ACTS(context, security_context_t context;)) 92 USE_FEATURE_FIND_PAREN( ACTS(paren, action ***subexpr;)) 93 USE_FEATURE_FIND_PRUNE( ACTS(prune)) 94 USE_FEATURE_FIND_DELETE( ACTS(delete)) 95 USE_FEATURE_FIND_EXEC( ACTS(exec, char **exec_argv; unsigned *subst_count; int exec_argc;)) 96 USE_FEATURE_FIND_GROUP( ACTS(group, gid_t gid;)) 97 98 static action ***actions; 99 static bool need_print = 1; 100 static int recurse_flags = ACTION_RECURSE; 250 251 #define ACTS(name, ...) typedef struct { action a; __VA_ARGS__ } action_##name; 252 #define ACTF(name) \ 253 static int FAST_FUNC func_##name(const char *fileName UNUSED_PARAM, \ 254 const struct stat *statbuf UNUSED_PARAM, \ 255 action_##name* ap UNUSED_PARAM) 256 257 ACTS(print) 258 ACTS(name, const char *pattern; bool iname;) 259 IF_FEATURE_FIND_PATH( ACTS(path, const char *pattern;)) 260 IF_FEATURE_FIND_REGEX( ACTS(regex, regex_t compiled_pattern;)) 261 IF_FEATURE_FIND_PRINT0( ACTS(print0)) 262 IF_FEATURE_FIND_TYPE( ACTS(type, int type_mask;)) 263 IF_FEATURE_FIND_PERM( ACTS(perm, char perm_char; mode_t perm_mask;)) 264 IF_FEATURE_FIND_MTIME( ACTS(mtime, char mtime_char; unsigned mtime_days;)) 265 IF_FEATURE_FIND_MMIN( ACTS(mmin, char mmin_char; unsigned mmin_mins;)) 266 IF_FEATURE_FIND_NEWER( ACTS(newer, time_t newer_mtime;)) 267 IF_FEATURE_FIND_INUM( ACTS(inum, ino_t inode_num;)) 268 IF_FEATURE_FIND_USER( ACTS(user, uid_t uid;)) 269 IF_FEATURE_FIND_SIZE( ACTS(size, char size_char; off_t size;)) 270 IF_FEATURE_FIND_CONTEXT(ACTS(context, security_context_t context;)) 271 IF_FEATURE_FIND_PAREN( ACTS(paren, action ***subexpr;)) 272 IF_FEATURE_FIND_PRUNE( ACTS(prune)) 273 IF_FEATURE_FIND_DELETE( ACTS(delete)) 274 IF_FEATURE_FIND_EXEC( ACTS(exec, char **exec_argv; unsigned *subst_count; int exec_argc;)) 275 IF_FEATURE_FIND_GROUP( ACTS(group, gid_t gid;)) 276 IF_FEATURE_FIND_LINKS( ACTS(links, char links_char; int links_count;)) 277 278 struct globals { 279 IF_FEATURE_FIND_XDEV(dev_t *xdev_dev;) 280 IF_FEATURE_FIND_XDEV(int xdev_count;) 281 action ***actions; 282 bool need_print; 283 recurse_flags_t recurse_flags; 284 } FIX_ALIASING; 285 #define G (*(struct globals*)&bb_common_bufsiz1) 286 #define INIT_G() do { \ 287 struct G_sizecheck { \ 288 char G_sizecheck[sizeof(G) > COMMON_BUFSIZE ? -1 : 1]; \ 289 }; \ 290 /* we have to zero it out because of NOEXEC */ \ 291 memset(&G, 0, offsetof(struct globals, need_print)); \ 292 G.need_print = 1; \ 293 G.recurse_flags = ACTION_RECURSE; \ 294 } while (0) 101 295 102 296 #if ENABLE_FEATURE_FIND_EXEC … … 135 329 */ 136 330 137 static int exec_actions(action ***appp, const char *fileName, struct stat *statbuf)331 static int exec_actions(action ***appp, const char *fileName, const struct stat *statbuf) 138 332 { 139 333 int cur_group; … … 160 354 161 355 cur_group = -1; 162 while ((app = appp[++cur_group]) ) {356 while ((app = appp[++cur_group]) != NULL) { 163 357 rc &= ~TRUE; /* 'success' so far, clear TRUE bit */ 164 358 cur_action = -1; … … 182 376 { 183 377 const char *tmp = bb_basename(fileName); 184 if (tmp != fileName && !*tmp) { /* "foo/bar/". Oh no... go back to 'b' */ 378 if (tmp != fileName && *tmp == '\0') { 379 /* "foo/bar/". Oh no... go back to 'b' */ 185 380 tmp--; 186 381 while (tmp != fileName && *--tmp != '/') … … 189 384 tmp++; 190 385 } 191 return fnmatch(ap->pattern, tmp, FNM_PERIOD) == 0; 192 } 386 /* Was using FNM_PERIOD flag too, 387 * but somewhere between 4.1.20 and 4.4.0 GNU find stopped using it. 388 * find -name '*foo' should match .foo too: 389 */ 390 return fnmatch(ap->pattern, tmp, (ap->iname ? FNM_CASEFOLD : 0)) == 0; 391 } 392 193 393 #if ENABLE_FEATURE_FIND_PATH 194 394 ACTF(path) … … 271 471 { 272 472 int i, rc; 473 #if ENABLE_USE_PORTABLE_CODE 474 char **argv = alloca(sizeof(char*) * (ap->exec_argc + 1)); 475 #else /* gcc 4.3.1 generates smaller code: */ 273 476 char *argv[ap->exec_argc + 1]; 477 #endif 274 478 for (i = 0; i < ap->exec_argc; i++) 275 479 argv[i] = subst(ap->exec_argv[i], ap->subst_count[i], fileName); … … 278 482 rc = spawn_and_wait(argv); 279 483 if (rc < 0) 280 bb_ perror_msg("%s",argv[0]);484 bb_simple_perror_msg(argv[0]); 281 485 282 486 i = 0; … … 348 552 } 349 553 if (rc < 0) 350 bb_ perror_msg("%s",fileName);554 bb_simple_perror_msg(fileName); 351 555 return TRUE; 352 556 } … … 358 562 int rc; 359 563 360 if ( recurse_flags & ACTION_FOLLOWLINKS) {564 if (G.recurse_flags & ACTION_FOLLOWLINKS) { 361 565 rc = getfilecon(fileName, &con); 362 566 } else { … … 370 574 } 371 575 #endif 372 373 374 static int fileAction(const char *fileName, struct stat *statbuf, void *userData, int depth) 375 { 376 int i; 576 #if ENABLE_FEATURE_FIND_LINKS 577 ACTF(links) 578 { 579 switch(ap->links_char) { 580 case '-' : return (statbuf->st_nlink < ap->links_count); 581 case '+' : return (statbuf->st_nlink > ap->links_count); 582 default: return (statbuf->st_nlink == ap->links_count); 583 } 584 } 585 #endif 586 587 static int FAST_FUNC fileAction(const char *fileName, 588 struct stat *statbuf, 589 void *userData IF_NOT_FEATURE_FIND_MAXDEPTH(UNUSED_PARAM), 590 int depth IF_NOT_FEATURE_FIND_MAXDEPTH(UNUSED_PARAM)) 591 { 592 int r; 377 593 #if ENABLE_FEATURE_FIND_MAXDEPTH 378 int maxdepth = (int)(ptrdiff_t)userData; 379 380 if (depth > maxdepth) return SKIP; 381 #endif 382 594 #define minmaxdepth ((int*)userData) 595 596 if (depth < minmaxdepth[0]) 597 return TRUE; /* skip this, continue recursing */ 598 if (depth > minmaxdepth[1]) 599 return SKIP; /* stop recursing */ 600 #endif 601 602 r = exec_actions(G.actions, fileName, statbuf); 603 /* Had no explicit -print[0] or -exec? then print */ 604 if ((r & TRUE) && G.need_print) 605 puts(fileName); 606 607 #if ENABLE_FEATURE_FIND_MAXDEPTH 608 if (S_ISDIR(statbuf->st_mode)) { 609 if (depth == minmaxdepth[1]) 610 return SKIP; 611 } 612 #endif 383 613 #if ENABLE_FEATURE_FIND_XDEV 384 if (S_ISDIR(statbuf->st_mode) && xdev_count) { 385 for (i = 0; i < xdev_count; i++) { 386 if (xdev_dev[i] == statbuf->st_dev) 387 break; 388 } 389 if (i == xdev_count) 614 /* -xdev stops on mountpoints, but AFTER mountpoit itself 615 * is processed as usual */ 616 if (S_ISDIR(statbuf->st_mode)) { 617 if (G.xdev_count) { 618 int i; 619 for (i = 0; i < G.xdev_count; i++) { 620 if (G.xdev_dev[i] == statbuf->st_dev) 621 goto found; 622 } 390 623 return SKIP; 391 } 392 #endif 393 i = exec_actions(actions, fileName, statbuf); 394 /* Had no explicit -print[0] or -exec? then print */ 395 if ((i & TRUE) && need_print) 396 puts(fileName); 624 found: ; 625 } 626 } 627 #endif 628 397 629 /* Cannot return 0: our caller, recursive_action(), 398 630 * will perror() and skip dirs (if called on dir) */ 399 return (i & SKIP) ? SKIP : TRUE; 631 return (r & SKIP) ? SKIP : TRUE; 632 #undef minmaxdepth 400 633 } 401 634 … … 421 654 mask = S_IFSOCK; 422 655 423 if (mask == 0 || *(type + 1)!= '\0')656 if (mask == 0 || type[1] != '\0') 424 657 bb_error_msg_and_die(bb_msg_invalid_arg, type, "-type"); 425 658 … … 430 663 #if ENABLE_FEATURE_FIND_PERM \ 431 664 || ENABLE_FEATURE_FIND_MTIME || ENABLE_FEATURE_FIND_MMIN \ 432 || ENABLE_FEATURE_FIND_SIZE 665 || ENABLE_FEATURE_FIND_SIZE || ENABLE_FEATURE_FIND_LINKS 433 666 static const char* plus_minus_num(const char* str) 434 667 { … … 442 675 { 443 676 enum { 444 445 446 USE_FEATURE_FIND_NOT(PARM_char_not ,)677 PARM_a , 678 PARM_o , 679 IF_FEATURE_FIND_NOT( PARM_char_not ,) 447 680 #if ENABLE_DESKTOP 448 449 450 USE_FEATURE_FIND_NOT( PARM_not ,)451 #endif 452 453 USE_FEATURE_FIND_PRINT0( PARM_print0 ,)454 USE_FEATURE_FIND_DEPTH( PARM_depth ,)455 USE_FEATURE_FIND_PRUNE( PARM_prune ,)456 USE_FEATURE_FIND_DELETE( PARM_delete ,)457 USE_FEATURE_FIND_EXEC( PARM_exec ,)458 USE_FEATURE_FIND_PAREN( PARM_char_brace,)681 PARM_and , 682 PARM_or , 683 IF_FEATURE_FIND_NOT( PARM_not ,) 684 #endif 685 PARM_print , 686 IF_FEATURE_FIND_PRINT0( PARM_print0 ,) 687 IF_FEATURE_FIND_DEPTH( PARM_depth ,) 688 IF_FEATURE_FIND_PRUNE( PARM_prune ,) 689 IF_FEATURE_FIND_DELETE( PARM_delete ,) 690 IF_FEATURE_FIND_EXEC( PARM_exec ,) 691 IF_FEATURE_FIND_PAREN( PARM_char_brace,) 459 692 /* All options starting from here require argument */ 460 PARM_name , 461 USE_FEATURE_FIND_PATH( PARM_path ,) 462 USE_FEATURE_FIND_REGEX( PARM_regex ,) 463 USE_FEATURE_FIND_TYPE( PARM_type ,) 464 USE_FEATURE_FIND_PERM( PARM_perm ,) 465 USE_FEATURE_FIND_MTIME( PARM_mtime ,) 466 USE_FEATURE_FIND_MMIN( PARM_mmin ,) 467 USE_FEATURE_FIND_NEWER( PARM_newer ,) 468 USE_FEATURE_FIND_INUM( PARM_inum ,) 469 USE_FEATURE_FIND_USER( PARM_user ,) 470 USE_FEATURE_FIND_GROUP( PARM_group ,) 471 USE_FEATURE_FIND_SIZE( PARM_size ,) 472 USE_FEATURE_FIND_CONTEXT(PARM_context ,) 693 PARM_name , 694 PARM_iname , 695 IF_FEATURE_FIND_PATH( PARM_path ,) 696 IF_FEATURE_FIND_REGEX( PARM_regex ,) 697 IF_FEATURE_FIND_TYPE( PARM_type ,) 698 IF_FEATURE_FIND_PERM( PARM_perm ,) 699 IF_FEATURE_FIND_MTIME( PARM_mtime ,) 700 IF_FEATURE_FIND_MMIN( PARM_mmin ,) 701 IF_FEATURE_FIND_NEWER( PARM_newer ,) 702 IF_FEATURE_FIND_INUM( PARM_inum ,) 703 IF_FEATURE_FIND_USER( PARM_user ,) 704 IF_FEATURE_FIND_GROUP( PARM_group ,) 705 IF_FEATURE_FIND_SIZE( PARM_size ,) 706 IF_FEATURE_FIND_CONTEXT(PARM_context ,) 707 IF_FEATURE_FIND_LINKS( PARM_links ,) 473 708 }; 474 709 … … 476 711 "-a\0" 477 712 "-o\0" 478 USE_FEATURE_FIND_NOT( "!\0" )713 IF_FEATURE_FIND_NOT( "!\0" ) 479 714 #if ENABLE_DESKTOP 480 715 "-and\0" 481 716 "-or\0" 482 USE_FEATURE_FIND_NOT( "-not\0" )717 IF_FEATURE_FIND_NOT( "-not\0" ) 483 718 #endif 484 719 "-print\0" 485 USE_FEATURE_FIND_PRINT0( "-print0\0" )486 USE_FEATURE_FIND_DEPTH( "-depth\0" )487 USE_FEATURE_FIND_PRUNE( "-prune\0" )488 USE_FEATURE_FIND_DELETE( "-delete\0" )489 USE_FEATURE_FIND_EXEC( "-exec\0" )490 USE_FEATURE_FIND_PAREN( "(\0" )720 IF_FEATURE_FIND_PRINT0( "-print0\0" ) 721 IF_FEATURE_FIND_DEPTH( "-depth\0" ) 722 IF_FEATURE_FIND_PRUNE( "-prune\0" ) 723 IF_FEATURE_FIND_DELETE( "-delete\0" ) 724 IF_FEATURE_FIND_EXEC( "-exec\0" ) 725 IF_FEATURE_FIND_PAREN( "(\0" ) 491 726 /* All options starting from here require argument */ 492 727 "-name\0" 493 USE_FEATURE_FIND_PATH( "-path\0" ) 494 USE_FEATURE_FIND_REGEX( "-regex\0" ) 495 USE_FEATURE_FIND_TYPE( "-type\0" ) 496 USE_FEATURE_FIND_PERM( "-perm\0" ) 497 USE_FEATURE_FIND_MTIME( "-mtime\0" ) 498 USE_FEATURE_FIND_MMIN( "-mmin\0" ) 499 USE_FEATURE_FIND_NEWER( "-newer\0" ) 500 USE_FEATURE_FIND_INUM( "-inum\0" ) 501 USE_FEATURE_FIND_USER( "-user\0" ) 502 USE_FEATURE_FIND_GROUP( "-group\0" ) 503 USE_FEATURE_FIND_SIZE( "-size\0" ) 504 USE_FEATURE_FIND_CONTEXT("-context\0") 728 "-iname\0" 729 IF_FEATURE_FIND_PATH( "-path\0" ) 730 IF_FEATURE_FIND_REGEX( "-regex\0" ) 731 IF_FEATURE_FIND_TYPE( "-type\0" ) 732 IF_FEATURE_FIND_PERM( "-perm\0" ) 733 IF_FEATURE_FIND_MTIME( "-mtime\0" ) 734 IF_FEATURE_FIND_MMIN( "-mmin\0" ) 735 IF_FEATURE_FIND_NEWER( "-newer\0" ) 736 IF_FEATURE_FIND_INUM( "-inum\0" ) 737 IF_FEATURE_FIND_USER( "-user\0" ) 738 IF_FEATURE_FIND_GROUP( "-group\0" ) 739 IF_FEATURE_FIND_SIZE( "-size\0" ) 740 IF_FEATURE_FIND_CONTEXT("-context\0") 741 IF_FEATURE_FIND_LINKS( "-links\0" ) 505 742 ; 506 743 … … 508 745 unsigned cur_group = 0; 509 746 unsigned cur_action = 0; 510 USE_FEATURE_FIND_NOT( bool invert_flag = 0; ) 511 512 /* 'static' doesn't work here! (gcc 4.1.2) */ 747 IF_FEATURE_FIND_NOT( bool invert_flag = 0; ) 748 749 /* This is the only place in busybox where we use nested function. 750 * So far more standard alternatives were bigger. */ 751 /* Auto decl suppresses "func without a prototype" warning: */ 752 auto action* alloc_action(int sizeof_struct, action_fp f); 513 753 action* alloc_action(int sizeof_struct, action_fp f) 514 754 { 515 755 action *ap; 516 756 appp[cur_group] = xrealloc(appp[cur_group], (cur_action+2) * sizeof(*appp)); 517 appp[cur_group][cur_action++] = ap = x malloc(sizeof_struct);757 appp[cur_group][cur_action++] = ap = xzalloc(sizeof_struct); 518 758 appp[cur_group][cur_action] = NULL; 519 759 ap->f = f; 520 USE_FEATURE_FIND_NOT( ap->invert = invert_flag; )521 USE_FEATURE_FIND_NOT( invert_flag = 0; )760 IF_FEATURE_FIND_NOT( ap->invert = invert_flag; ) 761 IF_FEATURE_FIND_NOT( invert_flag = 0; ) 522 762 return ap; 523 763 } … … 557 797 558 798 /* --- Operators --- */ 559 if (parm == PARM_a USE_DESKTOP(|| parm == PARM_and)) {799 if (parm == PARM_a IF_DESKTOP(|| parm == PARM_and)) { 560 800 /* no further special handling required */ 561 801 } 562 else if (parm == PARM_o USE_DESKTOP(|| parm == PARM_or)) {802 else if (parm == PARM_o IF_DESKTOP(|| parm == PARM_or)) { 563 803 /* start new OR group */ 564 804 cur_group++; … … 569 809 } 570 810 #if ENABLE_FEATURE_FIND_NOT 571 else if (parm == PARM_char_not USE_DESKTOP(|| parm == PARM_not)) {811 else if (parm == PARM_char_not IF_DESKTOP(|| parm == PARM_not)) { 572 812 /* also handles "find ! ! -name 'foo*'" */ 573 813 invert_flag ^= 1; … … 577 817 /* --- Tests and actions --- */ 578 818 else if (parm == PARM_print) { 579 need_print = 0;819 G.need_print = 0; 580 820 /* GNU find ignores '!' here: "find ! -print" */ 581 USE_FEATURE_FIND_NOT( invert_flag = 0; )821 IF_FEATURE_FIND_NOT( invert_flag = 0; ) 582 822 (void) ALLOC_ACTION(print); 583 823 } 584 824 #if ENABLE_FEATURE_FIND_PRINT0 585 825 else if (parm == PARM_print0) { 586 need_print = 0;587 USE_FEATURE_FIND_NOT( invert_flag = 0; )826 G.need_print = 0; 827 IF_FEATURE_FIND_NOT( invert_flag = 0; ) 588 828 (void) ALLOC_ACTION(print0); 589 829 } … … 591 831 #if ENABLE_FEATURE_FIND_DEPTH 592 832 else if (parm == PARM_depth) { 593 recurse_flags |= ACTION_DEPTHFIRST;833 G.recurse_flags |= ACTION_DEPTHFIRST; 594 834 } 595 835 #endif 596 836 #if ENABLE_FEATURE_FIND_PRUNE 597 837 else if (parm == PARM_prune) { 598 USE_FEATURE_FIND_NOT( invert_flag = 0; )838 IF_FEATURE_FIND_NOT( invert_flag = 0; ) 599 839 (void) ALLOC_ACTION(prune); 600 840 } … … 602 842 #if ENABLE_FEATURE_FIND_DELETE 603 843 else if (parm == PARM_delete) { 604 need_print = 0;605 recurse_flags |= ACTION_DEPTHFIRST;844 G.need_print = 0; 845 G.recurse_flags |= ACTION_DEPTHFIRST; 606 846 (void) ALLOC_ACTION(delete); 607 847 } … … 611 851 int i; 612 852 action_exec *ap; 613 need_print = 0;614 USE_FEATURE_FIND_NOT( invert_flag = 0; )853 G.need_print = 0; 854 IF_FEATURE_FIND_NOT( invert_flag = 0; ) 615 855 ap = ALLOC_ACTION(exec); 616 856 ap->exec_argv = ++argv; /* first arg after -exec */ 617 ap->exec_argc = 0;857 /*ap->exec_argc = 0; - ALLOC_ACTION did it */ 618 858 while (1) { 619 if (!*argv) /* did not see ';' until end */ 620 bb_error_msg_and_die("-exec CMD must end by ';'"); 621 if (LONE_CHAR(argv[0], ';')) 859 if (!*argv) /* did not see ';' or '+' until end */ 860 bb_error_msg_and_die(bb_msg_requires_arg, "-exec"); 861 // find -exec echo Foo ">{}<" ";" 862 // executes "echo Foo <filename>", 863 // find -exec echo Foo ">{}<" "+" 864 // executes "echo Foo <filename1> <filename2> <filename3>...". 865 // TODO (so far we treat "+" just like ";") 866 if ((argv[0][0] == ';' || argv[0][0] == '+') 867 && argv[0][1] == '\0' 868 ) { 622 869 break; 870 } 623 871 argv++; 624 872 ap->exec_argc++; … … 655 903 } 656 904 #endif 657 else if (parm == PARM_name ) {905 else if (parm == PARM_name || parm == PARM_iname) { 658 906 action_name *ap; 659 907 ap = ALLOC_ACTION(name); 660 908 ap->pattern = arg1; 909 ap->iname = (parm == PARM_iname); 661 910 } 662 911 #if ENABLE_FEATURE_FIND_PATH … … 692 941 ap->perm_char = arg1[0]; 693 942 arg1 = plus_minus_num(arg1); 694 ap->perm_mask = 0;943 /*ap->perm_mask = 0; - ALLOC_ACTION did it */ 695 944 if (!bb_parse_mode(arg1, &ap->perm_mask)) 696 bb_error_msg_and_die("invalid mode : %s", arg1);945 bb_error_msg_and_die("invalid mode '%s'", arg1); 697 946 } 698 947 #endif … … 766 1015 { "b", 512 }, 767 1016 { "k", 1024 }, 768 { }1017 { "", 0 } 769 1018 }; 770 1019 action_size *ap; … … 778 1027 action_context *ap; 779 1028 ap = ALLOC_ACTION(context); 780 ap->context = NULL;1029 /*ap->context = NULL; - ALLOC_ACTION did it */ 781 1030 /* SELinux headers erroneously declare non-const parameter */ 782 1031 if (selinux_raw_to_trans_context((char*)arg1, &ap->context)) 783 bb_perror_msg("%s", arg1); 1032 bb_simple_perror_msg(arg1); 1033 } 1034 #endif 1035 #if ENABLE_FEATURE_FIND_LINKS 1036 else if (parm == PARM_links) { 1037 action_links *ap; 1038 ap = ALLOC_ACTION(links); 1039 ap->links_char = arg1[0]; 1040 ap->links_count = xatoul(plus_minus_num(arg1)); 784 1041 } 785 1042 #endif … … 794 1051 } 795 1052 796 797 int find_main(int argc, char **argv); 798 int find_main(int argc, char **argv) 1053 //usage:#define find_trivial_usage 1054 //usage: "[PATH]... [EXPRESSION]" 1055 //usage:#define find_full_usage "\n\n" 1056 //usage: "Search for files. The default PATH is the current directory,\n" 1057 //usage: "default EXPRESSION is '-print'\n" 1058 //usage: "\nEXPRESSION may consist of:" 1059 //usage: "\n -follow Follow symlinks" 1060 //usage: IF_FEATURE_FIND_XDEV( 1061 //usage: "\n -xdev Don't descend directories on other filesystems" 1062 //usage: ) 1063 //usage: IF_FEATURE_FIND_MAXDEPTH( 1064 //usage: "\n -maxdepth N Descend at most N levels. -maxdepth 0 applies" 1065 //usage: "\n tests/actions to command line arguments only" 1066 //usage: ) 1067 //usage: "\n -mindepth N Don't act on first N levels" 1068 //usage: "\n -name PATTERN File name (w/o directory name) matches PATTERN" 1069 //usage: "\n -iname PATTERN Case insensitive -name" 1070 //usage: IF_FEATURE_FIND_PATH( 1071 //usage: "\n -path PATTERN Path matches PATTERN" 1072 //usage: ) 1073 //usage: IF_FEATURE_FIND_REGEX( 1074 //usage: "\n -regex PATTERN Path matches regex PATTERN" 1075 //usage: ) 1076 //usage: IF_FEATURE_FIND_TYPE( 1077 //usage: "\n -type X File type is X (X is one of: f,d,l,b,c,...)" 1078 //usage: ) 1079 //usage: IF_FEATURE_FIND_PERM( 1080 //usage: "\n -perm NNN Permissions match any of (+NNN), all of (-NNN)," 1081 //usage: "\n or exactly NNN" 1082 //usage: ) 1083 //usage: IF_FEATURE_FIND_MTIME( 1084 //usage: "\n -mtime DAYS Modified time is greater than (+N), less than (-N)," 1085 //usage: "\n or exactly N days" 1086 //usage: ) 1087 //usage: IF_FEATURE_FIND_MMIN( 1088 //usage: "\n -mmin MINS Modified time is greater than (+N), less than (-N)," 1089 //usage: "\n or exactly N minutes" 1090 //usage: ) 1091 //usage: IF_FEATURE_FIND_NEWER( 1092 //usage: "\n -newer FILE Modified time is more recent than FILE's" 1093 //usage: ) 1094 //usage: IF_FEATURE_FIND_INUM( 1095 //usage: "\n -inum N File has inode number N" 1096 //usage: ) 1097 //usage: IF_FEATURE_FIND_USER( 1098 //usage: "\n -user NAME File is owned by user NAME (numeric user ID allowed)" 1099 //usage: ) 1100 //usage: IF_FEATURE_FIND_GROUP( 1101 //usage: "\n -group NAME File belongs to group NAME (numeric group ID allowed)" 1102 //usage: ) 1103 //usage: IF_FEATURE_FIND_DEPTH( 1104 //usage: "\n -depth Process directory name after traversing it" 1105 //usage: ) 1106 //usage: IF_FEATURE_FIND_SIZE( 1107 //usage: "\n -size N[bck] File size is N (c:bytes,k:kbytes,b:512 bytes(def.))" 1108 //usage: "\n +/-N: file size is bigger/smaller than N" 1109 //usage: ) 1110 //usage: IF_FEATURE_FIND_LINKS( 1111 //usage: "\n -links N Number of links is greater than (+N), less than (-N)," 1112 //usage: "\n or exactly N" 1113 //usage: ) 1114 //usage: "\n -print Print (default and assumed)" 1115 //usage: IF_FEATURE_FIND_PRINT0( 1116 //usage: "\n -print0 Delimit output with null characters rather than" 1117 //usage: "\n newlines" 1118 //usage: ) 1119 //usage: IF_FEATURE_FIND_CONTEXT( 1120 //usage: "\n -context File has specified security context" 1121 //usage: ) 1122 //usage: IF_FEATURE_FIND_EXEC( 1123 //usage: "\n -exec CMD ARG ; Run CMD with all instances of {} replaced by the" 1124 //usage: "\n matching files" 1125 //usage: ) 1126 //usage: IF_FEATURE_FIND_PRUNE( 1127 //usage: "\n -prune Stop traversing current subtree" 1128 //usage: ) 1129 //usage: IF_FEATURE_FIND_DELETE( 1130 //usage: "\n -delete Delete files, turns on -depth option" 1131 //usage: ) 1132 //usage: IF_FEATURE_FIND_PAREN( 1133 //usage: "\n (EXPR) Group an expression" 1134 //usage: ) 1135 //usage: 1136 //usage:#define find_example_usage 1137 //usage: "$ find / -name passwd\n" 1138 //usage: "/etc/passwd\n" 1139 1140 int find_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 1141 int find_main(int argc UNUSED_PARAM, char **argv) 799 1142 { 800 1143 static const char options[] ALIGN1 = 801 1144 "-follow\0" 802 USE_FEATURE_FIND_XDEV( "-xdev\0" )803 USE_FEATURE_FIND_MAXDEPTH("-maxdepth\0")1145 IF_FEATURE_FIND_XDEV( "-xdev\0" ) 1146 IF_FEATURE_FIND_MAXDEPTH("-mindepth\0""-maxdepth\0") 804 1147 ; 805 1148 enum { 806 1149 OPT_FOLLOW, 807 USE_FEATURE_FIND_XDEV( OPT_XDEV ,)808 USE_FEATURE_FIND_MAXDEPTH(OPT_MAXDEPTH,)1150 IF_FEATURE_FIND_XDEV( OPT_XDEV ,) 1151 IF_FEATURE_FIND_MAXDEPTH(OPT_MINDEPTH,) 809 1152 }; 810 1153 … … 813 1156 int i, firstopt, status = EXIT_SUCCESS; 814 1157 #if ENABLE_FEATURE_FIND_MAXDEPTH 815 int maxdepth = INT_MAX; 816 #endif 817 818 for (firstopt = 1; firstopt < argc; firstopt++) { 1158 int minmaxdepth[2] = { 0, INT_MAX }; 1159 #else 1160 #define minmaxdepth NULL 1161 #endif 1162 1163 INIT_G(); 1164 1165 for (firstopt = 1; argv[firstopt]; firstopt++) { 819 1166 if (argv[firstopt][0] == '-') 820 1167 break; … … 843 1190 int opt = index_in_strings(options, arg); 844 1191 if (opt == OPT_FOLLOW) { 845 recurse_flags |= ACTION_FOLLOWLINKS;1192 G.recurse_flags |= ACTION_FOLLOWLINKS | ACTION_DANGLING_OK; 846 1193 argp[0] = (char*)"-a"; 847 1194 } … … 849 1196 if (opt == OPT_XDEV) { 850 1197 struct stat stbuf; 851 if (! xdev_count) {852 xdev_count = firstopt - 1;853 xdev_dev = xmalloc(xdev_count * sizeof(dev_t));1198 if (!G.xdev_count) { 1199 G.xdev_count = firstopt - 1; 1200 G.xdev_dev = xzalloc(G.xdev_count * sizeof(G.xdev_dev[0])); 854 1201 for (i = 1; i < firstopt; i++) { 855 1202 /* not xstat(): shouldn't bomb out on 856 1203 * "find not_exist exist -xdev" */ 857 if (stat(argv[i], &stbuf)) 858 stbuf.st_dev = -1L; 859 xdev_dev[i-1] = stbuf.st_dev; 1204 if (stat(argv[i], &stbuf) == 0) 1205 G.xdev_dev[i-1] = stbuf.st_dev; 1206 /* else G.xdev_dev[i-1] stays 0 and 1207 * won't match any real device dev_t */ 860 1208 } 861 1209 } … … 864 1212 #endif 865 1213 #if ENABLE_FEATURE_FIND_MAXDEPTH 866 if (opt == OPT_M AXDEPTH) {1214 if (opt == OPT_MINDEPTH || opt == OPT_MINDEPTH + 1) { 867 1215 if (!argp[1]) 868 1216 bb_show_usage(); 869 m axdepth = xatoi_u(argp[1]);1217 minmaxdepth[opt - OPT_MINDEPTH] = xatoi_positive(argp[1]); 870 1218 argp[0] = (char*)"-a"; 871 1219 argp[1] = (char*)"-a"; … … 876 1224 } 877 1225 878 actions = parse_params(&argv[firstopt]);1226 G.actions = parse_params(&argv[firstopt]); 879 1227 880 1228 for (i = 1; i < firstopt; i++) { 881 1229 if (!recursive_action(argv[i], 882 recurse_flags,/* flags */1230 G.recurse_flags,/* flags */ 883 1231 fileAction, /* file action */ 884 1232 fileAction, /* dir action */ 885 1233 #if ENABLE_FEATURE_FIND_MAXDEPTH 886 /* double cast suppresses 887 * "cast to ptr from int of different size" */ 888 (void*)(ptrdiff_t)maxdepth,/* user data */ 1234 minmaxdepth, /* user data */ 889 1235 #else 890 1236 NULL, /* user data */ -
branches/2.2.9/mindi-busybox/findutils/grep.c
r1765 r2725 6 6 * Copyright (C) 1999,2000,2001 by Mark Whitley <markw@codepoet.org> 7 7 * 8 * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.8 * Licensed under GPLv2 or later, see file LICENSE in this source tree. 9 9 */ 10 /* BB_AUDIT SUSv3 defects - unsupported option -x .*/10 /* BB_AUDIT SUSv3 defects - unsupported option -x "match whole line only". */ 11 11 /* BB_AUDIT GNU defects - always acts as -a. */ 12 12 /* http://www.opengroup.org/onlinepubs/007904975/utilities/grep.html */ … … 15 15 * correction "-e pattern1 -e pattern2" logic and more optimizations. 16 16 * precompiled regex 17 */ 18 /* 17 * 19 18 * (C) 2006 Jac Goudsmit added -o option 20 19 */ 21 20 21 //applet:IF_GREP(APPLET(grep, _BB_DIR_BIN, _BB_SUID_DROP)) 22 //applet:IF_FEATURE_GREP_EGREP_ALIAS(APPLET_ODDNAME(egrep, grep, _BB_DIR_BIN, _BB_SUID_DROP, egrep)) 23 //applet:IF_FEATURE_GREP_FGREP_ALIAS(APPLET_ODDNAME(fgrep, grep, _BB_DIR_BIN, _BB_SUID_DROP, fgrep)) 24 25 //kbuild:lib-$(CONFIG_GREP) += grep.o 26 27 //config:config GREP 28 //config: bool "grep" 29 //config: default y 30 //config: help 31 //config: grep is used to search files for a specified pattern. 32 //config: 33 //config:config FEATURE_GREP_EGREP_ALIAS 34 //config: bool "Enable extended regular expressions (egrep & grep -E)" 35 //config: default y 36 //config: depends on GREP 37 //config: help 38 //config: Enabled support for extended regular expressions. Extended 39 //config: regular expressions allow for alternation (foo|bar), grouping, 40 //config: and various repetition operators. 41 //config: 42 //config:config FEATURE_GREP_FGREP_ALIAS 43 //config: bool "Alias fgrep to grep -F" 44 //config: default y 45 //config: depends on GREP 46 //config: help 47 //config: fgrep sees the search pattern as a normal string rather than 48 //config: regular expressions. 49 //config: grep -F always works, this just creates the fgrep alias. 50 //config: 51 //config:config FEATURE_GREP_CONTEXT 52 //config: bool "Enable before and after context flags (-A, -B and -C)" 53 //config: default y 54 //config: depends on GREP 55 //config: help 56 //config: Print the specified number of leading (-B) and/or trailing (-A) 57 //config: context surrounding our matching lines. 58 //config: Print the specified number of context lines (-C). 59 22 60 #include "libbb.h" 23 61 #include "xregex.h" 24 62 63 25 64 /* options */ 65 //usage:#define grep_trivial_usage 66 //usage: "[-HhnlLoqvsriw" 67 //usage: "F" 68 //usage: IF_FEATURE_GREP_EGREP_ALIAS("E") 69 //usage: IF_EXTRA_COMPAT("z") 70 //usage: "] [-m N] " 71 //usage: IF_FEATURE_GREP_CONTEXT("[-A/B/C N] ") 72 //usage: "PATTERN/-e PATTERN.../-f FILE [FILE]..." 73 //usage:#define grep_full_usage "\n\n" 74 //usage: "Search for PATTERN in FILEs (or stdin)\n" 75 //usage: "\nOptions:" 76 //usage: "\n -H Add 'filename:' prefix" 77 //usage: "\n -h Do not add 'filename:' prefix" 78 //usage: "\n -n Add 'line_no:' prefix" 79 //usage: "\n -l Show only names of files that match" 80 //usage: "\n -L Show only names of files that don't match" 81 //usage: "\n -c Show only count of matching lines" 82 //usage: "\n -o Show only the matching part of line" 83 //usage: "\n -q Quiet. Return 0 if PATTERN is found, 1 otherwise" 84 //usage: "\n -v Select non-matching lines" 85 //usage: "\n -s Suppress open and read errors" 86 //usage: "\n -r Recurse" 87 //usage: "\n -i Ignore case" 88 //usage: "\n -w Match whole words only" 89 //usage: "\n -F PATTERN is a literal (not regexp)" 90 //usage: IF_FEATURE_GREP_EGREP_ALIAS( 91 //usage: "\n -E PATTERN is an extended regexp" 92 //usage: ) 93 //usage: IF_EXTRA_COMPAT( 94 //usage: "\n -z Input is NUL terminated" 95 //usage: ) 96 //usage: "\n -m N Match up to N times per file" 97 //usage: IF_FEATURE_GREP_CONTEXT( 98 //usage: "\n -A N Print N lines of trailing context" 99 //usage: "\n -B N Print N lines of leading context" 100 //usage: "\n -C N Same as '-A N -B N'" 101 //usage: ) 102 //usage: "\n -e PTRN Pattern to match" 103 //usage: "\n -f FILE Read pattern from file" 104 //usage: 105 //usage:#define grep_example_usage 106 //usage: "$ grep root /etc/passwd\n" 107 //usage: "root:x:0:0:root:/root:/bin/bash\n" 108 //usage: "$ grep ^[rR]oo. /etc/passwd\n" 109 //usage: "root:x:0:0:root:/root:/bin/bash\n" 110 //usage: 111 //usage:#define egrep_trivial_usage NOUSAGE_STR 112 //usage:#define egrep_full_usage "" 113 //usage:#define fgrep_trivial_usage NOUSAGE_STR 114 //usage:#define fgrep_full_usage "" 115 26 116 #define OPTSTR_GREP \ 27 "lnqvscFiHhe:f:Lorm: " \28 USE_FEATURE_GREP_CONTEXT("A:B:C:") \29 USE_FEATURE_GREP_EGREP_ALIAS("E") \30 USE_DESKTOP("w") \117 "lnqvscFiHhe:f:Lorm:w" \ 118 IF_FEATURE_GREP_CONTEXT("A:B:C:") \ 119 IF_FEATURE_GREP_EGREP_ALIAS("E") \ 120 IF_EXTRA_COMPAT("z") \ 31 121 "aI" 32 122 /* ignored: -a "assume all files to be text" */ 33 123 /* ignored: -I "assume binary files have no matches" */ 34 35 124 enum { 36 125 OPTBIT_l, /* list matched file names only */ 37 126 OPTBIT_n, /* print line# */ 38 OPTBIT_q, /* quiet - exit( 0) of first match */127 OPTBIT_q, /* quiet - exit(EXIT_SUCCESS) of first match */ 39 128 OPTBIT_v, /* invert the match, to select non-matching lines */ 40 129 OPTBIT_s, /* suppress errors about file open errors */ … … 50 139 OPTBIT_r, /* recurse dirs */ 51 140 OPTBIT_m, /* -m MAX_MATCHES */ 52 USE_FEATURE_GREP_CONTEXT( OPTBIT_A ,) /* -A NUM: after-match context */ 53 USE_FEATURE_GREP_CONTEXT( OPTBIT_B ,) /* -B NUM: before-match context */ 54 USE_FEATURE_GREP_CONTEXT( OPTBIT_C ,) /* -C NUM: -A and -B combined */ 55 USE_FEATURE_GREP_EGREP_ALIAS(OPTBIT_E ,) /* extended regexp */ 56 USE_DESKTOP( OPTBIT_w ,) /* whole word match */ 141 OPTBIT_w, /* -w whole word match */ 142 IF_FEATURE_GREP_CONTEXT( OPTBIT_A ,) /* -A NUM: after-match context */ 143 IF_FEATURE_GREP_CONTEXT( OPTBIT_B ,) /* -B NUM: before-match context */ 144 IF_FEATURE_GREP_CONTEXT( OPTBIT_C ,) /* -C NUM: -A and -B combined */ 145 IF_FEATURE_GREP_EGREP_ALIAS(OPTBIT_E ,) /* extended regexp */ 146 IF_EXTRA_COMPAT( OPTBIT_z ,) /* input is NUL terminated */ 57 147 OPT_l = 1 << OPTBIT_l, 58 148 OPT_n = 1 << OPTBIT_n, … … 71 161 OPT_r = 1 << OPTBIT_r, 72 162 OPT_m = 1 << OPTBIT_m, 73 OPT_A = USE_FEATURE_GREP_CONTEXT( (1 << OPTBIT_A)) + 0, 74 OPT_B = USE_FEATURE_GREP_CONTEXT( (1 << OPTBIT_B)) + 0, 75 OPT_C = USE_FEATURE_GREP_CONTEXT( (1 << OPTBIT_C)) + 0, 76 OPT_E = USE_FEATURE_GREP_EGREP_ALIAS((1 << OPTBIT_E)) + 0, 77 OPT_w = USE_DESKTOP( (1 << OPTBIT_w)) + 0, 163 OPT_w = 1 << OPTBIT_w, 164 OPT_A = IF_FEATURE_GREP_CONTEXT( (1 << OPTBIT_A)) + 0, 165 OPT_B = IF_FEATURE_GREP_CONTEXT( (1 << OPTBIT_B)) + 0, 166 OPT_C = IF_FEATURE_GREP_CONTEXT( (1 << OPTBIT_C)) + 0, 167 OPT_E = IF_FEATURE_GREP_EGREP_ALIAS((1 << OPTBIT_E)) + 0, 168 OPT_z = IF_EXTRA_COMPAT( (1 << OPTBIT_z)) + 0, 78 169 }; 79 170 … … 85 176 #define FGREP_FLAG (option_mask32 & OPT_F) 86 177 #define PRINT_FILES_WITHOUT_MATCHES (option_mask32 & OPT_L) 87 88 typedef unsigned char byte_t; 89 90 static int max_matches; 91 static int reflags; 92 static byte_t invert_search; 93 static byte_t print_filename; 94 static byte_t open_errors; 95 178 #define NUL_DELIMITED (option_mask32 & OPT_z) 179 180 struct globals { 181 int max_matches; 182 #if !ENABLE_EXTRA_COMPAT 183 int reflags; 184 #else 185 RE_TRANSLATE_TYPE case_fold; /* RE_TRANSLATE_TYPE is [[un]signed] char* */ 186 #endif 187 smalluint invert_search; 188 smalluint print_filename; 189 smalluint open_errors; 96 190 #if ENABLE_FEATURE_GREP_CONTEXT 97 static byte_t did_print_line; 98 static int lines_before; 99 static int lines_after; 100 static char **before_buf; 101 static int last_line_printed; 102 #endif /* ENABLE_FEATURE_GREP_CONTEXT */ 103 /* globals used internally */ 104 static llist_t *pattern_head; /* growable list of patterns to match */ 105 static const char *cur_file; /* the current file we are reading */ 191 smalluint did_print_line; 192 int lines_before; 193 int lines_after; 194 char **before_buf; 195 IF_EXTRA_COMPAT(size_t *before_buf_size;) 196 int last_line_printed; 197 #endif 198 /* globals used internally */ 199 llist_t *pattern_head; /* growable list of patterns to match */ 200 const char *cur_file; /* the current file we are reading */ 201 } FIX_ALIASING; 202 #define G (*(struct globals*)&bb_common_bufsiz1) 203 #define INIT_G() do { \ 204 struct G_sizecheck { \ 205 char G_sizecheck[sizeof(G) > COMMON_BUFSIZE ? -1 : 1]; \ 206 }; \ 207 } while (0) 208 #define max_matches (G.max_matches ) 209 #if !ENABLE_EXTRA_COMPAT 210 # define reflags (G.reflags ) 211 #else 212 # define case_fold (G.case_fold ) 213 /* http://www.delorie.com/gnu/docs/regex/regex_46.html */ 214 # define reflags re_syntax_options 215 # undef REG_NOSUB 216 # undef REG_EXTENDED 217 # undef REG_ICASE 218 # define REG_NOSUB bug:is:here /* should not be used */ 219 /* Just RE_SYNTAX_EGREP is not enough, need to enable {n[,[m]]} too */ 220 # define REG_EXTENDED (RE_SYNTAX_EGREP | RE_INTERVALS | RE_NO_BK_BRACES) 221 # define REG_ICASE bug:is:here /* should not be used */ 222 #endif 223 #define invert_search (G.invert_search ) 224 #define print_filename (G.print_filename ) 225 #define open_errors (G.open_errors ) 226 #define did_print_line (G.did_print_line ) 227 #define lines_before (G.lines_before ) 228 #define lines_after (G.lines_after ) 229 #define before_buf (G.before_buf ) 230 #define before_buf_size (G.before_buf_size ) 231 #define last_line_printed (G.last_line_printed ) 232 #define pattern_head (G.pattern_head ) 233 #define cur_file (G.cur_file ) 234 106 235 107 236 typedef struct grep_list_data_t { 108 237 char *pattern; 109 regex_t preg; 110 #define PATTERN_MEM_A 1 238 /* for GNU regex, matched_range must be persistent across grep_file() calls */ 239 #if !ENABLE_EXTRA_COMPAT 240 regex_t compiled_regex; 241 regmatch_t matched_range; 242 #else 243 struct re_pattern_buffer compiled_regex; 244 struct re_registers matched_range; 245 #endif 246 #define ALLOCATED 1 111 247 #define COMPILED 2 112 248 int flg_mem_alocated_compiled; 113 249 } grep_list_data_t; 114 250 115 static void print_line(const char *line, int linenum, char decoration) 251 #if !ENABLE_EXTRA_COMPAT 252 #define print_line(line, line_len, linenum, decoration) \ 253 print_line(line, linenum, decoration) 254 #endif 255 static void print_line(const char *line, size_t line_len, int linenum, char decoration) 116 256 { 117 257 #if ENABLE_FEATURE_GREP_CONTEXT … … 121 261 return; 122 262 /* possibly print the little '--' separator */ 123 if ((lines_before || lines_after) && did_print_line && 124 last_line_printed != linenum - 1) { 263 if ((lines_before || lines_after) && did_print_line 264 && last_line_printed != linenum - 1 265 ) { 125 266 puts("--"); 126 267 } … … 134 275 printf("%i%c", linenum, decoration); 135 276 /* Emulate weird GNU grep behavior with -ov */ 136 if ((option_mask32 & (OPT_v|OPT_o)) != (OPT_v|OPT_o)) 277 if ((option_mask32 & (OPT_v|OPT_o)) != (OPT_v|OPT_o)) { 278 #if !ENABLE_EXTRA_COMPAT 137 279 puts(line); 280 #else 281 fwrite(line, 1, line_len, stdout); 282 putchar(NUL_DELIMITED ? '\0' : '\n'); 283 #endif 284 } 138 285 } 286 287 #if ENABLE_EXTRA_COMPAT 288 /* Unlike getline, this one removes trailing '\n' */ 289 static ssize_t FAST_FUNC bb_getline(char **line_ptr, size_t *line_alloc_len, FILE *file) 290 { 291 ssize_t res_sz; 292 char *line; 293 int delim = (NUL_DELIMITED ? '\0' : '\n'); 294 295 res_sz = getdelim(line_ptr, line_alloc_len, delim, file); 296 line = *line_ptr; 297 298 if (res_sz > 0) { 299 if (line[res_sz - 1] == delim) 300 line[--res_sz] = '\0'; 301 } else { 302 free(line); /* uclibc allocates a buffer even on EOF. WTF? */ 303 } 304 return res_sz; 305 } 306 #endif 139 307 140 308 static int grep_file(FILE *file) 141 309 { 142 char *line; 143 byte_t ret; 310 smalluint found; 144 311 int linenum = 0; 145 312 int nmatches = 0; 146 regmatch_t regmatch; 313 #if !ENABLE_EXTRA_COMPAT 314 char *line; 315 #else 316 char *line = NULL; 317 ssize_t line_len; 318 size_t line_alloc_len; 319 # define rm_so start[0] 320 # define rm_eo end[0] 321 #endif 147 322 #if ENABLE_FEATURE_GREP_CONTEXT 148 323 int print_n_lines_after = 0; … … 151 326 #else 152 327 enum { print_n_lines_after = 0 }; 153 #endif /* ENABLE_FEATURE_GREP_CONTEXT */ 154 155 while ((line = xmalloc_getline(file)) != NULL) { 328 #endif 329 330 while ( 331 #if !ENABLE_EXTRA_COMPAT 332 (line = xmalloc_fgetline(file)) != NULL 333 #else 334 (line_len = bb_getline(&line, &line_alloc_len, file)) >= 0 335 #endif 336 ) { 156 337 llist_t *pattern_ptr = pattern_head; 157 grep_list_data_t * gl;338 grep_list_data_t *gl = gl; /* for gcc */ 158 339 159 340 linenum++; 160 ret= 0;341 found = 0; 161 342 while (pattern_ptr) { 162 343 gl = (grep_list_data_t *)pattern_ptr->data; 163 344 if (FGREP_FLAG) { 164 ret = strstr(line, gl->pattern) != NULL; 345 found |= (((option_mask32 & OPT_i) 346 ? strcasestr(line, gl->pattern) 347 : strstr(line, gl->pattern) 348 ) != NULL); 165 349 } else { 166 /*167 * test for a postitive-assertion match (regexec returns success (0)168 * and the user did not specify invert search), or a negative-assertion169 * match (regexec returns failure (REG_NOMATCH) and the user specified170 * invert search)171 */172 350 if (!(gl->flg_mem_alocated_compiled & COMPILED)) { 173 351 gl->flg_mem_alocated_compiled |= COMPILED; 174 xregcomp(&(gl->preg), gl->pattern, reflags); 352 #if !ENABLE_EXTRA_COMPAT 353 xregcomp(&gl->compiled_regex, gl->pattern, reflags); 354 #else 355 memset(&gl->compiled_regex, 0, sizeof(gl->compiled_regex)); 356 gl->compiled_regex.translate = case_fold; /* for -i */ 357 if (re_compile_pattern(gl->pattern, strlen(gl->pattern), &gl->compiled_regex)) 358 bb_error_msg_and_die("bad regex '%s'", gl->pattern); 359 #endif 175 360 } 176 regmatch.rm_so = 0; 177 regmatch.rm_eo = 0; 178 if (regexec(&(gl->preg), line, 1, ®match, 0) == 0) { 361 #if !ENABLE_EXTRA_COMPAT 362 gl->matched_range.rm_so = 0; 363 gl->matched_range.rm_eo = 0; 364 #endif 365 if ( 366 #if !ENABLE_EXTRA_COMPAT 367 regexec(&gl->compiled_regex, line, 1, &gl->matched_range, 0) == 0 368 #else 369 re_search(&gl->compiled_regex, line, line_len, 370 /*start:*/ 0, /*range:*/ line_len, 371 &gl->matched_range) >= 0 372 #endif 373 ) { 179 374 if (!(option_mask32 & OPT_w)) 180 ret= 1;375 found = 1; 181 376 else { 182 377 char c = ' '; 183 if ( regmatch.rm_so)184 c = line[ regmatch.rm_so - 1];378 if (gl->matched_range.rm_so) 379 c = line[gl->matched_range.rm_so - 1]; 185 380 if (!isalnum(c) && c != '_') { 186 c = line[ regmatch.rm_eo];381 c = line[gl->matched_range.rm_eo]; 187 382 if (!c || (!isalnum(c) && c != '_')) 188 ret= 1;383 found = 1; 189 384 } 190 385 } 191 386 } 192 387 } 388 /* If it's non-inverted search, we can stop 389 * at first match */ 390 if (found && !invert_search) 391 goto do_found; 193 392 pattern_ptr = pattern_ptr->link; 194 393 } /* while (pattern_ptr) */ 195 394 196 if (ret ^ invert_search) { 395 if (found ^ invert_search) { 396 do_found: 197 397 /* keep track of matches */ 198 398 nmatches++; … … 206 406 * if any match is found, 207 407 * even if errors were detected" */ 208 exit( 0);408 exit(EXIT_SUCCESS); 209 409 } 210 410 /* if we're just printing filenames, we stop after the first match */ 211 411 if (PRINT_FILES_WITH_MATCHES) { 212 412 puts(cur_file); 213 /* fall thr uto "return 1" */413 /* fall through to "return 1" */ 214 414 } 215 415 /* OPT_L aka PRINT_FILES_WITHOUT_MATCHES: return early */ … … 244 444 /* now print each line in the buffer, clearing them as we go */ 245 445 while (before_buf[idx] != NULL) { 246 print_line(before_buf[idx], first_buf_entry_line_num, '-');446 print_line(before_buf[idx], before_buf_size[idx], first_buf_entry_line_num, '-'); 247 447 free(before_buf[idx]); 248 448 before_buf[idx] = NULL; … … 256 456 #endif 257 457 if (option_mask32 & OPT_o) { 258 line[regmatch.rm_eo] = '\0'; 259 print_line(line + regmatch.rm_so, linenum, ':'); 458 if (FGREP_FLAG) { 459 /* -Fo just prints the pattern 460 * (unless -v: -Fov doesnt print anything at all) */ 461 if (found) 462 print_line(gl->pattern, strlen(gl->pattern), linenum, ':'); 463 } else while (1) { 464 unsigned start = gl->matched_range.rm_so; 465 unsigned end = gl->matched_range.rm_eo; 466 unsigned len = end - start; 467 char old = line[end]; 468 line[end] = '\0'; 469 /* Empty match is not printed: try "echo test | grep -o ''" */ 470 if (len != 0) 471 print_line(line + start, len, linenum, ':'); 472 if (old == '\0') 473 break; 474 line[end] = old; 475 if (len == 0) 476 end++; 477 #if !ENABLE_EXTRA_COMPAT 478 if (regexec(&gl->compiled_regex, line + end, 479 1, &gl->matched_range, REG_NOTBOL) != 0) 480 break; 481 gl->matched_range.rm_so += end; 482 gl->matched_range.rm_eo += end; 483 #else 484 if (re_search(&gl->compiled_regex, line, line_len, 485 end, line_len - end, 486 &gl->matched_range) < 0) 487 break; 488 #endif 489 } 260 490 } else { 261 print_line(line, line num, ':');491 print_line(line, line_len, linenum, ':'); 262 492 } 263 493 } … … 267 497 /* if we need to print some context lines after the last match, do so */ 268 498 if (print_n_lines_after) { 269 print_line(line, linenum, '-');499 print_line(line, strlen(line), linenum, '-'); 270 500 print_n_lines_after--; 271 501 } else if (lines_before) { … … 273 503 free(before_buf[curpos]); 274 504 before_buf[curpos] = line; 505 IF_EXTRA_COMPAT(before_buf_size[curpos] = line_len;) 275 506 curpos = (curpos + 1) % lines_before; 276 /* avoid free(line) - we took line */507 /* avoid free(line) - we took the line */ 277 508 line = NULL; 278 509 } … … 280 511 281 512 #endif /* ENABLE_FEATURE_GREP_CONTEXT */ 513 #if !ENABLE_EXTRA_COMPAT 282 514 free(line); 283 515 #endif 284 516 /* Did we print all context after last requested match? */ 285 517 if ((option_mask32 & OPT_m) 286 && !print_n_lines_after && nmatches == max_matches) 518 && !print_n_lines_after 519 && nmatches == max_matches 520 ) { 287 521 break; 288 } 522 } 523 } /* while (read line) */ 289 524 290 525 /* special-case file post-processing for options where we don't print line … … 311 546 #if ENABLE_FEATURE_CLEAN_UP 312 547 #define new_grep_list_data(p, m) add_grep_list_data(p, m) 313 static char * 548 static char *add_grep_list_data(char *pattern, int flg_used_mem) 314 549 #else 315 550 #define new_grep_list_data(p, m) add_grep_list_data(p) 316 static char * 551 static char *add_grep_list_data(char *pattern) 317 552 #endif 318 553 { 319 grep_list_data_t *gl = x malloc(sizeof(grep_list_data_t));554 grep_list_data_t *gl = xzalloc(sizeof(*gl)); 320 555 gl->pattern = pattern; 321 556 #if ENABLE_FEATURE_CLEAN_UP 322 557 gl->flg_mem_alocated_compiled = flg_used_mem; 323 558 #else 324 gl->flg_mem_alocated_compiled = 0;559 /*gl->flg_mem_alocated_compiled = 0;*/ 325 560 #endif 326 561 return (char *)gl; … … 338 573 fopt = cur->link; 339 574 free(cur); 340 f = xfopen (ffile, "r");341 while ((line = xmalloc_ getline(f)) != NULL) {575 f = xfopen_stdin(ffile); 576 while ((line = xmalloc_fgetline(f)) != NULL) { 342 577 llist_add_to(&pattern_head, 343 new_grep_list_data(line, PATTERN_MEM_A));578 new_grep_list_data(line, ALLOCATED)); 344 579 } 345 580 } 346 581 } 347 582 348 static int file_action_grep(const char *filename, struct stat *statbuf, void* matched, int depth) 583 static int FAST_FUNC file_action_grep(const char *filename, 584 struct stat *statbuf UNUSED_PARAM, 585 void* matched, 586 int depth UNUSED_PARAM) 349 587 { 350 FILE *file = fopen (filename, "r");588 FILE *file = fopen_for_read(filename); 351 589 if (file == NULL) { 352 590 if (!SUPPRESS_ERR_MSGS) 353 bb_ perror_msg("%s", cur_file);591 bb_simple_perror_msg(filename); 354 592 open_errors = 1; 355 593 return 0; … … 375 613 } 376 614 377 int grep_main(int argc, char **argv) ;378 int grep_main(int argc , char **argv)615 int grep_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 616 int grep_main(int argc UNUSED_PARAM, char **argv) 379 617 { 380 618 FILE *file; 381 619 int matched; 382 char *mopt;383 620 llist_t *fopt = NULL; 384 621 385 622 /* do normal option parsing */ 386 623 #if ENABLE_FEATURE_GREP_CONTEXT 387 char *slines_after;388 char *slines_before; 389 char *Copt;390 391 opt_complementary = "H-h: e::f::C-AB";392 getopt32(argv,624 int Copt, opts; 625 626 /* -H unsets -h; -C unsets -A,-B; -e,-f are lists; 627 * -m,-A,-B,-C have numeric param */ 628 opt_complementary = "H-h:C-AB:e::f::m+:A+:B+:C+"; 629 opts = getopt32(argv, 393 630 OPTSTR_GREP, 394 &pattern_head, &fopt, &m opt,395 & slines_after, &slines_before, &Copt);396 397 if (opt ion_mask32& OPT_C) {631 &pattern_head, &fopt, &max_matches, 632 &lines_after, &lines_before, &Copt); 633 634 if (opts & OPT_C) { 398 635 /* -C unsets prev -A and -B, but following -A or -B 399 636 may override it */ 400 if (!(option_mask32 & OPT_A)) /* not overridden */ 401 slines_after = Copt; 402 if (!(option_mask32 & OPT_B)) /* not overridden */ 403 slines_before = Copt; 404 option_mask32 |= OPT_A|OPT_B; /* for parser */ 405 } 406 if (option_mask32 & OPT_A) { 407 lines_after = xatoi_u(slines_after); 408 } 409 if (option_mask32 & OPT_B) { 410 lines_before = xatoi_u(slines_before); 637 if (!(opts & OPT_A)) /* not overridden */ 638 lines_after = Copt; 639 if (!(opts & OPT_B)) /* not overridden */ 640 lines_before = Copt; 411 641 } 412 642 /* sanity checks */ 413 if (opt ion_mask32& (OPT_c|OPT_q|OPT_l|OPT_L)) {643 if (opts & (OPT_c|OPT_q|OPT_l|OPT_L)) { 414 644 option_mask32 &= ~OPT_n; 415 645 lines_before = 0; 416 646 lines_after = 0; 417 } else if (lines_before > 0) 418 before_buf = xzalloc(lines_before * sizeof(char *)); 647 } else if (lines_before > 0) { 648 if (lines_before > INT_MAX / sizeof(long long)) 649 lines_before = INT_MAX / sizeof(long long); 650 /* overflow in (lines_before * sizeof(x)) is prevented (above) */ 651 before_buf = xzalloc(lines_before * sizeof(before_buf[0])); 652 IF_EXTRA_COMPAT(before_buf_size = xzalloc(lines_before * sizeof(before_buf_size[0]));) 653 } 419 654 #else 420 655 /* with auto sanity checks */ 421 opt_complementary = "H-h:e::f::c-n:q-n:l-n"; 656 /* -H unsets -h; -c,-q or -l unset -n; -e,-f are lists; -m N */ 657 opt_complementary = "H-h:c-n:q-n:l-n:e::f::m+"; 422 658 getopt32(argv, OPTSTR_GREP, 423 &pattern_head, &fopt, &mopt); 424 #endif 425 if (option_mask32 & OPT_m) { 426 max_matches = xatoi_u(mopt); 427 } 659 &pattern_head, &fopt, &max_matches); 660 #endif 428 661 invert_search = ((option_mask32 & OPT_v) != 0); /* 0 | 1 */ 429 662 … … 441 674 option_mask32 |= OPT_F; 442 675 676 #if !ENABLE_EXTRA_COMPAT 443 677 if (!(option_mask32 & (OPT_o | OPT_w))) 444 678 reflags = REG_NOSUB; 445 446 if (ENABLE_FEATURE_GREP_EGREP_ALIAS && 447 (applet_name[0] == 'e' || (option_mask32 & OPT_E))) 679 #endif 680 681 if (ENABLE_FEATURE_GREP_EGREP_ALIAS 682 && (applet_name[0] == 'e' || (option_mask32 & OPT_E)) 683 ) { 448 684 reflags |= REG_EXTENDED; 449 450 if (option_mask32 & OPT_i) 685 } 686 #if ENABLE_EXTRA_COMPAT 687 else { 688 reflags = RE_SYNTAX_GREP; 689 } 690 #endif 691 692 if (option_mask32 & OPT_i) { 693 #if !ENABLE_EXTRA_COMPAT 451 694 reflags |= REG_ICASE; 695 #else 696 int i; 697 case_fold = xmalloc(256); 698 for (i = 0; i < 256; i++) 699 case_fold[i] = (unsigned char)i; 700 for (i = 'a'; i <= 'z'; i++) 701 case_fold[i] = (unsigned char)(i - ('a' - 'A')); 702 #endif 703 } 452 704 453 705 argv += optind; 454 argc -= optind; 455 456 /* if we didn't get a pattern from a -e and no command file was specified, 457 * argv[optind] should be the pattern. no pattern, no worky */ 706 707 /* if we didn't get a pattern from -e and no command file was specified, 708 * first parameter should be the pattern. no pattern, no worky */ 458 709 if (pattern_head == NULL) { 459 710 char *pattern; … … 462 713 pattern = new_grep_list_data(*argv++, 0); 463 714 llist_add_to(&pattern_head, pattern); 464 argc--; 465 } 466 467 /* argv[(optind)..(argc-1)] should be names of file to grep through. If 715 } 716 717 /* argv[0..(argc-1)] should be names of file to grep through. If 468 718 * there is more than one file to grep, we will print the filenames. */ 469 if (arg c > 1)719 if (argv[0] && argv[1]) 470 720 print_filename = 1; 471 721 /* -H / -h of course override */ … … 477 727 /* If no files were specified, or '-' was specified, take input from 478 728 * stdin. Otherwise, we grep through all the files specified. */ 479 if (argc == 0)480 argc++;481 729 matched = 0; 482 while (argc--){483 cur_file = *argv ++;730 do { 731 cur_file = *argv; 484 732 file = stdin; 485 if (!cur_file || (*cur_file == '-' && !cur_file[1])) {733 if (!cur_file || LONE_DASH(cur_file)) { 486 734 cur_file = "(standard input)"; 487 735 } else { … … 496 744 } 497 745 /* else: fopen(dir) will succeed, but reading won't */ 498 file = fopen (cur_file, "r");746 file = fopen_for_read(cur_file); 499 747 if (file == NULL) { 500 748 if (!SUPPRESS_ERR_MSGS) 501 bb_ perror_msg("%s",cur_file);749 bb_simple_perror_msg(cur_file); 502 750 open_errors = 1; 503 751 continue; … … 507 755 fclose_if_not_stdin(file); 508 756 grep_done: ; 509 } 757 } while (*argv && *++argv); 510 758 511 759 /* destroy all the elments in the pattern list */ … … 513 761 while (pattern_head) { 514 762 llist_t *pattern_head_ptr = pattern_head; 515 grep_list_data_t *gl = 516 (grep_list_data_t *)pattern_head_ptr->data; 763 grep_list_data_t *gl = (grep_list_data_t *)pattern_head_ptr->data; 517 764 518 765 pattern_head = pattern_head->link; 519 if ( (gl->flg_mem_alocated_compiled & PATTERN_MEM_A))766 if (gl->flg_mem_alocated_compiled & ALLOCATED) 520 767 free(gl->pattern); 521 if ( (gl->flg_mem_alocated_compiled & COMPILED))522 regfree(& (gl->preg));768 if (gl->flg_mem_alocated_compiled & COMPILED) 769 regfree(&gl->compiled_regex); 523 770 free(gl); 524 771 free(pattern_head_ptr); … … 528 775 if (open_errors) 529 776 return 2; 530 return !matched; /* invert return value 0 = success, 1 = failed */777 return !matched; /* invert return value: 0 = success, 1 = failed */ 531 778 } -
branches/2.2.9/mindi-busybox/findutils/xargs.c
r1765 r2725 2 2 /* 3 3 * Mini xargs implementation for busybox 4 * Options are supported: "-prtx -n max_arg -s max_chars -e[ouf_str]"5 4 * 6 5 * (C) 2002,2003 by Vladimir Oleynik <dzo@simtreas.ru> … … 11 10 * and David MacKenzie <djm@gnu.ai.mit.edu>. 12 11 * 13 * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.12 * Licensed under GPLv2 or later, see file LICENSE in this source tree. 14 13 * 15 14 * xargs is described in the Single Unix Specification v3 at 16 15 * http://www.opengroup.org/onlinepubs/007904975/utilities/xargs.html 17 *18 16 */ 19 17 18 //applet:IF_XARGS(APPLET_NOEXEC(xargs, xargs, _BB_DIR_USR_BIN, _BB_SUID_DROP, xargs)) 19 20 //kbuild:lib-$(CONFIG_XARGS) += xargs.o 21 22 //config:config XARGS 23 //config: bool "xargs" 24 //config: default y 25 //config: help 26 //config: xargs is used to execute a specified command for 27 //config: every item from standard input. 28 //config: 29 //config:config FEATURE_XARGS_SUPPORT_CONFIRMATION 30 //config: bool "Enable -p: prompt and confirmation" 31 //config: default y 32 //config: depends on XARGS 33 //config: help 34 //config: Support -p: prompt the user whether to run each command 35 //config: line and read a line from the terminal. 36 //config: 37 //config:config FEATURE_XARGS_SUPPORT_QUOTES 38 //config: bool "Enable single and double quotes and backslash" 39 //config: default y 40 //config: depends on XARGS 41 //config: help 42 //config: Support quoting in the input. 43 //config: 44 //config:config FEATURE_XARGS_SUPPORT_TERMOPT 45 //config: bool "Enable -x: exit if -s or -n is exceeded" 46 //config: default y 47 //config: depends on XARGS 48 //config: help 49 //config: Support -x: exit if the command size (see the -s or -n option) 50 //config: is exceeded. 51 //config: 52 //config:config FEATURE_XARGS_SUPPORT_ZERO_TERM 53 //config: bool "Enable -0: NUL-terminated input" 54 //config: default y 55 //config: depends on XARGS 56 //config: help 57 //config: Support -0: input items are terminated by a NUL character 58 //config: instead of whitespace, and the quotes and backslash 59 //config: are not special. 60 20 61 #include "libbb.h" 21 62 … … 23 64 24 65 25 /* COMPAT: SYSV version defaults size (and has a max value of) to 470. 26 We try to make it as large as possible. */ 27 #if !defined(ARG_MAX) && defined(_SC_ARG_MAX) 28 #define ARG_MAX sysconf (_SC_ARG_MAX) 29 #endif 30 #ifndef ARG_MAX 31 #define ARG_MAX 470 32 #endif 66 //#define dbg_msg(...) bb_error_msg(__VA_ARGS__) 67 #define dbg_msg(...) ((void)0) 33 68 34 69 … … 48 83 #endif 49 84 85 86 struct globals { 87 char **args; 88 const char *eof_str; 89 int idx; 90 } FIX_ALIASING; 91 #define G (*(struct globals*)&bb_common_bufsiz1) 92 #define INIT_G() do { } while (0) 93 94 50 95 /* 51 52 53 */54 static int xargs_exec( char **args)96 * This function has special algorithm. 97 * Don't use fork and include to main! 98 */ 99 static int xargs_exec(void) 55 100 { 56 101 int status; 57 102 58 status = spawn_and_wait( args);103 status = spawn_and_wait(G.args); 59 104 if (status < 0) { 60 bb_ perror_msg("%s",args[0]);105 bb_simple_perror_msg(G.args[0]); 61 106 return errno == ENOENT ? 127 : 126; 62 107 } 63 108 if (status == 255) { 64 bb_error_msg("%s: exited with status 255; aborting", args[0]);109 bb_error_msg("%s: exited with status 255; aborting", G.args[0]); 65 110 return 124; 66 111 } 67 /* Huh? I think we won't see this, ever. We don't wait with WUNTRACED! 68 if (WIFSTOPPED(status)) { 69 bb_error_msg("%s: stopped by signal %d", 70 args[0], WSTOPSIG(status)); 71 return 125; 72 } 73 */ 74 if (status >= 1000) { 112 if (status >= 0x180) { 75 113 bb_error_msg("%s: terminated by signal %d", 76 args[0], status - 1000);114 G.args[0], status - 0x180); 77 115 return 125; 78 116 } … … 82 120 } 83 121 84 85 typedef struct xlist_t { 86 struct xlist_t *link; 87 size_t length; 88 char xstr[1]; 89 } xlist_t; 90 91 static smallint eof_stdin_detected; 92 93 #define ISBLANK(c) ((c) == ' ' || (c) == '\t') 94 #define ISSPACE(c) (ISBLANK(c) || (c) == '\n' || (c) == '\r' \ 95 || (c) == '\f' || (c) == '\v') 122 /* In POSIX/C locale isspace is only these chars: "\t\n\v\f\r" and space. 123 * "\t\n\v\f\r" happen to have ASCII codes 9,10,11,12,13. 124 */ 125 #define ISSPACE(a) ({ unsigned char xargs__isspace = (a) - 9; xargs__isspace == (' ' - 9) || xargs__isspace <= (13 - 9); }) 126 127 static void store_param(char *s) 128 { 129 /* Grow by 256 elements at once */ 130 if (!(G.idx & 0xff)) { /* G.idx == N*256 */ 131 /* Enlarge, make G.args[(N+1)*256 - 1] last valid idx */ 132 G.args = xrealloc(G.args, sizeof(G.args[0]) * (G.idx + 0x100)); 133 } 134 G.args[G.idx++] = s; 135 } 136 137 /* process[0]_stdin: 138 * Read characters into buf[n_max_chars+1], and when parameter delimiter 139 * is seen, store the address of a new parameter to args[]. 140 * If reading discovers that last chars do not form the complete 141 * parameter, the pointer to the first such "tail character" is returned. 142 * (buf has extra byte at the end to accomodate terminating NUL 143 * of "tail characters" string). 144 * Otherwise, the returned pointer points to NUL byte. 145 * On entry, buf[] may contain some "seed chars" which are to become 146 * the beginning of the first parameter. 147 */ 96 148 97 149 #if ENABLE_FEATURE_XARGS_SUPPORT_QUOTES 98 static xlist_t *process_stdin(xlist_t *list_arg, 99 const char *eof_str, size_t mc, char *buf) 150 static char* FAST_FUNC process_stdin(int n_max_chars, int n_max_arg, char *buf) 100 151 { 101 152 #define NORM 0 … … 103 154 #define BACKSLASH 2 104 155 #define SPACE 4 105 106 char *s = NULL; /* start word */ 107 char *p = NULL; /* pointer to end word */ 108 char q = '\0'; /* quote char */ 156 char q = '\0'; /* quote char */ 109 157 char state = NORM; 110 char eof_str_detected = 0; 111 size_t line_l = 0; /* size loaded args line */ 112 int c; /* current char */ 113 xlist_t *cur; 114 xlist_t *prev; 115 116 prev = cur = list_arg; 158 char *s = buf; /* start of the word */ 159 char *p = s + strlen(buf); /* end of the word */ 160 161 buf += n_max_chars; /* past buffer's end */ 162 163 /* "goto ret" is used instead of "break" to make control flow 164 * more obvious: */ 165 117 166 while (1) { 118 if (!cur) break; 119 prev = cur; 120 line_l += cur->length; 121 cur = cur->link; 122 } 123 124 while (!eof_stdin_detected) { 125 c = getchar(); 167 int c = getchar(); 126 168 if (c == EOF) { 127 eof_stdin_detected = 1; 128 if (s) 129 goto unexpected_eof; 130 break; 131 } 132 if (eof_str_detected) 133 continue; 169 if (p != s) 170 goto close_word; 171 goto ret; 172 } 134 173 if (state == BACKSLASH) { 135 174 state = NORM; 136 175 goto set; 137 } else if (state == QUOTE) { 176 } 177 if (state == QUOTE) { 138 178 if (c != q) 139 179 goto set; … … 142 182 } else { /* if (state == NORM) */ 143 183 if (ISSPACE(c)) { 144 if ( s) {145 unexpected_eof:184 if (p != s) { 185 close_word: 146 186 state = SPACE; 147 187 c = '\0'; … … 149 189 } 150 190 } else { 151 if (s == NULL)152 s = p = buf;153 191 if (c == '\\') { 154 192 state = BACKSLASH; … … 158 196 } else { 159 197 set: 160 if ((size_t)(p - buf) >= mc)161 bb_error_msg_and_die("argument line too long");162 198 *p++ = c; 163 199 } … … 169 205 q == '\'' ? "single" : "double"); 170 206 } 171 /* word loaded */ 172 if (eof_str) { 173 eof_str_detected = (strcmp(s, eof_str) == 0); 174 } 175 if (!eof_str_detected) { 176 size_t length = (p - buf); 177 /* Dont xzalloc - it can be quite big */ 178 cur = xmalloc(offsetof(xlist_t, xstr) + length); 179 cur->link = NULL; 180 cur->length = length; 181 memcpy(cur->xstr, s, length); 182 if (prev == NULL) { 183 list_arg = cur; 184 } else { 185 prev->link = cur; 207 /* A full word is loaded */ 208 if (G.eof_str) { 209 if (strcmp(s, G.eof_str) == 0) { 210 while (getchar() != EOF) 211 continue; 212 p = s; 213 goto ret; 186 214 } 187 prev = cur;188 line_l += length;189 if (line_l > mc) {190 /* stop memory usage :-) */191 break;192 }193 }194 s = NULL;215 } 216 store_param(s); 217 dbg_msg("args[]:'%s'", s); 218 s = p; 219 n_max_arg--; 220 if (n_max_arg == 0) { 221 goto ret; 222 } 195 223 state = NORM; 196 224 } 197 } 198 return list_arg; 225 if (p == buf) { 226 goto ret; 227 } 228 } 229 ret: 230 *p = '\0'; 231 /* store_param(NULL) - caller will do it */ 232 dbg_msg("return:'%s'", s); 233 return s; 199 234 } 200 235 #else 201 236 /* The variant does not support single quotes, double quotes or backslash */ 202 static xlist_t *process_stdin(xlist_t *list_arg, 203 const char *eof_str, size_t mc, char *buf) 204 { 205 206 int c; /* current char */ 207 char eof_str_detected = 0; 208 char *s = NULL; /* start word */ 209 char *p = NULL; /* pointer to end word */ 210 size_t line_l = 0; /* size loaded args line */ 211 xlist_t *cur; 212 xlist_t *prev; 213 214 prev = cur = list_arg; 237 static char* FAST_FUNC process_stdin(int n_max_chars, int n_max_arg, char *buf) 238 { 239 char *s = buf; /* start of the word */ 240 char *p = s + strlen(buf); /* end of the word */ 241 242 buf += n_max_chars; /* past buffer's end */ 243 215 244 while (1) { 216 if (!cur) break; 217 prev = cur; 218 line_l += cur->length; 219 cur = cur->link; 220 } 221 222 while (!eof_stdin_detected) { 223 c = getchar(); 245 int c = getchar(); 224 246 if (c == EOF) { 225 eof_stdin_detected = 1; 226 } 227 if (eof_str_detected) 228 continue; 247 if (p == s) 248 goto ret; 249 } 229 250 if (c == EOF || ISSPACE(c)) { 230 if ( s == NULL)251 if (p == s) 231 252 continue; 232 253 c = EOF; 233 254 } 234 if (s == NULL)235 s = p = buf;236 if ((p - buf) >= mc)237 bb_error_msg_and_die("argument line too long");238 255 *p++ = (c == EOF ? '\0' : c); 239 256 if (c == EOF) { /* word's delimiter or EOF detected */ 240 /* word loaded */ 241 if (eof_str) { 242 eof_str_detected = (strcmp(s, eof_str) == 0); 243 } 244 if (!eof_str_detected) { 245 size_t length = (p - buf); 246 /* Dont xzalloc - it can be quite big */ 247 cur = xmalloc(offsetof(xlist_t, xstr) + length); 248 cur->link = NULL; 249 cur->length = length; 250 memcpy(cur->xstr, s, length); 251 if (prev == NULL) { 252 list_arg = cur; 253 } else { 254 prev->link = cur; 257 /* A full word is loaded */ 258 if (G.eof_str) { 259 if (strcmp(s, G.eof_str) == 0) { 260 while (getchar() != EOF) 261 continue; 262 p = s; 263 goto ret; 255 264 } 256 prev = cur; 257 line_l += length; 258 if (line_l > mc) { 259 /* stop memory usage :-) */ 260 break; 261 } 262 s = NULL; 263 } 264 } 265 } 266 return list_arg; 265 } 266 store_param(s); 267 dbg_msg("args[]:'%s'", s); 268 s = p; 269 n_max_arg--; 270 if (n_max_arg == 0) { 271 goto ret; 272 } 273 } 274 if (p == buf) { 275 goto ret; 276 } 277 } 278 ret: 279 *p = '\0'; 280 /* store_param(NULL) - caller will do it */ 281 dbg_msg("return:'%s'", s); 282 return s; 267 283 } 268 284 #endif /* FEATURE_XARGS_SUPPORT_QUOTES */ 269 285 286 #if ENABLE_FEATURE_XARGS_SUPPORT_ZERO_TERM 287 static char* FAST_FUNC process0_stdin(int n_max_chars, int n_max_arg, char *buf) 288 { 289 char *s = buf; /* start of the word */ 290 char *p = s + strlen(buf); /* end of the word */ 291 292 buf += n_max_chars; /* past buffer's end */ 293 294 while (1) { 295 int c = getchar(); 296 if (c == EOF) { 297 if (p == s) 298 goto ret; 299 c = '\0'; 300 } 301 *p++ = c; 302 if (c == '\0') { /* word's delimiter or EOF detected */ 303 /* A full word is loaded */ 304 store_param(s); 305 dbg_msg("args[]:'%s'", s); 306 s = p; 307 n_max_arg--; 308 if (n_max_arg == 0) { 309 goto ret; 310 } 311 } 312 if (p == buf) { 313 goto ret; 314 } 315 } 316 ret: 317 *p = '\0'; 318 /* store_param(NULL) - caller will do it */ 319 dbg_msg("return:'%s'", s); 320 return s; 321 } 322 #endif /* FEATURE_XARGS_SUPPORT_ZERO_TERM */ 270 323 271 324 #if ENABLE_FEATURE_XARGS_SUPPORT_CONFIRMATION … … 278 331 int c, savec; 279 332 280 tty_stream = xfopen (CURRENT_TTY, "r");333 tty_stream = xfopen_for_read(CURRENT_TTY); 281 334 fputs(" ?...", stderr); 282 fflush (stderr);335 fflush_all(); 283 336 c = savec = getc(tty_stream); 284 337 while (c != EOF && c != '\n') … … 289 342 #else 290 343 # define xargs_ask_confirmation() 1 291 #endif /* FEATURE_XARGS_SUPPORT_CONFIRMATION */ 292 293 #if ENABLE_FEATURE_XARGS_SUPPORT_ZERO_TERM 294 static xlist_t *process0_stdin(xlist_t *list_arg, 295 const char *eof_str ATTRIBUTE_UNUSED, size_t mc, char *buf) 296 { 297 int c; /* current char */ 298 char *s = NULL; /* start word */ 299 char *p = NULL; /* pointer to end word */ 300 size_t line_l = 0; /* size loaded args line */ 301 xlist_t *cur; 302 xlist_t *prev; 303 304 prev = cur = list_arg; 305 while (1) { 306 if (!cur) break; 307 prev = cur; 308 line_l += cur->length; 309 cur = cur->link; 310 } 311 312 while (!eof_stdin_detected) { 313 c = getchar(); 314 if (c == EOF) { 315 eof_stdin_detected = 1; 316 if (s == NULL) 317 break; 318 c = '\0'; 319 } 320 if (s == NULL) 321 s = p = buf; 322 if ((size_t)(p - buf) >= mc) 323 bb_error_msg_and_die("argument line too long"); 324 *p++ = c; 325 if (c == '\0') { /* word's delimiter or EOF detected */ 326 /* word loaded */ 327 size_t length = (p - buf); 328 /* Dont xzalloc - it can be quite big */ 329 cur = xmalloc(offsetof(xlist_t, xstr) + length); 330 cur->link = NULL; 331 cur->length = length; 332 memcpy(cur->xstr, s, length); 333 if (prev == NULL) { 334 list_arg = cur; 335 } else { 336 prev->link = cur; 337 } 338 prev = cur; 339 line_l += length; 340 if (line_l > mc) { 341 /* stop memory usage :-) */ 342 break; 343 } 344 s = NULL; 345 } 346 } 347 return list_arg; 348 } 349 #endif /* FEATURE_XARGS_SUPPORT_ZERO_TERM */ 344 #endif 345 346 //usage:#define xargs_trivial_usage 347 //usage: "[OPTIONS] [PROG ARGS]" 348 //usage:#define xargs_full_usage "\n\n" 349 //usage: "Run PROG on every item given by stdin\n" 350 //usage: "\nOptions:" 351 //usage: IF_FEATURE_XARGS_SUPPORT_CONFIRMATION( 352 //usage: "\n -p Ask user whether to run each command" 353 //usage: ) 354 //usage: "\n -r Don't run command if input is empty" 355 //usage: IF_FEATURE_XARGS_SUPPORT_ZERO_TERM( 356 //usage: "\n -0 Input is separated by NUL characters" 357 //usage: ) 358 //usage: "\n -t Print the command on stderr before execution" 359 //usage: "\n -e[STR] STR stops input processing" 360 //usage: "\n -n N Pass no more than N args to PROG" 361 //usage: "\n -s N Pass command line of no more than N bytes" 362 //usage: IF_FEATURE_XARGS_SUPPORT_TERMOPT( 363 //usage: "\n -x Exit if size is exceeded" 364 //usage: ) 365 //usage:#define xargs_example_usage 366 //usage: "$ ls | xargs gzip\n" 367 //usage: "$ find . -name '*.c' -print | xargs rm\n" 350 368 351 369 /* Correct regardless of combination of CONFIG_xxx */ … … 356 374 OPTBIT_UPTO_SIZE, 357 375 OPTBIT_EOF_STRING, 358 USE_FEATURE_XARGS_SUPPORT_CONFIRMATION(OPTBIT_INTERACTIVE,) 359 USE_FEATURE_XARGS_SUPPORT_TERMOPT( OPTBIT_TERMINATE ,) 360 USE_FEATURE_XARGS_SUPPORT_ZERO_TERM( OPTBIT_ZEROTERM ,) 361 362 OPT_VERBOSE = 1<<OPTBIT_VERBOSE , 363 OPT_NO_EMPTY = 1<<OPTBIT_NO_EMPTY , 364 OPT_UPTO_NUMBER = 1<<OPTBIT_UPTO_NUMBER, 365 OPT_UPTO_SIZE = 1<<OPTBIT_UPTO_SIZE , 366 OPT_EOF_STRING = 1<<OPTBIT_EOF_STRING , 367 OPT_INTERACTIVE = USE_FEATURE_XARGS_SUPPORT_CONFIRMATION((1<<OPTBIT_INTERACTIVE)) + 0, 368 OPT_TERMINATE = USE_FEATURE_XARGS_SUPPORT_TERMOPT( (1<<OPTBIT_TERMINATE )) + 0, 369 OPT_ZEROTERM = USE_FEATURE_XARGS_SUPPORT_ZERO_TERM( (1<<OPTBIT_ZEROTERM )) + 0, 376 OPTBIT_EOF_STRING1, 377 IF_FEATURE_XARGS_SUPPORT_CONFIRMATION(OPTBIT_INTERACTIVE,) 378 IF_FEATURE_XARGS_SUPPORT_TERMOPT( OPTBIT_TERMINATE ,) 379 IF_FEATURE_XARGS_SUPPORT_ZERO_TERM( OPTBIT_ZEROTERM ,) 380 381 OPT_VERBOSE = 1 << OPTBIT_VERBOSE , 382 OPT_NO_EMPTY = 1 << OPTBIT_NO_EMPTY , 383 OPT_UPTO_NUMBER = 1 << OPTBIT_UPTO_NUMBER, 384 OPT_UPTO_SIZE = 1 << OPTBIT_UPTO_SIZE , 385 OPT_EOF_STRING = 1 << OPTBIT_EOF_STRING , /* GNU: -e[<param>] */ 386 OPT_EOF_STRING1 = 1 << OPTBIT_EOF_STRING1, /* SUS: -E<param> */ 387 OPT_INTERACTIVE = IF_FEATURE_XARGS_SUPPORT_CONFIRMATION((1 << OPTBIT_INTERACTIVE)) + 0, 388 OPT_TERMINATE = IF_FEATURE_XARGS_SUPPORT_TERMOPT( (1 << OPTBIT_TERMINATE )) + 0, 389 OPT_ZEROTERM = IF_FEATURE_XARGS_SUPPORT_ZERO_TERM( (1 << OPTBIT_ZEROTERM )) + 0, 370 390 }; 371 #define OPTION_STR "+trn:s:e:: " \372 USE_FEATURE_XARGS_SUPPORT_CONFIRMATION("p") \373 USE_FEATURE_XARGS_SUPPORT_TERMOPT( "x") \374 USE_FEATURE_XARGS_SUPPORT_ZERO_TERM( "0")375 376 int xargs_main(int argc, char **argv) ;391 #define OPTION_STR "+trn:s:e::E:" \ 392 IF_FEATURE_XARGS_SUPPORT_CONFIRMATION("p") \ 393 IF_FEATURE_XARGS_SUPPORT_TERMOPT( "x") \ 394 IF_FEATURE_XARGS_SUPPORT_ZERO_TERM( "0") 395 396 int xargs_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 377 397 int xargs_main(int argc, char **argv) 378 398 { 379 char **args; 380 int i, n; 381 xlist_t *list = NULL; 382 xlist_t *cur; 399 int i; 383 400 int child_error = 0; 384 char *max_args, *max_chars; 401 char *max_args; 402 char *max_chars; 403 char *buf; 404 unsigned opt; 405 int n_max_chars; 385 406 int n_max_arg; 386 size_t n_chars = 0;387 long orig_arg_max;388 const char *eof_str = "_";389 unsigned opt;390 size_t n_max_chars;391 407 #if ENABLE_FEATURE_XARGS_SUPPORT_ZERO_TERM 392 xlist_t* (*read_args)(xlist_t*, const char*, size_t, char*) = process_stdin;408 char* FAST_FUNC (*read_args)(int, int, char*) = process_stdin; 393 409 #else 394 410 #define read_args process_stdin 395 411 #endif 396 412 397 opt = getopt32(argv, OPTION_STR, &max_args, &max_chars, &eof_str); 413 INIT_G(); 414 415 G.eof_str = NULL; 416 opt = getopt32(argv, OPTION_STR, &max_args, &max_chars, &G.eof_str, &G.eof_str); 417 418 /* -E ""? You may wonder why not just omit -E? 419 * This is used for portability: 420 * old xargs was using "_" as default for -E / -e */ 421 if ((opt & OPT_EOF_STRING1) && G.eof_str[0] == '\0') 422 G.eof_str = NULL; 398 423 399 424 if (opt & OPT_ZEROTERM) 400 USE_FEATURE_XARGS_SUPPORT_ZERO_TERM(read_args = process0_stdin);425 IF_FEATURE_XARGS_SUPPORT_ZERO_TERM(read_args = process0_stdin); 401 426 402 427 argv += optind; 403 428 argc -= optind; 404 if (!arg c) {429 if (!argv[0]) { 405 430 /* default behavior is to echo all the filenames */ 406 * argv = (char*)"echo";431 *--argv = (char*)"echo"; 407 432 argc++; 408 433 } 409 434 410 orig_arg_max = ARG_MAX; 411 if (orig_arg_max == -1) 412 orig_arg_max = LONG_MAX; 413 orig_arg_max -= 2048; /* POSIX.2 requires subtracting 2048 */ 414 435 /* -s NUM default. fileutils-4.4.2 uses 128k, but I heasitate 436 * to use such a big value - first need to change code to use 437 * growable buffer instead of fixed one. 438 */ 439 n_max_chars = 32 * 1024; 440 /* Make smaller if system does not allow our default value. 441 * The Open Group Base Specifications Issue 6: 442 * "The xargs utility shall limit the command line length such that 443 * when the command line is invoked, the combined argument 444 * and environment lists (see the exec family of functions 445 * in the System Interfaces volume of IEEE Std 1003.1-2001) 446 * shall not exceed {ARG_MAX}-2048 bytes". 447 */ 448 { 449 long arg_max = 0; 450 #if defined _SC_ARG_MAX 451 arg_max = sysconf(_SC_ARG_MAX) - 2048; 452 #elif defined ARG_MAX 453 arg_max = ARG_MAX - 2048; 454 #endif 455 if (arg_max > 0 && n_max_chars > arg_max) 456 n_max_chars = arg_max; 457 } 415 458 if (opt & OPT_UPTO_SIZE) { 416 n_max_chars = xatoul_range(max_chars, 1, orig_arg_max); 417 for (i = 0; i < argc; i++) { 418 n_chars += strlen(*argv) + 1; 419 } 420 if (n_max_chars < n_chars) { 421 bb_error_msg_and_die("cannot fit single argument within argument list size limit"); 459 n_max_chars = xatou_range(max_chars, 1, INT_MAX); 460 } 461 /* Account for prepended fixed arguments */ 462 { 463 size_t n_chars = 0; 464 for (i = 0; argv[i]; i++) { 465 n_chars += strlen(argv[i]) + 1; 422 466 } 423 467 n_max_chars -= n_chars; 424 } else { 425 /* Sanity check for systems with huge ARG_MAX defines (e.g., Suns which 426 have it at 1 meg). Things will work fine with a large ARG_MAX but it 427 will probably hurt the system more than it needs to; an array of this 428 size is allocated. */ 429 if (orig_arg_max > 20 * 1024) 430 orig_arg_max = 20 * 1024; 431 n_max_chars = orig_arg_max; 432 } 433 max_chars = xmalloc(n_max_chars); 434 468 } 469 /* Sanity check */ 470 if (n_max_chars <= 0) { 471 bb_error_msg_and_die("can't fit single argument within argument list size limit"); 472 } 473 474 buf = xzalloc(n_max_chars + 1); 475 476 n_max_arg = n_max_chars; 435 477 if (opt & OPT_UPTO_NUMBER) { 436 n_max_arg = xatoul_range(max_args, 1, INT_MAX); 437 } else { 438 n_max_arg = n_max_chars; 439 } 440 441 while ((list = read_args(list, eof_str, n_max_chars, max_chars)) != NULL || 442 !(opt & OPT_NO_EMPTY)) 443 { 478 n_max_arg = xatou_range(max_args, 1, INT_MAX); 479 /* Not necessary, we use growable args[]: */ 480 /* if (n_max_arg > n_max_chars) n_max_arg = n_max_chars */ 481 } 482 483 /* Allocate pointers for execvp */ 484 /* We can statically allocate (argc + n_max_arg + 1) elements 485 * and do not bother with resizing args[], but on 64-bit machines 486 * this results in args[] vector which is ~8 times bigger 487 * than n_max_chars! That is, with n_max_chars == 20k, 488 * args[] will take 160k (!), which will most likely be 489 * almost entirely unused. 490 */ 491 /* See store_param() for matching 256-step growth logic */ 492 G.args = xmalloc(sizeof(G.args[0]) * ((argc + 0xff) & ~0xff)); 493 494 /* Store the command to be executed, part 1 */ 495 for (i = 0; argv[i]; i++) 496 G.args[i] = argv[i]; 497 498 while (1) { 499 char *rem; 500 501 G.idx = argc; 502 rem = read_args(n_max_chars, n_max_arg, buf); 503 store_param(NULL); 504 505 if (!G.args[argc]) { 506 if (*rem != '\0') 507 bb_error_msg_and_die("argument line too long"); 508 if (opt & OPT_NO_EMPTY) 509 break; 510 } 444 511 opt |= OPT_NO_EMPTY; 445 n = 0;446 n_chars = 0;447 #if ENABLE_FEATURE_XARGS_SUPPORT_TERMOPT448 for (cur = list; cur;) {449 n_chars += cur->length;450 n++;451 cur = cur->link;452 if (n_chars > n_max_chars || (n == n_max_arg && cur)) {453 if (opt & OPT_TERMINATE)454 bb_error_msg_and_die("argument list too long");455 break;456 }457 }458 #else459 for (cur = list; cur; cur = cur->link) {460 n_chars += cur->length;461 n++;462 if (n_chars > n_max_chars || n == n_max_arg) {463 break;464 }465 }466 #endif /* FEATURE_XARGS_SUPPORT_TERMOPT */467 468 /* allocate pointers for execvp:469 argc*arg, n*arg from stdin, NULL */470 args = xzalloc((n + argc + 1) * sizeof(char *));471 472 /* store the command to be executed473 (taken from the command line) */474 for (i = 0; i < argc; i++)475 args[i] = argv[i];476 /* (taken from stdin) */477 for (cur = list; n; cur = cur->link) {478 args[i++] = cur->xstr;479 n--;480 }481 512 482 513 if (opt & (OPT_INTERACTIVE | OPT_VERBOSE)) { 514 const char *fmt = " %s" + 1; 515 char **args = G.args; 483 516 for (i = 0; args[i]; i++) { 484 if (i) 485 fputc(' ', stderr); 486 fputs(args[i], stderr); 517 fprintf(stderr, fmt, args[i]); 518 fmt = " %s"; 487 519 } 488 520 if (!(opt & OPT_INTERACTIVE)) 489 fputc('\n', stderr); 490 } 521 bb_putchar_stderr('\n'); 522 } 523 491 524 if (!(opt & OPT_INTERACTIVE) || xargs_ask_confirmation()) { 492 child_error = xargs_exec(args); 493 } 494 495 /* clean up */ 496 for (i = argc; args[i]; i++) { 497 cur = list; 498 list = list->link; 499 free(cur); 500 } 501 free(args); 525 child_error = xargs_exec(); 526 } 527 502 528 if (child_error > 0 && child_error != 123) { 503 529 break; 504 530 } 505 } 506 if (ENABLE_FEATURE_CLEAN_UP) 507 free(max_chars); 531 532 overlapping_strcpy(buf, rem); 533 } /* while */ 534 535 if (ENABLE_FEATURE_CLEAN_UP) { 536 free(G.args); 537 free(buf); 538 } 539 508 540 return child_error; 509 541 } … … 518 550 fprintf(stderr, "Usage: %s [-p] [-r] [-t] -[x] [-n max_arg] [-s max_chars]\n", 519 551 applet_name); 520 exit( 1);552 exit(EXIT_FAILURE); 521 553 } 522 554
Note:
See TracChangeset
for help on using the changeset viewer.