1146572Sharti/*-
2146572Sharti * Copyright (c) 1988, 1989, 1990, 1993
3146572Sharti *	The Regents of the University of California.  All rights reserved.
4146572Sharti * Copyright (c) 1988, 1989 by Adam de Boor
5146572Sharti * Copyright (c) 1989 by Berkeley Softworks
6146572Sharti * All rights reserved.
7146572Sharti *
8146572Sharti * This code is derived from software contributed to Berkeley by
9146572Sharti * Adam de Boor.
10146572Sharti *
11146572Sharti * Redistribution and use in source and binary forms, with or without
12146572Sharti * modification, are permitted provided that the following conditions
13146572Sharti * are met:
14146572Sharti * 1. Redistributions of source code must retain the above copyright
15146572Sharti *    notice, this list of conditions and the following disclaimer.
16146572Sharti * 2. Redistributions in binary form must reproduce the above copyright
17146572Sharti *    notice, this list of conditions and the following disclaimer in the
18146572Sharti *    documentation and/or other materials provided with the distribution.
19146572Sharti * 3. All advertising materials mentioning features or use of this software
20146572Sharti *    must display the following acknowledgement:
21146572Sharti *	This product includes software developed by the University of
22146572Sharti *	California, Berkeley and its contributors.
23146572Sharti * 4. Neither the name of the University nor the names of its contributors
24146572Sharti *    may be used to endorse or promote products derived from this software
25146572Sharti *    without specific prior written permission.
26146572Sharti *
27146572Sharti * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28146572Sharti * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29146572Sharti * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30146572Sharti * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31146572Sharti * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32146572Sharti * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33146572Sharti * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34146572Sharti * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35146572Sharti * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36146572Sharti * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37146572Sharti * SUCH DAMAGE.
38146572Sharti */
39146572Sharti
40146572Sharti#include <sys/cdefs.h>
41146572Sharti__FBSDID("$FreeBSD$");
42146572Sharti
43146572Sharti#include <sys/queue.h>
44146572Sharti#include <stdio.h>
45146572Sharti#include <stdlib.h>
46146572Sharti#include <string.h>
47146572Sharti
48146572Sharti#include "parse.h"
49146572Sharti#include "pathnames.h"
50146572Sharti#include "shell.h"
51146572Sharti#include "util.h"
52146572Sharti
53146572Sharti/*
54146572Sharti * Descriptions for various shells. What the list of builtins should contain
55146572Sharti * is debatable: either all builtins or only those which may specified on
56146572Sharti * a single line without use of meta-characters. For correct makefiles that
57146572Sharti * contain only correct command lines there is no difference. But if a command
58146572Sharti * line, for example, is: 'if -foo bar' and there is an executable named 'if'
59146572Sharti * in the path, the first possibility would execute that 'if' while in the
60146572Sharti * second case the shell would give an error. Histerically only a small
61146572Sharti * subset of the builtins and no reserved words where given in the list which
62146572Sharti * corresponds roughly to the first variant. So go with this but add missing
63146572Sharti * words.
64146572Sharti */
65146572Sharti#define	CSH_BUILTINS						\
66146572Sharti	"alias cd eval exec exit read set ulimit unalias "	\
67146572Sharti	"umask unset wait"
68146572Sharti
69146572Sharti#define	SH_BUILTINS						\
70146572Sharti	"alias cd eval exec exit read set ulimit unalias "	\
71146572Sharti	"umask unset wait"
72146572Sharti
73146572Sharti#define	CSH_META	"#=|^(){};&<>*?[]:$`\\@\n"
74146572Sharti#define	SH_META		"#=|^(){};&<>*?[]:$`\\\n"
75146572Sharti
76146572Shartistatic const char *const shells_init[] = {
77146572Sharti	/*
78146572Sharti	 * CSH description. The csh can do echo control by playing
79146572Sharti	 * with the setting of the 'echo' shell variable. Sadly,
80146572Sharti	 * however, it is unable to do error control nicely.
81146572Sharti	 */
82146572Sharti	"name=csh path='" PATH_DEFSHELLDIR "/csh' "
83146572Sharti	"quiet='unset verbose' echo='set verbose' filter='unset verbose' "
84146572Sharti	"hasErrCtl=N check='echo \"%s\"\n' ignore='csh -c \"%s || exit 0\"' "
85146572Sharti	"echoFlag=v errFlag=e "
86146572Sharti	"meta='" CSH_META "' builtins='" CSH_BUILTINS "'",
87146572Sharti
88146572Sharti	/*
89146572Sharti	 * SH description. Echo control is also possible and, under
90146572Sharti	 * sun UNIX anyway, one can even control error checking.
91146572Sharti	 */
92146572Sharti	"name=sh path='" PATH_DEFSHELLDIR "/sh' "
93146572Sharti	"quiet='set -' echo='set -v' filter='set -' "
94146572Sharti	"hasErrCtl=Y check='set -e' ignore='set +e' "
95146572Sharti	"echoFlag=v errFlag=e "
96146572Sharti	"meta='" SH_META "' builtins='" SH_BUILTINS "'",
97146572Sharti
98146572Sharti	/*
99146572Sharti	 * KSH description. The Korn shell has a superset of
100146572Sharti	 * the Bourne shell's functionality. There are probably builtins
101146572Sharti	 * missing here.
102146572Sharti	 */
103146572Sharti	"name=ksh path='" PATH_DEFSHELLDIR "/ksh' "
104146572Sharti	"quiet='set -' echo='set -v' filter='set -' "
105146572Sharti	"hasErrCtl=Y check='set -e' ignore='set +e' "
106146572Sharti	"echoFlag=v errFlag=e "
107146572Sharti	"meta='" SH_META "' builtins='" SH_BUILTINS "' unsetenv=T",
108146572Sharti
109146572Sharti	NULL
110146572Sharti};
111146572Sharti
112146572Sharti/*
113146572Sharti * This is the shell to which we pass all commands in the Makefile.
114146572Sharti * It is set by the Job_ParseShell function.
115146572Sharti */
116146572Shartistruct Shell *commandShell;
117146572Sharti
118146572Sharti/*
119146572Sharti * This is the list of all known shells.
120146572Sharti */
121146572Shartistatic struct Shells shells = TAILQ_HEAD_INITIALIZER(shells);
122146572Sharti
123146572Shartivoid ShellDump(const struct Shell *) __unused;
124146572Sharti
125146572Sharti/**
126146572Sharti * Helper function for sorting the builtin list alphabetically.
127146572Sharti */
128146572Shartistatic int
129146572Shartisort_builtins(const void *p1, const void *p2)
130146572Sharti{
131146572Sharti
132146572Sharti	return (strcmp(*(const char* const*)p1, *(const char* const*)p2));
133146572Sharti}
134146572Sharti
135146572Sharti/**
136146572Sharti * Free a shell structure and all associated strings.
137146572Sharti */
138146572Shartistatic void
139146572ShartiShellFree(struct Shell *sh)
140146572Sharti{
141146572Sharti
142146572Sharti	if (sh != NULL) {
143146572Sharti		free(sh->name);
144146572Sharti		free(sh->path);
145146572Sharti		free(sh->echoOff);
146146572Sharti		free(sh->echoOn);
147146572Sharti		free(sh->noPrint);
148146572Sharti		free(sh->errCheck);
149146572Sharti		free(sh->ignErr);
150146572Sharti		free(sh->echo);
151146572Sharti		free(sh->exit);
152146572Sharti		ArgArray_Done(&sh->builtins);
153146572Sharti		free(sh->meta);
154146572Sharti		free(sh);
155146572Sharti	}
156146572Sharti}
157146572Sharti
158146572Sharti/**
159146572Sharti * Dump a shell specification to stderr.
160146572Sharti */
161146572Shartivoid
162146572ShartiShellDump(const struct Shell *sh)
163146572Sharti{
164146572Sharti	int i;
165146572Sharti
166146572Sharti	fprintf(stderr, "Shell %p:\n", sh);
167146572Sharti	fprintf(stderr, "  name='%s' path='%s'\n", sh->name, sh->path);
168146572Sharti	fprintf(stderr, "  hasEchoCtl=%d echoOff='%s' echoOn='%s'\n",
169146572Sharti	    sh->hasEchoCtl, sh->echoOff, sh->echoOn);
170146572Sharti	fprintf(stderr, "  noPrint='%s'\n", sh->noPrint);
171146572Sharti	fprintf(stderr, "  hasErrCtl=%d errCheck='%s' ignErr='%s'\n",
172146572Sharti	    sh->hasErrCtl, sh->errCheck, sh->ignErr);
173146572Sharti	fprintf(stderr, "  echo='%s' exit='%s'\n", sh->echo, sh->exit);
174146572Sharti	fprintf(stderr, "  builtins=%d\n", sh->builtins.argc - 1);
175146572Sharti	for (i = 1; i < sh->builtins.argc; i++)
176146572Sharti		fprintf(stderr, " '%s'", sh->builtins.argv[i]);
177146572Sharti	fprintf(stderr, "\n  meta='%s'\n", sh->meta);
178146572Sharti	fprintf(stderr, "  unsetenv=%d\n", sh->unsetenv);
179146572Sharti}
180146572Sharti
181146572Sharti/**
182146572Sharti * Parse a shell specification line and return the new Shell structure.
183146572Sharti * In case of an error a message is printed and NULL is returned.
184146572Sharti */
185146572Shartistatic struct Shell *
186146572ShartiShellParseSpec(const char *spec, Boolean *fullSpec)
187146572Sharti{
188146572Sharti	ArgArray	aa;
189146572Sharti	struct Shell	*sh;
190146572Sharti	char		*eq;
191146572Sharti	char		*keyw;
192146572Sharti	int		arg;
193146572Sharti
194146572Sharti	*fullSpec = FALSE;
195146572Sharti
196146572Sharti	sh = emalloc(sizeof(*sh));
197146572Sharti	memset(sh, 0, sizeof(*sh));
198146572Sharti	ArgArray_Init(&sh->builtins);
199146572Sharti
200146572Sharti	/*
201146572Sharti	 * Parse the specification by keyword but skip the first word
202146572Sharti	 */
203146572Sharti	brk_string(&aa, spec, TRUE);
204146572Sharti
205146572Sharti	for (arg = 1; arg < aa.argc; arg++) {
206146572Sharti		/*
207146572Sharti		 * Split keyword and value
208146572Sharti		 */
209146572Sharti		keyw = aa.argv[arg];
210146572Sharti		if ((eq = strchr(keyw, '=')) == NULL) {
211146572Sharti			Parse_Error(PARSE_FATAL, "missing '=' in shell "
212146572Sharti			    "specification keyword '%s'", keyw);
213146572Sharti			ArgArray_Done(&aa);
214146572Sharti			ShellFree(sh);
215146572Sharti			return (NULL);
216146572Sharti		}
217146572Sharti		*eq++ = '\0';
218146572Sharti
219146572Sharti		if (strcmp(keyw, "path") == 0) {
220146572Sharti			free(sh->path);
221146572Sharti			sh->path = estrdup(eq);
222146572Sharti		} else if (strcmp(keyw, "name") == 0) {
223146572Sharti			free(sh->name);
224146572Sharti			sh->name = estrdup(eq);
225146572Sharti		} else if (strcmp(keyw, "quiet") == 0) {
226146572Sharti			free(sh->echoOff);
227146572Sharti			sh->echoOff = estrdup(eq);
228146572Sharti			*fullSpec = TRUE;
229146572Sharti		} else if (strcmp(keyw, "echo") == 0) {
230146572Sharti			free(sh->echoOn);
231146572Sharti			sh->echoOn = estrdup(eq);
232146572Sharti			*fullSpec = TRUE;
233146572Sharti		} else if (strcmp(keyw, "filter") == 0) {
234146572Sharti			free(sh->noPrint);
235146572Sharti			sh->noPrint = estrdup(eq);
236146572Sharti			*fullSpec = TRUE;
237146572Sharti		} else if (strcmp(keyw, "echoFlag") == 0) {
238146572Sharti			free(sh->echo);
239146572Sharti			sh->echo = estrdup(eq);
240146572Sharti			*fullSpec = TRUE;
241146572Sharti		} else if (strcmp(keyw, "errFlag") == 0) {
242146572Sharti			free(sh->exit);
243146572Sharti			sh->exit = estrdup(eq);
244146572Sharti			*fullSpec = TRUE;
245146572Sharti		} else if (strcmp(keyw, "hasErrCtl") == 0) {
246146572Sharti			sh->hasErrCtl = (*eq == 'Y' || *eq == 'y' ||
247146572Sharti			    *eq == 'T' || *eq == 't');
248146572Sharti			*fullSpec = TRUE;
249146572Sharti		} else if (strcmp(keyw, "check") == 0) {
250146572Sharti			free(sh->errCheck);
251146572Sharti			sh->errCheck = estrdup(eq);
252146572Sharti			*fullSpec = TRUE;
253146572Sharti		} else if (strcmp(keyw, "ignore") == 0) {
254146572Sharti			free(sh->ignErr);
255146572Sharti			sh->ignErr = estrdup(eq);
256146572Sharti			*fullSpec = TRUE;
257146572Sharti		} else if (strcmp(keyw, "builtins") == 0) {
258146572Sharti			ArgArray_Done(&sh->builtins);
259146572Sharti			brk_string(&sh->builtins, eq, TRUE);
260146572Sharti			qsort(sh->builtins.argv + 1, sh->builtins.argc - 1,
261146572Sharti			    sizeof(char *), sort_builtins);
262146572Sharti			*fullSpec = TRUE;
263146572Sharti		} else if (strcmp(keyw, "meta") == 0) {
264146572Sharti			free(sh->meta);
265146572Sharti			sh->meta = estrdup(eq);
266146572Sharti			*fullSpec = TRUE;
267146572Sharti		} else if (strcmp(keyw, "unsetenv") == 0) {
268146572Sharti			sh->unsetenv = (*eq == 'Y' || *eq == 'y' ||
269146572Sharti			    *eq == 'T' || *eq == 't');
270146572Sharti			*fullSpec = TRUE;
271146572Sharti		} else {
272146572Sharti			Parse_Error(PARSE_FATAL, "unknown keyword in shell "
273146572Sharti			    "specification '%s'", keyw);
274146572Sharti			ArgArray_Done(&aa);
275146572Sharti			ShellFree(sh);
276146572Sharti			return (NULL);
277146572Sharti		}
278146572Sharti	}
279146572Sharti	ArgArray_Done(&aa);
280146572Sharti
281146572Sharti	/*
282146572Sharti	 * Some checks (could be more)
283146572Sharti	 */
284146572Sharti	if (*fullSpec) {
285146572Sharti		if ((sh->echoOn != NULL) ^ (sh->echoOff != NULL)) {
286146572Sharti			Parse_Error(PARSE_FATAL, "Shell must have either both "
287146572Sharti			    "echoOff and echoOn or none of them");
288146572Sharti			ShellFree(sh);
289146572Sharti			return (NULL);
290146572Sharti		}
291146572Sharti
292146572Sharti		if (sh->echoOn != NULL && sh->echoOff != NULL)
293146572Sharti			sh->hasEchoCtl = TRUE;
294146572Sharti	}
295146572Sharti
296146572Sharti	return (sh);
297146572Sharti}
298146572Sharti
299146572Sharti/**
300146572Sharti * Parse the builtin shell specifications and put them into the shell
301146572Sharti * list. Then select the default shell to be the current shell. This
302146572Sharti * is called from main() before any parsing (including MAKEFLAGS and
303146572Sharti * command line) is done.
304146572Sharti */
305146572Shartivoid
306146572ShartiShell_Init(void)
307146572Sharti{
308146572Sharti	int i;
309146572Sharti	struct Shell *sh;
310146572Sharti	Boolean fullSpec;
311146572Sharti
312146572Sharti	for (i = 0; shells_init[i] != NULL; i++) {
313146572Sharti		sh = ShellParseSpec(shells_init[i], &fullSpec);
314146572Sharti		TAILQ_INSERT_TAIL(&shells, sh, link);
315146572Sharti		if (strcmp(sh->name, DEFSHELLNAME) == 0)
316146572Sharti			commandShell = sh;
317146572Sharti	}
318146572Sharti}
319146572Sharti
320146572Sharti/**
321146572Sharti * Find a matching shell in 'shells' given its final component.
322146572Sharti *
323146572Sharti * Results:
324146572Sharti *	A pointer to a freshly allocated Shell structure with the contents
325146572Sharti *	from static description or NULL if no shell with the given name
326146572Sharti *	is found.
327146572Sharti */
328146572Shartistatic struct Shell *
329146572ShartiShellMatch(const char *name)
330146572Sharti{
331146572Sharti	struct Shell	*sh;
332146572Sharti
333146572Sharti	TAILQ_FOREACH(sh, &shells, link)
334146572Sharti		if (strcmp(sh->name, name) == 0)
335146572Sharti			return (sh);
336146572Sharti
337146572Sharti	return (NULL);
338146572Sharti}
339146572Sharti
340146572Sharti/**
341146572Sharti * Parse a shell specification and set up commandShell appropriately.
342146572Sharti *
343146572Sharti * Results:
344146572Sharti *	TRUE if the specification was correct. FALSE otherwise.
345146572Sharti *
346146572Sharti * Side Effects:
347146572Sharti *	commandShell points to a Shell structure.
348146572Sharti *	created from the shell spec).
349146572Sharti *
350146572Sharti * Notes:
351146572Sharti *	A shell specification consists of a .SHELL target, with dependency
352146572Sharti *	operator, followed by a series of blank-separated words. Double
353146572Sharti *	quotes can be used to use blanks in words. A backslash escapes
354146572Sharti *	anything (most notably a double-quote and a space) and
355146572Sharti *	provides the functionality it does in C. Each word consists of
356146572Sharti *	keyword and value separated by an equal sign. There should be no
357146572Sharti *	unnecessary spaces in the word. The keywords are as follows:
358146572Sharti *	    name	    Name of shell.
359146572Sharti *	    path	    Location of shell. Overrides "name" if given
360146572Sharti *	    quiet	    Command to turn off echoing.
361146572Sharti *	    echo	    Command to turn echoing on
362146572Sharti *	    filter	    Result of turning off echoing that shouldn't be
363146572Sharti *			    printed.
364146572Sharti *	    echoFlag	    Flag to turn echoing on at the start
365146572Sharti *	    errFlag	    Flag to turn error checking on at the start
366146572Sharti *	    hasErrCtl	    True if shell has error checking control
367146572Sharti *	    check	    Command to turn on error checking if hasErrCtl
368146572Sharti *			    is TRUE or template of command to echo a command
369146572Sharti *			    for which error checking is off if hasErrCtl is
370146572Sharti *			    FALSE.
371146572Sharti *	    ignore	    Command to turn off error checking if hasErrCtl
372146572Sharti *			    is TRUE or template of command to execute a
373146572Sharti *			    command so as to ignore any errors it returns if
374146572Sharti *			    hasErrCtl is FALSE.
375146572Sharti *	    builtins	    A space separated list of builtins. If one
376146572Sharti *			    of these builtins is detected when make wants
377146572Sharti *			    to execute a command line, the command line is
378146572Sharti *			    handed to the shell. Otherwise make may try to
379146572Sharti *			    execute the command directly. If this list is empty
380146572Sharti *			    it is assumed, that the command must always be
381146572Sharti *			    handed over to the shell.
382146572Sharti *	    meta	    The shell meta characters. If this is not specified
383146572Sharti *			    or empty, commands are alway passed to the shell.
384146572Sharti *			    Otherwise they are not passed when they contain
385146572Sharti *			    neither a meta character nor a builtin command.
386146572Sharti *	    unsetenv	    Unsetenv("ENV") before executing anything.
387146572Sharti */
388146572ShartiBoolean
389146572ShartiShell_Parse(const char line[])
390146572Sharti{
391146572Sharti	Boolean		fullSpec;
392146572Sharti	struct Shell	*sh;
393146572Sharti	struct Shell	*match;
394146572Sharti
395146572Sharti	/* parse the specification */
396146572Sharti	if ((sh = ShellParseSpec(line, &fullSpec)) == NULL)
397146572Sharti		return (FALSE);
398146572Sharti
399146572Sharti	if (sh->path == NULL) {
400146572Sharti		/*
401146572Sharti		 * If no path was given, the user wants one of the pre-defined
402146572Sharti		 * shells, yes? So we find the one s/he wants with the help of
403146572Sharti		 * JobMatchShell and set things up the right way.
404146572Sharti		 */
405146572Sharti		if (sh->name == NULL) {
406146572Sharti			Parse_Error(PARSE_FATAL,
407146572Sharti			    "Neither path nor name specified");
408146572Sharti			ShellFree(sh);
409146572Sharti			return (FALSE);
410146572Sharti		}
411146572Sharti		if (fullSpec) {
412146572Sharti			/*
413146572Sharti			 * XXX May want to merge sh into match. But this
414146572Sharti			 * require ShellParseSpec to return information
415146572Sharti			 * which attributes actuall have been specified.
416146572Sharti			 */
417146572Sharti			Parse_Error(PARSE_FATAL, "No path specified");
418146572Sharti			ShellFree(sh);
419146572Sharti			return (FALSE);
420146572Sharti		}
421146572Sharti		if ((match = ShellMatch(sh->name)) == NULL) {
422146572Sharti			Parse_Error(PARSE_FATAL, "%s: no matching shell",
423146572Sharti			    sh->name);
424146572Sharti			ShellFree(sh);
425146572Sharti			return (FALSE);
426146572Sharti		}
427146572Sharti		ShellFree(sh);
428146572Sharti		commandShell = match;
429146572Sharti
430146572Sharti		return (TRUE);
431146572Sharti	}
432146572Sharti
433146572Sharti	/*
434146572Sharti	 * The user provided a path. If s/he gave nothing else
435146572Sharti	 * (fullSpec is FALSE), try and find a matching shell in the
436146572Sharti	 * ones we know of. Else we just take the specification at its
437146572Sharti	 * word and copy it to a new location. In either case, we need
438146572Sharti	 * to record the path the user gave for the shell.
439146572Sharti	 */
440146572Sharti	if (sh->name == NULL) {
441146572Sharti		/* get the base name as the name */
442146572Sharti		if ((sh->name = strrchr(sh->path, '/')) == NULL) {
443146572Sharti			sh->name = estrdup(sh->path);
444146572Sharti		} else {
445146572Sharti			sh->name = estrdup(sh->name + 1);
446146572Sharti		}
447146572Sharti	}
448146572Sharti
449146572Sharti	if (!fullSpec) {
450146572Sharti		if ((match = ShellMatch(sh->name)) == NULL) {
451146572Sharti			Parse_Error(PARSE_FATAL,
452146572Sharti			    "%s: no matching shell", sh->name);
453146572Sharti			ShellFree(sh);
454146572Sharti			return (FALSE);
455146572Sharti		}
456146572Sharti
457146572Sharti		/* set the patch on the matching shell */
458146572Sharti		free(match->path);
459146572Sharti		match->path = sh->path;
460146572Sharti		sh->path = NULL;
461146572Sharti
462146572Sharti		ShellFree(sh);
463146572Sharti		commandShell = match;
464146572Sharti		return (TRUE);
465146572Sharti	}
466146572Sharti
467146572Sharti	TAILQ_INSERT_HEAD(&shells, sh, link);
468146572Sharti
469146572Sharti	/* set the new shell */
470146572Sharti	commandShell = sh;
471146572Sharti	return (TRUE);
472146572Sharti}
473