Print this page
4703 would like xargs support for -P
@@ -87,10 +87,11 @@
#define FORKFAIL "Could not fork child"
#define EXECFAIL "Could not exec command"
#define MISSQUOTE "Missing quote"
#define BADESCAPE "Incomplete escape"
#define IBUFOVERFLOW "Insert buffer overflow"
+#define NOCHILDSLOT "No free child slot available"
#define _(x) gettext(x)
static wctype_t blank;
static char *arglist[MAXARGS+1];
@@ -107,10 +108,11 @@
char *p_skel; /* ptr to arg template */
} saveargv[MAXINSERTS];
static int PROMPT = -1;
static int BUFLIM = BUFSIZE;
+static int MAXPROCS = 1;
static int N_ARGS = 0;
static int N_args = 0;
static int N_lines = 0;
static int DASHX = FALSE;
static int MORE = TRUE;
@@ -125,27 +127,35 @@
static int ibufsize = 0;
static int exitstat = 0; /* our exit status */
static int mac; /* modified argc, after parsing */
static char **mav; /* modified argv, after parsing */
static int n_inserts; /* # of insertions. */
+static pid_t *procs; /* pids of children */
+static int n_procs; /* # of child processes. */
/* our usage message: */
#define USAGEMSG "Usage: xargs: [-t] [-p] [-0] [-e[eofstr]] [-E eofstr] "\
- "[-I replstr] [-i[replstr]] [-L #] [-l[#]] [-n # [-x]] [-s size] "\
+ "[-I replstr] [-i[replstr]] [-L #] [-l[#]] [-n # [-x]] [-P maxprocs] [-s size] "\
"[cmd [args ...]]\n"
static int echoargs();
static wint_t getwchr(char *, size_t *);
-static int lcall(char *sub, char **subargs);
+static void lcall(char *sub, char **subargs);
static void addibuf(struct inserts *p);
static void ermsg(char *messages, ...);
static char *addarg(char *arg);
static void store_str(char **, char *, size_t);
static char *getarg(char *);
static char *insert(char *pattern, char *subst);
static void usage();
static void parseargs();
+static void procs_malloc(void);
+static int procs_find(pid_t child);
+static void procs_store(pid_t child);
+static int procs_delete(pid_t child);
+static pid_t procs_waitpid(int blocking, int *stat_loc);
+static void procs_wait(int blocking);
int
main(int argc, char **argv)
{
int j;
@@ -171,11 +181,11 @@
}
parseargs(argc, argv);
/* handling all of xargs arguments: */
- while ((c = getopt(mac, mav, "0tpe:E:I:i:L:l:n:s:x")) != EOF) {
+ while ((c = getopt(mac, mav, "0tpe:E:I:i:L:l:n:P:s:x")) != EOF) {
switch (c) {
case '0':
ZERO = TRUE;
break;
@@ -294,10 +304,18 @@
LEGAL = DASHX || N_ARGS == 1;
INSERT = PER_LINE = FALSE;
}
break;
+ case 'P': /* -P maxprocs: # of child processses */
+ MAXPROCS = atoi(optarg);
+ if (MAXPROCS <= 0) {
+ ermsg(_("#maxprocs must be positive int: %s\n"),
+ optarg);
+ }
+ break;
+
case 's': /* -s size: set max size of each arg list */
BUFLIM = atoi(optarg);
if (BUFLIM > BUFSIZE || BUFLIM <= 0) {
ermsg(_("0 < max-cmd-line-size <= %d: %s\n"),
BUFSIZE, optarg);
@@ -334,10 +352,12 @@
mac -= optind; /* dec arg count by what we've processed */
mav += optind; /* inc to current mav */
+ (void) procs_malloc();
+
if (mac <= 0) { /* if there're no more args to process, */
cmdname = "/usr/bin/echo"; /* our default command */
*ARGV++ = addarg(cmdname); /* use the default cmd. */
} else { /* otherwise keep parsing rest of the string. */
/*
@@ -404,10 +424,11 @@
* cannot create any list because it would be
* too big.
*/
if (LEGAL || N_args == 0) {
EMSG(LIST2LONG);
+ (void) procs_wait(1);
exit(2);
/* NOTREACHED */
}
/*
@@ -433,11 +454,11 @@
}
*ARGV = NULL;
if (N_args == 0) {
/* Reached the end with no more work. */
- exit(exitstat);
+ break;
}
/* insert arg if requested */
if (!ERR && INSERT) {
@@ -462,10 +483,11 @@
for (ARGV = arglist; *ARGV != NULL; ARGV++) {
linesize += strlen(*ARGV) + 1;
}
if (linesize >= BUFLIM) {
EMSG(LIST2LONG);
+ (void) procs_wait(1);
exit(2);
/* NOTREACHED */
}
}
@@ -482,15 +504,17 @@
* for xcu4, all invocations of cmdname must
* return 0, in order for us to return 0.
* so if we have a non-zero status here,
* quit immediately.
*/
- exitstat |= lcall(cmdname, arglist);
+ (void) lcall(cmdname, arglist);
}
}
}
+ (void) procs_wait(1);
+
if (OK)
return (exitstat);
/*
* if exitstat was set, to match XCU4 complience,
@@ -835,38 +859,22 @@
exit(1);
/* NOTREACHED */
}
-static int
+static void
lcall(char *sub, char **subargs)
{
- int retcode, retry = 0;
- pid_t iwait, child;
+ int retry = 0;
+ pid_t child;
for (;;) {
switch (child = fork()) {
default:
- while ((iwait = wait(&retcode)) != child &&
- iwait != (pid_t)-1)
- ;
- if (iwait == (pid_t)-1) {
- PERR(WAITFAIL);
- exit(122);
- /* NOTREACHED */
- }
- if (WIFSIGNALED(retcode)) {
- EMSG2(CHILDSIG, WTERMSIG(retcode));
- exit(125);
- /* NOTREACHED */
- }
- if ((WEXITSTATUS(retcode) & 0377) == 0377) {
- EMSG(CHILDFAIL);
- exit(124);
- /* NOTREACHED */
- }
- return (WEXITSTATUS(retcode));
+ (void) procs_store(child);
+ (void) procs_wait(0);
+ return;
case 0:
(void) execvp(sub, subargs);
PERR(EXECFAIL);
if (errno == EACCES)
exit(126);
@@ -880,10 +888,116 @@
(void) sleep(1);
}
}
}
+static void
+procs_malloc(void)
+{
+ int i;
+
+ procs = (pid_t *)(malloc(MAXPROCS * sizeof(pid_t)));
+ if (procs == NULL) {
+ PERR(MALLOCFAIL);
+ exit(1);
+ }
+
+ for (i = 0; i < MAXPROCS; i++) {
+ procs[i] = (pid_t)(0);
+ }
+}
+
+static int
+procs_find(pid_t child)
+{
+ int i;
+
+ for (i = 0; i < MAXPROCS; i++) {
+ if (procs[i] == child) {
+ return (i);
+ }
+ }
+
+ return (-1);
+}
+
+static void
+procs_store(pid_t child)
+{
+ int i;
+
+ i = procs_find((pid_t)(0));
+ if (i < 0) {
+ PERR(NOCHILDSLOT);
+ exit(1);
+ }
+ procs[i] = child;
+ n_procs++;
+}
+
+static int
+procs_delete(pid_t child)
+{
+ int i;
+
+ i = procs_find(child);
+ if (i < 0) {
+ return (0);
+ }
+ procs[i] = (pid_t)(0);
+ n_procs--;
+ return (1);
+}
+
+static pid_t
+procs_waitpid(int blocking, int *stat_loc)
+{
+ pid_t child;
+ int options;
+
+ if (n_procs == 0) {
+ errno = ECHILD;
+ return (-1);
+ }
+
+ options = (blocking) ? 0 : WNOHANG;
+
+ while ((child = waitpid(-1, stat_loc, options)) > 0) {
+ if (procs_delete(child)) {
+ break;
+ }
+ }
+
+ return (child);
+}
+
+static void
+procs_wait(int blocking)
+{
+ pid_t child;
+ int stat_loc;
+
+ while ((child = procs_waitpid(blocking || (n_procs >= MAXPROCS) ? 1 : 0, &stat_loc)) > 0) {
+ if (WIFSIGNALED(stat_loc)) {
+ EMSG2(CHILDSIG, WTERMSIG(stat_loc));
+ exit(125);
+ /* NOTREACHED */
+ } else if ((WEXITSTATUS(stat_loc) & 0377) == 0377) {
+ EMSG(CHILDFAIL);
+ exit(124);
+ /* NOTREACHED */
+ } else {
+ exitstat |= WEXITSTATUS(stat_loc);
+ }
+ }
+
+ if (child == (pid_t)(-1) && errno != ECHILD) {
+ EMSG(WAITFAIL);
+ exit(122);
+ /* NOTREACHED */
+ }
+}
static void
usage()
{
ermsg(_(USAGEMSG));
@@ -978,10 +1092,11 @@
* latter case. we handle the latter possibility
* first so both the old solaris way of handling
* and the new XCU4 way of handling things are allowed.
*/
case 'n': /* FALLTHROUGH */
+ case 'P': /* FALLTHROUGH */
case 's': /* FALLTHROUGH */
case 'E': /* FALLTHROUGH */
case 'I': /* FALLTHROUGH */
case 'L':
/*