[Midnightbsd-cvs] src: lib/libmport: Latest developement version of libmport.

ctriv at midnightbsd.org ctriv at midnightbsd.org
Sat Jan 5 17:18:20 EST 2008


Log Message:
-----------
Latest developement version of libmport.

Changes:

It is now possible to create, install, and delete packages from a system
with the library.

The install primative now uses the progress callback system to give the user
feedback during the install.

Support for installing into a chroot envirement is included at the library 
level.  This is useful if you have a GUI app and you don't want your entire
process stuck in the chroot.

Many function names have been changed in an effort to improve the library's
orginization.

Many bug fixes and subtle changes.  

Todo:

Docs: 
	library overview.
	function reference.
	mport bundle specification.

The merge primative.

The fetch primative.

The update primative.

Top level functions to do things like "fetch this bundle, its depends, and
then install them all."

Some of the sematics are still up in the air.  For example, gtk12 and 
gtk2 both have a pkgname of gtk.  libmport doesn't allow two package with
the same name to be installed.

Hard links are not implemented in a mport bundle.

Much more testing and bug fixing is needed.

Modified Files:
--------------
    src/lib/libmport:
        Makefile (r1.5 -> r1.6)
        db.c (r1.2 -> r1.3)
        error.c (r1.5 -> r1.6)
        mport.h (r1.8 -> r1.9)
        plist.c (r1.3 -> r1.4)
        util.c (r1.8 -> r1.9)

Added Files:
-----------
    src/lib/libmport:
        bundle.c (r1.1)
        check_preconditions.c (r1.1)
        create_primative.c (r1.1)
        default_cbs.c (r1.1)
        delete_primative.c (r1.1)
        install_primative.c (r1.1)
        instance.c (r1.1)

Removed Files:
-------------
    src/lib/libmport:
        archive.c
        create_pkg.c
        inst_init.c
        install_pkg.c

-------------- next part --------------
Index: plist.c
===================================================================
RCS file: /home/cvs/src/lib/libmport/plist.c,v
retrieving revision 1.3
retrieving revision 1.4
diff -L lib/libmport/plist.c -L lib/libmport/plist.c -u -r1.3 -r1.4
--- lib/libmport/plist.c
+++ lib/libmport/plist.c
@@ -32,10 +32,9 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <ctype.h>
 #include "mport.h"
 
-__MBSDID("$MidnightBSD$");
-
 #define CMND_MAGIC_COOKIE '@'
 #define STRING_EQ(r,l) (strcmp((r),(l)) == 0)
 
@@ -44,7 +43,7 @@
 /* Do everything needed to set up a new plist.  Always use this to create a plist,
  * don't go off and do it yourself.
  */
-mportPlist* mport_new_plist() 
+mportPlist* mport_plist_new() 
 {
   mportPlist *list = (mportPlist*)malloc(sizeof(mportPlist));
   STAILQ_INIT(list);
@@ -52,8 +51,8 @@
 }
 
 
-/* free all the entryes in the list, and then the list itself. */
-void mport_free_plist(mportPlist *list) 
+/* free all the entries in the list, and then the list itself. */
+void mport_plist_free(mportPlist *list) 
 {
   mportPlistEntry *n;
 
@@ -72,7 +71,7 @@
  *
  * Returns NULL on failure.
  */
-int mport_parse_plist_file(FILE *fp, mportPlist *list)
+int mport_plist_parsefile(FILE *fp, mportPlist *list)
 {
   size_t length;
   char *line;
@@ -133,6 +132,13 @@
       if (entry->data == NULL) {
         return MPORT_ERR_NO_MEM;
       }
+
+      char *pos = line + strlen(line) - 1;
+      
+      while (isspace(*pos)) {
+        *pos = 0;
+        pos--;
+      }
       
       strlcpy(entry->data, line, (strlen(line) + 1));
     }
Index: util.c
===================================================================
RCS file: /home/cvs/src/lib/libmport/util.c,v
retrieving revision 1.8
retrieving revision 1.9
diff -L lib/libmport/util.c -L lib/libmport/util.c -u -r1.8 -r1.9
--- lib/libmport/util.c
+++ lib/libmport/util.c
@@ -37,42 +37,56 @@
 #include <libgen.h>
 #include "mport.h"
 
-__MBSDID("$MidnightBSD$");
-
 /* Package meta-data creation and destruction */
-mportPackageMeta* mport_new_packagemeta() 
+mportPackageMeta* mport_packagemeta_new() 
 {
   /* we use calloc so any pointers that aren't set are NULL.
      (calloc zero's out the memory region. */
   return (mportPackageMeta *)calloc(1, sizeof(mportPackageMeta));
 }
 
-void mport_free_packagemeta(mportPackageMeta *pack)
+void mport_packagemeta_free(mportPackageMeta *pack)
 {
   free(pack->pkg_filename);
   free(pack->comment);
   free(pack->sourcedir);
   free(pack->desc);
   free(pack->prefix);
-  free(*(pack->depends));
   free(pack->depends);
   free(pack->mtree);
   free(pack->origin);
-  free(*(pack->conflicts));
   free(pack->conflicts);
   free(pack->pkginstall);
   free(pack->pkgdeinstall);
   free(pack->pkgmessage);
+  
+  if (pack->conflicts != NULL)
+    free(*(pack->conflicts));
+  
+  if (pack->depends != NULL)
+    free(*(pack->depends));
+
   free(pack);
 }
 
+/* free a vector of mportPackageMeta pointers */
+void mport_packagemeta_vec_free(mportPackageMeta **vec)
+{
+  int i;
+  for (i=0; *(vec + i) != NULL; i++) {
+    mport_packagemeta_free(*(vec + i));
+  }
+  
+  free(vec);
+}
+
 
 /* deletes the entire directory tree at name.
  * think rm -r filename
  */
 int mport_rmtree(const char *filename) 
 {
-  return mport_xsystem("/bin/rm -r %s", filename);
+  return mport_xsystem(NULL, "/bin/rm -r %s", filename);
 }  
 
 
@@ -82,7 +96,7 @@
  */
 int mport_copy_file(const char *fromname, const char *toname)
 {
-  return mport_xsystem("/bin/cp %s %s", fromname, toname);
+  return mport_xsystem(NULL, "/bin/cp %s %s", fromname, toname);
 }
 
 
@@ -100,9 +114,28 @@
   
   return MPORT_OK;
 }
-  
+
 
 /*
+ * mport_rmdir(dir, ignore_nonempty)
+ *
+ * delete the given directory.  If ignore_nonempty is non-zero, then
+ * we return OK even if we couldn't delete the dir because it wasn't empty or
+ * didn't exist.
+ */
+int mport_rmdir(const char *dir, int ignore_nonempty)
+{
+  if (rmdir(dir) != 0) {
+    if (ignore_nonempty && (errno == ENOTEMPTY || errno == ENOENT)) {
+      return MPORT_OK;
+    } else {
+      RETURN_ERROR(MPORT_ERR_SYSCALL_FAILED, strerror(errno));
+    }
+  } 
+  
+  return MPORT_OK;
+}
+/*
  * Quick test to see if a file exists.
  */
 int mport_file_exists(const char *file) 
@@ -113,23 +146,36 @@
 }
 
 
-/* mport_xsystem(char *fmt, ...)
+/* mport_xsystem(mportInstance *mport, char *fmt, ...)
  * 
  * Our own version on system that takes a format string and a list 
  * of values.  The fmt works exactly like the stdio output formats.
+ * 
+ * If mport is non-NULL and has a root set, your command will run 
+ * chroot'ed into mport->root.
  */
-int mport_xsystem(const char *fmt, ...) 
+int mport_xsystem(mportInstance *mport, const char *fmt, ...) 
 {
   va_list args;
   char *cmnd;
   int ret;
   
   va_start(args, fmt);
+  
   if (vasprintf(&cmnd, fmt, args) == -1) {
     /* XXX How will the caller know this is no mem, and not a failed exec? */
     return MPORT_ERR_NO_MEM;
   }
+ 
+  if (mport != NULL && *(mport->root) != '\0') {
+    char *chroot_cmd;
+    if (asprintf(&chroot_cmd, "%s %s %s", MPORT_CHROOT_BIN, mport->root, cmnd) == -1)
+      return MPORT_ERR_NO_MEM;
   
+    free(cmnd);
+    cmnd = chroot_cmd;
+  }
+    
   ret = system(cmnd);
   
   free(cmnd);
@@ -202,11 +248,12 @@
  * %B	Return the directory part ("dirname") of %D/%F
  * %f	Return the filename part of ("basename") %D/%F
  */
-int mport_run_plist_exec(const char *fmt, const char *cwd, const char *last_file) 
+int mport_run_plist_exec(mportInstance *mport, const char *fmt, const char *cwd, const char *last_file) 
 {
   size_t l;
   size_t max = FILENAME_MAX * 2;
   char cmnd[max];
+  char fqfile[FILENAME_MAX];
   char *pos = cmnd;
   char *name;
   
@@ -215,30 +262,31 @@
       fmt++;
       switch (*fmt) {
         case 'F':
-          strlcpy(pos, last_file, max);
+          (void)strlcpy(pos, last_file, max);
           l = strlen(last_file);
           pos += l;
           max -= l;
           break;
         case 'D':
-          strlcpy(pos, cwd, max);
+          (void)strlcpy(pos, cwd, max);
           l = strlen(cwd);
           pos += l;
           max -= l;
           break;
         case 'B':
-          name = dirname(last_file);
-          strlcpy(pos, name, max);
+          (void)snprintf(fqfile, sizeof(fqfile), "%s/%s", cwd, last_file);
+          name = dirname(fqfile);
+          (void)strlcpy(pos, name, max);
           l = strlen(name);
           pos += l;
           max -= l;
           break;
         case 'f':
           name = basename(last_file);
-          strlcpy(pos, name, max);
+          (void)strlcpy(pos, name, max);
           l = strlen(name);
           pos += l;
-          pos -= l;
+          max -= l;
           break;
         default:
           *pos = *fmt;
@@ -257,6 +305,6 @@
   *pos = '\0';
   
   /* cmnd now hold the expaded command, now execute it*/
-  return mport_xsystem(cmnd);
+  return mport_xsystem(mport, cmnd);
 }          
 
--- /dev/null
+++ lib/libmport/create_primative.c
@@ -0,0 +1,432 @@
+/*-
+ * Copyright (c) 2007 Chris Reinhardt
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $MidnightBSD: src/lib/libmport/create_primative.c,v 1.1 2008/01/05 22:18:20 ctriv Exp $
+ */
+
+
+
+#include <sys/cdefs.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sqlite3.h>
+#include <md5.h>
+#include <archive.h>
+#include <archive_entry.h>
+#include "mport.h"
+
+__MBSDID("$MidnightBSD: src/lib/libmport/create_primative.c,v 1.1 2008/01/05 22:18:20 ctriv Exp $");
+
+
+static int create_stub_db(sqlite3 **);
+static int insert_plist(sqlite3 *, mportPlist *, mportPackageMeta *);
+static int insert_meta(sqlite3 *, mportPackageMeta *);
+static int insert_depends(sqlite3 *, mportPackageMeta *);
+static int insert_conflicts(sqlite3 *, mportPackageMeta *);
+static int archive_files(mportPlist *, mportPackageMeta *, const char *);
+static int archive_metafiles(mportBundle *, mportPackageMeta *);
+static int archive_plistfiles(mportBundle *, mportPackageMeta *, mportPlist *);
+static int clean_up(const char *);
+
+
+int mport_create_primative(mportPlist *plist, mportPackageMeta *pack)
+{
+  
+  int ret;
+  sqlite3 *db;
+
+  char dirtmpl[] = "/tmp/mport.XXXXXXXX"; 
+  char *tmpdir = mkdtemp(dirtmpl);
+
+  if (tmpdir == NULL) {
+    ret = SET_ERROR(MPORT_ERR_FILEIO, strerror(errno));
+    goto CLEANUP;
+  }
+  if (chdir(tmpdir) != 0)  {
+    ret = SET_ERROR(MPORT_ERR_FILEIO, strerror(errno));
+    goto CLEANUP;
+  }
+
+  if ((ret = create_stub_db(&db)) != MPORT_OK)
+    goto CLEANUP;
+    
+  if ((ret = insert_plist(db, plist, pack)) != MPORT_OK)
+    goto CLEANUP;
+  
+  if ((ret = insert_meta(db, pack)) != MPORT_OK)
+    goto CLEANUP;
+    
+  if (sqlite3_close(db) != SQLITE_OK) {
+    ret = SET_ERROR(MPORT_ERR_SQLITE, sqlite3_errmsg(db));
+    goto CLEANUP;
+  }
+    
+  if ((ret = archive_files(plist, pack, tmpdir)) != MPORT_OK)
+    goto CLEANUP;
+  
+  CLEANUP:  
+    clean_up(tmpdir);
+    return ret;
+}
+
+
+static int create_stub_db(sqlite3 **db) 
+{
+  if (sqlite3_open(MPORT_STUB_DB_FILE, db) != SQLITE_OK) {
+    sqlite3_close(*db);
+    RETURN_ERROR(MPORT_ERR_SQLITE, sqlite3_errmsg(*db));
+  }
+  
+  /* create tables */
+  return mport_generate_stub_schema(*db);
+}
+
+static int insert_plist(sqlite3 *db, mportPlist *plist, mportPackageMeta *pack)
+{
+  mportPlistEntry *e;
+  sqlite3_stmt *stmnt;
+  char sql[]  = "INSERT INTO assets (pkg, type, data, checksum) VALUES (?,?,?,?)";
+  char md5[33];
+  char file[FILENAME_MAX];
+  char cwd[FILENAME_MAX];
+  struct stat st;
+
+  strlcpy(cwd, pack->sourcedir, FILENAME_MAX);
+  strlcat(cwd, pack->prefix, FILENAME_MAX);
+  
+  if (mport_db_prepare(db, &stmnt, sql) != MPORT_OK) 
+    RETURN_CURRENT_ERROR;
+  
+  STAILQ_FOREACH(e, plist, next) {
+    if (e->type == PLIST_CWD) {
+      strlcpy(cwd, pack->sourcedir, FILENAME_MAX);
+      if (e->data == NULL) {
+        strlcat(cwd, pack->prefix, FILENAME_MAX);
+      } else {
+        strlcat(cwd, e->data, FILENAME_MAX);
+      }
+    }
+    
+    if (sqlite3_bind_text(stmnt, 1, pack->name, -1, SQLITE_STATIC) != SQLITE_OK) {
+      RETURN_ERROR(MPORT_ERR_SQLITE, sqlite3_errmsg(db));
+    }
+    if (sqlite3_bind_int(stmnt, 2, e->type) != SQLITE_OK) {
+      RETURN_ERROR(MPORT_ERR_SQLITE, sqlite3_errmsg(db));
+    }
+    if (sqlite3_bind_text(stmnt, 3, e->data, -1, SQLITE_STATIC) != SQLITE_OK) {
+      RETURN_ERROR(MPORT_ERR_SQLITE, sqlite3_errmsg(db));
+    }
+    
+    if (e->type == PLIST_FILE) {
+      (void)snprintf(file, FILENAME_MAX, "%s/%s", cwd, e->data);
+      
+      if (lstat(file, &st) != 0) 
+        RETURN_ERRORX(MPORT_ERR_FILE_NOT_FOUND, "Couln't stat %s: %s", file, strerror(errno));
+      
+      if (S_ISREG(st.st_mode)) {
+
+        if (MD5File(file, md5) == NULL) 
+          RETURN_ERRORX(MPORT_ERR_FILE_NOT_FOUND, "File not found: %s", file);
+      
+        if (sqlite3_bind_text(stmnt, 4, md5, -1, SQLITE_STATIC) != SQLITE_OK) 
+          RETURN_ERROR(MPORT_ERR_SQLITE, sqlite3_errmsg(db));
+      } else {
+        sqlite3_bind_null(stmnt, 4);
+      }
+    } else {
+      if (sqlite3_bind_null(stmnt, 4) != SQLITE_OK) {
+        RETURN_ERROR(MPORT_ERR_SQLITE, sqlite3_errmsg(db));
+      }
+    }
+    
+    if (sqlite3_step(stmnt) != SQLITE_DONE) {
+      RETURN_ERROR(MPORT_ERR_SQLITE, sqlite3_errmsg(db));
+    }
+        
+    sqlite3_reset(stmnt);
+  } 
+  
+  sqlite3_finalize(stmnt);
+  
+  return MPORT_OK;
+}     
+
+static int insert_meta(sqlite3 *db, mportPackageMeta *pack)
+{
+  sqlite3_stmt *stmnt;
+  const char *rest  = 0;
+  struct timespec now;
+  int ret;
+  
+  char sql[]  = "INSERT INTO packages (pkg, version, origin, lang, prefix, date) VALUES (?,?,?,?,?,?)";
+  
+  if (sqlite3_prepare_v2(db, sql, -1, &stmnt, &rest) != SQLITE_OK) {
+    RETURN_ERROR(MPORT_ERR_SQLITE, sqlite3_errmsg(db));
+  }
+  if (sqlite3_bind_text(stmnt, 1, pack->name, -1, SQLITE_STATIC) != SQLITE_OK) {
+    RETURN_ERROR(MPORT_ERR_SQLITE, sqlite3_errmsg(db));
+  }
+  if (sqlite3_bind_text(stmnt, 2, pack->version, -1, SQLITE_STATIC) != SQLITE_OK) {
+    RETURN_ERROR(MPORT_ERR_SQLITE, sqlite3_errmsg(db));
+  }
+  if (sqlite3_bind_text(stmnt, 3, pack->origin, -1, SQLITE_STATIC) != SQLITE_OK) {
+    RETURN_ERROR(MPORT_ERR_SQLITE, sqlite3_errmsg(db));
+  }
+  if (sqlite3_bind_text(stmnt, 4, pack->lang, -1, SQLITE_STATIC) != SQLITE_OK) {
+    RETURN_ERROR(MPORT_ERR_SQLITE, sqlite3_errmsg(db));
+  }
+  if (sqlite3_bind_text(stmnt, 5, pack->prefix, -1, SQLITE_STATIC) != SQLITE_OK) {
+    RETURN_ERROR(MPORT_ERR_SQLITE, sqlite3_errmsg(db));
+  }
+  if (clock_gettime(CLOCK_REALTIME, &now) != 0) {
+    RETURN_ERROR(MPORT_ERR_SYSCALL_FAILED, strerror(errno));
+  }
+  
+  if (sqlite3_bind_int(stmnt, 6, now.tv_sec) != SQLITE_OK) {
+    RETURN_ERROR(MPORT_ERR_SQLITE, sqlite3_errmsg(db));
+  }
+    
+  if (sqlite3_step(stmnt) != SQLITE_DONE) {
+    RETURN_ERROR(MPORT_ERR_SQLITE, sqlite3_errmsg(db));
+  }
+  
+  sqlite3_finalize(stmnt);  
+
+  /* insert depends and conflicts */
+  if ((ret = insert_depends(db, pack)) != MPORT_OK)
+    return ret;  
+  if ((ret = insert_conflicts(db, pack)) != MPORT_OK)
+    return ret;
+    
+  return MPORT_OK;
+}
+
+
+static int insert_conflicts(sqlite3 *db, mportPackageMeta *pack) 
+{
+  sqlite3_stmt *stmnt;
+  char **conflict  = pack->conflicts;
+  char *version;
+  
+  /* we're done if there are no conflicts to record. */
+  if (conflict == NULL) 
+    return MPORT_OK;
+
+  if (mport_db_prepare(db, &stmnt, "INSERT INTO conflicts (pkg, conflict_pkg, conflict_version) VALUES (?,?,?)") != MPORT_OK)
+    RETURN_CURRENT_ERROR;
+    
+  /* we have a conflict like apache-1.4.  We want to do a m/(.*)-(.*)/ */
+  while (*conflict != NULL) {
+    version = rindex(*conflict, '-');
+    *version = '\0';
+    version++;
+    
+    if (sqlite3_bind_text(stmnt, 1, pack->name, -1, SQLITE_STATIC) != SQLITE_OK) {
+      RETURN_ERROR(MPORT_ERR_SQLITE, sqlite3_errmsg(db));
+    }
+    if (sqlite3_bind_text(stmnt, 2, *conflict, -1, SQLITE_STATIC) != SQLITE_OK) {
+      RETURN_ERROR(MPORT_ERR_SQLITE, sqlite3_errmsg(db));
+    }
+    if (sqlite3_bind_text(stmnt, 3, version, -1, SQLITE_STATIC) != SQLITE_OK) {
+      RETURN_ERROR(MPORT_ERR_SQLITE, sqlite3_errmsg(db));
+    }
+    if (sqlite3_step(stmnt) != SQLITE_DONE) {
+      RETURN_ERROR(MPORT_ERR_SQLITE, sqlite3_errmsg(db));
+    }
+    sqlite3_reset(stmnt);
+    conflict++;
+  }
+  
+  sqlite3_finalize(stmnt);
+  
+  return MPORT_OK;
+}
+    
+  
+
+static int insert_depends(sqlite3 *db, mportPackageMeta *pack) 
+{
+  sqlite3_stmt *stmnt;
+  char **depend    = pack->depends;
+  char *pkgversion;
+  char *port;
+  
+  /* we're done if there are no deps to record. */
+  if (depend == NULL) 
+    return MPORT_OK;
+
+  if (mport_db_prepare(db, &stmnt, "INSERT INTO depends (pkg, depend_pkgname, depend_pkgversion, depend_port) VALUES (?,?,?,?)") != MPORT_OK)
+    RETURN_CURRENT_ERROR;
+    
+  /* depends look like this.  break'em up into port, pkgversion and pkgname
+   * perl-5.8.8_1:lang/perl5.8
+   */
+  while (*depend != NULL) {
+    port = rindex(*depend, ':');
+    *port = '\0';
+    port++;
+
+    if (*port == 0)
+      RETURN_ERRORX(MPORT_ERR_MALFORMED_DEPEND, "Maformed depend: %s", *depend);
+    
+    pkgversion = rindex(*depend, '-');
+    *pkgversion = '\0';
+    pkgversion++;
+    
+    if (*pkgversion == 0)
+      RETURN_ERRORX(MPORT_ERR_MALFORMED_DEPEND, "Maformed depend: %s", *depend);
+      
+    if (sqlite3_bind_text(stmnt, 1, pack->name, -1, SQLITE_STATIC) != SQLITE_OK) {
+      RETURN_ERROR(MPORT_ERR_SQLITE, sqlite3_errmsg(db));
+    }
+    if (sqlite3_bind_text(stmnt, 2, *depend, -1, SQLITE_STATIC) != SQLITE_OK) {
+      RETURN_ERROR(MPORT_ERR_SQLITE, sqlite3_errmsg(db));
+    }
+    if (sqlite3_bind_text(stmnt, 3, pkgversion, -1, SQLITE_STATIC) != SQLITE_OK) {
+      RETURN_ERROR(MPORT_ERR_SQLITE, sqlite3_errmsg(db));
+    }
+    if (sqlite3_bind_text(stmnt, 4, port, -1, SQLITE_STATIC) != SQLITE_OK) {
+      RETURN_ERROR(MPORT_ERR_SQLITE, sqlite3_errmsg(db));
+    }
+    if (sqlite3_step(stmnt) != SQLITE_DONE) {
+      RETURN_ERROR(MPORT_ERR_SQLITE, sqlite3_errmsg(db));
+    }
+    sqlite3_reset(stmnt);
+    depend++;
+  }
+    
+  sqlite3_finalize(stmnt);
+  
+  return MPORT_OK;
+}
+
+
+
+static int archive_files(mportPlist *plist, mportPackageMeta *pack, const char *tmpdir)
+{
+  mportBundle *bundle;
+  char filename[FILENAME_MAX];
+  
+  bundle = mport_bundle_new();
+  
+  if (mport_bundle_init(bundle, pack->pkg_filename) != MPORT_OK)
+    RETURN_CURRENT_ERROR;
+
+  /* First step - +CONTENTS.db ALWAYS GOES FIRST!!! */        
+  (void)snprintf(filename, FILENAME_MAX, "%s/%s", tmpdir, MPORT_STUB_DB_FILE);
+  if (mport_bundle_add_file(bundle, filename, MPORT_STUB_DB_FILE)) 
+    RETURN_CURRENT_ERROR;
+    
+  /* second step - the meta files */
+  if (archive_metafiles(bundle, pack) != MPORT_OK)
+    RETURN_CURRENT_ERROR;
+  
+  /* last step - the real files from the plist */
+  if (archive_plistfiles(bundle, pack, plist) != MPORT_OK)
+    RETURN_CURRENT_ERROR;
+    
+  mport_bundle_finish(bundle);
+  
+  return MPORT_OK;    
+}
+
+
+static int archive_metafiles(mportBundle *bundle, mportPackageMeta *pack)
+{
+  char filename[FILENAME_MAX], dir[FILENAME_MAX];
+  
+  (void)snprintf(dir, FILENAME_MAX, "%s/%s-%s", MPORT_STUB_INFRA_DIR, pack->name, pack->version);
+
+  if (pack->mtree != NULL && mport_file_exists(pack->mtree)) {
+    (void)snprintf(filename, FILENAME_MAX, "%s/%s", dir, MPORT_MTREE_FILE);
+    if (mport_bundle_add_file(bundle, pack->mtree, filename) != MPORT_OK)
+      RETURN_CURRENT_ERROR;
+  }
+  
+  if (pack->pkginstall != NULL && mport_file_exists(pack->pkginstall)) {
+    (void)snprintf(filename, FILENAME_MAX, "%s/%s", dir, MPORT_INSTALL_FILE);
+    if (mport_bundle_add_file(bundle, pack->pkginstall, filename) != MPORT_OK)
+      RETURN_CURRENT_ERROR;
+  }
+  
+  if (pack->pkgdeinstall != NULL && mport_file_exists(pack->pkgdeinstall)) {
+    (void)snprintf(filename, FILENAME_MAX, "%s/%s", dir, MPORT_DEINSTALL_FILE);
+    if (mport_bundle_add_file(bundle, pack->pkgdeinstall, filename) != MPORT_OK)
+      RETURN_CURRENT_ERROR;
+  }
+  
+  if (pack->pkgmessage != NULL && mport_file_exists(pack->pkgmessage)) {
+    (void)snprintf(filename, FILENAME_MAX, "%s/%s", dir, MPORT_MESSAGE_FILE);
+    if (mport_bundle_add_file(bundle, pack->pkgmessage, filename) != MPORT_OK)
+      RETURN_CURRENT_ERROR;
+  }
+  
+  return MPORT_OK;
+}
+
+static int archive_plistfiles(mportBundle *bundle, mportPackageMeta *pack, mportPlist *plist)
+{
+  mportPlistEntry *e;
+  char filename[FILENAME_MAX];
+  char *cwd = pack->prefix;
+  
+  STAILQ_FOREACH(e, plist, next) {
+    if (e->type == PLIST_CWD) 
+      cwd = e->data == NULL ? pack->prefix : e->data;
+    
+    if (e->type != PLIST_FILE) {
+      continue;
+    }
+    
+    (void)snprintf(filename, FILENAME_MAX, "%s/%s/%s", pack->sourcedir, cwd, e->data);
+    
+    if (mport_bundle_add_file(bundle, filename, e->data) != MPORT_OK)
+      RETURN_CURRENT_ERROR;
+  }    
+ 
+  return MPORT_OK;
+}
+
+#ifdef DEBUG
+
+static int clean_up(const char *tmpdir)
+{
+  /* do nothing */
+}
+
+#else
+
+static int clean_up(const char *tmpdir) 
+{
+  return mport_rmtree(tmpdir);
+}
+
+#endif
+
Index: error.c
===================================================================
RCS file: /home/cvs/src/lib/libmport/error.c,v
retrieving revision 1.5
retrieving revision 1.6
diff -L lib/libmport/error.c -L lib/libmport/error.c -u -r1.5 -r1.6
--- lib/libmport/error.c
+++ lib/libmport/error.c
@@ -46,7 +46,15 @@
   "SQLite error.",
   "File not found."
   "System call failed.",
-  "libarchive error."
+  "libarchive error.",
+  "Package already installed.",
+  "Package conflicts with priviously installed package.",
+  "A depend is missing.",
+  "Malformed version.",
+  "Malformed depend.",
+  "No such package.",
+  "Checksum mismatch.",
+  "Packages depend on this package."
 };
   
 
--- /dev/null
+++ lib/libmport/install_primative.c
@@ -0,0 +1,376 @@
+/*-
+ * Copyright (c) 2007 Chris Reinhardt
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $MidnightBSD: src/lib/libmport/install_primative.c,v 1.1 2008/01/05 22:18:20 ctriv Exp $
+ */
+
+
+
+#include "mport.h"
+#include <sys/cdefs.h>
+#include <sys/stat.h>
+#include <libgen.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <archive.h>
+#include <archive_entry.h>
+
+static int do_pre_install(mportInstance *, mportPackageMeta *, const char *);
+static int do_actual_install(mportInstance *, struct archive *, struct archive_entry *, mportPackageMeta *, const char *);
+static int do_post_install(mportInstance *, mportPackageMeta *, const char *);
+static int run_pkg_install(mportInstance *, const char *, mportPackageMeta *, const char *);
+static int run_mtree(mportInstance *, const char *, mportPackageMeta *);
+static int display_pkg_msg(mportInstance *, mportPackageMeta *, const char *);
+static int clean_up(mportInstance *, const char *);
+static int rollback(void);
+
+int mport_install_primative(mportInstance *mport, const char *filename, const char *prefix) 
+{
+  /* 
+   * The general strategy here is to extract the meta-files into a tempdir, but
+   * extract the real files inplace.  There's huge IO overhead with having a stagging
+   * area. 
+   */
+  struct archive *a = archive_read_new();
+  struct archive_entry *entry;
+  char filepath[FILENAME_MAX];
+  const char *file;
+  sqlite3 *db = mport->db;
+  mportPackageMeta **packs;
+  mportPackageMeta *pack;
+  int i;
+  
+  /* extract the meta-files into the a temp dir */  
+  char dirtmpl[] = "/tmp/mport.XXXXXXXX"; 
+  char *tmpdir = mkdtemp(dirtmpl);
+
+  if (tmpdir == NULL)
+    RETURN_ERROR(MPORT_ERR_FILEIO, strerror(errno));
+    
+  archive_read_support_compression_bzip2(a);
+  archive_read_support_format_tar(a);
+
+  if (archive_read_open_filename(a, filename, 10240) != ARCHIVE_OK)
+    RETURN_ERROR(MPORT_ERR_ARCHIVE, archive_error_string(a));
+    
+  while (archive_read_next_header(a, &entry) == ARCHIVE_OK) {
+    file = archive_entry_pathname(entry);
+    
+    if (*file == '+') {
+      (void)snprintf(filepath, FILENAME_MAX, "%s/%s", tmpdir, file);
+      archive_entry_set_pathname(entry, filepath);
+      archive_read_extract(a, entry, 0);
+    } else {
+      break;
+    }
+  }
+
+  /* Attach the stub db */
+  if (mport_attach_stub_db(db, tmpdir) != MPORT_OK) 
+    RETURN_CURRENT_ERROR;
+
+  /* get the meta objects from the stub database */  
+  if (mport_get_meta_from_stub(db, &packs) != MPORT_OK)
+    RETURN_CURRENT_ERROR;
+
+  for (i=0; *(packs + i) != NULL; i++) {
+    pack  = *(packs + i);    
+
+    if (prefix != NULL) {
+      free(pack->prefix);
+      pack->prefix = strdup(prefix);
+    }
+    
+    /* check if this is installed already, depends, and conflicts */
+    if (mport_check_install_preconditions(mport, pack) != MPORT_OK)
+      RETURN_CURRENT_ERROR;
+
+    /* Run mtree.  Run pkg-install. Etc... */
+    if (do_pre_install(mport, pack, tmpdir) != MPORT_OK)
+      RETURN_CURRENT_ERROR;
+
+    if (do_actual_install(mport, a, entry, pack, tmpdir) != MPORT_OK)
+      RETURN_CURRENT_ERROR;
+    
+    archive_read_finish(a);
+    
+    if (do_post_install(mport, pack, tmpdir) != MPORT_OK)
+      RETURN_CURRENT_ERROR;
+  } 
+  
+  mport_packagemeta_vec_free(packs);
+  
+  if (clean_up(mport, tmpdir) != MPORT_OK)
+    RETURN_CURRENT_ERROR;
+  
+  return MPORT_OK;
+}
+
+/* This does everything that has to happen before we start installing files.
+ * We run mtree, pkg-install PRE-INSTALL, etc... 
+ */
+static int do_pre_install(mportInstance *mport, mportPackageMeta *pack, const char *tmpdir)
+{
+  int ret = MPORT_OK;
+  
+  /* run mtree */
+  if ((ret = run_mtree(mport, tmpdir, pack)) != MPORT_OK)
+    return ret;
+  
+  /* run pkg-install PRE-INSTALL */
+  if ((ret = run_pkg_install(mport, tmpdir, pack, "PRE-INSTALL")) != MPORT_OK)
+    return ret;
+
+  return ret;    
+}
+
+
+static int do_actual_install(
+      mportInstance *mport, 
+      struct archive *a, 
+      struct archive_entry *entry,
+      mportPackageMeta *pack, 
+      const char *tmpdir
+    )
+{
+  int ret, file_total;
+  int file_count = 0;
+  mportPlistEntryType type;
+  char *data; 
+  char file[FILENAME_MAX], last[FILENAME_MAX], cwd[FILENAME_MAX];
+  sqlite3_stmt *assets, *count;
+  sqlite3 *db;
+  
+ 
+  db = mport->db;
+
+  /* get the file count for the progress meter */
+  if (mport_db_prepare(db, &count, "SELECT COUNT(*) FROM stub.assets WHERE type=%i", PLIST_FILE) != MPORT_OK)
+    RETURN_CURRENT_ERROR;
+
+  switch (sqlite3_step(count)) {
+    case SQLITE_ROW:
+      file_total = sqlite3_column_int(count, 0);
+      sqlite3_finalize(count);
+      break;
+    default:
+      SET_ERROR(MPORT_ERR_SQLITE, sqlite3_errmsg(db));
+      sqlite3_finalize(count);
+      RETURN_CURRENT_ERROR;
+  }
+  
+  (mport->progress_init_cb)();
+  
+  if (mport_db_do(db, "BEGIN TRANSACTION") != MPORT_OK) 
+    goto ERROR;
+
+  /* Insert the package meta row into the packages table (We use pack here because things might have been twiddled) */  
+  if ((ret = mport_db_do(db, "INSERT INTO packages (pkg, version, origin, prefix, lang, options) VALUES (%Q,%Q,%Q,%Q,%Q,%Q)", pack->name, pack->version, pack->origin, pack->prefix, pack->lang, pack->options)) != MPORT_OK)
+    goto ERROR;
+  /* Insert the assets into the master table */
+  if ((ret = mport_db_do(db, "INSERT INTO assets (pkg, type, data, checksum) SELECT pkg,type,data,checksum FROM stub.assets WHERE pkg=%Q", pack->name)) != MPORT_OK)
+    goto ERROR;  
+  /* Insert the depends into the master table */
+  if ((ret = mport_db_do(db, "INSERT INTO depends (pkg, depend_pkgname, depend_pkgversion, depend_port) SELECT pkg,depend_pkgname,depend_pkgversion,depend_port FROM stub.depends WHERE pkg=%Q", pack->name)) != MPORT_OK) 
+    goto ERROR;
+  
+  if ((ret = mport_db_prepare(db, &assets, "SELECT type,data FROM stub.assets WHERE pkg=%Q", pack->name)) != MPORT_OK) 
+    goto ERROR;
+
+  (void)strlcpy(cwd, pack->prefix, sizeof(cwd));
+
+  while ((ret = sqlite3_step(assets)) == SQLITE_ROW) {
+    type = (mportPlistEntryType)sqlite3_column_int(assets, 0);
+    data = (char *)sqlite3_column_text(assets, 1);
+      
+    switch (type) {
+      case PLIST_CWD:      
+        (void)strlcpy(cwd, data == NULL ? pack->prefix : data, sizeof(cwd));
+        break;
+      case PLIST_EXEC:
+        if ((ret = mport_run_plist_exec(mport, data, cwd, last)) != MPORT_OK)
+          goto ERROR;
+        break;
+      case PLIST_FILE:
+        /* Our logic here is a bit backwards, because the first real file
+         * in the archive was read in the loop in mport_install_pkg.  we
+         * use the current entry and then update it. */
+        if (entry == NULL) {
+          ret = SET_ERROR(MPORT_ERR_INTERNAL, "Plist to arhive mismatch!");
+          goto ERROR; 
+        } 
+        
+        (void)strlcpy(last, data, sizeof(last));
+        (void)snprintf(file, FILENAME_MAX, "%s%s/%s", mport->root, cwd, data);
+
+        archive_entry_set_pathname(entry, file);
+
+        if ((ret = archive_read_extract(a, entry, ARCHIVE_EXTRACT_OWNER|ARCHIVE_EXTRACT_PERM|ARCHIVE_EXTRACT_TIME|ARCHIVE_EXTRACT_ACL|ARCHIVE_EXTRACT_FFLAGS)) != ARCHIVE_OK) {
+          ret = SET_ERROR(MPORT_ERR_ARCHIVE, archive_error_string(a));
+          goto ERROR;
+        }
+        
+        (mport->progress_step_cb)(++file_count, file_total, file);
+        
+        /* we only look for fatal, because EOF is only an error if we come
+        back around. */
+        if (archive_read_next_header(a, &entry) == ARCHIVE_FATAL) {
+          ret = SET_ERROR(MPORT_ERR_ARCHIVE, archive_error_string(a));
+          goto ERROR;
+        }
+        break;
+      default:
+        /* do nothing */
+        break;
+    }
+  }
+
+  sqlite3_finalize(assets);
+  
+  if (mport_db_do(db, "COMMIT TRANSACTION") != MPORT_OK) 
+    goto ERROR;
+    
+  (mport->progress_free_cb)();
+  
+  return MPORT_OK;
+  
+  ERROR:
+    (mport->progress_free_cb)();
+    rollback();
+    return ret;
+}           
+
+static int do_post_install(mportInstance *mport, mportPackageMeta *pack, const char *tmpdir)
+{
+  char to[FILENAME_MAX], from[FILENAME_MAX];
+  (void)snprintf(from, FILENAME_MAX, "%s/%s/%s-%s/%s", tmpdir, MPORT_STUB_INFRA_DIR, pack->name, pack->version, MPORT_DEINSTALL_FILE);
+  
+  if (mport_file_exists(from)) {
+    (void)snprintf(to, FILENAME_MAX, "%s%s/%s-%s/%s", mport->root, MPORT_INST_INFRA_DIR, pack->name, pack->version, MPORT_DEINSTALL_FILE);
+    
+    if (mport_mkdir(dirname(to)) != MPORT_OK)
+      RETURN_CURRENT_ERROR;
+  
+    if (mport_copy_file(from, to) != MPORT_OK)
+      RETURN_CURRENT_ERROR;
+  }
+
+  if (display_pkg_msg(mport, pack, tmpdir) != MPORT_OK)
+    RETURN_CURRENT_ERROR;
+  
+  return run_pkg_install(mport, tmpdir, pack, "POST-INSTALL");
+}
+
+
+      
+static int run_mtree(mportInstance *mport, const char *tmpdir, mportPackageMeta *pack)
+{
+  char file[FILENAME_MAX];
+  int ret;
+  
+  (void)snprintf(file, FILENAME_MAX, "%s/%s/%s-%s/%s", tmpdir, MPORT_STUB_INFRA_DIR, pack->name, pack->version, MPORT_MTREE_FILE);
+  
+  if (mport_file_exists(file)) {
+    if ((ret = mport_xsystem(mport, "%s -U -f %s -d -e -p %s >/dev/null", MPORT_MTREE_BIN, file, pack->prefix)) != 0) 
+      RETURN_ERRORX(MPORT_ERR_SYSCALL_FAILED, "%s returned non-zero: %i", MPORT_MTREE_BIN, ret);
+  }
+  
+  return MPORT_OK;
+}
+
+
+
+static int run_pkg_install(mportInstance *mport, const char *tmpdir, mportPackageMeta *pack, const char *mode)
+{
+  char file[FILENAME_MAX];
+  int ret;
+  
+  (void)snprintf(file, FILENAME_MAX, "%s/%s/%s-%s/%s", tmpdir, MPORT_STUB_INFRA_DIR, pack->name, pack->version, MPORT_INSTALL_FILE);    
+ 
+  if (mport_file_exists(file)) {
+   if ((ret = mport_xsystem(mport, "PKG_PREFIX=%s %s %s %s %s", pack->prefix, MPORT_SH_BIN, file, pack->name, mode)) != 0)
+     RETURN_ERRORX(MPORT_ERR_SYSCALL_FAILED, "%s %s returned non-zero: %i", MPORT_INSTALL_FILE, mode, ret);
+  }
+  
+ return MPORT_OK;
+}
+ 
+
+
+static int display_pkg_msg(mportInstance *mport, mportPackageMeta *pack, const char *tmpdir)
+{
+  char filename[FILENAME_MAX];
+  char *buf;
+  struct stat st;
+  FILE *file;
+  
+  (void)snprintf(filename, FILENAME_MAX, "%s/%s/%s-%s/%s", tmpdir, MPORT_STUB_INFRA_DIR, pack->name, pack->version, MPORT_MESSAGE_FILE);
+  
+  if (stat(filename, &st) == -1) 
+    /* if we couldn't stat the file, we assume there isn't a pkg-msg */
+    return MPORT_OK;
+    
+  if ((file = fopen(filename, "r")) == NULL) 
+    RETURN_ERRORX(MPORT_ERR_FILEIO, "Couldn't open %s: %s", filename, strerror(errno));
+  
+  if ((buf = (char *)malloc(st.st_size * sizeof(char))) == NULL)
+    return MPORT_ERR_NO_MEM;
+
+  
+  if (fread(buf, 1, st.st_size, file) != st.st_size) {
+    free(buf);
+    RETURN_ERRORX(MPORT_ERR_FILEIO, "Read error: %s", strerror(errno));
+  }
+  
+  (mport->msg_cb)(buf);
+  
+  free(buf);
+  
+  return MPORT_OK;
+}
+ 
+ 
+
+static int clean_up(mportInstance *mport, const char *tmpdir) 
+{
+  if (mport_detach_stub_db(mport->db) != MPORT_OK)
+    RETURN_CURRENT_ERROR;
+    
+#ifdef DEBUG
+  return MPORT_OK;
+#else
+  return mport_rmtree(tmpdir);
+#endif
+}
+
+
+static int rollback()
+{
+  fprintf(stderr, "Rollback called!\n");
+  return 0;
+}
+
Index: db.c
===================================================================
RCS file: /home/cvs/src/lib/libmport/db.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -L lib/libmport/db.c -L lib/libmport/db.c -u -r1.2 -r1.3
--- lib/libmport/db.c
+++ lib/libmport/db.c
@@ -39,26 +39,7 @@
 
 
 static int populate_meta_from_stmt(mportPackageMeta *, sqlite3 *, sqlite3_stmt *);
-
-
-/* mport_db_open_master(sqlite3 **)
- * 
- * Open the master database file, or create the file if it doesn't exist.
- * Note that this function will not create the schema for you, if you need
- * to create the schema use mport_inst_init() instead.
- */
-int mport_db_open_master(sqlite3 **db)
-{
-  if (sqlite3_open(MPORT_MASTER_DB_FILE, db) != 0) {
-    sqlite3_close(*db);
-    RETURN_ERROR(MPORT_ERR_SQLITE, sqlite3_errmsg(*db));
-  }
-  
-  return MPORT_OK;
-}
-
-
-
+static int populate_vec_from_stmt(mportPackageMeta ***, int, sqlite3 *, sqlite3_stmt *);
 
 /* mport_db_do(sqlite3 *db, const char *sql, ...)
  * 
@@ -107,8 +88,9 @@
   }
   
   if (sqlite3_prepare_v2(db, sql, -1, stmt, NULL) != SQLITE_OK) {
+    SET_ERRORX(MPORT_ERR_SQLITE, "sql error preparing '%s': %s", sql, sqlite3_errmsg(db));
     sqlite3_free(sql);
-    RETURN_ERROR(MPORT_ERR_SQLITE, sqlite3_errmsg(db));
+    RETURN_CURRENT_ERROR;
   }
   
   sqlite3_free(sql);
@@ -131,7 +113,8 @@
   asprintf(&file, "%s/%s", dir, MPORT_STUB_DB_FILE);
   
   if (mport_db_do(db, "ATTACH %Q AS stub", file) != MPORT_OK) { 
-    RETURN_ERROR(MPORT_ERR_SQLITE, sqlite3_errmsg(db));
+    free(file);
+    RETURN_CURRENT_ERROR;
   }
   
   free(file);
@@ -140,6 +123,22 @@
 }
 
 
+/* mport_detach_stub_db(sqlite *db) 
+ *
+ * The inverse of mport_attach_stub_db().
+ *
+ * Returns MPORT_OK on success.
+ */
+int mport_detach_stub_db(sqlite3 *db)
+{
+  if (mport_db_do(db, "DETACH stub") != MPORT_OK) 
+    RETURN_CURRENT_ERROR;
+  
+  return MPORT_OK;
+}
+
+
+
 /* mport_get_meta_from_stub(sqlite *db, mportPackageMeta ***pack)
  *
  * Allocates and populates a vector of mportPackageMeta structs from the stub database
@@ -149,91 +148,127 @@
 int mport_get_meta_from_stub(sqlite3 *db, mportPackageMeta ***ref)
 {
   sqlite3_stmt *stmt;
-  int len;
-  mportPackageMeta **vec;
+  int len, ret;
   
   if (mport_db_prepare(db, &stmt, "SELECT COUNT(*) FROM stub.packages") != MPORT_OK)
     RETURN_CURRENT_ERROR;
+
+  if (sqlite3_step(stmt) != SQLITE_ROW) {
+    sqlite3_finalize(stmt);
+    RETURN_ERROR(MPORT_ERR_SQLITE, sqlite3_errmsg(db));
+  }
   
   len = sqlite3_column_int(stmt, 0);
   sqlite3_finalize(stmt);
-  
-  vec = (mportPackageMeta**)malloc((1+len) * sizeof(mportPackageMeta *));
-  *ref = vec;
-  
-  if (vec == NULL) 
-    return MPORT_ERR_NO_MEM;
+
+  if (len == 0) {
+    /* a stub should have packages! */
+    RETURN_ERROR(MPORT_ERR_INTERNAL, "stub database contains no packages.");
+  }
     
   if (mport_db_prepare(db, &stmt, "SELECT pkg, version, origin, lang, prefix FROM stub.packages") != MPORT_OK)
     RETURN_CURRENT_ERROR;
   
-  while (*vec != NULL) { 
-    switch (sqlite3_step(stmt)) {
-      case SQLITE_ROW:
-        *vec = mport_new_packagemeta();
-        if (*vec == NULL)
-          return MPORT_ERR_NO_MEM;
-        if (populate_meta_from_stmt(*vec, db, stmt) != MPORT_OK)
-          RETURN_CURRENT_ERROR;
-        vec++;
-        break;
-      case SQLITE_DONE:
-        /* set the last cell in the array to null */
-        *vec = NULL;
-        break;
-      default:
-        sqlite3_finalize(stmt);
-        RETURN_ERROR(MPORT_ERR_SQLITE, sqlite3_errmsg(db));
-        break; /* not reached */
-    }
-  }
+  ret = populate_vec_from_stmt(ref, len, db, stmt);
   
   sqlite3_finalize(stmt);
   
-  return MPORT_OK;
+  return ret;
 }
 
 
-/* mport_get_meta_from_master(sqlite3 *db, mportPacakgeMeta **pack, const char *name)
+/* mport_get_meta_from_master(mportInstance *mport, mportPacakgeMeta ***pack, const char *where, ...)
  *
  * Allocate and populate the package meta for the given package from the
  * master database.
  * 
- * pack is set to NULL if package 'name' is not installed
+ * 'where' and the vargs are used to be build a where clause.  For example to search by
+ * name:
+ * 
+ * mport_get_meta_from_master(mport, &packvec, "pkg=%Q", name);
+ *
+ * or by origin
+ *
+ * mport_get_meta_from_master(mport, &packvec, "origin=%Q", origin);
+ *
+ * pack is set to NULL and MPORT_OK is returned if no packages where found.
  */
-int mport_get_meta_from_master(sqlite3 *db, mportPackageMeta **pack, const char *name)
+int mport_get_meta_from_master(mportInstance *mport, mportPackageMeta ***ref, const char *fmt, ...)
 {
+  va_list args;
   sqlite3_stmt *stmt;
-  int ret;
+  int ret, len;
+  char *where;
+  sqlite3 *db = mport->db;
+  
+  va_start(args, fmt);
+  
+  if ((where = sqlite3_vmprintf(fmt, args)) == NULL) {
+    RETURN_ERROR(MPORT_ERR_NO_MEM, "Could not build where clause");
+  }
   
-  if (mport_db_prepare(db, &stmt, "SELECT pkg, version, lang, prefix FROM packages WHERE pkg=%Q", name) != MPORT_OK)
+  if (mport_db_prepare(db, &stmt, "SELECT count(*) FROM packages WHERE %s", where) != MPORT_OK)
     RETURN_CURRENT_ERROR;
+
+  if (sqlite3_step(stmt) != SQLITE_ROW) {
+    sqlite3_finalize(stmt);
+    RETURN_ERROR(MPORT_ERR_SQLITE, sqlite3_errmsg(db));
+  }
+
+    
+  len = sqlite3_column_int(stmt, 0);
+  sqlite3_finalize(stmt);
+
+  if (len == 0) {
+    sqlite3_free(where);
+    *ref = NULL;
+    return MPORT_OK;
+  }
+
+  if (mport_db_prepare(db, &stmt, "SELECT pkg, version, origin, lang, prefix FROM packages WHERE %s", where) != MPORT_OK)
+    RETURN_CURRENT_ERROR;
+    
+    
+  ret = populate_vec_from_stmt(ref, len, db, stmt);
+
+  sqlite3_free(where);  
+  sqlite3_finalize(stmt);
   
-  switch (sqlite3_step(stmt)) {
-    case SQLITE_ROW:
-      *pack = mport_new_packagemeta();
-      if (*pack == NULL)
-        return MPORT_ERR_NO_MEM;
-      
-      ret = populate_meta_from_stmt(*pack, db, stmt);
-      sqlite3_finalize(stmt);
-      return ret;
-      break;
-    case SQLITE_DONE:
-      *pack = NULL;
-      sqlite3_finalize(stmt);
-      return MPORT_OK;
-      break;
-    default:
-      sqlite3_finalize(stmt);
-      RETURN_ERROR(MPORT_ERR_SQLITE, sqlite3_errmsg(db));
-      break;
+  return ret;
+}
+  
+
+static int populate_vec_from_stmt(mportPackageMeta ***ref, int len, sqlite3 *db, sqlite3_stmt *stmt)
+{ 
+  mportPackageMeta **vec;
+  int done = 0;
+  vec  = (mportPackageMeta**)malloc((1+len) * sizeof(mportPackageMeta *));
+  *ref = vec;
+
+  while (!done) { 
+    switch (sqlite3_step(stmt)) {
+      case SQLITE_ROW:
+        *vec = mport_packagemeta_new();
+        if (*vec == NULL)
+          RETURN_ERROR(MPORT_ERR_NO_MEM, "Couldn't allocate meta."); 
+        if (populate_meta_from_stmt(*vec, db, stmt) != MPORT_OK)
+          RETURN_CURRENT_ERROR;
+        vec++;
+        break;
+      case SQLITE_DONE:
+        /* set the last cell in the array to null */
+        *vec = NULL;
+        done++;
+        break;
+      default:
+        RETURN_ERROR(MPORT_ERR_SQLITE, sqlite3_errmsg(db));
+        break; /* not reached */
+    }
   }
   
-  /* no reached */
+  /* not reached */
   return MPORT_OK;
 }
-  
  
  
 static int populate_meta_from_stmt(mportPackageMeta *pack, sqlite3 *db, sqlite3_stmt *stmt) 
--- lib/libmport/install_pkg.c
+++ /dev/null
@@ -1,448 +0,0 @@
-/*-
- * Copyright (c) 2007 Chris Reinhardt
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * $MidnightBSD: src/lib/libmport/install_pkg.c,v 1.5 2007/12/05 17:02:15 ctriv Exp $
- */
-
-
-
-#include "mport.h"
-#include <sys/cdefs.h>
-#include <libgen.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-#include <archive.h>
-#include <archive_entry.h>
-
-__MBSDID("$MidnightBSD: src/lib/libmport/install_pkg.c,v 1.5 2007/12/05 17:02:15 ctriv Exp $");
-
-static int do_pre_install(sqlite3 *, mportPackageMeta *, const char *);
-static int do_actual_install(struct archive *, struct archive_entry *, sqlite3 *, mportPackageMeta *, const char *);
-static int do_post_install(sqlite3 *, mportPackageMeta *, const char *);
-static int check_preconditions(sqlite3 *, mportPackageMeta *);
-static int run_pkg_install(const char *, mportPackageMeta *, const char *);
-static int run_mtree(const char *, mportPackageMeta *);
-static int clean_up(const char *);
-static int rollback(void);
-
-int mport_install_pkg(const char *filename, const char *prefix) 
-{
-  /* 
-   * The general strategy here is to extract the meta-files into a tempdir, but
-   * extract the real files inplace.  There's huge IO overhead with having a stagging
-   * area. 
-   */
-  struct archive *a = archive_read_new();
-  struct archive_entry *entry;
-  char filepath[FILENAME_MAX];
-  const char *file;
-  sqlite3 *db;
-  mportPackageMeta **packs;
-  mportPackageMeta *pack;
-  
-  /* initialize our local mport instance */
-  if (mport_inst_init(&db) != MPORT_OK) 
-    RETURN_CURRENT_ERROR;
-
-  /* extract the meta-files into the a temp dir */  
-  char dirtmpl[] = "/tmp/mport.XXXXXXXX"; 
-  char *tmpdir = mkdtemp(dirtmpl);
-
-  if (tmpdir == NULL)
-    RETURN_ERROR(MPORT_ERR_FILEIO, strerror(errno));
-    
-  archive_read_support_compression_bzip2(a);
-  archive_read_support_format_tar(a);
-
-  if (archive_read_open_filename(a, filename, 10240) != ARCHIVE_OK)
-    RETURN_ERROR(MPORT_ERR_ARCHIVE, archive_error_string(a));
-    
-  while (archive_read_next_header(a, &entry) == ARCHIVE_OK) {
-    file = archive_entry_pathname(entry);
-    
-    if (*file == '+') {
-      snprintf(filepath, FILENAME_MAX, "%s/%s", tmpdir, file);
-      archive_entry_set_pathname(entry, filepath);
-      archive_read_extract(a, entry, ARCHIVE_EXTRACT_OWNER|ARCHIVE_EXTRACT_PERM);
-    } else {
-      break;
-    }
-  }
-  
-  /* Attach the stub db */
-  if (mport_attach_stub_db(db, tmpdir) != MPORT_OK) 
-    RETURN_CURRENT_ERROR;
-
-  /* get the meta objects from the stub database */  
-  if (mport_get_meta_from_stub(db, &packs) != MPORT_OK)
-    RETURN_CURRENT_ERROR;
-
-  for (;*packs; packs++) {
-    pack  = *packs;    
-
-    if (prefix != NULL) {
-      free(pack->prefix);
-      pack->prefix = strdup(prefix);
-    }
-    
-    /* check if this is installed already, depends, and conflicts */
-    if (check_preconditions(db, pack) != MPORT_OK)
-      RETURN_CURRENT_ERROR;
-
-    /* Run mtree.  Run pkg-install. Etc... */
-    if (do_pre_install(db, pack, tmpdir) != MPORT_OK)
-      RETURN_CURRENT_ERROR;
-
-    if (do_actual_install(a, entry, db, pack, tmpdir) != MPORT_OK)
-      RETURN_CURRENT_ERROR;
-    
-    archive_read_finish(a);
-    
-    if (do_post_install(db, pack, tmpdir) != MPORT_OK)
-      RETURN_CURRENT_ERROR;
-  } 
-  
-  // XXX mport_free_packagemeta_vec()
-  
-  if (clean_up(tmpdir) != MPORT_OK)
-    RETURN_CURRENT_ERROR;
-  
-  return MPORT_OK;
-}
-
-/* This does everything that has to happen before we start installing files.
- * We run mtree, pkg-install PRE-INSTALL, etc... 
- */
-static int do_pre_install(sqlite3 *db, mportPackageMeta *pack, const char *tmpdir)
-{
-  int ret = MPORT_OK;
-  
-  /* run mtree */
-  if ((ret = run_mtree(tmpdir, pack)) != MPORT_OK)
-    return ret;
-  
-  /* run pkg-install PRE-INSTALL */
-  if ((ret = run_pkg_install(tmpdir, pack, "PRE-INSTALL")) != MPORT_OK)
-    return ret;
-
-  return ret;    
-}
-
-
-static int do_actual_install(
-      struct archive *a, 
-      struct archive_entry *entry,
-      sqlite3 *db, 
-      mportPackageMeta *pack, 
-      const char *tmpdir
-    )
-{
-  int ret;
-  mportPlistEntryType type;
-  char *data, *cwd;
-  char file[FILENAME_MAX];
-  sqlite3_stmt *assets;
-
-  
-  if (mport_db_do(db, "BEGIN TRANSACTION") != MPORT_OK) 
-    goto ERROR;
-
-  /* Insert the package meta row into the packages table */  
-  if ((ret = mport_db_do(db, "INSERT INTO packages (pkg, version, origin, prefix, lang, options) VALUES (%Q,%Q,%Q,%Q,%Q,%Q)", pack->name, pack->version, pack->origin, pack->prefix, pack->lang, pack->options)) != MPORT_OK)
-    goto ERROR;
-  /* Insert the assets into the master table */
-  if ((ret = mport_db_do(db, "INSERT INTO assets (pkg, type, data, checksum) SELECT pkg,type,data,checksum FROM stub.assets WHERE pkg=%Q", pack->name)) != MPORT_OK)
-    goto ERROR;  
-  /* Insert the depends into the master table */
-  if ((ret = mport_db_do(db, "INSERT INTO depends (pkg, depend_pkgname, depend_pkgversion, depend_port) SELECT pkg,depend_pkgname,depend_pkgversion,depend_port FROM stub.depends WHERE pkg=%Q", pack->name)) != MPORT_OK) 
-    goto ERROR;
-  
-  if ((ret = mport_db_prepare(db, &assets, "SELECT type,data FROM stub.assets WHERE pkg=%Q", pack->name)) != MPORT_OK) {
-    mport_set_err(MPORT_ERR_SQLITE, sqlite3_errmsg(db));
-    goto ERROR;
-  }
-
-  cwd = pack->prefix;
-
-  while ((ret = sqlite3_step(assets)) == SQLITE_ROW) {
-    type = (mportPlistEntryType)sqlite3_column_int(assets, 0);
-    data = (char *)sqlite3_column_text(assets, 1);
-      
-    switch (type) {
-      case PLIST_CWD:      
-        if (data == NULL) {
-          cwd = pack->prefix;
-        } else {
-          cwd = data;
-        }
-        break;
-      case PLIST_EXEC:
-        if ((ret = mport_run_plist_exec(data, cwd, file)) != MPORT_OK)
-          goto ERROR;
-        break;
-      case PLIST_FILE:
-        /* Our logic here is a bit backwards, because the first real file
-         * in the archive was read in the loop in mport_install_pkg.  we
-         * use the current entry and then update it. */
-        if (entry == NULL) {
-          ret = SET_ERROR(MPORT_ERR_INTERNAL, "Plist to arhive mismatch!");
-          goto ERROR; 
-        } 
-        (void)snprintf(file, FILENAME_MAX, "%s/%s", cwd, data);
-        archive_entry_set_pathname(entry, file);
-        if ((ret = archive_read_extract(a, entry, ARCHIVE_EXTRACT_OWNER|ARCHIVE_EXTRACT_PERM)) != ARCHIVE_OK) {
-          ret = SET_ERROR(MPORT_ERR_ARCHIVE, archive_error_string(a));
-          goto ERROR;
-        }
-        /* we only look for fatal, because EOF is only an error if we come
-        back around. */
-        if (archive_read_next_header(a, &entry) == ARCHIVE_FATAL) {
-          ret = SET_ERROR(MPORT_ERR_ARCHIVE, archive_error_string(a));
-          goto ERROR;
-        }
-        break;
-      default:
-        /* do nothing */
-        break;
-    }
-  }
-
-  sqlite3_finalize(assets);
-  
-  if (mport_db_do(db, "COMMIT TRANSACTION") != MPORT_OK) 
-    goto ERROR;
-  
-  return MPORT_OK;
-  
-  ERROR:
-    rollback();
-    return ret;
-}           
-
-static int do_post_install(sqlite3 *db, mportPackageMeta *pack, const char *tmpdir)
-{
-  char to[FILENAME_MAX], from[FILENAME_MAX];
-  (void)snprintf(from, FILENAME_MAX, "%s/%s/%s-%s/%s", tmpdir, MPORT_STUB_INFRA_DIR, pack->name, pack->version, MPORT_DEINSTALL_FILE);
-  
-  if (mport_file_exists(from)) {
-    (void)snprintf(to, FILENAME_MAX, "%s/%s-%s/%s", MPORT_INST_INFRA_DIR, pack->name, pack->version, MPORT_DEINSTALL_FILE);
-    
-    if (mport_mkdir(dirname(to)) != MPORT_OK)
-      RETURN_CURRENT_ERROR;
-  
-    if (mport_copy_file(from, to) != MPORT_OK)
-      RETURN_CURRENT_ERROR;
-  }
-  
-  return run_pkg_install(tmpdir, pack, "POST-INSTALL");
-}
-
-
-/* check to see if the package is already installed, if it has any
- * conflicts, and that all its depends are installed.
- */
-static int check_preconditions(sqlite3 *db, mportPackageMeta *pack) 
-{
-  sqlite3_stmt *stmt, *lookup;
-  int ret, sret, lret;
-  const char *inst_version;
-
-  ret = MPORT_OK;
-
-  /* check if the package is already installed */
-  if (sqlite3_prepare_v2(db, "SELECT version FROM packages WHERE pkg=?", -1, &lookup, NULL) != SQLITE_OK) 
-    RETURN_ERROR(MPORT_ERR_SQLITE, sqlite3_errmsg(db));
-
-  if (sqlite3_bind_text(lookup, 1, pack->name, -1, SQLITE_STATIC) != SQLITE_OK) {
-    ret = SET_ERROR(MPORT_ERR_SQLITE, sqlite3_errmsg(db));
-    goto DONE;
-  }
-    
-  sret = sqlite3_step(lookup);
-  
-  switch (sret) {
-    case SQLITE_DONE:
-      /* No row found.  Do nothing */
-      break;
-    case SQLITE_ROW:
-      /* Row was found */
-      inst_version = sqlite3_column_text(lookup, 0);
-      ret = mport_set_errx(MPORT_ERR_ALREADY_INSTALLED, "%s (version %s) is already installed.", pack->name, inst_version);
-      goto DONE;
-      break;
-    default:
-      /* Some sort of sqlite error */
-      ret = SET_ERROR(MPORT_ERR_SQLITE, sqlite3_errmsg(db));
-      goto DONE;
-  }
-  sqlite3_finalize(lookup);
-
-  
-  /* Check for conflicts */
-  if (sqlite3_prepare_v2(db, "SELECT conflict_pkg, conflict_version FROM stub.conflicts", -1, &stmt, NULL) != SQLITE_OK) {
-    ret = SET_ERROR(MPORT_ERR_SQLITE, sqlite3_errmsg(db));
-    goto DONE;
-  }
-  
-  while (1) {
-    sret = sqlite3_step(stmt);
-    
-    if (sret == SQLITE_ROW) {
-      const char *conflict_pkg     = sqlite3_column_text(stmt, 0);
-      const char *conflict_version = sqlite3_column_text(stmt, 1);
-       
-      if (sqlite3_prepare_v2(db, "SELECT version FROM packages WHERE pkg GLOB ? AND version GLOB ?", -1, &lookup, NULL) != SQLITE_OK
-          ||
-          sqlite3_bind_text(lookup, 1, conflict_pkg, -1, SQLITE_STATIC) != SQLITE_OK
-          ||
-          sqlite3_bind_text(lookup, 2, conflict_version, -1, SQLITE_STATIC) != SQLITE_OK
-      ) {
-            ret = SET_ERROR(MPORT_ERR_SQLITE, sqlite3_errmsg(db));
-            goto DONE;
-      }
-      
-      lret = sqlite3_step(lookup);
-
-      if (lret == SQLITE_ROW) {
-        inst_version = sqlite3_column_text(lookup, 0);
-        ret = mport_set_errx(MPORT_ERR_CONFLICTS, "Installed package %s-%s conflicts with %s", conflict_pkg, inst_version, pack->name);
-        goto DONE;
-      } else if (lret == SQLITE_DONE) {
-        /* No hits.  Do nothing */
-      } else {
-        ret = SET_ERROR(MPORT_ERR_SQLITE, sqlite3_errmsg(db));
-        goto DONE;
-      } 
-    } else if (sret == SQLITE_DONE) {
-      /* No more conflicts to check */
-      break;
-    } else {
-      ret = SET_ERROR(MPORT_ERR_SQLITE, sqlite3_errmsg(db));
-      goto DONE;
-    }
-  }
-  
-  /* check for depends */
-  if (sqlite3_prepare_v2(db, "SELECT depend_pkgname, depend_pkgversion FROM stub.depends", -1, &stmt, NULL) != SQLITE_OK) {
-    ret = SET_ERROR(MPORT_ERR_SQLITE, sqlite3_errmsg(db));
-    goto DONE;
-  }
-  
-  while (1) {
-    sret = sqlite3_step(stmt);
-  
-    if (sret == SQLITE_ROW) {
-      const char *depend_pkg     = sqlite3_column_text(stmt, 0);
-      const char *depend_version = sqlite3_column_text(stmt, 1);
-      
-      if (sqlite3_prepare_v2(db, "SELECT version FROM packages WHERE pkg=?", -1, &lookup, NULL) != SQLITE_OK
-          ||
-          sqlite3_bind_text(lookup, 1, depend_pkg, -1, SQLITE_STATIC) != SQLITE_OK
-      ) {
-            ret = SET_ERROR(MPORT_ERR_SQLITE, sqlite3_errmsg(db));
-            goto DONE;
-      }
-      
-      lret = sqlite3_step(lookup);
-      
-      if (lret == SQLITE_ROW) {
-        inst_version = sqlite3_column_text(lookup, 0);
-        
-        if (mport_version_cmp(inst_version, depend_version) < 0) {
-          ret = mport_set_errx(MPORT_ERR_MISSING_DEPEND, "%s depends on %s version %s.  Version %s is installed.", pack->name, depend_pkg, depend_version, inst_version);
-          goto DONE;
-        }
-      } else if (lret == SQLITE_DONE) {
-        /* this depend isn't installed. */
-        ret = mport_set_errx(MPORT_ERR_MISSING_DEPEND, "%s depends on %s, which is not installed.", pack->name, depend_pkg);
-        goto DONE;
-      } else {
-        ret = SET_ERROR(MPORT_ERR_SQLITE, sqlite3_errmsg(db));
-        goto DONE;
-      }
-    } else if (sret == SQLITE_DONE) {
-      /* No more depends to check. */
-      break;
-    } else {
-      ret = SET_ERROR(MPORT_ERR_SQLITE, sqlite3_errmsg(db));
-      goto DONE;
-    }
-  }        
-  
-  DONE:
-    sqlite3_finalize(stmt);
-    sqlite3_finalize(lookup);
-    return ret;    
-}  
-      
-static int run_mtree(const char *tmpdir, mportPackageMeta *pack)
-{
-  char file[FILENAME_MAX];
-  int ret;
-  
-  (void)snprintf(file, FILENAME_MAX, "%s/%s/%s-%s/%s", tmpdir, MPORT_STUB_INFRA_DIR, pack->name, pack->version, MPORT_MTREE_FILE);
-  
-  if (mport_file_exists(file)) {
-    if ((ret = mport_xsystem("%s -U -f %s -d -e -p %s >/dev/null", MPORT_MTREE_BIN, file, pack->prefix)) != 0) 
-      RETURN_ERRORX(MPORT_ERR_SYSCALL_FAILED, "%s returned non-zero: %i", MPORT_MTREE_BIN, ret);
-  }
-  
-  return MPORT_OK;
-}
-
-
-static int run_pkg_install(const char *tmpdir, mportPackageMeta *pack, const char *mode)
-{
-  char file[FILENAME_MAX];
-  int ret;
-  
-  (void)snprintf(file, FILENAME_MAX, "%s/%s/%s-%s/%s", tmpdir, MPORT_STUB_INFRA_DIR, pack->name, pack->version, MPORT_INSTALL_FILE);    
-  if (mport_file_exists(file)) {
-    if ((ret = mport_xsystem("PKG_PREFIX=%s %s %s %s", pack->prefix, MPORT_SH_BIN, file, mode)) != 0)
-      RETURN_ERRORX(MPORT_ERR_SYSCALL_FAILED, "%s %s returned non-zero: %i" MPORT_INSTALL_FILE, mode, ret);
-  }
-  
-  return MPORT_OK;
-}
-
-
-static int clean_up(const char *tmpdir) 
-{
-#ifdef DEBUG
-  return MPORT_OK;
-#else
-  return mport_rmtree(tmpdir);
-#endif
-}
-
-
-static int rollback()
-{
-  fprintf(stderr, "Rollback called!\n");
-  return 0;
-}
-
--- /dev/null
+++ lib/libmport/check_preconditions.c
@@ -0,0 +1,207 @@
+/*-
+ * Copyright (c) 2007 Chris Reinhardt
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $MidnightBSD: src/lib/libmport/check_preconditions.c,v 1.1 2008/01/05 22:18:20 ctriv Exp $
+ */
+
+#include "mport.h"
+
+__MBSDID("$MidnightBSD: src/lib/libmport/check_preconditions.c,v 1.1 2008/01/05 22:18:20 ctriv Exp $");
+
+
+static int check_if_installed(sqlite3 *, mportPackageMeta *);
+static int check_if_older_installed(sqlite3 *, mportPackageMeta *);
+static int check_conflicts(sqlite3 *, mportPackageMeta *);
+static int check_depends(sqlite3 *, mportPackageMeta *);
+
+
+
+int mport_check_update_preconditions(mportInstance *mport, mportPackageMeta *pack)
+{
+  if (check_if_older_installed(mport->db, pack) != MPORT_OK)
+    RETURN_CURRENT_ERROR;
+  if (check_conflicts(mport->db, pack) != MPORT_OK)
+    RETURN_CURRENT_ERROR;
+  if (check_depends(mport->db, pack) != MPORT_OK)
+    RETURN_CURRENT_ERROR;
+    
+  return MPORT_OK;
+}
+
+
+/* check to see if the package is already installed, if it has any
+ * conflicts, and that all its depends are installed.
+ */
+int mport_check_install_preconditions(mportInstance *mport, mportPackageMeta *pack) 
+{
+  if (check_if_installed(mport->db, pack) != MPORT_OK)
+    RETURN_CURRENT_ERROR;
+  if (check_conflicts(mport->db, pack) != MPORT_OK)
+    RETURN_CURRENT_ERROR;
+  if (check_depends(mport->db, pack) != MPORT_OK)
+    RETURN_CURRENT_ERROR;
+    
+  return MPORT_OK;
+}
+
+
+static int check_if_older_installed(sqlite3 *db, mportPackageMeta *pack)
+{
+  /* write me */
+}
+
+
+static int check_if_installed(sqlite3 *db, mportPackageMeta *pack)
+{
+  sqlite3_stmt *stmt;
+  const char *inst_version;
+  
+  /* check if the package is already installed */
+  if (mport_db_prepare(db, &stmt, "SELECT version FROM packages WHERE pkg=%Q", pack->name) != MPORT_OK) 
+    RETURN_CURRENT_ERROR;
+
+  switch (sqlite3_step(stmt)) {
+    case SQLITE_DONE:
+      /* No row found.  Do nothing */
+      break;
+    case SQLITE_ROW:
+      /* Row was found */
+      inst_version = sqlite3_column_text(stmt, 0);
+      
+      SET_ERRORX(MPORT_ERR_ALREADY_INSTALLED, "%s (version %s) is already installed.", pack->name, inst_version);
+      sqlite3_finalize(stmt);
+      RETURN_CURRENT_ERROR;
+
+      break;
+    default:
+      /* Some sort of sqlite error */
+      SET_ERROR(MPORT_ERR_SQLITE, sqlite3_errmsg(db));
+      sqlite3_finalize(stmt);
+      RETURN_CURRENT_ERROR;
+  }
+
+  sqlite3_finalize(stmt);
+  return MPORT_OK;
+}  
+
+static int check_conflicts(sqlite3 *db, mportPackageMeta *pack)
+{
+  sqlite3_stmt *stmt;
+  int ret;
+  const char *inst_name, *inst_version;
+  
+  if (mport_db_prepare(db, &stmt, "SELECT packages.pkg, packages.version FROM stub.conflicts LEFT JOIN packages ON packages.pkg GLOB stub.conflicts.conflict_pkg AND packages.version GLOB stub.conflicts.conflict_version WHERE packages.pkg IS NOT NULL") != MPORT_OK) 
+    RETURN_CURRENT_ERROR;
+  
+  while (1) {
+    ret = sqlite3_step(stmt);
+    
+    if (ret == SQLITE_ROW) {
+        inst_name    = sqlite3_column_text(stmt, 0);
+        inst_version = sqlite3_column_text(stmt, 1);
+        
+        SET_ERRORX(MPORT_ERR_CONFLICTS, "Installed package %s-%s conflicts with %s", inst_name, inst_version, pack->name);
+        sqlite3_finalize(stmt);
+        RETURN_CURRENT_ERROR;
+    } else if (ret == SQLITE_DONE) {
+      /* No conflicts */
+      break;
+    } else {
+      SET_ERROR(MPORT_ERR_SQLITE, sqlite3_errmsg(db));
+      sqlite3_finalize(stmt);
+      RETURN_CURRENT_ERROR;
+    }
+  }
+  
+  sqlite3_finalize(stmt);
+  return MPORT_OK;
+}
+
+
+static int check_depends(sqlite3 *db, mportPackageMeta *pack)
+{
+  sqlite3_stmt *stmt, *lookup;
+  const char *depend_pkg, *depend_version, *inst_version;
+  int ret;
+  
+  /* check for depends */
+  if (mport_db_prepare(db, &stmt, "SELECT depend_pkgname, depend_pkgversion FROM stub.depends") != MPORT_OK) 
+    RETURN_CURRENT_ERROR;
+ 
+  if (mport_db_prepare(db, &lookup, "SELECT version FROM packages WHERE pkg=?") != MPORT_OK) {
+    sqlite3_finalize(stmt);
+    RETURN_CURRENT_ERROR;
+  }  
+  
+  while (1) {
+    ret = sqlite3_step(stmt);
+  
+    if (ret == SQLITE_ROW) {
+      depend_pkg     = sqlite3_column_text(stmt, 0);
+      depend_version = sqlite3_column_text(stmt, 1);
+      
+      if (sqlite3_bind_text(lookup, 1, depend_pkg, -1, SQLITE_STATIC) != SQLITE_OK) {
+        SET_ERROR(MPORT_ERR_SQLITE, sqlite3_errmsg(db));
+        sqlite3_finalize(lookup); sqlite3_finalize(stmt);
+        RETURN_CURRENT_ERROR;
+      }
+      
+      switch (sqlite3_step(lookup)) {
+        case SQLITE_ROW:
+          inst_version = sqlite3_column_text(lookup, 0);
+          
+          if (mport_version_cmp(inst_version, depend_version) < 0) {
+            SET_ERRORX(MPORT_ERR_MISSING_DEPEND, "%s depends on %s version %s.  Version %s is installed.", pack->name, depend_pkg, depend_version, inst_version);
+            sqlite3_finalize(lookup); sqlite3_finalize(stmt);
+            RETURN_CURRENT_ERROR;
+          }
+          break;
+        case SQLITE_DONE:
+          /* this depend isn't installed. */
+          SET_ERRORX(MPORT_ERR_MISSING_DEPEND, "%s depends on %s, which is not installed.", pack->name, depend_pkg);
+          sqlite3_finalize(lookup); sqlite3_finalize(stmt);
+          RETURN_CURRENT_ERROR;
+          break;
+        default:
+          SET_ERROR(MPORT_ERR_SQLITE, sqlite3_errmsg(db));
+          sqlite3_finalize(lookup); sqlite3_finalize(stmt);
+          RETURN_CURRENT_ERROR;
+      }
+      
+      sqlite3_reset(lookup);
+      sqlite3_clear_bindings(lookup);
+    } else if (ret == SQLITE_DONE) {
+      /* No more depends to check. */
+      break;
+    } else {
+      SET_ERROR(MPORT_ERR_SQLITE, sqlite3_errmsg(db));
+      sqlite3_finalize(lookup); sqlite3_finalize(stmt);
+      RETURN_CURRENT_ERROR;
+    }
+  }        
+  
+  return MPORT_OK;    
+}  
+
Index: Makefile
===================================================================
RCS file: /home/cvs/src/lib/libmport/Makefile,v
retrieving revision 1.5
retrieving revision 1.6
diff -L lib/libmport/Makefile -L lib/libmport/Makefile -u -r1.5 -r1.6
--- lib/libmport/Makefile
+++ lib/libmport/Makefile
@@ -1,8 +1,9 @@
 # $MidnightBSD$
 
 LIB=		mport
-SRCS=		archive.c plist.c create_pkg.c db.c util.c error.c \
-		install_pkg.c inst_init.c version_cmp.c
+SRCS=		bundle.c plist.c create_primative.c db.c util.c error.c \
+		install_primative.c instance.c version_cmp.c \
+		check_preconditions.c delete_primative.c default_cbs.c
 
 INCS=		mport.h
 
--- lib/libmport/inst_init.c
+++ /dev/null
@@ -1,63 +0,0 @@
-/*-
- * Copyright (c) 2007 Chris Reinhardt
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * $MidnightBSD: src/lib/libmport/inst_init.c,v 1.3 2007/12/05 17:02:15 ctriv Exp $
- */
-
-
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <errno.h>
-#include <string.h>
-#include <sqlite3.h>
-#include "mport.h"
-
-__MBSDID("$MidnightBSD: src/lib/libmport/inst_init.c,v 1.3 2007/12/05 17:02:15 ctriv Exp $");
-
-
-static int create_master_db(sqlite3 **);
-
-/* set up the master database, and related instance infrastructure. */
-int mport_inst_init(sqlite3 **db)
-{
-  if (mport_mkdir(MPORT_INST_DIR) != MPORT_OK)
-    RETURN_CURRENT_ERROR;
-  
-  if (mport_mkdir(MPORT_INST_INFRA_DIR) != MPORT_OK)
-    RETURN_CURRENT_ERROR;
-  
-  return create_master_db(db);
-}
-  
-  
-static int create_master_db(sqlite3 **db) 
-{
-  if (mport_db_open_master(db) != MPORT_OK)
-    RETURN_CURRENT_ERROR;  
-
-  /* create tables */
-  return mport_generate_master_schema(*db);
-}
--- /dev/null
+++ lib/libmport/instance.c
@@ -0,0 +1,128 @@
+/*-
+ * Copyright (c) 2007 Chris Reinhardt
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $MidnightBSD: src/lib/libmport/instance.c,v 1.1 2008/01/05 22:18:20 ctriv Exp $
+ */
+
+
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include "mport.h"
+
+__MBSDID("$MidnightBSD: src/lib/libmport/instance.c,v 1.1 2008/01/05 22:18:20 ctriv Exp $");
+
+
+/* allocate mem for a mportInstance */
+mportInstance * mport_instance_new() 
+{
+ return (mportInstance *)malloc(sizeof(mportInstance)); 
+}
+ 
+
+/* set up the master database, and related instance infrastructure. */
+int mport_instance_init(mportInstance *mport, const char *root)
+{
+  char dir[FILENAME_MAX];
+  
+  if (root != NULL) {
+    mport->root = strdup(root);
+  } else {
+    mport->root = strdup("");
+  }
+
+  (void)snprintf(dir, FILENAME_MAX, "%s/%s", mport->root, MPORT_INST_DIR);
+
+  if (mport_mkdir(dir) != MPORT_OK)
+    RETURN_CURRENT_ERROR;
+  
+  (void)snprintf(dir, FILENAME_MAX, "%s/%s", mport->root, MPORT_INST_INFRA_DIR);
+  
+  if (mport_mkdir(dir) != MPORT_OK)
+    RETURN_CURRENT_ERROR;
+
+  /* dir is a file here, just trying to save memory */
+  (void)snprintf(dir, FILENAME_MAX, "%s/%s", mport->root, MPORT_MASTER_DB_FILE);
+  if (sqlite3_open(dir, &(mport->db)) != 0) {
+    sqlite3_close(mport->db);
+    RETURN_ERROR(MPORT_ERR_SQLITE, sqlite3_errmsg(mport->db));
+  }
+  
+  
+  /* set the default UI callbacks */
+  mport->msg_cb           = &mport_default_msg_cb;
+  mport->progress_init_cb = &mport_default_progress_init_cb;
+  mport->progress_step_cb = &mport_default_progress_step_cb;
+  mport->progress_free_cb = &mport_default_progress_free_cb;
+  mport->confirm_cb       = &mport_default_confirm_cb;
+  
+
+  /* create tables */
+  return mport_generate_master_schema(mport->db);
+}
+
+
+/* Setters for the variable UI callbacks. */
+void mport_set_msg_cb(mportInstance *mport, mport_msg_cb cb) 
+{
+  mport->msg_cb = cb;
+}
+
+void mport_set_progress_init_cb(mportInstance *mport, mport_progress_init_cb cb)
+{
+  mport->progress_init_cb = cb;
+}
+
+void mport_set_progress_step_cb(mportInstance *mport, mport_progress_step_cb cb)
+{
+  mport->progress_step_cb = cb;
+}
+
+void mport_set_progress_free_cb(mportInstance *mport, mport_progress_free_cb cb)
+{
+  mport->progress_free_cb = cb;
+}
+
+
+void mport_set_confirm_cb(mportInstance *mport, mport_confirm_cb cb) 
+{
+  mport->confirm_cb = cb;
+}
+
+
+int mport_instance_free(mportInstance *mport) 
+{
+  if (sqlite3_close(mport->db) != SQLITE_OK) {
+    RETURN_ERROR(MPORT_ERR_SQLITE, sqlite3_errmsg(mport->db));
+  }
+  
+  free(mport->root);  
+  free(mport);
+  return MPORT_OK;
+}
+
--- /dev/null
+++ lib/libmport/delete_primative.c
@@ -0,0 +1,237 @@
+/*-
+ * Copyright (c) 2007 Chris Reinhardt
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $MidnightBSD: src/lib/libmport/delete_primative.c,v 1.1 2008/01/05 22:18:20 ctriv Exp $
+ */
+
+
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <string.h>
+#include <sqlite3.h>
+#include <md5.h>
+#include <stdlib.h>
+#include "mport.h"
+
+__MBSDID("$MidnightBSD: src/lib/libmport/delete_primative.c,v 1.1 2008/01/05 22:18:20 ctriv Exp $");
+
+
+
+static int run_pkg_deinstall(mportInstance *, mportPackageMeta *, const char *);
+static int delete_pkg_infra(mportInstance *, mportPackageMeta *);
+static int check_for_upwards_depends(mportInstance *, mportPackageMeta *);
+
+
+int mport_delete_primative(mportInstance *mport, mportPackageMeta *pack, int force) 
+{
+  sqlite3_stmt *stmt;
+  int ret;
+  mportPlistEntryType type;
+  char *data, *checksum, *cwd;
+  struct stat st;
+  char md5[33], file[FILENAME_MAX];
+  
+  if (force == 0) {
+    if (check_for_upwards_depends(mport, pack) != MPORT_OK)
+      RETURN_CURRENT_ERROR;
+  }
+
+  if (run_pkg_deinstall(mport, pack, "DEINSTALL") != MPORT_OK)
+    RETURN_CURRENT_ERROR;
+  
+  if (mport_db_prepare(mport->db, &stmt, "SELECT type,data,checksum FROM assets WHERE pkg=%Q", pack->name) != MPORT_OK)
+    RETURN_CURRENT_ERROR;  
+  
+  cwd = pack->prefix;
+
+  while (1) {
+    ret = sqlite3_step(stmt);
+    
+    if (ret == SQLITE_DONE)
+      break;
+      
+    if (ret != SQLITE_ROW) {
+      /* some error occured */
+      SET_ERROR(MPORT_ERR_SQLITE, sqlite3_errmsg(mport->db));
+      sqlite3_finalize(stmt);
+      RETURN_CURRENT_ERROR;
+    }
+    
+    type     = (mportPlistEntryType)sqlite3_column_int(stmt, 0);
+    data     = (char *)sqlite3_column_text(stmt, 1);
+    checksum = (char *)sqlite3_column_text(stmt, 2);
+    
+    switch (type) {
+      case PLIST_CWD:
+        cwd = data == NULL ? pack->prefix : data;
+        break;
+      case PLIST_FILE:
+        (void)snprintf(file, FILENAME_MAX, "%s%s/%s", mport->root, cwd, data);
+        
+        if (lstat(file, &st) != 0) {
+          char *msg;
+          (void)asprintf(&msg, "Can't stat %s: %s", file, strerror(errno));
+          (mport->msg_cb)(msg);
+          free(msg);
+          break; /* next asset */
+        } 
+        
+        
+        if (S_ISREG(st.st_mode)) {
+          if (MD5File(file, md5) == NULL) {
+            sqlite3_finalize(stmt);
+            RETURN_ERRORX(MPORT_ERR_FILE_NOT_FOUND, "File not found: %s", file);
+          }
+          
+          if (strcmp(md5, checksum) != 0) {
+            char *msg;
+            (void)asprintf(&msg, "Checksum mismatch: %s", file);
+            (mport->msg_cb)(msg);
+            free(msg);
+          }
+        }
+        
+        if (unlink(file) != 0) {
+          sqlite3_finalize(stmt);
+          RETURN_ERROR(MPORT_ERR_SYSCALL_FAILED, strerror(errno));
+        }
+
+        break;
+      case PLIST_UNEXEC:
+        if (mport_run_plist_exec(mport, data, cwd, file) != MPORT_OK) {
+          sqlite3_finalize(stmt);
+          RETURN_CURRENT_ERROR;
+        }
+        break;
+      case PLIST_DIRRM:
+      case PLIST_DIRRMTRY:
+        (void)snprintf(file, FILENAME_MAX, "%s%s/%s", mport->root, cwd, data);
+        
+        if (mport_rmdir(file, type == PLIST_DIRRMTRY ? 1 : 0) != MPORT_OK) {
+          sqlite3_finalize(stmt);
+          RETURN_CURRENT_ERROR;
+        }
+        
+        break;
+      default:
+        /* do nothing */
+        break;
+    }
+  }
+    
+  sqlite3_finalize(stmt);
+  
+  if (run_pkg_deinstall(mport, pack, "POST-DEINSTALL") != MPORT_OK)
+    RETURN_CURRENT_ERROR;
+    
+  if (mport_db_do(mport->db, "DELETE FROM assets WHERE pkg=%Q", pack->name) != MPORT_OK)
+    RETURN_CURRENT_ERROR;
+  
+  if (mport_db_do(mport->db, "DELETE FROM depends WHERE pkg=%Q", pack->name) != MPORT_OK)
+    RETURN_CURRENT_ERROR;
+  
+  if (mport_db_do(mport->db, "DELETE FROM packages WHERE pkg=%Q", pack->name) != MPORT_OK)
+    RETURN_CURRENT_ERROR;
+    
+  if (delete_pkg_infra(mport, pack) != MPORT_OK)
+    RETURN_CURRENT_ERROR;
+  
+  return MPORT_OK;
+    
+} 
+  
+
+static int run_pkg_deinstall(mportInstance *mport, mportPackageMeta *pack, const char *mode)
+{
+  char file[FILENAME_MAX];
+  int ret;
+  
+  (void)snprintf(file, FILENAME_MAX, "%s/%s-%s/%s", MPORT_INST_INFRA_DIR, pack->name, pack->version, MPORT_DEINSTALL_FILE);    
+
+  if (mport_file_exists(file)) {
+    if ((ret = mport_xsystem(mport, "PKG_PREFIX=%s %s %s %s %s", pack->prefix, MPORT_SH_BIN, file, pack->name, mode)) != 0)
+      RETURN_ERRORX(MPORT_ERR_SYSCALL_FAILED, "%s %s returned non-zero: %i", MPORT_INSTALL_FILE, mode, ret);
+  }
+  
+  return MPORT_OK;
+}
+
+
+/* delete this package's infrastructure dir. */
+static int delete_pkg_infra(mportInstance *mport, mportPackageMeta *pack)
+{
+  char dir[FILENAME_MAX];
+  int ret;
+
+  (void)snprintf(dir, FILENAME_MAX, "%s%s/%s-%s", mport->root, MPORT_INST_INFRA_DIR, pack->name, pack->version);
+  
+  if (mport_file_exists(dir)) {
+    if ((ret = mport_rmtree(dir)) != MPORT_OK) 
+      RETURN_ERRORX(MPORT_ERR_SYSCALL_FAILED, "mport_rmtree(%s) failed.",  dir);
+  }
+  
+  return MPORT_OK;
+}
+
+
+
+static int check_for_upwards_depends(mportInstance *mport, mportPackageMeta *pack)
+{
+  sqlite3_stmt *stmt;
+  char *depends, *msg;
+  int count;
+      
+  if (mport_db_prepare(mport->db, &stmt, "SELECT group_concat(packages.pkg),count(packages.pkg) FROM depends JOIN packages ON depends.pkg=packages.pkg WHERE depend_pkgname=%Q", pack->name) != MPORT_OK)
+    RETURN_CURRENT_ERROR;
+  
+  switch (sqlite3_step(stmt)) {
+    case SQLITE_ROW:
+      depends = (char *)sqlite3_column_text(stmt, 0);
+      count   = sqlite3_column_int(stmt, 1);
+      
+      if (count != 0) {
+        (void)asprintf(&msg, "%s depend on %s, delete anyway?", depends, pack->name);
+        if ((mport->confirm_cb)(msg, "Delete", "Don't delete", 0) != MPORT_OK) {
+          sqlite3_finalize(stmt);
+          free(msg);
+          RETURN_ERRORX(MPORT_ERR_UPWARDS_DEPENDS, "%s depend on %s", depends, pack->name);
+        }
+        free(msg);
+      }
+      
+      break;    
+    default:
+      SET_ERROR(MPORT_ERR_SQLITE, sqlite3_errmsg(mport->db));
+      sqlite3_finalize(stmt);
+      RETURN_CURRENT_ERROR;
+  }
+  
+  sqlite3_finalize(stmt);
+  return MPORT_OK;
+} 
+      
+  
--- lib/libmport/create_pkg.c
+++ /dev/null
@@ -1,434 +0,0 @@
-/*-
- * Copyright (c) 2007 Chris Reinhardt
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * $MidnightBSD: src/lib/libmport/create_pkg.c,v 1.8 2007/12/01 06:21:37 ctriv Exp $
- */
-
-
-
-#include <sys/cdefs.h>
-#include <sys/time.h>
-#include <sys/types.h>
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sqlite3.h>
-#include <md5.h>
-#include <archive.h>
-#include <archive_entry.h>
-#include "mport.h"
-
-__MBSDID("$MidnightBSD: src/lib/libmport/create_pkg.c,v 1.8 2007/12/01 06:21:37 ctriv Exp $");
-
-
-static int create_package_db(sqlite3 **);
-static int insert_plist(sqlite3 *, mportPlist *, mportPackageMeta *);
-static int insert_meta(sqlite3 *, mportPackageMeta *);
-static int insert_depends(sqlite3 *, mportPackageMeta *);
-static int insert_conflicts(sqlite3 *, mportPackageMeta *);
-static int archive_files(mportPlist *, mportPackageMeta *, const char *);
-static int archive_metafiles(struct archive *, mportPackageMeta *);
-static int archive_plistfiles(struct archive *, mportPackageMeta *, mportPlist *);
-static int clean_up(const char *);
-
-
-int mport_create_pkg(mportPlist *plist, mportPackageMeta *pack)
-{
-  
-  int ret;
-  sqlite3 *db;
-
-  char dirtmpl[] = "/tmp/mport.XXXXXXXX"; 
-  char *tmpdir = mkdtemp(dirtmpl);
-
-  if (tmpdir == NULL) {
-    ret = SET_ERROR(MPORT_ERR_FILEIO, strerror(errno));
-    goto CLEANUP;
-  }
-  if (chdir(tmpdir) != 0)  {
-    ret = SET_ERROR(MPORT_ERR_FILEIO, strerror(errno));
-    goto CLEANUP;
-  }
-
-  if ((ret = create_package_db(&db)) != MPORT_OK)
-    goto CLEANUP;
-    
-  if ((ret = insert_plist(db, plist, pack)) != MPORT_OK)
-    goto CLEANUP;
-  
-  if ((ret = insert_meta(db, pack)) != MPORT_OK)
-    goto CLEANUP;
-    
-  if (sqlite3_close(db) != SQLITE_OK) {
-    ret = SET_ERROR(MPORT_ERR_SQLITE, sqlite3_errmsg(db));
-    goto CLEANUP;
-  }
-    
-  if ((ret = archive_files(plist, pack, tmpdir)) != MPORT_OK)
-    goto CLEANUP;
-  
-  CLEANUP:  
-    clean_up(tmpdir);
-    return ret;
-}
-
-
-static int create_package_db(sqlite3 **db) 
-{
-  if (sqlite3_open(MPORT_STUB_DB_FILE, db) != SQLITE_OK) {
-    sqlite3_close(*db);
-    RETURN_ERROR(MPORT_ERR_SQLITE, sqlite3_errmsg(*db));
-  }
-  
-  /* create tables */
-  return mport_generate_stub_schema(*db);
-}
-
-static int insert_plist(sqlite3 *db, mportPlist *plist, mportPackageMeta *pack)
-{
-  mportPlistEntry *e;
-  sqlite3_stmt *stmnt;
-  char sql[]  = "INSERT INTO assets (pkg, type, data, checksum) VALUES (?,?,?,?)";
-  char md5[33];
-  char file[FILENAME_MAX];
-  char cwd[FILENAME_MAX];
-
-  strlcpy(cwd, pack->sourcedir, FILENAME_MAX);
-  strlcat(cwd, pack->prefix, FILENAME_MAX);
-  
-  if (mport_db_prepare(db, &stmnt, sql) != MPORT_OK) 
-    RETURN_CURRENT_ERROR;
-  
-  STAILQ_FOREACH(e, plist, next) {
-    if (e->type == PLIST_CWD) {
-      strlcpy(cwd, pack->sourcedir, FILENAME_MAX);
-      if (e->data == NULL) {
-        strlcat(cwd, pack->prefix, FILENAME_MAX);
-      } else {
-        strlcat(cwd, e->data, FILENAME_MAX);
-      }
-    }
-    
-    if (sqlite3_bind_text(stmnt, 1, pack->name, -1, SQLITE_STATIC) != SQLITE_OK) {
-      RETURN_ERROR(MPORT_ERR_SQLITE, sqlite3_errmsg(db));
-    }
-    if (sqlite3_bind_int(stmnt, 2, e->type) != SQLITE_OK) {
-      RETURN_ERROR(MPORT_ERR_SQLITE, sqlite3_errmsg(db));
-    }
-    if (sqlite3_bind_text(stmnt, 3, e->data, -1, SQLITE_STATIC) != SQLITE_OK) {
-      RETURN_ERROR(MPORT_ERR_SQLITE, sqlite3_errmsg(db));
-    }
-    
-    if (e->type == PLIST_FILE) {
-      (void)snprintf(file, FILENAME_MAX, "%s/%s", cwd, e->data);
-      
-      if (MD5File(file, md5) == NULL) {
-        char *error;
-        (void)asprintf(&error, "File not found: %s", file);
-        RETURN_ERROR(MPORT_ERR_FILE_NOT_FOUND, error);
-      }
-      
-      if (sqlite3_bind_text(stmnt, 4, md5, -1, SQLITE_STATIC) != SQLITE_OK) {
-        RETURN_ERROR(MPORT_ERR_SQLITE, sqlite3_errmsg(db));
-      }
-    } else {
-      if (sqlite3_bind_null(stmnt, 4) != SQLITE_OK) {
-        RETURN_ERROR(MPORT_ERR_SQLITE, sqlite3_errmsg(db));
-      }
-    }
-    if (sqlite3_step(stmnt) != SQLITE_DONE) {
-      RETURN_ERROR(MPORT_ERR_SQLITE, sqlite3_errmsg(db));
-    }
-        
-    sqlite3_reset(stmnt);
-  } 
-  
-  sqlite3_finalize(stmnt);
-  
-  return MPORT_OK;
-}     
-
-static int insert_meta(sqlite3 *db, mportPackageMeta *pack)
-{
-  sqlite3_stmt *stmnt;
-  const char *rest  = 0;
-  struct timespec now;
-  int ret;
-  
-  char sql[]  = "INSERT INTO packages (pkg, version, origin, lang, prefix, date) VALUES (?,?,?,?,?,?)";
-  
-  if (sqlite3_prepare_v2(db, sql, -1, &stmnt, &rest) != SQLITE_OK) {
-    RETURN_ERROR(MPORT_ERR_SQLITE, sqlite3_errmsg(db));
-  }
-  if (sqlite3_bind_text(stmnt, 1, pack->name, -1, SQLITE_STATIC) != SQLITE_OK) {
-    RETURN_ERROR(MPORT_ERR_SQLITE, sqlite3_errmsg(db));
-  }
-  if (sqlite3_bind_text(stmnt, 2, pack->version, -1, SQLITE_STATIC) != SQLITE_OK) {
-    RETURN_ERROR(MPORT_ERR_SQLITE, sqlite3_errmsg(db));
-  }
-  if (sqlite3_bind_text(stmnt, 3, pack->origin, -1, SQLITE_STATIC) != SQLITE_OK) {
-    RETURN_ERROR(MPORT_ERR_SQLITE, sqlite3_errmsg(db));
-  }
-  if (sqlite3_bind_text(stmnt, 4, pack->lang, -1, SQLITE_STATIC) != SQLITE_OK) {
-    RETURN_ERROR(MPORT_ERR_SQLITE, sqlite3_errmsg(db));
-  }
-  if (sqlite3_bind_text(stmnt, 5, pack->prefix, -1, SQLITE_STATIC) != SQLITE_OK) {
-    RETURN_ERROR(MPORT_ERR_SQLITE, sqlite3_errmsg(db));
-  }
-  if (clock_gettime(CLOCK_REALTIME, &now) != 0) {
-    RETURN_ERROR(MPORT_ERR_SYSCALL_FAILED, strerror(errno));
-  }
-  
-  if (sqlite3_bind_int(stmnt, 6, now.tv_sec) != SQLITE_OK) {
-    RETURN_ERROR(MPORT_ERR_SQLITE, sqlite3_errmsg(db));
-  }
-    
-  if (sqlite3_step(stmnt) != SQLITE_DONE) {
-    RETURN_ERROR(MPORT_ERR_SQLITE, sqlite3_errmsg(db));
-  }
-  
-  sqlite3_finalize(stmnt);  
-
-  /* insert depends and conflicts */
-  if ((ret = insert_depends(db, pack)) != MPORT_OK)
-    return ret;  
-  if ((ret = insert_conflicts(db, pack)) != MPORT_OK)
-    return ret;
-    
-  return MPORT_OK;
-}
-
-
-static int insert_conflicts(sqlite3 *db, mportPackageMeta *pack) 
-{
-  sqlite3_stmt *stmnt;
-  char sql[]  = "INSERT INTO conflicts (pkg, conflict_pkg, conflict_version) VALUES (?,?,?)";
-  char **conflict  = pack->conflicts;
-  char *version;
-  const char *rest = 0;
-  
-  /* we're done if there are no conflicts to record. */
-  if (conflict == NULL) 
-    return MPORT_OK;
-  
-  if (sqlite3_prepare_v2(db, sql, -1, &stmnt, &rest) != SQLITE_OK) {
-    RETURN_ERROR(MPORT_ERR_SQLITE, sqlite3_errmsg(db));
-  }
-
-  /* we have a conflict like apache-1.4.  We want to do a m/(.*)-(.*)/ */
-  while (*conflict != NULL) {
-    version = rindex(*conflict, '-');
-    *version = '\0';
-    version++;
-    
-    if (sqlite3_bind_text(stmnt, 1, pack->name, -1, SQLITE_STATIC) != SQLITE_OK) {
-      RETURN_ERROR(MPORT_ERR_SQLITE, sqlite3_errmsg(db));
-    }
-    if (sqlite3_bind_text(stmnt, 2, *conflict, -1, SQLITE_STATIC) != SQLITE_OK) {
-      RETURN_ERROR(MPORT_ERR_SQLITE, sqlite3_errmsg(db));
-    }
-    if (sqlite3_bind_text(stmnt, 3, version, -1, SQLITE_STATIC) != SQLITE_OK) {
-      RETURN_ERROR(MPORT_ERR_SQLITE, sqlite3_errmsg(db));
-    }
-    if (sqlite3_step(stmnt) != SQLITE_DONE) {
-      RETURN_ERROR(MPORT_ERR_SQLITE, sqlite3_errmsg(db));
-    }
-    sqlite3_reset(stmnt);
-    conflict++;
-  }
-  
-  sqlite3_finalize(stmnt);
-  
-  return MPORT_OK;
-}
-    
-  
-
-static int insert_depends(sqlite3 *db, mportPackageMeta *pack) 
-{
-  sqlite3_stmt *stmnt;
-  char sql[]  = "INSERT INTO depends (pkg, depend_pkgname, depend_pkgversion, depend_port) VALUES (?,?,?,?)";
-  char **depend    = pack->depends;
-  char *pkgversion;
-  char *port;
-  const char *rest = 0;
-  
-  /* we're done if there are no deps to record. */
-  if (depend == NULL) 
-    return MPORT_OK;
-  
-  if (sqlite3_prepare_v2(db, sql, -1, &stmnt, &rest) != SQLITE_OK) {
-    RETURN_ERROR(MPORT_ERR_SQLITE, sqlite3_errmsg(db));
-  }
-  
-  
-  /* depends look like this.  break'em up into port, pkgversion and pkgname
-   * perl-5.8.8_1:lang/perl5.8
-   */
-  while (*depend != NULL) {
-    port = rindex(*depend, ':');
-    *port = '\0';
-    port++;
-    
-    pkgversion = rindex(*depend, '-');
-    *pkgversion = '\0';
-    pkgversion++;
-    
-    if (sqlite3_bind_text(stmnt, 1, pack->name, -1, SQLITE_STATIC) != SQLITE_OK) {
-      RETURN_ERROR(MPORT_ERR_SQLITE, sqlite3_errmsg(db));
-    }
-    if (sqlite3_bind_text(stmnt, 2, *depend, -1, SQLITE_STATIC) != SQLITE_OK) {
-      RETURN_ERROR(MPORT_ERR_SQLITE, sqlite3_errmsg(db));
-    }
-    if (sqlite3_bind_text(stmnt, 3, pkgversion, -1, SQLITE_STATIC) != SQLITE_OK) {
-      RETURN_ERROR(MPORT_ERR_SQLITE, sqlite3_errmsg(db));
-    }
-    if (sqlite3_bind_text(stmnt, 4, port, -1, SQLITE_STATIC) != SQLITE_OK) {
-      RETURN_ERROR(MPORT_ERR_SQLITE, sqlite3_errmsg(db));
-    }
-    if (sqlite3_step(stmnt) != SQLITE_DONE) {
-      RETURN_ERROR(MPORT_ERR_SQLITE, sqlite3_errmsg(db));
-    }
-    sqlite3_reset(stmnt);
-    depend++;
-  }
-    
-  sqlite3_finalize(stmnt);
-  
-  return MPORT_OK;
-}
-
-
-
-static int archive_files(mportPlist *plist, mportPackageMeta *pack, const char *tmpdir)
-{
-  struct archive *a;
-  char filename[FILENAME_MAX];
-
-  a = archive_write_new();
-  archive_write_set_compression_bzip2(a);
-  archive_write_set_format_pax(a);
-  
-  if (archive_write_open_filename(a, pack->pkg_filename) != ARCHIVE_OK) {
-    RETURN_ERROR(MPORT_ERR_ARCHIVE, archive_error_string(a)); 
-  }
-  
-  /* First step - +CONTENTS.db ALWAYS GOES FIRST!!! */        
-  (void)snprintf(filename, FILENAME_MAX, "%s/%s", tmpdir, MPORT_STUB_DB_FILE);
-  if (mport_add_file_to_archive(a, filename, MPORT_STUB_DB_FILE)) 
-    RETURN_CURRENT_ERROR;
-    
-  /* second step - the meta files */
-  if (archive_metafiles(a, pack) != MPORT_OK)
-    RETURN_CURRENT_ERROR;
-  
-  /* last step - the real files from the plist */
-  if (archive_plistfiles(a, pack, plist) != MPORT_OK)
-    RETURN_CURRENT_ERROR;
-    
-  archive_write_finish(a);
-  
-  return MPORT_OK;    
-}
-
-
-static int archive_metafiles(struct archive *a, mportPackageMeta *pack)
-{
-  char filename[FILENAME_MAX], dir[FILENAME_MAX];
-  
-  (void)snprintf(dir, FILENAME_MAX, "%s/%s-%s", MPORT_STUB_INFRA_DIR, pack->name, pack->version);
-
-  if (pack->mtree != NULL && mport_file_exists(pack->mtree)) {
-    (void)snprintf(filename, FILENAME_MAX, "%s/%s", dir, MPORT_MTREE_FILE);
-    if (mport_add_file_to_archive(a, pack->mtree, filename) != MPORT_OK)
-      RETURN_CURRENT_ERROR;
-  }
-  
-  if (pack->pkginstall != NULL && mport_file_exists(pack->pkginstall)) {
-    (void)snprintf(filename, FILENAME_MAX, "%s/%s", dir, MPORT_INSTALL_FILE);
-    if (mport_add_file_to_archive(a, pack->pkginstall, filename) != MPORT_OK)
-      RETURN_CURRENT_ERROR;
-  }
-  
-  if (pack->pkgdeinstall != NULL && mport_file_exists(pack->pkgdeinstall)) {
-    (void)snprintf(filename, FILENAME_MAX, "%s/%s", dir, MPORT_DEINSTALL_FILE);
-    if (mport_add_file_to_archive(a, pack->pkgdeinstall, filename) != MPORT_OK)
-      RETURN_CURRENT_ERROR;
-  }
-  
-  if (pack->pkgmessage != NULL && mport_file_exists(pack->pkgmessage)) {
-    (void)snprintf(filename, FILENAME_MAX, "%s/%s", dir, MPORT_MESSAGE_FILE);
-    if (mport_add_file_to_archive(a, pack->pkgmessage, filename) != MPORT_OK)
-      RETURN_CURRENT_ERROR;
-  }
-  
-  return MPORT_OK;
-}
-
-static int archive_plistfiles(struct archive *a, mportPackageMeta *pack, mportPlist *plist)
-{
-  mportPlistEntry *e;
-  char filename[FILENAME_MAX];
-  char *cwd = pack->prefix;
-  
-  STAILQ_FOREACH(e, plist, next) {
-    if (e->type == PLIST_CWD) {
-      if (e->data == NULL) {
-        cwd = pack->prefix;
-      } else {
-        cwd = e->data;
-      }
-    }
-    
-    if (e->type != PLIST_FILE) {
-      continue;
-    }
-    
-    (void)snprintf(filename, FILENAME_MAX, "%s/%s/%s", pack->sourcedir, cwd, e->data);
-    
-    if (mport_add_file_to_archive(a, filename, e->data) != MPORT_OK)
-      RETURN_CURRENT_ERROR;
-  }    
- 
-  return MPORT_OK;
-}
-
-#ifdef DEBUG
-
-static int clean_up(const char *tmpdir)
-{
-  /* do nothing */
-}
-
-#else
-
-static int clean_up(const char *tmpdir) 
-{
-  return mport_rmtree(tmpdir);
-}
-
-#endif
-
--- /dev/null
+++ lib/libmport/bundle.c
@@ -0,0 +1,165 @@
+/*-
+ * Copyright (c) 2007 Chris Reinhardt
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $MidnightBSD: src/lib/libmport/bundle.c,v 1.1 2008/01/05 22:18:20 ctriv Exp $
+ */
+
+
+#include <sys/stat.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <errno.h>
+#include <archive.h>
+#include <archive_entry.h>
+#include "mport.h"
+
+
+/* 
+ * mport_new_bundle() 
+ *
+ * allocate a new bundle struct.  Returns null if no
+ * memory could be had 
+ */
+mportBundle* mport_bundle_new() 
+{
+  return (mportBundle *)malloc(sizeof(mportBundle));
+}
+
+/*
+ * mport_init_bundle(filename)
+ * 
+ * set up an bundle for adding files.  Sets the bundle file to
+ * filename.
+ */
+int mport_bundle_init(mportBundle *bundle, const char *filename)
+{
+  if ((bundle->filename = strdup(filename)) == NULL)
+    RETURN_ERROR(MPORT_ERR_NO_MEM, "Couldn't dup filename");
+   
+  bundle->archive = archive_write_new();
+  archive_write_set_compression_bzip2(bundle->archive);
+  archive_write_set_format_pax(bundle->archive);
+ 
+  if (archive_write_open_filename(bundle->archive, bundle->filename) != ARCHIVE_OK) {
+    RETURN_ERROR(MPORT_ERR_ARCHIVE, archive_error_string(bundle->archive)); 
+  }
+  
+  return MPORT_OK;
+}
+
+/* 
+ * mport_finish_bundle(bundle)
+ *
+ * Finish the bundle file, and then free any memory used by the mportBundle struct.
+ *
+ */
+int mport_bundle_finish(mportBundle *bundle)
+{
+  int ret = MPORT_OK;
+  
+  if (archive_write_finish(bundle->archive) != MPORT_OK)
+    ret = SET_ERROR(MPORT_ERR_ARCHIVE, archive_error_string(bundle->archive));
+      
+  free(bundle->filename);
+  free(bundle);
+  
+  return ret;
+}
+
+
+/*
+ * mport_add_file_to_bundle(bundle, filename, path)
+ *
+ * Add a single file to the bundle.  filename is the name of the file
+ * in the system, while path is where the file should be put in the bundle.
+ */
+int mport_bundle_add_file(mportBundle *bundle, const char *filename, const char *path) 
+{
+  struct archive_entry *entry;
+  struct stat st;
+  int fd, len;
+  char buff[1024*64];
+  
+  if (lstat(filename, &st) != 0) {
+    RETURN_ERROR(MPORT_ERR_SYSCALL_FAILED, strerror(errno));
+  }
+
+  entry = archive_entry_new();
+  archive_entry_set_pathname(entry, path);
+ 
+  
+  if (S_ISLNK(st.st_mode)) {
+    /* we have us a symlink */
+    int linklen;
+    char linkdata[PATH_MAX];
+    
+    linklen = readlink(filename, linkdata, PATH_MAX);
+    
+    if (linklen < 0) 
+      RETURN_ERROR(MPORT_ERR_SYSCALL_FAILED, strerror(errno));
+      
+    linkdata[linklen] = 0;
+    
+    archive_entry_set_symlink(entry, linkdata);
+  }
+  
+  
+  if (st.st_flags != 0) 
+    archive_entry_set_fflags(entry, st.st_flags, 0);
+    
+  archive_entry_copy_stat(entry, &st);
+  
+  /* non-regular files get archived with zero size */
+  if (!S_ISREG(st.st_mode)) {
+    archive_entry_set_size(entry, 0);
+  }
+  /* make sure we can open the file before its header is put in the archive */
+  else if ((fd = open(filename, O_RDONLY)) == -1) {
+   RETURN_ERROR(MPORT_ERR_SYSCALL_FAILED, strerror(errno));
+  }
+    
+  if (archive_write_header(bundle->archive, entry) != ARCHIVE_OK)
+    RETURN_ERROR(MPORT_ERR_ARCHIVE, archive_error_string(bundle->archive));
+  
+  /* write the data to the archive if there is data to write */
+  if (archive_entry_size(entry) > 0) {
+    len = read(fd, buff, sizeof(buff));
+    while (len > 0) {
+      archive_write_data(bundle->archive, buff, len);
+      len = read(fd, buff, sizeof(buff));
+    }
+  }
+    
+  archive_entry_free(entry);
+  
+  if (fd != 0)
+    close(fd);
+
+  return MPORT_OK;  
+}
+
--- /dev/null
+++ lib/libmport/default_cbs.c
@@ -0,0 +1,129 @@
+/*-
+ * Copyright (c) 2007 Chris Reinhardt
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $MidnightBSD: src/lib/libmport/default_cbs.c,v 1.1 2008/01/05 22:18:20 ctriv Exp $
+ */
+
+
+#include <stdio.h>
+#include <termios.h>
+#include <stdlib.h>
+#include <string.h>
+#include "mport.h"
+
+void mport_default_msg_cb(const char *msg) 
+{
+  (void)printf("%s\n", msg);
+}
+
+int mport_default_confirm_cb(const char *msg, const char *yes, const char *no, int def)
+{
+  size_t len;
+  char *ans;
+  
+  (void)fprintf(stderr, "%s (Y/N) [%s]: ", msg, def == 1 ? yes : no);
+  
+  while (1) {
+    /* get answer, if just \n, then default. */
+    ans = fgetln(stdin, &len);
+
+    if (len == 1) { 
+      /* user just hit return */
+      return def == 1 ? MPORT_OK : -1;
+    }  
+    
+    if (*ans == 'Y' || *ans == 'y') 
+      return MPORT_OK;
+    if (*ans == 'N' || *ans == 'n')
+      return -1;
+    
+    (void)fprintf(stderr, "Please enter yes or no: ");   
+  }
+  
+  /* Not reached */
+  return MPORT_OK;
+}
+
+
+void mport_default_progress_init_cb()
+{
+  /* do nothing */
+  return;
+}
+
+
+#define ESC "\x1b"
+#define BACK ESC "[%iD"
+#define UP   ESC "[A"
+#define DEL  ESC "[2K"
+
+void mport_default_progress_step_cb(int current, int total, const char *msg)
+{
+  struct termios term;
+  struct winsize win;
+  int width, bar_width, bar_on, bar_off;
+  double percent;
+  char *bar;
+
+  if ((tcgetattr(STDIN_FILENO, &term) < 0) || (ioctl(STDIN_FILENO, TIOCGWINSZ, &win) < 0)) {
+    /* not a terminal or couldn't get terminal width*/
+    (void)printf("%s\n", msg);
+    return;
+  }
+
+  width = win.ws_col;
+  bar_width = width - 10;
+
+  if ((bar = (char *)malloc(sizeof(char) * width)) == NULL) {
+    /* no memory, we're outa here */
+    (void)printf("%s\n", msg);
+    return;
+  }
+
+  percent = (double)current / (double)total;
+  
+  bar_on = (int)(percent * (bar_width - 2));
+  bar_off = bar_width - 2 - bar_on;
+
+  bar[0] = '[';
+  (void)memset(&(bar[1]), '=', bar_on);
+  (void)memset(&(bar[1 + bar_on]), ' ', bar_off);
+  bar[1 + bar_on + bar_off] = ']';
+  bar[2 + bar_on + bar_off] = 0;
+  
+  (void)printf(BACK DEL, width);
+//  (void)printf("%s\n", msg);
+  (void)printf("%s %3i/100%%", bar, (int)(percent * 100));
+  (void)fflush(stdout);
+  
+  free(bar);
+}
+
+void mport_default_progress_free_cb() 
+{
+  (void)printf("\n");
+  (void)fflush(stdout);
+}
+
--- lib/libmport/archive.c
+++ /dev/null
@@ -1,74 +0,0 @@
-/*-
- * Copyright (c) 2007 Chris Reinhardt
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * $MidnightBSD: src/lib/libmport/archive.c,v 1.1 2007/12/01 06:21:37 ctriv Exp $
- */
-
-
-#include <sys/stat.h>
-#include <string.h>
-#include <errno.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <archive.h>
-#include <archive_entry.h>
-#include "mport.h"
-
-__MBSDID("$MidnightBSD: src/lib/libmport/archive.c,v 1.1 2007/12/01 06:21:37 ctriv Exp $");
-
-
-int mport_add_file_to_archive(struct archive *a, const char *filename, const char *path) 
-{
-  struct archive_entry *entry;
-  struct stat st;
-  int fd, len;
-  char buff[1024*8];
-  
-  if (lstat(filename, &st) != 0) {
-    RETURN_ERROR(MPORT_ERR_SYSCALL_FAILED, strerror(errno));
-  }
-  
-  entry = archive_entry_new();
-  archive_entry_copy_stat(entry, &st);
-  archive_entry_set_pathname(entry, path);
-  archive_write_header(a, entry);
-  
-  if ((fd = open(filename, O_RDONLY)) == -1) {
-    RETURN_ERROR(MPORT_ERR_SYSCALL_FAILED, strerror(errno));
-  }
-    
-  len = read(fd, buff, sizeof(buff));
-  while (len > 0) {
-    archive_write_data(a, buff, len);
-    len = read(fd, buff, sizeof(buff));
-  }
-    
-  archive_entry_free(entry);
-  close(fd);
-
-  return MPORT_OK;  
-}
-
Index: mport.h
===================================================================
RCS file: /home/cvs/src/lib/libmport/mport.h,v
retrieving revision 1.8
retrieving revision 1.9
diff -L lib/libmport/mport.h -L lib/libmport/mport.h -u -r1.8 -r1.9
--- lib/libmport/mport.h
+++ lib/libmport/mport.h
@@ -34,12 +34,56 @@
 __MBSDID("$MidnightBSD$");
 
 
-
-/* plist stuff */
-
+#include <archive.h>
+#include <sqlite3.h>
 #include <sys/queue.h>
 #include <stdio.h>
 
+typedef void (*mport_msg_cb)(const char *);
+typedef void (*mport_progress_init_cb)(void);
+typedef void (*mport_progress_step_cb)(int, int, const char *);
+typedef void (*mport_progress_free_cb)(void);
+typedef int (*mport_confirm_cb)(const char *, const char *, const char *, int);
+
+/* Mport Instance (an installed copy of the mport system) */
+typedef struct {
+  sqlite3 *db;
+  char *root;
+  mport_msg_cb msg_cb;
+  mport_progress_init_cb progress_init_cb;
+  mport_progress_step_cb progress_step_cb;
+  mport_progress_free_cb progress_free_cb;
+  mport_confirm_cb confirm_cb;
+} mportInstance;
+
+mportInstance * mport_instance_new(void);
+int mport_instance_init(mportInstance *, const char *);
+int mport_instance_free(mportInstance *);
+
+void mport_set_msg_cb(mportInstance *, mport_msg_cb);
+void mport_set_progress_init_cb(mportInstance *, mport_progress_init_cb);
+void mport_set_progress_step_cb(mportInstance *, mport_progress_step_cb);
+void mport_set_progress_free_cb(mportInstance *, mport_progress_free_cb);
+void mport_set_confirm_cb(mportInstance *, mport_confirm_cb);
+
+void mport_default_msg_cb(const char *);
+int mport_default_confirm_cb(const char *, const char *, const char *, int);
+void mport_default_progress_init_cb(void);
+void mport_default_progress_step_cb(int, int, const char *);
+void mport_default_progress_free_cb(void);
+
+
+/* Mport Bundle (a file containing packages) */
+typedef struct {
+  struct archive *archive;
+  char *filename;
+} mportBundle;
+
+mportBundle* mport_bundle_new(void);
+int mport_bundle_init(mportBundle *, const char *);
+int mport_bundle_finish(mportBundle *);
+int mport_bundle_add_file(mportBundle *, const char *, const char *);
+
 
 /* For now this is just the FreeBSD list, this will change soon. */
 enum _PlistEntryType { 
@@ -63,9 +107,9 @@
 typedef struct _Plist mportPlist;
 typedef struct _PlistEntry mportPlistEntry;
 
-mportPlist* mport_new_plist(void);
-void mport_free_plist(mportPlist *);
-int mport_parse_plist_file(FILE *, mportPlist *);
+mportPlist* mport_plist_new(void);
+void mport_plist_free(mportPlist *);
+int mport_plist_parsefile(FILE *, mportPlist *);
 
 /* Package Meta-data structure */
 
@@ -88,35 +132,36 @@
   char *pkgmessage;
 } mportPackageMeta;  
 
-mportPackageMeta * mport_new_packagemeta(void);
-void mport_free_packagemeta(mportPackageMeta *);
-void mport_free_packagemeta_vec(mportPackageMeta **);
+mportPackageMeta * mport_packagemeta_new(void);
+void mport_packagemeta_free(mportPackageMeta *);
+void mport_packagemeta_vec_free(mportPackageMeta **);
 
-/* Package creation */
-int mport_create_pkg(mportPlist *, mportPackageMeta *);
 
+/* Package creation */
+int mport_create_primative(mportPlist *, mportPackageMeta *);
 
 /* Package installation */
-int mport_install_pkg(const char *, const char *);
+int mport_install_primative(mportInstance *, const char *, const char *);
 
+/* Package deletion */
+int mport_delete_primative(mportInstance *, mportPackageMeta *, int);
 
-#include <sqlite3.h>
+/* precondition checking */
+int mport_check_update_preconditions(mportInstance *, mportPackageMeta *);
+int mport_check_install_preconditions(mportInstance *, mportPackageMeta *);
 
 /* schema */
 int mport_generate_master_schema(sqlite3 *);
 int mport_generate_stub_schema(sqlite3 *);
 
 /* Various database convience functions */
-int mport_db_open_master(sqlite3 **);
 int mport_attach_stub_db(sqlite3 *, const char *);
+int mport_detach_stub_db(sqlite3 *);
 int mport_get_meta_from_stub(sqlite3 *, mportPackageMeta ***);
-int mport_get_meta_from_master(sqlite3 *, mportPackageMeta**, const char *);
+int mport_get_meta_from_master(mportInstance *, mportPackageMeta ***, const char *, ...);
 int mport_db_do(sqlite3 *, const char *, ...);
 int mport_db_prepare(sqlite3 *, sqlite3_stmt **, const char *, ...);
 
-/* instance init */
-int mport_inst_init(sqlite3 **);
-
 
 /* version comparing */
 int mport_version_cmp(const char *, const char *);
@@ -142,7 +187,10 @@
 #define MPORT_ERR_CONFLICTS		10
 #define MPORT_ERR_MISSING_DEPEND	11
 #define MPORT_ERR_MALFORMED_VERSION	12
-#define MPORT_ERR_NO_SUCH_PKG		13
+#define MPORT_ERR_MALFORMED_DEPEND	13
+#define MPORT_ERR_NO_SUCH_PKG		14
+#define MPORT_ERR_CHECKSUM_MISMATCH	15
+#define MPORT_ERR_UPWARDS_DEPENDS	16
 
 #define RETURN_CURRENT_ERROR return mport_err_code()
 #define RETURN_ERROR(code, msg) return mport_set_errx((code), "Error at %s:(%d): %s", __FILE__, __LINE__, (msg))
@@ -155,15 +203,13 @@
 int mport_copy_file(const char *, const char *);
 int mport_rmtree(const char *);
 int mport_mkdir(const char *);
+int mport_rmdir(const char *, int);
 int mport_file_exists(const char *);
-int mport_xsystem(const char *, ...);
+int mport_xsystem(mportInstance *mport, const char *, ...);
 void mport_parselist(char *, char ***);
-int mport_run_plist_exec(const char *, const char *, const char *);
+int mport_run_plist_exec(mportInstance *mport, const char *, const char *, const char *);
 
 
-/* archive helpers */
-#include <archive.h>
-int mport_add_file_to_archive(struct archive *, const char *, const char *);
 
 /* Infrastructure files */
 #define MPORT_STUB_DB_FILE 	"+CONTENTS.db"
@@ -182,5 +228,7 @@
 /* Binaries we use */
 #define MPORT_MTREE_BIN		"/usr/sbin/mtree"
 #define MPORT_SH_BIN		"/bin/sh"
+#define MPORT_CHROOT_BIN	"/usr/sbin/chroot"
 
 #endif /* ! defined _MPORT_H */
+


More information about the Midnightbsd-cvs mailing list