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