From nobody Tue Feb 10 14:29:28 2026 X-Original-To: dev-commits-src-main@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4f9P8T2cC1z6RPgw for ; Tue, 10 Feb 2026 14:29:29 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R13" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4f9P8S4vT0z3t0F for ; Tue, 10 Feb 2026 14:29:28 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1770733768; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=BgPmITt4rH4penjKm6SoNSD85qmtI4llGzUUzoCYxsM=; b=oMuqnMbskWFbs1/mCGmsPDl5TQ3KyzP0aPVhHRShIH/YB+2iaCrmGLyLCdhfJHo8nsdF03 jwtIVaNi8Y3KwfxVVhYHGnndMWx4hD8TMdMFcrdnPzQo1ihxKBdEtt6CVIxYEbzGyeH10s bZFlxP0UEWrbJtvBpT1hA9s2bNWRn67SsDm7PvZoz0TaRhLFi9Fuk8O3Co/G3Yt77yjLFG F44QJ4o527g90ASRzFbk9dmC3BpRCg2X3U+vm+s3FJsdXCXQKs4aywRsShoVZjkcyunb3S CK3JYwt35iw144gtDXORoun3ns2s5e36fvXUU6WOaeRvd35Ow6UxkE05A3NB2A== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1770733768; a=rsa-sha256; cv=none; b=d4r5MqT2AZsD8SoKs0gDWKrvJolls8cd82NO+vt7wsSzzWtOZ+L4nsspbFFpcU3bgTvPRp cZTSVwyLUtot144wFweM3k5xjgSA9zf97Hwzq0qHjuv2Im9/Q+FdJUxEOHbRdWG8JFvU2m wUEeTDXbq79UDC71wLkWKQaiXAox9P0WnPKpB+3xhmiE1UI9ZKQKO7fGfs0OCnFz0lNqBx TQpHz7S+eDSjcOSOIrSW+tBcBG05nFHY1UroB/hK9v+LFPWfMZzABRDcc9r4z5zsu4J32V 7st5x3gAOVNjg54uwqhZRZB0Dl8qZQ7P/p+pZflS/LlgP/uVyEHhH+mMMDBXLA== ARC-Authentication-Results: i=1; mx1.freebsd.org; none ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1770733768; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=BgPmITt4rH4penjKm6SoNSD85qmtI4llGzUUzoCYxsM=; b=ZPi3rcmLJKLenLvJ5OS0e2je71z46CT5ZIQhEMZdKD+C/ZJbNr4NCItucv87e2eoZbSfEL eMY1f5DU1UA5JVqUWejDL1v01DxT6uMaXDmPwuwqXUxbhysrCRIZyyp5VlVjccNbeyqZ6o KsX68PWzSrpkLw2EQP0vXRiUy9aDS2AumQm/gNlWVB1xOpxxLlrgZd1+jT0rGXxrHpmGRY LmNFZJJLbG1c4Z5AMVRKx0K0Xky6A7TnQJ7eG/w8aZLyrXkGe3Tl10+YMuvoHyjMZ7oT7/ TI7FlW1tB0lFVMqI7oKASMym69QzDz2oB5Od6ox/4JC+ieWAEppCSWm7R5ybBQ== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) by mxrelay.nyi.freebsd.org (Postfix) with ESMTP id 4f9P8S46Q0z1LnJ for ; Tue, 10 Feb 2026 14:29:28 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from git (uid 1279) (envelope-from git@FreeBSD.org) id 400ae by gitrepo.freebsd.org (DragonFly Mail Agent v0.13+ on gitrepo.freebsd.org); Tue, 10 Feb 2026 14:29:28 +0000 To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: Dag-Erling=?utf-8?Q? Sm=C3=B8rg?=rav Subject: git: 2df923c5d2d0 - main - pwd: Clean up and adopt POSIX semantics List-Id: Commit messages for the main branch of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-main List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-main@freebsd.org Sender: owner-dev-commits-src-main@FreeBSD.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: des X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: 2df923c5d2d02350abc29f61b603c5b9615b225c Auto-Submitted: auto-generated Date: Tue, 10 Feb 2026 14:29:28 +0000 Message-Id: <698b40c8.400ae.2f2225b4@gitrepo.freebsd.org> The branch main has been updated by des: URL: https://cgit.FreeBSD.org/src/commit/?id=2df923c5d2d02350abc29f61b603c5b9615b225c commit 2df923c5d2d02350abc29f61b603c5b9615b225c Author: Dag-Erling Smørgrav AuthorDate: 2026-02-10 14:29:04 +0000 Commit: Dag-Erling Smørgrav CommitDate: 2026-02-10 14:29:04 +0000 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 --- bin/pwd/pwd.1 | 4 +-- bin/pwd/pwd.c | 99 +++++++++++++++++++++++++++++++---------------------------- 2 files changed, 54 insertions(+), 49 deletions(-) diff --git a/bin/pwd/pwd.1 b/bin/pwd/pwd.1 index ce81e443d98e..8b03d060bc8e 100644 --- a/bin/pwd/pwd.1 +++ b/bin/pwd/pwd.1 @@ -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 diff --git a/bin/pwd/pwd.c b/bin/pwd/pwd.c index a49c638b1dee..f626a2236c02 100644 --- a/bin/pwd/pwd.c +++ b/bin/pwd/pwd.c @@ -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 #include -#include #include -#include +#include #include #include #include -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); -}