16767bd61SMark Peek /* $Header: /src/pub/tcsh/sh.dir.c,v 3.56 2001/01/29 01:28:02 christos Exp $ */ 2c80476e4SDavid E. O'Brien /* 3c80476e4SDavid E. O'Brien * sh.dir.c: Directory manipulation functions 4c80476e4SDavid E. O'Brien */ 5c80476e4SDavid E. O'Brien /*- 6c80476e4SDavid E. O'Brien * Copyright (c) 1980, 1991 The Regents of the University of California. 7c80476e4SDavid E. O'Brien * All rights reserved. 8c80476e4SDavid E. O'Brien * 9c80476e4SDavid E. O'Brien * Redistribution and use in source and binary forms, with or without 10c80476e4SDavid E. O'Brien * modification, are permitted provided that the following conditions 11c80476e4SDavid E. O'Brien * are met: 12c80476e4SDavid E. O'Brien * 1. Redistributions of source code must retain the above copyright 13c80476e4SDavid E. O'Brien * notice, this list of conditions and the following disclaimer. 14c80476e4SDavid E. O'Brien * 2. Redistributions in binary form must reproduce the above copyright 15c80476e4SDavid E. O'Brien * notice, this list of conditions and the following disclaimer in the 16c80476e4SDavid E. O'Brien * documentation and/or other materials provided with the distribution. 17c80476e4SDavid E. O'Brien * 3. All advertising materials mentioning features or use of this software 18c80476e4SDavid E. O'Brien * must display the following acknowledgement: 19c80476e4SDavid E. O'Brien * This product includes software developed by the University of 20c80476e4SDavid E. O'Brien * California, Berkeley and its contributors. 21c80476e4SDavid E. O'Brien * 4. Neither the name of the University nor the names of its contributors 22c80476e4SDavid E. O'Brien * may be used to endorse or promote products derived from this software 23c80476e4SDavid E. O'Brien * without specific prior written permission. 24c80476e4SDavid E. O'Brien * 25c80476e4SDavid E. O'Brien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 26c80476e4SDavid E. O'Brien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27c80476e4SDavid E. O'Brien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28c80476e4SDavid E. O'Brien * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 29c80476e4SDavid E. O'Brien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30c80476e4SDavid E. O'Brien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 31c80476e4SDavid E. O'Brien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 32c80476e4SDavid E. O'Brien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 33c80476e4SDavid E. O'Brien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 34c80476e4SDavid E. O'Brien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 35c80476e4SDavid E. O'Brien * SUCH DAMAGE. 36c80476e4SDavid E. O'Brien */ 37c80476e4SDavid E. O'Brien #include "sh.h" 38c80476e4SDavid E. O'Brien 396767bd61SMark Peek RCSID("$Id: sh.dir.c,v 3.56 2001/01/29 01:28:02 christos Exp $") 40c80476e4SDavid E. O'Brien 41c80476e4SDavid E. O'Brien /* 42c80476e4SDavid E. O'Brien * C Shell - directory management 43c80476e4SDavid E. O'Brien */ 44c80476e4SDavid E. O'Brien 45c80476e4SDavid E. O'Brien static void dstart __P((const char *)); 46c80476e4SDavid E. O'Brien static struct directory *dfind __P((Char *)); 47c80476e4SDavid E. O'Brien static Char *dfollow __P((Char *)); 48c80476e4SDavid E. O'Brien static void printdirs __P((int)); 49c80476e4SDavid E. O'Brien static Char *dgoto __P((Char *)); 50c80476e4SDavid E. O'Brien static void dnewcwd __P((struct directory *, int)); 51c80476e4SDavid E. O'Brien static void dset __P((Char *)); 52c80476e4SDavid E. O'Brien static void dextract __P((struct directory *)); 53c80476e4SDavid E. O'Brien static int skipargs __P((Char ***, char *, char *)); 54c80476e4SDavid E. O'Brien static void dgetstack __P((void)); 55c80476e4SDavid E. O'Brien 56c80476e4SDavid E. O'Brien static struct directory dhead INIT_ZERO_STRUCT; /* "head" of loop */ 57c80476e4SDavid E. O'Brien static int printd; /* force name to be printed */ 58c80476e4SDavid E. O'Brien 59c80476e4SDavid E. O'Brien int bequiet = 0; /* do not print dir stack -strike */ 60c80476e4SDavid E. O'Brien 61c80476e4SDavid E. O'Brien static void 62c80476e4SDavid E. O'Brien dstart(from) 63c80476e4SDavid E. O'Brien const char *from; 64c80476e4SDavid E. O'Brien { 65c80476e4SDavid E. O'Brien xprintf(CGETS(12, 1, "%s: Trying to start from \"%s\"\n"), progname, from); 66c80476e4SDavid E. O'Brien } 67c80476e4SDavid E. O'Brien 68c80476e4SDavid E. O'Brien /* 69c80476e4SDavid E. O'Brien * dinit - initialize current working directory 70c80476e4SDavid E. O'Brien */ 71c80476e4SDavid E. O'Brien void 72c80476e4SDavid E. O'Brien dinit(hp) 73c80476e4SDavid E. O'Brien Char *hp; 74c80476e4SDavid E. O'Brien { 75c80476e4SDavid E. O'Brien register char *tcp; 76c80476e4SDavid E. O'Brien register Char *cp; 77c80476e4SDavid E. O'Brien register struct directory *dp; 78c80476e4SDavid E. O'Brien char path[MAXPATHLEN]; 79c80476e4SDavid E. O'Brien 80c80476e4SDavid E. O'Brien /* Don't believe the login shell home, because it may be a symlink */ 81c80476e4SDavid E. O'Brien tcp = (char *) getcwd(path, sizeof(path)); 82c80476e4SDavid E. O'Brien if (tcp == NULL || *tcp == '\0') { 83c80476e4SDavid E. O'Brien xprintf("%s: %s\n", progname, strerror(errno)); 84c80476e4SDavid E. O'Brien if (hp && *hp) { 85c80476e4SDavid E. O'Brien tcp = short2str(hp); 86c80476e4SDavid E. O'Brien dstart(tcp); 87c80476e4SDavid E. O'Brien if (chdir(tcp) == -1) 88c80476e4SDavid E. O'Brien cp = NULL; 89c80476e4SDavid E. O'Brien else 90c80476e4SDavid E. O'Brien cp = Strsave(hp); 91c80476e4SDavid E. O'Brien } 92c80476e4SDavid E. O'Brien else 93c80476e4SDavid E. O'Brien cp = NULL; 94c80476e4SDavid E. O'Brien if (cp == NULL) { 95c80476e4SDavid E. O'Brien dstart("/"); 96c80476e4SDavid E. O'Brien if (chdir("/") == -1) 97c80476e4SDavid E. O'Brien /* I am not even try to print an error message! */ 98c80476e4SDavid E. O'Brien xexit(1); 99c80476e4SDavid E. O'Brien cp = SAVE("/"); 100c80476e4SDavid E. O'Brien } 101c80476e4SDavid E. O'Brien } 102c80476e4SDavid E. O'Brien else { 103c80476e4SDavid E. O'Brien #ifdef S_IFLNK 104c80476e4SDavid E. O'Brien struct stat swd, shp; 105c80476e4SDavid E. O'Brien 106c80476e4SDavid E. O'Brien /* 107c80476e4SDavid E. O'Brien * See if $HOME is the working directory we got and use that 108c80476e4SDavid E. O'Brien */ 109c80476e4SDavid E. O'Brien if (hp && *hp && 110c80476e4SDavid E. O'Brien stat(tcp, &swd) != -1 && stat(short2str(hp), &shp) != -1 && 111c80476e4SDavid E. O'Brien DEV_DEV_COMPARE(swd.st_dev, shp.st_dev) && 112c80476e4SDavid E. O'Brien swd.st_ino == shp.st_ino) 113c80476e4SDavid E. O'Brien cp = Strsave(hp); 114c80476e4SDavid E. O'Brien else { 115c80476e4SDavid E. O'Brien char *cwd; 116c80476e4SDavid E. O'Brien 117c80476e4SDavid E. O'Brien /* 118c80476e4SDavid E. O'Brien * use PWD if we have it (for subshells) 119c80476e4SDavid E. O'Brien */ 120c80476e4SDavid E. O'Brien if ((cwd = getenv("PWD")) != NULL) { 121c80476e4SDavid E. O'Brien if (stat(cwd, &shp) != -1 && 122c80476e4SDavid E. O'Brien DEV_DEV_COMPARE(swd.st_dev, shp.st_dev) && 123c80476e4SDavid E. O'Brien swd.st_ino == shp.st_ino) 124c80476e4SDavid E. O'Brien tcp = cwd; 125c80476e4SDavid E. O'Brien } 126c80476e4SDavid E. O'Brien cp = dcanon(SAVE(tcp), STRNULL); 127c80476e4SDavid E. O'Brien } 128c80476e4SDavid E. O'Brien #else /* S_IFLNK */ 129c80476e4SDavid E. O'Brien cp = dcanon(SAVE(tcp), STRNULL); 130c80476e4SDavid E. O'Brien #endif /* S_IFLNK */ 131c80476e4SDavid E. O'Brien } 132c80476e4SDavid E. O'Brien 133c80476e4SDavid E. O'Brien dp = (struct directory *) xcalloc(sizeof(struct directory), 1); 134c80476e4SDavid E. O'Brien dp->di_name = cp; 135c80476e4SDavid E. O'Brien dp->di_count = 0; 136c80476e4SDavid E. O'Brien dhead.di_next = dhead.di_prev = dp; 137c80476e4SDavid E. O'Brien dp->di_next = dp->di_prev = &dhead; 138c80476e4SDavid E. O'Brien printd = 0; 139c80476e4SDavid E. O'Brien dnewcwd(dp, 0); 140c80476e4SDavid E. O'Brien set(STRdirstack, Strsave(dp->di_name), VAR_READWRITE|VAR_NOGLOB); 141c80476e4SDavid E. O'Brien } 142c80476e4SDavid E. O'Brien 143c80476e4SDavid E. O'Brien static void 144c80476e4SDavid E. O'Brien dset(dp) 145c80476e4SDavid E. O'Brien Char *dp; 146c80476e4SDavid E. O'Brien { 147c80476e4SDavid E. O'Brien /* 148c80476e4SDavid E. O'Brien * Don't call set() directly cause if the directory contains ` or 149c80476e4SDavid E. O'Brien * other junk characters glob will fail. 150c80476e4SDavid E. O'Brien */ 151c80476e4SDavid E. O'Brien set(STRowd, Strsave(varval(STRcwd)), VAR_READWRITE|VAR_NOGLOB); 152c80476e4SDavid E. O'Brien set(STRcwd, Strsave(dp), VAR_READWRITE|VAR_NOGLOB); 153c80476e4SDavid E. O'Brien 154c80476e4SDavid E. O'Brien tsetenv(STRPWD, dp); 155c80476e4SDavid E. O'Brien } 156c80476e4SDavid E. O'Brien 157c80476e4SDavid E. O'Brien #define DIR_PRINT 0x01 /* -p */ 158c80476e4SDavid E. O'Brien #define DIR_LONG 0x02 /* -l */ 159c80476e4SDavid E. O'Brien #define DIR_VERT 0x04 /* -v */ 160c80476e4SDavid E. O'Brien #define DIR_LINE 0x08 /* -n */ 161c80476e4SDavid E. O'Brien #define DIR_SAVE 0x10 /* -S */ 162c80476e4SDavid E. O'Brien #define DIR_LOAD 0x20 /* -L */ 163c80476e4SDavid E. O'Brien #define DIR_CLEAR 0x40 /* -c */ 164c80476e4SDavid E. O'Brien #define DIR_OLD 0x80 /* - */ 165c80476e4SDavid E. O'Brien 166c80476e4SDavid E. O'Brien static int 167c80476e4SDavid E. O'Brien skipargs(v, dstr, str) 168c80476e4SDavid E. O'Brien Char ***v; 169c80476e4SDavid E. O'Brien char *dstr; 170c80476e4SDavid E. O'Brien char *str; 171c80476e4SDavid E. O'Brien { 172c80476e4SDavid E. O'Brien Char **n = *v, *s; 173c80476e4SDavid E. O'Brien 174c80476e4SDavid E. O'Brien int dflag = 0, loop = 1; 175c80476e4SDavid E. O'Brien for (n++; loop && *n != NULL && (*n)[0] == '-'; n++) 176c80476e4SDavid E. O'Brien if (*(s = &((*n)[1])) == '\0') /* test for bare "-" argument */ 177c80476e4SDavid E. O'Brien dflag |= DIR_OLD; 178c80476e4SDavid E. O'Brien else { 179c80476e4SDavid E. O'Brien char *p; 180c80476e4SDavid E. O'Brien while (loop && *s != '\0') /* examine flags */ 181c80476e4SDavid E. O'Brien { 182c80476e4SDavid E. O'Brien if ((p = strchr(dstr, *s++)) != NULL) 183c80476e4SDavid E. O'Brien dflag |= (1 << (p - dstr)); 184c80476e4SDavid E. O'Brien else { 185c80476e4SDavid E. O'Brien stderror(ERR_DIRUS, short2str(**v), dstr, str); 186c80476e4SDavid E. O'Brien loop = 0; /* break from both loops */ 187c80476e4SDavid E. O'Brien break; 188c80476e4SDavid E. O'Brien } 189c80476e4SDavid E. O'Brien } 190c80476e4SDavid E. O'Brien } 191c80476e4SDavid E. O'Brien if (*n && (dflag & DIR_OLD)) 192c80476e4SDavid E. O'Brien stderror(ERR_DIRUS, short2str(**v), dstr, str); 193c80476e4SDavid E. O'Brien *v = n; 194c80476e4SDavid E. O'Brien /* make -l, -v, and -n imply -p */ 195c80476e4SDavid E. O'Brien if (dflag & (DIR_LONG|DIR_VERT|DIR_LINE)) 196c80476e4SDavid E. O'Brien dflag |= DIR_PRINT; 197c80476e4SDavid E. O'Brien return dflag; 198c80476e4SDavid E. O'Brien } 199c80476e4SDavid E. O'Brien 200c80476e4SDavid E. O'Brien /* 201c80476e4SDavid E. O'Brien * dodirs - list all directories in directory loop 202c80476e4SDavid E. O'Brien */ 203c80476e4SDavid E. O'Brien /*ARGSUSED*/ 204c80476e4SDavid E. O'Brien void 205c80476e4SDavid E. O'Brien dodirs(v, c) 206c80476e4SDavid E. O'Brien Char **v; 207c80476e4SDavid E. O'Brien struct command *c; 208c80476e4SDavid E. O'Brien { 209c80476e4SDavid E. O'Brien static char flags[] = "plvnSLc"; 210c80476e4SDavid E. O'Brien int dflag = skipargs(&v, flags, ""); 211c80476e4SDavid E. O'Brien 212c80476e4SDavid E. O'Brien USE(c); 213c80476e4SDavid E. O'Brien if ((dflag & DIR_CLEAR) != 0) { 214c80476e4SDavid E. O'Brien struct directory *dp, *fdp; 215c80476e4SDavid E. O'Brien for (dp = dcwd->di_next; dp != dcwd; ) { 216c80476e4SDavid E. O'Brien fdp = dp; 217c80476e4SDavid E. O'Brien dp = dp->di_next; 218c80476e4SDavid E. O'Brien if (fdp != &dhead) 219c80476e4SDavid E. O'Brien dfree(fdp); 220c80476e4SDavid E. O'Brien } 221c80476e4SDavid E. O'Brien dhead.di_next = dhead.di_prev = dp; 222c80476e4SDavid E. O'Brien dp->di_next = dp->di_prev = &dhead; 223c80476e4SDavid E. O'Brien } 224c80476e4SDavid E. O'Brien if ((dflag & DIR_LOAD) != 0) 225c80476e4SDavid E. O'Brien loaddirs(*v); 226c80476e4SDavid E. O'Brien else if ((dflag & DIR_SAVE) != 0) 227c80476e4SDavid E. O'Brien recdirs(*v, 1); 228c80476e4SDavid E. O'Brien 229c80476e4SDavid E. O'Brien if (*v && (dflag & (DIR_SAVE|DIR_LOAD))) 230c80476e4SDavid E. O'Brien v++; 231c80476e4SDavid E. O'Brien 232c80476e4SDavid E. O'Brien if (*v != NULL || (dflag & DIR_OLD)) 233c80476e4SDavid E. O'Brien stderror(ERR_DIRUS, "dirs", flags, ""); 234c80476e4SDavid E. O'Brien if ((dflag & (DIR_CLEAR|DIR_LOAD|DIR_SAVE)) == 0 || (dflag & DIR_PRINT)) 235c80476e4SDavid E. O'Brien printdirs(dflag); 236c80476e4SDavid E. O'Brien } 237c80476e4SDavid E. O'Brien 238c80476e4SDavid E. O'Brien static void 239c80476e4SDavid E. O'Brien printdirs(dflag) 240c80476e4SDavid E. O'Brien int dflag; 241c80476e4SDavid E. O'Brien { 242c80476e4SDavid E. O'Brien register struct directory *dp; 243c80476e4SDavid E. O'Brien Char *s, *user; 244c80476e4SDavid E. O'Brien int idx, len, cur; 245c80476e4SDavid E. O'Brien extern int T_Cols; 246c80476e4SDavid E. O'Brien 247c80476e4SDavid E. O'Brien dp = dcwd; 248c80476e4SDavid E. O'Brien idx = 0; 249c80476e4SDavid E. O'Brien cur = 0; 250c80476e4SDavid E. O'Brien do { 251c80476e4SDavid E. O'Brien if (dp == &dhead) 252c80476e4SDavid E. O'Brien continue; 253c80476e4SDavid E. O'Brien if (dflag & DIR_VERT) { 254c80476e4SDavid E. O'Brien xprintf("%d\t", idx++); 255c80476e4SDavid E. O'Brien cur = 0; 256c80476e4SDavid E. O'Brien } 257c80476e4SDavid E. O'Brien s = dp->di_name; 258c80476e4SDavid E. O'Brien user = NULL; 259c80476e4SDavid E. O'Brien if (!(dflag & DIR_LONG) && (user = getusername(&s)) != NULL) 260c80476e4SDavid E. O'Brien len = (int) (Strlen(user) + Strlen(s) + 2); 261c80476e4SDavid E. O'Brien else 262c80476e4SDavid E. O'Brien len = (int) (Strlen(s) + 1); 263c80476e4SDavid E. O'Brien 264c80476e4SDavid E. O'Brien cur += len; 265c80476e4SDavid E. O'Brien if ((dflag & DIR_LINE) && cur >= T_Cols - 1 && len < T_Cols) { 266c80476e4SDavid E. O'Brien xputchar('\n'); 267c80476e4SDavid E. O'Brien cur = len; 268c80476e4SDavid E. O'Brien } 269c80476e4SDavid E. O'Brien if (user) 270c80476e4SDavid E. O'Brien xprintf("~%S", user); 271c80476e4SDavid E. O'Brien xprintf("%S%c", s, (dflag & DIR_VERT) ? '\n' : ' '); 272c80476e4SDavid E. O'Brien } while ((dp = dp->di_prev) != dcwd); 273c80476e4SDavid E. O'Brien if (!(dflag & DIR_VERT)) 274c80476e4SDavid E. O'Brien xputchar('\n'); 275c80476e4SDavid E. O'Brien } 276c80476e4SDavid E. O'Brien 277c80476e4SDavid E. O'Brien void 278c80476e4SDavid E. O'Brien dtildepr(dir) 279c80476e4SDavid E. O'Brien Char *dir; 280c80476e4SDavid E. O'Brien { 281c80476e4SDavid E. O'Brien Char* user; 282c80476e4SDavid E. O'Brien if ((user = getusername(&dir)) != NULL) 283c80476e4SDavid E. O'Brien xprintf("~%S%S", user, dir); 284c80476e4SDavid E. O'Brien else 285c80476e4SDavid E. O'Brien xprintf("%S", dir); 286c80476e4SDavid E. O'Brien } 287c80476e4SDavid E. O'Brien 288c80476e4SDavid E. O'Brien void 289c80476e4SDavid E. O'Brien dtilde() 290c80476e4SDavid E. O'Brien { 291c80476e4SDavid E. O'Brien struct directory *d = dcwd; 292c80476e4SDavid E. O'Brien 293c80476e4SDavid E. O'Brien do { 294c80476e4SDavid E. O'Brien if (d == &dhead) 295c80476e4SDavid E. O'Brien continue; 296c80476e4SDavid E. O'Brien d->di_name = dcanon(d->di_name, STRNULL); 297c80476e4SDavid E. O'Brien } while ((d = d->di_prev) != dcwd); 298c80476e4SDavid E. O'Brien 299c80476e4SDavid E. O'Brien dset(dcwd->di_name); 300c80476e4SDavid E. O'Brien } 301c80476e4SDavid E. O'Brien 302c80476e4SDavid E. O'Brien 303c80476e4SDavid E. O'Brien /* dnormalize(): 304c80476e4SDavid E. O'Brien * The path will be normalized if it 305c80476e4SDavid E. O'Brien * 1) is "..", 306c80476e4SDavid E. O'Brien * 2) or starts with "../", 307c80476e4SDavid E. O'Brien * 3) or ends with "/..", 308c80476e4SDavid E. O'Brien * 4) or contains the string "/../", 309c80476e4SDavid E. O'Brien * then it will be normalized, unless those strings are quoted. 310c80476e4SDavid E. O'Brien * Otherwise, a copy is made and sent back. 311c80476e4SDavid E. O'Brien */ 312c80476e4SDavid E. O'Brien Char * 313c80476e4SDavid E. O'Brien dnormalize(cp, exp) 314c80476e4SDavid E. O'Brien Char *cp; 315c80476e4SDavid E. O'Brien int exp; 316c80476e4SDavid E. O'Brien { 317c80476e4SDavid E. O'Brien 318c80476e4SDavid E. O'Brien /* return true if dp is of the form "../xxx" or "/../xxx" */ 319c80476e4SDavid E. O'Brien #define IS_DOTDOT(sp, p) (ISDOTDOT(p) && ((p) == (sp) || *((p) - 1) == '/')) 320c80476e4SDavid E. O'Brien #define IS_DOT(sp, p) (ISDOT(p) && ((p) == (sp) || *((p) - 1) == '/')) 321c80476e4SDavid E. O'Brien 322c80476e4SDavid E. O'Brien #ifdef S_IFLNK 323c80476e4SDavid E. O'Brien if (exp) { 324c80476e4SDavid E. O'Brien int dotdot = 0; 325c80476e4SDavid E. O'Brien Char *dp, *cwd, *start = cp, buf[MAXPATHLEN]; 326c80476e4SDavid E. O'Brien # ifdef apollo 327c80476e4SDavid E. O'Brien bool slashslash; 328c80476e4SDavid E. O'Brien # endif /* apollo */ 329c80476e4SDavid E. O'Brien 330c80476e4SDavid E. O'Brien /* 331c80476e4SDavid E. O'Brien * count the number of "../xxx" or "xxx/../xxx" in the path 332c80476e4SDavid E. O'Brien */ 333c80476e4SDavid E. O'Brien for (dp=start; *dp && *(dp+1); dp++) 334c80476e4SDavid E. O'Brien if (IS_DOTDOT(start, dp)) 335c80476e4SDavid E. O'Brien dotdot++; 336c80476e4SDavid E. O'Brien /* 337c80476e4SDavid E. O'Brien * if none, we are done. 338c80476e4SDavid E. O'Brien */ 339c80476e4SDavid E. O'Brien if (dotdot == 0) 340c80476e4SDavid E. O'Brien return (Strsave(cp)); 341c80476e4SDavid E. O'Brien 342c80476e4SDavid E. O'Brien cwd = (Char *) xmalloc((size_t) (((int) Strlen(dcwd->di_name) + 3) * 343c80476e4SDavid E. O'Brien sizeof(Char))); 344c80476e4SDavid E. O'Brien (void) Strcpy(cwd, dcwd->di_name); 345c80476e4SDavid E. O'Brien 346c80476e4SDavid E. O'Brien /* 347c80476e4SDavid E. O'Brien * If the path starts with a slash, we are not relative to 348c80476e4SDavid E. O'Brien * the current working directory. 349c80476e4SDavid E. O'Brien */ 350c80476e4SDavid E. O'Brien if (ABSOLUTEP(start)) 351c80476e4SDavid E. O'Brien *cwd = '\0'; 352c80476e4SDavid E. O'Brien # ifdef apollo 353c80476e4SDavid E. O'Brien slashslash = cwd[0] == '/' && cwd[1] == '/'; 354c80476e4SDavid E. O'Brien # endif /* apollo */ 355c80476e4SDavid E. O'Brien 356c80476e4SDavid E. O'Brien /* 357c80476e4SDavid E. O'Brien * Ignore . and count ..'s 358c80476e4SDavid E. O'Brien */ 359c80476e4SDavid E. O'Brien for (;;) { 360c80476e4SDavid E. O'Brien dotdot = 0; 361c80476e4SDavid E. O'Brien buf[0] = '\0'; 362c80476e4SDavid E. O'Brien dp = buf; 363c80476e4SDavid E. O'Brien while (*cp) 364c80476e4SDavid E. O'Brien if (IS_DOT(start, cp)) { 365c80476e4SDavid E. O'Brien if (*++cp) 366c80476e4SDavid E. O'Brien cp++; 367c80476e4SDavid E. O'Brien } 368c80476e4SDavid E. O'Brien else if (IS_DOTDOT(start, cp)) { 369c80476e4SDavid E. O'Brien if (buf[0]) 370c80476e4SDavid E. O'Brien break; /* finish analyzing .././../xxx/[..] */ 371c80476e4SDavid E. O'Brien dotdot++; 372c80476e4SDavid E. O'Brien cp += 2; 373c80476e4SDavid E. O'Brien if (*cp) 374c80476e4SDavid E. O'Brien cp++; 375c80476e4SDavid E. O'Brien } 376c80476e4SDavid E. O'Brien else 377c80476e4SDavid E. O'Brien *dp++ = *cp++; 378c80476e4SDavid E. O'Brien 379c80476e4SDavid E. O'Brien *dp = '\0'; 380c80476e4SDavid E. O'Brien while (dotdot > 0) 381c80476e4SDavid E. O'Brien if ((dp = Strrchr(cwd, '/')) != NULL) { 382c80476e4SDavid E. O'Brien # ifdef apollo 383c80476e4SDavid E. O'Brien if (dp == &cwd[1]) 384c80476e4SDavid E. O'Brien slashslash = 1; 385c80476e4SDavid E. O'Brien # endif /* apollo */ 386c80476e4SDavid E. O'Brien *dp = '\0'; 387c80476e4SDavid E. O'Brien dotdot--; 388c80476e4SDavid E. O'Brien } 389c80476e4SDavid E. O'Brien else 390c80476e4SDavid E. O'Brien break; 391c80476e4SDavid E. O'Brien 392c80476e4SDavid E. O'Brien if (!*cwd) { /* too many ..'s, starts with "/" */ 393c80476e4SDavid E. O'Brien cwd[0] = '/'; 394c80476e4SDavid E. O'Brien # ifdef apollo 395c80476e4SDavid E. O'Brien cwd[1] = '/'; 396c80476e4SDavid E. O'Brien cwd[2] = '\0'; 397c80476e4SDavid E. O'Brien # else /* !apollo */ 398c80476e4SDavid E. O'Brien cwd[1] = '\0'; 399c80476e4SDavid E. O'Brien # endif /* apollo */ 400c80476e4SDavid E. O'Brien } 401c80476e4SDavid E. O'Brien # ifdef apollo 402c80476e4SDavid E. O'Brien else if (slashslash && cwd[1] == '\0') { 403c80476e4SDavid E. O'Brien cwd[1] = '/'; 404c80476e4SDavid E. O'Brien cwd[2] = '\0'; 405c80476e4SDavid E. O'Brien } 406c80476e4SDavid E. O'Brien # endif /* apollo */ 407c80476e4SDavid E. O'Brien 408c80476e4SDavid E. O'Brien if (buf[0]) { 409c80476e4SDavid E. O'Brien if ((TRM(cwd[(dotdot = (int) Strlen(cwd)) - 1])) != '/') 410c80476e4SDavid E. O'Brien cwd[dotdot++] = '/'; 411c80476e4SDavid E. O'Brien cwd[dotdot] = '\0'; 412c80476e4SDavid E. O'Brien dp = Strspl(cwd, TRM(buf[0]) == '/' ? &buf[1] : buf); 413c80476e4SDavid E. O'Brien xfree((ptr_t) cwd); 414c80476e4SDavid E. O'Brien cwd = dp; 415c80476e4SDavid E. O'Brien if ((TRM(cwd[(dotdot = (int) Strlen(cwd)) - 1])) == '/') 416c80476e4SDavid E. O'Brien cwd[--dotdot] = '\0'; 417c80476e4SDavid E. O'Brien } 418c80476e4SDavid E. O'Brien if (!*cp) 419c80476e4SDavid E. O'Brien break; 420c80476e4SDavid E. O'Brien } 421c80476e4SDavid E. O'Brien return cwd; 422c80476e4SDavid E. O'Brien } 423c80476e4SDavid E. O'Brien #endif /* S_IFLNK */ 424c80476e4SDavid E. O'Brien return Strsave(cp); 425c80476e4SDavid E. O'Brien } 426c80476e4SDavid E. O'Brien 427c80476e4SDavid E. O'Brien 428c80476e4SDavid E. O'Brien /* 429c80476e4SDavid E. O'Brien * dochngd - implement chdir command. 430c80476e4SDavid E. O'Brien */ 431c80476e4SDavid E. O'Brien /*ARGSUSED*/ 432c80476e4SDavid E. O'Brien void 433c80476e4SDavid E. O'Brien dochngd(v, c) 434c80476e4SDavid E. O'Brien Char **v; 435c80476e4SDavid E. O'Brien struct command *c; 436c80476e4SDavid E. O'Brien { 437c80476e4SDavid E. O'Brien register Char *cp; 438c80476e4SDavid E. O'Brien register struct directory *dp; 439c80476e4SDavid E. O'Brien int dflag = skipargs(&v, "plvn", "[-|<dir>]"); 440c80476e4SDavid E. O'Brien 441c80476e4SDavid E. O'Brien USE(c); 442c80476e4SDavid E. O'Brien printd = 0; 443c80476e4SDavid E. O'Brien cp = (dflag & DIR_OLD) ? varval(STRowd) : *v; 444c80476e4SDavid E. O'Brien 445c80476e4SDavid E. O'Brien if (cp == NULL) { 446c80476e4SDavid E. O'Brien if ((cp = varval(STRhome)) == STRNULL || *cp == 0) 447c80476e4SDavid E. O'Brien stderror(ERR_NAME | ERR_NOHOMEDIR); 448c80476e4SDavid E. O'Brien if (chdir(short2str(cp)) < 0) 449c80476e4SDavid E. O'Brien stderror(ERR_NAME | ERR_CANTCHANGE); 450c80476e4SDavid E. O'Brien cp = Strsave(cp); 451c80476e4SDavid E. O'Brien } 452c80476e4SDavid E. O'Brien else if ((dflag & DIR_OLD) == 0 && v[1] != NULL) { 453c80476e4SDavid E. O'Brien stderror(ERR_NAME | ERR_TOOMANY); 454c80476e4SDavid E. O'Brien /* NOTREACHED */ 455c80476e4SDavid E. O'Brien return; 456c80476e4SDavid E. O'Brien } 457c80476e4SDavid E. O'Brien else if ((dp = dfind(cp)) != 0) { 458c80476e4SDavid E. O'Brien char *tmp; 459c80476e4SDavid E. O'Brien 460c80476e4SDavid E. O'Brien printd = 1; 461c80476e4SDavid E. O'Brien if (chdir(tmp = short2str(dp->di_name)) < 0) 462c80476e4SDavid E. O'Brien stderror(ERR_SYSTEM, tmp, strerror(errno)); 463c80476e4SDavid E. O'Brien dcwd->di_prev->di_next = dcwd->di_next; 464c80476e4SDavid E. O'Brien dcwd->di_next->di_prev = dcwd->di_prev; 465c80476e4SDavid E. O'Brien dfree(dcwd); 466c80476e4SDavid E. O'Brien dnewcwd(dp, dflag); 467c80476e4SDavid E. O'Brien return; 468c80476e4SDavid E. O'Brien } 469c80476e4SDavid E. O'Brien else 470c80476e4SDavid E. O'Brien if ((cp = dfollow(cp)) == NULL) 471c80476e4SDavid E. O'Brien return; 472c80476e4SDavid E. O'Brien dp = (struct directory *) xcalloc(sizeof(struct directory), 1); 473c80476e4SDavid E. O'Brien dp->di_name = cp; 474c80476e4SDavid E. O'Brien dp->di_count = 0; 475c80476e4SDavid E. O'Brien dp->di_next = dcwd->di_next; 476c80476e4SDavid E. O'Brien dp->di_prev = dcwd->di_prev; 477c80476e4SDavid E. O'Brien dp->di_prev->di_next = dp; 478c80476e4SDavid E. O'Brien dp->di_next->di_prev = dp; 479c80476e4SDavid E. O'Brien dfree(dcwd); 480c80476e4SDavid E. O'Brien dnewcwd(dp, dflag); 481c80476e4SDavid E. O'Brien } 482c80476e4SDavid E. O'Brien 483c80476e4SDavid E. O'Brien static Char * 484c80476e4SDavid E. O'Brien dgoto(cp) 485c80476e4SDavid E. O'Brien Char *cp; 486c80476e4SDavid E. O'Brien { 487c80476e4SDavid E. O'Brien Char *dp; 488c80476e4SDavid E. O'Brien 489c80476e4SDavid E. O'Brien if (!ABSOLUTEP(cp)) 490c80476e4SDavid E. O'Brien { 491c80476e4SDavid E. O'Brien register Char *p, *q; 492c80476e4SDavid E. O'Brien int cwdlen; 493c80476e4SDavid E. O'Brien 494c80476e4SDavid E. O'Brien for (p = dcwd->di_name; *p++;) 495c80476e4SDavid E. O'Brien continue; 496c80476e4SDavid E. O'Brien if ((cwdlen = (int) (p - dcwd->di_name - 1)) == 1) /* root */ 497c80476e4SDavid E. O'Brien cwdlen = 0; 498c80476e4SDavid E. O'Brien for (p = cp; *p++;) 499c80476e4SDavid E. O'Brien continue; 500c80476e4SDavid E. O'Brien dp = (Char *) xmalloc((size_t)((cwdlen + (p - cp) + 1) * sizeof(Char))); 501c80476e4SDavid E. O'Brien for (p = dp, q = dcwd->di_name; (*p++ = *q++) != '\0';) 502c80476e4SDavid E. O'Brien continue; 503c80476e4SDavid E. O'Brien if (cwdlen) 504c80476e4SDavid E. O'Brien p[-1] = '/'; 505c80476e4SDavid E. O'Brien else 506c80476e4SDavid E. O'Brien p--; /* don't add a / after root */ 507c80476e4SDavid E. O'Brien for (q = cp; (*p++ = *q++) != '\0';) 508c80476e4SDavid E. O'Brien continue; 509c80476e4SDavid E. O'Brien xfree((ptr_t) cp); 510c80476e4SDavid E. O'Brien cp = dp; 511c80476e4SDavid E. O'Brien dp += cwdlen; 512c80476e4SDavid E. O'Brien } 513c80476e4SDavid E. O'Brien else 514c80476e4SDavid E. O'Brien dp = cp; 515c80476e4SDavid E. O'Brien 5163b6eaa7bSAndrey A. Chernov #ifdef WINNT_NATIVE 517c80476e4SDavid E. O'Brien cp = SAVE(getcwd(NULL, 0)); 5183b6eaa7bSAndrey A. Chernov #else /* !WINNT_NATIVE */ 519c80476e4SDavid E. O'Brien cp = dcanon(cp, dp); 5203b6eaa7bSAndrey A. Chernov #endif /* WINNT_NATIVE */ 521c80476e4SDavid E. O'Brien return cp; 522c80476e4SDavid E. O'Brien } 523c80476e4SDavid E. O'Brien 524c80476e4SDavid E. O'Brien /* 525c80476e4SDavid E. O'Brien * dfollow - change to arg directory; fall back on cdpath if not valid 526c80476e4SDavid E. O'Brien */ 527c80476e4SDavid E. O'Brien static Char * 528c80476e4SDavid E. O'Brien dfollow(cp) 529c80476e4SDavid E. O'Brien register Char *cp; 530c80476e4SDavid E. O'Brien { 531c80476e4SDavid E. O'Brien register Char *dp; 532c80476e4SDavid E. O'Brien struct varent *c; 533c80476e4SDavid E. O'Brien char ebuf[MAXPATHLEN]; 534c80476e4SDavid E. O'Brien int serrno; 535c80476e4SDavid E. O'Brien 536c80476e4SDavid E. O'Brien cp = globone(cp, G_ERROR); 537c80476e4SDavid E. O'Brien #ifdef apollo 538c80476e4SDavid E. O'Brien if (Strchr(cp, '`')) { 539c80476e4SDavid E. O'Brien char *dptr, *ptr; 540c80476e4SDavid E. O'Brien if (chdir(dptr = short2str(cp)) < 0) 541c80476e4SDavid E. O'Brien stderror(ERR_SYSTEM, dptr, strerror(errno)); 542c80476e4SDavid E. O'Brien else if ((ptr = getcwd(ebuf, sizeof(ebuf))) && *ptr != '\0') { 543c80476e4SDavid E. O'Brien xfree((ptr_t) cp); 544c80476e4SDavid E. O'Brien cp = Strsave(str2short(ptr)); 545c80476e4SDavid E. O'Brien return dgoto(cp); 546c80476e4SDavid E. O'Brien } 547c80476e4SDavid E. O'Brien else 548c80476e4SDavid E. O'Brien stderror(ERR_SYSTEM, dptr, ebuf); 549c80476e4SDavid E. O'Brien } 550c80476e4SDavid E. O'Brien #endif /* apollo */ 551c80476e4SDavid E. O'Brien 552c80476e4SDavid E. O'Brien (void) strncpy(ebuf, short2str(cp), MAXPATHLEN); 553c80476e4SDavid E. O'Brien ebuf[MAXPATHLEN-1] = '\0'; 554c80476e4SDavid E. O'Brien /* 555c80476e4SDavid E. O'Brien * if we are ignoring symlinks, try to fix relatives now. 556c80476e4SDavid E. O'Brien * if we are expading symlinks, it should be done by now. 557c80476e4SDavid E. O'Brien */ 558c80476e4SDavid E. O'Brien dp = dnormalize(cp, symlinks == SYM_IGNORE); 559c80476e4SDavid E. O'Brien if (chdir(short2str(dp)) >= 0) { 560c80476e4SDavid E. O'Brien xfree((ptr_t) cp); 561c80476e4SDavid E. O'Brien return dgoto(dp); 562c80476e4SDavid E. O'Brien } 563c80476e4SDavid E. O'Brien else { 564c80476e4SDavid E. O'Brien xfree((ptr_t) dp); 565c80476e4SDavid E. O'Brien if (chdir(short2str(cp)) >= 0) 566c80476e4SDavid E. O'Brien return dgoto(cp); 567c80476e4SDavid E. O'Brien else if (errno != ENOENT && errno != ENOTDIR) 568c80476e4SDavid E. O'Brien stderror(ERR_SYSTEM, ebuf, strerror(errno)); 569c80476e4SDavid E. O'Brien serrno = errno; 570c80476e4SDavid E. O'Brien } 571c80476e4SDavid E. O'Brien 572c80476e4SDavid E. O'Brien if (cp[0] != '/' && !prefix(STRdotsl, cp) && !prefix(STRdotdotsl, cp) 573c80476e4SDavid E. O'Brien && (c = adrof(STRcdpath))) { 574c80476e4SDavid E. O'Brien Char **cdp; 575c80476e4SDavid E. O'Brien register Char *p; 576c80476e4SDavid E. O'Brien Char buf[MAXPATHLEN]; 577c80476e4SDavid E. O'Brien 578c80476e4SDavid E. O'Brien for (cdp = c->vec; *cdp; cdp++) { 579c80476e4SDavid E. O'Brien for (dp = buf, p = *cdp; (*dp++ = *p++) != '\0';) 580c80476e4SDavid E. O'Brien continue; 581c80476e4SDavid E. O'Brien dp[-1] = '/'; 582c80476e4SDavid E. O'Brien for (p = cp; (*dp++ = *p++) != '\0';) 583c80476e4SDavid E. O'Brien continue; 584c80476e4SDavid E. O'Brien /* 585c80476e4SDavid E. O'Brien * We always want to fix the directory here 586c80476e4SDavid E. O'Brien * If we are normalizing symlinks 587c80476e4SDavid E. O'Brien */ 588c80476e4SDavid E. O'Brien dp = dnormalize(buf, symlinks == SYM_IGNORE || 589c80476e4SDavid E. O'Brien symlinks == SYM_EXPAND); 590c80476e4SDavid E. O'Brien if (chdir(short2str(dp)) >= 0) { 591c80476e4SDavid E. O'Brien printd = 1; 592c80476e4SDavid E. O'Brien xfree((ptr_t) cp); 593c80476e4SDavid E. O'Brien return dgoto(dp); 594c80476e4SDavid E. O'Brien } 595c80476e4SDavid E. O'Brien else if (chdir(short2str(cp)) >= 0) { 596c80476e4SDavid E. O'Brien printd = 1; 597c80476e4SDavid E. O'Brien xfree((ptr_t) dp); 598c80476e4SDavid E. O'Brien return dgoto(cp); 599c80476e4SDavid E. O'Brien } 600c80476e4SDavid E. O'Brien } 601c80476e4SDavid E. O'Brien } 602c80476e4SDavid E. O'Brien dp = varval(cp); 603c80476e4SDavid E. O'Brien if ((dp[0] == '/' || dp[0] == '.') && chdir(short2str(dp)) >= 0) { 604c80476e4SDavid E. O'Brien xfree((ptr_t) cp); 605c80476e4SDavid E. O'Brien cp = Strsave(dp); 606c80476e4SDavid E. O'Brien printd = 1; 607c80476e4SDavid E. O'Brien return dgoto(cp); 608c80476e4SDavid E. O'Brien } 609c80476e4SDavid E. O'Brien xfree((ptr_t) cp); 610c80476e4SDavid E. O'Brien /* 611c80476e4SDavid E. O'Brien * on login source of ~/.cshdirs, errors are eaten. the dir stack is all 612c80476e4SDavid E. O'Brien * directories we could get to. 613c80476e4SDavid E. O'Brien */ 614c80476e4SDavid E. O'Brien if (!bequiet) { 615c80476e4SDavid E. O'Brien stderror(ERR_SYSTEM, ebuf, strerror(serrno)); 616c80476e4SDavid E. O'Brien return (NULL); 617c80476e4SDavid E. O'Brien } 618c80476e4SDavid E. O'Brien else 619c80476e4SDavid E. O'Brien return (NULL); 620c80476e4SDavid E. O'Brien } 621c80476e4SDavid E. O'Brien 622c80476e4SDavid E. O'Brien 623c80476e4SDavid E. O'Brien /* 624c80476e4SDavid E. O'Brien * dopushd - push new directory onto directory stack. 625c80476e4SDavid E. O'Brien * with no arguments exchange top and second. 626c80476e4SDavid E. O'Brien * with numeric argument (+n) bring it to top. 627c80476e4SDavid E. O'Brien */ 628c80476e4SDavid E. O'Brien /*ARGSUSED*/ 629c80476e4SDavid E. O'Brien void 630c80476e4SDavid E. O'Brien dopushd(v, c) 631c80476e4SDavid E. O'Brien Char **v; 632c80476e4SDavid E. O'Brien struct command *c; 633c80476e4SDavid E. O'Brien { 634c80476e4SDavid E. O'Brien register struct directory *dp; 635c80476e4SDavid E. O'Brien register Char *cp; 636c80476e4SDavid E. O'Brien int dflag = skipargs(&v, "plvn", " [-|<dir>|+<n>]"); 637c80476e4SDavid E. O'Brien 638c80476e4SDavid E. O'Brien USE(c); 639c80476e4SDavid E. O'Brien printd = 1; 640c80476e4SDavid E. O'Brien cp = (dflag & DIR_OLD) ? varval(STRowd) : *v; 641c80476e4SDavid E. O'Brien 642c80476e4SDavid E. O'Brien if (cp == NULL) { 643c80476e4SDavid E. O'Brien if (adrof(STRpushdtohome)) { 644c80476e4SDavid E. O'Brien if ((cp = varval(STRhome)) == STRNULL || *cp == 0) 645c80476e4SDavid E. O'Brien stderror(ERR_NAME | ERR_NOHOMEDIR); 646c80476e4SDavid E. O'Brien if (chdir(short2str(cp)) < 0) 647c80476e4SDavid E. O'Brien stderror(ERR_NAME | ERR_CANTCHANGE); 648c80476e4SDavid E. O'Brien cp = Strsave(cp); /* hmmm... PWP */ 649c80476e4SDavid E. O'Brien if ((cp = dfollow(cp)) == NULL) 650c80476e4SDavid E. O'Brien return; 651c80476e4SDavid E. O'Brien dp = (struct directory *) xcalloc(sizeof(struct directory), 1); 652c80476e4SDavid E. O'Brien dp->di_name = cp; 653c80476e4SDavid E. O'Brien dp->di_count = 0; 654c80476e4SDavid E. O'Brien dp->di_prev = dcwd; 655c80476e4SDavid E. O'Brien dp->di_next = dcwd->di_next; 656c80476e4SDavid E. O'Brien dcwd->di_next = dp; 657c80476e4SDavid E. O'Brien dp->di_next->di_prev = dp; 658c80476e4SDavid E. O'Brien } 659c80476e4SDavid E. O'Brien else { 660c80476e4SDavid E. O'Brien char *tmp; 661c80476e4SDavid E. O'Brien 662c80476e4SDavid E. O'Brien if ((dp = dcwd->di_prev) == &dhead) 663c80476e4SDavid E. O'Brien dp = dhead.di_prev; 664c80476e4SDavid E. O'Brien if (dp == dcwd) 665c80476e4SDavid E. O'Brien stderror(ERR_NAME | ERR_NODIR); 666c80476e4SDavid E. O'Brien if (chdir(tmp = short2str(dp->di_name)) < 0) 667c80476e4SDavid E. O'Brien stderror(ERR_SYSTEM, tmp, strerror(errno)); 668c80476e4SDavid E. O'Brien dp->di_prev->di_next = dp->di_next; 669c80476e4SDavid E. O'Brien dp->di_next->di_prev = dp->di_prev; 670c80476e4SDavid E. O'Brien dp->di_next = dcwd->di_next; 671c80476e4SDavid E. O'Brien dp->di_prev = dcwd; 672c80476e4SDavid E. O'Brien dcwd->di_next->di_prev = dp; 673c80476e4SDavid E. O'Brien dcwd->di_next = dp; 674c80476e4SDavid E. O'Brien } 675c80476e4SDavid E. O'Brien } 676c80476e4SDavid E. O'Brien else if ((dflag & DIR_OLD) == 0 && v[1] != NULL) { 677c80476e4SDavid E. O'Brien stderror(ERR_NAME | ERR_TOOMANY); 678c80476e4SDavid E. O'Brien /* NOTREACHED */ 679c80476e4SDavid E. O'Brien return; 680c80476e4SDavid E. O'Brien } 681c80476e4SDavid E. O'Brien else if ((dp = dfind(cp)) != NULL) { 682c80476e4SDavid E. O'Brien char *tmp; 683c80476e4SDavid E. O'Brien 684c80476e4SDavid E. O'Brien if (chdir(tmp = short2str(dp->di_name)) < 0) 685c80476e4SDavid E. O'Brien stderror(ERR_SYSTEM, tmp, strerror(errno)); 686c80476e4SDavid E. O'Brien /* 687c80476e4SDavid E. O'Brien * kfk - 10 Feb 1984 - added new "extraction style" pushd +n 688c80476e4SDavid E. O'Brien */ 689c80476e4SDavid E. O'Brien if (adrof(STRdextract)) 690c80476e4SDavid E. O'Brien dextract(dp); 691c80476e4SDavid E. O'Brien } 692c80476e4SDavid E. O'Brien else { 693c80476e4SDavid E. O'Brien register Char *ccp; 694c80476e4SDavid E. O'Brien 695c80476e4SDavid E. O'Brien if ((ccp = dfollow(cp)) == NULL) 696c80476e4SDavid E. O'Brien return; 697c80476e4SDavid E. O'Brien dp = (struct directory *) xcalloc(sizeof(struct directory), 1); 698c80476e4SDavid E. O'Brien dp->di_name = ccp; 699c80476e4SDavid E. O'Brien dp->di_count = 0; 700c80476e4SDavid E. O'Brien dp->di_prev = dcwd; 701c80476e4SDavid E. O'Brien dp->di_next = dcwd->di_next; 702c80476e4SDavid E. O'Brien dcwd->di_next = dp; 703c80476e4SDavid E. O'Brien dp->di_next->di_prev = dp; 704c80476e4SDavid E. O'Brien } 705c80476e4SDavid E. O'Brien dnewcwd(dp, dflag); 706c80476e4SDavid E. O'Brien } 707c80476e4SDavid E. O'Brien 708c80476e4SDavid E. O'Brien /* 709c80476e4SDavid E. O'Brien * dfind - find a directory if specified by numeric (+n) argument 710c80476e4SDavid E. O'Brien */ 711c80476e4SDavid E. O'Brien static struct directory * 712c80476e4SDavid E. O'Brien dfind(cp) 713c80476e4SDavid E. O'Brien register Char *cp; 714c80476e4SDavid E. O'Brien { 715c80476e4SDavid E. O'Brien register struct directory *dp; 716c80476e4SDavid E. O'Brien register int i; 717c80476e4SDavid E. O'Brien register Char *ep; 718c80476e4SDavid E. O'Brien 719c80476e4SDavid E. O'Brien if (*cp++ != '+') 720c80476e4SDavid E. O'Brien return (0); 721c80476e4SDavid E. O'Brien for (ep = cp; Isdigit(*ep); ep++) 722c80476e4SDavid E. O'Brien continue; 723c80476e4SDavid E. O'Brien if (*ep) 724c80476e4SDavid E. O'Brien return (0); 725c80476e4SDavid E. O'Brien i = getn(cp); 726c80476e4SDavid E. O'Brien if (i <= 0) 727c80476e4SDavid E. O'Brien return (0); 728c80476e4SDavid E. O'Brien for (dp = dcwd; i != 0; i--) { 729c80476e4SDavid E. O'Brien if ((dp = dp->di_prev) == &dhead) 730c80476e4SDavid E. O'Brien dp = dp->di_prev; 731c80476e4SDavid E. O'Brien if (dp == dcwd) 732c80476e4SDavid E. O'Brien stderror(ERR_NAME | ERR_DEEP); 733c80476e4SDavid E. O'Brien } 734c80476e4SDavid E. O'Brien return (dp); 735c80476e4SDavid E. O'Brien } 736c80476e4SDavid E. O'Brien 737c80476e4SDavid E. O'Brien /* 738c80476e4SDavid E. O'Brien * dopopd - pop a directory out of the directory stack 739c80476e4SDavid E. O'Brien * with a numeric argument just discard it. 740c80476e4SDavid E. O'Brien */ 741c80476e4SDavid E. O'Brien /*ARGSUSED*/ 742c80476e4SDavid E. O'Brien void 743c80476e4SDavid E. O'Brien dopopd(v, c) 744c80476e4SDavid E. O'Brien Char **v; 745c80476e4SDavid E. O'Brien struct command *c; 746c80476e4SDavid E. O'Brien { 747c80476e4SDavid E. O'Brien Char *cp; 748c80476e4SDavid E. O'Brien register struct directory *dp, *p = NULL; 749c80476e4SDavid E. O'Brien int dflag = skipargs(&v, "plvn", " [-|+<n>]"); 750c80476e4SDavid E. O'Brien 751c80476e4SDavid E. O'Brien USE(c); 752c80476e4SDavid E. O'Brien printd = 1; 753c80476e4SDavid E. O'Brien cp = (dflag & DIR_OLD) ? varval(STRowd) : *v; 754c80476e4SDavid E. O'Brien 755c80476e4SDavid E. O'Brien if (cp == NULL) 756c80476e4SDavid E. O'Brien dp = dcwd; 757c80476e4SDavid E. O'Brien else if ((dflag & DIR_OLD) == 0 && v[1] != NULL) { 758c80476e4SDavid E. O'Brien stderror(ERR_NAME | ERR_TOOMANY); 759c80476e4SDavid E. O'Brien /* NOTREACHED */ 760c80476e4SDavid E. O'Brien return; 761c80476e4SDavid E. O'Brien } 762c80476e4SDavid E. O'Brien else if ((dp = dfind(cp)) == 0) 763c80476e4SDavid E. O'Brien stderror(ERR_NAME | ERR_BADDIR); 764c80476e4SDavid E. O'Brien if (dp->di_prev == &dhead && dp->di_next == &dhead) 765c80476e4SDavid E. O'Brien stderror(ERR_NAME | ERR_EMPTY); 766c80476e4SDavid E. O'Brien if (dp == dcwd) { 767c80476e4SDavid E. O'Brien char *tmp; 768c80476e4SDavid E. O'Brien 769c80476e4SDavid E. O'Brien if ((p = dp->di_prev) == &dhead) 770c80476e4SDavid E. O'Brien p = dhead.di_prev; 771c80476e4SDavid E. O'Brien if (chdir(tmp = short2str(p->di_name)) < 0) 772c80476e4SDavid E. O'Brien stderror(ERR_SYSTEM, tmp, strerror(errno)); 773c80476e4SDavid E. O'Brien } 774c80476e4SDavid E. O'Brien dp->di_prev->di_next = dp->di_next; 775c80476e4SDavid E. O'Brien dp->di_next->di_prev = dp->di_prev; 776c80476e4SDavid E. O'Brien if (dp == dcwd) { 777c80476e4SDavid E. O'Brien dnewcwd(p, dflag); 778c80476e4SDavid E. O'Brien } 779c80476e4SDavid E. O'Brien else { 780c80476e4SDavid E. O'Brien printdirs(dflag); 781c80476e4SDavid E. O'Brien } 782c80476e4SDavid E. O'Brien dfree(dp); 783c80476e4SDavid E. O'Brien } 784c80476e4SDavid E. O'Brien 785c80476e4SDavid E. O'Brien /* 786c80476e4SDavid E. O'Brien * dfree - free the directory (or keep it if it still has ref count) 787c80476e4SDavid E. O'Brien */ 788c80476e4SDavid E. O'Brien void 789c80476e4SDavid E. O'Brien dfree(dp) 790c80476e4SDavid E. O'Brien register struct directory *dp; 791c80476e4SDavid E. O'Brien { 792c80476e4SDavid E. O'Brien 793c80476e4SDavid E. O'Brien if (dp->di_count != 0) { 794c80476e4SDavid E. O'Brien dp->di_next = dp->di_prev = 0; 795c80476e4SDavid E. O'Brien } 796c80476e4SDavid E. O'Brien else { 797c80476e4SDavid E. O'Brien xfree((ptr_t) dp->di_name); 798c80476e4SDavid E. O'Brien xfree((ptr_t) dp); 799c80476e4SDavid E. O'Brien } 800c80476e4SDavid E. O'Brien } 801c80476e4SDavid E. O'Brien 802c80476e4SDavid E. O'Brien /* 803c80476e4SDavid E. O'Brien * dcanon - canonicalize the pathname, removing excess ./ and ../ etc. 804c80476e4SDavid E. O'Brien * we are of course assuming that the file system is standardly 805c80476e4SDavid E. O'Brien * constructed (always have ..'s, directories have links) 806c80476e4SDavid E. O'Brien */ 807c80476e4SDavid E. O'Brien Char * 808c80476e4SDavid E. O'Brien dcanon(cp, p) 809c80476e4SDavid E. O'Brien register Char *cp, *p; 810c80476e4SDavid E. O'Brien { 811c80476e4SDavid E. O'Brien register Char *sp; 812c80476e4SDavid E. O'Brien register Char *p1, *p2; /* general purpose */ 813c80476e4SDavid E. O'Brien bool slash; 814c80476e4SDavid E. O'Brien #ifdef apollo 815c80476e4SDavid E. O'Brien bool slashslash; 816c80476e4SDavid E. O'Brien #endif /* apollo */ 81728ae2e3aSKris Kennaway size_t clen; 818c80476e4SDavid E. O'Brien 819c80476e4SDavid E. O'Brien #ifdef S_IFLNK /* if we have symlinks */ 820c80476e4SDavid E. O'Brien Char link[MAXPATHLEN]; 821c80476e4SDavid E. O'Brien char tlink[MAXPATHLEN]; 822c80476e4SDavid E. O'Brien int cc; 823c80476e4SDavid E. O'Brien Char *newcp; 824c80476e4SDavid E. O'Brien #endif /* S_IFLNK */ 825c80476e4SDavid E. O'Brien 826c80476e4SDavid E. O'Brien /* 82728ae2e3aSKris Kennaway * if the path given is too long truncate it! 828c80476e4SDavid E. O'Brien */ 82928ae2e3aSKris Kennaway if ((clen = Strlen(cp)) >= MAXPATHLEN) 83028ae2e3aSKris Kennaway cp[clen = MAXPATHLEN - 1] = '\0'; 831c80476e4SDavid E. O'Brien 832c80476e4SDavid E. O'Brien /* 833c80476e4SDavid E. O'Brien * christos: if the path given does not start with a slash prepend cwd. If 83428ae2e3aSKris Kennaway * cwd does not start with a slash or the result would be too long try to 83528ae2e3aSKris Kennaway * correct it. 836c80476e4SDavid E. O'Brien */ 837c80476e4SDavid E. O'Brien if (!ABSOLUTEP(cp)) { 838c80476e4SDavid E. O'Brien Char tmpdir[MAXPATHLEN]; 83928ae2e3aSKris Kennaway size_t len; 840c80476e4SDavid E. O'Brien 841c80476e4SDavid E. O'Brien p1 = varval(STRcwd); 84228ae2e3aSKris Kennaway if (p1 == STRNULL || !ABSOLUTEP(p1)) { 84328ae2e3aSKris Kennaway char *tmp = (char *)getcwd((char *)tmpdir, sizeof(tmpdir)); 84428ae2e3aSKris Kennaway if (tmp == NULL || *tmp == '\0') { 84528ae2e3aSKris Kennaway xprintf("%s: %s\n", progname, strerror(errno)); 84628ae2e3aSKris Kennaway set(STRcwd, SAVE("/"), VAR_READWRITE|VAR_NOGLOB); 84728ae2e3aSKris Kennaway } else { 84828ae2e3aSKris Kennaway set(STRcwd, SAVE(tmp), VAR_READWRITE|VAR_NOGLOB); 84928ae2e3aSKris Kennaway } 85028ae2e3aSKris Kennaway p1 = varval(STRcwd); 85128ae2e3aSKris Kennaway } 85228ae2e3aSKris Kennaway len = Strlen(p1); 85328ae2e3aSKris Kennaway if (len + clen + 1 >= MAXPATHLEN) 85428ae2e3aSKris Kennaway cp[MAXPATHLEN - (len + 1)] = '\0'; 855c80476e4SDavid E. O'Brien (void) Strcpy(tmpdir, p1); 856c80476e4SDavid E. O'Brien (void) Strcat(tmpdir, STRslash); 857c80476e4SDavid E. O'Brien (void) Strcat(tmpdir, cp); 858c80476e4SDavid E. O'Brien xfree((ptr_t) cp); 859c80476e4SDavid E. O'Brien cp = p = Strsave(tmpdir); 860c80476e4SDavid E. O'Brien } 861c80476e4SDavid E. O'Brien 862c80476e4SDavid E. O'Brien #ifdef apollo 863c80476e4SDavid E. O'Brien slashslash = (cp[0] == '/' && cp[1] == '/'); 864c80476e4SDavid E. O'Brien #endif /* apollo */ 865c80476e4SDavid E. O'Brien 866c80476e4SDavid E. O'Brien while (*p) { /* for each component */ 867c80476e4SDavid E. O'Brien sp = p; /* save slash address */ 868c80476e4SDavid E. O'Brien while (*++p == '/') /* flush extra slashes */ 869c80476e4SDavid E. O'Brien continue; 870c80476e4SDavid E. O'Brien if (p != ++sp) 871c80476e4SDavid E. O'Brien for (p1 = sp, p2 = p; (*p1++ = *p2++) != '\0';) 872c80476e4SDavid E. O'Brien continue; 873c80476e4SDavid E. O'Brien p = sp; /* save start of component */ 874c80476e4SDavid E. O'Brien slash = 0; 875c80476e4SDavid E. O'Brien if (*p) 876c80476e4SDavid E. O'Brien while (*++p) /* find next slash or end of path */ 877c80476e4SDavid E. O'Brien if (*p == '/') { 878c80476e4SDavid E. O'Brien slash = 1; 879c80476e4SDavid E. O'Brien *p = 0; 880c80476e4SDavid E. O'Brien break; 881c80476e4SDavid E. O'Brien } 882c80476e4SDavid E. O'Brien 883c80476e4SDavid E. O'Brien #ifdef apollo 884c80476e4SDavid E. O'Brien if (&cp[1] == sp && sp[0] == '.' && sp[1] == '.' && sp[2] == '\0') 885c80476e4SDavid E. O'Brien slashslash = 1; 886c80476e4SDavid E. O'Brien #endif /* apollo */ 887c80476e4SDavid E. O'Brien if (*sp == '\0') { /* if component is null */ 888c80476e4SDavid E. O'Brien if (--sp == cp) /* if path is one char (i.e. /) */ 889c80476e4SDavid E. O'Brien break; 890c80476e4SDavid E. O'Brien else 891c80476e4SDavid E. O'Brien *sp = '\0'; 892c80476e4SDavid E. O'Brien } 893c80476e4SDavid E. O'Brien else if (sp[0] == '.' && sp[1] == 0) { 894c80476e4SDavid E. O'Brien if (slash) { 895c80476e4SDavid E. O'Brien for (p1 = sp, p2 = p + 1; (*p1++ = *p2++) != '\0';) 896c80476e4SDavid E. O'Brien continue; 897c80476e4SDavid E. O'Brien p = --sp; 898c80476e4SDavid E. O'Brien } 899c80476e4SDavid E. O'Brien else if (--sp != cp) 900c80476e4SDavid E. O'Brien *sp = '\0'; 901c80476e4SDavid E. O'Brien else 902c80476e4SDavid E. O'Brien sp[1] = '\0'; 903c80476e4SDavid E. O'Brien } 904c80476e4SDavid E. O'Brien else if (sp[0] == '.' && sp[1] == '.' && sp[2] == 0) { 905c80476e4SDavid E. O'Brien /* 906c80476e4SDavid E. O'Brien * We have something like "yyy/xxx/..", where "yyy" can be null or 907c80476e4SDavid E. O'Brien * a path starting at /, and "xxx" is a single component. Before 908c80476e4SDavid E. O'Brien * compressing "xxx/..", we want to expand "yyy/xxx", if it is a 909c80476e4SDavid E. O'Brien * symbolic link. 910c80476e4SDavid E. O'Brien */ 911c80476e4SDavid E. O'Brien *--sp = 0; /* form the pathname for readlink */ 912c80476e4SDavid E. O'Brien #ifdef S_IFLNK /* if we have symlinks */ 913c80476e4SDavid E. O'Brien if (sp != cp && /* symlinks != SYM_IGNORE && */ 914c80476e4SDavid E. O'Brien (cc = readlink(short2str(cp), tlink, 915c80476e4SDavid E. O'Brien sizeof tlink)) >= 0) { 916c80476e4SDavid E. O'Brien tlink[cc] = '\0'; 917c80476e4SDavid E. O'Brien (void) Strncpy(link, str2short(tlink), 918c80476e4SDavid E. O'Brien sizeof(link) / sizeof(Char)); 919c80476e4SDavid E. O'Brien link[sizeof(link) / sizeof(Char) - 1] = '\0'; 920c80476e4SDavid E. O'Brien 921c80476e4SDavid E. O'Brien if (slash) 922c80476e4SDavid E. O'Brien *p = '/'; 923c80476e4SDavid E. O'Brien /* 924c80476e4SDavid E. O'Brien * Point p to the '/' in "/..", and restore the '/'. 925c80476e4SDavid E. O'Brien */ 926c80476e4SDavid E. O'Brien *(p = sp) = '/'; 927c80476e4SDavid E. O'Brien /* 928c80476e4SDavid E. O'Brien * find length of p 929c80476e4SDavid E. O'Brien */ 930c80476e4SDavid E. O'Brien for (p1 = p; *p1++;) 931c80476e4SDavid E. O'Brien continue; 932c80476e4SDavid E. O'Brien if (*link != '/') { 933c80476e4SDavid E. O'Brien /* 934c80476e4SDavid E. O'Brien * Relative path, expand it between the "yyy/" and the 935c80476e4SDavid E. O'Brien * "/..". First, back sp up to the character past "yyy/". 936c80476e4SDavid E. O'Brien */ 937c80476e4SDavid E. O'Brien while (*--sp != '/') 938c80476e4SDavid E. O'Brien continue; 939c80476e4SDavid E. O'Brien sp++; 940c80476e4SDavid E. O'Brien *sp = 0; 941c80476e4SDavid E. O'Brien /* 942c80476e4SDavid E. O'Brien * New length is "yyy/" + link + "/.." and rest 943c80476e4SDavid E. O'Brien */ 944c80476e4SDavid E. O'Brien p1 = newcp = (Char *) xmalloc((size_t) 945c80476e4SDavid E. O'Brien (((sp - cp) + cc + (p1 - p)) * 946c80476e4SDavid E. O'Brien sizeof(Char))); 947c80476e4SDavid E. O'Brien /* 948c80476e4SDavid E. O'Brien * Copy new path into newcp 949c80476e4SDavid E. O'Brien */ 950c80476e4SDavid E. O'Brien for (p2 = cp; (*p1++ = *p2++) != '\0';) 951c80476e4SDavid E. O'Brien continue; 952c80476e4SDavid E. O'Brien for (p1--, p2 = link; (*p1++ = *p2++) != '\0';) 953c80476e4SDavid E. O'Brien continue; 954c80476e4SDavid E. O'Brien for (p1--, p2 = p; (*p1++ = *p2++) != '\0';) 955c80476e4SDavid E. O'Brien continue; 956c80476e4SDavid E. O'Brien /* 957c80476e4SDavid E. O'Brien * Restart canonicalization at expanded "/xxx". 958c80476e4SDavid E. O'Brien */ 959c80476e4SDavid E. O'Brien p = sp - cp - 1 + newcp; 960c80476e4SDavid E. O'Brien } 961c80476e4SDavid E. O'Brien else { 962c80476e4SDavid E. O'Brien /* 963c80476e4SDavid E. O'Brien * New length is link + "/.." and rest 964c80476e4SDavid E. O'Brien */ 965c80476e4SDavid E. O'Brien p1 = newcp = (Char *) xmalloc((size_t) 966c80476e4SDavid E. O'Brien ((cc + (p1 - p)) * sizeof(Char))); 967c80476e4SDavid E. O'Brien /* 968c80476e4SDavid E. O'Brien * Copy new path into newcp 969c80476e4SDavid E. O'Brien */ 970c80476e4SDavid E. O'Brien for (p2 = link; (*p1++ = *p2++) != '\0';) 971c80476e4SDavid E. O'Brien continue; 972c80476e4SDavid E. O'Brien for (p1--, p2 = p; (*p1++ = *p2++) != '\0';) 973c80476e4SDavid E. O'Brien continue; 974c80476e4SDavid E. O'Brien /* 975c80476e4SDavid E. O'Brien * Restart canonicalization at beginning 976c80476e4SDavid E. O'Brien */ 977c80476e4SDavid E. O'Brien p = newcp; 978c80476e4SDavid E. O'Brien } 979c80476e4SDavid E. O'Brien xfree((ptr_t) cp); 980c80476e4SDavid E. O'Brien cp = newcp; 981c80476e4SDavid E. O'Brien #ifdef apollo 982c80476e4SDavid E. O'Brien slashslash = (cp[0] == '/' && cp[1] == '/'); 983c80476e4SDavid E. O'Brien #endif /* apollo */ 984c80476e4SDavid E. O'Brien continue; /* canonicalize the link */ 985c80476e4SDavid E. O'Brien } 986c80476e4SDavid E. O'Brien #endif /* S_IFLNK */ 987c80476e4SDavid E. O'Brien *sp = '/'; 988c80476e4SDavid E. O'Brien if (sp != cp) 989c80476e4SDavid E. O'Brien while (*--sp != '/') 990c80476e4SDavid E. O'Brien continue; 991c80476e4SDavid E. O'Brien if (slash) { 992c80476e4SDavid E. O'Brien for (p1 = sp + 1, p2 = p + 1; (*p1++ = *p2++) != '\0';) 993c80476e4SDavid E. O'Brien continue; 994c80476e4SDavid E. O'Brien p = sp; 995c80476e4SDavid E. O'Brien } 996c80476e4SDavid E. O'Brien else if (cp == sp) 997c80476e4SDavid E. O'Brien *++sp = '\0'; 998c80476e4SDavid E. O'Brien else 999c80476e4SDavid E. O'Brien *sp = '\0'; 1000c80476e4SDavid E. O'Brien } 1001c80476e4SDavid E. O'Brien else { /* normal dir name (not . or .. or nothing) */ 1002c80476e4SDavid E. O'Brien 1003c80476e4SDavid E. O'Brien #ifdef S_IFLNK /* if we have symlinks */ 1004c80476e4SDavid E. O'Brien if (sp != cp && symlinks == SYM_CHASE && 1005c80476e4SDavid E. O'Brien (cc = readlink(short2str(cp), tlink, 1006c80476e4SDavid E. O'Brien sizeof tlink)) >= 0) { 1007c80476e4SDavid E. O'Brien tlink[cc] = '\0'; 1008c80476e4SDavid E. O'Brien (void) Strncpy(link, str2short(tlink), 1009c80476e4SDavid E. O'Brien sizeof(link) / sizeof(Char)); 1010c80476e4SDavid E. O'Brien link[sizeof(link) / sizeof(Char) - 1] = '\0'; 1011c80476e4SDavid E. O'Brien 1012c80476e4SDavid E. O'Brien /* 1013c80476e4SDavid E. O'Brien * restore the '/'. 1014c80476e4SDavid E. O'Brien */ 1015c80476e4SDavid E. O'Brien if (slash) 1016c80476e4SDavid E. O'Brien *p = '/'; 1017c80476e4SDavid E. O'Brien 1018c80476e4SDavid E. O'Brien /* 1019c80476e4SDavid E. O'Brien * point sp to p (rather than backing up). 1020c80476e4SDavid E. O'Brien */ 1021c80476e4SDavid E. O'Brien sp = p; 1022c80476e4SDavid E. O'Brien 1023c80476e4SDavid E. O'Brien /* 1024c80476e4SDavid E. O'Brien * find length of p 1025c80476e4SDavid E. O'Brien */ 1026c80476e4SDavid E. O'Brien for (p1 = p; *p1++;) 1027c80476e4SDavid E. O'Brien continue; 1028c80476e4SDavid E. O'Brien if (*link != '/') { 1029c80476e4SDavid E. O'Brien /* 1030c80476e4SDavid E. O'Brien * Relative path, expand it between the "yyy/" and the 1031c80476e4SDavid E. O'Brien * remainder. First, back sp up to the character past 1032c80476e4SDavid E. O'Brien * "yyy/". 1033c80476e4SDavid E. O'Brien */ 1034c80476e4SDavid E. O'Brien while (*--sp != '/') 1035c80476e4SDavid E. O'Brien continue; 1036c80476e4SDavid E. O'Brien sp++; 1037c80476e4SDavid E. O'Brien *sp = 0; 1038c80476e4SDavid E. O'Brien /* 1039c80476e4SDavid E. O'Brien * New length is "yyy/" + link + "/.." and rest 1040c80476e4SDavid E. O'Brien */ 1041c80476e4SDavid E. O'Brien p1 = newcp = (Char *) xmalloc((size_t) 1042c80476e4SDavid E. O'Brien (((sp - cp) + cc + (p1 - p)) 1043c80476e4SDavid E. O'Brien * sizeof(Char))); 1044c80476e4SDavid E. O'Brien /* 1045c80476e4SDavid E. O'Brien * Copy new path into newcp 1046c80476e4SDavid E. O'Brien */ 1047c80476e4SDavid E. O'Brien for (p2 = cp; (*p1++ = *p2++) != '\0';) 1048c80476e4SDavid E. O'Brien continue; 1049c80476e4SDavid E. O'Brien for (p1--, p2 = link; (*p1++ = *p2++) != '\0';) 1050c80476e4SDavid E. O'Brien continue; 1051c80476e4SDavid E. O'Brien for (p1--, p2 = p; (*p1++ = *p2++) != '\0';) 1052c80476e4SDavid E. O'Brien continue; 1053c80476e4SDavid E. O'Brien /* 1054c80476e4SDavid E. O'Brien * Restart canonicalization at expanded "/xxx". 1055c80476e4SDavid E. O'Brien */ 1056c80476e4SDavid E. O'Brien p = sp - cp - 1 + newcp; 1057c80476e4SDavid E. O'Brien } 1058c80476e4SDavid E. O'Brien else { 1059c80476e4SDavid E. O'Brien /* 1060c80476e4SDavid E. O'Brien * New length is link + the rest 1061c80476e4SDavid E. O'Brien */ 1062c80476e4SDavid E. O'Brien p1 = newcp = (Char *) xmalloc((size_t) 1063c80476e4SDavid E. O'Brien ((cc + (p1 - p)) * sizeof(Char))); 1064c80476e4SDavid E. O'Brien /* 1065c80476e4SDavid E. O'Brien * Copy new path into newcp 1066c80476e4SDavid E. O'Brien */ 1067c80476e4SDavid E. O'Brien for (p2 = link; (*p1++ = *p2++) != '\0';) 1068c80476e4SDavid E. O'Brien continue; 1069c80476e4SDavid E. O'Brien for (p1--, p2 = p; (*p1++ = *p2++) != '\0';) 1070c80476e4SDavid E. O'Brien continue; 1071c80476e4SDavid E. O'Brien /* 1072c80476e4SDavid E. O'Brien * Restart canonicalization at beginning 1073c80476e4SDavid E. O'Brien */ 1074c80476e4SDavid E. O'Brien p = newcp; 1075c80476e4SDavid E. O'Brien } 1076c80476e4SDavid E. O'Brien xfree((ptr_t) cp); 1077c80476e4SDavid E. O'Brien cp = newcp; 1078c80476e4SDavid E. O'Brien #ifdef apollo 1079c80476e4SDavid E. O'Brien slashslash = (cp[0] == '/' && cp[1] == '/'); 1080c80476e4SDavid E. O'Brien #endif /* apollo */ 1081c80476e4SDavid E. O'Brien continue; /* canonicalize the link */ 1082c80476e4SDavid E. O'Brien } 1083c80476e4SDavid E. O'Brien #endif /* S_IFLNK */ 1084c80476e4SDavid E. O'Brien if (slash) 1085c80476e4SDavid E. O'Brien *p = '/'; 1086c80476e4SDavid E. O'Brien } 1087c80476e4SDavid E. O'Brien } 1088c80476e4SDavid E. O'Brien 1089c80476e4SDavid E. O'Brien /* 1090c80476e4SDavid E. O'Brien * fix home... 1091c80476e4SDavid E. O'Brien */ 1092c80476e4SDavid E. O'Brien #ifdef S_IFLNK 1093c80476e4SDavid E. O'Brien p1 = varval(STRhome); 1094c80476e4SDavid E. O'Brien cc = (int) Strlen(p1); 1095c80476e4SDavid E. O'Brien /* 1096c80476e4SDavid E. O'Brien * See if we're not in a subdir of STRhome 1097c80476e4SDavid E. O'Brien */ 1098c80476e4SDavid E. O'Brien if (p1 && *p1 == '/' && (Strncmp(p1, cp, (size_t) cc) != 0 || 1099c80476e4SDavid E. O'Brien (cp[cc] != '/' && cp[cc] != '\0'))) { 1100c80476e4SDavid E. O'Brien static ino_t home_ino = (ino_t) -1; 1101c80476e4SDavid E. O'Brien static dev_t home_dev = (dev_t) -1; 1102c80476e4SDavid E. O'Brien static Char *home_ptr = NULL; 1103c80476e4SDavid E. O'Brien struct stat statbuf; 1104c80476e4SDavid E. O'Brien int found; 1105c80476e4SDavid E. O'Brien 1106c80476e4SDavid E. O'Brien /* 1107c80476e4SDavid E. O'Brien * Get dev and ino of STRhome 1108c80476e4SDavid E. O'Brien */ 1109c80476e4SDavid E. O'Brien if (home_ptr != p1 && 1110c80476e4SDavid E. O'Brien stat(short2str(p1), &statbuf) != -1) { 1111c80476e4SDavid E. O'Brien home_dev = statbuf.st_dev; 1112c80476e4SDavid E. O'Brien home_ino = statbuf.st_ino; 1113c80476e4SDavid E. O'Brien home_ptr = p1; 1114c80476e4SDavid E. O'Brien } 1115c80476e4SDavid E. O'Brien /* 1116c80476e4SDavid E. O'Brien * Start comparing dev & ino backwards 1117c80476e4SDavid E. O'Brien */ 1118c80476e4SDavid E. O'Brien p2 = Strncpy(link, cp, sizeof(link) / sizeof(Char)); 1119c80476e4SDavid E. O'Brien link[sizeof(link) / sizeof(Char) - 1] = '\0'; 1120c80476e4SDavid E. O'Brien found = 0; 1121c80476e4SDavid E. O'Brien while (*p2 && stat(short2str(p2), &statbuf) != -1) { 1122c80476e4SDavid E. O'Brien if (DEV_DEV_COMPARE(statbuf.st_dev, home_dev) && 1123c80476e4SDavid E. O'Brien statbuf.st_ino == home_ino) { 1124c80476e4SDavid E. O'Brien found = 1; 1125c80476e4SDavid E. O'Brien break; 1126c80476e4SDavid E. O'Brien } 1127c80476e4SDavid E. O'Brien if ((sp = Strrchr(p2, '/')) != NULL) 1128c80476e4SDavid E. O'Brien *sp = '\0'; 1129c80476e4SDavid E. O'Brien } 1130c80476e4SDavid E. O'Brien /* 1131c80476e4SDavid E. O'Brien * See if we found it 1132c80476e4SDavid E. O'Brien */ 1133c80476e4SDavid E. O'Brien if (*p2 && found) { 1134c80476e4SDavid E. O'Brien /* 1135c80476e4SDavid E. O'Brien * Use STRhome to make '~' work 1136c80476e4SDavid E. O'Brien */ 1137c80476e4SDavid E. O'Brien newcp = Strspl(p1, cp + Strlen(p2)); 1138c80476e4SDavid E. O'Brien xfree((ptr_t) cp); 1139c80476e4SDavid E. O'Brien cp = newcp; 1140c80476e4SDavid E. O'Brien } 1141c80476e4SDavid E. O'Brien } 1142c80476e4SDavid E. O'Brien #endif /* S_IFLNK */ 1143c80476e4SDavid E. O'Brien 1144c80476e4SDavid E. O'Brien #ifdef apollo 1145c80476e4SDavid E. O'Brien if (slashslash) { 1146c80476e4SDavid E. O'Brien if (cp[1] != '/') { 1147c80476e4SDavid E. O'Brien p = (Char *) xmalloc((size_t) (Strlen(cp) + 2) * sizeof(Char)); 1148c80476e4SDavid E. O'Brien *p = '/'; 1149c80476e4SDavid E. O'Brien (void) Strcpy(&p[1], cp); 1150c80476e4SDavid E. O'Brien xfree((ptr_t) cp); 1151c80476e4SDavid E. O'Brien cp = p; 1152c80476e4SDavid E. O'Brien } 1153c80476e4SDavid E. O'Brien } 1154c80476e4SDavid E. O'Brien if (cp[1] == '/' && cp[2] == '/') 1155c80476e4SDavid E. O'Brien (void) Strcpy(&cp[1], &cp[2]); 1156c80476e4SDavid E. O'Brien #endif /* apollo */ 1157c80476e4SDavid E. O'Brien return cp; 1158c80476e4SDavid E. O'Brien } 1159c80476e4SDavid E. O'Brien 1160c80476e4SDavid E. O'Brien 1161c80476e4SDavid E. O'Brien /* 1162c80476e4SDavid E. O'Brien * dnewcwd - make a new directory in the loop the current one 1163c80476e4SDavid E. O'Brien */ 1164c80476e4SDavid E. O'Brien static void 1165c80476e4SDavid E. O'Brien dnewcwd(dp, dflag) 1166c80476e4SDavid E. O'Brien register struct directory *dp; 1167c80476e4SDavid E. O'Brien int dflag; 1168c80476e4SDavid E. O'Brien { 1169c80476e4SDavid E. O'Brien int print; 1170c80476e4SDavid E. O'Brien 1171c80476e4SDavid E. O'Brien if (adrof(STRdunique)) { 1172c80476e4SDavid E. O'Brien struct directory *dn; 1173c80476e4SDavid E. O'Brien 1174c80476e4SDavid E. O'Brien for (dn = dhead.di_prev; dn != &dhead; dn = dn->di_prev) 1175c80476e4SDavid E. O'Brien if (dn != dp && Strcmp(dn->di_name, dp->di_name) == 0) { 1176c80476e4SDavid E. O'Brien dn->di_next->di_prev = dn->di_prev; 1177c80476e4SDavid E. O'Brien dn->di_prev->di_next = dn->di_next; 1178c80476e4SDavid E. O'Brien dfree(dn); 1179c80476e4SDavid E. O'Brien break; 1180c80476e4SDavid E. O'Brien } 1181c80476e4SDavid E. O'Brien } 1182c80476e4SDavid E. O'Brien dcwd = dp; 1183c80476e4SDavid E. O'Brien dset(dcwd->di_name); 1184c80476e4SDavid E. O'Brien dgetstack(); 1185c80476e4SDavid E. O'Brien print = printd; /* if printd is set, print dirstack... */ 1186c80476e4SDavid E. O'Brien if (adrof(STRpushdsilent)) /* but pushdsilent overrides printd... */ 1187c80476e4SDavid E. O'Brien print = 0; 1188c80476e4SDavid E. O'Brien if (dflag & DIR_PRINT) /* but DIR_PRINT overrides pushdsilent... */ 1189c80476e4SDavid E. O'Brien print = 1; 1190c80476e4SDavid E. O'Brien if (bequiet) /* and bequiet overrides everything */ 1191c80476e4SDavid E. O'Brien print = 0; 1192c80476e4SDavid E. O'Brien if (print) 1193c80476e4SDavid E. O'Brien printdirs(dflag); 1194c80476e4SDavid E. O'Brien cwd_cmd(); /* PWP: run the defined cwd command */ 1195c80476e4SDavid E. O'Brien } 1196c80476e4SDavid E. O'Brien 1197c80476e4SDavid E. O'Brien void 1198c80476e4SDavid E. O'Brien dsetstack() 1199c80476e4SDavid E. O'Brien { 1200c80476e4SDavid E. O'Brien Char **cp; 1201c80476e4SDavid E. O'Brien struct varent *vp; 1202c80476e4SDavid E. O'Brien struct directory *dn, *dp; 1203c80476e4SDavid E. O'Brien 1204c80476e4SDavid E. O'Brien if ((vp = adrof(STRdirstack)) == NULL) 1205c80476e4SDavid E. O'Brien return; 1206c80476e4SDavid E. O'Brien 1207c80476e4SDavid E. O'Brien /* Free the whole stack */ 1208c80476e4SDavid E. O'Brien while ((dn = dhead.di_prev) != &dhead) { 1209c80476e4SDavid E. O'Brien dn->di_next->di_prev = dn->di_prev; 1210c80476e4SDavid E. O'Brien dn->di_prev->di_next = dn->di_next; 1211c80476e4SDavid E. O'Brien if (dn != dcwd) 1212c80476e4SDavid E. O'Brien dfree(dn); 1213c80476e4SDavid E. O'Brien } 1214c80476e4SDavid E. O'Brien 1215c80476e4SDavid E. O'Brien /* thread the current working directory */ 1216c80476e4SDavid E. O'Brien dhead.di_prev = dhead.di_next = dcwd; 1217c80476e4SDavid E. O'Brien dcwd->di_next = dcwd->di_prev = &dhead; 1218c80476e4SDavid E. O'Brien 1219c80476e4SDavid E. O'Brien /* put back the stack */ 1220c80476e4SDavid E. O'Brien for (cp = vp->vec; cp && *cp && **cp; cp++) { 1221c80476e4SDavid E. O'Brien dp = (struct directory *) xcalloc(sizeof(struct directory), 1); 1222c80476e4SDavid E. O'Brien dp->di_name = Strsave(*cp); 1223c80476e4SDavid E. O'Brien dp->di_count = 0; 1224c80476e4SDavid E. O'Brien dp->di_prev = dcwd; 1225c80476e4SDavid E. O'Brien dp->di_next = dcwd->di_next; 1226c80476e4SDavid E. O'Brien dcwd->di_next = dp; 1227c80476e4SDavid E. O'Brien dp->di_next->di_prev = dp; 1228c80476e4SDavid E. O'Brien } 1229c80476e4SDavid E. O'Brien dgetstack(); /* Make $dirstack reflect the current state */ 1230c80476e4SDavid E. O'Brien } 1231c80476e4SDavid E. O'Brien 1232c80476e4SDavid E. O'Brien static void 1233c80476e4SDavid E. O'Brien dgetstack() 1234c80476e4SDavid E. O'Brien { 1235c80476e4SDavid E. O'Brien int i = 0; 1236c80476e4SDavid E. O'Brien Char **dblk, **dbp; 1237c80476e4SDavid E. O'Brien struct directory *dn; 1238c80476e4SDavid E. O'Brien 1239c80476e4SDavid E. O'Brien if (adrof(STRdirstack) == NULL) 1240c80476e4SDavid E. O'Brien return; 1241c80476e4SDavid E. O'Brien 1242c80476e4SDavid E. O'Brien for (dn = dhead.di_prev; dn != &dhead; dn = dn->di_prev, i++) 1243c80476e4SDavid E. O'Brien continue; 1244c80476e4SDavid E. O'Brien dbp = dblk = (Char**) xmalloc((size_t) (i + 1) * sizeof(Char *)); 1245c80476e4SDavid E. O'Brien for (dn = dhead.di_prev; dn != &dhead; dn = dn->di_prev, dbp++) 1246c80476e4SDavid E. O'Brien *dbp = Strsave(dn->di_name); 1247c80476e4SDavid E. O'Brien *dbp = NULL; 1248c80476e4SDavid E. O'Brien setq(STRdirstack, dblk, &shvhed, VAR_READWRITE); 1249c80476e4SDavid E. O'Brien } 1250c80476e4SDavid E. O'Brien 1251c80476e4SDavid E. O'Brien /* 1252c80476e4SDavid E. O'Brien * getstakd - added by kfk 17 Jan 1984 1253c80476e4SDavid E. O'Brien * Support routine for the stack hack. Finds nth directory in 1254c80476e4SDavid E. O'Brien * the directory stack, or finds last directory in stack. 1255c80476e4SDavid E. O'Brien */ 1256c80476e4SDavid E. O'Brien int 1257c80476e4SDavid E. O'Brien getstakd(s, cnt) 1258c80476e4SDavid E. O'Brien Char *s; 1259c80476e4SDavid E. O'Brien int cnt; 1260c80476e4SDavid E. O'Brien { 1261c80476e4SDavid E. O'Brien struct directory *dp; 1262c80476e4SDavid E. O'Brien 1263c80476e4SDavid E. O'Brien dp = dcwd; 1264c80476e4SDavid E. O'Brien if (cnt < 0) { /* < 0 ==> last dir requested. */ 1265c80476e4SDavid E. O'Brien dp = dp->di_next; 1266c80476e4SDavid E. O'Brien if (dp == &dhead) 1267c80476e4SDavid E. O'Brien dp = dp->di_next; 1268c80476e4SDavid E. O'Brien } 1269c80476e4SDavid E. O'Brien else { 1270c80476e4SDavid E. O'Brien while (cnt-- > 0) { 1271c80476e4SDavid E. O'Brien dp = dp->di_prev; 1272c80476e4SDavid E. O'Brien if (dp == &dhead) 1273c80476e4SDavid E. O'Brien dp = dp->di_prev; 1274c80476e4SDavid E. O'Brien if (dp == dcwd) 1275c80476e4SDavid E. O'Brien return (0); 1276c80476e4SDavid E. O'Brien } 1277c80476e4SDavid E. O'Brien } 12783b6eaa7bSAndrey A. Chernov (void) Strncpy(s, dp->di_name, BUFSIZE); 12793b6eaa7bSAndrey A. Chernov s[BUFSIZE - 1] = '\0'; 1280c80476e4SDavid E. O'Brien return (1); 1281c80476e4SDavid E. O'Brien } 1282c80476e4SDavid E. O'Brien 1283c80476e4SDavid E. O'Brien /* 1284c80476e4SDavid E. O'Brien * Karl Kleinpaste - 10 Feb 1984 1285c80476e4SDavid E. O'Brien * Added dextract(), which is used in pushd +n. 1286c80476e4SDavid E. O'Brien * Instead of just rotating the entire stack around, dextract() 1287c80476e4SDavid E. O'Brien * lets the user have the nth dir extracted from its current 1288c80476e4SDavid E. O'Brien * position, and pushes it onto the top. 1289c80476e4SDavid E. O'Brien */ 1290c80476e4SDavid E. O'Brien static void 1291c80476e4SDavid E. O'Brien dextract(dp) 1292c80476e4SDavid E. O'Brien struct directory *dp; 1293c80476e4SDavid E. O'Brien { 1294c80476e4SDavid E. O'Brien if (dp == dcwd) 1295c80476e4SDavid E. O'Brien return; 1296c80476e4SDavid E. O'Brien dp->di_next->di_prev = dp->di_prev; 1297c80476e4SDavid E. O'Brien dp->di_prev->di_next = dp->di_next; 1298c80476e4SDavid E. O'Brien dp->di_next = dcwd->di_next; 1299c80476e4SDavid E. O'Brien dp->di_prev = dcwd; 1300c80476e4SDavid E. O'Brien dp->di_next->di_prev = dp; 1301c80476e4SDavid E. O'Brien dcwd->di_next = dp; 1302c80476e4SDavid E. O'Brien } 1303c80476e4SDavid E. O'Brien 1304c80476e4SDavid E. O'Brien void 1305c80476e4SDavid E. O'Brien loaddirs(fname) 1306c80476e4SDavid E. O'Brien Char *fname; 1307c80476e4SDavid E. O'Brien { 1308c80476e4SDavid E. O'Brien static Char *loaddirs_cmd[] = { STRsource, NULL, NULL }; 1309c80476e4SDavid E. O'Brien 1310c80476e4SDavid E. O'Brien bequiet = 1; 1311c80476e4SDavid E. O'Brien if (fname) 1312c80476e4SDavid E. O'Brien loaddirs_cmd[1] = fname; 1313c80476e4SDavid E. O'Brien else if ((fname = varval(STRdirsfile)) != STRNULL) 1314c80476e4SDavid E. O'Brien loaddirs_cmd[1] = fname; 1315c80476e4SDavid E. O'Brien else 1316c80476e4SDavid E. O'Brien loaddirs_cmd[1] = STRtildotdirs; 1317c80476e4SDavid E. O'Brien dosource(loaddirs_cmd, (struct command *)0); 1318c80476e4SDavid E. O'Brien bequiet = 0; 1319c80476e4SDavid E. O'Brien } 1320c80476e4SDavid E. O'Brien 1321c80476e4SDavid E. O'Brien /* 1322c80476e4SDavid E. O'Brien * create a file called ~/.cshdirs which has a sequence 1323c80476e4SDavid E. O'Brien * of pushd commands which will restore the dir stack to 1324c80476e4SDavid E. O'Brien * its state before exit/logout. remember that the order 1325c80476e4SDavid E. O'Brien * is reversed in the file because we are pushing. 1326c80476e4SDavid E. O'Brien * -strike 1327c80476e4SDavid E. O'Brien */ 1328c80476e4SDavid E. O'Brien void 1329c80476e4SDavid E. O'Brien recdirs(fname, def) 1330c80476e4SDavid E. O'Brien Char *fname; 1331c80476e4SDavid E. O'Brien int def; 1332c80476e4SDavid E. O'Brien { 1333c80476e4SDavid E. O'Brien int fp, ftmp, oldidfds; 1334c80476e4SDavid E. O'Brien int cdflag = 0; 1335c80476e4SDavid E. O'Brien extern struct directory *dcwd; 1336c80476e4SDavid E. O'Brien struct directory *dp; 1337c80476e4SDavid E. O'Brien unsigned int num; 1338c80476e4SDavid E. O'Brien Char *snum; 1339c80476e4SDavid E. O'Brien Char qname[MAXPATHLEN*2]; 1340c80476e4SDavid E. O'Brien 1341c80476e4SDavid E. O'Brien if (fname == NULL && !def) 1342c80476e4SDavid E. O'Brien return; 1343c80476e4SDavid E. O'Brien 1344c80476e4SDavid E. O'Brien if (fname == NULL) { 1345c80476e4SDavid E. O'Brien if ((fname = varval(STRdirsfile)) == STRNULL) 1346c80476e4SDavid E. O'Brien fname = Strspl(varval(STRhome), &STRtildotdirs[1]); 1347c80476e4SDavid E. O'Brien else 1348c80476e4SDavid E. O'Brien fname = Strsave(fname); 1349c80476e4SDavid E. O'Brien } 1350c80476e4SDavid E. O'Brien else 1351c80476e4SDavid E. O'Brien fname = globone(fname, G_ERROR); 1352c80476e4SDavid E. O'Brien 1353c80476e4SDavid E. O'Brien if ((fp = creat(short2str(fname), 0600)) == -1) { 1354c80476e4SDavid E. O'Brien xfree((ptr_t) fname); 1355c80476e4SDavid E. O'Brien return; 1356c80476e4SDavid E. O'Brien } 1357c80476e4SDavid E. O'Brien 13586767bd61SMark Peek if ((snum = varval(STRsavedirs)) == STRNULL || snum[0] == '\0') 1359c80476e4SDavid E. O'Brien num = (unsigned int) ~0; 1360c80476e4SDavid E. O'Brien else 1361c80476e4SDavid E. O'Brien num = (unsigned int) atoi(short2str(snum)); 1362c80476e4SDavid E. O'Brien 1363c80476e4SDavid E. O'Brien oldidfds = didfds; 1364c80476e4SDavid E. O'Brien didfds = 0; 1365c80476e4SDavid E. O'Brien ftmp = SHOUT; 1366c80476e4SDavid E. O'Brien SHOUT = fp; 1367c80476e4SDavid E. O'Brien 1368c80476e4SDavid E. O'Brien dp = dcwd->di_next; 1369c80476e4SDavid E. O'Brien do { 1370c80476e4SDavid E. O'Brien if (dp == &dhead) 1371c80476e4SDavid E. O'Brien continue; 1372c80476e4SDavid E. O'Brien 1373c80476e4SDavid E. O'Brien if (cdflag == 0) { 1374c80476e4SDavid E. O'Brien cdflag = 1; 1375c80476e4SDavid E. O'Brien xprintf("cd %S\n", quote_meta(qname, dp->di_name)); 1376c80476e4SDavid E. O'Brien } 1377c80476e4SDavid E. O'Brien else 1378c80476e4SDavid E. O'Brien xprintf("pushd %S\n", quote_meta(qname, dp->di_name)); 1379c80476e4SDavid E. O'Brien 1380c80476e4SDavid E. O'Brien if (num-- == 0) 1381c80476e4SDavid E. O'Brien break; 1382c80476e4SDavid E. O'Brien 1383c80476e4SDavid E. O'Brien } while ((dp = dp->di_next) != dcwd->di_next); 1384c80476e4SDavid E. O'Brien 1385c80476e4SDavid E. O'Brien (void) close(fp); 1386c80476e4SDavid E. O'Brien SHOUT = ftmp; 1387c80476e4SDavid E. O'Brien didfds = oldidfds; 1388c80476e4SDavid E. O'Brien xfree((ptr_t) fname); 1389c80476e4SDavid E. O'Brien } 1390