Index: trunk/ippTools/src/disttool.c
===================================================================
--- trunk/ippTools/src/disttool.c	(revision 28536)
+++ trunk/ippTools/src/disttool.c	(revision 28938)
@@ -34,4 +34,5 @@
 static bool updaterunMode(pxConfig *config);
 static bool revertrunMode(pxConfig *config);
+static bool rerunMode(pxConfig *config);
 static bool pendingcomponentMode(pxConfig *config);
 static bool addprocessedcomponentMode(pxConfig *config);
@@ -83,4 +84,5 @@
         MODECASE(DISTTOOL_MODE_UPDATERUN, updaterunMode);
         MODECASE(DISTTOOL_MODE_REVERTRUN, revertrunMode);
+        MODECASE(DISTTOOL_MODE_RERUN, rerunMode);
         MODECASE(DISTTOOL_MODE_PENDINGCOMPONENT, pendingcomponentMode);
         MODECASE(DISTTOOL_MODE_ADDPROCESSEDCOMPONENT, addprocessedcomponentMode);
@@ -587,4 +589,132 @@
 }
 
+static bool rerunMode(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_S64(config->args, where, "-stage_id", "stage_id", "==");
+    PXOPT_COPY_STR(config->args, where, "-label", "label", "==");
+    PXOPT_COPY_STR(config->args, where, "-data_group", "data_group", "==");
+
+    // require data_group or dist_id to be supplied
+    PXOPT_LOOKUP_STR(data_group, config->args, "-data_group", true, false);
+    PXOPT_LOOKUP_S64(dist_id, config->args, "-dist_id", false, false);
+    if (!data_group && !dist_id) {
+        psError(PXTOOLS_ERR_CONFIG, true, "data_group or dist_id is required");
+        return false;
+    }
+    PXOPT_LOOKUP_STR(set_label, config->args, "-set_label", false, false);
+
+    psString label_hook = psStringCopy("");
+    if (set_label) {
+        psStringAppend(&label_hook, ", label = '%s'", set_label);
+    }
+
+    PXOPT_LOOKUP_BOOL(pretend, config->args, "-pretend", false);
+    PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
+    PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
+
+
+    // It might be useful to be able to query by the parameters of the underlying runs
+
+    if (!psListLength(where->list)) {
+        psFree(where);
+        psError(PXTOOLS_ERR_CONFIG, false, "search parameters are required");
+        return false;
+    }
+
+    psString query = pxDataGet("disttool_rerun_select.sql");
+    if (!query) {
+        psError(PXTOOLS_ERR_SYS, 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);
+    }
+    psFree(where);
+
+    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("disttool", PS_LOG_INFO, "no rows found");
+        psFree(output);
+        return true;
+    }
+
+
+    if (pretend) {
+        if (!ippdbPrintMetadatas(stdout, output, "distRunsToUpdate", true)) {
+            psError(PS_ERR_UNKNOWN, false, "failed to print array");
+            psFree(output);
+            return false;
+        }
+        psFree(output);
+        return true;
+    }
+
+    query = "DELETE FROM distComponent where dist_id = %" PRId64;
+    
+    for (long i=0; i < psArrayLength(output); i++) {
+        psMetadata *md = output->data[i];
+        psS64 dist_id = psMetadataLookupS64(NULL, md, "dist_id");
+
+        if (!psDBTransaction(config->dbh)) {
+            psError(PS_ERR_UNKNOWN, false, "database error");
+            return false;
+        }
+
+        if (!p_psDBRunQueryF(config->dbh, query, dist_id)) {
+            psError(PS_ERR_UNKNOWN, false, "database error");
+            psFree(query);
+            if (!psDBRollback(config->dbh)) {
+                psError(PS_ERR_UNKNOWN, false, "database error");
+            }
+            return false;
+        }
+
+        if (!p_psDBRunQueryF(config->dbh,
+        "UPDATE distRun SET state = 'new', fault=0 %s WHERE dist_id =%" PRId64,
+                label_hook, dist_id)) {
+            psError(PS_ERR_UNKNOWN, false, "database error");
+            psFree(query);
+            if (!psDBRollback(config->dbh)) {
+                psError(PS_ERR_UNKNOWN, false, "database error");
+            }
+            return false;
+        }
+        if (!psDBCommit(config->dbh)) {
+            psError(PS_ERR_UNKNOWN, false, "database error");
+            return false;
+        }
+        printf("re-running distRun %" PRId64 "\n", dist_id);
+    }
+
+    psFree(output);
+
+    return true;
+}
 static bool revertrunMode(pxConfig *config)
 {
