1 /* $NetBSD: environ.c,v 1.1.1.1 2009/06/23 10:08:59 tron Exp $ */
2
3 /*
4 * From: TCP Wrapper.
5 *
6 * Many systems have putenv() but no setenv(). Other systems have setenv() but
7 * no putenv() (MIPS). Still other systems have neither (NeXT). This is a
8 * re-implementation that hopefully ends all problems.
9 *
10 * Author: Wietse Venema, Eindhoven University of Technology, The Netherlands.
11 */
12 #include "sys_defs.h"
13
14 #ifdef MISSING_SETENV_PUTENV
15
16 #include <stdio.h>
17 #include <string.h>
18 #include <stdlib.h>
19
20 extern char **environ;
21
22 static int addenv(char *); /* append entry to environment */
23 static int allocated = 0; /* environ is, or is not, allocated */
24
25 #define DO_CLOBBER 1
26
27 /* namelength - determine length of name in "name=whatever" */
28
namelength(const char * name)29 static ssize_t namelength(const char *name)
30 {
31 char *equal;
32
33 equal = strchr(name, '=');
34 return ((equal == 0) ? strlen(name) : (equal - name));
35 }
36
37 /* findenv - given name, locate name=value */
38
findenv(const char * name,ssize_t len)39 static char **findenv(const char *name, ssize_t len)
40 {
41 char **envp;
42
43 for (envp = environ; envp && *envp; envp++)
44 if (strncmp(name, *envp, len) == 0 && (*envp)[len] == '=')
45 return (envp);
46 return (0);
47 }
48
49 #if 0
50
51 /* getenv - given name, locate value */
52
53 char *getenv(const char *name)
54 {
55 ssize_t len = namelength(name);
56 char **envp = findenv(name, len);
57
58 return (envp ? *envp + len + 1 : 0);
59 }
60
61 /* putenv - update or append environment (name,value) pair */
62
63 int putenv(const char *nameval)
64 {
65 char *equal = strchr(nameval, '=');
66 char *value = (equal ? equal : "");
67
68 return (setenv(nameval, value, DO_CLOBBER));
69 }
70
71 /* unsetenv - remove variable from environment */
72
73 void unsetenv(const char *name)
74 {
75 char **envp;
76
77 while ((envp = findenv(name, namelength(name))) != 0)
78 while (envp[0] = envp[1])
79 envp++;
80 }
81
82 #endif
83
84 /* setenv - update or append environment (name,value) pair */
85
setenv(const char * name,const char * value,int clobber)86 int setenv(const char *name, const char *value, int clobber)
87 {
88 char *destination;
89 char **envp;
90 ssize_t l_name; /* length of name part */
91 unsigned int l_nameval; /* length of name=value */
92
93 /* Permit name= and =value. */
94
95 l_name = namelength(name);
96 envp = findenv(name, l_name);
97 if (envp != 0 && clobber == 0)
98 return (0);
99 if (*value == '=')
100 value++;
101 l_nameval = l_name + strlen(value) + 1;
102
103 /*
104 * Use available memory if the old value is long enough. Never free an
105 * old name=value entry because it may not be allocated.
106 */
107
108 destination = (envp != 0 && strlen(*envp) >= l_nameval) ?
109 *envp : malloc(l_nameval + 1);
110 if (destination == 0)
111 return (-1);
112 strncpy(destination, name, l_name);
113 destination[l_name] = '=';
114 strcpy(destination + l_name + 1, value);
115 return ((envp == 0) ? addenv(destination) : (*envp = destination, 0));
116 }
117
118 /* cmalloc - malloc and copy block of memory */
119
cmalloc(ssize_t new_len,char * old,ssize_t old_len)120 static char *cmalloc(ssize_t new_len, char *old, ssize_t old_len)
121 {
122 char *new = malloc(new_len);
123
124 if (new != 0)
125 memcpy(new, old, old_len);
126 return (new);
127 }
128
129 /* addenv - append environment entry */
130
addenv(char * nameval)131 static int addenv(char *nameval)
132 {
133 char **envp;
134 ssize_t n_used; /* number of environment entries */
135 ssize_t l_used; /* bytes used excl. terminator */
136 ssize_t l_need; /* bytes needed incl. terminator */
137
138 for (envp = environ; envp && *envp; envp++)
139 /* void */ ;
140 n_used = envp - environ;
141 l_used = n_used * sizeof(*envp);
142 l_need = l_used + 2 * sizeof(*envp);
143
144 envp = allocated ?
145 (char **) realloc((char *) environ, l_need) :
146 (char **) cmalloc(l_need, (char *) environ, l_used);
147 if (envp == 0) {
148 return (-1);
149 } else {
150 allocated = 1;
151 environ = envp;
152 environ[n_used++] = nameval; /* add new entry */
153 environ[n_used] = 0; /* terminate list */
154 return (0);
155 }
156 }
157
158 #endif
159