MFC r1.6 r1.30 r1.28 (HEAD):
[dragonfly.git] / usr.sbin / i4b / isdnd / exec.c
blob52f03f2fde7e8bbf148f4087fc9f29cbc44e8971
1 /*
2 * Copyright (c) 1997, 2001 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
6 * are met:
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
23 * SUCH DAMAGE.
25 *---------------------------------------------------------------------------
27 * exec.h - supplemental program/script execution
28 * ----------------------------------------------
30 * $FreeBSD: src/usr.sbin/i4b/isdnd/exec.c,v 1.6.2.4 2001/12/10 09:42:52 hm Exp $
31 * $DragonFly: src/usr.sbin/i4b/isdnd/exec.c,v 1.3 2004/03/26 00:30:12 cpressey Exp $
33 * last edit-date: [Mon Dec 10 10:39:53 2001]
35 *---------------------------------------------------------------------------*/
37 #include "isdnd.h"
39 #include <sys/wait.h>
40 #include <sys/socket.h>
41 #include <net/if.h>
42 #include <netinet/in.h>
43 #include <arpa/inet.h>
44 #include <paths.h>
46 #define MAX_PIDS 32
48 static struct pid_tab {
49 pid_t pid;
50 cfg_entry_t *cep;
51 } pid_tab[MAX_PIDS];
53 /*---------------------------------------------------------------------------*
54 * SIGCHLD signal handler
55 *---------------------------------------------------------------------------*/
56 void
57 sigchild_handler(int sig)
59 int retstat;
60 int i;
61 pid_t pid;
63 if((pid = waitpid(-1, &retstat, WNOHANG)) <= 0)
65 log(LL_ERR, "ERROR, sigchild_handler, waitpid: %s", strerror(errno));
66 error_exit(1, "ERROR, sigchild_handler, waitpid: %s", strerror(errno));
68 else
70 if(WIFEXITED(retstat))
72 DBGL(DL_PROC, (log(LL_DBG, "normal child (pid=%d) termination, exitstat = %d",
73 pid, WEXITSTATUS(retstat))));
75 else if(WIFSIGNALED(retstat))
77 if(WCOREDUMP(retstat))
78 log(LL_WRN, "child (pid=%d) termination due to signal %d (coredump)",
79 pid, WTERMSIG(retstat));
80 else
81 log(LL_WRN, "child (pid=%d) termination due to signal %d",
82 pid, WTERMSIG(retstat));
86 /* check if hangup required */
88 for(i=0; i < MAX_PIDS; i++)
90 if(pid_tab[i].pid == pid)
92 if(pid_tab[i].cep->cdid != CDID_UNUSED)
94 DBGL(DL_PROC, (log(LL_DBG, "sigchild_handler: scheduling hangup for cdid %d, pid %d",
95 pid_tab[i].cep->cdid, pid_tab[i].pid)));
96 pid_tab[i].cep->hangup = 1;
98 pid_tab[i].pid = 0;
99 break;
104 /*---------------------------------------------------------------------------*
105 * execute prog as a subprocess and pass an argumentlist
106 *---------------------------------------------------------------------------*/
107 pid_t
108 exec_prog(char *prog, char **arglist)
110 char tmp[MAXPATHLEN];
111 char path[MAXPATHLEN+1];
112 pid_t pid;
113 int a;
115 snprintf(path, sizeof(path), "%s/%s", ETCPATH, prog);
117 arglist[0] = path;
119 tmp[0] = '\0';
121 for(a=1; arglist[a] != NULL; ++a )
123 strcat(tmp, " " );
124 strcat(tmp, arglist[a]);
127 DBGL(DL_PROC, (log(LL_DBG, "exec_prog: %s, args:%s", path, tmp)));
129 switch(pid = fork())
131 case -1: /* error */
132 log(LL_ERR, "ERROR, exec_prog/fork: %s", strerror(errno));
133 error_exit(1, "ERROR, exec_prog/fork: %s", strerror(errno));
134 case 0: /* child */
135 break;
136 default: /* parent */
137 return(pid);
140 /* this is the child now */
143 * close files used only by isdnd, e.g.
144 * 1. /dev/i4b
145 * 2. /var/log/isdnd.acct (or similar, when used)
146 * 3. /var/log/isdnd.log (or similar, when used)
148 close(isdnfd);
150 if(useacctfile && acctfp)
151 fclose(acctfp);
153 if(uselogfile && logfp)
154 fclose(logfp);
156 if(execvp(path,arglist) < 0 )
157 _exit(127);
159 return(-1);
162 /*---------------------------------------------------------------------------*
163 * run interface up/down script
164 *---------------------------------------------------------------------------*/
166 exec_connect_prog(cfg_entry_t *cep, const char *prog, int link_down)
168 char *argv[32], **av = argv;
169 char devicename[MAXPATHLEN], addr[100];
170 char *device;
171 int s;
172 struct ifreq ifr;
174 /* the obvious things */
175 device = bdrivername(cep->usrdevicename);
176 snprintf(devicename, sizeof(devicename), "%s%d", device, cep->usrdeviceunit);
177 *av++ = (char*)prog;
178 *av++ = "-d";
179 *av++ = devicename;
180 *av++ = "-f";
181 *av++ = link_down ? "down" : "up";
183 /* try to figure AF_INET address of interface */
184 addr[0] = '\0';
185 memset(&ifr, 0, sizeof ifr);
186 ifr.ifr_addr.sa_family = AF_INET;
187 strncpy(ifr.ifr_name, devicename, sizeof(ifr.ifr_name));
188 s = socket(AF_INET, SOCK_DGRAM, 0);
189 if (s >= 0) {
190 if (ioctl(s, SIOCGIFADDR, (caddr_t)&ifr) >= 0) {
191 struct sockaddr_in *sin = (struct sockaddr_in *)&ifr.ifr_addr;
192 strcpy(addr, inet_ntoa(sin->sin_addr));
193 *av++ = "-a";
194 *av++ = addr;
196 close(s);
199 /* terminate argv */
200 *av++ = NULL;
202 return exec_prog((char*)prog, argv);
205 /*---------------------------------------------------------------------------*
206 * run answeringmachine application
207 *---------------------------------------------------------------------------*/
209 exec_answer(cfg_entry_t *cep)
211 char *argv[32];
212 u_char devicename[MAXPATHLEN];
213 int pid;
214 char *device;
216 device = bdrivername(cep->usrdevicename);
218 snprintf(devicename, sizeof(devicename), "%si4b%s%d", _PATH_DEV, device,
219 cep->usrdeviceunit);
221 argv[0] = cep->answerprog;
222 argv[1] = "-D";
223 argv[2] = devicename;
224 argv[3] = "-d";
225 argv[4] = "unknown";
226 argv[5] = "-s";
227 argv[6] = "unknown";
228 argv[7] = NULL;
230 /* if destination telephone number avail, add it as argument */
232 if(*cep->local_phone_incoming)
233 argv[4] = cep->local_phone_incoming;
235 /* if source telephone number avail, add it as argument */
237 if(*cep->real_phone_incoming)
238 argv[6] = cep->real_phone_incoming;
240 if(*cep->display)
242 argv[7] = "-t";
243 argv[8] = cep->display;
244 argv[9] = NULL;
247 /* exec program */
249 DBGL(DL_PROC, (log(LL_DBG, "exec_answer: prog=[%s]", cep->answerprog)));
251 pid = exec_prog(cep->answerprog, argv);
253 /* enter pid and conf ptr entry addr into table */
255 if(pid != -1)
257 int i;
259 for(i=0; i < MAX_PIDS; i++)
261 if(pid_tab[i].pid == 0)
263 pid_tab[i].pid = pid;
264 pid_tab[i].cep = cep;
265 break;
268 return(GOOD);
270 return(ERROR);
273 /*---------------------------------------------------------------------------*
274 * check if a connection has an outstanding process, if yes, kill it
275 *---------------------------------------------------------------------------*/
276 void
277 check_and_kill(cfg_entry_t *cep)
279 int i;
281 for(i=0; i < MAX_PIDS; i++)
283 if(pid_tab[i].cep == cep)
285 pid_t kp;
287 DBGL(DL_PROC, (log(LL_DBG, "check_and_kill: killing pid %d", pid_tab[i].pid)));
289 kp = pid_tab[i].pid;
290 pid_tab[i].pid = 0;
291 kill(kp, SIGHUP);
292 break;
297 /*---------------------------------------------------------------------------*
298 * update budget callout/callback statistics counter file
299 *---------------------------------------------------------------------------*/
300 void
301 upd_callstat_file(char *filename, int rotateflag)
303 FILE *fp;
304 time_t s, l, now;
305 int n;
306 int ret;
308 now = time(NULL);
310 fp = fopen(filename, "r+");
312 if(fp == NULL)
314 /* file not there, create it and exit */
316 log(LL_WRN, "upd_callstat_file: creating %s", filename);
318 fp = fopen(filename, "w");
319 if(fp == NULL)
321 log(LL_ERR, "ERROR, upd_callstat_file: cannot create %s, %s", filename, strerror(errno));
322 return;
325 ret = fprintf(fp, "%ld %ld 1", now, now);
326 if(ret <= 0)
327 log(LL_ERR, "ERROR, upd_callstat_file: fprintf failed: %s", strerror(errno));
329 fclose(fp);
330 return;
333 /* get contents */
335 ret = fscanf(fp, "%ld %ld %d", &s, &l, &n);
337 /* reset fp */
339 rewind(fp);
341 if(ret != 3)
343 /* file corrupt ? anyway, initialize */
345 log(LL_WRN, "upd_callstat_file: initializing %s", filename);
347 s = l = now;
348 n = 0;
351 if(rotateflag)
353 struct tm *stmp;
354 int dom;
356 /* get day of month for last timestamp */
357 stmp = localtime(&l);
358 dom = stmp->tm_mday;
360 /* get day of month for just now */
361 stmp = localtime(&now);
363 if(dom != stmp->tm_mday)
365 FILE *nfp;
366 char buf[MAXPATHLEN];
368 /* new day, write last days stats */
370 sprintf(buf, "%s-%02d", filename, stmp->tm_mday);
372 nfp = fopen(buf, "w");
373 if(nfp == NULL)
375 log(LL_ERR, "ERROR, upd_callstat_file: cannot open for write %s, %s", buf, strerror(errno));
376 return;
379 ret = fprintf(nfp, "%ld %ld %d", s, l, n);
380 if(ret <= 0)
381 log(LL_ERR, "ERROR, upd_callstat_file: fprintf failed: %s", strerror(errno));
383 fclose(nfp);
385 /* init new days stats */
386 n = 0;
387 s = now;
389 log(LL_WRN, "upd_callstat_file: rotate %s, new s=%ld l=%ld n=%d", filename, s, l, n);
393 n++; /* increment call count */
396 * the "%-3d" is necessary to overwrite any
397 * leftovers from previous contents!
400 ret = fprintf(fp, "%ld %ld %-3d", s, now, n);
402 if(ret <= 0)
403 log(LL_ERR, "ERROR, upd_callstat_file: fprintf failed: %s", strerror(errno));
405 fclose(fp);
408 /* EOF */