[GRASS-dev] G.proj requirements?

Maris Nartiss noticed that if you are starting from scratch (i.e., you have
no locations already defined), you can¹t create a new location from a
georeferenced file. But you can create one from an EPSG code.

I¹m working on the epsg startup and have found that Markus did a bash script
that makes an epsg created location functional even when there is no prior
location defined. This script creates a temporary location for use while
g.proj is running, and then deletes it.

I¹m wrapping this code into the new epsg_option.tcl script I've done (it now
can search the EPSG file and automatically grab the code). I can do the same
for the file_option.tcl script to make creating a new location from a
georeferenced file equally functional.

So here is what I need to know, if anyone has the answer. What does g.proj
*REALLY* need in order to run?

I'm beginning to think that it needs an existing .grassrc6 file with a
GISDBASE path defined (and set as an environmental variable) so that it
knows where to put a new location.

Is this all? Or does it also need a GISDBASE path with at least one location
already defined? Does it need a .grassrc6 file, or is setting the GISDBASE
environmental variable good enough?

This could really simplify the code for creating a new location.

Thanks
Michael
__________________________________________
Michael Barton, Professor of Anthropology
School of Human Evolution & Social Change
Center for Social Dynamics & Complexity
Arizona State University

phone: 480-965-6213
fax: 480-965-7671
www: http://www.public.asu.edu/~cmbarton

Hi Michael and others,

1st - g.proj, as most of other GRASS modules, calls G_gisinit() at
beginning. I traced down requirements to lib/gis/env.c, but at first
look could not understand how it works :slight_smile:

2nd - as make_location_epsg.sh works, the easiest way would be just to
copy that file and modify for geroef file needs.
Two questions still remain - a) should georeferenced file be imported
into new location and b) how to do that, as most of r/v.in.* modules
have a lot of options making they use user-dependent (I mean -
importing shapefile is straight - one file, one layer and all, but
what to do with more complex file types)?

3 - if You Michael are working on EPSG/Georef scripts, I will then
look on startup screen. Only question - do You plan to include some
code to notify user about failed process? I plan to get rid of
requirement to restart GRASS to start using new location and I need to
know how are You dealing with failure. One option is - after running
"create loc from XX", at startup screen check if newLoc is valid and
then report an error to user, if it is NOT valid (an error while
creating new loc).

About simplifying code - maybe there is place under the sun for script
crate-temp-location.sh?

Maris.

PS. Damn' tcl/tk! It's so easy (and fun), that I hack around in GRASS
code instead of doing real work :wink:

2006/12/15, Michael Barton <michael.barton@asu.edu>:

Maris Nartiss noticed that if you are starting from scratch (i.e., you have
no locations already defined), you can¹t create a new location from a
georeferenced file. But you can create one from an EPSG code.

I¹m working on the epsg startup and have found that Markus did a bash script
that makes an epsg created location functional even when there is no prior
location defined. This script creates a temporary location for use while
g.proj is running, and then deletes it.

I¹m wrapping this code into the new epsg_option.tcl script I've done (it now
can search the EPSG file and automatically grab the code). I can do the same
for the file_option.tcl script to make creating a new location from a
georeferenced file equally functional.

So here is what I need to know, if anyone has the answer. What does g.proj
*REALLY* need in order to run?

I'm beginning to think that it needs an existing .grassrc6 file with a
GISDBASE path defined (and set as an environmental variable) so that it
knows where to put a new location.

Is this all? Or does it also need a GISDBASE path with at least one location
already defined? Does it need a .grassrc6 file, or is setting the GISDBASE
environmental variable good enough?

This could really simplify the code for creating a new location.

Thanks
Michael
__________________________________________
Michael Barton, Professor of Anthropology
School of Human Evolution & Social Change
Center for Social Dynamics & Complexity
Arizona State University

phone: 480-965-6213
fax: 480-965-7671
www: http://www.public.asu.edu/~cmbarton

Hello Michael
I *think* all it should need is a valid GISRC file, i.e. with the 3 fields GISDBASE, LOCATION_NAME and MAPSET. The latter two won't be relevant if no exising locations are there, so they can contain anything, but GISDBASE is important. Look at the code in Init.sh that creates a initial GISRC if none is there. So I think it should work if the file contains the 3 lines:
GISDBASE: C:/grassdata
LOCATION_NAME: <UNKNOWN>
MAPSET: <UNKNOWN>

You need to set the GISRC environment variable to point to the location of this file; also the GISBASE environment variable needs to point to the location of the GRASS installation. I think that should be all you need. Note that Init.sh will have created a GISRC file if none exists before starting gis_set.tcl (AFAICT) so you should have no trouble here at all and not actually need to worry about this. I think.

Just a note that you need to pay attention to what is done by Init.sh and what is done by etc/set_data (text) or gis_set.tcl (GUI) and the interaction between the two. E.g. where Mariss was talking about failure. Failure should be handled in Init.sh I think - the key thing is for gis_set.tcl to return a proper return value so Init.sh knows it has failed. Of course "recoverable failures" could be handled within gis_set.tcl and give the user another chance to create the location.

Paul

On Fri, 15 Dec 2006, Michael Barton wrote:

Maris Nartiss noticed that if you are starting from scratch (i.e., you have
no locations already defined), you can¹t create a new location from a
georeferenced file. But you can create one from an EPSG code.

I¹m working on the epsg startup and have found that Markus did a bash script
that makes an epsg created location functional even when there is no prior
location defined. This script creates a temporary location for use while
g.proj is running, and then deletes it.

I¹m wrapping this code into the new epsg_option.tcl script I've done (it now
can search the EPSG file and automatically grab the code). I can do the same
for the file_option.tcl script to make creating a new location from a
georeferenced file equally functional.

So here is what I need to know, if anyone has the answer. What does g.proj
*REALLY* need in order to run?

I'm beginning to think that it needs an existing .grassrc6 file with a
GISDBASE path defined (and set as an environmental variable) so that it
knows where to put a new location.

Is this all? Or does it also need a GISDBASE path with at least one location
already defined? Does it need a .grassrc6 file, or is setting the GISDBASE
environmental variable good enough?

This could really simplify the code for creating a new location.

Thanks
Michael
__________________________________________
Michael Barton, Professor of Anthropology
School of Human Evolution & Social Change
Center for Social Dynamics & Complexity
Arizona State University

phone: 480-965-6213
fax: 480-965-7671
www: http://www.public.asu.edu/~cmbarton

_______________________________________________
grass-dev mailing list
grass-dev@grass.itc.it
http://grass.itc.it/mailman/listinfo/grass-dev

Paul,

This is very helpful.

On 12/15/06 3:44 AM, "Paul Kelly" <paul-grass@stjohnspoint.co.uk> wrote:

I *think* all it should need is a valid GISRC file, i.e. with the 3 fields
GISDBASE, LOCATION_NAME and MAPSET. The latter two won't be relevant if no
exising locations are there, so they can contain anything, but GISDBASE is
important. Look at the code in Init.sh that creates a initial GISRC if
none is there. So I think it should work if the file contains the 3 lines:
GISDBASE: C:/grassdata
LOCATION_NAME: <UNKNOWN>
MAPSET: <UNKNOWN>

This is what I began to suspect.

You need to set the GISRC environment variable to point to the location of
this file; also the GISBASE environment variable needs to point to the
location of the GRASS installation. I think that should be all you need.
Note that Init.sh will have created a GISRC file if none exists before
starting gis_set.tcl (AFAICT) so you should have no trouble here at all
and not actually need to worry about this. I think.

But given this, I'm wondering now if the .gisrc6 file is the issue at all.

Just a note that you need to pay attention to what is done by Init.sh and
what is done by etc/set_data (text) or gis_set.tcl (GUI) and the
interaction between the two. E.g. where Mariss was talking about failure.
Failure should be handled in Init.sh I think - the key thing is for
gis_set.tcl to return a proper return value so Init.sh knows it has
failed. Of course "recoverable failures" could be handled within
gis_set.tcl and give the user another chance to create the location.

Following your advice, I looked at what init.sh is doing with the grassrc
file at startup. I still don't understand it completely, but it looks like
it is creating a temporary GISRC file in all cases. If a .grassrc6 file
already exists, this is copied to GISRC in the tmp directory and used. If
not, a temporary GISRC is created. All this happens in init.sh before
gis_set.tcl is called. In the case of a first time user, the current working
directory (PWD in the bash script) is used as a GISDBASE initially. This is
what shows up in the GRASS entry GUI the first time you run it (or if you
run it after deleting your .grassrc6 file).

AFAICT, GRASS uses the GISRC file it creates (normally by copying .grassrc6,
but created by init.sh if needed) for all session reference to the startup
information.

What I'm not yet sure about is when the GISDBASE environmental variable gets
set. Quite possibly, with the gui startup, this is not until you push the
start grass button, even if you have a valid GISDBASE path in the startup
gui entry widget.

If this is the case, and if this is what g.proj needs to know in order to
create its new location, it is easy to simply set GISDBASE in both the EPSG
and georeferenced file startup scripts.

While I could certainly go through the procedures of making a temporary
GISRC file, init.sh has already done this and the script will overwrite what
is already there. I could also make the fake location, but I think that is
not necessary. I don't want to copy useless code into new modules; there is
enough of that legacy already to deal with.

At a minimum, we simply need to set the GISDBASE variable. At a maximum, we
may also need to create a .grassrc6 file by copying the existing GISRC file
to the home directory. However, I'm not sure how that works in Windows. Is
there anyway to see if g.proj actually reads .grassrc6 or checks for its
existence? An intermediate step might be to replace any temporary GISDBASE
setting in the working session GISRC file with a valid path, but I'm
skeptical since it should already be making one.

I'm not quite sure how I can test this. Maybe if I rename .grassrc6 it will
simulate a new user.

Michael
__________________________________________
Michael Barton, Professor of Anthropology
School of Human Evolution & Social Change
Center for Social Dynamics & Complexity
Arizona State University

phone: 480-965-6213
fax: 480-965-7671
www: http://www.public.asu.edu/~cmbarton

On Fri, 15 Dec 2006, Michael Barton wrote:

Paul,

This is very helpful.

On 12/15/06 3:44 AM, "Paul Kelly" <paul-grass@stjohnspoint.co.uk> wrote:

I *think* all it should need is a valid GISRC file, i.e. with the 3 fields
GISDBASE, LOCATION_NAME and MAPSET. The latter two won't be relevant if no
exising locations are there, so they can contain anything, but GISDBASE is
important. Look at the code in Init.sh that creates a initial GISRC if
none is there. So I think it should work if the file contains the 3 lines:
GISDBASE: C:/grassdata
LOCATION_NAME: <UNKNOWN>
MAPSET: <UNKNOWN>

This is what I began to suspect.

You need to set the GISRC environment variable to point to the location of
this file; also the GISBASE environment variable needs to point to the
location of the GRASS installation. I think that should be all you need.
Note that Init.sh will have created a GISRC file if none exists before
starting gis_set.tcl (AFAICT) so you should have no trouble here at all
and not actually need to worry about this. I think.

But given this, I'm wondering now if the .gisrc6 file is the issue at all.

Yes - what was the problem exactly? If there is something else in g.proj or the libraries it uses it might be better to fix it rather than working around it. I was thinking - if the user changes the GISDBASE setting in the gis_set.tcl window before clicking to create a new location with georeferenced file or EPSG code, will gis_set.tcl update the GISRC file before running g.proj? I suspect not, but it needs to do so so that the location is created under the correct GISDBASE.

Just a note that you need to pay attention to what is done by Init.sh and
what is done by etc/set_data (text) or gis_set.tcl (GUI) and the
interaction between the two. E.g. where Mariss was talking about failure.
Failure should be handled in Init.sh I think - the key thing is for
gis_set.tcl to return a proper return value so Init.sh knows it has
failed. Of course "recoverable failures" could be handled within
gis_set.tcl and give the user another chance to create the location.

Following your advice, I looked at what init.sh is doing with the grassrc
file at startup. I still don't understand it completely, but it looks like
it is creating a temporary GISRC file in all cases. If a .grassrc6 file
already exists, this is copied to GISRC in the tmp directory and used. If
not, a temporary GISRC is created. All this happens in init.sh before
gis_set.tcl is called. In the case of a first time user, the current working
directory (PWD in the bash script) is used as a GISDBASE initially. This is
what shows up in the GRASS entry GUI the first time you run it (or if you
run it after deleting your .grassrc6 file).

AFAICT, GRASS uses the GISRC file it creates (normally by copying .grassrc6,
but created by init.sh if needed) for all session reference to the startup
information.

Yes I think that's all correct. But it is very hard to follow now because of the complications allowed by allowing concurrent GRASS sessions. Previously there was just the one .grassrc6 file (actually IMHO this should be version-specific: .grassrc60, .grassrc62, .grassrc63 etc. as it was with GRASS 5.x) in the home directory and everything was read from or written to there - no temporary copies in /tmp were involved. For the Windows batch file (init.bat) I wrote to duplicate the functionality of Init.sh, I left all this temporary copying of GISRC out to simplify things. It means you can only have one concurrent session but that is normal on Windows I suppose.

What I'm not yet sure about is when the GISDBASE environmental variable gets
set. Quite possibly, with the gui startup, this is not until you push the
start grass button, even if you have a valid GISDBASE path in the startup
gui entry widget.

Is there actually a GISDBASE environment variable? I don't think there should be, and if something is relying on it being there it should be changed. As far as I understand it the only environment variables absolutely necessary are GISRC and GISBASE and GISDBASE is stored in GISRC and read by modules using library functions or with g.gisenv.

If this is the case, and if this is what g.proj needs to know in order to
create its new location, it is easy to simply set GISDBASE in both the EPSG
and georeferenced file startup scripts.

Like I said I don't think this is necessary or desirable - as far as I can see g.proj will get the GISDBASE value to create the new location under from the file specified by $GISRC.

While I could certainly go through the procedures of making a temporary
GISRC file, init.sh has already done this and the script will overwrite what
is already there. I could also make the fake location, but I think that is

It can be anywhere, as long as you change the value of $GISRC to point to it. No need to overwrite anything. But yes, it is not clear why the initial/temporary file created by Init.sh doesn't work. This would be the main point to look at I think.

not necessary. I don't want to copy useless code into new modules; there is
enough of that legacy already to deal with.

At a minimum, we simply need to set the GISDBASE variable. At a maximum, we
may also need to create a .grassrc6 file by copying the existing GISRC file
to the home directory. However, I'm not sure how that works in Windows. Is
there anyway to see if g.proj actually reads .grassrc6 or checks for its

All modules that use the parser do. They simply won't work without a GISRC file. To see this, just try changing the GISRC environment variable to a non-existent file within a GRASS text-based session and try running any GRASS command. It won't work. I think setting the GISRC environment
variable and/or making sure it is set properly is the main thing to look at rather than creating new .grassrc6 files everywhere (the file can actually of course have any name---it just needs to be contained in the GISRC environment variable).

existence? An intermediate step might be to replace any temporary GISDBASE
setting in the working session GISRC file with a valid path, but I'm
skeptical since it should already be making one.

I'm not quite sure how I can test this. Maybe if I rename .grassrc6 it will
simulate a new user.

Yes rename or delete it and on startup Init.sh will create a new one.

Paul

OK. This helps a LOT!

AFAICT, there should always be a GISRC file created by init.sh with some
kind of path to a folder that can serve as a GRASS database.

So this leaves us with asking why g.proj will fail. I'll need to run some
tests I guess. And maybe you and Maris can too.

An easy thing to do is get GRASS initialized but stop at the startup GUI
screen. Go find the session GISRC file and see what is in it for an initial
startup vs. a startup of someone with a valid .grassrc6 file.

What happens if you change this prior to trying to create a location using a
georeferenced file?

Michael

On 12/15/06 11:07 AM, "Paul Kelly" <paul-grass@stjohnspoint.co.uk> wrote:

All modules that use the parser do. They simply won't work without a GISRC
file. To see this, just try changing the GISRC environment variable to a
non-existent file within a GRASS text-based session and try running any
GRASS command. It won't work. I think setting the GISRC environment
variable and/or making sure it is set properly is the main thing to look
at rather than creating new .grassrc6 files everywhere (the file can
actually of course have any name---it just needs to be contained in the
GISRC environment variable).

__________________________________________
Michael Barton, Professor of Anthropology
School of Human Evolution & Social Change
Center for Social Dynamics and Complexity
Arizona State University

phone: 480-965-6213
fax: 480-965-7671
www: http://www.public.asu.edu/~cmbarton

Paul,

I've run some tests and understand what g.proj is doing and I understand
why. Here are a few of the test results. I started GRASS without a .grassrc6
file and tried to create a new location, using a georeferenced file. I
modified the GISRC file in several ways prior to invoking the georeferenced
file to define a new location. As I noted before, GRASS always makes a
default GISRC file. If there is no pre-existing .grassrc6 file, the GISRC
file sets GISDBASE to the current working directory, and both LOCATION_NAME
and MAPSET to <UNKNOWN>.

Test 1: started with no .grassrc6 file; no other modification

=================================================================
If you wish to resize the X monitor, do so now. Window size is
locked while interactive modules are running.

access: No such file or directory
ERROR: LOCATION << /Users/cmbarton/<UNKNOWN> >> not available

ERROR: g.proj exited abnormally. Press <enter> to continue.

************************************************************

Test 2: started with no .grassrc6 file; modified /tmp/.../GISRC file to
change

LOCATION_NAME: <UNKNOWN>

to

LOCATION_NAME: testloc

=================================================================
If you wish to resize the X monitor, do so now. Window size is
locked while interactive modules are running.

access: No such file or directory
ERROR: LOCATION << /Users/cmbarton/testloc >> not available

ERROR: g.proj exited abnormally. Press <enter> to continue.

************************************************************

Test 3: started with no .grassrc6 file; modified /tmp/.../GISRC file to name
a location and mapset directory (testloc and PERMANENT); created
$HOME/testloc/PERMANENT but did not put anything in directory

=================================================================
If you wish to resize the X monitor, do so now. Window size is
locked while interactive modules are running.

ERROR: default region is not set

ERROR: g.proj exited abnormally. Press <enter> to continue.

So, it is clear that g.proj looks at the GISRC file, then verifies the
existence of the location and mapset specified in the file, then looks for
the WIND file inside the PERMANENT mapset of the specified location.

This makes a lot of sense for most of g.proj functionality, specifically
reporting the current projection information in various formats and
modifying the projection information of the current location.

However, it is problematic for creating a new location--that is, with the -c
flag and a new location specified in the location=[new loc name] argument.

There are ways to get around this currently, but it would be much better if
the checks for a valid location, mapset, and WIND file were bypassed for
using g.proj to create a new location. The only thing it needs to know to do
this is a valid GISDBASE, and this is always specified in a GISRC file. So
what are the chances of modifying g.proj in this way instead of requiring
the startup scripts to make some fake locations and WIND files to satify
g.proj?

To start from scratch with something other than the current working
directory, we'd need to replace this temporary GISRC file with whatever
directory is specified in the GUI startup, but this isn't too difficult.

Markus has produced a workaround in a bash script that is necessary because
of the way g.proj functions. It makes and erases temporary location, mapset,
and WIND files, and archives, replaces, and restores the .grassrc6
file--regardless of whether or not you have a valid location already in
existence. This worries me a bit as it makes more opportunities for
corruption in the .grassrc6 file or GISDBASE path if something goes wrong in
the process.

Michael

On 12/15/06 11:07 AM, "Paul Kelly" <paul-grass@stjohnspoint.co.uk> wrote:

On Fri, 15 Dec 2006, Michael Barton wrote:

Paul,

This is very helpful.

On 12/15/06 3:44 AM, "Paul Kelly" <paul-grass@stjohnspoint.co.uk> wrote:

I *think* all it should need is a valid GISRC file, i.e. with the 3 fields
GISDBASE, LOCATION_NAME and MAPSET. The latter two won't be relevant if no
exising locations are there, so they can contain anything, but GISDBASE is
important. Look at the code in Init.sh that creates a initial GISRC if
none is there. So I think it should work if the file contains the 3 lines:
GISDBASE: C:/grassdata
LOCATION_NAME: <UNKNOWN>
MAPSET: <UNKNOWN>

This is what I began to suspect.

You need to set the GISRC environment variable to point to the location of
this file; also the GISBASE environment variable needs to point to the
location of the GRASS installation. I think that should be all you need.
Note that Init.sh will have created a GISRC file if none exists before
starting gis_set.tcl (AFAICT) so you should have no trouble here at all
and not actually need to worry about this. I think.

But given this, I'm wondering now if the .gisrc6 file is the issue at all.

Yes - what was the problem exactly? If there is something else in g.proj
or the libraries it uses it might be better to fix it rather than working
around it. I was thinking - if the user changes the GISDBASE setting in
the gis_set.tcl window before clicking to create a new location with
georeferenced file or EPSG code, will gis_set.tcl update the GISRC file
before running g.proj? I suspect not, but it needs to do so so that the
location is created under the correct GISDBASE.

Just a note that you need to pay attention to what is done by Init.sh and
what is done by etc/set_data (text) or gis_set.tcl (GUI) and the
interaction between the two. E.g. where Mariss was talking about failure.
Failure should be handled in Init.sh I think - the key thing is for
gis_set.tcl to return a proper return value so Init.sh knows it has
failed. Of course "recoverable failures" could be handled within
gis_set.tcl and give the user another chance to create the location.

Following your advice, I looked at what init.sh is doing with the grassrc
file at startup. I still don't understand it completely, but it looks like
it is creating a temporary GISRC file in all cases. If a .grassrc6 file
already exists, this is copied to GISRC in the tmp directory and used. If
not, a temporary GISRC is created. All this happens in init.sh before
gis_set.tcl is called. In the case of a first time user, the current working
directory (PWD in the bash script) is used as a GISDBASE initially. This is
what shows up in the GRASS entry GUI the first time you run it (or if you
run it after deleting your .grassrc6 file).

AFAICT, GRASS uses the GISRC file it creates (normally by copying .grassrc6,
but created by init.sh if needed) for all session reference to the startup
information.

Yes I think that's all correct. But it is very hard to follow now because
of the complications allowed by allowing concurrent GRASS sessions.
Previously there was just the one .grassrc6 file (actually IMHO this
should be version-specific: .grassrc60, .grassrc62, .grassrc63 etc. as it
was with GRASS 5.x) in the home directory and everything was read from or
written to there - no temporary copies in /tmp were involved. For the
Windows batch file (init.bat) I wrote to duplicate the functionality of
Init.sh, I left all this temporary copying of GISRC out to simplify
things. It means you can only have one concurrent session but that is
normal on Windows I suppose.

What I'm not yet sure about is when the GISDBASE environmental variable gets
set. Quite possibly, with the gui startup, this is not until you push the
start grass button, even if you have a valid GISDBASE path in the startup
gui entry widget.

Is there actually a GISDBASE environment variable? I don't think there
should be, and if something is relying on it being there it should be
changed. As far as I understand it the only environment variables
absolutely necessary are GISRC and GISBASE and GISDBASE is stored in GISRC
and read by modules using library functions or with g.gisenv.

If this is the case, and if this is what g.proj needs to know in order to
create its new location, it is easy to simply set GISDBASE in both the EPSG
and georeferenced file startup scripts.

Like I said I don't think this is necessary or desirable - as far as I can
see g.proj will get the GISDBASE value to create the new location under
from the file specified by $GISRC.

While I could certainly go through the procedures of making a temporary
GISRC file, init.sh has already done this and the script will overwrite what
is already there. I could also make the fake location, but I think that is

It can be anywhere, as long as you change the value of $GISRC to point to
it. No need to overwrite anything. But yes, it is not clear why the
initial/temporary file created by Init.sh doesn't work. This would be the
main point to look at I think.

not necessary. I don't want to copy useless code into new modules; there is
enough of that legacy already to deal with.

At a minimum, we simply need to set the GISDBASE variable. At a maximum, we
may also need to create a .grassrc6 file by copying the existing GISRC file
to the home directory. However, I'm not sure how that works in Windows. Is
there anyway to see if g.proj actually reads .grassrc6 or checks for its

All modules that use the parser do. They simply won't work without a GISRC
file. To see this, just try changing the GISRC environment variable to a
non-existent file within a GRASS text-based session and try running any
GRASS command. It won't work. I think setting the GISRC environment
variable and/or making sure it is set properly is the main thing to look
at rather than creating new .grassrc6 files everywhere (the file can
actually of course have any name---it just needs to be contained in the
GISRC environment variable).

existence? An intermediate step might be to replace any temporary GISDBASE
setting in the working session GISRC file with a valid path, but I'm
skeptical since it should already be making one.

I'm not quite sure how I can test this. Maybe if I rename .grassrc6 it will
simulate a new user.

Yes rename or delete it and on startup Init.sh will create a new one.

Paul

__________________________________________
Michael Barton, Professor of Anthropology
School of Human Evolution & Social Change
Center for Social Dynamics and Complexity
Arizona State University

phone: 480-965-6213
fax: 480-965-7671
www: http://www.public.asu.edu/~cmbarton

Hello Michael
I've re-organised g.proj a bit so it doesn't read the region and projection from the current location unless it has to. But the problem remains, in three places:
(a) G_gisint()
(b) G_tempfile()
(c) G__put_window()/G__fopen_new()

(a) All modules have to call G_gisinit() at the start, and among other things it checks for a valid current location and mapset. However the case we're discussing is a rare example of where that isn't needed. Most of the rest of what G_gisinit() does (from a quick skimming over the code) seems related to raster modules and might possibly be possibly avoided?

(b) If the call to G_gisinit() is simply commented out, the next problem is G_tempfile() [deep within GRASS gproj library] which tries to create a tempfile in the current mapset as far as I remember - is this a good/bad idea? Certainly bad if you don't have a current mapset.

(c) Hard-coding the tempfile path in lib/proj/datum.c instead of calling G_tempfile() gets as far as writing out the new WIND and DEFAULT_WIND. This is done by a call to G__put_window() in G__make_location().

G__fopen_new(), which is called by G__put_window(), makes a call to G__check_gisinit() which fails [because we haven't called G_gisinit()]. In many cases (particularly when working with elements of a raster map) I'm sure it is a very good idea to check at this stage whether G_gisinit() has been called because of the rastery stuff it does but here it really doesn't seem to be necessary and if I comment it out (in the library function), then g.proj completes successfully and creates the new location.

This would need quite a bit of re-engineering to fix in an elegant way, definitely worth thinking about though IMHO. For now, looks like a complicated workaround is required. :frowning:

The default region is still an issue also, as Helena said. I know I should copy some code from r.in.gdal and v.in.ogr to g.proj to handle this as far as possible (i.e. match the default region in the new location to the georeferenced file - better than doing nothing). When there's some more time can maybe do that. And it will still be a problem with creating from EPSG code as the user is not forced or even reminded to set the region.

In case I forget, another tempfile issue is that g.tempfile (used in scripts) returns a tempfile with a Windows pathname which will then have problems in Msys.

Paul

On Sat, 16 Dec 2006, Michael Barton wrote:

Paul,

I've run some tests and understand what g.proj is doing and I understand
why. Here are a few of the test results. I started GRASS without a .grassrc6
file and tried to create a new location, using a georeferenced file. I
modified the GISRC file in several ways prior to invoking the georeferenced
file to define a new location. As I noted before, GRASS always makes a
default GISRC file. If there is no pre-existing .grassrc6 file, the GISRC
file sets GISDBASE to the current working directory, and both LOCATION_NAME
and MAPSET to <UNKNOWN>.

Test 1: started with no .grassrc6 file; no other modification

=================================================================
If you wish to resize the X monitor, do so now. Window size is
locked while interactive modules are running.

access: No such file or directory
ERROR: LOCATION << /Users/cmbarton/<UNKNOWN> >> not available

ERROR: g.proj exited abnormally. Press <enter> to continue.

************************************************************

Test 2: started with no .grassrc6 file; modified /tmp/.../GISRC file to
change

LOCATION_NAME: <UNKNOWN>

to

LOCATION_NAME: testloc

=================================================================
If you wish to resize the X monitor, do so now. Window size is
locked while interactive modules are running.

access: No such file or directory
ERROR: LOCATION << /Users/cmbarton/testloc >> not available

ERROR: g.proj exited abnormally. Press <enter> to continue.

************************************************************

Test 3: started with no .grassrc6 file; modified /tmp/.../GISRC file to name
a location and mapset directory (testloc and PERMANENT); created
$HOME/testloc/PERMANENT but did not put anything in directory

=================================================================
If you wish to resize the X monitor, do so now. Window size is
locked while interactive modules are running.

ERROR: default region is not set

ERROR: g.proj exited abnormally. Press <enter> to continue.

So, it is clear that g.proj looks at the GISRC file, then verifies the
existence of the location and mapset specified in the file, then looks for
the WIND file inside the PERMANENT mapset of the specified location.

This makes a lot of sense for most of g.proj functionality, specifically
reporting the current projection information in various formats and
modifying the projection information of the current location.

However, it is problematic for creating a new location--that is, with the -c
flag and a new location specified in the location=[new loc name] argument.

There are ways to get around this currently, but it would be much better if
the checks for a valid location, mapset, and WIND file were bypassed for
using g.proj to create a new location. The only thing it needs to know to do
this is a valid GISDBASE, and this is always specified in a GISRC file. So
what are the chances of modifying g.proj in this way instead of requiring
the startup scripts to make some fake locations and WIND files to satify
g.proj?

To start from scratch with something other than the current working
directory, we'd need to replace this temporary GISRC file with whatever
directory is specified in the GUI startup, but this isn't too difficult.

Markus has produced a workaround in a bash script that is necessary because
of the way g.proj functions. It makes and erases temporary location, mapset,
and WIND files, and archives, replaces, and restores the .grassrc6
file--regardless of whether or not you have a valid location already in
existence. This worries me a bit as it makes more opportunities for
corruption in the .grassrc6 file or GISDBASE path if something goes wrong in
the process.

Michael

Hello Paul,

On Sun, Dec 17, 2006 at 07:42:16AM +0000, Paul Kelly wrote:

This would need quite a bit of re-engineering to fix in an elegant way,
definitely worth thinking about though IMHO. For now, looks like a
complicated workaround is required. :frowning:

FWIW, and if I understand correctly the problem, now when I set a new
system, a template LOCATION is created to avoid the chicken and egg
problem. This serves multiple purposes:

1) This is a simple example that can be used for a quick demo/teaching (this
is not Spearfish);

2) This holds informations to verify that the current layout of the data
matches the library (organization of the GISDATABASE in KerGIS may vary
from version to version);

3) There is always a LOCATION/MAPSET to create other ones.

Actually, in PostgreSQL for example, you always derive a new database
from a template[12] one.

This ensures integrity and symetry of the commands (no need to handle
the special case of ab ovo).

HTH
--
Thierry Laronde (Alceste) <tlaronde +AT+ polynum +dot+ com>
                 http://www.kergis.com/
Key fingerprint = 0FF7 E906 FBAF FE95 FD89 250D 52B1 AE95 6006 F40C

Paul Kelly wrote:

I've re-organised g.proj a bit so it doesn't read the region and
projection from the current location unless it has to. But the problem
remains, in three places:
(a) G_gisint()
(b) G_tempfile()
(c) G__put_window()/G__fopen_new()

(a) All modules have to call G_gisinit() at the start, and among other
things it checks for a valid current location and mapset. However the case
we're discussing is a rare example of where that isn't needed. Most of the
rest of what G_gisinit() does (from a quick skimming over the code) seems
related to raster modules and might possibly be possibly avoided?

Note that there is also G_no_gisinit(), which doesn't check for a
valid location/mapset.

This is probably more appropriate for a module which needs to run
without a valid mapset.

I do wonder whether it's appropriate for this functionality to be
bundled into g.proj rather than being a separate module.

(b) If the call to G_gisinit() is simply commented out, the next problem
is G_tempfile() [deep within GRASS gproj library] which tries to create a
tempfile in the current mapset as far as I remember - is this a good/bad
idea? Certainly bad if you don't have a current mapset.

G_tempfile() uses the current mapset so that "draft" output maps can
be moved (with either link()+remove() or rename()) into their final
location upon closure. This requires them to reside on the same
filesystem (partition) as the mapset directory (i.e. you can't use
/tmp or $TMPDIR).

I suggest:

1. Rename the existing G_tempfile() function.

2. Add a new G_tempfile() which uses the /tmp/grass6-<user>-<pid>
directory (or possibly $TMPDIR) instead.

3. Change close_new() (lib/gis/closecell.c, used by G_close_cell() and
G_unopen_cell()) to use the existing (renamed) function. Ditto for
anything else which creates temporary files with the intention of
moving them (if there is anything else).

(c) Hard-coding the tempfile path in lib/proj/datum.c instead of calling
G_tempfile() gets as far as writing out the new WIND and DEFAULT_WIND.
This is done by a call to G__put_window() in G__make_location().

G__fopen_new(), which is called by G__put_window(), makes a call to
G__check_gisinit() which fails [because we haven't called G_gisinit()].

G_no_gisinit() will suffice to keep G__check_gisinit() happy.

Note that the only thing that G__check_gisinit() actually verifies is
that certain fields in the G__ structure have been initialised
(specifically: fp_type, fp_nbytes, auto_mask), and that the mask
buffer has been allocated.

Unlike G_gisinit(), G_no_gisinit() doesn't set the program name, which
is probably a (design) bug, as G_fatal_error() etc assume that this
has been set.

This would need quite a bit of re-engineering to fix in an elegant way,
definitely worth thinking about though IMHO. For now, looks like a
complicated workaround is required. :frowning:

The G_check_gisinit() issue is solved by G_no_gisinit().

The default region is still an issue also, as Helena said. I know I should
copy some code from r.in.gdal and v.in.ogr to g.proj to handle this as far
as possible (i.e. match the default region in the new location to the
georeferenced file - better than doing nothing). When there's some more
time can maybe do that. And it will still be a problem with creating from
EPSG code as the user is not forced or even reminded to set the region.

Maybe lib/gis/gisinit.c needs another function which forces
initialisation, creating a temporary gisdbase/location/mapset,
including WIND and ../PERMANENT/DEFAULT_WIND files.

--
Glynn Clements <glynn@gclements.plus.com>

Should I wait a bit then to see if this can be resolved in g.proj and not
implment a TclTk workaround yet?

Michael

On 12/17/06 8:00 AM, "Glynn Clements" <glynn@gclements.plus.com> wrote:

Paul Kelly wrote:

I've re-organised g.proj a bit so it doesn't read the region and
projection from the current location unless it has to. But the problem
remains, in three places:
(a) G_gisint()
(b) G_tempfile()
(c) G__put_window()/G__fopen_new()

(a) All modules have to call G_gisinit() at the start, and among other
things it checks for a valid current location and mapset. However the case
we're discussing is a rare example of where that isn't needed. Most of the
rest of what G_gisinit() does (from a quick skimming over the code) seems
related to raster modules and might possibly be possibly avoided?

Note that there is also G_no_gisinit(), which doesn't check for a
valid location/mapset.

This is probably more appropriate for a module which needs to run
without a valid mapset.

I do wonder whether it's appropriate for this functionality to be
bundled into g.proj rather than being a separate module.

(b) If the call to G_gisinit() is simply commented out, the next problem
is G_tempfile() [deep within GRASS gproj library] which tries to create a
tempfile in the current mapset as far as I remember - is this a good/bad
idea? Certainly bad if you don't have a current mapset.

G_tempfile() uses the current mapset so that "draft" output maps can
be moved (with either link()+remove() or rename()) into their final
location upon closure. This requires them to reside on the same
filesystem (partition) as the mapset directory (i.e. you can't use
/tmp or $TMPDIR).

I suggest:

1. Rename the existing G_tempfile() function.

2. Add a new G_tempfile() which uses the /tmp/grass6-<user>-<pid>
directory (or possibly $TMPDIR) instead.

3. Change close_new() (lib/gis/closecell.c, used by G_close_cell() and
G_unopen_cell()) to use the existing (renamed) function. Ditto for
anything else which creates temporary files with the intention of
moving them (if there is anything else).

(c) Hard-coding the tempfile path in lib/proj/datum.c instead of calling
G_tempfile() gets as far as writing out the new WIND and DEFAULT_WIND.
This is done by a call to G__put_window() in G__make_location().

G__fopen_new(), which is called by G__put_window(), makes a call to
G__check_gisinit() which fails [because we haven't called G_gisinit()].

G_no_gisinit() will suffice to keep G__check_gisinit() happy.

Note that the only thing that G__check_gisinit() actually verifies is
that certain fields in the G__ structure have been initialised
(specifically: fp_type, fp_nbytes, auto_mask), and that the mask
buffer has been allocated.

Unlike G_gisinit(), G_no_gisinit() doesn't set the program name, which
is probably a (design) bug, as G_fatal_error() etc assume that this
has been set.

This would need quite a bit of re-engineering to fix in an elegant way,
definitely worth thinking about though IMHO. For now, looks like a
complicated workaround is required. :frowning:

The G_check_gisinit() issue is solved by G_no_gisinit().

The default region is still an issue also, as Helena said. I know I should
copy some code from r.in.gdal and v.in.ogr to g.proj to handle this as far
as possible (i.e. match the default region in the new location to the
georeferenced file - better than doing nothing). When there's some more
time can maybe do that. And it will still be a problem with creating from
EPSG code as the user is not forced or even reminded to set the region.

Maybe lib/gis/gisinit.c needs another function which forces
initialisation, creating a temporary gisdbase/location/mapset,
including WIND and ../PERMANENT/DEFAULT_WIND files.

__________________________________________
Michael Barton, Professor of Anthropology
School of Human Evolution & Social Change
Center for Social Dynamics & Complexity
Arizona State University

phone: 480-965-6213
fax: 480-965-7671
www: http://www.public.asu.edu/~cmbarton

Michael Barton wrote:

Should I wait a bit then to see if this can be resolved in g.proj and not
implment a TclTk workaround yet?

If you're talking about creating a dummy location/mapset, I'd rather
see one function in libgis to do this than having essentially the same
code duplicated across various modules and scripts.

--
Glynn Clements <glynn@gclements.plus.com>

I agree. So I'll hold off on revamping this part of epsg_option.tcl for a
bit.

On 12/17/06 9:48 AM, "Glynn Clements" <glynn@gclements.plus.com> wrote:

Michael Barton wrote:

Should I wait a bit then to see if this can be resolved in g.proj and not
implment a TclTk workaround yet?

If you're talking about creating a dummy location/mapset, I'd rather
see one function in libgis to do this than having essentially the same
code duplicated across various modules and scripts.

__________________________________________
Michael Barton, Professor of Anthropology
School of Human Evolution & Social Change
Center for Social Dynamics & Complexity
Arizona State University

phone: 480-965-6213
fax: 480-965-7671
www: http://www.public.asu.edu/~cmbarton

On Sun, 17 Dec 2006, Glynn Clements wrote:

(a) All modules have to call G_gisinit() at the start, and among other
things it checks for a valid current location and mapset. However the case
we're discussing is a rare example of where that isn't needed. Most of the
rest of what G_gisinit() does (from a quick skimming over the code) seems
related to raster modules and might possibly be possibly avoided?

Note that there is also G_no_gisinit(), which doesn't check for a
valid location/mapset.

This is probably more appropriate for a module which needs to run
without a valid mapset.

Of course. I did see G_no_gisinit() while browsing libgis but it just didn't occur to me that it was what I needed - I couldn't quite see what its purpose was.

I do wonder whether it's appropriate for this functionality to be
bundled into g.proj rather than being a separate module.

Yes I see where you're coming from, although the actual location-creation code in g.proj really just amounts to a call to G__make_location() : the vast bulk of the g.proj code relates to input and output of co-ordinate system descriptions from and to various sources and sinks - and in this sense the PROJ_INFO, PROJ_UNITS, WIND and DEFAULT_WIND of a new location can be considered just another output format for the co-ordinate system. So the functionality fits in here due to convenience of programming more than anything else.

(b) If the call to G_gisinit() is simply commented out, the next problem
is G_tempfile() [deep within GRASS gproj library] which tries to create a
tempfile in the current mapset as far as I remember - is this a good/bad
idea? Certainly bad if you don't have a current mapset.

G_tempfile() uses the current mapset so that "draft" output maps can
be moved (with either link()+remove() or rename()) into their final
location upon closure. This requires them to reside on the same
filesystem (partition) as the mapset directory (i.e. you can't use
/tmp or $TMPDIR).

I suggest:

1. Rename the existing G_tempfile() function.

2. Add a new G_tempfile() which uses the /tmp/grass6-<user>-<pid>
directory (or possibly $TMPDIR) instead.

Right. It was mentioned before that tempnam() could be used - although I see on Linux that warns that it shouldn't---but I don't understand why. The /tmp/grass6-<user>-<pid> location is tied in tightly to the concurrent session stuff in Init.sh isn't it---I'd rather not get into complications of relying on this if possible because it reduces the simplicity of only having to set a few environment variables (GISBASE and GISRC for GRASS to run). E.g. in the experimental Windows version of Init.sh (init.bat) I have not even bothered implementing concurrent sessions yet.

tempnam() uses $TMPDIR if set, which means it seems to work on Windows, or a specified directory as the second choice. This seems to work OK:

char *G_tempfile_in_mapset(void)
{
     return G__tempfile(getpid());
}

char *G_tempfile(void)
{
     return G_convert_dirseps_to_host( tempnam("/tmp", "grass") );
}

but I can see deleting of temporary files after a session being a problem. The prefix for the temp files (in this case "grass") can be at most 5 characters with tempnam() and I don't think it would be desirable to go looking in the temporary directory and deleting any files that started with that at the end of a session. Using the per-session directory would of course get round that problem, so maybe it is worth a second thought...

The other option is to keep a lookout after changing it for badly-behaved modules that don't delete their temp files. Also I don't think it's unreasonable for temp files to be left undeleted if a module crashes? Might be useful for debugging even.

3. Change close_new() (lib/gis/closecell.c, used by G_close_cell() and
G_unopen_cell()) to use the existing (renamed) function. Ditto for
anything else which creates temporary files with the intention of
moving them (if there is anything else).

opencell.c seemed to be the file that actually required changing? But only two places to change it and very easy.

(c) Hard-coding the tempfile path in lib/proj/datum.c instead of calling
G_tempfile() gets as far as writing out the new WIND and DEFAULT_WIND.
This is done by a call to G__put_window() in G__make_location().

G__fopen_new(), which is called by G__put_window(), makes a call to
G__check_gisinit() which fails [because we haven't called G_gisinit()].

G_no_gisinit() will suffice to keep G__check_gisinit() happy.

Yes - can confirm this. Works well now.

Will not commit any G_tempfile() changes in the near future though until the best option becomes clearer.

Paul

Paul Kelly wrote:

The other option is to keep a lookout after changing it for
badly-behaved modules that don't delete their temp files. Also I
don't think it's unreasonable for temp files to be left undeleted if
a module crashes?

While not important for native windows, e.g. d.text (and d.graph?) can
keep tmp files around so the command will survive d.redraw (if input was
piped from stdin). These are then removed when the .tmp dir is flushed
when GRASS exits/restarts.

Generally tmp files should be removed, but enforcing it is a pain for
debugging and development.

Hamish

Paul Kelly wrote:

>> (b) If the call to G_gisinit() is simply commented out, the next problem
>> is G_tempfile() [deep within GRASS gproj library] which tries to create a
>> tempfile in the current mapset as far as I remember - is this a good/bad
>> idea? Certainly bad if you don't have a current mapset.
>
> G_tempfile() uses the current mapset so that "draft" output maps can
> be moved (with either link()+remove() or rename()) into their final
> location upon closure. This requires them to reside on the same
> filesystem (partition) as the mapset directory (i.e. you can't use
> /tmp or $TMPDIR).
>
> I suggest:
>
> 1. Rename the existing G_tempfile() function.
>
> 2. Add a new G_tempfile() which uses the /tmp/grass6-<user>-<pid>
> directory (or possibly $TMPDIR) instead.

Right. It was mentioned before that tempnam() could be used - although I
see on Linux that warns that it shouldn't---but I don't understand why.

Race conditions.

Because tempnam() doesn't create the file, it's possible for another
user's process to create a file (or, more significantly, a link to an
existing file) with that name before your process does. This is
considered a potential security vulnerability, as an attacker can
trick a user into creating or modifying files which the attacker
wouldn't have access to.

mkstemp() and tmpfile() both attempt to create the file, and only
return once they have successfully created a new file.

The /tmp/grass6-<user>-<pid> location is tied in tightly to the concurrent
session stuff in Init.sh isn't it---I'd rather not get into complications
of relying on this if possible because it reduces the simplicity of only
having to set a few environment variables (GISBASE and GISRC for GRASS to
run). E.g. in the experimental Windows version of Init.sh (init.bat) I
have not even bothered implementing concurrent sessions yet.

tempnam() uses $TMPDIR if set, which means it seems to work on Windows, or
a specified directory as the second choice. This seems to work OK:

char *G_tempfile_in_mapset(void)
{
     return G__tempfile(getpid());
}

char *G_tempfile(void)
{
     return G_convert_dirseps_to_host( tempnam("/tmp", "grass") );
}

but I can see deleting of temporary files after a session being a problem.
The prefix for the temp files (in this case "grass") can be at most 5
characters with tempnam() and I don't think it would be desirable to go
looking in the temporary directory and deleting any files that started
with that at the end of a session. Using the per-session directory would
of course get round that problem, so maybe it is worth a second thought...

Apart from anything else, any security issues can be eliminated by
ensuring that the per-session directory is mode 0700.

The other option is to keep a lookout after changing it for badly-behaved
modules that don't delete their temp files. Also I don't think it's
unreasonable for temp files to be left undeleted if a module crashes?
Might be useful for debugging even.

Apart from anything else, the effort involved in cleaning up upon
G_fatal_error() is too much. At least, it's not practical to do it
module-by-module. You need a global mechanism, e.g. ensuring temp
files always contain the PID of their creator, so that G_fatal_error()
can just delete every temp file containing the current PID.

That still doesn't allow for crashes, but safely recovering from
SIGSEGV is next to impossible. If you suspect that application memory
has been corrupted, you certainly don't want to be calling remove()
etc on filenames which are derived from the contents of application
memory.

[Even constructing a filename from a combination of string literals
(which are read-only) and kernel data (e.g. getpid()) isn't as safe as
it looks, as references to functions in shared libraries may have been
corrupted, meaning that a getpid() call might invoke something other
than the actual "getpid" function.]

> 3. Change close_new() (lib/gis/closecell.c, used by G_close_cell() and
> G_unopen_cell()) to use the existing (renamed) function. Ditto for
> anything else which creates temporary files with the intention of
> moving them (if there is anything else).

opencell.c seemed to be the file that actually required changing?

Yeah; opencell.c creates the file in that way so that closecell.c
works.

But only two places to change it and very easy.

That's assuming that other subsystems don't do the same thing.

Ideally, a lot more code should be doing this. At present, it's only
the actual cell/fcell file which is replaced atomically; other files
(e.g. cellhd) are modified in-place.

If we switched the layout from <element>/<map_name> to
<map_name>/<element> (i.e. one directory for each map), the obvious
approach would be to rename the entire directory rather than
individual files.

--
Glynn Clements <glynn@gclements.plus.com>

On Wed, 20 Dec 2006, Hamish wrote:

Paul Kelly wrote:

The other option is to keep a lookout after changing it for
badly-behaved modules that don't delete their temp files. Also I
don't think it's unreasonable for temp files to be left undeleted if
a module crashes?

While not important for native windows, e.g. d.text (and d.graph?) can
keep tmp files around so the command will survive d.redraw (if input was
piped from stdin). These are then removed when the .tmp dir is flushed
when GRASS exits/restarts.

Hmm, that sounds like a definite issue. Perhaps those modules could be changed to use the new G_tempfile_in_mapset() or whatever we call it? I just thought of another reason not to put the tempfiles in the session directory---if the GRASS libraries are being called from e.g. QGIS or GDAL to read a GRASS file then there won't be an existing GRASS session so that wouldn't work.

Generally tmp files should be removed, but enforcing it is a pain for
debugging and development.

Modules that require temp files to stick around should specifically create them in the current mapset; others should carry on using G_tempfile(). How does that sound.

Paul

On Wed, 20 Dec 2006, Glynn Clements wrote:

Right. It was mentioned before that tempnam() could be used - although I
see on Linux that warns that it shouldn't---but I don't understand why.

Race conditions.

Because tempnam() doesn't create the file, it's possible for another
user's process to create a file (or, more significantly, a link to an
existing file) with that name before your process does. This is
considered a potential security vulnerability, as an attacker can
trick a user into creating or modifying files which the attacker
wouldn't have access to.

Ah OK. But the current G_tempfile() doesn't attempt to create the file either (although interestingly, g.tempfile does) so we wouldn't be losing or gaining anything there IIUC?

Paul Kelly wrote:

>> Right. It was mentioned before that tempnam() could be used - although I
>> see on Linux that warns that it shouldn't---but I don't understand why.
>
> Race conditions.
>
> Because tempnam() doesn't create the file, it's possible for another
> user's process to create a file (or, more significantly, a link to an
> existing file) with that name before your process does. This is
> considered a potential security vulnerability, as an attacker can
> trick a user into creating or modifying files which the attacker
> wouldn't have access to.

Ah OK. But the current G_tempfile() doesn't attempt to create the file
either (although interestingly, g.tempfile does) so we wouldn't be losing
or gaining anything there IIUC?

tempnam() might end up creating the files in a world-writable
directory. Even if you specify a directory which is known to be safe,
$TMPDIR takes precedence.

Personally, I consider it the user's responsibility not to point
$TMPDIR at a world-writable directory.

--
Glynn Clements <glynn@gclements.plus.com>