port fix from branch_1_1
[freeradius.git] / src / main / radiusd.c
1 /*
2  * radiusd.c    Main loop of the radius server.
3  *
4  * Version:     $Id$
5  *
6  *   This program is free software; you can redistribute it and/or modify
7  *   it under the terms of the GNU General Public License as published by
8  *   the Free Software Foundation; either version 2 of the License, or
9  *   (at your option) any later version.
10  *
11  *   This program is distributed in the hope that it will be useful,
12  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *   GNU General Public License for more details.
15  *
16  *   You should have received a copy of the GNU General Public License
17  *   along with this program; if not, write to the Free Software
18  *   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  *
20  * Copyright 2000-2004,2006  The FreeRADIUS server project
21  * Copyright 1999,2000  Miquel van Smoorenburg <miquels@cistron.nl>
22  * Copyright 2000  Alan DeKok <aland@ox.org>
23  * Copyright 2000  Alan Curry <pacman-radius@cqc.com>
24  * Copyright 2000  Jeff Carneal <jeff@apex.net>
25  * Copyright 2000  Chad Miller <cmiller@surfsouth.com>
26  */
27
28 #include <freeradius-devel/ident.h>
29 RCSID("$Id$")
30
31 #include <freeradius-devel/autoconf.h>
32
33 #include <sys/file.h>
34
35 #ifdef HAVE_NETINET_IN_H
36 #       include <netinet/in.h>
37 #endif
38
39 #include <stdlib.h>
40 #include <string.h>
41 #include <fcntl.h>
42 #include <ctype.h>
43
44 #ifdef HAVE_UNISTD_H
45 #       include <unistd.h>
46 #endif
47
48 #include <signal.h>
49
50 #ifdef HAVE_GETOPT_H
51 #       include <getopt.h>
52 #endif
53
54 #ifdef HAVE_SYS_SELECT_H
55 #       include <sys/select.h>
56 #endif
57
58 #ifdef HAVE_SYS_WAIT_H
59 #       include <sys/wait.h>
60 #endif
61 #ifndef WEXITSTATUS
62 #       define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
63 #endif
64 #ifndef WIFEXITED
65 #       define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
66 #endif
67
68 #include <freeradius-devel/radiusd.h>
69 #include <freeradius-devel/rad_assert.h>
70 #include <freeradius-devel/modules.h>
71 #include <freeradius-devel/request_list.h>
72 #include <freeradius-devel/radius_snmp.h>
73
74 #define SLEEP_FOREVER (65536)
75
76 /*
77  *  Global variables.
78  */
79 const char *progname = NULL;
80 const char *radius_dir = NULL;
81 const char *radacct_dir = NULL;
82 const char *radlog_dir = NULL;
83 const char *radlib_dir = NULL;
84 int log_stripped_names;
85 int debug_flag = 0;
86 int log_auth_detail = FALSE;
87 int need_reload = FALSE;
88
89 const char *radiusd_version = "FreeRADIUS Version " RADIUSD_VERSION ", for host " HOSTINFO ", built on " __DATE__ " at " __TIME__;
90
91 time_t time_now;
92 static pid_t radius_pid;
93 static int debug_memory = 0;
94
95 /*
96  *  Configuration items.
97  */
98 static int do_exit = 0;
99
100 /*
101  *      Static functions.
102  */
103 static void usage(int);
104
105 static void sig_fatal (int);
106 static void sig_hup (int);
107
108 /*
109  *      The main guy.
110  */
111 int main(int argc, char *argv[])
112 {
113         REQUEST *request;
114         unsigned char buffer[4096];
115         fd_set readfds;
116         int argval;
117         int pid;
118         int max_fd;
119         int status;
120         int sleep_time = SLEEP_FOREVER;
121         int spawn_flag = TRUE;
122         int dont_fork = FALSE;
123         int sig_hup_block = FALSE;
124         time_t last_cleaned_lists = 0;
125
126 #ifdef HAVE_SIGACTION
127         struct sigaction act;
128 #endif
129         rad_listen_t *listener;
130
131 #ifdef OSFC2
132         set_auth_parameters(argc,argv);
133 #endif
134
135         if ((progname = strrchr(argv[0], '/')) == NULL)
136                 progname = argv[0];
137         else
138                 progname++;
139
140         debug_flag = 0;
141         spawn_flag = TRUE;
142         radius_dir = strdup(RADIUS_DIR);
143
144         /*
145          *      Ensure that the configuration is initialized.
146          */
147         memset(&mainconfig, 0, sizeof(mainconfig));
148         mainconfig.myip.af = AF_UNSPEC;
149         mainconfig.port = -1;
150         mainconfig.radiusd_conf = strdup("radiusd.conf");
151
152 #ifdef HAVE_SIGACTION
153         memset(&act, 0, sizeof(act));
154         act.sa_flags = 0 ;
155         sigemptyset( &act.sa_mask ) ;
156 #endif
157
158         /*
159          *      Don't put output anywhere until we get told a little
160          *      more.
161          */
162         mainconfig.radlog_fd = -1;
163         mainconfig.log_file = NULL;
164
165         /*  Process the options.  */
166         while ((argval = getopt(argc, argv, "Aa:bcd:fg:hi:l:mn:p:sSvxXyz")) != EOF) {
167
168                 switch(argval) {
169
170                         case 'A':
171                                 log_auth_detail = TRUE;
172                                 break;
173
174                         case 'a':
175                                 if (radacct_dir) free(radacct_dir);
176                                 radacct_dir = strdup(optarg);
177                                 break;
178
179                         case 'c':
180                                 /* ignore for backwards compatibility with Cistron */
181                                 break;
182
183                         case 'd':
184                                 if (radius_dir) free(radius_dir);
185                                 radius_dir = strdup(optarg);
186                                 break;
187
188                         case 'f':
189                                 dont_fork = TRUE;
190                                 break;
191
192                         case 'h':
193                                 usage(0);
194                                 break;
195
196                         case 'i':
197                                 if (ip_hton(optarg, AF_UNSPEC, &mainconfig.myip) < 0) {
198                                         fprintf(stderr, "radiusd: Invalid IP Address or hostname \"%s\"\n", optarg);
199                                         exit(1);
200                                 }
201                                 break;
202
203                         case 'l':
204                                 if ((strcmp(optarg, "stdout") == 0) ||
205                                     (strcmp(optarg, "stderr") == 0) ||
206                                     (strcmp(optarg, "syslog") == 0)) {
207                                         fprintf(stderr, "radiusd: -l %s is unsupported.  Use log_destination in radiusd.conf\n", optarg);
208                                         exit(1);
209                                 }
210                                 if (radlog_dir) free(radlog_dir);
211                                 radlog_dir = strdup(optarg);
212                                 break;
213
214                         case 'g':
215                                 fprintf(stderr, "radiusd: -g is unsupported.  Use log_destination in radiusd.conf.\n");
216                                 exit(1);
217                                 break;
218
219                         case 'm':
220                                 debug_memory = 1;
221                                 break;
222
223                         case 'n':
224                                 if ((strchr(optarg, '/') != NULL) ||
225                                     (strchr(optarg, '.') != NULL) ||
226                                     (strlen(optarg) > 45)) usage(1);
227
228                                 snprintf(buffer, sizeof(buffer), "%s.conf",
229                                          optarg);
230                                 if (mainconfig.radiusd_conf)
231                                         free(mainconfig.radiusd_conf);
232                                 mainconfig.radiusd_conf = strdup(buffer);
233                                 break;
234
235                         case 'S':
236                                 log_stripped_names++;
237                                 break;
238
239                         case 'p':
240                                 mainconfig.port = atoi(optarg);
241                                 if ((mainconfig.port <= 0) ||
242                                     (mainconfig.port >= 65536)) {
243                                         fprintf(stderr, "radiusd: Invalid port number %s\n", optarg);
244                                         exit(1);
245                                 }
246                                 break;
247
248                         case 's':       /* Single process mode */
249                                 spawn_flag = FALSE;
250                                 dont_fork = TRUE;
251                                 break;
252
253                         case 'v':
254                                 version();
255                                 break;
256
257                                 /*
258                                  *  BIG debugging mode for users who are
259                                  *  TOO LAZY to type '-sfxxyz -l stdout' themselves.
260                                  */
261                         case 'X':
262                                 spawn_flag = FALSE;
263                                 dont_fork = TRUE;
264                                 debug_flag += 2;
265                                 mainconfig.log_auth = TRUE;
266                                 mainconfig.log_auth_badpass = TRUE;
267                                 mainconfig.log_auth_goodpass = TRUE;
268                                 mainconfig.radlog_dest = RADLOG_STDOUT;
269                                 mainconfig.radlog_fd = STDOUT_FILENO;
270                                 break;
271
272                         case 'x':
273                                 debug_flag++;
274                                 break;
275
276                         case 'y':
277                                 mainconfig.log_auth = TRUE;
278                                 mainconfig.log_auth_badpass = TRUE;
279                                 break;
280
281                         case 'z':
282                                 mainconfig.log_auth_badpass = TRUE;
283                                 mainconfig.log_auth_goodpass = TRUE;
284                                 break;
285
286                         default:
287                                 usage(1);
288                                 break;
289                 }
290         }
291
292         /*  Read the configuration files, BEFORE doing anything else.  */
293         if (read_mainconfig(0) < 0) {
294                 exit(1);
295         }
296
297         /*
298          *  Disconnect from session
299          */
300         if (debug_flag == 0 && dont_fork == FALSE) {
301                 pid = fork();
302                 if(pid < 0) {
303                         radlog(L_ERR|L_CONS, "Couldn't fork");
304                         exit(1);
305                 }
306
307                 /*
308                  *  The parent exits, so the child can run in the background.
309                  */
310                 if (pid > 0) {
311                         exit(0);
312                 }
313 #ifdef HAVE_SETSID
314                 setsid();
315 #endif
316         }
317
318         /*
319          *      If we're NOT debugging, trap fatal signals, so we can
320          *      easily clean up after ourselves.
321          *
322          *      If we ARE debugging, don't trap them, so we can
323          *      dump core.
324          */
325         if ((mainconfig.allow_core_dumps == FALSE) && (debug_flag == 0)) {
326 #ifdef SIGSEGV
327 #ifdef HAVE_SIGACTION
328                 act.sa_handler = sig_fatal;
329                 sigaction(SIGSEGV, &act, NULL);
330 #else
331                 signal(SIGSEGV, sig_fatal);
332 #endif
333 #endif
334         }
335
336 #ifdef WITH_SNMP
337         if (mainconfig.do_snmp) radius_snmp_init();
338 #endif
339
340         /*
341          *  Ensure that we're using the CORRECT pid after forking,
342          *  NOT the one we started with.
343          */
344         radius_pid = getpid();
345
346
347         /*
348          *  Only write the PID file if we're running as a daemon.
349          *
350          *  And write it AFTER we've forked, so that we write the
351          *  correct PID.
352          */
353         if (dont_fork == FALSE) {
354                 FILE *fp;
355
356                 fp = fopen(mainconfig.pid_file, "w");
357                 if (fp != NULL) {
358                         /*
359                          *      FIXME: What about following symlinks,
360                          *      and having it over-write a normal file?
361                          */
362                         fprintf(fp, "%d\n", (int) radius_pid);
363                         fclose(fp);
364                 } else {
365                         radlog(L_ERR|L_CONS, "Failed creating PID file %s: %s\n",
366                                mainconfig.pid_file, strerror(errno));
367                         exit(1);
368                 }
369         }
370
371         /*
372          *      If we're running as a daemon, close the default file
373          *      descriptors, AFTER forking.
374          */
375         if (!debug_flag) {
376                 int devnull;
377
378                 devnull = open("/dev/null", O_RDWR);
379                 if (devnull < 0) {
380                         radlog(L_ERR|L_CONS, "Failed opening /dev/null: %s\n",
381                                strerror(errno));
382                         exit(1);
383                 }
384                 dup2(devnull, STDIN_FILENO);
385                 if (mainconfig.radlog_dest == RADLOG_STDOUT) {
386                         mainconfig.radlog_fd = dup(STDOUT_FILENO);
387                 }
388                 dup2(devnull, STDOUT_FILENO);
389                 if (mainconfig.radlog_dest == RADLOG_STDERR) {
390                         mainconfig.radlog_fd = dup(STDERR_FILENO);
391                 }
392                 dup2(devnull, STDERR_FILENO);
393                 close(devnull);
394         }
395
396         /*
397          *      It's called the thread pool, but it does a little
398          *      more than that.
399          */
400         thread_pool_init(spawn_flag);
401
402         /*
403          *  Use linebuffered or unbuffered stdout if
404          *  the debug flag is on.
405          */
406         if (debug_flag == TRUE)
407                 setlinebuf(stdout);
408
409         /*
410          *      Print out which ports we're listening on.
411          */
412         for (listener = mainconfig.listen;
413              listener != NULL;
414              listener = listener->next) {
415                 listener->print(listener, buffer, sizeof(buffer));
416                 switch (listener->type) {
417                 case RAD_LISTEN_AUTH:
418                         DEBUG("Listening on authentication address %s", buffer);
419                         break;
420
421                 case RAD_LISTEN_ACCT:
422                         DEBUG("Listening on accounting address %s", buffer);
423                         break;
424
425                 case RAD_LISTEN_PROXY:
426                         DEBUG("Listening on proxy address %s", buffer);
427                         break;
428
429                 case RAD_LISTEN_DETAIL:
430                         DEBUG("Listening on detail file %s", buffer);
431                         break;
432
433                 default:
434                         break;
435                 }
436         }
437
438         /*
439          *      Now that we've set everything up, we can install the signal
440          *      handlers.  Before this, if we get any signal, we don't know
441          *      what to do, so we might as well do the default, and die.
442          */
443         signal(SIGPIPE, SIG_IGN);
444 #ifdef HAVE_SIGACTION
445         act.sa_handler = sig_hup;
446         sigaction(SIGHUP, &act, NULL);
447         act.sa_handler = sig_fatal;
448         sigaction(SIGTERM, &act, NULL);
449 #else
450         signal(SIGHUP, sig_hup);
451         signal(SIGTERM, sig_fatal);
452 #endif
453         /*
454          *      If we're debugging, then a CTRL-C will cause the
455          *      server to die immediately.  Use SIGTERM to shut down
456          *      the server cleanly in that case.
457          */
458         if ((debug_memory == 1) || (debug_flag == 0)) {
459 #ifdef HAVE_SIGACTION
460                 act.sa_handler = sig_fatal;
461                 sigaction(SIGINT, &act, NULL);
462                 sigaction(SIGQUIT, &act, NULL);
463 #else
464                 signal(SIGINT, sig_fatal);
465                 signal(SIGQUIT, sig_fatal);
466 #endif
467         }
468
469         radlog(L_INFO, "Ready to process requests.");
470
471         /*
472          *  Receive user requests
473          */
474         for (;;) {
475                 /*
476                  *      If we've been told to exit, then do so,
477                  *      even if we have data waiting.
478                  */
479                 if (do_exit) {
480                         DEBUG("Exiting...");
481
482                         /*
483                          *      Ignore the TERM signal: we're about
484                          *      to die.
485                          */
486                         signal(SIGTERM, SIG_IGN);
487
488                         /*
489                          *      Send a TERM signal to all associated
490                          *      processes (including us, which gets
491                          *      ignored.)
492                          */
493                         kill(-radius_pid, SIGTERM);
494
495                         /*
496                          *      FIXME: Kill child threads, and
497                          *      clean up?
498                          */
499
500                         /*
501                          *      FIXME: clean up any active REQUEST
502                          *      handles.
503                          */
504
505                         /*
506                          *      We're exiting, so we can delete the PID
507                          *      file.  (If it doesn't exist, we can ignore
508                          *      the error returned by unlink)
509                          */
510                         if (dont_fork == FALSE) {
511                                 unlink(mainconfig.pid_file);
512                         }
513
514                         /*
515                          *      Free the configuration items.
516                          */
517                         free_mainconfig();
518
519                         /*
520                          *      Detach any modules.
521                          */
522                         detach_modules();
523
524                         free(radius_dir);
525
526                         /*
527                          *      SIGTERM gets do_exit=0,
528                          *      and we want to exit cleanly.
529                          *
530                          *      Other signals make us exit
531                          *      with an error status.
532                          */
533                         exit(do_exit - 1);
534                 }
535
536                 if (need_reload) {
537 #ifdef HAVE_PTHREAD_H
538                         /*
539                          *      Threads: wait for all threads to stop
540                          *      processing before re-loading the
541                          *      config, so we don't pull the rug out
542                          *      from under them.
543                          */
544                         int max_wait = 0;
545                         if (spawn_flag) for(;;) {
546                                 /*
547                                  * Block until there are '0' threads
548                                  * with a REQUEST handle.
549                                  */
550                                 sig_hup_block = TRUE;
551                                 if( (total_active_threads() == 0) ||
552                                     (max_wait >= 5) ) {
553                                         sig_hup_block = FALSE;
554                                         break;
555                                 }
556                                 sleep(1);
557                                 max_wait++;
558                         }
559 #endif
560                         if (read_mainconfig(TRUE) < 0) {
561                                 exit(1);
562                         }
563
564                         need_reload = FALSE;
565                         radlog(L_INFO, "Ready to process requests.");
566                 }
567
568                 FD_ZERO(&readfds);
569                 max_fd = 0;
570
571                 /*
572                  *      Loop over all the listening FD's.
573                  */
574                 for (listener = mainconfig.listen;
575                      listener != NULL;
576                      listener = listener->next) {
577                         if (listener->fd < 0) continue;
578
579                         FD_SET(listener->fd, &readfds);
580                         if (listener->fd > max_fd) max_fd = listener->fd;
581                 }
582
583 #ifdef WITH_SNMP
584                 if (mainconfig.do_snmp &&
585                     (rad_snmp.smux_fd >= 0)) {
586                         FD_SET(rad_snmp.smux_fd, &readfds);
587                         if (rad_snmp.smux_fd > max_fd) max_fd = rad_snmp.smux_fd;
588                 }
589 #endif
590
591                 if (sleep_time == SLEEP_FOREVER) {
592                         DEBUG2("Nothing to do.  Sleeping until we see a request.");
593                         status = select(max_fd + 1, &readfds, NULL, NULL, NULL);
594                 } else {
595                         struct timeval tv;
596
597                         DEBUG2("Waking up in %d seconds...", sleep_time);
598
599                         tv.tv_sec = sleep_time;
600                         tv.tv_usec = 0;
601                         status = select(max_fd + 1, &readfds, NULL, NULL, &tv);
602                 }
603                 if (status == -1) {
604                         /*
605                          *      On interrupts, we clean up the request
606                          *      list.  We then continue with the loop,
607                          *      so that if we're supposed to exit,
608                          *      then the code at the start of the loop
609                          *      catches that, and exits.
610                          */
611                         if (errno == EINTR) {
612 #ifdef MEMORY_USE_DEBUGGING
613                                 /*
614                                  *      Run the server in debugging mode,
615                                  *      without threads, and give it a
616                                  *      SIGHUP.  It will clean up after
617                                  *      itself, and any memory left over
618                                  *      should be allocated by C libraries,
619                                  *      and the like.
620                                  */
621                                 detach_modules();
622                                 free_mainconfig();
623                                 exit(1);
624 #endif
625                                 continue;
626                         }
627                         radlog(L_ERR, "Unexpected error in select(): %s",
628                                         strerror(errno));
629                         exit(1);
630                 }
631
632                 time_now = time(NULL);
633 #ifndef HAVE_PTHREAD_H
634                 /*
635                  *      If there are no child threads, then there may
636                  *      be child processes.  In that case, wait for
637                  *      their exit status, and throw that exit status
638                  *      away.  This helps get rid of zxombie children.
639                  */
640                 while (waitpid(-1, &argval, WNOHANG) > 0) {
641                         /* do nothing */
642                 }
643 #endif
644
645                 /*
646                  *      Loop over the open socket FD's, reading any data.
647                  */
648                 for (listener = mainconfig.listen;
649                      listener != NULL;
650                      listener = listener->next) {
651                         RAD_REQUEST_FUNP fun;
652
653                         if ((listener->fd >= 0) &&
654                             !FD_ISSET(listener->fd, &readfds))
655                                 continue;
656
657                         /*
658                          *  Receive the packet.
659                          */
660                         if (sig_hup_block != FALSE) {
661                                 continue;
662                         }
663
664                         /*
665                          *      Do per-socket receive processing of the
666                          *      packet.
667                          */
668                         if (!listener->recv(listener, &fun, &request)) {
669                                 continue;
670                         }
671                         
672                         /*
673                          *      Drop the request into the thread pool,
674                          *      and let the thread pool take care of
675                          *      doing something with it.
676                          */
677                         if (!thread_pool_addrequest(request, fun)) {
678                                 /*
679                                  *      FIXME: Maybe just drop
680                                  *      the packet on the floor?
681                                  */
682                                 request_reject(request, REQUEST_FAIL_NO_THREADS);
683                                 request->finished = TRUE;
684                         }
685                 } /* loop over listening sockets*/
686
687 #ifdef WITH_SNMP
688                 if (mainconfig.do_snmp) {
689                         /*
690                          *  After handling all authentication/accounting
691                          *  requests, THEN process any pending SMUX/SNMP
692                          *  queries.
693                          *
694                          *  Note that the handling is done in the main server,
695                          *  which probably isn't a Good Thing.  It really
696                          *  should be wrapped, and handled in a thread pool.
697                          */
698                         if ((rad_snmp.smux_fd >= 0) &&
699                             FD_ISSET(rad_snmp.smux_fd, &readfds) &&
700                             (rad_snmp.smux_event == SMUX_READ)) {
701                                 smux_read();
702                         }
703
704                         /*
705                          *  If we've got to re-connect, then do so now,
706                          *  before calling select again.
707                          */
708                         if (rad_snmp.smux_event == SMUX_CONNECT) {
709                                 smux_connect();
710                         }
711                 }
712 #endif
713
714                 /*
715                  *      Loop through the request lists once per
716                  *      second, to clean up old requests.
717                  */
718                 if (last_cleaned_lists != time_now) {
719                         last_cleaned_lists = time_now;
720
721                         DEBUG2("--- Walking the entire request list ---");
722                         sleep_time = SLEEP_FOREVER;
723                         for (listener = mainconfig.listen;
724                              listener != NULL;
725                              listener = listener->next) {
726                                 int next;
727                                 
728                                 next = listener->update(listener, time_now);
729                                 if (next < sleep_time) {
730                                         sleep_time = next;
731                                 }
732                         }
733                 }
734
735 #ifdef HAVE_PTHREAD_H
736
737                 /*
738                  *      Only clean the thread pool if we're spawning
739                  *      child threads. 
740                  */
741                 if (spawn_flag) {
742                         thread_pool_clean(time_now);
743                 }
744 #endif
745         } /* loop forever */
746 }
747
748
749 /*
750  *  Display the syntax for starting this program.
751  */
752 static void NEVER_RETURNS usage(int status)
753 {
754         FILE *output = status?stderr:stdout;
755
756         fprintf(output,
757                         "Usage: %s [-a acct_dir] [-d db_dir] [-l log_dir] [-i address] [-AcfnsSvXxyz]\n", progname);
758         fprintf(output, "Options:\n\n");
759         fprintf(output, "  -a acct_dir     use accounting directory 'acct_dir'.\n");
760         fprintf(output, "  -A              Log auth detail.\n");
761         fprintf(output, "  -d raddb_dir    Configuration files are in \"raddbdir/*\".\n");
762         fprintf(output, "  -f              Run as a foreground process, not a daemon.\n");
763         fprintf(output, "  -h              Print this help message.\n");
764         fprintf(output, "  -i ipaddr       Listen on ipaddr ONLY\n");
765         fprintf(output, "  -l log_dir      Log file is \"log_dir/radius.log\" (not used in debug mode)\n");
766         fprintf(output, "  -p port         Listen on port ONLY\n");
767         fprintf(output, "  -s              Do not spawn child processes to handle requests.\n");
768         fprintf(output, "  -S              Log stripped names.\n");
769         fprintf(output, "  -v              Print server version information.\n");
770         fprintf(output, "  -X              Turn on full debugging.\n");
771         fprintf(output, "  -x              Turn on additional debugging. (-xx gives more debugging).\n");
772         fprintf(output, "  -y              Log authentication failures, with password.\n");
773         fprintf(output, "  -z              Log authentication successes, with password.\n");
774         exit(status);
775 }
776
777
778 /*
779  *      We got a fatal signal.
780  */
781 static void sig_fatal(int sig)
782 {
783         switch(sig) {
784                 case SIGSEGV:
785                         /* We can't really do anything intelligent here so just die */
786                         _exit(1);
787                 case SIGTERM:
788                         do_exit = 1;
789                         break;
790                 case SIGINT:
791                 case SIGQUIT:
792                         if (debug_memory) {
793                                 do_exit = 1;
794                                 break;
795                         }
796
797                 default:
798                         do_exit = 2;
799                         break;
800         }
801 }
802
803
804 /*
805  *  We got the hangup signal.
806  *  Re-read the configuration files.
807  */
808 /*ARGSUSED*/
809 static void sig_hup(int sig)
810 {
811         sig = sig; /* -Wunused */
812
813         reset_signal(SIGHUP, sig_hup);
814
815         /*
816          *  Only do the reload if we're the main server, both
817          *  for processes, and for threads.
818          */
819         if (getpid() == radius_pid) {
820                 need_reload = TRUE;
821         }
822 #ifdef WITH_SNMP
823         if (mainconfig.do_snmp) {
824                 rad_snmp.smux_failures = 0;
825                 rad_snmp.smux_event = SMUX_CONNECT;
826         }
827 #endif
828 }