Index: trunk/ippTools/share/chiptool_change_imfile_data_state.sql
===================================================================
--- trunk/ippTools/share/chiptool_change_imfile_data_state.sql	(revision 27737)
+++ trunk/ippTools/share/chiptool_change_imfile_data_state.sql	(revision 27738)
@@ -3,4 +3,5 @@
 -- chip_id and class_id
 UPDATE chipProcessedImfile
+JOIN chipRun USING(chip_id, exp_id)
 JOIN rawImfile USING(exp_id, class_id)
     SET 
Index: trunk/ippTools/share/chiptool_listrun.sql
===================================================================
--- trunk/ippTools/share/chiptool_listrun.sql	(revision 27738)
+++ trunk/ippTools/share/chiptool_listrun.sql	(revision 27738)
@@ -0,0 +1,26 @@
+SELECT DISTINCT
+    chipRun.chip_id,
+    chipRun.state,
+    chipRun.workdir,
+    chipRun.label,
+    chipRun.data_group,
+    chipRun.dist_group,
+    chipRun.note,
+    chipRun.magicked,
+    chipRun.reduction,
+    camRun.cam_id,
+    camRun.state AS camRun_state,
+    camProcessedExp.path_base AS cam_path_base,
+    rawExp.exp_id,
+    rawExp.exp_name,
+    rawExp.camera,
+    rawExp.filter,
+    rawExp.magicked AS raw_magicked,
+    magicDSRun.state AS dsRun_state
+FROM chipRun
+JOIN rawExp
+    USING(exp_id)
+LEFT JOIN camRun USING(chip_id)
+LEFT JOIN camProcessedExp USING(cam_id)
+LEFT JOIN magicDSRun
+    ON stage_id = chip_id AND stage = 'chip' AND magicDSRun.re_place
Index: trunk/ippTools/share/chiptool_pendingcleanupimfile.sql
===================================================================
--- trunk/ippTools/share/chiptool_pendingcleanupimfile.sql	(revision 27737)
+++ trunk/ippTools/share/chiptool_pendingcleanupimfile.sql	(revision 27738)
@@ -13,7 +13,8 @@
     USING(chip_id)
 WHERE
-    ((chipRun.state = 'goto_cleaned' AND chipProcessedImfile.data_state = 'full')
+    ((chipRun.state = 'goto_cleaned' AND (chipProcessedImfile.data_state = 'full'
+                                       OR chipProcessedImfile.data_state = 'update'))
 OR 
-    (chipRun.state = 'goto_scrubbed' AND chipProcessedImfile.data_state = 'full')
+    (chipRun.state = 'goto_scrubbed' AND chipProcessedImfile.data_state != 'scrubbed')
 OR 
     (chipRun.state = 'goto_purged' AND chipProcessedImfile.data_state != 'purged'))
Index: trunk/ippTools/share/chiptool_pendingimfile.sql
===================================================================
--- trunk/ippTools/share/chiptool_pendingimfile.sql	(revision 27737)
+++ trunk/ippTools/share/chiptool_pendingimfile.sql	(revision 27738)
@@ -33,9 +33,4 @@
     OR
     (chipRun.state = 'update'
-    AND chipProcessedImfile.data_state = 'update'))
--- // Restriction to prevent the processing of bad chips. Not needed now.
---     AND
---     (rawImfile.class_id != 'XY15' AND
---     rawImfile.class_id != 'XY32' AND
---     rawImfile.class_id != 'XY45')
-
+    AND chipProcessedImfile.data_state = 'update'
+    AND chipProcessedImfile.fault = 0))
Index: trunk/ippTools/share/chiptool_processedimfile.sql
===================================================================
--- trunk/ippTools/share/chiptool_processedimfile.sql	(revision 27737)
+++ trunk/ippTools/share/chiptool_processedimfile.sql	(revision 27738)
@@ -22,5 +22,8 @@
     rawExp.camera,
     rawExp.telescope,
-    rawExp.filelevel
+    rawExp.filelevel,
+    rawImfile.magicked AS raw_magicked,
+    rawImfile.burntool_state,
+    magicDSRun.state AS dsRun_state
 FROM chipRun
 JOIN chipImfile
@@ -30,2 +33,7 @@
 JOIN rawExp
     ON chipProcessedImfile.exp_id = rawExp.exp_id
+JOIN rawImfile
+    ON rawExp.exp_id = rawImfile.exp_id 
+    AND chipProcessedImfile.class_id = rawImfile.class_id
+LEFT JOIN magicDSRun
+    ON stage_id = chip_id AND stage = 'chip' AND magicDSRun.re_place
Index: trunk/ippTools/src/chiptool.c
===================================================================
--- trunk/ippTools/src/chiptool.c	(revision 27737)
+++ trunk/ippTools/src/chiptool.c	(revision 27738)
@@ -60,4 +60,5 @@
 static bool runstateMode(pxConfig *config);
 static bool setimfiletoupdateMode(pxConfig *config);
+static bool listrunMode(pxConfig *config);
 
 # define MODECASE(caseName, func) \
@@ -103,4 +104,5 @@
         MODECASE(CHIPTOOL_MODE_RUNSTATE,                runstateMode);
         MODECASE(CHIPTOOL_MODE_SETIMFILETOUPDATE,       setimfiletoupdateMode);
+        MODECASE(CHIPTOOL_MODE_LISTRUN,                 listrunMode);
         default:
             psAbort("invalid option (this should not happen)");
@@ -699,4 +701,8 @@
     PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
     PXOPT_LOOKUP_BOOL(faulted, config->args, "-faulted", false);
+    PXOPT_LOOKUP_BOOL(allfiles, config->args, "-allfiles", false);
+    if (allfiles) {
+        faulted = false;
+    }
 
     psMetadata *where = psMetadataAlloc();
@@ -740,5 +746,5 @@
         // list only faulted rows
         psStringAppend(&query, " %s", "AND chipProcessedImfile.fault != 0");
-    } else {
+    } else if (!allfiles) {
         // don't list faulted rows
         psStringAppend(&query, " %s", "AND chipProcessedImfile.fault = 0");
@@ -1414,6 +1420,6 @@
     }
 
-    char *set_magicked_imfile = "";
-    char *set_magicked_run = "";
+    psString set_magicked_imfile = psStringCopy("");
+    psString set_magicked_run = psStringCopy("");
     if (!strcmp(data_state, "full")) {
         // if (chipProcessedImfile.magicked < 0 and rawImfile.magicked = 0) leave magicked unchanged. This will
@@ -1421,10 +1427,14 @@
         // otherwise copy magicked from the rawImfile
         // Same thing for chipRun/rawExp
-        set_magicked_imfile = "\n , chipProcessedImfile.magicked = IF((chipProcessedImfile.magicked < 0 AND rawImfile.magicked = 0), chipProcessedImfile.magicked, rawImfile.magicked)";
-        set_magicked_run = "\n , chipRun.magicked = IF((chipRun.magicked < 0 AND rawExp.magicked = 0), chipRun.magicked, rawExp.magicked)";
+        psStringAppend(&set_magicked_imfile, "\n , chipProcessedImfile.magicked = IF((chipProcessedImfile.magicked < 0"
+                                      " AND rawImfile.magicked = 0), chipProcessedImfile.magicked, rawImfile.magicked)");
+        psStringAppend(&set_magicked_run, "\n , chipRun.magicked = IF((chipRun.magicked < 0 AND rawExp.magicked = 0), "
+                                      " chipRun.magicked, rawExp.magicked)");
+
     } else if (!strcmp(data_state, "cleaned") || !strcmp(data_state, "purged")) {
         // if magicked is non-zero set it to -1
-        set_magicked_imfile = "\n, chipProcessedImfile.magicked = IF(chipProcessedImfile.magicked = 0, 0, -1)";
-        set_magicked_run = "\n, chipRun.magicked = IF(chipRun.magicked = 0, 0, -1)";
+        // Once one imfile has been cleaned, the chipRun is no longer 'magicked'
+        psStringAppend(&set_magicked_imfile, "\n, chipProcessedImfile.magicked = IF(chipProcessedImfile.magicked = 0, 0, -1),"
+                                             " chipRun.magicked = IF(chipRun.magicked = 0, 0, -1)");
     }
 
@@ -1440,4 +1450,6 @@
     }
     psFree(query);
+    psFree(set_magicked_imfile);
+    psFree(set_magicked_run);
     if (psDBAffectedRows(config->dbh) < 1) {
         psError(PS_ERR_UNKNOWN, false, "should have affected atleast 1 row");
@@ -1757,2 +1769,90 @@
     return true;
 }
+
+static bool listrunMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, NULL);
+
+    PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
+    PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
+    PXOPT_LOOKUP_BOOL(pstamp_order, config->args, "-pstamp_order", false);
+
+    psMetadata *where = psMetadataAlloc();
+    pxchipGetSearchArgs (config, where); // chipRun, chipProcessedImfile, rawExp
+    PXOPT_COPY_S64(config->args, where, "-chip_id", "chipRun.chip_id", "==");
+    PXOPT_COPY_STR(config->args, where, "-reduction", "chipRun.reduction", "==");
+    PXOPT_COPY_STR(config->args, where, "-state", "chipRun.state", "==");
+    pxAddLabelSearchArgs (config, where, "-label", "chipRun.label", "LIKE");
+    pxAddLabelSearchArgs (config, where, "-data_group", "chipRun.data_group", "LIKE");
+    pxAddLabelSearchArgs (config, where, "-dist_group", "chipRun.dist_group", "LIKE");
+    PXOPT_COPY_S64(config->args, where, "-magicked", "chipRun.magicked", "==");
+
+    psString where2 = NULL;
+    pxmagicAddWhere(config, &where2, "chipRun");
+    // add cuts on ra and decl if supplied
+    if (!pxspaceAddWhere(config, &where2, "rawExp")) {
+        psError(psErrorCodeLast(), false, "pxSpaceAddWhere failed");
+        return false;
+    }
+
+    psString query = pxDataGet("chiptool_listrun.sql");
+    if (!query) {
+        psError(PXTOOLS_ERR_SYS, false, "failed to retreive SQL statement");
+        return false;
+    }
+
+    if (psListLength(where->list)) {
+        psString whereClause = psDBGenerateWhereConditionSQL(where, NULL);
+        psStringAppend(&query, " WHERE %s %s", whereClause, where2 ? where2 : "");
+        psFree(whereClause);
+    } else if (psMetadataLookupBool(NULL, config->args, "-all") || where2) {
+        psStringAppend(&query, " WHERE chipRun.chip_id IS NOT NULL %s", where2 ? where2 : "");
+    } else {
+        psFree(where);
+        psError(PXTOOLS_ERR_CONFIG, false, "search parameters (or -all) are required");
+        return false;
+    }
+    psFree(where);
+
+    if (pstamp_order) {
+        // put runs in order of exposure id with newest chip Runs first
+        // The postage stamp parser depends on this behavior
+        psStringAppend(&query, "\nORDER by exp_id, chip_id DESC");
+    }
+
+    // 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) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        return false;
+    }
+    if (!psArrayLength(output)) {
+        psTrace("chiptool", PS_LOG_INFO, "no rows found");
+        psFree(output);
+        return true;
+    }
+
+    // negative simple so the default is true
+    if (!ippdbPrintMetadatas(stdout, output, "chipRun", !simple)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to print array");
+        psFree(output);
+        return false;
+    }
+
+    psFree(output);
+
+    return true;
+}
Index: trunk/ippTools/src/chiptoolConfig.c
===================================================================
--- trunk/ippTools/src/chiptoolConfig.c	(revision 27737)
+++ trunk/ippTools/src/chiptoolConfig.c	(revision 27738)
@@ -196,4 +196,5 @@
     psMetadataAddBool(processedimfileArgs, PS_LIST_TAIL, "-all",  0,            "list everything without search terms", false);
     psMetadataAddBool(processedimfileArgs, PS_LIST_TAIL, "-faulted",  0,        "only return imfiles with a fault status set", false);
+    psMetadataAddBool(processedimfileArgs, PS_LIST_TAIL, "-allfiles",  0,       "only all matching imfiles regardless of fault status", false);
     psMetadataAddBool(processedimfileArgs, PS_LIST_TAIL, "-simple",  0,         "use the simple output format", false);
 
@@ -216,4 +217,22 @@
     psMetadataAddS16(updateprocessedimfileArgs, PS_LIST_TAIL, "-fault",  0,            "set fault code (required)", 0);
     psMetadataAddStr(updateprocessedimfileArgs, PS_LIST_TAIL, "-set_state", 0,         "set state", NULL);
+
+    // -processedExp
+    psMetadata *listrunArgs = psMetadataAlloc();
+    pxchipSetSearchArgs(listrunArgs);
+    psMetadataAddS64(listrunArgs, PS_LIST_TAIL, "-chip_id",  0,         "search by  chip ID", 0);
+    psMetadataAddStr(listrunArgs,  PS_LIST_TAIL, "-reduction",          0, "search by reduction class", NULL);
+    psMetadataAddStr(listrunArgs,  PS_LIST_TAIL, "-label",  PS_META_DUPLICATE_OK, "search by chipRun label (LIKE comparison)", NULL);
+    psMetadataAddStr(listrunArgs,  PS_LIST_TAIL, "-state",              0, "search by chipRun state", NULL);
+    psMetadataAddStr(listrunArgs,  PS_LIST_TAIL, "-data_group",  PS_META_DUPLICATE_OK, "search by chipRun data_group (LIKE comparison)", NULL);
+    psMetadataAddStr(listrunArgs,  PS_LIST_TAIL, "-dist_group",  PS_META_DUPLICATE_OK, "search by chipRun dist_group (LIKE comparison)", NULL);
+    pxmagicAddArguments(listrunArgs);
+
+    psMetadataAddBool(listrunArgs, PS_LIST_TAIL, "-pstamp_order",  0,    "order results for postage stamp server", false);
+    psMetadataAddU64(listrunArgs,  PS_LIST_TAIL, "-limit",  0,           "limit result set to N items", 0);
+    psMetadataAddBool(listrunArgs, PS_LIST_TAIL, "-all",  0,            "list everything without search terms", false);
+    psMetadataAddBool(listrunArgs, PS_LIST_TAIL, "-simple",  0,         "use the simple output format", false);
+    pxspaceAddArguments(listrunArgs);
+
     // -block
     psMetadata *blockArgs = psMetadataAlloc();
@@ -328,4 +347,5 @@
     PXOPT_ADD_MODE("-revertprocessedimfile","undo a processed imfile",              CHIPTOOL_MODE_REVERTPROCESSEDIMFILE,revertprocessedimfileArgs);
     PXOPT_ADD_MODE("-runstate",             "list the states of chip run",          CHIPTOOL_MODE_RUNSTATE,             runstateArgs);
+    PXOPT_ADD_MODE("-listrun",              "list chipRuns",                        CHIPTOOL_MODE_LISTRUN,              listrunArgs);
     PXOPT_ADD_MODE("-advanceexp",           "advance completed exposures",          CHIPTOOL_MODE_ADVANCEEXP,           advanceexpArgs);
     PXOPT_ADD_MODE("-block",                "set a label block",                    CHIPTOOL_MODE_BLOCK,                blockArgs);
