]> andersk Git - moira.git/blame - server/mr_main.c
Update for current file locations (/moira, not /u1/sms) and Oracle
[moira.git] / server / mr_main.c
CommitLineData
0fa91a0a 1/*
2 * $Source$
3 * $Author$
4 * $Header$
5 *
6 * Copyright (C) 1987 by the Massachusetts Institute of Technology
c801de4c 7 * For copying and distribution information, please see the file
8 * <mit-copyright.h>.
0fa91a0a 9 *
d548a4e7 10 * MOIRA server process.
0fa91a0a 11 *
12 * Most of this is stolen from ../gdb/tsr.c
13 *
14 * You are in a maze of twisty little finite automata, all different.
15 * Let the reader beware.
5eaef520 16 *
0fa91a0a 17 */
18
d548a4e7 19static char *rcsid_mr_main_c = "$Header$";
0fa91a0a 20
c801de4c 21#include <mit-copyright.h>
03c05291 22#include <string.h>
23#include <stdio.h>
589993be 24#include <sys/types.h>
70d54e43 25#include <sys/errno.h>
70d54e43 26#include <sys/signal.h>
554776b1 27#include <sys/wait.h>
589993be 28#include <sys/stat.h>
03c05291 29#include <unistd.h>
30#include <signal.h>
d548a4e7 31#include "mr_server.h"
40165bd0 32#include <krb_et.h>
03c05291 33#include <gdss_et.h>
34#include <arpa/inet.h>
70d54e43 35
0ec57336 36extern CONNECTION newconn, listencon;
0fa91a0a 37
0ec57336 38extern int nclients;
39extern client **clients, *cur_client;
0fa91a0a 40
0ec57336 41extern OPERATION listenop;
42extern LIST_OF_OPERATIONS op_list;
0fa91a0a 43
0ec57336 44extern struct sockaddr_in client_addr;
45extern int client_addrlen;
46extern TUPLE client_tuple;
0fa91a0a 47
0ec57336 48extern char *whoami;
49extern char buf1[BUFSIZ];
50extern char *takedown;
51extern int errno;
2f4ff9cd 52extern FILE *journal;
70d54e43 53
0eb9f52f 54extern time_t now;
55
3d0d0f07 56char hostbuf[BUFSIZ], *host;
57
03c05291 58int do_listen(char *port);
59void do_reset_listen(void);
60void clist_append(client *cp);
61void oplist_append(LIST_OF_OPERATIONS *oplp, OPERATION op);
62void oplist_delete(LIST_OF_OPERATIONS oplp, OPERATION op);
63void mr_setup_signals(void);
64int new_connection(void);
e448f08d 65
0ec57336 66/*
d548a4e7 67 * Main MOIRA server loop.
0ec57336 68 *
69 * Initialize the world, then start accepting connections and
70 * making progress on current connections.
71 */
0fa91a0a 72
5eaef520 73int main(int argc, char **argv)
0fa91a0a 74{
5eaef520 75 int status, i;
76 time_t tardy;
77 char *port, *p;
78 extern char *database;
79 struct stat stbuf;
80
81 whoami = argv[0];
82 /*
83 * Error handler init.
84 */
85 initialize_sms_error_table();
86 initialize_krb_error_table();
87 initialize_gdss_error_table();
88 set_com_err_hook(mr_com_err);
89 setvbuf(stderr, NULL, _IOLBF, BUFSIZ);
90
91 port = strchr(MOIRA_SERVER, ':') + 1;
92
93 for (i = 1; i < argc; i++)
94 {
95 if (!strcmp(argv[i], "-db") && i + 1 < argc)
96 {
97 database = argv[i + 1];
98 i++;
5dbd09a0 99 }
5eaef520 100 else if (!strcmp(argv[i], "-p") && i + 1 < argc)
101 {
102 port = argv[i + 1];
103 i++;
f6cc38de 104 }
5eaef520 105 else
106 {
107 com_err(whoami, 0, "Usage: moirad [-db database][-p port]");
3d0d0f07 108 exit(1);
109 }
5eaef520 110 }
111
112 /*
113 * GDB initialization.
114 */
115 if (gdb_init() != 0)
116 {
117 com_err(whoami, 0, "GDB initialization failed.");
118 exit(1);
119 }
120 gdb_debug(0); /* this can be patched, if necessary, to enable */
121 /* GDB level debugging .. */
122 krb_realm = malloc(REALM_SZ);
123 krb_get_lrealm(krb_realm, 1);
124
125 /*
126 * Database initialization. Only init if database should be open.
127 */
128
129 if (stat(MOIRA_MOTD_FILE, &stbuf) != 0)
130 {
131 if ((status = mr_open_database()))
132 {
133 com_err(whoami, status, " when trying to open database.");
134 exit(1);
2f4ff9cd 135 }
5eaef520 136 sanity_check_database();
137 }
138 else
139 {
140 dormant = ASLEEP;
141 com_err(whoami, 0, "sleeping, not opening database");
142 }
2f4ff9cd 143
5eaef520 144 sanity_check_queries();
145
146 /*
147 * Get moira server hostname for authentication
148 */
149 if (gethostname(hostbuf, sizeof(hostbuf)) < 0)
150 {
151 com_err(whoami, errno, "Unable to get local hostname");
152 exit(1);
153 }
154 host = canonicalize_hostname(strsave(hostbuf));
155 for (p = host; *p && *p != '.'; p++)
156 {
157 if (isupper(*p))
158 *p = tolower(*p);
159 }
160 *p = '\0';
161
162 /*
163 * Set up client array handler.
164 */
165 nclients = 0;
166 clients = malloc(0);
167
168 mr_setup_signals();
169
170 journal = fopen(JOURNAL, "a");
171 if (!journal)
172 {
173 com_err(whoami, errno, " while opening journal file");
174 exit(1);
175 }
176
177 /*
178 * Establish template connection.
179 */
180 if ((status = do_listen(port)))
181 {
182 com_err(whoami, status, " while trying to create listening connection");
183 exit(1);
184 }
185
186 op_list = create_list_of_operations(1, listenop);
187
188 com_err(whoami, 0, "started (pid %d)", getpid());
189 com_err(whoami, 0, rcsid_mr_main_c);
190 if (dormant != ASLEEP)
191 send_zgram("MOIRA", "server started");
192 else
193 send_zgram("MOIRA", "server started, but database closed");
194
195 /*
196 * Run until shut down.
197 */
198 while (!takedown)
199 {
44d12d58 200 int i;
5eaef520 201 /*
202 * Block until something happens.
203 */
204 if (dormant == SLEEPY)
205 {
206 mr_close_database();
207 com_err(whoami, 0, "database closed");
208 mr_setup_signals();
209 send_zgram("MOIRA", "database closed");
210 dormant = ASLEEP;
211 }
212 else if (dormant == GROGGY)
213 {
214 mr_open_database();
215 com_err(whoami, 0, "database open");
216 mr_setup_signals();
217 send_zgram("MOIRA", "database open again");
218 dormant = AWAKE;
0ec57336 219 }
589993be 220
5eaef520 221 errno = 0;
222 status = op_select_any(op_list, 0, NULL, NULL, NULL, NULL);
223 if (status == -1)
224 {
225 if (errno != EINTR)
226 com_err(whoami, errno, " error from op_select");
227 if (!inc_running || now - inc_started > INC_TIMEOUT)
228 next_incremental();
229 continue;
230 }
231 else if (status != -2)
232 {
233 com_err(whoami, 0, " wrong return from op_select_any");
234 continue;
235 }
236 if (takedown)
237 break;
238 time(&now);
239 if (!inc_running || now - inc_started > INC_TIMEOUT)
240 next_incremental();
241
242 /*
243 * Handle any new connections; this comes first so
244 * errno isn't tromped on.
245 */
246 if (OP_DONE(listenop))
247 {
248 if (OP_STATUS(listenop) == OP_CANCELLED)
249 {
250 if (errno == EWOULDBLOCK)
251 do_reset_listen();
252 else
253 {
254 static int count = 0;
255 com_err(whoami, errno, " error (%d) on listen", count);
256 if (count++ > 10)
257 exit(1);
0fa91a0a 258 }
5eaef520 259 }
260 else if ((status = new_connection()))
261 {
262 com_err(whoami, errno, " Error on listening operation.");
263 /*
264 * Sleep here to prevent hosing?
265 */
266 }
267 /* if the new connection is our only connection,
268 * and the server is supposed to be down, then go
269 * down now.
270 */
271 if ((dormant == AWAKE) && (nclients == 1) &&
272 (stat(MOIRA_MOTD_FILE, &stbuf) == 0))
273 {
274 com_err(whoami, 0, "motd file exists, slumbertime");
275 dormant = SLEEPY;
276 }
277 /* on new connection, if we are no longer supposed
278 * to be down, then wake up.
279 */
280 if ((dormant == ASLEEP) && (stat(MOIRA_MOTD_FILE, &stbuf) == -1) &&
281 (errno == ENOENT))
282 {
283 com_err(whoami, 0, "motd file no longer exists, waking up");
284 dormant = GROGGY;
285 }
0fa91a0a 286 }
5eaef520 287 /*
288 * Handle any existing connections.
289 */
290 tardy = now - 30 * 60;
291
292 for (i = 0; i < nclients; i++)
293 {
294 cur_client = clients[i];
295 if (OP_DONE(clients[i]->pending_op))
296 {
297 cur_client->last_time_used = now;
298 do_client(cur_client);
299 }
300 else if (clients[i]->last_time_used < tardy)
301 {
302 com_err(whoami, 0, "Shutting down connection due to inactivity");
303 shutdown(cur_client->con->in.fd, 2);
304 }
305 cur_client = NULL;
306 if (takedown)
307 break;
308 }
309 }
310 com_err(whoami, 0, "%s", takedown);
311 if (dormant != ASLEEP)
312 mr_close_database();
313 send_zgram("MOIRA", takedown);
314 return 0;
70d54e43 315}
316
0ec57336 317/*
318 * Set up the template connection and queue the first accept.
319 */
320
5eaef520 321int do_listen(char *port)
70d54e43 322{
5eaef520 323 listencon = create_listening_connection(port);
0ec57336 324
5eaef520 325 if (!listencon)
326 return errno;
0ec57336 327
5eaef520 328 listenop = create_operation();
329 client_addrlen = sizeof(client_addr);
0ec57336 330
5eaef520 331 start_accepting_client(listencon, listenop, &newconn, (char *)&client_addr,
332 &client_addrlen, &client_tuple);
333 return 0;
0fa91a0a 334}
335
b4182127 336
03c05291 337void do_reset_listen(void)
b4182127 338{
5eaef520 339 client_addrlen = sizeof(client_addr);
340 start_accepting_client(listencon, listenop, &newconn, (char *)&client_addr,
341 &client_addrlen, &client_tuple);
b4182127 342}
343
0ec57336 344/*
345 * This routine is called when a new connection comes in.
346 *
347 * It sets up a new client and adds it to the list of currently active clients.
348 */
03c05291 349int new_connection(void)
0fa91a0a 350{
44d12d58 351 client *cp;
5eaef520 352 static counter = 0;
353
354 /*
355 * Make sure there's been no error
356 */
357 if (OP_STATUS(listenop) != OP_COMPLETE)
358 return errno;
359
360 if (!newconn)
361 return MR_NOT_CONNECTED;
362
363 /*
364 * Set up the new connection and reply to the client
365 */
366 cp = malloc(sizeof(client));
367 memset(cp, 0, sizeof(*cp));
368 cp->action = CL_ACCEPT;
369 cp->con = newconn;
370 cp->id = counter++;
371 cp->args = NULL;
372 cp->clname[0] = NULL;
373 cp->reply.mr_argv = NULL;
374 cp->first = NULL;
375 cp->last = NULL;
376 cp->last_time_used = now;
377 newconn = NULL;
378
379 cp->pending_op = create_operation();
380 reset_operation(cp->pending_op);
381 oplist_append(&op_list, cp->pending_op);
382 cur_client = cp;
383
384 /*
385 * Add a new client to the array..
386 */
387 clist_append(cp);
388
389 /*
390 * Let him know we heard him.
391 */
392 start_replying_to_client(cp->pending_op, cp->con, GDB_ACCEPTED, "", "");
393
394 cp->haddr = client_addr;
395
396 /*
397 * Log new connection.
398 */
399 com_err(whoami, 0, "New connection from %s port %d (now %d client%s)",
400 inet_ntoa(cp->haddr.sin_addr), (int)ntohs(cp->haddr.sin_port),
401 nclients, nclients != 1 ? "s" : "");
402
403 /*
404 * Get ready to accept the next connection.
405 */
406 reset_operation(listenop);
407 client_addrlen = sizeof(client_addr);
408
409 start_accepting_client(listencon, listenop, &newconn, (char *)&client_addr,
410 &client_addrlen, &client_tuple);
411 return 0;
0fa91a0a 412}
413
0fa91a0a 414/*
415 * Add a new client to the known clients.
416 */
5eaef520 417void clist_append(client *cp)
418{
419 client **clients_n;
420
421 nclients++;
422 clients_n = malloc(nclients * sizeof(client *));
423 memcpy(clients_n, clients, (nclients - 1) * sizeof(cp));
424 clients_n[nclients - 1] = cp;
425 free(clients);
426 clients = clients_n;
427 clients_n = NULL;
0fa91a0a 428}
429
5eaef520 430
431void clist_delete(client *cp)
70d54e43 432{
5eaef520 433 client **clients_n, **scpp, **dcpp; /* source and dest client ptr ptr */
434
435 int found_it = 0;
436
437 clients_n = malloc((nclients - 1) * sizeof(client *));
438 for (scpp = clients, dcpp = clients_n; scpp < clients + nclients; )
439 {
440 if (*scpp != cp)
441 *dcpp++ = *scpp++;
442 else
443 {
444 scpp++;
445 if (found_it)
446 abort();
447 found_it = 1;
70d54e43 448 }
5eaef520 449 }
450 --nclients;
451 free(clients);
452 clients = clients_n;
453 clients_n = NULL;
454 oplist_delete(op_list, cp->pending_op);
455 reset_operation(cp->pending_op);
456 delete_operation(cp->pending_op);
457 sever_connection(cp->con);
458 free(cp);
70d54e43 459}
0ec57336 460
0fa91a0a 461/*
0ec57336 462 * Add a new operation to a list of operations.
463 *
464 * This should be rewritten to use realloc instead, since in most
465 * cases it won't have to copy the array.
0fa91a0a 466 */
467
5eaef520 468void oplist_append(LIST_OF_OPERATIONS *oplp, OPERATION op)
0fa91a0a 469{
5eaef520 470 int count = (*oplp)->count + 1;
471 LIST_OF_OPERATIONS newlist = (LIST_OF_OPERATIONS)
472 db_alloc(size_of_list_of_operations(count));
473 memcpy(newlist, *oplp, size_of_list_of_operations((*oplp)->count));
474 newlist->count++;
475 newlist->op[count - 1] = op;
476 db_free(*oplp, size_of_list_of_operations(count - 1));
477 *oplp = newlist;
0fa91a0a 478}
479
5eaef520 480void oplist_delete(LIST_OF_OPERATIONS oplp, OPERATION op)
c27b3454 481{
44d12d58 482 OPERATION *s;
483 int c;
5eaef520 484
485 for (s = oplp->op, c = oplp->count; c; --c, ++s)
486 {
487 if (*s == op)
488 {
489 while (c > 0)
490 {
491 *s = *(s + 1);
492 ++s;
493 --c;
494 }
495 oplp->count--;
496 return;
c27b3454 497 }
5eaef520 498 }
499 abort();
c27b3454 500}
554776b1 501
502
5eaef520 503void reapchild(int x)
554776b1 504{
5eaef520 505 int status, pid;
506
507 while ((pid = waitpid(-1, &status, WNOHANG)) > 0)
508 {
509 if (pid == inc_pid)
510 inc_running = 0;
511 if (!takedown && (WTERMSIG(status) != 0 || WEXITSTATUS(status) != 0))
512 com_err(whoami, 0, "%d: child exits with signal %d status %d",
513 pid, WTERMSIG(status), WEXITSTATUS(status));
554776b1 514 }
515}
589993be 516
517
5eaef520 518void godormant(int x)
589993be 519{
5eaef520 520 switch (dormant)
521 {
589993be 522 case AWAKE:
523 case GROGGY:
5eaef520 524 com_err(whoami, 0, "requested to go dormant");
525 break;
589993be 526 case ASLEEP:
5eaef520 527 com_err(whoami, 0, "already asleep");
528 break;
589993be 529 case SLEEPY:
5eaef520 530 break;
589993be 531 }
5eaef520 532 dormant = SLEEPY;
589993be 533}
534
535
5eaef520 536void gowakeup(int x)
589993be 537{
5eaef520 538 switch (dormant)
539 {
589993be 540 case ASLEEP:
541 case SLEEPY:
5eaef520 542 com_err(whoami, 0, "Good morning");
543 break;
589993be 544 case AWAKE:
5eaef520 545 com_err(whoami, 0, "already awake");
546 break;
589993be 547 case GROGGY:
5eaef520 548 break;
589993be 549 }
5eaef520 550 dormant = GROGGY;
589993be 551}
083a6e94 552
5eaef520 553
03c05291 554void mr_setup_signals(void)
083a6e94 555{
5eaef520 556 struct sigaction action;
557
558 action.sa_flags = 0;
559 sigemptyset(&action.sa_mask);
03c05291 560
5eaef520 561 /* There should probably be a few more of these. */
03c05291 562
5eaef520 563 action.sa_handler = sigshut;
564 if ((sigaction(SIGTERM, &action, NULL) < 0) ||
565 (sigaction(SIGINT, &action, NULL) < 0) ||
566 (sigaction(SIGHUP, &action, NULL) < 0))
567 {
03c05291 568 com_err(whoami, errno, "Unable to establish signal handlers.");
569 exit(1);
083a6e94 570 }
e448f08d 571
5eaef520 572 action.sa_handler = godormant;
573 if (sigaction(SIGUSR1, &action, NULL) < 0)
574 {
03c05291 575 com_err(whoami, errno, "Unable to establish signal handlers.");
576 exit(1);
577 }
e448f08d 578
5eaef520 579 action.sa_handler = gowakeup;
580 if (sigaction(SIGUSR2, &action, NULL) < 0)
581 {
03c05291 582 com_err(whoami, errno, "Unable to establish signal handlers.");
583 exit(1);
584 }
e448f08d 585
5eaef520 586 action.sa_handler = reapchild;
587 sigaddset(&action.sa_mask, SIGCHLD);
588 if (sigaction(SIGCHLD, &action, NULL) < 0)
589 {
03c05291 590 com_err(whoami, errno, "Unable to establish signal handlers.");
591 exit(1);
592 }
593}
This page took 0.176107 seconds and 5 git commands to generate.