From 09086b04991a49889fe2c0c4a1bb98ee54387d2b Mon Sep 17 00:00:00 2001 From: "Tim J. Robbins" Date: Wed, 22 May 2002 05:15:53 +0000 Subject: [PATCH] Bring back the cd -L and -P options from revision 1.24, but try harder not to fail when the logical current directory no longer exists. Allow changes to absolute paths when logical cwd is invalid, fall back to physical cd if logical cd fails. --- bin/sh/cd.c | 140 +++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 106 insertions(+), 34 deletions(-) diff --git a/bin/sh/cd.c b/bin/sh/cd.c index 26ad2f25d1f..2c0e6dcd456 100644 --- a/bin/sh/cd.c +++ b/bin/sh/cd.c @@ -67,25 +67,47 @@ static const char rcsid[] = #include "show.h" #include "cd.h" -STATIC int docd(char *, int); +STATIC int cdlogical(char *); +STATIC int cdphysical(char *); +STATIC int docd(char *, int, int); STATIC char *getcomponent(void); -STATIC void updatepwd(char *); +STATIC int updatepwd(char *); char *curdir = NULL; /* current working directory */ char *prevdir; /* previous working directory */ STATIC char *cdcomppath; int -cdcmd(int argc __unused, char **argv __unused) +cdcmd(int argc, char **argv) { char *dest; char *path; char *p; struct stat statb; - int print = 0; + int ch, phys, print = 0; - nextopt(nullstr); - if ((dest = *argptr) == NULL && (dest = bltinlookup("HOME", 1)) == NULL) + optreset = 1; optind = 1; /* initialize getopt */ + phys = 0; + while ((ch = getopt(argc, argv, "LP")) != -1) { + switch (ch) { + case 'L': + phys = 0; + break; + case 'P': + phys = 1; + break; + default: + error("unknown option: -%c", optopt); + break; + } + } + argc -= optind; + argv += optind; + + if (argc > 1) + error("too many arguments"); + + if ((dest = *argv) == NULL && (dest = bltinlookup("HOME", 1)) == NULL) error("HOME not set"); if (*dest == '\0') dest = "."; @@ -108,9 +130,8 @@ cdcmd(int argc __unused, char **argv __unused) p += 2; print = strcmp(p, dest); } - if (docd(p, print) >= 0) + if (docd(p, print, phys) >= 0) return 0; - } } error("can't cd to %s", dest); @@ -120,11 +141,27 @@ cdcmd(int argc __unused, char **argv __unused) /* - * Actually do the chdir. In an interactive shell, print the + * Actually change the directory. In an interactive shell, print the * directory name if "print" is nonzero. */ STATIC int -docd(char *dest, int print) +docd(char *dest, int print, int phys) +{ + + TRACE(("docd(\"%s\", %d, %d) called\n", dest, print, phys)); + + /* If logical cd fails, fall back to physical. */ + if ((phys || cdlogical(dest) < 0) && cdphysical(dest) < 0) + return (-1); + + if (print && iflag && curdir) + out1fmt("%s\n", curdir); + + return 0; +} + +STATIC int +cdlogical(char *dest) { char *p; char *q; @@ -133,8 +170,6 @@ docd(char *dest, int print) int first; int badstat; - TRACE(("docd(\"%s\", %d) called\n", dest, print)); - /* * Check each component of the path. If we find a symlink or * something we can't stat, clear curdir to force a getcwd() @@ -161,26 +196,33 @@ docd(char *dest, int print) if (equal(component, "..")) continue; STACKSTRNUL(p); - if ((lstat(stackblock(), &statb) < 0) - || (S_ISLNK(statb.st_mode))) { - /* print = 1; */ + if (lstat(stackblock(), &statb) < 0) { badstat = 1; break; } } INTOFF; - if (chdir(dest) < 0) { + if (updatepwd(badstat ? NULL : dest) < 0 || chdir(curdir) < 0) { INTON; - return -1; + return (-1); } - updatepwd(badstat ? NULL : dest); INTON; - if (print && iflag && curdir) - out1fmt("%s\n", curdir); - return 0; + return (0); } +STATIC int +cdphysical(char *dest) +{ + + INTOFF; + if (chdir(dest) < 0 || updatepwd(NULL) < 0) { + INTON; + return (-1); + } + INTON; + return (0); +} /* * Get the next component of the path name pointed to by cdcomppath. @@ -212,7 +254,7 @@ getcomponent(void) * cd command. We also call hashcd to let the routines in exec.c know * that the current directory has changed. */ -STATIC void +STATIC int updatepwd(char *dir) { char *new; @@ -231,12 +273,14 @@ updatepwd(char *dir) INTOFF; prevdir = curdir; curdir = NULL; - if (getpwd() == NULL) - error("getcwd() failed: %s", strerror(errno)); + if (getpwd() == NULL) { + INTON; + return (-1); + } setvar("PWD", curdir, VEXPORT); setvar("OLDPWD", prevdir, VEXPORT); INTON; - return; + return (0); } cdcomppath = stalloc(strlen(dir) + 1); scopy(dir, cdcomppath); @@ -268,24 +312,52 @@ updatepwd(char *dir) setvar("PWD", curdir, VEXPORT); setvar("OLDPWD", prevdir, VEXPORT); INTON; + + return (0); } +#define MAXPWD 256 int pwdcmd(int argc __unused, char **argv __unused) { - if (!getpwd()) - error("getcwd() failed: %s", strerror(errno)); - out1str(curdir); - out1c('\n'); + char buf[MAXPWD]; + int ch, phys; + + optreset = 1; optind = 1; /* initialize getopt */ + phys = 0; + while ((ch = getopt(argc, argv, "LP")) != -1) { + switch (ch) { + case 'L': + phys = 0; + break; + case 'P': + phys = 1; + break; + default: + error("unknown option: -%c", optopt); + break; + } + } + argc -= optind; + argv += optind; + + if (argc != 0) + error("too many arguments"); + + if (!phys && getpwd()) { + out1str(curdir); + out1c('\n'); + } else { + if (getcwd(buf, sizeof(buf)) == NULL) + error(".: %s", strerror(errno)); + out1str(buf); + out1c('\n'); + } + return 0; } - - - -#define MAXPWD 256 - /* * Find out what the current directory is. If we already know the current * directory, this routine returns immediately.