Radish alpha
H
HardenedBSD Package Manager
Radicle
Git (anonymous pull)
Log in to clone via SSH
Refactor. Add support for reading INDEXFILE from command line.
Matthew Seaman committed 12 years ago
commit 6b5b6492bc690b4ad2c462f022c91b5a8d5ba18c
parent 53c88bc318aab47272ef3974f6b5cbbdc82baadb
1 file changed +490 -254
modified src/version.c
@@ -4,9 +4,9 @@
 * Copyright (c) 2011 Philippe Pepiot <phil@philpep.org>
 * Copyright (c) 2011-2012 Marin Atanasov Nikolov <dnaeon@gmail.com>
 * Copyright (c) 2012 Bryan Drewery <bryan@shatow.net>
-
 * Copyright (c) 2013 Matthew Seaman <matthew@FreeBSD.org>
+
 * Copyright (c) 2013-2014 Matthew Seaman <matthew@FreeBSD.org>
 * All rights reserved.
-
 * 
+
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
@@ -16,7 +16,7 @@
 * 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(S) ``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.
@@ -59,64 +59,55 @@ void
usage_version(void)
{
	fprintf(stderr, "Usage: pkg version [-IPR] [-hoqvU] [-l limchar] [-L limchar] [-egix pattern]\n");
-
	fprintf(stderr, "                   [-r reponame] [-O origin] [index]\n");
-
	fprintf(stderr, "       pkg version -t <version1> <version2>\n");
-
	fprintf(stderr, "       pkg version -T <pkgname> <pattern>\n\n");
+
	fprintf(stderr, "		    [-r reponame] [-O origin] [index]\n");
+
	fprintf(stderr, "	pkg version -t <version1> <version2>\n");
+
	fprintf(stderr, "	pkg version -T <pkgname> <pattern>\n\n");
	fprintf(stderr, "For more information see 'pkg help version'.\n");
}

static void
-
print_version(struct pkg *pkg, const char *source, const char *ver, char limchar, unsigned int opt)
+
print_version(struct pkg *pkg, const char *source, const char *ver,
+
	      char limchar, unsigned int opt)
{
-
	bool to_print = true;
-
	char key;
-
	const char *version;
-
	char *namever = NULL;
+
	const char	*key;
+
	const char	*version;

	pkg_get(pkg, PKG_VERSION, &version);
	if (ver == NULL) {
		if (source == NULL)
-
			key = '!';
+
			key = "!";
		else
-
			key = '?';
+
			key = "?";
	} else {
		switch (pkg_version_cmp(version, ver)) {
		case -1:
-
			key = '<';
+
			key = "<";
			break;
		case 0:
-
			key = '=';
+
			key = "=";
			break;
		case 1:
-
			key = '>';
+
			key = ">";
			break;
		default:
-
			key = '!';
+
			key = "!";
			break;
		}
	}

-
	if ((opt & VERSION_STATUS) && limchar != key) {
-
		to_print = false;
-
	}
-
	if ((opt & VERSION_NOSTATUS) && limchar == key) {
-
		to_print = false;
-
	}
-

-
	if (!to_print)
+
	if ((opt & VERSION_STATUS) && limchar != *key)
		return;

+
	if ((opt & VERSION_NOSTATUS) && limchar == *key)
+
		return;

	if (opt & VERSION_ORIGIN)
-
		pkg_asprintf(&namever, "%-34o", pkg);
+
		pkg_printf("%-34o %S", pkg, key);
	else
-
		pkg_asprintf(&namever, "%n-%v", pkg, pkg);
-

-
	printf("%-34s %c", namever, key);
-
	free(namever);
+
		pkg_printf("%n-%v %S", pkg, pkg, key);

	if (opt & VERSION_VERBOSE) {
-
		switch (key) {
+
		switch (*key) {
		case '<':
			printf("   needs updating (%s has %s)", source, ver);
			break;
@@ -136,43 +127,436 @@ print_version(struct pkg *pkg, const char *source, const char *ver, char limchar
	}

	printf("\n");
+
	return;
+
}
+

+
static int
+
do_testversion(unsigned int opt, int argc, char ** restrict argv)
+
{
+
	/* -t must be unique and takes two arguments */
+
	if ( opt != VERSION_TESTVERSION || argc < 2 ) {
+
		usage_version();
+
		return (EX_USAGE);
+
	}
+

+
	switch (pkg_version_cmp(argv[0], argv[1])) {
+
	case -1:
+
		printf("<\n");
+
		break;
+
	case 0:
+
		printf("=\n");
+
		break;
+
	case 1:
+
		printf(">\n");
+
		break;
+
	}
+

+
	return (EX_OK);
+
}
+

+
static int
+
do_testpattern(unsigned int opt, int argc, char ** restrict argv)
+
{
+
	bool	 pattern_from_stdin = false;
+
	bool	 pkgname_from_stdin = false;
+
	char	*line = NULL;
+
	size_t	 linecap = 0;
+
	ssize_t	 linelen;
+
	int	 retval = FNM_NOMATCH;
+

+
	/* -T must be unique and takes two arguments */
+
	if ( opt != VERSION_TESTPATTERN || argc < 2 ) {
+
		usage_version();
+
		return (EX_USAGE);
+
	}
+

+
	if (strncmp(argv[0], "-", 1) == 0)
+
		pattern_from_stdin = true;
+

+
	if (strncmp(argv[1], "-", 1) == 0)
+
		pkgname_from_stdin = true;
+

+
	if (pattern_from_stdin && pkgname_from_stdin) {
+
		usage_version();
+
		return (EX_USAGE);
+
	}
+

+
	if (!pattern_from_stdin && !pkgname_from_stdin)
+
		return (fnmatch(argv[1], argv[0], 0));
+

+
	while ((linelen = getline(&line, &linecap, stdin)) > 0) {
+
		line[linelen - 1] = '\0'; /* Strip trailing newline */
+

+
		if ((pattern_from_stdin && (fnmatch(argv[1], line, 0) == 0)) ||
+
		    (pkgname_from_stdin && (fnmatch(line, argv[0], 0) == 0))) {
+
			retval = EPKG_OK;
+
			printf("%.*s\n", (int)linelen, line);
+
		}
+
	}
+

+
	free(line);
+

+
	return (retval);
+
}
+

+
static bool
+
have_ports(const char **portsdir)
+
{
+
	char		 portsdirmakefile[MAXPATHLEN];
+
	struct stat	 sb;
+
	bool		 have_ports;
+

+
	/* Look for Makefile within $PORTSDIR as indicative of
+
	 * installed ports tree. */
+

+
	*portsdir = pkg_object_string(pkg_config_get("PORTSDIR"));
+
	if (*portsdir == NULL)
+
		err(1, "Cannot get portsdir config entry!");
+

+
	snprintf(portsdirmakefile, sizeof(portsdirmakefile),
+
		 "%s/Makefile", *portsdir);
+

+
	have_ports = (stat(portsdirmakefile, &sb) == 0 && S_ISREG(sb.st_mode));
+

+
	if (!have_ports)
+
		warnx("Cannot find ports tree: unable to open %s",
+
		      portsdirmakefile);
+

+
	return (have_ports);
+
}
+

+
static const char*
+
indexfilename(char *filebuf, size_t filebuflen)
+
{
+
	const char	*indexdir;
+
	const char	*indexfile;
+

+
	/* Construct the canonical name of the indexfile from the
+
	 * ports directory and the major version number of the OS.
+
	 * Overridden by INDEXDIR and INDEXFILE if defined. (Mimics
+
	 * the behaviour of ${PORTSDIR}/Makefile) */
+

+
	indexdir = pkg_object_string(pkg_config_get("INDEXDIR"));
+
	if (indexdir == NULL) {
+
		indexdir = pkg_object_string(pkg_config_get("PORTSDIR"));
+

+
		if (indexdir == NULL)
+
			err(EX_SOFTWARE, "Cannot get either INDEXDIR or "
+
			    "PORTSDIR config entry!");
+
	}
+

+
	indexfile = pkg_object_string(pkg_config_get("INDEXFILE"));
+
	if (indexfile == NULL)
+
		err(EX_SOFTWARE, "Cannot get INDEXFILE config entry!");
+

+
	strlcpy(filebuf, indexdir, filebuflen);
+

+
	if (filebuf[0] != '\0' && filebuf[strlen(filebuf) - 1] != '/')
+
		strlcat(filebuf, "/", filebuflen);
+

+
	strlcat(filebuf, indexfile, filebuflen);
+

+
	return (filebuf);
+
}
+

+
static struct index_entry *
+
hash_indexfile(const char *indexfilename)
+
{
+
	FILE			*indexfile;
+
	struct index_entry	*indexhead = NULL;
+
	struct index_entry	*entry;
+
	char			*p, *version, *origin;
+
	char			*line;
+
	int			 dirs;
+
	size_t			 linecap;
+

+
	/* Create a hash table of all the package names and port
+
	 * directories from the index file. */
+

+
	indexfile = fopen(indexfilename, "r");
+
	if (!indexfile)
+
		err(EX_NOINPUT, "Unable to open %s!", indexfilename);
+

+
	while (getline(&line, &linecap, indexfile) > 0) {
+
		/* line is pkgname|portdir|... */
+

+
		version = strsep(&line, "|");
+
		origin = strsep(&line, "|");
+
		
+
		version = strrchr(version, '-');
+
		version[0] = '\0';
+
		version++;
+

+
		for (dirs = 0, p = strchr(line, '|');
+
		     p > origin && dirs < 2;
+
		     p--) {
+
			if ( p[-1] == '/' )
+
				dirs++;
+
		}
+
		origin = p;
+

+
		entry = malloc(sizeof(struct index_entry));
+
		if (entry != NULL) {
+
			entry->version = strdup(version);
+
			entry->origin = strdup(origin);
+
		}
+

+
		if (entry == NULL || entry->version == NULL ||
+
		    entry->origin == NULL)
+
			err(EX_SOFTWARE, "Out of memory while reading %s",
+
			    indexfilename);
+

+
		HASH_ADD_KEYPTR(hh, indexhead, entry->origin,
+
				strlen(entry->origin), entry);
+
	}
+

+
	free(line);
+
	fclose(indexfile);
+

+
	return (indexhead);
+
}
+

+
static void
+
free_index(struct index_entry *indexhead)
+
{
+
	struct index_entry	*entry, *tmp;
+

+
	HASH_ITER(hh, indexhead, entry, tmp) {
+
		HASH_DEL(indexhead, entry);
+
		free(entry->origin);
+
		free(entry->version);
+
		free(entry);
+
	}
+
	return;
+
}
+

+
static int
+
do_source_index(unsigned int opt, char limchar, char *pattern, match_t match,
+
		const char *indexfile, const char *matchorigin)
+
{
+
	char			 filebuf[MAXPATHLEN];
+
	struct index_entry	*indexhead;
+
	struct index_entry	*entry;
+
	struct pkgdb		*db;
+
	struct pkgdb_it		*it = NULL;
+
	struct pkg		*pkg = NULL;
+
	const char		*origin;
+

+
	if ( (opt & VERSION_SOURCES) != VERSION_SOURCE_INDEX ) {
+
		usage_version();
+
		return (EX_USAGE);
+
	}
+

+
	/* If there is a remaining command line argument, take
+
	   that as the name of the INDEX file to use.  Otherwise,
+
	   search for INDEX-N within the ports tree */
+

+
	if (indexfile == NULL) 
+
		indexfile = indexfilename(filebuf, sizeof(filebuf));
+

+
	if (pkgdb_open(&db, PKGDB_DEFAULT) != EPKG_OK)
+
		return (EX_IOERR);
+

+
	indexhead = hash_indexfile(indexfile);
+

+
	if (pkgdb_obtain_lock(db, PKGDB_LOCK_READONLY, 0, 0) != EPKG_OK) {
+
		pkgdb_close(db);
+
		free_index(indexhead);
+
		warnx("Cannot get a read lock on the database. "
+
		      "It is locked by another process");
+
		return (EX_TEMPFAIL);
+
	}
+

+
	it = pkgdb_query(db, pattern, match);
+
	if (it == NULL)
+
		goto cleanup;
+

+
	while (pkgdb_it_next(it, &pkg, PKG_LOAD_BASIC) == EPKG_OK) {
+
		pkg_get(pkg, PKG_ORIGIN, &origin);
+

+
		/* If -O was specified, check if this origin matches */
+

+
		if ((opt & VERSION_WITHORIGIN) &&
+
		    strcmp(origin, matchorigin) != 0)
+
			continue;
+
		
+
		HASH_FIND_STR(indexhead, origin, entry);
+
		if (entry != NULL)
+
			print_version(pkg, "index", entry->version,
+
			    limchar, opt);
+
	}
+

+
cleanup:
+
	pkgdb_release_lock(db, PKGDB_LOCK_READONLY);
+
	free_index(indexhead);
+
	pkg_free(pkg);
+
	pkgdb_it_free(it);
+
	pkgdb_close(db);
+

+
	return (EPKG_OK);
+
}
+

+
static int
+
do_source_remote(unsigned int opt, char limchar, char *pattern, match_t match,
+
		 bool auto_update, const char *reponame,
+
		 const char *matchorigin)
+
{
+
	struct pkgdb	*db = NULL;
+
	struct pkgdb_it	*it = NULL;
+
	struct pkgdb_it	*it_remote = NULL;
+
	struct pkg	*pkg = NULL;
+
	struct pkg	*pkg_remote = NULL;
+
	const char	*origin;
+
	const char	*version_remote;
+

+
	int		 retcode = EPKG_OK;
+

+
	if ( (opt & VERSION_SOURCES) != VERSION_SOURCE_REMOTE ) {
+
		usage_version();
+
		return (EX_USAGE);
+
	}
+

+
	/* Only force remote mode if looking up remote, otherwise
+
	   user is forced to have a repo.sqlite */
+

+
	if (auto_update) {
+
		retcode = pkgcli_update(false);
+
		if (retcode != EPKG_OK)
+
			return (retcode);
+
	}
+

+
	if (pkgdb_open(&db, PKGDB_REMOTE) != EPKG_OK)
+
		return (EX_IOERR);
+

+
	if (pkgdb_obtain_lock(db, PKGDB_LOCK_READONLY, 0, 0) != EPKG_OK) {
+
		pkgdb_close(db);
+
		warnx("Cannot get a read lock on a database. "
+
		      "It is locked by another process");
+
		return (EX_TEMPFAIL);
+
	}
+

+
	it = pkgdb_query(db, pattern, match);
+
	if (it == NULL) {
+
		retcode = EX_IOERR;
+
		goto cleanup;
+
	}
+

+
	while (pkgdb_it_next(it, &pkg, PKG_LOAD_BASIC) == EPKG_OK) {
+
		pkg_get(pkg, PKG_ORIGIN, &origin);
+

+
		/* If -O was specified, check if this origin matches */
+
		if ((opt & VERSION_WITHORIGIN) &&
+
		    strcmp(origin, matchorigin) != 0)
+
			continue;
+

+
		it_remote = pkgdb_rquery(db, origin, MATCH_EXACT, reponame);
+
		if (it_remote == NULL) {
+
			retcode = EX_IOERR;
+
			goto cleanup;
+
		}
+

+
		if (pkgdb_it_next(it_remote, &pkg_remote, PKG_LOAD_BASIC)
+
		    == EPKG_OK) {
+
			pkg_get(pkg_remote, PKG_VERSION, &version_remote);
+
			print_version(pkg, "remote", version_remote, limchar,
+
			    opt);
+
		} else {
+
			print_version(pkg, "remote", NULL, limchar, opt);
+
		}
+
		pkgdb_it_free(it_remote);
+
	}
+

+
cleanup:
+
	pkgdb_release_lock(db, PKGDB_LOCK_READONLY);
+

+
	pkg_free(pkg);
+
	pkg_free(pkg_remote);
+
	pkgdb_it_free(it);
+
	pkgdb_close(db);
+

+
	return (retcode);
+
}
+

+
static int
+
do_source_ports(unsigned int opt, char limchar, char *pattern, match_t match,
+
	const char *matchorigin)
+
{
+
	struct pkgdb	*db = NULL;
+
	struct pkgdb_it	*it = NULL;
+
	struct pkg	*pkg = NULL;
+
	struct sbuf	*cmd;
+
	struct sbuf	*res;
+
	const char	*portsdir;
+
	const char	*origin;
+
	char		*buf;
+

+
	if ( (opt & VERSION_SOURCES) != VERSION_SOURCE_PORTS ) {
+
		usage_version();
+
		return (EX_USAGE);
+
	}
+

+
	if (!have_ports(&portsdir))
+
		return (EX_SOFTWARE);
+

+
	if (pkgdb_open(&db, PKGDB_DEFAULT) != EPKG_OK)
+
		return (EX_IOERR);
+

+
	if (pkgdb_obtain_lock(db, PKGDB_LOCK_READONLY, 0, 0) != EPKG_OK) {
+
		pkgdb_close(db);
+
		warnx("Cannot get a read lock on a database. "
+
		      "It is locked by another process");
+
		return (EX_TEMPFAIL);
+
	}
+

+
	if ((it = pkgdb_query(db, pattern, match)) == NULL)
+
			goto cleanup;
+

+
	while (pkgdb_it_next(it, &pkg, PKG_LOAD_BASIC) == EPKG_OK) {
+
		pkg_get(pkg, PKG_ORIGIN, &origin);
+

+
		/* If -O was specified, check if this origin matches */
+
		if ((opt & VERSION_WITHORIGIN) &&
+
		    strcmp(origin, matchorigin) != 0)
+
			continue;
+

+
		cmd = sbuf_new_auto();
+
		sbuf_printf(cmd, "make -C %s/%s -VPKGVERSION 2>/dev/null",
+
			    portsdir, origin);
+
		sbuf_finish(cmd);
+

+
		if ((res = exec_buf(sbuf_data(cmd))) != NULL) {
+
			buf = sbuf_data(res);
+
			print_version(pkg, "port", strsep(&buf, "\n"), limchar,
+
			    opt);
+
			sbuf_delete(res);
+
		} else {
+
			print_version(pkg, "port", NULL, limchar, opt);
+
		}
+
		sbuf_delete(cmd);
+
	}
+

+
cleanup:
+
	pkgdb_release_lock(db, PKGDB_LOCK_READONLY);
+

+
	pkg_free(pkg);
+
	pkgdb_it_free(it);
+
	pkgdb_close(db);
+

+
	return (EPKG_OK);
}

int
exec_version(int argc, char **argv)
{
-
	unsigned int opt = 0;
-
	int ch;
-
	FILE *indexfile;
-
	char indexpath[MAXPATHLEN];
-
	struct index_entry *indexhead = NULL;
-
	struct utsname u;
-
	int rel_major_ver;
-
	int retval;
-
	char *line = NULL;
-
	size_t linecap = 0;
-
	ssize_t linelen;
-
	char *buf;
-
	char *version;
-
	struct index_entry *entry, *tmp;
-
	struct pkgdb *db = NULL;
-
	struct pkg *pkg = NULL, *pkg_remote = NULL;
-
	struct pkgdb_it *it = NULL, *it_remote = NULL;
-
	char limchar = '-';
-
	struct sbuf *cmd;
-
	struct sbuf *res;
-
	const char *portsdir;
-
	const char *origin;
-
	const char *matchorigin = NULL;
-
	const char *reponame = NULL;
-
	const char *version_remote = NULL;
-
	bool have_ports;
-
	bool auto_update;
-
	match_t match = MATCH_ALL;
-
	char *pattern=NULL;
-
	struct stat sb;
-
	char portsdirmakefile[MAXPATHLEN];
-
	int retcode = EXIT_SUCCESS;
+
	unsigned int	 opt = 0;
+
	char		 limchar = '-';
+
	const char	*origin;
+
	const char	*matchorigin = NULL;
+
	const char	*reponame = NULL;
+
	bool		 auto_update;
+
	match_t		 match = MATCH_ALL;
+
	char		*pattern = NULL;
+
	int		 ch;

	auto_update = pkg_object_bool(pkg_config_get("REPO_AUTOUPDATE"));

@@ -246,204 +630,56 @@ exec_version(int argc, char **argv)
	argc -= optind;
	argv += optind;

-
	if (opt & VERSION_STATUS) {
-
			if (limchar != '<' &&
-
					limchar != '>' &&
-
					limchar != '=') {
-
				usage_version();
-
				return (EX_USAGE);
-
			}
-
	}
+
	/*
+
	 * Allowed option combinations:
+
	 *   -t ver1 ver2	 -- only
+
	 *   -T pkgname pattern	 -- only
+
	 *   Only one of -I -P -R can be given
+
	 */

-
	/* -t must be unique */
-
	if (((opt & VERSION_TESTVERSION) && opt != VERSION_TESTVERSION) ||
-
			(opt == VERSION_TESTVERSION && argc < 2)) {
-
		usage_version();
-
		return (EX_USAGE);
-
	
-
	} else if (opt == VERSION_TESTVERSION) {
-
		switch (pkg_version_cmp(argv[0], argv[1])) {
-
		case -1:
-
			printf("<\n");
-
			break;
-
		case 0:
-
			printf("=\n");
-
			break;
-
		case 1:
-
			printf(">\n");
-
			break;
-
		}
-
	/* -T must be unique */
-
	} else if (((opt & VERSION_TESTPATTERN) && opt != VERSION_TESTPATTERN) ||
-
			(opt == VERSION_TESTPATTERN && argc != 2)) {
-
		usage_version();
-
		return (EX_USAGE);
-
	
-
	} else if (opt == VERSION_TESTPATTERN) {
-
		if (strcmp(argv[0], "-") == 0) {
-
			ch = 0; /* pattern from stdin */
-
		} else if (strcmp(argv[1], "-") == 0) {
-
			ch = 1; /* pkgname from stdin */
-
		} else return (fnmatch(argv[1], argv[0], 0));
-
		
-
		retval = FNM_NOMATCH;
-
		
-
		while ((linelen = getline(&line, &linecap, stdin)) > 0) {
-
			line[linelen - 1] = '\0'; /* Strip trailing newline */
-
			if ((ch == 0 && (fnmatch(argv[1], line, 0) == 0)) ||
-
				(ch == 1 && (fnmatch(line, argv[0], 0) == 0))) {
-
				retval = EPKG_OK;
-
				printf("%.*s\n", (int)linelen, line);
-
			}
-
		}
+
	if ( (opt & VERSION_TESTVERSION) == VERSION_TESTVERSION )
+
		return (do_testversion(opt, argc, argv));

-
		free(line);
-
		
-
		return (retval);
-
		
-
	} else {
-
		portsdir = pkg_object_string(pkg_config_get("PORTSDIR"));
-
		if (portsdir == NULL)
-
			err(1, "Cannot get portsdir config entry!");
-

-
		snprintf(portsdirmakefile, sizeof(portsdirmakefile),
-
		    "%s/Makefile", portsdir);
-

-
		have_ports = (stat(portsdirmakefile, &sb) == 0 && S_ISREG(sb.st_mode));
-

-
		/* If none of -IPR were specified, and portsdir exists use that,
-
		   otherwise fallback to remote. */
-
		if ((opt & (VERSION_SOURCE_PORTS|VERSION_SOURCE_REMOTE|VERSION_SOURCE_INDEX)) == 0) {
-
			if (have_ports)
-
				opt |= VERSION_SOURCE_PORTS;
-
			else
-
				opt |= VERSION_SOURCE_REMOTE;
-
		}
+
	if ( (opt & VERSION_TESTPATTERN) == VERSION_TESTPATTERN )
+
		return (do_testpattern(opt, argc, argv));

-
		if (!have_ports && (opt & (VERSION_SOURCE_INDEX|VERSION_SOURCE_PORTS)))
-
			err(1, "Unable to open ports directory %s", portsdir);
-

-
		/* Only force remote mode if looking up remote, otherwise
-
		   user is forced to have a repo.sqlite */
-
		if (opt & VERSION_SOURCE_REMOTE) {
-
			if (auto_update) {
-

-
				retcode = pkgcli_update(false);
-
				if (retcode != EPKG_OK)
-
					return (retcode);
-
			}
-
			if (pkgdb_open(&db, PKGDB_REMOTE) != EPKG_OK)
-
				return (EX_IOERR);
-
		} else
-
			if (pkgdb_open(&db, PKGDB_DEFAULT) != EPKG_OK)
-
				return (EX_IOERR);
-

-
		if (pkgdb_obtain_lock(db, PKGDB_LOCK_READONLY, 0, 0) != EPKG_OK) {
-
			pkgdb_close(db);
-
			warnx("Cannot get a read lock on a database, it is locked by another process");
-
			return (EX_TEMPFAIL);
+
	if (opt & (VERSION_STATUS|VERSION_NOSTATUS)) {
+
		if (limchar != '<' &&
+
		    limchar != '>' &&
+
		    limchar != '=') {
+
			usage_version();
+
			return (EX_USAGE);
		}
+
	}

-
		if ((it = pkgdb_query(db, pattern, match)) == NULL)
-
			goto cleanup;
+
	if ( (opt & VERSION_SOURCE_INDEX) == VERSION_SOURCE_INDEX )
+
		return (do_source_index(opt, limchar, pattern, match,
+
			    (argc > 0 ? argv[0] : NULL), matchorigin));

-
		if (opt & VERSION_SOURCE_INDEX) {
-
			uname(&u);
-
			rel_major_ver = (int) strtol(u.release, NULL, 10);
-
			snprintf(indexpath, sizeof(indexpath), "%s/INDEX-%d", portsdir, rel_major_ver);
-
			indexfile = fopen(indexpath, "r");
-
			if (!indexfile) {
-
				warnx("Unable to open %s!", indexpath);
-
				retcode = EX_IOERR;
-
				goto cleanup;
-
			}
-

-
			while ((linelen = getline(&line, &linecap, indexfile)) > 0) {
-
				/* line is pkgname|portdir|... */
-
				buf = strchr(line, '|');
-
				buf[0] = '\0';
-
				buf++;
-
				version = strrchr(line, '-');
-
				version[0] = '\0';
-
				version++;
-
				buf = strchr(buf, '|');
-
				buf[0] = '\0';
-
				buf--;
-
				/* go backward to get the last two dirs of portsdir */
-
				while (buf[0] != '/')
-
					buf--;
-
				buf--;
-
				while (buf[0] != '/')
-
					buf--;
-
				buf++;
-

-
				entry = malloc(sizeof(struct index_entry));
-
				entry->version = strdup(version);
-
				entry->origin = strdup(buf);
-
				HASH_ADD_KEYPTR(hh, indexhead, entry->origin, strlen(entry->origin), entry);
-
			}
-
			free(line);
-
			fclose(indexfile);
-
		}
+
	if ( (opt & VERSION_SOURCE_REMOTE) == VERSION_SOURCE_REMOTE )
+
		return (do_source_remote(opt, limchar, pattern, match,
+
			    auto_update, reponame, matchorigin));

-
		while (pkgdb_it_next(it, &pkg, PKG_LOAD_BASIC) == EPKG_OK) {
-
			pkg_get(pkg, PKG_ORIGIN, &origin);
-

-
			/* If -O was specific, check if this origin matches */
-
			if ((opt & VERSION_WITHORIGIN) && strcmp(origin, matchorigin) != 0)
-
				continue;
-

-
			if (opt & VERSION_SOURCE_INDEX) {
-
				HASH_FIND_STR(indexhead, origin, entry);
-
				if (entry != NULL)
-
					print_version(pkg, "index", entry->version, limchar, opt);
-
			} else if (opt & VERSION_SOURCE_PORTS) {
-
				cmd = sbuf_new_auto();
-
				sbuf_printf(cmd, "make -C %s/%s -VPKGVERSION 2>/dev/null", portsdir, origin);
-
				sbuf_finish(cmd);
-

-
				if ((res = exec_buf(sbuf_data(cmd))) != NULL) {
-
					buf = sbuf_data(res);
-
					while (*buf != '\0') {
-
						if (*buf == '\n') {
-
							*buf = '\0';
-
							break;
-
						}
-
						buf++;
-
					}
-
					print_version(pkg, "port", sbuf_data(res), limchar, opt);
-
					sbuf_delete(res);
-
				} else {
-
					print_version(pkg, "port", NULL, limchar, opt);
-
				}
-
				sbuf_delete(cmd);
-
			} else if (opt & VERSION_SOURCE_REMOTE) {
-
				if ((it_remote = pkgdb_rquery(db, origin, MATCH_EXACT, reponame)) == NULL)
-
					return (EX_IOERR);
-
				if (pkgdb_it_next(it_remote, &pkg_remote, PKG_LOAD_BASIC) == EPKG_OK) {
-
					pkg_get(pkg_remote, PKG_VERSION, &version_remote);
-
					print_version(pkg, "remote", version_remote, limchar, opt);
-
				} else {
-
					print_version(pkg, "remote", NULL, limchar, opt);
-
				}
-
				pkgdb_it_free(it_remote);
-
			}
-
		}
-
	}
-
	
-
cleanup:
-
	HASH_ITER(hh, indexhead, entry, tmp) {
-
		HASH_DEL(indexhead, entry);
-
		free(entry->origin);
-
		free(entry->version);
-
		free(entry);
-
	}
+
	if ( (opt & VERSION_SOURCE_PORTS) == VERSION_SOURCE_PORTS )
+
		return (do_source_ports(opt, limchar, pattern, match,
+
			    matchorigin));

-
	pkg_free(pkg);
-
	pkg_free(pkg_remote);
-
	pkgdb_it_free(it);
-
	pkgdb_release_lock(db, PKGDB_LOCK_READONLY);
-
	pkgdb_close(db);
+
	/* If none of -IPR were specified, and portsdir exists use
+
	   that, otherwise fallback to remote. */

-
	return (retcode);
+
	if (have_ports) {
+
		opt |= VERSION_SOURCE_PORTS;
+
		return (do_source_ports(opt, limchar, pattern, match,
+
			    matchorigin));
+
	} else {
+
		opt |= VERSION_SOURCE_REMOTE;
+
		return (do_source_remote(opt, limchar, pattern, match,
+
			    auto_update, reponame, matchorigin));
+
	}
+

+
	/* NOTREACHED */
+
	return (EX_SOFTWARE);
}
+
/*
+
 * That's All Folks!
+
 */