Use pid of exited child to close fifos.
[egate.git] / kernel / monitor.c
1 /* Gateway Resource Monitor
2  * Europagate, 1995
3  *
4  * $Log: monitor.c,v $
5  * Revision 1.3  1995/05/02 07:20:10  adam
6  * Use pid of exited child to close fifos.
7  *
8  * Revision 1.2  1995/05/01  16:26:57  adam
9  * More work on resource monitor.
10  *
11  * Revision 1.1  1995/05/01  12:43:36  adam
12  * First work on resource monitor program.
13  *
14  */
15
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <assert.h>
19 #include <ctype.h>
20 #include <string.h>
21 #include <unistd.h>
22 #include <fcntl.h>
23 #include <setjmp.h>
24 #include <signal.h>
25
26 #include <sys/file.h>
27 #include <sys/stat.h>
28 #include <sys/types.h>
29 #include <sys/time.h>
30 #include <sys/wait.h>
31
32 #include <gw-log.h>
33 #include <gw-log.h>
34 #include <gip.h>
35 #include <strqueue.h>
36 #include <lgets.h>
37
38 #define LINE_MAX 1024
39
40 static char *module = "monitor";
41 static jmp_buf retry_jmp;
42
43 struct ke_info {
44     pid_t pid;
45     int id;
46     GIP gip;
47     struct str_queue *queue;
48     struct ke_info *next;
49 };
50
51 struct ke_info *ke_info_list = NULL;
52
53 struct ke_info *ke_info_add (int id)
54 {
55     struct ke_info **kip;
56
57     for (kip = &ke_info_list; *kip; kip= &(*kip)->next)
58         if ((*kip)->id == id)
59             return *kip;
60     *kip = malloc (sizeof(**kip));
61     assert (*kip);
62     (*kip)->next = NULL;
63     (*kip)->id = id;
64     (*kip)->gip = NULL;
65     if (!((*kip)->queue = str_queue_mk ()))
66     {
67         gw_log (GW_LOG_FATAL|GW_LOG_ERRNO, module, "str_queue_mk");
68         exit (1);
69     }
70     return *kip;
71 }
72
73 void ke_info_del (void)
74 {
75     struct ke_info *ki;
76
77     assert (ke_info_list);
78     ki = ke_info_list;
79     str_queue_rm (&ki->queue);
80     ke_info_list = ki->next;
81     free (ki);
82 }
83
84 static void catchchild (int num)
85 {
86     pid_t pid;
87     struct ke_info *ki;
88
89     while ((pid=waitpid (-1, 0, WNOHANG)) > 0)
90         for (ki = ke_info_list; ki; ki = ki->next)
91             if (ki->pid == pid)
92             {
93                 gw_log (GW_LOG_DEBUG, module, "Close of %d", ki->id);
94                 if (ki->gip)
95                 {
96                     gipc_close (ki->gip);
97                     gipc_destroy (ki->gip);
98                     ki->gip = NULL;
99                 }
100             }
101     signal (SIGCHLD, catchchild);
102 }
103
104 static void pipe_handle (int dummy)
105 {
106     longjmp (retry_jmp, 1);
107 }
108
109 static pid_t start_kernel (int argc, char **argv, int id)
110 {
111     pid_t pid;
112     int i;
113     char **argv_p;
114     char userid_option[20];
115
116     argv_p = malloc (sizeof(*argv_p)*(argc+2));
117     if (!argv_p)
118     {
119         gw_log (GW_LOG_FATAL|GW_LOG_ERRNO, module, "malloc fail");
120         exit (1);
121     }
122     argv_p[0] = "kernel";
123     for (i = 1; i<argc; i++)
124         argv_p[i] = argv[i];
125     sprintf (userid_option, "-i%d", id);
126     argv_p[i++] = userid_option;
127     argv_p[i++] = NULL;
128
129     gw_log (GW_LOG_DEBUG, module, "Starting kernel");
130     pid = fork ();
131     if (pid == -1)
132     {
133         gw_log (GW_LOG_FATAL|GW_LOG_ERRNO, module, "fork");
134         exit (1);
135     }
136     if (!pid)
137     {
138         execv ("kernel", argv_p);
139         gw_log (GW_LOG_FATAL|GW_LOG_ERRNO, module, "execvp");
140         exit (1);
141     }
142     return pid;
143 }
144
145 static void deliver (int argc, char **argv, int id, struct str_queue *queue,
146                      GIP *gip, pid_t *pidp)
147 {
148     int pass = 0;
149     int r;
150     int index;
151     char fifo_server_name[128];
152     char fifo_client_name[128];
153     void (*oldsig)();
154     const char *msg;
155
156     sprintf (fifo_server_name, "fifo.s.%d", id);
157     sprintf (fifo_client_name, "fifo.c.%d", id);
158
159     assert (gip);
160     if (!*gip)
161         *gip = gipc_initialize (fifo_client_name);
162
163     oldsig = signal (SIGPIPE, pipe_handle);
164     setjmp (retry_jmp);
165     ++pass;
166     if (pass == 1)
167         r = gipc_open (*gip, fifo_server_name, 0);
168     else if (pass == 2)
169     {
170         pid_t pid;
171
172         mknod (fifo_server_name, S_IFIFO|0666, 0);
173         pid = start_kernel (argc, argv, id);
174         if (pidp)
175             *pidp = pid;
176         r = gipc_open (*gip, fifo_server_name, 1);
177     }
178     else
179     {
180         gw_log (GW_LOG_WARN, module, "Cannot start kernel");
181         return;
182     }
183     if (r < 0)
184     {
185         if (r == -2)
186         {
187             gw_log (GW_LOG_DEBUG|GW_LOG_ERRNO, module, "r==-2");
188             longjmp (retry_jmp, 1);
189         }
190         else if (r == -1)
191         {
192             gw_log (GW_LOG_DEBUG|GW_LOG_ERRNO, module, "r==-1");
193             longjmp (retry_jmp, 1);
194         }
195         else
196         {
197             gw_log (GW_LOG_WARN|GW_LOG_ERRNO, module, "gipc_open");
198             return;
199         }
200     }
201     index = 0;
202     while ((msg = str_queue_get (queue, index++)))
203         gip_wline (*gip, msg);
204     signal (SIGPIPE, oldsig);
205 }
206
207 static void monitor_events (int argc, char **argv)
208 {
209     GIP gip_m;
210     int r, gip_m_fd;
211     char line_buf[1024];
212     fd_set set_r;
213     char command[128], *cp;
214     int no_process = 0;
215     int max_process = 4;
216
217     gip_m = gips_initialize ("fifo.s");
218     r = gips_open (gip_m, "fifo.c");
219     gip_m_fd = gip_infileno (gip_m);
220     open ("fifo.s", O_WRONLY);
221
222     while (1)
223     {
224         int fd_max;
225         struct ke_info *ki;
226
227         while (1)
228         {
229             FD_ZERO (&set_r);
230             FD_SET (gip_m_fd, &set_r);
231             gw_log (GW_LOG_DEBUG, module, "set r %d", gip_m_fd);
232             fd_max = gip_m_fd;
233             
234             for (ki = ke_info_list; ki; ki = ki->next)
235             {
236                 if (!ki->queue)
237                     continue;
238                 gw_log (GW_LOG_DEBUG, module, "Transfer mail to %d", ki->id);
239                 deliver (argc, argv, ki->id, ki->queue, &ki->gip, &ki->pid);
240                 str_queue_rm (&ki->queue);
241             }
242             for (ki = ke_info_list; ki; ki = ki->next)
243             {
244                 int fd;
245                 if (ki->gip && (fd = gip_infileno (ki->gip)) != -1)
246                 {
247                     gw_log (GW_LOG_DEBUG, module, "set r %d", fd);
248                     FD_SET (fd, &set_r);
249                     if (fd > fd_max)
250                         fd_max = fd;
251                 }
252             }
253             gw_log (GW_LOG_DEBUG, module, "IPC select");
254             r = select (fd_max+1, &set_r, NULL, NULL, NULL);
255             if (r != -1)
256                 break;
257             if (errno != EINTR)
258             {
259                 gw_log (GW_LOG_FATAL|GW_LOG_ERRNO, module, "select");
260                 exit (1);
261             }
262             gw_log (GW_LOG_DEBUG|GW_LOG_ERRNO, module, "select");
263         }
264         gw_log (GW_LOG_DEBUG, module, "Testing ke_info_list");
265         for (ki = ke_info_list; ki; ki = ki->next)
266         {
267             int fd;
268             if (ki->gip && (fd = gip_infileno (ki->gip)) != -1)
269             {
270                 gw_log (GW_LOG_DEBUG, module, "Test of %d", fd);
271                 if (FD_ISSET (fd, &set_r))
272                 {
273                     if (lgets (line_buf, sizeof(line_buf)-1, fd))
274                     {
275                         gw_log (GW_LOG_DEBUG, module, "IPC: %s", line_buf);
276                     }
277                     else
278                     {
279                         gw_log (GW_LOG_DEBUG, module, "Close of %d", ki->id);
280                         gipc_close (ki->gip);
281                         gipc_destroy (ki->gip);
282                         ki->gip = NULL;
283                     }
284                 }
285             }
286         }
287
288         gw_log (GW_LOG_DEBUG, module, "Testing gip_m_fd %d", gip_m_fd);
289         if (FD_ISSET (gip_m_fd, &set_r))
290         {
291             gw_log (GW_LOG_DEBUG, module, "Reading from %d", gip_m_fd);
292             if (!(lgets (command, sizeof(command)-1, gip_m_fd)))
293             {
294                 gw_log (GW_LOG_FATAL, module, "Unexpected close");
295                 exit (1);
296             }
297             gw_log (GW_LOG_DEBUG, module, "Done");
298             if ((cp = strchr (command, '\n')))
299                 *cp = '\0';
300             gw_log (GW_LOG_DEBUG, module, "IPC: %s", command);
301             if (!memcmp (command, "eti ", 4))
302             {
303                 int id = atoi (command+4);
304                 struct ke_info *new_k;
305                 
306                 new_k = ke_info_add (id);
307                 gw_log (GW_LOG_DEBUG, module, "Incoming mail %d", id);
308                 str_queue_enq (new_k->queue, "mail\n");
309                 while (lgets (line_buf, sizeof(line_buf)-1, gip_m_fd))
310                     str_queue_enq (new_k->queue, line_buf);
311                 str_queue_enq (new_k->queue, "\001");
312             }
313         }
314     }
315 }
316
317 int main (int argc, char **argv)
318 {
319     gw_log_init (*argv);
320     gw_log_level (GW_LOG_ALL);
321     signal (SIGCHLD, catchchild);
322 #if 0
323     gw_log_file (GW_LOG_ALL, "monitor.log");
324 #endif
325     monitor_events (argc, argv);
326     exit (0);
327 }
328
329
330
331