xref: /onnv-gate/usr/src/cmd/ksh/builtins/alias.c (revision 10898)
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>
36*10898Sroland.mainz@nrubsig.org #include <cmdext.h>
378810SCasper.Dik@Sun.COM #include <stdio.h>
388810SCasper.Dik@Sun.COM 
39*10898Sroland.mainz@nrubsig.org typedef struct {
40*10898Sroland.mainz@nrubsig.org 	const char *name;
41*10898Sroland.mainz@nrubsig.org 	int (* func)(int, char **, void *);
42*10898Sroland.mainz@nrubsig.org } bfastpathrec;
43*10898Sroland.mainz@nrubsig.org 
44*10898Sroland.mainz@nrubsig.org /*
45*10898Sroland.mainz@nrubsig.org  * We've disabled the "fastpath" codepath for some commands below
46*10898Sroland.mainz@nrubsig.org  * because it causes a paradoxon for large input files (as used by
47*10898Sroland.mainz@nrubsig.org  * ON PerfPIT for testing). For /usr/bin/rev (where the issue was
48*10898Sroland.mainz@nrubsig.org  * first discovered) it looks like this:
49*10898Sroland.mainz@nrubsig.org  * - for small files like /etc/profile the fastpath is faster in a loop
50*10898Sroland.mainz@nrubsig.org  *   with 1000 iterations (8 seconds with fastpath, 14 seconds without
51*10898Sroland.mainz@nrubsig.org  *   fastpath)
52*10898Sroland.mainz@nrubsig.org  * - for large files (/usr/pub/UTF-8 replicated until the test file
53*10898Sroland.mainz@nrubsig.org  *   reaches 24884706 bytes) the benchmark reverses: The fastpath now
54*10898Sroland.mainz@nrubsig.org  *   needs 40 seconds and without fastpath it needs 30 seconds (for 100
55*10898Sroland.mainz@nrubsig.org  *   iterations).
56*10898Sroland.mainz@nrubsig.org  */
57*10898Sroland.mainz@nrubsig.org #if 0
58*10898Sroland.mainz@nrubsig.org #define	ENABLE_PERFORMANCE_PARADOXON 1
59*10898Sroland.mainz@nrubsig.org #endif
60*10898Sroland.mainz@nrubsig.org 
61*10898Sroland.mainz@nrubsig.org /*
62*10898Sroland.mainz@nrubsig.org  * List of libcmd builtins which do not require a |Shell_t| context.
63*10898Sroland.mainz@nrubsig.org  * This list was automatically generated from <ast/cmdext.h>
64*10898Sroland.mainz@nrubsig.org  */
65*10898Sroland.mainz@nrubsig.org static const
66*10898Sroland.mainz@nrubsig.org bfastpathrec fastpath_builtins[] =
67*10898Sroland.mainz@nrubsig.org {
68*10898Sroland.mainz@nrubsig.org 	/* This list must be alphabetically sorted for |strcmp()| usage */
69*10898Sroland.mainz@nrubsig.org 	{ "basename",	b_basename	},
70*10898Sroland.mainz@nrubsig.org 	{ "cat",	b_cat		},
71*10898Sroland.mainz@nrubsig.org 	{ "chgrp",	b_chgrp		},
72*10898Sroland.mainz@nrubsig.org 	{ "chmod",	b_chmod		},
73*10898Sroland.mainz@nrubsig.org 	{ "chown",	b_chown		},
74*10898Sroland.mainz@nrubsig.org #ifdef ENABLE_PERFORMANCE_PARADOXON
75*10898Sroland.mainz@nrubsig.org 	{ "cksum",	b_cksum		},
76*10898Sroland.mainz@nrubsig.org #endif /* ENABLE_PERFORMANCE_PARADOXON */
77*10898Sroland.mainz@nrubsig.org 	{ "cmp",	b_cmp		},
78*10898Sroland.mainz@nrubsig.org 	{ "comm",	b_comm		},
79*10898Sroland.mainz@nrubsig.org 	{ "cp",		b_cp		},
80*10898Sroland.mainz@nrubsig.org 	{ "cut",	b_cut		},
81*10898Sroland.mainz@nrubsig.org 	{ "date",	b_date		},
82*10898Sroland.mainz@nrubsig.org 	{ "dirname",	b_dirname	},
83*10898Sroland.mainz@nrubsig.org 	{ "egrep",	b_egrep		},
84*10898Sroland.mainz@nrubsig.org 	{ "expr",	b_expr		},
85*10898Sroland.mainz@nrubsig.org 	{ "fds",	b_fds		},
86*10898Sroland.mainz@nrubsig.org 	{ "fgrep",	b_fgrep		},
87*10898Sroland.mainz@nrubsig.org 	{ "fmt",	b_fmt		},
88*10898Sroland.mainz@nrubsig.org 	{ "fold",	b_fold		},
89*10898Sroland.mainz@nrubsig.org 	{ "getconf",	b_getconf	},
90*10898Sroland.mainz@nrubsig.org 	{ "grep",	b_grep		},
91*10898Sroland.mainz@nrubsig.org 	{ "head",	b_head		},
92*10898Sroland.mainz@nrubsig.org 	{ "id",		b_id		},
93*10898Sroland.mainz@nrubsig.org 	{ "join",	b_join		},
94*10898Sroland.mainz@nrubsig.org 	{ "ln",		b_ln		},
95*10898Sroland.mainz@nrubsig.org 	{ "logname",	b_logname	},
96*10898Sroland.mainz@nrubsig.org 	{ "md5sum",	b_md5sum	},
97*10898Sroland.mainz@nrubsig.org 	{ "mkdir",	b_mkdir		},
98*10898Sroland.mainz@nrubsig.org 	{ "mkfifo",	b_mkfifo	},
99*10898Sroland.mainz@nrubsig.org 	{ "mktemp",	b_mktemp	},
100*10898Sroland.mainz@nrubsig.org 	{ "mv",		b_mv		},
101*10898Sroland.mainz@nrubsig.org 	{ "paste",	b_paste 	},
102*10898Sroland.mainz@nrubsig.org 	{ "pathchk",	b_pathchk	},
103*10898Sroland.mainz@nrubsig.org 	{ "pids",	b_pids		},
104*10898Sroland.mainz@nrubsig.org 	{ "readlink",	b_readlink	},
105*10898Sroland.mainz@nrubsig.org #ifdef ENABLE_PERFORMANCE_PARADOXON
106*10898Sroland.mainz@nrubsig.org 	{ "rev",	b_rev		},
107*10898Sroland.mainz@nrubsig.org #endif /* ENABLE_PERFORMANCE_PARADOXON */
108*10898Sroland.mainz@nrubsig.org 	{ "rm",		b_rm		},
109*10898Sroland.mainz@nrubsig.org 	{ "rmdir",	b_rmdir		},
110*10898Sroland.mainz@nrubsig.org 	{ "stty",	b_stty		},
111*10898Sroland.mainz@nrubsig.org #ifdef ENABLE_PERFORMANCE_PARADOXON
112*10898Sroland.mainz@nrubsig.org 	{ "sum",	b_sum		},
113*10898Sroland.mainz@nrubsig.org #endif /* ENABLE_PERFORMANCE_PARADOXON */
114*10898Sroland.mainz@nrubsig.org 	{ "sync",	b_sync		},
115*10898Sroland.mainz@nrubsig.org 	{ "tail",	b_tail		},
116*10898Sroland.mainz@nrubsig.org 	{ "tee",	b_tee		},
117*10898Sroland.mainz@nrubsig.org 	{ "tty",	b_tty		},
118*10898Sroland.mainz@nrubsig.org 	{ "uname",	b_uname		},
119*10898Sroland.mainz@nrubsig.org 	{ "uniq",	b_uniq		},
120*10898Sroland.mainz@nrubsig.org 	{ "wc",		b_wc		},
121*10898Sroland.mainz@nrubsig.org 	{ "xgrep",	b_xgrep		},
122*10898Sroland.mainz@nrubsig.org 	{ NULL, 	(int (*)(int, char **, void *))NULL }
123*10898Sroland.mainz@nrubsig.org };
124*10898Sroland.mainz@nrubsig.org 
125*10898Sroland.mainz@nrubsig.org static inline
126*10898Sroland.mainz@nrubsig.org const bfastpathrec *
127*10898Sroland.mainz@nrubsig.org find_bfastpathrec(const char *name)
128*10898Sroland.mainz@nrubsig.org {
129*10898Sroland.mainz@nrubsig.org 	unsigned int i;
130*10898Sroland.mainz@nrubsig.org 	signed int cmpres;
131*10898Sroland.mainz@nrubsig.org 	for (i = 0; fastpath_builtins[i].name != NULL; i++) {
132*10898Sroland.mainz@nrubsig.org 		cmpres = strcmp(fastpath_builtins[i].name, name);
133*10898Sroland.mainz@nrubsig.org 		if (cmpres == 0)
134*10898Sroland.mainz@nrubsig.org 			return (&fastpath_builtins[i]);
135*10898Sroland.mainz@nrubsig.org 		else if (cmpres > 0)
136*10898Sroland.mainz@nrubsig.org 			return (NULL);
137*10898Sroland.mainz@nrubsig.org 
138*10898Sroland.mainz@nrubsig.org 	}
139*10898Sroland.mainz@nrubsig.org 	return (NULL);
140*10898Sroland.mainz@nrubsig.org }
141*10898Sroland.mainz@nrubsig.org 
142*10898Sroland.mainz@nrubsig.org static inline
143*10898Sroland.mainz@nrubsig.org int
144*10898Sroland.mainz@nrubsig.org fastpath_builtin_main(const bfastpathrec *brec, int argc, char *argv[])
145*10898Sroland.mainz@nrubsig.org {
146*10898Sroland.mainz@nrubsig.org 	setlocale(LC_ALL, ""); /* calls |_ast_setlocale()| */
147*10898Sroland.mainz@nrubsig.org 
148*10898Sroland.mainz@nrubsig.org 	return ((*brec->func)(argc, argv, NULL));
149*10898Sroland.mainz@nrubsig.org }
150*10898Sroland.mainz@nrubsig.org 
151*10898Sroland.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"
1698900SCasper.Dik@Sun.COM 	"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"
175*10898Sroland.mainz@nrubsig.org #ifdef WORKAROUND_FOR_ALIAS_CRASH
176*10898Sroland.mainz@nrubsig.org /*
177*10898Sroland.mainz@nrubsig.org  * Work around a crash in /usr/bin/alias when invalid options are
178*10898Sroland.mainz@nrubsig.org  * passed (e.g. $ /usr/bin/alias -c #). The shell code will call
179*10898Sroland.mainz@nrubsig.org  * an error handler which does a |longjmp()| but somehow the code
180*10898Sroland.mainz@nrubsig.org  * failed to do the |setjmp()| before this point.
181*10898Sroland.mainz@nrubsig.org  * Putting the "alias" command in a subshell avoids the crash.
182*10898Sroland.mainz@nrubsig.org  * Real cause of the issue is under investigation and a fix be
183*10898Sroland.mainz@nrubsig.org  * delivered with the next ast-ksh update.
184*10898Sroland.mainz@nrubsig.org  */
185*10898Sroland.mainz@nrubsig.org 	"( \"${cmd}\" \"$@\" )\n"
186*10898Sroland.mainz@nrubsig.org #else
1878900SCasper.Dik@Sun.COM 	"\"${cmd}\" \"$@\"\n"
188*10898Sroland.mainz@nrubsig.org #endif /* WORKAROUND_FOR_ALIAS_CRASH */
1898810SCasper.Dik@Sun.COM "fi\n"
1908810SCasper.Dik@Sun.COM "exitval=$?";
1918810SCasper.Dik@Sun.COM 
192*10898Sroland.mainz@nrubsig.org 
193*10898Sroland.mainz@nrubsig.org static inline
1948810SCasper.Dik@Sun.COM int
195*10898Sroland.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 }
230*10898Sroland.mainz@nrubsig.org 
231*10898Sroland.mainz@nrubsig.org int
232*10898Sroland.mainz@nrubsig.org main(int argc, char *argv[])
233*10898Sroland.mainz@nrubsig.org {
234*10898Sroland.mainz@nrubsig.org 	const char *progname;
235*10898Sroland.mainz@nrubsig.org 	const bfastpathrec *brec;
236*10898Sroland.mainz@nrubsig.org 	char execnamebuff[PATH_MAX+1];
237*10898Sroland.mainz@nrubsig.org 
238*10898Sroland.mainz@nrubsig.org 	/* Get program name */
239*10898Sroland.mainz@nrubsig.org 	if (pathprog(argv[0], execnamebuff, sizeof (execnamebuff)) <= 0)
240*10898Sroland.mainz@nrubsig.org 		error(ERROR_exit(1), "could not determinate exec name.");
241*10898Sroland.mainz@nrubsig.org 
242*10898Sroland.mainz@nrubsig.org 	progname = (const char *)strrchr(execnamebuff, '/');
243*10898Sroland.mainz@nrubsig.org 	if (progname != NULL) {
244*10898Sroland.mainz@nrubsig.org 		progname++;
245*10898Sroland.mainz@nrubsig.org 	}
246*10898Sroland.mainz@nrubsig.org 	else
247*10898Sroland.mainz@nrubsig.org 	{
248*10898Sroland.mainz@nrubsig.org 		progname = execnamebuff;
249*10898Sroland.mainz@nrubsig.org 	}
250*10898Sroland.mainz@nrubsig.org 
251*10898Sroland.mainz@nrubsig.org 	/* Execute command... */
252*10898Sroland.mainz@nrubsig.org 	if (brec = find_bfastpathrec(progname)) {
253*10898Sroland.mainz@nrubsig.org 		/* ... either via a fast path (calling the code directly) ... */
254*10898Sroland.mainz@nrubsig.org 		return (fastpath_builtin_main(brec, argc, argv));
255*10898Sroland.mainz@nrubsig.org 	}
256*10898Sroland.mainz@nrubsig.org 	else
257*10898Sroland.mainz@nrubsig.org 	{
258*10898Sroland.mainz@nrubsig.org 		/* ... or from within a full shell. */
259*10898Sroland.mainz@nrubsig.org 		return (script_builtin_main(argc, argv));
260*10898Sroland.mainz@nrubsig.org 	}
261*10898Sroland.mainz@nrubsig.org }
262