📄 tty.c
字号:
} strlcpy(devnam, p, sizeof(devnam)); if (stat(devnam, &devstat) < 0) fatal("Couldn't stat default device %s: %m", devnam); } /* * Parse the tty options file. * The per-tty options file should not change * ptycommand, pty_socket, notty or devnam. * options_for_tty doesn't override options set on the command line, * except for some privileged options. */ /*/if (!options_for_tty()) exit(EXIT_OPTION_ERROR);*/}/* * tty_check_options - do consistency checks on the options we were given. */voidtty_check_options(){ struct stat statbuf; int fdflags; if (demand && notty) { option_error("demand-dialling is incompatible with notty"); exit(EXIT_OPTION_ERROR); } if (demand && connect_script == 0 && ptycommand == NULL && pty_socket == NULL) { 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", pty_socket? "socket": 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; /* * 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;}/* * connect_tty - get the serial port ready to start doing PPP. * That is, open the serial port, set its speed and mode, and run * the connector and/or welcomer. */int connect_tty(){ char *connector; int fdflags;#ifndef __linux__ struct stat statbuf;#endif char numbuf[16]; /* * Get a pty master/slave pair if the pty, notty, socket, * or record options were specified. */ strlcpy(ppp_devnam, devnam, sizeof(ppp_devnam)); pty_master = -1; pty_slave = -1; real_ttyfd = -1; if (using_pty || record_file != NULL) { if (!get_pty(&pty_master, &pty_slave, ppp_devnam, uid)) { error("Couldn't allocate pseudo-tty"); status = EXIT_FATAL_ERROR; return -1; } set_up_tty(pty_slave, 1); } /* * Lock the device if we've been asked to. */ status = EXIT_LOCK_FAILED; if (lockflag && !privopen) { if (lock(devnam) < 0) goto errret; locked = 1; } /* * Open the serial device and set it up to be the ppp interface. * First we open it in non-blocking mode so we can set the * various termios flags appropriately. If we aren't dialling * out and we want to use the modem lines, we reopen it later * in order to wait for the carrier detect signal from the modem. */ hungup = 0; got_sigterm = 0; connector = doing_callback? callback_script: connect_script; if (devnam[0] != 0) { for (;;) { /* If the user specified the device name, become the user before opening it. */ int err, prio; prio = privopen? OPRIO_ROOT: tty_options[0].priority; if (prio < OPRIO_ROOT && seteuid(uid) == -1) { error("Unable to drop privileges before opening %s: %m\n", devnam); status = EXIT_OPEN_FAILED; goto errret; } real_ttyfd = open(devnam, O_NONBLOCK | O_RDWR, 0); err = errno; if (prio < OPRIO_ROOT && seteuid(0) == -1) fatal("Unable to regain privileges"); if (real_ttyfd >= 0) break; errno = err; if (err != EINTR) { error("Failed to open %s: %m", devnam); status = EXIT_OPEN_FAILED; } if (!persist || err != EINTR) goto errret; } ttyfd = real_ttyfd; if ((fdflags = fcntl(ttyfd, F_GETFL)) == -1 || fcntl(ttyfd, F_SETFL, fdflags & ~O_NONBLOCK) < 0) warn("Couldn't reset non-blocking mode on device: %m");#ifndef __linux__ /* * Linux 2.4 and above blocks normal writes to the tty * when it is in PPP line discipline, so this isn't needed. */ /* * Do the equivalent of `mesg n' to stop broadcast messages. */ if (fstat(ttyfd, &statbuf) < 0 || fchmod(ttyfd, statbuf.st_mode & ~(S_IWGRP | S_IWOTH)) < 0) { warn("Couldn't restrict write permissions to %s: %m", devnam); } else tty_mode = statbuf.st_mode;#endif /* __linux__ */ /* * Set line speed, flow control, etc. * If we have a non-null connection or initializer script, * on most systems we set CLOCAL for now so that we can talk * to the modem before carrier comes up. But this has the * side effect that we might miss it if CD drops before we * get to clear CLOCAL below. On systems where we can talk * successfully to the modem with CLOCAL clear and CD down, * we could clear CLOCAL at this point. */ set_up_tty(ttyfd, ((connector != NULL && connector[0] != 0) || initializer != NULL)); } /* * If the pty, socket, notty and/or record option was specified, * start up the character shunt now. */ status = EXIT_PTYCMD_FAILED; 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"); /* don't leak these to the ptycommand */ (void) fcntl(ipipe[0], F_SETFD, FD_CLOEXEC); (void) fcntl(opipe[1], F_SETFD, FD_CLOEXEC); 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 errret; } else { if (device_script(ptycommand, pty_master, pty_master, 1) < 0) goto errret; } } else if (pty_socket != NULL) { int fd = open_socket(pty_socket); if (fd < 0) goto errret; if (!start_charshunt(fd, fd)) goto errret; close(fd); } else if (notty) { if (!start_charshunt(0, 1)) goto errret; dup2(fd_devnull, 0); dup2(fd_devnull, 1); if (log_to_fd == 1) log_to_fd = -1; if (log_to_fd != 2) dup2(fd_devnull, 2); } else if (record_file != NULL) { int fd = dup(ttyfd); if (!start_charshunt(fd, fd)) goto errret; } if (using_pty || record_file != NULL) { ttyfd = pty_slave; close(pty_master); pty_master = -1; } /* run connection script */ if ((connector && connector[0]) || initializer) { if (real_ttyfd != -1) { /* XXX do this if doing_callback == CALLBACK_DIALIN? */ if (!default_device && modem) { setdtr(real_ttyfd, 0); /* in case modem is off hook */ sleep(1); setdtr(real_ttyfd, 1); } } if (initializer && initializer[0]) { if (device_script(initializer, ttyfd, ttyfd, 0) < 0) { error("Initializer script failed"); status = EXIT_INIT_FAILED; goto errret; } if (got_sigterm) { disconnect_tty(); goto errret; } info("Serial port initialized."); } if (connector && connector[0]) { if (device_script(connector, ttyfd, ttyfd, 0) < 0) { error("Connect script failed"); status = EXIT_CONNECT_FAILED; goto errret; } if (got_sigterm) { disconnect_tty(); goto errret; } info("Serial connection established."); } /* set line speed, flow control, etc.; clear CLOCAL if modem option */ if (real_ttyfd != -1) set_up_tty(real_ttyfd, 0); if (doing_callback == CALLBACK_DIALIN) connector = NULL; } /* reopen tty if necessary to wait for carrier */ if (connector == NULL && modem && devnam[0] != 0) { int i; for (;;) { if ((i = open(devnam, O_RDWR)) >= 0) break; if (errno != EINTR) { error("Failed to reopen %s: %m", devnam); status = EXIT_OPEN_FAILED; } if (!persist || errno != EINTR || hungup || got_sigterm) goto errret; } close(i); } slprintf(numbuf, sizeof(numbuf), "%d", baud_rate); script_setenv("SPEED", numbuf, 0); /* run welcome script, if any */ if (welcomer && welcomer[0]) { if (device_script(welcomer, ttyfd, ttyfd, 0) < 0) warn("Welcome script failed"); } /* * 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. */ if (connector != NULL || ptycommand != NULL || pty_socket != NULL) listen_time = connect_delay; return ttyfd; errret: if (pty_master >= 0) { close(pty_master); pty_master = -1; } ttyfd = -1; if (got_sigterm) asked_to_quit = 1; return -1;}void disconnect_tty(){ if (disconnect_script == NULL || hungup) return; if (real_ttyfd >= 0) set_up_tty(real_ttyfd, 1); if (device_script(disconnect_script, ttyfd, ttyfd, 0) < 0) { warn("disconnect script failed"); } else { info("Serial link disconnected."); } stop_charshunt(NULL, 0);}void tty_close_fds(){ if (pty_slave >= 0) close(pty_slave); if (real_ttyfd >= 0) { close(real_ttyfd); real_ttyfd = -1; } /* N.B. ttyfd will == either pty_slave or real_ttyfd */}void cleanup_tty(){ if (real_ttyfd >= 0) finish_tty(); tty_close_fds(); if (locked) { unlock(); locked = 0; }}/* * tty_do_send_config - set transmit-side PPP configuration. * We set the extended transmit ACCM here as well. */voidtty_do_send_config(mtu, accm, pcomp, accomp) int mtu; u_int32_t accm; int pcomp, accomp;{ tty_set_xaccm(xmit_accm); tty_send_config(mtu, accm, pcomp, accomp);}/* * finish_tty - restore the terminal device to its original settings */static voidfinish_tty(){ /* drop dtr to hang up */ if (!default_device && modem) { 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. */ sleep(1); } restore_tty(real_ttyfd);#ifndef __linux__ if (tty_mode != (mode_t) -1) { if (fchmod(real_ttyfd, tty_mode) != 0) error("Couldn't restore tty permissions");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -