xref: /freebsd/contrib/tcp_wrappers/environ.c (revision 9f44a47fd07924afc035991af15d84e6585dea4f)
1 /*
2  * Many systems have putenv() but no setenv(). Other systems have setenv()
3  * but no putenv() (MIPS). Still other systems have neither (NeXT). This is a
4  * re-implementation that hopefully ends all problems.
5  *
6  * Author: Wietse Venema, Eindhoven University of Technology, The Netherlands.
7  */
8 
9 #ifndef lint
10 static char sccsid[] = "@(#) environ.c 1.2 94/03/23 16:09:46";
11 #endif
12 
13 /* System libraries. */
14 
15 extern char **environ;
16 extern char *strchr();
17 extern char *strcpy();
18 extern char *strncpy();
19 extern char *malloc();
20 extern char *realloc();
21 extern int strncmp();
22 extern void free();
23 
24 #ifdef no_memcpy
25 #define memcpy(d,s,l) bcopy(s,d,l)
26 #else
27 extern char *memcpy();
28 #endif
29 
30 /* Local stuff. */
31 
32 static int addenv();			/* append entry to environment */
33 
34 static int allocated = 0;		/* environ is, or is not, allocated */
35 
36 #define DO_CLOBBER	1
37 
38 /* namelength - determine length of name in "name=whatever" */
39 
40 static int namelength(char *name)
41 {
42     char   *equal;
43 
44     equal = strchr(name, '=');
45     return ((equal == 0) ? strlen(name) : (equal - name));
46 }
47 
48 /* findenv - given name, locate name=value */
49 
50 static char **findenv(char *name, int len)
51 {
52     char  **envp;
53 
54     for (envp = environ; envp && *envp; envp++)
55 	if (strncmp(name, *envp, len) == 0 && (*envp)[len] == '=')
56 	    return (envp);
57     return (0);
58 }
59 
60 /* getenv - given name, locate value */
61 
62 char   *getenv(char *name)
63 {
64     int     len = namelength(name);
65     char  **envp = findenv(name, len);
66 
67     return (envp ? *envp + len + 1 : 0);
68 }
69 
70 /* putenv - update or append environment (name,value) pair */
71 
72 int     putenv(char *nameval)
73 {
74     char   *equal = strchr(nameval, '=');
75     char   *value = (equal ? equal : "");
76 
77     return (setenv(nameval, value, DO_CLOBBER));
78 }
79 
80 /* unsetenv - remove variable from environment */
81 
82 void    unsetenv(char *name)
83 {
84     char  **envp;
85 
86     if ((envp = findenv(name, namelength(name))) != 0)
87 	while (envp[0] = envp[1])
88 	    envp++;
89 }
90 
91 /* setenv - update or append environment (name,value) pair */
92 
93 int     setenv(char *name, char *value, int clobber)
94 {
95     char   *destination;
96     char  **envp;
97     int     l_name;			/* length of name part */
98     int     l_nameval;			/* length of name=value */
99 
100     /* Permit name= and =value. */
101 
102     l_name = namelength(name);
103     envp = findenv(name, l_name);
104     if (envp != 0 && clobber == 0)
105 	return (0);
106     if (*value == '=')
107 	value++;
108     l_nameval = l_name + strlen(value) + 1;
109 
110     /*
111      * Use available memory if the old value is long enough. Never free an
112      * old name=value entry because it may not be allocated.
113      */
114 
115     destination = (envp != 0 && strlen(*envp) >= l_nameval) ?
116 	*envp : malloc(l_nameval + 1);
117     if (destination == 0)
118 	return (-1);
119     strncpy(destination, name, l_name);
120     destination[l_name] = '=';
121     strcpy(destination + l_name + 1, value);
122     return ((envp == 0) ? addenv(destination) : (*envp = destination, 0));
123 }
124 
125 /* cmalloc - malloc and copy block of memory */
126 
127 static char *cmalloc(int new_len, char *old, int old_len)
128 {
129     char   *new = malloc(new_len);
130 
131     if (new != 0)
132 	memcpy(new, old, old_len);
133     return (new);
134 }
135 
136 /* addenv - append environment entry */
137 
138 static int addenv(char *nameval)
139 {
140     char  **envp;
141     int     n_used;			/* number of environment entries */
142     int     l_used;			/* bytes used excl. terminator */
143     int     l_need;			/* bytes needed incl. terminator */
144 
145     for (envp = environ; envp && *envp; envp++)
146 	 /* void */ ;
147     n_used = envp - environ;
148     l_used = n_used * sizeof(*envp);
149     l_need = l_used + 2 * sizeof(*envp);
150 
151     envp = allocated ?
152 	(char **) realloc((char *) environ, l_need) :
153 	(char **) cmalloc(l_need, (char *) environ, l_used);
154     if (envp == 0) {
155 	return (-1);
156     } else {
157 	allocated = 1;
158 	environ = envp;
159 	environ[n_used++] = nameval;		/* add new entry */
160 	environ[n_used] = 0;			/* terminate list */
161 	return (0);
162     }
163 }
164 
165 #ifdef TEST
166 
167  /*
168   * Stand-alone program for test purposes.
169   */
170 
171 /* printenv - display environment */
172 
173 static void printenv()
174 {
175     char  **envp;
176 
177     for (envp = environ; envp && *envp; envp++)
178 	printf("%s\n", *envp);
179 }
180 
181 int     main(int argc, char **argv)
182 {
183     char   *cp;
184     int     changed = 0;
185 
186     if (argc < 2) {
187 	printf("usage: %s name[=value]...\n", argv[0]);
188 	return (1);
189     }
190     while (--argc && *++argv) {
191 	if (argv[0][0] == '-') {		/* unsetenv() test */
192 	    unsetenv(argv[0] + 1);
193 	    changed = 1;
194 	} else if (strchr(argv[0], '=') == 0) {	/* getenv() test */
195 	    cp = getenv(argv[0]);
196 	    printf("%s: %s\n", argv[0], cp ? cp : "not found");
197 	} else {				/* putenv() test */
198 	    if (putenv(argv[0])) {
199 		perror("putenv");
200 		return (1);
201 	    }
202 	    changed = 1;
203 	}
204     }
205     if (changed)
206 	printenv();
207     return (0);
208 }
209 
210 #endif /* TEST */
211