PageRenderTime 46ms CodeModel.GetById 15ms app.highlight 24ms RepoModel.GetById 1ms app.codeStats 1ms

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