[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