xref: /titanic_50/usr/src/cmd/ksh/builtins/alias.c (revision d185aafa0dcc4aa576fc668a1d1ce3a28660c456)
181af778eSCasper H.S. Dik /*
281af778eSCasper H.S. Dik  * CDDL HEADER START
381af778eSCasper H.S. Dik  *
481af778eSCasper H.S. Dik  * The contents of this file are subject to the terms of the
581af778eSCasper H.S. Dik  * Common Development and Distribution License (the "License").
681af778eSCasper H.S. Dik  * You may not use this file except in compliance with the License.
781af778eSCasper H.S. Dik  *
881af778eSCasper H.S. Dik  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
981af778eSCasper H.S. Dik  * or http://www.opensolaris.org/os/licensing.
1081af778eSCasper H.S. Dik  * See the License for the specific language governing permissions
1181af778eSCasper H.S. Dik  * and limitations under the License.
1281af778eSCasper H.S. Dik  *
1381af778eSCasper H.S. Dik  * When distributing Covered Code, include this CDDL HEADER in each
1481af778eSCasper H.S. Dik  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1581af778eSCasper H.S. Dik  * If applicable, add the following below this CDDL HEADER, with the
1681af778eSCasper H.S. Dik  * fields enclosed by brackets "[]" replaced with your own identifying
1781af778eSCasper H.S. Dik  * information: Portions Copyright [yyyy] [name of copyright owner]
1881af778eSCasper H.S. Dik  *
1981af778eSCasper H.S. Dik  * CDDL HEADER END
2081af778eSCasper H.S. Dik  */
2181af778eSCasper H.S. Dik 
2281af778eSCasper H.S. Dik /*
2381af778eSCasper H.S. Dik  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
2481af778eSCasper H.S. Dik  * Use is subject to license terms.
2581af778eSCasper H.S. Dik  */
2681af778eSCasper H.S. Dik 
2781af778eSCasper H.S. Dik /*
2881af778eSCasper H.S. Dik  * alias.c is a C version of the alias.sh wrapper (which links ksh
2981af778eSCasper H.S. Dik  * builtins to commands in /usr/bin/, e.g. calling this wrapper as
3081af778eSCasper H.S. Dik  * /usr/bin/alias will call the ksh "alias" builtin, running it as
3181af778eSCasper H.S. Dik  * /usr/bin/cut will call the ksh "cut" builtin etc.
3281af778eSCasper H.S. Dik  */
3381af778eSCasper H.S. Dik 
3481af778eSCasper H.S. Dik #include <shell.h>
3581af778eSCasper H.S. Dik #include <nval.h>
3634f9b3eeSRoland Mainz #include <cmdext.h>
3781af778eSCasper H.S. Dik #include <stdio.h>
3881af778eSCasper H.S. Dik 
3934f9b3eeSRoland Mainz typedef struct {
4034f9b3eeSRoland Mainz 	const char *name;
4134f9b3eeSRoland Mainz 	int (* func)(int, char **, void *);
4234f9b3eeSRoland Mainz } bfastpathrec;
4334f9b3eeSRoland Mainz 
4434f9b3eeSRoland Mainz /*
4534f9b3eeSRoland Mainz  * We've disabled the "fastpath" codepath for some commands below
4634f9b3eeSRoland Mainz  * because it causes a paradoxon for large input files (as used by
4734f9b3eeSRoland Mainz  * ON PerfPIT for testing). For /usr/bin/rev (where the issue was
4834f9b3eeSRoland Mainz  * first discovered) it looks like this:
4934f9b3eeSRoland Mainz  * - for small files like /etc/profile the fastpath is faster in a loop
5034f9b3eeSRoland Mainz  *   with 1000 iterations (8 seconds with fastpath, 14 seconds without
5134f9b3eeSRoland Mainz  *   fastpath)
5234f9b3eeSRoland Mainz  * - for large files (/usr/pub/UTF-8 replicated until the test file
5334f9b3eeSRoland Mainz  *   reaches 24884706 bytes) the benchmark reverses: The fastpath now
5434f9b3eeSRoland Mainz  *   needs 40 seconds and without fastpath it needs 30 seconds (for 100
5534f9b3eeSRoland Mainz  *   iterations).
5634f9b3eeSRoland Mainz  */
5734f9b3eeSRoland Mainz #if 0
5834f9b3eeSRoland Mainz #define	ENABLE_PERFORMANCE_PARADOXON 1
5934f9b3eeSRoland Mainz #endif
6034f9b3eeSRoland Mainz 
6134f9b3eeSRoland Mainz /*
6234f9b3eeSRoland Mainz  * List of libcmd builtins which do not require a |Shell_t| context.
6334f9b3eeSRoland Mainz  * This list was automatically generated from <ast/cmdext.h>
6434f9b3eeSRoland Mainz  */
6534f9b3eeSRoland Mainz static const
6634f9b3eeSRoland Mainz bfastpathrec fastpath_builtins[] =
6734f9b3eeSRoland Mainz {
6834f9b3eeSRoland Mainz 	/* This list must be alphabetically sorted for |strcmp()| usage */
6934f9b3eeSRoland Mainz 	{ "basename",	b_basename	},
7034f9b3eeSRoland Mainz 	{ "cat",	b_cat		},
7134f9b3eeSRoland Mainz 	{ "chgrp",	b_chgrp		},
7234f9b3eeSRoland Mainz 	{ "chmod",	b_chmod		},
7334f9b3eeSRoland Mainz 	{ "chown",	b_chown		},
7434f9b3eeSRoland Mainz #ifdef ENABLE_PERFORMANCE_PARADOXON
7534f9b3eeSRoland Mainz 	{ "cksum",	b_cksum		},
7634f9b3eeSRoland Mainz #endif /* ENABLE_PERFORMANCE_PARADOXON */
7734f9b3eeSRoland Mainz 	{ "cmp",	b_cmp		},
7834f9b3eeSRoland Mainz 	{ "comm",	b_comm		},
7934f9b3eeSRoland Mainz 	{ "cp",		b_cp		},
8034f9b3eeSRoland Mainz 	{ "cut",	b_cut		},
8134f9b3eeSRoland Mainz 	{ "date",	b_date		},
8234f9b3eeSRoland Mainz 	{ "dirname",	b_dirname	},
8334f9b3eeSRoland Mainz 	{ "egrep",	b_egrep		},
8434f9b3eeSRoland Mainz 	{ "expr",	b_expr		},
8534f9b3eeSRoland Mainz 	{ "fds",	b_fds		},
8634f9b3eeSRoland Mainz 	{ "fgrep",	b_fgrep		},
8734f9b3eeSRoland Mainz 	{ "fmt",	b_fmt		},
8834f9b3eeSRoland Mainz 	{ "fold",	b_fold		},
8934f9b3eeSRoland Mainz 	{ "getconf",	b_getconf	},
9034f9b3eeSRoland Mainz 	{ "grep",	b_grep		},
9134f9b3eeSRoland Mainz 	{ "head",	b_head		},
9234f9b3eeSRoland Mainz 	{ "id",		b_id		},
9334f9b3eeSRoland Mainz 	{ "join",	b_join		},
9434f9b3eeSRoland Mainz 	{ "ln",		b_ln		},
9534f9b3eeSRoland Mainz 	{ "logname",	b_logname	},
9634f9b3eeSRoland Mainz 	{ "md5sum",	b_md5sum	},
9734f9b3eeSRoland Mainz 	{ "mkdir",	b_mkdir		},
9834f9b3eeSRoland Mainz 	{ "mkfifo",	b_mkfifo	},
9934f9b3eeSRoland Mainz 	{ "mktemp",	b_mktemp	},
10034f9b3eeSRoland Mainz 	{ "mv",		b_mv		},
10134f9b3eeSRoland Mainz 	{ "paste",	b_paste 	},
10234f9b3eeSRoland Mainz 	{ "pathchk",	b_pathchk	},
10334f9b3eeSRoland Mainz 	{ "pids",	b_pids		},
10434f9b3eeSRoland Mainz 	{ "readlink",	b_readlink	},
10534f9b3eeSRoland Mainz #ifdef ENABLE_PERFORMANCE_PARADOXON
10634f9b3eeSRoland Mainz 	{ "rev",	b_rev		},
10734f9b3eeSRoland Mainz #endif /* ENABLE_PERFORMANCE_PARADOXON */
10834f9b3eeSRoland Mainz 	{ "rm",		b_rm		},
10934f9b3eeSRoland Mainz 	{ "rmdir",	b_rmdir		},
11034f9b3eeSRoland Mainz 	{ "stty",	b_stty		},
11134f9b3eeSRoland Mainz #ifdef ENABLE_PERFORMANCE_PARADOXON
11234f9b3eeSRoland Mainz 	{ "sum",	b_sum		},
11334f9b3eeSRoland Mainz #endif /* ENABLE_PERFORMANCE_PARADOXON */
11434f9b3eeSRoland Mainz 	{ "sync",	b_sync		},
11534f9b3eeSRoland Mainz 	{ "tail",	b_tail		},
11634f9b3eeSRoland Mainz 	{ "tee",	b_tee		},
11734f9b3eeSRoland Mainz 	{ "tty",	b_tty		},
11834f9b3eeSRoland Mainz 	{ "uname",	b_uname		},
11934f9b3eeSRoland Mainz 	{ "uniq",	b_uniq		},
12034f9b3eeSRoland Mainz 	{ "wc",		b_wc		},
12134f9b3eeSRoland Mainz 	{ "xgrep",	b_xgrep		},
12234f9b3eeSRoland Mainz 	{ NULL, 	(int (*)(int, char **, void *))NULL }
12334f9b3eeSRoland Mainz };
12434f9b3eeSRoland Mainz 
12534f9b3eeSRoland Mainz static inline
12634f9b3eeSRoland Mainz const bfastpathrec *
find_bfastpathrec(const char * name)12734f9b3eeSRoland Mainz find_bfastpathrec(const char *name)
12834f9b3eeSRoland Mainz {
12934f9b3eeSRoland Mainz 	unsigned int i;
13034f9b3eeSRoland Mainz 	signed int cmpres;
13134f9b3eeSRoland Mainz 	for (i = 0; fastpath_builtins[i].name != NULL; i++) {
13234f9b3eeSRoland Mainz 		cmpres = strcmp(fastpath_builtins[i].name, name);
13334f9b3eeSRoland Mainz 		if (cmpres == 0)
13434f9b3eeSRoland Mainz 			return (&fastpath_builtins[i]);
13534f9b3eeSRoland Mainz 		else if (cmpres > 0)
13634f9b3eeSRoland Mainz 			return (NULL);
13734f9b3eeSRoland Mainz 
13834f9b3eeSRoland Mainz 	}
13934f9b3eeSRoland Mainz 	return (NULL);
14034f9b3eeSRoland Mainz }
14134f9b3eeSRoland Mainz 
14234f9b3eeSRoland Mainz static inline
14334f9b3eeSRoland Mainz int
fastpath_builtin_main(const bfastpathrec * brec,int argc,char * argv[])14434f9b3eeSRoland Mainz fastpath_builtin_main(const bfastpathrec *brec, int argc, char *argv[])
14534f9b3eeSRoland Mainz {
14634f9b3eeSRoland Mainz 	setlocale(LC_ALL, ""); /* calls |_ast_setlocale()| */
14734f9b3eeSRoland Mainz 
14834f9b3eeSRoland Mainz 	return ((*brec->func)(argc, argv, NULL));
14934f9b3eeSRoland Mainz }
15034f9b3eeSRoland Mainz 
15134f9b3eeSRoland Mainz 
15281af778eSCasper H.S. Dik /* Builtin script, original derived from alias.sh */
15381af778eSCasper H.S. Dik static const char *script = "\n"
15481af778eSCasper H.S. Dik /* Get name of builtin */
1559a6f360eSCasper H.S. Dik "typeset cmd=\"${0##*/}\"\n"
15681af778eSCasper H.S. Dik /*
15781af778eSCasper H.S. Dik  * If the requested command is not an alias load it explicitly
15881af778eSCasper H.S. Dik  * to make sure it is not bound to a path (those built-ins which
15981af778eSCasper H.S. Dik  * are mapped via shell aliases point to commands which are
16081af778eSCasper H.S. Dik  * "special shell built-ins" which cannot be bound to a specific
16181af778eSCasper H.S. Dik  * PATH element) - otherwise we may execute the wrong command
16281af778eSCasper H.S. Dik  * if an executable with the same name sits in a PATH element
16381af778eSCasper H.S. Dik  * before /usr/bin (e.g. /usr/xpg4/bin/ls would be executed
16481af778eSCasper H.S. Dik  * before /usr/bin/ls if the path was something like
16581af778eSCasper H.S. Dik  * PATH=/usr/xpg4/bin:/usr/bin).
16681af778eSCasper H.S. Dik  */
16781af778eSCasper H.S. Dik "if [[ \"${cmd}\" != ~(Elr)(alias|unalias|command) ]] && "
16881af778eSCasper H.S. Dik 	"! alias \"${cmd}\" >/dev/null 2>&1 ; then\n"
169*d185aafaSOlga Kryzhanovska 	"PATH='' builtin \"${cmd}\"\n"
17081af778eSCasper H.S. Dik "fi\n"
17181af778eSCasper H.S. Dik /* command is a keyword and needs to be handled separately */
17281af778eSCasper H.S. Dik "if [[ \"${cmd}\" == \"command\" ]] ; then\n"
17381af778eSCasper H.S. Dik 	"command \"$@\"\n"
17481af778eSCasper H.S. Dik "else\n"
17534f9b3eeSRoland Mainz #ifdef WORKAROUND_FOR_ALIAS_CRASH
17634f9b3eeSRoland Mainz /*
17734f9b3eeSRoland Mainz  * Work around a crash in /usr/bin/alias when invalid options are
17834f9b3eeSRoland Mainz  * passed (e.g. $ /usr/bin/alias -c #). The shell code will call
17934f9b3eeSRoland Mainz  * an error handler which does a |longjmp()| but somehow the code
18034f9b3eeSRoland Mainz  * failed to do the |setjmp()| before this point.
18134f9b3eeSRoland Mainz  * Putting the "alias" command in a subshell avoids the crash.
18234f9b3eeSRoland Mainz  * Real cause of the issue is under investigation and a fix be
18334f9b3eeSRoland Mainz  * delivered with the next ast-ksh update.
18434f9b3eeSRoland Mainz  */
18534f9b3eeSRoland Mainz 	"( \"${cmd}\" \"$@\" )\n"
18634f9b3eeSRoland Mainz #else
18781af778eSCasper H.S. Dik 	"\"${cmd}\" \"$@\"\n"
18834f9b3eeSRoland Mainz #endif /* WORKAROUND_FOR_ALIAS_CRASH */
18981af778eSCasper H.S. Dik "fi\n"
19081af778eSCasper H.S. Dik "exitval=$?";
19181af778eSCasper H.S. Dik 
19234f9b3eeSRoland Mainz 
19334f9b3eeSRoland Mainz static inline
19481af778eSCasper H.S. Dik int
script_builtin_main(int argc,char * argv[])19534f9b3eeSRoland Mainz script_builtin_main(int argc, char *argv[])
19681af778eSCasper H.S. Dik {
19781af778eSCasper H.S. Dik 	int i;
19881af778eSCasper H.S. Dik 	Shell_t *shp;
19981af778eSCasper H.S. Dik 	Namval_t *np;
20081af778eSCasper H.S. Dik 	int exitval;
20181af778eSCasper H.S. Dik 
20281af778eSCasper H.S. Dik 	/*
20381af778eSCasper H.S. Dik 	 * Create copy of |argv| array shifted by one position to
20481af778eSCasper H.S. Dik 	 * emulate $ /usr/bin/sh <scriptname> <args1> <arg2> ... #.
20581af778eSCasper H.S. Dik 	 * First position is set to "/usr/bin/sh" since other
20681af778eSCasper H.S. Dik 	 * values may trigger special shell modes (e.g. *rsh* will
20781af778eSCasper H.S. Dik 	 * trigger "restricted" shell mode etc.).
20881af778eSCasper H.S. Dik 	 */
20981af778eSCasper H.S. Dik 	char *xargv[argc+2];
21081af778eSCasper H.S. Dik 	xargv[0] = "/usr/bin/sh";
21181af778eSCasper H.S. Dik 	xargv[1] = "scriptname";
21281af778eSCasper H.S. Dik 	for (i = 0; i < argc; i++) {
21381af778eSCasper H.S. Dik 		xargv[i+1] = argv[i];
21481af778eSCasper H.S. Dik 	}
21581af778eSCasper H.S. Dik 	xargv[i+1] = NULL;
21681af778eSCasper H.S. Dik 
21781af778eSCasper H.S. Dik 	shp = sh_init(argc+1, xargv, 0);
21881af778eSCasper H.S. Dik 	if (!shp)
21981af778eSCasper H.S. Dik 		error(ERROR_exit(1), "shell initialisation failed.");
22081af778eSCasper H.S. Dik 	(void) sh_trap(script, 0);
22181af778eSCasper H.S. Dik 
22281af778eSCasper H.S. Dik 	np = nv_open("exitval", shp->var_tree, 0);
22381af778eSCasper H.S. Dik 	if (!np)
22481af778eSCasper H.S. Dik 		error(ERROR_exit(1), "variable %s not found.", "exitval");
22581af778eSCasper H.S. Dik 	exitval = (int)nv_getnum(np);
22681af778eSCasper H.S. Dik 	nv_close(np);
22781af778eSCasper H.S. Dik 
22881af778eSCasper H.S. Dik 	return (exitval);
22981af778eSCasper H.S. Dik }
23034f9b3eeSRoland Mainz 
23134f9b3eeSRoland Mainz int
main(int argc,char * argv[])23234f9b3eeSRoland Mainz main(int argc, char *argv[])
23334f9b3eeSRoland Mainz {
23434f9b3eeSRoland Mainz 	const char *progname;
23534f9b3eeSRoland Mainz 	const bfastpathrec *brec;
23634f9b3eeSRoland Mainz 	char execnamebuff[PATH_MAX+1];
23734f9b3eeSRoland Mainz 
23834f9b3eeSRoland Mainz 	/* Get program name */
23934f9b3eeSRoland Mainz 	if (pathprog(argv[0], execnamebuff, sizeof (execnamebuff)) <= 0)
24034f9b3eeSRoland Mainz 		error(ERROR_exit(1), "could not determinate exec name.");
24134f9b3eeSRoland Mainz 
24234f9b3eeSRoland Mainz 	progname = (const char *)strrchr(execnamebuff, '/');
24334f9b3eeSRoland Mainz 	if (progname != NULL) {
24434f9b3eeSRoland Mainz 		progname++;
24534f9b3eeSRoland Mainz 	}
24634f9b3eeSRoland Mainz 	else
24734f9b3eeSRoland Mainz 	{
24834f9b3eeSRoland Mainz 		progname = execnamebuff;
24934f9b3eeSRoland Mainz 	}
25034f9b3eeSRoland Mainz 
25134f9b3eeSRoland Mainz 	/* Execute command... */
25234f9b3eeSRoland Mainz 	if (brec = find_bfastpathrec(progname)) {
25334f9b3eeSRoland Mainz 		/* ... either via a fast path (calling the code directly) ... */
25434f9b3eeSRoland Mainz 		return (fastpath_builtin_main(brec, argc, argv));
25534f9b3eeSRoland Mainz 	}
25634f9b3eeSRoland Mainz 	else
25734f9b3eeSRoland Mainz 	{
25834f9b3eeSRoland Mainz 		/* ... or from within a full shell. */
25934f9b3eeSRoland Mainz 		return (script_builtin_main(argc, argv));
26034f9b3eeSRoland Mainz 	}
26134f9b3eeSRoland Mainz }
262