Index: trunk/Ohana/src/relphot/Makefile
===================================================================
--- trunk/Ohana/src/relphot/Makefile	(revision 4828)
+++ trunk/Ohana/src/relphot/Makefile	(revision 4864)
@@ -42,8 +42,12 @@
 $(SRC)/misc.$(ARCH).o		 \
 $(SRC)/reload_catalogs.$(ARCH).o \
+$(SRC)/image-db.$(ARCH).o \
 $(SRC)/free_catalogs.$(ARCH).o   \
+$(SRC)/check_permissions.$(ARCH).o   \
 $(SRC)/setMrelFinal.$(ARCH).o 	 \
 $(SRC)/write_coords.$(ARCH).o 	 \
 $(SRC)/setExclusions.$(ARCH).o 	 \
+$(SRC)/Shutdown.$(ARCH).o 	 \
+$(SRC)/SetSignals.$(ARCH).o 	 \
 $(SRC)/wcatalog.$(ARCH).o
 
Index: trunk/Ohana/src/relphot/include/relphot.h
===================================================================
--- trunk/Ohana/src/relphot/include/relphot.h	(revision 4828)
+++ trunk/Ohana/src/relphot/include/relphot.h	(revision 4864)
@@ -1,4 +1,5 @@
 # include <ohana.h>
 # include <dvo.h>
+# include <signal.h>
 
 /* # define GRID_V1 */
@@ -118,5 +119,11 @@
 void          findImages          PROTO((Catalog *catalog, int Ncatalog));
 int           findMosaics         PROTO((Catalog *catalog, int Ncatalog));
-Image        *find_images         PROTO((GSCRegion *region, int Nregion, int *Nimages, int **LineNum));
+Image        *find_images         PROTO((FITS_DB *db, GSCRegion *region, int Nregion, int *Nimage, int **LineNum));
+void set_db (FITS_DB *in);
+int Shutdown (char *format, ...);
+void TrapSignal (int sig);
+void SetProtect (int mode);
+int SetSignals ();
+
 GSCRegion    *find_regions        PROTO((Image *image, int Nimage, int *Nregions, GSCRegion *fullregion));
 void          freeGridBins        PROTO((int Ncatalog));
@@ -147,5 +154,11 @@
 int           liststats           PROTO((double *value, double *dvalue, int N, StatType *stats));
 Catalog      *load_catalogs       PROTO((GSCRegion *region, int Nregion, GSCRegion *fullregion));
-GSCRegion    *load_images         PROTO((char *seed, int *nregion, GSCRegion *fullregion));
+GSCRegion    *load_images         PROTO((FITS_DB *db, char *seed, int *nregion, GSCRegion *fullregion));
+
+void check_permissions (char *basefile);
+void lock_image_db (FITS_DB *db, char *filename);
+void unlock_image_db (FITS_DB *db);
+void create_image_db (FITS_DB *db);
+
 int           main                PROTO((int argc, char **argv));
 void          mark_images         PROTO((Image *image, int Nimage, Image *timage, int Ntimage));
@@ -167,5 +180,5 @@
 int           setExclusions       PROTO((Catalog *catalog, int Ncatalog));
 void          setMcal             PROTO((Catalog *catalog, int Poor));
-void          setMcalFinal        PROTO((Image *image, int Nimage));
+void          setMcalFinal        PROTO(());
 int           setMcalOutput       PROTO((Catalog *catalog, int Ncatalog));
 void          setMgrid            PROTO((Catalog *catalog));
Index: trunk/Ohana/src/relphot/src/MosaicOps.c
===================================================================
--- trunk/Ohana/src/relphot/src/MosaicOps.c	(revision 4828)
+++ trunk/Ohana/src/relphot/src/MosaicOps.c	(revision 4864)
@@ -167,9 +167,12 @@
 }
 
-void setMcalFinal (Image *image, int Nimage) {
-
-  int i, j, im;
+void setMcalFinal () {
+
+  int i, j, im, Nimage;
+  Image *image;
 
   if (!MOSAICNAME[0]) return;
+
+  image = getimages (&Nimage);
 
   for (i = 0; i < Nmosaic; i++) {
Index: trunk/Ohana/src/relphot/src/SetSignals.c
===================================================================
--- trunk/Ohana/src/relphot/src/SetSignals.c	(revision 4864)
+++ trunk/Ohana/src/relphot/src/SetSignals.c	(revision 4864)
@@ -0,0 +1,118 @@
+# include "relphot.h"
+
+static int Protect = FALSE;
+static int Trapped = FALSE;
+
+void TrapSignal (int sig) {
+    fprintf (stderr, "trapped signal %d\n", sig);
+    if (sig == 11) {
+      fprintf (stderr, "seg fault\n");
+      exit (1);
+    }
+    if (Protect) {
+      Trapped = TRUE;
+      fprintf (stderr, "blocking until protected sections are clear\n");
+      return;
+    }
+    Shutdown ("halted by signal (trapped)");
+}    
+
+void SetProtect (int mode) {
+  Protect = mode;
+  if (Trapped && !Protect) Shutdown ("halted by signal (protect)");
+}
+
+int SetSignals () {
+
+  int i;
+
+  /* disable almost all signal interrupts */
+  for (i = 0; i < 36; i++) {
+    switch (i) {
+      /* can't redirect this signals */
+    case SIGKILL:    /* kill -9: cannot be caught or ignored */
+    case SIGSTOP:    /* SIGSTOP: cannot be caught or ignored */
+      /* ignore these signals */
+    case SIGCHLD:    /* child halted: ignore */
+    case SIGPWR:     /* power failure - why ignore this? */
+    case SIGWINCH:   /* window resized */
+    case SIGCONT:    /* continue - maintain this action */
+    case SIGTSTP:    /* stop signal sent from tty - why ignore? */
+    case SIGURG:     /* socket signal, ignore this */
+      break;
+      
+    default:
+      signal (i, TrapSignal);
+    }
+  }
+  return (TRUE);
+}
+/*
+
+       Signal     Value     Action   Comment
+       -------------------------------------------------------------------------
+       SIGHUP        1        A      Hangup detected on controlling terminal
+                                     or death of controlling process
+       SIGINT        2        A      Interrupt from keyboard
+       SIGQUIT       3        A      Quit from keyboard
+       SIGILL        4        A      Illegal Instruction
+       SIGABRT       6        C      Abort signal from abort(3)
+       SIGFPE        8        C      Floating point exception
+       SIGKILL       9       AEF     Kill signal
+       SIGSEGV      11        C      Invalid memory reference
+       SIGPIPE      13        A      Broken pipe: write to pipe with no readers
+       SIGALRM      14        A      Timer signal from alarm(2)
+       SIGTERM      15        A      Termination signal
+       SIGUSR1   30,10,16     A      User-defined signal 1
+       SIGUSR2   31,12,17     A      User-defined signal 2
+       SIGCHLD   20,17,18     B      Child stopped or terminated
+       SIGCONT   19,18,25            Continue if stopped
+       SIGSTOP   17,19,23    DEF     Stop process
+       SIGTSTP   18,20,24     D      Stop typed at tty
+       SIGTTIN   21,21,26     D      tty input for background process
+       SIGTTOU   22,22,27     D      tty output for background process
+
+       Next various other signals.
+
+       Signal       Value     Action   Comment
+       ---------------------------------------------------------------------
+       SIGTRAP        5         CG     Trace/breakpoint trap
+       SIGIOT         6         CG     IOT trap. A synonym for SIGABRT
+       SIGEMT       7,-,7       G
+       SIGBUS      10,7,10      AG     Bus error
+       SIGSYS      12,-,12      G      Bad argument to routine (SVID)
+       SIGSTKFLT    -,16,-      AG     Stack fault on coprocessor
+       SIGURG      16,23,21     BG     Urgent condition on socket (4.2 BSD)
+       SIGIO       23,29,22     AG     I/O now possible (4.2 BSD)
+       SIGPOLL                  AG     A synonym for SIGIO (System V)
+       SIGCLD       -,-,18      G      A synonym for SIGCHLD
+       SIGXCPU     24,24,30     AG     CPU time limit exceeded (4.2 BSD)
+       SIGXFSZ     25,25,31     AG     File size limit exceeded (4.2 BSD)
+       SIGVTALRM   26,26,28     AG     Virtual alarm clock (4.2 BSD)
+       SIGPROF     27,27,29     AG     Profile alarm clock
+       SIGPWR      29,30,19     AG     Power failure (System V)
+       SIGINFO      29,-,-      G      A synonym for SIGPWR
+       SIGLOST      -,-,-       AG     File lock lost
+       SIGWINCH    28,28,20     BG     Window resize signal (4.3 BSD, Sun)
+       SIGUNUSED    -,31,-      AG     Unused signal
+       (Here - denotes that a signal is absent; there where three values are given, the first one is usually  valid  for  alpha  and
+       sparc,  the  middle  one  for i386 and ppc, the last one for mips. Signal 29 is SIGINFO / SIGPWR on an alpha but SIGLOST on a
+       sparc.)
+
+       The letters in the "Action" column have the following meanings:
+
+       A      Default action is to terminate the process.
+
+       B      Default action is to ignore the signal.
+
+       C      Default action is to dump core.
+
+       D      Default action is to stop the process.
+
+       E      Signal cannot be caught.
+
+       F      Signal cannot be ignored.
+
+       G      Not a POSIX.1 conformant signal.
+
+*/
Index: trunk/Ohana/src/relphot/src/Shutdown.c
===================================================================
--- trunk/Ohana/src/relphot/src/Shutdown.c	(revision 4864)
+++ trunk/Ohana/src/relphot/src/Shutdown.c	(revision 4864)
@@ -0,0 +1,28 @@
+# include "relphot.h"
+
+static FITS_DB *db;
+
+void set_db (FITS_DB *in) {
+  db = in;
+}
+
+/* clean up open / locked ImageCat before shutting down */
+int Shutdown (char *format, ...) {  
+  va_list argp;
+  char *formatplus;
+  
+  ALLOCATE (formatplus, char, strlen(format));
+  strcpy (formatplus, format);
+  strcat (formatplus, "\n");
+
+  va_start (argp, format);
+  vfprintf (stderr, formatplus, argp);
+  free (formatplus);
+  va_end (argp);
+
+  SetProtect (TRUE);
+  fits_db_close (db);
+  fprintf (stderr, "ERROR: addstar halted\n");
+  exit (1);
+}
+
Index: trunk/Ohana/src/relphot/src/check_permissions.c
===================================================================
--- trunk/Ohana/src/relphot/src/check_permissions.c	(revision 4864)
+++ trunk/Ohana/src/relphot/src/check_permissions.c	(revision 4864)
@@ -0,0 +1,67 @@
+# include "relphot.h"
+
+void check_permissions (char *basefile) {
+  
+  char *c, dir[256], filename[256];
+  struct stat filestat;
+  uid_t uid;
+  gid_t gid;
+  int status, cmode;
+
+  uid = getuid();
+  gid = getgid();
+
+  /* check permission to write to directory */
+  sprintf (filename, "%s", basefile);
+  c = strrchr (filename, '/');
+  if (c == (char *) NULL) {
+    strcpy (dir, ".");
+  } else {
+    *c = 0;
+    strcpy (dir, filename);
+  }
+  status = stat (dir, &filestat);
+  if (status == -1) {
+    fprintf (stderr, "directory %s does not exist, creating...\n", dir);
+    cmode = S_IRWXU | S_IRWXG | S_IRWXO;
+    status = mkdir (dir, cmode);
+    if (status == -1) {
+      fprintf (stderr, "ERROR: can't create %s\n", dir);
+      exit (1);
+    }
+  } 
+  status = stat (dir, &filestat);
+  if (((uid == filestat.st_uid) && (filestat.st_mode & S_IRWXU)) ||
+      ((gid == filestat.st_gid) && (filestat.st_mode & S_IRWXG)) || 
+      (filestat.st_mode & S_IRWXO)) {
+  } else {
+    fprintf (stderr, "ERROR: can't write to %s\n", dir);
+    exit (1);
+  }
+  
+  /* check permission to write to file */
+  sprintf (filename, "%s", basefile);
+  status = stat (filename, &filestat);
+  if (status == 0) { /* file exists, are permissions OK? */
+    if (((uid == filestat.st_uid) && (filestat.st_mode & S_IRUSR) && (filestat.st_mode & S_IWUSR)) ||
+	((gid == filestat.st_gid) && (filestat.st_mode & S_IRGRP) && (filestat.st_mode & S_IWGRP)) || 
+	((filestat.st_mode & S_IROTH) && (filestat.st_mode & S_IWOTH))) {
+    } else {
+      fprintf (stderr, "ERROR: can't write to %s\n", filename);
+      exit (1);
+    }
+  }
+  
+  /* check permission to write to backup file */
+  sprintf (filename, "%s~", basefile);
+  status = stat (filename, &filestat);
+  if (status == 0) { /* file exists, are permissions OK? */
+    if (((uid == filestat.st_uid) && (filestat.st_mode & S_IRUSR) && (filestat.st_mode & S_IWUSR)) ||
+	((gid == filestat.st_gid) && (filestat.st_mode & S_IRGRP) && (filestat.st_mode & S_IWGRP)) || 
+	((filestat.st_mode & S_IROTH) && (filestat.st_mode & S_IWOTH))) {
+    } else {
+      fprintf (stderr, "ERROR: can't write to %s\n", filename);
+      exit (1);
+    }
+  }
+}
Index: trunk/Ohana/src/relphot/src/find_images.c
===================================================================
--- trunk/Ohana/src/relphot/src/find_images.c	(revision 4828)
+++ trunk/Ohana/src/relphot/src/find_images.c	(revision 4864)
@@ -7,11 +7,9 @@
    images */
 
-Image *find_images (GSCRegion *region, int Nregion, int *Nimages, int **LineNum) {
-  
-  Header header;
+Image *find_images (FITS_DB *db, GSCRegion *region, int Nregion, int *Nimage, int **LineNum) {
+  
   Image *timage, *image;
-  int i, j, k, m, found, nimage, Nimage, NIMAGE;
-  int status, InRange, ecode;
-  FILE *f;
+  int i, j, k, m, found, nimage, Ntimage, NIMAGE;
+  int InRange, ecode;
   double Xc[5], Yc[5], Xi[5], Yi[5], r, d, dx, dy;
   int *line_number;
@@ -29,31 +27,5 @@
   strcpy (tcoords.ctype, "RA---TAN");
 
-  /* check if image datafile exists, get header, number of images */
-  if (!fits_read_header (ImageCat, &header)) {
-    fprintf (stderr, "ERROR: No images in catalog %s (1)\n", ImageCat);
-    exit (0);
-  }
-  Nimage = 0;
-  fits_scan (&header, "NIMAGES", "%d", 1, &Nimage);
-  if (Nimage == 0) {
-    fprintf (stderr, "ERROR: No images in catalog %s (1)\n", ImageCat);
-    exit (0);
-  }
-
-  /* get ready to read data on images */ 
-  f = fopen (ImageCat, "r");
-  if (f == (FILE *) NULL) {
-    fprintf (stderr, "ERROR: trouble opening Image catalog: %s (2)\n", ImageCat);
-    exit (0);
-  }
-  fseek (f, header.size, SEEK_SET); 
-
-  /* load all images */
-  ALLOCATE (timage, Image, Nimage);
-  status = Fread (timage, sizeof(Image), Nimage, f, "image");
-  if (status != Nimage) {
-    fprintf (stderr, "ERROR: couldn't read images from image catalog: %s\n", ImageCat);
-    exit (0);
-  }
+  timage = fits_table_get_Image (&db[0].ftable, &Ntimage, &db[0].swapped);
 
   nimage = 0;
@@ -62,5 +34,5 @@
   ALLOCATE (line_number, int, NIMAGE);
   
-  for (i = 0; i < Nimage; i++) {
+  for (i = 0; i < Ntimage; i++) {
       
     /* select images by photcode */
@@ -153,8 +125,6 @@
   REALLOCATE (line_number, int, MAX (nimage, 1));
 
-  free (timage);
-  *Nimages = nimage;
+  *Nimage  = nimage;
   *LineNum = line_number;
-  fclose (f);
   return (image);
 }
Index: trunk/Ohana/src/relphot/src/image-db.c
===================================================================
--- trunk/Ohana/src/relphot/src/image-db.c	(revision 4864)
+++ trunk/Ohana/src/relphot/src/image-db.c	(revision 4864)
@@ -0,0 +1,27 @@
+# include "relphot.h"
+
+void lock_image_db (FITS_DB *db, char *filename) {
+
+  /* lock the image catalog */
+  check_permissions (filename);
+
+  db[0].lockstate = LCK_XCLD;
+  db[0].timeout   = 3600.0;
+  fits_db_init (db);
+
+  if (!fits_db_lock (db, filename)) {
+    fprintf (stderr, "ERROR: can't lock image catalog\n");
+    exit (1);
+  }
+}
+
+void unlock_image_db (FITS_DB *db) {
+
+  mode_t mode;
+
+  fits_db_close (db);
+
+  /* force permissions to 666 */
+  mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
+  chmod (db[0].filename, mode);
+}
Index: trunk/Ohana/src/relphot/src/load_images.c
===================================================================
--- trunk/Ohana/src/relphot/src/load_images.c	(revision 4828)
+++ trunk/Ohana/src/relphot/src/load_images.c	(revision 4864)
@@ -1,27 +1,32 @@
 # include "relphot.h"
 
-static int   Nimage;
-static int   *Line;
-static Image *image;
-
-GSCRegion *load_images (char *seed, int *nregion, GSCRegion *fullregion) {
+GSCRegion *load_images (FITS_DB *db, char *seed, int *nregion, GSCRegion *fullregion) {
 
   GSCRegion *region;
-  int       Nregion, Ntimage;
-  Image     *timage;
+  int        Nregion;
+  Image     *image;
+  int       *Line;
+  int        Nimage;
+
+  if (db[0].dbstate == LCK_EMPTY) Shutdown ("ERROR: No images in catalog %s (1)", db[0].filename);
+
+  /* read entire db table */
+  if (!dvo_image_load (db, VERBOSE, FALSE)) Shutdown ("can't read image catalog %s", db[0].filename);
 
   region = name_region (seed, &Nregion);
 
   /* find images which supplied all measurements */
-  timage = find_images (region, Nregion, &Ntimage, &Line);
+  image = find_images (db, region, Nregion, &Nimage, &Line);
   free (Line);
 
   /* find all region files which touch images */
-  region = find_regions (timage, Ntimage, &Nregion, fullregion);
-  free (timage);
+  region = find_regions (image, Nimage, &Nregion, fullregion);
+  free (image);
 
   /* find images which supplied all measurements for all regions */
-  image = find_images (region, Nregion, &Nimage, &Line);
+  image = find_images (db, region, Nregion, &Nimage, &Line);
   getfullregion (image, Nimage, fullregion);
+
+  fits_vtable_from_ftable (&db[0].ftable, &db[0].vtable, Line, Nimage);
 
   initImages (image, Nimage);
@@ -30,38 +35,3 @@
   *nregion = Nregion;
   return (region);
-
 }
-
-void wimages () {
-  
-  int i, status, mode;
-  FILE *f;
-  Header header;
-
-  setMcalFinal (image, Nimage);
-
-  if (!fits_read_header (ImageCat, &header)) {
-    fprintf (stderr, "ERROR: can't find %s\n", ImageCat);
-    exit (0);
-  }
-  
-  f = fopen (ImageCat, "r+");
-  if (f == NULL) {
-    fprintf (stderr, "ERROR: can't open image catalog file to append: %s\n", ImageCat);
-    exit (0);
-  }
-  mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
-  chmod (ImageCat, mode);
-
-  if (VERBOSE) fprintf (stderr, "writing out %d images\n", Nimage);
-  for (i = 0; i < Nimage; i++) {
-    fseek (f, header.size + Line[i]*sizeof(Image), SEEK_SET);
-    status = Fwrite (&image[i], sizeof(Image), 1, f, "image");
-    if (status != 1) {
-      fprintf (stderr, "ERROR: failure writing image data to catalog %s\n", ImageCat);
-      exit (0);
-    }
-  }
-
-  fclose (f);
-}
Index: trunk/Ohana/src/relphot/src/relphot.c
===================================================================
--- trunk/Ohana/src/relphot/src/relphot.c	(revision 4828)
+++ trunk/Ohana/src/relphot/src/relphot.c	(revision 4864)
@@ -7,10 +7,14 @@
   Catalog *catalog;
   GSCRegion fullregion, *region;
+  FITS_DB db;
 
   /* get configuration info, args */
   initialize (argc, argv);
 
+  set_db (&db);
+  lock_image_db (&db, ImageCat);
+
   /* load regions and images based on seed region */
-  region = load_images (argv[1], &Ncatalog, &fullregion);
+  region = load_images (&db, argv[1], &Ncatalog, &fullregion);
 
   /* load catalog data from region files */
@@ -79,5 +83,8 @@
   /* load catalog data from region files, update Mrel include all data */
   reload_catalogs (region, Ncatalog, &fullregion);
-  wimages (); 
+  setMcalFinal ();
+  dvo_image_update (&db, VERBOSE);
+  unlock_image_db (&db); 
+
   exit (0);
 }
Index: trunk/Ohana/src/relphot/src/wimages.c
===================================================================
--- trunk/Ohana/src/relphot/src/wimages.c	(revision 4864)
+++ trunk/Ohana/src/relphot/src/wimages.c	(revision 4864)
@@ -0,0 +1,45 @@
+# include "relphot.h"
+
+/* add 1 image to image db */
+void wimages (FITS_DB *db, Image *image, int Nimage) {
+  
+  int status, Nimages;
+
+  /* set permissions somewhere ...
+  mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
+  fchmod (ImageCat, mode); */
+
+  /* adjust header */
+  Nimages = 0;
+  fits_scan (&db[0].header, "NIMAGES", "%d", 1, &Nimages);
+  Nimages ++;
+  fits_modify (&db[0].header, "NIMAGES", "%d", 1, Nimages);
+
+  fits_table_to_vtable (&db[0].ftable, &db[0].vtable, 0, 0);
+  for (i = 0; i < Nimage; i++) {
+    fits_vadd_rows (&db[0].vtable, (char *) image, 1, sizeof(Image));
+  }
+
+  /* check that primary header and table header agree */
+  if (Nimages != db[0].header.Naxis[1]) {
+    fprintf (stderr, "header / table length mismatch!\n");
+  }
+
+  SetProtect (TRUE);
+  status = dvo_image_update (db, VERBOSE);
+  SetProtect (FALSE);
+
+  if (!status) {
+    fprintf (stderr, "ERROR: failed writing data to image catalog\n");
+    exit (1);
+  }
+}
+
+/* add the new image to the image table:
+   - use the table header (from ftable)
+   - create an empty vtable
+   - add the new image to the end of the vtable
+   
+   - write out the vtable, either as TEXT or FITS
+   * dvo_image_update performs the needed byte-swap on the image data
+*/
