X-Git-Url: http://git.ozlabs.org/?p=ppp.git;a=blobdiff_plain;f=pppd%2Fmain.c;h=6541a3be3c472d208f43059ba8f74e3f88431425;hp=3d4c16acbad4db134f3ed5ea76eee7174327454d;hb=215baf28fc53e909b987a4b31d7d25ecd4ee7a71;hpb=52a17b6d41d64d0502a73e5b4224546360581b49 diff --git a/pppd/main.c b/pppd/main.c index 3d4c16a..6541a3b 100644 --- a/pppd/main.c +++ b/pppd/main.c @@ -17,7 +17,7 @@ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. */ -#define RCSID "$Id: main.c,v 1.99 2000/06/30 04:54:20 paulus Exp $" +#define RCSID "$Id: main.c,v 1.109 2002/01/11 18:10:16 etbe Exp $" #include #include @@ -54,7 +54,6 @@ #include "chap.h" #include "ccp.h" #include "pathnames.h" -#include "patchlevel.h" #include "tdb.h" #ifdef CBCP_SUPPORT @@ -74,6 +73,8 @@ static const char rcsid[] = RCSID; char ifname[32]; /* Interface name */ int ifunit; /* Interface unit number */ +struct channel *the_channel; + char *progname; /* Name of this program */ char hostname[MAXNAMELEN]; /* Our hostname */ static char pidfilename[MAXPATHLEN]; /* name of pid file */ @@ -89,7 +90,6 @@ int hungup; /* terminal has been hung up */ int privileged; /* we're running as real uid root */ int need_holdoff; /* need holdoff period before restarting */ int detached; /* have detached from terminal */ -struct stat devstat; /* result of stat() on devnam */ volatile int status; /* exit status for pppd */ int unsuccess; /* # unsuccessful connection attempts */ int do_callback; /* != 0 if we should do callback next */ @@ -108,6 +108,10 @@ static int fd_loop; /* fd for getting demand-dial packets */ int phase; /* where the link is at */ int kill_link; int open_ccp_flag; +int listen_time; +int got_sigusr2; +int got_sigterm; +int got_sighup; static int waiting; static sigjmp_buf sigjmp; @@ -170,6 +174,8 @@ static void update_db_entry __P((void)); static void add_db_key __P((const char *)); static void delete_db_key __P((const char *)); static void cleanup_db __P((void)); +static void handle_events __P((void)); +static void print_link_stats __P((void)); extern char *ttyname __P((int)); extern char *getlogin __P((void)); @@ -222,15 +228,13 @@ main(argc, argv) int argc; char *argv[]; { - int i, fdflags, t; + int i, t; char *p; struct passwd *pw; - struct timeval timo; - sigset_t mask; struct protent *protp; - struct stat statbuf; char numbuf[16]; + link_stats_valid = 0; new_phase(PHASE_INITIALIZE); /* @@ -278,39 +282,32 @@ main(argc, argv) for (i = 0; (protp = protocols[i]) != NULL; ++i) (*protp->init)(0); + /* + * Initialize the default channel. + */ + tty_init(); + progname = *argv; /* * Parse, in order, the system options file, the user's options file, - * the tty's options file, and the command line arguments. + * and the command line arguments. */ if (!options_from_file(_PATH_SYSOPTIONS, !privileged, 0, 1) || !options_from_user() || !parse_args(argc-1, argv+1)) exit(EXIT_OPTION_ERROR); + devnam_fixed = 1; /* can no longer change device name */ /* - * Work out the device name, if it hasn't already been specified. + * Work out the device name, if it hasn't already been specified, + * and parse the tty's options file. */ - using_pty = notty || ptycommand != NULL || pty_socket != NULL; - if (!using_pty && default_device) { - char *p; - if (!isatty(0) || (p = ttyname(0)) == NULL) { - option_error("no device specified and stdin is not a tty"); - exit(EXIT_OPTION_ERROR); - } - strlcpy(devnam, p, sizeof(devnam)); - if (stat(devnam, &devstat) < 0) - fatal("Couldn't stat default device %s: %m", devnam); - } + if (the_channel->process_extra_options) + (*the_channel->process_extra_options)(); - /* - * Parse the tty options file. - * The per-tty options file should not change - * ptycommand, pty_socket, notty or devnam. - */ - if (!using_pty && !options_for_tty()) - exit(EXIT_OPTION_ERROR); + if (debug) + setlogmask(LOG_UPTO(LOG_DEBUG)); /* * Check that we are running as root. @@ -322,13 +319,14 @@ main(argc, argv) } if (!ppp_available()) { - option_error(no_ppp_msg); + option_error("%s", no_ppp_msg); exit(EXIT_NO_KERNEL_SUPPORT); } /* * Check that the options given are valid and consistent. */ + check_options(); if (!sys_check_options()) exit(EXIT_OPTION_ERROR); auth_check_options(); @@ -338,65 +336,22 @@ main(argc, argv) for (i = 0; (protp = protocols[i]) != NULL; ++i) if (protp->check_options != NULL) (*protp->check_options)(); - if (demand && connect_script == 0) { - option_error("connect script is required for demand-dialling\n"); - exit(EXIT_OPTION_ERROR); - } - /* default holdoff to 0 if no connect script has been given */ - if (connect_script == 0 && !holdoff_specified) - holdoff = 0; - - if (using_pty) { - if (!default_device) { - option_error("%s option precludes specifying device name", - notty? "notty": "pty"); - exit(EXIT_OPTION_ERROR); - } - if (ptycommand != NULL && notty) { - option_error("pty option is incompatible with notty option"); - exit(EXIT_OPTION_ERROR); - } - if (pty_socket != NULL && (ptycommand != NULL || notty)) { - option_error("socket option is incompatible with pty and notty"); - exit(EXIT_OPTION_ERROR); - } - default_device = notty; - lockflag = 0; - modem = 0; - if (notty && log_to_fd <= 1) - log_to_fd = -1; - } else { - /* - * If the user has specified a device which is the same as - * the one on stdin, pretend they didn't specify any. - * If the device is already open read/write on stdin, - * we assume we don't need to lock it, and we can open it as root. - */ - if (fstat(0, &statbuf) >= 0 && S_ISCHR(statbuf.st_mode) - && statbuf.st_rdev == devstat.st_rdev) { - default_device = 1; - fdflags = fcntl(0, F_GETFL); - if (fdflags != -1 && (fdflags & O_ACCMODE) == O_RDWR) - privopen = 1; - } - } - if (default_device) - nodetach = 1; + if (the_channel->check_options) + (*the_channel->check_options)(); - /* - * Don't send log messages to the serial port, it tends to - * confuse the peer. :-) - */ - if (log_to_fd >= 0 && fstat(log_to_fd, &statbuf) >= 0 - && S_ISCHR(statbuf.st_mode) && statbuf.st_rdev == devstat.st_rdev) - log_to_fd = -1; + + if (dump_options || dryrun) { + init_pr_log(NULL, LOG_INFO); + print_options(pr_log, NULL); + end_pr_log(); + if (dryrun) + die(0); + } /* * Initialize system-dependent stuff. */ sys_init(); - if (debug) - setlogmask(LOG_UPTO(LOG_DEBUG)); pppdb = tdb_open(_PATH_PPPDB, 0, 0, O_RDWR|O_CREAT, 0644); if (pppdb != NULL) { @@ -424,8 +379,7 @@ main(argc, argv) else p = "(unknown)"; } - syslog(LOG_NOTICE, "pppd %s.%d%s started by %s, uid %d", - VERSION, PATCHLEVEL, IMPLEMENTATION, p, uid); + syslog(LOG_NOTICE, "pppd %s started by %s, uid %d", VERSION, p, uid); script_setenv("PPPLOGNAME", p, 0); if (devnam[0]) @@ -460,6 +414,7 @@ main(argc, argv) do_callback = 0; for (;;) { + listen_time = 0; need_holdoff = 1; devfd = -1; status = EXIT_OK; @@ -471,32 +426,15 @@ main(argc, argv) /* * Don't do anything until we see some activity. */ - kill_link = 0; new_phase(PHASE_DORMANT); demand_unblock(); add_fd(fd_loop); for (;;) { - if (sigsetjmp(sigjmp, 1) == 0) { - sigprocmask(SIG_BLOCK, &mask, NULL); - if (kill_link || got_sigchld) { - sigprocmask(SIG_UNBLOCK, &mask, NULL); - } else { - waiting = 1; - sigprocmask(SIG_UNBLOCK, &mask, NULL); - wait_input(timeleft(&timo)); - } - } - waiting = 0; - calltimeout(); - if (kill_link) { - if (!persist) - break; - kill_link = 0; - } + handle_events(); + if (kill_link && !persist) + break; if (get_loop_output()) break; - if (got_sigchld) - reap_kids(0); } remove_fd(fd_loop); if (kill_link && !persist) @@ -511,13 +449,13 @@ main(argc, argv) new_phase(PHASE_SERIALCONN); - devfd = connect_tty(); + devfd = the_channel->connect(); if (devfd < 0) goto fail; /* set up the serial device as a ppp interface */ tdb_writelock(pppdb); - fd_ppp = establish_ppp(devfd); + fd_ppp = the_channel->establish_ppp(devfd); if (fd_ppp < 0) { tdb_writeunlock(pppdb); status = EXIT_FATAL_ERROR; @@ -532,71 +470,34 @@ main(argc, argv) * Start opening the connection and wait for * incoming events (reply, timeout, etc.). */ - notice("Connect: %s <--> %s", ifname, ppp_devnam); + if (ifunit >= 0) + notice("Connect: %s <--> %s", ifname, ppp_devnam); + else + notice("Starting negotiation on %s", ppp_devnam); gettimeofday(&start_time, NULL); - link_stats_valid = 0; script_unsetenv("CONNECT_TIME"); script_unsetenv("BYTES_SENT"); script_unsetenv("BYTES_RCVD"); lcp_lowerup(0); - /* - * If we are initiating this connection, wait for a short - * time for something from the peer. This can avoid bouncing - * our packets off his tty before he has it set up. - */ add_fd(fd_ppp); -#ifdef XXX - if (connect_delay != 0 && (connector != NULL || ptycommand != NULL)) { - struct timeval t; - t.tv_sec = connect_delay / 1000; - t.tv_usec = connect_delay % 1000; - wait_input(&t); - } -#endif - lcp_open(0); /* Start protocol */ - open_ccp_flag = 0; status = EXIT_NEGOTIATION_FAILED; new_phase(PHASE_ESTABLISH); while (phase != PHASE_DEAD) { - if (sigsetjmp(sigjmp, 1) == 0) { - sigprocmask(SIG_BLOCK, &mask, NULL); - if (kill_link || open_ccp_flag || got_sigchld) { - sigprocmask(SIG_UNBLOCK, &mask, NULL); - } else { - waiting = 1; - sigprocmask(SIG_UNBLOCK, &mask, NULL); - wait_input(timeleft(&timo)); - } - } - waiting = 0; - calltimeout(); + handle_events(); get_input(); - if (kill_link) { + if (kill_link) lcp_close(0, "User request"); - kill_link = 0; - } if (open_ccp_flag) { if (phase == PHASE_NETWORK || phase == PHASE_RUNNING) { ccp_fsm[0].flags = OPT_RESTART; /* clears OPT_SILENT */ (*ccp_protent.open)(0); } - open_ccp_flag = 0; } - if (got_sigchld) - reap_kids(0); /* Don't leave dead kids lying around */ } - /* - * Print connect time and statistics. - */ - if (link_stats_valid) { - int t = (link_connect_time + 5) / 6; /* 1/10ths of minutes */ - info("Connect time %d.%d minutes.", t/10, t%10); - info("Sent %d bytes, received %d bytes.", - link_stats.bytes_out, link_stats.bytes_in); - } + print_link_stats(); /* * Delete pid file before disestablishing ppp. Otherwise it @@ -605,7 +506,7 @@ main(argc, argv) */ if (!demand) { if (pidfilename[0] != 0 - && unlink(pidfilename) < 0 && errno != ENOENT) + && unlink(pidfilename) < 0 && errno != ENOENT) warn("unable to delete pid file %s: %m", pidfilename); pidfilename[0] = 0; } @@ -617,9 +518,7 @@ main(argc, argv) */ remove_fd(fd_ppp); clean_check(); - if (demand) - restore_loop(); - disestablish_ppp(devfd); + the_channel->disestablish_ppp(devfd); fd_ppp = -1; if (!hungup) lcp_lowerdown(0); @@ -632,14 +531,15 @@ main(argc, argv) */ disconnect: new_phase(PHASE_DISCONNECT); - disconnect_tty(); + the_channel->disconnect(); fail: - cleanup_tty(); + if (the_channel->cleanup) + (*the_channel->cleanup)(); if (!demand) { if (pidfilename[0] != 0 - && unlink(pidfilename) < 0 && errno != ENOENT) + && unlink(pidfilename) < 0 && errno != ENOENT) warn("unable to delete pid file %s: %m", pidfilename); pidfilename[0] = 0; } @@ -647,7 +547,6 @@ main(argc, argv) if (!persist || (maxfail > 0 && unsuccess >= maxfail)) break; - kill_link = 0; if (demand) demand_discard(); t = need_holdoff? holdoff: 0; @@ -657,24 +556,9 @@ main(argc, argv) new_phase(PHASE_HOLDOFF); TIMEOUT(holdoff_end, NULL, t); do { - if (sigsetjmp(sigjmp, 1) == 0) { - sigprocmask(SIG_BLOCK, &mask, NULL); - if (kill_link || got_sigchld) { - sigprocmask(SIG_UNBLOCK, &mask, NULL); - } else { - waiting = 1; - sigprocmask(SIG_UNBLOCK, &mask, NULL); - wait_input(timeleft(&timo)); - } - } - waiting = 0; - calltimeout(); - if (kill_link) { - kill_link = 0; + handle_events(); + if (kill_link) new_phase(PHASE_DORMANT); /* allow signal to end holdoff */ - } - if (got_sigchld) - reap_kids(0); } while (phase == PHASE_HOLDOFF); if (!persist) break; @@ -698,6 +582,50 @@ main(argc, argv) return 0; } +/* + * handle_events - wait for something to happen and respond to it. + */ +static void +handle_events() +{ + struct timeval timo; + sigset_t mask; + + kill_link = open_ccp_flag = 0; + if (sigsetjmp(sigjmp, 1) == 0) { + sigprocmask(SIG_BLOCK, &mask, NULL); + if (got_sighup || got_sigterm || got_sigusr2 || got_sigchld) { + sigprocmask(SIG_UNBLOCK, &mask, NULL); + } else { + waiting = 1; + sigprocmask(SIG_UNBLOCK, &mask, NULL); + wait_input(timeleft(&timo)); + } + } + waiting = 0; + calltimeout(); + if (got_sighup) { + kill_link = 1; + got_sighup = 0; + if (status != EXIT_HANGUP) + status = EXIT_USER_REQUEST; + } + if (got_sigterm) { + kill_link = 1; + persist = 0; + status = EXIT_USER_REQUEST; + got_sigterm = 0; + } + if (got_sigchld) { + reap_kids(0); /* Don't leave dead kids lying around */ + got_sigchld = 0; + } + if (got_sigusr2) { + open_ccp_flag = 1; + got_sigusr2 = 0; + } +} + /* * setup_signals - initialize signal handling. */ @@ -825,7 +753,7 @@ detach() close(1); close(2); detached = 1; - if (!log_to_file && !log_to_specific_fd) + if (log_default) log_to_fd = -1; /* update pid files if they have been written already */ if (pidfilename[0]) @@ -1010,14 +938,13 @@ get_input() return; } - if (debug /*&& (debugflags & DBG_INPACKET)*/) - dbglog("rcvd %P", p, len); - if (len < PPP_HDRLEN) { - MAINDEBUG(("io(): Received short packet.")); + dbglog("received short packet:%.*B", len, p); return; } + dump_packet("rcvd", p, len); + p += 2; /* Skip address and control */ GETSHORT(protocol, p); len -= PPP_HDRLEN; @@ -1087,6 +1014,7 @@ void die(status) int status; { + print_link_stats(); cleanup(); notify(exitnotify, status); syslog(LOG_INFO, "Exit."); @@ -1103,13 +1031,14 @@ cleanup() sys_cleanup(); if (fd_ppp >= 0) - disestablish_ppp(devfd); - cleanup_tty(); + the_channel->disestablish_ppp(devfd); + if (the_channel->cleanup) + (*the_channel->cleanup)(); - if (pidfilename[0] != 0 && unlink(pidfilename) < 0 && errno != ENOENT) + if (pidfilename[0] != 0 && unlink(pidfilename) < 0 && errno != ENOENT) warn("unable to delete pid file %s: %m", pidfilename); pidfilename[0] = 0; - if (linkpidfile[0] != 0 && unlink(linkpidfile) < 0 && errno != ENOENT) + if (linkpidfile[0] != 0 && unlink(linkpidfile) < 0 && errno != ENOENT) warn("unable to delete pid file %s: %m", linkpidfile); linkpidfile[0] = 0; @@ -1117,6 +1046,20 @@ cleanup() cleanup_db(); } +void +print_link_stats() +{ + /* + * Print connect time and statistics. + */ + if (link_stats_valid) { + int t = (link_connect_time + 5) / 6; /* 1/10ths of minutes */ + info("Connect time %d.%d minutes.", t/10, t%10); + info("Sent %u bytes, received %u bytes.", + link_stats.bytes_out, link_stats.bytes_in); + } +} + /* * update_link_stats - get stats at link termination. */ @@ -1154,20 +1097,18 @@ static struct timeval timenow; /* Current time */ /* * timeout - Schedule a timeout. - * - * Note that this timeout takes the number of seconds, NOT hz (as in - * the kernel). */ void -timeout(func, arg, time) +timeout(func, arg, secs, usecs) void (*func) __P((void *)); void *arg; - int time; + int secs, usecs; { struct callout *newp, *p, **pp; - - MAINDEBUG(("Timeout %p:%p in %d seconds.", func, arg, time)); - + + MAINDEBUG(("Timeout %p:%p in %d.%03d seconds.", func, arg, + secs, usecs/1000)); + /* * Allocate timeout. */ @@ -1176,9 +1117,13 @@ timeout(func, arg, time) newp->c_arg = arg; newp->c_func = func; gettimeofday(&timenow, NULL); - newp->c_time.tv_sec = timenow.tv_sec + time; - newp->c_time.tv_usec = timenow.tv_usec; - + newp->c_time.tv_sec = timenow.tv_sec + secs; + newp->c_time.tv_usec = timenow.tv_usec + usecs; + if (newp->c_time.tv_usec >= 1000000) { + newp->c_time.tv_sec += newp->c_time.tv_usec / 1000000; + newp->c_time.tv_usec %= 1000000; + } + /* * Find correct place and link it in. */ @@ -1201,9 +1146,9 @@ untimeout(func, arg) void *arg; { struct callout **copp, *freep; - + MAINDEBUG(("Untimeout %p:%p.", func, arg)); - + /* * Find first matching timeout and remove it from the list. */ @@ -1295,9 +1240,7 @@ hup(sig) int sig; { info("Hangup (SIGHUP)"); - kill_link = 1; - if (status != EXIT_HANGUP) - status = EXIT_USER_REQUEST; + got_sighup = 1; if (conn_running) /* Send the signal to the [dis]connector process(es) also */ kill_my_pg(sig); @@ -1318,9 +1261,7 @@ term(sig) int sig; { info("Terminating on signal %d.", sig); - persist = 0; /* don't try to restart */ - kill_link = 1; - status = EXIT_USER_REQUEST; + got_sigterm = 1; if (conn_running) /* Send the signal to the [dis]connector process(es) also */ kill_my_pg(sig); @@ -1373,7 +1314,7 @@ static void open_ccp(sig) int sig; { - open_ccp_flag = 1; + got_sigusr2 = 1; if (waiting) siglongjmp(sigjmp, 1); } @@ -1461,7 +1402,8 @@ device_script(program, in, out, dont_wait) close(1); close(2); sys_close(); - tty_close_fds(); + if (the_channel->close) + (*the_channel->close)(); closelog(); /* dup the in, out, err fds to 0, 1, 2 */ @@ -1543,7 +1485,8 @@ run_program(prog, args, must_exist, done, arg) close (0); close (1); close (2); - tty_close_fds(); + if (the_channel->close) + (*the_channel->close)(); /* Don't pass handles to the PPP device, even by accident. */ new_fd = open (_PATH_DEVNULL, O_RDWR); @@ -1559,7 +1502,7 @@ run_program(prog, args, must_exist, done, arg) #ifdef BSD /* Force the priority back to zero if pppd is running higher. */ if (setpriority (PRIO_PROCESS, 0, 0) < 0) - warn("can't reset priority to 0: %m"); + warn("can't reset priority to 0: %m"); #endif /* SysV recommends a second fork at this point. */ @@ -1624,7 +1567,6 @@ reap_kids(waitfor) int pid, status; struct subprocess *chp, **prevp; - got_sigchld = 0; if (n_children == 0) return 0; while ((pid = waitpid(-1, &status, (waitfor? 0: WNOHANG))) != -1 @@ -1641,7 +1583,8 @@ reap_kids(waitfor) (chp? chp->prog: "??"), pid, WTERMSIG(status)); } else if (debug) dbglog("Script %s finished (pid %d), status = 0x%x", - (chp? chp->prog: "??"), pid, status); + (chp? chp->prog: "??"), pid, + WIFEXITED(status) ? WEXITSTATUS(status) : status); if (chp && chp->done) (*chp->done)(chp->arg); if (chp) @@ -1844,6 +1787,9 @@ update_db_entry() if (tdb_store(pppdb, key, dbuf, TDB_REPLACE)) error("tdb_store failed: %s", tdb_error(pppdb)); + if (vbuf) + free(vbuf); + } /*