file reorg, pathnames.h, paths.h
[unix-history] / usr / src / usr.bin / tip / tip.c
CommitLineData
051b1e55 1/*
c9686c12
KB
2 * Copyright (c) 1983 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms are permitted
6 * provided that the above copyright notice and this paragraph are
7 * duplicated in all such forms and that any documentation,
8 * advertising materials, and other materials related to such
9 * distribution and use acknowledge that the software was developed
10 * by the University of California, Berkeley. The name of the
11 * University may not be used to endorse or promote products derived
12 * from this software without specific prior written permission.
13 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
051b1e55
DF
16 */
17
18#ifndef lint
19char copyright[] =
c9686c12 20"@(#) Copyright (c) 1983 The Regents of the University of California.\n\
051b1e55 21 All rights reserved.\n";
c9686c12 22#endif /* not lint */
051b1e55 23
05862919 24#ifndef lint
435e8dff 25static char sccsid[] = "@(#)tip.c 5.9 (Berkeley) %G%";
c9686c12 26#endif /* not lint */
3f48242d 27
5f50159a 28/*
3f48242d 29 * tip - UNIX link to other systems
5f50159a 30 * tip [-v] [-speed] system-name
3f48242d
SL
31 * or
32 * cu phone-number [-s speed] [-l line] [-a acu]
5f50159a 33 */
5f50159a 34#include "tip.h"
435e8dff 35#include "pathnames.h"
5f50159a
BJ
36
37/*
38 * Baud rate mapping table
39 */
40int bauds[] = {
41 0, 50, 75, 110, 134, 150, 200, 300, 600,
42 1200, 1800, 2400, 4800, 9600, 19200, -1
43};
44
4b675d70 45int disc = OTTYDISC; /* tip normally runs this way */
5f50159a
BJ
46int intprompt();
47int timeout();
3f48242d 48int cleanup();
c731dacc 49char *sname();
f1da3c6d 50char PNbuf[256]; /* This limits the size of a number */
5f50159a
BJ
51
52main(argc, argv)
d8feebc2 53 char *argv[];
5f50159a
BJ
54{
55 char *system = NOSTR;
56 register int i;
c731dacc
BS
57 register char *p;
58 char sbuf[12];
5f50159a 59
45d9e9af
MK
60 gid = getgid();
61 egid = getegid();
62 uid = getuid();
63 euid = geteuid();
c731dacc 64 if (equal(sname(argv[0]), "cu")) {
3f48242d 65 cumode = 1;
f95c3446 66 cumain(argc, argv);
3f48242d
SL
67 goto cucommon;
68 }
69
5f50159a
BJ
70 if (argc > 4) {
71 fprintf(stderr, "usage: tip [-v] [-speed] [system-name]\n");
72 exit(1);
73 }
74 if (!isatty(0)) {
75 fprintf(stderr, "tip: must be interactive\n");
76 exit(1);
77 }
c731dacc
BS
78
79 for (; argc > 1; argv++, argc--) {
80 if (argv[1][0] != '-')
81 system = argv[1];
82 else switch (argv[1][1]) {
83
84 case 'v':
85 vflag++;
86 break;
87
88 case '0': case '1': case '2': case '3': case '4':
89 case '5': case '6': case '7': case '8': case '9':
90 BR = atoi(&argv[1][1]);
91 break;
92
93 default:
94 fprintf(stderr, "tip: %s, unknown option\n", argv[1]);
95 break;
96 }
97 }
98
d080fb0b
BS
99 if (system == NOSTR)
100 goto notnumber;
7eabb9c8
DS
101 if (isalpha(*system))
102 goto notnumber;
f1da3c6d
DS
103 /*
104 * System name is really a phone number...
105 * Copy the number then stomp on the original (in case the number
106 * is private, we don't want 'ps' or 'w' to find it).
107 */
108 if (strlen(system) > sizeof PNbuf - 1) {
109 fprintf(stderr, "tip: phone number too long (max = %d bytes)\n",
110 sizeof PNbuf - 1);
111 exit(1);
112 }
113 strncpy( PNbuf, system, sizeof PNbuf - 1 );
114 for (p = system; *p; p++)
115 *p = '\0';
116 PN = PNbuf;
9a491ec2
KB
117 (void)sprintf(sbuf, "tip%d", BR);
118 system = sbuf;
c731dacc
BS
119
120notnumber:
5f50159a
BJ
121 signal(SIGINT, cleanup);
122 signal(SIGQUIT, cleanup);
123 signal(SIGHUP, cleanup);
124 signal(SIGTERM, cleanup);
f0211bf2 125
5f50159a
BJ
126 if ((i = hunt(system)) == 0) {
127 printf("all ports busy\n");
128 exit(3);
129 }
130 if (i == -1) {
131 printf("link down\n");
5d369851 132 (void)uu_unlock(uucplock);
5f50159a
BJ
133 exit(3);
134 }
eaa86232 135 setbuf(stdout, NULL);
5f50159a 136 loginit();
c731dacc 137
5f50159a
BJ
138 /*
139 * Kludge, their's no easy way to get the initialization
140 * in the right order, so force it here
141 */
142 if ((PH = getenv("PHONES")) == NOSTR)
435e8dff 143 PH = _PATH_PHONES;
5f50159a 144 vinit(); /* init variables */
dfec50f2 145 setparity("even"); /* set the parity table */
4b675d70 146 if ((i = speed(number(value(BAUDRATE)))) == NULL) {
5f50159a 147 printf("tip: bad baud rate %d\n", number(value(BAUDRATE)));
5d369851 148 (void)uu_unlock(uucplock);
5f50159a
BJ
149 exit(3);
150 }
f0211bf2 151
f95c3446
MK
152 /*
153 * Now that we have the logfile and the ACU open
154 * return to the real uid and gid. These things will
155 * be closed on exit. Swap real and effective uid's
156 * so we can get the original permissions back
157 * for removing the uucp lock.
158 */
45d9e9af 159 user_uid();
f95c3446 160
4b675d70
SL
161 /*
162 * Hardwired connections require the
163 * line speed set before they make any transmissions
164 * (this is particularly true of things like a DF03-AC)
165 */
166 if (HW)
167 ttysetup(i);
f0211bf2
SL
168 if (p = connect()) {
169 printf("\07%s\n[EOT]\n", p);
45d9e9af 170 daemon_uid();
5d369851 171 (void)uu_unlock(uucplock);
f0211bf2
SL
172 exit(1);
173 }
4b675d70
SL
174 if (!HW)
175 ttysetup(i);
3f48242d 176cucommon:
5f50159a 177 /*
3f48242d
SL
178 * From here down the code is shared with
179 * the "cu" version of tip.
5f50159a 180 */
f95c3446 181
4b675d70
SL
182 ioctl(0, TIOCGETP, (char *)&defarg);
183 ioctl(0, TIOCGETC, (char *)&defchars);
c5d1037a 184 ioctl(0, TIOCGLTC, (char *)&deflchars);
4b675d70 185 ioctl(0, TIOCGETD, (char *)&odisc);
5f50159a
BJ
186 arg = defarg;
187 arg.sg_flags = ANYP | CBREAK;
188 tchars = defchars;
189 tchars.t_intrc = tchars.t_quitc = -1;
c5d1037a
BJ
190 ltchars = deflchars;
191 ltchars.t_suspc = ltchars.t_dsuspc = ltchars.t_flushc
192 = ltchars.t_lnextc = -1;
5f50159a 193 raw();
4b675d70 194
5f50159a
BJ
195 pipe(fildes); pipe(repdes);
196 signal(SIGALRM, timeout);
f0211bf2
SL
197
198 /*
199 * Everything's set up now:
20f8c5bf 200 * connection established (hardwired or dialup)
f0211bf2
SL
201 * line conditioned (baud rate, mode, etc.)
202 * internal data structures (variables)
203 * so, fork one process for local side and one for remote.
204 */
3f48242d 205 printf(cumode ? "Connected\r\n" : "\07connected\r\n");
5f50159a
BJ
206 if (pid = fork())
207 tipin();
208 else
209 tipout();
210 /*NOTREACHED*/
211}
212
5f50159a
BJ
213cleanup()
214{
05862919 215
45d9e9af 216 daemon_uid();
5d369851 217 (void)uu_unlock(uucplock);
f0211bf2
SL
218 if (odisc)
219 ioctl(0, TIOCSETD, (char *)&odisc);
5f50159a
BJ
220 exit(0);
221}
222
45d9e9af
MK
223/*
224 * Muck with user ID's. We are setuid to the owner of the lock
225 * directory when we start. user_uid() reverses real and effective
226 * ID's after startup, to run with the user's permissions.
227 * daemon_uid() switches back to the privileged uid for unlocking.
228 * Finally, to avoid running a shell with the wrong real uid,
229 * shell_uid() sets real and effective uid's to the user's real ID.
230 */
231static int uidswapped;
232
233user_uid()
234{
235 if (uidswapped == 0) {
236 setregid(egid, gid);
237 setreuid(euid, uid);
238 uidswapped = 1;
239 }
240}
241
242daemon_uid()
243{
244
245 if (uidswapped) {
246 setreuid(uid, euid);
247 setregid(gid, egid);
248 uidswapped = 0;
249 }
250}
251
252shell_uid()
253{
254
255 setreuid(uid, uid);
256 setregid(gid, gid);
257}
258
5f50159a
BJ
259/*
260 * put the controlling keyboard into raw mode
261 */
262raw()
263{
05862919 264
5f50159a
BJ
265 ioctl(0, TIOCSETP, &arg);
266 ioctl(0, TIOCSETC, &tchars);
c5d1037a 267 ioctl(0, TIOCSLTC, &ltchars);
4b675d70 268 ioctl(0, TIOCSETD, (char *)&disc);
5f50159a
BJ
269}
270
271
272/*
273 * return keyboard to normal mode
274 */
275unraw()
276{
05862919 277
4b675d70 278 ioctl(0, TIOCSETD, (char *)&odisc);
4b675d70
SL
279 ioctl(0, TIOCSETP, (char *)&defarg);
280 ioctl(0, TIOCSETC, (char *)&defchars);
c5d1037a 281 ioctl(0, TIOCSLTC, (char *)&deflchars);
5f50159a
BJ
282}
283
05862919
SL
284static jmp_buf promptbuf;
285
5f50159a
BJ
286/*
287 * Print string ``s'', then read a string
288 * in from the terminal. Handles signals & allows use of
289 * normal erase and kill characters.
290 */
291prompt(s, p)
292 char *s;
293 register char *p;
294{
295 register char *b = p;
05862919 296 int (*oint)(), (*oquit)();
5f50159a
BJ
297
298 stoprompt = 0;
05862919
SL
299 oint = signal(SIGINT, intprompt);
300 oint = signal(SIGQUIT, SIG_IGN);
5f50159a
BJ
301 unraw();
302 printf("%s", s);
05862919
SL
303 if (setjmp(promptbuf) == 0)
304 while ((*p = getchar()) != EOF && *p != '\n')
305 p++;
5f50159a 306 *p = '\0';
05862919 307
5f50159a 308 raw();
05862919
SL
309 signal(SIGINT, oint);
310 signal(SIGQUIT, oint);
311 return (stoprompt || p == b);
5f50159a
BJ
312}
313
314/*
315 * Interrupt service routine during prompting
316 */
317intprompt()
318{
05862919 319
5f50159a
BJ
320 signal(SIGINT, SIG_IGN);
321 stoprompt = 1;
322 printf("\r\n");
05862919 323 longjmp(promptbuf, 1);
5f50159a
BJ
324}
325
326/*
327 * ****TIPIN TIPIN****
328 */
329tipin()
330{
331 char gch, bol = 1;
332
388a70dc
SL
333 /*
334 * Kinda klugey here...
335 * check for scripting being turned on from the .tiprc file,
336 * but be careful about just using setscript(), as we may
337 * send a SIGEMT before tipout has a chance to set up catching
338 * it; so wait a second, then setscript()
339 */
340 if (boolean(value(SCRIPT))) {
341 sleep(1);
342 setscript();
343 }
344
5f50159a
BJ
345 while (1) {
346 gch = getchar()&0177;
347 if ((gch == character(value(ESCAPE))) && bol) {
348 if (!(gch = escape()))
349 continue;
3f48242d 350 } else if (!cumode && gch == character(value(RAISECHAR))) {
5f50159a 351 boolean(value(RAISE)) = !boolean(value(RAISE));
5f50159a
BJ
352 continue;
353 } else if (gch == '\r') {
354 bol = 1;
6b46907f
RC
355 pwrite(FD, &gch, 1);
356 if (boolean(value(HALFDUPLEX)))
357 printf("\r\n");
5f50159a 358 continue;
3f48242d 359 } else if (!cumode && gch == character(value(FORCE)))
5f50159a 360 gch = getchar()&0177;
5f50159a
BJ
361 bol = any(gch, value(EOL));
362 if (boolean(value(RAISE)) && islower(gch))
6b46907f
RC
363 gch = toupper(gch);
364 pwrite(FD, &gch, 1);
365 if (boolean(value(HALFDUPLEX)))
366 printf("%c", gch);
5f50159a
BJ
367 }
368}
369
370/*
371 * Escape handler --
372 * called on recognition of ``escapec'' at the beginning of a line
373 */
374escape()
375{
376 register char gch;
377 register esctable_t *p;
378 char c = character(value(ESCAPE));
379 extern esctable_t etable[];
380
381 gch = (getchar()&0177);
382 for (p = etable; p->e_char; p++)
383 if (p->e_char == gch) {
45d9e9af 384 if ((p->e_flags&PRIV) && uid)
5f50159a
BJ
385 continue;
386 printf("%s", ctrl(c));
387 (*p->e_func)(gch);
05862919 388 return (0);
5f50159a 389 }
62f62be8
SL
390 /* ESCAPE ESCAPE forces ESCAPE */
391 if (c != gch)
6b46907f 392 pwrite(FD, &c, 1);
05862919 393 return (gch);
5f50159a
BJ
394}
395
396speed(n)
05862919 397 int n;
5f50159a
BJ
398{
399 register int *p;
400
401 for (p = bauds; *p != -1; p++)
402 if (*p == n)
05862919
SL
403 return (p - bauds);
404 return (NULL);
5f50159a
BJ
405}
406
407any(c, p)
408 register char c, *p;
409{
05862919 410 while (p && *p)
5f50159a 411 if (*p++ == c)
05862919
SL
412 return (1);
413 return (0);
5f50159a
BJ
414}
415
416size(s)
417 register char *s;
418{
05862919 419 register int i = 0;
5f50159a 420
05862919
SL
421 while (s && *s++)
422 i++;
423 return (i);
5f50159a
BJ
424}
425
426char *
427interp(s)
428 register char *s;
429{
430 static char buf[256];
431 register char *p = buf, c, *q;
432
433 while (c = *s++) {
434 for (q = "\nn\rr\tt\ff\033E\bb"; *q; q++)
435 if (*q++ == c) {
436 *p++ = '\\'; *p++ = *q;
437 goto next;
438 }
439 if (c < 040) {
440 *p++ = '^'; *p++ = c + 'A'-1;
441 } else if (c == 0177) {
442 *p++ = '^'; *p++ = '?';
443 } else
444 *p++ = c;
445 next:
446 ;
447 }
448 *p = '\0';
05862919 449 return (buf);
5f50159a
BJ
450}
451
452char *
453ctrl(c)
454 char c;
455{
456 static char s[3];
457
458 if (c < 040 || c == 0177) {
459 s[0] = '^';
460 s[1] = c == 0177 ? '?' : c+'A'-1;
461 s[2] = '\0';
462 } else {
463 s[0] = c;
464 s[1] = '\0';
465 }
05862919 466 return (s);
5f50159a
BJ
467}
468
469/*
470 * Help command
471 */
472help(c)
473 char c;
474{
475 register esctable_t *p;
476 extern esctable_t etable[];
477
478 printf("%c\r\n", c);
479 for (p = etable; p->e_char; p++) {
45d9e9af 480 if ((p->e_flags&PRIV) && uid)
5f50159a
BJ
481 continue;
482 printf("%2s", ctrl(character(value(ESCAPE))));
483 printf("%-2s %c %s\r\n", ctrl(p->e_char),
484 p->e_flags&EXP ? '*': ' ', p->e_help);
485 }
486}
4b675d70
SL
487
488/*
489 * Set up the "remote" tty's state
490 */
4b675d70 491ttysetup(speed)
05862919 492 int speed;
4b675d70 493{
4b675d70 494 unsigned bits = LDECCTQ;
4b675d70
SL
495
496 arg.sg_ispeed = arg.sg_ospeed = speed;
05862919 497 arg.sg_flags = RAW;
6b46907f 498 if (boolean(value(TAND)))
05862919 499 arg.sg_flags |= TANDEM;
4b675d70 500 ioctl(FD, TIOCSETP, (char *)&arg);
4b675d70 501 ioctl(FD, TIOCLBIS, (char *)&bits);
4b675d70 502}
c731dacc
BS
503
504/*
505 * Return "simple" name from a file name,
506 * strip leading directories.
507 */
508char *
509sname(s)
510 register char *s;
511{
512 register char *p = s;
513
514 while (*s)
515 if (*s++ == '/')
516 p = s;
517 return (p);
518}
6b46907f 519
6b46907f
RC
520static char partab[0200];
521
522/*
05862919
SL
523 * Do a write to the remote machine with the correct parity.
524 * We are doing 8 bit wide output, so we just generate a character
6b46907f
RC
525 * with the right parity and output it.
526 */
527pwrite(fd, buf, n)
528 int fd;
529 char *buf;
530 register int n;
531{
532 register int i;
05862919 533 register char *bp;
e2326c44 534 extern int errno;
6b46907f 535
05862919
SL
536 bp = buf;
537 for (i = 0; i < n; i++) {
6b46907f 538 *bp = partab[(*bp) & 0177];
05862919 539 bp++;
6b46907f 540 }
e2326c44
SL
541 if (write(fd, buf, n) < 0) {
542 if (errno == EIO)
543 abort("Lost carrier.");
544 /* this is questionable */
545 perror("write");
546 }
6b46907f
RC
547}
548
549/*
05862919 550 * Build a parity table with appropriate high-order bit.
6b46907f 551 */
dfec50f2
SL
552setparity(defparity)
553 char *defparity;
6b46907f 554{
05862919 555 register int i;
6b46907f 556 char *parity;
05862919 557 extern char evenpartab[];
6b46907f
RC
558
559 if (value(PARITY) == NOSTR)
dfec50f2 560 value(PARITY) = defparity;
6b46907f 561 parity = value(PARITY);
6b46907f 562 for (i = 0; i < 0200; i++)
05862919
SL
563 partab[i] = evenpartab[i];
564 if (equal(parity, "even"))
565 return;
6b46907f
RC
566 if (equal(parity, "odd")) {
567 for (i = 0; i < 0200; i++)
568 partab[i] ^= 0200; /* reverse bit 7 */
05862919 569 return;
6b46907f 570 }
05862919 571 if (equal(parity, "none") || equal(parity, "zero")) {
6b46907f
RC
572 for (i = 0; i < 0200; i++)
573 partab[i] &= ~0200; /* turn off bit 7 */
05862919 574 return;
6b46907f 575 }
05862919 576 if (equal(parity, "one")) {
6b46907f
RC
577 for (i = 0; i < 0200; i++)
578 partab[i] |= 0200; /* turn on bit 7 */
05862919 579 return;
6b46907f 580 }
05862919
SL
581 fprintf(stderr, "%s: unknown parity value\n", PA);
582 fflush(stderr);
6b46907f 583}