BSD 4_4 release
[unix-history] / usr / src / usr.bin / tip / cmds.c
index b6aa514..63bfee2 100644 (file)
@@ -1,5 +1,43 @@
-/*     cmds.c  4.9     82/07/29        */
+/*
+ * Copyright (c) 1983, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)cmds.c     8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
 #include "tip.h"
 #include "tip.h"
+#include "pathnames.h"
+
 /*
  * tip
  *
 /*
  * tip
  *
@@ -12,10 +50,9 @@ char null = '\0';
 char   *sep[] = { "second", "minute", "hour" };
 static char *argv[10];         /* argument vector for take and put */
 
 char   *sep[] = { "second", "minute", "hour" };
 static char *argv[10];         /* argument vector for take and put */
 
-int    timeout();              /* timeout function called on alarm */
-int    stopsnd();              /* SIGINT handler during file transfers */
-int    intprompt();            /* used in handling SIG_INT during prompt */
-int    intcopy();              /* interrupt routine for file transfers */
+void   timeout();              /* timeout function called on alarm */
+void   stopsnd();              /* SIGINT handler during file transfers */
+void   intcopy();              /* interrupt routine for file transfers */
 
 /*
  * FTP - remote ==> local
 
 /*
  * FTP - remote ==> local
@@ -24,7 +61,7 @@ int   intcopy();              /* interrupt routine for file transfers */
 getfl(c)
        char c;
 {
 getfl(c)
        char c;
 {
-       char buf[256];
+       char buf[256], *cp, *expand();
        
        putchar(c);
        /*
        
        putchar(c);
        /*
@@ -32,7 +69,8 @@ getfl(c)
         */
        if (prompt("Local file name? ", copyname))
                return;
         */
        if (prompt("Local file name? ", copyname))
                return;
-       if ((sfd = creat(copyname, 0666)) < 0) {
+       cp = expand(copyname);
+       if ((sfd = creat(cp, 0666)) < 0) {
                printf("\r\n%s: cannot creat\r\n", copyname);
                return;
        }
                printf("\r\n%s: cannot creat\r\n", copyname);
                return;
        }
@@ -54,7 +92,7 @@ cu_take(cc)
        char cc;
 {
        int fd, argc;
        char cc;
 {
        int fd, argc;
-       char line[BUFSIZ];
+       char line[BUFSIZ], *expand(), *cp;
 
        if (prompt("[take] ", copyname))
                return;
 
        if (prompt("[take] ", copyname))
                return;
@@ -64,14 +102,16 @@ cu_take(cc)
        }
        if (argc == 1)
                argv[1] = argv[0];
        }
        if (argc == 1)
                argv[1] = argv[0];
-       if ((fd = creat(argv[1], 0666)) < 0) {
+       cp = expand(argv[1]);
+       if ((fd = creat(cp, 0666)) < 0) {
                printf("\r\n%s: cannot create\r\n", argv[1]);
                return;
        }
                printf("\r\n%s: cannot create\r\n", argv[1]);
                return;
        }
-       sprintf(line, "cat '%s';echo \01", argv[0]);
+       sprintf(line, "cat %s;echo \01", argv[0]);
        transfer(line, fd, "\01");
 }
 
        transfer(line, fd, "\01");
 }
 
+static jmp_buf intbuf;
 /*
  * Bulk transfer routine --
  *  used by getfl(), cu_take(), and pipefile()
 /*
  * Bulk transfer routine --
  *  used by getfl(), cu_take(), and pipefile()
@@ -84,22 +124,26 @@ transfer(buf, fd, eofchars)
        register char *p = buffer;
        register int cnt, eof;
        time_t start;
        register char *p = buffer;
        register int cnt, eof;
        time_t start;
+       sig_t f;
+       char r;
 
 
-       write(FD, buf, size(buf));
+       pwrite(FD, buf, size(buf));
        quit = 0;
        quit = 0;
-       signal(SIGINT, intcopy);
        kill(pid, SIGIOT);
        read(repdes[0], (char *)&ccc, 1);  /* Wait until read process stops */
        
        /*
         * finish command
         */
        kill(pid, SIGIOT);
        read(repdes[0], (char *)&ccc, 1);  /* Wait until read process stops */
        
        /*
         * finish command
         */
-       write(FD, "\r", 1);
+       r = '\r';
+       pwrite(FD, &r, 1);
        do
                read(FD, &c, 1); 
        while ((c&0177) != '\n');
        ioctl(0, TIOCSETC, &defchars);
        
        do
                read(FD, &c, 1); 
        while ((c&0177) != '\n');
        ioctl(0, TIOCSETC, &defchars);
        
+       (void) setjmp(intbuf);
+       f = signal(SIGINT, intcopy);
        start = time(0);
        for (ct = 0; !quit;) {
                eof = read(FD, &c, 1) <= 0;
        start = time(0);
        for (ct = 0; !quit;) {
                eof = read(FD, &c, 1) <= 0;
@@ -132,7 +176,7 @@ transfer(buf, fd, eofchars)
                prtime(" lines transferred in ", time(0)-start);
        ioctl(0, TIOCSETC, &tchars);
        write(fildes[1], (char *)&ccc, 1);
                prtime(" lines transferred in ", time(0)-start);
        ioctl(0, TIOCSETC, &tchars);
        write(fildes[1], (char *)&ccc, 1);
-       signal(SIGINT, SIG_DFL);
+       signal(SIGINT, f);
        close(fd);
 }
 
        close(fd);
 }
 
@@ -186,8 +230,10 @@ pipefile()
 /*
  * Interrupt service routine for FTP
  */
 /*
  * Interrupt service routine for FTP
  */
+void
 stopsnd()
 {
 stopsnd()
 {
+
        stop = 1;
        signal(SIGINT, SIG_IGN);
 }
        stop = 1;
        signal(SIGINT, SIG_IGN);
 }
@@ -201,6 +247,8 @@ sendfile(cc)
        char cc;
 {
        FILE *fd;
        char cc;
 {
        FILE *fd;
+       char *fnamex;
+       char *expand();
 
        putchar(cc);
        /*
 
        putchar(cc);
        /*
@@ -212,7 +260,8 @@ sendfile(cc)
        /*
         * look up file
         */
        /*
         * look up file
         */
-       if ((fd = fopen(fname, "r")) == NULL) {
+       fnamex = expand(fname);
+       if ((fd = fopen(fnamex, "r")) == NULL) {
                printf("%s: cannot open\r\n", fname);
                return;
        }
                printf("%s: cannot open\r\n", fname);
                return;
        }
@@ -233,13 +282,14 @@ transmit(fd, eofchars, command)
        FILE *fd;
        char *eofchars, *command;
 {
        FILE *fd;
        char *eofchars, *command;
 {
-       char *pc, lastc, rc;
+       char *pc, lastc;
        int c, ccount, lcount;
        time_t start_t, stop_t;
        int c, ccount, lcount;
        time_t start_t, stop_t;
+       sig_t f;
 
        kill(pid, SIGIOT);      /* put TIPOUT into a wait state */
 
        kill(pid, SIGIOT);      /* put TIPOUT into a wait state */
-       signal(SIGINT, stopsnd);
        stop = 0;
        stop = 0;
+       f = signal(SIGINT, stopsnd);
        ioctl(0, TIOCSETC, &defchars);
        read(repdes[0], (char *)&ccc, 1);
        if (command != NULL) {
        ioctl(0, TIOCSETC, &defchars);
        read(repdes[0], (char *)&ccc, 1);
        if (command != NULL) {
@@ -266,51 +316,59 @@ transmit(fd, eofchars, command)
                                goto out;
                        if (c == EOF)
                                goto out;
                                goto out;
                        if (c == EOF)
                                goto out;
-                       if (c == 0177)
+                       if (c == 0177 && !boolean(value(RAWFTP)))
                                continue;
                        lastc = c;
                        if (c < 040) {
                                continue;
                        lastc = c;
                        if (c < 040) {
-                               if (c == '\n')
-                                       c = '\r';
+                               if (c == '\n') {
+                                       if (!boolean(value(RAWFTP)))
+                                               c = '\r';
+                               }
                                else if (c == '\t') {
                                else if (c == '\t') {
-                                       if (boolean(value(TABEXPAND))) {
-                                               send(' ');
-                                               while ((++ccount % 8) != 0)
+                                       if (!boolean(value(RAWFTP))) {
+                                               if (boolean(value(TABEXPAND))) {
                                                        send(' ');
                                                        send(' ');
-                                               continue;
+                                                       while ((++ccount % 8) != 0)
+                                                               send(' ');
+                                                       continue;
+                                               }
                                        }
                                        }
-                               } else if (!any(c, value(EXCEPTIONS)))
-                                       continue;
+                               } else
+                                       if (!boolean(value(RAWFTP)))
+                                               continue;
                        }
                        send(c);
                        }
                        send(c);
-               } while (c != '\r');
+               } while (c != '\r' && !boolean(value(RAWFTP)));
                if (boolean(value(VERBOSE)))
                        printf("\r%d", ++lcount);
                if (boolean(value(ECHOCHECK))) {
                if (boolean(value(VERBOSE)))
                        printf("\r%d", ++lcount);
                if (boolean(value(ECHOCHECK))) {
-                       alarm(10);
                        timedout = 0;
                        timedout = 0;
+                       alarm((int)value(ETIMEOUT));
                        do {    /* wait for prompt */
                        do {    /* wait for prompt */
-                               read(FD, (char *)&rc, 1);
+                               read(FD, (char *)&c, 1);
                                if (timedout || stop) {
                                        if (timedout)
                                                printf("\r\ntimed out at eol\r\n");
                                        alarm(0);
                                        goto out;
                                }
                                if (timedout || stop) {
                                        if (timedout)
                                                printf("\r\ntimed out at eol\r\n");
                                        alarm(0);
                                        goto out;
                                }
-                       } while ((rc&0177) != character(value(PROMPT)));
+                       } while ((c&0177) != character(value(PROMPT)));
                        alarm(0);
                }
        }
 out:
                        alarm(0);
                }
        }
 out:
-       if (lastc != '\n')
+       if (lastc != '\n' && !boolean(value(RAWFTP)))
                send('\r');
        for (pc = eofchars; *pc; pc++)
                send(*pc);
        stop_t = time(0);
        fclose(fd);
                send('\r');
        for (pc = eofchars; *pc; pc++)
                send(*pc);
        stop_t = time(0);
        fclose(fd);
-       signal(SIGINT, SIG_DFL);
+       signal(SIGINT, f);
        if (boolean(value(VERBOSE)))
        if (boolean(value(VERBOSE)))
-               prtime(" lines transferred in ", stop_t-start_t);
+               if (boolean(value(RAWFTP)))
+                       prtime(" chars transferred in ", stop_t-start_t);
+               else
+                       prtime(" lines transferred in ", stop_t-start_t);
        write(fildes[1], (char *)&ccc, 1);
        ioctl(0, TIOCSETC, &tchars);
 }
        write(fildes[1], (char *)&ccc, 1);
        ioctl(0, TIOCSETC, &tchars);
 }
@@ -324,6 +382,8 @@ cu_put(cc)
        FILE *fd;
        char line[BUFSIZ];
        int argc;
        FILE *fd;
        char line[BUFSIZ];
        int argc;
+       char *expand();
+       char *copynamex;
 
        if (prompt("[put] ", copyname))
                return;
 
        if (prompt("[put] ", copyname))
                return;
@@ -333,14 +393,15 @@ cu_put(cc)
        }
        if (argc == 1)
                argv[1] = argv[0];
        }
        if (argc == 1)
                argv[1] = argv[0];
-       if ((fd = fopen(argv[0], "r")) == NULL) {
-               printf("%s: cannot open\r\n", argv[0]);
+       copynamex = expand(argv[0]);
+       if ((fd = fopen(copynamex, "r")) == NULL) {
+               printf("%s: cannot open\r\n", copynamex);
                return;
        }
        if (boolean(value(ECHOCHECK)))
                return;
        }
        if (boolean(value(ECHOCHECK)))
-               sprintf(line, "cat>'%s'\r", argv[1]);
+               sprintf(line, "cat>%s\r", argv[1]);
        else
        else
-               sprintf(line, "stty -echo;cat>'%s';stty echo\r", argv[1]);
+               sprintf(line, "stty -echo;cat>%s;stty echo\r", argv[1]);
        transmit(fd, "\04", line);
 }
 
        transmit(fd, "\04", line);
 }
 
@@ -355,37 +416,93 @@ send(c)
        int retry = 0;
 
        cc = c;
        int retry = 0;
 
        cc = c;
-       write(FD, (char *)&cc, 1);
-       if (!boolean(value(ECHOCHECK)))
+       pwrite(FD, &cc, 1);
+#ifdef notdef
+       if (number(value(CDELAY)) > 0 && c != '\r')
+               nap(number(value(CDELAY)));
+#endif
+       if (!boolean(value(ECHOCHECK))) {
+#ifdef notdef
+               if (number(value(LDELAY)) > 0 && c == '\r')
+                       nap(number(value(LDELAY)));
+#endif
                return;
                return;
+       }
 tryagain:
        timedout = 0;
 tryagain:
        timedout = 0;
-       alarm(10);
-       read(FD, (char *)&cc, 1);
+       alarm((int)value(ETIMEOUT));
+       read(FD, &cc, 1);
        alarm(0);
        if (timedout) {
                printf("\r\ntimeout error (%s)\r\n", ctrl(c));
                if (retry++ > 3)
                        return;
        alarm(0);
        if (timedout) {
                printf("\r\ntimeout error (%s)\r\n", ctrl(c));
                if (retry++ > 3)
                        return;
-               write(FD, &null, 1); /* poke it */
+               pwrite(FD, &null, 1); /* poke it */
                goto tryagain;
        }
 }
 
                goto tryagain;
        }
 }
 
+void
 timeout()
 {
        signal(SIGALRM, timeout);
        timedout = 1;
 }
 
 timeout()
 {
        signal(SIGALRM, timeout);
        timedout = 1;
 }
 
+/*
+ * Stolen from consh() -- puts a remote file on the output of a local command.
+ *     Identical to consh() except for where stdout goes.
+ */
+pipeout(c)
+{
+       char buf[256];
+       int cpid, status, p;
+       time_t start;
+
+       putchar(c);
+       if (prompt("Local command? ", buf))
+               return;
+       kill(pid, SIGIOT);      /* put TIPOUT into a wait state */
+       signal(SIGINT, SIG_IGN);
+       signal(SIGQUIT, SIG_IGN);
+       ioctl(0, TIOCSETC, &defchars);
+       read(repdes[0], (char *)&ccc, 1);
+       /*
+        * Set up file descriptors in the child and
+        *  let it go...
+        */
+       if ((cpid = fork()) < 0)
+               printf("can't fork!\r\n");
+       else if (cpid) {
+               start = time(0);
+               while ((p = wait(&status)) > 0 && p != cpid)
+                       ;
+       } else {
+               register int i;
+
+               dup2(FD, 1);
+               for (i = 3; i < 20; i++)
+                       close(i);
+               signal(SIGINT, SIG_DFL);
+               signal(SIGQUIT, SIG_DFL);
+               execute(buf);
+               printf("can't find `%s'\r\n", buf);
+               exit(0);
+       }
+       if (boolean(value(VERBOSE)))
+               prtime("away for ", time(0)-start);
+       write(fildes[1], (char *)&ccc, 1);
+       ioctl(0, TIOCSETC, &tchars);
+       signal(SIGINT, SIG_DFL);
+       signal(SIGQUIT, SIG_DFL);
+}
+
 #ifdef CONNECT
 /*
  * Fork a program with:
 #ifdef CONNECT
 /*
  * Fork a program with:
- *  0 <-> local tty in
- *  1 <-> local tty out
+ *  0 <-> remote tty in
+ *  1 <-> remote tty out
  *  2 <-> local tty out
  *  2 <-> local tty out
- *  3 <-> remote tty in
- *  4 <-> remote tty out
  */
 consh(c)
 {
  */
 consh(c)
 {
@@ -414,9 +531,9 @@ consh(c)
        } else {
                register int i;
 
        } else {
                register int i;
 
-               dup2(FD, 3);
-               dup2(3, 4);
-               for (i = 5; i < 20; i++)
+               dup2(FD, 0);
+               dup2(3, 1);
+               for (i = 3; i < 20; i++)
                        close(i);
                signal(SIGINT, SIG_DFL);
                signal(SIGQUIT, SIG_DFL);
                        close(i);
                signal(SIGINT, SIG_DFL);
                signal(SIGQUIT, SIG_DFL);
@@ -460,6 +577,7 @@ shell()
                        cp = value(SHELL);
                else
                        cp++;
                        cp = value(SHELL);
                else
                        cp++;
+               shell_uid();
                execl(value(SHELL), cp, 0);
                printf("\r\ncan't execl!\r\n");
                exit(1);
                execl(value(SHELL), cp, 0);
                printf("\r\ncan't execl!\r\n");
                exit(1);
@@ -494,33 +612,51 @@ setscript()
  */
 chdirectory()
 {
  */
 chdirectory()
 {
-       char    dirname[80];
+       char dirname[80];
        register char *cp = dirname;
 
        register char *cp = dirname;
 
-       if (prompt("[cd] ", dirname))
+       if (prompt("[cd] ", dirname)) {
                if (stoprompt)
                        return;
                if (stoprompt)
                        return;
-               else
-                       cp = value(HOME);
+               cp = value(HOME);
+       }
        if (chdir(cp) < 0)
                printf("%s: bad directory\r\n", cp);
        printf("!\r\n");
 }
 
        if (chdir(cp) < 0)
                printf("%s: bad directory\r\n", cp);
        printf("!\r\n");
 }
 
-finish()
+tipabort(msg)
+       char *msg;
 {
 {
+
        kill(pid, SIGTERM);
        kill(pid, SIGTERM);
-       disconnect();
+       disconnect(msg);
+       if (msg != NOSTR)
+               printf("\r\n%s", msg);
        printf("\r\n[EOT]\r\n");
        printf("\r\n[EOT]\r\n");
-       delock(uucplock);
+       daemon_uid();
+       (void)uu_unlock(uucplock);
        unraw();
        exit(0);
 }
 
        unraw();
        exit(0);
 }
 
+finish()
+{
+       char *dismsg;
+
+       if ((dismsg = value(DISCONNECT)) != NOSTR) {
+               write(FD, dismsg, strlen(dismsg));
+               sleep(5);
+       }
+       tipabort(NOSTR);
+}
+
+void
 intcopy()
 {
        raw();
        quit = 1;
 intcopy()
 {
        raw();
        quit = 1;
+       longjmp(intbuf, 1);
 }
 
 execute(s)
 }
 
 execute(s)
@@ -532,6 +668,7 @@ execute(s)
                cp = value(SHELL);
        else
                cp++;
                cp = value(SHELL);
        else
                cp++;
+       shell_uid();
        execl(value(SHELL), cp, "-c", s, 0);
 }
 
        execl(value(SHELL), cp, "-c", s, 0);
 }
 
@@ -572,7 +709,7 @@ prtime(s, a)
        }
        printf("%s", s);
        while (--i >= 0)
        }
        printf("%s", s);
        while (--i >= 0)
-               if (nums[i])
+               if (nums[i] || i == 0 && nums[1] == 0 && nums[2] == 0)
                        printf("%d %s%c ", nums[i], sep[i],
                                nums[i] == 1 ? '\0' : 's');
        printf("\r\n!\r\n");
                        printf("%d %s%c ", nums[i], sep[i],
                                nums[i] == 1 ? '\0' : 's');
        printf("\r\n!\r\n");
@@ -604,41 +741,148 @@ variable()
                if (boolean(value(SCRIPT)))
                        setscript();
        }
                if (boolean(value(SCRIPT)))
                        setscript();
        }
+       if (vtable[TAND].v_access&CHANGED) {
+               vtable[TAND].v_access &= ~CHANGED;
+               if (boolean(value(TAND)))
+                       tandem("on");
+               else
+                       tandem("off");
+       }
+       if (vtable[LECHO].v_access&CHANGED) {
+               vtable[LECHO].v_access &= ~CHANGED;
+               HD = boolean(value(LECHO));
+       }
+       if (vtable[PARITY].v_access&CHANGED) {
+               vtable[PARITY].v_access &= ~CHANGED;
+               setparity();
+       }
+}
+
+/*
+ * Turn tandem mode on or off for remote tty.
+ */
+tandem(option)
+       char *option;
+{
+       struct sgttyb rmtty;
+
+       ioctl(FD, TIOCGETP, &rmtty);
+       if (strcmp(option,"on") == 0) {
+               rmtty.sg_flags |= TANDEM;
+               arg.sg_flags |= TANDEM;
+       } else {
+               rmtty.sg_flags &= ~TANDEM;
+               arg.sg_flags &= ~TANDEM;
+       }
+       ioctl(FD, TIOCSETP, &rmtty);
+       ioctl(0,  TIOCSETP, &arg);
 }
 
 /*
  * Send a break.
 }
 
 /*
  * Send a break.
- * If we can't do it directly (as on VMUNIX), then simulate it.
  */
 genbrk()
 {
  */
 genbrk()
 {
-#ifdef VMUNIX
+
        ioctl(FD, TIOCSBRK, NULL);
        sleep(1);
        ioctl(FD, TIOCCBRK, NULL);
        ioctl(FD, TIOCSBRK, NULL);
        sleep(1);
        ioctl(FD, TIOCCBRK, NULL);
-#else
-       struct sgttyb ttbuf;
-       int sospeed;
-
-       ioctl(FD, TIOCGETP, &ttbuf);
-       sospeed = ttbuf.sg_ospeed;
-       ttbuf.sg_ospeed = B150;
-       ioctl(FD, TIOCSETP, &ttbuf);
-       write(FD, "\0\0\0\0\0\0\0\0\0\0", 10);
-       ttbuf.sg_ospeed = sospeed;
-       ioctl(FD, TIOCSETP, &ttbuf);
-       write(FD, "@", 1);
-#endif
 }
 
 }
 
-#ifdef SIGTSTP
 /*
  * Suspend tip
  */
 /*
  * Suspend tip
  */
-suspend()
+suspend(c)
+       char c;
 {
 {
+
        unraw();
        unraw();
-       kill(0, SIGTSTP);
+       kill(c == CTRL('y') ? getpid() : 0, SIGTSTP);
        raw();
 }
        raw();
 }
-#endif
+
+/*
+ *     expand a file name if it includes shell meta characters
+ */
+
+char *
+expand(name)
+       char name[];
+{
+       static char xname[BUFSIZ];
+       char cmdbuf[BUFSIZ];
+       register int pid, l, rc;
+       register char *cp, *Shell;
+       int s, pivec[2], (*sigint)();
+
+       if (!anyof(name, "~{[*?$`'\"\\"))
+               return(name);
+       /* sigint = signal(SIGINT, SIG_IGN); */
+       if (pipe(pivec) < 0) {
+               perror("pipe");
+               /* signal(SIGINT, sigint) */
+               return(name);
+       }
+       sprintf(cmdbuf, "echo %s", name);
+       if ((pid = vfork()) == 0) {
+               Shell = value(SHELL);
+               if (Shell == NOSTR)
+                       Shell = _PATH_BSHELL;
+               close(pivec[0]);
+               close(1);
+               dup(pivec[1]);
+               close(pivec[1]);
+               close(2);
+               shell_uid();
+               execl(Shell, Shell, "-c", cmdbuf, 0);
+               _exit(1);
+       }
+       if (pid == -1) {
+               perror("fork");
+               close(pivec[0]);
+               close(pivec[1]);
+               return(NOSTR);
+       }
+       close(pivec[1]);
+       l = read(pivec[0], xname, BUFSIZ);
+       close(pivec[0]);
+       while (wait(&s) != pid);
+               ;
+       s &= 0377;
+       if (s != 0 && s != SIGPIPE) {
+               fprintf(stderr, "\"Echo\" failed\n");
+               return(NOSTR);
+       }
+       if (l < 0) {
+               perror("read");
+               return(NOSTR);
+       }
+       if (l == 0) {
+               fprintf(stderr, "\"%s\": No match\n", name);
+               return(NOSTR);
+       }
+       if (l == BUFSIZ) {
+               fprintf(stderr, "Buffer overflow expanding \"%s\"\n", name);
+               return(NOSTR);
+       }
+       xname[l] = 0;
+       for (cp = &xname[l-1]; *cp == '\n' && cp > xname; cp--)
+               ;
+       *++cp = '\0';
+       return(xname);
+}
+
+/*
+ * Are any of the characters in the two strings the same?
+ */
+
+anyof(s1, s2)
+       register char *s1, *s2;
+{
+       register int c;
+
+       while (c = *s1++)
+               if (any(c, s2))
+                       return(1);
+       return(0);
+}