OSDN Git Service

2013.10.24
[uclinux-h8/uClinux-dist.git] / user / diald / diald.c
1 /*
2  * diald.c - Demand dialing daemon for ppp.
3  *
4  * Copyright (c) 1994, 1995, 1996 Eric Schenk.
5  * All rights reserved. Please see the file LICENSE which should be
6  * distributed with this software for terms of use.
7  *
8  * Portions of this code were derived from the code for pppd copyright
9  * (c) 1989 Carnegie Mellon University. The copyright notice on this code
10  * is reproduced below.
11  *
12  * Copyright (c) 1989 Carnegie Mellon University.
13  * All rights reserved.
14  *
15  * Redistribution and use in source and binary forms are permitted
16  * provided that the above copyright notice and this paragraph are
17  * duplicated in all such forms and that any documentation,
18  * advertising materials, and other materials related to such
19  * distribution and use acknowledge that the software was developed
20  * by Carnegie Mellon University.  The name of the
21  * University may not be used to endorse or promote products derived
22  * from this software without specific prior written permission.
23  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
24  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
25  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
26  */
27
28 #include "diald.h"
29 #include "version.h"
30
31 int call_start_time;
32 int fifo_fd;
33 int fwdfd;
34 int fwunit;
35 int orig_disc;
36 char packet[4096];
37 int pppd_argc;
38 char **pppd_argv;
39 int proxy_mfd;
40 FILE *proxy_mfp;
41 int proxy_sfd;
42 char *req_dev;
43 int req_pid;
44 int txtotal, rxtotal;
45 char snoop_dev[10];
46 int snoopfd;
47 int use_req;
48
49 /* intialized variables. */
50 int modem_fd = -1;              /* modem device fp (for proxy reads) */
51 MONITORS *monitors = 0;         /* Monitor pipes */
52 int modem_hup = 0;              /* have we seen a modem HUP? */
53 int sockfd = -1;                /* controling socket */
54 int delayed_quit = 0;           /* has the user requested a delayed quit? */
55 int request_down = 0;           /* has the user requested link down? */
56 int request_up = 0;             /* has the user requested link down? */
57 int forced = 0;                 /* has the user requested the link forced up? */
58 int link_pid = 0;               /* current protocol control command pid */
59 int dial_pid = 0;               /* current dial command pid */
60 int running_pid = 0;            /* current system command pid */
61 int running_status = 0;         /* status of last system command */
62 int dial_status = 0;            /* status from last dial command */
63 int state_timeout = -1;         /* state machine timeout counter */
64 int proxy_iface = 0;            /* Interface for the proxy */
65 int link_iface = -1;            /* Interface for the link */
66 int force_dynamic = 0;          /* true if connect passed back an addr */
67 int redial_rtimeout = -1;       /* initialized value */
68 int dial_failures = 0;          /* count of dialing failures */
69 int ppp_half_dead = 0;          /* is the ppp link half dead? */
70 int terminate = 0;
71 char *pidfile = 0;
72 static PIPE fifo_pipe;
73 int argc_save;
74 char **argv_save;
75
76 void do_config(void)
77 {
78     init_vars();
79     flush_prules();
80     flush_vars();
81     flush_strvars();
82     flush_filters();
83     /* Get the default defs and config files first */
84     parse_options_file(DIALD_DEFS_FILE);
85     parse_options_file(DIALD_CONFIG_FILE);
86     /* Get the command line modifications */
87     parse_args(argc_save-1,argv_save+1);
88     /* Do validity checks on the setup */
89     check_setup();
90
91     if (orig_local_ip)
92         free(orig_local_ip);
93     if (orig_remote_ip)
94         free(orig_remote_ip);
95     orig_local_ip = strdup(local_ip);
96     orig_remote_ip = strdup(remote_ip);
97 }
98
99 int main(int argc, char *argv[])
100 {
101     int sel;
102     struct timeval timeout;
103     fd_set readfds;
104
105     argc_save = argc;
106     argv_save = argv;
107
108     /* initialize system log interface */
109     openlog("diald", LOG_PID | LOG_NDELAY | LOG_PERROR,  LOG_LOCAL2);
110
111     /* initialize a firewall unit so we can store our options */
112     /* If I get things into a device this should be an "open" */
113     fwunit = ctl_firewall(IP_FW_OPEN,0);
114
115     parse_init();
116     do_config();
117
118     become_daemon();
119
120     /* Get an internet socket for doing socket ioctls. */
121     sockfd = socket(AF_INET, SOCK_DGRAM, 0);
122     if (sockfd < 0)
123       {
124         syslog(LOG_ERR, "Couldn't create IP socket: %m");
125         die(1);
126       }
127
128     open_fifo();
129
130     if (debug&DEBUG_VERBOSE)
131         syslog(LOG_INFO,"Starting diald version %s",VERSION);
132
133     signal_setup();
134     filter_setup();
135
136     /* get a pty and open up a proxy link on it */
137     if (openpty(&proxy_mfd,&proxy_sfd, NULL, NULL, NULL) < 0)
138                 die (-1);
139 #ifndef USE_BSD_PTYS
140         fcntl(proxy_mfd,F_SETFL,fcntl(proxy_mfd,F_GETFL)|O_NONBLOCK);
141 #endif
142     proxy_mfp = fdopen(proxy_mfd,"r+");
143     proxy_up();
144     idle_filter_proxy();
145
146     if (debug&DEBUG_VERBOSE)
147         syslog(LOG_INFO,"Diald initial setup completed.");
148
149     /* main loop */
150     timeout.tv_sec = PAUSETIME;
151     timeout.tv_usec = 0;
152     while (!terminate) {
153         /* wait up to a second for an event */
154         FD_ZERO(&readfds);
155         if (fifo_fd != -1)
156             FD_SET(fifo_fd,&readfds);
157         FD_SET(proxy_mfd,&readfds);
158         FD_SET(snoopfd,&readfds);
159         sel = select(100,&readfds,0,0,&timeout);
160         if (sel > 0) {
161             /* read user commands off the fifo */
162             if (fifo_fd != -1 && FD_ISSET(fifo_fd,&readfds)) fifo_read();
163
164             /* update the connection filters */
165             if (FD_ISSET(snoopfd,&readfds)) filter_read();
166
167             /* deal with packets coming into the pty proxy link */
168             if (FD_ISSET(proxy_mfd,&readfds)) proxy_read();
169         }
170         if (timeout.tv_sec == 0 && timeout.tv_usec == 0) {
171             /* advance the clock 1 second */
172             timeout.tv_sec = PAUSETIME;
173             timeout.tv_usec = 0;
174             if (state_timeout > 0) state_timeout--;
175             if (debug&DEBUG_TICK)
176                 syslog(LOG_DEBUG,"--- tick --- state %d block %d state_timeout %d",state,blocked,state_timeout);
177             //monitor_queue();
178         }
179         change_state();
180     }
181     die(0);
182 }
183
184 /* Write the pid and optionally the proxy interface to the pid file */
185
186 void create_pidfile(int iface)
187 {
188     FILE *fp;
189     if ((fp = fopen(pidfile,"w")) != NULL) {
190         fprintf(fp,"%d\n",getpid());
191         if (iface)
192                 fprintf(fp,"sl%d\n",proxy_iface);
193         fclose(fp);
194     } else {
195         syslog(LOG_ERR,"Unable to create run file %s: %m",pidfile);
196     }
197 }
198
199 /*
200  * Change into a daemon.
201  * Get rid of the stdio streams, and disassociate from the original
202  * controling terminal, and become a group leader.
203  */
204
205 void become_daemon()
206 {
207 #ifndef __uClinux__
208     pid_t pid;
209     if (dodaemon) {
210         close(0);
211         close(1);
212         close(2);
213         /* go into the background */
214         if ((pid = fork()) < 0) {
215             syslog(LOG_ERR,"Could not fork into background: %m");
216             die(1);
217         }
218         /* parent process is finished */
219         if (pid != 0) exit(0);
220     }
221 #endif /* __uClinux__ */
222     if (pidlog[0] == '/') {
223         pidfile = pidlog;
224     }
225     else {
226         pidfile = malloc(strlen(RUN_PREFIX) + strlen(pidlog) + 2);
227         sprintf(pidfile,"%s/%s",RUN_PREFIX,pidlog);
228     }
229     create_pidfile(0);
230 }
231
232 /* Open the command fifo, if any */
233
234 void open_fifo()
235 {
236     struct stat sbuf;
237
238     if (fifoname) {
239         if (stat(fifoname,&sbuf) < 0 || !(sbuf.st_mode&S_IFIFO)) {
240             syslog(LOG_INFO,"Creating FIFO");
241             /* Create the fifo. */
242             mknod(fifoname, S_IFIFO|0277, 0);
243             chmod(fifoname, 0600);
244         }
245         /* We need to open this RDWR to make select() work the
246          * way we want in kernels after 1.3.81. In particular
247          * we don't want select() to return 1 whenever there
248          * are no writers on the remote side of the command fifo.
249          * This guarantees that there is always at least one writer...
250          */
251         if ((fifo_fd = open(fifoname, O_RDWR | O_NDELAY)) >= 0) {
252             if (debug&DEBUG_VERBOSE)
253                  syslog(LOG_INFO,"Using fifo %s",fifoname);
254             pipe_init(fifo_fd,&fifo_pipe);
255         } else {
256             syslog(LOG_ERR,"Could not open fifo file %s",fifoname);
257             fifo_fd = -1;
258         }
259     } else {
260         /* make sure to invalidate the fifo_fd if we don't open one. */
261         fifo_fd = -1;
262     }
263 }
264
265
266 /*
267  * Set up the signal handlers.
268  */
269 static sigset_t sig_mask;
270
271 void signal_setup()
272 {
273     struct sigaction sa;
274     /* set up signal handlers */
275
276     sigemptyset(&sig_mask);
277     sigaddset(&sig_mask, SIGHUP);
278     sigaddset(&sig_mask, SIGINT);
279     sigaddset(&sig_mask, SIGTERM);
280     sigaddset(&sig_mask, SIGUSR1);
281     sigaddset(&sig_mask, SIGUSR2);
282     sigaddset(&sig_mask, SIGCHLD);
283     sigaddset(&sig_mask, SIGALRM);
284     sigaddset(&sig_mask, SIGPIPE);
285
286 #define SIGNAL(s, handler)      { \
287         sa.sa_handler = handler; \
288         if (sigaction(s, &sa, NULL) < 0) { \
289             syslog(LOG_ERR, "sigaction(%d): %m", s); \
290             die(1); \
291         } \
292     }
293
294     sa.sa_mask = sig_mask;
295     sa.sa_flags = 0;
296
297     SIGNAL(SIGHUP, sig_hup);            /* Hangup: modem went down. */
298     SIGNAL(SIGINT, sig_intr);           /* Interrupt: take demand dialer down */
299     SIGNAL(SIGTERM, sig_term);          /* Terminate: user take link down */
300     SIGNAL(SIGUSR1, linkup);            /* User requests the link to go up */
301     SIGNAL(SIGUSR2, print_filter_queue); /* dump the packet queue to the log */
302     SIGNAL(SIGCHLD, sig_chld);          /* reap dead kids */
303     SIGNAL(SIGPIPE, SIG_IGN);
304 }
305
306 void block_signals()
307 {
308     sigprocmask(SIG_BLOCK, &sig_mask, NULL);
309 }
310
311 void default_sigacts()
312 {
313     struct sigaction sa;
314     sa.sa_mask = sig_mask;
315     sa.sa_flags = 0;
316
317     SIGNAL(SIGHUP, SIG_DFL);
318     SIGNAL(SIGINT, SIG_DFL);
319     SIGNAL(SIGTERM, SIG_DFL);
320     SIGNAL(SIGUSR1, SIG_DFL);
321     SIGNAL(SIGUSR2, SIG_DFL);
322     SIGNAL(SIGCHLD, SIG_DFL);
323     SIGNAL(SIGALRM, SIG_DFL);
324     SIGNAL(SIGPIPE, SIG_DFL);
325 }
326
327 void unblock_signals()
328 {
329     sigprocmask(SIG_UNBLOCK, &sig_mask, NULL);
330 }
331
332 #ifdef USE_BSD_PTYS
333 /*
334  * Get a pty and open both the slave and master sides.
335  */
336
337 int openpty(int *mfd, int *sfd, void *name, void *termios, void *win)
338 {
339     char *ptys = "0123456789abcdef";
340     int i,c;
341     static char buf[128];
342
343     for (c = 'p'; c <= 's'; c++)
344         for (i = 0; i < 16; i++) {
345             sprintf(buf,"/dev/pty%c%c",c,ptys[i]);
346             if ((*mfd = open(buf,O_RDWR)) >= 0) {
347                 sprintf(buf,"/dev/tty%c%c",c,ptys[i]);
348                 if ((*sfd = open(buf,O_RDWR|O_NOCTTY|O_NDELAY)) < 0) {
349                     syslog(LOG_ERR,"Can't open slave side of pty: %m");
350                         return -1;
351                 }
352                 return 0;
353             }
354         }
355         syslog(LOG_ERR,"No pty found in range pty[p-s][0-9a-f]\n");
356         return -1;
357 }
358 #endif
359
360 /* Read a request off the fifo.
361  * Valid requests are:
362  *      block           - block diald from calling out.
363  *      unblock         - unblock diald from calling out.
364  *      down            - bring the link down.
365  *      up              - bring the link up.
366  *      delayed-quit    - quit next time diald is idle.
367  *      quit            - stop diald in its tracks.
368  *      queue           - dump the filter queue.
369  *      debug level     - set the debug level.
370  *      force           - force diald to put the connection up and keep it up.
371  *      unforce         - remove the forced up requirement.
372  *      connect pid dev - go up on a connection to the named port.
373  *                        We assume the connection negotiations are
374  *                        already finished and any lock files are in place.
375  *                        When the connection should be killed we send a
376  *                        SIGTERM to the given pid.
377  *      dynamic <lip> <rip> - pass back dynamic IP config info to diald.
378  *      message <txt>   - set the message text from the connect script.
379  *      monitor file    - start a monitoring program.
380  *      reset           - reread the configuration information.
381  */
382
383 void fifo_read()
384 {
385     int i;
386     int pid, dev, j,k,l;
387     char *buf, *tail;
388
389     i = pipe_read(&fifo_pipe);
390     buf = tail = fifo_pipe.buf;
391     if (i < 0) {
392         fifo_fd = -1;
393         return;
394     }
395     if (i == 0) return;
396
397     while (i--) {
398         if (*tail == '\n') {
399             *tail = '\0';
400             /* Ok, we've got a line, now we need to "parse" it. */
401             if (strcmp(buf,"block") == 0) {
402                 char sbuf[sizeof(PATH_IFCONFIG SL_DOWN) + 10];
403                 syslog(LOG_INFO, "FIFO: Block request received.");
404                 snprintf(sbuf, sizeof(sbuf), PATH_IFCONFIG SL_DOWN, proxy_iface);
405                 system(sbuf);
406                 snprintf(sbuf, sizeof(sbuf), PATH_IFCONFIG SL_UP, proxy_iface);
407                 system(sbuf);
408                 blocked = 1;
409             } else if (strcmp(buf, "state") == 0) {
410                 output_state();
411             } else if (strcmp(buf,"unblock") == 0) {
412                 syslog(LOG_INFO, "FIFO: Unblock request received.");
413                 blocked = 0;
414             } else if (strcmp(buf,"force") == 0) {
415                 syslog(LOG_INFO, "FIFO: Force request received.");
416                 forced = 1;
417             } else if (strcmp(buf,"unforce") == 0) {
418                 syslog(LOG_INFO, "FIFO: Unforce request received.");
419                 forced = 0;
420             } else if (strcmp(buf,"down") == 0) {
421                 syslog(LOG_INFO, "FIFO: Link down request received.");
422                 request_down = 1;
423                 request_up = 0;
424             } else if (strcmp(buf,"up") == 0) {
425                 syslog(LOG_INFO, "FIFO: Link up request received.");
426                 request_down = 0;
427                 request_up = 1;
428             } else if (strcmp(buf,"delayed-quit") == 0) {
429                 syslog(LOG_INFO, "FIFO. Delayed termination request received.");
430                 delayed_quit = 1;
431             } else if (strcmp(buf,"quit") == 0) {
432                 syslog(LOG_INFO, "FIFO. Termination request received.");
433                 terminate = 1;
434             } else if (strcmp(buf,"reset") == 0) {
435                 syslog(LOG_INFO, "FIFO. Reset request received. Re-reading configuration.");
436                 do_config();
437             } else if (strcmp(buf,"queue") == 0) {
438                 struct firewall_req req;
439                 syslog(LOG_INFO,"FIFO. User requested dump of firewall queue.");
440                 syslog(LOG_INFO,"--------------------------------------");
441                 req.unit = fwunit;
442                 ctl_firewall(IP_FW_PCONN,&req);
443                 syslog(LOG_INFO,"--------------------------------------");
444             } else if (sscanf(buf,"debug %d", &pid) == 1) {
445                 syslog(LOG_INFO,"FIFO. Changing debug flags to %d.",pid);
446                 debug = pid;
447             } else if (sscanf(buf,"dynamic %n%*s%n %n",&j,&k,&l) == 1) {
448                 buf[k] = 0;
449                 if (inet_addr(buf+j) == (unsigned long)0xffffffff
450                 ||  inet_addr(buf+l) == (unsigned long)0xffffffff) {
451                     syslog(LOG_INFO,"FIFO: bad parameters '%s' and '%s' to dynamic command ignored", buf+j,buf+l);
452                 } else {
453                     if (local_ip)
454                         free(local_ip);
455                     if (remote_ip)
456                         free(remote_ip);
457                     local_ip = strdup(buf+j);
458                     remote_ip = strdup(buf+l);
459                     force_dynamic = 1;
460                 }
461             } else if (strncmp(buf,"monitor", 7) == 0) {
462                 struct stat sbuf;
463                 int fd;
464                 MONITORS *new;
465
466                 k = 0;
467                 if (sscanf(buf,"monitor %d %n",&j,&k) == 1) {
468                     syslog(LOG_INFO,"FIFO: monitor connection at info level %d to %s requested",
469                             j,buf+k);
470                 } else if (buf[7] != 0 && buf[7] == ' ') {
471                     syslog(LOG_INFO,"FIFO: full monitor connection to %s requested",
472                         buf+k);
473                     j = 255;    /* Heavy weight connection requested */
474                     k = 8;
475                 }
476                 if (k >= 8) {
477                     /* Check list to see if this is just a status change */
478                     new = monitors;
479                     while (new) {
480                         if (strcmp(new->name,buf+k) == 0) {
481                             new->level = j;
482                             output_state();
483                             break;
484                         }
485                         new = new->next;
486                     }
487                     if (!new) {
488                         if (stat(fifoname,&sbuf) < 0 || !sbuf.st_mode&S_IFIFO) {
489                             syslog(LOG_INFO,"FIFO: %s not a pipe.",
490                                 buf+k);
491                         } else if ((fd = open(buf+k,O_WRONLY))<0) {
492                             syslog(LOG_INFO,"FIFO: could not open pipe %s: %m",
493                                 buf+k);
494                         } else {
495                             new = (MONITORS *)malloc(sizeof(MONITORS));
496                             new->name = strdup(buf+k);
497                             new->next = monitors;
498                             new->fd = fd;
499                             new->level = j;
500                             monitors = new;
501                             output_state();
502                         }
503                     }
504                 } else {
505                     syslog(LOG_INFO,"FIFO: empty monitor request ignored");
506                 }
507             } else if (strncmp(buf,"message ",8) == 0) {
508                 /* pass a message from the connector on to the monitor */
509                 if (monitors) {
510                     mon_write(MONITOR_MESSAGE,"MESSAGE\n",8);
511                     mon_write(MONITOR_MESSAGE,buf+8,strlen(buf+8));
512                     mon_write(MONITOR_MESSAGE,"\n",1);
513                 }
514             } else if (sscanf(buf,"connect %d %n", &pid, &dev) == 1) {
515                 if (pid > 1) {
516                     if ((state != STATE_DOWN && state != STATE_CLOSE
517                         && !give_way)
518                     || state==STATE_UP || req_pid) {
519                         /* somebody else already has this diald, tell 'em */
520                         kill(pid, SIGTERM);
521                         syslog(LOG_INFO,"FIFO: link up requested but denied");
522                     } else {
523                         req_pid = pid;
524                         req_dev = (char *)malloc(tail-(buf+dev)+1);
525                         if (req_dev == 0) {
526                             req_pid = 0;
527                             syslog(LOG_ERR,"FIFO: no memory to store requested devce!");
528                         } else {
529                             strcpy(req_dev, buf+dev);
530                             request_down = 0;
531                             request_up = 1;
532                             syslog(LOG_INFO,"FIFO: link up requested on device %s", req_dev);
533                         }
534                     }
535                 }
536             } else if (strncmp(buf, "interface ", 10) == 0) {
537                 syslog(LOG_INFO, "FIFO: interface set to %s.", buf+10);
538                 dev = strcspn(buf + 10, "0123456789");
539                 if (buf[dev])
540                     link_iface = atoi(buf + (10 + dev));
541             } else {
542                 syslog(LOG_ERR,"Unknown request '%s' made.", buf);
543             }
544            buf = tail+1;
545        }
546        tail++;
547     }
548
549     pipe_flush(&fifo_pipe,buf-fifo_pipe.buf);
550 }
551
552 /*
553  * Deal with master side packet on the SLIP link.
554  */
555 void proxy_read()
556 {
557     char buffer[4096];
558     int len;
559     struct SOCKADDR to;
560
561     /* read the SLIP packet */
562     len = recv_packet(buffer,4096);
563
564     if (!do_reroute) {
565         /* if we are doing unsafe routing, all counting is in the filter.
566          * otherwise we can see transmitted bytes directly at this spot.
567          */
568         txtotal += len;
569         itxtotal += len;
570         rxtotal -= len; /* since it will double count on the snoop */
571         irxtotal -= len;
572     }
573
574     /* If we get here with the link up and fwdfd not -1,
575      * and we are rerouting, then it must be
576      * that the external interface has gone down without
577      * taking the link with it, and as a result our route
578      * to the external interface got lost. (This CAN legally
579      * happen with PPP). In this case we buffer the packet so
580      * we can retransmit it when the link comes back up.
581      * OR
582      * the kernel is retransmitting something through sl0, despite
583      * the existance of a route through another device...
584      */
585
586     /* if the external iface is up then probably we can send it on */
587     if (link_iface != -1 && fwdfd != -1) {
588         /* Make sure we try to restore the link to working condition now... */
589         if (do_reroute && mode == MODE_PPP) {
590             /* Check if a route exists at this point through the ppp device. */
591             /* If not then we must be half dead. */
592             if (!ppp_route_exists()) {
593                 /* The external iface is down, buffer the packet so we can
594                  * forward it when the iface comes up.
595                  */
596                 ppp_half_dead = 1;
597                 if (buffer_packets)
598                     buffer_packet(len,buffer);
599                 return;
600             }
601         }
602
603         /* Ok, the interface is there, and the route is up,
604          * so just send it on. This can happen when routing is switched
605          * in the middle of a retransmission sequence. (There is a race
606          * between the route switching and the forwarding I think.)
607          */
608
609 #ifdef HAS_SOCKADDR_PKT
610         to.spkt_family = AF_INET;
611         strcpy(to.spkt_device,snoop_dev);
612         to.spkt_protocol = htons(ETH_P_IP);
613 #else
614         to.sa_family = AF_INET;
615         strcpy(to.sa_data,snoop_dev);
616 #endif
617         if (debug&DEBUG_VERBOSE)
618             syslog(LOG_DEBUG,"Forwarding packet of length %d",len);
619         if (sendto(fwdfd,buffer,len,0,(struct sockaddr *)&to,sizeof(struct SOCKADDR)) < 0) {
620             syslog(LOG_ERR,
621                 "Error forwarding data packet to physical device: %m");
622         }
623     } else {
624         /* If the link isn't up, then we better buffer the packets */
625         if (buffer_packets)
626             buffer_packet(len,buffer);
627     }
628 }
629
630 /*
631  * Terminate diald gracefully.
632  */
633
634 static int in_die = 0;
635
636 void die(int i)
637 {
638     int count;
639
640     if (!in_die) {
641         in_die = 1;
642         /* We're killing without a care here. Uhggg. */
643         if (link_pid) kill(link_pid,SIGINT);
644         if (dial_pid) kill(dial_pid,SIGINT);
645         if (running_pid) kill(running_pid,SIGINT);
646         /* Wait up to 30 seconds for them to die */
647         for (count = 0; (link_pid || dial_pid) && count < 30; count++)
648             sleep(1);
649         /* If they aren't dead yet, kill them for sure */
650         if (link_pid) kill(link_pid,SIGKILL);
651         if (dial_pid) kill(dial_pid,SIGKILL);
652         if (running_pid) kill(running_pid,SIGKILL);
653         /* Give the system a second to send the signals */
654         if (link_pid || dial_pid || running_pid) sleep(1);
655         close_modem();
656         interface_down();
657         proxy_down();
658         unlink(pidfile);
659         exit(i);
660     }
661 }
662
663 /*
664  * Signal handlers.
665  */
666
667 /*
668  * Modem link went down.
669  */
670 void sig_hup(int sig)
671 {
672     syslog(LOG_INFO, "SIGHUP: modem got hung up on.");
673     modem_hup = 1;
674 }
675
676 /*
677  * User wants the link to go down.
678  * (Perhaps there should be a 10 second delay? Configurable????)
679  */
680 void sig_intr(int sig)
681 {
682     syslog(LOG_INFO, "SIGINT: Link down request received.");
683     request_down = 1;
684     request_up = 0;
685 }
686
687 /*
688  *  The user has requested that the link be put up.
689  */
690 void linkup(int sig)
691 {
692     syslog(LOG_INFO, "SIGUSR1. External link up request received.");
693     request_down = 0;
694     request_up = 1;
695 }
696
697 /*
698  * A child process died. Find out which one.
699  */
700 void sig_chld(int sig)
701 {
702     int pid, status;
703     static int seq = 0;
704     ++seq;
705     while ((pid = waitpid(-1,&status,WNOHANG)) > 0) {
706         if (debug&DEBUG_VERBOSE)
707             syslog( LOG_DEBUG, "SIGCHLD[%d]: pid %d %s, status %d", seq, pid,
708                     pid == link_pid ? "link"
709                         : pid == dial_pid ? "dial"
710                         : pid == running_pid ? "system"
711                         : "other",
712                     status);
713         if (pid == link_pid) link_pid = 0;
714         else if (pid == dial_pid) { dial_status = status; dial_pid = 0; }
715         else if (pid == running_pid) { running_status = status; running_pid = 0; }
716         else if (!WIFEXITED(status))
717             syslog(LOG_ERR,"Abnormal exit (status %d) on pid %d",status,pid);
718         else if (WEXITSTATUS(status) != 0)
719             syslog(LOG_ERR,"Nonzero exit status (%d) on pid %d",
720                 WEXITSTATUS(status),pid);
721         if (pid > 0) {
722             if (WIFSIGNALED(status)) {
723                 syslog(LOG_WARNING, "child process %d terminated with signal %d",
724                        pid, WTERMSIG(status));
725             }
726         }
727     }
728     if (pid && errno != ECHILD)
729         syslog(LOG_ERR, "waitpid: %m");
730     return;
731 }
732
733 /*
734  * User wants diald to be terminated.
735  */
736 void sig_term(int sig)
737 {
738     syslog(LOG_INFO, "SIGTERM. Termination request received.");
739     terminate = 1;
740 }
741
742 int report_system_result(int res,char *buf)
743 {
744     if (res == -1)
745         syslog(LOG_ERR,"System call failure on command '%s'",buf);
746     else if (!WIFEXITED(res))
747         syslog(LOG_ERR,"Abnormal exit (status %d) on command '%s'",res,buf);
748     else if (WEXITSTATUS(res) != 0)
749         syslog(LOG_ERR,"Nonzero exit status (%d) on command '%s'",WEXITSTATUS(res),buf);
750     else
751         return 0;
752     return 1;
753 }
754
755
756 int system(const char *buf)
757 {
758     int fd, pid;
759
760     block_signals();
761
762 #ifdef __uClinux__
763     pid = running_pid = vfork();
764     if (pid > 0) {
765     if (debug&DEBUG_VERBOSE)
766         syslog(LOG_DEBUG, "running system pid=%d \"%s\"", pid, buf);
767         }
768 #else
769     if (debug&DEBUG_VERBOSE)
770         syslog(LOG_DEBUG,"running '%s'",buf);
771     pid = running_pid = fork();
772 #endif
773
774     if (pid != 0) unblock_signals();
775
776     if (pid < 0) {
777         syslog(LOG_ERR, "failed to fork and run '%s': %m",buf);
778                 return -1;
779     }
780
781     if (pid == 0) {
782         /* change the signal actions back to the defaults, then unblock them. */
783         default_sigacts();
784                 unblock_signals();
785
786         /* Leave the current location */
787         (void) setsid();    /* No controlling tty. */
788         (void) umask (S_IRWXG|S_IRWXO);
789         (void) chdir ("/"); /* no current directory. */
790
791         /* close all fd's the child should not see */
792         close(0);
793         close(1);
794         close(2);
795         if (modem_fd >= 0) close(modem_fd);
796         close(proxy_mfd);      /* close the master pty endpoint */
797         close(proxy_sfd);      /* close the slave pty endpoint */
798         if (fifo_fd != -1) close(fifo_fd);
799         if (monitors) {
800             MONITORS *c = monitors;
801             while (c) {
802                 close(c->fd);
803                 c = c->next;
804             }
805         }
806
807         /* make sure the stdin, stdout and stderr get directed to /dev/null */
808         fd = open("/dev/null", O_RDWR);
809         if (fd >= 0) {
810             if (fd != 0) {
811                 dup2(fd, 0);
812                 close(fd);
813             }
814             dup2(0, 1);
815             dup2(0, 2);
816         }
817
818 #ifdef EMBED
819         execuc(buf);
820         syslog(LOG_ERR, "could not exec program: errno=%d, buf=%s", errno, buf);
821 #else
822         execl("/bin/sh", "sh", "-c", buf, (char *)0);
823         syslog(LOG_ERR, "could not exec /bin/sh: %m");
824 #endif
825         _exit(127);
826         /* NOTREACHED */
827     }
828     while (running_pid) {
829         pause();
830     }
831     return running_status;
832 }
833
834 void background_system(const char *buf)
835 {
836     int fd, pid;
837
838     block_signals();
839
840 #ifdef __uClinux__
841     pid = vfork();
842     if (pid > 0)
843     if (debug&DEBUG_VERBOSE)
844         syslog(LOG_NOTICE, "running background pid=%d \"%s\"", pid, buf);
845 #else
846     if (debug&DEBUG_VERBOSE)
847         syslog(LOG_DEBUG,"running '%s'",buf);
848     pid = fork();
849 #endif
850
851     if (pid != 0) unblock_signals();
852
853     if (pid < 0) {
854         syslog(LOG_ERR, "failed to fork and run '%s': %m",buf);
855         return;
856     }
857
858     if (pid == 0) {
859         /* change the signal actions back to the defaults, then unblock them. */
860         default_sigacts();
861         unblock_signals();
862
863         /* Leave the current location */
864         (void) setsid();    /* No controlling tty. */
865         (void) umask (S_IRWXG|S_IRWXO);
866         (void) chdir ("/"); /* no current directory. */
867
868         /* close all fd's the child should not see */
869         close(0);
870         close(1);
871         close(2);
872         if (modem_fd >= 0) close(modem_fd);
873         close(proxy_mfd);      /* close the master pty endpoint */
874         close(proxy_sfd);      /* close the slave pty endpoint */
875         if (fifo_fd != -1) close(fifo_fd);
876         if (monitors) {
877             MONITORS *c = monitors;
878             while (c) {
879                 close(c->fd);
880                 c = c->next;
881             }
882         }
883
884         /* make sure the stdin, stdout and stderr get directed to /dev/null */
885         fd = open("/dev/null", O_RDWR);
886         if (fd >= 0) {
887             if (fd != 0) {
888                 dup2(fd, 0);
889                 close(fd);
890             }
891             dup2(0, 1);
892             dup2(0, 2);
893         }
894
895 #ifdef EMBED
896         execuc(buf);
897         syslog(LOG_ERR, "could not exec background: errno=%d buf=%s", errno, buf);
898 #else
899         execl("/bin/sh", "sh", "-c", buf, (char *)0);
900         syslog(LOG_ERR, "could not exec /bin/sh: %m");
901 #endif
902         _exit(127);
903         /* NOTREACHED */
904     }
905 }
906
907 void mon_write(int level, char *message,int len)
908 {
909     MONITORS *c = monitors, *p = 0, *cn;
910     while (c) {
911         cn = c->next;
912         if (c->level&level) {
913             if (write(c->fd,message,len) < 0) {
914                 if (errno == EPIPE) {
915                     syslog(LOG_INFO,"Monitor pipe %s closed.",c->name);
916                 } else {
917                     /* Write error. The reader probably got swapped out
918                      * or something and the pipe flooded. We'll just "loose"
919                      * the data.
920                      */
921                      p = c;
922                      continue;
923                 }
924                 close(c->fd);
925                 if (p) p->next = c->next;
926                 else monitors = c->next;
927                 free(c->name);
928                 free(c);
929             } else {
930                 p = c;
931             }
932         }
933         c = cn;
934     }
935 }