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
8 * This code is derived from software contributed to Berkeley by
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
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.
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
39 * $DragonFly: src/usr.bin/make/shell.c,v 1.2 2005/05/19 16:54:15 okumoto Exp $
47 #include "pathnames.h"
52 * Descriptions for various shells.
54 static const struct CShell shells[] = {
56 * CSH description. The csh can do echo control by playing
57 * with the setting of the 'echo' shell variable. Sadly,
58 * however, it is unable to do error control nicely.
62 TRUE, /* hasEchoCtl */
63 "unset verbose", /* echoOff */
64 "set verbose", /* echoOn */
65 "unset verbose", /* noPrint */
66 FALSE, /* hasErrCtl */
67 "echo \"%s\"\n", /* errCheck */
68 "csh -c \"%s || exit 0\"", /* ignErr */
73 * SH description. Echo control is also possible and, under
74 * sun UNIX anyway, one can even control error checking.
78 TRUE, /* hasEchoCtl */
79 "set -", /* echoOff */
80 "set -v", /* echoOn */
81 "set -", /* noPrint */
83 FALSE, /* hasErrCtl */
84 "echo \"%s\"\n", /* errCheck */
85 "sh -c '%s || exit 0'\n", /* ignErr */
88 "set -e", /* errCheck */
89 "set +e", /* ignErr */
95 * KSH description. The Korn shell has a superset of
96 * the Bourne shell's functionality.
100 TRUE, /* hasEchoCtl */
101 "set -", /* echoOff */
102 "set -v", /* echoOn */
103 "set -", /* noPrint */
104 TRUE, /* hasErrCtl */
105 "set -e", /* errCheck */
106 "set +e", /* ignErr */
112 static char *shellName = NULL; /* last component of shell */
113 char *shellPath = NULL; /* full pathname of executable image */
114 struct Shell *commandShell = NULL;
117 * Find a matching shell in 'shells' given its final component.
120 * A pointer to a freshly allocated Shell structure with a copy
121 * of the static structure or NULL if no shell with the given name
124 static struct Shell *
125 JobMatchShell(const char name[])
127 const struct CShell *sh; /* Pointer into shells table */
130 for (sh = shells; sh < shells + __arysize(shells); sh++)
131 if (strcmp(sh->name, name) == 0)
134 if (sh == shells + __arysize(shells))
138 nsh = emalloc(sizeof(*nsh));
140 nsh->name = estrdup(sh->name);
141 nsh->echoOff = estrdup(sh->echoOff);
142 nsh->echoOn = estrdup(sh->echoOn);
143 nsh->hasEchoCtl = sh->hasEchoCtl;
144 nsh->noPrint = estrdup(sh->noPrint);
145 nsh->hasErrCtl = sh->hasErrCtl;
146 nsh->errCheck = estrdup(sh->errCheck);
147 nsh->ignErr = estrdup(sh->ignErr);
148 nsh->echo = estrdup(sh->echo);
149 nsh->exit = estrdup(sh->exit);
155 * Make a new copy of the shell structure including a copy of the strings
156 * in it. This also defaults some fields in case they are NULL.
159 * The function returns a pointer to the new shell structure.
161 static struct Shell *
162 JobCopyShell(const struct Shell *osh)
166 nsh = emalloc(sizeof(*nsh));
167 nsh->name = estrdup(osh->name);
169 if (osh->echoOff != NULL)
170 nsh->echoOff = estrdup(osh->echoOff);
173 if (osh->echoOn != NULL)
174 nsh->echoOn = estrdup(osh->echoOn);
177 nsh->hasEchoCtl = osh->hasEchoCtl;
179 if (osh->noPrint != NULL)
180 nsh->noPrint = estrdup(osh->noPrint);
184 nsh->hasErrCtl = osh->hasErrCtl;
185 if (osh->errCheck == NULL)
186 nsh->errCheck = estrdup("");
188 nsh->errCheck = estrdup(osh->errCheck);
189 if (osh->ignErr == NULL)
190 nsh->ignErr = estrdup("%s");
192 nsh->ignErr = estrdup(osh->ignErr);
194 if (osh->echo == NULL)
195 nsh->echo = estrdup("");
197 nsh->echo = estrdup(osh->echo);
199 if (osh->exit == NULL)
200 nsh->exit = estrdup("");
202 nsh->exit = estrdup(osh->exit);
208 * Free a shell structure and all associated strings.
211 JobFreeShell(struct Shell *sh)
228 * Given the line following a .SHELL target, parse the
229 * line as a shell specification. Returns FALSE if the
230 * spec was incorrect.
232 * Parse a shell specification and set up commandShell, shellPath appropriately.
235 * TRUE if the specification was correct. FALSE otherwise.
238 * commandShell points to a Shell structure (either predefined or
239 * created from the shell spec), shellPath is the full path of the
240 * shell described by commandShell, while shellName is just the
241 * final component of shellPath.
244 * A shell specification consists of a .SHELL target, with dependency
245 * operator, followed by a series of blank-separated words. Double
246 * quotes can be used to use blanks in words. A backslash escapes
247 * anything (most notably a double-quote and a space) and
248 * provides the functionality it does in C. Each word consists of
249 * keyword and value separated by an equal sign. There should be no
250 * unnecessary spaces in the word. The keywords are as follows:
251 * name Name of shell.
252 * path Location of shell. Overrides "name" if given
253 * quiet Command to turn off echoing.
254 * echo Command to turn echoing on
255 * filter Result of turning off echoing that shouldn't be
257 * echoFlag Flag to turn echoing on at the start
258 * errFlag Flag to turn error checking on at the start
259 * hasErrCtl True if shell has error checking control
260 * check Command to turn on error checking if hasErrCtl
261 * is TRUE or template of command to echo a command
262 * for which error checking is off if hasErrCtl is
264 * ignore Command to turn off error checking if hasErrCtl
265 * is TRUE or template of command to execute a
266 * command so as to ignore any errors it returns if
267 * hasErrCtl is FALSE.
270 Job_ParseShell(const char line[])
276 Boolean fullSpec = FALSE;
277 struct Shell newShell;
280 memset(&newShell, 0, sizeof(newShell));
284 * Parse the specification by keyword but skip the first word
286 brk_string(&aa, line, TRUE);
288 for (argc = aa.argc - 1, argv = aa.argv + 1; argc != 0; argc--, argv++)
293 * Split keyword and value
295 if ((eq = strchr(*argv, '=')) == NULL) {
296 Parse_Error(PARSE_FATAL, "missing '=' in shell "
297 "specification keyword '%s'", *argv);
303 if (strcmp(*argv, "path") == 0) {
305 } else if (strcmp(*argv, "name") == 0) {
307 } else if (strcmp(*argv, "quiet") == 0) {
308 newShell.echoOff = eq;
310 } else if (strcmp(*argv, "echo") == 0) {
311 newShell.echoOn = eq;
313 } else if (strcmp(*argv, "filter") == 0) {
314 newShell.noPrint = eq;
316 } else if (strcmp(*argv, "echoFlag") == 0) {
319 } else if (strcmp(*argv, "errFlag") == 0) {
322 } else if (strcmp(*argv, "hasErrCtl") == 0) {
323 newShell.hasErrCtl = (*eq == 'Y' || *eq == 'y' ||
324 *eq == 'T' || *eq == 't');
326 } else if (strcmp(*argv, "check") == 0) {
327 newShell.errCheck = eq;
329 } else if (strcmp(*argv, "ignore") == 0) {
330 newShell.ignErr = eq;
333 Parse_Error(PARSE_FATAL, "unknown keyword in shell "
334 "specification '%s'", *argv);
341 * Some checks (could be more)
344 if ((newShell.echoOn != NULL) ^ (newShell.echoOff != NULL))
345 Parse_Error(PARSE_FATAL, "Shell must have either both "
346 "echoOff and echoOn or none of them");
348 if (newShell.echoOn != NULL && newShell.echoOff)
349 newShell.hasEchoCtl = TRUE;
354 * If no path was given, the user wants one of the pre-defined
355 * shells, yes? So we find the one s/he wants with the help of
356 * JobMatchShell and set things up the right way. shellPath
357 * will be set up by Job_Init.
359 if (newShell.name == NULL) {
360 Parse_Error(PARSE_FATAL,
361 "Neither path nor name specified");
365 if ((sh = JobMatchShell(newShell.name)) == NULL) {
366 Parse_Error(PARSE_FATAL, "%s: no matching shell",
374 * The user provided a path. If s/he gave nothing else
375 * (fullSpec is FALSE), try and find a matching shell in the
376 * ones we know of. Else we just take the specification at its
377 * word and copy it to a new location. In either case, we need
378 * to record the path the user gave for the shell.
380 path = estrdup(path);
381 if (newShell.name == NULL) {
382 /* get the base name as the name */
383 if ((newShell.name = strrchr(path, '/')) == NULL) {
384 newShell.name = path;
391 if ((sh = JobMatchShell(newShell.name)) == NULL) {
392 Parse_Error(PARSE_FATAL,
393 "%s: no matching shell", newShell.name);
399 sh = JobCopyShell(&newShell);
405 /* set the new shell */
406 JobFreeShell(commandShell);
409 shellName = commandShell->name;
418 commandShell = JobMatchShell(DEFSHELLNAME);
421 * Both the absolute path and the last component
422 * must be set. The last component is taken from the 'name'
423 * field of the default shell description pointed-to by
424 * commandShell. All default shells are located in
427 shellName = commandShell->name;
428 shellPath = str_concat(