[comp.unix.programmer] getting the current working directory

pefv700@perv.pe.utexas.edu (01/11/91)

Like the subject says, I want to get the current working directory.

According to my SunOS man page on getwd(3), getwd(buf) will put the absolute
path of the current working directory in buf UNLESS there is an error, in
which case buf contains some message.  The problem is, you don't know if you
got the directory name or the message.

I can't find any other std library function or system call that will get the
job done right (using malloc if necessary).  So...to write a "good" getwd,
it seems you would have to do something ugly like (skipping error checking)

getwd(buf)
char *buf;
{
    ino_t inode;
    struct stat stbuf;
    DIR *dfd;
    struct dirent *dp;

    stat(".", &stbuf);
    inode = stbuf.st_ino;
    if (. is /) {    /* not sure how to do this, stat .. and check inodes? */
        change buf to include / using [m,re]alloc as necessary
        return;
    } else
        chdir("..");
    dfd = opendir(".");
    while ((dp = readdir(dfd)) != NULL) {
        stat(dp->d_name, &stbuf);
        if (stbuf.st_ino == inode) {
            change buf to include dp->d_name using [m,re]alloc as necessary
            break;
        }
    getwd(buf);
}

Is there a better way, a function I'm missing...?

Thanks,

Chris

pfalstad@phoenix.Princeton.EDU (Paul John Falstad) (01/11/91)

In article <42380@ut-emx.uucp> pefv700@perv.pe.utexas.edu writes:
>According to my SunOS man page on getwd(3), getwd(buf) will put the absolute
>path of the current working directory in buf UNLESS there is an error, in
>which case buf contains some message.  The problem is, you don't know if you
>got the directory name or the message.

Yes, you do.  If there is an error, getwd returns NULL.  Otherwise it
returns the address of the buffer.

Here is a version of getwd I wrote for zsh.  I'd be interested in what
people think of it.  I needed a version that didn't fork(), and was
having problems with the Sun getwd().

char *getwd(void)
{
static char buf0[MAXPATHLEN];
char buf3[MAXPATHLEN],*buf2 = buf0+1;
struct stat sbuf;
struct direct *de;
DIR *dir;
ino_t ino = -1;
dev_t dev = -1;

	buf2[0] = '\0';
	buf0[0] = '/';
	for(;;) {
		if (stat(".",&sbuf) < 0) {
			chdir(buf0);
			return NULL;
			}
		ino = sbuf.st_ino;
		dev = sbuf.st_dev;
		if (stat("..",&sbuf) < 0) {
			chdir(buf0);
			return NULL;
			}
		if (sbuf.st_ino == ino && sbuf.st_dev == dev) { /* we're done */
			chdir(buf0);
			return strdup(buf0);
			}
		dir = opendir("..");
		if (!dir) {
			chdir(buf0);
			return NULL;
			}
		chdir("..");
		readdir(dir); readdir(dir);
		while (de = readdir(dir))
			if (de->d_fileno == ino) { /* find file with matching inode */
				lstat(de->d_name,&sbuf);
				if (sbuf.st_dev == dev)
					goto match;
				}
		rewinddir(dir);
		readdir(dir); readdir(dir);
		while (de = readdir(dir)) {
			lstat(de->d_name,&sbuf);
			if (sbuf.st_dev == dev) /* find file with matching device # */
				goto match;
			}
		closedir(dir);
		return NULL;
match:
		strcpy(buf3,de->d_name);
		if (*buf2)
			strcat(buf3,"/");
		strcat(buf3,buf2);
		strcpy(buf2,buf3);
		closedir(dir);
		}
}

--
Paul Falstad, pfalstad@phoenix.princeton.edu PLink:HYPNOS GEnie:P.FALSTAD
"We could nuke Baghdad into glass, wipe it with Windex, tie fatback on
our feet and go skating." - Air Force Times columnist Fred Reed

denap@alta.sw.stratus.com (Tom DeNapoli) (01/12/91)

Along the same lines... 

Has anyone got anything that will return the absolute pathname of
an open file to a process?  

Process A has file ./dir1/dir2/foo open and he wants the absolute
path to the file as in /usr/local/stuff/dir1/dir2.  

Ultimately I need to relay this info to Process B and prepend the
automount (SunOS 4.1) point to the pathname.  As in
/net/freddie/usr/local/stuff/dir1/dir2/foo. 

thanks in advance.
-Tom
--
  Tom DeNapoli              | Stratus Computer, Inc.
  denap@alta.sw.stratus.com | 55 Fairbanks Blvd M23EN3
  uunet!lectroid!alta!denap | Marlboro, MA 01752

6sigma2@polari.UUCP (Brian Matthews) (01/13/91)

In article <5195@idunno.Princeton.EDU> pfalstad@phoenix.Princeton.EDU (Paul John Falstad) writes:
|Here is a version of getwd I wrote for zsh.  I'd be interested in what
|people think of it.  I needed a version that didn't fork(), and was
|having problems with the Sun getwd().

[getwd that crawls up the directory tree reading each directory on the way]

The problem with this is that it's quite possible to be in a directory
which has some ancestors that can't be read.  Thus a program calling this
getwd must be running setuid root or in a restricted environment (in which
case it probably shouldn't need to call getwd) where it knows all ancestors
of the current directory are readable.
-- 
Brian L. Matthews	6sigma2@polari.UUCP

subbarao@phoenix.Princeton.EDU (Kartik Subbarao) (01/14/91)

In article <DENAP.91Jan11134939@alta.sw.stratus.com> denap@alta.sw.stratus.com (Tom DeNapoli) writes:
>Along the same lines... 
>
>Has anyone got anything that will return the absolute pathname of
>an open file to a process?  
>
>Process A has file ./dir1/dir2/foo open and he wants the absolute
>path to the file as in /usr/local/stuff/dir1/dir2.  
>

A way to do this is to chdir() to the directory of the file (i.e.
dir1/dir2) and then do a getcwd() to find out where absolutely where you
are, like this:

/* # include <sys/param.h> */
    
    char fullpath[MAXPATHLEN];
    chdir("dir1/dir2"); 
    getcwd(fullpath, MAXPATHLEN);
    printf("Full pathname is %s\n", fullpath);


			-Kartik



Newsgroups: comp.unix.programmer
Subject: Re: getting the current working directory
Summary: 
Expires: 
References: <42380@ut-emx.uucp> <DENAP.91Jan11134939@alta.sw.stratus.com>
Sender: 
Followup-To: 
Distribution: usa
Organization:  
Keywords: 

In article <DENAP.91Jan11134939@alta.sw.stratus.com> denap@alta.sw.stratus.com (Tom DeNapoli) writes:
>Along the same lines... 
>
>Has anyone got anything that will return the absolute pathname of
>an open file to a process?  
>
>Process A has file ./dir1/dir2/foo open and he wants the absolute
>path to the file as in /usr/local/stuff/dir1/dir2.  
>

A way to do this is to chdir() to the directory of the file (i.e.
dir1/dir2) and then do a getcwd() to find out where absolutely where you
are, like this:

/* # include <sys/param.h> */
    
    char fullpath[MAXPATHLEN];
    chdir("dir1/dir2"); 
    getcwd(fullpath, MAXPATHLEN);
    printf("Full pathname is %s\n", fullpath);


			-Kartik



--
internet# ls -alR | grep *.c
subbarao@{phoenix or gauguin}.Princeton.EDU -|Internet
kartik@silvertone.Princeton.EDU (NeXT mail)       -|	
SUBBARAO@PUCC.BITNET			          - Bitnet

guy@auspex.auspex.com (Guy Harris) (01/16/91)

>[getwd that crawls up the directory tree reading each directory on the way]
>
>The problem with this is that it's quite possible to be in a directory
>which has some ancestors that can't be read.  Thus a program calling this
>getwd must be running setuid root or in a restricted environment (in which
>case it probably shouldn't need to call getwd) where it knows all ancestors
>of the current directory are readable.

A program calling just about *any* flavor of "getwd()" must be running
set-uid "root" or in a restricted environment of that sort if you
actually care about getting the right answer in a directory that has
some ancestors that can't be read.  The 4.xBSD "getwd()" and SunOS
"getwd()"s, just like the posted one, crawl up the directory tree
reading each directory on the way.

Prior to S5R4, S5's "getcwd()" "popen()"ed a "pwd" program, but I don't
think "pwd" is set-UID "root" in S5.  I think S5R4's is a subroutine
that crawls up the directory tree, just like many (all?) "getwd()"s.

Note also that in the presence of various distributed file systems even
set-UID "root" may not be enough; both NFS and RFS servers may map the
root user-ID to some unprivileged user ID.

chip@tct.uucp (Chip Salzenberg) (01/17/91)

According to guy@auspex.auspex.com (Guy Harris):
>Note also that in the presence of various distributed file systems even
>set-UID "root" may not be enough; both NFS and RFS servers may map the
>root user-ID to some unprivileged user ID.

Just to chime in: In such environments, set-UID "root" programs have
less priviledge than the programs that call them.

I just use Doug Gwyn's getpwd() implementation.  It saves me a lot of
time and trouble.
-- 
Chip Salzenberg at Teltronics/TCT     <chip@tct.uucp>, <uunet!pdn!tct!chip>
       "If Usenet exists, then what is its mailing address?"  -- me
             "c/o The Daily Planet, Metropolis."  -- Jeff Daiell