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: }

Defined functions

err defined in line 316; used 12 times
main defined in line 75; never used
run defined in line 262; used 4 times
usage defined in line 302; used 3 times

Defined variables

copyright defined in line 38; never used
rval defined in line 69; used 4 times
sccsid defined in line 44; never used
tflag defined in line 69; used 2 times

Defined macros

ARG_MAX defined in line 67; used 1 times
  • in line 98
Last modified: 1995-06-24
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 3400
Valid CSS Valid XHTML 1.0 Strict