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