From 178897f127fb713d617f86606b5015761900c212 Mon Sep 17 00:00:00 2001 From: "Tim J. Robbins" Date: Mon, 20 May 2002 07:54:39 +0000 Subject: [PATCH] Add the SUSv3 -L and -P options to the cd and pwd builtin utilities. `Logical' handling of .. is now the default. --- bin/sh/cd.c | 100 ++++++++++++++++++++++++++++++++++++++++------------ bin/sh/sh.1 | 34 ++++++++++++++++-- 2 files changed, 110 insertions(+), 24 deletions(-) diff --git a/bin/sh/cd.c b/bin/sh/cd.c index 26ad2f25d1f..b7473badeb3 100644 --- a/bin/sh/cd.c +++ b/bin/sh/cd.c @@ -67,7 +67,7 @@ static const char rcsid[] = #include "show.h" #include "cd.h" -STATIC int docd(char *, int); +STATIC int docd(char *, int, int); STATIC char *getcomponent(void); STATIC void updatepwd(char *); @@ -76,16 +76,36 @@ 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; + + 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"); - nextopt(nullstr); - if ((dest = *argptr) == NULL && (dest = bltinlookup("HOME", 1)) == NULL) + if ((dest = *argv) == NULL && (dest = bltinlookup("HOME", 1)) == NULL) error("HOME not set"); if (*dest == '\0') dest = "."; @@ -108,9 +128,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); @@ -124,7 +143,7 @@ cdcmd(int argc __unused, char **argv __unused) * directory name if "print" is nonzero. */ STATIC int -docd(char *dest, int print) +docd(char *dest, int print, int phys) { char *p; char *q; @@ -133,7 +152,20 @@ docd(char *dest, int print) int first; int badstat; - TRACE(("docd(\"%s\", %d) called\n", dest, print)); + TRACE(("docd(\"%s\", %d, %d) called\n", dest, print, phys)); + + if (phys) { + INTOFF; + if (chdir(dest) < 0) { + INTON; + return -1; + } + updatepwd(NULL); + INTON; + if (print && iflag && curdir) + out1fmt("%s\n", curdir); + return 0; + } /* * Check each component of the path. If we find a symlink or @@ -161,20 +193,18 @@ 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) { + updatepwd(badstat ? NULL : dest); + if (chdir(curdir) < 0) { INTON; return -1; } - updatepwd(badstat ? NULL : dest); INTON; if (print && iflag && curdir) out1fmt("%s\n", curdir); @@ -270,21 +300,47 @@ updatepwd(char *dir) INTON; } +#define MAXPWD 256 int pwdcmd(int argc __unused, char **argv __unused) { - if (!getpwd()) - error("getcwd() failed: %s", strerror(errno)); - out1str(curdir); - out1c('\n'); - return 0; -} - + 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'); + } -#define MAXPWD 256 + return 0; +} /* * Find out what the current directory is. If we already know the current diff --git a/bin/sh/sh.1 b/bin/sh/sh.1 index 54e4465e610..85186875619 100644 --- a/bin/sh/sh.1 +++ b/bin/sh/sh.1 @@ -1317,7 +1317,11 @@ Execute the specified builtin command, .Ar cmd . This is useful when the user wishes to override a shell function with the same name as a builtin command. -.It Ic cd Op Ar directory +.It Xo +.Ic cd +.Op Fl LP +.Op Ar directory +.Xc Switch to the specified .Ar directory , or to the directory specified in the @@ -1351,6 +1355,20 @@ if this is different from the name that the user gave. These may be different either because the .Ev CDPATH mechanism was used or because a symbolic link was crossed. +.Pp +If the +.Fl P +option is specified, +.Dq \&.. +is handled physically and symbolic links are resolved before +.Dq \&.. +components are processed. +If the +.Fl L +option is specified, +.Dq \&.. +is handled logically. +This is the default. .It Ic chdir A synonym for the .Ic cd @@ -1622,7 +1640,10 @@ argument is omitted, use the current job. .It Ic jobs This command lists out all the background processes which are children of the current shell process. -.It Ic pwd +.It Xo +.Ic pwd +.Op Fl LP +.Xc Print the path of the current directory. The builtin command may differ from the program of the same name because the builtin command remembers what the current directory @@ -1632,6 +1653,15 @@ renamed, the builtin version of .Xr pwd 1 will continue to print the old name for the directory. +.Pp +If the +.Fl P +option is specified, symbolic links are resolved. +If the +.Fl L +option is specified, the shell's notion of the current directory +is printed (symbolic links are not resolved). +This is the default. .It Xo .Ic read .Op Fl p Ar prompt -- 2.45.2