var.c revision 207678
120253Sjoerg/*- 220302Sjoerg * Copyright (c) 1991, 1993 320302Sjoerg * The Regents of the University of California. All rights reserved. 420253Sjoerg * 520253Sjoerg * This code is derived from software contributed to Berkeley by 620253Sjoerg * Kenneth Almquist. 720253Sjoerg * 820253Sjoerg * Redistribution and use in source and binary forms, with or without 920302Sjoerg * modification, are permitted provided that the following conditions 1020253Sjoerg * are met: 1120253Sjoerg * 1. Redistributions of source code must retain the above copyright 1220253Sjoerg * notice, this list of conditions and the following disclaimer. 1320253Sjoerg * 2. Redistributions in binary form must reproduce the above copyright 1420302Sjoerg * notice, this list of conditions and the following disclaimer in the 1520253Sjoerg * documentation and/or other materials provided with the distribution. 1620253Sjoerg * 4. Neither the name of the University nor the names of its contributors 1720302Sjoerg * may be used to endorse or promote products derived from this software 1820253Sjoerg * without specific prior written permission. 1920253Sjoerg * 2020253Sjoerg * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2120253Sjoerg * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2220253Sjoerg * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2320253Sjoerg * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2420253Sjoerg * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2544229Sdavidn * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2620253Sjoerg * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2720253Sjoerg * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2830259Scharnier * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2930259Scharnier * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3050479Speter * SUCH DAMAGE. 3130259Scharnier */ 3230259Scharnier 3330259Scharnier#ifndef lint 3430259Scharnier#if 0 3520253Sjoergstatic char sccsid[] = "@(#)var.c 8.3 (Berkeley) 5/4/95"; 3620253Sjoerg#endif 3720253Sjoerg#endif /* not lint */ 3830259Scharnier#include <sys/cdefs.h> 3920253Sjoerg__FBSDID("$FreeBSD: head/bin/sh/var.c 207678 2010-05-05 21:48:40Z jilles $"); 4020555Sdavidn 4120555Sdavidn#include <unistd.h> 4220555Sdavidn#include <stdlib.h> 4330259Scharnier#include <paths.h> 4422394Sdavidn 4522394Sdavidn/* 4620555Sdavidn * Shell variables. 4722394Sdavidn */ 4820253Sjoerg 4920253Sjoerg#include <locale.h> 5020253Sjoerg 5123318Sache#include "shell.h" 5222394Sdavidn#include "output.h" 5322394Sdavidn#include "expand.h" 5423318Sache#include "nodes.h" /* for other headers */ 5522394Sdavidn#include "eval.h" /* defines cmdenviron */ 5622394Sdavidn#include "exec.h" 5749171Sdavidn#include "syntax.h" 5852512Sdavidn#include "options.h" 5924214Sache#include "mail.h" 6044386Sdavidn#include "var.h" 6120253Sjoerg#include "memalloc.h" 6220253Sjoerg#include "error.h" 6320253Sjoerg#include "mystring.h" 6420253Sjoerg#include "parser.h" 6520253Sjoerg#ifndef NO_HISTORY 6620253Sjoerg#include "myhistedit.h" 6720253Sjoerg#endif 6820253Sjoerg 6920253Sjoerg 7020747Sdavidn#define VTABSIZE 39 7120253Sjoerg 7220253Sjoerg 7320253Sjoergstruct varinit { 7420253Sjoerg struct var *var; 7520253Sjoerg int flags; 7620253Sjoerg const char *text; 7720253Sjoerg void (*func)(const char *); 7820253Sjoerg}; 7920253Sjoerg 8020253Sjoerg 8120253Sjoerg#ifndef NO_HISTORY 8220253Sjoergstruct var vhistsize; 8320253Sjoerg#endif 8420253Sjoergstruct var vifs; 8520253Sjoergstruct var vmail; 8620253Sjoergstruct var vmpath; 8720253Sjoergstruct var vpath; 8820253Sjoergstruct var vppid; 8920253Sjoergstruct var vps1; 9020253Sjoergstruct var vps2; 9120253Sjoergstruct var vps4; 9220253Sjoergstruct var vvers; 9320253SjoergSTATIC struct var voptind; 9420253Sjoerg 9520253SjoergSTATIC const struct varinit varinit[] = { 9620253Sjoerg#ifndef NO_HISTORY 9720253Sjoerg { &vhistsize, VUNSET, "HISTSIZE=", 9820253Sjoerg sethistsize }, 9920253Sjoerg#endif 10020253Sjoerg { &vifs, 0, "IFS= \t\n", 10120253Sjoerg NULL }, 10220253Sjoerg { &vmail, VUNSET, "MAIL=", 10320253Sjoerg NULL }, 10420253Sjoerg { &vmpath, VUNSET, "MAILPATH=", 10520253Sjoerg NULL }, 10652527Sdavidn { &vpath, 0, "PATH=" _PATH_DEFPATH, 10720253Sjoerg changepath }, 10852512Sdavidn { &vppid, VUNSET, "PPID=", 10920253Sjoerg NULL }, 11020253Sjoerg /* 11120253Sjoerg * vps1 depends on uid 11220253Sjoerg */ 11320253Sjoerg { &vps2, 0, "PS2=> ", 11420253Sjoerg NULL }, 11520747Sdavidn { &vps4, 0, "PS4=+ ", 11620253Sjoerg NULL }, 11720253Sjoerg { &voptind, 0, "OPTIND=1", 11820253Sjoerg getoptsreset }, 11920253Sjoerg { NULL, 0, NULL, 12020253Sjoerg NULL } 12120253Sjoerg}; 12220253Sjoerg 12320253SjoergSTATIC struct var *vartab[VTABSIZE]; 12420253Sjoerg 12520253SjoergSTATIC const char *const locale_names[7] = { 12656000Sdavidn "LC_COLLATE", "LC_CTYPE", "LC_MONETARY", 12720253Sjoerg "LC_NUMERIC", "LC_TIME", "LC_MESSAGES", NULL 12820253Sjoerg}; 12956000SdavidnSTATIC const int locale_categories[7] = { 13056000Sdavidn LC_COLLATE, LC_CTYPE, LC_MONETARY, LC_NUMERIC, LC_TIME, LC_MESSAGES, 0 13156000Sdavidn}; 13220253Sjoerg 13320253SjoergSTATIC struct var **hashvar(const char *); 13452512SdavidnSTATIC int varequal(const char *, const char *); 13520253SjoergSTATIC int localevar(const char *); 13620267Sjoerg 13720267Sjoerg/* 13820267Sjoerg * Initialize the variable symbol tables and import the environment. 13920267Sjoerg */ 14020267Sjoerg 14120267Sjoerg#ifdef mkinit 14220267SjoergINCLUDE "var.h" 14320267SjoergMKINIT char **environ; 14420267SjoergINIT { 14520267Sjoerg char **envp; 14620267Sjoerg 14720267Sjoerg initvar(); 14820267Sjoerg for (envp = environ ; *envp ; envp++) { 14920267Sjoerg if (strchr(*envp, '=')) { 15020253Sjoerg setvareq(*envp, VEXPORT|VTEXTFIXED); 15120253Sjoerg } 15220253Sjoerg } 15320253Sjoerg} 15420267Sjoerg#endif 15520253Sjoerg 15621052Sdavidn 15721052Sdavidn/* 15821052Sdavidn * This routine initializes the builtin variables. It is called when the 15921052Sdavidn * shell is initialized and again when a shell procedure is spawned. 16021052Sdavidn */ 16121052Sdavidn 16221052Sdavidnvoid 16321052Sdavidninitvar(void) 16421052Sdavidn{ 16521052Sdavidn char ppid[20]; 16621052Sdavidn const struct varinit *ip; 16721052Sdavidn struct var *vp; 16830259Scharnier struct var **vpp; 16921052Sdavidn 17021052Sdavidn for (ip = varinit ; (vp = ip->var) != NULL ; ip++) { 17121052Sdavidn if ((vp->flags & VEXPORT) == 0) { 17221052Sdavidn vpp = hashvar(ip->text); 17321242Sdavidn vp->next = *vpp; 17421242Sdavidn *vpp = vp; 17521242Sdavidn vp->text = __DECONST(char *, ip->text); 17621242Sdavidn vp->flags = ip->flags | VSTRFIXED | VTEXTFIXED; 17721242Sdavidn vp->func = ip->func; 17821242Sdavidn } 17921242Sdavidn } 18021242Sdavidn /* 18121242Sdavidn * PS1 depends on uid 18221242Sdavidn */ 18321242Sdavidn if ((vps1.flags & VEXPORT) == 0) { 18421242Sdavidn vpp = hashvar("PS1="); 18521242Sdavidn vps1.next = *vpp; 18621242Sdavidn *vpp = &vps1; 18721242Sdavidn vps1.text = __DECONST(char *, geteuid() ? "PS1=$ " : "PS1=# "); 18821052Sdavidn vps1.flags = VSTRFIXED|VTEXTFIXED; 18921052Sdavidn } 19021242Sdavidn if ((vppid.flags & VEXPORT) == 0) { 19121242Sdavidn fmtstr(ppid, sizeof(ppid), "%d", (int)getppid()); 19221242Sdavidn setvarsafe("PPID", ppid, 0); 19321242Sdavidn } 19421242Sdavidn} 19521242Sdavidn 19621242Sdavidn/* 19721242Sdavidn * Safe version of setvar, returns 1 on success 0 on failure. 19830259Scharnier */ 19921242Sdavidn 20021242Sdavidnint 20121052Sdavidnsetvarsafe(const char *name, const char *val, int flags) 20221242Sdavidn{ 20321052Sdavidn struct jmploc jmploc; 20430259Scharnier struct jmploc *const savehandler = handler; 20521052Sdavidn int err = 0; 20621052Sdavidn int inton; 20721052Sdavidn 20821052Sdavidn inton = is_int_on(); 20930259Scharnier if (setjmp(jmploc.loc)) 21021052Sdavidn err = 1; 21121052Sdavidn else { 21220253Sjoerg handler = &jmploc; 21320253Sjoerg setvar(name, val, flags); 21420253Sjoerg } 21521330Sdavidn handler = savehandler; 21621330Sdavidn SETINTON(inton); 21721330Sdavidn return err; 21820253Sjoerg} 21920253Sjoerg 22020253Sjoerg/* 22120253Sjoerg * Set the value of a variable. The flags argument is stored with the 22220253Sjoerg * flags of the variable. If val is NULL, the variable is unset. 22344229Sdavidn */ 22444229Sdavidn 22530259Scharniervoid 22620253Sjoergsetvar(const char *name, const char *val, int flags) 22720253Sjoerg{ 22820253Sjoerg const char *p; 22920253Sjoerg int len; 23020679Sdavidn int namelen; 23120253Sjoerg char *nameeq; 23220253Sjoerg int isbad; 23352527Sdavidn 23420253Sjoerg isbad = 0; 23520747Sdavidn p = name; 23644229Sdavidn if (! is_name(*p)) 23744229Sdavidn isbad = 1; 23830259Scharnier p++; 23920253Sjoerg for (;;) { 24020747Sdavidn if (! is_in_name(*p)) { 24120747Sdavidn if (*p == '\0' || *p == '=') 24220253Sjoerg break; 24320747Sdavidn isbad = 1; 24420253Sjoerg } 24520253Sjoerg p++; 24652527Sdavidn } 24720253Sjoerg namelen = p - name; 24826088Sdavidn if (isbad) 24930259Scharnier error("%.*s: bad variable name", namelen, name); 25020253Sjoerg len = namelen + 2; /* 2 is space for '=' and '\0' */ 25152527Sdavidn if (val == NULL) { 25220253Sjoerg flags |= VUNSET; 25320253Sjoerg } else { 25420253Sjoerg len += strlen(val); 25520253Sjoerg } 25620253Sjoerg nameeq = ckmalloc(len); 25730259Scharnier memcpy(nameeq, name, namelen); 25820253Sjoerg nameeq[namelen] = '='; 25920253Sjoerg if (val) 26020253Sjoerg scopy(val, nameeq + namelen + 1); 26120253Sjoerg else 26220253Sjoerg nameeq[namelen + 1] = '\0'; 26320253Sjoerg setvareq(nameeq, flags); 26420253Sjoerg} 26520253Sjoerg 26620253SjoergSTATIC int 26720253Sjoerglocalevar(const char *s) 26820253Sjoerg{ 26920253Sjoerg const char *const *ss; 27020253Sjoerg 27120253Sjoerg if (*s != 'L') 27220253Sjoerg return 0; 27320253Sjoerg if (varequal(s + 1, "ANG")) 27420253Sjoerg return 1; 27520267Sjoerg if (strncmp(s + 1, "C_", 2) != 0) 27630259Scharnier return 0; 27720267Sjoerg if (varequal(s + 3, "ALL")) 27820253Sjoerg return 1; 27952527Sdavidn for (ss = locale_names; *ss ; ss++) 28020253Sjoerg if (varequal(s + 3, *ss + 3)) 28120267Sjoerg return 1; 28244386Sdavidn return 0; 28320253Sjoerg} 28444229Sdavidn 28544229Sdavidn 28644386Sdavidn/* 28744229Sdavidn * Sets/unsets an environment variable from a pointer that may actually be a 28820267Sjoerg * pointer into environ where the string should not be manipulated. 28920253Sjoerg */ 29052527Sdavidnstatic void 29120253Sjoergchange_env(const char *s, int set) 29244229Sdavidn{ 29320253Sjoerg char *eqp; 29420253Sjoerg char *ss; 29520253Sjoerg 29620253Sjoerg ss = savestr(s); 29730259Scharnier if ((eqp = strchr(ss, '=')) != NULL) 29820253Sjoerg *eqp = '\0'; 29920253Sjoerg if (set && eqp != NULL) 30020253Sjoerg (void) setenv(ss, eqp + 1, 1); 30120253Sjoerg else 30220253Sjoerg (void) unsetenv(ss); 30320253Sjoerg ckfree(ss); 30443780Sdes 30543780Sdes return; 30643780Sdes} 30720253Sjoerg 30820253Sjoerg 30920253Sjoerg/* 31020253Sjoerg * Same as setvar except that the variable and value are passed in 31152527Sdavidn * the first argument as name=value. Since the first argument will 31220253Sjoerg * be actually stored in the table, it should not be a string that 31320253Sjoerg * will go away. 31420253Sjoerg */ 31552512Sdavidn 31652512Sdavidnvoid 31752527Sdavidnsetvareq(char *s, int flags) 31820253Sjoerg{ 31944229Sdavidn struct var *vp, **vpp; 32020253Sjoerg int len; 32120253Sjoerg 32220253Sjoerg if (aflag) 32320253Sjoerg flags |= VEXPORT; 32420253Sjoerg vpp = hashvar(s); 32544386Sdavidn for (vp = *vpp ; vp ; vp = vp->next) { 32644386Sdavidn if (varequal(s, vp->text)) { 32744386Sdavidn if (vp->flags & VREADONLY) { 32820253Sjoerg len = strchr(s, '=') - s; 32920253Sjoerg error("%.*s: is read only", len, s); 33030259Scharnier } 33130259Scharnier INTOFF; 33220253Sjoerg 33352527Sdavidn if (vp->func && (flags & VNOFUNC) == 0) 33420253Sjoerg (*vp->func)(strchr(s, '=') + 1); 33520253Sjoerg 33620253Sjoerg if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0) 33720253Sjoerg ckfree(vp->text); 33852512Sdavidn 33952512Sdavidn vp->flags &= ~(VTEXTFIXED|VSTACK|VUNSET); 34052512Sdavidn vp->flags |= flags; 34152512Sdavidn vp->text = s; 34252512Sdavidn 34352512Sdavidn /* 34452512Sdavidn * We could roll this to a function, to handle it as 34552512Sdavidn * a regular variable function callback, but why bother? 34652512Sdavidn * 34752512Sdavidn * Note: this assumes iflag is not set to 1 initially. 34852512Sdavidn * As part of init(), this is called before arguments 34952512Sdavidn * are looked at. 35052512Sdavidn */ 35152512Sdavidn if ((vp == &vmpath || (vp == &vmail && ! mpathset())) && 35252512Sdavidn iflag == 1) 35352512Sdavidn chkmail(1); 35452512Sdavidn if ((vp->flags & VEXPORT) && localevar(s)) { 35552512Sdavidn change_env(s, 1); 35652527Sdavidn (void) setlocale(LC_ALL, ""); 35752512Sdavidn } 35852512Sdavidn INTON; 35952512Sdavidn return; 36052512Sdavidn } 36152527Sdavidn } 36252527Sdavidn /* not found */ 36352527Sdavidn vp = ckmalloc(sizeof (*vp)); 36452527Sdavidn vp->flags = flags; 36552527Sdavidn vp->text = s; 36620253Sjoerg vp->next = *vpp; 36720253Sjoerg vp->func = NULL; 36820253Sjoerg INTOFF; 36920253Sjoerg *vpp = vp; 37020253Sjoerg if ((vp->flags & VEXPORT) && localevar(s)) { 37130259Scharnier change_env(s, 1); 37220253Sjoerg (void) setlocale(LC_ALL, ""); 37344229Sdavidn } 37444229Sdavidn INTON; 37544229Sdavidn} 37644229Sdavidn 37720747Sdavidn 37844229Sdavidn 37920747Sdavidn/* 38044229Sdavidn * Process a linked list of variable assignments. 38144229Sdavidn */ 38244229Sdavidn 38344229Sdavidnvoid 38444229Sdavidnlistsetvar(struct strlist *list) 38544229Sdavidn{ 38644229Sdavidn struct strlist *lp; 38744229Sdavidn 38820253Sjoerg INTOFF; 38920253Sjoerg for (lp = list ; lp ; lp = lp->next) { 39020253Sjoerg setvareq(savestr(lp->text), 0); 39120253Sjoerg } 39220253Sjoerg INTON; 39320253Sjoerg} 39420253Sjoerg 39520253Sjoerg 39620253Sjoerg 39752502Sdavidn/* 39852502Sdavidn * Find the value of a variable. Returns NULL if not set. 39952502Sdavidn */ 40052502Sdavidn 40156000Sdavidnchar * 40252502Sdavidnlookupvar(const char *name) 40352502Sdavidn{ 40421330Sdavidn struct var *v; 40552502Sdavidn 40652502Sdavidn for (v = *hashvar(name) ; v ; v = v->next) { 40752502Sdavidn if (varequal(v->text, name)) { 40852502Sdavidn if (v->flags & VUNSET) 40952502Sdavidn return NULL; 41056000Sdavidn return strchr(v->text, '=') + 1; 41152502Sdavidn } 41252502Sdavidn } 41352502Sdavidn return NULL; 41420253Sjoerg} 41520253Sjoerg 41620253Sjoerg 41720253Sjoerg 41844229Sdavidn/* 41944229Sdavidn * Search the environment of a builtin command. If the second argument 42044229Sdavidn * is nonzero, return the value of a variable even if it hasn't been 42144229Sdavidn * exported. 42244229Sdavidn */ 42320253Sjoerg 42444229Sdavidnchar * 42544229Sdavidnbltinlookup(const char *name, int doall) 42644229Sdavidn{ 42744229Sdavidn struct strlist *sp; 42844229Sdavidn struct var *v; 42920253Sjoerg 43044229Sdavidn for (sp = cmdenviron ; sp ; sp = sp->next) { 43144229Sdavidn if (varequal(sp->text, name)) 43244229Sdavidn return strchr(sp->text, '=') + 1; 43344229Sdavidn } 43444229Sdavidn for (v = *hashvar(name) ; v ; v = v->next) { 43544229Sdavidn if (varequal(v->text, name)) { 43644229Sdavidn if ((v->flags & VUNSET) 43744229Sdavidn || (!doall && (v->flags & VEXPORT) == 0)) 43844229Sdavidn return NULL; 43944229Sdavidn return strchr(v->text, '=') + 1; 44020253Sjoerg } 44120253Sjoerg } 44220267Sjoerg return NULL; 44320253Sjoerg} 44444386Sdavidn 44544386Sdavidn 44644386Sdavidn/* 44720253Sjoerg * Set up locale for a builtin (LANG/LC_* assignments). 44820253Sjoerg */ 44920253Sjoergvoid 45020253Sjoergbltinsetlocale(void) 45120253Sjoerg{ 45220253Sjoerg struct strlist *lp; 45330259Scharnier int act = 0; 45420679Sdavidn char *loc, *locdef; 45552527Sdavidn int i; 45620253Sjoerg 45752527Sdavidn for (lp = cmdenviron ; lp ; lp = lp->next) { 45820253Sjoerg if (localevar(lp->text)) { 45920253Sjoerg act = 1; 46052527Sdavidn break; 46120253Sjoerg } 46230259Scharnier } 46320253Sjoerg if (!act) 46430259Scharnier return; 46520253Sjoerg loc = bltinlookup("LC_ALL", 0); 46620253Sjoerg INTOFF; 46752527Sdavidn if (loc != NULL) { 46852527Sdavidn setlocale(LC_ALL, loc); 46952527Sdavidn INTON; 47052527Sdavidn return; 47161762Sdavidn } 47252527Sdavidn locdef = bltinlookup("LANG", 0); 47352527Sdavidn for (i = 0; locale_names[i] != NULL; i++) { 47452527Sdavidn loc = bltinlookup(locale_names[i], 0); 47520253Sjoerg if (loc == NULL) 47652527Sdavidn loc = locdef; 47752527Sdavidn if (loc != NULL) 47852527Sdavidn setlocale(locale_categories[i], loc); 47952527Sdavidn } 48052527Sdavidn INTON; 48152527Sdavidn} 48220253Sjoerg 48320253Sjoerg/* 48420253Sjoerg * Undo the effect of bltinlocaleset(). 48520253Sjoerg */ 48620253Sjoergvoid 48730259Scharnierbltinunsetlocale(void) 48852527Sdavidn{ 48952527Sdavidn struct strlist *lp; 49052527Sdavidn 49152527Sdavidn INTOFF; 49220253Sjoerg for (lp = cmdenviron ; lp ; lp = lp->next) { 49320253Sjoerg if (localevar(lp->text)) { 49452527Sdavidn setlocale(LC_ALL, ""); 49520267Sjoerg return; 49652527Sdavidn } 49752527Sdavidn } 49852527Sdavidn INTON; 49952527Sdavidn} 50052527Sdavidn 50152527Sdavidn 50220253Sjoerg/* 50320253Sjoerg * Generate a list of exported variables. This routine is used to construct 50420253Sjoerg * the third argument to execve when executing a program. 50520253Sjoerg */ 50620253Sjoerg 50730259Scharnierchar ** 50852527Sdavidnenvironment(void) 50952527Sdavidn{ 51052527Sdavidn int nenv; 51152527Sdavidn struct var **vpp; 51220253Sjoerg struct var *vp; 51320253Sjoerg char **env, **ep; 51420253Sjoerg 51552527Sdavidn nenv = 0; 51652527Sdavidn for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) { 51752527Sdavidn for (vp = *vpp ; vp ; vp = vp->next) 51852527Sdavidn if (vp->flags & VEXPORT) 51952527Sdavidn nenv++; 52052527Sdavidn } 52152527Sdavidn ep = env = stalloc((nenv + 1) * sizeof *env); 52252527Sdavidn for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) { 52352527Sdavidn for (vp = *vpp ; vp ; vp = vp->next) 52420253Sjoerg if (vp->flags & VEXPORT) 52552527Sdavidn *ep++ = vp->text; 52652527Sdavidn } 52752527Sdavidn *ep = NULL; 52852527Sdavidn return env; 52952527Sdavidn} 53052527Sdavidn 53152527Sdavidn 53252527Sdavidn/* 53352527Sdavidn * Called when a shell procedure is invoked to clear out nonexported 53420747Sdavidn * variables. It is also necessary to reallocate variables of with 53520747Sdavidn * VSTACK set since these are currently allocated on the stack. 53620747Sdavidn */ 53730259Scharnier 53820747SdavidnMKINIT void shprocvar(void); 53930259Scharnier 54020747Sdavidn#ifdef mkinit 54120747SdavidnSHELLPROC { 54252527Sdavidn shprocvar(); 54320267Sjoerg} 54452527Sdavidn#endif 54552527Sdavidn 54620267Sjoergvoid 54720253Sjoergshprocvar(void) 54852527Sdavidn{ 54952527Sdavidn struct var **vpp; 55052527Sdavidn struct var *vp, **prev; 55152527Sdavidn 55252527Sdavidn for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) { 55320253Sjoerg for (prev = vpp ; (vp = *prev) != NULL ; ) { 55430259Scharnier if ((vp->flags & VEXPORT) == 0) { 55544229Sdavidn *prev = vp->next; 55630259Scharnier if ((vp->flags & VTEXTFIXED) == 0) 55720253Sjoerg ckfree(vp->text); 55820253Sjoerg if ((vp->flags & VSTRFIXED) == 0) 55920253Sjoerg ckfree(vp); 56020253Sjoerg } else { 56120253Sjoerg if (vp->flags & VSTACK) { 56220253Sjoerg vp->text = savestr(vp->text); 56320253Sjoerg vp->flags &=~ VSTACK; 56420253Sjoerg } 56520253Sjoerg prev = &vp->next; 56620253Sjoerg } 56720253Sjoerg } 56820253Sjoerg } 56920253Sjoerg initvar(); 57020253Sjoerg} 57152527Sdavidn 57220253Sjoerg 57320253Sjoergstatic int 57430259Scharniervar_compare(const void *a, const void *b) 57520253Sjoerg{ 57620253Sjoerg const char *const *sa, *const *sb; 57720253Sjoerg 57820253Sjoerg sa = a; 57920253Sjoerg sb = b; 58052527Sdavidn /* 58152527Sdavidn * This compares two var=value strings which creates a different 58252527Sdavidn * order from what you would probably expect. POSIX is somewhat 58352527Sdavidn * ambiguous on what should be sorted exactly. 58452527Sdavidn */ 58552527Sdavidn return strcoll(*sa, *sb); 58652527Sdavidn} 58720253Sjoerg 58820253Sjoerg 58920253Sjoerg/* 59020253Sjoerg * Command to list all variables which are set. Currently this command 59120253Sjoerg * is invoked from the set command when the set command is called without 59220253Sjoerg * any variables. 59320253Sjoerg */ 59420253Sjoerg 59520253Sjoergint 59620253Sjoergshowvarscmd(int argc __unused, char **argv __unused) 59720253Sjoerg{ 59820253Sjoerg struct var **vpp; 59920253Sjoerg struct var *vp; 60020253Sjoerg const char *s; 60120253Sjoerg const char **vars; 60220253Sjoerg int i, n; 60320253Sjoerg 60420253Sjoerg /* 60520253Sjoerg * POSIX requires us to sort the variables. 60620253Sjoerg */ 60720253Sjoerg n = 0; 60820253Sjoerg for (vpp = vartab; vpp < vartab + VTABSIZE; vpp++) { 60920253Sjoerg for (vp = *vpp; vp; vp = vp->next) { 61020253Sjoerg if (!(vp->flags & VUNSET)) 61120253Sjoerg n++; 61220253Sjoerg } 61320253Sjoerg } 61420253Sjoerg 61520253Sjoerg INTON; 61620253Sjoerg vars = ckmalloc(n * sizeof(*vars)); 61730259Scharnier i = 0; 61820267Sjoerg for (vpp = vartab; vpp < vartab + VTABSIZE; vpp++) { 61920253Sjoerg for (vp = *vpp; vp; vp = vp->next) { 62020253Sjoerg if (!(vp->flags & VUNSET)) 62120253Sjoerg vars[i++] = vp->text; 62220253Sjoerg } 62320253Sjoerg } 62430259Scharnier 62520253Sjoerg qsort(vars, n, sizeof(*vars), var_compare); 62652527Sdavidn for (i = 0; i < n; i++) { 62720253Sjoerg for (s = vars[i]; *s != '='; s++) 62820253Sjoerg out1c(*s); 62920267Sjoerg out1c('='); 63020267Sjoerg out1qstr(s + 1); 63120267Sjoerg out1c('\n'); 63220267Sjoerg } 63320267Sjoerg ckfree(vars); 63444386Sdavidn INTOFF; 63544386Sdavidn 63644386Sdavidn return 0; 63720267Sjoerg} 63821330Sdavidn 63952527Sdavidn 64052502Sdavidn 64152502Sdavidn/* 64252502Sdavidn * The export and readonly commands. 64352502Sdavidn */ 64452502Sdavidn 64556000Sdavidnint 64652502Sdavidnexportcmd(int argc, char **argv) 64752502Sdavidn{ 64852502Sdavidn struct var **vpp; 64952502Sdavidn struct var *vp; 65052502Sdavidn char *name; 65152502Sdavidn char *p; 65252502Sdavidn char *cmdname; 65356000Sdavidn int ch, values; 65452502Sdavidn int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT; 65552502Sdavidn 65652512Sdavidn cmdname = argv[0]; 65752527Sdavidn optreset = optind = 1; 65852527Sdavidn opterr = 0; 65952527Sdavidn values = 0; 66052527Sdavidn while ((ch = getopt(argc, argv, "p")) != -1) { 66152527Sdavidn switch (ch) { 66252527Sdavidn case 'p': 66356000Sdavidn values = 1; 66452527Sdavidn break; 66552527Sdavidn case '?': 66652527Sdavidn default: 66752527Sdavidn error("unknown option: -%c", optopt); 66852527Sdavidn } 66952527Sdavidn } 67052527Sdavidn argc -= optind; 67156000Sdavidn argv += optind; 67252527Sdavidn 67352527Sdavidn if (values && argc != 0) 67452502Sdavidn error("-p requires no arguments"); 67521330Sdavidn if (argc != 0) { 67621330Sdavidn while ((name = *argv++) != NULL) { 67720253Sjoerg if ((p = strchr(name, '=')) != NULL) { 67820253Sjoerg p++; 67920253Sjoerg } else { 68020253Sjoerg vpp = hashvar(name); 68120253Sjoerg for (vp = *vpp ; vp ; vp = vp->next) { 68220253Sjoerg if (varequal(vp->text, name)) { 68320253Sjoerg 68461759Sdavidn vp->flags |= flag; 68561759Sdavidn if ((vp->flags & VEXPORT) && localevar(vp->text)) { 68661759Sdavidn change_env(vp->text, 1); 68761759Sdavidn (void) setlocale(LC_ALL, ""); 68861759Sdavidn } 68961759Sdavidn goto found; 69061759Sdavidn } 69161759Sdavidn } 69261759Sdavidn } 69361759Sdavidn setvar(name, p, flag); 69430259Scharnierfound:; 69520253Sjoerg } 69644229Sdavidn } else { 69720253Sjoerg for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) { 69820253Sjoerg for (vp = *vpp ; vp ; vp = vp->next) { 69920253Sjoerg if (vp->flags & flag) { 70020253Sjoerg if (values) { 70120253Sjoerg out1str(cmdname); 70220253Sjoerg out1c(' '); 70320253Sjoerg } 70420253Sjoerg for (p = vp->text ; *p != '=' ; p++) 70520253Sjoerg out1c(*p); 70620253Sjoerg if (values && !(vp->flags & VUNSET)) { 70720253Sjoerg out1c('='); 70820253Sjoerg out1qstr(p + 1); 70920253Sjoerg } 71044229Sdavidn out1c('\n'); 71144229Sdavidn } 71244229Sdavidn } 71344229Sdavidn } 71444229Sdavidn } 71520253Sjoerg return 0; 71644229Sdavidn} 71744229Sdavidn 71844229Sdavidn 71944229Sdavidn/* 72044229Sdavidn * The "local" command. 72120253Sjoerg */ 72244229Sdavidn 72344229Sdavidnint 72444229Sdavidnlocalcmd(int argc __unused, char **argv __unused) 72544229Sdavidn{ 72644229Sdavidn char *name; 72744229Sdavidn 72844229Sdavidn if (! in_function()) 72944229Sdavidn error("Not in a function"); 73044229Sdavidn while ((name = *argptr++) != NULL) { 73144229Sdavidn mklocal(name); 73244229Sdavidn } 73320253Sjoerg return 0; 73444229Sdavidn} 73520253Sjoerg 73620253Sjoerg 73720253Sjoerg/* 73852527Sdavidn * Make a variable a local variable. When a variable is made local, it's 73920253Sjoerg * value and flags are saved in a localvar structure. The saved values 74020253Sjoerg * will be restored when the shell function returns. We handle the name 74120253Sjoerg * "-" as a special case. 74220253Sjoerg */ 74320253Sjoerg 74444229Sdavidnvoid 74520253Sjoergmklocal(char *name) 74620253Sjoerg{ 74720253Sjoerg struct localvar *lvp; 74820253Sjoerg struct var **vpp; 74952527Sdavidn struct var *vp; 75020267Sjoerg 75120253Sjoerg INTOFF; 75220253Sjoerg lvp = ckmalloc(sizeof (struct localvar)); 75320253Sjoerg if (name[0] == '-' && name[1] == '\0') { 75420253Sjoerg lvp->text = ckmalloc(sizeof optlist); 75520253Sjoerg memcpy(lvp->text, optlist, sizeof optlist); 75620253Sjoerg vp = NULL; 75720253Sjoerg } else { 75820253Sjoerg vpp = hashvar(name); 75920253Sjoerg for (vp = *vpp ; vp && ! varequal(vp->text, name) ; vp = vp->next); 76020253Sjoerg if (vp == NULL) { 76120253Sjoerg if (strchr(name, '=')) 76220253Sjoerg setvareq(savestr(name), VSTRFIXED); 76320253Sjoerg else 76420253Sjoerg setvar(name, NULL, VSTRFIXED); 76520253Sjoerg vp = *vpp; /* the new variable */ 76620253Sjoerg lvp->text = NULL; 76744229Sdavidn lvp->flags = VUNSET; 76830259Scharnier } else { 76920253Sjoerg lvp->text = vp->text; 77020253Sjoerg lvp->flags = vp->flags; 77120253Sjoerg vp->flags |= VSTRFIXED|VTEXTFIXED; 77220253Sjoerg if (strchr(name, '=')) 77320253Sjoerg setvareq(savestr(name), 0); 77420253Sjoerg } 77520253Sjoerg } 77620253Sjoerg lvp->vp = vp; 77720253Sjoerg lvp->next = localvars; 77820253Sjoerg localvars = lvp; 77920253Sjoerg INTON; 78020253Sjoerg} 78120253Sjoerg 78220253Sjoerg 78320253Sjoerg/* 78420253Sjoerg * Called after a function returns. 78520253Sjoerg */ 78620253Sjoerg 78744229Sdavidnvoid 78844229Sdavidnpoplocalvars(void) 78944229Sdavidn{ 79020253Sjoerg struct localvar *lvp; 79144229Sdavidn struct var *vp; 79220253Sjoerg 79320253Sjoerg while ((lvp = localvars) != NULL) { 79420253Sjoerg localvars = lvp->next; 79520253Sjoerg vp = lvp->vp; 79620253Sjoerg if (vp == NULL) { /* $- saved */ 79720253Sjoerg memcpy(optlist, lvp->text, sizeof optlist); 79820253Sjoerg ckfree(lvp->text); 79920253Sjoerg } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) { 80020253Sjoerg (void)unsetvar(vp->text); 80120253Sjoerg } else { 80220253Sjoerg if ((vp->flags & VTEXTFIXED) == 0) 80330259Scharnier ckfree(vp->text); 80420253Sjoerg vp->flags = lvp->flags; 80520253Sjoerg vp->text = lvp->text; 80620253Sjoerg } 80720253Sjoerg ckfree(lvp); 80820253Sjoerg } 80920253Sjoerg} 81020253Sjoerg 81120253Sjoerg 81220253Sjoergint 81320253Sjoergsetvarcmd(int argc, char **argv) 81420253Sjoerg{ 81520253Sjoerg if (argc <= 2) 81620253Sjoerg return unsetcmd(argc, argv); 81720253Sjoerg else if (argc == 3) 81820253Sjoerg setvar(argv[1], argv[2], 0); 81920253Sjoerg else 82020253Sjoerg error("List assignment not implemented"); 82120253Sjoerg return 0; 82220253Sjoerg} 82320253Sjoerg 82420253Sjoerg 82520253Sjoerg/* 82644229Sdavidn * The unset builtin command. We unset the function before we unset the 82720253Sjoerg * variable to allow a function to be unset when there is a readonly variable 82844229Sdavidn * with the same name. 82920253Sjoerg */ 83044229Sdavidn 83130259Scharnierint 83220253Sjoergunsetcmd(int argc __unused, char **argv __unused) 83320253Sjoerg{ 83444229Sdavidn char **ap; 83520267Sjoerg int i; 83620253Sjoerg int flg_func = 0; 83720253Sjoerg int flg_var = 0; 83820253Sjoerg int ret = 0; 83920253Sjoerg 84020253Sjoerg while ((i = nextopt("vf")) != '\0') { 84120253Sjoerg if (i == 'f') 84220253Sjoerg flg_func = 1; 84320253Sjoerg else 84420253Sjoerg flg_var = 1; 84520253Sjoerg } 84620253Sjoerg if (flg_func == 0 && flg_var == 0) 84720253Sjoerg flg_var = 1; 84820253Sjoerg 84920253Sjoerg for (ap = argptr; *ap ; ap++) { 85020253Sjoerg if (flg_func) 85120253Sjoerg ret |= unsetfunc(*ap); 85244229Sdavidn if (flg_var) 85320253Sjoerg ret |= unsetvar(*ap); 85420253Sjoerg } 85520253Sjoerg return ret; 85620267Sjoerg} 85720267Sjoerg 85820267Sjoerg 85920267Sjoerg/* 86020267Sjoerg * Unset the specified variable. 86120267Sjoerg */ 86220267Sjoerg 86320267Sjoergint 86420267Sjoergunsetvar(const char *s) 86544229Sdavidn{ 86620267Sjoerg struct var **vpp; 86720267Sjoerg struct var *vp; 86820253Sjoerg 86920253Sjoerg vpp = hashvar(s); 87020253Sjoerg for (vp = *vpp ; vp ; vpp = &vp->next, vp = *vpp) { 87120253Sjoerg if (varequal(vp->text, s)) { 87220253Sjoerg if (vp->flags & VREADONLY) 87320253Sjoerg return (1); 87420253Sjoerg INTOFF; 87544229Sdavidn if (*(strchr(vp->text, '=') + 1) != '\0') 87620253Sjoerg setvar(s, nullstr, 0); 87720253Sjoerg if ((vp->flags & VEXPORT) && localevar(vp->text)) { 87820253Sjoerg change_env(s, 0); 87920253Sjoerg setlocale(LC_ALL, ""); 88020253Sjoerg } 88120253Sjoerg vp->flags &= ~VEXPORT; 88220253Sjoerg vp->flags |= VUNSET; 88320253Sjoerg if ((vp->flags & VSTRFIXED) == 0) { 88420253Sjoerg if ((vp->flags & VTEXTFIXED) == 0) 88527831Sdavidn ckfree(vp->text); 88620253Sjoerg *vpp = vp->next; 88720253Sjoerg ckfree(vp); 88820253Sjoerg } 88930259Scharnier INTON; 89020253Sjoerg return (0); 89120253Sjoerg } 89220253Sjoerg } 89320253Sjoerg 89420253Sjoerg return (0); 89520253Sjoerg} 89620253Sjoerg 89720253Sjoerg 89820253Sjoerg 89920253Sjoerg/* 90020253Sjoerg * Find the appropriate entry in the hash table from the name. 90120253Sjoerg */ 90220253Sjoerg 90320253SjoergSTATIC struct var ** 90420253Sjoerghashvar(const char *p) 90530259Scharnier{ 90620253Sjoerg unsigned int hashval; 90720253Sjoerg 90820253Sjoerg hashval = ((unsigned char) *p) << 4; 90920253Sjoerg while (*p && *p != '=') 91020253Sjoerg hashval += (unsigned char) *p++; 91120253Sjoerg return &vartab[hashval % VTABSIZE]; 91220253Sjoerg} 91320253Sjoerg 91420253Sjoerg 91520253Sjoerg 91620253Sjoerg/* 91720253Sjoerg * Returns true if the two strings specify the same varable. The first 91820253Sjoerg * variable name is terminated by '='; the second may be terminated by 91920253Sjoerg * either '=' or '\0'. 92020253Sjoerg */ 92120253Sjoerg 92220253SjoergSTATIC int 92330259Scharniervarequal(const char *p, const char *q) 92420253Sjoerg{ 92520253Sjoerg while (*p == *q++) { 92620253Sjoerg if (*p++ == '=') 92720253Sjoerg return 1; 92820253Sjoerg } 92920253Sjoerg if (*p == '=' && *(q - 1) == '\0') 93020253Sjoerg return 1; 93120253Sjoerg return 0; 93220253Sjoerg} 93320253Sjoerg