[comp.lang.perl] How to find working directory?

petolino@joe.Eng.Sun.COM (Joe Petolino) (08/01/90)

I'm a fairly new perl user, so excuse me if this is a dumb question.

I know I can change my working directory with chdir(<string>).  Is there a 
symmetrical operation which tells me what my working directory is (short
of invoking pwd in a subshell, that is)?  Imagine my surprise when I
found out that chdir() doesn't set $ENV{'PWD'} !  Do I really have to
test each chdir() for success and then conditionally assign its argument
to $ENV{'PWD'} ?  The programs I'm invoking after the chdir() expect
$PWD to be accurate.

-Joe

lwall@jpl-devvax.JPL.NASA.GOV (Larry Wall) (08/03/90)

In article <139945@sun.Eng.Sun.COM> petolino@joe.Eng.Sun.COM (Joe Petolino) writes:
: I know I can change my working directory with chdir(<string>).  Is there a 
: symmetrical operation which tells me what my working directory is (short
: of invoking pwd in a subshell, that is)?

No.

: Imagine my surprise when I found out that chdir() doesn't set $ENV{'PWD'} !

Ok.

: Do I really have to test each chdir() for success and then conditionally
: assign its argument to $ENV{'PWD'} ?

Yes and/or no, depending on how you work it.

Here's the slow but concise way:

    sub initpwd { chop($ENV{'PWD'} = `pwd`); }
    sub chdir { chdir shift; &initpwd; }

Call initpwd at the top of the show.

Note that the existence of a getwd call wouldn't speed this up all that
much--getwd is a fairly expensive operation.  You really just want to
init PWD at the beginning of the program and then keep track of it.

So here's the fast way

    sub initpwd {
	if ($ENV{'PWD'}) {
	    local($dd,$di) = stat('.');
	    local($pd,$pi) = stat($ENV{'PWD'});
	    return if $di == $pi && $dd == $pd;
	}
	chop($ENV{'PWD'} = `pwd`);
    }

    sub chdir {
	local($newdir) = shift;
	if (chdir $newdir) {
	    if ($newdir =~ m#^/#) {
		$ENV{'PWD'} = $newdir;
	    }
	    else {
		local(@curdir) = split(m#/#,$ENV{'PWD'});
		@curdir = '' unless @curdir;
		foreach $component (split(m#/#, $newdir)) {
		    next if $component eq '.';
		    pop(@curdir),next if $component eq '..';
		    push(@curdir,$component);
		}
		$ENV{'PWD'} = join('/',@curdir) || '/';
	    }
	}
	else {
	    0;
	}
    }

There will be a library package to do this in the next patch.

: The programs I'm invoking after the chdir() expect $PWD to be accurate.

Then the programs you're invoking are highly non-portable.  Only certain
shells keep track of PWD.  Any C program that uses chdir and then invokes
one of these programs will confuse it.

I stop just short of saying the programs are busted.

Larry

khera@juliet.cs.duke.edu (Vick Khera) (08/03/90)

In article <8974@jpl-devvax.JPL.NASA.GOV> lwall@jpl-devvax.JPL.NASA.GOV (Larry Wall) writes:
:In article <139945@sun.Eng.Sun.COM> petolino@joe.Eng.Sun.COM (Joe Petolino) writes:
:: The programs I'm invoking after the chdir() expect $PWD to be accurate.
:
:Then the programs you're invoking are highly non-portable.  Only certain
:shells keep track of PWD.  Any C program that uses chdir and then invokes
:one of these programs will confuse it.
:
:I stop just short of saying the programs are busted.
:
:Larry

GNU Emacs uses PWD if it exists.  my normal login shell updates PWD
but /bin/csh doesn't (under 4.3BSD) so when i fire up emacs after
su'ing to another user, emacs gets the wrong directory.  i'd say this
is busted.

								v.
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
Vick Khera           (919) 660-6528     Department of Computer Science
ARPA:   khera@cs.duke.edu               Duke University
UUCP:   ..!{mcnc,decvax}!duke!khera     Durham, NC 27706

tchrist@convex.COM (Tom Christiansen) (08/04/90)

In article <21198@duke.cs.duke.edu> khera@cs.duke.edu (Vick Khera) writes:
>In article <8974@jpl-devvax.JPL.NASA.GOV> lwall@jpl-devvax.JPL.NASA.GOV (Larry Wall) writes:
>:I stop just short of saying the programs are busted.

>GNU Emacs uses PWD if it exists.  my normal login shell updates PWD
>but /bin/csh doesn't (under 4.3BSD) so when i fire up emacs after
>su'ing to another user, emacs gets the wrong directory.  i'd say this
>is busted.

I'm not sure which you say is busted.  It seems highly suspect
to look at your environment for the $PWD.  It's like trusting
it for $USER.  Use getwd() and getpwnam(getuid()) for these.  
What if a program does its own chdir() followed by an exec()
or system()?  

--tom
--

    Tom Christiansen                       {uunet,uiucdcs,sun}!convex!tchrist 
    Convex Computer Corporation                            tchrist@convex.COM
		 "EMACS belongs in <sys/errno.h>: Editor too big!"

richard@pegasus.com (Richard Foulk) (08/05/90)

>>GNU Emacs uses PWD if it exists.  my normal login shell updates PWD
>>but /bin/csh doesn't (under 4.3BSD) so when i fire up emacs after
>>su'ing to another user, emacs gets the wrong directory.  i'd say this
>>is busted.
>
>I'm not sure which you say is busted.  It seems highly suspect
>to look at your environment for the $PWD.  It's like trusting
>it for $USER.  Use getwd() and getpwnam(getuid()) for these.  
>What if a program does its own chdir() followed by an exec()
>or system()?  

The only time $USER isn't trusted is when security is at stake.  Having
a $PWD that is incorrect seems very ungood to me.  You could at least
remove it from the environment if you know it's wrong.



-- 
Richard Foulk		richard@pegasus.com

jv@mh.nl (Johan Vromans) (08/06/90)

In article <1990Aug5.115155.10191@pegasus.com> richard@pegasus.com (Richard Foulk) writes:

> The only time $USER isn't trusted is when security is at stake.  Having
> a $PWD that is incorrect seems very ungood to me.  You could at least
> remove it from the environment if you know it's wrong.

The environment variable PWD does not have any relation at all with
the current working directory, although some programs think it does.
Because sometimes it does reflect where you are, it may be used as a
starting point to find out the current working dir.

Removing PWD from the environment in certain situations would violate
all rules. The user is in total control of all environment variables,
no program should interfere.

	Johan
-- 
Johan Vromans				       jv@mh.nl via internet backbones
Multihouse Automatisering bv		       uucp: ..!{uunet,hp4nl}!mh.nl!jv
Doesburgweg 7, 2803 PL Gouda, The Netherlands  phone/fax: +31 1820 62911/62500
------------------------ "Arms are made for hugging" -------------------------

stef@zweig.sun (Stephane Payrard) (08/07/90)

At high levels, the infos about the current directory, are not
very reliable. But sometimes it is no better in the lowest level!!!

On a Sun host using automounter (at least in SunOS 4.1),
you can't even always expect something usable from getwd()
or getcwd().

As an example, my current directory is:
     /home/fred
But
    getwd() says me that it is /auto/home/fred

This path will work as long as the file-system is mounted.
But the automounter unmounts file systems not recently referenced
and is unable to understand /auto/home/fred once the corresponding
has been unmounted.


I guess what happened is that getcwd() tried to normalize the path and
returned a path without symbolic links. This is clearly not the
correct behavior with automounted directories.  Using the infos in
/etc/mtab and the automounter maps, it should be possible to write a
perl script which does correctly what getwd() should do.  In my
particular case, I know that the prefix to suppress is '/auto' so I
don't need such a general script.


The automounter is a utility which allows to mount dynamically and
transparently NFS files-sytems. It uses the NIS (ex YP) so the
administration of the mount  is not necessarily done host by host.
It is great (as in SunOS 4.1), but, as mentionned, has still some
minor shortcoming.


        stef
--
Stephane Payrard -- stef@sun.com -- (415) 336 3726
Sun Microsystems -- 2550 Garcia Avenue --  M/S 10-09 -- Mountain View  CA 94043

                     
                     

hakanson@ogicse.ogi.edu (Marion Hakanson) (08/09/90)

In article <8974@jpl-devvax.JPL.NASA.GOV> lwall@jpl-devvax.JPL.NASA.GOV (Larry Wall) writes:
>In article <139945@sun.Eng.Sun.COM> petolino@joe.Eng.Sun.COM (Joe Petolino) writes:
>: I know I can change my working directory with chdir(<string>).  Is there a 
>: symmetrical operation which tells me what my working directory is (short
>: of invoking pwd in a subshell, that is)?
>
>No.

This has bugged me for a long time.  You've got rmdir and mkdir, which
are implemented by running the corresponding commands, on systems
which don't have rmdir(2) and mkdir(2).  Why not provide the same kind
of uniform access to getwd?  Use the system call if it's there, and
run "pwd" for the user if it's not.  After all, isn't one of the
points of Perl's existence to provide a uniform interface to various
systems?  Suppose I want to port my Perl script to a machine that
doesn't have a pwd command (like DOS or some such)?

I've asked for this before.  I've also asked for a gethostname interface
to the various "uname/hostname/gethostname" system calls, too.  And
ctime(3) and getfsent(3), etc.  You can't always get what you want....

-- 
Marion Hakanson         Domain: hakanson@cse.ogi.edu
                        UUCP  : {hp-pcd,tektronix}!ogicse!hakanson