1: char *ckxv = "UNIX Communications support, 5A(0102), 23 Nov 92"; 2: 3: /* C K U T I O */ 4: 5: /* C-Kermit interrupt, terminal control & i/o functions for UNIX */ 6: 7: /* 8: Author: Frank da Cruz (fdc@columbia.edu, FDCCU@CUVMA.BITNET), 9: Columbia University Center for Computing Activities. 10: First released January 1985. 11: Copyright (C) 1985, 1992, Trustees of Columbia University in the City of New 12: York. Permission is granted to any individual or institution to use this 13: software as long as it is not sold for profit. This copyright notice must be 14: retained. This software may not be included in commercial products without 15: written permission of Columbia University. 16: */ 17: 18: /* Includes */ 19: 20: #include "ckcdeb.h" /* This moved to here. */ 21: #include <errno.h> /* System error numbers */ 22: #ifdef __386BSD__ 23: #define ENOTCONN 57 24: #endif /* __386BSD__ */ 25: 26: #include "ckcnet.h" /* Symbols for network types. */ 27: 28: /* 29: The directory-related includes are here because we need to test some 30: file-system-related symbols to find out which system we're being compiled 31: under. For example, MAXNAMLEN is defined in BSD4.2 but not 4.1. 32: */ 33: #ifdef SDIRENT /* Directory bits... */ 34: #define DIRENT 35: #endif /* SDIRENT */ 36: 37: #ifdef XNDIR 38: #include <sys/ndir.h> 39: #else /* !XNDIR */ 40: #ifdef NDIR 41: #include <ndir.h> 42: #else /* !NDIR, !XNDIR */ 43: #ifdef RTU 44: #include "/usr/lib/ndir.h" 45: #else /* !RTU, !NDIR, !XNDIR */ 46: #ifdef DIRENT 47: #ifdef SDIRENT 48: #include <sys/dirent.h> 49: #else 50: #include <dirent.h> 51: #endif /* SDIRENT */ 52: #else /* !RTU, !NDIR, !XNDIR, !DIRENT, i.e. all others */ 53: #include <sys/dir.h> 54: #endif /* DIRENT */ 55: #endif /* RTU */ 56: #endif /* NDIR */ 57: #endif /* XNDIR */ 58: 59: /* Definition of HZ, used in msleep() */ 60: 61: #ifdef MIPS 62: #define HZ ( 1000 / CLOCK_TICK ) 63: #else 64: #ifdef ATTSV 65: #ifndef NAP 66: #ifndef TRS16 67: #include <sys/param.h> 68: #else 69: #define HZ ( 1000 / CLOCK_TICK ) 70: #endif /* TRS16 */ 71: #ifdef NAPHACK 72: #define nap(x) (void)syscall(3112, (x)) 73: #define NAP 74: #endif /* NAPHACK */ 75: #endif /* NAP */ 76: #endif /* ATTSV */ 77: #endif /* MIPS */ 78: 79: #ifdef M_UNIX 80: #undef NGROUPS_MAX /* Prevent multiple definition warnings */ 81: #endif /* M_UNIX */ 82: 83: #include <signal.h> /* Signals */ 84: 85: /* For setjmp and longjmp */ 86: 87: #ifndef ZILOG 88: #include <setjmp.h> 89: #else 90: #include <setret.h> 91: #endif /* ZILOG */ 92: 93: /* Maximum length for the name of a tty device */ 94: 95: #ifndef DEVNAMLEN 96: #define DEVNAMLEN 25 97: #endif 98: 99: #ifdef NETCONN 100: #undef DEVNAMLEN 101: #define DEVNAMLEN 50 /* longer field for host:service */ 102: #endif /* NETCONN */ 103: 104: /* 105: The following test differentiates between 4.1 BSD and 4.2 & later. 106: If you have a 4.1BSD system with the DIRENT library, this test could 107: mistakenly diagnose 4.2BSD and then later enable the use of system calls 108: that aren't defined. If indeed there are such systems, we can use some 109: other way of testing for 4.1BSD, or add yet another compile-time switch. 110: */ 111: #ifdef BSD4 112: #ifdef MAXNAMLEN 113: #ifndef FT21 114: #ifndef FT18 /* Except for Fortune. */ 115: #define BSD42 116: #endif /* FT18 */ 117: #endif /* FT21 */ 118: #endif /* MAXNAMLEN */ 119: #endif /* BSD4 */ 120: /* 121: Minix support added by Charles Hedrick, 122: Rutgers University: hedrick@aramis.rutgers.edu 123: Minix also has V7 enabled. 124: */ 125: #ifdef MINIX 126: #define TANDEM 0 127: #define MYREAD 128: #include <limits.h> 129: #endif /* MINIX */ 130: 131: #include "ckuver.h" /* Version herald */ 132: char *ckxsys = HERALD; 133: 134: /* UUCP lock file name definition */ 135: 136: #ifndef NOUUCP 137: 138: /* Name of UUCP tty device lock file */ 139: 140: #ifdef ACUCNTRL 141: #define LCKDIR 142: #endif /* ACUCNTRL */ 143: /* 144: LOCK_DIR is the name of the lockfile directory. 145: If LOCK_DIR is already defined (e.g. on command line), we don't change it. 146: PIDSTRING means use ASCII string to represent pid in lockfile. 147: */ 148: #ifndef LOCK_DIR 149: #ifdef BSD44 150: #define LOCK_DIR "/var/spool/uucp"; 151: #else 152: #ifdef DGUX430 153: #define LOCK_DIR "/var/spool/locks"; 154: #else 155: #ifdef RTAIX /* IBM RT PC AIX 2.2.1 */ 156: #define PIDSTRING 157: #define LOCK_DIR "/etc/locks"; 158: #else 159: #ifdef AIXRS 160: #define PIDSTRING 161: #define LOCK_DIR "/etc/locks"; 162: #else 163: #ifdef ISIII 164: #define LOCK_DIR "/etc/locks"; 165: #else 166: #ifdef HDBUUCP 167: #define PIDSTRING 168: #ifdef M_SYS5 /* wht@n4hgf - SCO */ 169: #define LOCK_DIR "/usr/spool/uucp"; 170: #else 171: #ifdef M_UNIX 172: #define LOCK_DIR "/usr/spool/uucp"; 173: #else 174: #ifdef SVR4 175: #define LOCK_DIR "/var/spool/locks"; 176: #ifndef LOCKF 177: #define LOCKF /* Use lockf() too in SVR4 */ 178: #endif /* LOCKF */ 179: #else 180: #ifdef SUNOS4 181: #define LOCK_DIR "/var/spool/locks"; 182: #else 183: #define LOCK_DIR "/usr/spool/locks"; 184: #endif /* SUNOS4 */ 185: #endif /* SVR4 */ 186: #endif /* M_UNIX */ 187: #endif /* M_SYS5 */ 188: #else 189: #ifdef LCKDIR 190: #define LOCK_DIR "/usr/spool/uucp/LCK"; 191: #else 192: #define LOCK_DIR "/usr/spool/uucp"; 193: #endif /* LCKDIR */ 194: #endif /* HDBUUCP */ 195: #endif /* ISIII */ 196: #endif /* AIXRS */ 197: #endif /* RTAIX */ 198: #endif /* DGUX430 */ 199: #endif /* BSD44 */ 200: #endif /* !LOCK_DIR (outside ifndef) */ 201: 202: #endif /* !NOUUCP */ 203: 204: #ifdef ATTSV 205: #define MYREAD 206: #endif /* ATTSV */ 207: 208: #ifdef ATT7300 209: #ifndef MYREAD 210: #define MYREAD 211: #endif /* MYREAD */ 212: /* bits for attmodem: internal modem in use, restart getty */ 213: #define ISMODEM 1 214: #define DOGETY 512 215: #endif /* ATT7300 */ 216: 217: #ifdef BSD42 218: #define MYREAD 219: #endif /* BSD42 */ 220: 221: #ifdef POSIX 222: #define MYREAD 223: #endif /* POSIX */ 224: 225: /* 226: Variables available to outside world: 227: 228: dftty -- Pointer to default tty name string, like "/dev/tty". 229: dfloc -- 0 if dftty is console, 1 if external line. 230: dfprty -- Default parity 231: dfflow -- Default flow control 232: ckxech -- Flag for who echoes console typein: 233: 1 - The program (system echo is turned off) 234: 0 - The system (or front end, or terminal). 235: functions that want to do their own echoing should check this flag 236: before doing so. 237: 238: flfnam -- Name of lock file, including its path, e.g., 239: "/usr/spool/uucp/LCK..cul0" or "/etc/locks/tty77" 240: lkflfn -- Name of link to lock file, including its paths 241: haslock -- Flag set if this kermit established a uucp lock. 242: backgrd -- Flag indicating program executing in background ( & on 243: end of shell command). Used to ignore INT and QUIT signals. 244: rtu_bug -- Set by stptrap(). RTU treats ^Z as EOF (but only when we handle 245: SIGTSTP) 246: 247: Functions for assigned communication line (either external or console tty): 248: 249: sysinit() -- System dependent program initialization 250: syscleanup() -- System dependent program shutdown 251: ttopen(ttname,local,mdmtyp,timo) -- Open the named tty for exclusive access. 252: ttclos() -- Close & reset the tty, releasing any access lock. 253: ttsspd(cps) -- Set the transmission speed of the tty. 254: ttgspd() -- Get (read) the the transmission speed of the tty. 255: ttpkt(speed,flow,parity) -- Put the tty in packet mode and set the speed. 256: ttvt(speed,flow) -- Put the tty in virtual terminal mode. 257: or in DIALING or CONNECTED modem control state. 258: ttres() -- Restore original tty modes. 259: ttscarr(carrier) -- Set carrier control mode, on/off/auto. 260: ttinl(dest,max,timo) -- Timed read line from the tty. 261: ttinc(timo) -- Timed read character from tty. 262: myread() -- Raw mode bulk buffer read, gives subsequent 263: chars one at a time and simulates FIONREAD. 264: myunrd(c) -- Places c back in buffer to be read (one only) 265: ttchk() -- See how many characters in tty input buffer. 266: ttxin(n,buf) -- Read n characters from tty (untimed). 267: ttol(string,length) -- Write a string to the tty. 268: ttoc(c) -- Write a character to the tty. 269: ttflui() -- Flush tty input buffer. 270: ttsndb() -- Send BREAK signal. 271: ttsndlb() -- Send Long BREAK signal. 272: 273: ttlock(ttname) -- "Lock" tty device against uucp collisions. 274: ttunlck() -- Unlock tty device. 275: 276: For ATT7300/Unix PC, System V: 277: attdial(ttname,speed,telnbr) -- dials ATT7300/Unix PC internal modem 278: offgetty(ttname) -- Turns off getty(1m) for comms line 279: ongetty(ttname) -- Restores getty() to comms line 280: */ 281: 282: /* 283: Functions for console terminal: 284: 285: congm() -- Get console terminal modes. 286: concb(esc) -- Put the console in single-character wakeup mode with no echo. 287: conbin(esc) -- Put the console in binary (raw) mode. 288: conres() -- Restore the console to mode obtained by congm(). 289: conoc(c) -- Unbuffered output, one character to console. 290: conol(s) -- Unbuffered output, null-terminated string to the console. 291: conola(s) -- Unbuffered output, array of strings to the console. 292: conxo(n,s) -- Unbuffered output, n characters to the console. 293: conchk() -- Check if characters available at console (bsd 4.2). 294: Check if escape char (^\) typed at console (System III/V). 295: coninc(timo) -- Timed get a character from the console. 296: congks(timo) -- Timed get keyboard scan code. 297: conint() -- Enable terminal interrupts on the console if not background. 298: connoi() -- Disable terminal interrupts on the console if not background. 299: 300: Time functions 301: 302: msleep(m) -- Millisecond sleep 303: ztime(&s) -- Return pointer to date/time string 304: rtimer() -- Reset timer 305: gtimer() -- Get elapsed time since last call to rtimer() 306: */ 307: 308: /* Conditional Includes */ 309: 310: /* Whether to include <sys/file.h> */ 311: 312: #ifdef RTU /* RTU doesn't */ 313: #define NOFILEH 314: #endif /* RTU */ 315: 316: #ifdef CIE /* CIE does. */ 317: #undef NOFILEH 318: #endif /* CIE */ 319: 320: #ifdef BSD41 /* 4.1 BSD doesn't */ 321: #define NOFILEH 322: #endif /* BSD41 */ 323: 324: #ifdef is68k /* is68k (whatever that is) */ 325: #define NOFILEH 326: #endif /* is68k */ 327: 328: #ifdef MINIX /* MINIX */ 329: #define NOFILEH 330: #endif /* MINIX */ 331: 332: #ifdef COHERENT /* Coherent */ 333: #define NOFILEH 334: #endif /* COHERENT */ 335: 336: #ifndef NOFILEH /* Now include if selected. */ 337: #include <sys/file.h> 338: #endif /* NOFILEH */ 339: 340: /* POSIX */ 341: 342: #ifdef BSD44ORPOSIX /* POSIX uses termios.h */ 343: #define TERMIOS 344: #ifdef bsdi 345: #ifndef NCCS 346: #define NCCS 20 347: #endif /* NCCS */ 348: #endif /* bsdi */ 349: #include <termios.h> 350: #ifndef BSD44 /* Really POSIX */ 351: #define NOSYSIOCTLH /* No ioctl's allowed. */ 352: #undef ultrix /* Turn off any ultrix features. */ 353: #endif /* BSD44 */ 354: #endif /* POSIX */ 355: 356: /* System III, System V */ 357: 358: #ifdef ATTSV 359: #ifndef BSD44 360: #include <termio.h> 361: #endif /* BSD44 */ 362: #ifdef SVR4 /* Sys V R4 and later */ 363: #ifdef TERMIOX 364: /* Need this for termiox structure, RTS/CTS and DTR/CD flow control */ 365: #include <termiox.h> 366: struct termiox rctsx; 367: #else 368: #ifdef STERMIOX 369: #include <sys/termiox.h> 370: struct termiox rctsx; 371: #endif /* STERMIOX */ 372: #endif /* TERMIOX */ 373: #endif /* SVR4 */ 374: #endif /* ATTSV */ 375: 376: #ifdef MINIX /* MINIX uses ioctl's */ 377: #define NOSYSIOCTLH /* but has no <sys/ioctl.h> */ 378: #endif /* MINIX */ 379: 380: /* Others */ 381: 382: #ifndef NOSYSIOCTLH /* Others use ioctl() */ 383: #ifdef SUN4S5 384: /* 385: This is to get rid of cpp warning messages that occur because all of 386: these symbols are defined by both termios.h and ioctl.h on the SUN. 387: */ 388: #undef ECHO 389: #undef NL0 390: #undef NL1 391: #undef TAB0 392: #undef TAB1 393: #undef TAB2 394: #undef XTABS 395: #undef CR0 396: #undef CR1 397: #undef CR2 398: #undef CR3 399: #undef FF0 400: #undef FF1 401: #undef BS0 402: #undef BS1 403: #undef TOSTOP 404: #undef FLUSHO 405: #undef PENDIN 406: #undef NOFLSH 407: #endif /* SUN4S5 */ 408: #include <sys/ioctl.h> 409: #endif /* NOSYSIOCTLH */ 410: 411: /* Whether to include <fcntl.h> */ 412: 413: #ifndef is68k /* Only a few don't have this one. */ 414: #ifndef BSD41 415: #ifndef FT21 416: #ifndef FT18 417: #ifndef COHERENT 418: #include <fcntl.h> 419: #endif /* COHERENT */ 420: #endif /* FT18 */ 421: #endif /* FT21 */ 422: #endif /* BSD41 */ 423: #endif /* not is68k */ 424: 425: #ifdef COHERENT 426: #include <sys/fcntl.h> 427: #endif /* COHERENT */ 428: 429: #ifdef ATT7300 /* Unix PC, internal modem dialer */ 430: #include <sys/phone.h> 431: #endif /* ATT7300 */ 432: 433: #ifdef HPUX /* HP-UX variations. */ 434: #define HPUXJOBCTL 435: #include <sys/modem.h> /* HP-UX modem signals */ 436: #ifdef hp9000s500 /* Model 500 */ 437: #undef HPUXJOBCTL 438: #endif /* hp9000s500 */ 439: #ifdef HPUXPRE65 440: #undef HPUXJOBCTL 441: typedef int mflag; 442: #endif /* HPUXPRE65 */ 443: #ifdef HPUXJOBCTL 444: #include <sys/bsdtty.h> /* HP-UX Berkeley tty support */ 445: #endif /* HPUXJOBCTL */ 446: #endif /* HPUX */ 447: 448: /* BSD, V7, Coherent, Minix, et al. */ 449: 450: #ifdef SVORPOSIX /* Sys V or POSIX */ 451: #ifdef BSD44 452: #include <sys/time.h> 453: #endif /* BSD44 */ 454: #ifdef AIXRS 455: #include <sys/time.h> 456: #endif /* AIXRS */ 457: #ifdef NOIEXTEN /* This is broken on some systems */ 458: #undef IEXTEN /* like Convex/OS 9.1 */ 459: #endif /* NOIEXTEN */ 460: #ifndef IEXTEN /* Turn off ^O/^V processing. */ 461: #define IEXTEN 0 /* Needed, at least, on BSDI. */ 462: #endif /* IEXTEN */ 463: #else /* Not AT&T Sys V or POSIX */ 464: #include <sgtty.h> /* So we use <sgtty.h> */ 465: #ifndef PROVX1 /* Now <sys/time.h> ... */ 466: #ifndef V7 467: #ifndef BSD41 468: #ifndef COHERENT 469: #include <sys/time.h> /* Clock info (for break generation) */ 470: #endif /* COHERENT */ 471: #endif /* BSD41 */ 472: #endif /* V7 */ 473: #endif /* PROVX1 */ 474: #endif /* SVORPOSIX */ 475: 476: #ifdef OSF /* DEC OSF/1 1.0 */ 477: #include <sys/timeb.h> 478: #endif /* OSF */ 479: 480: #ifdef BSD41 /* BSD 4.1 */ 481: #include <sys/timeb.h> 482: #endif /* BSD41 */ 483: 484: #ifdef FT21 /* For:Pro 2.1 */ 485: #include <sys/timeb.h> 486: #endif /* FT21 */ 487: 488: #ifdef BSD29 /* BSD 2.9 */ 489: #include <sys/timeb.h> 490: #endif /* BSD29 */ 491: 492: #ifdef TOWER1 493: #include <sys/timeb.h> /* Clock info for NCR Tower */ 494: #endif /* TOWER1 */ 495: 496: #ifdef COHERENT 497: #include <sys/timeb.h> /* Clock info for NCR Tower */ 498: #endif /* COHERENT */ 499: 500: #ifdef aegis 501: #include "/sys/ins/base.ins.c" 502: #include "/sys/ins/error.ins.c" 503: #include "/sys/ins/ios.ins.c" 504: #include "/sys/ins/sio.ins.c" 505: #include "/sys/ins/pad.ins.c" 506: #include "/sys/ins/time.ins.c" 507: #include "/sys/ins/pfm.ins.c" 508: #include "/sys/ins/pgm.ins.c" 509: #include "/sys/ins/ec2.ins.c" 510: #include "/sys/ins/type_uids.ins.c" 511: #include <default_acl.h> 512: #undef TIOCEXCL 513: #undef FIONREAD 514: #endif /* aegis */ 515: 516: #ifdef sxaE50 /* PFU Compact A SX/A TISP V10/L50 */ 517: #undef FIONREAD 518: #endif /* sxaE50 */ 519: 520: /* The following #defines are catch-alls for those systems */ 521: /* that didn't have or couldn't find <file.h>... */ 522: 523: #ifndef FREAD 524: #define FREAD 0x01 525: #endif /* FREAD */ 526: 527: #ifndef FWRITE 528: #define FWRITE 0x10 529: #endif /* FWRITE */ 530: 531: #ifndef O_RDONLY 532: #define O_RDONLY 000 533: #endif /* O_RDONLY */ 534: 535: /* Declarations */ 536: 537: #ifdef _POSIX_SOURCE /* This includes MINIX */ 538: #ifndef AIXRS 539: #include <time.h> 540: #endif /* AIXRS */ 541: #ifdef __GNUC__ 542: #ifdef XENIX 543: /* 544: Because Xenix <time.h> doesn't declare time() if we're using gcc. 545: */ 546: time_t time(); 547: #endif /* XENIX */ 548: #endif /* __GNUC__ */ 549: #else 550: time_t time(); /* All Unixes should have this... */ 551: #endif /* _POSIX_SOURCE */ 552: 553: /* Special stuff for V7 input buffer peeking */ 554: 555: #ifdef V7 556: int kmem[2] = { -1, -1}; 557: char *initrawq(), *qaddr[2]={0,0}; 558: #define CON 0 559: #define TTY 1 560: #endif /* V7 */ 561: 562: /* dftty is the device name of the default device for file transfer */ 563: /* dfloc is 0 if dftty is the user's console terminal, 1 if an external line */ 564: 565: #ifndef DFTTY 566: #ifdef PROVX1 567: char *dftty = "/dev/com1.dout"; /* Only example so far of a system */ 568: char *dfmdm = "none"; 569: int dfloc = 1; /* that goes in local mode by default */ 570: #else 571: #ifdef COHERENT 572: char *dftty = "/dev/modem"; 573: char *dfmdm = "none"; 574: int dfloc = 1; 575: #else 576: char *dftty = CTTNAM; /* Remote by default, use normal */ 577: char *dfmdm = "none"; 578: int dfloc = 0; /* controlling terminal name. */ 579: #endif /* COHERENT */ 580: #endif /* PROVX1 */ 581: #else 582: char *dftty = DFTTY; /* Default location specified on */ 583: char *dfmdm = "none"; /* command line. */ 584: int dfloc = 1; /* controlling terminal name. */ 585: #endif /* DFTTY */ 586: 587: #ifdef RTU 588: int rtu_bug = 0; /* set to 1 when returning from SIGTSTP */ 589: #endif /* RTU */ 590: 591: int dfprty = 0; /* Default parity (0 = none) */ 592: int ttprty = 0; /* The parity that is in use. */ 593: int ttpflg = 0; /* Parity not sensed yet. */ 594: static int ttpmsk = 0377; /* Parity stripping mask. */ 595: int ttmdm = 0; /* Modem in use. */ 596: int ttcarr = CAR_AUT; /* Carrier handling mode. */ 597: int dfflow = FLO_XONX; /* Default is Xon/Xoff */ 598: int backgrd = 0; /* Assume in foreground (no '&' ) */ 599: #ifdef ultrix 600: int iniflags = 0; /* fcntl flags for ttyfd */ 601: #endif /* ultrix */ 602: int fdflag = 0; /* Flag for redirected stdio */ 603: int ttfdflg = 0; /* Open File descriptor was given */ 604: int tvtflg = 0; /* Flag that ttvt has been called */ 605: long ttspeed = -1; /* For saving speed */ 606: int ttflow = -9; /* For saving flow */ 607: int ttld = -1; /* Line discipline */ 608: 609: #ifdef sony_news 610: static int km_con = -1; /* Kanji mode for console tty */ 611: static int km_ext = -1; /* Kanji mode for external device */ 612: #endif /* sony_news */ 613: 614: extern int ttnproto; /* Defined in ckcnet.c */ 615: extern int ttnet; /* Defined in ckcnet.c */ 616: 617: int ckxech = 0; /* 0 if system normally echoes console characters, else 1 */ 618: 619: /* Declarations of variables global within this module */ 620: 621: static time_t tcount; /* Elapsed time counter */ 622: static SIGTYP (*saval)() = NULL; /* For saving alarm() handler */ 623: 624: /* 625: BREAKNULS is defined for systems that simulate sending a BREAK signal 626: by sending a bunch of NUL characters at low speed. 627: */ 628: #ifdef PROVX1 629: #ifndef BREAKNULS 630: #define BREAKNULS 631: #endif /* BREAKNULS */ 632: #endif /* PROVX1 */ 633: 634: #ifdef V7 635: #ifndef BREAKNULS 636: #define BREAKNULS 637: #endif /* BREAKNULS */ 638: #endif /* V7 */ 639: 640: #ifdef BREAKNULS 641: static char /* A string of nulls */ 642: *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"; 643: #endif /* BREAKNULS */ 644: 645: static jmp_buf sjbuf; /* Longjump buffers */ 646: #ifdef V7 647: static jmp_buf jjbuf; 648: #endif /* V7 */ 649: 650: /* static */ /* (Not static any more) */ 651: int ttyfd = -1; /* TTY file descriptor */ 652: 653: int telnetfd = 0; /* File descriptor is for telnet */ 654: int x25fd = 0; /* File descriptor is for X.25 */ 655: 656: static int lkf = 0, /* Line lock flag */ 657: cgmf = 0, /* Flag that console modes saved */ 658: xlocal = 0, /* Flag for tty local or remote */ 659: curcarr = 0; /* Carrier mode: require/ignore. */ 660: 661: static int netconn = 0; /* 1 if network connection active */ 662: 663: static char escchr; /* Escape or attn character */ 664: 665: #ifdef AIXRS 666: static struct timeval tv; /* For getting time, from sys/time.h */ 667: static struct timezone tz; 668: #else 669: #ifdef BSD44 670: static struct timeval tv; /* For getting time, from sys/time.h */ 671: static struct timezone tz; 672: #else 673: #ifdef BSD42 674: static struct timeval tv; /* For getting time, from sys/time.h */ 675: static struct timezone tz; 676: #ifdef OSF 677: static struct timeb ftp; /* And from sys/timeb.h */ 678: #endif /* OSF */ 679: #endif /* BSD42 */ 680: #endif /* BSD44 */ 681: #endif /* AIXRS */ 682: 683: #ifdef BSD29 684: static long xclock; /* For getting time from sys/time.h */ 685: static struct timeb ftp; /* And from sys/timeb.h */ 686: #endif /* BSD29 */ 687: 688: #ifdef BSD41 689: static long xclock; /* For getting time from sys/time.h */ 690: static struct timeb ftp; /* And from sys/timeb.h */ 691: #endif /* BSD41 */ 692: 693: #ifdef FT21 694: static long xclock; /* For getting time from sys/time.h */ 695: static struct timeb ftp; /* And from sys/timeb.h */ 696: #endif /* FT21 */ 697: 698: #ifdef TOWER1 699: static long xclock; /* For getting time from sys/time.h */ 700: static struct timeb ftp; /* And from sys/timeb.h */ 701: #endif /* TOWER1 */ 702: 703: #ifdef COHERENT 704: static long xclock; /* For getting time from sys/time.h */ 705: static struct timeb ftp; /* And from sys/timeb.h */ 706: #endif /* COHERENT */ 707: 708: #ifdef V7 709: static long xclock; 710: #endif /* V7 */ 711: 712: /* sgtty/termio information... */ 713: 714: #ifdef BSD44ORPOSIX /* POSIX or BSD44 */ 715: static struct termios 716: ttold, ttraw, tttvt, ttcur, 717: ccold, ccraw, cccbrk; 718: #else /* BSD, V7, etc */ 719: #ifdef ATTSV 720: static struct termio ttold = {0}; /* Init'd for word alignment, */ 721: static struct termio ttraw = {0}; /* which is important for some */ 722: static struct termio tttvt = {0}; /* systems, like Zilog... */ 723: static struct termio ttcur = {0}; 724: static struct termio ccold = {0}; 725: static struct termio ccraw = {0}; 726: static struct termio cccbrk = {0}; 727: #else 728: static struct sgttyb /* sgtty info... */ 729: ttold, ttraw, tttvt, ttcur, /* for communication line */ 730: ccold, ccraw, cccbrk; /* and for console */ 731: #ifdef TIOCGETC 732: #ifdef MINIX 733: static struct sgttyb tchold, tchnoi; /* Special chars */ 734: #else 735: static struct tchars tchold, tchnoi; 736: #endif /* MINIX */ 737: static int tcharf; 738: #endif /* TIOCGETC */ 739: #ifdef TIOCGLTC 740: #ifdef MINIX 741: static struct sgttyb ltchold, ltchnoi; 742: #else 743: static struct ltchars ltchold, ltchnoi; 744: #endif /* MINIX */ 745: static int ltcharf; 746: #endif /* TIOCGLTC */ 747: int lmodef = 0; /* Local modes */ 748: int lmode = 0; 749: #endif /* ATTSV */ 750: #endif /* BSD44ORPOSIX */ 751: 752: #ifdef PROVX1 753: static struct sgttyb ttbuf; 754: #endif /* PROVX1 */ 755: 756: #ifdef ultrix 757: /* do we really need this? */ 758: static struct sgttyb vanilla; 759: #endif /* ultrix */ 760: 761: #ifdef ATT7300 762: static int attmodem = 0; /* ATT7300 internal-modem status */ 763: struct updata dialer = {0}; /* Condition dialer for data call */ 764: #endif /* ATT7300 */ 765: 766: char flfnam[80]; /* uucp lock file path name */ 767: #ifdef RTAIX 768: char lkflfn[80]; /* and possible link to it */ 769: #endif /* RTAIX */ 770: int haslock = 0; /* =1 if this kermit locked uucp */ 771: 772: #ifdef SVORPOSIX 773: static int conesc = 0; /* set to 1 if esc char (^\) typed */ 774: #else 775: #ifdef V7 776: static int conesc = 0; 777: #else 778: #ifdef C70 779: static int conesc = 0; 780: #endif /* C70 */ 781: #endif /* V7 */ 782: #endif /* ATTSV */ 783: 784: static char ttnmsv[DEVNAMLEN]; /* Copy of open path for tthang */ 785: 786: #ifdef aegis 787: static status_$t st; /* error status return value */ 788: static short concrp = 0; /* true if console is CRP pad */ 789: #define CONBUFSIZ 10 790: static char conbuf[CONBUFSIZ]; /* console readahead buffer */ 791: static int conbufn = 0; /* # chars in readahead buffer */ 792: static char *conbufp; /* next char in readahead buffer */ 793: static uid_$t ttyuid; /* tty type uid */ 794: static uid_$t conuid; /* stdout type uid */ 795: 796: /* APOLLO Aegis main() 797: * establish acl usage and cleanup handling 798: * this makes sure that CRP pads 799: * get restored to a usable mode 800: */ 801: main(argc,argv) int argc; char **argv; { 802: status_$t status; 803: pfm_$cleanup_rec dirty; 804: 805: PID_T pid = getpid(); 806: 807: /* acl usage according to invoking environment */ 808: default_acl(USE_DEFENV); 809: 810: /* establish a cleanup continuation */ 811: status = pfm_$cleanup(dirty); 812: if (status.all != pfm_$cleanup_set) { 813: /* only handle faults for the original process */ 814: if (pid == getpid() && status.all > pgm_$max_severity) { 815: /* blew up in main process */ 816: status_$t quo; 817: pfm_$cleanup_rec clean; 818: 819: /* restore the console in any case */ 820: conres(); 821: 822: /* attempt a clean exit */ 823: debug(F101, "cleanup fault status", "", status.all); 824: 825: /* doexit(), then send status to continuation */ 826: quo = pfm_$cleanup(clean); 827: if (quo.all == pfm_$cleanup_set) 828: doexit(pgm_$program_faulted,-1); 829: else if (quo.all > pgm_$max_severity) 830: pfm_$signal(quo); /* blew up in doexit() */ 831: } 832: /* send to the original continuation */ 833: pfm_$signal(status); 834: /*NOTREACHED*/ 835: } 836: return(ckcmai(argc, argv)); 837: } 838: #endif /* aegis */ 839: 840: /* ANSI-style prototypes for internal functions. */ 841: /* Functions used outside this module are prototyped in ckcker.h. */ 842: 843: #ifdef apollo 844: _PROTOTYP( SIGTYP timerh, () ); 845: _PROTOTYP( SIGTYP cctrap, () ); 846: _PROTOTYP( SIGTYP esctrp, () ); 847: _PROTOTYP( SIGTYP sig_ign, () ); 848: #else 849: _PROTOTYP( SIGTYP timerh, (int) ); 850: _PROTOTYP( SIGTYP cctrap, (int) ); 851: _PROTOTYP( SIGTYP esctrp, (int) ); 852: #endif /* apollo */ 853: _PROTOTYP( int do_open, (char *) ); 854: _PROTOTYP( int ttrpid, (char *) ); 855: _PROTOTYP( static int ttlock, (char *) ); 856: _PROTOTYP( static int ttunlck, (void) ); 857: _PROTOTYP( int mygetbuf, (void) ); 858: _PROTOTYP( int myfillbuf, (void) ); 859: _PROTOTYP( VOID conbgt, (int) ); 860: #ifdef ACUCNTRL 861: _PROTOTYP( VOID acucntrl, (char *, char *) ); 862: #endif /* ACUCNTRL */ 863: 864: #ifdef BSD44ORPOSIX 865: _PROTOTYP( int carrctl, (struct termios *, int) ); 866: #else 867: #ifdef ATTSV 868: _PROTOTYP( int carrctl, (struct termio *, int) ); 869: #else 870: _PROTOTYP( int carrctl, (struct sgttyb *, int) ); 871: #endif /* ATTSV */ 872: #endif /* BSD44ORPOSIX */ 873: 874: #ifdef ATT7300 875: _PROTOTYP( int attdial, (char *, long, char *) ); 876: _PROTOTYP( int offgetty, (char *) ); 877: _PROTOTYP( int ongetty, (char *) ); 878: #endif /* ATT7300 */ 879: 880: #ifdef CK_ANSIC 881: static char * 882: xxlast(char *s, char c) 883: #else 884: static char * 885: xxlast(s,c) char *s; char c; 886: #endif /* CK_ANSIC */ 887: /* xxlast */ { /* Last occurrence of character c in string s. */ 888: int i; 889: for (i = (int)strlen(s); i > 0; i--) 890: if ( s[i-1] == c ) return( s + (i - 1) ); 891: return(NULL); 892: } 893: 894: /* Timeout handler for communication line input functions */ 895: 896: SIGTYP 897: timerh(foo) int foo; { 898: ttimoff(); 899: longjmp(sjbuf,1); 900: } 901: 902: /* Control-C trap for communication line input functions */ 903: 904: int cc_int; /* Flag */ 905: SIGTYP (* occt)(); /* For saving old SIGINT handler */ 906: 907: SIGTYP 908: cctrap(foo) int foo; { /* Needs arg for ANSI C */ 909: cc_int = 1; /* signal() prototype. */ 910: return; 911: } 912: 913: /* S Y S I N I T -- System-dependent program initialization. */ 914: 915: int 916: sysinit() { 917: int x; 918: 919: conbgt(0); /* See if we're in the background */ 920: #ifndef __386BSD__ 921: /* 922: 386BSD doesn't allow opening /dev/tty if Kermit is running setuid. 923: */ 924: congm(); /* Get console modes */ 925: #endif /* __386BSD__ */ 926: signal(SIGALRM,SIG_IGN); /* Ignore alarms */ 927: 928: #ifdef ultrix 929: gtty(0,&vanilla); /* Get sgtty info */ 930: iniflags = fcntl(0,F_GETFL,0); /* Get flags */ 931: #else 932: #ifdef AUX 933: set42sig(); /* Don't ask! (hakanson@cs.orst.edu) */ 934: #endif /* AUX */ 935: #endif /* ultrix */ 936: 937: /* Initialize the setuid package. */ 938: /* Change to the user's real user and group id. */ 939: /* If this can't be done, don't run at all. */ 940: 941: if (x = priv_ini()) { 942: if (x | 1) fprintf(stderr,"Fatal: setuid failure.\n"); 943: if (x | 2) fprintf(stderr,"Fatal: setgid failure.\n"); 944: if (x | 4) fprintf(stderr,"Fatal: C-Kermit setuid to root!\n"); 945: exit(1); 946: } 947: #ifdef __386BSD__ 948: /* 949: 386BSD... OK, now we have changed into ourselves, so can open /dev/tty. 950: */ 951: congm(); /* Get console modes */ 952: #endif /* __386BSD__ */ 953: return(0); 954: } 955: 956: /* S Y S C L E A N U P -- System-dependent program cleanup. */ 957: 958: int 959: syscleanup() { 960: #ifdef ultrix 961: stty(0,&vanilla); /* Get sgtty info */ 962: fcntl(0,F_SETFL,iniflags); /* Restore flags */ 963: #endif /* ultrix */ 964: /* No need to call anything in the suid package here, right? */ 965: return(0); 966: } 967: 968: /* T T O P E N -- Open a tty for exclusive access. */ 969: 970: /* 971: Call with: 972: ttname: character string - device name or network host name. 973: lcl: 974: If called with lcl < 0, sets value of lcl as follows: 975: 0: the terminal named by ttname is the job's controlling terminal. 976: 1: the terminal named by ttname is not the job's controlling terminal. 977: But watch out: if a line is already open, or if requested line can't 978: be opened, then lcl remains (and is returned as) -1. 979: modem: 980: Less than zero: ttname is a network host name. 981: Zero or greater: ttname is a terminal device name. 982: Zero means a local connection (don't use modem signals). 983: Positive means use modem signals. 984: timo: 985: 0 = no timer. 986: nonzero = number of seconds to wait for open() to return before timing out. 987: 988: Returns: 989: 0 on success 990: -5 if device is in use 991: -4 if access to device is denied 992: -3 if access to lock directory denied 993: -2 upon timeout waiting for device to open 994: -1 on other error 995: */ 996: static int ttotmo = 0; /* Timeout flag */ 997: /* Flag kept here to avoid being clobbered by longjmp. */ 998: 999: int 1000: ttopen(ttname,lcl,modem,timo) char *ttname; int *lcl, modem, timo; { 1001: 1002: #ifdef BSD44 1003: #define ctermid(x) strcpy(x,"") 1004: #else 1005: #ifdef SVORPOSIX 1006: #ifndef CIE 1007: extern char *ctermid(); /* Wish they all had this! */ 1008: #else /* CIE Regulus */ 1009: #define ctermid(x) strcpy(x,"") 1010: #endif /* CIE */ 1011: #endif /* SVORPOSIX */ 1012: #endif /* BSD44 */ 1013: 1014: char *x; /* what's this ? */ 1015: 1016: #ifndef MINIX 1017: extern char* ttyname(); 1018: #endif /* MINIX */ 1019: char cname[DEVNAMLEN+4]; 1020: 1021: #ifndef pdp11 1022: #define NAMEFD /* Feature to allow name to be an open file descriptor */ 1023: #endif /* pdp11 */ 1024: 1025: #ifdef NAMEFD 1026: char *p; 1027: 1028: debug(F101,"ttopen telnetfd","",telnetfd); 1029: #endif /* NAMEFD */ 1030: 1031: debug(F111,"ttopen entry modem",ttname,modem); 1032: debug(F101," ttyfd","",ttyfd); 1033: debug(F101," lcl","",*lcl); 1034: 1035: #ifdef MAXNAMLEN 1036: debug(F100,"ttopen MAXNAMLEN defined","",0); 1037: #else 1038: debug(F100,"ttopen MAXNAMLEN *NOT* defined","",0); 1039: #endif 1040: 1041: #ifdef BSD4 1042: debug(F100,"ttopen BSD4 defined","",0); 1043: #else 1044: debug(F100,"ttopen BSD4 *NOT* defined","",0); 1045: #endif 1046: 1047: #ifdef BSD42 1048: debug(F100,"ttopen BSD42 defined","",0); 1049: #else 1050: debug(F100,"ttopen BSD42 *NOT* defined","",0); 1051: #endif /* BSD42 */ 1052: 1053: #ifdef MYREAD 1054: debug(F100,"ttopen MYREAD defined","",0); 1055: #else 1056: debug(F100,"ttopen MYREAD *NOT* defined","",0); 1057: #endif /* MYREAD */ 1058: 1059: 1060: if (ttyfd > -1) { /* if device already opened */ 1061: if (strncmp(ttname,ttnmsv,DEVNAMLEN)) /* are new & old names equal? */ 1062: ttclos(ttyfd); /* no, close old ttname, open new */ 1063: else /* else same, ignore this call, */ 1064: return(0); /* and return. */ 1065: } 1066: 1067: #ifdef NETCONN 1068: if (modem < 0) { /* modem < 0 = special code for net */ 1069: int x; 1070: ttmdm = modem; 1071: modem = -modem; /* Positive network type number */ 1072: fdflag = 0; /* Stdio not redirected. */ 1073: netconn = 1; /* And it's a network connection */ 1074: debug(F111,"ttopen net",ttname,modem); 1075: #ifdef NAMEFD 1076: for (p = ttname; isdigit(*p); p++) ; /* Check for all digits */ 1077: if (*p == '\0' && (telnetfd || x25fd)) { /* Avoid X.121 addresses */ 1078: ttyfd = atoi(ttname); /* Is there a way to test it's open? */ 1079: ttfdflg = 1; /* We got an open file descriptor */ 1080: debug(F111,"ttopen got open network fd",ttname,ttyfd); 1081: strncpy(ttnmsv,ttname,DEVNAMLEN); /* Remember the "name". */ 1082: x = 1; /* Return code is "good". */ 1083: if (telnetfd) { 1084: ttnet = NET_TCPB; 1085: ttnproto = NP_TELNET; 1086: #ifdef SUNX25 1087: } else if (x25fd) { 1088: ttnet = NET_SX25; 1089: ttnproto = NP_NONE; 1090: #endif /* SUNX25 */ 1091: } 1092: } else { /* Host name or address given */ 1093: #endif /* NAMEFD */ 1094: x = netopen(ttname, lcl, modem); /* (see ckcnet.h) */ 1095: if (x > -1) { 1096: strncpy(ttnmsv,ttname,DEVNAMLEN); 1097: } else netconn = 0; 1098: #ifdef NAMEFD 1099: } 1100: #endif /* NAMEFD */ 1101: 1102: #ifdef sony_news /* Sony NEWS */ 1103: if (ioctl(ttyfd,TIOCKGET,&km_ext) < 0) { /* Get Kanji mode */ 1104: perror("ttopen error getting Kanji mode (network)"); 1105: debug(F111,"ttopen error getting Kanji mode","network",0); 1106: km_ext = -1; /* Make sure this stays undefined. */ 1107: } 1108: #endif /* sony_news */ 1109: 1110: xlocal = *lcl = 1; /* Network connections are local. */ 1111: debug(F101,"ttopen net x","",x); 1112: 1113: if (x > -1 && !x25fd) 1114: x = tn_ini(); /* Initialize TELNET protocol */ 1115: return(x); 1116: } else { /* Terminal device */ 1117: #endif /* NETCONN */ 1118: 1119: #ifdef NAMEFD 1120: /* 1121: This code lets you give Kermit an open file descriptor for a serial 1122: communication device, rather than a device name. Kermit assumes that the 1123: line is already open, locked, conditioned with the right parameters, etc. 1124: */ 1125: for (p = ttname; isdigit(*p); p++) ; /* Check for all digits */ 1126: if (*p == '\0') { 1127: ttyfd = atoi(ttname); /* Is there a way to test it's open? */ 1128: debug(F111,"ttopen got open fd",ttname,ttyfd); 1129: strncpy(ttnmsv,ttname,DEVNAMLEN); /* Remember the "name". */ 1130: xlocal = *lcl = 1; /* Assume it's local. */ 1131: netconn = 0; /* Assume it's not a network. */ 1132: tvtflg = 0; /* Might need to initialize modes. */ 1133: ttmdm = modem; /* Remember modem type. */ 1134: fdflag = 0; /* Stdio not redirected. */ 1135: ttfdflg = 1; /* Flag we were opened this way. */ 1136: 1137: #ifdef sony_news /* Sony NEWS */ 1138: /* Get device Kanji mode */ 1139: if (ioctl(ttyfd,TIOCKGET,&km_ext) < 0) { 1140: perror("ttopen error getting Kanji mode"); 1141: debug(F101,"ttopen error getting Kanji mode","",0); 1142: km_ext = -1; /* Make sure this stays undefined. */ 1143: } 1144: #endif /* sony_news */ 1145: return(0); /* Return success */ 1146: } 1147: #endif /* NAMEFD */ 1148: #ifdef NETCONN 1149: } 1150: #endif /* NETCONN */ 1151: 1152: /* Here we have to open a serial device of the given name. */ 1153: 1154: occt = signal(SIGINT, cctrap); /* Set Control-C trap, save old one */ 1155: 1156: tvtflg = 0; /* Flag for use by ttvt(). */ 1157: /* 0 = ttvt not called yet for this device */ 1158: 1159: fdflag = (!isatty(0) || !isatty(1)); /* Flag for stdio redirected */ 1160: debug(F101,"ttopen fdflag","",fdflag); 1161: 1162: ttmdm = modem; /* Make this available to other fns */ 1163: xlocal = *lcl; /* Make this available to other fns */ 1164: 1165: /* Code for handling bidirectional tty lines goes here. */ 1166: /* Use specified method for turning off logins and suppressing getty. */ 1167: 1168: #ifdef ACUCNTRL 1169: /* Should put call to priv_on() here, but that would be very risky! */ 1170: acucntrl("disable",ttname); /* acucntrl() program. */ 1171: /* and priv_off() here... */ 1172: #else 1173: #ifdef ATT7300 1174: if ((attmodem & DOGETY) == 0) /* offgetty() program. */ 1175: attmodem |= offgetty(ttname); /* Remember response. */ 1176: #endif /* ATT7300 */ 1177: #endif /* ACUCNTRL */ 1178: 1179: /* 1180: In the following section, we open the tty device for read/write. 1181: If a modem has been specified via "set modem" prior to "set line" 1182: then the O_NDELAY parameter is used in the open, provided this symbol 1183: is defined (e.g. in fcntl.h), so that the program does not hang waiting 1184: for carrier (which in most cases won't be present because a connection 1185: has not been dialed yet). O_NDELAY is removed later on in ttopen(). It 1186: would make more sense to first determine if the line is local before 1187: doing this, but because ttyname() requires a file descriptor, we have 1188: to open it first. See do_open(). 1189: 1190: Now open the device using the desired treatment of carrier. 1191: If carrier is REQUIRED, then open could hang forever, so an optional 1192: timer is provided. If carrier is not required, the timer should never 1193: go off, and should do no harm... 1194: */ 1195: ttotmo = 0; /* Flag no timeout */ 1196: if (timo > 0) { 1197: int xx; 1198: saval = signal(SIGALRM,timerh); /* Timed, set up timer. */ 1199: xx = alarm(timo); /* Timed open() */ 1200: debug(F101,"ttopen alarm","",xx); 1201: if (setjmp(sjbuf)) { 1202: ttotmo = 1; /* Flag timeout. */ 1203: } else ttyfd = do_open(ttname); 1204: ttimoff(); 1205: debug(F111,"ttopen","modem",modem); 1206: debug(F101," ttyfd","",ttyfd); 1207: debug(F101," alarm return","",ttotmo); 1208: } else ttyfd = do_open(ttname); 1209: debug(F111,"ttopen ttyfd",ttname,ttyfd); 1210: if (ttyfd < 0) { /* If couldn't open, fail. */ 1211: #ifdef ATT7300 1212: if (attmodem & DOGETY) /* was getty(1m) running before us? */ 1213: ongetty(ttnmsv); /* yes, restart on tty line */ 1214: attmodem &= ~DOGETY; /* no phone in use, getty restored */ 1215: #else 1216: #if ACUCNTRL 1217: /* Should put call to priv_on() here, but that would be risky! */ 1218: acucntrl("enable",ttname); /* acucntrl() program. */ 1219: /* and priv_off() here... */ 1220: #endif /* ACUNTRL */ 1221: #endif /* ATT7300 */ 1222: 1223: signal(SIGINT,occt); /* Put old Ctrl-C trap back. */ 1224: if (errno == EACCES) { /* Device is protected against user */ 1225: perror(ttname); /* Print message */ 1226: debug(F111,"ttopen tty access denied",ttname,errno); 1227: return(-4); 1228: } else return(ttotmo ? -2 : -1); 1229: } 1230: 1231: /* Make sure it's a real tty. */ 1232: if (!isatty(ttyfd)) { 1233: fprintf(stderr,"%s is not a tty!\n",ttname); 1234: debug(F110,"ttopen not a tty",ttname,0); 1235: close(ttyfd); 1236: ttyfd = -1; 1237: signal(SIGINT,occt); 1238: return(-1); 1239: } 1240: 1241: #ifdef aegis 1242: /* Apollo C runtime claims that console pads are tty devices, which 1243: * is reasonable, but they aren't any good for packet transfer. */ 1244: ios_$inq_type_uid((short)ttyfd, ttyuid, st); 1245: if (st.all != status_$ok) { 1246: fprintf(stderr, "problem getting tty object type: "); 1247: error_$print(st); 1248: } else if (ttyuid != sio_$uid) { /* reject non-SIO lines */ 1249: close(ttyfd); ttyfd = -1; 1250: errno = ENOTTY; perror(ttname); 1251: signal(SIGINT,occt); 1252: return(-1); 1253: } 1254: #endif /* aegis */ 1255: 1256: strncpy(ttnmsv,ttname,DEVNAMLEN); /* Keep copy of name locally. */ 1257: 1258: /* Caller wants us to figure out if line is controlling tty */ 1259: 1260: if (*lcl < 0) { 1261: int x0 = 0, x1 = 0; 1262: if (strcmp(ttname,CTTNAM) == 0) { /* "/dev/tty" always remote */ 1263: xlocal = 0; 1264: debug(F111," ttname=CTTNAM",ttname,xlocal); 1265: 1266: /* If any of 0, 1, or 2 not redirected, we can use ttyname() to get */ 1267: /* the name of the controlling terminal... */ 1268: 1269: /* 1270: Warning: on some UNIX systems (SVR4?), ttyname() reportedly opens /dev but 1271: never closes it. If it is called often enough, we run out of file 1272: descriptors and subsequent open()'s of other devices or files can fail. 1273: */ 1274: 1275: } else if ((x0 = isatty(0)) || (x1 = isatty(1)) || isatty(2)) { 1276: #ifndef MINIX 1277: if (x0) 1278: x = ttyname(0); /* and compare it with the */ 1279: else if (x1) /* tty device name. */ 1280: x = ttyname(1); 1281: else x = ttyname(2); 1282: strncpy(cname,x,DEVNAMLEN); /* (copy from internal static buf) */ 1283: debug(F110," cname",x,0); 1284: x = ttyname(ttyfd); /* Gat real name of ttname. */ 1285: xlocal = (strncmp(x,cname,DEVNAMLEN) == 0) ? 0 : 1; /* Compare. */ 1286: debug(F111," ttyname",x,xlocal); 1287: #else 1288: xlocal = 1; /* Can't do this test in MINIX */ 1289: #endif /* MINIX */ 1290: } else { /* Else, if stdin redirected... */ 1291: #ifdef SVORPOSIX 1292: /* System V provides nice ctermid() function to get name of controlling tty */ 1293: ctermid(cname); /* Get name of controlling terminal */ 1294: debug(F110," ctermid",cname,0); 1295: x = ttyname(ttyfd); /* Compare with name of comm line. */ 1296: xlocal = (strncmp(x,cname,DEVNAMLEN) == 0) ? 0 : 1; 1297: debug(F111," ttyname",x,xlocal); 1298: #else 1299: /* Just assume local */ 1300: xlocal = 1; 1301: #endif /* SVORPOSIX */ 1302: debug(F101," redirected stdin","",xlocal); 1303: } 1304: } 1305: 1306: #ifndef NOFDZERO 1307: /* Note, the following code was added so that Unix "idle-line" snoopers */ 1308: /* would not think Kermit was idle when it was transferring files, and */ 1309: /* maybe log people out. */ 1310: if (xlocal == 0) { /* Remote mode */ 1311: if (fdflag == 0) { /* Standard i/o is not redirected */ 1312: debug(F100,"ttopen setting ttyfd = 0","",0); 1313: close(ttyfd); /* Use file descriptor 0 */ 1314: ttyfd = 0; 1315: } else { /* Standard i/o is redirected */ 1316: debug(F101,"ttopen stdio redirected","",ttyfd); 1317: } 1318: } 1319: #endif /* NOFDZERO */ 1320: 1321: /* Now check if line is locked -- if so fail, else lock for ourselves */ 1322: /* Note: After having done this, don't forget to delete the lock if you */ 1323: /* leave ttopen() with an error condition. */ 1324: 1325: lkf = 0; /* Check lock */ 1326: if (xlocal > 0) { 1327: int xx; int xpid; 1328: if ((xx = ttlock(ttname)) < 0) { /* Can't lock it. */ 1329: debug(F111,"ttopen ttlock fails",ttname,xx); 1330: close(ttyfd); /* Close the device. */ 1331: ttyfd = -1; /* Erase its file descriptor. */ 1332: signal(SIGINT,occt); /* Put old SIGINT back. */ 1333: if (xx == -2) { /* If lockfile says tty is in use, */ 1334: char *p = malloc(200); /* print an ls -l listing */ 1335: if (p) { /* if we can get space... */ 1336: sprintf(p,"/bin/ls -l %s",flfnam); 1337: zsyscmd(p); /* Get listing. */ 1338: free(p); /* free the space */ 1339: xpid = ttrpid(flfnam); /* Try to read pid from lockfile */ 1340: priv_off(); /* Turn privs back off. */ 1341: if (xpid > -1) printf("pid = %d\n",xpid); /* show pid */ 1342: } 1343: return(-5); /* Code for device in use */ 1344: } else return(-3); /* Access denied */ 1345: } else lkf = 1; 1346: } 1347: 1348: /* Got the line, now set the desired value for local. */ 1349: 1350: if (*lcl != 0) *lcl = xlocal; 1351: 1352: /* Some special stuff for v7... */ 1353: 1354: #ifdef V7 1355: #ifndef MINIX 1356: if (kmem[TTY] < 0) { /* If open, then skip this. */ 1357: qaddr[TTY] = initrawq(ttyfd); /* Init the queue. */ 1358: if ((kmem[TTY] = open("/dev/kmem", 0)) < 0) { 1359: fprintf(stderr, "Can't read /dev/kmem in ttopen.\n"); 1360: perror("/dev/kmem"); 1361: exit(1); 1362: } 1363: } 1364: #endif /* !MINIX */ 1365: #endif /* V7 */ 1366: 1367: /* No failure returns after this point */ 1368: 1369: #ifdef ultrix 1370: #ifdef TIOCSINUSE 1371: if (xlocal && ioctl(ttyfd, TIOCSINUSE, NULL) < 0) { 1372: fprintf(stderr, "Can't set in-use flag on modem.\n"); 1373: perror("TIOCSINUSE"); 1374: } 1375: #endif /* TIOCSINUSE */ 1376: #endif /* ultrix */ 1377: 1378: /* Get tty device settings */ 1379: 1380: #ifdef BSD44ORPOSIX /* POSIX */ 1381: tcgetattr(ttyfd,&ttold); 1382: debug(F101,"ttopen tcgetattr ttold.c_lflag","",ttold.c_lflag); 1383: tcgetattr(ttyfd,&ttraw); 1384: tcgetattr(ttyfd,&tttvt); 1385: #else /* BSD, V7, and all others */ 1386: #ifdef ATTSV /* AT&T UNIX */ 1387: ioctl(ttyfd,TCGETA,&ttold); 1388: debug(F101,"ttopen ioctl TCGETA ttold.c_lflag","",ttold.c_lflag); 1389: ioctl(ttyfd,TCGETA,&ttraw); 1390: ioctl(ttyfd,TCGETA,&tttvt); 1391: #else 1392: gtty(ttyfd,&ttold); 1393: debug(F101,"ttopen gtty ttold.sg_flags","",ttold.sg_flags); 1394: 1395: #ifdef sony_news /* Sony NEWS */ 1396: if (ioctl(ttyfd,TIOCKGET,&km_ext) < 0) { /* Get console Kanji mode */ 1397: perror("ttopen error getting Kanji mode"); 1398: debug(F101,"ttopen error getting Kanji mode","",0); 1399: km_ext = -1; /* Make sure this stays undefined. */ 1400: } 1401: #endif /* sony_news */ 1402: 1403: #ifdef TIOCGETC 1404: tcharf = 0; /* In remote mode, also get */ 1405: if (xlocal == 0) { /* special characters */ 1406: if (ioctl(ttyfd,TIOCGETC,&tchold) < 0) { 1407: debug(F100,"ttopen TIOCGETC failed","",0); 1408: } else { 1409: tcharf = 1; /* It worked. */ 1410: ioctl(ttyfd,TIOCGETC,&tchnoi); /* Get another copy */ 1411: debug(F100,"ttopen TIOCGETC ok","",0); 1412: } 1413: } 1414: #else 1415: debug(F100,"ttopen TIOCGETC not defined","",0); 1416: #endif /* TIOCGETC */ 1417: 1418: #ifdef TIOCGLTC 1419: ltcharf = 0; /* In remote mode, also get */ 1420: if (xlocal == 0) { /* local special characters */ 1421: if (ioctl(ttyfd,TIOCGLTC,<chold) < 0) { 1422: debug(F100,"ttopen TIOCGLTC failed","",0); 1423: } else { 1424: ltcharf = 1; /* It worked. */ 1425: ioctl(ttyfd,TIOCGLTC,<chnoi); /* Get another copy */ 1426: debug(F100,"ttopen TIOCGLTC ok","",0); 1427: } 1428: } 1429: #else 1430: debug(F100,"ttopen TIOCGLTC not defined","",0); 1431: #endif /* TIOCGLTC */ 1432: 1433: #ifdef TIOCLGET 1434: lmodef = 0; 1435: if (ioctl(ttyfd,TIOCLGET,&lmode) < 0) { 1436: debug(F100,"ttopen TIOCLGET failed","",0); 1437: } else { 1438: lmodef = 1; 1439: debug(F100,"ttopen TIOCLGET ok","",0); 1440: } 1441: #endif /* TIOCLGET */ 1442: 1443: gtty(ttyfd,&ttraw); /* And a copy of it for packets*/ 1444: gtty(ttyfd,&tttvt); /* And one for virtual tty service */ 1445: 1446: #endif /* ATTSV */ 1447: #endif /* BSD44ORPOSIX */ 1448: 1449: 1450: /* Section for changing line discipline. It's restored in ttres(). */ 1451: 1452: #ifdef BSD41 1453: /* For 4.1BSD only, force "old" tty driver, new one botches TANDEM. */ 1454: { int k; 1455: ioctl(ttyfd, TIOCGETD, &ttld); /* Get and save line discipline */ 1456: debug(F101,"4.1bsd line discipline","",ttld); 1457: k = OTTYDISC; /* Switch to "old" discipline */ 1458: k = ioctl(ttyfd, TIOCSETD, &k); 1459: debug(F101,"4.1bsd tiocsetd","",k); 1460: } 1461: #endif /* BSD41 */ 1462: 1463: #ifdef aegis 1464: /* This was previously done before the last two TCGETA or gtty above, 1465: * in both the ATTSV and not-ATTSV case. If it is not okay to have only 1466: * one copy if it here instead, give us a shout! 1467: */ 1468: sio_$control((short)ttyfd, sio_$raw_nl, false, st); 1469: if (xlocal) { /* ignore breaks from local line */ 1470: sio_$control((short)ttyfd, sio_$int_enable, false, st); 1471: sio_$control((short)ttyfd, sio_$quit_enable, false, st); 1472: } 1473: #endif /* aegis */ 1474: 1475: #ifdef VXVE 1476: ttraw.c_line = 0; /* STTY line 0 for VX/VE */ 1477: tttvt.c_line = 0; /* STTY line 0 for VX/VE */ 1478: ioctl(ttyfd,TCSETA,&ttraw); 1479: #endif /* vxve */ 1480: 1481: /* If O_NDELAY was used during open(), then remove it now. */ 1482: 1483: #ifdef O_NDELAY 1484: if (fcntl(ttyfd, F_GETFL, 0) & O_NDELAY) { 1485: 1486: #ifndef aegis 1487: if (fcntl(ttyfd,F_SETFL, fcntl(ttyfd, F_GETFL, 0) & ~O_NDELAY) < 0 ) 1488: perror("Can't unset O_NDELAY"); 1489: #endif /* aegis */ 1490: /* Some systems, notably Xenix (don't know how common this is in 1491: * other systems), need special treatment to get rid of the O_NDELAY 1492: * behaviour on read() with respect to carrier presence (i.e. read() 1493: * returning 0 when carrier absent), even though the above fcntl() 1494: * is enough to make read() wait for input when carrier is present. 1495: * This magic, in turn, requires CLOCAL for working when the carrier 1496: * is absent. But if xlocal == 0, presumably you already have CLOCAL 1497: * or you have a carrier, otherwise you wouldn't be running this. 1498: */ 1499: #ifdef ATTSV 1500: #ifdef BSD44 1501: tcsetattr(ttyfd, TCSADRAIN, &ttraw); 1502: #else 1503: if (xlocal) { 1504: ttraw.c_cflag |= CLOCAL; 1505: ioctl(ttyfd, TCSETA, &ttraw); 1506: } 1507: #endif /* BSD44 */ 1508: #endif /* ATTSV */ 1509: #ifndef SCO3R2 1510: #ifndef OXOS 1511: /* Reportedly lets uugetty grab the device in SCO UNIX 3.2 / XENIX 2.3 */ 1512: close( priv_opn(ttname, O_RDWR) ); /* Magic to force change. */ 1513: #endif /* OXOS */ 1514: #endif /* SCO3R2 */ 1515: } 1516: #endif /* O_NDELAY */ 1517: 1518: /* Instruct the system how to treat the carrier, and set a few other tty 1519: * parameters. 1520: * 1521: * This also undoes the temporary setting of CLOCAL that may have been done 1522: * for the close(open()) above (except in Xenix). Also throw in ~ECHO, to 1523: * prevent the other end of the line from sitting there talking to itself, 1524: * producing garbage when the user performs a connect. 1525: * 1526: * SCO Xenix unfortunately seems to ignore the actual state of CLOCAL. 1527: * Now it thinks CLOCAL is always on. It seems the only real solution for 1528: * Xenix is to switch between the lower and upper case device names. 1529: * 1530: * This section may at some future time expand into setting a complete 1531: * collection of tty parameters, or call a function shared with ttpkt()/ 1532: * ttvt() that does so. On the other hand, the initial parameters are not 1533: * that important, since ttpkt() or ttvt() should always fix that before 1534: * any communication is done. Well, we'll see... 1535: */ 1536: if (xlocal) { 1537: curcarr = -2; 1538: carrctl(&ttraw, ttcarr == CAR_ON); 1539: 1540: #ifdef SVORPOSIX 1541: ttraw.c_lflag &= ~ECHO; 1542: ttold.c_lflag &= ~ECHO; 1543: #ifdef BSD44ORPOSIX 1544: tcsetattr(ttyfd, TCSADRAIN, &ttraw); 1545: #else 1546: ioctl(ttyfd, TCSETA, &ttraw); 1547: #endif /* BSD44ORPOSIX */ 1548: 1549: #else /* BSD, etc */ 1550: ttraw.sg_flags &= ~ECHO; 1551: ttold.sg_flags &= ~ECHO; 1552: stty(ttyfd,&ttraw); 1553: #endif /* SVORPOSIX */ 1554: /* ttflui(); This fails for some reason */ 1555: } 1556: 1557: /* Get current speed */ 1558: 1559: ttspeed = ttgspd(); 1560: debug(F101,"ttopen ttspeed","",ttspeed); 1561: 1562: /* Done, make entries in debug log, restore Ctrl-C trap, and return. */ 1563: 1564: debug(F101,"ttopen, ttyfd","",ttyfd); 1565: debug(F101," lcl","",*lcl); 1566: debug(F111," lock file",flfnam,lkf); 1567: signal(SIGINT,occt); 1568: return(0); 1569: } 1570: 1571: 1572: /* D O _ O P E N -- Do the right kind of open() call for the tty. */ 1573: 1574: int 1575: do_open(ttname) char *ttname; { 1576: 1577: #ifndef O_NDELAY /* O_NDELAY not defined */ 1578: return(priv_opn(ttname,2)); 1579: #else /* O_NDELAY defined */ 1580: 1581: #ifdef ATT7300 1582: /* 1583: Open comms line without waiting for carrier so initial call does not hang 1584: because state of "modem" is likely unknown at the initial call -jrd. 1585: If this is needed for the getty stuff to work, and the open would not work 1586: without O_NDELAY when getty is still on, then this special case is ok. 1587: Otherwise, get rid of it. -ske 1588: */ 1589: return(priv_opn(ttname, O_RDWR | O_NDELAY)); 1590: 1591: #else /* !ATT7300 */ 1592: 1593: /* Normal case. Use O_NDELAY according to SET CARRIER. See ttscarr(). */ 1594: 1595: return(priv_opn(ttname, O_RDWR | ((ttcarr != CAR_ON) ? O_NDELAY : 0) )); 1596: 1597: #endif /* !ATT7300 */ 1598: #endif /* O_NDELAY */ 1599: } 1600: 1601: /* T T C L O S -- Close the TTY, releasing any lock. */ 1602: 1603: int 1604: ttclos(foo) int foo; { /* Arg req'd for signal() prototype */ 1605: int x = 0; 1606: 1607: debug(F101,"ttclos ttyfd","",ttyfd); 1608: if (ttyfd < 0) return(0); /* Wasn't open. */ 1609: 1610: if (ttfdflg) return(0); /* If we got ttyfd from another */ 1611: /* process, don't close it. */ 1612: tvtflg = 0; 1613: #ifdef NETCONN 1614: if (netconn) { /* Network connection. */ 1615: debug(F100,"ttclos closing net","",0); 1616: netclos(); /* Close it. */ 1617: netconn = 0; 1618: return(0); 1619: } 1620: #endif /* NETCONN */ 1621: #ifdef FT21 1622: if (xlocal) ioctl(ttyfd,TIOCHPCL, NULL); 1623: #endif /* FT21 */ 1624: #ifdef ultrix 1625: if (xlocal) ioctl(ttyfd, TIOCNCAR, NULL); 1626: #endif /* ultrix */ 1627: if (xlocal) { 1628: debug(F100,"ttclos about to call ttunlck","",0); 1629: if (ttunlck()) /* Release uucp-style lock */ 1630: fprintf(stderr,"Warning, problem releasing lock\r\n"); 1631: debug(F100,"ttclos about to call ttres","",0); 1632: } 1633: if (ttyfd > 0) { 1634: int xx; 1635: saval = signal(SIGALRM,timerh); /* Enable timer interrupt. */ 1636: xx = alarm(5); /* Allow 5 seconds for this. */ 1637: debug(F101,"ttclos alarm","",xx); 1638: if (setjmp(sjbuf)) { /* Timer went off? */ 1639: x = -1; 1640: } else { /* What we're really trying to do */ 1641: if (xlocal) { 1642: tthang(); /* Hang up first, then... */ 1643: ttres(); /* reset device modes. */ 1644: } 1645: debug(F101,"ttclos about to call close","",ttyfd); 1646: close(ttyfd); /* Close the device. */ 1647: x = 1; 1648: } 1649: ttimoff(); /* Turn off timer. */ 1650: if (x < 0) { 1651: fprintf(stderr,"?Timed out closing device: %s\n",ttnmsv); 1652: debug(F100,"ttclos timed out","",0); 1653: } 1654: } 1655: ttyfd = -1; /* Invalidate the file descriptor. */ 1656: #ifdef sony_news 1657: km_ext = -1; /* Invalidate device's Kanji-mode */ 1658: #endif /* sony_news */ 1659: 1660: /* For bidirectional lines, restore getty if it was there before. */ 1661: 1662: #ifdef ACUCNTRL /* 4.3BSD acucntrl() method. */ 1663: acucntrl("enable",ttnmsv); /* Enable getty on the device. */ 1664: #else 1665: #ifdef ATT7300 /* ATT UNIX PC (3B1, 7300) method. */ 1666: if (attmodem & DOGETY) /* Was getty(1m) running before us? */ 1667: ongetty(ttnmsv); /* Yes, restart getty on tty line */ 1668: attmodem &= ~DOGETY; /* No phone in use, getty restored */ 1669: #endif /* ATT7300 */ 1670: #endif /* System-dependent getty-restoring methods */ 1671: 1672: debug(F100,"ttclos done","",0); 1673: return(0); 1674: } 1675: 1676: /* T T H A N G -- Hangup phone line or network connection. */ 1677: /* 1678: Returns: 1679: 0 if it does nothing. 1680: 1 if it believes that it hung up successfully. 1681: -1 if it believes that the hangup attempt failed. 1682: */ 1683: 1684: #define HUPTIME 500 /* Milliseconds for hangup */ 1685: 1686: int 1687: tthang() { 1688: int x = 0; /* Sometimes used as return code. */ 1689: #ifndef POSIX 1690: int z; /* worker */ 1691: #endif /* POSIX */ 1692: 1693: #ifdef SVORPOSIX /* AT&T, POSIX, HPUX declarations. */ 1694: int spdsav; /* for saving speed */ 1695: int spdsavi; 1696: #ifdef HPUX 1697: mflag dtr_down = 00000000000, 1698: modem_rtn; 1699: mflag modem_sav; 1700: char modem_state[64]; 1701: #endif /* HPUX */ 1702: int flags; /* fcntl flags */ 1703: unsigned short ttc_save; 1704: #endif /* SVORPOSIX */ 1705: 1706: if (ttyfd < 0) return(0); /* Don't do this if not open */ 1707: if (xlocal < 1) return(0); /* Don't do this if not local */ 1708: 1709: #ifdef NETCONN 1710: if (netconn) /* Network connection. */ 1711: return((netclos() < 0) ? -1 : 1); /* Just close it. */ 1712: #endif /* NETCONN */ 1713: 1714: /* From here down, we handle real tty devices. */ 1715: 1716: #ifdef BSD44ORPOSIX 1717: /* Should add some error checking here... */ 1718: debug(F100,"tthang POSIX style","",0); 1719: spdsav = cfgetospeed(&ttcur); /* Get current speed */ 1720: spdsavi = cfgetispeed(&ttcur); /* Get current speed */ 1721: cfsetospeed(&ttcur,B0); /* Replace by 0 */ 1722: cfsetispeed(&ttcur,B0); 1723: if (tcsetattr(ttyfd,TCSADRAIN,&ttcur) == -1) 1724: debug(F100,"tthang tcsetattr fails","",errno); 1725: msleep(HUPTIME); /* Sleep */ 1726: cfsetospeed(&ttcur,spdsav); /* Restore previous speed */ 1727: cfsetispeed(&ttcur,spdsavi); 1728: tcsetattr(ttyfd,TCSADRAIN,&ttcur); 1729: return(1); 1730: 1731: #else /* BSD44ORPOSIX */ 1732: 1733: #ifdef aegis /* Apollo Aegis */ 1734: sio_$control((short)ttyfd, sio_$dtr, false, st); /* DTR down */ 1735: msleep(HUPTIME); /* pause */ 1736: sio_$control((short)ttyfd, sio_$dtr, true, st); /* DTR up */ 1737: return(1); 1738: #endif /* aegis */ 1739: 1740: #ifdef ANYBSD /* Any BSD version. */ 1741: debug(F100,"tthang BSD style","",0); 1742: if (ioctl(ttyfd,TIOCCDTR,0) < 0) { /* Clear DTR. */ 1743: debug(F101,"tthang TIOCCDTR fails","",errno); 1744: return(-1); 1745: } 1746: msleep(HUPTIME); /* For about 1/2 sec */ 1747: errno = 0; 1748: x = ioctl(ttyfd,TIOCSDTR,0); /* Restore DTR */ 1749: if (x < 0) { 1750: /* 1751: For some reason, this tends to fail with "no such device or address" 1752: but the operation still works, probably because of the close/open 1753: later on. So let's not scare the user unnecessarily here. 1754: */ 1755: debug(F101,"tthang TIOCSDTR errno","",errno); /* Log the error */ 1756: x = 1; /* Pretend we succeeded */ 1757: } else if (x == 0) x = 1; /* Success */ 1758: #ifdef COMMENT 1759: #ifdef FT21 1760: ioctl(ttyfd, TIOCSAVEMODES, 0); 1761: ioctl(ttyfd, TIOCHPCL, 0); 1762: close(ttyfd); /* Yes, must do this twice */ 1763: if ((ttyfd = open(ttnmsv,2)) < 0) /* on Fortune computers... */ 1764: return(-1); /* (but why?) */ 1765: else x = 1; 1766: #endif /* FT21 */ 1767: #endif /* COMMENT */ 1768: close(do_open(ttnmsv)); /* Clear i/o error condition */ 1769: errno = 0; 1770: #ifdef COMMENT 1771: /* This is definitely dangerous. Why was it here? */ 1772: z = ttvt(ttspeed,ttflow); /* Restore modes. */ 1773: debug(F101,"tthang ttvt returns","",z); 1774: return(z < 0 ? -1 : 1); 1775: #else 1776: return(x); 1777: #endif /* COMMENT */ 1778: #endif /* ANYBSD */ 1779: 1780: #ifdef ATTSV 1781: /* AT&T UNIX section, includes HP-UX and generic AT&T System III/V... */ 1782: 1783: #ifdef HPUX 1784: /* Hewlett Packard allows explicit manipulation of modem signals. */ 1785: 1786: #ifdef COMMENT 1787: /* Old way... */ 1788: debug(F100,"tthang HP-UX style","",0); 1789: if (ioctl(ttyfd,MCSETAF,&dtr_down) < 0) /* lower DTR */ 1790: return(-1); /* oops, can't. */ 1791: msleep(HUPTIME); /* Pause half a second. */ 1792: x = 1; /* Set return code */ 1793: if (ioctl(ttyfd,MCGETA,&modem_rtn) > -1) { /* Get line status. */ 1794: if ((modem_rtn & MDCD) != 0) /* Check if CD is low. */ 1795: x = -1; /* CD didn't drop, fail. */ 1796: } else x = -1; 1797: 1798: /* Even if above calls fail, RTS & DTR should be turned back on. */ 1799: modem_rtn = MRTS | MDTR; 1800: if (ioctl(ttyfd,MCSETAF,&modem_rtn) < 0) x = -1; 1801: return(x); 1802: #else 1803: /* New way, from Hellmuth Michaelis */ 1804: debug(F100,"tthang HP-UX style, HPUXDEBUG","",0); 1805: if (ioctl(ttyfd,MCGETA,&modem_rtn) == -1) { /* Get current status. */ 1806: debug(F100,"tthang HP-UX: can't get modem lines, NO HANGUP!","",0); 1807: return(-1); 1808: } 1809: sprintf(modem_state,"%#lx",modem_rtn); 1810: debug(F110,"tthang HP-UX: modem lines got = ",modem_state,0); 1811: modem_sav = modem_rtn; /* save line status */ 1812: modem_rtn &= ~MDTR; /* DTR bit down */ 1813: sprintf(modem_state,"%#lx",modem_rtn); 1814: debug(F110,"tthang HP-UX: modem lines lowered DTR = ",modem_state,0); 1815: if (ioctl(ttyfd,MCSETAF,&modem_rtn) < 0) { /* lower DTR */ 1816: debug(F100,"tthang HP-UX: can't lower DTR!","",0); 1817: return(-1); /* oops, can't. */ 1818: } 1819: msleep(HUPTIME); /* Pause half a second. */ 1820: x = 1; /* Set return code */ 1821: if (ioctl(ttyfd,MCGETA,&modem_rtn) > -1) { /* Get line status. */ 1822: sprintf(modem_state,"%#lx",modem_rtn); 1823: debug(F110,"tthang HP-UX: modem lines got = ",modem_state,0); 1824: if ((modem_rtn & MDCD) != 0) { /* Check if CD is low. */ 1825: debug(F100,"tthang HP-UX: DCD didn't get down!","",0); 1826: x = -1; /* CD didn't drop, fail. */ 1827: } else { 1828: debug(F100,"tthang HP-UX: DCD down!","",0); 1829: } 1830: } else { 1831: x = -1; 1832: debug(F100,"tthang HP-UX: can't get DCD status !","",0); 1833: } 1834: 1835: /* Even if above calls fail, RTS & DTR should be turned back on. */ 1836: 1837: modem_sav |= (MRTS | MDTR); 1838: if (ioctl(ttyfd,MCSETAF,&modem_sav) < 0) { 1839: x = -1; 1840: debug(F100,"tthang HP-UX: can't set saved state |=(RTS | DTR)","",0); 1841: } else { 1842: sprintf(modem_state,"%#lx",modem_sav); 1843: debug(F110,"tthang HP-UX: final modem lines = ",modem_state,0); 1844: } 1845: return(x); 1846: #endif /* COMMENT */ 1847: 1848: #else /* AT&T but not HP-UX */ 1849: 1850: /* SVID for AT&T System V R3 defines ioctl's for handling modem signals. */ 1851: /* It is not known how many, if any, systems actually implement them, */ 1852: /* so we include them here in ifdef's. */ 1853: 1854: #ifndef _IBMR2 1855: /* 1856: No modem-signal twiddling for IBM RT PC or RS/6000. 1857: In AIX 3.1 and earlier, the ioctl() call is broken. 1858: This code could be activated for AIX 3.1 with PTF 2006 or later 1859: (e.g. AIX 3.2), but close/open does the job too, so why bother. 1860: */ 1861: #ifdef TIOCMBIS /* Bit Set */ 1862: #ifdef TIOCMBIC /* Bit Clear */ 1863: #ifdef TIOCM_DTR /* DTR */ 1864: 1865: /* Clear DTR, sleep 300 msec, turn it back on. */ 1866: /* If any of the ioctl's return failure, go on to the next section. */ 1867: 1868: z = TIOCM_DTR; /* Code for DTR. */ 1869: #ifdef TIOCM_RTS /* Lower RTS too if symbol is known. */ 1870: z |= TIOCM_RTS; 1871: #endif /* TIOCM_RTS */ 1872: 1873: debug(F101,"tthang TIOCM signal mask","",z); 1874: if (ioctl(ttyfd,TIOCMBIC,&z) > -1) { /* Try to lower DTR. */ 1875: debug(F100,"tthang TIOCMBIC ok","",0); 1876: msleep(HUPTIME); /* Pause half a second. */ 1877: if (ioctl(ttyfd,TIOCMBIS,&z) > -1) { /* Try to turn it back on. */ 1878: debug(F100,"tthang TIOCMBIS ok","",0); 1879: #ifndef CLSOPN 1880: return(1); /* Success, done. */ 1881: #endif /* CLSOPN */ 1882: } else { /* Couldn't raise, continue. */ 1883: debug(F101,"tthang TIOCMBIS errno","",errno); 1884: } 1885: } else { /* Couldn't lower, continue. */ 1886: debug(F101,"tthang TIOCMBIC errno","",errno); 1887: } 1888: #endif /* TIOCM_DTR */ 1889: #endif /* TIOCMBIC */ 1890: #endif /* TIOCMBIS */ 1891: #endif /* _IBMR2 */ 1892: /* 1893: General AT&T UNIX case, not HPUX. The following code is highly suspect. No 1894: two AT&T-based systems seem to do this the same way. The object is simply 1895: to turn off DTR and then turn it back on. SVID says the universal method 1896: for turning off DTR is to set the speed to zero, and this does seem to do 1897: the trick in all cases. But neither SVID nor any known man pages say how to 1898: turn DTR back on again. Some variants, like most Xenix implementations, 1899: raise DTR again when the speed is restored to a nonzero value. Others 1900: require the device to be closed and opened again, but this is risky because 1901: getty could seize the device during the instant it is closed. 1902: */ 1903: 1904: /* Return code for ioctl failures... */ 1905: #ifdef ATT6300 1906: x = 1; /* ATT6300 doesn't want to fail... */ 1907: #else 1908: x = -1; 1909: #endif /* ATT6300 */ 1910: 1911: debug(F100,"tthang get settings","",0); 1912: if (ioctl(ttyfd,TCGETA,&ttcur) < 0) /* Get current settings. */ 1913: return(x); /* Fail if this doesn't work. */ 1914: if ((flags = fcntl(ttyfd,F_GETFL,0)) < 0) /* Get device flags. */ 1915: return(x); 1916: ttc_save = ttcur.c_cflag; /* Remember current speed. */ 1917: spdsav = ttc_save & CBAUD; 1918: debug(F101,"tthang speed","",spdsav); 1919: 1920: #ifdef O_NDELAY 1921: debug(F100,"tthang turning O_NDELAY on","",0); 1922: fcntl(ttyfd, F_SETFL, flags | O_NDELAY); /* Activate O_NDELAY */ 1923: #endif /* O_NDELAY */ 1924: 1925: #ifdef ATT7300 /* This is the way it is SUPPOSED to work */ 1926: ttcur.c_cflag &= ~CBAUD; /* Change the speed to zero. */ 1927: #else 1928: #ifdef RTAIX 1929: ttcur.c_cflag &= ~CBAUD; /* Change the speed to zero. */ 1930: #else /* This way really works but may be dangerous */ 1931: #ifdef u3b2 1932: ttcur.c_cflag = ~(CBAUD|CLOCAL); /* Special for AT&T 3B2s */ 1933: /* (CLOCAL must be OFF) */ 1934: #else 1935: #ifdef SCO3R2 /* SCO UNIX 3.2 */ 1936: /* 1937: This is complete nonsense, but an SCO user claimed this change made 1938: hanging up work. Comments from other SCO UNIX 3.2 users would be 1939: appreciated. 1940: */ 1941: ttcur.c_cflag = CBAUD|B0; 1942: #else /* None of the above. */ 1943: ttcur.c_cflag = CLOCAL|HUPCL; /* Change all but these to zero */ 1944: /* (CLOCAL must be ON) */ 1945: #endif /* SCO3R2 */ 1946: #endif /* u3b2 */ 1947: #endif /* RTAIX */ 1948: #endif /* ATT7300 */ 1949: 1950: #ifdef COMMENT 1951: /* and if none of those work, try one of these... */ 1952: ttcur.c_cflag = 0; 1953: ttcur.c_cflag = CLOCAL; 1954: ttcur.c_cflag &= ~(CBAUD|HUPCL); 1955: ttcur.c_cflag &= ~(CBAUD|CREAD); 1956: ttcur.c_cflag &= ~(CBAUD|CREAD|HUPCL); 1957: /* or other combinations */ 1958: #endif /* COMMENT */ 1959: 1960: #ifdef TCXONC 1961: debug(F100,"tthang TCXONC","",0); 1962: ioctl(ttyfd, TCXONC, 1); 1963: #endif /* TCXONC */ 1964: 1965: #ifdef TIOCSTART 1966: debug(F100,"tthang TIOCSTART","",0); 1967: ioctl(ttyfd, TIOCSTART, 0); 1968: #endif /* TIOCSTART */ 1969: 1970: if (ioctl(ttyfd,TCSETAF,&ttcur) < 0) { /* Fail if we can't. */ 1971: fcntl(ttyfd, F_SETFL, flags); /* Restore flags */ 1972: return(-1); /* before returning. */ 1973: } 1974: msleep(300); /* Give modem time to notice. */ 1975: 1976: /* Now, even though it doesn't say this in SVID or any man page, we have */ 1977: /* to close and reopen the device. This is not necessary for all systems, */ 1978: /* but it's impossible to predict which ones need it and which ones don't. */ 1979: 1980: #ifdef ATT7300 1981: /* 1982: Special handling for ATT 7300 UNIX PC and 3B1, which have "phone" 1983: related ioctl's for their internal modems. attmodem has getty status and 1984: modem-in-use bit. Reportedly the ATT7300/3B1 PIOCDISC call is necessary, 1985: but also ruins the file descriptor, and no other phone(7) ioctl call can fix 1986: it. Whateverit does, it seems to escape detection with PIOCGETA and TCGETA. 1987: The only way to undo the damage is to close the fd and then reopen it. 1988: */ 1989: if (attmodem & ISMODEM) { 1990: debug(F100,"tthang attmodem close/open","",0); 1991: ioctl(ttyfd,PIOCUNHOLD,&dialer); /* Return call to handset. */ 1992: ioctl(ttyfd,PIOCDISC,&dialer); /* Disconnect phone. */ 1993: close(ttyfd); /* Close and reopen the fd. */ 1994: ttyfd = priv_opn(ttnmsv, O_RDWR | O_NDELAY); 1995: attmodem &= ~ISMODEM; /* Phone no longer in use. */ 1996: } 1997: #else /* !ATT7300 */ 1998: /* It seems we have to close and open the device for other AT&T systems */ 1999: /* too, and this is the place to do it. The following code does the */ 2000: /* famous close(open(...)) magic by default. If that doesn't work for you, */ 2001: /* then try uncommenting the following statement or putting -DCLSOPN in */ 2002: /* the makefile CFLAGS. */ 2003: 2004: /* #define CLSOPN */ 2005: 2006: #ifndef SCO32 /* Not needed by, and harmful to, SCO UNIX 3.2 / Xenix 2.3 */ 2007: 2008: #ifdef O_NDELAY 2009: #define OPENFLGS O_RDWR | O_NDELAY 2010: #else 2011: #define OPENFLGS O_RDWR 2012: #endif 2013: 2014: #ifndef CLSOPN 2015: /* This method is used by default, i.e. unless CLSOPN is defined. */ 2016: /* It is thought to be safer because there is no window where getty */ 2017: /* can seize control of the device. The drawback is that it might not work. */ 2018: 2019: debug(F101,"tthang close(open()), OPENFLGS","",OPENFLGS); 2020: close(priv_opn(ttnmsv, OPENFLGS)); 2021: 2022: #else 2023: /* This method is used if you #define CLSOPN. It is more likely to work */ 2024: /* than the previous method, but it's also more dangerous. */ 2025: 2026: debug(F101,"tthang close/open, OPENFLGS","",OPENFLGS); 2027: close(ttyfd); 2028: msleep(10); 2029: ttyfd = priv_opn(ttnmsv, OPENFLGS); /* Open it again */ 2030: #endif /* CLSOPN */ 2031: #undef OPENFLGS 2032: 2033: #endif /* SCO32 */ 2034: #endif /* ATT7300 */ 2035: 2036: /* Now put all flags & modes back the way we found them. */ 2037: /* (Does the order of ioctl & fcntl matter ? ) */ 2038: 2039: debug(F100,"tthang restore settings","",0); 2040: ttcur.c_cflag = ttc_save; /* Get old speed back. */ 2041: if (ioctl(ttyfd,TCSETAF,&ttcur) < 0) /* ioctl parameters. */ 2042: return(-1); 2043: #ifdef O_NDELAY 2044: /* 2045: This is required for IBM RT and RS/6000, probably helps elsewhere too (?). 2046: After closing a modem line, the modem will probably not be asserting 2047: carrier any more, so we should not require carrier any more. If this 2048: causes trouble on non-IBM UNIXes, change the #ifdef to use _IBMR2 rather 2049: than O_NDELAY. 2050: */ 2051: flags &= ~O_NDELAY; /* Don't require carrier on reopen */ 2052: #endif /* O_NDELAY */ 2053: if (fcntl(ttyfd,F_SETFL,flags) < 0) /* fcntl parameters */ 2054: return(-1); 2055: 2056: return(1); 2057: #endif /* not HPUX */ 2058: #endif /* ATTSV */ 2059: #endif /* BSD44ORPOSIX */ 2060: } 2061: 2062: /* 2063: Major change in 5A(174). We used to use LPASS8, if it was defined, to 2064: allow 8-bit data and Xon/Xoff flow control at the same time. But this 2065: LPASS8 business seems to have been causing trouble for everybody but me! 2066: For example, Annex terminal servers, commonly used with Encore computers, 2067: do not support LPASS8 even though the Encore itself does. Ditto for many 2068: other terminal servers, TELNET connections, rlogin connections, etc etc. 2069: Now, reportedly, even vanilla 4.3 BSD systems can't do this right on their 2070: serial lines, even though LPASS8 is a feature of 4.3BSD. So let's turn it 2071: off for everybody. That means we goes back to using raw mode, with no 2072: flow control. Phooey. 2073: 2074: NOTE: This must be done before the first reference to LPASS8 in this file, 2075: and after the last #include statment. 2076: */ 2077: #ifdef LPASS8 2078: #undef LPASS8 2079: #endif /* LPASS8 */ 2080: 2081: /* T T R E S -- Restore terminal to "normal" mode. */ 2082: 2083: /* ske@pkmab.se: There are two choices for what this function should do. 2084: * (1) Restore the tty to current "normal" mode, with carrier treatment 2085: * according to ttcarr, to be used after every kermit command. (2) Restore 2086: * the tty to the state it was in before kermit opened it. These choices 2087: * conflict, since ttold can't hold both choices of tty parameters. ttres() 2088: * is currently being called as in choice (1), but ttold basically holds 2089: * the initial parameters, as in (2), and the description at the beginning 2090: * of this file says (2). 2091: * 2092: * I don't think restoring tty parameters after all kermit commands makes 2093: * much of a difference. Restoring them upon exit from kermit may be of 2094: * some use in some cases (when the line is not restored automatically on 2095: * close, by the operating system). 2096: * 2097: * I can't choose which one it should be, so I haven't changed it. It 2098: * probably works as it is, too. It would probably even work even with 2099: * ttres() entirely deleted... 2100: * 2101: * (from fdc: Actually, this function operates in remote mode too, so 2102: * it restores the console (command) terminal to whatever mode it was 2103: * in before packet operations began, so that commands work right again.) 2104: */ 2105: int 2106: ttres() { /* Restore the tty to normal. */ 2107: int x; 2108: 2109: if (ttyfd < 0) return(-1); /* Not open. */ 2110: 2111: if (ttfdflg) return(0); /* Don't mess with terminal modes if */ 2112: /* we got ttyfd from another process */ 2113: #ifdef NETCONN 2114: if (netconn) return (0); /* Network connection, do nothing */ 2115: #endif /* NETCONN */ 2116: 2117: /* Real terminal device, so restore its original modes */ 2118: 2119: #ifdef BSD44ORPOSIX /* For POSIX like this */ 2120: x = tcsetattr(ttyfd,TCSADRAIN,&ttold); 2121: #else /* For all others... */ 2122: #ifdef ATTSV /* For AT&T versions... */ 2123: x = ioctl(ttyfd,TCSETAW,&ttold); /* Restore tty modes this way. */ 2124: #else 2125: msleep(HUPTIME); /* This replaces sleep(1)... */ 2126: /* Put back sleep(1) if tty is */ 2127: /* messed up after close. */ 2128: 2129: /* Here we restore the modes for BSD */ 2130: 2131: #ifdef LPASS8 /* Undo "pass8" if it were done */ 2132: if (lmodef) { 2133: if (ioctl(ttyfd,TIOCLSET,&lmode) < 0) 2134: debug(F100,"ttres TIOCLSET failed","",0); 2135: else 2136: debug(F100,"ttres TIOCLSET ok","",0); 2137: } 2138: #endif /* LPASS8 */ 2139: 2140: #ifdef CK_DTRCTS /* Undo hardware flow if it were done */ 2141: if (lmodef) { 2142: if (ioctl(ttyfd,TIOCLSET,&lmode) < 0) 2143: debug(F100,"ttres TIOCLSET failed","",0); 2144: else 2145: debug(F100,"ttres TIOCLSET ok","",0); 2146: } 2147: #endif /* CK_DTRCTS */ 2148: 2149: #ifdef TIOCGETC /* Put back special characters */ 2150: if (tcharf && (xlocal == 0)) { 2151: if (ioctl(ttyfd,TIOCSETC,&tchold) < 0) 2152: debug(F100,"ttres TIOCSETC failed","",0); 2153: else 2154: debug(F100,"ttres TIOCSETC ok","",0); 2155: } 2156: #endif /* TIOCGETC */ 2157: 2158: #ifdef TIOCGLTC /* Put back local special characters */ 2159: if (ltcharf && (xlocal == 0)) { 2160: if (ioctl(ttyfd,TIOCSLTC,<chold) < 0) 2161: debug(F100,"ttres TIOCSLTC failed","",0); 2162: else 2163: debug(F100,"ttres TIOCSLTC ok","",0); 2164: } 2165: #endif /* TIOCGLTC */ 2166: 2167: x = stty(ttyfd,&ttold); /* restore tty modes the old way. */ 2168: 2169: #endif /* ATTSV */ 2170: #endif /* BSD44ORPOSIX */ 2171: 2172: debug(F101,"ttres tty modes restore","",x); 2173: if (x < 0) debug(F101,"ttres errno","",errno); 2174: 2175: #ifdef BSD41 2176: if (ttld > -1) { /* Put back line discipline */ 2177: x = ioctl(ttyfd, TIOCSETD, &ttld); 2178: debug(F101,"ttres line discipline restore","",x); 2179: if (x < 0) debug(F101,"...ioctl errno","",errno); 2180: ttld = -1; 2181: } 2182: #endif /* BSD41 */ 2183: 2184: #ifdef sony_news 2185: x = xlocal ? km_ext : km_con; /* Restore Kanji mode. */ 2186: if (x != -1) { /* Make sure we know original modes. */ 2187: if (ioctl(ttyfd,TIOCKSET, &x) < 0) { 2188: perror("ttres can't set Kanji mode"); 2189: debug(F101,"ttres error setting Kanji mode","",x); 2190: return(-1); 2191: } 2192: } 2193: debug(F100,"ttres set Kanji mode ok","",0); 2194: #endif /* sony_news */ 2195: 2196: tvtflg = 0; /* Invalidate terminal mode settings */ 2197: return(x); 2198: } 2199: 2200: /* T T R P I D -- Read pid from lockfile "name" (used by ttlock) */ 2201: 2202: int 2203: ttrpid(name) char *name; { 2204: int x, fd, pid; 2205: 2206: fd = open(name,O_RDONLY); /* Try to open lockfile. */ 2207: if (fd > 0) { 2208: 2209: #ifdef PIDSTRING 2210: char buf[12]; 2211: x = read(fd, buf, 11); /* For HDP UUCP, read pid string */ 2212: if (x < 0) return(-1); 2213: buf[11] = '\0'; 2214: if (x == 11) 2215: x = sscanf(buf,"%d",&pid); /* Get the integer pid from it. */ 2216: #else 2217: x = read(fd, (char *)&pid, sizeof(pid)); /* Else read integer pid */ 2218: #endif /* PIDSTRING */ 2219: 2220: if (x < 0) pid = -1; /* Return any errors. */ 2221: close(fd); /* Close the lockfile. */ 2222: } else pid = -1; 2223: return(pid); 2224: } 2225: 2226: /* T T L O C K */ 2227: 2228: /* 2229: This function attempts to coordinate use of the communication device with 2230: other copies of Kermit and any other program that follows the UUCP 2231: device-locking conventions, which, unfortunately, vary among different UNIX 2232: implementations. The idea is to look for a file of a certain name, the 2233: "lockfile", in a certain directory. If such a file is found, then the line 2234: is presumed to be in use, and Kermit should not use it. If no such file is 2235: found, Kermit attempts to create one so that other programs will not use the 2236: same line at the same time. Because the lockfile and/or the directory it's 2237: in might lack write permission for the person running Kermit, Kermit could 2238: find itself running setuid to uucp or other user that does have the 2239: necessary permissions. At startup, Kermit has changed its effective uid to 2240: the user's real uid, and so ttlock() must switch back to the original 2241: effective uid in order to create the lockfile, and then back again to the 2242: real uid to prevent unauthorized access to other directories or files owned 2243: by the user the program is setuid to. 2244: 2245: Totally rewritten for C-Kermit 5A to eliminate windows of vulnerability, 2246: based on suggestions from Warren Tucker. Call with pointer to name of 2247: tty device. Returns: 2248: 2249: 0 on success 2250: -1 on failure 2251: 2252: Note: Once privileges are turned on using priv_on(), it is essential that 2253: they are turned off again before this function returns. 2254: */ 2255: #ifdef SVR4 /* Lockfile uses device numbers. */ 2256: #ifndef LFDEVNO /* Define this for SVR4 */ 2257: #ifndef AIXRS /* But not for RS/6000 AIX 3.2 */ 2258: #define LFDEVNO /* If anybody else needs it, */ 2259: #endif /* AIXRS */ 2260: #endif /* LFDEVNO */ /* define it here or on CC */ 2261: #endif /* SVR4 */ /* command line. */ 2262: 2263: #ifdef LFDEVNO 2264: #include <sys/stat.h> /* For major() & minor() macros. */ 2265: /* Should be in <sys/types.h>. */ 2266: #ifndef major /* If we didn't find it */ 2267: #ifdef SVR4 /* then for Sys V R4 */ 2268: #include <sys/mkdev.h> /* look here */ 2269: #else /* or for Sunos versions */ 2270: #ifdef SUNOS4 /* ... */ 2271: #include <sys/sysmacros.h> /* look here */ 2272: #else /* Otherwise take a chance: */ 2273: #define major(dev) ( (int) ( ((unsigned)(dev) >> 8) & 0xff)) 2274: #define minor(dev) ( (int) ( (dev) & 0xff)) 2275: #endif /* SUNOS4 */ 2276: #endif /* SVR4 */ 2277: #endif /* major */ 2278: #endif /* LFDEVNO */ 2279: /* 2280: Note for RS/6000: routines ttylock(devicename), ttyunlock(devicename), 2281: and ttylocked(devicename) from the standard library (libc.a) could be 2282: used here instead. It's not clear whether there is any advantage in this. 2283: */ 2284: static int 2285: ttlock(ttdev) char *ttdev; { 2286: int x; 2287: 2288: #ifdef MINIX 2289: char *buf; 2290: #endif /* MINIX */ 2291: 2292: #ifdef NOUUCP 2293: strcpy(flfnam,"NOLOCK"); 2294: haslock = 1; 2295: return(0); 2296: #else /* !NOUUCP */ 2297: int lockfd; /* File descriptor for lock file. */ 2298: PID_T pid; /* Process id of this process. */ 2299: int fpid; /* pid found in existing lockfile. */ 2300: int tries; /* How many times we've tried... */ 2301: #ifdef LFDEVNO 2302: struct stat devbuf; /* For device numbers (SVR4). */ 2303: #endif /* LFDEVNO */ 2304: 2305: #ifdef PIDSTRING 2306: char pid_str[12]; /* My pid in string format. */ 2307: #endif /* PIDSTRING */ 2308: 2309: char *device, *devname; 2310: 2311: #define LFNAML 50 /* Max length for lock file name. */ 2312: char lockfil[LFNAML]; /* Lock file name */ 2313: #ifdef RTAIX 2314: char lklockf[LFNAML]; /* Name for link to lock file */ 2315: #endif /* RTAIX */ 2316: char tmpnam[LFNAML+30]; /* Temporary lockfile name. */ 2317: char *lockdir = LOCK_DIR; /* Defined near top of this file, */ 2318: /* or on cc command line. */ 2319: 2320: haslock = 0; /* Not locked yet. */ 2321: *flfnam = '\0'; /* Lockfile name is empty. */ 2322: pid = getpid(); /* Get id of this process. */ 2323: 2324: /* Construct name of lockfile and temporary file */ 2325: 2326: /* device = name of tty device without the path, e.g. "ttyh8" */ 2327: /* lockfil = name of lock file, without path, e.g. "LCK..ttyh8" */ 2328: 2329: device = ((devname = xxlast(ttdev,'/')) != NULL ? devname+1 : ttdev); 2330: 2331: #ifdef ISIII /* Interactive System III, PC/IX */ 2332: strcpy(lockfil, device); 2333: #else 2334: #ifdef LFDEVNO /* Lockfilename has device numbers. */ 2335: if (stat(ttdev,&devbuf) < 0) 2336: return(-1); 2337: sprintf(lockfil,"LK.%03d.%03d.%03d", 2338: major(devbuf.st_dev), /* inode */ 2339: major(devbuf.st_rdev), /* major device number */ 2340: minor(devbuf.st_rdev)); /* minor device number */ 2341: 2342: #else /* Others... */ 2343: #ifdef PTX /* Dynix PTX */ 2344: if (device != &ttdev[5] && strncmp(ttdev,"/dev/",5)==0) { 2345: sprintf(lockfil,"LCK..%.3s%s", &ttdev[5], device); 2346: } else 2347: #endif /* PTX */ 2348: sprintf(lockfil,"LCK..%s", device); 2349: #ifdef M_XENIX /* SCO Xenix */ 2350: { int x; char c; 2351: x = (int)strlen(lockfil) - 1; /* Get last letter of device name. */ 2352: if (x > 0) { /* If it's uppercase, lower it. */ 2353: c = lockfil[x]; 2354: if (c >= 'A' && c <= 'Z') lockfil[x] += ('a' - 'A'); 2355: } 2356: } 2357: #endif /* M_XENIX */ 2358: #ifdef RTAIX 2359: strcpy(lklockf,device); 2360: #endif /* RTAIX */ 2361: #endif /* LFDEVNO */ 2362: #endif /* ISIII */ 2363: 2364: /* flfnam = full lockfile pathname, e.g. "/usr/spool/uucp/LCK..ttyh8" */ 2365: /* tmpnam = temporary unique, e.g. "/usr/spool/uucp/LTMP..pid" */ 2366: 2367: sprintf(flfnam,"%s/%s",lockdir,lockfil); 2368: #ifdef RTAIX 2369: sprintf(lkflfn,"%s/%s",lockdir,lklockf); 2370: #endif /* RTAIX */ 2371: sprintf(tmpnam,"%s/LTMP.%05d",lockdir,(int) pid); 2372: debug(F110,"ttlock flfnam",flfnam,0); 2373: debug(F110,"ttlock tmpnam",tmpnam,0); 2374: 2375: priv_on(); /* Turn on privileges if possible. */ 2376: lockfd = creat(tmpnam, 0444); /* Try to create temp lock file. */ 2377: if (lockfd < 0) { /* Create failed. */ 2378: debug(F111,"ttlock creat failed",tmpnam,errno); 2379: if (errno == ENOENT) { 2380: perror(lockdir); 2381: printf("UUCP not installed or Kermit misconfigured\n"); 2382: } else { 2383: perror(lockdir); 2384: unlink(tmpnam); /* Get rid of the temporary file. */ 2385: } 2386: priv_off(); /* Turn off privileges!!! */ 2387: return(-1); /* Return failure code. */ 2388: } 2389: /* Now write the pid into the temp lockfile in the appropriate format */ 2390: 2391: #ifdef PIDSTRING /* For Honey DanBer UUCP, */ 2392: sprintf(pid_str,"%10d\n", (int) pid); /* Write pid as decimal string. */ 2393: write(lockfd, pid_str, 11); 2394: debug(F111,"ttlock hdb pid string",pid_str,(int) pid); 2395: #else /* Others use integer pid */ 2396: write(lockfd, (char *)&pid, sizeof(pid) ); 2397: debug(F111,"ttlock pid","",(int) pid); 2398: #endif /* PIDSTRING */ 2399: 2400: /* Now try to rename the temp file to the real lock file name. */ 2401: /* This will fail if a lock file of that name already exists. */ 2402: 2403: close(lockfd); /* Close the temp lockfile. */ 2404: chmod(tmpnam,0444); /* Permission for a valid lock. */ 2405: tries = 0; 2406: while (!haslock && tries++ < 2) { 2407: haslock = (link(tmpnam,flfnam) == 0); /* Create a link to it. */ 2408: if (haslock) { /* If we got the lockfile */ 2409: #ifdef RTAIX 2410: link(flfnam,lkflfn); 2411: #endif /* RTAIX */ 2412: #ifdef LOCKF 2413: /* 2414: Advisory file locking works on SVR4, so we use it. In fact, it is 2415: necessary in some cases, e.g. when SLIP is involved. 2416: */ 2417: while ( lockf(ttyfd, F_TLOCK, 0L) != 0 ) { 2418: debug(F111, "ttlock: lockf returns errno", "", errno); 2419: if ( (++tries >= 3) || (errno != EAGAIN) ) { 2420: x = unlink(flfnam); /* remove the lockfile */ 2421: debug(F111,"ttlock unlink",flfnam,x); 2422: haslock = 0; 2423: break; 2424: } 2425: sleep(2); 2426: } 2427: if (haslock) /* If we got an advisory lock */ 2428: #endif /* LOCKF */ 2429: break; /* We're done. */ 2430: 2431: } else { /* We didn't create a new lockfile. */ 2432: if ((fpid = ttrpid(flfnam)) > -1) { /* Read pid from old one. */ 2433: if (fpid > 0) { 2434: debug(F101,"ttlock fpid","",fpid); 2435: errno = 0; /* See if process still exists. */ 2436: x = kill((PID_T) fpid,0); 2437: debug(F101,"ttlock kill","",x); 2438: debug(F101,"ttlock kill errno","",errno); 2439: if (x < 0 && errno == ESRCH) { /* pid is invalid */ 2440: debug(F111,"ttlock removing stale lock",flfnam, 2441: fpid); 2442: if (!backgrd) 2443: printf( 2444: "Removing stale lock %s (pid %d terminated)\n", 2445: flfnam,fpid); 2446: x = unlink(flfnam); /* remove the lockfile. */ 2447: debug(F111,"ttlock unlink",flfnam,x); 2448: continue; /* and go back and try again. */ 2449: } else if ((x < 0 && errno == EPERM) || x == 0) { 2450: unlink(tmpnam); /* Delete the tempfile */ 2451: debug(F101,"ttlock found tty locked","",fpid); 2452: priv_off(); /* Turn off privs */ 2453: return(-2); /* Code for device is in use. */ 2454: } 2455: } else { 2456: debug(F101,"ttlock can't get fpid","",fpid); 2457: break; 2458: } 2459: } else break; /* Couldn't read pid from old file */ 2460: } 2461: } 2462: unlink(tmpnam); /* Unlink (remove) the temp file. */ 2463: priv_off(); /* Turn off privs */ 2464: return(haslock ? 0 : -1); /* Return link's return code. */ 2465: #endif /* !NOUUCP */ 2466: } 2467: 2468: /* T T U N L O C K */ 2469: 2470: static int 2471: ttunlck() { /* Remove UUCP lockfile. */ 2472: #ifndef NOUUCP 2473: if (haslock && *flfnam) { 2474: priv_on(); /* Turn privileges on. */ 2475: unlink(flfnam); /* Remove the lockfile. */ 2476: #ifdef RTAIX 2477: unlink(lkflfn); /* Remove other lockfile */ 2478: #endif /* RTAIX */ 2479: #ifdef LOCKF 2480: (void) lockf(ttyfd, F_ULOCK, 0L); /* Remove advisory lock */ 2481: #endif /* LOCKF */ 2482: *flfnam = '\0'; /* Erase the name. */ 2483: priv_off(); /* Turn privileges off. */ 2484: } 2485: #endif /* !NOUUCP */ 2486: return(0); 2487: } 2488: 2489: /* 4.3BSD-style UUCP line direction control (Stan Barber, Rice U) */ 2490: 2491: #ifdef ACUCNTRL 2492: VOID 2493: acucntrl(flag,ttname) char *flag, *ttname; { 2494: char x[DEVNAMLEN+32], *device, *devname; 2495: 2496: if (strcmp(ttname,CTTNAM) == 0 || xlocal == 0) /* If not local, */ 2497: return; /* just return. */ 2498: device = ((devname = xxlast(ttname,'/')) != NULL ? devname+1 : ttname); 2499: if (strncmp(device,"LCK..",4) == 0) device += 5; 2500: sprintf(x,"/usr/lib/uucp/acucntrl %s %s",flag,device); 2501: debug(F110,"called ",x,0); 2502: zsyscmd(x); 2503: } 2504: #endif /* ACUCNTRL */ 2505: 2506: /* 2507: T T H F L O W -- Set hardware flow control. 2508: */ 2509: static int 2510: tthflow(flow) int flow; { 2511: int x = 0; /* Return code */ 2512: 2513: /* There is no hardware flow control in POSIX. */ 2514: 2515: /* 2516: For SunOS 4.0 and later in the BSD environment ... 2517: 2518: The declarations are copied and interpreted from the System V header files, 2519: so we don't actually have to pull in all the System V junk when building 2520: C-Kermit for SunOS in the BSD environment, which would be dangerous because 2521: having those symbols defined would cause us to take the wrong paths through 2522: the code. The code in this section is used in both the BSD and Sys V SunOS 2523: versions. 2524: */ 2525: #ifdef SUNOS41 2526: /* 2527: In SunOS 4.1 and later, we use the POSIX calls rather than ioctl calls 2528: because GNU CC uses different formats for the _IOxxx macros than regular CC; 2529: the POSIX forms work for both. But the POSIX calls are not available in 2530: SunOS 4.0. 2531: */ 2532: #define CRTSCTS 0x80000000 /* RTS/CTS flow control */ 2533: #define TCSANOW 0 /* Do it now */ 2534: 2535: struct termios { 2536: unsigned long c_iflag; /* Input modes */ 2537: unsigned long c_oflag; /* Output modes */ 2538: unsigned long c_cflag; /* Control modes */ 2539: unsigned long c_lflag; /* Line discipline modes */ 2540: char c_line; 2541: CHAR c_cc[17]; 2542: }; 2543: struct termios temp; 2544: 2545: _PROTOTYP( int tcgetattr, (int, struct termios *) ); 2546: _PROTOTYP( int tcsetattr, (int, int, struct termios *) ); 2547: 2548: /* 2549: When CRTSCTS is set, SunOS won't do output unless both CTS and CD are 2550: asserted. So we don't set CRTSCTS unless CD is up. This should be OK, 2551: since we don't need RTS/CTS during dialing, and after dialing is complete, 2552: we should have CD. If not, we still communicate, but without RTS/CTS. 2553: */ 2554: int mflags; /* Modem signal flags */ 2555: if (ioctl(ttyfd,TIOCMGET,&mflags) > -1 && /* Get modem signals */ 2556: (mflags & TIOCM_CAR)) { /* Check for CD */ 2557: debug(F100,"tthflow SunOS has CD","",0); 2558: if (tcgetattr(ttyfd, &temp) > -1 && /* Get device attributes */ 2559: !(temp.c_cflag & CRTSCTS)) { /* Check for RTS/CTS */ 2560: temp.c_cflag |= CRTSCTS; /* Not there, add it */ 2561: x = tcsetattr(ttyfd,TCSANOW,&temp); 2562: } 2563: } else debug(F100,"tthflow SunOS no CD","",0); 2564: #else 2565: #ifdef SUNOS4 2566: /* 2567: SunOS 4.0 (and maybe earlier?). This code is dangerous because it 2568: prevents compilation with GNU gcc, which uses different formats for the 2569: _IORxxx macros than regular cc. SunOS 4.1 and later can use the POSIX 2570: routines in the #else part of this clause, which work for both cc and gcc. 2571: */ 2572: #define TCGETS _IOR(T, 8, struct termios) /* Get modes into termios struct */ 2573: #define TCSETS _IOW(T, 9, struct termios) /* Set modes from termios struct */ 2574: #define CRTSCTS 0x80000000 /* RTS/CTS flow control */ 2575: 2576: struct termios { 2577: unsigned long c_iflag; /* Input modes */ 2578: unsigned long c_oflag; /* Output modes */ 2579: unsigned long c_cflag; /* Control modes */ 2580: unsigned long c_lflag; /* Line discipline modes */ 2581: char c_line; 2582: CHAR c_cc[17]; 2583: }; 2584: struct termios temp; 2585: 2586: if (ioctl(ttyfd,TCGETS,&temp) > -1) { /* Get current terminal modes. */ 2587: temp.c_cflag |= CRTSCTS; /* Add RTS/CTS to them. */ 2588: x = ioctl(ttyfd,TCSETS,&temp); /* Set them again. */ 2589: } 2590: #else /* Not SunOS 4.0 or later */ 2591: #ifdef ATTSV 2592: if (flow == FLO_RTSC) { 2593: /* RTS/CTS Flow control... */ 2594: #ifdef RTSXOFF 2595: /* This is the preferred way, according to SVID R4 */ 2596: if (ioctl(ttyfd,TCGETX,&rctsx) > -1) { 2597: rctsx.x_hflag |= RTSXOFF | CTSXON; 2598: x = ioctl(ttyfd,TCSETX,&rctsx); 2599: } 2600: #endif /* RTSXOFF */ 2601: } 2602: if (flow == FLO_DTRC) { 2603: /* DTR/CD Flow control... */ 2604: #ifdef DTRXOFF 2605: /* This is straight out of SVID R4 */ 2606: if (ioctl(ttyfd,TCGETX,&rctsx) > -1) { 2607: rctsx.x_hflag |= DTRXOFF | CDXON; 2608: x = ioctl(ttyfd,TCSETX,&rctsx); 2609: } 2610: #endif /* DTRXOFF */ 2611: } 2612: #else /* not System V */ 2613: #ifdef CK_DTRCTS 2614: x = LDODTR | LDOCTS; /* Found only on UTEK? */ 2615: if (flow == FLO_DTRT) { /* Use hardware flow control */ 2616: if (lmodef) { 2617: x = ioctl(ttyfd,TIOCLBIS,&x); 2618: if (x < 0) { 2619: debug(F100,"hardflow TIOCLBIS error","",0); 2620: } else { 2621: lmodef++; 2622: debug(F100,"hardflow TIOCLBIS ok","",0); 2623: } 2624: } 2625: } else { 2626: if (lmodef) { 2627: x = ioctl(ttyfd,TIOCLBIC,&x); 2628: if (x < 0) { 2629: debug(F100,"hardflow TIOCLBIC error","",0); 2630: } else { 2631: lmodef++; 2632: debug(F100,"hardflow TIOCLBIC ok","",0); 2633: } 2634: } 2635: } 2636: #endif /* CK_DTRCTS */ 2637: #endif /* ATTSV */ 2638: #endif /* SUNOS4 */ 2639: #endif /* SUNOS41 */ 2640: return(x); 2641: } 2642: 2643: /* T T P K T -- Condition the communication line for packets */ 2644: /* or for modem dialing */ 2645: 2646: /* 2647: If called with speed > -1, also set the speed. 2648: Returns 0 on success, -1 on failure. 2649: 2650: NOTE: the "xflow" parameter is supposed to be the currently selected 2651: type of flow control, but for historical reasons, this parameter is also 2652: used to indicate that we are dialing. Therefore, when the true flow 2653: control setting is needed, we access the external variable "flow", rather 2654: than trusting our "xflow" argument. 2655: */ 2656: int 2657: #ifdef CK_ANSIC 2658: ttpkt(long speed, int xflow, int parity) 2659: #else 2660: ttpkt(speed,xflow,parity) long speed; int xflow, parity; 2661: #endif /* CK_ANSIC */ 2662: /* ttpkt */ { 2663: int s2; 2664: int s = -1; 2665: #ifndef SVORPOSIX 2666: int x; 2667: #endif /* SVORPOSIX */ 2668: extern int flow; /* REAL flow-control setting */ 2669: 2670: if (ttyfd < 0) return(-1); /* Not open. */ 2671: 2672: debug(F101,"ttpkt parity","",parity); 2673: debug(F101,"ttpkt xflow","",xflow); 2674: debug(F101,"ttpkt speed","",(int) speed); 2675: 2676: ttprty = parity; /* Let other tt functions see these. */ 2677: ttpflg = 0; /* Parity not sensed yet */ 2678: ttpmsk = ttprty ? 0177 : 0377; /* Parity stripping mask */ 2679: ttspeed = speed; /* Make global copy for this module */ 2680: 2681: #ifdef NETCONN /* Nothing to do for telnet */ 2682: if (netconn) return (0); 2683: #endif /* NETCONN */ 2684: 2685: if (ttfdflg && !isatty(ttyfd)) return(0); 2686: 2687: #ifndef SVORPOSIX /* Berkeley, V7, etc. */ 2688: #ifdef LPASS8 2689: /* 2690: For some reason, with BSD terminal drivers, you can't set FLOW to XON/XOFF 2691: after having previously set it to NONE without closing and reopening the 2692: device. Unless there's something I overlooked below... 2693: */ 2694: if (ttflow == FLO_NONE && flow == FLO_XONX && xlocal == 0) { 2695: debug(F101,"ttpkt executing horrible flow kludge","",0); 2696: ttclos(0); /* Close it */ 2697: x = 0; 2698: ttopen(ttnmsv,&x,ttmdm,0); /* Open it again */ 2699: } 2700: #endif /* LPASS8 */ 2701: #endif /* SVORPOSIX */ 2702: 2703: if (xflow != FLO_DIAL && xflow != FLO_DIAX) 2704: ttflow = xflow; /* Now make this available too. */ 2705: 2706: if (xlocal) { 2707: s2 = (int) (speed / 10L); /* Convert bps to cps */ 2708: s = ttsspd(s2); /* Check and set the speed */ 2709: debug(F101,"ttpkt carrier","",xflow); 2710: carrctl(&ttraw, xflow != FLO_DIAL /* Carrier control */ 2711: && (ttcarr == CAR_ON)); 2712: tvtflg = 0; /* So ttvt() will work next time */ 2713: } 2714: 2715: #ifndef SVORPOSIX /* BSD section */ 2716: if (flow == FLO_RTSC || /* Hardware flow control */ 2717: flow == FLO_DTRC || 2718: flow == FLO_DTRT) { 2719: tthflow(flow); 2720: debug(F100,"ttpkt hard flow, TANDEM off, RAW on","",0); 2721: ttraw.sg_flags &= ~TANDEM; /* Don't ask for it. */ 2722: ttraw.sg_flags |= RAW; 2723: } else if (flow == FLO_NONE) { /* No Xon/Xoff flow control */ 2724: debug(F100,"ttpkt no flow, TANDEM off, RAW on","",0); 2725: ttraw.sg_flags &= ~TANDEM; /* Don't ask for it. */ 2726: ttraw.sg_flags |= RAW; 2727: /* NOTE: We should also turn off hardware flow control here! */ 2728: } else if (flow == FLO_KEEP) { /* Keep device's original setting */ 2729: debug(F100,"ttpkt keeping original TANDEM","",0); 2730: ttraw.sg_flags &= ~TANDEM; 2731: ttraw.sg_flags |= (ttold.sg_flags & TANDEM); 2732: /* NOTE: We should also handle hardware flow control here! */ 2733: } 2734: 2735: /* SET FLOW XON/XOFF is in effect, or SET FLOW KEEP resulted in Xon/Xoff */ 2736: 2737: if ((flow == FLO_XONX) || (ttraw.sg_flags & TANDEM)) { 2738: debug(F100,"ttpkt turning on TANDEM","",0); 2739: ttraw.sg_flags |= TANDEM; /* So ask for it. */ 2740: 2741: #ifdef LPASS8 /* Can pass 8-bit data through? */ 2742: /* If the LPASS8 local mode is available, then flow control can always */ 2743: /* be used, even if parity is none and we are transferring 8-bit data. */ 2744: /* But we only need to do all this if Xon/Xoff is requested. */ 2745: /* BUT... this tends not to work through IP or LAT connections, terminal */ 2746: /* servers, telnet, rlogin, etc, so it is currently disabled. */ 2747: x = LPASS8; /* If LPASS8 defined, then */ 2748: debug(F100,"ttpkt executing LPASS8 code","",0); 2749: if (lmodef) { /* TIOCLBIS must be too. */ 2750: x = ioctl(ttyfd,TIOCLBIS,&x); /* Try to set LPASS8. */ 2751: if (x < 0) { 2752: debug(F100,"ttpkt TIOCLBIS error","",0); 2753: } else { 2754: lmodef++; 2755: debug(F100,"ttpkt TIOCLBIS ok","",0); 2756: } 2757: } 2758: /* 2759: But if we use LPASS8 mode, we must explicitly turn off 2760: terminal interrupts of all kinds. 2761: */ 2762: #ifdef TIOCGETC /* Not rawmode, */ 2763: if (tcharf && (xlocal == 0)) { /* must turn off */ 2764: tchnoi.t_intrc = -1; /* interrupt character */ 2765: tchnoi.t_quitc = -1; /* and quit character. */ 2766: tchnoi.t_startc = 17; /* Make sure xon */ 2767: tchnoi.t_stopc = 19; /* and xoff not ignored. */ 2768: #ifndef NOBRKC 2769: tchnoi.t_eofc = -1; /* eof character. */ 2770: tchnoi.t_brkc = -1; /* brk character. */ 2771: #endif /* NOBRKC */ 2772: if (ioctl(ttyfd,TIOCSETC,&tchnoi) < 0) { 2773: debug(F100,"ttpkt TIOCSETC failed","",0); 2774: } else { 2775: tcharf = 1; 2776: debug(F100,"ttpkt TIOCSETC ok","",0); 2777: } 2778: #ifdef COMMENT 2779: /* only for paranoid debugging */ 2780: if (tcharf) { 2781: struct tchars foo; 2782: char tchbuf[100]; 2783: ioctl(0,TIOCGETC,&foo); 2784: sprintf(tchbuf, 2785: "intr=%d,quit=%d, start=%d, stop=%d, eof=%d, brk=%d", 2786: foo.t_intrc, foo.t_quitc, foo.t_startc, 2787: foo.t_stopc, foo.t_eofc, foo.t_brkc); 2788: debug(F110,"ttpkt chars",tchbuf,0); 2789: } 2790: #endif /* COMMENT */ 2791: } 2792: ttraw.sg_flags |= CBREAK; /* Needed for unknown reason */ 2793: #endif /* TIOCGETC */ 2794: 2795: /* Prevent suspend during packet mode */ 2796: #ifdef TIOCGLTC /* Not rawmode, */ 2797: if (ltcharf && (xlocal == 0)) { /* must turn off */ 2798: ltchnoi.t_suspc = -1; /* suspend character */ 2799: ltchnoi.t_dsuspc = -1; /* and delayed suspend character */ 2800: if (ioctl(ttyfd,TIOCSLTC,&tchnoi) < 0) { 2801: debug(F100,"ttpkt TIOCSLTC failed","",0); 2802: } else { 2803: ltcharf = 1; 2804: debug(F100,"ttpkt TIOCSLTC ok","",0); 2805: } 2806: } 2807: #endif /* TIOCGLTC */ 2808: 2809: #else /* LPASS8 not defined */ 2810: 2811: /* Previously, BSD-based implementations always */ 2812: /* used rawmode for packets. Now, we use rawmode only if parity is NONE. */ 2813: /* This allows the flow control requested above to actually work, but only */ 2814: /* if the user asks for parity (which also means they get 8th-bit quoting). */ 2815: 2816: if (parity) { /* If parity, */ 2817: ttraw.sg_flags &= ~RAW; /* use cooked mode */ 2818: #ifdef COMMENT 2819: /* WHY??? */ 2820: if (xlocal) 2821: #endif /* COMMENT */ 2822: ttraw.sg_flags |= CBREAK; 2823: debug(F101,"ttpkt cooked, cbreak, parity","",parity); 2824: #ifdef TIOCGETC /* Not rawmode, */ 2825: if (tcharf && (xlocal == 0)) { /* must turn off */ 2826: tchnoi.t_intrc = -1; /* interrupt character */ 2827: tchnoi.t_quitc = -1; /* and quit character. */ 2828: tchnoi.t_startc = 17; /* Make sure xon */ 2829: tchnoi.t_stopc = 19; /* and xoff not ignored. */ 2830: #ifndef NOBRKC 2831: tchnoi.t_eofc = -1; /* eof character. */ 2832: tchnoi.t_brkc = -1; /* brk character. */ 2833: #endif /* NOBRKC */ 2834: if (ioctl(ttyfd,TIOCSETC,&tchnoi) < 0) { 2835: debug(F100,"ttpkt TIOCSETC failed","",0); 2836: } else { 2837: tcharf = 1; 2838: debug(F100,"ttpkt TIOCSETC ok","",0); 2839: } 2840: } 2841: #endif /* TIOCGETC */ 2842: #ifdef TIOCGLTC /* Not rawmode, */ 2843: /* Prevent suspend during packet mode */ 2844: if (ltcharf && (xlocal == 0)) { /* must turn off */ 2845: ltchnoi.t_suspc = -1; /* suspend character */ 2846: ltchnoi.t_dsuspc = -1; /* and delayed suspend character */ 2847: if (ioctl(ttyfd,TIOCSLTC,&tchnoi) < 0) { 2848: debug(F100,"ttpkt TIOCSLTC failed","",0); 2849: } else { 2850: ltcharf = 1; 2851: debug(F100,"ttpkt TIOCSLTC ok","",0); 2852: } 2853: } 2854: #endif /* TIOCGLTC */ 2855: } else { /* If no parity, */ 2856: ttraw.sg_flags |= RAW; /* must use 8-bit raw mode. */ 2857: debug(F101,"ttpkt setting rawmode, parity","",parity); 2858: } 2859: #endif /* LPASS8 */ 2860: } /* End of Xon/Xoff section */ 2861: 2862: /* Don't echo, don't map CR to CRLF on output, don't fool with case */ 2863: #ifdef LCASE 2864: ttraw.sg_flags &= ~(ECHO|CRMOD|LCASE); 2865: #else 2866: ttraw.sg_flags &= ~(ECHO|CRMOD); 2867: #endif /* LCASE */ 2868: 2869: #ifdef TOWER1 2870: ttraw.sg_flags &= ~ANYP; /* Must set this on old Towers */ 2871: #endif /* TOWER1 */ 2872: 2873: if (stty(ttyfd,&ttraw) < 0) return(-1); /* Set the new modes. */ 2874: debug(F100,"ttpkt stty ok","",0); 2875: 2876: #ifdef sony_news 2877: x = xlocal ? km_ext : km_con; /* Put line in ASCII mode. */ 2878: if (x != -1) { /* Make sure we know original modes. */ 2879: x &= ~KM_TTYPE; 2880: x |= KM_ASCII; 2881: if (ioctl(ttyfd,TIOCKSET, &x) < 0) { 2882: perror("ttpkt can't set ASCII mode"); 2883: debug(F101,"ttpkt error setting ASCII mode","",x); 2884: return(-1); 2885: } 2886: } 2887: debug(F100,"ttpkt set ASCII mode ok","",0); 2888: #endif /* sony_news */ 2889: 2890: if (xlocal == 0) /* Turn this off so we can read */ 2891: signal(SIGINT,SIG_IGN); /* Ctrl-C chars typed at console */ 2892: 2893: tvtflg = 0; /* So ttvt() will work next time */ 2894: return(0); 2895: 2896: #endif /* Not ATTSV or POSIX */ 2897: 2898: /* AT&T UNIX and POSIX */ 2899: 2900: #ifdef SVORPOSIX 2901: if (flow == FLO_XONX) /* Xon/Xoff */ 2902: ttraw.c_iflag |= (IXON|IXOFF); 2903: else if (flow == FLO_NONE) /* None */ 2904: /* NOTE: We should also turn off hardware flow control here! */ 2905: ttraw.c_iflag &= ~(IXON|IXOFF); 2906: else if (flow == FLO_KEEP) { /* Keep */ 2907: ttraw.c_iflag &= ~(IXON|IXOFF); /* Turn off Xon/Xoff flags */ 2908: ttraw.c_iflag |= (ttold.c_iflag & (IXON|IXOFF)); /* OR in old ones */ 2909: /* NOTE: We should also handle hardware flow control here! */ 2910: } else if (flow == FLO_RTSC || /* Hardware */ 2911: flow == FLO_DTRC || 2912: flow == FLO_DTRT) 2913: tthflow(flow); 2914: 2915: ttraw.c_lflag &= ~(ICANON|ECHO); 2916: ttraw.c_lflag &= ~ISIG; /* Do NOT check for interrupt chars */ 2917: ttraw.c_lflag &= ~IEXTEN; /* Turn off ^O/^V processing */ 2918: ttraw.c_lflag |= NOFLSH; /* Don't flush */ 2919: ttraw.c_iflag |= (BRKINT|IGNPAR); 2920: #ifdef ATTSV 2921: #ifdef BSD44 2922: ttraw.c_iflag &= ~(IGNBRK|INLCR|IGNCR|ICRNL|INPCK|ISTRIP|IXANY); 2923: #else 2924: ttraw.c_iflag &= ~(IGNBRK|INLCR|IGNCR|ICRNL|IUCLC|INPCK|ISTRIP|IXANY); 2925: #endif /* BSD44 */ 2926: #else /* POSIX */ 2927: ttraw.c_iflag &= ~(IGNBRK|INLCR|IGNCR|ICRNL|INPCK|ISTRIP); 2928: #endif /* ATTSV */ 2929: ttraw.c_oflag &= ~OPOST; 2930: ttraw.c_cflag &= ~(CSIZE|PARENB); 2931: ttraw.c_cflag |= (CS8|CREAD|HUPCL); 2932: #ifdef IX370 2933: ttraw.c_cc[4] = 48; /* So Series/1 doesn't interrupt on every char */ 2934: ttraw.c_cc[5] = 1; 2935: #else 2936: #ifndef VEOF /* for DGUX this is VEOF, not VMIN */ 2937: ttraw.c_cc[4] = 1; /* [VMIN] return max of this many characters or */ 2938: #else 2939: #ifdef VMIN 2940: ttraw.c_cc[VMIN] = 1; 2941: #endif /* VMIN */ 2942: #endif /* VEOF */ 2943: #ifndef VEOL /* for DGUX this is VEOL, not VTIME */ 2944: ttraw.c_cc[5] = 0; /* [VTIME] when this many secs/10 expire w/no input */ 2945: #else 2946: #ifdef VTIME 2947: ttraw.c_cc[VTIME] = 0; 2948: #endif /* VTIME */ 2949: #endif /* VEOL */ 2950: #endif /* IX370 */ 2951: 2952: #ifdef VINTR /* Turn off interrupt character */ 2953: if (xlocal == 0) /* so ^C^C can break us out of */ 2954: ttraw.c_cc[VINTR] = 0; /* packet mode. */ 2955: #endif /* VINTR */ 2956: 2957: #ifdef BSD44ORPOSIX 2958: if (xlocal && (s > 0)) { 2959: cfsetispeed(&ttraw,s); 2960: cfsetospeed(&ttraw,s); 2961: } 2962: if (tcsetattr(ttyfd,TCSADRAIN,&ttraw) < 0) return(-1); 2963: #else /* ATTSV */ 2964: if (xlocal && (s > 0)) { /* set speed */ 2965: ttraw.c_cflag &= ~CBAUD; 2966: ttraw.c_cflag |= s; 2967: } 2968: if (ioctl(ttyfd,TCSETAW,&ttraw) < 0) return(-1); /* set new modes . */ 2969: #endif /* BSD44ORPOSIX */ 2970: tvtflg = 0; 2971: return(0); 2972: #endif /* ATTSV */ 2973: } 2974: 2975: /* T T V T -- Condition communication line for use as virtual terminal */ 2976: 2977: int 2978: #ifdef CK_ANSIC 2979: ttvt(long speed, int flow) 2980: #else 2981: ttvt(speed,flow) long speed; int flow; 2982: #endif /* CK_ANSIC */ 2983: /* ttvt */ { 2984: int s, s2; 2985: 2986: debug(F101,"ttvt ttyfd","",ttyfd); 2987: debug(F101,"ttvt tvtflg","",tvtflg); 2988: debug(F101,"ttvt speed","",speed); 2989: if (ttyfd < 0) return(-1); /* Not open. */ 2990: #ifdef NETCONN 2991: if (netconn) { 2992: tvtflg = 1; /* Network connections */ 2993: return(0); /* require no special setup */ 2994: } 2995: #endif /* NETCONN */ 2996: 2997: if (tvtflg != 0 && speed == ttspeed && flow == ttflow && ttcarr == curcarr) 2998: return(0); /* Already been called. */ 2999: 3000: if (ttfdflg && !isatty(ttyfd)) return(0); 3001: 3002: if (xlocal) { /* For external lines... */ 3003: s2 = (int) (speed / 10L); 3004: s = ttsspd(s2); /* Check/set the speed */ 3005: carrctl(&tttvt, flow != FLO_DIAL /* Do carrier control */ 3006: && (ttcarr == CAR_ON || (ttcarr == CAR_AUT && ttmdm != 0))); 3007: } else s = s2 = -1; 3008: 3009: #ifndef SVORPOSIX 3010: /* Berkeley, V7, etc */ 3011: if (flow == FLO_RTSC || /* Hardware flow control */ 3012: flow == FLO_DTRC || 3013: flow == FLO_DTRT) 3014: tthflow(flow); 3015: if (flow == FLO_XONX) { /* No Xon/Xoff flow control */ 3016: tttvt.sg_flags |= TANDEM; /* Ask for it. */ 3017: } else if (flow == FLO_KEEP) { 3018: tttvt.sg_flags &= ~TANDEM; 3019: tttvt.sg_flags |= (ttold.sg_flags & TANDEM); 3020: /* NOTE: We should also handle hardware flow control here! */ 3021: } else if (flow == FLO_NONE) { 3022: tttvt.sg_flags &= ~TANDEM; /* Don't ask for it. */ 3023: /* NOTE: We should also turn off hardware flow control here! */ 3024: } 3025: tttvt.sg_flags |= RAW; /* Raw mode in all cases */ 3026: #ifdef TOWER1 3027: tttvt.sg_flags &= ~(ECHO|ANYP); /* No echo or parity */ 3028: #else 3029: tttvt.sg_flags &= ~ECHO; /* No echo */ 3030: #endif /* TOWER1 */ 3031: 3032: if (stty(ttyfd,&tttvt) < 0) /* Set the new modes */ 3033: return(-1); 3034: 3035: #else /* It is ATTSV or POSIX */ 3036: 3037: if (flow == FLO_RTSC || /* Hardware flow control */ 3038: flow == FLO_DTRC || 3039: flow == FLO_DTRT) 3040: tthflow(flow); 3041: else if (flow == FLO_XONX) /* Software flow control */ 3042: tttvt.c_iflag |= (IXON|IXOFF); /* On if requested. */ 3043: else if (flow == FLO_KEEP) { 3044: tttvt.c_iflag &= ~(IXON|IXOFF); /* Turn off Xon/Xoff flags */ 3045: tttvt.c_iflag |= (ttold.c_iflag & (IXON|IXOFF)); /* OR in old ones */ 3046: /* NOTE: We should also handle hardware flow control here! */ 3047: } else if (flow == FLO_NONE) /* Off if NONE or hardware */ 3048: tttvt.c_iflag &= ~(IXON|IXOFF); /* requested. */ 3049: 3050: tttvt.c_lflag &= ~(ISIG|ICANON|ECHO|IEXTEN); 3051: tttvt.c_iflag |= (IGNBRK|IGNPAR); 3052: #ifdef ATTSV 3053: #ifdef BSD44 3054: tttvt.c_iflag &= ~(INLCR|IGNCR|ICRNL|BRKINT|INPCK|ISTRIP|IXANY); 3055: #else 3056: tttvt.c_iflag &= ~(INLCR|IGNCR|ICRNL|IUCLC|BRKINT|INPCK|ISTRIP|IXANY); 3057: #endif /* BSD44 */ 3058: #else /* POSIX */ 3059: tttvt.c_iflag &= ~(INLCR|IGNCR|ICRNL|BRKINT|INPCK|ISTRIP); 3060: #endif /* ATTSV */ 3061: tttvt.c_oflag &= ~OPOST; 3062: tttvt.c_cflag &= ~(CSIZE|PARENB); 3063: tttvt.c_cflag |= (CS8|CREAD|HUPCL); 3064: #ifndef VEOF /* DGUX termio has VEOF at entry 4, see comment above */ 3065: tttvt.c_cc[4] = 1; 3066: #else 3067: #ifdef VMIN 3068: tttvt.c_cc[VMIN] = 1; 3069: #endif /* VMIN */ 3070: #endif /* VEOF */ 3071: #ifndef VEOL /* DGUX termio has VEOL at entry 5, see comment above */ 3072: tttvt.c_cc[5] = 0; 3073: #else 3074: #ifdef VTIME 3075: tttvt.c_cc[VTIME] = 0; 3076: #endif /* VTIME */ 3077: #endif /* VEOL */ 3078: 3079: #ifdef BSD44ORPOSIX 3080: if (xlocal && (s > 0)) { 3081: cfsetispeed(&tttvt,s); 3082: cfsetospeed(&tttvt,s); 3083: } 3084: if (tcsetattr(ttyfd,TCSADRAIN,&tttvt) < 0) return(-1); 3085: #else /* ATTSV */ 3086: if (s > 0) { /* Set speed */ 3087: tttvt.c_cflag &= ~CBAUD; 3088: tttvt.c_cflag |= s; 3089: } 3090: if (ioctl(ttyfd,TCSETAW,&tttvt) < 0) return(-1); /* set new modes . */ 3091: #endif /* BSD44ORPOSIX */ 3092: #endif /* ATTSV */ 3093: 3094: ttspeed = speed; /* Done, remember how we were */ 3095: ttflow = flow; /* called, so we can decide how to */ 3096: tvtflg = 1; /* respond next time. */ 3097: 3098: debug(F101,"ttvt done","",tvtflg); 3099: return(0); 3100: } 3101: 3102: /* T T S S P D -- Checks and sets transmission rate. */ 3103: 3104: /* Call with speed in characters (not bits!) per second. */ 3105: /* Returns internal speed code if successful, -1 otherwise. */ 3106: 3107: int 3108: ttsspd(cps) int cps; { 3109: int s, s2; 3110: 3111: debug(F101,"ttsspd","",cps); 3112: 3113: #ifdef NETCONN 3114: if (netconn) return (0); 3115: #endif /* NETCONN */ 3116: 3117: if (cps < 0) return(-1); 3118: s = s2 = -1; 3119: 3120: /* First check that the given speed is valid. */ 3121: 3122: switch (cps) { 3123: #ifndef MINIX 3124: case 0: s = B0; break; 3125: case 5: s = B50; break; 3126: case 7: s = B75; break; 3127: #endif 3128: case 11: s = B110; break; 3129: #ifndef MINIX 3130: case 15: s = B150; break; 3131: case 20: s = B200; break; 3132: #endif 3133: case 30: s = B300; break; 3134: #ifndef MINIX 3135: case 60: s = B600; break; 3136: #endif 3137: case 120: s = B1200; break; 3138: #ifndef MINIX 3139: case 180: s = B1800; break; 3140: #endif 3141: case 240: s = B2400; break; 3142: case 480: s = B4800; break; 3143: #ifndef MINIX 3144: case 888: s = B75; s2 = B1200; break; /* 888 = 75/1200 split speed */ 3145: #endif 3146: case 960: s = B9600; break; 3147: #ifdef B19200 3148: case 1920: s = B19200; break; 3149: #else 3150: #ifdef EXTA 3151: case 1920: s = EXTA; break; 3152: #endif 3153: #endif 3154: #ifdef B38400 3155: case 3840: s = B38400; break; 3156: #else 3157: #ifdef EXTB 3158: case 3840: s = EXTB; break; 3159: #endif 3160: #endif 3161: default: 3162: return(-1); 3163: } 3164: /* Actually set the speed */ 3165: 3166: if (ttyfd > -1 && s > -1 && xlocal != 0) { 3167: if (s2 == -1) s2 = s; 3168: 3169: #ifdef BSD44ORPOSIX 3170: if (tcgetattr(ttyfd,&ttcur) < 0) return(-1); 3171: cfsetospeed(&ttcur,s); 3172: cfsetispeed(&ttcur,s2); 3173: cfsetospeed(&ttraw,s); 3174: cfsetispeed(&ttraw,s2); 3175: cfsetospeed(&tttvt,s); 3176: cfsetispeed(&tttvt,s2); 3177: cfsetospeed(&ttold,s); 3178: cfsetispeed(&ttold,s2); 3179: if (tcsetattr(ttyfd,TCSADRAIN,&ttcur) < 0) return(-1); 3180: #else 3181: #ifdef ATTSV 3182: if (cps == 888) return(-1); /* No split speeds, sorry. */ 3183: if (ioctl(ttyfd,TCGETA,&ttcur) < 0) return(-1); 3184: ttcur.c_cflag &= ~CBAUD; 3185: ttcur.c_cflag |= s; 3186: tttvt.c_cflag &= ~CBAUD; 3187: tttvt.c_cflag |= s; 3188: ttraw.c_cflag &= ~CBAUD; 3189: ttraw.c_cflag |= s; 3190: ttold.c_cflag &= ~CBAUD; 3191: ttold.c_cflag |= s; 3192: if (ioctl(ttyfd,TCSETAW,&ttcur) < 0) return(-1); 3193: #else 3194: if (gtty(ttyfd,&ttcur) < 0) return(-1); 3195: ttcur.sg_ospeed = s; ttcur.sg_ispeed = s2; 3196: tttvt.sg_ospeed = s; tttvt.sg_ispeed = s2; 3197: ttraw.sg_ospeed = s; ttraw.sg_ispeed = s2; 3198: ttold.sg_ospeed = s; ttold.sg_ispeed = s2; 3199: if (stty(ttyfd,&ttcur) < 0) return(-1); 3200: #endif /* ATTSV */ 3201: #endif /* BSD44ORPOSIX */ 3202: } 3203: return(s); 3204: } 3205: 3206: /* T T G S P D - Get speed of currently selected tty line */ 3207: 3208: /* 3209: Unreliable. After SET LINE, it returns an actual speed, but not the real 3210: speed. Apparently it always returns the line's nominal speed, from 3211: /etc/ttytab. Even if you SET SPEED to something else, this function might 3212: not notice. 3213: */ 3214: long 3215: ttgspd() { /* Get current tty speed */ 3216: int s; long ss; 3217: char temp[12]; 3218: 3219: #ifdef NETCONN 3220: if (netconn) return(-1); /* -1 if network connection */ 3221: #endif /* NETCONN */ 3222: 3223: if (ttyfd < 0) { 3224: #ifdef BSD44ORPOSIX 3225: s = cfgetospeed(&ccold); 3226: #else 3227: #ifdef ATTSV 3228: s = ccold.c_cflag & CBAUD; 3229: #else 3230: s = ccold.sg_ospeed; /* (obtained by congm()) */ 3231: #endif /* ATTSV */ 3232: #endif /* BSD44ORPOSIX */ 3233: 3234: } else { 3235: #ifdef BSD44ORPOSIX 3236: if (tcgetattr(ttyfd,&ttcur) < 0) return(-1); 3237: s = cfgetospeed(&ttcur); 3238: #else 3239: #ifdef ATTSV 3240: if (ioctl(ttyfd,TCGETA,&ttcur) < 0) return(-1); 3241: s = ttcur.c_cflag & CBAUD; 3242: #else 3243: if (gtty(ttyfd,&ttcur) < 0) return(-1); 3244: s = ttcur.sg_ospeed; 3245: #endif /* ATTSV */ 3246: #endif /* BSD44ORPOSIX */ 3247: } 3248: debug(F101,"ttgspd ttyfd","",ttyfd); 3249: debug(F101,"ttgspd code","",s); 3250: switch (s) { 3251: #ifdef B0 3252: case B0: ss = 0L; break; 3253: #endif /* B0 */ 3254: 3255: #ifndef MINIX 3256: /* 3257: MINIX defines the Bxx symbols to be bps/100, so B50==B75, B110==B134==B150, 3258: etc, making for many "duplicate case in switch" errors, which are fatal. 3259: */ 3260: #ifdef B50 3261: case B50: ss = 50L; break; 3262: #endif 3263: #ifdef B75 3264: case B75: ss = 75L; break; 3265: #endif 3266: #endif /* MINIX */ 3267: 3268: #ifdef B110 3269: case B110: ss = 110L; break; 3270: #endif 3271: 3272: #ifndef MINIX 3273: #ifdef B134 3274: case B134: ss = 134L; break; 3275: #endif 3276: #ifdef B150 3277: case B150: ss = 150L; break; 3278: #endif 3279: #endif /* MINIX */ 3280: 3281: #ifdef B200 3282: case B200: ss = 200L; break; 3283: #endif 3284: 3285: #ifdef B300 3286: case B300: ss = 300L; break; 3287: #endif 3288: #ifdef B600 3289: case B600: ss = 600L; break; 3290: #endif 3291: #ifdef B1200 3292: case B1200: ss = 1200L; break; 3293: #endif 3294: #ifdef B1800 3295: case B1800: ss = 1800L; break; 3296: #endif 3297: #ifdef B2400 3298: case B2400: ss = 2400L; break; 3299: #endif 3300: #ifdef B4800 3301: case B4800: ss = 4800L; break; 3302: #endif 3303: #ifdef B9600 3304: case B9600: ss = 9600L; break; 3305: #endif 3306: #ifdef B19200 3307: case B19200: ss = 19200L; break; 3308: #else 3309: #ifdef EXTA 3310: case EXTA: ss = 19200L; break; 3311: #endif 3312: #endif 3313: 3314: #ifndef MINIX 3315: #ifdef B38400 3316: case B38400: ss = 38400L; break; 3317: #else 3318: #ifdef EXTB 3319: case EXTB: ss = 38400L; break; 3320: #endif 3321: #endif 3322: #endif /* MINIX */ 3323: 3324: default: 3325: ss = -1; break; 3326: } 3327: sprintf(temp,"%ld",ss); 3328: debug(F110,"speed",temp,0); 3329: return(ss); 3330: } 3331: 3332: /* ckumyr.c by Kristoffer Eriksson, ske@pkmab.se, 15 Mar 1990. */ 3333: 3334: #ifdef COHERENT 3335: #ifdef FIONREAD 3336: #undef FIONREAD 3337: #endif 3338: #define FIONREAD TIOCQUERY 3339: #define PEEKTYPE int 3340: #else 3341: #define PEEKTYPE long 3342: #endif /* COHERENT */ 3343: 3344: #ifdef MYREAD 3345: 3346: /* Private buffer for myread() and its companions. Not for use by anything 3347: * else. ttflui() is allowed to reset them to initial values. ttchk() is 3348: * allowed to read my_count. 3349: * 3350: * my_item is an index into mybuf[]. Increment it *before* reading mybuf[]. 3351: * 3352: * A global parity mask variable could be useful too. We could use it to 3353: * let myread() strip the parity on its own, instead of stripping sign 3354: * bits as it does now. 3355: */ 3356: #define MYBUFLEN 256 3357: #ifdef SUNX25 3358: /* 3359: On X.25 connections, there is an extra control byte at the beginning. 3360: */ 3361: static CHAR x25buf[MYBUFLEN+1]; /* Communication device input buffer */ 3362: static CHAR *mybuf = x25buf+1; 3363: #else 3364: static CHAR mybuf[MYBUFLEN]; 3365: #endif /* SUNX25 */ 3366: 3367: static int my_count = 0; /* Number of chars still in mybuf */ 3368: static int my_item = -1; /* Last index read from mybuf[] */ 3369: 3370: /* myread() -- Efficient read of one character from communications line. 3371: * 3372: * Uses a private buffer to minimize the number of expensive read() system 3373: * calls. Essentially performs the equivalent of read() of 1 character, which 3374: * is then returned. By reading all available input from the system buffers 3375: * to the private buffer in one chunk, and then working from this buffer, the 3376: * number of system calls is reduced in any case where more than one character 3377: * arrives during the processing of the previous chunk, for instance high 3378: * baud rates or network type connections where input arrives in packets. 3379: * If the time needed for a read() system call approaches the time for more 3380: * than one character to arrive, then this mechanism automatically compensates 3381: * for that by performing bigger read()s less frequently. If the system load 3382: * is high, the same mechanism compensates for that too. 3383: * 3384: * myread() is a macro that returns the next character from the buffer. If the 3385: * buffer is empty, mygetbuf() is called. See mygetbuf() for possible error 3386: * returns. 3387: * 3388: * This should be efficient enough for any one-character-at-a-time loops. 3389: * For even better efficiency you might use memcpy()/bcopy() or such between 3390: * buffers (since they are often better optimized for copying), but it may not 3391: * be worth it if you have to take an extra pass over the buffer to strip 3392: * parity and check for CTRL-C anyway. 3393: * 3394: * Note that if you have been using myread() from another program module, you 3395: * may have some trouble accessing this macro version and the private variables 3396: * it uses. In that case, just add a function in this module, that invokes the 3397: * macro. 3398: */ 3399: #define myread() (--my_count < 0 ? mygetbuf() : 255 & (int)mybuf[++my_item]) 3400: 3401: /* Specification: Push back up to one character onto myread()'s queue. 3402: * 3403: * This implementation: Push back characters into mybuf. At least one character 3404: * must have been read through myread() before myunrd() may be used. After 3405: * EOF or read error, again, myunrd() can not be used. Sometimes more than 3406: * one character can be pushed back, but only one character is guaranteed. 3407: * Since a previous myread() must have read its character out of mybuf[], 3408: * that guarantees that there is space for at least one character. If push 3409: * back was really needed after EOF, a small addition could provide that. 3410: * 3411: * myunrd() is currently not called from anywhere inside kermit... 3412: */ 3413: #ifdef NOTUSED 3414: myunrd(ch) CHAR ch; { 3415: if (my_item >= 0) { 3416: mybuf[my_item--] = ch; 3417: ++my_count; 3418: } 3419: } 3420: #endif 3421: 3422: /* mygetbuf() -- Fill buffer for myread() and return first character. 3423: * 3424: * This function is what myread() uses when it can't get the next character 3425: * directly from its buffer. First, it calls a system dependent myfillbuf() 3426: * to read at least one new character into the buffer, and then it returns 3427: * the first character just as myread() would have done. This function also 3428: * is responsible for all error conditions that myread() can indicate. 3429: * 3430: * Returns: When OK => a positive character, 0 or greater. 3431: * When EOF => -2. 3432: * When error => -3, error code in errno. 3433: * 3434: * Older myread()s additionally returned -1 to indicate that there was nothing 3435: * to read, upon which the caller would call myread() again until it got 3436: * something. The new myread()/mygetbuf() always gets something. If it 3437: * doesn't, then make it do so! Any program that actually depends on the old 3438: * behaviour will break. 3439: * 3440: * The older version also used to return -2 both for EOF and other errors, 3441: * and used to set errno to 9999 on EOF. The errno stuff is gone, EOF and 3442: * other errors now return different results, although Kermit currently never 3443: * checks to see which it was. It just disconnects in both cases. 3444: * 3445: * Kermit lets the user use the quit key to perform some special commands 3446: * during file transfer. This causes read(), and thus also mygetbuf(), to 3447: * finish without reading anything and return the EINTR error. This should 3448: * be checked by the caller. Mygetbuf() could retry the read() on EINTR, 3449: * but if there is nothing to read, this could delay Kermit's reaction to 3450: * the command, and make Kermit appear unresponsive. 3451: * 3452: * The debug() call should be removed for optimum performance. 3453: */ 3454: int 3455: mygetbuf() { 3456: my_count = myfillbuf(); 3457: debug(F101, "myfillbuf read", "", my_count); 3458: if (my_count <= 0) 3459: return(my_count < 0 ? -3 : -2); 3460: --my_count; 3461: return(255 & (int)mybuf[my_item = 0]); 3462: } 3463: 3464: /* myfillbuf(): 3465: * System-dependent read() into mybuf[], as many characters as possible. 3466: * 3467: * Returns: OK => number of characters read, always more than zero. 3468: * EOF => 0 3469: * Error => -1, error code in errno. 3470: * 3471: * If there is input available in the system's buffers, all of it should be 3472: * read into mybuf[] and the function return immediately. If no input is 3473: * available, it should wait for a character to arrive, and return with that 3474: * one in mybuf[] as soon as possible. It may wait somewhat past the first 3475: * character, but be aware that any such delay lengthens the packet turnaround 3476: * time during kermit file transfers. Should never return with zero characters 3477: * unless EOF or irrecoverable read error. 3478: * 3479: * Correct functioning depends on the correct tty parameters being used. 3480: * Better control of current parameters is required than may have been the 3481: * case in older Kermit releases. For instance, O_NDELAY (or equivalent) can 3482: * no longer be sometimes off and sometimes on like it used to, unless a 3483: * special myfillbuf() is written to handle that. Otherwise the ordinary 3484: * myfillbuf()s may think they have come to EOF. 3485: * 3486: * If your system has a facility to directly perform the functioning of 3487: * myfillbuf(), then use it. If the system can tell you how many characters 3488: * are available in its buffers, then read that amount (but not less than 1). 3489: * If the system can return a special indication when you try to read without 3490: * anything to read, while allowing you to read all there is when there is 3491: * something, you may loop until there is something to read, but probably that 3492: * is not good for the system load. 3493: */ 3494: 3495: #ifdef SVORPOSIX 3496: /* This is for System III/V with VMIN>0, VTIME=0 and O_NDELAY off, 3497: * and CLOCAL set any way you like. This way, read() will do exactly 3498: * what is required by myfillbuf(): If there is data in the buffers 3499: * of the O.S., all available data is read into mybuf, up to the size 3500: * of mybuf. If there is none, the first character to arrive is 3501: * awaited and returned. 3502: */ 3503: int 3504: myfillbuf() { 3505: #ifdef sxaE50 3506: /* From S. Dezawa at Fujifilm in Japan. I don't know why this is */ 3507: /* necessary for the sxa E50, but it is. */ 3508: return read(ttyfd, mybuf, 255); 3509: #else 3510: /* sizeof(mybuf) should be MYBUFL == 256 */ 3511: return read(ttyfd, mybuf, sizeof(mybuf)); 3512: #endif /* sxaE50 */ 3513: } 3514: 3515: #else /* not AT&T or POSIX */ 3516: 3517: #ifdef aegis 3518: /* This is quoted from the old myread(). The semantics seem to be 3519: * alright, but maybe errno would not need to be set even when 3520: * there is no error? I don't know aegis. 3521: */ 3522: int 3523: myfillbuf() { 3524: int count; 3525: 3526: count = ios_$get((short)ttyfd, ios_$cond_opt, mybuf, 256L, st); 3527: errno = EIO; 3528: if (st.all == ios_$get_conditional_failed) /* get at least one */ 3529: inbufc = ios_$get((short)ttyfd, 0, mybuf, 1L, st); 3530: if (st.all == ios_$end_of_file) 3531: return(0); 3532: else if (st.all != status_$ok) { 3533: errno = EIO; 3534: return(-1); 3535: } 3536: return(count); 3537: } 3538: #else /* !aegis */ 3539: 3540: #ifdef FIONREAD 3541: /* This is for systems with FIONREAD. FIONREAD returns the number 3542: * of characters available for reading. If none are available, wait 3543: * until something arrives, otherwise return all there is. 3544: */ 3545: int 3546: myfillbuf() { 3547: PEEKTYPE avail; 3548: int x; 3549: 3550: #ifdef SUNX25 3551: /* 3552: SunLink X.25 support in this routine from Stefaan A. Eeckels, Eurostat (CEC). 3553: Depends on SunOS having FIONREAD, not because we use it, but just so this 3554: code is grouped correctly within the #ifdefs. Let's hope Solaris keeps it. 3555: 3556: We call x25xin() instead of read() so that Q-Bit packets, which contain 3557: X.25 service-level information (e.g. PAD parameter changes), can be processed 3558: transparently to the upper-level code. This is a blocking read, and so 3559: we depend on higher-level code (such as ttinc()) to set any necessary alarms. 3560: */ 3561: extern int nettype; 3562: if (netconn && nettype == NET_SX25) { 3563: while ((x = x25xin(sizeof(x25buf), x25buf)) < 1) ; 3564: return(x - 1); /* "-1" compensates for extra status byte */ 3565: } 3566: #endif /* SUNX25 */ 3567: 3568: x = ioctl(ttyfd, FIONREAD, &avail); 3569: if (x < 0) { 3570: debug(F101,"myfillbuf FIONREAD","",x); 3571: debug(F101,"myfillbuf errno","",errno); 3572: } 3573: if (x < 0 || avail == 0) 3574: avail = 1; 3575: 3576: if (avail > MYBUFLEN) 3577: avail = MYBUFLEN; 3578: 3579: return(read(ttyfd, mybuf, (int) avail)); 3580: } 3581: 3582: #else /* !FIONREAD */ 3583: /* Add other systems here, between #ifdef and #else, e.g. NETCONN. */ 3584: /* When there is no other possibility, read 1 character at a time. */ 3585: int 3586: myfillbuf() { 3587: return read(ttyfd, mybuf, 1); 3588: } 3589: 3590: #endif /* !FIONREAD */ 3591: #endif /* !aegis */ 3592: #endif /* !ATTSV */ 3593: 3594: #endif /* MYREAD */ 3595: 3596: /* T T F L U I -- Flush tty input buffer */ 3597: 3598: int 3599: ttflui() { 3600: #ifdef BSD44 3601: int n; 3602: #endif /* BSD44 */ 3603: #ifndef SVORPOSIX 3604: int n; 3605: #endif /* SVORPOSIX */ 3606: 3607: #ifdef MYREAD 3608: /* 3609: Flush internal MYREAD buffer *FIRST*, in all cases. 3610: */ 3611: my_count = 0; /* Reset count to zero */ 3612: my_item = -1; /* And buffer index to -1 */ 3613: #endif /* MYREAD */ 3614: 3615: #ifdef NETCONN 3616: /* 3617: Network flush is done specially, in the network support module. 3618: */ 3619: if (netconn) return(netflui()); 3620: #endif /* NETCONN */ 3621: 3622: debug(F101,"ttflui ttyfd","",ttyfd); 3623: if (ttyfd < 0) return(-1); 3624: 3625: #ifdef aegis 3626: sio_$control((short)ttyfd, sio_$flush_in, true, st); 3627: if (st.all != status_$ok) { 3628: fprintf(stderr, "flush failed: "); error_$print(st); 3629: } else { /* sometimes the flush doesn't work */ 3630: for (;;) { 3631: char buf[256]; 3632: /* eat all the characters that shouldn't be available */ 3633: ios_$get((short)ttyfd, ios_$cond_opt, buf, 256L, st); /* (void) */ 3634: if (st.all == ios_$get_conditional_failed) break; 3635: fprintf(stderr, "flush failed(2): "); error_$print(st); 3636: } 3637: } 3638: #else 3639: #ifdef BSD44 /* 4.4 BSD */ 3640: n = FREAD; /* Specify read queue */ 3641: debug(F101,"ttflui BSD44 flush","",ttyfd); 3642: ioctl(ttyfd,TIOCFLUSH,&n); 3643: ioctl(ttyfd,TCSAFLUSH,&n); 3644: #else 3645: #ifdef POSIX /* POSIX */ 3646: tcflush(ttyfd,TCIFLUSH); 3647: #else 3648: #ifdef ATTSV /* System V */ 3649: #ifndef VXVE 3650: ioctl(ttyfd,TCFLSH,0); 3651: #endif /* VXVE */ 3652: #else /* Not BSD44, POSIX, or Sys V */ 3653: #ifdef TIOCFLUSH /* Those with TIOCFLUSH defined */ 3654: #ifdef ANYBSD /* Berkeley */ 3655: n = FREAD; /* Specify read queue */ 3656: debug(F101,"ttflui anybsd flush","",ttyfd); 3657: ioctl(ttyfd,TIOCFLUSH,&n); 3658: #else /* Others (V7, etc) */ 3659: ioctl(ttyfd,TIOCFLUSH,0); 3660: #endif /* ANYBSD */ 3661: #else /* All others... */ 3662: /* 3663: No system call (that we know about) for input buffer flushing. 3664: So see how many there are and read them in a loop, using ttinc(). 3665: ttinc() is buffered, so we're not getting charged with a system call 3666: per character, just a function call. 3667: */ 3668: if ((n = ttchk()) > 0) { 3669: debug(F101,"ttflui reading","",n); 3670: while ((n--) && ttinc(0) > 1) ; 3671: } 3672: #endif /* TIOCFLUSH */ 3673: #endif /* ATTSV */ 3674: #endif /* POSIX */ 3675: #endif /* BSD44 */ 3676: #endif /* aegis */ 3677: return(0); 3678: } 3679: 3680: int 3681: ttfluo() { /* Flush output buffer */ 3682: #ifdef POSIX 3683: return(tcflush(ttyfd,TCOFLUSH)); 3684: #else 3685: return(0); /* (dummy for now) */ 3686: #endif /* POSIX */ 3687: 3688: } 3689: 3690: /* Interrupt Functions */ 3691: 3692: /* Set up terminal interrupts on console terminal */ 3693: 3694: #ifdef SVORPOSIX 3695: SIGTYP 3696: esctrp(foo) int foo; { /* trap console escapes (^\) */ 3697: signal(SIGQUIT,SIG_IGN); /* ignore until trapped */ 3698: conesc = 1; 3699: debug(F101,"esctrp caught SIGQUIT","",conesc); 3700: } 3701: #endif /* SVORPOSIX */ 3702: 3703: #ifdef V7 3704: SIGTYP 3705: esctrp(foo) int foo; { /* trap console escapes (^\) */ 3706: signal(SIGQUIT,SIG_IGN); /* ignore until trapped */ 3707: conesc = 1; 3708: debug(F101,"esctrp caught SIGQUIT","",conesc); 3709: } 3710: #endif 3711: 3712: #ifdef C70 3713: SIGTYP 3714: esctrp(foo) int foo; { /* trap console escapes (^\) */ 3715: conesc = 1; 3716: signal(SIGQUIT,SIG_IGN); /* ignore until trapped */ 3717: } 3718: #endif 3719: 3720: /* C O N B G T -- Background Test */ 3721: 3722: static int jc = 0; /* 0 = no job control */ 3723: 3724: /* 3725: Call with flag == 1 to prevent signal test, which can not be expected 3726: to work during file transfer, when SIGINT probably *is* set to SIG_IGN. 3727: 3728: Call with flag == 0 to use the signal test, but only if the process-group 3729: test fails, as it does on some UNIX systems, where getpgrp() is buggy, 3730: requires an argument when the man page says it doesn't, or vice versa. 3731: 3732: If flag == 0 and the process-group test fails, then we determine background 3733: status simply (but not necessarily reliably) from isatty(). 3734: 3735: conbgt() sets the global backgrd = 1 if we appear to be in the background, 3736: and to 0 if we seem to be in the foreground. conbgt() is highly prone to 3737: misbehavior. 3738: */ 3739: VOID 3740: conbgt(flag) int flag; { 3741: int x = -1, /* process group or SIGINT test */ 3742: y = 0; /* isatty() test */ 3743: /* 3744: Check for background operation, even if not running on real tty, so that 3745: background flag can be set correctly. If background status is detected, 3746: then Kermit will not issue its interactive prompt or most messages. 3747: If your prompt goes away, you can blame (and fix?) this function. 3748: */ 3749: 3750: /* Use process-group test if possible. */ 3751: 3752: #ifdef POSIX /* We can do it in POSIX */ 3753: #define PGROUP_T 3754: #else 3755: #ifdef BSD4 /* and in BSD 4.x. */ 3756: #define PGROUP_T 3757: #else 3758: #ifdef HPUXJOBCTL /* and in most HP-UX's */ 3759: #define PGROUP_T 3760: #else 3761: #ifdef TIOCGPGRP /* and anyplace that has this ioctl. */ 3762: #define PGROUP_T 3763: #endif /* TIOCGPGRP */ 3764: #endif /* HPUXJOBCTL */ 3765: #endif /* BSD4 */ 3766: #endif /* POSIX */ 3767: 3768: #ifdef MIPS /* Except if it doesn't work... */ 3769: #undef PGROUP_T 3770: #endif /* MIPS */ 3771: 3772: #ifdef PGROUP_T 3773: /* 3774: Semi-reliable process-group test. Check whether this process's group is 3775: the same as the controlling terminal's process group. This works if the 3776: getpgrp() call doesn't lie (as it does in the SUNOS System V environment). 3777: */ 3778: PID_T mypgrp = (PID_T)0; /* Kermit's process group */ 3779: PID_T ctpgrp = (PID_T)0; /* The terminal's process group */ 3780: #ifndef _POSIX_SOURCE 3781: /* 3782: The getpgrp() prototype is obtained from system header files for POSIX 3783: and Sys V R4 compilations. Other systems, who knows. Some complain about 3784: a duplicate declaration here, others don't, so it's safer to leave it in 3785: if we don't know for certain. 3786: */ 3787: #ifndef SVR4 3788: #ifndef PS2AIX10 3789: extern PID_T getpgrp(); 3790: #endif /* PS2AIX10 */ 3791: #endif /* SVR4 */ 3792: #endif /* _POSIX_SOURCE */ 3793: 3794: /* Get my process group. */ 3795: 3796: #ifdef SVR3 /* Maybe this should be ATTSV? */ 3797: /* This function is not described in SVID R2 */ 3798: mypgrp = getpgrp(); 3799: debug(F101,"ATTSV conbgt process group","",(int) mypgrp); 3800: #else 3801: #ifdef POSIX 3802: mypgrp = getpgrp(); 3803: debug(F101,"POSIX conbgt process group","",(int) mypgrp); 3804: #else /* BSD, V7, etc */ 3805: mypgrp = getpgrp(0); 3806: debug(F101,"BSD conbgt process group","",(int) mypgrp); 3807: #endif /* POSIX */ 3808: #endif /* SVR3 */ 3809: 3810: /* Now get controlling tty's process group */ 3811: #ifdef BSD44ORPOSIX 3812: ctpgrp = tcgetpgrp(1); /* The POSIX way */ 3813: debug(F101,"POSIX conbgt terminal process group","",(int) ctpgrp); 3814: #else 3815: ioctl(1, TIOCGPGRP, &ctpgrp); /* Or the BSD way */ 3816: debug(F101,"non-POSIX conbgt terminal process group","",(int) ctpgrp); 3817: #endif /* BSD44ORPOSIX */ 3818: 3819: if ((mypgrp > (PID_T) 0) && (ctpgrp > (PID_T) 0)) 3820: x = (mypgrp == ctpgrp) ? 0 : 1; /* If they differ, then background. */ 3821: else x = -1; /* If error, remember. */ 3822: debug(F101,"conbgt process group test","",x); 3823: #endif /* PGROUP_T */ 3824: 3825: /* Try to see if job control is available */ 3826: 3827: #ifdef NOJC /* User override */ 3828: jc = 0; /* No job control allowed */ 3829: debug(F111,"NOJC","jc",jc); 3830: #else 3831: #ifdef BSD44 3832: jc = 1; 3833: #else 3834: #ifdef SVR4ORPOSIX /* POSIX actually tells us */ 3835: debug(F100,"SVR4ORPOSIX jc test...","",0); 3836: #ifdef _SC_JOB_CONTROL 3837: #ifdef bsdi 3838: jc = 1; 3839: #else 3840: #ifdef __386BSD__ 3841: jc = 1; 3842: #else 3843: jc = sysconf(_SC_JOB_CONTROL); /* Whatever system says */ 3844: debug(F111,"sysconf(_SC_JOB_CONTROL)","jc",jc); 3845: #endif /* __386BSD__ */ 3846: #endif /* bsdi */ 3847: #else 3848: #ifdef _POSIX_JOB_CONTROL 3849: jc = 1; /* By definition */ 3850: debug(F111,"_POSIX_JOB_CONTROL is defined","jc",jc); 3851: #else 3852: jc = 0; /* Assume job control not allowed */ 3853: debug(F111,"SVR4ORPOSIX _SC/POSIX_JOB_CONTROL not defined","jc",jc); 3854: #endif /* _POSIX_JOB_CONTROL */ 3855: #endif /* _SC_JOB_CONTROL */ 3856: #else 3857: #ifdef BSD4 3858: jc = 1; /* Job control allowed */ 3859: debug(F111,"BSD job control","jc",jc); 3860: #else 3861: #ifdef SVR3JC 3862: jc = 1; /* JC allowed */ 3863: debug(F111,"SVR3 job control","jc",jc); 3864: #else 3865: jc = 0; /* JC not allowed */ 3866: debug(F111,"job control catch-all","jc",jc); 3867: #endif /* SVR3JC */ 3868: #endif /* BSD4 */ 3869: #endif /* SVR4ORPOSIX */ 3870: #endif /* BSD44 */ 3871: #endif /* NOJC */ 3872: debug(F101,"conbgt jc","",jc); 3873: 3874: /* 3875: Another background test. 3876: Test if SIGINT (terminal interrupt) is set to SIG_IGN (ignore), 3877: which is done by the shell (sh) if the program is started with '&'. 3878: Unfortunately, this is NOT done by csh or ksh so watch out! 3879: Note, it's safe to set SIGINT to SIG_IGN here, because further down 3880: we always set it to something else. 3881: */ 3882: if (x < 0 && !flag) { /* Didn't get good results above... */ 3883: 3884: SIGTYP (*osigint)(); 3885: 3886: osigint = signal(SIGINT,SIG_IGN); /* What is SIGINT set to? */ 3887: x = (osigint == SIG_IGN) ? 1 : 0; /* SIG_IGN? */ 3888: debug(F101,"conbgt osigint","",(int) osigint); 3889: debug(F101,"conbgt signal test","",x); 3890: } 3891: 3892: /* Also check to see if we're running with redirected stdio. */ 3893: /* This is not really background operation, but we want to act as though */ 3894: /* it were. */ 3895: 3896: y = (isatty(0) && isatty(1)) ? 1 : 0; 3897: debug(F101,"conbgt isatty test","",y); 3898: 3899: #ifdef BSD29 3900: /* The process group and/or signal test doesn't work under these... */ 3901: backgrd = !y; 3902: #else 3903: #ifdef sxaE50 3904: backgrd = !y; 3905: #else 3906: #ifdef MINIX 3907: backgrd = !y; 3908: #else 3909: if (x > -1) 3910: backgrd = (x || !y) ? 1 : 0; 3911: else backgrd = !y; 3912: #endif /* BSD29 */ 3913: #endif /* sxaE50 */ 3914: #endif /* MINIX */ 3915: debug(F101,"conbgt backgrd","",backgrd); 3916: } 3917: 3918: /* C O N I N T -- Console Interrupt setter */ 3919: 3920: /* 3921: First arg is pointer to function to handle SIGTERM & SIGINT (like Ctrl-C). 3922: Second arg is pointer to function to handle SIGTSTP (suspend). 3923: */ 3924: 3925: VOID /* Set terminal interrupt traps. */ 3926: #ifdef CK_ANSIC 3927: #ifdef apollo 3928: conint(f,s) SIGTYP (*f)(), (*s)(); 3929: #else 3930: conint(SIGTYP (*f)(int), SIGTYP (*s)(int)) 3931: #endif /* apollo */ 3932: #else 3933: conint(f,s) SIGTYP (*f)(), (*s)(); 3934: #endif /* CK_ANSIC */ 3935: /* conint */ { 3936: 3937: conbgt(0); /* Do background test. */ 3938: 3939: /* Set the desired handlers for hangup and software termination. */ 3940: 3941: signal(SIGTERM,f); /* Software termination */ 3942: 3943: #ifdef COMMENT 3944: /* 3945: Prior to edit 184, we used to trap SIGHUP here. That is clearly wrong; 3946: on some systems, it would leave the user's process on the terminal after 3947: the phone hung up. But the trap was here for a reason: most likely some 3948: UNIX systems (init, getty, or login) fail to properly restore the terminal 3949: modes after regaining control of a hung-up-upon login terminal. Therefore 3950: removing this trap is likely to cause problems too. A more sensible 3951: approach would be to use a special handler for HANGUP, which would restore 3952: the terminal modes and then exit(). But that could leave zombie processes 3953: around (like the lower CONNECT fork, or any fork started by zxcmd()), but 3954: there is probably no clean, portable, reliable way for Kermit to kill all 3955: its forks. So we just exit() and hope that UNIX fixes the terminal modes 3956: before the next person tries to log in. 3957: */ 3958: signal(SIGHUP,f); /* Hangup */ 3959: #endif /* COMMENT */ 3960: 3961: /* Now handle keyboard stop, quit, and interrupt signals. */ 3962: /* Check if invoked in background -- if so signals set to be ignored. */ 3963: /* However, if running under a job control shell, don't ignore them. */ 3964: /* We won't be getting any, as we aren't in the terminal's process group. */ 3965: 3966: debug(F101,"conint backgrd","",backgrd); 3967: debug(F101,"conint jc","",jc); 3968: 3969: if (backgrd && !jc) { /* In background, ignore signals */ 3970: debug(F101,"conint background ignoring signals, jc","",jc); 3971: #ifdef SIGTSTP 3972: signal(SIGTSTP,SIG_IGN); /* Keyboard stop */ 3973: #endif /* SIGTSTP */ 3974: signal(SIGQUIT,SIG_IGN); /* Keyboard quit */ 3975: signal(SIGINT,SIG_IGN); /* Keyboard interrupt */ 3976: } else { /* Else in foreground or suspended */ 3977: debug(F101,"conint foreground catching signals, jc","",jc); 3978: signal(SIGINT,f); /* Catch terminal interrupt */ 3979: 3980: #ifdef SIGTSTP /* Keyboard stop (suspend) */ 3981: debug(F101,"conint SIGSTSTP","",(int) s); 3982: if (s == NULL) s = SIG_DFL; 3983: #ifdef NOJC /* No job control allowed. */ 3984: signal(SIGTSTP,SIG_IGN); 3985: #else /* Job control allowed */ 3986: if (jc) /* if available. */ 3987: signal(SIGTSTP,s); 3988: else 3989: signal(SIGTSTP,SIG_IGN); 3990: #endif /* NOJC */ 3991: #endif /* SIGTSTP */ 3992: 3993: #ifdef SVORPOSIX 3994: signal(SIGQUIT,esctrp); /* Quit signal, Sys III/V. */ 3995: if (conesc) conesc = 0; /* Clear out pending escapes */ 3996: #else 3997: #ifdef V7 3998: signal(SIGQUIT,esctrp); /* V7 like Sys III/V */ 3999: if (conesc) conesc = 0; 4000: #else 4001: #ifdef aegis 4002: signal(SIGQUIT,f); /* Apollo, catch it like others. */ 4003: #else 4004: signal(SIGQUIT,SIG_IGN); /* Others, ignore like 4D & earlier. */ 4005: #endif /* aegis */ 4006: #endif /* V7 */ 4007: #endif /* SVORPOSIX */ 4008: } 4009: } 4010: 4011: 4012: /* C O N N O I -- Reset console terminal interrupts */ 4013: 4014: SIGTYP /* Dummy function to ignore signals */ 4015: #ifdef CK_ANSIC 4016: sig_ign(int foo) 4017: #else 4018: sig_ign(foo) int foo; 4019: #endif /* CK_ANSIC */ 4020: /* sig_IGN */ { /* Just like the real one, but has */ 4021: } /* different address. */ 4022: 4023: VOID 4024: connoi() { /* Console-no-interrupts */ 4025: 4026: debug(F100,"connoi","",0); 4027: #ifdef SIGTSTP 4028: signal(SIGTSTP,SIG_DFL); 4029: #endif /* SIGTSTP */ 4030: /* Note the locally defined replacement for SIG_IGN that is used here */ 4031: /* for the SIGINT setting. This is done so that the Sys V background */ 4032: /* test -- (signal(SIGINT,SIG_IGN) == SIG_IGN) -- can work. If we use */ 4033: /* the real SIG_IGN here, then conint will always decide that this */ 4034: /* program is running in the background! */ 4035: 4036: signal(SIGINT,sig_ign); /* <--- note! */ 4037: 4038: signal(SIGHUP,SIG_DFL); 4039: signal(SIGQUIT,SIG_IGN); 4040: signal(SIGTERM,SIG_IGN); 4041: } 4042: 4043: /* I N I T R A W Q -- Set up to read /dev/kmem for character count. */ 4044: 4045: #ifdef V7 4046: /* 4047: Used in Version 7 to simulate Berkeley's FIONREAD ioctl call. This 4048: eliminates blocking on a read, because we can read /dev/kmem to get the 4049: number of characters available for raw input. If your system can't 4050: or you won't let the world read /dev/kmem then you must figure out a 4051: different way to do the counting of characters available, or else replace 4052: this by a dummy function that always returns 0. 4053: */ 4054: /* 4055: * Call this routine as: initrawq(tty) 4056: * where tty is the file descriptor of a terminal. It will return 4057: * (as a char *) the kernel-mode memory address of the rawq character 4058: * count, which may then be read. It has the side-effect of flushing 4059: * input on the terminal. 4060: */ 4061: /* 4062: * John Mackin, Physiology Dept., University of Sydney (Australia) 4063: * ...!decvax!mulga!physiol.su.oz!john 4064: * 4065: * Permission is hereby granted to do anything with this code, as 4066: * long as this comment is retained unmodified and no commercial 4067: * advantage is gained. 4068: */ 4069: #ifndef MINIX 4070: #ifndef COHERENT 4071: #include <a.out.h> 4072: #include <sys/proc.h> 4073: #endif /* COHERENT */ 4074: #endif /* MINIX */ 4075: 4076: #ifdef COHERENT 4077: #include <l.out.h> 4078: #include <sys/proc.h> 4079: #endif /* COHERENT */ 4080: 4081: char * 4082: initrawq(tty) int tty; { 4083: #ifdef MINIX 4084: return(0); 4085: #else 4086: #ifdef UTS24 4087: return(0); 4088: #else 4089: #ifdef BSD29 4090: return(0); 4091: #else 4092: long lseek(); 4093: static struct nlist nl[] = { 4094: {PROCNAME}, 4095: {NPROCNAME}, 4096: {""} 4097: }; 4098: static struct proc *pp; 4099: char *qaddr, *p, c; 4100: int m; 4101: PID_T pid, me; 4102: NPTYPE xproc; /* Its type is defined in makefile. */ 4103: int catch(); 4104: 4105: me = getpid(); 4106: if ((m = open("/dev/kmem", 0)) < 0) err("kmem"); 4107: nlist(BOOTNAME, nl); 4108: if (nl[0].n_type == 0) err("proc array"); 4109: 4110: if (nl[1].n_type == 0) err("nproc"); 4111: 4112: lseek(m, (long)(nl[1].n_value), 0); 4113: read (m, &xproc, sizeof(xproc)); 4114: saval = signal(SIGALRM, catch); 4115: if ((pid = fork()) == 0) { 4116: while(1) 4117: read(tty, &c, 1); 4118: } 4119: alarm(2); 4120: 4121: if(setjmp(jjbuf) == 0) { 4122: while(1) 4123: read(tty, &c, 1); 4124: } 4125: signal(SIGALRM, SIG_DFL); 4126: 4127: #ifdef DIRECT 4128: pp = (struct proc *) nl[0].n_value; 4129: #else 4130: if (lseek(m, (long)(nl[0].n_value), 0) < 0L) err("seek"); 4131: if (read(m, &pp, sizeof(pp)) != sizeof(pp)) err("no read of proc ptr"); 4132: #endif 4133: lseek(m, (long)(nl[1].n_value), 0); 4134: read(m, &xproc, sizeof(xproc)); 4135: 4136: if (lseek(m, (long)pp, 0) < 0L) err("Can't seek to proc"); 4137: if ((p = malloc(xproc * sizeof(struct proc))) == NULL) err("malloc"); 4138: if (read(m,p,xproc * sizeof(struct proc)) != xproc*sizeof(struct proc)) 4139: err("read proc table"); 4140: for (pp = (struct proc *)p; xproc > 0; --xproc, ++pp) { 4141: if (pp -> p_pid == (short) pid) goto iout; 4142: } 4143: err("no such proc"); 4144: 4145: iout: 4146: close(m); 4147: qaddr = (char *)(pp -> p_wchan); 4148: free (p); 4149: kill(pid, SIGKILL); 4150: wait((WAIT_T)0); /* Destroy the ZOMBIEs! */ 4151: return (qaddr); 4152: #endif 4153: #endif 4154: #endif 4155: } 4156: 4157: /* More V7-support functions... */ 4158: 4159: static VOID 4160: err(s) char *s; { 4161: char buf[200]; 4162: 4163: sprintf(buf, "fatal error in initrawq: %s", s); 4164: perror(buf); 4165: doexit(1,-1); 4166: } 4167: 4168: static VOID 4169: catch(foo) int foo; { 4170: longjmp(jjbuf, -1); 4171: } 4172: 4173: 4174: /* G E N B R K -- Simulate a modem break. */ 4175: 4176: #ifdef MINIX 4177: #define BSPEED B110 4178: #else 4179: #define BSPEED B150 4180: #endif /* MINIX */ 4181: 4182: VOID 4183: genbrk(fn,msec) int fn, msec; { 4184: struct sgttyb ttbuf; 4185: int ret, sospeed, x, y; 4186: 4187: ret = ioctl(fn, TIOCGETP, &ttbuf); 4188: sospeed = ttbuf.sg_ospeed; 4189: ttbuf.sg_ospeed = BSPEED; 4190: ret = ioctl(fn, TIOCSETP, &ttbuf); 4191: y = (int)strlen(brnuls); 4192: x = ( BSPEED * 100 ) / msec; 4193: if (x > y) x = y; 4194: ret = write(fn, brnuls, (( BSPEED * 100 ) / msec )); 4195: ttbuf.sg_ospeed = sospeed; 4196: ret = ioctl(fn, TIOCSETP, &ttbuf); 4197: ret = write(fn, "@", 1); 4198: return; 4199: } 4200: #endif /* V7 */ 4201: 4202: /* T T C H K -- Tell how many characters are waiting in tty input buffer */ 4203: 4204: /* Some callers of this want to know whether there is something to read 4205: * either in the system buffers or in our private buffers (and mostly don't 4206: * care how many characters, just whether it's more than zero or not), while 4207: * some others would be better off with the number of characters in our 4208: * private buffers only. 4209: * 4210: * Some systems can say how many characters there are in the system buffers. 4211: * Others can not. For those that can't, the number in the private buffers 4212: * will have to do (or should we put the tty into O_NDELAY-mode and try to 4213: * read one character?). If the system can tell whether there is zero or 4214: * more than zero characters, we can return 1 in the latter case even if the 4215: * private buffer is empty. (That is good for sliding windows.) 4216: */ 4217: int 4218: ttchk() { 4219: int x; 4220: PEEKTYPE n = 0; 4221: 4222: #ifdef COMMENT 4223: /* 4224: This was REALLY slowing TELNET connections down! Just do the regular 4225: ttyfd-based stuff here. Let the VMS version call nettchk if it has to... 4226: FIONREAD definitely works for TELNET, at least on the NeXT and SUNOS. 4227: */ 4228: #ifdef NETCONN 4229: if (netconn) return(nettchk()); 4230: #endif /* NETCONN */ 4231: #endif /* COMMENT */ 4232: 4233: #ifdef FIONREAD 4234: x = ioctl(ttyfd, FIONREAD, &n); /* Berkeley and maybe some others */ 4235: debug(F101,"ttchk FIONREAD return code","",x); 4236: debug(F101,"ttchk FIONREAD count","",n); 4237: if (x < 0) n = 0; 4238: #else 4239: #ifdef V7 4240: #ifdef MINIX 4241: return(0); 4242: #else 4243: lseek(kmem[TTY], (long) qaddr[TTY], 0); /* 7th Edition Unix */ 4244: x = read(kmem[TTY], &n, sizeof(int)); 4245: if (x != sizeof(int)) n = 0; 4246: #endif /* MINIX */ 4247: #else 4248: #ifdef PROVX1 4249: x = ioctl(ttyfd, TIOCQCNT, &ttbuf); /* Pro/3xx Venix V.1 */ 4250: n = ttbuf.sg_ispeed & 0377; 4251: if (x < 0) n = 0; 4252: #else 4253: #ifdef RDCHK 4254: /* 4255: Last resort for systems without FIONREAD or equivalent, but with 4256: something like rdchk(), like XENIX. 4257: */ 4258: if (my_count == 0 && rdchk(ttyfd) > 0) n = 1; 4259: debug(F101,"ttchk rdchk","",n); 4260: #endif /* RDCHK */ 4261: #endif /* PROVX1 */ 4262: #endif /* V7 */ 4263: #endif /* FIONREAD */ 4264: 4265: #ifdef MYREAD 4266: /* 4267: For myread() users, add the contents of myread()'s private buffer. 4268: Sometimes, this is all there is to construct a result of ttchk() on. 4269: */ 4270: if (my_count > 0) 4271: n += my_count; 4272: #endif /* MYREAD */ 4273: 4274: debug(F101,"ttchk returns","",n); 4275: return(n); 4276: } 4277: 4278: /* T T X I N -- Get n characters from tty input buffer */ 4279: 4280: /* Returns number of characters actually gotten, or -1 on failure */ 4281: 4282: /* Intended for use only when it is known that n characters are actually */ 4283: /* Available in the input buffer. */ 4284: 4285: int 4286: ttxin(n,buf) int n; CHAR *buf; { 4287: register int x, c; 4288: 4289: debug(F101,"ttxin n","",n); 4290: if (n < 1) return(0); 4291: ttpmsk = (ttprty) ? 0177 : 0377; /* Parity stripping mask. */ 4292: 4293: #ifdef SUNX25 4294: if (netconn && (ttnet == NET_SX25)) /* X.25 connection */ 4295: return(x25xin(n,buf)); 4296: #endif /* SUNX25 */ 4297: 4298: #ifdef MYREAD 4299: debug(F101,"ttxin MYREAD","",0); 4300: c = -2; 4301: for( x = 0; (x > -1) && (x < n) && (c = myread()) >= 0; ) 4302: buf[x++] = c & ttpmsk; 4303: if (c < 0) { 4304: debug(F101,"ttxin myread returns","",c); 4305: if (c == -3) x = -1; 4306: } 4307: #else 4308: x = read(ttyfd,buf,n); 4309: for (c = 0; c < n; c++) buf[c] &= ttpmsk; 4310: debug(F101," x","",x); 4311: #endif /* MYREAD */ 4312: if (x > 0) buf[x] = '\0'; 4313: if (x < 0) x = -1; 4314: return(x); 4315: } 4316: 4317: /* T T O L -- Write string s, length n, to communication device. */ 4318: /* 4319: Returns: 4320: >= 0 on success, number of characters actually written. 4321: -1 on failure. 4322: */ 4323: #define TTOLMAXT 5 4324: int 4325: ttol(s,n) int n; CHAR *s; { 4326: int x, len, tries; 4327: 4328: if (ttyfd < 0) return(-1); /* Not open? */ 4329: debug(F101,"ttol n","",n); 4330: tries = TTOLMAXT; /* Allow up to this many tries */ 4331: len = n; /* Remember original length */ 4332: 4333: while (n > 0 && tries-- > 0) { /* Be persistent */ 4334: debug(F101,"ttol try","",TTOLMAXT - tries); 4335: x = write(ttyfd,s,n); /* Write string to device */ 4336: if (x == n) { /* Worked? */ 4337: debug(F101,"ttol ok","",x); /* OK */ 4338: return(len); /* Done */ 4339: } else if (x < 0) { /* No, got error? */ 4340: debug(F101,"ttol failed","",errno); 4341: return(-1); 4342: } else { /* No error, so partial success */ 4343: debug(F101,"ttol partial","",x); 4344: s += x; /* Point to part not written yet */ 4345: n -= x; /* Adjust length */ 4346: if (x > 0) msleep(100); /* Wait 100 msec */ 4347: } /* Go back and try again */ 4348: } 4349: return(n < 1 ? len : -1); /* Too many tries */ 4350: } 4351: 4352: 4353: 4354: /* T T O C -- Output a character to the communication line */ 4355: 4356: /* 4357: This function should only be used for interactive, character-mode operations, 4358: like terminal connection, script execution, dialer i/o, where the overhead 4359: of the signals and alarms does not create a bottleneck. 4360: */ 4361: int 4362: #ifdef CK_ANSIC 4363: ttoc(char c) 4364: #else 4365: ttoc(c) char c; 4366: #endif /* CK_ANSIC */ 4367: /* ttoc */ { 4368: #define TTOC_TMO 15 /* Timeout in case we get stuck */ 4369: int xx; 4370: c &= 0xff; 4371: /* debug(F101,"ttoc","",(CHAR) c); */ 4372: if (ttyfd < 0) return(-1); /* Check for not open. */ 4373: saval = signal(SIGALRM,timerh); /* Enable timer interrupt */ 4374: xx = alarm(TTOC_TMO); /* for this many seconds. */ 4375: if (xx < 0) xx = 0; /* Save old alarm value. */ 4376: /* debug(F101,"ttoc alarm","",xx); */ 4377: if (setjmp(sjbuf)) { /* Timer went off? */ 4378: ttimoff(); /* Yes, cancel this alarm. */ 4379: if (xx - TTOC_TMO > 0) alarm(xx - TTOC_TMO); /* Restore previous one */ 4380: /* debug(F100,"ttoc timeout","",0); */ 4381: #ifdef NETCONN 4382: if (!netconn) { 4383: #endif /* NETCONN */ 4384: debug(F101,"ttoc timeout","",c); 4385: if (ttflow == FLO_XONX) { 4386: int x = 0, y; 4387: debug(F101,"ttoc flow","",ttflow); /* Maybe we're xoff'd */ 4388: #ifdef POSIX 4389: y = tcflow(ttyfd,TCOON); /* POSIX way to unstick. */ 4390: debug(F100,"ttoc tcflow","",y); 4391: #else 4392: #ifdef BSD4 /* Berkeley way to do it. */ 4393: #ifdef TIOCSTART 4394: /* .... Used to be "ioctl(ttyfd, TIOCSTART, 0);". Who knows? */ 4395: y = ioctl(ttyfd, TIOCSTART, &x); 4396: debug(F101,"ttoc TIOCSTART","",y); 4397: #endif /* TIOCSTART */ 4398: #endif /* BSD4 */ 4399: /* Is there a Sys V way to do this? */ 4400: #endif /* POSIX */ 4401: } 4402: #ifdef NETCONN 4403: } 4404: #endif /* NETCONN */ 4405: return(-1); /* Return failure code. */ 4406: } else { 4407: if (write(ttyfd,&c,1) < 1) { /* Try to write the character. */ 4408: ttimoff(); /* Failed, turn off the alarm. */ 4409: alarm(xx); /* Restore previous alarm. */ 4410: debug(F101,"ttoc error","",errno); /* Log the error, */ 4411: return(-1); /* and return the error code. */ 4412: } 4413: } 4414: ttimoff(); /* Success, turn off the alarm. */ 4415: alarm(xx); /* Restore previous alarm. */ 4416: return(0); /* Return good code. */ 4417: } 4418: 4419: /* T T I N L -- Read a record (up to break character) from comm line. */ 4420: /* 4421: Reads up to "max" characters from the communication line, terminating on: 4422: 4423: (a) the packet length field if the "turn" argument is zero, or 4424: (b) on the packet-end character (eol) if the "turn" argument is nonzero 4425: (c) two Ctrl-C's in a row 4426: 4427: and returns the number of characters read upon success, or if "max" was 4428: exceeded or the timeout interval expired before (a) or (b), returns -1. 4429: 4430: The characters that were input are copied into "dest" with their parity bits 4431: stripped if parity was selected. Returns the number of characters read. 4432: Characters after the eol are available upon the next call to this function. 4433: 4434: The idea is to minimize the number of system calls per packet, and also to 4435: minimize timeouts. This function is the inner loop of the program and must 4436: be as efficient as possible. The current strategy is to use myread(). 4437: 4438: WARNING: this function calls parchk(), which is defined in another module. 4439: Normally, ckutio.c does not depend on code from any other module, but there 4440: is an exception in this case because all the other ck?tio.c modules also 4441: need to call parchk(), so it's better to have it defined in a common place. 4442: 4443: Since this function has grown to have its fingers so deeply into the 4444: protocol, it is slated for removal: rpack() will take care of everything. 4445: */ 4446: #ifdef CTRLC 4447: #undef CTRLC 4448: #endif /* CTRLC */ 4449: #define CTRLC '\03' 4450: /* 4451: We have four different declarations here because: 4452: (a) to allow Kermit to be built without the automatic parity sensing feature 4453: (b) one of each type for ANSI C, one for non-ANSI. 4454: */ 4455: int 4456: #ifdef PARSENSE 4457: #ifdef CK_ANSIC 4458: ttinl(CHAR *dest, int max,int timo, CHAR eol, CHAR start, int turn) 4459: #else 4460: ttinl(dest,max,timo,eol,start,turn) int max,timo,turn; CHAR *dest, eol, start; 4461: #endif /* CK_ANSIC */ 4462: #else /* not PARSENSE */ 4463: #ifdef CK_ANSIC 4464: ttinl(CHAR *dest, int max,int timo, CHAR eol) 4465: #else 4466: ttinl(dest,max,timo,eol) int max,timo; CHAR *dest, eol; 4467: #endif /* __SDTC__ */ 4468: #endif /* PARSENSE */ 4469: /* ttinl */ { 4470: 4471: #ifndef MYREAD 4472: CHAR ch; 4473: #endif /* MYREAD */ 4474: #ifdef PARSENSE 4475: int pktlen = -1; 4476: int lplen = 0; 4477: int havelen = 0; 4478: #endif /* PARSENSE */ 4479: 4480: if (ttyfd < 0) return(-1); /* Not open. */ 4481: 4482: debug(F101,"ttinl max","",max); 4483: debug(F101,"ttinl timo","",timo); 4484: 4485: *dest = '\0'; /* Clear destination buffer */ 4486: if (timo < 0) timo = 0; /* Safety */ 4487: if (timo) { /* Don't time out if timo == 0 */ 4488: int xx; 4489: saval = signal(SIGALRM,timerh); /* Enable timer interrupt */ 4490: xx = alarm(timo); /* Set it. */ 4491: debug(F101,"ttinl alarm","",xx); 4492: } 4493: if (setjmp(sjbuf)) { /* Timer went off? */ 4494: debug(F100,"ttinl timout","",0); /* Get here on timeout. */ 4495: /* debug(F110," with",(char *) dest,0); */ 4496: ttimoff(); /* Turn off timer */ 4497: return(-1); /* and return error code. */ 4498: } else { 4499: register int i, m, n; /* local variables */ 4500: int ccn = 0; 4501: #ifdef PARSENSE 4502: int flag = 0; 4503: 4504: debug(F000,"ttinl start","",start); 4505: flag = 0; /* Start of packet flag */ 4506: #endif /* PARSENSE */ 4507: 4508: ttpmsk = m = (ttprty) ? 0177 : 0377; /* Set parity stripping mask. */ 4509: 4510: #ifdef COMMENT 4511: /* 4512: No longer needed. 4513: */ 4514: #ifdef SUNX25 4515: if (netconn && (ttnet == NET_SX25)) 4516: #ifdef PARSENSE 4517: return(x25inl(dest,max,timo,eol,start)); 4518: #else 4519: return(x25inl(dest,max,timo,eol)); 4520: #endif /* PARSENSE */ 4521: #endif /* SUNX25 */ 4522: #endif /* COMMENT */ 4523: 4524: /* Now read into destination, stripping parity and looking for the */ 4525: /* the packet terminator, and also for two Ctrl-C's typed in a row. */ 4526: 4527: i = 0; /* Destination index */ 4528: debug(F101,"ttinl eol","",eol); 4529: 4530: #ifdef MYREAD 4531: while (i < max-1) { 4532: /* debug(F101,"ttinl i","",i); */ 4533: if ((n = myread()) < 0) { 4534: debug(F101,"ttinl myread failure, n","",n); 4535: debug(F101,"ttinl myread errno,","",errno); 4536: /* Don't let EINTR break packets. */ 4537: if (n == -3 && errno == EINTR && i > 0) { 4538: debug(F101,"ttinl myread i","",i); 4539: continue; 4540: } 4541: break; 4542: } 4543: #else 4544: while ((i < max-1) && (n = read(ttyfd, &ch, 1)) > 0) { 4545: n = ch; 4546: #endif /* MYREAD */ 4547: 4548: /* debug(F101,"ttinl char","", (n & ttpmsk)); */ 4549: 4550: #ifdef PARSENSE 4551: /* 4552: Figure out what the length is supposed to be in case the packet 4553: has no terminator (as with Honeywell GCOS-8 Kermit). 4554: */ 4555: #ifndef xunchar 4556: #define xunchar(ch) (((ch) - 32 ) & 0xFF ) /* Character to number */ 4557: #endif /* xunchar */ 4558: if ((flag == 0) && ((n & 0x7f) == start)) flag = 1; 4559: if (flag) dest[i++] = n & ttpmsk; 4560: /* 4561: If we have not been instructed to wait for a turnaround character, we 4562: can go by the packet length field. If turn != 0, we must wait for the 4563: end of line (eol) character before returning. 4564: */ 4565: if (i == 2) { 4566: pktlen = xunchar(dest[1]); 4567: havelen = (pktlen > 1); 4568: debug(F101,"ttinl length","",pktlen); 4569: } else if (i == 5 && pktlen == 0) { 4570: lplen = xunchar(dest[4]); 4571: } else if (i == 6 && pktlen == 0) { 4572: pktlen = lplen * 95 + xunchar(dest[5]) + 5; 4573: havelen = 1; 4574: debug(F101,"ttinl length","",pktlen); 4575: } 4576: #else 4577: dest[i++] = n & ttpmsk; 4578: #endif /* PARSENSE */ 4579: if ((n & 0x7f) == CTRLC) { /* Check for ^C^C */ 4580: if (++ccn > 1) { /* If we got 2 in a row, bail out. */ 4581: if (timo) { /* Clear timer. */ 4582: ttimoff(); 4583: } 4584: fprintf(stderr,"^C...\r\n"); /* Echo Ctrl-C */ 4585: return(-2); 4586: } 4587: } else ccn = 0; /* Not ^C, so reset ^C counter, */ 4588: 4589: #ifdef PARSENSE 4590: if (flag == 0) { 4591: debug(F101,"ttinl skipping","",n); 4592: continue; 4593: } 4594: #endif /* PARSENSE */ 4595: 4596: /* Check for end of packet */ 4597: 4598: if (((n & 0x7f) == eol) 4599: #ifdef PARSENSE 4600: || (!turn && havelen && (i > pktlen+1)) 4601: #endif /* PARSENSE */ 4602: ) { 4603: #ifndef PARSENSE 4604: debug(F101,"ttinl got eol","",eol); 4605: dest[i] = '\0'; /* Yes, terminate the string, */ 4606: /* debug(F101,"ttinl i","",i); */ 4607: #else 4608: if ((n & 0x7f) != eol) { 4609: debug(F101,"ttinl EOP length","",pktlen); 4610: debug(F101,"ttinl i","",i); 4611: } else debug(F101,"ttinl got eol","",eol); 4612: dest[i] = '\0'; /* Terminate the string, */ 4613: /* Parity checked yet? */ 4614: if (ttpflg++ == 0 && ttprty == 0) { 4615: if ((ttprty = parchk(dest,start,i)) > 0) { /* No, check. */ 4616: int j; 4617: debug(F101,"ttinl senses parity","",ttprty); 4618: debug(F110,"ttinl packet before",dest,0); 4619: ttpmsk = 0x7f; 4620: for (j = 0; j < i; j++) 4621: dest[j] &= 0x7f; /* Strip parity from packet */ 4622: debug(F110,"ttinl packet after ",dest,0); 4623: } else ttprty = 0; /* restore if parchk error */ 4624: } 4625: #endif /* PARSENSE */ 4626: if (timo) { /* Turn off timer. */ 4627: ttimoff(); 4628: } 4629: debug(F111,"ttinl got", dest,i); 4630: return(i); 4631: } 4632: } /* end of while() */ 4633: ttimoff(); 4634: return(-1); 4635: } 4636: } 4637: 4638: /* T T I N C -- Read a character from the communication line */ 4639: /* 4640: On success, returns the character that was read, >= 0. 4641: On failure, returns -1 or other negative myread error code. 4642: */ 4643: int 4644: ttinc(timo) int timo; { 4645: 4646: int n = 0; 4647: #ifndef MYREAD 4648: CHAR ch = 0; 4649: #endif /* MYREAD */ 4650: 4651: if (ttyfd < 0) return(-1); /* Not open. */ 4652: if (timo <= 0) { /* Untimed. */ 4653: #ifdef MYREAD 4654: /* comm line failure returns -1 thru myread, so no &= 0377 */ 4655: n = myread(); /* Wait for a character... */ 4656: /* debug(F101,"ttinc MYREAD n","",n); */ 4657: return(n < 0 ? n : n & ttpmsk); 4658: #else 4659: while ((n = read(ttyfd,&ch,1)) == 0) /* Wait for a character. */ 4660: /* Shouldn't have to loop in ver 5A. */ 4661: #ifdef NETCONN 4662: if (netconn) { /* Special handling for net */ 4663: netclos(); /* If read() returns 0 it means */ 4664: netconn = 0; /* the connection has dropped. */ 4665: errno = ENOTCONN; 4666: return(-2); 4667: } 4668: #endif /* NETCONN */ 4669: ; 4670: /* debug(F000,"ttinc","",ch); */ 4671: return( (n < 1) ? -3 : (ch & ttpmsk) ); 4672: #endif /* MYREAD */ 4673: } else { /* Timed read */ 4674: int xx; 4675: saval = signal(SIGALRM,timerh); /* Set up handler, save old one. */ 4676: xx = alarm(timo); /* Set alarm, save old one. */ 4677: /* debug(F101,"ttinc alarm","",xx); */ 4678: if (setjmp(sjbuf)) { /* Timer expired */ 4679: n = -1; /* set flag */ 4680: } else { 4681: #ifdef MYREAD 4682: n = myread(); /* If managing own buffer... */ 4683: /* debug(F101,"ttinc myread","",n); */ 4684: #else 4685: n = read(ttyfd,&ch,1); /* Otherwise call the system. */ 4686: /* debug(F101,"ttinc read","",n); */ 4687: if (n > 0) 4688: n = ch & 255; 4689: else 4690: n = (n < 0) ? -3 : -2; /* Special return codes. */ 4691: #endif /* MYREAD */ 4692: } 4693: ttimoff(); /* Turn off the timer */ 4694: /* #ifdef COMMENT */ 4695: if (n == -1) xx -= timo; /* and restore any previous alarm */ 4696: if (xx < 0) xx = 0; /* adjusted by timeout interval */ 4697: alarm(xx); /* if timer expired. */ 4698: /* #endif */ /* COMMENT */ 4699: #ifdef NETCONN 4700: if (netconn) { 4701: if (n == -2) { /* read() returns 0 */ 4702: netclos(); /* on network read failure */ 4703: netconn = 0; 4704: errno = ENOTCONN; 4705: } 4706: } 4707: #endif /* NETCONN */ 4708: return( (n < 0) ? n : (n & ttpmsk) ); /* Return masked char or neg. */ 4709: } 4710: } 4711: 4712: /* S N D B R K -- Send a BREAK signal of the given duration */ 4713: 4714: static int 4715: #ifdef CK_ANSIC 4716: sndbrk(int msec) { /* Argument is milliseconds */ 4717: #else 4718: sndbrk(msec) int msec; { 4719: #endif /* CK_ANSIC */ 4720: #ifndef POSIX 4721: int x, n; 4722: #endif /* POSIX */ 4723: 4724: #ifdef ANYBSD 4725: #define BSDBREAK 4726: #endif /* ANYBSD */ 4727: 4728: #ifdef BSD44 4729: #define BSDBREAK 4730: #endif /* BSD44 */ 4731: 4732: #ifdef COHERENT 4733: #define BSDBREAK 4734: #endif /* COHERENT */ 4735: 4736: #ifdef PROVX1 4737: char spd; 4738: #endif /* PROVX1 */ 4739: 4740: debug(F101,"ttsndb ttyfd","",ttyfd); 4741: if (ttyfd < 0) return(-1); /* Not open. */ 4742: 4743: #ifdef NETCONN 4744: if (netconn) /* Send network BREAK */ 4745: return(netbreak()); 4746: #endif /* NETCONN */ 4747: 4748: if (msec < 1 || msec > 5000) return(-1); /* Bad argument */ 4749: 4750: #ifdef POSIX /* Easy in POSIX */ 4751: return(tcsendbreak(ttyfd,msec / 375)); 4752: #else 4753: #ifdef PROVX1 4754: gtty(ttyfd,&ttbuf); /* Get current tty flags */ 4755: spd = ttbuf.sg_ospeed; /* Save speed */ 4756: ttbuf.sg_ospeed = B50; /* Change to 50 baud */ 4757: stty(ttyfd,&ttbuf); /* ... */ 4758: n = (int)strlen(brnuls); /* Send the right number of nulls */ 4759: x = msec / 91; 4760: if (x > n) x = n; 4761: write(ttyfd,brnuls,n); 4762: ttbuf.sg_ospeed = spd; /* Restore speed */ 4763: stty(ttyfd,&ttbuf); /* ... */ 4764: return(0); 4765: #else 4766: #ifdef aegis 4767: sio_$control((short)ttyfd, sio_$send_break, msec, st); 4768: return(0); 4769: #else 4770: #ifdef BSDBREAK 4771: n = FWRITE; /* Flush output queue. */ 4772: /* Watch out for int vs long problems in &n arg! */ 4773: ioctl(ttyfd,TIOCFLUSH,&n); /* Ignore any errors.. */ 4774: if (ioctl(ttyfd,TIOCSBRK,(char *)0) < 0) { /* Turn on BREAK */ 4775: perror("Can't send BREAK"); 4776: return(-1); 4777: } 4778: x = msleep(msec); /* Sleep for so many milliseconds */ 4779: if (ioctl(ttyfd,TIOCCBRK,(char *)0) < 0) { /* Turn off BREAK */ 4780: perror("BREAK stuck!!!"); 4781: doexit(BAD_EXIT,-1); /* Get out, closing the line. */ 4782: /* with bad exit status */ 4783: } 4784: return(x); 4785: #else 4786: #ifdef ATTSV 4787: /* 4788: No way to send a long BREAK in Sys V, so send a bunch of regular ones. 4789: (Actually, Sys V R4 is *supposed* to have the POSIX tcsendbreak() function, 4790: but there's no way for this code to know for sure.) 4791: */ 4792: x = msec / 275; 4793: for (n = 0; n < x; n++) { 4794: if (ioctl(ttyfd,TCSBRK,(char *)0) < 0) { 4795: perror("Can't send BREAK"); 4796: return(-1); 4797: } 4798: } 4799: return(0); 4800: #else 4801: #ifdef V7 4802: return(genbrk(ttyfd,250)); /* Simulate a BREAK */ 4803: #endif /* V7 */ 4804: #endif /* BSDBREAK */ 4805: #endif /* ATTSV */ 4806: #endif /* aegis */ 4807: #endif /* PROVX1 */ 4808: #endif /* POSIX */ 4809: } 4810: 4811: /* T T S N D B -- Send a BREAK signal */ 4812: 4813: int 4814: ttsndb() { 4815: return(sndbrk(275)); 4816: } 4817: 4818: /* T T S N D L B -- Send a Long BREAK signal */ 4819: 4820: int 4821: ttsndlb() { 4822: return(sndbrk(1500)); 4823: } 4824: 4825: /* M S L E E P -- Millisecond version of sleep(). */ 4826: 4827: /* 4828: Call with number of milliseconds (thousandths of seconds) to sleep. 4829: Intended only for small intervals. For big ones, just use sleep(). 4830: Highly system-dependent. 4831: Returns 0 always, even if it didn't work. 4832: */ 4833: 4834: /* Define MSLFTIME for systems that must use an ftime() loop. */ 4835: #ifdef ANYBSD /* For pre-4.2 BSD versions */ 4836: #ifndef BSD4 4837: #define MSLFTIME 4838: #endif /* BSD4 */ 4839: #endif /* ANYBSD */ 4840: 4841: #ifdef TOWER1 /* NCR Tower OS 1.0 */ 4842: #define MSLFTIME 4843: #endif /* TOWER1 */ 4844: 4845: #ifdef COHERENT /* Coherent */ 4846: #ifndef _I386 4847: #define MSLFTIME 4848: #endif /* _I386 */ 4849: #endif /* COHERENT */ 4850: 4851: int 4852: msleep(m) int m; { 4853: 4854: #ifndef USLEEP 4855: #ifdef SUNOS4 /* Systems that have usleep() */ 4856: #define USLEEP 4857: #endif /* SUNOS4 */ 4858: #ifdef SUN4S5 4859: #define USLEEP 4860: #endif /* SUN4S5 */ 4861: #ifdef NEXT 4862: #define USLEEP 4863: #endif /* NEXT*/ 4864: #endif /* USLEEP */ 4865: 4866: #ifdef AIXRS /* RS/6000 can do select() */ 4867: #define BSD42 4868: #endif /* AIXRS */ 4869: 4870: #ifndef SELECT 4871: #ifdef BSD44 4872: #define SELECT 4873: #endif /* BSD44 */ 4874: #ifdef BSD42 4875: #define SELECT 4876: #endif /* BSD42 */ 4877: #endif /* SELECT */ 4878: 4879: #ifdef SELECT 4880: /* BSD 4.2 & above can do it with select()... */ 4881: int t1; 4882: if (m <= 0) return(0); 4883: if (m >= 1000) { /* Catch big arguments. */ 4884: sleep(m/1000); 4885: m = m % 1000; 4886: if (m < 10) return(0); 4887: } 4888: if (gettimeofday(&tv, &tz) < 0) return(-1); /* Get current time. */ 4889: t1 = tv.tv_sec; /* Seconds */ 4890: tv.tv_sec = 0; /* Use select() */ 4891: tv.tv_usec = m * 1000L; 4892: #ifdef BSD44 4893: select( 0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tv ); 4894: #else 4895: #ifdef BSD43 4896: select( 0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tv ); 4897: #else 4898: select( 0, (int *)0, (int *)0, (int *)0, &tv ); 4899: #endif /* BSD43 */ 4900: #endif /* BSD44 */ 4901: return(0); 4902: 4903: #else /* Not SELECT */ 4904: 4905: #ifdef USLEEP 4906: /* 4907: "This routine is implemented using setitimer(2); it requires eight 4908: system calls...". In other words, it might take 5 minutes to sleep 4909: for 100 milliseconds... 4910: */ 4911: if (m >= 1000) { /* Catch big arguments. */ 4912: sleep(m/1000); 4913: m = m % 1000; 4914: if (m < 10) return(0); 4915: } 4916: usleep((unsigned int)(m * 1000)); 4917: return(0); 4918: #else 4919: #ifdef aegis 4920: time_$clock_t dur; 4921: 4922: dur.c2.high16 = 0; 4923: dur.c2.low32 = 250 * m; /* one millisecond = 250 four microsecond ticks */ 4924: time_$wait(time_$relative, dur, st); 4925: return(0); 4926: #else 4927: #ifdef PROVX1 4928: if (m <= 0) return(0); 4929: sleep(-((m * 60 + 500) / 1000)); 4930: return(0); 4931: #else 4932: #ifdef NAP 4933: nap((long)m); 4934: return(0); 4935: #else 4936: #ifdef ATTSV 4937: #ifndef BSD44 4938: extern long times(); /* Or #include <times.h> ? */ 4939: #endif /* BSD44 */ 4940: long t1, t2, tarray[4]; 4941: int t3; 4942: 4943: #ifdef COMMENT 4944: /* This better be picked up in ckcdeb.h... */ 4945: char *getenv(); 4946: #endif /* COMMENT */ 4947: char *cp = getenv("HZ"); 4948: int CLOCK_TICK; 4949: int hertz; 4950: 4951: if (cp && (hertz = atoi(cp))) { 4952: CLOCK_TICK = 1000 / hertz; 4953: } else { /* probably single user mode */ 4954: #ifdef HZ 4955: CLOCK_TICK = 1000 / HZ; 4956: #else 4957: static warned = 0; 4958: /* HZ always exists in, for instance, SCO Xenix, so you don't have to 4959: * make special #ifdefs for XENIX here, like in ver 4F. Also, if you 4960: * have Xenix, you have should have nap(), so the best is to use -DNAP 4961: * in the makefile. Most systems have HZ. 4962: */ 4963: CLOCK_TICK = 17; /* 1/60 sec */ 4964: if (!warned) { 4965: printf("warning: environment variable HZ bad... using HZ=%d\r\n", 4966: 1000 / CLOCK_TICK); 4967: warned = 1; 4968: } 4969: #endif /* !HZ */ 4970: } 4971: 4972: if (m <= 0) return(0); 4973: if (m >= 1000) { /* Catch big arguments. */ 4974: sleep(m/1000); 4975: m = m % 1000; 4976: if (m < 10) return(0); 4977: } 4978: if ((t1 = times(tarray)) < 0) return(-1); 4979: while (1) { 4980: if ((t2 = times(tarray)) < 0) return(-1); 4981: t3 = ((int)(t2 - t1)) * CLOCK_TICK; 4982: if (t3 > m) return(t3); 4983: } 4984: #else /* Not ATTSV */ 4985: #ifdef MSLFTIME /* Use ftime() loop... */ 4986: int t1, t3 = 0; 4987: if (m <= 0) return(0); 4988: if (m >= 1000) { /* Catch big arguments. */ 4989: sleep(m/1000); 4990: m = m % 1000; 4991: if (m < 10) return(0); 4992: } 4993: if (ftime(&ftp) < 0) return(-1); /* Get base time. */ 4994: t1 = ((ftp.time & 0xff) * 1000) + ftp.millitm; 4995: while (1) { 4996: ftime(&ftp); /* Get current time and compare. */ 4997: t3 = (((ftp.time & 0xff) * 1000) + ftp.millitm) - t1; 4998: if (t3 > m) return(0); 4999: } 5000: #else 5001: /* This includes true POSIX, which has no way to do this. */ 5002: if (m >= 1000) { /* Catch big arguments. */ 5003: sleep(m/1000); 5004: m = m % 1000; 5005: if (m < 10) return(0); 5006: } 5007: if (m > 0) while (m > 0) m--; /* Just a dumb busy loop */ 5008: return(0); 5009: #endif /* MSLFTIME */ 5010: #endif /* ATTSV */ 5011: #endif /* NAP */ 5012: #endif /* PROVX1 */ 5013: #endif /* aegis */ 5014: #endif /* SELECT */ 5015: #endif /* USLEEP */ 5016: } 5017: 5018: /* R T I M E R -- Reset elapsed time counter */ 5019: 5020: VOID 5021: rtimer() { 5022: tcount = time( (time_t *) 0 ); 5023: } 5024: 5025: 5026: /* G T I M E R -- Get current value of elapsed time counter in seconds */ 5027: 5028: int 5029: gtimer() { 5030: int x; 5031: x = (int) (time( (time_t *) 0 ) - tcount); 5032: debug(F101,"gtimer","",x); 5033: return( (x < 0) ? 0 : x ); 5034: } 5035: 5036: 5037: /* Z T I M E -- Return date/time string */ 5038: 5039: VOID 5040: ztime(s) char **s; { 5041: 5042: #undef ZTIMEV7 /* Which systems need to use */ 5043: #ifdef COHERENT /* old UNIX Version 7 way... */ 5044: #define ZTIMEV7 5045: #endif /* COHERENT */ 5046: #ifdef TOWER1 5047: #define ZTIMEV7 5048: #endif /* TOWER1 */ 5049: #ifdef ANYBSD 5050: #ifndef BSD42 5051: #define ZTIMEV7 5052: #endif /* BSD42 */ 5053: #endif /* ANYBSD */ 5054: #ifdef V7 5055: #ifndef MINIX 5056: #define ZTIMEV7 5057: #endif /* MINIX */ 5058: #endif /* V7 */ 5059: #ifdef POSIX 5060: #define ZTIMEV7 5061: #endif /* POSIX */ 5062: 5063: #ifdef ATTSV /* AT&T way */ 5064: /* extern long time(); */ /* Theoretically these should */ 5065: char *ctime(); /* already been dcl'd in <time.h> */ 5066: long clock_storage; 5067: clock_storage = time( (long *) 0 ); 5068: *s = ctime( &clock_storage ); 5069: #else 5070: #ifdef PROVX1 /* Venix 1.0 way */ 5071: int utime[2]; 5072: time(utime); 5073: *s = ctime(utime); 5074: #else 5075: #ifdef BSD42 /* 4.2BSD way */ 5076: char *asctime(); 5077: struct tm *localtime(); 5078: struct tm *tp; 5079: gettimeofday(&tv, &tz); 5080: time(&tv.tv_sec); 5081: tp = localtime(&tv.tv_sec); 5082: *s = asctime(tp); 5083: #else 5084: #ifdef MINIX /* MINIX way */ 5085: #ifdef COMMENT 5086: extern long time(); /* Already got these from <time.h> */ 5087: extern char *ctime(); 5088: #endif /* COMMENT */ 5089: time_t utime[2]; 5090: time(utime); 5091: *s = ctime(utime); 5092: #else 5093: #ifdef ZTIMEV7 /* The regular way */ 5094: char *asctime(); 5095: struct tm *localtime(); 5096: struct tm *tp; 5097: long xclock; 5098: time(&xclock); 5099: tp = localtime(&xclock); 5100: *s = asctime(tp); 5101: #else /* Catch-all for others... */ 5102: *s = "Ddd Mmm 00 00:00:00 0000\n" /* Return dummy in asctime() format */ 5103: #endif /* ZTIMEV7 */ 5104: #endif /* MINIX */ 5105: #endif /* BSD42 */ 5106: #endif /* PROVX1 */ 5107: #endif /* SVORPOSIX */ 5108: } 5109: 5110: /* C O N G M -- Get console terminal modes. */ 5111: 5112: /* 5113: Saves initial console mode, and establishes variables for switching 5114: between current (presumably normal) mode and other modes. 5115: Should be called when program starts, but only after establishing 5116: whether program is in the foreground or background. 5117: Returns 1 if it got the modes OK, 0 if it did nothing, -1 on error. 5118: */ 5119: int 5120: congm() { 5121: int fd; 5122: if (backgrd || !isatty(0)) { /* If in background. */ 5123: cgmf = -1; /* Don't bother, modes are garbage. */ 5124: return(-1); 5125: } 5126: if (cgmf > 0) return(0); /* Already did this. */ 5127: debug(F100,"congm getting modes","",0); /* Need to do it. */ 5128: #ifdef aegis 5129: ios_$inq_type_uid(ios_$stdin, conuid, st); 5130: if (st.all != status_$ok) { 5131: fprintf(stderr, "problem getting stdin objtype: "); 5132: error_$print(st); 5133: } 5134: concrp = (conuid == mbx_$uid); 5135: conbufn = 0; 5136: #endif /* aegis */ 5137: 5138: if ((fd = open(CTTNAM,2)) < 0) { /* Open controlling terminal */ 5139: fprintf(stderr,"Error opening %s\n", CTTNAM); 5140: perror("congm"); 5141: return(-1); 5142: } 5143: #ifdef BSD44ORPOSIX 5144: if (tcgetattr(fd,&ccold) < 0) return(-1); 5145: if (tcgetattr(fd,&cccbrk) < 0) return(-1); 5146: if (tcgetattr(fd,&ccraw) < 0) return(-1); 5147: #else 5148: #ifdef ATTSV 5149: if (ioctl(fd,TCGETA,&ccold) < 0) return(-1); 5150: if (ioctl(fd,TCGETA,&cccbrk) < 0) return(-1); 5151: if (ioctl(fd,TCGETA,&ccraw) < 0) return(-1); 5152: #ifdef VXVE 5153: cccbrk.c_line = 0; /* STTY line 0 for CDC VX/VE */ 5154: if (ioctl(fd,TCSETA,&cccbrk) < 0) return(-1); 5155: ccraw.c_line = 0; /* STTY line 0 for CDC VX/VE */ 5156: if (ioctl(fd,TCSETA,&ccraw) < 0) return(-1); 5157: #endif /* VXVE */ 5158: #else 5159: if (gtty(fd,&ccold) < 0) return(-1); 5160: if (gtty(fd,&cccbrk) < 0) return(-1); 5161: if (gtty(fd,&ccraw) < 0) return(-1); 5162: #endif /* ATTSV */ 5163: #endif /* BSD44ORPOSIX */ 5164: #ifdef sony_news /* Sony NEWS */ 5165: if (ioctl(fd,TIOCKGET,&km_con) < 0) { /* Get console Kanji mode */ 5166: perror("congm error getting Kanji mode"); 5167: debug(F101,"congm error getting Kanji mode","",0); 5168: km_con = -1; /* Make sure this stays undefined. */ 5169: return(-1); 5170: } 5171: #endif /* sony_news */ 5172: close(fd); 5173: cgmf = 1; /* Flag that we got them. */ 5174: return(1); 5175: } 5176: 5177: 5178: /* C O N C B -- Put console in cbreak mode. */ 5179: 5180: /* Returns 0 if ok, -1 if not */ 5181: 5182: int 5183: #ifdef CK_ANSIC 5184: concb(char esc) 5185: #else 5186: concb(esc) char esc; 5187: #endif /* CK_ANSIC */ 5188: /* concb */ { 5189: int x; 5190: if (cgmf < 1) return(0); /* Console modes not available yet */ 5191: if (ttfdflg && ttyfd >= 0 && ttyfd < 3) 5192: return(0); 5193: debug(F101,"concb backgrd","",backgrd); 5194: if (!isatty(0)) return(0); /* Only for real ttys */ 5195: debug(F100,"concb isatty","",0); 5196: if (backgrd) return(0); /* Do nothing if in background. */ 5197: escchr = esc; /* Make this available to other fns */ 5198: ckxech = 1; /* Program can echo characters */ 5199: #ifdef aegis 5200: conbufn = 0; 5201: if (concrp) return(write(1, "\035\002", 2)); 5202: if (conuid == input_pad_$uid) {pad_$raw(ios_$stdin, st); return(0);} 5203: #endif 5204: #ifndef SVORPOSIX /* BSD, V7, etc */ 5205: cccbrk.sg_flags |= CBREAK; /* Set to character wakeup, */ 5206: cccbrk.sg_flags &= ~ECHO; /* no echo. */ 5207: x = stty(0,&cccbrk); 5208: #else /* Sys V and POSIX */ 5209: cccbrk.c_lflag &= ~(ICANON|ECHO|IEXTEN); 5210: #ifndef VINTR 5211: cccbrk.c_cc[0] = 003; /* interrupt char is control-c */ 5212: #else 5213: cccbrk.c_cc[VINTR] = 003; 5214: #endif /* VINTR */ 5215: #ifndef VQUIT 5216: cccbrk.c_cc[1] = escchr; /* escape during packet modes */ 5217: #else 5218: cccbrk.c_cc[VQUIT] = escchr; 5219: #endif /* VQUIT */ 5220: #ifndef VEOF 5221: cccbrk.c_cc[4] = 1; 5222: #else 5223: #ifdef VMIN 5224: cccbrk.c_cc[VMIN] = 1; 5225: #endif /* VMIN */ 5226: #endif /* VEOF */ 5227: #ifdef ZILOG 5228: cccbrk.c_cc[5] = 0; 5229: #else 5230: #ifndef VEOL 5231: cccbrk.c_cc[5] = 1; 5232: #else 5233: #ifdef VTIME 5234: cccbrk.c_cc[VTIME] = 1; 5235: #endif /* VTIME */ 5236: #endif /* VEOL */ 5237: #endif /* ZILOG */ 5238: #ifdef BSD44ORPOSIX /* Set new modes */ 5239: x = tcsetattr(0,TCSADRAIN,&cccbrk); 5240: #else /* ATTSV */ /* or the POSIX way */ 5241: x = ioctl(0,TCSETAW,&cccbrk); /* the Sys V way */ 5242: #endif /* BSD44ORPOSIX */ 5243: #endif /* SVORPOSIX */ 5244: 5245: #ifndef aegis 5246: #ifndef NOSETBUF 5247: if (x > -1) setbuf(stdout,NULL); /* Make console unbuffered. */ 5248: #endif /* NOSETBUF */ 5249: #endif /* aegis */ 5250: 5251: #ifdef V7 5252: #ifndef MINIX 5253: if (kmem[CON] < 0) { 5254: qaddr[CON] = initrawq(0); 5255: if((kmem[CON] = open("/dev/kmem", 0)) < 0) { 5256: fprintf(stderr, "Can't read /dev/kmem in concb.\n"); 5257: perror("/dev/kmem"); 5258: exit(1); 5259: } 5260: } 5261: #endif /* MINIX */ 5262: #endif /* V7 */ 5263: debug(F101,"concb returns","",x); 5264: return(x); 5265: } 5266: 5267: /* C O N B I N -- Put console in binary mode */ 5268: 5269: /* Returns 0 if ok, -1 if not */ 5270: 5271: int 5272: #ifdef CK_ANSIC 5273: conbin(char esc) 5274: #else 5275: conbin(esc) char esc; 5276: #endif /* CK_ANSIC */ 5277: /* conbin */ { 5278: if (!isatty(0)) return(0); /* only for real ttys */ 5279: congm(); /* Get modes if necessary. */ 5280: debug(F100,"conbin","",0); 5281: escchr = esc; /* Make this available to other fns */ 5282: ckxech = 1; /* Program can echo characters */ 5283: #ifdef aegis 5284: conbufn = 0; 5285: if (concrp) return(write(1, "\035\002", 2)); 5286: if (conuid == input_pad_$uid) 5287: pad_$raw(ios_$stdin, st); 5288: return(0) 5289: #endif /* aegis */ 5290: 5291: #ifdef SVORPOSIX 5292: ccraw.c_lflag &= ~(ISIG|ICANON|ECHO|IEXTEN); 5293: ccraw.c_iflag |= (BRKINT|IGNPAR); 5294: #ifdef ATTSV 5295: #ifdef BSD44 5296: ccraw.c_iflag &= ~(IGNBRK|INLCR|IGNCR|ICRNL|IXON|IXANY|IXOFF 5297: |INPCK|ISTRIP); 5298: #else 5299: ccraw.c_iflag &= ~(IGNBRK|INLCR|IGNCR|ICRNL|IUCLC|IXON|IXANY|IXOFF 5300: |INPCK|ISTRIP); 5301: #endif /* BSD44 */ 5302: #else /* POSIX */ 5303: ccraw.c_iflag &= ~(IGNBRK|INLCR|IGNCR|ICRNL|IXON|IXOFF|INPCK|ISTRIP); 5304: #endif /* ATTSV */ 5305: ccraw.c_oflag &= ~OPOST; 5306: #ifdef ATT7300 5307: ccraw.c_cflag = CLOCAL | B9600 | CS8 | CREAD | HUPCL; 5308: #endif /* ATT7300 */ 5309: /*** Kermit used to put the console in 8-bit raw mode, but some users have 5310: *** pointed out that this should not be done, since some sites actually 5311: *** use terminals with parity settings on their Unix systems, and if we 5312: *** override the current settings and stop doing parity, then their terminals 5313: *** will display blotches for characters whose parity is wrong. Therefore, 5314: *** the following two lines are commented out (Larry Afrin, Clemson U): 5315: *** 5316: *** ccraw.c_cflag &= ~(PARENB|CSIZE); 5317: *** ccraw.c_cflag |= (CS8|CREAD); 5318: *** 5319: *** Sys III/V sites that have trouble with this can restore these lines. 5320: ***/ 5321: #ifndef VINTR 5322: ccraw.c_cc[0] = 003; /* Interrupt char is Ctrl-C */ 5323: #else 5324: ccraw.c_cc[VINTR] = 003; 5325: #endif /* VINTR */ 5326: #ifndef VQUIT 5327: ccraw.c_cc[1] = escchr; /* Escape during packet mode */ 5328: #else 5329: ccraw.c_cc[VQUIT] = escchr; 5330: #endif /* VQUIT */ 5331: #ifndef VEOF 5332: ccraw.c_cc[4] = 1; 5333: #else 5334: #ifdef VMIN 5335: ccraw.c_cc[VMIN] = 1; 5336: #endif 5337: #endif /* VEOF */ 5338: 5339: #ifdef ZILOG 5340: ccraw.c_cc[5] = 0; 5341: #else 5342: #ifndef VEOL 5343: ccraw.c_cc[5] = 1; 5344: #else 5345: #ifdef VTIME 5346: ccraw.c_cc[VTIME] = 1; 5347: #endif /* VTIME */ 5348: #endif /* VEOL */ 5349: #endif /* ZILOG */ 5350: 5351: #ifdef BSD44ORPOSIX 5352: return(tcsetattr(0,TCSADRAIN,&ccraw)); 5353: #else 5354: return(ioctl(0,TCSETAW,&ccraw)); /* Set new modes. */ 5355: #endif /* BSD44ORPOSIX */ 5356: 5357: #else /* Berkeley, etc. */ 5358: ccraw.sg_flags |= (RAW|TANDEM); /* Set rawmode, XON/XOFF (ha) */ 5359: ccraw.sg_flags &= ~(ECHO|CRMOD); /* Set char wakeup, no echo */ 5360: return(stty(0,&ccraw)); 5361: #endif /* SVORPOSIX */ 5362: } 5363: 5364: 5365: /* C O N R E S -- Restore the console terminal */ 5366: 5367: int 5368: conres() { 5369: debug(F101,"conres cgmf","",cgmf); 5370: if (cgmf < 1) return(0); /* Do nothing if modes unchanged */ 5371: if (!isatty(0)) return(0); /* only for real ttys */ 5372: debug(F100,"conres isatty ok","",0); 5373: ckxech = 0; /* System should echo chars */ 5374: 5375: #ifdef aegis 5376: conbufn = 0; 5377: if (concrp) return(write(1, "\035\001", 2)); 5378: if (conuid == input_pad_$uid) 5379: pad_$cooked(ios_$stdin, st); 5380: return(0); 5381: #endif /* aegis */ 5382: 5383: #ifdef BSD44ORPOSIX 5384: debug(F100,"conres restoring tcsetattr","",0); 5385: return(tcsetattr(0,TCSADRAIN,&ccold)); 5386: #else 5387: #ifdef ATTSV 5388: debug(F100,"conres restoring ioctl","",0); 5389: return(ioctl(0,TCSETAW,&ccold)); 5390: #else /* BSD, V7, and friends */ 5391: #ifdef sony_news /* Sony NEWS */ 5392: if (km_con != -1) 5393: ioctl(0,TIOCKSET,&km_con); /* Restore console Kanji mode */ 5394: #endif /* sony_news */ 5395: msleep(300); 5396: debug(F100,"conres restoring stty","",0); 5397: return(stty(0,&ccold)); 5398: #endif /* ATTSV */ 5399: #endif /* BSD44ORPOSIX */ 5400: } 5401: 5402: /* C O N O C -- Output a character to the console terminal */ 5403: 5404: int 5405: #ifdef CK_ANSIC 5406: conoc(char c) 5407: #else 5408: conoc(c) char c; 5409: #endif /* CK_ANSIC */ 5410: /* conoc */ { 5411: return(write(1,&c,1)); 5412: } 5413: 5414: /* C O N X O -- Write x characters to the console terminal */ 5415: 5416: int 5417: conxo(x,s) int x; char *s; { 5418: return(write(1,s,x)); 5419: } 5420: 5421: /* C O N O L -- Write a line to the console terminal */ 5422: 5423: int 5424: conol(s) char *s; { 5425: int len; 5426: len = (int)strlen(s); 5427: return(write(1,s,len)); 5428: } 5429: 5430: /* C O N O L A -- Write an array of lines to the console terminal */ 5431: 5432: int 5433: conola(s) char *s[]; { 5434: int i; 5435: for (i=0 ; *s[i] ; i++) if (conol(s[i]) < 0) return(-1);; 5436: return(0); 5437: } 5438: 5439: /* C O N O L L -- Output a string followed by CRLF */ 5440: 5441: int 5442: conoll(s) char *s; { 5443: conol(s); 5444: return(write(1,"\r\n",2)); 5445: } 5446: 5447: /* C O N C H K -- Return how many characters available at console */ 5448: 5449: int 5450: conchk() { 5451: int x; PEEKTYPE n; 5452: 5453: if (backgrd || !isatty(0)) return(0); 5454: #ifdef PROVX1 5455: x = ioctl(0, TIOCQCNT, &ttbuf); 5456: n = ttbuf.sg_ispeed & 0377; 5457: return((x < 0) ? 0 : n); 5458: #else 5459: #ifdef aegis 5460: if (conbufn > 0) return(conbufn); /* use old count if nonzero */ 5461: 5462: /* read in more characters */ 5463: conbufn = ios_$get(ios_$stdin, 5464: ios_$cond_opt, conbuf, (long)sizeof(conbuf), st); 5465: if (st.all != status_$ok) conbufn = 0; 5466: conbufp = conbuf; 5467: return(conbufn); 5468: #else 5469: #ifdef V7 5470: #ifdef MINIX 5471: return(0); 5472: #else 5473: lseek(kmem[CON], (long) qaddr[CON], 0); 5474: x = read(kmem[CON], &n, sizeof(int)); 5475: return((x == sizeof(int))? n: 0); 5476: #endif /* MINIX */ 5477: #else 5478: #ifdef SVORPOSIX 5479: if (conesc) { /* Escape typed */ 5480: debug(F100,"conchk returns conesc","",conesc); 5481: conesc = 0; 5482: signal(SIGQUIT,esctrp); /* Restore escape */ 5483: return(1); 5484: } 5485: return(0); 5486: #else 5487: #ifdef C70 5488: if (conesc) { /* Escape typed */ 5489: conesc = 0; 5490: signal(SIGQUIT,esctrp); /* Restore escape */ 5491: return(1); 5492: } 5493: return(0); 5494: #else 5495: #ifdef FIONREAD 5496: /* 5497: Reportedly, this can cause C-Kermit to be suspended on certain OS's, 5498: such as Olivetti X/OS, when called if Kermit is really in the background. 5499: Hence the change at the top of this routine to return 0 if the backgrd 5500: flag is set. 5501: */ 5502: x = ioctl(0, FIONREAD, &n); /* BSD and maybe some others */ 5503: debug(F101,"conchk","",n); 5504: return((x < 0) ? 0 : n); 5505: #else 5506: return(0); /* Others can't do. */ 5507: #endif 5508: #endif 5509: #endif 5510: #endif 5511: #endif 5512: #endif 5513: } 5514: 5515: /* C O N I N C -- Get a character from the console */ 5516: /* 5517: Call with timo > 0 to do a timed read, timo == 0 to do an untimed blocking 5518: read. Upon success, returns the character. Upon failure, returns -1. 5519: A timed read that does not complete within the timeout period returns -1. 5520: */ 5521: int 5522: coninc(timo) int timo; { 5523: int n = 0; CHAR ch; 5524: int xx; 5525: #ifdef aegis /* Apollo Aegis only... */ 5526: debug(F101,"coninc timo","",timo); 5527: fflush(stdout); 5528: if (conchk() > 0) { 5529: --conbufn; 5530: return(*conbufp++ & 0377); 5531: } 5532: #endif /* aegis */ 5533: 5534: if (timo <= 0 ) { /* Untimed, blocking read. */ 5535: while (1) { /* Keep trying till we get one. */ 5536: n = read(0, &ch, 1); /* Read a character. */ 5537: if (n == 0) continue; /* Shouldn't happen. */ 5538: if (n > 0) /* If read was successful, */ 5539: return(ch & 0377); /* return the character. */ 5540: 5541: /* Come here if read() returned an error. */ 5542: 5543: debug(F101, "coninc(0) errno","",errno); /* Log the error. */ 5544: #ifdef SVORPOSIX 5545: #ifdef CIE /* CIE Regulus has no EINTR symbol? */ 5546: #ifndef EINTR 5547: #define EINTR 4 5548: #endif /* EINTR */ 5549: #endif /* CIE */ 5550: /* 5551: This routine is used for several different purposes. In CONNECT mode, it is 5552: used to do an untimed, blocking read from the keyboard in the lower CONNECT 5553: fork. During local-mode file transfer, it reads a character from the 5554: console to interrupt the file transfer (like A for a status report, X to 5555: cancel a file, etc). Obviously, we don't want the reads in the latter case 5556: to be blocking, or the file transfer would stop until the user typed 5557: something. Unfortunately, System V does not allow the console device input 5558: buffer to be sampled nondestructively (e.g. by conchk()), so a kludge is 5559: used instead. During local-mode file transfer, the SIGQUIT signal is armed 5560: and trapped by esctrp(), and this routine pretends to have read the quit 5561: character from the keyboard normally. But, kludge or no kludge, the read() 5562: issued by this command, under System V only, can fail if a signal -- ANY 5563: signal -- is caught while the read is pending. This can occur not only when 5564: the user types the quit character, but also during telnet negotiations, when 5565: the lower CONNECT fork signals the upper one about an echoing mode change. 5566: When this happens, we have to post the read() again. This is apparently not 5567: a problem in BSD-based UNIX versions. 5568: */ 5569: if (errno == EINTR) /* Read interrupted. */ 5570: if (conesc) { /* If by SIGQUIT, */ 5571: conesc = 0; /* the conesc variable is set, */ 5572: return(escchr); /* so return the escape character. */ 5573: } else continue; /* By other signal, try again. */ 5574: #else 5575: /* 5576: This might be dangerous, but let's do this on non-System V versions too, 5577: since at least one SunOS 4.1.2 user complains of immediate disconnections 5578: upon first making a TELNET connection. 5579: */ 5580: if (errno == EINTR) /* Read interrupted. */ 5581: continue; 5582: #endif /* SVORPOSIX */ 5583: return(-1); /* Error */ 5584: } 5585: } 5586: 5587: if (timo <= 0) 5588: /* This should never happen */ 5589: debug(F100,"coninc HORRIBLE ERROR","",0); 5590: 5591: /* Timed read... */ 5592: 5593: saval = signal(SIGALRM,timerh); /* Set up timeout handler. */ 5594: xx = alarm(timo); /* Set the alarm. */ 5595: debug(F101,"coninc alarm","",xx); 5596: if (setjmp(sjbuf)) /* The read() timed out. */ 5597: n = -2; /* Code for timeout. */ 5598: else 5599: n = read(0, &ch, 1); 5600: ttimoff(); /* Turn off timer */ 5601: if (n > 0) /* Got character OK. */ 5602: return(ch & 0377); /* Return it. */ 5603: 5604: /* 5605: Read returned an error. Same deal as above, but without the loop. 5606: */ 5607: debug(F101, "coninc(timo) n","",n); 5608: debug(F101, "coninc(timo) errno","",errno); 5609: #ifdef SVORPOSIX 5610: if (n == -1 && errno == EINTR && conesc != 0) { 5611: conesc = 0; 5612: return(escchr); /* User entered escape character. */ 5613: } else /* n == 0 shouldn't happen. */ 5614: #endif /* SVORPOSIX */ 5615: return(-1); 5616: } 5617: 5618: /* C O N G K S -- Console Get Keyboard Scancode */ 5619: 5620: #ifndef congks 5621: /* 5622: This function needs to be filled in with the various system-dependent 5623: system calls used by SUNOS, NeXT OS, Xenix, Aviion, etc, to read a full 5624: keyboard scan code. For now, it's a dummy. 5625: */ 5626: int 5627: congks(timo) int timo; { 5628: return(coninc(timo)); 5629: } 5630: #endif /* congks */ 5631: 5632: #ifdef ATT7300 5633: 5634: /* A T T D I A L -- Dial up the remote system using internal modem 5635: * Purpose: to open and dial a number on the internal modem available on the 5636: * ATT7300 UNIX PC. Written by Joe Doupnik. Superceeds version written by 5637: * Richard E. Hill, Dickinson, TX. which employed dial(3c). 5638: * Uses information in <sys/phone.h> and our status int attmodem. 5639: */ 5640: attdial(ttname,speed,telnbr) char *ttname,*telnbr; long speed; { 5641: char *telnum; 5642: int ttclos(); 5643: 5644: attmodem &= ~ISMODEM; /* modem not in use yet */ 5645: /* Ensure O_NDELAY is set, else i/o traffic hangs */ 5646: /* We turn this flag off once the dial is complete */ 5647: fcntl(ttyfd, F_SETFL, fcntl(ttyfd, F_GETFL, 0) | O_NDELAY); 5648: 5649: /* Condition line, check availability & DATA mode, turn on speaker */ 5650: if (ioctl(ttyfd,PIOCOFFHOOK, &dialer) == -1) { 5651: printf("cannot access phone\n"); 5652: ttclos(0); 5653: return (-2); 5654: } 5655: ioctl(ttyfd,PIOCGETP,&dialer); /* get phone dialer parameters */ 5656: 5657: if (dialer.c_lineparam & VOICE) { /* phone must be in DATA mode */ 5658: printf(" Should not dial with modem in VOICE mode.\n"); 5659: printf(" Exit Kermit, switch to DATA and retry call.\n"); 5660: ttclos(0); 5661: return (-2); 5662: } 5663: #ifdef ATTTONED /* Old way, tone dialing only. */ 5664: dialer.c_lineparam = DATA | DTMF; /* Dial with tones, */ 5665: dialer.c_lineparam &= ~PULSE; /* not with pulses. */ 5666: #else 5667: /* Leave current pulse/tone state alone. */ 5668: /* But what about DATA? Add it back if you have trouble. */ 5669: /* sys/phone says you get DATA automatically by opening device RDWR */ 5670: #endif 5671: dialer.c_waitdialtone = 5; /* wait 5 sec for dialtone */ 5672: #ifdef COMMENT 5673: dialer.c_feedback = SPEAKERON|NORMSPK|RINGON; /* control speaker */ 5674: #else 5675: /* sys/phone says RINGON used only for incoming voice calls */ 5676: dialer.c_feedback &= ~(SOFTSPK|LOUDSPK); 5677: dialer.c_feedback |= SPEAKERON|NORMSPK; 5678: #endif 5679: dialer.c_waitflash = 500; /* 0.5 sec flash hook */ 5680: if(ioctl(ttyfd,PIOCSETP,&dialer) == -1) { /* set phone parameters */ 5681: printf("Cannot set modem characteristics\n"); 5682: ttclos(0); 5683: return (-2); 5684: } 5685: ioctl(ttyfd,PIOCRECONN,0); /* Turns on speaker for pulse */ 5686: 5687: #ifdef COMMENT 5688: fprintf(stderr,"Phone line status. line_par:%o dialtone_wait:%o \ 5689: line_status:%o feedback:%o\n", 5690: dialer.c_lineparam, dialer.c_waitdialtone, 5691: dialer.c_linestatus, dialer.c_feedback); 5692: #endif 5693: 5694: attmodem |= ISMODEM; /* modem is now in-use */ 5695: sleep(1); 5696: for (telnum = telnbr; *telnum != '\0'; telnum++) /* dial number */ 5697: #ifdef ATTTONED 5698: /* Tone dialing only */ 5699: if (ioctl(ttyfd,PIOCDIAL,telnum) != 0) { 5700: perror("Error in dialing"); 5701: ttclos(0); 5702: return(-2); 5703: } 5704: #else /* Allow Pulse or Tone dialing */ 5705: switch (*telnum) { 5706: case 't': case 'T': case '%': /* Tone dialing requested */ 5707: dialer.c_lineparam |= DTMF; 5708: dialer.c_lineparam &= ~PULSE; 5709: if (ioctl(ttyfd,PIOCSETP,&dialer) == -1) { 5710: printf("Cannot set modem to tone dialing\n"); 5711: ttclos(0); 5712: return(-2); 5713: } 5714: break; 5715: case 'd': case 'D': case 'p': case 'P': case '^': 5716: dialer.c_lineparam |= PULSE; 5717: dialer.c_lineparam &= ~DTMF; 5718: if (ioctl(ttyfd,PIOCSETP,&dialer) == -1) { 5719: printf("Cannot set modem to pulse dialing\n"); 5720: ttclos(0); 5721: return(-2); 5722: } 5723: break; 5724: default: 5725: if (ioctl(ttyfd,PIOCDIAL,telnum) != 0) { 5726: perror("Dialing error"); 5727: ttclos(0); 5728: return(-2); 5729: } 5730: break; 5731: } 5732: #endif 5733: 5734: ioctl(ttyfd,PIOCDIAL,"@"); /* terminator for data call */ 5735: do { /* wait for modems to Connect */ 5736: if (ioctl(ttyfd,PIOCGETP,&dialer) != 0) { /* get params */ 5737: perror("Cannot get modems to connect"); 5738: ttclos(0); 5739: return(-2); 5740: } 5741: } while ((dialer.c_linestatus & MODEMCONNECTED) == 0); 5742: /* Turn off O_NDELAY flag now. */ 5743: fcntl(ttyfd, F_SETFL, fcntl(ttyfd, F_GETFL, 0) & ~O_NDELAY); 5744: signal(SIGHUP, ttclos); /* hangup on loss of carrier */ 5745: return(0); /* return success */ 5746: } 5747: 5748: /* 5749: Offgetty, ongetty functions. These function get the 'getty(1m)' off 5750: and restore it to the indicated line. Shell's return codes are: 5751: 0: Can't do it. Probably a user logged on. 5752: 1: No need. No getty on that line. 5753: 2: Done, you should restore the getty when you're done. 5754: DOGETY System(3), however, returns them as 0, 256, 512, respectively. 5755: Thanks to Kevin O'Gorman, Anarm Software Systems. 5756: 5757: getoff.sh looks like: geton.sh looks like: 5758: setgetty $1 0 setgetty $1 1 5759: err=$? exit $? 5760: sleep 2 5761: exit $err 5762: */ 5763: 5764: /* O F F G E T T Y -- Turn off getty(1m) for the communications tty line 5765: * and get status so it can be restarted after the line is hung up. 5766: */ 5767: int 5768: offgetty(ttname) char *ttname; { 5769: char temp[30]; 5770: while (*ttname != '\0') ttname++; /* seek terminator of path */ 5771: ttname -= 3; /* get last 3 chars of name */ 5772: sprintf(temp,"/usr/bin/getoff.sh %s",ttname); 5773: return(zsyscmd(temp)); 5774: } 5775: 5776: /* O N G E T T Y -- Turn on getty(1m) for the communications tty line */ 5777: 5778: int 5779: ongetty(ttname) char *ttname; { 5780: char temp[30]; 5781: while (*ttname != '\0') ttname++; /* comms tty path name */ 5782: ttname -= 3; 5783: sprintf(temp,"/usr/bin/geton.sh %s",ttname); 5784: return(zsyscmd(temp)); 5785: } 5786: #endif /* ATT7300 */ 5787: 5788: /* T T S C A R R -- Set ttcarr variable, controlling carrier handling. 5789: * 5790: * 0 = Off: Always ignore carrier. E.g. you can connect without carrier. 5791: * 1 = On: Heed carrier, except during dialing. Carrier loss gives disconnect. 5792: * 2 = Auto: For "modem direct": The same as "Off". 5793: * For real modem types: Heed carrier during connect, but ignore 5794: * it anytime else. Compatible with pre-5A C-Kermit versions. 5795: * 5796: * As you can see, this setting does not affect dialing, which always ignores 5797: * carrier (unless there is some special exception for some modem type). It 5798: * does affect ttopen() if it is set before ttopen() is used. This setting 5799: * takes effect on the next call to ttopen()/ttpkt()/ttvt(). And they are 5800: * (or should be) always called before any communications is tried, which 5801: * means that, practically speaking, the effect is immediate. 5802: * 5803: * Of course, nothing of this applies to remote mode (xlocal = 0). 5804: * 5805: * Someone has yet to uncover how to manipulate the carrier in the BSD 5806: * environment (or any non-termio using environment). Until that time, this 5807: * will simply be a no-op for BSD. 5808: * 5809: * Note that in previous versions, the carrier was most often left unchanged 5810: * in ttpkt()/ttvt() unless they were called with FLO_DIAL or FLO_DIAX. This 5811: * has changed. Now it is controlled by ttcarr in conjunction with these 5812: * modes. 5813: */ 5814: int 5815: ttscarr(carrier) int carrier; { 5816: ttcarr = carrier; 5817: debug(F101, "ttscarr","",ttcarr); 5818: return(ttcarr); 5819: } 5820: 5821: /* C A R R C T L -- Set tty modes for carrier treatment. 5822: * 5823: * Sets the appropriate bits in a termio or sgttyb struct for carrier control 5824: * (actually, there are no bits in sgttyb for that), or performs any other 5825: * operations needed to control this on the current system. The function does 5826: * not do the actual TCSETA or stty, since often we want to set other bits too 5827: * first. Don't call this function when xlocal is 0, or the tty is not opened. 5828: * 5829: * We don't know how to do anything like carrier control on non-ATTSV systems, 5830: * except, apparently, ultrix. See above. It is also known that this doesn't 5831: * have much effect on a Xenix system. For Xenix, one should switch back and 5832: * forth between the upper and lower case device files. Maybe later. 5833: * Presently, Xenix will stick to the mode it was opened with. 5834: * 5835: * carrier: 0 = ignore carrier, 1 = require carrier. 5836: * The current state is saved in curcarr, and checked to save labour. 5837: */ 5838: #ifdef SVORPOSIX 5839: int 5840: #ifdef BSD44ORPOSIX 5841: carrctl(ttpar, carrier) struct termios *ttpar; int carrier; 5842: #else /* ATTSV */ 5843: carrctl(ttpar, carrier) struct termio *ttpar; int carrier; 5844: #endif /* BSD44ORPOSIX */ 5845: /* carrctl */ { 5846: debug(F101, "carrctl","",carrier); 5847: if (carrier) 5848: ttpar->c_cflag &= ~CLOCAL; 5849: else 5850: ttpar->c_cflag |= CLOCAL; 5851: return(0); 5852: } 5853: #else /* Berkeley, V7, et al... */ 5854: int 5855: carrctl(ttpar, carrier) struct sgttyb *ttpar; int carrier; { 5856: #ifdef ultrix 5857: int temp = 0; 5858: #endif /* ultrix */ 5859: #ifdef OXOS 5860: int modem_status, lnohang = LNOHANG; 5861: #endif /* OXOS */ 5862: debug(F101, "carrctl","",carrier); 5863: if (carrier == curcarr) 5864: return(0); 5865: curcarr = carrier; 5866: #ifdef ultrix 5867: if (carrier) { 5868: ioctl(ttyfd, TIOCMODEM, &temp); 5869: ioctl(ttyfd, TIOCHPCL, 0); 5870: } else { 5871: /* (According to the manuals, TIOCNCAR should be preferred */ 5872: /* over TIOCNMODEM...) */ 5873: ioctl(ttyfd, TIOCNMODEM, &temp); 5874: } 5875: #endif /* ultrix */ 5876: #ifdef OXOS 5877: /* 5878: From Fulvio Marino at Olivetti. This code allows CONNECT to work even 5879: if DCD/RTS are down, if "carrier" is set appropriately. 5880: */ 5881: if (ioctl(ttyfd, TIOCMODG, &modem_status) == 0) { 5882: if (carrier) { 5883: /* enable carrier detect */ 5884: modem_status |= TIOCM_CAR; 5885: } else { 5886: /* disable carrier detect */ 5887: modem_status &= ~TIOCM_CAR; 5888: } 5889: (void)ioctl(ttyfd, TIOCMODS, &modem_status); 5890: } 5891: if (carrier) { 5892: /* Send hangup when carrier drops */ 5893: (void)ioctl(ttyfd, TIOCLBIC, &lnohang); 5894: /* hang up the phone */ 5895: (void)ioctl(ttyfd, TIOCHPCL, NULL); 5896: } else { 5897: /* Don't send hangup when carrier drops */ 5898: (void)ioctl(ttyfd, TIOCLBIS, &lnohang); 5899: } 5900: #endif /* OXOS */ 5901: return(0); 5902: } 5903: #endif /* SVORPOSIX */ 5904: 5905: 5906: /* T T G M D M -- Get modem signals */ 5907: /* 5908: Looks for RS-232 modem signals, and returns those that are on in as its 5909: return value, in a bit mask composed of the BM_xxx values defined in ckcdeb.h. 5910: Returns: 5911: -3 Not implemented 5912: -2 if the communication device does not have modem control (e.g. telnet) 5913: -1 on error. 5914: >= 0 on success, with a bit mask containing the modem signals that are on. 5915: */ 5916: 5917: /* 5918: Define the symbol K_MDMCTL if we have Sys V R3 / 4.3 BSD style 5919: modem control, namely the TIOCMGET ioctl. 5920: */ 5921: 5922: #ifdef BSD43 5923: #define K_MDMCTL 5924: #endif 5925: 5926: #ifdef SUNOS4 5927: #define K_MDMCTL 5928: #endif 5929: 5930: #ifdef TIOCMGET 5931: #define K_MDMCTL 5932: #endif 5933: 5934: int 5935: ttgmdm() { 5936: 5937: #ifdef HPUX /* HPUX has its own way */ 5938: 5939: /* 5940: NOTE: I don't have an HPUX man page, and so I'm only guessing at the 5941: right names for these symbols. Somebody with HPUX please let me know 5942: what corrections are needed. 5943: */ 5944: 5945: int x, y, z; 5946: 5947: if (netconn) return(-2); /* No modem signals for network */ 5948: if (xlocal) /* Get modem signals */ 5949: x = ioctl(ttyfd,MCGETA,&y); 5950: else 5951: x = ioctl(0,MCGETA,&y); 5952: if (x < 0) return(-1); 5953: debug(F101,"ttgmdm","",y); 5954: 5955: z = 0; /* Initialize return value */ 5956: 5957: /* Now set bits for each modem signal that is reported to be on. */ 5958: 5959: #ifdef MCTS 5960: /* Clear To Send */ 5961: if (y & MCTS) z |= BM_CTS; 5962: #endif 5963: #ifdef MDSR 5964: /* Data Set Ready */ 5965: if (y & MDSR) z |= BM_DSR; 5966: #endif 5967: #ifdef MDCD 5968: /* Carrier */ 5969: if (y & MDCD) z |= BM_DCD; 5970: #endif 5971: #ifdef MRNG 5972: /* Ring Indicate */ 5973: if (y & MRNG) z |= BM_RNG; 5974: #endif 5975: #ifdef MDTR 5976: /* Data Terminal Ready */ 5977: if (y & MDTR) z |= BM_DTR; 5978: #endif 5979: #ifdef MRTS 5980: /* Request To Send */ 5981: if (y & MRTS) z |= BM_RTS; 5982: #endif 5983: return(z); 5984: 5985: #else /* ! HPUX */ 5986: 5987: #ifdef K_MDMCTL 5988: /* 5989: Note, <sys/ttycom> might have already been included by by <sys/ioctl.h>. 5990: Hence the following ifndef on a symbol which is defined there. 5991: */ 5992: #ifndef TIOCMGET 5993: #include <sys/ttycom.h> 5994: #endif /* TIOCMGET */ 5995: 5996: int x, y, z; 5997: 5998: if (netconn) return(-2); /* Network, no modem signals. */ 5999: if (xlocal) 6000: x = ioctl(ttyfd,TIOCMGET,&y); /* Get modem signals. */ 6001: else 6002: x = ioctl(0,TIOCMGET,&y); 6003: if (x < 0) return(-1); 6004: debug(F101,"ttgmdm","",y); 6005: 6006: z = 0; /* Initialize return value. */ 6007: #ifdef TIOCM_CTS 6008: /* Clear To Send */ 6009: if (y & TIOCM_CTS) z |= BM_CTS; 6010: #endif 6011: #ifdef TIOCM_DSR 6012: /* Data Set Ready */ 6013: if (y & TIOCM_DSR) z |= BM_DSR; 6014: #endif 6015: #ifdef TIOCM_CAR 6016: /* Carrier */ 6017: if (y & TIOCM_CAR) z |= BM_DCD; 6018: #endif 6019: #ifdef TIOCM_RNG 6020: /* Ring Indicate */ 6021: if (y & TIOCM_RNG) z |= BM_RNG; 6022: #endif 6023: #ifdef TIOCM_DTR 6024: /* Data Terminal Ready */ 6025: if (y & TIOCM_DTR) z |= BM_DTR; 6026: #endif 6027: #ifdef TIOCM_RTS 6028: /* Request To Send */ 6029: if (y & TIOCM_RTS) z |= BM_RTS; 6030: #endif 6031: return(z); 6032: #else 6033: if (netconn) return(-2); 6034: return(-3); 6035: 6036: #endif /* K_MDMCTL */ 6037: #endif /* HPUX */ 6038: } 6039: 6040: /* P S U S P E N D -- Put this process in the background. */ 6041: 6042: /* 6043: Call with flag nonzero if suspending is allowed, zero if not allowed. 6044: Returns 0 on apparent success, -1 on failure (flag was zero, or 6045: kill() returned an error code. 6046: */ 6047: int 6048: psuspend(flag) int flag; { 6049: 6050: #ifdef RTU 6051: extern int rtu_bug; 6052: #endif /* RTU */ 6053: 6054: if (flag == 0) return(-1); 6055: 6056: #ifdef NOJC 6057: return(-1); 6058: #else 6059: #ifdef SIGTSTP 6060: /* 6061: The big question here is whether job control is *really* supported. 6062: There's no way Kermit can know for sure. The fact that SIGTSTP is 6063: defined does not guarantee the Unix kernel supports it, and the fact 6064: that the Unix kernel supports it doesn't guarantee that the user's 6065: shell (or other process that invoked Kermit) supports it. 6066: */ 6067: #ifdef RTU 6068: rtu_bug = 1; 6069: #endif /* RTU */ 6070: if (kill(0,SIGSTOP) < 0 6071: #ifdef OXOS 6072: /* 6073: Because "kill(myself,SIGSTOP)" can't be caught, blocked, or ignored..." 6074: */ 6075: && kill(getpid(),SIGSTOP) < 0 6076: #else 6077: #ifdef MIPS 6078: /* Let's try this for MIPS too. */ 6079: && kill(getpid(),SIGSTOP) < 0 6080: #endif /* MIPS */ 6081: #endif /* OXOS */ 6082: ) { /* If job control, suspend the job */ 6083: perror("suspend"); 6084: debug(F101,"psuspend error","",errno); 6085: return(-1); 6086: } 6087: debug(F100,"psuspend ok","",0); 6088: return(0); 6089: #else 6090: return(-1); 6091: #endif /* SIGTSTP */ 6092: #endif /* NOJC */ 6093: } 6094: 6095: /* 6096: setuid package, by Kristoffer Eriksson, with contributions from Dean 6097: Long and fdc. 6098: */ 6099: 6100: #ifndef _POSIX_SOURCE 6101: #ifndef SUNOS4 6102: #ifndef NEXT 6103: #ifndef PS2AIX10 6104: extern UID_T getuid(), geteuid(), getreuid(); 6105: extern GID_T getgid(), getegid(), getregid(); 6106: #endif /* PS2AIX10 */ 6107: #endif /* NEXT */ 6108: #endif /* SUNOS4 */ 6109: #endif /* _POSIX_SOURCE */ 6110: 6111: /* 6112: Subject: Set-user-id 6113: To: fdc@watsun.cc.columbia.edu (Frank da Cruz) 6114: Date: Sat, 21 Apr 90 4:48:25 MES 6115: From: Kristoffer Eriksson <ske@pkmab.se> 6116: 6117: This is a set of functions to be used in programs that may be run set-user-id 6118: and/or set-group-id. They handle both the case where the program is not run 6119: with such privileges (nothing special happens then), and the case where one 6120: or both of these set-id modes are used. The program is made to run with the 6121: user's real user and group ids most of the time, except for when more 6122: privileges are needed. Don't set-user-id to "root". 6123: 6124: This works on System V and POSIX. In BSD, it depends on the 6125: "saved-set-user-id" feature. 6126: */ 6127: 6128: #define UID_ROOT 0 /* Root user and group ids */ 6129: #define GID_ROOT 0 6130: 6131: /* 6132: The following construction automatically defines the symbol SETREUID for 6133: Unix versions based on Berkeley Unix 4.2 or later. If this symbol is 6134: defined, then this program will use getreuid() and getregid() calls in 6135: preference to getuid() and getgid(), which in Berkeley-based Unixes do 6136: not allow arbitrary switching back and forth of real & effective uid. 6137: This construction also allows -DSETREUID to be put on the cc command line 6138: for any system that has and wants to use setre[ug]id(). It also prevents 6139: automatic definition of SETREUID if -DNOSETREU is included on the cc 6140: command line (or otherwise defined). 6141: */ 6142: #ifdef FT18 /* None of this for Fortune. */ 6143: #define NOSETREU 6144: #endif /* FT18 */ 6145: 6146: #ifdef ANYBSD 6147: #ifndef BSD29 6148: #ifndef BSD41 6149: #ifndef SETREUID 6150: #ifndef NOSETREU 6151: #define SETREUID 6152: #endif /* NOSETREU */ 6153: #endif /* SETREUID */ 6154: #endif /* !BSD41 */ 6155: #endif /* !BSD29 */ 6156: #endif /* ANYBSD */ 6157: 6158: /* Variables for user and group IDs. */ 6159: 6160: static UID_T realuid = (UID_T) -1, privuid = (UID_T) -1; 6161: static GID_T realgid = (GID_T) -1, privgid = (GID_T) -1; 6162: 6163: 6164: /* P R I V _ I N I -- Initialize privileges package */ 6165: 6166: /* Called as early as possible in a set-uid or set-gid program to store the 6167: * set-to uid and/or gid and step down to the users real uid and gid. The 6168: * stored id's can be temporarily restored (allowed in System V) during 6169: * operations that require the privilege. Most of the time, the program 6170: * should execute in unpriviliged state, to not impose any security threat. 6171: * 6172: * Note: Don't forget that access() always uses the real id:s to determine 6173: * file access, even with privileges restored. 6174: * 6175: * Returns an error mask, with error values or:ed together: 6176: * 1 if setuid() fails, 6177: * 2 if setgid() fails, and 6178: * 4 if the program is set-user-id to "root", which can't be handled. 6179: * 6180: * Only the return value 0 indicates real success. In case of failure, 6181: * those privileges that could be reduced have been, at least, but the 6182: * program should be aborted none-the-less. 6183: * 6184: * Also note that these functions do not expect the uid or gid to change 6185: * without their knowing. It may work if it is only done temporarily, but 6186: * you're on your own. 6187: */ 6188: int 6189: priv_ini() { 6190: int err = 0; 6191: 6192: /* Save real ID:s. */ 6193: realuid = getuid(); 6194: realgid = getgid(); 6195: 6196: /* Save current effective ID:s, those set to at program exec. */ 6197: privuid = geteuid(); 6198: privgid = getegid(); 6199: 6200: /* If running set-uid, go down to real uid, otherwise remember that 6201: * no privileged uid is available. 6202: * 6203: * Exceptions: 6204: * 6205: * 1) If the real uid is already "root" and the set-uid uid (the 6206: * initial effective uid) is not "root", then we would have trouble 6207: * if we went "down" to "root" here, and then temporarily back to the 6208: * set-uid uid (not "root") and then again tried to become "root". I 6209: * think the "saved set-uid" is lost when changing uid from effective 6210: * uid "root", which changes all uid, not only the effective uid. But 6211: * in this situation, we can simply go to "root" and stay there all 6212: * the time. That should give sufficient privilege (understatement!), 6213: * and give the right uids for subprocesses. 6214: * 6215: * 2) If the set-uid (the initial effective uid) is "root", and we 6216: * change uid to the real uid, we can't change it back to "root" when 6217: * we need the privilege, for the same reason as in 1). Thus, we can't 6218: * handle programs that are set-user-id to "root" at all. The program 6219: * should be aborted. Use some other uid. "root" is probably to 6220: * privileged for such things, anyway. (The uid is reverted to the 6221: * real uid until abortion.) 6222: * 6223: * These two exceptions have the effect that the "root" uid will never 6224: * be one of the two uids that are being switched between, which also 6225: * means we don't have to check for such cases in the switching 6226: * functions. 6227: * 6228: * Note that exception 1) is handled by these routines (by constantly 6229: * running with uid "root", while exception 2) is a serious error, and 6230: * is not provided for at all in the switching functions. 6231: */ 6232: if (realuid == privuid) 6233: privuid = (UID_T) -1; /* Not running set-user-id. */ 6234: 6235: /* If running set-gid, go down to real gid, otherwise remember that 6236: * no privileged gid is available. 6237: * 6238: * There are no exception like there is for the user id, since there 6239: * is no group id that is privileged in the manner of uid "root". 6240: * There could be equivalent problems for group changing if the 6241: * program sometimes ran with uid "root" and sometimes not, but 6242: * that is already avoided as explained above. 6243: * 6244: * Thus we can expect always to be able to switch to the "saved set- 6245: * gid" when we want, and back to the real gid again. You may also 6246: * draw the conclusion that set-gid provides for fewer hassles than 6247: * set-uid. 6248: */ 6249: 6250: if (realgid == privgid) /* If not running set-user-id, */ 6251: privgid = (GID_T) -1; /* remember it this way. */ 6252: 6253: err = priv_off(); /* Turn off setuid privilege. */ 6254: 6255: if (privuid == UID_ROOT) /* If setuid to root, */ 6256: err |= 4; /* return this error. */ 6257: 6258: if (realuid == UID_ROOT) /* If real id is root, */ 6259: privuid = (UID_T) -1; /* stay root at all times. */ 6260: 6261: return(err); 6262: } 6263: 6264: 6265: /* Macros for hiding the differences in UID/GID setting between various Unix 6266: * systems. These macros should always be called with both the privileged ID 6267: * and the non-privileged ID. The one in the second argument, will become the 6268: * effective ID. The one in the first argument will be retained for later 6269: * retrieval. 6270: */ 6271: #ifdef SETREUID 6272: #ifdef SAVEDUID 6273: /* On BSD systems with the saved-UID feature, we just juggle the effective 6274: * UID back and forth, and leave the real UID at its true value. The kernel 6275: * allows switching to both the current real UID, the effective UID, and the 6276: * UID which the program is set-UID to. The saved set-UID always holds the 6277: * privileged UID for us, and the real UID will always be the non-privileged, 6278: * and we can freely choose one of them for the effective UID at any time. 6279: */ 6280: #define switchuid(hidden,active) setreuid( (UID_T) -1, active) 6281: #define switchgid(hidden,active) setregid( (GID_T) -1, active) 6282: 6283: #else /* SETREUID,!SAVEDUID */ 6284: 6285: /* On systems with setreXid() but without the saved-UID feature, notably 6286: * BSD 4.2, we swap the real and effective UIDs each time. It's 6287: * the effective UID that we are interrested in, but we have to retain the 6288: * unused UID somewhere to enable us to restore it later, and that we do this 6289: * in the real UID. The kernel only allows switching to either the current 6290: * real or the effective UID, unless you're "root". 6291: */ 6292: #define switchuid(hidden,active) setreuid(hidden,active) 6293: #define switchgid(hidden,active) setregid(hidden,active) 6294: #endif 6295: 6296: #else /* !SETREUID, !SAVEDUID */ 6297: 6298: /* On System V and POSIX, the only thing we can change is the effective UID 6299: * (unless the current effective UID is "root", but initsuid() avoids that for 6300: * us). The kernel allows switching to the current real UID or to the saved 6301: * set-UID. These are always set to the non-privileged UID and the privileged 6302: * UID, respectively, and we only change the effective UID. This breaks if 6303: * the current effective UID is "root", though, because for "root" setuid/gid 6304: * becomes more powerful, which is why initsuid() treats "root" specially. 6305: * Note: That special treatment maybe could be ignored for BSD? Note: For 6306: * systems that don't fit any of these three cases, we simply can't support 6307: * set-UID. 6308: */ 6309: #define switchuid(hidden,active) setuid(active) 6310: #define switchgid(hidden,active) setgid(active) 6311: #endif /* SETREUID */ 6312: 6313: 6314: /* P R I V _ O N -- Turn on the setuid and/or setgid */ 6315: 6316: /* Go to the privileged uid (gid) that the program is set-user-id 6317: * (set-group-id) to, unless the program is running unprivileged. 6318: * If setuid() fails, return value will be 1. If getuid() fails it 6319: * will be 2. Return immediately after first failure, and the function 6320: * tries to restore any partial work done. Returns 0 on success. 6321: * Group id is changed first, since it is less serious than user id. 6322: */ 6323: int 6324: priv_on() { 6325: if (privgid != (GID_T) -1) 6326: if (switchgid(realgid,privgid)) 6327: return(2); 6328: 6329: if (privuid != (UID_T) -1) 6330: if (switchuid(realuid,privuid)) { 6331: if (privgid != (GID_T) -1) 6332: switchgid(privgid,realgid); 6333: return(1); 6334: } 6335: return(0); 6336: } 6337: 6338: /* P R I V _ O F F -- Turn on the real uid and gid */ 6339: 6340: /* Return to the unprivileged uid (gid) after an temporary visit to 6341: * privileged status, unless the program is running without set-user-id 6342: * (set-group-id). Returns 1 for failure in setuid() and 2 for failure 6343: * in setgid() or:ed together. The functions tries to return both uid 6344: * and gid to unprivileged state, regardless of errors. Returns 0 on 6345: * success. 6346: */ 6347: int 6348: priv_off() { 6349: int err = 0; 6350: 6351: if (privuid != (UID_T) -1) 6352: if (switchuid(privuid,realuid)) 6353: err |= 1; 6354: 6355: if (privgid != (GID_T) -1) 6356: if (switchgid(privgid,realgid)) 6357: err |= 2; 6358: 6359: return(err); 6360: } 6361: 6362: /* Turn off privilege permanently. No going back. This is necessary before 6363: * a fork() on BSD43 machines that don't save the setUID or setGID, because 6364: * we swap the real and effective ids, and we don't want to let the forked 6365: * process swap them again and get the privilege back. It will work on other 6366: * machines too, such that you can rely on its effect always being the same, 6367: * for instance, even when you're in priv_on() state when this is called. 6368: * (Well, that part about "permanent" is on System V only true if you follow 6369: * this with a call to exec(), but that's what we want it for anyway.) 6370: * Added by Dean Long -- dlong@midgard.ucsc.edu 6371: */ 6372: int 6373: priv_can() { 6374: 6375: #ifdef SETREUID 6376: int err = 0; 6377: if (privuid != (UID_T) -1) 6378: if (setreuid(realuid,realuid)) 6379: err |= 1; 6380: 6381: if (privgid != (GID_T) -1) 6382: if (setregid(realgid,realgid)) 6383: err |= 2; 6384: 6385: return(err); 6386: 6387: #else 6388: /* Easy way of using setuid()/setgid() instead of setreuid()/setregid().*/ 6389: return(priv_off()); 6390: 6391: #endif /* SETREUID */ 6392: } 6393: 6394: /* P R I V _ O P N -- For opening protected files or devices. */ 6395: 6396: int 6397: priv_opn(name, modes) char *name; int modes; { 6398: int x; 6399: priv_on(); /* Turn privileges on */ 6400: x = open(name, modes); /* Try to open the device */ 6401: priv_off(); /* Turn privileges off */ 6402: return(x); /* Return open's return code */ 6403: } 6404: 6405: /* P R I V _ C H K -- Check privileges. */ 6406: 6407: /* Try to turn them off. If turning them off did not succeed, cancel them */ 6408: 6409: int 6410: priv_chk() { 6411: int x, y = 0; 6412: x = priv_off(); /* Turn off privs. */ 6413: if (x != 0 || getuid() == privuid || geteuid() == privuid) 6414: y = priv_can(); 6415: if (x != 0 || getgid() == privgid || getegid() == privgid) 6416: y = y | priv_can(); 6417: return(y); 6418: } 6419: 6420: UID_T 6421: real_uid() { 6422: return(realuid); 6423: } 6424: 6425: VOID 6426: ttimoff() { /* Turn off any timer interrupts */ 6427: int xx; 6428: /* 6429: As of 5A(183), we set SIGALRM to SIG_IGN (to ignore alarms) rather than to 6430: SIG_DFL (to catch alarms, or if there is no handler, to exit). This is to 6431: cure (mask, really) a deeper problem with stray alarms that occurs on some 6432: systems, possibly having to do with sleep(), that caused core dumps. It 6433: should be OK to do this, because no code in this module uses nested alarms. 6434: (But we still have to watch out for SCRIPT and DIAL...) 6435: */ 6436: xx = alarm(0); 6437: /* debug(F101,"ttimoff alarm","",xx); */ 6438: if (saval) { /* Restore any previous */ 6439: signal(SIGALRM,saval); /* alarm handler. */ 6440: /* debug(F101,"ttimoff alarm restoring saval","",saval); */ 6441: saval = NULL; 6442: } else { 6443: signal(SIGALRM,SIG_IGN); /* Used to be SIG_DFL */ 6444: /* debug(F100,"ttimoff alarm SIG_IGN","",0); */ 6445: } 6446: }