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