xref: /freebsd/contrib/tcp_wrappers/environ.c (revision fcb560670601b2a4d87bb31d7531c8dcc37ee71b)
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(name)
41 char   *name;
42 {
43     char   *equal;
44 
45     equal = strchr(name, '=');
46     return ((equal == 0) ? strlen(name) : (equal - name));
47 }
48 
49 /* findenv - given name, locate name=value */
50 
51 static char **findenv(name, len)
52 char   *name;
53 int     len;
54 {
55     char  **envp;
56 
57     for (envp = environ; envp && *envp; envp++)
58 	if (strncmp(name, *envp, len) == 0 && (*envp)[len] == '=')
59 	    return (envp);
60     return (0);
61 }
62 
63 /* getenv - given name, locate value */
64 
65 char   *getenv(name)
66 char   *name;
67 {
68     int     len = namelength(name);
69     char  **envp = findenv(name, len);
70 
71     return (envp ? *envp + len + 1 : 0);
72 }
73 
74 /* putenv - update or append environment (name,value) pair */
75 
76 int     putenv(nameval)
77 char   *nameval;
78 {
79     char   *equal = strchr(nameval, '=');
80     char   *value = (equal ? equal : "");
81 
82     return (setenv(nameval, value, DO_CLOBBER));
83 }
84 
85 /* unsetenv - remove variable from environment */
86 
87 void    unsetenv(name)
88 char   *name;
89 {
90     char  **envp;
91 
92     if ((envp = findenv(name, namelength(name))) != 0)
93 	while (envp[0] = envp[1])
94 	    envp++;
95 }
96 
97 /* setenv - update or append environment (name,value) pair */
98 
99 int     setenv(name, value, clobber)
100 char   *name;
101 char   *value;
102 int     clobber;
103 {
104     char   *destination;
105     char  **envp;
106     int     l_name;			/* length of name part */
107     int     l_nameval;			/* length of name=value */
108 
109     /* Permit name= and =value. */
110 
111     l_name = namelength(name);
112     envp = findenv(name, l_name);
113     if (envp != 0 && clobber == 0)
114 	return (0);
115     if (*value == '=')
116 	value++;
117     l_nameval = l_name + strlen(value) + 1;
118 
119     /*
120      * Use available memory if the old value is long enough. Never free an
121      * old name=value entry because it may not be allocated.
122      */
123 
124     destination = (envp != 0 && strlen(*envp) >= l_nameval) ?
125 	*envp : malloc(l_nameval + 1);
126     if (destination == 0)
127 	return (-1);
128     strncpy(destination, name, l_name);
129     destination[l_name] = '=';
130     strcpy(destination + l_name + 1, value);
131     return ((envp == 0) ? addenv(destination) : (*envp = destination, 0));
132 }
133 
134 /* cmalloc - malloc and copy block of memory */
135 
136 static char *cmalloc(new_len, old, old_len)
137 char   *old;
138 int     old_len;
139 {
140     char   *new = malloc(new_len);
141 
142     if (new != 0)
143 	memcpy(new, old, old_len);
144     return (new);
145 }
146 
147 /* addenv - append environment entry */
148 
149 static int addenv(nameval)
150 char   *nameval;
151 {
152     char  **envp;
153     int     n_used;			/* number of environment entries */
154     int     l_used;			/* bytes used excl. terminator */
155     int     l_need;			/* bytes needed incl. terminator */
156 
157     for (envp = environ; envp && *envp; envp++)
158 	 /* void */ ;
159     n_used = envp - environ;
160     l_used = n_used * sizeof(*envp);
161     l_need = l_used + 2 * sizeof(*envp);
162 
163     envp = allocated ?
164 	(char **) realloc((char *) environ, l_need) :
165 	(char **) cmalloc(l_need, (char *) environ, l_used);
166     if (envp == 0) {
167 	return (-1);
168     } else {
169 	allocated = 1;
170 	environ = envp;
171 	environ[n_used++] = nameval;		/* add new entry */
172 	environ[n_used] = 0;			/* terminate list */
173 	return (0);
174     }
175 }
176 
177 #ifdef TEST
178 
179  /*
180   * Stand-alone program for test purposes.
181   */
182 
183 /* printenv - display environment */
184 
185 static void printenv()
186 {
187     char  **envp;
188 
189     for (envp = environ; envp && *envp; envp++)
190 	printf("%s\n", *envp);
191 }
192 
193 int     main(argc, argv)
194 int     argc;
195 char  **argv;
196 {
197     char   *cp;
198     int     changed = 0;
199 
200     if (argc < 2) {
201 	printf("usage: %s name[=value]...\n", argv[0]);
202 	return (1);
203     }
204     while (--argc && *++argv) {
205 	if (argv[0][0] == '-') {		/* unsetenv() test */
206 	    unsetenv(argv[0] + 1);
207 	    changed = 1;
208 	} else if (strchr(argv[0], '=') == 0) {	/* getenv() test */
209 	    cp = getenv(argv[0]);
210 	    printf("%s: %s\n", argv[0], cp ? cp : "not found");
211 	} else {				/* putenv() test */
212 	    if (putenv(argv[0])) {
213 		perror("putenv");
214 		return (1);
215 	    }
216 	    changed = 1;
217 	}
218     }
219     if (changed)
220 	printenv();
221     return (0);
222 }
223 
224 #endif /* TEST */
225