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