2 * Copyright (c) 1997, 1999 Hellmuth Michaelis. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 *---------------------------------------------------------------------------
27 * i4b daemon - main program entry
28 * -------------------------------
30 * $Id: main.c,v 1.11 2009/04/16 05:56:32 lukem Exp $
34 * last edit-date: [Mon Jan 8 07:57:26 2001]
36 *---------------------------------------------------------------------------*/
40 #ifdef I4B_EXTERNAL_MONITOR
48 #ifdef I4B_EXTERNAL_MONITOR
50 #ifdef I4B_NOTCPIP_MONITOR
51 /* monitor via local socket */
52 static void mloop(int sockfd
);
53 #else /* I4B_NOTCPIP_MONITOR */
54 /* monitor via local and tcp/ip socket */
55 static void mloop(int localsock
, int remotesock
);
56 #endif /* I4B_NOTCPIP_MONITOR */
58 #else /* I4B_EXTERNAL_MONITOR */
59 /* no monitoring at all */
61 #endif /* I4B_EXTERNAL_MONITOR */
64 static void kbdrdhdl(void);
67 static void isdnrdhdl(void);
68 static void usage(void);
70 #define MSG_BUF_SIZ 1024 /* message buffer size */
72 /*---------------------------------------------------------------------------*
73 * usage display and exit
74 *---------------------------------------------------------------------------*/
78 fprintf(stderr
, "\n");
79 fprintf(stderr
, "isdnd - i4b ISDN manager daemon, version %02d.%02d.%d\n", VERSION
, REL
, STEP
);
81 fprintf(stderr
, " usage: isdnd [-c file] [-d level] [-F] [-f [-r dev] [-t termtype]]\n");
83 fprintf(stderr
, " usage: isdnd [-c file] [-F] [-f [-r dev] [-t termtype]]\n");
85 fprintf(stderr
, " [-l] [-L file] [-m] [-s facility] [-u time]\n");
86 fprintf(stderr
, " -c <filename> configuration file name (def: %s)\n", CONFIG_FILE_DEF
);
88 fprintf(stderr
, " -d <level> set debug flag bits:\n");
89 fprintf(stderr
, " general = 0x%04x, rates = 0x%04x, timing = 0x%04x\n", DL_MSG
, DL_RATES
, DL_TIME
);
90 fprintf(stderr
, " state = 0x%04x, retry = 0x%04x, dial = 0x%04x\n", DL_STATE
, DL_RCVRY
, DL_DIAL
);
91 fprintf(stderr
, " process = 0x%04x, kernio = 0x%04x ctrlstat = 0x%04x\n", DL_PROC
, DL_DRVR
, DL_CNST
);
92 fprintf(stderr
, " rc-file = 0x%04x, budget = 0x%04x\n", DL_RCCF
, DL_BDGT
);
93 fprintf(stderr
, " -dn no debug output on fullscreen display\n");
95 fprintf(stderr
, " -f fullscreen status display\n");
96 fprintf(stderr
, " -F do not become a daemon process\n");
97 fprintf(stderr
, " -l use a logfile instead of syslog\n");
98 fprintf(stderr
, " -L <file> use file instead of %s for logging\n", LOG_FILE_DEF
);
99 fprintf(stderr
, " -P pretty print real config to stdout and exit\n");
100 fprintf(stderr
, " -r <device> redirect output to other device (for -f)\n");
101 fprintf(stderr
, " -s <facility> use facility instead of %d for syslog logging\n", LOG_LOCAL0
>> 3);
102 fprintf(stderr
, " -t <termtype> terminal type of redirected screen (for -f)\n");
103 fprintf(stderr
, " -u <time> length of a charging unit in seconds\n");
104 #ifdef I4B_EXTERNAL_MONITOR
105 fprintf(stderr
, " -m inhibit network/local monitoring (protocol %02d.%02d)\n", MPROT_VERSION
, MPROT_REL
);
107 fprintf(stderr
, "\n");
111 /*---------------------------------------------------------------------------*
113 *---------------------------------------------------------------------------*/
115 main(int argc
, char **argv
)
120 #ifdef I4B_EXTERNAL_MONITOR
121 int sockfd
= -1; /* local monitor socket */
122 #ifndef I4B_NOTCPIP_MONITOR
123 int remotesockfd
= -1; /* tcp/ip monitor socket */
127 setlocale (LC_ALL
, "");
129 while ((i
= getopt(argc
, argv
, "mc:d:fFlL:Pr:s:t:u:")) != -1)
133 #ifdef I4B_EXTERNAL_MONITOR
147 else if ((sscanf(optarg
, "%i", &debug_flags
)) == 1)
158 fprintf(stderr
, "Sorry, no fullscreen mode available - daemon compiled without USE_CURSES\n");
172 strlcpy(logfile
, optarg
, sizeof(logfile
));
185 if (isdigit((unsigned char)*optarg
))
188 logfacility
= strtoul(optarg
, NULL
, 10);
189 facility
= logfacility
<< 3;
191 if ((facility
< LOG_KERN
) ||
192 (facility
> LOG_FTP
&& facility
< LOG_LOCAL0
) ||
193 (facility
> LOG_LOCAL7
))
195 fprintf(stderr
, "Error, option -s has invalid logging facility %d", logfacility
);
198 logfacility
= facility
;
202 fprintf(stderr
, "Error: option -s requires a numeric argument!\n");
213 if (isdigit((unsigned char)*optarg
))
215 unit_length
= strtoul(optarg
, NULL
, 10);
216 if (unit_length
< ULSRC_CMDLMIN
)
217 unit_length
= ULSRC_CMDLMIN
;
218 else if (unit_length
> ULSRC_CMDLMAX
)
219 unit_length
= ULSRC_CMDLMAX
;
224 fprintf(stderr
, "Error: option -T requires a numeric argument!\n");
242 umask(UMASK
); /* set our umask ... */
244 init_log(); /* initialize the logging subsystem */
247 check_pid(); /* check if we are already running */
251 if (do_fork
|| (do_fullscreen
&& do_rdev
)) /* daemon mode ? */
254 write_pid(); /* write our pid to file */
256 /* set signal handler(s) */
258 signal(SIGCHLD
, sigchild_handler
); /* process handling */
259 signal(SIGHUP
, rereadconfig
); /* reread configuration */
260 signal(SIGUSR1
, reopenfiles
); /* reopen acct/log files*/
261 signal(SIGPIPE
, SIG_IGN
); /* handled manually */
262 signal(SIGINT
, do_exit
); /* clean up on SIGINT */
263 signal(SIGTERM
, do_exit
); /* clean up on SIGTERM */
264 signal(SIGQUIT
, do_exit
); /* clean up on SIGQUIT */
267 /* open isdn device */
269 if ((isdnfd
= open(I4BDEVICE
, O_RDWR
)) < 0)
271 logit(LL_ERR
, "main: cannot open %s: %s", I4BDEVICE
, strerror(errno
));
275 /* check kernel and userland have same version/release numbers */
277 if ((ioctl(isdnfd
, I4B_VR_REQ
, &mvr
)) < 0)
279 logit(LL_ERR
, "main: ioctl I4B_VR_REQ failed: %s", strerror(errno
));
283 if (mvr
.version
!= VERSION
)
285 logit(LL_ERR
, "main: version mismatch, kernel %d, daemon %d", mvr
.version
, VERSION
);
289 if (mvr
.release
!= REL
)
291 logit(LL_ERR
, "main: release mismatch, kernel %d, daemon %d", mvr
.release
, REL
);
295 if (mvr
.step
!= STEP
)
297 logit(LL_ERR
, "main: step mismatch, kernel %d, daemon %d", mvr
.step
, STEP
);
301 /* init controller state array */
305 /* read runtime configuration file and configure ourselves */
307 configure(configfile
, 0);
309 if (config_error_flag
)
311 logit(LL_ERR
, "there were %d error(s) in the configuration file, terminating!", config_error_flag
);
315 /* set controller ISDN protocol */
317 init_controller_protocol();
319 /* init active controllers, if any */
321 signal(SIGCHLD
, SIG_IGN
); /*XXX*/
323 init_active_controller();
325 signal(SIGCHLD
, sigchild_handler
); /*XXX*/
327 /* handle the rates stuff */
329 if ((i
= readrates(ratesfile
)) == ERROR
)
331 if (rate_error
!= NULL
)
332 logit(LL_ERR
, "%s", rate_error
);
338 got_rate
= 1; /* flag, ratesfile read and ok */
339 DBGL(DL_RCCF
, (logit(LL_DBG
, "ratesfile %s read successfully", ratesfile
)));
343 if (rate_error
!= NULL
)
344 logit(LL_WRN
, "%s", rate_error
);
347 /* if writing accounting info, open file, set unbuffered */
351 if ((acctfp
= fopen(acctfile
, "a")) == NULL
)
353 logit(LL_ERR
, "ERROR, can't open acctfile %s for writing, terminating!", acctfile
);
356 setvbuf(acctfp
, (char *)NULL
, _IONBF
, 0);
359 /* initialize alias processing */
362 init_alias(aliasfile
);
366 init_holidays(holidayfile
);
368 /* init remote monitoring */
370 #ifdef I4B_EXTERNAL_MONITOR
374 sockfd
= monitor_create_local_socket();
375 #ifndef I4B_NOTCPIP_MONITOR
376 remotesockfd
= monitor_create_remote_socket(monitorport
);
381 /* in case fullscreendisplay, initialize */
390 /* init realtime priority */
393 if (rt_prio
!= RTPRIO_NOTUSED
)
397 rtp
.type
= RTP_PRIO_REALTIME
;
400 if ((rtprio(RTP_SET
, getpid(), &rtp
)) == -1)
402 logit(LL_ERR
, "rtprio failed: %s", strerror(errno
));
408 starttime
= time(NULL
); /* get starttime */
410 srandom(580403); /* init random number gen */
412 mloop( /* enter loop of no return .. */
413 #ifdef I4B_EXTERNAL_MONITOR
415 #ifndef I4B_NOTCPIP_MONITOR
424 /*---------------------------------------------------------------------------*
426 *---------------------------------------------------------------------------*/
434 logit(LL_DMN
, "daemon terminating, exitval = %d", exitval
);
437 if (do_fullscreen
&& curses_ready
)
441 #ifdef I4B_EXTERNAL_MONITOR
448 /*---------------------------------------------------------------------------*
450 *---------------------------------------------------------------------------*/
452 error_exit(int exitval
, const char *fmt
, ...)
458 logit(LL_DMN
, "fatal error, daemon terminating, exitval = %d", exitval
);
461 if (do_fullscreen
&& curses_ready
)
465 #ifdef I4B_EXTERNAL_MONITOR
469 if (mailto
[0] && mailer
[0])
474 char ebuffer
[EXITBL
];
475 char sbuffer
[EXITBL
];
479 vsnprintf(ebuffer
, EXITBL
-1, fmt
, ap
);
482 signal(SIGCHLD
, SIG_IGN
); /* remove handler */
484 snprintf(sbuffer
, sizeof(sbuffer
), "%s%s%s%s%s%s%s%s",
485 "cat << ENDOFDATA | ",
487 " -s \"i4b isdnd: fatal error, terminating\" ",
489 "\nThe isdnd terminated because of a fatal error:\n\n",
491 "\n\nYours sincerely,\n the isdnd\n",
499 /*---------------------------------------------------------------------------*
501 *---------------------------------------------------------------------------*/
504 #ifdef I4B_EXTERNAL_MONITOR
506 #ifndef I4B_NOTCPIP_MONITOR
513 struct timeval timeo
;
519 logit(LL_DMN
, "i4b isdn daemon started (pid = %d)", getpid());
527 FD_SET(STDIN_FILENO
, &set
);
530 FD_SET(isdnfd
, &set
);
534 #ifdef I4B_EXTERNAL_MONITOR
537 if (localmonitor
!= -1) {
538 /* always watch for new connections */
539 FD_SET(localmonitor
, &set
);
540 if (localmonitor
> high_selfd
)
541 high_selfd
= localmonitor
;
543 #ifndef I4B_NOTCPIP_MONITOR
544 if (remotemonitor
!= -1) {
545 FD_SET(remotemonitor
, &set
);
546 if (remotemonitor
> high_selfd
)
547 high_selfd
= remotemonitor
;
551 /* if there are client connections, let monitor module
552 * enter them into the fdset */
555 monitor_prepselect(&set
, &high_selfd
);
563 ret
= select(high_selfd
+ 1, &set
, NULL
, NULL
, &timeo
);
567 if (FD_ISSET(isdnfd
, &set
))
571 if (FD_ISSET(STDIN_FILENO
, &set
))
575 #ifdef I4B_EXTERNAL_MONITOR
578 if (localmonitor
!= -1 && FD_ISSET(localmonitor
, &set
))
579 monitor_handle_connect(localmonitor
, 1);
581 #ifndef I4B_NOTCPIP_MONITOR
582 if (remotemonitor
!= -1 && FD_ISSET(remotemonitor
, &set
))
583 monitor_handle_connect(remotemonitor
, 0);
586 monitor_handle_input(&set
);
594 logit(LL_ERR
, "mloop: ERROR, select error on isdn device, errno = %d!", errno
);
595 error_exit(1, "mloop: ERROR, select error on isdn device, errno = %d!", errno
);
599 /* handle timeout and recovery */
606 /*---------------------------------------------------------------------------*
607 * data from keyboard available, read and process it
608 *---------------------------------------------------------------------------*/
616 case 0x0c: /* control L */
628 /*---------------------------------------------------------------------------*
629 * data from /dev/isdn available, read and process them
630 *---------------------------------------------------------------------------*/
634 static unsigned char msg_rd_buf
[MSG_BUF_SIZ
];
635 msg_hdr_t
*hp
= (msg_hdr_t
*)&msg_rd_buf
[0];
639 if ((len
= read(isdnfd
, msg_rd_buf
, MSG_BUF_SIZ
)) > 0)
643 case MSG_CONNECT_IND
:
644 msg_connect_ind((msg_connect_ind_t
*)msg_rd_buf
, len
);
647 case MSG_CONNECT_ACTIVE_IND
:
648 msg_connect_active_ind((msg_connect_active_ind_t
*)msg_rd_buf
);
651 case MSG_DISCONNECT_IND
:
652 msg_disconnect_ind((msg_disconnect_ind_t
*)msg_rd_buf
);
655 case MSG_DIALOUT_IND
:
656 msg_dialout((msg_dialout_ind_t
*)msg_rd_buf
);
660 msg_accounting((msg_accounting_ind_t
*)msg_rd_buf
);
663 case MSG_IDLE_TIMEOUT_IND
:
664 msg_idle_timeout_ind((msg_idle_timeout_ind_t
*)msg_rd_buf
);
667 case MSG_CHARGING_IND
:
668 msg_charging_ind((msg_charging_ind_t
*)msg_rd_buf
);
671 case MSG_PROCEEDING_IND
:
672 msg_proceeding_ind((msg_proceeding_ind_t
*)msg_rd_buf
);
676 msg_alert_ind((msg_alert_ind_t
*)msg_rd_buf
);
679 case MSG_DRVRDISC_REQ
:
680 msg_drvrdisc_req((msg_drvrdisc_req_t
*)msg_rd_buf
);
683 case MSG_L12STAT_IND
:
684 msg_l12stat_ind((msg_l12stat_ind_t
*)msg_rd_buf
);
688 msg_teiasg_ind((msg_teiasg_ind_t
*)msg_rd_buf
);
692 msg_pdeact_ind((msg_pdeact_ind_t
*)msg_rd_buf
);
695 case MSG_NEGCOMP_IND
:
696 msg_negcomplete_ind((msg_negcomplete_ind_t
*)msg_rd_buf
);
699 case MSG_IFSTATE_CHANGED_IND
:
700 msg_ifstatechg_ind((msg_ifstatechg_ind_t
*)msg_rd_buf
);
703 case MSG_DIALOUTNUMBER_IND
:
704 msg_dialoutnumber((msg_dialoutnumber_ind_t
*)msg_rd_buf
);
708 msg_packet_ind((msg_packet_ind_t
*)msg_rd_buf
);
711 case MSG_CONTR_EV_IND
:
712 msg_ctrl_ev_ind((msg_ctrl_ev_ind_t
*)msg_rd_buf
);
716 logit(LL_WRN
, "ERROR, unknown message received from /dev/isdn (0x%x)", msg_rd_buf
[0]);
722 logit(LL_WRN
, "ERROR, read error on isdn device, errno = %d, length = %d", errno
, len
);
726 /*---------------------------------------------------------------------------*
727 * re-read the config file on SIGHUP or menu command
728 *---------------------------------------------------------------------------*/
730 rereadconfig(int dummy
)
732 logit(LL_DMN
, "re-reading configuration file");
736 #if I4B_EXTERNAL_MONITOR
737 monitor_clear_rights();
740 remove_all_cfg_entries();
742 /* read runtime configuration file and configure ourselves */
744 configure(configfile
, 1);
746 if (config_error_flag
)
748 logit(LL_ERR
, "rereadconfig: there were %d error(s) in the configuration file, terminating!", config_error_flag
);
749 error_exit(1, "rereadconfig: there were %d error(s) in the configuration file, terminating!", config_error_flag
);
754 /* reread alias database */
756 init_alias(aliasfile
);
760 /*---------------------------------------------------------------------------*
761 * re-open the log/acct files on SIGUSR1
762 *---------------------------------------------------------------------------*/
764 reopenfiles(int dummy
)
773 /* if user specified a suffix, rename the old file */
775 if (rotatesuffix
[0] != '\0')
777 char filename
[MAXPATHLEN
];
779 snprintf(filename
, sizeof(filename
), "%s%s", acctfile
, rotatesuffix
);
781 if ((rename(acctfile
, filename
)) != 0)
783 logit(LL_ERR
, "reopenfiles: acct rename failed, cause = %s", strerror(errno
));
784 error_exit(1, "reopenfiles: acct rename failed, cause = %s", strerror(errno
));
788 if ((acctfp
= fopen(acctfile
, "a")) == NULL
)
790 logit(LL_ERR
, "ERROR, can't open acctfile %s for writing, terminating!", acctfile
);
791 error_exit(1, "ERROR, can't open acctfile %s for writing, terminating!", acctfile
);
793 setvbuf(acctfp
, (char *)NULL
, _IONBF
, 0);
800 /* if user specified a suffix, rename the old file */
802 if (rotatesuffix
[0] != '\0')
804 char filename
[MAXPATHLEN
];
806 snprintf(filename
, sizeof(filename
), "%s%s", logfile
, rotatesuffix
);
808 if ((rename(logfile
, filename
)) != 0)
810 logit(LL_ERR
, "reopenfiles: log rename failed, cause = %s", strerror(errno
));
811 error_exit(1, "reopenfiles: log rename failed, cause = %s", strerror(errno
));
815 if ((logfp
= fopen(logfile
, "a")) == NULL
)
817 fprintf(stderr
, "ERROR, cannot open logfile %s: %s\n",
818 logfile
, strerror(errno
));
819 error_exit(1, "reopenfiles: ERROR, cannot open logfile %s: %s\n",
820 logfile
, strerror(errno
));
823 /* set unbuffered operation */
825 setvbuf(logfp
, (char *)NULL
, _IONBF
, 0);