예제 #1
0
파일: utils.c 프로젝트: afb/pkgng
void
print_info(struct pkg * const pkg, unsigned int options)
{
	struct pkg_category *cat    = NULL;
	struct pkg_dep	    *dep    = NULL;
	struct pkg_dir	    *dir    = NULL;
	struct pkg_file	    *file   = NULL;
	struct pkg_group    *group  = NULL;
	struct pkg_license  *lic    = NULL;
	struct pkg_option   *option = NULL;
	struct pkg_shlib    *shlib  = NULL;
	struct pkg_note	    *note   = NULL;
	struct pkg_user	    *user   = NULL;
	bool print_tag = false;
	bool show_locks = false;
	char size[7];
	const char *name, *version, *prefix, *origin, *reponame, *repourl;
	const char *maintainer, *www, *comment, *desc, *message, *arch;
	const char *repopath;
	const char *tab;
	unsigned opt;
	int64_t flatsize, oldflatsize, pkgsize;
	lic_t licenselogic;
	bool locked;
	int cout = 0;		/* Number of characters output */
	int info_num;		/* Number of different data items to print */

	pkg_get(pkg,
		PKG_NAME,          &name,
		PKG_VERSION,       &version,
		PKG_PREFIX,        &prefix,
		PKG_ORIGIN,        &origin,
		PKG_REPONAME,      &reponame,
		PKG_REPOURL,       &repourl,
		PKG_MAINTAINER,    &maintainer,
		PKG_WWW,           &www,
		PKG_COMMENT,       &comment,
		PKG_DESC,          &desc,
		PKG_FLATSIZE,      &flatsize,
		PKG_OLD_FLATSIZE,  &oldflatsize,
		PKG_PKGSIZE,   &pkgsize,
		PKG_LICENSE_LOGIC, &licenselogic,
		PKG_MESSAGE,       &message,
		PKG_ARCH,	   &arch,
		PKG_REPOPATH,	   &repopath,
		PKG_LOCKED,	   &locked);

	if (options & INFO_RAW) {
		if (pkg_type(pkg) != PKG_REMOTE)
			pkg_emit_manifest_file(pkg, stdout, 0, NULL);
		else
			pkg_emit_manifest_file(pkg, stdout, PKG_MANIFEST_EMIT_COMPACT, NULL);
		return;
	}

	/* Show locking status when requested to display it and the
	   package is locally installed */
	if (pkg_type(pkg) == PKG_INSTALLED && (options & INFO_LOCKED) != 0)
		show_locks = true;

	if (!quiet) {
		/* Print a tag-line identifying the package -- either
		   NAMEVER, ORIGIN or NAME (in that order of
		   preference).  This may be the only output from this
		   function */

		if (options & INFO_TAG_NAMEVER)
			cout = printf("%s-%s", name, version);
		else if (options & INFO_TAG_ORIGIN)
			cout = printf("%s", origin);
		else if (options & INFO_TAG_NAME)
			cout = printf("%s", name);
	}

	/* Don't display a tab if quiet, retains compatibility. */
	tab = quiet ? "" : "\t";

	/* If we printed a tag, and there are no other items to print,
	   then just return now. If there's only one single-line item
	   to print, show it at column 32 on the same line. If there's
	   one multi-line item to print, start a new line. If there is
	   more than one item to print per pkg, use 'key : value'
	   style to show on a new line.  */

	info_num = 0;
	for (opt = 0x1U; opt <= INFO_LASTFIELD; opt <<= 1) 
		if ((opt & options) != 0)
			info_num++;

	if (info_num == 0 && cout > 0) {
		printf("\n");
		return;
	}

	if (info_num == 1) {
		/* Only one item to print */
		print_tag = false;
		if (!quiet) {
			if (options & INFO_MULTILINE)
				printf(":\n");
			else {
				if (cout < 31)
					cout = 31 - cout;
				else
					cout = 1;
				printf("%*s", cout, " ");
			}
		}
	} else {
		/* Several items to print */
		print_tag = true;
		if (!quiet)
			printf("\n");
	}

	for (opt = 0x1; opt <= INFO_LASTFIELD; opt <<= 1) {
		if ((opt & options) == 0)
			continue;

		switch (opt) {
		case INFO_NAME:
			if (print_tag)
				printf("%-15s: ", "Name");
			printf("%s\n", name);
			break;
		case INFO_VERSION:
			if (print_tag)
				printf("%-15s: ", "Version");
			printf("%s\n", version);
			break;
		case INFO_ORIGIN:
			if (print_tag)
				printf("%-15s: ", "Origin");
			printf("%s\n", origin);
			break;
		case INFO_PREFIX:
			if (print_tag)
				printf("%-15s: ", "Prefix");
			printf("%s\n", prefix);
			break;
		case INFO_REPOSITORY:
			if (pkg_type(pkg) == PKG_REMOTE &&
			    repourl != NULL && repourl[0] != '\0') {
				if (print_tag)
					printf("%-15s: ", "Repository");
				printf("%s [%s]\n", reponame, repourl);
			} else if (!print_tag)
				printf("\n");
			break;
		case INFO_CATEGORIES:
			if (pkg_list_count(pkg, PKG_CATEGORIES) > 0) {
				if (print_tag)
					printf("%-15s: ", "Categories");
				if (pkg_categories(pkg, &cat) == EPKG_OK)
					printf("%s", pkg_category_name(cat));
				while (pkg_categories(pkg, &cat) == EPKG_OK)
					printf(" %s", pkg_category_name(cat));
				printf("\n");
			} else if (!print_tag)
				printf("\n");
			break;
		case INFO_LICENSES:
			if (pkg_list_count(pkg, PKG_LICENSES) > 0) {
				if (print_tag)
					printf("%-15s: ", "Licenses");
				if (pkg_licenses(pkg, &lic) == EPKG_OK)
					printf("%s", pkg_license_name(lic));
				while (pkg_licenses(pkg, &lic) == EPKG_OK) {
					if (licenselogic != 1)
						printf(" %c", licenselogic);
					printf(" %s", pkg_license_name(lic));
				}
				printf("\n");				
			} else if (!print_tag)
				printf("\n");
			break;
		case INFO_MAINTAINER:
			if (print_tag)
				printf("%-15s: ", "Maintainer");
			printf("%s\n", maintainer);
			break;
		case INFO_WWW:	
			if (print_tag)
				printf("%-15s: ", "WWW");
			printf("%s\n", www);
			break;
		case INFO_COMMENT:
			if (print_tag)
				printf("%-15s: ", "Comment");
			printf("%s\n", comment);
			break;
		case INFO_OPTIONS:
			if (pkg_list_count(pkg, PKG_OPTIONS) > 0) {
				if (print_tag)
					printf("%-15s:\n", "Options");
				while (pkg_options(pkg, &option) == EPKG_OK)
					printf("%s%-15s: %s\n",
					       tab,
					       pkg_option_opt(option),
					       pkg_option_value(option));
			}
			break;
		case INFO_SHLIBS_REQUIRED:
			if (pkg_list_count(pkg, PKG_SHLIBS_REQUIRED) > 0) {
				if (print_tag)
					printf("%-15s:\n", "Shared Libs required");
				while (pkg_shlibs_required(pkg, &shlib) == EPKG_OK)
					printf("%s%s\n", tab, pkg_shlib_name(shlib));
			}
			break;
		case INFO_SHLIBS_PROVIDED:
			if (pkg_list_count(pkg, PKG_SHLIBS_PROVIDED) > 0) {
				if (print_tag)
					printf("%-15s:\n", "Shared Libs provided");
				while (pkg_shlibs_provided(pkg, &shlib) == EPKG_OK)
					printf("%s%s\n", tab, pkg_shlib_name(shlib));
			}
			break;
		case INFO_ANNOTATIONS:
			if (pkg_list_count(pkg, PKG_ANNOTATIONS) > 0) {
				if (print_tag)
					printf("%-15s:\n", "Annotations");
				while (pkg_annotations(pkg, &note) == EPKG_OK)
					printf("%s%-15s: %s\n", tab,
					       pkg_annotation_tag(note),
					       pkg_annotation_value(note));
			}
			break;
		case INFO_FLATSIZE:
			humanize_number(size, sizeof(size),
			    flatsize,"B",
			    HN_AUTOSCALE, 0);

			if (print_tag)
				printf("%-15s: ", "Flat size");
			printf("%s\n", size);
			break;
		case INFO_PKGSIZE: /* Remote pkgs only */
			if (pkg_type(pkg) == PKG_REMOTE) {
				humanize_number(size, sizeof(size),
						pkgsize,"B",
						HN_AUTOSCALE, 0);
				if (print_tag)
					printf("%-15s: ", "Pkg size");
				printf("%s\n", size);
			} else if (!print_tag)
				printf("\n");
			break;
		case INFO_DESCR:
			if (print_tag)
				printf("%-15s:\n", "Description");
			printf("%s\n", desc);
			break;
		case INFO_MESSAGE:
			if (message) {
				if (print_tag)
					printf("%-15s:\n", "Message");
				printf("%s\n", message);
			}
			break;
		case INFO_DEPS:
			if (pkg_list_count(pkg, PKG_DEPS) > 0) {
				if (print_tag)
					printf("%-15s:\n", "Depends on");
				while (pkg_deps(pkg, &dep) == EPKG_OK) {
					printf("%s%s-%s",
					       tab,
					       pkg_dep_name(dep),
					       pkg_dep_version(dep));
					if (show_locks && pkg_dep_is_locked(dep))
						printf(" (*)");
					printf("\n");
				}
			}
			break;
		case INFO_RDEPS:
			if (pkg_list_count(pkg, PKG_RDEPS) > 0) {
				if (print_tag)
					printf("%-15s:\n", "Required by");
				while (pkg_rdeps(pkg, &dep) == EPKG_OK) {
					printf("%s%s-%s",
					       tab,
					       pkg_dep_name(dep),
					       pkg_dep_version(dep));
					if (show_locks && pkg_dep_is_locked(dep))
						printf(" (*)");
					printf("\n");
				}
			}
			break;
		case INFO_FILES: /* Installed pkgs only */
			if (pkg_type(pkg) != PKG_REMOTE &&
			    pkg_list_count(pkg, PKG_FILES) > 0) {
				if (print_tag)
					printf("%-15s:\n", "Files");
				while (pkg_files(pkg, &file) == EPKG_OK)
					printf("%s%s\n",
					       tab,
					       pkg_file_path(file));
			}
			break;
		case INFO_DIRS:	/* Installed pkgs only */
			if (pkg_type(pkg) != PKG_REMOTE &&
			    pkg_list_count(pkg, PKG_DIRS) > 0) {
				if (print_tag)
					printf("%-15s:\n", "Directories");
				while (pkg_dirs(pkg, &dir) == EPKG_OK)
					printf("%s%s\n",
					       tab,
					       pkg_dir_path(dir));
			}
			break;
		case INFO_USERS: /* Installed pkgs only */
			if (pkg_type(pkg) != PKG_REMOTE &&
			    pkg_list_count(pkg, PKG_USERS) > 0) {
				if (print_tag)
					printf("%-15s: ", "Users");
				if (pkg_users(pkg, &user) == EPKG_OK)
					printf("%s", pkg_user_name(user));
				while (pkg_users(pkg, &user) == EPKG_OK)
					printf(" %s", pkg_user_name(user));
				printf("\n");
			}
			break;
		case INFO_GROUPS: /* Installed pkgs only */
			if (pkg_type(pkg) != PKG_REMOTE &&
			    pkg_list_count(pkg, PKG_GROUPS) > 0) {
				if (print_tag)
					printf("%-15s: ", "Groups");
				if (pkg_groups(pkg, &group) == EPKG_OK)
					printf("%s", pkg_group_name(group));
				while (pkg_groups(pkg, &group) == EPKG_OK)
					printf(" %s", pkg_group_name(group));
				printf("\n");
			}
			break;
		case INFO_ARCH:
			if (print_tag)
				printf("%-15s: ", "Architecture");
			printf("%s\n", arch);
			break;
		case INFO_REPOURL:
			if (pkg_type(pkg) == PKG_REMOTE &&
			    repourl != NULL && repourl[0] != '\0') {
				if (print_tag)
					printf("%-15s: ", "Pkg URL");
				if (repourl[strlen(repourl) -1] == '/')
					printf("%s%s\n", repourl, repopath);
				else
					printf("%s/%s\n", repourl, repopath);
			} else if (!print_tag)
				printf("\n");
			break;
		case INFO_LOCKED:
			if (print_tag)
				printf("%-15s: ", "Locked");
			printf("%s\n", locked ? "yes" : "no");
			break;
		}
	}
}
예제 #2
0
파일: utils.c 프로젝트: DarknessWarrior/pkg
void
print_info(struct pkg * const pkg, unsigned int options)
{
	bool print_tag = false;
	bool show_locks = false;
	char size[7];
	const char *repourl;
	unsigned opt;
	int64_t flatsize, oldflatsize, pkgsize;
	int cout = 0;		/* Number of characters output */
	int info_num;		/* Number of different data items to print */

	pkg_get(pkg,
		PKG_REPOURL,       &repourl,
		PKG_FLATSIZE,      &flatsize,
		PKG_OLD_FLATSIZE,  &oldflatsize,
		PKG_PKGSIZE,       &pkgsize);

	if (options & INFO_RAW) {
		if (pkg_type(pkg) != PKG_REMOTE)
			pkg_emit_manifest_file(pkg, stdout, PKG_MANIFEST_EMIT_PRETTY, NULL);
		else
			pkg_emit_manifest_file(pkg, stdout, PKG_MANIFEST_EMIT_COMPACT|PKG_MANIFEST_EMIT_PRETTY, NULL);
		return;
	}

	/* Show locking status when requested to display it and the
	   package is locally installed */
	if (pkg_type(pkg) == PKG_INSTALLED && (options & INFO_LOCKED) != 0)
		show_locks = true;

	if (!quiet) {
		/* Print a tag-line identifying the package -- either
		   NAMEVER, ORIGIN or NAME (in that order of
		   preference).  This may be the only output from this
		   function */

		if (options & INFO_TAG_NAMEVER)
			cout = pkg_printf("%n-%v", pkg, pkg);
		else if (options & INFO_TAG_ORIGIN)
			cout = pkg_printf("%o", pkg);
		else if (options & INFO_TAG_NAME)
			cout = pkg_printf("%n", pkg);
	}

	/* If we printed a tag, and there are no other items to print,
	   then just return now. If there's only one single-line item
	   to print, show it at column 32 on the same line. If there's
	   one multi-line item to print, start a new line. If there is
	   more than one item to print per pkg, use 'key : value'
	   style to show on a new line.  */

	info_num = 0;
	for (opt = 0x1U; opt <= INFO_LASTFIELD; opt <<= 1) 
		if ((opt & options) != 0)
			info_num++;

	if (info_num == 0 && cout > 0) {
		printf("\n");
		return;
	}

	if (info_num == 1) {
		/* Only one item to print */
		print_tag = false;
		if (!quiet) {
			if (options & INFO_MULTILINE)
				printf(":\n");
			else {
				if (cout < 31)
					cout = 31 - cout;
				else
					cout = 1;
				printf("%*s", cout, " ");
			}
		}
	} else {
		/* Several items to print */
		print_tag = true;
		if (!quiet)
			printf("\n");
	}

	for (opt = 0x1; opt <= INFO_LASTFIELD; opt <<= 1) {
		if ((opt & options) == 0)
			continue;

		switch (opt) {
		case INFO_NAME:
			if (print_tag)
				printf("%-15s: ", "Name");
			pkg_printf("%n\n", pkg);
			break;
		case INFO_VERSION:
			if (print_tag)
				printf("%-15s: ", "Version");
			pkg_printf("%v\n", pkg);
			break;
		case INFO_ORIGIN:
			if (print_tag)
				printf("%-15s: ", "Origin");
			pkg_printf("%o\n", pkg);
			break;
		case INFO_PREFIX:
			if (print_tag)
				printf("%-15s: ", "Prefix");
			pkg_printf("%p\n", pkg);
			break;
		case INFO_REPOSITORY:
			if (pkg_type(pkg) == PKG_REMOTE &&
			    repourl != NULL && repourl[0] != '\0') {
				if (print_tag)
					printf("%-15s: ", "Repository");
				pkg_printf("%N [%S]\n", pkg, repourl);
			} else if (!print_tag)
				printf("\n");
			break;
		case INFO_CATEGORIES:
			if (pkg_list_count(pkg, PKG_CATEGORIES) > 0) {
				if (print_tag)
					printf("%-15s: ", "Categories");
				pkg_printf("%C%{%Cn%| %}\n", pkg);
			} else if (!print_tag)
				printf("\n");
			break;
		case INFO_LICENSES:
			if (pkg_list_count(pkg, PKG_LICENSES) > 0) {
				if (print_tag)
					printf("%-15s: ", "Licenses");
				pkg_printf("%L%{%Ln%| %l %}\n", pkg);
			} else if (!print_tag)
				printf("\n");
			break;
		case INFO_MAINTAINER:
			if (print_tag)
				printf("%-15s: ", "Maintainer");
			pkg_printf("%m\n", pkg);
			break;
		case INFO_WWW:	
			if (print_tag)
				printf("%-15s: ", "WWW");
			pkg_printf("%w\n", pkg);
			break;
		case INFO_COMMENT:
			if (print_tag)
				printf("%-15s: ", "Comment");
			pkg_printf("%c\n", pkg);
			break;
		case INFO_OPTIONS:
			if (pkg_list_count(pkg, PKG_OPTIONS) > 0) {
				if (print_tag)
					printf("%-15s:\n", "Options");
				if (quiet) 
					pkg_printf("%O%{%-15On: %Ov\n%|%}", pkg);
				else
					pkg_printf("%O%{\t%-15On: %Ov\n%|%}", pkg);
			}
			break;
		case INFO_SHLIBS_REQUIRED:
			if (pkg_list_count(pkg, PKG_SHLIBS_REQUIRED) > 0) {
				if (print_tag)
					printf("%-15s:\n", "Shared Libs required");
				if (quiet)
					pkg_printf("%B%{%Bn\n%|%}", pkg);
				else
					pkg_printf("%B%{\t%Bn\n%|%}", pkg);
			}
			break;
		case INFO_SHLIBS_PROVIDED:
			if (pkg_list_count(pkg, PKG_SHLIBS_PROVIDED) > 0) {
				if (print_tag)
					printf("%-15s:\n", "Shared Libs provided");
				if (quiet)
					pkg_printf("%b%{%bn\n%|%}", pkg);
				else
					pkg_printf("%b%{\t%bn\n%|%}", pkg);
			}
			break;
		case INFO_ANNOTATIONS:
			if (pkg_list_count(pkg, PKG_ANNOTATIONS) > 0) {
				if (print_tag)
					printf("%-15s:\n", "Annotations");
				if (quiet)
					pkg_printf("%A%{%-15An: %Av\n%|%}", pkg);
				else
					pkg_printf("%A%{\t%-15An: %Av\n%|%}", pkg);					
			}
			break;
		case INFO_FLATSIZE:
			if (print_tag)
				printf("%-15s: ", "Flat size");
			pkg_printf("%#sB\n", pkg);
			break;
		case INFO_PKGSIZE: /* Remote pkgs only */
			if (pkg_type(pkg) == PKG_REMOTE) {
				humanize_number(size, sizeof(size),
						pkgsize,"B",
						HN_AUTOSCALE, 0);
				if (print_tag)
					printf("%-15s: ", "Pkg size");
				printf("%s\n", size);
			} else if (!print_tag)
				printf("\n");
			break;
		case INFO_DESCR:
			if (print_tag)
				printf("%-15s:\n", "Description");
			pkg_printf("%e\n", pkg);
			break;
		case INFO_MESSAGE:
			if (print_tag)
				printf("%-15s:\n", "Message");
			if (pkg_has_message(pkg))
				pkg_printf("%M\n", pkg);
			break;
		case INFO_DEPS:
			if (pkg_list_count(pkg, PKG_DEPS) > 0) {
				if (print_tag)
					printf("%-15s:\n", "Depends on");
				if (quiet) {
					if (show_locks) 
						pkg_printf("%d%{%dn-%dv%#dk\n%|%}", pkg);
					else
						pkg_printf("%d%{%dn-%dv\n%|%}", pkg);
				} else {
					if (show_locks)
						pkg_printf("%d%{\t%dn-%dv%#dk\n%|%}", pkg);
					else
						pkg_printf("%d%{\t%dn-%dv\n%|%}", pkg);
				}
			}
			break;
		case INFO_RDEPS:
			if (pkg_list_count(pkg, PKG_RDEPS) > 0) {
				if (print_tag)
					printf("%-15s:\n", "Required by");
				if (quiet) {
					if (show_locks) 
						pkg_printf("%r%{%rn-%rv%#rk\n%|%}", pkg);
					else
						pkg_printf("%r%{%rn-%rv\n%|%}", pkg);
				} else {
					if (show_locks)
						pkg_printf("%r%{\t%rn-%rv%#rk\n%|%}", pkg);
					else
						pkg_printf("%r%{\t%rn-%rv\n%|%}", pkg);
				}
			}
			break;
		case INFO_FILES: /* Installed pkgs only */
			if (pkg_type(pkg) != PKG_REMOTE &&
			    pkg_list_count(pkg, PKG_FILES) > 0) {
				if (print_tag)
					printf("%-15s:\n", "Files");
				if (quiet)
					pkg_printf("%F%{%Fn\n%|%}", pkg);
				else
					pkg_printf("%F%{\t%Fn\n%|%}", pkg);
			}
			break;
		case INFO_DIRS:	/* Installed pkgs only */
			if (pkg_type(pkg) != PKG_REMOTE &&
			    pkg_list_count(pkg, PKG_DIRS) > 0) {
				if (print_tag)
					printf("%-15s:\n", "Directories");
				if (quiet)
					pkg_printf("%D%{%Dn\n%|%}", pkg);
				else
					pkg_printf("%D%{\t%Dn\n%|%}", pkg);
			}
			break;
		case INFO_USERS: /* Installed pkgs only */
			if (pkg_type(pkg) != PKG_REMOTE &&
			    pkg_list_count(pkg, PKG_USERS) > 0) {
				if (print_tag)
					printf("%-15s: ", "Users");
				pkg_printf("%U%{%Un%| %}\n", pkg);
			}
			break;
		case INFO_GROUPS: /* Installed pkgs only */
			if (pkg_type(pkg) != PKG_REMOTE &&
			    pkg_list_count(pkg, PKG_GROUPS) > 0) {
				if (print_tag)
					printf("%-15s: ", "Groups");
				pkg_printf("%G%{%Gn%| %}\n", pkg);
			}
			break;
		case INFO_ARCH:
			if (print_tag)
				printf("%-15s: ", "Architecture");
			pkg_printf("%q\n", pkg);
			break;
		case INFO_REPOURL:
			if (pkg_type(pkg) == PKG_REMOTE &&
			    repourl != NULL && repourl[0] != '\0') {
				if (print_tag)
					printf("%-15s: ", "Pkg URL");
				if (repourl[strlen(repourl) -1] == '/')
					pkg_printf("%S%R\n", repourl, pkg);
				else
					pkg_printf("%S/%R\n", repourl, pkg);
			} else if (!print_tag)
				printf("\n");
			break;
		case INFO_LOCKED:
			if (print_tag)
				printf("%-15s: ", "Locked");
			pkg_printf("%?k\n", pkg);
			break;
		}
	}
}
예제 #3
0
파일: pkg_repo.c 프로젝트: yerenkow/pkg
int
pkg_create_repo(char *path, bool force, bool filelist,
		void (progress)(struct pkg *pkg, void *data), void *data)
{
	FTS *fts = NULL;
	struct thd_data thd_data;
	int num_workers;
	size_t len;
	pthread_t *tids = NULL;
	struct digest_list_entry *dlist = NULL, *cur_dig, *dtmp;
	sqlite3 *sqlite = NULL;

	char *errmsg = NULL;
	int retcode = EPKG_OK;

	char *repopath[2];
	char repodb[MAXPATHLEN + 1];
	char repopack[MAXPATHLEN + 1];
	char *manifest_digest;
	FILE *psyml, *fsyml, *mandigests;

	psyml = fsyml = mandigests = NULL;

	if (!is_dir(path)) {
		pkg_emit_error("%s is not a directory", path);
		return (EPKG_FATAL);
	}

	repopath[0] = path;
	repopath[1] = NULL;

	len = sizeof(num_workers);
	if (sysctlbyname("hw.ncpu", &num_workers, &len, NULL, 0) == -1)
		num_workers = 6;

	if ((fts = fts_open(repopath, FTS_PHYSICAL|FTS_NOCHDIR, NULL)) == NULL) {
		pkg_emit_errno("fts_open", path);
		retcode = EPKG_FATAL;
		goto cleanup;
	}

	snprintf(repodb, sizeof(repodb), "%s/%s", path, repo_packagesite_file);
	if ((psyml = fopen(repodb, "w")) == NULL) {
		retcode = EPKG_FATAL;
		goto cleanup;
	}
	if (filelist) {
		snprintf(repodb, sizeof(repodb), "%s/%s", path, repo_filesite_file);
		if ((fsyml = fopen(repodb, "w")) == NULL) {
			retcode = EPKG_FATAL;
			goto cleanup;
		}
	}
	snprintf(repodb, sizeof(repodb), "%s/%s", path, repo_digests_file);
	if ((mandigests = fopen(repodb, "w")) == NULL) {
		retcode = EPKG_FATAL;
		goto cleanup;
	}

	snprintf(repodb, sizeof(repodb), "%s/%s", path, repo_db_file);
	snprintf(repopack, sizeof(repopack), "%s/repo.txz", path);

	pack_extract(repopack, repo_db_file, repodb);

	if ((retcode = pkgdb_repo_open(repodb, force, &sqlite, true)) != EPKG_OK)
		goto cleanup;

	if ((retcode = pkgdb_repo_init(sqlite, true)) != EPKG_OK)
		goto cleanup;

	thd_data.root_path = path;
	thd_data.max_results = num_workers;
	thd_data.num_results = 0;
	thd_data.stop = false;
	thd_data.fts = fts;
	thd_data.read_files = filelist;
	pthread_mutex_init(&thd_data.fts_m, NULL);
	thd_data.results = NULL;
	thd_data.thd_finished = 0;
	pthread_mutex_init(&thd_data.results_m, NULL);
	pthread_cond_init(&thd_data.has_result, NULL);
	pthread_cond_init(&thd_data.has_room, NULL);

	/* Launch workers */
	tids = calloc(num_workers, sizeof(pthread_t));
	for (int i = 0; i < num_workers; i++) {
		pthread_create(&tids[i], NULL, (void *)&read_pkg_file, &thd_data);
	}

	for (;;) {
		struct pkg_result *r;
		const char *origin;

		long manifest_pos, files_pos;

		pthread_mutex_lock(&thd_data.results_m);
		while ((r = thd_data.results) == NULL) {
			if (thd_data.thd_finished == num_workers) {
				break;
			}
			pthread_cond_wait(&thd_data.has_result, &thd_data.results_m);
		}
		if (r != NULL) {
			LL_DELETE(thd_data.results, thd_data.results);
			thd_data.num_results--;
			pthread_cond_signal(&thd_data.has_room);
		}
		pthread_mutex_unlock(&thd_data.results_m);
		if (r == NULL) {
			break;
		}

		if (r->retcode != EPKG_OK) {
			continue;
		}

		/* do not add if package if already in repodb
		   (possibly at a different pkg_path) */

		retcode = pkgdb_repo_cksum_exists(sqlite, r->cksum);
		if (retcode == EPKG_FATAL) {
			goto cleanup;
		}
		else if (retcode == EPKG_OK) {
			continue;
		}

		if (progress != NULL)
			progress(r->pkg, data);

		manifest_pos = ftell(psyml);
		pkg_emit_manifest_file(r->pkg, psyml, PKG_MANIFEST_EMIT_COMPACT, &manifest_digest);
		if (filelist) {
			files_pos = ftell(fsyml);
			pkg_emit_filelist(r->pkg, fsyml);
		} else {
			files_pos = 0;
		}

		pkg_get(r->pkg, PKG_ORIGIN, &origin);

		cur_dig = malloc(sizeof (struct digest_list_entry));
		cur_dig->origin = strdup(origin);
		cur_dig->digest = manifest_digest;
		cur_dig->manifest_pos = manifest_pos;
		cur_dig->files_pos = files_pos;
		LL_PREPEND(dlist, cur_dig);

		retcode = pkgdb_repo_add_package(r->pkg, r->path, sqlite,
				manifest_digest, false, true);
		if (retcode == EPKG_END) {
			continue;
		}
		else if (retcode != EPKG_OK) {
			goto cleanup;
		}

		pkg_free(r->pkg);
		free(r);
	}

	/* Now sort all digests */
	LL_SORT(dlist, digest_sort_compare_func);
cleanup:
	if (pkgdb_repo_close(sqlite, retcode == EPKG_OK) != EPKG_OK) {
		retcode = EPKG_FATAL;
	}
	LL_FOREACH_SAFE(dlist, cur_dig, dtmp) {
		if (retcode == EPKG_OK) {
			fprintf(mandigests, "%s:%s:%ld:%ld\n", cur_dig->origin,
				cur_dig->digest, cur_dig->manifest_pos, cur_dig->files_pos);
		}
		free(cur_dig->digest);
		free(cur_dig->origin);
		free(cur_dig);
	}
	if (tids != NULL) {
		// Cancel running threads
		if (retcode != EPKG_OK) {
			pthread_mutex_lock(&thd_data.fts_m);
			thd_data.stop = true;
			pthread_mutex_unlock(&thd_data.fts_m);
		}
		// Join on threads to release thread IDs
		for (int i = 0; i < num_workers; i++) {
			pthread_join(tids[i], NULL);
		}
		free(tids);
	}

	if (fts != NULL)
		fts_close(fts);

	if (fsyml != NULL)
		fclose(fsyml);

	if (psyml != NULL)
		fclose(psyml);

	if (mandigests != NULL)
		fclose(mandigests);

	if (sqlite != NULL)
		sqlite3_close(sqlite);

	if (errmsg != NULL)
		sqlite3_free(errmsg);

	sqlite3_shutdown();

	return (retcode);
}