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