1: /*- 2: * Copyright (c) 1990, 1993 3: * The Regents of the University of California. All rights reserved. 4: * 5: * This code is derived from software contributed to Berkeley by 6: * John B. Roll Jr. 7: * 8: * Redistribution and use in source and binary forms, with or without 9: * modification, are permitted provided that the following conditions 10: * are met: 11: * 1. Redistributions of source code must retain the above copyright 12: * notice, this list of conditions and the following disclaimer. 13: * 2. Redistributions in binary form must reproduce the above copyright 14: * notice, this list of conditions and the following disclaimer in the 15: * documentation and/or other materials provided with the distribution. 16: * 3. All advertising materials mentioning features or use of this software 17: * must display the following acknowledgement: 18: * This product includes software developed by the University of 19: * California, Berkeley and its contributors. 20: * 4. Neither the name of the University nor the names of its contributors 21: * may be used to endorse or promote products derived from this software 22: * without specific prior written permission. 23: * 24: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34: * SUCH DAMAGE. 35: */ 36: 37: #if defined(DOSCCS) && !defined(lint) 38: static char copyright[] = 39: "@(#) Copyright (c) 1990, 1993\n\ 40: The Regents of the University of California. All rights reserved.\n"; 41: #endif 42: 43: #if defined(DOSCCS) && !defined(lint) 44: static char sccsid[] = "@(#)xargs.c 8.1 (Berkeley) 6/6/93"; 45: #endif 46: 47: #include <sys/param.h> 48: #include <sys/types.h> 49: #include <sys/wait.h> 50: #include <errno.h> 51: #include <stdio.h> 52: #include "pathnames.h" 53: 54: extern int errno; 55: extern char *optarg; 56: extern int optind; 57: 58: /* 59: * This is defined for pdp11s. ARG_MAX is usually defined in 60: * an include file. I have left it here until such times as 61: * the system limits stuff in machparam etc is changed to the 62: * same names as 4.4. Note that 63: * this is much smaller than the normal value cos it's only a 64: * small computer (sigh). 65: */ 66: 67: #define ARG_MAX NCARGS 68: 69: int tflag, rval; 70: 71: void err(); 72: void run(); 73: void usage(); 74: 75: main(argc, argv) 76: int argc; 77: char **argv; 78: { 79: register int ch; 80: register char *p, *bbp, *ebp, **bxp, **exp, **xp; 81: int cnt, indouble, insingle, nargs, nflag, nline, xflag; 82: char **av, *argp; 83: 84: /* 85: * POSIX.2 limits the exec line length to ARG_MAX - 2K. Running that 86: * caused some E2BIG errors, so it was changed to ARG_MAX - 4K. Given 87: * that the smallest argument is 2 bytes in length, this means that 88: * the number of arguments is limited to: 89: * 90: * (ARG_MAX - 4K - LENGTH(utility + arguments)) / 2. 91: * 92: * We arbitrarily limit the number of arguments to 5000. This is 93: * allowed by POSIX.2 as long as the resulting minimum exec line is 94: * at least LINE_MAX. Realloc'ing as necessary is possible, but 95: * probably not worthwhile. 96: */ 97: nargs = 5000; 98: nline = ARG_MAX - 4 * 1024; 99: nflag = xflag = 0; 100: while ((ch = getopt(argc, argv, "n:s:tx")) != EOF) 101: switch(ch) { 102: case 'n': 103: nflag = 1; 104: if ((nargs = atoi(optarg)) <= 0) 105: err("illegal argument count"); 106: break; 107: case 's': 108: nline = atoi(optarg); 109: break; 110: case 't': 111: tflag = 1; 112: break; 113: case 'x': 114: xflag = 1; 115: break; 116: case '?': 117: default: 118: usage(); 119: } 120: argc -= optind; 121: argv += optind; 122: 123: if (xflag && !nflag) 124: usage(); 125: 126: /* 127: * Allocate pointers for the utility name, the utility arguments, 128: * the maximum arguments to be read from stdin and the trailing 129: * NULL. 130: */ 131: if (!(av = bxp = 132: (char **)malloc((u_int)(1 + argc + nargs + 1) * sizeof(char **)))) 133: err("%s", strerror(errno)); 134: 135: /* 136: * Use the user's name for the utility as argv[0], just like the 137: * shell. Echo is the default. Set up pointers for the user's 138: * arguments. 139: */ 140: if (!*argv) 141: cnt = strlen(*bxp++ = _PATH_ECHO); 142: else { 143: cnt = 0; 144: do { 145: cnt += strlen(*bxp++ = *argv) + 1; 146: } while (*++argv); 147: } 148: 149: /* 150: * Set up begin/end/traversing pointers into the array. The -n 151: * count doesn't include the trailing NULL pointer, so the malloc 152: * added in an extra slot. 153: */ 154: exp = (xp = bxp) + nargs; 155: 156: /* 157: * Allocate buffer space for the arguments read from stdin and the 158: * trailing NULL. Buffer space is defined as the default or specified 159: * space, minus the length of the utility name and arguments. Set up 160: * begin/end/traversing pointers into the array. The -s count does 161: * include the trailing NULL, so the malloc didn't add in an extra 162: * slot. 163: */ 164: nline -= cnt; 165: if (nline <= 0) 166: err("insufficient space for command"); 167: 168: if (!(bbp = (char *)malloc((u_int)nline + 1))) 169: err("%s", strerror(errno)); 170: ebp = (argp = p = bbp) + nline - 1; 171: 172: for (insingle = indouble = 0;;) 173: switch(ch = getchar()) { 174: case EOF: 175: /* No arguments since last exec. */ 176: if (p == bbp) 177: exit(rval); 178: 179: /* Nothing since end of last argument. */ 180: if (argp == p) { 181: *xp = NULL; 182: run(av); 183: exit(rval); 184: } 185: goto arg1; 186: case ' ': 187: case '\t': 188: /* Quotes escape tabs and spaces. */ 189: if (insingle || indouble) 190: goto addch; 191: goto arg2; 192: case '\n': 193: /* Empty lines are skipped. */ 194: if (argp == p) 195: continue; 196: 197: /* Quotes do not escape newlines. */ 198: arg1: if (insingle || indouble) 199: err("unterminated quote"); 200: 201: arg2: *p = '\0'; 202: *xp++ = argp; 203: 204: /* 205: * If max'd out on args or buffer, or reached EOF, 206: * run the command. If xflag and max'd out on buffer 207: * but not on args, object. 208: */ 209: if (xp == exp || p == ebp || ch == EOF) { 210: if (xflag && xp != exp && p == ebp) 211: err("insufficient space for arguments"); 212: *xp = NULL; 213: run(av); 214: if (ch == EOF) 215: exit(rval); 216: p = bbp; 217: xp = bxp; 218: } else 219: ++p; 220: argp = p; 221: break; 222: case '\'': 223: if (indouble) 224: goto addch; 225: insingle = !insingle; 226: break; 227: case '"': 228: if (insingle) 229: goto addch; 230: indouble = !indouble; 231: break; 232: case '\\': 233: /* Backslash escapes anything, is escaped by quotes. */ 234: if (!insingle && !indouble && (ch = getchar()) == EOF) 235: err("backslash at EOF"); 236: /* FALLTHROUGH */ 237: default: 238: addch: if (p < ebp) { 239: *p++ = ch; 240: break; 241: } 242: 243: /* If only one argument, not enough buffer space. */ 244: if (bxp == xp) 245: err("insufficient space for argument"); 246: /* Didn't hit argument limit, so if xflag object. */ 247: if (xflag) 248: err("insufficient space for arguments"); 249: 250: *xp = NULL; 251: run(av); 252: xp = bxp; 253: cnt = ebp - argp; 254: bcopy(argp, bbp, cnt); 255: p = (argp = bbp) + cnt; 256: *p++ = ch; 257: break; 258: } 259: /* NOTREACHED */ 260: } 261: 262: void 263: run(argv) 264: char **argv; 265: { 266: int noinvoke; 267: register char **p; 268: pid_t pid; 269: union wait status; 270: 271: if (tflag) { 272: (void)fprintf(stderr, "%s", *argv); 273: for (p = argv + 1; *p; ++p) 274: (void)fprintf(stderr, " %s", *p); 275: (void)fprintf(stderr, "\n"); 276: (void)fflush(stderr); 277: } 278: noinvoke = 0; 279: switch(pid = vfork()) { 280: case -1: 281: err("vfork: %s", strerror(errno)); 282: case 0: 283: execvp(argv[0], argv); 284: (void)fprintf(stderr, 285: "xargs: %s: %s\n", argv[0], strerror(errno)); 286: noinvoke = 1; 287: _exit(1); 288: } 289: pid = waitpid(pid, &status, 0); 290: if (pid == -1) 291: err("waitpid: %s", strerror(errno)); 292: /* If we couldn't invoke the utility, exit 127. */ 293: if (noinvoke) 294: exit(127); 295: /* If utility signaled or exited with a value of 255, exit 1-125. */ 296: if (WIFSIGNALED(status) || WEXITSTATUS(status) == 255) 297: exit(1); 298: if (WEXITSTATUS(status)) 299: rval = 1; 300: } 301: 302: void 303: usage() 304: { 305: (void)fprintf(stderr, 306: "usage: xargs [-t] [-n number [-x]] [-s size] [utility [argument ...]]\n"); 307: exit(1); 308: } 309: 310: #if __STDC__ 311: #include <stdarg.h> 312: #else 313: #include <varargs.h> 314: #endif 315: 316: void 317: #if __STDC__ 318: err(const char *fmt, ...) 319: #else 320: err(fmt, va_alist) 321: char *fmt; 322: va_dcl 323: #endif 324: { 325: va_list ap; 326: #if __STDC__ 327: va_start(ap, fmt); 328: #else 329: va_start(ap); 330: #endif 331: (void)fprintf(stderr, "xargs: "); 332: (void)vfprintf(stderr, fmt, ap); 333: va_end(ap); 334: (void)fprintf(stderr, "\n"); 335: exit(1); 336: /* NOTREACHED */ 337: }