X-Git-Url: http://git.ozlabs.org/?a=blobdiff_plain;f=pppd%2Fmain.c;h=cad0fa3b44a0668ebaadcec1a7d640561eabcfd4;hb=5018cc2da57e555b620750f33dce6b1c964e612a;hp=4a4e14b010cbbf23559380017c7bdf48561bebd8;hpb=5ba9d88b943e9d5a3ababdadf1d2e246581dfdc6;p=ppp.git diff --git a/pppd/main.c b/pppd/main.c index 4a4e14b..cad0fa3 100644 --- a/pppd/main.c +++ b/pppd/main.c @@ -18,7 +18,7 @@ */ #ifndef lint -static char rcsid[] = "$Id: main.c,v 1.64 1999/03/22 05:55:31 paulus Exp $"; +static char rcsid[] = "$Id: main.c,v 1.73 1999/04/01 07:19:59 paulus Exp $"; #endif #include @@ -90,7 +90,7 @@ int need_holdoff; /* need holdoff period before restarting */ int detached; /* have detached from terminal */ int log_to_fd; /* send log messages to this fd too */ -static int fd_ppp; /* fd for talking PPP */ +static int fd_ppp = -1; /* fd for talking PPP */ static int fd_loop; /* fd for getting demand-dial packets */ static int pty_master; /* fd for master side of pty */ static int pty_slave; /* fd for slave side of pty */ @@ -110,6 +110,7 @@ u_char outpacket_buf[PPP_MRU+PPP_HDRLEN]; /* buffer for outgoing packet */ u_char inpacket_buf[PPP_MRU+PPP_HDRLEN]; /* buffer for incoming packet */ static int n_children; /* # child processes still running */ +static int got_sigchld; /* set if we have received a SIGCHLD */ static int locked; /* lock() has succeeded */ @@ -124,7 +125,6 @@ struct pppd_stats link_stats; int link_stats_valid; static int charshunt_pid; /* Process ID for charshunt */ -static FILE *recordf; /* File for recording chars sent/rcvd */ /* Prototypes for procedures local to this file. */ @@ -142,7 +142,7 @@ static void toggle_debug __P((int)); static void open_ccp __P((int)); static void bad_signal __P((int)); static void holdoff_end __P((void *)); -static int device_script __P((char *, int, int)); +static int device_script __P((char *, int, int, int)); static void reap_kids __P((int waitfor)); static void pr_log __P((void *, char *, ...)); static void logit __P((int, char *, va_list)); @@ -150,9 +150,11 @@ static void vslp_printer __P((void *, char *, ...)); static void format_packet __P((u_char *, int, void (*) (void *, char *, ...), void *)); static void record_child __P((int, char *, void (*) (void *), void *)); -static void charshunt __P((int)); -static int record_write(FILE *, int code, u_char *buf, int nb, - struct timeval *); +static int start_charshunt __P((int, int)); +static void charshunt_done __P((void *)); +static void charshunt __P((int, int, char *)); +static int record_write __P((FILE *, int code, u_char *buf, int nb, + struct timeval *)); extern char *ttyname __P((int)); extern char *getlogin __P((void)); @@ -212,12 +214,7 @@ main(argc, argv) script_env = NULL; /* Initialize syslog facilities */ -#ifdef ULTRIX - openlog("pppd", LOG_PID); -#else - openlog("pppd", LOG_PID | LOG_NDELAY, LOG_PPP); - setlogmask(LOG_UPTO(LOG_INFO)); -#endif + reopen_log(); if (gethostname(hostname, MAXNAMELEN) < 0 ) { option_error("Couldn't get hostname: %m"); @@ -245,7 +242,25 @@ main(argc, argv) if (!options_from_file(_PATH_SYSOPTIONS, !privileged, 0, 1) || !options_from_user()) exit(1); + using_pty = notty || ptycommand != NULL; scan_args(argc-1, argv+1); /* look for tty name on command line */ + + /* + * Work out the device name, if it hasn't already been specified. + */ + if (!using_pty) { + p = isatty(0)? ttyname(0): NULL; + if (p != NULL) { + if (default_device) + strlcpy(devnam, p, sizeof(devnam)); + else if (strcmp(devnam, p) == 0) + default_device = 1; + } + } + + /* + * Parse the tty options file and the command line. + */ if (!options_for_tty() || !parse_args(argc-1, argv+1)) exit(1); @@ -278,36 +293,23 @@ main(argc, argv) exit(1); } - if (ptycommand != NULL || notty) { + if (using_pty) { if (!default_device) { option_error("%s option precludes specifying device name", notty? "notty": "pty"); exit(1); } - if (ptycommand != NULL && (notty || record_file != NULL)) { - option_error("pty option is incompatible with %s option", - notty? "notty": "record"); + if (ptycommand != NULL && notty) { + option_error("pty option is incompatible with notty option"); exit(1); } default_device = notty; lockflag = 0; modem = 0; } else { - /* - * If the user has specified the default device name explicitly, - * pretend they hadn't. - */ - p = isatty(0)? ttyname(0): NULL; - if (p == NULL) { - if (default_device) { - option_error("no device specified and stdin is not a tty"); - exit(1); - } - } else { - if (default_device) - strlcpy(devnam, p, sizeof(devnam)); - else if (strcmp(devnam, p) == 0) - default_device = 1; + if (devnam[0] == 0) { + option_error("no device specified and stdin is not a tty"); + exit(1); } } if (default_device) @@ -316,21 +318,6 @@ main(argc, argv) log_to_fd = 1; /* default to stdout */ script_setenv("DEVICE", devnam); - slprintf(numbuf, sizeof(numbuf), "%d", baud_rate); - script_setenv("SPEED", numbuf); - - /* - * Open the record file (as the user) if required. - */ - if (record_file != NULL) { - if (uid != 0) - seteuid(uid); - recordf = fopen(record_file, "a"); - if (uid != 0) - seteuid(0); - if (recordf == NULL) - option_error("Couldn't create record file %s: %m", record_file); - } /* * Initialize system-dependent stuff and magic number package. @@ -489,7 +476,8 @@ main(argc, argv) } if (get_loop_output()) break; - reap_kids(0); + if (got_sigchld) + reap_kids(0); } remove_fd(fd_loop); if (kill_link && !persist) @@ -515,13 +503,6 @@ main(argc, argv) goto fail; } set_up_tty(pty_slave, 1); - if (ptycommand != NULL) { - if (device_script(ptycommand, pty_master, 1) < 0) - goto fail; - ttyfd = pty_slave; - close(pty_master); - pty_master = -1; - } } /* @@ -546,10 +527,10 @@ main(argc, argv) for (;;) { /* If the user specified the device name, become the user before opening it. */ - if (!devnam_info.priv) + if (!devnam_info.priv && !default_device) seteuid(uid); ttyfd = open(devnam, O_NONBLOCK | O_RDWR, 0); - if (!devnam_info.priv) + if (!devnam_info.priv && !default_device) seteuid(0); if (ttyfd >= 0) break; @@ -589,30 +570,33 @@ main(argc, argv) * If the notty and/or record option was specified, * start up the character shunt now. */ - if (notty || record_file != NULL) { - int cpid; - - cpid = fork(); - if (cpid == -1) { - error("Can't fork process for character shunt: %m"); - goto fail; - } - if (cpid == 0) { - close(pty_slave); - setuid(uid); - if (getuid() != uid) - fatal("setuid failed"); - setgid(getgid()); - charshunt(ttyfd); - exit(0); + if (ptycommand != NULL) { + if (record_file != NULL) { + int ipipe[2], opipe[2], ok; + + if (pipe(ipipe) < 0 || pipe(opipe) < 0) + fatal("Couldn't create pipes for record option: %m"); + ok = device_script(ptycommand, opipe[0], ipipe[1], 1) == 0 + && start_charshunt(ipipe[0], opipe[1]); + close(ipipe[0]); + close(ipipe[1]); + close(opipe[0]); + close(opipe[1]); + if (!ok) + goto fail; + } else { + if (device_script(ptycommand, pty_master, pty_master, 1) < 0) + goto fail; + ttyfd = pty_slave; + close(pty_master); + pty_master = -1; } - charshunt_pid = cpid; - close(pty_master); - pty_master = -1; - if (ttyfd >= 0) - close(ttyfd); - ttyfd = pty_slave; - record_child(cpid, "pppd (charshunt)", NULL, NULL); + } else if (notty) { + if (!start_charshunt(0, 1)) + goto fail; + } else if (record_file != NULL) { + if (!start_charshunt(ttyfd, ttyfd)) + goto fail; } /* run connection script */ @@ -627,10 +611,12 @@ main(argc, argv) } } - if (device_script(connector, ttyfd, 0) < 0) { + if (device_script(connector, ttyfd, ttyfd, 0) < 0) { error("Connect script failed"); goto fail; } + if (kill_link) + goto disconnect; info("Serial connection established."); @@ -653,16 +639,19 @@ main(argc, argv) close(i); } + slprintf(numbuf, sizeof(numbuf), "%d", baud_rate); + script_setenv("SPEED", numbuf); + /* run welcome script, if any */ if (welcomer && welcomer[0]) { - if (device_script(welcomer, ttyfd, 0) < 0) + if (device_script(welcomer, ttyfd, ttyfd, 0) < 0) warn("Welcome script failed"); } /* set up the serial device as a ppp interface */ fd_ppp = establish_ppp(ttyfd); if (fd_ppp < 0) - goto fail; + goto disconnect; if (!demand) { @@ -721,7 +710,8 @@ main(argc, argv) } open_ccp_flag = 0; } - reap_kids(0); /* Don't leave dead kids lying around */ + if (got_sigchld) + reap_kids(0); /* Don't leave dead kids lying around */ } /* @@ -747,28 +737,31 @@ main(argc, argv) if (demand) restore_loop(); disestablish_ppp(ttyfd); + fd_ppp = -1; + if (!hungup) + lcp_lowerdown(0); /* * Run disconnector script, if requested. * XXX we may not be able to do this if the line has hung up! */ + disconnect: if (disconnector && !hungup) { - set_up_tty(ttyfd, 1); - if (device_script(disconnector, ttyfd, 0) < 0) { + if (real_ttyfd >= 0) + set_up_tty(real_ttyfd, 1); + if (device_script(disconnector, ttyfd, ttyfd, 0) < 0) { warn("disconnect script failed"); } else { info("Serial link disconnected."); } } - if (!hungup) - lcp_lowerdown(0); fail: if (pty_master >= 0) close(pty_master); - if (pty_slave >= 0 && pty_slave != ttyfd) + if (pty_slave >= 0) close(pty_slave); - if (ttyfd >= 0) + if (real_ttyfd >= 0) close_tty(); if (locked) { unlock(); @@ -808,7 +801,8 @@ main(argc, argv) kill_link = 0; phase = PHASE_DORMANT; /* allow signal to end holdoff */ } - reap_kids(0); + if (got_sigchld) + reap_kids(0); } while (phase == PHASE_HOLDOFF); if (!persist) break; @@ -843,6 +837,20 @@ detach() create_pidfile(); } +/* + * reopen_log - (re)open our connection to syslog. + */ +void +reopen_log() +{ +#ifdef ULTRIX + openlog("pppd", LOG_PID); +#else + openlog("pppd", LOG_PID | LOG_NDELAY, LOG_PPP); + setlogmask(LOG_UPTO(LOG_INFO)); +#endif +} + /* * Create a file containing our process ID. */ @@ -974,7 +982,9 @@ cleanup() { sys_cleanup(); - if (ttyfd >= 0) + if (fd_ppp >= 0) + disestablish_ppp(ttyfd); + if (real_ttyfd >= 0) close_tty(); if (pidfilename[0] != 0 && unlink(pidfilename) < 0 && errno != ENOENT) @@ -991,11 +1001,9 @@ cleanup() static void close_tty() { - disestablish_ppp(ttyfd); - /* drop dtr to hang up */ if (!default_device && modem) { - setdtr(ttyfd, 0); + setdtr(real_ttyfd, 0); /* * This sleep is in case the serial port has CLOCAL set by default, * and consequently will reassert DTR when we close the device. @@ -1003,17 +1011,17 @@ close_tty() sleep(1); } - restore_tty(ttyfd); + restore_tty(real_ttyfd); if (tty_mode != (mode_t) -1) { - if (fchmod(ttyfd, tty_mode) != 0) { + if (fchmod(real_ttyfd, tty_mode) != 0) { /* XXX if devnam is a symlink, this will change the link */ chmod(devnam, tty_mode); } } - close(ttyfd); - ttyfd = -1; + close(real_ttyfd); + real_ttyfd = -1; } @@ -1206,12 +1214,13 @@ term(sig) /* * chld - Catch SIGCHLD signal. - * Calls reap_kids to get status for any dead kids. + * Sets a flag so we will call reap_kids in the mainline. */ static void chld(sig) int sig; { + got_sigchld = 1; if (waiting) siglongjmp(sigjmp, 1); } @@ -1274,17 +1283,17 @@ bad_signal(sig) /* - * device_script - run a program to connect or disconnect the - * serial device. + * device_script - run a program to talk to the serial device + * (e.g. to run the connector or disconnector script). */ static int -device_script(program, inout, dont_wait) +device_script(program, in, out, dont_wait) char *program; - int inout; + int in, out; int dont_wait; { int pid; - int status = 0; + int status = -1; int errfd; ++conn_running; @@ -1299,11 +1308,14 @@ device_script(program, inout, dont_wait) if (pid == 0) { sys_close(); closelog(); - if (inout == 2) { + if (in == 2) { /* aargh!!! */ - int newio = dup(inout); - close(inout); - inout = newio; + int newin = dup(in); + if (in == out) + out = newin; + in = newin; + } else if (out == 2) { + out = dup(out); } if (log_to_fd >= 0) { if (log_to_fd != 2) @@ -1316,18 +1328,25 @@ device_script(program, inout, dont_wait) close(errfd); } } - if (inout != 0) { - dup2(inout, 0); - close(inout); + if (in != 0) { + if (out == 0) + out = dup(out); + dup2(in, 0); + } + if (out != 1) { + dup2(out, 1); } - dup2(0, 1); + if (real_ttyfd > 2) + close(real_ttyfd); + if (pty_master > 2) + close(pty_master); + if (pty_slave > 2) + close(pty_slave); setuid(uid); if (getuid() != uid) { error("setuid failed"); exit(1); } - if (ttyfd > 2 && ttyfd != inout) - close(ttyfd); setgid(getgid()); execl("/bin/sh", "sh", "-c", program, (char *)0); error("could not exec /bin/sh: %m"); @@ -1337,6 +1356,7 @@ device_script(program, inout, dont_wait) if (dont_wait) { record_child(pid, program, NULL, NULL); + status = 0; } else { while (waitpid(pid, &status, 0) < 0) { if (errno == EINTR) @@ -1421,6 +1441,8 @@ run_program(prog, args, must_exist, done, arg) close (1); close (2); close (ttyfd); /* tty interface to the ppp device */ + if (real_ttyfd >= 0) + close(real_ttyfd); /* Don't pass handles to the PPP device, even by accident. */ new_fd = open (_PATH_DEVNULL, O_RDWR); @@ -1446,12 +1468,7 @@ run_program(prog, args, must_exist, done, arg) if (must_exist || errno != ENOENT) { /* have to reopen the log, there's nowhere else for the message to go. */ -#ifdef ULTRIX - openlog("pppd", LOG_PID); -#else - openlog("pppd", LOG_PID | LOG_NDELAY, LOG_PPP); - setlogmask(LOG_UPTO(LOG_INFO)); -#endif + reopen_log(); syslog(LOG_ERR, "Can't execute %s: %m", prog); closelog(); } @@ -1506,6 +1523,7 @@ reap_kids(waitfor) int pid, status; struct subprocess *chp, **prevp; + got_sigchld = 0; if (n_children == 0) return; while ((pid = waitpid(-1, &status, (waitfor? 0: WNOHANG))) != -1 @@ -1518,8 +1536,8 @@ reap_kids(waitfor) warn("Child process %s (pid %d) terminated with signal %d", (chp? chp->prog: "??"), pid, WTERMSIG(status)); } else if (debug) - dbglog("process %d (%s) finished, status = 0x%x", - pid, (chp? chp->prog: "??"), status); + dbglog("Script %s finished (pid %d), status = 0x%x", + (chp? chp->prog: "??"), pid, status); if (chp && chp->done) (*chp->done)(chp->arg); } @@ -2240,28 +2258,71 @@ dbglog __V((char *fmt, ...)) va_end(pvar); } +/* + * start_charshunt - create a child process to run the character shunt. + */ +static int +start_charshunt(ifd, ofd) + int ifd, ofd; +{ + int cpid; + + cpid = fork(); + if (cpid == -1) { + error("Can't fork process for character shunt: %m"); + return 0; + } + if (cpid == 0) { + /* child */ + close(pty_slave); + setuid(uid); + if (getuid() != uid) + fatal("setuid failed"); + setgid(getgid()); + if (!nodetach) + log_to_fd = -1; + charshunt(ifd, ofd, record_file); + exit(0); + } + charshunt_pid = cpid; + close(pty_master); + pty_master = -1; + ttyfd = pty_slave; + record_child(cpid, "pppd (charshunt)", charshunt_done, NULL); + return 1; +} + +static void +charshunt_done(arg) + void *arg; +{ + charshunt_pid = 0; +} + /* * charshunt - the character shunt, which passes characters between * the pty master side and the serial port (or stdin/stdout). * This runs as the user (not as root). + * (We assume ofd >= ifd which is true the way this gets called. :-). */ static void -charshunt(ttyfd) - int ttyfd; +charshunt(ifd, ofd, record_file) + int ifd, ofd; + char *record_file; { - int ifd, ofd, nfds; - int n; + int n, nfds; fd_set ready, writey; u_char *ibufp, *obufp; int nibuf, nobuf; int flags; int pty_readable, stdin_readable; struct timeval lasttime; + FILE *recordf = NULL; /* * Reset signal handlers. */ - signal(SIGHUP, SIG_DFL); /* Hangup */ + signal(SIGHUP, SIG_IGN); /* Hangup */ signal(SIGINT, SIG_DFL); /* Interrupt */ signal(SIGTERM, SIG_DFL); /* Terminate */ signal(SIGCHLD, SIG_DFL); @@ -2302,14 +2363,14 @@ charshunt(ttyfd) signal(SIGXFSZ, SIG_DFL); #endif - /* work out which fds we're using. */ - if (notty) { - ifd = 0; - ofd = 1; - } else { - ifd = ofd = ttyfd; + /* + * Open the record file if required. + */ + if (record_file != NULL) { + recordf = fopen(record_file, "a"); + if (recordf == NULL) + error("Couldn't create record file %s: %m", record_file); } - nfds = (ofd > pty_master? ifd: pty_master) + 1; /* set all the fds to non-blocking mode */ flags = fcntl(pty_master, F_GETFL); @@ -2319,8 +2380,8 @@ charshunt(ttyfd) flags = fcntl(ifd, F_GETFL); if (flags == -1 || fcntl(ifd, F_SETFL, flags | O_NONBLOCK) == -1) - warn("couldn't set %s to nonblock: %m", (notty? "stdin": "tty")); - if (notty) { + warn("couldn't set %s to nonblock: %m", (ifd==0? "stdin": "tty")); + if (ofd != ifd) { flags = fcntl(ofd, F_GETFL); if (flags == -1 || fcntl(ofd, F_SETFL, flags | O_NONBLOCK) == -1) @@ -2330,7 +2391,17 @@ charshunt(ttyfd) nibuf = nobuf = 0; ibufp = obufp = NULL; pty_readable = stdin_readable = 1; - gettimeofday(&lasttime, NULL); + nfds = (ofd > pty_master? ofd: pty_master) + 1; + if (recordf != NULL) { + gettimeofday(&lasttime, NULL); + putc(7, recordf); /* put start marker */ + putc(lasttime.tv_sec >> 24, recordf); + putc(lasttime.tv_sec >> 16, recordf); + putc(lasttime.tv_sec >> 8, recordf); + putc(lasttime.tv_sec, recordf); + lasttime.tv_usec = 0; + } + while (nibuf != 0 || nobuf != 0 || pty_readable || stdin_readable) { FD_ZERO(&ready); FD_ZERO(&writey); @@ -2445,8 +2516,8 @@ record_write(f, code, buf, nb, tp) int diff; gettimeofday(&now, NULL); - diff = (now.tv_sec - tp->tv_sec) * 10 - + (now.tv_usec - tp->tv_usec) / 100000; + now.tv_usec /= 100000; /* actually 1/10 s, not usec now */ + diff = (now.tv_sec - tp->tv_sec) * 10 + (now.tv_usec - tp->tv_usec); if (diff > 0) { if (diff > 255) { putc(5, f);