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