1 /* $NetBSD: tip.c,v 1.49 2008/07/21 14:19:26 lukem Exp $ */
4 * Copyright (c) 1983, 1993
5 * The Regents of the University of California. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 #include <sys/cdefs.h>
37 __COPYRIGHT("@(#) Copyright (c) 1983, 1993\
38 The Regents of the University of California. All rights reserved.");
43 static char sccsid
[] = "@(#)tip.c 8.1 (Berkeley) 6/6/93";
45 __RCSID("$NetBSD: tip.c,v 1.49 2008/07/21 14:19:26 lukem Exp $");
49 * tip - UNIX link to other systems
50 * tip [-v] [-speed] system-name
52 * cu [options] [phone-number|"dir"]
55 #include "pathnames.h"
57 static void tipusage(void);
60 int main(int, char **);
64 char PNbuf
[256]; /* This limits the size of a number */
66 static char path_phones
[] = _PATH_PHONES
;
69 main(int argc
, char *argv
[])
76 static char brbuf
[16];
83 if (equal(basename(argv
[0]), "cu")) {
93 (void)fprintf(stderr
, "%s: must be interactive\n", getprogname());
97 while((c
= getopt(argc
, argv
, "v0123456789")) != -1) {
104 case '0': case '1': case '2': case '3': case '4':
105 case '5': case '6': case '7': case '8': case '9':
106 (void)snprintf(brbuf
, sizeof(brbuf
) -1, "%s%c", brbuf
, c
);
111 warnx("%s, unknown option", argv
[1]);
127 if (isalpha((unsigned char)*System
))
130 * System name is really a phone number...
131 * Copy the number then stomp on the original (in case the number
132 * is private, we don't want 'ps' or 'w' to find it).
134 if (strlen(System
) > sizeof PNbuf
- 1) {
135 errx(1, "phone number too long (max = %d bytes)",
136 (int)sizeof(PNbuf
) - 1);
138 (void)strlcpy(PNbuf
, System
, sizeof(PNbuf
));
139 for (p
= System
; *p
; p
++)
142 (void)snprintf(sbuf
, sizeof sbuf
, "tip%d", (int)BR
);
146 (void)signal(SIGINT
, cleanup
);
147 (void)signal(SIGQUIT
, cleanup
);
148 (void)signal(SIGHUP
, cleanup
);
149 (void)signal(SIGTERM
, cleanup
);
151 if ((i
= hunt(System
)) == 0) {
152 (void)printf("all ports busy\n");
156 errx(3, "link down\n");
158 setbuf(stdout
, NULL
);
161 * Kludge, their's no easy way to get the initialization
162 * in the right order, so force it here
164 if ((PH
= getenv("PHONES")) == NULL
)
166 vinit(); /* init variables */
167 setparity("none"); /* set the parity table */
170 * Hardwired connections require the
171 * line speed set before they make any transmissions
172 * (this is particularly true of things like a DF03-AC)
175 if (ttysetup((speed_t
)number(value(BAUDRATE
))) != 0) {
176 errx(3, "bad baud rate %d",
177 (int)number(value(BAUDRATE
)));
180 if ((q
= tip_connect()) != NULL
) {
181 errx(1, "\07%s\n[EOT]\n", q
);
184 if (ttysetup((speed_t
)number(value(BAUDRATE
))) != 0) {
185 errx(3, "bad baud rate %d",
186 (int)number(value(BAUDRATE
)));
193 * From here down the code is shared with
194 * the "cu" version of tip.
198 * Direct connections with no carrier require using O_NONBLOCK on
199 * open, but we don't want to keep O_NONBLOCK after open because it
200 * will cause busy waits.
203 ((fcarg
= fcntl(FD
, F_GETFL
, 0)) < 0 ||
204 fcntl(FD
, F_SETFL
, fcarg
& ~O_NONBLOCK
) < 0)) {
205 err(1, "can't clear O_NONBLOCK");
208 (void)tcgetattr(0, &defterm
);
210 term
.c_lflag
&= ~(ICANON
|IEXTEN
|ECHO
);
211 term
.c_iflag
&= ~(INPCK
|ICRNL
);
212 term
.c_oflag
&= ~OPOST
;
214 term
.c_cc
[VTIME
] = 0;
216 term
.c_cc
[VINTR
] = term
.c_cc
[VQUIT
] = term
.c_cc
[VSUSP
] =
217 term
.c_cc
[VDSUSP
] = term
.c_cc
[VDISCARD
] =
218 term
.c_cc
[VLNEXT
] = _POSIX_VDISABLE
;
224 (void)signal(SIGALRM
, alrmtimeout
);
227 * Everything's set up now:
228 * connection established (hardwired or dialup)
229 * line conditioned (baud rate, mode, etc.)
230 * internal data structures (variables)
231 * so, fork one process for local side and one for remote.
233 (void)printf("%s", cumode
? "Connected\r\n" : "\07connected\r\n");
234 switch (pid
= fork()) {
242 err(1, "can't fork");
245 exit(0); /* XXX: pacify gcc */
251 (void)fprintf(stderr
, "usage: %s [-v] [-speed] system-name\n",
253 (void)fprintf(stderr
, " %s [-v] [-speed] phone-number\n",
260 cleanup(int dummy __unused
)
264 (void)ioctl(0, TIOCSETD
, &odisc
);
269 * put the controlling keyboard into raw mode
275 (void)tcsetattr(0, TCSADRAIN
, &term
);
280 * return keyboard to normal mode
286 (void)tcsetattr(0, TCSADRAIN
, &defterm
);
289 static jmp_buf promptbuf
;
292 * Print string ``s'', then read a string
293 * in from the terminal. Handles signals & allows use of
294 * normal erase and kill characters.
297 prompt(const char *s
, char *volatile p
, size_t l
)
304 oint
= signal(SIGINT
, intprompt
);
305 oquit
= signal(SIGQUIT
, SIG_IGN
);
307 (void)printf("%s", s
);
308 if (setjmp(promptbuf
) == 0)
309 while ((c
= getchar()) != -1 && (*p
= c
) != '\n' &&
315 (void)signal(SIGINT
, oint
);
316 (void)signal(SIGQUIT
, oquit
);
317 return (stoprompt
|| p
== b
);
321 * Interrupt service routine during prompting
325 intprompt(int dummy __unused
)
328 (void)signal(SIGINT
, SIG_IGN
);
330 (void)printf("\r\n");
331 longjmp(promptbuf
, 1);
335 * ****TIPIN TIPIN****
343 * Kinda klugey here...
344 * check for scripting being turned on from the .tiprc file,
345 * but be careful about just using setscript(), as we may
346 * send a SIGEMT before tipout has a chance to set up catching
347 * it; so wait a second, then setscript()
349 if (boolean(value(SCRIPT
))) {
355 gch
= getchar()&STRIP_PAR
;
356 if ((gch
== character(value(ESCAPE
))) && bol
) {
357 if (!(gch
= escape()))
359 } else if (!cumode
&&
360 gch
&& gch
== character(value(RAISECHAR
))) {
361 setboolean(value(RAISE
), !boolean(value(RAISE
)));
363 } else if (gch
== '\r') {
365 xpwrite(FD
, &gch
, 1);
366 if (boolean(value(HALFDUPLEX
)))
367 (void)printf("\r\n");
369 } else if (!cumode
&& gch
&& gch
== character(value(FORCE
)))
370 gch
= getchar()&STRIP_PAR
;
371 bol
= any(gch
, value(EOL
));
372 if (boolean(value(RAISE
)) && islower((unsigned char)gch
))
373 gch
= toupper((unsigned char)gch
);
374 xpwrite(FD
, &gch
, 1);
375 if (boolean(value(HALFDUPLEX
)))
376 (void)printf("%c", gch
);
382 * called on recognition of ``escapec'' at the beginning of a line
389 char c
= character(value(ESCAPE
));
391 gch
= (getchar()&STRIP_PAR
);
392 for (p
= etable
; p
->e_char
; p
++)
393 if (p
->e_char
== gch
) {
394 if ((p
->e_flags
&PRIV
) && uid
)
396 (void)printf("%s", ctrl(c
));
400 /* ESCAPE ESCAPE forces ESCAPE */
407 any(char c
, const char *p
)
417 interp(const char *s
)
419 static char buf
[256];
423 while ((c
= *s
++) != 0 && buf
+ sizeof buf
- p
> 2) {
424 for (q
= "\nn\rr\tt\ff\033E\bb"; *q
; q
++)
426 *p
++ = '\\'; *p
++ = *q
;
430 *p
++ = '^'; *p
++ = c
+ 'A'-1;
431 } else if (c
== 0177) {
432 *p
++ = '^'; *p
++ = '?';
447 if (c
< 040 || c
== 0177) {
449 s
[1] = c
== 0177 ? '?' : c
+'A'-1;
466 (void)printf("%c\r\n", c
);
467 for (p
= etable
; p
->e_char
; p
++) {
468 if ((p
->e_flags
&PRIV
) && uid
)
470 (void)printf("%2s", ctrl(character(value(ESCAPE
))));
471 (void)printf("%-2s %c %s\r\n", ctrl(p
->e_char
),
472 p
->e_flags
&EXP
? '*': ' ', p
->e_help
);
477 * Set up the "remote" tty's state
480 ttysetup(speed_t spd
)
482 struct termios cntrl
;
484 (void)tcgetattr(FD
, &cntrl
);
485 (void)cfsetospeed(&cntrl
, spd
);
486 (void)cfsetispeed(&cntrl
, spd
);
487 cntrl
.c_cflag
&= ~(CSIZE
|PARENB
);
488 cntrl
.c_cflag
|= CS8
;
490 cntrl
.c_cflag
|= CLOCAL
;
491 if (boolean(value(HARDWAREFLOW
)))
492 cntrl
.c_cflag
|= CRTSCTS
;
493 cntrl
.c_iflag
&= ~(ISTRIP
|ICRNL
);
494 cntrl
.c_oflag
&= ~OPOST
;
495 cntrl
.c_lflag
&= ~(ICANON
|ISIG
|IEXTEN
|ECHO
);
496 cntrl
.c_cc
[VMIN
] = 1;
497 cntrl
.c_cc
[VTIME
] = 0;
498 if (boolean(value(TAND
)))
499 cntrl
.c_iflag
|= IXOFF
;
500 return tcsetattr(FD
, TCSAFLUSH
, &cntrl
);
503 static char partab
[0200];
506 * Do a write to the remote machine with the correct parity.
507 * We are doing 8 bit wide output, so we just generate a character
508 * with the right parity and output it.
511 xpwrite(int fd
, char *buf
, size_t n
)
518 for (i
= 0; i
< n
; i
++) {
519 *bp
= partab
[(*bp
) & 0177];
522 if (write(fd
, buf
, n
) < 0) {
524 tipabort("Lost carrier.");
525 /* this is questionable */
531 * Build a parity table with appropriate high-order bit.
534 setparity(const char *defparity
)
536 int i
, flip
, clr
, set
;
540 if (value(PARITY
) == NULL
|| ((char *)value(PARITY
))[0] == '\0') {
543 value(PARITY
) = curpar
= strdup(defparity
);
545 parity
= value(PARITY
);
546 if (equal(parity
, "none")) {
554 if (equal(parity
, "odd"))
555 flip
= 0200; /* reverse bit 7 */
556 else if (equal(parity
, "zero"))
557 clr
= 0177; /* turn off bit 7 */
558 else if (equal(parity
, "one"))
559 set
= 0200; /* turn on bit 7 */
560 else if (!equal(parity
, "even")) {
561 (void)fprintf(stderr
, "%s: unknown parity value\r\n", parity
);
562 (void)fflush(stderr
);
564 for (i
= 0; i
< 0200; i
++)
565 partab
[i
] = ((evenpartab
[i
] ^ flip
) | set
) & clr
;