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