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