/*
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
/* All Rights Reserved */
/*
* Copyright (c) 1980 Regents of the University of California.
* All rights reserved. The Berkeley Software License Agreement
* specifies the terms and conditions for redistribution.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include "sh.h"
#include "sh.dir.h"
#include "sh.tconst.h"
/*
* C Shell - directory management
*/
/*
* dinit - initialize current working directory
*/
void
{
#ifdef TRACE
tprintf("TRACE- dinit()\n");
#endif
/*
* If this is a login shell, we should have a home directory. But,
* if we got here via 'su - <user>' where the user has no directory
* in his passwd file, then su has passed HOME=<nothing>, so hp is
* non-null, but has zero length. Thus, we do not know the current
* working directory based on the home directory.
*/
else {
printf("Warning: cannot determine current directory\n");
}
}
printd = 0;
}
/*
* dodirs - list all directories in directory loop
*/
void
{
bool lflag;
#ifdef TRACE
tprintf("TRACE- dodirs()\n");
#endif
if (*hp == '\0')
if (*++v != NOSTR)
lflag = 1;
else
error("Usage: dirs [ -l ]");
else
lflag = 0;
do {
continue;
} else
printf(" ");
printf("\n");
}
void
{
#ifdef TRACE
tprintf("TRACE- dtildepr()\n");
#endif
else
}
/*
* dochngd - implement chdir command.
*/
void
{
#ifdef TRACE
tprintf("TRACE- dochngd()\n");
#endif
printd = 0;
if (*++v == NOSTR) {
bferr("No home directory");
bferr("Can't change to home directory");
printd = 1;
goto flushcwd;
} else
}
/*
* dfollow - change to arg directory; fall back on cdpath if not valid
*/
tchar *
{
struct varent *c;
int index;
#ifdef TRACE
tprintf("TRACE- dfollow()\n");
#endif
goto gotcha;
/*
* If the directory argument has a slash in it,
* find that in the cache table.
*/
/*
* Try interpreting wrt successive components of cdpath.
* cdpath caching is turned off or directory argument
* has a slash in it.
*/
if (cp[0] != '/'
tchar *p;
;
;
printd = 1;
goto gotcha;
}
}
}
/* cdpath caching turned on */
if (cp[0] != '/'
/* If no cdpath or no paths in cdpath, leave */
if (c == 0 || c->vec[0] == 0)
else
/* index points to next path component to test */
index = 0;
/*
* Look at each path in cdpath until get a match.
* Only look at those path beginning with a slash
*/
do {
/* only check cache for absolute pathnames */
if (pv[0][0] == '/') {
/*
* concatenate found path with
* arg directory
*/
printd = 1;
goto gotcha;
}
}
}
/*
* relative pathnames are not cached, and must be
* checked manually
*/
else {
tchar *p;
;
;
printd = 1;
goto gotcha;
}
}
pv++;
index++;
} while (*pv);
}
/*
* Try dereferencing the variable named by the argument.
*/
printd = 1;
goto gotcha;
}
if (*cp != '/') {
tchar *p, *q;
int cwdlen;
int len;
/*
* All in the name of efficiency?
*/
cwdlen = 0;
else
{
/*
* if we are here, when the shell started
* it was unable to getwd(), lets try it again
*/
if (p == NULL)
error("cannot determine current directory");
else
{
}
}
}
/*
*
* for (p = cp; *p++;)
* ;
* dp = (tchar *)xalloc((unsigned) (cwdlen + (p - cp) + 1)*sizeof (tchar))
*/
;
if (cwdlen)
p[-1] = '/';
else
p--; /* don't add a / after root */
for (q = cp; *p++ = *q++; )
;
} else
}
/*
* dopushd - push new directory onto directory stack.
* with no arguments exchange top and second.
* with numeric argument (+n) bring it to top.
*/
void
{
#ifdef TRACE
tprintf("TRACE- dopushd()\n");
#endif
printd = 1;
if (*++v == NOSTR) {
bferr("No other directory");
} else {
}
}
/*
* dfind - find a directory if specified by numeric (+n) argument
*/
struct directory *
{
int i;
#ifdef TRACE
tprintf("TRACE- dfind()\n");
#endif
if (*cp++ != '+')
return (0);
continue;
if (*ep)
return (0);
if (i <= 0)
return (0);
bferr("Directory stack not that deep");
}
return (dp);
}
/*
* dopopd - pop a directory out of the directory stack
* with a numeric argument just discard it.
*/
void
{
#ifdef TRACE
tprintf("TRACE- dopopd()\n");
#endif
printd = 1;
if (*++v == NOSTR)
bferr("Invalid argument");
bferr("Directory stack empty");
}
dnewcwd(p);
else
}
/*
* dfree - free the directory (or keep it if it still has ref count)
*/
void
{
#ifdef TRACE
tprintf("TRACE- dfree()\n");
#endif
else
}
/*
* dcanon - canonicalize the pathname, removing excess ./ and ../ etc.
* We are of course assuming that the file system is standardly
* constructed (always have ..'s, directories have links).
*
* If the hardpaths shell variable is set, resolve the
* resulting pathname to contain no symbolic link components.
*/
tchar *
{
consideration */
*p2;
#ifdef TRACE
tprintf("TRACE- dcannon()\n");
#endif
if (*cp != '/')
abort();
/*
* Be paranoid: don't trust the initial prefix
* to be symlink-free.
*/
p = cp;
}
/*
* Loop invariant: cp points to the overall path start,
* p to its as yet uncanonicalized trailing suffix.
*/
while (*p) { /* for each component */
sp = p; /* save slash address */
while (*++p == '/') /* flush extra slashes */
;
if (p != ++sp)
;
p = sp; /* save start of component */
slash = 0;
if (*p)
while (*++p) /* find next slash or end of path */
if (*p == '/') {
slash = 1;
*p = '\0';
break;
}
if (*sp == '\0') {
/* component is null */
break;
else
*sp = '\0';
continue;
}
/* Squeeze out component consisting of "." */
if (slash) {
;
p = --sp;
*sp = '\0';
continue;
}
/*
* where "x" is null or rooted at "/", "y" is a single
* component, and "z" is possibly null. The pointer cp
* points to the start of "x", sp to the start of "y",
* and p to the beginning of "z", which has been forced
* to a null.
*/
/*
* Process symbolic link component. Provided that either
* the hardpaths shell variable is set or "y" is really
* ".." we replace the symlink with its contents. The
* second condition for replacement is necessary to make
* the command "cd x/.." produce the same results as the
* sequence "cd x; cd ..".
*
* Note that the two conditions correspond to different
* potential symlinks. When hardpaths is set, we must
* check "x/y"; otherwise, when "y" is known to be "..",
* we check "x".
*/
int cc;
/*
* Isolate the end of the component that is to
* be checked for symlink-hood.
*/
sp--;
if (! hardpaths)
*sp = '\0';
/*
* See whether the component is really a symlink by
* trying to read it. If the read succeeds, it is.
*/
/*
* readlink_ put null, so we don't need this.
*/
/* link[cc] = '\0'; */
/* Restore path. */
if (slash)
*p = '/';
/*
* Point p at the start of the trailing
* path following the symlink component.
* It's already there is hardpaths is set.
*/
if (! hardpaths) {
/* Restore path as well. */
*(p = sp) = '/';
}
/*
* Find length of p.
*/
;
if (*link != '/') {
/*
* Relative path: replace the symlink
* component with its value. First,
* set sp to point to the slash at
* its beginning. If hardpaths is
* set, this is already the case.
*/
if (! hardpaths) {
while (*--sp != '/')
;
}
/*
* Terminate the leading part of the
* path, including trailing slash.
*/
sp++;
*sp = '\0';
/*
* New length is: "x/" + link + "z"
*/
/*
* Copy new path into newcp
*/
;
;
;
/*
* Restart canonicalization at
* expanded "/y".
*/
} else {
/*
* New length is: link + "z"
*/
/*
* Copy new path into newcp
*/
;
;
/*
* Restart canonicalization at beginning
*/
p = newcp;
}
continue; /* canonicalize the link */
}
/* The component wasn't a symlink after all. */
if (! hardpaths)
*sp = '/';
}
if (dotdot) {
while (*--sp != '/')
;
if (slash) {
;
p = sp;
*++sp = '\0';
else
*sp = '\0';
continue;
}
if (slash)
*p = '/';
}
return cp;
}
/*
* dnewcwd - make a new directory in the loop the current one
* and export its name to the PWD environment variable.
*/
void
{
#ifdef TRACE
tprintf("TRACE- dnewcwd()\n");
#endif
#ifdef notdef
/*
* If we have a fast version of getwd available
* and hardpaths is set, it would be reasonable
* here to verify that dcwd->di_name really does
* name the current directory. Later...
*/
#endif /* notdef */
didchdir = 1;
didchdir = 0;
if (printd)
}