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