10Sstevel@tonic-gate /* 2*9354STim.Marsland@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 30Sstevel@tonic-gate * Use is subject to license terms. 40Sstevel@tonic-gate */ 5549Smuffin 60Sstevel@tonic-gate /* 70Sstevel@tonic-gate * Copyright (c) 1983 Regents of the University of California. 80Sstevel@tonic-gate * All rights reserved. The Berkeley software License Agreement 90Sstevel@tonic-gate * specifies the terms and conditions for redistribution. 100Sstevel@tonic-gate */ 110Sstevel@tonic-gate 120Sstevel@tonic-gate /* 130Sstevel@tonic-gate * tip - UNIX link to other systems 140Sstevel@tonic-gate * tip [-v] [-speed] system-name 150Sstevel@tonic-gate * or 160Sstevel@tonic-gate * cu phone-number [-s speed] [-l line] [-a acu] 170Sstevel@tonic-gate */ 180Sstevel@tonic-gate #include "tip.h" 190Sstevel@tonic-gate #include <sys/wait.h> 200Sstevel@tonic-gate #include <locale.h> 210Sstevel@tonic-gate 220Sstevel@tonic-gate /* 230Sstevel@tonic-gate * Baud rate mapping table 240Sstevel@tonic-gate */ 250Sstevel@tonic-gate int bauds[] = { 260Sstevel@tonic-gate 0, 50, 75, 110, 134, 150, 200, 300, 600, 270Sstevel@tonic-gate 1200, 1800, 2400, 4800, 9600, 19200, 38400, 28*9354STim.Marsland@Sun.COM 57600, 76800, 115200, 153600, 230400, 307200, 29*9354STim.Marsland@Sun.COM 460800, 921600, -1 300Sstevel@tonic-gate }; 310Sstevel@tonic-gate 32549Smuffin extern void tipout(void) __NORETURN; 33549Smuffin extern void timeout(void); 34549Smuffin extern esctable_t etable[]; 35549Smuffin extern unsigned char evenpartab[]; 36549Smuffin 37549Smuffin void intprompt(void); 38549Smuffin void deadkid(void); 39549Smuffin void cleanup(void); 40549Smuffin void tipin(void) __NORETURN; 41549Smuffin unsigned char escape(void); 42549Smuffin char *sname(char *); 43549Smuffin char PNbuf[256]; /* This limits the size of a number */ 440Sstevel@tonic-gate int noparity = 0; 450Sstevel@tonic-gate 46549Smuffin int 47549Smuffin main(int argc, char *argv[]) 480Sstevel@tonic-gate { 490Sstevel@tonic-gate char *system = NOSTR; 50549Smuffin int i; 51549Smuffin char *p; 522590Ssn199410 char sbuf[15]; 530Sstevel@tonic-gate 540Sstevel@tonic-gate gid = getgid(); 550Sstevel@tonic-gate egid = getegid(); 560Sstevel@tonic-gate uid = getuid(); 570Sstevel@tonic-gate euid = geteuid(); 580Sstevel@tonic-gate if (equal(sname(argv[0]), "cu")) { 590Sstevel@tonic-gate cumode = 1; 600Sstevel@tonic-gate cumain(argc, argv); 610Sstevel@tonic-gate goto cucommon; 620Sstevel@tonic-gate } 630Sstevel@tonic-gate 640Sstevel@tonic-gate if (argc > 4) { 65549Smuffin (void) fprintf(stderr, 66549Smuffin "usage: tip [-v] [-speed] [system-name]\n"); 67549Smuffin return (1); 680Sstevel@tonic-gate } 690Sstevel@tonic-gate if (!isatty(0)) { 70549Smuffin (void) fprintf(stderr, "tip: must be interactive\n"); 71549Smuffin return (1); 720Sstevel@tonic-gate } 730Sstevel@tonic-gate 740Sstevel@tonic-gate for (; argc > 1; argv++, argc--) { 750Sstevel@tonic-gate if (argv[1][0] != '-') 760Sstevel@tonic-gate system = argv[1]; 770Sstevel@tonic-gate else switch (argv[1][1]) { 780Sstevel@tonic-gate 790Sstevel@tonic-gate case 'v': 800Sstevel@tonic-gate vflag++; 810Sstevel@tonic-gate break; 820Sstevel@tonic-gate 830Sstevel@tonic-gate case '0': case '1': case '2': case '3': case '4': 840Sstevel@tonic-gate case '5': case '6': case '7': case '8': case '9': 850Sstevel@tonic-gate BR = atoi(&argv[1][1]); 860Sstevel@tonic-gate break; 870Sstevel@tonic-gate 880Sstevel@tonic-gate default: 89549Smuffin (void) fprintf(stderr, "tip: %s, unknown option\n", 90549Smuffin argv[1]); 910Sstevel@tonic-gate break; 920Sstevel@tonic-gate } 930Sstevel@tonic-gate } 940Sstevel@tonic-gate 950Sstevel@tonic-gate (void) setlocale(LC_CTYPE, ""); 960Sstevel@tonic-gate 970Sstevel@tonic-gate if (system == NOSTR) 980Sstevel@tonic-gate goto notnumber; 990Sstevel@tonic-gate for (p = system; *p; p++) 1000Sstevel@tonic-gate if (isalpha(*p)) 1010Sstevel@tonic-gate goto notnumber; 1020Sstevel@tonic-gate /* 1030Sstevel@tonic-gate * System name is really a phone number... 1040Sstevel@tonic-gate * Copy the number then stomp on the original (in case the number 1050Sstevel@tonic-gate * is private, we don't want 'ps' or 'w' to find it). 1060Sstevel@tonic-gate */ 1070Sstevel@tonic-gate if (strlen(system) > sizeof (PNbuf) - 1) { 108549Smuffin (void) fprintf(stderr, 109549Smuffin "tip: phone number too long (max = %d bytes)\n", 1100Sstevel@tonic-gate sizeof (PNbuf) - 1); 111549Smuffin return (1); 1120Sstevel@tonic-gate } 113549Smuffin (void) strncpy(PNbuf, system, sizeof (PNbuf) - 1); 1140Sstevel@tonic-gate for (p = system; *p; p++) 1150Sstevel@tonic-gate *p = '\0'; 1160Sstevel@tonic-gate PN = PNbuf; 1172590Ssn199410 (void) snprintf(sbuf, sizeof (sbuf), "tip%d", BR); 1180Sstevel@tonic-gate system = sbuf; 1190Sstevel@tonic-gate 1200Sstevel@tonic-gate notnumber: 121549Smuffin (void) signal(SIGINT, (sig_handler_t)cleanup); 122549Smuffin (void) signal(SIGQUIT, (sig_handler_t)cleanup); 123549Smuffin (void) signal(SIGHUP, (sig_handler_t)cleanup); 124549Smuffin (void) signal(SIGTERM, (sig_handler_t)cleanup); 1250Sstevel@tonic-gate 1260Sstevel@tonic-gate if ((i = hunt(system)) == 0) { 127549Smuffin (void) printf("all ports busy\n"); 128549Smuffin return (3); 1290Sstevel@tonic-gate } 1300Sstevel@tonic-gate if (i == -1) { 131549Smuffin (void) printf("link down\n"); 1320Sstevel@tonic-gate delock(uucplock); 133549Smuffin return (3); 1340Sstevel@tonic-gate } 1350Sstevel@tonic-gate setbuf(stdout, NULL); 1360Sstevel@tonic-gate loginit(); 1370Sstevel@tonic-gate 1380Sstevel@tonic-gate /* 1390Sstevel@tonic-gate * Now that we have the logfile and the ACU open 1400Sstevel@tonic-gate * return to the real uid and gid. These things will 1410Sstevel@tonic-gate * be closed on exit. The saved-setuid uid and gid 1420Sstevel@tonic-gate * allows us to get the original setuid permissions back 1430Sstevel@tonic-gate * for removing the uucp lock. 1440Sstevel@tonic-gate */ 1450Sstevel@tonic-gate userperm(); 1460Sstevel@tonic-gate 1470Sstevel@tonic-gate /* 1480Sstevel@tonic-gate * Kludge, there's no easy way to get the initialization 1490Sstevel@tonic-gate * in the right order, so force it here. 1500Sstevel@tonic-gate * Do the open here, before we change back to real uid. 1510Sstevel@tonic-gate * We will check whether the open succeeded later, when 1520Sstevel@tonic-gate * (and if) we actually go to use the file. 1530Sstevel@tonic-gate */ 1540Sstevel@tonic-gate if ((PH = getenv("PHONES")) == NOSTR) { 1550Sstevel@tonic-gate myperm(); 1560Sstevel@tonic-gate PH = "/etc/phones"; 1570Sstevel@tonic-gate } 1580Sstevel@tonic-gate phfd = fopen(PH, "r"); 1590Sstevel@tonic-gate 1600Sstevel@tonic-gate userperm(); 1610Sstevel@tonic-gate 1620Sstevel@tonic-gate vinit(); /* init variables */ 1630Sstevel@tonic-gate setparity("none"); /* set the parity table */ 1640Sstevel@tonic-gate if ((i = speed(number(value(BAUDRATE)))) == NULL) { 165549Smuffin (void) printf("tip: bad baud rate %d\n", 166549Smuffin number(value(BAUDRATE))); 1670Sstevel@tonic-gate myperm(); 1680Sstevel@tonic-gate delock(uucplock); 169549Smuffin return (3); 1700Sstevel@tonic-gate } 1710Sstevel@tonic-gate 1720Sstevel@tonic-gate 1730Sstevel@tonic-gate /* 1740Sstevel@tonic-gate * Hardwired connections require the 1750Sstevel@tonic-gate * line speed set before they make any transmissions 1760Sstevel@tonic-gate * (this is particularly true of things like a DF03-AC) 1770Sstevel@tonic-gate */ 1780Sstevel@tonic-gate if (HW) 1790Sstevel@tonic-gate ttysetup(i); 1800Sstevel@tonic-gate if (p = connect()) { 181549Smuffin (void) printf("\07%s\n[EOT]\n", p); 1820Sstevel@tonic-gate myperm(); 1830Sstevel@tonic-gate delock(uucplock); 184549Smuffin return (1); 1850Sstevel@tonic-gate } 1860Sstevel@tonic-gate 1870Sstevel@tonic-gate /* 1880Sstevel@tonic-gate * Always setup the tty again here in case hardware flow 1890Sstevel@tonic-gate * control was selected, which can only be set after the 1900Sstevel@tonic-gate * connection is made, or in case this is not a hardwired 1910Sstevel@tonic-gate * modem (rare these days) that likewise can only be setup 1920Sstevel@tonic-gate * after the connection is made. 1930Sstevel@tonic-gate */ 1940Sstevel@tonic-gate ttysetup(i); 1950Sstevel@tonic-gate cucommon: 1960Sstevel@tonic-gate /* 1970Sstevel@tonic-gate * From here down the code is shared with 1980Sstevel@tonic-gate * the "cu" version of tip. 1990Sstevel@tonic-gate */ 2000Sstevel@tonic-gate 201549Smuffin (void) ioctl(0, TCGETS, (char *)&defarg); 2020Sstevel@tonic-gate arg = defarg; 2030Sstevel@tonic-gate /* turn off input processing */ 2040Sstevel@tonic-gate arg.c_lflag &= ~(ICANON|ISIG|ECHO|IEXTEN); 2050Sstevel@tonic-gate arg.c_cc[VMIN] = 1; 2060Sstevel@tonic-gate arg.c_cc[VTIME] = 0; 2070Sstevel@tonic-gate arg.c_iflag &= ~(INPCK|IXON|IXOFF|ICRNL); 2080Sstevel@tonic-gate arg.c_oflag = 0; /* turn off all output processing */ 2090Sstevel@tonic-gate /* handle tandem mode in case was set in remote file */ 2100Sstevel@tonic-gate if (boolean(value(TAND))) 2110Sstevel@tonic-gate tandem("on"); 2120Sstevel@tonic-gate else 2130Sstevel@tonic-gate tandem("off"); 2140Sstevel@tonic-gate raw(); 2150Sstevel@tonic-gate 216549Smuffin (void) pipe(fildes); (void) pipe(repdes); 217549Smuffin (void) signal(SIGALRM, (sig_handler_t)timeout); 2180Sstevel@tonic-gate 2190Sstevel@tonic-gate /* 2200Sstevel@tonic-gate * Everything's set up now: 2210Sstevel@tonic-gate * connection established (hardwired or dialup) 2220Sstevel@tonic-gate * line conditioned (baud rate, mode, etc.) 2230Sstevel@tonic-gate * internal data structures (variables) 2240Sstevel@tonic-gate * so, fork one process for local side and one for remote. 2250Sstevel@tonic-gate */ 2260Sstevel@tonic-gate if (CM != NOSTR) { 227549Smuffin (void) sleep(2); /* let line settle */ 228549Smuffin parwrite(FD, (unsigned char *)CM, strlen(CM)); 2290Sstevel@tonic-gate } 230549Smuffin (void) printf(cumode ? "Connected\r\n" : "\07connected\r\n"); 231549Smuffin (void) signal(SIGCHLD, (sig_handler_t)deadkid); 2320Sstevel@tonic-gate if (pid = fork()) 2330Sstevel@tonic-gate tipin(); 2340Sstevel@tonic-gate else 2350Sstevel@tonic-gate tipout(); 2360Sstevel@tonic-gate /*NOTREACHED*/ 2370Sstevel@tonic-gate } 2380Sstevel@tonic-gate 2390Sstevel@tonic-gate void 240549Smuffin deadkid(void) 2410Sstevel@tonic-gate { 2420Sstevel@tonic-gate 2430Sstevel@tonic-gate if (pid >= 0 && waitpid(pid, NULL, WNOHANG) == pid) 244549Smuffin tip_abort("Connection Closed"); 2450Sstevel@tonic-gate } 2460Sstevel@tonic-gate 2470Sstevel@tonic-gate void 248549Smuffin cleanup(void) 2490Sstevel@tonic-gate { 2500Sstevel@tonic-gate 2510Sstevel@tonic-gate if (uid != getuid()) { 2520Sstevel@tonic-gate myperm(); 2530Sstevel@tonic-gate } 2540Sstevel@tonic-gate delock(uucplock); 2550Sstevel@tonic-gate exit(0); 2560Sstevel@tonic-gate } 2570Sstevel@tonic-gate 2580Sstevel@tonic-gate /* 2590Sstevel@tonic-gate * put the controlling keyboard into raw mode 2600Sstevel@tonic-gate */ 261549Smuffin void 262549Smuffin raw(void) 2630Sstevel@tonic-gate { 2640Sstevel@tonic-gate 265549Smuffin (void) ioctl(0, TCSETSF, (char *)&arg); 2660Sstevel@tonic-gate } 2670Sstevel@tonic-gate 2680Sstevel@tonic-gate 2690Sstevel@tonic-gate /* 2700Sstevel@tonic-gate * return keyboard to normal mode 2710Sstevel@tonic-gate */ 272549Smuffin void 273549Smuffin unraw(void) 2740Sstevel@tonic-gate { 2750Sstevel@tonic-gate 276549Smuffin (void) ioctl(0, TCSETSF, (char *)&defarg); 2770Sstevel@tonic-gate } 2780Sstevel@tonic-gate 2790Sstevel@tonic-gate /* 2800Sstevel@tonic-gate * switch to using invoking user's permissions 2810Sstevel@tonic-gate */ 282549Smuffin void 283549Smuffin userperm(void) 2840Sstevel@tonic-gate { 2850Sstevel@tonic-gate 286549Smuffin (void) setegid(gid); 287549Smuffin (void) seteuid(uid); 2880Sstevel@tonic-gate } 2890Sstevel@tonic-gate 2900Sstevel@tonic-gate /* 2910Sstevel@tonic-gate * switch to using my special (setuid) permissions 2920Sstevel@tonic-gate */ 293549Smuffin void 294549Smuffin myperm(void) 2950Sstevel@tonic-gate { 2960Sstevel@tonic-gate 297549Smuffin (void) setegid(egid); 298549Smuffin (void) seteuid(euid); 2990Sstevel@tonic-gate } 3000Sstevel@tonic-gate 3010Sstevel@tonic-gate static sigjmp_buf promptbuf; 3020Sstevel@tonic-gate 3030Sstevel@tonic-gate /* 3040Sstevel@tonic-gate * Print string ``s'', then read a string 3050Sstevel@tonic-gate * in from the terminal. Handles signals & allows use of 3060Sstevel@tonic-gate * normal erase and kill characters. 3070Sstevel@tonic-gate */ 308549Smuffin int 309549Smuffin prompt(char *s, char *p, size_t len) 3100Sstevel@tonic-gate { 311549Smuffin char *b = p; 312549Smuffin int c; 313549Smuffin sig_handler_t ointr, oquit; 3140Sstevel@tonic-gate 3150Sstevel@tonic-gate stoprompt = 0; 316549Smuffin ointr = signal(SIGINT, (sig_handler_t)intprompt); 3170Sstevel@tonic-gate oquit = signal(SIGQUIT, SIG_IGN); 3180Sstevel@tonic-gate unraw(); 319549Smuffin (void) printf("%s", s); 3200Sstevel@tonic-gate if (sigsetjmp(promptbuf, 1) == 0) 3210Sstevel@tonic-gate while (p < b + len - 1 && 3220Sstevel@tonic-gate ((c = getchar()) != EOF) && (c != '\n')) 3230Sstevel@tonic-gate *p++ = c; 3240Sstevel@tonic-gate *p = '\0'; 3250Sstevel@tonic-gate 3260Sstevel@tonic-gate raw(); 327549Smuffin (void) signal(SIGINT, ointr); 328549Smuffin (void) signal(SIGQUIT, oquit); 3290Sstevel@tonic-gate return (stoprompt || p == b); 3300Sstevel@tonic-gate } 3310Sstevel@tonic-gate 3320Sstevel@tonic-gate /* 3330Sstevel@tonic-gate * Interrupt service routine during prompting 3340Sstevel@tonic-gate */ 3350Sstevel@tonic-gate void 336549Smuffin intprompt(void) 3370Sstevel@tonic-gate { 3380Sstevel@tonic-gate 339549Smuffin (void) signal(SIGINT, SIG_IGN); 340549Smuffin (void) signal(SIGQUIT, SIG_IGN); 3410Sstevel@tonic-gate stoprompt = 1; 342549Smuffin (void) printf("\r\n"); 3430Sstevel@tonic-gate siglongjmp(promptbuf, 1); 3440Sstevel@tonic-gate } 3450Sstevel@tonic-gate 3460Sstevel@tonic-gate /* 3470Sstevel@tonic-gate * ****TIPIN TIPIN**** 3480Sstevel@tonic-gate */ 349549Smuffin void 350549Smuffin tipin(void) 3510Sstevel@tonic-gate { 3520Sstevel@tonic-gate unsigned char gch, c; 3530Sstevel@tonic-gate int bol = 1; 3540Sstevel@tonic-gate 3550Sstevel@tonic-gate /* 3560Sstevel@tonic-gate * Kinda klugey here... 3570Sstevel@tonic-gate * check for scripting being turned on from the .tiprc file, 3580Sstevel@tonic-gate * but be careful about just using setscript(), as we may 3590Sstevel@tonic-gate * send a SIGEMT before tipout has a chance to set up catching 3600Sstevel@tonic-gate * it; so wait a second, then setscript() 3610Sstevel@tonic-gate */ 3620Sstevel@tonic-gate if (boolean(value(SCRIPT))) { 363549Smuffin (void) sleep(1); 3640Sstevel@tonic-gate setscript(); 3650Sstevel@tonic-gate } 3660Sstevel@tonic-gate 3670Sstevel@tonic-gate for (;;) { 3680Sstevel@tonic-gate gch = getchar()&0377; 3690Sstevel@tonic-gate if ((gch == character(value(ESCAPE))) && bol) { 3700Sstevel@tonic-gate if (!(gch = escape())) 3710Sstevel@tonic-gate continue; 3720Sstevel@tonic-gate } else if (!cumode && gch == character(value(RAISECHAR))) { 3730Sstevel@tonic-gate boolean(value(RAISE)) = !boolean(value(RAISE)); 3740Sstevel@tonic-gate continue; 3750Sstevel@tonic-gate } else if (gch == '\r') { 3760Sstevel@tonic-gate bol = 1; 3770Sstevel@tonic-gate parwrite(FD, &gch, 1); 3780Sstevel@tonic-gate if (boolean(value(HALFDUPLEX))) 379549Smuffin (void) printf("\r\n"); 3800Sstevel@tonic-gate continue; 3810Sstevel@tonic-gate } else if (!cumode && gch == character(value(FORCE))) 3820Sstevel@tonic-gate gch = getchar()&0377; 3830Sstevel@tonic-gate bol = any(gch, value(EOL)); 3840Sstevel@tonic-gate if (boolean(value(RAISE)) && islower(gch)) 3850Sstevel@tonic-gate gch = toupper(gch); 3860Sstevel@tonic-gate c = gch; 3870Sstevel@tonic-gate parwrite(FD, &gch, 1); 3880Sstevel@tonic-gate if (boolean(value(HALFDUPLEX))) 389549Smuffin (void) putchar(c); 3900Sstevel@tonic-gate } 3910Sstevel@tonic-gate } 3920Sstevel@tonic-gate 3930Sstevel@tonic-gate /* 3940Sstevel@tonic-gate * Escape handler -- 3950Sstevel@tonic-gate * called on recognition of ``escapec'' at the beginning of a line 3960Sstevel@tonic-gate */ 397549Smuffin unsigned char 398549Smuffin escape(void) 3990Sstevel@tonic-gate { 400549Smuffin unsigned char gch; 401549Smuffin esctable_t *p; 4020Sstevel@tonic-gate char c = character(value(ESCAPE)); 4030Sstevel@tonic-gate 4040Sstevel@tonic-gate gch = (getchar()&0377); 4050Sstevel@tonic-gate for (p = etable; p->e_char; p++) 4060Sstevel@tonic-gate if (p->e_char == gch) { 4070Sstevel@tonic-gate if ((p->e_flags&PRIV) && uid) 4080Sstevel@tonic-gate continue; 409549Smuffin (void) printf("%s", ctrl(c)); 4100Sstevel@tonic-gate (*p->e_func)(gch); 4110Sstevel@tonic-gate return (0); 4120Sstevel@tonic-gate } 4130Sstevel@tonic-gate /* ESCAPE ESCAPE forces ESCAPE */ 4140Sstevel@tonic-gate if (c != gch) 415549Smuffin parwrite(FD, (unsigned char *)&c, 1); 4160Sstevel@tonic-gate return (gch); 4170Sstevel@tonic-gate } 4180Sstevel@tonic-gate 419549Smuffin int 420549Smuffin speed(int n) 4210Sstevel@tonic-gate { 422549Smuffin int *p; 4230Sstevel@tonic-gate 4240Sstevel@tonic-gate for (p = bauds; *p != -1; p++) 4250Sstevel@tonic-gate if (*p == n) 4260Sstevel@tonic-gate return (p - bauds); 427549Smuffin return (0); 4280Sstevel@tonic-gate } 4290Sstevel@tonic-gate 430549Smuffin int 431549Smuffin any(char c, char *p) 4320Sstevel@tonic-gate { 4330Sstevel@tonic-gate while (p && *p) 4340Sstevel@tonic-gate if (*p++ == c) 4350Sstevel@tonic-gate return (1); 4360Sstevel@tonic-gate return (0); 4370Sstevel@tonic-gate } 4380Sstevel@tonic-gate 4390Sstevel@tonic-gate char * 440549Smuffin interp(char *s) 4410Sstevel@tonic-gate { 4420Sstevel@tonic-gate static char buf[256]; 443549Smuffin char *p = buf, c, *q; 4440Sstevel@tonic-gate 4450Sstevel@tonic-gate while (c = *s++) { 4460Sstevel@tonic-gate for (q = "\nn\rr\tt\ff\033E\bb"; *q; q++) 4470Sstevel@tonic-gate if (*q++ == c) { 4480Sstevel@tonic-gate *p++ = '\\'; *p++ = *q; 4490Sstevel@tonic-gate goto next; 4500Sstevel@tonic-gate } 4510Sstevel@tonic-gate if (c < 040) { 4520Sstevel@tonic-gate *p++ = '^'; *p++ = c + 'A'-1; 4530Sstevel@tonic-gate } else if (c == 0177) { 4540Sstevel@tonic-gate *p++ = '^'; *p++ = '?'; 4550Sstevel@tonic-gate } else 4560Sstevel@tonic-gate *p++ = c; 4570Sstevel@tonic-gate next: 4580Sstevel@tonic-gate ; 4590Sstevel@tonic-gate } 4600Sstevel@tonic-gate *p = '\0'; 4610Sstevel@tonic-gate return (buf); 4620Sstevel@tonic-gate } 4630Sstevel@tonic-gate 4640Sstevel@tonic-gate char * 465549Smuffin ctrl(char c) 4660Sstevel@tonic-gate { 4670Sstevel@tonic-gate static char s[3]; 4680Sstevel@tonic-gate 4690Sstevel@tonic-gate if (c < 040 || c == 0177) { 4700Sstevel@tonic-gate s[0] = '^'; 4710Sstevel@tonic-gate s[1] = c == 0177 ? '?' : c+'A'-1; 4720Sstevel@tonic-gate s[2] = '\0'; 4730Sstevel@tonic-gate } else { 4740Sstevel@tonic-gate s[0] = c; 4750Sstevel@tonic-gate s[1] = '\0'; 4760Sstevel@tonic-gate } 4770Sstevel@tonic-gate return (s); 4780Sstevel@tonic-gate } 4790Sstevel@tonic-gate 4800Sstevel@tonic-gate /* 4810Sstevel@tonic-gate * Help command 4820Sstevel@tonic-gate */ 483549Smuffin void 484549Smuffin help(int c) 4850Sstevel@tonic-gate { 486549Smuffin esctable_t *p; 4870Sstevel@tonic-gate 488549Smuffin (void) printf("%c\r\n", c); 4890Sstevel@tonic-gate for (p = etable; p->e_char; p++) { 4900Sstevel@tonic-gate if ((p->e_flags&PRIV) && uid) 4910Sstevel@tonic-gate continue; 492549Smuffin (void) printf("%2s", ctrl(character(value(ESCAPE)))); 493549Smuffin (void) printf("%-2s %c %s\r\n", ctrl(p->e_char), 494549Smuffin p->e_flags&EXP ? '*': ' ', p->e_help); 4950Sstevel@tonic-gate } 4960Sstevel@tonic-gate } 4970Sstevel@tonic-gate 4980Sstevel@tonic-gate /* 4990Sstevel@tonic-gate * Set up the "remote" tty's state 5000Sstevel@tonic-gate */ 501549Smuffin void 502549Smuffin ttysetup(int speed) 5030Sstevel@tonic-gate { 5040Sstevel@tonic-gate struct termios buf; 5050Sstevel@tonic-gate char *loc; 5060Sstevel@tonic-gate 507549Smuffin (void) ioctl(FD, TCGETS, (char *)&buf); 5080Sstevel@tonic-gate buf.c_cflag &= (CREAD|HUPCL|CLOCAL|CRTSCTS|CRTSXOFF); 5090Sstevel@tonic-gate buf.c_cflag |= CS8; 510549Smuffin (void) cfsetospeed(&buf, speed); 5110Sstevel@tonic-gate if (boolean(value(HARDWAREFLOW))) { 5120Sstevel@tonic-gate int i = TIOCM_CAR; 5130Sstevel@tonic-gate 5140Sstevel@tonic-gate /* 5150Sstevel@tonic-gate * Only set hardware flow control if carrier is up, 5160Sstevel@tonic-gate * because some devices require both CD and RTS to 5170Sstevel@tonic-gate * be up before sending. 5180Sstevel@tonic-gate */ 519549Smuffin (void) ioctl(FD, TIOCMGET, &i); 5200Sstevel@tonic-gate if (i & TIOCM_CAR) 5210Sstevel@tonic-gate buf.c_cflag |= (CRTSCTS|CRTSXOFF); 5220Sstevel@tonic-gate } 5230Sstevel@tonic-gate 5240Sstevel@tonic-gate /* 5250Sstevel@tonic-gate * Careful to only penalize the 8-bit users here on the 5260Sstevel@tonic-gate * incoming tty port. The default 7-bit users will 5270Sstevel@tonic-gate * still get the parity bit from the other side's login 5280Sstevel@tonic-gate * process (which happens to be the default for sun tip 5290Sstevel@tonic-gate * configurations). 5300Sstevel@tonic-gate */ 5310Sstevel@tonic-gate loc = setlocale(LC_CTYPE, NULL); 5320Sstevel@tonic-gate if (noparity && loc != 0 && strcmp(loc, "C") != 0) 5330Sstevel@tonic-gate buf.c_iflag = 0; 5340Sstevel@tonic-gate else 5350Sstevel@tonic-gate buf.c_iflag = ISTRIP; 5360Sstevel@tonic-gate buf.c_oflag = 0; 5370Sstevel@tonic-gate buf.c_lflag = 0; 5380Sstevel@tonic-gate buf.c_cc[VMIN] = 1; 5390Sstevel@tonic-gate buf.c_cc[VTIME] = 0; 540549Smuffin (void) ioctl(FD, TCSETSF, (char *)&buf); 5410Sstevel@tonic-gate } 5420Sstevel@tonic-gate 5430Sstevel@tonic-gate /* 5440Sstevel@tonic-gate * Return "simple" name from a file name, 5450Sstevel@tonic-gate * strip leading directories. 5460Sstevel@tonic-gate */ 5470Sstevel@tonic-gate char * 548549Smuffin sname(char *s) 5490Sstevel@tonic-gate { 550549Smuffin char *p = s; 5510Sstevel@tonic-gate 5520Sstevel@tonic-gate while (*s) 5530Sstevel@tonic-gate if (*s++ == '/') 5540Sstevel@tonic-gate p = s; 5550Sstevel@tonic-gate return (p); 5560Sstevel@tonic-gate } 5570Sstevel@tonic-gate 5580Sstevel@tonic-gate static char partab[0400]; 5590Sstevel@tonic-gate 5600Sstevel@tonic-gate /* 5610Sstevel@tonic-gate * Do a write to the remote machine with the correct parity. 5620Sstevel@tonic-gate * We are doing 8 bit wide output, so we just generate a character 5630Sstevel@tonic-gate * with the right parity and output it. 5640Sstevel@tonic-gate */ 565549Smuffin void 566549Smuffin parwrite(int fd, unsigned char *buf, int n) 5670Sstevel@tonic-gate { 568549Smuffin int i; 569549Smuffin unsigned char *bp; 5700Sstevel@tonic-gate 5710Sstevel@tonic-gate bp = buf; 5720Sstevel@tonic-gate for (i = 0; i < n; i++) { 5730Sstevel@tonic-gate *bp = partab[(*bp)&0377]; 5740Sstevel@tonic-gate bp++; 5750Sstevel@tonic-gate } 5760Sstevel@tonic-gate if (write(fd, buf, n) < 0) { 5770Sstevel@tonic-gate if (errno == EIO || errno == ENXIO) 578549Smuffin tip_abort("Lost carrier."); 5790Sstevel@tonic-gate /* this is questionable */ 5800Sstevel@tonic-gate perror("write"); 5810Sstevel@tonic-gate } 5820Sstevel@tonic-gate } 5830Sstevel@tonic-gate 5840Sstevel@tonic-gate /* 5850Sstevel@tonic-gate * Build a parity table with appropriate high-order bit. 5860Sstevel@tonic-gate */ 587549Smuffin void 588549Smuffin setparity(char *defparity) 5890Sstevel@tonic-gate { 590549Smuffin int i; 5910Sstevel@tonic-gate char *parity; 5920Sstevel@tonic-gate 5930Sstevel@tonic-gate if (value(PARITY) == NOSTR) 5940Sstevel@tonic-gate value(PARITY) = defparity; 5950Sstevel@tonic-gate parity = value(PARITY); 5960Sstevel@tonic-gate for (i = 0; i < 0400; i++) 5970Sstevel@tonic-gate partab[i] = evenpartab[i]; 598549Smuffin if (equal(parity, "even")) { 599549Smuffin /* EMPTY */ 600549Smuffin } else if (equal(parity, "odd")) { 6010Sstevel@tonic-gate for (i = 0; i < 0400; i++) 6020Sstevel@tonic-gate partab[i] ^= 0200; /* reverse bit 7 */ 6030Sstevel@tonic-gate } else if (equal(parity, "none")) { 6040Sstevel@tonic-gate /* Do nothing so we can pass thru 8-bit chars */ 6050Sstevel@tonic-gate noparity = 1; 6060Sstevel@tonic-gate for (i = 0; i < 0400; i++) 6070Sstevel@tonic-gate partab[i] = i; 6080Sstevel@tonic-gate } else if (equal(parity, "zero")) { 6090Sstevel@tonic-gate for (i = 0; i < 0400; i++) 6100Sstevel@tonic-gate partab[i] &= ~0200; /* turn off bit 7 */ 6110Sstevel@tonic-gate } else if (equal(parity, "one")) { 6120Sstevel@tonic-gate for (i = 0; i < 0400; i++) 6130Sstevel@tonic-gate partab[i] |= 0200; /* turn on bit 7 */ 6140Sstevel@tonic-gate } else { 615549Smuffin (void) fprintf(stderr, "%s: unknown parity value\n", PA); 616549Smuffin (void) fflush(stderr); 6170Sstevel@tonic-gate } 6180Sstevel@tonic-gate } 619