4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
28 * alias.c is a C version of the alias.sh wrapper (which links ksh
29 * builtins to commands in /usr/bin/, e.g. calling this wrapper as
30 * /usr/bin/alias will call the ksh "alias" builtin, running it as
31 * /usr/bin/cut will call the ksh "cut" builtin etc.
41 int (* func
)(int, char **, void *);
45 * We've disabled the "fastpath" codepath for some commands below
46 * because it causes a paradoxon for large input files (as used by
47 * ON PerfPIT for testing). For /usr/bin/rev (where the issue was
48 * first discovered) it looks like this:
49 * - for small files like /etc/profile the fastpath is faster in a loop
50 * with 1000 iterations (8 seconds with fastpath, 14 seconds without
52 * - for large files (/usr/pub/UTF-8 replicated until the test file
53 * reaches 24884706 bytes) the benchmark reverses: The fastpath now
54 * needs 40 seconds and without fastpath it needs 30 seconds (for 100
58 #define ENABLE_PERFORMANCE_PARADOXON 1
62 * List of libcmd builtins which do not require a |Shell_t| context.
63 * This list was automatically generated from <ast/cmdext.h>
66 bfastpathrec fastpath_builtins
[] =
68 /* This list must be alphabetically sorted for |strcmp()| usage */
69 { "basename", b_basename
},
74 #ifdef ENABLE_PERFORMANCE_PARADOXON
76 #endif /* ENABLE_PERFORMANCE_PARADOXON */
82 { "dirname", b_dirname
},
89 { "getconf", b_getconf
},
95 { "logname", b_logname
},
96 { "md5sum", b_md5sum
},
98 { "mkfifo", b_mkfifo
},
99 { "mktemp", b_mktemp
},
101 { "paste", b_paste
},
102 { "pathchk", b_pathchk
},
104 { "readlink", b_readlink
},
105 #ifdef ENABLE_PERFORMANCE_PARADOXON
107 #endif /* ENABLE_PERFORMANCE_PARADOXON */
109 { "rmdir", b_rmdir
},
111 #ifdef ENABLE_PERFORMANCE_PARADOXON
113 #endif /* ENABLE_PERFORMANCE_PARADOXON */
118 { "uname", b_uname
},
121 { "xgrep", b_xgrep
},
122 { NULL
, (int (*)(int, char **, void *))NULL
}
127 find_bfastpathrec(const char *name
)
131 for (i
= 0; fastpath_builtins
[i
].name
!= NULL
; i
++) {
132 cmpres
= strcmp(fastpath_builtins
[i
].name
, name
);
134 return (&fastpath_builtins
[i
]);
144 fastpath_builtin_main(const bfastpathrec
*brec
, int argc
, char *argv
[])
146 setlocale(LC_ALL
, ""); /* calls |_ast_setlocale()| */
148 return ((*brec
->func
)(argc
, argv
, NULL
));
152 /* Builtin script, original derived from alias.sh */
153 static const char *script
= "\n"
154 /* Get name of builtin */
155 "typeset cmd=\"${0##*/}\"\n"
157 * If the requested command is not an alias load it explicitly
158 * to make sure it is not bound to a path (those built-ins which
159 * are mapped via shell aliases point to commands which are
160 * "special shell built-ins" which cannot be bound to a specific
161 * PATH element) - otherwise we may execute the wrong command
162 * if an executable with the same name sits in a PATH element
163 * before /usr/bin (e.g. /usr/xpg4/bin/ls would be executed
164 * before /usr/bin/ls if the path was something like
165 * PATH=/usr/xpg4/bin:/usr/bin).
167 "if [[ \"${cmd}\" != ~(Elr)(alias|unalias|command) ]] && "
168 "! alias \"${cmd}\" >/dev/null 2>&1 ; then\n"
169 "PATH='' builtin \"${cmd}\"\n"
171 /* command is a keyword and needs to be handled separately */
172 "if [[ \"${cmd}\" == \"command\" ]] ; then\n"
175 #ifdef WORKAROUND_FOR_ALIAS_CRASH
177 * Work around a crash in /usr/bin/alias when invalid options are
178 * passed (e.g. $ /usr/bin/alias -c #). The shell code will call
179 * an error handler which does a |longjmp()| but somehow the code
180 * failed to do the |setjmp()| before this point.
181 * Putting the "alias" command in a subshell avoids the crash.
182 * Real cause of the issue is under investigation and a fix be
183 * delivered with the next ast-ksh update.
185 "( \"${cmd}\" \"$@\" )\n"
187 "\"${cmd}\" \"$@\"\n"
188 #endif /* WORKAROUND_FOR_ALIAS_CRASH */
195 script_builtin_main(int argc
, char *argv
[])
203 * Create copy of |argv| array shifted by one position to
204 * emulate $ /usr/bin/sh <scriptname> <args1> <arg2> ... #.
205 * First position is set to "/usr/bin/sh" since other
206 * values may trigger special shell modes (e.g. *rsh* will
207 * trigger "restricted" shell mode etc.).
210 xargv
[0] = "/usr/bin/sh";
211 xargv
[1] = "scriptname";
212 for (i
= 0; i
< argc
; i
++) {
213 xargv
[i
+1] = argv
[i
];
217 shp
= sh_init(argc
+1, xargv
, 0);
219 error(ERROR_exit(1), "shell initialisation failed.");
220 (void) sh_trap(script
, 0);
222 np
= nv_open("exitval", shp
->var_tree
, 0);
224 error(ERROR_exit(1), "variable %s not found.", "exitval");
225 exitval
= (int)nv_getnum(np
);
232 main(int argc
, char *argv
[])
234 const char *progname
;
235 const bfastpathrec
*brec
;
236 char execnamebuff
[PATH_MAX
+1];
238 /* Get program name */
239 if (pathprog(argv
[0], execnamebuff
, sizeof (execnamebuff
)) <= 0)
240 error(ERROR_exit(1), "could not determinate exec name.");
242 progname
= (const char *)strrchr(execnamebuff
, '/');
243 if (progname
!= NULL
) {
248 progname
= execnamebuff
;
251 /* Execute command... */
252 if (brec
= find_bfastpathrec(progname
)) {
253 /* ... either via a fast path (calling the code directly) ... */
254 return (fastpath_builtin_main(brec
, argc
, argv
));
258 /* ... or from within a full shell. */
259 return (script_builtin_main(argc
, argv
));