Print this page
4703 would like xargs support for -P

*** 87,96 **** --- 87,97 ---- #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,116 **** --- 108,118 ---- 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,151 **** 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. */ /* our usage message: */ #define USAGEMSG "Usage: xargs: [-t] [-p] [-0] [-e[eofstr]] [-E eofstr] "\ ! "[-I replstr] [-i[replstr]] [-L #] [-l[#]] [-n # [-x]] [-s size] "\ "[cmd [args ...]]\n" static int echoargs(); static wint_t getwchr(char *, size_t *); ! static int 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(); int main(int argc, char **argv) { int j; --- 127,161 ---- 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]] [-P maxprocs] [-s size] "\ "[cmd [args ...]]\n" static int echoargs(); static wint_t getwchr(char *, size_t *); ! 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,181 **** } parseargs(argc, argv); /* handling all of xargs arguments: */ ! while ((c = getopt(mac, mav, "0tpe:E:I:i:L:l:n:s:x")) != EOF) { switch (c) { case '0': ZERO = TRUE; break; --- 181,191 ---- } parseargs(argc, argv); /* handling all of xargs arguments: */ ! while ((c = getopt(mac, mav, "0tpe:E:I:i:L:l:n:P:s:x")) != EOF) { switch (c) { case '0': ZERO = TRUE; break;
*** 294,303 **** --- 304,321 ---- 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,343 **** --- 352,363 ---- 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,413 **** --- 424,434 ---- * 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,443 **** } *ARGV = NULL; if (N_args == 0) { /* Reached the end with no more work. */ ! exit(exitstat); } /* insert arg if requested */ if (!ERR && INSERT) { --- 454,464 ---- } *ARGV = NULL; if (N_args == 0) { /* Reached the end with no more work. */ ! break; } /* insert arg if requested */ if (!ERR && INSERT) {
*** 462,471 **** --- 483,493 ---- for (ARGV = arglist; *ARGV != NULL; ARGV++) { linesize += strlen(*ARGV) + 1; } if (linesize >= BUFLIM) { EMSG(LIST2LONG); + (void) procs_wait(1); exit(2); /* NOTREACHED */ } }
*** 482,496 **** * 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); } } } if (OK) return (exitstat); /* * if exitstat was set, to match XCU4 complience, --- 504,520 ---- * 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. */ ! (void) lcall(cmdname, arglist); } } } + (void) procs_wait(1); + if (OK) return (exitstat); /* * if exitstat was set, to match XCU4 complience,
*** 835,872 **** exit(1); /* NOTREACHED */ } ! static int lcall(char *sub, char **subargs) { ! int retcode, retry = 0; ! pid_t iwait, 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)); case 0: (void) execvp(sub, subargs); PERR(EXECFAIL); if (errno == EACCES) exit(126); --- 859,880 ---- exit(1); /* NOTREACHED */ } ! static void lcall(char *sub, char **subargs) { ! int retry = 0; ! pid_t child; for (;;) { switch (child = fork()) { default: ! (void) procs_store(child); ! (void) procs_wait(0); ! return; case 0: (void) execvp(sub, subargs); PERR(EXECFAIL); if (errno == EACCES) exit(126);
*** 880,889 **** --- 888,1003 ---- (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,987 **** --- 1092,1102 ---- * 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': /*