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