sh.dir.c revision 145479
1205194Sdelphij/* $Header: /src/pub/tcsh/sh.dir.c,v 3.66 2005/03/03 16:40:53 kim Exp $ */ 2250261Sdelphij/* 3205194Sdelphij * sh.dir.c: Directory manipulation functions 4205194Sdelphij */ 5205194Sdelphij/*- 6206002Sdelphij * Copyright (c) 1980, 1991 The Regents of the University of California. 7206002Sdelphij * All rights reserved. 8205194Sdelphij * 9206002Sdelphij * Redistribution and use in source and binary forms, with or without 10205194Sdelphij * modification, are permitted provided that the following conditions 11237410Sdelphij * are met: 12237410Sdelphij * 1. Redistributions of source code must retain the above copyright 13237410Sdelphij * notice, this list of conditions and the following disclaimer. 14206708Sdelphij * 2. Redistributions in binary form must reproduce the above copyright 15205194Sdelphij * notice, this list of conditions and the following disclaimer in the 16205194Sdelphij * documentation and/or other materials provided with the distribution. 17205194Sdelphij * 3. Neither the name of the University nor the names of its contributors 18205194Sdelphij * may be used to endorse or promote products derived from this software 19237410Sdelphij * without specific prior written permission. 20205194Sdelphij * 21205194Sdelphij * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22205194Sdelphij * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23237410Sdelphij * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24205194Sdelphij * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25206002Sdelphij * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26205194Sdelphij * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27205194Sdelphij * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28205194Sdelphij * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29205194Sdelphij * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30205194Sdelphij * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31205194Sdelphij * SUCH DAMAGE. 32205194Sdelphij */ 33205194Sdelphij#include "sh.h" 34205194Sdelphij#include "ed.h" 35205194Sdelphij 36206924SdelphijRCSID("$Id: sh.dir.c,v 3.66 2005/03/03 16:40:53 kim Exp $") 37205194Sdelphij 38205194Sdelphij/* 39205194Sdelphij * C Shell - directory management 40205194Sdelphij */ 41205194Sdelphij 42205194Sdelphijstatic void dstart __P((const char *)); 43205194Sdelphijstatic struct directory *dfind __P((Char *)); 44205194Sdelphijstatic Char *dfollow __P((Char *)); 45205194Sdelphijstatic void printdirs __P((int)); 46205194Sdelphijstatic Char *dgoto __P((Char *)); 47205194Sdelphijstatic void dnewcwd __P((struct directory *, int)); 48205194Sdelphijstatic void dset __P((Char *)); 49205194Sdelphijstatic void dextract __P((struct directory *)); 50205194Sdelphijstatic int skipargs __P((Char ***, const char *, 51205194Sdelphij const char *)); 52205194Sdelphijstatic void dgetstack __P((void)); 53205194Sdelphij 54205194Sdelphijstatic struct directory dhead INIT_ZERO_STRUCT; /* "head" of loop */ 55205194Sdelphijstatic int printd; /* force name to be printed */ 56205194Sdelphij 57205194Sdelphijint bequiet = 0; /* do not print dir stack -strike */ 58205194Sdelphij 59205194Sdelphijstatic void 60205194Sdelphijdstart(from) 61205194Sdelphij const char *from; 62205194Sdelphij{ 63205194Sdelphij xprintf(CGETS(12, 1, "%s: Trying to start from \"%s\"\n"), progname, from); 64205194Sdelphij} 65205194Sdelphij 66205194Sdelphij/* 67205194Sdelphij * dinit - initialize current working directory 68205194Sdelphij */ 69205194Sdelphijvoid 70205194Sdelphijdinit(hp) 71205194Sdelphij Char *hp; 72205194Sdelphij{ 73205194Sdelphij char *tcp; 74205194Sdelphij Char *cp; 75206002Sdelphij struct directory *dp; 76205194Sdelphij char path[MAXPATHLEN]; 77205194Sdelphij 78205194Sdelphij /* Don't believe the login shell home, because it may be a symlink */ 79205194Sdelphij tcp = (char *) getcwd(path, sizeof(path)); 80205194Sdelphij if (tcp == NULL || *tcp == '\0') { 81237410Sdelphij xprintf("%s: %s\n", progname, strerror(errno)); 82205194Sdelphij if (hp && *hp) { 83205194Sdelphij tcp = short2str(hp); 84237410Sdelphij dstart(tcp); 85205194Sdelphij if (chdir(tcp) == -1) 86205194Sdelphij cp = NULL; 87205194Sdelphij else 88205194Sdelphij cp = Strsave(hp); 89237410Sdelphij } 90205194Sdelphij else 91205194Sdelphij cp = NULL; 92205194Sdelphij if (cp == NULL) { 93205194Sdelphij dstart("/"); 94205194Sdelphij if (chdir("/") == -1) 95237410Sdelphij /* I am not even try to print an error message! */ 96205194Sdelphij xexit(1); 97205194Sdelphij cp = SAVE("/"); 98205194Sdelphij } 99205194Sdelphij } 100237410Sdelphij else { 101237410Sdelphij#ifdef S_IFLNK 102237410Sdelphij struct stat swd, shp; 103237410Sdelphij 104237410Sdelphij /* 105237410Sdelphij * See if $HOME is the working directory we got and use that 106237410Sdelphij */ 107237410Sdelphij if (hp && *hp && 108205194Sdelphij stat(tcp, &swd) != -1 && stat(short2str(hp), &shp) != -1 && 109237410Sdelphij DEV_DEV_COMPARE(swd.st_dev, shp.st_dev) && 110237410Sdelphij swd.st_ino == shp.st_ino) 111237410Sdelphij cp = Strsave(hp); 112237410Sdelphij else { 113205194Sdelphij char *cwd; 114250261Sdelphij 115205194Sdelphij /* 116205194Sdelphij * use PWD if we have it (for subshells) 117205194Sdelphij */ 118205194Sdelphij if ((cwd = getenv("PWD")) != NULL) { 119205194Sdelphij if (stat(cwd, &shp) != -1 && 120205194Sdelphij DEV_DEV_COMPARE(swd.st_dev, shp.st_dev) && 121205194Sdelphij swd.st_ino == shp.st_ino) 122205194Sdelphij tcp = cwd; 123205194Sdelphij } 124205194Sdelphij cp = dcanon(SAVE(tcp), STRNULL); 125237410Sdelphij } 126205194Sdelphij#else /* S_IFLNK */ 127205194Sdelphij cp = dcanon(SAVE(tcp), STRNULL); 128205194Sdelphij#endif /* S_IFLNK */ 129205194Sdelphij } 130205194Sdelphij 131205194Sdelphij dp = (struct directory *) xcalloc(sizeof(struct directory), 1); 132205194Sdelphij dp->di_name = cp; 133205194Sdelphij dp->di_count = 0; 134205194Sdelphij dhead.di_next = dhead.di_prev = dp; 135205194Sdelphij dp->di_next = dp->di_prev = &dhead; 136205194Sdelphij printd = 0; 137205194Sdelphij dnewcwd(dp, 0); 138205194Sdelphij set(STRdirstack, Strsave(dp->di_name), VAR_READWRITE|VAR_NOGLOB); 139205194Sdelphij} 140205194Sdelphij 141205194Sdelphijstatic void 142205194Sdelphijdset(dp) 143205194SdelphijChar *dp; 144205194Sdelphij{ 145205194Sdelphij /* 146205194Sdelphij * Don't call set() directly cause if the directory contains ` or 147237410Sdelphij * other junk characters glob will fail. 148237410Sdelphij */ 149237410Sdelphij set(STRowd, Strsave(varval(STRcwd)), VAR_READWRITE|VAR_NOGLOB); 150237410Sdelphij set(STRcwd, Strsave(dp), VAR_READWRITE|VAR_NOGLOB); 151237410Sdelphij 152237410Sdelphij tsetenv(STRPWD, dp); 153237410Sdelphij} 154237410Sdelphij 155237410Sdelphij#define DIR_PRINT 0x01 /* -p */ 156237410Sdelphij#define DIR_LONG 0x02 /* -l */ 157205194Sdelphij#define DIR_VERT 0x04 /* -v */ 158205194Sdelphij#define DIR_LINE 0x08 /* -n */ 159205194Sdelphij#define DIR_SAVE 0x10 /* -S */ 160205194Sdelphij#define DIR_LOAD 0x20 /* -L */ 161205194Sdelphij#define DIR_CLEAR 0x40 /* -c */ 162205194Sdelphij#define DIR_OLD 0x80 /* - */ 163205194Sdelphij 164205194Sdelphijstatic int 165205194Sdelphijskipargs(v, dstr, str) 166205194Sdelphij Char ***v; 167205194Sdelphij const char *dstr; 168250261Sdelphij const char *str; 169237410Sdelphij{ 170237410Sdelphij Char **n = *v, *s; 171250261Sdelphij 172205194Sdelphij int dflag = 0, loop = 1; 173205194Sdelphij for (n++; loop && *n != NULL && (*n)[0] == '-'; n++) 174205194Sdelphij if (*(s = &((*n)[1])) == '\0') /* test for bare "-" argument */ 175205194Sdelphij dflag |= DIR_OLD; 176205194Sdelphij else { 177205194Sdelphij char *p; 178205194Sdelphij while (loop && *s != '\0') /* examine flags */ 179205194Sdelphij { 180205194Sdelphij if ((p = strchr(dstr, *s++)) != NULL) 181205194Sdelphij dflag |= (1 << (p - dstr)); 182205194Sdelphij else { 183205194Sdelphij stderror(ERR_DIRUS, short2str(**v), dstr, str); 184237410Sdelphij loop = 0; /* break from both loops */ 185237410Sdelphij break; 186237410Sdelphij } 187237410Sdelphij } 188237410Sdelphij } 189237410Sdelphij if (*n && (dflag & DIR_OLD)) 190237410Sdelphij stderror(ERR_DIRUS, short2str(**v), dstr, str); 191237410Sdelphij *v = n; 192237410Sdelphij /* make -l, -v, and -n imply -p */ 193205194Sdelphij if (dflag & (DIR_LONG|DIR_VERT|DIR_LINE)) 194237410Sdelphij dflag |= DIR_PRINT; 195237410Sdelphij return dflag; 196237410Sdelphij} 197237410Sdelphij 198237410Sdelphij/* 199237410Sdelphij * dodirs - list all directories in directory loop 200237410Sdelphij */ 201237410Sdelphij/*ARGSUSED*/ 202250261Sdelphijvoid 203250261Sdelphijdodirs(v, c) 204205194Sdelphij Char **v; 205205194Sdelphij struct command *c; 206205194Sdelphij{ 207205194Sdelphij static char flags[] = "plvnSLc"; 208237410Sdelphij int dflag = skipargs(&v, flags, ""); 209237410Sdelphij 210237410Sdelphij USE(c); 211237410Sdelphij if ((dflag & DIR_CLEAR) != 0) { 212237410Sdelphij struct directory *dp, *fdp; 213237410Sdelphij for (dp = dcwd->di_next; dp != dcwd; ) { 214237410Sdelphij fdp = dp; 215237410Sdelphij dp = dp->di_next; 216250261Sdelphij if (fdp != &dhead) 217250261Sdelphij dfree(fdp); 218250261Sdelphij } 219237410Sdelphij dhead.di_next = dhead.di_prev = dp; 220250261Sdelphij dp->di_next = dp->di_prev = &dhead; 221205194Sdelphij } 222237410Sdelphij if ((dflag & DIR_LOAD) != 0) 223237410Sdelphij loaddirs(*v); 224205194Sdelphij else if ((dflag & DIR_SAVE) != 0) 225237410Sdelphij recdirs(*v, 1); 226205194Sdelphij 227205194Sdelphij if (*v && (dflag & (DIR_SAVE|DIR_LOAD))) 228237410Sdelphij v++; 229205194Sdelphij 230237410Sdelphij if (*v != NULL || (dflag & DIR_OLD)) 231237410Sdelphij stderror(ERR_DIRUS, "dirs", flags, ""); 232237410Sdelphij if ((dflag & (DIR_CLEAR|DIR_LOAD|DIR_SAVE)) == 0 || (dflag & DIR_PRINT)) 233237410Sdelphij printdirs(dflag); 234237410Sdelphij} 235237410Sdelphij 236237410Sdelphijstatic void 237237410Sdelphijprintdirs(dflag) 238237410Sdelphij int dflag; 239237410Sdelphij{ 240237410Sdelphij struct directory *dp; 241237410Sdelphij Char *s, *user; 242237410Sdelphij int idx, len, cur; 243237410Sdelphij 244237410Sdelphij dp = dcwd; 245237410Sdelphij idx = 0; 246237410Sdelphij cur = 0; 247237410Sdelphij do { 248250261Sdelphij if (dp == &dhead) 249205194Sdelphij continue; 250206708Sdelphij if (dflag & DIR_VERT) { 251205194Sdelphij xprintf("%d\t", idx++); 252205194Sdelphij cur = 0; 253205194Sdelphij } 254205194Sdelphij s = dp->di_name; 255205194Sdelphij user = NULL; 256205194Sdelphij if (!(dflag & DIR_LONG) && (user = getusername(&s)) != NULL) 257205194Sdelphij len = (int) (Strlen(user) + Strlen(s) + 2); 258205194Sdelphij else 259205194Sdelphij len = (int) (Strlen(s) + 1); 260205194Sdelphij 261205194Sdelphij cur += len; 262205194Sdelphij if ((dflag & DIR_LINE) && cur >= T_Cols - 1 && len < T_Cols) { 263205194Sdelphij xputchar('\n'); 264205194Sdelphij cur = len; 265205194Sdelphij } 266205194Sdelphij if (user) 267205194Sdelphij xprintf("~%S", user); 268205194Sdelphij xprintf("%-S%c", s, (dflag & DIR_VERT) ? '\n' : ' '); 269205194Sdelphij } while ((dp = dp->di_prev) != dcwd); 270205194Sdelphij if (!(dflag & DIR_VERT)) 271205194Sdelphij xputchar('\n'); 272205194Sdelphij} 273205194Sdelphij 274205194Sdelphijvoid 275205194Sdelphijdtildepr(dir) 276205194Sdelphij Char *dir; 277205194Sdelphij{ 278205194Sdelphij Char* user; 279205194Sdelphij if ((user = getusername(&dir)) != NULL) 280205194Sdelphij xprintf("~%-S%S", user, dir); 281205194Sdelphij else 282205194Sdelphij xprintf("%S", dir); 283205194Sdelphij} 284205194Sdelphij 285205194Sdelphijvoid 286205194Sdelphijdtilde() 287205194Sdelphij{ 288205194Sdelphij struct directory *d = dcwd; 289205194Sdelphij 290205194Sdelphij do { 291205194Sdelphij if (d == &dhead) 292205194Sdelphij continue; 293205194Sdelphij d->di_name = dcanon(d->di_name, STRNULL); 294250261Sdelphij } while ((d = d->di_prev) != dcwd); 295205194Sdelphij 296250261Sdelphij dset(dcwd->di_name); 297250261Sdelphij} 298250261Sdelphij 299206002Sdelphij 300250261Sdelphij/* dnormalize(): 301205194Sdelphij * The path will be normalized if it 302205194Sdelphij * 1) is "..", 303205194Sdelphij * 2) or starts with "../", 304205194Sdelphij * 3) or ends with "/..", 305205194Sdelphij * 4) or contains the string "/../", 306205194Sdelphij * then it will be normalized, unless those strings are quoted. 307237410Sdelphij * Otherwise, a copy is made and sent back. 308237410Sdelphij */ 309237410SdelphijChar * 310237410Sdelphijdnormalize(cp, expnd) 311237410Sdelphij Char *cp; 312237410Sdelphij int expnd; 313237410Sdelphij{ 314237410Sdelphij 315237410Sdelphij/* return true if dp is of the form "../xxx" or "/../xxx" */ 316237410Sdelphij#define IS_DOTDOT(sp, p) (ISDOTDOT(p) && ((p) == (sp) || *((p) - 1) == '/')) 317205194Sdelphij#define IS_DOT(sp, p) (ISDOT(p) && ((p) == (sp) || *((p) - 1) == '/')) 318205194Sdelphij 319205194Sdelphij#ifdef S_IFLNK 320205194Sdelphij if (expnd) { 321205194Sdelphij int dotdot = 0; 322205194Sdelphij Char *dp, *cwd, *start = cp, buf[MAXPATHLEN]; 323205194Sdelphij struct stat sb; 324205194Sdelphij# ifdef apollo 325205194Sdelphij int slashslash; 326205194Sdelphij# endif /* apollo */ 327205194Sdelphij 328205194Sdelphij /* 329205194Sdelphij * count the number of "../xxx" or "xxx/../xxx" in the path 330205194Sdelphij */ 331205194Sdelphij for (dp=start; *dp && *(dp+1); dp++) 332205194Sdelphij if (IS_DOTDOT(start, dp)) 333205194Sdelphij dotdot++; 334205194Sdelphij /* 335237410Sdelphij * if none, we are done. 336237410Sdelphij */ 337205194Sdelphij if (dotdot == 0) 338205194Sdelphij return (Strsave(cp)); 339205194Sdelphij 340205194Sdelphij /* 341205194Sdelphij * If the path doesn't exist, we are done too. 342205194Sdelphij */ 343205194Sdelphij if (lstat(short2str(cp), &sb) != 0 && errno == ENOENT) 344205194Sdelphij return (Strsave(cp)); 345205194Sdelphij 346205194Sdelphij 347205194Sdelphij cwd = (Char *) xmalloc((size_t) (((int) Strlen(dcwd->di_name) + 3) * 348205194Sdelphij sizeof(Char))); 349205194Sdelphij (void) Strcpy(cwd, dcwd->di_name); 350205194Sdelphij 351205194Sdelphij /* 352205194Sdelphij * If the path starts with a slash, we are not relative to 353237410Sdelphij * the current working directory. 354237410Sdelphij */ 355205194Sdelphij if (ABSOLUTEP(start)) 356205194Sdelphij *cwd = '\0'; 357205194Sdelphij# ifdef apollo 358205194Sdelphij slashslash = cwd[0] == '/' && cwd[1] == '/'; 359205194Sdelphij# endif /* apollo */ 360205194Sdelphij 361205194Sdelphij /* 362205194Sdelphij * Ignore . and count ..'s 363205194Sdelphij */ 364205194Sdelphij for (;;) { 365205194Sdelphij dotdot = 0; 366205194Sdelphij buf[0] = '\0'; 367205194Sdelphij dp = buf; 368205194Sdelphij while (*cp) 369205194Sdelphij if (IS_DOT(start, cp)) { 370205194Sdelphij if (*++cp) 371205194Sdelphij cp++; 372205194Sdelphij } 373205194Sdelphij else if (IS_DOTDOT(start, cp)) { 374205194Sdelphij if (buf[0]) 375205194Sdelphij break; /* finish analyzing .././../xxx/[..] */ 376205194Sdelphij dotdot++; 377205194Sdelphij cp += 2; 378205194Sdelphij if (*cp) 379205194Sdelphij cp++; 380205194Sdelphij } 381205194Sdelphij else 382237410Sdelphij *dp++ = *cp++; 383205194Sdelphij 384205194Sdelphij *dp = '\0'; 385205194Sdelphij while (dotdot > 0) 386205194Sdelphij if ((dp = Strrchr(cwd, '/')) != NULL) { 387205194Sdelphij# ifdef apollo 388205194Sdelphij if (dp == &cwd[1]) 389205194Sdelphij slashslash = 1; 390205194Sdelphij# endif /* apollo */ 391237410Sdelphij *dp = '\0'; 392205194Sdelphij dotdot--; 393205194Sdelphij } 394205194Sdelphij else 395205194Sdelphij break; 396205194Sdelphij 397205194Sdelphij if (!*cwd) { /* too many ..'s, starts with "/" */ 398237410Sdelphij cwd[0] = '/'; 399237410Sdelphij# ifdef apollo 400205194Sdelphij cwd[1] = '/'; 401205194Sdelphij cwd[2] = '\0'; 402237410Sdelphij# else /* !apollo */ 403205194Sdelphij cwd[1] = '\0'; 404237410Sdelphij# endif /* apollo */ 405205194Sdelphij } 406205194Sdelphij# ifdef apollo 407205194Sdelphij else if (slashslash && cwd[1] == '\0') { 408237410Sdelphij cwd[1] = '/'; 409237410Sdelphij cwd[2] = '\0'; 410205194Sdelphij } 411205194Sdelphij# endif /* apollo */ 412205194Sdelphij 413205194Sdelphij if (buf[0]) { 414205194Sdelphij if ((TRM(cwd[(dotdot = (int) Strlen(cwd)) - 1])) != '/') 415205194Sdelphij cwd[dotdot++] = '/'; 416237410Sdelphij cwd[dotdot] = '\0'; 417205194Sdelphij dp = Strspl(cwd, TRM(buf[0]) == '/' ? &buf[1] : buf); 418205194Sdelphij xfree((ptr_t) cwd); 419205194Sdelphij cwd = dp; 420205194Sdelphij if ((TRM(cwd[(dotdot = (int) Strlen(cwd)) - 1])) == '/') 421205194Sdelphij cwd[--dotdot] = '\0'; 422205194Sdelphij } 423205194Sdelphij /* Reduction of ".." following the stuff we collected in buf 424205194Sdelphij * only makes sense if the directory item in buf really exists. 425237410Sdelphij * Avoid reduction of "-I../.." (typical compiler call) to "" 426237410Sdelphij * or "/usr/nonexistant/../bin" to "/usr/bin": 427237410Sdelphij */ 428237410Sdelphij if (cwd[0]) { 429237410Sdelphij struct stat exists; 430205194Sdelphij if (0 != stat(short2str(cwd), &exists)) { 431205194Sdelphij xfree((ptr_t) cwd); 432205194Sdelphij return Strsave(start); 433205194Sdelphij } 434205194Sdelphij } 435205194Sdelphij if (!*cp) 436205194Sdelphij break; 437205194Sdelphij } 438237410Sdelphij return cwd; 439205194Sdelphij } 440205194Sdelphij#endif /* S_IFLNK */ 441205194Sdelphij return Strsave(cp); 442205194Sdelphij} 443205194Sdelphij 444205194Sdelphij 445205194Sdelphij/* 446205194Sdelphij * dochngd - implement chdir command. 447205194Sdelphij */ 448205194Sdelphij/*ARGSUSED*/ 449205194Sdelphijvoid 450205194Sdelphijdochngd(v, c) 451205194Sdelphij Char **v; 452205194Sdelphij struct command *c; 453205194Sdelphij{ 454205194Sdelphij Char *cp; 455205194Sdelphij struct directory *dp; 456205194Sdelphij int dflag = skipargs(&v, "plvn", "[-|<dir>]"); 457205194Sdelphij 458205194Sdelphij USE(c); 459205194Sdelphij printd = 0; 460205194Sdelphij cp = (dflag & DIR_OLD) ? varval(STRowd) : *v; 461205194Sdelphij 462205194Sdelphij if (cp == NULL) { 463205194Sdelphij if ((cp = varval(STRhome)) == STRNULL || *cp == 0) 464205194Sdelphij stderror(ERR_NAME | ERR_NOHOMEDIR); 465205194Sdelphij if (chdir(short2str(cp)) < 0) 466205194Sdelphij stderror(ERR_NAME | ERR_CANTCHANGE); 467237410Sdelphij cp = Strsave(cp); 468205194Sdelphij } 469205194Sdelphij else if ((dflag & DIR_OLD) == 0 && v[1] != NULL) { 470205194Sdelphij stderror(ERR_NAME | ERR_TOOMANY); 471205194Sdelphij /* NOTREACHED */ 472205194Sdelphij return; 473205194Sdelphij } 474205194Sdelphij else if ((dp = dfind(cp)) != 0) { 475205194Sdelphij char *tmp; 476205194Sdelphij 477205194Sdelphij printd = 1; 478205194Sdelphij if (chdir(tmp = short2str(dp->di_name)) < 0) 479205194Sdelphij stderror(ERR_SYSTEM, tmp, strerror(errno)); 480205194Sdelphij dcwd->di_prev->di_next = dcwd->di_next; 481205194Sdelphij dcwd->di_next->di_prev = dcwd->di_prev; 482205194Sdelphij dfree(dcwd); 483205194Sdelphij dnewcwd(dp, dflag); 484205194Sdelphij return; 485205194Sdelphij } 486205194Sdelphij else 487205194Sdelphij if ((cp = dfollow(cp)) == NULL) 488205194Sdelphij return; 489205194Sdelphij dp = (struct directory *) xcalloc(sizeof(struct directory), 1); 490205194Sdelphij dp->di_name = cp; 491205194Sdelphij dp->di_count = 0; 492205194Sdelphij dp->di_next = dcwd->di_next; 493205194Sdelphij dp->di_prev = dcwd->di_prev; 494205194Sdelphij dp->di_prev->di_next = dp; 495205194Sdelphij dp->di_next->di_prev = dp; 496205194Sdelphij dfree(dcwd); 497205194Sdelphij dnewcwd(dp, dflag); 498205194Sdelphij} 499205194Sdelphij 500205194Sdelphijstatic Char * 501205194Sdelphijdgoto(cp) 502205194Sdelphij Char *cp; 503205194Sdelphij{ 504205194Sdelphij Char *dp; 505205194Sdelphij 506205194Sdelphij if (!ABSOLUTEP(cp)) 507205194Sdelphij { 508205194Sdelphij Char *p, *q; 509205194Sdelphij int cwdlen; 510205194Sdelphij 511205194Sdelphij for (p = dcwd->di_name; *p++;) 512205194Sdelphij continue; 513205194Sdelphij if ((cwdlen = (int) (p - dcwd->di_name - 1)) == 1) /* root */ 514205194Sdelphij cwdlen = 0; 515205194Sdelphij for (p = cp; *p++;) 516205194Sdelphij continue; 517205194Sdelphij dp = (Char *) xmalloc((size_t)((cwdlen + (p - cp) + 1) * sizeof(Char))); 518205194Sdelphij for (p = dp, q = dcwd->di_name; (*p++ = *q++) != '\0';) 519205194Sdelphij continue; 520205194Sdelphij if (cwdlen) 521205194Sdelphij p[-1] = '/'; 522205194Sdelphij else 523205194Sdelphij p--; /* don't add a / after root */ 524205194Sdelphij for (q = cp; (*p++ = *q++) != '\0';) 525205194Sdelphij continue; 526205194Sdelphij xfree((ptr_t) cp); 527237410Sdelphij cp = dp; 528205194Sdelphij dp += cwdlen; 529205194Sdelphij } 530205194Sdelphij else 531205194Sdelphij dp = cp; 532205194Sdelphij 533205194Sdelphij#if defined(WINNT_NATIVE) 534205194Sdelphij cp = SAVE(getcwd(NULL, 0)); 535205194Sdelphij#elif defined(__CYGWIN__) 536205194Sdelphij if (ABSOLUTEP(cp) && cp[1] == ':') /* Only DOS paths are treated that way */ 537205194Sdelphij cp = SAVE(getcwd(NULL, 0)); 538205194Sdelphij else 539205194Sdelphij cp = dcanon(cp, dp); 540205194Sdelphij#else /* !WINNT_NATIVE */ 541205194Sdelphij cp = dcanon(cp, dp); 542205194Sdelphij#endif /* WINNT_NATIVE */ 543205194Sdelphij return cp; 544205194Sdelphij} 545205194Sdelphij 546205194Sdelphij/* 547250261Sdelphij * dfollow - change to arg directory; fall back on cdpath if not valid 548250261Sdelphij */ 549205194Sdelphijstatic Char * 550205194Sdelphijdfollow(cp) 551205194Sdelphij Char *cp; 552205194Sdelphij{ 553205194Sdelphij Char *dp; 554205194Sdelphij struct varent *c; 555205194Sdelphij char ebuf[MAXPATHLEN]; 556205194Sdelphij int serrno; 557205194Sdelphij 558205194Sdelphij cp = globone(cp, G_ERROR); 559205194Sdelphij#ifdef apollo 560205194Sdelphij if (Strchr(cp, '`')) { 561205194Sdelphij char *dptr, *ptr; 562205194Sdelphij if (chdir(dptr = short2str(cp)) < 0) 563205194Sdelphij stderror(ERR_SYSTEM, dptr, strerror(errno)); 564205194Sdelphij else if ((ptr = getcwd(ebuf, sizeof(ebuf))) && *ptr != '\0') { 565237410Sdelphij xfree((ptr_t) cp); 566205194Sdelphij cp = Strsave(str2short(ptr)); 567237410Sdelphij return dgoto(cp); 568237410Sdelphij } 569205194Sdelphij else 570205194Sdelphij stderror(ERR_SYSTEM, dptr, ebuf); 571205194Sdelphij } 572205194Sdelphij#endif /* apollo */ 573205194Sdelphij 574205194Sdelphij (void) strncpy(ebuf, short2str(cp), MAXPATHLEN); 575205194Sdelphij ebuf[MAXPATHLEN-1] = '\0'; 576205194Sdelphij /* 577205194Sdelphij * if we are ignoring symlinks, try to fix relatives now. 578206924Sdelphij * if we are expading symlinks, it should be done by now. 579205194Sdelphij */ 580205194Sdelphij dp = dnormalize(cp, symlinks == SYM_IGNORE); 581205194Sdelphij if (chdir(short2str(dp)) >= 0) { 582205194Sdelphij xfree((ptr_t) cp); 583205194Sdelphij return dgoto(dp); 584205194Sdelphij } 585205194Sdelphij else { 586205194Sdelphij xfree((ptr_t) dp); 587205194Sdelphij if (chdir(short2str(cp)) >= 0) 588205194Sdelphij return dgoto(cp); 589205194Sdelphij else if (errno != ENOENT && errno != ENOTDIR) 590237410Sdelphij stderror(ERR_SYSTEM, ebuf, strerror(errno)); 591237410Sdelphij serrno = errno; 592237410Sdelphij } 593237410Sdelphij 594205194Sdelphij if (cp[0] != '/' && !prefix(STRdotsl, cp) && !prefix(STRdotdotsl, cp) 595205194Sdelphij && (c = adrof(STRcdpath)) && c->vec != NULL) { 596205194Sdelphij Char **cdp; 597205194Sdelphij Char *p; 598205194Sdelphij Char buf[MAXPATHLEN]; 599250261Sdelphij 600250261Sdelphij for (cdp = c->vec; *cdp; cdp++) { 601205194Sdelphij for (dp = buf, p = *cdp; (*dp++ = *p++) != '\0';) 602205194Sdelphij continue; 603205194Sdelphij dp[-1] = '/'; 604250261Sdelphij for (p = cp; (*dp++ = *p++) != '\0';) 605250261Sdelphij continue; 606205194Sdelphij /* 607205194Sdelphij * We always want to fix the directory here 608205194Sdelphij * If we are normalizing symlinks 609250261Sdelphij */ 610250261Sdelphij dp = dnormalize(buf, symlinks == SYM_IGNORE || 611250261Sdelphij symlinks == SYM_EXPAND); 612250261Sdelphij if (chdir(short2str(dp)) >= 0) { 613205194Sdelphij printd = 1; 614205194Sdelphij xfree((ptr_t) cp); 615205194Sdelphij return dgoto(dp); 616250261Sdelphij } 617205194Sdelphij else if (chdir(short2str(cp)) >= 0) { 618205194Sdelphij printd = 1; 619205194Sdelphij xfree((ptr_t) dp); 620205194Sdelphij return dgoto(cp); 621205194Sdelphij } 622205194Sdelphij } 623205194Sdelphij } 624205194Sdelphij dp = varval(cp); 625206924Sdelphij if ((dp[0] == '/' || dp[0] == '.') && chdir(short2str(dp)) >= 0) { 626205194Sdelphij xfree((ptr_t) cp); 627205194Sdelphij cp = Strsave(dp); 628205194Sdelphij printd = 1; 629205194Sdelphij return dgoto(cp); 630205194Sdelphij } 631205194Sdelphij xfree((ptr_t) cp); 632205194Sdelphij /* 633205194Sdelphij * on login source of ~/.cshdirs, errors are eaten. the dir stack is all 634205194Sdelphij * directories we could get to. 635205194Sdelphij */ 636205194Sdelphij if (!bequiet) { 637205194Sdelphij stderror(ERR_SYSTEM, ebuf, strerror(serrno)); 638 return (NULL); 639 } 640 else 641 return (NULL); 642} 643 644 645/* 646 * dopushd - push new directory onto directory stack. 647 * with no arguments exchange top and second. 648 * with numeric argument (+n) bring it to top. 649 */ 650/*ARGSUSED*/ 651void 652dopushd(v, c) 653 Char **v; 654 struct command *c; 655{ 656 struct directory *dp; 657 Char *cp; 658 int dflag = skipargs(&v, "plvn", " [-|<dir>|+<n>]"); 659 660 USE(c); 661 printd = 1; 662 cp = (dflag & DIR_OLD) ? varval(STRowd) : *v; 663 664 if (cp == NULL) { 665 if (adrof(STRpushdtohome)) { 666 if ((cp = varval(STRhome)) == STRNULL || *cp == 0) 667 stderror(ERR_NAME | ERR_NOHOMEDIR); 668 if (chdir(short2str(cp)) < 0) 669 stderror(ERR_NAME | ERR_CANTCHANGE); 670 cp = Strsave(cp); /* hmmm... PWP */ 671 if ((cp = dfollow(cp)) == NULL) 672 return; 673 dp = (struct directory *) xcalloc(sizeof(struct directory), 1); 674 dp->di_name = cp; 675 dp->di_count = 0; 676 dp->di_prev = dcwd; 677 dp->di_next = dcwd->di_next; 678 dcwd->di_next = dp; 679 dp->di_next->di_prev = dp; 680 } 681 else { 682 char *tmp; 683 684 if ((dp = dcwd->di_prev) == &dhead) 685 dp = dhead.di_prev; 686 if (dp == dcwd) 687 stderror(ERR_NAME | ERR_NODIR); 688 if (chdir(tmp = short2str(dp->di_name)) < 0) 689 stderror(ERR_SYSTEM, tmp, strerror(errno)); 690 dp->di_prev->di_next = dp->di_next; 691 dp->di_next->di_prev = dp->di_prev; 692 dp->di_next = dcwd->di_next; 693 dp->di_prev = dcwd; 694 dcwd->di_next->di_prev = dp; 695 dcwd->di_next = dp; 696 } 697 } 698 else if ((dflag & DIR_OLD) == 0 && v[1] != NULL) { 699 stderror(ERR_NAME | ERR_TOOMANY); 700 /* NOTREACHED */ 701 return; 702 } 703 else if ((dp = dfind(cp)) != NULL) { 704 char *tmp; 705 706 if (chdir(tmp = short2str(dp->di_name)) < 0) 707 stderror(ERR_SYSTEM, tmp, strerror(errno)); 708 /* 709 * kfk - 10 Feb 1984 - added new "extraction style" pushd +n 710 */ 711 if (adrof(STRdextract)) 712 dextract(dp); 713 } 714 else { 715 Char *ccp; 716 717 if ((ccp = dfollow(cp)) == NULL) 718 return; 719 dp = (struct directory *) xcalloc(sizeof(struct directory), 1); 720 dp->di_name = ccp; 721 dp->di_count = 0; 722 dp->di_prev = dcwd; 723 dp->di_next = dcwd->di_next; 724 dcwd->di_next = dp; 725 dp->di_next->di_prev = dp; 726 } 727 dnewcwd(dp, dflag); 728} 729 730/* 731 * dfind - find a directory if specified by numeric (+n) argument 732 */ 733static struct directory * 734dfind(cp) 735 Char *cp; 736{ 737 struct directory *dp; 738 int i; 739 Char *ep; 740 741 if (*cp++ != '+') 742 return (0); 743 for (ep = cp; Isdigit(*ep); ep++) 744 continue; 745 if (*ep) 746 return (0); 747 i = getn(cp); 748 if (i <= 0) 749 return (0); 750 for (dp = dcwd; i != 0; i--) { 751 if ((dp = dp->di_prev) == &dhead) 752 dp = dp->di_prev; 753 if (dp == dcwd) 754 stderror(ERR_NAME | ERR_DEEP); 755 } 756 return (dp); 757} 758 759/* 760 * dopopd - pop a directory out of the directory stack 761 * with a numeric argument just discard it. 762 */ 763/*ARGSUSED*/ 764void 765dopopd(v, c) 766 Char **v; 767 struct command *c; 768{ 769 Char *cp; 770 struct directory *dp, *p = NULL; 771 int dflag = skipargs(&v, "plvn", " [-|+<n>]"); 772 773 USE(c); 774 printd = 1; 775 cp = (dflag & DIR_OLD) ? varval(STRowd) : *v; 776 777 if (cp == NULL) 778 dp = dcwd; 779 else if ((dflag & DIR_OLD) == 0 && v[1] != NULL) { 780 stderror(ERR_NAME | ERR_TOOMANY); 781 /* NOTREACHED */ 782 return; 783 } 784 else if ((dp = dfind(cp)) == 0) 785 stderror(ERR_NAME | ERR_BADDIR); 786 if (dp->di_prev == &dhead && dp->di_next == &dhead) 787 stderror(ERR_NAME | ERR_EMPTY); 788 if (dp == dcwd) { 789 char *tmp; 790 791 if ((p = dp->di_prev) == &dhead) 792 p = dhead.di_prev; 793 if (chdir(tmp = short2str(p->di_name)) < 0) 794 stderror(ERR_SYSTEM, tmp, strerror(errno)); 795 } 796 dp->di_prev->di_next = dp->di_next; 797 dp->di_next->di_prev = dp->di_prev; 798 if (dp == dcwd) { 799 dnewcwd(p, dflag); 800 } 801 else { 802 printdirs(dflag); 803 } 804 dfree(dp); 805} 806 807/* 808 * dfree - free the directory (or keep it if it still has ref count) 809 */ 810void 811dfree(dp) 812 struct directory *dp; 813{ 814 815 if (dp->di_count != 0) { 816 dp->di_next = dp->di_prev = 0; 817 } 818 else { 819 xfree((ptr_t) dp->di_name); 820 xfree((ptr_t) dp); 821 } 822} 823 824/* 825 * dcanon - canonicalize the pathname, removing excess ./ and ../ etc. 826 * we are of course assuming that the file system is standardly 827 * constructed (always have ..'s, directories have links) 828 */ 829Char * 830dcanon(cp, p) 831 Char *cp, *p; 832{ 833 Char *sp; 834 Char *p1, *p2; /* general purpose */ 835 int slash; 836#ifdef apollo 837 int slashslash; 838#endif /* apollo */ 839 size_t clen; 840 841#ifdef S_IFLNK /* if we have symlinks */ 842 Char mlink[MAXPATHLEN]; 843 char tlink[MAXPATHLEN]; 844 int cc; 845 Char *newcp; 846#endif /* S_IFLNK */ 847 848 /* 849 * if the path given is too long truncate it! 850 */ 851 if ((clen = Strlen(cp)) >= MAXPATHLEN) 852 cp[clen = MAXPATHLEN - 1] = '\0'; 853 854 /* 855 * christos: if the path given does not start with a slash prepend cwd. If 856 * cwd does not start with a slash or the result would be too long try to 857 * correct it. 858 */ 859 if (!ABSOLUTEP(cp)) { 860 Char tmpdir[MAXPATHLEN]; 861 size_t len; 862 863 p1 = varval(STRcwd); 864 if (p1 == STRNULL || !ABSOLUTEP(p1)) { 865 char *tmp = (char *)getcwd((char *)tmpdir, sizeof(tmpdir)); 866 if (tmp == NULL || *tmp == '\0') { 867 xprintf("%s: %s\n", progname, strerror(errno)); 868 set(STRcwd, SAVE("/"), VAR_READWRITE|VAR_NOGLOB); 869 } else { 870 set(STRcwd, SAVE(tmp), VAR_READWRITE|VAR_NOGLOB); 871 } 872 p1 = varval(STRcwd); 873 } 874 len = Strlen(p1); 875 if (len + clen + 1 >= MAXPATHLEN) 876 cp[MAXPATHLEN - (len + 1)] = '\0'; 877 (void) Strcpy(tmpdir, p1); 878 (void) Strcat(tmpdir, STRslash); 879 (void) Strcat(tmpdir, cp); 880 xfree((ptr_t) cp); 881 cp = p = Strsave(tmpdir); 882 } 883 884#ifdef apollo 885 slashslash = (cp[0] == '/' && cp[1] == '/'); 886#endif /* apollo */ 887 888 while (*p) { /* for each component */ 889 sp = p; /* save slash address */ 890 while (*++p == '/') /* flush extra slashes */ 891 continue; 892 if (p != ++sp) 893 for (p1 = sp, p2 = p; (*p1++ = *p2++) != '\0';) 894 continue; 895 p = sp; /* save start of component */ 896 slash = 0; 897 if (*p) 898 while (*++p) /* find next slash or end of path */ 899 if (*p == '/') { 900 slash = 1; 901 *p = 0; 902 break; 903 } 904 905#ifdef apollo 906 if (&cp[1] == sp && sp[0] == '.' && sp[1] == '.' && sp[2] == '\0') 907 slashslash = 1; 908#endif /* apollo */ 909 if (*sp == '\0') { /* if component is null */ 910 if (--sp == cp) /* if path is one char (i.e. /) */ 911 break; 912 else 913 *sp = '\0'; 914 } 915 else if (sp[0] == '.' && sp[1] == 0) { 916 if (slash) { 917 for (p1 = sp, p2 = p + 1; (*p1++ = *p2++) != '\0';) 918 continue; 919 p = --sp; 920 } 921 else if (--sp != cp) 922 *sp = '\0'; 923 else 924 sp[1] = '\0'; 925 } 926 else if (sp[0] == '.' && sp[1] == '.' && sp[2] == 0) { 927 /* 928 * We have something like "yyy/xxx/..", where "yyy" can be null or 929 * a path starting at /, and "xxx" is a single component. Before 930 * compressing "xxx/..", we want to expand "yyy/xxx", if it is a 931 * symbolic link. 932 */ 933 *--sp = 0; /* form the pathname for readlink */ 934#ifdef S_IFLNK /* if we have symlinks */ 935 if (sp != cp && /* symlinks != SYM_IGNORE && */ 936 (cc = readlink(short2str(cp), tlink, 937 sizeof(tlink) - 1)) >= 0) { 938 tlink[cc] = '\0'; 939 (void) Strncpy(mlink, str2short(tlink), 940 sizeof(mlink) / sizeof(Char)); 941 mlink[sizeof(mlink) / sizeof(Char) - 1] = '\0'; 942 943 if (slash) 944 *p = '/'; 945 /* 946 * Point p to the '/' in "/..", and restore the '/'. 947 */ 948 *(p = sp) = '/'; 949 /* 950 * find length of p 951 */ 952 for (p1 = p; *p1++;) 953 continue; 954 if (*mlink != '/') { 955 /* 956 * Relative path, expand it between the "yyy/" and the 957 * "/..". First, back sp up to the character past "yyy/". 958 */ 959 while (*--sp != '/') 960 continue; 961 sp++; 962 *sp = 0; 963 /* 964 * New length is "yyy/" + mlink + "/.." and rest 965 */ 966 p1 = newcp = (Char *) xmalloc((size_t) 967 (((sp - cp) + cc + (p1 - p)) * 968 sizeof(Char))); 969 /* 970 * Copy new path into newcp 971 */ 972 for (p2 = cp; (*p1++ = *p2++) != '\0';) 973 continue; 974 for (p1--, p2 = mlink; (*p1++ = *p2++) != '\0';) 975 continue; 976 for (p1--, p2 = p; (*p1++ = *p2++) != '\0';) 977 continue; 978 /* 979 * Restart canonicalization at expanded "/xxx". 980 */ 981 p = sp - cp - 1 + newcp; 982 } 983 else { 984 /* 985 * New length is mlink + "/.." and rest 986 */ 987 p1 = newcp = (Char *) xmalloc((size_t) 988 ((cc + (p1 - p)) * sizeof(Char))); 989 /* 990 * Copy new path into newcp 991 */ 992 for (p2 = mlink; (*p1++ = *p2++) != '\0';) 993 continue; 994 for (p1--, p2 = p; (*p1++ = *p2++) != '\0';) 995 continue; 996 /* 997 * Restart canonicalization at beginning 998 */ 999 p = newcp; 1000 } 1001 xfree((ptr_t) cp); 1002 cp = newcp; 1003#ifdef apollo 1004 slashslash = (cp[0] == '/' && cp[1] == '/'); 1005#endif /* apollo */ 1006 continue; /* canonicalize the link */ 1007 } 1008#endif /* S_IFLNK */ 1009 *sp = '/'; 1010 if (sp != cp) 1011 while (*--sp != '/') 1012 continue; 1013 if (slash) { 1014 for (p1 = sp + 1, p2 = p + 1; (*p1++ = *p2++) != '\0';) 1015 continue; 1016 p = sp; 1017 } 1018 else if (cp == sp) 1019 *++sp = '\0'; 1020 else 1021 *sp = '\0'; 1022 } 1023 else { /* normal dir name (not . or .. or nothing) */ 1024 1025#ifdef S_IFLNK /* if we have symlinks */ 1026 if (sp != cp && symlinks == SYM_CHASE && 1027 (cc = readlink(short2str(cp), tlink, 1028 sizeof(tlink) - 1)) >= 0) { 1029 tlink[cc] = '\0'; 1030 (void) Strncpy(mlink, str2short(tlink), 1031 sizeof(mlink) / sizeof(Char)); 1032 mlink[sizeof(mlink) / sizeof(Char) - 1] = '\0'; 1033 1034 /* 1035 * restore the '/'. 1036 */ 1037 if (slash) 1038 *p = '/'; 1039 1040 /* 1041 * point sp to p (rather than backing up). 1042 */ 1043 sp = p; 1044 1045 /* 1046 * find length of p 1047 */ 1048 for (p1 = p; *p1++;) 1049 continue; 1050 if (*mlink != '/') { 1051 /* 1052 * Relative path, expand it between the "yyy/" and the 1053 * remainder. First, back sp up to the character past 1054 * "yyy/". 1055 */ 1056 while (*--sp != '/') 1057 continue; 1058 sp++; 1059 *sp = 0; 1060 /* 1061 * New length is "yyy/" + mlink + "/.." and rest 1062 */ 1063 p1 = newcp = (Char *) xmalloc((size_t) 1064 (((sp - cp) + cc + (p1 - p)) 1065 * sizeof(Char))); 1066 /* 1067 * Copy new path into newcp 1068 */ 1069 for (p2 = cp; (*p1++ = *p2++) != '\0';) 1070 continue; 1071 for (p1--, p2 = mlink; (*p1++ = *p2++) != '\0';) 1072 continue; 1073 for (p1--, p2 = p; (*p1++ = *p2++) != '\0';) 1074 continue; 1075 /* 1076 * Restart canonicalization at expanded "/xxx". 1077 */ 1078 p = sp - cp - 1 + newcp; 1079 } 1080 else { 1081 /* 1082 * New length is mlink + the rest 1083 */ 1084 p1 = newcp = (Char *) xmalloc((size_t) 1085 ((cc + (p1 - p)) * sizeof(Char))); 1086 /* 1087 * Copy new path into newcp 1088 */ 1089 for (p2 = mlink; (*p1++ = *p2++) != '\0';) 1090 continue; 1091 for (p1--, p2 = p; (*p1++ = *p2++) != '\0';) 1092 continue; 1093 /* 1094 * Restart canonicalization at beginning 1095 */ 1096 p = newcp; 1097 } 1098 xfree((ptr_t) cp); 1099 cp = newcp; 1100#ifdef apollo 1101 slashslash = (cp[0] == '/' && cp[1] == '/'); 1102#endif /* apollo */ 1103 continue; /* canonicalize the mlink */ 1104 } 1105#endif /* S_IFLNK */ 1106 if (slash) 1107 *p = '/'; 1108 } 1109 } 1110 1111 /* 1112 * fix home... 1113 */ 1114#ifdef S_IFLNK 1115 p1 = varval(STRhome); 1116 cc = (int) Strlen(p1); 1117 /* 1118 * See if we're not in a subdir of STRhome 1119 */ 1120 if (p1 && *p1 == '/' && (Strncmp(p1, cp, (size_t) cc) != 0 || 1121 (cp[cc] != '/' && cp[cc] != '\0'))) { 1122 static ino_t home_ino = (ino_t) -1; 1123 static dev_t home_dev = (dev_t) -1; 1124 static Char *home_ptr = NULL; 1125 struct stat statbuf; 1126 int found; 1127 1128 /* 1129 * Get dev and ino of STRhome 1130 */ 1131 if (home_ptr != p1 && 1132 stat(short2str(p1), &statbuf) != -1) { 1133 home_dev = statbuf.st_dev; 1134 home_ino = statbuf.st_ino; 1135 home_ptr = p1; 1136 } 1137 /* 1138 * Start comparing dev & ino backwards 1139 */ 1140 p2 = Strncpy(mlink, cp, sizeof(mlink) / sizeof(Char)); 1141 mlink[sizeof(mlink) / sizeof(Char) - 1] = '\0'; 1142 found = 0; 1143 while (*p2 && stat(short2str(p2), &statbuf) != -1) { 1144 if (DEV_DEV_COMPARE(statbuf.st_dev, home_dev) && 1145 statbuf.st_ino == home_ino) { 1146 found = 1; 1147 break; 1148 } 1149 if ((sp = Strrchr(p2, '/')) != NULL) 1150 *sp = '\0'; 1151 } 1152 /* 1153 * See if we found it 1154 */ 1155 if (*p2 && found) { 1156 /* 1157 * Use STRhome to make '~' work 1158 */ 1159 newcp = Strspl(p1, cp + Strlen(p2)); 1160 xfree((ptr_t) cp); 1161 cp = newcp; 1162 } 1163 } 1164#endif /* S_IFLNK */ 1165 1166#ifdef apollo 1167 if (slashslash) { 1168 if (cp[1] != '/') { 1169 p = (Char *) xmalloc((size_t) (Strlen(cp) + 2) * sizeof(Char)); 1170 *p = '/'; 1171 (void) Strcpy(&p[1], cp); 1172 xfree((ptr_t) cp); 1173 cp = p; 1174 } 1175 } 1176 if (cp[1] == '/' && cp[2] == '/') 1177 (void) Strcpy(&cp[1], &cp[2]); 1178#endif /* apollo */ 1179 return cp; 1180} 1181 1182 1183/* 1184 * dnewcwd - make a new directory in the loop the current one 1185 */ 1186static void 1187dnewcwd(dp, dflag) 1188 struct directory *dp; 1189 int dflag; 1190{ 1191 int print; 1192 1193 if (adrof(STRdunique)) { 1194 struct directory *dn; 1195 1196 for (dn = dhead.di_prev; dn != &dhead; dn = dn->di_prev) 1197 if (dn != dp && Strcmp(dn->di_name, dp->di_name) == 0) { 1198 dn->di_next->di_prev = dn->di_prev; 1199 dn->di_prev->di_next = dn->di_next; 1200 dfree(dn); 1201 break; 1202 } 1203 } 1204 dcwd = dp; 1205 dset(dcwd->di_name); 1206 dgetstack(); 1207 print = printd; /* if printd is set, print dirstack... */ 1208 if (adrof(STRpushdsilent)) /* but pushdsilent overrides printd... */ 1209 print = 0; 1210 if (dflag & DIR_PRINT) /* but DIR_PRINT overrides pushdsilent... */ 1211 print = 1; 1212 if (bequiet) /* and bequiet overrides everything */ 1213 print = 0; 1214 if (print) 1215 printdirs(dflag); 1216 cwd_cmd(); /* PWP: run the defined cwd command */ 1217} 1218 1219void 1220dsetstack() 1221{ 1222 Char **cp; 1223 struct varent *vp; 1224 struct directory *dn, *dp; 1225 1226 if ((vp = adrof(STRdirstack)) == NULL || vp->vec == NULL) 1227 return; 1228 1229 /* Free the whole stack */ 1230 while ((dn = dhead.di_prev) != &dhead) { 1231 dn->di_next->di_prev = dn->di_prev; 1232 dn->di_prev->di_next = dn->di_next; 1233 if (dn != dcwd) 1234 dfree(dn); 1235 } 1236 1237 /* thread the current working directory */ 1238 dhead.di_prev = dhead.di_next = dcwd; 1239 dcwd->di_next = dcwd->di_prev = &dhead; 1240 1241 /* put back the stack */ 1242 for (cp = vp->vec; cp && *cp && **cp; cp++) { 1243 dp = (struct directory *) xcalloc(sizeof(struct directory), 1); 1244 dp->di_name = Strsave(*cp); 1245 dp->di_count = 0; 1246 dp->di_prev = dcwd; 1247 dp->di_next = dcwd->di_next; 1248 dcwd->di_next = dp; 1249 dp->di_next->di_prev = dp; 1250 } 1251 dgetstack(); /* Make $dirstack reflect the current state */ 1252} 1253 1254static void 1255dgetstack() 1256{ 1257 int i = 0; 1258 Char **dblk, **dbp; 1259 struct directory *dn; 1260 1261 if (adrof(STRdirstack) == NULL) 1262 return; 1263 1264 for (dn = dhead.di_prev; dn != &dhead; dn = dn->di_prev, i++) 1265 continue; 1266 dbp = dblk = (Char**) xmalloc((size_t) (i + 1) * sizeof(Char *)); 1267 for (dn = dhead.di_prev; dn != &dhead; dn = dn->di_prev, dbp++) 1268 *dbp = Strsave(dn->di_name); 1269 *dbp = NULL; 1270 setq(STRdirstack, dblk, &shvhed, VAR_READWRITE); 1271} 1272 1273/* 1274 * getstakd - added by kfk 17 Jan 1984 1275 * Support routine for the stack hack. Finds nth directory in 1276 * the directory stack, or finds last directory in stack. 1277 */ 1278int 1279getstakd(s, cnt) 1280 Char *s; 1281 int cnt; 1282{ 1283 struct directory *dp; 1284 1285 dp = dcwd; 1286 if (cnt < 0) { /* < 0 ==> last dir requested. */ 1287 dp = dp->di_next; 1288 if (dp == &dhead) 1289 dp = dp->di_next; 1290 } 1291 else { 1292 while (cnt-- > 0) { 1293 dp = dp->di_prev; 1294 if (dp == &dhead) 1295 dp = dp->di_prev; 1296 if (dp == dcwd) 1297 return (0); 1298 } 1299 } 1300 (void) Strncpy(s, dp->di_name, BUFSIZE); 1301 s[BUFSIZE - 1] = '\0'; 1302 return (1); 1303} 1304 1305/* 1306 * Karl Kleinpaste - 10 Feb 1984 1307 * Added dextract(), which is used in pushd +n. 1308 * Instead of just rotating the entire stack around, dextract() 1309 * lets the user have the nth dir extracted from its current 1310 * position, and pushes it onto the top. 1311 */ 1312static void 1313dextract(dp) 1314 struct directory *dp; 1315{ 1316 if (dp == dcwd) 1317 return; 1318 dp->di_next->di_prev = dp->di_prev; 1319 dp->di_prev->di_next = dp->di_next; 1320 dp->di_next = dcwd->di_next; 1321 dp->di_prev = dcwd; 1322 dp->di_next->di_prev = dp; 1323 dcwd->di_next = dp; 1324} 1325 1326void 1327loaddirs(fname) 1328 Char *fname; 1329{ 1330 static Char *loaddirs_cmd[] = { STRsource, NULL, NULL }; 1331 1332 bequiet = 1; 1333 if (fname) 1334 loaddirs_cmd[1] = fname; 1335 else if ((fname = varval(STRdirsfile)) != STRNULL) 1336 loaddirs_cmd[1] = fname; 1337 else 1338 loaddirs_cmd[1] = STRtildotdirs; 1339 dosource(loaddirs_cmd, (struct command *)0); 1340 bequiet = 0; 1341} 1342 1343/* 1344 * create a file called ~/.cshdirs which has a sequence 1345 * of pushd commands which will restore the dir stack to 1346 * its state before exit/logout. remember that the order 1347 * is reversed in the file because we are pushing. 1348 * -strike 1349 */ 1350void 1351recdirs(fname, def) 1352 Char *fname; 1353 int def; 1354{ 1355 int fp, ftmp, oldidfds; 1356 int cdflag = 0; 1357 struct directory *dp; 1358 unsigned int num; 1359 Char *snum; 1360 Char qname[MAXPATHLEN*2]; 1361 1362 if (fname == NULL && !def) 1363 return; 1364 1365 if (fname == NULL) { 1366 if ((fname = varval(STRdirsfile)) == STRNULL) 1367 fname = Strspl(varval(STRhome), &STRtildotdirs[1]); 1368 else 1369 fname = Strsave(fname); 1370 } 1371 else 1372 fname = globone(fname, G_ERROR); 1373 1374 if ((fp = creat(short2str(fname), 0600)) == -1) { 1375 xfree((ptr_t) fname); 1376 return; 1377 } 1378 1379 if ((snum = varval(STRsavedirs)) == STRNULL || snum[0] == '\0') 1380 num = (unsigned int) ~0; 1381 else 1382 num = (unsigned int) atoi(short2str(snum)); 1383 1384 oldidfds = didfds; 1385 didfds = 0; 1386 ftmp = SHOUT; 1387 SHOUT = fp; 1388 1389 dp = dcwd->di_next; 1390 do { 1391 if (dp == &dhead) 1392 continue; 1393 1394 if (cdflag == 0) { 1395 cdflag = 1; 1396 xprintf("cd %S\n", quote_meta(qname, dp->di_name)); 1397 } 1398 else 1399 xprintf("pushd %S\n", quote_meta(qname, dp->di_name)); 1400 1401 if (num-- == 0) 1402 break; 1403 1404 } while ((dp = dp->di_next) != dcwd->di_next); 1405 1406 (void) close(fp); 1407 SHOUT = ftmp; 1408 didfds = oldidfds; 1409 xfree((ptr_t) fname); 1410} 1411