lock alias file while rebuilding if flock system call available
[unix-history] / usr / src / usr.bin / tip / cmds.c
CommitLineData
05862919 1#ifndef lint
ab76a038 2static char sccsid[] = "@(#)cmds.c 4.14 (Berkeley) %G%";
05862919
SL
3#endif
4
22daf918
BJ
5#include "tip.h"
6/*
7 * tip
8 *
9 * miscellaneous commands
10 */
11
12int quant[] = { 60, 60, 24 };
13
14char null = '\0';
15char *sep[] = { "second", "minute", "hour" };
16static char *argv[10]; /* argument vector for take and put */
17
18int timeout(); /* timeout function called on alarm */
19int stopsnd(); /* SIGINT handler during file transfers */
20int intprompt(); /* used in handling SIG_INT during prompt */
21int intcopy(); /* interrupt routine for file transfers */
22
23/*
24 * FTP - remote ==> local
25 * get a file from the remote host
26 */
27getfl(c)
28 char c;
29{
05862919 30 char buf[256], *cp, *expand();
22daf918
BJ
31
32 putchar(c);
33 /*
34 * get the UNIX receiving file's name
35 */
36 if (prompt("Local file name? ", copyname))
37 return;
05862919
SL
38 cp = expand(copyname);
39 if ((sfd = creat(cp, 0666)) < 0) {
22daf918
BJ
40 printf("\r\n%s: cannot creat\r\n", copyname);
41 return;
42 }
43
44 /*
45 * collect parameters
46 */
47 if (prompt("List command for remote system? ", buf)) {
48 unlink(copyname);
49 return;
50 }
51 transfer(buf, sfd, value(EOFREAD));
52}
53
54/*
55 * Cu-like take command
56 */
57cu_take(cc)
58 char cc;
59{
60 int fd, argc;
05862919 61 char line[BUFSIZ], *expand(), *cp;
22daf918
BJ
62
63 if (prompt("[take] ", copyname))
64 return;
65 if ((argc = args(copyname, argv)) < 1 || argc > 2) {
66 printf("usage: <take> from [to]\r\n");
67 return;
68 }
69 if (argc == 1)
70 argv[1] = argv[0];
05862919
SL
71 cp = expand(argv[1]);
72 if ((fd = creat(cp, 0666)) < 0) {
22daf918
BJ
73 printf("\r\n%s: cannot create\r\n", argv[1]);
74 return;
75 }
6b46907f 76 sprintf(line, "cat %s;echo \01", argv[0]);
22daf918
BJ
77 transfer(line, fd, "\01");
78}
79
05862919 80static jmp_buf intbuf;
22daf918
BJ
81/*
82 * Bulk transfer routine --
83 * used by getfl(), cu_take(), and pipefile()
84 */
85transfer(buf, fd, eofchars)
86 char *buf, *eofchars;
87{
88 register int ct;
89 char c, buffer[BUFSIZ];
90 register char *p = buffer;
91 register int cnt, eof;
92 time_t start;
05862919 93 int (*f)();
22daf918 94
6b46907f 95 pwrite(FD, buf, size(buf));
22daf918 96 quit = 0;
22daf918
BJ
97 kill(pid, SIGIOT);
98 read(repdes[0], (char *)&ccc, 1); /* Wait until read process stops */
99
100 /*
101 * finish command
102 */
6b46907f 103 pwrite(FD, "\r", 1);
22daf918
BJ
104 do
105 read(FD, &c, 1);
106 while ((c&0177) != '\n');
107 ioctl(0, TIOCSETC, &defchars);
108
ab76a038 109 (void) setjmp(intbuf);
05862919 110 f = signal(SIGINT, intcopy);
22daf918
BJ
111 start = time(0);
112 for (ct = 0; !quit;) {
113 eof = read(FD, &c, 1) <= 0;
114 c &= 0177;
115 if (quit)
116 continue;
117 if (eof || any(c, eofchars))
118 break;
119 if (c == 0)
120 continue; /* ignore nulls */
121 if (c == '\r')
122 continue;
123 *p++ = c;
124
125 if (c == '\n' && boolean(value(VERBOSE)))
126 printf("\r%d", ++ct);
127 if ((cnt = (p-buffer)) == number(value(FRAMESIZE))) {
128 if (write(fd, buffer, cnt) != cnt) {
129 printf("\r\nwrite error\r\n");
130 quit = 1;
131 }
132 p = buffer;
133 }
134 }
135 if (cnt = (p-buffer))
136 if (write(fd, buffer, cnt) != cnt)
137 printf("\r\nwrite error\r\n");
138
139 if (boolean(value(VERBOSE)))
140 prtime(" lines transferred in ", time(0)-start);
141 ioctl(0, TIOCSETC, &tchars);
142 write(fildes[1], (char *)&ccc, 1);
ab76a038 143 signal(SIGINT, f);
22daf918
BJ
144 close(fd);
145}
146
147/*
148 * FTP - remote ==> local process
149 * send remote input to local process via pipe
150 */
151pipefile()
152{
153 int cpid, pdes[2];
154 char buf[256];
155 int status, p;
156 extern int errno;
157
158 if (prompt("Local command? ", buf))
159 return;
160
161 if (pipe(pdes)) {
162 printf("can't establish pipe\r\n");
163 return;
164 }
165
166 if ((cpid = fork()) < 0) {
167 printf("can't fork!\r\n");
168 return;
169 } else if (cpid) {
170 if (prompt("List command for remote system? ", buf)) {
171 close(pdes[0]), close(pdes[1]);
172 kill (cpid, SIGKILL);
173 } else {
174 close(pdes[0]);
175 signal(SIGPIPE, intcopy);
176 transfer(buf, pdes[1], value(EOFREAD));
177 signal(SIGPIPE, SIG_DFL);
178 while ((p = wait(&status)) > 0 && p != cpid)
179 ;
180 }
181 } else {
182 register int f;
183
184 dup2(pdes[0], 0);
185 close(pdes[0]);
186 for (f = 3; f < 20; f++)
187 close(f);
188 execute(buf);
189 printf("can't execl!\r\n");
190 exit(0);
191 }
192}
193
194/*
195 * Interrupt service routine for FTP
196 */
197stopsnd()
198{
05862919 199
22daf918
BJ
200 stop = 1;
201 signal(SIGINT, SIG_IGN);
202}
203
204/*
205 * FTP - local ==> remote
206 * send local file to remote host
207 * terminate transmission with pseudo EOF sequence
208 */
209sendfile(cc)
210 char cc;
211{
212 FILE *fd;
6b46907f
RC
213 char *fnamex;
214 char *expand();
22daf918
BJ
215
216 putchar(cc);
217 /*
218 * get file name
219 */
220 if (prompt("Local file name? ", fname))
221 return;
222
223 /*
224 * look up file
225 */
6b46907f
RC
226 fnamex = expand(fname);
227 if ((fd = fopen(fnamex, "r")) == NULL) {
22daf918
BJ
228 printf("%s: cannot open\r\n", fname);
229 return;
230 }
231 transmit(fd, value(EOFWRITE), NULL);
a2c6551c
SL
232 if (!boolean(value(ECHOCHECK))) {
233 struct sgttyb buf;
234
235 ioctl(FD, TIOCGETP, &buf); /* this does a */
236 ioctl(FD, TIOCSETP, &buf); /* wflushtty */
237 }
22daf918
BJ
238}
239
240/*
241 * Bulk transfer routine to remote host --
242 * used by sendfile() and cu_put()
243 */
244transmit(fd, eofchars, command)
245 FILE *fd;
246 char *eofchars, *command;
247{
6b46907f 248 char *pc, lastc;
22daf918
BJ
249 int c, ccount, lcount;
250 time_t start_t, stop_t;
ab76a038 251 int (*f)();
22daf918
BJ
252
253 kill(pid, SIGIOT); /* put TIPOUT into a wait state */
22daf918 254 stop = 0;
ab76a038 255 f = signal(SIGINT, stopsnd);
22daf918
BJ
256 ioctl(0, TIOCSETC, &defchars);
257 read(repdes[0], (char *)&ccc, 1);
258 if (command != NULL) {
259 for (pc = command; *pc; pc++)
260 send(*pc);
a2c6551c
SL
261 if (boolean(value(ECHOCHECK)))
262 read(FD, (char *)&c, 1); /* trailing \n */
263 else {
264 struct sgttyb buf;
265
266 ioctl(FD, TIOCGETP, &buf); /* this does a */
267 ioctl(FD, TIOCSETP, &buf); /* wflushtty */
268 sleep(5); /* wait for remote stty to take effect */
269 }
22daf918
BJ
270 }
271 lcount = 0;
272 lastc = '\0';
273 start_t = time(0);
3f48242d 274 while (1) {
22daf918
BJ
275 ccount = 0;
276 do {
277 c = getc(fd);
278 if (stop)
279 goto out;
280 if (c == EOF)
281 goto out;
6b46907f 282 if (c == 0177 && !boolean(value(RAWFTP)))
22daf918
BJ
283 continue;
284 lastc = c;
285 if (c < 040) {
6b46907f
RC
286 if (c == '\n') {
287 if (!boolean(value(RAWFTP)))
288 c = '\r';
289 }
22daf918 290 else if (c == '\t') {
6b46907f
RC
291 if (!boolean(value(RAWFTP))) {
292 if (boolean(value(TABEXPAND))) {
22daf918 293 send(' ');
6b46907f
RC
294 while ((++ccount % 8) != 0)
295 send(' ');
296 continue;
297 }
22daf918 298 }
6b46907f
RC
299 } else
300 if (!boolean(value(RAWFTP)))
301 continue;
22daf918
BJ
302 }
303 send(c);
6b46907f 304 } while (c != '\r' && !boolean(value(RAWFTP)));
22daf918
BJ
305 if (boolean(value(VERBOSE)))
306 printf("\r%d", ++lcount);
a2c6551c 307 if (boolean(value(ECHOCHECK))) {
a2c6551c 308 timedout = 0;
ab76a038 309 alarm(value(ETIMEOUT));
a2c6551c 310 do { /* wait for prompt */
6b46907f 311 read(FD, (char *)&c, 1);
a2c6551c
SL
312 if (timedout || stop) {
313 if (timedout)
314 printf("\r\ntimed out at eol\r\n");
315 alarm(0);
316 goto out;
317 }
6b46907f 318 } while ((c&0177) != character(value(PROMPT)));
a2c6551c
SL
319 alarm(0);
320 }
22daf918
BJ
321 }
322out:
6b46907f 323 if (lastc != '\n' && !boolean(value(RAWFTP)))
22daf918
BJ
324 send('\r');
325 for (pc = eofchars; *pc; pc++)
326 send(*pc);
327 stop_t = time(0);
328 fclose(fd);
ab76a038 329 signal(SIGINT, f);
22daf918 330 if (boolean(value(VERBOSE)))
6b46907f
RC
331 if (boolean(value(RAWFTP)))
332 prtime(" chars transferred in ", stop_t-start_t);
333 else
334 prtime(" lines transferred in ", stop_t-start_t);
22daf918
BJ
335 write(fildes[1], (char *)&ccc, 1);
336 ioctl(0, TIOCSETC, &tchars);
337}
338
339/*
340 * Cu-like put command
341 */
342cu_put(cc)
343 char cc;
344{
345 FILE *fd;
346 char line[BUFSIZ];
347 int argc;
6b46907f
RC
348 char *expand();
349 char *copynamex;
22daf918
BJ
350
351 if (prompt("[put] ", copyname))
352 return;
353 if ((argc = args(copyname, argv)) < 1 || argc > 2) {
354 printf("usage: <put> from [to]\r\n");
355 return;
356 }
357 if (argc == 1)
358 argv[1] = argv[0];
6b46907f
RC
359 copynamex = expand(argv[0]);
360 if ((fd = fopen(copynamex, "r")) == NULL) {
361 printf("%s: cannot open\r\n", copynamex);
22daf918
BJ
362 return;
363 }
a2c6551c 364 if (boolean(value(ECHOCHECK)))
6b46907f 365 sprintf(line, "cat>%s\r", argv[1]);
a2c6551c 366 else
6b46907f 367 sprintf(line, "stty -echo;cat>%s;stty echo\r", argv[1]);
22daf918
BJ
368 transmit(fd, "\04", line);
369}
370
371/*
372 * FTP - send single character
373 * wait for echo & handle timeout
374 */
375send(c)
376 char c;
377{
96ad7152 378 char cc;
22daf918
BJ
379 int retry = 0;
380
381 cc = c;
6b46907f
RC
382 pwrite(FD, &cc, 1);
383#ifdef notdef
384 if (number(value(CDELAY)) > 0 && c != '\r')
385 nap(number(value(CDELAY)));
386#endif
387 if (!boolean(value(ECHOCHECK))) {
388#ifdef notdef
389 if (number(value(LDELAY)) > 0 && c == '\r')
390 nap(number(value(LDELAY)));
391#endif
a2c6551c 392 return;
6b46907f 393 }
22daf918
BJ
394tryagain:
395 timedout = 0;
6b46907f
RC
396 alarm(value(ETIMEOUT));
397 read(FD, &cc, 1);
22daf918
BJ
398 alarm(0);
399 if (timedout) {
400 printf("\r\ntimeout error (%s)\r\n", ctrl(c));
401 if (retry++ > 3)
402 return;
6b46907f 403 pwrite(FD, &null, 1); /* poke it */
22daf918
BJ
404 goto tryagain;
405 }
406}
407
408timeout()
409{
410 signal(SIGALRM, timeout);
411 timedout = 1;
412}
413
414#ifdef CONNECT
415/*
416 * Fork a program with:
417 * 0 <-> local tty in
418 * 1 <-> local tty out
419 * 2 <-> local tty out
420 * 3 <-> remote tty in
421 * 4 <-> remote tty out
422 */
423consh(c)
424{
425 char buf[256];
426 int cpid, status, p;
427 time_t start;
428
429 putchar(c);
430 if (prompt("Local command? ", buf))
431 return;
432 kill(pid, SIGIOT); /* put TIPOUT into a wait state */
433 signal(SIGINT, SIG_IGN);
434 signal(SIGQUIT, SIG_IGN);
435 ioctl(0, TIOCSETC, &defchars);
436 read(repdes[0], (char *)&ccc, 1);
437 /*
438 * Set up file descriptors in the child and
439 * let it go...
440 */
441 if ((cpid = fork()) < 0)
442 printf("can't fork!\r\n");
443 else if (cpid) {
444 start = time(0);
445 while ((p = wait(&status)) > 0 && p != cpid)
446 ;
447 } else {
448 register int i;
449
450 dup2(FD, 3);
451 dup2(3, 4);
452 for (i = 5; i < 20; i++)
453 close(i);
454 signal(SIGINT, SIG_DFL);
455 signal(SIGQUIT, SIG_DFL);
456 execute(buf);
457 printf("can't find `%s'\r\n", buf);
458 exit(0);
459 }
460 if (boolean(value(VERBOSE)))
461 prtime("away for ", time(0)-start);
462 write(fildes[1], (char *)&ccc, 1);
463 ioctl(0, TIOCSETC, &tchars);
464 signal(SIGINT, SIG_DFL);
465 signal(SIGQUIT, SIG_DFL);
466}
467#endif
468
469/*
470 * Escape to local shell
471 */
472shell()
473{
474 int shpid, status;
475 extern char **environ;
476 char *cp;
477
478 printf("[sh]\r\n");
479 signal(SIGINT, SIG_IGN);
480 signal(SIGQUIT, SIG_IGN);
481 unraw();
482 if (shpid = fork()) {
483 while (shpid != wait(&status));
484 raw();
485 printf("\r\n!\r\n");
486 signal(SIGINT, SIG_DFL);
487 signal(SIGQUIT, SIG_DFL);
488 return;
489 } else {
490 signal(SIGQUIT, SIG_DFL);
491 signal(SIGINT, SIG_DFL);
492 if ((cp = rindex(value(SHELL), '/')) == NULL)
493 cp = value(SHELL);
494 else
495 cp++;
496 execl(value(SHELL), cp, 0);
497 printf("\r\ncan't execl!\r\n");
498 exit(1);
499 }
500}
501
502/*
503 * TIPIN portion of scripting
504 * initiate the conversation with TIPOUT
505 */
506setscript()
507{
508 char c;
509 /*
510 * enable TIPOUT side for dialogue
511 */
512 kill(pid, SIGEMT);
513 if (boolean(value(SCRIPT)))
514 write(fildes[1], value(RECORD), size(value(RECORD)));
515 write(fildes[1], "\n", 1);
516 /*
517 * wait for TIPOUT to finish
518 */
519 read(repdes[0], &c, 1);
520 if (c == 'n')
521 printf("can't create %s\r\n", value(RECORD));
522}
523
524/*
525 * Change current working directory of
526 * local portion of tip
527 */
528chdirectory()
529{
05862919 530 char dirname[80];
22daf918
BJ
531 register char *cp = dirname;
532
05862919 533 if (prompt("[cd] ", dirname)) {
22daf918
BJ
534 if (stoprompt)
535 return;
05862919
SL
536 cp = value(HOME);
537 }
22daf918
BJ
538 if (chdir(cp) < 0)
539 printf("%s: bad directory\r\n", cp);
540 printf("!\r\n");
541}
542
e2326c44
SL
543abort(msg)
544 char *msg;
22daf918 545{
6b46907f 546
22daf918 547 kill(pid, SIGTERM);
e2326c44
SL
548 disconnect(msg);
549 if (msg != NOSTR)
550 printf("\r\n%s", msg);
22daf918
BJ
551 printf("\r\n[EOT]\r\n");
552 delock(uucplock);
22daf918
BJ
553 unraw();
554 exit(0);
555}
556
e2326c44
SL
557finish()
558{
559 char *dismsg;
560
561 if ((dismsg = value(DISCONNECT)) != NOSTR) {
562 write(FD, dismsg, strlen(dismsg));
563 sleep(5);
564 }
565 abort(NOSTR);
566}
567
22daf918
BJ
568intcopy()
569{
05862919 570
22daf918
BJ
571 raw();
572 quit = 1;
05862919 573 longjmp(intbuf, 1);
22daf918
BJ
574}
575
576execute(s)
577 char *s;
578{
579 register char *cp;
580
581 if ((cp = rindex(value(SHELL), '/')) == NULL)
582 cp = value(SHELL);
583 else
584 cp++;
585 execl(value(SHELL), cp, "-c", s, 0);
586}
587
588args(buf, a)
589 char *buf, *a[];
590{
591 register char *p = buf, *start;
592 register char **parg = a;
593 register int n = 0;
594
595 do {
596 while (*p && (*p == ' ' || *p == '\t'))
597 p++;
598 start = p;
599 if (*p)
600 *parg = p;
601 while (*p && (*p != ' ' && *p != '\t'))
602 p++;
603 if (p != start)
604 parg++, n++;
605 if (*p)
606 *p++ = '\0';
607 } while (*p);
608
609 return(n);
610}
611
612prtime(s, a)
613 char *s;
614 time_t a;
615{
616 register i;
617 int nums[3];
618
619 for (i = 0; i < 3; i++) {
620 nums[i] = (int)(a % quant[i]);
621 a /= quant[i];
622 }
623 printf("%s", s);
624 while (--i >= 0)
ab76a038 625 if (nums[i] || i == 0 && nums[1] == 0 && nums[2] == 0)
22daf918
BJ
626 printf("%d %s%c ", nums[i], sep[i],
627 nums[i] == 1 ? '\0' : 's');
628 printf("\r\n!\r\n");
629}
630
631variable()
632{
633 char buf[256];
634
635 if (prompt("[set] ", buf))
636 return;
637 vlex(buf);
638 if (vtable[BEAUTIFY].v_access&CHANGED) {
639 vtable[BEAUTIFY].v_access &= ~CHANGED;
3463e9c6 640 kill(pid, SIGSYS);
22daf918
BJ
641 }
642 if (vtable[SCRIPT].v_access&CHANGED) {
643 vtable[SCRIPT].v_access &= ~CHANGED;
644 setscript();
7367df0e
SL
645 /*
646 * So that "set record=blah script" doesn't
647 * cause two transactions to occur.
648 */
649 if (vtable[RECORD].v_access&CHANGED)
650 vtable[RECORD].v_access &= ~CHANGED;
22daf918
BJ
651 }
652 if (vtable[RECORD].v_access&CHANGED) {
653 vtable[RECORD].v_access &= ~CHANGED;
654 if (boolean(value(SCRIPT)))
655 setscript();
656 }
6b46907f
RC
657 if (vtable[TAND].v_access&CHANGED) {
658 vtable[TAND].v_access &= ~CHANGED;
659 if (boolean(value(TAND)))
660 tandem("on");
661 else
662 tandem("off");
663 }
664 if (vtable[LECHO].v_access&CHANGED) {
665 vtable[LECHO].v_access &= ~CHANGED;
666 HD = boolean(value(LECHO));
667 }
668 if (vtable[PARITY].v_access&CHANGED) {
669 vtable[PARITY].v_access &= ~CHANGED;
670 setparity();
671 }
672}
673
674/*
05862919 675 * Turn tandem mode on or off for remote tty.
6b46907f 676 */
6b46907f 677tandem(option)
05862919 678 char *option;
6b46907f
RC
679{
680 struct sgttyb rmtty;
681
682 ioctl(FD, TIOCGETP, &rmtty);
683 if (strcmp(option,"on") == 0) {
684 rmtty.sg_flags |= TANDEM;
685 arg.sg_flags |= TANDEM;
05862919 686 } else {
6b46907f
RC
687 rmtty.sg_flags &= ~TANDEM;
688 arg.sg_flags &= ~TANDEM;
689 }
690 ioctl(FD, TIOCSETP, &rmtty);
691 ioctl(0, TIOCSETP, &arg);
22daf918 692}
061754f3
SL
693
694/*
695 * Send a break.
061754f3
SL
696 */
697genbrk()
698{
05862919 699
061754f3
SL
700 ioctl(FD, TIOCSBRK, NULL);
701 sleep(1);
702 ioctl(FD, TIOCCBRK, NULL);
061754f3 703}
3f48242d 704
3f48242d
SL
705/*
706 * Suspend tip
707 */
708suspend()
709{
05862919 710
3f48242d
SL
711 unraw();
712 kill(0, SIGTSTP);
713 raw();
714}
6b46907f
RC
715
716/*
717 * expand a file name if it includes shell meta characters
718 */
719
720char *
721expand(name)
722 char name[];
723{
724 static char xname[BUFSIZ];
725 char cmdbuf[BUFSIZ];
726 register int pid, l, rc;
727 register char *cp, *Shell;
728 int s, pivec[2], (*sigint)();
729
730 if (!anyof(name, "~{[*?$`'\"\\"))
731 return(name);
732 /* sigint = signal(SIGINT, SIG_IGN); */
733 if (pipe(pivec) < 0) {
734 perror("pipe");
735 /* signal(SIGINT, sigint) */
736 return(name);
737 }
738 sprintf(cmdbuf, "echo %s", name);
739 if ((pid = vfork()) == 0) {
740 Shell = value(SHELL);
741 if (Shell == NOSTR)
742 Shell = "/bin/sh";
743 close(pivec[0]);
744 close(1);
745 dup(pivec[1]);
746 close(pivec[1]);
747 close(2);
748 execl(Shell, Shell, "-c", cmdbuf, 0);
749 _exit(1);
750 }
751 if (pid == -1) {
752 perror("fork");
753 close(pivec[0]);
754 close(pivec[1]);
755 return(NOSTR);
756 }
757 close(pivec[1]);
758 l = read(pivec[0], xname, BUFSIZ);
759 close(pivec[0]);
760 while (wait(&s) != pid);
761 ;
762 s &= 0377;
763 if (s != 0 && s != SIGPIPE) {
764 fprintf(stderr, "\"Echo\" failed\n");
765 return(NOSTR);
766 }
767 if (l < 0) {
768 perror("read");
769 return(NOSTR);
770 }
771 if (l == 0) {
772 fprintf(stderr, "\"%s\": No match\n", name);
773 return(NOSTR);
774 }
775 if (l == BUFSIZ) {
776 fprintf(stderr, "Buffer overflow expanding \"%s\"\n", name);
777 return(NOSTR);
778 }
779 xname[l] = 0;
780 for (cp = &xname[l-1]; *cp == '\n' && cp > xname; cp--)
781 ;
782 *++cp = '\0';
783 return(xname);
784}
785
786/*
787 * Are any of the characters in the two strings the same?
788 */
789
790anyof(s1, s2)
791 register char *s1, *s2;
792{
793 register int c;
794
795 while (c = *s1++)
796 if (any(c, s2))
797 return(1);
798 return(0);
799}