1 /*- 2 * Copyright (c) 1990 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * John B. Roll Jr. 7 * 8 * %sccs.include.redist.c% 9 */ 10 11 #ifndef lint 12 char copyright[] = 13 "@(#) Copyright (c) 1990 The Regents of the University of California.\n\ 14 All rights reserved.\n"; 15 #endif /* not lint */ 16 17 #ifndef lint 18 static char sccsid[] = "@(#)xargs.c 5.7 (Berkeley) 03/05/91"; 19 #endif /* not lint */ 20 21 #include <sys/types.h> 22 #include <sys/wait.h> 23 #include <errno.h> 24 #include <stdio.h> 25 #include <stdlib.h> 26 #include <string.h> 27 #include <unistd.h> 28 #include <limits.h> 29 #include "pathnames.h" 30 31 #define DEF_ARGC 255 32 33 int tflag; 34 int fflag; 35 36 main(argc, argv) 37 int argc; 38 char **argv; 39 { 40 extern int errno, optind; 41 extern char *optarg; 42 register int ch; 43 register char *p, *bp, *endbp, **bxp, **endxp, **xp; 44 int cnt, indouble, insingle, nargs, nline; 45 char *mark, *prog, **xargs; 46 47 nargs = DEF_ARGC; 48 nline = _POSIX2_LINE_MAX; 49 50 while ((ch = getopt(argc, argv, "n:s:tf")) != EOF) 51 switch(ch) { 52 case 'n': 53 if ((nargs = atoi(optarg)) <= 0) { 54 (void)fprintf(stderr, 55 "xargs: bad argument count.\n"); 56 exit(1); 57 } 58 break; 59 case 's': 60 if ((nline = atoi(optarg)) <= 0) { 61 (void)fprintf(stderr, 62 "xargs: bad command length.\n"); 63 exit(1); 64 } 65 break; 66 case 't': 67 tflag = 1; 68 break; 69 case 'f': 70 fflag = 1; 71 break; 72 case '?': 73 default: 74 usage(); 75 } 76 argc -= optind; 77 argv += optind; 78 79 /* room for the command, leftover arguments and trailing NULL */ 80 if (!(xargs = 81 (char **)malloc((u_int)(nargs + argc + 2) * sizeof(char **)))) 82 enomem(); 83 84 if (!(bp = malloc((u_int)nline + 1))) 85 enomem(); 86 87 xp = xargs + 1; 88 if (!*argv) 89 prog = _PATH_ECHO; 90 else { 91 prog = *argv; 92 while (*++argv) 93 *xp++ = *argv; 94 } 95 96 if (xargs[0] = rindex(prog, '/')) 97 ++xargs[0]; 98 else 99 xargs[0] = prog; 100 101 /* set up the pointers into the buffer and the arguments */ 102 *(endxp = (bxp = xp) + nargs) = NULL; 103 endbp = (mark = p = bp) + nline; 104 105 insingle = indouble = 0; 106 for (;;) 107 switch(ch = getchar()) { 108 case EOF: 109 if (p == bp) /* nothing to display */ 110 exit(0); 111 if (mark == p) { /* nothing since last arg end */ 112 *xp = NULL; 113 run(prog, xargs); 114 exit(0); 115 } 116 goto addarg; 117 case ' ': 118 case '\t': 119 if (insingle || indouble) 120 goto addch; 121 goto addarg; 122 case '\n': 123 if (mark == p) /* empty line */ 124 continue; 125 addarg: *xp++ = mark; 126 *p++ = '\0'; 127 if (xp == endxp || p >= endbp || ch == EOF) { 128 if (insingle || indouble) { 129 (void)fprintf(stderr, 130 "xargs: unterminated quote.\n"); 131 exit(1); 132 } 133 *xp = NULL; 134 run(prog, xargs); 135 if (ch == EOF) 136 exit(0); 137 p = bp; 138 xp = bxp; 139 } 140 mark = p; 141 break; 142 case '\'': 143 if (indouble) 144 goto addch; 145 insingle = !insingle; 146 break; 147 case '"': 148 if (insingle) 149 goto addch; 150 indouble = !indouble; 151 break; 152 case '\\': 153 if ((ch = getchar()) == EOF) 154 ch = '\\'; 155 if (ch == '\n') { 156 (void)fprintf(stderr, 157 "xargs: newline may not be escaped.\n"); 158 exit(1); 159 } 160 /* FALLTHROUGH */ 161 default: 162 addch: if (p != endbp) { 163 *p++ = ch; 164 continue; 165 } 166 if (xp == bxp) { 167 (void)fprintf(stderr, 168 "xargs: argument too large.\n"); 169 exit(1); 170 } 171 *xp = NULL; 172 run(prog, xargs); 173 cnt = endbp - mark; 174 bcopy(mark, bp, cnt); 175 p = (mark = bp) + cnt; 176 *p++ = ch; 177 xp = bxp; 178 break; 179 } 180 /* NOTREACHED */ 181 } 182 183 run(prog, argv) 184 char *prog, **argv; 185 { 186 union wait pstat; 187 pid_t pid; 188 char **p; 189 190 if (tflag) { 191 (void)fprintf(stderr, "%s", *argv); 192 for (p = argv + 1; *p; ++p) 193 (void)fprintf(stderr, " %s", *p); 194 (void)fprintf(stderr, "\n"); 195 (void)fflush(stderr); 196 } 197 switch(pid = vfork()) { 198 case -1: 199 (void)fprintf(stderr, 200 "xargs: vfork: %s.\n", strerror(errno)); 201 exit(1); 202 case 0: 203 execvp(prog, argv); 204 (void)fprintf(stderr, 205 "xargs: %s: %s.\n", prog, strerror(errno)); 206 _exit(1); 207 } 208 pid = waitpid(pid, (int *)&pstat, 0); 209 if (pid == -1) { 210 (void)fprintf(stderr, 211 "xargs: waitpid: %s.\n", strerror(errno)); 212 exit(1); 213 } 214 if (!fflag && pstat.w_status) 215 exit(1); 216 } 217 218 enomem() 219 { 220 (void)fprintf(stderr, "xargs: %s.\n", strerror(ENOMEM)); 221 exit(1); 222 } 223 224 usage() 225 { 226 (void)fprintf(stderr, 227 "xargs: [-t] [-f] [-n number] [-s size] [utility [argument ...]]\n"); 228 exit(1); 229 } 230