1 /***********************************************************************
2 * *
3 * This software is part of the ast package *
4 * Copyright (c) 1982-2014 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 #include "config_ast.h" // IWYU pragma: keep
21
22 #include <signal.h>
23 #include <stdarg.h>
24 #include <stddef.h>
25
26 #include "cmdext.h"
27 #include "defs.h"
28 #include "name.h"
29 #include "shtable.h"
30
31 #include "builtins.h"
32 #include "jobs.h"
33 #include "sfio.h"
34
35 #define bltin(x) (b_##x)
36
37 // In the last beta release that came out from AT&T, all the builtins for standard commands
38 // were enabled by default. It was a backward incompatible change from the last stable
39 // release. Since we want to be as close as possible to the last stable release, I am keeping
40 // these builtins disabled by default. Alternative CMDLIST macro which was used in the last
41 // beta release has been removed.
42 #define CMDLIST(f) SH_CMDLIB_DIR "/" #f, NV_BLTIN | NV_BLTINOPT | NV_NOFREE, b_##f
43
44 // The order of the entries in this table must be kept in sync with the SYS...
45 // symbols in src/cmd/ksh93/include/builtins.h
46 const struct shtable3 shtab_builtins[] = {
47 {"exec", NV_BLTIN | BLT_ENV | BLT_SPC, bltin(exec)},
48 {"set", NV_BLTIN | BLT_ENV | BLT_SPC, bltin(set)},
49 {":", NV_BLTIN | BLT_ENV | BLT_SPC, bltin(true)},
50 {"true", NV_BLTIN | BLT_ENV, bltin(true)},
51 {"command", NV_BLTIN | BLT_ENV | BLT_EXIT, bltin(command)},
52 {"cd", NV_BLTIN | BLT_ENV, bltin(cd)},
53 {"break", NV_BLTIN | BLT_ENV | BLT_SPC, bltin(break)},
54 {"continue", NV_BLTIN | BLT_ENV | BLT_SPC, bltin(continue)},
55 {"typeset", NV_BLTIN | BLT_ENV | BLT_SPC | BLT_DCL, bltin(typeset)},
56 {"test", NV_BLTIN | BLT_ENV, bltin(test)},
57 {"[", NV_BLTIN | BLT_ENV, bltin(test)},
58 {"let", NV_BLTIN | BLT_ENV, bltin(let)},
59 {"export", NV_BLTIN | BLT_ENV | BLT_SPC | BLT_DCL, bltin(export)},
60 {".", NV_BLTIN | BLT_ENV | BLT_SPC, bltin(source)},
61 {"return", NV_BLTIN | BLT_ENV | BLT_SPC, bltin(return )},
62 {"enum", NV_BLTIN | BLT_ENV | BLT_SPC | BLT_DCL, bltin(enum)},
63 {"declare", NV_BLTIN | BLT_ENV | BLT_SPC | BLT_DCL, bltin(typeset)},
64 {"local", NV_BLTIN | BLT_ENV | BLT_DCL, bltin(typeset)},
65 {"alias", NV_BLTIN | BLT_SPC | BLT_DCL, bltin(alias)},
66 {"eval", NV_BLTIN | BLT_ENV | BLT_SPC | BLT_EXIT, bltin(eval)},
67 {"exit", NV_BLTIN | BLT_ENV | BLT_SPC, bltin(exit)},
68 {"fc", NV_BLTIN | BLT_ENV | BLT_EXIT, bltin(hist)},
69 {"hist", NV_BLTIN | BLT_ENV | BLT_EXIT, bltin(hist)},
70 {"readonly", NV_BLTIN | BLT_ENV | BLT_SPC | BLT_DCL, bltin(readonly)},
71 {"shift", NV_BLTIN | BLT_ENV | BLT_SPC, bltin(shift)},
72 {"trap", NV_BLTIN | BLT_ENV | BLT_SPC, bltin(trap)},
73 {"unalias", NV_BLTIN | BLT_ENV | BLT_SPC, bltin(unalias)},
74 {"unset", NV_BLTIN | BLT_ENV | BLT_SPC, bltin(unset)},
75 {"builtin", NV_BLTIN, bltin(builtin)},
76 {"echo", NV_BLTIN | BLT_ENV, bltin(echo)},
77 #ifdef JOBS
78 #ifdef SIGTSTP
79 {"bg", NV_BLTIN | BLT_ENV, bltin(bg)},
80 {"fg", NV_BLTIN | BLT_ENV | BLT_EXIT, bltin(fg)},
81 {"disown", NV_BLTIN | BLT_ENV, bltin(disown)},
82 {"kill", NV_BLTIN | BLT_ENV, bltin(kill)},
83 #else // SIGTSTP
84 {"/bin/kill", NV_BLTIN | BLT_ENV, bltin(kill)},
85 #endif // SIGTSTP
86 {"jobs", NV_BLTIN | BLT_ENV, bltin(jobs)},
87 #endif // JOBS
88 {"compgen", NV_BLTIN, bltin(complete)},
89 {"complete", NV_BLTIN, bltin(complete)},
90 {"false", NV_BLTIN | BLT_ENV, bltin(false)},
91 {"getopts", NV_BLTIN | BLT_ENV, bltin(getopts)},
92 {"print", NV_BLTIN | BLT_ENV, bltin(print)},
93 {"printf", NV_BLTIN | BLT_ENV, bltin(printf)},
94 {"pwd", NV_BLTIN, bltin(pwd)},
95 {"read", NV_BLTIN | BLT_ENV, bltin(read)},
96 {"sleep", NV_BLTIN, bltin(sleep)},
97 {"ulimit", NV_BLTIN | BLT_ENV, bltin(ulimit)},
98 {"umask", NV_BLTIN | BLT_ENV, bltin(umask)},
99 {"wait", NV_BLTIN | BLT_ENV | BLT_EXIT, bltin(wait)},
100 {"whence", NV_BLTIN | BLT_ENV, bltin(whence)},
101 {"source", NV_BLTIN | BLT_ENV, bltin(source)},
102 {"times", NV_BLTIN | BLT_ENV, bltin(times)},
103 // These commands are implemented by the modules in src/lib/libcmd and are only usable if the
104 // user does `builtin cmd` (e.g., `builtin basename`). Or has /opt/ast/bin in PATH ahead of the
105 // directory with an external command of the same name. Otherwise the external command of the
106 // same name, if any, is used.
107 {CMDLIST(basename)},
108 {CMDLIST(chmod)},
109 {CMDLIST(dirname)},
110 {CMDLIST(head)},
111 {CMDLIST(mkdir)},
112 {CMDLIST(logname)},
113 {CMDLIST(cat)},
114 {CMDLIST(cmp)},
115 {CMDLIST(cut)},
116 {CMDLIST(uname)},
117 {CMDLIST(wc)},
118 {CMDLIST(sync)},
119 {NULL, 0, NULL}};
120
121 // This is used in infof(), in src/cmd/ksh93/sh/args.c, which is only used by sh_argopts(). Why is
122 // unclear but it appears to be due to flags shared by the `ksh` command and the `set` builtin. The
123 // two use cases should not be entangled in that manner.
124 const char sh_set[] =
125 "[a?Set the export attribute for each variable whose name does not "
126 "contain a \b.\b that you assign a value in the current shell "
127 "environment.]"
128 "[b?The shell writes a message to standard error as soon it detects that "
129 "a background job completes rather than waiting until the next prompt.]"
130 "[e?A simple command that has an non-zero exit status will cause the shell "
131 "to exit unless the simple command is:]{"
132 "[++?contained in an \b&&\b or \b||\b list.]"
133 "[++?the command immediately following \bif\b, \bwhile\b, or \buntil\b.]"
134 "[++?contained in the pipeline following \b!\b.]"
135 "}"
136 "[f?Pathname expansion is disabled.]"
137 "[h?Obsolete. Causes each command whose name has the syntax of an "
138 "alias to become a tracked alias when it is first encountered.]"
139 "[k?This is obsolete. All arguments of the form \aname\a\b=\b\avalue\a "
140 "are removed and placed in the variable assignment list for "
141 "the command. Ordinarily, variable assignments must precede "
142 "command arguments.]"
143 "[m?When enabled, the shell runs background jobs in a separate process "
144 "group and displays a line upon completion. This mode is enabled "
145 "by default for interactive shells on systems that support job "
146 "control.]"
147 "[n?The shell reads commands and checks for syntax errors, but does "
148 "not execute the command. Usually specified on command invocation.]"
149 "[o]:?[option?If \aoption\a is not specified, the list of options and "
150 "their current settings will be written to standard output. When "
151 "invoked with a \b+\b the options will be written in a format "
152 "that can be reinput to the shell to restore the settings. "
153 "Options \b-o\b \aname\a can also be specified with \b--\b\aname\a "
154 "and \b+o \aname\a can be specified with \b--no\b\aname\a except that "
155 "options names beginning with \bno\b are turned on by omitting \bno\b."
156 "This option can be repeated to enable/disable multiple options. "
157 "The value of \aoption\a must be one of the following:]{"
158 "[+allexport?Equivalent to \b-a\b.]"
159 "[+bgnice?Runs background jobs at lower priorities.]"
160 "[+braceexpand?Equivalent to \b-B\b.] "
161 "[+emacs?Enables/disables \bemacs\b editing mode.]"
162 "[+errexit?Equivalent to \b-e\b.]"
163 "[+globstar?Equivalent to \b-G\b.]"
164 "[+gmacs?Enables/disables \bgmacs\b editing mode. \bgmacs\b "
165 "editing mode is the same as \bemacs\b editing mode "
166 "except for the handling of \b^T\b.]"
167 "[+histexpand?Equivalent to \b-H\b.]"
168 "[+ignoreeof?Prevents an interactive shell from exiting on "
169 "reading an end-of-file.]"
170 "[+keyword?Equivalent to \b-k\b.]"
171 "[+letoctal?The \blet\b builtin recognizes octal constants "
172 "with leading 0.]"
173 "[+markdirs?A trailing \b/\b is appended to directories "
174 "resulting from pathname expansion.]"
175 "[+monitor?Equivalent to \b-m\b.]"
176 "[+multiline?Use multiple lines when editing lines that are "
177 "longer than the window width.]"
178 "[+noclobber?Equivalent to \b-C\b.]"
179 "[+noexec?Equivalent to \b-n\b.]"
180 "[+noglob?Equivalent to \b-f\b.]"
181 "[+nolog?This has no effect. It is provided for backward "
182 "compatibility.]"
183 "[+notify?Equivalent to \b-b\b.]"
184 "[+nounset?Equivalent to \b-u\b.]"
185 "[+pipefail?A pipeline will not complete until all components "
186 "of the pipeline have completed, and the exit status "
187 "of the pipeline will be the value of the last "
188 "command to exit with non-zero exit status, or will "
189 "be zero if all commands return zero exit status.]"
190 "[+privileged?Equivalent to \b-p\b.]"
191 "[+rc?Do not run the \b.kshrc\b file for interactive shells.]"
192 "[+showme?Simple commands preceded by a \b;\b will be traced "
193 "as if \b-x\b were enabled but not executed.]"
194 "[+trackall?Equivalent to \b-h\b.]"
195 "[+verbose?Equivalent to \b-v\b.]"
196 "[+vi?Enables/disables \bvi\b editing mode.]"
197 "[+viraw?This option no longer does anything.]"
198 "[+xtrace?Equivalent to \b-x\b.]"
199 "}"
200 "[p?Privileged mode. Disabling \b-p\b sets the effective user id to the "
201 "real user id, and the effective group id to the real group id. "
202 "Enabling \b-p\b restores the effective user and group ids to their "
203 "values when the shell was invoked. The \b-p\b option is on "
204 "whenever the real and effective user id is not equal or the "
205 "real and effective group id is not equal. User profiles are "
206 "not processed when \b-p\b is enabled.]"
207 "[r?restricted. Enables restricted shell. This option cannot be unset once "
208 "enabled.]"
209 "[t?Obsolete. The shell reads one command and then exits.]"
210 "[u?If enabled, the shell displays an error message when it tries to expand "
211 "a variable that is unset.]"
212 "[v?Verbose. The shell displays its input onto standard error as it "
213 "reads it.]"
214 "[x?Execution trace. The shell will display each command after all "
215 "expansion and before execution preceded by the expanded value "
216 "of the \bPS4\b parameter.]"
217 "[B?Enable {...} group expansion. On by default.]"
218 "[C?Prevents existing regular files from being overwritten using the \b>\b "
219 "redirection operator. The \b>|\b redirection overrides this "
220 "\bnoclobber\b option.]"
221 "[G?Causes \b**\b by itself to also match all sub-directories during pathname "
222 "expansion.]"
223 "[H?Enable \b!\b-style history expansion similar to \bcsh\b.]";
224
225 const char e_baddisc[] = "%s: invalid discipline function";
226 const char e_nospace[] = "out of memory";
227 const char e_nofork[] = "cannot fork";
228 const char e_nosignal[] = "%s: unknown signal name";
229 const char e_condition[] = "condition(s) required";
230 const char e_cneedsarg[] = "-c requires argument";
231
232 // Error message for missing option argument.
233 #define BUILTIN_ERR_MISSING "%s: %s: expected argument for option"
234 // Error message for unrecognized option.
235 #define BUILTIN_ERR_UNKNOWN "%s: %s: unknown option"
236
237 // Invoke a helper function or command to print a subset of the man page for the command. Such as
238 // from doing "cmd --help". This only produces output if the shell is interactive.
builtin_print_help(Shell_t * shp,const char * cmd)239 void builtin_print_help(Shell_t *shp, const char *cmd) {
240 if (!sh_isoption(shp, SH_INTERACTIVE)) return;
241
242 const char *argv[3] = {"_ksh_print_help", cmd, NULL};
243 sh_eval(shp, sh_sfeval(argv), 0);
244 sfputc(sfstderr, '\n');
245 return;
246 }
247
248 // Error reporting for encounter with unknown option when parsing command arguments.
builtin_unknown_option(Shell_t * shp,const char * cmd,const char * opt)249 void builtin_unknown_option(Shell_t *shp, const char *cmd, const char *opt) {
250 builtin_print_help(shp, cmd);
251 sfprintf(sfstderr, BUILTIN_ERR_UNKNOWN, cmd, opt);
252 sfputc(sfstderr, '\n');
253 }
254
255 // Error reporting for encounter with missing argument when parsing command arguments.
builtin_missing_argument(Shell_t * shp,const char * cmd,const char * opt)256 void builtin_missing_argument(Shell_t *shp, const char *cmd, const char *opt) {
257 builtin_print_help(shp, cmd);
258 sfprintf(sfstderr, BUILTIN_ERR_MISSING, cmd, opt);
259 sfputc(sfstderr, '\n');
260 }
261
262 // Error reporting for general errors when parsing command arguments.
builtin_usage_error(Shell_t * shp,const char * cmd,const char * fmt,...)263 void builtin_usage_error(Shell_t *shp, const char *cmd, const char *fmt, ...) {
264 builtin_print_help(shp, cmd);
265 va_list ap;
266 va_start(ap, fmt);
267 sfprintf(sfstderr, "%s: ", cmd);
268 sfvprintf(sfstderr, fmt, ap);
269 sfputc(sfstderr, '\n');
270 va_end(ap);
271 }
272