upstream nginx-0.7.31
[nginx.git] / nginx / src / core / ngx_cycle.c
1
2 /*
3  * Copyright (C) Igor Sysoev
4  */
5
6
7 #include <ngx_config.h>
8 #include <ngx_core.h>
9 #include <ngx_event.h>
10
11
12 static ngx_int_t ngx_test_lockfile(u_char *file, ngx_log_t *log);
13 static void ngx_destroy_cycle_pools(ngx_conf_t *conf);
14 static ngx_int_t ngx_cmp_sockaddr(struct sockaddr *sa1, struct sockaddr *sa2);
15 static void ngx_clean_old_cycles(ngx_event_t *ev);
16
17
18 volatile ngx_cycle_t  *ngx_cycle;
19 ngx_array_t            ngx_old_cycles;
20
21 static ngx_pool_t     *ngx_temp_pool;
22 static ngx_event_t     ngx_cleaner_event;
23
24 ngx_uint_t             ngx_test_config;
25
26 #if (NGX_THREADS)
27 ngx_tls_key_t          ngx_core_tls_key;
28 #endif
29
30
31 /* STUB NAME */
32 static ngx_connection_t  dumb;
33 /* STUB */
34
35 #ifdef NGX_ERROR_LOG_PATH
36 static ngx_str_t  error_log = ngx_string(NGX_ERROR_LOG_PATH);
37 #else
38 static ngx_str_t  error_log = ngx_null_string;
39 #endif
40
41
42 ngx_cycle_t *
43 ngx_init_cycle(ngx_cycle_t *old_cycle)
44 {
45     void                *rv;
46     char               **senv, **env;
47     u_char              *lock_file;
48     ngx_uint_t           i, n;
49     ngx_log_t           *log;
50     ngx_time_t          *tp;
51     ngx_conf_t           conf;
52     ngx_pool_t          *pool;
53     ngx_cycle_t         *cycle, **old;
54     ngx_shm_zone_t      *shm_zone, *oshm_zone;
55     ngx_slab_pool_t     *shpool;
56     ngx_list_part_t     *part, *opart;
57     ngx_open_file_t     *file;
58     ngx_listening_t     *ls, *nls;
59     ngx_core_conf_t     *ccf, *old_ccf;
60     ngx_core_module_t   *module;
61     char                 hostname[NGX_MAXHOSTNAMELEN];
62
63     ngx_timezone_update();
64
65     /* force localtime update with a new timezone */
66
67     tp = ngx_timeofday();
68     tp->sec = 0;
69
70     ngx_time_update(0, 0);
71
72
73     log = old_cycle->log;
74
75     pool = ngx_create_pool(NGX_CYCLE_POOL_SIZE, log);
76     if (pool == NULL) {
77         return NULL;
78     }
79     pool->log = log;
80
81     cycle = ngx_pcalloc(pool, sizeof(ngx_cycle_t));
82     if (cycle == NULL) {
83         ngx_destroy_pool(pool);
84         return NULL;
85     }
86
87     cycle->pool = pool;
88     cycle->log = log;
89     cycle->old_cycle = old_cycle;
90     cycle->root.len = sizeof(NGX_PREFIX) - 1;
91     cycle->root.data = (u_char *) NGX_PREFIX;
92
93
94     cycle->conf_file.len = old_cycle->conf_file.len;
95     cycle->conf_file.data = ngx_pnalloc(pool, old_cycle->conf_file.len + 1);
96     if (cycle->conf_file.data == NULL) {
97         ngx_destroy_pool(pool);
98         return NULL;
99     }
100     ngx_cpystrn(cycle->conf_file.data, old_cycle->conf_file.data,
101                 old_cycle->conf_file.len + 1);
102
103
104     cycle->conf_param.len = old_cycle->conf_param.len;
105     cycle->conf_param.data = ngx_pnalloc(pool, old_cycle->conf_param.len);
106     if (cycle->conf_param.data == NULL) {
107         ngx_destroy_pool(pool);
108         return NULL;
109     }
110     ngx_memcpy(cycle->conf_param.data, old_cycle->conf_param.data,
111                old_cycle->conf_param.len);
112
113
114     n = old_cycle->pathes.nelts ? old_cycle->pathes.nelts : 10;
115
116     cycle->pathes.elts = ngx_pcalloc(pool, n * sizeof(ngx_path_t *));
117     if (cycle->pathes.elts == NULL) {
118         ngx_destroy_pool(pool);
119         return NULL;
120     }
121
122     cycle->pathes.nelts = 0;
123     cycle->pathes.size = sizeof(ngx_path_t *);
124     cycle->pathes.nalloc = n;
125     cycle->pathes.pool = pool;
126
127
128     if (old_cycle->open_files.part.nelts) {
129         n = old_cycle->open_files.part.nelts;
130         for (part = old_cycle->open_files.part.next; part; part = part->next) {
131             n += part->nelts;
132         }
133
134     } else {
135         n = 20;
136     }
137
138     if (ngx_list_init(&cycle->open_files, pool, n, sizeof(ngx_open_file_t))
139         == NGX_ERROR)
140     {
141         ngx_destroy_pool(pool);
142         return NULL;
143     }
144
145
146     if (old_cycle->shared_memory.part.nelts) {
147         n = old_cycle->shared_memory.part.nelts;
148         for (part = old_cycle->shared_memory.part.next; part; part = part->next)
149         {
150             n += part->nelts;
151         }
152
153     } else {
154         n = 1;
155     }
156
157     if (ngx_list_init(&cycle->shared_memory, pool, n, sizeof(ngx_shm_zone_t))
158         == NGX_ERROR)
159     {
160         ngx_destroy_pool(pool);
161         return NULL;
162     }
163
164
165     cycle->new_log = ngx_log_create_errlog(cycle, NULL);
166     if (cycle->new_log == NULL) {
167         ngx_destroy_pool(pool);
168         return NULL;
169     }
170
171     cycle->new_log->file->name = error_log;
172
173
174     n = old_cycle->listening.nelts ? old_cycle->listening.nelts : 10;
175
176     cycle->listening.elts = ngx_pcalloc(pool, n * sizeof(ngx_listening_t));
177     if (cycle->listening.elts == NULL) {
178         ngx_destroy_pool(pool);
179         return NULL;
180     }
181
182     cycle->listening.nelts = 0;
183     cycle->listening.size = sizeof(ngx_listening_t);
184     cycle->listening.nalloc = n;
185     cycle->listening.pool = pool;
186
187
188     cycle->conf_ctx = ngx_pcalloc(pool, ngx_max_module * sizeof(void *));
189     if (cycle->conf_ctx == NULL) {
190         ngx_destroy_pool(pool);
191         return NULL;
192     }
193
194
195     if (gethostname(hostname, NGX_MAXHOSTNAMELEN) == -1) {
196         ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "gethostname() failed");
197         ngx_destroy_pool(pool);
198         return NULL;
199     }
200
201     /* on Linux gethostname() silently truncates name that does not fit */
202
203     hostname[NGX_MAXHOSTNAMELEN - 1] = '\0';
204     cycle->hostname.len = ngx_strlen(hostname);
205
206     cycle->hostname.data = ngx_pnalloc(pool, cycle->hostname.len);
207     if (cycle->hostname.data == NULL) {
208         ngx_destroy_pool(pool);
209         return NULL;
210     }
211
212     ngx_memcpy(cycle->hostname.data, hostname, cycle->hostname.len);
213
214
215     for (i = 0; ngx_modules[i]; i++) {
216         if (ngx_modules[i]->type != NGX_CORE_MODULE) {
217             continue;
218         }
219
220         module = ngx_modules[i]->ctx;
221
222         if (module->create_conf) {
223             rv = module->create_conf(cycle);
224             if (rv == NGX_CONF_ERROR) {
225                 ngx_destroy_pool(pool);
226                 return NULL;
227             }
228             cycle->conf_ctx[ngx_modules[i]->index] = rv;
229         }
230     }
231
232
233     senv = environ;
234
235
236     ngx_memzero(&conf, sizeof(ngx_conf_t));
237     /* STUB: init array ? */
238     conf.args = ngx_array_create(pool, 10, sizeof(ngx_str_t));
239     if (conf.args == NULL) {
240         ngx_destroy_pool(pool);
241         return NULL;
242     }
243
244     conf.temp_pool = ngx_create_pool(NGX_CYCLE_POOL_SIZE, log);
245     if (conf.temp_pool == NULL) {
246         ngx_destroy_pool(pool);
247         return NULL;
248     }
249
250
251     conf.ctx = cycle->conf_ctx;
252     conf.cycle = cycle;
253     conf.pool = pool;
254     conf.log = log;
255     conf.module_type = NGX_CORE_MODULE;
256     conf.cmd_type = NGX_MAIN_CONF;
257
258 #if 0
259     log->log_level = NGX_LOG_DEBUG_ALL;
260 #endif
261
262     if (ngx_conf_param(&conf) != NGX_CONF_OK) {
263         ngx_destroy_cycle_pools(&conf);
264         return NULL;
265     }
266
267     if (ngx_conf_parse(&conf, &cycle->conf_file) != NGX_CONF_OK) {
268         ngx_destroy_cycle_pools(&conf);
269         return NULL;
270     }
271
272     if (ngx_test_config) {
273         ngx_log_error(NGX_LOG_INFO, log, 0,
274                       "the configuration file %s syntax is ok",
275                       cycle->conf_file.data);
276     }
277
278
279     for (i = 0; ngx_modules[i]; i++) {
280         if (ngx_modules[i]->type != NGX_CORE_MODULE) {
281             continue;
282         }
283
284         module = ngx_modules[i]->ctx;
285
286         if (module->init_conf) {
287             if (module->init_conf(cycle, cycle->conf_ctx[ngx_modules[i]->index])
288                 == NGX_CONF_ERROR)
289             {
290                 ngx_destroy_cycle_pools(&conf);
291                 return NULL;
292             }
293         }
294     }
295
296
297     ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module);
298
299 #if !(NGX_WIN32)
300
301     if (ngx_test_config) {
302
303         if (ngx_create_pidfile(&ccf->pid, log) != NGX_OK) {
304             goto failed;
305         }
306
307     } else if (!ngx_is_init_cycle(old_cycle)) {
308
309         /*
310          * we do not create the pid file in the first ngx_init_cycle() call
311          * because we need to write the demonized process pid
312          */
313
314         old_ccf = (ngx_core_conf_t *) ngx_get_conf(old_cycle->conf_ctx,
315                                                    ngx_core_module);
316         if (ccf->pid.len != old_ccf->pid.len
317             || ngx_strcmp(ccf->pid.data, old_ccf->pid.data) != 0)
318         {
319             /* new pid file name */
320
321             if (ngx_create_pidfile(&ccf->pid, log) != NGX_OK) {
322                 goto failed;
323             }
324
325             ngx_delete_pidfile(old_cycle);
326         }
327     }
328
329 #endif
330
331
332     if (ngx_test_lockfile(cycle->lock_file.data, log) != NGX_OK) {
333         goto failed;
334     }
335
336
337     if (ngx_create_pathes(cycle, ccf->user) != NGX_OK) {
338         goto failed;
339     }
340
341
342     /* open the new files */
343
344     part = &cycle->open_files.part;
345     file = part->elts;
346
347     for (i = 0; /* void */ ; i++) {
348
349         if (i >= part->nelts) {
350             if (part->next == NULL) {
351                 break;
352             }
353             part = part->next;
354             file = part->elts;
355             i = 0;
356         }
357
358         if (file[i].name.data == NULL) {
359             continue;
360         }
361
362         file[i].fd = ngx_open_file(file[i].name.data, NGX_FILE_RDWR,
363                                    NGX_FILE_CREATE_OR_OPEN|NGX_FILE_APPEND,
364                                    NGX_FILE_DEFAULT_ACCESS);
365
366         ngx_log_debug3(NGX_LOG_DEBUG_CORE, log, 0,
367                        "log: %p %d \"%s\"",
368                        &file[i], file[i].fd, file[i].name.data);
369
370         if (file[i].fd == NGX_INVALID_FILE) {
371             ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,
372                           ngx_open_file_n " \"%s\" failed",
373                           file[i].name.data);
374             goto failed;
375         }
376
377 #if (NGX_WIN32)
378         if (ngx_file_append_mode(file[i].fd) != NGX_OK) {
379             ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,
380                           ngx_file_append_mode_n " \"%s\" failed",
381                           file[i].name.data);
382             goto failed;
383         }
384 #else
385         if (fcntl(file[i].fd, F_SETFD, FD_CLOEXEC) == -1) {
386             ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,
387                           "fcntl(FD_CLOEXEC) \"%s\" failed",
388                           file[i].name.data);
389             goto failed;
390         }
391 #endif
392     }
393
394     cycle->log = cycle->new_log;
395     pool->log = cycle->new_log;
396
397
398     /* create shared memory */
399
400     part = &cycle->shared_memory.part;
401     shm_zone = part->elts;
402
403     for (i = 0; /* void */ ; i++) {
404
405         if (i >= part->nelts) {
406             if (part->next == NULL) {
407                 break;
408             }
409             part = part->next;
410             shm_zone = part->elts;
411             i = 0;
412         }
413
414         if (shm_zone[i].shm.size == 0) {
415             ngx_log_error(NGX_LOG_EMERG, log, 0,
416                           "zero size shared memory zone \"%V\"",
417                           &shm_zone[i].name);
418             goto failed;
419         }
420
421         if (shm_zone[i].init == NULL) {
422             /* unused shared zone */
423             continue;
424         }
425
426         shm_zone[i].shm.log = cycle->log;
427
428         opart = &old_cycle->shared_memory.part;
429         oshm_zone = opart->elts;
430
431         for (n = 0; /* void */ ; n++) {
432
433             if (n >= opart->nelts) {
434                 if (opart->next == NULL) {
435                     break;
436                 }
437                 opart = opart->next;
438                 oshm_zone = opart->elts;
439                 n = 0;
440             }
441
442             if (shm_zone[i].name.len != oshm_zone[n].name.len) {
443                 continue;
444             }
445
446             if (ngx_strncmp(shm_zone[i].name.data, oshm_zone[n].name.data,
447                             shm_zone[i].name.len)
448                 != 0)
449             {
450                 continue;
451             }
452
453             if (shm_zone[i].shm.size == oshm_zone[n].shm.size) {
454                 shm_zone[i].shm.addr = oshm_zone[n].shm.addr;
455
456                 if (shm_zone[i].init(&shm_zone[i], oshm_zone[n].data)
457                     != NGX_OK)
458                 {
459                     goto failed;
460                 }
461
462                 goto shm_zone_found;
463             }
464
465             ngx_shm_free(&oshm_zone[n].shm);
466
467             break;
468         }
469
470         if (ngx_shm_alloc(&shm_zone[i].shm) != NGX_OK) {
471             goto failed;
472         }
473
474         shpool = (ngx_slab_pool_t *) shm_zone[i].shm.addr;
475
476         shpool->end = shm_zone[i].shm.addr + shm_zone[i].shm.size;
477         shpool->min_shift = 3;
478
479 #if (NGX_HAVE_ATOMIC_OPS)
480
481         lock_file = NULL;
482
483 #else
484
485         lock_file = ngx_pnalloc(cycle->pool,
486                                 cycle->lock_file.len + shm_zone[i].name.len);
487
488         if (lock_file == NULL) {
489             goto failed;
490         }
491
492         (void) ngx_cpystrn(ngx_cpymem(lock_file, cycle->lock_file.data,
493                                       cycle->lock_file.len),
494                            shm_zone[i].name.data, shm_zone[i].name.len + 1);
495
496 #endif
497
498         if (ngx_shmtx_create(&shpool->mutex, (void *) &shpool->lock, lock_file)
499             != NGX_OK)
500         {
501             goto failed;
502         }
503
504         ngx_slab_init(shpool);
505
506         if (shm_zone[i].init(&shm_zone[i], NULL) != NGX_OK) {
507             goto failed;
508         }
509
510     shm_zone_found:
511
512         continue;
513     }
514
515
516     /* handle the listening sockets */
517
518     if (old_cycle->listening.nelts) {
519         ls = old_cycle->listening.elts;
520         for (i = 0; i < old_cycle->listening.nelts; i++) {
521             ls[i].remain = 0;
522         }
523
524         nls = cycle->listening.elts;
525         for (n = 0; n < cycle->listening.nelts; n++) {
526
527             for (i = 0; i < old_cycle->listening.nelts; i++) {
528                 if (ls[i].ignore) {
529                     continue;
530                 }
531
532                 if (ngx_cmp_sockaddr(nls[n].sockaddr, ls[i].sockaddr) == NGX_OK)
533                 {
534                     nls[n].fd = ls[i].fd;
535                     nls[n].previous = &ls[i];
536                     ls[i].remain = 1;
537
538                     if (ls[n].backlog != nls[i].backlog) {
539                         nls[n].listen = 1;
540                     }
541
542 #if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER)
543
544                     /*
545                      * FreeBSD, except the most recent versions,
546                      * could not remove accept filter
547                      */
548                     nls[n].deferred_accept = ls[i].deferred_accept;
549
550                     if (ls[i].accept_filter && nls[n].accept_filter) {
551                         if (ngx_strcmp(ls[i].accept_filter,
552                                        nls[n].accept_filter)
553                             != 0)
554                         {
555                             nls[n].delete_deferred = 1;
556                             nls[n].add_deferred = 1;
557                         }
558
559                     } else if (ls[i].accept_filter) {
560                         nls[n].delete_deferred = 1;
561
562                     } else if (nls[n].accept_filter) {
563                         nls[n].add_deferred = 1;
564                     }
565 #endif
566
567 #if (NGX_HAVE_DEFERRED_ACCEPT && defined TCP_DEFER_ACCEPT)
568
569                     if (ls[n].deferred_accept && !nls[n].deferred_accept) {
570                         nls[n].delete_deferred = 1;
571
572                     } else if (ls[i].deferred_accept != nls[n].deferred_accept)
573                     {
574                         nls[n].add_deferred = 1;
575                     }
576 #endif
577                     break;
578                 }
579             }
580
581             if (nls[n].fd == -1) {
582                 nls[n].open = 1;
583             }
584         }
585
586     } else {
587         ls = cycle->listening.elts;
588         for (i = 0; i < cycle->listening.nelts; i++) {
589             ls[i].open = 1;
590 #if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER)
591             if (ls[i].accept_filter) {
592                 ls[i].add_deferred = 1;
593             }
594 #endif
595 #if (NGX_HAVE_DEFERRED_ACCEPT && defined TCP_DEFER_ACCEPT)
596             if (ls[i].deferred_accept) {
597                 ls[i].add_deferred = 1;
598             }
599 #endif
600         }
601     }
602
603     if (ngx_open_listening_sockets(cycle) != NGX_OK) {
604         goto failed;
605     }
606
607     if (!ngx_test_config) {
608         ngx_configure_listening_socket(cycle);
609     }
610
611
612     /* commit the new cycle configuration */
613
614 #if !(NGX_WIN32)
615
616     if (!ngx_test_config && cycle->log->file->fd != STDERR_FILENO) {
617
618         ngx_log_debug3(NGX_LOG_DEBUG_CORE, log, 0,
619                        "dup2: %p %d \"%s\"",
620                        cycle->log->file,
621                        cycle->log->file->fd, cycle->log->file->name.data);
622
623         if (dup2(cycle->log->file->fd, STDERR_FILENO) == -1) {
624             ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,
625                           "dup2(STDERR) failed");
626             /* fatal */
627             exit(1);
628         }
629     }
630
631 #endif
632
633     pool->log = cycle->log;
634
635     for (i = 0; ngx_modules[i]; i++) {
636         if (ngx_modules[i]->init_module) {
637             if (ngx_modules[i]->init_module(cycle) != NGX_OK) {
638                 /* fatal */
639                 exit(1);
640             }
641         }
642     }
643
644
645     /* close and delete stuff that lefts from an old cycle */
646
647     /* free the unnecessary shared memory */
648
649     opart = &old_cycle->shared_memory.part;
650     oshm_zone = opart->elts;
651
652     for (i = 0; /* void */ ; i++) {
653
654         if (i >= opart->nelts) {
655             if (opart->next == NULL) {
656                 goto old_shm_zone_done;
657             }
658             opart = opart->next;
659             oshm_zone = opart->elts;
660             i = 0;
661         }
662
663         part = &cycle->shared_memory.part;
664         shm_zone = part->elts;
665
666         for (n = 0; /* void */ ; n++) {
667
668             if (n >= part->nelts) {
669                 if (part->next == NULL) {
670                     break;
671                 }
672                 part = part->next;
673                 shm_zone = part->elts;
674                 n = 0;
675             }
676
677             if (oshm_zone[i].name.len == shm_zone[n].name.len
678                 && ngx_strncmp(oshm_zone[i].name.data,
679                                shm_zone[n].name.data,
680                                oshm_zone[i].name.len)
681                 == 0)
682             {
683                 goto live_shm_zone;
684             }
685         }
686
687         ngx_shm_free(&oshm_zone[i].shm);
688
689     live_shm_zone:
690
691         continue;
692     }
693
694 old_shm_zone_done:
695
696
697     /* close the unnecessary listening sockets */
698
699     ls = old_cycle->listening.elts;
700     for (i = 0; i < old_cycle->listening.nelts; i++) {
701         if (ls[i].remain) {
702             continue;
703         }
704
705         if (ngx_close_socket(ls[i].fd) == -1) {
706             ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,
707                           ngx_close_socket_n " listening socket on %V failed",
708                           &ls[i].addr_text);
709         }
710     }
711
712
713     /* close the unnecessary open files */
714
715     part = &old_cycle->open_files.part;
716     file = part->elts;
717
718     for (i = 0; /* void */ ; i++) {
719
720         if (i >= part->nelts) {
721             if (part->next == NULL) {
722                 break;
723             }
724             part = part->next;
725             file = part->elts;
726             i = 0;
727         }
728
729         if (file[i].fd == NGX_INVALID_FILE || file[i].fd == ngx_stderr_fileno) {
730             continue;
731         }
732
733         if (ngx_close_file(file[i].fd) == NGX_FILE_ERROR) {
734             ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,
735                           ngx_close_file_n " \"%s\" failed",
736                           file[i].name.data);
737         }
738     }
739
740     ngx_destroy_pool(conf.temp_pool);
741
742     if (ngx_process == NGX_PROCESS_MASTER || ngx_is_init_cycle(old_cycle)) {
743
744         /*
745          * perl_destruct() frees environ if it is not the same as it was at
746          * perl_construct() time.  So we have saved an previous cycle
747          * environment before ngx_conf_parse() where it will be changed.
748          */
749
750         env = environ;
751         environ = senv;
752
753         ngx_destroy_pool(old_cycle->pool);
754         cycle->old_cycle = NULL;
755
756         environ = env;
757
758         return cycle;
759     }
760
761
762     if (ngx_temp_pool == NULL) {
763         ngx_temp_pool = ngx_create_pool(128, cycle->log);
764         if (ngx_temp_pool == NULL) {
765             ngx_log_error(NGX_LOG_EMERG, cycle->log, 0,
766                           "can not create ngx_temp_pool");
767             exit(1);
768         }
769
770         n = 10;
771         ngx_old_cycles.elts = ngx_pcalloc(ngx_temp_pool,
772                                           n * sizeof(ngx_cycle_t *));
773         if (ngx_old_cycles.elts == NULL) {
774             exit(1);
775         }
776         ngx_old_cycles.nelts = 0;
777         ngx_old_cycles.size = sizeof(ngx_cycle_t *);
778         ngx_old_cycles.nalloc = n;
779         ngx_old_cycles.pool = ngx_temp_pool;
780
781         ngx_cleaner_event.handler = ngx_clean_old_cycles;
782         ngx_cleaner_event.log = cycle->log;
783         ngx_cleaner_event.data = &dumb;
784         dumb.fd = (ngx_socket_t) -1;
785     }
786
787     ngx_temp_pool->log = cycle->log;
788
789     old = ngx_array_push(&ngx_old_cycles);
790     if (old == NULL) {
791         exit(1);
792     }
793     *old = old_cycle;
794
795     if (!ngx_cleaner_event.timer_set) {
796         ngx_add_timer(&ngx_cleaner_event, 30000);
797         ngx_cleaner_event.timer_set = 1;
798     }
799
800     return cycle;
801
802
803 failed:
804
805     if (!ngx_is_init_cycle(old_cycle)) {
806         old_ccf = (ngx_core_conf_t *) ngx_get_conf(old_cycle->conf_ctx,
807                                                    ngx_core_module);
808         if (old_ccf->environment) {
809             environ = old_ccf->environment;
810         }
811     }
812
813     /* rollback the new cycle configuration */
814
815     part = &cycle->open_files.part;
816     file = part->elts;
817
818     for (i = 0; /* void */ ; i++) {
819
820         if (i >= part->nelts) {
821             if (part->next == NULL) {
822                 break;
823             }
824             part = part->next;
825             file = part->elts;
826             i = 0;
827         }
828
829         if (file[i].fd == NGX_INVALID_FILE || file[i].fd == ngx_stderr_fileno) {
830             continue;
831         }
832
833         if (ngx_close_file(file[i].fd) == NGX_FILE_ERROR) {
834             ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,
835                           ngx_close_file_n " \"%s\" failed",
836                           file[i].name.data);
837         }
838     }
839
840     if (ngx_test_config) {
841         ngx_destroy_cycle_pools(&conf);
842         return NULL;
843     }
844
845     ls = cycle->listening.elts;
846     for (i = 0; i < cycle->listening.nelts; i++) {
847         if (ls[i].fd == -1 || !ls[i].open) {
848             continue;
849         }
850
851         if (ngx_close_socket(ls[i].fd) == -1) {
852             ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,
853                           ngx_close_socket_n " %V failed",
854                           &ls[i].addr_text);
855         }
856     }
857
858     ngx_destroy_cycle_pools(&conf);
859
860     return NULL;
861 }
862
863
864 static void
865 ngx_destroy_cycle_pools(ngx_conf_t *conf)
866 {
867     ngx_destroy_pool(conf->temp_pool);
868     ngx_destroy_pool(conf->pool);
869 }
870
871
872 static ngx_int_t
873 ngx_cmp_sockaddr(struct sockaddr *sa1, struct sockaddr *sa2)
874 {
875     struct sockaddr_in  *sin1, *sin2;
876
877     /* AF_INET only */
878
879     if (sa1->sa_family != AF_INET || sa2->sa_family != AF_INET) {
880         return NGX_DECLINED;
881     }
882
883     sin1 = (struct sockaddr_in *) sa1;
884     sin2 = (struct sockaddr_in *) sa2;
885
886     if (sin1->sin_addr.s_addr != sin2->sin_addr.s_addr) {
887         return NGX_DECLINED;
888     }
889
890     if (sin1->sin_port != sin2->sin_port) {
891         return NGX_DECLINED;
892     }
893
894     return NGX_OK;
895 }
896
897
898 #if !(NGX_WIN32)
899
900 ngx_int_t
901 ngx_create_pidfile(ngx_str_t *name, ngx_log_t *log)
902 {
903     size_t            len;
904     ngx_uint_t        trunc;
905     ngx_file_t        file;
906     u_char            pid[NGX_INT64_LEN + 2];
907
908     ngx_memzero(&file, sizeof(ngx_file_t));
909
910     file.name = *name;
911     file.log = log;
912
913     trunc = ngx_test_config ? 0 : NGX_FILE_TRUNCATE;
914
915     file.fd = ngx_open_file(file.name.data, NGX_FILE_RDWR,
916                             NGX_FILE_CREATE_OR_OPEN|trunc,
917                             NGX_FILE_DEFAULT_ACCESS);
918
919     if (file.fd == NGX_INVALID_FILE) {
920         ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,
921                       ngx_open_file_n " \"%s\" failed", file.name.data);
922         return NGX_ERROR;
923     }
924
925     if (!ngx_test_config) {
926         len = ngx_snprintf(pid, NGX_INT64_LEN + 2, "%P%N", ngx_pid) - pid;
927
928         if (ngx_write_file(&file, pid, len, 0) == NGX_ERROR) {
929             return NGX_ERROR;
930         }
931     }
932
933     if (ngx_close_file(file.fd) == NGX_FILE_ERROR) {
934         ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
935                       ngx_close_file_n " \"%s\" failed", file.name.data);
936     }
937
938     return NGX_OK;
939 }
940
941
942 void
943 ngx_delete_pidfile(ngx_cycle_t *cycle)
944 {
945     u_char           *name;
946     ngx_core_conf_t  *ccf;
947
948     ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module);
949
950     name = ngx_new_binary ? ccf->oldpid.data : ccf->pid.data;
951
952     if (ngx_delete_file(name) == NGX_FILE_ERROR) {
953         ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
954                       ngx_delete_file_n " \"%s\" failed", name);
955     }
956 }
957
958 #endif
959
960
961 static ngx_int_t
962 ngx_test_lockfile(u_char *file, ngx_log_t *log)
963 {
964 #if !(NGX_HAVE_ATOMIC_OPS)
965     ngx_fd_t  fd;
966
967     fd = ngx_open_file(file, NGX_FILE_RDWR, NGX_FILE_CREATE_OR_OPEN,
968                        NGX_FILE_DEFAULT_ACCESS);
969
970     if (fd == NGX_INVALID_FILE) {
971         ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,
972                       ngx_open_file_n " \"%s\" failed", file);
973         return NGX_ERROR;
974     }
975
976     if (ngx_close_file(fd) == NGX_FILE_ERROR) {
977         ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
978                       ngx_close_file_n " \"%s\" failed", file);
979     }
980
981     if (ngx_delete_file(file) == NGX_FILE_ERROR) {
982         ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
983                       ngx_delete_file_n " \"%s\" failed", file);
984     }
985
986 #endif
987
988     return NGX_OK;
989 }
990
991
992 void
993 ngx_reopen_files(ngx_cycle_t *cycle, ngx_uid_t user)
994 {
995     ssize_t           n, len;
996     ngx_fd_t          fd;
997     ngx_uint_t        i;
998     ngx_list_part_t  *part;
999     ngx_open_file_t  *file;
1000
1001     part = &cycle->open_files.part;
1002     file = part->elts;
1003
1004     for (i = 0; /* void */ ; i++) {
1005
1006         if (i >= part->nelts) {
1007             if (part->next == NULL) {
1008                 break;
1009             }
1010             part = part->next;
1011             file = part->elts;
1012             i = 0;
1013         }
1014
1015         if (file[i].name.data == NULL) {
1016             continue;
1017         }
1018
1019         len = file[i].pos - file[i].buffer;
1020
1021         if (file[i].buffer && len != 0) {
1022
1023             n = ngx_write_fd(file[i].fd, file[i].buffer, len);
1024
1025             if (n == NGX_FILE_ERROR) {
1026                 ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
1027                               ngx_write_fd_n " to \"%s\" failed",
1028                               file[i].name.data);
1029
1030             } else if (n != len) {
1031                 ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
1032                           ngx_write_fd_n " to \"%s\" was incomplete: %z of %uz",
1033                           file[i].name.data, n, len);
1034             }
1035
1036             file[i].pos = file[i].buffer;
1037         }
1038
1039         fd = ngx_open_file(file[i].name.data, NGX_FILE_RDWR,
1040                            NGX_FILE_CREATE_OR_OPEN|NGX_FILE_APPEND,
1041                            NGX_FILE_DEFAULT_ACCESS);
1042
1043         ngx_log_debug3(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
1044                        "reopen file \"%s\", old:%d new:%d",
1045                        file[i].name.data, file[i].fd, fd);
1046
1047         if (fd == NGX_INVALID_FILE) {
1048             ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
1049                           ngx_open_file_n " \"%s\" failed", file[i].name.data);
1050             continue;
1051         }
1052
1053 #if (NGX_WIN32)
1054         if (ngx_file_append_mode(fd) == NGX_ERROR) {
1055             ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
1056                           ngx_file_append_mode_n " \"%s\" failed",
1057                           file[i].name.data);
1058
1059             if (ngx_close_file(fd) == NGX_FILE_ERROR) {
1060                 ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
1061                               ngx_close_file_n " \"%s\" failed",
1062                               file[i].name.data);
1063             }
1064
1065             continue;
1066         }
1067 #else
1068         if (user != (ngx_uid_t) NGX_CONF_UNSET_UINT) {
1069             ngx_file_info_t  fi;
1070
1071             if (ngx_file_info((const char *) file[i].name.data, &fi) == -1) {
1072                 ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
1073                               ngx_file_info_n " \"%s\" failed",
1074                               file[i].name.data);
1075
1076                 if (ngx_close_file(fd) == NGX_FILE_ERROR) {
1077                     ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
1078                                   ngx_close_file_n " \"%s\" failed",
1079                                   file[i].name.data);
1080                 }
1081             }
1082
1083             if (fi.st_uid != user) {
1084                 if (chown((const char *) file[i].name.data, user, -1) == -1) {
1085                     ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
1086                                   "chown(\"%s\", %d) failed",
1087                                   file[i].name.data, user);
1088
1089                     if (ngx_close_file(fd) == NGX_FILE_ERROR) {
1090                         ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
1091                                       ngx_close_file_n " \"%s\" failed",
1092                                       file[i].name.data);
1093                     }
1094                 }
1095             }
1096
1097             if ((fi.st_mode & (S_IRUSR|S_IWUSR)) != (S_IRUSR|S_IWUSR)) {
1098
1099                 fi.st_mode |= (S_IRUSR|S_IWUSR);
1100
1101                 if (chmod((const char *) file[i].name.data, fi.st_mode) == -1) {
1102                     ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
1103                                   "chmod() \"%s\" failed", file[i].name.data);
1104
1105                     if (ngx_close_file(fd) == NGX_FILE_ERROR) {
1106                         ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
1107                                       ngx_close_file_n " \"%s\" failed",
1108                                       file[i].name.data);
1109                     }
1110                 }
1111             }
1112         }
1113
1114         if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) {
1115             ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
1116                           "fcntl(FD_CLOEXEC) \"%s\" failed",
1117                           file[i].name.data);
1118
1119             if (ngx_close_file(fd) == NGX_FILE_ERROR) {
1120                 ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
1121                               ngx_close_file_n " \"%s\" failed",
1122                               file[i].name.data);
1123             }
1124
1125             continue;
1126         }
1127 #endif
1128
1129         if (ngx_close_file(file[i].fd) == NGX_FILE_ERROR) {
1130             ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
1131                           ngx_close_file_n " \"%s\" failed",
1132                           file[i].name.data);
1133         }
1134
1135         file[i].fd = fd;
1136     }
1137
1138 #if !(NGX_WIN32)
1139
1140     if (cycle->log->file->fd != STDERR_FILENO) {
1141         if (dup2(cycle->log->file->fd, STDERR_FILENO) == -1) {
1142             ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
1143                           "dup2(STDERR) failed");
1144         }
1145     }
1146
1147 #endif
1148 }
1149
1150
1151 ngx_shm_zone_t *
1152 ngx_shared_memory_add(ngx_conf_t *cf, ngx_str_t *name, size_t size, void *tag)
1153 {
1154     ngx_uint_t        i;
1155     ngx_shm_zone_t   *shm_zone;
1156     ngx_list_part_t  *part;
1157
1158     part = &cf->cycle->shared_memory.part;
1159     shm_zone = part->elts;
1160
1161     for (i = 0; /* void */ ; i++) {
1162
1163         if (i >= part->nelts) {
1164             if (part->next == NULL) {
1165                 break;
1166             }
1167             part = part->next;
1168             shm_zone = part->elts;
1169             i = 0;
1170         }
1171
1172         if (name->len != shm_zone[i].name.len) {
1173             continue;
1174         }
1175
1176         if (ngx_strncmp(name->data, shm_zone[i].name.data, name->len) != 0) {
1177             continue;
1178         }
1179
1180         if (size && size != shm_zone[i].shm.size) {
1181             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1182                                "the size %uz of shared memory zone \"%V\" "
1183                                "conflicts with already declared size %uz",
1184                                size, &shm_zone[i].name, shm_zone[i].shm.size);
1185             return NULL;
1186         }
1187
1188         if (tag != shm_zone[i].tag) {
1189             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1190                                "the shared memory zone \"%V\" is "
1191                                "already declared for a different use",
1192                                &shm_zone[i].name);
1193             return NULL;
1194         }
1195
1196         return &shm_zone[i];
1197     }
1198
1199     shm_zone = ngx_list_push(&cf->cycle->shared_memory);
1200
1201     if (shm_zone == NULL) {
1202         return NULL;
1203     }
1204
1205     shm_zone->data = NULL;
1206     shm_zone->shm.log = cf->cycle->log;
1207     shm_zone->shm.size = size;
1208     shm_zone->init = NULL;
1209     shm_zone->name = *name;
1210     shm_zone->tag = tag;
1211
1212     return shm_zone;
1213 }
1214
1215
1216 static void
1217 ngx_clean_old_cycles(ngx_event_t *ev)
1218 {
1219     ngx_uint_t     i, n, found, live;
1220     ngx_log_t     *log;
1221     ngx_cycle_t  **cycle;
1222
1223     log = ngx_cycle->log;
1224     ngx_temp_pool->log = log;
1225
1226     ngx_log_debug0(NGX_LOG_DEBUG_CORE, log, 0, "clean old cycles");
1227
1228     live = 0;
1229
1230     cycle = ngx_old_cycles.elts;
1231     for (i = 0; i < ngx_old_cycles.nelts; i++) {
1232
1233         if (cycle[i] == NULL) {
1234             continue;
1235         }
1236
1237         found = 0;
1238
1239         for (n = 0; n < cycle[i]->connection_n; n++) {
1240             if (cycle[i]->connections[n].fd != (ngx_socket_t) -1) {
1241                 found = 1;
1242
1243                 ngx_log_debug1(NGX_LOG_DEBUG_CORE, log, 0, "live fd:%d", n);
1244
1245                 break;
1246             }
1247         }
1248
1249         if (found) {
1250             live = 1;
1251             continue;
1252         }
1253
1254         ngx_log_debug1(NGX_LOG_DEBUG_CORE, log, 0, "clean old cycle: %d", i);
1255
1256         ngx_destroy_pool(cycle[i]->pool);
1257         cycle[i] = NULL;
1258     }
1259
1260     ngx_log_debug1(NGX_LOG_DEBUG_CORE, log, 0, "old cycles status: %d", live);
1261
1262     if (live) {
1263         ngx_add_timer(ev, 30000);
1264
1265     } else {
1266         ngx_destroy_pool(ngx_temp_pool);
1267         ngx_temp_pool = NULL;
1268         ngx_old_cycles.nelts = 0;
1269     }
1270 }