missing unlock on hunt returning -1: normally seen timed out opens
[unix-history] / usr / src / usr.bin / tip / tip.c
CommitLineData
1603e05e 1/* tip.c 4.8 81/08/26 */
5f50159a
BJ
2/*
3 * tip - Unix link to other systems
4 * tip [-v] [-speed] system-name
5 *
6 * Uses remote file for system descriptions.
7 * Current commands (escapes):
8 *
9 * ~! fork a shell on the local machine
10 * ~c change working directory on local machine
11 * ~^D exit tip
12 * ~< fetch file from remote system
13 * ~> send file to remote system
14 * ~t take a file from a remote UNIX (uses cat & echo)
15 * ~p send a file to a remote UNIX (uses cat)
16 * ~| fetch file from remote system and pipe it to
17 * a local process
18 * ~% fork and wait for a program which inherits file
19 * descriptors 3 & 4 attached to the remote machine
20 * (optional by CONNECT define)
21 * ~s set or show variable
22 * ~? give a help summary
23 *
24 * Samuel J. Leffler 1-18-81
25 *
26 * sjl 2-11-81
27 * add auto-dial stuff for the BIZCOMP
28 *
29 * sjl 2-14-81
30 * cleaned up auto-dialer stuff and added variables
31 *
32 * sjl 2-19-81
33 * handle quit and interrupt during calls
34 *
35 * sjl 3-8-81
36 * made to pass lint
37 *
38 * sjl 4-11-81
39 * mods to handle both FIOCAPACITY and FIONREAD in biz.c
40 *
41 * sjl 4-17-81
42 * added take and put, made piping stuff work
43 * honor uucp locks
44 * rewrite remote file stuff for DN-11 like acu's and just to clean
45 * it up
f0211bf2
SL
46 *
47 * sjl 6-16-81
48 * real working setup for DN-11's
5f50159a
BJ
49 */
50
51#include "tip.h"
52
53/*
54 * Baud rate mapping table
55 */
56int bauds[] = {
57 0, 50, 75, 110, 134, 150, 200, 300, 600,
58 1200, 1800, 2400, 4800, 9600, 19200, -1
59};
60
4b675d70
SL
61#ifdef VMUNIX
62int disc = OTTYDISC; /* tip normally runs this way */
63#endif
64
5f50159a
BJ
65int intprompt();
66int timeout();
67static int cleanup();
68
69main(argc, argv)
70char *argv[];
71{
72 char *system = NOSTR;
73 register int i;
5f50159a
BJ
74 char *p;
75
76 if (argc > 4) {
77 fprintf(stderr, "usage: tip [-v] [-speed] [system-name]\n");
78 exit(1);
79 }
80 if (!isatty(0)) {
81 fprintf(stderr, "tip: must be interactive\n");
82 exit(1);
83 }
84 if (argc > 1 && argv[argc-1][0] != '-')
85 system = argv[argc-1]; /* always last item */
86 signal(SIGINT, cleanup);
87 signal(SIGQUIT, cleanup);
88 signal(SIGHUP, cleanup);
89 signal(SIGTERM, cleanup);
f0211bf2 90
5f50159a
BJ
91 if ((i = hunt(system)) == 0) {
92 printf("all ports busy\n");
93 exit(3);
94 }
95 if (i == -1) {
96 printf("link down\n");
1603e05e 97 delock(uucplock);
5f50159a
BJ
98 exit(3);
99 }
eaa86232 100 setbuf(stdout, NULL);
5f50159a
BJ
101 loginit();
102 /*
103 * Now that we have the logfile and the ACU open
104 * return to the real uid and gid. These things will
105 * be closed on exit. Note that we can't run as root,
106 * because locking mechanism on the tty and the accounting
107 * will be bypassed.
108 */
109 setuid(getuid());
110 setgid(getgid());
111 for (i = 1; i < argc-1; i++)
112 if (equal(argv[i], "-v"))
113 vflag++;
114 /*
115 * Kludge, their's no easy way to get the initialization
116 * in the right order, so force it here
117 */
118 if ((PH = getenv("PHONES")) == NOSTR)
119 PH = "/etc/phones";
120 vinit(); /* init variables */
121 for (i = 1; i < argc-1; i++)
122 if (argv[i][0] == '-' && argv[i][1] != 'v') {
123 if (isnum(argv[i][1]))
124 number(value(BAUDRATE)) = atoi(&argv[i][1]);
125 else
126 printf("%s: unknown option\n", argv[i]);
127 }
4b675d70 128 if ((i = speed(number(value(BAUDRATE)))) == NULL) {
5f50159a
BJ
129 printf("tip: bad baud rate %d\n", number(value(BAUDRATE)));
130 delock(uucplock);
131 exit(3);
132 }
f0211bf2 133
4b675d70
SL
134 /*
135 * Hardwired connections require the
136 * line speed set before they make any transmissions
137 * (this is particularly true of things like a DF03-AC)
138 */
139 if (HW)
140 ttysetup(i);
f0211bf2
SL
141 if (p = connect()) {
142 printf("\07%s\n[EOT]\n", p);
143 delock(uucplock);
144 exit(1);
145 }
4b675d70
SL
146 if (!HW)
147 ttysetup(i);
148
5f50159a 149 /*
4b675d70 150 * Set up local tty state
5f50159a 151 */
4b675d70
SL
152 ioctl(0, TIOCGETP, (char *)&defarg);
153 ioctl(0, TIOCGETC, (char *)&defchars);
5d1f1475 154#ifdef VMUNIX
4b675d70 155 ioctl(0, TIOCGETD, (char *)&odisc);
5d1f1475 156#endif
5f50159a
BJ
157 arg = defarg;
158 arg.sg_flags = ANYP | CBREAK;
159 tchars = defchars;
160 tchars.t_intrc = tchars.t_quitc = -1;
5f50159a 161 raw();
4b675d70 162
5f50159a
BJ
163 pipe(fildes); pipe(repdes);
164 signal(SIGALRM, timeout);
f0211bf2
SL
165
166 /*
167 * Everything's set up now:
168 * connection established (hardwired or diaulup)
169 * line conditioned (baud rate, mode, etc.)
170 * internal data structures (variables)
171 * so, fork one process for local side and one for remote.
172 */
173 write(1, "\07connected\r\n", 12);
5f50159a
BJ
174 if (pid = fork())
175 tipin();
176 else
177 tipout();
178 /*NOTREACHED*/
179}
180
181static
182cleanup()
183{
184 delock(uucplock);
f0211bf2
SL
185#ifdef VMUNIX
186 if (odisc)
187 ioctl(0, TIOCSETD, (char *)&odisc);
188#endif
5f50159a
BJ
189 exit(0);
190}
191
192/*
193 * put the controlling keyboard into raw mode
194 */
195raw()
196{
197 ioctl(0, TIOCSETP, &arg);
198 ioctl(0, TIOCSETC, &tchars);
4b675d70
SL
199#ifdef VMUNIX
200 ioctl(0, TIOCSETD, (char *)&disc);
201#endif
5f50159a
BJ
202}
203
204
205/*
206 * return keyboard to normal mode
207 */
208unraw()
209{
4b675d70
SL
210#ifdef VMUNIX
211 ioctl(0, TIOCSETD, (char *)&odisc);
212#endif
213 ioctl(0, TIOCSETP, (char *)&defarg);
214 ioctl(0, TIOCSETC, (char *)&defchars);
5f50159a
BJ
215}
216
217/*
218 * Print string ``s'', then read a string
219 * in from the terminal. Handles signals & allows use of
220 * normal erase and kill characters.
221 */
222prompt(s, p)
223 char *s;
224 register char *p;
225{
226 register char *b = p;
227
228 stoprompt = 0;
229 signal(SIGINT, intprompt);
230 signal(SIGQUIT, SIG_IGN);
231 unraw();
232 printf("%s", s);
233 while ((*p = getchar()) != EOF && *p != '\n') {
234 if (stoprompt)
235 goto pbreak;
236 p++;
237 }
238 *p = '\0';
239pbreak:
240 raw();
241 signal(SIGINT, SIG_DFL);
242 signal(SIGQUIT,SIG_DFL);
243 return(stoprompt || p == b);
244}
245
246/*
247 * Interrupt service routine during prompting
248 */
249intprompt()
250{
251 signal(SIGINT, SIG_IGN);
252 stoprompt = 1;
253 printf("\r\n");
254}
255
256/*
257 * ****TIPIN TIPIN****
258 */
259tipin()
260{
261 char gch, bol = 1;
262
388a70dc
SL
263 /*
264 * Kinda klugey here...
265 * check for scripting being turned on from the .tiprc file,
266 * but be careful about just using setscript(), as we may
267 * send a SIGEMT before tipout has a chance to set up catching
268 * it; so wait a second, then setscript()
269 */
270 if (boolean(value(SCRIPT))) {
271 sleep(1);
272 setscript();
273 }
274
5f50159a
BJ
275 while (1) {
276 gch = getchar()&0177;
277 if ((gch == character(value(ESCAPE))) && bol) {
278 if (!(gch = escape()))
279 continue;
280 } else if (gch == character(value(RAISECHAR))) {
281 boolean(value(RAISE)) = !boolean(value(RAISE));
282 printf("%s", ctrl(character(value(RAISECHAR))));
283 continue;
284 } else if (gch == '\r') {
285 bol = 1;
286 write(FD, &gch, 1);
287 continue;
288 } else if (gch == character(value(FORCE))) {
289 printf("%s", ctrl(character(value(FORCE))));
290 gch = getchar()&0177;
291 }
292 bol = any(gch, value(EOL));
293 if (boolean(value(RAISE)) && islower(gch))
294 toupper(gch);
295 write(FD, &gch, 1);
296 }
297}
298
299/*
300 * Escape handler --
301 * called on recognition of ``escapec'' at the beginning of a line
302 */
303escape()
304{
305 register char gch;
306 register esctable_t *p;
307 char c = character(value(ESCAPE));
308 extern esctable_t etable[];
309
310 gch = (getchar()&0177);
311 for (p = etable; p->e_char; p++)
312 if (p->e_char == gch) {
313 if ((p->e_flags&PRIV) && getuid())
314 continue;
315 printf("%s", ctrl(c));
316 (*p->e_func)(gch);
317 return(0);
318 }
62f62be8
SL
319 /* ESCAPE ESCAPE forces ESCAPE */
320 if (c != gch)
321 write(FD, &c, 1);
5f50159a
BJ
322 return(gch);
323}
324
325speed(n)
326{
327 register int *p;
328
329 for (p = bauds; *p != -1; p++)
330 if (*p == n)
331 return(p-bauds);
332 return(NULL);
333}
334
335any(c, p)
336 register char c, *p;
337{
338 while (*p)
339 if (*p++ == c)
340 return(1);
341 return(0);
342}
343
344size(s)
345 register char *s;
346{
347 register int i = 0;
348
349 while (*s++) i++;
350 return(i);
351}
352
353char *
354interp(s)
355 register char *s;
356{
357 static char buf[256];
358 register char *p = buf, c, *q;
359
360 while (c = *s++) {
361 for (q = "\nn\rr\tt\ff\033E\bb"; *q; q++)
362 if (*q++ == c) {
363 *p++ = '\\'; *p++ = *q;
364 goto next;
365 }
366 if (c < 040) {
367 *p++ = '^'; *p++ = c + 'A'-1;
368 } else if (c == 0177) {
369 *p++ = '^'; *p++ = '?';
370 } else
371 *p++ = c;
372 next:
373 ;
374 }
375 *p = '\0';
376 return(buf);
377}
378
379char *
380ctrl(c)
381 char c;
382{
383 static char s[3];
384
385 if (c < 040 || c == 0177) {
386 s[0] = '^';
387 s[1] = c == 0177 ? '?' : c+'A'-1;
388 s[2] = '\0';
389 } else {
390 s[0] = c;
391 s[1] = '\0';
392 }
393 return(s);
394}
395
396/*
397 * Help command
398 */
399help(c)
400 char c;
401{
402 register esctable_t *p;
403 extern esctable_t etable[];
404
405 printf("%c\r\n", c);
406 for (p = etable; p->e_char; p++) {
407 if ((p->e_flags&PRIV) && getuid())
408 continue;
409 printf("%2s", ctrl(character(value(ESCAPE))));
410 printf("%-2s %c %s\r\n", ctrl(p->e_char),
411 p->e_flags&EXP ? '*': ' ', p->e_help);
412 }
413}
4b675d70
SL
414
415/*
416 * Set up the "remote" tty's state
417 */
418static
419ttysetup(speed)
420{
421#ifdef VMUNIX
422 unsigned bits = LDECCTQ;
423#endif
424
425 arg.sg_ispeed = arg.sg_ospeed = speed;
426 arg.sg_flags = TANDEM|RAW;
427 ioctl(FD, TIOCSETP, (char *)&arg);
428#ifdef VMUNIX
429 ioctl(FD, TIOCLBIS, (char *)&bits);
430#endif
431}