Expand PMF_FN_* macros.
[netbsd-mini2440.git] / external / ibm-public / postfix / dist / src / master / master_status.c
blob0a7eee683dd29b051a4470d6e6e7c3d9f1c2acc8
1 /* $NetBSD$ */
3 /*++
4 /* NAME
5 /* master_status 3
6 /* SUMMARY
7 /* Postfix master - process child status reports
8 /* SYNOPSIS
9 /* #include "master.h"
11 /* void master_status_init(serv)
12 /* MASTER_SERV *serv;
14 /* void master_status_cleanup(serv)
15 /* MASTER_SERV *serv;
16 /* DESCRIPTION
17 /* This module reads and processes status reports from child processes.
19 /* master_status_init() enables the processing of child status updates
20 /* for the specified service. Child process status updates (process
21 /* available, process taken) are passed on to the master_avail_XXX()
22 /* routines.
24 /* master_status_cleanup() disables child status update processing
25 /* for the specified service.
26 /* DIAGNOSTICS
27 /* Panic: internal inconsistency. Warnings: a child process sends
28 /* incomplete or incorrect information.
29 /* BUGS
30 /* SEE ALSO
31 /* master_avail(3)
32 /* LICENSE
33 /* .ad
34 /* .fi
35 /* The Secure Mailer license must be distributed with this software.
36 /* AUTHOR(S)
37 /* Wietse Venema
38 /* IBM T.J. Watson Research
39 /* P.O. Box 704
40 /* Yorktown Heights, NY 10598, USA
41 /*--*/
43 /* System libraries. */
45 #include <sys_defs.h>
46 #include <unistd.h>
48 /* Utility library. */
50 #include <msg.h>
51 #include <events.h>
52 #include <binhash.h>
53 #include <iostuff.h>
55 /* Application-specific. */
57 #include "master_proto.h"
58 #include "master.h"
60 /* master_status_event - status read event handler */
62 static void master_status_event(int event, char *context)
64 const char *myname = "master_status_event";
65 MASTER_SERV *serv = (MASTER_SERV *) context;
66 MASTER_STATUS stat;
67 MASTER_PROC *proc;
68 MASTER_PID pid;
69 int n;
71 if (event == 0) /* XXX Can this happen? */
72 return;
75 * We always keep the child end of the status pipe open, so an EOF read
76 * condition means that we're seriously confused. We use non-blocking
77 * reads so that we don't get stuck when someone sends a partial message.
78 * Messages are short, so a partial read means someone wrote less than a
79 * whole status message. Hopefully the next read will be in sync again...
80 * We use a global child process status table because when a child dies
81 * only its pid is known - we do not know what service it came from.
83 switch (n = read(serv->status_fd[0], (char *) &stat, sizeof(stat))) {
85 case -1:
86 msg_warn("%s: read: %m", myname);
87 return;
89 case 0:
90 msg_panic("%s: read EOF status", myname);
91 /* NOTREACHED */
93 default:
94 msg_warn("service %s(%s): child (pid %d) sent partial status update (%d bytes)",
95 serv->ext_name, serv->name, stat.pid, n);
96 return;
98 case sizeof(stat):
99 pid = stat.pid;
100 if (msg_verbose)
101 msg_info("%s: pid %d gen %u avail %d",
102 myname, stat.pid, stat.gen, stat.avail);
106 * Sanity checks. Do not freak out when the child sends garbage because
107 * it is confused or for other reasons. However, be sure to freak out
108 * when our own data structures are inconsistent. A process not found
109 * condition can happen when we reap a process before receiving its
110 * status update, so this is not an error.
112 if ((proc = (MASTER_PROC *) binhash_find(master_child_table,
113 (char *) &pid, sizeof(pid))) == 0) {
114 if (msg_verbose)
115 msg_info("%s: process id not found: %d", myname, stat.pid);
116 return;
118 if (proc->gen != stat.gen) {
119 msg_info("ignoring status update from child pid %d generation %u",
120 pid, stat.gen);
121 return;
123 if (proc->serv != serv)
124 msg_panic("%s: pointer corruption: %p != %p",
125 myname, (void *) proc->serv, (void *) serv);
128 * Update our idea of the child process status. Allow redundant status
129 * updates, because different types of events may be processed out of
130 * order. Otherwise, warn about weird status updates but do not take
131 * action. It's all gossip after all.
133 if (proc->avail == stat.avail)
134 return;
135 switch (stat.avail) {
136 case MASTER_STAT_AVAIL:
137 proc->use_count++;
138 master_avail_more(serv, proc);
139 break;
140 case MASTER_STAT_TAKEN:
141 master_avail_less(serv, proc);
142 break;
143 default:
144 msg_warn("%s: ignoring unknown status: %d allegedly from pid: %d",
145 myname, stat.pid, stat.avail);
146 break;
150 /* master_status_init - start status event processing for this service */
152 void master_status_init(MASTER_SERV *serv)
154 const char *myname = "master_status_init";
157 * Sanity checks.
159 if (serv->status_fd[0] >= 0 || serv->status_fd[1] >= 0)
160 msg_panic("%s: status events already enabled", myname);
161 if (msg_verbose)
162 msg_info("%s: %s", myname, serv->name);
165 * Make the read end of this service's status pipe non-blocking so that
166 * we can detect partial writes on the child side. We use a duplex pipe
167 * so that the child side becomes readable when the master goes away.
169 if (duplex_pipe(serv->status_fd) < 0)
170 msg_fatal("pipe: %m");
171 non_blocking(serv->status_fd[0], BLOCKING);
172 close_on_exec(serv->status_fd[0], CLOSE_ON_EXEC);
173 close_on_exec(serv->status_fd[1], CLOSE_ON_EXEC);
174 event_enable_read(serv->status_fd[0], master_status_event, (char *) serv);
177 /* master_status_cleanup - stop status event processing for this service */
179 void master_status_cleanup(MASTER_SERV *serv)
181 const char *myname = "master_status_cleanup";
184 * Sanity checks.
186 if (serv->status_fd[0] < 0 || serv->status_fd[1] < 0)
187 msg_panic("%s: status events not enabled", myname);
188 if (msg_verbose)
189 msg_info("%s: %s", myname, serv->name);
192 * Dispose of this service's status pipe after disabling read events.
194 event_disable_readwrite(serv->status_fd[0]);
195 if (close(serv->status_fd[0]) != 0)
196 msg_warn("%s: close status descriptor (read side): %m", myname);
197 if (close(serv->status_fd[1]) != 0)
198 msg_warn("%s: close status descriptor (write side): %m", myname);
199 serv->status_fd[0] = serv->status_fd[1] = -1;