diff -Naur net-scripts-0.4.9.1/src/ppp-watch.c net-scripts-0.4.9.1-lvu/src/ppp-watch.c --- net-scripts-0.4.9.1/src/ppp-watch.c 2001-03-05 02:22:06 +0200 +++ net-scripts-0.4.9.1-lvu/src/ppp-watch.c 2005-11-04 09:18:05 +0200 @@ -75,6 +75,7 @@ #include #include #include +#include #include "shvar.h" #include "alloc.h" @@ -116,6 +117,104 @@ } +// Returns pid of pppd (must be /usr/sbin/pppd) process that has +// "linkname device" in its command line. 0 if not found, -1 on error. +static int +get_pppd_pid(char *device) { + int i; + glob_t globbuf; + int ge = glob("/proc/*/cmdline", 0, NULL, &globbuf); + if (!ge) { + for (i = 0; i < globbuf.gl_pathc; ++i) { + FILE *fcmdline; + char cmdline[1024]; // hope this will be enough + if (fcmdline = fopen(globbuf.gl_pathv[i], "r")) { + int num_read; + num_read = fread(cmdline, 1, 1024, fcmdline); + if (num_read > 0 && !strcmp(cmdline, "/usr/sbin/pppd")) { + int prev_linkname = 0; + char *p = cmdline; + while (*p && p - cmdline < 1024) { + if (prev_linkname && !strcmp(p, device)) { + int retval; + globbuf.gl_pathv[i][strlen(globbuf.gl_pathv[i])-8] = 0; + retval = atoi(globbuf.gl_pathv[i]+6); + globfree(&globbuf); + fclose(fcmdline); + return retval; + } + prev_linkname = !strcmp(p, "linkname"); + p += strlen(p) + 1; + } + } + fclose(fcmdline); + } + } + globfree(&globbuf); + return 0; + } + else + return -1; +} + +// If there exists only one child of specified process, returns its pid. +// Otherwise (if no children or more than 1) returns 0. -1 on error. +static int get_only_child(int parent_pid) { + int i; + glob_t globbuf; + int ge = glob("/proc/*/status", 0, NULL, &globbuf); + if (!ge) { + int result_pid = 0; + for (i = 0; i < globbuf.gl_pathc; ++i) { + FILE *fstatus; + char status[1024]; // hope this will be enough + if (fstatus = fopen(globbuf.gl_pathv[i], "r")) { + int num_read; + num_read = fread(status, 1, 1023, fstatus); + if (num_read > 0) { + char *ppid_pos; + status[num_read] = 0; + ppid_pos = strstr(status, "PPid:\t"); + if (ppid_pos) + { + int cur_ppid = atoi(ppid_pos+6); + if (cur_ppid == parent_pid) + { + // Heuristics: we look only for those chldren + // which have non-empty commandline + char cmdline[256], *p; + FILE *fcmdline; + strcpy(cmdline, globbuf.gl_pathv[i]); + for(p=cmdline+strlen(cmdline); *p!='/' && p>=cmdline; --p); + ++p; + strcpy(p, "cmdline"); + if (!(fcmdline = fopen(cmdline, "r")) + || !fread(cmdline, 1, 256, fcmdline)) + { + fclose(fstatus); + continue; + } + fclose(fcmdline); + if (result_pid) + { + globfree(&globbuf); + fclose(fstatus); + return 0; + } + else + result_pid = atoi(globbuf.gl_pathv[i]+6); + } + } + } + fclose(fstatus); + } + } + globfree(&globbuf); + return result_pid; + } + else + return -1; +} static void detach(int now, int parentExitCode, char *device) { @@ -541,6 +640,7 @@ sigsuspend(&unblockedsigs); if (theSigterm || theSigint) { + int proc_pppd_pid, chat_pid, i; theSigterm = theSigint = 0; if (dieing) sendsig = SIGKILL; @@ -550,6 +650,28 @@ if (physicalDevice) { free(physicalDevice); physicalDevice = NULL; } physicalDevice = pppLogicalToPhysical(&pppdPid, real_device); if (physicalDevice) { free(physicalDevice); physicalDevice = NULL; } + // We suspect that pppd is running, but haven't created + // .pid file yet. Keep waiting for .pid file and try + // to find chat or whatever pppd uses + // to establish connection. + for (i=0; !pppdPid && (proc_pppd_pid = get_pppd_pid(device)) + && !(chat_pid = get_only_child(proc_pppd_pid)) + && i<60000; + ++i) + { + physicalDevice = pppLogicalToPhysical(&pppdPid, real_device); + if (physicalDevice) { free(physicalDevice); physicalDevice = NULL; } + usleep(1000); + } + if (pppdPid) + sleep(2); // Else pppd may hangup, seems there's a bug in it + else + if (chat_pid) + { + // Found chat or whatever. + // Let's kill it instead of pppd. + pppdPid = chat_pid; + } if (!pppdPid) cleanExit(35); kill(pppdPid, sendsig); if (sendsig == SIGKILL) { @@ -617,7 +739,9 @@ pppdPid = 0; if (!WIFEXITED(status)) cleanExit(29); - if (dieing) cleanExit(WEXITSTATUS(status)); + // We want to know if user terminated dialing, even if it was + // during execution of connect script. + if (dieing) cleanExit(WEXITSTATUS(status)==8?5:WEXITSTATUS(status)); /* error conditions from which we do not expect to recover * without user intervention -- do not fill up the logs.