Patrick Welche <prlw1@cam.ac.uk>
[netbsd-mini2440.git] / usr.bin / tip / cmds.c
blob51a53e1fd1d8957006df80a2866643875ef606c7
1 /* $NetBSD: cmds.c,v 1.30 2006/10/22 16:46:49 christos Exp $ */
3 /*
4 * Copyright (c) 1983, 1993
5 * The Regents of the University of California. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
32 #include <sys/cdefs.h>
33 #ifndef lint
34 #if 0
35 static char sccsid[] = "@(#)cmds.c 8.1 (Berkeley) 6/6/93";
36 #endif
37 __RCSID("$NetBSD: cmds.c,v 1.30 2006/10/22 16:46:49 christos Exp $");
38 #endif /* not lint */
40 #include "tip.h"
41 #include "pathnames.h"
44 * tip
46 * miscellaneous commands
49 int quant[] = { 60, 60, 24 };
51 char null = '\0';
52 const char *sep[] = { "second", "minute", "hour" };
53 static char *argv[10]; /* argument vector for take and put */
55 int args(char *, char **);
56 int anyof(char *, const char *);
57 void execute(char *);
58 void intcopy(int);
59 void prtime(const char *, time_t);
60 void stopsnd(int);
61 void transfer(char *, int, const char *);
62 void transmit(FILE *, const char *, char *);
65 * FTP - remote ==> local
66 * get a file from the remote host
68 void
69 getfl(char c)
71 char buf[256], *cp;
73 (void)putchar(c);
75 * get the UNIX receiving file's name
77 if (prompt("Local file name? ", copyname, sizeof copyname))
78 return;
79 cp = expand(copyname);
80 if ((sfd = open(cp, O_RDWR|O_CREAT, 0666)) < 0) {
81 (void)printf("\r\n%s: cannot create\r\n", copyname);
82 return;
86 * collect parameters
88 if (prompt("List command for remote system? ", buf,
89 sizeof buf)) {
90 (void)unlink(copyname);
91 return;
93 transfer(buf, sfd, value(EOFREAD));
97 * Cu-like take command
99 /* ARGSUSED */
100 void
101 cu_take(char dummy __unused)
103 int fd, argc;
104 char line[BUFSIZ], *cp;
106 if (prompt("[take] ", copyname, sizeof copyname))
107 return;
108 if ((argc = args(copyname, argv)) < 1 || argc > 2) {
109 (void)printf("usage: <take> from [to]\r\n");
110 return;
112 if (argc == 1)
113 argv[1] = argv[0];
114 cp = expand(argv[1]);
115 if ((fd = open(cp, O_RDWR|O_CREAT, 0666)) < 0) {
116 (void)printf("\r\n%s: cannot create\r\n", argv[1]);
117 return;
119 (void)snprintf(line, sizeof line, "cat %s;echo \01", argv[0]);
120 transfer(line, fd, "\01");
123 static jmp_buf intbuf;
125 * Bulk transfer routine --
126 * used by getfl(), cu_take(), and pipefile()
128 void
129 transfer(char *buf, int fd, const char *eofchars)
131 int ct;
132 char c, buffer[BUFSIZ];
133 char * volatile p;
134 int cnt, eof;
135 time_t start;
136 sig_t f;
137 char r;
139 p = buffer;
140 xpwrite(FD, buf, strlen(buf));
141 quit = 0;
142 (void)write(attndes[1], "W", 1); /* Put TIPOUT into a wait state */
143 (void)read(repdes[0], (char *)&ccc, 1); /* Wait until read process stops */
146 * finish command
148 r = '\r';
149 xpwrite(FD, &r, 1);
151 (void)read(FD, &c, 1);
152 while ((c&STRIP_PAR) != '\n');
153 (void)tcsetattr(0, TCSAFLUSH, &defchars);
155 (void) setjmp(intbuf);
156 f = signal(SIGINT, intcopy);
157 start = time(0);
158 for (ct = 0; !quit;) {
159 eof = read(FD, &c, 1) <= 0;
160 c &= STRIP_PAR;
161 if (quit)
162 continue;
163 if (eof || any(c, eofchars))
164 break;
165 if (c == 0)
166 continue; /* ignore nulls */
167 if (c == '\r')
168 continue;
169 *p++ = c;
171 if (c == '\n' && boolean(value(VERBOSE)))
172 (void)printf("\r%d", ++ct);
173 if ((cnt = (p-buffer)) == number(value(FRAMESIZE))) {
174 if (write(fd, buffer, (size_t)cnt) != cnt) {
175 (void)printf("\r\nwrite error\r\n");
176 quit = 1;
178 p = buffer;
181 if ((cnt = (p-buffer)) != 0)
182 if (write(fd, buffer, (size_t)cnt) != cnt)
183 (void)printf("\r\nwrite error\r\n");
185 if (boolean(value(VERBOSE)))
186 prtime(" lines transferred in ", time(0)-start);
187 (void)tcsetattr(0, TCSAFLUSH, &term);
188 (void)write(fildes[1], (char *)&ccc, 1);
189 (void)signal(SIGINT, f);
190 (void)close(fd);
194 * FTP - remote ==> local process
195 * send remote input to local process via pipe
197 /* ARGSUSED */
198 void
199 pipefile(char dummy __unused)
201 int cpid, pdes[2];
202 char buf[256];
203 int status, p;
205 if (prompt("Local command? ", buf, sizeof buf))
206 return;
208 if (pipe(pdes)) {
209 (void)printf("can't establish pipe\r\n");
210 return;
213 if ((cpid = fork()) < 0) {
214 (void)printf("can't fork!\r\n");
215 return;
216 } else if (cpid) {
217 if (prompt("List command for remote system? ", buf,
218 sizeof buf)) {
219 (void)close(pdes[0]);
220 (void)close(pdes[1]);
221 (void)kill(cpid, SIGKILL);
222 } else {
223 (void)close(pdes[0]);
224 (void)signal(SIGPIPE, intcopy);
225 transfer(buf, pdes[1], value(EOFREAD));
226 (void)signal(SIGPIPE, SIG_DFL);
227 while ((p = wait(&status)) > 0 && p != cpid)
230 } else {
231 (void)dup2(pdes[0], 0);
232 (void)close(pdes[0]);
233 (void)closefrom(3);
234 execute(buf);
235 (void)printf("can't execl!\r\n");
236 exit(0);
241 * Interrupt service routine for FTP
243 /* ARGSUSED */
244 void
245 stopsnd(int dummy __unused)
248 stop = 1;
249 (void)signal(SIGINT, SIG_IGN);
253 * FTP - local ==> remote
254 * send local file to remote host
255 * terminate transmission with pseudo EOF sequence
257 void
258 sendfile(char cc)
260 FILE *fd;
261 char *fnamex;
263 (void)putchar(cc);
265 * get file name
267 if (prompt("Local file name? ", fname, sizeof fname))
268 return;
271 * look up file
273 fnamex = expand(fname);
274 if ((fd = fopen(fnamex, "r")) == NULL) {
275 (void)printf("%s: cannot open\r\n", fname);
276 return;
278 transmit(fd, value(EOFWRITE), NULL);
279 if (!boolean(value(ECHOCHECK)))
280 (void)tcdrain(FD);
284 * Bulk transfer routine to remote host --
285 * used by sendfile() and cu_put()
287 void
288 transmit(FILE *fd, const char *eofchars, char *command)
290 const char *pc;
291 char lastc;
292 int c;
293 int ccount, lcount;
294 time_t start_t, stop_t;
295 sig_t f;
297 (void)write(attndes[1], "W", 1); /* put TIPOUT into a wait state */
298 stop = 0;
299 f = signal(SIGINT, stopsnd);
300 (void)tcsetattr(0, TCSAFLUSH, &defchars);
301 (void)read(repdes[0], (char *)&ccc, 1);
302 if (command != NULL) {
303 for (pc = command; *pc; pc++)
304 sendchar(*pc);
305 if (boolean(value(ECHOCHECK)))
306 (void)read(FD, &c, (size_t)1); /* trailing \n */
307 else {
308 (void)tcdrain(FD);
309 (void)sleep(5); /* wait for remote stty to take effect */
312 lcount = 0;
313 lastc = '\0';
314 start_t = time(0);
315 /* CONSTCOND */
316 while (1) {
317 ccount = 0;
318 do {
319 c = getc(fd);
320 if (stop)
321 goto out;
322 if (c == EOF)
323 goto out;
324 if (c == 0177 && !boolean(value(RAWFTP)))
325 continue;
326 lastc = c;
327 if (c < 040) {
328 if (c == '\n') {
329 if (!boolean(value(RAWFTP)))
330 c = '\r';
332 else if (c == '\t') {
333 if (!boolean(value(RAWFTP))) {
334 if (boolean(value(TABEXPAND))) {
335 sendchar(' ');
336 while ((++ccount % 8) != 0)
337 sendchar(' ');
338 continue;
341 } else
342 if (!boolean(value(RAWFTP)))
343 continue;
345 sendchar(c);
346 } while (c != '\r' && !boolean(value(RAWFTP)));
347 if (boolean(value(VERBOSE)))
348 (void)printf("\r%d", ++lcount);
349 if (boolean(value(ECHOCHECK))) {
350 timedout = 0;
351 (void)alarm((unsigned int)number(value(ETIMEOUT)));
352 do { /* wait for prompt */
353 (void)read(FD, &c, (size_t)1);
354 if (timedout || stop) {
355 if (timedout)
356 (void)printf(
357 "\r\ntimed out at eol\r\n");
358 (void)alarm(0);
359 goto out;
361 } while ((c&STRIP_PAR) != character(value(PROMPT)));
362 (void)alarm(0);
365 out:
366 if (lastc != '\n' && !boolean(value(RAWFTP)))
367 sendchar('\r');
368 if (eofchars) {
369 for (pc = eofchars; *pc; pc++)
370 sendchar(*pc);
372 stop_t = time(0);
373 (void)fclose(fd);
374 (void)signal(SIGINT, f);
375 if (boolean(value(VERBOSE))) {
376 if (boolean(value(RAWFTP)))
377 prtime(" chars transferred in ", stop_t-start_t);
378 else
379 prtime(" lines transferred in ", stop_t-start_t);
381 (void)write(fildes[1], (char *)&ccc, 1);
382 (void)tcsetattr(0, TCSAFLUSH, &term);
386 * Cu-like put command
388 /* ARGSUSED */
389 void
390 cu_put(char dummy __unused)
392 FILE *fd;
393 char line[BUFSIZ];
394 int argc;
395 char *copynamex;
397 if (prompt("[put] ", copyname, sizeof copyname))
398 return;
399 if ((argc = args(copyname, argv)) < 1 || argc > 2) {
400 (void)printf("usage: <put> from [to]\r\n");
401 return;
403 if (argc == 1)
404 argv[1] = argv[0];
405 copynamex = expand(argv[0]);
406 if ((fd = fopen(copynamex, "r")) == NULL) {
407 (void)printf("%s: cannot open\r\n", copynamex);
408 return;
410 if (boolean(value(ECHOCHECK)))
411 (void)snprintf(line, sizeof line, "cat>%s\r", argv[1]);
412 else
413 (void)snprintf(line, sizeof line, "stty -echo;cat>%s;stty echo\r", argv[1]);
414 transmit(fd, "\04", line);
418 * FTP - send single character
419 * wait for echo & handle timeout
421 void
422 sendchar(char c)
424 char cc;
425 int retry = 0;
427 cc = c;
428 xpwrite(FD, &cc, 1);
429 #ifdef notdef
430 if (number(value(CDELAY)) > 0 && c != '\r')
431 nap(number(value(CDELAY)));
432 #endif
433 if (!boolean(value(ECHOCHECK))) {
434 #ifdef notdef
435 if (number(value(LDELAY)) > 0 && c == '\r')
436 nap(number(value(LDELAY)));
437 #endif
438 return;
440 tryagain:
441 timedout = 0;
442 (void)alarm((unsigned int)number(value(ETIMEOUT)));
443 (void)read(FD, &cc, 1);
444 (void)alarm(0);
445 if (timedout) {
446 (void)printf("\r\ntimeout error (%s)\r\n", ctrl(c));
447 if (retry++ > 3)
448 return;
449 xpwrite(FD, &null, 1); /* poke it */
450 goto tryagain;
454 /* ARGSUSED */
455 void
456 alrmtimeout(int dummy __unused)
459 (void)signal(SIGALRM, alrmtimeout);
460 timedout = 1;
464 * Stolen from consh() -- puts a remote file on the output of a local command.
465 * Identical to consh() except for where stdout goes.
467 void
468 pipeout(char c)
470 char buf[256];
471 int cpid, status, p;
472 time_t start = 0;
474 (void)putchar(c);
475 if (prompt("Local command? ", buf, sizeof buf))
476 return;
477 (void)write(attndes[1], "W", 1); /* put TIPOUT into a wait state */
478 (void)signal(SIGINT, SIG_IGN);
479 (void)signal(SIGQUIT, SIG_IGN);
480 (void)tcsetattr(0, TCSAFLUSH, &defchars);
481 (void)read(repdes[0], (char *)&ccc, 1);
483 * Set up file descriptors in the child and
484 * let it go...
486 if ((cpid = fork()) < 0)
487 (void)printf("can't fork!\r\n");
488 else if (cpid) {
489 start = time(0);
490 while ((p = wait(&status)) > 0 && p != cpid)
492 } else {
493 (void)dup2(FD, 1);
494 (void)closefrom(3);
495 (void)signal(SIGINT, SIG_DFL);
496 (void)signal(SIGQUIT, SIG_DFL);
497 execute(buf);
498 (void)printf("can't find `%s'\r\n", buf);
499 exit(0);
501 if (boolean(value(VERBOSE)))
502 prtime("away for ", time(0)-start);
503 (void)write(fildes[1], (char *)&ccc, 1);
504 (void)tcsetattr(0, TCSAFLUSH, &term);
505 (void)signal(SIGINT, SIG_DFL);
506 (void)signal(SIGQUIT, SIG_DFL);
510 * Fork a program with:
511 * 0 <-> remote tty in
512 * 1 <-> remote tty out
513 * 2 <-> local tty out
515 void
516 consh(char c)
518 char buf[256];
519 int cpid, status, p;
520 time_t start = 0;
522 (void)putchar(c);
523 if (prompt("Local command? ", buf, sizeof buf))
524 return;
525 (void)write(attndes[1], "W", 1); /* put TIPOUT into a wait state */
526 (void)signal(SIGINT, SIG_IGN);
527 (void)signal(SIGQUIT, SIG_IGN);
528 (void)tcsetattr(0, TCSAFLUSH, &defchars);
529 (void)read(repdes[0], (char *)&ccc, 1);
531 * Set up file descriptors in the child and
532 * let it go...
534 if ((cpid = fork()) < 0)
535 (void)printf("can't fork!\r\n");
536 else if (cpid) {
537 start = time(0);
538 while ((p = wait(&status)) > 0 && p != cpid)
540 } else {
541 (void)dup2(FD, 0);
542 (void)dup2(FD, 1);
543 (void)closefrom(3);
544 (void)signal(SIGINT, SIG_DFL);
545 (void)signal(SIGQUIT, SIG_DFL);
546 execute(buf);
547 (void)printf("can't find `%s'\r\n", buf);
548 exit(0);
550 if (boolean(value(VERBOSE)))
551 prtime("away for ", time(0)-start);
552 (void)write(fildes[1], (char *)&ccc, 1);
553 (void)tcsetattr(0, TCSAFLUSH, &term);
554 (void)signal(SIGINT, SIG_DFL);
555 (void)signal(SIGQUIT, SIG_DFL);
559 * Escape to local shell
561 /* ARGSUSED */
562 void
563 shell(char dummy __unused)
565 int shpid, status;
566 const char *cp;
568 (void)printf("[sh]\r\n");
569 (void)signal(SIGINT, SIG_IGN);
570 (void)signal(SIGQUIT, SIG_IGN);
571 unraw();
572 switch (shpid = fork()) {
573 default:
574 while (shpid != wait(&status));
575 raw();
576 (void)printf("\r\n!\r\n");
577 (void)signal(SIGINT, SIG_DFL);
578 (void)signal(SIGQUIT, SIG_DFL);
579 break;
580 case 0:
581 (void)signal(SIGQUIT, SIG_DFL);
582 (void)signal(SIGINT, SIG_DFL);
583 if ((cp = strrchr(value(SHELL), '/')) == NULL)
584 cp = value(SHELL);
585 else
586 cp++;
587 (void)execl(value(SHELL), cp, NULL);
588 (void)fprintf(stderr, "\r\n");
589 err(1, "can't execl");
590 /* NOTREACHED */
591 case -1:
592 (void)fprintf(stderr, "\r\n");
593 err(1, "can't fork");
594 /* NOTREACHED */
599 * TIPIN portion of scripting
600 * initiate the conversation with TIPOUT
602 void
603 setscript(void)
605 char c;
607 * enable TIPOUT side for dialogue
609 (void)write(attndes[1], "S", 1);
610 if (boolean(value(SCRIPT)) && strlen(value(RECORD)))
611 (void)write(fildes[1], value(RECORD), strlen(value(RECORD)));
612 (void)write(fildes[1], "\n", 1);
614 * wait for TIPOUT to finish
616 (void)read(repdes[0], &c, 1);
617 if (c == 'n')
618 (void)printf("can't create %s\r\n", (char *)value(RECORD));
622 * Change current working directory of
623 * local portion of tip
625 /* ARGSUSED */
626 void
627 chdirectory(char dummy __unused)
629 char dirnam[80];
630 const char *cp = dirnam;
632 if (prompt("[cd] ", dirnam, sizeof dirnam)) {
633 if (stoprompt)
634 return;
635 cp = value(HOME);
637 if (chdir(cp) < 0)
638 (void)printf("%s: bad directory\r\n", cp);
639 (void)printf("!\r\n");
642 void
643 tipabort(const char *msg)
646 (void)kill(pid, SIGTERM);
647 disconnect(msg);
648 if (msg != NULL)
649 (void)printf("\r\n%s", msg);
650 (void)printf("\r\n[EOT]\r\n");
651 unraw();
652 exit(0);
655 /* ARGSUSED */
656 void
657 finish(char dummy __unused)
659 const char *dismsg;
661 dismsg = value(DISCONNECT);
662 if (dismsg != NULL && dismsg[0] != '\0') {
663 (void)write(FD, dismsg, strlen(dismsg));
664 (void)sleep(5);
666 tipabort(NULL);
669 /* ARGSUSED */
670 void
671 intcopy(int dummy __unused)
674 raw();
675 quit = 1;
676 longjmp(intbuf, 1);
679 void
680 execute(char *s)
682 const char *cp;
684 if ((cp = strrchr(value(SHELL), '/')) == NULL)
685 cp = value(SHELL);
686 else
687 cp++;
688 (void)execl(value(SHELL), cp, "-c", s, NULL);
692 args(char *buf, char *a[])
694 char *p = buf, *start;
695 char **parg = a;
696 int n = 0;
698 do {
699 while (*p && (*p == ' ' || *p == '\t'))
700 p++;
701 start = p;
702 if (*p)
703 *parg = p;
704 while (*p && (*p != ' ' && *p != '\t'))
705 p++;
706 if (p != start)
707 parg++, n++;
708 if (*p)
709 *p++ = '\0';
710 } while (*p);
712 return(n);
715 void
716 prtime(const char *s, time_t a)
718 int i;
719 int nums[3];
721 for (i = 0; i < 3; i++) {
722 nums[i] = (int)(a % quant[i]);
723 a /= quant[i];
725 (void)printf("%s", s);
726 while (--i >= 0)
727 if (nums[i] || (i == 0 && nums[1] == 0 && nums[2] == 0))
728 (void)printf("%d %s%c ", nums[i], sep[i],
729 nums[i] == 1 ? '\0' : 's');
730 (void)printf("\r\n!\r\n");
733 /* ARGSUSED */
734 void
735 variable(char dummy __unused)
737 char buf[256];
739 if (prompt("[set] ", buf, sizeof buf))
740 return;
741 vlex(buf);
742 if (vtable[BEAUTIFY].v_access&CHANGED) {
743 vtable[BEAUTIFY].v_access &= ~CHANGED;
744 (void)write(attndes[1], "B", 1); /* Tell TIPOUT to toggle */
746 if (vtable[SCRIPT].v_access&CHANGED) {
747 vtable[SCRIPT].v_access &= ~CHANGED;
748 setscript();
750 * So that "set record=blah script" doesn't
751 * cause two transactions to occur.
753 if (vtable[RECORD].v_access&CHANGED)
754 vtable[RECORD].v_access &= ~CHANGED;
756 if (vtable[RECORD].v_access&CHANGED) {
757 vtable[RECORD].v_access &= ~CHANGED;
758 if (boolean(value(SCRIPT)))
759 setscript();
761 if (vtable[TAND].v_access&CHANGED) {
762 vtable[TAND].v_access &= ~CHANGED;
763 if (boolean(value(TAND)))
764 tandem("on");
765 else
766 tandem("off");
768 if (vtable[LECHO].v_access&CHANGED) {
769 vtable[LECHO].v_access &= ~CHANGED;
770 HD = boolean(value(LECHO));
772 if (vtable[PARITY].v_access&CHANGED) {
773 vtable[PARITY].v_access &= ~CHANGED;
774 setparity(NULL); /* XXX what is the correct arg? */
776 if (vtable[HARDWAREFLOW].v_access&CHANGED) {
777 vtable[HARDWAREFLOW].v_access &= ~CHANGED;
778 if (boolean(value(HARDWAREFLOW)))
779 hardwareflow("on");
780 else
781 hardwareflow("off");
786 * Turn tandem mode on or off for remote tty.
788 void
789 tandem(const char *option)
791 struct termios rmtty;
793 (void)tcgetattr(FD, &rmtty);
794 if (strcmp(option, "on") == 0) {
795 rmtty.c_iflag |= IXOFF;
796 term.c_iflag |= IXOFF;
797 } else {
798 rmtty.c_iflag &= ~IXOFF;
799 term.c_iflag &= ~IXOFF;
801 (void)tcsetattr(FD, TCSADRAIN, &rmtty);
802 (void)tcsetattr(0, TCSADRAIN, &term);
806 * Turn hardware flow control on or off for remote tty.
808 void
809 hardwareflow(const char *option)
811 struct termios rmtty;
813 (void)tcgetattr(FD, &rmtty);
814 if (strcmp(option, "on") == 0)
815 rmtty.c_cflag |= CRTSCTS;
816 else
817 rmtty.c_cflag &= ~CRTSCTS;
818 (void)tcsetattr(FD, TCSADRAIN, &rmtty);
822 * Send a break.
824 /* ARGSUSED */
825 void
826 genbrk(char dummy __unused)
829 (void)ioctl(FD, TIOCSBRK, NULL);
830 (void)sleep(1);
831 (void)ioctl(FD, TIOCCBRK, NULL);
835 * Suspend tip
837 void
838 suspend(char c)
841 unraw();
842 (void)kill(c == CTRL('y') ? getpid() : 0, SIGTSTP);
843 raw();
847 * expand a file name if it includes shell meta characters
850 char *
851 expand(char aname[])
853 static char xname[BUFSIZ];
854 char * volatile name;
855 char cmdbuf[BUFSIZ];
856 int mypid, l;
857 char *cp;
858 const char *Shell;
859 int s, pivec[2];
861 name = aname;
862 if (!anyof(name, "~{[*?$`'\"\\"))
863 return(name);
864 if (pipe(pivec) < 0) {
865 warn("pipe");
866 return(name);
868 (void)snprintf(cmdbuf, sizeof cmdbuf, "echo %s", name);
869 if ((mypid = vfork()) == 0) {
870 Shell = value(SHELL);
871 if (Shell == NULL)
872 Shell = _PATH_BSHELL;
873 (void)close(pivec[0]);
874 (void)close(1);
875 (void)dup(pivec[1]);
876 (void)close(pivec[1]);
877 (void)close(2);
878 (void)execl(Shell, Shell, "-c", cmdbuf, NULL);
879 _exit(1);
881 if (mypid == -1) {
882 warn("fork");
883 (void)close(pivec[0]);
884 (void)close(pivec[1]);
885 return(NULL);
887 (void)close(pivec[1]);
888 l = read(pivec[0], xname, BUFSIZ);
889 (void)close(pivec[0]);
890 while (wait(&s) != mypid);
892 s &= 0377;
893 if (s != 0 && s != SIGPIPE) {
894 (void)fprintf(stderr, "\"Echo\" failed\n");
895 return(NULL);
897 if (l < 0) {
898 warn("read");
899 return(NULL);
901 if (l == 0) {
902 (void)fprintf(stderr, "\"%s\": No match\n", name);
903 return(NULL);
905 if (l == BUFSIZ) {
906 (void)fprintf(stderr, "Buffer overflow expanding \"%s\"\n", name);
907 return(NULL);
909 xname[l] = 0;
910 for (cp = &xname[l-1]; *cp == '\n' && cp > xname; cp--)
912 *++cp = '\0';
913 return(xname);
917 * Are any of the characters in the two strings the same?
921 anyof(char *s1, const char *s2)
923 int c;
925 while ((c = *s1++) != '\0')
926 if (any(c, s2))
927 return(1);
928 return(0);