Print this page
4703 would like xargs support for -P
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/cmd/xargs/xargs.c
+++ new/usr/src/cmd/xargs/xargs.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21 /*
22 22 * Copyright 2012 DEY Storage Systems, Inc. All rights reserved.
23 23 *
24 24 * Portions of this file developed by DEY Storage Systems, Inc. are licensed
25 25 * under the terms of the Common Development and Distribution License (CDDL)
26 26 * version 1.0 only. The use of subsequent versions of the License are
27 27 * is specifically prohibited unless those terms are not in conflict with
28 28 * version 1.0 of the License. You can find this license on-line at
29 29 * http://www.illumos.org/license/CDDL
30 30 */
31 31 /*
32 32 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
33 33 * Use is subject to license terms.
34 34 */
35 35
36 36 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
37 37 /* All Rights Reserved */
38 38
39 39
40 40 #include <stdio.h>
41 41 #include <sys/types.h>
42 42 #include <sys/wait.h>
43 43 #include <unistd.h>
44 44 #include <fcntl.h>
45 45 #include <string.h>
46 46 #include <stdarg.h>
47 47 #include <stdlib.h>
48 48 #include <limits.h>
49 49 #include <wchar.h>
50 50 #include <locale.h>
51 51 #include <langinfo.h>
52 52 #include <stropts.h>
53 53 #include <poll.h>
54 54 #include <errno.h>
55 55 #include <stdarg.h>
56 56 #include "getresponse.h"
57 57
58 58 #define HEAD 0
59 59 #define TAIL 1
60 60 #define FALSE 0
61 61 #define TRUE 1
62 62 #define MAXSBUF 255
63 63 #define MAXIBUF 512
64 64 #define MAXINSERTS 5
65 65 #define BUFSIZE LINE_MAX
66 66 #define MAXARGS 255
67 67 #define INSPAT_STR "{}" /* default replstr string for -[Ii] */
68 68 #define FORK_RETRY 5
69 69
70 70 #define QBUF_STARTLEN 255 /* start size of growable string buffer */
71 71 #define QBUF_INC 100 /* how much to grow a growable string by */
72 72
73 73 /* We use these macros to help make formatting look "consistent" */
74 74 #define EMSG(s) ermsg(gettext(s "\n"))
75 75 #define EMSG2(s, a) ermsg(gettext(s "\n"), a)
76 76 #define PERR(s) perror(gettext("xargs: " s))
77 77
78 78 /* Some common error messages */
79 79
80 80 #define LIST2LONG "Argument list too long"
81 81 #define ARG2LONG "A single argument was greater than %d bytes"
↓ open down ↓ |
81 lines elided |
↑ open up ↑ |
82 82 #define MALLOCFAIL "Memory allocation failure"
83 83 #define CORRUPTFILE "Corrupt input file"
84 84 #define WAITFAIL "Wait failure"
85 85 #define CHILDSIG "Child killed with signal %d"
86 86 #define CHILDFAIL "Command could not continue processing data"
87 87 #define FORKFAIL "Could not fork child"
88 88 #define EXECFAIL "Could not exec command"
89 89 #define MISSQUOTE "Missing quote"
90 90 #define BADESCAPE "Incomplete escape"
91 91 #define IBUFOVERFLOW "Insert buffer overflow"
92 +#define NOCHILDSLOT "No free child slot available"
92 93
93 94 #define _(x) gettext(x)
94 95
95 96 static wctype_t blank;
96 97 static char *arglist[MAXARGS+1];
97 98 static char argbuf[BUFSIZE * 2 + 1];
98 99 static char lastarg[BUFSIZE + 1];
99 100 static char **ARGV = arglist;
100 101 static char *LEOF = "_";
101 102 static char *INSPAT = INSPAT_STR;
102 103 static char ins_buf[MAXIBUF];
103 104 static char *p_ibuf;
104 105
105 106 static struct inserts {
106 107 char **p_ARGV; /* where to put newarg ptr in arg list */
107 108 char *p_skel; /* ptr to arg template */
108 109 } saveargv[MAXINSERTS];
109 110
110 111 static int PROMPT = -1;
111 112 static int BUFLIM = BUFSIZE;
113 +static int MAXPROCS = 1;
112 114 static int N_ARGS = 0;
113 115 static int N_args = 0;
114 116 static int N_lines = 0;
115 117 static int DASHX = FALSE;
116 118 static int MORE = TRUE;
117 119 static int PER_LINE = FALSE;
118 120 static int ERR = FALSE;
119 121 static int OK = TRUE;
120 122 static int LEGAL = FALSE;
121 123 static int TRACE = FALSE;
122 124 static int INSERT = FALSE;
123 125 static int ZERO = FALSE;
124 126 static int linesize = 0;
125 127 static int ibufsize = 0;
126 128 static int exitstat = 0; /* our exit status */
127 129 static int mac; /* modified argc, after parsing */
128 130 static char **mav; /* modified argv, after parsing */
129 131 static int n_inserts; /* # of insertions. */
132 +static pid_t *procs; /* pids of children */
133 +static int n_procs; /* # of child processes. */
130 134
131 135 /* our usage message: */
132 136 #define USAGEMSG "Usage: xargs: [-t] [-p] [-0] [-e[eofstr]] [-E eofstr] "\
133 - "[-I replstr] [-i[replstr]] [-L #] [-l[#]] [-n # [-x]] [-s size] "\
137 + "[-I replstr] [-i[replstr]] [-L #] [-l[#]] [-n # [-x]] [-P maxprocs] [-s size] "\
134 138 "[cmd [args ...]]\n"
135 139
136 140 static int echoargs();
137 141 static wint_t getwchr(char *, size_t *);
138 -static int lcall(char *sub, char **subargs);
142 +static void lcall(char *sub, char **subargs);
139 143 static void addibuf(struct inserts *p);
140 144 static void ermsg(char *messages, ...);
141 145 static char *addarg(char *arg);
142 146 static void store_str(char **, char *, size_t);
143 147 static char *getarg(char *);
144 148 static char *insert(char *pattern, char *subst);
145 149 static void usage();
146 150 static void parseargs();
151 +static void procs_malloc(void);
152 +static int procs_find(pid_t child);
153 +static void procs_store(pid_t child);
154 +static int procs_delete(pid_t child);
155 +static pid_t procs_waitpid(int blocking, int *stat_loc);
156 +static void procs_wait(int blocking);
147 157
148 158 int
149 159 main(int argc, char **argv)
150 160 {
151 161 int j;
152 162 struct inserts *psave;
153 163 int c;
154 164 int initsize;
155 165 char *cmdname, **initlist;
156 166 char *arg;
157 167 char *next;
158 168
159 169 /* initialization */
160 170 blank = wctype("blank");
161 171 n_inserts = 0;
162 172 psave = saveargv;
163 173 (void) setlocale(LC_ALL, "");
164 174 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
165 175 #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */
↓ open down ↓ |
9 lines elided |
↑ open up ↑ |
166 176 #endif
167 177 (void) textdomain(TEXT_DOMAIN);
168 178 if (init_yes() < 0) {
169 179 ermsg(_(ERR_MSG_INIT_YES), strerror(errno));
170 180 exit(1);
171 181 }
172 182
173 183 parseargs(argc, argv);
174 184
175 185 /* handling all of xargs arguments: */
176 - while ((c = getopt(mac, mav, "0tpe:E:I:i:L:l:n:s:x")) != EOF) {
186 + while ((c = getopt(mac, mav, "0tpe:E:I:i:L:l:n:P:s:x")) != EOF) {
177 187 switch (c) {
178 188 case '0':
179 189 ZERO = TRUE;
180 190 break;
181 191
182 192 case 't': /* -t: turn trace mode on */
183 193 TRACE = TRUE;
184 194 break;
185 195
186 196 case 'p': /* -p: turn on prompt mode. */
187 197 if ((PROMPT = open("/dev/tty", O_RDONLY)) == -1) {
188 198 PERR("can't read from tty for -p");
189 199 } else {
190 200 TRACE = TRUE;
191 201 }
192 202 break;
193 203
194 204 case 'e':
195 205 /*
196 206 * -e[eofstr]: set/disable end-of-file.
197 207 * N.B. that an argument *isn't* required here; but
198 208 * parseargs forced an argument if not was given. The
199 209 * forced argument is the default...
200 210 */
201 211 LEOF = optarg; /* can be empty */
202 212 break;
203 213
204 214 case 'E':
205 215 /*
206 216 * -E eofstr: change end-of-file string.
207 217 * eofstr *is* required here, but can be empty:
208 218 */
209 219 LEOF = optarg;
210 220 break;
211 221
212 222 case 'I':
213 223 /* -I replstr: Insert mode. replstr *is* required. */
214 224 INSERT = PER_LINE = LEGAL = TRUE;
215 225 N_ARGS = 0;
216 226 INSPAT = optarg;
217 227 if (*optarg == '\0') {
218 228 ermsg(_("Option requires an argument: -%c\n"),
219 229 c);
220 230 }
221 231 break;
222 232
223 233 case 'i':
224 234 /*
225 235 * -i [replstr]: insert mode, with *optional* replstr.
226 236 * N.B. that an argument *isn't* required here; if
227 237 * it's not given, then the string INSPAT_STR will
228 238 * be assumed.
229 239 *
230 240 * Since getopts(3C) doesn't handle the case of an
231 241 * optional variable argument at all, we have to
232 242 * parse this by hand:
233 243 */
234 244
235 245 INSERT = PER_LINE = LEGAL = TRUE;
236 246 N_ARGS = 0;
237 247 if ((optarg != NULL) && (*optarg != '\0')) {
238 248 INSPAT = optarg;
239 249 } else {
240 250 /*
241 251 * here, there is no next argument. so
242 252 * we reset INSPAT to the INSPAT_STR.
243 253 * we *have* to do this, as -i/I may have
244 254 * been given previously, and XCU4 requires
245 255 * that only "the last one specified takes
246 256 * effect".
247 257 */
248 258 INSPAT = INSPAT_STR;
249 259 }
250 260 break;
251 261
252 262 case 'L':
253 263 /*
254 264 * -L number: # of times cmd is executed
255 265 * number *is* required here:
256 266 */
257 267 PER_LINE = TRUE;
258 268 N_ARGS = 0;
259 269 INSERT = FALSE;
260 270 if ((PER_LINE = atoi(optarg)) <= 0) {
261 271 ermsg(_("#lines must be positive int: %s\n"),
262 272 optarg);
263 273 }
264 274 break;
265 275
266 276 case 'l':
267 277 /*
268 278 * -l [number]: # of times cmd is executed
269 279 * N.B. that an argument *isn't* required here; if
270 280 * it's not given, then 1 is assumed.
271 281 *
272 282 * parseargs handles the optional arg processing.
273 283 */
274 284
275 285 PER_LINE = LEGAL = TRUE; /* initialization */
276 286 N_ARGS = 0;
277 287 INSERT = FALSE;
278 288
279 289 if ((optarg != NULL) && (*optarg != '\0')) {
280 290 if ((PER_LINE = atoi(optarg)) <= 0)
281 291 PER_LINE = 1;
282 292 }
283 293 break;
284 294
285 295 case 'n': /* -n number: # stdin args */
286 296 /*
287 297 * -n number: # stdin args.
288 298 * number *is* required here:
↓ open down ↓ |
102 lines elided |
↑ open up ↑ |
289 299 */
290 300 if ((N_ARGS = atoi(optarg)) <= 0) {
291 301 ermsg(_("#args must be positive int: %s\n"),
292 302 optarg);
293 303 } else {
294 304 LEGAL = DASHX || N_ARGS == 1;
295 305 INSERT = PER_LINE = FALSE;
296 306 }
297 307 break;
298 308
309 + case 'P': /* -P maxprocs: # of child processses */
310 + MAXPROCS = atoi(optarg);
311 + if (MAXPROCS <= 0) {
312 + ermsg(_("#maxprocs must be positive int: %s\n"),
313 + optarg);
314 + }
315 + break;
316 +
299 317 case 's': /* -s size: set max size of each arg list */
300 318 BUFLIM = atoi(optarg);
301 319 if (BUFLIM > BUFSIZE || BUFLIM <= 0) {
302 320 ermsg(_("0 < max-cmd-line-size <= %d: %s\n"),
303 321 BUFSIZE, optarg);
304 322 }
305 323 break;
306 324
307 325 case 'x': /* -x: terminate if args > size limit */
308 326 DASHX = LEGAL = TRUE;
309 327 break;
310 328
311 329 default:
312 330 /*
313 331 * bad argument. complain and get ready to die.
314 332 */
315 333 usage();
316 334 exit(2);
317 335 break;
318 336 }
319 337 }
320 338
321 339 /*
322 340 * if anything called ermsg(), something screwed up, so
323 341 * we exit early.
324 342 */
325 343 if (OK == FALSE) {
326 344 usage();
327 345 exit(2);
328 346 }
↓ open down ↓ |
20 lines elided |
↑ open up ↑ |
329 347
330 348 /*
331 349 * we're finished handling xargs's options, so now pick up
332 350 * the command name (if any), and it's options.
333 351 */
334 352
335 353
336 354 mac -= optind; /* dec arg count by what we've processed */
337 355 mav += optind; /* inc to current mav */
338 356
357 + (void) procs_malloc();
358 +
339 359 if (mac <= 0) { /* if there're no more args to process, */
340 360 cmdname = "/usr/bin/echo"; /* our default command */
341 361 *ARGV++ = addarg(cmdname); /* use the default cmd. */
342 362 } else { /* otherwise keep parsing rest of the string. */
343 363 /*
344 364 * note that we can't use getopts(3C), and *must* parse
345 365 * this by hand, as we don't know apriori what options the
346 366 * command will take.
347 367 */
348 368 cmdname = *mav; /* get the command name */
349 369
350 370
351 371 /* pick up the remaining args from the command line: */
352 372 while ((OK == TRUE) && (mac-- > 0)) {
353 373 /*
354 374 * while we haven't crapped out, and there's
355 375 * work to do:
356 376 */
357 377 if (INSERT && ! ERR) {
358 378 if (strstr(*mav, INSPAT) != NULL) {
359 379 if (++n_inserts > MAXINSERTS) {
360 380 ermsg(_("too many args "
361 381 "with %s\n"), INSPAT);
362 382 ERR = TRUE;
363 383 }
364 384 psave->p_ARGV = ARGV;
365 385 (psave++)->p_skel = *mav;
366 386 }
367 387 }
368 388 *ARGV++ = addarg(*mav++);
369 389 }
370 390 }
371 391
372 392 /* pick up args from standard input */
373 393
374 394 initlist = ARGV;
375 395 initsize = linesize;
376 396 lastarg[0] = '\0';
377 397
378 398 while (OK) {
379 399 N_args = 0;
380 400 N_lines = 0;
381 401 ARGV = initlist;
382 402 linesize = initsize;
383 403 next = argbuf;
384 404
385 405 while (MORE || (lastarg[0] != '\0')) {
386 406 int l;
387 407
388 408 if (*lastarg != '\0') {
389 409 arg = strcpy(next, lastarg);
390 410 *lastarg = '\0';
391 411 } else if ((arg = getarg(next)) == NULL) {
392 412 break;
393 413 }
394 414
395 415 l = strlen(arg) + 1;
396 416 linesize += l;
397 417 next += l;
398 418
↓ open down ↓ |
50 lines elided |
↑ open up ↑ |
399 419 /* Inserts are handled specially later. */
400 420 if ((n_inserts == 0) && (linesize >= BUFLIM)) {
401 421 /*
402 422 * Legal indicates hard fail if the list is
403 423 * truncated due to size. So fail, or if we
404 424 * cannot create any list because it would be
405 425 * too big.
406 426 */
407 427 if (LEGAL || N_args == 0) {
408 428 EMSG(LIST2LONG);
429 + (void) procs_wait(1);
409 430 exit(2);
410 431 /* NOTREACHED */
411 432 }
412 433
413 434 /*
414 435 * Otherwise just save argument for later.
415 436 */
416 437 (void) strcpy(lastarg, arg);
417 438 break;
418 439 }
419 440
420 441 *ARGV++ = arg;
421 442
422 443 N_args++;
423 444
424 445 if ((PER_LINE && N_lines >= PER_LINE) ||
425 446 (N_ARGS && (N_args) >= N_ARGS)) {
426 447 break;
427 448 }
↓ open down ↓ |
9 lines elided |
↑ open up ↑ |
428 449
429 450
430 451 if ((ARGV - arglist) == MAXARGS) {
431 452 break;
432 453 }
433 454 }
434 455
435 456 *ARGV = NULL;
436 457 if (N_args == 0) {
437 458 /* Reached the end with no more work. */
438 - exit(exitstat);
459 + break;
439 460 }
440 461
441 462 /* insert arg if requested */
442 463
443 464 if (!ERR && INSERT) {
444 465
445 466 p_ibuf = ins_buf;
446 467 ARGV--;
447 468 j = ibufsize = 0;
448 469 for (psave = saveargv; ++j <= n_inserts; ++psave) {
449 470 addibuf(psave);
450 471 if (ERR)
451 472 break;
452 473 }
453 474 }
454 475 *ARGV = NULL;
455 476
456 477 if (n_inserts > 0) {
↓ open down ↓ |
8 lines elided |
↑ open up ↑ |
457 478 /*
458 479 * if we've done any insertions, re-calculate the
459 480 * linesize. bomb out if we've exceeded our length.
460 481 */
461 482 linesize = 0;
462 483 for (ARGV = arglist; *ARGV != NULL; ARGV++) {
463 484 linesize += strlen(*ARGV) + 1;
464 485 }
465 486 if (linesize >= BUFLIM) {
466 487 EMSG(LIST2LONG);
488 + (void) procs_wait(1);
467 489 exit(2);
468 490 /* NOTREACHED */
469 491 }
470 492 }
471 493
472 494 /* exec command */
473 495
474 496 if (!ERR) {
475 497 if (!MORE &&
476 498 (PER_LINE && N_lines == 0 || N_ARGS && N_args == 0))
477 499 exit(exitstat);
478 500 OK = TRUE;
479 501 j = TRACE ? echoargs() : TRUE;
480 502 if (j) {
481 503 /*
482 504 * for xcu4, all invocations of cmdname must
483 505 * return 0, in order for us to return 0.
484 506 * so if we have a non-zero status here,
485 507 * quit immediately.
486 508 */
487 - exitstat |= lcall(cmdname, arglist);
509 + (void) lcall(cmdname, arglist);
488 510 }
489 511 }
490 512 }
491 513
514 + (void) procs_wait(1);
515 +
492 516 if (OK)
493 517 return (exitstat);
494 518
495 519 /*
496 520 * if exitstat was set, to match XCU4 complience,
497 521 * return that value, otherwise, return 1.
498 522 */
499 523 return (exitstat ? exitstat : 1);
500 524 }
501 525
502 526 static char *
503 527 addarg(char *arg)
504 528 {
505 529 linesize += (strlen(arg) + 1);
506 530 return (arg);
507 531 }
508 532
509 533
510 534 static void
511 535 store_str(char **buffer, char *str, size_t len)
512 536 {
513 537 (void) memcpy(*buffer, str, len);
514 538 (*buffer)[len] = '\0';
515 539 *buffer += len;
516 540 }
517 541
518 542
519 543 static char *
520 544 getarg(char *arg)
521 545 {
522 546 char *xarg = arg;
523 547 wchar_t c;
524 548 char mbc[MB_LEN_MAX];
525 549 size_t len;
526 550 int escape = 0;
527 551 int inquote = 0;
528 552
529 553 arg[0] = '\0';
530 554
531 555 while (MORE) {
532 556
533 557 len = 0;
534 558 c = getwchr(mbc, &len);
535 559
536 560 if (((arg - xarg) + len) > BUFLIM) {
537 561 EMSG2(ARG2LONG, BUFLIM);
538 562 exit(2);
539 563 ERR = TRUE;
540 564 return (NULL);
541 565 }
542 566
543 567 switch (c) {
544 568 case '\n':
545 569 if (ZERO) {
546 570 store_str(&arg, mbc, len);
547 571 continue;
548 572 }
549 573 /* FALLTHRU */
550 574
551 575 case '\0':
552 576 case WEOF: /* Note WEOF == EOF */
553 577
554 578 if (escape) {
555 579 EMSG(BADESCAPE);
556 580 ERR = TRUE;
557 581 return (NULL);
558 582 }
559 583 if (inquote) {
560 584 EMSG(MISSQUOTE);
561 585 ERR = TRUE;
562 586 return (NULL);
563 587 }
564 588
565 589 N_lines++;
566 590 break;
567 591
568 592 case '"':
569 593 if (ZERO || escape || (inquote == 1)) {
570 594 /* treat it literally */
571 595 escape = 0;
572 596 store_str(&arg, mbc, len);
573 597
574 598 } else if (inquote == 2) {
575 599 /* terminating double quote */
576 600 inquote = 0;
577 601
578 602 } else {
579 603 /* starting quoted string */
580 604 inquote = 2;
581 605 }
582 606 continue;
583 607
584 608 case '\'':
585 609 if (ZERO || escape || (inquote == 2)) {
586 610 /* treat it literally */
587 611 escape = 0;
588 612 store_str(&arg, mbc, len);
589 613
590 614 } else if (inquote == 1) {
591 615 /* terminating single quote */
592 616 inquote = 0;
593 617
594 618 } else {
595 619 /* starting quoted string */
596 620 inquote = 1;
597 621 }
598 622 continue;
599 623
600 624 case '\\':
601 625 /*
602 626 * Any unquoted character can be escaped by
603 627 * preceding it with a backslash.
604 628 */
605 629 if (ZERO || inquote || escape) {
606 630 escape = 0;
607 631 store_str(&arg, mbc, len);
608 632 } else {
609 633 escape = 1;
610 634 }
611 635 continue;
612 636
613 637 default:
614 638 /* most times we will just want to store it */
615 639 if (inquote || escape || ZERO || !iswctype(c, blank)) {
616 640 escape = 0;
617 641 store_str(&arg, mbc, len);
618 642 continue;
619 643 }
620 644 /* unquoted blank */
621 645 break;
622 646 }
623 647
624 648 /*
625 649 * At this point we are processing a complete argument.
626 650 */
627 651 if (strcmp(xarg, LEOF) == 0 && *LEOF != '\0') {
628 652 MORE = FALSE;
629 653 return (NULL);
630 654 }
631 655 if (c == WEOF) {
632 656 MORE = FALSE;
633 657 }
634 658 if (xarg[0] == '\0')
635 659 continue;
636 660 break;
637 661 }
638 662
639 663 return (xarg[0] == '\0' ? NULL : xarg);
640 664 }
641 665
642 666 /*
643 667 * ermsg(): print out an error message, and indicate failure globally.
644 668 *
645 669 * Assumes that message has already been gettext()'d. It would be
646 670 * nice if we could just do the gettext() here, but we can't, since
647 671 * since xgettext(1M) wouldn't be able to pick up our error message.
648 672 */
649 673 /* PRINTFLIKE1 */
650 674 static void
651 675 ermsg(char *messages, ...)
652 676 {
653 677 va_list ap;
654 678
655 679 va_start(ap, messages);
656 680
657 681 (void) fprintf(stderr, "xargs: ");
658 682 (void) vfprintf(stderr, messages, ap);
659 683
660 684 va_end(ap);
661 685 OK = FALSE;
662 686 }
663 687
664 688 static int
665 689 echoargs()
666 690 {
667 691 char **anarg;
668 692 char **tanarg; /* tmp ptr */
669 693 int i;
670 694 char reply[LINE_MAX];
671 695
672 696 tanarg = anarg = arglist-1;
673 697
674 698 /*
675 699 * write out each argument, separated by a space. the tanarg
676 700 * nonsense is for xcu4 testsuite compliance - so that an
677 701 * extra space isn't echoed after the last argument.
678 702 */
679 703 while (*++anarg) { /* while there's an argument */
680 704 ++tanarg; /* follow anarg */
681 705 (void) write(2, *anarg, strlen(*anarg));
682 706
683 707 if (*++tanarg) { /* if there's another argument: */
684 708 (void) write(2, " ", 1); /* add a space */
685 709 --tanarg; /* reset back to anarg */
686 710 }
687 711 }
688 712 if (PROMPT == -1) {
689 713 (void) write(2, "\n", 1);
690 714 return (TRUE);
691 715 }
692 716
693 717 (void) write(2, "?...", 4); /* ask the user for input */
694 718
695 719 for (i = 0; i < LINE_MAX && read(PROMPT, &reply[i], 1) > 0; i++) {
696 720 if (reply[i] == '\n') {
697 721 if (i == 0)
698 722 return (FALSE);
699 723 break;
700 724 }
701 725 }
702 726 reply[i] = 0;
703 727
704 728 /* flush remainder of line if necessary */
705 729 if (i == LINE_MAX) {
706 730 char bitbucket;
707 731
708 732 while ((read(PROMPT, &bitbucket, 1) > 0) && (bitbucket != '\n'))
709 733 ;
710 734 }
711 735
712 736 return (yes_check(reply));
713 737 }
714 738
715 739
716 740 static char *
717 741 insert(char *pattern, char *subst)
718 742 {
719 743 static char buffer[MAXSBUF+1];
720 744 int len, ipatlen;
721 745 char *pat;
722 746 char *bufend;
723 747 char *pbuf;
724 748
725 749 len = strlen(subst);
726 750 ipatlen = strlen(INSPAT) - 1;
727 751 pat = pattern - 1;
728 752 pbuf = buffer;
729 753 bufend = &buffer[MAXSBUF];
730 754
731 755 while (*++pat) {
732 756 if (strncmp(pat, INSPAT, ipatlen) == 0) {
733 757 if (pbuf + len >= bufend) {
734 758 break;
735 759 } else {
736 760 (void) strcpy(pbuf, subst);
737 761 pat += ipatlen;
738 762 pbuf += len;
739 763 }
740 764 } else {
741 765 *pbuf++ = *pat;
742 766 if (pbuf >= bufend)
743 767 break;
744 768 }
745 769 }
746 770
747 771 if (!*pat) {
748 772 *pbuf = '\0';
749 773 return (buffer);
750 774 } else {
751 775 ermsg(gettext("Maximum argument size with insertion via %s's "
752 776 "exceeded\n"), INSPAT);
753 777 ERR = TRUE;
754 778 return (NULL);
755 779 }
756 780 }
757 781
758 782
759 783 static void
760 784 addibuf(struct inserts *p)
761 785 {
762 786 char *newarg, *skel, *sub;
763 787 int l;
764 788
765 789 skel = p->p_skel;
766 790 sub = *ARGV;
767 791 newarg = insert(skel, sub);
768 792 if (ERR)
769 793 return;
770 794
771 795 l = strlen(newarg) + 1;
772 796 if ((ibufsize += l) > MAXIBUF) {
773 797 EMSG(IBUFOVERFLOW);
774 798 ERR = TRUE;
775 799 }
776 800 (void) strcpy(p_ibuf, newarg);
777 801 *(p->p_ARGV) = p_ibuf;
778 802 p_ibuf += l;
779 803 }
780 804
781 805
782 806 /*
783 807 * getwchr(): get the next wide character.
784 808 * description:
785 809 * we get the next character from stdin. This returns WEOF if no
786 810 * character is present. If ZERO is set, it gets a single byte instead
787 811 * a wide character.
788 812 */
789 813 static wint_t
790 814 getwchr(char *mbc, size_t *sz)
791 815 {
792 816 size_t i;
793 817 int c;
794 818 wchar_t wch;
795 819
796 820 i = 0;
797 821 while (i < MB_CUR_MAX) {
798 822
799 823 if ((c = fgetc(stdin)) == EOF) {
800 824
801 825 if (i == 0) {
802 826 /* TRUE EOF has been reached */
803 827 return (WEOF);
804 828 }
805 829
806 830 /*
807 831 * We have some characters in our buffer still so it
808 832 * must be an invalid character right before EOF.
809 833 */
810 834 break;
811 835 }
812 836 mbc[i++] = (char)c;
813 837
814 838 /* If this succeeds then we are done */
815 839 if (ZERO) {
816 840 *sz = i;
817 841 return ((char)c);
818 842 }
819 843 if (mbtowc(&wch, mbc, i) != -1) {
820 844 *sz = i;
821 845 return ((wint_t)wch);
822 846 }
823 847 }
824 848
825 849 /*
826 850 * We have now encountered an illegal character sequence.
827 851 * There is nothing much we can do at this point but
828 852 * return an error. If we attempt to recover we may in fact
829 853 * return garbage as arguments, from the customer's point
↓ open down ↓ |
328 lines elided |
↑ open up ↑ |
830 854 * of view. After all what if they are feeding us a file
831 855 * generated in another locale?
832 856 */
833 857 errno = EILSEQ;
834 858 PERR(CORRUPTFILE);
835 859 exit(1);
836 860 /* NOTREACHED */
837 861 }
838 862
839 863
840 -static int
864 +static void
841 865 lcall(char *sub, char **subargs)
842 866 {
843 - int retcode, retry = 0;
844 - pid_t iwait, child;
867 + int retry = 0;
868 + pid_t child;
845 869
846 870 for (;;) {
847 871 switch (child = fork()) {
848 872 default:
849 - while ((iwait = wait(&retcode)) != child &&
850 - iwait != (pid_t)-1)
851 - ;
852 - if (iwait == (pid_t)-1) {
853 - PERR(WAITFAIL);
854 - exit(122);
855 - /* NOTREACHED */
856 - }
857 - if (WIFSIGNALED(retcode)) {
858 - EMSG2(CHILDSIG, WTERMSIG(retcode));
859 - exit(125);
860 - /* NOTREACHED */
861 - }
862 - if ((WEXITSTATUS(retcode) & 0377) == 0377) {
863 - EMSG(CHILDFAIL);
864 - exit(124);
865 - /* NOTREACHED */
866 - }
867 - return (WEXITSTATUS(retcode));
873 + (void) procs_store(child);
874 + (void) procs_wait(0);
875 + return;
868 876 case 0:
869 877 (void) execvp(sub, subargs);
870 878 PERR(EXECFAIL);
871 879 if (errno == EACCES)
872 880 exit(126);
873 881 exit(127);
874 882 /* NOTREACHED */
875 883 case -1:
876 884 if (errno != EAGAIN && retry++ < FORK_RETRY) {
877 885 PERR(FORKFAIL);
878 886 exit(123);
879 887 }
880 888 (void) sleep(1);
881 889 }
882 890 }
883 891 }
884 892
893 +static void
894 +procs_malloc(void)
895 +{
896 + int i;
897 +
898 + procs = (pid_t *)(malloc(MAXPROCS * sizeof(pid_t)));
899 + if (procs == NULL) {
900 + PERR(MALLOCFAIL);
901 + exit(1);
902 + }
903 +
904 + for (i = 0; i < MAXPROCS; i++) {
905 + procs[i] = (pid_t)(0);
906 + }
907 +}
908 +
909 +static int
910 +procs_find(pid_t child)
911 +{
912 + int i;
913 +
914 + for (i = 0; i < MAXPROCS; i++) {
915 + if (procs[i] == child) {
916 + return (i);
917 + }
918 + }
919 +
920 + return (-1);
921 +}
922 +
923 +static void
924 +procs_store(pid_t child)
925 +{
926 + int i;
927 +
928 + i = procs_find((pid_t)(0));
929 + if (i < 0) {
930 + PERR(NOCHILDSLOT);
931 + exit(1);
932 + }
933 + procs[i] = child;
934 + n_procs++;
935 +}
936 +
937 +static int
938 +procs_delete(pid_t child)
939 +{
940 + int i;
941 +
942 + i = procs_find(child);
943 + if (i < 0) {
944 + return (0);
945 + }
946 + procs[i] = (pid_t)(0);
947 + n_procs--;
948 + return (1);
949 +}
950 +
951 +static pid_t
952 +procs_waitpid(int blocking, int *stat_loc)
953 +{
954 + pid_t child;
955 + int options;
956 +
957 + if (n_procs == 0) {
958 + errno = ECHILD;
959 + return (-1);
960 + }
961 +
962 + options = (blocking) ? 0 : WNOHANG;
963 +
964 + while ((child = waitpid(-1, stat_loc, options)) > 0) {
965 + if (procs_delete(child)) {
966 + break;
967 + }
968 + }
969 +
970 + return (child);
971 +}
972 +
973 +static void
974 +procs_wait(int blocking)
975 +{
976 + pid_t child;
977 + int stat_loc;
978 +
979 + while ((child = procs_waitpid(blocking || (n_procs >= MAXPROCS) ? 1 : 0, &stat_loc)) > 0) {
980 + if (WIFSIGNALED(stat_loc)) {
981 + EMSG2(CHILDSIG, WTERMSIG(stat_loc));
982 + exit(125);
983 + /* NOTREACHED */
984 + } else if ((WEXITSTATUS(stat_loc) & 0377) == 0377) {
985 + EMSG(CHILDFAIL);
986 + exit(124);
987 + /* NOTREACHED */
988 + } else {
989 + exitstat |= WEXITSTATUS(stat_loc);
990 + }
991 + }
992 +
993 + if (child == (pid_t)(-1) && errno != ECHILD) {
994 + EMSG(WAITFAIL);
995 + exit(122);
996 + /* NOTREACHED */
997 + }
998 +}
885 999
886 1000 static void
887 1001 usage()
888 1002 {
889 1003 ermsg(_(USAGEMSG));
890 1004 OK = FALSE;
891 1005 }
892 1006
893 1007
894 1008
895 1009 /*
896 1010 * parseargs(): modify the args
897 1011 * since the -e, -i and -l flags all take optional subarguments,
898 1012 * and getopts(3C) is clueless about this nonsense, we change the
899 1013 * our local argument count and strings to separate this out,
900 1014 * and make it easier to handle via getopts(3c).
901 1015 *
902 1016 * -e -> "-e ""
903 1017 * -e3 -> "-e "3"
904 1018 * -Estr -> "-E "str"
905 1019 * -i -> "-i "{}"
906 1020 * -irep -> "-i "rep"
907 1021 * -l -> "-i "1"
908 1022 * -l10 -> "-i "10"
909 1023 *
910 1024 * since the -e, -i and -l flags all take optional subarguments,
911 1025 */
912 1026 static void
913 1027 parseargs(int ac, char **av)
914 1028 {
915 1029 int i; /* current argument */
916 1030 int cflag; /* 0 = not processing cmd arg */
917 1031
918 1032 if ((mav = malloc((ac * 2 + 1) * sizeof (char *))) == NULL) {
919 1033 PERR(MALLOCFAIL);
920 1034 exit(1);
921 1035 }
922 1036
923 1037 /* for each argument, see if we need to change things: */
924 1038 for (i = mac = cflag = 0; (av[i] != NULL) && i < ac; i++, mac++) {
925 1039 if ((mav[mac] = strdup(av[i])) == NULL) {
926 1040 PERR(MALLOCFAIL);
927 1041 exit(1);
928 1042 }
929 1043
930 1044 /* -- has been found or argument list is fully processes */
931 1045 if (cflag)
932 1046 continue;
933 1047
934 1048 /*
935 1049 * if we're doing special processing, and we've got a flag
936 1050 */
937 1051 else if ((av[i][0] == '-') && (av[i][1] != NULL)) {
938 1052 char *def;
939 1053
940 1054 switch (av[i][1]) {
941 1055 case 'e':
942 1056 def = ""; /* -e with no arg turns off eof */
943 1057 goto process_special;
944 1058 case 'i':
945 1059 def = INSPAT_STR;
946 1060 goto process_special;
947 1061 case 'l':
948 1062 def = "1";
949 1063 process_special:
950 1064 /*
951 1065 * if there's no sub-option, we *must* add
952 1066 * a default one. this is because xargs must
953 1067 * be able to distinguish between a valid
954 1068 * suboption, and a command name.
955 1069 */
956 1070 if (av[i][2] == NULL) {
957 1071 mav[++mac] = strdup(def);
958 1072 } else {
959 1073 /* clear out our version: */
960 1074 mav[mac][2] = NULL;
961 1075 mav[++mac] = strdup(&av[i][2]);
962 1076 }
963 1077 if (mav[mac] == NULL) {
964 1078 PERR(MALLOCFAIL);
965 1079 exit(1);
966 1080 }
967 1081 break;
968 1082
969 1083 /* flags with required subarguments: */
970 1084
971 1085 /*
972 1086 * there are two separate cases here. either the
↓ open down ↓ |
78 lines elided |
↑ open up ↑ |
973 1087 * flag can have the normal XCU4 handling
974 1088 * (of the form: -X subargument); or it can have
975 1089 * the old solaris 2.[0-4] handling (of the
976 1090 * form: -Xsubargument). in order to maintain
977 1091 * backwards compatibility, we must support the
978 1092 * latter case. we handle the latter possibility
979 1093 * first so both the old solaris way of handling
980 1094 * and the new XCU4 way of handling things are allowed.
981 1095 */
982 1096 case 'n': /* FALLTHROUGH */
1097 + case 'P': /* FALLTHROUGH */
983 1098 case 's': /* FALLTHROUGH */
984 1099 case 'E': /* FALLTHROUGH */
985 1100 case 'I': /* FALLTHROUGH */
986 1101 case 'L':
987 1102 /*
988 1103 * if the second character isn't null, then
989 1104 * the user has specified the old syntax.
990 1105 * we move the subargument into our
991 1106 * mod'd argument list.
992 1107 */
993 1108 if (av[i][2] != NULL) {
994 1109 /* first clean things up: */
995 1110 mav[mac][2] = NULL;
996 1111
997 1112 /* now add the separation: */
998 1113 ++mac; /* inc to next mod'd arg */
999 1114 if ((mav[mac] = strdup(&av[i][2])) ==
1000 1115 NULL) {
1001 1116 PERR(MALLOCFAIL);
1002 1117 exit(1);
1003 1118 }
1004 1119 break;
1005 1120 }
1006 1121 i++;
1007 1122 mac++;
1008 1123
1009 1124 if (av[i] == NULL) {
1010 1125 mav[mac] = NULL;
1011 1126 return;
1012 1127 }
1013 1128 if ((mav[mac] = strdup(av[i])) == NULL) {
1014 1129 PERR(MALLOCFAIL);
1015 1130 exit(1);
1016 1131 }
1017 1132 break;
1018 1133
1019 1134 /* flags */
1020 1135 case 'p' :
1021 1136 case 't' :
1022 1137 case 'x' :
1023 1138 case '0' :
1024 1139 break;
1025 1140
1026 1141 case '-' :
1027 1142 default:
1028 1143 /*
1029 1144 * here we've hit the cmd argument. so
1030 1145 * we'll stop special processing, as the
1031 1146 * cmd may have a "-i" etc., argument,
1032 1147 * and we don't want to add a "" to it.
1033 1148 */
1034 1149 cflag = 1;
1035 1150 break;
1036 1151 }
1037 1152 } else if (i > 0) { /* if we're not the 1st arg */
1038 1153 /*
1039 1154 * if it's not a flag, then it *must* be the cmd.
1040 1155 * set cflag, so we don't mishandle the -[eil] flags.
1041 1156 */
1042 1157 cflag = 1;
1043 1158 }
1044 1159 }
1045 1160
1046 1161 mav[mac] = NULL;
1047 1162 }
↓ open down ↓ |
55 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX