src/core/ngx_conf_file.c - nginx-1.31.7 nginx/ @ 939334eff

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. ‌ngx_conf_post_t  ngx_conf_size_nonzero_post = { ngx_conf_check_size_nonzero };


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

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

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

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

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

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

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

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

  70.     rv = ngx_conf_parse(cf, NULL);

  71.     cf->conf_file = NULL;

  72.     return rv;
  73. }


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

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

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

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

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

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

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

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

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

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

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

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

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

  113.     return NGX_OK;
  114. }


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

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

  132.     if (filename) {

  133.         /* open configuration file */

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

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

  141.         prev = cf->conf_file;

  142.         cf->conf_file = &conf_file;

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

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

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

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

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

  162.         type = parse_file;

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

  175.         } else {
  176.             cf->conf_file->dump = NULL;
  177.         }

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

  179.         type = parse_block;

  180.     } else {
  181.         type = parse_param;
  182.     }


  183.     for ( ;; ) {
  184.         rc = ngx_conf_read_token(cf);

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

  194.         if (rc == NGX_ERROR) {
  195.             goto done;
  196.         }

  197.         if (rc == NGX_CONF_BLOCK_DONE) {

  198.             if (type != parse_block) {
  199.                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "unexpected \"}\"");
  200.                 goto failed;
  201.             }

  202.             goto done;
  203.         }

  204.         if (rc == NGX_CONF_FILE_DONE) {

  205.             if (type == parse_block) {
  206.                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  207.                                    "unexpected end of file, expecting \"}\"");
  208.                 goto failed;
  209.             }

  210.             goto done;
  211.         }

  212.         if (rc == NGX_CONF_BLOCK_START) {

  213.             if (type == parse_param) {
  214.                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  215.                                    "block directives are not supported "
  216.                                    "in -g option");
  217.                 goto failed;
  218.             }
  219.         }

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

  221.         if (cf->handler) {

  222.             /*
  223.              * the custom handler, i.e., that is used in the http's
  224.              * "types { ... }" directive
  225.              */

  226.             if (rc == NGX_CONF_BLOCK_START) {
  227.                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "unexpected \"{\"");
  228.                 goto failed;
  229.             }

  230.             rv = (*cf->handler)(cf, NULL, cf->handler_conf);
  231.             if (rv == NGX_CONF_OK) {
  232.                 continue;
  233.             }

  234.             if (rv == NGX_CONF_ERROR) {
  235.                 goto failed;
  236.             }

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

  238.             goto failed;
  239.         }


  240.         rc = ngx_conf_handler(cf, rc);

  241.         if (rc == NGX_ERROR) {
  242.             goto failed;
  243.         }
  244.     }

  245. failed:

  246.     rc = NGX_ERROR;

  247. done:

  248.     if (filename) {
  249.         if (cf->conf_file->buffer->start) {
  250.             ngx_free(cf->conf_file->buffer->start);
  251.         }

  252.         if (ngx_close_file(fd) == NGX_FILE_ERROR) {
  253.             ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno,
  254.                           ngx_close_file_n " %s failed",
  255.                           filename->data);
  256.             rc = NGX_ERROR;
  257.         }

  258.         cf->conf_file = prev;
  259.     }

  260.     if (rc == NGX_ERROR) {
  261.         return NGX_CONF_ERROR;
  262.     }

  263.     return NGX_CONF_OK;
  264. }


  265. static ngx_int_t
  266. ‌ngx_conf_handler(ngx_conf_t *cf, ngx_int_t last)
  267. {
  268.     char           *rv;
  269.     void           *conf, **confp;
  270.     ngx_uint_t      i, found;
  271.     ngx_str_t      *name;
  272.     ngx_command_t  *cmd;

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

  274.     found = 0;

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

  276.         cmd = cf->cycle->modules[i]->commands;
  277.         if (cmd == NULL) {
  278.             continue;
  279.         }

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

  281.             if (name->len != cmd->name.len) {
  282.                 continue;
  283.             }

  284.             if (ngx_strcmp(name->data, cmd->name.data) != 0) {
  285.                 continue;
  286.             }

  287.             found = 1;

  288.             if (cf->cycle->modules[i]->type != NGX_CONF_MODULE
  289.                 && cf->cycle->modules[i]->type != cf->module_type)
  290.             {
  291.                 continue;
  292.             }

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

  294.             if (!(cmd->type & cf->cmd_type)) {
  295.                 continue;
  296.             }

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

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

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

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

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

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

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

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

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

  320.                     if (cf->args->nelts < 3) {
  321.                         goto invalid;
  322.                     }

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

  324.                     goto invalid;

  325.                 } else if (!(cmd->type & argument_number[cf->args->nelts - 1]))
  326.                 {
  327.                     goto invalid;
  328.                 }
  329.             }

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

  331.             conf = NULL;

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

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

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

  338.                 if (confp) {
  339.                     conf = confp[cf->cycle->modules[i]->ctx_index];
  340.                 }
  341.             }

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

  343.             if (rv == NGX_CONF_OK) {
  344.                 return NGX_OK;
  345.             }

  346.             if (rv == NGX_CONF_ERROR) {
  347.                 return NGX_ERROR;
  348.             }

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

  351.             return NGX_ERROR;
  352.         }
  353.     }

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

  357.         return NGX_ERROR;
  358.     }

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

  361.     return NGX_ERROR;

  362. invalid:

  363.     ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  364.                        "invalid number of arguments in \"%s\" directive",
  365.                        name->data);

  366.     return NGX_ERROR;
  367. }


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

  379.     found = 0;
  380.     need_space = 0;
  381.     last_space = 1;
  382.     sharp_comment = 0;
  383.     variable = 0;
  384.     quoted = 0;
  385.     s_quoted = 0;
  386.     d_quoted = 0;

  387.     cf->args->nelts = 0;
  388.     b = cf->conf_file->buffer;
  389.     dump = cf->conf_file->dump;
  390.     start = b->pos;
  391.     start_line = cf->conf_file->line;

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

  393.     for ( ;; ) {

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

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

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

  397.                     if (cf->conf_file->file.fd == NGX_INVALID_FILE) {
  398.                         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  399.                                            "unexpected end of parameter, "
  400.                                            "expecting \";\"");
  401.                         return NGX_ERROR;
  402.                     }

  403.                     ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  404.                                        "unexpected end of file, "
  405.                                        "expecting \";\" or \"}\"");
  406.                     return NGX_ERROR;
  407.                 }

  408.                 return NGX_CONF_FILE_DONE;
  409.             }

  410.             len = b->pos - start;

  411.             if (len == NGX_CONF_BUFFER) {
  412.                 cf->conf_file->line = start_line;

  413.                 if (d_quoted) {
  414.                     ch = '"';

  415.                 } else if (s_quoted) {
  416.                     ch = '\'';

  417.                 } else {
  418.                     ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  419.                                        "too long parameter \"%*s...\" started",
  420.                                        (size_t) 10, start);
  421.                     return NGX_ERROR;
  422.                 }

  423.                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  424.                                    "too long parameter, probably "
  425.                                    "missing terminating \"%c\" character", ch);
  426.                 return NGX_ERROR;
  427.             }

  428.             if (len) {
  429.                 ngx_memmove(b->start, start, len);
  430.             }

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

  432.             if (size > b->end - (b->start + len)) {
  433.                 size = b->end - (b->start + len);
  434.             }

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

  437.             if (n == NGX_ERROR) {
  438.                 return NGX_ERROR;
  439.             }

  440.             if (n != size) {
  441.                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  442.                                    ngx_read_file_n " returned "
  443.                                    "only %z bytes instead of %z",
  444.                                    n, size);
  445.                 return NGX_ERROR;
  446.             }

  447.             b->pos = b->start + len;
  448.             b->last = b->pos + n;
  449.             start = b->start;

  450.             if (dump) {
  451.                 dump->last = ngx_cpymem(dump->last, b->pos, size);
  452.             }
  453.         }

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

  455.         if (ch == LF) {
  456.             cf->conf_file->line++;

  457.             if (sharp_comment) {
  458.                 sharp_comment = 0;
  459.             }
  460.         }

  461.         if (sharp_comment) {
  462.             continue;
  463.         }

  464.         if (quoted) {
  465.             quoted = 0;
  466.             continue;
  467.         }

  468.         if (need_space) {
  469.             if (ch == ' ' || ch == '\t' || ch == CR || ch == LF) {
  470.                 last_space = 1;
  471.                 need_space = 0;
  472.                 continue;
  473.             }

  474.             if (ch == ';') {
  475.                 return NGX_OK;
  476.             }

  477.             if (ch == '{') {
  478.                 return NGX_CONF_BLOCK_START;
  479.             }

  480.             if (ch == ')') {
  481.                 last_space = 1;
  482.                 need_space = 0;

  483.             } else {
  484.                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  485.                                    "unexpected \"%c\"", ch);
  486.                 return NGX_ERROR;
  487.             }
  488.         }

  489.         if (last_space) {

  490.             start = b->pos - 1;
  491.             start_line = cf->conf_file->line;

  492.             if (ch == ' ' || ch == '\t' || ch == CR || ch == LF) {
  493.                 continue;
  494.             }

  495.             switch (ch) {

  496.             case ';':
  497.             case '{':
  498.                 if (cf->args->nelts == 0) {
  499.                     ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  500.                                        "unexpected \"%c\"", ch);
  501.                     return NGX_ERROR;
  502.                 }

  503.                 if (ch == '{') {
  504.                     return NGX_CONF_BLOCK_START;
  505.                 }

  506.                 return NGX_OK;

  507.             case '}':
  508.                 if (cf->args->nelts != 0) {
  509.                     ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  510.                                        "unexpected \"}\"");
  511.                     return NGX_ERROR;
  512.                 }

  513.                 return NGX_CONF_BLOCK_DONE;

  514.             case '#':
  515.                 sharp_comment = 1;
  516.                 continue;

  517.             case '\\':
  518.                 quoted = 1;
  519.                 last_space = 0;
  520.                 continue;

  521.             case '"':
  522.                 start++;
  523.                 d_quoted = 1;
  524.                 last_space = 0;
  525.                 continue;

  526.             case '\'':
  527.                 start++;
  528.                 s_quoted = 1;
  529.                 last_space = 0;
  530.                 continue;

  531.             case '$':
  532.                 variable = 1;
  533.                 last_space = 0;
  534.                 continue;

  535.             default:
  536.                 last_space = 0;
  537.             }

  538.         } else {
  539.             if (ch == '{' && variable) {
  540.                 continue;
  541.             }

  542.             variable = 0;

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

  547.             if (ch == '$') {
  548.                 variable = 1;
  549.                 continue;
  550.             }

  551.             if (d_quoted) {
  552.                 if (ch == '"') {
  553.                     d_quoted = 0;
  554.                     need_space = 1;
  555.                     found = 1;
  556.                 }

  557.             } else if (s_quoted) {
  558.                 if (ch == '\'') {
  559.                     s_quoted = 0;
  560.                     need_space = 1;
  561.                     found = 1;
  562.                 }

  563.             } else if (ch == ' ' || ch == '\t' || ch == CR || ch == LF
  564.                        || ch == ';' || ch == '{')
  565.             {
  566.                 last_space = 1;
  567.                 found = 1;
  568.             }

  569.             if (found) {
  570.                 word = ngx_array_push(cf->args);
  571.                 if (word == NULL) {
  572.                     return NGX_ERROR;
  573.                 }

  574.                 word->data = ngx_pnalloc(cf->pool, b->pos - 1 - start + 1);
  575.                 if (word->data == NULL) {
  576.                     return NGX_ERROR;
  577.                 }

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

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

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

  597.                         case 'n':
  598.                             *dst++ = '\n';
  599.                             src += 2;
  600.                             continue;
  601.                         }

  602.                     }
  603.                     *dst++ = *src++;
  604.                 }
  605.                 *dst = '\0';
  606.                 word->len = len;

  607.                 if (ch == ';') {
  608.                     return NGX_OK;
  609.                 }

  610.                 if (ch == '{') {
  611.                     return NGX_CONF_BLOCK_START;
  612.                 }

  613.                 found = 0;
  614.             }
  615.         }
  616.     }
  617. }


  618. char *
  619. ‌ngx_conf_include(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  620. {
  621.     char        *rv;
  622.     ngx_int_t    n;
  623.     ngx_str_t   *value, file, name;
  624.     ngx_glob_t   gl;

  625.     value = cf->args->elts;
  626.     file = value[1];

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

  628.     if (ngx_conf_full_name(cf->cycle, &file, 1) != NGX_OK) {
  629.         return NGX_CONF_ERROR;
  630.     }

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

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

  633.         return ngx_conf_parse(cf, &file);
  634.     }

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

  636.     gl.pattern = file.data;
  637.     gl.log = cf->log;
  638.     gl.test = 1;

  639.     if (ngx_open_glob(&gl) != NGX_OK) {
  640.         ngx_conf_log_error(NGX_LOG_EMERG, cf, ngx_errno,
  641.                            ngx_open_glob_n " \"%s\" failed", file.data);
  642.         return NGX_CONF_ERROR;
  643.     }

  644.     rv = NGX_CONF_OK;

  645.     for ( ;; ) {
  646.         n = ngx_read_glob(&gl, &name);

  647.         if (n != NGX_OK) {
  648.             break;
  649.         }

  650.         file.len = name.len++;
  651.         file.data = ngx_pstrdup(cf->pool, &name);
  652.         if (file.data == NULL) {
  653.             return NGX_CONF_ERROR;
  654.         }

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

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

  657.         if (rv != NGX_CONF_OK) {
  658.             break;
  659.         }
  660.     }

  661.     ngx_close_glob(&gl);

  662.     return rv;
  663. }


  664. ngx_int_t
  665. ‌ngx_conf_full_name(ngx_cycle_t *cycle, ngx_str_t *name, ngx_uint_t conf_prefix)
  666. {
  667.     ngx_str_t  *prefix;

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

  669.     return ngx_get_full_name(cycle->pool, prefix, name);
  670. }


  671. ngx_open_file_t *
  672. ‌ngx_conf_open_file(ngx_cycle_t *cycle, ngx_str_t *name)
  673. {
  674.     ngx_str_t         full;
  675.     ngx_uint_t        i;
  676.     ngx_list_part_t  *part;
  677.     ngx_open_file_t  *file;

  678. #if (NGX_SUPPRESS_WARN)
  679.     ngx_str_null(&full);
  680. #endif

  681.     if (name->len) {
  682.         full = *name;

  683.         if (ngx_conf_full_name(cycle, &full, 0) != NGX_OK) {
  684.             return NULL;
  685.         }

  686.         part = &cycle->open_files.part;
  687.         file = part->elts;

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

  689.             if (i >= part->nelts) {
  690.                 if (part->next == NULL) {
  691.                     break;
  692.                 }
  693.                 part = part->next;
  694.                 file = part->elts;
  695.                 i = 0;
  696.             }

  697.             if (full.len != file[i].name.len) {
  698.                 continue;
  699.             }

  700.             if (ngx_strcmp(full.data, file[i].name.data) == 0) {
  701.                 return &file[i];
  702.             }
  703.         }
  704.     }

  705.     file = ngx_list_push(&cycle->open_files);
  706.     if (file == NULL) {
  707.         return NULL;
  708.     }

  709.     if (name->len) {
  710.         file->fd = NGX_INVALID_FILE;
  711.         file->name = full;

  712.     } else {
  713.         file->fd = ngx_stderr;
  714.         file->name = *name;
  715.     }

  716.     file->flush = NULL;
  717.     file->data = NULL;

  718.     return file;
  719. }


  720. static void
  721. ‌ngx_conf_flush_files(ngx_cycle_t *cycle)
  722. {
  723.     ngx_uint_t        i;
  724.     ngx_list_part_t  *part;
  725.     ngx_open_file_t  *file;

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

  727.     part = &cycle->open_files.part;
  728.     file = part->elts;

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

  730.         if (i >= part->nelts) {
  731.             if (part->next == NULL) {
  732.                 break;
  733.             }
  734.             part = part->next;
  735.             file = part->elts;
  736.             i = 0;
  737.         }

  738.         if (file[i].flush) {
  739.             file[i].flush(&file[i], cycle->log);
  740.         }
  741.     }
  742. }


  743. void ngx_cdecl
  744. ‌ngx_conf_log_error(ngx_uint_t level, ngx_conf_t *cf, ngx_err_t err,
  745.     const char *fmt, ...)
  746. {
  747.     u_char   errstr[NGX_MAX_CONF_ERRSTR], *p, *last;
  748.     va_list  args;

  749.     last = errstr + NGX_MAX_CONF_ERRSTR;

  750.     va_start(args, fmt);
  751.     p = ngx_vslprintf(errstr, last, fmt, args);
  752.     va_end(args);

  753.     if (err) {
  754.         p = ngx_log_errno(p, last, err);
  755.     }

  756.     if (cf->conf_file == NULL) {
  757.         ngx_log_error(level, cf->log, 0, "%*s", p - errstr, errstr);
  758.         return;
  759.     }

  760.     if (cf->conf_file->file.fd == NGX_INVALID_FILE) {
  761.         ngx_log_error(level, cf->log, 0, "%*s in command line",
  762.                       p - errstr, errstr);
  763.         return;
  764.     }

  765.     ngx_log_error(level, cf->log, 0, "%*s in %s:%ui",
  766.                   p - errstr, errstr,
  767.                   cf->conf_file->file.name.data, cf->conf_file->line);
  768. }


  769. char *
  770. ‌ngx_conf_set_flag_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  771. {
  772.     char  *p = conf;

  773.     ngx_str_t        *value;
  774.     ngx_flag_t       *fp;
  775.     ngx_conf_post_t  *post;

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

  777.     if (*fp != NGX_CONF_UNSET) {
  778.         return "is duplicate";
  779.     }

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

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

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

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

  792.     if (cmd->post) {
  793.         post = cmd->post;
  794.         return post->post_handler(cf, post, fp);
  795.     }

  796.     return NGX_CONF_OK;
  797. }


  798. char *
  799. ‌ngx_conf_set_str_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  800. {
  801.     char  *p = conf;

  802.     ngx_str_t        *field, *value;
  803.     ngx_conf_post_t  *post;

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

  805.     if (field->data) {
  806.         return "is duplicate";
  807.     }

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

  809.     *field = value[1];

  810.     if (cmd->post) {
  811.         post = cmd->post;
  812.         return post->post_handler(cf, post, field);
  813.     }

  814.     return NGX_CONF_OK;
  815. }


  816. char *
  817. ‌ngx_conf_set_str_array_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  818. {
  819.     char  *p = conf;

  820.     ngx_str_t         *value, *s;
  821.     ngx_array_t      **a;
  822.     ngx_conf_post_t   *post;

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

  824.     if (*a == NGX_CONF_UNSET_PTR) {
  825.         *a = ngx_array_create(cf->pool, 4, sizeof(ngx_str_t));
  826.         if (*a == NULL) {
  827.             return NGX_CONF_ERROR;
  828.         }
  829.     }

  830.     s = ngx_array_push(*a);
  831.     if (s == NULL) {
  832.         return NGX_CONF_ERROR;
  833.     }

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

  835.     *s = value[1];

  836.     if (cmd->post) {
  837.         post = cmd->post;
  838.         return post->post_handler(cf, post, s);
  839.     }

  840.     return NGX_CONF_OK;
  841. }


  842. char *
  843. ‌ngx_conf_set_keyval_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  844. {
  845.     char  *p = conf;

  846.     ngx_str_t         *value;
  847.     ngx_array_t      **a;
  848.     ngx_keyval_t      *kv;
  849.     ngx_conf_post_t   *post;

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

  851.     if (*a == NGX_CONF_UNSET_PTR || *a == NULL) {
  852.         *a = ngx_array_create(cf->pool, 4, sizeof(ngx_keyval_t));
  853.         if (*a == NULL) {
  854.             return NGX_CONF_ERROR;
  855.         }
  856.     }

  857.     kv = ngx_array_push(*a);
  858.     if (kv == NULL) {
  859.         return NGX_CONF_ERROR;
  860.     }

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

  862.     kv->key = value[1];
  863.     kv->value = value[2];

  864.     if (cmd->post) {
  865.         post = cmd->post;
  866.         return post->post_handler(cf, post, kv);
  867.     }

  868.     return NGX_CONF_OK;
  869. }


  870. char *
  871. ‌ngx_conf_set_num_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  872. {
  873.     char  *p = conf;

  874.     ngx_int_t        *np;
  875.     ngx_str_t        *value;
  876.     ngx_conf_post_t  *post;


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

  878.     if (*np != NGX_CONF_UNSET) {
  879.         return "is duplicate";
  880.     }

  881.     value = cf->args->elts;
  882.     *np = ngx_atoi(value[1].data, value[1].len);
  883.     if (*np == NGX_ERROR) {
  884.         return "invalid number";
  885.     }

  886.     if (cmd->post) {
  887.         post = cmd->post;
  888.         return post->post_handler(cf, post, np);
  889.     }

  890.     return NGX_CONF_OK;
  891. }


  892. char *
  893. ‌ngx_conf_set_size_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  894. {
  895.     char  *p = conf;

  896.     size_t           *sp;
  897.     ngx_str_t        *value;
  898.     ngx_conf_post_t  *post;


  899.     sp = (size_t *) (p + cmd->offset);
  900.     if (*sp != NGX_CONF_UNSET_SIZE) {
  901.         return "is duplicate";
  902.     }

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

  904.     *sp = ngx_parse_size(&value[1]);
  905.     if (*sp == (size_t) NGX_ERROR) {
  906.         return "invalid value";
  907.     }

  908.     if (cmd->post) {
  909.         post = cmd->post;
  910.         return post->post_handler(cf, post, sp);
  911.     }

  912.     return NGX_CONF_OK;
  913. }


  914. char *
  915. ‌ngx_conf_set_off_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  916. {
  917.     char  *p = conf;

  918.     off_t            *op;
  919.     ngx_str_t        *value;
  920.     ngx_conf_post_t  *post;


  921.     op = (off_t *) (p + cmd->offset);
  922.     if (*op != NGX_CONF_UNSET) {
  923.         return "is duplicate";
  924.     }

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

  926.     *op = ngx_parse_offset(&value[1]);
  927.     if (*op == (off_t) NGX_ERROR) {
  928.         return "invalid value";
  929.     }

  930.     if (cmd->post) {
  931.         post = cmd->post;
  932.         return post->post_handler(cf, post, op);
  933.     }

  934.     return NGX_CONF_OK;
  935. }


  936. char *
  937. ‌ngx_conf_set_msec_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  938. {
  939.     char  *p = conf;

  940.     ngx_msec_t       *msp;
  941.     ngx_str_t        *value;
  942.     ngx_conf_post_t  *post;


  943.     msp = (ngx_msec_t *) (p + cmd->offset);
  944.     if (*msp != NGX_CONF_UNSET_MSEC) {
  945.         return "is duplicate";
  946.     }

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

  948.     *msp = ngx_parse_time(&value[1], 0);
  949.     if (*msp == (ngx_msec_t) NGX_ERROR) {
  950.         return "invalid value";
  951.     }

  952.     if (cmd->post) {
  953.         post = cmd->post;
  954.         return post->post_handler(cf, post, msp);
  955.     }

  956.     return NGX_CONF_OK;
  957. }


  958. char *
  959. ‌ngx_conf_set_sec_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  960. {
  961.     char  *p = conf;

  962.     time_t           *sp;
  963.     ngx_str_t        *value;
  964.     ngx_conf_post_t  *post;


  965.     sp = (time_t *) (p + cmd->offset);
  966.     if (*sp != NGX_CONF_UNSET) {
  967.         return "is duplicate";
  968.     }

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

  970.     *sp = ngx_parse_time(&value[1], 1);
  971.     if (*sp == (time_t) NGX_ERROR) {
  972.         return "invalid value";
  973.     }

  974.     if (cmd->post) {
  975.         post = cmd->post;
  976.         return post->post_handler(cf, post, sp);
  977.     }

  978.     return NGX_CONF_OK;
  979. }


  980. char *
  981. ‌ngx_conf_set_bufs_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  982. {
  983.     char *p = conf;

  984.     ngx_str_t   *value;
  985.     ngx_bufs_t  *bufs;


  986.     bufs = (ngx_bufs_t *) (p + cmd->offset);
  987.     if (bufs->num) {
  988.         return "is duplicate";
  989.     }

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

  991.     bufs->num = ngx_atoi(value[1].data, value[1].len);
  992.     if (bufs->num == NGX_ERROR || bufs->num == 0) {
  993.         return "invalid value";
  994.     }

  995.     bufs->size = ngx_parse_size(&value[2]);
  996.     if (bufs->size == (size_t) NGX_ERROR || bufs->size == 0) {
  997.         return "invalid value";
  998.     }

  999.     return NGX_CONF_OK;
  1000. }


  1001. char *
  1002. ‌ngx_conf_set_enum_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  1003. {
  1004.     char  *p = conf;

  1005.     ngx_uint_t       *np, i;
  1006.     ngx_str_t        *value;
  1007.     ngx_conf_enum_t  *e;

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

  1009.     if (*np != NGX_CONF_UNSET_UINT) {
  1010.         return "is duplicate";
  1011.     }

  1012.     value = cf->args->elts;
  1013.     e = cmd->post;

  1014.     for (i = 0; e[i].name.len != 0; i++) {
  1015.         if (e[i].name.len != value[1].len
  1016.             || ngx_strcasecmp(e[i].name.data, value[1].data) != 0)
  1017.         {
  1018.             continue;
  1019.         }

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

  1021.         return NGX_CONF_OK;
  1022.     }

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

  1025.     return NGX_CONF_ERROR;
  1026. }


  1027. char *
  1028. ‌ngx_conf_set_bitmask_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  1029. {
  1030.     char  *p = conf;

  1031.     ngx_uint_t          *np, i, m;
  1032.     ngx_str_t           *value;
  1033.     ngx_conf_bitmask_t  *mask;


  1034.     np = (ngx_uint_t *) (p + cmd->offset);
  1035.     value = cf->args->elts;
  1036.     mask = cmd->post;

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

  1039.             if (mask[m].name.len != value[i].len
  1040.                 || ngx_strcasecmp(mask[m].name.data, value[i].data) != 0)
  1041.             {
  1042.                 continue;
  1043.             }

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

  1047.             } else {
  1048.                 *np |= mask[m].mask;
  1049.             }

  1050.             break;
  1051.         }

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

  1055.             return NGX_CONF_ERROR;
  1056.         }
  1057.     }

  1058.     return NGX_CONF_OK;
  1059. }


  1060. #if 0

  1061. char *
  1062. ngx_conf_unsupported(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  1063. {
  1064.     return "unsupported on this platform";
  1065. }

  1066. #endif


  1067. char *
  1068. ‌ngx_conf_deprecated(ngx_conf_t *cf, void *post, void *data)
  1069. {
  1070.     ngx_conf_deprecated_t  *d = post;

  1071.     ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
  1072.                        "the \"%s\" directive is deprecated, "
  1073.                        "use the \"%s\" directive instead",
  1074.                        d->old_name, d->new_name);

  1075.     return NGX_CONF_OK;
  1076. }


  1077. char *
  1078. ‌ngx_conf_check_num_bounds(ngx_conf_t *cf, void *post, void *data)
  1079. {
  1080.     ngx_conf_num_bounds_t  *bounds = post;
  1081.     ngx_int_t  *np = data;

  1082.     if (bounds->high == -1) {
  1083.         if (*np >= bounds->low) {
  1084.             return NGX_CONF_OK;
  1085.         }

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

  1089.         return NGX_CONF_ERROR;
  1090.     }

  1091.     if (*np >= bounds->low && *np <= bounds->high) {
  1092.         return NGX_CONF_OK;
  1093.     }

  1094.     ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  1095.                        "value must be between %i and %i",
  1096.                        bounds->low, bounds->high);

  1097.     return NGX_CONF_ERROR;
  1098. }


  1099. char *
  1100. ‌ngx_conf_check_size_nonzero(ngx_conf_t *cf, void *post, void *data)
  1101. {
  1102.     size_t  *sp = data;

  1103.     if (*sp == 0) {
  1104.         return "value must be nonzero";
  1105.     }

  1106.     return NGX_CONF_OK;
  1107. }