3 * Moira server process.
5 * Copyright (C) 1987-1998 by the Massachusetts Institute of Technology
6 * For copying and distribution information, please see the file
11 #include <mit-copyright.h>
12 #include "mr_server.h"
14 #include <sys/socket.h>
16 #include <sys/types.h>
17 #include <sys/utsname.h>
20 #include <netinet/in.h>
21 #include <arpa/inet.h>
44 char krb_realm[REALM_SZ];
46 /* Client array and associated data. This needs to be global for _list_users */
48 int nclients, clientssize;
51 int child_exited_abnormally = 0;
52 int child_pid, child_signal, child_status;
54 void reapchild(int x);
55 void godormant(int x);
57 void clist_append(client *cp);
58 void mr_setup_signals(void);
61 * Main Moira server loop.
63 * Initialize the world, then start accepting connections and
64 * making progress on current connections.
67 int main(int argc, char **argv)
69 int status, i, listener;
72 extern char *database;
75 fd_set readfds, writefds, xreadfds, xwritefds;
76 int nfds, counter = 0;
83 set_com_err_hook(mr_com_err);
84 setvbuf(stderr, NULL, _IOLBF, BUFSIZ);
86 port = strchr(MOIRA_SERVER, ':') + 1;
88 for (i = 1; i < argc; i++)
90 if (!strcmp(argv[i], "-db") && i + 1 < argc)
92 database = argv[i + 1];
95 else if (!strcmp(argv[i], "-p") && i + 1 < argc)
102 com_err(whoami, 0, "Usage: moirad [-db database][-p port]");
107 krb_get_lrealm(krb_realm, 1);
110 * Database initialization. Only init if database should be open.
113 if (stat(MOIRA_MOTD_FILE, &stbuf) != 0)
115 if ((status = mr_open_database()))
117 com_err(whoami, status, "trying to open database.");
120 sanity_check_database();
125 com_err(whoami, 0, "sleeping, not opening database");
128 sanity_check_queries();
131 * Get moira server hostname for authentication
135 com_err(whoami, errno, "Unable to get local hostname");
138 host = canonicalize_hostname(xstrdup(uts.nodename));
139 for (p = host; *p && *p != '.'; p++)
147 * Set up client array handler.
151 clients = xmalloc(clientssize * sizeof(client *));
155 journal = fopen(JOURNAL, "a");
158 com_err(whoami, errno, "opening journal file");
163 * Establish template connection.
165 listener = mr_listen(port);
168 com_err(whoami, MR_ABORTED, "trying to create listening connection");
173 FD_SET(listener, &xreadfds);
176 com_err(whoami, 0, "started (pid %d)", getpid());
177 com_err(whoami, 0, rcsid);
178 if (dormant != ASLEEP)
179 send_zgram("MOIRA", "server started");
181 send_zgram("MOIRA", "server started, but database closed");
184 * Run until shut down.
189 struct timeval timeout = {60, 0}; /* 1 minute */
191 /* If we're supposed to go down and we can, do it */
192 if (((dormant == AWAKE) && (nclients == 0) &&
193 (stat(MOIRA_MOTD_FILE, &stbuf) == 0)) ||
197 com_err(whoami, 0, "database closed");
199 send_zgram("MOIRA", "database closed");
203 /* Block until something happens. */
204 memcpy(&readfds, &xreadfds, sizeof(readfds));
205 memcpy(&writefds, &xwritefds, sizeof(writefds));
206 if (select(nfds, &readfds, &writefds, NULL, &timeout) == -1)
209 com_err(whoami, errno, "in select");
210 if (!inc_running || now - inc_started > INC_TIMEOUT)
218 if (child_exited_abnormally)
220 critical_alert("moirad", "%d: child exits with signal %d status %d",
221 child_pid, child_signal, child_status);
222 child_exited_abnormally = 0;
226 if (!inc_running || now - inc_started > INC_TIMEOUT)
228 tardy = now - 30 * 60;
230 /* If we're asleep and we should wake up, do it */
231 if ((dormant == ASLEEP) && (stat(MOIRA_MOTD_FILE, &stbuf) == -1) &&
235 com_err(whoami, 0, "database open");
237 send_zgram("MOIRA", "database open again");
241 /* Handle any new connections */
242 if (FD_ISSET(listener, &readfds))
244 int newconn, addrlen = sizeof(struct sockaddr_in);
245 struct sockaddr_in addr;
248 newconn = accept(listener, (struct sockaddr *)&addr, &addrlen);
250 com_err(whoami, errno, "accepting new connection");
251 else if (newconn > 0)
253 if (newconn + 1 > nfds)
255 FD_SET(newconn, &xreadfds);
257 /* Add a new client to the array */
259 if (nclients > clientssize)
261 clientssize = 2 * clientssize;
262 clients = xrealloc(clients, clientssize * sizeof(client *));
265 clients[nclients - 1] = cp = xmalloc(sizeof(client));
266 memset(cp, 0, sizeof(client));
269 cp->last_time_used = now;
272 cp->tuples = xmalloc(sizeof(mr_params));
273 memset(cp->tuples, 0, sizeof(mr_params));
274 cp->state = CL_ACCEPTING;
279 "New connection from %s port %d (now %d client%s)",
280 inet_ntoa(cp->haddr.sin_addr),
281 (int)ntohs(cp->haddr.sin_port),
282 nclients, nclients != 1 ? "s" : "");
286 /* Handle any existing connections. */
287 for (i = 0; i < nclients; i++)
289 cur_client = clients[i];
291 if (FD_ISSET(clients[i]->con, &writefds))
293 client_write(clients[i]);
294 if (!clients[i]->ntuples)
296 FD_CLR(clients[i]->con, &xwritefds);
297 FD_SET(clients[i]->con, &xreadfds);
299 clients[i]->last_time_used = now;
302 if (FD_ISSET(clients[i]->con, &readfds))
304 if (clients[i]->state == CL_ACCEPTING)
306 switch(mr_cont_accept(clients[i]->con,
314 clients[i]->state = CL_CLOSING;
318 clients[i]->state = CL_ACTIVE;
319 clients[i]->hsbuf = NULL;
325 client_read(clients[i]);
326 if (clients[i]->ntuples)
328 FD_CLR(clients[i]->con, &xreadfds);
329 FD_SET(clients[i]->con, &xwritefds);
331 clients[i]->last_time_used = now;
335 if (clients[i]->last_time_used < tardy)
337 com_err(whoami, 0, "Shutting down connection due to inactivity");
338 clients[i]->state = CL_CLOSING;
341 if (clients[i]->state == CL_CLOSING)
345 com_err(whoami, 0, "Closed connection (now %d client%s, "
346 "%d queries)", nclients - 1, nclients != 2 ? "s" : "",
349 shutdown(clients[i]->con, 2);
350 close(clients[i]->con);
351 FD_CLR(clients[i]->con, &xreadfds);
352 FD_CLR(clients[i]->con, &xwritefds);
353 free_rtn_tuples(clients[i]);
354 free(clients[i]->tuples);
355 free(clients[i]->hsbuf);
357 clients[i] = clients[--nclients];
367 com_err(whoami, 0, "%s", takedown);
368 if (dormant != ASLEEP)
370 send_zgram("MOIRA", takedown);
374 void reapchild(int x)
378 while ((pid = waitpid(-1, &status, WNOHANG)) > 0)
382 if (!takedown && (WTERMSIG(status) != 0 || WEXITSTATUS(status) != 0))
384 child_exited_abnormally = 1;
386 child_signal = WTERMSIG(status);
387 child_status = WEXITSTATUS(status);
393 void godormant(int x)
399 com_err(whoami, 0, "requested to go dormant");
402 com_err(whoami, 0, "already asleep");
417 com_err(whoami, 0, "Good morning");
420 com_err(whoami, 0, "already awake");
429 void mr_setup_signals(void)
431 struct sigaction action;
434 sigemptyset(&action.sa_mask);
436 /* There should probably be a few more of these. */
438 action.sa_handler = sigshut;
439 if ((sigaction(SIGTERM, &action, NULL) < 0) ||
440 (sigaction(SIGINT, &action, NULL) < 0) ||
441 (sigaction(SIGHUP, &action, NULL) < 0))
443 com_err(whoami, errno, "Unable to establish signal handlers.");
447 action.sa_handler = godormant;
448 if (sigaction(SIGUSR1, &action, NULL) < 0)
450 com_err(whoami, errno, "Unable to establish signal handlers.");
454 action.sa_handler = gowakeup;
455 if (sigaction(SIGUSR2, &action, NULL) < 0)
457 com_err(whoami, errno, "Unable to establish signal handlers.");
461 action.sa_handler = SIG_IGN;
462 if (sigaction(SIGPIPE, &action, NULL) < 0)
464 com_err(whoami, errno, "Unable to establish signal handlers.");
468 action.sa_handler = reapchild;
469 sigaddset(&action.sa_mask, SIGCHLD);
470 if (sigaction(SIGCHLD, &action, NULL) < 0)
472 com_err(whoami, errno, "Unable to establish signal handlers.");