Zsh Mailing List Archive
Messages sorted by:
Reverse Date,
Date,
Thread,
Author
Re: [PATCH] Re: `pwd -P` with systemd-homed causes inconsistent cwd state
- X-seq: zsh-workers 52273
- From: Kyle Laker <kyle@laker.email>
- To: zsh-workers@xxxxxxx
- Subject: Re: [PATCH] Re: `pwd -P` with systemd-homed causes inconsistent cwd state
- Date: Sun, 5 Nov 2023 09:16:40 -0500
- Arc-authentication-results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=kylelaker.com; dmarc=pass action=none header.from=laker.email; dkim=pass header.d=laker.email; arc=none
- Arc-message-signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=nVELgOh0/IHVEo/5rHwyI5XyGO3xrTxwb//j3ltf2r0=; b=hFzxvwzfPflxITiZuaPjqlukweMAKEBUTcDGKRC8tQM0iK1AY1Lu44OSiZj9NTL4dO8sX9c+nbg1tbOfRjpsvnwZfw3eSnFq14rbTMjI3gh2kEUCz3RdSqkGc7rnRS7JUbBDVniKtfG4kTAeSMw/zOgHzPbH0Km9pJF78uDs6qb6Vlys+CPXKpzUYPZC6S2kTshsSQKbMQgxQoBb53FqeKGwNKgcz/UPoj0i4JEB6YoH8v8332de9YAo2kXw69L7HYa4Uq829nJvJD3qizzp2NPIblnUhnATm98+L1TTmCdeO15SLsgdpSoUhrNrykYs62yCK0wgeD4oFs/RD4kt0Q==
- Arc-seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=f6rjJmvxAlI3ICuZlNwaIfDdxRj0W6KG5znkfct0ewSVK75qieqgG2+sXOVpvreOznAJ1bn3Puar7FIOW0JgymFJMNrq+sc9JrITwrvnDuGqJXHXfXVwm95joVIkXupbJj4q8I0cCtdQrWjjMEw4AQPXMytO4oieqA74kW4oQHNcuD39BG16neUEbweAjLdtGht661FYRrFODWUYDbW9d4FCeNwGy6o45iNwXmQZCvNpxvBefBLJ5tSoEZnpGe36KcOxVa9fgrLOpVXUmIBEcqd4ti4EDw3EmvM5Bd+MAhxoSlMUZ/lIKU7yjXMHWSwo4Vl4b/Y2rT6jNIw6yLHqqw==
- Archived-at: <https://zsh.org/workers/52273>
- In-reply-to: <CAH+w=7YtPvL6odikmzyUg067DFd3cMhP-X1BwyTOkG7qO8x5vg@mail.gmail.com>
- List-id: <zsh-workers.zsh.org>
- References: <f31c3d78-11de-4aac-81d7-c061916a9108@laker.email> <CAH+w=7YepkrZ1EYkovCvH-Qib4LCqFMGaw+j3EG8Cn3bTaE+XQ@mail.gmail.com> <e3adbc41-1cba-46d7-99a7-552a14882c59@laker.email> <CAH+w=7YYuFa71r4c3XKZgrgsMEy9_ifQeMjYMBsOGQtM0qEhJQ@mail.gmail.com> <CAH+w=7bcBOGxYzVYSxaNu_8hEE2mtL7GS0vbAjWfQrYs2R1juA@mail.gmail.com> <6f0cc0e8-665f-4c90-ba6e-6180ebcf9d60@laker.email> <CAH+w=7YtPvL6odikmzyUg067DFd3cMhP-X1BwyTOkG7qO8x5vg@mail.gmail.com>
On 11/3/23 00:28, Bart Schaefer wrote:> Somehow getcwd() might bypass
whatever restriction caused this to
fail? In all other cases we've chdir'd away from the current
directory and can't get back. I'm tempted to say we should just
delete that entire fallback, but then we never use getcwd() at all.
If that fallback gets deleted, it seems like HAVE_GETCWD in its entirety
isn't particularly useful anymore; this is the only `#ifdef` for it. It
might simplify the logic a bit; if USE_GETCWD then do so, otherwise,
rely on fallbacks (especially since zgetdir() itself may be calling
getcwd()).
Maybe we should be checking errno (for what?) as well as ret before
falling back to getcwd()? Or maybe when USE_GETCWD, we should use it
preferentially, and zgetdir() should be the fallback?
I think zgetdir() does use getcwd() preferentially when USE_GETCWD. It's
awkwardly at the bottom of zgetdir(). When USE_GETCWD, all the internal
pathwalking logic of zgetdir() is skipped.
Or maybe zgetdir() itself should USE_GETCWD there at line 364?
That feels possibly the cleanest. That would allow removing all the
calls to getcwd() from within zgetcwd() itself.
I've attached a patch that builds on yours. Testing it in my use case,
it correctly works when HAVE_GETCWD && USE_GETCWD (eagerly invokes
getcwd()), HAVE_GETCWD && !USE_GETCWD (zgetdir() returns null and the
pwd fallback in zgetcwd() is used), and !HAVE_GETCWD && !USE_GETCWD
(same as when HAVE && !USE). The patch also removes
`GETCWD_CALLS_MALLOC` because it was only used in that fallback case.
Running `make check` for me still passes.diff --git a/Src/compat.c b/Src/compat.c
index 817bb4aaf..23ad703f4 100644
--- a/Src/compat.c
+++ b/Src/compat.c
@@ -359,9 +359,40 @@ zgetdir(struct dirsav *d)
buf = zhalloc(bufsiz = PATH_MAX+1);
pos = bufsiz - 1;
buf[pos] = '\0';
+#if defined(USE_GETCWD) || defined(__CYGWIN__)
+ if (!getcwd(buf, bufsiz)) {
+ if (d) {
+ return NULL;
+ }
+ } else {
+ if (d) {
+ return d->dirname = ztrdup(buf);
+ }
+ return buf;
+ }
+#else
strcpy(nbuf, "../");
if (stat(".", &sbuf) < 0) {
+ /*
+ * Fallback to getcwd() since it may be able to overcome
+ * the failure in stat(). We haven't changed directories
+ * to walk the path yet, so this should return the current
+ * directory.
+ */
+#ifdef HAVE_GETCWD
+ if (!getcwd(buf, bufsiz)) {
+ if (d) {
+ return NULL;
+ }
+ } else {
+ if (d) {
+ return d->dirname = ztrdup(buf);
+ }
+ return buf;
+ }
+#else
return NULL;
+#endif
}
/* Record the initial inode and device */
@@ -369,7 +400,6 @@ zgetdir(struct dirsav *d)
pdev = sbuf.st_dev;
if (d)
d->ino = pino, d->dev = pdev;
-#if !defined(__CYGWIN__) && !defined(USE_GETCWD)
#ifdef HAVE_FCHDIR
else
#endif
@@ -403,12 +433,25 @@ zgetdir(struct dirsav *d)
buf[--pos] = '/';
if (d) {
#ifndef HAVE_FCHDIR
- zchdir(buf + pos);
+ if (zchdir(buf + pos) < 0) {
+ /*
+ * The reason for all this chdir-ing is to get the
+ * absolute name of the current directory, so if we
+ * cannot chdir to that name we have to assume our
+ * directory is lost. See "something bad" below.
+ */
+ noholdintr();
+ return NULL;
+ }
noholdintr();
#endif
return d->dirname = ztrdup(buf + pos);
}
- zchdir(buf + pos);
+ if (zchdir(buf + pos) < 0) {
+ /* Current directory lost */
+ noholdintr();
+ return NULL;
+ }
noholdintr();
return buf + pos;
}
@@ -477,28 +520,23 @@ zgetdir(struct dirsav *d)
if (d) {
#ifndef HAVE_FCHDIR
if (buf[pos])
- zchdir(buf + pos + 1);
+ if (zchdir(buf + pos + 1) < 0) {
+ /* Current directory lost */
+ noholdintr();
+ return NULL;
+ }
noholdintr();
#endif
return NULL;
}
if (buf[pos])
- zchdir(buf + pos + 1);
- noholdintr();
-
-#else /* __CYGWIN__, USE_GETCWD cases */
-
- if (!getcwd(buf, bufsiz)) {
- if (d) {
+ if (zchdir(buf + pos + 1) < 0) {
+ /* Current directory lost */
+ noholdintr();
return NULL;
}
- } else {
- if (d) {
- return d->dirname = ztrdup(buf);
- }
- return buf;
- }
+ noholdintr();
#endif
/*
@@ -526,25 +564,12 @@ mod_export char *
zgetcwd(void)
{
char *ret = zgetdir(NULL);
-#ifdef HAVE_GETCWD
- if (!ret) {
-#ifdef GETCWD_CALLS_MALLOC
- char *cwd = getcwd(NULL, 0);
- if (cwd) {
- ret = dupstring(cwd);
- free(cwd);
- }
-#else
- char *cwdbuf = zalloc(PATH_MAX+1);
- ret = getcwd(cwdbuf, PATH_MAX);
- if (ret)
- ret = dupstring(ret);
- zfree(cwdbuf, PATH_MAX+1);
-#endif /* GETCWD_CALLS_MALLOC */
- }
-#endif /* HAVE_GETCWD */
if (!ret)
- ret = unmeta(pwd);
+ if (chdir(ret = unmeta(pwd)) < 0) {
+ zwarn("%e: current directory %s lost, using /",
+ errno, ret);
+ chdir(ret = dupstring("/"));
+ }
if (!ret || *ret == '\0')
ret = dupstring(".");
return ret;
diff --git a/configure.ac b/configure.ac
index c5263035e..5dd6c7892 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2068,31 +2068,6 @@ if test x$zsh_cv_use_getcwd = xyes; then
AC_DEFINE(USE_GETCWD)
fi
-dnl GNU getcwd() can allocate as much space as necessary for a
-dnl directory name, preventing guessing games.
-AH_TEMPLATE([GETCWD_CALLS_MALLOC],
-[Define to 1 if getcwd() calls malloc to allocate memory.])
-if test x$ac_cv_func_getcwd = xyes; then
- AC_CACHE_CHECK(whether getcwd calls malloc to allocate memory,
- zsh_cv_getcwd_malloc,
- [AC_RUN_IFELSE([AC_LANG_SOURCE([[
-#include <unistd.h>
-#include <string.h>
-int main() {
- char buf[1024], *ptr1, *ptr2;
- ptr1 = getcwd(buf, 1024);
- ptr2 = getcwd(NULL, 0);
- if (ptr1 && ptr2 && !strcmp(ptr1, ptr2)) {
- return 0;
- }
- return 1;
-}
-]])],[zsh_cv_getcwd_malloc=yes],[zsh_cv_getcwd_malloc=no],[zsh_cv_getcwd_malloc=no])])
- if test x$zsh_cv_getcwd_malloc = xyes; then
- AC_DEFINE(GETCWD_CALLS_MALLOC)
- fi
-fi
-
dnl CHECK FOR setproctitle() FOR jobs -Z / ARGV0
AH_TEMPLATE([HAVE_SETPROCTITLE],
[Define to 1 if the system supports `setproctitle' to change process name])
Messages sorted by:
Reverse Date,
Date,
Thread,
Author