diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/pacman/Makefile.am | 2 | ||||
| -rw-r--r-- | src/pacman/callback.c | 109 | ||||
| -rw-r--r-- | src/pacman/callback.h | 4 | ||||
| -rw-r--r-- | src/pacman/conf.c | 2 | ||||
| -rw-r--r-- | src/pacman/conf.h | 2 | ||||
| -rw-r--r-- | src/pacman/database.c | 6 | ||||
| -rw-r--r-- | src/pacman/deptest.c | 16 | ||||
| -rw-r--r-- | src/pacman/package.c | 79 | ||||
| -rw-r--r-- | src/pacman/package.h | 2 | ||||
| -rw-r--r-- | src/pacman/pacman.c | 693 | ||||
| -rw-r--r-- | src/pacman/pacman.h | 2 | ||||
| -rw-r--r-- | src/pacman/query.c | 67 | ||||
| -rw-r--r-- | src/pacman/remove.c | 4 | ||||
| -rw-r--r-- | src/pacman/sync.c | 57 | ||||
| -rw-r--r-- | src/pacman/upgrade.c | 4 | ||||
| -rw-r--r-- | src/pacman/util.c | 90 | ||||
| -rw-r--r-- | src/pacman/util.h | 8 | ||||
| -rw-r--r-- | src/util/.gitignore | 15 | ||||
| -rw-r--r-- | src/util/Makefile.am | 5 | ||||
| -rw-r--r-- | src/util/cleanupdelta.c | 14 | ||||
| -rw-r--r-- | src/util/pactree.c | 372 | ||||
| -rw-r--r-- | src/util/testdb.c | 75 | ||||
| -rw-r--r-- | src/util/testpkg.c | 4 | ||||
| -rw-r--r-- | src/util/vercmp.c | 34 | 
24 files changed, 1164 insertions, 502 deletions
| diff --git a/src/pacman/Makefile.am b/src/pacman/Makefile.am index 8c14562c..31e8b134 100644 --- a/src/pacman/Makefile.am +++ b/src/pacman/Makefile.am @@ -18,7 +18,7 @@ INCLUDES = -I$(top_srcdir)/lib/libalpm  AM_CFLAGS = -pedantic -D_GNU_SOURCE  if USE_GIT_VERSION -GIT_VERSION := $(shell sh -c 'git describe --abbrev=4 | sed s/^v//')-dirty +GIT_VERSION := $(shell sh -c 'git describe --abbrev=4 --dirty | sed s/^v//')  DEFS += -DGIT_VERSION=\"$(GIT_VERSION)\"  endif diff --git a/src/pacman/callback.c b/src/pacman/callback.c index f5bf17d1..e3feea16 100644 --- a/src/pacman/callback.c +++ b/src/pacman/callback.c @@ -1,7 +1,7 @@  /*   *  callback.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-2006 by Judd Vinet <jvinet@zeroflux.org>   *   *  This program is free software; you can redistribute it and/or modify @@ -26,7 +26,6 @@  #include <sys/time.h>  #include <sys/types.h> /* off_t */  #include <unistd.h> -#include <dirent.h>  #include <wchar.h>  #include <alpm.h> @@ -37,7 +36,7 @@  #include "conf.h"  /* download progress bar */ -static float rate_last; +static double rate_last;  static off_t xfered_last;  static off_t list_xfered = 0.0;  static off_t list_total = 0.0; @@ -56,9 +55,9 @@ static alpm_list_t *output = NULL;   *   * first_call indicates if this is the first time it is called, for   * initialization purposes */ -static float get_update_timediff(int first_call) +static double get_update_timediff(int first_call)  { -	float retval = 0.0; +	double retval = 0.0;  	static struct timeval last_time = {0, 0};  	/* on first call, simply set the last time and return */ @@ -66,7 +65,7 @@ static float get_update_timediff(int first_call)  		gettimeofday(&last_time, NULL);  	} else {  		struct timeval this_time; -		float diff_sec, diff_usec; +		double diff_sec, diff_usec;  		gettimeofday(&this_time, NULL);  		diff_sec = this_time.tv_sec - last_time.tv_sec; @@ -79,7 +78,6 @@ static float get_update_timediff(int first_call)  			retval = 0.0;  		} else {  			last_time = this_time; -			/* printf("\nupdate retval: %f\n", retval); DEBUG*/  		}  	} @@ -163,7 +161,7 @@ void cb_trans_evt(pmtransevt_t event, void *data1, void *data2)  			break;  		case PM_TRANS_EVT_FILECONFLICTS_START:  			if(config->noprogressbar) { -			printf(_("checking for file conflicts...\n")); +				printf(_("checking for file conflicts...\n"));  			}  			break;  		case PM_TRANS_EVT_RESOLVEDEPS_START: @@ -206,7 +204,9 @@ void cb_trans_evt(pmtransevt_t event, void *data1, void *data2)  			display_new_optdepends(data2,data1);  			break;  		case PM_TRANS_EVT_INTEGRITY_START: -			printf(_("checking package integrity...\n")); +			if(config->noprogressbar) { +				printf(_("checking package integrity...\n")); +			}  			break;  		case PM_TRANS_EVT_DELTA_INTEGRITY_START:  			printf(_("checking delta integrity...\n")); @@ -229,6 +229,11 @@ void cb_trans_evt(pmtransevt_t event, void *data1, void *data2)  		case PM_TRANS_EVT_RETRIEVE_START:  			printf(_(":: Retrieving packages from %s...\n"), (char*)data1);  			break; +		case PM_TRANS_EVT_DISKSPACE_START: +			if(config->noprogressbar) { +				printf(_("checking available disk space...\n")); +			} +			break;  		/* all the simple done events, with fallthrough for each */  		case PM_TRANS_EVT_FILECONFLICTS_DONE:  		case PM_TRANS_EVT_CHECKDEPS_DONE: @@ -237,6 +242,7 @@ void cb_trans_evt(pmtransevt_t event, void *data1, void *data2)  		case PM_TRANS_EVT_INTEGRITY_DONE:  		case PM_TRANS_EVT_DELTA_INTEGRITY_DONE:  		case PM_TRANS_EVT_DELTA_PATCHES_DONE: +		case PM_TRANS_EVT_DISKSPACE_DONE:  			/* nothing */  			break;  	} @@ -262,7 +268,7 @@ void cb_trans_conv(pmtransconv_t event, void *data1, void *data2,  		case PM_TRANS_CONV_CONFLICT_PKG:  			/* data parameters: target package, local package, conflict (strings) */  			/* print conflict only if it contains new information */ -			if(!strcmp(data1, data3) || !strcmp(data2, data3)) { +			if(strcmp(data1, data3) == 0 || strcmp(data2, data3) == 0) {  				*response = noyes(_(":: %s and %s are in conflict. Remove %s?"),  						(char *)data1,  						(char *)data2, @@ -283,11 +289,16 @@ void cb_trans_conv(pmtransconv_t event, void *data1, void *data2,  					namelist = alpm_list_add(namelist,  							(char *)alpm_pkg_get_name(i->data));  				} -				printf(_(":: the following package(s) cannot be upgraded due to " -						"unresolvable dependencies:\n")); +				printf(_n( +							":: The following package cannot be upgraded due to unresolvable dependencies:\n", +							":: The following packages cannot be upgraded due to unresolvable dependencies:\n", +							alpm_list_count(namelist)));  				list_display("     ", namelist); -				*response = noyes(_("\nDo you want to skip the above " -							"package(s) for this upgrade?")); +				printf("\n"); +				*response = noyes(_n( +							"Do you want to skip the above package for this upgrade?", +							"Do you want to skip the above packages for this upgrade?", +							alpm_list_count(namelist)));  				alpm_list_free(namelist);  			}  			break; @@ -315,13 +326,12 @@ void cb_trans_conv(pmtransconv_t event, void *data1, void *data2,  /* callback to handle display of transaction progress */  void cb_trans_progress(pmtransprog_t event, const char *pkgname, int percent, -                       int howmany, int remain) +                       size_t howmany, size_t current)  { -	float timediff; -  	/* size of line to allocate for text printing (e.g. not progressbar) */  	int infolen; -	int tmp, digits, textlen; +	int digits, textlen; +	size_t tmp;  	char *opr = NULL;  	/* used for wide character width determination and printing */  	int len, wclen, wcwid, padwid; @@ -331,32 +341,24 @@ void cb_trans_progress(pmtransprog_t event, const char *pkgname, int percent,  		return;  	} -	infolen = getcols() * 6 / 10; -	if (infolen < 50) { -		infolen = 50; -	} -  	if(percent == 0) { -		timediff = get_update_timediff(1); +		get_update_timediff(1); +	} else if(percent == 100) { +		/* no need for timediff update, but unconditionally continue unless we +		 * already completed on a previous call */ +		if(prevpercent == 100) { +			return; +		}  	} else { -		timediff = get_update_timediff(0); -	} - -	if(percent > 0 && percent < 100 && !timediff) { -		/* only update the progress bar when -		 * a) we first start -		 * b) we end the progress -		 * c) it has been long enough since the last call -		 */ -		return; +		if(!pkgname || percent == prevpercent || get_update_timediff(0) < UPDATE_SPEED_SEC) { +			/* only update the progress bar when we have a package name, the +			 * percentage has changed, and it has been long enough.  */ +			return; +		}  	} -	/* if no pkgname, percent is too high or unchanged, then return */ -	if(!pkgname || percent == prevpercent) { -		return; -	} +	prevpercent = percent; -	prevpercent=percent;  	/* set text of message to display */  	switch (event) {  		case PM_TRANS_PROGRESS_ADD_START: @@ -371,10 +373,21 @@ void cb_trans_progress(pmtransprog_t event, const char *pkgname, int percent,  		case PM_TRANS_PROGRESS_CONFLICTS_START:  			opr = _("checking for file conflicts");  			break; +		case PM_TRANS_PROGRESS_DISKSPACE_START: +			opr = _("checking available disk space"); +			break; +		case PM_TRANS_PROGRESS_INTEGRITY_START: +			opr = _("checking package integrity"); +			break;  		default:  			return;  	} +	infolen = getcols() * 6 / 10; +	if (infolen < 50) { +		infolen = 50; +	} +  	/* find # of digits in package counts to scale output */  	digits = 1;  	tmp = howmany; @@ -389,7 +402,7 @@ void cb_trans_progress(pmtransprog_t event, const char *pkgname, int percent,  	 * done here to figure out the actual number of screen columns used  	 * by the output, and then pad it accordingly so we fill the terminal.  	 */ -	/* len = opr len + pkgname len (if available) + space  + null */ +	/* len = opr len + pkgname len (if available) + space + null */  	len = strlen(opr) + ((pkgname) ? strlen(pkgname) : 0) + 2;  	wcstr = calloc(len, sizeof(wchar_t));  	/* print our strings to the alloc'ed memory */ @@ -421,8 +434,8 @@ void cb_trans_progress(pmtransprog_t event, const char *pkgname, int percent,  	} -	printf("(%*d/%*d) %ls%-*s", digits, remain, digits, howmany, -			wcstr, padwid, ""); +	printf("(%*ld/%*ld) %ls%-*s", digits, (unsigned long)current, +			digits, (unsigned long)howmany, wcstr, padwid, "");  	free(wcstr); @@ -465,7 +478,7 @@ void cb_dl_progress(const char *filename, off_t file_xfered, off_t file_total)  	int totaldownload = 0;  	off_t xfered, total; -	float rate = 0.0, timediff = 0.0, f_xfered = 0.0; +	double rate = 0.0, timediff = 0.0, f_xfered = 0.0;  	unsigned int eta_h = 0, eta_m = 0, eta_s = 0;  	int file_percent = 0, total_percent = 0;  	char rate_size = 'K', xfered_size = 'K'; @@ -524,7 +537,7 @@ void cb_dl_progress(const char *filename, off_t file_xfered, off_t file_total)  	} else if(file_xfered == file_total) {  		/* compute final values */  		struct timeval current_time; -		float diff_sec, diff_usec; +		double diff_sec, diff_usec;  		gettimeofday(¤t_time, NULL);  		diff_sec = current_time.tv_sec - initial_time.tv_sec; @@ -550,11 +563,11 @@ void cb_dl_progress(const char *filename, off_t file_xfered, off_t file_total)  		xfered_last = xfered;  	} -	file_percent = (int)((float)file_xfered) / ((float)file_total) * 100; +	file_percent = (file_xfered * 100) / file_total;  	if(totaldownload) { -		total_percent = (int)((float)list_xfered + file_xfered) / -			((float)list_total) * 100; +		total_percent = ((list_xfered + file_xfered) * 100) / +			list_total;  		/* if we are at the end, add the completed file to list_xfered */  		if(file_xfered == file_total) { @@ -570,7 +583,7 @@ void cb_dl_progress(const char *filename, off_t file_xfered, off_t file_total)  	fname = strdup(filename);  	/* strip package or DB extension for cleaner look */ -	if((p = strstr(fname, ".pkg.tar.")) || (p = strstr(fname, ".db.tar."))) { +	if((p = strstr(fname, ".pkg")) || (p = strstr(fname, ".db"))) {  			*p = '\0';  	}  	/* In order to deal with characters from all locales, we have to worry diff --git a/src/pacman/callback.h b/src/pacman/callback.h index c56eaa74..f5bf1c1d 100644 --- a/src/pacman/callback.h +++ b/src/pacman/callback.h @@ -1,7 +1,7 @@  /*   *  callback.h   * - *  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-2006 by Judd Vinet <jvinet@zeroflux.org>   *   *  This program is free software; you can redistribute it and/or modify @@ -33,7 +33,7 @@ void cb_trans_conv(pmtransconv_t event, void *data1, void *data2,  /* callback to handle display of transaction progress */  void cb_trans_progress(pmtransprog_t event, const char *pkgname, int percent, -                   int howmany, int remain); +                   size_t howmany, size_t remain);  /* callback to handle receipt of total download value */  void cb_dl_total(off_t total); diff --git a/src/pacman/conf.c b/src/pacman/conf.c index 71e8dd80..e2a168ee 100644 --- a/src/pacman/conf.c +++ b/src/pacman/conf.c @@ -1,7 +1,7 @@  /*   *  conf.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-2006 by Judd Vinet <jvinet@zeroflux.org>   *   *  This program is free software; you can redistribute it and/or modify diff --git a/src/pacman/conf.h b/src/pacman/conf.h index 8b1bc2e1..ff7a9c79 100644 --- a/src/pacman/conf.h +++ b/src/pacman/conf.h @@ -1,7 +1,7 @@  /*   *  conf.h   * - *  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-2006 by Judd Vinet <jvinet@zeroflux.org>   *   *  This program is free software; you can redistribute it and/or modify diff --git a/src/pacman/database.c b/src/pacman/database.c index 9e335fe1..36433f33 100644 --- a/src/pacman/database.c +++ b/src/pacman/database.c @@ -1,7 +1,7 @@  /*   *  database.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-2006 by Judd Vinet <jvinet@zeroflux.org>   *   *  This program is free software; you can redistribute it and/or modify @@ -31,8 +31,6 @@  #include "conf.h"  #include "util.h" -extern pmdb_t *db_local; -  /**   * @brief Modify the 'local' package database.   * @@ -43,6 +41,7 @@ extern pmdb_t *db_local;  int pacman_database(alpm_list_t *targets)  {  	alpm_list_t *i; +	pmdb_t *db_local;  	int retval = 0;  	pmpkgreason_t reason; @@ -65,6 +64,7 @@ int pacman_database(alpm_list_t *targets)  		return(1);  	} +	db_local = alpm_option_get_localdb();  	for(i = targets; i; i = alpm_list_next(i)) {  		char *pkgname = i->data;  		if(alpm_db_set_pkgreason(db_local, pkgname, reason) == -1) { diff --git a/src/pacman/deptest.c b/src/pacman/deptest.c index f043c201..8895b487 100644 --- a/src/pacman/deptest.c +++ b/src/pacman/deptest.c @@ -1,7 +1,7 @@  /*   *  deptest.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-2006 by Judd Vinet <jvinet@zeroflux.org>   *   *  This program is free software; you can redistribute it and/or modify @@ -35,16 +35,24 @@  int pacman_deptest(alpm_list_t *targets)  {  	alpm_list_t *i; +	alpm_list_t *deps = NULL; +	pmdb_t *localdb = alpm_option_get_localdb(); + +	for(i = targets; i; i = alpm_list_next(i)) { +		char *target = alpm_list_getdata(i); + +		if(!alpm_find_satisfier(alpm_db_get_pkgcache(localdb), target)) { +			deps = alpm_list_add(deps, target); +		} +	} -	alpm_list_t *deps = alpm_deptest(alpm_option_get_localdb(), targets);  	if(deps == NULL) {  		return(0);  	}  	for(i = deps; i; i = alpm_list_next(i)) { -		const char *dep; +		const char *dep = alpm_list_getdata(i); -		dep = alpm_list_getdata(i);  		printf("%s\n", dep);  	}  	alpm_list_free(deps); diff --git a/src/pacman/package.c b/src/pacman/package.c index 413754c7..77a5ee72 100644 --- a/src/pacman/package.c +++ b/src/pacman/package.c @@ -1,7 +1,7 @@  /*   *  package.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-2006 by Judd Vinet <jvinet@zeroflux.org>   *   *  This program is free software; you can redistribute it and/or modify @@ -25,6 +25,7 @@  #include <string.h>  #include <unistd.h>  #include <limits.h> +#include <errno.h>  #include <wchar.h>  #include <alpm.h> @@ -106,15 +107,15 @@ void dump_pkg_full(pmpkg_t *pkg, int level)  	list_display(_("Replaces       :"), alpm_pkg_get_replaces(pkg));  	if(level < 0) {  		printf(_("Download Size  : %6.2f K\n"), -			(float)alpm_pkg_get_size(pkg) / 1024.0); +			(double)alpm_pkg_get_size(pkg) / 1024.0);  	}  	if(level == 0) {  		printf(_("Compressed Size: %6.2f K\n"), -			(float)alpm_pkg_get_size(pkg) / 1024.0); +			(double)alpm_pkg_get_size(pkg) / 1024.0);  	}  	printf(_("Installed Size : %6.2f K\n"), -			(float)alpm_pkg_get_isize(pkg) / 1024.0); +			(double)alpm_pkg_get_isize(pkg) / 1024.0);  	string_display(_("Packager       :"), alpm_pkg_get_packager(pkg));  	string_display(_("Architecture   :"), alpm_pkg_get_arch(pkg));  	string_display(_("Build Date     :"), bdatestr); @@ -157,6 +158,46 @@ void dump_pkg_sync(pmpkg_t *pkg, const char *treename, int level)  	dump_pkg_full(pkg, -level);  } +static const char *get_backup_file_status(const char *root, +		const char *filename, const char *expected_md5) +{ +	char path[PATH_MAX]; +	char *ret; + +	snprintf(path, PATH_MAX, "%s%s", root, filename); + +	/* if we find the file, calculate checksums, otherwise it is missing */ +	if(access(path, R_OK) == 0) { +		char *md5sum = alpm_compute_md5sum(path); + +		if(md5sum == NULL) { +			pm_fprintf(stderr, PM_LOG_ERROR, +					_("could not calculate checksums for %s\n"), path); +			return(NULL); +		} + +		/* if checksums don't match, file has been modified */ +		if (strcmp(md5sum, expected_md5) != 0) { +			ret = "MODIFIED"; +		} else { +			ret = "UNMODIFIED"; +		} +		free(md5sum); +	} else { +		switch(errno) { +			case EACCES: +				ret = "UNREADABLE"; +				break; +			case ENOENT: +				ret = "MISSING"; +				break; +			default: +				ret = "UNKNOWN"; +		} +	} +	return(ret); +} +  /* Display list of backup files and their modification states   */  void dump_pkg_backups(pmpkg_t *pkg) @@ -167,37 +208,17 @@ void dump_pkg_backups(pmpkg_t *pkg)  	if(alpm_pkg_get_backup(pkg)) {  		/* package has backup files, so print them */  		for(i = alpm_pkg_get_backup(pkg); i; i = alpm_list_next(i)) { -			char path[PATH_MAX]; +			const char *value;  			char *str = strdup(alpm_list_getdata(i)); -			char *ptr = index(str, '\t'); +			char *ptr = strchr(str, '\t');  			if(ptr == NULL) {  				free(str);  				continue;  			}  			*ptr = '\0';  			ptr++; -			snprintf(path, PATH_MAX-1, "%s%s", root, str); -			/* if we find the file, calculate checksums, otherwise it is missing */ -			if(access(path, R_OK) == 0) { -				char *md5sum = alpm_compute_md5sum(path); - -				if(md5sum == NULL) { -					pm_fprintf(stderr, PM_LOG_ERROR, -						_("could not calculate checksums for %s\n"), path); -					free(str); -					continue; -				} - -				/* if checksums don't match, file has been modified */ -				if (strcmp(md5sum, ptr)) { -					printf(_("MODIFIED\t%s\n"), path); -				} else { -					printf(_("Not Modified\t%s\n"), path); -				} -				free(md5sum); -			} else { -				printf(_("MISSING\t\t%s\n"), path); -			} +			value = get_backup_file_status(root, str, ptr); +			printf("%s\t%s%s\n", value, root, str);  			free(str);  		}  	} else { @@ -242,7 +263,7 @@ void dump_pkg_changelog(pmpkg_t *pkg)  	} else {  		/* allocate a buffer to get the changelog back in chunks */  		char buf[CLBUF_SIZE]; -		int ret = 0; +		size_t ret = 0;  		while((ret = alpm_pkg_changelog_read(buf, CLBUF_SIZE, pkg, fp))) {  			if(ret < CLBUF_SIZE) {  				/* if we hit the end of the file, we need to add a null terminator */ diff --git a/src/pacman/package.h b/src/pacman/package.h index 006ea1c9..26333c5a 100644 --- a/src/pacman/package.h +++ b/src/pacman/package.h @@ -1,7 +1,7 @@  /*   *  package.h   * - *  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-2006 by Judd Vinet <jvinet@zeroflux.org>   *   *  This program is free software; you can redistribute it and/or modify diff --git a/src/pacman/pacman.c b/src/pacman/pacman.c index 7fbffc36..45500cfb 100644 --- a/src/pacman/pacman.c +++ b/src/pacman/pacman.c @@ -1,7 +1,7 @@  /*   *  pacman.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-2006 by Judd Vinet <jvinet@zeroflux.org>   *   *  This program is free software; you can redistribute it and/or modify @@ -26,8 +26,10 @@  #define PACKAGE_VERSION GIT_VERSION  #endif +#include <ctype.h> /* isspace */  #include <stdlib.h> /* atoi */  #include <stdio.h> +#include <ctype.h> /* isspace */  #include <limits.h>  #include <getopt.h>  #include <string.h> @@ -55,16 +57,55 @@  #include "conf.h"  #include "package.h" -pmdb_t *db_local;  /* list of targets specified on command line */  static alpm_list_t *pm_targets; +/* Used to sort the options in --help */ +static int options_cmp(const void *p1, const void *p2) +{ +	const char *s1 = p1; +	const char *s2 = p2; + +	if(s1 == s2) return(0); +	if(!s1) return(-1); +	if(!s2) return(1); +	/* First skip all spaces in both strings */ +	while(isspace((unsigned char)*s1)) { +		s1++; +	} +	while(isspace((unsigned char)*s2)) { +		s2++; +	} +	/* If we compare a long option (--abcd) and a short one (-a), +	 * the short one always wins */ +	if(*s1 == '-' && *s2 == '-') { +		s1++; +		s2++; +		if(*s1 == '-' && *s2 == '-') { +			/* two long -> strcmp */ +			s1++; +			s2++; +		} else if(*s2 == '-') { +			/* s1 short, s2 long */ +			return(-1); +		} else if(*s1 == '-') { +			/* s1 long, s2 short */ +			return(1); +		} +		/* two short -> strcmp */ +	} + +	return(strcmp(s1, s2)); +} +  /** Display usage/syntax for the specified operation.   * @param op     the operation code requested   * @param myname basename(argv[0])   */  static void usage(int op, const char * const myname)  { +#define addlist(s) (list = alpm_list_add(list, s)) +	alpm_list_t *list = NULL, *i;  	/* prefetch some strings for usage below, which moves a lot of calls  	 * out of gettext. */  	char const * const str_opt = _("options"); @@ -89,85 +130,87 @@ static void usage(int op, const char * const myname)  		if(op == PM_OP_REMOVE) {  			printf("%s:  %s {-R --remove} [%s] <%s>\n", str_usg, myname, str_opt, str_pkg);  			printf("%s:\n", str_opt); -			printf(_("  -c, --cascade        remove packages and all packages that depend on them\n")); -			printf(_("  -d, --nodeps         skip dependency checks\n")); -			printf(_("  -k, --dbonly         only remove database entries, do not remove files\n")); -			printf(_("  -n, --nosave         remove configuration files as well\n")); -			printf(_("  -s, --recursive      remove dependencies also (that won't break packages)\n" +			addlist(_("  -c, --cascade        remove packages and all packages that depend on them\n")); +			addlist(_("  -n, --nosave         remove configuration files as well\n")); +			addlist(_("  -s, --recursive      remove dependencies also (that won't break packages)\n"  				 "                       (-ss includes explicitly installed dependencies too)\n")); -			printf(_("  -u, --unneeded       remove unneeded packages (that won't break packages)\n")); -			printf(_("      --print          only print the targets instead of performing the operation\n")); -			printf(_("      --print-format <string>\n" -			         "                       specify how the targets should be printed\n")); +			addlist(_("  -u, --unneeded       remove unneeded packages (that won't break packages)\n"));  		} else if(op == PM_OP_UPGRADE) {  			printf("%s:  %s {-U --upgrade} [%s] <%s>\n", str_usg, myname, str_opt, str_file);  			printf("%s:\n", str_opt); -			printf(_("      --asdeps         install packages as non-explicitly installed\n")); -			printf(_("      --asexplicit     install packages as explicitly installed\n")); -			printf(_("  -d, --nodeps         skip dependency checks\n")); -			printf(_("  -f, --force          force install, overwrite conflicting files\n")); -			printf(_("  -k, --dbonly         add database entries, do not install or keep existing files\n")); -			printf(_("      --print          only print the targets instead of performing the operation\n")); -			printf(_("      --print-format <string>\n" -			         "                       specify how the targets should be printed\n"));  		} else if(op == PM_OP_QUERY) {  			printf("%s:  %s {-Q --query} [%s] [%s]\n", str_usg, myname, str_opt, str_pkg);  			printf("%s:\n", str_opt); -			printf(_("  -c, --changelog      view the changelog of a package\n")); -			printf(_("  -d, --deps           list packages installed as dependencies [filter]\n")); -			printf(_("  -e, --explicit       list packages explicitly installed [filter]\n")); -			printf(_("  -g, --groups         view all members of a package group\n")); -			printf(_("  -i, --info           view package information (-ii for backup files)\n")); -			printf(_("  -k, --check          check that the files owned by the package(s) are present\n")); -			printf(_("  -l, --list           list the contents of the queried package\n")); -			printf(_("  -m, --foreign        list installed packages not found in sync db(s) [filter]\n")); -			printf(_("  -o, --owns <file>    query the package that owns <file>\n")); -			printf(_("  -p, --file <package> query a package file instead of the database\n")); -			printf(_("  -s, --search <regex> search locally-installed packages for matching strings\n")); -			printf(_("  -t, --unrequired     list packages not required by any package [filter]\n")); -			printf(_("  -u, --upgrades       list outdated packages [filter]\n")); -			printf(_("  -q, --quiet          show less information for query and search\n")); +			addlist(_("  -c, --changelog      view the changelog of a package\n")); +			addlist(_("  -d, --deps           list packages installed as dependencies [filter]\n")); +			addlist(_("  -e, --explicit       list packages explicitly installed [filter]\n")); +			addlist(_("  -g, --groups         view all members of a package group\n")); +			addlist(_("  -i, --info           view package information (-ii for backup files)\n")); +			addlist(_("  -k, --check          check that the files owned by the package(s) are present\n")); +			addlist(_("  -l, --list           list the contents of the queried package\n")); +			addlist(_("  -m, --foreign        list installed packages not found in sync db(s) [filter]\n")); +			addlist(_("  -o, --owns <file>    query the package that owns <file>\n")); +			addlist(_("  -p, --file <package> query a package file instead of the database\n")); +			addlist(_("  -q, --quiet          show less information for query and search\n")); +			addlist(_("  -s, --search <regex> search locally-installed packages for matching strings\n")); +			addlist(_("  -t, --unrequired     list packages not required by any package [filter]\n")); +			addlist(_("  -u, --upgrades       list outdated packages [filter]\n"));  		} else if(op == PM_OP_SYNC) {  			printf("%s:  %s {-S --sync} [%s] [%s]\n", str_usg, myname, str_opt, str_pkg);  			printf("%s:\n", str_opt); -			printf(_("      --asdeps         install packages as non-explicitly installed\n")); -			printf(_("      --asexplicit     install packages as explicitly installed\n")); -			printf(_("  -c, --clean          remove old packages from cache directory (-cc for all)\n")); -			printf(_("  -d, --nodeps         skip dependency checks\n")); -			printf(_("  -f, --force          force install, overwrite conflicting files\n")); -			printf(_("  -g, --groups         view all members of a package group\n")); -			printf(_("  -i, --info           view package information\n")); -			printf(_("  -l, --list <repo>    view a list of packages in a repo\n")); -			printf(_("  -s, --search <regex> search remote repositories for matching strings\n")); -			printf(_("  -u, --sysupgrade     upgrade installed packages (-uu allows downgrade)\n")); -			printf(_("  -w, --downloadonly   download packages but do not install/upgrade anything\n")); -			printf(_("  -y, --refresh        download fresh package databases from the server\n")); -			printf(_("      --needed         don't reinstall up to date packages\n")); -			printf(_("      --ignore <pkg>   ignore a package upgrade (can be used more than once)\n")); -			printf(_("      --ignoregroup <grp>\n" -			         "                       ignore a group upgrade (can be used more than once)\n")); -			printf(_("      --print          only print the targets instead of performing the operation\n")); -			printf(_("      --print-format <string>\n" -			         "                       specify how the targets should be printed\n")); -			printf(_("  -q, --quiet          show less information for query and search\n")); +			addlist(_("  -c, --clean          remove old packages from cache directory (-cc for all)\n")); +			addlist(_("  -g, --groups         view all members of a package group\n")); +			addlist(_("  -i, --info           view package information\n")); +			addlist(_("  -l, --list <repo>    view a list of packages in a repo\n")); +			addlist(_("  -q, --quiet          show less information for query and search\n")); +			addlist(_("  -s, --search <regex> search remote repositories for matching strings\n")); +			addlist(_("  -u, --sysupgrade     upgrade installed packages (-uu allows downgrade)\n")); +			addlist(_("  -w, --downloadonly   download packages but do not install/upgrade anything\n")); +			addlist(_("  -y, --refresh        download fresh package databases from the server\n")); +			addlist(_("      --needed         don't reinstall up to date packages\n"));  		} else if (op == PM_OP_DATABASE) {  			printf("%s:  %s {-D --database} <%s> <%s>\n", str_usg, myname, str_opt, str_pkg);  			printf("%s:\n", str_opt); -			printf(_("      --asdeps         mark packages as non-explicitly installed\n")); -			printf(_("      --asexplicit     mark packages as explicitly installed\n")); +			addlist(_("      --asdeps         mark packages as non-explicitly installed\n")); +			addlist(_("      --asexplicit     mark packages as explicitly installed\n")); +		} +		switch(op) { +			case PM_OP_SYNC: +			case PM_OP_UPGRADE: +				addlist(_("  -f, --force          force install, overwrite conflicting files\n")); +				addlist(_("      --asdeps         install packages as non-explicitly installed\n")); +				addlist(_("      --asexplicit     install packages as explicitly installed\n")); +				addlist(_("      --ignore <pkg>   ignore a package upgrade (can be used more than once)\n")); +				addlist(_("      --ignoregroup <grp>\n" +				         "                       ignore a group upgrade (can be used more than once)\n")); +				/* pass through */ +			case PM_OP_REMOVE: +				addlist(_("  -d, --nodeps         skip dependency checks\n")); +				addlist(_("  -k, --dbonly         only modify database entries, not package files\n")); +				addlist(_("      --noprogressbar  do not show a progress bar when downloading files\n")); +				addlist(_("      --noscriptlet    do not execute the install scriptlet if one exists\n")); +				addlist(_("      --print          only print the targets instead of performing the operation\n")); +				addlist(_("      --print-format <string>\n" +				         "                       specify how the targets should be printed\n")); +				break;  		} -		printf(_("      --config <path>  set an alternate configuration file\n")); -		printf(_("      --logfile <path> set an alternate log file\n")); -		printf(_("      --noconfirm      do not ask for any confirmation\n")); -		printf(_("      --noprogressbar  do not show a progress bar when downloading files\n")); -		printf(_("      --noscriptlet    do not execute the install scriptlet if one exists\n")); -		printf(_("  -v, --verbose        be verbose\n")); -		printf(_("      --debug          display debug messages\n")); -		printf(_("  -r, --root <path>    set an alternate installation root\n")); -		printf(_("  -b, --dbpath <path>  set an alternate database location\n")); -		printf(_("      --cachedir <dir> set an alternate package cache location\n")); -		printf(_("      --arch <arch>    set an alternate architecture\n")); + +		addlist(_("  -b, --dbpath <path>  set an alternate database location\n")); +		addlist(_("  -r, --root <path>    set an alternate installation root\n")); +		addlist(_("  -v, --verbose        be verbose\n")); +		addlist(_("      --arch <arch>    set an alternate architecture\n")); +		addlist(_("      --cachedir <dir> set an alternate package cache location\n")); +		addlist(_("      --config <path>  set an alternate configuration file\n")); +		addlist(_("      --debug          display debug messages\n")); +		addlist(_("      --logfile <path> set an alternate log file\n")); +		addlist(_("      --noconfirm      do not ask for any confirmation\n")); +	} +	list = alpm_list_msort(list, alpm_list_count(list), options_cmp); +	for (i = list; i; i = alpm_list_next(i)) { +		printf("%s", (char *)alpm_list_getdata(i));  	} +	alpm_list_free(list); +#undef addlist  }  /** Output pacman version and copyright. @@ -261,7 +304,7 @@ static ssize_t xwrite(int fd, const void *buf, size_t count)   * in a consistant state.   * @param signum the thrown signal   */ -static RETSIGTYPE handler(int signum) +static void handler(int signum)  {  	int out = fileno(stdout);  	int err = fileno(stderr); @@ -352,6 +395,241 @@ static void setlibpaths(void)  #define check_optarg() if(!optarg) { return(1); } +typedef void (*fn_add) (const char *s); + +static int parsearg_util_addlist(fn_add fn) +{ +	alpm_list_t *list = NULL, *item = NULL; /* lists for splitting strings */ + +	check_optarg(); +	list = strsplit(optarg, ','); +	for(item = list; item; item = alpm_list_next(item)) { +		fn((char *)alpm_list_getdata(item)); +	} +	FREELIST(list); +	return(0); +} + +/** Helper function for parsing operation from command-line arguments. + * @param opt Keycode returned by getopt_long + * @param dryrun If nonzero, application state is NOT changed + * @return 0 if opt was handled, 1 if it was not handled + */ +static int parsearg_op(int opt, int dryrun) +{ +	switch(opt) { +		/* operations */ +		case 'D': +			if(dryrun) break; +			config->op = (config->op != PM_OP_MAIN ? 0 : PM_OP_DATABASE); break; +		case 'Q': +			if(dryrun) break; +			config->op = (config->op != PM_OP_MAIN ? 0 : PM_OP_QUERY); break; +		case 'R': +			if(dryrun) break; +			config->op = (config->op != PM_OP_MAIN ? 0 : PM_OP_REMOVE); break; +		case 'S': +			if(dryrun) break; +			config->op = (config->op != PM_OP_MAIN ? 0 : PM_OP_SYNC); break; +		case 'T': +			if(dryrun) break; +			config->op = (config->op != PM_OP_MAIN ? 0 : PM_OP_DEPTEST); break; +		case 'U': +			if(dryrun) break; +			config->op = (config->op != PM_OP_MAIN ? 0 : PM_OP_UPGRADE); break; +		case 'V': +			if(dryrun) break; +			config->version = 1; break; +		case 'h': +			if(dryrun) break; +			config->help = 1; break; +		default: +			return(1); +	} +	return(0); +} + +/** Helper functions for parsing command-line arguments. + * @param opt Keycode returned by getopt_long + * @return 0 on success, 1 on failure + */ +static int parsearg_global(int opt) +{ +	switch(opt) { +		case OP_ARCH: check_optarg(); setarch(optarg); break; +		case OP_ASK: +			check_optarg(); +			config->noask = 1; +			config->ask = (unsigned int)atoi(optarg); +			break; +		case OP_CACHEDIR: +			check_optarg(); +			if(alpm_option_add_cachedir(optarg) != 0) { +				pm_printf(PM_LOG_ERROR, _("problem adding cachedir '%s' (%s)\n"), +						optarg, alpm_strerrorlast()); +				return(1); +			} +			break; +		case OP_CONFIG: +			check_optarg(); +			if(config->configfile) { +				free(config->configfile); +			} +			config->configfile = strndup(optarg, PATH_MAX); +			break; +		case OP_DEBUG: +			/* debug levels are made more 'human readable' than using a raw logmask +			 * here, error and warning are set in config_new, though perhaps a +			 * --quiet option will remove these later */ +			if(optarg) { +				unsigned short debug = (unsigned short)atoi(optarg); +				switch(debug) { +					case 2: +						config->logmask |= PM_LOG_FUNCTION; /* fall through */ +					case 1: +						config->logmask |= PM_LOG_DEBUG; +						break; +					default: +						pm_printf(PM_LOG_ERROR, _("'%s' is not a valid debug level\n"), +								optarg); +						return(1); +				} +			} else { +				config->logmask |= PM_LOG_DEBUG; +			} +			/* progress bars get wonky with debug on, shut them off */ +			config->noprogressbar = 1; +			break; +		case OP_LOGFILE: +			check_optarg(); +			config->logfile = strndup(optarg, PATH_MAX); +			break; +		case OP_NOCONFIRM: config->noconfirm = 1; break; +		case 'b': +			check_optarg(); +			config->dbpath = strdup(optarg); +			break; +		case 'r': check_optarg(); config->rootdir = strdup(optarg); break; +		case 'v': (config->verbose)++; break; +		default: return(1); +	} +	return(0); +} + +static int parsearg_database(int opt) +{ +	switch(opt) { +		case OP_ASDEPS: config->flags |= PM_TRANS_FLAG_ALLDEPS; break; +		case OP_ASEXPLICIT: config->flags |= PM_TRANS_FLAG_ALLEXPLICIT; break; +		default: return(1); +	} +	return(0); +} + +static int parsearg_query(int opt) +{ +	switch(opt) { +		case 'c': config->op_q_changelog = 1; break; +		case 'd': config->op_q_deps = 1; break; +		case 'e': config->op_q_explicit = 1; break; +		case 'g': (config->group)++; break; +		case 'i': (config->op_q_info)++; break; +		case 'k': config->op_q_check = 1; break; +		case 'l': config->op_q_list = 1; break; +		case 'm': config->op_q_foreign = 1; break; +		case 'o': config->op_q_owns = 1; break; +		case 'p': config->op_q_isfile = 1; break; +		case 'q': config->quiet = 1; break; +		case 's': config->op_q_search = 1; break; +		case 't': config->op_q_unrequired = 1; break; +		case 'u': config->op_q_upgrade = 1; break; +		default: return(1); +	} +	return(0); +} + +/* options common to -S -R -U */ +static int parsearg_trans(int opt) +{ +	switch(opt) { +		case 'd': config->flags |= PM_TRANS_FLAG_NODEPS; break; +		case 'k': config->flags |= PM_TRANS_FLAG_DBONLY; break; +		case OP_NOPROGRESSBAR: config->noprogressbar = 1; break; +		case OP_NOSCRIPTLET: config->flags |= PM_TRANS_FLAG_NOSCRIPTLET; break; +		case 'p': config->print = 1; break; +		case OP_PRINTFORMAT: +			check_optarg(); +			config->print_format = strdup(optarg); +			break; +		default: return(1); +	} +	return(0); +} + +static int parsearg_remove(int opt) +{ +	if (parsearg_trans(opt) == 0) +		return(0); +	switch(opt) { +		case 'c': config->flags |= PM_TRANS_FLAG_CASCADE; break; +		case 'n': config->flags |= PM_TRANS_FLAG_NOSAVE; break; +		case 's': +			if(config->flags & PM_TRANS_FLAG_RECURSE) { +				config->flags |= PM_TRANS_FLAG_RECURSEALL; +			} else { +				config->flags |= PM_TRANS_FLAG_RECURSE; +			} +			break; +		case 'u': config->flags |= PM_TRANS_FLAG_UNNEEDED; break; +		default: return(1); +	} +	return(0); +} + +/* options common to -S -U */ +static int parsearg_upgrade(int opt) +{ +	if (parsearg_trans(opt) == 0) +		return(0); +	switch(opt) { +		case 'f': config->flags |= PM_TRANS_FLAG_FORCE; break; +		case OP_ASDEPS: config->flags |= PM_TRANS_FLAG_ALLDEPS; break; +		case OP_ASEXPLICIT: config->flags |= PM_TRANS_FLAG_ALLEXPLICIT; break; +		case OP_IGNORE: +			parsearg_util_addlist(alpm_option_add_ignorepkg); +			break; +		case OP_IGNOREGROUP: +			parsearg_util_addlist(alpm_option_add_ignoregrp); +			break; +		default: return(1); +	} +	return(0); +} + +static int parsearg_sync(int opt) +{ +	if (parsearg_upgrade(opt) == 0) +		return(0); +	switch(opt) { +		case OP_NEEDED: config->flags |= PM_TRANS_FLAG_NEEDED; break; +		case 'c': (config->op_s_clean)++; break; +		case 'g': (config->group)++; break; +		case 'i': (config->op_s_info)++; break; +		case 'l': config->op_q_list = 1; break; +		case 'q': config->quiet = 1; break; +		case 's': config->op_s_search = 1; break; +		case 'u': (config->op_s_upgrade)++; break; +		case 'w': +			config->op_s_downloadonly = 1; +			config->flags |= PM_TRANS_FLAG_DOWNLOADONLY; +			config->flags |= PM_TRANS_FLAG_NOCONFLICTS; +			break; +		case 'y': (config->op_s_sync)++; break; +		default: return(1); +	} +	return(0); +} +  /** Parse command-line arguments for each operation.   * @param argc argc   * @param argv argv @@ -361,6 +639,8 @@ static int parseargs(int argc, char *argv[])  {  	int opt;  	int option_index = 0; +	int result; +	const char *optstring = "DQRSTUVb:cdefghiklmnopqr:stuvwy";  	static struct option opts[] =  	{  		{"database",   no_argument,       0, 'D'}, @@ -418,175 +698,23 @@ static int parseargs(int argc, char *argv[])  		{0, 0, 0, 0}  	}; -	while((opt = getopt_long(argc, argv, "DQRSTUVb:cdefghiklmnopqr:stuvwy", opts, &option_index))) { -		alpm_list_t *list = NULL, *item = NULL; /* lists for splitting strings */ - +	/* parse operation */ +	while((opt = getopt_long(argc, argv, optstring, opts, &option_index))) {  		if(opt < 0) {  			break; +		} else if(opt == 0) { +			continue; +		} else if(opt == '?') { +			/* unknown option, getopt printed an error */ +			return(1);  		} -		switch(opt) { -			case 0: break; -			case OP_NOCONFIRM: config->noconfirm = 1; break; -			case OP_CONFIG: -				check_optarg(); -				if(config->configfile) { -					free(config->configfile); -				} -				config->configfile = strndup(optarg, PATH_MAX); -				break; -			case OP_IGNORE: -				check_optarg(); -				list = strsplit(optarg, ','); -				for(item = list; item; item = alpm_list_next(item)) { -					alpm_option_add_ignorepkg((char *)alpm_list_getdata(item)); -				} -				FREELIST(list); -				break; -			case OP_DEBUG: -				/* debug levels are made more 'human readable' than using a raw logmask -				 * here, error and warning are set in config_new, though perhaps a -				 * --quiet option will remove these later */ -				if(optarg) { -					unsigned short debug = atoi(optarg); -					switch(debug) { -						case 2: -							config->logmask |= PM_LOG_FUNCTION; /* fall through */ -						case 1: -							config->logmask |= PM_LOG_DEBUG; -							break; -						default: -						  pm_printf(PM_LOG_ERROR, _("'%s' is not a valid debug level\n"), -									optarg); -							return(1); -					} -				} else { -					config->logmask |= PM_LOG_DEBUG; -				} -				/* progress bars get wonky with debug on, shut them off */ -				config->noprogressbar = 1; -				break; -			case OP_NOPROGRESSBAR: config->noprogressbar = 1; break; -			case OP_NOSCRIPTLET: config->flags |= PM_TRANS_FLAG_NOSCRIPTLET; break; -			case OP_ASK: -				check_optarg(); -				config->noask = 1; -				config->ask = atoi(optarg); -				break; -			case OP_CACHEDIR: -				check_optarg(); -				if(alpm_option_add_cachedir(optarg) != 0) { -					pm_printf(PM_LOG_ERROR, _("problem adding cachedir '%s' (%s)\n"), -							optarg, alpm_strerrorlast()); -					return(1); -				} -				break; -			case OP_ASDEPS: -				config->flags |= PM_TRANS_FLAG_ALLDEPS; -				break; -			case OP_LOGFILE: -				check_optarg(); -				config->logfile = strndup(optarg, PATH_MAX); -				break; -			case OP_IGNOREGROUP: -				check_optarg(); -				list = strsplit(optarg, ','); -				for(item = list; item; item = alpm_list_next(item)) { -					alpm_option_add_ignoregrp((char *)alpm_list_getdata(item)); -				} -				FREELIST(list); -				break; -			case OP_NEEDED: config->flags |= PM_TRANS_FLAG_NEEDED; break; -			case OP_ASEXPLICIT: -				config->flags |= PM_TRANS_FLAG_ALLEXPLICIT; -				break; -			case OP_ARCH: -				check_optarg(); -				setarch(optarg); -				break; -			case OP_PRINTFORMAT: -				check_optarg(); -				config->print_format = strdup(optarg); -				break; -			case 'D': config->op = (config->op != PM_OP_MAIN ? 0 : PM_OP_DATABASE); break; -			case 'Q': config->op = (config->op != PM_OP_MAIN ? 0 : PM_OP_QUERY); break; -			case 'R': config->op = (config->op != PM_OP_MAIN ? 0 : PM_OP_REMOVE); break; -			case 'S': config->op = (config->op != PM_OP_MAIN ? 0 : PM_OP_SYNC); break; -			case 'T': config->op = (config->op != PM_OP_MAIN ? 0 : PM_OP_DEPTEST); break; -			case 'U': config->op = (config->op != PM_OP_MAIN ? 0 : PM_OP_UPGRADE); break; -			case 'V': config->version = 1; break; -			case 'b': -				check_optarg(); -				config->dbpath = strdup(optarg); -				break; -			case 'c': -				(config->op_s_clean)++; -				config->flags |= PM_TRANS_FLAG_CASCADE; -				config->op_q_changelog = 1; -				break; -			case 'd': -				config->op_q_deps = 1; -				config->flags |= PM_TRANS_FLAG_NODEPS; -				break; -			case 'e': -				config->op_q_explicit = 1; -				break; -			case 'f': config->flags |= PM_TRANS_FLAG_FORCE; break; -			case 'g': (config->group)++; break; -			case 'h': config->help = 1; break; -			case 'i': (config->op_q_info)++; (config->op_s_info)++; break; -			case 'k': -				config->flags |= PM_TRANS_FLAG_DBONLY; -				config->op_q_check = 1; -				break; -			case 'l': config->op_q_list = 1; break; -			case 'm': config->op_q_foreign = 1; break; -			case 'n': config->flags |= PM_TRANS_FLAG_NOSAVE; break; -			case 'o': config->op_q_owns = 1; break; -			case 'p': -				config->op_q_isfile = 1; -				config->print = 1; -				break; -			case 'q': -				config->quiet = 1; -				break; -			case 'r': -				check_optarg(); -				config->rootdir = strdup(optarg); -				break; -			case 's': -				config->op_s_search = 1; -				config->op_q_search = 1; -				if(config->flags & PM_TRANS_FLAG_RECURSE) { -					config->flags |= PM_TRANS_FLAG_RECURSEALL; -				} else { -					config->flags |= PM_TRANS_FLAG_RECURSE; -				} -				break; -			case 't': -				config->op_q_unrequired = 1; -				break; -			case 'u': -				(config->op_s_upgrade)++; -				config->op_q_upgrade = 1; -				config->flags |= PM_TRANS_FLAG_UNNEEDED; -				break; -			case 'v': (config->verbose)++; break; -			case 'w': -				config->op_s_downloadonly = 1; -				config->flags |= PM_TRANS_FLAG_DOWNLOADONLY; -				config->flags |= PM_TRANS_FLAG_NOCONFLICTS; -				break; -			case 'y': (config->op_s_sync)++; break; -			case '?': return(1); -			default: return(1); -		} +		parsearg_op(opt, 0);  	}  	if(config->op == 0) {  		pm_printf(PM_LOG_ERROR, _("only one operation may be used at a time\n"));  		return(1);  	} -  	if(config->help) {  		usage(config->op, mbasename(argv[0]));  		return(2); @@ -596,6 +724,55 @@ static int parseargs(int argc, char *argv[])  		return(2);  	} +	/* parse all other options */ +	optind = 1; +	while((opt = getopt_long(argc, argv, optstring, opts, &option_index))) { +		if(opt < 0) { +			break; +		} else if(opt == 0) { +			continue; +		} else if(opt == '?') { +			/* this should have failed during first pass already */ +			return(1); +		} else if(parsearg_op(opt, 1) == 0) {	/* opt is an operation */ +			continue; +		} + +		switch(config->op) { +			case PM_OP_DATABASE: +				result = parsearg_database(opt); +				break; +			case PM_OP_QUERY: +				result = parsearg_query(opt); +				break; +			case PM_OP_REMOVE: +				result = parsearg_remove(opt); +				break; +			case PM_OP_SYNC: +				result = parsearg_sync(opt); +				break; +			case PM_OP_DEPTEST: +				result = 1; +				break; +			case PM_OP_UPGRADE: +				result = parsearg_upgrade(opt); +				break; +			default: +				pm_printf(PM_LOG_ERROR, _("no operation specified (use -h for help)\n")); +				return(1); +		} +		if (result == 0) +			continue; + +		/* fall back to global options */ +		result = parsearg_global(opt); +		if(result != 0) { +			/* global option parsing failed, abort */ +			pm_printf(PM_LOG_ERROR, _("invalid option\n")); +			return(result); +		} +	} +  	while(optind < argc) {  		/* add the target to our target array */  		pm_targets = alpm_list_add(pm_targets, strdup(argv[optind])); @@ -668,7 +845,7 @@ static char *get_tempfile(const char *path, const char *filename) {  }  /** External fetch callback */ -int download_with_xfercommand(const char *url, const char *localpath, +static int download_with_xfercommand(const char *url, const char *localpath,  		int force) {  	int ret = 0;  	int retval; @@ -676,6 +853,7 @@ int download_with_xfercommand(const char *url, const char *localpath,  	struct stat st;  	char *parsedcmd,*tempcmd;  	char cwd[PATH_MAX]; +	int restore_cwd = 0;  	char *destfile, *tempfile, *filename;  	if(!config->xfercommand) { @@ -708,8 +886,14 @@ int download_with_xfercommand(const char *url, const char *localpath,  	parsedcmd = strreplace(tempcmd, "%u", url);  	free(tempcmd); +	/* save the cwd so we can restore it later */ +	if(getcwd(cwd, PATH_MAX) == NULL) { +		pm_printf(PM_LOG_ERROR, _("could not get current working directory\n")); +	} else { +		restore_cwd = 1; +	} +  	/* cwd to the download directory */ -	getcwd(cwd, PATH_MAX);  	if(chdir(localpath)) {  		pm_printf(PM_LOG_WARNING, _("could not chdir to download directory %s\n"), localpath);  		ret = -1; @@ -736,7 +920,11 @@ int download_with_xfercommand(const char *url, const char *localpath,  	}  cleanup: -	chdir(cwd); +	/* restore the old cwd if we have it */ +	if(restore_cwd && chdir(cwd) != 0) { +		pm_printf(PM_LOG_ERROR, _("could not change directory to %s (%s)\n"), cwd, strerror(errno)); +	} +  	if(ret == -1) {  		/* hack to let an user the time to cancel a download */  		sleep(2); @@ -767,6 +955,8 @@ static int _parse_options(char *key, char *value)  		} else if(strcmp(key, "TotalDownload") == 0) {  			config->totaldownload = 1;  			pm_printf(PM_LOG_DEBUG, "config: totaldownload\n"); +		} else if(strcmp(key, "CheckSpace") == 0) { +			alpm_option_set_checkspace(1);  		} else {  			pm_printf(PM_LOG_ERROR, _("directive '%s' without value not recognized\n"), key);  			return(1); @@ -989,7 +1179,7 @@ static int _parseconfig(const char *file, const char *givensection,  							file, linenum, value);  				break;  				default: -					for(int gindex = 0; gindex < globbuf.gl_pathc; gindex++) { +					for(size_t gindex = 0; gindex < globbuf.gl_pathc; gindex++) {  						pm_printf(PM_LOG_DEBUG, "config file %s, line %d: including %s\n",  								file, linenum, globbuf.gl_pathv[gindex]);  						_parseconfig(globbuf.gl_pathv[gindex], section, db); @@ -1161,6 +1351,39 @@ int main(int argc, char *argv[])  		cleanup(ret);  	} +	/* we also support reading targets from stdin */ +	if(!isatty(fileno(stdin))) { +		char line[PATH_MAX]; +		int i = 0; +		while(i < PATH_MAX && (line[i] = (char)fgetc(stdin)) != EOF) { +			if(isspace((unsigned char)line[i])) { +				/* avoid adding zero length arg when multiple spaces separate args */ +				if(i > 0) { +					line[i] = '\0'; +					pm_targets = alpm_list_add(pm_targets, strdup(line)); +					i = 0; +				} +			} else { +				i++; +			} +		} +		/* check for buffer overflow */ +		if (i >= PATH_MAX) { +			pm_printf(PM_LOG_ERROR, _("buffer overflow detected in arg parsing\n")); +			cleanup(EXIT_FAILURE); +		} + +		/* end of stream -- check for data still in line buffer */ +		if(i > 0) { +			line[i] = '\0'; +			pm_targets = alpm_list_add(pm_targets, strdup(line)); +		} +		if (!freopen(ctermid(NULL), "r", stdin)) { +			pm_printf(PM_LOG_ERROR, _("failed to reopen stdin for reading: (%s)\n"), +					strerror(errno)); +		} +	} +  	/* parse the config file */  	ret = parseconfig(config->configfile);  	if(ret != 0) { @@ -1209,14 +1432,6 @@ int main(int argc, char *argv[])  		list_display("Targets   :", pm_targets);  	} -	/* Opening local database */ -	db_local = alpm_db_register_local(); -	if(db_local == NULL) { -		pm_printf(PM_LOG_ERROR, _("could not register 'local' database (%s)\n"), -		        alpm_strerrorlast()); -		cleanup(EXIT_FAILURE); -	} -  	/* Log commandline */  	if(needs_root()) {  		cl_to_log(argc, argv); diff --git a/src/pacman/pacman.h b/src/pacman/pacman.h index f8443cf6..f5b972bb 100644 --- a/src/pacman/pacman.h +++ b/src/pacman/pacman.h @@ -1,7 +1,7 @@  /*   *  pacman.h   * - *  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-2006 by Judd Vinet <jvinet@zeroflux.org>   *   *  This program is free software; you can redistribute it and/or modify diff --git a/src/pacman/query.c b/src/pacman/query.c index 7f064f23..c79133d1 100644 --- a/src/pacman/query.c +++ b/src/pacman/query.c @@ -1,7 +1,7 @@  /*   *  query.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-2006 by Judd Vinet <jvinet@zeroflux.org>   *   *  This program is free software; you can redistribute it and/or modify @@ -37,13 +37,11 @@  #include "conf.h"  #include "util.h" -extern pmdb_t *db_local; - -static char *resolve_path(const char* file) +static char *resolve_path(const char *file)  {  	char *str = NULL; -	str = calloc(PATH_MAX+1, sizeof(char)); +	str = calloc(PATH_MAX + 1, sizeof(char));  	if(!str) {  		return(NULL);  	} @@ -97,8 +95,12 @@ static int search_path(char **filename, struct stat *bufptr)  static int query_fileowner(alpm_list_t *targets)  {  	int ret = 0; -	char *filename; +	char path[PATH_MAX]; +	const char *root; +	char *append; +	size_t max_length;  	alpm_list_t *t; +	pmdb_t *db_local;  	/* This code is here for safety only */  	if(targets == NULL) { @@ -106,13 +108,24 @@ static int query_fileowner(alpm_list_t *targets)  		return(1);  	} +	/* Set up our root path buffer. We only need to copy the location of root in +	 * once, then we can just overwrite whatever file was there on the previous +	 * iteration. */ +	root = alpm_option_get_root(); +	strncpy(path, root, PATH_MAX - 1); +	append = path + strlen(path); +	max_length = PATH_MAX - (append - path) - 1; + +	db_local = alpm_option_get_localdb(); +  	for(t = targets; t; t = alpm_list_next(t)) { +		char *filename, *dname, *rpath; +		const char *bname; +		struct stat buf; +		alpm_list_t *i;  		int found = 0; +  		filename = strdup(alpm_list_getdata(t)); -		char *bname, *dname, *rpath; -		const char *root; -		struct stat buf; -		alpm_list_t *i, *j;  		if(lstat(filename, &buf) == -1) {  			/*  if it is not a path but a program name, then check in PATH */ @@ -144,32 +157,38 @@ static int query_fileowner(alpm_list_t *targets)  		bname = mbasename(filename);  		dname = mdirname(filename);  		rpath = resolve_path(dname); -		free(dname); -		if(!rpath) { +		/* this odd conditional is to ensure files in '/' can be checked */ +		if(!rpath && strcmp(dname, "") != 0) {  			pm_fprintf(stderr, PM_LOG_ERROR, _("cannot determine real path for '%s': %s\n"),  					filename, strerror(errno));  			free(filename); +			free(dname);  			free(rpath);  			ret++;  			continue;  		} - -		root = alpm_option_get_root(); +		free(dname);  		for(i = alpm_db_get_pkgcache(db_local); i && !found; i = alpm_list_next(i)) { +			alpm_list_t *j;  			pmpkg_t *info = alpm_list_getdata(i);  			for(j = alpm_pkg_get_files(info); j && !found; j = alpm_list_next(j)) { -				char path[PATH_MAX], *ppath, *pdname; -				snprintf(path, PATH_MAX, "%s%s", -						root, (const char *)alpm_list_getdata(j)); +				char *ppath, *pdname; +				const char *pkgfile = alpm_list_getdata(j);  				/* avoid the costly resolve_path usage if the basenames don't match */ -				if(strcmp(mbasename(path), bname) != 0) { +				if(strcmp(mbasename(pkgfile), bname) != 0) {  					continue;  				} +				if(strlen(pkgfile) > max_length) { +					pm_fprintf(stderr, PM_LOG_ERROR, _("Path too long: %s%s\n"), root, pkgfile); +				} +				/* concatenate our file and the root path */ +				strcpy(append, pkgfile); +  				pdname = mdirname(path);  				ppath = resolve_path(pdname);  				free(pdname); @@ -202,6 +221,7 @@ static int query_search(alpm_list_t *targets)  {  	alpm_list_t *i, *searchlist;  	int freelist; +	pmdb_t *db_local = alpm_option_get_localdb();  	/* if we have a targets list, search for packages matching it */  	if(targets) { @@ -268,6 +288,8 @@ static int query_group(alpm_list_t *targets)  	alpm_list_t *i, *j;  	char *grpname = NULL;  	int ret = 0; +	pmdb_t *db_local = alpm_option_get_localdb(); +  	if(targets == NULL) {  		for(j = alpm_db_get_grpcache(db_local); j; j = alpm_list_next(j)) {  			pmgrp_t *grp = alpm_list_getdata(j); @@ -406,8 +428,10 @@ static int check(pmpkg_t *pkg)  	}  	if(!config->quiet) { -		printf(_("%s: %d total files, %d missing file(s)\n"), -				pkgname, allfiles, errors); +		printf(_n("%s: %d total file, ", "%s: %d total files, ", +					(unsigned long)allfiles), pkgname, allfiles); +		printf(_n("%d missing file\n", "%d missing files\n", +					(unsigned long)errors), errors);  	}  	return(errors != 0 ? 1 : 0); @@ -451,6 +475,7 @@ int pacman_query(alpm_list_t *targets)  	int match = 0;  	alpm_list_t *i;  	pmpkg_t *pkg = NULL; +	pmdb_t *db_local;  	/* First: operations that do not require targets */ @@ -475,6 +500,8 @@ int pacman_query(alpm_list_t *targets)  		}  	} +	db_local = alpm_option_get_localdb(); +  	/* operations on all packages in the local DB  	 * valid: no-op (plain -Q), list, info, check  	 * invalid: isfile, owns */ diff --git a/src/pacman/remove.c b/src/pacman/remove.c index 1e2cadaf..82d1c384 100644 --- a/src/pacman/remove.c +++ b/src/pacman/remove.c @@ -1,7 +1,7 @@  /*   *  remove.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-2006 by Judd Vinet <jvinet@zeroflux.org>   *   *  This program is free software; you can redistribute it and/or modify @@ -31,8 +31,6 @@  #include "util.h"  #include "conf.h" -extern pmdb_t *db_local; -  /**   * @brief Remove a specified list of packages.   * diff --git a/src/pacman/sync.c b/src/pacman/sync.c index b2994389..7353f7ee 100644 --- a/src/pacman/sync.c +++ b/src/pacman/sync.c @@ -1,7 +1,7 @@  /*   *  sync.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-2006 by Judd Vinet <jvinet@zeroflux.org>   *   *  This program is free software; you can redistribute it and/or modify @@ -37,9 +37,7 @@  #include "package.h"  #include "conf.h" -extern pmdb_t *db_local; - -/* if keep_used != 0, then the dirnames which match an used syncdb +/* if keep_used != 0, then the db files which match an used syncdb   * will be kept  */  static int sync_cleandb(const char *dbpath, int keep_used) {  	DIR *dir; @@ -59,31 +57,47 @@ static int sync_cleandb(const char *dbpath, int keep_used) {  		alpm_list_t *syncdbs = NULL, *i;  		int found = 0;  		const char *dname = ent->d_name; +		size_t len; -		if(!strcmp(dname, ".") || !strcmp(dname, "..")) { +		if(strcmp(dname, ".") == 0 || strcmp(dname, "..") == 0) {  			continue;  		}  		/* skip the local and sync directories */ -		if(!strcmp(dname, "sync") || !strcmp(dname, "local")) { +		if(strcmp(dname, "sync") == 0 || strcmp(dname, "local") == 0) { +			continue; +		} +		/* skip the db.lck file */ +		if(strcmp(dname, "db.lck") == 0) {  			continue;  		}  		/* build the full path */  		snprintf(path, PATH_MAX, "%s%s", dbpath, dname); -		/* skip entries that are not dirs (lock file, etc.) */ + +		/* remove all non-skipped directories and non-database files */  		stat(path, &buf); -		if(!S_ISDIR(buf.st_mode)) { +		len = strlen(path); +		if(S_ISDIR(buf.st_mode) || strcmp(path+(len-3),".db") != 0) { +			if(rmrf(path)) { +				pm_fprintf(stderr, PM_LOG_ERROR, +					_("could not remove %s\n"), path); +				closedir(dir); +				return(1); +			}  			continue;  		}  		if(keep_used) { +			len = strlen(dname); +			char *dbname = strndup(dname, len-3);  			syncdbs = alpm_option_get_syncdbs();  			for(i = syncdbs; i && !found; i = alpm_list_next(i)) {  				pmdb_t *db = alpm_list_getdata(i); -				found = !strcmp(dname, alpm_db_get_name(db)); +				found = !strcmp(dbname, alpm_db_get_name(db));  			} +			free(dbname);  		} -		/* We have a directory that doesn't match any syncdb. +		/* We have a database that doesn't match any syncdb.  		 * Ask the user if he wants to remove it. */  		if(!found) {  			if(!yesno(_("Do you want to remove %s?"), path)) { @@ -92,7 +106,7 @@ static int sync_cleandb(const char *dbpath, int keep_used) {  			if(rmrf(path)) {  				pm_fprintf(stderr, PM_LOG_ERROR, -					_("could not remove repository directory\n")); +					_("could not remove %s\n"), path);  				closedir(dir);  				return(1);  			} @@ -113,8 +127,8 @@ static int sync_cleandb_all(void) {  		return(0);  	}  	/* The sync dbs were previously put in dbpath/, but are now in dbpath/sync/, -	 * so we will clean everything in dbpath/ (except dbpath/local/ and dbpath/sync/, -	 * and only the unused sync dbs in dbpath/sync/ */ +	 * so we will clean everything in dbpath/ (except dbpath/local/ and dbpath/sync/ +	 * and db.lck) and only the unused sync dbs in dbpath/sync/ */  	ret += sync_cleandb(dbpath, 0);  	sprintf(newdbpath, "%s%s", dbpath, "sync/"); @@ -128,6 +142,7 @@ static int sync_cleancache(int level)  {  	alpm_list_t *i;  	alpm_list_t *sync_dbs = alpm_option_get_syncdbs(); +	pmdb_t *db_local = alpm_option_get_localdb();  	int ret = 0;  	for(i = alpm_option_get_cachedirs(); i; i = alpm_list_next(i)) { @@ -178,7 +193,7 @@ static int sync_cleancache(int level)  			pmpkg_t *localpkg = NULL, *pkg = NULL;  			alpm_list_t *j; -			if(!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, "..")) { +			if(strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0) {  				continue;  			}  			/* build the full filepath */ @@ -279,7 +294,7 @@ static int sync_synctree(int level, alpm_list_t *syncs)  	return(success > 0);  } -static void print_installed(pmpkg_t *pkg) +static void print_installed(pmdb_t *db_local, pmpkg_t *pkg)  {  	const char *pkgname = alpm_pkg_get_name(pkg);  	const char *pkgver = alpm_pkg_get_version(pkg); @@ -300,6 +315,7 @@ static int sync_search(alpm_list_t *syncs, alpm_list_t *targets)  	alpm_list_t *i, *j, *ret;  	int freelist;  	int found = 0; +	pmdb_t *db_local = alpm_option_get_localdb();  	for(i = syncs; i; i = alpm_list_next(i)) {  		pmdb_t *db = alpm_list_getdata(i); @@ -330,7 +346,7 @@ static int sync_search(alpm_list_t *syncs, alpm_list_t *targets)  			/* print the package size with the output if ShowSize option set */  			if(!config->quiet && config->showsize) {  				/* Convert byte size to MB */ -				double mbsize = alpm_pkg_get_size(pkg) / (1024.0 * 1024.0); +				double mbsize = (double)alpm_pkg_get_size(pkg) / (1024.0 * 1024.0);  				printf(" [%.2f MB]", mbsize);  			} @@ -350,7 +366,7 @@ static int sync_search(alpm_list_t *syncs, alpm_list_t *targets)  					printf(")");  				} -				print_installed(pkg); +				print_installed(db_local, pkg);  				/* we need a newline and initial indent first */  				printf("\n    "); @@ -503,6 +519,7 @@ static int sync_info(alpm_list_t *syncs, alpm_list_t *targets)  static int sync_list(alpm_list_t *syncs, alpm_list_t *targets)  {  	alpm_list_t *i, *j, *ls = NULL; +	pmdb_t *db_local = alpm_option_get_localdb();  	if(targets) {  		for(i = targets; i; i = alpm_list_next(i)) { @@ -540,7 +557,7 @@ static int sync_list(alpm_list_t *syncs, alpm_list_t *targets)  			if (!config->quiet) {  				printf("%s %s %s", alpm_db_get_name(db), alpm_pkg_get_name(pkg),  						alpm_pkg_get_version(pkg)); -				print_installed(pkg); +				print_installed(db_local, pkg);  				printf("\n");  			} else {  				printf("%s\n", alpm_pkg_get_name(pkg)); @@ -555,7 +572,7 @@ static int sync_list(alpm_list_t *syncs, alpm_list_t *targets)  	return(0);  } -static alpm_list_t *syncfirst() { +static alpm_list_t *syncfirst(void) {  	alpm_list_t *i, *res = NULL;  	for(i = config->syncfirst; i; i = alpm_list_next(i)) { @@ -666,7 +683,7 @@ static int sync_trans(alpm_list_t *targets)  					const char *package2 = alpm_conflict_get_package2(conflict);  					const char *reason = alpm_conflict_get_reason(conflict);  					/* only print reason if it contains new information */ -					if(!strcmp(package1, reason) || !strcmp(package2, reason)) { +					if(strcmp(package1, reason) == 0 || strcmp(package2, reason) == 0) {  						printf(_(":: %s and %s are in conflict\n"), package1, package2);  					} else {  						printf(_(":: %s and %s are in conflict (%s)\n"), package1, package2, reason); diff --git a/src/pacman/upgrade.c b/src/pacman/upgrade.c index 1442eb56..92a477e0 100644 --- a/src/pacman/upgrade.c +++ b/src/pacman/upgrade.c @@ -1,7 +1,7 @@  /*   *  upgrade.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-2006 by Judd Vinet <jvinet@zeroflux.org>   *   *  This program is free software; you can redistribute it and/or modify @@ -112,7 +112,7 @@ int pacman_upgrade(alpm_list_t *targets)  					const char *package2 = alpm_conflict_get_package2(conflict);  					const char *reason = alpm_conflict_get_reason(conflict);  					/* only print reason if it contains new information */ -					if(!strcmp(package1, reason) || !strcmp(package2, reason)) { +					if(strcmp(package1, reason) == 0 || strcmp(package2, reason) == 0) {  						printf(_(":: %s and %s are in conflict\n"), package1, package2);  					} else {  						printf(_(":: %s and %s are in conflict (%s)\n"), package1, package2, reason); diff --git a/src/pacman/util.c b/src/pacman/util.c index 557696b0..0377bf79 100644 --- a/src/pacman/util.c +++ b/src/pacman/util.c @@ -1,7 +1,7 @@  /*   *  util.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-2006 by Judd Vinet <jvinet@zeroflux.org>   *   *  This program is free software; you can redistribute it and/or modify @@ -143,7 +143,7 @@ int rmrf(const char *path)  			if(dp->d_ino) {  				char name[PATH_MAX];  				sprintf(name, "%s/%s", path, dp->d_name); -				if(strcmp(dp->d_name, "..") && strcmp(dp->d_name, ".")) { +				if(strcmp(dp->d_name, "..") != 0 && strcmp(dp->d_name, ".") != 0) {  					errflag += rmrf(name);  				}  			} @@ -157,25 +157,17 @@ int rmrf(const char *path)  }  /** Parse the basename of a program from a path. -* Grabbed from the uClibc source.  * @param path path to parse basename from  *  * @return everything following the final '/'  */ -char *mbasename(const char *path) +const char *mbasename(const char *path)  { -	const char *s; -	const char *p; - -	p = s = path; - -	while (*s) { -		if (*s++ == '/') { -			p = s; -		} +	const char *last = strrchr(path, '/'); +	if(last) { +		return(last + 1);  	} - -	return (char *)p; +	return(path);  }  /** Parse the dirname of a program from a path. @@ -275,7 +267,7 @@ char *strtoupper(char *str)  	char *ptr = str;  	while(*ptr) { -		(*ptr) = toupper((unsigned char)*ptr); +		(*ptr) = (char)toupper((unsigned char)*ptr);  		ptr++;  	}  	return str; @@ -355,7 +347,7 @@ char *strreplace(const char *str, const char *needle, const char *replace)  		q = alpm_list_getdata(i);  		if(q > p){  			/* add chars between this occurence and last occurence, if any */ -			strncpy(newp, p, q - p); +			strncpy(newp, p, (size_t)(q - p));  			newp += q - p;  		}  		strncpy(newp, replace, replacesz); @@ -389,7 +381,7 @@ alpm_list_t *strsplit(const char *str, const char splitchar)  	char *dup = NULL;  	while((str = strchr(str, splitchar))) { -		dup = strndup(prev, str - prev); +		dup = strndup(prev, (size_t)(str - prev));  		if(dup == NULL) {  			return(NULL);  		} @@ -523,29 +515,30 @@ void display_targets(const alpm_list_t *pkgs, int install)  	for(i = pkgs; i; i = alpm_list_next(i)) {  		pmpkg_t *pkg = alpm_list_getdata(i); -		dlsize += alpm_pkg_download_size(pkg); +		if(install) { +			dlsize += alpm_pkg_download_size(pkg); +		}  		isize += alpm_pkg_get_isize(pkg);  		/* print the package size with the output if ShowSize option set */  		if(config->showsize) { -			double mbsize = 0.0; -			mbsize = alpm_pkg_get_size(pkg) / (1024.0 * 1024.0); +			double mbsize = (double)alpm_pkg_get_size(pkg) / (1024.0 * 1024.0); -			asprintf(&str, "%s-%s [%.2f MB]", alpm_pkg_get_name(pkg), +			pm_asprintf(&str, "%s-%s [%.2f MB]", alpm_pkg_get_name(pkg),  					alpm_pkg_get_version(pkg), mbsize);  		} else { -			asprintf(&str, "%s-%s", alpm_pkg_get_name(pkg), +			pm_asprintf(&str, "%s-%s", alpm_pkg_get_name(pkg),  					alpm_pkg_get_version(pkg));  		}  		targets = alpm_list_add(targets, str);  	}  	/* Convert byte sizes to MB */ -	mbdlsize = dlsize / (1024.0 * 1024.0); -	mbisize = isize / (1024.0 * 1024.0); +	mbdlsize = (double)dlsize / (1024.0 * 1024.0); +	mbisize = (double)isize / (1024.0 * 1024.0);  	if(install) { -		asprintf(&str, _("Targets (%d):"), alpm_list_count(targets)); +		pm_asprintf(&str, _("Targets (%d):"), alpm_list_count(targets));  		list_display(str, targets);  		free(str);  		printf("\n"); @@ -555,7 +548,7 @@ void display_targets(const alpm_list_t *pkgs, int install)  			printf(_("Total Installed Size:   %.2f MB\n"), mbisize);  		}  	} else { -		asprintf(&str, _("Remove (%d):"), alpm_list_count(targets)); +		pm_asprintf(&str, _("Remove (%d):"), alpm_list_count(targets));  		list_display(str, targets);  		free(str);  		printf("\n"); @@ -589,14 +582,14 @@ static char *pkg_get_location(pmpkg_t *pkg)  			dburl = alpm_db_get_url(db);  			if(dburl) {  				char *pkgurl = NULL; -				asprintf(&pkgurl, "%s/%s", dburl, alpm_pkg_get_filename(pkg)); +				pm_asprintf(&pkgurl, "%s/%s", dburl, alpm_pkg_get_filename(pkg));  				return(pkgurl);  			}  		case PM_OP_UPGRADE:  			return(strdup(alpm_pkg_get_filename(pkg)));  		default:  			string = NULL; -			asprintf(&string, "%s-%s", alpm_pkg_get_name(pkg), alpm_pkg_get_version(pkg)); +			pm_asprintf(&string, "%s-%s", alpm_pkg_get_name(pkg), alpm_pkg_get_version(pkg));  			return(string);  	}  } @@ -645,13 +638,11 @@ void print_packages(const alpm_list_t *packages)  		/* %s : size */  		if(strstr(temp,"%s")) {  			char *size; -			double mbsize = 0.0; -			mbsize = pkg_get_size(pkg) / (1024.0 * 1024.0); -			asprintf(&size, "%.2f", mbsize); +			double mbsize = (double)pkg_get_size(pkg) / (1024.0 * 1024.0); +			pm_asprintf(&size, "%.2f", mbsize);  			string = strreplace(temp, "%s", size);  			free(size);  			free(temp); -			temp = string;  		}  		printf("%s\n",string);  		free(string); @@ -690,7 +681,6 @@ void display_optdepends(pmpkg_t *pkg)  static int question(short preset, char *fmt, va_list args)  {  	char response[32]; -	int sresponse = sizeof(response)-1;  	FILE *stream;  	if(config->noconfirm) { @@ -713,15 +703,15 @@ static int question(short preset, char *fmt, va_list args)  		return(preset);  	} -	if(fgets(response, sresponse, stdin)) { +	if(fgets(response, sizeof(response), stdin)) {  		strtrim(response);  		if(strlen(response) == 0) {  			return(preset);  		} -		if(!strcasecmp(response, _("Y")) || !strcasecmp(response, _("YES"))) { +		if(strcasecmp(response, _("Y")) == 0 || strcasecmp(response, _("YES")) == 0) {  			return(1); -		} else if (!strcasecmp(response, _("N")) || !strcasecmp(response, _("NO"))) { +		} else if (strcasecmp(response, _("N")) == 0 || strcasecmp(response, _("NO")) == 0) {  			return(0);  		}  	} @@ -778,6 +768,22 @@ int pm_fprintf(FILE *stream, pmloglevel_t level, const char *format, ...)  	return(ret);  } +int pm_asprintf(char **string, const char *format, ...) +{ +	int ret = 0; +	va_list args; + +	/* print the message using va_arg list */ +	va_start(args, format); +	if(vasprintf(string, format, args) == -1) { +		pm_fprintf(stderr, PM_LOG_ERROR,  _("failed to allocate string\n")); +		ret = -1; +	} +	va_end(args); + +	return(ret); +} +  int pm_vasprintf(char **string, pmloglevel_t level, const char *format, va_list args)  {  	int ret = 0; @@ -794,16 +800,16 @@ int pm_vasprintf(char **string, pmloglevel_t level, const char *format, va_list  	/* print a prefix to the message */  	switch(level) {  		case PM_LOG_DEBUG: -			asprintf(string, "debug: %s", msg); +			pm_asprintf(string, "debug: %s", msg);  			break;  		case PM_LOG_ERROR: -			asprintf(string, _("error: %s"), msg); +			pm_asprintf(string, _("error: %s"), msg);  			break;  		case PM_LOG_WARNING: -			asprintf(string, _("warning: %s"), msg); +			pm_asprintf(string, _("warning: %s"), msg);  			break;  		case PM_LOG_FUNCTION: -			asprintf(string, _("function: %s"), msg); +			pm_asprintf(string, _("function: %s"), msg);  			break;  		default:  			break; @@ -824,7 +830,7 @@ int pm_vfprintf(FILE *stream, pmloglevel_t level, const char *format, va_list ar  #if defined(PACMAN_DEBUG)  	/* If debug is on, we'll timestamp the output */ -  if(config->logmask & PM_LOG_DEBUG) { +	if(config->logmask & PM_LOG_DEBUG) {  		time_t t;  		struct tm *tmp;  		char timestr[10] = {0}; diff --git a/src/pacman/util.h b/src/pacman/util.h index bbf43827..78fe5b59 100644 --- a/src/pacman/util.h +++ b/src/pacman/util.h @@ -1,7 +1,7 @@  /*   *  util.h   * - *  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-2006 by Judd Vinet <jvinet@zeroflux.org>   *   *  This program is free software; you can redistribute it and/or modify @@ -30,8 +30,10 @@  #include <libintl.h> /* here so it doesn't need to be included elsewhere */  /* define _() as shortcut for gettext() */  #define _(str) gettext(str) +#define _n(str1, str2, ct) ngettext(str1, str2, ct)  #else  #define _(str) str +#define _n(str1, str2, ct) (ct == 1 ? str1 : str2)  #endif  /* update speed for the fill_progress based functions */ @@ -42,7 +44,7 @@ int trans_release(void);  int needs_root(void);  int getcols(void);  int rmrf(const char *path); -char *mbasename(const char *path); +const char *mbasename(const char *path);  char *mdirname(const char *path);  void indentprint(const char *str, int indent);  char *strtoupper(char *str); @@ -53,6 +55,7 @@ void string_display(const char *title, const char *string);  void list_display(const char *title, const alpm_list_t *list);  void list_display_linebreak(const char *title, const alpm_list_t *list);  void display_targets(const alpm_list_t *pkgs, int install); +int str_cmp(const void *s1, const void *s2);  void display_new_optdepends(pmpkg_t *oldpkg, pmpkg_t *newpkg);  void display_optdepends(pmpkg_t *pkg);  void print_packages(const alpm_list_t *packages); @@ -60,6 +63,7 @@ int yesno(char *fmt, ...);  int noyes(char *fmt, ...);  int pm_printf(pmloglevel_t level, const char *format, ...) __attribute__((format(printf,2,3)));  int pm_fprintf(FILE *stream, pmloglevel_t level, const char *format, ...) __attribute__((format(printf,3,4))); +int pm_asprintf(char **string, const char *format, ...);  int pm_vfprintf(FILE *stream, pmloglevel_t level, const char *format, va_list args) __attribute__((format(printf,3,0)));  int pm_vasprintf(char **string, pmloglevel_t level, const char *format, va_list args) __attribute__((format(printf,3,0))); 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..4403e9fa 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; @@ -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..6a10006f --- /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(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..461cf23a 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,19 +126,17 @@ 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()); @@ -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..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);  } | 
