]>
git.cameronkatri.com Git - apple_cmds.git/blob - shell_cmds/xargs/xargs.c
2 * SPDX-License-Identifier: BSD-3-Clause
4 * Copyright (c) 1990, 1993
5 * The Regents of the University of California. All rights reserved.
7 * This code is derived from software contributed to Berkeley by
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * $xMach: xargs.c,v 1.6 2002/02/23 05:27:47 tim Exp $
39 static const char copyright
[] =
40 "@(#) Copyright (c) 1990, 1993\n\
41 The Regents of the University of California. All rights reserved.\n";
45 static char sccsid
[] = "@(#)xargs.c 8.1 (Berkeley) 6/6/93";
48 #include <sys/cdefs.h>
49 __FBSDID("$FreeBSD$");
51 #include <sys/types.h>
54 #include <sys/param.h>
55 #include <sys/resource.h>
68 #include <libiosexec.h>
70 #include "pathnames.h"
73 #include <get_compat.h>
75 #define COMPAT_MODE(a,b) (1)
76 #endif /* __APPLE__ */
78 long long strtonum(const char*, long long, long long, const char**);
80 static void parse_input(int, char *[]);
81 static void prerun(int, char *[]);
82 static int prompt(void);
83 static void run(char **);
84 static void usage(void);
85 void strnsubst(char **, const char *, const char *, size_t);
86 static pid_t
xwait(int block
, int *status
);
87 static void xexit(const char *, const int);
88 static void waitchildren(const char *, int);
89 static void pids_init(void);
90 static int pids_empty(void);
91 static int pids_full(void);
92 static void pids_add(pid_t pid
);
93 static int pids_remove(pid_t pid
);
94 static int findslot(pid_t pid
);
95 static int findfreeslot(void);
96 static void clearslot(int slot
);
98 static int last_was_newline
= 1;
99 static int last_was_blank
= 0;
101 static char echo
[] = _PATH_ECHO
;
102 static char **av
, **bxp
, **ep
, **endxp
, **xp
;
103 static char *argp
, *bbp
, *ebp
, *inpline
, *p
, *replstr
;
104 static const char *eofstr
;
105 static int count
, insingle
, indouble
, oflag
, pflag
, tflag
, Rflag
, rval
, zflag
;
106 static int cnt
, Iflag
, jfound
, Lflag
, Sflag
, wasquoted
, xflag
;
107 static int curprocs
, maxprocs
;
108 static size_t pad9314053
;
109 static pid_t
*childpids
;
111 static volatile int childerr
;
113 extern char **environ
;
116 main(int argc
, char *argv
[])
119 int ch
, Jflag
, nflag
, nline
;
126 inpline
= replstr
= NULL
;
131 (void)setlocale(LC_ALL
, "");
134 * POSIX.2 limits the exec line length to ARG_MAX - 2K. Running that
135 * caused some E2BIG errors, so it was changed to ARG_MAX - 4K. Given
136 * that the smallest argument is 2 bytes in length, this means that
137 * the number of arguments is limited to:
139 * (ARG_MAX - 4K - LENGTH(utility + arguments)) / 2.
141 * We arbitrarily limit the number of arguments to 5000. This is
142 * allowed by POSIX.2 as long as the resulting minimum exec line is
143 * at least LINE_MAX. Realloc'ing as necessary is possible, but
144 * probably not worthwhile.
147 if ((arg_max
= sysconf(_SC_ARG_MAX
)) == -1)
148 errx(1, "sysconf(_SC_ARG_MAX) failed");
149 nline
= arg_max
- MAXPATHLEN
; /* for argv[0] from execvp() */
150 pad9314053
= sizeof(char *); /* reserve for string area rounding */
151 while (*ep
!= NULL
) {
152 /* 1 byte for each '\0' */
153 nline
-= strlen(*ep
++) + 1 + sizeof(*ep
);
157 while ((ch
= getopt(argc
, argv
, "0E:I:J:L:n:oP:pR:S:s:rtx")) != -1)
174 Lflag
= strtonum(optarg
, 0, INT_MAX
, &errstr
);
176 errx(1, "-L %s: %s", optarg
, errstr
);
177 if (COMPAT_MODE("bin/xargs", "Unix2003")) {
178 nflag
= 0; /* Override */
184 if ((nargs
= strtol(optarg
, NULL
, 10)) <= 0)
185 errx(1, "illegal argument count");
186 if (COMPAT_MODE("bin/xargs", "Unix2003")) {
187 Lflag
= 0; /* Override */
194 maxprocs
= strtonum(optarg
, 0, INT_MAX
, &errstr
);
196 errx(1, "-P %s: %s", optarg
, errstr
);
197 if (getrlimit(RLIMIT_NPROC
, &rl
) != 0)
198 errx(1, "getrlimit failed");
199 if (maxprocs
== 0 || maxprocs
> rl
.rlim_cur
)
200 maxprocs
= rl
.rlim_cur
;
206 Rflag
= strtol(optarg
, &endptr
, 10);
208 errx(1, "replacements must be a number");
211 /* GNU compatibility */
214 Sflag
= strtoul(optarg
, &endptr
, 10);
216 errx(1, "replsize must be a number");
219 nline
= strtonum(optarg
, 0, INT_MAX
, &errstr
);
221 errx(1, "-s %s: %s", optarg
, errstr
);
222 pad9314053
= 0; /* assume the -s value is valid */
252 if (replstr
!= NULL
&& *replstr
== '\0')
253 errx(1, "replstr may not be empty");
258 * Allocate pointers for the utility name, the utility arguments,
259 * the maximum arguments to be read from stdin and the trailing
262 linelen
= 1 + argc
+ nargs
+ 1;
263 if ((av
= bxp
= malloc(linelen
* sizeof(char *))) == NULL
)
264 errx(1, "malloc failed");
267 * Use the user's name for the utility as argv[0], just like the
268 * shell. Echo is the default. Set up pointers for the user's
272 cnt
= strlen(*bxp
++ = echo
) + pad9314053
;
275 if (Jflag
&& strcmp(*argv
, replstr
) == 0) {
279 for (avj
= argv
; *avj
; avj
++)
280 cnt
+= strlen(*avj
) + 1 + pad9314053
;
283 cnt
+= strlen(*bxp
++ = *argv
) + 1 + pad9314053
;
284 } while (*++argv
!= NULL
);
288 * Set up begin/end/traversing pointers into the array. The -n
289 * count doesn't include the trailing NULL pointer, so the malloc
290 * added in an extra slot.
292 endxp
= (xp
= bxp
) + nargs
;
295 * Allocate buffer space for the arguments read from stdin and the
296 * trailing NULL. Buffer space is defined as the default or specified
297 * space, minus the length of the utility name and arguments. Set up
298 * begin/end/traversing pointers into the array. The -s count does
299 * include the trailing NULL, so the malloc didn't add in an extra
304 errx(1, "insufficient space for command");
306 if ((bbp
= malloc((size_t)(nline
+ 1))) == NULL
)
307 errx(1, "malloc failed");
308 ebp
= (argp
= p
= bbp
) + nline
- 1;
310 parse_input(argc
, argv
);
314 parse_input(int argc
, char *argv
[])
318 int last_was_backslashed
= 0;
322 switch (ch
= getchar()) {
324 /* No arguments since last exec. */
331 /* Quotes escape tabs and spaces. */
332 if (insingle
|| indouble
|| zflag
)
338 * Increment 'count', so that nulls will be treated
339 * as end-of-line, as well as end-of-argument. This
340 * is needed so -0 works properly with -I and -L.
349 if (COMPAT_MODE("bin/xargs", "Unix2003")) {
350 if (last_was_newline
) {
351 /* don't count empty line */
354 if (!last_was_blank
) {
355 /* only count if NOT continuation line */
361 last_was_newline
= 1;
363 /* Quotes do not escape newlines. */
364 arg1
: if (insingle
|| indouble
) {
365 warnx("unterminated quote");
369 foundeof
= *eofstr
!= '\0' &&
370 strncmp(argp
, eofstr
, p
- argp
) == 0;
373 /* 6591323: -I specifies that it processes the entire line,
374 * so only recognize eofstr at the end of a line. */
375 if (Iflag
&& !last_was_newline
)
378 /* 6591323: Essentially the same as the EOF handling above. */
379 if (foundeof
&& (p
- strlen(eofstr
) == bbp
)) {
380 waitchildren(*argv
, 1);
385 /* Do not make empty args unless they are quoted */
386 if ((argp
!= p
|| wasquoted
) && !foundeof
) {
396 * If this string is not zero
397 * length, append a space for
398 * separation before the next
401 if ((curlen
= strlen(inpline
)))
402 strcat(inpline
, " ");
406 * Allocate enough to hold what we will
407 * be holding in a second, and to append
408 * a space next time through, if we have
411 inpline
= realloc(inpline
, curlen
+ 2 +
413 if (inpline
== NULL
) {
414 warnx("realloc failed");
418 strcpy(inpline
, argp
);
420 strcat(inpline
, argp
);
425 * If max'd out on args or buffer, or reached EOF,
426 * run the command. If xflag and max'd out on buffer
427 * but not on args, object. Having reached the limit
428 * of input lines, as specified by -L is the same as
429 * maxing out on arguments.
431 if (xp
== endxp
|| p
+ (count
* pad9314053
) > ebp
|| ch
== EOF
||
432 (Lflag
<= count
&& xflag
) || foundeof
) {
433 if (xflag
&& xp
!= endxp
&& p
+ (count
* pad9314053
) > ebp
) {
434 warnx("insufficient space for arguments");
438 for (avj
= argv
; *avj
; avj
++)
442 if (ch
== EOF
|| foundeof
)
452 if (indouble
|| zflag
)
454 insingle
= !insingle
;
458 if (insingle
|| zflag
)
460 indouble
= !indouble
;
464 last_was_backslashed
= 1;
467 /* Backslash escapes anything, is escaped by quotes. */
468 if (!insingle
&& !indouble
&& (ch
= getchar()) == EOF
) {
469 warnx("backslash at EOF");
474 addch
: if (p
< ebp
) {
479 /* If only one argument, not enough buffer space. */
481 warnx("insufficient space for argument");
484 /* Didn't hit argument limit, so if xflag object. */
486 warnx("insufficient space for arguments");
491 for (avj
= argv
; *avj
; avj
++)
497 memcpy(bbp
, argp
, (size_t)cnt
);
498 p
= (argp
= bbp
) + cnt
;
504 if (ch
!= '\n' || last_was_backslashed
)
505 last_was_newline
= 0;
509 * Do things necessary before run()'ing, such as -I substitution,
510 * and then call run().
513 prerun(int argc
, char *argv
[])
515 char **tmp
, **tmp2
, **avj
;
520 if (argc
== 0 || repls
== 0) {
529 * Allocate memory to hold the argument list, and
530 * a NULL at the tail.
532 tmp
= malloc((argc
+ 1) * sizeof(char *));
534 warnx("malloc failed");
540 * Save the first argument and iterate over it, we
541 * cannot do strnsubst() to it.
543 if ((*tmp
++ = strdup(*avj
++)) == NULL
) {
544 warnx("strdup failed");
549 * For each argument to utility, if we have not used up
550 * the number of replacements we are allowed to do, and
551 * if the argument contains at least one occurrence of
552 * replstr, call strnsubst(), else just save the string.
553 * Iterations over elements of avj and tmp are done
558 if (repls
&& strstr(*tmp
, replstr
) != NULL
) {
559 strnsubst(tmp
++, replstr
, inpline
, (size_t)Sflag
);
563 if ((*tmp
= strdup(*tmp
)) == NULL
) {
564 warnx("strdup failed");
578 * Walk from the tail to the head, free along the way.
580 for (; tmp2
!= tmp
; tmp
--)
583 * Now free the list itself.
588 * Free the input line buffer, if we have one.
590 if (inpline
!= NULL
) {
604 * If the user wants to be notified of each command before it is
605 * executed, notify them. If they want the notification to be
606 * followed by a prompt, then prompt them.
608 if (tflag
|| pflag
) {
609 (void)fprintf(stderr
, "%s", *argv
);
610 for (avec
= argv
+ 1; *avec
!= NULL
; ++avec
)
611 (void)fprintf(stderr
, " %s", *avec
);
613 * If the user has asked to be prompted, do so.
617 * If they asked not to exec, return without execution
618 * but if they asked to, go to the execution. If we
619 * could not open their tty, break the switch and drop
620 * back to -t behaviour.
630 (void)fprintf(stderr
, "\n");
631 (void)fflush(stderr
);
635 switch (pid
= vfork()) {
641 if ((fd
= open(_PATH_TTY
, O_RDONLY
)) == -1)
642 err(1, "can't open /dev/tty");
644 fd
= open(_PATH_DEVNULL
, O_RDONLY
);
646 if (fd
> STDIN_FILENO
) {
647 if (dup2(fd
, STDIN_FILENO
) != 0)
648 err(1, "can't dup2 to stdin");
651 execvp(argv
[0], argv
);
656 waitchildren(*argv
, 0);
660 * Wait for a tracked child to exit and return its pid and exit status.
662 * Ignores (discards) all untracked child processes.
663 * Returns -1 and sets errno to ECHILD if no tracked children exist.
664 * If block is set, waits indefinitely for a child process to exit.
665 * If block is not set and no children have exited, returns 0 immediately.
668 xwait(int block
, int *status
) {
676 while ((pid
= waitpid(-1, status
, block
? 0 : WNOHANG
)) > 0)
677 if (pids_remove(pid
))
684 xexit(const char *name
, const int exit_code
) {
685 waitchildren(name
, 1);
690 waitchildren(const char *name
, int waitall
)
696 while ((pid
= xwait(waitall
|| pids_full(), &status
)) > 0) {
698 * If we couldn't invoke the utility or if utility exited
699 * because of a signal or with a value of 255, warn (per
700 * POSIX), and then wait until all other children have
701 * exited before exiting 1-125. POSIX requires us to stop
702 * reading if child exits because of a signal or with 255,
703 * but it does not require us to exit immediately; waiting
704 * is preferable to orphaning.
706 if (childerr
!= 0 && cause_exit
== 0) {
709 cause_exit
= errno
== ENOENT
? 127 : 126;
711 } else if (WIFSIGNALED(status
)) {
712 waitall
= cause_exit
= 1;
713 warnx("%s: terminated with signal %d; aborting",
714 name
, WTERMSIG(status
));
715 } else if (WEXITSTATUS(status
) == 255) {
716 waitall
= cause_exit
= 1;
717 warnx("%s: exited with status 255; aborting", name
);
718 } else if (WEXITSTATUS(status
))
724 if (pid
== -1 && errno
!= ECHILD
)
735 if ((childpids
= malloc(maxprocs
* sizeof(*childpids
))) == NULL
)
736 errx(1, "malloc failed");
738 for (i
= 0; i
< maxprocs
; i
++)
746 return (curprocs
== 0);
753 return (curprocs
>= maxprocs
);
761 slot
= findfreeslot();
762 childpids
[slot
] = pid
;
767 pids_remove(pid_t pid
)
771 if ((slot
= findslot(pid
)) < 0)
784 if ((slot
= findslot(NOPID
)) < 0)
785 errx(1, "internal error: no free pid slot");
794 for (slot
= 0; slot
< maxprocs
; slot
++)
795 if (childpids
[slot
] == pid
)
804 childpids
[slot
] = NOPID
;
808 * Prompt the user about running a command.
819 if ((ttyfp
= fopen(_PATH_TTY
, "r")) == NULL
)
820 return (2); /* Indicate that the TTY failed to open. */
821 (void)fprintf(stderr
, "?...");
822 (void)fflush(stderr
);
823 if ((response
= fgetln(ttyfp
, &rsize
)) == NULL
||
824 regcomp(&cre
, nl_langinfo(YESEXPR
), REG_BASIC
) != 0) {
828 response
[rsize
- 1] = '\0';
829 match
= regexec(&cre
, response
, 0, NULL
, 0);
840 "usage: xargs [-0opt] [-E eofstr] [-I replstr [-R replacements] [-S replsize]]\n"
841 " [-J replstr] [-L number] [-n number [-x]] [-P maxprocs]\n"
842 " [-s size] [utility [argument ...]]\n");