mirror of
https://github.com/freebsd/freebsd-src.git
synced 2026-10-28 19:34:43 +01:00
pwd: Clean up and adopt POSIX semantics
According to POSIX, the default should be -L. Based on code history, whoever first wrote BSD pwd(1) could not figure out how to implement -L and therefore made -P the default (and only) option. Support for -L was later added, but the default was never changed. Clean up the code, make -L the default, and rewrite getcwd_logical() to reject paths that contain dot or dot-dot, as required by POSIX. MFC after: 1 week Reviewed by: olce Differential Revision: https://reviews.freebsd.org/D55146
This commit is contained in:
1 parent
47fb51847f
commit
2df923c5d2
2 files changed
+54
-49
No files matched your search
+2
-2
@@ -29,7 +29,7 @@
|
||||
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
.\" SUCH DAMAGE.
|
||||
.\"
|
||||
.Dd May 22, 2023
|
||||
.Dd Februrary 6, 2026
|
||||
.Dt PWD 1
|
||||
.Os
|
||||
.Sh NAME
|
||||
@@ -60,7 +60,7 @@ Display the physical current working directory (all symbolic links resolved).
|
||||
.El
|
||||
.Pp
|
||||
If no options are specified, the
|
||||
.Fl P
|
||||
.Fl L
|
||||
option is assumed.
|
||||
.Sh ENVIRONMENT
|
||||
Environment variables used by
|
||||
|
||||
+52
-47
@@ -3,6 +3,7 @@
|
||||
*
|
||||
* Copyright (c) 1991, 1993, 1994
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
* Copyright (c) 2026 Dag-Erling Smørgrav
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
@@ -31,40 +32,74 @@
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
static char *getcwd_logical(void);
|
||||
void usage(void);
|
||||
static char *
|
||||
getcwd_logical(void)
|
||||
{
|
||||
struct stat log, phy;
|
||||
char *pwd, *p, *q;
|
||||
|
||||
/* $PWD is set and absolute */
|
||||
if ((pwd = getenv("PWD")) == NULL || *pwd != '/')
|
||||
return (NULL);
|
||||
/* $PWD does not contain /./ or /../ */
|
||||
for (p = pwd; *p; p = q) {
|
||||
for (q = ++p; *q && *q != '/'; q++)
|
||||
/* nothing */;
|
||||
if ((*p == '.' && q == ++p) ||
|
||||
(*p == '.' && q == ++p))
|
||||
return (NULL);
|
||||
}
|
||||
/* $PWD refers to the current directory */
|
||||
if (stat(pwd, &log) != 0 || stat(".", &phy) != 0 ||
|
||||
log.st_dev != phy.st_dev || log.st_ino != phy.st_ino)
|
||||
return (NULL);
|
||||
return (pwd);
|
||||
}
|
||||
|
||||
static char *
|
||||
getcwd_physical(void)
|
||||
{
|
||||
static char pwd[MAXPATHLEN];
|
||||
|
||||
return (getcwd(pwd, sizeof(pwd)));
|
||||
}
|
||||
|
||||
static void
|
||||
usage(void)
|
||||
{
|
||||
(void)fprintf(stderr, "usage: pwd [-L | -P]\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
int physical;
|
||||
int ch;
|
||||
char *p;
|
||||
char *pwd;
|
||||
int opt;
|
||||
bool logical;
|
||||
|
||||
physical = 1;
|
||||
while ((ch = getopt(argc, argv, "LP")) != -1)
|
||||
switch (ch) {
|
||||
logical = true;
|
||||
while ((opt = getopt(argc, argv, "LP")) != -1) {
|
||||
switch (opt) {
|
||||
case 'L':
|
||||
physical = 0;
|
||||
logical = true;
|
||||
break;
|
||||
case 'P':
|
||||
physical = 1;
|
||||
logical = false;
|
||||
break;
|
||||
case '?':
|
||||
default:
|
||||
usage();
|
||||
}
|
||||
}
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
if (argc != 0)
|
||||
usage();
|
||||
|
||||
@@ -72,40 +107,10 @@ main(int argc, char *argv[])
|
||||
* If we're trying to find the logical current directory and that
|
||||
* fails, behave as if -P was specified.
|
||||
*/
|
||||
if ((!physical && (p = getcwd_logical()) != NULL) ||
|
||||
(p = getcwd(NULL, 0)) != NULL)
|
||||
printf("%s\n", p);
|
||||
if ((logical && (pwd = getcwd_logical()) != NULL) ||
|
||||
(pwd = getcwd_physical()) != NULL)
|
||||
printf("%s\n", pwd);
|
||||
else
|
||||
err(1, ".");
|
||||
|
||||
exit(0);
|
||||
}
|
||||
|
||||
void __dead2
|
||||
usage(void)
|
||||
{
|
||||
|
||||
(void)fprintf(stderr, "usage: pwd [-L | -P]\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static char *
|
||||
getcwd_logical(void)
|
||||
{
|
||||
struct stat lg, 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, &lg) == -1 || stat(".", &phy) == -1)
|
||||
return (NULL);
|
||||
if (lg.st_dev == phy.st_dev && lg.st_ino == phy.st_ino)
|
||||
return (pwd);
|
||||
}
|
||||
|
||||
errno = ENOENT;
|
||||
return (NULL);
|
||||
}
|
||||
Reference in new issue
Block a user