1 
2 /*
3  * Copyright (C) Igor Sysoev
4  * Copyright (C) Nginx, Inc.
5  */
6 
7 
8 #include <ngx_config.h>
9 #include <ngx_core.h>
10 
11 #define NGX_CONF_BUFFER  4096
12 
13 static ngx_int_t ngx_conf_add_dump(ngx_conf_t *cf, ngx_str_t *filename);
14 static ngx_int_t ngx_conf_handler(ngx_conf_t *cf, ngx_int_t last);
15 static ngx_int_t ngx_conf_read_token(ngx_conf_t *cf);
16 static void ngx_conf_flush_files(ngx_cycle_t *cycle);
17 
18 
19 static ngx_command_t  ngx_conf_commands[] = {
20 
21     { ngx_string("include"),
22       NGX_ANY_CONF|NGX_CONF_TAKE1,
23       ngx_conf_include,
24       0,
25       0,
26       NULL },
27 
28       ngx_null_command
29 };
30 
31 
32 ngx_module_t  ngx_conf_module = {
33     NGX_MODULE_V1,
34     NULL,                                  /* module context */
35     ngx_conf_commands,                     /* module directives */
36     NGX_CONF_MODULE,                       /* module type */
37     NULL,                                  /* init master */
38     NULL,                                  /* init module */
39     NULL,                                  /* init process */
40     NULL,                                  /* init thread */
41     NULL,                                  /* exit thread */
42     ngx_conf_flush_files,                  /* exit process */
43     NULL,                                  /* exit master */
44     NGX_MODULE_V1_PADDING
45 };
46 
47 
48 /* The eight fixed arguments */
49 
50 static ngx_uint_t argument_number[] = {
51     NGX_CONF_NOARGS,
52     NGX_CONF_TAKE1,
53     NGX_CONF_TAKE2,
54     NGX_CONF_TAKE3,
55     NGX_CONF_TAKE4,
56     NGX_CONF_TAKE5,
57     NGX_CONF_TAKE6,
58     NGX_CONF_TAKE7
59 };
60 
61 
62 char *
ngx_conf_param(ngx_conf_t * cf)63 ngx_conf_param(ngx_conf_t *cf)
64 {
65     char             *rv;
66     ngx_str_t        *param;
67     ngx_buf_t         b;
68     ngx_conf_file_t   conf_file;
69 
70     param = &cf->cycle->conf_param;
71 
72     if (param->len == 0) {
73         return NGX_CONF_OK;
74     }
75 
76     ngx_memzero(&conf_file, sizeof(ngx_conf_file_t));
77 
78     ngx_memzero(&b, sizeof(ngx_buf_t));
79 
80     b.start = param->data;
81     b.pos = param->data;
82     b.last = param->data + param->len;
83     b.end = b.last;
84     b.temporary = 1;
85 
86     conf_file.file.fd = NGX_INVALID_FILE;
87     conf_file.file.name.data = NULL;
88     conf_file.line = 0;
89 
90     cf->conf_file = &conf_file;
91     cf->conf_file->buffer = &b;
92 
93     rv = ngx_conf_parse(cf, NULL);
94 
95     cf->conf_file = NULL;
96 
97     return rv;
98 }
99 
100 
101 static ngx_int_t
ngx_conf_add_dump(ngx_conf_t * cf,ngx_str_t * filename)102 ngx_conf_add_dump(ngx_conf_t *cf, ngx_str_t *filename)
103 {
104     off_t             size;
105     u_char           *p;
106     uint32_t          hash;
107     ngx_buf_t        *buf;
108     ngx_str_node_t   *sn;
109     ngx_conf_dump_t  *cd;
110 
111     hash = ngx_crc32_long(filename->data, filename->len);
112 
113     sn = ngx_str_rbtree_lookup(&cf->cycle->config_dump_rbtree, filename, hash);
114 
115     if (sn) {
116         cf->conf_file->dump = NULL;
117         return NGX_OK;
118     }
119 
120     p = ngx_pstrdup(cf->cycle->pool, filename);
121     if (p == NULL) {
122         return NGX_ERROR;
123     }
124 
125     cd = ngx_array_push(&cf->cycle->config_dump);
126     if (cd == NULL) {
127         return NGX_ERROR;
128     }
129 
130     size = ngx_file_size(&cf->conf_file->file.info);
131 
132     buf = ngx_create_temp_buf(cf->cycle->pool, (size_t) size);
133     if (buf == NULL) {
134         return NGX_ERROR;
135     }
136 
137     cd->name.data = p;
138     cd->name.len = filename->len;
139     cd->buffer = buf;
140 
141     cf->conf_file->dump = buf;
142 
143     sn = ngx_palloc(cf->temp_pool, sizeof(ngx_str_node_t));
144     if (sn == NULL) {
145         return NGX_ERROR;
146     }
147 
148     sn->node.key = hash;
149     sn->str = cd->name;
150 
151     ngx_rbtree_insert(&cf->cycle->config_dump_rbtree, &sn->node);
152 
153     return NGX_OK;
154 }
155 
156 
157 char *
ngx_conf_parse(ngx_conf_t * cf,ngx_str_t * filename)158 ngx_conf_parse(ngx_conf_t *cf, ngx_str_t *filename)
159 {
160     char             *rv;
161     ngx_fd_t          fd;
162     ngx_int_t         rc;
163     ngx_buf_t         buf;
164     ngx_conf_file_t  *prev, conf_file;
165     enum {
166         parse_file = 0,
167         parse_block,
168         parse_param
169     } type;
170 
171 #if (NGX_SUPPRESS_WARN)
172     fd = NGX_INVALID_FILE;
173     prev = NULL;
174 #endif
175 
176     if (filename) {
177 
178         /* open configuration file */
179 
180         fd = ngx_open_file(filename->data, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0);
181 
182         if (fd == NGX_INVALID_FILE) {
183             ngx_conf_log_error(NGX_LOG_EMERG, cf, ngx_errno,
184                                ngx_open_file_n " \"%s\" failed",
185                                filename->data);
186             return NGX_CONF_ERROR;
187         }
188 
189         prev = cf->conf_file;
190 
191         cf->conf_file = &conf_file;
192 
193         if (ngx_fd_info(fd, &cf->conf_file->file.info) == NGX_FILE_ERROR) {
194             ngx_log_error(NGX_LOG_EMERG, cf->log, ngx_errno,
195                           ngx_fd_info_n " \"%s\" failed", filename->data);
196         }
197 
198         cf->conf_file->buffer = &buf;
199 
200         buf.start = ngx_alloc(NGX_CONF_BUFFER, cf->log);
201         if (buf.start == NULL) {
202             goto failed;
203         }
204 
205         buf.pos = buf.start;
206         buf.last = buf.start;
207         buf.end = buf.last + NGX_CONF_BUFFER;
208         buf.temporary = 1;
209 
210         cf->conf_file->file.fd = fd;
211         cf->conf_file->file.name.len = filename->len;
212         cf->conf_file->file.name.data = filename->data;
213         cf->conf_file->file.offset = 0;
214         cf->conf_file->file.log = cf->log;
215         cf->conf_file->line = 1;
216 
217         type = parse_file;
218 
219         if (ngx_dump_config
220 #if (NGX_DEBUG)
221             || 1
222 #endif
223            )
224         {
225             if (ngx_conf_add_dump(cf, filename) != NGX_OK) {
226                 goto failed;
227             }
228 
229         } else {
230             cf->conf_file->dump = NULL;
231         }
232 
233     } else if (cf->conf_file->file.fd != NGX_INVALID_FILE) {
234 
235         type = parse_block;
236 
237     } else {
238         type = parse_param;
239     }
240 
241 
242     for ( ;; ) {
243         rc = ngx_conf_read_token(cf);
244 
245         /*
246          * ngx_conf_read_token() may return
247          *
248          *    NGX_ERROR             there is error
249          *    NGX_OK                the token terminated by ";" was found
250          *    NGX_CONF_BLOCK_START  the token terminated by "{" was found
251          *    NGX_CONF_BLOCK_DONE   the "}" was found
252          *    NGX_CONF_FILE_DONE    the configuration file is done
253          */
254 
255         if (rc == NGX_ERROR) {
256             goto done;
257         }
258 
259         if (rc == NGX_CONF_BLOCK_DONE) {
260 
261             if (type != parse_block) {
262                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "unexpected \"}\"");
263                 goto failed;
264             }
265 
266             goto done;
267         }
268 
269         if (rc == NGX_CONF_FILE_DONE) {
270 
271             if (type == parse_block) {
272                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
273                                    "unexpected end of file, expecting \"}\"");
274                 goto failed;
275             }
276 
277             goto done;
278         }
279 
280         if (rc == NGX_CONF_BLOCK_START) {
281 
282             if (type == parse_param) {
283                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
284                                    "block directives are not supported "
285                                    "in -g option");
286                 goto failed;
287             }
288         }
289 
290         /* rc == NGX_OK || rc == NGX_CONF_BLOCK_START */
291 
292         if (cf->handler) {
293 
294             /*
295              * the custom handler, i.e., that is used in the http's
296              * "types { ... }" directive
297              */
298 
299             if (rc == NGX_CONF_BLOCK_START) {
300                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "unexpected \"{\"");
301                 goto failed;
302             }
303 
304             rv = (*cf->handler)(cf, NULL, cf->handler_conf);
305             if (rv == NGX_CONF_OK) {
306                 continue;
307             }
308 
309             if (rv == NGX_CONF_ERROR) {
310                 goto failed;
311             }
312 
313             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%s", rv);
314 
315             goto failed;
316         }
317 
318 
319         rc = ngx_conf_handler(cf, rc);
320 
321         if (rc == NGX_ERROR) {
322             goto failed;
323         }
324     }
325 
326 failed:
327 
328     rc = NGX_ERROR;
329 
330 done:
331 
332     if (filename) {
333         if (cf->conf_file->buffer->start) {
334             ngx_free(cf->conf_file->buffer->start);
335         }
336 
337         if (ngx_close_file(fd) == NGX_FILE_ERROR) {
338             ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno,
339                           ngx_close_file_n " %s failed",
340                           filename->data);
341             rc = NGX_ERROR;
342         }
343 
344         cf->conf_file = prev;
345     }
346 
347     if (rc == NGX_ERROR) {
348         return NGX_CONF_ERROR;
349     }
350 
351     return NGX_CONF_OK;
352 }
353 
354 
355 static ngx_int_t
ngx_conf_handler(ngx_conf_t * cf,ngx_int_t last)356 ngx_conf_handler(ngx_conf_t *cf, ngx_int_t last)
357 {
358     char           *rv;
359     void           *conf, **confp;
360     ngx_uint_t      i, found;
361     ngx_str_t      *name;
362     ngx_command_t  *cmd;
363 
364     name = cf->args->elts;
365 
366     found = 0;
367 
368     for (i = 0; cf->cycle->modules[i]; i++) {
369 
370         cmd = cf->cycle->modules[i]->commands;
371         if (cmd == NULL) {
372             continue;
373         }
374 
375         for ( /* void */ ; cmd->name.len; cmd++) {
376 
377             if (name->len != cmd->name.len) {
378                 continue;
379             }
380 
381             if (ngx_strcmp(name->data, cmd->name.data) != 0) {
382                 continue;
383             }
384 
385             found = 1;
386 
387             if (cf->cycle->modules[i]->type != NGX_CONF_MODULE
388                 && cf->cycle->modules[i]->type != cf->module_type)
389             {
390                 continue;
391             }
392 
393             /* is the directive's location right ? */
394 
395             if (!(cmd->type & cf->cmd_type)) {
396                 continue;
397             }
398 
399             if (!(cmd->type & NGX_CONF_BLOCK) && last != NGX_OK) {
400                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
401                                   "directive \"%s\" is not terminated by \";\"",
402                                   name->data);
403                 return NGX_ERROR;
404             }
405 
406             if ((cmd->type & NGX_CONF_BLOCK) && last != NGX_CONF_BLOCK_START) {
407                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
408                                    "directive \"%s\" has no opening \"{\"",
409                                    name->data);
410                 return NGX_ERROR;
411             }
412 
413             /* is the directive's argument count right ? */
414 
415             if (!(cmd->type & NGX_CONF_ANY)) {
416 
417                 if (cmd->type & NGX_CONF_FLAG) {
418 
419                     if (cf->args->nelts != 2) {
420                         goto invalid;
421                     }
422 
423                 } else if (cmd->type & NGX_CONF_1MORE) {
424 
425                     if (cf->args->nelts < 2) {
426                         goto invalid;
427                     }
428 
429                 } else if (cmd->type & NGX_CONF_2MORE) {
430 
431                     if (cf->args->nelts < 3) {
432                         goto invalid;
433                     }
434 
435                 } else if (cf->args->nelts > NGX_CONF_MAX_ARGS) {
436 
437                     goto invalid;
438 
439                 } else if (!(cmd->type & argument_number[cf->args->nelts - 1]))
440                 {
441                     goto invalid;
442                 }
443             }
444 
445             /* set up the directive's configuration context */
446 
447             conf = NULL;
448 
449             if (cmd->type & NGX_DIRECT_CONF) {
450                 conf = ((void **) cf->ctx)[cf->cycle->modules[i]->index];
451 
452             } else if (cmd->type & NGX_MAIN_CONF) {
453                 conf = &(((void **) cf->ctx)[cf->cycle->modules[i]->index]);
454 
455             } else if (cf->ctx) {
456                 confp = *(void **) ((char *) cf->ctx + cmd->conf);
457 
458                 if (confp) {
459                     conf = confp[cf->cycle->modules[i]->ctx_index];
460                 }
461             }
462 
463             rv = cmd->set(cf, cmd, conf);
464 
465             if (rv == NGX_CONF_OK) {
466                 return NGX_OK;
467             }
468 
469             if (rv == NGX_CONF_ERROR) {
470                 return NGX_ERROR;
471             }
472 
473             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
474                                "\"%s\" directive %s", name->data, rv);
475 
476             return NGX_ERROR;
477         }
478     }
479 
480     if (found) {
481         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
482                            "\"%s\" directive is not allowed here", name->data);
483 
484         return NGX_ERROR;
485     }
486 
487     ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
488                        "unknown directive \"%s\"", name->data);
489 
490     return NGX_ERROR;
491 
492 invalid:
493 
494     ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
495                        "invalid number of arguments in \"%s\" directive",
496                        name->data);
497 
498     return NGX_ERROR;
499 }
500 
501 
502 static ngx_int_t
ngx_conf_read_token(ngx_conf_t * cf)503 ngx_conf_read_token(ngx_conf_t *cf)
504 {
505     u_char      *start, ch, *src, *dst;
506     off_t        file_size;
507     size_t       len;
508     ssize_t      n, size;
509     ngx_uint_t   found, need_space, last_space, sharp_comment, variable;
510     ngx_uint_t   quoted, s_quoted, d_quoted, start_line;
511     ngx_str_t   *word;
512     ngx_buf_t   *b, *dump;
513 
514     found = 0;
515     need_space = 0;
516     last_space = 1;
517     sharp_comment = 0;
518     variable = 0;
519     quoted = 0;
520     s_quoted = 0;
521     d_quoted = 0;
522 
523     cf->args->nelts = 0;
524     b = cf->conf_file->buffer;
525     dump = cf->conf_file->dump;
526     start = b->pos;
527     start_line = cf->conf_file->line;
528 
529     file_size = ngx_file_size(&cf->conf_file->file.info);
530 
531     for ( ;; ) {
532 
533         if (b->pos >= b->last) {
534 
535             if (cf->conf_file->file.offset >= file_size) {
536 
537                 if (cf->args->nelts > 0 || !last_space) {
538 
539                     if (cf->conf_file->file.fd == NGX_INVALID_FILE) {
540                         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
541                                            "unexpected end of parameter, "
542                                            "expecting \";\"");
543                         return NGX_ERROR;
544                     }
545 
546                     ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
547                                   "unexpected end of file, "
548                                   "expecting \";\" or \"}\"");
549                     return NGX_ERROR;
550                 }
551 
552                 return NGX_CONF_FILE_DONE;
553             }
554 
555             len = b->pos - start;
556 
557             if (len == NGX_CONF_BUFFER) {
558                 cf->conf_file->line = start_line;
559 
560                 if (d_quoted) {
561                     ch = '"';
562 
563                 } else if (s_quoted) {
564                     ch = '\'';
565 
566                 } else {
567                     ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
568                                        "too long parameter \"%*s...\" started",
569                                        10, start);
570                     return NGX_ERROR;
571                 }
572 
573                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
574                                    "too long parameter, probably "
575                                    "missing terminating \"%c\" character", ch);
576                 return NGX_ERROR;
577             }
578 
579             if (len) {
580                 ngx_memmove(b->start, start, len);
581             }
582 
583             size = (ssize_t) (file_size - cf->conf_file->file.offset);
584 
585             if (size > b->end - (b->start + len)) {
586                 size = b->end - (b->start + len);
587             }
588 
589             n = ngx_read_file(&cf->conf_file->file, b->start + len, size,
590                               cf->conf_file->file.offset);
591 
592             if (n == NGX_ERROR) {
593                 return NGX_ERROR;
594             }
595 
596             if (n != size) {
597                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
598                                    ngx_read_file_n " returned "
599                                    "only %z bytes instead of %z",
600                                    n, size);
601                 return NGX_ERROR;
602             }
603 
604             b->pos = b->start + len;
605             b->last = b->pos + n;
606             start = b->start;
607 
608             if (dump) {
609                 dump->last = ngx_cpymem(dump->last, b->pos, size);
610             }
611         }
612 
613         ch = *b->pos++;
614 
615         if (ch == LF) {
616             cf->conf_file->line++;
617 
618             if (sharp_comment) {
619                 sharp_comment = 0;
620             }
621         }
622 
623         if (sharp_comment) {
624             continue;
625         }
626 
627         if (quoted) {
628             quoted = 0;
629             continue;
630         }
631 
632         if (need_space) {
633             if (ch == ' ' || ch == '\t' || ch == CR || ch == LF) {
634                 last_space = 1;
635                 need_space = 0;
636                 continue;
637             }
638 
639             if (ch == ';') {
640                 return NGX_OK;
641             }
642 
643             if (ch == '{') {
644                 return NGX_CONF_BLOCK_START;
645             }
646 
647             if (ch == ')') {
648                 last_space = 1;
649                 need_space = 0;
650 
651             } else {
652                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
653                                    "unexpected \"%c\"", ch);
654                 return NGX_ERROR;
655             }
656         }
657 
658         if (last_space) {
659 
660             start = b->pos - 1;
661             start_line = cf->conf_file->line;
662 
663             if (ch == ' ' || ch == '\t' || ch == CR || ch == LF) {
664                 continue;
665             }
666 
667             switch (ch) {
668 
669             case ';':
670             case '{':
671                 if (cf->args->nelts == 0) {
672                     ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
673                                        "unexpected \"%c\"", ch);
674                     return NGX_ERROR;
675                 }
676 
677                 if (ch == '{') {
678                     return NGX_CONF_BLOCK_START;
679                 }
680 
681                 return NGX_OK;
682 
683             case '}':
684                 if (cf->args->nelts != 0) {
685                     ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
686                                        "unexpected \"}\"");
687                     return NGX_ERROR;
688                 }
689 
690                 return NGX_CONF_BLOCK_DONE;
691 
692             case '#':
693                 sharp_comment = 1;
694                 continue;
695 
696             case '\\':
697                 quoted = 1;
698                 last_space = 0;
699                 continue;
700 
701             case '"':
702                 start++;
703                 d_quoted = 1;
704                 last_space = 0;
705                 continue;
706 
707             case '\'':
708                 start++;
709                 s_quoted = 1;
710                 last_space = 0;
711                 continue;
712 
713             case '$':
714                 variable = 1;
715                 last_space = 0;
716                 continue;
717 
718             default:
719                 last_space = 0;
720             }
721 
722         } else {
723             if (ch == '{' && variable) {
724                 continue;
725             }
726 
727             variable = 0;
728 
729             if (ch == '\\') {
730                 quoted = 1;
731                 continue;
732             }
733 
734             if (ch == '$') {
735                 variable = 1;
736                 continue;
737             }
738 
739             if (d_quoted) {
740                 if (ch == '"') {
741                     d_quoted = 0;
742                     need_space = 1;
743                     found = 1;
744                 }
745 
746             } else if (s_quoted) {
747                 if (ch == '\'') {
748                     s_quoted = 0;
749                     need_space = 1;
750                     found = 1;
751                 }
752 
753             } else if (ch == ' ' || ch == '\t' || ch == CR || ch == LF
754                        || ch == ';' || ch == '{')
755             {
756                 last_space = 1;
757                 found = 1;
758             }
759 
760             if (found) {
761                 word = ngx_array_push(cf->args);
762                 if (word == NULL) {
763                     return NGX_ERROR;
764                 }
765 
766                 word->data = ngx_pnalloc(cf->pool, b->pos - 1 - start + 1);
767                 if (word->data == NULL) {
768                     return NGX_ERROR;
769                 }
770 
771                 for (dst = word->data, src = start, len = 0;
772                      src < b->pos - 1;
773                      len++)
774                 {
775                     if (*src == '\\') {
776                         switch (src[1]) {
777                         case '"':
778                         case '\'':
779                         case '\\':
780                             src++;
781                             break;
782 
783                         case 't':
784                             *dst++ = '\t';
785                             src += 2;
786                             continue;
787 
788                         case 'r':
789                             *dst++ = '\r';
790                             src += 2;
791                             continue;
792 
793                         case 'n':
794                             *dst++ = '\n';
795                             src += 2;
796                             continue;
797                         }
798 
799                     }
800                     *dst++ = *src++;
801                 }
802                 *dst = '\0';
803                 word->len = len;
804 
805                 if (ch == ';') {
806                     return NGX_OK;
807                 }
808 
809                 if (ch == '{') {
810                     return NGX_CONF_BLOCK_START;
811                 }
812 
813                 found = 0;
814             }
815         }
816     }
817 }
818 
819 
820 char *
ngx_conf_include(ngx_conf_t * cf,ngx_command_t * cmd,void * conf)821 ngx_conf_include(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
822 {
823     char        *rv;
824     ngx_int_t    n;
825     ngx_str_t   *value, file, name;
826     ngx_glob_t   gl;
827 
828     value = cf->args->elts;
829     file = value[1];
830 
831     ngx_log_debug1(NGX_LOG_DEBUG_CORE, cf->log, 0, "include %s", file.data);
832 
833     if (ngx_conf_full_name(cf->cycle, &file, 1) != NGX_OK) {
834         return NGX_CONF_ERROR;
835     }
836 
837     if (strpbrk((char *) file.data, "*?[") == NULL) {
838 
839         ngx_log_debug1(NGX_LOG_DEBUG_CORE, cf->log, 0, "include %s", file.data);
840 
841         return ngx_conf_parse(cf, &file);
842     }
843 
844     ngx_memzero(&gl, sizeof(ngx_glob_t));
845 
846     gl.pattern = file.data;
847     gl.log = cf->log;
848     gl.test = 1;
849 
850     if (ngx_open_glob(&gl) != NGX_OK) {
851         ngx_conf_log_error(NGX_LOG_EMERG, cf, ngx_errno,
852                            ngx_open_glob_n " \"%s\" failed", file.data);
853         return NGX_CONF_ERROR;
854     }
855 
856     rv = NGX_CONF_OK;
857 
858     for ( ;; ) {
859         n = ngx_read_glob(&gl, &name);
860 
861         if (n != NGX_OK) {
862             break;
863         }
864 
865         file.len = name.len++;
866         file.data = ngx_pstrdup(cf->pool, &name);
867         if (file.data == NULL) {
868             return NGX_CONF_ERROR;
869         }
870 
871         ngx_log_debug1(NGX_LOG_DEBUG_CORE, cf->log, 0, "include %s", file.data);
872 
873         rv = ngx_conf_parse(cf, &file);
874 
875         if (rv != NGX_CONF_OK) {
876             break;
877         }
878     }
879 
880     ngx_close_glob(&gl);
881 
882     return rv;
883 }
884 
885 
886 ngx_int_t
ngx_conf_full_name(ngx_cycle_t * cycle,ngx_str_t * name,ngx_uint_t conf_prefix)887 ngx_conf_full_name(ngx_cycle_t *cycle, ngx_str_t *name, ngx_uint_t conf_prefix)
888 {
889     ngx_str_t  *prefix;
890 
891     prefix = conf_prefix ? &cycle->conf_prefix : &cycle->prefix;
892 
893     return ngx_get_full_name(cycle->pool, prefix, name);
894 }
895 
896 
897 ngx_open_file_t *
ngx_conf_open_file(ngx_cycle_t * cycle,ngx_str_t * name)898 ngx_conf_open_file(ngx_cycle_t *cycle, ngx_str_t *name)
899 {
900     ngx_str_t         full;
901     ngx_uint_t        i;
902     ngx_list_part_t  *part;
903     ngx_open_file_t  *file;
904 
905 #if (NGX_SUPPRESS_WARN)
906     ngx_str_null(&full);
907 #endif
908 
909     if (name->len) {
910         full = *name;
911 
912         if (ngx_conf_full_name(cycle, &full, 0) != NGX_OK) {
913             return NULL;
914         }
915 
916         part = &cycle->open_files.part;
917         file = part->elts;
918 
919         for (i = 0; /* void */ ; i++) {
920 
921             if (i >= part->nelts) {
922                 if (part->next == NULL) {
923                     break;
924                 }
925                 part = part->next;
926                 file = part->elts;
927                 i = 0;
928             }
929 
930             if (full.len != file[i].name.len) {
931                 continue;
932             }
933 
934             if (ngx_strcmp(full.data, file[i].name.data) == 0) {
935                 return &file[i];
936             }
937         }
938     }
939 
940     file = ngx_list_push(&cycle->open_files);
941     if (file == NULL) {
942         return NULL;
943     }
944 
945     if (name->len) {
946         file->fd = NGX_INVALID_FILE;
947         file->name = full;
948 
949     } else {
950         file->fd = ngx_stderr;
951         file->name = *name;
952     }
953 
954     file->flush = NULL;
955     file->data = NULL;
956 
957     return file;
958 }
959 
960 
961 static void
ngx_conf_flush_files(ngx_cycle_t * cycle)962 ngx_conf_flush_files(ngx_cycle_t *cycle)
963 {
964     ngx_uint_t        i;
965     ngx_list_part_t  *part;
966     ngx_open_file_t  *file;
967 
968     ngx_log_debug0(NGX_LOG_DEBUG_CORE, cycle->log, 0, "flush files");
969 
970     part = &cycle->open_files.part;
971     file = part->elts;
972 
973     for (i = 0; /* void */ ; i++) {
974 
975         if (i >= part->nelts) {
976             if (part->next == NULL) {
977                 break;
978             }
979             part = part->next;
980             file = part->elts;
981             i = 0;
982         }
983 
984         if (file[i].flush) {
985             file[i].flush(&file[i], cycle->log);
986         }
987     }
988 }
989 
990 
991 void ngx_cdecl
ngx_conf_log_error(ngx_uint_t level,ngx_conf_t * cf,ngx_err_t err,const char * fmt,...)992 ngx_conf_log_error(ngx_uint_t level, ngx_conf_t *cf, ngx_err_t err,
993     const char *fmt, ...)
994 {
995     u_char   errstr[NGX_MAX_CONF_ERRSTR], *p, *last;
996     va_list  args;
997 
998     last = errstr + NGX_MAX_CONF_ERRSTR;
999 
1000     va_start(args, fmt);
1001     p = ngx_vslprintf(errstr, last, fmt, args);
1002     va_end(args);
1003 
1004     if (err) {
1005         p = ngx_log_errno(p, last, err);
1006     }
1007 
1008     if (cf->conf_file == NULL) {
1009         ngx_log_error(level, cf->log, 0, "%*s", p - errstr, errstr);
1010         return;
1011     }
1012 
1013     if (cf->conf_file->file.fd == NGX_INVALID_FILE) {
1014         ngx_log_error(level, cf->log, 0, "%*s in command line",
1015                       p - errstr, errstr);
1016         return;
1017     }
1018 
1019     ngx_log_error(level, cf->log, 0, "%*s in %s:%ui",
1020                   p - errstr, errstr,
1021                   cf->conf_file->file.name.data, cf->conf_file->line);
1022 }
1023 
1024 
1025 char *
ngx_conf_set_flag_slot(ngx_conf_t * cf,ngx_command_t * cmd,void * conf)1026 ngx_conf_set_flag_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
1027 {
1028     char  *p = conf;
1029 
1030     ngx_str_t        *value;
1031     ngx_flag_t       *fp;
1032     ngx_conf_post_t  *post;
1033 
1034     fp = (ngx_flag_t *) (p + cmd->offset);
1035 
1036     if (*fp != NGX_CONF_UNSET) {
1037         return "is duplicate";
1038     }
1039 
1040     value = cf->args->elts;
1041 
1042     if (ngx_strcasecmp(value[1].data, (u_char *) "on") == 0) {
1043         *fp = 1;
1044 
1045     } else if (ngx_strcasecmp(value[1].data, (u_char *) "off") == 0) {
1046         *fp = 0;
1047 
1048     } else {
1049         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1050                      "invalid value \"%s\" in \"%s\" directive, "
1051                      "it must be \"on\" or \"off\"",
1052                      value[1].data, cmd->name.data);
1053         return NGX_CONF_ERROR;
1054     }
1055 
1056     if (cmd->post) {
1057         post = cmd->post;
1058         return post->post_handler(cf, post, fp);
1059     }
1060 
1061     return NGX_CONF_OK;
1062 }
1063 
1064 
1065 char *
ngx_conf_set_str_slot(ngx_conf_t * cf,ngx_command_t * cmd,void * conf)1066 ngx_conf_set_str_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
1067 {
1068     char  *p = conf;
1069 
1070     ngx_str_t        *field, *value;
1071     ngx_conf_post_t  *post;
1072 
1073     field = (ngx_str_t *) (p + cmd->offset);
1074 
1075     if (field->data) {
1076         return "is duplicate";
1077     }
1078 
1079     value = cf->args->elts;
1080 
1081     *field = value[1];
1082 
1083     if (cmd->post) {
1084         post = cmd->post;
1085         return post->post_handler(cf, post, field);
1086     }
1087 
1088     return NGX_CONF_OK;
1089 }
1090 
1091 
1092 char *
ngx_conf_set_str_array_slot(ngx_conf_t * cf,ngx_command_t * cmd,void * conf)1093 ngx_conf_set_str_array_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
1094 {
1095     char  *p = conf;
1096 
1097     ngx_str_t         *value, *s;
1098     ngx_array_t      **a;
1099     ngx_conf_post_t   *post;
1100 
1101     a = (ngx_array_t **) (p + cmd->offset);
1102 
1103     if (*a == NGX_CONF_UNSET_PTR) {
1104         *a = ngx_array_create(cf->pool, 4, sizeof(ngx_str_t));
1105         if (*a == NULL) {
1106             return NGX_CONF_ERROR;
1107         }
1108     }
1109 
1110     s = ngx_array_push(*a);
1111     if (s == NULL) {
1112         return NGX_CONF_ERROR;
1113     }
1114 
1115     value = cf->args->elts;
1116 
1117     *s = value[1];
1118 
1119     if (cmd->post) {
1120         post = cmd->post;
1121         return post->post_handler(cf, post, s);
1122     }
1123 
1124     return NGX_CONF_OK;
1125 }
1126 
1127 
1128 char *
ngx_conf_set_keyval_slot(ngx_conf_t * cf,ngx_command_t * cmd,void * conf)1129 ngx_conf_set_keyval_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
1130 {
1131     char  *p = conf;
1132 
1133     ngx_str_t         *value;
1134     ngx_array_t      **a;
1135     ngx_keyval_t      *kv;
1136     ngx_conf_post_t   *post;
1137 
1138     a = (ngx_array_t **) (p + cmd->offset);
1139 
1140     if (*a == NULL) {
1141         *a = ngx_array_create(cf->pool, 4, sizeof(ngx_keyval_t));
1142         if (*a == NULL) {
1143             return NGX_CONF_ERROR;
1144         }
1145     }
1146 
1147     kv = ngx_array_push(*a);
1148     if (kv == NULL) {
1149         return NGX_CONF_ERROR;
1150     }
1151 
1152     value = cf->args->elts;
1153 
1154     kv->key = value[1];
1155     kv->value = value[2];
1156 
1157     if (cmd->post) {
1158         post = cmd->post;
1159         return post->post_handler(cf, post, kv);
1160     }
1161 
1162     return NGX_CONF_OK;
1163 }
1164 
1165 
1166 char *
ngx_conf_set_num_slot(ngx_conf_t * cf,ngx_command_t * cmd,void * conf)1167 ngx_conf_set_num_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
1168 {
1169     char  *p = conf;
1170 
1171     ngx_int_t        *np;
1172     ngx_str_t        *value;
1173     ngx_conf_post_t  *post;
1174 
1175 
1176     np = (ngx_int_t *) (p + cmd->offset);
1177 
1178     if (*np != NGX_CONF_UNSET) {
1179         return "is duplicate";
1180     }
1181 
1182     value = cf->args->elts;
1183     *np = ngx_atoi(value[1].data, value[1].len);
1184     if (*np == NGX_ERROR) {
1185         return "invalid number";
1186     }
1187 
1188     if (cmd->post) {
1189         post = cmd->post;
1190         return post->post_handler(cf, post, np);
1191     }
1192 
1193     return NGX_CONF_OK;
1194 }
1195 
1196 
1197 char *
ngx_conf_set_size_slot(ngx_conf_t * cf,ngx_command_t * cmd,void * conf)1198 ngx_conf_set_size_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
1199 {
1200     char  *p = conf;
1201 
1202     size_t           *sp;
1203     ngx_str_t        *value;
1204     ngx_conf_post_t  *post;
1205 
1206 
1207     sp = (size_t *) (p + cmd->offset);
1208     if (*sp != NGX_CONF_UNSET_SIZE) {
1209         return "is duplicate";
1210     }
1211 
1212     value = cf->args->elts;
1213 
1214     *sp = ngx_parse_size(&value[1]);
1215     if (*sp == (size_t) NGX_ERROR) {
1216         return "invalid value";
1217     }
1218 
1219     if (cmd->post) {
1220         post = cmd->post;
1221         return post->post_handler(cf, post, sp);
1222     }
1223 
1224     return NGX_CONF_OK;
1225 }
1226 
1227 
1228 char *
ngx_conf_set_off_slot(ngx_conf_t * cf,ngx_command_t * cmd,void * conf)1229 ngx_conf_set_off_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
1230 {
1231     char  *p = conf;
1232 
1233     off_t            *op;
1234     ngx_str_t        *value;
1235     ngx_conf_post_t  *post;
1236 
1237 
1238     op = (off_t *) (p + cmd->offset);
1239     if (*op != NGX_CONF_UNSET) {
1240         return "is duplicate";
1241     }
1242 
1243     value = cf->args->elts;
1244 
1245     *op = ngx_parse_offset(&value[1]);
1246     if (*op == (off_t) NGX_ERROR) {
1247         return "invalid value";
1248     }
1249 
1250     if (cmd->post) {
1251         post = cmd->post;
1252         return post->post_handler(cf, post, op);
1253     }
1254 
1255     return NGX_CONF_OK;
1256 }
1257 
1258 
1259 char *
ngx_conf_set_msec_slot(ngx_conf_t * cf,ngx_command_t * cmd,void * conf)1260 ngx_conf_set_msec_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
1261 {
1262     char  *p = conf;
1263 
1264     ngx_msec_t       *msp;
1265     ngx_str_t        *value;
1266     ngx_conf_post_t  *post;
1267 
1268 
1269     msp = (ngx_msec_t *) (p + cmd->offset);
1270     if (*msp != NGX_CONF_UNSET_MSEC) {
1271         return "is duplicate";
1272     }
1273 
1274     value = cf->args->elts;
1275 
1276     *msp = ngx_parse_time(&value[1], 0);
1277     if (*msp == (ngx_msec_t) NGX_ERROR) {
1278         return "invalid value";
1279     }
1280 
1281     if (cmd->post) {
1282         post = cmd->post;
1283         return post->post_handler(cf, post, msp);
1284     }
1285 
1286     return NGX_CONF_OK;
1287 }
1288 
1289 
1290 char *
ngx_conf_set_sec_slot(ngx_conf_t * cf,ngx_command_t * cmd,void * conf)1291 ngx_conf_set_sec_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
1292 {
1293     char  *p = conf;
1294 
1295     time_t           *sp;
1296     ngx_str_t        *value;
1297     ngx_conf_post_t  *post;
1298 
1299 
1300     sp = (time_t *) (p + cmd->offset);
1301     if (*sp != NGX_CONF_UNSET) {
1302         return "is duplicate";
1303     }
1304 
1305     value = cf->args->elts;
1306 
1307     *sp = ngx_parse_time(&value[1], 1);
1308     if (*sp == (time_t) NGX_ERROR) {
1309         return "invalid value";
1310     }
1311 
1312     if (cmd->post) {
1313         post = cmd->post;
1314         return post->post_handler(cf, post, sp);
1315     }
1316 
1317     return NGX_CONF_OK;
1318 }
1319 
1320 
1321 char *
ngx_conf_set_bufs_slot(ngx_conf_t * cf,ngx_command_t * cmd,void * conf)1322 ngx_conf_set_bufs_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
1323 {
1324     char *p = conf;
1325 
1326     ngx_str_t   *value;
1327     ngx_bufs_t  *bufs;
1328 
1329 
1330     bufs = (ngx_bufs_t *) (p + cmd->offset);
1331     if (bufs->num) {
1332         return "is duplicate";
1333     }
1334 
1335     value = cf->args->elts;
1336 
1337     bufs->num = ngx_atoi(value[1].data, value[1].len);
1338     if (bufs->num == NGX_ERROR || bufs->num == 0) {
1339         return "invalid value";
1340     }
1341 
1342     bufs->size = ngx_parse_size(&value[2]);
1343     if (bufs->size == (size_t) NGX_ERROR || bufs->size == 0) {
1344         return "invalid value";
1345     }
1346 
1347     return NGX_CONF_OK;
1348 }
1349 
1350 
1351 char *
ngx_conf_set_enum_slot(ngx_conf_t * cf,ngx_command_t * cmd,void * conf)1352 ngx_conf_set_enum_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
1353 {
1354     char  *p = conf;
1355 
1356     ngx_uint_t       *np, i;
1357     ngx_str_t        *value;
1358     ngx_conf_enum_t  *e;
1359 
1360     np = (ngx_uint_t *) (p + cmd->offset);
1361 
1362     if (*np != NGX_CONF_UNSET_UINT) {
1363         return "is duplicate";
1364     }
1365 
1366     value = cf->args->elts;
1367     e = cmd->post;
1368 
1369     for (i = 0; e[i].name.len != 0; i++) {
1370         if (e[i].name.len != value[1].len
1371             || ngx_strcasecmp(e[i].name.data, value[1].data) != 0)
1372         {
1373             continue;
1374         }
1375 
1376         *np = e[i].value;
1377 
1378         return NGX_CONF_OK;
1379     }
1380 
1381     ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1382                        "invalid value \"%s\"", value[1].data);
1383 
1384     return NGX_CONF_ERROR;
1385 }
1386 
1387 
1388 char *
ngx_conf_set_bitmask_slot(ngx_conf_t * cf,ngx_command_t * cmd,void * conf)1389 ngx_conf_set_bitmask_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
1390 {
1391     char  *p = conf;
1392 
1393     ngx_uint_t          *np, i, m;
1394     ngx_str_t           *value;
1395     ngx_conf_bitmask_t  *mask;
1396 
1397 
1398     np = (ngx_uint_t *) (p + cmd->offset);
1399     value = cf->args->elts;
1400     mask = cmd->post;
1401 
1402     for (i = 1; i < cf->args->nelts; i++) {
1403         for (m = 0; mask[m].name.len != 0; m++) {
1404 
1405             if (mask[m].name.len != value[i].len
1406                 || ngx_strcasecmp(mask[m].name.data, value[i].data) != 0)
1407             {
1408                 continue;
1409             }
1410 
1411             if (*np & mask[m].mask) {
1412                 ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
1413                                    "duplicate value \"%s\"", value[i].data);
1414 
1415             } else {
1416                 *np |= mask[m].mask;
1417             }
1418 
1419             break;
1420         }
1421 
1422         if (mask[m].name.len == 0) {
1423             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1424                                "invalid value \"%s\"", value[i].data);
1425 
1426             return NGX_CONF_ERROR;
1427         }
1428     }
1429 
1430     return NGX_CONF_OK;
1431 }
1432 
1433 
1434 #if 0
1435 
1436 char *
1437 ngx_conf_unsupported(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
1438 {
1439     return "unsupported on this platform";
1440 }
1441 
1442 #endif
1443 
1444 
1445 char *
ngx_conf_deprecated(ngx_conf_t * cf,void * post,void * data)1446 ngx_conf_deprecated(ngx_conf_t *cf, void *post, void *data)
1447 {
1448     ngx_conf_deprecated_t  *d = post;
1449 
1450     ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
1451                        "the \"%s\" directive is deprecated, "
1452                        "use the \"%s\" directive instead",
1453                        d->old_name, d->new_name);
1454 
1455     return NGX_CONF_OK;
1456 }
1457 
1458 
1459 char *
ngx_conf_check_num_bounds(ngx_conf_t * cf,void * post,void * data)1460 ngx_conf_check_num_bounds(ngx_conf_t *cf, void *post, void *data)
1461 {
1462     ngx_conf_num_bounds_t  *bounds = post;
1463     ngx_int_t  *np = data;
1464 
1465     if (bounds->high == -1) {
1466         if (*np >= bounds->low) {
1467             return NGX_CONF_OK;
1468         }
1469 
1470         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1471                            "value must be equal to or greater than %i",
1472                            bounds->low);
1473 
1474         return NGX_CONF_ERROR;
1475     }
1476 
1477     if (*np >= bounds->low && *np <= bounds->high) {
1478         return NGX_CONF_OK;
1479     }
1480 
1481     ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1482                        "value must be between %i and %i",
1483                        bounds->low, bounds->high);
1484 
1485     return NGX_CONF_ERROR;
1486 }
1487