1 /***********************************************************************
2  *                                                                      *
3  *               This software is part of the ast package               *
4  *          Copyright (c) 1982-2013 AT&T Intellectual Property          *
5  *                      and is licensed under the                       *
6  *                 Eclipse Public License, Version 1.0                  *
7  *                    by AT&T Intellectual Property                     *
8  *                                                                      *
9  *                A copy of the License is available at                 *
10  *          http://www.eclipse.org/org/documents/epl-v10.html           *
11  *         (with md5 checksum b35adb5213ca9657e911e9befb180842)         *
12  *                                                                      *
13  *              Information and Software Systems Research               *
14  *                            AT&T Research                             *
15  *                           Florham Park NJ                            *
16  *                                                                      *
17  *                    David Korn <dgkorn@gmail.com>                     *
18  *                                                                      *
19  ***********************************************************************/
20 //
21 // David Korn
22 // AT&T Labs
23 //
24 // Shell script to shell binary converter.
25 //
26 #include "config_ast.h"  // IWYU pragma: keep
27 
28 #include <stdbool.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <sys/stat.h>
32 
33 #include "argnod.h"
34 #include "builtins.h"
35 #include "defs.h"
36 #include "error.h"
37 #include "name.h"
38 #include "optget_long.h"
39 #include "sfio.h"
40 #include "shnodes.h"
41 #include "stk.h"
42 
43 #define CNTL(x) ((x)&037)
44 #define VERSION 3
45 static const char header[6] = {CNTL('k'), CNTL('s'), CNTL('h'), 0, VERSION, 0};
46 
47 static const char *short_options = "nvD";
48 static const struct optget_option long_options[] = {
49     {"help", optget_no_arg, NULL, 1},  // all builtins support --help
50     {"dictionary", optget_no_arg, NULL, 'D'},
51     {"noexec", optget_no_arg, NULL, 'n'},
52     {"verbose", optget_no_arg, NULL, 'v'},
53     {NULL, 0, NULL, 0}};
54 
main(int argc,char * argv[])55 int main(int argc, char *argv[]) {
56     Sfio_t *in, *out;
57     Shell_t *shp;
58     Namval_t *np;
59     Shnode_t *t;
60     char *cp;
61     int opt;
62     bool nflag = false, vflag = false, dflag = false;
63     char *cmd = argv[0];
64 
65     error_info.id = argv[0];
66     shp = sh_init(argc, argv, NULL);
67 
68     optget_ind = 0;
69     while ((opt = optget_long(argc, argv, short_options, long_options)) != -1) {
70         switch (opt) {
71             case 1: {
72                 builtin_print_help(shp, cmd);
73                 return 0;
74             }
75             case 'D': {
76                 dflag = true;
77                 break;
78             }
79             case 'v': {
80                 vflag = true;
81                 break;
82             }
83             case 'n': {
84                 nflag = true;
85                 break;
86             }
87             case ':': {
88                 builtin_missing_argument(shp, cmd, argv[optget_ind - 1]);
89                 return 2;
90             }
91             case '?': {
92                 builtin_unknown_option(shp, cmd, argv[optget_ind - 1]);
93                 return 2;
94             }
95             default: { abort(); }
96         }
97     }
98     argv += optget_ind;
99     argc -= optget_ind;
100 
101     shp->shcomp = 1;
102     if (argc > 2) {
103         builtin_usage_error(shp, cmd, "expected at most two args, got %d", argc);
104         return 2;
105     }
106 
107     cp = *argv;
108     if (cp) {
109         argv++;
110         in = sh_pathopen(shp, cp);
111     } else {
112         in = sfstdin;
113     }
114     cp = *argv;
115     if (cp) {
116         struct stat statb;
117         if (!(out = sfopen(NULL, cp, "w"))) {
118             errormsg(SH_DICT, ERROR_system(1), "%s: cannot create", cp);
119             __builtin_unreachable();
120         }
121         if (fstat(sffileno(out), &statb) >= 0) {
122             chmod(cp, (statb.st_mode & ~S_IFMT) | S_IXUSR | S_IXGRP | S_IXOTH);
123         }
124     } else {
125         out = sfstdout;
126     }
127     if (dflag) {
128         sh_onoption(shp, SH_DICTIONARY);
129         sh_onoption(shp, SH_NOEXEC);
130     }
131     sh_trap(shp, "enum _Bool=(false true) ;", 0);
132     if (nflag) sh_onoption(shp, SH_NOEXEC);
133     if (vflag) sh_onoption(shp, SH_VERBOSE);
134     if (!dflag) sfwrite(out, header, sizeof(header));
135     shp->inlineno = 1;
136     sh_onoption(shp, SH_BRACEEXPAND);
137     while (1) {
138         stkset(stkstd, NULL, 0);
139         t = sh_parse(shp, in, 0);
140         if (t) {
141             if ((t->tre.tretyp & (COMMSK | COMSCAN)) == TCOM && t->com.comnamp &&
142                 strcmp(nv_name((Namval_t *)t->com.comnamp), "alias") == 0) {
143                 sh_exec(shp, t, 0);
144             }
145             if (!dflag && sh_tdump(out, t) < 0) {
146                 errormsg(SH_DICT, ERROR_exit(1), "dump failed");
147                 __builtin_unreachable();
148             }
149         } else if (sfeof(in)) {
150             break;
151         }
152         if (sferror(in)) {
153             errormsg(SH_DICT, ERROR_system(1), "I/O error");
154             __builtin_unreachable();
155         }
156         if (t && ((t->tre.tretyp & COMMSK) == TCOM) && (np = t->com.comnamp) &&
157             (cp = nv_name(np))) {
158             if (strcmp(cp, "exit") == 0) break;
159             // Check for exec of a command.
160             if (strcmp(cp, "exec") == 0) {
161                 if (t->com.comtyp & COMSCAN) {
162                     if (t->com.comarg->argnxt.ap) break;
163                 } else {
164                     struct dolnod *ap = (struct dolnod *)t->com.comarg;
165                     if (ap->dolnum > 1) break;
166                 }
167             }
168         }
169     }
170     // Copy any remaining input.
171     sfmove(in, out, SF_UNBOUND, -1);
172     if (in != sfstdin) sfclose(in);
173     if (out != sfstdout) sfclose(out);
174     return 0;
175 }
176