* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#define RCSID "$Id: tty.c,v 1.21 2004/11/13 12:05:48 paulus Exp $"
-
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
+#include <termios.h>
#include <unistd.h>
#include <signal.h>
#include <errno.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 "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));
+void tty_process_extra_options(void);
+void tty_check_options(void);
+int connect_tty(void);
+void disconnect_tty(void);
+void tty_close_fds(void);
+void cleanup_tty(void);
+void tty_do_send_config(int, u_int32_t, int, int);
+
+static int setdevname(char *, char **, int);
+static int setspeed(char *, char **, int);
+static int setxonxoff(char **);
+static int setescape(char **);
+static void printescape(option_t *, void (*)(void *, char *,...),void *);
+static void finish_tty(void);
+static int start_charshunt(int, int);
+static void stop_charshunt(void *, int);
+static void charshunt_done(void *);
+static void charshunt(int, int, char *);
+static int record_write(FILE *, int code, u_char *buf, int nb,
+ struct timeval *);
+static int open_socket(char *);
+static void maybe_relock(void *, int);
static int pty_master; /* fd for master side of pty */
static int pty_slave; /* fd for slave side of pty */
/* option variables */
int crtscts = 0; /* Use hardware flow control */
+int stop_bits = 1; /* Number of serial port stop bits */
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 */
OPT_PRIOSUB | OPT_ALIAS | OPT_NOARG | OPT_VAL(-1) },
{ "xonxoff", o_special_noarg, (void *)setxonxoff,
"Set software (XON/XOFF) flow control", OPT_PRIOSUB },
+ { "stop-bits", o_int, &stop_bits,
+ "Number of stop bits in serial port",
+ OPT_PRIO | OPT_PRIVFIX | OPT_LIMITS, NULL, 2, 1 },
{ "modem", o_bool, &modem,
"Use modem control lines", OPT_PRIO | 1 },
* potentially a speed value.
*/
static int
-setspeed(arg, argv, doit)
- char *arg;
- char **argv;
- int doit;
+setspeed(char *arg, char **argv, int doit)
{
char *ptr;
int spd;
* potentially a device name.
*/
static int
-setdevname(cp, argv, doit)
- char *cp;
- char **argv;
- int doit;
+setdevname(char *cp, char **argv, int doit)
{
struct stat statbuf;
char dev[MAXPATHLEN];
}
static int
-setxonxoff(argv)
- char **argv;
+setxonxoff(char **argv)
{
lcp_wantoptions[0].asyncmap |= 0x000A0000; /* escape ^S and ^Q */
lcp_wantoptions[0].neg_asyncmap = 1;
* setescape - add chars to the set we escape on transmission.
*/
static int
-setescape(argv)
- char **argv;
+setescape(char **argv)
{
int n, ret;
char *p, *endp;
}
static void
-printescape(opt, printer, arg)
- option_t *opt;
- void (*printer) __P((void *, char *, ...));
- void *arg;
+printescape(option_t *opt, void (*printer)(void *, char *, ...), void *arg)
{
int n;
int first = 1;
/*
* tty_init - do various tty-related initializations.
*/
-void tty_init()
+void tty_init(void)
{
add_notifier(&pidchange, maybe_relock, 0);
the_channel = &tty_channel;
* tty_process_extra_options - work out which tty device we are using
* and read its options file.
*/
-void tty_process_extra_options()
+void tty_process_extra_options(void)
{
using_pty = notty || ptycommand != NULL || pty_socket != NULL;
if (using_pty)
* tty_check_options - do consistency checks on the options we were given.
*/
void
-tty_check_options()
+tty_check_options(void)
{
struct stat statbuf;
int fdflags;
- if (demand && connect_script == 0) {
+ 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);
}
* That is, open the serial port, set its speed and mode, and run
* the connector and/or welcomer.
*/
-int connect_tty()
+int connect_tty(void)
{
char *connector;
int fdflags;
* 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) {
int err, prio;
prio = privopen? OPRIO_ROOT: tty_options[0].priority;
- if (prio < OPRIO_ROOT)
- seteuid(uid);
+ 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);
+ if (prio < OPRIO_ROOT && seteuid(0) == -1)
+ fatal("Unable to regain privileges");
if (real_ttyfd >= 0)
break;
errno = err;
if (device_script(initializer, ttyfd, ttyfd, 0) < 0) {
error("Initializer script failed");
status = EXIT_INIT_FAILED;
- goto errret;
+ goto errretf;
}
if (got_sigterm) {
disconnect_tty();
- goto errret;
+ goto errretf;
}
info("Serial port initialized.");
}
if (device_script(connector, ttyfd, ttyfd, 0) < 0) {
error("Connect script failed");
status = EXIT_CONNECT_FAILED;
- goto errret;
+ goto errretf;
}
if (got_sigterm) {
disconnect_tty();
- goto errret;
+ goto errretf;
}
info("Serial connection established.");
}
* 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)
+ if (connector != NULL || ptycommand != NULL || pty_socket != NULL)
listen_time = connect_delay;
return ttyfd;
+ errretf:
+ if (real_ttyfd >= 0)
+ tcflush(real_ttyfd, TCIOFLUSH);
errret:
if (pty_master >= 0) {
close(pty_master);
pty_master = -1;
}
- if (pty_slave >= 0) {
- close(pty_slave);
- pty_slave = -1;
- }
- if (real_ttyfd >= 0) {
- close(real_ttyfd);
- real_ttyfd = -1;
- }
ttyfd = -1;
if (got_sigterm)
asked_to_quit = 1;
}
-void disconnect_tty()
+void disconnect_tty(void)
{
if (disconnect_script == NULL || hungup)
return;
} else {
info("Serial link disconnected.");
}
+ stop_charshunt(NULL, 0);
}
-void tty_close_fds()
+void tty_close_fds(void)
{
if (pty_slave >= 0)
close(pty_slave);
/* N.B. ttyfd will == either pty_slave or real_ttyfd */
}
-void cleanup_tty()
+void cleanup_tty(void)
{
if (real_ttyfd >= 0)
finish_tty();
* We set the extended transmit ACCM here as well.
*/
void
-tty_do_send_config(mtu, accm, pcomp, accomp)
- int mtu;
- u_int32_t accm;
- int pcomp, accomp;
+tty_do_send_config(int mtu, u_int32_t accm, int pcomp, int accomp)
{
tty_set_xaccm(xmit_accm);
tty_send_config(mtu, accm, pcomp, accomp);
* finish_tty - restore the terminal device to its original settings
*/
static void
-finish_tty()
+finish_tty(void)
{
/* drop dtr to hang up */
if (!default_device && modem) {
* maybe_relock - our PID has changed, maybe update the lock file.
*/
static void
-maybe_relock(arg, pid)
- void *arg;
- int pid;
+maybe_relock(void *arg, int pid)
{
if (locked)
relock(pid);
* host and port.
*/
static int
-open_socket(dest)
- char *dest;
+open_socket(char *dest)
{
char *sep, *endp = NULL;
int sock, port = -1;
* start_charshunt - create a child process to run the character shunt.
*/
static int
-start_charshunt(ifd, ofd)
- int ifd, ofd;
+start_charshunt(int ifd, int ofd)
{
int cpid;
exit(0);
}
charshunt_pid = cpid;
- add_notifier(&sigreceived, stop_charshunt, 0);
- record_child(cpid, "pppd (charshunt)", charshunt_done, NULL);
+ record_child(cpid, "pppd (charshunt)", charshunt_done, NULL, 1);
return 1;
}
static void
-charshunt_done(arg)
- void *arg;
+charshunt_done(void *arg)
{
charshunt_pid = 0;
}
static void
-stop_charshunt(arg, sig)
- void *arg;
- int sig;
+stop_charshunt(void *arg, int sig)
{
if (charshunt_pid)
kill(charshunt_pid, (sig == SIGINT? sig: SIGTERM));
* (We assume ofd >= ifd which is true the way this gets called. :-).
*/
static void
-charshunt(ifd, ofd, record_file)
- int ifd, ofd;
- char *record_file;
+charshunt(int ifd, int ofd, char *record_file)
{
int n, nfds;
fd_set ready, writey;
pty_readable = stdin_readable = 1;
ilevel = olevel = 0;
- gettimeofday(&levelt, NULL);
+ get_time(&levelt);
if (max_data_rate) {
max_level = max_data_rate / 10;
if (max_level < 100)
int nbt;
struct timeval now;
- gettimeofday(&now, NULL);
+ get_time(&now);
dt = (now.tv_sec - levelt.tv_sec
+ (now.tv_usec - levelt.tv_usec) / 1e6);
nbt = (int)(dt * max_data_rate);
}
static int
-record_write(f, code, buf, nb, tp)
- FILE *f;
- int code;
- u_char *buf;
- int nb;
- struct timeval *tp;
+record_write(FILE *f, int code, u_char *buf, int nb, struct timeval *tp)
{
struct timeval now;
int diff;