--------src/master
typedef struct {
char *program; /* postfix */
int major; /* 2 */
int minor; /* 9 */
int patch; /* null */
char *snapshot; /* 20111209-nonprod */
} MAIL_VERSION;
进入master.c的main函数:
定义了相关的变量,postfix提供了相关的锁机制,
static VSTREAM *lock_fp;
static VSTREAM *data_lock_fp;
VSTRING *lock_path;
VSTRING *data_lock_path;
off_t inherited_limit;
int debug_me = 0;
int ch;
int fd;
int n;
int test_lock = 0;
VSTRING *why;
WATCHDOG *watchdog;
ARGV *import_env;
int wait_flag = 0;
int monitor_fd = -1;
/*
* Fingerprint executables and core dumps.
*/
检验版本
MAIL_VERSION_STAMP_ALLOCATE;
/*
* Initialize.
*/
设置执行权限,只有用户有执行权限
umask(077); /* never fails! */
//根据获取的环境变量,定义msg_verbose和debug_me的值,在后续的模块中会有相关的判断。
if (getenv(CONF_ENV_VERB))
msg_verbose = 1;
if (getenv(CONF_ENV_DEBUG))
debug_me = 1;
/*
* Don't die when a process goes away unexpectedly.
*/
为了避免进程退出,忽略SIGPIPE信号。
signal(SIGPIPE, SIG_IGN);
保存进程名称,调用basename()函数获取可执行文件名称,
然后将其复制到var_procname.
/*
* Strip and save the process name for diagnostics etc.
*/
var_procname = mystrdup(basename(argv[0]));
关闭文件描述符大于等于3的值
*/
closefrom(3);
初始化日志,发送消息到系统日志。Openlog打开系统调试文件。
/*
* Initialize logging and exit handler.
*/
msg_syslog_init(mail_task(var_procname), LOG_PID, LOG_FACILITY);
/*
* Check the Postfix library version as soon as we enable logging.
*/
MAIL_VERSION_CHECK;
邮件系统必须要 root用户选择和操作,uid == o
/*
* The mail system must be run by the superuser so it can revoke
* privileges for selected operations. That's right - it takes privileges
* to toss privileges.
*/
if (getuid() != 0)
msg_fatal("the master command is reserved for the superuser");
if (unsafe() != 0)
msg_fatal("the master command must not run as a set-uid process");
/*
/
加载作业控制语言,由此参数传入进程,进程执行。
/*
* Process JCL.
*/
while ((ch = GETOPT(argc, argv, "c:Dde:tvw")) > 0) {
switch (ch) {
case 'c':
if (setenv(CONF_ENV_PATH, optarg, 1) < 0)
msg_fatal("out of memory");
break;
case 'd':
master_detach = 0;
break;
case 'e':
event_request_timer(master_exit_event, (void *) 0, atoi(optarg));
break;
case 'D':
debug_me = 1;
break;
case 't':
test_lock = 1;
break;
case 'v':
msg_verbose++;
break;
case 'w':
wait_flag = 1;
break;
default:
usage(argv[0]);
/* NOTREACHED */
}
}
if (wait_flag)
monitor_fd = master_monitor(MASTER_INIT_TIMEOUT);
进入master_monitor
/* master_monitor - fork off a foreground monitor process */
int master_monitor(int time_limit)
{
pid_t pid;
int pipes[2];
char buf[1];
/*
* Sanity check.
*/
if (time_limit <= 0)
msg_panic("master_monitor: bad time limit: %d", time_limit);
/*
* Set up the plumbing for child-to-parent communication.
*/
if (pipe(pipes) < 0)
msg_fatal("pipe: %m");
close_on_exec(pipes[0], CLOSE_ON_EXEC);
close_on_exec(pipes[1], CLOSE_ON_EXEC);
利用管道,创建一个子进程监视
/*
* Fork the child, and wait for it to report successful initialization.
*/
switch (pid = fork()) {
case -1:
/* Error. */
msg_fatal("fork: %m");
case 0:
/* Child. Initialize as daemon in the background. */
close(pipes[0]);
return (pipes[1]);
default:
/* Parent. Monitor the child in the foreground. */
close(pipes[1]);
switch (timed_read(pipes[0], buf, 1, time_limit, (void *) 0)) {
default:
/* The child process still runs, but something is wrong. */
(void) kill(pid, SIGKILL);
/* FALLTHROUGH */
case 0:
/* The child process exited prematurely. */
msg_fatal("daemon initialization failure");
case 1:
/* The child process initialized successfully. */
exit(0);
}
}
}
从master.cf的配置文件中把参数信息加载进入进程中。
/*
* Final initializations. Unfortunately, we must read the global Postfix
* configuration file after doing command-line processing, so that we get
* consistent results when we SIGHUP the server to reload configuration
* files.
*/
master_vars_init();
(void) inet_proto_init(VAR_INET_PROTOCOLS, var_inet_protocols);
读取master模块的配置文件。
void master_config(void)
{
MASTER_SERV *entry;
MASTER_SERV *serv;
#define STR_DIFF strcmp
#define STR_SAME !strcmp
#define SWAP(type,a,b) { type temp = a; a = b; b = temp; }
/*
* A service is identified by its endpoint name AND by its transport
* type, not just by its name alone. The name is unique within its
* transport type. XXX Service privacy is encoded in the service name.
*/
set_master_ent();
while ((entry = get_master_ent()) != 0) {
if (msg_verbose)
print_master_ent(entry);
for (serv = master_head; serv != 0; serv = serv->next)
if (STR_SAME(serv->name, entry->name) && serv->type == entry->type)
break;
/*
* Add a new service entry. We do not really care in what order the
* service entries are kept in memory.
*/
if (serv == 0) {
entry->next = master_head;
master_head = entry;
master_start_service(entry);
}
/*
* Update an existing service entry. Make the current generation of
* child processes commit suicide whenever it is convenient. The next
* generation of child processes will run with the new configuration
* settings.
*/
else {
serv->flags &= ~MASTER_FLAG_MARK;
if (entry->flags & MASTER_FLAG_CONDWAKE)
serv->flags |= MASTER_FLAG_CONDWAKE;
else
serv->flags &= ~MASTER_FLAG_CONDWAKE;
serv->wakeup_time = entry->wakeup_time;
serv->max_proc = entry->max_proc;
serv->throttle_delay = entry->throttle_delay;
SWAP(char *, serv->ext_name, entry->ext_name);
SWAP(char *, serv->path, entry->path);
SWAP(ARGV *, serv->args, entry->args);
SWAP(char *, serv->stress_param_val, entry->stress_param_val);
master_restart_service(serv, DO_CONF_RELOAD);
free_master_ent(entry);
}
}
end_master_ent();
}