diff options
author | Nguyễn Thái Ngọc Duy <pclouds@gmail.com> | 2010-09-14 12:56:34 +1000 |
---|---|---|
committer | Nguyễn Thái Ngọc Duy <pclouds@gmail.com> | 2010-09-14 12:56:34 +1000 |
commit | c31744ca1a86b2276c37c6d9a884660185debed6 (patch) | |
tree | bb051c35c3430a3793ceef173a01cb522fb4ae05 /findutils | |
parent | 1a286d510c2125bdab601ce47afd4d27b6ce6f41 (diff) | |
parent | e329089c62ed813e97344f8c61d7dc34221fd5ee (diff) | |
download | busybox-w32-c31744ca1a86b2276c37c6d9a884660185debed6.tar.gz busybox-w32-c31744ca1a86b2276c37c6d9a884660185debed6.tar.bz2 busybox-w32-c31744ca1a86b2276c37c6d9a884660185debed6.zip |
Merge branch 'origin/master' (early part)
Diffstat (limited to 'findutils')
-rw-r--r-- | findutils/find.c | 90 | ||||
-rw-r--r-- | findutils/grep.c | 63 | ||||
-rw-r--r-- | findutils/xargs.c | 519 |
3 files changed, 398 insertions, 274 deletions
diff --git a/findutils/find.c b/findutils/find.c index ca630b6c5..297081489 100644 --- a/findutils/find.c +++ b/findutils/find.c | |||
@@ -53,8 +53,10 @@ | |||
53 | * diff -u /tmp/std_find /tmp/bb_find && echo Identical | 53 | * diff -u /tmp/std_find /tmp/bb_find && echo Identical |
54 | */ | 54 | */ |
55 | 55 | ||
56 | //applet:IF_FIND(APPLET_NOEXEC(find, find, _BB_DIR_USR_BIN, _BB_SUID_DROP, find)) | ||
57 | |||
56 | //kbuild:lib-$(CONFIG_FIND) += find.o | 58 | //kbuild:lib-$(CONFIG_FIND) += find.o |
57 | //config: | 59 | |
58 | //config:config FIND | 60 | //config:config FIND |
59 | //config: bool "find" | 61 | //config: bool "find" |
60 | //config: default y | 62 | //config: default y |
@@ -1044,6 +1046,92 @@ static action*** parse_params(char **argv) | |||
1044 | #undef ALLOC_ACTION | 1046 | #undef ALLOC_ACTION |
1045 | } | 1047 | } |
1046 | 1048 | ||
1049 | //usage:#define find_trivial_usage | ||
1050 | //usage: "[PATH]... [EXPRESSION]" | ||
1051 | //usage:#define find_full_usage "\n\n" | ||
1052 | //usage: "Search for files. The default PATH is the current directory,\n" | ||
1053 | //usage: "default EXPRESSION is '-print'\n" | ||
1054 | //usage: "\nEXPRESSION may consist of:" | ||
1055 | //usage: "\n -follow Follow symlinks" | ||
1056 | //usage: IF_FEATURE_FIND_XDEV( | ||
1057 | //usage: "\n -xdev Don't descend directories on other filesystems" | ||
1058 | //usage: ) | ||
1059 | //usage: IF_FEATURE_FIND_MAXDEPTH( | ||
1060 | //usage: "\n -maxdepth N Descend at most N levels. -maxdepth 0 applies" | ||
1061 | //usage: "\n tests/actions to command line arguments only" | ||
1062 | //usage: ) | ||
1063 | //usage: "\n -mindepth N Don't act on first N levels" | ||
1064 | //usage: "\n -name PATTERN File name (w/o directory name) matches PATTERN" | ||
1065 | //usage: "\n -iname PATTERN Case insensitive -name" | ||
1066 | //usage: IF_FEATURE_FIND_PATH( | ||
1067 | //usage: "\n -path PATTERN Path matches PATTERN" | ||
1068 | //usage: ) | ||
1069 | //usage: IF_FEATURE_FIND_REGEX( | ||
1070 | //usage: "\n -regex PATTERN Path matches regex PATTERN" | ||
1071 | //usage: ) | ||
1072 | //usage: IF_FEATURE_FIND_TYPE( | ||
1073 | //usage: "\n -type X File type is X (X is one of: f,d,l,b,c,...)" | ||
1074 | //usage: ) | ||
1075 | //usage: IF_FEATURE_FIND_PERM( | ||
1076 | //usage: "\n -perm NNN Permissions match any of (+NNN), all of (-NNN)," | ||
1077 | //usage: "\n or exactly NNN" | ||
1078 | //usage: ) | ||
1079 | //usage: IF_FEATURE_FIND_MTIME( | ||
1080 | //usage: "\n -mtime DAYS Modified time is greater than (+N), less than (-N)," | ||
1081 | //usage: "\n or exactly N days" | ||
1082 | //usage: ) | ||
1083 | //usage: IF_FEATURE_FIND_MMIN( | ||
1084 | //usage: "\n -mmin MINS Modified time is greater than (+N), less than (-N)," | ||
1085 | //usage: "\n or exactly N minutes" | ||
1086 | //usage: ) | ||
1087 | //usage: IF_FEATURE_FIND_NEWER( | ||
1088 | //usage: "\n -newer FILE Modified time is more recent than FILE's" | ||
1089 | //usage: ) | ||
1090 | //usage: IF_FEATURE_FIND_INUM( | ||
1091 | //usage: "\n -inum N File has inode number N" | ||
1092 | //usage: ) | ||
1093 | //usage: IF_FEATURE_FIND_USER( | ||
1094 | //usage: "\n -user NAME File is owned by user NAME (numeric user ID allowed)" | ||
1095 | //usage: ) | ||
1096 | //usage: IF_FEATURE_FIND_GROUP( | ||
1097 | //usage: "\n -group NAME File belongs to group NAME (numeric group ID allowed)" | ||
1098 | //usage: ) | ||
1099 | //usage: IF_FEATURE_FIND_DEPTH( | ||
1100 | //usage: "\n -depth Process directory name after traversing it" | ||
1101 | //usage: ) | ||
1102 | //usage: IF_FEATURE_FIND_SIZE( | ||
1103 | //usage: "\n -size N[bck] File size is N (c:bytes,k:kbytes,b:512 bytes(def.))" | ||
1104 | //usage: "\n +/-N: file size is bigger/smaller than N" | ||
1105 | //usage: ) | ||
1106 | //usage: IF_FEATURE_FIND_LINKS( | ||
1107 | //usage: "\n -links N Number of links is greater than (+N), less than (-N)," | ||
1108 | //usage: "\n or exactly N" | ||
1109 | //usage: ) | ||
1110 | //usage: "\n -print Print (default and assumed)" | ||
1111 | //usage: IF_FEATURE_FIND_PRINT0( | ||
1112 | //usage: "\n -print0 Delimit output with null characters rather than" | ||
1113 | //usage: "\n newlines" | ||
1114 | //usage: ) | ||
1115 | //usage: IF_FEATURE_FIND_CONTEXT( | ||
1116 | //usage: "\n -context File has specified security context" | ||
1117 | //usage: ) | ||
1118 | //usage: IF_FEATURE_FIND_EXEC( | ||
1119 | //usage: "\n -exec CMD ARG ; Run CMD with all instances of {} replaced by the" | ||
1120 | //usage: "\n matching files" | ||
1121 | //usage: ) | ||
1122 | //usage: IF_FEATURE_FIND_PRUNE( | ||
1123 | //usage: "\n -prune Stop traversing current subtree" | ||
1124 | //usage: ) | ||
1125 | //usage: IF_FEATURE_FIND_DELETE( | ||
1126 | //usage: "\n -delete Delete files, turns on -depth option" | ||
1127 | //usage: ) | ||
1128 | //usage: IF_FEATURE_FIND_PAREN( | ||
1129 | //usage: "\n (EXPR) Group an expression" | ||
1130 | //usage: ) | ||
1131 | //usage: | ||
1132 | //usage:#define find_example_usage | ||
1133 | //usage: "$ find / -name passwd\n" | ||
1134 | //usage: "/etc/passwd\n" | ||
1047 | 1135 | ||
1048 | int find_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 1136 | int find_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
1049 | int find_main(int argc UNUSED_PARAM, char **argv) | 1137 | int find_main(int argc UNUSED_PARAM, char **argv) |
diff --git a/findutils/grep.c b/findutils/grep.c index fedf12d8a..9eb5e5a1b 100644 --- a/findutils/grep.c +++ b/findutils/grep.c | |||
@@ -14,13 +14,16 @@ | |||
14 | * 2004,2006 (C) Vladimir Oleynik <dzo@simtreas.ru> - | 14 | * 2004,2006 (C) Vladimir Oleynik <dzo@simtreas.ru> - |
15 | * correction "-e pattern1 -e pattern2" logic and more optimizations. | 15 | * correction "-e pattern1 -e pattern2" logic and more optimizations. |
16 | * precompiled regex | 16 | * precompiled regex |
17 | */ | 17 | * |
18 | /* | ||
19 | * (C) 2006 Jac Goudsmit added -o option | 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 | |||
22 | //kbuild:lib-$(CONFIG_GREP) += grep.o | 25 | //kbuild:lib-$(CONFIG_GREP) += grep.o |
23 | //config: | 26 | |
24 | //config:config GREP | 27 | //config:config GREP |
25 | //config: bool "grep" | 28 | //config: bool "grep" |
26 | //config: default y | 29 | //config: default y |
@@ -57,17 +60,67 @@ | |||
57 | #include "libbb.h" | 60 | #include "libbb.h" |
58 | #include "xregex.h" | 61 | #include "xregex.h" |
59 | 62 | ||
63 | |||
60 | /* options */ | 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 | |||
61 | #define OPTSTR_GREP \ | 116 | #define OPTSTR_GREP \ |
62 | "lnqvscFiHhe:f:Lorm:w" \ | 117 | "lnqvscFiHhe:f:Lorm:w" \ |
63 | IF_FEATURE_GREP_CONTEXT("A:B:C:") \ | 118 | IF_FEATURE_GREP_CONTEXT("A:B:C:") \ |
64 | IF_FEATURE_GREP_EGREP_ALIAS("E") \ | 119 | IF_FEATURE_GREP_EGREP_ALIAS("E") \ |
65 | IF_EXTRA_COMPAT("z") \ | 120 | IF_EXTRA_COMPAT("z") \ |
66 | "aI" | 121 | "aI" |
67 | |||
68 | /* ignored: -a "assume all files to be text" */ | 122 | /* ignored: -a "assume all files to be text" */ |
69 | /* ignored: -I "assume binary files have no matches" */ | 123 | /* ignored: -I "assume binary files have no matches" */ |
70 | |||
71 | enum { | 124 | enum { |
72 | OPTBIT_l, /* list matched file names only */ | 125 | OPTBIT_l, /* list matched file names only */ |
73 | OPTBIT_n, /* print line# */ | 126 | OPTBIT_n, /* print line# */ |
diff --git a/findutils/xargs.c b/findutils/xargs.c index 9133b8f6c..46a62cbf1 100644 --- a/findutils/xargs.c +++ b/findutils/xargs.c | |||
@@ -1,7 +1,6 @@ | |||
1 | /* vi: set sw=4 ts=4: */ | 1 | /* vi: set sw=4 ts=4: */ |
2 | /* | 2 | /* |
3 | * Mini xargs implementation for busybox | 3 | * Mini xargs implementation for busybox |
4 | * Options are supported: "-prtx -n max_arg -s max_chars -e[ouf_str]" | ||
5 | * | 4 | * |
6 | * (C) 2002,2003 by Vladimir Oleynik <dzo@simtreas.ru> | 5 | * (C) 2002,2003 by Vladimir Oleynik <dzo@simtreas.ru> |
7 | * | 6 | * |
@@ -14,11 +13,12 @@ | |||
14 | * | 13 | * |
15 | * xargs is described in the Single Unix Specification v3 at | 14 | * xargs is described in the Single Unix Specification v3 at |
16 | * http://www.opengroup.org/onlinepubs/007904975/utilities/xargs.html | 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 | 20 | //kbuild:lib-$(CONFIG_XARGS) += xargs.o |
21 | //config: | 21 | |
22 | //config:config XARGS | 22 | //config:config XARGS |
23 | //config: bool "xargs" | 23 | //config: bool "xargs" |
24 | //config: default y | 24 | //config: default y |
@@ -59,10 +59,6 @@ | |||
59 | //config: are not special. | 59 | //config: are not special. |
60 | 60 | ||
61 | #include "libbb.h" | 61 | #include "libbb.h" |
62 | |||
63 | /* This is a NOEXEC applet. Be very careful! */ | ||
64 | |||
65 | |||
66 | /* COMPAT: SYSV version defaults size (and has a max value of) to 470. | 62 | /* COMPAT: SYSV version defaults size (and has a max value of) to 470. |
67 | We try to make it as large as possible. */ | 63 | We try to make it as large as possible. */ |
68 | #if !defined(ARG_MAX) && defined(_SC_ARG_MAX) | 64 | #if !defined(ARG_MAX) && defined(_SC_ARG_MAX) |
@@ -72,6 +68,12 @@ | |||
72 | # define ARG_MAX 470 | 68 | # define ARG_MAX 470 |
73 | #endif | 69 | #endif |
74 | 70 | ||
71 | /* This is a NOEXEC applet. Be very careful! */ | ||
72 | |||
73 | |||
74 | //#define dbg_msg(...) bb_error_msg(__VA_ARGS__) | ||
75 | #define dbg_msg(...) ((void)0) | ||
76 | |||
75 | 77 | ||
76 | #ifdef TEST | 78 | #ifdef TEST |
77 | # ifndef ENABLE_FEATURE_XARGS_SUPPORT_CONFIRMATION | 79 | # ifndef ENABLE_FEATURE_XARGS_SUPPORT_CONFIRMATION |
@@ -88,26 +90,36 @@ | |||
88 | # endif | 90 | # endif |
89 | #endif | 91 | #endif |
90 | 92 | ||
93 | |||
94 | struct globals { | ||
95 | char **args; | ||
96 | const char *eof_str; | ||
97 | int idx; | ||
98 | } FIX_ALIASING; | ||
99 | #define G (*(struct globals*)&bb_common_bufsiz1) | ||
100 | #define INIT_G() do { } while (0) | ||
101 | |||
102 | |||
91 | /* | 103 | /* |
92 | This function has special algorithm. | 104 | * This function has special algorithm. |
93 | Don't use fork and include to main! | 105 | * Don't use fork and include to main! |
94 | */ | 106 | */ |
95 | static int xargs_exec(char **args) | 107 | static int xargs_exec(void) |
96 | { | 108 | { |
97 | int status; | 109 | int status; |
98 | 110 | ||
99 | status = spawn_and_wait(args); | 111 | status = spawn_and_wait(G.args); |
100 | if (status < 0) { | 112 | if (status < 0) { |
101 | bb_simple_perror_msg(args[0]); | 113 | bb_simple_perror_msg(G.args[0]); |
102 | return errno == ENOENT ? 127 : 126; | 114 | return errno == ENOENT ? 127 : 126; |
103 | } | 115 | } |
104 | if (status == 255) { | 116 | if (status == 255) { |
105 | bb_error_msg("%s: exited with status 255; aborting", args[0]); | 117 | bb_error_msg("%s: exited with status 255; aborting", G.args[0]); |
106 | return 124; | 118 | return 124; |
107 | } | 119 | } |
108 | if (status >= 0x180) { | 120 | if (status >= 0x180) { |
109 | bb_error_msg("%s: terminated by signal %d", | 121 | bb_error_msg("%s: terminated by signal %d", |
110 | args[0], status - 0x180); | 122 | G.args[0], status - 0x180); |
111 | return 125; | 123 | return 125; |
112 | } | 124 | } |
113 | if (status) | 125 | if (status) |
@@ -115,75 +127,75 @@ static int xargs_exec(char **args) | |||
115 | return 0; | 127 | return 0; |
116 | } | 128 | } |
117 | 129 | ||
130 | /* In POSIX/C locale isspace is only these chars: "\t\n\v\f\r" and space. | ||
131 | * "\t\n\v\f\r" happen to have ASCII codes 9,10,11,12,13. | ||
132 | */ | ||
133 | #define ISSPACE(a) ({ unsigned char xargs__isspace = (a) - 9; xargs__isspace == (' ' - 9) || xargs__isspace <= (13 - 9); }) | ||
118 | 134 | ||
119 | typedef struct xlist_t { | 135 | static void store_param(char *s) |
120 | struct xlist_t *link; | 136 | { |
121 | size_t length; | 137 | /* Grow by 256 elements at once */ |
122 | char xstr[1]; | 138 | if (!(G.idx & 0xff)) { /* G.idx == N*256 */ |
123 | } xlist_t; | 139 | /* Enlarge, make G.args[(N+1)*256 - 1] last valid idx */ |
124 | 140 | G.args = xrealloc(G.args, sizeof(G.args[0]) * (G.idx + 0x100)); | |
125 | static smallint eof_stdin_detected; | 141 | } |
142 | G.args[G.idx++] = s; | ||
143 | } | ||
126 | 144 | ||
127 | #define ISBLANK(c) ((c) == ' ' || (c) == '\t') | 145 | /* process[0]_stdin: |
128 | #define ISSPACE(c) (ISBLANK(c) || (c) == '\n' || (c) == '\r' \ | 146 | * Read characters into buf[n_max_chars+1], and when parameter delimiter |
129 | || (c) == '\f' || (c) == '\v') | 147 | * is seen, store the address of a new parameter to args[]. |
148 | * If reading discovers that last chars do not form the complete | ||
149 | * parameter, the pointer to the first such "tail character" is returned. | ||
150 | * (buf has extra byte at the end to accomodate terminating NUL | ||
151 | * of "tail characters" string). | ||
152 | * Otherwise, the returned pointer points to NUL byte. | ||
153 | * On entry, buf[] may contain some "seed chars" which are to become | ||
154 | * the beginning of the first parameter. | ||
155 | */ | ||
130 | 156 | ||
131 | #if ENABLE_FEATURE_XARGS_SUPPORT_QUOTES | 157 | #if ENABLE_FEATURE_XARGS_SUPPORT_QUOTES |
132 | static xlist_t *process_stdin(xlist_t *list_arg, | 158 | static char* FAST_FUNC process_stdin(int n_max_chars, int n_max_arg, char *buf) |
133 | const char *eof_str, size_t mc, char *buf) | ||
134 | { | 159 | { |
135 | #define NORM 0 | 160 | #define NORM 0 |
136 | #define QUOTE 1 | 161 | #define QUOTE 1 |
137 | #define BACKSLASH 2 | 162 | #define BACKSLASH 2 |
138 | #define SPACE 4 | 163 | #define SPACE 4 |
139 | 164 | char q = '\0'; /* quote char */ | |
140 | char *s = NULL; /* start word */ | ||
141 | char *p = NULL; /* pointer to end word */ | ||
142 | char q = '\0'; /* quote char */ | ||
143 | char state = NORM; | 165 | char state = NORM; |
144 | char eof_str_detected = 0; | 166 | char *s = buf; /* start of the word */ |
145 | size_t line_l = 0; /* size loaded args line */ | 167 | char *p = s + strlen(buf); /* end of the word */ |
146 | int c; /* current char */ | ||
147 | xlist_t *cur; | ||
148 | xlist_t *prev; | ||
149 | 168 | ||
150 | prev = cur = list_arg; | 169 | buf += n_max_chars; /* past buffer's end */ |
151 | while (1) { | 170 | |
152 | if (!cur) break; | 171 | /* "goto ret" is used instead of "break" to make control flow |
153 | prev = cur; | 172 | * more obvious: */ |
154 | line_l += cur->length; | ||
155 | cur = cur->link; | ||
156 | } | ||
157 | 173 | ||
158 | while (!eof_stdin_detected) { | 174 | while (1) { |
159 | c = getchar(); | 175 | int c = getchar(); |
160 | if (c == EOF) { | 176 | if (c == EOF) { |
161 | eof_stdin_detected = 1; | 177 | if (p != s) |
162 | if (s) | 178 | goto close_word; |
163 | goto unexpected_eof; | 179 | goto ret; |
164 | break; | ||
165 | } | 180 | } |
166 | if (eof_str_detected) | ||
167 | continue; | ||
168 | if (state == BACKSLASH) { | 181 | if (state == BACKSLASH) { |
169 | state = NORM; | 182 | state = NORM; |
170 | goto set; | 183 | goto set; |
171 | } else if (state == QUOTE) { | 184 | } |
185 | if (state == QUOTE) { | ||
172 | if (c != q) | 186 | if (c != q) |
173 | goto set; | 187 | goto set; |
174 | q = '\0'; | 188 | q = '\0'; |
175 | state = NORM; | 189 | state = NORM; |
176 | } else { /* if (state == NORM) */ | 190 | } else { /* if (state == NORM) */ |
177 | if (ISSPACE(c)) { | 191 | if (ISSPACE(c)) { |
178 | if (s) { | 192 | if (p != s) { |
179 | unexpected_eof: | 193 | close_word: |
180 | state = SPACE; | 194 | state = SPACE; |
181 | c = '\0'; | 195 | c = '\0'; |
182 | goto set; | 196 | goto set; |
183 | } | 197 | } |
184 | } else { | 198 | } else { |
185 | if (s == NULL) | ||
186 | s = p = buf; | ||
187 | if (c == '\\') { | 199 | if (c == '\\') { |
188 | state = BACKSLASH; | 200 | state = BACKSLASH; |
189 | } else if (c == '\'' || c == '"') { | 201 | } else if (c == '\'' || c == '"') { |
@@ -191,8 +203,6 @@ static xlist_t *process_stdin(xlist_t *list_arg, | |||
191 | state = QUOTE; | 203 | state = QUOTE; |
192 | } else { | 204 | } else { |
193 | set: | 205 | set: |
194 | if ((size_t)(p - buf) >= mc) | ||
195 | bb_error_msg_and_die("argument line too long"); | ||
196 | *p++ = c; | 206 | *p++ = c; |
197 | } | 207 | } |
198 | } | 208 | } |
@@ -202,105 +212,122 @@ static xlist_t *process_stdin(xlist_t *list_arg, | |||
202 | bb_error_msg_and_die("unmatched %s quote", | 212 | bb_error_msg_and_die("unmatched %s quote", |
203 | q == '\'' ? "single" : "double"); | 213 | q == '\'' ? "single" : "double"); |
204 | } | 214 | } |
205 | /* word loaded */ | 215 | /* A full word is loaded */ |
206 | if (eof_str) { | 216 | if (G.eof_str) { |
207 | eof_str_detected = (strcmp(s, eof_str) == 0); | 217 | if (strcmp(s, G.eof_str) == 0) { |
208 | } | 218 | while (getchar() != EOF) |
209 | if (!eof_str_detected) { | 219 | continue; |
210 | size_t length = (p - buf); | 220 | p = s; |
211 | /* Dont xzalloc - it can be quite big */ | 221 | goto ret; |
212 | cur = xmalloc(offsetof(xlist_t, xstr) + length); | ||
213 | cur->link = NULL; | ||
214 | cur->length = length; | ||
215 | memcpy(cur->xstr, s, length); | ||
216 | if (prev == NULL) { | ||
217 | list_arg = cur; | ||
218 | } else { | ||
219 | prev->link = cur; | ||
220 | } | ||
221 | prev = cur; | ||
222 | line_l += length; | ||
223 | if (line_l > mc) { | ||
224 | /* stop memory usage :-) */ | ||
225 | break; | ||
226 | } | 222 | } |
227 | } | 223 | } |
228 | s = NULL; | 224 | store_param(s); |
225 | dbg_msg("args[]:'%s'", s); | ||
226 | s = p; | ||
227 | n_max_arg--; | ||
228 | if (n_max_arg == 0) { | ||
229 | goto ret; | ||
230 | } | ||
229 | state = NORM; | 231 | state = NORM; |
230 | } | 232 | } |
233 | if (p == buf) { | ||
234 | goto ret; | ||
235 | } | ||
231 | } | 236 | } |
232 | return list_arg; | 237 | ret: |
238 | *p = '\0'; | ||
239 | /* store_param(NULL) - caller will do it */ | ||
240 | dbg_msg("return:'%s'", s); | ||
241 | return s; | ||
233 | } | 242 | } |
234 | #else | 243 | #else |
235 | /* The variant does not support single quotes, double quotes or backslash */ | 244 | /* The variant does not support single quotes, double quotes or backslash */ |
236 | static xlist_t *process_stdin(xlist_t *list_arg, | 245 | static char* FAST_FUNC process_stdin(int n_max_chars, int n_max_arg, char *buf) |
237 | const char *eof_str, size_t mc, char *buf) | ||
238 | { | 246 | { |
247 | char *s = buf; /* start of the word */ | ||
248 | char *p = s + strlen(buf); /* end of the word */ | ||
239 | 249 | ||
240 | int c; /* current char */ | 250 | buf += n_max_chars; /* past buffer's end */ |
241 | char eof_str_detected = 0; | ||
242 | char *s = NULL; /* start word */ | ||
243 | char *p = NULL; /* pointer to end word */ | ||
244 | size_t line_l = 0; /* size loaded args line */ | ||
245 | xlist_t *cur; | ||
246 | xlist_t *prev; | ||
247 | 251 | ||
248 | prev = cur = list_arg; | ||
249 | while (1) { | 252 | while (1) { |
250 | if (!cur) break; | 253 | int c = getchar(); |
251 | prev = cur; | ||
252 | line_l += cur->length; | ||
253 | cur = cur->link; | ||
254 | } | ||
255 | |||
256 | while (!eof_stdin_detected) { | ||
257 | c = getchar(); | ||
258 | if (c == EOF) { | 254 | if (c == EOF) { |
259 | eof_stdin_detected = 1; | 255 | if (p == s) |
256 | goto ret; | ||
260 | } | 257 | } |
261 | if (eof_str_detected) | ||
262 | continue; | ||
263 | if (c == EOF || ISSPACE(c)) { | 258 | if (c == EOF || ISSPACE(c)) { |
264 | if (s == NULL) | 259 | if (p == s) |
265 | continue; | 260 | continue; |
266 | c = EOF; | 261 | c = EOF; |
267 | } | 262 | } |
268 | if (s == NULL) | ||
269 | s = p = buf; | ||
270 | if ((size_t)(p - buf) >= mc) | ||
271 | bb_error_msg_and_die("argument line too long"); | ||
272 | *p++ = (c == EOF ? '\0' : c); | 263 | *p++ = (c == EOF ? '\0' : c); |
273 | if (c == EOF) { /* word's delimiter or EOF detected */ | 264 | if (c == EOF) { /* word's delimiter or EOF detected */ |
274 | /* word loaded */ | 265 | /* A full word is loaded */ |
275 | if (eof_str) { | 266 | if (G.eof_str) { |
276 | eof_str_detected = (strcmp(s, eof_str) == 0); | 267 | if (strcmp(s, G.eof_str) == 0) { |
277 | } | 268 | while (getchar() != EOF) |
278 | if (!eof_str_detected) { | 269 | continue; |
279 | size_t length = (p - buf); | 270 | p = s; |
280 | /* Dont xzalloc - it can be quite big */ | 271 | goto ret; |
281 | cur = xmalloc(offsetof(xlist_t, xstr) + length); | ||
282 | cur->link = NULL; | ||
283 | cur->length = length; | ||
284 | memcpy(cur->xstr, s, length); | ||
285 | if (prev == NULL) { | ||
286 | list_arg = cur; | ||
287 | } else { | ||
288 | prev->link = cur; | ||
289 | } | 272 | } |
290 | prev = cur; | ||
291 | line_l += length; | ||
292 | if (line_l > mc) { | ||
293 | /* stop memory usage :-) */ | ||
294 | break; | ||
295 | } | ||
296 | s = NULL; | ||
297 | } | 273 | } |
274 | store_param(s); | ||
275 | dbg_msg("args[]:'%s'", s); | ||
276 | s = p; | ||
277 | n_max_arg--; | ||
278 | if (n_max_arg == 0) { | ||
279 | goto ret; | ||
280 | } | ||
281 | } | ||
282 | if (p == buf) { | ||
283 | goto ret; | ||
298 | } | 284 | } |
299 | } | 285 | } |
300 | return list_arg; | 286 | ret: |
287 | *p = '\0'; | ||
288 | /* store_param(NULL) - caller will do it */ | ||
289 | dbg_msg("return:'%s'", s); | ||
290 | return s; | ||
301 | } | 291 | } |
302 | #endif /* FEATURE_XARGS_SUPPORT_QUOTES */ | 292 | #endif /* FEATURE_XARGS_SUPPORT_QUOTES */ |
303 | 293 | ||
294 | #if ENABLE_FEATURE_XARGS_SUPPORT_ZERO_TERM | ||
295 | static char* FAST_FUNC process0_stdin(int n_max_chars, int n_max_arg, char *buf) | ||
296 | { | ||
297 | char *s = buf; /* start of the word */ | ||
298 | char *p = s + strlen(buf); /* end of the word */ | ||
299 | |||
300 | buf += n_max_chars; /* past buffer's end */ | ||
301 | |||
302 | while (1) { | ||
303 | int c = getchar(); | ||
304 | if (c == EOF) { | ||
305 | if (p == s) | ||
306 | goto ret; | ||
307 | c = '\0'; | ||
308 | } | ||
309 | *p++ = c; | ||
310 | if (c == '\0') { /* word's delimiter or EOF detected */ | ||
311 | /* A full word is loaded */ | ||
312 | store_param(s); | ||
313 | dbg_msg("args[]:'%s'", s); | ||
314 | s = p; | ||
315 | n_max_arg--; | ||
316 | if (n_max_arg == 0) { | ||
317 | goto ret; | ||
318 | } | ||
319 | } | ||
320 | if (p == buf) { | ||
321 | goto ret; | ||
322 | } | ||
323 | } | ||
324 | ret: | ||
325 | *p = '\0'; | ||
326 | /* store_param(NULL) - caller will do it */ | ||
327 | dbg_msg("return:'%s'", s); | ||
328 | return s; | ||
329 | } | ||
330 | #endif /* FEATURE_XARGS_SUPPORT_ZERO_TERM */ | ||
304 | 331 | ||
305 | #if ENABLE_FEATURE_XARGS_SUPPORT_CONFIRMATION | 332 | #if ENABLE_FEATURE_XARGS_SUPPORT_CONFIRMATION |
306 | /* Prompt the user for a response, and | 333 | /* Prompt the user for a response, and |
@@ -322,65 +349,30 @@ static int xargs_ask_confirmation(void) | |||
322 | } | 349 | } |
323 | #else | 350 | #else |
324 | # define xargs_ask_confirmation() 1 | 351 | # define xargs_ask_confirmation() 1 |
325 | #endif /* FEATURE_XARGS_SUPPORT_CONFIRMATION */ | 352 | #endif |
326 | |||
327 | #if ENABLE_FEATURE_XARGS_SUPPORT_ZERO_TERM | ||
328 | static xlist_t *process0_stdin(xlist_t *list_arg, | ||
329 | const char *eof_str UNUSED_PARAM, size_t mc, char *buf) | ||
330 | { | ||
331 | int c; /* current char */ | ||
332 | char *s = NULL; /* start word */ | ||
333 | char *p = NULL; /* pointer to end word */ | ||
334 | size_t line_l = 0; /* size loaded args line */ | ||
335 | xlist_t *cur; | ||
336 | xlist_t *prev; | ||
337 | |||
338 | prev = cur = list_arg; | ||
339 | while (1) { | ||
340 | if (!cur) break; | ||
341 | prev = cur; | ||
342 | line_l += cur->length; | ||
343 | cur = cur->link; | ||
344 | } | ||
345 | 353 | ||
346 | while (!eof_stdin_detected) { | 354 | //usage:#define xargs_trivial_usage |
347 | c = getchar(); | 355 | //usage: "[OPTIONS] [PROG ARGS]" |
348 | if (c == EOF) { | 356 | //usage:#define xargs_full_usage "\n\n" |
349 | eof_stdin_detected = 1; | 357 | //usage: "Run PROG on every item given by stdin\n" |
350 | if (s == NULL) | 358 | //usage: "\nOptions:" |
351 | break; | 359 | //usage: IF_FEATURE_XARGS_SUPPORT_CONFIRMATION( |
352 | c = '\0'; | 360 | //usage: "\n -p Ask user whether to run each command" |
353 | } | 361 | //usage: ) |
354 | if (s == NULL) | 362 | //usage: "\n -r Don't run command if input is empty" |
355 | s = p = buf; | 363 | //usage: IF_FEATURE_XARGS_SUPPORT_ZERO_TERM( |
356 | if ((size_t)(p - buf) >= mc) | 364 | //usage: "\n -0 Input is separated by NUL characters" |
357 | bb_error_msg_and_die("argument line too long"); | 365 | //usage: ) |
358 | *p++ = c; | 366 | //usage: "\n -t Print the command on stderr before execution" |
359 | if (c == '\0') { /* word's delimiter or EOF detected */ | 367 | //usage: "\n -e[STR] STR stops input processing" |
360 | /* word loaded */ | 368 | //usage: "\n -n N Pass no more than N args to PROG" |
361 | size_t length = (p - buf); | 369 | //usage: "\n -s N Pass command line of no more than N bytes" |
362 | /* Dont xzalloc - it can be quite big */ | 370 | //usage: IF_FEATURE_XARGS_SUPPORT_TERMOPT( |
363 | cur = xmalloc(offsetof(xlist_t, xstr) + length); | 371 | //usage: "\n -x Exit if size is exceeded" |
364 | cur->link = NULL; | 372 | //usage: ) |
365 | cur->length = length; | 373 | //usage:#define xargs_example_usage |
366 | memcpy(cur->xstr, s, length); | 374 | //usage: "$ ls | xargs gzip\n" |
367 | if (prev == NULL) { | 375 | //usage: "$ find . -name '*.c' -print | xargs rm\n" |
368 | list_arg = cur; | ||
369 | } else { | ||
370 | prev->link = cur; | ||
371 | } | ||
372 | prev = cur; | ||
373 | line_l += length; | ||
374 | if (line_l > mc) { | ||
375 | /* stop memory usage :-) */ | ||
376 | break; | ||
377 | } | ||
378 | s = NULL; | ||
379 | } | ||
380 | } | ||
381 | return list_arg; | ||
382 | } | ||
383 | #endif /* FEATURE_XARGS_SUPPORT_ZERO_TERM */ | ||
384 | 376 | ||
385 | /* Correct regardless of combination of CONFIG_xxx */ | 377 | /* Correct regardless of combination of CONFIG_xxx */ |
386 | enum { | 378 | enum { |
@@ -412,44 +404,42 @@ enum { | |||
412 | int xargs_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 404 | int xargs_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
413 | int xargs_main(int argc, char **argv) | 405 | int xargs_main(int argc, char **argv) |
414 | { | 406 | { |
415 | char **args; | 407 | int i; |
416 | int i, n; | ||
417 | xlist_t *list = NULL; | ||
418 | xlist_t *cur; | ||
419 | int child_error = 0; | 408 | int child_error = 0; |
420 | char *max_args, *max_chars; | 409 | char *max_args; |
421 | int n_max_arg; | 410 | char *max_chars; |
422 | const char *eof_str = NULL; | 411 | char *buf; |
423 | unsigned opt; | 412 | unsigned opt; |
424 | size_t n_max_chars; | 413 | int n_max_chars; |
414 | int n_max_arg; | ||
425 | #if ENABLE_FEATURE_XARGS_SUPPORT_ZERO_TERM | 415 | #if ENABLE_FEATURE_XARGS_SUPPORT_ZERO_TERM |
426 | xlist_t* (*read_args)(xlist_t*, const char*, size_t, char*) = process_stdin; | 416 | char* FAST_FUNC (*read_args)(int, int, char*) = process_stdin; |
427 | #else | 417 | #else |
428 | #define read_args process_stdin | 418 | #define read_args process_stdin |
429 | #endif | 419 | #endif |
430 | 420 | ||
431 | opt = getopt32(argv, OPTION_STR, &max_args, &max_chars, &eof_str, &eof_str); | 421 | INIT_G(); |
422 | |||
423 | G.eof_str = NULL; | ||
424 | opt = getopt32(argv, OPTION_STR, &max_args, &max_chars, &G.eof_str, &G.eof_str); | ||
432 | 425 | ||
433 | /* -E ""? You may wonder why not just omit -E? | 426 | /* -E ""? You may wonder why not just omit -E? |
434 | * This is used for portability: | 427 | * This is used for portability: |
435 | * old xargs was using "_" as default for -E / -e */ | 428 | * old xargs was using "_" as default for -E / -e */ |
436 | if ((opt & OPT_EOF_STRING1) && eof_str[0] == '\0') | 429 | if ((opt & OPT_EOF_STRING1) && G.eof_str[0] == '\0') |
437 | eof_str = NULL; | 430 | G.eof_str = NULL; |
438 | 431 | ||
439 | if (opt & OPT_ZEROTERM) | 432 | if (opt & OPT_ZEROTERM) |
440 | IF_FEATURE_XARGS_SUPPORT_ZERO_TERM(read_args = process0_stdin); | 433 | IF_FEATURE_XARGS_SUPPORT_ZERO_TERM(read_args = process0_stdin); |
441 | 434 | ||
442 | argv += optind; | 435 | argv += optind; |
443 | argc -= optind; | 436 | argc -= optind; |
444 | if (!argc) { | 437 | if (!argv[0]) { |
445 | /* default behavior is to echo all the filenames */ | 438 | /* default behavior is to echo all the filenames */ |
446 | *argv = (char*)"echo"; | 439 | *--argv = (char*)"echo"; |
447 | argc++; | 440 | argc++; |
448 | } | 441 | } |
449 | 442 | ||
450 | n_max_chars = ARG_MAX; /* might be calling sysconf(_SC_ARG_MAX) */ | ||
451 | if (n_max_chars < 4*1024); /* paranoia */ | ||
452 | n_max_chars = LONG_MAX; | ||
453 | /* The Open Group Base Specifications Issue 6: | 443 | /* The Open Group Base Specifications Issue 6: |
454 | * "The xargs utility shall limit the command line length such that | 444 | * "The xargs utility shall limit the command line length such that |
455 | * when the command line is invoked, the combined argument | 445 | * when the command line is invoked, the combined argument |
@@ -457,101 +447,94 @@ int xargs_main(int argc, char **argv) | |||
457 | * in the System Interfaces volume of IEEE Std 1003.1-2001) | 447 | * in the System Interfaces volume of IEEE Std 1003.1-2001) |
458 | * shall not exceed {ARG_MAX}-2048 bytes". | 448 | * shall not exceed {ARG_MAX}-2048 bytes". |
459 | */ | 449 | */ |
450 | n_max_chars = ARG_MAX; /* might be calling sysconf(_SC_ARG_MAX) */ | ||
451 | if (n_max_chars < 4*1024); /* paranoia */ | ||
452 | n_max_chars = 4*1024; | ||
460 | n_max_chars -= 2048; | 453 | n_max_chars -= 2048; |
461 | /* Sanity check for systems with huge ARG_MAX defines (e.g., Suns which | 454 | /* Sanity check for systems with huge ARG_MAX defines (e.g., Suns which |
462 | * have it at 1 meg). Things will work fine with a large ARG_MAX but it | 455 | * have it at 1 meg). Things will work fine with a large ARG_MAX |
463 | * will probably hurt the system more than it needs to; an array of this | 456 | * but it will probably hurt the system more than it needs to; |
464 | * size is allocated. | 457 | * an array of this size is allocated. |
465 | */ | 458 | */ |
466 | if (n_max_chars > 20 * 1024) | 459 | if (n_max_chars > 20 * 1024) |
467 | n_max_chars = 20 * 1024; | 460 | n_max_chars = 20 * 1024; |
468 | 461 | ||
469 | if (opt & OPT_UPTO_SIZE) { | 462 | if (opt & OPT_UPTO_SIZE) { |
470 | size_t n_chars = 0; | 463 | size_t n_chars = 0; |
471 | n_max_chars = xatoul_range(max_chars, 1, n_max_chars); | 464 | n_max_chars = xatou_range(max_chars, 1, INT_MAX); |
472 | for (i = 0; i < argc; i++) { | 465 | for (i = 0; argv[i]; i++) { |
473 | n_chars += strlen(*argv) + 1; | 466 | n_chars += strlen(argv[i]) + 1; |
474 | } | 467 | } |
475 | if (n_max_chars <= n_chars) { | 468 | n_max_chars -= n_chars; |
469 | if (n_max_chars <= 0) { | ||
476 | bb_error_msg_and_die("can't fit single argument within argument list size limit"); | 470 | bb_error_msg_and_die("can't fit single argument within argument list size limit"); |
477 | } | 471 | } |
478 | n_max_chars -= n_chars; | ||
479 | } | 472 | } |
480 | max_chars = xmalloc(n_max_chars); | ||
481 | 473 | ||
474 | buf = xzalloc(n_max_chars + 1); | ||
475 | |||
476 | n_max_arg = n_max_chars; | ||
482 | if (opt & OPT_UPTO_NUMBER) { | 477 | if (opt & OPT_UPTO_NUMBER) { |
483 | n_max_arg = xatoul_range(max_args, 1, INT_MAX); | 478 | n_max_arg = xatou_range(max_args, 1, INT_MAX); |
484 | } else { | ||
485 | n_max_arg = n_max_chars; | ||
486 | } | 479 | } |
487 | 480 | ||
488 | while ((list = read_args(list, eof_str, n_max_chars, max_chars)) != NULL || | 481 | /* Allocate pointers for execvp */ |
489 | !(opt & OPT_NO_EMPTY)) | 482 | /* We can statically allocate (argc + n_max_arg + 1) elements |
490 | { | 483 | * and do not bother with resizing args[], but on 64-bit machines |
491 | size_t n_chars = 0; | 484 | * this results in args[] vector which is ~8 times bigger |
492 | opt |= OPT_NO_EMPTY; | 485 | * than n_max_chars! That is, with n_max_chars == 20k, |
493 | n = 0; | 486 | * args[] will take 160k (!), which will most likely be |
494 | #if ENABLE_FEATURE_XARGS_SUPPORT_TERMOPT | 487 | * almost entirely unused. |
495 | for (cur = list; cur;) { | 488 | */ |
496 | n_chars += cur->length; | 489 | /* See store_param() for matching 256-step growth logic */ |
497 | n++; | 490 | G.args = xmalloc(sizeof(G.args[0]) * ((argc + 0xff) & ~0xff)); |
498 | cur = cur->link; | 491 | |
499 | if (n_chars > n_max_chars || (n == n_max_arg && cur)) { | 492 | /* Store the command to be executed, part 1 */ |
500 | if (opt & OPT_TERMINATE) | 493 | for (i = 0; argv[i]; i++) |
501 | bb_error_msg_and_die("argument list too long"); | 494 | G.args[i] = argv[i]; |
502 | break; | 495 | |
503 | } | 496 | while (1) { |
504 | } | 497 | char *rem; |
505 | #else | 498 | |
506 | for (cur = list; cur; cur = cur->link) { | 499 | G.idx = argc; |
507 | n_chars += cur->length; | 500 | rem = read_args(n_max_chars, n_max_arg, buf); |
508 | n++; | 501 | store_param(NULL); |
509 | if (n_chars > n_max_chars || n == n_max_arg) { | 502 | |
503 | if (!G.args[argc]) { | ||
504 | if (*rem != '\0') | ||
505 | bb_error_msg_and_die("argument line too long"); | ||
506 | if (opt & OPT_NO_EMPTY) | ||
510 | break; | 507 | break; |
511 | } | ||
512 | } | ||
513 | #endif /* FEATURE_XARGS_SUPPORT_TERMOPT */ | ||
514 | |||
515 | /* allocate pointers for execvp: | ||
516 | argc*arg, n*arg from stdin, NULL */ | ||
517 | args = xzalloc((n + argc + 1) * sizeof(char *)); | ||
518 | |||
519 | /* store the command to be executed | ||
520 | (taken from the command line) */ | ||
521 | for (i = 0; i < argc; i++) | ||
522 | args[i] = argv[i]; | ||
523 | /* (taken from stdin) */ | ||
524 | for (cur = list; n; cur = cur->link) { | ||
525 | args[i++] = cur->xstr; | ||
526 | n--; | ||
527 | } | 508 | } |
509 | opt |= OPT_NO_EMPTY; | ||
528 | 510 | ||
529 | if (opt & (OPT_INTERACTIVE | OPT_VERBOSE)) { | 511 | if (opt & (OPT_INTERACTIVE | OPT_VERBOSE)) { |
512 | const char *fmt = " %s" + 1; | ||
513 | char **args = G.args; | ||
530 | for (i = 0; args[i]; i++) { | 514 | for (i = 0; args[i]; i++) { |
531 | if (i) | 515 | fprintf(stderr, fmt, args[i]); |
532 | bb_putchar_stderr(' '); | 516 | fmt = " %s"; |
533 | fputs(args[i], stderr); | ||
534 | } | 517 | } |
535 | if (!(opt & OPT_INTERACTIVE)) | 518 | if (!(opt & OPT_INTERACTIVE)) |
536 | bb_putchar_stderr('\n'); | 519 | bb_putchar_stderr('\n'); |
537 | } | 520 | } |
521 | |||
538 | if (!(opt & OPT_INTERACTIVE) || xargs_ask_confirmation()) { | 522 | if (!(opt & OPT_INTERACTIVE) || xargs_ask_confirmation()) { |
539 | child_error = xargs_exec(args); | 523 | child_error = xargs_exec(); |
540 | } | 524 | } |
541 | 525 | ||
542 | /* clean up */ | ||
543 | for (i = argc; args[i]; i++) { | ||
544 | cur = list; | ||
545 | list = list->link; | ||
546 | free(cur); | ||
547 | } | ||
548 | free(args); | ||
549 | if (child_error > 0 && child_error != 123) { | 526 | if (child_error > 0 && child_error != 123) { |
550 | break; | 527 | break; |
551 | } | 528 | } |
529 | |||
530 | overlapping_strcpy(buf, rem); | ||
552 | } /* while */ | 531 | } /* while */ |
553 | if (ENABLE_FEATURE_CLEAN_UP) | 532 | |
554 | free(max_chars); | 533 | if (ENABLE_FEATURE_CLEAN_UP) { |
534 | free(G.args); | ||
535 | free(buf); | ||
536 | } | ||
537 | |||
555 | return child_error; | 538 | return child_error; |
556 | } | 539 | } |
557 | 540 | ||