1/* 2 * Copyright (c) 1997, 2000 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 * $Id: exec.c,v 1.10 2009/04/16 05:56:32 lukem Exp $ 31 * 32 * $FreeBSD$ 33 * 34 * last edit-date: [Wed Sep 27 09:39:22 2000] 35 * 36 *---------------------------------------------------------------------------*/ 37 38#include "isdnd.h" 39 40#include <sys/wait.h> 41#include <sys/socket.h> 42#include <net/if.h> 43#include <netinet/in.h> 44#include <arpa/inet.h> 45 46#define MAX_PIDS 32 47 48static struct pid_tab { 49 pid_t pid; 50 struct cfg_entry *cep; 51} pid_tab[MAX_PIDS]; 52 53/*---------------------------------------------------------------------------* 54 * SIGCHLD signal handler 55 *---------------------------------------------------------------------------*/ 56void 57sigchild_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 logit(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, (logit(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 logit(LL_WRN, "child (pid=%d) termination due to signal %d (coredump)", 79 pid, WTERMSIG(retstat)); 80 else 81 logit(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, (logit(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 *---------------------------------------------------------------------------*/ 107pid_t 108exec_prog(const char *prog, const 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 strlcat(tmp, " ", sizeof(tmp)); 124 strlcat(tmp, arglist[a], sizeof(tmp)); 125 } 126 127 DBGL(DL_PROC, (logit(LL_DBG, "exec_prog: %s, args:%s", path, tmp))); 128 129 switch (pid = fork()) 130 { 131 case -1: /* error */ 132 logit(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/isdn 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 if (useacctfile) 150 fclose(acctfp); 151 if (uselogfile) 152 fclose(logfp); 153 154 155 if (execvp(path, __UNCONST(arglist)) < 0 ) 156 _exit(127); 157 158 return(-1); 159} 160 161/*---------------------------------------------------------------------------* 162 * run interface up/down script 163 *---------------------------------------------------------------------------*/ 164int 165exec_connect_prog(struct cfg_entry *cep, const char *prog, int link_down) 166{ 167 const char *argv[32], **av = argv; 168 char devicename[MAXPATHLEN], addr[100]; 169 int s; 170 struct ifreq ifr; 171 172 /* the obvious things */ 173 snprintf(devicename, sizeof(devicename), "%s%d", cep->usrdevicename, cep->usrdeviceunit); 174 *av++ = prog; 175 *av++ = "-d"; 176 *av++ = devicename; 177 *av++ = "-f"; 178 *av++ = link_down ? "down" : "up"; 179 180 /* try to figure AF_INET address of interface */ 181 addr[0] = '\0'; 182 memset(&ifr, 0, sizeof ifr); 183 ifr.ifr_addr.sa_family = AF_INET; 184 strncpy(ifr.ifr_name, devicename, sizeof(ifr.ifr_name)); 185 s = socket(AF_INET, SOCK_DGRAM, 0); 186 if (s >= 0) { 187 if (ioctl(s, SIOCGIFADDR, (caddr_t)&ifr) >= 0) { 188 struct sockaddr_in *sin = (struct sockaddr_in *)&ifr.ifr_addr; 189 strlcpy(addr, inet_ntoa(sin->sin_addr), sizeof(addr)); 190 *av++ = "-a"; 191 *av++ = addr; 192 } 193 close(s); 194 } 195 196 /* terminate argv */ 197 *av++ = NULL; 198 199 return exec_prog(prog, argv); 200} 201 202/*---------------------------------------------------------------------------* 203 * run answeringmachine application 204 *---------------------------------------------------------------------------*/ 205int 206exec_answer(struct cfg_entry *cep) 207{ 208 const char *argv[32]; 209 char devicename[MAXPATHLEN]; 210 int pid; 211 212 snprintf(devicename, sizeof(devicename), "/dev/%s%d", cep->usrdevicename, cep->usrdeviceunit); 213 214 argv[0] = cep->answerprog; 215 argv[1] = "-D"; 216 argv[2] = devicename; 217 argv[3] = "-d"; 218 argv[4] = "unknown"; 219 argv[5] = "-s"; 220 argv[6] = "unknown"; 221 argv[7] = NULL; 222 223 /* if destination telephone number avail, add it as argument */ 224 225 if (*cep->local_phone_incoming) 226 argv[4] = cep->local_phone_incoming; 227 228 /* if source telephone number avail, add it as argument */ 229 230 if (*cep->real_phone_incoming) 231 argv[6] = cep->real_phone_incoming; 232 233 if (*cep->display) 234 { 235 argv[7] = "-t"; 236 argv[8] = cep->display; 237 argv[9] = NULL; 238 } 239 240 /* exec program */ 241 242 DBGL(DL_PROC, (logit(LL_DBG, "exec_answer: prog=[%s]", cep->answerprog))); 243 244 pid = exec_prog(cep->answerprog, argv); 245 246 /* enter pid and conf ptr entry addr into table */ 247 248 if (pid != -1) 249 { 250 int i; 251 252 for (i=0; i < MAX_PIDS; i++) 253 { 254 if (pid_tab[i].pid == 0) 255 { 256 pid_tab[i].pid = pid; 257 pid_tab[i].cep = cep; 258 break; 259 } 260 } 261 return(GOOD); 262 } 263 return(ERROR); 264} 265 266/*---------------------------------------------------------------------------* 267 * check if a connection has an outstanding process, if yes, kill it 268 *---------------------------------------------------------------------------*/ 269void 270check_and_kill(struct cfg_entry *cep) 271{ 272 int i; 273 274 for (i=0; i < MAX_PIDS; i++) 275 { 276 if (pid_tab[i].cep == cep) 277 { 278 pid_t kp; 279 280 DBGL(DL_PROC, (logit(LL_DBG, "check_and_kill: killing pid %d", pid_tab[i].pid))); 281 282 kp = pid_tab[i].pid; 283 pid_tab[i].pid = 0; 284 kill(kp, SIGHUP); 285 break; 286 } 287 } 288} 289 290/*---------------------------------------------------------------------------* 291 * update budget callout/callback statistics counter file 292 *---------------------------------------------------------------------------*/ 293void 294upd_callstat_file(char *filename, int rotateflag) 295{ 296 FILE *fp; 297 time_t s, l, now; 298 long s_in, l_in; 299 int n; 300 int ret; 301 302 now = time(NULL); 303 304 fp = fopen(filename, "r+"); 305 306 if (fp == NULL) 307 { 308 /* file not there, create it and exit */ 309 310 logit(LL_WRN, "upd_callstat_file: creating %s", filename); 311 312 fp = fopen(filename, "w"); 313 if (fp == NULL) 314 { 315 logit(LL_ERR, "ERROR, upd_callstat_file: cannot create %s, %s", filename, strerror(errno)); 316 return; 317 } 318 319 ret = fprintf(fp, "%ld %ld 1", (long)now, (long)now); 320 if (ret <= 0) 321 logit(LL_ERR, "ERROR, upd_callstat_file: fprintf failed: %s", strerror(errno)); 322 323 fclose(fp); 324 return; 325 } 326 327 /* get contents */ 328 329 ret = fscanf(fp, "%ld %ld %d", &s_in, &l_in, &n); 330 s = s_in; l = l_in; 331 332 /* reset fp */ 333 334 rewind(fp); 335 336 if (ret != 3) 337 { 338 /* file corrupt ? anyway, initialize */ 339 340 logit(LL_WRN, "upd_callstat_file: initializing %s", filename); 341 342 s = l = now; 343 n = 0; 344 } 345 346 if (rotateflag) 347 { 348 struct tm *stmp; 349 int dom; 350 351 /* get day of month for last timestamp */ 352 stmp = localtime(&l); 353 dom = stmp->tm_mday; 354 355 /* get day of month for just now */ 356 stmp = localtime(&now); 357 358 if (dom != stmp->tm_mday) 359 { 360 FILE *nfp; 361 char buf[MAXPATHLEN]; 362 363 /* new day, write last days stats */ 364 365 snprintf(buf, sizeof(buf), "%s-%02d", filename, 366 stmp->tm_mday); 367 368 nfp = fopen(buf, "w"); 369 if (nfp == NULL) 370 { 371 logit(LL_ERR, "ERROR, upd_callstat_file: cannot open for write %s, %s", buf, strerror(errno)); 372 return; 373 } 374 375 ret = fprintf(nfp, "%ld %ld %d", (long)s, (long)l, n); 376 if (ret <= 0) 377 logit(LL_ERR, "ERROR, upd_callstat_file: fprintf failed: %s", strerror(errno)); 378 379 fclose(nfp); 380 381 /* init new days stats */ 382 n = 0; 383 s = now; 384 385 logit(LL_WRN, "upd_callstat_file: rotate %s, new s=%ld l=%ld n=%d", filename, s, l, n); 386 } 387 } 388 389 n++; /* increment call count */ 390 391 /* 392 * the "%-3d" is necessary to overwrite any 393 * leftovers from previous contents! 394 */ 395 396 ret = fprintf(fp, "%ld %ld %-3d", (long)s, (long)now, n); 397 398 if (ret <= 0) 399 logit(LL_ERR, "ERROR, upd_callstat_file: fprintf failed: %s", strerror(errno)); 400 401 fclose(fp); 402} 403 404/* EOF */ 405