var.c revision 171268
1139749Simp/*- 237785Smsmith * Copyright (c) 1991, 1993 337785Smsmith * The Regents of the University of California. All rights reserved. 437785Smsmith * 537785Smsmith * This code is derived from software contributed to Berkeley by 637785Smsmith * Kenneth Almquist. 737785Smsmith * 837785Smsmith * Redistribution and use in source and binary forms, with or without 937785Smsmith * modification, are permitted provided that the following conditions 1037785Smsmith * are met: 1137785Smsmith * 1. Redistributions of source code must retain the above copyright 1237785Smsmith * notice, this list of conditions and the following disclaimer. 1337785Smsmith * 2. Redistributions in binary form must reproduce the above copyright 1437785Smsmith * notice, this list of conditions and the following disclaimer in the 1537785Smsmith * documentation and/or other materials provided with the distribution. 1637785Smsmith * 4. Neither the name of the University nor the names of its contributors 1737785Smsmith * may be used to endorse or promote products derived from this software 1837785Smsmith * without specific prior written permission. 1937785Smsmith * 2037785Smsmith * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2137785Smsmith * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2237785Smsmith * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2337785Smsmith * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2437785Smsmith * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2537785Smsmith * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2637785Smsmith * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2737785Smsmith * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2837785Smsmith * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2937785Smsmith * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3050477Speter * SUCH DAMAGE. 3137785Smsmith */ 3237785Smsmith 3358816Simp#ifndef lint 3458816Simp#if 0 3537785Smsmithstatic char sccsid[] = "@(#)var.c 8.3 (Berkeley) 5/4/95"; 3637785Smsmith#endif 3737785Smsmith#endif /* not lint */ 3837785Smsmith#include <sys/cdefs.h> 3937785Smsmith__FBSDID("$FreeBSD: head/bin/sh/var.c 171268 2007-07-06 04:04:58Z scf $"); 4037785Smsmith 4137785Smsmith#include <unistd.h> 4237785Smsmith#include <stdlib.h> 4337785Smsmith#include <paths.h> 4437785Smsmith 4537785Smsmith/* 4637785Smsmith * Shell variables. 4737785Smsmith */ 4837785Smsmith 4937785Smsmith#include <locale.h> 5037785Smsmith 5137785Smsmith#include "shell.h" 5237785Smsmith#include "output.h" 5337785Smsmith#include "expand.h" 5437785Smsmith#include "nodes.h" /* for other headers */ 5537785Smsmith#include "eval.h" /* defines cmdenviron */ 5637785Smsmith#include "exec.h" 5737785Smsmith#include "syntax.h" 5837785Smsmith#include "options.h" 5937785Smsmith#include "mail.h" 6037785Smsmith#include "var.h" 6137785Smsmith#include "memalloc.h" 6237785Smsmith#include "error.h" 6337785Smsmith#include "mystring.h" 6437785Smsmith#include "parser.h" 6537785Smsmith#ifndef NO_HISTORY 6637785Smsmith#include "myhistedit.h" 6737785Smsmith#endif 6837785Smsmith 6937785Smsmith 7037785Smsmith#define VTABSIZE 39 7137785Smsmith 7237785Smsmith 7337785Smsmithstruct varinit { 7437785Smsmith struct var *var; 7537785Smsmith int flags; 7637785Smsmith char *text; 7737785Smsmith void (*func)(const char *); 7837785Smsmith}; 7937785Smsmith 8037785Smsmith 8137785Smsmith#ifndef NO_HISTORY 8237785Smsmithstruct var vhistsize; 8337785Smsmith#endif 8437785Smsmithstruct var vifs; 8537785Smsmithstruct var vmail; 8637785Smsmithstruct var vmpath; 8737785Smsmithstruct var vpath; 8837785Smsmithstruct var vppid; 8937785Smsmithstruct var vps1; 9037785Smsmithstruct var vps2; 9137785Smsmithstruct var vps4; 9237785Smsmithstruct var vvers; 9337785SmsmithSTATIC struct var voptind; 9437785Smsmith 9537785SmsmithSTATIC const struct varinit varinit[] = { 9637785Smsmith#ifndef NO_HISTORY 9737785Smsmith { &vhistsize, VSTRFIXED|VTEXTFIXED|VUNSET, "HISTSIZE=", 9837785Smsmith sethistsize }, 9937785Smsmith#endif 10037785Smsmith { &vifs, VSTRFIXED|VTEXTFIXED, "IFS= \t\n", 10137785Smsmith NULL }, 10237785Smsmith { &vmail, VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL=", 10337785Smsmith NULL }, 10437785Smsmith { &vmpath, VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH=", 10537785Smsmith NULL }, 10637785Smsmith { &vpath, VSTRFIXED|VTEXTFIXED, "PATH=" _PATH_DEFPATH, 10737785Smsmith changepath }, 10837785Smsmith { &vppid, VSTRFIXED|VTEXTFIXED|VUNSET, "PPID=", 10937785Smsmith NULL }, 11037785Smsmith /* 11137785Smsmith * vps1 depends on uid 11237785Smsmith */ 11337785Smsmith { &vps2, VSTRFIXED|VTEXTFIXED, "PS2=> ", 11437785Smsmith NULL }, 11537785Smsmith { &vps4, VSTRFIXED|VTEXTFIXED, "PS4=+ ", 11637785Smsmith NULL }, 11737785Smsmith { &voptind, VSTRFIXED|VTEXTFIXED, "OPTIND=1", 11837785Smsmith getoptsreset }, 11937785Smsmith { NULL, 0, NULL, 12037785Smsmith NULL } 12137785Smsmith}; 12237785Smsmith 12337785SmsmithSTATIC struct var *vartab[VTABSIZE]; 12437785Smsmith 12537785SmsmithSTATIC struct var **hashvar(char *); 12637785SmsmithSTATIC int varequal(char *, char *); 12737785SmsmithSTATIC int localevar(char *); 12837785Smsmith 12937785Smsmith/* 13037785Smsmith * Initialize the variable symbol tables and import the environment. 13137785Smsmith */ 13237785Smsmith 13337785Smsmith#ifdef mkinit 13437785SmsmithINCLUDE "var.h" 13537785SmsmithINIT { 13637785Smsmith char **envp; 13737785Smsmith extern char **environ; 13837785Smsmith 13937785Smsmith initvar(); 14037785Smsmith for (envp = environ ; *envp ; envp++) { 14137785Smsmith if (strchr(*envp, '=')) { 14237785Smsmith setvareq(*envp, VEXPORT|VTEXTFIXED); 14337785Smsmith } 14437785Smsmith } 14537785Smsmith} 14637785Smsmith#endif 14737785Smsmith 14837785Smsmith 14937785Smsmith/* 15037785Smsmith * This routine initializes the builtin variables. It is called when the 15137785Smsmith * shell is initialized and again when a shell procedure is spawned. 15237785Smsmith */ 15337785Smsmith 15437785Smsmithvoid 15537785Smsmithinitvar(void) 15637785Smsmith{ 15737785Smsmith char ppid[20]; 15837785Smsmith const struct varinit *ip; 15937785Smsmith struct var *vp; 16037785Smsmith struct var **vpp; 16137785Smsmith 16237785Smsmith for (ip = varinit ; (vp = ip->var) != NULL ; ip++) { 16337785Smsmith if ((vp->flags & VEXPORT) == 0) { 16437785Smsmith vpp = hashvar(ip->text); 16537785Smsmith vp->next = *vpp; 16637785Smsmith *vpp = vp; 16737785Smsmith vp->text = ip->text; 16837785Smsmith vp->flags = ip->flags; 16937785Smsmith vp->func = ip->func; 17037785Smsmith } 17137785Smsmith } 17237785Smsmith /* 17337785Smsmith * PS1 depends on uid 17437785Smsmith */ 17537785Smsmith if ((vps1.flags & VEXPORT) == 0) { 17637785Smsmith vpp = hashvar("PS1="); 17737785Smsmith vps1.next = *vpp; 17837785Smsmith *vpp = &vps1; 17937785Smsmith vps1.text = geteuid() ? "PS1=$ " : "PS1=# "; 18037785Smsmith vps1.flags = VSTRFIXED|VTEXTFIXED; 18137785Smsmith } 18237785Smsmith if ((vppid.flags & VEXPORT) == 0) { 18337785Smsmith fmtstr(ppid, sizeof(ppid), "%d", (int)getppid()); 18437785Smsmith setvarsafe("PPID", ppid, 0); 18537785Smsmith } 18637785Smsmith} 18737785Smsmith 18837785Smsmith/* 18937785Smsmith * Safe version of setvar, returns 1 on success 0 on failure. 19037785Smsmith */ 19137785Smsmith 19237785Smsmithint 19337785Smsmithsetvarsafe(char *name, char *val, int flags) 19437785Smsmith{ 19537785Smsmith struct jmploc jmploc; 19637785Smsmith struct jmploc *volatile savehandler = handler; 19737785Smsmith int err = 0; 19837785Smsmith#if __GNUC__ 19937785Smsmith /* Avoid longjmp clobbering */ 20037785Smsmith (void) &err; 20137785Smsmith#endif 20237785Smsmith 20337785Smsmith if (setjmp(jmploc.loc)) 20437785Smsmith err = 1; 20537785Smsmith else { 20637785Smsmith handler = &jmploc; 20737785Smsmith setvar(name, val, flags); 20837785Smsmith } 20937785Smsmith handler = savehandler; 21037785Smsmith return err; 21137785Smsmith} 21237785Smsmith 21337785Smsmith/* 21437785Smsmith * Set the value of a variable. The flags argument is stored with the 21537785Smsmith * flags of the variable. If val is NULL, the variable is unset. 21637785Smsmith */ 21737785Smsmith 21837785Smsmithvoid 21937785Smsmithsetvar(char *name, char *val, int flags) 22037785Smsmith{ 22137785Smsmith char *p, *q; 22237785Smsmith int len; 22337785Smsmith int namelen; 22437785Smsmith char *nameeq; 22537785Smsmith int isbad; 22637785Smsmith 22737785Smsmith isbad = 0; 22837785Smsmith p = name; 22937785Smsmith if (! is_name(*p)) 23037785Smsmith isbad = 1; 23137785Smsmith p++; 23237785Smsmith for (;;) { 23337785Smsmith if (! is_in_name(*p)) { 23437785Smsmith if (*p == '\0' || *p == '=') 23537785Smsmith break; 23637785Smsmith isbad = 1; 23737785Smsmith } 23837785Smsmith p++; 23937785Smsmith } 24037785Smsmith namelen = p - name; 24137785Smsmith if (isbad) 24237785Smsmith error("%.*s: bad variable name", namelen, name); 24337785Smsmith len = namelen + 2; /* 2 is space for '=' and '\0' */ 24437785Smsmith if (val == NULL) { 24537785Smsmith flags |= VUNSET; 24637785Smsmith } else { 24737785Smsmith len += strlen(val); 24837785Smsmith } 24937785Smsmith p = nameeq = ckmalloc(len); 25037785Smsmith q = name; 25137785Smsmith while (--namelen >= 0) 25237785Smsmith *p++ = *q++; 25337785Smsmith *p++ = '='; 25437785Smsmith *p = '\0'; 25537785Smsmith if (val) 25637785Smsmith scopy(val, p); 25737785Smsmith setvareq(nameeq, flags); 25837785Smsmith} 25937785Smsmith 26037785SmsmithSTATIC int 26137785Smsmithlocalevar(char *s) 26237785Smsmith{ 26337785Smsmith static char *lnames[7] = { 26437785Smsmith "ALL", "COLLATE", "CTYPE", "MONETARY", 26537785Smsmith "NUMERIC", "TIME", NULL 26637785Smsmith }; 26737785Smsmith char **ss; 26837785Smsmith 26937785Smsmith if (*s != 'L') 27037785Smsmith return 0; 27137785Smsmith if (varequal(s + 1, "ANG")) 27237785Smsmith return 1; 27337785Smsmith if (strncmp(s + 1, "C_", 2) != 0) 27437785Smsmith return 0; 27537785Smsmith for (ss = lnames; *ss ; ss++) 27637785Smsmith if (varequal(s + 3, *ss)) 27737785Smsmith return 1; 27837785Smsmith return 0; 27937785Smsmith} 28037785Smsmith 28137785Smsmith 28237785Smsmith/* 28337785Smsmith * Sets/unsets an environment variable from a pointer that may actually be a 28437785Smsmith * pointer into environ where the string should not be manipulated. 28537785Smsmith */ 28637785Smsmithstatic void 28737785Smsmithchange_env(char *s, int set) 28837785Smsmith{ 28937785Smsmith char *eqp; 29037785Smsmith char *ss; 29137785Smsmith 29237785Smsmith ss = savestr(s); 29337785Smsmith if ((eqp = strchr(ss, '=')) != NULL) 29437785Smsmith *eqp = '\0'; 29537785Smsmith if (set && eqp != NULL) 29637785Smsmith (void) setenv(ss, eqp + 1, 1); 29737785Smsmith else 29837785Smsmith (void) unsetenv(ss); 29937785Smsmith ckfree(ss); 30037785Smsmith 30137785Smsmith return; 30237785Smsmith} 30337785Smsmith 30437785Smsmith 30537785Smsmith/* 30637785Smsmith * Same as setvar except that the variable and value are passed in 30737785Smsmith * the first argument as name=value. Since the first argument will 30837785Smsmith * be actually stored in the table, it should not be a string that 30937785Smsmith * will go away. 31037785Smsmith */ 31137785Smsmith 31237785Smsmithvoid 31337785Smsmithsetvareq(char *s, int flags) 31437785Smsmith{ 31537785Smsmith struct var *vp, **vpp; 31637785Smsmith int len; 31737785Smsmith 31837785Smsmith if (aflag) 31937785Smsmith flags |= VEXPORT; 32037785Smsmith vpp = hashvar(s); 32137785Smsmith for (vp = *vpp ; vp ; vp = vp->next) { 32237785Smsmith if (varequal(s, vp->text)) { 32337785Smsmith if (vp->flags & VREADONLY) { 32437785Smsmith len = strchr(s, '=') - s; 32537785Smsmith error("%.*s: is read only", len, s); 32637785Smsmith } 32737785Smsmith INTOFF; 32837785Smsmith 32937785Smsmith if (vp->func && (flags & VNOFUNC) == 0) 33037785Smsmith (*vp->func)(strchr(s, '=') + 1); 33137785Smsmith 33237785Smsmith if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0) 33337785Smsmith ckfree(vp->text); 33437785Smsmith 33537785Smsmith vp->flags &= ~(VTEXTFIXED|VSTACK|VUNSET); 33637785Smsmith vp->flags |= flags; 33737785Smsmith vp->text = s; 33837785Smsmith 33937785Smsmith /* 34037785Smsmith * We could roll this to a function, to handle it as 34137785Smsmith * a regular variable function callback, but why bother? 34237785Smsmith */ 34337785Smsmith if (vp == &vmpath || (vp == &vmail && ! mpathset())) 34437785Smsmith chkmail(1); 34537785Smsmith if ((vp->flags & VEXPORT) && localevar(s)) { 34637785Smsmith change_env(s, 1); 34737785Smsmith (void) setlocale(LC_ALL, ""); 34837785Smsmith } 34937785Smsmith INTON; 35037785Smsmith return; 35137785Smsmith } 35237785Smsmith } 35337785Smsmith /* not found */ 35437785Smsmith vp = ckmalloc(sizeof (*vp)); 35537785Smsmith vp->flags = flags; 35637785Smsmith vp->text = s; 35737785Smsmith vp->next = *vpp; 35837785Smsmith vp->func = NULL; 35937785Smsmith INTOFF; 36037785Smsmith *vpp = vp; 36137785Smsmith if ((vp->flags & VEXPORT) && localevar(s)) { 36237785Smsmith change_env(s, 1); 36337785Smsmith (void) setlocale(LC_ALL, ""); 36437785Smsmith } 36537785Smsmith INTON; 36637785Smsmith} 36737785Smsmith 36837785Smsmith 36937785Smsmith 37037785Smsmith/* 37137785Smsmith * Process a linked list of variable assignments. 37237785Smsmith */ 37337785Smsmith 37437785Smsmithvoid 37537785Smsmithlistsetvar(struct strlist *list) 37637785Smsmith{ 37737785Smsmith struct strlist *lp; 37837785Smsmith 37937785Smsmith INTOFF; 38037785Smsmith for (lp = list ; lp ; lp = lp->next) { 38137785Smsmith setvareq(savestr(lp->text), 0); 38237785Smsmith } 38337785Smsmith INTON; 38437785Smsmith} 38537785Smsmith 38637785Smsmith 38737785Smsmith 38837785Smsmith/* 38937785Smsmith * Find the value of a variable. Returns NULL if not set. 39037785Smsmith */ 39137785Smsmith 39237785Smsmithchar * 39337785Smsmithlookupvar(char *name) 39437785Smsmith{ 39537785Smsmith struct var *v; 39637785Smsmith 39737785Smsmith for (v = *hashvar(name) ; v ; v = v->next) { 39837785Smsmith if (varequal(v->text, name)) { 39937785Smsmith if (v->flags & VUNSET) 40037785Smsmith return NULL; 40137785Smsmith return strchr(v->text, '=') + 1; 40237785Smsmith } 40337785Smsmith } 40437785Smsmith return NULL; 40537785Smsmith} 40637785Smsmith 40737785Smsmith 40837785Smsmith 40937785Smsmith/* 41037785Smsmith * Search the environment of a builtin command. If the second argument 41137785Smsmith * is nonzero, return the value of a variable even if it hasn't been 41237785Smsmith * exported. 41337785Smsmith */ 41437785Smsmith 41537785Smsmithchar * 41637785Smsmithbltinlookup(char *name, int doall) 41737785Smsmith{ 41837785Smsmith struct strlist *sp; 41937785Smsmith struct var *v; 42037785Smsmith 42137785Smsmith for (sp = cmdenviron ; sp ; sp = sp->next) { 42237785Smsmith if (varequal(sp->text, name)) 42337785Smsmith return strchr(sp->text, '=') + 1; 42437785Smsmith } 42537785Smsmith for (v = *hashvar(name) ; v ; v = v->next) { 42637785Smsmith if (varequal(v->text, name)) { 42737785Smsmith if ((v->flags & VUNSET) 42837785Smsmith || (!doall && (v->flags & VEXPORT) == 0)) 42937785Smsmith return NULL; 43037785Smsmith return strchr(v->text, '=') + 1; 43137785Smsmith } 43237785Smsmith } 43337785Smsmith return NULL; 43437785Smsmith} 43537785Smsmith 43637785Smsmith 43737785Smsmith 43837785Smsmith/* 43937785Smsmith * Generate a list of exported variables. This routine is used to construct 44037785Smsmith * the third argument to execve when executing a program. 44137785Smsmith */ 44237785Smsmith 44337785Smsmithchar ** 44437785Smsmithenvironment(void) 44537785Smsmith{ 44637785Smsmith int nenv; 44737785Smsmith struct var **vpp; 44837785Smsmith struct var *vp; 44937785Smsmith char **env, **ep; 45037785Smsmith 45137785Smsmith nenv = 0; 45237785Smsmith for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) { 45337785Smsmith for (vp = *vpp ; vp ; vp = vp->next) 45437785Smsmith if (vp->flags & VEXPORT) 45537785Smsmith nenv++; 45637785Smsmith } 45737785Smsmith ep = env = stalloc((nenv + 1) * sizeof *env); 45837785Smsmith for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) { 45937785Smsmith for (vp = *vpp ; vp ; vp = vp->next) 46037785Smsmith if (vp->flags & VEXPORT) 46137785Smsmith *ep++ = vp->text; 46237785Smsmith } 46337785Smsmith *ep = NULL; 46437785Smsmith return env; 46537785Smsmith} 46637785Smsmith 46737785Smsmith 46837785Smsmith/* 46937785Smsmith * Called when a shell procedure is invoked to clear out nonexported 47037785Smsmith * variables. It is also necessary to reallocate variables of with 47137785Smsmith * VSTACK set since these are currently allocated on the stack. 47237785Smsmith */ 47337785Smsmith 47437785Smsmith#ifdef mkinit 47537785SmsmithMKINIT void shprocvar(void); 47637785Smsmith 47737785SmsmithSHELLPROC { 47837785Smsmith shprocvar(); 47937785Smsmith} 48037785Smsmith#endif 48137785Smsmith 48237785Smsmithvoid 48337785Smsmithshprocvar(void) 48437785Smsmith{ 48537785Smsmith struct var **vpp; 48637785Smsmith struct var *vp, **prev; 48737785Smsmith 48837785Smsmith for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) { 48937785Smsmith for (prev = vpp ; (vp = *prev) != NULL ; ) { 49037785Smsmith if ((vp->flags & VEXPORT) == 0) { 49137785Smsmith *prev = vp->next; 49237785Smsmith if ((vp->flags & VTEXTFIXED) == 0) 49337785Smsmith ckfree(vp->text); 49437785Smsmith if ((vp->flags & VSTRFIXED) == 0) 49537785Smsmith ckfree(vp); 49637785Smsmith } else { 49737785Smsmith if (vp->flags & VSTACK) { 49837785Smsmith vp->text = savestr(vp->text); 49937785Smsmith vp->flags &=~ VSTACK; 50037785Smsmith } 50137785Smsmith prev = &vp->next; 50237785Smsmith } 50337785Smsmith } 50437785Smsmith } 50537785Smsmith initvar(); 50637785Smsmith} 50737785Smsmith 50837785Smsmith 50937785Smsmithstatic int 51037785Smsmithvar_compare(const void *a, const void *b) 51137785Smsmith{ 51237785Smsmith const char *const *sa, *const *sb; 51337785Smsmith 51437785Smsmith sa = a; 51537785Smsmith sb = b; 51637785Smsmith /* 51737785Smsmith * This compares two var=value strings which creates a different 51837785Smsmith * order from what you would probably expect. POSIX is somewhat 51937785Smsmith * ambiguous on what should be sorted exactly. 52037785Smsmith */ 52137785Smsmith return strcoll(*sa, *sb); 52237785Smsmith} 52337785Smsmith 52472940Simp 52572940Simp/* 52672940Simp * Command to list all variables which are set. Currently this command 52772940Simp * is invoked from the set command when the set command is called without 52872940Simp * any variables. 52972940Simp */ 53072940Simp 53172940Simpint 53272940Simpshowvarscmd(int argc __unused, char **argv __unused) 533122024Simp{ 53472940Simp struct var **vpp; 53572940Simp struct var *vp; 53672940Simp const char *s; 53772940Simp const char **vars; 53872940Simp int i, n; 53972940Simp 540122024Simp /* 54172940Simp * POSIX requires us to sort the variables. 54272940Simp */ 54372940Simp n = 0; 54472940Simp for (vpp = vartab; vpp < vartab + VTABSIZE; vpp++) { 54572940Simp for (vp = *vpp; vp; vp = vp->next) { 54637785Smsmith if (!(vp->flags & VUNSET)) 54772940Simp n++; 548122024Simp } 54972940Simp } 55072940Simp 55172940Simp INTON; 55237785Smsmith vars = ckmalloc(n * sizeof(*vars)); 553122024Simp i = 0; 554122024Simp for (vpp = vartab; vpp < vartab + VTABSIZE; vpp++) { 55572940Simp for (vp = *vpp; vp; vp = vp->next) { 55672940Simp if (!(vp->flags & VUNSET)) 55772940Simp vars[i++] = vp->text; 55872940Simp } 55972940Simp } 560122024Simp 56172940Simp qsort(vars, n, sizeof(*vars), var_compare); 56272940Simp for (i = 0; i < n; i++) { 56372940Simp for (s = vars[i]; *s != '='; s++) 56472940Simp out1c(*s); 56572940Simp out1c('='); 56672940Simp out1qstr(s + 1); 56772940Simp out1c('\n'); 56872940Simp } 56972940Simp ckfree(vars); 57072940Simp INTOFF; 57172940Simp 57272940Simp return 0; 57337785Smsmith} 57472940Simp 57537785Smsmith 57637785Smsmith 57772940Simp/* 57837785Smsmith * The export and readonly commands. 579 */ 580 581int 582exportcmd(int argc, char **argv) 583{ 584 struct var **vpp; 585 struct var *vp; 586 char *name; 587 char *p; 588 char *cmdname; 589 int ch, values; 590 int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT; 591 592 cmdname = argv[0]; 593 optreset = optind = 1; 594 opterr = 0; 595 values = 0; 596 while ((ch = getopt(argc, argv, "p")) != -1) { 597 switch (ch) { 598 case 'p': 599 values = 1; 600 break; 601 case '?': 602 default: 603 error("unknown option: -%c", optopt); 604 } 605 } 606 argc -= optind; 607 argv += optind; 608 609 if (values && argc != 0) 610 error("-p requires no arguments"); 611 listsetvar(cmdenviron); 612 if (argc != 0) { 613 while ((name = *argv++) != NULL) { 614 if ((p = strchr(name, '=')) != NULL) { 615 p++; 616 } else { 617 vpp = hashvar(name); 618 for (vp = *vpp ; vp ; vp = vp->next) { 619 if (varequal(vp->text, name)) { 620 621 vp->flags |= flag; 622 if ((vp->flags & VEXPORT) && localevar(vp->text)) { 623 change_env(vp->text, 1); 624 (void) setlocale(LC_ALL, ""); 625 } 626 goto found; 627 } 628 } 629 } 630 setvar(name, p, flag); 631found:; 632 } 633 } else { 634 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) { 635 for (vp = *vpp ; vp ; vp = vp->next) { 636 if (vp->flags & flag) { 637 if (values) { 638 out1str(cmdname); 639 out1c(' '); 640 } 641 for (p = vp->text ; *p != '=' ; p++) 642 out1c(*p); 643 if (values && !(vp->flags & VUNSET)) { 644 out1c('='); 645 out1qstr(p + 1); 646 } 647 out1c('\n'); 648 } 649 } 650 } 651 } 652 return 0; 653} 654 655 656/* 657 * The "local" command. 658 */ 659 660int 661localcmd(int argc __unused, char **argv __unused) 662{ 663 char *name; 664 665 if (! in_function()) 666 error("Not in a function"); 667 while ((name = *argptr++) != NULL) { 668 mklocal(name); 669 } 670 return 0; 671} 672 673 674/* 675 * Make a variable a local variable. When a variable is made local, it's 676 * value and flags are saved in a localvar structure. The saved values 677 * will be restored when the shell function returns. We handle the name 678 * "-" as a special case. 679 */ 680 681void 682mklocal(char *name) 683{ 684 struct localvar *lvp; 685 struct var **vpp; 686 struct var *vp; 687 688 INTOFF; 689 lvp = ckmalloc(sizeof (struct localvar)); 690 if (name[0] == '-' && name[1] == '\0') { 691 lvp->text = ckmalloc(sizeof optlist); 692 memcpy(lvp->text, optlist, sizeof optlist); 693 vp = NULL; 694 } else { 695 vpp = hashvar(name); 696 for (vp = *vpp ; vp && ! varequal(vp->text, name) ; vp = vp->next); 697 if (vp == NULL) { 698 if (strchr(name, '=')) 699 setvareq(savestr(name), VSTRFIXED); 700 else 701 setvar(name, NULL, VSTRFIXED); 702 vp = *vpp; /* the new variable */ 703 lvp->text = NULL; 704 lvp->flags = VUNSET; 705 } else { 706 lvp->text = vp->text; 707 lvp->flags = vp->flags; 708 vp->flags |= VSTRFIXED|VTEXTFIXED; 709 if (strchr(name, '=')) 710 setvareq(savestr(name), 0); 711 } 712 } 713 lvp->vp = vp; 714 lvp->next = localvars; 715 localvars = lvp; 716 INTON; 717} 718 719 720/* 721 * Called after a function returns. 722 */ 723 724void 725poplocalvars(void) 726{ 727 struct localvar *lvp; 728 struct var *vp; 729 730 while ((lvp = localvars) != NULL) { 731 localvars = lvp->next; 732 vp = lvp->vp; 733 if (vp == NULL) { /* $- saved */ 734 memcpy(optlist, lvp->text, sizeof optlist); 735 ckfree(lvp->text); 736 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) { 737 (void)unsetvar(vp->text); 738 } else { 739 if ((vp->flags & VTEXTFIXED) == 0) 740 ckfree(vp->text); 741 vp->flags = lvp->flags; 742 vp->text = lvp->text; 743 } 744 ckfree(lvp); 745 } 746} 747 748 749int 750setvarcmd(int argc, char **argv) 751{ 752 if (argc <= 2) 753 return unsetcmd(argc, argv); 754 else if (argc == 3) 755 setvar(argv[1], argv[2], 0); 756 else 757 error("List assignment not implemented"); 758 return 0; 759} 760 761 762/* 763 * The unset builtin command. We unset the function before we unset the 764 * variable to allow a function to be unset when there is a readonly variable 765 * with the same name. 766 */ 767 768int 769unsetcmd(int argc __unused, char **argv __unused) 770{ 771 char **ap; 772 int i; 773 int flg_func = 0; 774 int flg_var = 0; 775 int ret = 0; 776 777 while ((i = nextopt("vf")) != '\0') { 778 if (i == 'f') 779 flg_func = 1; 780 else 781 flg_var = 1; 782 } 783 if (flg_func == 0 && flg_var == 0) 784 flg_var = 1; 785 786 for (ap = argptr; *ap ; ap++) { 787 if (flg_func) 788 ret |= unsetfunc(*ap); 789 if (flg_var) 790 ret |= unsetvar(*ap); 791 } 792 return ret; 793} 794 795 796/* 797 * Unset the specified variable. 798 */ 799 800int 801unsetvar(char *s) 802{ 803 struct var **vpp; 804 struct var *vp; 805 806 vpp = hashvar(s); 807 for (vp = *vpp ; vp ; vpp = &vp->next, vp = *vpp) { 808 if (varequal(vp->text, s)) { 809 if (vp->flags & VREADONLY) 810 return (1); 811 INTOFF; 812 if (*(strchr(vp->text, '=') + 1) != '\0') 813 setvar(s, nullstr, 0); 814 if ((vp->flags & VEXPORT) && localevar(vp->text)) { 815 change_env(s, 0); 816 setlocale(LC_ALL, ""); 817 } 818 vp->flags &= ~VEXPORT; 819 vp->flags |= VUNSET; 820 if ((vp->flags & VSTRFIXED) == 0) { 821 if ((vp->flags & VTEXTFIXED) == 0) 822 ckfree(vp->text); 823 *vpp = vp->next; 824 ckfree(vp); 825 } 826 INTON; 827 return (0); 828 } 829 } 830 831 return (0); 832} 833 834 835 836/* 837 * Find the appropriate entry in the hash table from the name. 838 */ 839 840STATIC struct var ** 841hashvar(char *p) 842{ 843 unsigned int hashval; 844 845 hashval = ((unsigned char) *p) << 4; 846 while (*p && *p != '=') 847 hashval += (unsigned char) *p++; 848 return &vartab[hashval % VTABSIZE]; 849} 850 851 852 853/* 854 * Returns true if the two strings specify the same varable. The first 855 * variable name is terminated by '='; the second may be terminated by 856 * either '=' or '\0'. 857 */ 858 859STATIC int 860varequal(char *p, char *q) 861{ 862 while (*p == *q++) { 863 if (*p++ == '=') 864 return 1; 865 } 866 if (*p == '=' && *(q - 1) == '\0') 867 return 1; 868 return 0; 869} 870