src/core/ngx_conf_file.c - nginx-1.7.10

Global variables 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_handler(ngx_conf_t *cf, ngx_int_t last);
  9. static ngx_int_t ngx_conf_read_token(ngx_conf_t *cf);
  10. static void ngx_conf_flush_files(ngx_cycle_t *cycle);


  11. static ngx_command_t  ngx_conf_commands[] = {

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

  18.       ngx_null_command
  19. };


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


  34. /* The eight fixed arguments */

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


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

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

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

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

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

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

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

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

  68.     rv = ngx_conf_parse(cf, NULL);

  69.     cf->conf_file = NULL;

  70.     return rv;
  71. }


  72. char *
  73. ngx_conf_parse(ngx_conf_t *cf, ngx_str_t *filename)
  74. {
  75.     char             *rv;
  76.     ngx_fd_t          fd;
  77.     ngx_int_t         rc;
  78.     ngx_buf_t         buf;
  79.     ngx_conf_file_t  *prev, conf_file;
  80.     enum {
  81.         parse_file = 0,
  82.         parse_block,
  83.         parse_param
  84.     } type;

  85. #if (NGX_SUPPRESS_WARN)
  86.     fd = NGX_INVALID_FILE;
  87.     prev = NULL;
  88. #endif

  89.     if (filename) {

  90.         /* open configuration file */

  91.         fd = ngx_open_file(filename->data, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0);
  92.         if (fd == NGX_INVALID_FILE) {
  93.             ngx_conf_log_error(NGX_LOG_EMERG, cf, ngx_errno,
  94.                                ngx_open_file_n " \"%s\" failed",
  95.                                filename->data);
  96.             return NGX_CONF_ERROR;
  97.         }

  98.         prev = cf->conf_file;

  99.         cf->conf_file = &conf_file;

  100.         if (ngx_fd_info(fd, &cf->conf_file->file.info) == NGX_FILE_ERROR) {
  101.             ngx_log_error(NGX_LOG_EMERG, cf->log, ngx_errno,
  102.                           ngx_fd_info_n " \"%s\" failed", filename->data);
  103.         }

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

  105.         buf.start = ngx_alloc(NGX_CONF_BUFFER, cf->log);
  106.         if (buf.start == NULL) {
  107.             goto failed;
  108.         }

  109.         buf.pos = buf.start;
  110.         buf.last = buf.start;
  111.         buf.end = buf.last + NGX_CONF_BUFFER;
  112.         buf.temporary = 1;

  113.         cf->conf_file->file.fd = fd;
  114.         cf->conf_file->file.name.len = filename->len;
  115.         cf->conf_file->file.name.data = filename->data;
  116.         cf->conf_file->file.offset = 0;
  117.         cf->conf_file->file.log = cf->log;
  118.         cf->conf_file->line = 1;

  119.         type = parse_file;

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

  121.         type = parse_block;

  122.     } else {
  123.         type = parse_param;
  124.     }


  125.     for ( ;; ) {
  126.         rc = ngx_conf_read_token(cf);

  127.         /*
  128.          * ngx_conf_read_token() may return
  129.          *
  130.          *    NGX_ERROR             there is error
  131.          *    NGX_OK                the token terminated by ";" was found
  132.          *    NGX_CONF_BLOCK_START  the token terminated by "{" was found
  133.          *    NGX_CONF_BLOCK_DONE   the "}" was found
  134.          *    NGX_CONF_FILE_DONE    the configuration file is done
  135.          */

  136.         if (rc == NGX_ERROR) {
  137.             goto done;
  138.         }

  139.         if (rc == NGX_CONF_BLOCK_DONE) {

  140.             if (type != parse_block) {
  141.                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "unexpected \"}\"");
  142.                 goto failed;
  143.             }

  144.             goto done;
  145.         }

  146.         if (rc == NGX_CONF_FILE_DONE) {

  147.             if (type == parse_block) {
  148.                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  149.                                    "unexpected end of file, expecting \"}\"");
  150.                 goto failed;
  151.             }

  152.             goto done;
  153.         }

  154.         if (rc == NGX_CONF_BLOCK_START) {

  155.             if (type == parse_param) {
  156.                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  157.                                    "block directives are not supported "
  158.                                    "in -g option");
  159.                 goto failed;
  160.             }
  161.         }

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

  163.         if (cf->handler) {

  164.             /*
  165.              * the custom handler, i.e., that is used in the http's
  166.              * "types { ... }" directive
  167.              */

  168.             if (rc == NGX_CONF_BLOCK_START) {
  169.                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "unexpected \"{\"");
  170.                 goto failed;
  171.             }

  172.             rv = (*cf->handler)(cf, NULL, cf->handler_conf);
  173.             if (rv == NGX_CONF_OK) {
  174.                 continue;
  175.             }

  176.             if (rv == NGX_CONF_ERROR) {
  177.                 goto failed;
  178.             }

  179.             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, rv);

  180.             goto failed;
  181.         }


  182.         rc = ngx_conf_handler(cf, rc);

  183.         if (rc == NGX_ERROR) {
  184.             goto failed;
  185.         }
  186.     }

  187. failed:

  188.     rc = NGX_ERROR;

  189. done:

  190.     if (filename) {
  191.         if (cf->conf_file->buffer->start) {
  192.             ngx_free(cf->conf_file->buffer->start);
  193.         }

  194.         if (ngx_close_file(fd) == NGX_FILE_ERROR) {
  195.             ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno,
  196.                           ngx_close_file_n " %s failed",
  197.                           filename->data);
  198.             rc = NGX_ERROR;
  199.         }

  200.         cf->conf_file = prev;
  201.     }

  202.     if (rc == NGX_ERROR) {
  203.         return NGX_CONF_ERROR;
  204.     }

  205.     return NGX_CONF_OK;
  206. }


  207. static ngx_int_t
  208. ngx_conf_handler(ngx_conf_t *cf, ngx_int_t last)
  209. {
  210.     char           *rv;
  211.     void           *conf, **confp;
  212.     ngx_uint_t      i, found;
  213.     ngx_str_t      *name;
  214.     ngx_command_t  *cmd;

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

  216.     found = 0;

  217.     for (i = 0; ngx_modules[i]; i++) {

  218.         cmd = ngx_modules[i]->commands;
  219.         if (cmd == NULL) {
  220.             continue;
  221.         }

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

  223.             if (name->len != cmd->name.len) {
  224.                 continue;
  225.             }

  226.             if (ngx_strcmp(name->data, cmd->name.data) != 0) {
  227.                 continue;
  228.             }

  229.             found = 1;

  230.             if (ngx_modules[i]->type != NGX_CONF_MODULE
  231.                 && ngx_modules[i]->type != cf->module_type)
  232.             {
  233.                 continue;
  234.             }

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

  236.             if (!(cmd->type & cf->cmd_type)) {
  237.                 continue;
  238.             }

  239.             if (!(cmd->type & NGX_CONF_BLOCK) && last != NGX_OK) {
  240.                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  241.                                   "directive \"%s\" is not terminated by \";\"",
  242.                                   name->data);
  243.                 return NGX_ERROR;
  244.             }

  245.             if ((cmd->type & NGX_CONF_BLOCK) && last != NGX_CONF_BLOCK_START) {
  246.                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  247.                                    "directive \"%s\" has no opening \"{\"",
  248.                                    name->data);
  249.                 return NGX_ERROR;
  250.             }

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

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

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

  254.                     if (cf->args->nelts != 2) {
  255.                         goto invalid;
  256.                     }

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

  258.                     if (cf->args->nelts < 2) {
  259.                         goto invalid;
  260.                     }

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

  262.                     if (cf->args->nelts < 3) {
  263.                         goto invalid;
  264.                     }

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

  266.                     goto invalid;

  267.                 } else if (!(cmd->type & argument_number[cf->args->nelts - 1]))
  268.                 {
  269.                     goto invalid;
  270.                 }
  271.             }

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

  273.             conf = NULL;

  274.             if (cmd->type & NGX_DIRECT_CONF) {
  275.                 conf = ((void **) cf->ctx)[ngx_modules[i]->index];

  276.             } else if (cmd->type & NGX_MAIN_CONF) {
  277.                 conf = &(((void **) cf->ctx)[ngx_modules[i]->index]);

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

  280.                 if (confp) {
  281.                     conf = confp[ngx_modules[i]->ctx_index];
  282.                 }
  283.             }

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

  285.             if (rv == NGX_CONF_OK) {
  286.                 return NGX_OK;
  287.             }

  288.             if (rv == NGX_CONF_ERROR) {
  289.                 return NGX_ERROR;
  290.             }

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

  293.             return NGX_ERROR;
  294.         }
  295.     }

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

  299.         return NGX_ERROR;
  300.     }

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

  303.     return NGX_ERROR;

  304. invalid:

  305.     ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  306.                        "invalid number of arguments in \"%s\" directive",
  307.                        name->data);

  308.     return NGX_ERROR;
  309. }


  310. static ngx_int_t
  311. ngx_conf_read_token(ngx_conf_t *cf)
  312. {
  313.     u_char      *start, ch, *src, *dst;
  314.     off_t        file_size;
  315.     size_t       len;
  316.     ssize_t      n, size;
  317.     ngx_uint_t   found, need_space, last_space, sharp_comment, variable;
  318.     ngx_uint_t   quoted, s_quoted, d_quoted, start_line;
  319.     ngx_str_t   *word;
  320.     ngx_buf_t   *b;

  321.     found = 0;
  322.     need_space = 0;
  323.     last_space = 1;
  324.     sharp_comment = 0;
  325.     variable = 0;
  326.     quoted = 0;
  327.     s_quoted = 0;
  328.     d_quoted = 0;

  329.     cf->args->nelts = 0;
  330.     b = cf->conf_file->buffer;
  331.     start = b->pos;
  332.     start_line = cf->conf_file->line;

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

  334.     for ( ;; ) {

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

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

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

  338.                     if (cf->conf_file->file.fd == NGX_INVALID_FILE) {
  339.                         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  340.                                            "unexpected end of parameter, "
  341.                                            "expecting \";\"");
  342.                         return NGX_ERROR;
  343.                     }

  344.                     ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  345.                                   "unexpected end of file, "
  346.                                   "expecting \";\" or \"}\"");
  347.                     return NGX_ERROR;
  348.                 }

  349.                 return NGX_CONF_FILE_DONE;
  350.             }

  351.             len = b->pos - start;

  352.             if (len == NGX_CONF_BUFFER) {
  353.                 cf->conf_file->line = start_line;

  354.                 if (d_quoted) {
  355.                     ch = '"';

  356.                 } else if (s_quoted) {
  357.                     ch = '\'';

  358.                 } else {
  359.                     ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  360.                                        "too long parameter \"%*s...\" started",
  361.                                        10, start);
  362.                     return NGX_ERROR;
  363.                 }

  364.                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  365.                                    "too long parameter, probably "
  366.                                    "missing terminating \"%c\" character", ch);
  367.                 return NGX_ERROR;
  368.             }

  369.             if (len) {
  370.                 ngx_memmove(b->start, start, len);
  371.             }

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

  373.             if (size > b->end - (b->start + len)) {
  374.                 size = b->end - (b->start + len);
  375.             }

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

  378.             if (n == NGX_ERROR) {
  379.                 return NGX_ERROR;
  380.             }

  381.             if (n != size) {
  382.                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  383.                                    ngx_read_file_n " returned "
  384.                                    "only %z bytes instead of %z",
  385.                                    n, size);
  386.                 return NGX_ERROR;
  387.             }

  388.             b->pos = b->start + len;
  389.             b->last = b->pos + n;
  390.             start = b->start;
  391.         }

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

  393.         if (ch == LF) {
  394.             cf->conf_file->line++;

  395.             if (sharp_comment) {
  396.                 sharp_comment = 0;
  397.             }
  398.         }

  399.         if (sharp_comment) {
  400.             continue;
  401.         }

  402.         if (quoted) {
  403.             quoted = 0;
  404.             continue;
  405.         }

  406.         if (need_space) {
  407.             if (ch == ' ' || ch == '\t' || ch == CR || ch == LF) {
  408.                 last_space = 1;
  409.                 need_space = 0;
  410.                 continue;
  411.             }

  412.             if (ch == ';') {
  413.                 return NGX_OK;
  414.             }

  415.             if (ch == '{') {
  416.                 return NGX_CONF_BLOCK_START;
  417.             }

  418.             if (ch == ')') {
  419.                 last_space = 1;
  420.                 need_space = 0;

  421.             } else {
  422.                  ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  423.                                     "unexpected \"%c\"", ch);
  424.                  return NGX_ERROR;
  425.             }
  426.         }

  427.         if (last_space) {
  428.             if (ch == ' ' || ch == '\t' || ch == CR || ch == LF) {
  429.                 continue;
  430.             }

  431.             start = b->pos - 1;
  432.             start_line = cf->conf_file->line;

  433.             switch (ch) {

  434.             case ';':
  435.             case '{':
  436.                 if (cf->args->nelts == 0) {
  437.                     ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  438.                                        "unexpected \"%c\"", ch);
  439.                     return NGX_ERROR;
  440.                 }

  441.                 if (ch == '{') {
  442.                     return NGX_CONF_BLOCK_START;
  443.                 }

  444.                 return NGX_OK;

  445.             case '}':
  446.                 if (cf->args->nelts != 0) {
  447.                     ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  448.                                        "unexpected \"}\"");
  449.                     return NGX_ERROR;
  450.                 }

  451.                 return NGX_CONF_BLOCK_DONE;

  452.             case '#':
  453.                 sharp_comment = 1;
  454.                 continue;

  455.             case '\\':
  456.                 quoted = 1;
  457.                 last_space = 0;
  458.                 continue;

  459.             case '"':
  460.                 start++;
  461.                 d_quoted = 1;
  462.                 last_space = 0;
  463.                 continue;

  464.             case '\'':
  465.                 start++;
  466.                 s_quoted = 1;
  467.                 last_space = 0;
  468.                 continue;

  469.             default:
  470.                 last_space = 0;
  471.             }

  472.         } else {
  473.             if (ch == '{' && variable) {
  474.                 continue;
  475.             }

  476.             variable = 0;

  477.             if (ch == '\\') {
  478.                 quoted = 1;
  479.                 continue;
  480.             }

  481.             if (ch == '$') {
  482.                 variable = 1;
  483.                 continue;
  484.             }

  485.             if (d_quoted) {
  486.                 if (ch == '"') {
  487.                     d_quoted = 0;
  488.                     need_space = 1;
  489.                     found = 1;
  490.                 }

  491.             } else if (s_quoted) {
  492.                 if (ch == '\'') {
  493.                     s_quoted = 0;
  494.                     need_space = 1;
  495.                     found = 1;
  496.                 }

  497.             } else if (ch == ' ' || ch == '\t' || ch == CR || ch == LF
  498.                        || ch == ';' || ch == '{')
  499.             {
  500.                 last_space = 1;
  501.                 found = 1;
  502.             }

  503.             if (found) {
  504.                 word = ngx_array_push(cf->args);
  505.                 if (word == NULL) {
  506.                     return NGX_ERROR;
  507.                 }

  508.                 word->data = ngx_pnalloc(cf->pool, b->pos - start + 1);
  509.                 if (word->data == NULL) {
  510.                     return NGX_ERROR;
  511.                 }

  512.                 for (dst = word->data, src = start, len = 0;
  513.                      src < b->pos - 1;
  514.                      len++)
  515.                 {
  516.                     if (*src == '\\') {
  517.                         switch (src[1]) {
  518.                         case '"':
  519.                         case '\'':
  520.                         case '\\':
  521.                             src++;
  522.                             break;

  523.                         case 't':
  524.                             *dst++ = '\t';
  525.                             src += 2;
  526.                             continue;

  527.                         case 'r':
  528.                             *dst++ = '\r';
  529.                             src += 2;
  530.                             continue;

  531.                         case 'n':
  532.                             *dst++ = '\n';
  533.                             src += 2;
  534.                             continue;
  535.                         }

  536.                     }
  537.                     *dst++ = *src++;
  538.                 }
  539.                 *dst = '\0';
  540.                 word->len = len;

  541.                 if (ch == ';') {
  542.                     return NGX_OK;
  543.                 }

  544.                 if (ch == '{') {
  545.                     return NGX_CONF_BLOCK_START;
  546.                 }

  547.                 found = 0;
  548.             }
  549.         }
  550.     }
  551. }


  552. char *
  553. ngx_conf_include(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  554. {
  555.     char        *rv;
  556.     ngx_int_t    n;
  557.     ngx_str_t   *value, file, name;
  558.     ngx_glob_t   gl;

  559.     value = cf->args->elts;
  560.     file = value[1];

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

  562.     if (ngx_conf_full_name(cf->cycle, &file, 1) != NGX_OK) {
  563.         return NGX_CONF_ERROR;
  564.     }

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

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

  567.         return ngx_conf_parse(cf, &file);
  568.     }

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

  570.     gl.pattern = file.data;
  571.     gl.log = cf->log;
  572.     gl.test = 1;

  573.     if (ngx_open_glob(&gl) != NGX_OK) {
  574.         ngx_conf_log_error(NGX_LOG_EMERG, cf, ngx_errno,
  575.                            ngx_open_glob_n " \"%s\" failed", file.data);
  576.         return NGX_CONF_ERROR;
  577.     }

  578.     rv = NGX_CONF_OK;

  579.     for ( ;; ) {
  580.         n = ngx_read_glob(&gl, &name);

  581.         if (n != NGX_OK) {
  582.             break;
  583.         }

  584.         file.len = name.len++;
  585.         file.data = ngx_pstrdup(cf->pool, &name);
  586.         if (file.data == NULL) {
  587.             return NGX_CONF_ERROR;
  588.         }

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

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

  591.         if (rv != NGX_CONF_OK) {
  592.             break;
  593.         }
  594.     }

  595.     ngx_close_glob(&gl);

  596.     return rv;
  597. }


  598. ngx_int_t
  599. ngx_conf_full_name(ngx_cycle_t *cycle, ngx_str_t *name, ngx_uint_t conf_prefix)
  600. {
  601.     ngx_str_t  *prefix;

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

  603.     return ngx_get_full_name(cycle->pool, prefix, name);
  604. }


  605. ngx_open_file_t *
  606. ngx_conf_open_file(ngx_cycle_t *cycle, ngx_str_t *name)
  607. {
  608.     ngx_str_t         full;
  609.     ngx_uint_t        i;
  610.     ngx_list_part_t  *part;
  611.     ngx_open_file_t  *file;

  612. #if (NGX_SUPPRESS_WARN)
  613.     ngx_str_null(&full);
  614. #endif

  615.     if (name->len) {
  616.         full = *name;

  617.         if (ngx_conf_full_name(cycle, &full, 0) != NGX_OK) {
  618.             return NULL;
  619.         }

  620.         part = &cycle->open_files.part;
  621.         file = part->elts;

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

  623.             if (i >= part->nelts) {
  624.                 if (part->next == NULL) {
  625.                     break;
  626.                 }
  627.                 part = part->next;
  628.                 file = part->elts;
  629.                 i = 0;
  630.             }

  631.             if (full.len != file[i].name.len) {
  632.                 continue;
  633.             }

  634.             if (ngx_strcmp(full.data, file[i].name.data) == 0) {
  635.                 return &file[i];
  636.             }
  637.         }
  638.     }

  639.     file = ngx_list_push(&cycle->open_files);
  640.     if (file == NULL) {
  641.         return NULL;
  642.     }

  643.     if (name->len) {
  644.         file->fd = NGX_INVALID_FILE;
  645.         file->name = full;

  646.     } else {
  647.         file->fd = ngx_stderr;
  648.         file->name = *name;
  649.     }

  650.     file->flush = NULL;
  651.     file->data = NULL;

  652.     return file;
  653. }


  654. static void
  655. ngx_conf_flush_files(ngx_cycle_t *cycle)
  656. {
  657.     ngx_uint_t        i;
  658.     ngx_list_part_t  *part;
  659.     ngx_open_file_t  *file;

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

  661.     part = &cycle->open_files.part;
  662.     file = part->elts;

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

  664.         if (i >= part->nelts) {
  665.             if (part->next == NULL) {
  666.                 break;
  667.             }
  668.             part = part->next;
  669.             file = part->elts;
  670.             i = 0;
  671.         }

  672.         if (file[i].flush) {
  673.             file[i].flush(&file[i], cycle->log);
  674.         }
  675.     }
  676. }


  677. void ngx_cdecl
  678. ngx_conf_log_error(ngx_uint_t level, ngx_conf_t *cf, ngx_err_t err,
  679.     const char *fmt, ...)
  680. {
  681.     u_char   errstr[NGX_MAX_CONF_ERRSTR], *p, *last;
  682.     va_list  args;

  683.     last = errstr + NGX_MAX_CONF_ERRSTR;

  684.     va_start(args, fmt);
  685.     p = ngx_vslprintf(errstr, last, fmt, args);
  686.     va_end(args);

  687.     if (err) {
  688.         p = ngx_log_errno(p, last, err);
  689.     }

  690.     if (cf->conf_file == NULL) {
  691.         ngx_log_error(level, cf->log, 0, "%*s", p - errstr, errstr);
  692.         return;
  693.     }

  694.     if (cf->conf_file->file.fd == NGX_INVALID_FILE) {
  695.         ngx_log_error(level, cf->log, 0, "%*s in command line",
  696.                       p - errstr, errstr);
  697.         return;
  698.     }

  699.     ngx_log_error(level, cf->log, 0, "%*s in %s:%ui",
  700.                   p - errstr, errstr,
  701.                   cf->conf_file->file.name.data, cf->conf_file->line);
  702. }


  703. char *
  704. ngx_conf_set_flag_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  705. {
  706.     char  *p = conf;

  707.     ngx_str_t        *value;
  708.     ngx_flag_t       *fp;
  709.     ngx_conf_post_t  *post;

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

  711.     if (*fp != NGX_CONF_UNSET) {
  712.         return "is duplicate";
  713.     }

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

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

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

  719.     } else {
  720.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  721.                      "invalid value \"%s\" in \"%s\" directive, "
  722.                      "it must be \"on\" or \"off\"",
  723.                      value[1].data, cmd->name.data);
  724.         return NGX_CONF_ERROR;
  725.     }

  726.     if (cmd->post) {
  727.         post = cmd->post;
  728.         return post->post_handler(cf, post, fp);
  729.     }

  730.     return NGX_CONF_OK;
  731. }


  732. char *
  733. ngx_conf_set_str_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  734. {
  735.     char  *p = conf;

  736.     ngx_str_t        *field, *value;
  737.     ngx_conf_post_t  *post;

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

  739.     if (field->data) {
  740.         return "is duplicate";
  741.     }

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

  743.     *field = value[1];

  744.     if (cmd->post) {
  745.         post = cmd->post;
  746.         return post->post_handler(cf, post, field);
  747.     }

  748.     return NGX_CONF_OK;
  749. }


  750. char *
  751. ngx_conf_set_str_array_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  752. {
  753.     char  *p = conf;

  754.     ngx_str_t         *value, *s;
  755.     ngx_array_t      **a;
  756.     ngx_conf_post_t   *post;

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

  758.     if (*a == NGX_CONF_UNSET_PTR) {
  759.         *a = ngx_array_create(cf->pool, 4, sizeof(ngx_str_t));
  760.         if (*a == NULL) {
  761.             return NGX_CONF_ERROR;
  762.         }
  763.     }

  764.     s = ngx_array_push(*a);
  765.     if (s == NULL) {
  766.         return NGX_CONF_ERROR;
  767.     }

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

  769.     *s = value[1];

  770.     if (cmd->post) {
  771.         post = cmd->post;
  772.         return post->post_handler(cf, post, s);
  773.     }

  774.     return NGX_CONF_OK;
  775. }


  776. char *
  777. ngx_conf_set_keyval_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  778. {
  779.     char  *p = conf;

  780.     ngx_str_t         *value;
  781.     ngx_array_t      **a;
  782.     ngx_keyval_t      *kv;
  783.     ngx_conf_post_t   *post;

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

  785.     if (*a == NULL) {
  786.         *a = ngx_array_create(cf->pool, 4, sizeof(ngx_keyval_t));
  787.         if (*a == NULL) {
  788.             return NGX_CONF_ERROR;
  789.         }
  790.     }

  791.     kv = ngx_array_push(*a);
  792.     if (kv == NULL) {
  793.         return NGX_CONF_ERROR;
  794.     }

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

  796.     kv->key = value[1];
  797.     kv->value = value[2];

  798.     if (cmd->post) {
  799.         post = cmd->post;
  800.         return post->post_handler(cf, post, kv);
  801.     }

  802.     return NGX_CONF_OK;
  803. }


  804. char *
  805. ngx_conf_set_num_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  806. {
  807.     char  *p = conf;

  808.     ngx_int_t        *np;
  809.     ngx_str_t        *value;
  810.     ngx_conf_post_t  *post;


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

  812.     if (*np != NGX_CONF_UNSET) {
  813.         return "is duplicate";
  814.     }

  815.     value = cf->args->elts;
  816.     *np = ngx_atoi(value[1].data, value[1].len);
  817.     if (*np == NGX_ERROR) {
  818.         return "invalid number";
  819.     }

  820.     if (cmd->post) {
  821.         post = cmd->post;
  822.         return post->post_handler(cf, post, np);
  823.     }

  824.     return NGX_CONF_OK;
  825. }


  826. char *
  827. ngx_conf_set_size_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  828. {
  829.     char  *p = conf;

  830.     size_t           *sp;
  831.     ngx_str_t        *value;
  832.     ngx_conf_post_t  *post;


  833.     sp = (size_t *) (p + cmd->offset);
  834.     if (*sp != NGX_CONF_UNSET_SIZE) {
  835.         return "is duplicate";
  836.     }

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

  838.     *sp = ngx_parse_size(&value[1]);
  839.     if (*sp == (size_t) NGX_ERROR) {
  840.         return "invalid value";
  841.     }

  842.     if (cmd->post) {
  843.         post = cmd->post;
  844.         return post->post_handler(cf, post, sp);
  845.     }

  846.     return NGX_CONF_OK;
  847. }


  848. char *
  849. ngx_conf_set_off_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  850. {
  851.     char  *p = conf;

  852.     off_t            *op;
  853.     ngx_str_t        *value;
  854.     ngx_conf_post_t  *post;


  855.     op = (off_t *) (p + cmd->offset);
  856.     if (*op != NGX_CONF_UNSET) {
  857.         return "is duplicate";
  858.     }

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

  860.     *op = ngx_parse_offset(&value[1]);
  861.     if (*op == (off_t) NGX_ERROR) {
  862.         return "invalid value";
  863.     }

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

  868.     return NGX_CONF_OK;
  869. }


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

  874.     ngx_msec_t       *msp;
  875.     ngx_str_t        *value;
  876.     ngx_conf_post_t  *post;


  877.     msp = (ngx_msec_t *) (p + cmd->offset);
  878.     if (*msp != NGX_CONF_UNSET_MSEC) {
  879.         return "is duplicate";
  880.     }

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

  882.     *msp = ngx_parse_time(&value[1], 0);
  883.     if (*msp == (ngx_msec_t) NGX_ERROR) {
  884.         return "invalid value";
  885.     }

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

  890.     return NGX_CONF_OK;
  891. }


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

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


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

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

  904.     *sp = ngx_parse_time(&value[1], 1);
  905.     if (*sp == (time_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_bufs_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  916. {
  917.     char *p = conf;

  918.     ngx_str_t   *value;
  919.     ngx_bufs_t  *bufs;


  920.     bufs = (ngx_bufs_t *) (p + cmd->offset);
  921.     if (bufs->num) {
  922.         return "is duplicate";
  923.     }

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

  925.     bufs->num = ngx_atoi(value[1].data, value[1].len);
  926.     if (bufs->num == NGX_ERROR || bufs->num == 0) {
  927.         return "invalid value";
  928.     }

  929.     bufs->size = ngx_parse_size(&value[2]);
  930.     if (bufs->size == (size_t) NGX_ERROR || bufs->size == 0) {
  931.         return "invalid value";
  932.     }

  933.     return NGX_CONF_OK;
  934. }


  935. char *
  936. ngx_conf_set_enum_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  937. {
  938.     char  *p = conf;

  939.     ngx_uint_t       *np, i;
  940.     ngx_str_t        *value;
  941.     ngx_conf_enum_t  *e;

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

  943.     if (*np != NGX_CONF_UNSET_UINT) {
  944.         return "is duplicate";
  945.     }

  946.     value = cf->args->elts;
  947.     e = cmd->post;

  948.     for (i = 0; e[i].name.len != 0; i++) {
  949.         if (e[i].name.len != value[1].len
  950.             || ngx_strcasecmp(e[i].name.data, value[1].data) != 0)
  951.         {
  952.             continue;
  953.         }

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

  955.         return NGX_CONF_OK;
  956.     }

  957.     ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
  958.                        "invalid value \"%s\"", value[1].data);

  959.     return NGX_CONF_ERROR;
  960. }


  961. char *
  962. ngx_conf_set_bitmask_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  963. {
  964.     char  *p = conf;

  965.     ngx_uint_t          *np, i, m;
  966.     ngx_str_t           *value;
  967.     ngx_conf_bitmask_t  *mask;


  968.     np = (ngx_uint_t *) (p + cmd->offset);
  969.     value = cf->args->elts;
  970.     mask = cmd->post;

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

  973.             if (mask[m].name.len != value[i].len
  974.                 || ngx_strcasecmp(mask[m].name.data, value[i].data) != 0)
  975.             {
  976.                 continue;
  977.             }

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

  981.             } else {
  982.                 *np |= mask[m].mask;
  983.             }

  984.             break;
  985.         }

  986.         if (mask[m].name.len == 0) {
  987.             ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
  988.                                "invalid value \"%s\"", value[i].data);

  989.             return NGX_CONF_ERROR;
  990.         }
  991.     }

  992.     return NGX_CONF_OK;
  993. }


  994. #if 0

  995. char *
  996. ngx_conf_unsupported(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  997. {
  998.     return "unsupported on this platform";
  999. }

  1000. #endif


  1001. char *
  1002. ngx_conf_deprecated(ngx_conf_t *cf, void *post, void *data)
  1003. {
  1004.     ngx_conf_deprecated_t  *d = post;

  1005.     ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
  1006.                        "the \"%s\" directive is deprecated, "
  1007.                        "use the \"%s\" directive instead",
  1008.                        d->old_name, d->new_name);

  1009.     return NGX_CONF_OK;
  1010. }


  1011. char *
  1012. ngx_conf_check_num_bounds(ngx_conf_t *cf, void *post, void *data)
  1013. {
  1014.     ngx_conf_num_bounds_t  *bounds = post;
  1015.     ngx_int_t  *np = data;

  1016.     if (bounds->high == -1) {
  1017.         if (*np >= bounds->low) {
  1018.             return NGX_CONF_OK;
  1019.         }

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

  1023.         return NGX_CONF_ERROR;
  1024.     }

  1025.     if (*np >= bounds->low && *np <= bounds->high) {
  1026.         return NGX_CONF_OK;
  1027.     }

  1028.     ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  1029.                        "value must be between %i and %i",
  1030.                        bounds->low, bounds->high);

  1031.     return NGX_CONF_ERROR;
  1032. }