summaryrefslogtreecommitdiffstats
path: root/src/pacman
diff options
context:
space:
mode:
Diffstat (limited to 'src/pacman')
-rw-r--r--src/pacman/Makefile.am2
-rw-r--r--src/pacman/callback.c122
-rw-r--r--src/pacman/callback.h4
-rw-r--r--src/pacman/conf.c2
-rw-r--r--src/pacman/conf.h6
-rw-r--r--src/pacman/database.c6
-rw-r--r--src/pacman/deptest.c16
-rw-r--r--src/pacman/package.c79
-rw-r--r--src/pacman/package.h2
-rw-r--r--src/pacman/pacman.c721
-rw-r--r--src/pacman/pacman.h2
-rw-r--r--src/pacman/query.c73
-rw-r--r--src/pacman/remove.c35
-rw-r--r--src/pacman/sync.c259
-rw-r--r--src/pacman/upgrade.c17
-rw-r--r--src/pacman/util.c274
-rw-r--r--src/pacman/util.h11
17 files changed, 1136 insertions, 495 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..f1e71bb4 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,
@@ -279,18 +285,36 @@ void cb_trans_conv(pmtransconv_t event, void *data1, void *data2,
{
alpm_list_t *unresolved = (alpm_list_t *) data1;
alpm_list_t *namelist = NULL, *i;
+ size_t count = alpm_list_count(namelist);
for (i = unresolved; i; i = i->next) {
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",
+ count));
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?",
+ count));
alpm_list_free(namelist);
}
break;
+ case PM_TRANS_CONV_SELECT_PROVIDER:
+ {
+ alpm_list_t *providers = (alpm_list_t *)data1;
+ int count = alpm_list_count(providers);
+ char *depstring = alpm_dep_compute_string((pmdepend_t *)data2);
+ printf(_(":: There are %d providers available for %s:\n"), count,
+ depstring);
+ free(depstring);
+ select_display(providers);
+ *response = select_question(count);
+ }
+ break;
case PM_TRANS_CONV_LOCAL_NEWER:
if(!config->op_s_downloadonly) {
*response = yesno(_(":: %s-%s: local version is newer. Upgrade anyway?"),
@@ -315,13 +339,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 +354,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 +386,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 +415,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 +447,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 +491,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 +550,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(&current_time, NULL);
diff_sec = current_time.tv_sec - initial_time.tv_sec;
@@ -550,11 +576,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 +596,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..92c379fc 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
@@ -111,8 +111,8 @@ enum {
/* clean method */
enum {
- PM_CLEAN_KEEPINST = 0, /* default */
- PM_CLEAN_KEEPCUR
+ PM_CLEAN_KEEPINST = 1,
+ PM_CLEAN_KEEPCUR = (1 << 1)
};
/* global config variable */
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..0d265c70 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_list(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..984bd1b7 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,247 @@ 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':
+ if(config->flags & PM_TRANS_FLAG_NODEPVERSION) {
+ config->flags |= PM_TRANS_FLAG_NODEPS;
+ } else {
+ config->flags |= PM_TRANS_FLAG_NODEPVERSION;
+ }
+ 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 +645,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 +704,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 +730,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]));
@@ -615,6 +798,18 @@ static void option_add_syncfirst(const char *name) {
config->syncfirst = alpm_list_add(config->syncfirst, strdup(name));
}
+/* helper for being used with setrepeatingoption */
+static void option_add_cleanmethod(const char *value) {
+ if (strcmp(value, "KeepInstalled") == 0) {
+ config->cleanmethod |= PM_CLEAN_KEEPINST;
+ } else if (strcmp(value, "KeepCurrent") == 0) {
+ config->cleanmethod |= PM_CLEAN_KEEPCUR;
+ } else {
+ pm_printf(PM_LOG_ERROR, _("invalid value for 'CleanMethod' : '%s'\n"),
+ value);
+ }
+}
+
/** Add repeating options such as NoExtract, NoUpgrade, etc to libalpm
* settings. Refactored out of the parseconfig code since all of them did
* the exact same thing and duplicated code.
@@ -668,7 +863,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 +871,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 +904,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 +938,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 +973,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);
@@ -818,15 +1026,7 @@ static int _parse_options(char *key, char *value)
alpm_option_set_fetchcb(download_with_xfercommand);
pm_printf(PM_LOG_DEBUG, "config: xfercommand: %s\n", value);
} else if (strcmp(key, "CleanMethod") == 0) {
- if (strcmp(value, "KeepInstalled") == 0) {
- config->cleanmethod = PM_CLEAN_KEEPINST;
- } else if (strcmp(value, "KeepCurrent") == 0) {
- config->cleanmethod = PM_CLEAN_KEEPCUR;
- } else {
- pm_printf(PM_LOG_ERROR, _("invalid value for 'CleanMethod' : '%s'\n"), value);
- return(1);
- }
- pm_printf(PM_LOG_DEBUG, "config: cleanmethod: %s\n", value);
+ setrepeatingoption(value, "CleanMethod", option_add_cleanmethod);
} else {
pm_printf(PM_LOG_ERROR, _("directive '%s' with a value not recognized\n"), key);
return(1);
@@ -989,7 +1189,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 +1361,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 +1442,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..734875be 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;
}
+ free(dname);
- root = alpm_option_get_root();
-
- for(i = alpm_db_get_pkgcache(db_local); i && !found; i = alpm_list_next(i)) {
+ for(i = alpm_db_get_pkgcache_list(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,13 +221,14 @@ 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) {
searchlist = alpm_db_search(db_local, targets);
freelist = 1;
} else {
- searchlist = alpm_db_get_pkgcache(db_local);
+ searchlist = alpm_db_get_pkgcache_list(db_local);
freelist = 0;
}
if(searchlist == NULL) {
@@ -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 */
@@ -484,7 +511,7 @@ int pacman_query(alpm_list_t *targets)
return(1);
}
- for(i = alpm_db_get_pkgcache(db_local); i; i = alpm_list_next(i)) {
+ for(i = alpm_db_get_pkgcache_list(db_local); i; i = alpm_list_next(i)) {
pkg = alpm_list_getdata(i);
if(filter(pkg)) {
int value = display(pkg);
diff --git a/src/pacman/remove.c b/src/pacman/remove.c
index 1e2cadaf..fb02e242 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,7 +31,35 @@
#include "util.h"
#include "conf.h"
-extern pmdb_t *db_local;
+static int remove_target(char *target)
+{
+ pmpkg_t *info;
+ pmdb_t *db_local = alpm_option_get_localdb();
+ alpm_list_t *p;
+
+ if((info = alpm_db_get_pkg(db_local, target)) != NULL) {
+ if(alpm_remove_pkg(info) == -1) {
+ pm_fprintf(stderr, PM_LOG_ERROR, "'%s': %s\n", target, alpm_strerrorlast());
+ return(-1);
+ }
+ return(0);
+ }
+
+ /* fallback to group */
+ pmgrp_t *grp = alpm_db_readgrp(db_local, target);
+ if(grp == NULL) {
+ pm_fprintf(stderr, PM_LOG_ERROR, "'%s': target not found\n", target);
+ return(-1);
+ }
+ for(p = alpm_grp_get_pkgs(grp); p; p = alpm_list_next(p)) {
+ pmpkg_t *pkg = alpm_list_getdata(p);
+ if(alpm_remove_pkg(pkg) == -1) {
+ pm_fprintf(stderr, PM_LOG_ERROR, "'%s': %s\n", target, alpm_strerrorlast());
+ return(-1);
+ }
+ }
+ return(0);
+}
/**
* @brief Remove a specified list of packages.
@@ -64,8 +92,7 @@ int pacman_remove(alpm_list_t *targets)
} else {
targ = target;
}
- if(alpm_remove_target(targ) == -1) {
- pm_fprintf(stderr, PM_LOG_ERROR, "'%s': %s\n", targ, alpm_strerrorlast());
+ if(remove_target(targ) == -1) {
retval = 1;
goto cleanup;
}
diff --git a/src/pacman/sync.c b/src/pacman/sync.c
index b2994389..7af1667a 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,13 +37,12 @@
#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;
struct dirent *ent;
+ alpm_list_t *syncdbs;
dir = opendir(dbpath);
if(dir == NULL) {
@@ -51,39 +50,56 @@ static int sync_cleandb(const char *dbpath, int keep_used) {
return(1);
}
+ syncdbs = alpm_option_get_syncdbs();
+
rewinddir(dir);
/* step through the directory one file at a time */
while((ent = readdir(dir)) != NULL) {
char path[PATH_MAX];
struct stat buf;
- 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) {
- syncdbs = alpm_option_get_syncdbs();
+ alpm_list_t *i;
+ len = strlen(dname);
+ char *dbname = strndup(dname, len - 3);
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 +108,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);
}
@@ -112,9 +128,9 @@ static int sync_cleandb_all(void) {
if(!yesno(_("Do you want to remove unused repositories?"))) {
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/ */
+ /* The sync dbs were previously put in dbpath/ but are now in dbpath/sync/.
+ * We will clean everything in dbpath/ except local/, 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,27 +144,28 @@ 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)) {
printf(_("Cache directory: %s\n"), (char*)alpm_list_getdata(i));
}
+ if(!config->cleanmethod) {
+ /* default to KeepInstalled if user did not specify */
+ config->cleanmethod = PM_CLEAN_KEEPINST;
+ }
+
if(level == 1) {
- switch(config->cleanmethod) {
- case PM_CLEAN_KEEPINST:
- if(!yesno(_("Do you want to remove uninstalled packages from cache?"))) {
- return(0);
- }
- break;
- case PM_CLEAN_KEEPCUR:
- if(!yesno(_("Do you want to remove outdated packages from cache?"))) {
- return(0);
- }
- break;
- default:
- /* this should not happen : the config parsing doesn't set any other value */
- return(1);
+ printf(_("Packages to keep:\n"));
+ if(config->cleanmethod & PM_CLEAN_KEEPINST) {
+ printf(_(" All locally installed packages\n"));
+ }
+ if(config->cleanmethod & PM_CLEAN_KEEPCUR) {
+ printf(_(" All current sync database packages\n"));
+ }
+ if(!yesno(_("Do you want to remove all other packages from cache?"))) {
+ return(0);
}
printf(_("removing old packages from cache...\n"));
} else {
@@ -176,9 +193,10 @@ static int sync_cleancache(int level)
char path[PATH_MAX];
int delete = 1;
pmpkg_t *localpkg = NULL, *pkg = NULL;
+ const char *local_name, *local_version;
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 */
@@ -202,32 +220,33 @@ static int sync_cleancache(int level)
}
continue;
}
- switch(config->cleanmethod) {
- case PM_CLEAN_KEEPINST:
- /* check if this package is in the local DB */
- pkg = alpm_db_get_pkg(db_local, alpm_pkg_get_name(localpkg));
- if(pkg != NULL && alpm_pkg_vercmp(alpm_pkg_get_version(localpkg),
+ local_name = alpm_pkg_get_name(localpkg);
+ local_version = alpm_pkg_get_version(localpkg);
+
+ if(config->cleanmethod & PM_CLEAN_KEEPINST) {
+ /* check if this package is in the local DB */
+ pkg = alpm_db_get_pkg(db_local, local_name);
+ if(pkg != NULL && alpm_pkg_vercmp(local_version,
+ alpm_pkg_get_version(pkg)) == 0) {
+ /* package was found in local DB and version matches, keep it */
+ pm_printf(PM_LOG_DEBUG, "pkg %s-%s found in local db\n",
+ local_name, local_version);
+ delete = 0;
+ }
+ }
+ if(config->cleanmethod & PM_CLEAN_KEEPCUR) {
+ /* check if this package is in a sync DB */
+ for(j = sync_dbs; j && delete; j = alpm_list_next(j)) {
+ pmdb_t *db = alpm_list_getdata(j);
+ pkg = alpm_db_get_pkg(db, local_name);
+ if(pkg != NULL && alpm_pkg_vercmp(local_version,
alpm_pkg_get_version(pkg)) == 0) {
- /* package was found in local DB and version matches, keep it */
+ /* package was found in a sync DB and version matches, keep it */
+ pm_printf(PM_LOG_DEBUG, "pkg %s-%s found in sync db\n",
+ local_name, local_version);
delete = 0;
}
- break;
- case PM_CLEAN_KEEPCUR:
- /* check if this package is in a sync DB */
- for(j = sync_dbs; j && delete; j = alpm_list_next(j)) {
- pmdb_t *db = alpm_list_getdata(j);
- pkg = alpm_db_get_pkg(db, alpm_pkg_get_name(localpkg));
- if(pkg != NULL && alpm_pkg_vercmp(alpm_pkg_get_version(localpkg),
- alpm_pkg_get_version(pkg)) == 0) {
- /* package was found in a sync DB and version matches, keep it */
- delete = 0;
- }
- }
- break;
- default:
- /* this should not happen : the config parsing doesn't set any other value */
- delete = 0;
- break;
+ }
}
/* free the local file package */
alpm_pkg_free(localpkg);
@@ -279,7 +298,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 +319,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);
@@ -308,7 +328,7 @@ static int sync_search(alpm_list_t *syncs, alpm_list_t *targets)
ret = alpm_db_search(db, targets);
freelist = 1;
} else {
- ret = alpm_db_get_pkgcache(db);
+ ret = alpm_db_get_pkgcache_list(db);
freelist = 0;
}
if(ret == NULL) {
@@ -330,7 +350,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 +370,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 ");
@@ -449,7 +469,7 @@ static int sync_info(alpm_list_t *syncs, alpm_list_t *targets)
return(1);
}
- for(k = alpm_db_get_pkgcache(db); k; k = alpm_list_next(k)) {
+ for(k = alpm_db_get_pkgcache_list(db); k; k = alpm_list_next(k)) {
pmpkg_t *pkg = alpm_list_getdata(k);
if(strcmp(alpm_pkg_get_name(pkg), pkgstr) == 0) {
@@ -470,7 +490,7 @@ static int sync_info(alpm_list_t *syncs, alpm_list_t *targets)
for(j = syncs; j; j = alpm_list_next(j)) {
pmdb_t *db = alpm_list_getdata(j);
- for(k = alpm_db_get_pkgcache(db); k; k = alpm_list_next(k)) {
+ for(k = alpm_db_get_pkgcache_list(db); k; k = alpm_list_next(k)) {
pmpkg_t *pkg = alpm_list_getdata(k);
if(strcmp(alpm_pkg_get_name(pkg), pkgstr) == 0) {
@@ -491,7 +511,7 @@ static int sync_info(alpm_list_t *syncs, alpm_list_t *targets)
for(i = syncs; i; i = alpm_list_next(i)) {
pmdb_t *db = alpm_list_getdata(i);
- for(j = alpm_db_get_pkgcache(db); j; j = alpm_list_next(j)) {
+ for(j = alpm_db_get_pkgcache_list(db); j; j = alpm_list_next(j)) {
dump_pkg_sync(alpm_list_getdata(j), alpm_db_get_name(db), config->op_s_info);
}
}
@@ -503,6 +523,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)) {
@@ -534,13 +555,13 @@ static int sync_list(alpm_list_t *syncs, alpm_list_t *targets)
for(i = ls; i; i = alpm_list_next(i)) {
pmdb_t *db = alpm_list_getdata(i);
- for(j = alpm_db_get_pkgcache(db); j; j = alpm_list_next(j)) {
+ for(j = alpm_db_get_pkgcache_list(db); j; j = alpm_list_next(j)) {
pmpkg_t *pkg = alpm_list_getdata(j);
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 +576,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)) {
@@ -573,6 +594,82 @@ static alpm_list_t *syncfirst() {
return(res);
}
+static pmdb_t *get_db(const char *dbname)
+{
+ alpm_list_t *i;
+ for(i = alpm_option_get_syncdbs(); i; i = i->next) {
+ pmdb_t *db = i->data;
+ if(strcmp(alpm_db_get_name(db), dbname) == 0) {
+ return(db);
+ }
+ }
+ return(NULL);
+}
+
+static int process_pkg(pmpkg_t *pkg)
+{
+ int ret = alpm_add_pkg(pkg);
+
+ if(ret == -1) {
+ if(pm_errno == PM_ERR_TRANS_DUP_TARGET
+ || pm_errno == PM_ERR_PKG_IGNORED) {
+ /* just skip duplicate or ignored targets */
+ pm_printf(PM_LOG_WARNING, _("skipping target: %s\n"), alpm_pkg_get_name(pkg));
+ return(0);
+ } else {
+ pm_fprintf(stderr, PM_LOG_ERROR, "'%s': %s\n", alpm_pkg_get_name(pkg),
+ alpm_strerrorlast());
+ return(1);
+ }
+ }
+ return(0);
+}
+
+static int process_group(alpm_list_t *dbs, char *group)
+{
+ int ret = 0;
+ alpm_list_t *i;
+ alpm_list_t *pkgs = alpm_find_grp_pkgs(dbs, group);
+ int count = alpm_list_count(pkgs);
+
+ if(!count) {
+ pm_fprintf(stderr, PM_LOG_ERROR, _("target not found: %s\n"), group);
+ return(1);
+ }
+
+ printf(_(":: There are %d members in group %s:\n"), count,
+ group);
+ select_display(pkgs);
+ char *array = malloc(count);
+ multiselect_question(array, count);
+ int n = 0;
+ for(i = pkgs; i; i = alpm_list_next(i)) {
+ if(array[n++] == 0)
+ continue;
+ pmpkg_t *pkg = alpm_list_getdata(i);
+
+ if(process_pkg(pkg) == 1) {
+ ret = 1;
+ goto cleanup;
+ }
+ }
+cleanup:
+ alpm_list_free(pkgs);
+ free(array);
+ return(ret);
+}
+
+static int process_targname(alpm_list_t *dblist, char *targname)
+{
+ pmpkg_t *pkg = alpm_find_dbs_satisfier(dblist, targname);
+
+ if(pkg) {
+ return(process_pkg(pkg));
+ }
+ /* fallback on group */
+ return(process_group(dblist, targname));
+}
+
static int process_target(char *target)
{
/* process targets */
@@ -580,28 +677,30 @@ static int process_target(char *target)
char *targname = strchr(targstring, '/');
char *dbname = NULL;
int ret = 0;
+ alpm_list_t *dblist = NULL;
+
if(targname) {
+ pmdb_t *db = NULL;
+
*targname = '\0';
targname++;
dbname = targstring;
- ret = alpm_sync_dbtarget(dbname,targname);
- } else {
- targname = targstring;
- ret = alpm_sync_target(targname);
- }
-
- if(ret == -1) {
- if(pm_errno == PM_ERR_TRANS_DUP_TARGET
- || pm_errno == PM_ERR_PKG_IGNORED) {
- /* just skip duplicate or ignored targets */
- pm_printf(PM_LOG_WARNING, _("skipping target: %s\n"), target);
- } else {
- pm_fprintf(stderr, PM_LOG_ERROR, "'%s': %s\n", target,
- alpm_strerrorlast());
+ db = get_db(dbname);
+ if(!db) {
+ pm_fprintf(stderr, PM_LOG_ERROR, _("database not found: %s\n"),
+ dbname);
ret = 1;
+ goto cleanup;
}
+ dblist = alpm_list_add(dblist, db);
+ ret = process_targname(dblist, targname);
+ alpm_list_free(dblist);
+ } else {
+ targname = targstring;
+ dblist = alpm_option_get_syncdbs();
+ ret = process_targname(dblist, targname);
}
-
+cleanup:
free(targstring);
return(ret);
}
@@ -666,7 +765,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..8cd29da0 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
@@ -55,6 +55,8 @@ int pacman_upgrade(alpm_list_t *targets)
if(strstr(i->data, "://")) {
char *str = alpm_fetch_pkgurl(i->data);
if(str == NULL) {
+ pm_fprintf(stderr, PM_LOG_ERROR, "'%s': %s\n",
+ (char *)i->data, alpm_strerrorlast());
return(1);
} else {
free(i->data);
@@ -71,9 +73,18 @@ int pacman_upgrade(alpm_list_t *targets)
/* add targets to the created transaction */
for(i = targets; i; i = alpm_list_next(i)) {
char *targ = alpm_list_getdata(i);
- if(alpm_add_target(targ) == -1) {
+ pmpkg_t *pkg;
+
+ if(alpm_pkg_load(targ, 1, &pkg) != 0) {
+ pm_fprintf(stderr, PM_LOG_ERROR, "'%s': %s\n",
+ targ, alpm_strerrorlast());
+ trans_release();
+ return(1);
+ }
+ if(alpm_add_pkg(pkg) == -1) {
pm_fprintf(stderr, PM_LOG_ERROR, "'%s': %s\n",
targ, alpm_strerrorlast());
+ alpm_pkg_free(pkg);
trans_release();
return(1);
}
@@ -112,7 +123,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..c08ebb15 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);
@@ -686,11 +677,194 @@ void display_optdepends(pmpkg_t *pkg)
}
}
+static void display_repo_list(const char *dbname, alpm_list_t *list)
+{
+ const char *prefix= " ";
+
+ printf(":: ");
+ printf(_("Repository %s\n"), dbname);
+ list_display(prefix, list);
+}
+
+void select_display(const alpm_list_t *pkglist)
+{
+ const alpm_list_t *i;
+ int nth = 1;
+ alpm_list_t *list = NULL;
+ char *string = NULL;
+ const char *dbname = NULL;
+
+ for (i = pkglist; i; i = i->next) {
+ pmpkg_t *pkg = alpm_list_getdata(i);
+ pmdb_t *db = alpm_pkg_get_db(pkg);
+
+ if(!dbname)
+ dbname = alpm_db_get_name(db);
+ if(strcmp(alpm_db_get_name(db), dbname) != 0) {
+ display_repo_list(dbname, list);
+ FREELIST(list);
+ dbname = alpm_db_get_name(db);
+ }
+ string = NULL;
+ pm_asprintf(&string, "%d) %s", nth, alpm_pkg_get_name(pkg));
+ list = alpm_list_add(list, string);
+ nth++;
+ }
+ display_repo_list(dbname, list);
+ FREELIST(list);
+}
+
+static int parseindex(char *s, int *val, int min, int max)
+{
+ char *endptr = NULL;
+ int n = strtol(s, &endptr, 10);
+ if(*endptr == '\0') {
+ if(n < min || n > max) {
+ fprintf(stderr, _("Invalid value: %d is not between %d and %d\n"),
+ n, min, max);
+ return(-1);
+ }
+ *val = n;
+ return(0);
+ } else {
+ fprintf(stderr, _("Invalid number: %s\n"), s);
+ return(-1);
+ }
+}
+
+static int multiselect_parse(char *array, int count, char *response)
+{
+ char *str, *saveptr;
+
+ for (str = response; ; str = NULL) {
+ int include = 1;
+ int start, end;
+ char *ends = NULL;
+ char *starts = strtok_r(str, " ", &saveptr);
+
+ if (starts == NULL)
+ break;
+ strtrim(starts);
+ int len = strlen(starts);
+ if(len == 0)
+ continue;
+
+ if (*starts == '^') {
+ starts++;
+ len--;
+ include = 0;
+ } else if(str) {
+ /* if first token is including, we unselect all targets */
+ memset(array, 0, count);
+ }
+
+ if(len > 1) {
+ /* check for range */
+ char *p;
+ if((p = strchr(starts+1, '-'))) {
+ *p = 0;
+ ends = p+1;
+ }
+ }
+
+ if(parseindex(starts, &start, 1, count) != 0)
+ return(-1);
+
+ if(!ends) {
+ array[start-1] = include;
+ } else {
+ if(parseindex(ends, &end, start, count) != 0)
+ return(-1);
+ for(int d = start; d <= end; d++) {
+ array[d-1] = include;
+ }
+ }
+ }
+
+ return(0);
+}
+
+int multiselect_question(char *array, int count)
+{
+ char response[64];
+ FILE *stream;
+
+ if(config->noconfirm) {
+ stream = stdout;
+ } else {
+ /* Use stderr so questions are always displayed when redirecting output */
+ stream = stderr;
+ }
+
+ while(1) {
+ memset(array, 1, count);
+
+ fprintf(stream, "\n");
+ fprintf(stream, _("Enter a selection (default=all)"));
+ fprintf(stream, ": ");
+
+ if(config->noconfirm) {
+ fprintf(stream, "\n");
+ break;
+ }
+
+ if(fgets(response, sizeof(response), stdin)) {
+ strtrim(response);
+ if(strlen(response) > 0) {
+ if(multiselect_parse(array, count, response) == -1) {
+ /* only loop if user gave an invalid answer */
+ continue;
+ }
+ }
+ }
+ break;
+ }
+ return(0);
+}
+
+int select_question(int count)
+{
+ char response[32];
+ FILE *stream;
+ int preset = 1;
+
+ if(config->noconfirm) {
+ stream = stdout;
+ } else {
+ /* Use stderr so questions are always displayed when redirecting output */
+ stream = stderr;
+ }
+
+ while(1) {
+ fprintf(stream, "\n");
+ fprintf(stream, _("Enter a number (default=%d)"), preset);
+ fprintf(stream, ": ");
+
+ if(config->noconfirm) {
+ fprintf(stream, "\n");
+ break;
+ }
+
+ if(fgets(response, sizeof(response), stdin)) {
+ strtrim(response);
+ if(strlen(response) > 0) {
+ int n;
+ if(parseindex(response, &n, 1, count) != 0)
+ continue;
+ return(n-1);
+ }
+ }
+ break;
+ }
+
+ return(preset-1);
+}
+
+
/* presents a prompt and gets a Y/N answer */
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 +887,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 +952,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 +984,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 +1014,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..234a631d 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,13 +55,18 @@ 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);
+void select_display(const alpm_list_t *pkglist);
+int select_question(int count);
+int multiselect_question(char *array, int count);
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)));