2 * Copyright (c) 1983, 1993
3 * The Regents of the University of California. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the University nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * @(#) Copyright (c) 1983, 1993 The Regents of the University of California. All rights reserved.
30 * @(#)tip.c 8.1 (Berkeley) 6/6/93
31 * $FreeBSD: src/usr.bin/tip/tip/tip.c,v 1.12.2.2 2001/06/02 08:08:24 phk Exp $
37 void ttysetup (int speed
);
40 * tip - UNIX link to other systems
41 * tip [-v] [-speed] system-name
43 * cu phone-number [-s speed] [-l line] [-a acu]
48 #include <sys/types.h>
51 #include "pathnames.h"
53 static void intprompt(int);
54 static void killchild(void);
55 static void tipdone(int);
56 static char *sname(char *);
57 char PNbuf
[256]; /* This limits the size of a number */
59 static void usage(void);
60 void setparity(char *);
61 void xpwrite(int, char *, int);
64 int prompt(char *, char *, size_t);
67 void daemon_uid(void);
71 main(int argc
, char *argv
[])
83 if (equal(sname(argv
[0]), "cu")) {
92 errx(1, "must be interactive");
94 for (; argc
> 1; argv
++, argc
--) {
95 if (argv
[1][0] != '-')
97 else switch (argv
[1][1]) {
103 case '0': case '1': case '2': case '3': case '4':
104 case '5': case '6': case '7': case '8': case '9':
105 BR
= atoi(&argv
[1][1]);
109 warnx("%s, unknown option", argv
[1]);
116 if (isalpha(*system
))
119 * System name is really a phone number...
120 * Copy the number then stomp on the original (in case the number
121 * is private, we don't want 'ps' or 'w' to find it).
123 if (strlen(system
) > sizeof(PNbuf
) - 1)
124 errx(1, "phone number too long (max = %zd bytes)", sizeof PNbuf
- 1);
125 strncpy(PNbuf
, system
, sizeof(PNbuf
) - 1);
126 for (p
= system
; *p
; p
++)
129 (void)snprintf(sbuf
, sizeof(sbuf
), "tip%ld", BR
);
133 (void)signal(SIGINT
, cleanup
);
134 (void)signal(SIGQUIT
, cleanup
);
135 (void)signal(SIGHUP
, cleanup
);
136 (void)signal(SIGTERM
, cleanup
);
137 (void)signal(SIGUSR1
, tipdone
);
139 if ((i
= hunt(system
)) == 0) {
140 printf("all ports busy\n");
144 printf("link down\n");
145 (void)uu_unlock(uucplock
);
148 setbuf(stdout
, NULL
);
152 * Kludge, their's no easy way to get the initialization
153 * in the right order, so force it here
155 if ((PH
= getenv("PHONES")) == NULL
)
157 vinit(); /* init variables */
158 setparity("even"); /* set the parity table */
159 if ((i
= speed(number(value(BAUDRATE
)))) == 0) {
160 printf("tip: bad baud rate %d\n", number(value(BAUDRATE
)));
161 (void)uu_unlock(uucplock
);
166 * Now that we have the logfile and the ACU open
167 * return to the real uid and gid. These things will
168 * be closed on exit. Swap real and effective uid's
169 * so we can get the original permissions back
170 * for removing the uucp lock.
175 * Hardwired connections require the
176 * line speed set before they make any transmissions
177 * (this is particularly true of things like a DF03-AC)
181 if ((p
= connect())) {
182 printf("\07%s\n[EOT]\n", p
);
184 (void)uu_unlock(uucplock
);
191 * From here down the code is shared with
192 * the "cu" version of tip.
195 tcgetattr (0, &otermios
);
197 ctermios
.c_iflag
= (IMAXBEL
|IXANY
|ISTRIP
|IXON
|BRKINT
);
198 ctermios
.c_lflag
= (PENDIN
|IEXTEN
|ISIG
|ECHOCTL
|ECHOE
|ECHOKE
);
199 ctermios
.c_cflag
= (CLOCAL
|HUPCL
|CREAD
|CS8
);
200 ctermios
.c_cc
[VINTR
] = ctermios
.c_cc
[VQUIT
] = -1;
201 ctermios
.c_cc
[VSUSP
] = ctermios
.c_cc
[VDSUSP
] = ctermios
.c_cc
[VDISCARD
] =
202 ctermios
.c_cc
[VLNEXT
] = -1;
205 pipe(fildes
); pipe(repdes
);
206 (void)signal(SIGALRM
, timeoutfunc
);
209 * Everything's set up now:
210 * connection established (hardwired or dialup)
211 * line conditioned (baud rate, mode, etc.)
212 * internal data structures (variables)
213 * so, fork one process for local side and one for remote.
215 printf(cumode
? "Connected\r\n" : "\07connected\r\n");
217 if (LI
!= NULL
&& tiplink (LI
, 0) != 0) {
218 tipabort ("login failed");
231 fprintf(stderr
, "usage: tip [-v] [-speed] [system-name]\n");
249 (void)uu_unlock(uucplock
);
259 * Muck with user ID's. We are setuid to the owner of the lock
260 * directory when we start. user_uid() reverses real and effective
261 * ID's after startup, to run with the user's permissions.
262 * daemon_uid() switches back to the privileged uid for unlocking.
263 * Finally, to avoid running a shell with the wrong real uid,
264 * shell_uid() sets real and effective uid's to the user's real ID.
266 static int uidswapped
;
271 if (uidswapped
== 0) {
294 * put the controlling keyboard into raw mode
299 tcsetattr (0, TCSANOW
, &ctermios
);
304 * return keyboard to normal mode
309 tcsetattr (0, TCSANOW
, &otermios
);
312 static jmp_buf promptbuf
;
315 * Print string ``s'', then read a string
316 * in from the terminal. Handles signals & allows use of
317 * normal erase and kill characters.
320 prompt(char *s
, char *p
, size_t sz
)
326 oint
= signal(SIGINT
, intprompt
);
327 oquit
= signal(SIGQUIT
, SIG_IGN
);
330 if (setjmp(promptbuf
) == 0)
331 while ((*p
= getchar()) != EOF
&& *p
!= '\n' && --sz
> 0)
336 (void)signal(SIGINT
, oint
);
337 (void)signal(SIGQUIT
, oquit
);
338 return (stoprompt
|| p
== b
);
342 * Interrupt service routine during prompting
348 (void)signal(SIGINT
, SIG_IGN
);
351 longjmp(promptbuf
, 1);
355 * ****TIPIN TIPIN****
366 * Kinda klugey here...
367 * check for scripting being turned on from the .tiprc file,
368 * but be careful about just using setscript(), as we may
369 * send a SIGEMT before tipout has a chance to set up catching
370 * it; so wait a second, then setscript()
372 if (boolean(value(SCRIPT
))) {
382 if ((gch
== character(value(ESCAPE
))) && bol
) {
383 if (!(gch
= escape()))
385 } else if (!cumode
&& gch
== character(value(RAISECHAR
))) {
386 boolean(value(RAISE
)) = !boolean(value(RAISE
));
388 } else if (gch
== '\r') {
390 xpwrite(FD
, &gch
, 1);
391 if (boolean(value(HALFDUPLEX
)))
394 } else if (!cumode
&& gch
== character(value(FORCE
))) {
400 bol
= any(gch
, value(EOL
));
401 if (boolean(value(RAISE
)) && islower(gch
))
403 xpwrite(FD
, &gch
, 1);
404 if (boolean(value(HALFDUPLEX
)))
409 extern esctable_t etable
[];
413 * called on recognition of ``escapec'' at the beginning of a line
420 char c
= character(value(ESCAPE
));
427 for (p
= etable
; p
->e_char
; p
++)
428 if (p
->e_char
== gch
) {
429 if ((p
->e_flags
&PRIV
) && uid
)
431 printf("%s", ctrl(c
));
435 /* ESCAPE ESCAPE forces ESCAPE */
469 static char buf
[256];
470 char *p
= buf
, c
, *q
;
473 for (q
= "\nn\rr\tt\ff\033E\bb"; *q
; q
++)
475 *p
++ = '\\'; *p
++ = *q
;
479 *p
++ = '^'; *p
++ = c
+ 'A'-1;
480 } else if (c
== 0177) {
481 *p
++ = '^'; *p
++ = '?';
496 if (c
< 040 || c
== 0177) {
498 s
[1] = c
== 0177 ? '?' : c
+'A'-1;
516 for (p
= etable
; p
->e_char
; p
++) {
517 if ((p
->e_flags
&PRIV
) && uid
)
519 printf("%2s", ctrl(character(value(ESCAPE
))));
520 printf("%-2s %c %s\r\n", ctrl(p
->e_char
),
521 (p
->e_flags
&EXP
) ? '*': ' ', p
->e_help
);
526 * Set up the "remote" tty's state
531 struct termios termios
;
532 tcgetattr (FD
, &termios
);
533 if (boolean(value(TAND
)))
534 termios
.c_iflag
= IXOFF
;
537 termios
.c_lflag
= (PENDIN
|ECHOKE
|ECHOE
);
538 termios
.c_cflag
= (CLOCAL
|HUPCL
|CREAD
|CS8
);
539 termios
.c_ispeed
= termios
.c_ospeed
= speed
;
540 tcsetattr (FD
, TCSANOW
, &termios
);
544 * Return "simple" name from a file name,
545 * strip leading directories.
558 static char partab
[0200];
562 * Do a write to the remote machine with the correct parity.
563 * We are doing 8 bit wide output, so we just generate a character
564 * with the right parity and output it.
567 xpwrite(int fd
, char *buf
, int n
)
574 for (i
= 0; i
< n
; i
++) {
575 *bp
= partab
[(*bp
) & 0177];
578 if (write(fd
, buf
, n
) < 0) {
580 tipabort("Lost carrier.");
582 tipabort("tty not available.");
583 tipabort("Something wrong...");
588 * Build a parity table with appropriate high-order bit.
591 setparity(char *defparity
)
593 int i
, flip
, clr
, set
;
595 extern char evenpartab
[];
597 if (value(PARITY
) == NULL
)
598 value(PARITY
) = defparity
;
599 parity
= value(PARITY
);
600 if (equal(parity
, "none")) {
608 if (equal(parity
, "odd"))
609 flip
= 0200; /* reverse bit 7 */
610 else if (equal(parity
, "zero"))
611 clr
= 0177; /* turn off bit 7 */
612 else if (equal(parity
, "one"))
613 set
= 0200; /* turn on bit 7 */
614 else if (!equal(parity
, "even")) {
615 (void) fprintf(stderr
, "%s: unknown parity value\r\n", parity
);
616 (void) fflush(stderr
);
618 for (i
= 0; i
< 0200; i
++)
619 partab
[i
] = (evenpartab
[i
] ^ flip
) | (set
& clr
);