* Copyright (c) 1991 The Regents of the University of California.
* This code is derived from software contributed to Berkeley by
* %sccs.include.redist.c%
static char sccsid
[] = "@(#)cd.c 5.2 (Berkeley) %G%";
* The cd and pwd commands.
#include "nodes.h" /* for jobs.h */
STATIC
int docd(char *, int);
STATIC
void updatepwd(char *);
STATIC
void getpwd(void);
STATIC
char *getcomponent(void);
STATIC
char *getcomponent();
char *curdir
; /* current working directory */
extern int didudir
; /* set if /u/logname expanded */
cdcmd(argc
, argv
) char **argv
; {
if ((dest
= *argptr
) == NULL
&& (dest
= bltinlookup("HOME", 1)) == NULL
)
if (*dest
== '/' || (path
= bltinlookup("CDPATH", 1)) == NULL
)
while ((p
= padvance(&path
, dest
)) != NULL
) {
&& (statb
.st_mode
& S_IFMT
) == S_IFDIR
&& docd(p
, strcmp(p
, dest
)) >= 0)
error("can't cd to %s", dest
);
* Actually do the chdir. If the name refers to symbolic links, we
* compute the actual directory name before doing the cd. In an
* interactive shell, print the directory name if "print" is nonzero
* or if the name refers to a symbolic link. We also print the name
* if "/u/logname" was expanded in it, since this is similar to a
* symbolic link. (The check for this breaks if the user gives the
* cd command some additional, unused arguments.)
out1fmt("%s\n", stackblock());
TRACE(("docd(\"%s\", %d) called\n", dest
, print
));
while ((q
= getcomponent()) != NULL
) {
if (q
[0] == '\0' || q
[0] == '.' && q
[1] == '\0')
if (equal(component
, ".."))
if (lstat(stackblock(), &statb
) < 0)
error("lstat %s failed", stackblock());
if ((statb
.st_mode
& S_IFMT
) != S_IFLNK
)
/* Hit a symbolic link. We have to start all over again. */
symlink
= grabstackstr(p
);
i
= (int)statb
.st_size
+ 2; /* 2 for '/' and '\0' */
if (readlink(symlink
, p
, (int)statb
.st_size
) < 0) {
error("readlink %s failed", stackblock());
if (cdcomppath
!= NULL
) {
p
[(int)statb
.st_size
] = '/';
scopy(cdcomppath
, p
+ (int)statb
.st_size
+ 1);
p
[(int)statb
.st_size
] = '\0';
if (p
[0] != '/') { /* relative path name */
dest
= stalloc(strlen(symlink
) + strlen(p
) + 1);
* Get the next component of the path name pointed to by cdcomppath.
* This routine overwrites the string pointed to by cdcomppath.
if ((p
= cdcomppath
) == NULL
)
while (*p
!= '/' && *p
!= '\0')
* Update curdir (the name of the current directory) in response to a
* cd command. We also call hashcd to let the routines in exec.c know
* that the current directory has changed.
hashcd(); /* update command hash table */
cdcomppath
= stalloc(strlen(dir
) + 1);
while ((p
= getcomponent()) != NULL
) {
while (new > stackblock() && (STUNPUTC(new), *new) != '/');
} else if (*p
!= '\0' && ! equal(p
, ".")) {
curdir
= savestr(stackblock());
pwdcmd(argc
, argv
) char **argv
; {
* Run /bin/pwd to find out what the current directory is. We suppress
* interrupts throughout most of this, but the user can still break out
* of it by killing the pwd program. If we already know the current
* directory, this routine returns immediately.
error("Pipe call failed");
jp
= makejob((union node
*)NULL
, 1);
if (forkshell(jp
, (union node
*)NULL
, FORK_NOJOB
) == 0) {
execl("/bin/pwd", "pwd", (char *)0);
error("Cannot exec /bin/pwd");
while ((i
= read(pip
[0], p
, buf
+ MAXPWD
- p
)) > 0
|| i
== -1 && errno
== EINTR
) {
if (i
< 0 || p
== buf
|| p
[-1] != '\n')
error("pwd command failed");