Add the DragonFly cvs id and perform general cleanups on cvs/rcs/sccs ids. Most
[dragonfly.git] / usr.sbin / i4b / isdnd / exec.c
1 /*
2  * Copyright (c) 1997, 2001 Hellmuth Michaelis. All rights reserved.
3  *
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.
12  *
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.
24  *
25  *---------------------------------------------------------------------------
26  *
27  *      exec.h - supplemental program/script execution
28  *      ----------------------------------------------
29  *
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.2 2003/06/17 04:29:54 dillon Exp $
32  *
33  *      last edit-date: [Mon Dec 10 10:39:53 2001]
34  *
35  *---------------------------------------------------------------------------*/
36
37 #include "isdnd.h"
38
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>
45
46 #define MAX_PIDS 32
47
48 static struct pid_tab {
49         pid_t   pid;
50         cfg_entry_t *cep;
51 } pid_tab[MAX_PIDS];
52
53 /*---------------------------------------------------------------------------*
54  *      SIGCHLD signal handler
55  *---------------------------------------------------------------------------*/
56 void
57 sigchild_handler(int sig)
58 {
59         int retstat;
60         register int i;
61         pid_t pid;
62         
63         if((pid = waitpid(-1, &retstat, WNOHANG)) <= 0)
64         {
65                 log(LL_ERR, "ERROR, sigchild_handler, waitpid: %s", strerror(errno));
66                 error_exit(1, "ERROR, sigchild_handler, waitpid: %s", strerror(errno));
67         }
68         else
69         {
70                 if(WIFEXITED(retstat))
71                 {
72                         DBGL(DL_PROC, (log(LL_DBG, "normal child (pid=%d) termination, exitstat = %d",
73                                 pid, WEXITSTATUS(retstat))));
74                 }
75                 else if(WIFSIGNALED(retstat))
76                 {
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));
83                 }
84         }
85
86         /* check if hangup required */
87         
88         for(i=0; i < MAX_PIDS; i++)
89         {
90                 if(pid_tab[i].pid == pid)
91                 {
92                         if(pid_tab[i].cep->cdid != CDID_UNUSED)
93                         {
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;
97                         }
98                         pid_tab[i].pid = 0;
99                         break;
100                 }
101         }
102 }
103
104 /*---------------------------------------------------------------------------*
105  *      execute prog as a subprocess and pass an argumentlist
106  *---------------------------------------------------------------------------*/
107 pid_t
108 exec_prog(char *prog, char **arglist)
109 {
110         char tmp[MAXPATHLEN];
111         char path[MAXPATHLEN+1];
112         pid_t pid;
113         int a;
114
115         snprintf(path, sizeof(path), "%s/%s", ETCPATH, prog);
116
117         arglist[0] = path;
118
119         tmp[0] = '\0';
120
121         for(a=1; arglist[a] != NULL; ++a )
122         {
123                 strcat(tmp, " " );
124                 strcat(tmp, arglist[a]);
125         }
126
127         DBGL(DL_PROC, (log(LL_DBG, "exec_prog: %s, args:%s", path, tmp)));
128         
129         switch(pid = fork())
130         {
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);
138         }
139
140         /* this is the child now */
141
142         /*
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)
147          */
148         close(isdnfd);
149
150         if(useacctfile && acctfp)
151                 fclose(acctfp);
152
153         if(uselogfile && logfp)
154                 fclose(logfp);
155
156         if(execvp(path,arglist) < 0 )
157                 _exit(127);
158
159         return(-1);
160 }
161
162 /*---------------------------------------------------------------------------*
163  *      run interface up/down script
164  *---------------------------------------------------------------------------*/
165 int
166 exec_connect_prog(cfg_entry_t *cep, const char *prog, int link_down)
167 {
168         char *argv[32], **av = argv;
169         char devicename[MAXPATHLEN], addr[100];
170         char *device;
171         int s;
172         struct ifreq ifr;
173
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";
182
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;
195                 }
196                 close(s);
197         }
198
199         /* terminate argv */
200         *av++ = NULL;
201
202         return exec_prog((char*)prog, argv);
203 }
204
205 /*---------------------------------------------------------------------------*
206  *      run answeringmachine application
207  *---------------------------------------------------------------------------*/
208 int
209 exec_answer(cfg_entry_t *cep)
210 {
211         char *argv[32];
212         u_char devicename[MAXPATHLEN];  
213         int pid;
214         char *device;
215         
216         device = bdrivername(cep->usrdevicename);
217
218         snprintf(devicename, sizeof(devicename), "%si4b%s%d", _PATH_DEV, device,
219             cep->usrdeviceunit);
220
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;
229
230         /* if destination telephone number avail, add it as argument */
231         
232         if(*cep->local_phone_incoming)
233                 argv[4] = cep->local_phone_incoming;
234
235         /* if source telephone number avail, add it as argument */
236         
237         if(*cep->real_phone_incoming)
238                 argv[6] = cep->real_phone_incoming;
239
240         if(*cep->display)
241         {
242                 argv[7] = "-t";
243                 argv[8] = cep->display;
244                 argv[9] = NULL;
245         }
246
247         /* exec program */
248         
249         DBGL(DL_PROC, (log(LL_DBG, "exec_answer: prog=[%s]", cep->answerprog)));
250         
251         pid = exec_prog(cep->answerprog, argv);
252                 
253         /* enter pid and conf ptr entry addr into table */
254         
255         if(pid != -1)
256         {
257                 int i;
258                 
259                 for(i=0; i < MAX_PIDS; i++)
260                 {
261                         if(pid_tab[i].pid == 0)
262                         {
263                                 pid_tab[i].pid = pid;
264                                 pid_tab[i].cep = cep;
265                                 break;
266                         }
267                 }
268                 return(GOOD);
269         }
270         return(ERROR);
271 }
272
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)
278 {
279         int i;
280         
281         for(i=0; i < MAX_PIDS; i++)
282         {
283                 if(pid_tab[i].cep == cep)
284                 {
285                         pid_t kp;
286
287                         DBGL(DL_PROC, (log(LL_DBG, "check_and_kill: killing pid %d", pid_tab[i].pid)));
288
289                         kp = pid_tab[i].pid;
290                         pid_tab[i].pid = 0;                     
291                         kill(kp, SIGHUP);
292                         break;
293                 }
294         }
295 }
296
297 /*---------------------------------------------------------------------------*
298  *      update budget callout/callback statistics counter file
299  *---------------------------------------------------------------------------*/
300 void
301 upd_callstat_file(char *filename, int rotateflag)
302 {
303         FILE *fp;
304         time_t s, l, now;
305         int n;
306         int ret;
307
308         now = time(NULL);
309         
310         fp = fopen(filename, "r+");
311
312         if(fp == NULL)
313         {
314                 /* file not there, create it and exit */
315                 
316                 log(LL_WRN, "upd_callstat_file: creating %s", filename);
317
318                 fp = fopen(filename, "w");
319                 if(fp == NULL)
320                 {
321                         log(LL_ERR, "ERROR, upd_callstat_file: cannot create %s, %s", filename, strerror(errno));
322                         return;
323                 }
324
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));
328                 
329                 fclose(fp);
330                 return;
331         }
332
333         /* get contents */
334         
335         ret = fscanf(fp, "%ld %ld %d", &s, &l, &n);
336
337         /* reset fp */
338         
339         rewind(fp);
340                 
341         if(ret != 3)
342         {
343                 /* file corrupt ? anyway, initialize */
344                 
345                 log(LL_WRN, "upd_callstat_file: initializing %s", filename);
346
347                 s = l = now;
348                 n = 0;
349         }
350
351         if(rotateflag)
352         {
353                 struct tm *stmp;
354                 int dom;
355
356                 /* get day of month for last timestamp */
357                 stmp = localtime(&l);
358                 dom = stmp->tm_mday;    
359
360                 /* get day of month for just now */
361                 stmp = localtime(&now);
362                 
363                 if(dom != stmp->tm_mday)
364                 {
365                         FILE *nfp;
366                         char buf[MAXPATHLEN];
367
368                         /* new day, write last days stats */
369
370                         sprintf(buf, "%s-%02d", filename, stmp->tm_mday);
371
372                         nfp = fopen(buf, "w");
373                         if(nfp == NULL)
374                         {
375                                 log(LL_ERR, "ERROR, upd_callstat_file: cannot open for write %s, %s", buf, strerror(errno));
376                                 return;
377                         }
378
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));
382                         
383                         fclose(nfp);
384
385                         /* init new days stats */
386                         n = 0;
387                         s = now;
388
389                         log(LL_WRN, "upd_callstat_file: rotate %s, new s=%ld l=%ld n=%d", filename, s, l, n);
390                 }                               
391         }
392
393         n++;    /* increment call count */
394
395         /*
396          * the "%-3d" is necessary to overwrite any
397          * leftovers from previous contents!
398          */
399
400         ret = fprintf(fp, "%ld %ld %-3d", s, now, n);   
401
402         if(ret <= 0)
403                 log(LL_ERR, "ERROR, upd_callstat_file: fprintf failed: %s", strerror(errno));
404         
405         fclose(fp);
406 }
407         
408 /* EOF */