1*8462SApril.Chin@Sun.COM /*********************************************************************** 2*8462SApril.Chin@Sun.COM * * 3*8462SApril.Chin@Sun.COM * This software is part of the ast package * 4*8462SApril.Chin@Sun.COM * Copyright (c) 1985-2008 AT&T Intellectual Property * 5*8462SApril.Chin@Sun.COM * and is licensed under the * 6*8462SApril.Chin@Sun.COM * Common Public License, Version 1.0 * 7*8462SApril.Chin@Sun.COM * by AT&T Intellectual Property * 8*8462SApril.Chin@Sun.COM * * 9*8462SApril.Chin@Sun.COM * A copy of the License is available at * 10*8462SApril.Chin@Sun.COM * http://www.opensource.org/licenses/cpl1.0.txt * 11*8462SApril.Chin@Sun.COM * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * 12*8462SApril.Chin@Sun.COM * * 13*8462SApril.Chin@Sun.COM * Information and Software Systems Research * 14*8462SApril.Chin@Sun.COM * AT&T Research * 15*8462SApril.Chin@Sun.COM * Florham Park NJ * 16*8462SApril.Chin@Sun.COM * * 17*8462SApril.Chin@Sun.COM * Glenn Fowler <gsf@research.att.com> * 18*8462SApril.Chin@Sun.COM * David Korn <dgk@research.att.com> * 19*8462SApril.Chin@Sun.COM * Phong Vo <kpv@research.att.com> * 20*8462SApril.Chin@Sun.COM * * 21*8462SApril.Chin@Sun.COM ***********************************************************************/ 22*8462SApril.Chin@Sun.COM #pragma prototyped 23*8462SApril.Chin@Sun.COM /* 24*8462SApril.Chin@Sun.COM * Glenn Fowler 25*8462SApril.Chin@Sun.COM * AT&T Research 26*8462SApril.Chin@Sun.COM * 27*8462SApril.Chin@Sun.COM * xargs/tw command arg list support 28*8462SApril.Chin@Sun.COM */ 29*8462SApril.Chin@Sun.COM 30*8462SApril.Chin@Sun.COM #include <ast.h> 31*8462SApril.Chin@Sun.COM #include <ctype.h> 32*8462SApril.Chin@Sun.COM #include <error.h> 33*8462SApril.Chin@Sun.COM #include <proc.h> 34*8462SApril.Chin@Sun.COM 35*8462SApril.Chin@Sun.COM #include "cmdarg.h" 36*8462SApril.Chin@Sun.COM 37*8462SApril.Chin@Sun.COM #ifndef EXIT_QUIT 38*8462SApril.Chin@Sun.COM #define EXIT_QUIT 255 39*8462SApril.Chin@Sun.COM #endif 40*8462SApril.Chin@Sun.COM 41*8462SApril.Chin@Sun.COM static const char* echo[] = { "echo", 0 }; 42*8462SApril.Chin@Sun.COM 43*8462SApril.Chin@Sun.COM /* 44*8462SApril.Chin@Sun.COM * open a cmdarg stream 45*8462SApril.Chin@Sun.COM * initialize the command for execution 46*8462SApril.Chin@Sun.COM * argv[-1] is reserved for procrun(PROC_ARGMOD) 47*8462SApril.Chin@Sun.COM */ 48*8462SApril.Chin@Sun.COM 49*8462SApril.Chin@Sun.COM Cmdarg_t* 50*8462SApril.Chin@Sun.COM cmdopen(char** argv, int argmax, int size, const char* argpat, int flags) 51*8462SApril.Chin@Sun.COM { 52*8462SApril.Chin@Sun.COM register Cmdarg_t* cmd; 53*8462SApril.Chin@Sun.COM register int n; 54*8462SApril.Chin@Sun.COM register char** p; 55*8462SApril.Chin@Sun.COM register char* s; 56*8462SApril.Chin@Sun.COM char* sh; 57*8462SApril.Chin@Sun.COM int c; 58*8462SApril.Chin@Sun.COM int m; 59*8462SApril.Chin@Sun.COM int argc; 60*8462SApril.Chin@Sun.COM long x; 61*8462SApril.Chin@Sun.COM 62*8462SApril.Chin@Sun.COM char** post = 0; 63*8462SApril.Chin@Sun.COM 64*8462SApril.Chin@Sun.COM n = sizeof(char**); 65*8462SApril.Chin@Sun.COM if (*argv) 66*8462SApril.Chin@Sun.COM { 67*8462SApril.Chin@Sun.COM for (p = argv + 1; *p; p++) 68*8462SApril.Chin@Sun.COM { 69*8462SApril.Chin@Sun.COM if ((flags & CMD_POST) && argpat && streq(*p, argpat)) 70*8462SApril.Chin@Sun.COM { 71*8462SApril.Chin@Sun.COM *p = 0; 72*8462SApril.Chin@Sun.COM post = p + 1; 73*8462SApril.Chin@Sun.COM argpat = 0; 74*8462SApril.Chin@Sun.COM } 75*8462SApril.Chin@Sun.COM else 76*8462SApril.Chin@Sun.COM n += strlen(*p) + 1; 77*8462SApril.Chin@Sun.COM } 78*8462SApril.Chin@Sun.COM argc = p - argv; 79*8462SApril.Chin@Sun.COM } 80*8462SApril.Chin@Sun.COM else 81*8462SApril.Chin@Sun.COM argc = 0; 82*8462SApril.Chin@Sun.COM for (p = environ; *p; p++) 83*8462SApril.Chin@Sun.COM n += sizeof(char**) + strlen(*p) + 1; 84*8462SApril.Chin@Sun.COM if ((x = strtol(astconf("ARG_MAX", NiL, NiL), NiL, 0)) <= 0) 85*8462SApril.Chin@Sun.COM x = ARG_MAX; 86*8462SApril.Chin@Sun.COM if (size <= 0 || size > x) 87*8462SApril.Chin@Sun.COM size = x; 88*8462SApril.Chin@Sun.COM sh = pathshell(); 89*8462SApril.Chin@Sun.COM m = n + (argc + 4) * sizeof(char**) + strlen(sh) + 1; 90*8462SApril.Chin@Sun.COM m = roundof(m, sizeof(char**)); 91*8462SApril.Chin@Sun.COM if (size < m) 92*8462SApril.Chin@Sun.COM { 93*8462SApril.Chin@Sun.COM error(2, "size must be at least %d", m); 94*8462SApril.Chin@Sun.COM return 0; 95*8462SApril.Chin@Sun.COM } 96*8462SApril.Chin@Sun.COM if ((m = x / 10) > 2048) 97*8462SApril.Chin@Sun.COM m = 2048; 98*8462SApril.Chin@Sun.COM if (size > (x - m)) 99*8462SApril.Chin@Sun.COM size = x - m; 100*8462SApril.Chin@Sun.COM n = size - n; 101*8462SApril.Chin@Sun.COM m = ((flags & CMD_INSERT) && argpat) ? (strlen(argpat) + 1) : 0; 102*8462SApril.Chin@Sun.COM if (!(cmd = newof(0, Cmdarg_t, 1, n + m))) 103*8462SApril.Chin@Sun.COM { 104*8462SApril.Chin@Sun.COM error(ERROR_SYSTEM|2, "out of space"); 105*8462SApril.Chin@Sun.COM return 0; 106*8462SApril.Chin@Sun.COM } 107*8462SApril.Chin@Sun.COM c = n / sizeof(char**); 108*8462SApril.Chin@Sun.COM if (argmax <= 0 || argmax > c) 109*8462SApril.Chin@Sun.COM argmax = c; 110*8462SApril.Chin@Sun.COM s = cmd->buf; 111*8462SApril.Chin@Sun.COM if (!argv[0]) 112*8462SApril.Chin@Sun.COM { 113*8462SApril.Chin@Sun.COM argv = (char**)echo; 114*8462SApril.Chin@Sun.COM cmd->echo = 1; 115*8462SApril.Chin@Sun.COM } 116*8462SApril.Chin@Sun.COM else if (streq(argv[0], echo[0])) 117*8462SApril.Chin@Sun.COM { 118*8462SApril.Chin@Sun.COM cmd->echo = 1; 119*8462SApril.Chin@Sun.COM flags &= ~CMD_NEWLINE; 120*8462SApril.Chin@Sun.COM } 121*8462SApril.Chin@Sun.COM else if (!(flags & CMD_CHECKED)) 122*8462SApril.Chin@Sun.COM { 123*8462SApril.Chin@Sun.COM if (!pathpath(s, argv[0], NiL, PATH_REGULAR|PATH_EXECUTE)) 124*8462SApril.Chin@Sun.COM { 125*8462SApril.Chin@Sun.COM if (!(flags & CMD_SILENT)) 126*8462SApril.Chin@Sun.COM { 127*8462SApril.Chin@Sun.COM error(ERROR_SYSTEM|2, "%s: command not found", argv[0]); 128*8462SApril.Chin@Sun.COM exit(EXIT_NOTFOUND); 129*8462SApril.Chin@Sun.COM } 130*8462SApril.Chin@Sun.COM free(cmd); 131*8462SApril.Chin@Sun.COM return 0; 132*8462SApril.Chin@Sun.COM } 133*8462SApril.Chin@Sun.COM argv[0] = s; 134*8462SApril.Chin@Sun.COM } 135*8462SApril.Chin@Sun.COM s += strlen(s) + 1; 136*8462SApril.Chin@Sun.COM if (m) 137*8462SApril.Chin@Sun.COM { 138*8462SApril.Chin@Sun.COM cmd->insert = strcpy(s, argpat); 139*8462SApril.Chin@Sun.COM cmd->insertlen = m - 1; 140*8462SApril.Chin@Sun.COM s += m; 141*8462SApril.Chin@Sun.COM } 142*8462SApril.Chin@Sun.COM s += sizeof(char**) - (s - cmd->buf) % sizeof(char**); 143*8462SApril.Chin@Sun.COM p = (char**)s; 144*8462SApril.Chin@Sun.COM n -= strlen(*p++ = sh) + 1; 145*8462SApril.Chin@Sun.COM cmd->argv = p; 146*8462SApril.Chin@Sun.COM while (*p = *argv++) 147*8462SApril.Chin@Sun.COM p++; 148*8462SApril.Chin@Sun.COM if (m) 149*8462SApril.Chin@Sun.COM { 150*8462SApril.Chin@Sun.COM argmax = 1; 151*8462SApril.Chin@Sun.COM *p++ = 0; 152*8462SApril.Chin@Sun.COM cmd->insertarg = p; 153*8462SApril.Chin@Sun.COM argv = cmd->argv; 154*8462SApril.Chin@Sun.COM c = *cmd->insert; 155*8462SApril.Chin@Sun.COM while (s = *argv) 156*8462SApril.Chin@Sun.COM { 157*8462SApril.Chin@Sun.COM while ((s = strchr(s, c)) && strncmp(cmd->insert, s, cmd->insertlen)) 158*8462SApril.Chin@Sun.COM s++; 159*8462SApril.Chin@Sun.COM *p++ = s ? *argv : (char*)0; 160*8462SApril.Chin@Sun.COM argv++; 161*8462SApril.Chin@Sun.COM } 162*8462SApril.Chin@Sun.COM *p++ = 0; 163*8462SApril.Chin@Sun.COM } 164*8462SApril.Chin@Sun.COM cmd->firstarg = cmd->nextarg = p; 165*8462SApril.Chin@Sun.COM cmd->laststr = cmd->nextstr = cmd->buf + n; 166*8462SApril.Chin@Sun.COM cmd->argmax = argmax; 167*8462SApril.Chin@Sun.COM cmd->flags = flags; 168*8462SApril.Chin@Sun.COM cmd->offset = ((cmd->postarg = post) ? (argc - (post - argv)) : 0) + 3; 169*8462SApril.Chin@Sun.COM return cmd; 170*8462SApril.Chin@Sun.COM } 171*8462SApril.Chin@Sun.COM 172*8462SApril.Chin@Sun.COM /* 173*8462SApril.Chin@Sun.COM * flush outstanding command file args 174*8462SApril.Chin@Sun.COM */ 175*8462SApril.Chin@Sun.COM 176*8462SApril.Chin@Sun.COM int 177*8462SApril.Chin@Sun.COM cmdflush(register Cmdarg_t* cmd) 178*8462SApril.Chin@Sun.COM { 179*8462SApril.Chin@Sun.COM register char* s; 180*8462SApril.Chin@Sun.COM register char** p; 181*8462SApril.Chin@Sun.COM register int n; 182*8462SApril.Chin@Sun.COM 183*8462SApril.Chin@Sun.COM if (cmd->flags & CMD_EMPTY) 184*8462SApril.Chin@Sun.COM cmd->flags &= ~CMD_EMPTY; 185*8462SApril.Chin@Sun.COM else if (cmd->nextarg <= cmd->firstarg) 186*8462SApril.Chin@Sun.COM return 0; 187*8462SApril.Chin@Sun.COM if ((cmd->flags & CMD_MINIMUM) && cmd->argcount < cmd->argmax) 188*8462SApril.Chin@Sun.COM { 189*8462SApril.Chin@Sun.COM if (!(cmd->flags & CMD_SILENT)) 190*8462SApril.Chin@Sun.COM error(2, "%d arg command would be too long", cmd->argcount); 191*8462SApril.Chin@Sun.COM return -1; 192*8462SApril.Chin@Sun.COM } 193*8462SApril.Chin@Sun.COM cmd->total.args += cmd->argcount; 194*8462SApril.Chin@Sun.COM cmd->total.commands++; 195*8462SApril.Chin@Sun.COM cmd->argcount = 0; 196*8462SApril.Chin@Sun.COM if (p = cmd->postarg) 197*8462SApril.Chin@Sun.COM while (*cmd->nextarg++ = *p++); 198*8462SApril.Chin@Sun.COM else 199*8462SApril.Chin@Sun.COM *cmd->nextarg = 0; 200*8462SApril.Chin@Sun.COM if (s = cmd->insert) 201*8462SApril.Chin@Sun.COM { 202*8462SApril.Chin@Sun.COM char* a; 203*8462SApril.Chin@Sun.COM char* b; 204*8462SApril.Chin@Sun.COM char* e; 205*8462SApril.Chin@Sun.COM char* t; 206*8462SApril.Chin@Sun.COM char* u; 207*8462SApril.Chin@Sun.COM int c; 208*8462SApril.Chin@Sun.COM int m; 209*8462SApril.Chin@Sun.COM 210*8462SApril.Chin@Sun.COM a = cmd->firstarg[0]; 211*8462SApril.Chin@Sun.COM b = (char*)&cmd->nextarg[1]; 212*8462SApril.Chin@Sun.COM e = cmd->nextstr; 213*8462SApril.Chin@Sun.COM c = *s; 214*8462SApril.Chin@Sun.COM m = cmd->insertlen; 215*8462SApril.Chin@Sun.COM for (n = 1; cmd->argv[n]; n++) 216*8462SApril.Chin@Sun.COM if (t = cmd->insertarg[n]) 217*8462SApril.Chin@Sun.COM { 218*8462SApril.Chin@Sun.COM cmd->argv[n] = b; 219*8462SApril.Chin@Sun.COM for (;;) 220*8462SApril.Chin@Sun.COM { 221*8462SApril.Chin@Sun.COM if (!(u = strchr(t, c))) 222*8462SApril.Chin@Sun.COM { 223*8462SApril.Chin@Sun.COM b += sfsprintf(b, e - b, "%s", t); 224*8462SApril.Chin@Sun.COM break; 225*8462SApril.Chin@Sun.COM } 226*8462SApril.Chin@Sun.COM if (!strncmp(s, u, m)) 227*8462SApril.Chin@Sun.COM { 228*8462SApril.Chin@Sun.COM b += sfsprintf(b, e - b, "%-.*s%s", u - t, t, a); 229*8462SApril.Chin@Sun.COM t = u + m; 230*8462SApril.Chin@Sun.COM } 231*8462SApril.Chin@Sun.COM else if (b >= e) 232*8462SApril.Chin@Sun.COM break; 233*8462SApril.Chin@Sun.COM else 234*8462SApril.Chin@Sun.COM { 235*8462SApril.Chin@Sun.COM *b++ = *u++; 236*8462SApril.Chin@Sun.COM t = u; 237*8462SApril.Chin@Sun.COM } 238*8462SApril.Chin@Sun.COM } 239*8462SApril.Chin@Sun.COM if (b < e) 240*8462SApril.Chin@Sun.COM *b++ = 0; 241*8462SApril.Chin@Sun.COM } 242*8462SApril.Chin@Sun.COM if (b >= e) 243*8462SApril.Chin@Sun.COM { 244*8462SApril.Chin@Sun.COM if (!(cmd->flags & CMD_SILENT)) 245*8462SApril.Chin@Sun.COM error(2, "%s: command too large after insert", a); 246*8462SApril.Chin@Sun.COM return -1; 247*8462SApril.Chin@Sun.COM } 248*8462SApril.Chin@Sun.COM } 249*8462SApril.Chin@Sun.COM cmd->nextarg = cmd->firstarg; 250*8462SApril.Chin@Sun.COM cmd->nextstr = cmd->laststr; 251*8462SApril.Chin@Sun.COM if (cmd->flags & (CMD_QUERY|CMD_TRACE)) 252*8462SApril.Chin@Sun.COM { 253*8462SApril.Chin@Sun.COM p = cmd->argv; 254*8462SApril.Chin@Sun.COM sfprintf(sfstderr, "+ %s", *p); 255*8462SApril.Chin@Sun.COM while (s = *++p) 256*8462SApril.Chin@Sun.COM sfprintf(sfstderr, " %s", s); 257*8462SApril.Chin@Sun.COM if (!(cmd->flags & CMD_QUERY)) 258*8462SApril.Chin@Sun.COM sfprintf(sfstderr, "\n"); 259*8462SApril.Chin@Sun.COM else if (astquery(1, "? ")) 260*8462SApril.Chin@Sun.COM return 0; 261*8462SApril.Chin@Sun.COM } 262*8462SApril.Chin@Sun.COM if (cmd->echo) 263*8462SApril.Chin@Sun.COM { 264*8462SApril.Chin@Sun.COM n = (cmd->flags & CMD_NEWLINE) ? '\n' : ' '; 265*8462SApril.Chin@Sun.COM for (p = cmd->argv + 1; s = *p++;) 266*8462SApril.Chin@Sun.COM sfputr(sfstdout, s, *p ? n : '\n'); 267*8462SApril.Chin@Sun.COM n = 0; 268*8462SApril.Chin@Sun.COM } 269*8462SApril.Chin@Sun.COM else if ((n = procrun(*cmd->argv, cmd->argv, PROC_ARGMOD|PROC_IGNOREPATH)) == -1) 270*8462SApril.Chin@Sun.COM { 271*8462SApril.Chin@Sun.COM if (!(cmd->flags & CMD_SILENT)) 272*8462SApril.Chin@Sun.COM { 273*8462SApril.Chin@Sun.COM error(ERROR_SYSTEM|2, "%s: command exec error", *cmd->argv); 274*8462SApril.Chin@Sun.COM exit(EXIT_NOTFOUND - 1); 275*8462SApril.Chin@Sun.COM } 276*8462SApril.Chin@Sun.COM return -1; 277*8462SApril.Chin@Sun.COM } 278*8462SApril.Chin@Sun.COM else if (n >= EXIT_NOTFOUND - 1) 279*8462SApril.Chin@Sun.COM { 280*8462SApril.Chin@Sun.COM if (!(cmd->flags & CMD_SILENT)) 281*8462SApril.Chin@Sun.COM exit(n); 282*8462SApril.Chin@Sun.COM } 283*8462SApril.Chin@Sun.COM else if (!(cmd->flags & CMD_IGNORE)) 284*8462SApril.Chin@Sun.COM { 285*8462SApril.Chin@Sun.COM if (n == EXIT_QUIT && !(cmd->flags & CMD_SILENT)) 286*8462SApril.Chin@Sun.COM exit(2); 287*8462SApril.Chin@Sun.COM if (n) 288*8462SApril.Chin@Sun.COM error_info.errors++; 289*8462SApril.Chin@Sun.COM } 290*8462SApril.Chin@Sun.COM return n; 291*8462SApril.Chin@Sun.COM } 292*8462SApril.Chin@Sun.COM 293*8462SApril.Chin@Sun.COM /* 294*8462SApril.Chin@Sun.COM * add file to the command arg list 295*8462SApril.Chin@Sun.COM */ 296*8462SApril.Chin@Sun.COM 297*8462SApril.Chin@Sun.COM int 298*8462SApril.Chin@Sun.COM cmdarg(register Cmdarg_t* cmd, const char* file, register int len) 299*8462SApril.Chin@Sun.COM { 300*8462SApril.Chin@Sun.COM int i; 301*8462SApril.Chin@Sun.COM int r; 302*8462SApril.Chin@Sun.COM 303*8462SApril.Chin@Sun.COM r = 0; 304*8462SApril.Chin@Sun.COM if (len) 305*8462SApril.Chin@Sun.COM { 306*8462SApril.Chin@Sun.COM while ((cmd->nextstr -= len + 1) < (char*)(cmd->nextarg + cmd->offset)) 307*8462SApril.Chin@Sun.COM { 308*8462SApril.Chin@Sun.COM if (cmd->nextarg == cmd->firstarg) 309*8462SApril.Chin@Sun.COM { 310*8462SApril.Chin@Sun.COM error(2, "%s: path too long for exec args", file); 311*8462SApril.Chin@Sun.COM return -1; 312*8462SApril.Chin@Sun.COM } 313*8462SApril.Chin@Sun.COM if (i = cmdflush(cmd)) 314*8462SApril.Chin@Sun.COM { 315*8462SApril.Chin@Sun.COM if (r < i) 316*8462SApril.Chin@Sun.COM r = i; 317*8462SApril.Chin@Sun.COM if (!(cmd->flags & CMD_IGNORE)) 318*8462SApril.Chin@Sun.COM return r; 319*8462SApril.Chin@Sun.COM } 320*8462SApril.Chin@Sun.COM } 321*8462SApril.Chin@Sun.COM *cmd->nextarg++ = cmd->nextstr; 322*8462SApril.Chin@Sun.COM memcpy(cmd->nextstr, file, len); 323*8462SApril.Chin@Sun.COM cmd->nextstr[len] = 0; 324*8462SApril.Chin@Sun.COM cmd->argcount++; 325*8462SApril.Chin@Sun.COM if (cmd->argcount >= cmd->argmax && (i = cmdflush(cmd)) > r) 326*8462SApril.Chin@Sun.COM r = i; 327*8462SApril.Chin@Sun.COM } 328*8462SApril.Chin@Sun.COM return r; 329*8462SApril.Chin@Sun.COM } 330*8462SApril.Chin@Sun.COM 331*8462SApril.Chin@Sun.COM /* 332*8462SApril.Chin@Sun.COM * close a cmdarg stream 333*8462SApril.Chin@Sun.COM */ 334*8462SApril.Chin@Sun.COM 335*8462SApril.Chin@Sun.COM int 336*8462SApril.Chin@Sun.COM cmdclose(Cmdarg_t* cmd) 337*8462SApril.Chin@Sun.COM { 338*8462SApril.Chin@Sun.COM int n; 339*8462SApril.Chin@Sun.COM 340*8462SApril.Chin@Sun.COM if ((cmd->flags & CMD_EXACT) && cmd->argcount < cmd->argmax) 341*8462SApril.Chin@Sun.COM { 342*8462SApril.Chin@Sun.COM if (!(cmd->flags & CMD_SILENT)) 343*8462SApril.Chin@Sun.COM error(2, "only %d arguments for last command", cmd->argcount); 344*8462SApril.Chin@Sun.COM return -1; 345*8462SApril.Chin@Sun.COM } 346*8462SApril.Chin@Sun.COM cmd->flags &= ~CMD_MINIMUM; 347*8462SApril.Chin@Sun.COM n = cmdflush(cmd); 348*8462SApril.Chin@Sun.COM free(cmd); 349*8462SApril.Chin@Sun.COM return n; 350*8462SApril.Chin@Sun.COM } 351