]> andersk Git - moira.git/blob - server/mr_main.c
Use moira_schema.h
[moira.git] / server / mr_main.c
1 /* $Id$
2  *
3  * Moira server process.
4  *
5  * Copyright (C) 1987-1998 by the Massachusetts Institute of Technology
6  * For copying and distribution information, please see the file
7  * <mit-copyright.h>.
8  *
9  */
10
11 #include <mit-copyright.h>
12 #include "mr_server.h"
13
14 #include <sys/socket.h>
15 #include <sys/stat.h>
16 #include <sys/types.h>
17 #include <sys/utsname.h>
18 #include <sys/wait.h>
19
20 #include <netinet/in.h>
21 #include <arpa/inet.h>
22
23 #include <ctype.h>
24 #include <errno.h>
25 #include <signal.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <unistd.h>
30
31 #include <krb.h>
32
33 RCSID("$Header$");
34
35 extern char *krb_get_lrealm(char *, int);
36
37 client *cur_client;
38
39 char *whoami;
40 char *takedown;
41 FILE *journal;
42
43 time_t now;
44
45 char *host;
46 char krb_realm[REALM_SZ];
47
48 /* Client array and associated data. This needs to be global for _list_users */
49 client **clients;
50 int nclients, clientssize;
51
52 int dormant;
53
54 void reapchild(int x);
55 void godormant(int x);
56 void gowakeup(int x);
57 void clist_append(client *cp);
58 void mr_setup_signals(void);
59
60 /*
61  * Main Moira server loop.
62  *
63  * Initialize the world, then start accepting connections and
64  * making progress on current connections.
65  */
66
67 int main(int argc, char **argv)
68 {
69   int status, i, listener;
70   time_t tardy;
71   char *port, *p;
72   extern char *database;
73   struct stat stbuf;
74   struct utsname uts;
75   fd_set readfds, writefds, xreadfds, xwritefds;
76   int nfds, counter = 0;
77
78   whoami = argv[0];
79   /*
80    * Error handler init.
81    */
82   mr_init();
83   set_com_err_hook(mr_com_err);
84   setvbuf(stderr, NULL, _IOLBF, BUFSIZ);
85
86   port = strchr(MOIRA_SERVER, ':') + 1;
87
88   for (i = 1; i < argc; i++)
89     {
90       if (!strcmp(argv[i], "-db") && i + 1 < argc)
91         {
92           database = argv[i + 1];
93           i++;
94         }
95       else if (!strcmp(argv[i], "-p") && i + 1 < argc)
96         {
97           port = argv[i + 1];
98           i++;
99         }
100       else
101         {
102           com_err(whoami, 0, "Usage: moirad [-db database][-p port]");
103           exit(1);
104         }
105     }
106
107   krb_get_lrealm(krb_realm, 1);
108
109   /*
110    * Database initialization.  Only init if database should be open.
111    */
112
113   if (stat(MOIRA_MOTD_FILE, &stbuf) != 0)
114     {
115       if ((status = mr_open_database()))
116         {
117           com_err(whoami, status, "trying to open database.");
118           exit(1);
119         }
120       sanity_check_database();
121     }
122   else
123     {
124       dormant = ASLEEP;
125       com_err(whoami, 0, "sleeping, not opening database");
126     }
127
128   sanity_check_queries();
129
130   /*
131    * Get moira server hostname for authentication
132    */
133   if (uname(&uts) < 0)
134     {
135       com_err(whoami, errno, "Unable to get local hostname");
136       exit(1);
137     }
138   host = canonicalize_hostname(xstrdup(uts.nodename));
139   for (p = host; *p && *p != '.'; p++)
140     {
141       if (isupper(*p))
142         *p = tolower(*p);
143     }
144   *p = '\0';
145
146   /*
147    * Set up client array handler.
148    */
149   nclients = 0;
150   clientssize = 10;
151   clients = xmalloc(clientssize * sizeof(client *));
152
153   mr_setup_signals();
154
155   journal = fopen(JOURNAL, "a");
156   if (!journal)
157     {
158       com_err(whoami, errno, "opening journal file");
159       exit(1);
160     }
161
162   /*
163    * Establish template connection.
164    */
165   if (!(listener = mr_listen(port)))
166     {
167       com_err(whoami, status, "trying to create listening connection");
168       exit(1);
169     }
170   FD_ZERO(&xreadfds);
171   FD_ZERO(&xwritefds);
172   FD_SET(listener, &xreadfds);
173   nfds = listener + 1;
174
175   com_err(whoami, 0, "started (pid %d)", getpid());
176   com_err(whoami, 0, rcsid);
177   if (dormant != ASLEEP)
178     send_zgram("MOIRA", "server started");
179   else
180     send_zgram("MOIRA", "server started, but database closed");
181
182   /*
183    * Run until shut down.
184    */
185   while (!takedown)
186     {
187       int i;
188       struct timeval timeout;
189
190       /* If we're supposed to go down and we can, do it */
191       if ((dormant == AWAKE) && (nclients == 0) &&
192           (stat(MOIRA_MOTD_FILE, &stbuf) == 0))
193         {
194           mr_close_database();
195           com_err(whoami, 0, "database closed");
196           mr_setup_signals();
197           send_zgram("MOIRA", "database closed");
198           dormant = ASLEEP;
199         }
200
201       /* Block until something happens. */
202       memcpy(&readfds, &xreadfds, sizeof(readfds));
203       memcpy(&writefds, &xwritefds, sizeof(writefds));
204       /* XXX set timeout */
205       if (select(nfds, &readfds, &writefds, NULL, NULL) == -1)
206         {
207           if (errno != EINTR)
208             com_err(whoami, errno, "in select");
209           if (!inc_running || now - inc_started > INC_TIMEOUT)
210             next_incremental();
211           continue;
212         }
213
214       if (takedown)
215         break;
216       time(&now);
217       if (!inc_running || now - inc_started > INC_TIMEOUT)
218         next_incremental();
219       tardy = now - 30 * 60;
220
221       /* If we're asleep and we should wake up, do it */
222       if ((dormant == ASLEEP) && (stat(MOIRA_MOTD_FILE, &stbuf) == -1) &&
223           (errno == ENOENT))
224         {
225           mr_open_database();
226           com_err(whoami, 0, "database open");
227           mr_setup_signals();
228           send_zgram("MOIRA", "database open again");
229           dormant = AWAKE;
230         }
231
232       /* Handle any new connections */
233       if (FD_ISSET(listener, &readfds))
234         {
235           int newconn;
236           struct sockaddr_in addr;
237           client *cp;
238
239           newconn = mr_accept(listener, &addr);
240           if (newconn == -1)
241             com_err(whoami, errno, "accepting new connection");
242           else if (newconn > 0)
243             {
244               if (newconn + 1 > nfds)
245                 nfds = newconn + 1;
246               FD_SET(newconn, &xreadfds);
247
248               /* Add a new client to the array */
249               nclients++;
250               if (nclients > clientssize)
251                 {
252                   clientssize = 2 * clientssize;
253                   clients = xrealloc(clients, clientssize * sizeof(client *));
254                 }
255
256               clients[nclients - 1] = cp = xmalloc(sizeof(client));
257               memset(cp, 0, sizeof(client));
258               cp->con = newconn;
259               cp->id = counter++;
260               cp->last_time_used = now;
261               cp->haddr = addr;
262               cp->tuplessize = 1;
263               cp->tuples = xmalloc(sizeof(mr_params));
264               memset(cp->tuples, 0, sizeof(mr_params));
265
266               cur_client = cp;
267               com_err(whoami, 0,
268                       "New connection from %s port %d (now %d client%s)",
269                       inet_ntoa(cp->haddr.sin_addr),
270                       (int)ntohs(cp->haddr.sin_port),
271                       nclients, nclients != 1 ? "s" : "");
272             }
273         }
274
275       /* Handle any existing connections. */
276       for (i = 0; i < nclients; i++)
277         {
278           cur_client = clients[i];
279
280           if (FD_ISSET(clients[i]->con, &writefds))
281             {
282               client_write(clients[i]);
283               if (!clients[i]->ntuples)
284                 {
285                   FD_CLR(clients[i]->con, &xwritefds);
286                   /* Now that we're done writing we can read again */
287                   FD_SET(clients[i]->con, &xreadfds);
288                 }
289               clients[i]->last_time_used = now;
290             }
291
292           if (FD_ISSET(clients[i]->con, &readfds))
293             {
294               client_read(clients[i]);
295               if (clients[i]->ntuples)
296                 FD_SET(clients[i]->con, &xwritefds);
297               clients[i]->last_time_used = now;
298             }
299
300           if (clients[i]->last_time_used < tardy)
301             {
302               com_err(whoami, 0, "Shutting down connection due to inactivity");
303               clients[i]->done = 1;
304             }
305
306           if (clients[i]->done)
307             {
308               client *old;
309
310               com_err(whoami, 0, "Closed connection (now %d client%s, "
311                       "%d queries)", nclients - 1, nclients != 2 ? "s" : "",
312                       newqueries);
313
314               shutdown(clients[i]->con, 2);
315               close(clients[i]->con);
316               FD_CLR(clients[i]->con, &xreadfds);
317               FD_CLR(clients[i]->con, &xwritefds);
318               for (; clients[i]->ntuples; clients[i]->ntuples--)
319                 mr_destroy_reply(clients[i]->tuples[clients[i]->ntuples - 1]);
320               free(clients[i]->tuples);
321               old = clients[i];
322               clients[i] = clients[--nclients];
323               free(old);
324             }
325
326           cur_client = NULL;
327           if (takedown)
328             break;
329         }
330     }
331
332   com_err(whoami, 0, "%s", takedown);
333   if (dormant != ASLEEP)
334     mr_close_database();
335   send_zgram("MOIRA", takedown);
336   return 0;
337 }
338
339 void reapchild(int x)
340 {
341   int status, pid;
342
343   while ((pid = waitpid(-1, &status, WNOHANG)) > 0)
344     {
345       if (pid == inc_pid)
346         inc_running = 0;
347       if (!takedown && (WTERMSIG(status) != 0 || WEXITSTATUS(status) != 0))
348         com_err(whoami, 0, "%d: child exits with signal %d status %d",
349                 pid, WTERMSIG(status), WEXITSTATUS(status));
350     }
351 }
352
353
354 void godormant(int x)
355 {
356   switch (dormant)
357     {
358     case AWAKE:
359     case GROGGY:
360       com_err(whoami, 0, "requested to go dormant");
361       break;
362     case ASLEEP:
363       com_err(whoami, 0, "already asleep");
364       break;
365     case SLEEPY:
366       break;
367     }
368   dormant = SLEEPY;
369 }
370
371
372 void gowakeup(int x)
373 {
374   switch (dormant)
375     {
376     case ASLEEP:
377     case SLEEPY:
378       com_err(whoami, 0, "Good morning");
379       break;
380     case AWAKE:
381       com_err(whoami, 0, "already awake");
382       break;
383     case GROGGY:
384       break;
385     }
386   dormant = GROGGY;
387 }
388
389
390 void mr_setup_signals(void)
391 {
392   struct sigaction action;
393
394   action.sa_flags = 0;
395   sigemptyset(&action.sa_mask);
396
397   /* There should probably be a few more of these. */
398
399   action.sa_handler = sigshut;
400   if ((sigaction(SIGTERM, &action, NULL) < 0) ||
401       (sigaction(SIGINT, &action, NULL) < 0) ||
402       (sigaction(SIGHUP, &action, NULL) < 0))
403     {
404       com_err(whoami, errno, "Unable to establish signal handlers.");
405       exit(1);
406     }
407
408   action.sa_handler = godormant;
409   if (sigaction(SIGUSR1, &action, NULL) < 0)
410     {
411       com_err(whoami, errno, "Unable to establish signal handlers.");
412       exit(1);
413     }
414
415   action.sa_handler = gowakeup;
416   if (sigaction(SIGUSR2, &action, NULL) < 0)
417     {
418       com_err(whoami, errno, "Unable to establish signal handlers.");
419       exit(1);
420     }
421
422   action.sa_handler = reapchild;
423   sigaddset(&action.sa_mask, SIGCHLD);
424   if (sigaction(SIGCHLD, &action, NULL) < 0)
425     {
426       com_err(whoami, errno, "Unable to establish signal handlers.");
427       exit(1);
428     }
429 }
This page took 0.067551 seconds and 5 git commands to generate.