1 /*- 2 * Copyright (c) 1991, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * Kenneth Almquist. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by the University of 19 * California, Berkeley and its contributors. 20 * 4. Neither the name of the University nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 * 36 * $Id: options.c,v 1.7 1996/09/01 10:21:16 peter Exp $ 37 */ 38 39 #ifndef lint 40 static char sccsid[] = "@(#)options.c 8.2 (Berkeley) 5/4/95"; 41 #endif /* not lint */ 42 43 #include <signal.h> 44 #include <unistd.h> 45 #include <stdlib.h> 46 47 #include "shell.h" 48 #define DEFINE_OPTIONS 49 #include "options.h" 50 #undef DEFINE_OPTIONS 51 #include "nodes.h" /* for other header files */ 52 #include "eval.h" 53 #include "jobs.h" 54 #include "input.h" 55 #include "output.h" 56 #include "trap.h" 57 #include "var.h" 58 #include "memalloc.h" 59 #include "error.h" 60 #include "mystring.h" 61 #ifndef NO_HISTORY 62 #include "myhistedit.h" 63 #endif 64 65 char *arg0; /* value of $0 */ 66 struct shparam shellparam; /* current positional parameters */ 67 char **argptr; /* argument list for builtin commands */ 68 char *optarg; /* set by nextopt (like getopt) */ 69 char *optptr; /* used by nextopt */ 70 71 char *minusc; /* argument to -c option */ 72 73 74 STATIC void options __P((int)); 75 STATIC void minus_o __P((char *, int)); 76 STATIC void setoption __P((int, int)); 77 78 79 /* 80 * Process the shell command line arguments. 81 */ 82 83 void 84 procargs(argc, argv) 85 int argc; 86 char **argv; 87 { 88 int i; 89 90 argptr = argv; 91 if (argc > 0) 92 argptr++; 93 for (i = 0; i < NOPTS; i++) 94 optlist[i].val = 2; 95 privileged = (getuid() != geteuid() || getgid() != getegid()); 96 options(1); 97 if (*argptr == NULL && minusc == NULL) 98 sflag = 1; 99 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1)) 100 iflag = 1; 101 if (mflag == 2) 102 mflag = iflag; 103 for (i = 0; i < NOPTS; i++) 104 if (optlist[i].val == 2) 105 optlist[i].val = 0; 106 arg0 = argv[0]; 107 if (sflag == 0 && minusc == NULL) { 108 commandname = arg0 = *argptr++; 109 setinputfile(commandname, 0); 110 } 111 if (*argptr && minusc) 112 /* Posix.2: first arg after -c cmd is $0, remainder $1... */ 113 arg0 = *argptr++; 114 shellparam.p = argptr; 115 /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */ 116 while (*argptr) { 117 shellparam.nparam++; 118 argptr++; 119 } 120 optschanged(); 121 } 122 123 124 void 125 optschanged() 126 { 127 setinteractive(iflag); 128 #ifndef NO_HISTORY 129 histedit(); 130 #endif 131 setjobctl(mflag); 132 } 133 134 /* 135 * Process shell options. The global variable argptr contains a pointer 136 * to the argument list; we advance it past the options. 137 */ 138 139 STATIC void 140 options(cmdline) 141 int cmdline; 142 { 143 register char *p; 144 int val; 145 int c; 146 147 if (cmdline) 148 minusc = NULL; 149 while ((p = *argptr) != NULL) { 150 argptr++; 151 if ((c = *p++) == '-') { 152 val = 1; 153 if (p[0] == '\0' || (p[0] == '-' && p[1] == '\0')) { 154 if (!cmdline) { 155 /* "-" means turn off -x and -v */ 156 if (p[0] == '\0') 157 xflag = vflag = 0; 158 /* "--" means reset params */ 159 else if (*argptr == NULL) 160 setparam(argptr); 161 } 162 break; /* "-" or "--" terminates options */ 163 } 164 } else if (c == '+') { 165 val = 0; 166 } else { 167 argptr--; 168 break; 169 } 170 while ((c = *p++) != '\0') { 171 if (c == 'c' && cmdline) { 172 char *q; 173 #ifdef NOHACK /* removing this code allows sh -ce 'foo' for compat */ 174 if (*p == '\0') 175 #endif 176 q = *argptr++; 177 if (q == NULL || minusc != NULL) 178 error("Bad -c option"); 179 minusc = q; 180 #ifdef NOHACK 181 break; 182 #endif 183 } else if (c == 'o') { 184 minus_o(*argptr, val); 185 if (*argptr) 186 argptr++; 187 } else { 188 if (c == 'p' && !val && privileged) { 189 (void) setuid(getuid()); 190 (void) setgid(getgid()); 191 } 192 setoption(c, val); 193 } 194 } 195 } 196 } 197 198 STATIC void 199 minus_o(name, val) 200 char *name; 201 int val; 202 { 203 int i; 204 205 if (name == NULL) { 206 out1str("Current option settings\n"); 207 for (i = 0; i < NOPTS; i++) 208 out1fmt("%-16s%s\n", optlist[i].name, 209 optlist[i].val ? "on" : "off"); 210 } else { 211 for (i = 0; i < NOPTS; i++) 212 if (equal(name, optlist[i].name)) { 213 if (!val && privileged && equal(name, "privileged")) { 214 (void) setuid(getuid()); 215 (void) setgid(getgid()); 216 } 217 setoption(optlist[i].letter, val); 218 return; 219 } 220 error("Illegal option -o %s", name); 221 } 222 } 223 224 225 STATIC void 226 setoption(flag, val) 227 char flag; 228 int val; 229 { 230 int i; 231 232 for (i = 0; i < NOPTS; i++) 233 if (optlist[i].letter == flag) { 234 optlist[i].val = val; 235 if (val) { 236 /* #%$ hack for ksh semantics */ 237 if (flag == 'V') 238 Eflag = 0; 239 else if (flag == 'E') 240 Vflag = 0; 241 } 242 return; 243 } 244 error("Illegal option -%c", flag); 245 } 246 247 248 249 #ifdef mkinit 250 INCLUDE "options.h" 251 252 SHELLPROC { 253 int i; 254 255 for (i = 0; i < NOPTS; i++) 256 optlist[i].val = 0; 257 optschanged(); 258 259 } 260 #endif 261 262 263 /* 264 * Set the shell parameters. 265 */ 266 267 void 268 setparam(argv) 269 char **argv; 270 { 271 char **newparam; 272 char **ap; 273 int nparam; 274 275 for (nparam = 0 ; argv[nparam] ; nparam++); 276 ap = newparam = ckmalloc((nparam + 1) * sizeof *ap); 277 while (*argv) { 278 *ap++ = savestr(*argv++); 279 } 280 *ap = NULL; 281 freeparam(&shellparam); 282 shellparam.malloc = 1; 283 shellparam.nparam = nparam; 284 shellparam.p = newparam; 285 shellparam.optnext = NULL; 286 } 287 288 289 /* 290 * Free the list of positional parameters. 291 */ 292 293 void 294 freeparam(param) 295 struct shparam *param; 296 { 297 char **ap; 298 299 if (param->malloc) { 300 for (ap = param->p ; *ap ; ap++) 301 ckfree(*ap); 302 ckfree(param->p); 303 } 304 } 305 306 307 308 /* 309 * The shift builtin command. 310 */ 311 312 int 313 shiftcmd(argc, argv) 314 int argc; 315 char **argv; 316 { 317 int n; 318 char **ap1, **ap2; 319 320 n = 1; 321 if (argc > 1) 322 n = number(argv[1]); 323 if (n > shellparam.nparam) 324 error("can't shift that many"); 325 INTOFF; 326 shellparam.nparam -= n; 327 for (ap1 = shellparam.p ; --n >= 0 ; ap1++) { 328 if (shellparam.malloc) 329 ckfree(*ap1); 330 } 331 ap2 = shellparam.p; 332 while ((*ap2++ = *ap1++) != NULL); 333 shellparam.optnext = NULL; 334 INTON; 335 return 0; 336 } 337 338 339 340 /* 341 * The set command builtin. 342 */ 343 344 int 345 setcmd(argc, argv) 346 int argc; 347 char **argv; 348 { 349 if (argc == 1) 350 return showvarscmd(argc, argv); 351 INTOFF; 352 options(0); 353 optschanged(); 354 if (*argptr != NULL) { 355 setparam(argptr); 356 } 357 INTON; 358 return 0; 359 } 360 361 362 /* 363 * The getopts builtin. Shellparam.optnext points to the next argument 364 * to be processed. Shellparam.optptr points to the next character to 365 * be processed in the current argument. If shellparam.optnext is NULL, 366 * then it's the first time getopts has been called. 367 */ 368 369 int 370 getoptscmd(argc, argv) 371 int argc; 372 char **argv; 373 { 374 register char *p, *q; 375 char c; 376 char s[10]; 377 378 if (argc != 3) 379 error("Usage: getopts optstring var"); 380 if (shellparam.optnext == NULL) { 381 shellparam.optnext = shellparam.p; 382 shellparam.optptr = NULL; 383 } 384 if ((p = shellparam.optptr) == NULL || *p == '\0') { 385 p = *shellparam.optnext; 386 if (p == NULL || *p != '-' || *++p == '\0') { 387 atend: 388 fmtstr(s, 10, "%d", shellparam.optnext - shellparam.p + 1); 389 setvar("OPTIND", s, 0); 390 shellparam.optnext = NULL; 391 return 1; 392 } 393 shellparam.optnext++; 394 if (p[0] == '-' && p[1] == '\0') /* check for "--" */ 395 goto atend; 396 } 397 c = *p++; 398 for (q = argv[1] ; *q != c ; ) { 399 if (*q == '\0') { 400 out1fmt("Illegal option -%c\n", c); 401 c = '?'; 402 goto out; 403 } 404 if (*++q == ':') 405 q++; 406 } 407 if (*++q == ':') { 408 if (*p == '\0' && (p = *shellparam.optnext++) == NULL) { 409 out1fmt("No arg for -%c option\n", c); 410 c = '?'; 411 goto out; 412 } 413 setvar("OPTARG", p, 0); 414 p = NULL; 415 } 416 out: 417 shellparam.optptr = p; 418 s[0] = c; 419 s[1] = '\0'; 420 setvar(argv[2], s, 0); 421 return 0; 422 } 423 424 /* 425 * XXX - should get rid of. have all builtins use getopt(3). the 426 * library getopt must have the BSD extension static variable "optreset" 427 * otherwise it can't be used within the shell safely. 428 * 429 * Standard option processing (a la getopt) for builtin routines. The 430 * only argument that is passed to nextopt is the option string; the 431 * other arguments are unnecessary. It return the character, or '\0' on 432 * end of input. 433 */ 434 435 int 436 nextopt(optstring) 437 char *optstring; 438 { 439 register char *p, *q; 440 char c; 441 442 if ((p = optptr) == NULL || *p == '\0') { 443 p = *argptr; 444 if (p == NULL || *p != '-' || *++p == '\0') 445 return '\0'; 446 argptr++; 447 if (p[0] == '-' && p[1] == '\0') /* check for "--" */ 448 return '\0'; 449 } 450 c = *p++; 451 for (q = optstring ; *q != c ; ) { 452 if (*q == '\0') 453 error("Illegal option -%c", c); 454 if (*++q == ':') 455 q++; 456 } 457 if (*++q == ':') { 458 if (*p == '\0' && (p = *argptr++) == NULL) 459 error("No arg for -%c option", c); 460 optarg = p; 461 p = NULL; 462 } 463 optptr = p; 464 return c; 465 } 466