1 #include "uwsgi.h"
2 
3 /*
4 
5 	pluggable configuration system
6 
7 */
8 
9 extern struct uwsgi_server uwsgi;
10 
uwsgi_register_configurator(char * name,void (* func)(char *,char **))11 struct uwsgi_configurator *uwsgi_register_configurator(char *name, void (*func)(char *, char **)) {
12 	struct uwsgi_configurator *old_uc = NULL,*uc = uwsgi.configurators;
13         while(uc) {
14                 if (!strcmp(uc->name, name)) {
15                         return uc;
16                 }
17                 old_uc = uc;
18                 uc = uc->next;
19         }
20 
21         uc = uwsgi_calloc(sizeof(struct uwsgi_configurator));
22         uc->name = name;
23         uc->func = func;
24 
25         if (old_uc) {
26                 old_uc->next = uc;
27         }
28         else {
29                 uwsgi.configurators = uc;
30         }
31 
32         return uc;
33 }
34 
uwsgi_logic_opt_if_exists(char * key,char * value)35 int uwsgi_logic_opt_if_exists(char *key, char *value) {
36 
37         if (uwsgi_file_exists(uwsgi.logic_opt_data)) {
38                 add_exported_option(key, uwsgi_substitute(value, "%(_)", uwsgi.logic_opt_data), 0);
39                 return 1;
40         }
41 
42         return 0;
43 }
44 
uwsgi_logic_opt_if_not_exists(char * key,char * value)45 int uwsgi_logic_opt_if_not_exists(char *key, char *value) {
46 
47         if (!uwsgi_file_exists(uwsgi.logic_opt_data)) {
48                 add_exported_option(key, uwsgi_substitute(value, "%(_)", uwsgi.logic_opt_data), 0);
49                 return 1;
50         }
51 
52         return 0;
53 }
54 
55 
uwsgi_logic_opt_for(char * key,char * value)56 int uwsgi_logic_opt_for(char *key, char *value) {
57 
58         char *p, *ctx = NULL;
59 	uwsgi_foreach_token(uwsgi.logic_opt_data, " ", p, ctx) {
60                 add_exported_option(key, uwsgi_substitute(value, "%(_)", p), 0);
61         }
62 
63         return 1;
64 }
65 
uwsgi_logic_opt_for_glob(char * key,char * value)66 int uwsgi_logic_opt_for_glob(char *key, char *value) {
67 
68         glob_t g;
69         int i;
70         if (glob(uwsgi.logic_opt_data, GLOB_MARK | GLOB_NOCHECK, NULL, &g)) {
71                 uwsgi_error("uwsgi_logic_opt_for_glob()");
72                 return 0;
73         }
74 
75         for (i = 0; i < (int) g.gl_pathc; i++) {
76                 add_exported_option(key, uwsgi_substitute(value, "%(_)", g.gl_pathv[i]), 0);
77         }
78 
79         globfree(&g);
80 
81         return 1;
82 }
83 
uwsgi_logic_opt_for_readline(char * key,char * value)84 int uwsgi_logic_opt_for_readline(char *key, char *value) {
85 
86 	char line[1024];
87 
88         FILE *fh = fopen(uwsgi.logic_opt_data, "r");
89         if (fh) {
90                 while (fgets(line, 1024, fh)) {
91 			add_exported_option(key, uwsgi_substitute(value, "%(_)", uwsgi_chomp(uwsgi_str(line))), 0);
92                 }
93                 fclose(fh);
94                 return 1;
95         }
96         uwsgi_error_open(uwsgi.logic_opt_data);
97 	return 0;
98 }
99 
uwsgi_logic_opt_for_times(char * key,char * value)100 int uwsgi_logic_opt_for_times(char *key, char *value) {
101 
102         int num = atoi(uwsgi.logic_opt_data);
103         int i;
104         char str_num[11];
105 
106         for (i = 1; i <= num; i++) {
107                 int ret = uwsgi_num2str2(i, str_num);
108                 // security check
109                 if (ret < 0 || ret > 11) {
110                         exit(1);
111                 }
112                 add_exported_option(key, uwsgi_substitute(value, "%(_)", str_num), 0);
113         }
114 
115         return 1;
116 }
117 
118 
uwsgi_logic_opt_if_opt(char * key,char * value)119 int uwsgi_logic_opt_if_opt(char *key, char *value) {
120 
121         // check for env-value syntax
122         char *equal = strchr(uwsgi.logic_opt_data, '=');
123         if (equal)
124                 *equal = 0;
125 
126         char *p = uwsgi_get_exported_opt(uwsgi.logic_opt_data);
127         if (equal)
128                 *equal = '=';
129 
130         if (p) {
131                 if (equal) {
132                         if (strcmp(equal + 1, p))
133                                 return 0;
134                 }
135                 add_exported_option(key, uwsgi_substitute(value, "%(_)", p), 0);
136                 return 1;
137         }
138 
139         return 0;
140 }
141 
142 
uwsgi_logic_opt_if_not_opt(char * key,char * value)143 int uwsgi_logic_opt_if_not_opt(char *key, char *value) {
144 
145         // check for env-value syntax
146         char *equal = strchr(uwsgi.logic_opt_data, '=');
147         if (equal)
148                 *equal = 0;
149 
150         char *p = uwsgi_get_exported_opt(uwsgi.logic_opt_data);
151         if (equal)
152                 *equal = '=';
153 
154         if (p) {
155                 if (equal) {
156                         if (!strcmp(equal + 1, p))
157                                 return 0;
158                 }
159                 else {
160                         return 0;
161                 }
162         }
163 
164         add_exported_option(key, uwsgi_substitute(value, "%(_)", p), 0);
165         return 1;
166 }
167 
168 
169 
uwsgi_logic_opt_if_env(char * key,char * value)170 int uwsgi_logic_opt_if_env(char *key, char *value) {
171 
172         // check for env-value syntax
173         char *equal = strchr(uwsgi.logic_opt_data, '=');
174         if (equal)
175                 *equal = 0;
176 
177         char *p = getenv(uwsgi.logic_opt_data);
178         if (equal)
179                 *equal = '=';
180 
181         if (p) {
182                 if (equal) {
183                         if (strcmp(equal + 1, p))
184                                 return 0;
185                 }
186                 add_exported_option(key, uwsgi_substitute(value, "%(_)", p), 0);
187                 return 1;
188         }
189 
190         return 0;
191 }
192 
193 
uwsgi_logic_opt_if_not_env(char * key,char * value)194 int uwsgi_logic_opt_if_not_env(char *key, char *value) {
195 
196         // check for env-value syntax
197         char *equal = strchr(uwsgi.logic_opt_data, '=');
198         if (equal)
199                 *equal = 0;
200 
201         char *p = getenv(uwsgi.logic_opt_data);
202         if (equal)
203                 *equal = '=';
204 
205         if (p) {
206                 if (equal) {
207                         if (!strcmp(equal + 1, p))
208                                 return 0;
209                 }
210                 else {
211                         return 0;
212                 }
213         }
214 
215         add_exported_option(key, uwsgi_substitute(value, "%(_)", p), 0);
216         return 1;
217 }
218 
uwsgi_logic_opt_if_reload(char * key,char * value)219 int uwsgi_logic_opt_if_reload(char *key, char *value) {
220         if (uwsgi.is_a_reload) {
221                 add_exported_option(key, value, 0);
222                 return 1;
223         }
224         return 0;
225 }
226 
uwsgi_logic_opt_if_not_reload(char * key,char * value)227 int uwsgi_logic_opt_if_not_reload(char *key, char *value) {
228         if (!uwsgi.is_a_reload) {
229                 add_exported_option(key, value, 0);
230                 return 1;
231         }
232         return 0;
233 }
234 
uwsgi_logic_opt_if_file(char * key,char * value)235 int uwsgi_logic_opt_if_file(char *key, char *value) {
236 
237         if (uwsgi_is_file(uwsgi.logic_opt_data)) {
238                 add_exported_option(key, uwsgi_substitute(value, "%(_)", uwsgi.logic_opt_data), 0);
239                 return 1;
240         }
241 
242         return 0;
243 }
244 
uwsgi_logic_opt_if_not_file(char * key,char * value)245 int uwsgi_logic_opt_if_not_file(char *key, char *value) {
246 
247         if (!uwsgi_is_file(uwsgi.logic_opt_data)) {
248                 add_exported_option(key, uwsgi_substitute(value, "%(_)", uwsgi.logic_opt_data), 0);
249                 return 1;
250         }
251 
252         return 0;
253 }
254 
uwsgi_logic_opt_if_dir(char * key,char * value)255 int uwsgi_logic_opt_if_dir(char *key, char *value) {
256 
257         if (uwsgi_is_dir(uwsgi.logic_opt_data)) {
258                 add_exported_option(key, uwsgi_substitute(value, "%(_)", uwsgi.logic_opt_data), 0);
259                 return 1;
260         }
261 
262         return 0;
263 }
264 
uwsgi_logic_opt_if_not_dir(char * key,char * value)265 int uwsgi_logic_opt_if_not_dir(char *key, char *value) {
266 
267         if (!uwsgi_is_dir(uwsgi.logic_opt_data)) {
268                 add_exported_option(key, uwsgi_substitute(value, "%(_)", uwsgi.logic_opt_data), 0);
269                 return 1;
270         }
271 
272         return 0;
273 }
274 
275 
276 
uwsgi_logic_opt_if_plugin(char * key,char * value)277 int uwsgi_logic_opt_if_plugin(char *key, char *value) {
278 
279         if (plugin_already_loaded(uwsgi.logic_opt_data)) {
280                 add_exported_option(key, uwsgi_substitute(value, "%(_)", uwsgi.logic_opt_data), 0);
281                 return 1;
282         }
283 
284         return 0;
285 }
286 
uwsgi_logic_opt_if_not_plugin(char * key,char * value)287 int uwsgi_logic_opt_if_not_plugin(char *key, char *value) {
288 
289         if (!plugin_already_loaded(uwsgi.logic_opt_data)) {
290                 add_exported_option(key, uwsgi_substitute(value, "%(_)", uwsgi.logic_opt_data), 0);
291                 return 1;
292         }
293 
294         return 0;
295 }
296 
uwsgi_logic_opt_if_hostname(char * key,char * value)297 int uwsgi_logic_opt_if_hostname(char *key, char *value) {
298 
299         if (!strcmp(uwsgi.hostname, uwsgi.logic_opt_data)) {
300                 add_exported_option(key, uwsgi_substitute(value, "%(_)", uwsgi.logic_opt_data), 0);
301                 return 1;
302         }
303 
304         return 0;
305 }
306 
uwsgi_logic_opt_if_not_hostname(char * key,char * value)307 int uwsgi_logic_opt_if_not_hostname(char *key, char *value) {
308 
309         if (strcmp(uwsgi.hostname, uwsgi.logic_opt_data)) {
310                 add_exported_option(key, uwsgi_substitute(value, "%(_)", uwsgi.logic_opt_data), 0);
311                 return 1;
312         }
313 
314         return 0;
315 }
316 
317 #ifdef UWSGI_PCRE
uwsgi_logic_opt_if_hostname_match(char * key,char * value)318 int uwsgi_logic_opt_if_hostname_match(char *key, char *value) {
319 	if (uwsgi_regexp_match_pattern(uwsgi.logic_opt_data, uwsgi.hostname)) {
320 		add_exported_option(key, uwsgi_substitute(value, "%(_)", uwsgi.logic_opt_data), 0);
321 		return 1;
322 	}
323 	return 0;
324 }
325 
uwsgi_logic_opt_if_not_hostname_match(char * key,char * value)326 int uwsgi_logic_opt_if_not_hostname_match(char *key, char *value) {
327 	if (!uwsgi_regexp_match_pattern(uwsgi.logic_opt_data, uwsgi.hostname)) {
328 		add_exported_option(key, uwsgi_substitute(value, "%(_)", uwsgi.logic_opt_data), 0);
329 		return 1;
330 	}
331 	return 0;
332 }
333 #endif
334 
uwsgi_count_options(struct uwsgi_option * uopt)335 int uwsgi_count_options(struct uwsgi_option *uopt) {
336 
337         struct uwsgi_option *aopt;
338         int count = 0;
339 
340         while ((aopt = uopt)) {
341                 if (!aopt->name)
342                         break;
343                 count++;
344                 uopt++;
345         }
346 
347         return count;
348 }
349 
uwsgi_opt_exists(char * name)350 int uwsgi_opt_exists(char *name) {
351 	struct uwsgi_option *op = uwsgi.options;
352 	while (op->name) {
353 		if (!strcmp(name, op->name)) return 1;
354 		op++;
355 	}
356 	return 0;
357 }
358 
359 /*
360 	avoid loops here !!!
361 */
uwsgi_opt_get(char * name)362 struct uwsgi_option *uwsgi_opt_get(char *name) {
363         struct uwsgi_option *op;
364 	int round = 0;
365 retry:
366 	round++;
367 	if (round > 2) goto end;
368 	op = uwsgi.options;
369 
370         while (op->name) {
371                 if (!strcmp(name, op->name)) {
372                         return op;
373                 }
374                 op++;
375         }
376 
377 	if (uwsgi.autoload) {
378 		if (uwsgi_try_autoload(name)) goto retry;
379 	}
380 
381 end:
382 	if (uwsgi.strict) {
383                 uwsgi_log("[strict-mode] unknown config directive: %s\n", name);
384                 exit(1);
385         }
386 
387         return NULL;
388 }
389 
390 
391 
add_exported_option(char * key,char * value,int configured)392 void add_exported_option(char *key, char *value, int configured) {
393 	add_exported_option_do(key, value, configured, 0);
394 }
395 
add_exported_option_do(char * key,char * value,int configured,int placeholder_only)396 void add_exported_option_do(char *key, char *value, int configured, int placeholder_only) {
397 
398 	struct uwsgi_string_list *blacklist = uwsgi.blacklist;
399 	struct uwsgi_string_list *whitelist = uwsgi.whitelist;
400 
401 	while (blacklist) {
402 		if (!strcmp(key, blacklist->value)) {
403 			uwsgi_log("uWSGI error: forbidden option \"%s\" (by blacklist)\n", key);
404 			exit(1);
405 		}
406 		blacklist = blacklist->next;
407 	}
408 
409 	if (whitelist) {
410 		int allowed = 0;
411 		while (whitelist) {
412 			if (!strcmp(key, whitelist->value)) {
413 				allowed = 1;
414 				break;
415 			}
416 			whitelist = whitelist->next;
417 		}
418 		if (!allowed) {
419 			uwsgi_log("uWSGI error: forbidden option \"%s\" (by whitelist)\n", key);
420 			exit(1);
421 		}
422 	}
423 
424 	if (uwsgi.blacklist_context) {
425 		if (uwsgi_list_has_str(uwsgi.blacklist_context, key)) {
426 			uwsgi_log("uWSGI error: forbidden option \"%s\" (by blacklist)\n", key);
427 			exit(1);
428 		}
429 	}
430 
431 	if (uwsgi.whitelist_context) {
432                 if (!uwsgi_list_has_str(uwsgi.whitelist_context, key)) {
433                         uwsgi_log("uWSGI error: forbidden option \"%s\" (by whitelist)\n", key);
434                         exit(1);
435                 }
436         }
437 
438 	if (uwsgi.logic_opt_running)
439 		goto add;
440 
441 	if (!strcmp(key, "end") || !strcmp(key, "endfor") || !strcmp(key, "endif")
442 		|| !strcmp(key, "end-if") || !strcmp(key, "end-for")) {
443 		if (uwsgi.logic_opt_data) {
444 			free(uwsgi.logic_opt_data);
445 		}
446 		uwsgi.logic_opt = NULL;
447 		uwsgi.logic_opt_arg = NULL;
448 		uwsgi.logic_opt_cycles = 0;
449 		uwsgi.logic_opt_data = NULL;
450 	}
451 
452 	if (uwsgi.logic_opt) {
453 		if (uwsgi.logic_opt_data) {
454 			free(uwsgi.logic_opt_data);
455 		}
456 		uwsgi.logic_opt_data = uwsgi_str(uwsgi.logic_opt_arg);
457 		uwsgi.logic_opt_cycles++;
458 		uwsgi.logic_opt_running = 1;
459 		uwsgi.logic_opt(key, value);
460 		uwsgi.logic_opt_running = 0;
461 		return;
462 	}
463 
464 add:
465 
466 	if (!uwsgi.exported_opts) {
467 		uwsgi.exported_opts = uwsgi_malloc(sizeof(struct uwsgi_opt *));
468 	}
469 	else {
470 		uwsgi.exported_opts = realloc(uwsgi.exported_opts, sizeof(struct uwsgi_opt *) * (uwsgi.exported_opts_cnt + 1));
471 		if (!uwsgi.exported_opts) {
472 			uwsgi_error("realloc()");
473 			exit(1);
474 		}
475 	}
476 
477 	int id = uwsgi.exported_opts_cnt;
478 	uwsgi.exported_opts[id] = uwsgi_malloc(sizeof(struct uwsgi_opt));
479 	uwsgi.exported_opts[id]->key = key;
480 	uwsgi.exported_opts[id]->value = value;
481 	uwsgi.exported_opts[id]->configured = configured;
482 	uwsgi.exported_opts_cnt++;
483 	uwsgi.dirty_config = 1;
484 
485 	if (placeholder_only) {
486 		if (uwsgi_opt_exists(key)) {
487 			uwsgi_log("you cannot use %s as a placeholder, it is already available as an option\n");
488 			exit(1);
489 		}
490 		uwsgi.exported_opts[id]->configured = 1;
491 		return;
492 	}
493 
494 	struct uwsgi_option *op = uwsgi_opt_get(key);
495 	if (op) {
496 		// requires master ?
497 		if (op->flags & UWSGI_OPT_MASTER) {
498 			uwsgi.master_process = 1;
499 		}
500 		// requires log_master ?
501 		if (op->flags & UWSGI_OPT_LOG_MASTER) {
502 			uwsgi.master_process = 1;
503 			uwsgi.log_master = 1;
504 		}
505 		if (op->flags & UWSGI_OPT_REQ_LOG_MASTER) {
506 			uwsgi.master_process = 1;
507 			uwsgi.log_master = 1;
508 			uwsgi.req_log_master = 1;
509 		}
510 		// requires threads ?
511 		if (op->flags & UWSGI_OPT_THREADS) {
512 			uwsgi.has_threads = 1;
513 		}
514 		// requires cheaper mode ?
515 		if (op->flags & UWSGI_OPT_CHEAPER) {
516 			uwsgi.cheaper = 1;
517 		}
518 		// requires virtualhosting ?
519 		if (op->flags & UWSGI_OPT_VHOST) {
520 			uwsgi.vhost = 1;
521 		}
522 		// requires memusage ?
523 		if (op->flags & UWSGI_OPT_MEMORY) {
524 			uwsgi.force_get_memusage = 1;
525 		}
526 		// requires auto procname ?
527 		if (op->flags & UWSGI_OPT_PROCNAME) {
528 			uwsgi.auto_procname = 1;
529 		}
530 		// requires lazy ?
531 		if (op->flags & UWSGI_OPT_LAZY) {
532 			uwsgi.lazy = 1;
533 		}
534 		// requires no_initial ?
535 		if (op->flags & UWSGI_OPT_NO_INITIAL) {
536 			uwsgi.no_initial_output = 1;
537 		}
538 		// requires no_server ?
539 		if (op->flags & UWSGI_OPT_NO_SERVER) {
540 			uwsgi.no_server = 1;
541 		}
542 		// requires post_buffering ?
543 		if (op->flags & UWSGI_OPT_POST_BUFFERING) {
544 			if (!uwsgi.post_buffering)
545 				uwsgi.post_buffering = 4096;
546 		}
547 		// requires building mime dict ?
548 		if (op->flags & UWSGI_OPT_MIME) {
549 			uwsgi.build_mime_dict = 1;
550 		}
551 		// enable metrics ?
552 		if (op->flags & UWSGI_OPT_METRICS) {
553                         uwsgi.has_metrics = 1;
554                 }
555 		// immediate ?
556 		if (op->flags & UWSGI_OPT_IMMEDIATE) {
557 			op->func(key, value, op->data);
558 			uwsgi.exported_opts[id]->configured = 1;
559 		}
560 	}
561 }
562 
uwsgi_fallback_config()563 void uwsgi_fallback_config() {
564 	if (uwsgi.fallback_config && uwsgi.last_exit_code == 1) {
565 		uwsgi_log_verbose("!!! %s (pid: %d) exited with status %d !!!\n", uwsgi.binary_path, (int) getpid(), uwsgi.last_exit_code);
566 		uwsgi_log_verbose("!!! Fallback config to %s !!!\n", uwsgi.fallback_config);
567 		char *argv[3];
568 		argv[0] = uwsgi.binary_path;
569 		argv[1] = uwsgi.fallback_config;
570 		argv[2] = NULL;
571         	execvp(uwsgi.binary_path, argv);
572         	uwsgi_error("execvp()");
573         	// never here
574 	}
575 }
576 
uwsgi_manage_opt(char * key,char * value)577 int uwsgi_manage_opt(char *key, char *value) {
578 
579         struct uwsgi_option *op = uwsgi_opt_get(key);
580 	if (op) {
581         	op->func(key, value, op->data);
582                 return 1;
583         }
584         return 0;
585 
586 }
587 
uwsgi_configure()588 void uwsgi_configure() {
589 
590         int i;
591 
592         // and now apply the remaining configs
593 restart:
594         for (i = 0; i < uwsgi.exported_opts_cnt; i++) {
595                 if (uwsgi.exported_opts[i]->configured)
596                         continue;
597                 uwsgi.dirty_config = 0;
598                 uwsgi.exported_opts[i]->configured = uwsgi_manage_opt(uwsgi.exported_opts[i]->key, uwsgi.exported_opts[i]->value);
599 		// some option could cause a dirty config tree
600                 if (uwsgi.dirty_config)
601                         goto restart;
602         }
603 
604 }
605 
606 
uwsgi_opt_custom(char * key,char * value,void * data)607 void uwsgi_opt_custom(char *key, char *value, void *data ) {
608         struct uwsgi_custom_option *uco = (struct uwsgi_custom_option *)data;
609         size_t i, count = 1;
610         size_t value_len = 0;
611         if (value)
612                 value_len = strlen(value);
613         off_t pos = 0;
614         char **opt_argv;
615         char *tmp_val = NULL, *p = NULL;
616 
617         // now count the number of args
618         for (i = 0; i < value_len; i++) {
619                 if (value[i] == ' ') {
620                         count++;
621                 }
622         }
623 
624         // allocate a tmp array
625         opt_argv = uwsgi_calloc(sizeof(char *) * count);
626         //make a copy of the value;
627         if (value_len > 0) {
628                 tmp_val = uwsgi_str(value);
629                 // fill the array of options
630                 char *p, *ctx = NULL;
631                 uwsgi_foreach_token(tmp_val, " ", p, ctx) {
632                         opt_argv[pos] = p;
633                         pos++;
634                 }
635         }
636         else {
637                 // no argument specified
638                 opt_argv[0] = "";
639         }
640 
641 #ifdef UWSGI_DEBUG
642         uwsgi_log("found custom option %s with %d args\n", key, count);
643 #endif
644 
645         // now make a copy of the option template
646         char *tmp_opt = uwsgi_str(uco->value);
647         // split it
648         char *ctx = NULL;
649         uwsgi_foreach_token(tmp_opt, ";", p, ctx) {
650                 char *equal = strchr(p, '=');
651                 if (!equal)
652                         goto clear;
653                 *equal = '\0';
654 
655                 // build the key
656                 char *new_key = uwsgi_str(p);
657                 for (i = 0; i < count; i++) {
658                         char *old_key = new_key;
659                         char *tmp_num = uwsgi_num2str(i + 1);
660                         char *placeholder = uwsgi_concat2((char *) "$", tmp_num);
661                         free(tmp_num);
662                         new_key = uwsgi_substitute(old_key, placeholder, opt_argv[i]);
663                         if (new_key != old_key)
664                                 free(old_key);
665                         free(placeholder);
666                 }
667 
668                 // build the value
669                 char *new_value = uwsgi_str(equal + 1);
670                 for (i = 0; i < count; i++) {
671                         char *old_value = new_value;
672                         char *tmp_num = uwsgi_num2str(i + 1);
673                         char *placeholder = uwsgi_concat2((char *) "$", tmp_num);
674                         free(tmp_num);
675                         new_value = uwsgi_substitute(old_value, placeholder, opt_argv[i]);
676                         if (new_value != old_value)
677                                 free(old_value);
678                         free(placeholder);
679                 }
680                 // ignore return value here
681                 uwsgi_manage_opt(new_key, new_value);
682         }
683 
684 clear:
685         free(tmp_val);
686         free(tmp_opt);
687         free(opt_argv);
688 
689 }
690 
uwsgi_get_exported_opt(char * key)691 char *uwsgi_get_exported_opt(char *key) {
692 
693         int i;
694 
695         for (i = 0; i < uwsgi.exported_opts_cnt; i++) {
696                 if (!strcmp(uwsgi.exported_opts[i]->key, key)) {
697                         return uwsgi.exported_opts[i]->value;
698                 }
699         }
700 
701         return NULL;
702 }
703 
uwsgi_get_optname_by_index(int index)704 char *uwsgi_get_optname_by_index(int index) {
705 
706         struct uwsgi_option *op = uwsgi.options;
707 
708         while (op->name) {
709                 if (op->shortcut == index) {
710                         return op->name;
711                 }
712                 op++;
713         }
714 
715         return NULL;
716 }
717 
718 /*
719 
720 	this works as a pipeline
721 
722 	processes = 2
723 	cpu_cores = 8
724 	foobar = %(processes cpu_cores + 2)
725 
726 	translate as:
727 
728 		step1 = proceses cpu_cores = 2 8 = 28 (string concatenation)
729 
730 		step1 + = step1_apply_func_plus (func token)
731 
732 		step1_apply_func_plus 2 = 28 + 2 = 30 (math)
733 
734 */
735 
uwsgi_manage_placeholder(char * key)736 char *uwsgi_manage_placeholder(char *key) {
737 	enum {
738 		concat = 0,
739 		sum,
740 		sub,
741 		mul,
742 		div,
743 	} state;
744 
745 	state = concat;
746 	char *current_value = NULL;
747 
748 	char *space = strchr(key, ' ');
749 	if (!space) {
750 		return uwsgi_get_exported_opt(key);
751 	}
752 	// let's start the heavy metal here
753 	char *tmp_value = uwsgi_str(key);
754 	char *p, *ctx = NULL;
755         uwsgi_foreach_token(tmp_value, " ", p, ctx) {
756 		char *value = NULL;
757 		if (is_a_number(p)) {
758 			value = uwsgi_str(p);
759 		}
760 		else if (!strcmp(p, "+")) {
761 			state = sum;
762 			continue;
763 		}
764 		else if (!strcmp(p, "-")) {
765 			state = sub;
766 			continue;
767 		}
768 		else if (!strcmp(p, "*")) {
769 			state = mul;
770 			continue;
771 		}
772 		else if (!strcmp(p, "/")) {
773 			state = div;
774 			continue;
775 		}
776 		else if (!strcmp(p, "++")) {
777 			if (current_value) {
778 				int64_t tmp_num = strtoll(current_value, NULL, 10);
779 				free(current_value);
780 				current_value = uwsgi_64bit2str(tmp_num+1);
781 			}
782 			state = concat;
783 			continue;
784 		}
785 		else if (!strcmp(p, "--")) {
786 			if (current_value) {
787 				int64_t tmp_num = strtoll(current_value, NULL, 10);
788 				free(current_value);
789 				current_value = uwsgi_64bit2str(tmp_num-1);
790 			}
791 			state = concat;
792 			continue;
793 		}
794 		// find the option
795 		else {
796 			char *ov = uwsgi_get_exported_opt(p);
797 			if (!ov) ov = "";
798 			value = uwsgi_str(ov);
799 		}
800 
801 		int64_t arg1n = 0, arg2n = 0;
802 		char *arg1 = "", *arg2 = "";
803 
804 		switch(state) {
805 			case concat:
806 				if (current_value) arg1 = current_value;
807 				if (value) arg2 = value;
808 				char *ret = uwsgi_concat2(arg1, arg2);
809 				if (current_value) free(current_value);
810 				current_value = ret;
811 				break;
812 			case sum:
813 				if (current_value) arg1n = strtoll(current_value, NULL, 10);
814 				if (value) arg2n = strtoll(value, NULL, 10);
815 				if (current_value) free(current_value);
816 				current_value = uwsgi_64bit2str(arg1n + arg2n);
817 				break;
818 			case sub:
819 				if (current_value) arg1n = strtoll(current_value, NULL, 10);
820 				if (value) arg2n = strtoll(value, NULL, 10);
821 				if (current_value) free(current_value);
822 				current_value = uwsgi_64bit2str(arg1n - arg2n);
823 				break;
824 			case mul:
825 				if (current_value) arg1n = strtoll(current_value, NULL, 10);
826 				if (value) arg2n = strtoll(value, NULL, 10);
827 				if (current_value) free(current_value);
828 				current_value = uwsgi_64bit2str(arg1n * arg2n);
829 				break;
830 			case div:
831 				if (current_value) arg1n = strtoll(current_value, NULL, 10);
832 				if (value) arg2n = strtoll(value, NULL, 10);
833 				if (current_value) free(current_value);
834 				// avoid division by zero
835 				if (arg2n == 0) {
836 					current_value = uwsgi_64bit2str(0);
837 				}
838 				else {
839 					current_value = uwsgi_64bit2str(arg1n / arg2n);
840 				}
841 				break;
842 			default:
843 				break;
844 		}
845 
846 		// over engineering
847 		if (value)
848 			free(value);
849 
850 		// reset state to concat
851 		state = concat;
852 	}
853 	free(tmp_value);
854 
855 	return current_value;
856 }
857 
uwsgi_opt_resolve(char * opt,char * value,void * foo)858 void uwsgi_opt_resolve(char *opt, char *value, void *foo) {
859         char *equal = strchr(value, '=');
860         if (!equal) {
861                 uwsgi_log("invalid resolve syntax, must be placeholder=domain\n");
862                 exit(1);
863         }
864         char *ip = uwsgi_resolve_ip(equal+1);
865         if (!ip) {
866 		uwsgi_log("unable to resolve name %s\n", equal+1);
867                 uwsgi_error("uwsgi_resolve_ip()");
868                 exit(1);
869         }
870         char *new_opt = uwsgi_concat2n(value, (equal-value)+1, ip, strlen(ip));
871         uwsgi_opt_set_placeholder(opt, new_opt, (void *) 1);
872 }
873