17d8fb588SMatthias Schmidt /*
27d8fb588SMatthias Schmidt * sh.dir.c: Directory manipulation functions
37d8fb588SMatthias Schmidt */
47d8fb588SMatthias Schmidt /*-
57d8fb588SMatthias Schmidt * Copyright (c) 1980, 1991 The Regents of the University of California.
67d8fb588SMatthias Schmidt * All rights reserved.
77d8fb588SMatthias Schmidt *
87d8fb588SMatthias Schmidt * Redistribution and use in source and binary forms, with or without
97d8fb588SMatthias Schmidt * modification, are permitted provided that the following conditions
107d8fb588SMatthias Schmidt * are met:
117d8fb588SMatthias Schmidt * 1. Redistributions of source code must retain the above copyright
127d8fb588SMatthias Schmidt * notice, this list of conditions and the following disclaimer.
137d8fb588SMatthias Schmidt * 2. Redistributions in binary form must reproduce the above copyright
147d8fb588SMatthias Schmidt * notice, this list of conditions and the following disclaimer in the
157d8fb588SMatthias Schmidt * documentation and/or other materials provided with the distribution.
167d8fb588SMatthias Schmidt * 3. Neither the name of the University nor the names of its contributors
177d8fb588SMatthias Schmidt * may be used to endorse or promote products derived from this software
187d8fb588SMatthias Schmidt * without specific prior written permission.
197d8fb588SMatthias Schmidt *
207d8fb588SMatthias Schmidt * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
217d8fb588SMatthias Schmidt * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
227d8fb588SMatthias Schmidt * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
237d8fb588SMatthias Schmidt * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
247d8fb588SMatthias Schmidt * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
257d8fb588SMatthias Schmidt * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
267d8fb588SMatthias Schmidt * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
277d8fb588SMatthias Schmidt * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
287d8fb588SMatthias Schmidt * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
297d8fb588SMatthias Schmidt * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
307d8fb588SMatthias Schmidt * SUCH DAMAGE.
317d8fb588SMatthias Schmidt */
327d8fb588SMatthias Schmidt #include "sh.h"
337d8fb588SMatthias Schmidt #include "ed.h"
347d8fb588SMatthias Schmidt
357d8fb588SMatthias Schmidt /*
367d8fb588SMatthias Schmidt * C Shell - directory management
377d8fb588SMatthias Schmidt */
387d8fb588SMatthias Schmidt
397d8fb588SMatthias Schmidt static Char *agetcwd (void);
407d8fb588SMatthias Schmidt static void dstart (const char *);
417d8fb588SMatthias Schmidt static struct directory *dfind (Char *);
4257e3f2b5SSimon 'corecode' Schubert static Char *dfollow (Char *, int);
437d8fb588SMatthias Schmidt static void printdirs (int);
447d8fb588SMatthias Schmidt static Char *dgoto (Char *);
457d8fb588SMatthias Schmidt static void dnewcwd (struct directory *, int);
467d8fb588SMatthias Schmidt static void dset (Char *);
477d8fb588SMatthias Schmidt static void dextract (struct directory *);
487d8fb588SMatthias Schmidt static int skipargs (Char ***, const char *,
497d8fb588SMatthias Schmidt const char *);
507d8fb588SMatthias Schmidt static void dgetstack (void);
51*d6ab524cSAntonio Huete Jimenez static Char *dcanon_internal(Char *, Char *);
527d8fb588SMatthias Schmidt
537d8fb588SMatthias Schmidt static struct directory dhead INIT_ZERO_STRUCT; /* "head" of loop */
547d8fb588SMatthias Schmidt static int printd; /* force name to be printed */
557d8fb588SMatthias Schmidt
567d8fb588SMatthias Schmidt int bequiet = 0; /* do not print dir stack -strike */
577d8fb588SMatthias Schmidt
587d8fb588SMatthias Schmidt static Char *
agetcwd(void)597d8fb588SMatthias Schmidt agetcwd(void)
607d8fb588SMatthias Schmidt {
617d8fb588SMatthias Schmidt char *buf;
627d8fb588SMatthias Schmidt Char *cwd;
637d8fb588SMatthias Schmidt size_t len;
647d8fb588SMatthias Schmidt
657d8fb588SMatthias Schmidt len = MAXPATHLEN;
667d8fb588SMatthias Schmidt buf = xmalloc(len);
677d8fb588SMatthias Schmidt while (getcwd(buf, len) == NULL) {
687d8fb588SMatthias Schmidt int err;
697d8fb588SMatthias Schmidt
707d8fb588SMatthias Schmidt err = errno;
717d8fb588SMatthias Schmidt if (err != ERANGE) {
727d8fb588SMatthias Schmidt xfree(buf);
737d8fb588SMatthias Schmidt errno = err;
747d8fb588SMatthias Schmidt return NULL;
757d8fb588SMatthias Schmidt }
767d8fb588SMatthias Schmidt len *= 2;
777d8fb588SMatthias Schmidt buf = xrealloc(buf, len);
787d8fb588SMatthias Schmidt }
797d8fb588SMatthias Schmidt if (*buf == '\0') {
807d8fb588SMatthias Schmidt xfree(buf);
817d8fb588SMatthias Schmidt return NULL;
827d8fb588SMatthias Schmidt }
837d8fb588SMatthias Schmidt cwd = SAVE(buf);
847d8fb588SMatthias Schmidt xfree(buf);
857d8fb588SMatthias Schmidt return cwd;
867d8fb588SMatthias Schmidt }
877d8fb588SMatthias Schmidt
887d8fb588SMatthias Schmidt static void
dstart(const char * from)897d8fb588SMatthias Schmidt dstart(const char *from)
907d8fb588SMatthias Schmidt {
917d8fb588SMatthias Schmidt xprintf(CGETS(12, 1, "%s: Trying to start from \"%s\"\n"), progname, from);
927d8fb588SMatthias Schmidt }
937d8fb588SMatthias Schmidt
947d8fb588SMatthias Schmidt /*
957d8fb588SMatthias Schmidt * dinit - initialize current working directory
967d8fb588SMatthias Schmidt */
977d8fb588SMatthias Schmidt void
dinit(Char * hp)987d8fb588SMatthias Schmidt dinit(Char *hp)
997d8fb588SMatthias Schmidt {
1007d8fb588SMatthias Schmidt Char *cp, *tcp;
1017d8fb588SMatthias Schmidt struct directory *dp;
1027d8fb588SMatthias Schmidt
1037d8fb588SMatthias Schmidt /* Don't believe the login shell home, because it may be a symlink */
1047d8fb588SMatthias Schmidt tcp = agetcwd();
1057d8fb588SMatthias Schmidt if (tcp == NULL) {
1067d8fb588SMatthias Schmidt xprintf("%s: %s\n", progname, strerror(errno));
1077d8fb588SMatthias Schmidt if (hp && *hp) {
1087d8fb588SMatthias Schmidt char *xcp = short2str(hp);
1097d8fb588SMatthias Schmidt dstart(xcp);
1107d8fb588SMatthias Schmidt if (chdir(xcp) == -1)
1117d8fb588SMatthias Schmidt cp = NULL;
1127d8fb588SMatthias Schmidt else
1137d8fb588SMatthias Schmidt cp = Strsave(hp);
1147d8fb588SMatthias Schmidt }
1157d8fb588SMatthias Schmidt else
1167d8fb588SMatthias Schmidt cp = NULL;
1177d8fb588SMatthias Schmidt if (cp == NULL) {
1187d8fb588SMatthias Schmidt dstart("/");
1197d8fb588SMatthias Schmidt if (chdir("/") == -1)
1207d8fb588SMatthias Schmidt /* I am not even try to print an error message! */
1217d8fb588SMatthias Schmidt xexit(1);
1227d8fb588SMatthias Schmidt cp = SAVE("/");
1237d8fb588SMatthias Schmidt }
1247d8fb588SMatthias Schmidt }
1257d8fb588SMatthias Schmidt else {
1267d8fb588SMatthias Schmidt #ifdef S_IFLNK
1277d8fb588SMatthias Schmidt struct stat swd, shp;
1287d8fb588SMatthias Schmidt int swd_ok;
1297d8fb588SMatthias Schmidt
1307d8fb588SMatthias Schmidt swd_ok = stat(short2str(tcp), &swd) == 0;
1317d8fb588SMatthias Schmidt /*
1327d8fb588SMatthias Schmidt * See if $HOME is the working directory we got and use that
1337d8fb588SMatthias Schmidt */
1347d8fb588SMatthias Schmidt if (swd_ok && hp && *hp && stat(short2str(hp), &shp) != -1 &&
1357d8fb588SMatthias Schmidt DEV_DEV_COMPARE(swd.st_dev, shp.st_dev) &&
1367d8fb588SMatthias Schmidt swd.st_ino == shp.st_ino)
1377d8fb588SMatthias Schmidt cp = Strsave(hp);
1387d8fb588SMatthias Schmidt else {
1397d8fb588SMatthias Schmidt char *cwd;
1407d8fb588SMatthias Schmidt
1417d8fb588SMatthias Schmidt /*
1427d8fb588SMatthias Schmidt * use PWD if we have it (for subshells)
1437d8fb588SMatthias Schmidt */
1447d8fb588SMatthias Schmidt if (swd_ok && (cwd = getenv("PWD")) != NULL) {
1457d8fb588SMatthias Schmidt if (stat(cwd, &shp) != -1 &&
1467d8fb588SMatthias Schmidt DEV_DEV_COMPARE(swd.st_dev, shp.st_dev) &&
1477d8fb588SMatthias Schmidt swd.st_ino == shp.st_ino) {
1487d8fb588SMatthias Schmidt tcp = SAVE(cwd);
1497d8fb588SMatthias Schmidt cleanup_push(tcp, xfree);
1507d8fb588SMatthias Schmidt }
1517d8fb588SMatthias Schmidt }
1527d8fb588SMatthias Schmidt cp = dcanon(tcp, STRNULL);
1537d8fb588SMatthias Schmidt }
1547d8fb588SMatthias Schmidt #else /* S_IFLNK */
1557d8fb588SMatthias Schmidt cp = dcanon(tcp, STRNULL);
1567d8fb588SMatthias Schmidt #endif /* S_IFLNK */
1577d8fb588SMatthias Schmidt }
1587d8fb588SMatthias Schmidt
1597d8fb588SMatthias Schmidt dp = xcalloc(sizeof(struct directory), 1);
1607d8fb588SMatthias Schmidt dp->di_name = cp;
1617d8fb588SMatthias Schmidt dp->di_count = 0;
1627d8fb588SMatthias Schmidt dhead.di_next = dhead.di_prev = dp;
1637d8fb588SMatthias Schmidt dp->di_next = dp->di_prev = &dhead;
1647d8fb588SMatthias Schmidt printd = 0;
1657d8fb588SMatthias Schmidt dnewcwd(dp, 0);
1667d8fb588SMatthias Schmidt setcopy(STRdirstack, dp->di_name, VAR_READWRITE|VAR_NOGLOB);
1677d8fb588SMatthias Schmidt }
1687d8fb588SMatthias Schmidt
1697d8fb588SMatthias Schmidt static void
dset(Char * dp)1707d8fb588SMatthias Schmidt dset(Char *dp)
1717d8fb588SMatthias Schmidt {
1727d8fb588SMatthias Schmidt /*
1737d8fb588SMatthias Schmidt * Don't call set() directly cause if the directory contains ` or
1747d8fb588SMatthias Schmidt * other junk characters glob will fail.
1757d8fb588SMatthias Schmidt */
1767d8fb588SMatthias Schmidt setcopy(STRowd, varval(STRcwd), VAR_READWRITE|VAR_NOGLOB);
1777d8fb588SMatthias Schmidt setcopy(STRcwd, dp, VAR_READWRITE|VAR_NOGLOB);
1787d8fb588SMatthias Schmidt tsetenv(STRPWD, dp);
1797d8fb588SMatthias Schmidt }
1807d8fb588SMatthias Schmidt
1817d8fb588SMatthias Schmidt #define DIR_PRINT 0x01 /* -p */
1827d8fb588SMatthias Schmidt #define DIR_LONG 0x02 /* -l */
1837d8fb588SMatthias Schmidt #define DIR_VERT 0x04 /* -v */
1847d8fb588SMatthias Schmidt #define DIR_LINE 0x08 /* -n */
1857d8fb588SMatthias Schmidt #define DIR_SAVE 0x10 /* -S */
1867d8fb588SMatthias Schmidt #define DIR_LOAD 0x20 /* -L */
1877d8fb588SMatthias Schmidt #define DIR_CLEAR 0x40 /* -c */
1887d8fb588SMatthias Schmidt #define DIR_OLD 0x80 /* - */
1897d8fb588SMatthias Schmidt
1907d8fb588SMatthias Schmidt static int
skipargs(Char *** v,const char * dstr,const char * str)1917d8fb588SMatthias Schmidt skipargs(Char ***v, const char *dstr, const char *str)
1927d8fb588SMatthias Schmidt {
1937d8fb588SMatthias Schmidt Char **n = *v, *s;
1947d8fb588SMatthias Schmidt
1957d8fb588SMatthias Schmidt int dflag = 0, loop = 1;
1967d8fb588SMatthias Schmidt for (n++; loop && *n != NULL && (*n)[0] == '-'; n++)
1977d8fb588SMatthias Schmidt if (*(s = &((*n)[1])) == '\0') /* test for bare "-" argument */
1987d8fb588SMatthias Schmidt dflag |= DIR_OLD;
19994afa86dSJohn Marino else if ((*n)[1] == '-' && (*n)[2] == '\0') { /* test for -- */
20094afa86dSJohn Marino n++;
20194afa86dSJohn Marino break;
20294afa86dSJohn Marino } else {
2037d8fb588SMatthias Schmidt char *p;
20494afa86dSJohn Marino while (*s != '\0') /* examine flags */ {
2057d8fb588SMatthias Schmidt if ((p = strchr(dstr, *s++)) != NULL)
2067d8fb588SMatthias Schmidt dflag |= (1 << (p - dstr));
2077d8fb588SMatthias Schmidt else
2087d8fb588SMatthias Schmidt stderror(ERR_DIRUS, short2str(**v), dstr, str);
2097d8fb588SMatthias Schmidt }
2107d8fb588SMatthias Schmidt }
2117d8fb588SMatthias Schmidt if (*n && (dflag & DIR_OLD))
2127d8fb588SMatthias Schmidt stderror(ERR_DIRUS, short2str(**v), dstr, str);
2137d8fb588SMatthias Schmidt *v = n;
2147d8fb588SMatthias Schmidt /* make -l, -v, and -n imply -p */
2157d8fb588SMatthias Schmidt if (dflag & (DIR_LONG|DIR_VERT|DIR_LINE))
2167d8fb588SMatthias Schmidt dflag |= DIR_PRINT;
2177d8fb588SMatthias Schmidt return dflag;
2187d8fb588SMatthias Schmidt }
2197d8fb588SMatthias Schmidt
2207d8fb588SMatthias Schmidt /*
2217d8fb588SMatthias Schmidt * dodirs - list all directories in directory loop
2227d8fb588SMatthias Schmidt */
2237d8fb588SMatthias Schmidt /*ARGSUSED*/
2247d8fb588SMatthias Schmidt void
dodirs(Char ** v,struct command * c)2257d8fb588SMatthias Schmidt dodirs(Char **v, struct command *c)
2267d8fb588SMatthias Schmidt {
2277d8fb588SMatthias Schmidt static const char flags[] = "plvnSLc";
2287d8fb588SMatthias Schmidt int dflag = skipargs(&v, flags, "");
2297d8fb588SMatthias Schmidt
2307d8fb588SMatthias Schmidt USE(c);
2317d8fb588SMatthias Schmidt if ((dflag & DIR_CLEAR) != 0) {
2327d8fb588SMatthias Schmidt struct directory *dp, *fdp;
2337d8fb588SMatthias Schmidt for (dp = dcwd->di_next; dp != dcwd; ) {
2347d8fb588SMatthias Schmidt fdp = dp;
2357d8fb588SMatthias Schmidt dp = dp->di_next;
2367d8fb588SMatthias Schmidt if (fdp != &dhead)
2377d8fb588SMatthias Schmidt dfree(fdp);
2387d8fb588SMatthias Schmidt }
2397d8fb588SMatthias Schmidt dhead.di_next = dhead.di_prev = dp;
2407d8fb588SMatthias Schmidt dp->di_next = dp->di_prev = &dhead;
2417d8fb588SMatthias Schmidt }
2427d8fb588SMatthias Schmidt if ((dflag & DIR_LOAD) != 0)
2437d8fb588SMatthias Schmidt loaddirs(*v);
2447d8fb588SMatthias Schmidt else if ((dflag & DIR_SAVE) != 0)
2457d8fb588SMatthias Schmidt recdirs(*v, 1);
2467d8fb588SMatthias Schmidt
2477d8fb588SMatthias Schmidt if (*v && (dflag & (DIR_SAVE|DIR_LOAD)))
2487d8fb588SMatthias Schmidt v++;
2497d8fb588SMatthias Schmidt
2507d8fb588SMatthias Schmidt if (*v != NULL || (dflag & DIR_OLD))
2517d8fb588SMatthias Schmidt stderror(ERR_DIRUS, "dirs", flags, "");
2527d8fb588SMatthias Schmidt if ((dflag & (DIR_CLEAR|DIR_LOAD|DIR_SAVE)) == 0 || (dflag & DIR_PRINT))
2537d8fb588SMatthias Schmidt printdirs(dflag);
2547d8fb588SMatthias Schmidt }
2557d8fb588SMatthias Schmidt
2567d8fb588SMatthias Schmidt static void
printdirs(int dflag)2577d8fb588SMatthias Schmidt printdirs(int dflag)
2587d8fb588SMatthias Schmidt {
2597d8fb588SMatthias Schmidt struct directory *dp;
2607d8fb588SMatthias Schmidt Char *s, *user;
2617d8fb588SMatthias Schmidt int idx, len, cur;
2627d8fb588SMatthias Schmidt
2637d8fb588SMatthias Schmidt dp = dcwd;
2647d8fb588SMatthias Schmidt idx = 0;
2657d8fb588SMatthias Schmidt cur = 0;
2667d8fb588SMatthias Schmidt do {
2677d8fb588SMatthias Schmidt if (dp == &dhead)
2687d8fb588SMatthias Schmidt continue;
2697d8fb588SMatthias Schmidt if (dflag & DIR_VERT) {
2707d8fb588SMatthias Schmidt xprintf("%d\t", idx++);
2717d8fb588SMatthias Schmidt cur = 0;
2727d8fb588SMatthias Schmidt }
2737d8fb588SMatthias Schmidt s = dp->di_name;
2747d8fb588SMatthias Schmidt user = NULL;
2757d8fb588SMatthias Schmidt if (!(dflag & DIR_LONG) && (user = getusername(&s)) != NULL)
2767d8fb588SMatthias Schmidt len = (int) (Strlen(user) + Strlen(s) + 2);
2777d8fb588SMatthias Schmidt else
2787d8fb588SMatthias Schmidt len = (int) (Strlen(s) + 1);
2797d8fb588SMatthias Schmidt
2807d8fb588SMatthias Schmidt cur += len;
2817d8fb588SMatthias Schmidt if ((dflag & DIR_LINE) && cur >= TermH - 1 && len < TermH) {
2827d8fb588SMatthias Schmidt xputchar('\n');
2837d8fb588SMatthias Schmidt cur = len;
2847d8fb588SMatthias Schmidt }
2857d8fb588SMatthias Schmidt if (user)
286*d6ab524cSAntonio Huete Jimenez xprintf("~%" TCSH_S, user);
287*d6ab524cSAntonio Huete Jimenez xprintf("%-" TCSH_S "%c", s, (dflag & DIR_VERT) ? '\n' : ' ');
2887d8fb588SMatthias Schmidt } while ((dp = dp->di_prev) != dcwd);
2897d8fb588SMatthias Schmidt if (!(dflag & DIR_VERT))
2907d8fb588SMatthias Schmidt xputchar('\n');
2917d8fb588SMatthias Schmidt }
2927d8fb588SMatthias Schmidt
2937d8fb588SMatthias Schmidt void
dtildepr(Char * dir)2947d8fb588SMatthias Schmidt dtildepr(Char *dir)
2957d8fb588SMatthias Schmidt {
2967d8fb588SMatthias Schmidt Char* user;
2977d8fb588SMatthias Schmidt if ((user = getusername(&dir)) != NULL)
298*d6ab524cSAntonio Huete Jimenez xprintf("~%-" TCSH_S "%" TCSH_S, user, dir);
2997d8fb588SMatthias Schmidt else
300*d6ab524cSAntonio Huete Jimenez xprintf("%" TCSH_S, dir);
3017d8fb588SMatthias Schmidt }
3027d8fb588SMatthias Schmidt
3037d8fb588SMatthias Schmidt void
dtilde(void)3047d8fb588SMatthias Schmidt dtilde(void)
3057d8fb588SMatthias Schmidt {
3067d8fb588SMatthias Schmidt struct directory *d = dcwd;
3077d8fb588SMatthias Schmidt
3087d8fb588SMatthias Schmidt do {
3097d8fb588SMatthias Schmidt if (d == &dhead)
3107d8fb588SMatthias Schmidt continue;
311*d6ab524cSAntonio Huete Jimenez d->di_name = dcanon_internal(d->di_name, STRNULL);
3127d8fb588SMatthias Schmidt } while ((d = d->di_prev) != dcwd);
3137d8fb588SMatthias Schmidt
3147d8fb588SMatthias Schmidt dset(dcwd->di_name);
3157d8fb588SMatthias Schmidt }
3167d8fb588SMatthias Schmidt
3177d8fb588SMatthias Schmidt
3187d8fb588SMatthias Schmidt /* dnormalize():
3197d8fb588SMatthias Schmidt * The path will be normalized if it
3207d8fb588SMatthias Schmidt * 1) is "..",
3217d8fb588SMatthias Schmidt * 2) or starts with "../",
3227d8fb588SMatthias Schmidt * 3) or ends with "/..",
3237d8fb588SMatthias Schmidt * 4) or contains the string "/../",
3247d8fb588SMatthias Schmidt * then it will be normalized, unless those strings are quoted.
3257d8fb588SMatthias Schmidt * Otherwise, a copy is made and sent back.
3267d8fb588SMatthias Schmidt */
3277d8fb588SMatthias Schmidt Char *
dnormalize(const Char * cp,int expnd)3287d8fb588SMatthias Schmidt dnormalize(const Char *cp, int expnd)
3297d8fb588SMatthias Schmidt {
3307d8fb588SMatthias Schmidt
3317d8fb588SMatthias Schmidt /* return true if dp is of the form "../xxx" or "/../xxx" */
3327d8fb588SMatthias Schmidt #define IS_DOTDOT(sp, p) (ISDOTDOT(p) && ((p) == (sp) || *((p) - 1) == '/'))
3337d8fb588SMatthias Schmidt #define IS_DOT(sp, p) (ISDOT(p) && ((p) == (sp) || *((p) - 1) == '/'))
3347d8fb588SMatthias Schmidt
3357d8fb588SMatthias Schmidt #ifdef S_IFLNK
3367d8fb588SMatthias Schmidt if (expnd) {
3377d8fb588SMatthias Schmidt struct Strbuf buf = Strbuf_INIT;
3387d8fb588SMatthias Schmidt int dotdot = 0;
3397d8fb588SMatthias Schmidt Char *dp, *cwd;
3407d8fb588SMatthias Schmidt const Char *start = cp;
3417d8fb588SMatthias Schmidt # ifdef HAVE_SLASHSLASH
3427d8fb588SMatthias Schmidt int slashslash;
3437d8fb588SMatthias Schmidt # endif /* HAVE_SLASHSLASH */
3447d8fb588SMatthias Schmidt
3457d8fb588SMatthias Schmidt /*
3467d8fb588SMatthias Schmidt * count the number of "../xxx" or "xxx/../xxx" in the path
3477d8fb588SMatthias Schmidt */
3487d8fb588SMatthias Schmidt for ( ; *cp && *(cp + 1); cp++)
3497d8fb588SMatthias Schmidt if (IS_DOTDOT(start, cp))
3507d8fb588SMatthias Schmidt dotdot++;
3517d8fb588SMatthias Schmidt
3527d8fb588SMatthias Schmidt /*
3537d8fb588SMatthias Schmidt * if none, we are done.
3547d8fb588SMatthias Schmidt */
3557d8fb588SMatthias Schmidt if (dotdot == 0)
3567d8fb588SMatthias Schmidt return (Strsave(start));
3577d8fb588SMatthias Schmidt
3587d8fb588SMatthias Schmidt # ifdef notdef
3597d8fb588SMatthias Schmidt struct stat sb;
3607d8fb588SMatthias Schmidt /*
3617d8fb588SMatthias Schmidt * We disable this test because:
3627d8fb588SMatthias Schmidt * cd /tmp; mkdir dir1 dir2; cd dir2; ln -s /tmp/dir1; cd dir1;
3637d8fb588SMatthias Schmidt * echo ../../dir1 does not expand. We had enabled this before
3647d8fb588SMatthias Schmidt * because it was bothering people with expansions in compilation
3657d8fb588SMatthias Schmidt * lines like -I../../foo. Maybe we need some kind of finer grain
3667d8fb588SMatthias Schmidt * control?
3677d8fb588SMatthias Schmidt *
3687d8fb588SMatthias Schmidt * If the path doesn't exist, we are done too.
3697d8fb588SMatthias Schmidt */
3707d8fb588SMatthias Schmidt if (lstat(short2str(start), &sb) != 0 && errno == ENOENT)
3717d8fb588SMatthias Schmidt return (Strsave(start));
3727d8fb588SMatthias Schmidt # endif
3737d8fb588SMatthias Schmidt
3747d8fb588SMatthias Schmidt cwd = xmalloc((Strlen(dcwd->di_name) + 3) * sizeof(Char));
3757d8fb588SMatthias Schmidt (void) Strcpy(cwd, dcwd->di_name);
3767d8fb588SMatthias Schmidt
3777d8fb588SMatthias Schmidt /*
3787d8fb588SMatthias Schmidt * If the path starts with a slash, we are not relative to
3797d8fb588SMatthias Schmidt * the current working directory.
3807d8fb588SMatthias Schmidt */
3817d8fb588SMatthias Schmidt if (ABSOLUTEP(start))
3827d8fb588SMatthias Schmidt *cwd = '\0';
3837d8fb588SMatthias Schmidt # ifdef HAVE_SLASHSLASH
3847d8fb588SMatthias Schmidt slashslash = cwd[0] == '/' && cwd[1] == '/';
3857d8fb588SMatthias Schmidt # endif /* HAVE_SLASHSLASH */
3867d8fb588SMatthias Schmidt
3877d8fb588SMatthias Schmidt /*
3887d8fb588SMatthias Schmidt * Ignore . and count ..'s
3897d8fb588SMatthias Schmidt */
3907d8fb588SMatthias Schmidt cp = start;
3917d8fb588SMatthias Schmidt do {
3927d8fb588SMatthias Schmidt dotdot = 0;
3937d8fb588SMatthias Schmidt buf.len = 0;
3947d8fb588SMatthias Schmidt while (*cp)
3957d8fb588SMatthias Schmidt if (IS_DOT(start, cp)) {
3967d8fb588SMatthias Schmidt if (*++cp)
3977d8fb588SMatthias Schmidt cp++;
3987d8fb588SMatthias Schmidt }
3997d8fb588SMatthias Schmidt else if (IS_DOTDOT(start, cp)) {
4007d8fb588SMatthias Schmidt if (buf.len != 0)
4017d8fb588SMatthias Schmidt break; /* finish analyzing .././../xxx/[..] */
4027d8fb588SMatthias Schmidt dotdot++;
4037d8fb588SMatthias Schmidt cp += 2;
4047d8fb588SMatthias Schmidt if (*cp)
4057d8fb588SMatthias Schmidt cp++;
4067d8fb588SMatthias Schmidt }
4077d8fb588SMatthias Schmidt else
4087d8fb588SMatthias Schmidt Strbuf_append1(&buf, *cp++);
4097d8fb588SMatthias Schmidt
4107d8fb588SMatthias Schmidt Strbuf_terminate(&buf);
4117d8fb588SMatthias Schmidt while (dotdot > 0)
4127d8fb588SMatthias Schmidt if ((dp = Strrchr(cwd, '/')) != NULL) {
4137d8fb588SMatthias Schmidt # ifdef HAVE_SLASHSLASH
4147d8fb588SMatthias Schmidt if (dp == &cwd[1])
4157d8fb588SMatthias Schmidt slashslash = 1;
4167d8fb588SMatthias Schmidt # endif /* HAVE_SLASHSLASH */
4177d8fb588SMatthias Schmidt *dp = '\0';
4187d8fb588SMatthias Schmidt dotdot--;
4197d8fb588SMatthias Schmidt }
4207d8fb588SMatthias Schmidt else
4217d8fb588SMatthias Schmidt break;
4227d8fb588SMatthias Schmidt
4237d8fb588SMatthias Schmidt if (!*cwd) { /* too many ..'s, starts with "/" */
4247d8fb588SMatthias Schmidt cwd[0] = '/';
4257d8fb588SMatthias Schmidt # ifdef HAVE_SLASHSLASH
4267d8fb588SMatthias Schmidt /*
4277d8fb588SMatthias Schmidt * Only append another slash, if already the former cwd
4287d8fb588SMatthias Schmidt * was in a double-slash path.
4297d8fb588SMatthias Schmidt */
4307d8fb588SMatthias Schmidt cwd[1] = slashslash ? '/' : '\0';
4317d8fb588SMatthias Schmidt cwd[2] = '\0';
4327d8fb588SMatthias Schmidt # else /* !HAVE_SLASHSLASH */
4337d8fb588SMatthias Schmidt cwd[1] = '\0';
4347d8fb588SMatthias Schmidt # endif /* HAVE_SLASHSLASH */
4357d8fb588SMatthias Schmidt }
4367d8fb588SMatthias Schmidt # ifdef HAVE_SLASHSLASH
4377d8fb588SMatthias Schmidt else if (slashslash && cwd[1] == '\0') {
4387d8fb588SMatthias Schmidt cwd[1] = '/';
4397d8fb588SMatthias Schmidt cwd[2] = '\0';
4407d8fb588SMatthias Schmidt }
4417d8fb588SMatthias Schmidt # endif /* HAVE_SLASHSLASH */
4427d8fb588SMatthias Schmidt
4437d8fb588SMatthias Schmidt if (buf.len != 0) {
4447d8fb588SMatthias Schmidt size_t i;
4457d8fb588SMatthias Schmidt
4467d8fb588SMatthias Schmidt i = Strlen(cwd);
4477d8fb588SMatthias Schmidt if (TRM(cwd[i - 1]) != '/') {
4487d8fb588SMatthias Schmidt cwd[i++] = '/';
4497d8fb588SMatthias Schmidt cwd[i] = '\0';
4507d8fb588SMatthias Schmidt }
4517d8fb588SMatthias Schmidt dp = Strspl(cwd, TRM(buf.s[0]) == '/' ? &buf.s[1] : buf.s);
4527d8fb588SMatthias Schmidt xfree(cwd);
4537d8fb588SMatthias Schmidt cwd = dp;
4547d8fb588SMatthias Schmidt i = Strlen(cwd) - 1;
4557d8fb588SMatthias Schmidt if (TRM(cwd[i]) == '/')
4567d8fb588SMatthias Schmidt cwd[i] = '\0';
4577d8fb588SMatthias Schmidt }
4587d8fb588SMatthias Schmidt /* Reduction of ".." following the stuff we collected in buf
4597d8fb588SMatthias Schmidt * only makes sense if the directory item in buf really exists.
4607d8fb588SMatthias Schmidt * Avoid reduction of "-I../.." (typical compiler call) to ""
4617d8fb588SMatthias Schmidt * or "/usr/nonexistant/../bin" to "/usr/bin":
4627d8fb588SMatthias Schmidt */
4637d8fb588SMatthias Schmidt if (cwd[0]) {
4647d8fb588SMatthias Schmidt struct stat exists;
4657d8fb588SMatthias Schmidt if (0 != stat(short2str(cwd), &exists)) {
4667d8fb588SMatthias Schmidt xfree(buf.s);
4677d8fb588SMatthias Schmidt xfree(cwd);
4687d8fb588SMatthias Schmidt return Strsave(start);
4697d8fb588SMatthias Schmidt }
4707d8fb588SMatthias Schmidt }
4717d8fb588SMatthias Schmidt } while (*cp != '\0');
4727d8fb588SMatthias Schmidt xfree(buf.s);
4737d8fb588SMatthias Schmidt return cwd;
4747d8fb588SMatthias Schmidt }
4757d8fb588SMatthias Schmidt #endif /* S_IFLNK */
4767d8fb588SMatthias Schmidt return Strsave(cp);
4777d8fb588SMatthias Schmidt }
4787d8fb588SMatthias Schmidt
4797d8fb588SMatthias Schmidt
4807d8fb588SMatthias Schmidt /*
4817d8fb588SMatthias Schmidt * dochngd - implement chdir command.
4827d8fb588SMatthias Schmidt */
4837d8fb588SMatthias Schmidt /*ARGSUSED*/
4847d8fb588SMatthias Schmidt void
dochngd(Char ** v,struct command * c)4857d8fb588SMatthias Schmidt dochngd(Char **v, struct command *c)
4867d8fb588SMatthias Schmidt {
4877d8fb588SMatthias Schmidt Char *cp;
4887d8fb588SMatthias Schmidt struct directory *dp;
4897d8fb588SMatthias Schmidt int dflag = skipargs(&v, "plvn", "[-|<dir>]");
4907d8fb588SMatthias Schmidt
4917d8fb588SMatthias Schmidt USE(c);
4927d8fb588SMatthias Schmidt printd = 0;
4937d8fb588SMatthias Schmidt cp = (dflag & DIR_OLD) ? varval(STRowd) : *v;
4947d8fb588SMatthias Schmidt
4957d8fb588SMatthias Schmidt if (cp == NULL) {
49660962bbcSJohn Marino if (!cdtohome)
49760962bbcSJohn Marino stderror(ERR_NAME | ERR_TOOFEW);
49860962bbcSJohn Marino else if ((cp = varval(STRhome)) == STRNULL || *cp == 0)
4997d8fb588SMatthias Schmidt stderror(ERR_NAME | ERR_NOHOMEDIR);
5007d8fb588SMatthias Schmidt if (chdir(short2str(cp)) < 0)
5017d8fb588SMatthias Schmidt stderror(ERR_NAME | ERR_CANTCHANGE);
5027d8fb588SMatthias Schmidt cp = Strsave(cp);
5037d8fb588SMatthias Schmidt }
5047d8fb588SMatthias Schmidt else if ((dflag & DIR_OLD) == 0 && v[1] != NULL) {
5057d8fb588SMatthias Schmidt stderror(ERR_NAME | ERR_TOOMANY);
5067d8fb588SMatthias Schmidt /* NOTREACHED */
5077d8fb588SMatthias Schmidt return;
5087d8fb588SMatthias Schmidt }
5097d8fb588SMatthias Schmidt else if ((dp = dfind(cp)) != 0) {
5107d8fb588SMatthias Schmidt char *tmp;
5117d8fb588SMatthias Schmidt
5127d8fb588SMatthias Schmidt printd = 1;
5137d8fb588SMatthias Schmidt if (chdir(tmp = short2str(dp->di_name)) < 0)
5147d8fb588SMatthias Schmidt stderror(ERR_SYSTEM, tmp, strerror(errno));
5157d8fb588SMatthias Schmidt dcwd->di_prev->di_next = dcwd->di_next;
5167d8fb588SMatthias Schmidt dcwd->di_next->di_prev = dcwd->di_prev;
5177d8fb588SMatthias Schmidt dfree(dcwd);
5187d8fb588SMatthias Schmidt dnewcwd(dp, dflag);
5197d8fb588SMatthias Schmidt return;
5207d8fb588SMatthias Schmidt }
5217d8fb588SMatthias Schmidt else
52257e3f2b5SSimon 'corecode' Schubert if ((cp = dfollow(cp, dflag & DIR_OLD)) == NULL)
5237d8fb588SMatthias Schmidt return;
5247d8fb588SMatthias Schmidt dp = xcalloc(sizeof(struct directory), 1);
5257d8fb588SMatthias Schmidt dp->di_name = cp;
5267d8fb588SMatthias Schmidt dp->di_count = 0;
5277d8fb588SMatthias Schmidt dp->di_next = dcwd->di_next;
5287d8fb588SMatthias Schmidt dp->di_prev = dcwd->di_prev;
5297d8fb588SMatthias Schmidt dp->di_prev->di_next = dp;
5307d8fb588SMatthias Schmidt dp->di_next->di_prev = dp;
5317d8fb588SMatthias Schmidt dfree(dcwd);
5327d8fb588SMatthias Schmidt dnewcwd(dp, dflag);
5337d8fb588SMatthias Schmidt }
5347d8fb588SMatthias Schmidt
5357d8fb588SMatthias Schmidt static Char *
dgoto(Char * cp)5367d8fb588SMatthias Schmidt dgoto(Char *cp)
5377d8fb588SMatthias Schmidt {
5387d8fb588SMatthias Schmidt Char *dp, *ret;
5397d8fb588SMatthias Schmidt
5407d8fb588SMatthias Schmidt if (!ABSOLUTEP(cp))
5417d8fb588SMatthias Schmidt {
5427d8fb588SMatthias Schmidt Char *p, *q;
5437d8fb588SMatthias Schmidt size_t cwdlen;
5447d8fb588SMatthias Schmidt
5457d8fb588SMatthias Schmidt cwdlen = Strlen(dcwd->di_name);
5467d8fb588SMatthias Schmidt if (cwdlen == 1) /* root */
5477d8fb588SMatthias Schmidt cwdlen = 0;
5487d8fb588SMatthias Schmidt dp = xmalloc((cwdlen + Strlen(cp) + 2) * sizeof(Char));
5497d8fb588SMatthias Schmidt for (p = dp, q = dcwd->di_name; (*p++ = *q++) != '\0';)
5507d8fb588SMatthias Schmidt continue;
5517d8fb588SMatthias Schmidt if (cwdlen)
5527d8fb588SMatthias Schmidt p[-1] = '/';
5537d8fb588SMatthias Schmidt else
5547d8fb588SMatthias Schmidt p--; /* don't add a / after root */
5557d8fb588SMatthias Schmidt Strcpy(p, cp);
5567d8fb588SMatthias Schmidt xfree(cp);
5577d8fb588SMatthias Schmidt cp = dp;
5587d8fb588SMatthias Schmidt dp += cwdlen;
5597d8fb588SMatthias Schmidt }
5607d8fb588SMatthias Schmidt else
5617d8fb588SMatthias Schmidt dp = cp;
5627d8fb588SMatthias Schmidt
5637d8fb588SMatthias Schmidt #if defined(WINNT_NATIVE)
5647d8fb588SMatthias Schmidt return agetcwd();
5657d8fb588SMatthias Schmidt #elif defined(__CYGWIN__)
5667d8fb588SMatthias Schmidt if (ABSOLUTEP(cp) && cp[1] == ':') { /* Only DOS paths are treated that way */
5677d8fb588SMatthias Schmidt return agetcwd();
5687d8fb588SMatthias Schmidt } else {
5697d8fb588SMatthias Schmidt ret = dcanon(cp, dp);
5707d8fb588SMatthias Schmidt }
5717d8fb588SMatthias Schmidt #else /* !WINNT_NATIVE */
5727d8fb588SMatthias Schmidt ret = dcanon(cp, dp);
5737d8fb588SMatthias Schmidt #endif /* WINNT_NATIVE */
5747d8fb588SMatthias Schmidt return ret;
5757d8fb588SMatthias Schmidt }
5767d8fb588SMatthias Schmidt
5777d8fb588SMatthias Schmidt /*
5787d8fb588SMatthias Schmidt * dfollow - change to arg directory; fall back on cdpath if not valid
5797d8fb588SMatthias Schmidt */
5807d8fb588SMatthias Schmidt static Char *
dfollow(Char * cp,int old)58157e3f2b5SSimon 'corecode' Schubert dfollow(Char *cp, int old)
5827d8fb588SMatthias Schmidt {
5837d8fb588SMatthias Schmidt Char *dp;
5847d8fb588SMatthias Schmidt struct varent *c;
5857d8fb588SMatthias Schmidt int serrno;
5867d8fb588SMatthias Schmidt
58757e3f2b5SSimon 'corecode' Schubert cp = old ? Strsave(cp) : globone(cp, G_ERROR);
5887d8fb588SMatthias Schmidt cleanup_push(cp, xfree);
5897d8fb588SMatthias Schmidt #ifdef apollo
5907d8fb588SMatthias Schmidt if (Strchr(cp, '`')) {
5917d8fb588SMatthias Schmidt char *dptr;
5927d8fb588SMatthias Schmidt if (chdir(dptr = short2str(cp)) < 0)
5937d8fb588SMatthias Schmidt stderror(ERR_SYSTEM, dptr, strerror(errno));
5947d8fb588SMatthias Schmidt dp = agetcwd();
5957d8fb588SMatthias Schmidt cleanup_push(dp, xfree);
5967d8fb588SMatthias Schmidt if (dp != NULL) {
5977d8fb588SMatthias Schmidt cleanup_until(cp);
5987d8fb588SMatthias Schmidt return dgoto(dp);
5997d8fb588SMatthias Schmidt }
6007d8fb588SMatthias Schmidt else
6017d8fb588SMatthias Schmidt stderror(ERR_SYSTEM, dptr, strerror(errno));
6027d8fb588SMatthias Schmidt }
6037d8fb588SMatthias Schmidt #endif /* apollo */
6047d8fb588SMatthias Schmidt
6057d8fb588SMatthias Schmidt /*
6067d8fb588SMatthias Schmidt * if we are ignoring symlinks, try to fix relatives now.
6077d8fb588SMatthias Schmidt * if we are expading symlinks, it should be done by now.
6087d8fb588SMatthias Schmidt */
6097d8fb588SMatthias Schmidt dp = dnormalize(cp, symlinks == SYM_IGNORE);
6107d8fb588SMatthias Schmidt if (chdir(short2str(dp)) >= 0) {
6117d8fb588SMatthias Schmidt cleanup_until(cp);
6127d8fb588SMatthias Schmidt return dgoto(dp);
6137d8fb588SMatthias Schmidt }
6147d8fb588SMatthias Schmidt else {
6157d8fb588SMatthias Schmidt xfree(dp);
6167d8fb588SMatthias Schmidt if (chdir(short2str(cp)) >= 0) {
6177d8fb588SMatthias Schmidt cleanup_ignore(cp);
6187d8fb588SMatthias Schmidt cleanup_until(cp);
6197d8fb588SMatthias Schmidt return dgoto(cp);
6207d8fb588SMatthias Schmidt }
6217d8fb588SMatthias Schmidt else if (errno != ENOENT && errno != ENOTDIR) {
6227d8fb588SMatthias Schmidt int err;
6237d8fb588SMatthias Schmidt
6247d8fb588SMatthias Schmidt err = errno;
6257d8fb588SMatthias Schmidt stderror(ERR_SYSTEM, short2str(cp), strerror(err));
6267d8fb588SMatthias Schmidt }
6277d8fb588SMatthias Schmidt serrno = errno;
6287d8fb588SMatthias Schmidt }
6297d8fb588SMatthias Schmidt
6307d8fb588SMatthias Schmidt if (cp[0] != '/' && !prefix(STRdotsl, cp) && !prefix(STRdotdotsl, cp)
6317d8fb588SMatthias Schmidt && (c = adrof(STRcdpath)) && c->vec != NULL) {
6327d8fb588SMatthias Schmidt struct Strbuf buf = Strbuf_INIT;
6337d8fb588SMatthias Schmidt Char **cdp;
6347d8fb588SMatthias Schmidt
6357d8fb588SMatthias Schmidt for (cdp = c->vec; *cdp; cdp++) {
63694afa86dSJohn Marino size_t len = Strlen(*cdp);
6377d8fb588SMatthias Schmidt buf.len = 0;
63894afa86dSJohn Marino if (len > 0) {
6397d8fb588SMatthias Schmidt Strbuf_append(&buf, *cdp);
64094afa86dSJohn Marino if ((*cdp)[len - 1] != '/')
6417d8fb588SMatthias Schmidt Strbuf_append1(&buf, '/');
64294afa86dSJohn Marino }
6437d8fb588SMatthias Schmidt Strbuf_append(&buf, cp);
6447d8fb588SMatthias Schmidt Strbuf_terminate(&buf);
6457d8fb588SMatthias Schmidt /*
6467d8fb588SMatthias Schmidt * We always want to fix the directory here
6477d8fb588SMatthias Schmidt * If we are normalizing symlinks
6487d8fb588SMatthias Schmidt */
6497d8fb588SMatthias Schmidt dp = dnormalize(buf.s, symlinks == SYM_IGNORE ||
6507d8fb588SMatthias Schmidt symlinks == SYM_EXPAND);
6517d8fb588SMatthias Schmidt if (chdir(short2str(dp)) >= 0) {
6527d8fb588SMatthias Schmidt printd = 1;
6537d8fb588SMatthias Schmidt xfree(buf.s);
6547d8fb588SMatthias Schmidt cleanup_until(cp);
6557d8fb588SMatthias Schmidt return dgoto(dp);
6567d8fb588SMatthias Schmidt }
6577d8fb588SMatthias Schmidt else if (chdir(short2str(cp)) >= 0) {
6587d8fb588SMatthias Schmidt printd = 1;
6597d8fb588SMatthias Schmidt xfree(dp);
6607d8fb588SMatthias Schmidt xfree(buf.s);
6617d8fb588SMatthias Schmidt cleanup_ignore(cp);
6627d8fb588SMatthias Schmidt cleanup_until(cp);
6637d8fb588SMatthias Schmidt return dgoto(cp);
6647d8fb588SMatthias Schmidt }
665653fab9eSSascha Wildner xfree(dp);
6667d8fb588SMatthias Schmidt }
6677d8fb588SMatthias Schmidt xfree(buf.s);
6687d8fb588SMatthias Schmidt }
6697d8fb588SMatthias Schmidt dp = varval(cp);
6707d8fb588SMatthias Schmidt if ((dp[0] == '/' || dp[0] == '.') && chdir(short2str(dp)) >= 0) {
6717d8fb588SMatthias Schmidt cleanup_until(cp);
6727d8fb588SMatthias Schmidt cp = Strsave(dp);
6737d8fb588SMatthias Schmidt printd = 1;
6747d8fb588SMatthias Schmidt return dgoto(cp);
6757d8fb588SMatthias Schmidt }
6767d8fb588SMatthias Schmidt /*
6777d8fb588SMatthias Schmidt * on login source of ~/.cshdirs, errors are eaten. the dir stack is all
6787d8fb588SMatthias Schmidt * directories we could get to.
6797d8fb588SMatthias Schmidt */
6807d8fb588SMatthias Schmidt if (!bequiet)
6817d8fb588SMatthias Schmidt stderror(ERR_SYSTEM, short2str(cp), strerror(serrno));
6827d8fb588SMatthias Schmidt cleanup_until(cp);
6837d8fb588SMatthias Schmidt return (NULL);
6847d8fb588SMatthias Schmidt }
6857d8fb588SMatthias Schmidt
6867d8fb588SMatthias Schmidt
6877d8fb588SMatthias Schmidt /*
6887d8fb588SMatthias Schmidt * dopushd - push new directory onto directory stack.
6897d8fb588SMatthias Schmidt * with no arguments exchange top and second.
6907d8fb588SMatthias Schmidt * with numeric argument (+n) bring it to top.
6917d8fb588SMatthias Schmidt */
6927d8fb588SMatthias Schmidt /*ARGSUSED*/
6937d8fb588SMatthias Schmidt void
dopushd(Char ** v,struct command * c)6947d8fb588SMatthias Schmidt dopushd(Char **v, struct command *c)
6957d8fb588SMatthias Schmidt {
6967d8fb588SMatthias Schmidt struct directory *dp;
6977d8fb588SMatthias Schmidt Char *cp;
6987d8fb588SMatthias Schmidt int dflag = skipargs(&v, "plvn", " [-|<dir>|+<n>]");
6997d8fb588SMatthias Schmidt
7007d8fb588SMatthias Schmidt USE(c);
7017d8fb588SMatthias Schmidt printd = 1;
7027d8fb588SMatthias Schmidt cp = (dflag & DIR_OLD) ? varval(STRowd) : *v;
7037d8fb588SMatthias Schmidt
7047d8fb588SMatthias Schmidt if (cp == NULL) {
7057d8fb588SMatthias Schmidt if (adrof(STRpushdtohome)) {
7067d8fb588SMatthias Schmidt if ((cp = varval(STRhome)) == STRNULL || *cp == 0)
7077d8fb588SMatthias Schmidt stderror(ERR_NAME | ERR_NOHOMEDIR);
7087d8fb588SMatthias Schmidt if (chdir(short2str(cp)) < 0)
7097d8fb588SMatthias Schmidt stderror(ERR_NAME | ERR_CANTCHANGE);
71057e3f2b5SSimon 'corecode' Schubert if ((cp = dfollow(cp, dflag & DIR_OLD)) == NULL)
7117d8fb588SMatthias Schmidt return;
7127d8fb588SMatthias Schmidt dp = xcalloc(sizeof(struct directory), 1);
7137d8fb588SMatthias Schmidt dp->di_name = cp;
7147d8fb588SMatthias Schmidt dp->di_count = 0;
7157d8fb588SMatthias Schmidt dp->di_prev = dcwd;
7167d8fb588SMatthias Schmidt dp->di_next = dcwd->di_next;
7177d8fb588SMatthias Schmidt dcwd->di_next = dp;
7187d8fb588SMatthias Schmidt dp->di_next->di_prev = dp;
7197d8fb588SMatthias Schmidt }
7207d8fb588SMatthias Schmidt else {
7217d8fb588SMatthias Schmidt char *tmp;
7227d8fb588SMatthias Schmidt
7237d8fb588SMatthias Schmidt if ((dp = dcwd->di_prev) == &dhead)
7247d8fb588SMatthias Schmidt dp = dhead.di_prev;
7257d8fb588SMatthias Schmidt if (dp == dcwd)
7267d8fb588SMatthias Schmidt stderror(ERR_NAME | ERR_NODIR);
7277d8fb588SMatthias Schmidt if (chdir(tmp = short2str(dp->di_name)) < 0)
7287d8fb588SMatthias Schmidt stderror(ERR_SYSTEM, tmp, strerror(errno));
7297d8fb588SMatthias Schmidt dp->di_prev->di_next = dp->di_next;
7307d8fb588SMatthias Schmidt dp->di_next->di_prev = dp->di_prev;
7317d8fb588SMatthias Schmidt dp->di_next = dcwd->di_next;
7327d8fb588SMatthias Schmidt dp->di_prev = dcwd;
7337d8fb588SMatthias Schmidt dcwd->di_next->di_prev = dp;
7347d8fb588SMatthias Schmidt dcwd->di_next = dp;
7357d8fb588SMatthias Schmidt }
7367d8fb588SMatthias Schmidt }
7377d8fb588SMatthias Schmidt else if ((dflag & DIR_OLD) == 0 && v[1] != NULL) {
7387d8fb588SMatthias Schmidt stderror(ERR_NAME | ERR_TOOMANY);
7397d8fb588SMatthias Schmidt /* NOTREACHED */
7407d8fb588SMatthias Schmidt return;
7417d8fb588SMatthias Schmidt }
7427d8fb588SMatthias Schmidt else if ((dp = dfind(cp)) != NULL) {
7437d8fb588SMatthias Schmidt char *tmp;
7447d8fb588SMatthias Schmidt
7457d8fb588SMatthias Schmidt if (chdir(tmp = short2str(dp->di_name)) < 0)
7467d8fb588SMatthias Schmidt stderror(ERR_SYSTEM, tmp, strerror(errno));
7477d8fb588SMatthias Schmidt /*
7487d8fb588SMatthias Schmidt * kfk - 10 Feb 1984 - added new "extraction style" pushd +n
7497d8fb588SMatthias Schmidt */
7507d8fb588SMatthias Schmidt if (adrof(STRdextract))
7517d8fb588SMatthias Schmidt dextract(dp);
7527d8fb588SMatthias Schmidt }
7537d8fb588SMatthias Schmidt else {
7547d8fb588SMatthias Schmidt Char *ccp;
7557d8fb588SMatthias Schmidt
75657e3f2b5SSimon 'corecode' Schubert if ((ccp = dfollow(cp, dflag & DIR_OLD)) == NULL)
7577d8fb588SMatthias Schmidt return;
7587d8fb588SMatthias Schmidt dp = xcalloc(sizeof(struct directory), 1);
7597d8fb588SMatthias Schmidt dp->di_name = ccp;
7607d8fb588SMatthias Schmidt dp->di_count = 0;
7617d8fb588SMatthias Schmidt dp->di_prev = dcwd;
7627d8fb588SMatthias Schmidt dp->di_next = dcwd->di_next;
7637d8fb588SMatthias Schmidt dcwd->di_next = dp;
7647d8fb588SMatthias Schmidt dp->di_next->di_prev = dp;
7657d8fb588SMatthias Schmidt }
7667d8fb588SMatthias Schmidt dnewcwd(dp, dflag);
7677d8fb588SMatthias Schmidt }
7687d8fb588SMatthias Schmidt
7697d8fb588SMatthias Schmidt /*
7707d8fb588SMatthias Schmidt * dfind - find a directory if specified by numeric (+n) argument
7717d8fb588SMatthias Schmidt */
7727d8fb588SMatthias Schmidt static struct directory *
dfind(Char * cp)7737d8fb588SMatthias Schmidt dfind(Char *cp)
7747d8fb588SMatthias Schmidt {
7757d8fb588SMatthias Schmidt struct directory *dp;
7767d8fb588SMatthias Schmidt int i;
7777d8fb588SMatthias Schmidt Char *ep;
7787d8fb588SMatthias Schmidt
7797d8fb588SMatthias Schmidt if (*cp++ != '+')
7807d8fb588SMatthias Schmidt return (0);
7817d8fb588SMatthias Schmidt for (ep = cp; Isdigit(*ep); ep++)
7827d8fb588SMatthias Schmidt continue;
7837d8fb588SMatthias Schmidt if (*ep)
7847d8fb588SMatthias Schmidt return (0);
7857d8fb588SMatthias Schmidt i = getn(cp);
7867d8fb588SMatthias Schmidt if (i <= 0)
7877d8fb588SMatthias Schmidt return (0);
7887d8fb588SMatthias Schmidt for (dp = dcwd; i != 0; i--) {
7897d8fb588SMatthias Schmidt if ((dp = dp->di_prev) == &dhead)
7907d8fb588SMatthias Schmidt dp = dp->di_prev;
7917d8fb588SMatthias Schmidt if (dp == dcwd)
7927d8fb588SMatthias Schmidt stderror(ERR_NAME | ERR_DEEP);
7937d8fb588SMatthias Schmidt }
7947d8fb588SMatthias Schmidt return (dp);
7957d8fb588SMatthias Schmidt }
7967d8fb588SMatthias Schmidt
7977d8fb588SMatthias Schmidt /*
7987d8fb588SMatthias Schmidt * dopopd - pop a directory out of the directory stack
7997d8fb588SMatthias Schmidt * with a numeric argument just discard it.
8007d8fb588SMatthias Schmidt */
8017d8fb588SMatthias Schmidt /*ARGSUSED*/
8027d8fb588SMatthias Schmidt void
dopopd(Char ** v,struct command * c)8037d8fb588SMatthias Schmidt dopopd(Char **v, struct command *c)
8047d8fb588SMatthias Schmidt {
8057d8fb588SMatthias Schmidt Char *cp;
8067d8fb588SMatthias Schmidt struct directory *dp, *p = NULL;
8077d8fb588SMatthias Schmidt int dflag = skipargs(&v, "plvn", " [-|+<n>]");
8087d8fb588SMatthias Schmidt
8097d8fb588SMatthias Schmidt USE(c);
8107d8fb588SMatthias Schmidt printd = 1;
8117d8fb588SMatthias Schmidt cp = (dflag & DIR_OLD) ? varval(STRowd) : *v;
8127d8fb588SMatthias Schmidt
8137d8fb588SMatthias Schmidt if (cp == NULL)
8147d8fb588SMatthias Schmidt dp = dcwd;
8157d8fb588SMatthias Schmidt else if ((dflag & DIR_OLD) == 0 && v[1] != NULL) {
8167d8fb588SMatthias Schmidt stderror(ERR_NAME | ERR_TOOMANY);
8177d8fb588SMatthias Schmidt /* NOTREACHED */
8187d8fb588SMatthias Schmidt return;
8197d8fb588SMatthias Schmidt }
8207d8fb588SMatthias Schmidt else if ((dp = dfind(cp)) == 0)
8217d8fb588SMatthias Schmidt stderror(ERR_NAME | ERR_BADDIR);
8227d8fb588SMatthias Schmidt if (dp->di_prev == &dhead && dp->di_next == &dhead)
8237d8fb588SMatthias Schmidt stderror(ERR_NAME | ERR_EMPTY);
8247d8fb588SMatthias Schmidt if (dp == dcwd) {
8257d8fb588SMatthias Schmidt char *tmp;
8267d8fb588SMatthias Schmidt
8277d8fb588SMatthias Schmidt if ((p = dp->di_prev) == &dhead)
8287d8fb588SMatthias Schmidt p = dhead.di_prev;
8297d8fb588SMatthias Schmidt if (chdir(tmp = short2str(p->di_name)) < 0)
8307d8fb588SMatthias Schmidt stderror(ERR_SYSTEM, tmp, strerror(errno));
8317d8fb588SMatthias Schmidt }
8327d8fb588SMatthias Schmidt dp->di_prev->di_next = dp->di_next;
8337d8fb588SMatthias Schmidt dp->di_next->di_prev = dp->di_prev;
8347d8fb588SMatthias Schmidt dfree(dp);
8357d8fb588SMatthias Schmidt if (dp == dcwd) {
8367d8fb588SMatthias Schmidt dnewcwd(p, dflag);
8377d8fb588SMatthias Schmidt }
8387d8fb588SMatthias Schmidt else {
8397d8fb588SMatthias Schmidt printdirs(dflag);
8407d8fb588SMatthias Schmidt }
8417d8fb588SMatthias Schmidt }
8427d8fb588SMatthias Schmidt
8437d8fb588SMatthias Schmidt /*
8447d8fb588SMatthias Schmidt * dfree - free the directory (or keep it if it still has ref count)
8457d8fb588SMatthias Schmidt */
8467d8fb588SMatthias Schmidt void
dfree(struct directory * dp)8477d8fb588SMatthias Schmidt dfree(struct directory *dp)
8487d8fb588SMatthias Schmidt {
8497d8fb588SMatthias Schmidt
8507d8fb588SMatthias Schmidt if (dp->di_count != 0) {
8517d8fb588SMatthias Schmidt dp->di_next = dp->di_prev = 0;
8527d8fb588SMatthias Schmidt }
8537d8fb588SMatthias Schmidt else {
8547d8fb588SMatthias Schmidt xfree(dp->di_name);
8557d8fb588SMatthias Schmidt xfree(dp);
8567d8fb588SMatthias Schmidt }
8577d8fb588SMatthias Schmidt }
8587d8fb588SMatthias Schmidt
8597d8fb588SMatthias Schmidt /*
860*d6ab524cSAntonio Huete Jimenez * dcanon - a safe version of dcanon_internal that arranges for cleanup
8617d8fb588SMatthias Schmidt */
8627d8fb588SMatthias Schmidt Char *
dcanon(Char * cp,Char * p)8637d8fb588SMatthias Schmidt dcanon(Char *cp, Char *p)
8647d8fb588SMatthias Schmidt {
865*d6ab524cSAntonio Huete Jimenez cleanup_push(cp, xfree);
866*d6ab524cSAntonio Huete Jimenez p = dcanon_internal(cp, p);
867*d6ab524cSAntonio Huete Jimenez // coverity[use_after_free] we use the pointer as a marker
868*d6ab524cSAntonio Huete Jimenez cleanup_ignore(cp);
869*d6ab524cSAntonio Huete Jimenez cleanup_until(cp);
870*d6ab524cSAntonio Huete Jimenez return p;
871*d6ab524cSAntonio Huete Jimenez }
872*d6ab524cSAntonio Huete Jimenez
873*d6ab524cSAntonio Huete Jimenez /*
874*d6ab524cSAntonio Huete Jimenez * dcanon_internal - canonicalize the pathname, removing excess ./ and ../ etc.
875*d6ab524cSAntonio Huete Jimenez * we are of course assuming that the file system is standardly
876*d6ab524cSAntonio Huete Jimenez * constructed (always have ..'s, directories have links)
877*d6ab524cSAntonio Huete Jimenez */
878*d6ab524cSAntonio Huete Jimenez static Char *
dcanon_internal(Char * cp,Char * p)879*d6ab524cSAntonio Huete Jimenez dcanon_internal(Char *cp, Char *p)
880*d6ab524cSAntonio Huete Jimenez {
8817d8fb588SMatthias Schmidt Char *sp;
8827d8fb588SMatthias Schmidt Char *p1, *p2; /* general purpose */
8837d8fb588SMatthias Schmidt int slash;
8847d8fb588SMatthias Schmidt #ifdef HAVE_SLASHSLASH
8857d8fb588SMatthias Schmidt int slashslash;
8867d8fb588SMatthias Schmidt #endif /* HAVE_SLASHSLASH */
8877d8fb588SMatthias Schmidt size_t clen;
8887d8fb588SMatthias Schmidt
8897d8fb588SMatthias Schmidt #ifdef S_IFLNK /* if we have symlinks */
8907d8fb588SMatthias Schmidt Char *mlink, *newcp;
8917d8fb588SMatthias Schmidt char *tlink;
8927d8fb588SMatthias Schmidt size_t cc;
8937d8fb588SMatthias Schmidt #endif /* S_IFLNK */
8947d8fb588SMatthias Schmidt
8957d8fb588SMatthias Schmidt clen = Strlen(cp);
8967d8fb588SMatthias Schmidt
8977d8fb588SMatthias Schmidt /*
8987d8fb588SMatthias Schmidt * christos: if the path given does not start with a slash prepend cwd. If
8997d8fb588SMatthias Schmidt * cwd does not start with a slash or the result would be too long try to
9007d8fb588SMatthias Schmidt * correct it.
9017d8fb588SMatthias Schmidt */
9027d8fb588SMatthias Schmidt if (!ABSOLUTEP(cp)) {
9037d8fb588SMatthias Schmidt Char *tmpdir;
9047d8fb588SMatthias Schmidt size_t len;
9057d8fb588SMatthias Schmidt
9067d8fb588SMatthias Schmidt p1 = varval(STRcwd);
9077d8fb588SMatthias Schmidt if (p1 == STRNULL || !ABSOLUTEP(p1)) {
9087d8fb588SMatthias Schmidt Char *new_cwd = agetcwd();
9097d8fb588SMatthias Schmidt
9107d8fb588SMatthias Schmidt if (new_cwd == NULL) {
9117d8fb588SMatthias Schmidt xprintf("%s: %s\n", progname, strerror(errno));
9127d8fb588SMatthias Schmidt setcopy(STRcwd, str2short("/"), VAR_READWRITE|VAR_NOGLOB);
9137d8fb588SMatthias Schmidt }
9147d8fb588SMatthias Schmidt else
9157d8fb588SMatthias Schmidt setv(STRcwd, new_cwd, VAR_READWRITE|VAR_NOGLOB);
9167d8fb588SMatthias Schmidt p1 = varval(STRcwd);
9177d8fb588SMatthias Schmidt }
9187d8fb588SMatthias Schmidt len = Strlen(p1);
9197d8fb588SMatthias Schmidt tmpdir = xmalloc((len + clen + 2) * sizeof (*tmpdir));
9207d8fb588SMatthias Schmidt (void) Strcpy(tmpdir, p1);
9217d8fb588SMatthias Schmidt (void) Strcat(tmpdir, STRslash);
9227d8fb588SMatthias Schmidt (void) Strcat(tmpdir, cp);
9237d8fb588SMatthias Schmidt xfree(cp);
9247d8fb588SMatthias Schmidt cp = p = tmpdir;
9257d8fb588SMatthias Schmidt }
9267d8fb588SMatthias Schmidt
9277d8fb588SMatthias Schmidt #ifdef HAVE_SLASHSLASH
9287d8fb588SMatthias Schmidt slashslash = (cp[0] == '/' && cp[1] == '/');
9297d8fb588SMatthias Schmidt #endif /* HAVE_SLASHSLASH */
9307d8fb588SMatthias Schmidt
9317d8fb588SMatthias Schmidt while (*p) { /* for each component */
9327d8fb588SMatthias Schmidt sp = p; /* save slash address */
9337d8fb588SMatthias Schmidt while (*++p == '/') /* flush extra slashes */
9347d8fb588SMatthias Schmidt continue;
9357d8fb588SMatthias Schmidt if (p != ++sp)
9367d8fb588SMatthias Schmidt for (p1 = sp, p2 = p; (*p1++ = *p2++) != '\0';)
9377d8fb588SMatthias Schmidt continue;
9387d8fb588SMatthias Schmidt p = sp; /* save start of component */
9397d8fb588SMatthias Schmidt slash = 0;
9407d8fb588SMatthias Schmidt if (*p)
9417d8fb588SMatthias Schmidt while (*++p) /* find next slash or end of path */
9427d8fb588SMatthias Schmidt if (*p == '/') {
9437d8fb588SMatthias Schmidt slash = 1;
9447d8fb588SMatthias Schmidt *p = 0;
9457d8fb588SMatthias Schmidt break;
9467d8fb588SMatthias Schmidt }
9477d8fb588SMatthias Schmidt
9487d8fb588SMatthias Schmidt #ifdef HAVE_SLASHSLASH
9497d8fb588SMatthias Schmidt if (&cp[1] == sp && sp[0] == '.' && sp[1] == '.' && sp[2] == '\0')
9507d8fb588SMatthias Schmidt slashslash = 1;
9517d8fb588SMatthias Schmidt #endif /* HAVE_SLASHSLASH */
9527d8fb588SMatthias Schmidt if (*sp == '\0') { /* if component is null */
9537d8fb588SMatthias Schmidt if (--sp == cp) /* if path is one char (i.e. /) */
9547d8fb588SMatthias Schmidt break;
9557d8fb588SMatthias Schmidt else
9567d8fb588SMatthias Schmidt *sp = '\0';
9577d8fb588SMatthias Schmidt }
9587d8fb588SMatthias Schmidt else if (sp[0] == '.' && sp[1] == 0) {
9597d8fb588SMatthias Schmidt if (slash) {
9607d8fb588SMatthias Schmidt for (p1 = sp, p2 = p + 1; (*p1++ = *p2++) != '\0';)
9617d8fb588SMatthias Schmidt continue;
9627d8fb588SMatthias Schmidt p = --sp;
9637d8fb588SMatthias Schmidt }
9647d8fb588SMatthias Schmidt else if (--sp != cp)
9657d8fb588SMatthias Schmidt *sp = '\0';
9667d8fb588SMatthias Schmidt else
9677d8fb588SMatthias Schmidt sp[1] = '\0';
9687d8fb588SMatthias Schmidt }
9697d8fb588SMatthias Schmidt else if (sp[0] == '.' && sp[1] == '.' && sp[2] == 0) {
9707d8fb588SMatthias Schmidt /*
9717d8fb588SMatthias Schmidt * We have something like "yyy/xxx/..", where "yyy" can be null or
9727d8fb588SMatthias Schmidt * a path starting at /, and "xxx" is a single component. Before
9737d8fb588SMatthias Schmidt * compressing "xxx/..", we want to expand "yyy/xxx", if it is a
9747d8fb588SMatthias Schmidt * symbolic link.
9757d8fb588SMatthias Schmidt */
9767d8fb588SMatthias Schmidt *--sp = 0; /* form the pathname for readlink */
9777d8fb588SMatthias Schmidt #ifdef S_IFLNK /* if we have symlinks */
9787d8fb588SMatthias Schmidt if (sp != cp && /* symlinks != SYM_IGNORE && */
9797d8fb588SMatthias Schmidt (tlink = areadlink(short2str(cp))) != NULL) {
9807d8fb588SMatthias Schmidt mlink = str2short(tlink);
9817d8fb588SMatthias Schmidt xfree(tlink);
9827d8fb588SMatthias Schmidt
9837d8fb588SMatthias Schmidt if (slash)
9847d8fb588SMatthias Schmidt *p = '/';
9857d8fb588SMatthias Schmidt /*
9867d8fb588SMatthias Schmidt * Point p to the '/' in "/..", and restore the '/'.
9877d8fb588SMatthias Schmidt */
9887d8fb588SMatthias Schmidt *(p = sp) = '/';
9897d8fb588SMatthias Schmidt if (*mlink != '/') {
9907d8fb588SMatthias Schmidt /*
9917d8fb588SMatthias Schmidt * Relative path, expand it between the "yyy/" and the
9927d8fb588SMatthias Schmidt * "/..". First, back sp up to the character past "yyy/".
9937d8fb588SMatthias Schmidt */
9947d8fb588SMatthias Schmidt while (*--sp != '/')
9957d8fb588SMatthias Schmidt continue;
9967d8fb588SMatthias Schmidt sp++;
9977d8fb588SMatthias Schmidt *sp = 0;
9987d8fb588SMatthias Schmidt /*
9997d8fb588SMatthias Schmidt * New length is "yyy/" + mlink + "/.." and rest
10007d8fb588SMatthias Schmidt */
10017d8fb588SMatthias Schmidt p1 = newcp = xmalloc(((sp - cp) + Strlen(mlink) +
10027d8fb588SMatthias Schmidt Strlen(p) + 1) * sizeof(Char));
10037d8fb588SMatthias Schmidt /*
10047d8fb588SMatthias Schmidt * Copy new path into newcp
10057d8fb588SMatthias Schmidt */
10067d8fb588SMatthias Schmidt for (p2 = cp; (*p1++ = *p2++) != '\0';)
10077d8fb588SMatthias Schmidt continue;
10087d8fb588SMatthias Schmidt for (p1--, p2 = mlink; (*p1++ = *p2++) != '\0';)
10097d8fb588SMatthias Schmidt continue;
10107d8fb588SMatthias Schmidt for (p1--, p2 = p; (*p1++ = *p2++) != '\0';)
10117d8fb588SMatthias Schmidt continue;
10127d8fb588SMatthias Schmidt /*
10137d8fb588SMatthias Schmidt * Restart canonicalization at expanded "/xxx".
10147d8fb588SMatthias Schmidt */
10157d8fb588SMatthias Schmidt p = sp - cp - 1 + newcp;
10167d8fb588SMatthias Schmidt }
10177d8fb588SMatthias Schmidt else {
10187d8fb588SMatthias Schmidt newcp = Strspl(mlink, p);
10197d8fb588SMatthias Schmidt /*
10207d8fb588SMatthias Schmidt * Restart canonicalization at beginning
10217d8fb588SMatthias Schmidt */
10227d8fb588SMatthias Schmidt p = newcp;
10237d8fb588SMatthias Schmidt }
10247d8fb588SMatthias Schmidt xfree(cp);
10257d8fb588SMatthias Schmidt cp = newcp;
10267d8fb588SMatthias Schmidt #ifdef HAVE_SLASHSLASH
10277d8fb588SMatthias Schmidt slashslash = (cp[0] == '/' && cp[1] == '/');
10287d8fb588SMatthias Schmidt #endif /* HAVE_SLASHSLASH */
10297d8fb588SMatthias Schmidt continue; /* canonicalize the link */
10307d8fb588SMatthias Schmidt }
10317d8fb588SMatthias Schmidt #endif /* S_IFLNK */
10327d8fb588SMatthias Schmidt *sp = '/';
10337d8fb588SMatthias Schmidt if (sp != cp)
10347d8fb588SMatthias Schmidt while (*--sp != '/')
10357d8fb588SMatthias Schmidt continue;
10367d8fb588SMatthias Schmidt if (slash) {
10377d8fb588SMatthias Schmidt for (p1 = sp + 1, p2 = p + 1; (*p1++ = *p2++) != '\0';)
10387d8fb588SMatthias Schmidt continue;
10397d8fb588SMatthias Schmidt p = sp;
10407d8fb588SMatthias Schmidt }
10417d8fb588SMatthias Schmidt else if (cp == sp)
10427d8fb588SMatthias Schmidt *++sp = '\0';
10437d8fb588SMatthias Schmidt else
10447d8fb588SMatthias Schmidt *sp = '\0';
10457d8fb588SMatthias Schmidt }
10467d8fb588SMatthias Schmidt else { /* normal dir name (not . or .. or nothing) */
10477d8fb588SMatthias Schmidt
10487d8fb588SMatthias Schmidt #ifdef S_IFLNK /* if we have symlinks */
10497d8fb588SMatthias Schmidt if (sp != cp && symlinks == SYM_CHASE &&
10507d8fb588SMatthias Schmidt (tlink = areadlink(short2str(cp))) != NULL) {
10517d8fb588SMatthias Schmidt mlink = str2short(tlink);
10527d8fb588SMatthias Schmidt xfree(tlink);
10537d8fb588SMatthias Schmidt
10547d8fb588SMatthias Schmidt /*
10557d8fb588SMatthias Schmidt * restore the '/'.
10567d8fb588SMatthias Schmidt */
10577d8fb588SMatthias Schmidt if (slash)
10587d8fb588SMatthias Schmidt *p = '/';
10597d8fb588SMatthias Schmidt
10607d8fb588SMatthias Schmidt /*
10617d8fb588SMatthias Schmidt * point sp to p (rather than backing up).
10627d8fb588SMatthias Schmidt */
10637d8fb588SMatthias Schmidt sp = p;
10647d8fb588SMatthias Schmidt
10657d8fb588SMatthias Schmidt if (*mlink != '/') {
10667d8fb588SMatthias Schmidt /*
10677d8fb588SMatthias Schmidt * Relative path, expand it between the "yyy/" and the
10687d8fb588SMatthias Schmidt * remainder. First, back sp up to the character past
10697d8fb588SMatthias Schmidt * "yyy/".
10707d8fb588SMatthias Schmidt */
10717d8fb588SMatthias Schmidt while (*--sp != '/')
10727d8fb588SMatthias Schmidt continue;
10737d8fb588SMatthias Schmidt sp++;
10747d8fb588SMatthias Schmidt *sp = 0;
10757d8fb588SMatthias Schmidt /*
10767d8fb588SMatthias Schmidt * New length is "yyy/" + mlink + "/.." and rest
10777d8fb588SMatthias Schmidt */
10787d8fb588SMatthias Schmidt p1 = newcp = xmalloc(((sp - cp) + Strlen(mlink) +
10797d8fb588SMatthias Schmidt Strlen(p) + 1) * sizeof(Char));
10807d8fb588SMatthias Schmidt /*
10817d8fb588SMatthias Schmidt * Copy new path into newcp
10827d8fb588SMatthias Schmidt */
10837d8fb588SMatthias Schmidt for (p2 = cp; (*p1++ = *p2++) != '\0';)
10847d8fb588SMatthias Schmidt continue;
10857d8fb588SMatthias Schmidt for (p1--, p2 = mlink; (*p1++ = *p2++) != '\0';)
10867d8fb588SMatthias Schmidt continue;
10877d8fb588SMatthias Schmidt for (p1--, p2 = p; (*p1++ = *p2++) != '\0';)
10887d8fb588SMatthias Schmidt continue;
10897d8fb588SMatthias Schmidt /*
10907d8fb588SMatthias Schmidt * Restart canonicalization at expanded "/xxx".
10917d8fb588SMatthias Schmidt */
10927d8fb588SMatthias Schmidt p = sp - cp - 1 + newcp;
10937d8fb588SMatthias Schmidt }
10947d8fb588SMatthias Schmidt else {
10957d8fb588SMatthias Schmidt newcp = Strspl(mlink, p);
10967d8fb588SMatthias Schmidt /*
10977d8fb588SMatthias Schmidt * Restart canonicalization at beginning
10987d8fb588SMatthias Schmidt */
10997d8fb588SMatthias Schmidt p = newcp;
11007d8fb588SMatthias Schmidt }
11017d8fb588SMatthias Schmidt xfree(cp);
11027d8fb588SMatthias Schmidt cp = newcp;
11037d8fb588SMatthias Schmidt #ifdef HAVE_SLASHSLASH
11047d8fb588SMatthias Schmidt slashslash = (cp[0] == '/' && cp[1] == '/');
11057d8fb588SMatthias Schmidt #endif /* HAVE_SLASHSLASH */
11067d8fb588SMatthias Schmidt continue; /* canonicalize the mlink */
11077d8fb588SMatthias Schmidt }
11087d8fb588SMatthias Schmidt #endif /* S_IFLNK */
11097d8fb588SMatthias Schmidt if (slash)
11107d8fb588SMatthias Schmidt *p = '/';
11117d8fb588SMatthias Schmidt }
11127d8fb588SMatthias Schmidt }
11137d8fb588SMatthias Schmidt
11147d8fb588SMatthias Schmidt /*
11157d8fb588SMatthias Schmidt * fix home...
11167d8fb588SMatthias Schmidt */
11177d8fb588SMatthias Schmidt #ifdef S_IFLNK
11187d8fb588SMatthias Schmidt p1 = varval(STRhome);
11197d8fb588SMatthias Schmidt cc = Strlen(p1);
11207d8fb588SMatthias Schmidt /*
11217d8fb588SMatthias Schmidt * See if we're not in a subdir of STRhome
11227d8fb588SMatthias Schmidt */
11237d8fb588SMatthias Schmidt if (p1 && *p1 == '/' && (Strncmp(p1, cp, cc) != 0 ||
11247d8fb588SMatthias Schmidt (cp[cc] != '/' && cp[cc] != '\0'))) {
11257d8fb588SMatthias Schmidt static ino_t home_ino = (ino_t) -1;
11267d8fb588SMatthias Schmidt static dev_t home_dev = (dev_t) -1;
11277d8fb588SMatthias Schmidt static Char *home_ptr = NULL;
11287d8fb588SMatthias Schmidt struct stat statbuf;
11297d8fb588SMatthias Schmidt int found;
11307d8fb588SMatthias Schmidt Char *copy;
11317d8fb588SMatthias Schmidt
11327d8fb588SMatthias Schmidt /*
11337d8fb588SMatthias Schmidt * Get dev and ino of STRhome
11347d8fb588SMatthias Schmidt */
11357d8fb588SMatthias Schmidt if (home_ptr != p1 &&
11367d8fb588SMatthias Schmidt stat(short2str(p1), &statbuf) != -1) {
11377d8fb588SMatthias Schmidt home_dev = statbuf.st_dev;
11387d8fb588SMatthias Schmidt home_ino = statbuf.st_ino;
11397d8fb588SMatthias Schmidt home_ptr = p1;
11407d8fb588SMatthias Schmidt }
11417d8fb588SMatthias Schmidt /*
11427d8fb588SMatthias Schmidt * Start comparing dev & ino backwards
11437d8fb588SMatthias Schmidt */
11447d8fb588SMatthias Schmidt p2 = copy = Strsave(cp);
11457d8fb588SMatthias Schmidt found = 0;
11467d8fb588SMatthias Schmidt while (*p2 && stat(short2str(p2), &statbuf) != -1) {
11477d8fb588SMatthias Schmidt if (DEV_DEV_COMPARE(statbuf.st_dev, home_dev) &&
11487d8fb588SMatthias Schmidt statbuf.st_ino == home_ino) {
11497d8fb588SMatthias Schmidt found = 1;
11507d8fb588SMatthias Schmidt break;
11517d8fb588SMatthias Schmidt }
11527d8fb588SMatthias Schmidt if ((sp = Strrchr(p2, '/')) != NULL)
11537d8fb588SMatthias Schmidt *sp = '\0';
11547d8fb588SMatthias Schmidt }
11557d8fb588SMatthias Schmidt /*
11567d8fb588SMatthias Schmidt * See if we found it
11577d8fb588SMatthias Schmidt */
11587d8fb588SMatthias Schmidt if (*p2 && found) {
11597d8fb588SMatthias Schmidt /*
11607d8fb588SMatthias Schmidt * Use STRhome to make '~' work
11617d8fb588SMatthias Schmidt */
11627d8fb588SMatthias Schmidt newcp = Strspl(p1, cp + Strlen(p2));
11637d8fb588SMatthias Schmidt xfree(cp);
11647d8fb588SMatthias Schmidt cp = newcp;
11657d8fb588SMatthias Schmidt }
11667d8fb588SMatthias Schmidt xfree(copy);
11677d8fb588SMatthias Schmidt }
11687d8fb588SMatthias Schmidt #endif /* S_IFLNK */
11697d8fb588SMatthias Schmidt
11707d8fb588SMatthias Schmidt #ifdef HAVE_SLASHSLASH
11717d8fb588SMatthias Schmidt if (slashslash) {
11727d8fb588SMatthias Schmidt if (cp[1] != '/') {
11737d8fb588SMatthias Schmidt p = xmalloc((Strlen(cp) + 2) * sizeof(Char));
11747d8fb588SMatthias Schmidt *p = '/';
11757d8fb588SMatthias Schmidt (void) Strcpy(&p[1], cp);
11767d8fb588SMatthias Schmidt xfree(cp);
11777d8fb588SMatthias Schmidt cp = p;
11787d8fb588SMatthias Schmidt }
11797d8fb588SMatthias Schmidt }
11807d8fb588SMatthias Schmidt if (cp[1] == '/' && cp[2] == '/') {
11817d8fb588SMatthias Schmidt for (p1 = &cp[1], p2 = &cp[2]; (*p1++ = *p2++) != '\0';)
11827d8fb588SMatthias Schmidt continue;
11837d8fb588SMatthias Schmidt }
11847d8fb588SMatthias Schmidt #endif /* HAVE_SLASHSLASH */
11857d8fb588SMatthias Schmidt return cp;
11867d8fb588SMatthias Schmidt }
11877d8fb588SMatthias Schmidt
11887d8fb588SMatthias Schmidt
11897d8fb588SMatthias Schmidt /*
11907d8fb588SMatthias Schmidt * dnewcwd - make a new directory in the loop the current one
11917d8fb588SMatthias Schmidt */
11927d8fb588SMatthias Schmidt static void
dnewcwd(struct directory * dp,int dflag)11937d8fb588SMatthias Schmidt dnewcwd(struct directory *dp, int dflag)
11947d8fb588SMatthias Schmidt {
11957d8fb588SMatthias Schmidt int print;
11967d8fb588SMatthias Schmidt
11977d8fb588SMatthias Schmidt if (adrof(STRdunique)) {
11987d8fb588SMatthias Schmidt struct directory *dn;
11997d8fb588SMatthias Schmidt
12007d8fb588SMatthias Schmidt for (dn = dhead.di_prev; dn != &dhead; dn = dn->di_prev)
12017d8fb588SMatthias Schmidt if (dn != dp && Strcmp(dn->di_name, dp->di_name) == 0) {
12027d8fb588SMatthias Schmidt dn->di_next->di_prev = dn->di_prev;
12037d8fb588SMatthias Schmidt dn->di_prev->di_next = dn->di_next;
12047d8fb588SMatthias Schmidt dfree(dn);
12057d8fb588SMatthias Schmidt break;
12067d8fb588SMatthias Schmidt }
12077d8fb588SMatthias Schmidt }
12087d8fb588SMatthias Schmidt dcwd = dp;
12097d8fb588SMatthias Schmidt dset(dcwd->di_name);
12107d8fb588SMatthias Schmidt dgetstack();
12117d8fb588SMatthias Schmidt print = printd; /* if printd is set, print dirstack... */
12127d8fb588SMatthias Schmidt if (adrof(STRpushdsilent)) /* but pushdsilent overrides printd... */
12137d8fb588SMatthias Schmidt print = 0;
12147d8fb588SMatthias Schmidt if (dflag & DIR_PRINT) /* but DIR_PRINT overrides pushdsilent... */
12157d8fb588SMatthias Schmidt print = 1;
12167d8fb588SMatthias Schmidt if (bequiet) /* and bequiet overrides everything */
12177d8fb588SMatthias Schmidt print = 0;
12187d8fb588SMatthias Schmidt if (print)
12197d8fb588SMatthias Schmidt printdirs(dflag);
12207d8fb588SMatthias Schmidt cwd_cmd(); /* PWP: run the defined cwd command */
12217d8fb588SMatthias Schmidt }
12227d8fb588SMatthias Schmidt
12237d8fb588SMatthias Schmidt void
dsetstack(void)12247d8fb588SMatthias Schmidt dsetstack(void)
12257d8fb588SMatthias Schmidt {
12267d8fb588SMatthias Schmidt Char **cp;
12277d8fb588SMatthias Schmidt struct varent *vp;
12287d8fb588SMatthias Schmidt struct directory *dn, *dp;
12297d8fb588SMatthias Schmidt
12307d8fb588SMatthias Schmidt if ((vp = adrof(STRdirstack)) == NULL || vp->vec == NULL)
12317d8fb588SMatthias Schmidt return;
12327d8fb588SMatthias Schmidt
12337d8fb588SMatthias Schmidt /* Free the whole stack */
12347d8fb588SMatthias Schmidt while ((dn = dhead.di_prev) != &dhead) {
12357d8fb588SMatthias Schmidt dn->di_next->di_prev = dn->di_prev;
12367d8fb588SMatthias Schmidt dn->di_prev->di_next = dn->di_next;
12377d8fb588SMatthias Schmidt if (dn != dcwd)
12387d8fb588SMatthias Schmidt dfree(dn);
12397d8fb588SMatthias Schmidt }
12407d8fb588SMatthias Schmidt
12417d8fb588SMatthias Schmidt /* thread the current working directory */
12427d8fb588SMatthias Schmidt dhead.di_prev = dhead.di_next = dcwd;
12437d8fb588SMatthias Schmidt dcwd->di_next = dcwd->di_prev = &dhead;
12447d8fb588SMatthias Schmidt
12457d8fb588SMatthias Schmidt /* put back the stack */
12467d8fb588SMatthias Schmidt for (cp = vp->vec; cp && *cp && **cp; cp++) {
12477d8fb588SMatthias Schmidt dp = xcalloc(sizeof(struct directory), 1);
12487d8fb588SMatthias Schmidt dp->di_name = Strsave(*cp);
12497d8fb588SMatthias Schmidt dp->di_count = 0;
12507d8fb588SMatthias Schmidt dp->di_prev = dcwd;
12517d8fb588SMatthias Schmidt dp->di_next = dcwd->di_next;
12527d8fb588SMatthias Schmidt dcwd->di_next = dp;
12537d8fb588SMatthias Schmidt dp->di_next->di_prev = dp;
12547d8fb588SMatthias Schmidt }
12557d8fb588SMatthias Schmidt dgetstack(); /* Make $dirstack reflect the current state */
12567d8fb588SMatthias Schmidt }
12577d8fb588SMatthias Schmidt
12587d8fb588SMatthias Schmidt static void
dgetstack(void)12597d8fb588SMatthias Schmidt dgetstack(void)
12607d8fb588SMatthias Schmidt {
12617d8fb588SMatthias Schmidt int i = 0;
12627d8fb588SMatthias Schmidt Char **dblk, **dbp;
12637d8fb588SMatthias Schmidt struct directory *dn;
12647d8fb588SMatthias Schmidt
12657d8fb588SMatthias Schmidt if (adrof(STRdirstack) == NULL)
12667d8fb588SMatthias Schmidt return;
12677d8fb588SMatthias Schmidt
12687d8fb588SMatthias Schmidt for (dn = dhead.di_prev; dn != &dhead; dn = dn->di_prev, i++)
12697d8fb588SMatthias Schmidt continue;
12707d8fb588SMatthias Schmidt dbp = dblk = xmalloc((i + 1) * sizeof(Char *));
12717d8fb588SMatthias Schmidt for (dn = dhead.di_prev; dn != &dhead; dn = dn->di_prev, dbp++)
12727d8fb588SMatthias Schmidt *dbp = Strsave(dn->di_name);
12737d8fb588SMatthias Schmidt *dbp = NULL;
12747d8fb588SMatthias Schmidt cleanup_push(dblk, blk_cleanup);
12757d8fb588SMatthias Schmidt setq(STRdirstack, dblk, &shvhed, VAR_READWRITE);
12767d8fb588SMatthias Schmidt cleanup_ignore(dblk);
12777d8fb588SMatthias Schmidt cleanup_until(dblk);
12787d8fb588SMatthias Schmidt }
12797d8fb588SMatthias Schmidt
12807d8fb588SMatthias Schmidt /*
12817d8fb588SMatthias Schmidt * getstakd - added by kfk 17 Jan 1984
12827d8fb588SMatthias Schmidt * Support routine for the stack hack. Finds nth directory in
12837d8fb588SMatthias Schmidt * the directory stack, or finds last directory in stack.
12847d8fb588SMatthias Schmidt */
12857d8fb588SMatthias Schmidt const Char *
getstakd(int cnt)12867d8fb588SMatthias Schmidt getstakd(int cnt)
12877d8fb588SMatthias Schmidt {
12887d8fb588SMatthias Schmidt struct directory *dp;
12897d8fb588SMatthias Schmidt
12907d8fb588SMatthias Schmidt dp = dcwd;
12917d8fb588SMatthias Schmidt if (cnt < 0) { /* < 0 ==> last dir requested. */
12927d8fb588SMatthias Schmidt dp = dp->di_next;
12937d8fb588SMatthias Schmidt if (dp == &dhead)
12947d8fb588SMatthias Schmidt dp = dp->di_next;
12957d8fb588SMatthias Schmidt }
12967d8fb588SMatthias Schmidt else {
12977d8fb588SMatthias Schmidt while (cnt-- > 0) {
12987d8fb588SMatthias Schmidt dp = dp->di_prev;
12997d8fb588SMatthias Schmidt if (dp == &dhead)
13007d8fb588SMatthias Schmidt dp = dp->di_prev;
13017d8fb588SMatthias Schmidt if (dp == dcwd)
13027d8fb588SMatthias Schmidt return NULL;
13037d8fb588SMatthias Schmidt }
13047d8fb588SMatthias Schmidt }
13057d8fb588SMatthias Schmidt return dp->di_name;
13067d8fb588SMatthias Schmidt }
13077d8fb588SMatthias Schmidt
13087d8fb588SMatthias Schmidt /*
13097d8fb588SMatthias Schmidt * Karl Kleinpaste - 10 Feb 1984
13107d8fb588SMatthias Schmidt * Added dextract(), which is used in pushd +n.
13117d8fb588SMatthias Schmidt * Instead of just rotating the entire stack around, dextract()
13127d8fb588SMatthias Schmidt * lets the user have the nth dir extracted from its current
13137d8fb588SMatthias Schmidt * position, and pushes it onto the top.
13147d8fb588SMatthias Schmidt */
13157d8fb588SMatthias Schmidt static void
dextract(struct directory * dp)13167d8fb588SMatthias Schmidt dextract(struct directory *dp)
13177d8fb588SMatthias Schmidt {
13187d8fb588SMatthias Schmidt if (dp == dcwd)
13197d8fb588SMatthias Schmidt return;
13207d8fb588SMatthias Schmidt dp->di_next->di_prev = dp->di_prev;
13217d8fb588SMatthias Schmidt dp->di_prev->di_next = dp->di_next;
13227d8fb588SMatthias Schmidt dp->di_next = dcwd->di_next;
13237d8fb588SMatthias Schmidt dp->di_prev = dcwd;
13247d8fb588SMatthias Schmidt dp->di_next->di_prev = dp;
13257d8fb588SMatthias Schmidt dcwd->di_next = dp;
13267d8fb588SMatthias Schmidt }
13277d8fb588SMatthias Schmidt
13287d8fb588SMatthias Schmidt static void
bequiet_cleanup(void * dummy)13297d8fb588SMatthias Schmidt bequiet_cleanup(void *dummy)
13307d8fb588SMatthias Schmidt {
13317d8fb588SMatthias Schmidt USE(dummy);
13327d8fb588SMatthias Schmidt bequiet = 0;
13337d8fb588SMatthias Schmidt }
13347d8fb588SMatthias Schmidt
13357d8fb588SMatthias Schmidt void
loaddirs(Char * fname)13367d8fb588SMatthias Schmidt loaddirs(Char *fname)
13377d8fb588SMatthias Schmidt {
13387d8fb588SMatthias Schmidt static Char *loaddirs_cmd[] = { STRsource, NULL, NULL };
13397d8fb588SMatthias Schmidt
13407d8fb588SMatthias Schmidt bequiet = 1;
13417d8fb588SMatthias Schmidt cleanup_push(&bequiet, bequiet_cleanup);
13427d8fb588SMatthias Schmidt if (fname)
13437d8fb588SMatthias Schmidt loaddirs_cmd[1] = fname;
13447d8fb588SMatthias Schmidt else if ((fname = varval(STRdirsfile)) != STRNULL)
13457d8fb588SMatthias Schmidt loaddirs_cmd[1] = fname;
13467d8fb588SMatthias Schmidt else
13477d8fb588SMatthias Schmidt loaddirs_cmd[1] = STRtildotdirs;
13487d8fb588SMatthias Schmidt dosource(loaddirs_cmd, NULL);
13497d8fb588SMatthias Schmidt cleanup_until(&bequiet);
13507d8fb588SMatthias Schmidt }
13517d8fb588SMatthias Schmidt
13527d8fb588SMatthias Schmidt /*
13537d8fb588SMatthias Schmidt * create a file called ~/.cshdirs which has a sequence
13547d8fb588SMatthias Schmidt * of pushd commands which will restore the dir stack to
13557d8fb588SMatthias Schmidt * its state before exit/logout. remember that the order
13567d8fb588SMatthias Schmidt * is reversed in the file because we are pushing.
13577d8fb588SMatthias Schmidt * -strike
13587d8fb588SMatthias Schmidt */
13597d8fb588SMatthias Schmidt void
recdirs(Char * fname,int def)13607d8fb588SMatthias Schmidt recdirs(Char *fname, int def)
13617d8fb588SMatthias Schmidt {
1362*d6ab524cSAntonio Huete Jimenez int fp, ftmp, oldidfds, ophup_disabled;
13637d8fb588SMatthias Schmidt int cdflag = 0;
13647d8fb588SMatthias Schmidt struct directory *dp;
13657d8fb588SMatthias Schmidt unsigned int num;
13667d8fb588SMatthias Schmidt Char *snum;
13677d8fb588SMatthias Schmidt struct Strbuf qname = Strbuf_INIT;
13687d8fb588SMatthias Schmidt
13697d8fb588SMatthias Schmidt if (fname == NULL && !def)
13707d8fb588SMatthias Schmidt return;
13717d8fb588SMatthias Schmidt
1372*d6ab524cSAntonio Huete Jimenez ophup_disabled = phup_disabled;
1373*d6ab524cSAntonio Huete Jimenez phup_disabled = 1;
13747d8fb588SMatthias Schmidt if (fname == NULL) {
13757d8fb588SMatthias Schmidt if ((fname = varval(STRdirsfile)) == STRNULL)
13767d8fb588SMatthias Schmidt fname = Strspl(varval(STRhome), &STRtildotdirs[1]);
13777d8fb588SMatthias Schmidt else
13787d8fb588SMatthias Schmidt fname = Strsave(fname);
13797d8fb588SMatthias Schmidt }
13807d8fb588SMatthias Schmidt else
13817d8fb588SMatthias Schmidt fname = globone(fname, G_ERROR);
13827d8fb588SMatthias Schmidt cleanup_push(fname, xfree);
13837d8fb588SMatthias Schmidt
13847d8fb588SMatthias Schmidt if ((fp = xcreat(short2str(fname), 0600)) == -1) {
13857d8fb588SMatthias Schmidt cleanup_until(fname);
1386*d6ab524cSAntonio Huete Jimenez phup_disabled = ophup_disabled;
13877d8fb588SMatthias Schmidt return;
13887d8fb588SMatthias Schmidt }
13897d8fb588SMatthias Schmidt
13907d8fb588SMatthias Schmidt if ((snum = varval(STRsavedirs)) == STRNULL || snum[0] == '\0')
13917d8fb588SMatthias Schmidt num = (unsigned int) ~0;
13927d8fb588SMatthias Schmidt else
13937d8fb588SMatthias Schmidt num = (unsigned int) atoi(short2str(snum));
13947d8fb588SMatthias Schmidt
13957d8fb588SMatthias Schmidt oldidfds = didfds;
13967d8fb588SMatthias Schmidt didfds = 0;
13977d8fb588SMatthias Schmidt ftmp = SHOUT;
13987d8fb588SMatthias Schmidt SHOUT = fp;
13997d8fb588SMatthias Schmidt
14007d8fb588SMatthias Schmidt cleanup_push(&qname, Strbuf_cleanup);
14017d8fb588SMatthias Schmidt dp = dcwd->di_next;
14027d8fb588SMatthias Schmidt do {
14037d8fb588SMatthias Schmidt if (dp == &dhead)
14047d8fb588SMatthias Schmidt continue;
14057d8fb588SMatthias Schmidt
14067d8fb588SMatthias Schmidt if (cdflag == 0) {
14077d8fb588SMatthias Schmidt cdflag = 1;
1408*d6ab524cSAntonio Huete Jimenez xprintf("cd %" TCSH_S "\n", quote_meta(&qname, dp->di_name));
14097d8fb588SMatthias Schmidt }
14107d8fb588SMatthias Schmidt else
1411*d6ab524cSAntonio Huete Jimenez xprintf("pushd %" TCSH_S "\n", quote_meta(&qname, dp->di_name));
14127d8fb588SMatthias Schmidt
14137d8fb588SMatthias Schmidt if (num-- == 0)
14147d8fb588SMatthias Schmidt break;
14157d8fb588SMatthias Schmidt
14167d8fb588SMatthias Schmidt } while ((dp = dp->di_next) != dcwd->di_next);
14177d8fb588SMatthias Schmidt
14187d8fb588SMatthias Schmidt xclose(fp);
14197d8fb588SMatthias Schmidt SHOUT = ftmp;
14207d8fb588SMatthias Schmidt didfds = oldidfds;
14217d8fb588SMatthias Schmidt cleanup_until(fname);
1422*d6ab524cSAntonio Huete Jimenez phup_disabled = ophup_disabled;
14237d8fb588SMatthias Schmidt }
1424