Index: branches/simmosaic_branches/ippTools/src/disttool.c
===================================================================
--- branches/simmosaic_branches/ippTools/src/disttool.c	(revision 24860)
+++ branches/simmosaic_branches/ippTools/src/disttool.c	(revision 27839)
@@ -2,5 +2,5 @@
  * disttool.c
  *
- * Copyright (C) 2008
+ * Copyright (C) 2008-2009
  *
  * This program is free software; you can redistribute it and/or modify it
@@ -32,9 +32,9 @@
 
 static bool definebyqueryMode(pxConfig *config);
-static bool definerunMode(pxConfig *config);
 static bool updaterunMode(pxConfig *config);
 static bool revertrunMode(pxConfig *config);
 static bool pendingcomponentMode(pxConfig *config);
 static bool addprocessedcomponentMode(pxConfig *config);
+static bool revertcomponentMode(pxConfig *config);
 static bool processedcomponentMode(pxConfig *config);
 static bool toadvanceMode(pxConfig *config);
@@ -42,15 +42,15 @@
 static bool addfilesetMode(pxConfig *config);
 static bool revertfilesetMode(pxConfig *config);
+static bool updatefilesetMode(pxConfig *config);
 static bool queuercrunMode(pxConfig *config);
 static bool updatercrunMode(pxConfig *config);
 static bool revertrcrunMode(pxConfig *config);
 static bool pendingdestMode(pxConfig *config);
+static bool pendingcleanupMode(pxConfig *config);
+static bool listfilesetsMode(pxConfig *config);
 
 static bool definetargetMode(pxConfig *config);
 static bool updatetargetMode(pxConfig *config);
-static bool listtargetMode(pxConfig *config);
-
-static bool definedsproductMode(pxConfig *config);
-static bool updatedsproductMode(pxConfig *config);
+static bool listtargetsMode(pxConfig *config);
 
 static bool definedestinationMode(pxConfig *config);
@@ -59,4 +59,5 @@
 static bool defineinterestMode(pxConfig *config);
 static bool updateinterestMode(pxConfig *config);
+static bool listinterestsMode(pxConfig *config);
 
 # define MODECASE(caseName, func) \
@@ -80,5 +81,4 @@
     switch (config->mode) {
         MODECASE(DISTTOOL_MODE_DEFINEBYQUERY, definebyqueryMode);
-        MODECASE(DISTTOOL_MODE_DEFINERUN, definerunMode);
         MODECASE(DISTTOOL_MODE_UPDATERUN, updaterunMode);
         MODECASE(DISTTOOL_MODE_REVERTRUN, revertrunMode);
@@ -86,8 +86,12 @@
         MODECASE(DISTTOOL_MODE_ADDPROCESSEDCOMPONENT, addprocessedcomponentMode);
         MODECASE(DISTTOOL_MODE_PROCESSEDCOMPONENT, processedcomponentMode);
+        MODECASE(DISTTOOL_MODE_REVERTCOMPONENT, revertcomponentMode);
         MODECASE(DISTTOOL_MODE_TOADVANCE, toadvanceMode);
         MODECASE(DISTTOOL_MODE_PENDINGFILESET, pendingfilesetMode);
+        MODECASE(DISTTOOL_MODE_PENDINGCLEANUP, pendingcleanupMode);
         MODECASE(DISTTOOL_MODE_ADDFILESET, addfilesetMode);
         MODECASE(DISTTOOL_MODE_REVERTFILESET, revertfilesetMode);
+        MODECASE(DISTTOOL_MODE_LISTFILESETS, listfilesetsMode);
+        MODECASE(DISTTOOL_MODE_UPDATEFILESET, updatefilesetMode);
         MODECASE(DISTTOOL_MODE_QUEUERCRUN, queuercrunMode);
         MODECASE(DISTTOOL_MODE_UPDATERCRUN, updatercrunMode);
@@ -96,11 +100,10 @@
         MODECASE(DISTTOOL_MODE_DEFINETARGET, definetargetMode);
         MODECASE(DISTTOOL_MODE_UPDATETARGET, updatetargetMode);
-        MODECASE(DISTTOOL_MODE_LISTTARGET, listtargetMode);
-        MODECASE(DISTTOOL_MODE_DEFINEDSPRODUCT, definedsproductMode);
-        MODECASE(DISTTOOL_MODE_UPDATEDSPRODUCT, updatedsproductMode);
+        MODECASE(DISTTOOL_MODE_LISTTARGETS, listtargetsMode);
         MODECASE(DISTTOOL_MODE_DEFINEDESTINATION, definedestinationMode);
         MODECASE(DISTTOOL_MODE_UPDATEDESTINATION, updatedestinationMode);
         MODECASE(DISTTOOL_MODE_DEFINEINTEREST, defineinterestMode);
         MODECASE(DISTTOOL_MODE_UPDATEINTEREST, updateinterestMode);
+        MODECASE(DISTTOOL_MODE_LISTINTERESTS, listinterestsMode);
         default:
             psAbort("invalid option (this should not happen)");
@@ -124,45 +127,4 @@
 }
 
-static bool definerunMode(pxConfig *config)
-{
-    PS_ASSERT_PTR_NON_NULL(config, false);
-
-    // required
-    PXOPT_LOOKUP_STR(stage, config->args, "-stage", true, false);
-    PXOPT_LOOKUP_S64(stage_id, config->args, "-stage_id",  true, false);
-    PXOPT_LOOKUP_STR(outroot, config->args, "-outroot", true, false);
-    PXOPT_LOOKUP_S64(target_id, config->args, "-target_id",  true, false);
-
-    // optional
-    PXOPT_LOOKUP_BOOL(clean, config->args, "-clean", false);
-    PXOPT_LOOKUP_BOOL(no_magic, config->args, "-no_magic", false);
-    PXOPT_LOOKUP_STR(set_label, config->args, "-set_label", false, false);
-
-    // TODO: check that stage has an expected value
-    // XXX: all of the following concerns will be managed properly by definebyquery
-
-    // TODO: should we check that stage_id actually exists for stage
-    // in magicdstool we queue off of a magic_id so the stage_id, exp_id, and cam_id get looked up
-    // when the run is queued
-
-    if (!distRunInsert(config->dbh,
-            0,          // dist_id
-            target_id,
-            stage,
-            stage_id,
-            set_label,
-            outroot,
-            clean,
-            no_magic,
-            "new",
-            NULL,       // time_stamp
-            0           // fault
-            )) {
-        psError(PS_ERR_UNKNOWN, false, "database error");
-        return false;
-    }
-
-    return true;
-}
 
 static bool definebyqueryMode(pxConfig *config)
@@ -175,11 +137,25 @@
 
     // optional
-    PXOPT_LOOKUP_S64(magic_ds_id, config->args, "-magic_ds_id",  false, false);
+    PXOPT_LOOKUP_BOOL(use_alternate, config->args, "-use_alternate", false);
     PXOPT_LOOKUP_BOOL(no_magic, config->args, "-no_magic", false);
     PXOPT_LOOKUP_STR(set_label, config->args, "-set_label", false, false);
+    PXOPT_LOOKUP_STR(set_data_group, config->args, "-set_data_group", false, false);
+    PXOPT_LOOKUP_STR(set_note, config->args, "-set_note", false, false);
+
     PXOPT_LOOKUP_S64(limit, config->args, "-limit", false, false);
     PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
-    
-    PXOPT_LOOKUP_BOOL(dry_run, config->args, "-dry_run", false);
+
+    PXOPT_LOOKUP_BOOL(pretend, config->args, "-pretend", false);
+
+    if (use_alternate) { 
+        if (strcmp(stage, "raw")) {
+            psError(PXTOOLS_ERR_SYS, true, "alternate inputs only supported for raw stage");
+            return false;
+        }
+        if (no_magic) {
+            psError(PXTOOLS_ERR_SYS, true, "no_magic forbidden with alternate inputs");
+            return false;
+        }
+    }
 
     // select arguments
@@ -191,4 +167,5 @@
 
     PXOPT_LOOKUP_STR(label, config->args, "-label", false, false);
+    PXOPT_LOOKUP_STR(dist_group, config->args, "-dist_group", false, false);
 
     psString query = NULL;
@@ -196,16 +173,24 @@
     psString runJoinStr = NULL;
     if (!strcmp(stage, "raw")) {
-        magicRunType = "rawExp";
-        runJoinStr = "rawExp.exp_id";
+        if (! use_alternate ) {
+            magicRunType = "rawExp";
+            runJoinStr = "rawExp.exp_id";
+        } else {
+            magicRunType = "camRun";
+            runJoinStr = "camRun.exp_id";
+        }
         query = pxDataGet("disttool_definebyquery_raw.sql");
         if (!query) {
-            psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
+            psError(PXTOOLS_ERR_SYS, false, "failed to retreive SQL statement");
             psFree(where);
             return false;
         }
 
-        // for raw stage we select by chipRun.label because raw labels typically aren't set
+        // for raw stage we select by camRun.label and dist_group because rawExp doesn't have those columns
         if (label) {
-            psStringAppend(&query, " AND (chipRun.label = '%s')", label);
+            psStringAppend(&query, " AND (magicDSRun.label = '%s')", label);
+        }
+        if (dist_group) {
+            psStringAppend(&query, " AND (camRun.dist_group = '%s')", dist_group);
         }
     } else if (!strcmp(stage, "chip")) {
@@ -214,5 +199,5 @@
         query = pxDataGet("disttool_definebyquery_chip.sql");
         if (!query) {
-            psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
+            psError(PXTOOLS_ERR_SYS, false, "failed to retreive SQL statement");
             psFree(where);
             return false;
@@ -222,9 +207,13 @@
             psStringAppend(&query, " AND (chipRun.label = '%s')", label);
         }
+        if (dist_group) {
+            psStringAppend(&query, " AND (chipRun.dist_group = '%s')", dist_group);
+        }
     } else if (!strcmp(stage, "camera")) {
-        magicRunType = "chipRun";    // This is used below to set the magicked business
+        magicRunType = "camRun";    // This is used below to set the magicked business
+        runJoinStr = "camRun.cam_id";
         query = pxDataGet("disttool_definebyquery_camera.sql");
         if (!query) {
-            psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
+            psError(PXTOOLS_ERR_SYS, false, "failed to retreive SQL statement");
             psFree(where);
             return false;
@@ -233,4 +222,7 @@
         if (label) {
             psStringAppend(&query, " AND (camRun.label = '%s')", label);
+        }
+        if (dist_group) {
+            psStringAppend(&query, " AND (camRun.dist_group = '%s')", dist_group);
         }
     } else if (!strcmp(stage, "fake")) {
@@ -238,5 +230,5 @@
         query = pxDataGet("disttool_definebyquery_fake.sql");
         if (!query) {
-            psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
+            psError(PXTOOLS_ERR_SYS, false, "failed to retreive SQL statement");
             psFree(where);
             return false;
@@ -245,4 +237,7 @@
         if (label) {
             psStringAppend(&query, " AND (fakeRun.label = '%s')", label);
+        }
+        if (dist_group) {
+            psStringAppend(&query, " AND (fakeRun.dist_group = '%s')", dist_group);
         }
         // fake stage doesn't require magic
@@ -253,5 +248,5 @@
         query = pxDataGet("disttool_definebyquery_warp.sql");
         if (!query) {
-            psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
+            psError(PXTOOLS_ERR_SYS, false, "failed to retreive SQL statement");
             psFree(where);
             return false;
@@ -260,4 +255,7 @@
         if (label) {
             psStringAppend(&query, " AND (warpRun.label = '%s')", label);
+        }
+        if (dist_group) {
+            psStringAppend(&query, " AND (warpRun.dist_group = '%s')", dist_group);
         }
 
@@ -267,5 +265,5 @@
         query = pxDataGet("disttool_definebyquery_diff.sql");
         if (!query) {
-            psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
+            psError(PXTOOLS_ERR_SYS, false, "failed to retreive SQL statement");
             psFree(where);
             return false;
@@ -274,4 +272,7 @@
         if (label) {
             psStringAppend(&query, " AND (diffRun.label = '%s')", label);
+        }
+        if (dist_group) {
+            psStringAppend(&query, " AND (diffRun.dist_group = '%s')", dist_group);
         }
 
@@ -280,5 +281,5 @@
         query = pxDataGet("disttool_definebyquery_stack.sql");
         if (!query) {
-            psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
+            psError(PXTOOLS_ERR_SYS, false, "failed to retreive SQL statement");
             psFree(where);
             return false;
@@ -288,10 +289,38 @@
             psStringAppend(&query, " AND (stackRun.label = '%s')", label);
         }
-        // stack stage doesn't require magic (perhaps let the script do this?
+        if (dist_group) {
+            psStringAppend(&query, " AND (stackRun.dist_group = '%s')", dist_group);
+        }
+        // stack stage doesn't require magic
         no_magic = true;
+    } else if (!strcmp(stage, "SSdiff")) {
+      magicRunType = "diffRun";
+      runJoinStr = "diffRun.diff_id";
+      query = pxDataGet("disttool_definebyquery_SSdiff.sql");
+      if (!query) {
+	psError(PXTOOLS_ERR_SYS, false, "failed to retrieve SQL statement");
+	psFree(where);
+	return(false);
+      }
+
+      if (label) {
+	psStringAppend(&query, " AND (diffRun.label = '%s') ", label);
+      }
+      if (dist_group) {
+	psStringAppend(&query, " AND (diffRun.dist_group = '%s') ", dist_group);
+      }
+
+      no_magic = true;    
     } else {
         psError(PS_ERR_UNKNOWN, true, "unknown value for stage: %s", stage);
         psFree(where);
         return false;
+    }
+
+    if (!strcmp(stage, "raw")) {
+        if (!no_magic) {
+            psStringAppend(&query, " AND (magicDSRun.re_place = %d)", !use_alternate);
+            psStringAppend(&query, " AND (camRun.state = 'full')");
+        }
     }
 
@@ -306,26 +335,5 @@
 
     if (!no_magic) {
-        psStringAppend(&query, " AND (distTarget.clean OR %s.magicked)", magicRunType);
-
-        // is selecting by magic_ds_id really interesting?
-        if (magic_ds_id) {
-            if (strcmp(stage, "camera")) {
-                // stage other than camera
-                if (!runJoinStr) {
-                    psError(PS_ERR_PROGRAMMING, true, "cannot select by magic_ds_id for stage: %s", stage);
-                    psFree(query);
-                    return false;
-                }
-                psStringAppend(&joinHook, "\nJOIN magicDSRun ON magicDSRun.stage = distTarget.stage"
-                                              " AND magicDSRun.stage_id = %s", runJoinStr);
-            } else {
-                // camera masks are magicked when the chipRun is magicked
-                // XXX: This is confusing. Is it dangerous?
-                // Maybe I should add a magicked bit to camRun. Note this isn't
-                psStringAppend(&joinHook, "\nJOIN magicDSRun ON magicDSRun.stage = 'chip'"
-                                              " AND magicDSRun.stage_id = chipRun.chip_id");
-            }
-            psStringAppend(&query, " AND (magicDSRun.state = 'full' AND magicDSRun.re_place AND (magic_ds_id = %" PRId64 "))", magic_ds_id);
-        }
+        psStringAppend(&query, " AND (%s.magicked > 0)", magicRunType);
     }
 
@@ -335,9 +343,9 @@
         psFree(limitString);
     }
-
+    psTrace("disttool",2,query,joinHook ? joinHook : "");
     if (!p_psDBRunQueryF(config->dbh, query, joinHook ? joinHook : "")) {
-        psError(PS_ERR_UNKNOWN, false, "database error");
-        psFree(query);
-        return false;
+      psError(PS_ERR_UNKNOWN, false, "database error");
+      psFree(query);
+      return false;
     }
     psFree(query);
@@ -356,5 +364,5 @@
 
 
-    if (dry_run) {
+    if (pretend) {
         if (!ippdbPrintMetadatas(stdout, output, "newdistRuns", true)) {
             psError(PS_ERR_UNKNOWN, false, "failed to print array");
@@ -377,14 +385,26 @@
         psString run_tag = psMetadataLookupStr(NULL, md, "run_tag");
         psS64 stage_id = psMetadataLookupS64(NULL, md, "stage_id");
+        psS64 magic_ds_id = psMetadataLookupS64(NULL, md, "magicked");
         psS64 target_id = psMetadataLookupS64(NULL, md, "target_id");
-        psString target_label = psMetadataLookupStr(NULL, md, "label");
+        psString stage_label = psMetadataLookupStr(NULL, md, "label");
+        psString stage_data_group = psMetadataLookupStr(NULL, md, "data_group");
         bool clean = psMetadataLookupBool(NULL, md, "clean");
 
         psString outroot = NULL;
-        psStringAppend(&outroot, "%s/%s/%s", workdir, run_tag, stage); 
-
-        if (set_label == NULL) {
-            set_label = target_label;
-        }
+        psStringAppend(&outroot, "%s/%s/%s", workdir, run_tag, stage);
+
+        psString new_label;
+        if (set_label != NULL) {
+            new_label = set_label;
+        } else {
+            new_label = stage_label;
+        }
+        psString new_data_group;
+        if (set_data_group != NULL) {
+            new_data_group = set_data_group;
+        } else {
+            new_data_group = stage_data_group;
+        }
+
         distRunRow *row = distRunRowAlloc(
                 0,      // dist_id
@@ -392,11 +412,16 @@
                 stage,
                 stage_id,
-                set_label,
+                magic_ds_id,
+                new_label,
                 outroot,
+                NULL,     // outdir
                 clean,
                 no_magic,
+                use_alternate,
                 "new",
-                NULL,   // time_stamp
-                0       // fault
+                NULL,    // time_stamp
+                0,       // fault
+                new_data_group,
+                set_note // note does not propagate
                 );
 
@@ -441,10 +466,13 @@
     PXOPT_COPY_S64(config->args, where, "-dist_id", "dist_id", "==");
     PXOPT_COPY_STR(config->args, where, "-stage", "stage", "==");;
-    PXOPT_COPY_STR(config->args, where, "-state", "state", "==");
+    PXOPT_COPY_STR(config->args, where, "-state", "distRun.state", "==");
     PXOPT_COPY_STR(config->args, where, "-label", "label", "==");
+    PXOPT_COPY_STR(config->args, where, "-data_group", "distRun.data_group", "LIKE");
+    PXOPT_COPY_STR(config->args, where, "-dist_group", "distTarget.dist_group", "==");
+    PXOPT_COPY_STR(config->args, where, "-label", "label", "==");
 
     if (!psListLength(where->list)) {
         psFree(where);
-        psError(PXTOOLS_ERR_DATA, false, "search parameters are required");
+        psError(PXTOOLS_ERR_CONFIG, false, "search parameters are required");
         return false;
     }
@@ -452,25 +480,40 @@
     PXOPT_LOOKUP_STR(state, config->args, "-set_state", false, false);
     PXOPT_LOOKUP_STR(label, config->args, "-set_label", false, false);
+    PXOPT_LOOKUP_STR(data_group, config->args, "-set_data_group", false, false);
+    PXOPT_LOOKUP_STR(outdir, config->args, "-set_outdir", false, false);
     PXOPT_LOOKUP_S16(fault, config->args, "-fault", false, false);
-
-    if ((!state) && (!label) && (!fault)) {
-        psError(PXTOOLS_ERR_DATA, false, "parameters (-fault or -set_state or -set_label) are required");
-        psFree(where);
-        return false;
-    }
-
-    psString query = psStringCopy("UPDATE distRun SET time_stamp = UTC_TIMESTAMP()");
-
+    PXOPT_LOOKUP_STR(set_note, config->args, "-set_note", false, false);
+
+    if ((!state) && (!label) && (!fault) &&(!data_group)) {
+        psError(PXTOOLS_ERR_CONFIG, false, "parameters (-fault or -set_state or -set_label -set_data_group) are required");
+        psFree(where);
+        return false;
+    }
+
+    psString query = psStringCopy("UPDATE distRun join distTarget using(target_id, stage) SET distRun.time_stamp = UTC_TIMESTAMP()");
+
+    if (outdir) {
+        psStringAppend(&query, " , distRun.outdir = '%s'", outdir);
+    }
     if (state) {
-        psStringAppend(&query, " , state = '%s'", state);
+        psStringAppend(&query, " , distRun.state = '%s'", state);
     }
 
     if (label) {
-        psStringAppend(&query, " , label = '%s'", label);
+        psStringAppend(&query, " , distRun.label = '%s'", label);
     }
 
     if (fault) {
-        psStringAppend(&query, " , fault = %d", fault);
-    }
+        psStringAppend(&query, " , distRun.fault = %d", fault);
+    }
+
+    if (data_group) {
+        psStringAppend(&query, " , distRun.data_group = '%s'", data_group);
+    }
+
+    if (set_note) {
+        psStringAppend(&query, " , distRun.note = '%s'", set_note);
+    }
+
 
     psString whereClause = psDBGenerateWhereConditionSQL(where, NULL);
@@ -497,8 +540,5 @@
     PXOPT_COPY_STR(config->args, where, "-label", "label", "==");
 
-    // we need to disambiguate fault so make a copy of the where list before adding fault
-    psMetadata *whereComponent = psMetadataCopy(NULL, where);
     PXOPT_COPY_S16(config->args, where,  "-fault", "distRun.fault", "==");
-    PXOPT_COPY_S16(config->args, whereComponent, "-fault", "distComponent.fault", "==");
 
     // It might be useful to be able to query by the parameters of the underlying runs
@@ -506,88 +546,81 @@
     if (!psListLength(where->list) && !psMetadataLookupBool(NULL, config->args, "-all")) {
         psFree(where);
-        psError(PXTOOLS_ERR_DATA, false, "search parameters are required");
-        return false;
-    }
-
-    if (!psDBTransaction(config->dbh)) {
-        psError(PS_ERR_UNKNOWN, false, "database error");
-        psFree(where);
-        return false;
-    }
-
-    // Update state to 'new'
-    int numUpdated;                     // Number updated
-    {
-        psString query = pxDataGet("disttool_revertrun_update.sql");
-        if (!query) {
-            psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
-            if (!psDBRollback(config->dbh)) {
-                psError(PS_ERR_UNKNOWN, false, "database error");
-            }
-            return false;
-        }
-
-        if (psListLength(where->list)) {
-            psString whereClause = psDBGenerateWhereConditionSQL(where, NULL);
-            psStringAppend(&query, " AND %s", whereClause);
-            psFree(whereClause);
-        }
-
-        if (!p_psDBRunQuery(config->dbh, query)) {
+        psError(PXTOOLS_ERR_CONFIG, false, "search parameters are required");
+        return false;
+    }
+
+    psString query = pxDataGet("disttool_revertrun.sql");
+    if (!query) {
+        psError(PXTOOLS_ERR_SYS, false, "failed to retreive SQL statement");
+        if (!psDBRollback(config->dbh)) {
             psError(PS_ERR_UNKNOWN, false, "database error");
-            psFree(query);
-            if (!psDBRollback(config->dbh)) {
-                psError(PS_ERR_UNKNOWN, false, "database error");
-            }
-            return false;
-        }
-        psFree(query);
-
-        numUpdated = psDBAffectedRows(config->dbh);
-    }
+        }
+        return false;
+    }
+
+    if (psListLength(where->list)) {
+        psString whereClause = psDBGenerateWhereConditionSQL(where, NULL);
+        psStringAppend(&query, " AND %s", whereClause);
+        psFree(whereClause);
+    }
+    psFree(where);
+
+    if (!p_psDBRunQuery(config->dbh, query)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        psFree(query);
+        return false;
+    }
+
+    int numUpdated = psDBAffectedRows(config->dbh);
 
     psLogMsg("disttool", PS_LOG_INFO, "Updated %d dist runs", numUpdated);
 
-    // Delete product
-    int numDeleted;                     // Number deleted
-    {
-        psString query = pxDataGet("disttool_revertrun_delete.sql");
-        if (!query) {
-            psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
-            if (!psDBRollback(config->dbh)) {
-                psError(PS_ERR_UNKNOWN, false, "database error");
-            }
-            return false;
-        }
-
-        if (psListLength(whereComponent->list)) {
-            psString whereClause = psDBGenerateWhereConditionSQL(whereComponent, NULL);
-            psStringAppend(&query, " AND %s", whereClause);
-            psFree(whereClause);
-        }
-
-        if (!p_psDBRunQuery(config->dbh, query)) {
-            psError(PS_ERR_UNKNOWN, false, "database error");
-            psFree(query);
-            if (!psDBRollback(config->dbh)) {
-                psError(PS_ERR_UNKNOWN, false, "database error");
-            }
-            return false;
-        }
-        psFree(query);
-
-        numDeleted = psDBAffectedRows(config->dbh);
-    }
+    return true;
+}
+
+static bool revertcomponentMode(pxConfig *config)
+{
+    psMetadata *where = psMetadataAlloc();
+    PXOPT_COPY_S64(config->args, where, "-dist_id", "distRun.dist_id", "==");
+    PXOPT_COPY_STR(config->args, where, "-stage", "stage", "==");;
+    PXOPT_COPY_STR(config->args, where, "-component", "component", "==");;
+    PXOPT_COPY_S64(config->args, where, "-stage_id", "stage_id", "==");
+    PXOPT_COPY_STR(config->args, where, "-state", "state", "==");
+    pxAddLabelSearchArgs(config, where, "-label", "distRun.label", "==");
+
+    PXOPT_COPY_S16(config->args, where,  "-fault", "distComponent.fault", "==");
+
+    // It might be useful to be able to query by the parameters of the underlying runs
+
+    if (!psListLength(where->list) && !psMetadataLookupBool(NULL, config->args, "-all")) {
+        psFree(where);
+        psError(PXTOOLS_ERR_CONFIG, false, "search parameters are required");
+        return false;
+    }
+
+    psString query = pxDataGet("disttool_revertcomponent.sql");
+    if (!query) {
+        psError(PXTOOLS_ERR_SYS, false, "failed to retreive SQL statement");
+        psFree(where);
+        return false;
+    }
+
+    if (psListLength(where->list)) {
+        psString whereClause = psDBGenerateWhereConditionSQL(where, NULL);
+        psStringAppend(&query, " AND %s", whereClause);
+        psFree(whereClause);
+    }
+    psFree(where);
+
+    if (!p_psDBRunQuery(config->dbh, query)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        psFree(query);
+        return false;
+    }
+
+    int numDeleted = psDBAffectedRows(config->dbh);
 
     psLogMsg("disttool", PS_LOG_INFO, "Deleted %d distComponents", numDeleted);
 
-    psFree(where);
-    psFree(whereComponent);
-
-    if (!psDBCommit(config->dbh)) {
-        psError(PS_ERR_UNKNOWN, false, "database error");
-        return false;
-    }
-
     return true;
 }
@@ -597,16 +630,18 @@
     PS_ASSERT_PTR_NON_NULL(config, false);
 
-    psMetadata *where = psMetadataAlloc();
-    PXOPT_COPY_S64(config->args, where, "-dist_id", "dist_id", "==");
-    PXOPT_COPY_STR(config->args, where, "-stage", "stage", "==");
-    pxAddLabelSearchArgs (config, where, "-label", "label", "==");
+    PXOPT_LOOKUP_STR(stage, config->args, "-stage", true, false);
+
+    psMetadata *where = psMetadataAlloc();
+    PXOPT_COPY_S64(config->args, where, "-dist_id", "distRun.dist_id", "==");
+    pxAddLabelSearchArgs (config, where, "-label", "distRun.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_pendingcomponent.sql");
+    psString queryFile = NULL;
+    psStringAppend(&queryFile, "disttool_pending_%s.sql", stage);
+    psString query = pxDataGet(queryFile);
     if (!query) {
-        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
+        psError(PXTOOLS_ERR_SYS, false, "failed to retreive SQL statement from %s", queryFile);
         return false;
     }
@@ -614,5 +649,5 @@
     if (psListLength(where->list)) {
         psString whereClause = psDBGenerateWhereConditionSQL(where, NULL);
-        psStringAppend(&query, " WHERE %s", whereClause);
+        psStringAppend(&query, " AND %s", whereClause);
         psFree(whereClause);
     }
@@ -626,28 +661,5 @@
     }
 
-    // the query has where hooks for each stage.
-    // right now we aren't using them.
-    // XXX: I think that I want to change the query from a union of selects on the various
-    // stages to separate queries. As it is pending data at the later stages of the pipline
-    // will get blocked by pending earlier stages
-    psString    raw_where = "";
-    psString    raw_clean_where = "";
-    psString    chip_where = "";
-    psString    camera_where = "";
-    psString    fake_where = "";
-    psString    warp_where = "";
-    psString    diff_where = "";
-    psString    stack_where = "";
-
-    if (!p_psDBRunQueryF(config->dbh,
-            query,
-            raw_where,
-            raw_clean_where,
-            chip_where,
-            camera_where,
-            fake_where,
-            warp_where,
-            diff_where,
-            stack_where)) {
+    if (!p_psDBRunQuery(config->dbh, query)) {
         psError(PS_ERR_UNKNOWN, false, "database error");
         psFree(query);
@@ -705,7 +717,8 @@
     PXOPT_LOOKUP_S32(bytes, config->args, "-bytes", require_fileinfo, false);
     PXOPT_LOOKUP_STR(md5sum, config->args, "-md5sum", require_fileinfo, false);
+    PXOPT_LOOKUP_STR(outdir, config->args, "-outdir", require_fileinfo, false);
     PXOPT_LOOKUP_STR(name, config->args, "-name", require_fileinfo, false);
 
-    if (!distComponentInsert(config->dbh, dist_id, component, bytes, md5sum, "full", name, fault)) {
+    if (!distComponentInsert(config->dbh, dist_id, component, bytes, md5sum, "full", outdir, name, fault)) {
         psError(PS_ERR_UNKNOWN, false, "database error");
         return false;
@@ -729,5 +742,5 @@
     psString query = pxDataGet("disttool_toadvance.sql");
     if (!query) {
-        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
+        psError(PXTOOLS_ERR_SYS, false, "failed to retreive SQL statement");
         return false;
     }
@@ -800,5 +813,5 @@
     psString query = pxDataGet("disttool_processedcomponent.sql");
     if (!query) {
-        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
+        psError(PXTOOLS_ERR_SYS, false, "failed to retreive SQL statement");
         return false;
     }
@@ -865,4 +878,5 @@
     psMetadata *where = psMetadataAlloc();
     PXOPT_COPY_S64(config->args, where, "-dist_id", "dist_id", "==");
+    PXOPT_COPY_STR(config->args, where, "-stage", "distRun.stage", "==");
     pxAddLabelSearchArgs (config, where, "-label", "distRun.label", "==");
 
@@ -873,5 +887,5 @@
     psString query = pxDataGet("disttool_pendingfileset.sql");
     if (!query) {
-        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
+        psError(PXTOOLS_ERR_SYS, false, "failed to retreive SQL statement");
         return false;
     }
@@ -936,5 +950,5 @@
     // required values
     PXOPT_LOOKUP_S64(dist_id, config->args, "-dist_id", true, false);
-    PXOPT_LOOKUP_S64(prod_id, config->args, "-prod_id", true, false);
+    PXOPT_LOOKUP_S64(dest_id, config->args, "-dest_id", true, false);
 
     PXOPT_LOOKUP_S16(fault, config->args, "-fault", false, false);
@@ -943,8 +957,8 @@
     PXOPT_LOOKUP_STR(name, config->args, "-name", fault == 0, false);
 
-    if (!rcDSFilesetInsert(config->dbh, 
+    if (!rcDSFilesetInsert(config->dbh,
             0,          // fs_id
             dist_id,
-            prod_id,
+            dest_id,
             name,
             "full",
@@ -956,4 +970,5 @@
     return true;
 }
+
 static bool revertfilesetMode(pxConfig *config)
 {
@@ -961,5 +976,5 @@
     PXOPT_COPY_S64(config->args, where, "-fs_id", "fs_id", "==");
     PXOPT_COPY_S64(config->args, where, "-dist_id", "rcDSFileset.dist_id", "==");
-    PXOPT_COPY_S64(config->args, where, "-prod_id", "prod_id", "==");
+    PXOPT_COPY_S64(config->args, where, "-dest_id", "dest_id", "==");
     PXOPT_COPY_STR(config->args, where, "-stage", "stage", "==");;
     PXOPT_COPY_S64(config->args, where, "-stage_id", "stage_id", "==");
@@ -972,5 +987,5 @@
     if (!psListLength(where->list) && !psMetadataLookupBool(NULL, config->args, "-all")) {
         psFree(where);
-        psError(PXTOOLS_ERR_DATA, false, "search parameters are required");
+        psError(PXTOOLS_ERR_CONFIG, false, "search parameters are required");
         return false;
     }
@@ -978,5 +993,5 @@
     psString query = pxDataGet("disttool_revertfileset.sql");
     if (!query) {
-        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
+        psError(PXTOOLS_ERR_SYS, false, "failed to retreive SQL statement");
         psFree(where);
         return false;
@@ -1020,5 +1035,5 @@
     psString query = pxDataGet("disttool_pendingdest.sql");
     if (!query) {
-        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
+        psError(PXTOOLS_ERR_SYS, false, "failed to retreive SQL statement");
         return false;
     }
@@ -1089,5 +1104,4 @@
     PXOPT_COPY_S64(config->args, where, "-dist_id",  "dist_id", "==");
     PXOPT_COPY_S64(config->args, where, "-dest_id",  "dest_id", "==");
-    PXOPT_COPY_S64(config->args, where, "-prod_id",  "prod_id", "==");
     PXOPT_COPY_S64(config->args, where, "-target_id","target_id", "==");
     PXOPT_COPY_S64(config->args, where, "-fs_id",    "fs_id", "==");
@@ -1100,5 +1114,5 @@
     psString query = pxDataGet("disttool_queuercrun.sql");
     if (!query) {
-        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
+        psError(PXTOOLS_ERR_SYS, false, "failed to retreive SQL statement");
         return false;
     }
@@ -1146,5 +1160,5 @@
     // We either need rc_id or (dest_id and fs_name) to identifiy the rcRun
     if ((!rc_id) && !(dest_id && fs_name)) {
-        psError(PXTOOLS_ERR_DATA, true, "either -rc_id or (-fs_name and -dest_id) are required");
+        psError(PXTOOLS_ERR_CONFIG, true, "either -rc_id or (-fs_name and -dest_id) are required");
         return false;
     }
@@ -1158,5 +1172,5 @@
         // this can't happen because we checked above
         psFree(where);
-        psError(PXTOOLS_ERR_DATA, false, "search parameters are required");
+        psError(PXTOOLS_ERR_CONFIG, false, "search parameters are required");
         return false;
     }
@@ -1168,5 +1182,5 @@
 
     if (!state && (fault < 0)) {
-        psError(PXTOOLS_ERR_DATA, false, "parameters (-fault or -set_state) are required");
+        psError(PXTOOLS_ERR_CONFIG, false, "parameters (-fault or -set_state) are required");
         psFree(where);
         return false;
@@ -1175,5 +1189,5 @@
     psString query = pxDataGet("disttool_updatercrun.sql");
     if (!query) {
-        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
+        psError(PXTOOLS_ERR_SYS, false, "failed to retreive SQL statement");
         return false;
     }
@@ -1232,5 +1246,5 @@
     if (!psListLength(where->list) && !psMetadataLookupBool(NULL, config->args, "-all")) {
         psFree(where);
-        psError(PXTOOLS_ERR_DATA, false, "search parameters are required");
+        psError(PXTOOLS_ERR_CONFIG, false, "search parameters are required");
         return false;
     }
@@ -1238,5 +1252,5 @@
     psString query = pxDataGet("disttool_revertrcrun.sql");
     if (!query) {
-        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
+        psError(PXTOOLS_ERR_SYS, false, "failed to retreive SQL statement");
         if (!psDBRollback(config->dbh)) {
             psError(PS_ERR_UNKNOWN, false, "database error");
@@ -1273,5 +1287,5 @@
 
     // required
-    PXOPT_LOOKUP_STR(label, config->args, "-label", true, false);
+    PXOPT_LOOKUP_STR(dist_group, config->args, "-dist_group", true, false);
     PXOPT_LOOKUP_STR(filter, config->args, "-filter", true, false);
     PXOPT_LOOKUP_STR(stage, config->args, "-stage", true, false);
@@ -1284,5 +1298,5 @@
     distTargetRow *row = distTargetRowAlloc(
             0,          // target_id
-            label,
+            dist_group,
             filter,
             stage,
@@ -1291,5 +1305,5 @@
             comment
             );
-            
+
     if (!row) {
         psError(PS_ERR_UNKNOWN, false, "failed to allocate distTarget object");
@@ -1321,5 +1335,5 @@
     psMetadata *where = psMetadataAlloc();
     PXOPT_COPY_S64(config->args, where, "-target_id", "target_id", "==");
-    PXOPT_COPY_STR(config->args, where, "-label", "label", "==");
+    PXOPT_COPY_STR(config->args, where, "-dist_group", "dist_group", "==");
     PXOPT_COPY_STR(config->args, where, "-filter", "filter", "==");
     PXOPT_COPY_STR(config->args, where, "-stage", "stage", "==");
@@ -1351,5 +1365,5 @@
 }
 
-static bool listtargetMode(pxConfig *config)
+static bool listtargetsMode(pxConfig *config)
 {
     PS_ASSERT_PTR_NON_NULL(config, false);
@@ -1357,5 +1371,5 @@
     psMetadata *where = psMetadataAlloc();
     PXOPT_COPY_S64(config->args, where, "-target_id", "target_id", "==");
-    PXOPT_COPY_STR(config->args, where, "-label", "label", "==");
+    PXOPT_COPY_STR(config->args, where, "-dist_group", "dist_group", "LIKE");
     PXOPT_COPY_STR(config->args, where, "-filter", "filter", "==");
     PXOPT_COPY_STR(config->args, where, "-stage", "stage", "==");
@@ -1430,27 +1444,37 @@
 }
 
-static bool definedsproductMode(pxConfig *config)
+static bool definedestinationMode(pxConfig *config)
 {
     PS_ASSERT_PTR_NON_NULL(config, false);
 
     // required
-    PXOPT_LOOKUP_STR(name, config->args,   "-name", true, false);
-    PXOPT_LOOKUP_STR(dbname, config->args, "-ds_dbname", true, false);
-    PXOPT_LOOKUP_STR(dbhost, config->args, "-ds_dbhost", true, false);
+    PXOPT_LOOKUP_STR(name, config->args,         "-name", true, false);
+    PXOPT_LOOKUP_STR(dbname, config->args,       "-ds_dbname", true, false);
+    PXOPT_LOOKUP_STR(dbhost, config->args,       "-ds_dbhost", true, false);
+
+    // optional
+    PXOPT_LOOKUP_STR(status_uri, config->args,   "-status_uri", false, false);
+    PXOPT_LOOKUP_STR(comment, config->args,      "-comment", false, false);
+    PXOPT_LOOKUP_STR(last_fileset, config->args, "-last_fileset", false, false);
+    PXOPT_LOOKUP_STR(state, config->args,        "-set_state", false, false);
 
     // XXX: should we insure that these names do not contatin any whitespace?
 
-    rcDSProductRow *row = rcDSProductRowAlloc(
-            0,          // prod_id
+    rcDestinationRow *row = rcDestinationRowAlloc(
+            0,          // dest_id
             name,
+            status_uri,
+            comment,
+            last_fileset,
             dbname,
-            dbhost
+            dbhost,
+            state ? state : "enabled"
             );
-            
+
     if (!row) {
-        psError(PS_ERR_UNKNOWN, false, "failed to allocate rcDSProduct object");
-        return false;
-    }
-   if (!rcDSProductInsertObject(config->dbh, row)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to allocate rcDestination object");
+        return false;
+    }
+   if (!rcDestinationInsertObject(config->dbh, row)) {
         psError(PS_ERR_UNKNOWN, false, "database error");
         psFree(row);
@@ -1459,7 +1483,7 @@
 
     // get the assigned target_id
-    row->prod_id = psDBLastInsertID(config->dbh);
-
-    if (!rcDSProductPrintObject(stdout, row, true)) {
+    row->dest_id = psDBLastInsertID(config->dbh);
+
+    if (!rcDestinationPrintObject(stdout, row, true)) {
         psError(PS_ERR_UNKNOWN, false, "failed to print object");
         psFree(row);
@@ -1471,28 +1495,37 @@
     return true;
 }
-static bool updatedsproductMode(pxConfig *config)
+
+static bool updatedestinationMode(pxConfig *config)
 {
     PS_ASSERT_PTR_NON_NULL(config, false);
 
     psMetadata *where = psMetadataAlloc();
-    PXOPT_COPY_S64(config->args, where, "-prod_id", "prod_id", "==");
-
-    PXOPT_LOOKUP_STR(dbname, config->args, "-ds_dbname", false, false);
-    PXOPT_LOOKUP_STR(dbhost, config->args, "-ds_dbhost", false, false);
-
-    if (!(dbname || dbhost)) {
-        psError(PS_ERR_UNKNOWN, true, "one or more of dbname or dbhost is required");
-        psFree(where);
-        return false;
-    }
-    psString query = psStringCopy("UPDATE rcDSProduct SET");
+    PXOPT_COPY_S64(config->args, where, "-dest_id", "dest_id", "==");
+
+    PXOPT_LOOKUP_STR(state, config->args, "-set_state", false, false);
+#ifdef ALLOW_UPDATE_LAST_FILESET
+    PXOPT_LOOKUP_STR(last_fileset, config->args, "-set_last_fileset", false, false);
+    if (!(state || last_fileset)) {
+        psError(PS_ERR_UNKNOWN, true, "one or more of -set_state or -set_last_fileset is required");
+# else
+    if (!state) {
+#endif
+        psFree(where);
+        return false;
+    }
+    psString query = psStringCopy("UPDATE rcDestination SET");
     psString sep = "";
-    if (dbname) {
-        psStringAppend(&query, " dbname = '%s'", dbname);
+    if (state) {
+        psStringAppend(&query, " state = '%s'", state);
         sep = ",";
     }
-    if (dbhost) {
-        psStringAppend(&query, " %s dbhost = '%s'", sep, dbhost);
-    }
+#ifdef ALLOW_UPDATE_LAST_FILESET
+    // last_fileset normally gets set by updatercrunMode
+    // Allowing it to be set here might cause problems
+    // especially since we are allowing selection by dest_id
+    if (last_fileset) {
+        psStringAppend(&query, " %s last_fileset = '%s'", sep, last_fileset);
+    }
+#endif
 
     if (psListLength(where->list)) {
@@ -1518,87 +1551,142 @@
 }
 
-static bool definedestinationMode(pxConfig *config)
+static bool defineinterestMode(pxConfig *config)
 {
     PS_ASSERT_PTR_NON_NULL(config, false);
 
-    // required
-    PXOPT_LOOKUP_S64(prod_id, config->args,      "-prod_id", true, false);
-    PXOPT_LOOKUP_STR(name, config->args,         "-name", true, false);
+    // one of these is required
+    PXOPT_LOOKUP_S64(dest_id, config->args,      "-dest_id", false, false);
+    PXOPT_LOOKUP_STR(dest_name, config->args,    "-dest_name", false, false);
+    if (!dest_id && !dest_name) {
+        psError(PS_ERR_UNKNOWN, true, "either dest_id or dest_name is required");
+        return false;
+    }
+
+    // either target_id or stage and label are required
+    PXOPT_LOOKUP_S64(target_id, config->args,    "-target_id", false, false);
+    PXOPT_LOOKUP_STR(stage, config->args,        "-stage", false, false);
+    PXOPT_LOOKUP_STR(dist_group, config->args,   "-dist_group", false, false);
+    PXOPT_LOOKUP_STR(filter, config->args,       "-filter", false, false);
+    PXOPT_LOOKUP_BOOL(clean, config->args,       "-clean", false);
+
+    if (!target_id) {
+        bool error = false;
+        if (!stage) {
+            psError(PS_ERR_UNKNOWN, true, "stage is required if target_id is not supplied");
+            error = true;
+        }
+        if (!dist_group) {
+            psError(PS_ERR_UNKNOWN, !error, "dist_group is required if target_id is not supplied");
+            error = true;
+        }
+        if (error) {
+            return false;
+        }
+    }
 
     // optional
-    PXOPT_LOOKUP_STR(status_uri, config->args,   "-status_uri", false, false);
-    PXOPT_LOOKUP_STR(comment, config->args,      "-comment", false, false);
-    PXOPT_LOOKUP_STR(last_fileset, config->args, "-last_fileset", false, false);
-    PXOPT_LOOKUP_STR(state, config->args,        "-set_state", false, false);
-
-    // XXX: should we insure that these names do not contatin any whitespace?
-
-    rcDestinationRow *row = rcDestinationRowAlloc(
-            0,          // dest_id
-            prod_id,
-            name,
-            status_uri,
-            comment,
-            last_fileset,
-            state ? state : "enabled"
-            );
-            
-    if (!row) {
-        psError(PS_ERR_UNKNOWN, false, "failed to allocate rcDestination object");
-        return false;
-    }
-   if (!rcDestinationInsertObject(config->dbh, row)) {
-        psError(PS_ERR_UNKNOWN, false, "database error");
-        psFree(row);
-        return false;
-    }
-
-    // get the assigned target_id
-    row->dest_id = psDBLastInsertID(config->dbh);
-
-    if (!rcDestinationPrintObject(stdout, row, true)) {
-        psError(PS_ERR_UNKNOWN, false, "failed to print object");
-        psFree(row);
-        return false;
-    }
-
-    psFree(row);
-
-    return true;
-}
-
-static bool updatedestinationMode(pxConfig *config)
+    PXOPT_LOOKUP_S64(limit, config->args, "-limit", false, false);
+    PXOPT_LOOKUP_STR(state, config->args,  "-set_state", false, false);
+    if (state) {
+        if (strcmp(state, "enabled") && strcmp(state, "disabled")) {
+            psError(PS_ERR_PROGRAMMING, true, "state must be enabled or disabled");
+            return false;
+        }
+    } else {
+        // default state
+        state = "enabled";
+    }
+
+    // now that we've done all of our argument checking, copy the values to where
+    psMetadata *where = psMetadataAlloc();
+    PXOPT_COPY_S64(config->args, where, "-dest_id", "dest_id", "==");
+    PXOPT_COPY_STR(config->args, where, "-dest_name", "rcDestination.name", "==");
+    PXOPT_COPY_S64(config->args, where, "-target_id", "target_id", "==");
+    PXOPT_COPY_STR(config->args, where, "-dist_group", "dist_group", "LIKE");
+    PXOPT_COPY_STR(config->args, where, "-filter", "filter", "LIKE");
+    // if stage is all don't add it to the query (match all stages)
+    if (stage && strcmp(stage, "all")) {
+        PXOPT_COPY_STR(config->args, where, "-stage", "stage", "==");
+    }
+
+    psString query = pxDataGet("disttool_defineinterest.sql");
+
+    if (!psListLength(where->list)) {
+        // can't get here
+        psError(PS_ERR_PROGRAMMING, true, "search parameters are required");
+        psFree(where);
+        psFree(query);
+        return false;
+    }
+    psString whereClause = psDBGenerateWhereConditionSQL(where, NULL);
+    psStringAppend(&query, " AND %s", whereClause);
+    psFree(whereClause);
+    psFree(where);
+    if (clean) {
+        psStringAppend(&query, " AND (distTarget.clean)");
+    } else {
+        psStringAppend(&query, " AND (!distTarget.clean)");
+    }
+    if (limit) {
+        psString limitString = psDBGenerateLimitSQL(limit);
+        psStringAppend(&query, " %s", limitString);
+        psFree(limitString);
+    }
+    {
+        // psStringSubstitute fails unless the input is a psString which it determines by
+        // comparing the memory blocks free function to an expected value.
+        // pxDataGet uses psSlurp which leaves a different free function on the memory block.
+        // To work around this make a copy of the query before doing the substitution.
+        psString queryCopy = psStringCopy(query);
+        psFree(query);
+        query = queryCopy;
+    }
+    // change the @STATE@ in the sql file to our state
+    if (!psStringSubstitute(&query, state, "@STATE@")) {
+        psError(PS_ERR_UNKNOWN, false, "failed to substitute state string");
+        return false;
+    }
+
+    if (!p_psDBRunQuery(config->dbh, query)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        psFree(query);
+        return false;
+    }
+    psFree(query);
+    int numInserted = psDBAffectedRows(config->dbh);
+    printf("inserted %d rows into rcInterest\n", numInserted);
+
+    return true;
+}
+
+static bool updateinterestMode(pxConfig *config)
 {
     PS_ASSERT_PTR_NON_NULL(config, false);
 
     psMetadata *where = psMetadataAlloc();
-    PXOPT_COPY_S64(config->args, where, "-dest_id", "dest_id", "==");
-    PXOPT_COPY_S64(config->args, where, "-prod_id", "prod_id", "==");
+    PXOPT_COPY_S64(config->args, where, "-int_id",    "int_id", "==");
+    PXOPT_COPY_S64(config->args, where, "-dest_id",   "dest_id", "==");
+    PXOPT_COPY_S64(config->args, where, "-target_id", "target_id", "==");
+    PXOPT_COPY_STR(config->args, where, "-dest_name", "rcDestination.name", "LIKE");
+    PXOPT_COPY_STR(config->args, where, "-stage", "stage", "==");
+    PXOPT_COPY_STR(config->args, where, "-filter", "filter", "LIKE");
+    PXOPT_COPY_STR(config->args, where, "-dist_group", "dist_group", "LIKE");
+
+    PXOPT_LOOKUP_BOOL(clean, config->args, "-clean", false);
+    PXOPT_LOOKUP_BOOL(full, config->args, "-full", false);
+    if (full && clean) {
+        psError(PS_ERR_UNKNOWN, true, "-full and -clean makes no sense, chose one or the other");
+        psFree(where);
+        return false;
+    }
+        
 
     PXOPT_LOOKUP_STR(state, config->args, "-set_state", false, false);
-#ifdef ALLOW_UPDATE_LAST_FILESET
-    PXOPT_LOOKUP_STR(last_fileset, config->args, "-set_last_fileset", false, false);
-    if (!(state || last_fileset)) {
-        psError(PS_ERR_UNKNOWN, true, "one or more of -set_state or -set_last_fileset is required");
-# else 
     if (!state) {
-#endif
-        psFree(where);
-        return false;
-    }
-    psString query = psStringCopy("UPDATE rcDestination SET");
-    psString sep = "";
-    if (state) {
-        psStringAppend(&query, " state = '%s'", state);
-        sep = ",";
-    }
-#ifdef ALLOW_UPDATE_LAST_FILESET
-    // last_fileset normally gets set by updatercrunMode
-    // Allowing it to be set here might cause problems
-    // especially since we are allowing selection by prod_id
-    if (last_fileset) {
-        psStringAppend(&query, " %s last_fileset = '%s'", sep, last_fileset);
-    }
-#endif
+        psError(PS_ERR_UNKNOWN, true, "-set_state is required");
+        psFree(where);
+        return false;
+    }
+    psString query = pxDataGet("disttool_updateinterest.sql");
 
     if (psListLength(where->list)) {
@@ -1614,5 +1702,11 @@
     psFree(where);
 
-    if (!p_psDBRunQuery(config->dbh, query)) {
+    if (clean) {
+        psStringAppend(&query, " AND distTarget.clean");
+    } else {
+        psStringAppend(&query, " AND NOT distTarget.clean");
+    }
+
+    if (!p_psDBRunQueryF(config->dbh, query, state)) {
         psError(PS_ERR_UNKNOWN, false, "database error");
         psFree(query);
@@ -1621,68 +1715,35 @@
     psFree(query);
 
-    return true;
-}
-
-static bool defineinterestMode(pxConfig *config)
+    psS64 numUpdated = psDBAffectedRows(config->dbh);
+    printf("updated %" PRId64 " interests\n", numUpdated);
+
+    return true;
+}
+static bool listinterestsMode(pxConfig *config)
 {
     PS_ASSERT_PTR_NON_NULL(config, false);
 
-    // required
-    PXOPT_LOOKUP_S64(dest_id, config->args,      "-dest_id", true, false);
-    PXOPT_LOOKUP_S64(target_id, config->args,    "-target_id", true, false);
-
-    // optional
-    PXOPT_LOOKUP_STR(state, config->args,        "-set_state", false, false);
-
-    // XXX: should we insure that these names do not contatin any whitespace?
-
-    rcInterestRow *row = rcInterestRowAlloc(
-            0,          // int_id
-            dest_id,
-            target_id,
-            state ? state : "enabled"
-            );
-            
-    if (!row) {
-        psError(PS_ERR_UNKNOWN, false, "failed to allocate rcInterest object");
-        return false;
-    }
-   if (!rcInterestInsertObject(config->dbh, row)) {
-        psError(PS_ERR_UNKNOWN, false, "database error");
-        psFree(row);
-        return false;
-    }
-
-    // get the assigned target_id
-    row->int_id = psDBLastInsertID(config->dbh);
-
-    if (!rcInterestPrintObject(stdout, row, true)) {
-        psError(PS_ERR_UNKNOWN, false, "failed to print object");
-        psFree(row);
-        return false;
-    }
-
-    psFree(row);
-
-    return true;
-}
-
-static bool updateinterestMode(pxConfig *config)
-{
-    PS_ASSERT_PTR_NON_NULL(config, false);
-
-    psMetadata *where = psMetadataAlloc();
-    PXOPT_COPY_S64(config->args, where, "-int_id",    "int_id", "==");
-    PXOPT_COPY_S64(config->args, where, "-dest_id",   "dest_id", "==");
+    psMetadata *where = psMetadataAlloc();
+    PXOPT_COPY_S64(config->args, where, "-int_id", "int_id", "==");
+    PXOPT_COPY_S64(config->args, where, "-dest_id", "dest_id", "==");
+    PXOPT_COPY_STR(config->args, where, "-dest_name", "name", "==");
     PXOPT_COPY_S64(config->args, where, "-target_id", "target_id", "==");
-
-    PXOPT_LOOKUP_STR(state, config->args, "-set_state", false, false);
-    if (!state) {
-        psError(PS_ERR_UNKNOWN, true, "-set_state is required");
-        psFree(where);
-        return false;
-    }
-    psString query = NULL;
-    psStringAppend(&query, "UPDATE rcInterest SET state = '%s'", state);
+    PXOPT_COPY_STR(config->args, where, "-stage", "stage", "==");
+    PXOPT_COPY_STR(config->args, where, "-dist_group", "dist_group", "LIKE");
+    PXOPT_COPY_STR(config->args, where, "-filter", "filter", "LIKE");
+    PXOPT_COPY_STR(config->args, where, "-state", "rcInterest.state", "==");
+
+    PXOPT_LOOKUP_BOOL(clean, config->args, "-clean", false);
+    PXOPT_LOOKUP_BOOL(full, config->args, "-full", false);
+
+    PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
+    PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
+
+    if (clean && full) {
+        psError(PS_ERR_UNKNOWN, false, "can't select both -clean and -full");
+        return false;
+    }
+
+    psString query = pxDataGet("disttool_listinterests.sql");
 
     if (psListLength(where->list)) {
@@ -1690,20 +1751,237 @@
         psStringAppend(&query, " WHERE %s", whereClause);
         psFree(whereClause);
-    } else {
-        psError(PS_ERR_UNKNOWN, true, "search parameters are required");
-        psFree(where);
-        psFree(query);
-        return false;
+        if (clean) {
+            psStringAppend(&query, " AND (clean)");
+        } else if (full) {
+            psStringAppend(&query, " AND (!clean)");
+        }
+    } else if (clean) {
+        psStringAppend(&query, " WHERE clean");
+    } else if (full) {
+        psStringAppend(&query, " WHERE !clean");
     }
     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);
+        if (!psDBRollback(config->dbh)) {
+            psError(PS_ERR_UNKNOWN, false, "database error");
+        }
         return false;
     }
     psFree(query);
 
-    return true;
-}
-
+    psArray *output = p_psDBFetchResult(config->dbh);
+    if (!output) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        return false;
+    }
+    if (!psArrayLength(output)) {
+        psTrace("disttool", PS_LOG_INFO, "no rows found");
+        psFree(output);
+        return true;
+    }
+
+    if (!ippdbPrintMetadatas(stdout, output, "rcInterest", !simple)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to print array");
+        psFree(output);
+        return false;
+    }
+
+    psFree(output);
+
+    return true;
+}
+static bool pendingcleanupMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
+
+    psMetadata *where = psMetadataAlloc();
+    PXOPT_COPY_S64(config->args, where, "-dist_id", "dist_id", "==");
+    PXOPT_COPY_STR(config->args, where, "-stage", "stage", "==");
+    pxAddLabelSearchArgs (config, where, "-label", "distRun.label", "==");
+
+    PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
+    PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
+    PXOPT_LOOKUP_BOOL(all, config->args, "-all", false);
+
+    psString query = pxDataGet("disttool_pendingcleanup.sql");
+
+    if (psListLength(where->list)) {
+        psString whereClause = psDBGenerateWhereConditionSQL(where, NULL);
+        psStringAppend(&query, " AND %s", whereClause);
+        psFree(whereClause);
+        psFree(where);
+    } else if (!all) {
+        psFree(where);
+        psError(PXTOOLS_ERR_CONFIG, false, "search parameters or -all are required");
+        return false;
+    }
+
+    // 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);
+        if (!psDBRollback(config->dbh)) {
+            psError(PS_ERR_UNKNOWN, false, "database error");
+        }
+        return false;
+    }
+    psFree(query);
+
+    psArray *output = p_psDBFetchResult(config->dbh);
+    if (!output) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        return false;
+    }
+    if (!psArrayLength(output)) {
+        psTrace("disttool", PS_LOG_INFO, "no rows found");
+        psFree(output);
+        return true;
+    }
+
+    if (!ippdbPrintMetadatas(stdout, output, "distToCleanup", !simple)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to print array");
+        psFree(output);
+        return false;
+    }
+
+    psFree(output);
+
+    return true;
+}
+static bool listfilesetsMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
+
+    psMetadata *where = psMetadataAlloc();
+    PXOPT_COPY_S64(config->args, where, "-dist_id", "dist_id", "==");
+    PXOPT_COPY_S64(config->args, where, "-int_id", "int_id", "==");
+    PXOPT_COPY_S64(config->args, where, "-dest_id", "dest_id", "==");
+    PXOPT_COPY_STR(config->args, where, "-dest_name", "name", "==");
+    PXOPT_COPY_S64(config->args, where, "-target_id", "target_id", "==");
+    PXOPT_COPY_STR(config->args, where, "-stage", "stage", "==");
+    PXOPT_COPY_STR(config->args, where, "-dist_group", "dist_group", "LIKE");
+    PXOPT_COPY_STR(config->args, where, "-filter", "filter", "LIKE");
+    PXOPT_COPY_STR(config->args, where, "-state", "state", "==");
+
+    PXOPT_LOOKUP_BOOL(clean, config->args, "-clean", false);
+    PXOPT_LOOKUP_BOOL(full, config->args, "-full", false);
+
+    pxAddLabelSearchArgs (config, where, "-label", "distRun.label", "==");
+
+    PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
+    PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
+
+    if (!psListLength(where->list)) {
+        psFree(where);
+        psError(PXTOOLS_ERR_CONFIG, false, "search parameters are required");
+        return false;
+    }
+
+    psString query = pxDataGet("disttool_listfilesets.sql");
+
+    psString whereClause = psDBGenerateWhereConditionSQL(where, NULL);
+    psStringAppend(&query, " WHERE %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);
+        if (!psDBRollback(config->dbh)) {
+            psError(PS_ERR_UNKNOWN, false, "database error");
+        }
+        return false;
+    }
+    psFree(query);
+
+    psArray *output = p_psDBFetchResult(config->dbh);
+    if (!output) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        return false;
+    }
+    if (!psArrayLength(output)) {
+        psTrace("disttool", PS_LOG_INFO, "no rows found");
+        psFree(output);
+        return true;
+    }
+
+    if (!ippdbPrintMetadatas(stdout, output, "distFilesets", !simple)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to print array");
+        psFree(output);
+        return false;
+    }
+
+    psFree(output);
+
+    return true;
+}
+static bool updatefilesetMode(pxConfig *config)
+{
+    psMetadata *where = psMetadataAlloc();
+    PXOPT_COPY_S64(config->args, where, "-fs_id", "fs_id", "==");
+
+    if (!psListLength(where->list)) {
+        psFree(where);
+        psError(PXTOOLS_ERR_CONFIG, false, "search parameters are required");
+        return false;
+    }
+
+    PXOPT_LOOKUP_STR(state, config->args, "-set_state", false, false);
+
+    // We don't use PXOPT_LOOKUP_S16(fault, config->args, "-fault", false, false); here
+    // because we want -fault 0 to work
+    bool gotFault = false;
+    psS16 fault = psMetadataLookupS16(&gotFault, config->args, "-fault");
+
+    if ((!state) && (!gotFault)) {
+        psError(PXTOOLS_ERR_CONFIG, true, "parameters (-fault or -set_state) is required");
+        psFree(where);
+        return false;
+    }
+
+    psString query = psStringCopy("UPDATE rcDSFileset SET ");
+
+    if (state) {
+        psStringAppend(&query, " state = '%s'", state);
+    }
+
+    if (gotFault) {
+        psStringAppend(&query, "%s fault = %d", state ? ", " : "", fault);
+    }
+
+    psString whereClause = psDBGenerateWhereConditionSQL(where, NULL);
+    psStringAppend(&query, " WHERE %s", whereClause);
+    psFree(whereClause);
+    psFree(where);
+
+    if (!p_psDBRunQuery(config->dbh, query)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        psFree(query);
+        return false;
+    }
+
+    return true;
+}
