1*05e80ac3Skre /* $NetBSD: cd.c,v 1.53 2022/01/31 16:54:28 kre Exp $ */
249f0ad86Scgd
361f28255Scgd /*-
437ed7877Sjtc * Copyright (c) 1991, 1993
537ed7877Sjtc * The Regents of the University of California. All rights reserved.
661f28255Scgd *
761f28255Scgd * This code is derived from software contributed to Berkeley by
861f28255Scgd * Kenneth Almquist.
961f28255Scgd *
1061f28255Scgd * Redistribution and use in source and binary forms, with or without
1161f28255Scgd * modification, are permitted provided that the following conditions
1261f28255Scgd * are met:
1361f28255Scgd * 1. Redistributions of source code must retain the above copyright
1461f28255Scgd * notice, this list of conditions and the following disclaimer.
1561f28255Scgd * 2. Redistributions in binary form must reproduce the above copyright
1661f28255Scgd * notice, this list of conditions and the following disclaimer in the
1761f28255Scgd * documentation and/or other materials provided with the distribution.
18b5b29542Sagc * 3. Neither the name of the University nor the names of its contributors
1961f28255Scgd * may be used to endorse or promote products derived from this software
2061f28255Scgd * without specific prior written permission.
2161f28255Scgd *
2261f28255Scgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2361f28255Scgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2461f28255Scgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2561f28255Scgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2661f28255Scgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2761f28255Scgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2861f28255Scgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2961f28255Scgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3061f28255Scgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3161f28255Scgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3261f28255Scgd * SUCH DAMAGE.
3361f28255Scgd */
3461f28255Scgd
35cbf48b75Schristos #include <sys/cdefs.h>
3661f28255Scgd #ifndef lint
3749f0ad86Scgd #if 0
3807bae7edSchristos static char sccsid[] = "@(#)cd.c 8.2 (Berkeley) 5/4/95";
3949f0ad86Scgd #else
40*05e80ac3Skre __RCSID("$NetBSD: cd.c,v 1.53 2022/01/31 16:54:28 kre Exp $");
4149f0ad86Scgd #endif
4261f28255Scgd #endif /* not lint */
4361f28255Scgd
445dad1439Scgd #include <sys/types.h>
455dad1439Scgd #include <sys/stat.h>
4682386044Skre #include <stdbool.h>
4707bae7edSchristos #include <stdlib.h>
4847f18130Sthorpej #include <string.h>
495dad1439Scgd #include <unistd.h>
505dad1439Scgd #include <errno.h>
515dad1439Scgd
5261f28255Scgd /*
5361f28255Scgd * The cd and pwd commands.
5461f28255Scgd */
5561f28255Scgd
5661f28255Scgd #include "shell.h"
5761f28255Scgd #include "var.h"
5861f28255Scgd #include "nodes.h" /* for jobs.h */
5961f28255Scgd #include "jobs.h"
6061f28255Scgd #include "options.h"
614fc4fe2eSchristos #include "builtins.h"
6261f28255Scgd #include "output.h"
6361f28255Scgd #include "memalloc.h"
6461f28255Scgd #include "error.h"
6570ad20e9Schristos #include "exec.h"
6607bae7edSchristos #include "redir.h"
6761f28255Scgd #include "mystring.h"
6807bae7edSchristos #include "show.h"
69ff008dabSchristos #include "cd.h"
7061f28255Scgd
7182386044Skre STATIC int docd(const char *, bool, bool);
72c02b3bbdSchristos STATIC char *getcomponent(void);
7382386044Skre STATIC bool updatepwd(const char *);
74296844feSdsl STATIC void find_curdir(int noerror);
7582386044Skre STATIC bool is_curdir(const char *);
7661f28255Scgd
77ff008dabSchristos char *curdir = NULL; /* current working directory */
7837ed7877Sjtc char *prevdir; /* previous working directory */
7961f28255Scgd STATIC char *cdcomppath;
8061f28255Scgd
8161f28255Scgd int
cdcmd(int argc,char ** argv)82c02b3bbdSchristos cdcmd(int argc, char **argv)
834ce0d34aScgd {
843d424690Schristos const char *dest;
851676135eSkre const char *path, *cp;
861676135eSkre char *p;
878c772bc7Sdsl char *d;
8861f28255Scgd struct stat statb;
8982386044Skre char opt;
9082386044Skre bool eopt = false;
911676135eSkre int print = cdprint; /* set -o cdprint to enable */
9261f28255Scgd
9382386044Skre while ((opt = nextopt("Pe")) != '\0')
9482386044Skre if (opt == 'e')
9582386044Skre eopt = true;
96c02b3bbdSchristos
97296844feSdsl /*
98296844feSdsl * Try (quite hard) to have 'curdir' defined, nothing has set
99296844feSdsl * it on entry to the shell, but we want 'cd fred; cd -' to work.
100296844feSdsl */
101c02b3bbdSchristos getpwd(1);
102c02b3bbdSchristos dest = *argptr;
103c02b3bbdSchristos if (dest == NULL) {
104c02b3bbdSchristos dest = bltinlookup("HOME", 1);
105c02b3bbdSchristos if (dest == NULL)
10661f28255Scgd error("HOME not set");
1071676135eSkre } else if (argptr[1]) {
108c02b3bbdSchristos /* Do 'ksh' style substitution */
109c02b3bbdSchristos if (!curdir)
110c02b3bbdSchristos error("PWD not set");
111c02b3bbdSchristos p = strstr(curdir, dest);
112c02b3bbdSchristos if (!p)
113c02b3bbdSchristos error("bad substitution");
114c02b3bbdSchristos d = stalloc(strlen(curdir) + strlen(argptr[1]) + 1);
115c02b3bbdSchristos memcpy(d, curdir, p - curdir);
116c02b3bbdSchristos strcpy(d + (p - curdir), argptr[1]);
117c02b3bbdSchristos strcat(d, p + strlen(dest));
118c02b3bbdSchristos dest = d;
119c02b3bbdSchristos print = 1;
1201676135eSkre } else if (dest[0] == '-' && dest[1] == '\0') {
12137ed7877Sjtc dest = prevdir ? prevdir : curdir;
12237ed7877Sjtc print = 1;
12337ed7877Sjtc }
124296844feSdsl if (*dest == '\0')
125296844feSdsl dest = ".";
1261676135eSkre
1271676135eSkre cp = dest;
1281676135eSkre if (*cp == '.' && *++cp == '.')
1291676135eSkre cp++;
1301676135eSkre if (*cp == 0 || *cp == '/' || (path = bltinlookup("CDPATH", 1)) == NULL)
13161f28255Scgd path = nullstr;
1321676135eSkre while ((p = padvance(&path, dest, 0)) != NULL) {
1331676135eSkre stunalloc(p);
134f5ad44b6Smycroft if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
1351676135eSkre int dopr = print;
13682386044Skre int x;
1371676135eSkre
13882386044Skre if (!print)
1391676135eSkre dopr = strcmp(p, dest);
14037ed7877Sjtc
14182386044Skre if ((x = docd(p, dopr != 0, eopt)) >= 0)
14282386044Skre return x;
14337ed7877Sjtc }
14461f28255Scgd }
14561f28255Scgd error("can't cd to %s", dest);
14607bae7edSchristos /* NOTREACHED */
14761f28255Scgd }
14861f28255Scgd
14961f28255Scgd
15061f28255Scgd /*
15116f5230cSjtc * Actually do the chdir. In an interactive shell, print the
15216f5230cSjtc * directory name if "print" is nonzero.
15361f28255Scgd */
15461f28255Scgd
15561f28255Scgd STATIC int
docd(const char * dest,bool print,bool eopt)15682386044Skre docd(const char *dest, bool print, bool eopt)
15761f28255Scgd {
15882386044Skre bool gotpwd;
15982386044Skre
1601676135eSkre #if 0 /* no "cd -L" (ever) so all this is just a waste of time ... */
16148250187Stls char *p;
16248250187Stls char *q;
1635678a13fScjs char *component;
1645678a13fScjs struct stat statb;
1655678a13fScjs int first;
1665678a13fScjs int badstat;
16716f5230cSjtc
1685678a13fScjs /*
1695678a13fScjs * Check each component of the path. If we find a symlink or
1705678a13fScjs * something we can't stat, clear curdir to force a getcwd()
1715678a13fScjs * next time we get the value of the current directory.
1725678a13fScjs */
1735678a13fScjs badstat = 0;
1745678a13fScjs cdcomppath = stalloc(strlen(dest) + 1);
1755678a13fScjs scopy(dest, cdcomppath);
1765678a13fScjs STARTSTACKSTR(p);
1775678a13fScjs if (*dest == '/') {
1785678a13fScjs STPUTC('/', p);
1795678a13fScjs cdcomppath++;
1805678a13fScjs }
1815678a13fScjs first = 1;
1825678a13fScjs while ((q = getcomponent()) != NULL) {
1835678a13fScjs if (q[0] == '\0' || (q[0] == '.' && q[1] == '\0'))
1845678a13fScjs continue;
1855678a13fScjs if (! first)
1865678a13fScjs STPUTC('/', p);
1875678a13fScjs first = 0;
1885678a13fScjs component = q;
1895678a13fScjs while (*q)
1905678a13fScjs STPUTC(*q++, p);
1915678a13fScjs if (equal(component, ".."))
1925678a13fScjs continue;
1935678a13fScjs STACKSTRNUL(p);
19456b5e396Schristos if (lstat(stackblock(), &statb) < 0) {
1955678a13fScjs badstat = 1;
1965678a13fScjs break;
1975678a13fScjs }
1985678a13fScjs }
1991676135eSkre #endif
2005678a13fScjs
20182386044Skre CTRACE(DBG_CMDS, ("docd(\"%s\", %s, %s) called\n", dest,
20282386044Skre print ? "true" : "false", eopt ? "true" : "false"));
20382386044Skre
20461f28255Scgd INTOFF;
20561f28255Scgd if (chdir(dest) < 0) {
20661f28255Scgd INTON;
20761f28255Scgd return -1;
20861f28255Scgd }
20982386044Skre gotpwd = updatepwd(NULL); /* only do cd -P, no "pretend" -L mode */
21061f28255Scgd INTON;
21182386044Skre if (print && (iflag || posix))
21282386044Skre out1fmt("%s\n", gotpwd ? curdir : dest);
21382386044Skre return gotpwd || !eopt ? 0 : 1;
21461f28255Scgd }
21561f28255Scgd
21661f28255Scgd
21761f28255Scgd /*
21861f28255Scgd * Get the next component of the path name pointed to by cdcomppath.
21961f28255Scgd * This routine overwrites the string pointed to by cdcomppath.
22061f28255Scgd */
22161f28255Scgd
22261f28255Scgd STATIC char *
getcomponent(void)2238c772bc7Sdsl getcomponent(void)
224c02b3bbdSchristos {
22548250187Stls char *p;
22661f28255Scgd char *start;
22761f28255Scgd
22861f28255Scgd if ((p = cdcomppath) == NULL)
22961f28255Scgd return NULL;
23061f28255Scgd start = cdcomppath;
23161f28255Scgd while (*p != '/' && *p != '\0')
23261f28255Scgd p++;
23361f28255Scgd if (*p == '\0') {
23461f28255Scgd cdcomppath = NULL;
23561f28255Scgd } else {
23661f28255Scgd *p++ = '\0';
23761f28255Scgd cdcomppath = p;
23861f28255Scgd }
23961f28255Scgd return start;
24061f28255Scgd }
24161f28255Scgd
24261f28255Scgd
24361f28255Scgd
24461f28255Scgd /*
24561f28255Scgd * Update curdir (the name of the current directory) in response to a
24661f28255Scgd * cd command. We also call hashcd to let the routines in exec.c know
24761f28255Scgd * that the current directory has changed.
24861f28255Scgd */
24961f28255Scgd
25082386044Skre STATIC bool
updatepwd(const char * dir)2518c772bc7Sdsl updatepwd(const char *dir)
25261f28255Scgd {
25361f28255Scgd char *new;
25461f28255Scgd char *p;
25561f28255Scgd
25661f28255Scgd hashcd(); /* update command hash table */
2575678a13fScjs
2585678a13fScjs /*
2595678a13fScjs * If our argument is NULL, we don't know the current directory
2605678a13fScjs * any more because we traversed a symbolic link or something
26182386044Skre * we couldn't stat(). Or we simply don't trust what we had.
2625678a13fScjs */
263ac875ddaSross if (dir == NULL || curdir == NULL) {
2645678a13fScjs if (prevdir)
2655678a13fScjs ckfree(prevdir);
2665678a13fScjs INTOFF;
2675678a13fScjs prevdir = curdir;
2685678a13fScjs curdir = NULL;
269c02b3bbdSchristos getpwd(1);
2705678a13fScjs INTON;
27182e9aeceSuebayasi if (curdir) {
27282e9aeceSuebayasi setvar("OLDPWD", prevdir, VEXPORT);
273c02b3bbdSchristos setvar("PWD", curdir, VEXPORT);
27482386044Skre return true;
27582e9aeceSuebayasi } else
276c02b3bbdSchristos unsetvar("PWD", 0);
27782386044Skre return false;
2785678a13fScjs }
27982386044Skre
28082386044Skre /* XXX none of the following code is ever executed any more */
28182386044Skre
28261f28255Scgd cdcomppath = stalloc(strlen(dir) + 1);
28361f28255Scgd scopy(dir, cdcomppath);
28461f28255Scgd STARTSTACKSTR(new);
28561f28255Scgd if (*dir != '/') {
28661f28255Scgd p = curdir;
28761f28255Scgd while (*p)
28861f28255Scgd STPUTC(*p++, new);
28961f28255Scgd if (p[-1] == '/')
29061f28255Scgd STUNPUTC(new);
29161f28255Scgd }
29261f28255Scgd while ((p = getcomponent()) != NULL) {
29361f28255Scgd if (equal(p, "..")) {
29461f28255Scgd while (new > stackblock() && (STUNPUTC(new), *new) != '/');
29561f28255Scgd } else if (*p != '\0' && ! equal(p, ".")) {
29661f28255Scgd STPUTC('/', new);
29761f28255Scgd while (*p)
29861f28255Scgd STPUTC(*p++, new);
29961f28255Scgd }
30061f28255Scgd }
30161f28255Scgd if (new == stackblock())
30261f28255Scgd STPUTC('/', new);
30361f28255Scgd STACKSTRNUL(new);
30437ed7877Sjtc INTOFF;
30537ed7877Sjtc if (prevdir)
30637ed7877Sjtc ckfree(prevdir);
30737ed7877Sjtc prevdir = curdir;
30861f28255Scgd curdir = savestr(stackblock());
30982e9aeceSuebayasi setvar("OLDPWD", prevdir, VEXPORT);
310ed00fe0aShe setvar("PWD", curdir, VEXPORT);
31137ed7877Sjtc INTON;
31282386044Skre return true;
31382386044Skre }
31482386044Skre
31582386044Skre /*
31682386044Skre * Test whether we are currently in the direcory given
31782386044Skre * (provided it is given, and is absolute)
31882386044Skre * ie: determine if path is fully qualified pathname of "."
31982386044Skre */
32082386044Skre STATIC bool
is_curdir(const char * path)32182386044Skre is_curdir(const char *path)
32282386044Skre {
32382386044Skre struct stat stdot, stpath;
32482386044Skre
32582386044Skre return path != NULL &&
32682386044Skre *path == '/' &&
32782386044Skre stat(".", &stdot) != -1 &&
32882386044Skre stat(path, &stpath) != -1 &&
32982386044Skre stdot.st_dev == stpath.st_dev &&
33082386044Skre stdot.st_ino == stpath.st_ino;
33161f28255Scgd }
33261f28255Scgd
333296844feSdsl /*
334296844feSdsl * Posix says the default should be 'pwd -L' (as below), however
335296844feSdsl * the 'cd' command (above) does something much nearer to the
336296844feSdsl * posix 'cd -P' (not the posix default of 'cd -L').
337296844feSdsl * If 'cd' is changed to support -P/L then the default here
338296844feSdsl * needs to be revisited if the historic behaviour is to be kept.
339296844feSdsl */
34061f28255Scgd
34161f28255Scgd int
pwdcmd(int argc,char ** argv)342c02b3bbdSchristos pwdcmd(int argc, char **argv)
3434ce0d34aScgd {
344df5bd11fSdsl int i;
345df5bd11fSdsl char opt = 'L';
346df5bd11fSdsl
347df5bd11fSdsl while ((i = nextopt("LP")) != '\0')
348df5bd11fSdsl opt = i;
349df5bd11fSdsl if (*argptr)
350df5bd11fSdsl error("unexpected argument");
351df5bd11fSdsl
352296844feSdsl if (opt == 'L')
353c02b3bbdSchristos getpwd(0);
354296844feSdsl else
355296844feSdsl find_curdir(0);
356df5bd11fSdsl
35782386044Skre #if 0 /* posix has been changed to forbid this */
35882e9aeceSuebayasi setvar("OLDPWD", prevdir, VEXPORT);
359296844feSdsl setvar("PWD", curdir, VEXPORT);
36082386044Skre #endif
36182386044Skre
36282386044Skre if (!is_curdir(curdir)) {
36382386044Skre find_curdir(1);
36482386044Skre if (curdir == NULL)
36582386044Skre error("Unable to find current directory");
36682386044Skre }
367b6dd340dSkre
368b6dd340dSkre flushout(out1); /* make sure buffer is empty */
369b6dd340dSkre clr_err(out1); /* and forget any earlier errors */
370296844feSdsl out1str(curdir);
37161f28255Scgd out1c('\n');
372b6dd340dSkre flushout(out1);
373b6dd340dSkre if (io_err(out1))
374b6dd340dSkre error("stdout: %s", strerror(errno));
375b6dd340dSkre
37661f28255Scgd return 0;
37761f28255Scgd }
37861f28255Scgd
37961f28255Scgd
38061f28255Scgd
3818d6ffce2Schristos void
initpwd(void)3828d6ffce2Schristos initpwd(void)
3838d6ffce2Schristos {
38415dc8572Ssimonb getpwd(1);
38515dc8572Ssimonb if (curdir)
3868d6ffce2Schristos setvar("PWD", curdir, VEXPORT);
38715dc8572Ssimonb else
38815dc8572Ssimonb sh_warnx("Cannot determine current working directory");
3898d6ffce2Schristos }
39061f28255Scgd
39161f28255Scgd #define MAXPWD 256
39261f28255Scgd
393ff008dabSchristos /*
394ff008dabSchristos * Find out what the current directory is. If we already know the current
395ff008dabSchristos * directory, this routine returns immediately.
396ff008dabSchristos */
397ff008dabSchristos void
getpwd(int noerror)398c02b3bbdSchristos getpwd(int noerror)
399ff008dabSchristos {
400c02b3bbdSchristos char *pwd;
401c02b3bbdSchristos static int first = 1;
402ff008dabSchristos
403ff008dabSchristos if (curdir)
404ff008dabSchristos return;
405c02b3bbdSchristos
406c02b3bbdSchristos if (first) {
407*05e80ac3Skre /*
408*05e80ac3Skre * Note that this happens via the call from initpwd()
409*05e80ac3Skre * just above, which is called early from main() during
410*05e80ac3Skre * sh startup, so fetching PWD from the entry environment
411*05e80ac3Skre * (which is what getenv() does) is acceptable. Here we
412*05e80ac3Skre * could use normal sh var lookup functions instead, as
413*05e80ac3Skre * the arriving environment has already been imported before
414*05e80ac3Skre * we get here, but it makes little difference.
415*05e80ac3Skre *
416*05e80ac3Skre * XXX What would be better perhaps would be to move all of
417*05e80ac3Skre * this into initpwd() instead of here, so we could get rid of
418*05e80ac3Skre * this "first" static - that function is only ever called once.
419*05e80ac3Skre * XXX Some other day.
420*05e80ac3Skre */
421df5bd11fSdsl first = 0;
422c02b3bbdSchristos pwd = getenv("PWD");
42382386044Skre if (is_curdir(pwd)) {
424c02b3bbdSchristos curdir = savestr(pwd);
425c02b3bbdSchristos return;
426c02b3bbdSchristos }
427c02b3bbdSchristos }
428df5bd11fSdsl
429296844feSdsl find_curdir(noerror);
430df5bd11fSdsl
431df5bd11fSdsl return;
432df5bd11fSdsl }
433df5bd11fSdsl
434296844feSdsl STATIC void
find_curdir(int noerror)435296844feSdsl find_curdir(int noerror)
436df5bd11fSdsl {
437df5bd11fSdsl int i;
438df5bd11fSdsl char *pwd;
439c02b3bbdSchristos
440ff008dabSchristos /*
441ff008dabSchristos * Things are a bit complicated here; we could have just used
442ff008dabSchristos * getcwd, but traditionally getcwd is implemented using popen
443ff008dabSchristos * to /bin/pwd. This creates a problem for us, since we cannot
444ff008dabSchristos * keep track of the job if it is being ran behind our backs.
44582386044Skre * XXX That's not actually the problem, a process created and
44682386044Skre * XXX destroyed that we know nothing about is harmless. The
44782386044Skre * XXX problem is that old popen() implementations would use
44882386044Skre * XXX wait(2) to await completion of the command, and that might
44982386044Skre * XXX collect (and ignore) our children. As long as we are
45082386044Skre * XXX confident that popen() uses waitpid() (or the equv) there
45182386044Skre * XXX would not be a problem. But how do we know that?
452ff008dabSchristos * So we re-implement getcwd(), and we suppress interrupts
453ff008dabSchristos * throughout the process. This is not completely safe, since
454ff008dabSchristos * the user can still break out of it by killing the pwd program.
455ff008dabSchristos * We still try to use getcwd for systems that we know have a
456ff008dabSchristos * c implementation of getcwd, that does not open a pipe to
457ff008dabSchristos * /bin/pwd.
458ff008dabSchristos */
4592c8f740eSchristos #if defined(__NetBSD__) || defined(__SVR4)
4606b7623a6Schristos
461c02b3bbdSchristos for (i = MAXPWD;; i *= 2) {
462c02b3bbdSchristos pwd = stalloc(i);
463296844feSdsl if (getcwd(pwd, i) != NULL) {
464296844feSdsl curdir = savestr(pwd);
4659038bdcaSkre stunalloc(pwd);
466296844feSdsl return;
467296844feSdsl }
468c02b3bbdSchristos stunalloc(pwd);
469c02b3bbdSchristos if (errno == ERANGE)
470c02b3bbdSchristos continue;
471c02b3bbdSchristos if (!noerror)
47247f18130Sthorpej error("getcwd() failed: %s", strerror(errno));
473296844feSdsl return;
4746b7623a6Schristos }
475ff008dabSchristos #else
476ff008dabSchristos {
47761f28255Scgd char *p;
47861f28255Scgd int status;
47961f28255Scgd struct job *jp;
48061f28255Scgd int pip[2];
48161f28255Scgd
482296844feSdsl pwd = stalloc(MAXPWD);
48361f28255Scgd INTOFF;
48461f28255Scgd if (pipe(pip) < 0)
48561f28255Scgd error("Pipe call failed");
4869f61b804Splunky jp = makejob(NULL, 1);
4879f61b804Splunky if (forkshell(jp, NULL, FORK_NOJOB) == 0) {
488ff008dabSchristos (void) close(pip[0]);
4891fad4bb6Schristos movefd(pip[1], 1);
490ff008dabSchristos (void) execl("/bin/pwd", "pwd", (char *)0);
49137ed7877Sjtc error("Cannot exec /bin/pwd");
49261f28255Scgd }
493ff008dabSchristos (void) close(pip[1]);
49461f28255Scgd pip[1] = -1;
495296844feSdsl p = pwd;
496296844feSdsl while ((i = read(pip[0], p, pwd + MAXPWD - p)) > 0
49707bae7edSchristos || (i == -1 && errno == EINTR)) {
49861f28255Scgd if (i > 0)
49961f28255Scgd p += i;
50061f28255Scgd }
501ff008dabSchristos (void) close(pip[0]);
50261f28255Scgd pip[0] = -1;
50361f28255Scgd status = waitforjob(jp);
50461f28255Scgd if (status != 0)
50561f28255Scgd error((char *)0);
506296844feSdsl if (i < 0 || p == pwd || p[-1] != '\n') {
507c02b3bbdSchristos if (noerror) {
508c02b3bbdSchristos INTON;
509296844feSdsl return;
510c02b3bbdSchristos }
51161f28255Scgd error("pwd command failed");
512c02b3bbdSchristos }
51361f28255Scgd p[-1] = '\0';
51461f28255Scgd INTON;
515296844feSdsl curdir = savestr(pwd);
5169038bdcaSkre stunalloc(pwd);
517296844feSdsl return;
518df5bd11fSdsl }
51916f5230cSjtc #endif
52061f28255Scgd }
521