blob: 4c517cc38aca8ed3e252294b43a5302f700ab850 [file] [log] [blame]
#ifdef aegis
char *ckxv = "Aegis Communications support, 8.0.303, 17 Apr 2004";
#else
#ifdef Plan9
char *ckxv = "Plan 9 Communications support, 8.0.303, 17 Apr 2004";
#else
char *ckxv = "UNIX Communications support, 8.0.303, 17 Apr 2004";
#endif /* Plan9 */
#endif /* aegis */
/* C K U T I O */
/* C-Kermit interrupt, communications control and I/O functions for UNIX */
/*
Author: Frank da Cruz (fdc@columbia.edu),
Columbia University Academic Information Systems, New York City.
Copyright (C) 1985, 2004,
Trustees of Columbia University in the City of New York.
All rights reserved. See the C-Kermit COPYING.TXT file or the
copyright text in the ckcmai.c module for disclaimer and permissions.
*/
/*
NOTE TO CONTRIBUTORS: This file, and all the other C-Kermit files, must be
compatible with C preprocessors that support only #ifdef, #else, #endif,
#define, and #undef. Please do not use #if, logical operators, or other
preprocessor features in any of the portable C-Kermit modules. You can,
of course, use these constructions in platform-specific modules when they
are supported by all compilers/preprocessors that could be used on that
platform.
*/
extern int nettype; /* Defined in ckcmai.c */
/* Includes */
#include "ckcsym.h" /* This must go first */
#include "ckcdeb.h" /* This must go second */
#ifdef OSF13
#ifdef CK_ANSIC
#ifdef _NO_PROTO
#undef _NO_PROTO
#endif /* _NO_PROTO */
#endif /* CK_ANSIC */
#endif /* OSF13 */
#include <errno.h> /* System error numbers */
#ifdef __386BSD__
#define ENOTCONN 57
#else
#ifdef __bsdi__
#define ENOTCONN 57
#else
#ifdef __FreeBSD__
#define ENOTCONN 57
#endif /* __FreeBSD__ */
#endif /* __bsdi__ */
#endif /* __386BSD__ */
#ifdef SCO_OSR504
#define NBBY 8
#endif /* SCO_OSR504 */
#ifdef Plan9
#define SELECT
#include <sys/time.h>
#include <select.h>
#define FD_SETSIZE (3 * sizeof(long) * 8)
static struct timeval tv;
#endif /* Plan9 */
#ifdef CLIX
#include <sys/time.h>
#endif /* CLIX */
#include "ckcnet.h" /* Symbols for network types. */
#ifdef CK_SSL
#include "ck_ssl.h"
#endif /* CK_SSL */
/*
The directory-related includes are here because we need to test some
file-system-related symbols to find out which system we're being compiled
under. For example, MAXNAMLEN is defined in BSD4.2 but not 4.1.
*/
#ifdef SDIRENT /* Directory bits... */
#define DIRENT
#endif /* SDIRENT */
#ifdef XNDIR
#include <sys/ndir.h>
#else /* !XNDIR */
#ifdef NDIR
#include <ndir.h>
#else /* !NDIR, !XNDIR */
#ifdef RTU
#include "/usr/lib/ndir.h"
#else /* !RTU, !NDIR, !XNDIR */
#ifdef DIRENT
#ifdef SDIRENT
#include <sys/dirent.h>
#else
#include <dirent.h>
#endif /* SDIRENT */
#else /* !RTU, !NDIR, !XNDIR, !DIRENT, i.e. all others */
#include <sys/dir.h>
#endif /* DIRENT */
#endif /* RTU */
#endif /* NDIR */
#endif /* XNDIR */
#ifdef QNX
#include <sys/dev.h>
#endif /* QNX */
#ifdef HPUX5
#ifndef TCPSOCKET
/* I don't know why this is needed here since we never reference bzero(). */
/* But without it C-Kermit won't link in an HP-UX 5.xx non-TCP build. */
void
bzero(s,n) char *s; int n; {
extern char * memset();
memset(s,0,n);
}
#endif /* TCPSOCKET */
#endif /* HPUX5 */
/* Definition of HZ, used in msleep() */
#ifdef MIPS
#define HZ ( 1000 / CLOCK_TICK )
#else /* MIPS */
#ifdef ATTSV
#ifndef NAP
#ifdef TRS16
#define HZ ( 1000 / CLOCK_TICK )
#endif /* TRS16 */
#ifdef NAPHACK
#define nap(x) (void)syscall(3112, (x))
#define NAP
#endif /* NAPHACK */
#endif /* NAP */
#endif /* ATTSV */
#endif /* MIPS */
#ifdef M_UNIX
#undef NGROUPS_MAX /* Prevent multiple definition warnings */
#endif /* M_UNIX */
/*
NOTE: HP-UX 8.0 has a <sys/poll.h>, but there is no corresponding
library routine, so _poll comes up undefined at link time.
*/
#ifdef CK_POLL
#ifndef AIXRS /* IBM AIX needs special handling */
#include <poll.h> /* "standard" (SVID) i/o multiplexing, etc */
#else /* AIXRS */
#ifdef SVR4 /* AIX 3.2 is like SVID... */
#include <poll.h>
#else /* But AIX 3.1 is not ... */
#include <sys/poll.h> /* The include file is in include/sys */
#define events reqevents /* And it does not map IBM-specific member */
#define revents rtnevents /* names to the System V equivalents */
#endif /* SVR4 */
#endif /* AIXRS */
#endif /* CK_POLL */
#include <signal.h> /* Signals */
/* For setjmp and longjmp */
#ifndef ZILOG
#include <setjmp.h>
#else
#include <setret.h>
#endif /* ZILOG */
/*
The following test differentiates between 4.1 BSD and 4.2 & later.
If you have a 4.1BSD system with the DIRENT library, this test could
mistakenly diagnose 4.2BSD and then later enable the use of system calls
that aren't defined. If indeed there are such systems, we can use some
other way of testing for 4.1BSD, or add yet another compile-time switch.
*/
#ifdef BSD4
#ifdef MAXNAMLEN
#ifndef FT21 /* Except for Fortune. */
#ifndef FT18
#ifndef BELLV10 /* And Bell Labs Research UNIX V10 */
#define BSD42
#endif /* BELLV10 */
#endif /* FT18 */
#endif /* FT21 */
#endif /* MAXNAMLEN */
#endif /* BSD4 */
/*
Minix 2.0 support added by Terry McConnell,
Syracuse University <tmc@barnyard.syr.edu>
No more sgtty interface, posix compliant.
*/
#ifdef MINIX2
#define _MINIX /* Needed for some Minix header files */
#undef MINIX /* Old minix 1.0: used sgtty interface */
#define BSD44ORPOSIX
#define SVORPOSIX
#define DCLTIMEVAL
#define NOFILEH
#include <sys/types.h>
#include <sys/ioctl.h>
#include <termios.h>
#include <limits.h>
#undef TIOCGETC /* defined in sys/ioctl.h, but not really supported */
#define TANDEM 0
#endif /* MINIX2 */
/*
MINIX 1.0 support added by Charles Hedrick,
Rutgers University <hedrick@aramis.rutgers.edu>.
MINIX also has V7 enabled.
*/
#ifdef MINIX
#define TANDEM 0
#define MYREAD
#define NOSYSIOCTLH
#include <limits.h>
#endif /* MINIX */
#ifdef CK_REDIR /* <sys/wait.h> needed only for REDIRECT command. */
/*
If anybody can figure out how to make this work with NeXTSTEP, be
my guest! (NeXTBlah/NeXTBlah/bsd/sys/wait.h does not define WEXITSTATUS)
*/
#ifndef CK_WAIT_H /* If wait.h not already included... */
#ifdef OSF /* force OSF to select POSIX wait */
#ifdef _BSD /* instead of BSD (see ckcdeb.h) */
#define CK_OSF_BSD
#undef _BSD
#endif /* _BSD */
#endif /* OSF */
#include <sys/wait.h> /* Include it */
#ifdef OSF
#ifdef CK_OSF_BSD
#define _BSD /* Restore it */
#undef CK_OSF_BSD
#endif /* CK_OSF_BSD */
#endif /* OSF */
#endif /* CK_WAIT_H */
#endif /* CK_REDIR */
#include "ckuver.h" /* Version herald */
char *ckxsys = HERALD;
#ifdef CK_UTSNAME
#include <sys/utsname.h>
#ifdef TRU64 /* Tru64 UNIX 4.0 and later */
/* Verified on Tru64 4.0F - might break on 4.0E or earlier */
#include <sys/sysinfo.h> /* (don't know about OSF/1 or DU) */
#include <machine/hal_sysinfo.h>
#endif /* TRU64 */
#ifdef SOLARIS25 /* Solaris 2.5 and later */
#include <sys/systeminfo.h> /* (don't know about earlier ones) */
#endif /* SOLARIS25 */
#ifdef UW7
#ifndef SYS_NMLN
#define SYS_NMLN 257
#endif /* NMLN */
#endif /* UW7 */
#ifdef HPUX9PLUS
static int hpis800 = 0;
#endif /* HPUX9PLUS */
#ifdef SYS_NMLN
#define CK_SYSNMLN SYS_NMLN
#else
#ifdef _SYS_NMLN
#define CK_SYSNMLN _SYS_NMLN
#else
#ifdef UTSLEN
#define CK_SYSNMLN UTSLEN
#else
#define CK_SYSNMLN 31
#endif /* UTSLEN */
#endif /* _SYS_NMLN */
#endif /* SYS_NMLN */
char unm_mch[CK_SYSNMLN+1] = { '\0', '\0' };
char unm_mod[CK_SYSNMLN+1] = { '\0', '\0' };
char unm_nam[CK_SYSNMLN+1] = { '\0', '\0' };
char unm_rel[CK_SYSNMLN+1] = { '\0', '\0' };
char unm_ver[CK_SYSNMLN+1] = { '\0', '\0' };
#endif /* CK_UTSNAME */
#ifdef CIE
#include <stat.h> /* For chasing symlinks, etc. */
#else
#include <sys/stat.h>
#endif /* CIE */
/* UUCP lockfile material... */
#ifndef NOUUCP
#ifdef USETTYLOCK
#ifdef HAVE_BAUDBOY /* Red Hat baudboy/lockdev */
#include <baudboy.h>
#else
#ifdef USE_UU_LOCK
#ifdef __FreeBSD__
#include <libutil.h> /* FreeBSD */
#else
#include <util.h> /* OpenBSD */
#endif /* HAVE_BAUDBOY */
#endif /* __FreeBSD */
#endif /* USE_UU_LOCK */
#else /* USETTYLOCK */
/* Name of UUCP tty device lockfile */
#ifdef LINUXFSSTND
#ifndef HDBUUCP
#define HDBUUCP
#endif /* HDBUUCP */
#endif /* LINUXFSSTND */
#ifdef ACUCNTRL
#define LCKDIR
#endif /* ACUCNTRL */
/*
PIDSTRING means use ASCII string to represent pid in lockfile.
*/
#ifndef PIDSTRING
#ifdef HDBUUCP
#define PIDSTRING
#else
#ifdef BSD44
#define PIDSTRING
#else
#ifdef RTAIX
#define PIDSTRING
#else
#ifdef AIXRS
#define PIDSTRING
#else
#ifdef COHERENT
#define PIDSTRING
#endif /* COHERENT */
#endif /* AIXRS */
#endif /* RTAIX */
#endif /* BSD44 */
#endif /* HDBUUCP */
#endif /* PIDSTRING */
/* Now the PIDSTRING exceptions... */
#ifdef PIDSTRING
#ifdef HPUX
#undef PIDSTRING
#endif /* HPUX */
#endif /* PIDSTRING */
#ifdef __bsdi__ /* BSDI (at least thru 1.1) */
#ifdef PIDSTRING
#undef PIDSTRING
#endif /* PIDSTRING */
#endif /* __bsdi__ */
#ifdef OSF32 /* Digital UNIX (OSF/1) 3.2 */
#ifdef PIDSTRING
#undef PIDSTRING
#endif /* PIDSTRING */
#endif /* OSF32 */
/*
LOCK_DIR is the name of the lockfile directory.
If LOCK_DIR is already defined (e.g. on command line), we don't change it.
*/
#ifndef LOCK_DIR
#ifdef MACOSX
#define LOCK_DIR "/var/spool/lock"
#endif /* MACOSX */
#endif/* LOCK_DIR */
#ifndef LOCK_DIR
#ifdef BSD44
#ifdef __386BSD__
#define LOCK_DIR "/var/spool/lock"
#else
#ifdef __FreeBSD__
#define LOCK_DIR "/var/spool/lock"
#else
#ifdef __NetBSD__
#define LOCK_DIR "/var/spool/lock"
#else
#ifdef __OpenBSD__
#define LOCK_DIR "/var/spool/lock"
#else
/* So which ones is this for? */
/* Probably original 4.4BSD on Vangogh */
/* Plus who knows about Mac OS X... It doesn't even have a cu program */
#define LOCK_DIR "/var/spool/uucp"
#endif /* __OpenBSD__ */
#endif /* __NetBSD__ */
#endif /* __FreeBSD__ */
#endif /* __386BSD__ */
#else
#ifdef DGUX430
#define LOCK_DIR "/var/spool/locks"
#else
#ifdef HPUX10
#define LOCK_DIR "/var/spool/locks"
#else
#ifdef RTAIX /* IBM RT PC AIX 2.2.1 */
#define LOCK_DIR "/etc/locks"
#else
#ifdef AIXRS
#define LOCK_DIR "/etc/locks"
#else
#ifdef ISIII
#define LOCK_DIR "/etc/locks"
#else
#ifdef HDBUUCP
#ifdef M_SYS5
#define LOCK_DIR "/usr/spool/uucp"
#else
#ifdef M_UNIX
#define LOCK_DIR "/usr/spool/uucp"
#else
#ifdef SVR4
#define LOCK_DIR "/var/spool/locks"
#else
#ifdef SUNOS4
#define LOCK_DIR "/var/spool/locks"
#else
#ifdef LINUXFSSTND
#define LOCK_DIR "/var/lock";
#else
#define LOCK_DIR "/usr/spool/locks"
#endif /* LINUXFSSTND */
#endif /* SUNOS4 */
#endif /* SVR4 */
#endif /* M_UNIX */
#endif /* M_SYS5 */
#else
#ifdef LCKDIR
#define LOCK_DIR "/usr/spool/uucp/LCK"
#else
#ifdef COHERENT
#define LOCK_DIR "/usr/spool/uucp"
#else
#define LOCK_DIR "/usr/spool/uucp"
#endif /* COHERENT */
#endif /* LCKDIR */
#endif /* HDBUUCP */
#endif /* ISIII */
#endif /* AIXRS */
#endif /* RTAIX */
#endif /* HPUX10 */
#endif /* DGUX430 */
#endif /* BSD44 */
#endif /* !LOCK_DIR (outside ifndef) */
#ifdef OSF2 /* OSF/1 2.0 or later */
#ifdef LOCK_DIR /* (maybe 1.x too, who knows...) */
#undef LOCK_DIR
#define LOCK_DIR "/var/spool/locks"
#endif /* LOCK_DIR */
#endif /* OSF2 */
#ifdef COMMENT
/* Sorry no more lockf() -- we lock first and THEN open the device. */
#ifdef SVR4
#ifndef BSD44
#ifndef LOCKF
#define LOCKF /* Use lockf() on tty device in SVR4 */
#endif /* LOCKF */
#endif /* BSD44 */
#endif /* SVR4 */
#endif /* COMMENT */
#ifdef NOLOCKF /* But NOLOCKF cancels LOCKF */
#ifdef LOCKF
#undef LOCKF
#endif /* LOCKF */
#endif /* NOLOCKF */
/* More about this below... */
#endif /* USETTYLOCK */
#endif /* NOUUCP */
/*
MYREAD means use our internally defined nonblocking buffered read routine.
*/
#ifdef ATTSV
#define MYREAD
#endif /* ATTSV */
#ifdef ATT7300
#ifndef MYREAD
#define MYREAD
#endif /* MYREAD */
/* bits for attmodem: internal modem in use, restart getty */
#define ISMODEM 1
#define DOGETY 512
#endif /* ATT7300 */
#ifdef BSD42
#define MYREAD
#endif /* BSD42 */
#ifdef POSIX
#define MYREAD
#endif /* POSIX */
#ifdef __bsdi__
#ifndef O_NDELAY
#define O_NDELAY O_NONBLOCK
#endif /* O_NDELAY */
#endif /* __bsdi__ */
/*
Variables available to outside world:
dftty -- Pointer to default tty name string, like "/dev/tty".
dfloc -- 0 if dftty is console, 1 if external line.
dfprty -- Default parity
dfflow -- Default flow control
ckxech -- Flag for who echoes console typein:
1 - The program (system echo is turned off)
0 - The system (or front end, or terminal).
functions that want to do their own echoing should check this flag
before doing so.
flfnam -- Name of lock file, including its path, e.g.,
"/usr/spool/uucp/LCK..cul0" or "/etc/locks/tty77"
lkflfn -- Name of link to lock file, including its paths
haslock -- Flag set if this kermit established a uucp lock.
lockpid -- PID of other process that has desired line open, as string.
backgrd -- Flag indicating program executing in background ( & on
end of shell command). Used to ignore INT and QUIT signals.
rtu_bug -- Set by stptrap(). RTU treats ^Z as EOF (but only when we handle
SIGTSTP)
Functions for assigned communication line (either external or console tty):
sysinit() -- System dependent program initialization
syscleanup() -- System dependent program shutdown
ttopen(ttname,local,mdmtyp,timo) -- Open the named tty for exclusive access.
ttclos() -- Close & reset the tty, releasing any access lock.
ttsspd(cps) -- Set the transmission speed of the tty.
ttgspd() -- Get (read) the the transmission speed of the tty.
ttpkt(speed,flow,parity) -- Put the tty in packet mode and set the speed.
ttvt(speed,flow) -- Put the tty in virtual terminal mode.
or in DIALING or CONNECTED modem control state.
ttres() -- Restore original tty modes.
ttscarr(carrier) -- Set carrier control mode, on/off/auto.
ttinl(dest,max,timo) -- Timed read line from the tty.
ttinc(timo) -- Timed read character from tty.
myread() -- Raw mode bulk buffer read, gives subsequent
chars one at a time and simulates FIONREAD.
myunrd(c) -- Places c back in buffer to be read (one only)
ttchk() -- See how many characters in tty input buffer.
ttxin(n,buf) -- Read n characters from tty (untimed).
ttol(string,length) -- Write a string to the tty.
ttoc(c) -- Write a character to the tty.
ttflui() -- Flush tty input buffer.
ttsndb() -- Send BREAK signal.
ttsndlb() -- Send Long BREAK signal.
ttlock(ttname) -- "Lock" tty device against uucp collisions.
ttunlck() -- Unlock tty device.
For ATT7300/Unix PC, System V:
attdial(ttname,speed,telnbr) -- dials ATT7300/Unix PC internal modem
offgetty(ttname) -- Turns off getty(1m) for comms line
ongetty(ttname) -- Restores getty() to comms line
*/
/*
Functions for console terminal:
congm() -- Get console terminal modes.
concb(esc) -- Put the console in single-character wakeup mode with no echo.
conbin(esc) -- Put the console in binary (raw) mode.
conres() -- Restore the console to mode obtained by congm().
conoc(c) -- Unbuffered output, one character to console.
conol(s) -- Unbuffered output, null-terminated string to the console.
conola(s) -- Unbuffered output, array of strings to the console.
conxo(n,s) -- Unbuffered output, n characters to the console.
conchk() -- Check if characters available at console (bsd 4.2).
Check if escape char (^\) typed at console (System III/V).
coninc(timo) -- Timed get a character from the console.
congks(timo) -- Timed get keyboard scan code.
conint() -- Enable terminal interrupts on the console if not background.
connoi() -- Disable terminal interrupts on the console if not background.
Time functions
msleep(m) -- Millisecond sleep
ztime(&s) -- Return pointer to date/time string
rtimer() -- Reset timer
gtimer() -- Get elapsed time since last call to rtimer()
*/
/* Conditional Includes */
/* Whether to include <sys/file.h> */
#ifdef RTU /* RTU doesn't */
#define NOFILEH
#endif /* RTU */
#ifdef CIE /* CIE does. */
#undef NOFILEH
#endif /* CIE */
#ifdef BSD41 /* 4.1 BSD doesn't */
#define NOFILEH
#endif /* BSD41 */
#ifdef is68k /* Integrated Solutions 68000 UNIX */
#define NOFILEH /* e.g. on Plexux P60 and Sun-1 */
#endif /* is68k */
#ifdef MINIX /* MINIX */
#define NOFILEH
#endif /* MINIX */
#ifdef COHERENT /* Coherent */
#define NOFILEH
#endif /* COHERENT */
#ifndef NOFILEH /* Now include if selected. */
#include <sys/file.h>
#endif /* NOFILEH */
/* POSIX */
#ifdef BSD44ORPOSIX /* POSIX uses termios.h */
#define TERMIOS
#ifdef __bsdi__
#ifdef POSIX
#undef _POSIX_SOURCE /* Get extra stuff from termios.h */
#endif /* POSIX */
#endif /* __bsdi__ */
#include <termios.h>
#ifdef LINUX
#include <sys/ioctl.h>
#endif /* LINUX */
#ifdef QNX16
#include <ioctl.h>
#else
#ifdef QNX6
#include <ioctl.h>
#endif /* QNX6 */
#endif /* QNX16 */
#ifdef __bsdi__
#ifdef POSIX
#define _POSIX_SOURCE
#endif /* POSIX */
#endif /* __bsdi__ */
#ifndef BSD44 /* Really POSIX */
#ifndef CK_QNX32 /* was CK_QNX32 */
#define NOSYSIOCTLH /* No ioctl's allowed. */
#undef ultrix /* Turn off any ultrix features. */
#endif /* CK_QNX32 */
#endif /* BSD44 */
#endif /* POSIX */
/* System III, System V */
#ifdef ATTSV
#ifndef BSD44
#ifndef POSIX
#include <termio.h>
#endif /* POSIX */
#endif /* BSD44 */
#ifdef TERMIOX
/* Need this for termiox structure, RTS/CTS and DTR/CD flow control */
#include <termiox.h>
struct termiox rctsx;
#else
#ifdef STERMIOX
#ifdef SCO_OSR504
/* Sorry, this is truly disgusting but it's SCO's fault. */
#ifndef _SVID3
#define _CK_SVID3_X
#define _SVID3
#endif /* _SVID3 */
#endif /* SCO_OSR504 */
#include <sys/termiox.h>
struct termiox rctsx;
#ifdef CK_SVID3_X
#undef _SVID3
#undef CK_SVID3_X
#endif /* CK_SVID3_X */
#endif /* STERMIOX */
#endif /* TERMIOX */
#endif /* ATTSV */
#ifdef COHERENT /* Use termio.h, not sgtty.h for Coherent */
#include <termio.h>
#endif /* COHERENT */
#ifdef MINIX /* MINIX uses ioctl's */
#define NOSYSIOCTLH /* but has no <sys/ioctl.h> */
#endif /* MINIX */
/* Others */
#ifndef NOSYSIOCTLH /* Others use ioctl() */
#ifdef SUN4S5
/*
This is to get rid of cpp warning messages that occur because all of
these symbols are defined by both termios.h and ioctl.h on the SUN.
*/
#undef ECHO
#undef NL0
#undef NL1
#undef TAB0
#undef TAB1
#undef TAB2
#undef XTABS
#undef CR0
#undef CR1
#undef CR2
#undef CR3
#undef FF0
#undef FF1
#undef BS0
#undef BS1
#undef TOSTOP
#undef FLUSHO
#undef PENDIN
#undef NOFLSH
#endif /* SUN4S5 */
#include <sys/ioctl.h>
#endif /* NOSYSIOCTLH */
/*
We really, really, REALLY want FIONREAD, because it is the only way to find
out not just *if* stuff is waiting to be read, but how much, which is
critical to our sliding-window and streaming procedures, not to mention
efficiency of CONNECT, etc.
*/
#ifdef BELLV10
#include <sys/filio.h> /* For FIONREAD */
#ifdef FIONREAD
#define MYREAD
#endif /* MYREAD */
#endif /* BELLV10 */
#ifndef FIONREAD
/* It wasn't found in ioctl.h or term*.h - try these places: */
#ifdef UNIXWARE
#include <sys/filio.h>
#else
#ifdef SOLARIS
#include <sys/filio.h>
#endif /* SOLARIS */
#endif /* UNIXWARE */
#endif /* FIONREAD */
#ifdef XENIX /* Was M_UNIX but XENIX implies M_UNIX and applies to XENIX too */
/*
<sys/socket.h> included above via "ckcnet.h" defines FIONREAD as
something. Due to this, in_chk() uses the FIONREAD instead of RDCHK
and the hot keys during file transfer (X to cancel file etc) do not
work because FIONREAD doesn't work even though it is defined.
NOTE: This might also be true elsewhere.
*/
#ifdef FIONREAD
#undef FIONREAD
#endif /* FIONREAD */
#endif /* XENIX */
#ifdef CK_SCOV5 /* Ditto for SCO OpenServer 5.0 */
#ifdef FIONREAD
#undef FIONREAD
#endif /* FIONREAD */
#endif /* XENIX */
/* Whether to include <fcntl.h> */
#ifndef is68k /* Only a few don't have this one. */
#ifndef BSD41
#ifndef FT21
#ifndef FT18
#ifndef COHERENT
#include <fcntl.h>
#endif /* COHERENT */
#endif /* FT18 */
#endif /* FT21 */
#endif /* BSD41 */
#endif /* not is68k */
#ifdef COHERENT
#ifdef _I386
#include <fcntl.h>
#else
#include <sys/fcntl.h>
#endif /* _I386 */
#endif /* COHERENT */
#ifdef ATT7300 /* Unix PC, internal modem dialer */
#include <sys/phone.h>
#endif /* ATT7300 */
#ifdef HPUX /* HP-UX variations. */
#define HPUXJOBCTL
#include <sys/modem.h> /* HP-UX modem signals */
#ifdef hp9000s500 /* Model 500 */
#undef HPUXJOBCTL
#endif /* hp9000s500 */
#ifdef HPUXPRE65
#undef HPUXJOBCTL
typedef long mflag;
#endif /* HPUXPRE65 */
#ifdef HPUXJOBCTL
#include <sys/bsdtty.h> /* HP-UX Berkeley tty support */
#endif /* HPUXJOBCTL */
#endif /* HPUX */
/*
Which time.h files to include... See ckcdeb.h for defaults.
Note that 0, 1, 2, or all 3 of these can be included according to
the symbol definitions.
*/
#ifndef NOTIMEH
#ifdef TIMEH
#include <time.h>
#endif /* TIMEH */
#endif /* NOTIMEH */
#ifndef NOSYSTIMEH
#ifdef SYSTIMEH
#include <sys/time.h>
#endif /* SYSTIMEH */
#endif /* NOSYSTIMEH */
#ifndef NOSYSTIMEBH
#ifdef SYSTIMEBH
#include <sys/timeb.h>
#endif /* SYSTIMEBH */
#endif /* NOSYSTIMEBH */
#ifndef NODCLTIMEVAL
#ifdef DCLTIMEVAL
/*
In certain POSIX builds (like Unixware 7), <[sys/]time.h> refuses to
define the structs we need to access the higher speeds, so we have to
do it ourselves.
*/
struct timeval {
long tv_sec;
long tv_usec;
};
struct timezone {
int tz_minuteswest;
int tz_dsttime;
};
#endif /* DCLTIMEVAL */
#endif /* NODCLTIMEVAL */
#ifdef __linux__
/* THIS IS OBSOLETE since about Linux 0.92 */
#ifdef OLINUXHISPEED
#include <linux/serial.h>
#endif /* OLINUXHISPEED */
#ifdef __alpha__ /* Linux on DEC Alpha */
#ifndef __GLIBC__ /* But not with glibc */
#include <asm/termios.h>
#endif /* __GLIBC__ */
#endif /* __alpha__ */
#endif /* __linux__ */
#ifdef NOIEXTEN /* This is broken on some systems */
#undef IEXTEN /* like Convex/OS 9.1 */
#endif /* NOIEXTEN */
#ifndef IEXTEN /* Turn off ^O/^V processing. */
#define IEXTEN 0 /* Needed, at least, on BSDI. */
#endif /* IEXTEN */
/*
Pick up definitions needed for select() if we don't have them already.
Normally they come from <sys/types.h> but some systems get them from
<sys/select.h>... Rather than hardwire all of them into the source, we
include it if SELECT_H is defined in compile-time CFLAGS.
*/
#ifndef SCO_OSR504
#ifdef SELECT_H
#include <sys/select.h>
#endif /* SELECT_H */
#endif /* SCO_OSR504 */
#ifdef aegis
#include "/sys/ins/base.ins.c"
#include "/sys/ins/error.ins.c"
#include "/sys/ins/ios.ins.c"
#include "/sys/ins/sio.ins.c"
#include "/sys/ins/pad.ins.c"
#include "/sys/ins/time.ins.c"
#include "/sys/ins/pfm.ins.c"
#include "/sys/ins/pgm.ins.c"
#include "/sys/ins/ec2.ins.c"
#include "/sys/ins/type_uids.ins.c"
#include <default_acl.h>
#undef TIOCEXCL
#undef FIONREAD
#endif /* aegis */
#ifdef sxaE50 /* PFU Compact A SX/A TISP V10/L50 */
#undef FIONREAD
#endif /* sxaE50 */
/* The following #defines are catch-alls for those systems */
/* that didn't have or couldn't find <file.h>... */
#ifndef FREAD
#define FREAD 0x01
#endif /* FREAD */
#ifndef FWRITE
#define FWRITE 0x10
#endif /* FWRITE */
#ifndef O_RDONLY
#define O_RDONLY 000
#endif /* O_RDONLY */
#ifdef SVORPOSIX
/*
Modem signals are also forbidden in the POSIX world. But some POSIX-based
platforms let us at them anyway if we know where to look.
*/
#ifndef NEEDMDMDEFS
/* Doesn't work for Linux */
#ifdef UNIXWARE7
#define NEEDMDMDEFS
#endif /* UNIXWARE7 */
#endif /* NEEDMDMDEFS */
#ifdef NEEDMDMDEFS
#ifndef TIOCMGET
#define TIOCMGET (('t'<<8)|29)
#endif /* TIOCMGET */
#ifndef TIOCM_DTR
#define TIOCM_DTR 0x0002
#endif /* TIOCM_DTR */
#ifndef TIOCM_RTS
#define TIOCM_RTS 0x0004
#endif /* TIOCM_RTS */
#ifndef TIOCM_CTS
#define TIOCM_CTS 0x0020
#endif /* TIOCM_CTS */
#ifndef TIOCM_CAR
#define TIOCM_CAR 0x0040
#endif /* TIOCM_CAR */
#ifndef TIOCM_RNG
#define TIOCM_RNG 0x0080
#endif /* TIOCM_RNG */
#ifndef TIOCM_DSR
#define TIOCM_DSR 0x0100
#endif /* TIOCM_DSR */
#endif /* NEEDMDMDEFS */
#endif /* SVORPOSIX */
/* Declarations */
#ifdef OXOS
#undef TCGETA
#undef TCSETA
#undef TCSETAW
#undef TCSETAF
#define TCGETA TCGETS
#define TCSETA TCSETS
#define TCSETAW TCSETSW
#define TCSETAF TCSETSF
#define termio termios
#endif /* OXOS */
#ifdef SVORPOSIX /* AT&T Sys V or POSIX */
#ifdef UNIXWAREPOSIX /* UnixWare 7 POSIX build */
/*
In Unixware POSIX builds, <[sys/]time.h> refuses to define the
structs we need to access the higher speeds, so we have to do it
ourselves.
*/
struct timeval {
long tv_sec;
long tv_usec;
};
struct timezone {
int tz_minuteswest;
int tz_dsttime;
};
#endif /* UNIXWAREPOSIX */
#endif /* SVORPOSIX */
#ifdef __GNUC__
#ifdef XENIX
/*
Because Xenix <time.h> doesn't declare time() if we're using gcc.
*/
time_t time();
#endif /* XENIX */
#endif /* __GNUC__ */
/* Special stuff for V7 input buffer peeking */
#ifdef V7
int kmem[2] = { -1, -1};
char *initrawq(), *qaddr[2]={0,0};
#define CON 0
#define TTY 1
#endif /* V7 */
/* dftty is the device name of the default device for file transfer */
/* dfloc is 0 if dftty is the user's console terminal, 1 if an external line */
#ifdef BEOS
char * dftty = NULL;
char * dfmdm = "none";
int dfloc = 0; /* that goes in local mode by default */
#else
#ifndef DFTTY
#ifdef PROVX1
char *dftty = "/dev/com1.dout"; /* Only example so far of a system */
char *dfmdm = "none";
int dfloc = 1; /* that goes in local mode by default */
#else
char *dftty = CTTNAM; /* Remote by default, use normal */
char *dfmdm = "none";
int dfloc = 0; /* controlling terminal name. */
#endif /* PROVX1 */
#else
char *dftty = DFTTY; /* Default location specified on */
char *dfmdm = "none"; /* command line. */
int dfloc = 1; /* controlling terminal name. */
#endif /* DFTTY */
#endif /* BEOS */
#define CON_RES 0 /* Console state is "reset" */
#define CON_CB 1 /* Console state is CBREAK */
#define CON_BIN 2 /* Console state is binary */
static int constate = CON_RES;
#define CONI_RES 0 /* Console interrupts are "reset" */
#define CONI_INT 1 /* Console intterupts are set */
#define CONI_NOI 2 /* Console intterupts are disabled */
static int conistate = CONI_RES;
#ifdef CK_SMALL
#define CONBUFSIZ 15
#else
#define CONBUFSIZ 255
#endif /* CK_SMALL */
static char conbuf[CONBUFSIZ]; /* Console readahead buffer */
static int conbufn = 0; /* Chars in readahead buffer */
static char *conbufp = conbuf; /* Next char in readahead buffer */
char cttnam[DEVNAMLEN+1] = { '\0', '\0' }; /* Determined at runtime */
#ifdef RTU
int rtu_bug = 0; /* set to 1 when returning from SIGTSTP */
#endif /* RTU */
int dfprty = DEFPAR; /* Default parity (0 = none) */
int ttprty = 0; /* The parity that is in use. */
static int ttpmsk = 0xff; /* Parity stripping mask. */
int ttmdm = 0; /* Modem in use. */
int ttcarr = CAR_AUT; /* Carrier handling mode. */
int dfflow = FLO_NONE; /* Default flow control is NONE */
int backgrd = 0; /* Assume in foreground (no '&' ) */
#ifdef F_SETFL
int iniflags = -1; /* fcntl flags for ttyfd */
#endif /* F_SETFL */
int fdflag = 0; /* Flag for redirected stdio */
int ttfdflg = 0; /* Open File descriptor was given */
int tvtflg = 0; /* Flag that ttvt has been called */
long ttspeed = -1L; /* For saving speed */
int ttflow = -9; /* For saving flow */
int ttld = -1; /* Line discipline */
#ifdef sony_news
static int km_con = -1; /* Kanji mode for console tty */
static int km_ext = -1; /* Kanji mode for external device */
#endif /* sony_news */
#ifdef PARSENSE
static int needpchk = 1; /* Need parity check */
#else
static int needpchk = 0;
#endif /* PARSENSE */
extern int stopbits; /* Stop bits */
#ifdef HWPARITY
/*
Unfortunately we must do this with global variables rather than through the
tt...() APIs to avoid changing the APIs and the many modules that use them.
If hwparity != 0, this indicates 8 data bits + parity, rather than 7 data
bits + parity or 8 data bits and no parity, and overrides the regular parity
variable, which is communicated to this module thru ttpkt(), and represented
locally by the ttprty variable.
*/
extern int hwparity; /* Hardware parity */
#endif /* HWPARITY */
#ifdef TCPSOCKET
#ifdef TCP_NODELAY
static int nodelay_sav = -1;
#endif /* TCP_NODELAY */
#endif /* TCPSOCKET */
static int sigint_ign = 0; /* SIGINT is ignored */
/*
Having this module rely on external globals is bad, but fixing this
requires overhaul of the ck*tio.c modules for all the different operating
systems supported by C-Kermit. Left for a future release.
*/
extern int ttnproto; /* Defined in ckcnet.c */
extern int ttnet; /* Defined in ckcnet.c */
extern int nopush, xfrcan, xfrchr, xfrnum; /* Defined in ckcmai.c */
extern int xsuspend, wasclosed;
extern int inserver, local;
int ckxech = 0; /* 0 if system normally echoes console characters, else 1 */
int ckmaxfiles = 0; /* Max number of open files */
#ifdef CK_ENCRYPTION /* Kerberos */
#include "ckuath.h"
extern int me_encrypt, u_encrypt;
#endif /* CK_ENCRYPTION */
/* Declarations of variables global within this module */
#ifdef TTLEBUF /* See ckcnet.h */
int ttpush = -1;
#define LEBUFSIZ 4096
static CHAR le_buf[LEBUFSIZ];
static int le_start = 0, le_end = 0, le_data = 0;
#endif /* TTLEBUF */
static int gotsigs = 0;
static time_t tcount = (time_t)0; /* Elapsed time counter */
static SIGTYP (*saval)() = NULL; /* For saving alarm() handler */
static SIGTYP (*savquit)() = NULL; /* and other signal handlers */
#ifdef SIGUSR1
static SIGTYP (*savusr1)() = NULL;
#endif /* SIGUSR1 */
#ifdef SIGUSR2
static SIGTYP (*savusr2)() = NULL;
#endif /* SIGUSR2 */
#ifdef SIGPIPE
static SIGTYP (*savpipe)() = NULL;
#endif /* SIGPIPE */
#ifdef SIGDANGER
static SIGTYP (*savdanger)() = NULL;
#endif /* SIGDANGER */
#ifndef NOJC
static SIGTYP (*jchdlr)() = NULL; /* For checking suspend handler */
#endif /* NOJC */
static int jcshell = -1; /* And flag for result */
/*
BREAKNULS is defined for systems that simulate sending a BREAK signal
by sending a bunch of NUL characters at low speed.
*/
#ifdef PROVX1
#ifndef BREAKNULS
#define BREAKNULS
#endif /* BREAKNULS */
#endif /* PROVX1 */
#ifdef V7
#ifndef BREAKNULS
#define BREAKNULS
#endif /* BREAKNULS */
#endif /* V7 */
#ifdef BREAKNULS
static char /* A string of nulls */
*brnuls = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
#endif /* BREAKNULS */
#ifdef CK_POSIX_SIG /* Longjump buffers */
static sigjmp_buf sjbuf; /* POSIX signal handling */
#else
static jmp_buf sjbuf;
#endif /* CK_POSIX_SIG */
#ifdef V7
static jmp_buf jjbuf;
#endif /* V7 */
/* static */ /* (Not static any more) */
int ttyfd = -1; /* TTY file descriptor */
int ttpipe = 0; /* NETCMD: Use pipe instead of ttyfd */
int ttpty = 0; /* NETPTY: Use pty instead of ttfyd */
#ifdef NETCMD
#ifdef NETCONN
static int pipe0[2], pipe1[2]; /* Pipes for net i/o */
#endif /* NETCONN */
static PID_T ttpid = 0; /* Process ID for fork */
static int fdin, fdout; /* File descriptors for pipe */
static FILE * ttout = NULL; /* File pointer for output pipe */
#ifdef DCLFDOPEN
/* fdopen() needs declaring because it's not declared in <stdio.h> */
_PROTOTYP( FILE * fdopen, (int, char *) );
#endif /* DCLFDOPEN */
#endif /* NETCMD */
extern int pexitstat, quiet;
#ifdef Plan9
int ttyctlfd = -1; /* TTY control channel - What? UNIX doesn't have one? */
int consctlfd = -1; /* Console control channel */
int noisefd = -1; /* tone channel */
static int ttylastspeed = -1; /* So we can lie about the speed */
#endif /* Plan9 */
int telnetfd = 0; /* File descriptor is for telnet */
#ifdef NETCONN
int x25fd = 0; /* File descriptor is for X.25 */
#endif /* NETCONN */
char lockpid[16] = { '\0', '\0' }; /* PID stored in lockfile, as string */
static int lkf = 0, /* Line lock flag */
cgmf = 0, /* Flag that console modes saved */
xlocal = 0, /* Flag for tty local or remote */
curcarr = 0; /* Carrier mode: require/ignore. */
static int netconn = 0; /* 1 if network connection active */
static char escchr; /* Escape or attn character */
#ifdef CK_SCO32V4
#include <sys/time.h>
#endif /* CK_SCO32V4 */
#ifdef HAVE_TV
static struct timeval tv; /* For getting time, from sys/time.h */
#endif /* HAVE_TV */
#ifdef HAVE_TZ
static struct timezone tz;
#endif /* HAVE_TZ */
#ifdef OSF
static struct timeb ftp; /* And from sys/timeb.h */
#endif /* OSF */
#ifdef BSD29
static long xclock; /* For getting time from sys/time.h */
static struct timeb ftp; /* And from sys/timeb.h */
#endif /* BSD29 */
#ifdef BSD41
static long xclock; /* For getting time from sys/time.h */
static struct timeb ftp; /* And from sys/timeb.h */
#endif /* BSD41 */
#ifdef BELLV10
static long xclock; /* For getting time from sys/time.h */
static struct timeb ftp; /* And from sys/timeb.h */
#endif /* BELLV10 */
#ifdef FT21
static long xclock; /* For getting time from sys/time.h */
static struct timeb ftp; /* And from sys/timeb.h */
#endif /* FT21 */
#ifdef TOWER1
static long xclock; /* For getting time from sys/time.h */
static struct timeb ftp; /* And from sys/timeb.h */
#endif /* TOWER1 */
#ifdef COHERENT
static long xclock; /* For getting time from sys/time.h */
static struct timeb ftp; /* And from sys/timeb.h */
#endif /* COHERENT */
#ifdef V7
static long xclock;
#endif /* V7 */
/* sgtty/termio information... */
#ifdef BSD44ORPOSIX /* POSIX or BSD44 */
static struct termios
ttold, ttraw, tttvt, ttcur,
ccold, ccraw, cccbrk;
#else /* BSD, V7, etc */
#ifdef COHERENT /* Hack alert... */
#define ATTSV
#endif /* COHERENT */
#ifdef ATTSV
static struct termio ttold = {0}; /* Init'd for word alignment, */
static struct termio ttraw = {0}; /* which is important for some */
static struct termio tttvt = {0}; /* systems, like Zilog... */
static struct termio ttcur = {0};
static struct termio ccold = {0};
static struct termio ccraw = {0};
static struct termio cccbrk = {0};
#else
static struct sgttyb /* sgtty info... */
ttold, ttraw, tttvt, ttcur, /* for communication line */
ccold, ccraw, cccbrk; /* and for console */
#ifdef BELLV10
static struct ttydevb /* Device info... */
tdold, tdcur; /* for communication device */
#endif /* BELLV10 */
#ifdef TIOCGETC
static struct tchars tchold, tchnoi;
static int tcharf;
#endif /* TIOCGETC */
#ifdef TIOCGLTC
static struct ltchars ltchold, ltchnoi;
static int ltcharf;
#endif /* TIOCGLTC */
int lmodef = 0; /* Local modes */
int lmode = 0;
#endif /* ATTSV */
#endif /* BSD44ORPOSIX */
#ifdef COMMENT
/* It picks up the speeds but they don't work */
#ifdef UNIXWARE /* For higher serial speeds */
#ifdef UW7 /* in Unixware 7.0 */
#include <sys/asyc.h> /* This picks up 57600 and 115200 */
#endif /* UW7 */
#endif /* UNIXWARE */
#endif /* COMMENT */
#ifdef PROVX1
static struct sgttyb ttbuf;
#endif /* PROVX1 */
#ifdef ultrix
/* do we really need this? */
static struct sgttyb vanilla;
#endif /* ultrix */
#ifdef ATT7300
static int attmodem = 0; /* ATT7300 internal-modem status */
struct updata dialer = {0}; /* Condition dialer for data call */
#endif /* ATT7300 */
#ifndef NOUUCP
#define FLFNAML 128
#ifndef USETTYLOCK
#ifdef RTAIX
char lkflfn[FLFNAML] = { '\0', '\0' }; /* and possible link to it */
#endif /* RTAIX */
char lock2[FLFNAML] = { '\0', '\0' }; /* Name of second lockfile */
#endif /* USETTYLOCK */
#else
#define FLFNAML 7
#endif /* NOUUCP */
char flfnam[FLFNAML+1] = { '\0', '\0' }; /* UUCP lock file path name */
int haslock = 0; /* =1 if this kermit locked uucp */
#ifndef OXOS
#ifdef SVORPOSIX
static int conesc = 0; /* set to 1 if esc char (^\) typed */
#else
#ifdef V7
static int conesc = 0;
#else
#ifdef C70
static int conesc = 0;
#endif /* C70 */
#endif /* V7 */
#endif /* SVORPOSIX */
#endif /* OXOS */
/* Local copy of comm device name or network host */
static char ttnmsv[DEVNAMLEN+1] = { '\0', '\0' };
#ifdef USETTYLOCK
static char lockname[DEVNAMLEN+1]; /* Ditto, the part after "/dev/". */
#endif /* USETTYLOCK */
#ifdef aegis
static status_$t st; /* error status return value */
static short concrp = 0; /* true if console is CRP pad */
static uid_$t ttyuid; /* tty type uid */
static uid_$t conuid; /* stdout type uid */
/* APOLLO Aegis main()
* establish acl usage and cleanup handling
* this makes sure that CRP pads
* get restored to a usable mode
*/
main(argc,argv) int argc; char **argv; {
status_$t status;
pfm_$cleanup_rec dirty;
PID_T pid = getpid();
/* acl usage according to invoking environment */
default_acl(USE_DEFENV);
/* establish a cleanup continuation */
status = pfm_$cleanup(dirty);
if (status.all != pfm_$cleanup_set) {
/* only handle faults for the original process */
if (pid == getpid() && status.all > pgm_$max_severity) {
/* blew up in main process */
status_$t quo;
pfm_$cleanup_rec clean;
/* restore the console in any case */
conres();
/* attempt a clean exit */
debug(F101, "cleanup fault status", "", status.all);
/* doexit(), then send status to continuation */
quo = pfm_$cleanup(clean);
if (quo.all == pfm_$cleanup_set)
doexit(pgm_$program_faulted,-1);
else if (quo.all > pgm_$max_severity)
pfm_$signal(quo); /* blew up in doexit() */
}
/* send to the original continuation */
pfm_$signal(status);
/*NOTREACHED*/
}
return(ckcmai(argc, argv));
}
#endif /* aegis */
/* ANSI-style prototypes for internal functions. */
/* Functions used outside this module are prototyped in ckcker.h. */
#ifdef apollo
_PROTOTYP( SIGTYP timerh, () );
_PROTOTYP( SIGTYP cctrap, () );
_PROTOTYP( SIGTYP esctrp, () );
_PROTOTYP( SIGTYP sig_ign, () );
#else
_PROTOTYP( SIGTYP timerh, (int) );
_PROTOTYP( SIGTYP cctrap, (int) );
_PROTOTYP( SIGTYP esctrp, (int) );
#endif /* apollo */
_PROTOTYP( int do_open, (char *) );
_PROTOTYP( static int in_chk, (int, int) );
_PROTOTYP( static int ttrpid, (char *) );
_PROTOTYP( static int ttchkpid, (char *) );
_PROTOTYP( static int ttlock, (char *) );
_PROTOTYP( static int ttunlck, (void) );
_PROTOTYP( int mygetbuf, (void) );
_PROTOTYP( int myfillbuf, (void) );
_PROTOTYP( VOID conbgt, (int) );
#ifdef ACUCNTRL
_PROTOTYP( VOID acucntrl, (char *, char *) );
#endif /* ACUCNTRL */
#ifdef BSD44ORPOSIX
_PROTOTYP( int carrctl, (struct termios *, int) );
#else
#ifdef ATTSV
_PROTOTYP( int carrctl, (struct termio *, int) );
#else
_PROTOTYP( int carrctl, (struct sgttyb *, int) );
#endif /* ATTSV */
#endif /* BSD44ORPOSIX */
#ifdef ATT7300
_PROTOTYP( int attdial, (char *, long, char *) );
_PROTOTYP( int offgetty, (char *) );
_PROTOTYP( int ongetty, (char *) );
#endif /* ATT7300 */
#ifdef BEOSORBEBOX
#ifdef SELECT
/* BeOS is not capable of using SELECT on anything but sockets */
#undef SELECT
#endif /* SELECT */
#include <kernel/OS.h>
/* #ifdef BE_DR_7 */
static double time_started = 0.0;
struct ALARM_STRUCT {
thread_id thread;
int time;
};
static thread_id alarm_thread = -1;
static struct ALARM_STRUCT alarm_struct;
_PROTOTYP( long do_alarm, (void *) );
_PROTOTYP( unsigned int alarm, (unsigned int) );
_PROTOTYP( void alarm_expired, (void) );
/* #endif */ /* BE_DR_7 */
#endif /* BEOSORBEBOX */
#ifndef xunchar
#define xunchar(ch) (((ch) - 32 ) & 0xFF ) /* Character to number */
#endif /* xunchar */
#ifdef CK_ANSIC
static char *
xxlast(char *s, char c)
#else
static char *
xxlast(s,c) char *s; char c;
#endif /* CK_ANSIC */
/* xxlast */ { /* Last occurrence of character c in string s. */
int i;
for (i = (int)strlen(s); i > 0; i--)
if (s[i-1] == c ) return(s + (i - 1));
return(NULL);
}
/* Timeout handler for communication line input functions */
/*ARGSUSED*/
SIGTYP
timerh(foo) int foo; {
ttimoff();
#ifdef BEOSORBEBOX
/* #ifdef BE_DR_7 */
alarm_expired();
/* #endif */ /* BE_DR_7 */
#endif /* BEOSORBEBOX */
#ifdef CK_POSIX_SIG
siglongjmp(sjbuf,1);
#else
longjmp(sjbuf,1);
#endif /* CK_POSIX_SIG */
}
/*ARGSUSED*/
SIGTYP
xtimerh(foo) int foo; { /* Like timerh() but does */
#ifdef BEOSORBEBOX /* not reset the timer itslef */
/* #ifdef BE_DR_7 */
alarm_expired();
/* #endif */ /* BE_DR_7 */
#endif /* BEOSORBEBOX */
#ifdef CK_POSIX_SIG
siglongjmp(sjbuf,1);
#else
longjmp(sjbuf,1);
#endif /* CK_POSIX_SIG */
}
/* Control-C trap for communication line input functions */
int cc_int; /* Flag */
SIGTYP (* occt)(); /* For saving old SIGINT handler */
/*ARGSUSED*/
SIGTYP
cctrap(foo) int foo; { /* Needs arg for ANSI C */
cc_int = 1; /* signal() prototype. */
return;
}
/* S Y S I N I T -- System-dependent program initialization. */
/*
* ttgwsiz() returns:
* 1 tt_rows and tt_cols are known, both altered, both > 0
* 0 tt_rows and/or tt_cols are known, both altered, one or both <= 0
* -1 tt_rows and tt_cols are unknown and unaltered
*/
extern int tt_rows, tt_cols;
static int
xttgwsiz() {
char *p;
int rows = 0, cols = 0;
p = getenv("LINES");
debug(F110,"xttgwsiz LINES",p,0);
if (p) {
rows = atol(p);
if (rows > 0) {
p = getenv("COLUMNS");
debug(F110,"xttgwsiz COLUMNS",p,0);
if (p) {
cols = atol(p);
if (cols > 0) {
tt_rows = rows;
tt_cols = cols;
return(1);
}
return(0);
}
}
}
return(-1);
}
#ifdef TTLEBUF
VOID
le_init() { /* LocalEchoInit() */
int i;
for (i = 0; i < LEBUFSIZ; i++)
le_buf[i] = '\0';
le_start = 0;
le_end = 0;
le_data = 0;
}
VOID
le_clean() { /* LocalEchoCleanup() */
le_init();
return;
}
int
le_inbuf() {
int rc = 0;
if (le_start != le_end) {
rc = (le_end -
le_start +
LEBUFSIZ) % LEBUFSIZ;
}
debug(F111,"le_inbuf","chars waiting",rc);
return(rc);
}
int
#ifdef CK_ANSIC
le_putchar(CHAR ch)
#else
le_putchar(ch) CHAR ch;
#endif /* CK_ANSIC */
/* le_putchar */ {
#ifdef COMMENT
/* In UNIX we do not have another thread taking chars out of the buffer */
while ((le_start - le_end == 1) ||
(le_start == 0 && le_end == LEBUFSIZ - 1)) {
/* Buffer is full */
debug(F111,"le_putchar","Buffer is Full",ch);
ReleaseLocalEchoMutex() ;
msleep(250);
RequestLocalEchoMutex( SEM_INDEFINITE_WAIT ) ;
}
#else
if ((le_start - le_end + LEBUFSIZ)%LEBUFSIZ == 1) {
debug(F110,"le_putchar","buffer is full",0);
return(-1);
}
#endif /* COMMENT */
le_buf[le_end++] = ch;
if (le_end == LEBUFSIZ)
le_end = 0;
le_data = 1;
return(0);
}
int
#ifdef CK_ANSIC
le_puts(CHAR * s, int n)
#else
le_puts(s,n) CHAR * s; int n;
#endif /* CK_ANSIC */
/* le_puts */ {
int rc = 0;
int i = 0;
CHAR * p = (CHAR *)"le_puts";
hexdump(p,s,n);
for (i = 0; i < n; i++)
rc = le_putchar((char)s[i]);
debug(F101,"le_puts","",rc);
return(rc);
}
int
#ifdef CK_ANSIC
le_putstr(CHAR * s)
#else
le_putstr(s) CHAR * s;
#endif /* CK_ANSIC */
/* le_puts */ {
CHAR * p;
int rc = 0;
p = (CHAR *)"le_putstr";
hexdump(p,s,(int)strlen((char *)s));
for (p = s; *p && !rc; p++)
rc = le_putchar(*p);
return(rc);
}
int
#ifdef CK_ANSIC
le_getchar(CHAR * pch)
#else /* CK_ANSIC */
le_getchar(pch) CHAR * pch;
#endif /* CK_ANSIC */
/* le_gatchar */ {
int rc = 0;
if (le_start != le_end) {
*pch = le_buf[le_start];
le_buf[le_start] = 0;
le_start++;
if (le_start == LEBUFSIZ)
le_start = 0;
if (le_start == le_end) {
le_data = 0;
}
rc++;
} else {
*pch = 0;
}
return(rc);
}
#endif /* TTLEBUF */
#ifdef COMMENT
/*
Some systems like OSF/1 use TIOCGSIZE instead of TIOCGWINSZ.
But as far as I know, whenever TIOCGSIZE is defined, it is
equated to TIOCGWINSZ. For cases where this is not done, try this:
*/
#ifndef TIOCGWINSZ
#ifdef TIOCGSIZE
#define TIOCGWINSZ TIOCGSIZE
#endif /* TIOCGSIZE */
#endif /* TIOCGWINSZ */
#endif /* COMMENT */
static int tt_xpixel = 0, tt_ypixel = 0;
int
ttgwsiz() {
int x = 0;
#ifndef NONAWS
#ifdef QNX
/*
NOTE: TIOCGWSIZ works here too, but only in the 32-bit version.
This code works for both the 16- and 32-bit versions.
*/
extern int dev_size(int, int, int, int *, int *);
int r, c;
if (dev_size(0, -1, -1, &r, &c) == 0) {
debug(F101,"ttgwsiz QNX r","",r);
debug(F101,"ttgwsiz QNX c","",c);
tt_rows = r;
tt_cols = c;
return ((r > 0 && c > 0) ? 1 : 0);
} else return(xttgwsiz());
#else /* QNX */
#ifdef TIOCGWINSZ
/* Note, this was M_UNIX, changed to XENIX to allow cross compilation... */
#ifdef XENIX /* SCO UNIX 3.2v4.0 */
#include <sys/stream.h> /* typedef mblk_t needed by ptem.h */
#include <sys/ptem.h> /* for ttgwsiz() */
#endif /* XENIX */
#ifdef I386IX /* Ditto for Interactive */
#include <sys/stream.h>
#include <sys/ptem.h>
#endif /* I386IX */
/* Note, the above might be needed for some other older SVR3 Intel makes... */
struct winsize w;
tt_xpixel = 0;
tt_ypixel = 0;
#ifdef IKSD
if (inserver)
return(xttgwsiz());
#endif /* IKSD */
x = ioctl(0, (int)TIOCGWINSZ, (char *)&w);
debug(F101,"ttgwsiz TIOCGWINSZ","",x);
if (x < 0) {
return(xttgwsiz());
} else if (w.ws_row > 0 && w.ws_col > 0) {
tt_rows = w.ws_row;
tt_cols = w.ws_col;
tt_xpixel = w.ws_xpixel;
tt_ypixel = w.ws_ypixel;
debug(F101,"ttgwsiz tt_rows","",tt_rows);
debug(F101,"ttgwsiz tt_cols","",tt_cols);
return(1);
} else {
debug(F100,"ttgwsiz TIOCGWINSZ 00","",0);
return(xttgwsiz());
}
#else
return(xttgwsiz());
#endif /* TIOCGWINSZ */
#endif /* QNX */
#endif /* NONAWS */
}
#ifndef NOSIGWINCH
#ifdef SIGWINCH
SIGTYP
winchh(foo) int foo; { /* SIGWINCH handler */
int x = 0;
#ifdef NETPTY
extern int pty_fork_pid;
#endif /* NETPTY */
#ifdef CK_TTYFD
#ifndef VMS
extern int ttyfd;
#endif /* VMS */
#endif /* CK_TTYFD */
extern int tt_rows, tt_cols, cmd_rows, cmd_cols;
#ifdef DEBUG
if (deblog) {
debug(F100,"***************","",0);
debug(F100,"SIGWINCH caught","",0);
debug(F100,"***************","",0);
#ifdef NETPTY
debug(F101,"SIGWINCH pty_fork_pid","",pty_fork_pid);
#endif /* NETPTY */
}
#endif /* DEUB */
signal(SIGWINCH,winchh); /* Re-arm the signal */
x = ttgwsiz(); /* Get new window size */
cmd_rows = tt_rows; /* Adjust command screen too */
cmd_cols = tt_cols;
#ifdef CK_TTYFD
if /* If we don't have a connection */
#ifdef VMS /* we're done. */
(vmsttyfd() == -1)
#else
(ttyfd == -1)
#endif /* VMS */
#else
(!local)
#endif /* CK_TTYFD */
return;
#ifdef NETPTY
if (pty_fork_pid > -1) { /* "set host" to a PTY? */
int x;
#ifdef TIOCSWINSZ
struct winsize w; /* Resize the PTY */
errno = 0;
w.ws_col = tt_cols;
w.ws_row = tt_rows;
w.ws_xpixel = tt_xpixel;
w.ws_ypixel = tt_ypixel;
x = ioctl(ttyfd,TIOCSWINSZ,&w);
debug(F101,"winchh TIOCSWINSZ","",x);
debug(F101,"winchh TIOCSWINSZ errno","",errno);
#endif /* TIOCSWINSZ */
errno = 0;
x = kill(pty_fork_pid,SIGWINCH);
debug(F101,"winchh kill","",x);
debug(F101,"winchh kill errno","",errno);
}
#endif /* NETPTY */
/*
This should be OK. It might seem that sending this from
interrupt level could interfere with another TELNET IAC string
that was in the process of being sent. But we always send
TELNET strings with a single write(), which should prevent mixups.
blah_snaws() should protect themselves from being called on the
wrong kind of connection.
*/
#ifdef TCPSOCKET
#ifndef NOTTGWSIZ
if (x > 0 && tt_rows > 0 && tt_cols > 0) {
tn_snaws();
#ifdef RLOGCODE
rlog_naws();
#endif /* RLOGCODE */
}
#endif /* NOTTGWSIZ */
#endif /* TCPSOCKET */
SIGRETURN;
}
#endif /* SIGWINCH */
#endif /* NOSIGWINCH */
SIGTYP
sighup(foo) int foo; { /* SIGHUP handler */
backgrd = 1;
debug(F100,"***************","",0);
debug(F100,"SIGHUP received","",0);
debug(F100,"***************","",0);
doexit(BAD_EXIT,-1);
/*NOTREACHED*/
SIGRETURN; /* Shut picky compilers up... */
}
#ifdef CK_SCO32V4
/* Exists but there is no prototype in the header files */
_PROTOTYP( char * ttyname, (int) );
#else
#ifdef SV68R3V6
_PROTOTYP( char * ttyname, (int) );
#else
#ifdef ultrix
_PROTOTYP( char * ttyname, (int) );
#else
#ifdef HPUX6
_PROTOTYP( char * ttyname, (int) );
#else
#ifdef HPUX5
_PROTOTYP( char * ttyname, (int) );
#else
#ifdef PS2AIX10
_PROTOTYP( char * ttyname, (int) );
#else
#ifdef BSD42
_PROTOTYP( char * ttyname, (int) );
#endif /* BSD42 */
#endif /* PS2AIX10 */
#endif /* HPUX5 */
#endif /* HPUX6 */
#endif /* ultrix */
#endif /* SV68R3V6 */
#endif /* CK_SCO32V4 */
#ifndef SIGUSR1 /* User-defined signals */
#define SIGUSR1 30
#endif /* SIGUSR1 */
#ifndef SIGUSR2
#define SIGUSR2 31
#endif /* SIGUSR2 */
/*
ignorsigs() sets certain signals to SIG_IGN. But when a signal is
ignored, it remains ignored across exec(), so we have to restore these
signals before exec(), which is the purpose of restorsigs().
*/
static VOID
ignorsigs() { /* Ignore these signals */
savquit = signal(SIGQUIT,SIG_IGN); /* Ignore Quit signal */
#ifdef SIGDANGER /* Ignore danger signals */
/*
This signal is sent when the system is low on swap space. Processes
that don't handle it are candidates for termination. If swap space doesn't
clear out enough, we still might be terminated via kill() -- nothing we can
do about that! Conceivably, this could be improved by installing a real
signal handler that warns the user, but that would be pretty complicated,
since we are not always in control of the screen -- e.g. during remote-mode
file transfer.
*/
savdanger = signal(SIGDANGER,SIG_IGN); /* e.g. in AIX */
#endif /* SIGDANGER */
#ifdef SIGPIPE
/*
This one comes when a TCP/IP connection is broken by the remote.
We prefer to catch this situation by examining error codes from write().
*/
savpipe = signal(SIGPIPE,SIG_IGN);
#endif /* SIGPIPE */
savusr1 = signal(SIGUSR1,SIG_IGN); /* Ignore user-defined signals */
savusr2 = signal(SIGUSR2,SIG_IGN);
}
VOID
restorsigs() { /* Restore these signals */
(VOID) signal(SIGQUIT,savquit); /* (used in ckufio.c) */
#ifdef SIGDANGER
(VOID) signal(SIGDANGER,savdanger);
#endif /* SIGDANGER */
#ifdef SIGPIPE
(VOID) signal(SIGPIPE,savpipe);
#endif /* SIGPIPE */
(VOID) signal(SIGUSR1,savusr1);
(VOID) signal(SIGUSR2,savusr2);
}
int
sysinit() {
int x;
char * s;
#ifdef CK_UTSNAME
struct utsname name;
#endif /* CK_UTSNAME */
extern char startupdir[];
/*
BEFORE ANYTHING ELSE: Initialize the setuid package.
Change to the user's real user and group ID.
If this can't be done, don't run at all.
*/
x = priv_ini();
#ifdef SUIDDEBUG
fprintf(stderr,"PRIV_INI=%d\n",x);
#endif /* SUIDDEBUG */
if (x) {
if (x & 1) fprintf(stderr,"Fatal: setuid failure.\n");
if (x & 2) fprintf(stderr,"Fatal: setgid failure.\n");
if (x & 4) fprintf(stderr,"Fatal: C-Kermit setuid to root!\n");
exit(1);
}
signal(SIGINT,SIG_IGN); /* Ignore interrupts at first */
signal(SIGFPE,SIG_IGN); /* Ignore floating-point exceptions */
signal(SIGHUP,sighup); /* Catch SIGHUP */
#ifndef NOSIGWINCH
#ifdef SIGWINCH
signal(SIGWINCH,winchh); /* Catch window-size change */
#endif /* SIGWINCH */
#endif /* NOSIGWINCH */
#ifndef NOJC
/*
Get the initial job control state.
If it is SIG_IGN, that means the shell does not support job control,
and so we'd better not suspend ourselves.
*/
#ifdef SIGTSTP
jchdlr = signal(SIGTSTP,SIG_IGN);
if (jchdlr == SIG_IGN) {
jcshell = 0;
debug(F100,"sysinit jchdlr: SIG_IGN","",0);
} else if (jchdlr == SIG_DFL) {
debug(F100,"sysinit jchdlr: SIG_DFL","",0);
jcshell = 1;
} else {
debug(F100,"sysinit jchdlr: other","",0);
jcshell = 3;
}
(VOID) signal(SIGTSTP,jchdlr); /* Put it back... */
#endif /* SIGTSTP */
#endif /* NOJC */
conbgt(0); /* See if we're in the background */
congm(); /* Get console modes */
(VOID) signal(SIGALRM,SIG_IGN); /* Ignore alarms */
ignorsigs(); /* Ignore some other signals */
#ifdef F_SETFL
iniflags = fcntl(0,F_GETFL,0); /* Get stdin flags */
#endif /* F_SETFL */
#ifdef ultrix
gtty(0,&vanilla); /* Get sgtty info */
#else
#ifdef AUX
set42sig(); /* Don't ask! (hakanson@cs.orst.edu) */
#endif /* AUX */
#endif /* ultrix */
/*
Warning: on some UNIX systems (SVR4?), ttyname() reportedly opens /dev but
never closes it. If it is called often enough, we run out of file
descriptors and subsequent open()'s of other devices or files can fail.
*/
s = NULL;
#ifndef MINIX
if (isatty(0)) /* Name of controlling terminal */
s = ttyname(0);
else if (isatty(1))
s = ttyname(1);
else if (isatty(2))
s = ttyname(2);
debug(F110,"sysinit ttyname(0)",s,0);
#endif /* MINIX */
#ifdef BEOS
if (!dftty)
makestr(&dftty,s);
#endif /* BEOS */
if (s)
ckstrncpy((char *)cttnam,s,DEVNAMLEN+1);
#ifdef SVORPOSIX
if (!cttnam[0])
ctermid(cttnam);
#endif /* SVORPOSIX */
if (!cttnam[0])
ckstrncpy((char *)cttnam,dftty,DEVNAMLEN+1);
debug(F110,"sysinit CTTNAM",CTTNAM,0);
debug(F110,"sysinit cttnam",cttnam,0);
ttgwsiz(); /* Get window (screen) dimensions. */
#ifndef NOSYSCONF
#ifdef _SC_OPEN_MAX
ckmaxfiles = sysconf(_SC_OPEN_MAX);
#endif /* _SC_OPEN_MAX */
#endif /* NOSYSCONF */
#ifdef Plan9
if (!backgrd) {
consctlfd = open("/dev/consctl", O_WRONLY);
/*noisefd = open("/dev/noise", O_WRONLY)*/
}
ckxech = 1;
#endif /* Plan9 */
#ifdef CK_UTSNAME
if (uname(&name) > -1) {
ckstrncpy(unm_mch,name.machine,CK_SYSNMLN);
ckstrncpy(unm_nam,name.sysname,CK_SYSNMLN);
ckstrncpy(unm_rel,name.release,CK_SYSNMLN);
ckstrncpy(unm_ver,name.version,CK_SYSNMLN);
#ifdef DEBUG
if (deblog) {
debug(F110,"sysinit uname machine",unm_mch,0);
debug(F110,"sysinit uname sysname",unm_nam,0);
debug(F110,"sysinit uname release",unm_rel,0);
debug(F110,"sysinit uname version",unm_ver,0);
}
#endif /* DEBUG */
#ifdef HPUX9PLUS
if (name.machine[5] == '8')
hpis800 = 1;
else
hpis800 = 0;
debug(F101,"sysinit hpis800","",hpis800);
#endif /* HPUX9PLUS */
#ifdef TRU64
getsysinfo(GSI_PLATFORM_NAME, unm_mod, CK_SYSNMLN, 0, 0);
debug(F110,"sysinit getsysinfo model",unm_mod,0);
#endif /* TRU64 */
#ifdef SOLARIS25
sysinfo(SI_PLATFORM, unm_mod, CK_SYSNMLN);
debug(F110,"sysinit sysinfo model",unm_mod,0);
#endif /* SOLARIS25 */
}
#endif /* CK_UTSNAME */
#ifdef CK_ENVIRONMENT
{
#ifdef TNCODE
extern char tn_env_acct[], tn_env_disp[], tn_env_job[],
tn_env_prnt[], tn_env_sys[];
#endif /* TNCODE */
extern char uidbuf[];
extern char * whoami();
char *p;
#ifdef CKSENDUID
uidbuf[0] = '\0';
#ifdef IKSD
if (!inserver) {
#endif /* IKSD */
p = getenv("USER");
debug(F110,"sysinit uidbuf from USER",uidbuf,0);
if (!p) p = "";
if (!*p) {
p = getenv("LOGNAME");
debug(F110,"sysinit uidbuf from LOGNAME",uidbuf,0);
}
if (!p) p = "";
if (!*p) {
p = whoami();
debug(F110,"sysinit uidbuf from whoami()",uidbuf,0);
}
if (!p) p = "";
ckstrncpy(uidbuf, *p ? p : "UNKNOWN", UIDBUFLEN);
#ifdef IKSD
}
#endif /* IKSD */
debug(F110,"sysinit final uidbuf",uidbuf,0);
#endif /* CKSENDUID */
#ifdef TNCODE
if ((p = getenv("JOB"))) ckstrncpy(tn_env_job,p,63);
if ((p = getenv("ACCT"))) ckstrncpy(tn_env_acct,p,63);
if ((p = getenv("PRINTER"))) ckstrncpy(tn_env_prnt,p,63);
if ((p = getenv("DISPLAY"))) ckstrncpy(tn_env_disp,p,63);
#ifdef aegis
ckstrncpy(tn_env_sys,"Aegis",64);
#else
#ifdef Plan9
ckstrncpy(tn_env_sys,"Plan9",64);
#else
ckstrncpy(tn_env_sys,"UNIX",64);
#endif /* Plan9 */
#endif /* aegis */
#endif /* TNCODE */
}
#endif /* CK_ENVIRONMENT */
#ifdef CK_SNDLOC
{
extern char * tn_loc;
char *p;
if (p = getenv("LOCATION"))
if (tn_loc = (char *)malloc((int)strlen(p)+1))
strcpy(tn_loc,p); /* safe */
}
#endif /* CK_SNDLOC */
ckstrncpy(startupdir, zgtdir(), CKMAXPATH);
startupdir[CKMAXPATH] = '\0';
x = strlen(startupdir);
if (x <= 0) {
startupdir[0] = '/';
startupdir[1] = '\0';
} else if (startupdir[x-1] != '/') {
startupdir[x] = '/';
startupdir[x+1] = '\0';
}
debug(F110,"sysinit startupdir",startupdir,0);
#ifdef TTLEBUF
le_init();
#endif /* TTLEBUF */
#ifdef BSD44ORPOSIX
/* This should catch the ncurses platforms */
/* Some platforms don't have putenv(), like NeXTSTEP */
putenv("NCURSES_NO_SETBUF=1");
#endif /* BSD44ORPOSIX */
return(0);
}
/* S Y S C L E A N U P -- System-dependent program cleanup. */
int
syscleanup() {
#ifdef F_SETFL
if (iniflags > -1)
fcntl(0,F_SETFL,iniflags); /* Restore stdin flags */
#endif /* F_SETFL */
#ifdef ultrix
stty(0,&vanilla); /* Get sgtty info */
#endif /* ultrix */
#ifdef NETCMD
if (ttpid) kill(ttpid,9);
#endif /* NETCMD */
return(0);
}
/* T T O P E N -- Open a tty for exclusive access. */
/*
Call with:
ttname: character string - device name or network host name.
lcl:
If called with lcl < 0, sets value of lcl as follows:
0: the terminal named by ttname is the job's controlling terminal.
1: the terminal named by ttname is not the job's controlling terminal.
But watch out: if a line is already open, or if requested line can't
be opened, then lcl remains (and is returned as) -1.
modem:
Less than zero: ttname is a network host name.
Zero or greater: ttname is a terminal device name.
Zero means a local connection (don't use modem signals).
Positive means use modem signals.
timo:
0 = no timer.
nonzero = number of seconds to wait for open() to return before timing out.
Returns:
0 on success
-5 if device is in use
-4 if access to device is denied
-3 if access to lock directory denied
-2 upon timeout waiting for device to open
-1 on other error
*/
static int ttotmo = 0; /* Timeout flag */
/* Flag kept here to avoid being clobbered by longjmp. */
int
ttopen(ttname,lcl,modem,timo) char *ttname; int *lcl, modem, timo; {
#ifdef BSD44
#define ctermid(x) strcpy(x,"")
#else
#ifdef SVORPOSIX
#ifndef CIE
extern char *ctermid(); /* Wish they all had this! */
#else /* CIE Regulus */
#define ctermid(x) strcpy(x,"")
#endif /* CIE */
#endif /* SVORPOSIX */
#endif /* BSD44 */
#ifdef ultrix
int temp = 0;
#endif /* ultrix */
#ifndef OPENFIRST
char fullname[DEVNAMLEN+1];
#endif /* OPENFIRST */
char * fnam; /* Full name after expansion */
int y;
#ifndef pdp11
#define NAMEFD /* Feature to allow name to be an open file descriptor */
#endif /* pdp11 */
#ifdef NAMEFD
char *p;
debug(F101,"ttopen telnetfd","",telnetfd);
#endif /* NAMEFD */
debug(F110,"ttopen ttname",ttname,0);
debug(F110,"ttopen ttnmsv",ttnmsv,0);
debug(F101,"ttopen modem","",modem);
debug(F101,"ttopen netconn","",netconn);
debug(F101,"ttopen ttyfd","",ttyfd);
debug(F101,"ttopen *lcl","",*lcl);
debug(F101,"ttopen ttmdm","",ttmdm);
debug(F101,"ttopen ttnet","",ttnet);
ttpmsk = 0xff;
lockpid[0] = '\0';
if (ttyfd > -1) { /* If device already opened */
if (!strncmp(ttname,ttnmsv,DEVNAMLEN)) /* are new & old names equal? */
return(0); /* Yes, nothing to do - just return */
ttnmsv[0] = '\0'; /* No, clear out old name */
ttclos(ttyfd); /* close old connection. */
}
wasclosed = 0; /* New connection, not closed yet. */
ttpipe = 0; /* Assume it's not a pipe */
ttpty = 0; /* or a pty... */
#ifdef NETCONN
/*
This is a bit tricky... Suppose that previously Kermit had dialed a telnet
modem server ("set host xxx:2001, set modem type usr, dial ..."). Then the
connection was closed (ttyfd = -1), and then a REDIAL command was given. At
this point we've obliterated the negative modem type hack, and so would
treat the IP hostname as a device name, and would then fail because of "No
such device or directory". But the previous connection has left behind some
clues, so let's use them...
*/
if (ttyfd < 0) { /* Connection is not open */
if (!strcmp(ttname,ttnmsv)) { /* Old and new names the same? */
if (((netconn > 0) && (ttmdm < 0)) ||
((ttnet > 0) &&
(!ckstrchr(ttname,'/')) && (ckstrchr(ttname,':')))
) {
int x, rc;
x = (ttmdm < 0) ? -ttmdm : ttnet;
rc = netopen(ttname, lcl, x);
debug(F111,"ttopen REOPEN netopen",ttname,rc);
if (rc > -1) {
netconn = 1;
xlocal = *lcl = 1;
} else {
netconn = 0;
}
gotsigs = 0;
return(rc);
}
}
}
#endif /* NETCONN */
#ifdef MAXNAMLEN
debug(F100,"ttopen MAXNAMLEN defined","",0);
#else
debug(F100,"ttopen MAXNAMLEN *NOT* defined","",0);
#endif
#ifdef BSD4
debug(F100,"ttopen BSD4 defined","",0);
#else
debug(F100,"ttopen BSD4 *NOT* defined","",0);
#endif /* BSD4 */
#ifdef BSD42
debug(F100,"ttopen BSD42 defined","",0);
#else
debug(F100,"ttopen BSD42 *NOT* defined","",0);
#endif /* BSD42 */
#ifdef MYREAD
debug(F100,"ttopen MYREAD defined","",0);
#else
debug(F100,"ttopen MYREAD *NOT* defined","",0);
#endif /* MYREAD */
#ifdef NETCONN
if (modem < 0) { /* modem < 0 = code for network */
int x;
ttmdm = modem;
modem = -modem; /* Positive network type number */
fdflag = 0; /* Stdio not redirected. */
netconn = 1; /* And it's a network connection */
debug(F111,"ttopen net",ttname,modem);
#ifdef NAMEFD
for (p = ttname; isdigit(*p); p++) ; /* Check for all digits */
if (*p == '\0' && (telnetfd || x25fd)) { /* Avoid X.121 addresses */
ttyfd = atoi(ttname); /* Is there a way to test it's open? */
ttfdflg = 1; /* We got an open file descriptor */
debug(F111,"ttopen net ttfdflg",ttname,ttfdflg);
debug(F101,"ttopen net ttyfd","",ttyfd);
ckstrncpy(ttnmsv,ttname,DEVNAMLEN); /* Remember the "name". */
x = 1; /* Return code is "good". */
if (telnetfd) {
ttnet = NET_TCPB;
if (ttnproto != NP_TCPRAW)
ttnproto = NP_TELNET;
#ifdef SUNX25
} else if (x25fd) {
ttnet = NET_SX25;
ttnproto = NP_NONE;
#endif /* SUNX25 */
}
} else { /* Host name or address given */
#ifdef NETPTY
if (modem == NET_PTY) {
int x;
if (nopush) {
debug(F100,"ttopen PTY: nopush","",0);
return(-1);
}
ttnet = NET_PTY;
ttnproto = NP_NONE;
netconn = 1; /* but we don't use network i/o */
ttpty = 1;
debug(F110,"ttopen PTY",ttname,0);
x = do_pty(ttname);
if (x > -1) {
ckstrncpy(ttnmsv,ttname,DEVNAMLEN);
xlocal = *lcl = 1; /* It's local */
} else {
ttpty = 0;
netconn = 0;
}
gotsigs = 0;
return(x);
}
#endif /* NETPTY */
#ifdef NETCMD
/*
dup2() is not available on older System V platforms like AT&T 3Bx. For
those systems we punt by not defining NETCMD, but we might be able to do
better -- see workarounds for this problem in ckufio.c (search for dup2).
*/
if (modem == NET_CMD) {
if (nopush) {
debug(F100,"ttopen pipe: nopush","",0);
return(-1);
}
if (pipe(pipe0) || pipe(pipe1)) {
perror("Pipe error");
return(-1);
}
ttpid = fork(); /* Make a fork */
switch (ttpid) {
case -1: /* Error making fork */
close(pipe0[0]);
close(pipe0[1]);
close(pipe1[0]);
close(pipe1[1]);
perror("Fork error");
return(-1);
case 0: /* Child. */
close(pipe0[0]);
close(pipe1[1]);
dup2(pipe0[1], 1);
close(pipe0[1]);
dup2(pipe1[0], 0);
close(pipe1[0]);
system(ttname);
_exit(0);
default: /* Parent */
close(pipe0[1]);
close(pipe1[0]);
fdin = pipe0[0]; /* Read from pipe */
fdout = pipe1[1]; /* Write to pipe */
ttout = fdopen(fdout,"w"); /* Get stream so we can */
if (!ttout) { /* make it unbuffered. */
perror("fdopen failure");
return(-1);
}
setbuf(ttout,NULL);
ckstrncpy(ttnmsv,ttname,DEVNAMLEN);
xlocal = *lcl = 1; /* It's local */
netconn = 1; /* Call it a network connection */
ttmdm = modem; /* Remember network type */
ttyfd = fdin;
ttpipe = 1;
gotsigs = 0;
return(0);
}
}
#endif /* NETCMD */
#endif /* NAMEFD */
x = netopen(ttname, lcl, modem); /* (see ckcnet.h) */
if (x > -1) {
ckstrncpy(ttnmsv,ttname,DEVNAMLEN);
} else netconn = 0;
#ifdef NAMEFD
}
#endif /* NAMEFD */
#ifdef sony_news /* Sony NEWS */
if (ioctl(ttyfd,TIOCKGET,&km_ext) < 0) { /* Get Kanji mode */
perror("ttopen error getting Kanji mode (network)");
debug(F111,"ttopen error getting Kanji mode","network",0);
km_ext = -1; /* Make sure this stays undefined. */
}
#endif /* sony_news */
xlocal = *lcl = 1; /* Network connections are local. */
debug(F101,"ttopen net x","",x);
#ifdef COMMENT
/* Let netopen() do this */
if (x > -1 && !x25fd)
x = tn_ini(); /* Initialize TELNET protocol */
#endif /* COMMENT */
gotsigs = 0;
return(x);
} else { /* Terminal device */
#endif /* NETCONN */
#ifdef NAMEFD
/*
This code lets you give Kermit an open file descriptor for a serial
communication device, rather than a device name. Kermit assumes that the
line is already open, locked, conditioned with the right parameters, etc.
*/
for (p = ttname; isdigit(*p); p++) ; /* Check for all-digits */
if (*p == '\0') {
ttyfd = atoi(ttname); /* Is there a way to test it's open? */
debug(F111,"ttopen got open fd",ttname,ttyfd);
ckstrncpy(ttnmsv,ttname,DEVNAMLEN); /* Remember the "name". */
if (ttyfd >= 0 && ttyfd < 3) /* If it's stdio... */
xlocal = *lcl = 0; /* we're in remote mode */
else /* otherwise */
xlocal = *lcl = 1; /* local mode. */
netconn = 0; /* Assume it's not a network. */
tvtflg = 0; /* Might need to initialize modes. */
ttmdm = modem; /* Remember modem type. */
fdflag = 0; /* Stdio not redirected. */
ttfdflg = 1; /* Flag we were opened this way. */
debug(F111,"ttopen non-net ttfdflg",ttname,ttfdflg);
debug(F101,"ttopen non-net ttyfd","",ttyfd);
#ifdef sony_news /* Sony NEWS */
/* Get device Kanji mode */
if (ioctl(ttyfd,TIOCKGET,&km_ext) < 0) {
perror("ttopen error getting Kanji mode");
debug(F101,"ttopen error getting Kanji mode","",0);
km_ext = -1; /* Make sure this stays undefined. */
}
#endif /* sony_news */
gotsigs = 0;
return(0); /* Return success */
}
#endif /* NAMEFD */
#ifdef NETCONN
}
#endif /* NETCONN */
/* Here we have to open a serial device of the given name. */
netconn = 0; /* So it's not a network connection */
occt = signal(SIGINT, cctrap); /* Set Control-C trap, save old one */
sigint_ign = 0;
tvtflg = 0; /* Flag for use by ttvt(). */
/* 0 = ttvt not called yet for this device */
fdflag = (!isatty(0) || !isatty(1)); /* Flag for stdio redirected */
debug(F101,"ttopen fdflag","",fdflag);
ttmdm = modem; /* Make this available to other fns */
xlocal = *lcl; /* Make this available to other fns */
/* Code for handling bidirectional tty lines goes here. */
/* Use specified method for turning off logins and suppressing getty. */
#ifdef ACUCNTRL
/* Should put call to priv_on() here, but that would be very risky! */
acucntrl("disable",ttname); /* acucntrl() program. */
/* and priv_off() here... */
#else
#ifdef ATT7300
if ((attmodem & DOGETY) == 0) /* offgetty() program. */
attmodem |= offgetty(ttname); /* Remember response. */
#endif /* ATT7300 */
#endif /* ACUCNTRL */
#ifdef OPENFIRST
/*
1985-2001: opens device first then gets lock; reason:
Kermit usually has to run setuid or setgid in order to create a lockfile.
If you give a SET LINE command for a device that happens to be your job's
controlling terminal, Kermit doesn't have to create a lockfile, and in fact
should not create one, and would fail if it tried to if it did not have the
required privileges. But you can't find out if two tty device names are
equivalent until you have a file descriptor that you can give to ttyname().
But this can cause a race condition between Kermit and [m]getty. So see
the [#]else part...
*/
/*
In the following section, we open the tty device for read/write.
If a modem has been specified via "set modem" prior to "set line"
then the O_NDELAY parameter is used in the open, provided this symbol
is defined (e.g. in fcntl.h), so that the program does not hang waiting
for carrier (which in most cases won't be present because a connection
has not been dialed yet). O_NDELAY is removed later on in ttopen(). It
would make more sense to first determine if the line is local before
doing this, but because ttyname() requires a file descriptor, we have
to open it first. See do_open().
Now open the device using the desired treatment of carrier.
If carrier is REQUIRED, then open could hang forever, so an optional
timer is provided. If carrier is not required, the timer should never
go off, and should do no harm...
*/
ttotmo = 0; /* Flag no timeout */
debug(F101,"ttopen timo","",timo);
debug(F101,"ttopen xlocal","",xlocal);
if (timo > 0) {
int xx;
saval = signal(SIGALRM,timerh); /* Timed, set up timer. */
xx = alarm(timo); /* Timed open() */
debug(F101,"ttopen alarm","",xx);
if (
#ifdef CK_POSIX_SIG
sigsetjmp(sjbuf,1)
#else
setjmp(sjbuf)
#endif /* CK_POSIX_SIG */
) {
ttotmo = 1; /* Flag timeout. */
} else ttyfd = do_open(ttname);
ttimoff();
debug(F111,"ttopen","modem",modem);
debug(F101,"ttopen ttyfd","",ttyfd);
debug(F101,"ttopen alarm return","",ttotmo);
} else {
errno = 0;
ttyfd = do_open(ttname);
}
debug(F111,"ttopen ttyfd",ttname,ttyfd);
if (ttyfd < 0) { /* If couldn't open, fail. */
debug(F101,"ttopen errno","",errno);
if (errno > 0 && !quiet)
perror(ttname); /* Print message */
#ifdef ATT7300
if (attmodem & DOGETY) /* was getty(1m) running before us? */
ongetty(ttnmsv); /* yes, restart on tty line */
attmodem &= ~DOGETY; /* no phone in use, getty restored */
#else
#ifdef ACUCNTRL
/* Should put call to priv_on() here, but that would be risky! */
acucntrl("enable",ttname); /* acucntrl() program. */
/* and priv_off() here... */
#endif /* ACUNTRL */
#endif /* ATT7300 */
signal(SIGINT,occt); /* Put old Ctrl-C trap back. */
if (errno == EACCES) { /* Device is protected against user */
debug(F110,"ttopen EACCESS",ttname,0); /* Return -4 */
return(-4);
} else return(ttotmo ? -2 : -1); /* Otherwise -2 if timeout, or -1 */
}
#ifdef QNX
{
extern int qnxportlock;
x = qnxopencount();
debug(F101,"ttopen qnxopencount","",x);
debug(F101,"ttopen qnxportlock","",qnxportlock);
if (x < 0 && qnxportlock) {
ttclos(0);
printf("?Can't get port open count\n");
printf("(Try again with SET QNX-PORT-LOCK OFF)\n");
return(-1); /* Indicate device is in use */
}
if (x > 1) { /* 1 == me */
if (qnxportlock)
ttclos(0);
return(-2); /* Indicate device is in use */
else if (!quiet)
printf("WARNING: \"%s\" looks busy...\n",ttdev);
}
}
#endif /* QNX */
#ifdef Plan9
/* take this opportunity to open the control channel */
if (p9openttyctl(ttname) < 0)
#else
/* Make sure it's a real tty. */
if (!ttfdflg && !isatty(ttyfd) && strcmp(ttname,"/dev/null"))
#endif /* Plan9 */
{
fprintf(stderr,"%s is not a terminal device\n",ttname);
debug(F111,"ttopen not a tty",ttname,errno);
close(ttyfd);
ttyfd = -1;
wasclosed = 1;
signal(SIGINT,occt);
return(-1);
}
#ifdef aegis
/* Apollo C runtime claims that console pads are tty devices, which
* is reasonable, but they aren't any good for packet transfer. */
ios_$inq_type_uid((short)ttyfd, ttyuid, st);
if (st.all != status_$ok) {
fprintf(stderr, "problem getting tty object type: ");
error_$print(st);
} else if (ttyuid != sio_$uid) { /* reject non-SIO lines */
close(ttyfd); ttyfd = -1;
wasclosed = 1;
errno = ENOTTY; perror(ttname);
signal(SIGINT,occt);
return(-1);
}
#endif /* aegis */
sigint_ign = (occt == SIG_IGN) ? 1 : 0;
ckstrncpy(ttnmsv,ttname,DEVNAMLEN); /* Keep copy of name locally. */
/* Caller wants us to figure out if line is controlling tty */
if (*lcl < 0) {
if (strcmp(ttname,CTTNAM) == 0) { /* "/dev/tty" always remote */
xlocal = 0;
debug(F111,"ttopen ttname=CTTNAM",ttname,xlocal);
} else if (strcmp(ttname,cttnam) == 0) {
xlocal = 0;
debug(F111,"ttopen ttname=cttnam",ttname,xlocal);
} else if (cttnam[0]) {
#ifdef BEBOX_DR7
x = ttnmsv; /* ttyname() is broken */
#else
x = ttyname(ttyfd); /* Get real name of ttname. */
#endif /* BEBOX_DR7 */
if (!x) x = "";
if (*x)
xlocal = ((strncmp(x,cttnam,DEVNAMLEN) == 0) ? 0 : 1);
else
xlocal = 1;
debug(F111,"ttopen ttyname(ttyfd) xlocal",x,xlocal);
}
}
#ifndef NOFDZERO
/* Note, the following code was added so that Unix "idle-line" snoopers */
/* would not think Kermit was idle when it was transferring files, and */
/* maybe log people out. */
if (xlocal == 0) { /* Remote mode */
if (fdflag == 0) { /* Standard i/o is not redirected */
debug(F100,"ttopen setting ttyfd = 0","",0);
#ifdef LYNXOS
/* On Lynx OS, fd 0 is open for read only. */
dup2(ttyfd,0);
#endif /* LYNXOS */
close(ttyfd); /* Use file descriptor 0 */
ttyfd = 0;
} else { /* Standard i/o is redirected */
debug(F101,"ttopen stdio redirected","",ttyfd);
}
}
#endif /* NOFDZERO */
/* Now check if line is locked -- if so fail, else lock for ourselves */
/* Note: After having done this, don't forget to delete the lock if you */
/* leave ttopen() with an error condition. */
lkf = 0; /* Check lock */
if (xlocal > 0) {
int xx; int xpid;
if ((xx = ttlock(ttname)) < 0) { /* Can't lock it. */
debug(F111,"ttopen ttlock fails",ttname,xx);
/* WARNING - This close() can hang if tty is an empty socket... */
close(ttyfd); /* Close the device. */
ttyfd = -1; /* Erase its file descriptor. */
wasclosed = 1;
signal(SIGINT,occt); /* Put old SIGINT back. */
sigint_ign = (occt == SIG_IGN) ? 1 : 0;
if (xx == -2) { /* If lockfile says device in use, */
#ifndef NOUUCP
debug(F111,"ttopen reading lockfile pid",flfnam,xx);
xpid = ttrpid(flfnam); /* Try to read pid from lockfile */
if (xpid > -1) { /* If we got a pid */
if (!quiet)
printf("Locked by process %d\n",xpid); /* tell them. */
sprintf(lockpid,"%d",xpid); /* Record it too */
debug(F110,"ttopen lockpid",lockpid,0);
} else if (*flfnam) {
extern char *DIRCMD;
char *p = NULL;
int x;
x = (int)strlen(flfnam) + (int)strlen(DIRCMD) + 2;
p = malloc(x); /* Print a directory listing. */
/*
Note: priv_on() won't help here, because we do not pass privs along to
to inferior processes, in this case ls. So if the real user does not have
directory-listing access to the lockfile directory, this will result in
something like "not found". That's why we try this only as a last resort.
*/
if (p) { /* If we got the space... */
ckmakmsg(p,x,DIRCMD," ",flfnam,NULL);
zsyscmd(p); /* Get listing. */
if (p) { /* free the space */
free(p);
p = NULL;
}
}
}
#endif /* NOUUCP */
return(-5); /* Code for device in use */
} else return(-3); /* Access denied */
} else lkf = 1;
}
#else /* OPENFIRST */
/*
27 Oct 2001: New simpler code that gets the lock first and then opens the
device, which eliminates the race condition. The downside is you can no
longer say "set line /dev/ttyp0" or whatever, where /dev/ttyp0 is your login
terminal, without trying to create a lockfile, which fails if C-Kermit lacks
privs, and if it succeeds, it has created a lockfile where it didn't create
one before.
*/
xlocal = *lcl; /* Is the device my login terminal? */
debug(F111,"ttopen xlocal","A",xlocal);
fnam = ttname;
if (strcmp(ttname,CTTNAM) && netconn == 0) {
if (zfnqfp(ttname,DEVNAMLEN+1,fullname)) {
if ((int)strlen(fullname) > 0)
fnam = fullname;
}
}
debug(F110,"ttopen fnam",fnam,0);
if (xlocal < 0) {
xlocal = (strcmp(fnam,CTTNAM) != 0);
}
debug(F111,"ttopen xlocal","B",xlocal);
lkf = 0; /* No lock yet */
if (xlocal > 0) { /* If not... */
int xx; int xpid;
xx = ttlock(fnam); /* Try to lock it. */
debug(F101,"ttopen ttlock","",xx);
if (xx < 0) { /* Can't lock it. */
debug(F111,"ttopen ttlock fails",fnam,xx);
if (xx == -2) { /* If lockfile says device in use, */
#ifndef NOUUCP
debug(F111,"ttopen reading lockfile pid",flfnam,xx);
xpid = ttrpid(flfnam); /* Try to read pid from lockfile */
if (xpid > -1) { /* If we got a pid */
if (!quiet)
printf("Locked by process %d\n",xpid); /* tell them. */
ckstrncpy(lockpid,ckitoa(xpid),16);
debug(F110,"ttopen lockpid",lockpid,0);
#ifndef NOPUSH
} else if (flfnam[0] && !nopush) {
extern char *DIRCMD;
char *p = NULL;
int x;
x = (int)strlen(flfnam) + (int)strlen(DIRCMD) + 2;
p = malloc(x); /* Print a directory listing. */
/*
Note: priv_on() won't help here, because we do not pass privs along to
to inferior processes, in this case ls. So if the real user does not have
directory-listing access to the lockfile directory, this will result in
something like "not found". That's why we try this only as a last resort.
*/
if (p) { /* If we got the space... */
ckmakmsg(p,x,DIRCMD," ",flfnam,NULL);
zsyscmd(p); /* Get listing. */
if (p) { /* free the space */
free(p);
p = NULL;
}
}
#endif /* NOPUSH */
}
#endif /* NOUUCP */
return(-5); /* Code for device in use */
} else return(-3); /* Access denied */
} else lkf = 1;
}
/* Have lock -- now it's safe to open the device */
debug(F101,"ttopen lkf","",lkf);
debug(F101,"ttopen timo","",timo);
ttotmo = 0; /* Flag no timeout */
if (timo > 0) {
int xx;
saval = signal(SIGALRM,timerh); /* Timed, set up timer. */
xx = alarm(timo); /* Timed open() */
debug(F101,"ttopen alarm","",xx);
if (
#ifdef CK_POSIX_SIG
sigsetjmp(sjbuf,1)
#else
setjmp(sjbuf)
#endif /* CK_POSIX_SIG */
) {
ttotmo = 1; /* Flag timeout. */
} else {
ttyfd = do_open(fnam);
}
ttimoff();
debug(F111,"ttopen timed ttyfd",fnam,ttyfd);
} else {
errno = 0;
ttyfd = do_open(fnam);
debug(F111,"ttopen untimed ttyfd",fnam,ttyfd);
}
if (ttyfd < 0) { /* If couldn't open, fail. */
debug(F111,"ttopen errno",fnam,errno);
debug(F111,"ttopen xlocal","C",xlocal);
if (xlocal == 0) {
debug(F100,"ttopen substituting 0","",0);
ttyfd = 0;
} else {
if (errno > 0 && !quiet) {
debug(F111,"ttopen perror",fnam,errno);
perror(fnam); /* Print message */
}
if (ttunlck()) /* Release the lock file */
fprintf(stderr,"Warning, problem releasing lock\r\n");
}