Remove __P macros from src/usr.bin and src/usr.sbin.
[dragonfly.git] / usr.bin / tip / tip / tip.c
CommitLineData
984263bc
MD
1/*
2 * Copyright (c) 1983, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
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. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
1de703da
MD
32 *
33 * @(#) Copyright (c) 1983, 1993 The Regents of the University of California. All rights reserved.
34 * @(#)tip.c 8.1 (Berkeley) 6/6/93
35 * $FreeBSD: src/usr.bin/tip/tip/tip.c,v 1.12.2.2 2001/06/02 08:08:24 phk Exp $
2d8a3be7 36 * $DragonFly: src/usr.bin/tip/tip/tip.c,v 1.3 2003/11/03 19:31:33 eirikn Exp $
984263bc
MD
37 */
38
984263bc
MD
39/*
40 Forward declarations
41*/
42void ttysetup (int speed);
43
44/*
45 * tip - UNIX link to other systems
46 * tip [-v] [-speed] system-name
47 * or
48 * cu phone-number [-s speed] [-l line] [-a acu]
49 */
50
51#include <err.h>
52#include <errno.h>
53#include <sys/types.h>
54#include <libutil.h>
55#include "tipconf.h"
56#include "tip.h"
57#include "pathnames.h"
58
59/*
60 * Baud rate mapping table
61 */
62#if !HAVE_TERMIOS
63CONST int bauds[] = {
64 0, 50, 75, 110, 134, 150, 200, 300, 600,
65 1200, 1800, 2400, 4800, 9600, 19200, 38400, 57600, 115200, -1
66};
67#endif
68
69#if !HAVE_TERMIOS
70int disc = OTTYDISC; /* tip normally runs this way */
71#endif
72
73void intprompt();
74void timeout();
75void killchild();
76void cleanup();
77void tipdone();
78char *sname();
79char PNbuf[256]; /* This limits the size of a number */
80
2d8a3be7
EN
81static void usage(void);
82void setparity(char *);
83void xpwrite(int, char *, int);
84char escape(void);
85void tipin(void);
86int prompt(char *, char *, size_t);
87void unraw(void);
88void shell_uid(void);
89void daemon_uid(void);
90void user_uid(void);
91int speed(int);
984263bc
MD
92
93int
94main(argc, argv)
95 char *argv[];
96{
97 char *system = NOSTR;
98 register int i;
99 register char *p;
100 char sbuf[12];
101
102 gid = getgid();
103 egid = getegid();
104 uid = getuid();
105 euid = geteuid();
106
107#if INCLUDE_CU_INTERFACE
108 if (equal(sname(argv[0]), "cu")) {
109 cumode = 1;
110 cumain(argc, argv);
111 goto cucommon;
112 }
113#endif /* INCLUDE_CU_INTERFACE */
114
115 if (argc > 4)
116 usage();
117 if (!isatty(0))
118 errx(1, "must be interactive");
119
120 for (; argc > 1; argv++, argc--) {
121 if (argv[1][0] != '-')
122 system = argv[1];
123 else switch (argv[1][1]) {
124
125 case 'v':
126 vflag++;
127 break;
128
129 case '0': case '1': case '2': case '3': case '4':
130 case '5': case '6': case '7': case '8': case '9':
131 BR = atoi(&argv[1][1]);
132 break;
133
134 default:
135 warnx("%s, unknown option", argv[1]);
136 break;
137 }
138 }
139
140 if (system == NOSTR)
141 goto notnumber;
142 if (isalpha(*system))
143 goto notnumber;
144 /*
145 * System name is really a phone number...
146 * Copy the number then stomp on the original (in case the number
147 * is private, we don't want 'ps' or 'w' to find it).
148 */
149 if (strlen(system) > sizeof(PNbuf) - 1)
150 errx(1, "phone number too long (max = %d bytes)", sizeof PNbuf - 1);
151 strncpy(PNbuf, system, sizeof(PNbuf) - 1);
152 for (p = system; *p; p++)
153 *p = '\0';
154 PN = PNbuf;
155 (void)snprintf(sbuf, sizeof(sbuf), "tip%ld", BR);
156 system = sbuf;
157
158notnumber:
159 (void)signal(SIGINT, cleanup);
160 (void)signal(SIGQUIT, cleanup);
161 (void)signal(SIGHUP, cleanup);
162 (void)signal(SIGTERM, cleanup);
163 (void)signal(SIGUSR1, tipdone);
164
165 if ((i = hunt(system)) == 0) {
166 printf("all ports busy\n");
167 exit(3);
168 }
169 if (i == -1) {
170 printf("link down\n");
171 (void)uu_unlock(uucplock);
172 exit(3);
173 }
174 setbuf(stdout, NULL);
175 loginit();
176
177 /*
178 * Kludge, their's no easy way to get the initialization
179 * in the right order, so force it here
180 */
181 if ((PH = getenv("PHONES")) == NOSTR)
182 PH = _PATH_PHONES;
183 vinit(); /* init variables */
184 setparity("even"); /* set the parity table */
185 if ((i = speed(number(value(BAUDRATE)))) == 0) {
186 printf("tip: bad baud rate %d\n", number(value(BAUDRATE)));
187 (void)uu_unlock(uucplock);
188 exit(3);
189 }
190
191 /*
192 * Now that we have the logfile and the ACU open
193 * return to the real uid and gid. These things will
194 * be closed on exit. Swap real and effective uid's
195 * so we can get the original permissions back
196 * for removing the uucp lock.
197 */
198 user_uid();
199
200 /*
201 * Hardwired connections require the
202 * line speed set before they make any transmissions
203 * (this is particularly true of things like a DF03-AC)
204 */
205 if (HW)
206 ttysetup(i);
207 if ((p = connect())) {
208 printf("\07%s\n[EOT]\n", p);
209 daemon_uid();
210 (void)uu_unlock(uucplock);
211 exit(1);
212 }
213 if (!HW)
214 ttysetup(i);
215/* cucommon:*/
216 /*
217 * From here down the code is shared with
218 * the "cu" version of tip.
219 */
220
221#if HAVE_TERMIOS
222 tcgetattr (0, &otermios);
223 ctermios = otermios;
224#ifndef _POSIX_SOURCE
225 ctermios.c_iflag = (IMAXBEL|IXANY|ISTRIP|IXON|BRKINT);
226 ctermios.c_lflag = (PENDIN|IEXTEN|ISIG|ECHOCTL|ECHOE|ECHOKE);
227#else
228 ctermios.c_iflag = (ISTRIP|IXON|BRKINT);
229 ctermios.c_lflag = (PENDIN|IEXTEN|ISIG|ECHOE);
230#endif
231 ctermios.c_cflag = (CLOCAL|HUPCL|CREAD|CS8);
232 ctermios.c_cc[VINTR] = ctermios.c_cc[VQUIT] = -1;
233 ctermios.c_cc[VSUSP] = ctermios.c_cc[VDSUSP] = ctermios.c_cc[VDISCARD] =
234 ctermios.c_cc[VLNEXT] = -1;
235#else /* HAVE_TERMIOS */
236 ioctl(0, TIOCGETP, (char *)&defarg);
237 ioctl(0, TIOCGETC, (char *)&defchars);
238 ioctl(0, TIOCGLTC, (char *)&deflchars);
239 ioctl(0, TIOCGETD, (char *)&odisc);
240 arg = defarg;
241 arg.sg_flags = ANYP | CBREAK;
242 tchars = defchars;
243 tchars.t_intrc = tchars.t_quitc = -1;
244 ltchars = deflchars;
245 ltchars.t_suspc = ltchars.t_dsuspc = ltchars.t_flushc
246 = ltchars.t_lnextc = -1;
247#endif /* HAVE_TERMIOS */
248 raw();
249
250 pipe(fildes); pipe(repdes);
251 (void)signal(SIGALRM, timeout);
252
253 /*
254 * Everything's set up now:
255 * connection established (hardwired or dialup)
256 * line conditioned (baud rate, mode, etc.)
257 * internal data structures (variables)
258 * so, fork one process for local side and one for remote.
259 */
260 printf(cumode ? "Connected\r\n" : "\07connected\r\n");
261
262 if (LI != NOSTR && tiplink (LI, 0) != 0) {
263 tipabort ("login failed");
264 }
265
266 if ((pid = fork()))
267 tipin();
268 else
269 tipout();
270 /*NOTREACHED*/
271}
272
273static void
274usage()
275{
276 fprintf(stderr, "usage: tip [-v] [-speed] [system-name]\n");
277 exit(1);
278}
279
280void
281killchild()
282{
283 if (pid != 0) {
284 kill(pid, SIGTERM);
285 pid = 0;
286 }
287}
288
289void
290cleanup()
291{
292
293 daemon_uid();
294 (void)uu_unlock(uucplock);
295#if !HAVE_TERMIOS
296 if (odisc)
297 ioctl(0, TIOCSETD, (char *)&odisc);
298#endif
299 exit(0);
300}
301
302void
303tipdone()
304{
305 tipabort("Hangup.");
306}
307/*
308 * Muck with user ID's. We are setuid to the owner of the lock
309 * directory when we start. user_uid() reverses real and effective
310 * ID's after startup, to run with the user's permissions.
311 * daemon_uid() switches back to the privileged uid for unlocking.
312 * Finally, to avoid running a shell with the wrong real uid,
313 * shell_uid() sets real and effective uid's to the user's real ID.
314 */
315static int uidswapped;
316
317void
318user_uid()
319{
320 if (uidswapped == 0) {
321 seteuid(uid);
322 uidswapped = 1;
323 }
324}
325
326void
327daemon_uid()
328{
329 if (uidswapped) {
330 seteuid(euid);
331 uidswapped = 0;
332 }
333}
334
335void
336shell_uid()
337{
338 setegid(gid);
339 seteuid(uid);
340}
341
342/*
343 * put the controlling keyboard into raw mode
344 */
345void
346raw ()
347{
348#if HAVE_TERMIOS
349 tcsetattr (0, TCSANOW, &ctermios);
350#else /* HAVE_TERMIOS */
351
352 ioctl(0, TIOCSETP, &arg);
353 ioctl(0, TIOCSETC, &tchars);
354 ioctl(0, TIOCSLTC, &ltchars);
355 ioctl(0, TIOCSETD, (char *)&disc);
356#endif /* HAVE_TERMIOS */
357}
358
359
360/*
361 * return keyboard to normal mode
362 */
363void
364unraw()
365{
366#if HAVE_TERMIOS
367 tcsetattr (0, TCSANOW, &otermios);
368#else /* HAVE_TERMIOS */
369
370 ioctl(0, TIOCSETD, (char *)&odisc);
371 ioctl(0, TIOCSETP, (char *)&defarg);
372 ioctl(0, TIOCSETC, (char *)&defchars);
373 ioctl(0, TIOCSLTC, (char *)&deflchars);
374#endif /* HAVE_TERMIOS */
375}
376
377static jmp_buf promptbuf;
378
379/*
380 * Print string ``s'', then read a string
381 * in from the terminal. Handles signals & allows use of
382 * normal erase and kill characters.
383 */
384int
385prompt(s, p, sz)
386 char *s;
387 register char *p;
388 size_t sz;
389{
390 register char *b = p;
391 sig_t oint, oquit;
392
393 stoprompt = 0;
394 oint = signal(SIGINT, intprompt);
395 oquit = signal(SIGQUIT, SIG_IGN);
396 unraw();
397 printf("%s", s);
398 if (setjmp(promptbuf) == 0)
399 while ((*p = getchar()) != EOF && *p != '\n' && --sz > 0)
400 p++;
401 *p = '\0';
402
403 raw();
404 (void)signal(SIGINT, oint);
405 (void)signal(SIGQUIT, oquit);
406 return (stoprompt || p == b);
407}
408
409/*
410 * Interrupt service routine during prompting
411 */
412void
413intprompt()
414{
415
416 (void)signal(SIGINT, SIG_IGN);
417 stoprompt = 1;
418 printf("\r\n");
419 longjmp(promptbuf, 1);
420}
421
422/*
423 * ****TIPIN TIPIN****
424 */
425void
426tipin()
427{
428 int i;
429 char gch, bol = 1;
430
431 atexit(killchild);
432
433 /*
434 * Kinda klugey here...
435 * check for scripting being turned on from the .tiprc file,
436 * but be careful about just using setscript(), as we may
437 * send a SIGEMT before tipout has a chance to set up catching
438 * it; so wait a second, then setscript()
439 */
440 if (boolean(value(SCRIPT))) {
441 sleep(1);
442 setscript();
443 }
444
445 while (1) {
446 i = getchar();
447 if (i == EOF)
448 break;
449 gch = i&0177;
450 if ((gch == character(value(ESCAPE))) && bol) {
451 if (!(gch = escape()))
452 continue;
453 } else if (!cumode && gch == character(value(RAISECHAR))) {
454 boolean(value(RAISE)) = !boolean(value(RAISE));
455 continue;
456 } else if (gch == '\r') {
457 bol = 1;
458 xpwrite(FD, &gch, 1);
459 if (boolean(value(HALFDUPLEX)))
460 printf("\r\n");
461 continue;
462 } else if (!cumode && gch == character(value(FORCE))) {
463 i = getchar();
464 if (i == EOF)
465 break;
466 gch = i & 0177;
467 }
468 bol = any(gch, value(EOL));
469 if (boolean(value(RAISE)) && islower(gch))
470 gch = toupper(gch);
471 xpwrite(FD, &gch, 1);
472 if (boolean(value(HALFDUPLEX)))
473 printf("%c", gch);
474 }
475}
476
477extern esctable_t etable[];
478
479/*
480 * Escape handler --
481 * called on recognition of ``escapec'' at the beginning of a line
482 */
483char
484escape()
485{
486 register char gch;
487 register esctable_t *p;
488 char c = character(value(ESCAPE));
489 int i;
490
491 i = getchar();
492 if (i == EOF)
493 return 0;
494 gch = (i&0177);
495 for (p = etable; p->e_char; p++)
496 if (p->e_char == gch) {
497 if ((p->e_flags&PRIV) && uid)
498 continue;
499 printf("%s", ctrl(c));
500 (*p->e_func)(gch);
501 return (0);
502 }
503 /* ESCAPE ESCAPE forces ESCAPE */
504 if (c != gch)
505 xpwrite(FD, &c, 1);
506 return (gch);
507}
508
509int
510speed(n)
511 int n;
512{
513#if HAVE_TERMIOS
514 return (n);
515#else
516 register CONST int *p;
517
518 for (p = bauds; *p != -1; p++)
519 if (*p == n)
520 return (p - bauds);
521 return (NULL);
522#endif
523}
524
525int
526any(c, p)
527 register char c, *p;
528{
529 while (p && *p)
530 if (*p++ == c)
531 return (1);
532 return (0);
533}
534
535int
536size(s)
537 register char *s;
538{
539 register int i = 0;
540
541 while (s && *s++)
542 i++;
543 return (i);
544}
545
546char *
547interp(s)
548 register char *s;
549{
550 static char buf[256];
551 register char *p = buf, c, *q;
552
553 while ((c = *s++)) {
554 for (q = "\nn\rr\tt\ff\033E\bb"; *q; q++)
555 if (*q++ == c) {
556 *p++ = '\\'; *p++ = *q;
557 goto next;
558 }
559 if (c < 040) {
560 *p++ = '^'; *p++ = c + 'A'-1;
561 } else if (c == 0177) {
562 *p++ = '^'; *p++ = '?';
563 } else
564 *p++ = c;
565 next:
566 ;
567 }
568 *p = '\0';
569 return (buf);
570}
571
572char *
573ctrl(c)
574 char c;
575{
576 static char s[3];
577
578 if (c < 040 || c == 0177) {
579 s[0] = '^';
580 s[1] = c == 0177 ? '?' : c+'A'-1;
581 s[2] = '\0';
582 } else {
583 s[0] = c;
584 s[1] = '\0';
585 }
586 return (s);
587}
588
589/*
590 * Help command
591 */
592void
593help(c)
594 char c;
595{
596 register esctable_t *p;
597
598 printf("%c\r\n", c);
599 for (p = etable; p->e_char; p++) {
600 if ((p->e_flags&PRIV) && uid)
601 continue;
602 printf("%2s", ctrl(character(value(ESCAPE))));
603 printf("%-2s %c %s\r\n", ctrl(p->e_char),
604 p->e_flags&EXP ? '*': ' ', p->e_help);
605 }
606}
607
608/*
609 * Set up the "remote" tty's state
610 */
611void
612ttysetup (int speed)
613{
614#if HAVE_TERMIOS
615 struct termios termios;
616 tcgetattr (FD, &termios);
617 if (boolean(value(TAND)))
618 termios.c_iflag = IXOFF;
619 else
620 termios.c_iflag = 0;
621#ifndef _POSIX_SOURCE
622 termios.c_lflag = (PENDIN|ECHOKE|ECHOE);
623#else
624 termios.c_lflag = (PENDIN|ECHOE);
625#endif
626 termios.c_cflag = (CLOCAL|HUPCL|CREAD|CS8);
627 termios.c_ispeed = termios.c_ospeed = speed;
628 tcsetattr (FD, TCSANOW, &termios);
629#else /* HAVE_TERMIOS */
630 unsigned bits = LDECCTQ;
631
632 arg.sg_ispeed = arg.sg_ospeed = speed;
633 arg.sg_flags = RAW;
634 if (boolean(value(TAND)))
635 arg.sg_flags |= TANDEM;
636 ioctl(FD, TIOCSETP, (char *)&arg);
637 ioctl(FD, TIOCLBIS, (char *)&bits);
638#endif /* HAVE_TERMIOS */
639}
640
641/*
642 * Return "simple" name from a file name,
643 * strip leading directories.
644 */
645char *
646sname(s)
647 register char *s;
648{
649 register char *p = s;
650
651 while (*s)
652 if (*s++ == '/')
653 p = s;
654 return (p);
655}
656
657static char partab[0200];
658static int bits8;
659
660/*
661 * Do a write to the remote machine with the correct parity.
662 * We are doing 8 bit wide output, so we just generate a character
663 * with the right parity and output it.
664 */
665void
666xpwrite(fd, buf, n)
667 int fd;
668 char *buf;
669 register int n;
670{
671 register int i;
672 register char *bp;
673
674 bp = buf;
675 if (bits8 == 0)
676 for (i = 0; i < n; i++) {
677 *bp = partab[(*bp) & 0177];
678 bp++;
679 }
680 if (write(fd, buf, n) < 0) {
681 if (errno == EIO)
682 tipabort("Lost carrier.");
683 if (errno == ENODEV)
684 tipabort("tty not available.");
685 tipabort("Something wrong...");
686 }
687}
688
689/*
690 * Build a parity table with appropriate high-order bit.
691 */
692void
693setparity(defparity)
694 char *defparity;
695{
696 register int i, flip, clr, set;
697 char *parity;
698 extern char evenpartab[];
699
700 if (value(PARITY) == NOSTR)
701 value(PARITY) = defparity;
702 parity = value(PARITY);
703 if (equal(parity, "none")) {
704 bits8 = 1;
705 return;
706 }
707 bits8 = 0;
708 flip = 0;
709 clr = 0377;
710 set = 0;
711 if (equal(parity, "odd"))
712 flip = 0200; /* reverse bit 7 */
713 else if (equal(parity, "zero"))
714 clr = 0177; /* turn off bit 7 */
715 else if (equal(parity, "one"))
716 set = 0200; /* turn on bit 7 */
717 else if (!equal(parity, "even")) {
718 (void) fprintf(stderr, "%s: unknown parity value\r\n", parity);
719 (void) fflush(stderr);
720 }
721 for (i = 0; i < 0200; i++)
722 partab[i] = (evenpartab[i] ^ flip) | (set & clr);
723}