Index: /trunk/ippTools/share/Makefile.am
===================================================================
--- /trunk/ippTools/share/Makefile.am	(revision 27981)
+++ /trunk/ippTools/share/Makefile.am	(revision 27982)
@@ -198,4 +198,5 @@
      magictool_rawimfile.sql \
      magictool_revertnode.sql \
+     magictool_exposure.sql \
      magicdstool_clearstatefaults.sql \
      magicdstool_completed_runs.sql \
Index: /trunk/ippTools/share/magictool_exposure.sql
===================================================================
--- /trunk/ippTools/share/magictool_exposure.sql	(revision 27982)
+++ /trunk/ippTools/share/magictool_exposure.sql	(revision 27982)
@@ -0,0 +1,54 @@
+SELECT *
+FROM (
+    -- Forward diff
+    SELECT DISTINCT
+        magicRun.magic_id,
+        rawExp.*,
+        camProcessedExp.path_base,
+        camProcessedExp.zpt_obs,
+        camProcessedExp.zpt_stdev,
+        camProcessedExp.fwhm_major,
+        camProcessedExp.fwhm_minor,
+        camProcessedExp.iq_m2,
+        camProcessedExp.iq_m3,
+        camProcessedExp.iq_m4
+    FROM
+        magicRun
+    JOIN diffRun USING(diff_id)
+    JOIN diffInputSkyfile USING(diff_id)
+    LEFT JOIN warpRun
+        ON warpRun.warp_id = diffInputSkyfile.warp1
+        AND magicRun.inverse = 0
+    JOIN fakeRun USING(fake_id)
+    JOIN camRun USING(cam_id)
+    JOIN camProcessedExp USING(cam_id)
+    JOIN chipRun USING(chip_id,exp_id)
+    JOIN rawExp USING(exp_id)
+    -- WHERE hook %s
+    UNION
+    -- Backward diff
+    SELECT DISTINCT
+        magicRun.magic_id,
+        rawExp.*,
+        camProcessedExp.path_base,
+        camProcessedExp.zpt_obs,
+        camProcessedExp.zpt_stdev,
+        camProcessedExp.fwhm_major,
+        camProcessedExp.fwhm_minor,
+        camProcessedExp.iq_m2,
+        camProcessedExp.iq_m3,
+        camProcessedExp.iq_m4
+    FROM
+        magicRun
+    JOIN diffRun USING(diff_id)
+    JOIN diffInputSkyfile USING(diff_id)
+    LEFT JOIN warpRun
+        ON warpRun.warp_id = diffInputSkyfile.warp2
+        AND magicRun.inverse = 1
+    JOIN fakeRun USING(fake_id)
+    JOIN camRun USING(cam_id)
+    JOIN camProcessedExp USING(cam_id)
+    JOIN chipRun USING(chip_id,exp_id)
+    JOIN rawExp USING(exp_id)
+    -- WHERE hook %s
+) AS magicExposures
Index: /trunk/ippTools/share/magictool_inputs.sql
===================================================================
--- /trunk/ippTools/share/magictool_inputs.sql	(revision 27981)
+++ /trunk/ippTools/share/magictool_inputs.sql	(revision 27982)
@@ -2,4 +2,5 @@
 SELECT
     magicRun.magic_id,
+    magicRun.exp_id,
     magicRun.inverse, -- Using the inverse subtraction?
     magicRun.diff_id,
@@ -10,5 +11,6 @@
     magicInputs.warp_path_base, -- path_base for the template warp (if any)
     magicInputs.stack_path_base, -- path_base for the template stack (if any)
-    magicInputs.magic_path_base -- path_base for child nodes (if any)
+    magicInputs.magic_path_base, -- path_base for child nodes (if any)
+    magicInputs.cam_path_base -- path_base for the input camera
 FROM magicRun
 JOIN (
Index: /trunk/ippTools/src/magictool.c
===================================================================
--- /trunk/ippTools/src/magictool.c	(revision 27981)
+++ /trunk/ippTools/src/magictool.c	(revision 27982)
@@ -48,4 +48,5 @@
 static bool maskMode(pxConfig *config);
 static bool censorrunMode(pxConfig *config);
+static bool exposureMode(pxConfig *config);
 
 static bool setmagicRunState(pxConfig *config, psS64 magic_id, const char *state);
@@ -87,4 +88,5 @@
         MODECASE(MAGICTOOL_MODE_MASK,                maskMode);
         MODECASE(MAGICTOOL_MODE_CENSORRUN,           censorrunMode);
+        MODECASE(MAGICTOOL_MODE_EXPOSURE,            exposureMode);
         default:
             psAbort("invalid option (this should not happen)");
@@ -1514,2 +1516,66 @@
     return true;
 }
+
+
+static bool exposureMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
+
+    psMetadata *where = psMetadataAlloc();
+    PXOPT_COPY_S64(config->args, where, "-magic_id", "magicRun.magic_id", "==");
+    PXOPT_COPY_BOOL(config->args, where, "-inverse", "magicRun.inverse", "==");
+
+    PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
+
+    psString query = pxDataGet("magictool_exposure.sql");
+    if (!query) {
+        psError(PXTOOLS_ERR_SYS, false, "failed to retreive SQL statement");
+        return false;
+    }
+
+    psString whereClause = psStringCopy(""); // WHERE restrictions
+    if (psListLength(where->list)) {
+        psString clause = psDBGenerateWhereConditionSQL(where, NULL);
+        psStringAppend(&whereClause, " AND %s", clause);
+        psFree(clause);
+    }
+    psFree(where);
+
+    if (!p_psDBRunQueryF(config->dbh, query, whereClause, whereClause)) {
+        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");
+                break;
+            case PS_ERR_DB_SERVER:
+                psError(PXTOOLS_ERR_PROG, false, "database error");
+                break;
+            default:
+                psError(PXTOOLS_ERR_PROG, false, "unknown error");
+                break;
+        }
+        return false;
+    }
+    if (!psArrayLength(output)) {
+        psTrace("magictool", PS_LOG_INFO, "no rows found");
+        psFree(output);
+        return true;
+    }
+
+    if (!ippdbPrintMetadatas(stdout, output, "magicMask", !simple)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to print array");
+        psFree(output);
+        return false;
+    }
+    psFree(output);
+
+    return true;
+}
Index: /trunk/ippTools/src/magictool.h
===================================================================
--- /trunk/ippTools/src/magictool.h	(revision 27981)
+++ /trunk/ippTools/src/magictool.h	(revision 27982)
@@ -42,4 +42,5 @@
     MAGICTOOL_MODE_MASK,
     MAGICTOOL_MODE_CENSORRUN,
+    MAGICTOOL_MODE_EXPOSURE,
 } MAGICtoolMode;
 
Index: /trunk/ippTools/src/magictoolConfig.c
===================================================================
--- /trunk/ippTools/src/magictoolConfig.c	(revision 27981)
+++ /trunk/ippTools/src/magictoolConfig.c	(revision 27982)
@@ -168,4 +168,10 @@
     psMetadataAddS64(censorrunArgs, PS_LIST_TAIL, "-exp_id", 0, "define exposure ID", 0);
     psMetadataAddStr(censorrunArgs, PS_LIST_TAIL, "-label",       0, "define label", NULL);
+
+    // -exposure
+    psMetadata *exposureArgs = psMetadataAlloc();
+    psMetadataAddS64(exposureArgs, PS_LIST_TAIL, "-magic_id", 0, "define magictool ID", 0);
+    psMetadataAddBool(exposureArgs, PS_LIST_TAIL, "-inverse", 0, "select the inverse subtraction?", false);
+    psMetadataAddBool(exposureArgs, PS_LIST_TAIL, "-simple", 0, "use the simple output format", false);
 
     psFree(now);
@@ -191,4 +197,5 @@
     PXOPT_ADD_MODE("-mask",                "", MAGICTOOL_MODE_MASK,                maskArgs);
     PXOPT_ADD_MODE("-censorrun",           "", MAGICTOOL_MODE_CENSORRUN,           censorrunArgs);
+    PXOPT_ADD_MODE("-exposure",            "", MAGICTOOL_MODE_EXPOSURE,            exposureArgs);
 
     if (!pxGetOptions(stderr, argc, argv, config, modes, argSets)) {
