sh.dir.c revision 100616
178189Sbrian/* $Header: /src/pub/tcsh/sh.dir.c,v 3.60 2002/07/08 21:03:04 christos Exp $ */ 278189Sbrian/* 378189Sbrian * sh.dir.c: Directory manipulation functions 478189Sbrian */ 578189Sbrian/*- 66059Samurai * Copyright (c) 1980, 1991 The Regents of the University of California. 778189Sbrian * All rights reserved. 878189Sbrian * 978189Sbrian * Redistribution and use in source and binary forms, with or without 1078189Sbrian * modification, are permitted provided that the following conditions 1178189Sbrian * are met: 1278189Sbrian * 1. Redistributions of source code must retain the above copyright 1378189Sbrian * notice, this list of conditions and the following disclaimer. 1478189Sbrian * 2. Redistributions in binary form must reproduce the above copyright 156059Samurai * notice, this list of conditions and the following disclaimer in the 1678189Sbrian * documentation and/or other materials provided with the distribution. 1778189Sbrian * 3. Neither the name of the University nor the names of its contributors 1878189Sbrian * may be used to endorse or promote products derived from this software 1978189Sbrian * without specific prior written permission. 2078189Sbrian * 2178189Sbrian * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2278189Sbrian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2378189Sbrian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2478189Sbrian * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2578189Sbrian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2678189Sbrian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 276059Samurai * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2850479Speter * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 296059Samurai * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3036285Sbrian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3143313Sbrian * SUCH DAMAGE. 3230715Sbrian */ 3336285Sbrian#include "sh.h" 3436285Sbrian 3581634SbrianRCSID("$Id: sh.dir.c,v 3.60 2002/07/08 21:03:04 christos Exp $") 3636285Sbrian 3730715Sbrian/* 3830715Sbrian * C Shell - directory management 3930715Sbrian */ 4030715Sbrian 4146686Sbrianstatic void dstart __P((const char *)); 4238814Sbrianstatic struct directory *dfind __P((Char *)); 4330715Sbrianstatic Char *dfollow __P((Char *)); 4430715Sbrianstatic void printdirs __P((int)); 4530715Sbrianstatic Char *dgoto __P((Char *)); 4630715Sbrianstatic void dnewcwd __P((struct directory *, int)); 476059Samuraistatic void dset __P((Char *)); 4836285Sbrianstatic void dextract __P((struct directory *)); 4936285Sbrianstatic int skipargs __P((Char ***, char *, char *)); 506059Samuraistatic void dgetstack __P((void)); 5136285Sbrian 5236285Sbrianstatic struct directory dhead INIT_ZERO_STRUCT; /* "head" of loop */ 5381634Sbrianstatic int printd; /* force name to be printed */ 5436285Sbrian 5536285Sbrianint bequiet = 0; /* do not print dir stack -strike */ 5636285Sbrian 576059Samuraistatic void 5813389Sphkdstart(from) 5936285Sbrian const char *from; 6036285Sbrian{ 6143313Sbrian xprintf(CGETS(12, 1, "%s: Trying to start from \"%s\"\n"), progname, from); 6243313Sbrian} 6343313Sbrian 6481634Sbrian/* 6581634Sbrian * dinit - initialize current working directory 6636285Sbrian */ 6736285Sbrianvoid 6836285Sbriandinit(hp) 6946686Sbrian Char *hp; 706059Samurai{ 7130715Sbrian register char *tcp; 7230715Sbrian register Char *cp; 7344305Sbrian register struct directory *dp; 7430715Sbrian char path[MAXPATHLEN]; 7536285Sbrian 7636285Sbrian /* Don't believe the login shell home, because it may be a symlink */ 7736285Sbrian tcp = (char *) getcwd(path, sizeof(path)); 7836285Sbrian if (tcp == NULL || *tcp == '\0') { 7936285Sbrian xprintf("%s: %s\n", progname, strerror(errno)); 8036285Sbrian if (hp && *hp) { 8136285Sbrian tcp = short2str(hp); 8236285Sbrian dstart(tcp); 8336285Sbrian if (chdir(tcp) == -1) 8436285Sbrian cp = NULL; 8536285Sbrian else 8636285Sbrian cp = Strsave(hp); 8736285Sbrian } 8836285Sbrian else 8936285Sbrian cp = NULL; 9036285Sbrian if (cp == NULL) { 9136285Sbrian dstart("/"); 9236285Sbrian if (chdir("/") == -1) 9336285Sbrian /* I am not even try to print an error message! */ 9436285Sbrian xexit(1); 9536285Sbrian cp = SAVE("/"); 9636285Sbrian } 9736285Sbrian } 9836285Sbrian else { 9963484Sbrian#ifdef S_IFLNK 10036285Sbrian struct stat swd, shp; 10146686Sbrian 10236285Sbrian /* 1036059Samurai * See if $HOME is the working directory we got and use that 1046059Samurai */ 10536285Sbrian if (hp && *hp && 10636285Sbrian stat(tcp, &swd) != -1 && stat(short2str(hp), &shp) != -1 && 10736285Sbrian DEV_DEV_COMPARE(swd.st_dev, shp.st_dev) && 10836285Sbrian swd.st_ino == shp.st_ino) 10936285Sbrian cp = Strsave(hp); 11036285Sbrian else { 11136285Sbrian char *cwd; 11236285Sbrian 11336285Sbrian /* 11436285Sbrian * use PWD if we have it (for subshells) 11536285Sbrian */ 11655146Sbrian if ((cwd = getenv("PWD")) != NULL) { 11736285Sbrian if (stat(cwd, &shp) != -1 && 11836285Sbrian DEV_DEV_COMPARE(swd.st_dev, shp.st_dev) && 11936285Sbrian swd.st_ino == shp.st_ino) 12036285Sbrian tcp = cwd; 12136285Sbrian } 12236285Sbrian cp = dcanon(SAVE(tcp), STRNULL); 12336285Sbrian } 12436285Sbrian#else /* S_IFLNK */ 12536285Sbrian cp = dcanon(SAVE(tcp), STRNULL); 12628327Sbrian#endif /* S_IFLNK */ 12731343Sbrian } 12828327Sbrian 12931343Sbrian dp = (struct directory *) xcalloc(sizeof(struct directory), 1); 13031343Sbrian dp->di_name = cp; 13136285Sbrian dp->di_count = 0; 13232658Sbrian dhead.di_next = dhead.di_prev = dp; 13336285Sbrian dp->di_next = dp->di_prev = &dhead; 13436285Sbrian printd = 0; 13536285Sbrian dnewcwd(dp, 0); 13632658Sbrian set(STRdirstack, Strsave(dp->di_name), VAR_READWRITE|VAR_NOGLOB); 13737060Sbrian} 13837060Sbrian 13928327Sbrianstatic void 14028327Sbriandset(dp) 1416059SamuraiChar *dp; 14236285Sbrian{ 14344305Sbrian /* 14436285Sbrian * Don't call set() directly cause if the directory contains ` or 14555146Sbrian * other junk characters glob will fail. 1466059Samurai */ 14736285Sbrian set(STRowd, Strsave(varval(STRcwd)), VAR_READWRITE|VAR_NOGLOB); 14836285Sbrian set(STRcwd, Strsave(dp), VAR_READWRITE|VAR_NOGLOB); 14936285Sbrian 15036285Sbrian tsetenv(STRPWD, dp); 15136285Sbrian} 1526059Samurai 1536059Samurai#define DIR_PRINT 0x01 /* -p */ 15446686Sbrian#define DIR_LONG 0x02 /* -l */ 15536285Sbrian#define DIR_VERT 0x04 /* -v */ 15636285Sbrian#define DIR_LINE 0x08 /* -n */ 15736285Sbrian#define DIR_SAVE 0x10 /* -S */ 15836285Sbrian#define DIR_LOAD 0x20 /* -L */ 15936285Sbrian#define DIR_CLEAR 0x40 /* -c */ 16036285Sbrian#define DIR_OLD 0x80 /* - */ 16136285Sbrian 16236285Sbrianstatic int 16336285Sbrianskipargs(v, dstr, str) 16436285Sbrian Char ***v; 16536285Sbrian char *dstr; 1666059Samurai char *str; 1676059Samurai{ 16830715Sbrian Char **n = *v, *s; 16946828Sbrian 1706059Samurai int dflag = 0, loop = 1; 17136285Sbrian for (n++; loop && *n != NULL && (*n)[0] == '-'; n++) 17294894Sbrian if (*(s = &((*n)[1])) == '\0') /* test for bare "-" argument */ 17328461Sbrian dflag |= DIR_OLD; 17436285Sbrian else { 1756059Samurai char *p; 17628327Sbrian while (loop && *s != '\0') /* examine flags */ 17736285Sbrian { 17828461Sbrian if ((p = strchr(dstr, *s++)) != NULL) 17936285Sbrian dflag |= (1 << (p - dstr)); 18028461Sbrian else { 18128679Sbrian stderror(ERR_DIRUS, short2str(**v), dstr, str); 18236285Sbrian loop = 0; /* break from both loops */ 18328327Sbrian break; 18428327Sbrian } 1856059Samurai } 1866059Samurai } 1876059Samurai if (*n && (dflag & DIR_OLD)) 188134789Sbrian stderror(ERR_DIRUS, short2str(**v), dstr, str); 18947695Sbrian *v = n; 1906059Samurai /* make -l, -v, and -n imply -p */ 1916059Samurai if (dflag & (DIR_LONG|DIR_VERT|DIR_LINE)) 1926059Samurai dflag |= DIR_PRINT; 1936059Samurai return dflag; 1946059Samurai} 19536285Sbrian 19636285Sbrian/* 19736285Sbrian * dodirs - list all directories in directory loop 19836285Sbrian */ 19936285Sbrian/*ARGSUSED*/ 20036285Sbrianvoid 20136285Sbriandodirs(v, c) 20236285Sbrian Char **v; 20394894Sbrian struct command *c; 20494894Sbrian{ 20536285Sbrian static char flags[] = "plvnSLc"; 20636285Sbrian int dflag = skipargs(&v, flags, ""); 20736285Sbrian 20836285Sbrian USE(c); 20936285Sbrian if ((dflag & DIR_CLEAR) != 0) { 21028679Sbrian struct directory *dp, *fdp; 2116059Samurai for (dp = dcwd->di_next; dp != dcwd; ) { 2126059Samurai fdp = dp; 2136059Samurai dp = dp->di_next; 21454912Sbrian if (fdp != &dhead) 21530715Sbrian dfree(fdp); 2166059Samurai } 21730715Sbrian dhead.di_next = dhead.di_prev = dp; 21836285Sbrian dp->di_next = dp->di_prev = &dhead; 21950867Sbrian } 22050867Sbrian if ((dflag & DIR_LOAD) != 0) 22163484Sbrian loaddirs(*v); 22263484Sbrian else if ((dflag & DIR_SAVE) != 0) 22363484Sbrian recdirs(*v, 1); 2246059Samurai 2256059Samurai if (*v && (dflag & (DIR_SAVE|DIR_LOAD))) 22632658Sbrian v++; 22732658Sbrian 22832658Sbrian if (*v != NULL || (dflag & DIR_OLD)) 22932658Sbrian stderror(ERR_DIRUS, "dirs", flags, ""); 23032658Sbrian if ((dflag & (DIR_CLEAR|DIR_LOAD|DIR_SAVE)) == 0 || (dflag & DIR_PRINT)) 23136285Sbrian printdirs(dflag); 23232658Sbrian} 23337210Sbrian 23437210Sbrianstatic void 23537210Sbrianprintdirs(dflag) 23637210Sbrian int dflag; 23737210Sbrian{ 23837210Sbrian register struct directory *dp; 23937210Sbrian Char *s, *user; 24037210Sbrian int idx, len, cur; 24137210Sbrian extern int T_Cols; 24237210Sbrian 24337210Sbrian dp = dcwd; 24437210Sbrian idx = 0; 24537210Sbrian cur = 0; 24637210Sbrian do { 24737210Sbrian if (dp == &dhead) 24844305Sbrian continue; 24932658Sbrian if (dflag & DIR_VERT) { 25032658Sbrian xprintf("%d\t", idx++); 25132658Sbrian cur = 0; 25232658Sbrian } 25332658Sbrian s = dp->di_name; 2546059Samurai user = NULL; 25546828Sbrian if (!(dflag & DIR_LONG) && (user = getusername(&s)) != NULL) 2566059Samurai len = (int) (Strlen(user) + Strlen(s) + 2); 2576059Samurai else 25836285Sbrian len = (int) (Strlen(s) + 1); 2596059Samurai 26036285Sbrian cur += len; 26136285Sbrian if ((dflag & DIR_LINE) && cur >= T_Cols - 1 && len < T_Cols) { 2626059Samurai xputchar('\n'); 2636059Samurai cur = len; 2646059Samurai } 26537210Sbrian if (user) 26632658Sbrian xprintf("~%S", user); 26732658Sbrian xprintf("%S%c", s, (dflag & DIR_VERT) ? '\n' : ' '); 26836285Sbrian } while ((dp = dp->di_prev) != dcwd); 26936285Sbrian if (!(dflag & DIR_VERT)) 27037210Sbrian xputchar('\n'); 27136285Sbrian} 27232658Sbrian 27332658Sbrianvoid 27432658Sbriandtildepr(dir) 27536285Sbrian Char *dir; 27632658Sbrian{ 27732658Sbrian Char* user; 2786059Samurai if ((user = getusername(&dir)) != NULL) 27928679Sbrian xprintf("~%S%S", user, dir); 2806059Samurai else 2816059Samurai xprintf("%S", dir); 2826059Samurai} 28328679Sbrian 2846059Samuraivoid 28528679Sbriandtilde() 28628679Sbrian{ 2876059Samurai struct directory *d = dcwd; 2886059Samurai 2896059Samurai do { 2906059Samurai if (d == &dhead) 2916059Samurai continue; 2926059Samurai d->di_name = dcanon(d->di_name, STRNULL); 29346828Sbrian } while ((d = d->di_prev) != dcwd); 2946059Samurai 2956059Samurai dset(dcwd->di_name); 29637210Sbrian} 29736285Sbrian 29836285Sbrian 2996059Samurai/* dnormalize(): 3006059Samurai * The path will be normalized if it 3016059Samurai * 1) is "..", 30244305Sbrian * 2) or starts with "../", 3036059Samurai * 3) or ends with "/..", 3046059Samurai * 4) or contains the string "/../", 3056059Samurai * then it will be normalized, unless those strings are quoted. 3066059Samurai * Otherwise, a copy is made and sent back. 30736285Sbrian */ 30836285SbrianChar * 3096059Samuraidnormalize(cp, exp) 3106059Samurai Char *cp; 3116059Samurai int exp; 3126059Samurai{ 3136059Samurai 31436285Sbrian/* return true if dp is of the form "../xxx" or "/../xxx" */ 3156059Samurai#define IS_DOTDOT(sp, p) (ISDOTDOT(p) && ((p) == (sp) || *((p) - 1) == '/')) 3166059Samurai#define IS_DOT(sp, p) (ISDOT(p) && ((p) == (sp) || *((p) - 1) == '/')) 31736285Sbrian 3186059Samurai#ifdef S_IFLNK 3196059Samurai if (exp) { 32036285Sbrian int dotdot = 0; 32144359Sbrian Char *dp, *cwd, *start = cp, buf[MAXPATHLEN]; 32236285Sbrian struct stat sb; 32336285Sbrian# ifdef apollo 32436285Sbrian bool slashslash; 32536285Sbrian# endif /* apollo */ 3266059Samurai 32736285Sbrian /* 32836285Sbrian * count the number of "../xxx" or "xxx/../xxx" in the path 32936285Sbrian */ 33036285Sbrian for (dp=start; *dp && *(dp+1); dp++) 3316059Samurai if (IS_DOTDOT(start, dp)) 3326059Samurai dotdot++; 3336059Samurai /* 3346059Samurai * if none, we are done. 3356059Samurai */ 3366059Samurai if (dotdot == 0) 3376059Samurai return (Strsave(cp)); 33836285Sbrian 3396059Samurai /* 34036285Sbrian * If the path doesn't exist, we are done too. 3416059Samurai */ 3426059Samurai if (lstat(short2str(cp), &sb) != 0 && errno == ENOENT) 3436059Samurai return (Strsave(cp)); 3446059Samurai 3456059Samurai 34636285Sbrian cwd = (Char *) xmalloc((size_t) (((int) Strlen(dcwd->di_name) + 3) * 3476059Samurai sizeof(Char))); 3486059Samurai (void) Strcpy(cwd, dcwd->di_name); 34936285Sbrian 35036285Sbrian /* 3516059Samurai * If the path starts with a slash, we are not relative to 35236285Sbrian * the current working directory. 3536059Samurai */ 3546059Samurai if (ABSOLUTEP(start)) 3556059Samurai *cwd = '\0'; 3566059Samurai# ifdef apollo 3576059Samurai slashslash = cwd[0] == '/' && cwd[1] == '/'; 3586059Samurai# endif /* apollo */ 3596059Samurai 3606059Samurai /* 36136285Sbrian * Ignore . and count ..'s 36271658Sbrian */ 36371658Sbrian for (;;) { 36471658Sbrian dotdot = 0; 36571658Sbrian buf[0] = '\0'; 36671658Sbrian dp = buf; 36771658Sbrian while (*cp) 36836285Sbrian if (IS_DOT(start, cp)) { 3696059Samurai if (*++cp) 3706059Samurai cp++; 3716059Samurai } 37244305Sbrian else if (IS_DOTDOT(start, cp)) { 3736059Samurai if (buf[0]) 3746059Samurai break; /* finish analyzing .././../xxx/[..] */ 3756059Samurai dotdot++; 3766059Samurai cp += 2; 3776059Samurai if (*cp) 3786059Samurai cp++; 3796059Samurai } 3806059Samurai else 3816059Samurai *dp++ = *cp++; 38230715Sbrian 38346828Sbrian *dp = '\0'; 3846059Samurai while (dotdot > 0) 38544305Sbrian if ((dp = Strrchr(cwd, '/')) != NULL) { 38636285Sbrian# ifdef apollo 38744305Sbrian if (dp == &cwd[1]) 3886059Samurai slashslash = 1; 38944305Sbrian# endif /* apollo */ 39044305Sbrian *dp = '\0'; 39144305Sbrian dotdot--; 39263484Sbrian } 39336285Sbrian else 3946059Samurai break; 3956059Samurai 3966059Samurai if (!*cwd) { /* too many ..'s, starts with "/" */ 39730715Sbrian cwd[0] = '/'; 39836285Sbrian# ifdef apollo 3996059Samurai cwd[1] = '/'; 40047695Sbrian cwd[2] = '\0'; 40136285Sbrian# else /* !apollo */ 40236285Sbrian cwd[1] = '\0'; 4036059Samurai# endif /* apollo */ 4046059Samurai } 4056059Samurai# ifdef apollo 4066059Samurai else if (slashslash && cwd[1] == '\0') { 4076059Samurai cwd[1] = '/'; 4086059Samurai cwd[2] = '\0'; 40930715Sbrian } 41031343Sbrian# endif /* apollo */ 4116059Samurai 41231343Sbrian if (buf[0]) { 41331343Sbrian if ((TRM(cwd[(dotdot = (int) Strlen(cwd)) - 1])) != '/') 4146059Samurai cwd[dotdot++] = '/'; 4156059Samurai cwd[dotdot] = '\0'; 41636285Sbrian dp = Strspl(cwd, TRM(buf[0]) == '/' ? &buf[1] : buf); 41736285Sbrian xfree((ptr_t) cwd); 4186059Samurai cwd = dp; 4196059Samurai if ((TRM(cwd[(dotdot = (int) Strlen(cwd)) - 1])) == '/') 4206059Samurai cwd[--dotdot] = '\0'; 4216059Samurai } 4226059Samurai /* Reduction of ".." following the stuff we collected in buf 4236059Samurai * only makes sense if the directory item in buf really exists. 4246059Samurai * Avoid reduction of "-I../.." (typical compiler call) to "" 4256059Samurai * or "/usr/nonexistant/../bin" to "/usr/bin": 4266059Samurai */ 4276059Samurai if (cwd[0]) { 4286059Samurai struct stat exists; 42936285Sbrian if (0 != stat(short2str(cwd), &exists)) { 4306059Samurai xfree((ptr_t) cwd); 4316059Samurai return Strsave(start); 4326059Samurai } 43336285Sbrian } 4346059Samurai if (!*cp) 43536285Sbrian break; 4366059Samurai } 4376059Samurai return cwd; 43836285Sbrian } 4396059Samurai#endif /* S_IFLNK */ 44036285Sbrian return Strsave(cp); 4416059Samurai} 4426059Samurai 4436059Samurai 4446059Samurai/* 44536285Sbrian * dochngd - implement chdir command. 4466059Samurai */ 44736285Sbrian/*ARGSUSED*/ 4486059Samuraivoid 4496059Samuraidochngd(v, c) 4506059Samurai Char **v; 4516059Samurai struct command *c; 4526059Samurai{ 45330715Sbrian register Char *cp; 45444305Sbrian register struct directory *dp; 4556059Samurai int dflag = skipargs(&v, "plvn", "[-|<dir>]"); 45636285Sbrian 4576059Samurai USE(c); 45844305Sbrian printd = 0; 45944305Sbrian cp = (dflag & DIR_OLD) ? varval(STRowd) : *v; 4606059Samurai 4616059Samurai if (cp == NULL) { 4626059Samurai if ((cp = varval(STRhome)) == STRNULL || *cp == 0) 46346828Sbrian stderror(ERR_NAME | ERR_NOHOMEDIR); 4646059Samurai if (chdir(short2str(cp)) < 0) 46530715Sbrian stderror(ERR_NAME | ERR_CANTCHANGE); 46636285Sbrian cp = Strsave(cp); 46728679Sbrian } 4686059Samurai else if ((dflag & DIR_OLD) == 0 && v[1] != NULL) { 46936285Sbrian stderror(ERR_NAME | ERR_TOOMANY); 4706735Samurai /* NOTREACHED */ 4716059Samurai return; 47294894Sbrian } 4738857Srgrimes else if ((dp = dfind(cp)) != 0) { 47494894Sbrian char *tmp; 47554912Sbrian 47631962Sbrian printd = 1; 4776735Samurai if (chdir(tmp = short2str(dp->di_name)) < 0) 47837019Sbrian stderror(ERR_SYSTEM, tmp, strerror(errno)); 47994894Sbrian dcwd->di_prev->di_next = dcwd->di_next; 48054912Sbrian dcwd->di_next->di_prev = dcwd->di_prev; 4816059Samurai dfree(dcwd); 4826059Samurai dnewcwd(dp, dflag); 4836059Samurai return; 48495872Sbrian } 48595872Sbrian else 48695872Sbrian if ((cp = dfollow(cp)) == NULL) 48795872Sbrian return; 48895872Sbrian dp = (struct directory *) xcalloc(sizeof(struct directory), 1); 48995872Sbrian dp->di_name = cp; 49094894Sbrian dp->di_count = 0; 49194894Sbrian dp->di_next = dcwd->di_next; 49294894Sbrian dp->di_prev = dcwd->di_prev; 49394894Sbrian dp->di_prev->di_next = dp; 49494894Sbrian dp->di_next->di_prev = dp; 495134789Sbrian dfree(dcwd); 49694894Sbrian dnewcwd(dp, dflag); 49794894Sbrian} 49894894Sbrian 49994894Sbrianstatic Char * 50094894Sbriandgoto(cp) 50146828Sbrian Char *cp; 5026059Samurai{ 5036059Samurai Char *dp; 50437320Sbrian 50537320Sbrian if (!ABSOLUTEP(cp)) 50637320Sbrian { 50746686Sbrian register Char *p, *q; 50837320Sbrian int cwdlen; 50954912Sbrian 51046686Sbrian for (p = dcwd->di_name; *p++;) 51154912Sbrian continue; 51254912Sbrian if ((cwdlen = (int) (p - dcwd->di_name - 1)) == 1) /* root */ 51354912Sbrian cwdlen = 0; 51437320Sbrian for (p = cp; *p++;) 51537320Sbrian continue; 51637320Sbrian dp = (Char *) xmalloc((size_t)((cwdlen + (p - cp) + 1) * sizeof(Char))); 5176059Samurai for (p = dp, q = dcwd->di_name; (*p++ = *q++) != '\0';) 51836285Sbrian continue; 51936285Sbrian if (cwdlen) 52054912Sbrian p[-1] = '/'; 5216059Samurai else 5226059Samurai p--; /* don't add a / after root */ 52336285Sbrian for (q = cp; (*p++ = *q++) != '\0';) 52454912Sbrian continue; 5256059Samurai xfree((ptr_t) cp); 5266059Samurai cp = dp; 52736285Sbrian dp += cwdlen; 52836285Sbrian } 5296059Samurai else 53054912Sbrian dp = cp; 5316059Samurai 5326059Samurai#ifdef WINNT_NATIVE 53344305Sbrian cp = SAVE(getcwd(NULL, 0)); 53495872Sbrian#else /* !WINNT_NATIVE */ 53537995Sbrian cp = dcanon(cp, dp); 5366059Samurai#endif /* WINNT_NATIVE */ 5376059Samurai return cp; 5386059Samurai} 5396059Samurai 54036285Sbrian/* 54147695Sbrian * dfollow - change to arg directory; fall back on cdpath if not valid 54247695Sbrian */ 54336285Sbrianstatic Char * 54447695Sbriandfollow(cp) 54547695Sbrian register Char *cp; 5466059Samurai{ 54747695Sbrian register Char *dp; 54847695Sbrian struct varent *c; 5496059Samurai char ebuf[MAXPATHLEN]; 5506059Samurai int serrno; 55144305Sbrian 55244305Sbrian cp = globone(cp, G_ERROR); 55344305Sbrian#ifdef apollo 55444305Sbrian if (Strchr(cp, '`')) { 55544305Sbrian char *dptr, *ptr; 55644305Sbrian if (chdir(dptr = short2str(cp)) < 0) 55744305Sbrian stderror(ERR_SYSTEM, dptr, strerror(errno)); 55844305Sbrian else if ((ptr = getcwd(ebuf, sizeof(ebuf))) && *ptr != '\0') { 559102413Scharnier xfree((ptr_t) cp); 56044305Sbrian cp = Strsave(str2short(ptr)); 56136285Sbrian return dgoto(cp); 5626059Samurai } 5636059Samurai else 5646059Samurai stderror(ERR_SYSTEM, dptr, ebuf); 5656059Samurai } 56681634Sbrian#endif /* apollo */ 5676059Samurai 5686059Samurai (void) strncpy(ebuf, short2str(cp), MAXPATHLEN); 5696059Samurai ebuf[MAXPATHLEN-1] = '\0'; 5706059Samurai /* 5716059Samurai * if we are ignoring symlinks, try to fix relatives now. 5726059Samurai * if we are expading symlinks, it should be done by now. 5736059Samurai */ 5746059Samurai dp = dnormalize(cp, symlinks == SYM_IGNORE); 57536285Sbrian if (chdir(short2str(dp)) >= 0) { 57636285Sbrian xfree((ptr_t) cp); 57736285Sbrian return dgoto(dp); 57836285Sbrian } 57944305Sbrian else { 58036285Sbrian xfree((ptr_t) dp); 58136285Sbrian if (chdir(short2str(cp)) >= 0) 58263484Sbrian return dgoto(cp); 58336285Sbrian else if (errno != ENOENT && errno != ENOTDIR) 5846059Samurai stderror(ERR_SYSTEM, ebuf, strerror(errno)); 5856059Samurai serrno = errno; 5866059Samurai } 5876059Samurai 5886059Samurai if (cp[0] != '/' && !prefix(STRdotsl, cp) && !prefix(STRdotdotsl, cp) 5896059Samurai && (c = adrof(STRcdpath)) && c->vec != NULL) { 5906059Samurai Char **cdp; 59154912Sbrian register Char *p; 59244305Sbrian Char buf[MAXPATHLEN]; 59344305Sbrian 59444305Sbrian for (cdp = c->vec; *cdp; cdp++) { 59544305Sbrian for (dp = buf, p = *cdp; (*dp++ = *p++) != '\0';) 59663484Sbrian continue; 59744305Sbrian dp[-1] = '/'; 59844305Sbrian for (p = cp; (*dp++ = *p++) != '\0';) 59944305Sbrian continue; 60044305Sbrian /* 60144305Sbrian * We always want to fix the directory here 60244305Sbrian * If we are normalizing symlinks 60363484Sbrian */ 60444305Sbrian dp = dnormalize(buf, symlinks == SYM_IGNORE || 60544305Sbrian symlinks == SYM_EXPAND); 6066059Samurai if (chdir(short2str(dp)) >= 0) { 6076059Samurai printd = 1; 60830715Sbrian xfree((ptr_t) cp); 60936285Sbrian return dgoto(dp); 61028679Sbrian } 6116059Samurai else if (chdir(short2str(cp)) >= 0) { 61294894Sbrian printd = 1; 61394894Sbrian xfree((ptr_t) dp); 61494894Sbrian return dgoto(cp); 61594894Sbrian } 61694894Sbrian } 61794894Sbrian } 61894894Sbrian dp = varval(cp); 61994894Sbrian if ((dp[0] == '/' || dp[0] == '.') && chdir(short2str(dp)) >= 0) { 62094894Sbrian xfree((ptr_t) cp); 62194894Sbrian cp = Strsave(dp); 62294894Sbrian printd = 1; 62394894Sbrian return dgoto(cp); 62494894Sbrian } 62594894Sbrian xfree((ptr_t) cp); 62694894Sbrian /* 62794894Sbrian * on login source of ~/.cshdirs, errors are eaten. the dir stack is all 62894894Sbrian * directories we could get to. 629134789Sbrian */ 63094894Sbrian if (!bequiet) { 63194894Sbrian stderror(ERR_SYSTEM, ebuf, strerror(serrno)); 6326059Samurai return (NULL); 63328679Sbrian } 63428679Sbrian else 63536285Sbrian return (NULL); 6366059Samurai} 6376059Samurai 6386059Samurai 6396059Samurai/* 6406059Samurai * dopushd - push new directory onto directory stack. 64144305Sbrian * with no arguments exchange top and second. 6426059Samurai * with numeric argument (+n) bring it to top. 6436059Samurai */ 6446059Samurai/*ARGSUSED*/ 6456059Samuraivoid 6466059Samuraidopushd(v, c) 6476059Samurai Char **v; 6486059Samurai struct command *c; 64944305Sbrian{ 6506059Samurai register struct directory *dp; 65136285Sbrian register Char *cp; 65236285Sbrian int dflag = skipargs(&v, "plvn", " [-|<dir>|+<n>]"); 65336285Sbrian 65436285Sbrian USE(c); 65544305Sbrian printd = 1; 65636285Sbrian cp = (dflag & DIR_OLD) ? varval(STRowd) : *v; 65736285Sbrian 65863484Sbrian if (cp == NULL) { 65936285Sbrian if (adrof(STRpushdtohome)) { 6606059Samurai if ((cp = varval(STRhome)) == STRNULL || *cp == 0) 6616059Samurai stderror(ERR_NAME | ERR_NOHOMEDIR); 66236285Sbrian if (chdir(short2str(cp)) < 0) 6636059Samurai stderror(ERR_NAME | ERR_CANTCHANGE); 6646059Samurai cp = Strsave(cp); /* hmmm... PWP */ 66536285Sbrian if ((cp = dfollow(cp)) == NULL) 6666059Samurai return; 6676059Samurai dp = (struct directory *) xcalloc(sizeof(struct directory), 1); 66854912Sbrian dp->di_name = cp; 6696059Samurai dp->di_count = 0; 6706059Samurai dp->di_prev = dcwd; 67130715Sbrian dp->di_next = dcwd->di_next; 67236285Sbrian dcwd->di_next = dp; 67328679Sbrian dp->di_next->di_prev = dp; 6746059Samurai } 67536285Sbrian else { 6766735Samurai char *tmp; 67794894Sbrian 6788857Srgrimes if ((dp = dcwd->di_prev) == &dhead) 67954912Sbrian dp = dhead.di_prev; 68031962Sbrian if (dp == dcwd) 6816735Samurai stderror(ERR_NAME | ERR_NODIR); 68254912Sbrian if (chdir(tmp = short2str(dp->di_name)) < 0) 6836059Samurai stderror(ERR_SYSTEM, tmp, strerror(errno)); 6846059Samurai dp->di_prev->di_next = dp->di_next; 6856059Samurai dp->di_next->di_prev = dp->di_prev; 6866059Samurai dp->di_next = dcwd->di_next; 68728679Sbrian dp->di_prev = dcwd; 6886059Samurai dcwd->di_next->di_prev = dp; 6896059Samurai dcwd->di_next = dp; 6906059Samurai } 6916059Samurai } 69236285Sbrian else if ((dflag & DIR_OLD) == 0 && v[1] != NULL) { 69336285Sbrian stderror(ERR_NAME | ERR_TOOMANY); 69454912Sbrian /* NOTREACHED */ 6956059Samurai return; 6966059Samurai } 6976059Samurai else if ((dp = dfind(cp)) != NULL) { 69836285Sbrian char *tmp; 69954912Sbrian 7006059Samurai if (chdir(tmp = short2str(dp->di_name)) < 0) 7016059Samurai stderror(ERR_SYSTEM, tmp, strerror(errno)); 7026059Samurai /* 70354912Sbrian * kfk - 10 Feb 1984 - added new "extraction style" pushd +n 7046059Samurai */ 7056059Samurai if (adrof(STRdextract)) 7066059Samurai dextract(dp); 70754912Sbrian } 70836285Sbrian else { 70936285Sbrian register Char *ccp; 71036285Sbrian 71194894Sbrian if ((ccp = dfollow(cp)) == NULL) 71294894Sbrian return; 713134789Sbrian dp = (struct directory *) xcalloc(sizeof(struct directory), 1); 71436285Sbrian dp->di_name = ccp; 7156059Samurai dp->di_count = 0; 7166059Samurai dp->di_prev = dcwd; 7176059Samurai dp->di_next = dcwd->di_next; 7186059Samurai dcwd->di_next = dp; 71944305Sbrian dp->di_next->di_prev = dp; 7206059Samurai } 7216059Samurai dnewcwd(dp, dflag); 7226059Samurai} 72336285Sbrian 72436285Sbrian/* 72536285Sbrian * dfind - find a directory if specified by numeric (+n) argument 72636285Sbrian */ 72736285Sbrianstatic struct directory * 7286059Samuraidfind(cp) 7296059Samurai register Char *cp; 7306059Samurai{ 7316059Samurai register struct directory *dp; 7326059Samurai register int i; 7336059Samurai register Char *ep; 73454912Sbrian 7356059Samurai if (*cp++ != '+') 7366059Samurai return (0); 73730715Sbrian for (ep = cp; Isdigit(*ep); ep++) 73836285Sbrian continue; 73928679Sbrian if (*ep) 7406059Samurai return (0); 7416059Samurai i = getn(cp); 74236285Sbrian if (i <= 0) 74336285Sbrian return (0); 74436285Sbrian for (dp = dcwd; i != 0; i--) { 74536285Sbrian if ((dp = dp->di_prev) == &dhead) 7466059Samurai dp = dp->di_prev; 7476059Samurai if (dp == dcwd) 7486059Samurai stderror(ERR_NAME | ERR_DEEP); 7496059Samurai } 7506059Samurai return (dp); 7516059Samurai} 75236285Sbrian 7536059Samurai/* 7546059Samurai * dopopd - pop a directory out of the directory stack 7556059Samurai * with a numeric argument just discard it. 75636285Sbrian */ 7576059Samurai/*ARGSUSED*/ 7586059Samuraivoid 7596059Samuraidopopd(v, c) 76036285Sbrian Char **v; 76136285Sbrian struct command *c; 76244305Sbrian{ 76344305Sbrian Char *cp; 76426353Sbrian register struct directory *dp, *p = NULL; 76526353Sbrian int dflag = skipargs(&v, "plvn", " [-|+<n>]"); 76636285Sbrian 76744305Sbrian USE(c); 7686059Samurai printd = 1; 7696059Samurai cp = (dflag & DIR_OLD) ? varval(STRowd) : *v; 77054912Sbrian 7716059Samurai if (cp == NULL) 7726059Samurai dp = dcwd; 77330715Sbrian else if ((dflag & DIR_OLD) == 0 && v[1] != NULL) { 774134789Sbrian stderror(ERR_NAME | ERR_TOOMANY); 77528679Sbrian /* NOTREACHED */ 7766059Samurai return; 7776059Samurai } 77836285Sbrian else if ((dp = dfind(cp)) == 0) 77936285Sbrian stderror(ERR_NAME | ERR_BADDIR); 7806059Samurai if (dp->di_prev == &dhead && dp->di_next == &dhead) 78136285Sbrian stderror(ERR_NAME | ERR_EMPTY); 7826059Samurai if (dp == dcwd) { 7836059Samurai char *tmp; 78436285Sbrian 7856059Samurai if ((p = dp->di_prev) == &dhead) 78636285Sbrian p = dhead.di_prev; 7876059Samurai if (chdir(tmp = short2str(p->di_name)) < 0) 7886059Samurai stderror(ERR_SYSTEM, tmp, strerror(errno)); 7896059Samurai } 7906059Samurai dp->di_prev->di_next = dp->di_next; 7916059Samurai dp->di_next->di_prev = dp->di_prev; 79236285Sbrian if (dp == dcwd) { 7936059Samurai dnewcwd(p, dflag); 7946059Samurai } 79536285Sbrian else { 7966059Samurai printdirs(dflag); 7976059Samurai } 79854912Sbrian dfree(dp); 7996059Samurai} 8006059Samurai 80130715Sbrian/* 80236285Sbrian * dfree - free the directory (or keep it if it still has ref count) 80328679Sbrian */ 8046059Samuraivoid 80536285Sbriandfree(dp) 806134789Sbrian register struct directory *dp; 807134789Sbrian{ 80894894Sbrian 8098857Srgrimes if (dp->di_count != 0) { 81054912Sbrian dp->di_next = dp->di_prev = 0; 81131962Sbrian } 812134789Sbrian else { 81354912Sbrian xfree((ptr_t) dp->di_name); 8146059Samurai xfree((ptr_t) dp); 8156059Samurai } 8166059Samurai} 81763484Sbrian 81863484Sbrian/* 8196059Samurai * dcanon - canonicalize the pathname, removing excess ./ and ../ etc. 82028679Sbrian * we are of course assuming that the file system is standardly 8216059Samurai * constructed (always have ..'s, directories have links) 8226059Samurai */ 8236059SamuraiChar * 8246059Samuraidcanon(cp, p) 82536285Sbrian register Char *cp, *p; 82636285Sbrian{ 82754912Sbrian register Char *sp; 8286059Samurai register Char *p1, *p2; /* general purpose */ 8296059Samurai bool slash; 8306059Samurai#ifdef apollo 83136285Sbrian bool slashslash; 83254912Sbrian#endif /* apollo */ 8336059Samurai size_t clen; 8346059Samurai 8356059Samurai#ifdef S_IFLNK /* if we have symlinks */ 83654912Sbrian Char link[MAXPATHLEN]; 8376059Samurai char tlink[MAXPATHLEN]; 8386059Samurai int cc; 8396059Samurai Char *newcp; 84054912Sbrian#endif /* S_IFLNK */ 84136285Sbrian 84236285Sbrian /* 84336285Sbrian * if the path given is too long truncate it! 84494894Sbrian */ 84594894Sbrian if ((clen = Strlen(cp)) >= MAXPATHLEN) 846134789Sbrian cp[clen = MAXPATHLEN - 1] = '\0'; 84736285Sbrian 8486059Samurai /* 8496059Samurai * christos: if the path given does not start with a slash prepend cwd. If 8506059Samurai * cwd does not start with a slash or the result would be too long try to 8516059Samurai * correct it. 85244305Sbrian */ 8536059Samurai if (!ABSOLUTEP(cp)) { 8546059Samurai Char tmpdir[MAXPATHLEN]; 8556059Samurai size_t len; 85636285Sbrian 85736285Sbrian p1 = varval(STRcwd); 85836285Sbrian if (p1 == STRNULL || !ABSOLUTEP(p1)) { 85936285Sbrian char *tmp = (char *)getcwd((char *)tmpdir, sizeof(tmpdir)); 86036285Sbrian if (tmp == NULL || *tmp == '\0') { 8616059Samurai xprintf("%s: %s\n", progname, strerror(errno)); 8626059Samurai set(STRcwd, SAVE("/"), VAR_READWRITE|VAR_NOGLOB); 8636059Samurai } else { 8646059Samurai set(STRcwd, SAVE(tmp), VAR_READWRITE|VAR_NOGLOB); 8656059Samurai } 86654912Sbrian p1 = varval(STRcwd); 8676059Samurai } 8686059Samurai len = Strlen(p1); 86930715Sbrian if (len + clen + 1 >= MAXPATHLEN) 870134789Sbrian cp[MAXPATHLEN - (len + 1)] = '\0'; 871134789Sbrian (void) Strcpy(tmpdir, p1); 8726059Samurai (void) Strcat(tmpdir, STRslash); 87354912Sbrian (void) Strcat(tmpdir, cp); 8746059Samurai xfree((ptr_t) cp); 8756059Samurai cp = p = Strsave(tmpdir); 87630715Sbrian } 877134789Sbrian 8786059Samurai#ifdef apollo 87936285Sbrian slashslash = (cp[0] == '/' && cp[1] == '/'); 88046828Sbrian#endif /* apollo */ 8816059Samurai 88254912Sbrian while (*p) { /* for each component */ 88354912Sbrian sp = p; /* save slash address */ 88446828Sbrian while (*++p == '/') /* flush extra slashes */ 88546828Sbrian continue; 88646828Sbrian if (p != ++sp) 88746828Sbrian for (p1 = sp, p2 = p; (*p1++ = *p2++) != '\0';) 88836285Sbrian continue; 88936285Sbrian p = sp; /* save start of component */ 8906059Samurai slash = 0; 8916059Samurai if (*p) 8926059Samurai while (*++p) /* find next slash or end of path */ 89336285Sbrian if (*p == '/') { 89436285Sbrian slash = 1; 89536285Sbrian *p = 0; 89636285Sbrian break; 89736285Sbrian } 8986059Samurai 8996059Samurai#ifdef apollo 90036285Sbrian if (&cp[1] == sp && sp[0] == '.' && sp[1] == '.' && sp[2] == '\0') 90136285Sbrian slashslash = 1; 90244359Sbrian#endif /* apollo */ 90344359Sbrian if (*sp == '\0') { /* if component is null */ 90436285Sbrian if (--sp == cp) /* if path is one char (i.e. /) */ 90536285Sbrian break; 90636285Sbrian else 90736285Sbrian *sp = '\0'; 90893420Sbrian } 90936285Sbrian else if (sp[0] == '.' && sp[1] == 0) { 91036285Sbrian if (slash) { 91136285Sbrian for (p1 = sp, p2 = p + 1; (*p1++ = *p2++) != '\0';) 91236285Sbrian continue; 91344359Sbrian p = --sp; 91444359Sbrian } 9156059Samurai else if (--sp != cp) 9166059Samurai *sp = '\0'; 91749599Sbrian else 91849599Sbrian sp[1] = '\0'; 91949599Sbrian } 92049599Sbrian else if (sp[0] == '.' && sp[1] == '.' && sp[2] == 0) { 92149599Sbrian /* 92249599Sbrian * We have something like "yyy/xxx/..", where "yyy" can be null or 92349599Sbrian * a path starting at /, and "xxx" is a single component. Before 92481634Sbrian * compressing "xxx/..", we want to expand "yyy/xxx", if it is a 92581634Sbrian * symbolic link. 92681897Sbrian */ 92781634Sbrian *--sp = 0; /* form the pathname for readlink */ 92881634Sbrian#ifdef S_IFLNK /* if we have symlinks */ 92981634Sbrian if (sp != cp && /* symlinks != SYM_IGNORE && */ 93081634Sbrian (cc = readlink(short2str(cp), tlink, 93181634Sbrian sizeof tlink)) >= 0) { 93281634Sbrian tlink[cc] = '\0'; 93336285Sbrian (void) Strncpy(link, str2short(tlink), 93436285Sbrian sizeof(link) / sizeof(Char)); 93536285Sbrian link[sizeof(link) / sizeof(Char) - 1] = '\0'; 93636285Sbrian 93736285Sbrian if (slash) 93836285Sbrian *p = '/'; 93936285Sbrian /* 94036285Sbrian * Point p to the '/' in "/..", and restore the '/'. 94136285Sbrian */ 94236285Sbrian *(p = sp) = '/'; 94336285Sbrian /* 9446059Samurai * find length of p 94554912Sbrian */ 9466059Samurai for (p1 = p; *p1++;) 9476059Samurai continue; 94830715Sbrian if (*link != '/') { 94936285Sbrian /* 9506059Samurai * Relative path, expand it between the "yyy/" and the 95136285Sbrian * "/..". First, back sp up to the character past "yyy/". 9526059Samurai */ 95336285Sbrian while (*--sp != '/') 9546059Samurai continue; 95554912Sbrian sp++; 95654912Sbrian *sp = 0; 95752942Sbrian /* 95852942Sbrian * New length is "yyy/" + link + "/.." and rest 95936285Sbrian */ 96038814Sbrian p1 = newcp = (Char *) xmalloc((size_t) 96136285Sbrian (((sp - cp) + cc + (p1 - p)) * 96251970Sbrian sizeof(Char))); 96351970Sbrian /* 96451970Sbrian * Copy new path into newcp 96536285Sbrian */ 96636285Sbrian for (p2 = cp; (*p1++ = *p2++) != '\0';) 96736285Sbrian continue; 96838814Sbrian for (p1--, p2 = link; (*p1++ = *p2++) != '\0';) 96952942Sbrian continue; 97052942Sbrian for (p1--, p2 = p; (*p1++ = *p2++) != '\0';) 97136285Sbrian continue; 9726059Samurai /* 97354912Sbrian * Restart canonicalization at expanded "/xxx". 9746059Samurai */ 9756059Samurai p = sp - cp - 1 + newcp; 97630715Sbrian } 977134789Sbrian else { 9786059Samurai /* 97947169Sbrian * New length is link + "/.." and rest 98047169Sbrian */ 9816059Samurai p1 = newcp = (Char *) xmalloc((size_t) 98254912Sbrian ((cc + (p1 - p)) * sizeof(Char))); 9836059Samurai /* 9846059Samurai * Copy new path into newcp 98530715Sbrian */ 986134789Sbrian for (p2 = link; (*p1++ = *p2++) != '\0';) 987134789Sbrian continue; 9886059Samurai for (p1--, p2 = p; (*p1++ = *p2++) != '\0';) 98954912Sbrian continue; 9906059Samurai /* 9916059Samurai * Restart canonicalization at beginning 99230715Sbrian */ 99346828Sbrian p = newcp; 9946059Samurai } 99563484Sbrian xfree((ptr_t) cp); 99663484Sbrian cp = newcp; 99763484Sbrian#ifdef apollo 99863484Sbrian slashslash = (cp[0] == '/' && cp[1] == '/'); 99963484Sbrian#endif /* apollo */ 100063484Sbrian continue; /* canonicalize the link */ 100163484Sbrian } 100263484Sbrian#endif /* S_IFLNK */ 100363484Sbrian *sp = '/'; 100463484Sbrian if (sp != cp) 100563484Sbrian while (*--sp != '/') 100663484Sbrian continue; 100763484Sbrian if (slash) { 100863484Sbrian for (p1 = sp + 1, p2 = p + 1; (*p1++ = *p2++) != '\0';) 100963484Sbrian continue; 101063484Sbrian p = sp; 101154912Sbrian } 10126059Samurai else if (cp == sp) 10136059Samurai *++sp = '\0'; 101430715Sbrian else 1015134789Sbrian *sp = '\0'; 1016134789Sbrian } 10176059Samurai else { /* normal dir name (not . or .. or nothing) */ 101854912Sbrian 10196059Samurai#ifdef S_IFLNK /* if we have symlinks */ 10206059Samurai if (sp != cp && symlinks == SYM_CHASE && 102130715Sbrian (cc = readlink(short2str(cp), tlink, 102236285Sbrian sizeof tlink)) >= 0) { 10236059Samurai tlink[cc] = '\0'; 102478411Sbrian (void) Strncpy(link, str2short(tlink), 102578411Sbrian sizeof(link) / sizeof(Char)); 102678411Sbrian link[sizeof(link) / sizeof(Char) - 1] = '\0'; 102778411Sbrian 102878411Sbrian /* 102978411Sbrian * restore the '/'. 103078411Sbrian */ 103178411Sbrian if (slash) 103278411Sbrian *p = '/'; 103354912Sbrian 10346059Samurai /* 10356059Samurai * point sp to p (rather than backing up). 103630715Sbrian */ 103736285Sbrian sp = p; 10386059Samurai 103936285Sbrian /* 104054912Sbrian * find length of p 10416059Samurai */ 10426059Samurai for (p1 = p; *p1++;) 10436059Samurai continue; 104436285Sbrian if (*link != '/') { 10456059Samurai /* 1046134789Sbrian * Relative path, expand it between the "yyy/" and the 104746686Sbrian * remainder. First, back sp up to the character past 104831514Sbrian * "yyy/". 10496059Samurai */ 105054912Sbrian while (*--sp != '/') 10516059Samurai continue; 105254912Sbrian sp++; 10536059Samurai *sp = 0; 10546059Samurai /* 105546686Sbrian * New length is "yyy/" + link + "/.." and rest 105652942Sbrian */ 105763484Sbrian p1 = newcp = (Char *) xmalloc((size_t) 1058134833Smarcel (((sp - cp) + cc + (p1 - p)) 105963484Sbrian * sizeof(Char))); 106063484Sbrian /* 106163484Sbrian * Copy new path into newcp 106260957Sbrian */ 106352942Sbrian for (p2 = cp; (*p1++ = *p2++) != '\0';) 106446686Sbrian continue; 106546686Sbrian for (p1--, p2 = link; (*p1++ = *p2++) != '\0';) 106636285Sbrian continue; 106736285Sbrian for (p1--, p2 = p; (*p1++ = *p2++) != '\0';) 106836285Sbrian continue; 106936285Sbrian /* 107036285Sbrian * Restart canonicalization at expanded "/xxx". 107137010Sbrian */ 107254912Sbrian p = sp - cp - 1 + newcp; 107354912Sbrian } 107454912Sbrian else { 107554912Sbrian /* 10766059Samurai * New length is link + the rest 10776059Samurai */ 10786059Samurai p1 = newcp = (Char *) xmalloc((size_t) 107946686Sbrian ((cc + (p1 - p)) * sizeof(Char))); 108046686Sbrian /* 108136285Sbrian * Copy new path into newcp 108236285Sbrian */ 108394894Sbrian for (p2 = link; (*p1++ = *p2++) != '\0';) 108436285Sbrian continue; 108536285Sbrian for (p1--, p2 = p; (*p1++ = *p2++) != '\0';) 108636285Sbrian continue; 108736285Sbrian /* 108894894Sbrian * Restart canonicalization at beginning 108936285Sbrian */ 109046686Sbrian p = newcp; 109136285Sbrian } 109236285Sbrian xfree((ptr_t) cp); 109336285Sbrian cp = newcp; 109446686Sbrian#ifdef apollo 10956059Samurai slashslash = (cp[0] == '/' && cp[1] == '/'); 109636285Sbrian#endif /* apollo */ 109778411Sbrian continue; /* canonicalize the link */ 109836285Sbrian } 109936285Sbrian#endif /* S_IFLNK */ 110036285Sbrian if (slash) 110136285Sbrian *p = '/'; 110278411Sbrian } 110336285Sbrian } 110436285Sbrian 110536285Sbrian /* 1106134789Sbrian * fix home... 110736285Sbrian */ 110836285Sbrian#ifdef S_IFLNK 110936285Sbrian p1 = varval(STRhome); 111036285Sbrian cc = (int) Strlen(p1); 111137060Sbrian /* 111237060Sbrian * See if we're not in a subdir of STRhome 111337160Sbrian */ 111437160Sbrian if (p1 && *p1 == '/' && (Strncmp(p1, cp, (size_t) cc) != 0 || 111537160Sbrian (cp[cc] != '/' && cp[cc] != '\0'))) { 111637160Sbrian static ino_t home_ino = (ino_t) -1; 111744305Sbrian static dev_t home_dev = (dev_t) -1; 111837160Sbrian static Char *home_ptr = NULL; 111937160Sbrian struct stat statbuf; 112037160Sbrian int found; 112137160Sbrian 112237160Sbrian /* 112337160Sbrian * Get dev and ino of STRhome 112437160Sbrian */ 112537060Sbrian if (home_ptr != p1 && 112637060Sbrian stat(short2str(p1), &statbuf) != -1) { 112744305Sbrian home_dev = statbuf.st_dev; 112844305Sbrian home_ino = statbuf.st_ino; 112944305Sbrian home_ptr = p1; 113037060Sbrian } 113137060Sbrian /* 113237060Sbrian * Start comparing dev & ino backwards 113337060Sbrian */ 113437060Sbrian p2 = Strncpy(link, cp, sizeof(link) / sizeof(Char)); 113537060Sbrian link[sizeof(link) / sizeof(Char) - 1] = '\0'; 113637060Sbrian found = 0; 113794894Sbrian while (*p2 && stat(short2str(p2), &statbuf) != -1) { 113894894Sbrian if (DEV_DEV_COMPARE(statbuf.st_dev, home_dev) && 113994894Sbrian statbuf.st_ino == home_ino) { 114094894Sbrian found = 1; 114194894Sbrian break; 114294894Sbrian } 114394894Sbrian if ((sp = Strrchr(p2, '/')) != NULL) 114494894Sbrian *sp = '\0'; 114594894Sbrian } 114694894Sbrian /* 114794894Sbrian * See if we found it 114894894Sbrian */ 114994894Sbrian if (*p2 && found) { 115094894Sbrian /* 115198244Sbrian * Use STRhome to make '~' work 115298244Sbrian */ 115394894Sbrian newcp = Strspl(p1, cp + Strlen(p2)); 115494894Sbrian xfree((ptr_t) cp); 115594894Sbrian cp = newcp; 115694894Sbrian } 115794894Sbrian } 115894894Sbrian#endif /* S_IFLNK */ 115994894Sbrian 116094894Sbrian#ifdef apollo 116194894Sbrian if (slashslash) { 1162134789Sbrian if (cp[1] != '/') { 116394894Sbrian p = (Char *) xmalloc((size_t) (Strlen(cp) + 2) * sizeof(Char)); 1164134789Sbrian *p = '/'; 116594894Sbrian (void) Strcpy(&p[1], cp); 116694894Sbrian xfree((ptr_t) cp); 1167134789Sbrian cp = p; 116894894Sbrian } 116994894Sbrian } 117094894Sbrian if (cp[1] == '/' && cp[2] == '/') 117194894Sbrian (void) Strcpy(&cp[1], &cp[2]); 117294894Sbrian#endif /* apollo */ 117394894Sbrian return cp; 117494894Sbrian} 117594894Sbrian 117694894Sbrian 117794894Sbrian/* 117894894Sbrian * dnewcwd - make a new directory in the loop the current one 117994894Sbrian */ 118094894Sbrianstatic void 118194894Sbriandnewcwd(dp, dflag) 118294894Sbrian register struct directory *dp; 118394894Sbrian int dflag; 118494894Sbrian{ 118594894Sbrian int print; 118694894Sbrian 118794894Sbrian if (adrof(STRdunique)) { 118894894Sbrian struct directory *dn; 118994894Sbrian 119094894Sbrian for (dn = dhead.di_prev; dn != &dhead; dn = dn->di_prev) 119194894Sbrian if (dn != dp && Strcmp(dn->di_name, dp->di_name) == 0) { 119294894Sbrian dn->di_next->di_prev = dn->di_prev; 119394894Sbrian dn->di_prev->di_next = dn->di_next; 119494894Sbrian dfree(dn); 119594894Sbrian break; 119694894Sbrian } 119794894Sbrian } 119894894Sbrian dcwd = dp; 119994894Sbrian dset(dcwd->di_name); 120094894Sbrian dgetstack(); 120194894Sbrian print = printd; /* if printd is set, print dirstack... */ 120294894Sbrian if (adrof(STRpushdsilent)) /* but pushdsilent overrides printd... */ 120394894Sbrian print = 0; 120494894Sbrian if (dflag & DIR_PRINT) /* but DIR_PRINT overrides pushdsilent... */ 120594894Sbrian print = 1; 120694894Sbrian if (bequiet) /* and bequiet overrides everything */ 120794894Sbrian print = 0; 120894894Sbrian if (print) 120994894Sbrian printdirs(dflag); 121094894Sbrian cwd_cmd(); /* PWP: run the defined cwd command */ 121194894Sbrian} 121294894Sbrian 121394894Sbrianvoid 1214dsetstack() 1215{ 1216 Char **cp; 1217 struct varent *vp; 1218 struct directory *dn, *dp; 1219 1220 if ((vp = adrof(STRdirstack)) == NULL || vp->vec == NULL) 1221 return; 1222 1223 /* Free the whole stack */ 1224 while ((dn = dhead.di_prev) != &dhead) { 1225 dn->di_next->di_prev = dn->di_prev; 1226 dn->di_prev->di_next = dn->di_next; 1227 if (dn != dcwd) 1228 dfree(dn); 1229 } 1230 1231 /* thread the current working directory */ 1232 dhead.di_prev = dhead.di_next = dcwd; 1233 dcwd->di_next = dcwd->di_prev = &dhead; 1234 1235 /* put back the stack */ 1236 for (cp = vp->vec; cp && *cp && **cp; cp++) { 1237 dp = (struct directory *) xcalloc(sizeof(struct directory), 1); 1238 dp->di_name = Strsave(*cp); 1239 dp->di_count = 0; 1240 dp->di_prev = dcwd; 1241 dp->di_next = dcwd->di_next; 1242 dcwd->di_next = dp; 1243 dp->di_next->di_prev = dp; 1244 } 1245 dgetstack(); /* Make $dirstack reflect the current state */ 1246} 1247 1248static void 1249dgetstack() 1250{ 1251 int i = 0; 1252 Char **dblk, **dbp; 1253 struct directory *dn; 1254 1255 if (adrof(STRdirstack) == NULL) 1256 return; 1257 1258 for (dn = dhead.di_prev; dn != &dhead; dn = dn->di_prev, i++) 1259 continue; 1260 dbp = dblk = (Char**) xmalloc((size_t) (i + 1) * sizeof(Char *)); 1261 for (dn = dhead.di_prev; dn != &dhead; dn = dn->di_prev, dbp++) 1262 *dbp = Strsave(dn->di_name); 1263 *dbp = NULL; 1264 setq(STRdirstack, dblk, &shvhed, VAR_READWRITE); 1265} 1266 1267/* 1268 * getstakd - added by kfk 17 Jan 1984 1269 * Support routine for the stack hack. Finds nth directory in 1270 * the directory stack, or finds last directory in stack. 1271 */ 1272int 1273getstakd(s, cnt) 1274 Char *s; 1275 int cnt; 1276{ 1277 struct directory *dp; 1278 1279 dp = dcwd; 1280 if (cnt < 0) { /* < 0 ==> last dir requested. */ 1281 dp = dp->di_next; 1282 if (dp == &dhead) 1283 dp = dp->di_next; 1284 } 1285 else { 1286 while (cnt-- > 0) { 1287 dp = dp->di_prev; 1288 if (dp == &dhead) 1289 dp = dp->di_prev; 1290 if (dp == dcwd) 1291 return (0); 1292 } 1293 } 1294 (void) Strncpy(s, dp->di_name, BUFSIZE); 1295 s[BUFSIZE - 1] = '\0'; 1296 return (1); 1297} 1298 1299/* 1300 * Karl Kleinpaste - 10 Feb 1984 1301 * Added dextract(), which is used in pushd +n. 1302 * Instead of just rotating the entire stack around, dextract() 1303 * lets the user have the nth dir extracted from its current 1304 * position, and pushes it onto the top. 1305 */ 1306static void 1307dextract(dp) 1308 struct directory *dp; 1309{ 1310 if (dp == dcwd) 1311 return; 1312 dp->di_next->di_prev = dp->di_prev; 1313 dp->di_prev->di_next = dp->di_next; 1314 dp->di_next = dcwd->di_next; 1315 dp->di_prev = dcwd; 1316 dp->di_next->di_prev = dp; 1317 dcwd->di_next = dp; 1318} 1319 1320void 1321loaddirs(fname) 1322 Char *fname; 1323{ 1324 static Char *loaddirs_cmd[] = { STRsource, NULL, NULL }; 1325 1326 bequiet = 1; 1327 if (fname) 1328 loaddirs_cmd[1] = fname; 1329 else if ((fname = varval(STRdirsfile)) != STRNULL) 1330 loaddirs_cmd[1] = fname; 1331 else 1332 loaddirs_cmd[1] = STRtildotdirs; 1333 dosource(loaddirs_cmd, (struct command *)0); 1334 bequiet = 0; 1335} 1336 1337/* 1338 * create a file called ~/.cshdirs which has a sequence 1339 * of pushd commands which will restore the dir stack to 1340 * its state before exit/logout. remember that the order 1341 * is reversed in the file because we are pushing. 1342 * -strike 1343 */ 1344void 1345recdirs(fname, def) 1346 Char *fname; 1347 int def; 1348{ 1349 int fp, ftmp, oldidfds; 1350 int cdflag = 0; 1351 extern struct directory *dcwd; 1352 struct directory *dp; 1353 unsigned int num; 1354 Char *snum; 1355 Char qname[MAXPATHLEN*2]; 1356 1357 if (fname == NULL && !def) 1358 return; 1359 1360 if (fname == NULL) { 1361 if ((fname = varval(STRdirsfile)) == STRNULL) 1362 fname = Strspl(varval(STRhome), &STRtildotdirs[1]); 1363 else 1364 fname = Strsave(fname); 1365 } 1366 else 1367 fname = globone(fname, G_ERROR); 1368 1369 if ((fp = creat(short2str(fname), 0600)) == -1) { 1370 xfree((ptr_t) fname); 1371 return; 1372 } 1373 1374 if ((snum = varval(STRsavedirs)) == STRNULL || snum[0] == '\0') 1375 num = (unsigned int) ~0; 1376 else 1377 num = (unsigned int) atoi(short2str(snum)); 1378 1379 oldidfds = didfds; 1380 didfds = 0; 1381 ftmp = SHOUT; 1382 SHOUT = fp; 1383 1384 dp = dcwd->di_next; 1385 do { 1386 if (dp == &dhead) 1387 continue; 1388 1389 if (cdflag == 0) { 1390 cdflag = 1; 1391 xprintf("cd %S\n", quote_meta(qname, dp->di_name)); 1392 } 1393 else 1394 xprintf("pushd %S\n", quote_meta(qname, dp->di_name)); 1395 1396 if (num-- == 0) 1397 break; 1398 1399 } while ((dp = dp->di_next) != dcwd->di_next); 1400 1401 (void) close(fp); 1402 SHOUT = ftmp; 1403 didfds = oldidfds; 1404 xfree((ptr_t) fname); 1405} 1406