source: MondoRescue/branches/stable/mindi-busybox/findutils/xargs.c@ 1770

Last change on this file since 1770 was 1770, checked in by Bruno Cornec, 16 years ago
  • Better output for mindi-busybox revision
  • Remove dummy file created on NFS - report from Arnaud Tiger <arnaud.tiger_at_hp.com>
  • strace useful for debug
  • fix new versions for pb (2.0.0 for mindi and 1.7.2 for mindi-busybox)
  • fix build process for mindi-busybox + options used in that version (dd for label-partitions-as-necessary)
  • fix typo in label-partitions-as-necessary which doesn't seem to work
  • Update to busybox 1.7.2
  • perl is now required at restore time to support uuid swap partitions (and will be used for many other thigs

in the future for sure)

  • next mindi version will be 2.0.0 due to all the changes made in it (udev may break working distros)
  • small optimization in mindi on keyboard handling (one single find instead of multiple)
  • better interaction for USB device when launching mindi manually
  • attempt to automatically guess block disk size for ramdisk
  • fix typos in bkphw
  • Fix the remaining problem with UUID support for swap partitions
  • Updates mondoarchive man page for USB support
  • Adds preliminary Hardware support to mindi (Proliant SSSTK)
  • Tries to add udev support also for rhel4
  • Fix UUID support which was still broken.
  • Be conservative in test for the start-nfs script
  • Update config file for mindi-busybox for 1.7.2 migration
  • Try to run around a busybox bug (1.2.2 pb on inexistant links)
  • Add build content for mindi-busybox in pb
  • Remove distributions content for mindi-busybox
  • Fix a warning on inexistant raidtab
  • Solve problem on tmpfs in restore init (Problem of inexistant symlink and busybox)
  • Create MONDO_CACHE and use it everywhere + creation at start
  • Really never try to eject a USB device
  • Fix a issue with &> usage (replaced with 1> and 2>)
  • Adds magic file to depllist in order to have file working + ldd which helps for debugging issues
  • tty modes correct to avoid sh error messages
  • Use ext3 normally and not ext2 instead
  • USB device should be corrected after reading (take 1st part)
  • Adds a mount_USB_here function derived from mount_CDROM_here
  • usb detection place before /dev detection in device name at restore time
  • Fix when restoring from USB: media is asked in interactive mode
  • Adds USB support for mondorestore
  • mount_cdrom => mount_media
  • elilo.efi is now searched throughout /boot/efi and not in a fixed place as there is no standard
  • untar-and-softlink => untar (+ interface change)
  • suppress useless softlinks creation/removal in boot process
  • avoids udevd messages on groups
  • Increase # of disks to 99 as in mindi at restore time (should be a conf file parameter)
  • skip existing big file creation
  • seems to work correctly for USB mindi boot
  • Adds group and tty link to udev conf
  • Always load usb-torage (even 2.6) to initiate USB bus discovery
  • Better printing of messages
  • Attempt to fix a bug in supporting OpenSusE 10.3 kernel for initramfs (mindi may now use multiple regex for kernel initrd detection)
  • Links were not correctly done as non relative for modules in mindi
  • exclusion of modules denied now works
  • Also create modules in their ordinary place, so that classical modprobe works + copy modules.dep
  • Fix bugs for DENY_MODS handling
  • Add device /dev/console for udev
  • ide-generic should now really be excluded
  • Fix a bug in major number for tty
  • If udev then adds modprobe/insmod to rootfs
  • tty0 is also cretaed with udev
  • ide-generic put rather in DENY_MODS
  • udevd remove from deplist s handled in mindi directly
  • better default for mindi when using --usb
  • Handles dynamically linked busybox (in case we want to use it soon ;-)
  • Adds fixed devices to create for udev
  • ide-generic should not be part of the initrd when using libata v2
  • support a dynamically linked udev (case on Ubuntu 7.10 and Mandriva 2008.0 so should be quite generic) This will give incitation to move to dyn. linked binaries in the initrd which will help for other tasks (ia6 4)
  • Improvement in udev support (do not use cl options not available in busybox)
  • Udev in mindi
    • auto creation of the right links at boot time with udev-links.conf(from Mandriva 2008.0)
    • rework startup of udev as current makes kernel crash (from Mandriva 2008.0)
    • add support for 64 bits udev
  • Try to render MyInsmod silent at boot time
  • Adds udev support (mandatory for newest distributions to avoid remapping of devices in a different way as on the original system)
  • We also need vaft format support for USB boot
  • Adds libusual support (Ubuntu 7.10 needs it for USB)
  • Improve Ubuntu/Debian keyboard detection and support
  • pbinit adapted to new pb (0.8.10). Filtering of docs done in it
  • Suppress some mondo warnings and errors on USB again
  • Tries to fix lack of files in deb mindi package
  • Verify should now work for USB devices
  • More log/mesages improvement for USB support
  • - Supress g_erase_tmpdir_and_scratchdir
  • Improve some log messages for USB support
  • Try to improve install in mindi to avoid issues with isolinux.cfg not installed vene if in the pkg :-(
  • Improve mindi-busybox build
  • In conformity with pb 0.8.9
  • Add support for Ubuntu 7.10 in build process
  • Add USB Key button to Menu UI (CD streamer removed)
  • Attempt to fix error messages on tmp/scratch files at the end by removing those dir at the latest possible.
  • Fix a bug linked to the size of the -E param which could be used (Arnaud Tiger/René Ribaud).
  • Integrate ~/.pbrc content into mondorescue.pb (required project-builder >= 0.8.7)
  • Put mondorescue in conformity with new pb filtering rules
  • Add USB support at restore time (no test done yet). New start-usb script PB varibale added where useful
  • Unmounting USB device before removal of temporary scratchdir
  • Stil refining USB copy back to mondo (one command was not executed)
  • No need to have the image subdor in the csratchdir when USB.
  • umount the USB partition before attempting to use it
  • Remove useless copy from mindi to mondo at end of USB handling

(risky merge, we are raising the limits of 2 diverging branches. The status of stable is not completely sure as such. Will need lots of tests, but it's not yet done :-()
(merge -r1692:1769 $SVN_M/branches/2.2.5)

File size: 12.3 KB
Line 
1/* vi: set sw=4 ts=4: */
2/*
3 * Mini xargs implementation for busybox
4 * Options are supported: "-prtx -n max_arg -s max_chars -e[ouf_str]"
5 *
6 * (C) 2002,2003 by Vladimir Oleynik <dzo@simtreas.ru>
7 *
8 * Special thanks
9 * - Mark Whitley and Glenn McGrath for stimulus to rewrite :)
10 * - Mike Rendell <michael@cs.mun.ca>
11 * and David MacKenzie <djm@gnu.ai.mit.edu>.
12 *
13 * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
14 *
15 * xargs is described in the Single Unix Specification v3 at
16 * http://www.opengroup.org/onlinepubs/007904975/utilities/xargs.html
17 *
18 */
19
20#include "libbb.h"
21
22/* This is a NOEXEC applet. Be very careful! */
23
24
25/* COMPAT: SYSV version defaults size (and has a max value of) to 470.
26 We try to make it as large as possible. */
27#if !defined(ARG_MAX) && defined(_SC_ARG_MAX)
28#define ARG_MAX sysconf (_SC_ARG_MAX)
29#endif
30#ifndef ARG_MAX
31#define ARG_MAX 470
32#endif
33
34
35#ifdef TEST
36# ifndef ENABLE_FEATURE_XARGS_SUPPORT_CONFIRMATION
37# define ENABLE_FEATURE_XARGS_SUPPORT_CONFIRMATION 1
38# endif
39# ifndef ENABLE_FEATURE_XARGS_SUPPORT_QUOTES
40# define ENABLE_FEATURE_XARGS_SUPPORT_QUOTES 1
41# endif
42# ifndef ENABLE_FEATURE_XARGS_SUPPORT_TERMOPT
43# define ENABLE_FEATURE_XARGS_SUPPORT_TERMOPT 1
44# endif
45# ifndef ENABLE_FEATURE_XARGS_SUPPORT_ZERO_TERM
46# define ENABLE_FEATURE_XARGS_SUPPORT_ZERO_TERM 1
47# endif
48#endif
49
50/*
51 This function has special algorithm.
52 Don't use fork and include to main!
53*/
54static 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
85typedef struct xlist_t {
86 struct xlist_t *link;
87 size_t length;
88 char xstr[1];
89} xlist_t;
90
91static smallint eof_stdin_detected;
92
93#define ISBLANK(c) ((c) == ' ' || (c) == '\t')
94#define ISSPACE(c) (ISBLANK(c) || (c) == '\n' || (c) == '\r' \
95 || (c) == '\f' || (c) == '\v')
96
97#if ENABLE_FEATURE_XARGS_SUPPORT_QUOTES
98static xlist_t *process_stdin(xlist_t *list_arg,
99 const char *eof_str, size_t mc, char *buf)
100{
101#define NORM 0
102#define QUOTE 1
103#define BACKSLASH 2
104#define SPACE 4
105
106 char *s = NULL; /* start word */
107 char *p = NULL; /* pointer to end word */
108 char q = '\0'; /* quote char */
109 char state = NORM;
110 char eof_str_detected = 0;
111 size_t line_l = 0; /* size loaded args line */
112 int c; /* current char */
113 xlist_t *cur;
114 xlist_t *prev;
115
116 prev = cur = list_arg;
117 while (1) {
118 if (!cur) break;
119 prev = cur;
120 line_l += cur->length;
121 cur = cur->link;
122 }
123
124 while (!eof_stdin_detected) {
125 c = getchar();
126 if (c == EOF) {
127 eof_stdin_detected = 1;
128 if (s)
129 goto unexpected_eof;
130 break;
131 }
132 if (eof_str_detected)
133 continue;
134 if (state == BACKSLASH) {
135 state = NORM;
136 goto set;
137 } else if (state == QUOTE) {
138 if (c != q)
139 goto set;
140 q = '\0';
141 state = NORM;
142 } else { /* if (state == NORM) */
143 if (ISSPACE(c)) {
144 if (s) {
145 unexpected_eof:
146 state = SPACE;
147 c = '\0';
148 goto set;
149 }
150 } else {
151 if (s == NULL)
152 s = p = buf;
153 if (c == '\\') {
154 state = BACKSLASH;
155 } else if (c == '\'' || c == '"') {
156 q = c;
157 state = QUOTE;
158 } else {
159 set:
160 if ((size_t)(p - buf) >= mc)
161 bb_error_msg_and_die("argument line too long");
162 *p++ = c;
163 }
164 }
165 }
166 if (state == SPACE) { /* word's delimiter or EOF detected */
167 if (q) {
168 bb_error_msg_and_die("unmatched %s quote",
169 q == '\'' ? "single" : "double");
170 }
171 /* word loaded */
172 if (eof_str) {
173 eof_str_detected = (strcmp(s, eof_str) == 0);
174 }
175 if (!eof_str_detected) {
176 size_t length = (p - buf);
177 /* Dont xzalloc - it can be quite big */
178 cur = xmalloc(offsetof(xlist_t, xstr) + length);
179 cur->link = NULL;
180 cur->length = length;
181 memcpy(cur->xstr, s, length);
182 if (prev == NULL) {
183 list_arg = cur;
184 } else {
185 prev->link = cur;
186 }
187 prev = cur;
188 line_l += length;
189 if (line_l > mc) {
190 /* stop memory usage :-) */
191 break;
192 }
193 }
194 s = NULL;
195 state = NORM;
196 }
197 }
198 return list_arg;
199}
200#else
201/* The variant does not support single quotes, double quotes or backslash */
202static xlist_t *process_stdin(xlist_t *list_arg,
203 const char *eof_str, size_t mc, char *buf)
204{
205
206 int c; /* current char */
207 char eof_str_detected = 0;
208 char *s = NULL; /* start word */
209 char *p = NULL; /* pointer to end word */
210 size_t line_l = 0; /* size loaded args line */
211 xlist_t *cur;
212 xlist_t *prev;
213
214 prev = cur = list_arg;
215 while (1) {
216 if (!cur) break;
217 prev = cur;
218 line_l += cur->length;
219 cur = cur->link;
220 }
221
222 while (!eof_stdin_detected) {
223 c = getchar();
224 if (c == EOF) {
225 eof_stdin_detected = 1;
226 }
227 if (eof_str_detected)
228 continue;
229 if (c == EOF || ISSPACE(c)) {
230 if (s == NULL)
231 continue;
232 c = EOF;
233 }
234 if (s == NULL)
235 s = p = buf;
236 if ((p - buf) >= mc)
237 bb_error_msg_and_die("argument line too long");
238 *p++ = (c == EOF ? '\0' : c);
239 if (c == EOF) { /* word's delimiter or EOF detected */
240 /* word loaded */
241 if (eof_str) {
242 eof_str_detected = (strcmp(s, eof_str) == 0);
243 }
244 if (!eof_str_detected) {
245 size_t length = (p - buf);
246 /* Dont xzalloc - it can be quite big */
247 cur = xmalloc(offsetof(xlist_t, xstr) + length);
248 cur->link = NULL;
249 cur->length = length;
250 memcpy(cur->xstr, s, length);
251 if (prev == NULL) {
252 list_arg = cur;
253 } else {
254 prev->link = cur;
255 }
256 prev = cur;
257 line_l += length;
258 if (line_l > mc) {
259 /* stop memory usage :-) */
260 break;
261 }
262 s = NULL;
263 }
264 }
265 }
266 return list_arg;
267}
268#endif /* FEATURE_XARGS_SUPPORT_QUOTES */
269
270
271#if ENABLE_FEATURE_XARGS_SUPPORT_CONFIRMATION
272/* Prompt the user for a response, and
273 if the user responds affirmatively, return true;
274 otherwise, return false. Uses "/dev/tty", not stdin. */
275static int xargs_ask_confirmation(void)
276{
277 FILE *tty_stream;
278 int c, savec;
279
280 tty_stream = xfopen(CURRENT_TTY, "r");
281 fputs(" ?...", stderr);
282 fflush(stderr);
283 c = savec = getc(tty_stream);
284 while (c != EOF && c != '\n')
285 c = getc(tty_stream);
286 fclose(tty_stream);
287 return (savec == 'y' || savec == 'Y');
288}
289#else
290# define xargs_ask_confirmation() 1
291#endif /* FEATURE_XARGS_SUPPORT_CONFIRMATION */
292
293#if ENABLE_FEATURE_XARGS_SUPPORT_ZERO_TERM
294static xlist_t *process0_stdin(xlist_t *list_arg,
295 const char *eof_str ATTRIBUTE_UNUSED, size_t mc, char *buf)
296{
297 int c; /* current char */
298 char *s = NULL; /* start word */
299 char *p = NULL; /* pointer to end word */
300 size_t line_l = 0; /* size loaded args line */
301 xlist_t *cur;
302 xlist_t *prev;
303
304 prev = cur = list_arg;
305 while (1) {
306 if (!cur) break;
307 prev = cur;
308 line_l += cur->length;
309 cur = cur->link;
310 }
311
312 while (!eof_stdin_detected) {
313 c = getchar();
314 if (c == EOF) {
315 eof_stdin_detected = 1;
316 if (s == NULL)
317 break;
318 c = '\0';
319 }
320 if (s == NULL)
321 s = p = buf;
322 if ((size_t)(p - buf) >= mc)
323 bb_error_msg_and_die("argument line too long");
324 *p++ = c;
325 if (c == '\0') { /* word's delimiter or EOF detected */
326 /* word loaded */
327 size_t length = (p - buf);
328 /* Dont xzalloc - it can be quite big */
329 cur = xmalloc(offsetof(xlist_t, xstr) + length);
330 cur->link = NULL;
331 cur->length = length;
332 memcpy(cur->xstr, s, length);
333 if (prev == NULL) {
334 list_arg = cur;
335 } else {
336 prev->link = cur;
337 }
338 prev = cur;
339 line_l += length;
340 if (line_l > mc) {
341 /* stop memory usage :-) */
342 break;
343 }
344 s = NULL;
345 }
346 }
347 return list_arg;
348}
349#endif /* FEATURE_XARGS_SUPPORT_ZERO_TERM */
350
351/* Correct regardless of combination of CONFIG_xxx */
352enum {
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
376int xargs_main(int argc, char **argv);
377int xargs_main(int argc, char **argv)
378{
379 char **args;
380 int i, n;
381 xlist_t *list = NULL;
382 xlist_t *cur;
383 int child_error = 0;
384 char *max_args, *max_chars;
385 int n_max_arg;
386 size_t n_chars = 0;
387 long orig_arg_max;
388 const char *eof_str = "_";
389 unsigned opt;
390 size_t n_max_chars;
391#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
395#endif
396
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
402 argv += optind;
403 argc -= optind;
404 if (!argc) {
405 /* default behavior is to echo all the filenames */
406 *argv = (char*)"echo";
407 argc++;
408 }
409
410 orig_arg_max = ARG_MAX;
411 if (orig_arg_max == -1)
412 orig_arg_max = LONG_MAX;
413 orig_arg_max -= 2048; /* POSIX.2 requires subtracting 2048 */
414
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++) {
418 n_chars += strlen(*argv) + 1;
419 }
420 if (n_max_chars < n_chars) {
421 bb_error_msg_and_die("cannot fit single argument within argument list size limit");
422 }
423 n_max_chars -= n_chars;
424 } else {
425 /* Sanity check for systems with huge ARG_MAX defines (e.g., Suns which
426 have it at 1 meg). Things will work fine with a large ARG_MAX but it
427 will probably hurt the system more than it needs to; an array of this
428 size is allocated. */
429 if (orig_arg_max > 20 * 1024)
430 orig_arg_max = 20 * 1024;
431 n_max_chars = orig_arg_max;
432 }
433 max_chars = xmalloc(n_max_chars);
434
435 if (opt & OPT_UPTO_NUMBER) {
436 n_max_arg = xatoul_range(max_args, 1, INT_MAX);
437 } else {
438 n_max_arg = n_max_chars;
439 }
440
441 while ((list = read_args(list, eof_str, n_max_chars, max_chars)) != NULL ||
442 !(opt & OPT_NO_EMPTY))
443 {
444 opt |= OPT_NO_EMPTY;
445 n = 0;
446 n_chars = 0;
447#if ENABLE_FEATURE_XARGS_SUPPORT_TERMOPT
448 for (cur = list; cur;) {
449 n_chars += cur->length;
450 n++;
451 cur = cur->link;
452 if (n_chars > n_max_chars || (n == n_max_arg && cur)) {
453 if (opt & OPT_TERMINATE)
454 bb_error_msg_and_die("argument list too long");
455 break;
456 }
457 }
458#else
459 for (cur = list; cur; cur = cur->link) {
460 n_chars += cur->length;
461 n++;
462 if (n_chars > n_max_chars || n == n_max_arg) {
463 break;
464 }
465 }
466#endif /* FEATURE_XARGS_SUPPORT_TERMOPT */
467
468 /* allocate pointers for execvp:
469 argc*arg, n*arg from stdin, NULL */
470 args = xzalloc((n + argc + 1) * sizeof(char *));
471
472 /* store the command to be executed
473 (taken from the command line) */
474 for (i = 0; i < argc; i++)
475 args[i] = argv[i];
476 /* (taken from stdin) */
477 for (cur = list; n; cur = cur->link) {
478 args[i++] = cur->xstr;
479 n--;
480 }
481
482 if (opt & (OPT_INTERACTIVE | OPT_VERBOSE)) {
483 for (i = 0; args[i]; i++) {
484 if (i)
485 fputc(' ', stderr);
486 fputs(args[i], stderr);
487 }
488 if (!(opt & OPT_INTERACTIVE))
489 fputc('\n', stderr);
490 }
491 if (!(opt & OPT_INTERACTIVE) || xargs_ask_confirmation()) {
492 child_error = xargs_exec(args);
493 }
494
495 /* clean up */
496 for (i = argc; args[i]; i++) {
497 cur = list;
498 list = list->link;
499 free(cur);
500 }
501 free(args);
502 if (child_error > 0 && child_error != 123) {
503 break;
504 }
505 }
506 if (ENABLE_FEATURE_CLEAN_UP)
507 free(max_chars);
508 return child_error;
509}
510
511
512#ifdef TEST
513
514const char *applet_name = "debug stuff usage";
515
516void bb_show_usage(void)
517{
518 fprintf(stderr, "Usage: %s [-p] [-r] [-t] -[x] [-n max_arg] [-s max_chars]\n",
519 applet_name);
520 exit(1);
521}
522
523int main(int argc, char **argv)
524{
525 return xargs_main(argc, argv);
526}
527#endif /* TEST */
Note: See TracBrowser for help on using the repository browser.