Added -delete action (Savannah patch #3454 with additions)
[findutils.git] / xargs / xargs.c
blobe7281d8c25ba0e1f74002819de61927d9161ee87
1 /* xargs -- build and execute command lines from standard input
2 Copyright (C) 1990, 91, 92, 93, 94, 2000,2003 Free Software Foundation, Inc.
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2, or (at your option)
7 any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
17 USA.
20 /* Written by Mike Rendell <michael@cs.mun.ca>
21 and David MacKenzie <djm@gnu.ai.mit.edu>. */
23 #include <config.h>
25 # ifndef PARAMS
26 # if defined PROTOTYPES || (defined __STDC__ && __STDC__)
27 # define PARAMS(Args) Args
28 # else
29 # define PARAMS(Args) ()
30 # endif
31 # endif
33 #include <ctype.h>
35 #if !defined (isascii) || defined (STDC_HEADERS)
36 #ifdef isascii
37 #undef isascii
38 #endif
39 #define isascii(c) 1
40 #endif
42 #ifdef isblank
43 #define ISBLANK(c) (isascii (c) && isblank (c))
44 #else
45 #define ISBLANK(c) ((c) == ' ' || (c) == '\t')
46 #endif
48 #define ISSPACE(c) (ISBLANK (c) || (c) == '\n' || (c) == '\r' \
49 || (c) == '\f' || (c) == '\v')
51 #include <sys/types.h>
52 #include <stdio.h>
53 #include <errno.h>
54 #include <getopt.h>
55 #include <fcntl.h>
57 #if defined(HAVE_STRING_H) || defined(STDC_HEADERS)
58 #include <string.h>
59 #if !defined(STDC_HEADERS)
60 #include <memory.h>
61 #endif
62 #else
63 #include <strings.h>
64 #define memcpy(dest, source, count) (bcopy((source), (dest), (count)))
65 #endif
67 #ifndef _POSIX_SOURCE
68 #include <sys/param.h>
69 #endif
71 #ifdef HAVE_LIMITS_H
72 #include <limits.h>
73 #endif
75 #ifndef LONG_MAX
76 #define LONG_MAX (~(1 << (sizeof (long) * 8 - 1)))
77 #endif
79 #ifdef HAVE_UNISTD_H
80 #include <unistd.h>
81 #endif
83 #include <signal.h>
85 #if !defined(SIGCHLD) && defined(SIGCLD)
86 #define SIGCHLD SIGCLD
87 #endif
89 /* COMPAT: SYSV version defaults size (and has a max value of) to 470.
90 We try to make it as large as possible. */
91 #if !defined(ARG_MAX) && defined(_SC_ARG_MAX)
92 #define ARG_MAX sysconf (_SC_ARG_MAX)
93 #endif
94 #ifndef ARG_MAX
95 #define ARG_MAX NCARGS
96 #endif
98 #include "wait.h"
100 /* States for read_line. */
101 #define NORM 0
102 #define SPACE 1
103 #define QUOTE 2
104 #define BACKSLASH 3
106 #ifdef STDC_HEADERS
107 #include <stdlib.h>
108 #else
109 extern int errno;
110 #endif
112 #ifdef HAVE_LOCALE_H
113 #include <locale.h>
114 #endif
115 #if ENABLE_NLS
116 # include <libintl.h>
117 # define _(Text) gettext (Text)
118 #else
119 # define _(Text) Text
120 #define textdomain(Domain)
121 #define bindtextdomain(Package, Directory)
122 #endif
123 #ifdef gettext_noop
124 # define N_(String) gettext_noop (String)
125 #else
126 /* See locate.c for explanation as to why not use (String) */
127 # define N_(String) String
128 #endif
130 /* Return nonzero if S is the EOF string. */
131 #define EOF_STR(s) (eof_str && *eof_str == *s && !strcmp (eof_str, s))
133 extern char **environ;
135 /* Do multibyte processing if multibyte characters are supported,
136 unless multibyte sequences are search safe. Multibyte sequences
137 are search safe if searching for a substring using the byte
138 comparison function 'strstr' gives no false positives. All 8-bit
139 encodings and the UTF-8 multibyte encoding are search safe, but
140 the EUC encodings are not.
141 BeOS uses the UTF-8 encoding exclusively, so it is search safe. */
142 #if defined __BEOS__
143 # define MULTIBYTE_IS_SEARCH_SAFE 1
144 #endif
145 #define DO_MULTIBYTE (HAVE_MBLEN && ! MULTIBYTE_IS_SEARCH_SAFE)
147 #if DO_MULTIBYTE
148 # if HAVE_MBRLEN
149 # include <wchar.h>
150 # else
151 /* Simulate mbrlen with mblen as best we can. */
152 # define mbstate_t int
153 # define mbrlen(s, n, ps) mblen (s, n)
154 # endif
155 #endif
157 /* Not char because of type promotion; NeXT gcc can't handle it. */
158 typedef int boolean;
159 #define true 1
160 #define false 0
162 #if __STDC__
163 #define VOID void
164 #else
165 #define VOID char
166 #endif
168 #include <xalloc.h>
169 void error PARAMS ((int status, int errnum, char *message,...));
171 extern char *version_string;
173 /* The name this program was run with. */
174 char *program_name;
176 /* Buffer for reading arguments from stdin. */
177 static char *linebuf;
179 /* Line number in stdin since the last command was executed. */
180 static int lineno = 0;
182 /* If nonzero, then instead of putting the args from stdin at
183 the end of the command argument list, they are each stuck into the
184 initial args, replacing each occurrence of the `replace_pat' in the
185 initial args. */
186 static char *replace_pat = NULL;
188 /* The length of `replace_pat'. */
189 static size_t rplen = 0;
191 /* If nonzero, when this string is read on stdin it is treated as
192 end of file.
193 I don't like this - it should default to NULL. */
194 static char *eof_str = "_";
196 /* If nonzero, the maximum number of nonblank lines from stdin to use
197 per command line. */
198 static long lines_per_exec = 0;
200 /* The maximum number of arguments to use per command line. */
201 static long args_per_exec = 1024;
203 /* If true, exit if lines_per_exec or args_per_exec is exceeded. */
204 static boolean exit_if_size_exceeded = false;
206 /* The maximum number of characters that can be used per command line. */
207 static long arg_max;
209 /* Storage for elements of `cmd_argv'. */
210 static char *argbuf;
212 /* The list of args being built. */
213 static char **cmd_argv = NULL;
215 /* Number of elements allocated for `cmd_argv'. */
216 static int cmd_argv_alloc = 0;
218 /* Number of valid elements in `cmd_argv'. */
219 static int cmd_argc = 0;
221 /* Number of chars being used in `cmd_argv'. */
222 static int cmd_argv_chars = 0;
224 /* Number of initial arguments given on the command line. */
225 static int initial_argc = 0;
227 /* Number of chars in the initial args. */
228 static int initial_argv_chars = 0;
230 /* true when building up initial arguments in `cmd_argv'. */
231 static boolean initial_args = true;
233 /* If nonzero, the maximum number of child processes that can be running
234 at once. */
235 static int proc_max = 1;
237 /* Total number of child processes that have been executed. */
238 static int procs_executed = 0;
240 /* The number of elements in `pids'. */
241 static int procs_executing = 0;
243 /* List of child processes currently executing. */
244 static pid_t *pids = NULL;
246 /* The number of allocated elements in `pids'. */
247 static int pids_alloc = 0;
249 /* Exit status; nonzero if any child process exited with a
250 status of 1-125. */
251 static int child_error = 0;
253 /* If true, print each command on stderr before executing it. */
254 static boolean print_command = false;
256 /* If true, query the user before executing each command, and only
257 execute the command if the user responds affirmatively. */
258 static boolean query_before_executing = false;
260 static struct option const longopts[] =
262 {"null", no_argument, NULL, '0'},
263 {"eof", optional_argument, NULL, 'e'},
264 {"replace", optional_argument, NULL, 'i'},
265 {"max-lines", optional_argument, NULL, 'l'},
266 {"max-args", required_argument, NULL, 'n'},
267 {"interactive", no_argument, NULL, 'p'},
268 {"no-run-if-empty", no_argument, NULL, 'r'},
269 {"max-chars", required_argument, NULL, 's'},
270 {"verbose", no_argument, NULL, 't'},
271 {"exit", no_argument, NULL, 'x'},
272 {"max-procs", required_argument, NULL, 'P'},
273 {"version", no_argument, NULL, 'v'},
274 {"help", no_argument, NULL, 'h'},
275 {NULL, no_argument, NULL, 0}
278 static int read_line PARAMS ((void));
279 static int read_string PARAMS ((void));
280 static char *mbstrstr PARAMS ((const char *haystack, const char *needle));
281 static void do_insert PARAMS ((char *arg, size_t arglen, size_t lblen));
282 static void push_arg PARAMS ((char *arg, size_t len));
283 static boolean print_args PARAMS ((boolean ask));
284 static void do_exec PARAMS ((void));
285 static void add_proc PARAMS ((pid_t pid));
286 static void wait_for_proc PARAMS ((boolean all));
287 static long parse_num PARAMS ((char *str, int option, long min, long max));
288 static long env_size PARAMS ((char **envp));
289 static void usage PARAMS ((FILE * stream));
292 main (int argc, char **argv)
294 int optc;
295 int always_run_command = 1;
296 long orig_arg_max;
297 long arg_size;
298 long size_of_environment = env_size(environ);
299 char *default_cmd = "/bin/echo";
300 int (*read_args) PARAMS ((void)) = read_line;
302 program_name = argv[0];
304 #ifdef HAVE_SETLOCALE
305 setlocale (LC_ALL, "");
306 #endif
307 bindtextdomain (PACKAGE, LOCALEDIR);
308 textdomain (PACKAGE);
310 orig_arg_max = ARG_MAX;
311 if (orig_arg_max == -1)
312 orig_arg_max = LONG_MAX;
313 orig_arg_max -= 2048; /* POSIX.2 requires subtracting 2048. */
314 arg_max = orig_arg_max;
316 arg_size = 20 * 1048 + size_of_environment;
319 /* Take the size of the environment into account. */
320 arg_max -= env_size (environ);
321 if (arg_max <= 0)
322 error (1, 0, _("environment is too large for exec"));
324 while ((optc = getopt_long (argc, argv, "+0e::i::l::n:prs:txP:",
325 longopts, (int *) 0)) != -1)
327 switch (optc)
329 case '0':
330 read_args = read_string;
331 break;
333 case 'e':
334 if (optarg)
335 eof_str = optarg;
336 else
337 eof_str = 0;
338 break;
340 case 'h':
341 usage (stdout);
342 return 0;
344 case 'i':
345 if (optarg)
346 replace_pat = optarg;
347 else
348 replace_pat = "{}";
349 /* -i excludes -n -l. */
350 args_per_exec = 0;
351 lines_per_exec = 0;
352 break;
354 case 'l':
355 if (optarg)
356 lines_per_exec = parse_num (optarg, 'l', 1L, -1L);
357 else
358 lines_per_exec = 1;
359 /* -l excludes -i -n. */
360 args_per_exec = 0;
361 replace_pat = NULL;
362 break;
364 case 'n':
365 args_per_exec = parse_num (optarg, 'n', 1L, -1L);
366 /* -n excludes -i -l. */
367 lines_per_exec = 0;
368 if (args_per_exec == 1 && replace_pat)
369 /* ignore -n1 in '-i -n1' */
370 args_per_exec = 0;
371 else
372 replace_pat = NULL;
373 break;
375 case 's':
376 arg_size = parse_num (optarg, 's', 1L, orig_arg_max);
377 break;
379 case 't':
380 print_command = true;
381 break;
383 case 'x':
384 exit_if_size_exceeded = true;
385 break;
387 case 'p':
388 query_before_executing = true;
389 print_command = true;
390 break;
392 case 'r':
393 always_run_command = 0;
394 break;
396 case 'P':
397 proc_max = parse_num (optarg, 'P', 0L, -1L);
398 break;
400 case 'v':
401 printf (_("GNU xargs version %s\n"), version_string);
402 return 0;
404 default:
405 usage (stderr);
406 return 1;
410 if (replace_pat || lines_per_exec)
411 exit_if_size_exceeded = true;
413 if (optind == argc)
415 optind = 0;
416 argc = 1;
417 argv = &default_cmd;
420 /* Taking into account the sisze of the environment,
421 * figure out how large a buffer we need to
422 * hold all the arguments. We cannot use ARG_MAX
423 * directly since that may be arbitrarily large.
424 * This is from a patch by Bob Prolux, <bob@proulx.com>.
426 if (arg_max > arg_size)
428 arg_max = arg_size;
431 linebuf = (char *) xmalloc (arg_max + 1);
432 argbuf = (char *) xmalloc (arg_max + 1);
434 /* Make sure to listen for the kids. */
435 signal (SIGCHLD, SIG_DFL);
437 if (!replace_pat)
439 for (; optind < argc; optind++)
440 push_arg (argv[optind], strlen (argv[optind]) + 1);
441 initial_args = false;
442 initial_argc = cmd_argc;
443 initial_argv_chars = cmd_argv_chars;
445 while ((*read_args) () != -1)
446 if (lines_per_exec && lineno >= lines_per_exec)
448 do_exec ();
449 lineno = 0;
452 /* SYSV xargs seems to do at least one exec, even if the
453 input is empty. */
454 if (cmd_argc != initial_argc
455 || (always_run_command && procs_executed == 0))
456 do_exec ();
458 else
460 int i;
461 size_t len;
462 size_t *arglen = (size_t *) xmalloc (sizeof (size_t) * argc);
464 for (i = optind; i < argc; i++)
465 arglen[i] = strlen(argv[i]);
466 rplen = strlen (replace_pat);
467 while ((len = (*read_args) ()) != -1)
469 /* Don't do insert on the command name. */
470 push_arg (argv[optind], arglen[optind] + 1);
471 len--;
472 for (i = optind + 1; i < argc; i++)
473 do_insert (argv[i], arglen[i], len);
474 do_exec ();
478 wait_for_proc (true);
479 return child_error;
482 #if 0
483 static int
484 append_char_to_buf(char **pbuf, char **pend, char **pp, int c)
486 char *end_of_buffer = *pend;
487 char *start_of_buffer = *pbuf;
488 char *p = *pp;
489 if (p >= end_of_buffer)
491 if (replace_pat)
493 size_t len = end_of_buffer - start_of_buffer;
494 size_t offset = p - start_of_buffer;
495 len *= 2;
496 start_of_buffer = xrealloc(start_of_buffer, len*2);
497 if (NULL != start_of_buffer)
499 end_of_buffer = start_of_buffer + len;
500 p = start_of_buffer + offset;
501 *p++ = c;
503 /* Update the caller's idea of where the buffer is. */
504 *pbuf = start_of_buffer;
505 *pend = end_of_buffer;
506 *pp = p;
508 return 0;
510 else
512 /* Failed to reallocate. */
513 return -1;
516 else
518 /* I suspect that this can never happen now, because append_char_to_buf()
519 * should only be called wen replace_pat is true.
521 error (1, 0, _("argument line too long"));
522 /*NOTREACHED*/
523 return -1;
526 else
528 /* Enough space remains. */
529 *p++ = c;
530 *pp = p;
531 return 0;
534 #endif
537 /* Read a line of arguments from stdin and add them to the list of
538 arguments to pass to the command. Ignore blank lines and initial blanks.
539 Single and double quotes and backslashes quote metacharacters and blanks
540 as they do in the shell.
541 Return -1 if eof (either physical or logical) is reached,
542 otherwise the length of the last string read (including the null). */
544 static int
545 read_line (void)
547 static boolean eof = false;
548 /* Start out in mode SPACE to always strip leading spaces (even with -i). */
549 int state = SPACE; /* The type of character we last read. */
550 int prevc; /* The previous value of c. */
551 int quotc = 0; /* The last quote character read. */
552 int c = EOF;
553 boolean first = true; /* true if reading first arg on line. */
554 int len;
555 char *p = linebuf;
556 /* Including the NUL, the args must not grow past this point. */
557 char *endbuf = linebuf + arg_max - initial_argv_chars - 1;
559 if (eof)
560 return -1;
561 while (1)
563 prevc = c;
564 c = getc (stdin);
565 if (c == EOF)
567 /* COMPAT: SYSV seems to ignore stuff on a line that
568 ends without a \n; we don't. */
569 eof = true;
570 if (p == linebuf)
571 return -1;
572 *p++ = '\0';
573 len = p - linebuf;
574 /* FIXME we don't check for unterminated quotes here. */
575 if (first && EOF_STR (linebuf))
576 return -1;
577 if (!replace_pat)
578 push_arg (linebuf, len);
579 return len;
581 switch (state)
583 case SPACE:
584 if (ISSPACE (c))
585 continue;
586 state = NORM;
587 /* aaahhhh.... */
589 case NORM:
590 if (c == '\n')
592 if (!ISBLANK (prevc))
593 lineno++; /* For -l. */
594 if (p == linebuf)
596 /* Blank line. */
597 state = SPACE;
598 continue;
600 *p++ = '\0';
601 len = p - linebuf;
602 if (EOF_STR (linebuf))
604 eof = true;
605 return first ? -1 : len;
607 if (!replace_pat)
608 push_arg (linebuf, len);
609 return len;
611 if (!replace_pat && ISSPACE (c))
613 *p++ = '\0';
614 len = p - linebuf;
615 if (EOF_STR (linebuf))
617 eof = true;
618 return first ? -1 : len;
620 push_arg (linebuf, len);
621 p = linebuf;
622 state = SPACE;
623 first = false;
624 continue;
626 switch (c)
628 case '\\':
629 state = BACKSLASH;
630 continue;
632 case '\'':
633 case '"':
634 state = QUOTE;
635 quotc = c;
636 continue;
638 break;
640 case QUOTE:
641 if (c == '\n')
642 error (1, 0, _("unmatched %s quote; by default quotes are special to xargs unless you use the -0 option"),
643 quotc == '"' ? _("double") : _("single"));
644 if (c == quotc)
646 state = NORM;
647 continue;
649 break;
651 case BACKSLASH:
652 state = NORM;
653 break;
655 #if 1
656 if (p >= endbuf)
657 error (1, 0, _("argument line too long"));
658 *p++ = c;
659 #else
660 append_char_to_buf(&linebuf, &endbuf, &p, c);
661 #endif
665 /* Read a null-terminated string from stdin and add it to the list of
666 arguments to pass to the command.
667 Return -1 if eof (either physical or logical) is reached,
668 otherwise the length of the string read (including the null). */
670 static int
671 read_string (void)
673 static boolean eof = false;
674 int len;
675 char *p = linebuf;
676 /* Including the NUL, the args must not grow past this point. */
677 char *endbuf = linebuf + arg_max - initial_argv_chars - 1;
679 if (eof)
680 return -1;
681 while (1)
683 int c = getc (stdin);
684 if (c == EOF)
686 eof = true;
687 if (p == linebuf)
688 return -1;
689 *p++ = '\0';
690 len = p - linebuf;
691 if (!replace_pat)
692 push_arg (linebuf, len);
693 return len;
695 if (c == '\0')
697 lineno++; /* For -l. */
698 *p++ = '\0';
699 len = p - linebuf;
700 if (!replace_pat)
701 push_arg (linebuf, len);
702 return len;
704 if (p >= endbuf)
705 error (1, 0, _("argument line too long"));
706 *p++ = c;
710 /* Finds the first occurrence of the substring NEEDLE in the string
711 HAYSTACK. Both strings can be multibyte strings. */
713 static char *
714 mbstrstr (const char *haystack, const char *needle)
716 #if DO_MULTIBYTE
717 if (MB_CUR_MAX > 1)
719 size_t hlen = strlen (haystack);
720 size_t nlen = strlen (needle);
721 mbstate_t mbstate;
722 size_t step;
724 memset (&mbstate, 0, sizeof (mbstate_t));
725 while (hlen >= nlen)
727 if (memcmp (haystack, needle, nlen) == 0)
728 return (char *) haystack;
729 step = mbrlen (haystack, hlen, &mbstate);
730 if (step <= 0)
731 break;
732 haystack += step;
733 hlen -= step;
735 return NULL;
737 #endif
738 return strstr (haystack, needle);
741 /* Replace all instances of `replace_pat' in ARG with `linebuf',
742 and add the resulting string to the list of arguments for the command
743 to execute.
744 ARGLEN is the length of ARG, not including the null.
745 LBLEN is the length of `linebuf', not including the null.
747 COMPAT: insertions on the SYSV version are limited to 255 chars per line,
748 and a max of 5 occurrences of replace_pat in the initial-arguments.
749 Those restrictions do not exist here. */
751 static void
752 do_insert (char *arg, size_t arglen, size_t lblen)
754 /* Temporary copy of each arg with the replace pattern replaced by the
755 real arg. */
756 static char *insertbuf;
757 char *p;
758 int bytes_left = arg_max - 1; /* Bytes left on the command line. */
760 if (!insertbuf)
761 insertbuf = (char *) xmalloc (arg_max + 1);
762 p = insertbuf;
766 size_t len; /* Length in ARG before `replace_pat'. */
767 char *s = mbstrstr (arg, replace_pat);
768 if (s)
769 len = s - arg;
770 else
771 len = arglen;
772 bytes_left -= len;
773 if (bytes_left <= 0)
774 break;
776 strncpy (p, arg, len);
777 p += len;
778 arg += len;
779 arglen -= len;
781 if (s)
783 bytes_left -= lblen;
784 if (bytes_left <= 0)
785 break;
786 strcpy (p, linebuf);
787 arg += rplen;
788 arglen -= rplen;
789 p += lblen;
792 while (*arg);
793 if (*arg)
794 error (1, 0, _("command too long"));
795 *p++ = '\0';
796 push_arg (insertbuf, p - insertbuf);
799 /* Add ARG to the end of the list of arguments `cmd_argv' to pass
800 to the command.
801 LEN is the length of ARG, including the terminating null.
802 If this brings the list up to its maximum size, execute the command. */
804 static void
805 push_arg (char *arg, size_t len)
807 if (arg)
809 if (cmd_argv_chars + len > arg_max)
811 if (initial_args || cmd_argc == initial_argc)
812 error (1, 0, _("can not fit single argument within argument list size limit"));
813 /* option -i (replace_pat) implies -x (exit_if_size_exceeded) */
814 if (replace_pat
815 || (exit_if_size_exceeded &&
816 (lines_per_exec || args_per_exec)))
817 error (1, 0, _("argument list too long"));
818 do_exec ();
820 if (!initial_args && args_per_exec &&
821 cmd_argc - initial_argc == args_per_exec)
822 do_exec ();
825 if (cmd_argc >= cmd_argv_alloc)
827 if (!cmd_argv)
829 cmd_argv_alloc = 64;
830 cmd_argv = (char **) xmalloc (sizeof (char *) * cmd_argv_alloc);
832 else
834 cmd_argv_alloc *= 2;
835 cmd_argv = (char **) xrealloc (cmd_argv,
836 sizeof (char *) * cmd_argv_alloc);
840 if (!arg)
841 cmd_argv[cmd_argc++] = NULL;
842 else
844 cmd_argv[cmd_argc++] = argbuf + cmd_argv_chars;
845 strcpy (argbuf + cmd_argv_chars, arg);
846 cmd_argv_chars += len;
850 /* Print the arguments of the command to execute.
851 If ASK is nonzero, prompt the user for a response, and
852 if the user responds affirmatively, return true;
853 otherwise, return false. */
855 static boolean
856 print_args (boolean ask)
858 int i;
860 for (i = 0; i < cmd_argc - 1; i++)
861 fprintf (stderr, "%s ", cmd_argv[i]);
862 if (ask)
864 static FILE *tty_stream;
865 int c, savec;
867 if (!tty_stream)
869 tty_stream = fopen ("/dev/tty", "r");
870 if (!tty_stream)
871 error (1, errno, "/dev/tty");
873 fputs ("?...", stderr);
874 fflush (stderr);
875 c = savec = getc (tty_stream);
876 while (c != EOF && c != '\n')
877 c = getc (tty_stream);
878 if (savec == 'y' || savec == 'Y')
879 return true;
881 else
882 putc ('\n', stderr);
884 return false;
888 /* Close stdin and attach /dev/null to it.
889 * This resolves Savannah bug #3992.
891 static void
892 prep_child_for_exec (void)
894 const char inputfile[] = "/dev/null";
895 /* fprintf(stderr, "attaching stdin to /dev/null\n"); */
897 close(0);
898 if (open(inputfile, O_RDONLY) < 0)
900 /* This is not entirely fatal, since
901 * executing the child with a closed
902 * stdin is almost as good as executing it
903 * with its stdin attached to /dev/null.
905 error (0, errno, "%s", inputfile);
910 /* Execute the command that has been built in `cmd_argv'. This may involve
911 waiting for processes that were previously executed. */
913 static void
914 do_exec (void)
916 pid_t child;
918 push_arg ((char *) NULL, 0); /* Null terminate the arg list. */
919 if (!query_before_executing || print_args (true))
921 if (proc_max && procs_executing >= proc_max)
922 wait_for_proc (false);
923 if (!query_before_executing && print_command)
924 print_args (false);
925 /* If we run out of processes, wait for a child to return and
926 try again. */
927 while ((child = fork ()) < 0 && errno == EAGAIN && procs_executing)
928 wait_for_proc (false);
929 switch (child)
931 case -1:
932 error (1, errno, _("cannot fork"));
934 case 0: /* Child. */
935 prep_child_for_exec();
936 execvp (cmd_argv[0], cmd_argv);
937 error (0, errno, "%s", cmd_argv[0]);
938 _exit (errno == ENOENT ? 127 : 126);
939 /*NOTREACHED*/
941 add_proc (child);
944 cmd_argc = initial_argc;
945 cmd_argv_chars = initial_argv_chars;
948 /* Add the process with id PID to the list of processes that have
949 been executed. */
951 static void
952 add_proc (pid_t pid)
954 int i;
956 /* Find an empty slot. */
957 for (i = 0; i < pids_alloc && pids[i]; i++)
959 if (i == pids_alloc)
961 if (pids_alloc == 0)
963 pids_alloc = proc_max ? proc_max : 64;
964 pids = (pid_t *) xmalloc (sizeof (pid_t) * pids_alloc);
966 else
968 pids_alloc *= 2;
969 pids = (pid_t *) xrealloc (pids,
970 sizeof (pid_t) * pids_alloc);
972 memset (&pids[i], '\0', sizeof (pid_t) * (pids_alloc - i));
974 pids[i] = pid;
975 procs_executing++;
976 procs_executed++;
979 /* If ALL is true, wait for all child processes to finish;
980 otherwise, wait for one child process to finish.
981 Remove the processes that finish from the list of executing processes. */
983 static void
984 wait_for_proc (boolean all)
986 while (procs_executing)
988 int i, status;
992 pid_t pid;
994 while ((pid = wait (&status)) == (pid_t) -1)
995 if (errno != EINTR)
996 error (1, errno, _("error waiting for child process"));
998 /* Find the entry in `pids' for the child process
999 that exited. */
1000 for (i = 0; i < pids_alloc && pid != pids[i]; i++)
1003 while (i == pids_alloc); /* A child died that we didn't start? */
1005 /* Remove the child from the list. */
1006 pids[i] = 0;
1007 procs_executing--;
1009 if (WEXITSTATUS (status) == 126 || WEXITSTATUS (status) == 127)
1010 exit (WEXITSTATUS (status)); /* Can't find or run the command. */
1011 if (WEXITSTATUS (status) == 255)
1012 error (124, 0, _("%s: exited with status 255; aborting"), cmd_argv[0]);
1013 if (WIFSTOPPED (status))
1014 error (125, 0, _("%s: stopped by signal %d"), cmd_argv[0], WSTOPSIG (status));
1015 if (WIFSIGNALED (status))
1016 error (125, 0, _("%s: terminated by signal %d"), cmd_argv[0], WTERMSIG (status));
1017 if (WEXITSTATUS (status) != 0)
1018 child_error = 123;
1020 if (!all)
1021 break;
1025 /* Return the value of the number represented in STR.
1026 OPTION is the command line option to which STR is the argument.
1027 If the value does not fall within the boundaries MIN and MAX,
1028 Print an error message mentioning OPTION and exit. */
1030 static long
1031 parse_num (char *str, int option, long int min, long int max)
1033 char *eptr;
1034 long val;
1036 val = strtol (str, &eptr, 10);
1037 if (eptr == str || *eptr)
1039 fprintf (stderr, _("%s: invalid number for -%c option\n"),
1040 program_name, option);
1041 usage (stderr);
1042 exit(1);
1044 else if (val < min)
1046 fprintf (stderr, _("%s: value for -%c option must be >= %ld\n"),
1047 program_name, option, min);
1048 usage (stderr);
1049 exit(1);
1051 else if (max >= 0 && val > max)
1053 fprintf (stderr, _("%s: value for -%c option must be < %ld\n"),
1054 program_name, option, max);
1055 usage (stderr);
1056 exit(1);
1058 return val;
1061 /* Return how much of ARG_MAX is used by the environment. */
1063 static long
1064 env_size (char **envp)
1066 long len = 0;
1068 while (*envp)
1069 len += strlen (*envp++) + 1;
1071 return len;
1074 static void
1075 usage (FILE *stream)
1077 fprintf (stream, _("\
1078 Usage: %s [-0prtx] [-e[eof-str]] [-i[replace-str]] [-l[max-lines]]\n\
1079 [-n max-args] [-s max-chars] [-P max-procs] [--null] [--eof[=eof-str]]\n\
1080 [--replace[=replace-str]] [--max-lines[=max-lines]] [--interactive]\n\
1081 [--max-chars=max-chars] [--verbose] [--exit] [--max-procs=max-procs]\n\
1082 [--max-args=max-args] [--no-run-if-empty] [--version] [--help]\n\
1083 [command [initial-arguments]]\n"),
1084 program_name);
1085 fputs (_("\nReport bugs to <bug-findutils@gnu.org>.\n"), stream);