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

Last change on this file since 1770 was 1770, checked in by Bruno Cornec, 13 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.