1 /* (c) 2007,2008 Andrei Nigmatulin */
2
3 #include "fpm_config.h"
4
5 #ifdef HAVE_ALLOCA_H
6 #include <alloca.h>
7 #endif
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11
12 #include "fpm_env.h"
13 #include "fpm.h"
14 #include "fpm_cleanup.h"
15
16 #ifndef HAVE_SETPROCTITLE
17 #if defined(__linux__) || defined(__APPLE__)
18 static char **fpm_env_argv = NULL;
19 static size_t fpm_env_argv_len = 0;
20 #endif
21 #endif
22
23 #ifndef HAVE_SETENV
24 # ifdef (__sparc__ || __sparc)
setenv(char * name,char * value,int clobber)25 int setenv(char *name, char *value, int clobber) /* {{{ */
26 {
27 char *malloc();
28 char *getenv();
29 char *cp;
30
31 if (clobber == 0 && getenv(name) != 0) {
32 return 0;
33 }
34
35 if ((cp = malloc(strlen(name) + strlen(value) + 2)) == 0) {
36 return 1;
37 }
38 sprintf(cp, "%s=%s", name, value);
39 return putenv(cp);
40 }
41 /* }}} */
42 # else
setenv(char * name,char * value,int overwrite)43 int setenv(char *name, char *value, int overwrite) /* {{{ */
44 {
45 int name_len = strlen(name);
46 int value_len = strlen(value);
47 char *var = alloca(name_len + 1 + value_len + 1);
48
49 memcpy(var, name, name_len);
50
51 var[name_len] = '=';
52
53 memcpy(var + name_len + 1, value, value_len);
54
55 var[name_len + 1 + value_len] = '\0';
56
57 return putenv(var);
58 }
59 /* }}} */
60 # endif
61 #endif
62
63 #ifndef HAVE_CLEARENV
clearenv(void)64 void clearenv(void)
65 {
66 char **envp;
67 char *s;
68
69 /* this algo is the only one known to me
70 that works well on all systems */
71 while (*(envp = environ)) {
72 char *eq = strchr(*envp, '=');
73
74 s = strdup(*envp);
75
76 if (eq) s[eq - *envp] = '\0';
77
78 unsetenv(s);
79 free(s);
80 }
81
82 }
83 #endif
84
85 #ifndef HAVE_UNSETENV
unsetenv(const char * name)86 void unsetenv(const char *name) /* {{{ */
87 {
88 if(getenv(name) != NULL) {
89 int ct = 0;
90 int del = 0;
91
92 while(environ[ct] != NULL) {
93 if (nvmatch(name, environ[ct]) != 0) del=ct; /* <--- WTF?! */
94 { ct++; } /* <--- WTF?! */
95 }
96 /* isn't needed free here?? */
97 environ[del] = environ[ct-1];
98 environ[ct-1] = NULL;
99 }
100 }
101 /* }}} */
102
nvmatch(char * s1,char * s2)103 static char * nvmatch(char *s1, char *s2) /* {{{ */
104 {
105 while(*s1 == *s2++)
106 {
107 if(*s1++ == '=') {
108 return s2;
109 }
110 }
111 if(*s1 == '\0' && *(s2-1) == '=') {
112 return s2;
113 }
114 return NULL;
115 }
116 /* }}} */
117 #endif
118
fpm_env_setproctitle(char * title)119 void fpm_env_setproctitle(char *title) /* {{{ */
120 {
121 #if defined(HAVE_SETPROCTITLE_FAST)
122 setproctitle_fast("%s", title);
123 #elif defined(HAVE_SETPROCTITLE)
124 setproctitle("%s", title);
125 #elif defined(__linux__) || defined(__APPLE__)
126 size_t prefixlen = strlen(SETPROCTITLE_PREFIX);
127 if (fpm_env_argv != NULL && fpm_env_argv_len > prefixlen + 3) {
128 memset(fpm_env_argv[0], 0, fpm_env_argv_len);
129 strncpy(fpm_env_argv[0], SETPROCTITLE_PREFIX, fpm_env_argv_len - 2);
130 strncpy(fpm_env_argv[0] + prefixlen, title, fpm_env_argv_len - prefixlen - 2);
131 fpm_env_argv[1] = NULL;
132 }
133 #endif
134 }
135 /* }}} */
136
fpm_env_init_child(struct fpm_worker_pool_s * wp)137 int fpm_env_init_child(struct fpm_worker_pool_s *wp) /* {{{ */
138 {
139 struct key_value_s *kv;
140 char *title;
141 spprintf(&title, 0, "pool %s", wp->config->name);
142 fpm_env_setproctitle(title);
143 efree(title);
144
145 if (wp->config->clear_env) {
146 clearenv();
147 }
148
149 for (kv = wp->config->env; kv; kv = kv->next) {
150 setenv(kv->key, kv->value, 1);
151 }
152
153 if (wp->user) {
154 setenv("USER", wp->user, 1);
155 }
156
157 if (wp->home) {
158 setenv("HOME", wp->home, 1);
159 }
160
161 return 0;
162 }
163 /* }}} */
164
fpm_env_conf_wp(struct fpm_worker_pool_s * wp)165 static int fpm_env_conf_wp(struct fpm_worker_pool_s *wp) /* {{{ */
166 {
167 struct key_value_s *kv;
168
169 for (kv = wp->config->env; kv; kv = kv->next) {
170 if (*kv->value == '$') {
171 char *value = getenv(kv->value + 1);
172
173 if (!value) {
174 value = "";
175 }
176
177 free(kv->value);
178 kv->value = strdup(value);
179 }
180
181 /* autodetected values should be removed
182 if these vars specified in config */
183 if (!strcmp(kv->key, "USER")) {
184 free(wp->user);
185 wp->user = 0;
186 }
187
188 if (!strcmp(kv->key, "HOME")) {
189 free(wp->home);
190 wp->home = 0;
191 }
192 }
193
194 return 0;
195 }
196 /* }}} */
197
198
199 #ifndef HAVE_SETPROCTITLE
200 #if defined(__linux__) || defined(__APPLE__)
201 /* Frees our copied environment variables. */
fpm_env_cleanup(int which,void * arg)202 static void fpm_env_cleanup(int which, void *arg) /* {{{ */
203 {
204 char** allocated_environ = environ;
205 if (allocated_environ) {
206 environ = NULL;
207 unsigned int i = 0;
208 while (allocated_environ[i]) {
209 free(allocated_environ[i]);
210 i++;
211 }
212 free(allocated_environ);
213 }
214 }
215 #endif
216 #endif
217
fpm_env_init_main(void)218 int fpm_env_init_main(void)
219 {
220 struct fpm_worker_pool_s *wp;
221 char *title;
222
223 for (wp = fpm_worker_all_pools; wp; wp = wp->next) {
224 if (0 > fpm_env_conf_wp(wp)) {
225 return -1;
226 }
227 }
228 #ifndef HAVE_SETPROCTITLE
229 #if defined(__linux__) || defined(__APPLE__)
230 int i;
231 char *first = NULL;
232 char *last = NULL;
233 /*
234 * This piece of code has been inspired from nginx and pureftpd code, which
235 * are under BSD licence.
236 *
237 * To change the process title in Linux we have to set argv[1] to NULL
238 * and to copy the title to the same place where the argv[0] points to.
239 * However, argv[0] may be too small to hold a new title. Fortunately, Linux
240 * store argv[] and environ[] one after another. So we should ensure that is
241 * the continuous memory and then we allocate the new memory for environ[]
242 * and copy it. After this we could use the memory starting from argv[0] for
243 * our process title.
244 */
245
246 for (i = 0; i < fpm_globals.argc; i++) {
247 if (first == NULL) {
248 first = fpm_globals.argv[i];
249 }
250 if (last == NULL || fpm_globals.argv[i] == last + 1) {
251 last = fpm_globals.argv[i] + strlen(fpm_globals.argv[i]);
252 }
253 }
254 if (environ) {
255 for (i = 0; environ[i]; i++) {
256 if (first == NULL) {
257 first = environ[i];
258 }
259 if (last == NULL || environ[i] == last + 1) {
260 last = environ[i] + strlen(environ[i]);
261 }
262 }
263 }
264 if (first == NULL || last == NULL) {
265 return 0;
266 }
267
268 fpm_env_argv_len = last - first;
269 fpm_env_argv = fpm_globals.argv;
270 if (environ != NULL) {
271 char **new_environ;
272 unsigned int env_nb = 0U;
273
274 while (environ[env_nb]) {
275 env_nb++;
276 }
277
278 if (0 > fpm_cleanup_add(FPM_CLEANUP_PARENT_EXIT_MAIN, fpm_env_cleanup, 0)) {
279 return -1;
280 }
281
282 if ((new_environ = malloc((1U + env_nb) * sizeof (char *))) == NULL) {
283 return -1;
284 }
285 new_environ[env_nb] = NULL;
286 while (env_nb > 0U) {
287 env_nb--;
288 new_environ[env_nb] = strdup(environ[env_nb]);
289 }
290 environ = new_environ;
291 }
292 #endif
293 #endif
294
295 spprintf(&title, 0, "master process (%s)", fpm_globals.config);
296 fpm_env_setproctitle(title);
297 efree(title);
298 return 0;
299 }
300