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