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