src/core/ngx_conf_file.c - nginx source code

Global variables defined

Data types defined

Functions defined

Macros defined

Source code


  1. /*
  2. * Copyright (C) Igor Sysoev
  3. * Copyright (C) Nginx, Inc.
  4. */


  5. #include <ngx_config.h>
  6. #include <ngx_core.h>

  7. #define NGX_CONF_BUFFER  4096

  8. static ngx_int_t ngx_conf_add_dump(ngx_conf_t *cf, ngx_str_t *filename);
  9. static ngx_int_t ngx_conf_handler(ngx_conf_t *cf, ngx_int_t last);
  10. static ngx_int_t ngx_conf_read_token(ngx_conf_t *cf);
  11. static void ngx_conf_flush_files(ngx_cycle_t *cycle);


  12. static ngx_command_t  ngx_conf_commands[] = {

  13.     { ngx_string("include"),
  14.       NGX_ANY_CONF|NGX_CONF_TAKE1,
  15.       ngx_conf_include,
  16.       0,
  17.       0,
  18.       NULL },

  19.       ngx_null_command
  20. };


  21. ngx_module_t  ngx_conf_module = {
  22.     NGX_MODULE_V1,
  23.     NULL,                                  /* module context */
  24.     ngx_conf_commands,                     /* module directives */
  25.     NGX_CONF_MODULE,                       /* module type */
  26.     NULL,                                  /* init master */
  27.     NULL,                                  /* init module */
  28.     NULL,                                  /* init process */
  29.     NULL,                                  /* init thread */
  30.     NULL,                                  /* exit thread */
  31.     ngx_conf_flush_files,                  /* exit process */
  32.     NULL,                                  /* exit master */
  33.     NGX_MODULE_V1_PADDING
  34. };


  35. /* The eight fixed arguments */

  36. static ngx_uint_t argument_number[] = {
  37.     NGX_CONF_NOARGS,
  38.     NGX_CONF_TAKE1,
  39.     NGX_CONF_TAKE2,
  40.     NGX_CONF_TAKE3,
  41.     NGX_CONF_TAKE4,
  42.     NGX_CONF_TAKE5,
  43.     NGX_CONF_TAKE6,
  44.     NGX_CONF_TAKE7
  45. };


  46. char *
  47. ngx_conf_param(ngx_conf_t *cf)
  48. {
  49.     char             *rv;
  50.     ngx_str_t        *param;
  51.     ngx_buf_t         b;
  52.     ngx_conf_file_t   conf_file;

  53.     param = &cf->cycle->conf_param;

  54.     if (param->len == 0) {
  55.         return NGX_CONF_OK;
  56.     }

  57.     ngx_memzero(&conf_file, sizeof(ngx_conf_file_t));

  58.     ngx_memzero(&b, sizeof(ngx_buf_t));

  59.     b.start = param->data;
  60.     b.pos = param->data;
  61.     b.last = param->data + param->len;
  62.     b.end = b.last;
  63.     b.temporary = 1;

  64.     conf_file.file.fd = NGX_INVALID_FILE;
  65.     conf_file.file.name.data = NULL;
  66.     conf_file.line = 0;

  67.     cf->conf_file = &conf_file;
  68.     cf->conf_file->buffer = &b;

  69.     rv = ngx_conf_parse(cf, NULL);

  70.     cf->conf_file = NULL;

  71.     return rv;
  72. }


  73. static ngx_int_t
  74. ngx_conf_add_dump(ngx_conf_t *cf, ngx_str_t *filename)
  75. {
  76.     off_t             size;
  77.     u_char           *p;
  78.     uint32_t          hash;
  79.     ngx_buf_t        *buf;
  80.     ngx_str_node_t   *sn;
  81.     ngx_conf_dump_t  *cd;

  82.     hash = ngx_crc32_long(filename->data, filename->len);

  83.     sn = ngx_str_rbtree_lookup(&cf->cycle->config_dump_rbtree, filename, hash);

  84.     if (sn) {
  85.         cf->conf_file->dump = NULL;
  86.         return NGX_OK;
  87.     }

  88.     p = ngx_pstrdup(cf->cycle->pool, filename);
  89.     if (p == NULL) {
  90.         return NGX_ERROR;
  91.     }

  92.     cd = ngx_array_push(&cf->cycle->config_dump);
  93.     if (cd == NULL) {
  94.         return NGX_ERROR;
  95.     }

  96.     size = ngx_file_size(&cf->conf_file->file.info);

  97.     buf = ngx_create_temp_buf(cf->cycle->pool, (size_t) size);
  98.     if (buf == NULL) {
  99.         return NGX_ERROR;
  100.     }

  101.     cd->name.data = p;
  102.     cd->name.len = filename->len;
  103.     cd->buffer = buf;

  104.     cf->conf_file->dump = buf;

  105.     sn = ngx_palloc(cf->temp_pool, sizeof(ngx_str_node_t));
  106.     if (sn == NULL) {
  107.         return NGX_ERROR;
  108.     }

  109.     sn->node.key = hash;
  110.     sn->str = cd->name;

  111.     ngx_rbtree_insert(&cf->cycle->config_dump_rbtree, &sn->node);

  112.     return NGX_OK;
  113. }


  114. char *
  115. ngx_conf_parse(ngx_conf_t *cf, ngx_str_t *filename)
  116. {
  117.     char             *rv;
  118.     ngx_fd_t          fd;
  119.     ngx_int_t         rc;
  120.     ngx_buf_t         buf;
  121.     ngx_conf_file_t  *prev, conf_file;
  122.     enum {
  123.         parse_file = 0,
  124.         parse_block,
  125.         parse_param
  126.     } type;

  127. #if (NGX_SUPPRESS_WARN)
  128.     fd = NGX_INVALID_FILE;
  129.     prev = NULL;
  130. #endif

  131.     if (filename) {

  132.         /* open configuration file */

  133.         fd = ngx_open_file(filename->data, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0);

  134.         if (fd == NGX_INVALID_FILE) {
  135.             ngx_conf_log_error(NGX_LOG_EMERG, cf, ngx_errno,
  136.                                ngx_open_file_n " \"%s\" failed",
  137.                                filename->data);
  138.             return NGX_CONF_ERROR;
  139.         }

  140.         prev = cf->conf_file;

  141.         cf->conf_file = &conf_file;

  142.         if (ngx_fd_info(fd, &cf->conf_file->file.info) == NGX_FILE_ERROR) {
  143.             ngx_log_error(NGX_LOG_EMERG, cf->log, ngx_errno,
  144.                           ngx_fd_info_n " \"%s\" failed", filename->data);
  145.         }

  146.         cf->conf_file->buffer = &buf;

  147.         buf.start = ngx_alloc(NGX_CONF_BUFFER, cf->log);
  148.         if (buf.start == NULL) {
  149.             goto failed;
  150.         }

  151.         buf.pos = buf.start;
  152.         buf.last = buf.start;
  153.         buf.end = buf.last + NGX_CONF_BUFFER;
  154.         buf.temporary = 1;

  155.         cf->conf_file->file.fd = fd;
  156.         cf->conf_file->file.name.len = filename->len;
  157.         cf->conf_file->file.name.data = filename->data;
  158.         cf->conf_file->file.offset = 0;
  159.         cf->conf_file->file.log = cf->log;
  160.         cf->conf_file->line = 1;

  161.         type = parse_file;

  162.         if (ngx_dump_config
  163. #if (NGX_DEBUG)
  164.             || 1
  165. #endif
  166.            )
  167.         {
  168.             if (ngx_conf_add_dump(cf, filename) != NGX_OK) {
  169.                 goto failed;
  170.             }

  171.         } else {
  172.             cf->conf_file->dump = NULL;
  173.         }

  174.     } else if (cf->conf_file->file.fd != NGX_INVALID_FILE) {

  175.         type = parse_block;

  176.     } else {
  177.         type = parse_param;
  178.     }


  179.     for ( ;; ) {
  180.         rc = ngx_conf_read_token(cf);

  181.         /*
  182.          * ngx_conf_read_token() may return
  183.          *
  184.          *    NGX_ERROR             there is error
  185.          *    NGX_OK                the token terminated by ";" was found
  186.          *    NGX_CONF_BLOCK_START  the token terminated by "{" was found
  187.          *    NGX_CONF_BLOCK_DONE   the "}" was found
  188.          *    NGX_CONF_FILE_DONE    the configuration file is done
  189.          */

  190.         if (rc == NGX_ERROR) {
  191.             goto done;
  192.         }

  193.         if (rc == NGX_CONF_BLOCK_DONE) {

  194.             if (type != parse_block) {
  195.                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "unexpected \"}\"");
  196.                 goto failed;
  197.             }

  198.             goto done;
  199.         }

  200.         if (rc == NGX_CONF_FILE_DONE) {

  201.             if (type == parse_block) {
  202.                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  203.                                    "unexpected end of file, expecting \"}\"");
  204.                 goto failed;
  205.             }

  206.             goto done;
  207.         }

  208.         if (rc == NGX_CONF_BLOCK_START) {

  209.             if (type == parse_param) {
  210.                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  211.                                    "block directives are not supported "
  212.                                    "in -g option");
  213.                 goto failed;
  214.             }
  215.         }

  216.         /* rc == NGX_OK || rc == NGX_CONF_BLOCK_START */

  217.         if (cf->handler) {

  218.             /*
  219.              * the custom handler, i.e., that is used in the http's
  220.              * "types { ... }" directive
  221.              */

  222.             if (rc == NGX_CONF_BLOCK_START) {
  223.                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "unexpected \"{\"");
  224.                 goto failed;
  225.             }

  226.             rv = (*cf->handler)(cf, NULL, cf->handler_conf);
  227.             if (rv == NGX_CONF_OK) {
  228.                 continue;
  229.             }

  230.             if (rv == NGX_CONF_ERROR) {
  231.                 goto failed;
  232.             }

  233.             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%s", rv);

  234.             goto failed;
  235.         }


  236.         rc = ngx_conf_handler(cf, rc);

  237.         if (rc == NGX_ERROR) {
  238.             goto failed;
  239.         }
  240.     }

  241. failed:

  242.     rc = NGX_ERROR;

  243. done:

  244.     if (filename) {
  245.         if (cf->conf_file->buffer->start) {
  246.             ngx_free(cf->conf_file->buffer->start);
  247.         }

  248.         if (ngx_close_file(fd) == NGX_FILE_ERROR) {
  249.             ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno,
  250.                           ngx_close_file_n " %s failed",
  251.                           filename->data);
  252.             rc = NGX_ERROR;
  253.         }

  254.         cf->conf_file = prev;
  255.     }

  256.     if (rc == NGX_ERROR) {
  257.         return NGX_CONF_ERROR;
  258.     }

  259.     return NGX_CONF_OK;
  260. }


  261. static ngx_int_t
  262. ngx_conf_handler(ngx_conf_t *cf, ngx_int_t last)
  263. {
  264.     char           *rv;
  265.     void           *conf, **confp;
  266.     ngx_uint_t      i, found;
  267.     ngx_str_t      *name;
  268.     ngx_command_t  *cmd;

  269.     name = cf->args->elts;

  270.     found = 0;

  271.     for (i = 0; cf->cycle->modules[i]; i++) {

  272.         cmd = cf->cycle->modules[i]->commands;
  273.         if (cmd == NULL) {
  274.             continue;
  275.         }

  276.         for ( /* void */ ; cmd->name.len; cmd++) {

  277.             if (name->len != cmd->name.len) {
  278.                 continue;
  279.             }

  280.             if (ngx_strcmp(name->data, cmd->name.data) != 0) {
  281.                 continue;
  282.             }

  283.             found = 1;

  284.             if (cf->cycle->modules[i]->type != NGX_CONF_MODULE
  285.                 && cf->cycle->modules[i]->type != cf->module_type)
  286.             {
  287.                 continue;
  288.             }

  289.             /* is the directive's location right ? */

  290.             if (!(cmd->type & cf->cmd_type)) {
  291.                 continue;
  292.             }

  293.             if (!(cmd->type & NGX_CONF_BLOCK) && last != NGX_OK) {
  294.                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  295.                                   "directive \"%s\" is not terminated by \";\"",
  296.                                   name->data);
  297.                 return NGX_ERROR;
  298.             }

  299.             if ((cmd->type & NGX_CONF_BLOCK) && last != NGX_CONF_BLOCK_START) {
  300.                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  301.                                    "directive \"%s\" has no opening \"{\"",
  302.                                    name->data);
  303.                 return NGX_ERROR;
  304.             }

  305.             /* is the directive's argument count right ? */

  306.             if (!(cmd->type & NGX_CONF_ANY)) {

  307.                 if (cmd->type & NGX_CONF_FLAG) {

  308.                     if (cf->args->nelts != 2) {
  309.                         goto invalid;
  310.                     }

  311.                 } else if (cmd->type & NGX_CONF_1MORE) {

  312.                     if (cf->args->nelts < 2) {
  313.                         goto invalid;
  314.                     }

  315.                 } else if (cmd->type & NGX_CONF_2MORE) {

  316.                     if (cf->args->nelts < 3) {
  317.                         goto invalid;
  318.                     }

  319.                 } else if (cf->args->nelts > NGX_CONF_MAX_ARGS) {

  320.                     goto invalid;

  321.                 } else if (!(cmd->type & argument_number[cf->args->nelts - 1]))
  322.                 {
  323.                     goto invalid;
  324.                 }
  325.             }

  326.             /* set up the directive's configuration context */

  327.             conf = NULL;

  328.             if (cmd->type & NGX_DIRECT_CONF) {
  329.                 conf = ((void **) cf->ctx)[cf->cycle->modules[i]->index];

  330.             } else if (cmd->type & NGX_MAIN_CONF) {
  331.                 conf = &(((void **) cf->ctx)[cf->cycle->modules[i]->index]);

  332.             } else if (cf->ctx) {
  333.                 confp = *(void **) ((char *) cf->ctx + cmd->conf);

  334.                 if (confp) {
  335.                     conf = confp[cf->cycle->modules[i]->ctx_index];
  336.                 }
  337.             }

  338.             rv = cmd->set(cf, cmd, conf);

  339.             if (rv == NGX_CONF_OK) {
  340.                 return NGX_OK;
  341.             }

  342.             if (rv == NGX_CONF_ERROR) {
  343.                 return NGX_ERROR;
  344.             }

  345.             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  346.                                "\"%s\" directive %s", name->data, rv);

  347.             return NGX_ERROR;
  348.         }
  349.     }

  350.     if (found) {
  351.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  352.                            "\"%s\" directive is not allowed here", name->data);

  353.         return NGX_ERROR;
  354.     }

  355.     ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  356.                        "unknown directive \"%s\"", name->data);

  357.     return NGX_ERROR;

  358. invalid:

  359.     ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  360.                        "invalid number of arguments in \"%s\" directive",
  361.                        name->data);

  362.     return NGX_ERROR;
  363. }


  364. static ngx_int_t
  365. ngx_conf_read_token(ngx_conf_t *cf)
  366. {
  367.     u_char      *start, ch, *src, *dst;
  368.     off_t        file_size;
  369.     size_t       len;
  370.     ssize_t      n, size;
  371.     ngx_uint_t   found, need_space, last_space, sharp_comment, variable;
  372.     ngx_uint_t   quoted, s_quoted, d_quoted, start_line;
  373.     ngx_str_t   *word;
  374.     ngx_buf_t   *b, *dump;

  375.     found = 0;
  376.     need_space = 0;
  377.     last_space = 1;
  378.     sharp_comment = 0;
  379.     variable = 0;
  380.     quoted = 0;
  381.     s_quoted = 0;
  382.     d_quoted = 0;

  383.     cf->args->nelts = 0;
  384.     b = cf->conf_file->buffer;
  385.     dump = cf->conf_file->dump;
  386.     start = b->pos;
  387.     start_line = cf->conf_file->line;

  388.     file_size = ngx_file_size(&cf->conf_file->file.info);

  389.     for ( ;; ) {

  390.         if (b->pos >= b->last) {

  391.             if (cf->conf_file->file.offset >= file_size) {

  392.                 if (cf->args->nelts > 0 || !last_space) {

  393.                     if (cf->conf_file->file.fd == NGX_INVALID_FILE) {
  394.                         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  395.                                            "unexpected end of parameter, "
  396.                                            "expecting \";\"");
  397.                         return NGX_ERROR;
  398.                     }

  399.                     ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  400.                                        "unexpected end of file, "
  401.                                        "expecting \";\" or \"}\"");
  402.                     return NGX_ERROR;
  403.                 }

  404.                 return NGX_CONF_FILE_DONE;
  405.             }

  406.             len = b->pos - start;

  407.             if (len == NGX_CONF_BUFFER) {
  408.                 cf->conf_file->line = start_line;

  409.                 if (d_quoted) {
  410.                     ch = '"';

  411.                 } else if (s_quoted) {
  412.                     ch = '\'';

  413.                 } else {
  414.                     ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  415.                                        "too long parameter \"%*s...\" started",
  416.                                        10, start);
  417.                     return NGX_ERROR;
  418.                 }

  419.                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  420.                                    "too long parameter, probably "
  421.                                    "missing terminating \"%c\" character", ch);
  422.                 return NGX_ERROR;
  423.             }

  424.             if (len) {
  425.                 ngx_memmove(b->start, start, len);
  426.             }

  427.             size = (ssize_t) (file_size - cf->conf_file->file.offset);

  428.             if (size > b->end - (b->start + len)) {
  429.                 size = b->end - (b->start + len);
  430.             }

  431.             n = ngx_read_file(&cf->conf_file->file, b->start + len, size,
  432.                               cf->conf_file->file.offset);

  433.             if (n == NGX_ERROR) {
  434.                 return NGX_ERROR;
  435.             }

  436.             if (n != size) {
  437.                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  438.                                    ngx_read_file_n " returned "
  439.                                    "only %z bytes instead of %z",
  440.                                    n, size);
  441.                 return NGX_ERROR;
  442.             }

  443.             b->pos = b->start + len;
  444.             b->last = b->pos + n;
  445.             start = b->start;

  446.             if (dump) {
  447.                 dump->last = ngx_cpymem(dump->last, b->pos, size);
  448.             }
  449.         }

  450.         ch = *b->pos++;

  451.         if (ch == LF) {
  452.             cf->conf_file->line++;

  453.             if (sharp_comment) {
  454.                 sharp_comment = 0;
  455.             }
  456.         }

  457.         if (sharp_comment) {
  458.             continue;
  459.         }

  460.         if (quoted) {
  461.             quoted = 0;
  462.             continue;
  463.         }

  464.         if (need_space) {
  465.             if (ch == ' ' || ch == '\t' || ch == CR || ch == LF) {
  466.                 last_space = 1;
  467.                 need_space = 0;
  468.                 continue;
  469.             }

  470.             if (ch == ';') {
  471.                 return NGX_OK;
  472.             }

  473.             if (ch == '{') {
  474.                 return NGX_CONF_BLOCK_START;
  475.             }

  476.             if (ch == ')') {
  477.                 last_space = 1;
  478.                 need_space = 0;

  479.             } else {
  480.                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  481.                                    "unexpected \"%c\"", ch);
  482.                 return NGX_ERROR;
  483.             }
  484.         }

  485.         if (last_space) {

  486.             start = b->pos - 1;
  487.             start_line = cf->conf_file->line;

  488.             if (ch == ' ' || ch == '\t' || ch == CR || ch == LF) {
  489.                 continue;
  490.             }

  491.             switch (ch) {

  492.             case ';':
  493.             case '{':
  494.                 if (cf->args->nelts == 0) {
  495.                     ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  496.                                        "unexpected \"%c\"", ch);
  497.                     return NGX_ERROR;
  498.                 }

  499.                 if (ch == '{') {
  500.                     return NGX_CONF_BLOCK_START;
  501.                 }

  502.                 return NGX_OK;

  503.             case '}':
  504.                 if (cf->args->nelts != 0) {
  505.                     ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  506.                                        "unexpected \"}\"");
  507.                     return NGX_ERROR;
  508.                 }

  509.                 return NGX_CONF_BLOCK_DONE;

  510.             case '#':
  511.                 sharp_comment = 1;
  512.                 continue;

  513.             case '\\':
  514.                 quoted = 1;
  515.                 last_space = 0;
  516.                 continue;

  517.             case '"':
  518.                 start++;
  519.                 d_quoted = 1;
  520.                 last_space = 0;
  521.                 continue;

  522.             case '\'':
  523.                 start++;
  524.                 s_quoted = 1;
  525.                 last_space = 0;
  526.                 continue;

  527.             case '$':
  528.                 variable = 1;
  529.                 last_space = 0;
  530.                 continue;

  531.             default:
  532.                 last_space = 0;
  533.             }

  534.         } else {
  535.             if (ch == '{' && variable) {
  536.                 continue;
  537.             }

  538.             variable = 0;

  539.             if (ch == '\\') {
  540.                 quoted = 1;
  541.                 continue;
  542.             }

  543.             if (ch == '$') {
  544.                 variable = 1;
  545.                 continue;
  546.             }

  547.             if (d_quoted) {
  548.                 if (ch == '"') {
  549.                     d_quoted = 0;
  550.                     need_space = 1;
  551.                     found = 1;
  552.                 }

  553.             } else if (s_quoted) {
  554.                 if (ch == '\'') {
  555.                     s_quoted = 0;
  556.                     need_space = 1;
  557.                     found = 1;
  558.                 }

  559.             } else if (ch == ' ' || ch == '\t' || ch == CR || ch == LF
  560.                        || ch == ';' || ch == '{')
  561.             {
  562.                 last_space = 1;
  563.                 found = 1;
  564.             }

  565.             if (found) {
  566.                 word = ngx_array_push(cf->args);
  567.                 if (word == NULL) {
  568.                     return NGX_ERROR;
  569.                 }

  570.                 word->data = ngx_pnalloc(cf->pool, b->pos - 1 - start + 1);
  571.                 if (word->data == NULL) {
  572.                     return NGX_ERROR;
  573.                 }

  574.                 for (dst = word->data, src = start, len = 0;
  575.                      src < b->pos - 1;
  576.                      len++)
  577.                 {
  578.                     if (*src == '\\') {
  579.                         switch (src[1]) {
  580.                         case '"':
  581.                         case '\'':
  582.                         case '\\':
  583.                             src++;
  584.                             break;

  585.                         case 't':
  586.                             *dst++ = '\t';
  587.                             src += 2;
  588.                             continue;

  589.                         case 'r':
  590.                             *dst++ = '\r';
  591.                             src += 2;
  592.                             continue;

  593.                         case 'n':
  594.                             *dst++ = '\n';
  595.                             src += 2;
  596.                             continue;
  597.                         }

  598.                     }
  599.                     *dst++ = *src++;
  600.                 }
  601.                 *dst = '\0';
  602.                 word->len = len;

  603.                 if (ch == ';') {
  604.                     return NGX_OK;
  605.                 }

  606.                 if (ch == '{') {
  607.                     return NGX_CONF_BLOCK_START;
  608.                 }

  609.                 found = 0;
  610.             }
  611.         }
  612.     }
  613. }


  614. char *
  615. ngx_conf_include(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  616. {
  617.     char        *rv;
  618.     ngx_int_t    n;
  619.     ngx_str_t   *value, file, name;
  620.     ngx_glob_t   gl;

  621.     value = cf->args->elts;
  622.     file = value[1];

  623.     ngx_log_debug1(NGX_LOG_DEBUG_CORE, cf->log, 0, "include %s", file.data);

  624.     if (ngx_conf_full_name(cf->cycle, &file, 1) != NGX_OK) {
  625.         return NGX_CONF_ERROR;
  626.     }

  627.     if (strpbrk((char *) file.data, "*?[") == NULL) {

  628.         ngx_log_debug1(NGX_LOG_DEBUG_CORE, cf->log, 0, "include %s", file.data);

  629.         return ngx_conf_parse(cf, &file);
  630.     }

  631.     ngx_memzero(&gl, sizeof(ngx_glob_t));

  632.     gl.pattern = file.data;
  633.     gl.log = cf->log;
  634.     gl.test = 1;

  635.     if (ngx_open_glob(&gl) != NGX_OK) {
  636.         ngx_conf_log_error(NGX_LOG_EMERG, cf, ngx_errno,
  637.                            ngx_open_glob_n " \"%s\" failed", file.data);
  638.         return NGX_CONF_ERROR;
  639.     }

  640.     rv = NGX_CONF_OK;

  641.     for ( ;; ) {
  642.         n = ngx_read_glob(&gl, &name);

  643.         if (n != NGX_OK) {
  644.             break;
  645.         }

  646.         file.len = name.len++;
  647.         file.data = ngx_pstrdup(cf->pool, &name);
  648.         if (file.data == NULL) {
  649.             return NGX_CONF_ERROR;
  650.         }

  651.         ngx_log_debug1(NGX_LOG_DEBUG_CORE, cf->log, 0, "include %s", file.data);

  652.         rv = ngx_conf_parse(cf, &file);

  653.         if (rv != NGX_CONF_OK) {
  654.             break;
  655.         }
  656.     }

  657.     ngx_close_glob(&gl);

  658.     return rv;
  659. }


  660. ngx_int_t
  661. ngx_conf_full_name(ngx_cycle_t *cycle, ngx_str_t *name, ngx_uint_t conf_prefix)
  662. {
  663.     ngx_str_t  *prefix;

  664.     prefix = conf_prefix ? &cycle->conf_prefix : &cycle->prefix;

  665.     return ngx_get_full_name(cycle->pool, prefix, name);
  666. }


  667. ngx_open_file_t *
  668. ngx_conf_open_file(ngx_cycle_t *cycle, ngx_str_t *name)
  669. {
  670.     ngx_str_t         full;
  671.     ngx_uint_t        i;
  672.     ngx_list_part_t  *part;
  673.     ngx_open_file_t  *file;

  674. #if (NGX_SUPPRESS_WARN)
  675.     ngx_str_null(&full);
  676. #endif

  677.     if (name->len) {
  678.         full = *name;

  679.         if (ngx_conf_full_name(cycle, &full, 0) != NGX_OK) {
  680.             return NULL;
  681.         }

  682.         part = &cycle->open_files.part;
  683.         file = part->elts;

  684.         for (i = 0; /* void */ ; i++) {

  685.             if (i >= part->nelts) {
  686.                 if (part->next == NULL) {
  687.                     break;
  688.                 }
  689.                 part = part->next;
  690.                 file = part->elts;
  691.                 i = 0;
  692.             }

  693.             if (full.len != file[i].name.len) {
  694.                 continue;
  695.             }

  696.             if (ngx_strcmp(full.data, file[i].name.data) == 0) {
  697.                 return &file[i];
  698.             }
  699.         }
  700.     }

  701.     file = ngx_list_push(&cycle->open_files);
  702.     if (file == NULL) {
  703.         return NULL;
  704.     }

  705.     if (name->len) {
  706.         file->fd = NGX_INVALID_FILE;
  707.         file->name = full;

  708.     } else {
  709.         file->fd = ngx_stderr;
  710.         file->name = *name;
  711.     }

  712.     file->flush = NULL;
  713.     file->data = NULL;

  714.     return file;
  715. }


  716. static void
  717. ngx_conf_flush_files(ngx_cycle_t *cycle)
  718. {
  719.     ngx_uint_t        i;
  720.     ngx_list_part_t  *part;
  721.     ngx_open_file_t  *file;

  722.     ngx_log_debug0(NGX_LOG_DEBUG_CORE, cycle->log, 0, "flush files");

  723.     part = &cycle->open_files.part;
  724.     file = part->elts;

  725.     for (i = 0; /* void */ ; i++) {

  726.         if (i >= part->nelts) {
  727.             if (part->next == NULL) {
  728.                 break;
  729.             }
  730.             part = part->next;
  731.             file = part->elts;
  732.             i = 0;
  733.         }

  734.         if (file[i].flush) {
  735.             file[i].flush(&file[i], cycle->log);
  736.         }
  737.     }
  738. }


  739. void ngx_cdecl
  740. ngx_conf_log_error(ngx_uint_t level, ngx_conf_t *cf, ngx_err_t err,
  741.     const char *fmt, ...)
  742. {
  743.     u_char   errstr[NGX_MAX_CONF_ERRSTR], *p, *last;
  744.     va_list  args;

  745.     last = errstr + NGX_MAX_CONF_ERRSTR;

  746.     va_start(args, fmt);
  747.     p = ngx_vslprintf(errstr, last, fmt, args);
  748.     va_end(args);

  749.     if (err) {
  750.         p = ngx_log_errno(p, last, err);
  751.     }

  752.     if (cf->conf_file == NULL) {
  753.         ngx_log_error(level, cf->log, 0, "%*s", p - errstr, errstr);
  754.         return;
  755.     }

  756.     if (cf->conf_file->file.fd == NGX_INVALID_FILE) {
  757.         ngx_log_error(level, cf->log, 0, "%*s in command line",
  758.                       p - errstr, errstr);
  759.         return;
  760.     }

  761.     ngx_log_error(level, cf->log, 0, "%*s in %s:%ui",
  762.                   p - errstr, errstr,
  763.                   cf->conf_file->file.name.data, cf->conf_file->line);
  764. }


  765. char *
  766. ngx_conf_set_flag_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  767. {
  768.     char  *p = conf;

  769.     ngx_str_t        *value;
  770.     ngx_flag_t       *fp;
  771.     ngx_conf_post_t  *post;

  772.     fp = (ngx_flag_t *) (p + cmd->offset);

  773.     if (*fp != NGX_CONF_UNSET) {
  774.         return "is duplicate";
  775.     }

  776.     value = cf->args->elts;

  777.     if (ngx_strcasecmp(value[1].data, (u_char *) "on") == 0) {
  778.         *fp = 1;

  779.     } else if (ngx_strcasecmp(value[1].data, (u_char *) "off") == 0) {
  780.         *fp = 0;

  781.     } else {
  782.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  783.                      "invalid value \"%s\" in \"%s\" directive, "
  784.                      "it must be \"on\" or \"off\"",
  785.                      value[1].data, cmd->name.data);
  786.         return NGX_CONF_ERROR;
  787.     }

  788.     if (cmd->post) {
  789.         post = cmd->post;
  790.         return post->post_handler(cf, post, fp);
  791.     }

  792.     return NGX_CONF_OK;
  793. }


  794. char *
  795. ngx_conf_set_str_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  796. {
  797.     char  *p = conf;

  798.     ngx_str_t        *field, *value;
  799.     ngx_conf_post_t  *post;

  800.     field = (ngx_str_t *) (p + cmd->offset);

  801.     if (field->data) {
  802.         return "is duplicate";
  803.     }

  804.     value = cf->args->elts;

  805.     *field = value[1];

  806.     if (cmd->post) {
  807.         post = cmd->post;
  808.         return post->post_handler(cf, post, field);
  809.     }

  810.     return NGX_CONF_OK;
  811. }


  812. char *
  813. ngx_conf_set_str_array_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  814. {
  815.     char  *p = conf;

  816.     ngx_str_t         *value, *s;
  817.     ngx_array_t      **a;
  818.     ngx_conf_post_t   *post;

  819.     a = (ngx_array_t **) (p + cmd->offset);

  820.     if (*a == NGX_CONF_UNSET_PTR) {
  821.         *a = ngx_array_create(cf->pool, 4, sizeof(ngx_str_t));
  822.         if (*a == NULL) {
  823.             return NGX_CONF_ERROR;
  824.         }
  825.     }

  826.     s = ngx_array_push(*a);
  827.     if (s == NULL) {
  828.         return NGX_CONF_ERROR;
  829.     }

  830.     value = cf->args->elts;

  831.     *s = value[1];

  832.     if (cmd->post) {
  833.         post = cmd->post;
  834.         return post->post_handler(cf, post, s);
  835.     }

  836.     return NGX_CONF_OK;
  837. }


  838. char *
  839. ngx_conf_set_keyval_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  840. {
  841.     char  *p = conf;

  842.     ngx_str_t         *value;
  843.     ngx_array_t      **a;
  844.     ngx_keyval_t      *kv;
  845.     ngx_conf_post_t   *post;

  846.     a = (ngx_array_t **) (p + cmd->offset);

  847.     if (*a == NGX_CONF_UNSET_PTR || *a == NULL) {
  848.         *a = ngx_array_create(cf->pool, 4, sizeof(ngx_keyval_t));
  849.         if (*a == NULL) {
  850.             return NGX_CONF_ERROR;
  851.         }
  852.     }

  853.     kv = ngx_array_push(*a);
  854.     if (kv == NULL) {
  855.         return NGX_CONF_ERROR;
  856.     }

  857.     value = cf->args->elts;

  858.     kv->key = value[1];
  859.     kv->value = value[2];

  860.     if (cmd->post) {
  861.         post = cmd->post;
  862.         return post->post_handler(cf, post, kv);
  863.     }

  864.     return NGX_CONF_OK;
  865. }


  866. char *
  867. ngx_conf_set_num_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  868. {
  869.     char  *p = conf;

  870.     ngx_int_t        *np;
  871.     ngx_str_t        *value;
  872.     ngx_conf_post_t  *post;


  873.     np = (ngx_int_t *) (p + cmd->offset);

  874.     if (*np != NGX_CONF_UNSET) {
  875.         return "is duplicate";
  876.     }

  877.     value = cf->args->elts;
  878.     *np = ngx_atoi(value[1].data, value[1].len);
  879.     if (*np == NGX_ERROR) {
  880.         return "invalid number";
  881.     }

  882.     if (cmd->post) {
  883.         post = cmd->post;
  884.         return post->post_handler(cf, post, np);
  885.     }

  886.     return NGX_CONF_OK;
  887. }


  888. char *
  889. ngx_conf_set_size_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  890. {
  891.     char  *p = conf;

  892.     size_t           *sp;
  893.     ngx_str_t        *value;
  894.     ngx_conf_post_t  *post;


  895.     sp = (size_t *) (p + cmd->offset);
  896.     if (*sp != NGX_CONF_UNSET_SIZE) {
  897.         return "is duplicate";
  898.     }

  899.     value = cf->args->elts;

  900.     *sp = ngx_parse_size(&value[1]);
  901.     if (*sp == (size_t) NGX_ERROR) {
  902.         return "invalid value";
  903.     }

  904.     if (cmd->post) {
  905.         post = cmd->post;
  906.         return post->post_handler(cf, post, sp);
  907.     }

  908.     return NGX_CONF_OK;
  909. }


  910. char *
  911. ngx_conf_set_off_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  912. {
  913.     char  *p = conf;

  914.     off_t            *op;
  915.     ngx_str_t        *value;
  916.     ngx_conf_post_t  *post;


  917.     op = (off_t *) (p + cmd->offset);
  918.     if (*op != NGX_CONF_UNSET) {
  919.         return "is duplicate";
  920.     }

  921.     value = cf->args->elts;

  922.     *op = ngx_parse_offset(&value[1]);
  923.     if (*op == (off_t) NGX_ERROR) {
  924.         return "invalid value";
  925.     }

  926.     if (cmd->post) {
  927.         post = cmd->post;
  928.         return post->post_handler(cf, post, op);
  929.     }

  930.     return NGX_CONF_OK;
  931. }


  932. char *
  933. ngx_conf_set_msec_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  934. {
  935.     char  *p = conf;

  936.     ngx_msec_t       *msp;
  937.     ngx_str_t        *value;
  938.     ngx_conf_post_t  *post;


  939.     msp = (ngx_msec_t *) (p + cmd->offset);
  940.     if (*msp != NGX_CONF_UNSET_MSEC) {
  941.         return "is duplicate";
  942.     }

  943.     value = cf->args->elts;

  944.     *msp = ngx_parse_time(&value[1], 0);
  945.     if (*msp == (ngx_msec_t) NGX_ERROR) {
  946.         return "invalid value";
  947.     }

  948.     if (cmd->post) {
  949.         post = cmd->post;
  950.         return post->post_handler(cf, post, msp);
  951.     }

  952.     return NGX_CONF_OK;
  953. }


  954. char *
  955. ngx_conf_set_sec_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  956. {
  957.     char  *p = conf;

  958.     time_t           *sp;
  959.     ngx_str_t        *value;
  960.     ngx_conf_post_t  *post;


  961.     sp = (time_t *) (p + cmd->offset);
  962.     if (*sp != NGX_CONF_UNSET) {
  963.         return "is duplicate";
  964.     }

  965.     value = cf->args->elts;

  966.     *sp = ngx_parse_time(&value[1], 1);
  967.     if (*sp == (time_t) NGX_ERROR) {
  968.         return "invalid value";
  969.     }

  970.     if (cmd->post) {
  971.         post = cmd->post;
  972.         return post->post_handler(cf, post, sp);
  973.     }

  974.     return NGX_CONF_OK;
  975. }


  976. char *
  977. ngx_conf_set_bufs_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  978. {
  979.     char *p = conf;

  980.     ngx_str_t   *value;
  981.     ngx_bufs_t  *bufs;


  982.     bufs = (ngx_bufs_t *) (p + cmd->offset);
  983.     if (bufs->num) {
  984.         return "is duplicate";
  985.     }

  986.     value = cf->args->elts;

  987.     bufs->num = ngx_atoi(value[1].data, value[1].len);
  988.     if (bufs->num == NGX_ERROR || bufs->num == 0) {
  989.         return "invalid value";
  990.     }

  991.     bufs->size = ngx_parse_size(&value[2]);
  992.     if (bufs->size == (size_t) NGX_ERROR || bufs->size == 0) {
  993.         return "invalid value";
  994.     }

  995.     return NGX_CONF_OK;
  996. }


  997. char *
  998. ngx_conf_set_enum_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  999. {
  1000.     char  *p = conf;

  1001.     ngx_uint_t       *np, i;
  1002.     ngx_str_t        *value;
  1003.     ngx_conf_enum_t  *e;

  1004.     np = (ngx_uint_t *) (p + cmd->offset);

  1005.     if (*np != NGX_CONF_UNSET_UINT) {
  1006.         return "is duplicate";
  1007.     }

  1008.     value = cf->args->elts;
  1009.     e = cmd->post;

  1010.     for (i = 0; e[i].name.len != 0; i++) {
  1011.         if (e[i].name.len != value[1].len
  1012.             || ngx_strcasecmp(e[i].name.data, value[1].data) != 0)
  1013.         {
  1014.             continue;
  1015.         }

  1016.         *np = e[i].value;

  1017.         return NGX_CONF_OK;
  1018.     }

  1019.     ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  1020.                        "invalid value \"%s\"", value[1].data);

  1021.     return NGX_CONF_ERROR;
  1022. }


  1023. char *
  1024. ngx_conf_set_bitmask_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  1025. {
  1026.     char  *p = conf;

  1027.     ngx_uint_t          *np, i, m;
  1028.     ngx_str_t           *value;
  1029.     ngx_conf_bitmask_t  *mask;


  1030.     np = (ngx_uint_t *) (p + cmd->offset);
  1031.     value = cf->args->elts;
  1032.     mask = cmd->post;

  1033.     for (i = 1; i < cf->args->nelts; i++) {
  1034.         for (m = 0; mask[m].name.len != 0; m++) {

  1035.             if (mask[m].name.len != value[i].len
  1036.                 || ngx_strcasecmp(mask[m].name.data, value[i].data) != 0)
  1037.             {
  1038.                 continue;
  1039.             }

  1040.             if (*np & mask[m].mask) {
  1041.                 ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
  1042.                                    "duplicate value \"%s\"", value[i].data);

  1043.             } else {
  1044.                 *np |= mask[m].mask;
  1045.             }

  1046.             break;
  1047.         }

  1048.         if (mask[m].name.len == 0) {
  1049.             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  1050.                                "invalid value \"%s\"", value[i].data);

  1051.             return NGX_CONF_ERROR;
  1052.         }
  1053.     }

  1054.     return NGX_CONF_OK;
  1055. }


  1056. #if 0

  1057. char *
  1058. ngx_conf_unsupported(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  1059. {
  1060.     return "unsupported on this platform";
  1061. }

  1062. #endif


  1063. char *
  1064. ngx_conf_deprecated(ngx_conf_t *cf, void *post, void *data)
  1065. {
  1066.     ngx_conf_deprecated_t  *d = post;

  1067.     ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
  1068.                        "the \"%s\" directive is deprecated, "
  1069.                        "use the \"%s\" directive instead",
  1070.                        d->old_name, d->new_name);

  1071.     return NGX_CONF_OK;
  1072. }


  1073. char *
  1074. ngx_conf_check_num_bounds(ngx_conf_t *cf, void *post, void *data)
  1075. {
  1076.     ngx_conf_num_bounds_t  *bounds = post;
  1077.     ngx_int_t  *np = data;

  1078.     if (bounds->high == -1) {
  1079.         if (*np >= bounds->low) {
  1080.             return NGX_CONF_OK;
  1081.         }

  1082.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  1083.                            "value must be equal to or greater than %i",
  1084.                            bounds->low);

  1085.         return NGX_CONF_ERROR;
  1086.     }

  1087.     if (*np >= bounds->low && *np <= bounds->high) {
  1088.         return NGX_CONF_OK;
  1089.     }

  1090.     ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  1091.                        "value must be between %i and %i",
  1092.                        bounds->low, bounds->high);

  1093.     return NGX_CONF_ERROR;
  1094. }