mirror of
https://gitee.com/acl-dev/acl.git
synced 2024-12-15 09:20:52 +08:00
287 lines
7.8 KiB
C++
287 lines
7.8 KiB
C++
/* System libraries. */
|
|
#include "stdafx.h"
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <sys/stat.h>
|
|
#include <syslog.h>
|
|
#include <signal.h>
|
|
#include <unistd.h>
|
|
#include <string.h>
|
|
#include <fcntl.h>
|
|
#include <limits.h>
|
|
|
|
#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;
|
|
}
|