Make /bin/pwd almost conform to IEEE 1003.1

- Make 'pwd -L' fall back to 'pwd -P' if PWD is incorrect.
- Ignore PWD if it contains "/./" or "/../".
- Garbage collect some redundant code.
It is still non-conformant because posix mandates that the default
be 'pwd -L' (aka ksh), not 'pwd -P' (historic practise everywhere else).
Changing the default will break too much...
This commit is contained in:
dsl 2003-10-30 13:52:23 +00:00
parent 6d25a1e180
commit db9b05af0d
2 changed files with 66 additions and 52 deletions

View File

@ -1,4 +1,4 @@
.\" $NetBSD: pwd.1,v 1.22 2003/08/07 09:05:25 agc Exp $ .\" $NetBSD: pwd.1,v 1.23 2003/10/30 13:52:23 dsl Exp $
.\" .\"
.\" Copyright (c) 1990, 1993 .\" Copyright (c) 1990, 1993
.\" The Regents of the University of California. All rights reserved. .\" The Regents of the University of California. All rights reserved.
@ -32,7 +32,7 @@
.\" .\"
.\" @(#)pwd.1 8.2 (Berkeley) 4/28/95 .\" @(#)pwd.1 8.2 (Berkeley) 4/28/95
.\" .\"
.Dd November 2, 1998 .Dd October 30, 2003
.Dt PWD 1 .Dt PWD 1
.Os .Os
.Sh NAME .Sh NAME
@ -49,15 +49,25 @@ the standard output.
The following options are available: The following options are available:
.Bl -tag -width indent .Bl -tag -width indent
.It Fl L .It Fl L
Print the logical path to the current working directory, as indicated If the
by the shell in the environment variable .Ev PWD
.Ev PWD , environment variable is an absolute pathname that contains
if possible. neither "/./" nor "/../" and references the current directory, then
.Ev PWD
is assumed to be the name of the current directory.
.It Fl P .It Fl P
Print the physical path to the current working directory, with symbolic Print the physical path to the current working directory, with symbolic
links in the path resolved. links in the path resolved.
This is the default.
.El .El
.Pp
The default for the
.Nm
command is
.Fl P .
.Pp
.Nm
is usually provided as a shell builtin (which may have a different
default).
.Sh EXIT STATUS .Sh EXIT STATUS
The The
.Nm .Nm
@ -65,13 +75,18 @@ utility exits 0 on success, and \*[Gt]0 if an error occurs.
.Sh SEE ALSO .Sh SEE ALSO
.Xr cd 1 , .Xr cd 1 ,
.Xr csh 1 , .Xr csh 1 ,
.Xr ksh 1 ,
.Xr sh 1 ,
.Xr getcwd 3 .Xr getcwd 3
.Sh STANDARDS .Sh STANDARDS
The The
.Nm .Nm
utility is expected to be conforming to utility is expected to be conforming to
.St -p1003.2 . .St -p1003.1 ,
The options are extensions to the standard. except that the default is
.Fl P
not
.Fl L .
.Sh BUGS .Sh BUGS
In In
.Xr csh 1 .Xr csh 1
@ -80,3 +95,13 @@ the command
is always faster (although it can give a different answer in the rare case is always faster (although it can give a different answer in the rare case
that the current directory or a containing directory was moved after that the current directory or a containing directory was moved after
the shell descended into it). the shell descended into it).
.Pp
.Nm
.Fl L
relies on the filesystem having unique inode numbers.
If this is not true (eg msdos) then
.Nm
.Fl L
may fail to detect that
.Ev PWD
is incorrect.

View File

@ -1,4 +1,4 @@
/* $NetBSD: pwd.c,v 1.18 2003/09/14 19:20:23 jschauma Exp $ */ /* $NetBSD: pwd.c,v 1.19 2003/10/30 13:52:23 dsl Exp $ */
/* /*
* Copyright (c) 1991, 1993, 1994 * Copyright (c) 1991, 1993, 1994
@ -39,7 +39,7 @@ __COPYRIGHT("@(#) Copyright (c) 1991, 1993, 1994\n\
#if 0 #if 0
static char sccsid[] = "@(#)pwd.c 8.3 (Berkeley) 4/1/94"; static char sccsid[] = "@(#)pwd.c 8.3 (Berkeley) 4/1/94";
#else #else
__RCSID("$NetBSD: pwd.c,v 1.18 2003/09/14 19:20:23 jschauma Exp $"); __RCSID("$NetBSD: pwd.c,v 1.19 2003/10/30 13:52:23 dsl Exp $");
#endif #endif
#endif /* not lint */ #endif /* not lint */
@ -53,13 +53,17 @@ __RCSID("$NetBSD: pwd.c,v 1.18 2003/09/14 19:20:23 jschauma Exp $");
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
#include <vis.h>
int stdout_ok; /* stdout connected to a terminal */ static char *getcwd_logical(void);
static char *getcwd_logical(char *, size_t);
static void usage(void); static void usage(void);
int main(int, char *[]);
/*
* Note that EEE Std 1003.1, 2003 requires that the default be -L.
* This is inconsistent with the historic behaviour of everything
* except the ksh builtin.
* To avoid breaking scripts the default has been kept as -P.
* (Some scripts run /bin/pwd in order to get 'pwd -P'.)
*/
int int
main(int argc, char *argv[]) main(int argc, char *argv[])
@ -69,7 +73,7 @@ main(int argc, char *argv[])
setprogname(argv[0]); setprogname(argv[0]);
lFlag = 0; lFlag = 0;
while ((ch = getopt(argc, argv, "LP")) != -1) while ((ch = getopt(argc, argv, "LP")) != -1) {
switch (ch) { switch (ch) {
case 'L': case 'L':
lFlag = 1; lFlag = 1;
@ -81,6 +85,7 @@ main(int argc, char *argv[])
default: default:
usage(); usage();
} }
}
argc -= optind; argc -= optind;
argv += optind; argv += optind;
@ -88,15 +93,15 @@ main(int argc, char *argv[])
usage(); usage();
if (lFlag) if (lFlag)
p = getcwd_logical(NULL, 0); p = getcwd_logical();
else else
p = NULL;
if (p == NULL)
p = getcwd(NULL, 0); p = getcwd(NULL, 0);
if (p == NULL) if (p == NULL)
err(EXIT_FAILURE, NULL); err(EXIT_FAILURE, NULL);
stdout_ok = isatty(STDOUT_FILENO);
(void)printf("%s\n", p); (void)printf("%s\n", p);
exit(EXIT_SUCCESS); exit(EXIT_SUCCESS);
@ -104,42 +109,26 @@ main(int argc, char *argv[])
} }
static char * static char *
getcwd_logical(char *pt, size_t size) getcwd_logical(void)
{ {
char *pwd; char *pwd;
size_t pwdlen; struct stat s_pwd, s_dot;
dev_t dev;
ino_t ino;
struct stat s;
/* Check $PWD -- if it's right, it's fast. */ /* Check $PWD -- if it's right, it's fast. */
if ((pwd = getenv("PWD")) != NULL && pwd[0] == '/') { pwd = getenv("PWD");
if (stat(pwd, &s) != -1) { if (pwd == NULL)
dev = s.st_dev; return NULL;
ino = s.st_ino; if (pwd[0] != '/')
if (stat(".", &s) != -1 && dev == s.st_dev && return NULL;
ino == s.st_ino) { if (strstr(pwd, "/./") != NULL)
pwdlen = strlen(pwd); return NULL;
if (pt) { if (strstr(pwd, "/../") != NULL)
if (!size) { return NULL;
errno = EINVAL; if (stat(pwd, &s_pwd) == -1 || stat(".", &s_dot) == -1)
return (NULL); return NULL;
} if (s_pwd.st_dev != s_dot.st_dev || s_pwd.st_ino != s_dot.st_ino)
if (pwdlen + 1 > size) { return NULL;
errno = ERANGE; return pwd;
return (NULL);
}
} else if ((pt = malloc(pwdlen + 1)) == NULL)
return (NULL);
(void)memmove(pt, pwd, pwdlen);
pt[pwdlen] = '\0';
return (pt);
}
}
} else
errno = ENOENT;
return (NULL);
} }
static void static void