Index: /trunk/PS-IPP-Config/lib/PS/IPP/Config.pm
===================================================================
--- /trunk/PS-IPP-Config/lib/PS/IPP/Config.pm	(revision 16610)
+++ /trunk/PS-IPP-Config/lib/PS/IPP/Config.pm	(revision 16611)
@@ -1,5 +1,5 @@
 # Copyright (c) 2006  Paul Price, Joshua Hoblitt
 #
-# $Id: Config.pm,v 1.75 2008-02-06 02:05:44 price Exp $
+# $Id: Config.pm,v 1.76 2008-02-22 20:20:37 eugene Exp $
 
 package PS::IPP::Config;
@@ -62,5 +62,5 @@
     my $name;			# Name of ipprc file
     GetOptions( 'site=s' => \$name );
-    $name = $ENV{PS_SITE} if not defined $name;
+    $name = $ENV{IPPRC} if not defined $name;
     if (not defined $name and defined $ENV{HOME}) {
 	$name = $ENV{HOME} . '/.ipprc';
@@ -90,7 +90,12 @@
 	filerules => undef,	# File rules from the camera configuration
 	rejection => undef,	# Rejection data
-	_ipprc => $mdc		# The parsed configuration
+	_userConfig => $mdc,	# The top-level user configuration
+	_siteConfig => undef,	# The site configuration (from _userConfig)
+	_systemConfig => undef	# The system configuration (from _userConfig)
 	};
     bless $self, $class;
+
+    $self->load_site();
+    $self->load_system();
 
     $self->define_camera($camera) if defined $camera;
@@ -140,4 +145,80 @@
 }
 
+# Load the site config file
+sub load_site
+{
+    my $self = shift;		# Configuration object
+
+    my $i = 0;
+
+    unless (defined $self) {
+	carp "Programming error";
+	exit($PS_EXIT_PROG_ERROR);
+    }
+
+    my $filename = metadataLookupStr($self->{_userConfig}, 'SITE'); # Site config file
+    unless (defined $filename) {
+	carp "Unable to find site configuration file\n";
+	exit($PS_EXIT_CONFIG_ERROR);
+    }
+
+    my $realfile = $self->_find_config($filename); # Resolved filename, after hunting the PATH
+
+    # Read the file
+    my $file;			# File handle
+    unless (open $file, $realfile) {
+	carp "Unable to open site configuration file $realfile: $!";
+	exit($PS_EXIT_CONFIG_ERROR);
+    }
+
+    my @contents = <$file>;
+    close $file;
+    $self->{_siteConfig} = $parser->parse( join '', @contents); # The parsed metadata config
+
+    unless (defined $self->{_siteConfig}) {
+	carp "Failure to parse the site configuration file $realfile";
+	exit($PS_EXIT_CONFIG_ERROR);
+    }
+
+    return $self;
+}
+
+# Load the system config file
+sub load_system
+{
+    my $self = shift;		# Configuration object
+
+    unless (defined $self) {
+	carp "Programming error";
+	exit($PS_EXIT_PROG_ERROR);
+    }
+
+    my $filename = metadataLookupStr($self->{_userConfig}, 'SYSTEM'); # System config file
+    unless (defined $filename) {
+	carp "Unable to find system configuration file\n";
+	exit($PS_EXIT_CONFIG_ERROR);
+    }
+
+    my $realfile = $self->_find_config($filename); # Resolved filename, after hunting the PATH
+
+    # Read the file
+    my $file;			# File handle
+    unless (open $file, $realfile) {
+	carp "Unable to open system configuration file $realfile: $!";
+	exit($PS_EXIT_CONFIG_ERROR);
+    }
+    my @contents = <$file>;
+    close $file;
+    $self->{_systemConfig} = $parser->parse( join '', @contents); # The parsed metadata config
+
+    unless (defined $self->{_systemConfig}) {
+	carp "Failure to define system configuration";
+	exit($PS_EXIT_CONFIG_ERROR);
+    }
+
+    # XXX why isn't just $self being returned here? -JH
+    return $self;
+}
+
 # Define a camera to use
 sub define_camera
@@ -151,5 +232,5 @@
     }
 
-    my $camera_list = metadataLookupMD($self->{_ipprc}, 'CAMERAS'); # List of cameras
+    my $camera_list = metadataLookupMD($self->{_systemConfig}, 'CAMERAS'); # List of cameras
     my $filename = metadataLookupStr($camera_list, $name); # Filename of camera configuration
     unless (defined $filename) {
@@ -233,5 +314,5 @@
     }
 
-    my $path_list = metadataLookupMD($self->{_ipprc}, 'DATAPATH'); # List of paths
+    my $path_list = metadataLookupMD($self->{_siteConfig}, 'DATAPATH'); # List of paths
     my $pathname = metadataLookupStr($path_list, $name); # Path of interest
     unless (defined $pathname) {
@@ -258,5 +339,5 @@
     return 1 if defined $self->{nebulous}; # Already started
 
-    my $server = metadataLookupStr( $self->{_ipprc}, 'NEB_SERVER' ); # Nebulous server
+    my $server = metadataLookupStr( $self->{_siteConfig}, 'NEB_SERVER' ); # Nebulous server
     unless (defined $server) {
 	carp "Unable to find NEB_SERVER in camera configuration file.";
@@ -561,5 +642,5 @@
     my @dirs = File::Spec->splitdir( $name );
     
-    my $path_list = metadataLookupMD($self->{_ipprc}, 'DATAPATH'); # List of paths
+    my $path_list = metadataLookupMD($self->{_siteConfig}, 'DATAPATH'); # List of paths
     my $best_path;
     my $best_name;
@@ -790,10 +871,10 @@
     my $tess_id = shift;	# Tessellation identifier
 
-    unless (defined $self and defined $self->{_ipprc} and defined $tess_id) {
-	carp "Programming error";
-	exit($PS_EXIT_PROG_ERROR);
-    }
-
-    my $tessellations = metadataLookupMD($self->{_ipprc}, 'TESSELLATIONS'); # Tessellations
+    unless (defined $self and defined $self->{_siteConfig} and defined $tess_id) {
+	carp "Programming error";
+	exit($PS_EXIT_PROG_ERROR);
+    }
+
+    my $tessellations = metadataLookupMD($self->{_siteConfig}, 'TESSELLATIONS'); # Tessellations
     unless (defined $tessellations) {
 	carp "Can't find TESSELLATIONS in site configuration.\n";
@@ -817,4 +898,70 @@
 }
 
+
+# Return catdir for the dvo db, from DVO.CATDIRS within the site configuration
+sub dvo_catdir
+{
+    my $self = shift;	# Configuration object
+    my $dvodb = shift;	# DVO db identifier
+
+    unless (defined $self and defined $self->{_siteConfig} and defined $dvodb) {
+	carp "Programming error";
+	exit($PS_EXIT_PROG_ERROR);
+    }
+
+    my $catdirs = metadataLookupMD($self->{_siteConfig}, 'DVO.CATDIRS'); # Tessellations
+    unless (defined $catdirs) {
+	carp "Can't find DVO.CATDIRS in site configuration.\n";
+	exit($PS_EXIT_CONFIG_ERROR);
+    }
+
+    my $catdir = metadataLookupStr($catdirs, $dvodb);
+    unless (defined $catdir) {
+	carp "Can't find dvodb identifier $dvodb in DVO.CATDIR in site configuration.\n";
+	exit($PS_EXIT_CONFIG_ERROR);
+    }
+
+    ### Because DVO doesn't use psModules, it doesn't understand Nebulous --- check
+    my $scheme = file_scheme($catdir); # The scheme, e.g., file, path, neb
+    if (defined $scheme and lc($scheme) eq 'neb') {
+	carp "DVO catdir $dvodb refers to a Nebulous path: $catdir\n";
+	exit($PS_EXIT_CONFIG_ERROR);
+    }
+
+    return $catdir
+}
+
+# Return catdir for the psastro reference, from PSASTRO.CATDIRS within the site configuration
+sub psastro_catdir
+{
+    my $self = shift;	# Configuration object
+    my $dvodb = shift;	# DVO db identifier
+
+    unless (defined $self and defined $self->{_siteConfig} and defined $dvodb) {
+	carp "Programming error";
+	exit($PS_EXIT_PROG_ERROR);
+    }
+
+    my $catdirs = metadataLookupMD($self->{_siteConfig}, 'PSASTRO.CATDIRS'); # Tessellations
+    unless (defined $catdirs) {
+	carp "Can't find PSASTRO.CATDIRS in site configuration.\n";
+	exit($PS_EXIT_CONFIG_ERROR);
+    }
+
+    my $catdir = metadataLookupStr($catdirs, $dvodb);
+    unless (defined $catdir) {
+	carp "Can't find dvodb identifier $dvodb in PSASTRO.CATDIR in site configuration.\n";
+	exit($PS_EXIT_CONFIG_ERROR);
+    }
+
+    ### Because DVO doesn't use psModules, it doesn't understand Nebulous --- check
+    my $scheme = file_scheme($catdir); # The scheme, e.g., file, path, neb
+    if (defined $scheme and lc($scheme) eq 'neb') {
+	carp "PSASTRO catdir $dvodb refers to a Nebulous path: $catdir\n";
+	exit($PS_EXIT_CONFIG_ERROR);
+    }
+
+    return $catdir
+}
 
 # Return the DVO.CAMERADIR in the camera configuration
Index: /trunk/ippTools/src/pxadminConfig.c
===================================================================
--- /trunk/ippTools/src/pxadminConfig.c	(revision 16610)
+++ /trunk/ippTools/src/pxadminConfig.c	(revision 16611)
@@ -35,8 +35,9 @@
     fprintf (stderr, " [mode] : -create | -delete\n\n");
 
-    psString dbServer = psMetadataLookupStr(&status, config->modules->site, "DBSERVER");
-    psString dbUsername = psMetadataLookupStr(&status, config->modules->site, "DBUSER");
-    psString dbName = psMetadataLookupStr(&status, config->modules->site, "DBNAME");
-    psS32 dbPort = psMetadataLookupS32(&status, config->modules->site, "DBPORT");
+    // XXX EAM : this should be done with psDB function calls
+    psString dbServer = psMetadataLookupStr(&status, config->modules->complete, "DBSERVER");
+    psString dbUsername = psMetadataLookupStr(&status, config->modules->complete, "DBUSER");
+    psString dbName = psMetadataLookupStr(&status, config->modules->complete, "DBNAME");
+    psS32 dbPort = psMetadataLookupS32(&status, config->modules->complete, "DBPORT");
 
     fprintf (stderr, "connecting to %s as %s (port %d)\n", dbServer, dbUsername, dbPort);
Index: /trunk/ippTools/src/pxtables.c
===================================================================
--- /trunk/ippTools/src/pxtables.c	(revision 16610)
+++ /trunk/ippTools/src/pxtables.c	(revision 16611)
@@ -116,5 +116,6 @@
     PS_ASSERT_PTR_NON_NULL(config, false);
 
-    psString dbName = psMetadataLookupStr(&status, config->modules->site, "DBNAME");
+    // XXX use the values defined in config->dbh?
+    psString dbName = psMetadataLookupStr(&status, config->modules->complete, "DBNAME");
 
     fprintf (stdout, "*** delete the chip tables from database %s? ***\n", dbName);
@@ -136,5 +137,5 @@
     {
         bool status;
-        psString dbPassword = psMetadataLookupStr(&status, config->modules->site, "DBPASSWORD");
+        psString dbPassword = psMetadataLookupStr(&status, config->modules->complete, "DBPASSWORD");
         if (strcmp (answer, dbPassword)) {
             psError(PS_ERR_UNKNOWN, true, "tables NOT deleleted");
Index: /trunk/ippconfig/.cvsignore
===================================================================
--- /trunk/ippconfig/.cvsignore	(revision 16610)
+++ /trunk/ippconfig/.cvsignore	(revision 16611)
@@ -12,2 +12,3 @@
 missing
 ipprc.config
+site.config
Index: /trunk/ippconfig/Makefile.am
===================================================================
--- /trunk/ippconfig/Makefile.am	(revision 16610)
+++ /trunk/ippconfig/Makefile.am	(revision 16611)
@@ -15,4 +15,6 @@
 
 install_files = \
+	site.config \
+	system.config \
 	GSCregions.tbl \
 	dvo.photcodes
Index: /trunk/ippconfig/ipprc.config.in
===================================================================
--- /trunk/ippconfig/ipprc.config.in	(revision 16610)
+++ /trunk/ippconfig/ipprc.config.in	(revision 16611)
@@ -1,110 +1,24 @@
-### Example .ipprc file
+## Example .ipprc file : copy to your home directory and modify as desired
 
 # Default search path for configuration files (add $HOME if desired)
+# Note: do not include $HOME in the distributed copy used by ippMonitor
 # PATH            STR     @pkgdatadir@:$HOME/.ipp:.
-PATH            STR     @pkgdatadir@:.
-# note: do not include $HOME in the distributed copy used by ippMonitor
+PATH              STR     @pkgdatadir@:.
 
-# place your data directories here and refer to as path://PATH/remainder
-DATAPATH	METADATA
-	ALALA	STR	/data/alala.0/
-	ISP	STR	/data/ipp000.0/isp
-	ISP_V2	STR	/data/ipp000.0/isp_v2
-	ISP_V3	STR	/data/ipp000.0/isp_v3
-	ISP_TEST STR	/data/ipp000.0/isp_test
-	EAMTEST STR     /data/alala.0/eugene/swtests/simtest/raw
-	EAMWORK STR     /data/alala.0/eugene/swtests/simtest/work
-	CFH12K  STR     /data/ipp003.0/eugene/cfh12k
-        DATA1   STR     /data/alala.0/
-        SRESS1  STR     /data/ipp003.0/SM_W/sm030927/
-        SRESSWORK STR   /data/ipp003.0/rodney/sresswork
-        SIMTEST STR     /data/po05.0/rodney/sim/
-        SIMWORK STR     /data/po05.0/rodney/simwork/
-	MOPS	STR	/data/ipp002.0/MOPS/
-	TALCS	STR	/data/ipp003.0/TALCS/
-END
+# load the site-specific information from here
+SITE              STR     site.config
 
-NEB_SERVER	STR	http://alala:80/nebulous	# Nebulous server
+# load the system configuration information from here
+SYSTEM            STR     system.config
 
-### Database configuration
-DBSERVER	STR	ipp000			# Database host name (for psDBInit)
-DBNAME		STR	ipp			# Database name (for psDBInit)
-DBUSER		STR	XXX			# Database user name (for psDBInit)
-DBPASSWORD	STR	XXX			# Database password (for psDBInit)
-
-### Setups for each camera system
-CAMERAS		METADATA
-	MEGACAM			STR	megacam/camera.config
-	CFH12K			STR	cfh12k/camera.config
-	ISP-Apogee     		STR	isp/camera.config
-	CTIO_MOSAIC2		STR	ctio_mosaic2/camera.config	# CTIO MOSAIC2 camera, for ESSENCE
-	SDSS			STR	sdss/camera.config		# Sloan Digital Sky Survey
-	GPC1			STR	gpc1/camera.config
-	ESOWFI			STR	esowfi/camera.config		# ESO Wide-Field Imager
-#	UCAM			STR	ucam/camera.config
-#	LRIS_BLUE		STR	lris_blue/camera.config
-#	TC3			STR	tc3/camera.config		# Pan-STARRS Test Camera III
-#	LRIS_RED		STR	lris_red/camera.config
-	SIMMOSAIC		STR	simmosaic/camera.config		# Simulated mosaic, for testing
-	SIMTEST			STR	simtest/camera.config
-	SIMPLE			STR	simple/camera.config
-END
-
-### camera names as expected by DVO
-DVO.CAMERAS		METADATA
-	MEGACAM			STR	megacam
-	CFH12K			STR	cfh12k
-	ISP-Apogee     		STR	isp
-	CTIO_MOSAIC2		STR	ctio_mosaic2
-	SDSS			STR	sdss
-	GPC1			STR	gpc1
-	ESOWFI			STR	esowfi
-#	UCAM			STR	ucam
-#	TC3			STR	tc3
-#	LRIS_BLUE		STR	lris_blue
-#	LRIS_RED		STR	lris_red
-	SIMMOSAIC		STR	simmosaic
-	SIMTEST			STR	simtest
-	SIMPLE			STR	simple
-END
-
-### psLib setup
-#TIME		STR	/home/mithrandir/price/pan-starrs/jhroot/i686-pc-linux-gnu/etc/pslib/psTime.config	# Time configuration file
+# logging verbosity levels
 LOGLEVEL	S32	9			# Logging level; 3=INFO
 LOGFORMAT	STR	THLNM			# Log format
 LOGDEST		STR	STDERR			# Log destination
 TRACEDEST	STR	STDERR			# Trace destination
+
+# place default trace lines here
 TRACE		METADATA			# Trace levels
-	err		S32	10
-# place default trace lines here
-# example: 
-# psLib.db S32	10
+  err		S32	10
+# psLib.db      S32	10
 END
-
-RECIPES		METADATA		# Site-level recipes
-	MASKS		STR		recipes/masks.config	# Mask values
-	REJECTIONS	STR		recipes/rejections.config # Rejection for detrend creation
-	PPIMAGE		STR		recipes/ppImage.config  # Image reduction
-	PPMERGE		STR		recipes/ppMerge.config	# Image combination
- 	PPSTATS		STR		recipes/ppStats.config	# Image statistics
-	PSPHOT		STR     	recipes/psphot.config	# Photometry
-	PSASTRO		STR		recipes/psastro.config	# Astrometry
-	PPSTACK		STR		recipes/ppStack.config	# Combination
-	PSWARP		STR		recipes/pswarp.config   # Warping
-	PPSIM		STR		recipes/ppSim.config	# Simulations
-	PPSUB		STR		recipes/ppSub.config	# Subtraction
-END
-
-# Header keywords for skycell concepts; required because DVO doesn't read HIERARCH
-SKYCELLS	METADATA
-	FPA.TIME	STR	MJD-OBS
-	CELL.TIME	STR	MJD-OBS
-	FPA.EXPOSURE	STR	EXPTIME
-	CELL.EXPOSURE	STR	EXPTIME
-	FPA.AIRMASS	STR	AIRMASS
-END
-
-# List of tessellations, and their DVO CATDIR
-TESSELLATIONS	METADATA
-	MOPS		STR	path://MOPS/skycells/
-END
Index: /trunk/ippconfig/site.config.in
===================================================================
--- /trunk/ippconfig/site.config.in	(revision 16611)
+++ /trunk/ippconfig/site.config.in	(revision 16611)
@@ -0,0 +1,52 @@
+## Site Configuration : use this as an example for your installation
+## Supply locations of interest
+
+# place your data directories here and refer to as path://PATH/remainder
+DATAPATH	METADATA
+	ALALA	STR	/data/alala.0/
+	ISP	STR	/data/ipp000.0/isp
+	ISP_V2	STR	/data/ipp000.0/isp_v2
+	ISP_V3	STR	/data/ipp000.0/isp_v3
+	ISP_TEST STR	/data/ipp000.0/isp_test
+	EAMTEST STR     /data/alala.0/eugene/swtests/simtest/raw
+	EAMWORK STR     /data/alala.0/eugene/swtests/simtest/work
+	CFH12K  STR     /data/ipp003.0/eugene/cfh12k
+        DATA1   STR     /data/alala.0/
+        SRESS1  STR     /data/ipp003.0/SM_W/sm030927/
+        SRESSWORK STR   /data/ipp003.0/rodney/sresswork
+        SIMTEST STR     /data/po05.0/rodney/sim/
+        SIMWORK STR     /data/po05.0/rodney/simwork/
+	MOPS	STR	/data/ipp002.0/MOPS/
+	TALCS	STR	/data/ipp003.0/TALCS/
+END
+
+# List of tessellations, and their DVO CATDIR
+TESSELLATIONS	METADATA
+	MOPS		STR	path://MOPS/skycells/
+END
+
+# dvo databases used for output
+DVO.CATDIRS     METADATA
+	MOPS		STR	path://MOPS/catdir/
+END
+
+# dvo databases used for psastro reference
+PSASTRO.CATDIRS METADATA
+	2MASS		STR	/data/alala.0/ipp/ippRefs/catdir.2mass
+	SYNTH.GRIZY	STR	/data/alala.0/ipp/ippRefs/catdir.synth.grizy
+	SYNTH.BRIGHT	STR	/data/alala.0/ipp/ippRefs/catdir.synth.bright
+END
+
+# nebulous server
+NEB_SERVER	STR	http://alala:80/nebulous	# Nebulous server
+
+# Database configuration
+DBSERVER	STR	ipp000			# Database host name (for psDBInit)
+DBNAME		STR	XXX			# Database name (for psDBInit)
+DBUSER		STR	XXX			# Database user name (for psDBInit)
+DBPASSWORD	STR	XXX			# Database password (for psDBInit)
+
+# other basic values:
+# XXX is TIME still needed / used?
+# XXX use autoconf to put this in a known location?
+# TIME		STR	psTime.config	# Time configuration file
Index: /trunk/ippconfig/system.config
===================================================================
--- /trunk/ippconfig/system.config	(revision 16611)
+++ /trunk/ippconfig/system.config	(revision 16611)
@@ -0,0 +1,58 @@
+## system-wide options : these are concepts not specific to any camera or recipe
+
+### Setups for each camera system
+CAMERAS		METADATA
+	MEGACAM			STR	megacam/camera.config
+	CFH12K			STR	cfh12k/camera.config
+	ISP-Apogee     		STR	isp/camera.config
+	MOSAIC2 		STR	ctio_mosaic2/camera.config	# CTIO MOSAIC2 camera, for ESSENCE
+	SDSS			STR	sdss/camera.config		# Sloan Digital Sky Survey
+	GPC1			STR	gpc1/camera.config
+	ESOWFI			STR	esowfi/camera.config		# ESO Wide-Field Imager
+	SIMMOSAIC		STR	simmosaic/camera.config		# Simulated mosaic, for testing
+	SIMTEST			STR	simtest/camera.config
+	SIMPLE			STR	simple/camera.config
+END
+
+## directories exist for other camera, introduce if they are tested and working
+#	UCAM			STR	ucam/camera.config
+#	LRIS_BLUE		STR	lris_blue/camera.config
+#	TC3			STR	tc3/camera.config		# Pan-STARRS Test Camera III
+#	LRIS_RED		STR	lris_red/camera.config
+
+### camera names as expected by DVO
+DVO.CAMERAS		METADATA
+	MEGACAM			STR	megacam
+	CFH12K			STR	cfh12k
+	ISP-Apogee     		STR	isp
+	MOSAIC2 		STR	ctio_mosaic2
+	SDSS			STR	sdss
+	GPC1			STR	gpc1
+	ESOWFI			STR	esowfi
+	SIMMOSAIC		STR	simmosaic
+	SIMTEST			STR	simtest
+	SIMPLE			STR	simple
+END
+
+# Header keywords for skycell concepts; required because DVO doesn't read HIERARCH
+SKYCELLS	METADATA
+	FPA.TIME	STR	MJD-OBS
+	CELL.TIME	STR	MJD-OBS
+	FPA.EXPOSURE	STR	EXPTIME
+	CELL.EXPOSURE	STR	EXPTIME
+	FPA.AIRMASS	STR	AIRMASS
+END
+
+RECIPES		METADATA		# Site-level recipes
+	MASKS		STR		recipes/masks.config	# Mask values
+	REJECTIONS	STR		recipes/rejections.config # Rejection for detrend creation
+	PPIMAGE		STR		recipes/ppImage.config  # Image reduction
+	PPMERGE		STR		recipes/ppMerge.config	# Image combination
+ 	PPSTATS		STR		recipes/ppStats.config	# Image statistics
+	PSPHOT		STR     	recipes/psphot.config	# Photometry
+	PSASTRO		STR		recipes/psastro.config	# Astrometry
+	PPSTACK		STR		recipes/ppStack.config	# Combination
+	PSWARP		STR		recipes/pswarp.config   # Warping
+	PPSIM		STR		recipes/ppSim.config	# Simulations
+	PPSUB		STR		recipes/ppSub.config	# Subtraction
+END
Index: /trunk/ppConfigDump/src/ppConfigDump.c
===================================================================
--- /trunk/ppConfigDump/src/ppConfigDump.c	(revision 16610)
+++ /trunk/ppConfigDump/src/ppConfigDump.c	(revision 16611)
@@ -112,6 +112,15 @@
     }
 
+    const char *userName = psMetadataLookupStr(NULL, arguments, "-dump-user"); // User filename
+    dump(userName, "user configuration", config->user);
+
     const char *siteName = psMetadataLookupStr(NULL, arguments, "-dump-site"); // Site filename
     dump(siteName, "site configuration", config->site);
+
+    const char *systemName = psMetadataLookupStr(NULL, arguments, "-dump-system"); // System filename
+    dump(systemName, "system configuration", config->system);
+
+    const char *completeName = psMetadataLookupStr(NULL, arguments, "-dump-complete"); // Complete filename
+    dump(completeName, "complete configuration", config->complete);
 
     const char *camName = psMetadataLookupStr(NULL, arguments, "-dump-camera"); // Camera filename
Index: /trunk/psModules/src/camera/pmFPAfileDefine.c
===================================================================
--- /trunk/psModules/src/camera/pmFPAfileDefine.c	(revision 16610)
+++ /trunk/psModules/src/camera/pmFPAfileDefine.c	(revision 16611)
@@ -155,7 +155,7 @@
     } else {
         bool mdok;                      // Status of MD lookup
-        psMetadata *cameras = psMetadataLookupMetadata(&mdok, config->site, "CAMERAS"); // Known cameras
+        psMetadata *cameras = psMetadataLookupMetadata(&mdok, config->complete, "CAMERAS"); // Known cameras
         if (!mdok || !cameras) {
-            psError(PS_ERR_UNEXPECTED_NULL, true, "Unable to find CAMERAS in the site configuration.\n");
+            psError(PS_ERR_UNEXPECTED_NULL, true, "Unable to find CAMERAS in the system configuration.\n");
             return NULL;
         }
@@ -163,5 +163,5 @@
         if (!mdok || !camera) {
             psError(PS_ERR_UNEXPECTED_NULL, true, "Unable to find automatically generated "
-                    "camera configuration %s in site configuration.\n", cameraName);
+                    "camera configuration %s in system configuration.\n", cameraName);
             return NULL;
         }
Index: /trunk/psModules/src/config/pmConfig.c
===================================================================
--- /trunk/psModules/src/config/pmConfig.c	(revision 16610)
+++ /trunk/psModules/src/config/pmConfig.c	(revision 16611)
@@ -34,6 +34,6 @@
 #endif // ifdef HAVE_NEBCLIENT
 
-#define PS_SITE "PS_SITE"         // Name of the environment variable containing the site config file
-#define PS_DEFAULT_SITE ".ipprc"  // Default site config file
+#define IPPRC_ENV "IPPRC"        // Name of the environment variable containing the top-level config file
+#define IPPRC_FILE ".ipprc"      // Default top-level config file
 
 #define DEFAULT_LOG STDERR_FILENO       // Default file descriptor for log messages
@@ -52,5 +52,8 @@
 static void configFree(pmConfig *config)
 {
+    psFree(config->user);
     psFree(config->site);
+    psFree(config->system);
+    psFree(config->complete);
     psFree(config->files);
     psFree(config->camera);
@@ -80,5 +83,8 @@
 
     // Initialise
+    config->user = NULL;
     config->site = NULL;
+    config->system = NULL;
+    config->complete = NULL;
     config->camera = NULL;
     config->cameraName = NULL;
@@ -145,5 +151,7 @@
     PS_ASSERT_STRING_NON_EMPTY(path,);
 
-    pmConfigDone();
+    assert (configPath == NULL);
+    // XXX why was this being called?  pmConfigSet should only be called once...
+    // pmConfigDone();
 
     psList *list = psStringSplit(path, ":", false);
@@ -159,5 +167,7 @@
 void pmConfigDone(void)
 {
-    psFree(configPath);
+    if (configPath) { 
+	psFree(configPath);
+    }
     configPath = NULL;
 
@@ -380,25 +390,20 @@
     config->defaultRecipe = defaultRecipe;
 
-    //
-    // The following section of code attempts to determine which file is
-    // the configuration file.  At the end of this code block, the siteName
+    // The following section of code attempts to determine which file to use as the
+    // top-level the configuration file.  At the end of this code block, the configFile
     // variable will contain the name of the configuration file.
-    //
-    char *siteName = NULL;
+
+    char *configFile = NULL;
     //
     // First, try command line
     //
-    psS32 argNum = psArgumentGet(*argc, argv, "-site");
+    psS32 argNum = psArgumentGet(*argc, argv, "-ipprc");
     if (argNum != 0) {
-        //
-        // We remove the "-site" argument from argv.  Then
-        // we look for the next argument, which should be the filename, and
-        // remove it as well.
-        //
+        // remove the "-ipprc" argument from argv, check and remove filename
         psArgumentRemove(argNum, argc, argv);
         if (argNum >= *argc) {
-            psWarning("-site command-line switch provided without the required filename --- ignored.\n");
+            psWarning("-ipprc command-line switch provided without the required filename --- ignored.\n");
         } else {
-            siteName = psStringCopy(argv[argNum]);
+            configFile = psStringCopy(argv[argNum]);
             psArgumentRemove(argNum, argc, argv);
         }
@@ -407,8 +412,8 @@
     // Next, try environment variable
     //
-    if (!siteName) {
-        siteName = getenv(PS_SITE);
-        if (siteName) {
-            siteName = psStringCopy (siteName);
+    if (!configFile) {
+        configFile = getenv(IPPRC_ENV);
+        if (configFile) {
+            configFile = psStringCopy (configFile);
         }
     }
@@ -417,35 +422,53 @@
     // Last chance is ~/.ipprc
     //
-    if (!siteName) {
+    if (!configFile) {
         char *home = getenv("HOME");
-        siteName = psStringCopy(home);
-        psStringAppend(&siteName, "/%s", PS_DEFAULT_SITE);
-    }
-
+        configFile = psStringCopy(home);
+        psStringAppend(&configFile, "/%s", IPPRC_FILE);
+    }
 
     // We have the configuration filename; now we read and parse the config
-    // file and store in psMetadata struct site.
-    //
-
-    if (!pmConfigFileRead(&config->site, siteName, "site")) {
+    // file and store in psMetadata struct user.
+    // XXX move this section to pmConfigReadUser.c ?
+
+    if (!pmConfigFileRead(&config->user, configFile, "user")) {
         psFree(config);
         return NULL;
     }
 
-    // Set options based on the site configuration.
+    // XXX why was this being called here?  Is someone calling pmConfigRead multiple times?
+    // pmConfigDone();
+    assert (configPath == NULL);  
+
+    // define the config-file search path (configPath).  
+    psString path = psMetadataLookupStr(NULL, config->user, "PATH");
+    pmConfigSet (path);
+
+    // read the SITE file
+    psString siteFile = psMetadataLookupStr(NULL, config->user, "SITE");
+    if (!pmConfigFileRead(&config->site, siteFile, "site")) {
+        psFree(config);
+        return NULL;
+    }
+
+    // load the SYSTEM file
+    psString systemFile = psMetadataLookupStr(NULL, config->user, "SYSTEM");
+    if (!pmConfigFileRead(&config->system, systemFile, "system")) {
+        psFree(config);
+        return NULL;
+    }
+
+    // interpolate USER, SITE and SYSTEM into the config->complete metadata
+    config->complete = psMetadataCopy (NULL,             config->user);
+    config->complete = psMetadataCopy (config->complete, config->site);
+    config->complete = psMetadataCopy (config->complete, config->system);
+
+    // Set LOG and TRACE options based on the user configuration.  These must be set AFTER
+    // the SITE and SYSTEM config files are read so path:// entries here can be resolved.
     {
         bool mdok = true;   // Status of MD lookup result
 
-        // Initialise the psLib time handling
-        psString timeName = psMetadataLookupStr(&mdok, config->site, "TIME");
-        if (mdok && timeName)
-        {
-            psTrace("psModules.config", 7, "Initialising psTime with file %s\n", timeName);
-            psTimeInit(timeName);
-        }
-
-
         // Set logging level
-        int logLevel = psMetadataLookupS32(&mdok, config->site, "LOGLEVEL");
+        int logLevel = psMetadataLookupS32(&mdok, config->user, "LOGLEVEL");
         if (mdok && logLevel >= 0)
         {
@@ -456,5 +479,5 @@
 
         // Set logging format
-        psString logFormat = psMetadataLookupStr(&mdok, config->site, "LOGFORMAT");
+        psString logFormat = psMetadataLookupStr(&mdok, config->user, "LOGFORMAT");
         if (mdok && logFormat)
         {
@@ -463,5 +486,5 @@
         }
 
-        // Set logging destination first from command line, second from site configuration
+        // Set logging destination first from command line, second from user configuration
         psString logDest = NULL;        // Logging destination
         argNum = psArgumentGet(*argc, argv, "-log");
@@ -477,5 +500,5 @@
         }
         if (!logDest) {
-            logDest = psMemIncrRefCounter(psMetadataLookupStr(&mdok, config->site, "LOGDEST"));
+            logDest = psMemIncrRefCounter(psMetadataLookupStr(&mdok, config->user, "LOGDEST"));
         }
         if (logDest) {
@@ -497,5 +520,5 @@
 
         // Set trace levels
-        psMetadata *trace = psMetadataLookupMetadata(&mdok, config->site, "TRACE");
+        psMetadata *trace = psMetadataLookupMetadata(&mdok, config->user, "TRACE");
         if (mdok && trace) {
             psMetadataIterator *traceIter = psMetadataIteratorAlloc(trace, PS_LIST_HEAD, NULL); // Iterator
@@ -515,5 +538,5 @@
 
         // Set trace formats
-        psString traceFormat = psMetadataLookupStr(&mdok, config->site, "TRACEFORMAT");
+        psString traceFormat = psMetadataLookupStr(&mdok, config->user, "TRACEFORMAT");
         if (mdok && traceFormat) {
             psTrace("psModules.config", 7, "Setting trace format to %s\n", traceFormat);
@@ -535,5 +558,5 @@
         }
         if (!traceDest) {
-            traceDest = psMemIncrRefCounter(psMetadataLookupStr(&mdok, config->site, "TRACEDEST"));
+            traceDest = psMemIncrRefCounter(psMetadataLookupStr(&mdok, config->user, "TRACEDEST"));
         }
         if (traceDest) {
@@ -563,31 +586,20 @@
     }
 
-    // define the config-file search path (configPath).  Ensure that
-    // it contains the directory where we found the config file in
-    // the first place
-    if (configPath) {
-        pmConfigDone();
-    }
-
-    psString siteNameDir = psStringCopy(dirname(siteName));
-    psFree(siteName);
-
-    psString path = psMetadataLookupStr(NULL, config->site, "PATH");
-    psString newPath = NULL;            // New path
-    // The following gymnastics with 'newPath' are required to avoid changing the pointer out from under the
-    // psMetadataItem on which 'path' sits (leading to memory corruption because it no longer points to valid
-    // memory).
-    if (path) {
-        psStringAppend(&newPath, "%s:%s", path, siteNameDir);
-    } else {
-        newPath = psMemIncrRefCounter(siteNameDir);
-    }
-    psFree(siteNameDir);
-    pmConfigSet(newPath);
-    psFree(newPath);
+    // XXX read TIME from SITE (or system?)
+    { 
+	bool mdok = true;
+
+        // Initialise the psLib time handling
+	// XXX is this still needed / desired?
+        psString timeName = psMetadataLookupStr(&mdok, config->complete, "TIME");
+        if (mdok && timeName)
+        {
+            psTrace("psModules.config", 7, "Initialising psTime with file %s\n", timeName);
+            psTimeInit(timeName);
+        }
+    }
 
     // Next, we do a similar thing for the camera configuration file.  The
     // file is read and parsed into psMetadata struct "camera".
-    //
     argNum = psArgumentGet(*argc, argv, "-camera");
     if (argNum > 0) {
@@ -600,6 +612,6 @@
             char *cameraName = argv[argNum]; // symbolic name of the camera
 
-            // look for the CAMERAS list in config->site
-            psMetadata *cameras = psMetadataLookupMetadata(&mdok, config->site, "CAMERAS");
+            // look for the CAMERAS list in config->complete
+            psMetadata *cameras = psMetadataLookupMetadata(&mdok, config->complete, "CAMERAS");
             if (!cameras) {
                 psError(PS_ERR_IO, false, "Unable to find CAMERAS in site configuration.\n");
@@ -647,5 +659,5 @@
                                   "Camera specified on command line", config->camera);
 
-            if (!pmConfigCameraSkycellVersion(config->site, cameraName)) {
+            if (!pmConfigCameraSkycellVersion(config->complete, cameraName)) {
                 psError(PS_ERR_UNKNOWN, false,
                         "Unable to generate skycell versions of specified camera %s.\n",
@@ -655,5 +667,5 @@
             }
 
-            if (!pmConfigCameraMosaickedVersions(config->site, cameraName)) {
+            if (!pmConfigCameraMosaickedVersions(config->complete, cameraName)) {
                 psError(PS_ERR_UNKNOWN, false,
                         "Unable to generate mosaicked versions of specified camera %s.\n",
@@ -668,12 +680,12 @@
     if (!config->camera && readCameraConfig) {
         bool mdok;                      // Status of MD lookup
-        psMetadata *cameras = psMetadataLookupMetadata(&mdok, config->site, "CAMERAS"); // List of cameras
+        psMetadata *cameras = psMetadataLookupMetadata(&mdok, config->complete, "CAMERAS"); // List of cameras
         if (!mdok || !cameras) {
-            psError(PS_ERR_UNEXPECTED_NULL, true, "Unable to find CAMERAS in the site configuration.\n");
+            psError(PS_ERR_UNEXPECTED_NULL, true, "Unable to find CAMERAS in the system configuration.\n");
             return false;
         }
 
         if (!metadataReadFiles(cameras, "camera configuration")) {
-            psError(PS_ERR_UNKNOWN, false, "Unable to read cameras within site configuration.\n");
+            psError(PS_ERR_UNKNOWN, false, "Unable to read cameras within system configuration.\n");
             psFree(config);
             return NULL;
@@ -702,10 +714,10 @@
         psFree(iter);
 
-        if (!pmConfigCameraSkycellVersionsAll(config->site)) {
+        if (!pmConfigCameraSkycellVersionsAll(config->complete)) {
             psError(PS_ERR_UNKNOWN, false, "Unable to generate skycell versions of cameras.\n");
             psFree(config);
             return NULL;
         }
-        if (!pmConfigCameraMosaickedVersionsAll(config->site)) {
+        if (!pmConfigCameraMosaickedVersionsAll(config->complete)) {
             psError(PS_ERR_UNKNOWN, false, "Unable to generate mosaicked versions of cameras.\n");
             psFree(config);
@@ -715,5 +727,5 @@
 
     // Load the recipes from the camera file, if appropriate
-    if(!pmConfigReadRecipes(config, PM_RECIPE_SOURCE_SITE | PM_RECIPE_SOURCE_CAMERA)) {
+    if(!pmConfigReadRecipes(config, PM_RECIPE_SOURCE_SYSTEM | PM_RECIPE_SOURCE_CAMERA)) {
         psError(PS_ERR_IO, false, "Failed to read recipes from camera file");
         psFree(config);
@@ -746,5 +758,5 @@
         psArgumentRemove(argNum, argc, argv);
 
-        psMetadata *cameras = psMetadataLookupMetadata(NULL, config->site, "CAMERAS"); // List of cameras
+        psMetadata *cameras = psMetadataLookupMetadata(NULL, config->complete, "CAMERAS"); // List of cameras
         if (!cameras) {
             psError(PS_ERR_UNEXPECTED_NULL, false, "Unable to find CAMERAS in the site configuration.\n");
@@ -794,5 +806,5 @@
         } else {
             char *dbserver = argv[argNum]; // The camera configuration file to read
-            if (!psMetadataAddStr(config->site, PS_LIST_TAIL, "DBSERVER", PS_META_REPLACE, NULL, dbserver)) {
+            if (!psMetadataAddStr(config->complete, PS_LIST_TAIL, "DBSERVER", PS_META_REPLACE, NULL, dbserver)) {
                 psWarning("Failed to overwrite .ipprc DBSERVER value");
             }
@@ -809,5 +821,5 @@
         } else {
             char *dbname = argv[argNum]; // The camera configuration file to read
-            if (!psMetadataAddStr(config->site, PS_LIST_TAIL, "DBNAME", PS_META_REPLACE, NULL, dbname)) {
+            if (!psMetadataAddStr(config->complete, PS_LIST_TAIL, "DBNAME", PS_META_REPLACE, NULL, dbname)) {
                 psWarning("Failed to overwrite .ipprc DBNAME value");
             }
@@ -824,5 +836,5 @@
         } else {
             char *dbuser = argv[argNum]; // The camera configuration file to read
-            if (!psMetadataAddStr(config->site, PS_LIST_TAIL, "DBUSER", PS_META_REPLACE, NULL, dbuser)) {
+            if (!psMetadataAddStr(config->complete, PS_LIST_TAIL, "DBUSER", PS_META_REPLACE, NULL, dbuser)) {
                 psWarning("Failed to overwrite .ipprc DBUSER value");
             }
@@ -839,5 +851,5 @@
         } else {
             char *dbpassword = argv[argNum]; // The camera configuration file to read
-            if (!psMetadataAddStr(config->site, PS_LIST_TAIL, "DBPASSWORD", PS_META_REPLACE,
+            if (!psMetadataAddStr(config->complete, PS_LIST_TAIL, "DBPASSWORD", PS_META_REPLACE,
                                   NULL, dbpassword)) {
                 psWarning("Failed to overwrite .ipprc DBPASSWORD value");
@@ -855,5 +867,5 @@
         } else {
             char *dbport = argv[argNum]; // The camera configuration file to read
-            if (!psMetadataAddS32(config->site, PS_LIST_TAIL, "DBPORT", PS_META_REPLACE, NULL,
+            if (!psMetadataAddS32(config->complete, PS_LIST_TAIL, "DBPORT", PS_META_REPLACE, NULL,
                                   (psS32)atoi(dbport))) {
                 psWarning("Failed to overwrite .ipprc DBPORT value");
@@ -1027,5 +1039,5 @@
     if (! config->camera) {
         bool mdok;                      // Metadata lookup status
-        psMetadata *cameras = psMetadataLookupMetadata(&mdok, config->site, "CAMERAS");
+        psMetadata *cameras = psMetadataLookupMetadata(&mdok, config->complete, "CAMERAS");
         if (! mdok || !cameras) {
             psError(PS_ERR_IO, true, "Unable to find CAMERAS in the configuration.");
@@ -1114,5 +1126,5 @@
     PS_ASSERT_STRING_NON_EMPTY(cameraName, NULL);
 
-    psMetadata *cameras = psMetadataLookupMetadata(NULL, config->site, "CAMERAS");
+    psMetadata *cameras = psMetadataLookupMetadata(NULL, config->complete, "CAMERAS");
     if (!cameras) {
         psError(PS_ERR_IO, true, "Unable to find CAMERAS in the configuration.");
@@ -1140,5 +1152,5 @@
 {
     PS_ASSERT_PTR_NON_NULL(config, NULL);
-    PS_ASSERT_PTR_NON_NULL(config->site, NULL);
+    PS_ASSERT_PTR_NON_NULL(config->complete, NULL);
 
     #ifndef HAVE_PSDB
@@ -1157,9 +1169,9 @@
 
     // XXX leaky strings
-    psString dbServer = psMetadataLookupStr(&mdStatus01, config->site, "DBSERVER");
-    psString dbUsername = psMetadataLookupStr(&mdStatus02, config->site, "DBUSER");
-    psString dbPassword = psMetadataLookupStr(&mdStatus03, config->site, "DBPASSWORD");
-    psString dbName = psMetadataLookupStr(&mdStatus04, config->site, "DBNAME");
-    psS32 dbPort = psMetadataLookupS32(&mdStatus05, config->site, "DBPORT");
+    psString dbServer = psMetadataLookupStr(&mdStatus01, config->complete, "DBSERVER");
+    psString dbUsername = psMetadataLookupStr(&mdStatus02, config->complete, "DBUSER");
+    psString dbPassword = psMetadataLookupStr(&mdStatus03, config->complete, "DBPASSWORD");
+    psString dbName = psMetadataLookupStr(&mdStatus04, config->complete, "DBNAME");
+    psS32 dbPort = psMetadataLookupS32(&mdStatus05, config->complete, "DBPORT");
     if (!mdStatus05) {
         dbPort = 0;
@@ -1352,11 +1364,11 @@
     // replace path://PATH with matched datapath
     if (!strncasecmp(filename, "path://", strlen("path://"))) {
-        PS_ASSERT_METADATA_NON_NULL(config->site, NULL);
+        PS_ASSERT_METADATA_NON_NULL(config->complete, NULL);
 
         psString newName = psStringCopy(filename);
 
         // filename should be of the form: path://PATH/rest/of/file
-        // replace PATH with matching name from config->site:DATAPATH
-        psMetadata *datapath = psMetadataLookupPtr (NULL, config->site, "DATAPATH");
+        // replace PATH with matching name from config->complete:DATAPATH
+        psMetadata *datapath = psMetadataLookupPtr (NULL, config->complete, "DATAPATH");
         if (datapath == NULL) {
             psError(PS_ERR_UNKNOWN, true, "DATAPATH is not defined in config.site");
@@ -1410,5 +1422,5 @@
         // if env isn't set, check the config system
         if (!neb_server) {
-            neb_server = psMetadataLookupStr(&status, config->site, "NEB_SERVER");
+            neb_server = psMetadataLookupStr(&status, config->complete, "NEB_SERVER");
             if (!status) {
                 psError(PM_ERR_CONFIG, true, "failed to lookup config value for NEB_SERVER.");
Index: /trunk/psModules/src/config/pmConfig.h
===================================================================
--- /trunk/psModules/src/config/pmConfig.h	(revision 16610)
+++ /trunk/psModules/src/config/pmConfig.h	(revision 16611)
@@ -5,6 +5,6 @@
  *  @author Eugene Magnier, IfA
  *
- *  @version $Revision: 1.32 $ $Name: not supported by cvs2svn $
- *  @date $Date: 2007-10-26 02:41:15 $
+ *  @version $Revision: 1.33 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2008-02-22 20:20:38 $
  *  Copyright 2005-2006 Institute for Astronomy, University of Hawaii
  */
@@ -25,5 +25,5 @@
 typedef enum {
     PM_RECIPE_SOURCE_NONE        = 0x00, ///< None yet
-    PM_RECIPE_SOURCE_SITE        = 0x01, ///< Site configuration
+    PM_RECIPE_SOURCE_SYSTEM      = 0x01, ///< System configuration
     PM_RECIPE_SOURCE_CAMERA      = 0x02, ///< Camera configuration
     PM_RECIPE_SOURCE_CL          = 0x04, ///< Command-line
@@ -34,8 +34,11 @@
 /// Configuration information
 ///
-/// This structure stores the configuration information: the site, camera and recipe configuration, the
+/// This structure stores the configuration information: user, site, system, camera and recipe configuration, the
 /// command-line arguments, the pmFPAfiles used, and the database handle.
 typedef struct {
-    psMetadata *site;                   ///< Site configuration
+    psMetadata *user;                 	///< User configuration
+    psMetadata *site;                 	///< Site configuration
+    psMetadata *system;               	///< System configuration
+    psMetadata *complete;               ///< Full merged configuration
     psMetadata *camera;                 ///< Camera specification
     psString cameraName;                ///< Camera name
@@ -68,10 +71,10 @@
 /// Read configuration information from the command line.
 ///
-/// pmConfigRead loads the site configuration (the file name is specified by "-site SITE_FILE" on the
-/// command-line, the PS_SITE environment variable, or it is $HOME/.ipprc).  The configuration search path is
+/// pmConfigRead loads the user configuration (the file name is specified by "-ipprc FILE" on the
+/// command-line, the IPPRC environment variable, or it is $HOME/.ipprc).  The configuration search path is
 /// set. The camera configuration is loaded if it is specified on the command line ("-camera
 /// CAMERA_FILE"). Recipes specified on the command line ("-recipe RECIPE_NAME RECIPE_SOURCE") are also
 /// loaded.  These command-line arguments are removed from from the command-line, to simplify parsing.  The
-/// psLib log, trace and time setups are also performed if specified in the site configuration.
+/// psLib log, trace and time setups are also performed if specified in the user configuration.
 pmConfig *pmConfigRead(int *argc,       ///< Number of command-line arguments
                        char **argv, ///< Array of command-line arguments
@@ -166,5 +169,5 @@
 /// Get the file rule of interest
 ///
-/// Look up the name of the set of file rules to use, get that set from the site configuration, and return the
+/// Look up the name of the set of file rules to use, get that set from the system configuration, and return the
 /// appropriate rule from the set.
 psMetadata *pmConfigFileRule(const pmConfig *config, ///< Configuration
Index: /trunk/psModules/src/config/pmConfigCamera.c
===================================================================
--- /trunk/psModules/src/config/pmConfigCamera.c	(revision 16610)
+++ /trunk/psModules/src/config/pmConfigCamera.c	(revision 16611)
@@ -24,18 +24,18 @@
 
 // Generate the skycell version of a named camera configuration
-bool pmConfigCameraSkycellVersion(psMetadata *site, // The site configuration
+bool pmConfigCameraSkycellVersion(psMetadata *system, // The system configuration
                                   const char *name // Name of the un-mosaicked camera
                                   )
 {
-    PS_ASSERT_METADATA_NON_NULL(site, false);
+    PS_ASSERT_METADATA_NON_NULL(system, false);
     PS_ASSERT_STRING_NON_EMPTY(name, false);
 
     bool mdok;                          // Status of MD lookup
-    psMetadata *cameras = psMetadataLookupMetadata(&mdok, site, "CAMERAS"); // List of cameras
+    psMetadata *cameras = psMetadataLookupMetadata(&mdok, system, "CAMERAS"); // List of cameras
     if (!mdok || !cameras) {
-        psError(PS_ERR_UNEXPECTED_NULL, true, "Unable to find CAMERAS in the site configuration.\n");
-        return false;
-    }
-    if (!pmConfigGenerateSkycellVersion(cameras, cameras, name, site)) {
+        psError(PS_ERR_UNEXPECTED_NULL, true, "Unable to find CAMERAS in the system configuration.\n");
+        return false;
+    }
+    if (!pmConfigGenerateSkycellVersion(cameras, cameras, name, system)) {
         psError(PS_ERR_UNKNOWN, true, "Failed to build skycell camera description for %s\n", name);
         return false;
@@ -45,12 +45,12 @@
 
 
-bool pmConfigCameraSkycellVersionsAll(psMetadata *site)
-{
-    PS_ASSERT_METADATA_NON_NULL(site, false);
+bool pmConfigCameraSkycellVersionsAll(psMetadata *system)
+{
+    PS_ASSERT_METADATA_NON_NULL(system, false);
 
     bool mdok;                          // Status of MD lookup
-    psMetadata *cameras = psMetadataLookupMetadata(&mdok, site, "CAMERAS"); // List of cameras
+    psMetadata *cameras = psMetadataLookupMetadata(&mdok, system, "CAMERAS"); // List of cameras
     if (!mdok || !cameras) {
-        psError(PS_ERR_UNEXPECTED_NULL, true, "Unable to find CAMERAS in the site configuration.\n");
+        psError(PS_ERR_UNEXPECTED_NULL, true, "Unable to find CAMERAS in the system configuration.\n");
         return false;
     }
@@ -61,5 +61,5 @@
     while ((camerasItem = psMetadataGetAndIncrement(camerasIter))) {
         assert(camerasItem->type == PS_DATA_METADATA); // Only metadata are allowed here!
-        if (!pmConfigGenerateSkycellVersion(cameras, new, camerasItem->name, site)) {
+        if (!pmConfigGenerateSkycellVersion(cameras, new, camerasItem->name, system)) {
             psError(PS_ERR_UNKNOWN, true, "Failed to build skycell camera description for %s\n",
                     camerasItem->name);
@@ -92,5 +92,5 @@
 static const char *skycellConceptName(const char *name, // Name of concept
                                       const char **concepts, // List of concepts NOT to update
-                                      const psMetadata *site // Site configuration
+                                      const psMetadata *system // System configuration
                                       )
 {
@@ -101,9 +101,9 @@
     }
 
-    if (!site) {
+    if (!system) {
         return name;
     }
     bool mdok;                          // Status of MD lookup
-    psMetadata *skycells = psMetadataLookupMetadata(&mdok, site, "SKYCELLS"); // Skycell concept headers
+    psMetadata *skycells = psMetadataLookupMetadata(&mdok, system, "SKYCELLS"); // Skycell concept headers
     if (!skycells) {
         return name;
@@ -121,5 +121,5 @@
                                     psMetadata *newCameras, // New list of camera configurations
                                     const char *name, // Name of original camera configuration
-                                    const psMetadata *site // Site configuration
+                                    const psMetadata *system // System configuration
                                     )
 {
@@ -213,5 +213,5 @@
         iter = psListIteratorAlloc(concepts, PS_LIST_HEAD, false);
         while ((name = psListGetAndIncrement(iter))) {
-            const char *new = skycellConceptName(name, skycellConceptsFPA, site); // Name for skycell
+            const char *new = skycellConceptName(name, skycellConceptsFPA, system); // Name for skycell
             if (new) {
                 psMetadataAddStr(translation, PS_LIST_TAIL, name, 0, NULL, new);
@@ -224,5 +224,5 @@
         iter = psListIteratorAlloc(concepts, PS_LIST_HEAD, false);
         while ((name = psListGetAndIncrement(iter))) {
-            const char *new = skycellConceptName(name, skycellConceptsChip, site); // Name for skycell
+            const char *new = skycellConceptName(name, skycellConceptsChip, system); // Name for skycell
             if (new) {
                 psMetadataAddStr(translation, PS_LIST_TAIL, name, 0, NULL, new);
@@ -235,5 +235,5 @@
         iter = psListIteratorAlloc(concepts, PS_LIST_HEAD, false);
         while ((name = psListGetAndIncrement(iter))) {
-            const char *new = skycellConceptName(name, skycellConceptsCell, site); // Name for skycell
+            const char *new = skycellConceptName(name, skycellConceptsCell, system); // Name for skycell
             if (new) {
                 psMetadataAddStr(translation, PS_LIST_TAIL, name, 0, NULL, new);
@@ -299,15 +299,15 @@
 
 // Generate the Chip and FPA mosaicked version of a named camera configuration
-bool pmConfigCameraMosaickedVersions(psMetadata *site, // The site configuration
+bool pmConfigCameraMosaickedVersions(psMetadata *system, // The system configuration
                                      const char *name // Name of the un-mosaicked camera
                                     )
 {
-    PS_ASSERT_METADATA_NON_NULL(site, false);
+    PS_ASSERT_METADATA_NON_NULL(system, false);
     PS_ASSERT_STRING_NON_EMPTY(name, false);
 
     bool mdok;                          // Status of MD lookup
-    psMetadata *cameras = psMetadataLookupMetadata(&mdok, site, "CAMERAS"); // List of cameras
+    psMetadata *cameras = psMetadataLookupMetadata(&mdok, system, "CAMERAS"); // List of cameras
     if (!mdok || !cameras) {
-        psError(PS_ERR_UNEXPECTED_NULL, true, "Unable to find CAMERAS in the site configuration.\n");
+        psError(PS_ERR_UNEXPECTED_NULL, true, "Unable to find CAMERAS in the system configuration.\n");
         return false;
     }
@@ -325,12 +325,12 @@
 // the operation putting the new entries first is now implemented in pmConfigGenerateMosaickedVersion
 // Generate the Chip and FPA mosaicked version of a named camera configuration
-bool pmConfigCameraMosaickedVersionsAll(psMetadata *site)
-{
-    PS_ASSERT_METADATA_NON_NULL(site, false);
+bool pmConfigCameraMosaickedVersionsAll(psMetadata *system)
+{
+    PS_ASSERT_METADATA_NON_NULL(system, false);
 
     bool mdok;                          // Status of MD lookup
-    psMetadata *cameras = psMetadataLookupMetadata(&mdok, site, "CAMERAS"); // List of cameras
+    psMetadata *cameras = psMetadataLookupMetadata(&mdok, system, "CAMERAS"); // List of cameras
     if (!mdok || !cameras) {
-        psError(PS_ERR_UNEXPECTED_NULL, true, "Unable to find CAMERAS in the site configuration.\n");
+        psError(PS_ERR_UNEXPECTED_NULL, true, "Unable to find CAMERAS in the system configuration.\n");
         return false;
     }
Index: /trunk/psModules/src/config/pmConfigCommand.c
===================================================================
--- /trunk/psModules/src/config/pmConfigCommand.c	(revision 16610)
+++ /trunk/psModules/src/config/pmConfigCommand.c	(revision 16611)
@@ -12,25 +12,27 @@
 {
     PS_ASSERT_PTR_NON_NULL(command, false);
+    PS_ASSERT_PTR_NON_NULL(config, false);
+    PS_ASSERT_PTR_NON_NULL(config->complete, false);
 
     bool mdok;                          // Status of MD lookup
-    const char *dbserver = psMetadataLookupStr(&mdok, config->site, "DBSERVER"); // Database server
+    const char *dbserver = psMetadataLookupStr(&mdok, config->complete, "DBSERVER"); // Database server
     if (!mdok || strlen(dbserver) == 0) {
         psError(PS_ERR_UNEXPECTED_NULL, true, "Unable to find DBSERVER in site configuration.\n");
-        return NULL;
+        return false;
     }
-    const char *dbname = psMetadataLookupStr(&mdok, config->site, "DBNAME"); // Database name
+    const char *dbname = psMetadataLookupStr(&mdok, config->complete, "DBNAME"); // Database name
     if (!mdok || strlen(dbname) == 0) {
         psError(PS_ERR_UNEXPECTED_NULL, true, "Unable to find DBNAME in site configuration.\n");
-        return NULL;
+        return false;
     }
-    const char *dbuser = psMetadataLookupStr(&mdok, config->site, "DBUSER"); // Database user
+    const char *dbuser = psMetadataLookupStr(&mdok, config->complete, "DBUSER"); // Database user
     if (!mdok || strlen(dbuser) == 0) {
         psError(PS_ERR_UNEXPECTED_NULL, true, "Unable to find DBUSER in site configuration.\n");
-        return NULL;
+        return false;
     }
-    const char *dbpassword = psMetadataLookupStr(&mdok, config->site, "DBPASSWORD"); // Database password
+    const char *dbpassword = psMetadataLookupStr(&mdok, config->complete, "DBPASSWORD"); // Database password
     if (!mdok || strlen(dbpassword) == 0) {
         psError(PS_ERR_UNEXPECTED_NULL, true, "Unable to find DBPASSWORD in site configuration.\n");
-        return NULL;
+        return false;
     }
 
Index: /trunk/psModules/src/config/pmConfigRecipes.c
===================================================================
--- /trunk/psModules/src/config/pmConfigRecipes.c	(revision 16610)
+++ /trunk/psModules/src/config/pmConfigRecipes.c	(revision 16611)
@@ -11,5 +11,5 @@
 #include "pmConfigRecipes.h"
 
-static bool loadRecipeSite(bool *status, pmConfig *config, psMetadata *source);
+static bool loadRecipeSystem(bool *status, pmConfig *config, psMetadata *source);
 static bool loadRecipeCamera(bool *status, pmConfig *config, psMetadata *source);
 static bool loadRecipeFromArguments(bool *status, pmConfig *config);
@@ -46,7 +46,7 @@
 
 // this function may be called several times.  it attempts to load the recipe data from one of
-// three locations: config->site, config->camera, and argv.  We cannot read the recipes
+// three locations: config->complete, config->camera, and argv.  We cannot read the recipes
 // from config->camera until a camera has been read BUT, the argv recipes must override the
-// camera and site recipes.
+// camera and system recipes.
 bool pmConfigReadRecipes(pmConfig *config, pmRecipeSource source)
 {
@@ -58,13 +58,13 @@
     }
 
-    // Read the recipe file names from the site configuration and camera configuration
-    // It is an error for config->site:recipes not to exist.  all programs install their
-    // master recipe files in the site:recipe location when they are built.
-    if (config->site && (source & PM_RECIPE_SOURCE_SITE)) {
-        if (!loadRecipeSite(&status, config, config->site)) {
-            psError(PS_ERR_IO, false, "Failed to read recipes from site config");
-            return false;
-        }
-        psTrace ("psModules.config", 3, "read recipes from site config");
+    // Read the recipe file names from the system configuration and camera configuration
+    // It is an error for config->complete:recipes not to exist.  all programs install their
+    // master recipe files in the system:recipe location when they are built.
+    if (config->complete && (source & PM_RECIPE_SOURCE_SYSTEM)) {
+        if (!loadRecipeSystem(&status, config, config->complete)) {
+            psError(PS_ERR_IO, false, "Failed to read recipes from system config");
+            return false;
+        }
+        psTrace ("psModules.config", 3, "read recipes from system config");
     }
 
@@ -283,6 +283,6 @@
 }
 
-// Load the recipe files for SITE : REQUIRED
-static bool loadRecipeSite(bool *status,
+// Load the recipe files for SYSTEM : REQUIRED
+static bool loadRecipeSystem(bool *status,
                            pmConfig *config, // The configuration into which to read the recipes
                            psMetadata *source // The source configuration, from which to read the filenames
@@ -294,6 +294,6 @@
 
     if (!source) {
-        psError(PS_ERR_IO, true, "The site configuration has not been read --- cannot read recipes from this location.\n");
-        config->recipesRead &= ~PM_RECIPE_SOURCE_SITE;
+        psError(PS_ERR_IO, true, "The system configuration has not been read --- cannot read recipes from this location.\n");
+        config->recipesRead &= ~PM_RECIPE_SOURCE_SYSTEM;
         return false;
     }
@@ -301,5 +301,5 @@
     psMetadata *recipes = psMetadataLookupMetadata(NULL, source, "RECIPES"); // The list of recipes
     if (!recipes) {
-        psError(PS_ERR_IO, false, "RECIPES not found in the site configuration\n");
+        psError(PS_ERR_IO, false, "RECIPES not found in the system configuration\n");
         return false;
     }
@@ -313,5 +313,5 @@
         // type mismatch is a serious error
         if (fileItem->type != PS_DATA_STRING) {
-            psError(PS_ERR_IO, true, "%s in site configuration RECIPES is not of type STR", fileItem->name);
+            psError(PS_ERR_IO, true, "%s in system configuration RECIPES is not of type STR", fileItem->name);
             return false;
         }
@@ -320,5 +320,5 @@
         psMetadata *recipe = NULL;
         if (!pmConfigFileRead(&recipe, fileItem->data.str, "recipe")) {
-            psError(PS_ERR_IO, false, "Failed to read recipe file %s listed in site configuration\n",
+            psError(PS_ERR_IO, false, "Failed to read recipe file %s listed in system configuration\n",
                     fileItem->data.str);
             return false;
@@ -331,5 +331,5 @@
     }
     psFree(recipesIter);
-    config->recipesRead |= PM_RECIPE_SOURCE_SITE;
+    config->recipesRead |= PM_RECIPE_SOURCE_SYSTEM;
 
     *status = true;
@@ -337,7 +337,7 @@
 }
 
-// Load the recipe files (valid for SITE | CAMERA)
+// Load the recipe files (valid for SYSTEM | CAMERA)
 // each time we load a specific recipe, it overrides the existing metadata for that recipe
-// for sourceType == SITE | CAMERA, RECIPES contains a list of files to be read (pmConfigFileRead)
+// for sourceType == SYSTEM | CAMERA, RECIPES contains a list of files to be read (pmConfigFileRead)
 static bool loadRecipeCamera(bool *status, // status variable
                              pmConfig *config, // The configuration into which to read the recipes
Index: /trunk/psModules/src/detrend/pmDetrendDB.c
===================================================================
--- /trunk/psModules/src/detrend/pmDetrendDB.c	(revision 16610)
+++ /trunk/psModules/src/detrend/pmDetrendDB.c	(revision 16611)
@@ -115,5 +115,4 @@
     PS_ASSERT_PTR_NON_NULL(options, NULL);
     PS_ASSERT_PTR_NON_NULL(config, NULL);
-    PS_ASSERT_PTR_NON_NULL(config->site, NULL);
 
     int status, exit_status;
@@ -150,7 +149,15 @@
         psStringAppend(&line, " -airmass %f", options->twilight);
     }
-
-    pmConfigDatabaseCommand(&line, config);
-    pmConfigTraceCommand(&line);
+    
+    if (!pmConfigDatabaseCommand(&line, config)) {
+        psError (PS_ERR_IO, false, "error building detrend command %s", line);
+        goto failure;
+    }
+
+    if (!pmConfigTraceCommand(&line)) {
+        psError (PS_ERR_IO, false, "error building detrend command %s", line);
+        goto failure;
+    }
+
     psTrace("psModules.detrend", 5, "running %s", line);
 
Index: /trunk/psphot/src/psphotOutput.c
===================================================================
--- /trunk/psphot/src/psphotOutput.c	(revision 16610)
+++ /trunk/psphot/src/psphotOutput.c	(revision 16611)
@@ -19,7 +19,8 @@
 }
 
+// XXX replace this with a call to a pmConfig function (pmConfigDump...)
 bool psphotDumpConfig (pmConfig *config) {
 
-  psMetadataConfigWrite (config->site, "site.md");
+  psMetadataConfigWrite (config->complete, "complete.md");
   psMetadataConfigWrite (config->camera, "camera.md");
   psMetadataConfigWrite (config->recipes, "recipes.md");
Index: /trunk/pswarp/src/pswarpDefineSkycell.c
===================================================================
--- /trunk/pswarp/src/pswarpDefineSkycell.c	(revision 16610)
+++ /trunk/pswarp/src/pswarpDefineSkycell.c	(revision 16611)
@@ -62,6 +62,8 @@
     // determine the current format from the header
     // determine camera if not specified already
+    // XXX EAM : this operation should be defined as a pmConfig function (pmConfigCopy?)
     skyConfig = pmConfigAlloc(0, NULL);
-    skyConfig->site = psMemIncrRefCounter (config->site);
+    skyConfig->complete = psMemIncrRefCounter (config->complete);
+
     psFree (skyConfig->files);
     skyConfig->files = psMemIncrRefCounter (config->files);
