diff -cr --exclude=man --exclude=html --exclude=README_FILES --new-file /var/tmp/postfix-2.10-20120305/HISTORY ./HISTORY *** /var/tmp/postfix-2.10-20120305/HISTORY Mon Mar 5 10:35:50 2012 --- ./HISTORY Tue Mar 6 19:40:04 2012 *************** *** 17668,17670 **** --- 17668,17685 ---- of specific permit-like actions in Postfix SMTP server access lists. Files: mantools/postlink, proto/postconf.proto, global/mail_params.h, smtpd/smtpd.c, smtpd/smtpd_check.c. + + 20120206 + + Workaround: some Linux systems don't use "postfix status" + to find out if the mail system still runs. Instead they + claim that Postfix runs even when the master has aborted. + Even worse, they refuse to start Postfix when the problem + is fixed, claiming that Postfix is still running! As a + workaround, "postfix start" now waits until *after* master + daemon process initialization and returns a non-zero exit + status if daemon initialization did not complete in time. + Of course the real fix is that Linux systems stop reporting + bogus information and use "postfix status" properly. Files: + conf/postfix-script, master/master.c, master/master.h. + master/master_monitor.c. diff -cr --exclude=man --exclude=html --exclude=README_FILES --new-file /var/tmp/postfix-2.10-20120305/conf/postfix-script ./conf/postfix-script *** /var/tmp/postfix-2.10-20120305/conf/postfix-script Fri Jan 15 20:07:52 2010 --- ./conf/postfix-script Wed Mar 7 13:01:37 2012 *************** *** 124,130 **** $daemon_directory/postfix-script check-warn fi $INFO starting the Postfix mail system ! $daemon_directory/master & ;; drain) --- 124,134 ---- $daemon_directory/postfix-script check-warn fi $INFO starting the Postfix mail system ! # NOTE: wait in foreground process to get the initialization status. ! $daemon_directory/master -w || { ! $FATAL "mail system startup failed" ! exit 1 ! } ;; drain) diff -cr --exclude=man --exclude=html --exclude=README_FILES --new-file /var/tmp/postfix-2.10-20120305/src/master/Makefile.in ./src/master/Makefile.in *** /var/tmp/postfix-2.10-20120305/src/master/Makefile.in Sun Jan 22 10:55:16 2012 --- ./src/master/Makefile.in Wed Mar 7 11:37:49 2012 *************** *** 2,11 **** SRCS = master.c master_conf.c master_ent.c master_sig.c master_avail.c \ master_spawn.c master_service.c master_status.c master_listen.c \ master_proto.c single_server.c multi_server.c master_vars.c \ ! master_wakeup.c master_flow.c master_watch.c mail_flow.c OBJS = master.o master_conf.o master_ent.o master_sig.o master_avail.o \ master_spawn.o master_service.o master_status.o master_listen.o \ ! master_vars.o master_wakeup.o master_watch.o master_flow.o LIB_OBJ = single_server.o multi_server.o trigger_server.o master_proto.o \ mail_flow.o event_server.o HDRS = mail_server.h master_proto.h mail_flow.h --- 2,13 ---- SRCS = master.c master_conf.c master_ent.c master_sig.c master_avail.c \ master_spawn.c master_service.c master_status.c master_listen.c \ master_proto.c single_server.c multi_server.c master_vars.c \ ! master_wakeup.c master_flow.c master_watch.c mail_flow.c \ ! master_monitor.c OBJS = master.o master_conf.o master_ent.o master_sig.o master_avail.o \ master_spawn.o master_service.o master_status.o master_listen.o \ ! master_vars.o master_wakeup.o master_watch.o master_flow.o \ ! master_monitor.o LIB_OBJ = single_server.o multi_server.o trigger_server.o master_proto.o \ mail_flow.o event_server.o HDRS = mail_server.h master_proto.h mail_flow.h *************** *** 207,212 **** --- 209,219 ---- master_listen.o: ../../include/vstring.h master_listen.o: master.h master_listen.o: master_listen.c + master_monitor.o: ../../include/iostuff.h + master_monitor.o: ../../include/msg.h + master_monitor.o: ../../include/sys_defs.h + master_monitor.o: master.h + master_monitor.o: master_monitor.c master_proto.o: ../../include/msg.h master_proto.o: ../../include/sys_defs.h master_proto.o: master_proto.c diff -cr --exclude=man --exclude=html --exclude=README_FILES --new-file /var/tmp/postfix-2.10-20120305/src/master/master.c ./src/master/master.c *** /var/tmp/postfix-2.10-20120305/src/master/master.c Fri Dec 9 20:10:00 2011 --- ./src/master/master.c Wed Mar 7 13:24:14 2012 *************** *** 4,10 **** /* SUMMARY /* Postfix master process /* SYNOPSIS ! /* \fBmaster\fR [\fB-Ddtv\fR] [\fB-c \fIconfig_dir\fR] [\fB-e \fIexit_time\fR] /* DESCRIPTION /* The \fBmaster\fR(8) daemon is the resident process that runs Postfix /* daemons on demand: daemons to send or receive messages via the --- 4,10 ---- /* SUMMARY /* Postfix master process /* SYNOPSIS ! /* \fBmaster\fR [\fB-Ddtvw\fR] [\fB-c \fIconfig_dir\fR] [\fB-e \fIexit_time\fR] /* DESCRIPTION /* The \fBmaster\fR(8) daemon is the resident process that runs Postfix /* daemons on demand: daemons to send or receive messages via the *************** *** 45,50 **** --- 45,57 ---- /* Enable verbose logging for debugging purposes. This option /* is passed on to child processes. Multiple \fB-v\fR options /* make the software increasingly verbose. + /* .IP \fB-w\fR + /* Wait in a dummy foreground process, while the real master + /* daemon initializes in a background process. The dummy + /* foreground process returns a zero exit status only when the + /* master daemon initialization is successful. + /* .sp + /* This feature is available in Postfix 2.10 and later. /* .PP /* Signals: /* .IP \fBSIGHUP\fR *************** *** 63,69 **** /* terminate only the master ("\fBpostfix stop\fR") and allow running /* processes to finish what they are doing. /* DIAGNOSTICS ! /* Problems are reported to \fBsyslogd\fR(8). /* ENVIRONMENT /* .ad /* .fi --- 70,78 ---- /* terminate only the master ("\fBpostfix stop\fR") and allow running /* processes to finish what they are doing. /* DIAGNOSTICS ! /* Problems are reported to \fBsyslogd\fR(8). The exit status ! /* is non-zero in case of problems, including problems while ! /* initializing as a master daemon process in the background. /* ENVIRONMENT /* .ad /* .fi *************** *** 221,227 **** static NORETURN usage(const char *me) { ! msg_fatal("usage: %s [-c config_dir] [-D (debug)] [-d (don't detach from terminal)] [-e exit_time] [-t (test)] [-v]", me); } MAIL_VERSION_STAMP_DECLARE; --- 230,236 ---- static NORETURN usage(const char *me) { ! msg_fatal("usage: %s [-c config_dir] [-D (debug)] [-d (don't detach from terminal)] [-e exit_time] [-t (test)] [-v] [-w (wait for initialization)]", me); } MAIL_VERSION_STAMP_DECLARE; *************** *** 243,248 **** --- 252,259 ---- VSTRING *why; WATCHDOG *watchdog; ARGV *import_env; + int wait_flag = 0; + int monitor_fd = -1; /* * Fingerprint executables and core dumps. *************** *** 311,317 **** /* * Process JCL. */ ! while ((ch = GETOPT(argc, argv, "c:Dde:tv")) > 0) { switch (ch) { case 'c': if (setenv(CONF_ENV_PATH, optarg, 1) < 0) --- 322,328 ---- /* * Process JCL. */ ! while ((ch = GETOPT(argc, argv, "c:Dde:tvw")) > 0) { switch (ch) { case 'c': if (setenv(CONF_ENV_PATH, optarg, 1) < 0) *************** *** 332,337 **** --- 343,351 ---- case 'v': msg_verbose++; break; + case 'w': + wait_flag = 1; + break; default: usage(argv[0]); /* NOTREACHED */ *************** *** 345,350 **** --- 359,375 ---- usage(argv[0]); /* + * Run a foreground monitor process that returns an exit status of 0 when + * the child background process reports successful initialization as a + * daemon process. We use a generous limit in case main/master.cf specify + * symbolic hosts/ports and the naming service is slow. + */ + #define MASTER_INIT_TIMEOUT 100 /* keep this limit generous */ + + if (wait_flag) + monitor_fd = master_monitor(MASTER_INIT_TIMEOUT); + + /* * 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. */ *************** *** 471,476 **** --- 496,509 ---- var_mail_version, var_config_dir); /* + * Report successful initialization to the foreground monitor process. + */ + if (monitor_fd >= 0) { + write(monitor_fd, "", 1); + (void) close(monitor_fd); + } + + /* * 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 diff -cr --exclude=man --exclude=html --exclude=README_FILES --new-file /var/tmp/postfix-2.10-20120305/src/master/master.h ./src/master/master.h *** /var/tmp/postfix-2.10-20120305/src/master/master.h Wed Sep 7 13:18:25 2011 --- ./src/master/master.h Tue Mar 6 17:06:35 2012 *************** *** 219,224 **** --- 219,229 ---- extern void master_str_watch(const MASTER_STR_WATCH *); extern void master_int_watch(MASTER_INT_WATCH *); + /* + * master_monitor.c + */ + extern int master_monitor(int); + /* DIAGNOSTICS /* BUGS /* SEE ALSO diff -cr --exclude=man --exclude=html --exclude=README_FILES --new-file /var/tmp/postfix-2.10-20120305/src/master/master_monitor.c ./src/master/master_monitor.c *** /var/tmp/postfix-2.10-20120305/src/master/master_monitor.c Wed Dec 31 19:00:00 1969 --- ./src/master/master_monitor.c Tue Mar 6 17:32:19 2012 *************** *** 0 **** --- 1,100 ---- + /*++ + /* NAME + /* master_monitor 3 + /* SUMMARY + /* Postfix master - start-up monitoring + /* SYNOPSIS + /* #include "master.h" + /* + /* int master_monitor(time_limit) + /* int time_limit; + /* DESCRIPTION + /* master_monitor() forks off a background child process, and + /* returns in the child. The result value is the file descriptor + /* on which the child process must write one byte after it + /* completes successful initialization as a daemon process. + /* + /* The foreground process waits for the child's completion for + /* a limited amount of time. It terminates with exit status 0 + /* in case of success, non-zero otherwise. + /* DIAGNOSTICS + /* Fatal errors: system call failure. + /* BUGS + /* SEE ALSO + /* LICENSE + /* .ad + /* .fi + /* The Secure Mailer license must be distributed with this software. + /* AUTHOR(S) + /* Wietse Venema + /* IBM T.J. Watson Research + /* P.O. Box 704 + /* Yorktown Heights, NY 10598, USA + /*--*/ + + /* System library. */ + + #include + #include + #include + #include + + /* Utility library. */ + + #include + #include + + /* Application-specific. */ + + #include + + /* 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, (char *) 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); + } + } + }