xref: /php-src/sapi/fpm/fpm/fpm_env.c (revision 80d4d406)
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