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