diff options
author | Nalin Dahyabhai <nalin@redhat.com> | 2001-02-28 15:03:27 +0000 |
---|---|---|
committer | Nalin Dahyabhai <nalin@redhat.com> | 2001-02-28 15:03:27 +0000 |
commit | bd85b21189a840a13649929062832f6003d698a3 (patch) | |
tree | a221f9d099edccda23097c56718b4e03f58c93db | |
parent | cd56db10c17e6319e3fdd9a08bbd2689dc1a7a9c (diff) | |
download | initscripts-bd85b21189a840a13649929062832f6003d698a3.tar initscripts-bd85b21189a840a13649929062832f6003d698a3.tar.gz initscripts-bd85b21189a840a13649929062832f6003d698a3.tar.bz2 initscripts-bd85b21189a840a13649929062832f6003d698a3.tar.xz initscripts-bd85b21189a840a13649929062832f6003d698a3.zip |
general cleanups and reorg
-rw-r--r-- | src/ppp-watch.c | 764 |
1 files changed, 433 insertions, 331 deletions
diff --git a/src/ppp-watch.c b/src/ppp-watch.c index d74935a1..6114215f 100644 --- a/src/ppp-watch.c +++ b/src/ppp-watch.c @@ -6,7 +6,7 @@ * one argument: the logical name of the device to bring up. Does not * detach until the interface is up or has permanently failed to come up. * - * Copyright 1999 Red Hat, Inc. + * Copyright 1999-2001 Red Hat, Inc. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by @@ -75,198 +75,198 @@ #include <sys/wait.h> #include <termios.h> #include <net/if.h> - +#include <glib.h> #include "shvar.h" +#define IFCFGPREFIX "/etc/sysconfig/network-scripts/ifcfg-" +#define IFUP_PPP "/etc/sysconfig/network-scripts/ifup-ppp" + static int theSigterm = 0; static int theSigint = 0; static int theSighup = 0; static int theSigio = 0; static int theSigchld = 0; static int theSigalrm = 0; +static int pipeArray[2]; // patch to respect the maxfail parameter to ppp // Scott Sharkey <ssharkey@linux-no-limits.com> static int dialCount = 0; static int theChild; - - -static void -cleanExit(int exitCode); - - +static void failureExit(int exitCode); static void -forward_signal(int signo) { +interrupt_child(int signo) { kill(theChild, SIGINT); } - - - static void set_signal(int signo, void (*handler)(int)) { struct sigaction act; - act.sa_handler = handler; act.sa_flags = SA_RESTART; sigemptyset(&act.sa_mask); sigaction(signo, &act, NULL); } +/* Create a pipe, and fork off a child. This is the end of the road for + * the parent, which will wait for an exit status byte on the pipe (which + * is written by the child). */ +static void +detach(char *device) { + pid_t childpid; + unsigned char exitCode; + int fd; + if (pipe(pipeArray) == -1) + exit(25); -static void -detach(int now, int parentExitCode, char *device) { - static int pipeArray[2]; - char exitCode; + childpid = fork(); + if (childpid == -1) + exit(26); - if (now) { - /* execute -- ignore errors in case called more than once */ - exitCode = parentExitCode; - write(pipeArray[1], &exitCode, 1); - close(pipeArray[1]); + if (childpid != 0) { + /* The parent only cares about notifications from the child. */ + close (pipeArray[1]); - } else { - /* set up */ - int child; - - if (pipe(pipeArray)) exit (25); - - child = fork(); - if (child < 0) exit(26); - if (child) { - /* parent process */ - close (pipeArray[1]); - - /* forward likely signals to the main process; we will - * react later - */ - theChild = child; - set_signal(SIGINT, forward_signal); - set_signal(SIGTERM, forward_signal); - set_signal(SIGHUP, forward_signal); - - while (read (pipeArray[0], &exitCode, 1) < 0) { - switch (errno) { - case EINTR: continue; - default: exit (27); /* this will catch EIO in particular */ - } + /* Certain signals are meant for our child, the watcher process. */ + theChild = childpid; + set_signal(SIGINT, interrupt_child); + set_signal(SIGTERM, interrupt_child); + set_signal(SIGHUP, interrupt_child); + + /* Read the pipe until the child gives us an exit code as a byte. */ + while (read (pipeArray[0], &exitCode, 1) == -1) { + switch (errno) { + case EINTR: continue; + default: exit (27); /* this will catch EIO in particular */ } - switch (exitCode) { - case 0: - break; + } + switch (exitCode) { + case 0: + break; case 33: - fprintf(stderr, "%s already up, initiating redial\n", device); - break; + fprintf(stderr, "%s already up, initiating redial\n", device); + break; case 34: - fprintf(stderr, "Failed to activate %s, retrying in the background\n", device); - break; + fprintf(stderr, "Failed to activate %s, retrying in the background\n", device); + break; default: - fprintf(stderr, "Failed to activate %s with error %d\n", device, exitCode); - break; - } - exit(exitCode); - - } else { - int devnull; - - /* child process */ - close (pipeArray[0]); - /* become a daemon */ - devnull = open("/dev/null", O_RDONLY); - dup2(devnull,0); - close(devnull); - devnull = open("/dev/null", O_WRONLY); - dup2(devnull,1); - dup2(devnull,2); - close(devnull); - setsid(); - setpgid(0, 0); - } + fprintf(stderr, "Failed to activate %s with error %d\n", device, exitCode); + break; + } + exit(exitCode); } -} + /* We're in the child process, which only writes the exit status + * of the pppd process to its parent (i.e., it reads nothing). */ + close (pipeArray[0]); + + /* Redirect stdio to /dev/null. */ + fd = open("/dev/null", O_RDONLY); + dup2(fd, STDIN_FILENO); + close(fd); + fd = open("/dev/null", O_WRONLY); + dup2(fd, STDOUT_FILENO); + dup2(fd, STDERR_FILENO); + close(fd); + + /* Become session and process group leader. */ + setsid(); + setpgid(0, 0); +} +/* Do magic with the pid file (/var/run/pppwatch-$DEVICE.pid): + * Try to open it for writing. If it exists, send a SIGHUP to whatever PID + * is already listed in it and remove it. Repeat until we can open it. + * Write out our PID, and return. */ static void doPidFile(char *device) { - static char *pidFileName = NULL; - char *pidFilePath; - int fd; FILE *f; + static char pidFilePath[PATH_MAX] = ""; + int fd = -1; + FILE *f = NULL; pid_t pid = 0; - if (pidFileName) { - /* remove it */ - pidFilePath = alloca(strlen(pidFileName) + 25); - sprintf(pidFilePath, "/var/run/pppwatch-%s.pid", pidFileName); - unlink(pidFilePath); /* not much we can do in case of error... */ - } - - if (device) { - /* create it */ - pidFileName = device; - pidFilePath = alloca(strlen(pidFileName) + 25); - sprintf(pidFilePath, "/var/run/pppwatch-%s.pid", pidFileName); -restart: - fd = open(pidFilePath, O_WRONLY|O_TRUNC|O_CREAT|O_EXCL, - S_IRUSR|S_IWUSR | S_IRGRP | S_IROTH); - - if (fd == -1) { - /* file already existed, or terrible things have happened... */ - fd = open(pidFilePath, O_RDONLY); - if (fd == -1) - cleanExit(36); /* terrible things have happened */ - /* already running, send a SIGHUP (we presume that they - * are calling ifup for a reason, so they probably want - * to redial) and then exit cleanly and let things go - * on in the background - */ - f = fdopen(fd, "r"); - if (!f) cleanExit(37); - fscanf(f, "%d", &pid); - fclose(f); - if (pid) { - if (kill(pid, SIGHUP)) { - unlink(pidFilePath); - goto restart; - } else { - /* reset pidFileName so we don't delete the current one */ - pidFileName = NULL; - cleanExit(33); - } - } + if (device == NULL) { + /* Remove an existing pid file -- we're exiting. */ + if(strlen(pidFilePath) > 0) { + unlink(pidFilePath); } + } else { + /* Set up the name of the pid file, used only the first time. */ + snprintf(pidFilePath, sizeof(pidFilePath), "/var/run/pppwatch-%s.pid", + device); + + /* Create the pid file. */ + do { + fd = open(pidFilePath, O_WRONLY|O_TRUNC|O_CREAT|O_EXCL|O_NOFOLLOW, + S_IRUSR|S_IWUSR | S_IRGRP | S_IROTH); + if(fd == -1) { + /* Try to open the file for read. */ + fd = open(pidFilePath, O_RDONLY); + if(fd == -1) + failureExit(36); /* This is not good. */ + + /* We're already running, send a SIGHUP (we presume that they + * are calling ifup for a reason, so they probably want to + * redial) and then exit cleanly and let things go on in the + * background. Muck with the filename so that we don't go + * deleting the pid file for the already-running instance. + */ + f = fdopen(fd, "r"); + if(f == NULL) + failureExit(37); + + pid = 0; + fscanf(f, "%d", &pid); + fclose(f); + + if(pid) { + /* Try to kill it. */ + if (kill(pid, SIGHUP) == -1) { + /* No such pid, remove the bogus pid file. */ + unlink(pidFilePath); + } else { + /* Got it. Don't mess with the pid file on + * our way out. */ + memset(pidFilePath, '\0', sizeof(pidFilePath)); + failureExit(33); + } + } + } + } while(fd == -1); f = fdopen(fd, "w"); - if (!f) - cleanExit(31); + if(f == NULL) + failureExit(31); fprintf(f, "%d\n", getpid()); fclose(f); } } - - - - -int -fork_exec(int wait, char *path, char *arg1, char *arg2, char *arg3) +/* Fork off and exec() a child process. If reap_child is non-zero, + * wait for the child to exit and return 0 if it ran successfully, + * otherwise return 0 right away and let the SIGCHLD handler deal. */ +static int +fork_exec(gboolean reap, char *path, char *arg1, char *arg2, char *arg3) { - pid_t child; + pid_t childpid; int status; sigset_t sigs; - if (!(child = fork())) { - /* child */ + childpid = fork(); + if (childpid == -1) + exit(26); - /* don't leave signals blocked for pppd */ + if (childpid == 0) { + /* Do the exec magic. Prepare by clearing the signal mask for pppd. */ sigemptyset(&sigs); sigprocmask(SIG_SETMASK, &sigs, NULL); - if (!wait) { - /* make sure that pppd is in its own process group */ + if (!reap) { + /* Make sure that the pppd is the leader for its process group. */ setsid(); setpgid(0, 0); } @@ -276,8 +276,8 @@ fork_exec(int wait, char *path, char *arg1, char *arg2, char *arg3) _exit (1); } - if (wait) { - wait4 (child, &status, 0, NULL); + if (reap) { + waitpid (childpid, &status, 0); if (WIFEXITED(status) && (WEXITSTATUS(status) == 0)) { return 0; } else { @@ -288,174 +288,205 @@ fork_exec(int wait, char *path, char *arg1, char *arg2, char *arg3) } } +/* Relay the pppd's exit code up to the parent -- can only be called once, + * because the parent exits as soon as it reads a byte. */ +static void +relay_exitcode(unsigned char code) +{ + unsigned char exitCode; + exitCode = code; + write(pipeArray[1], &exitCode, 1); + close(pipeArray[1]); +} - +/* Unregister with netreport, relay a status byte to the parent, clean up + * the pid file, and bail. */ static void -cleanExit(int exitCode) { - fork_exec(1, "/sbin/netreport", "-r", NULL, NULL); - detach(1, exitCode, NULL); +failureExit(int exitCode) { + fork_exec(TRUE, "/sbin/netreport", "-r", NULL, NULL); + relay_exitcode(exitCode); doPidFile(NULL); exit(exitCode); } - - +/* Keeps track of which signals we've seen so far. */ static void -signal_handler (int signum) { +signal_tracker (int signum) { switch(signum) { - case SIGTERM: - theSigterm = 1; break; - case SIGINT: - theSigint = 1; break; - case SIGHUP: - theSighup = 1; break; - case SIGIO: - theSigio = 1; break; - case SIGCHLD: - theSigchld = 1; break; - case SIGALRM: - theSigalrm = 1; break; + case SIGTERM: + theSigterm = 1; break; + case SIGINT: + theSigint = 1; break; + case SIGHUP: + theSighup = 1; break; + case SIGIO: + theSigio = 1; break; + case SIGCHLD: + theSigchld = 1; break; + case SIGALRM: + theSigalrm = 1; break; } } - +/* Return a shvarFile for this interface, taking into account one level of + * inheritance (eeewww). */ static shvarFile * -shvarfilesGet(char *interfaceName) { - shvarFile *ifcfg; - char *ifcfgName, *ifcfgParentName, *ifcfgParentDiff; - static char ifcfgPrefix[] = "/etc/sysconfig/network-scripts/ifcfg-"; +shvarfilesGet(const char *interfaceName) { + shvarFile *ifcfg = NULL; + char ifcfgName[PATH_MAX]; + char *ifcfgParentDiff = NULL; - ifcfgName = alloca(sizeof(ifcfgPrefix)+strlen(interfaceName)+1); - sprintf(ifcfgName, "%s%s", ifcfgPrefix, interfaceName); + /* Start with the basic configuration. */ + snprintf(ifcfgName, sizeof(ifcfgName), "%s%s", IFCFGPREFIX, interfaceName); ifcfg = svNewFile(ifcfgName); - if (!ifcfg) return NULL; + if (ifcfg == NULL) + return NULL; - /* Do we have a parent interface to inherit? */ - ifcfgParentDiff = strchr(interfaceName, '-'); + /* Do we have a parent interface (i.e., for ppp0-blah, ppp0) to inherit? */ + ifcfgParentDiff = strchr(ifcfgName + sizeof(IFCFGPREFIX), '-'); if (ifcfgParentDiff) { - /* allocate more than enough memory... */ - ifcfgParentName = alloca(sizeof(ifcfgPrefix)+strlen(interfaceName)+1); - strcpy(ifcfgParentName, ifcfgPrefix); - strncat(ifcfgParentName, interfaceName, ifcfgParentDiff-interfaceName); - ifcfg->parent = svNewFile(ifcfgParentName); + *ifcfgParentDiff = '\0'; + ifcfg->parent = svNewFile(ifcfgName); } - /* don't keep the file descriptors around, they can become - * stdout for children - */ - close (ifcfg->fd); ifcfg->fd = 0; + /* This is very unclean, but we have to close the shvar descriptors in + * case they've been numbered STDOUT_FILENO or STDERR_FILENO, which would + * be disastrous if inherited by a child process. */ + close (ifcfg->fd); + ifcfg->fd = 0; + if (ifcfg->parent) { - close (ifcfg->parent->fd); ifcfg->parent->fd = 0; + close (ifcfg->parent->fd); + ifcfg->parent->fd = 0; } return ifcfg; } - - -static char * -pppLogicalToPhysical(int *pppdPid, char *logicalName) { - char *mapFileName; - char buffer[20]; /* more than enough space for ppp<n> */ +/* Convert a logical interface name to a real one by reading the lock + * file created by pppd. */ +static void +pppLogicalToPhysical(int *pppdPid, char *logicalName, char **physicalName) { + char mapFileName[PATH_MAX]; + char buffer[20]; char *p, *q; - int f, n; + int fd, n; char *physicalDevice = NULL; - mapFileName = alloca (strlen(logicalName)+20); - sprintf(mapFileName, "/var/run/ppp-%s.pid", logicalName); - if ((f = open(mapFileName, O_RDONLY)) >= 0) { - n = read(f, buffer, 20); + snprintf(mapFileName, sizeof(mapFileName), "/var/run/ppp-%s.pid", + logicalName); + fd = open(mapFileName, O_RDONLY); + if (fd != -1) { + n = read(fd, buffer, sizeof(buffer)); + close(fd); if (n > 0) { buffer[n] = '\0'; - /* get past pid */ - p = buffer; while (*p && *p != '\n') p++; *p = '\0'; p++; - if (pppdPid) *pppdPid = atoi(buffer); - /* get rid of \n */ - q = p; while (*q && *q != '\n' && q < buffer+n) q++; *q = '\0'; - if (*p) physicalDevice = strdup(p); + /* Split up the file at the first line break -- the PID is on the + * first line. */ + if((p = strchr(buffer, '\n')) != NULL) { + *p = '\0'; + p++; + if (pppdPid) { + *pppdPid = atoi(buffer); + } + /* The physical device name is on the second line. */ + if((q = strchr(p, '\n')) != NULL) { + *q = '\0'; + physicalDevice = strdup(p); + } + } } - close(f); } - return physicalDevice; + if (physicalDevice) { + if (physicalName) { + *physicalName = physicalDevice; + } else { + free(physicalDevice); + } + } else { + if (physicalName) { + *physicalName = NULL; + } + } } - -static int -interfaceStatus(char *device) { +/* Return a boolean value indicating if the interface is up. If not, or + * if we don't know, return FALSE. */ +static gboolean +interfaceIsUp(char *device) { int sock = -1; - int pfs[] = {AF_INET, AF_IPX, AF_AX25, AF_APPLETALK, 0}; + int family[] = {PF_INET, PF_IPX, PF_AX25, PF_APPLETALK, 0}; int p = 0; struct ifreq ifr; - int retcode = 0; + gboolean retcode = FALSE; - while ((sock == -1) && pfs[p]) { - sock = socket(pfs[p++], SOCK_DGRAM, 0); + /* Create a socket suitable for doing routing ioctls. */ + for (p = 0; (sock == -1) && family[p]; p++) { + sock = socket(family[p], SOCK_DGRAM, 0); } - if (sock == -1) return 0; + if (sock == -1) + return FALSE; + /* Populate the request structure for getting the interface's status. */ memset(&ifr, 0, sizeof(ifr)); - strncpy(ifr.ifr_name, device, IFNAMSIZ); + strncpy(ifr.ifr_name, device, sizeof(ifr.ifr_name) - 1); + ifr.ifr_name[sizeof(ifr.ifr_name) - 1] = '\0'; - if (ioctl(sock, SIOCGIFFLAGS, &ifr) < 0) { - retcode = 0; + /* We return TRUE iff the ioctl succeeded and the interface is UP. */ + if (ioctl(sock, SIOCGIFFLAGS, &ifr) == -1) { + retcode = FALSE; } else if (ifr.ifr_flags & IFF_UP) { - retcode = 1; + retcode = TRUE; } close(sock); + return retcode; } - -/* very, very minimal hangup function. This is just to attempt to - * hang up a device that should already be hung up, so it does not - * need to be bulletproof. - */ -void +/* Very, very minimal hangup function. This just attempts to hang up a device + * that should already be hung up, so it does not need to be bulletproof. */ +static void hangup(shvarFile *ifcfg) { int fd; - char *filename; - struct termios ots, ts; - - filename = svGetValue(ifcfg, "MODEMPORT"); - if (!filename) return; - fd = open(filename, O_RDWR|O_NOCTTY|O_NONBLOCK); - if (fd == -1) goto clean; - if (tcgetattr(fd, &ts)) goto clean; - ots = ts; - write(fd, "\r", 1); /* tickle modems that do not like dropped DTR */ - usleep(1000); - cfsetospeed(&ts, B0); - tcsetattr(fd, TCSANOW, &ts); - usleep(100000); - tcsetattr(fd, TCSANOW, &ots); - -clean: - free(filename); + char *line; + struct termios original_ts, ts; + + line = svGetValue(ifcfg, "MODEMPORT"); + if (line == NULL) + return; + + fd = open(line, O_RDWR | O_NOCTTY | O_NONBLOCK); + if (fd != -1) { + if (tcgetattr(fd, &ts) != -1) { + original_ts = ts; + write(fd, "\r", 1); /* tickle modems that do not like dropped DTR */ + usleep(1000); + cfsetospeed(&ts, B0); + tcsetattr(fd, TCSANOW, &ts); + usleep(100000); + tcsetattr(fd, TCSANOW, &original_ts); + } + close(fd); + } + free(line); } - - - - - - - - int main(int argc, char **argv) { - int status, waited; + int status; + pid_t waited; char *device, *real_device, *physicalDevice = NULL; - char *theBoot = NULL; + char *boot = NULL; shvarFile *ifcfg; sigset_t blockedsigs, unblockedsigs; int pppdPid = 0; int timeout = 30; char *temp; - int dieing = 0; + gboolean dying = FALSE; int sendsig; - int connectedOnce = 0; + gboolean connectedOnce = FALSE; int maxfail = 0; // MAXFAIL Patch <ssharkey@linux-no-limits.com> if (argc < 2) { @@ -463,32 +494,39 @@ main(int argc, char **argv) { exit(30); } - if (!strncmp(argv[1], "ifcfg-", 6)) { + if (strncmp(argv[1], "ifcfg-", 6) == 0) { device = argv[1] + 6; } else { device = argv[1]; } - detach(0, 0, device); /* prepare */ + detach(device); /* Prepare a child process to monitor pppd. When we + return, we'll be in the child. */ - if (argc > 2 && !strcmp("boot", argv[2])) { - theBoot = argv[2]; + if ((argc > 2) && (strcmp("boot", argv[2]) == 0)) { + boot = argv[2]; } ifcfg = shvarfilesGet(device); - if (!ifcfg) cleanExit(28); + if (ifcfg == NULL) + failureExit(28); real_device = svGetValue(ifcfg, "DEVICE"); - if (!real_device) real_device = device; + if (real_device == NULL) + real_device = device; doPidFile(real_device); - set_signal(SIGTERM, signal_handler); - set_signal(SIGINT, signal_handler); - set_signal(SIGHUP, signal_handler); - set_signal(SIGIO, signal_handler); - set_signal(SIGCHLD, signal_handler); - if (theBoot) { + /* We'll want to know which signal interrupted our sleep below, so + * attach a signal handler to these. */ + set_signal(SIGTERM, signal_tracker); + set_signal(SIGINT, signal_tracker); + set_signal(SIGHUP, signal_tracker); + set_signal(SIGIO, signal_tracker); + set_signal(SIGCHLD, signal_tracker); + + /* We time out only if we're being run at boot-time. */ + if (boot) { temp = svGetValue(ifcfg, "BOOTTIMEOUT"); if (temp) { timeout = atoi(temp); @@ -497,35 +535,41 @@ main(int argc, char **argv) { } else { timeout = 30; } - set_signal(SIGALRM, signal_handler); + set_signal(SIGALRM, signal_tracker); alarm(timeout); } - fork_exec(1, "/sbin/netreport", NULL, NULL, NULL); + /* Register us to get a signal when something changes. Yes, that's vague. */ + fork_exec(TRUE, "/sbin/netreport", NULL, NULL, NULL); + + /* Reset theSigchld, which should have been triggered by netreport. */ theSigchld = 0; - /* don't set up the procmask until after we have received the netreport - * signal - */ + /* We don't set up the procmask until after we have received the netreport + * signal. Do so now. */ sigemptyset(&blockedsigs); sigaddset(&blockedsigs, SIGTERM); sigaddset(&blockedsigs, SIGINT); sigaddset(&blockedsigs, SIGHUP); sigaddset(&blockedsigs, SIGIO); sigaddset(&blockedsigs, SIGCHLD); - if (theBoot) sigaddset(&blockedsigs, SIGALRM); + if (boot) { + sigaddset(&blockedsigs, SIGALRM); + } sigprocmask(SIG_BLOCK, &blockedsigs, NULL); - /* prepare for sigsuspend later */ sigfillset(&unblockedsigs); sigdelset(&unblockedsigs, SIGTERM); sigdelset(&unblockedsigs, SIGINT); sigdelset(&unblockedsigs, SIGHUP); sigdelset(&unblockedsigs, SIGIO); sigdelset(&unblockedsigs, SIGCHLD); - if (theBoot) sigdelset(&unblockedsigs, SIGALRM); + if (boot) { + sigdelset(&unblockedsigs, SIGALRM); + } + sigprocmask(SIG_UNBLOCK, &unblockedsigs, NULL); - fork_exec(0, "/etc/sysconfig/network-scripts/ifup-ppp", "daemon", device, theBoot); + /* Initialize the retry timeout using the RETRYTIMEOUT setting. */ temp = svGetValue(ifcfg, "RETRYTIMEOUT"); if (temp) { timeout = atoi(temp); @@ -534,71 +578,111 @@ main(int argc, char **argv) { timeout = 30; } - while (1) { - if (!theSigterm && !theSigint && !theSighup && !theSigio && !theSigchld && !theSigalrm) + /* Start trying to bring the interface up. */ + fork_exec(FALSE, IFUP_PPP, "daemon", device, boot); + + while (TRUE) { + /* Wait for a signal. */ + if (!theSigterm && + !theSigint && + !theSighup && + !theSigio && + !theSigchld && + !theSigalrm) { sigsuspend(&unblockedsigs); + } + /* If we got SIGTERM or SIGINT, give up and hang up. */ if (theSigterm || theSigint) { theSigterm = theSigint = 0; - if (dieing) sendsig = SIGKILL; - else sendsig = SIGTERM; - dieing = 1; + /* If we've already tried to exit this way, use SIGKILL instead + * of SIGTERM, because pppd's just being stubborn. */ + if (dying) { + sendsig = SIGKILL; + } else { + sendsig = SIGTERM; + } + dying = TRUE; + + /* Get the pid of our child pppd. */ + pppLogicalToPhysical(&pppdPid, real_device, NULL); - if (physicalDevice) { free(physicalDevice); physicalDevice = NULL; } - physicalDevice = pppLogicalToPhysical(&pppdPid, real_device); - if (physicalDevice) { free(physicalDevice); physicalDevice = NULL; } - if (!pppdPid) cleanExit(35); + /* We don't know what our child pid is. This is very confusing. */ + if (!pppdPid) { + failureExit(35); + } + + /* Die, pppd, die. */ kill(pppdPid, sendsig); if (sendsig == SIGKILL) { - kill(-pppdPid, SIGTERM); /* give it a chance to die nicely */ + kill(-pppdPid, SIGTERM); /* Give it a chance to die nicely, then + kill its whole process group. */ usleep(2500000); kill(-pppdPid, sendsig); hangup(ifcfg); - cleanExit(32); + failureExit(32); } } + /* If we got SIGHUP, reload and redial. */ if (theSighup) { theSighup = 0; - if (ifcfg->parent) svCloseFile(ifcfg->parent); + + /* Free and reload the configuration structure. */ + if (ifcfg->parent) + svCloseFile(ifcfg->parent); svCloseFile(ifcfg); ifcfg = shvarfilesGet(device); - physicalDevice = pppLogicalToPhysical(&pppdPid, real_device); - if (physicalDevice) { free(physicalDevice); physicalDevice = NULL; } + + /* Get the PID of our child pppd. */ + pppLogicalToPhysical(&pppdPid, real_device, NULL); kill(pppdPid, SIGTERM); - /* redial when SIGCHLD arrives, even if !PERSIST */ - connectedOnce = 0; - timeout = 0; /* redial immediately */ + + /* We'll redial when the SIGCHLD arrives, even if PERSIST is + * not set (the latter handled by clearing the "we've connected + * at least once" flag). */ + connectedOnce = FALSE; + + /* We don't want to delay before redialing, either, so cut + * the retry timeout to zero. */ + timeout = 0; } + /* If we got a SIGIO (from netreport, presumably), check if the + * interface is up and return zero (via our parent) if it is. */ if (theSigio) { theSigio = 0; - if (connectedOnce) { - if (physicalDevice) { free(physicalDevice); physicalDevice = NULL; } - } - physicalDevice = pppLogicalToPhysical(NULL, real_device); + + pppLogicalToPhysical(NULL, real_device, &physicalDevice); if (physicalDevice) { - if (interfaceStatus(physicalDevice)) { - /* device is up */ - detach(1, 0, NULL); - connectedOnce = 1; + if (interfaceIsUp(physicalDevice)) { + /* The interface is up, so report a success to a parent if + * we have one. Any errors after this we just swallow. */ + relay_exitcode(0); + connectedOnce = TRUE; } + free(physicalDevice); } } + /* If we got a SIGCHLD, then pppd died (possibly because we killed it), + * and we need to restart it after timeout seconds. */ if (theSigchld) { theSigchld = 0; - waited = wait3(&status, 0, NULL); - if (waited < 0) continue; - /* now, we need to kill any children of pppd still in pppd's + /* Find its pid, which is also its process group ID. */ + waited = waitpid(-1, &status, 0); + if (waited == -1) { + continue; + } + + /* Now, we need to kill any children of pppd still in pppd's * process group, in case they are hanging around. * pppd is dead (we just waited for it) but there is no * guarantee that its children are dead, and they will * hold the modem if we do not get rid of them. - * We have kept the old pid/pgrp around in pppdPid. - */ + * We have kept the old pid/pgrp around in pppdPid. */ if (pppdPid) { kill(-pppdPid, SIGTERM); /* give it a chance to die nicely */ usleep(2500000); @@ -607,52 +691,69 @@ main(int argc, char **argv) { } pppdPid = 0; - if (!WIFEXITED(status)) cleanExit(29); - if (dieing) cleanExit(WEXITSTATUS(status)); + /* Bail if the child exitted abnormally or we were already + * signalled to kill it. */ + if (!WIFEXITED(status)) { + failureExit(29); + } + if (dying) { + failureExit(WEXITSTATUS(status)); + } - /* error conditions from which we do not expect to recover - * without user intervention -- do not fill up the logs. - */ + /* Error conditions from which we do not expect to recover + * without user intervention -- do not fill up the logs. */ switch (WEXITSTATUS(status)) { case 1: case 2: case 3: case 4: case 6: case 7: case 9: case 14: case 17: - cleanExit(WEXITSTATUS(status)); + failureExit(WEXITSTATUS(status)); break; default: break; } - /* We default to retrying the connect phase for backward compatibility. */ - if ((WEXITSTATUS(status) == 8) && !svTrueValue(ifcfg, "RETRYCONNECT", 1)) { - cleanExit(WEXITSTATUS(status)); + /* We default to retrying the connect phase for backward + * compatibility, unless RETRYCONNECT is false. */ + if ((WEXITSTATUS(status) == 8) && + !svTrueValue(ifcfg, "RETRYCONNECT", TRUE)) { + failureExit(WEXITSTATUS(status)); } + /* If we've never connected, or PERSIST is set, dial again, up + * to MAXFAIL times. */ if ((WEXITSTATUS(status) == 8) || - !connectedOnce || svTrueValue(ifcfg, "PERSIST", 0)) { - if (!connectedOnce) { - temp = svGetValue(ifcfg, "RETRYTIMEOUT"); - if (temp) { - timeout = atoi(temp); - free(temp); - } else { - timeout = 30; - } - - } else { - connectedOnce = 0; - temp = svGetValue(ifcfg, "DISCONNECTTIMEOUT"); - if (temp) { - timeout = atoi(temp); - free(temp); - } else { - timeout = 2; - } - } - sigprocmask(SIG_UNBLOCK, &blockedsigs, NULL); - sleep(timeout); - sigprocmask(SIG_BLOCK, &blockedsigs, NULL); - if (!theSigterm && !theSighup && !theSigio && !theSigchld && !theSigalrm) - fork_exec(0, "/etc/sysconfig/network-scripts/ifup-ppp", "daemon", device, theBoot); + !connectedOnce || + svTrueValue(ifcfg, "PERSIST", FALSE)) { + /* If we've been connected (i.e., if we didn't force a redial, + * but the connection went down) wait for DISCONNECTTIMEOUT + * seconds before redialing. */ + if (connectedOnce) { + connectedOnce = FALSE; + temp = svGetValue(ifcfg, "DISCONNECTTIMEOUT"); + if (temp) { + timeout = atoi(temp); + free(temp); + } else { + timeout = 2; + } + } + sigprocmask(SIG_UNBLOCK, &blockedsigs, NULL); + sleep(timeout); + sigprocmask(SIG_BLOCK, &blockedsigs, NULL); + if (!theSigterm && + !theSighup && + !theSigio && + !theSigchld && + !theSigalrm) { + fork_exec(FALSE, IFUP_PPP, "daemon", device, boot); + } + /* Reinitialize the retry timeout. */ + temp = svGetValue(ifcfg, "RETRYTIMEOUT"); + if (temp) { + timeout = atoi(temp); + free(temp); + } else { + timeout = 30; + } // Scott Sharkey <ssharkey@linux-no-limits.com> // MAXFAIL Patch... temp = svGetValue(ifcfg, "MAXFAIL"); @@ -665,20 +766,21 @@ main(int argc, char **argv) { if ( maxfail != 0 ) { dialCount++; if ( dialCount < maxfail ) { - fork_exec(0, "/etc/sysconfig/network-scripts/ifup-ppp", "daemon", device, theBoot); + fork_exec(FALSE, IFUP_PPP, "daemon", device, boot); } else { - cleanExit(WEXITSTATUS(status)); + failureExit(WEXITSTATUS(status)); } } else { - fork_exec(0, "/etc/sysconfig/network-scripts/ifup-ppp", "daemon", device, theBoot); + fork_exec(FALSE, IFUP_PPP, "daemon", device, boot); } } else { - cleanExit(WEXITSTATUS(status)); + failureExit(WEXITSTATUS(status)); } } + /* We timed out, and we're running at boot-time. */ if (theSigalrm) { - detach(1, 34, NULL); + failureExit(34); } } } |