[Midnightbsd-cvs] src: lib/libmport: Add version comparisons.

ctriv at midnightbsd.org ctriv at midnightbsd.org
Fri Nov 23 00:57:43 EST 2007


Log Message:
-----------
Add version comparisons.
Add preconditions check to package installation.

Modified Files:
--------------
    src/lib/libmport:
        Makefile (r1.3 -> r1.4)
        install_pkg.c (r1.1 -> r1.2)
        mport.h (r1.5 -> r1.6)

Added Files:
-----------
    src/lib/libmport:
        version_cmp.c (r1.1)

-------------- next part --------------
Index: install_pkg.c
===================================================================
RCS file: /home/cvs/src/lib/libmport/install_pkg.c,v
retrieving revision 1.1
retrieving revision 1.2
diff -L lib/libmport/install_pkg.c -L lib/libmport/install_pkg.c -u -r1.1 -r1.2
--- lib/libmport/install_pkg.c
+++ lib/libmport/install_pkg.c
@@ -41,6 +41,7 @@
 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 *);
@@ -102,8 +103,8 @@
     pack->prefix = (char *)prefix;
     
   /* check if this is installed already, depends, and conflicts */
-//  if ((ret = mport_check_preconditions(db, pack)) != MPORT_OK)
-//    return ret;
+  if ((ret = check_preconditions(db, pack)) != MPORT_OK)
+    return ret;
  
   /* Run mtree.  Run pkg-install. Etc... */
   if ((ret = do_pre_install(db, pack, tmpdir)) != MPORT_OK)
@@ -161,7 +162,7 @@
     goto ERROR;
 
   /* Insert the package meta row into the packages table  - XXX Does not honor pack->prefix! */  
-  if (mport_db_do(db, "INSERT INTO packages (pkg, version, origin, prefix, lang, options) SELECT (pkg, version, origin, prefix, lang, options) FROM stub.package") != MPORT_OK)
+  if (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 (mport_db_do(db, "INSERT INTO assets (pkg, type, data, checksum) SELECT (pkg,type,data,checksum) FROM stub.assets") != MPORT_OK)
@@ -237,6 +238,134 @@
   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_pkgersion 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) {
+        /* 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)
 {
--- /dev/null
+++ lib/libmport/version_cmp.c
@@ -0,0 +1,130 @@
+/*-
+ * 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/version_cmp.c,v 1.1 2007/11/23 05:57:43 ctriv Exp $
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include "mport.h"
+
+__MBSDID("$MidnightBSD: src/lib/libmport/version_cmp.c,v 1.1 2007/11/23 05:57:43 ctriv Exp $");
+
+struct version {
+  char *version;
+  int revision;
+  int epoch;
+};
+
+static void parse_version(const char *, struct version *);
+static int cmp_versions(char *, char *);
+
+int mport_version_cmp(const char *astr, const char *bstr)
+{
+  struct version a;
+  struct version b;
+  int result;
+  
+  parse_version(astr, &a);
+  parse_version(bstr, &b);
+
+  /* remember that a.version/b.version are useless after calling
+     cmp_versions (but astr and bstr are unchanged.) */
+  result =  (a.epoch < b.epoch) 
+         || cmp_versions(a.version, b.version) 
+         || (a.revision < b.revision);
+  
+  free(a.version);
+  free(b.version);
+  
+  return result;
+}
+
+static void parse_version(const char *in, struct version *v) 
+{
+  char *s = strdup(in);
+  char *underscore;
+  char *comma;
+  
+  underscore = rindex(s, '_');
+  comma      = rindex(s, ',');
+  
+  if (comma == NULL) {
+    v->epoch = 0;
+  } else {
+    *comma = '\0';
+    v->epoch = (int)strtol(comma + 1, NULL, 10);
+  }
+  
+  if (underscore == NULL) {
+    v->revision = 0;
+  } else {
+    *underscore = '\0';
+    v->revision = (int)strtol(underscore + 1, NULL, 10);
+  }
+  
+  v->version = s;
+}
+
+static int cmp_versions(char *a, char *b)
+{
+  char *a_dot, *b_dot;
+  int a_sub, b_sub;
+  
+  while (1) {
+    a_dot = index(a, '.');
+    b_dot = index(b, '.');
+    
+    if (a_dot == NULL && b_dot == NULL) {
+      a_sub = (int)strtol(a, NULL, 10);
+      b_sub = (int)strtol(b, NULL, 10);
+      
+      return a_sub < b_sub;
+    } else if (a_dot == NULL) {
+      /* b has more sub versions, must be more recent */
+      return -1;
+    } else if (b_dot == NULL) {
+      /* a has more sub versions, must be more recent */
+      return 1;
+    } else {
+       *a_dot = *b_dot = '\0';
+    
+      a_sub = (int)strtol(a, NULL, 10);
+      b_sub = (int)strtol(b, NULL, 10);
+    
+      if (a_sub != b_sub) {
+        return a_sub < b_sub;
+      }
+    
+      /* this pair of sub versions matched.  Go to the next pair. */
+      a = a_dot + 1;
+      b = b_dot + 1;
+    }
+  }
+  
+  /* not reached */
+  return 0;
+}
+
Index: mport.h
===================================================================
RCS file: /home/cvs/src/lib/libmport/mport.h,v
retrieving revision 1.5
retrieving revision 1.6
diff -L lib/libmport/mport.h -L lib/libmport/mport.h -u -r1.5 -r1.6
--- lib/libmport/mport.h
+++ lib/libmport/mport.h
@@ -116,6 +116,10 @@
 int mport_inst_init(sqlite3 **);
 
 
+/* version comparing */
+int mport_version_cmp(const char *, const char *);
+
+
 /* Errors */
 int mport_err_code(void);
 char * mport_err_string(void);
@@ -132,6 +136,11 @@
 #define MPORT_ERR_SYSCALL_FAILED	6
 #define MPORT_ERR_ARCHIVE		7
 #define MPORT_ERR_INTERNAL		8
+#define MPORT_ERR_ALREADY_INSTALLED	9
+#define MPORT_ERR_CONFLICTS		10
+#define MPORT_ERR_MISSING_DEPEND	11
+#define MPORT_ERR_MALFORMED_VERSION	12
+
 
 #define RETURN_ERROR(code, msg) return mport_set_errx((code), "Error at %s:(%d): %s", __FILE__, __LINE__, (msg))
 #define SET_ERROR(code,msg) mport_set_errx((code), "Error at %s:(%d): %s", __FILE__, __LINE__, (msg))
Index: Makefile
===================================================================
RCS file: /home/cvs/src/lib/libmport/Makefile,v
retrieving revision 1.3
retrieving revision 1.4
diff -L lib/libmport/Makefile -L lib/libmport/Makefile -u -r1.3 -r1.4
--- lib/libmport/Makefile
+++ lib/libmport/Makefile
@@ -1,7 +1,7 @@
 # $MidnightBSD$
 
 LIB=		mport
-SRCS=		plist.c	create_pkg.c db_schema.c db_stub.c db_util.c util.c error.c install_pkg.c inst_init.c
+SRCS=		plist.c	create_pkg.c db_schema.c db_stub.c db_util.c util.c error.c install_pkg.c inst_init.c version_cmp.c
 
 INCS=		mport.h
 


More information about the Midnightbsd-cvs mailing list