- it is now possible to make the serial drivers pipe their input/output

to programs by using a '|' followed by a command line as the modem or
  printer port setting (instead of a device name like '/dev/ttyS0')
  [Brian Johnson]
- the option "--config FILE" tells B2 to use a different config file
This commit is contained in:
cebix 2002-07-31 16:46:14 +00:00
parent 586d299bfc
commit 3d2bac9f15
13 changed files with 937 additions and 66 deletions

View File

@ -4,6 +4,12 @@ V1.0 (snapshot) - <date>
- Unix: cleaned up pthread attributes [Brian Johnson]
- Unix: fixed floppy problems under Linux
- Unix: implement "ignoresegv" feature on Linux/x86, Linux/ppc, Darwin/ppc
- Unix: serial port baud rates are now set correctly
- Unix: it is now possible to make the serial drivers pipe their input/output
to programs by using a '|' followed by a command line as the modem or
printer port setting (instead of a device name like '/dev/ttyS0')
[Brian Johnson]
- Unix: the option "--config FILE" tells B2 to use a different config file
V1.0 (snapshot) - 15.Jan.2002
- added support for on-the-fly video resolution and depth switching, and

View File

@ -42,5 +42,4 @@ Unix:
- sys_unix.cpp: SysFormat(), SysIsFixedDisk(), SysIsDiskInserted(),
prevent/allow for non-floppy/CDROM devices
- ESD is also available on Solaris
- serial_unix.cpp: provide a way to pipe input/output to programs
- display progress bar during disk file creation in prefs editor

View File

@ -0,0 +1,110 @@
README file for networking under IRIX
by Brian J. Johnson 7/23/2002
version 1.0
==================================================
BasiliskII does not currently support networking natively on IRIX.
That is, the emulated Ethernet card does not do anything. There's no
reason one couldn't use raw domain sockets and the snoop(7p) facility
to do networking, but so far no one has written the required glue
code.
However, it is possible to do TCP/IP networking with BasiliskII on
IRIX via PPP, by connecting an emulated serial port to the IRIX PPP
daemon. Here are the steps to set it up:
Set up PPP on IRIX
------------------
You need root privileges to do this.
First, make sure you have eoe.sw.ppp and eoe.sw.uucp installed:
IRIS# versions eoe.sw.ppp eoe.sw.uucp
I = Installed, R = Removed
Name Date Description
I eoe 07/22/2002 IRIX Execution Environment, 6.5.17m
I eoe.sw 07/22/2002 IRIX Execution Environment Software
I eoe.sw.ppp 07/22/2002 Point-to-Point Protocol Software
I eoe.sw.uucp 07/22/2002 UUCP Utilities
If they aren't installed, install them from your distribution CDs.
Next, pick IP addresses for the IRIX and MacOS sides of the PPP
connection. You may want to ask your local network administrator
about this, but any two unused addresses on your local subnet should
work.
Edit /etc/ppp.conf and add these three lines:
_NET_INCOMING
remotehost=<MacOS PPP IP address>
localhost=<IRIX PPP IP address>
(Replace the angle brackets and the text in them with the appropriate
IP addresses.)
Next, make a script to set up the environment properly when invoking
pppd from BasiliskII. You can name this whatever you want; I chose
/usr/etc/ppp-b2:
IRIS# whoami
root
IRIS# cat < /usr/etc/ppp-b2
#!/bin/sh
export USER=_NET_INCOMING
exec /usr/etc/ppp "$@"
IRIS# chmod 4775 /usr/etc/ppp-b2
Rewrite this in perl or python or C or whatever if you don't like
setuid shell scripts. The alternative is to run BasiliskII as root:
pppd _must_ be run as root.
Configure BasiliskII to start the PPP daemon
--------------------------------------------
Start up BasiliskII, and in the serial devices tab, enter:
|exec /usr/etc/ppp-b2
Supply the name you used for the script you created. Be sure to
include the leading pipe symbol ("|").
The "exec" causes your PPP startup script to replace the shell
BasiliskII runs to interpret the command. It's not strictly
necessary, but cuts down on the number of extra processes hanging
about.
Install a PPP client on MacOS
-----------------------------
The details of this step will vary depending on your PPP client
software. Set it up for a "direct" connection, with no modem chatting
or login scripting. For instance, with FreePPP I set the "Connect:"
item on the "Edit..." screen under the "Accounts" tab to "Directly".
Be sure to select the correct serial port. The serial port speed
shouldn't matter (BasiliskII ignores it), but I set it to 115200 bps.
Next, configure MacOS's TCP/IP stack. If you're using Open Transport,
Open the TCP/IP control panel and select "Using PPP Server" under the
"Configure" item. Copy IRIX's DNS client info. from /etc/resolv.conf
to the control panel: the addresses from the "nameserver" lines go in
the "Name server addr.:" box, and the domains from the "search" lines
go in the "Search domains:" box. The steps should be similar for
MacTCP.
Now fire up PPP. Your PPP client should establish communication with
the IRIX PPP daemon, and you're off and running.
Disclaimer
----------
I haven't tried this procedure from scratch on a freshly installed
system, so I might have missed a step somewhere. But it should get
you close....

View File

@ -34,7 +34,7 @@ SRCS = ../main.cpp main_unix.cpp ../prefs.cpp ../prefs_items.cpp prefs_unix.cpp
timer_unix.cpp clip_unix.cpp ../adb.cpp ../serial.cpp ../ether.cpp \
../sony.cpp ../disk.cpp ../cdrom.cpp ../scsi.cpp ../video.cpp video_blit.cpp \
video_x.cpp vm_alloc.cpp sigsegv.cpp ../audio.cpp ../extfs.cpp extfs_unix.cpp \
../user_strings.cpp user_strings_unix.cpp \
../user_strings.cpp user_strings_unix.cpp sshpty.c strlcpy.c \
$(SYSSRCS) $(CPUSRCS)
APP = BasiliskII

View File

@ -80,6 +80,17 @@
/* Define if libgnomeui is available */
#undef HAVE_GNOMEUI
/* Additions from openssh-3.2.2p1, for sshpty.c */
/* Define if you are on NEWS-OS */
#undef HAVE_NEWS4
/* Define if you have /dev/ptmx */
#undef HAVE_DEV_PTMX
/* Define if you have /dev/ptc */
#undef HAVE_DEV_PTS_AND_PTC
/* Leave that blank line there!! Autoheader needs it.
If you're adding to this file, keep in mind:

View File

@ -257,6 +257,50 @@ AC_CHECK_FUNCS(vm_allocate vm_deallocate vm_protect)
dnl Darwin seems to define mach_task_self() instead of task_self().
AC_CHECK_FUNCS(mach_task_self task_self)
dnl Check for headers and functions related to pty support (sshpty.c)
dnl From openssh-3.2.2p1 configure.ac
AC_CHECK_HEADERS(strings.h login.h sys/bsdtty.h sys/stat.h util.h pty.h)
AC_CHECK_FUNCS(_getpty vhangup strlcpy)
case "$host" in
*-*-hpux10.26)
disable_ptmx_check=yes
;;
*-*-linux*)
no_dev_ptmx=1
;;
mips-sony-bsd|mips-sony-newsos4)
AC_DEFINE(HAVE_NEWS4)
;;
*-*-sco3.2v4*)
no_dev_ptmx=1
;;
*-*-sco3.2v5*)
no_dev_ptmx=1
;;
esac
if test -z "$no_dev_ptmx" ; then
if test "x$disable_ptmx_check" != "xyes" ; then
AC_CHECK_FILE("/dev/ptmx",
[
AC_DEFINE_UNQUOTED(HAVE_DEV_PTMX)
have_dev_ptmx=1
]
)
fi
fi
AC_CHECK_FILE("/dev/ptc",
[
AC_DEFINE_UNQUOTED(HAVE_DEV_PTS_AND_PTC)
have_dev_ptc=1
]
)
dnl (end of code from openssh-3.2.2p1 configure.ac)
dnl Select system-dependant source files.
SERIALSRC=serial_unix.cpp
ETHERSRC=../dummy/ether_dummy.cpp

View File

@ -61,6 +61,9 @@ struct sigstate {
# include <X11/extensions/xf86dga.h>
#endif
#include <string>
using std::string;
#include "cpu_emulation.h"
#include "sys.h"
#include "rom_patches.h"
@ -226,11 +229,15 @@ static void sigsegv_dump_state(sigsegv_address_t fault_address, sigsegv_address_
static void usage(const char *prg_name)
{
printf("Usage: %s [OPTION...]\n", prg_name);
printf("\nUnix options:\n");
printf(" --display STRING\n X display to use\n");
printf(" --break ADDRESS\n set ROM breakpoint\n");
printf(" --rominfo\n dump ROM information\n");
printf(
"Usage: %s [OPTION...]\n"
"\nUnix options:\n"
" --config FILE\n read/write configuration from/to FILE\n"
" --display STRING\n X display to use\n"
" --break ADDRESS\n set ROM breakpoint\n"
" --rominfo\n dump ROM information\n", prg_name
);
LoadPrefs(); // read the prefs file so PrefsPrintUsage() will print the correct default values
PrefsPrintUsage();
exit(0);
}
@ -249,6 +256,47 @@ int main(int argc, char **argv)
printf(GetString(STR_ABOUT_TEXT1), VERSION_MAJOR, VERSION_MINOR);
printf(" %s\n", GetString(STR_ABOUT_TEXT2));
// Parse command line arguments
for (int i=1; i<argc; i++) {
if (strcmp(argv[i], "--help") == 0) {
usage(argv[0]);
} else if (strcmp(argv[i], "--display") == 0) {
i++; // don't remove the argument, gtk_init() needs it too
if (i < argc)
x_display_name = strdup(argv[i]);
} else if (strcmp(argv[i], "--break") == 0) {
argv[i++] = NULL;
if (i < argc) {
ROMBreakpoint = strtol(argv[i], NULL, 0);
argv[i] = NULL;
}
} else if (strcmp(argv[i], "--config") == 0) {
argv[i++] = NULL;
if (i < argc) {
extern string UserPrefsPath; // from prefs_unix.cpp
UserPrefsPath = argv[i];
argv[i] = NULL;
}
} else if (strcmp(argv[i], "--rominfo") == 0) {
argv[i] = NULL;
PrintROMInfo = true;
}
}
// Remove processed arguments
for (int i=1; i<argc; i++) {
int k;
for (k=i; k<argc; k++)
if (argv[k] != NULL)
break;
if (k > i) {
k -= i;
for (int j=i+k; j<argc; j++)
argv[j-k] = argv[j];
argc -= k;
}
}
#ifdef ENABLE_GTK
#ifdef HAVE_GNOMEUI
// Init GNOME/GTK
@ -260,27 +308,14 @@ int main(int argc, char **argv)
gtk_set_locale();
gtk_init(&argc, &argv);
#endif
x_display_name = gdk_get_display(); // gtk_init() handles and removes the "--display" argument
#endif
// Read preferences
PrefsInit(argc, argv);
// Parse command line arguments
// Any command line arguments left?
for (int i=1; i<argc; i++) {
if (strcmp(argv[i], "--help") == 0) {
usage(argv[0]);
} else if (strcmp(argv[i], "--display") == 0) {
i++;
if (i < argc)
x_display_name = strdup(argv[i]);
} else if (strcmp(argv[i], "--break") == 0) {
i++;
if (i < argc)
ROMBreakpoint = strtol(argv[i], NULL, 0);
} else if (strcmp(argv[i], "--rominfo") == 0) {
PrintROMInfo = true;
} else if (argv[i][0] == '-') {
if (argv[i][0] == '-') {
fprintf(stderr, "Unrecognized option '%s'\n", argv[i]);
usage(argv[0]);
}

View File

@ -23,6 +23,9 @@
#include <stdio.h>
#include <stdlib.h>
#include <string>
using std::string;
#include "prefs.h"
@ -42,7 +45,8 @@ prefs_desc platform_prefs_items[] = {
// Prefs file name and path
const char PREFS_FILE_NAME[] = ".basilisk_ii_prefs";
static char prefs_path[1024];
string UserPrefsPath;
static string prefs_path;
/*
@ -52,16 +56,16 @@ static char prefs_path[1024];
void LoadPrefs(void)
{
// Construct prefs path
prefs_path[0] = 0;
char *home = getenv("HOME");
if (home != NULL && strlen(home) < 1000) {
strncpy(prefs_path, home, 1000);
strcat(prefs_path, "/");
}
strcat(prefs_path, PREFS_FILE_NAME);
if (UserPrefsPath.empty()) {
char *home = getenv("HOME");
if (home)
prefs_path = string(home) + '/';
prefs_path += PREFS_FILE_NAME;
} else
prefs_path = UserPrefsPath;
// Read preferences from settings file
FILE *f = fopen(prefs_path, "r");
FILE *f = fopen(prefs_path.c_str(), "r");
if (f != NULL) {
// Prefs file found, load settings
@ -83,7 +87,7 @@ void LoadPrefs(void)
void SavePrefs(void)
{
FILE *f;
if ((f = fopen(prefs_path, "w")) != NULL) {
if ((f = fopen(prefs_path.c_str(), "w")) != NULL) {
SavePrefsToStream(f);
fclose(f);
}

View File

@ -22,9 +22,11 @@
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <pthread.h>
#include <semaphore.h>
#include <termios.h>
#include <errno.h>
#ifdef __linux__
#include <linux/lp.h>
#include <linux/major.h>
@ -38,6 +40,11 @@
#include "serial.h"
#include "serial_defs.h"
extern "C" {
#include "sshpty.h"
}
#define DEBUG 0
#include "debug.h"
@ -64,8 +71,9 @@ public:
XSERDPort(const char *dev)
{
device_name = dev;
is_parallel = false;
protocol = serial;
fd = -1;
pid = 0;
input_thread_active = output_thread_active = false;
Set_pthread_attr(&thread_attr, 2);
@ -101,14 +109,17 @@ public:
virtual int16 close(void);
private:
bool open_pty(void);
bool configure(uint16 config);
void set_handshake(uint32 s, bool with_dtr);
static void *input_func(void *arg);
static void *output_func(void *arg);
const char *device_name; // Device name
bool is_parallel; // Flag: Port is parallel
enum {serial, parallel, pty, midi}
protocol; // Type of device
int fd; // FD of device
pid_t pid; // PID of child process
bool io_killed; // Flag: KillIO called, I/O threads must not call deferred tasks
bool quitting; // Flag: Quit threads
@ -168,27 +179,39 @@ int16 XSERDPort::open(uint16 config)
io_killed = false;
quitting = false;
// Open port
fd = ::open(device_name, O_RDWR);
if (fd < 0)
goto open_error;
// Open port, according to the syntax of the path
if (device_name[0] == '|') {
// Open a process via ptys
if (!open_pty())
goto open_error;
}
else if (!strcmp(device_name, "midi")) {
// MIDI: not yet implemented
return openErr;
}
else {
// Device special file
fd = ::open(device_name, O_RDWR);
if (fd < 0)
goto open_error;
#if defined(__linux__)
// Parallel port?
struct stat st;
if (fstat(fd, &st) == 0)
if (S_ISCHR(st.st_mode))
is_parallel = (MAJOR(st.st_rdev) == LP_MAJOR);
// Parallel port?
struct stat st;
if (fstat(fd, &st) == 0)
if (S_ISCHR(st.st_mode))
protocol = ((MAJOR(st.st_rdev) == LP_MAJOR) ? parallel : serial);
#elif defined(__FreeBSD__) || defined(__NetBSD__)
// Parallel port?
struct stat st;
if (fstat(fd, &st) == 0)
if (S_ISCHR(st.st_mode))
is_parallel = ((st.st_rdev >> 16) == 16);
// Parallel port?
struct stat st;
if (fstat(fd, &st) == 0)
if (S_ISCHR(st.st_mode))
protocol = (((st.st_rdev >> 16) == 16) ? parallel : serial);
#endif
}
// Configure port for raw mode
if (!is_parallel) {
if (protocol == serial) {
if (tcgetattr(fd, &mode) < 0)
goto open_error;
cfmakeraw(&mode);
@ -280,7 +303,7 @@ int16 XSERDPort::control(uint32 pb, uint32 dce, uint16 code)
switch (code) {
case 1: // KillIO
io_killed = true;
if (!is_parallel)
if (protocol == serial)
tcflush(fd, TCIOFLUSH);
while (read_pending || write_pending)
usleep(10000);
@ -301,7 +324,7 @@ int16 XSERDPort::control(uint32 pb, uint32 dce, uint16 code)
return noErr;
case kSERDSetBreak:
if (!is_parallel)
if (protocol == serial)
tcsendbreak(fd, 0);
return noErr;
@ -309,7 +332,7 @@ int16 XSERDPort::control(uint32 pb, uint32 dce, uint16 code)
return noErr;
case kSERDBaudRate: {
if (is_parallel)
if (protocol != serial)
return noErr;
uint16 rate = ReadMacInt16(pb + csParam);
speed_t baud_rate;
@ -350,8 +373,8 @@ int16 XSERDPort::control(uint32 pb, uint32 dce, uint16 code)
rate = 57600; baud_rate = B57600;
}
WriteMacInt16(pb + csParam, rate);
cfsetispeed(&mode, B115200);
cfsetospeed(&mode, B115200);
cfsetispeed(&mode, baud_rate);
cfsetospeed(&mode, baud_rate);
tcsetattr(fd, TCSANOW, &mode);
return noErr;
}
@ -362,7 +385,7 @@ int16 XSERDPort::control(uint32 pb, uint32 dce, uint16 code)
return noErr;
case kSERDMiscOptions:
if (is_parallel)
if (protocol != serial)
return noErr;
if (ReadMacInt8(pb + csParam) & kOptionPreserveDTR)
mode.c_cflag &= ~HUPCL;
@ -372,7 +395,7 @@ int16 XSERDPort::control(uint32 pb, uint32 dce, uint16 code)
return noErr;
case kSERDAssertDTR: {
if (is_parallel)
if (protocol != serial)
return noErr;
unsigned int status = TIOCM_DTR;
ioctl(fd, TIOCMBIS, &status);
@ -380,7 +403,7 @@ int16 XSERDPort::control(uint32 pb, uint32 dce, uint16 code)
}
case kSERDNegateDTR: {
if (is_parallel)
if (protocol != serial)
return noErr;
unsigned int status = TIOCM_DTR;
ioctl(fd, TIOCMBIC, &status);
@ -392,12 +415,12 @@ int16 XSERDPort::control(uint32 pb, uint32 dce, uint16 code)
return noErr; // Not supported under Unix
case kSERDResetChannel:
if (!is_parallel)
if (protocol == serial)
tcflush(fd, TCIOFLUSH);
return noErr;
case kSERDAssertRTS: {
if (is_parallel)
if (protocol != serial)
return noErr;
unsigned int status = TIOCM_RTS;
ioctl(fd, TIOCMBIS, &status);
@ -405,7 +428,7 @@ int16 XSERDPort::control(uint32 pb, uint32 dce, uint16 code)
}
case kSERDNegateRTS: {
if (is_parallel)
if (protocol != serial)
return noErr;
unsigned int status = TIOCM_RTS;
ioctl(fd, TIOCMBIC, &status);
@ -413,7 +436,7 @@ int16 XSERDPort::control(uint32 pb, uint32 dce, uint16 code)
}
case kSERD115KBaud:
if (is_parallel)
if (protocol != serial)
return noErr;
cfsetispeed(&mode, B115200);
cfsetospeed(&mode, B115200);
@ -422,7 +445,7 @@ int16 XSERDPort::control(uint32 pb, uint32 dce, uint16 code)
case kSERD230KBaud:
case kSERDSetHighSpeed:
if (is_parallel)
if (protocol != serial)
return noErr;
cfsetispeed(&mode, B230400);
cfsetospeed(&mode, B230400);
@ -458,7 +481,7 @@ int16 XSERDPort::status(uint32 pb, uint32 dce, uint16 code)
WriteMacInt8(p + staXOffHold, 0);
WriteMacInt8(p + staRdPend, read_pending);
WriteMacInt8(p + staWrPend, write_pending);
if (is_parallel) {
if (protocol != serial) {
WriteMacInt8(p + staCtsHold, 0);
WriteMacInt8(p + staDsrHold, 0);
WriteMacInt8(p + staModemStatus, dsrEvent | dcdEvent | ctsEvent);
@ -509,10 +532,66 @@ int16 XSERDPort::close()
if (fd > 0)
::close(fd);
fd = -1;
// Wait for the subprocess to exit
if (pid)
waitpid(pid, NULL, 0);
pid = 0;
return noErr;
}
/*
* Open a process via ptys
*/
bool XSERDPort::open_pty(void)
{
// Talk to a process via a pty
char slave[128];
int slavefd;
protocol = pty;
if (!pty_allocate(&fd, &slavefd, slave, sizeof(slave)))
return false;
fflush(stdout);
fflush(stderr);
switch (pid = fork()) {
case -1: // error
return false;
break;
case 0: // child
::close(fd);
/* Make the pseudo tty our controlling tty. */
pty_make_controlling_tty(&slavefd, slave);
::close(0); dup(slavefd); // Use the slave fd for stdin,
::close(1); dup(slavefd); // stdout,
::close(2); dup(slavefd); // and stderr.
// <should we be more paranoid about closing unused fds?>
// <should we drop privileges if running setuid?>
// Let the shell do the dirty work
execlp("/bin/sh", "/bin/sh", "-c", ++device_name, 0);
// exec failed!
printf("serial_open: could not exec %s: %s\n",
"/bin/sh", strerror(errno));
exit(1);
break;
default: // parent
// Pid was stored above
break;
}
return true;
}
/*
* Configure serial port with MacOS config word
*/
@ -520,7 +599,7 @@ int16 XSERDPort::close()
bool XSERDPort::configure(uint16 config)
{
D(bug(" configure %04x\n", config));
if (is_parallel)
if (protocol != serial)
return true;
// Set number of stop bits
@ -604,7 +683,7 @@ void XSERDPort::set_handshake(uint32 s, bool with_dtr)
D(bug(" set_handshake %02x %02x %02x %02x %02x %02x %02x %02x\n",
ReadMacInt8(s + 0), ReadMacInt8(s + 1), ReadMacInt8(s + 2), ReadMacInt8(s + 3),
ReadMacInt8(s + 4), ReadMacInt8(s + 5), ReadMacInt8(s + 6), ReadMacInt8(s + 7)));
if (is_parallel)
if (protocol != serial)
return;
if (with_dtr) {

View File

@ -0,0 +1,470 @@
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved
* Allocating a pseudo-terminal, and making it the controlling tty.
*
* As far as I am concerned, the code I have written for this software
* can be used freely for any purpose. Any derived versions of this
* software must be clearly marked as such, and if the derived work is
* incompatible with the protocol description in the RFC file, it must be
* called by a name other than "ssh" or "Secure Shell".
*/
#if 0 /* not in BasiliskII */
#include "includes.h"
RCSID("$OpenBSD: sshpty.c,v 1.4 2001/12/19 07:18:56 deraadt Exp $");
#else /* not in BasiliskII */
/* Selections from openssh's "includes.h" */
#include "config.h"
#include <stdio.h>
#include <ctype.h>
#include <errno.h>
#include <fcntl.h> /* For O_NONBLOCK */
#include <stdlib.h>
#include <string.h>
#include <pwd.h>
#include <unistd.h> /* For STDIN_FILENO, etc */
#include <termios.h> /* Struct winsize */
/*
*-*-nto-qnx needs these headers for strcasecmp and LASTLOG_FILE respectively
*/
#ifdef HAVE_STRINGS_H
# include <strings.h>
#endif
#ifdef HAVE_LOGIN_H
# include <login.h>
#endif
#include <sys/ioctl.h>
#ifdef HAVE_SYS_BSDTTY_H
# include <sys/bsdtty.h>
#endif
#ifdef HAVE_SYS_STAT_H
# include <sys/stat.h> /* For S_* constants and macros */
#endif
#ifndef _PATH_TTY
# define _PATH_TTY "/dev/tty"
#endif
#include "strlcpy.h"
#define debug(x) ;
#endif /* not in BasiliskII */
#ifdef HAVE_UTIL_H
# include <util.h>
#endif /* HAVE_UTIL_H */
#include "sshpty.h"
#if 0 /* not in BasiliskII */
#include "log.h"
#include "misc.h"
#else /* stubs for BasiliskII */
#define error printf
#define fatal(x) {printf("Fatal error: %s", x); return 0}
#endif /* not in BasiliskII */
/* Pty allocated with _getpty gets broken if we do I_PUSH:es to it. */
#if defined(HAVE__GETPTY) || defined(HAVE_OPENPTY)
#undef HAVE_DEV_PTMX
#endif
#ifdef HAVE_PTY_H
# include <pty.h>
#endif
#if defined(HAVE_DEV_PTMX) && defined(HAVE_SYS_STROPTS_H)
# include <sys/stropts.h>
#endif
#ifndef O_NOCTTY
#define O_NOCTTY 0
#endif
/*
* Allocates and opens a pty. Returns 0 if no pty could be allocated, or
* nonzero if a pty was successfully allocated. On success, open file
* descriptors for the pty and tty sides and the name of the tty side are
* returned (the buffer must be able to hold at least 64 characters).
*/
int
pty_allocate(int *ptyfd, int *ttyfd, char *namebuf, int namebuflen)
{
#if defined(HAVE_OPENPTY) || defined(BSD4_4)
/* openpty(3) exists in OSF/1 and some other os'es */
char *name;
int i;
i = openpty(ptyfd, ttyfd, NULL, NULL, NULL);
if (i < 0) {
error("openpty: %.100s", strerror(errno));
return 0;
}
name = ttyname(*ttyfd);
if (!name)
fatal("openpty returns device for which ttyname fails.");
strlcpy(namebuf, name, namebuflen); /* possible truncation */
return 1;
#else /* HAVE_OPENPTY */
#ifdef HAVE__GETPTY
/*
* _getpty(3) exists in SGI Irix 4.x, 5.x & 6.x -- it generates more
* pty's automagically when needed
*/
char *slave;
slave = _getpty(ptyfd, O_RDWR, 0622, 0);
if (slave == NULL) {
error("_getpty: %.100s", strerror(errno));
return 0;
}
strlcpy(namebuf, slave, namebuflen);
/* Open the slave side. */
*ttyfd = open(namebuf, O_RDWR | O_NOCTTY);
if (*ttyfd < 0) {
error("%.200s: %.100s", namebuf, strerror(errno));
close(*ptyfd);
return 0;
}
return 1;
#else /* HAVE__GETPTY */
#if defined(HAVE_DEV_PTMX)
/*
* This code is used e.g. on Solaris 2.x. (Note that Solaris 2.3
* also has bsd-style ptys, but they simply do not work.)
*/
int ptm;
char *pts;
mysig_t old_signal;
ptm = open("/dev/ptmx", O_RDWR | O_NOCTTY);
if (ptm < 0) {
error("/dev/ptmx: %.100s", strerror(errno));
return 0;
}
old_signal = mysignal(SIGCHLD, SIG_DFL);
if (grantpt(ptm) < 0) {
error("grantpt: %.100s", strerror(errno));
return 0;
}
mysignal(SIGCHLD, old_signal);
if (unlockpt(ptm) < 0) {
error("unlockpt: %.100s", strerror(errno));
return 0;
}
pts = ptsname(ptm);
if (pts == NULL)
error("Slave pty side name could not be obtained.");
strlcpy(namebuf, pts, namebuflen);
*ptyfd = ptm;
/* Open the slave side. */
*ttyfd = open(namebuf, O_RDWR | O_NOCTTY);
if (*ttyfd < 0) {
error("%.100s: %.100s", namebuf, strerror(errno));
close(*ptyfd);
return 0;
}
#ifndef HAVE_CYGWIN
/*
* Push the appropriate streams modules, as described in Solaris pts(7).
* HP-UX pts(7) doesn't have ttcompat module.
*/
if (ioctl(*ttyfd, I_PUSH, "ptem") < 0)
error("ioctl I_PUSH ptem: %.100s", strerror(errno));
if (ioctl(*ttyfd, I_PUSH, "ldterm") < 0)
error("ioctl I_PUSH ldterm: %.100s", strerror(errno));
#ifndef __hpux
if (ioctl(*ttyfd, I_PUSH, "ttcompat") < 0)
error("ioctl I_PUSH ttcompat: %.100s", strerror(errno));
#endif
#endif
return 1;
#else /* HAVE_DEV_PTMX */
#ifdef HAVE_DEV_PTS_AND_PTC
/* AIX-style pty code. */
const char *name;
*ptyfd = open("/dev/ptc", O_RDWR | O_NOCTTY);
if (*ptyfd < 0) {
error("Could not open /dev/ptc: %.100s", strerror(errno));
return 0;
}
name = ttyname(*ptyfd);
if (!name)
fatal("Open of /dev/ptc returns device for which ttyname fails.");
strlcpy(namebuf, name, namebuflen);
*ttyfd = open(name, O_RDWR | O_NOCTTY);
if (*ttyfd < 0) {
error("Could not open pty slave side %.100s: %.100s",
name, strerror(errno));
close(*ptyfd);
return 0;
}
return 1;
#else /* HAVE_DEV_PTS_AND_PTC */
#ifdef _CRAY
char buf[64];
int i;
int highpty;
#ifdef _SC_CRAY_NPTY
highpty = sysconf(_SC_CRAY_NPTY);
if (highpty == -1)
highpty = 128;
#else
highpty = 128;
#endif
for (i = 0; i < highpty; i++) {
snprintf(buf, sizeof(buf), "/dev/pty/%03d", i);
*ptyfd = open(buf, O_RDWR|O_NOCTTY);
if (*ptyfd < 0)
continue;
snprintf(namebuf, namebuflen, "/dev/ttyp%03d", i);
/* Open the slave side. */
*ttyfd = open(namebuf, O_RDWR|O_NOCTTY);
if (*ttyfd < 0) {
error("%.100s: %.100s", namebuf, strerror(errno));
close(*ptyfd);
return 0;
}
return 1;
}
return 0;
#else
/* BSD-style pty code. */
char buf[64];
int i;
const char *ptymajors = "pqrstuvwxyzabcdefghijklmnoABCDEFGHIJKLMNOPQRSTUVWXYZ";
const char *ptyminors = "0123456789abcdef";
int num_minors = strlen(ptyminors);
int num_ptys = strlen(ptymajors) * num_minors;
struct termios tio;
for (i = 0; i < num_ptys; i++) {
snprintf(buf, sizeof buf, "/dev/pty%c%c", ptymajors[i / num_minors],
ptyminors[i % num_minors]);
snprintf(namebuf, namebuflen, "/dev/tty%c%c",
ptymajors[i / num_minors], ptyminors[i % num_minors]);
*ptyfd = open(buf, O_RDWR | O_NOCTTY);
if (*ptyfd < 0) {
/* Try SCO style naming */
snprintf(buf, sizeof buf, "/dev/ptyp%d", i);
snprintf(namebuf, namebuflen, "/dev/ttyp%d", i);
*ptyfd = open(buf, O_RDWR | O_NOCTTY);
if (*ptyfd < 0)
continue;
}
/* Open the slave side. */
*ttyfd = open(namebuf, O_RDWR | O_NOCTTY);
if (*ttyfd < 0) {
error("%.100s: %.100s", namebuf, strerror(errno));
close(*ptyfd);
return 0;
}
/* set tty modes to a sane state for broken clients */
if (tcgetattr(*ptyfd, &tio) < 0)
log("Getting tty modes for pty failed: %.100s", strerror(errno));
else {
tio.c_lflag |= (ECHO | ISIG | ICANON);
tio.c_oflag |= (OPOST | ONLCR);
tio.c_iflag |= ICRNL;
/* Set the new modes for the terminal. */
if (tcsetattr(*ptyfd, TCSANOW, &tio) < 0)
log("Setting tty modes for pty failed: %.100s", strerror(errno));
}
return 1;
}
return 0;
#endif /* CRAY */
#endif /* HAVE_DEV_PTS_AND_PTC */
#endif /* HAVE_DEV_PTMX */
#endif /* HAVE__GETPTY */
#endif /* HAVE_OPENPTY */
}
/* Releases the tty. Its ownership is returned to root, and permissions to 0666. */
void
pty_release(const char *ttyname)
{
if (chown(ttyname, (uid_t) 0, (gid_t) 0) < 0)
error("chown %.100s 0 0 failed: %.100s", ttyname, strerror(errno));
if (chmod(ttyname, (mode_t) 0666) < 0)
error("chmod %.100s 0666 failed: %.100s", ttyname, strerror(errno));
}
/* Makes the tty the processes controlling tty and sets it to sane modes. */
void
pty_make_controlling_tty(int *ttyfd, const char *ttyname)
{
int fd;
#ifdef USE_VHANGUP
void *old;
#endif /* USE_VHANGUP */
#ifdef _CRAY
if (setsid() < 0)
error("setsid: %.100s", strerror(errno));
fd = open(ttyname, O_RDWR|O_NOCTTY);
if (fd != -1) {
mysignal(SIGHUP, SIG_IGN);
ioctl(fd, TCVHUP, (char *)NULL);
mysignal(SIGHUP, SIG_DFL);
setpgid(0, 0);
close(fd);
} else {
error("Failed to disconnect from controlling tty.");
}
debug("Setting controlling tty using TCSETCTTY.");
ioctl(*ttyfd, TCSETCTTY, NULL);
fd = open("/dev/tty", O_RDWR);
if (fd < 0)
error("%.100s: %.100s", ttyname, strerror(errno));
close(*ttyfd);
*ttyfd = fd;
#else /* _CRAY */
/* First disconnect from the old controlling tty. */
#ifdef TIOCNOTTY
fd = open(_PATH_TTY, O_RDWR | O_NOCTTY);
if (fd >= 0) {
(void) ioctl(fd, TIOCNOTTY, NULL);
close(fd);
}
#endif /* TIOCNOTTY */
if (setsid() < 0)
error("setsid: %.100s", strerror(errno));
/*
* Verify that we are successfully disconnected from the controlling
* tty.
*/
fd = open(_PATH_TTY, O_RDWR | O_NOCTTY);
if (fd >= 0) {
error("Failed to disconnect from controlling tty.");
close(fd);
}
/* Make it our controlling tty. */
#ifdef TIOCSCTTY
debug("Setting controlling tty using TIOCSCTTY.");
if (ioctl(*ttyfd, TIOCSCTTY, NULL) < 0)
error("ioctl(TIOCSCTTY): %.100s", strerror(errno));
#endif /* TIOCSCTTY */
#ifdef HAVE_NEWS4
if (setpgrp(0,0) < 0)
error("SETPGRP %s",strerror(errno));
#endif /* HAVE_NEWS4 */
#ifdef USE_VHANGUP
old = mysignal(SIGHUP, SIG_IGN);
vhangup();
mysignal(SIGHUP, old);
#endif /* USE_VHANGUP */
fd = open(ttyname, O_RDWR);
if (fd < 0) {
error("%.100s: %.100s", ttyname, strerror(errno));
} else {
#ifdef USE_VHANGUP
close(*ttyfd);
*ttyfd = fd;
#else /* USE_VHANGUP */
close(fd);
#endif /* USE_VHANGUP */
}
/* Verify that we now have a controlling tty. */
fd = open(_PATH_TTY, O_WRONLY);
if (fd < 0)
error("open /dev/tty failed - could not set controlling tty: %.100s",
strerror(errno));
else {
close(fd);
}
#endif /* _CRAY */
}
#if 0 /* not in BasiliskII */
/* Changes the window size associated with the pty. */
void
pty_change_window_size(int ptyfd, int row, int col,
int xpixel, int ypixel)
{
struct winsize w;
w.ws_row = row;
w.ws_col = col;
w.ws_xpixel = xpixel;
w.ws_ypixel = ypixel;
(void) ioctl(ptyfd, TIOCSWINSZ, &w);
}
void
pty_setowner(struct passwd *pw, const char *ttyname)
{
struct group *grp;
gid_t gid;
mode_t mode;
struct stat st;
/* Determine the group to make the owner of the tty. */
grp = getgrnam("tty");
if (grp) {
gid = grp->gr_gid;
mode = S_IRUSR | S_IWUSR | S_IWGRP;
} else {
gid = pw->pw_gid;
mode = S_IRUSR | S_IWUSR | S_IWGRP | S_IWOTH;
}
/*
* Change owner and mode of the tty as required.
* Warn but continue if filesystem is read-only and the uids match/
* tty is owned by root.
*/
if (stat(ttyname, &st))
fatal("stat(%.100s) failed: %.100s", ttyname,
strerror(errno));
if (st.st_uid != pw->pw_uid || st.st_gid != gid) {
if (chown(ttyname, pw->pw_uid, gid) < 0) {
if (errno == EROFS &&
(st.st_uid == pw->pw_uid || st.st_uid == 0))
error("chown(%.100s, %d, %d) failed: %.100s",
ttyname, pw->pw_uid, gid,
strerror(errno));
else
fatal("chown(%.100s, %d, %d) failed: %.100s",
ttyname, pw->pw_uid, gid,
strerror(errno));
}
}
if ((st.st_mode & (S_IRWXU|S_IRWXG|S_IRWXO)) != mode) {
if (chmod(ttyname, mode) < 0) {
if (errno == EROFS &&
(st.st_mode & (S_IRGRP | S_IROTH)) == 0)
error("chmod(%.100s, 0%o) failed: %.100s",
ttyname, mode, strerror(errno));
else
fatal("chmod(%.100s, 0%o) failed: %.100s",
ttyname, mode, strerror(errno));
}
}
}
#endif /* not in BasiliskII */

View File

@ -0,0 +1,26 @@
/* $OpenBSD: sshpty.h,v 1.4 2002/03/04 17:27:39 stevesk Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved
* Functions for allocating a pseudo-terminal and making it the controlling
* tty.
*
* As far as I am concerned, the code I have written for this software
* can be used freely for any purpose. Any derived versions of this
* software must be clearly marked as such, and if the derived work is
* incompatible with the protocol description in the RFC file, it must be
* called by a name other than "ssh" or "Secure Shell".
*/
#ifndef SSHPTY_H
#define SSHPTY_H
int pty_allocate(int *, int *, char *, int);
void pty_release(const char *);
void pty_make_controlling_tty(int *, const char *);
void pty_change_window_size(int, int, int, int, int);
void pty_setowner(struct passwd *, const char *);
#endif /* SSHPTY_H */

View File

@ -0,0 +1,75 @@
/* $OpenBSD: strlcpy.c,v 1.5 2001/05/13 15:40:16 deraadt Exp $ */
/*
* Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
* 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 of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "config.h"
#ifndef HAVE_STRLCPY
#if defined(LIBC_SCCS) && !defined(lint)
static char *rcsid = "$OpenBSD: strlcpy.c,v 1.5 2001/05/13 15:40:16 deraadt Exp $";
#endif /* LIBC_SCCS and not lint */
#include <sys/types.h>
#include <string.h>
#include "strlcpy.h"
/*
* Copy src to string dst of size siz. At most siz-1 characters
* will be copied. Always NUL terminates (unless siz == 0).
* Returns strlen(src); if retval >= siz, truncation occurred.
*/
size_t
strlcpy(dst, src, siz)
char *dst;
const char *src;
size_t siz;
{
register char *d = dst;
register const char *s = src;
register size_t n = siz;
/* Copy as many bytes as will fit */
if (n != 0 && --n != 0) {
do {
if ((*d++ = *s++) == 0)
break;
} while (--n != 0);
}
/* Not enough room in dst, add NUL and traverse rest of src */
if (n == 0) {
if (siz != 0)
*d = '\0'; /* NUL-terminate dst */
while (*s++)
;
}
return(s - src - 1); /* count does not include NUL */
}
#endif /* !HAVE_STRLCPY */

View File

@ -0,0 +1,12 @@
/* $Id$ */
#ifndef _BSD_STRLCPY_H
#define _BSD_STRLCPY_H
#include "config.h"
#ifndef HAVE_STRLCPY
#include <sys/types.h>
size_t strlcpy(char *dst, const char *src, size_t siz);
#endif /* !HAVE_STRLCPY */
#endif /* _BSD_STRLCPY_H */