diff options
Diffstat (limited to 'src/util')
-rw-r--r-- | src/util/.gitignore | 15 | ||||
-rw-r--r-- | src/util/Makefile.am | 5 | ||||
-rw-r--r-- | src/util/cleanupdelta.c | 16 | ||||
-rw-r--r-- | src/util/pactree.c | 372 | ||||
-rw-r--r-- | src/util/testdb.c | 79 | ||||
-rw-r--r-- | src/util/testpkg.c | 4 | ||||
-rw-r--r-- | src/util/vercmp.c | 34 |
7 files changed, 439 insertions, 86 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..36a4e072 100644 --- a/src/util/cleanupdelta.c +++ b/src/util/cleanupdelta.c @@ -1,7 +1,7 @@ /* * cleanupdelta.c : return list of unused delta in a given sync database * - * Copyright (c) 2010 Pacman Development Team <pacman-dev@archlinux.org> + * Copyright (c) 2011 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 @@ -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> @@ -35,7 +37,7 @@ static void cleanup(int signum) { exit(signum); } -void output_cb(pmloglevel_t level, char *fmt, va_list args) +static void output_cb(pmloglevel_t level, char *fmt, va_list args) { if(strlen(fmt)) { switch(level) { @@ -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; @@ -77,19 +79,19 @@ void checkdbs(char *dbpath, alpm_list_t *dbnames) { alpm_strerrorlast()); return; } - checkpkgs(alpm_db_get_pkgcache(db)); + checkpkgs(alpm_db_get_pkgcache_list(db)); } } -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..947ed61c --- /dev/null +++ b/src/util/pactree.c @@ -0,0 +1,372 @@ +/* + * pactree.c - a simple dependency tree viewer + * + * Copyright (c) 2010-2011 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_option_get_localdb(); + 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 = (int)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_list(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_list(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..124a66dd 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()); @@ -43,7 +39,7 @@ static void cleanup(int signum) { exit(signum); } -void output_cb(pmloglevel_t level, char *fmt, va_list args) +static void output_cb(pmloglevel_t level, char *fmt, va_list args) { if(strlen(fmt)) { switch(level) { @@ -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,44 +126,35 @@ 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); } - db = alpm_db_register_local(); + db = alpm_option_get_localdb(); if(db == NULL) { fprintf(stderr, "error: could not register 'local' database (%s)\n", alpm_strerrorlast()); cleanup(EXIT_FAILURE); } - pkglist = alpm_db_get_pkgcache(db); + pkglist = alpm_db_get_pkgcache_list(db); ret += checkdeps(pkglist); ret += checkconflicts(pkglist); 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", @@ -180,7 +162,7 @@ int check_syncdbs(char *dbpath, alpm_list_t *dbnames) { ret = 1; goto cleanup; } - pkglist = alpm_db_get_pkgcache(db); + pkglist = alpm_db_get_pkgcache_list(db); syncpkglist = alpm_list_join(syncpkglist, alpm_list_copy(pkglist)); } ret += checkdeps(syncpkglist); @@ -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..0dd8db8f 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 */ @@ -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..adb5a42a 100644 --- a/src/util/vercmp.c +++ b/src/util/vercmp.c @@ -1,7 +1,7 @@ /* * vercmp.c * - * Copyright (c) 2006-2010 Pacman Development Team <pacman-dev@archlinux.org> + * Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org> * Copyright (c) 2002-2005 by Judd Vinet <jvinet@zeroflux.org> * * This program is free software; you can redistribute it and/or modify @@ -18,23 +18,20 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include "config.h" - +#include <stdlib.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 */ +/* forward declaration, comes from version.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"); + fprintf(stderr, "output values:\n"); fprintf(stderr, " < 0 : if ver1 < ver2\n"); fprintf(stderr, " 0 : if ver1 == ver2\n"); fprintf(stderr, " > 0 : if ver1 > ver2\n"); @@ -42,8 +39,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,19 +53,14 @@ 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); printf("%d\n", ret); - return(ret); + return(EXIT_SUCCESS); } |