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