Index: /trunk/ippScripts/Build.PL
===================================================================
--- /trunk/ippScripts/Build.PL	(revision 23860)
+++ /trunk/ippScripts/Build.PL	(revision 23861)
@@ -82,4 +82,5 @@
         scripts/dist_component.pl
         scripts/dist_advancerun.pl
+        scripts/dist_make_fileset.pl
     )],
     dist_abstract => 'Scripts for running the Pan-STARRS IPP',
Index: /trunk/ippScripts/scripts/dist_advancerun.pl
===================================================================
--- /trunk/ippScripts/scripts/dist_advancerun.pl	(revision 23860)
+++ /trunk/ippScripts/scripts/dist_advancerun.pl	(revision 23861)
@@ -89,5 +89,5 @@
 }
 
-# XXX we should create a file rule for this
+# XXX should we create a file rule for this?
 my $outfile = "$outdir/dbinfo.$stage.$stage_id.mdc";
 
Index: /trunk/ippScripts/scripts/dist_make_fileset.pl
===================================================================
--- /trunk/ippScripts/scripts/dist_make_fileset.pl	(revision 23860)
+++ /trunk/ippScripts/scripts/dist_make_fileset.pl	(revision 23861)
@@ -39,5 +39,5 @@
 
 # Parse the command-line arguments
-my ($dist_id, $dist_dir, $target_id, $stage, $stage_id, $prod_id, $product_name, $product_root, $ds_dbhost, $ds_dbname);
+my ($dist_id, $dist_dir, $target_id, $stage, $stage_id, $prod_id, $product_name, $ds_dbhost, $ds_dbname);
 my ($dbname, $save_temps, $verbose, $no_update, $logfile);
 
@@ -50,5 +50,4 @@
            'prod_id=s'      => \$prod_id,    # id for the product
            'product_name=s' => \$product_name,  # location of the data store directory for this product
-           'product_root=s' => \$product_root,  # location of the data store directory for this product
            'ds_dbhost=s'    => \$ds_dbhost,  # database host for the datastore database
            'ds_dbname=s'    => \$ds_dbname,  # database name for the datastore database
@@ -61,5 +60,5 @@
 
 pod2usage( -msg => "Unknown option: @ARGV", -exitval => 2 ) if @ARGV;
-pod2usage( -msg => "Required options: --dist_id --dist_dir --target_id --stage --stage_id --prod_id --product_root --ds_dbhost --ds_dbname",
+pod2usage( -msg => "Required options: --dist_id --dist_dir --target_id --stage --stage_id --prod_id --ds_dbhost --ds_dbname",
            -exitval => 3) unless
     defined $dist_id and
@@ -70,5 +69,4 @@
     defined $prod_id and
     defined $product_name and
-    defined $product_root and
     defined $ds_dbhost and
     defined $ds_dbname;
@@ -156,6 +154,16 @@
 
 # XXX: disttool -addrcdsfileset
-
-# XXX todo: add rcRun's for the destinations
+{
+    my $command = "$disttool -addfileset -dist_id $dist_id -prod_id $prod_id -name $fileset_name";
+    $command .= " -dbname $dbname" if $dbname;
+
+    my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
+        run(command => $command, verbose => $verbose);
+    unless ($success) {
+        $error_code = (($error_code >> 8) or $PS_EXIT_PROG_ERROR);
+        &my_die("Unable to perform $command error_code: $error_code", $dist_id, $prod_id, $error_code);
+    }
+}
+
 
 
@@ -239,4 +247,13 @@
     print STDERR "$msg\n";
 
+    my $command = "$disttool -addfileset -dist_id $dist_id -prod_id $prod_id -fault $fault";
+    $command .= " -dbname $dbname" if $dbname;
+
+    my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
+        run(command => $command, verbose => $verbose);
+    unless ($success) {
+        $error_code = (($error_code >> 8) or $PS_EXIT_PROG_ERROR);
+        print STDERR "Unable to perform $command error_code: $error_code\n";
+    }
     exit $fault;
 }
Index: /trunk/ippTasks/Makefile.am
===================================================================
--- /trunk/ippTasks/Makefile.am	(revision 23860)
+++ /trunk/ippTasks/Makefile.am	(revision 23861)
@@ -21,4 +21,5 @@
 	replicate.pro \
 	dist.pro \
+	rcserver.pro \
 	pstamp.pro
 
Index: /trunk/ippTasks/rcserver.pro
===================================================================
--- /trunk/ippTasks/rcserver.pro	(revision 23861)
+++ /trunk/ippTasks/rcserver.pro	(revision 23861)
@@ -0,0 +1,274 @@
+## rcserver.pro : tasks for managing the server side of the ipp data distribution system : -*- sh -*-
+
+# test for required global variables
+check.globals
+
+#$LOGSUBDIR = $LOGDIR/rcserver
+#exec mkdir -p $LOGSUBDIR
+
+### Initialise the books containing the tasks to do
+book init rcPendingFS
+book init rcPendingDS
+
+### Database lists
+$rcPendingFS_DB = 0
+$rcPendingDS_DB = 0
+
+### Check status of tasks
+macro rcserver.status
+  book listbook rcPendingFS
+  book listbook rcPendingDS
+end
+
+### Reset tasks
+macro rcserver.reset
+  book init rcPendingFS
+  book init rcPendingDS
+end
+
+### Turn tasks on
+macro rcserver.on
+  task rcserver.makefileset.load
+    active true
+  end
+  task rcserver.makefileset.run
+    active true
+  end
+  task rcserver.checkruns.load
+    active true
+  end
+  task rcserver.checkruns.run
+    active true
+  end
+end
+macro rcserver.off
+  task rcserver.makefileset.load
+    active false
+  end
+  task rcserver.makefileset.run
+    active false
+  end
+  task rcserver.checkruns.load
+    active false
+  end
+  task rcserver.checkruns.run
+    active false
+  end
+end
+
+task	       rcserver.makefileset.load
+  host         local
+
+  periods      -poll $LOADPOLL
+  periods      -exec $LOADEXEC
+  periods      -timeout 30
+  npending     1
+
+  stdout NULL
+  stderr $LOGDIR/rcserver.makefileset.load.log
+
+  task.exec
+    $run = disttool -pendingfileset
+    if ($DB:n == 0)
+      option DEFAULT
+    else
+      # save the DB name for the exit tasks
+      option $DB:$rcPendingFS_DB
+      $run = $run -dbname $DB:$rcPendingFS_DB
+      $rcPendingFS_DB ++
+      if ($rcPendingFS_DB >= $DB:n) set rcPendingFS_DB = 0
+    end
+    add_poll_args run
+    command $run
+  end
+
+  # success
+  task.exit    0
+    # convert 'stdout' to book format
+    ipptool2book stdout rcPendingFS -key dist_id:prod_id -uniq -setword dbname $options:0 -setword pantaskState INIT
+    if ($VERBOSE > 2)
+      book listbook rcPendingFS
+    end
+
+    # delete existing entries in the appropriate pantaskStates
+    process_cleanup rcPendingFS
+  end
+
+  # locked list
+  task.exit    default
+    showcommand failure
+  end
+
+  # operation times out?
+  task.exit    timeout
+    showcommand timeout
+  end
+end
+
+task	       rcserver.makefileset.run
+  periods      -poll $RUNPOLL
+  periods      -exec $RUNEXEC
+  periods      -timeout 60
+
+  task.exec
+    book npages rcPendingFS -var N
+    if ($N == 0) break
+    if ($NETWORK == 0) break
+    
+    # look for new components to process (pantaskState == INIT)
+    book getpage rcPendingFS 0 -var pageName -key pantaskState INIT
+    if ("$pageName" == "NULL") break
+
+    book getword rcPendingFS $pageName dist_id -var DIST_ID
+    book getword rcPendingFS $pageName target_id -var TARGET_ID
+    book getword rcPendingFS $pageName stage -var STAGE
+    book getword rcPendingFS $pageName stage_id -var STAGE_ID
+    book getword rcPendingFS $pageName dist_dir -var DIST_DIR
+#    book getword rcPendingFS $pageName clean -var CLEAN
+    book getword rcPendingFS $pageName prod_id -var PROD_ID
+    book getword rcPendingFS $pageName product_name -var PRODUCT_NAME
+    book getword rcPendingFS $pageName ds_dbhost -var DS_DBHOST
+    book getword rcPendingFS $pageName ds_dbname -var DS_DBNAME
+    book getword rcPendingFS $pageName dbname -var DBNAME
+
+#    set.host.for.camera $CAMERA $MAGIC_ID
+#    set.workdir.by.camera $CAMERA $MAGIC_ID $WORKDIR_TEMPLATE $default_host WORKDIR
+    host anyhost
+
+    sprintf logfile "%s/makefs.%s.%s.log" $DIST_DIR $DIST_ID $PROD_ID
+    stdout $logfile
+    stderr $logfile
+
+    book setword rcPendingFS $pageName pantaskState RUN
+
+    $run = dist_make_fileset.pl --dist_id $DIST_ID --target_id $TARGET_ID --stage $STAGE --stage_id $STAGE_ID --prod_id $PROD_ID --product_name $PRODUCT_NAME  --ds_dbhost $DS_DBHOST --ds_dbname $DS_DBNAME --dist_dir $DIST_DIR
+
+    add_standard_args run
+
+    # save the pageName for future reference below
+    options $pageName
+
+    # create the command line
+    if ($VERBOSE > 1)
+      echo command $run
+    end
+    command $run
+  end
+
+  # default exit status
+  task.exit    default
+    process_exit rcPendingFS $options:0 $JOB_STATUS
+  end
+
+  # operation timed out?
+  task.exit    timeout
+    showcommand timeout
+    book setword rcPendingFS $options:0 pantaskState TIMEOUT
+  end
+end
+
+
+task	       rcserver.checkruns.load
+  host         local
+
+  periods      -poll $LOADPOLL
+  periods      -exec $LOADEXEC
+  periods      -timeout 30
+  npending     1
+
+  active false
+
+  stdout NULL
+  stderr $LOGDIR/rcserver.checkruns.load.log
+
+  task.exec
+    $run = disttool -pendingdatastores
+    if ($DB:n == 0)
+      option DEFAULT
+    else
+      # save the DB name for the exit tasks
+      option $DB:$rcPendingDS_DB
+      $run = $run -dbname $DB:$rcPendingDS_DB
+      $rcPendingDS_DB ++
+      if ($rcPendingDS_DB >= $DB:n) set rcPendingDS_DB = 0
+    end
+    add_poll_args run
+    command $run
+  end
+
+  # success
+  task.exit    0
+    # convert 'stdout' to book format
+    ipptool2book stdout rcPendingDS -key fs_id -uniq -setword dbname $options:0 -setword pantaskState INIT
+    if ($VERBOSE > 2)
+      book listbook rcPendingDS
+    end
+
+    # delete existing entries in the appropriate pantaskStates
+    process_cleanup rcPendingDS
+  end
+
+  # locked list
+  task.exit    default
+    showcommand failure
+  end
+
+  # operation times out?
+  task.exit    timeout
+    showcommand timeout
+  end
+end
+
+task	       rcserver.checkruns.run
+  periods      -poll $RUNPOLL
+  periods      -exec $RUNEXEC
+  periods      -timeout 60
+
+  active false
+
+  task.exec
+    book npages rcPendingDS -var N
+    if ($N == 0) break
+    if ($NETWORK == 0) break
+    
+    # look for new components to process (pantaskState == INIT)
+    book getpage rcPendingDS 0 -var pageName -key pantaskState INIT
+    if ("$pageName" == "NULL") break
+
+    book setword rcPendingDS $pageName pantaskState RUN
+    book getword rcPendingDS $pageName dist_id -var DIST_ID
+    book getword rcPendingDS $pageName stage   -var STAGE
+    book getword rcPendingDS $pageName stage_id -var STAGE_ID
+    book getword rcPendingDS $pageName outdir -var OUTDIR
+
+    host anyhost
+
+    sprintf logfile "%s/dist.advance.%s.log" $OUTDIR $DIST_ID
+    stdout $logfile
+    stderr $logfile
+
+    $run = dist_advancerun.pl --dist_id $DIST_ID --stage $STAGE --stage_id $STAGE_ID --outdir $OUTDIR --logfile $logfile
+    add_standard_args run
+
+    # save the pageName for future reference below
+    options $pageName
+
+    # create the command line
+    if ($VERBOSE > 1)
+      echo command $run
+    end
+    command $run
+  end
+
+  # default exit status
+  task.exit    default
+    process_exit rcPendingDS $options:0 $JOB_STATUS
+  end
+
+  # operation timed out?
+  task.exit    timeout
+    showcommand timeout
+    book setword rcPendingDS $options:0 pantaskState TIMEOUT
+  end
+end
+
Index: /trunk/ippTools/share/disttool_pendingfileset.sql
===================================================================
--- /trunk/ippTools/share/disttool_pendingfileset.sql	(revision 23860)
+++ /trunk/ippTools/share/disttool_pendingfileset.sql	(revision 23861)
@@ -5,5 +5,8 @@
     stage_id,
     CONCAT_WS('.', distRun.outroot, CONVERT(distRun.dist_id, CHAR)) as dist_dir,
-    rcDSProduct.*
+    rcDSProduct.name AS product_name,
+    rcDSProduct.prod_id,
+    rcDSProduct.dbname AS ds_dbname,
+    rcDSProduct.dbhost AS ds_dbhost
 FROM rcDestination 
 JOIN rcInterest USING(dest_id) 
Index: /trunk/ippTools/src/disttool.c
===================================================================
--- /trunk/ippTools/src/disttool.c	(revision 23860)
+++ /trunk/ippTools/src/disttool.c	(revision 23861)
@@ -41,4 +41,5 @@
 static bool pendingfilesetMode(pxConfig *config);
 static bool addfilesetMode(pxConfig *config);
+static bool pendingdatastoresMode(pxConfig *config);
 
 # define MODECASE(caseName, func) \
@@ -71,4 +72,5 @@
         MODECASE(DISTTOOL_MODE_PENDINGFILESET, pendingfilesetMode);
         MODECASE(DISTTOOL_MODE_ADDFILESET, addfilesetMode);
+        MODECASE(DISTTOOL_MODE_PENDINGDATASTORES, pendingdatastoresMode);
         default:
             psAbort("invalid option (this should not happen)");
@@ -893,2 +895,75 @@
 }
 
+static bool pendingdatastoresMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
+#ifdef notyet
+
+    psMetadata *where = psMetadataAlloc();
+    PXOPT_COPY_S64(config->args, where, "-dist_id", "dist_id", "==");
+    PXOPT_COPY_STR(config->args, where, "-label", "label", "==");
+
+    PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
+    PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
+
+    // look for "inputs" that need to processed
+    psString query = pxDataGet("disttool_pendingfileset.sql");
+    if (!query) {
+        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
+        return false;
+    }
+
+    if (psListLength(where->list)) {
+        psString whereClause = psDBGenerateWhereConditionSQL(where, NULL);
+        psStringAppend(&query, " AND %s", whereClause);
+        psFree(whereClause);
+    }
+    psFree(where);
+
+    // treat limit == 0 as "no limit"
+    if (limit) {
+        psString limitString = psDBGenerateLimitSQL(limit);
+        psStringAppend(&query, " %s", limitString);
+        psFree(limitString);
+    }
+
+    if (!p_psDBRunQuery(config->dbh, query)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        psFree(query);
+        return false;
+    }
+    psFree(query);
+
+    psArray *output = p_psDBFetchResult(config->dbh);
+    if (!output) {
+        psErrorCode err = psErrorCodeLast();
+        switch (err) {
+            case PS_ERR_DB_CLIENT:
+                psError(PXTOOLS_ERR_SYS, false, "database error");
+            case PS_ERR_DB_SERVER:
+                psError(PXTOOLS_ERR_PROG, false, "database error");
+            default:
+                psError(PXTOOLS_ERR_PROG, false, "unknown error");
+        }
+
+        return false;
+    }
+    if (!psArrayLength(output)) {
+        psTrace("disttool", PS_LOG_INFO, "no rows found");
+        psFree(output);
+        return true;
+    }
+
+    if (psArrayLength(output)) {
+        // negative simple so the default is true
+        if (!ippdbPrintMetadatas(stdout, output, "pendingfileset", !simple)) {
+            psError(PS_ERR_UNKNOWN, false, "failed to print array");
+            psFree(output);
+            return false;
+        }
+    }
+
+    psFree(output);
+# endif // notdef
+    return true;
+}
Index: /trunk/ippTools/src/disttool.h
===================================================================
--- /trunk/ippTools/src/disttool.h	(revision 23860)
+++ /trunk/ippTools/src/disttool.h	(revision 23861)
@@ -35,4 +35,5 @@
     DISTTOOL_MODE_PENDINGFILESET,
     DISTTOOL_MODE_ADDFILESET,
+    DISTTOOL_MODE_PENDINGDATASTORES,
 } disttoolMode;
 
Index: /trunk/ippTools/src/disttoolConfig.c
===================================================================
--- /trunk/ippTools/src/disttoolConfig.c	(revision 23860)
+++ /trunk/ippTools/src/disttoolConfig.c	(revision 23861)
@@ -138,4 +138,13 @@
     psMetadataAddStr(addfilesetArgs, PS_LIST_TAIL, "-name", 0, "define file name", NULL);
     psMetadataAddS32(addfilesetArgs, PS_LIST_TAIL, "-fault", 0, "define fault code", 0);
+    //
+    // -pendingfileset
+    psMetadata *pendingdatastoresArgs = psMetadataAlloc();
+    psMetadataAddS64(pendingdatastoresArgs, PS_LIST_TAIL, "-dist_id", 0, "define dist_id", 0);
+    psMetadataAddStr(pendingdatastoresArgs, PS_LIST_TAIL, "-label",    0, "limit results to label", NULL);
+    psMetadataAddStr(pendingdatastoresArgs, PS_LIST_TAIL, "-stage",    0, "limit results to runs for stage", NULL);
+    psMetadataAddU64(pendingdatastoresArgs, PS_LIST_TAIL, "-limit",  0,  "limit result set to N items", 0);
+    psMetadataAddBool(pendingdatastoresArgs, PS_LIST_TAIL, "-simple", 0, "use the simple output format", false);
+
     psMetadata *argSets = psMetadataAlloc();
     psMetadata *modes = psMetadataAlloc();
@@ -151,4 +160,5 @@
     PXOPT_ADD_MODE("-pendingfileset",      "", DISTTOOL_MODE_PENDINGFILESET, pendingfilesetArgs);
     PXOPT_ADD_MODE("-addfileset",      "", DISTTOOL_MODE_ADDFILESET, addfilesetArgs);
+    PXOPT_ADD_MODE("-pendingdatastores",      "", DISTTOOL_MODE_PENDINGDATASTORES, pendingdatastoresArgs);
 
     if (!pxGetOptions(stderr, argc, argv, config, modes, argSets)) {
