summaryrefslogtreecommitdiffstats
path: root/src/util
diff options
context:
space:
mode:
Diffstat (limited to 'src/util')
-rw-r--r--src/util/.gitignore15
-rw-r--r--src/util/Makefile.am5
-rw-r--r--src/util/cleanupdelta.c10
-rw-r--r--src/util/pactree.c372
-rw-r--r--src/util/testdb.c71
-rw-r--r--src/util/testpkg.c6
-rw-r--r--src/util/vercmp.c23
7 files changed, 427 insertions, 75 deletions
diff --git a/src/util/.gitignore b/src/util/.gitignore
index 9c855dff..2880ce2a 100644
--- a/src/util/.gitignore
+++ b/src/util/.gitignore
@@ -1,11 +1,12 @@
.deps
.libs
-vercmp
-vercmp.exe
-testpkg
-testpkg.exe
-testdb
-testdb.exe
cleanupdelta
cleanupdelta.exe
-
+pactree
+pactree.exe
+testdb
+testdb.exe
+testpkg
+testpkg.exe
+vercmp
+vercmp.exe
diff --git a/src/util/Makefile.am b/src/util/Makefile.am
index 7dce9dcc..30a2ee35 100644
--- a/src/util/Makefile.am
+++ b/src/util/Makefile.am
@@ -3,7 +3,7 @@ conffile = ${sysconfdir}/pacman.conf
dbpath = ${localstatedir}/lib/pacman/
cachedir = ${localstatedir}/cache/pacman/pkg/
-bin_PROGRAMS = vercmp testpkg testdb cleanupdelta
+bin_PROGRAMS = vercmp testpkg testdb cleanupdelta pactree
DEFS = -DLOCALEDIR=\"@localedir@\" \
-DCONFFILE=\"$(conffile)\" \
@@ -27,5 +27,8 @@ testdb_LDADD = $(top_builddir)/lib/libalpm/.libs/libalpm.la
cleanupdelta_SOURCES = cleanupdelta.c
cleanupdelta_LDADD = $(top_builddir)/lib/libalpm/.libs/libalpm.la
+pactree_SOURCES = pactree.c
+pactree_LDADD = $(top_builddir)/lib/libalpm/.libs/libalpm.la
+
# vim:set ts=2 sw=2 noet:
diff --git a/src/util/cleanupdelta.c b/src/util/cleanupdelta.c
index ffcfaba5..20102824 100644
--- a/src/util/cleanupdelta.c
+++ b/src/util/cleanupdelta.c
@@ -17,6 +17,8 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#include "config.h"
+
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -49,7 +51,7 @@ void output_cb(pmloglevel_t level, char *fmt, va_list args)
}
-void checkpkgs(alpm_list_t *pkglist)
+static void checkpkgs(alpm_list_t *pkglist)
{
alpm_list_t *i, *j;
for(i = pkglist; i; i = alpm_list_next(i)) {
@@ -63,7 +65,7 @@ void checkpkgs(alpm_list_t *pkglist)
}
}
-void checkdbs(char *dbpath, alpm_list_t *dbnames) {
+static void checkdbs(char *dbpath, alpm_list_t *dbnames) {
char syncdbpath[PATH_MAX];
pmdb_t *db = NULL;
alpm_list_t *i;
@@ -82,14 +84,14 @@ void checkdbs(char *dbpath, alpm_list_t *dbnames) {
}
-void usage() {
+static void usage(void) {
fprintf(stderr, "usage:\n");
fprintf(stderr,
"\t%s [-b <pacman db>] core extra ... : check the listed sync databases\n", BASENAME);
exit(1);
}
-int main(int argc, char **argv)
+int main(int argc, char *argv[])
{
char *dbpath = DBPATH;
int a = 1;
diff --git a/src/util/pactree.c b/src/util/pactree.c
new file mode 100644
index 00000000..967f5c8c
--- /dev/null
+++ b/src/util/pactree.c
@@ -0,0 +1,372 @@
+/*
+ * pactree.c - a simple dependency tree viewer
+ *
+ * Copyright (c) 2010 Pacman Development Team <pacman-dev@archlinux.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include <getopt.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <alpm.h>
+#include <alpm_list.h>
+
+/* output */
+char *provides = " provides";
+char *unresolvable = " [unresolvable]";
+char *branch_tip1 = "|--";
+char *branch_tip2 = "+--";
+int indent_size = 3;
+
+/* color */
+char *branch1_color = "\033[0;33m"; /* yellow */
+char *branch2_color = "\033[0;37m"; /* white */
+char *leaf1_color = "\033[1;32m"; /* bold green */
+char *leaf2_color = "\033[0;32m"; /* green */
+char *color_off = "\033[0m";
+
+/* globals */
+pmdb_t *db_local;
+alpm_list_t *walked = NULL;
+alpm_list_t *provisions = NULL;
+
+/* options */
+int color = 0;
+int graphviz = 0;
+int linear = 0;
+int max_depth = -1;
+int reverse = 0;
+int unique = 0;
+char *dbpath = NULL;
+
+static int alpm_local_init(void)
+{
+ int ret;
+
+ ret = alpm_initialize();
+ if(ret != 0) {
+ return(ret);
+ }
+
+ ret = alpm_option_set_root(ROOTDIR);
+ if(ret != 0) {
+ return(ret);
+ }
+
+ if(dbpath) {
+ ret = alpm_option_set_dbpath(dbpath);
+ } else {
+ ret = alpm_option_set_dbpath(DBPATH);
+ }
+ if(ret != 0) {
+ return(ret);
+ }
+
+ db_local = alpm_db_register_local();
+ if(!db_local) {
+ return(1);
+ }
+
+ return(0);
+}
+
+static int parse_options(int argc, char *argv[])
+{
+ int opt, option_index = 0;
+ char *endptr = NULL;
+
+ static struct option opts[] = {
+ {"dbpath", required_argument, 0, 'b'},
+ {"color", no_argument, 0, 'c'},
+ {"depth", required_argument, 0, 'd'},
+ {"graph", no_argument, 0, 'g'},
+ {"help", no_argument, 0, 'h'},
+ {"linear", no_argument, 0, 'l'},
+ {"reverse", no_argument, 0, 'r'},
+ {"unique", no_argument, 0, 'u'},
+ {0, 0, 0, 0}
+ };
+
+ while((opt = getopt_long(argc, argv, "b:cd:ghlru", opts, &option_index))) {
+ if(opt < 0) {
+ break;
+ }
+
+ switch(opt) {
+ case 'b':
+ dbpath = strdup(optarg);
+ break;
+ case 'c':
+ color = 1;
+ break;
+ case 'd':
+ /* validate depth */
+ max_depth = strtol(optarg, &endptr, 10);
+ if(*endptr != '\0') {
+ fprintf(stderr, "error: invalid depth -- %s\n", optarg);
+ return 1;
+ }
+ break;
+ case 'g':
+ graphviz = 1;
+ break;
+ case 'l':
+ linear = 1;
+ break;
+ case 'r':
+ reverse = 1;
+ break;
+ case 'u':
+ unique = linear = 1;
+ break;
+ case 'h':
+ case '?':
+ default:
+ return(1);
+ }
+ }
+
+ if(!argv[optind]) {
+ return(1);
+ }
+
+ if(!color) {
+ branch1_color = "";
+ branch2_color = "";
+ leaf1_color = "";
+ leaf2_color = "";
+ color_off = "";
+ }
+ if(linear) {
+ provides = "";
+ branch_tip1 = "";
+ branch_tip2 = "";
+ indent_size = 0;
+ }
+
+ return(0);
+}
+
+static void usage(void)
+{
+ fprintf(stderr, "pactree v" PACKAGE_VERSION "\n"
+ "Usage: pactree [options] PACKAGE\n\n"
+ " -b, --dbpath <path> set an alternate database location\n"
+ " -c, --color colorize output\n"
+ " -d, --depth <#> limit the depth of recursion\n"
+ " -g, --graph generate output for graphviz's dot\n"
+ " -l, --linear enable linear output\n"
+ " -r, --reverse show reverse dependencies\n"
+ " -u, --unique show dependencies with no duplicates (implies -l)\n\n"
+ " -h, --help display this help message\n");
+}
+
+static void cleanup(void)
+{
+ if(dbpath) {
+ free(dbpath);
+ }
+
+ alpm_list_free(walked);
+ alpm_list_free(provisions);
+ alpm_release();
+}
+
+/* pkg provides provision */
+static void print_text(const char *pkg, const char *provision, int depth)
+{
+ int indent_sz = (depth + 1) * indent_size;
+
+ if(!pkg && !provision) {
+ /* not much we can do */
+ return;
+ }
+
+ if(!pkg && provision) {
+ /* we failed to resolve provision */
+ printf("%s%*s%s%s%s%s%s\n", branch1_color, indent_sz, branch_tip1,
+ leaf1_color, provision, branch1_color, unresolvable, color_off);
+ } else if(provision && strcmp(pkg, provision) != 0) {
+ /* pkg provides provision */
+ printf("%s%*s%s%s%s%s %s%s%s\n", branch2_color, indent_sz, branch_tip2,
+ leaf1_color, pkg, leaf2_color, provides, leaf1_color, provision,
+ color_off);
+ } else {
+ /* pkg is a normal package */
+ printf("%s%*s%s%s%s\n", branch1_color, indent_sz, branch_tip1, leaf1_color,
+ pkg, color_off);
+ }
+}
+
+static void print_graph(const char *parentname, const char *pkgname, const char *depname)
+{
+ if(depname) {
+ printf("\"%s\" -> \"%s\" [color=chocolate4];\n", parentname, depname);
+ if(pkgname && strcmp(depname, pkgname) != 0 && !alpm_list_find_str(provisions, depname)) {
+ printf("\"%s\" -> \"%s\" [arrowhead=none, color=grey];\n", depname, pkgname);
+ provisions = alpm_list_add(provisions, (char *)depname);
+ }
+ } else if(pkgname) {
+ printf("\"%s\" -> \"%s\" [color=chocolate4];\n", parentname, pkgname);
+ }
+}
+
+/* parent depends on dep which is satisfied by pkg */
+static void print(const char *parentname, const char *pkgname, const char *depname, int depth)
+{
+ if(graphviz) {
+ print_graph(parentname, pkgname, depname);
+ } else {
+ print_text(pkgname, depname, depth);
+ }
+}
+
+static void print_start(const char *pkgname, const char *provname)
+{
+ if(graphviz) {
+ printf("digraph G { START [color=red, style=filled];\n"
+ "node [style=filled, color=green];\n"
+ " \"START\" -> \"%s\";\n", pkgname);
+ } else {
+ print_text(pkgname, provname, 0);
+ }
+}
+
+static void print_end(void)
+{
+ if(graphviz) {
+ /* close graph output */
+ printf("}\n");
+ }
+}
+
+
+/**
+ * walk dependencies in reverse, showing packages which require the target
+ */
+static void walk_reverse_deps(pmpkg_t *pkg, int depth)
+{
+ alpm_list_t *required_by, *i;
+
+ if((max_depth >= 0) && (depth == max_depth + 1)) {
+ return;
+ }
+
+ walked = alpm_list_add(walked, (void*)alpm_pkg_get_name(pkg));
+ required_by = alpm_pkg_compute_requiredby(pkg);
+
+ for(i = required_by; i; i = alpm_list_next(i)) {
+ const char *pkgname = alpm_list_getdata(i);
+
+ if(alpm_list_find_str(walked, pkgname)) {
+ /* if we've already seen this package, don't print in "unique" output
+ * and don't recurse */
+ if(!unique) {
+ print(alpm_pkg_get_name(pkg), pkgname, NULL, depth);
+ }
+ } else {
+ print(alpm_pkg_get_name(pkg), pkgname, NULL, depth);
+ walk_reverse_deps(alpm_db_get_pkg(db_local, pkgname), depth + 1);
+ }
+ }
+
+ FREELIST(required_by);
+}
+
+/**
+ * walk dependencies, showing dependencies of the target
+ */
+static void walk_deps(pmpkg_t *pkg, int depth)
+{
+ alpm_list_t *i;
+
+ if((max_depth >= 0) && (depth == max_depth + 1)) {
+ return;
+ }
+
+ walked = alpm_list_add(walked, (void*)alpm_pkg_get_name(pkg));
+
+ for(i = alpm_pkg_get_depends(pkg); i; i = alpm_list_next(i)) {
+ pmdepend_t *depend = alpm_list_getdata(i);
+ pmpkg_t *provider = alpm_find_satisfier(alpm_db_get_pkgcache(db_local),
+ alpm_dep_get_name(depend));
+
+ if(provider) {
+ const char *provname = alpm_pkg_get_name(provider);
+
+ if(alpm_list_find_str(walked, provname)) {
+ /* if we've already seen this package, don't print in "unique" output
+ * and don't recurse */
+ if(!unique) {
+ print(alpm_pkg_get_name(pkg), provname, alpm_dep_get_name(depend), depth);
+ }
+ } else {
+ print(alpm_pkg_get_name(pkg), provname, alpm_dep_get_name(depend), depth);
+ walk_deps(provider, depth + 1);
+ }
+ } else {
+ /* unresolvable package */
+ print(alpm_pkg_get_name(pkg), NULL, alpm_dep_get_name(depend), depth);
+ }
+ }
+}
+
+int main(int argc, char *argv[])
+{
+ int ret;
+ const char *target_name;
+ pmpkg_t *pkg;
+
+ ret = parse_options(argc, argv);
+ if(ret != 0) {
+ usage();
+ goto finish;
+ }
+
+ ret = alpm_local_init();
+ if(ret != 0) {
+ fprintf(stderr, "error: cannot initialize alpm: %s\n", alpm_strerrorlast());
+ goto finish;
+ }
+
+ /* we only care about the first non option arg for walking */
+ target_name = argv[optind];
+
+ pkg = alpm_find_satisfier(alpm_db_get_pkgcache(db_local), target_name);
+ if(!pkg) {
+ fprintf(stderr, "error: package '%s' not found\n", target_name);
+ ret = 1;
+ goto finish;
+ }
+
+ print_start(alpm_pkg_get_name(pkg), target_name);
+
+ if(reverse) {
+ walk_reverse_deps(pkg, 1);
+ } else {
+ walk_deps(pkg, 1);
+ }
+
+ print_end();
+
+finish:
+ cleanup();
+ return(ret);
+}
+
+/* vim: set ts=2 sw=2 noet: */
diff --git a/src/util/testdb.c b/src/util/testdb.c
index 6d351ebd..332224e1 100644
--- a/src/util/testdb.c
+++ b/src/util/testdb.c
@@ -17,11 +17,12 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#include "config.h"
+
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
-#include <limits.h>
#include <string.h>
#include <dirent.h>
@@ -30,11 +31,6 @@
#define BASENAME "testdb"
-int str_cmp(const void *s1, const void *s2)
-{
- return(strcmp(s1, s2));
-}
-
static void cleanup(int signum) {
if(alpm_release() == -1) {
fprintf(stderr, "error releasing alpm: %s\n", alpm_strerrorlast());
@@ -55,42 +51,37 @@ void output_cb(pmloglevel_t level, char *fmt, va_list args)
}
}
-static int db_test(char *dbpath, int local)
+static int check_localdb_files(void)
{
struct dirent *ent;
- char path[PATH_MAX];
+ const char *dbpath;
+ char path[4096];
int ret = 0;
-
DIR *dir;
- if(!(dir = opendir(dbpath))) {
- fprintf(stderr, "error : %s : %s\n", dbpath, strerror(errno));
+ dbpath = alpm_option_get_dbpath();
+ snprintf(path, sizeof(path), "%slocal", dbpath);
+ if(!(dir = opendir(path))) {
+ fprintf(stderr, "error : %s : %s\n", path, strerror(errno));
return(1);
}
while ((ent = readdir(dir)) != NULL) {
- if(!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, "..")
+ if(strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0
|| ent->d_name[0] == '.') {
continue;
}
- /* check for desc, depends, and files */
- snprintf(path, PATH_MAX, "%s/%s/desc", dbpath, ent->d_name);
+ /* check for known db files in local database */
+ snprintf(path, sizeof(path), "%slocal/%s/desc", dbpath, ent->d_name);
if(access(path, F_OK)) {
printf("%s: description file is missing\n", ent->d_name);
ret++;
}
- snprintf(path, PATH_MAX, "%s/%s/depends", dbpath, ent->d_name);
+ snprintf(path, sizeof(path), "%slocal/%s/files", dbpath, ent->d_name);
if(access(path, F_OK)) {
- printf("%s: dependency file is missing\n", ent->d_name);
+ printf("%s: file list is missing\n", ent->d_name);
ret++;
}
- if(local) {
- snprintf(path, PATH_MAX, "%s/%s/files", dbpath, ent->d_name);
- if(access(path, F_OK)) {
- printf("%s: file list is missing\n", ent->d_name);
- ret++;
- }
- }
}
if(closedir(dir)) {
fprintf(stderr, "error closing dbpath : %s\n", strerror(errno));
@@ -100,7 +91,7 @@ static int db_test(char *dbpath, int local)
return(ret);
}
-int checkdeps(alpm_list_t *pkglist)
+static int checkdeps(alpm_list_t *pkglist)
{
alpm_list_t *data, *i;
int ret = 0;
@@ -119,7 +110,7 @@ int checkdeps(alpm_list_t *pkglist)
return(ret);
}
-int checkconflicts(alpm_list_t *pkglist)
+static int checkconflicts(alpm_list_t *pkglist)
{
alpm_list_t *data, *i;
int ret = 0;
@@ -135,14 +126,12 @@ int checkconflicts(alpm_list_t *pkglist)
return(ret);
}
-int check_localdb(char *dbpath) {
- char localdbpath[PATH_MAX];
+static int check_localdb(void) {
int ret = 0;
pmdb_t *db = NULL;
alpm_list_t *pkglist;
- snprintf(localdbpath, PATH_MAX, "%s/local", dbpath);
- ret = db_test(localdbpath, 1);
+ ret = check_localdb_files();
if(ret) {
return(ret);
}
@@ -159,20 +148,13 @@ int check_localdb(char *dbpath) {
return(ret);
}
-int check_syncdbs(char *dbpath, alpm_list_t *dbnames) {
- char syncdbpath[PATH_MAX];
+static int check_syncdbs(alpm_list_t *dbnames) {
int ret = 0;
pmdb_t *db = NULL;
alpm_list_t *i, *pkglist, *syncpkglist = NULL;
for(i = dbnames; i; i = alpm_list_next(i)) {
char *dbname = alpm_list_getdata(i);
- snprintf(syncdbpath, PATH_MAX, "%s/sync/%s", dbpath, dbname);
- ret = db_test(syncdbpath, 0);
- if(ret) {
- ret = 1;
- goto cleanup;
- }
db = alpm_db_register_sync(dbname);
if(db == NULL) {
fprintf(stderr, "error: could not register sync database (%s)\n",
@@ -190,7 +172,7 @@ cleanup:
return(ret);
}
-void usage() {
+static void usage(void) {
fprintf(stderr, "usage:\n");
fprintf(stderr,
"\t%s [-b <pacman db>] : check the local database\n", BASENAME);
@@ -199,7 +181,7 @@ void usage() {
exit(1);
}
-int main(int argc, char **argv)
+int main(int argc, char *argv[])
{
int ret = 0;
char *dbpath = DBPATH;
@@ -224,18 +206,21 @@ int main(int argc, char **argv)
if(alpm_initialize() == -1) {
fprintf(stderr, "cannot initialize alpm: %s\n", alpm_strerrorlast());
- return(1);
+ return(EXIT_FAILURE);
}
/* let us get log messages from libalpm */
alpm_option_set_logcb(output_cb);
- alpm_option_set_dbpath(dbpath);
+ if(alpm_option_set_dbpath(dbpath) != 0) {
+ fprintf(stderr, "cannot set dbpath: %s\n", alpm_strerrorlast());
+ return(EXIT_FAILURE);
+ }
if(!dbnames) {
- ret = check_localdb(dbpath);
+ ret = check_localdb();
} else {
- ret = check_syncdbs(dbpath,dbnames);
+ ret = check_syncdbs(dbnames);
alpm_list_free(dbnames);
}
diff --git a/src/util/testpkg.c b/src/util/testpkg.c
index d86fb1e0..6fc0ce00 100644
--- a/src/util/testpkg.c
+++ b/src/util/testpkg.c
@@ -17,8 +17,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include "config.h"
-
#include <stdio.h> /* printf */
#include <stdarg.h> /* va_list */
@@ -26,7 +24,7 @@
#define BASENAME "testpkg"
-static void output_cb(pmloglevel_t level, char *fmt, va_list args)
+void output_cb(pmloglevel_t level, char *fmt, va_list args)
{
if(fmt[0] == '\0') {
return;
@@ -39,7 +37,7 @@ static void output_cb(pmloglevel_t level, char *fmt, va_list args)
vprintf(fmt, args);
}
-int main(int argc, char **argv)
+int main(int argc, char *argv[])
{
int retval = 1; /* default = false */
pmpkg_t *pkg = NULL;
diff --git a/src/util/vercmp.c b/src/util/vercmp.c
index 959dc137..8a785bb8 100644
--- a/src/util/vercmp.c
+++ b/src/util/vercmp.c
@@ -18,20 +18,16 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include "config.h"
-
#include <stdio.h> /* printf */
#include <string.h> /* strncpy */
#define BASENAME "vercmp"
-#define MAX_LEN 255
-
/* forward declaration, comes from vercmp.o in libalpm source that is linked in
* directly so we don't have any library deps */
int alpm_pkg_vercmp(const char *a, const char *b);
-static void usage()
+static void usage(void)
{
fprintf(stderr, "usage: %s <ver1> <ver2>\n\n", BASENAME);
fprintf(stderr, "return values:\n");
@@ -42,8 +38,8 @@ static void usage()
int main(int argc, char *argv[])
{
- char s1[MAX_LEN] = "";
- char s2[MAX_LEN] = "";
+ const char *s1 = "";
+ const char *s2 = "";
int ret;
if(argc == 1) {
@@ -56,16 +52,11 @@ int main(int argc, char *argv[])
usage();
return(0);
}
- if(argc > 1) {
- strncpy(s1, argv[1], MAX_LEN);
- s1[MAX_LEN -1] = '\0';
- }
if(argc > 2) {
- strncpy(s2, argv[2], MAX_LEN);
- s2[MAX_LEN -1] = '\0';
- } else {
- printf("0\n");
- return(0);
+ s2 = argv[2];
+ }
+ if(argc > 1) {
+ s1 = argv[1];
}
ret = alpm_pkg_vercmp(s1, s2);