/usr.bin/make/shell.c

https://bitbucket.org/freebsd/freebsd-head/ · C · 472 lines · 253 code · 43 blank · 176 comment · 88 complexity · b8c850a9284335efa96c011d00ba4a42 MD5 · raw file

  1. /*-
  2. * Copyright (c) 1988, 1989, 1990, 1993
  3. * The Regents of the University of California. All rights reserved.
  4. * Copyright (c) 1988, 1989 by Adam de Boor
  5. * Copyright (c) 1989 by Berkeley Softworks
  6. * All rights reserved.
  7. *
  8. * This code is derived from software contributed to Berkeley by
  9. * Adam de Boor.
  10. *
  11. * Redistribution and use in source and binary forms, with or without
  12. * modification, are permitted provided that the following conditions
  13. * are met:
  14. * 1. Redistributions of source code must retain the above copyright
  15. * notice, this list of conditions and the following disclaimer.
  16. * 2. Redistributions in binary form must reproduce the above copyright
  17. * notice, this list of conditions and the following disclaimer in the
  18. * documentation and/or other materials provided with the distribution.
  19. * 3. All advertising materials mentioning features or use of this software
  20. * must display the following acknowledgement:
  21. * This product includes software developed by the University of
  22. * California, Berkeley and its contributors.
  23. * 4. Neither the name of the University nor the names of its contributors
  24. * may be used to endorse or promote products derived from this software
  25. * without specific prior written permission.
  26. *
  27. * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  28. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  29. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  30. * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  31. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  32. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  33. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  34. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  35. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  36. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  37. * SUCH DAMAGE.
  38. */
  39. #include <sys/cdefs.h>
  40. __FBSDID("$FreeBSD$");
  41. #include <sys/queue.h>
  42. #include <stdio.h>
  43. #include <stdlib.h>
  44. #include <string.h>
  45. #include "parse.h"
  46. #include "pathnames.h"
  47. #include "shell.h"
  48. #include "util.h"
  49. /*
  50. * Descriptions for various shells. What the list of builtins should contain
  51. * is debatable: either all builtins or only those which may specified on
  52. * a single line without use of meta-characters. For correct makefiles that
  53. * contain only correct command lines there is no difference. But if a command
  54. * line, for example, is: 'if -foo bar' and there is an executable named 'if'
  55. * in the path, the first possibility would execute that 'if' while in the
  56. * second case the shell would give an error. Histerically only a small
  57. * subset of the builtins and no reserved words where given in the list which
  58. * corresponds roughly to the first variant. So go with this but add missing
  59. * words.
  60. */
  61. #define CSH_BUILTINS \
  62. "alias cd eval exec exit read set ulimit unalias " \
  63. "umask unset wait"
  64. #define SH_BUILTINS \
  65. "alias cd eval exec exit read set ulimit unalias " \
  66. "umask unset wait"
  67. #define CSH_META "#=|^(){};&<>*?[]:$`\\@\n"
  68. #define SH_META "#=|^(){};&<>*?[]:$`\\\n"
  69. static const char *const shells_init[] = {
  70. /*
  71. * CSH description. The csh can do echo control by playing
  72. * with the setting of the 'echo' shell variable. Sadly,
  73. * however, it is unable to do error control nicely.
  74. */
  75. "name=csh path='" PATH_DEFSHELLDIR "/csh' "
  76. "quiet='unset verbose' echo='set verbose' filter='unset verbose' "
  77. "hasErrCtl=N check='echo \"%s\"\n' ignore='csh -c \"%s || exit 0\"' "
  78. "echoFlag=v errFlag=e "
  79. "meta='" CSH_META "' builtins='" CSH_BUILTINS "'",
  80. /*
  81. * SH description. Echo control is also possible and, under
  82. * sun UNIX anyway, one can even control error checking.
  83. */
  84. "name=sh path='" PATH_DEFSHELLDIR "/sh' "
  85. "quiet='set -' echo='set -v' filter='set -' "
  86. "hasErrCtl=Y check='set -e' ignore='set +e' "
  87. "echoFlag=v errFlag=e "
  88. "meta='" SH_META "' builtins='" SH_BUILTINS "'",
  89. /*
  90. * KSH description. The Korn shell has a superset of
  91. * the Bourne shell's functionality. There are probably builtins
  92. * missing here.
  93. */
  94. "name=ksh path='" PATH_DEFSHELLDIR "/ksh' "
  95. "quiet='set -' echo='set -v' filter='set -' "
  96. "hasErrCtl=Y check='set -e' ignore='set +e' "
  97. "echoFlag=v errFlag=e "
  98. "meta='" SH_META "' builtins='" SH_BUILTINS "' unsetenv=T",
  99. NULL
  100. };
  101. /*
  102. * This is the shell to which we pass all commands in the Makefile.
  103. * It is set by the Job_ParseShell function.
  104. */
  105. struct Shell *commandShell;
  106. /*
  107. * This is the list of all known shells.
  108. */
  109. static struct Shells shells = TAILQ_HEAD_INITIALIZER(shells);
  110. void ShellDump(const struct Shell *) __unused;
  111. /**
  112. * Helper function for sorting the builtin list alphabetically.
  113. */
  114. static int
  115. sort_builtins(const void *p1, const void *p2)
  116. {
  117. return (strcmp(*(const char* const*)p1, *(const char* const*)p2));
  118. }
  119. /**
  120. * Free a shell structure and all associated strings.
  121. */
  122. static void
  123. ShellFree(struct Shell *sh)
  124. {
  125. if (sh != NULL) {
  126. free(sh->name);
  127. free(sh->path);
  128. free(sh->echoOff);
  129. free(sh->echoOn);
  130. free(sh->noPrint);
  131. free(sh->errCheck);
  132. free(sh->ignErr);
  133. free(sh->echo);
  134. free(sh->exit);
  135. ArgArray_Done(&sh->builtins);
  136. free(sh->meta);
  137. free(sh);
  138. }
  139. }
  140. /**
  141. * Dump a shell specification to stderr.
  142. */
  143. void
  144. ShellDump(const struct Shell *sh)
  145. {
  146. int i;
  147. fprintf(stderr, "Shell %p:\n", sh);
  148. fprintf(stderr, " name='%s' path='%s'\n", sh->name, sh->path);
  149. fprintf(stderr, " hasEchoCtl=%d echoOff='%s' echoOn='%s'\n",
  150. sh->hasEchoCtl, sh->echoOff, sh->echoOn);
  151. fprintf(stderr, " noPrint='%s'\n", sh->noPrint);
  152. fprintf(stderr, " hasErrCtl=%d errCheck='%s' ignErr='%s'\n",
  153. sh->hasErrCtl, sh->errCheck, sh->ignErr);
  154. fprintf(stderr, " echo='%s' exit='%s'\n", sh->echo, sh->exit);
  155. fprintf(stderr, " builtins=%d\n", sh->builtins.argc - 1);
  156. for (i = 1; i < sh->builtins.argc; i++)
  157. fprintf(stderr, " '%s'", sh->builtins.argv[i]);
  158. fprintf(stderr, "\n meta='%s'\n", sh->meta);
  159. fprintf(stderr, " unsetenv=%d\n", sh->unsetenv);
  160. }
  161. /**
  162. * Parse a shell specification line and return the new Shell structure.
  163. * In case of an error a message is printed and NULL is returned.
  164. */
  165. static struct Shell *
  166. ShellParseSpec(const char *spec, Boolean *fullSpec)
  167. {
  168. ArgArray aa;
  169. struct Shell *sh;
  170. char *eq;
  171. char *keyw;
  172. int arg;
  173. *fullSpec = FALSE;
  174. sh = emalloc(sizeof(*sh));
  175. memset(sh, 0, sizeof(*sh));
  176. ArgArray_Init(&sh->builtins);
  177. /*
  178. * Parse the specification by keyword but skip the first word
  179. */
  180. brk_string(&aa, spec, TRUE);
  181. for (arg = 1; arg < aa.argc; arg++) {
  182. /*
  183. * Split keyword and value
  184. */
  185. keyw = aa.argv[arg];
  186. if ((eq = strchr(keyw, '=')) == NULL) {
  187. Parse_Error(PARSE_FATAL, "missing '=' in shell "
  188. "specification keyword '%s'", keyw);
  189. ArgArray_Done(&aa);
  190. ShellFree(sh);
  191. return (NULL);
  192. }
  193. *eq++ = '\0';
  194. if (strcmp(keyw, "path") == 0) {
  195. free(sh->path);
  196. sh->path = estrdup(eq);
  197. } else if (strcmp(keyw, "name") == 0) {
  198. free(sh->name);
  199. sh->name = estrdup(eq);
  200. } else if (strcmp(keyw, "quiet") == 0) {
  201. free(sh->echoOff);
  202. sh->echoOff = estrdup(eq);
  203. *fullSpec = TRUE;
  204. } else if (strcmp(keyw, "echo") == 0) {
  205. free(sh->echoOn);
  206. sh->echoOn = estrdup(eq);
  207. *fullSpec = TRUE;
  208. } else if (strcmp(keyw, "filter") == 0) {
  209. free(sh->noPrint);
  210. sh->noPrint = estrdup(eq);
  211. *fullSpec = TRUE;
  212. } else if (strcmp(keyw, "echoFlag") == 0) {
  213. free(sh->echo);
  214. sh->echo = estrdup(eq);
  215. *fullSpec = TRUE;
  216. } else if (strcmp(keyw, "errFlag") == 0) {
  217. free(sh->exit);
  218. sh->exit = estrdup(eq);
  219. *fullSpec = TRUE;
  220. } else if (strcmp(keyw, "hasErrCtl") == 0) {
  221. sh->hasErrCtl = (*eq == 'Y' || *eq == 'y' ||
  222. *eq == 'T' || *eq == 't');
  223. *fullSpec = TRUE;
  224. } else if (strcmp(keyw, "check") == 0) {
  225. free(sh->errCheck);
  226. sh->errCheck = estrdup(eq);
  227. *fullSpec = TRUE;
  228. } else if (strcmp(keyw, "ignore") == 0) {
  229. free(sh->ignErr);
  230. sh->ignErr = estrdup(eq);
  231. *fullSpec = TRUE;
  232. } else if (strcmp(keyw, "builtins") == 0) {
  233. ArgArray_Done(&sh->builtins);
  234. brk_string(&sh->builtins, eq, TRUE);
  235. qsort(sh->builtins.argv + 1, sh->builtins.argc - 1,
  236. sizeof(char *), sort_builtins);
  237. *fullSpec = TRUE;
  238. } else if (strcmp(keyw, "meta") == 0) {
  239. free(sh->meta);
  240. sh->meta = estrdup(eq);
  241. *fullSpec = TRUE;
  242. } else if (strcmp(keyw, "unsetenv") == 0) {
  243. sh->unsetenv = (*eq == 'Y' || *eq == 'y' ||
  244. *eq == 'T' || *eq == 't');
  245. *fullSpec = TRUE;
  246. } else {
  247. Parse_Error(PARSE_FATAL, "unknown keyword in shell "
  248. "specification '%s'", keyw);
  249. ArgArray_Done(&aa);
  250. ShellFree(sh);
  251. return (NULL);
  252. }
  253. }
  254. ArgArray_Done(&aa);
  255. /*
  256. * Some checks (could be more)
  257. */
  258. if (*fullSpec) {
  259. if ((sh->echoOn != NULL) ^ (sh->echoOff != NULL)) {
  260. Parse_Error(PARSE_FATAL, "Shell must have either both "
  261. "echoOff and echoOn or none of them");
  262. ShellFree(sh);
  263. return (NULL);
  264. }
  265. if (sh->echoOn != NULL && sh->echoOff != NULL)
  266. sh->hasEchoCtl = TRUE;
  267. }
  268. return (sh);
  269. }
  270. /**
  271. * Parse the builtin shell specifications and put them into the shell
  272. * list. Then select the default shell to be the current shell. This
  273. * is called from main() before any parsing (including MAKEFLAGS and
  274. * command line) is done.
  275. */
  276. void
  277. Shell_Init(void)
  278. {
  279. int i;
  280. struct Shell *sh;
  281. Boolean fullSpec;
  282. for (i = 0; shells_init[i] != NULL; i++) {
  283. sh = ShellParseSpec(shells_init[i], &fullSpec);
  284. TAILQ_INSERT_TAIL(&shells, sh, link);
  285. if (strcmp(sh->name, DEFSHELLNAME) == 0)
  286. commandShell = sh;
  287. }
  288. }
  289. /**
  290. * Find a matching shell in 'shells' given its final component.
  291. *
  292. * Results:
  293. * A pointer to a freshly allocated Shell structure with the contents
  294. * from static description or NULL if no shell with the given name
  295. * is found.
  296. */
  297. static struct Shell *
  298. ShellMatch(const char *name)
  299. {
  300. struct Shell *sh;
  301. TAILQ_FOREACH(sh, &shells, link)
  302. if (strcmp(sh->name, name) == 0)
  303. return (sh);
  304. return (NULL);
  305. }
  306. /**
  307. * Parse a shell specification and set up commandShell appropriately.
  308. *
  309. * Results:
  310. * TRUE if the specification was correct. FALSE otherwise.
  311. *
  312. * Side Effects:
  313. * commandShell points to a Shell structure.
  314. * created from the shell spec).
  315. *
  316. * Notes:
  317. * A shell specification consists of a .SHELL target, with dependency
  318. * operator, followed by a series of blank-separated words. Double
  319. * quotes can be used to use blanks in words. A backslash escapes
  320. * anything (most notably a double-quote and a space) and
  321. * provides the functionality it does in C. Each word consists of
  322. * keyword and value separated by an equal sign. There should be no
  323. * unnecessary spaces in the word. The keywords are as follows:
  324. * name Name of shell.
  325. * path Location of shell. Overrides "name" if given
  326. * quiet Command to turn off echoing.
  327. * echo Command to turn echoing on
  328. * filter Result of turning off echoing that shouldn't be
  329. * printed.
  330. * echoFlag Flag to turn echoing on at the start
  331. * errFlag Flag to turn error checking on at the start
  332. * hasErrCtl True if shell has error checking control
  333. * check Command to turn on error checking if hasErrCtl
  334. * is TRUE or template of command to echo a command
  335. * for which error checking is off if hasErrCtl is
  336. * FALSE.
  337. * ignore Command to turn off error checking if hasErrCtl
  338. * is TRUE or template of command to execute a
  339. * command so as to ignore any errors it returns if
  340. * hasErrCtl is FALSE.
  341. * builtins A space separated list of builtins. If one
  342. * of these builtins is detected when make wants
  343. * to execute a command line, the command line is
  344. * handed to the shell. Otherwise make may try to
  345. * execute the command directly. If this list is empty
  346. * it is assumed, that the command must always be
  347. * handed over to the shell.
  348. * meta The shell meta characters. If this is not specified
  349. * or empty, commands are alway passed to the shell.
  350. * Otherwise they are not passed when they contain
  351. * neither a meta character nor a builtin command.
  352. * unsetenv Unsetenv("ENV") before executing anything.
  353. */
  354. Boolean
  355. Shell_Parse(const char line[])
  356. {
  357. Boolean fullSpec;
  358. struct Shell *sh;
  359. struct Shell *match;
  360. /* parse the specification */
  361. if ((sh = ShellParseSpec(line, &fullSpec)) == NULL)
  362. return (FALSE);
  363. if (sh->path == NULL) {
  364. /*
  365. * If no path was given, the user wants one of the pre-defined
  366. * shells, yes? So we find the one s/he wants with the help of
  367. * JobMatchShell and set things up the right way.
  368. */
  369. if (sh->name == NULL) {
  370. Parse_Error(PARSE_FATAL,
  371. "Neither path nor name specified");
  372. ShellFree(sh);
  373. return (FALSE);
  374. }
  375. if (fullSpec) {
  376. /*
  377. * XXX May want to merge sh into match. But this
  378. * require ShellParseSpec to return information
  379. * which attributes actuall have been specified.
  380. */
  381. Parse_Error(PARSE_FATAL, "No path specified");
  382. ShellFree(sh);
  383. return (FALSE);
  384. }
  385. if ((match = ShellMatch(sh->name)) == NULL) {
  386. Parse_Error(PARSE_FATAL, "%s: no matching shell",
  387. sh->name);
  388. ShellFree(sh);
  389. return (FALSE);
  390. }
  391. ShellFree(sh);
  392. commandShell = match;
  393. return (TRUE);
  394. }
  395. /*
  396. * The user provided a path. If s/he gave nothing else
  397. * (fullSpec is FALSE), try and find a matching shell in the
  398. * ones we know of. Else we just take the specification at its
  399. * word and copy it to a new location. In either case, we need
  400. * to record the path the user gave for the shell.
  401. */
  402. if (sh->name == NULL) {
  403. /* get the base name as the name */
  404. if ((sh->name = strrchr(sh->path, '/')) == NULL) {
  405. sh->name = estrdup(sh->path);
  406. } else {
  407. sh->name = estrdup(sh->name + 1);
  408. }
  409. }
  410. if (!fullSpec) {
  411. if ((match = ShellMatch(sh->name)) == NULL) {
  412. Parse_Error(PARSE_FATAL,
  413. "%s: no matching shell", sh->name);
  414. ShellFree(sh);
  415. return (FALSE);
  416. }
  417. /* set the patch on the matching shell */
  418. free(match->path);
  419. match->path = sh->path;
  420. sh->path = NULL;
  421. ShellFree(sh);
  422. commandShell = match;
  423. return (TRUE);
  424. }
  425. TAILQ_INSERT_HEAD(&shells, sh, link);
  426. /* set the new shell */
  427. commandShell = sh;
  428. return (TRUE);
  429. }