Changeset 1770 in MondoRescue for branches/stable/mindi-busybox/findutils
- Timestamp:
- Nov 6, 2007, 11:01:53 AM (16 years ago)
- Location:
- branches/stable/mindi-busybox/findutils
- Files:
-
- 2 deleted
- 4 edited
- 1 copied
Legend:
- Unmodified
- Added
- Removed
-
branches/stable/mindi-busybox/findutils/Config.in
r821 r1770 6 6 menu "Finding Utilities" 7 7 8 config CONFIG_FIND8 config FIND 9 9 bool "find" 10 10 default n … … 12 12 find is used to search your system to find specified files. 13 13 14 config CONFIG_FEATURE_FIND_PRINT014 config FEATURE_FIND_PRINT0 15 15 bool "Enable -print0 option" 16 16 default y 17 depends on CONFIG_FIND17 depends on FIND 18 18 help 19 19 Causes output names to be separated by a null character … … 22 22 interpreted by other programs. 23 23 24 config CONFIG_FEATURE_FIND_MTIME24 config FEATURE_FIND_MTIME 25 25 bool "Enable modified time matching (-mtime) option" 26 26 default y 27 depends on CONFIG_FIND27 depends on FIND 28 28 help 29 29 Allow searching based on the modification time of 30 30 files, in days. 31 31 32 config CONFIG_FEATURE_FIND_MMIN33 bool "Enable modified time matching (-m in) option"34 default y 35 depends on CONFIG_FIND32 config FEATURE_FIND_MMIN 33 bool "Enable modified time matching (-mmin) option" 34 default y 35 depends on FIND 36 36 help 37 37 Allow searching based on the modification time of 38 38 files, in minutes. 39 39 40 config CONFIG_FEATURE_FIND_PERM40 config FEATURE_FIND_PERM 41 41 bool "Enable permissions matching (-perm) option" 42 42 default y 43 depends on CONFIG_FIND43 depends on FIND 44 44 help 45 45 Enable searching based on file permissions. 46 46 47 config CONFIG_FEATURE_FIND_TYPE47 config FEATURE_FIND_TYPE 48 48 bool "Enable filetype matching (-type) option" 49 49 default y 50 depends on CONFIG_FIND50 depends on FIND 51 51 help 52 52 Enable searching based on file type (file, 53 53 directory, socket, device, etc.). 54 54 55 config CONFIG_FEATURE_FIND_XDEV55 config FEATURE_FIND_XDEV 56 56 bool "Enable stay in filesystem (-xdev) option" 57 57 default y 58 depends on CONFIG_FIND 59 help 60 This option will allow find to restrict searches to a single 61 filesystem. 62 63 config CONFIG_FEATURE_FIND_NEWER 58 depends on FIND 59 help 60 This option allows find to restrict searches to a single filesystem. 61 62 config FEATURE_FIND_MAXDEPTH 63 bool "Enable -maxdepth N option" 64 default y 65 depends on FIND 66 help 67 This option enables -maxdepth N option. 68 69 config FEATURE_FIND_NEWER 64 70 bool "Enable -newer option for comparing file mtimes" 65 71 default y 66 depends on CONFIG_FIND72 depends on FIND 67 73 help 68 74 Support the 'find -newer' option for finding any files which have 69 75 a modified time that is more recent than the specified FILE. 70 76 71 config CONFIG_FEATURE_FIND_INUM77 config FEATURE_FIND_INUM 72 78 bool "Enable inode number matching (-inum) option" 73 79 default y 74 depends on CONFIG_FIND80 depends on FIND 75 81 help 76 82 Support the 'find -inum' option for searching by inode number. 77 83 78 config CONFIG_FEATURE_FIND_EXEC84 config FEATURE_FIND_EXEC 79 85 bool "Enable (-exec) option allowing execution of commands" 80 86 default y 81 depends on CONFIG_FIND87 depends on FIND 82 88 help 83 89 Support the 'find -exec' option for executing commands based upon 84 90 the files matched. 85 91 86 config CONFIG_GREP 92 config FEATURE_FIND_USER 93 bool "Enable username/uid matching (-user) option" 94 default y 95 depends on FIND 96 help 97 Support the 'find -user' option for searching by username or uid. 98 99 config FEATURE_FIND_GROUP 100 bool "Enable group/gid matching (-group) option" 101 default y 102 depends on FIND 103 help 104 Support the 'find -group' option for searching by group name or gid. 105 106 config FEATURE_FIND_NOT 107 bool "Enable the 'not' (!) operator" 108 default y 109 depends on FIND 110 help 111 Support the '!' operator to invert the test results. 112 If 'Enable full-blown desktop' is enabled, then will also support 113 the non-POSIX notation '-not'. 114 115 config FEATURE_FIND_DEPTH 116 bool "Enable the -depth option" 117 default y 118 depends on FIND 119 help 120 Process each directory's contents before the directory itself. 121 122 config FEATURE_FIND_PAREN 123 bool "Enable parens in options" 124 default y 125 depends on FIND 126 help 127 Enable usage of parens '(' to specify logical order of arguments. 128 129 config FEATURE_FIND_SIZE 130 bool "Enable (-size) option allowing matching for file size" 131 default y 132 depends on FIND 133 help 134 Support the 'find -size' option for searching by file size. 135 136 config FEATURE_FIND_PRUNE 137 bool "Enable (-prune) option allowing to exclude subdirectories" 138 default y 139 depends on FIND 140 help 141 If the file is a directory, dont descend into it. Useful for 142 exclusion .svn and CVS directories. 143 144 config FEATURE_FIND_DELETE 145 bool "Enable -delete option allowing to delete files" 146 default n 147 depends on FIND && FEATURE_FIND_DEPTH 148 help 149 Support the 'find -delete' option for deleting files and direcotries. 150 WARNING: This option can do much harm if used wrong. Busybox will not 151 try to protect the user from doing stupid things. Use with care. 152 153 config FEATURE_FIND_PATH 154 bool "Enable -path option allowing to match pathname patterns" 155 default y 156 depends on FIND 157 help 158 The -path option matches whole pathname instead of just filename. 159 160 config FEATURE_FIND_REGEX 161 bool "Enable -regex: match pathname to regex" 162 default y 163 depends on FIND 164 help 165 The -regex option matches whole pathname against regular expression. 166 167 config FEATURE_FIND_CONTEXT 168 bool "Enable (-context) option for matching security context" 169 default n 170 depends on FIND && SELINUX 171 help 172 Support the 'find -context' option for matching security context. 173 174 config GREP 87 175 bool "grep" 88 176 default n … … 90 178 grep is used to search files for a specified pattern. 91 179 92 config CONFIG_FEATURE_GREP_EGREP_ALIAS180 config FEATURE_GREP_EGREP_ALIAS 93 181 bool "Support extended regular expressions (egrep & grep -E)" 94 182 default y 95 depends on CONFIG_GREP183 depends on GREP 96 184 help 97 185 Enabled support for extended regular expressions. Extended … … 99 187 and various repetition operators. 100 188 101 config CONFIG_FEATURE_GREP_FGREP_ALIAS189 config FEATURE_GREP_FGREP_ALIAS 102 190 bool "Alias fgrep to grep -F" 103 191 default y 104 depends on CONFIG_GREP192 depends on GREP 105 193 help 106 194 fgrep sees the search pattern as a normal string rather than … … 108 196 grep -F is always builtin, this just creates the fgrep alias. 109 197 110 config CONFIG_FEATURE_GREP_CONTEXT198 config FEATURE_GREP_CONTEXT 111 199 bool "Enable before and after context flags (-A, -B and -C)" 112 200 default y 113 depends on CONFIG_GREP201 depends on GREP 114 202 help 115 203 Print the specified number of leading (-B) and/or trailing (-A) … … 117 205 Print the specified number of context lines (-C). 118 206 119 config CONFIG_XARGS207 config XARGS 120 208 bool "xargs" 121 209 default n … … 124 212 every item from standard input. 125 213 126 config CONFIG_FEATURE_XARGS_SUPPORT_CONFIRMATION214 config FEATURE_XARGS_SUPPORT_CONFIRMATION 127 215 bool "Enable prompt and confirmation option -p" 128 216 default n 129 depends on CONFIG_XARGS217 depends on XARGS 130 218 help 131 219 Support prompt the user about whether to run each command 132 220 line and read a line from the terminal. 133 221 134 config CONFIG_FEATURE_XARGS_SUPPORT_QUOTES222 config FEATURE_XARGS_SUPPORT_QUOTES 135 223 bool "Enable support single and double quotes and backslash" 136 224 default n 137 depends on CONFIG_XARGS225 depends on XARGS 138 226 help 139 227 Default xargs unsupport single and double quotes 140 228 and backslash for can use aruments with spaces. 141 229 142 config CONFIG_FEATURE_XARGS_SUPPORT_TERMOPT230 config FEATURE_XARGS_SUPPORT_TERMOPT 143 231 bool "Enable support options -x" 144 232 default n 145 depends on CONFIG_XARGS233 depends on XARGS 146 234 help 147 235 Enable support exit if the size (see the -s or -n option) 148 236 is exceeded. 149 237 150 config CONFIG_FEATURE_XARGS_SUPPORT_ZERO_TERM151 bool "Enable options-0"152 default n 153 depends on CONFIG_XARGS238 config FEATURE_XARGS_SUPPORT_ZERO_TERM 239 bool "Enable null terminated option -0" 240 default n 241 depends on XARGS 154 242 help 155 243 Enable input filenames are terminated by a null character -
branches/stable/mindi-busybox/findutils/find.c
r821 r1770 8 8 * Matt Kraai <kraai@alumni.carnegiemellon.edu>. 9 9 * 10 * Licensed under the GPL v 2 or later, see the file LICENSE in this tarball.10 * Licensed under the GPL version 2, see the file LICENSE in this tarball. 11 11 */ 12 12 13 #include "busybox.h" 14 #include <stdio.h> 15 #include <unistd.h> 16 #include <dirent.h> 17 #include <string.h> 18 #include <stdlib.h> 13 /* findutils-4.1.20: 14 * 15 * # find file.txt -exec 'echo {}' '{} {}' ';' 16 * find: echo file.txt: No such file or directory 17 * # find file.txt -exec 'echo' '{} {}' '; ' 18 * find: missing argument to `-exec' 19 * # find file.txt -exec 'echo {}' '{} {}' ';' junk 20 * find: paths must precede expression 21 * # find file.txt -exec 'echo {}' '{} {}' ';' junk ';' 22 * find: paths must precede expression 23 * # find file.txt -exec 'echo' '{} {}' ';' 24 * file.txt file.txt 25 * (strace: execve("/bin/echo", ["echo", "file.txt file.txt"], [ 30 vars ])) 26 * # find file.txt -exec 'echo' '{} {}' ';' -print -exec pwd ';' 27 * file.txt file.txt 28 * file.txt 29 * /tmp 30 * # find -name '*.c' -o -name '*.h' 31 * [shows files, *.c and *.h intermixed] 32 * # find file.txt -name '*f*' -o -name '*t*' 33 * file.txt 34 * # find file.txt -name '*z*' -o -name '*t*' 35 * file.txt 36 * # find file.txt -name '*f*' -o -name '*z*' 37 * file.txt 38 * 39 * # find t z -name '*t*' -print -o -name '*z*' 40 * t 41 * # find t z t z -name '*t*' -o -name '*z*' -print 42 * z 43 * z 44 * # find t z t z '(' -name '*t*' -o -name '*z*' ')' -o -print 45 * (no output) 46 */ 47 48 /* Testing script 49 * ./busybox find "$@" | tee /tmp/bb_find 50 * echo ================== 51 * /path/to/gnu/find "$@" | tee /tmp/std_find 52 * echo ================== 53 * diff -u /tmp/std_find /tmp/bb_find && echo Identical 54 */ 55 19 56 #include <fnmatch.h> 20 #include <time.h> 21 #include <ctype.h> 22 23 static char *pattern; 24 #ifdef CONFIG_FEATURE_FIND_PRINT0 25 static char printsep = '\n'; 26 #endif 27 28 #ifdef CONFIG_FEATURE_FIND_TYPE 29 static int type_mask = 0; 30 #endif 31 32 #ifdef CONFIG_FEATURE_FIND_PERM 33 static char perm_char = 0; 34 static int perm_mask = 0; 35 #endif 36 37 #ifdef CONFIG_FEATURE_FIND_MTIME 38 static char mtime_char; 39 static int mtime_days; 40 #endif 41 42 #ifdef CONFIG_FEATURE_FIND_MMIN 43 static char mmin_char; 44 static int mmin_mins; 45 #endif 46 47 #ifdef CONFIG_FEATURE_FIND_XDEV 48 static dev_t *xdev_dev; 49 static int xdev_count = 0; 50 #endif 51 52 #ifdef CONFIG_FEATURE_FIND_NEWER 53 static time_t newer_mtime; 54 #endif 55 56 #ifdef CONFIG_FEATURE_FIND_INUM 57 static ino_t inode_num; 58 #endif 59 60 #ifdef CONFIG_FEATURE_FIND_EXEC 61 static char **exec_str; 62 static int num_matches; 63 static int exec_opt; 64 #endif 65 66 static int fileAction(const char *fileName, struct stat *statbuf, void* junk) 67 { 68 #ifdef CONFIG_FEATURE_FIND_XDEV 57 #include "libbb.h" 58 #if ENABLE_FEATURE_FIND_REGEX 59 #include "xregex.h" 60 #endif 61 62 /* This is a NOEXEC applet. Be very careful! */ 63 64 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 *); 69 70 typedef struct { 71 action_fp f; 72 #if ENABLE_FEATURE_FIND_NOT 73 bool invert; 74 #endif 75 } 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; 101 102 #if ENABLE_FEATURE_FIND_EXEC 103 static unsigned count_subst(const char *str) 104 { 105 unsigned count = 0; 106 while ((str = strstr(str, "{}")) != NULL) { 107 count++; 108 str++; 109 } 110 return count; 111 } 112 113 114 static char* subst(const char *src, unsigned count, const char* filename) 115 { 116 char *buf, *dst, *end; 117 size_t flen = strlen(filename); 118 /* we replace each '{}' with filename: growth by strlen-2 */ 119 buf = dst = xmalloc(strlen(src) + count*(flen-2) + 1); 120 while ((end = strstr(src, "{}"))) { 121 memcpy(dst, src, end - src); 122 dst += end - src; 123 src = end + 2; 124 memcpy(dst, filename, flen); 125 dst += flen; 126 } 127 strcpy(dst, src); 128 return buf; 129 } 130 #endif 131 132 /* Return values of ACTFs ('action functions') are a bit mask: 133 * bit 1=1: prune (use SKIP constant for setting it) 134 * bit 0=1: matched successfully (TRUE) 135 */ 136 137 static int exec_actions(action ***appp, const char *fileName, struct stat *statbuf) 138 { 139 int cur_group; 140 int cur_action; 141 int rc = 0; 142 action **app, *ap; 143 144 /* "action group" is a set of actions ANDed together. 145 * groups are ORed together. 146 * We simply evaluate each group until we find one in which all actions 147 * succeed. */ 148 149 /* -prune is special: if it is encountered, then we won't 150 * descend into current directory. It doesn't matter whether 151 * action group (in which -prune sits) will succeed or not: 152 * find * -prune -name 'f*' -o -name 'm*' -- prunes every dir 153 * find * -name 'f*' -o -prune -name 'm*' -- prunes all dirs 154 * not starting with 'f' */ 155 156 /* We invert TRUE bit (bit 0). Now 1 there means 'failure'. 157 * and bitwise OR in "rc |= TRUE ^ ap->f()" will: 158 * (1) make SKIP (-prune) bit stick; and (2) detect 'failure'. 159 * On return, bit is restored. */ 160 161 cur_group = -1; 162 while ((app = appp[++cur_group])) { 163 rc &= ~TRUE; /* 'success' so far, clear TRUE bit */ 164 cur_action = -1; 165 while (1) { 166 ap = app[++cur_action]; 167 if (!ap) /* all actions in group were successful */ 168 return rc ^ TRUE; /* restore TRUE bit */ 169 rc |= TRUE ^ ap->f(fileName, statbuf, ap); 170 #if ENABLE_FEATURE_FIND_NOT 171 if (ap->invert) rc ^= TRUE; 172 #endif 173 if (rc & TRUE) /* current group failed, try next */ 174 break; 175 } 176 } 177 return rc ^ TRUE; /* restore TRUE bit */ 178 } 179 180 181 ACTF(name) 182 { 183 const char *tmp = bb_basename(fileName); 184 if (tmp != fileName && !*tmp) { /* "foo/bar/". Oh no... go back to 'b' */ 185 tmp--; 186 while (tmp != fileName && *--tmp != '/') 187 continue; 188 if (*tmp == '/') 189 tmp++; 190 } 191 return fnmatch(ap->pattern, tmp, FNM_PERIOD) == 0; 192 } 193 #if ENABLE_FEATURE_FIND_PATH 194 ACTF(path) 195 { 196 return fnmatch(ap->pattern, fileName, 0) == 0; 197 } 198 #endif 199 #if ENABLE_FEATURE_FIND_REGEX 200 ACTF(regex) 201 { 202 regmatch_t match; 203 if (regexec(&ap->compiled_pattern, fileName, 1, &match, 0 /*eflags*/)) 204 return 0; /* no match */ 205 if (match.rm_so) 206 return 0; /* match doesn't start at pos 0 */ 207 if (fileName[match.rm_eo]) 208 return 0; /* match doesn't end exactly at end of pathname */ 209 return 1; 210 } 211 #endif 212 #if ENABLE_FEATURE_FIND_TYPE 213 ACTF(type) 214 { 215 return ((statbuf->st_mode & S_IFMT) == ap->type_mask); 216 } 217 #endif 218 #if ENABLE_FEATURE_FIND_PERM 219 ACTF(perm) 220 { 221 /* -perm +mode: at least one of perm_mask bits are set */ 222 if (ap->perm_char == '+') 223 return (statbuf->st_mode & ap->perm_mask) != 0; 224 /* -perm -mode: all of perm_mask are set */ 225 if (ap->perm_char == '-') 226 return (statbuf->st_mode & ap->perm_mask) == ap->perm_mask; 227 /* -perm mode: file mode must match perm_mask */ 228 return (statbuf->st_mode & 07777) == ap->perm_mask; 229 } 230 #endif 231 #if ENABLE_FEATURE_FIND_MTIME 232 ACTF(mtime) 233 { 234 time_t file_age = time(NULL) - statbuf->st_mtime; 235 time_t mtime_secs = ap->mtime_days * 24*60*60; 236 if (ap->mtime_char == '+') 237 return file_age >= mtime_secs + 24*60*60; 238 if (ap->mtime_char == '-') 239 return file_age < mtime_secs; 240 /* just numeric mtime */ 241 return file_age >= mtime_secs && file_age < (mtime_secs + 24*60*60); 242 } 243 #endif 244 #if ENABLE_FEATURE_FIND_MMIN 245 ACTF(mmin) 246 { 247 time_t file_age = time(NULL) - statbuf->st_mtime; 248 time_t mmin_secs = ap->mmin_mins * 60; 249 if (ap->mmin_char == '+') 250 return file_age >= mmin_secs + 60; 251 if (ap->mmin_char == '-') 252 return file_age < mmin_secs; 253 /* just numeric mmin */ 254 return file_age >= mmin_secs && file_age < (mmin_secs + 60); 255 } 256 #endif 257 #if ENABLE_FEATURE_FIND_NEWER 258 ACTF(newer) 259 { 260 return (ap->newer_mtime < statbuf->st_mtime); 261 } 262 #endif 263 #if ENABLE_FEATURE_FIND_INUM 264 ACTF(inum) 265 { 266 return (statbuf->st_ino == ap->inode_num); 267 } 268 #endif 269 #if ENABLE_FEATURE_FIND_EXEC 270 ACTF(exec) 271 { 272 int i, rc; 273 char *argv[ap->exec_argc + 1]; 274 for (i = 0; i < ap->exec_argc; i++) 275 argv[i] = subst(ap->exec_argv[i], ap->subst_count[i], fileName); 276 argv[i] = NULL; /* terminate the list */ 277 278 rc = spawn_and_wait(argv); 279 if (rc < 0) 280 bb_perror_msg("%s", argv[0]); 281 282 i = 0; 283 while (argv[i]) 284 free(argv[i++]); 285 return rc == 0; /* return 1 if exitcode 0 */ 286 } 287 #endif 288 #if ENABLE_FEATURE_FIND_USER 289 ACTF(user) 290 { 291 return (statbuf->st_uid == ap->uid); 292 } 293 #endif 294 #if ENABLE_FEATURE_FIND_GROUP 295 ACTF(group) 296 { 297 return (statbuf->st_gid == ap->gid); 298 } 299 #endif 300 #if ENABLE_FEATURE_FIND_PRINT0 301 ACTF(print0) 302 { 303 printf("%s%c", fileName, '\0'); 304 return TRUE; 305 } 306 #endif 307 ACTF(print) 308 { 309 puts(fileName); 310 return TRUE; 311 } 312 #if ENABLE_FEATURE_FIND_PAREN 313 ACTF(paren) 314 { 315 return exec_actions(ap->subexpr, fileName, statbuf); 316 } 317 #endif 318 #if ENABLE_FEATURE_FIND_SIZE 319 ACTF(size) 320 { 321 if (ap->size_char == '+') 322 return statbuf->st_size > ap->size; 323 if (ap->size_char == '-') 324 return statbuf->st_size < ap->size; 325 return statbuf->st_size == ap->size; 326 } 327 #endif 328 #if ENABLE_FEATURE_FIND_PRUNE 329 /* 330 * -prune: if -depth is not given, return true and do not descend 331 * current dir; if -depth is given, return false with no effect. 332 * Example: 333 * find dir -name 'asm-*' -prune -o -name '*.[chS]' -print 334 */ 335 ACTF(prune) 336 { 337 return SKIP + TRUE; 338 } 339 #endif 340 #if ENABLE_FEATURE_FIND_DELETE 341 ACTF(delete) 342 { 343 int rc; 344 if (S_ISDIR(statbuf->st_mode)) { 345 rc = rmdir(fileName); 346 } else { 347 rc = unlink(fileName); 348 } 349 if (rc < 0) 350 bb_perror_msg("%s", fileName); 351 return TRUE; 352 } 353 #endif 354 #if ENABLE_FEATURE_FIND_CONTEXT 355 ACTF(context) 356 { 357 security_context_t con; 358 int rc; 359 360 if (recurse_flags & ACTION_FOLLOWLINKS) { 361 rc = getfilecon(fileName, &con); 362 } else { 363 rc = lgetfilecon(fileName, &con); 364 } 365 if (rc < 0) 366 return FALSE; 367 rc = strcmp(ap->context, con); 368 freecon(con); 369 return rc == 0; 370 } 371 #endif 372 373 374 static int fileAction(const char *fileName, struct stat *statbuf, void *userData, int depth) 375 { 376 int i; 377 #if ENABLE_FEATURE_FIND_MAXDEPTH 378 int maxdepth = (int)(ptrdiff_t)userData; 379 380 if (depth > maxdepth) return SKIP; 381 #endif 382 383 #if ENABLE_FEATURE_FIND_XDEV 69 384 if (S_ISDIR(statbuf->st_mode) && xdev_count) { 70 int i; 71 for (i=0; i<xdev_count; i++) { 72 if (xdev_dev[i] != statbuf->st_dev) 73 return SKIP; 74 } 75 } 76 #endif 77 if (pattern != NULL) { 78 const char *tmp = strrchr(fileName, '/'); 79 80 if (tmp == NULL) 81 tmp = fileName; 82 else 83 tmp++; 84 if (!(fnmatch(pattern, tmp, FNM_PERIOD) == 0)) 85 goto no_match; 86 } 87 #ifdef CONFIG_FEATURE_FIND_TYPE 88 if (type_mask != 0) { 89 if (!((statbuf->st_mode & S_IFMT) == type_mask)) 90 goto no_match; 91 } 92 #endif 93 #ifdef CONFIG_FEATURE_FIND_PERM 94 if (perm_mask != 0) { 95 if (!((isdigit(perm_char) && (statbuf->st_mode & 07777) == perm_mask) || 96 (perm_char == '-' && (statbuf->st_mode & perm_mask) == perm_mask) || 97 (perm_char == '+' && (statbuf->st_mode & perm_mask) != 0))) 98 goto no_match; 99 } 100 #endif 101 #ifdef CONFIG_FEATURE_FIND_MTIME 102 if (mtime_char != 0) { 103 time_t file_age = time(NULL) - statbuf->st_mtime; 104 time_t mtime_secs = mtime_days * 24 * 60 * 60; 105 if (!((isdigit(mtime_char) && file_age >= mtime_secs && 106 file_age < mtime_secs + 24 * 60 * 60) || 107 (mtime_char == '+' && file_age >= mtime_secs + 24 * 60 * 60) || 108 (mtime_char == '-' && file_age < mtime_secs))) 109 goto no_match; 110 } 111 #endif 112 #ifdef CONFIG_FEATURE_FIND_MMIN 113 if (mmin_char != 0) { 114 time_t file_age = time(NULL) - statbuf->st_mtime; 115 time_t mmin_secs = mmin_mins * 60; 116 if (!((isdigit(mmin_char) && file_age >= mmin_secs && 117 file_age < mmin_secs + 60) || 118 (mmin_char == '+' && file_age >= mmin_secs + 60) || 119 (mmin_char == '-' && file_age < mmin_secs))) 120 goto no_match; 121 } 122 #endif 123 #ifdef CONFIG_FEATURE_FIND_NEWER 124 if (newer_mtime != 0) { 125 time_t file_age = newer_mtime - statbuf->st_mtime; 126 if (file_age >= 0) 127 goto no_match; 128 } 129 #endif 130 #ifdef CONFIG_FEATURE_FIND_INUM 131 if (inode_num != 0) { 132 if (!(statbuf->st_ino == inode_num)) 133 goto no_match; 134 } 135 #endif 136 #ifdef CONFIG_FEATURE_FIND_EXEC 137 if (exec_opt) { 138 int i; 139 char *cmd_string = ""; 140 for (i = 0; i < num_matches; i++) 141 cmd_string = bb_xasprintf("%s%s%s", cmd_string, exec_str[i], fileName); 142 cmd_string = bb_xasprintf("%s%s", cmd_string, exec_str[num_matches]); 143 system(cmd_string); 144 goto no_match; 145 } 146 #endif 147 148 #ifdef CONFIG_FEATURE_FIND_PRINT0 149 printf("%s%c", fileName, printsep); 385 for (i = 0; i < xdev_count; i++) { 386 if (xdev_dev[i] == statbuf->st_dev) 387 break; 388 } 389 if (i == xdev_count) 390 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); 397 /* Cannot return 0: our caller, recursive_action(), 398 * will perror() and skip dirs (if called on dir) */ 399 return (i & SKIP) ? SKIP : TRUE; 400 } 401 402 403 #if ENABLE_FEATURE_FIND_TYPE 404 static int find_type(const char *type) 405 { 406 int mask = 0; 407 408 if (*type == 'b') 409 mask = S_IFBLK; 410 else if (*type == 'c') 411 mask = S_IFCHR; 412 else if (*type == 'd') 413 mask = S_IFDIR; 414 else if (*type == 'p') 415 mask = S_IFIFO; 416 else if (*type == 'f') 417 mask = S_IFREG; 418 else if (*type == 'l') 419 mask = S_IFLNK; 420 else if (*type == 's') 421 mask = S_IFSOCK; 422 423 if (mask == 0 || *(type + 1) != '\0') 424 bb_error_msg_and_die(bb_msg_invalid_arg, type, "-type"); 425 426 return mask; 427 } 428 #endif 429 430 #if ENABLE_FEATURE_FIND_PERM \ 431 || ENABLE_FEATURE_FIND_MTIME || ENABLE_FEATURE_FIND_MMIN \ 432 || ENABLE_FEATURE_FIND_SIZE 433 static const char* plus_minus_num(const char* str) 434 { 435 if (*str == '-' || *str == '+') 436 str++; 437 return str; 438 } 439 #endif 440 441 static action*** parse_params(char **argv) 442 { 443 enum { 444 PARM_a , 445 PARM_o , 446 USE_FEATURE_FIND_NOT( PARM_char_not ,) 447 #if ENABLE_DESKTOP 448 PARM_and , 449 PARM_or , 450 USE_FEATURE_FIND_NOT( PARM_not ,) 451 #endif 452 PARM_print , 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,) 459 /* 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 ,) 473 }; 474 475 static const char params[] ALIGN1 = 476 "-a\0" 477 "-o\0" 478 USE_FEATURE_FIND_NOT( "!\0" ) 479 #if ENABLE_DESKTOP 480 "-and\0" 481 "-or\0" 482 USE_FEATURE_FIND_NOT( "-not\0" ) 483 #endif 484 "-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" ) 491 /* All options starting from here require argument */ 492 "-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") 505 ; 506 507 action*** appp; 508 unsigned cur_group = 0; 509 unsigned cur_action = 0; 510 USE_FEATURE_FIND_NOT( bool invert_flag = 0; ) 511 512 /* 'static' doesn't work here! (gcc 4.1.2) */ 513 action* alloc_action(int sizeof_struct, action_fp f) 514 { 515 action *ap; 516 appp[cur_group] = xrealloc(appp[cur_group], (cur_action+2) * sizeof(*appp)); 517 appp[cur_group][cur_action++] = ap = xmalloc(sizeof_struct); 518 appp[cur_group][cur_action] = NULL; 519 ap->f = f; 520 USE_FEATURE_FIND_NOT( ap->invert = invert_flag; ) 521 USE_FEATURE_FIND_NOT( invert_flag = 0; ) 522 return ap; 523 } 524 525 #define ALLOC_ACTION(name) (action_##name*)alloc_action(sizeof(action_##name), (action_fp) func_##name) 526 527 appp = xzalloc(2 * sizeof(appp[0])); /* appp[0],[1] == NULL */ 528 529 /* Actions have side effects and return a true or false value 530 * We implement: -print, -print0, -exec 531 * 532 * The rest are tests. 533 * 534 * Tests and actions are grouped by operators 535 * ( expr ) Force precedence 536 * ! expr True if expr is false 537 * -not expr Same as ! expr 538 * expr1 [-a[nd]] expr2 And; expr2 is not evaluated if expr1 is false 539 * expr1 -o[r] expr2 Or; expr2 is not evaluated if expr1 is true 540 * expr1 , expr2 List; both expr1 and expr2 are always evaluated 541 * We implement: (), -a, -o 542 */ 543 while (*argv) { 544 const char *arg = argv[0]; 545 int parm = index_in_strings(params, arg); 546 const char *arg1 = argv[1]; 547 548 if (parm >= PARM_name) { 549 /* All options starting from -name require argument */ 550 if (!arg1) 551 bb_error_msg_and_die(bb_msg_requires_arg, arg); 552 argv++; 553 } 554 555 /* We can use big switch() here, but on i386 556 * it doesn't give smaller code. Other arches? */ 557 558 /* --- Operators --- */ 559 if (parm == PARM_a USE_DESKTOP(|| parm == PARM_and)) { 560 /* no further special handling required */ 561 } 562 else if (parm == PARM_o USE_DESKTOP(|| parm == PARM_or)) { 563 /* start new OR group */ 564 cur_group++; 565 appp = xrealloc(appp, (cur_group+2) * sizeof(*appp)); 566 /*appp[cur_group] = NULL; - already NULL */ 567 appp[cur_group+1] = NULL; 568 cur_action = 0; 569 } 570 #if ENABLE_FEATURE_FIND_NOT 571 else if (parm == PARM_char_not USE_DESKTOP(|| parm == PARM_not)) { 572 /* also handles "find ! ! -name 'foo*'" */ 573 invert_flag ^= 1; 574 } 575 #endif 576 577 /* --- Tests and actions --- */ 578 else if (parm == PARM_print) { 579 need_print = 0; 580 /* GNU find ignores '!' here: "find ! -print" */ 581 USE_FEATURE_FIND_NOT( invert_flag = 0; ) 582 (void) ALLOC_ACTION(print); 583 } 584 #if ENABLE_FEATURE_FIND_PRINT0 585 else if (parm == PARM_print0) { 586 need_print = 0; 587 USE_FEATURE_FIND_NOT( invert_flag = 0; ) 588 (void) ALLOC_ACTION(print0); 589 } 590 #endif 591 #if ENABLE_FEATURE_FIND_DEPTH 592 else if (parm == PARM_depth) { 593 recurse_flags |= ACTION_DEPTHFIRST; 594 } 595 #endif 596 #if ENABLE_FEATURE_FIND_PRUNE 597 else if (parm == PARM_prune) { 598 USE_FEATURE_FIND_NOT( invert_flag = 0; ) 599 (void) ALLOC_ACTION(prune); 600 } 601 #endif 602 #if ENABLE_FEATURE_FIND_DELETE 603 else if (parm == PARM_delete) { 604 need_print = 0; 605 recurse_flags |= ACTION_DEPTHFIRST; 606 (void) ALLOC_ACTION(delete); 607 } 608 #endif 609 #if ENABLE_FEATURE_FIND_EXEC 610 else if (parm == PARM_exec) { 611 int i; 612 action_exec *ap; 613 need_print = 0; 614 USE_FEATURE_FIND_NOT( invert_flag = 0; ) 615 ap = ALLOC_ACTION(exec); 616 ap->exec_argv = ++argv; /* first arg after -exec */ 617 ap->exec_argc = 0; 618 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], ';')) 622 break; 623 argv++; 624 ap->exec_argc++; 625 } 626 if (ap->exec_argc == 0) 627 bb_error_msg_and_die(bb_msg_requires_arg, arg); 628 ap->subst_count = xmalloc(ap->exec_argc * sizeof(int)); 629 i = ap->exec_argc; 630 while (i--) 631 ap->subst_count[i] = count_subst(ap->exec_argv[i]); 632 } 633 #endif 634 #if ENABLE_FEATURE_FIND_PAREN 635 else if (parm == PARM_char_brace) { 636 action_paren *ap; 637 char **endarg; 638 unsigned nested = 1; 639 640 endarg = argv; 641 while (1) { 642 if (!*++endarg) 643 bb_error_msg_and_die("unpaired '('"); 644 if (LONE_CHAR(*endarg, '(')) 645 nested++; 646 else if (LONE_CHAR(*endarg, ')') && !--nested) { 647 *endarg = NULL; 648 break; 649 } 650 } 651 ap = ALLOC_ACTION(paren); 652 ap->subexpr = parse_params(argv + 1); 653 *endarg = (char*) ")"; /* restore NULLed parameter */ 654 argv = endarg; 655 } 656 #endif 657 else if (parm == PARM_name) { 658 action_name *ap; 659 ap = ALLOC_ACTION(name); 660 ap->pattern = arg1; 661 } 662 #if ENABLE_FEATURE_FIND_PATH 663 else if (parm == PARM_path) { 664 action_path *ap; 665 ap = ALLOC_ACTION(path); 666 ap->pattern = arg1; 667 } 668 #endif 669 #if ENABLE_FEATURE_FIND_REGEX 670 else if (parm == PARM_regex) { 671 action_regex *ap; 672 ap = ALLOC_ACTION(regex); 673 xregcomp(&ap->compiled_pattern, arg1, 0 /*cflags*/); 674 } 675 #endif 676 #if ENABLE_FEATURE_FIND_TYPE 677 else if (parm == PARM_type) { 678 action_type *ap; 679 ap = ALLOC_ACTION(type); 680 ap->type_mask = find_type(arg1); 681 } 682 #endif 683 #if ENABLE_FEATURE_FIND_PERM 684 /* -perm mode File's permission bits are exactly mode (octal or symbolic). 685 * Symbolic modes use mode 0 as a point of departure. 686 * -perm -mode All of the permission bits mode are set for the file. 687 * -perm +mode Any of the permission bits mode are set for the file. 688 */ 689 else if (parm == PARM_perm) { 690 action_perm *ap; 691 ap = ALLOC_ACTION(perm); 692 ap->perm_char = arg1[0]; 693 arg1 = plus_minus_num(arg1); 694 ap->perm_mask = 0; 695 if (!bb_parse_mode(arg1, &ap->perm_mask)) 696 bb_error_msg_and_die("invalid mode: %s", arg1); 697 } 698 #endif 699 #if ENABLE_FEATURE_FIND_MTIME 700 else if (parm == PARM_mtime) { 701 action_mtime *ap; 702 ap = ALLOC_ACTION(mtime); 703 ap->mtime_char = arg1[0]; 704 ap->mtime_days = xatoul(plus_minus_num(arg1)); 705 } 706 #endif 707 #if ENABLE_FEATURE_FIND_MMIN 708 else if (parm == PARM_mmin) { 709 action_mmin *ap; 710 ap = ALLOC_ACTION(mmin); 711 ap->mmin_char = arg1[0]; 712 ap->mmin_mins = xatoul(plus_minus_num(arg1)); 713 } 714 #endif 715 #if ENABLE_FEATURE_FIND_NEWER 716 else if (parm == PARM_newer) { 717 struct stat stat_newer; 718 action_newer *ap; 719 ap = ALLOC_ACTION(newer); 720 xstat(arg1, &stat_newer); 721 ap->newer_mtime = stat_newer.st_mtime; 722 } 723 #endif 724 #if ENABLE_FEATURE_FIND_INUM 725 else if (parm == PARM_inum) { 726 action_inum *ap; 727 ap = ALLOC_ACTION(inum); 728 ap->inode_num = xatoul(arg1); 729 } 730 #endif 731 #if ENABLE_FEATURE_FIND_USER 732 else if (parm == PARM_user) { 733 action_user *ap; 734 ap = ALLOC_ACTION(user); 735 ap->uid = bb_strtou(arg1, NULL, 10); 736 if (errno) 737 ap->uid = xuname2uid(arg1); 738 } 739 #endif 740 #if ENABLE_FEATURE_FIND_GROUP 741 else if (parm == PARM_group) { 742 action_group *ap; 743 ap = ALLOC_ACTION(group); 744 ap->gid = bb_strtou(arg1, NULL, 10); 745 if (errno) 746 ap->gid = xgroup2gid(arg1); 747 } 748 #endif 749 #if ENABLE_FEATURE_FIND_SIZE 750 else if (parm == PARM_size) { 751 /* -size n[bckw]: file uses n units of space 752 * b (default): units are 512-byte blocks 753 * c: 1 byte 754 * k: kilobytes 755 * w: 2-byte words 756 */ 757 #if ENABLE_LFS 758 #define XATOU_SFX xatoull_sfx 150 759 #else 151 puts(fileName); 152 #endif 153 no_match: 154 return (TRUE); 155 } 156 157 #ifdef CONFIG_FEATURE_FIND_TYPE 158 static int find_type(char *type) 159 { 160 int mask = 0; 161 162 switch (type[0]) { 163 case 'b': 164 mask = S_IFBLK; 165 break; 166 case 'c': 167 mask = S_IFCHR; 168 break; 169 case 'd': 170 mask = S_IFDIR; 171 break; 172 case 'p': 173 mask = S_IFIFO; 174 break; 175 case 'f': 176 mask = S_IFREG; 177 break; 178 case 'l': 179 mask = S_IFLNK; 180 break; 181 case 's': 182 mask = S_IFSOCK; 183 break; 184 } 185 186 if (mask == 0 || type[1] != '\0') 187 bb_error_msg_and_die(bb_msg_invalid_arg, type, "-type"); 188 189 return mask; 190 } 191 #endif 192 760 #define XATOU_SFX xatoul_sfx 761 #endif 762 static const struct suffix_mult find_suffixes[] = { 763 { "c", 1 }, 764 { "w", 2 }, 765 { "", 512 }, 766 { "b", 512 }, 767 { "k", 1024 }, 768 { } 769 }; 770 action_size *ap; 771 ap = ALLOC_ACTION(size); 772 ap->size_char = arg1[0]; 773 ap->size = XATOU_SFX(plus_minus_num(arg1), find_suffixes); 774 } 775 #endif 776 #if ENABLE_FEATURE_FIND_CONTEXT 777 else if (parm == PARM_context) { 778 action_context *ap; 779 ap = ALLOC_ACTION(context); 780 ap->context = NULL; 781 /* SELinux headers erroneously declare non-const parameter */ 782 if (selinux_raw_to_trans_context((char*)arg1, &ap->context)) 783 bb_perror_msg("%s", arg1); 784 } 785 #endif 786 else { 787 bb_error_msg("unrecognized: %s", arg); 788 bb_show_usage(); 789 } 790 argv++; 791 } 792 return appp; 793 #undef ALLOC_ACTION 794 } 795 796 797 int find_main(int argc, char **argv); 193 798 int find_main(int argc, char **argv) 194 799 { 195 int dereference = FALSE; 800 static const char options[] ALIGN1 = 801 "-follow\0" 802 USE_FEATURE_FIND_XDEV( "-xdev\0" ) 803 USE_FEATURE_FIND_MAXDEPTH("-maxdepth\0") 804 ; 805 enum { 806 OPT_FOLLOW, 807 USE_FEATURE_FIND_XDEV( OPT_XDEV ,) 808 USE_FEATURE_FIND_MAXDEPTH(OPT_MAXDEPTH,) 809 }; 810 811 char *arg; 812 char **argp; 196 813 int i, firstopt, status = EXIT_SUCCESS; 814 #if ENABLE_FEATURE_FIND_MAXDEPTH 815 int maxdepth = INT_MAX; 816 #endif 197 817 198 818 for (firstopt = 1; firstopt < argc; firstopt++) { 199 819 if (argv[firstopt][0] == '-') 200 820 break; 201 } 202 203 /* Parse any options */ 204 for (i = firstopt; i < argc; i++) { 205 if (strcmp(argv[i], "-follow") == 0) 206 dereference = TRUE; 207 else if (strcmp(argv[i], "-print") == 0) { 208 ; 209 } 210 #ifdef CONFIG_FEATURE_FIND_PRINT0 211 else if (strcmp(argv[i], "-print0") == 0) 212 printsep = '\0'; 213 #endif 214 else if (strcmp(argv[i], "-name") == 0) { 215 if (++i == argc) 216 bb_error_msg_and_die(bb_msg_requires_arg, "-name"); 217 pattern = argv[i]; 218 #ifdef CONFIG_FEATURE_FIND_TYPE 219 } else if (strcmp(argv[i], "-type") == 0) { 220 if (++i == argc) 221 bb_error_msg_and_die(bb_msg_requires_arg, "-type"); 222 type_mask = find_type(argv[i]); 223 #endif 224 #ifdef CONFIG_FEATURE_FIND_PERM 225 } else if (strcmp(argv[i], "-perm") == 0) { 226 char *end; 227 if (++i == argc) 228 bb_error_msg_and_die(bb_msg_requires_arg, "-perm"); 229 perm_mask = strtol(argv[i], &end, 8); 230 if ((end[0] != '\0') || (perm_mask > 07777)) 231 bb_error_msg_and_die(bb_msg_invalid_arg, argv[i], "-perm"); 232 if ((perm_char = argv[i][0]) == '-') 233 perm_mask = -perm_mask; 234 #endif 235 #ifdef CONFIG_FEATURE_FIND_MTIME 236 } else if (strcmp(argv[i], "-mtime") == 0) { 237 char *end; 238 if (++i == argc) 239 bb_error_msg_and_die(bb_msg_requires_arg, "-mtime"); 240 mtime_days = strtol(argv[i], &end, 10); 241 if (end[0] != '\0') 242 bb_error_msg_and_die(bb_msg_invalid_arg, argv[i], "-mtime"); 243 if ((mtime_char = argv[i][0]) == '-') 244 mtime_days = -mtime_days; 245 #endif 246 #ifdef CONFIG_FEATURE_FIND_MMIN 247 } else if (strcmp(argv[i], "-mmin") == 0) { 248 char *end; 249 if (++i == argc) 250 bb_error_msg_and_die(bb_msg_requires_arg, "-mmin"); 251 mmin_mins = strtol(argv[i], &end, 10); 252 if (end[0] != '\0') 253 bb_error_msg_and_die(bb_msg_invalid_arg, argv[i], "-mmin"); 254 if ((mmin_char = argv[i][0]) == '-') 255 mmin_mins = -mmin_mins; 256 #endif 257 #ifdef CONFIG_FEATURE_FIND_XDEV 258 } else if (strcmp(argv[i], "-xdev") == 0) { 821 if (ENABLE_FEATURE_FIND_NOT && LONE_CHAR(argv[firstopt], '!')) 822 break; 823 #if ENABLE_FEATURE_FIND_PAREN 824 if (LONE_CHAR(argv[firstopt], '(')) 825 break; 826 #endif 827 } 828 if (firstopt == 1) { 829 argv[0] = (char*)"."; 830 argv--; 831 firstopt++; 832 } 833 834 /* All options always return true. They always take effect 835 * rather than being processed only when their place in the 836 * expression is reached. 837 * We implement: -follow, -xdev, -maxdepth 838 */ 839 /* Process options, and replace then with -a */ 840 /* (-a will be ignored by recursive parser later) */ 841 argp = &argv[firstopt]; 842 while ((arg = argp[0])) { 843 int opt = index_in_strings(options, arg); 844 if (opt == OPT_FOLLOW) { 845 recurse_flags |= ACTION_FOLLOWLINKS; 846 argp[0] = (char*)"-a"; 847 } 848 #if ENABLE_FEATURE_FIND_XDEV 849 if (opt == OPT_XDEV) { 259 850 struct stat stbuf; 260 261 xdev_count = ( firstopt - 1 ) ? ( firstopt - 1 ) : 1; 262 xdev_dev = xmalloc ( xdev_count * sizeof( dev_t )); 263 264 if ( firstopt == 1 ) { 265 xstat ( ".", &stbuf ); 266 xdev_dev [0] = stbuf. st_dev; 267 } 268 else { 269 851 if (!xdev_count) { 852 xdev_count = firstopt - 1; 853 xdev_dev = xmalloc(xdev_count * sizeof(dev_t)); 270 854 for (i = 1; i < firstopt; i++) { 271 xstat ( argv [i], &stbuf ); 272 xdev_dev [i-1] = stbuf. st_dev; 855 /* not xstat(): shouldn't bomb out on 856 * "find not_exist exist -xdev" */ 857 if (stat(argv[i], &stbuf)) 858 stbuf.st_dev = -1L; 859 xdev_dev[i-1] = stbuf.st_dev; 273 860 } 274 861 } 275 #endif 276 #ifdef CONFIG_FEATURE_FIND_NEWER 277 } else if (strcmp(argv[i], "-newer") == 0) { 278 struct stat stat_newer; 279 if (++i == argc) 280 bb_error_msg_and_die(bb_msg_requires_arg, "-newer"); 281 xstat (argv[i], &stat_newer); 282 newer_mtime = stat_newer.st_mtime; 283 #endif 284 #ifdef CONFIG_FEATURE_FIND_INUM 285 } else if (strcmp(argv[i], "-inum") == 0) { 286 char *end; 287 if (++i == argc) 288 bb_error_msg_and_die(bb_msg_requires_arg, "-inum"); 289 inode_num = strtol(argv[i], &end, 10); 290 if (end[0] != '\0') 291 bb_error_msg_and_die(bb_msg_invalid_arg, argv[i], "-inum"); 292 #endif 293 #ifdef CONFIG_FEATURE_FIND_EXEC 294 } else if (strcmp(argv[i], "-exec") == 0) { 295 int b_pos; 296 char *cmd_string = ""; 297 298 while (i++) { 299 if (i == argc) 300 bb_error_msg_and_die(bb_msg_requires_arg, "-exec"); 301 if (*argv[i] == ';') 302 break; 303 cmd_string = bb_xasprintf("%s %s", cmd_string, argv[i]); 304 } 305 306 if (*cmd_string == 0) 307 bb_error_msg_and_die(bb_msg_requires_arg, "-exec"); 308 cmd_string++; 309 exec_str = xmalloc(sizeof(char *)); 310 311 while ((b_pos = strstr(cmd_string, "{}") - cmd_string), (b_pos >= 0)) { 312 num_matches++; 313 exec_str = xrealloc(exec_str, (num_matches + 1) * sizeof(char *)); 314 exec_str[num_matches - 1] = bb_xstrndup(cmd_string, b_pos); 315 cmd_string += b_pos + 2; 316 } 317 exec_str[num_matches] = bb_xstrdup(cmd_string); 318 exec_opt = 1; 319 #endif 320 } else 321 bb_show_usage(); 322 } 323 324 if (firstopt == 1) { 325 if (! recursive_action(".", TRUE, dereference, FALSE, fileAction, 326 fileAction, NULL)) 862 argp[0] = (char*)"-a"; 863 } 864 #endif 865 #if ENABLE_FEATURE_FIND_MAXDEPTH 866 if (opt == OPT_MAXDEPTH) { 867 if (!argp[1]) 868 bb_show_usage(); 869 maxdepth = xatoi_u(argp[1]); 870 argp[0] = (char*)"-a"; 871 argp[1] = (char*)"-a"; 872 argp++; 873 } 874 #endif 875 argp++; 876 } 877 878 actions = parse_params(&argv[firstopt]); 879 880 for (i = 1; i < firstopt; i++) { 881 if (!recursive_action(argv[i], 882 recurse_flags, /* flags */ 883 fileAction, /* file action */ 884 fileAction, /* dir action */ 885 #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 */ 889 #else 890 NULL, /* user data */ 891 #endif 892 0)) /* depth */ 327 893 status = EXIT_FAILURE; 328 } else { 329 for (i = 1; i < firstopt; i++) { 330 if (! recursive_action(argv[i], TRUE, dereference, FALSE, fileAction, 331 fileAction, NULL)) 332 status = EXIT_FAILURE; 333 } 334 } 335 894 } 336 895 return status; 337 896 } -
branches/stable/mindi-busybox/findutils/grep.c
r821 r1770 6 6 * Copyright (C) 1999,2000,2001 by Mark Whitley <markw@codepoet.org> 7 7 * 8 * Licensed under the GPL v2 , see the file LICENSE in this tarball.8 * Licensed under the GPL v2 or later, see the file LICENSE in this tarball. 9 9 */ 10 10 /* BB_AUDIT SUSv3 defects - unsupported option -x. */ … … 15 15 * correction "-e pattern1 -e pattern2" logic and more optimizations. 16 16 * precompiled regex 17 */ 18 19 #include "busybox.h" 20 #include <stdio.h> 21 #include <stdlib.h> 22 #include <getopt.h> 23 #include <string.h> 24 #include <errno.h> 17 */ 18 /* 19 * (C) 2006 Jac Goudsmit added -o option 20 */ 21 22 #include "libbb.h" 25 23 #include "xregex.h" 26 24 27 28 25 /* options */ 29 static unsigned long opt; 30 #define GREP_OPTS "lnqvscFiHhe:f:L" 31 #define GREP_OPT_l (1<<0) 32 #define PRINT_FILES_WITH_MATCHES (opt & GREP_OPT_l) 33 #define GREP_OPT_n (1<<1) 34 #define PRINT_LINE_NUM (opt & GREP_OPT_n) 35 #define GREP_OPT_q (1<<2) 36 #define BE_QUIET (opt & GREP_OPT_q) 37 #define GREP_OPT_v (1<<3) 38 typedef char invert_search_t; 39 static invert_search_t invert_search; 40 #define GREP_OPT_s (1<<4) 41 #define SUPPRESS_ERR_MSGS (opt & GREP_OPT_s) 42 #define GREP_OPT_c (1<<5) 43 #define PRINT_MATCH_COUNTS (opt & GREP_OPT_c) 44 #define GREP_OPT_F (1<<6) 45 #define FGREP_FLAG (opt & GREP_OPT_F) 46 #define GREP_OPT_i (1<<7) 47 #define GREP_OPT_H (1<<8) 48 #define GREP_OPT_h (1<<9) 49 #define GREP_OPT_e (1<<10) 50 #define GREP_OPT_f (1<<11) 51 #define GREP_OPT_L (1<<12) 52 #define PRINT_FILES_WITHOUT_MATCHES ((opt & GREP_OPT_L) != 0) 53 #if ENABLE_FEATURE_GREP_CONTEXT 54 #define GREP_OPT_CONTEXT "A:B:C" 55 #define GREP_OPT_A (1<<13) 56 #define GREP_OPT_B (1<<14) 57 #define GREP_OPT_C (1<<15) 58 #define GREP_OPT_E (1<<16) 59 #else 60 #define GREP_OPT_CONTEXT "" 61 #define GREP_OPT_A (0) 62 #define GREP_OPT_B (0) 63 #define GREP_OPT_C (0) 64 #define GREP_OPT_E (1<<13) 65 #endif 66 #if ENABLE_FEATURE_GREP_EGREP_ALIAS 67 # define OPT_EGREP "E" 68 #else 69 # define OPT_EGREP "" 70 #endif 71 26 #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") \ 31 "aI" 32 /* ignored: -a "assume all files to be text" */ 33 /* ignored: -I "assume binary files have no matches" */ 34 35 enum { 36 OPTBIT_l, /* list matched file names only */ 37 OPTBIT_n, /* print line# */ 38 OPTBIT_q, /* quiet - exit(0) of first match */ 39 OPTBIT_v, /* invert the match, to select non-matching lines */ 40 OPTBIT_s, /* suppress errors about file open errors */ 41 OPTBIT_c, /* count matches per file (suppresses normal output) */ 42 OPTBIT_F, /* literal match */ 43 OPTBIT_i, /* case-insensitive */ 44 OPTBIT_H, /* force filename display */ 45 OPTBIT_h, /* inhibit filename display */ 46 OPTBIT_e, /* -e PATTERN */ 47 OPTBIT_f, /* -f FILE_WITH_PATTERNS */ 48 OPTBIT_L, /* list unmatched file names only */ 49 OPTBIT_o, /* show only matching parts of lines */ 50 OPTBIT_r, /* recurse dirs */ 51 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 */ 57 OPT_l = 1 << OPTBIT_l, 58 OPT_n = 1 << OPTBIT_n, 59 OPT_q = 1 << OPTBIT_q, 60 OPT_v = 1 << OPTBIT_v, 61 OPT_s = 1 << OPTBIT_s, 62 OPT_c = 1 << OPTBIT_c, 63 OPT_F = 1 << OPTBIT_F, 64 OPT_i = 1 << OPTBIT_i, 65 OPT_H = 1 << OPTBIT_H, 66 OPT_h = 1 << OPTBIT_h, 67 OPT_e = 1 << OPTBIT_e, 68 OPT_f = 1 << OPTBIT_f, 69 OPT_L = 1 << OPTBIT_L, 70 OPT_o = 1 << OPTBIT_o, 71 OPT_r = 1 << OPTBIT_r, 72 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, 78 }; 79 80 #define PRINT_FILES_WITH_MATCHES (option_mask32 & OPT_l) 81 #define PRINT_LINE_NUM (option_mask32 & OPT_n) 82 #define BE_QUIET (option_mask32 & OPT_q) 83 #define SUPPRESS_ERR_MSGS (option_mask32 & OPT_s) 84 #define PRINT_MATCH_COUNTS (option_mask32 & OPT_c) 85 #define FGREP_FLAG (option_mask32 & OPT_F) 86 #define PRINT_FILES_WITHOUT_MATCHES (option_mask32 & OPT_L) 87 88 typedef unsigned char byte_t; 89 90 static int max_matches; 72 91 static int reflags; 73 static int print_filename; 74 75 #if ENABLE_FEATURE_GREP_CONTEXT 92 static byte_t invert_search; 93 static byte_t print_filename; 94 static byte_t open_errors; 95 96 #if ENABLE_FEATURE_GREP_CONTEXT 97 static byte_t did_print_line; 76 98 static int lines_before; 77 99 static int lines_after; … … 79 101 static int last_line_printed; 80 102 #endif /* ENABLE_FEATURE_GREP_CONTEXT */ 81 82 103 /* globals used internally */ 83 104 static llist_t *pattern_head; /* growable list of patterns to match */ 84 static c har *cur_file;/* the current file we are reading */85 86 typedef struct GREP_LIST_DATA{105 static const char *cur_file; /* the current file we are reading */ 106 107 typedef struct grep_list_data_t { 87 108 char *pattern; 88 109 regex_t preg; … … 95 116 { 96 117 #if ENABLE_FEATURE_GREP_CONTEXT 118 /* Happens when we go to next file, immediately hit match 119 * and try to print prev context... from prev file! Don't do it */ 120 if (linenum < 1) 121 return; 97 122 /* possibly print the little '--' separator */ 98 if ((lines_before || lines_after) && last_line_printed&&99 last_line_printed <linenum - 1) {123 if ((lines_before || lines_after) && did_print_line && 124 last_line_printed != linenum - 1) { 100 125 puts("--"); 101 126 } 127 /* guard against printing "--" before first line of first file */ 128 did_print_line = 1; 102 129 last_line_printed = linenum; 103 130 #endif 104 if (print_filename > 0)131 if (print_filename) 105 132 printf("%s%c", cur_file, decoration); 106 133 if (PRINT_LINE_NUM) 107 134 printf("%i%c", linenum, decoration); 108 puts(line); 109 } 110 135 /* Emulate weird GNU grep behavior with -ov */ 136 if ((option_mask32 & (OPT_v|OPT_o)) != (OPT_v|OPT_o)) 137 puts(line); 138 } 111 139 112 140 static int grep_file(FILE *file) 113 141 { 114 142 char *line; 115 invert_search_t ret;143 byte_t ret; 116 144 int linenum = 0; 117 145 int nmatches = 0; 146 regmatch_t regmatch; 118 147 #if ENABLE_FEATURE_GREP_CONTEXT 119 148 int print_n_lines_after = 0; 120 149 int curpos = 0; /* track where we are in the circular 'before' buffer */ 121 150 int idx = 0; /* used for iteration through the circular buffer */ 151 #else 152 enum { print_n_lines_after = 0 }; 122 153 #endif /* ENABLE_FEATURE_GREP_CONTEXT */ 123 154 124 while ((line = bb_get_chomped_line_from_file(file)) != NULL) {155 while ((line = xmalloc_getline(file)) != NULL) { 125 156 llist_t *pattern_ptr = pattern_head; 126 157 grep_list_data_t * gl; … … 139 170 * invert search) 140 171 */ 141 if (!(gl->flg_mem_alocated_compiled & COMPILED)) {172 if (!(gl->flg_mem_alocated_compiled & COMPILED)) { 142 173 gl->flg_mem_alocated_compiled |= COMPILED; 143 174 xregcomp(&(gl->preg), gl->pattern, reflags); 144 175 } 145 ret |= regexec(&(gl->preg), line, 0, NULL, 0) == 0; 176 regmatch.rm_so = 0; 177 regmatch.rm_eo = 0; 178 if (regexec(&(gl->preg), line, 1, ®match, 0) == 0) { 179 if (!(option_mask32 & OPT_w)) 180 ret = 1; 181 else { 182 char c = ' '; 183 if (regmatch.rm_so) 184 c = line[regmatch.rm_so - 1]; 185 if (!isalnum(c) && c != '_') { 186 c = line[regmatch.rm_eo]; 187 if (!c || (!isalnum(c) && c != '_')) 188 ret = 1; 189 } 190 } 191 } 146 192 } 147 193 pattern_ptr = pattern_ptr->link; 148 194 } /* while (pattern_ptr) */ 149 195 150 if ((ret ^ invert_search)) { 151 152 if (PRINT_FILES_WITH_MATCHES || BE_QUIET) 153 free(line); 154 155 /* if we found a match but were told to be quiet, stop here */ 156 if (BE_QUIET || PRINT_FILES_WITHOUT_MATCHES) 157 return -1; 158 159 /* keep track of matches */ 160 nmatches++; 161 196 if (ret ^ invert_search) { 197 /* keep track of matches */ 198 nmatches++; 199 200 /* quiet/print (non)matching file names only? */ 201 if (option_mask32 & (OPT_q|OPT_l|OPT_L)) { 202 free(line); /* we don't need line anymore */ 203 if (BE_QUIET) { 204 /* manpage says about -q: 205 * "exit immediately with zero status 206 * if any match is found, 207 * even if errors were detected" */ 208 exit(0); 209 } 162 210 /* if we're just printing filenames, we stop after the first match */ 163 if (PRINT_FILES_WITH_MATCHES) 164 break; 165 166 /* print the matched line */ 167 if (PRINT_MATCH_COUNTS == 0) { 168 #if ENABLE_FEATURE_GREP_CONTEXT 169 int prevpos = (curpos == 0) ? lines_before - 1 : curpos - 1; 170 171 /* if we were told to print 'before' lines and there is at least 172 * one line in the circular buffer, print them */ 173 if (lines_before && before_buf[prevpos] != NULL) { 174 int first_buf_entry_line_num = linenum - lines_before; 175 176 /* advance to the first entry in the circular buffer, and 177 * figure out the line number is of the first line in the 178 * buffer */ 179 idx = curpos; 180 while (before_buf[idx] == NULL) { 181 idx = (idx + 1) % lines_before; 182 first_buf_entry_line_num++; 183 } 184 185 /* now print each line in the buffer, clearing them as we go */ 186 while (before_buf[idx] != NULL) { 187 print_line(before_buf[idx], first_buf_entry_line_num, '-'); 188 free(before_buf[idx]); 189 before_buf[idx] = NULL; 190 idx = (idx + 1) % lines_before; 191 first_buf_entry_line_num++; 192 } 211 if (PRINT_FILES_WITH_MATCHES) { 212 puts(cur_file); 213 /* fall thru to "return 1" */ 214 } 215 /* OPT_L aka PRINT_FILES_WITHOUT_MATCHES: return early */ 216 return 1; /* one match */ 217 } 218 219 #if ENABLE_FEATURE_GREP_CONTEXT 220 /* Were we printing context and saw next (unwanted) match? */ 221 if ((option_mask32 & OPT_m) && nmatches > max_matches) 222 break; 223 #endif 224 225 /* print the matched line */ 226 if (PRINT_MATCH_COUNTS == 0) { 227 #if ENABLE_FEATURE_GREP_CONTEXT 228 int prevpos = (curpos == 0) ? lines_before - 1 : curpos - 1; 229 230 /* if we were told to print 'before' lines and there is at least 231 * one line in the circular buffer, print them */ 232 if (lines_before && before_buf[prevpos] != NULL) { 233 int first_buf_entry_line_num = linenum - lines_before; 234 235 /* advance to the first entry in the circular buffer, and 236 * figure out the line number is of the first line in the 237 * buffer */ 238 idx = curpos; 239 while (before_buf[idx] == NULL) { 240 idx = (idx + 1) % lines_before; 241 first_buf_entry_line_num++; 193 242 } 194 243 195 /* make a note that we need to print 'after' lines */ 196 print_n_lines_after = lines_after; 244 /* now print each line in the buffer, clearing them as we go */ 245 while (before_buf[idx] != NULL) { 246 print_line(before_buf[idx], first_buf_entry_line_num, '-'); 247 free(before_buf[idx]); 248 before_buf[idx] = NULL; 249 idx = (idx + 1) % lines_before; 250 first_buf_entry_line_num++; 251 } 252 } 253 254 /* make a note that we need to print 'after' lines */ 255 print_n_lines_after = lines_after; 197 256 #endif 257 if (option_mask32 & OPT_o) { 258 line[regmatch.rm_eo] = '\0'; 259 print_line(line + regmatch.rm_so, linenum, ':'); 260 } else { 198 261 print_line(line, linenum, ':'); 199 262 } 200 263 } 201 #if ENABLE_FEATURE_GREP_CONTEXT 202 else { /* no match */ 203 /* Add the line to the circular 'before' buffer */ 204 if(lines_before) { 205 free(before_buf[curpos]); 206 before_buf[curpos] = bb_xstrdup(line); 207 curpos = (curpos + 1) % lines_before; 208 } 209 } 210 264 } 265 #if ENABLE_FEATURE_GREP_CONTEXT 266 else { /* no match */ 211 267 /* if we need to print some context lines after the last match, do so */ 212 if (print_n_lines_after && (last_line_printed != linenum)) {268 if (print_n_lines_after) { 213 269 print_line(line, linenum, '-'); 214 270 print_n_lines_after--; 271 } else if (lines_before) { 272 /* Add the line to the circular 'before' buffer */ 273 free(before_buf[curpos]); 274 before_buf[curpos] = line; 275 curpos = (curpos + 1) % lines_before; 276 /* avoid free(line) - we took line */ 277 line = NULL; 215 278 } 279 } 280 216 281 #endif /* ENABLE_FEATURE_GREP_CONTEXT */ 217 282 free(line); 218 } 219 283 284 /* Did we print all context after last requested match? */ 285 if ((option_mask32 & OPT_m) 286 && !print_n_lines_after && nmatches == max_matches) 287 break; 288 } 220 289 221 290 /* special-case file post-processing for options where we don't print line … … 224 293 /* grep -c: print [filename:]count, even if count is zero */ 225 294 if (PRINT_MATCH_COUNTS) { 226 if (print_filename > 0)295 if (print_filename) 227 296 printf("%s:", cur_file); 228 printf("%d\n", nmatches); 229 } 230 231 /* grep -l: print just the filename, but only if we grepped the line in the file */ 232 if (PRINT_FILES_WITH_MATCHES && nmatches > 0) { 233 puts(cur_file); 234 } 235 236 /* grep -L: print just the filename, but only if we didn't grep the line in the file */ 237 if (PRINT_FILES_WITHOUT_MATCHES && nmatches == 0) { 297 printf("%d\n", nmatches); 298 } 299 300 /* grep -L: print just the filename */ 301 if (PRINT_FILES_WITHOUT_MATCHES) { 302 /* nmatches is zero, no need to check it: 303 * we return 1 early if we detected a match 304 * and PRINT_FILES_WITHOUT_MATCHES is set */ 238 305 puts(cur_file); 239 306 } … … 260 327 } 261 328 262 263 329 static void load_regexes_from_file(llist_t *fopt) 264 330 { … … 266 332 FILE *f; 267 333 268 while (fopt) {334 while (fopt) { 269 335 llist_t *cur = fopt; 270 336 char *ffile = cur->data; … … 272 338 fopt = cur->link; 273 339 free(cur); 274 f = bb_xfopen(ffile, "r");275 while ((line = bb_get_chomped_line_from_file(f)) != NULL) {340 f = xfopen(ffile, "r"); 341 while ((line = xmalloc_getline(f)) != NULL) { 276 342 llist_add_to(&pattern_head, 277 343 new_grep_list_data(line, PATTERN_MEM_A)); … … 280 346 } 281 347 282 348 static int file_action_grep(const char *filename, struct stat *statbuf, void* matched, int depth) 349 { 350 FILE *file = fopen(filename, "r"); 351 if (file == NULL) { 352 if (!SUPPRESS_ERR_MSGS) 353 bb_perror_msg("%s", cur_file); 354 open_errors = 1; 355 return 0; 356 } 357 cur_file = filename; 358 *(int*)matched += grep_file(file); 359 fclose(file); 360 return 1; 361 } 362 363 static int grep_dir(const char *dir) 364 { 365 int matched = 0; 366 recursive_action(dir, 367 /* recurse=yes */ ACTION_RECURSE | 368 /* followLinks=no */ 369 /* depthFirst=yes */ ACTION_DEPTHFIRST, 370 /* fileAction= */ file_action_grep, 371 /* dirAction= */ NULL, 372 /* userData= */ &matched, 373 /* depth= */ 0); 374 return matched; 375 } 376 377 int grep_main(int argc, char **argv); 283 378 int grep_main(int argc, char **argv) 284 379 { 285 380 FILE *file; 286 381 int matched; 382 char *mopt; 287 383 llist_t *fopt = NULL; 288 int error_open_count = 0;289 384 290 385 /* do normal option parsing */ 291 386 #if ENABLE_FEATURE_GREP_CONTEXT 292 {293 char *junk;294 387 char *slines_after; 295 388 char *slines_before; 296 389 char *Copt; 297 390 298 bb_opt_complementally = "H-h:e::f::C-AB";299 opt = bb_getopt_ulflags(argc,argv,300 GREP_OPTS GREP_OPT_CONTEXT OPT_EGREP,301 &pattern_head, &fopt, 391 opt_complementary = "H-h:e::f::C-AB"; 392 getopt32(argv, 393 OPTSTR_GREP, 394 &pattern_head, &fopt, &mopt, 302 395 &slines_after, &slines_before, &Copt); 303 396 304 if (opt & GREP_OPT_C) {305 /* C option unseted A and B options, but next-A or -B306 may be ovewrite own option*/307 if (!(opt & GREP_OPT_A)) /* not overwtited*/397 if (option_mask32 & OPT_C) { 398 /* -C unsets prev -A and -B, but following -A or -B 399 may override it */ 400 if (!(option_mask32 & OPT_A)) /* not overridden */ 308 401 slines_after = Copt; 309 if (!(opt & GREP_OPT_B)) /* not overwtited*/402 if (!(option_mask32 & OPT_B)) /* not overridden */ 310 403 slines_before = Copt; 311 opt |= GREP_OPT_A|GREP_OPT_B; /* set for parse now */ 312 } 313 if(opt & GREP_OPT_A) { 314 lines_after = strtoul(slines_after, &junk, 10); 315 if(*junk != '\0') 316 bb_error_msg_and_die(bb_msg_invalid_arg, slines_after, "-A"); 317 } 318 if(opt & GREP_OPT_B) { 319 lines_before = strtoul(slines_before, &junk, 10); 320 if(*junk != '\0') 321 bb_error_msg_and_die(bb_msg_invalid_arg, slines_before, "-B"); 322 } 323 /* sanity checks after parse may be invalid numbers ;-) */ 324 if ((opt & (GREP_OPT_c|GREP_OPT_q|GREP_OPT_l|GREP_OPT_L))) { 325 opt &= ~GREP_OPT_n; 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); 411 } 412 /* sanity checks */ 413 if (option_mask32 & (OPT_c|OPT_q|OPT_l|OPT_L)) { 414 option_mask32 &= ~OPT_n; 326 415 lines_before = 0; 327 416 lines_after = 0; 328 } else if(lines_before > 0) 329 before_buf = (char **)xcalloc(lines_before, sizeof(char *)); 330 } 417 } else if (lines_before > 0) 418 before_buf = xzalloc(lines_before * sizeof(char *)); 331 419 #else 332 420 /* with auto sanity checks */ 333 bb_opt_complementally = "H-h:e::f::c-n:q-n:l-n";334 opt = bb_getopt_ulflags(argc, argv, GREP_OPTS OPT_EGREP,335 &pattern_head, &fopt );421 opt_complementary = "H-h:e::f::c-n:q-n:l-n"; 422 getopt32(argv, OPTSTR_GREP, 423 &pattern_head, &fopt, &mopt); 336 424 #endif 337 invert_search = (opt & GREP_OPT_v) != 0; /* 0 | 1 */ 338 339 if(opt & GREP_OPT_H) 340 print_filename++; 341 if(opt & GREP_OPT_h) 342 print_filename--; 425 if (option_mask32 & OPT_m) { 426 max_matches = xatoi_u(mopt); 427 } 428 invert_search = ((option_mask32 & OPT_v) != 0); /* 0 | 1 */ 429 343 430 if (pattern_head != NULL) { 344 /* convert char * argv[]to grep_list_data_t */431 /* convert char **argv to grep_list_data_t */ 345 432 llist_t *cur; 346 433 347 for (cur = pattern_head; cur; cur = cur->link)434 for (cur = pattern_head; cur; cur = cur->link) 348 435 cur->data = new_grep_list_data(cur->data, 0); 349 436 } 350 if (opt & GREP_OPT_f)437 if (option_mask32 & OPT_f) 351 438 load_regexes_from_file(fopt); 352 439 353 if(ENABLE_FEATURE_GREP_FGREP_ALIAS && bb_applet_name[0] == 'f') 354 opt |= GREP_OPT_F; 355 356 if(ENABLE_FEATURE_GREP_EGREP_ALIAS && 357 (bb_applet_name[0] == 'e' || (opt & GREP_OPT_E))) 358 reflags = REG_EXTENDED | REG_NOSUB; 359 else 440 if (ENABLE_FEATURE_GREP_FGREP_ALIAS && applet_name[0] == 'f') 441 option_mask32 |= OPT_F; 442 443 if (!(option_mask32 & (OPT_o | OPT_w))) 360 444 reflags = REG_NOSUB; 361 445 362 if(opt & GREP_OPT_i) 446 if (ENABLE_FEATURE_GREP_EGREP_ALIAS && 447 (applet_name[0] == 'e' || (option_mask32 & OPT_E))) 448 reflags |= REG_EXTENDED; 449 450 if (option_mask32 & OPT_i) 363 451 reflags |= REG_ICASE; 364 452 … … 369 457 * argv[optind] should be the pattern. no pattern, no worky */ 370 458 if (pattern_head == NULL) { 459 char *pattern; 371 460 if (*argv == NULL) 372 461 bb_show_usage(); 373 else { 374 char *pattern = new_grep_list_data(*argv++, 0); 375 376 llist_add_to(&pattern_head, pattern); 377 argc--; 378 } 462 pattern = new_grep_list_data(*argv++, 0); 463 llist_add_to(&pattern_head, pattern); 464 argc--; 379 465 } 380 466 381 467 /* argv[(optind)..(argc-1)] should be names of file to grep through. If 382 * there is more than one file to grep, we will print the filenames */ 383 if (argc > 1) { 384 print_filename++; 468 * there is more than one file to grep, we will print the filenames. */ 469 if (argc > 1) 470 print_filename = 1; 471 /* -H / -h of course override */ 472 if (option_mask32 & OPT_H) 473 print_filename = 1; 474 if (option_mask32 & OPT_h) 475 print_filename = 0; 385 476 386 477 /* If no files were specified, or '-' was specified, take input from 387 478 * stdin. Otherwise, we grep through all the files specified. */ 388 } else if (argc == 0) {479 if (argc == 0) 389 480 argc++; 390 }391 481 matched = 0; 392 482 while (argc--) { 393 483 cur_file = *argv++; 394 if(!cur_file || (*cur_file == '-' && !cur_file[1])) { 484 file = stdin; 485 if (!cur_file || (*cur_file == '-' && !cur_file[1])) { 395 486 cur_file = "(standard input)"; 396 file = stdin;397 487 } else { 488 if (option_mask32 & OPT_r) { 489 struct stat st; 490 if (stat(cur_file, &st) == 0 && S_ISDIR(st.st_mode)) { 491 if (!(option_mask32 & OPT_h)) 492 print_filename = 1; 493 matched += grep_dir(cur_file); 494 goto grep_done; 495 } 496 } 497 /* else: fopen(dir) will succeed, but reading won't */ 398 498 file = fopen(cur_file, "r"); 499 if (file == NULL) { 500 if (!SUPPRESS_ERR_MSGS) 501 bb_perror_msg("%s", cur_file); 502 open_errors = 1; 503 continue; 504 } 399 505 } 400 if (file == NULL) { 401 if (!SUPPRESS_ERR_MSGS) 402 bb_perror_msg("%s", cur_file); 403 error_open_count++; 404 } else { 405 matched += grep_file(file); 406 if(matched < 0) { 407 /* we found a match but were told to be quiet, stop here and 408 * return success */ 409 break; 410 } 411 fclose(file); 412 } 506 matched += grep_file(file); 507 fclose_if_not_stdin(file); 508 grep_done: ; 413 509 } 414 510 … … 421 517 422 518 pattern_head = pattern_head->link; 423 if ((gl->flg_mem_alocated_compiled & PATTERN_MEM_A))519 if ((gl->flg_mem_alocated_compiled & PATTERN_MEM_A)) 424 520 free(gl->pattern); 425 if ((gl->flg_mem_alocated_compiled & COMPILED))521 if ((gl->flg_mem_alocated_compiled & COMPILED)) 426 522 regfree(&(gl->preg)); 523 free(gl); 427 524 free(pattern_head_ptr); 428 525 } 429 526 } 430 527 /* 0 = success, 1 = failed, 2 = error */ 431 /* If the -q option is specified, the exit status shall be zero 432 * if an input line is selected, even if an error was detected. */ 433 if(BE_QUIET && matched) 434 return 0; 435 if(error_open_count) 528 if (open_errors) 436 529 return 2; 437 530 return !matched; /* invert return value 0 = success, 1 = failed */ -
branches/stable/mindi-busybox/findutils/xargs.c
r821 r1770 18 18 */ 19 19 20 #include "busybox.h" 21 #include <stdio.h> 22 #include <stdlib.h> 23 #include <string.h> 24 #include <unistd.h> 25 #include <getopt.h> 26 #include <errno.h> 27 #include <fcntl.h> 28 #include <sys/types.h> 29 #include <sys/wait.h> 20 #include "libbb.h" 21 22 /* This is a NOEXEC applet. Be very careful! */ 23 30 24 31 25 /* COMPAT: SYSV version defaults size (and has a max value of) to 470. … … 40 34 41 35 #ifdef TEST 42 # ifndef CONFIG_FEATURE_XARGS_SUPPORT_CONFIRMATION43 # define CONFIG_FEATURE_XARGS_SUPPORT_CONFIRMATION36 # ifndef ENABLE_FEATURE_XARGS_SUPPORT_CONFIRMATION 37 # define ENABLE_FEATURE_XARGS_SUPPORT_CONFIRMATION 1 44 38 # endif 45 # ifndef CONFIG_FEATURE_XARGS_SUPPORT_QUOTES46 # define CONFIG_FEATURE_XARGS_SUPPORT_QUOTES39 # ifndef ENABLE_FEATURE_XARGS_SUPPORT_QUOTES 40 # define ENABLE_FEATURE_XARGS_SUPPORT_QUOTES 1 47 41 # endif 48 # ifndef CONFIG_FEATURE_XARGS_SUPPORT_TERMOPT49 # define CONFIG_FEATURE_XARGS_SUPPORT_TERMOPT42 # ifndef ENABLE_FEATURE_XARGS_SUPPORT_TERMOPT 43 # define ENABLE_FEATURE_XARGS_SUPPORT_TERMOPT 1 50 44 # endif 51 # ifndef CONFIG_FEATURE_XARGS_SUPPORT_ZERO_TERM52 # define CONFIG_FEATURE_XARGS_SUPPORT_ZERO_TERM45 # ifndef ENABLE_FEATURE_XARGS_SUPPORT_ZERO_TERM 46 # define ENABLE_FEATURE_XARGS_SUPPORT_ZERO_TERM 1 53 47 # endif 54 48 #endif 55 49 56 50 /* 57 This function ha vespecial algorithm.58 Don `t use fork and include to main!51 This function has special algorithm. 52 Don't use fork and include to main! 59 53 */ 60 static int xargs_exec(char *const *args) 61 { 62 pid_t p; 63 volatile int exec_errno = 0; /* shared vfork stack */ 64 65 if ((p = vfork()) >= 0) { 66 if (p == 0) { 67 /* vfork -- child */ 68 execvp(args[0], args); 69 exec_errno = errno; /* set error to shared stack */ 70 _exit(1); 71 } else { 72 /* vfork -- parent */ 73 int status; 74 75 while (wait(&status) == (pid_t) - 1) 76 if (errno != EINTR) 77 break; 78 if (exec_errno) { 79 errno = exec_errno; 80 bb_perror_msg("%s", args[0]); 81 return exec_errno == ENOENT ? 127 : 126; 82 } else { 83 if (WEXITSTATUS(status) == 255) { 84 bb_error_msg("%s: exited with status 255; aborting", args[0]); 85 return 124; 86 } 87 if (WIFSTOPPED(status)) { 88 bb_error_msg("%s: stopped by signal %d", 89 args[0], WSTOPSIG(status)); 90 return 125; 91 } 92 if (WIFSIGNALED(status)) { 93 bb_error_msg("%s: terminated by signal %d", 94 args[0], WTERMSIG(status)); 95 return 125; 96 } 97 if (WEXITSTATUS(status) != 0) 98 return 123; 99 return 0; 100 } 101 } 102 } else { 103 bb_perror_msg_and_die("vfork"); 104 } 105 } 106 107 108 typedef struct xlist_s { 109 char *data; 110 size_t lenght; 111 struct xlist_s *link; 54 static int xargs_exec(char **args) 55 { 56 int status; 57 58 status = spawn_and_wait(args); 59 if (status < 0) { 60 bb_perror_msg("%s", args[0]); 61 return errno == ENOENT ? 127 : 126; 62 } 63 if (status == 255) { 64 bb_error_msg("%s: exited with status 255; aborting", args[0]); 65 return 124; 66 } 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) { 75 bb_error_msg("%s: terminated by signal %d", 76 args[0], status - 1000); 77 return 125; 78 } 79 if (status) 80 return 123; 81 return 0; 82 } 83 84 85 typedef struct xlist_t { 86 struct xlist_t *link; 87 size_t length; 88 char xstr[1]; 112 89 } xlist_t; 113 90 114 static int eof_stdin_detected;91 static smallint eof_stdin_detected; 115 92 116 93 #define ISBLANK(c) ((c) == ' ' || (c) == '\t') 117 #define ISSPACE(c) (ISBLANK 94 #define ISSPACE(c) (ISBLANK(c) || (c) == '\n' || (c) == '\r' \ 118 95 || (c) == '\f' || (c) == '\v') 119 96 120 #if def CONFIG_FEATURE_XARGS_SUPPORT_QUOTES121 static xlist_t *process_stdin(xlist_t * 97 #if ENABLE_FEATURE_XARGS_SUPPORT_QUOTES 98 static xlist_t *process_stdin(xlist_t *list_arg, 122 99 const char *eof_str, size_t mc, char *buf) 123 100 { … … 129 106 char *s = NULL; /* start word */ 130 107 char *p = NULL; /* pointer to end word */ 131 char q = 0;/* quote char */108 char q = '\0'; /* quote char */ 132 109 char state = NORM; 133 110 char eof_str_detected = 0; … … 137 114 xlist_t *prev; 138 115 139 for (prev = cur = list_arg; cur; cur = cur->link) { 140 line_l += cur->lenght; /* previous allocated */ 141 if (prev != cur) 142 prev = prev->link; 116 prev = cur = list_arg; 117 while (1) { 118 if (!cur) break; 119 prev = cur; 120 line_l += cur->length; 121 cur = cur->link; 143 122 } 144 123 … … 146 125 c = getchar(); 147 126 if (c == EOF) { 148 eof_stdin_detected ++;127 eof_stdin_detected = 1; 149 128 if (s) 150 129 goto unexpected_eof; … … 157 136 goto set; 158 137 } else if (state == QUOTE) { 159 if (c == q) { 160 q = 0; 161 state = NORM; 162 } else { 138 if (c != q) 163 139 goto set; 164 }165 } else { /* if(state == NORM) */166 140 q = '\0'; 141 state = NORM; 142 } else { /* if (state == NORM) */ 167 143 if (ISSPACE(c)) { 168 144 if (s) { 169 unexpected_eof:145 unexpected_eof: 170 146 state = SPACE; 171 c = 0;147 c = '\0'; 172 148 goto set; 173 149 } … … 181 157 state = QUOTE; 182 158 } else { 183 set:159 set: 184 160 if ((size_t)(p - buf) >= mc) 185 161 bb_error_msg_and_die("argument line too long"); … … 195 171 /* word loaded */ 196 172 if (eof_str) { 197 eof_str_detected = strcmp(s, eof_str) == 0;173 eof_str_detected = (strcmp(s, eof_str) == 0); 198 174 } 199 175 if (!eof_str_detected) { 200 size_t lenght = (p - buf); 201 202 cur = xmalloc(sizeof(xlist_t) + lenght); 203 cur->data = memcpy(cur + 1, s, lenght); 204 cur->lenght = lenght; 176 size_t length = (p - buf); 177 /* Dont xzalloc - it can be quite big */ 178 cur = xmalloc(offsetof(xlist_t, xstr) + length); 205 179 cur->link = NULL; 180 cur->length = length; 181 memcpy(cur->xstr, s, length); 206 182 if (prev == NULL) { 207 183 list_arg = cur; … … 210 186 } 211 187 prev = cur; 212 line_l += leng ht;188 line_l += length; 213 189 if (line_l > mc) { 214 190 /* stop memory usage :-) */ … … 224 200 #else 225 201 /* The variant does not support single quotes, double quotes or backslash */ 226 static xlist_t *process_stdin(xlist_t * 227 const char *eof_str, size_t mc, char *buf)202 static xlist_t *process_stdin(xlist_t *list_arg, 203 const char *eof_str, size_t mc, char *buf) 228 204 { 229 205 230 206 int c; /* current char */ 231 inteof_str_detected = 0;207 char eof_str_detected = 0; 232 208 char *s = NULL; /* start word */ 233 209 char *p = NULL; /* pointer to end word */ … … 236 212 xlist_t *prev; 237 213 238 for (prev = cur = list_arg; cur; cur = cur->link) { 239 line_l += cur->lenght; /* previous allocated */ 240 if (prev != cur) 241 prev = prev->link; 214 prev = cur = list_arg; 215 while (1) { 216 if (!cur) break; 217 prev = cur; 218 line_l += cur->length; 219 cur = cur->link; 242 220 } 243 221 … … 245 223 c = getchar(); 246 224 if (c == EOF) { 247 eof_stdin_detected ++;225 eof_stdin_detected = 1; 248 226 } 249 227 if (eof_str_detected) … … 258 236 if ((p - buf) >= mc) 259 237 bb_error_msg_and_die("argument line too long"); 260 *p++ = c == EOF ? 0 : c;238 *p++ = (c == EOF ? '\0' : c); 261 239 if (c == EOF) { /* word's delimiter or EOF detected */ 262 240 /* word loaded */ 263 241 if (eof_str) { 264 eof_str_detected = strcmp(s, eof_str) == 0;242 eof_str_detected = (strcmp(s, eof_str) == 0); 265 243 } 266 244 if (!eof_str_detected) { 267 size_t lenght = (p - buf); 268 269 cur = xmalloc(sizeof(xlist_t) + lenght); 270 cur->data = memcpy(cur + 1, s, lenght); 271 cur->lenght = lenght; 245 size_t length = (p - buf); 246 /* Dont xzalloc - it can be quite big */ 247 cur = xmalloc(offsetof(xlist_t, xstr) + length); 272 248 cur->link = NULL; 249 cur->length = length; 250 memcpy(cur->xstr, s, length); 273 251 if (prev == NULL) { 274 252 list_arg = cur; … … 277 255 } 278 256 prev = cur; 279 line_l += leng ht;257 line_l += length; 280 258 if (line_l > mc) { 281 259 /* stop memory usage :-) */ … … 288 266 return list_arg; 289 267 } 290 #endif /* CONFIG_FEATURE_XARGS_SUPPORT_QUOTES */291 292 293 #if def CONFIG_FEATURE_XARGS_SUPPORT_CONFIRMATION268 #endif /* FEATURE_XARGS_SUPPORT_QUOTES */ 269 270 271 #if ENABLE_FEATURE_XARGS_SUPPORT_CONFIRMATION 294 272 /* Prompt the user for a response, and 295 273 if the user responds affirmatively, return true; 296 otherwise, return false. Use d"/dev/tty", not stdin. */274 otherwise, return false. Uses "/dev/tty", not stdin. */ 297 275 static int xargs_ask_confirmation(void) 298 276 { 299 staticFILE *tty_stream;277 FILE *tty_stream; 300 278 int c, savec; 301 279 302 if (!tty_stream) { 303 tty_stream = bb_xfopen(CURRENT_TTY, "r"); 304 /* pranoidal security by vodz */ 305 fcntl(fileno(tty_stream), F_SETFD, FD_CLOEXEC); 306 } 280 tty_stream = xfopen(CURRENT_TTY, "r"); 307 281 fputs(" ?...", stderr); 308 282 fflush(stderr); … … 310 284 while (c != EOF && c != '\n') 311 285 c = getc(tty_stream); 312 if (savec == 'y' || savec == 'Y') 313 return 1; 314 return 0; 315 } 316 317 # define OPT_INC_P 1 286 fclose(tty_stream); 287 return (savec == 'y' || savec == 'Y'); 288 } 318 289 #else 319 # define OPT_INC_P 0320 290 # define xargs_ask_confirmation() 1 321 #endif /* CONFIG_FEATURE_XARGS_SUPPORT_CONFIRMATION */ 322 323 #ifdef CONFIG_FEATURE_XARGS_SUPPORT_TERMOPT 324 # define OPT_INC_X 1 325 #else 326 # define OPT_INC_X 0 327 #endif 328 329 #ifdef CONFIG_FEATURE_XARGS_SUPPORT_ZERO_TERM 330 static xlist_t *process0_stdin(xlist_t * list_arg, const char *eof_str ATTRIBUTE_UNUSED, 331 size_t mc, char *buf) 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) 332 296 { 333 297 int c; /* current char */ … … 338 302 xlist_t *prev; 339 303 340 for (prev = cur = list_arg; cur; cur = cur->link) { 341 line_l += cur->lenght; /* previous allocated */ 342 if (prev != cur) 343 prev = prev->link; 304 prev = cur = list_arg; 305 while (1) { 306 if (!cur) break; 307 prev = cur; 308 line_l += cur->length; 309 cur = cur->link; 344 310 } 345 311 … … 347 313 c = getchar(); 348 314 if (c == EOF) { 349 eof_stdin_detected ++;315 eof_stdin_detected = 1; 350 316 if (s == NULL) 351 317 break; 352 c = 0;318 c = '\0'; 353 319 } 354 320 if (s == NULL) … … 357 323 bb_error_msg_and_die("argument line too long"); 358 324 *p++ = c; 359 if (c == 0) { /* word's delimiter or EOF detected */325 if (c == '\0') { /* word's delimiter or EOF detected */ 360 326 /* word loaded */ 361 size_t lenght = (p - buf); 362 363 cur = xmalloc(sizeof(xlist_t) + lenght); 364 cur->data = memcpy(cur + 1, s, lenght); 365 cur->lenght = lenght; 327 size_t length = (p - buf); 328 /* Dont xzalloc - it can be quite big */ 329 cur = xmalloc(offsetof(xlist_t, xstr) + length); 366 330 cur->link = NULL; 331 cur->length = length; 332 memcpy(cur->xstr, s, length); 367 333 if (prev == NULL) { 368 334 list_arg = cur; … … 371 337 } 372 338 prev = cur; 373 line_l += leng ht;339 line_l += length; 374 340 if (line_l > mc) { 375 341 /* stop memory usage :-) */ … … 381 347 return list_arg; 382 348 } 383 384 # define READ_ARGS(l, e, nmc, mc) (*read_args)(l, e, nmc, mc) 385 # define OPT_INC_0 1 /* future use */ 386 #else 387 # define OPT_INC_0 0 /* future use */ 388 # define READ_ARGS(l, e, nmc, mc) process_stdin(l, e, nmc, mc) 389 #endif /* CONFIG_FEATURE_XARGS_SUPPORT_ZERO_TERM */ 390 391 392 #define OPT_VERBOSE (1<<0) 393 #define OPT_NO_EMPTY (1<<1) 394 #define OPT_UPTO_NUMBER (1<<2) 395 #define OPT_UPTO_SIZE (1<<3) 396 #define OPT_EOF_STRING (1<<4) 397 #ifdef CONFIG_FEATURE_XARGS_SUPPORT_CONFIRMATION 398 #define OPT_INTERACTIVE (1<<5) 399 #else 400 #define OPT_INTERACTIVE (0) /* require for algorithm &| */ 401 #endif 402 #define OPT_TERMINATE (1<<(5+OPT_INC_P)) 403 #define OPT_ZEROTERM (1<<(5+OPT_INC_P+OPT_INC_X)) 404 /* next future 405 #define OPT_NEXT_OTHER (1<<(5+OPT_INC_P+OPT_INC_X+OPT_INC_0)) 406 */ 407 349 #endif /* FEATURE_XARGS_SUPPORT_ZERO_TERM */ 350 351 /* Correct regardless of combination of CONFIG_xxx */ 352 enum { 353 OPTBIT_VERBOSE = 0, 354 OPTBIT_NO_EMPTY, 355 OPTBIT_UPTO_NUMBER, 356 OPTBIT_UPTO_SIZE, 357 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, 370 }; 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); 408 377 int xargs_main(int argc, char **argv) 409 378 { 410 379 char **args; 411 int i, a,n;380 int i, n; 412 381 xlist_t *list = NULL; 413 382 xlist_t *cur; … … 418 387 long orig_arg_max; 419 388 const char *eof_str = "_"; 420 unsigned longopt;389 unsigned opt; 421 390 size_t n_max_chars; 422 423 #ifdef CONFIG_FEATURE_XARGS_SUPPORT_ZERO_TERM 424 xlist_t *(*read_args) (xlist_t *, const char *, size_t, char *) = process_stdin; 391 #if ENABLE_FEATURE_XARGS_SUPPORT_ZERO_TERM 392 xlist_t* (*read_args)(xlist_t*, const char*, size_t, char*) = process_stdin; 393 #else 394 #define read_args process_stdin 425 395 #endif 426 396 427 #ifdef CONFIG_FEATURE_XARGS_SUPPORT_CONFIRMATION 428 bb_opt_complementally = "pt"; 429 #endif 430 431 opt = bb_getopt_ulflags(argc, argv, "+trn:s:e::" 432 #ifdef CONFIG_FEATURE_XARGS_SUPPORT_CONFIRMATION 433 "p" 434 #endif 435 #ifdef CONFIG_FEATURE_XARGS_SUPPORT_TERMOPT 436 "x" 437 #endif 438 #ifdef CONFIG_FEATURE_XARGS_SUPPORT_ZERO_TERM 439 "0" 440 #endif 441 ,&max_args, &max_chars, &eof_str); 442 443 a = argc - optind; 397 opt = getopt32(argv, OPTION_STR, &max_args, &max_chars, &eof_str); 398 399 if (opt & OPT_ZEROTERM) 400 USE_FEATURE_XARGS_SUPPORT_ZERO_TERM(read_args = process0_stdin); 401 444 402 argv += optind; 445 if (a == 0) { 403 argc -= optind; 404 if (!argc) { 446 405 /* default behavior is to echo all the filenames */ 447 *argv = "echo";448 a ++;406 *argv = (char*)"echo"; 407 argc++; 449 408 } 450 409 … … 452 411 if (orig_arg_max == -1) 453 412 orig_arg_max = LONG_MAX; 454 orig_arg_max -= 2048; /* POSIX.2 requires subtracting 2048. */ 455 if ((opt & OPT_UPTO_SIZE)) { 456 n_max_chars = bb_xgetularg10_bnd(max_chars, 1, orig_arg_max); 457 for (i = 0; i < a; i++) { 413 orig_arg_max -= 2048; /* POSIX.2 requires subtracting 2048 */ 414 415 if (opt & OPT_UPTO_SIZE) { 416 n_max_chars = xatoul_range(max_chars, 1, orig_arg_max); 417 for (i = 0; i < argc; i++) { 458 418 n_chars += strlen(*argv) + 1; 459 419 } 460 420 if (n_max_chars < n_chars) { 461 bb_error_msg_and_die("can 421 bb_error_msg_and_die("cannot fit single argument within argument list size limit"); 462 422 } 463 423 n_max_chars -= n_chars; … … 473 433 max_chars = xmalloc(n_max_chars); 474 434 475 if ( (opt & OPT_UPTO_NUMBER)) {476 n_max_arg = bb_xgetularg10_bnd(max_args, 1, INT_MAX);435 if (opt & OPT_UPTO_NUMBER) { 436 n_max_arg = xatoul_range(max_args, 1, INT_MAX); 477 437 } else { 478 438 n_max_arg = n_max_chars; 479 439 } 480 440 481 #ifdef CONFIG_FEATURE_XARGS_SUPPORT_ZERO_TERM 482 if (opt & OPT_ZEROTERM) 483 read_args = process0_stdin; 484 #endif 485 486 while ((list = READ_ARGS(list, eof_str, n_max_chars, max_chars)) != NULL || 487 (opt & OPT_NO_EMPTY) == 0) 441 while ((list = read_args(list, eof_str, n_max_chars, max_chars)) != NULL || 442 !(opt & OPT_NO_EMPTY)) 488 443 { 489 444 opt |= OPT_NO_EMPTY; 490 445 n = 0; 491 446 n_chars = 0; 492 #if def CONFIG_FEATURE_XARGS_SUPPORT_TERMOPT447 #if ENABLE_FEATURE_XARGS_SUPPORT_TERMOPT 493 448 for (cur = list; cur;) { 494 n_chars += cur->leng ht;449 n_chars += cur->length; 495 450 n++; 496 451 cur = cur->link; … … 503 458 #else 504 459 for (cur = list; cur; cur = cur->link) { 505 n_chars += cur->leng ht;460 n_chars += cur->length; 506 461 n++; 507 462 if (n_chars > n_max_chars || n == n_max_arg) { … … 509 464 } 510 465 } 511 #endif /* CONFIG_FEATURE_XARGS_SUPPORT_TERMOPT */512 513 /* allocat ingpointers for execvp:514 a *arg, n*arg from stdin, NULL */515 args = x calloc(n + a + 1,sizeof(char *));516 517 /* Store the command to be executed466 #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 executed 518 473 (taken from the command line) */ 519 for (i = 0; i < a ; i++)474 for (i = 0; i < argc; i++) 520 475 args[i] = argv[i]; 521 476 /* (taken from stdin) */ 522 477 for (cur = list; n; cur = cur->link) { 523 args[i++] = cur-> data;478 args[i++] = cur->xstr; 524 479 n--; 525 480 } 526 481 527 if ( (opt & (OPT_INTERACTIVE | OPT_VERBOSE))) {482 if (opt & (OPT_INTERACTIVE | OPT_VERBOSE)) { 528 483 for (i = 0; args[i]; i++) { 529 484 if (i) … … 531 486 fputs(args[i], stderr); 532 487 } 533 if ( (opt & OPT_INTERACTIVE) == 0)488 if (!(opt & OPT_INTERACTIVE)) 534 489 fputc('\n', stderr); 535 490 } 536 if ( (opt & OPT_INTERACTIVE) == 0 || xargs_ask_confirmation() != 0) {491 if (!(opt & OPT_INTERACTIVE) || xargs_ask_confirmation()) { 537 492 child_error = xargs_exec(args); 538 493 } 539 494 540 495 /* clean up */ 541 for (i = a ; args[i]; i++) {496 for (i = argc; args[i]; i++) { 542 497 cur = list; 543 498 list = list->link; … … 549 504 } 550 505 } 551 #ifdef CONFIG_FEATURE_CLEAN_UP 552 free(max_chars); 553 #endif 506 if (ENABLE_FEATURE_CLEAN_UP) 507 free(max_chars); 554 508 return child_error; 555 509 } … … 558 512 #ifdef TEST 559 513 560 const char * bb_applet_name = "debug stuff usage";514 const char *applet_name = "debug stuff usage"; 561 515 562 516 void bb_show_usage(void) 563 517 { 564 518 fprintf(stderr, "Usage: %s [-p] [-r] [-t] -[x] [-n max_arg] [-s max_chars]\n", 565 bb_applet_name);519 applet_name); 566 520 exit(1); 567 521 }
Note:
See TracChangeset
for help on using the changeset viewer.