tech-toolchain archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: make cleaning the environment for children



On Sun, 15 Nov 2009 08:51:26 +0000, David Laight writes:
>Adding ".unexport" and ".unexportall" might be safest.

Agreed.  Here's an updated patch which adds 
.unexport 
.unexport-env
Hopefully make.1 explains clearly.  Here's the rendered version:

     .unexport variable ...
             The opposite of `.export'.  The specified variable will be
             removed from .MAKE.EXPORTED.  If no variable list is provided,
             all globals are unexported, and .MAKE.EXPORTED deleted.

     .unexport-env variable ...
             Clear the environment inherited from the parent, and re-export
             variable.  If no variable is provided, all previously exported
             globals are re-exported.  This operation will cause a memory leak
             of the original environment, so should be used sparingly.  Test-
             ing for .MAKE.LEVEL being 0, would make sense.  Also note that
             any variables which originated in the parent environment should
             be explicitly preserved if desired.  For example:

                   .if ${.MAKE.LEVEL} == 0
                   PATH := ${PATH}
                   .unexport-env PATH
                   .endif

             Would result in an environment containing only `PATH', which is
             the minimal useful environment.  Actually `.MAKE.LEVEL' will also
             be pushed into the new environment.

--sjg

Index: make.1
===================================================================
RCS file: /cvsroot/src/usr.bin/make/make.1,v
retrieving revision 1.163
diff -u -p -r1.163 make.1
--- make.1      2 Oct 2009 07:43:15 -0000       1.163
+++ make.1      16 Nov 2009 04:00:25 -0000
@@ -29,7 +29,7 @@
 .\"
 .\"    from: @(#)make.1        8.4 (Berkeley) 3/19/94
 .\"
-.Dd October 1, 2009
+.Dd November 15, 2009
 .Dt MAKE 1
 .Os
 .Sh NAME
@@ -1282,17 +1282,54 @@ Conditional expressions are also precede
 character of a line.
 The possible conditionals are as follows:
 .Bl -tag -width Ds
-.It Ic .export Ar variable
+.It Ic .export Ar variable ...
 Export the specified global variable.
-If no variable is provided, all globals are exported
+If no variable list is provided, all globals are exported
 except for internal variables (those that start with
 .Ql \&. ) .
 This is not affected by the
 .Fl X
 flag, so should be used with caution.
+.Pp
 Appending a variable name to
 .Va .MAKE.EXPORTED
 is equivalent to exporting a variable.
+.It Ic .unexport Ar variable ...
+The opposite of
+.Ql .export .
+The specified 
+.Va variable 
+will be removed from 
+.Va .MAKE.EXPORTED .
+If no variable list is provided, all globals are unexported,
+and
+.Va .MAKE.EXPORTED 
+deleted.
+.It Ic .unexport-env Ar variable ...
+Clear the environment inherited from the parent, 
+and re-export 
+.Va variable .
+If no variable is provided, all previously exported globals are re-exported.
+This operation will cause a memory leak of the original environment, 
+so should be used sparingly.  Testing for 
+.Va .MAKE.LEVEL
+being 0, would make sense.
+Also note that any variables which originated in the parent environment 
+should be explicitly preserved if desired.
+For example:
+.Bd -literal -offset indent
+.Li .if ${.MAKE.LEVEL} == 0
+PATH := ${PATH}
+.Li .unexport-env PATH
+.Li .endif
+.Pp
+.Ed
+Would result in an environment containing only 
+.Ql Ev PATH ,
+which is the minimal useful environment.
+Actually
+.Ql Ev .MAKE.LEVEL 
+will also be pushed into the new environment.
 .It Ic .undef Ar variable
 Un-define the specified global variable.
 Only global variables may be un-defined.
Index: nonints.h
===================================================================
RCS file: /cvsroot/src/usr.bin/make/nonints.h,v
retrieving revision 1.56
diff -u -p -r1.56 nonints.h
--- nonints.h   28 Jan 2009 21:38:13 -0000      1.56
+++ nonints.h   16 Nov 2009 04:00:25 -0000
@@ -193,3 +193,4 @@ void Var_End(void);
 void Var_Dump(GNode *);
 void Var_ExportVars(void);
 void Var_Export(char *, int);
+void Var_UnExport(char *);
Index: parse.c
===================================================================
RCS file: /cvsroot/src/usr.bin/make/parse.c,v
retrieving revision 1.158
diff -u -p -r1.158 parse.c
--- parse.c     7 Oct 2009 16:40:30 -0000       1.158
+++ parse.c     16 Nov 2009 04:00:26 -0000
@@ -2506,6 +2506,9 @@ Parse_File(const char *name, int fd)
                        continue;
                    Var_Export(cp, 1);
                    continue;
+               } else if (strncmp(cp, "unexport", 8) == 0) {
+                   Var_UnExport(cp);
+                   continue;
                }
            }
 
Index: var.c
===================================================================
RCS file: /cvsroot/src/usr.bin/make/var.c,v
retrieving revision 1.154
diff -u -p -r1.154 var.c
--- var.c       8 Sep 2009 17:29:20 -0000       1.154
+++ var.c       16 Nov 2009 04:00:26 -0000
@@ -527,6 +527,9 @@ Var_Delete(const char *name, GNode *ctxt
        if ((v->flags & VAR_EXPORTED)) {
            unsetenv(v->name);
        }
+       if (strcmp(MAKE_EXPORTED, v->name) == 0) {
+           var_exportedVars = VAR_EXPORTED_NONE;
+       }
        if (v->name != ln->name)
                free(v->name);
        Hash_DeleteEntry(&ctxt->context, ln);
@@ -572,9 +575,15 @@ Var_Export1(const char *name, int parent
     if (v == NULL) {
        return 0;
     }
-    if (!parent &&
-       (v->flags & (VAR_EXPORTED|VAR_REEXPORT)) == VAR_EXPORTED) {
-       return 0;                       /* nothing to do */
+    if (!parent) {
+       switch ((v->flags & (VAR_EXPORTED|VAR_REEXPORT))) {
+       case 0:
+           if (VAR_EXPORTED_ALL != var_exportedVars)
+               return 0;               /* unexported */
+           break;
+       case VAR_EXPORTED:
+           return 0;                   /* nothing to do */
+       }
     }
     val = Buf_GetAll(&v->val, NULL);
     if (strchr(val, '$')) {
@@ -711,6 +720,115 @@ Var_Export(char *str, int isExport)
     free(av);
 }
 
+
+/*
+ * This is called when .unexport[-env] is seen.
+ */
+void
+Var_UnExport(char *str)
+{
+    char tmp[BUFSIZ];
+    char *vlist;
+    char *cp;
+    Boolean reexport;
+    int n;
+
+    if (!str || !str[0]) {
+       return;                         /* assert? */
+    }
+
+    vlist = NULL;
+    reexport = 0;
+
+    str += 8;
+    if (strncmp(str, "-env", 4) == 0) {
+       extern char **environ;
+       static char **savenv;
+       char **newenv;
+
+       cp = getenv(MAKE_LEVEL);        /* we should preserve this */
+       if (environ == savenv) {
+           /* we have been here before! */
+           newenv = bmake_realloc(environ, 2 * sizeof(char *));
+       } else {
+           if (savenv) {
+               free(savenv);
+               savenv = NULL;
+           }
+           newenv = bmake_malloc(2 * sizeof(char *));
+       }
+       if (!newenv)
+           return;
+       environ = savenv = newenv;
+       newenv[0] = NULL;
+       newenv[1] = NULL;
+       setenv(MAKE_LEVEL, cp, 1);
+       reexport = 1;
+       str += 4;
+    }
+    for (; *str != '\n' && isspace((unsigned char) *str); str++)
+       continue;
+    if (str[0] && str[0] != '\n') {
+       vlist = str;
+    }
+
+    if (!vlist) {
+       /* Using .MAKE.EXPORTED */
+       n = snprintf(tmp, sizeof(tmp), "${" MAKE_EXPORTED ":O:u}");
+       if (n < (int)sizeof(tmp)) {
+           vlist = Var_Subst(NULL, tmp, VAR_GLOBAL, 0);
+       }
+    }
+    if (vlist) {
+       Var *v;
+       char **av;
+       char *as;
+       int ac;
+       int i;
+
+       av = brk_string(vlist, &ac, FALSE, &as);
+       for (i = 0; i < ac; i++) {
+           v = VarFind(av[i], VAR_GLOBAL, 0);
+           if (!v)
+               continue;
+           if ((v->flags & (VAR_EXPORTED|VAR_REEXPORT)) == VAR_EXPORTED) {
+               if (reexport) {
+                   /*
+                    * If it had VAR_REEXPORT set, we could skip it.
+                    */
+                   v->flags &= ~(VAR_EXPORTED|VAR_REEXPORT);
+                   Var_Export1(v->name, VAR_EXPORT_PARENT);
+               } else {
+                   unsetenv(v->name);
+               }
+           }
+           if (!reexport) {
+               v->flags &= ~(VAR_EXPORTED|VAR_REEXPORT);
+               if (vlist == str) {
+                   /*
+                    * remove v->name from .MAKE.EXPORTED
+                    */
+                   n = snprintf(tmp, sizeof(tmp),
+                                "${" MAKE_EXPORTED ":N%s}", v->name);
+                   if (n < (int)sizeof(tmp)) {
+                       cp = Var_Subst(NULL, tmp, VAR_GLOBAL, 0);
+                       Var_Set(MAKE_EXPORTED, cp, VAR_GLOBAL, 0);
+                       free(cp);
+                   }
+               }
+           }
+       }
+       free(as);
+       free(av);
+       if (vlist != str) {
+           if (!reexport) {
+               Var_Delete(MAKE_EXPORTED, VAR_GLOBAL);
+           }
+           free(vlist);
+       }
+    }
+}
+
 /*-
  *-----------------------------------------------------------------------
  * Var_Set --
Index: unit-tests/Makefile
===================================================================
RCS file: /cvsroot/src/usr.bin/make/unit-tests/Makefile,v
retrieving revision 1.24
diff -u -p -r1.24 Makefile
--- unit-tests/Makefile 7 Oct 2009 16:40:30 -0000       1.24
+++ unit-tests/Makefile 16 Nov 2009 04:00:26 -0000
@@ -34,6 +34,8 @@ SUBFILES= \
        posix \
        qequals \
        ternary \
+       unexport \
+       unexport2 \
        varcmd
 
 all: ${SUBFILES}
Index: unit-tests/test.exp
===================================================================
RCS file: /cvsroot/src/usr.bin/make/unit-tests/test.exp,v
retrieving revision 1.29
diff -u -p -r1.29 test.exp
--- unit-tests/test.exp 7 Oct 2009 16:40:30 -0000       1.29
+++ unit-tests/test.exp 16 Nov 2009 04:00:26 -0000
@@ -302,6 +302,11 @@ The answer is empty
 The answer is known
 The answer is 42
 The answer is 42
+UT_DOLLAR=This is $UT_FU
+UT_FOO=foobar is fubar
+UT_FU=fubar
+UT_TEST=unexport
+UT_TEST=unexport2
 default FU=<v>fu</v> FOO=<v>foo</v> VAR=<v></v>
 two FU=<v>bar</v> FOO=<v>goo</v> VAR=<v></v>
 three FU=<v>bar</v> FOO=<v>goo</v> VAR=<v></v>
Index: unit-tests/unexport
===================================================================
RCS file: unit-tests/unexport
diff -N unit-tests/unexport
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ unit-tests/unexport 16 Nov 2009 04:00:26 -0000
@@ -0,0 +1,15 @@
+# $Id$
+
+# pick up a bunch of exported vars
+.include "export"
+
+# an example of setting up a minimal environment.
+PATH = /bin:/usr/bin:/sbin:/usr/sbin
+
+.unexport UT_ZOO
+
+UT_TEST = unexport
+
+# trim the environment
+# this will re-export everything in .MAKE.EXPORTED
+.unexport-env
Index: unit-tests/unexport2
===================================================================
RCS file: unit-tests/unexport2
diff -N unit-tests/unexport2
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ unit-tests/unexport2        16 Nov 2009 04:00:26 -0000
@@ -0,0 +1,15 @@
+# $Id$
+
+# pick up a bunch of exported vars
+.include "export"
+
+# an example of setting up a minimal environment.
+PATH = /bin:/usr/bin:/sbin:/usr/sbin
+
+# now clobber the environment to just PATH and UT_TEST
+UT_TEST = unexport2
+
+.unexport
+.export PATH UT_TEST
+# trim the environment
+.unexport-env PATH UT_TEST


Home | Main Index | Thread Index | Old Index