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