/* System libraries. */ #include "stdafx.h" #include #include #include #include #include #include #include #include #include #include #include "version.h" #include "master/master_params.h" #include "master/master.h" #include "manage/manager.h" char *var_master_procname; #define STR acl_vstring_str #define LEN ACL_VSTRING_LEN static void lock_service(void) { ACL_VSTRING *buf = acl_vstring_alloc(128); ACL_VSTRING *tmp = acl_vstring_alloc(128); ACL_VSTREAM *fp; /* create lock file make sure acl_master can only start once */ acl_vstring_sprintf(buf, "%s/.master.lock", acl_var_master_queue_dir); fp = acl_open_lock(STR(buf), O_RDWR | O_CREAT, 0644, tmp); if (fp == NULL) { acl_msg_fatal("%s(%d): open lock file %s: %s", __FUNCTION__, __LINE__, STR(buf), STR(tmp)); } acl_vstring_sprintf(buf, "%lu\n", (long) time(NULL)); acl_vstream_writen(fp, STR(buf), LEN(buf)); acl_close_on_exec(ACL_VSTREAM_FILE(fp), ACL_CLOSE_ON_EXEC); acl_vstring_free(buf); acl_vstring_free(tmp); } static void lock_pidfile(void) { ACL_VSTREAM *fp; ACL_VSTRING *buf; /* open pid file, lock it and write the master's pid value into it */ buf = acl_vstring_alloc(10); fp = acl_open_lock(acl_var_master_pid_file, O_RDWR | O_CREAT, 0644, buf); if (fp == NULL) { acl_msg_fatal("%s(%d): open lock file %s: %s", __FUNCTION__, __LINE__, acl_var_master_pid_file, STR(buf)); } acl_vstring_sprintf(buf, "%*lu\n", (int) sizeof(unsigned long) * 4, (unsigned long) acl_var_master_pid); acl_vstream_writen(fp, STR(buf), LEN(buf)); acl_close_on_exec(ACL_VSTREAM_FILE(fp), ACL_CLOSE_ON_EXEC); acl_vstring_free(buf); } /* usage - show hint and terminate */ static void usage(const char *me) { printf("usage: %s -c root_dir\r\n" " -l log_file\r\n" " -v [version]\r\n" " -V [verbose]\r\n" " -h [help]\r\n" " -k (keep_mask)\r\n", me); } /* main - main program */ int main(int argc, char **argv) { //ACL_WATCHDOG *watchdog; int ch, fd, n, keep_mask = 0; ACL_AIO *aio; char *ptr; /* * Strip and save the process name for diagnostics etc. */ var_master_procname = acl_mystrdup(acl_safe_basename(argv[0])); acl_var_master_pid = getpid(); acl_var_master_conf_dir = NULL; acl_var_master_log_file = NULL; acl_open_limit(0); while ((ch = getopt(argc, argv, "Vhvc:l:k")) > 0) { switch (ch) { case 'V': acl_msg_verbose++; break; case 'v': printf("%s %s %s(acl-%s)\r\n", MASTER_NAME, MASTER_VERSION, MASTER_DATE, acl_version()); return 0; case 'h': usage(argv[0]); return 0; case 'c': acl_var_master_conf_dir = acl_mystrdup(optarg); break; case 'l': acl_var_master_log_file = acl_mystrdup(optarg); break; case 'k': keep_mask = 1; break; default: usage(argv[0]); return 0; /* NOTREACHED */ } } /* Initialize. */ if (!keep_mask) umask(077); /* never fails! */ /* Don't die when a process goes away unexpectedly. */ signal(SIGPIPE, SIG_IGN); if (acl_var_master_conf_dir == NULL || acl_var_master_log_file == NULL) usage(argv[0]); ptr = strrchr(acl_var_master_conf_dir, '/'); if (ptr != NULL && *(ptr + 1) == '\0') /* as "/opt/master/conf/" */ *ptr = '\0'; /* * This program takes no other arguments. */ if (argc > optind) usage(argv[0]); /* * When running a child process, don't leak any open files that were * leaked to us by our own (privileged) parent process. Descriptors 0-2 * are taken care of after we have initialized error logging. * * Some systems such as AIX have a huge per-process open file limit. * In those cases, limit the search for potential file descriptor leaks * to just the first couple hundred. * * The Debian post-installation script passes an open file descriptor * into the master process and waits forever for someone to close it. * Because of this we have to close descriptors > 2, and pray that * doing so does not break things. */ acl_closefrom(3); /* 0: stdin; 1: stdout; 2: stderr */ /* Initialize logging and exit handler. */ /* * don't call acl_close_on_exec that the children can use * master's log in starting status * acl_log_close_onexec(0); */ /* use 0 as the log's fd */ close(0); acl_msg_open(acl_var_master_log_file, var_master_procname); /* * If started from a terminal, get rid of any tty association. This also * means that all errors and warnings must go to the syslog daemon. */ for (fd = 1; fd < 3; fd++) { (void) close(fd); if (open("/dev/null", (int) O_RDWR, 0) != fd) acl_msg_fatal("open /dev/null: %s", acl_last_serror()); } if (setsid() == -1 && getsid(0) != getpid()) acl_msg_warn("unable to set session %s", acl_last_serror()); /* * Make some room for plumbing with file descriptors. XXX This breaks * when a service listens on many ports. In order to do this right we * must change the master-child interface so that descriptors do not * need to have fixed numbers. * * In a child we need two descriptors for the flow control pipe, one * for child->master status updates and at least one for listening. */ for (n = 0; n < 5; n++) { fd = dup(1); if (acl_close_on_exec(fd, ACL_CLOSE_ON_EXEC) < 0) acl_msg_fatal("dup(0): %s", acl_last_serror()); if (acl_msg_verbose) acl_msg_info("dup(0), fd = %d", fd); } /* load main.cf of acl_master */ acl_master_main_config(); /* For the unique master service be started, first to lock file */ lock_service(); /* just for prefork service -- zsx, 2012.3.24 */ acl_master_flow_init(); /* start all services processes */ acl_master_start_services(); /* init master manager module */ manager::get_instance().init(acl_var_master_global_event, acl_var_master_manage_addr, acl_var_master_rw_timeout); /* * Finish initialization, last part. We must process configuration * files after processing command-line parameters, so that we get * consistent results when we SIGHUP the server to reload * configuration files. */ acl_master_sigsetup(); /* Save pid to local file and lock it */ lock_pidfile(); acl_msg_info("daemon started -- version %s, configuration %s", MASTER_VERSION, acl_var_master_conf_dir); /* * Process events. The event handler will execute the read/write/timer * action routines. Whenever something has happened, see if we received * any signal in the mean time. Although the master process appears to do * multiple things at the same time, it really is all a single thread, so * that there are no concurrency conflicts within the master process. */ //watchdog = acl_watchdog_create(1000, (ACL_WATCHDOG_FN) 0, (char *) 0); for (;;) { #ifdef HAS_VOLATILE_LOCKS if (acl_myflock(ACL_VSTREAM_FILE(lock_fp), ACL_INTERNAL_LOCK, ACL_FLOCK_OP_EXCLUSIVE) < 0) { acl_msg_fatal("refresh exclusive lock: %m"); } #endif //acl_watchdog_start(watchdog); /* same as trigger servers */ acl_event_loop(acl_var_master_global_event); aio = manager::get_instance().get_aio(); if (aio) acl_aio_check(aio); if (acl_var_master_gotsighup) { acl_msg_info("reload configuration"); acl_var_master_gotsighup = 0; /* this first */ acl_master_refresh(); /* then this */ } if (acl_var_master_gotsigchld) { if (acl_msg_verbose) acl_msg_info("got sigchld"); acl_var_master_gotsigchld = 0; /* this first */ acl_master_reap_child(); /* then this */ } if (acl_var_master_stopped) break; } #define EQ !strcasecmp if (EQ(acl_var_master_stop_kill, "true") || EQ(acl_var_master_stop_kill, "yes") || EQ(acl_var_master_stop_kill, "on")) { acl_master_delete_all_children(); } return 0; }