diff --git a/bin/pwd/pwd.1 b/bin/pwd/pwd.1 index 98fb967c3332..a6573ca31100 100644 --- a/bin/pwd/pwd.1 +++ b/bin/pwd/pwd.1 @@ -35,7 +35,7 @@ .\" @(#)pwd.1 8.2 (Berkeley) 4/28/95 .\" $FreeBSD$ .\" -.Dd April 28, 1995 +.Dd February 4, 2002 .Dt PWD 1 .Os .Sh NAME @@ -43,6 +43,7 @@ .Nd return working directory name .Sh SYNOPSIS .Nm +.Op Fl L | P .Sh DESCRIPTION .Nm Pwd writes the absolute pathname of the current working directory to @@ -54,17 +55,32 @@ command which is similar or identical to this utility. Consult the .Xr builtin 1 manual page. +.Pp +The options are as follows: +.Bl -tag -width indent +.It Fl L +Display the logical current working directory. +.It Fl P +Display the physical current working directory (all symbolic links resolved). +.El +.Pp +If no options are specified, the +.Fl P +option is assumed. +.Sh ENVIRONMENT +Environment variables used by +.Nm : +.Bl -tag -width PWD +.It Ev PWD +Logical current working directory. +.El .Sh DIAGNOSTICS .Ex -std .Sh STANDARDS The .Nm -utility is expected to be -.St -p1003.2 -compatible. -The -.Fl L -flag is not supported. +utility conforms to +.St -p1003.1-2001 . .Sh SEE ALSO .Xr builtin 1 , .Xr cd 1 , @@ -80,3 +96,9 @@ is always faster because it is built into that shell. However, it can give a different answer in the rare case that the current directory or a containing directory was moved after the shell descended into it. +.Pp +The +.Fl L +option does not work unless the +.Ev PWD +environment variable is exported by the shell. diff --git a/bin/pwd/pwd.c b/bin/pwd/pwd.c index 23df46248378..a05f04effb99 100644 --- a/bin/pwd/pwd.c +++ b/bin/pwd/pwd.c @@ -45,31 +45,47 @@ static const char rcsid[] = "$FreeBSD$"; #endif /* not lint */ +#include +#include + #include +#include #include #include #include #include #include +extern char *__progname; + +static char *getcwd_logical(void); void usage(void); int main(int argc, char *argv[]) { + int Lflag, Pflag; int ch; char *p; char buf[PATH_MAX]; - /* - * Flags for pwd are a bit strange. The POSIX 1003.2B/D9 document - * has an optional -P flag for physical, which is what this program - * will produce by default. The logical flag, -L, should fail, as - * there's no way to display a logical path after forking. - */ - while ((ch = getopt(argc, argv, "P")) != -1) + if (strcmp(__progname, "realpath") == 0) { + if (argc != 2) + usage(); + if ((p = realpath(argv[1], buf)) == NULL) + err(1, "%s", argv[1]); + (void)printf("%s\n", p); + exit(0); + } + + Lflag = Pflag = 0; + while ((ch = getopt(argc, argv, "LP")) != -1) switch (ch) { + case 'L': + Lflag = 1; + break; case 'P': + Pflag = 1; break; case '?': default: @@ -78,19 +94,13 @@ main(int argc, char *argv[]) argc -= optind; argv += optind; - if (argc == 1) { - p = realpath(argv[0], buf); - if (p == NULL) - err(1, "%s", argv[0]); - (void)printf("%s\n", p); - } else if (argc == 0) { - p = getcwd(NULL, (size_t)0); - if (p == NULL) - err(1, "."); - (void)printf("%s\n", p); - } else { + if (argc != 0 || (Lflag && Pflag)) usage(); - } + + p = Lflag ? getcwd_logical() : getcwd(NULL, 0); + if (p == NULL) + err(1, "."); + (void)printf("%s\n", p); exit(0); } @@ -99,6 +109,30 @@ void usage(void) { - (void)fprintf(stderr, "usage: pwd\n"); - exit(1); + if (strcmp(__progname, "realpath") == 0) + (void)fprintf(stderr, "usage: realpath [path]\n"); + else + (void)fprintf(stderr, "usage: pwd [-L | -P]\n"); + exit(1); +} + +static char * +getcwd_logical(void) +{ + struct stat log, phy; + char *pwd; + + /* + * Check that $PWD is an absolute logical pathname referring to + * the current working directory. + */ + if ((pwd = getenv("PWD")) != NULL && *pwd == '/') { + if (stat(pwd, &log) == -1 || stat(".", &phy) == -1) + return (NULL); + if (log.st_dev == phy.st_dev && log.st_ino == phy.st_ino) + return (pwd); + } + + errno = ENOENT; + return (NULL); }