2 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
7 * Copyright (c) 1983 Regents of the University of California.
8 * All rights reserved. The Berkeley software License Agreement
9 * specifies the terms and conditions for redistribution.
13 * tip - UNIX link to other systems
14 * tip [-v] [-speed] system-name
16 * cu phone-number [-s speed] [-l line] [-a acu]
23 * Baud rate mapping table
26 0, 50, 75, 110, 134, 150, 200, 300, 600,
27 1200, 1800, 2400, 4800, 9600, 19200, 38400,
28 57600, 76800, 115200, 153600, 230400, 307200,
32 extern void tipout(void) __NORETURN
;
33 extern void timeout(void);
34 extern esctable_t etable
[];
35 extern unsigned char evenpartab
[];
40 void tipin(void) __NORETURN
;
41 unsigned char escape(void);
43 char PNbuf
[256]; /* This limits the size of a number */
47 main(int argc
, char *argv
[])
58 if (equal(sname(argv
[0]), "cu")) {
65 (void) fprintf(stderr
,
66 "usage: tip [-v] [-speed] [system-name]\n");
70 (void) fprintf(stderr
, "tip: must be interactive\n");
74 for (; argc
> 1; argv
++, argc
--) {
75 if (argv
[1][0] != '-')
77 else switch (argv
[1][1]) {
83 case '0': case '1': case '2': case '3': case '4':
84 case '5': case '6': case '7': case '8': case '9':
85 BR
= atoi(&argv
[1][1]);
89 (void) fprintf(stderr
, "tip: %s, unknown option\n",
95 (void) setlocale(LC_CTYPE
, "");
99 for (p
= system
; *p
; p
++)
103 * System name is really a phone number...
104 * Copy the number then stomp on the original (in case the number
105 * is private, we don't want 'ps' or 'w' to find it).
107 if (strlen(system
) > sizeof (PNbuf
) - 1) {
108 (void) fprintf(stderr
,
109 "tip: phone number too long (max = %d bytes)\n",
113 (void) strncpy(PNbuf
, system
, sizeof (PNbuf
) - 1);
114 for (p
= system
; *p
; p
++)
117 (void) snprintf(sbuf
, sizeof (sbuf
), "tip%d", BR
);
121 (void) signal(SIGINT
, (sig_handler_t
)cleanup
);
122 (void) signal(SIGQUIT
, (sig_handler_t
)cleanup
);
123 (void) signal(SIGHUP
, (sig_handler_t
)cleanup
);
124 (void) signal(SIGTERM
, (sig_handler_t
)cleanup
);
126 if ((i
= hunt(system
)) == 0) {
127 (void) printf("all ports busy\n");
131 (void) printf("link down\n");
135 setbuf(stdout
, NULL
);
139 * Now that we have the logfile and the ACU open
140 * return to the real uid and gid. These things will
141 * be closed on exit. The saved-setuid uid and gid
142 * allows us to get the original setuid permissions back
143 * for removing the uucp lock.
148 * Kludge, there's no easy way to get the initialization
149 * in the right order, so force it here.
150 * Do the open here, before we change back to real uid.
151 * We will check whether the open succeeded later, when
152 * (and if) we actually go to use the file.
154 if ((PH
= getenv("PHONES")) == NOSTR
) {
158 phfd
= fopen(PH
, "r");
162 vinit(); /* init variables */
163 setparity("none"); /* set the parity table */
164 if ((i
= speed(number(value(BAUDRATE
)))) == NULL
) {
165 (void) printf("tip: bad baud rate %d\n",
166 number(value(BAUDRATE
)));
174 * Hardwired connections require the
175 * line speed set before they make any transmissions
176 * (this is particularly true of things like a DF03-AC)
181 (void) printf("\07%s\n[EOT]\n", p
);
188 * Always setup the tty again here in case hardware flow
189 * control was selected, which can only be set after the
190 * connection is made, or in case this is not a hardwired
191 * modem (rare these days) that likewise can only be setup
192 * after the connection is made.
197 * From here down the code is shared with
198 * the "cu" version of tip.
201 (void) ioctl(0, TCGETS
, (char *)&defarg
);
203 /* turn off input processing */
204 arg
.c_lflag
&= ~(ICANON
|ISIG
|ECHO
|IEXTEN
);
207 arg
.c_iflag
&= ~(INPCK
|IXON
|IXOFF
|ICRNL
);
208 arg
.c_oflag
= 0; /* turn off all output processing */
209 /* handle tandem mode in case was set in remote file */
210 if (boolean(value(TAND
)))
216 (void) pipe(fildes
); (void) pipe(repdes
);
217 (void) signal(SIGALRM
, (sig_handler_t
)timeout
);
220 * Everything's set up now:
221 * connection established (hardwired or dialup)
222 * line conditioned (baud rate, mode, etc.)
223 * internal data structures (variables)
224 * so, fork one process for local side and one for remote.
227 (void) sleep(2); /* let line settle */
228 parwrite(FD
, (unsigned char *)CM
, strlen(CM
));
230 (void) printf(cumode
? "Connected\r\n" : "\07connected\r\n");
231 (void) signal(SIGCHLD
, (sig_handler_t
)deadkid
);
243 if (pid
>= 0 && waitpid(pid
, NULL
, WNOHANG
) == pid
)
244 tip_abort("Connection Closed");
251 if (uid
!= getuid()) {
259 * put the controlling keyboard into raw mode
265 (void) ioctl(0, TCSETSF
, (char *)&arg
);
270 * return keyboard to normal mode
276 (void) ioctl(0, TCSETSF
, (char *)&defarg
);
280 * switch to using invoking user's permissions
291 * switch to using my special (setuid) permissions
297 (void) setegid(egid
);
298 (void) seteuid(euid
);
301 static sigjmp_buf promptbuf
;
304 * Print string ``s'', then read a string
305 * in from the terminal. Handles signals & allows use of
306 * normal erase and kill characters.
309 prompt(char *s
, char *p
, size_t len
)
313 sig_handler_t ointr
, oquit
;
316 ointr
= signal(SIGINT
, (sig_handler_t
)intprompt
);
317 oquit
= signal(SIGQUIT
, SIG_IGN
);
319 (void) printf("%s", s
);
320 if (sigsetjmp(promptbuf
, 1) == 0)
321 while (p
< b
+ len
- 1 &&
322 ((c
= getchar()) != EOF
) && (c
!= '\n'))
327 (void) signal(SIGINT
, ointr
);
328 (void) signal(SIGQUIT
, oquit
);
329 return (stoprompt
|| p
== b
);
333 * Interrupt service routine during prompting
339 (void) signal(SIGINT
, SIG_IGN
);
340 (void) signal(SIGQUIT
, SIG_IGN
);
342 (void) printf("\r\n");
343 siglongjmp(promptbuf
, 1);
347 * ****TIPIN TIPIN****
352 unsigned char gch
, c
;
356 * Kinda klugey here...
357 * check for scripting being turned on from the .tiprc file,
358 * but be careful about just using setscript(), as we may
359 * send a SIGEMT before tipout has a chance to set up catching
360 * it; so wait a second, then setscript()
362 if (boolean(value(SCRIPT
))) {
368 gch
= getchar()&0377;
369 if ((gch
== character(value(ESCAPE
))) && bol
) {
370 if (!(gch
= escape()))
372 } else if (!cumode
&& gch
== character(value(RAISECHAR
))) {
373 boolean(value(RAISE
)) = !boolean(value(RAISE
));
375 } else if (gch
== '\r') {
377 parwrite(FD
, &gch
, 1);
378 if (boolean(value(HALFDUPLEX
)))
379 (void) printf("\r\n");
381 } else if (!cumode
&& gch
== character(value(FORCE
)))
382 gch
= getchar()&0377;
383 bol
= any(gch
, value(EOL
));
384 if (boolean(value(RAISE
)) && islower(gch
))
387 parwrite(FD
, &gch
, 1);
388 if (boolean(value(HALFDUPLEX
)))
395 * called on recognition of ``escapec'' at the beginning of a line
402 char c
= character(value(ESCAPE
));
404 gch
= (getchar()&0377);
405 for (p
= etable
; p
->e_char
; p
++)
406 if (p
->e_char
== gch
) {
407 if ((p
->e_flags
&PRIV
) && uid
)
409 (void) printf("%s", ctrl(c
));
413 /* ESCAPE ESCAPE forces ESCAPE */
415 parwrite(FD
, (unsigned char *)&c
, 1);
424 for (p
= bauds
; *p
!= -1; p
++)
442 static char buf
[256];
443 char *p
= buf
, c
, *q
;
446 for (q
= "\nn\rr\tt\ff\033E\bb"; *q
; q
++)
448 *p
++ = '\\'; *p
++ = *q
;
452 *p
++ = '^'; *p
++ = c
+ 'A'-1;
453 } else if (c
== 0177) {
454 *p
++ = '^'; *p
++ = '?';
469 if (c
< 040 || c
== 0177) {
471 s
[1] = c
== 0177 ? '?' : c
+'A'-1;
488 (void) printf("%c\r\n", c
);
489 for (p
= etable
; p
->e_char
; p
++) {
490 if ((p
->e_flags
&PRIV
) && uid
)
492 (void) printf("%2s", ctrl(character(value(ESCAPE
))));
493 (void) printf("%-2s %c %s\r\n", ctrl(p
->e_char
),
494 p
->e_flags
&EXP
? '*': ' ', p
->e_help
);
499 * Set up the "remote" tty's state
507 (void) ioctl(FD
, TCGETS
, (char *)&buf
);
508 buf
.c_cflag
&= (CREAD
|HUPCL
|CLOCAL
|CRTSCTS
|CRTSXOFF
);
510 (void) cfsetospeed(&buf
, speed
);
511 if (boolean(value(HARDWAREFLOW
))) {
515 * Only set hardware flow control if carrier is up,
516 * because some devices require both CD and RTS to
517 * be up before sending.
519 (void) ioctl(FD
, TIOCMGET
, &i
);
521 buf
.c_cflag
|= (CRTSCTS
|CRTSXOFF
);
525 * Careful to only penalize the 8-bit users here on the
526 * incoming tty port. The default 7-bit users will
527 * still get the parity bit from the other side's login
528 * process (which happens to be the default for sun tip
531 loc
= setlocale(LC_CTYPE
, NULL
);
532 if (noparity
&& loc
!= 0 && strcmp(loc
, "C") != 0)
535 buf
.c_iflag
= ISTRIP
;
540 (void) ioctl(FD
, TCSETSF
, (char *)&buf
);
544 * Return "simple" name from a file name,
545 * strip leading directories.
558 static char partab
[0400];
561 * Do a write to the remote machine with the correct parity.
562 * We are doing 8 bit wide output, so we just generate a character
563 * with the right parity and output it.
566 parwrite(int fd
, unsigned char *buf
, int n
)
572 for (i
= 0; i
< n
; i
++) {
573 *bp
= partab
[(*bp
)&0377];
576 if (write(fd
, buf
, n
) < 0) {
577 if (errno
== EIO
|| errno
== ENXIO
)
578 tip_abort("Lost carrier.");
579 /* this is questionable */
585 * Build a parity table with appropriate high-order bit.
588 setparity(char *defparity
)
593 if (value(PARITY
) == NOSTR
)
594 value(PARITY
) = defparity
;
595 parity
= value(PARITY
);
596 for (i
= 0; i
< 0400; i
++)
597 partab
[i
] = evenpartab
[i
];
598 if (equal(parity
, "even")) {
600 } else if (equal(parity
, "odd")) {
601 for (i
= 0; i
< 0400; i
++)
602 partab
[i
] ^= 0200; /* reverse bit 7 */
603 } else if (equal(parity
, "none")) {
604 /* Do nothing so we can pass thru 8-bit chars */
606 for (i
= 0; i
< 0400; i
++)
608 } else if (equal(parity
, "zero")) {
609 for (i
= 0; i
< 0400; i
++)
610 partab
[i
] &= ~0200; /* turn off bit 7 */
611 } else if (equal(parity
, "one")) {
612 for (i
= 0; i
< 0400; i
++)
613 partab
[i
] |= 0200; /* turn on bit 7 */
615 (void) fprintf(stderr
, "%s: unknown parity value\n", PA
);
616 (void) fflush(stderr
);