18462SApril.Chin@Sun.COM /*********************************************************************** 28462SApril.Chin@Sun.COM * * 38462SApril.Chin@Sun.COM * This software is part of the ast package * 4*12068SRoger.Faulkner@Oracle.COM * Copyright (c) 1985-2010 AT&T Intellectual Property * 58462SApril.Chin@Sun.COM * and is licensed under the * 68462SApril.Chin@Sun.COM * Common Public License, Version 1.0 * 78462SApril.Chin@Sun.COM * by AT&T Intellectual Property * 88462SApril.Chin@Sun.COM * * 98462SApril.Chin@Sun.COM * A copy of the License is available at * 108462SApril.Chin@Sun.COM * http://www.opensource.org/licenses/cpl1.0.txt * 118462SApril.Chin@Sun.COM * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * 128462SApril.Chin@Sun.COM * * 138462SApril.Chin@Sun.COM * Information and Software Systems Research * 148462SApril.Chin@Sun.COM * AT&T Research * 158462SApril.Chin@Sun.COM * Florham Park NJ * 168462SApril.Chin@Sun.COM * * 178462SApril.Chin@Sun.COM * Glenn Fowler <gsf@research.att.com> * 188462SApril.Chin@Sun.COM * David Korn <dgk@research.att.com> * 198462SApril.Chin@Sun.COM * Phong Vo <kpv@research.att.com> * 208462SApril.Chin@Sun.COM * * 218462SApril.Chin@Sun.COM ***********************************************************************/ 228462SApril.Chin@Sun.COM #pragma prototyped 238462SApril.Chin@Sun.COM /* 248462SApril.Chin@Sun.COM * Glenn Fowler 258462SApril.Chin@Sun.COM * AT&T Research 268462SApril.Chin@Sun.COM * 278462SApril.Chin@Sun.COM * xargs/tw command arg list support 288462SApril.Chin@Sun.COM */ 298462SApril.Chin@Sun.COM 308462SApril.Chin@Sun.COM #include <ast.h> 318462SApril.Chin@Sun.COM #include <ctype.h> 328462SApril.Chin@Sun.COM #include <error.h> 338462SApril.Chin@Sun.COM #include <proc.h> 348462SApril.Chin@Sun.COM 358462SApril.Chin@Sun.COM #include "cmdarg.h" 368462SApril.Chin@Sun.COM 3710898Sroland.mainz@nrubsig.org #ifndef ARG_MAX 3810898Sroland.mainz@nrubsig.org #define ARG_MAX (64*1024) 3910898Sroland.mainz@nrubsig.org #endif 408462SApril.Chin@Sun.COM #ifndef EXIT_QUIT 418462SApril.Chin@Sun.COM #define EXIT_QUIT 255 428462SApril.Chin@Sun.COM #endif 438462SApril.Chin@Sun.COM 448462SApril.Chin@Sun.COM static const char* echo[] = { "echo", 0 }; 458462SApril.Chin@Sun.COM 468462SApril.Chin@Sun.COM /* 478462SApril.Chin@Sun.COM * open a cmdarg stream 488462SApril.Chin@Sun.COM * initialize the command for execution 498462SApril.Chin@Sun.COM * argv[-1] is reserved for procrun(PROC_ARGMOD) 508462SApril.Chin@Sun.COM */ 518462SApril.Chin@Sun.COM 528462SApril.Chin@Sun.COM Cmdarg_t* 538462SApril.Chin@Sun.COM cmdopen(char** argv, int argmax, int size, const char* argpat, int flags) 548462SApril.Chin@Sun.COM { 558462SApril.Chin@Sun.COM register Cmdarg_t* cmd; 568462SApril.Chin@Sun.COM register int n; 578462SApril.Chin@Sun.COM register char** p; 588462SApril.Chin@Sun.COM register char* s; 598462SApril.Chin@Sun.COM char* sh; 608462SApril.Chin@Sun.COM int c; 618462SApril.Chin@Sun.COM int m; 628462SApril.Chin@Sun.COM int argc; 638462SApril.Chin@Sun.COM long x; 648462SApril.Chin@Sun.COM 658462SApril.Chin@Sun.COM char** post = 0; 668462SApril.Chin@Sun.COM 678462SApril.Chin@Sun.COM n = sizeof(char**); 688462SApril.Chin@Sun.COM if (*argv) 698462SApril.Chin@Sun.COM { 708462SApril.Chin@Sun.COM for (p = argv + 1; *p; p++) 718462SApril.Chin@Sun.COM { 728462SApril.Chin@Sun.COM if ((flags & CMD_POST) && argpat && streq(*p, argpat)) 738462SApril.Chin@Sun.COM { 748462SApril.Chin@Sun.COM *p = 0; 758462SApril.Chin@Sun.COM post = p + 1; 768462SApril.Chin@Sun.COM argpat = 0; 778462SApril.Chin@Sun.COM } 788462SApril.Chin@Sun.COM else 798462SApril.Chin@Sun.COM n += strlen(*p) + 1; 808462SApril.Chin@Sun.COM } 818462SApril.Chin@Sun.COM argc = p - argv; 828462SApril.Chin@Sun.COM } 838462SApril.Chin@Sun.COM else 848462SApril.Chin@Sun.COM argc = 0; 858462SApril.Chin@Sun.COM for (p = environ; *p; p++) 868462SApril.Chin@Sun.COM n += sizeof(char**) + strlen(*p) + 1; 878462SApril.Chin@Sun.COM if ((x = strtol(astconf("ARG_MAX", NiL, NiL), NiL, 0)) <= 0) 888462SApril.Chin@Sun.COM x = ARG_MAX; 898462SApril.Chin@Sun.COM if (size <= 0 || size > x) 908462SApril.Chin@Sun.COM size = x; 918462SApril.Chin@Sun.COM sh = pathshell(); 928462SApril.Chin@Sun.COM m = n + (argc + 4) * sizeof(char**) + strlen(sh) + 1; 938462SApril.Chin@Sun.COM m = roundof(m, sizeof(char**)); 948462SApril.Chin@Sun.COM if (size < m) 958462SApril.Chin@Sun.COM { 968462SApril.Chin@Sun.COM error(2, "size must be at least %d", m); 978462SApril.Chin@Sun.COM return 0; 988462SApril.Chin@Sun.COM } 998462SApril.Chin@Sun.COM if ((m = x / 10) > 2048) 1008462SApril.Chin@Sun.COM m = 2048; 1018462SApril.Chin@Sun.COM if (size > (x - m)) 1028462SApril.Chin@Sun.COM size = x - m; 1038462SApril.Chin@Sun.COM n = size - n; 1048462SApril.Chin@Sun.COM m = ((flags & CMD_INSERT) && argpat) ? (strlen(argpat) + 1) : 0; 1058462SApril.Chin@Sun.COM if (!(cmd = newof(0, Cmdarg_t, 1, n + m))) 1068462SApril.Chin@Sun.COM { 1078462SApril.Chin@Sun.COM error(ERROR_SYSTEM|2, "out of space"); 1088462SApril.Chin@Sun.COM return 0; 1098462SApril.Chin@Sun.COM } 1108462SApril.Chin@Sun.COM c = n / sizeof(char**); 1118462SApril.Chin@Sun.COM if (argmax <= 0 || argmax > c) 1128462SApril.Chin@Sun.COM argmax = c; 1138462SApril.Chin@Sun.COM s = cmd->buf; 1148462SApril.Chin@Sun.COM if (!argv[0]) 1158462SApril.Chin@Sun.COM { 1168462SApril.Chin@Sun.COM argv = (char**)echo; 1178462SApril.Chin@Sun.COM cmd->echo = 1; 1188462SApril.Chin@Sun.COM } 1198462SApril.Chin@Sun.COM else if (streq(argv[0], echo[0])) 1208462SApril.Chin@Sun.COM { 1218462SApril.Chin@Sun.COM cmd->echo = 1; 1228462SApril.Chin@Sun.COM flags &= ~CMD_NEWLINE; 1238462SApril.Chin@Sun.COM } 1248462SApril.Chin@Sun.COM else if (!(flags & CMD_CHECKED)) 1258462SApril.Chin@Sun.COM { 1268462SApril.Chin@Sun.COM if (!pathpath(s, argv[0], NiL, PATH_REGULAR|PATH_EXECUTE)) 1278462SApril.Chin@Sun.COM { 1288462SApril.Chin@Sun.COM if (!(flags & CMD_SILENT)) 1298462SApril.Chin@Sun.COM { 1308462SApril.Chin@Sun.COM error(ERROR_SYSTEM|2, "%s: command not found", argv[0]); 1318462SApril.Chin@Sun.COM exit(EXIT_NOTFOUND); 1328462SApril.Chin@Sun.COM } 1338462SApril.Chin@Sun.COM free(cmd); 1348462SApril.Chin@Sun.COM return 0; 1358462SApril.Chin@Sun.COM } 1368462SApril.Chin@Sun.COM argv[0] = s; 1378462SApril.Chin@Sun.COM } 1388462SApril.Chin@Sun.COM s += strlen(s) + 1; 1398462SApril.Chin@Sun.COM if (m) 1408462SApril.Chin@Sun.COM { 1418462SApril.Chin@Sun.COM cmd->insert = strcpy(s, argpat); 1428462SApril.Chin@Sun.COM cmd->insertlen = m - 1; 1438462SApril.Chin@Sun.COM s += m; 1448462SApril.Chin@Sun.COM } 1458462SApril.Chin@Sun.COM s += sizeof(char**) - (s - cmd->buf) % sizeof(char**); 1468462SApril.Chin@Sun.COM p = (char**)s; 1478462SApril.Chin@Sun.COM n -= strlen(*p++ = sh) + 1; 1488462SApril.Chin@Sun.COM cmd->argv = p; 1498462SApril.Chin@Sun.COM while (*p = *argv++) 1508462SApril.Chin@Sun.COM p++; 1518462SApril.Chin@Sun.COM if (m) 1528462SApril.Chin@Sun.COM { 1538462SApril.Chin@Sun.COM argmax = 1; 1548462SApril.Chin@Sun.COM *p++ = 0; 1558462SApril.Chin@Sun.COM cmd->insertarg = p; 1568462SApril.Chin@Sun.COM argv = cmd->argv; 1578462SApril.Chin@Sun.COM c = *cmd->insert; 1588462SApril.Chin@Sun.COM while (s = *argv) 1598462SApril.Chin@Sun.COM { 1608462SApril.Chin@Sun.COM while ((s = strchr(s, c)) && strncmp(cmd->insert, s, cmd->insertlen)) 1618462SApril.Chin@Sun.COM s++; 1628462SApril.Chin@Sun.COM *p++ = s ? *argv : (char*)0; 1638462SApril.Chin@Sun.COM argv++; 1648462SApril.Chin@Sun.COM } 1658462SApril.Chin@Sun.COM *p++ = 0; 1668462SApril.Chin@Sun.COM } 1678462SApril.Chin@Sun.COM cmd->firstarg = cmd->nextarg = p; 1688462SApril.Chin@Sun.COM cmd->laststr = cmd->nextstr = cmd->buf + n; 1698462SApril.Chin@Sun.COM cmd->argmax = argmax; 1708462SApril.Chin@Sun.COM cmd->flags = flags; 1718462SApril.Chin@Sun.COM cmd->offset = ((cmd->postarg = post) ? (argc - (post - argv)) : 0) + 3; 1728462SApril.Chin@Sun.COM return cmd; 1738462SApril.Chin@Sun.COM } 1748462SApril.Chin@Sun.COM 1758462SApril.Chin@Sun.COM /* 1768462SApril.Chin@Sun.COM * flush outstanding command file args 1778462SApril.Chin@Sun.COM */ 1788462SApril.Chin@Sun.COM 1798462SApril.Chin@Sun.COM int 1808462SApril.Chin@Sun.COM cmdflush(register Cmdarg_t* cmd) 1818462SApril.Chin@Sun.COM { 1828462SApril.Chin@Sun.COM register char* s; 1838462SApril.Chin@Sun.COM register char** p; 1848462SApril.Chin@Sun.COM register int n; 1858462SApril.Chin@Sun.COM 1868462SApril.Chin@Sun.COM if (cmd->flags & CMD_EMPTY) 1878462SApril.Chin@Sun.COM cmd->flags &= ~CMD_EMPTY; 1888462SApril.Chin@Sun.COM else if (cmd->nextarg <= cmd->firstarg) 1898462SApril.Chin@Sun.COM return 0; 1908462SApril.Chin@Sun.COM if ((cmd->flags & CMD_MINIMUM) && cmd->argcount < cmd->argmax) 1918462SApril.Chin@Sun.COM { 1928462SApril.Chin@Sun.COM if (!(cmd->flags & CMD_SILENT)) 1938462SApril.Chin@Sun.COM error(2, "%d arg command would be too long", cmd->argcount); 1948462SApril.Chin@Sun.COM return -1; 1958462SApril.Chin@Sun.COM } 1968462SApril.Chin@Sun.COM cmd->total.args += cmd->argcount; 1978462SApril.Chin@Sun.COM cmd->total.commands++; 1988462SApril.Chin@Sun.COM cmd->argcount = 0; 1998462SApril.Chin@Sun.COM if (p = cmd->postarg) 2008462SApril.Chin@Sun.COM while (*cmd->nextarg++ = *p++); 2018462SApril.Chin@Sun.COM else 2028462SApril.Chin@Sun.COM *cmd->nextarg = 0; 2038462SApril.Chin@Sun.COM if (s = cmd->insert) 2048462SApril.Chin@Sun.COM { 2058462SApril.Chin@Sun.COM char* a; 2068462SApril.Chin@Sun.COM char* b; 2078462SApril.Chin@Sun.COM char* e; 2088462SApril.Chin@Sun.COM char* t; 2098462SApril.Chin@Sun.COM char* u; 2108462SApril.Chin@Sun.COM int c; 2118462SApril.Chin@Sun.COM int m; 2128462SApril.Chin@Sun.COM 2138462SApril.Chin@Sun.COM a = cmd->firstarg[0]; 2148462SApril.Chin@Sun.COM b = (char*)&cmd->nextarg[1]; 2158462SApril.Chin@Sun.COM e = cmd->nextstr; 2168462SApril.Chin@Sun.COM c = *s; 2178462SApril.Chin@Sun.COM m = cmd->insertlen; 2188462SApril.Chin@Sun.COM for (n = 1; cmd->argv[n]; n++) 2198462SApril.Chin@Sun.COM if (t = cmd->insertarg[n]) 2208462SApril.Chin@Sun.COM { 2218462SApril.Chin@Sun.COM cmd->argv[n] = b; 2228462SApril.Chin@Sun.COM for (;;) 2238462SApril.Chin@Sun.COM { 2248462SApril.Chin@Sun.COM if (!(u = strchr(t, c))) 2258462SApril.Chin@Sun.COM { 2268462SApril.Chin@Sun.COM b += sfsprintf(b, e - b, "%s", t); 2278462SApril.Chin@Sun.COM break; 2288462SApril.Chin@Sun.COM } 2298462SApril.Chin@Sun.COM if (!strncmp(s, u, m)) 2308462SApril.Chin@Sun.COM { 2318462SApril.Chin@Sun.COM b += sfsprintf(b, e - b, "%-.*s%s", u - t, t, a); 2328462SApril.Chin@Sun.COM t = u + m; 2338462SApril.Chin@Sun.COM } 2348462SApril.Chin@Sun.COM else if (b >= e) 2358462SApril.Chin@Sun.COM break; 2368462SApril.Chin@Sun.COM else 2378462SApril.Chin@Sun.COM { 2388462SApril.Chin@Sun.COM *b++ = *u++; 2398462SApril.Chin@Sun.COM t = u; 2408462SApril.Chin@Sun.COM } 2418462SApril.Chin@Sun.COM } 2428462SApril.Chin@Sun.COM if (b < e) 2438462SApril.Chin@Sun.COM *b++ = 0; 2448462SApril.Chin@Sun.COM } 2458462SApril.Chin@Sun.COM if (b >= e) 2468462SApril.Chin@Sun.COM { 2478462SApril.Chin@Sun.COM if (!(cmd->flags & CMD_SILENT)) 2488462SApril.Chin@Sun.COM error(2, "%s: command too large after insert", a); 2498462SApril.Chin@Sun.COM return -1; 2508462SApril.Chin@Sun.COM } 2518462SApril.Chin@Sun.COM } 2528462SApril.Chin@Sun.COM cmd->nextarg = cmd->firstarg; 2538462SApril.Chin@Sun.COM cmd->nextstr = cmd->laststr; 2548462SApril.Chin@Sun.COM if (cmd->flags & (CMD_QUERY|CMD_TRACE)) 2558462SApril.Chin@Sun.COM { 2568462SApril.Chin@Sun.COM p = cmd->argv; 2578462SApril.Chin@Sun.COM sfprintf(sfstderr, "+ %s", *p); 2588462SApril.Chin@Sun.COM while (s = *++p) 2598462SApril.Chin@Sun.COM sfprintf(sfstderr, " %s", s); 2608462SApril.Chin@Sun.COM if (!(cmd->flags & CMD_QUERY)) 2618462SApril.Chin@Sun.COM sfprintf(sfstderr, "\n"); 2628462SApril.Chin@Sun.COM else if (astquery(1, "? ")) 2638462SApril.Chin@Sun.COM return 0; 2648462SApril.Chin@Sun.COM } 2658462SApril.Chin@Sun.COM if (cmd->echo) 2668462SApril.Chin@Sun.COM { 2678462SApril.Chin@Sun.COM n = (cmd->flags & CMD_NEWLINE) ? '\n' : ' '; 2688462SApril.Chin@Sun.COM for (p = cmd->argv + 1; s = *p++;) 2698462SApril.Chin@Sun.COM sfputr(sfstdout, s, *p ? n : '\n'); 2708462SApril.Chin@Sun.COM n = 0; 2718462SApril.Chin@Sun.COM } 2728462SApril.Chin@Sun.COM else if ((n = procrun(*cmd->argv, cmd->argv, PROC_ARGMOD|PROC_IGNOREPATH)) == -1) 2738462SApril.Chin@Sun.COM { 2748462SApril.Chin@Sun.COM if (!(cmd->flags & CMD_SILENT)) 2758462SApril.Chin@Sun.COM { 2768462SApril.Chin@Sun.COM error(ERROR_SYSTEM|2, "%s: command exec error", *cmd->argv); 2778462SApril.Chin@Sun.COM exit(EXIT_NOTFOUND - 1); 2788462SApril.Chin@Sun.COM } 2798462SApril.Chin@Sun.COM return -1; 2808462SApril.Chin@Sun.COM } 2818462SApril.Chin@Sun.COM else if (n >= EXIT_NOTFOUND - 1) 2828462SApril.Chin@Sun.COM { 2838462SApril.Chin@Sun.COM if (!(cmd->flags & CMD_SILENT)) 2848462SApril.Chin@Sun.COM exit(n); 2858462SApril.Chin@Sun.COM } 2868462SApril.Chin@Sun.COM else if (!(cmd->flags & CMD_IGNORE)) 2878462SApril.Chin@Sun.COM { 2888462SApril.Chin@Sun.COM if (n == EXIT_QUIT && !(cmd->flags & CMD_SILENT)) 2898462SApril.Chin@Sun.COM exit(2); 2908462SApril.Chin@Sun.COM if (n) 2918462SApril.Chin@Sun.COM error_info.errors++; 2928462SApril.Chin@Sun.COM } 2938462SApril.Chin@Sun.COM return n; 2948462SApril.Chin@Sun.COM } 2958462SApril.Chin@Sun.COM 2968462SApril.Chin@Sun.COM /* 2978462SApril.Chin@Sun.COM * add file to the command arg list 2988462SApril.Chin@Sun.COM */ 2998462SApril.Chin@Sun.COM 3008462SApril.Chin@Sun.COM int 3018462SApril.Chin@Sun.COM cmdarg(register Cmdarg_t* cmd, const char* file, register int len) 3028462SApril.Chin@Sun.COM { 3038462SApril.Chin@Sun.COM int i; 3048462SApril.Chin@Sun.COM int r; 3058462SApril.Chin@Sun.COM 3068462SApril.Chin@Sun.COM r = 0; 3078462SApril.Chin@Sun.COM if (len) 3088462SApril.Chin@Sun.COM { 3098462SApril.Chin@Sun.COM while ((cmd->nextstr -= len + 1) < (char*)(cmd->nextarg + cmd->offset)) 3108462SApril.Chin@Sun.COM { 3118462SApril.Chin@Sun.COM if (cmd->nextarg == cmd->firstarg) 3128462SApril.Chin@Sun.COM { 3138462SApril.Chin@Sun.COM error(2, "%s: path too long for exec args", file); 3148462SApril.Chin@Sun.COM return -1; 3158462SApril.Chin@Sun.COM } 3168462SApril.Chin@Sun.COM if (i = cmdflush(cmd)) 3178462SApril.Chin@Sun.COM { 3188462SApril.Chin@Sun.COM if (r < i) 3198462SApril.Chin@Sun.COM r = i; 3208462SApril.Chin@Sun.COM if (!(cmd->flags & CMD_IGNORE)) 3218462SApril.Chin@Sun.COM return r; 3228462SApril.Chin@Sun.COM } 3238462SApril.Chin@Sun.COM } 3248462SApril.Chin@Sun.COM *cmd->nextarg++ = cmd->nextstr; 3258462SApril.Chin@Sun.COM memcpy(cmd->nextstr, file, len); 3268462SApril.Chin@Sun.COM cmd->nextstr[len] = 0; 3278462SApril.Chin@Sun.COM cmd->argcount++; 3288462SApril.Chin@Sun.COM if (cmd->argcount >= cmd->argmax && (i = cmdflush(cmd)) > r) 3298462SApril.Chin@Sun.COM r = i; 3308462SApril.Chin@Sun.COM } 3318462SApril.Chin@Sun.COM return r; 3328462SApril.Chin@Sun.COM } 3338462SApril.Chin@Sun.COM 3348462SApril.Chin@Sun.COM /* 3358462SApril.Chin@Sun.COM * close a cmdarg stream 3368462SApril.Chin@Sun.COM */ 3378462SApril.Chin@Sun.COM 3388462SApril.Chin@Sun.COM int 3398462SApril.Chin@Sun.COM cmdclose(Cmdarg_t* cmd) 3408462SApril.Chin@Sun.COM { 3418462SApril.Chin@Sun.COM int n; 3428462SApril.Chin@Sun.COM 3438462SApril.Chin@Sun.COM if ((cmd->flags & CMD_EXACT) && cmd->argcount < cmd->argmax) 3448462SApril.Chin@Sun.COM { 3458462SApril.Chin@Sun.COM if (!(cmd->flags & CMD_SILENT)) 3468462SApril.Chin@Sun.COM error(2, "only %d arguments for last command", cmd->argcount); 3478462SApril.Chin@Sun.COM return -1; 3488462SApril.Chin@Sun.COM } 3498462SApril.Chin@Sun.COM cmd->flags &= ~CMD_MINIMUM; 3508462SApril.Chin@Sun.COM n = cmdflush(cmd); 3518462SApril.Chin@Sun.COM free(cmd); 3528462SApril.Chin@Sun.COM return n; 3538462SApril.Chin@Sun.COM } 354