upstream nginx-0.7.36
[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     if (cycle->log->log_level == 0) {
398         cycle->log->log_level = NGX_LOG_ERR;
399     }
400
401
402     /* create shared memory */
403
404     part = &cycle->shared_memory.part;
405     shm_zone = part->elts;
406
407     for (i = 0; /* void */ ; i++) {
408
409         if (i >= part->nelts) {
410             if (part->next == NULL) {
411                 break;
412             }
413             part = part->next;
414             shm_zone = part->elts;
415             i = 0;
416         }
417
418         if (shm_zone[i].shm.size == 0) {
419             ngx_log_error(NGX_LOG_EMERG, log, 0,
420                           "zero size shared memory zone \"%V\"",
421                           &shm_zone[i].name);
422             goto failed;
423         }
424
425         if (shm_zone[i].init == NULL) {
426             /* unused shared zone */
427             continue;
428         }
429
430         shm_zone[i].shm.log = cycle->log;
431
432         opart = &old_cycle->shared_memory.part;
433         oshm_zone = opart->elts;
434
435         for (n = 0; /* void */ ; n++) {
436
437             if (n >= opart->nelts) {
438                 if (opart->next == NULL) {
439                     break;
440                 }
441                 opart = opart->next;
442                 oshm_zone = opart->elts;
443                 n = 0;
444             }
445
446             if (shm_zone[i].name.len != oshm_zone[n].name.len) {
447                 continue;
448             }
449
450             if (ngx_strncmp(shm_zone[i].name.data, oshm_zone[n].name.data,
451                             shm_zone[i].name.len)
452                 != 0)
453             {
454                 continue;
455             }
456
457             if (shm_zone[i].shm.size == oshm_zone[n].shm.size) {
458                 shm_zone[i].shm.addr = oshm_zone[n].shm.addr;
459
460                 if (shm_zone[i].init(&shm_zone[i], oshm_zone[n].data)
461                     != NGX_OK)
462                 {
463                     goto failed;
464                 }
465
466                 goto shm_zone_found;
467             }
468
469             ngx_shm_free(&oshm_zone[n].shm);
470
471             break;
472         }
473
474         if (ngx_shm_alloc(&shm_zone[i].shm) != NGX_OK) {
475             goto failed;
476         }
477
478         shpool = (ngx_slab_pool_t *) shm_zone[i].shm.addr;
479
480         shpool->end = shm_zone[i].shm.addr + shm_zone[i].shm.size;
481         shpool->min_shift = 3;
482
483 #if (NGX_HAVE_ATOMIC_OPS)
484
485         lock_file = NULL;
486
487 #else
488
489         lock_file = ngx_pnalloc(cycle->pool,
490                                 cycle->lock_file.len + shm_zone[i].name.len);
491
492         if (lock_file == NULL) {
493             goto failed;
494         }
495
496         (void) ngx_cpystrn(ngx_cpymem(lock_file, cycle->lock_file.data,
497                                       cycle->lock_file.len),
498                            shm_zone[i].name.data, shm_zone[i].name.len + 1);
499
500 #endif
501
502         if (ngx_shmtx_create(&shpool->mutex, (void *) &shpool->lock, lock_file)
503             != NGX_OK)
504         {
505             goto failed;
506         }
507
508         ngx_slab_init(shpool);
509
510         if (shm_zone[i].init(&shm_zone[i], NULL) != NGX_OK) {
511             goto failed;
512         }
513
514     shm_zone_found:
515
516         continue;
517     }
518
519
520     /* handle the listening sockets */
521
522     if (old_cycle->listening.nelts) {
523         ls = old_cycle->listening.elts;
524         for (i = 0; i < old_cycle->listening.nelts; i++) {
525             ls[i].remain = 0;
526         }
527
528         nls = cycle->listening.elts;
529         for (n = 0; n < cycle->listening.nelts; n++) {
530
531             for (i = 0; i < old_cycle->listening.nelts; i++) {
532                 if (ls[i].ignore) {
533                     continue;
534                 }
535
536                 if (ngx_cmp_sockaddr(nls[n].sockaddr, ls[i].sockaddr) == NGX_OK)
537                 {
538                     nls[n].fd = ls[i].fd;
539                     nls[n].previous = &ls[i];
540                     ls[i].remain = 1;
541
542                     if (ls[n].backlog != nls[i].backlog) {
543                         nls[n].listen = 1;
544                     }
545
546 #if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER)
547
548                     /*
549                      * FreeBSD, except the most recent versions,
550                      * could not remove accept filter
551                      */
552                     nls[n].deferred_accept = ls[i].deferred_accept;
553
554                     if (ls[i].accept_filter && nls[n].accept_filter) {
555                         if (ngx_strcmp(ls[i].accept_filter,
556                                        nls[n].accept_filter)
557                             != 0)
558                         {
559                             nls[n].delete_deferred = 1;
560                             nls[n].add_deferred = 1;
561                         }
562
563                     } else if (ls[i].accept_filter) {
564                         nls[n].delete_deferred = 1;
565
566                     } else if (nls[n].accept_filter) {
567                         nls[n].add_deferred = 1;
568                     }
569 #endif
570
571 #if (NGX_HAVE_DEFERRED_ACCEPT && defined TCP_DEFER_ACCEPT)
572
573                     if (ls[n].deferred_accept && !nls[n].deferred_accept) {
574                         nls[n].delete_deferred = 1;
575
576                     } else if (ls[i].deferred_accept != nls[n].deferred_accept)
577                     {
578                         nls[n].add_deferred = 1;
579                     }
580 #endif
581                     break;
582                 }
583             }
584
585             if (nls[n].fd == -1) {
586                 nls[n].open = 1;
587             }
588         }
589
590     } else {
591         ls = cycle->listening.elts;
592         for (i = 0; i < cycle->listening.nelts; i++) {
593             ls[i].open = 1;
594 #if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER)
595             if (ls[i].accept_filter) {
596                 ls[i].add_deferred = 1;
597             }
598 #endif
599 #if (NGX_HAVE_DEFERRED_ACCEPT && defined TCP_DEFER_ACCEPT)
600             if (ls[i].deferred_accept) {
601                 ls[i].add_deferred = 1;
602             }
603 #endif
604         }
605     }
606
607     if (ngx_open_listening_sockets(cycle) != NGX_OK) {
608         goto failed;
609     }
610
611     if (!ngx_test_config) {
612         ngx_configure_listening_socket(cycle);
613     }
614
615
616     /* commit the new cycle configuration */
617
618 #if !(NGX_WIN32)
619
620     if (!ngx_test_config && cycle->log->file->fd != STDERR_FILENO) {
621
622         ngx_log_debug3(NGX_LOG_DEBUG_CORE, log, 0,
623                        "dup2: %p %d \"%s\"",
624                        cycle->log->file,
625                        cycle->log->file->fd, cycle->log->file->name.data);
626
627         if (dup2(cycle->log->file->fd, STDERR_FILENO) == -1) {
628             ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,
629                           "dup2(STDERR) failed");
630             /* fatal */
631             exit(1);
632         }
633     }
634
635 #endif
636
637     pool->log = cycle->log;
638
639     for (i = 0; ngx_modules[i]; i++) {
640         if (ngx_modules[i]->init_module) {
641             if (ngx_modules[i]->init_module(cycle) != NGX_OK) {
642                 /* fatal */
643                 exit(1);
644             }
645         }
646     }
647
648
649     /* close and delete stuff that lefts from an old cycle */
650
651     /* free the unnecessary shared memory */
652
653     opart = &old_cycle->shared_memory.part;
654     oshm_zone = opart->elts;
655
656     for (i = 0; /* void */ ; i++) {
657
658         if (i >= opart->nelts) {
659             if (opart->next == NULL) {
660                 goto old_shm_zone_done;
661             }
662             opart = opart->next;
663             oshm_zone = opart->elts;
664             i = 0;
665         }
666
667         part = &cycle->shared_memory.part;
668         shm_zone = part->elts;
669
670         for (n = 0; /* void */ ; n++) {
671
672             if (n >= part->nelts) {
673                 if (part->next == NULL) {
674                     break;
675                 }
676                 part = part->next;
677                 shm_zone = part->elts;
678                 n = 0;
679             }
680
681             if (oshm_zone[i].name.len == shm_zone[n].name.len
682                 && ngx_strncmp(oshm_zone[i].name.data,
683                                shm_zone[n].name.data,
684                                oshm_zone[i].name.len)
685                 == 0)
686             {
687                 goto live_shm_zone;
688             }
689         }
690
691         ngx_shm_free(&oshm_zone[i].shm);
692
693     live_shm_zone:
694
695         continue;
696     }
697
698 old_shm_zone_done:
699
700
701     /* close the unnecessary listening sockets */
702
703     ls = old_cycle->listening.elts;
704     for (i = 0; i < old_cycle->listening.nelts; i++) {
705         if (ls[i].remain) {
706             continue;
707         }
708
709         if (ngx_close_socket(ls[i].fd) == -1) {
710             ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,
711                           ngx_close_socket_n " listening socket on %V failed",
712                           &ls[i].addr_text);
713         }
714     }
715
716
717     /* close the unnecessary open files */
718
719     part = &old_cycle->open_files.part;
720     file = part->elts;
721
722     for (i = 0; /* void */ ; i++) {
723
724         if (i >= part->nelts) {
725             if (part->next == NULL) {
726                 break;
727             }
728             part = part->next;
729             file = part->elts;
730             i = 0;
731         }
732
733         if (file[i].fd == NGX_INVALID_FILE || file[i].fd == ngx_stderr_fileno) {
734             continue;
735         }
736
737         if (ngx_close_file(file[i].fd) == NGX_FILE_ERROR) {
738             ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,
739                           ngx_close_file_n " \"%s\" failed",
740                           file[i].name.data);
741         }
742     }
743
744     ngx_destroy_pool(conf.temp_pool);
745
746     if (ngx_process == NGX_PROCESS_MASTER || ngx_is_init_cycle(old_cycle)) {
747
748         /*
749          * perl_destruct() frees environ if it is not the same as it was at
750          * perl_construct() time.  So we have saved an previous cycle
751          * environment before ngx_conf_parse() where it will be changed.
752          */
753
754         env = environ;
755         environ = senv;
756
757         ngx_destroy_pool(old_cycle->pool);
758         cycle->old_cycle = NULL;
759
760         environ = env;
761
762         return cycle;
763     }
764
765
766     if (ngx_temp_pool == NULL) {
767         ngx_temp_pool = ngx_create_pool(128, cycle->log);
768         if (ngx_temp_pool == NULL) {
769             ngx_log_error(NGX_LOG_EMERG, cycle->log, 0,
770                           "can not create ngx_temp_pool");
771             exit(1);
772         }
773
774         n = 10;
775         ngx_old_cycles.elts = ngx_pcalloc(ngx_temp_pool,
776                                           n * sizeof(ngx_cycle_t *));
777         if (ngx_old_cycles.elts == NULL) {
778             exit(1);
779         }
780         ngx_old_cycles.nelts = 0;
781         ngx_old_cycles.size = sizeof(ngx_cycle_t *);
782         ngx_old_cycles.nalloc = n;
783         ngx_old_cycles.pool = ngx_temp_pool;
784
785         ngx_cleaner_event.handler = ngx_clean_old_cycles;
786         ngx_cleaner_event.log = cycle->log;
787         ngx_cleaner_event.data = &dumb;
788         dumb.fd = (ngx_socket_t) -1;
789     }
790
791     ngx_temp_pool->log = cycle->log;
792
793     old = ngx_array_push(&ngx_old_cycles);
794     if (old == NULL) {
795         exit(1);
796     }
797     *old = old_cycle;
798
799     if (!ngx_cleaner_event.timer_set) {
800         ngx_add_timer(&ngx_cleaner_event, 30000);
801         ngx_cleaner_event.timer_set = 1;
802     }
803
804     return cycle;
805
806
807 failed:
808
809     if (!ngx_is_init_cycle(old_cycle)) {
810         old_ccf = (ngx_core_conf_t *) ngx_get_conf(old_cycle->conf_ctx,
811                                                    ngx_core_module);
812         if (old_ccf->environment) {
813             environ = old_ccf->environment;
814         }
815     }
816
817     /* rollback the new cycle configuration */
818
819     part = &cycle->open_files.part;
820     file = part->elts;
821
822     for (i = 0; /* void */ ; i++) {
823
824         if (i >= part->nelts) {
825             if (part->next == NULL) {
826                 break;
827             }
828             part = part->next;
829             file = part->elts;
830             i = 0;
831         }
832
833         if (file[i].fd == NGX_INVALID_FILE || file[i].fd == ngx_stderr_fileno) {
834             continue;
835         }
836
837         if (ngx_close_file(file[i].fd) == NGX_FILE_ERROR) {
838             ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,
839                           ngx_close_file_n " \"%s\" failed",
840                           file[i].name.data);
841         }
842     }
843
844     if (ngx_test_config) {
845         ngx_destroy_cycle_pools(&conf);
846         return NULL;
847     }
848
849     ls = cycle->listening.elts;
850     for (i = 0; i < cycle->listening.nelts; i++) {
851         if (ls[i].fd == -1 || !ls[i].open) {
852             continue;
853         }
854
855         if (ngx_close_socket(ls[i].fd) == -1) {
856             ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,
857                           ngx_close_socket_n " %V failed",
858                           &ls[i].addr_text);
859         }
860     }
861
862     ngx_destroy_cycle_pools(&conf);
863
864     return NULL;
865 }
866
867
868 static void
869 ngx_destroy_cycle_pools(ngx_conf_t *conf)
870 {
871     ngx_destroy_pool(conf->temp_pool);
872     ngx_destroy_pool(conf->pool);
873 }
874
875
876 static ngx_int_t
877 ngx_cmp_sockaddr(struct sockaddr *sa1, struct sockaddr *sa2)
878 {
879     struct sockaddr_in   *sin1, *sin2;
880 #if (NGX_HAVE_INET6)
881     struct sockaddr_in6  *sin61, *sin62;
882 #endif
883
884     if (sa1->sa_family != sa2->sa_family) {
885         return NGX_DECLINED;
886     }
887
888     switch (sa1->sa_family) {
889
890 #if (NGX_HAVE_INET6)
891     case AF_INET6:
892         sin61 = (struct sockaddr_in6 *) sa1;
893         sin62 = (struct sockaddr_in6 *) sa2;
894
895         if (sin61->sin6_port != sin61->sin6_port) {
896             return NGX_DECLINED;
897         }
898
899         if (ngx_memcmp(&sin61->sin6_addr, &sin62->sin6_addr, 16) != 0) {
900             return NGX_DECLINED;
901         }
902
903         break;
904 #endif
905
906     default: /* AF_INET */
907
908         sin1 = (struct sockaddr_in *) sa1;
909         sin2 = (struct sockaddr_in *) sa2;
910
911         if (sin1->sin_port != sin2->sin_port) {
912             return NGX_DECLINED;
913         }
914
915         if (sin1->sin_addr.s_addr != sin2->sin_addr.s_addr) {
916             return NGX_DECLINED;
917         }
918
919         break;
920     }
921
922     return NGX_OK;
923 }
924
925
926 #if !(NGX_WIN32)
927
928 ngx_int_t
929 ngx_create_pidfile(ngx_str_t *name, ngx_log_t *log)
930 {
931     size_t            len;
932     ngx_uint_t        trunc;
933     ngx_file_t        file;
934     u_char            pid[NGX_INT64_LEN + 2];
935
936     ngx_memzero(&file, sizeof(ngx_file_t));
937
938     file.name = *name;
939     file.log = log;
940
941     trunc = ngx_test_config ? 0 : NGX_FILE_TRUNCATE;
942
943     file.fd = ngx_open_file(file.name.data, NGX_FILE_RDWR,
944                             NGX_FILE_CREATE_OR_OPEN|trunc,
945                             NGX_FILE_DEFAULT_ACCESS);
946
947     if (file.fd == NGX_INVALID_FILE) {
948         ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,
949                       ngx_open_file_n " \"%s\" failed", file.name.data);
950         return NGX_ERROR;
951     }
952
953     if (!ngx_test_config) {
954         len = ngx_snprintf(pid, NGX_INT64_LEN + 2, "%P%N", ngx_pid) - pid;
955
956         if (ngx_write_file(&file, pid, len, 0) == NGX_ERROR) {
957             return NGX_ERROR;
958         }
959     }
960
961     if (ngx_close_file(file.fd) == NGX_FILE_ERROR) {
962         ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
963                       ngx_close_file_n " \"%s\" failed", file.name.data);
964     }
965
966     return NGX_OK;
967 }
968
969
970 void
971 ngx_delete_pidfile(ngx_cycle_t *cycle)
972 {
973     u_char           *name;
974     ngx_core_conf_t  *ccf;
975
976     ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module);
977
978     name = ngx_new_binary ? ccf->oldpid.data : ccf->pid.data;
979
980     if (ngx_delete_file(name) == NGX_FILE_ERROR) {
981         ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
982                       ngx_delete_file_n " \"%s\" failed", name);
983     }
984 }
985
986 #endif
987
988
989 static ngx_int_t
990 ngx_test_lockfile(u_char *file, ngx_log_t *log)
991 {
992 #if !(NGX_HAVE_ATOMIC_OPS)
993     ngx_fd_t  fd;
994
995     fd = ngx_open_file(file, NGX_FILE_RDWR, NGX_FILE_CREATE_OR_OPEN,
996                        NGX_FILE_DEFAULT_ACCESS);
997
998     if (fd == NGX_INVALID_FILE) {
999         ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,
1000                       ngx_open_file_n " \"%s\" failed", file);
1001         return NGX_ERROR;
1002     }
1003
1004     if (ngx_close_file(fd) == NGX_FILE_ERROR) {
1005         ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
1006                       ngx_close_file_n " \"%s\" failed", file);
1007     }
1008
1009     if (ngx_delete_file(file) == NGX_FILE_ERROR) {
1010         ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
1011                       ngx_delete_file_n " \"%s\" failed", file);
1012     }
1013
1014 #endif
1015
1016     return NGX_OK;
1017 }
1018
1019
1020 void
1021 ngx_reopen_files(ngx_cycle_t *cycle, ngx_uid_t user)
1022 {
1023     ssize_t           n, len;
1024     ngx_fd_t          fd;
1025     ngx_uint_t        i;
1026     ngx_list_part_t  *part;
1027     ngx_open_file_t  *file;
1028
1029     part = &cycle->open_files.part;
1030     file = part->elts;
1031
1032     for (i = 0; /* void */ ; i++) {
1033
1034         if (i >= part->nelts) {
1035             if (part->next == NULL) {
1036                 break;
1037             }
1038             part = part->next;
1039             file = part->elts;
1040             i = 0;
1041         }
1042
1043         if (file[i].name.data == NULL) {
1044             continue;
1045         }
1046
1047         len = file[i].pos - file[i].buffer;
1048
1049         if (file[i].buffer && len != 0) {
1050
1051             n = ngx_write_fd(file[i].fd, file[i].buffer, len);
1052
1053             if (n == NGX_FILE_ERROR) {
1054                 ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
1055                               ngx_write_fd_n " to \"%s\" failed",
1056                               file[i].name.data);
1057
1058             } else if (n != len) {
1059                 ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
1060                           ngx_write_fd_n " to \"%s\" was incomplete: %z of %uz",
1061                           file[i].name.data, n, len);
1062             }
1063
1064             file[i].pos = file[i].buffer;
1065         }
1066
1067         fd = ngx_open_file(file[i].name.data, NGX_FILE_RDWR,
1068                            NGX_FILE_CREATE_OR_OPEN|NGX_FILE_APPEND,
1069                            NGX_FILE_DEFAULT_ACCESS);
1070
1071         ngx_log_debug3(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
1072                        "reopen file \"%s\", old:%d new:%d",
1073                        file[i].name.data, file[i].fd, fd);
1074
1075         if (fd == NGX_INVALID_FILE) {
1076             ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
1077                           ngx_open_file_n " \"%s\" failed", file[i].name.data);
1078             continue;
1079         }
1080
1081 #if (NGX_WIN32)
1082         if (ngx_file_append_mode(fd) == NGX_ERROR) {
1083             ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
1084                           ngx_file_append_mode_n " \"%s\" failed",
1085                           file[i].name.data);
1086
1087             if (ngx_close_file(fd) == NGX_FILE_ERROR) {
1088                 ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
1089                               ngx_close_file_n " \"%s\" failed",
1090                               file[i].name.data);
1091             }
1092
1093             continue;
1094         }
1095 #else
1096         if (user != (ngx_uid_t) NGX_CONF_UNSET_UINT) {
1097             ngx_file_info_t  fi;
1098
1099             if (ngx_file_info((const char *) file[i].name.data, &fi) == -1) {
1100                 ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
1101                               ngx_file_info_n " \"%s\" failed",
1102                               file[i].name.data);
1103
1104                 if (ngx_close_file(fd) == NGX_FILE_ERROR) {
1105                     ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
1106                                   ngx_close_file_n " \"%s\" failed",
1107                                   file[i].name.data);
1108                 }
1109             }
1110
1111             if (fi.st_uid != user) {
1112                 if (chown((const char *) file[i].name.data, user, -1) == -1) {
1113                     ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
1114                                   "chown(\"%s\", %d) failed",
1115                                   file[i].name.data, user);
1116
1117                     if (ngx_close_file(fd) == NGX_FILE_ERROR) {
1118                         ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
1119                                       ngx_close_file_n " \"%s\" failed",
1120                                       file[i].name.data);
1121                     }
1122                 }
1123             }
1124
1125             if ((fi.st_mode & (S_IRUSR|S_IWUSR)) != (S_IRUSR|S_IWUSR)) {
1126
1127                 fi.st_mode |= (S_IRUSR|S_IWUSR);
1128
1129                 if (chmod((const char *) file[i].name.data, fi.st_mode) == -1) {
1130                     ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
1131                                   "chmod() \"%s\" failed", file[i].name.data);
1132
1133                     if (ngx_close_file(fd) == NGX_FILE_ERROR) {
1134                         ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
1135                                       ngx_close_file_n " \"%s\" failed",
1136                                       file[i].name.data);
1137                     }
1138                 }
1139             }
1140         }
1141
1142         if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) {
1143             ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
1144                           "fcntl(FD_CLOEXEC) \"%s\" failed",
1145                           file[i].name.data);
1146
1147             if (ngx_close_file(fd) == NGX_FILE_ERROR) {
1148                 ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
1149                               ngx_close_file_n " \"%s\" failed",
1150                               file[i].name.data);
1151             }
1152
1153             continue;
1154         }
1155 #endif
1156
1157         if (ngx_close_file(file[i].fd) == NGX_FILE_ERROR) {
1158             ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
1159                           ngx_close_file_n " \"%s\" failed",
1160                           file[i].name.data);
1161         }
1162
1163         file[i].fd = fd;
1164     }
1165
1166 #if !(NGX_WIN32)
1167
1168     if (cycle->log->file->fd != STDERR_FILENO) {
1169         if (dup2(cycle->log->file->fd, STDERR_FILENO) == -1) {
1170             ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
1171                           "dup2(STDERR) failed");
1172         }
1173     }
1174
1175 #endif
1176 }
1177
1178
1179 ngx_shm_zone_t *
1180 ngx_shared_memory_add(ngx_conf_t *cf, ngx_str_t *name, size_t size, void *tag)
1181 {
1182     ngx_uint_t        i;
1183     ngx_shm_zone_t   *shm_zone;
1184     ngx_list_part_t  *part;
1185
1186     part = &cf->cycle->shared_memory.part;
1187     shm_zone = part->elts;
1188
1189     for (i = 0; /* void */ ; i++) {
1190
1191         if (i >= part->nelts) {
1192             if (part->next == NULL) {
1193                 break;
1194             }
1195             part = part->next;
1196             shm_zone = part->elts;
1197             i = 0;
1198         }
1199
1200         if (name->len != shm_zone[i].name.len) {
1201             continue;
1202         }
1203
1204         if (ngx_strncmp(name->data, shm_zone[i].name.data, name->len) != 0) {
1205             continue;
1206         }
1207
1208         if (size && size != shm_zone[i].shm.size) {
1209             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1210                                "the size %uz of shared memory zone \"%V\" "
1211                                "conflicts with already declared size %uz",
1212                                size, &shm_zone[i].name, shm_zone[i].shm.size);
1213             return NULL;
1214         }
1215
1216         if (tag != shm_zone[i].tag) {
1217             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1218                                "the shared memory zone \"%V\" is "
1219                                "already declared for a different use",
1220                                &shm_zone[i].name);
1221             return NULL;
1222         }
1223
1224         return &shm_zone[i];
1225     }
1226
1227     shm_zone = ngx_list_push(&cf->cycle->shared_memory);
1228
1229     if (shm_zone == NULL) {
1230         return NULL;
1231     }
1232
1233     shm_zone->data = NULL;
1234     shm_zone->shm.log = cf->cycle->log;
1235     shm_zone->shm.size = size;
1236     shm_zone->init = NULL;
1237     shm_zone->name = *name;
1238     shm_zone->tag = tag;
1239
1240     return shm_zone;
1241 }
1242
1243
1244 static void
1245 ngx_clean_old_cycles(ngx_event_t *ev)
1246 {
1247     ngx_uint_t     i, n, found, live;
1248     ngx_log_t     *log;
1249     ngx_cycle_t  **cycle;
1250
1251     log = ngx_cycle->log;
1252     ngx_temp_pool->log = log;
1253
1254     ngx_log_debug0(NGX_LOG_DEBUG_CORE, log, 0, "clean old cycles");
1255
1256     live = 0;
1257
1258     cycle = ngx_old_cycles.elts;
1259     for (i = 0; i < ngx_old_cycles.nelts; i++) {
1260
1261         if (cycle[i] == NULL) {
1262             continue;
1263         }
1264
1265         found = 0;
1266
1267         for (n = 0; n < cycle[i]->connection_n; n++) {
1268             if (cycle[i]->connections[n].fd != (ngx_socket_t) -1) {
1269                 found = 1;
1270
1271                 ngx_log_debug1(NGX_LOG_DEBUG_CORE, log, 0, "live fd:%d", n);
1272
1273                 break;
1274             }
1275         }
1276
1277         if (found) {
1278             live = 1;
1279             continue;
1280         }
1281
1282         ngx_log_debug1(NGX_LOG_DEBUG_CORE, log, 0, "clean old cycle: %d", i);
1283
1284         ngx_destroy_pool(cycle[i]->pool);
1285         cycle[i] = NULL;
1286     }
1287
1288     ngx_log_debug1(NGX_LOG_DEBUG_CORE, log, 0, "old cycles status: %d", live);
1289
1290     if (live) {
1291         ngx_add_timer(ev, 30000);
1292
1293     } else {
1294         ngx_destroy_pool(ngx_temp_pool);
1295         ngx_temp_pool = NULL;
1296         ngx_old_cycles.nelts = 0;
1297     }
1298 }