📄 tty.c
字号:
/* * tty.c - code for handling serial ports in pppd. * * Copyright (C) 2000-2004 Paul Mackerras. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. The name(s) of the authors of this software must not be used to * endorse or promote products derived from this software without * prior written permission. * * 3. Redistributions of any form whatsoever must retain the following * acknowledgment: * "This product includes software developed by Paul Mackerras * <paulus@samba.org>". * * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Portions derived from main.c, which is: * * Copyright (c) 1984-2000 Carnegie Mellon University. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The name "Carnegie Mellon University" must not be used to * endorse or promote products derived from this software without * prior written permission. For permission or any legal * details, please contact * Office of Technology Transfer * Carnegie Mellon University * 5000 Forbes Avenue * Pittsburgh, PA 15213-3890 * (412) 268-4387, fax: (412) 268-7395 * tech-transfer@andrew.cmu.edu * * 4. Redistributions of any form whatsoever must retain the following * acknowledgment: * "This product includes software developed by Computing Services * at Carnegie Mellon University (http://www.cmu.edu/computing/)." * * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */#define RCSID "$Id: tty.c,v 1.25 2006/06/04 07:04:57 paulus Exp $"#include <stdio.h>#include <ctype.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <signal.h>#include <errno.h>#include <fcntl.h>#include <syslog.h>#include <netdb.h>#include <utmp.h>#include <pwd.h>#include <setjmp.h>#include <sys/param.h>#include <sys/types.h>#include <sys/wait.h>#include <sys/time.h>#include <sys/resource.h>#include <sys/stat.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include "pppd.h"#include "fsm.h"#include "lcp.h"void tty_process_extra_options __P((void));void tty_check_options __P((void));int connect_tty __P((void));void disconnect_tty __P((void));void tty_close_fds __P((void));void cleanup_tty __P((void));void tty_do_send_config __P((int, u_int32_t, int, int));static int setdevname __P((char *, char **, int));static int setspeed __P((char *, char **, int));static int setxonxoff __P((char **));static int setescape __P((char **));static void printescape __P((option_t *, void (*)(void *, char *,...),void *));static void finish_tty __P((void));static int start_charshunt __P((int, int));static void stop_charshunt __P((void *, 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 *));static int open_socket __P((char *));static void maybe_relock __P((void *, int));static int pty_master; /* fd for master side of pty */static int pty_slave; /* fd for slave side of pty */static int real_ttyfd; /* fd for actual serial port (not pty) */static int ttyfd; /* Serial port file descriptor */static char speed_str[16]; /* Serial port speed as string */mode_t tty_mode = (mode_t)-1; /* Original access permissions to tty */int baud_rate; /* Actual bits/second for serial device */char *callback_script; /* script for doing callback */int charshunt_pid; /* Process ID for charshunt */int locked; /* lock() has succeeded */struct stat devstat; /* result of stat() on devnam *//* option variables */int crtscts = 0; /* Use hardware flow control */bool modem = 1; /* Use modem control lines */int inspeed = 0; /* Input/Output speed requested */bool lockflag = 0; /* Create lock file to lock the serial dev */char *initializer = NULL; /* Script to initialize physical link */char *connect_script = NULL; /* Script to establish physical link */char *disconnect_script = NULL; /* Script to disestablish physical link */char *welcomer = NULL; /* Script to run after phys link estab. */char *ptycommand = NULL; /* Command to run on other side of pty */bool notty = 0; /* Stdin/out is not a tty */char *record_file = NULL; /* File to record chars sent/received */int max_data_rate; /* max bytes/sec through charshunt */bool sync_serial = 0; /* Device is synchronous serial device */char *pty_socket = NULL; /* Socket to connect to pty */int using_pty = 0; /* we're allocating a pty as the device */extern uid_t uid;extern int kill_link;extern int asked_to_quit;extern int got_sigterm;/* XXX */extern int privopen; /* don't lock, open device as root */u_int32_t xmit_accm[8]; /* extended transmit ACCM *//* option descriptors */option_t tty_options[] = { /* device name must be first, or change connect_tty() below! */ { "device name", o_wild, (void *) &setdevname, "Serial port device name", OPT_DEVNAM | OPT_PRIVFIX | OPT_NOARG | OPT_A2STRVAL | OPT_STATIC, devnam}, { "tty speed", o_wild, (void *) &setspeed, "Baud rate for serial port", OPT_PRIO | OPT_NOARG | OPT_A2STRVAL | OPT_STATIC, speed_str }, { "lock", o_bool, &lockflag, "Lock serial device with UUCP-style lock file", OPT_PRIO | 1 }, { "nolock", o_bool, &lockflag, "Don't lock serial device", OPT_PRIOSUB | OPT_PRIV }, { "init", o_string, &initializer, "A program to initialize the device", OPT_PRIO | OPT_PRIVFIX }, { "connect", o_string, &connect_script, "A program to set up a connection", OPT_PRIO | OPT_PRIVFIX }, { "disconnect", o_string, &disconnect_script, "Program to disconnect serial device", OPT_PRIO | OPT_PRIVFIX }, { "welcome", o_string, &welcomer, "Script to welcome client", OPT_PRIO | OPT_PRIVFIX }, { "pty", o_string, &ptycommand, "Script to run on pseudo-tty master side", OPT_PRIO | OPT_PRIVFIX | OPT_DEVNAM }, { "notty", o_bool, ¬ty, "Input/output is not a tty", OPT_DEVNAM | 1 }, { "socket", o_string, &pty_socket, "Send and receive over socket, arg is host:port", OPT_PRIO | OPT_DEVNAM }, { "record", o_string, &record_file, "Record characters sent/received to file", OPT_PRIO }, { "crtscts", o_int, &crtscts, "Set hardware (RTS/CTS) flow control", OPT_PRIO | OPT_NOARG | OPT_VAL(1) }, { "cdtrcts", o_int, &crtscts, "Set alternate hardware (DTR/CTS) flow control", OPT_PRIOSUB | OPT_NOARG | OPT_VAL(2) }, { "nocrtscts", o_int, &crtscts, "Disable hardware flow control", OPT_PRIOSUB | OPT_NOARG | OPT_VAL(-1) }, { "-crtscts", o_int, &crtscts, "Disable hardware flow control", OPT_PRIOSUB | OPT_ALIAS | OPT_NOARG | OPT_VAL(-1) }, { "nocdtrcts", o_int, &crtscts, "Disable hardware flow control", OPT_PRIOSUB | OPT_ALIAS | OPT_NOARG | OPT_VAL(-1) }, { "xonxoff", o_special_noarg, (void *)setxonxoff, "Set software (XON/XOFF) flow control", OPT_PRIOSUB }, { "modem", o_bool, &modem, "Use modem control lines", OPT_PRIO | 1 }, { "local", o_bool, &modem, "Don't use modem control lines", OPT_PRIOSUB | 0 }, { "sync", o_bool, &sync_serial, "Use synchronous HDLC serial encoding", 1 }, { "datarate", o_int, &max_data_rate, "Maximum data rate in bytes/sec (with pty, notty or record option)", OPT_PRIO }, { "escape", o_special, (void *)setescape, "List of character codes to escape on transmission", OPT_A2PRINTER, (void *)printescape }, { NULL }};struct channel tty_channel = { tty_options, &tty_process_extra_options, &tty_check_options, &connect_tty, &disconnect_tty, &tty_establish_ppp, &tty_disestablish_ppp, &tty_do_send_config, &tty_recv_config, &cleanup_tty, &tty_close_fds};/* * setspeed - Set the serial port baud rate. * If doit is 0, the call is to check whether this option is * potentially a speed value. */static intsetspeed(arg, argv, doit) char *arg; char **argv; int doit;{ char *ptr; int spd; spd = strtol(arg, &ptr, 0); if (ptr == arg || *ptr != 0 || spd == 0) return 0; if (doit) { inspeed = spd; slprintf(speed_str, sizeof(speed_str), "%d", spd); } return 1;}/* * setdevname - Set the device name. * If doit is 0, the call is to check whether this option is * potentially a device name. */static intsetdevname(cp, argv, doit) char *cp; char **argv; int doit;{ struct stat statbuf; char dev[MAXPATHLEN]; if (*cp == 0) return 0; if (*cp != '/') { strlcpy(dev, "/dev/", sizeof(dev)); strlcat(dev, cp, sizeof(dev)); cp = dev; } /* * Check if there is a character device by this name. */ if (stat(cp, &statbuf) < 0) { if (!doit) return errno != ENOENT; option_error("Couldn't stat %s: %m", cp); return 0; } if (!S_ISCHR(statbuf.st_mode)) { if (doit) option_error("%s is not a character device", cp); return 0; } if (doit) { strlcpy(devnam, cp, sizeof(devnam)); devstat = statbuf; default_device = 0; } return 1;}static intsetxonxoff(argv) char **argv;{ lcp_wantoptions[0].asyncmap |= 0x000A0000; /* escape ^S and ^Q */ lcp_wantoptions[0].neg_asyncmap = 1; crtscts = -2; return 1;}/* * setescape - add chars to the set we escape on transmission. */static intsetescape(argv) char **argv;{ int n, ret; char *p, *endp; p = *argv; ret = 1; while (*p) { n = strtol(p, &endp, 16); if (p == endp) { option_error("escape parameter contains invalid hex number '%s'", p); return 0; } p = endp; if (n < 0 || n == 0x5E || n > 0xFF) { option_error("can't escape character 0x%x", n); ret = 0; } else xmit_accm[n >> 5] |= 1 << (n & 0x1F); while (*p == ',' || *p == ' ') ++p; } lcp_allowoptions[0].asyncmap = xmit_accm[0]; return ret;}static voidprintescape(opt, printer, arg) option_t *opt; void (*printer) __P((void *, char *, ...)); void *arg;{ int n; int first = 1; for (n = 0; n < 256; ++n) { if (n == 0x7d) n += 2; /* skip 7d, 7e */ if (xmit_accm[n >> 5] & (1 << (n & 0x1f))) { if (!first) printer(arg, ","); else first = 0; printer(arg, "%x", n); } } if (first) printer(arg, "oops # nothing escaped");}/* * tty_init - do various tty-related initializations. */void tty_init(){ add_notifier(&pidchange, maybe_relock, 0); the_channel = &tty_channel; xmit_accm[3] = 0x60000000;}/* * tty_process_extra_options - work out which tty device we are using * and read its options file. */void tty_process_extra_options(){ using_pty = notty || ptycommand != NULL || pty_socket != NULL; if (using_pty) return; if (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);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -