/*
* tty.c - code for handling serial ports in pppd.
*
- * Copyright (C) 2000-2002 Paul Mackerras. All rights reserved.
+ * 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
* 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(s) of the authors of this software must not be used to
+ * 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.
*
- * 4. Redistributions of any form whatsoever must retain the following
+ * 3. Redistributions of any form whatsoever must retain the following
* acknowledgment:
* "This product includes software developed by Paul Mackerras
* <paulus@samba.org>".
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#define RCSID "$Id: tty.c,v 1.12 2003/04/07 00:01:46 paulus Exp $"
+#define RCSID "$Id: tty.c,v 1.24 2005/07/12 01:09:05 paulus Exp $"
#include <stdio.h>
#include <ctype.h>
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 */
if (*cp == 0)
return 0;
- if (strncmp("/dev/", cp, 5) != 0) {
+ if (*cp != '/') {
strlcpy(dev, "/dev/", sizeof(dev));
strlcat(dev, cp, sizeof(dev));
cp = dev;
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);
}
if (using_pty) {
if (!default_device) {
option_error("%s option precludes specifying device name",
- notty? "notty": "pty");
+ pty_socket? "socket": notty? "notty": "pty");
exit(EXIT_OPTION_ERROR);
}
if (ptycommand != NULL && notty) {
{
char *connector;
int fdflags;
+#ifndef __linux__
struct stat statbuf;
+#endif
char numbuf[16];
/*
status = EXIT_LOCK_FAILED;
if (lockflag && !privopen) {
if (lock(devnam) < 0)
- return -1;
+ goto errret;
locked = 1;
}
* in order to wait for the carrier detect signal from the modem.
*/
hungup = 0;
- kill_link = 0;
+ got_sigterm = 0;
connector = doing_callback? callback_script: connect_script;
if (devnam[0] != 0) {
for (;;) {
prio = privopen? OPRIO_ROOT: tty_options[0].priority;
if (prio < OPRIO_ROOT)
seteuid(uid);
- ttyfd = open(devnam, O_NONBLOCK | O_RDWR, 0);
+ real_ttyfd = open(devnam, O_NONBLOCK | O_RDWR, 0);
err = errno;
if (prio < OPRIO_ROOT)
seteuid(0);
- if (ttyfd >= 0)
+ if (real_ttyfd >= 0)
break;
errno = err;
if (err != EINTR) {
status = EXIT_OPEN_FAILED;
}
if (!persist || err != EINTR)
- return -1;
+ goto errret;
}
- real_ttyfd = ttyfd;
+ 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.
*/
warn("Couldn't restrict write permissions to %s: %m", devnam);
} else
tty_mode = statbuf.st_mode;
+#endif /* __linux__ */
/*
* Set line speed, flow control, etc.
close(opipe[0]);
close(opipe[1]);
if (!ok)
- return -1;
+ goto errret;
} else {
if (device_script(ptycommand, pty_master, pty_master, 1) < 0)
- return -1;
- ttyfd = pty_slave;
- close(pty_master);
- pty_master = -1;
+ goto errret;
}
} else if (pty_socket != NULL) {
int fd = open_socket(pty_socket);
if (fd < 0)
- return -1;
+ goto errret;
if (!start_charshunt(fd, fd))
- return -1;
+ goto errret;
+ close(fd);
} else if (notty) {
if (!start_charshunt(0, 1))
- return -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) {
- if (!start_charshunt(ttyfd, ttyfd))
- return -1;
+ 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 (device_script(initializer, ttyfd, ttyfd, 0) < 0) {
error("Initializer script failed");
status = EXIT_INIT_FAILED;
- return -1;
+ goto errret;
}
- if (kill_link) {
+ if (got_sigterm) {
disconnect_tty();
- return -1;
+ goto errret;
}
info("Serial port initialized.");
}
if (device_script(connector, ttyfd, ttyfd, 0) < 0) {
error("Connect script failed");
status = EXIT_CONNECT_FAILED;
- return -1;
+ goto errret;
}
- if (kill_link) {
+ if (got_sigterm) {
disconnect_tty();
- return -1;
+ goto errret;
}
info("Serial connection established.");
}
error("Failed to reopen %s: %m", devnam);
status = EXIT_OPEN_FAILED;
}
- if (!persist || errno != EINTR || hungup || kill_link)
- return -1;
+ if (!persist || errno != EINTR || hungup || got_sigterm)
+ goto errret;
}
close(i);
}
* 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;
+
+ errret:
+ if (pty_master >= 0) {
+ close(pty_master);
+ pty_master = -1;
+ }
+ ttyfd = -1;
+ if (got_sigterm)
+ asked_to_quit = 1;
+ return -1;
}
} else {
info("Serial link disconnected.");
}
+ stop_charshunt(NULL, 0);
}
void tty_close_fds()
{
- if (pty_master >= 0)
- close(pty_master);
if (pty_slave >= 0)
close(pty_slave);
if (real_ttyfd >= 0) {
restore_tty(real_ttyfd);
+#ifndef __linux__
if (tty_mode != (mode_t) -1) {
- if (fchmod(real_ttyfd, tty_mode) != 0) {
- /* XXX if devnam is a symlink, this will change the link */
- chmod(devnam, tty_mode);
- }
+ if (fchmod(real_ttyfd, tty_mode) != 0)
+ error("Couldn't restore tty permissions");
}
+#endif /* __linux__ */
close(real_ttyfd);
real_ttyfd = -1;
{
int cpid;
- cpid = safe_fork();
+ cpid = safe_fork(ifd, ofd, (log_to_fd >= 0? log_to_fd: 2));
if (cpid == -1) {
error("Can't fork process for character shunt: %m");
return 0;
}
if (cpid == 0) {
/* child */
- close(pty_slave);
+ reopen_log();
+ if (!nodetach)
+ log_to_fd = -1;
+ else if (log_to_fd >= 0)
+ log_to_fd = 2;
+ setgid(getgid());
setuid(uid);
if (getuid() != uid)
fatal("setuid failed");
- setgid(getgid());
- if (!nodetach)
- log_to_fd = -1;
- charshunt(ifd, ofd, record_file);
+ charshunt(0, 1, record_file);
exit(0);
}
charshunt_pid = cpid;
- add_notifier(&sigreceived, stop_charshunt, 0);
- close(pty_master);
- pty_master = -1;
- ttyfd = pty_slave;
record_child(cpid, "pppd (charshunt)", charshunt_done, NULL);
return 1;
}
} else if (nibuf == 0) {
/* end of file from stdin */
stdin_readable = 0;
- /* do a 0-length write, hopefully this will generate
- an EOF (hangup) on the slave side. */
- write(pty_master, inpacket_buf, 0);
if (recordf)
if (!record_write(recordf, 4, NULL, 0, &lasttime))
recordf = NULL;
if (!record_write(recordf, 1, obufp, nobuf, &lasttime))
recordf = NULL;
}
- }
+ } else if (!stdin_readable)
+ pty_readable = 0;
if (FD_ISSET(ofd, &writey)) {
n = nobuf;
if (olevel + n > max_level)