xref: /titanic_51/usr/src/cmd/ast/ksh/builtins/alias.c (revision b4dd7d09880f14016feece03929a224eca1cf39a)
1*b4dd7d09SAndy Fiddaman /*
2*b4dd7d09SAndy Fiddaman  * CDDL HEADER START
3*b4dd7d09SAndy Fiddaman  *
4*b4dd7d09SAndy Fiddaman  * The contents of this file are subject to the terms of the
5*b4dd7d09SAndy Fiddaman  * Common Development and Distribution License (the "License").
6*b4dd7d09SAndy Fiddaman  * You may not use this file except in compliance with the License.
7*b4dd7d09SAndy Fiddaman  *
8*b4dd7d09SAndy Fiddaman  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*b4dd7d09SAndy Fiddaman  * or http://www.opensolaris.org/os/licensing.
10*b4dd7d09SAndy Fiddaman  * See the License for the specific language governing permissions
11*b4dd7d09SAndy Fiddaman  * and limitations under the License.
12*b4dd7d09SAndy Fiddaman  *
13*b4dd7d09SAndy Fiddaman  * When distributing Covered Code, include this CDDL HEADER in each
14*b4dd7d09SAndy Fiddaman  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*b4dd7d09SAndy Fiddaman  * If applicable, add the following below this CDDL HEADER, with the
16*b4dd7d09SAndy Fiddaman  * fields enclosed by brackets "[]" replaced with your own identifying
17*b4dd7d09SAndy Fiddaman  * information: Portions Copyright [yyyy] [name of copyright owner]
18*b4dd7d09SAndy Fiddaman  *
19*b4dd7d09SAndy Fiddaman  * CDDL HEADER END
20*b4dd7d09SAndy Fiddaman  */
21*b4dd7d09SAndy Fiddaman 
22*b4dd7d09SAndy Fiddaman /*
23*b4dd7d09SAndy Fiddaman  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24*b4dd7d09SAndy Fiddaman  * Use is subject to license terms.
25*b4dd7d09SAndy Fiddaman  *
26*b4dd7d09SAndy Fiddaman  * Copyright 2021 OmniOS Community Edition (OmniOSce) Association.
27*b4dd7d09SAndy Fiddaman  */
28*b4dd7d09SAndy Fiddaman 
29*b4dd7d09SAndy Fiddaman /*
30*b4dd7d09SAndy Fiddaman  * alias.c is a C version of the alias.sh wrapper (which links ksh
31*b4dd7d09SAndy Fiddaman  * builtins to commands in /usr/bin/, e.g. calling this wrapper as
32*b4dd7d09SAndy Fiddaman  * /usr/bin/alias will call the ksh "alias" builtin, running it as
33*b4dd7d09SAndy Fiddaman  * /usr/bin/cut will call the ksh "cut" builtin etc.
34*b4dd7d09SAndy Fiddaman  */
35*b4dd7d09SAndy Fiddaman 
36*b4dd7d09SAndy Fiddaman #include <defs.h>
37*b4dd7d09SAndy Fiddaman #include <shell.h>
38*b4dd7d09SAndy Fiddaman #include <nval.h>
39*b4dd7d09SAndy Fiddaman #include <cmdext.h>
40*b4dd7d09SAndy Fiddaman #include <stdio.h>
41*b4dd7d09SAndy Fiddaman #include <setjmp.h>
42*b4dd7d09SAndy Fiddaman 
43*b4dd7d09SAndy Fiddaman #undef calloc
44*b4dd7d09SAndy Fiddaman #undef free
45*b4dd7d09SAndy Fiddaman 
46*b4dd7d09SAndy Fiddaman typedef struct {
47*b4dd7d09SAndy Fiddaman 	const char *name;
48*b4dd7d09SAndy Fiddaman 	int (* func)(int, char **, Shbltin_t *);
49*b4dd7d09SAndy Fiddaman } bfastpathrec;
50*b4dd7d09SAndy Fiddaman 
51*b4dd7d09SAndy Fiddaman /*
52*b4dd7d09SAndy Fiddaman  * We've disabled the "fastpath" codepath for some commands below
53*b4dd7d09SAndy Fiddaman  * because it causes a paradoxon for large input files (as used by
54*b4dd7d09SAndy Fiddaman  * ON PerfPIT for testing). For /usr/bin/rev (where the issue was
55*b4dd7d09SAndy Fiddaman  * first discovered) it looks like this:
56*b4dd7d09SAndy Fiddaman  * - for small files like /etc/profile the fastpath is faster in a loop
57*b4dd7d09SAndy Fiddaman  *   with 1000 iterations (8 seconds with fastpath, 14 seconds without
58*b4dd7d09SAndy Fiddaman  *   fastpath)
59*b4dd7d09SAndy Fiddaman  * - for large files (/usr/pub/UTF-8 replicated until the test file
60*b4dd7d09SAndy Fiddaman  *   reaches 24884706 bytes) the benchmark reverses: The fastpath now
61*b4dd7d09SAndy Fiddaman  *   needs 40 seconds and without fastpath it needs 30 seconds (for 100
62*b4dd7d09SAndy Fiddaman  *   iterations).
63*b4dd7d09SAndy Fiddaman  */
64*b4dd7d09SAndy Fiddaman #if 0
65*b4dd7d09SAndy Fiddaman #define	ENABLE_PERFORMANCE_PARADOXON 1
66*b4dd7d09SAndy Fiddaman #endif
67*b4dd7d09SAndy Fiddaman 
68*b4dd7d09SAndy Fiddaman /*
69*b4dd7d09SAndy Fiddaman  * List of libcmd builtins which do not require a |Shell_t| context.
70*b4dd7d09SAndy Fiddaman  * This list was automatically generated from <ast/cmdext.h>
71*b4dd7d09SAndy Fiddaman  */
72*b4dd7d09SAndy Fiddaman static const
73*b4dd7d09SAndy Fiddaman bfastpathrec fastpath_builtins[] =
74*b4dd7d09SAndy Fiddaman {
75*b4dd7d09SAndy Fiddaman 	/* This list must be alphabetically sorted for |strcmp()| usage */
76*b4dd7d09SAndy Fiddaman 	{ "basename",	b_basename	},
77*b4dd7d09SAndy Fiddaman 	{ "cat",	b_cat		},
78*b4dd7d09SAndy Fiddaman 	{ "chgrp",	b_chgrp		},
79*b4dd7d09SAndy Fiddaman 	{ "chmod",	b_chmod		},
80*b4dd7d09SAndy Fiddaman 	{ "chown",	b_chown		},
81*b4dd7d09SAndy Fiddaman #ifdef ENABLE_PERFORMANCE_PARADOXON
82*b4dd7d09SAndy Fiddaman 	{ "cksum",	b_cksum		},
83*b4dd7d09SAndy Fiddaman #endif /* ENABLE_PERFORMANCE_PARADOXON */
84*b4dd7d09SAndy Fiddaman 	{ "cmp",	b_cmp		},
85*b4dd7d09SAndy Fiddaman 	{ "comm",	b_comm		},
86*b4dd7d09SAndy Fiddaman 	{ "cp",		b_cp		},
87*b4dd7d09SAndy Fiddaman 	{ "cut",	b_cut		},
88*b4dd7d09SAndy Fiddaman 	{ "date",	b_date		},
89*b4dd7d09SAndy Fiddaman 	{ "dirname",	b_dirname	},
90*b4dd7d09SAndy Fiddaman 	{ "expr",	b_expr		},
91*b4dd7d09SAndy Fiddaman 	{ "fds",	b_fds		},
92*b4dd7d09SAndy Fiddaman 	{ "fmt",	b_fmt		},
93*b4dd7d09SAndy Fiddaman 	{ "fold",	b_fold		},
94*b4dd7d09SAndy Fiddaman 	{ "getconf",	b_getconf	},
95*b4dd7d09SAndy Fiddaman 	{ "head",	b_head		},
96*b4dd7d09SAndy Fiddaman 	{ "id",		b_id		},
97*b4dd7d09SAndy Fiddaman 	{ "join",	b_join		},
98*b4dd7d09SAndy Fiddaman 	{ "ln",		b_ln		},
99*b4dd7d09SAndy Fiddaman 	{ "logname",	b_logname	},
100*b4dd7d09SAndy Fiddaman 	{ "md5sum",	b_md5sum	},
101*b4dd7d09SAndy Fiddaman 	{ "mkdir",	b_mkdir		},
102*b4dd7d09SAndy Fiddaman 	{ "mkfifo",	b_mkfifo	},
103*b4dd7d09SAndy Fiddaman 	{ "mktemp",	b_mktemp	},
104*b4dd7d09SAndy Fiddaman 	{ "mv",		b_mv		},
105*b4dd7d09SAndy Fiddaman 	{ "paste",	b_paste 	},
106*b4dd7d09SAndy Fiddaman 	{ "pathchk",	b_pathchk	},
107*b4dd7d09SAndy Fiddaman 	{ "pids",	b_pids		},
108*b4dd7d09SAndy Fiddaman #ifdef ENABLE_PERFORMANCE_PARADOXON
109*b4dd7d09SAndy Fiddaman 	{ "rev",	b_rev		},
110*b4dd7d09SAndy Fiddaman #endif /* ENABLE_PERFORMANCE_PARADOXON */
111*b4dd7d09SAndy Fiddaman 	{ "rm",		b_rm		},
112*b4dd7d09SAndy Fiddaman 	{ "rmdir",	b_rmdir		},
113*b4dd7d09SAndy Fiddaman 	{ "stty",	b_stty		},
114*b4dd7d09SAndy Fiddaman #ifdef ENABLE_PERFORMANCE_PARADOXON
115*b4dd7d09SAndy Fiddaman 	{ "sum",	b_sum		},
116*b4dd7d09SAndy Fiddaman #endif /* ENABLE_PERFORMANCE_PARADOXON */
117*b4dd7d09SAndy Fiddaman 	{ "sync",	b_sync		},
118*b4dd7d09SAndy Fiddaman 	{ "tail",	b_tail		},
119*b4dd7d09SAndy Fiddaman 	{ "tee",	b_tee		},
120*b4dd7d09SAndy Fiddaman 	{ "tty",	b_tty		},
121*b4dd7d09SAndy Fiddaman 	{ "uname",	b_uname		},
122*b4dd7d09SAndy Fiddaman 	{ "uniq",	b_uniq		},
123*b4dd7d09SAndy Fiddaman 	{ "vmstate",	b_vmstate	},
124*b4dd7d09SAndy Fiddaman 	{ "wc",		b_wc		},
125*b4dd7d09SAndy Fiddaman 	{ NULL,		NULL		}
126*b4dd7d09SAndy Fiddaman };
127*b4dd7d09SAndy Fiddaman 
128*b4dd7d09SAndy Fiddaman static inline const bfastpathrec *
129*b4dd7d09SAndy Fiddaman find_bfastpathrec(const char *name)
130*b4dd7d09SAndy Fiddaman {
131*b4dd7d09SAndy Fiddaman 	unsigned int i;
132*b4dd7d09SAndy Fiddaman 	signed int cmpres;
133*b4dd7d09SAndy Fiddaman 	for (i = 0; fastpath_builtins[i].name != NULL; i++) {
134*b4dd7d09SAndy Fiddaman 		cmpres = strcmp(fastpath_builtins[i].name, name);
135*b4dd7d09SAndy Fiddaman 		if (cmpres == 0)
136*b4dd7d09SAndy Fiddaman 			return (&fastpath_builtins[i]);
137*b4dd7d09SAndy Fiddaman 		else if (cmpres > 0)
138*b4dd7d09SAndy Fiddaman 			return (NULL);
139*b4dd7d09SAndy Fiddaman 	}
140*b4dd7d09SAndy Fiddaman 	return (NULL);
141*b4dd7d09SAndy Fiddaman }
142*b4dd7d09SAndy Fiddaman 
143*b4dd7d09SAndy Fiddaman static inline int
144*b4dd7d09SAndy Fiddaman fastpath_builtin_main(const bfastpathrec *brec, int argc, char *argv[])
145*b4dd7d09SAndy Fiddaman {
146*b4dd7d09SAndy Fiddaman 	setlocale(LC_ALL, ""); /* calls |_ast_setlocale()| */
147*b4dd7d09SAndy Fiddaman 
148*b4dd7d09SAndy Fiddaman 	return ((*brec->func)(argc, argv, NULL));
149*b4dd7d09SAndy Fiddaman }
150*b4dd7d09SAndy Fiddaman 
151*b4dd7d09SAndy Fiddaman 
152*b4dd7d09SAndy Fiddaman /* Builtin script, originally derived from alias.sh */
153*b4dd7d09SAndy Fiddaman static const char *script = "\n"
154*b4dd7d09SAndy Fiddaman /* Get name of builtin */
155*b4dd7d09SAndy Fiddaman "typeset cmd=\"${0##*/}\"\n"
156*b4dd7d09SAndy Fiddaman /*
157*b4dd7d09SAndy Fiddaman  * If the requested command is not an alias, load it explicitly
158*b4dd7d09SAndy Fiddaman  * to make sure it is not bound to a path (those built-ins which
159*b4dd7d09SAndy Fiddaman  * are mapped via shell aliases point to commands which are
160*b4dd7d09SAndy Fiddaman  * "special shell built-ins" which cannot be bound to a specific
161*b4dd7d09SAndy Fiddaman  * PATH element) - otherwise we may execute the wrong command
162*b4dd7d09SAndy Fiddaman  * if an executable with the same name sits in a PATH element
163*b4dd7d09SAndy Fiddaman  * before /usr/bin (e.g. /usr/xpg4/bin/ls would be executed
164*b4dd7d09SAndy Fiddaman  * before /usr/bin/ls if the path was something like
165*b4dd7d09SAndy Fiddaman  * PATH=/usr/xpg4/bin:/usr/bin).
166*b4dd7d09SAndy Fiddaman  */
167*b4dd7d09SAndy Fiddaman "if [[ \"${cmd}\" != ~(Elr)(alias|unalias|command) ]] && "
168*b4dd7d09SAndy Fiddaman 	"! alias \"${cmd}\" >/dev/null 2>&1 ; then\n"
169*b4dd7d09SAndy Fiddaman 	"PATH='' builtin \"${cmd}\"\n"
170*b4dd7d09SAndy Fiddaman "fi\n"
171*b4dd7d09SAndy Fiddaman /* command is a keyword and needs to be handled separately */
172*b4dd7d09SAndy Fiddaman "if [[ \"${cmd}\" == \"command\" ]] ; then\n"
173*b4dd7d09SAndy Fiddaman 	"command \"$@\"\n"
174*b4dd7d09SAndy Fiddaman "else\n"
175*b4dd7d09SAndy Fiddaman 	"\"${cmd}\" \"$@\"\n"
176*b4dd7d09SAndy Fiddaman "fi\n"
177*b4dd7d09SAndy Fiddaman "exitval=$?";
178*b4dd7d09SAndy Fiddaman 
179*b4dd7d09SAndy Fiddaman static inline int
180*b4dd7d09SAndy Fiddaman script_builtin_main(int argc, char **argv)
181*b4dd7d09SAndy Fiddaman {
182*b4dd7d09SAndy Fiddaman 	int i;
183*b4dd7d09SAndy Fiddaman 	Shell_t *shp;
184*b4dd7d09SAndy Fiddaman 	Namval_t *np;
185*b4dd7d09SAndy Fiddaman 	int exitval;
186*b4dd7d09SAndy Fiddaman 	char **xargv;
187*b4dd7d09SAndy Fiddaman 
188*b4dd7d09SAndy Fiddaman 	/*
189*b4dd7d09SAndy Fiddaman 	 * Create copy of |argv| array shifted by one position to
190*b4dd7d09SAndy Fiddaman 	 * emulate $ /usr/bin/sh <scriptname> <args1> <arg2> ... #.
191*b4dd7d09SAndy Fiddaman 	 * First position is set to "/usr/bin/sh" since other
192*b4dd7d09SAndy Fiddaman 	 * values may trigger special shell modes (e.g. *rsh* will
193*b4dd7d09SAndy Fiddaman 	 * trigger "restricted" shell mode etc.).
194*b4dd7d09SAndy Fiddaman 	 */
195*b4dd7d09SAndy Fiddaman 	xargv = calloc(argc + 2, sizeof (char *));
196*b4dd7d09SAndy Fiddaman 	if (xargv == NULL)
197*b4dd7d09SAndy Fiddaman 		return (1);
198*b4dd7d09SAndy Fiddaman 	xargv[0] = "/usr/bin/sh";
199*b4dd7d09SAndy Fiddaman 	for (i = 0; i < argc; i++)
200*b4dd7d09SAndy Fiddaman 		xargv[i + 1] = argv[i];
201*b4dd7d09SAndy Fiddaman 	xargv[i + 1] = NULL;
202*b4dd7d09SAndy Fiddaman 
203*b4dd7d09SAndy Fiddaman 	shp = sh_init(argc + 1, xargv, 0);
204*b4dd7d09SAndy Fiddaman 	if (!shp)
205*b4dd7d09SAndy Fiddaman 		error(ERROR_exit(1), "shell initialisation failed.");
206*b4dd7d09SAndy Fiddaman 	if (setjmp(*shp->jmplist) == 0)
207*b4dd7d09SAndy Fiddaman 		(void) sh_trap(script, 0);
208*b4dd7d09SAndy Fiddaman 
209*b4dd7d09SAndy Fiddaman 	np = nv_open("exitval", shp->var_tree, 0);
210*b4dd7d09SAndy Fiddaman 	if (!np)
211*b4dd7d09SAndy Fiddaman 		error(ERROR_exit(1), "variable %s not found.", "exitval");
212*b4dd7d09SAndy Fiddaman 	exitval = (int)nv_getnum(np);
213*b4dd7d09SAndy Fiddaman 	nv_close(np);
214*b4dd7d09SAndy Fiddaman 
215*b4dd7d09SAndy Fiddaman 	free(xargv);
216*b4dd7d09SAndy Fiddaman 
217*b4dd7d09SAndy Fiddaman 	return (exitval);
218*b4dd7d09SAndy Fiddaman }
219*b4dd7d09SAndy Fiddaman 
220*b4dd7d09SAndy Fiddaman int
221*b4dd7d09SAndy Fiddaman main(int argc, char **argv)
222*b4dd7d09SAndy Fiddaman {
223*b4dd7d09SAndy Fiddaman 	const char *progname;
224*b4dd7d09SAndy Fiddaman 	const bfastpathrec *brec;
225*b4dd7d09SAndy Fiddaman 	char execnamebuff[PATH_MAX + 1];
226*b4dd7d09SAndy Fiddaman 
227*b4dd7d09SAndy Fiddaman 	/* Get program name */
228*b4dd7d09SAndy Fiddaman 	if (pathprog(argv[0], execnamebuff, sizeof (execnamebuff)) <= 0)
229*b4dd7d09SAndy Fiddaman 		error(ERROR_exit(1), "could not determinate exec name.");
230*b4dd7d09SAndy Fiddaman 
231*b4dd7d09SAndy Fiddaman 	progname = (const char *)strrchr(execnamebuff, '/');
232*b4dd7d09SAndy Fiddaman 
233*b4dd7d09SAndy Fiddaman 	if (progname != NULL)
234*b4dd7d09SAndy Fiddaman 		progname++;
235*b4dd7d09SAndy Fiddaman 	else
236*b4dd7d09SAndy Fiddaman 		progname = execnamebuff;
237*b4dd7d09SAndy Fiddaman 
238*b4dd7d09SAndy Fiddaman 	/* Execute command... */
239*b4dd7d09SAndy Fiddaman 	if (brec = find_bfastpathrec(progname)) {
240*b4dd7d09SAndy Fiddaman 		/* ... either via a fast path (calling the code directly) ... */
241*b4dd7d09SAndy Fiddaman 		return (fastpath_builtin_main(brec, argc, argv));
242*b4dd7d09SAndy Fiddaman 	} else {
243*b4dd7d09SAndy Fiddaman 		/* ... or from within a full shell. */
244*b4dd7d09SAndy Fiddaman 		return (script_builtin_main(argc, argv));
245*b4dd7d09SAndy Fiddaman 	}
246*b4dd7d09SAndy Fiddaman }
247