options.c revision 19240
11556Srgrimes/*- 21556Srgrimes * Copyright (c) 1991, 1993 31556Srgrimes * The Regents of the University of California. All rights reserved. 41556Srgrimes * 51556Srgrimes * This code is derived from software contributed to Berkeley by 61556Srgrimes * Kenneth Almquist. 71556Srgrimes * 81556Srgrimes * Redistribution and use in source and binary forms, with or without 91556Srgrimes * modification, are permitted provided that the following conditions 101556Srgrimes * are met: 111556Srgrimes * 1. Redistributions of source code must retain the above copyright 121556Srgrimes * notice, this list of conditions and the following disclaimer. 131556Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 141556Srgrimes * notice, this list of conditions and the following disclaimer in the 151556Srgrimes * documentation and/or other materials provided with the distribution. 161556Srgrimes * 3. All advertising materials mentioning features or use of this software 171556Srgrimes * must display the following acknowledgement: 181556Srgrimes * This product includes software developed by the University of 191556Srgrimes * California, Berkeley and its contributors. 201556Srgrimes * 4. Neither the name of the University nor the names of its contributors 211556Srgrimes * may be used to endorse or promote products derived from this software 221556Srgrimes * without specific prior written permission. 231556Srgrimes * 241556Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 251556Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 261556Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 271556Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 281556Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 291556Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 301556Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 311556Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 321556Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 331556Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 341556Srgrimes * SUCH DAMAGE. 353044Sdg * 3619240Ssteve * $Id: options.c,v 1.7 1996/09/01 10:21:16 peter Exp $ 371556Srgrimes */ 381556Srgrimes 391556Srgrimes#ifndef lint 4017987Speterstatic char sccsid[] = "@(#)options.c 8.2 (Berkeley) 5/4/95"; 411556Srgrimes#endif /* not lint */ 421556Srgrimes 4317987Speter#include <signal.h> 4417987Speter#include <unistd.h> 4517987Speter#include <stdlib.h> 4617987Speter 471556Srgrimes#include "shell.h" 481556Srgrimes#define DEFINE_OPTIONS 491556Srgrimes#include "options.h" 501556Srgrimes#undef DEFINE_OPTIONS 511556Srgrimes#include "nodes.h" /* for other header files */ 521556Srgrimes#include "eval.h" 531556Srgrimes#include "jobs.h" 541556Srgrimes#include "input.h" 551556Srgrimes#include "output.h" 561556Srgrimes#include "trap.h" 571556Srgrimes#include "var.h" 581556Srgrimes#include "memalloc.h" 591556Srgrimes#include "error.h" 601556Srgrimes#include "mystring.h" 6117987Speter#ifndef NO_HISTORY 6217987Speter#include "myhistedit.h" 6317987Speter#endif 641556Srgrimes 651556Srgrimeschar *arg0; /* value of $0 */ 661556Srgrimesstruct shparam shellparam; /* current positional parameters */ 671556Srgrimeschar **argptr; /* argument list for builtin commands */ 681556Srgrimeschar *optarg; /* set by nextopt (like getopt) */ 691556Srgrimeschar *optptr; /* used by nextopt */ 701556Srgrimes 711556Srgrimeschar *minusc; /* argument to -c option */ 721556Srgrimes 731556Srgrimes 7417987SpeterSTATIC void options __P((int)); 7517987SpeterSTATIC void minus_o __P((char *, int)); 7617987SpeterSTATIC void setoption __P((int, int)); 771556Srgrimes 781556Srgrimes 791556Srgrimes/* 801556Srgrimes * Process the shell command line arguments. 811556Srgrimes */ 821556Srgrimes 831556Srgrimesvoid 841556Srgrimesprocargs(argc, argv) 8517987Speter int argc; 861556Srgrimes char **argv; 8717987Speter{ 881556Srgrimes int i; 891556Srgrimes 901556Srgrimes argptr = argv; 911556Srgrimes if (argc > 0) 921556Srgrimes argptr++; 931556Srgrimes for (i = 0; i < NOPTS; i++) 941556Srgrimes optlist[i].val = 2; 9519240Ssteve privileged = (getuid() != geteuid() || getgid() != getegid()); 961556Srgrimes options(1); 971556Srgrimes if (*argptr == NULL && minusc == NULL) 981556Srgrimes sflag = 1; 991556Srgrimes if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1)) 1001556Srgrimes iflag = 1; 1011556Srgrimes if (mflag == 2) 1021556Srgrimes mflag = iflag; 1031556Srgrimes for (i = 0; i < NOPTS; i++) 1041556Srgrimes if (optlist[i].val == 2) 1051556Srgrimes optlist[i].val = 0; 1061556Srgrimes arg0 = argv[0]; 1071556Srgrimes if (sflag == 0 && minusc == NULL) { 1081556Srgrimes commandname = arg0 = *argptr++; 1091556Srgrimes setinputfile(commandname, 0); 1101556Srgrimes } 11111377Sjoerg if (*argptr && minusc) 11211111Sjoerg /* Posix.2: first arg after -c cmd is $0, remainder $1... */ 11311111Sjoerg arg0 = *argptr++; 1141556Srgrimes shellparam.p = argptr; 1151556Srgrimes /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */ 1161556Srgrimes while (*argptr) { 1171556Srgrimes shellparam.nparam++; 1181556Srgrimes argptr++; 1191556Srgrimes } 1201556Srgrimes optschanged(); 1211556Srgrimes} 1221556Srgrimes 1231556Srgrimes 12417987Spetervoid 12517987Speteroptschanged() 12617987Speter{ 1271556Srgrimes setinteractive(iflag); 12817987Speter#ifndef NO_HISTORY 1291556Srgrimes histedit(); 13017987Speter#endif 1311556Srgrimes setjobctl(mflag); 1321556Srgrimes} 1331556Srgrimes 1341556Srgrimes/* 1351556Srgrimes * Process shell options. The global variable argptr contains a pointer 1361556Srgrimes * to the argument list; we advance it past the options. 1371556Srgrimes */ 1381556Srgrimes 1391556SrgrimesSTATIC void 14017987Speteroptions(cmdline) 14117987Speter int cmdline; 14217987Speter{ 1431556Srgrimes register char *p; 1441556Srgrimes int val; 1451556Srgrimes int c; 1461556Srgrimes 1471556Srgrimes if (cmdline) 1481556Srgrimes minusc = NULL; 1491556Srgrimes while ((p = *argptr) != NULL) { 1501556Srgrimes argptr++; 1511556Srgrimes if ((c = *p++) == '-') { 1521556Srgrimes val = 1; 15317987Speter if (p[0] == '\0' || (p[0] == '-' && p[1] == '\0')) { 1541556Srgrimes if (!cmdline) { 1551556Srgrimes /* "-" means turn off -x and -v */ 1561556Srgrimes if (p[0] == '\0') 1571556Srgrimes xflag = vflag = 0; 1581556Srgrimes /* "--" means reset params */ 1591556Srgrimes else if (*argptr == NULL) 16017987Speter setparam(argptr); 1611556Srgrimes } 1621556Srgrimes break; /* "-" or "--" terminates options */ 1631556Srgrimes } 1641556Srgrimes } else if (c == '+') { 1651556Srgrimes val = 0; 1661556Srgrimes } else { 1671556Srgrimes argptr--; 1681556Srgrimes break; 1691556Srgrimes } 1701556Srgrimes while ((c = *p++) != '\0') { 1711556Srgrimes if (c == 'c' && cmdline) { 1721556Srgrimes char *q; 1731556Srgrimes#ifdef NOHACK /* removing this code allows sh -ce 'foo' for compat */ 1741556Srgrimes if (*p == '\0') 1751556Srgrimes#endif 1761556Srgrimes q = *argptr++; 1771556Srgrimes if (q == NULL || minusc != NULL) 1781556Srgrimes error("Bad -c option"); 1791556Srgrimes minusc = q; 1801556Srgrimes#ifdef NOHACK 1811556Srgrimes break; 1821556Srgrimes#endif 1831556Srgrimes } else if (c == 'o') { 1841556Srgrimes minus_o(*argptr, val); 1851556Srgrimes if (*argptr) 1861556Srgrimes argptr++; 1871556Srgrimes } else { 18819240Ssteve if (c == 'p' && !val && privileged) { 18919240Ssteve (void) setuid(getuid()); 19019240Ssteve (void) setgid(getgid()); 19119240Ssteve } 1921556Srgrimes setoption(c, val); 1931556Srgrimes } 1941556Srgrimes } 1951556Srgrimes } 1961556Srgrimes} 1971556Srgrimes 1981556SrgrimesSTATIC void 1991556Srgrimesminus_o(name, val) 2001556Srgrimes char *name; 2011556Srgrimes int val; 2021556Srgrimes{ 2031556Srgrimes int i; 2041556Srgrimes 2051556Srgrimes if (name == NULL) { 2061556Srgrimes out1str("Current option settings\n"); 2071556Srgrimes for (i = 0; i < NOPTS; i++) 2081556Srgrimes out1fmt("%-16s%s\n", optlist[i].name, 2091556Srgrimes optlist[i].val ? "on" : "off"); 2101556Srgrimes } else { 2111556Srgrimes for (i = 0; i < NOPTS; i++) 2121556Srgrimes if (equal(name, optlist[i].name)) { 21319240Ssteve if (!val && privileged && equal(name, "privileged")) { 21419240Ssteve (void) setuid(getuid()); 21519240Ssteve (void) setgid(getgid()); 21619240Ssteve } 2171556Srgrimes setoption(optlist[i].letter, val); 2181556Srgrimes return; 2191556Srgrimes } 2201556Srgrimes error("Illegal option -o %s", name); 2211556Srgrimes } 2221556Srgrimes} 2231556Srgrimes 2248855Srgrimes 2251556SrgrimesSTATIC void 2261556Srgrimessetoption(flag, val) 2271556Srgrimes char flag; 2281556Srgrimes int val; 2291556Srgrimes { 2301556Srgrimes int i; 2311556Srgrimes 2321556Srgrimes for (i = 0; i < NOPTS; i++) 2331556Srgrimes if (optlist[i].letter == flag) { 2341556Srgrimes optlist[i].val = val; 2351556Srgrimes if (val) { 2361556Srgrimes /* #%$ hack for ksh semantics */ 2371556Srgrimes if (flag == 'V') 2381556Srgrimes Eflag = 0; 2391556Srgrimes else if (flag == 'E') 2401556Srgrimes Vflag = 0; 2411556Srgrimes } 2421556Srgrimes return; 2431556Srgrimes } 2441556Srgrimes error("Illegal option -%c", flag); 2451556Srgrimes} 2461556Srgrimes 2471556Srgrimes 2481556Srgrimes 2491556Srgrimes#ifdef mkinit 2501556SrgrimesINCLUDE "options.h" 2511556Srgrimes 2521556SrgrimesSHELLPROC { 2531556Srgrimes int i; 2541556Srgrimes 2551556Srgrimes for (i = 0; i < NOPTS; i++) 2561556Srgrimes optlist[i].val = 0; 2571556Srgrimes optschanged(); 2581556Srgrimes 2591556Srgrimes} 2601556Srgrimes#endif 2611556Srgrimes 2621556Srgrimes 2631556Srgrimes/* 2641556Srgrimes * Set the shell parameters. 2651556Srgrimes */ 2661556Srgrimes 2671556Srgrimesvoid 2681556Srgrimessetparam(argv) 2691556Srgrimes char **argv; 2701556Srgrimes { 2711556Srgrimes char **newparam; 2721556Srgrimes char **ap; 2731556Srgrimes int nparam; 2741556Srgrimes 2751556Srgrimes for (nparam = 0 ; argv[nparam] ; nparam++); 2761556Srgrimes ap = newparam = ckmalloc((nparam + 1) * sizeof *ap); 2771556Srgrimes while (*argv) { 2781556Srgrimes *ap++ = savestr(*argv++); 2791556Srgrimes } 2801556Srgrimes *ap = NULL; 2811556Srgrimes freeparam(&shellparam); 2821556Srgrimes shellparam.malloc = 1; 2831556Srgrimes shellparam.nparam = nparam; 2841556Srgrimes shellparam.p = newparam; 2851556Srgrimes shellparam.optnext = NULL; 2861556Srgrimes} 2871556Srgrimes 2881556Srgrimes 2891556Srgrimes/* 2901556Srgrimes * Free the list of positional parameters. 2911556Srgrimes */ 2921556Srgrimes 2931556Srgrimesvoid 2941556Srgrimesfreeparam(param) 2951556Srgrimes struct shparam *param; 2961556Srgrimes { 2971556Srgrimes char **ap; 2981556Srgrimes 2991556Srgrimes if (param->malloc) { 3001556Srgrimes for (ap = param->p ; *ap ; ap++) 3011556Srgrimes ckfree(*ap); 3021556Srgrimes ckfree(param->p); 3031556Srgrimes } 3041556Srgrimes} 3051556Srgrimes 3061556Srgrimes 3071556Srgrimes 3081556Srgrimes/* 3091556Srgrimes * The shift builtin command. 3101556Srgrimes */ 3111556Srgrimes 31217987Speterint 31317987Spetershiftcmd(argc, argv) 31417987Speter int argc; 31517987Speter char **argv; 31617987Speter{ 3171556Srgrimes int n; 3181556Srgrimes char **ap1, **ap2; 3191556Srgrimes 3201556Srgrimes n = 1; 3211556Srgrimes if (argc > 1) 3221556Srgrimes n = number(argv[1]); 3231556Srgrimes if (n > shellparam.nparam) 3241556Srgrimes error("can't shift that many"); 3251556Srgrimes INTOFF; 3261556Srgrimes shellparam.nparam -= n; 3271556Srgrimes for (ap1 = shellparam.p ; --n >= 0 ; ap1++) { 3281556Srgrimes if (shellparam.malloc) 3291556Srgrimes ckfree(*ap1); 3301556Srgrimes } 3311556Srgrimes ap2 = shellparam.p; 3321556Srgrimes while ((*ap2++ = *ap1++) != NULL); 3331556Srgrimes shellparam.optnext = NULL; 3341556Srgrimes INTON; 3351556Srgrimes return 0; 3361556Srgrimes} 3371556Srgrimes 3381556Srgrimes 3391556Srgrimes 3401556Srgrimes/* 3411556Srgrimes * The set command builtin. 3421556Srgrimes */ 3431556Srgrimes 34417987Speterint 34517987Spetersetcmd(argc, argv) 34617987Speter int argc; 34717987Speter char **argv; 34817987Speter{ 3491556Srgrimes if (argc == 1) 3501556Srgrimes return showvarscmd(argc, argv); 3511556Srgrimes INTOFF; 3521556Srgrimes options(0); 3531556Srgrimes optschanged(); 3541556Srgrimes if (*argptr != NULL) { 3551556Srgrimes setparam(argptr); 3561556Srgrimes } 3571556Srgrimes INTON; 3581556Srgrimes return 0; 3591556Srgrimes} 3601556Srgrimes 3611556Srgrimes 3621556Srgrimes/* 3631556Srgrimes * The getopts builtin. Shellparam.optnext points to the next argument 3641556Srgrimes * to be processed. Shellparam.optptr points to the next character to 3651556Srgrimes * be processed in the current argument. If shellparam.optnext is NULL, 3661556Srgrimes * then it's the first time getopts has been called. 3671556Srgrimes */ 3681556Srgrimes 36917987Speterint 37017987Spetergetoptscmd(argc, argv) 37117987Speter int argc; 37217987Speter char **argv; 37317987Speter{ 3741556Srgrimes register char *p, *q; 3751556Srgrimes char c; 3761556Srgrimes char s[10]; 3771556Srgrimes 3781556Srgrimes if (argc != 3) 3791556Srgrimes error("Usage: getopts optstring var"); 3801556Srgrimes if (shellparam.optnext == NULL) { 3811556Srgrimes shellparam.optnext = shellparam.p; 3821556Srgrimes shellparam.optptr = NULL; 3831556Srgrimes } 3841556Srgrimes if ((p = shellparam.optptr) == NULL || *p == '\0') { 3851556Srgrimes p = *shellparam.optnext; 3861556Srgrimes if (p == NULL || *p != '-' || *++p == '\0') { 3871556Srgrimesatend: 3881556Srgrimes fmtstr(s, 10, "%d", shellparam.optnext - shellparam.p + 1); 3891556Srgrimes setvar("OPTIND", s, 0); 3901556Srgrimes shellparam.optnext = NULL; 3911556Srgrimes return 1; 3921556Srgrimes } 3931556Srgrimes shellparam.optnext++; 3941556Srgrimes if (p[0] == '-' && p[1] == '\0') /* check for "--" */ 3951556Srgrimes goto atend; 3961556Srgrimes } 3971556Srgrimes c = *p++; 3981556Srgrimes for (q = argv[1] ; *q != c ; ) { 3991556Srgrimes if (*q == '\0') { 4001556Srgrimes out1fmt("Illegal option -%c\n", c); 4011556Srgrimes c = '?'; 4021556Srgrimes goto out; 4031556Srgrimes } 4041556Srgrimes if (*++q == ':') 4051556Srgrimes q++; 4061556Srgrimes } 4071556Srgrimes if (*++q == ':') { 4089974Sjoerg if (*p == '\0' && (p = *shellparam.optnext++) == NULL) { 4091556Srgrimes out1fmt("No arg for -%c option\n", c); 4101556Srgrimes c = '?'; 4111556Srgrimes goto out; 4121556Srgrimes } 4131556Srgrimes setvar("OPTARG", p, 0); 4141556Srgrimes p = NULL; 4151556Srgrimes } 4161556Srgrimesout: 4171556Srgrimes shellparam.optptr = p; 4181556Srgrimes s[0] = c; 4191556Srgrimes s[1] = '\0'; 4201556Srgrimes setvar(argv[2], s, 0); 4211556Srgrimes return 0; 4221556Srgrimes} 4231556Srgrimes 4241556Srgrimes/* 4251556Srgrimes * XXX - should get rid of. have all builtins use getopt(3). the 4261556Srgrimes * library getopt must have the BSD extension static variable "optreset" 4271556Srgrimes * otherwise it can't be used within the shell safely. 4281556Srgrimes * 4291556Srgrimes * Standard option processing (a la getopt) for builtin routines. The 4301556Srgrimes * only argument that is passed to nextopt is the option string; the 4311556Srgrimes * other arguments are unnecessary. It return the character, or '\0' on 4321556Srgrimes * end of input. 4331556Srgrimes */ 4341556Srgrimes 4351556Srgrimesint 4361556Srgrimesnextopt(optstring) 4371556Srgrimes char *optstring; 4381556Srgrimes { 4391556Srgrimes register char *p, *q; 4401556Srgrimes char c; 4411556Srgrimes 4421556Srgrimes if ((p = optptr) == NULL || *p == '\0') { 4431556Srgrimes p = *argptr; 4441556Srgrimes if (p == NULL || *p != '-' || *++p == '\0') 4451556Srgrimes return '\0'; 4461556Srgrimes argptr++; 4471556Srgrimes if (p[0] == '-' && p[1] == '\0') /* check for "--" */ 4481556Srgrimes return '\0'; 4491556Srgrimes } 4501556Srgrimes c = *p++; 4511556Srgrimes for (q = optstring ; *q != c ; ) { 4521556Srgrimes if (*q == '\0') 4531556Srgrimes error("Illegal option -%c", c); 4541556Srgrimes if (*++q == ':') 4551556Srgrimes q++; 4561556Srgrimes } 4571556Srgrimes if (*++q == ':') { 4581556Srgrimes if (*p == '\0' && (p = *argptr++) == NULL) 4591556Srgrimes error("No arg for -%c option", c); 4601556Srgrimes optarg = p; 4611556Srgrimes p = NULL; 4621556Srgrimes } 4631556Srgrimes optptr = p; 4641556Srgrimes return c; 4651556Srgrimes} 466