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