18810SCasper.Dik@Sun.COM /*
28810SCasper.Dik@Sun.COM * CDDL HEADER START
38810SCasper.Dik@Sun.COM *
48810SCasper.Dik@Sun.COM * The contents of this file are subject to the terms of the
58810SCasper.Dik@Sun.COM * Common Development and Distribution License (the "License").
68810SCasper.Dik@Sun.COM * You may not use this file except in compliance with the License.
78810SCasper.Dik@Sun.COM *
88810SCasper.Dik@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
98810SCasper.Dik@Sun.COM * or http://www.opensolaris.org/os/licensing.
108810SCasper.Dik@Sun.COM * See the License for the specific language governing permissions
118810SCasper.Dik@Sun.COM * and limitations under the License.
128810SCasper.Dik@Sun.COM *
138810SCasper.Dik@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each
148810SCasper.Dik@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
158810SCasper.Dik@Sun.COM * If applicable, add the following below this CDDL HEADER, with the
168810SCasper.Dik@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying
178810SCasper.Dik@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner]
188810SCasper.Dik@Sun.COM *
198810SCasper.Dik@Sun.COM * CDDL HEADER END
208810SCasper.Dik@Sun.COM */
218810SCasper.Dik@Sun.COM
228810SCasper.Dik@Sun.COM /*
238810SCasper.Dik@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
248810SCasper.Dik@Sun.COM * Use is subject to license terms.
258810SCasper.Dik@Sun.COM */
268810SCasper.Dik@Sun.COM
278810SCasper.Dik@Sun.COM /*
288810SCasper.Dik@Sun.COM * alias.c is a C version of the alias.sh wrapper (which links ksh
298810SCasper.Dik@Sun.COM * builtins to commands in /usr/bin/, e.g. calling this wrapper as
308810SCasper.Dik@Sun.COM * /usr/bin/alias will call the ksh "alias" builtin, running it as
318810SCasper.Dik@Sun.COM * /usr/bin/cut will call the ksh "cut" builtin etc.
328810SCasper.Dik@Sun.COM */
338810SCasper.Dik@Sun.COM
348810SCasper.Dik@Sun.COM #include <shell.h>
358810SCasper.Dik@Sun.COM #include <nval.h>
3610898Sroland.mainz@nrubsig.org #include <cmdext.h>
378810SCasper.Dik@Sun.COM #include <stdio.h>
388810SCasper.Dik@Sun.COM
3910898Sroland.mainz@nrubsig.org typedef struct {
4010898Sroland.mainz@nrubsig.org const char *name;
4110898Sroland.mainz@nrubsig.org int (* func)(int, char **, void *);
4210898Sroland.mainz@nrubsig.org } bfastpathrec;
4310898Sroland.mainz@nrubsig.org
4410898Sroland.mainz@nrubsig.org /*
4510898Sroland.mainz@nrubsig.org * We've disabled the "fastpath" codepath for some commands below
4610898Sroland.mainz@nrubsig.org * because it causes a paradoxon for large input files (as used by
4710898Sroland.mainz@nrubsig.org * ON PerfPIT for testing). For /usr/bin/rev (where the issue was
4810898Sroland.mainz@nrubsig.org * first discovered) it looks like this:
4910898Sroland.mainz@nrubsig.org * - for small files like /etc/profile the fastpath is faster in a loop
5010898Sroland.mainz@nrubsig.org * with 1000 iterations (8 seconds with fastpath, 14 seconds without
5110898Sroland.mainz@nrubsig.org * fastpath)
5210898Sroland.mainz@nrubsig.org * - for large files (/usr/pub/UTF-8 replicated until the test file
5310898Sroland.mainz@nrubsig.org * reaches 24884706 bytes) the benchmark reverses: The fastpath now
5410898Sroland.mainz@nrubsig.org * needs 40 seconds and without fastpath it needs 30 seconds (for 100
5510898Sroland.mainz@nrubsig.org * iterations).
5610898Sroland.mainz@nrubsig.org */
5710898Sroland.mainz@nrubsig.org #if 0
5810898Sroland.mainz@nrubsig.org #define ENABLE_PERFORMANCE_PARADOXON 1
5910898Sroland.mainz@nrubsig.org #endif
6010898Sroland.mainz@nrubsig.org
6110898Sroland.mainz@nrubsig.org /*
6210898Sroland.mainz@nrubsig.org * List of libcmd builtins which do not require a |Shell_t| context.
6310898Sroland.mainz@nrubsig.org * This list was automatically generated from <ast/cmdext.h>
6410898Sroland.mainz@nrubsig.org */
6510898Sroland.mainz@nrubsig.org static const
6610898Sroland.mainz@nrubsig.org bfastpathrec fastpath_builtins[] =
6710898Sroland.mainz@nrubsig.org {
6810898Sroland.mainz@nrubsig.org /* This list must be alphabetically sorted for |strcmp()| usage */
6910898Sroland.mainz@nrubsig.org { "basename", b_basename },
7010898Sroland.mainz@nrubsig.org { "cat", b_cat },
7110898Sroland.mainz@nrubsig.org { "chgrp", b_chgrp },
7210898Sroland.mainz@nrubsig.org { "chmod", b_chmod },
7310898Sroland.mainz@nrubsig.org { "chown", b_chown },
7410898Sroland.mainz@nrubsig.org #ifdef ENABLE_PERFORMANCE_PARADOXON
7510898Sroland.mainz@nrubsig.org { "cksum", b_cksum },
7610898Sroland.mainz@nrubsig.org #endif /* ENABLE_PERFORMANCE_PARADOXON */
7710898Sroland.mainz@nrubsig.org { "cmp", b_cmp },
7810898Sroland.mainz@nrubsig.org { "comm", b_comm },
7910898Sroland.mainz@nrubsig.org { "cp", b_cp },
8010898Sroland.mainz@nrubsig.org { "cut", b_cut },
8110898Sroland.mainz@nrubsig.org { "date", b_date },
8210898Sroland.mainz@nrubsig.org { "dirname", b_dirname },
8310898Sroland.mainz@nrubsig.org { "egrep", b_egrep },
8410898Sroland.mainz@nrubsig.org { "expr", b_expr },
8510898Sroland.mainz@nrubsig.org { "fds", b_fds },
8610898Sroland.mainz@nrubsig.org { "fgrep", b_fgrep },
8710898Sroland.mainz@nrubsig.org { "fmt", b_fmt },
8810898Sroland.mainz@nrubsig.org { "fold", b_fold },
8910898Sroland.mainz@nrubsig.org { "getconf", b_getconf },
9010898Sroland.mainz@nrubsig.org { "grep", b_grep },
9110898Sroland.mainz@nrubsig.org { "head", b_head },
9210898Sroland.mainz@nrubsig.org { "id", b_id },
9310898Sroland.mainz@nrubsig.org { "join", b_join },
9410898Sroland.mainz@nrubsig.org { "ln", b_ln },
9510898Sroland.mainz@nrubsig.org { "logname", b_logname },
9610898Sroland.mainz@nrubsig.org { "md5sum", b_md5sum },
9710898Sroland.mainz@nrubsig.org { "mkdir", b_mkdir },
9810898Sroland.mainz@nrubsig.org { "mkfifo", b_mkfifo },
9910898Sroland.mainz@nrubsig.org { "mktemp", b_mktemp },
10010898Sroland.mainz@nrubsig.org { "mv", b_mv },
10110898Sroland.mainz@nrubsig.org { "paste", b_paste },
10210898Sroland.mainz@nrubsig.org { "pathchk", b_pathchk },
10310898Sroland.mainz@nrubsig.org { "pids", b_pids },
10410898Sroland.mainz@nrubsig.org { "readlink", b_readlink },
10510898Sroland.mainz@nrubsig.org #ifdef ENABLE_PERFORMANCE_PARADOXON
10610898Sroland.mainz@nrubsig.org { "rev", b_rev },
10710898Sroland.mainz@nrubsig.org #endif /* ENABLE_PERFORMANCE_PARADOXON */
10810898Sroland.mainz@nrubsig.org { "rm", b_rm },
10910898Sroland.mainz@nrubsig.org { "rmdir", b_rmdir },
11010898Sroland.mainz@nrubsig.org { "stty", b_stty },
11110898Sroland.mainz@nrubsig.org #ifdef ENABLE_PERFORMANCE_PARADOXON
11210898Sroland.mainz@nrubsig.org { "sum", b_sum },
11310898Sroland.mainz@nrubsig.org #endif /* ENABLE_PERFORMANCE_PARADOXON */
11410898Sroland.mainz@nrubsig.org { "sync", b_sync },
11510898Sroland.mainz@nrubsig.org { "tail", b_tail },
11610898Sroland.mainz@nrubsig.org { "tee", b_tee },
11710898Sroland.mainz@nrubsig.org { "tty", b_tty },
11810898Sroland.mainz@nrubsig.org { "uname", b_uname },
11910898Sroland.mainz@nrubsig.org { "uniq", b_uniq },
12010898Sroland.mainz@nrubsig.org { "wc", b_wc },
12110898Sroland.mainz@nrubsig.org { "xgrep", b_xgrep },
12210898Sroland.mainz@nrubsig.org { NULL, (int (*)(int, char **, void *))NULL }
12310898Sroland.mainz@nrubsig.org };
12410898Sroland.mainz@nrubsig.org
12510898Sroland.mainz@nrubsig.org static inline
12610898Sroland.mainz@nrubsig.org const bfastpathrec *
find_bfastpathrec(const char * name)12710898Sroland.mainz@nrubsig.org find_bfastpathrec(const char *name)
12810898Sroland.mainz@nrubsig.org {
12910898Sroland.mainz@nrubsig.org unsigned int i;
13010898Sroland.mainz@nrubsig.org signed int cmpres;
13110898Sroland.mainz@nrubsig.org for (i = 0; fastpath_builtins[i].name != NULL; i++) {
13210898Sroland.mainz@nrubsig.org cmpres = strcmp(fastpath_builtins[i].name, name);
13310898Sroland.mainz@nrubsig.org if (cmpres == 0)
13410898Sroland.mainz@nrubsig.org return (&fastpath_builtins[i]);
13510898Sroland.mainz@nrubsig.org else if (cmpres > 0)
13610898Sroland.mainz@nrubsig.org return (NULL);
13710898Sroland.mainz@nrubsig.org
13810898Sroland.mainz@nrubsig.org }
13910898Sroland.mainz@nrubsig.org return (NULL);
14010898Sroland.mainz@nrubsig.org }
14110898Sroland.mainz@nrubsig.org
14210898Sroland.mainz@nrubsig.org static inline
14310898Sroland.mainz@nrubsig.org int
fastpath_builtin_main(const bfastpathrec * brec,int argc,char * argv[])14410898Sroland.mainz@nrubsig.org fastpath_builtin_main(const bfastpathrec *brec, int argc, char *argv[])
14510898Sroland.mainz@nrubsig.org {
14610898Sroland.mainz@nrubsig.org setlocale(LC_ALL, ""); /* calls |_ast_setlocale()| */
14710898Sroland.mainz@nrubsig.org
14810898Sroland.mainz@nrubsig.org return ((*brec->func)(argc, argv, NULL));
14910898Sroland.mainz@nrubsig.org }
15010898Sroland.mainz@nrubsig.org
15110898Sroland.mainz@nrubsig.org
1528810SCasper.Dik@Sun.COM /* Builtin script, original derived from alias.sh */
1538810SCasper.Dik@Sun.COM static const char *script = "\n"
1548810SCasper.Dik@Sun.COM /* Get name of builtin */
1558900SCasper.Dik@Sun.COM "typeset cmd=\"${0##*/}\"\n"
1568810SCasper.Dik@Sun.COM /*
1578810SCasper.Dik@Sun.COM * If the requested command is not an alias load it explicitly
1588810SCasper.Dik@Sun.COM * to make sure it is not bound to a path (those built-ins which
1598810SCasper.Dik@Sun.COM * are mapped via shell aliases point to commands which are
1608810SCasper.Dik@Sun.COM * "special shell built-ins" which cannot be bound to a specific
1618810SCasper.Dik@Sun.COM * PATH element) - otherwise we may execute the wrong command
1628810SCasper.Dik@Sun.COM * if an executable with the same name sits in a PATH element
1638810SCasper.Dik@Sun.COM * before /usr/bin (e.g. /usr/xpg4/bin/ls would be executed
1648810SCasper.Dik@Sun.COM * before /usr/bin/ls if the path was something like
1658810SCasper.Dik@Sun.COM * PATH=/usr/xpg4/bin:/usr/bin).
1668810SCasper.Dik@Sun.COM */
1678810SCasper.Dik@Sun.COM "if [[ \"${cmd}\" != ~(Elr)(alias|unalias|command) ]] && "
1688810SCasper.Dik@Sun.COM "! alias \"${cmd}\" >/dev/null 2>&1 ; then\n"
169*11138Solga.kryzhanovska@gmail.com "PATH='' builtin \"${cmd}\"\n"
1708810SCasper.Dik@Sun.COM "fi\n"
1718810SCasper.Dik@Sun.COM /* command is a keyword and needs to be handled separately */
1728810SCasper.Dik@Sun.COM "if [[ \"${cmd}\" == \"command\" ]] ; then\n"
1738900SCasper.Dik@Sun.COM "command \"$@\"\n"
1748810SCasper.Dik@Sun.COM "else\n"
17510898Sroland.mainz@nrubsig.org #ifdef WORKAROUND_FOR_ALIAS_CRASH
17610898Sroland.mainz@nrubsig.org /*
17710898Sroland.mainz@nrubsig.org * Work around a crash in /usr/bin/alias when invalid options are
17810898Sroland.mainz@nrubsig.org * passed (e.g. $ /usr/bin/alias -c #). The shell code will call
17910898Sroland.mainz@nrubsig.org * an error handler which does a |longjmp()| but somehow the code
18010898Sroland.mainz@nrubsig.org * failed to do the |setjmp()| before this point.
18110898Sroland.mainz@nrubsig.org * Putting the "alias" command in a subshell avoids the crash.
18210898Sroland.mainz@nrubsig.org * Real cause of the issue is under investigation and a fix be
18310898Sroland.mainz@nrubsig.org * delivered with the next ast-ksh update.
18410898Sroland.mainz@nrubsig.org */
18510898Sroland.mainz@nrubsig.org "( \"${cmd}\" \"$@\" )\n"
18610898Sroland.mainz@nrubsig.org #else
1878900SCasper.Dik@Sun.COM "\"${cmd}\" \"$@\"\n"
18810898Sroland.mainz@nrubsig.org #endif /* WORKAROUND_FOR_ALIAS_CRASH */
1898810SCasper.Dik@Sun.COM "fi\n"
1908810SCasper.Dik@Sun.COM "exitval=$?";
1918810SCasper.Dik@Sun.COM
19210898Sroland.mainz@nrubsig.org
19310898Sroland.mainz@nrubsig.org static inline
1948810SCasper.Dik@Sun.COM int
script_builtin_main(int argc,char * argv[])19510898Sroland.mainz@nrubsig.org script_builtin_main(int argc, char *argv[])
1968810SCasper.Dik@Sun.COM {
1978810SCasper.Dik@Sun.COM int i;
1988810SCasper.Dik@Sun.COM Shell_t *shp;
1998810SCasper.Dik@Sun.COM Namval_t *np;
2008810SCasper.Dik@Sun.COM int exitval;
2018810SCasper.Dik@Sun.COM
2028810SCasper.Dik@Sun.COM /*
2038810SCasper.Dik@Sun.COM * Create copy of |argv| array shifted by one position to
2048810SCasper.Dik@Sun.COM * emulate $ /usr/bin/sh <scriptname> <args1> <arg2> ... #.
2058810SCasper.Dik@Sun.COM * First position is set to "/usr/bin/sh" since other
2068810SCasper.Dik@Sun.COM * values may trigger special shell modes (e.g. *rsh* will
2078810SCasper.Dik@Sun.COM * trigger "restricted" shell mode etc.).
2088810SCasper.Dik@Sun.COM */
2098810SCasper.Dik@Sun.COM char *xargv[argc+2];
2108810SCasper.Dik@Sun.COM xargv[0] = "/usr/bin/sh";
2118810SCasper.Dik@Sun.COM xargv[1] = "scriptname";
2128810SCasper.Dik@Sun.COM for (i = 0; i < argc; i++) {
2138810SCasper.Dik@Sun.COM xargv[i+1] = argv[i];
2148810SCasper.Dik@Sun.COM }
2158810SCasper.Dik@Sun.COM xargv[i+1] = NULL;
2168810SCasper.Dik@Sun.COM
2178810SCasper.Dik@Sun.COM shp = sh_init(argc+1, xargv, 0);
2188810SCasper.Dik@Sun.COM if (!shp)
2198810SCasper.Dik@Sun.COM error(ERROR_exit(1), "shell initialisation failed.");
2208810SCasper.Dik@Sun.COM (void) sh_trap(script, 0);
2218810SCasper.Dik@Sun.COM
2228810SCasper.Dik@Sun.COM np = nv_open("exitval", shp->var_tree, 0);
2238810SCasper.Dik@Sun.COM if (!np)
2248810SCasper.Dik@Sun.COM error(ERROR_exit(1), "variable %s not found.", "exitval");
2258810SCasper.Dik@Sun.COM exitval = (int)nv_getnum(np);
2268810SCasper.Dik@Sun.COM nv_close(np);
2278810SCasper.Dik@Sun.COM
2288810SCasper.Dik@Sun.COM return (exitval);
2298810SCasper.Dik@Sun.COM }
23010898Sroland.mainz@nrubsig.org
23110898Sroland.mainz@nrubsig.org int
main(int argc,char * argv[])23210898Sroland.mainz@nrubsig.org main(int argc, char *argv[])
23310898Sroland.mainz@nrubsig.org {
23410898Sroland.mainz@nrubsig.org const char *progname;
23510898Sroland.mainz@nrubsig.org const bfastpathrec *brec;
23610898Sroland.mainz@nrubsig.org char execnamebuff[PATH_MAX+1];
23710898Sroland.mainz@nrubsig.org
23810898Sroland.mainz@nrubsig.org /* Get program name */
23910898Sroland.mainz@nrubsig.org if (pathprog(argv[0], execnamebuff, sizeof (execnamebuff)) <= 0)
24010898Sroland.mainz@nrubsig.org error(ERROR_exit(1), "could not determinate exec name.");
24110898Sroland.mainz@nrubsig.org
24210898Sroland.mainz@nrubsig.org progname = (const char *)strrchr(execnamebuff, '/');
24310898Sroland.mainz@nrubsig.org if (progname != NULL) {
24410898Sroland.mainz@nrubsig.org progname++;
24510898Sroland.mainz@nrubsig.org }
24610898Sroland.mainz@nrubsig.org else
24710898Sroland.mainz@nrubsig.org {
24810898Sroland.mainz@nrubsig.org progname = execnamebuff;
24910898Sroland.mainz@nrubsig.org }
25010898Sroland.mainz@nrubsig.org
25110898Sroland.mainz@nrubsig.org /* Execute command... */
25210898Sroland.mainz@nrubsig.org if (brec = find_bfastpathrec(progname)) {
25310898Sroland.mainz@nrubsig.org /* ... either via a fast path (calling the code directly) ... */
25410898Sroland.mainz@nrubsig.org return (fastpath_builtin_main(brec, argc, argv));
25510898Sroland.mainz@nrubsig.org }
25610898Sroland.mainz@nrubsig.org else
25710898Sroland.mainz@nrubsig.org {
25810898Sroland.mainz@nrubsig.org /* ... or from within a full shell. */
25910898Sroland.mainz@nrubsig.org return (script_builtin_main(argc, argv));
26010898Sroland.mainz@nrubsig.org }
26110898Sroland.mainz@nrubsig.org }
262