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