diff options
Diffstat (limited to 'src/pacman')
-rw-r--r-- | src/pacman/Makefile.am | 2 | ||||
-rw-r--r-- | src/pacman/callback.c | 69 | ||||
-rw-r--r-- | src/pacman/conf.c | 728 | ||||
-rw-r--r-- | src/pacman/conf.h | 31 | ||||
-rw-r--r-- | src/pacman/database.c | 15 | ||||
-rw-r--r-- | src/pacman/deptest.c | 9 | ||||
-rw-r--r-- | src/pacman/package.c | 82 | ||||
-rw-r--r-- | src/pacman/package.h | 10 | ||||
-rw-r--r-- | src/pacman/pacman.c | 711 | ||||
-rw-r--r-- | src/pacman/pacman.h | 5 | ||||
-rw-r--r-- | src/pacman/query.c | 107 | ||||
-rw-r--r-- | src/pacman/remove.c | 49 | ||||
-rw-r--r-- | src/pacman/sync.c | 211 | ||||
-rw-r--r-- | src/pacman/upgrade.c | 57 | ||||
-rw-r--r-- | src/pacman/util.c | 470 | ||||
-rw-r--r-- | src/pacman/util.h | 2 |
16 files changed, 1488 insertions, 1070 deletions
diff --git a/src/pacman/Makefile.am b/src/pacman/Makefile.am index 31e8b134..333b8193 100644 --- a/src/pacman/Makefile.am +++ b/src/pacman/Makefile.am @@ -1,6 +1,7 @@ # paths set at make time conffile = ${sysconfdir}/pacman.conf dbpath = ${localstatedir}/lib/pacman/ +gpgdir = ${sysconfdir}/pacman.d/gnupg/ cachedir = ${localstatedir}/cache/pacman/pkg/ logfile = ${localstatedir}/log/pacman.log @@ -10,6 +11,7 @@ DEFS = -DLOCALEDIR=\"@localedir@\" \ -DCONFFILE=\"$(conffile)\" \ -DROOTDIR=\"$(ROOTDIR)\" \ -DDBPATH=\"$(dbpath)\" \ + -DGPGDIR=\"$(gpgdir)\" \ -DCACHEDIR=\"$(cachedir)\" \ -DLOGFILE=\"$(logfile)\" \ @DEFS@ diff --git a/src/pacman/callback.c b/src/pacman/callback.c index 46ff2e88..4ac3b56b 100644 --- a/src/pacman/callback.c +++ b/src/pacman/callback.c @@ -81,7 +81,7 @@ static double get_update_timediff(int first_call) } } - return(retval); + return retval; } /* refactored from cb_trans_progress */ @@ -176,7 +176,7 @@ void cb_trans_evt(pmtransevt_t event, void *data1, void *data2) } break; case PM_TRANS_EVT_ADD_DONE: - alpm_logaction("installed %s (%s)\n", + alpm_logaction(config->handle, "installed %s (%s)\n", alpm_pkg_get_name(data1), alpm_pkg_get_version(data1)); display_optdepends(data1); @@ -187,7 +187,7 @@ void cb_trans_evt(pmtransevt_t event, void *data1, void *data2) } break; case PM_TRANS_EVT_REMOVE_DONE: - alpm_logaction("removed %s (%s)\n", + alpm_logaction(config->handle, "removed %s (%s)\n", alpm_pkg_get_name(data1), alpm_pkg_get_version(data1)); break; @@ -197,7 +197,7 @@ void cb_trans_evt(pmtransevt_t event, void *data1, void *data2) } break; case PM_TRANS_EVT_UPGRADE_DONE: - alpm_logaction("upgraded %s (%s -> %s)\n", + alpm_logaction(config->handle, "upgraded %s (%s -> %s)\n", (char *)alpm_pkg_get_name(data1), (char *)alpm_pkg_get_version(data2), (char *)alpm_pkg_get_version(data1)); @@ -224,10 +224,10 @@ void cb_trans_evt(pmtransevt_t event, void *data1, void *data2) printf(_("failed.\n")); break; case PM_TRANS_EVT_SCRIPTLET_INFO: - printf("%s", (char*)data1); + printf("%s", (char *)data1); break; case PM_TRANS_EVT_RETRIEVE_START: - printf(_(":: Retrieving packages from %s...\n"), (char*)data1); + printf(_(":: Retrieving packages from %s...\n"), (char *)data1); break; case PM_TRANS_EVT_DISKSPACE_START: if(config->noprogressbar) { @@ -256,8 +256,12 @@ void cb_trans_conv(pmtransconv_t event, void *data1, void *data2, { switch(event) { case PM_TRANS_CONV_INSTALL_IGNOREPKG: - *response = yesno(_(":: %s is in IgnorePkg/IgnoreGroup. Install anyway?"), - alpm_pkg_get_name(data1)); + if(!config->op_s_downloadonly) { + *response = yesno(_(":: %s is in IgnorePkg/IgnoreGroup. Install anyway?"), + alpm_pkg_get_name(data1)); + } else { + *response = 1; + } break; case PM_TRANS_CONV_REPLACE_PKG: *response = yesno(_(":: Replace %s with %s/%s?"), @@ -400,7 +404,7 @@ void cb_trans_progress(pmtransprog_t event, const char *pkgname, int percent, } infolen = cols * 6 / 10; - if (infolen < 50) { + if(infolen < 50) { infolen = 50; } @@ -494,10 +498,11 @@ void cb_dl_progress(const char *filename, off_t file_xfered, off_t file_total) int totaldownload = 0; off_t xfered, total; - double rate = 0.0, timediff = 0.0, f_xfered = 0.0; + double rate = 0.0, timediff = 0.0; unsigned int eta_h = 0, eta_m = 0, eta_s = 0; + double rate_human, xfered_human; + const char *rate_label, *xfered_label; int file_percent = 0, total_percent = 0; - char rate_size = 'K', xfered_size = 'K'; const int cols = getcols(0); @@ -510,7 +515,7 @@ void cb_dl_progress(const char *filename, off_t file_xfered, off_t file_total) } infolen = cols * 6 / 10; - if (infolen < 50) { + if(infolen < 50) { infolen = 50; } /* explanation of magic 28 number at the end */ @@ -561,7 +566,7 @@ void cb_dl_progress(const char *filename, off_t file_xfered, off_t file_total) diff_sec = current_time.tv_sec - initial_time.tv_sec; diff_usec = current_time.tv_usec - initial_time.tv_usec; timediff = diff_sec + (diff_usec / 1000000.0); - rate = xfered / (timediff * 1024.0); + rate = xfered / timediff; /* round elapsed time to the nearest second */ eta_s = (int)(timediff + 0.5); @@ -573,10 +578,10 @@ void cb_dl_progress(const char *filename, off_t file_xfered, off_t file_total) /* return if the calling interval was too short */ return; } - rate = (xfered - xfered_last) / (timediff * 1024.0); + rate = (xfered - xfered_last) / timediff; /* average rate to reduce jumpiness */ rate = (rate + 2 * rate_last) / 3; - eta_s = (total - xfered) / (rate * 1024.0); + eta_s = (total - xfered) / rate; rate_last = rate; xfered_last = xfered; } @@ -630,37 +635,13 @@ void cb_dl_progress(const char *filename, off_t file_xfered, off_t file_total) } - /* Awesome formatting for progress bar. We need a mess of Kb->Mb->Gb stuff - * here. We'll use limit of 2048 for each until we get some empirical */ - /* rate_size = 'K'; was set above */ - if(rate > 2048.0) { - rate /= 1024.0; - rate_size = 'M'; - if(rate > 2048.0) { - rate /= 1024.0; - rate_size = 'G'; - /* we should not go higher than this for a few years (9999.9 Gb/s?)*/ - } - } - - f_xfered = xfered / 1024.0; /* convert to K by default */ - /* xfered_size = 'K'; was set above */ - if(f_xfered > 2048.0) { - f_xfered /= 1024.0; - xfered_size = 'M'; - if(f_xfered > 2048.0) { - f_xfered /= 1024.0; - xfered_size = 'G'; - /* I should seriously hope that archlinux packages never break - * the 9999.9GB mark... we'd have more serious problems than the progress - * bar in pacman */ - } - } + rate_human = humanize_size((off_t)rate, '\0', 0, &rate_label); + xfered_human = humanize_size(xfered, '\0', 0, &xfered_label); /* 1 space + filenamelen + 1 space + 7 for size + 1 + 7 for rate + 2 for /s + 1 space + 8 for eta */ - printf(" %ls%-*s %6.1f%c %#6.1f%c/s %02u:%02u:%02u", wcfname, - padwid, "", f_xfered, xfered_size, - rate, rate_size, eta_h, eta_m, eta_s); + printf(" %ls%-*s %6.1f%s %#6.1f%s/s %02u:%02u:%02u", wcfname, + padwid, "", xfered_human, xfered_label, rate_human, rate_label, + eta_h, eta_m, eta_s); free(fname); free(wcfname); diff --git a/src/pacman/conf.c b/src/pacman/conf.c index e2a168ee..82f525c4 100644 --- a/src/pacman/conf.c +++ b/src/pacman/conf.c @@ -20,13 +20,21 @@ #include "config.h" +#include <errno.h> +#include <glob.h> +#include <limits.h> #include <stdlib.h> #include <stdio.h> #include <string.h> /* strdup */ +#include <sys/stat.h> +#include <sys/utsname.h> /* uname */ +#include <unistd.h> /* pacman */ #include "conf.h" #include "util.h" +#include "pacman.h" +#include "callback.h" /* global config variable */ config_t *config = NULL; @@ -38,35 +46,745 @@ config_t *config_new(void) pm_fprintf(stderr, PM_LOG_ERROR, _("malloc failure: could not allocate %zd bytes\n"), sizeof(config_t)); - return(NULL); + return NULL; } /* defaults which may get overridden later */ newconfig->op = PM_OP_MAIN; newconfig->logmask = PM_LOG_ERROR | PM_LOG_WARNING; - /* CONFFILE is defined at compile-time */ newconfig->configfile = strdup(CONFFILE); + newconfig->sigverify = PM_PGP_VERIFY_UNKNOWN; - return(newconfig); + return newconfig; } int config_free(config_t *oldconfig) { if(oldconfig == NULL) { - return(-1); + return -1; } FREELIST(oldconfig->holdpkg); FREELIST(oldconfig->syncfirst); + FREELIST(oldconfig->ignorepkg); + FREELIST(oldconfig->ignoregrp); + FREELIST(oldconfig->noupgrade); + FREELIST(oldconfig->noextract); free(oldconfig->configfile); free(oldconfig->rootdir); free(oldconfig->dbpath); free(oldconfig->logfile); + free(oldconfig->gpgdir); + FREELIST(oldconfig->cachedirs); free(oldconfig->xfercommand); free(oldconfig->print_format); + free(oldconfig->arch); free(oldconfig); oldconfig = NULL; - return(0); + return 0; +} + +/** Helper function for download_with_xfercommand() */ +static char *get_filename(const char *url) { + char *filename = strrchr(url, '/'); + if(filename != NULL) { + filename++; + } + return filename; +} + +/** Helper function for download_with_xfercommand() */ +static char *get_destfile(const char *path, const char *filename) { + char *destfile; + /* len = localpath len + filename len + null */ + size_t len = strlen(path) + strlen(filename) + 1; + destfile = calloc(len, sizeof(char)); + snprintf(destfile, len, "%s%s", path, filename); + + return destfile; +} + +/** Helper function for download_with_xfercommand() */ +static char *get_tempfile(const char *path, const char *filename) { + char *tempfile; + /* len = localpath len + filename len + '.part' len + null */ + size_t len = strlen(path) + strlen(filename) + 6; + tempfile = calloc(len, sizeof(char)); + snprintf(tempfile, len, "%s%s.part", path, filename); + + return tempfile; +} + +/** External fetch callback */ +static int download_with_xfercommand(const char *url, const char *localpath, + int force) { + int ret = 0; + int retval; + int usepart = 0; + struct stat st; + char *parsedcmd,*tempcmd; + char cwd[PATH_MAX]; + int restore_cwd = 0; + char *destfile, *tempfile, *filename; + + if(!config->xfercommand) { + return -1; + } + + filename = get_filename(url); + if(!filename) { + return -1; + } + destfile = get_destfile(localpath, filename); + tempfile = get_tempfile(localpath, filename); + + if(force && stat(tempfile, &st) == 0) { + unlink(tempfile); + } + if(force && stat(destfile, &st) == 0) { + unlink(destfile); + } + + tempcmd = strdup(config->xfercommand); + /* replace all occurrences of %o with fn.part */ + if(strstr(tempcmd, "%o")) { + usepart = 1; + parsedcmd = strreplace(tempcmd, "%o", tempfile); + free(tempcmd); + tempcmd = parsedcmd; + } + /* replace all occurrences of %u with the download URL */ + 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 */ + if(chdir(localpath)) { + pm_printf(PM_LOG_WARNING, _("could not chdir to download directory %s\n"), localpath); + ret = -1; + goto cleanup; + } + /* execute the parsed command via /bin/sh -c */ + pm_printf(PM_LOG_DEBUG, "running command: %s\n", parsedcmd); + retval = system(parsedcmd); + + if(retval == -1) { + pm_printf(PM_LOG_WARNING, _("running XferCommand: fork failed!\n")); + ret = -1; + } else if(retval != 0) { + /* download failed */ + pm_printf(PM_LOG_DEBUG, "XferCommand command returned non-zero status " + "code (%d)\n", retval); + ret = -1; + } else { + /* download was successful */ + if(usepart) { + rename(tempfile, destfile); + } + ret = 0; + } + +cleanup: + /* 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); + } + free(destfile); + free(tempfile); + free(parsedcmd); + + return ret; +} + + +int config_set_arch(const char *arch) +{ + if(strcmp(arch, "auto") == 0) { + struct utsname un; + uname(&un); + config->arch = strdup(un.machine); + } else { + config->arch = strdup(arch); + } + pm_printf(PM_LOG_DEBUG, "config: arch: %s\n", config->arch); + return 0; +} + +static pgp_verify_t option_verifysig(const char *value) +{ + pgp_verify_t level; + if(strcmp(value, "Always") == 0) { + level = PM_PGP_VERIFY_ALWAYS; + } else if(strcmp(value, "Optional") == 0) { + level = PM_PGP_VERIFY_OPTIONAL; + } else if(strcmp(value, "Never") == 0) { + level = PM_PGP_VERIFY_NEVER; + } else { + level = PM_PGP_VERIFY_UNKNOWN; + } + pm_printf(PM_LOG_DEBUG, "config: VerifySig = %s (%d)\n", value, level); + return level; +} + +static int process_cleanmethods(alpm_list_t *values) { + alpm_list_t *i; + for(i = values; i; i = alpm_list_next(i)) { + const char *value = i->data; + 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; + } + } + return 0; +} + +/** 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. + * @param ptr a pointer to the start of the multiple options + * @param option the string (friendly) name of the option, used for messages + * @param list the list to add the option to + */ +static void setrepeatingoption(char *ptr, const char *option, + alpm_list_t **list) +{ + char *q; + + while((q = strchr(ptr, ' '))) { + *q = '\0'; + *list = alpm_list_add(*list, strdup(ptr)); + pm_printf(PM_LOG_DEBUG, "config: %s: %s\n", option, ptr); + ptr = q; + ptr++; + } + *list = alpm_list_add(*list, strdup(ptr)); + pm_printf(PM_LOG_DEBUG, "config: %s: %s\n", option, ptr); +} + +static int _parse_options(const char *key, char *value, + const char *file, int linenum) +{ + if(value == NULL) { + /* options without settings */ + if(strcmp(key, "UseSyslog") == 0) { + config->usesyslog = 1; + pm_printf(PM_LOG_DEBUG, "config: usesyslog\n"); + } else if(strcmp(key, "ILoveCandy") == 0) { + config->chomp = 1; + pm_printf(PM_LOG_DEBUG, "config: chomp\n"); + } else if(strcmp(key, "VerbosePkgLists") == 0) { + config->verbosepkglists = 1; + pm_printf(PM_LOG_DEBUG, "config: verbosepkglists\n"); + } else if(strcmp(key, "UseDelta") == 0) { + config->usedelta = 1; + pm_printf(PM_LOG_DEBUG, "config: usedelta\n"); + } else if(strcmp(key, "TotalDownload") == 0) { + config->totaldownload = 1; + pm_printf(PM_LOG_DEBUG, "config: totaldownload\n"); + } else if(strcmp(key, "CheckSpace") == 0) { + config->checkspace = 1; + } else { + pm_printf(PM_LOG_WARNING, + _("config file %s, line %d: directive '%s' in section '%s' not recognized.\n"), + file, linenum, key, "options"); + } + } else { + /* options with settings */ + if(strcmp(key, "NoUpgrade") == 0) { + setrepeatingoption(value, "NoUpgrade", &(config->noupgrade)); + } else if(strcmp(key, "NoExtract") == 0) { + setrepeatingoption(value, "NoExtract", &(config->noextract)); + } else if(strcmp(key, "IgnorePkg") == 0) { + setrepeatingoption(value, "IgnorePkg", &(config->ignorepkg)); + } else if(strcmp(key, "IgnoreGroup") == 0) { + setrepeatingoption(value, "IgnoreGroup", &(config->ignoregrp)); + } else if(strcmp(key, "HoldPkg") == 0) { + setrepeatingoption(value, "HoldPkg", &(config->holdpkg)); + } else if(strcmp(key, "SyncFirst") == 0) { + setrepeatingoption(value, "SyncFirst", &(config->syncfirst)); + } else if(strcmp(key, "CacheDir") == 0) { + setrepeatingoption(value, "CacheDir", &(config->cachedirs)); + } else if(strcmp(key, "Architecture") == 0) { + if(!config->arch) { + config_set_arch(value); + } + } else if(strcmp(key, "DBPath") == 0) { + /* don't overwrite a path specified on the command line */ + if(!config->dbpath) { + config->dbpath = strdup(value); + pm_printf(PM_LOG_DEBUG, "config: dbpath: %s\n", value); + } + } else if(strcmp(key, "RootDir") == 0) { + /* don't overwrite a path specified on the command line */ + if(!config->rootdir) { + config->rootdir = strdup(value); + pm_printf(PM_LOG_DEBUG, "config: rootdir: %s\n", value); + } + } else if(strcmp(key, "GPGDir") == 0) { + if(!config->gpgdir) { + config->gpgdir = strdup(value); + pm_printf(PM_LOG_DEBUG, "config: gpgdir: %s\n", value); + } + } else if(strcmp(key, "LogFile") == 0) { + if(!config->logfile) { + config->logfile = strdup(value); + pm_printf(PM_LOG_DEBUG, "config: logfile: %s\n", value); + } + } else if(strcmp(key, "XferCommand") == 0) { + config->xfercommand = strdup(value); + pm_printf(PM_LOG_DEBUG, "config: xfercommand: %s\n", value); + } else if(strcmp(key, "CleanMethod") == 0) { + alpm_list_t *methods = NULL; + setrepeatingoption(value, "CleanMethod", &methods); + if(process_cleanmethods(methods)) { + FREELIST(methods); + return 1; + } + FREELIST(methods); + } else if(strcmp(key, "VerifySig") == 0) { + pgp_verify_t level = option_verifysig(value); + if(level != PM_PGP_VERIFY_UNKNOWN) { + config->sigverify = level; + } else { + pm_printf(PM_LOG_ERROR, + _("config file %s, line %d: directive '%s' has invalid value '%s'\n"), + file, linenum, key, value); + return 1; + } + } else { + pm_printf(PM_LOG_WARNING, + _("config file %s, line %d: directive '%s' in section '%s' not recognized.\n"), + file, linenum, key, "options"); + } + + } + return 0; +} + +static int _add_mirror(pmdb_t *db, char *value) +{ + const char *dbname = alpm_db_get_name(db); + /* let's attempt a replacement for the current repo */ + char *temp = strreplace(value, "$repo", dbname); + /* let's attempt a replacement for the arch */ + const char *arch = config->arch; + char *server; + if(arch) { + server = strreplace(temp, "$arch", arch); + free(temp); + } else { + if(strstr(temp, "$arch")) { + free(temp); + pm_printf(PM_LOG_ERROR, _("The mirror '%s' contains the $arch" + " variable, but no Architecture is defined.\n"), value); + return 1; + } + server = temp; + } + + if(alpm_db_add_server(db, server) != 0) { + /* pm_errno is set by alpm_db_setserver */ + pm_printf(PM_LOG_ERROR, _("could not add server URL to database '%s': %s (%s)\n"), + dbname, server, alpm_strerror(alpm_errno(config->handle))); + free(server); + return 1; + } + + free(server); + return 0; +} + +/** Sets up libalpm global stuff in one go. Called after the command line + * and inital config file parsing. Once this is complete, we can see if any + * paths were defined. If a rootdir was defined and nothing else, we want all + * of our paths to live under the rootdir that was specified. Safe to call + * multiple times (will only do anything the first time). + */ +static int setup_libalpm(void) +{ + int ret = 0; + enum _pmerrno_t err; + pmhandle_t *handle; + + pm_printf(PM_LOG_DEBUG, "setup_libalpm called\n"); + + /* Configure root path first. If it is set and dbpath/logfile were not + * set, then set those as well to reside under the root. */ + if(config->rootdir) { + char path[PATH_MAX]; + if(!config->dbpath) { + snprintf(path, PATH_MAX, "%s/%s", config->rootdir, DBPATH + 1); + config->dbpath = strdup(path); + } + if(!config->logfile) { + snprintf(path, PATH_MAX, "%s/%s", config->rootdir, LOGFILE + 1); + config->logfile = strdup(path); + } + } else { + config->rootdir = strdup(ROOTDIR); + if(!config->dbpath) { + config->dbpath = strdup(DBPATH); + } + } + + /* initialize library */ + handle = alpm_initialize(config->rootdir, config->dbpath, &err); + if(!handle) { + pm_printf(PM_LOG_ERROR, _("failed to initialize alpm library (%s)\n"), + alpm_strerror(err)); + return -1; + } + config->handle = handle; + + alpm_option_set_logcb(handle, cb_log); + alpm_option_set_dlcb(handle, cb_dl_progress); + + config->logfile = config->logfile ? config->logfile : strdup(LOGFILE); + ret = alpm_option_set_logfile(handle, config->logfile); + if(ret != 0) { + pm_printf(PM_LOG_ERROR, _("problem setting logfile '%s' (%s)\n"), + config->logfile, alpm_strerror(alpm_errno(config->handle))); + return ret; + } + + /* Set GnuPG's home directory. This is not relative to rootdir, even if + * rootdir is defined. Reasoning: gpgdir contains configuration data. */ + config->gpgdir = config->gpgdir ? config->gpgdir : strdup(GPGDIR); + ret = alpm_option_set_signaturedir(handle, config->gpgdir); + if(ret != 0) { + pm_printf(PM_LOG_ERROR, _("problem setting gpgdir '%s' (%s)\n"), + config->gpgdir, alpm_strerror(alpm_errno(config->handle))); + return ret; + } + + /* add a default cachedir if one wasn't specified */ + if(config->cachedirs == NULL) { + alpm_option_add_cachedir(handle, CACHEDIR); + } else { + alpm_option_set_cachedirs(handle, config->cachedirs); + } + + if(config->sigverify != PM_PGP_VERIFY_UNKNOWN) { + alpm_option_set_default_sigverify(handle, config->sigverify); + } + + if(config->xfercommand) { + alpm_option_set_fetchcb(handle, download_with_xfercommand); + } + + if(config->totaldownload) { + alpm_option_set_totaldlcb(handle, cb_dl_total); + } + + alpm_option_set_arch(handle, config->arch); + alpm_option_set_checkspace(handle, config->checkspace); + alpm_option_set_usesyslog(handle, config->usesyslog); + alpm_option_set_usedelta(handle, config->usedelta); + + alpm_option_set_ignorepkgs(handle, config->ignorepkg); + alpm_option_set_ignoregrps(handle, config->ignoregrp); + alpm_option_set_noupgrades(handle, config->noupgrade); + alpm_option_set_noextracts(handle, config->noextract); + + return 0; +} + +/** + * Allows parsing in advance of an entire config section before we start + * calling library methods. + */ +struct section_t { + /* useful for all sections */ + char *name; + int is_options; + /* db section option gathering */ + pgp_verify_t sigverify; + alpm_list_t *servers; +}; + +/** + * Wrap up a section once we have reached the end of it. This should be called + * when a subsequent section is encountered, or when we have reached the end of + * the root config file. Once called, all existing saved config pieces on the + * section struct are freed. + * @param section the current parsed and saved section data + * @param parse_options whether we are parsing options or repo data + * @return 0 on success, 1 on failure + */ +static int finish_section(struct section_t *section, int parse_options) +{ + int ret = 0; + alpm_list_t *i; + pmdb_t *db; + + pm_printf(PM_LOG_DEBUG, "config: finish section '%s'\n", section->name); + + /* parsing options (or nothing)- nothing to do except free the pieces */ + if(!section->name || parse_options || section->is_options) { + goto cleanup; + } + + /* if we are not looking at options sections only, register a db */ + db = alpm_db_register_sync(config->handle, section->name); + if(db == NULL) { + pm_printf(PM_LOG_ERROR, _("could not register '%s' database (%s)\n"), + section->name, alpm_strerror(alpm_errno(config->handle))); + ret = 1; + goto cleanup; + } + + if(section->sigverify) { + if(alpm_db_set_pgp_verify(db, section->sigverify)) { + pm_printf(PM_LOG_ERROR, + _("could not set verify option for database '%s' (%s)\n"), + section->name, alpm_strerror(alpm_errno(config->handle))); + ret = 1; + goto cleanup; + } + } + + for(i = section->servers; i; i = alpm_list_next(i)) { + char *value = alpm_list_getdata(i); + if(_add_mirror(db, value) != 0) { + pm_printf(PM_LOG_ERROR, + _("could not add mirror '%s' to database '%s' (%s)\n"), + value, section->name, alpm_strerror(alpm_errno(config->handle))); + ret = 1; + goto cleanup; + } + free(value); + } + +cleanup: + alpm_list_free(section->servers); + section->servers = NULL; + section->sigverify = 0; + free(section->name); + section->name = NULL; + return ret; +} + +/** The "real" parseconfig. Each "Include" directive will recall this method so + * recursion and stack depth are limited to 10 levels. The publicly visible + * parseconfig calls this with a NULL section argument so we can recall from + * within ourself on an include. + * @param file path to the config file + * @param section the current active section + * @param parse_options whether to parse and call methods for the options + * section; if 0, parse and call methods for the repos sections + * @param depth the current recursion depth + * @return 0 on success, 1 on failure + */ +static int _parseconfig(const char *file, struct section_t *section, + int parse_options, int depth) +{ + FILE *fp = NULL; + char line[PATH_MAX]; + int linenum = 0; + int ret = 0; + const int max_depth = 10; + + if(depth >= max_depth) { + pm_printf(PM_LOG_ERROR, + _("config parsing exceeded max recursion depth of %d.\n"), max_depth); + ret = 1; + goto cleanup; + } + + pm_printf(PM_LOG_DEBUG, "config: attempting to read file %s\n", file); + fp = fopen(file, "r"); + if(fp == NULL) { + pm_printf(PM_LOG_ERROR, _("config file %s could not be read.\n"), file); + ret = 1; + goto cleanup; + } + + while(fgets(line, PATH_MAX, fp)) { + char *key, *value, *ptr; + size_t line_len; + + linenum++; + strtrim(line); + line_len = strlen(line); + + /* ignore whole line and end of line comments */ + if(line_len == 0 || line[0] == '#') { + continue; + } + if((ptr = strchr(line, '#'))) { + *ptr = '\0'; + } + + if(line[0] == '[' && line[line_len - 1] == ']') { + char *name; + /* only possibility here is a line == '[]' */ + if(line_len <= 2) { + pm_printf(PM_LOG_ERROR, _("config file %s, line %d: bad section name.\n"), + file, linenum); + ret = 1; + goto cleanup; + } + /* new config section, skip the '[' */ + name = strdup(line + 1); + name[line_len - 2] = '\0'; + /* we're at a new section; perform any post-actions for the prior */ + if(finish_section(section, parse_options)) { + ret = 1; + goto cleanup; + } + pm_printf(PM_LOG_DEBUG, "config: new section '%s'\n", name); + section->name = name; + section->is_options = (strcmp(name, "options") == 0); + continue; + } + + /* directive */ + /* strsep modifies the 'line' string: 'key \0 value' */ + key = line; + value = line; + strsep(&value, "="); + strtrim(key); + strtrim(value); + + if(key == NULL) { + pm_printf(PM_LOG_ERROR, _("config file %s, line %d: syntax error in config file- missing key.\n"), + file, linenum); + ret = 1; + goto cleanup; + } + /* For each directive, compare to the camelcase string. */ + if(section->name == NULL) { + pm_printf(PM_LOG_ERROR, _("config file %s, line %d: All directives must belong to a section.\n"), + file, linenum); + ret = 1; + goto cleanup; + } + /* Include is allowed in both options and repo sections */ + if(strcmp(key, "Include") == 0) { + glob_t globbuf; + int globret; + size_t gindex; + + if(value == NULL) { + pm_printf(PM_LOG_ERROR, _("config file %s, line %d: directive '%s' needs a value\n"), + file, linenum, key); + ret = 1; + goto cleanup; + } + /* Ignore include failures... assume non-critical */ + globret = glob(value, GLOB_NOCHECK, NULL, &globbuf); + switch(globret) { + case GLOB_NOSPACE: + pm_printf(PM_LOG_DEBUG, + "config file %s, line %d: include globbing out of space\n", + file, linenum); + break; + case GLOB_ABORTED: + pm_printf(PM_LOG_DEBUG, + "config file %s, line %d: include globbing read error for %s\n", + file, linenum, value); + break; + case GLOB_NOMATCH: + pm_printf(PM_LOG_DEBUG, + "config file %s, line %d: no include found for %s\n", + file, linenum, value); + break; + default: + for(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, parse_options, depth + 1); + } + break; + } + globfree(&globbuf); + continue; + } + if(parse_options && section->is_options) { + /* we are either in options ... */ + if((ret = _parse_options(key, value, file, linenum)) != 0) { + goto cleanup; + } + } else if (!parse_options && !section->is_options) { + /* ... or in a repo section */ + if(strcmp(key, "Server") == 0) { + if(value == NULL) { + pm_printf(PM_LOG_ERROR, _("config file %s, line %d: directive '%s' needs a value\n"), + file, linenum, key); + ret = 1; + goto cleanup; + } + section->servers = alpm_list_add(section->servers, strdup(value)); + } else if(strcmp(key, "VerifySig") == 0) { + pgp_verify_t level = option_verifysig(value); + if(level != PM_PGP_VERIFY_UNKNOWN) { + section->sigverify = level; + } else { + pm_printf(PM_LOG_ERROR, + _("config file %s, line %d: directive '%s' has invalid value '%s'\n"), + file, linenum, key, value); + ret = 1; + goto cleanup; + } + } else { + pm_printf(PM_LOG_WARNING, + _("config file %s, line %d: directive '%s' in section '%s' not recognized.\n"), + file, linenum, key, section->name); + } + } + } + + if(depth == 0) { + ret = finish_section(section, parse_options); + } + +cleanup: + fclose(fp); + pm_printf(PM_LOG_DEBUG, "config: finished parsing %s\n", file); + return ret; +} + +/** Parse a configuration file. + * @param file path to the config file + * @return 0 on success, non-zero on error + */ +int parseconfig(const char *file) +{ + int ret; + struct section_t section; + memset(§ion, 0, sizeof(struct section_t)); + /* the config parse is a two-pass affair. We first parse the entire thing for + * the [options] section so we can get all default and path options set. + * Next, we go back and parse everything but [options]. */ + + /* call the real parseconfig function with a null section & db argument */ + pm_printf(PM_LOG_DEBUG, "parseconfig: options pass\n"); + if((ret = _parseconfig(file, §ion, 1, 0))) { + return ret; + } + if((ret = setup_libalpm())) { + return ret; + } + /* second pass, repo section parsing */ + pm_printf(PM_LOG_DEBUG, "parseconfig: repo pass\n"); + return _parseconfig(file, §ion, 0, 0); } /* vim: set ts=2 sw=2 noet: */ diff --git a/src/pacman/conf.h b/src/pacman/conf.h index 92c379fc..4c44bfdd 100644 --- a/src/pacman/conf.h +++ b/src/pacman/conf.h @@ -32,6 +32,10 @@ typedef struct __config_t { unsigned short noprogressbar; unsigned short logmask; unsigned short print; + unsigned short checkspace; + unsigned short usesyslog; + unsigned short usedelta; + char *arch; char *print_format; /* unfortunately, we have to keep track of paths both here and in the library * because they can come from both the command line or config file, and we @@ -40,7 +44,8 @@ typedef struct __config_t { char *rootdir; char *dbpath; char *logfile; - /* TODO how to handle cachedirs? */ + char *gpgdir; + alpm_list_t *cachedirs; unsigned short op_q_isfile; unsigned short op_q_info; @@ -63,20 +68,31 @@ typedef struct __config_t { unsigned short op_s_upgrade; unsigned short group; - pmtransflag_t flags; unsigned short noask; unsigned int ask; + pmtransflag_t flags; + pgp_verify_t sigverify; /* conf file options */ - unsigned short chomp; /* I Love Candy! */ - unsigned short showsize; /* show individual package sizes */ + /* I Love Candy! */ + unsigned short chomp; + /* format target pkg lists as table */ + unsigned short verbosepkglists; /* When downloading, display the amount downloaded, rate, ETA, and percent * downloaded of the total download list */ unsigned short totaldownload; - unsigned short cleanmethod; /* select -Sc behavior */ + /* select -Sc behavior */ + unsigned short cleanmethod; alpm_list_t *holdpkg; alpm_list_t *syncfirst; + alpm_list_t *ignorepkg; + alpm_list_t *ignoregrp; + alpm_list_t *noupgrade; + alpm_list_t *noextract; char *xfercommand; + + /* our connection to libalpm */ + pmhandle_t *handle; } config_t; /* Operations */ @@ -106,7 +122,8 @@ enum { OP_NEEDED, OP_ASEXPLICIT, OP_ARCH, - OP_PRINTFORMAT + OP_PRINTFORMAT, + OP_GPGDIR }; /* clean method */ @@ -121,6 +138,8 @@ extern config_t *config; config_t *config_new(void); int config_free(config_t *oldconfig); +int config_set_arch(const char *arch); +int parseconfig(const char *file); #endif /* _PM_CONF_H */ /* vim: set ts=2 sw=2 noet: */ diff --git a/src/pacman/database.c b/src/pacman/database.c index 36433f33..292fa54a 100644 --- a/src/pacman/database.c +++ b/src/pacman/database.c @@ -20,7 +20,6 @@ #include "config.h" -#include <stdlib.h> #include <stdio.h> #include <alpm.h> @@ -47,7 +46,7 @@ int pacman_database(alpm_list_t *targets) if(targets == NULL) { pm_printf(PM_LOG_ERROR, _("no targets specified (use -h for help)\n")); - return(1); + return 1; } if(config->flags & PM_TRANS_FLAG_ALLDEPS) { /* --asdeps */ @@ -56,20 +55,20 @@ int pacman_database(alpm_list_t *targets) reason = PM_PKG_REASON_EXPLICIT; } else { pm_printf(PM_LOG_ERROR, _("no install reason specified (use -h for help)\n")); - return(1); + return 1; } /* Lock database */ if(trans_init(0) == -1) { - return(1); + return 1; } - db_local = alpm_option_get_localdb(); + db_local = alpm_option_get_localdb(config->handle); for(i = targets; i; i = alpm_list_next(i)) { char *pkgname = i->data; if(alpm_db_set_pkgreason(db_local, pkgname, reason) == -1) { pm_printf(PM_LOG_ERROR, _("could not set install reason for package %s (%s)\n"), - pkgname, alpm_strerrorlast()); + pkgname, alpm_strerror(alpm_errno(config->handle))); retval = 1; } else { if(reason == PM_PKG_REASON_DEPEND) { @@ -82,9 +81,9 @@ int pacman_database(alpm_list_t *targets) /* Unlock database */ if(trans_release() == -1) { - return(1); + return 1; } - return(retval); + return retval; } /* vim: set ts=2 sw=2 noet: */ diff --git a/src/pacman/deptest.c b/src/pacman/deptest.c index 8895b487..99abd72d 100644 --- a/src/pacman/deptest.c +++ b/src/pacman/deptest.c @@ -20,23 +20,20 @@ #include "config.h" -#include <stdlib.h> #include <stdio.h> -#include <string.h> #include <alpm.h> #include <alpm_list.h> /* pacman */ #include "pacman.h" -#include "util.h" #include "conf.h" int pacman_deptest(alpm_list_t *targets) { alpm_list_t *i; alpm_list_t *deps = NULL; - pmdb_t *localdb = alpm_option_get_localdb(); + pmdb_t *localdb = alpm_option_get_localdb(config->handle); for(i = targets; i; i = alpm_list_next(i)) { char *target = alpm_list_getdata(i); @@ -47,7 +44,7 @@ int pacman_deptest(alpm_list_t *targets) } if(deps == NULL) { - return(0); + return 0; } for(i = deps; i; i = alpm_list_next(i)) { @@ -56,7 +53,7 @@ int pacman_deptest(alpm_list_t *targets) printf("%s\n", dep); } alpm_list_free(deps); - return(127); + return 127; } /* vim: set ts=2 sw=2 noet: */ diff --git a/src/pacman/package.c b/src/pacman/package.c index 77a5ee72..9cdb4877 100644 --- a/src/pacman/package.c +++ b/src/pacman/package.c @@ -26,7 +26,6 @@ #include <unistd.h> #include <limits.h> #include <errno.h> -#include <wchar.h> #include <alpm.h> #include <alpm_list.h> @@ -34,23 +33,25 @@ /* pacman */ #include "package.h" #include "util.h" +#include "conf.h" #define CLBUF_SIZE 4096 -/* Display the content of a package - * - * levels: - * <-1 - sync package, extra information (required by) [-Sii] - * -1 - sync package, normal level [-Si] - * =0 - file query [-Qip] - * 1 - localdb query, normal level [-Qi] - * >1 - localdb query, extra information (backup files) [-Qii] +/** + * Display the details of a package. + * Extra information entails 'required by' info for sync packages and backup + * files info for local packages. + * @param pkg package to display information for + * @param from the type of package we are dealing with + * @param extra should we show extra information */ -void dump_pkg_full(pmpkg_t *pkg, int level) +void dump_pkg_full(pmpkg_t *pkg, enum pkg_from from, int extra) { const char *reason; time_t bdate, idate; char bdatestr[50] = "", idatestr[50] = ""; + const char *label; + double size; const alpm_list_t *i; alpm_list_t *requiredby = NULL, *depstrings = NULL; @@ -82,16 +83,20 @@ void dump_pkg_full(pmpkg_t *pkg, int level) /* turn depends list into a text list */ for(i = alpm_pkg_get_depends(pkg); i; i = alpm_list_next(i)) { - pmdepend_t *dep = (pmdepend_t*)alpm_list_getdata(i); + pmdepend_t *dep = (pmdepend_t *)alpm_list_getdata(i); depstrings = alpm_list_add(depstrings, alpm_dep_compute_string(dep)); } - if(level > 0 || level < -1) { + if(extra || from == PKG_FROM_LOCALDB) { /* compute this here so we don't get a pause in the middle of output */ requiredby = alpm_pkg_compute_requiredby(pkg); } /* actual output */ + if(from == PKG_FROM_SYNCDB) { + string_display(_("Repository :"), + alpm_db_get_name(alpm_pkg_get_db(pkg))); + } string_display(_("Name :"), alpm_pkg_get_name(pkg)); string_display(_("Version :"), alpm_pkg_get_version(pkg)); string_display(_("URL :"), alpm_pkg_get_url(pkg)); @@ -100,42 +105,41 @@ void dump_pkg_full(pmpkg_t *pkg, int level) list_display(_("Provides :"), alpm_pkg_get_provides(pkg)); list_display(_("Depends On :"), depstrings); list_display_linebreak(_("Optional Deps :"), alpm_pkg_get_optdepends(pkg)); - if(level > 0 || level < -1) { + if(extra || from == PKG_FROM_LOCALDB) { list_display(_("Required By :"), requiredby); } list_display(_("Conflicts With :"), alpm_pkg_get_conflicts(pkg)); list_display(_("Replaces :"), alpm_pkg_get_replaces(pkg)); - if(level < 0) { - printf(_("Download Size : %6.2f K\n"), - (double)alpm_pkg_get_size(pkg) / 1024.0); - } - if(level == 0) { - printf(_("Compressed Size: %6.2f K\n"), - (double)alpm_pkg_get_size(pkg) / 1024.0); + + size = humanize_size(alpm_pkg_get_size(pkg), 'K', 1, &label); + if(from == PKG_FROM_SYNCDB) { + printf(_("Download Size : %6.2f %s\n"), size, label); + } else if(from == PKG_FROM_FILE) { + printf(_("Compressed Size: %6.2f %s\n"), size, label); } - printf(_("Installed Size : %6.2f K\n"), - (double)alpm_pkg_get_isize(pkg) / 1024.0); + size = humanize_size(alpm_pkg_get_isize(pkg), 'K', 1, &label); + printf(_("Installed Size : %6.2f %s\n"), size, label); + string_display(_("Packager :"), alpm_pkg_get_packager(pkg)); string_display(_("Architecture :"), alpm_pkg_get_arch(pkg)); string_display(_("Build Date :"), bdatestr); - if(level > 0) { + if(from == PKG_FROM_LOCALDB) { string_display(_("Install Date :"), idatestr); string_display(_("Install Reason :"), reason); } - if(level >= 0) { + if(from == PKG_FROM_FILE || from == PKG_FROM_LOCALDB) { string_display(_("Install Script :"), alpm_pkg_has_scriptlet(pkg) ? _("Yes") : _("No")); } - /* MD5 Sum for sync package */ - if(level < 0) { + if(from == PKG_FROM_SYNCDB) { string_display(_("MD5 Sum :"), alpm_pkg_get_md5sum(pkg)); } string_display(_("Description :"), alpm_pkg_get_desc(pkg)); /* Print additional package info if info flag passed more than once */ - if(level > 1) { + if(from == PKG_FROM_LOCALDB && extra) { dump_pkg_backups(pkg); } @@ -146,23 +150,11 @@ void dump_pkg_full(pmpkg_t *pkg, int level) FREELIST(requiredby); } -/* Display the content of a sync package - */ -void dump_pkg_sync(pmpkg_t *pkg, const char *treename, int level) -{ - if(pkg == NULL) { - return; - } - string_display(_("Repository :"), treename); - /* invert the level since we are a sync package */ - 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; + const char *ret; snprintf(path, PATH_MAX, "%s%s", root, filename); @@ -173,11 +165,11 @@ static const char *get_backup_file_status(const char *root, if(md5sum == NULL) { pm_fprintf(stderr, PM_LOG_ERROR, _("could not calculate checksums for %s\n"), path); - return(NULL); + return NULL; } /* if checksums don't match, file has been modified */ - if (strcmp(md5sum, expected_md5) != 0) { + if(strcmp(md5sum, expected_md5) != 0) { ret = "MODIFIED"; } else { ret = "UNMODIFIED"; @@ -195,7 +187,7 @@ static const char *get_backup_file_status(const char *root, ret = "UNKNOWN"; } } - return(ret); + return ret; } /* Display list of backup files and their modification states @@ -203,7 +195,7 @@ static const char *get_backup_file_status(const char *root, void dump_pkg_backups(pmpkg_t *pkg) { alpm_list_t *i; - const char *root = alpm_option_get_root(); + const char *root = alpm_option_get_root(config->handle); printf(_("Backup Files:\n")); if(alpm_pkg_get_backup(pkg)) { /* package has backup files, so print them */ @@ -236,7 +228,7 @@ void dump_pkg_files(pmpkg_t *pkg, int quiet) pkgname = alpm_pkg_get_name(pkg); pkgfiles = alpm_pkg_get_files(pkg); - root = alpm_option_get_root(); + root = alpm_option_get_root(config->handle); for(i = pkgfiles; i; i = alpm_list_next(i)) { filestr = alpm_list_getdata(i); diff --git a/src/pacman/package.h b/src/pacman/package.h index 26333c5a..7a5e5853 100644 --- a/src/pacman/package.h +++ b/src/pacman/package.h @@ -22,8 +22,14 @@ #include <alpm.h> -void dump_pkg_full(pmpkg_t *pkg, int level); -void dump_pkg_sync(pmpkg_t *pkg, const char *treename, int level); +/* TODO it would be nice if we didn't duplicate a backend type */ +enum pkg_from { + PKG_FROM_FILE = 1, + PKG_FROM_LOCALDB, + PKG_FROM_SYNCDB +}; + +void dump_pkg_full(pmpkg_t *pkg, enum pkg_from from, int extra); void dump_pkg_backups(pmpkg_t *pkg); void dump_pkg_files(pmpkg_t *pkg, int quiet); diff --git a/src/pacman/pacman.c b/src/pacman/pacman.c index 347d8af9..afc79f6f 100644 --- a/src/pacman/pacman.c +++ b/src/pacman/pacman.c @@ -36,12 +36,9 @@ #include <signal.h> #include <unistd.h> #include <sys/types.h> -#include <sys/stat.h> #include <sys/utsname.h> /* uname */ #include <locale.h> /* setlocale */ -#include <time.h> /* time_t */ #include <errno.h> -#include <glob.h> #if defined(PACMAN_DEBUG) && defined(HAVE_MCHECK_H) #include <mcheck.h> /* debug tracing (mtrace) */ #endif @@ -53,9 +50,7 @@ /* pacman */ #include "pacman.h" #include "util.h" -#include "callback.h" #include "conf.h" -#include "package.h" /* list of targets specified on command line */ static alpm_list_t *pm_targets; @@ -66,9 +61,9 @@ 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); + 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++; @@ -87,15 +82,15 @@ static int options_cmp(const void *p1, const void *p2) s2++; } else if(*s2 == '-') { /* s1 short, s2 long */ - return(-1); + return -1; } else if(*s1 == '-') { /* s1 long, s2 short */ - return(1); + return 1; } /* two short -> strcmp */ } - return(strcmp(s1, s2)); + return strcmp(s1, s2); } /** Display usage/syntax for the specified operation. @@ -170,7 +165,7 @@ static void usage(int op, const char * const myname) 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) { + } 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); addlist(_(" --asdeps mark packages as non-explicitly installed\n")); @@ -207,6 +202,7 @@ static void usage(int op, const char * const myname) 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(_(" --gpgdir <path> set an alternate home directory for GnuPG\n")); addlist(_(" --logfile <path> set an alternate log file\n")); addlist(_(" --noconfirm do not ask for any confirmation\n")); } @@ -239,7 +235,7 @@ static void version(void) static void localize(void) { static int init = 0; - if (!init) { + if(!init) { setlocale(LC_ALL, ""); bindtextdomain(PACKAGE, LOCALEDIR); textdomain(PACKAGE); @@ -261,27 +257,14 @@ static void setuseragent(void) setenv("HTTP_USER_AGENT", agent, 0); } -static void setarch(const char *arch) -{ - if (strcmp(arch, "auto") == 0) { - struct utsname un; - uname(&un); - pm_printf(PM_LOG_DEBUG, "config: Architecture: %s\n", un.machine); - alpm_option_set_arch(un.machine); - } else { - pm_printf(PM_LOG_DEBUG, "config: Architecture: %s\n", arch); - alpm_option_set_arch(arch); - } -} - /** Free the resources. * * @param ret the return value */ static void cleanup(int ret) { /* free alpm library resources */ - if(alpm_release() == -1) { - pm_printf(PM_LOG_ERROR, "%s\n", alpm_strerrorlast()); + if(config->handle && alpm_release(config->handle) == -1) { + pm_printf(PM_LOG_ERROR, "error releasing alpm library\n"); } /* free memory */ @@ -302,7 +285,7 @@ static ssize_t xwrite(int fd, const void *buf, size_t count) do { ret = write(fd, buf, count); } while(ret == -1 && errno == EINTR); - return(ret); + return ret; } /** Catches thrown signals. Performs necessary cleanup to ensure database is @@ -321,98 +304,34 @@ static void handler(int signum) xwrite(out, msg1, strlen(msg1)); xwrite(err, msg2, strlen(msg2)); exit(signum); - } else if((signum == SIGINT)) { + } else if(signum == SIGINT) { const char *msg = "\nInterrupt signal received\n"; xwrite(err, msg, strlen(msg)); - if(alpm_trans_interrupt() == 0) { + if(alpm_trans_interrupt(config->handle) == 0) { /* a transaction is being interrupted, don't exit pacman yet. */ return; } /* no commiting transaction, we can release it now and then exit pacman */ - alpm_trans_release(); + alpm_trans_release(config->handle); /* output a newline to be sure we clear any line we may be on */ xwrite(out, "\n", 1); } cleanup(signum); } -/** Sets all libalpm required paths in one go. Called after the command line - * and inital config file parsing. Once this is complete, we can see if any - * paths were defined. If a rootdir was defined and nothing else, we want all - * of our paths to live under the rootdir that was specified. Safe to call - * multiple times (will only do anything the first time). - */ -static void setlibpaths(void) -{ - static int init = 0; - if (!init) { - int ret = 0; - - pm_printf(PM_LOG_DEBUG, "setlibpaths() called\n"); - /* Configure root path first. If it is set and dbpath/logfile were not - * set, then set those as well to reside under the root. */ - if(config->rootdir) { - char path[PATH_MAX]; - ret = alpm_option_set_root(config->rootdir); - if(ret != 0) { - pm_printf(PM_LOG_ERROR, _("problem setting rootdir '%s' (%s)\n"), - config->rootdir, alpm_strerrorlast()); - cleanup(ret); - } - if(!config->dbpath) { - /* omit leading slash from our static DBPATH, root handles it */ - snprintf(path, PATH_MAX, "%s%s", alpm_option_get_root(), DBPATH + 1); - config->dbpath = strdup(path); - } - if(!config->logfile) { - /* omit leading slash from our static LOGFILE path, root handles it */ - snprintf(path, PATH_MAX, "%s%s", alpm_option_get_root(), LOGFILE + 1); - config->logfile = strdup(path); - } - } - /* Set other paths if they were configured. Note that unless rootdir - * was left undefined, these two paths (dbpath and logfile) will have - * been set locally above, so the if cases below will now trigger. */ - if(config->dbpath) { - ret = alpm_option_set_dbpath(config->dbpath); - if(ret != 0) { - pm_printf(PM_LOG_ERROR, _("problem setting dbpath '%s' (%s)\n"), - config->dbpath, alpm_strerrorlast()); - cleanup(ret); - } - } - if(config->logfile) { - ret = alpm_option_set_logfile(config->logfile); - if(ret != 0) { - pm_printf(PM_LOG_ERROR, _("problem setting logfile '%s' (%s)\n"), - config->logfile, alpm_strerrorlast()); - cleanup(ret); - } - } +#define check_optarg() if(!optarg) { return 1; } - /* add a default cachedir if one wasn't specified */ - if(alpm_option_get_cachedirs() == NULL) { - alpm_option_add_cachedir(CACHEDIR); - } - init = 1; - } -} - -#define check_optarg() if(!optarg) { return(1); } - -typedef void (*fn_add) (const char *s); - -static int parsearg_util_addlist(fn_add fn) +static int parsearg_util_addlist(alpm_list_t **list) { - alpm_list_t *list = NULL, *item = NULL; /* lists for splitting strings */ + alpm_list_t *split, *item; check_optarg(); - list = strsplit(optarg, ','); - for(item = list; item; item = alpm_list_next(item)) { - fn((char *)alpm_list_getdata(item)); + split = strsplit(optarg, ','); + for(item = split; item; item = alpm_list_next(item)) { + *list = alpm_list_add(*list, item->data); } - FREELIST(list); - return(0); + alpm_list_free(split); + return 0; } /** Helper function for parsing operation from command-line arguments. @@ -449,9 +368,9 @@ static int parsearg_op(int opt, int dryrun) if(dryrun) break; config->help = 1; break; default: - return(1); + return 1; } - return(0); + return 0; } /** Helper functions for parsing command-line arguments. @@ -461,7 +380,10 @@ static int parsearg_op(int opt, int dryrun) static int parsearg_global(int opt) { switch(opt) { - case OP_ARCH: check_optarg(); setarch(optarg); break; + case OP_ARCH: + check_optarg(); + config_set_arch(strdup(optarg)); + break; case OP_ASK: check_optarg(); config->noask = 1; @@ -469,11 +391,7 @@ static int parsearg_global(int opt) 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); - } + config->cachedirs = alpm_list_add(config->cachedirs, strdup(optarg)); break; case OP_CONFIG: check_optarg(); @@ -497,7 +415,7 @@ static int parsearg_global(int opt) default: pm_printf(PM_LOG_ERROR, _("'%s' is not a valid debug level\n"), optarg); - return(1); + return 1; } } else { config->logmask |= PM_LOG_DEBUG; @@ -505,6 +423,9 @@ static int parsearg_global(int opt) /* progress bars get wonky with debug on, shut them off */ config->noprogressbar = 1; break; + case OP_GPGDIR: + config->gpgdir = strdup(optarg); + break; case OP_LOGFILE: check_optarg(); config->logfile = strndup(optarg, PATH_MAX); @@ -516,9 +437,9 @@ static int parsearg_global(int opt) break; case 'r': check_optarg(); config->rootdir = strdup(optarg); break; case 'v': (config->verbose)++; break; - default: return(1); + default: return 1; } - return(0); + return 0; } static int parsearg_database(int opt) @@ -526,9 +447,9 @@ 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); + default: return 1; } - return(0); + return 0; } static int parsearg_query(int opt) @@ -548,9 +469,9 @@ static int parsearg_query(int opt) 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); + default: return 1; } - return(0); + return 0; } /* options common to -S -R -U */ @@ -572,15 +493,15 @@ static int parsearg_trans(int opt) check_optarg(); config->print_format = strdup(optarg); break; - default: return(1); + default: return 1; } - return(0); + return 0; } static int parsearg_remove(int opt) { - if (parsearg_trans(opt) == 0) - return(0); + 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; @@ -592,35 +513,35 @@ static int parsearg_remove(int opt) } break; case 'u': config->flags |= PM_TRANS_FLAG_UNNEEDED; break; - default: return(1); + default: return 1; } - return(0); + return 0; } /* options common to -S -U */ static int parsearg_upgrade(int opt) { - if (parsearg_trans(opt) == 0) - return(0); + 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); + parsearg_util_addlist(&(config->ignorepkg)); break; case OP_IGNOREGROUP: - parsearg_util_addlist(alpm_option_add_ignoregrp); + parsearg_util_addlist(&(config->ignoregrp)); break; - default: return(1); + default: return 1; } - return(0); + return 0; } static int parsearg_sync(int opt) { - if (parsearg_upgrade(opt) == 0) - return(0); + 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; @@ -636,9 +557,9 @@ static int parsearg_sync(int opt) config->flags |= PM_TRANS_FLAG_NOCONFLICTS; break; case 'y': (config->op_s_sync)++; break; - default: return(1); + default: return 1; } - return(0); + return 0; } /** Parse command-line arguments for each operation. @@ -706,6 +627,7 @@ static int parseargs(int argc, char *argv[]) {"asexplicit", no_argument, 0, OP_ASEXPLICIT}, {"arch", required_argument, 0, OP_ARCH}, {"print-format", required_argument, 0, OP_PRINTFORMAT}, + {"gpgdir", required_argument, 0, OP_GPGDIR}, {0, 0, 0, 0} }; @@ -717,22 +639,22 @@ static int parseargs(int argc, char *argv[]) continue; } else if(opt == '?') { /* unknown option, getopt printed an error */ - return(1); + 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); + return 1; } if(config->help) { usage(config->op, mbasename(argv[0])); - return(2); + return 2; } if(config->version) { version(); - return(2); + return 2; } /* parse all other options */ @@ -744,7 +666,7 @@ static int parseargs(int argc, char *argv[]) continue; } else if(opt == '?') { /* this should have failed during first pass already */ - return(1); + return 1; } else if(parsearg_op(opt, 1) == 0) { /* opt is an operation */ continue; @@ -771,7 +693,7 @@ static int parseargs(int argc, char *argv[]) result = 1; break; } - if (result == 0) { + if(result == 0) { continue; } @@ -780,7 +702,7 @@ static int parseargs(int argc, char *argv[]) if(result != 0) { /* global option parsing failed, abort */ pm_printf(PM_LOG_ERROR, _("invalid option\n")); - return(result); + return result; } } @@ -790,469 +712,7 @@ static int parseargs(int argc, char *argv[]) optind++; } - return(0); -} - -/* helper for being used with setrepeatingoption */ -static void option_add_holdpkg(const char *name) { - config->holdpkg = alpm_list_add(config->holdpkg, strdup(name)); -} - -/* helper for being used with setrepeatingoption */ -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. - * @param ptr a pointer to the start of the multiple options - * @param option the string (friendly) name of the option, used for messages - * @param optionfunc a function pointer to an alpm_option_add_* function - */ -static void setrepeatingoption(char *ptr, const char *option, - void (*optionfunc)(const char*)) -{ - char *q; - - while((q = strchr(ptr, ' '))) { - *q = '\0'; - (*optionfunc)(ptr); - pm_printf(PM_LOG_DEBUG, "config: %s: %s\n", option, ptr); - ptr = q; - ptr++; - } - (*optionfunc)(ptr); - pm_printf(PM_LOG_DEBUG, "config: %s: %s\n", option, ptr); -} - -static char *get_filename(const char *url) { - char *filename = strrchr(url, '/'); - if(filename != NULL) { - filename++; - } - return(filename); -} - -static char *get_destfile(const char *path, const char *filename) { - char *destfile; - /* len = localpath len + filename len + null */ - size_t len = strlen(path) + strlen(filename) + 1; - destfile = calloc(len, sizeof(char)); - snprintf(destfile, len, "%s%s", path, filename); - - return(destfile); -} - -static char *get_tempfile(const char *path, const char *filename) { - char *tempfile; - /* len = localpath len + filename len + '.part' len + null */ - size_t len = strlen(path) + strlen(filename) + 6; - tempfile = calloc(len, sizeof(char)); - snprintf(tempfile, len, "%s%s.part", path, filename); - - return(tempfile); -} - -/** External fetch callback */ -static int download_with_xfercommand(const char *url, const char *localpath, - int force) { - int ret = 0; - int retval; - int usepart = 0; - struct stat st; - char *parsedcmd,*tempcmd; - char cwd[PATH_MAX]; - int restore_cwd = 0; - char *destfile, *tempfile, *filename; - - if(!config->xfercommand) { - return -1; - } - - filename = get_filename(url); - if(!filename) { - return -1; - } - destfile = get_destfile(localpath, filename); - tempfile = get_tempfile(localpath, filename); - - if(force && stat(tempfile, &st) == 0) { - unlink(tempfile); - } - if(force && stat(destfile, &st) == 0) { - unlink(destfile); - } - - tempcmd = strdup(config->xfercommand); - /* replace all occurrences of %o with fn.part */ - if(strstr(tempcmd, "%o")) { - usepart = 1; - parsedcmd = strreplace(tempcmd, "%o", tempfile); - free(tempcmd); - tempcmd = parsedcmd; - } - /* replace all occurrences of %u with the download URL */ - 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 */ - if(chdir(localpath)) { - pm_printf(PM_LOG_WARNING, _("could not chdir to download directory %s\n"), localpath); - ret = -1; - goto cleanup; - } - /* execute the parsed command via /bin/sh -c */ - pm_printf(PM_LOG_DEBUG, "running command: %s\n", parsedcmd); - retval = system(parsedcmd); - - if(retval == -1) { - pm_printf(PM_LOG_WARNING, _("running XferCommand: fork failed!\n")); - ret = -1; - } else if(retval != 0) { - /* download failed */ - pm_printf(PM_LOG_DEBUG, "XferCommand command returned non-zero status " - "code (%d)\n", retval); - ret = -1; - } else { - /* download was successful */ - if(usepart) { - rename(tempfile, destfile); - } - ret = 0; - } - -cleanup: - /* 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); - } - free(destfile); - free(tempfile); - free(parsedcmd); - - return(ret); -} - -static int _parse_options(const char *key, char *value, - const char *file, int linenum) -{ - if(value == NULL) { - /* options without settings */ - if(strcmp(key, "UseSyslog") == 0) { - alpm_option_set_usesyslog(1); - pm_printf(PM_LOG_DEBUG, "config: usesyslog\n"); - } else if(strcmp(key, "ILoveCandy") == 0) { - config->chomp = 1; - pm_printf(PM_LOG_DEBUG, "config: chomp\n"); - } else if(strcmp(key, "ShowSize") == 0) { - config->showsize = 1; - pm_printf(PM_LOG_DEBUG, "config: showsize\n"); - } else if(strcmp(key, "UseDelta") == 0) { - alpm_option_set_usedelta(1); - pm_printf(PM_LOG_DEBUG, "config: usedelta\n"); - } 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_WARNING, - _("config file %s, line %d: directive '%s' in section '%s' not recognized.\n"), - file, linenum, key, "options"); - } - } else { - /* options with settings */ - if(strcmp(key, "NoUpgrade") == 0) { - setrepeatingoption(value, "NoUpgrade", alpm_option_add_noupgrade); - } else if(strcmp(key, "NoExtract") == 0) { - setrepeatingoption(value, "NoExtract", alpm_option_add_noextract); - } else if(strcmp(key, "IgnorePkg") == 0) { - setrepeatingoption(value, "IgnorePkg", alpm_option_add_ignorepkg); - } else if(strcmp(key, "IgnoreGroup") == 0) { - setrepeatingoption(value, "IgnoreGroup", alpm_option_add_ignoregrp); - } else if(strcmp(key, "HoldPkg") == 0) { - setrepeatingoption(value, "HoldPkg", option_add_holdpkg); - } else if(strcmp(key, "SyncFirst") == 0) { - setrepeatingoption(value, "SyncFirst", option_add_syncfirst); - } else if(strcmp(key, "Architecture") == 0) { - if(!alpm_option_get_arch()) { - setarch(value); - } - } else if(strcmp(key, "DBPath") == 0) { - /* don't overwrite a path specified on the command line */ - if(!config->dbpath) { - config->dbpath = strdup(value); - pm_printf(PM_LOG_DEBUG, "config: dbpath: %s\n", value); - } - } else if(strcmp(key, "CacheDir") == 0) { - if(alpm_option_add_cachedir(value) != 0) { - pm_printf(PM_LOG_ERROR, _("problem adding cachedir '%s' (%s)\n"), - value, alpm_strerrorlast()); - return(1); - } - pm_printf(PM_LOG_DEBUG, "config: cachedir: %s\n", value); - } else if(strcmp(key, "RootDir") == 0) { - /* don't overwrite a path specified on the command line */ - if(!config->rootdir) { - config->rootdir = strdup(value); - pm_printf(PM_LOG_DEBUG, "config: rootdir: %s\n", value); - } - } else if (strcmp(key, "LogFile") == 0) { - if(!config->logfile) { - config->logfile = strdup(value); - pm_printf(PM_LOG_DEBUG, "config: logfile: %s\n", value); - } - } else if (strcmp(key, "XferCommand") == 0) { - config->xfercommand = strdup(value); - alpm_option_set_fetchcb(download_with_xfercommand); - pm_printf(PM_LOG_DEBUG, "config: xfercommand: %s\n", value); - } else if (strcmp(key, "CleanMethod") == 0) { - setrepeatingoption(value, "CleanMethod", option_add_cleanmethod); - } else { - - pm_printf(PM_LOG_WARNING, - _("config file %s, line %d: directive '%s' in section '%s' not recognized.\n"), - file, linenum, key, "options"); - } - - } - return(0); -} - -static int _add_mirror(pmdb_t *db, char *value) -{ - const char *dbname = alpm_db_get_name(db); - /* let's attempt a replacement for the current repo */ - char *temp = strreplace(value, "$repo", dbname); - /* let's attempt a replacement for the arch */ - const char *arch = alpm_option_get_arch(); - char *server; - if(arch) { - server = strreplace(temp, "$arch", arch); - free(temp); - } else { - if(strstr(temp, "$arch")) { - free(temp); - pm_printf(PM_LOG_ERROR, _("The mirror '%s' contains the $arch" - " variable, but no Architecture is defined.\n"), value); - return(1); - } - server = temp; - } - - if(alpm_db_setserver(db, server) != 0) { - /* pm_errno is set by alpm_db_setserver */ - pm_printf(PM_LOG_ERROR, _("could not add server URL to database '%s': %s (%s)\n"), - dbname, server, alpm_strerrorlast()); - free(server); - return(1); - } - - free(server); - return(0); -} - -/* The real parseconfig. Called with a null section argument by the publicly - * visible parseconfig so we can recall from within ourself on an include */ -static int _parseconfig(const char *file, const char *givensection, - pmdb_t * const givendb) -{ - FILE *fp = NULL; - char line[PATH_MAX+1]; - int linenum = 0; - char *ptr, *section = NULL; - pmdb_t *db = NULL; - int ret = 0; - - pm_printf(PM_LOG_DEBUG, "config: attempting to read file %s\n", file); - fp = fopen(file, "r"); - if(fp == NULL) { - pm_printf(PM_LOG_ERROR, _("config file %s could not be read.\n"), file); - return(1); - } - - /* if we are passed a section, use it as our starting point */ - if(givensection != NULL) { - section = strdup(givensection); - } - /* if we are passed a db, use it as our starting point */ - if(givendb != NULL) { - db = givendb; - } - - while(fgets(line, PATH_MAX, fp)) { - linenum++; - strtrim(line); - - /* ignore whole line and end of line comments */ - if(strlen(line) == 0 || line[0] == '#') { - continue; - } - if((ptr = strchr(line, '#'))) { - *ptr = '\0'; - } - - if(line[0] == '[' && line[strlen(line)-1] == ']') { - /* new config section, skip the '[' */ - ptr = line; - ptr++; - if(section) { - free(section); - } - section = strdup(ptr); - section[strlen(section)-1] = '\0'; - pm_printf(PM_LOG_DEBUG, "config: new section '%s'\n", section); - if(!strlen(section)) { - pm_printf(PM_LOG_ERROR, _("config file %s, line %d: bad section name.\n"), - file, linenum); - ret = 1; - goto cleanup; - } - /* if we are not looking at the options section, register a db */ - if(strcmp(section, "options") != 0) { - db = alpm_db_register_sync(section); - if(db == NULL) { - pm_printf(PM_LOG_ERROR, _("could not register '%s' database (%s)\n"), - section, alpm_strerrorlast()); - ret = 1; - goto cleanup; - } - } - continue; - } - - /* directive */ - char *key, *value; - /* strsep modifies the 'line' string: 'key \0 value' */ - key = line; - value = line; - strsep(&value, "="); - strtrim(key); - strtrim(value); - - if(key == NULL) { - pm_printf(PM_LOG_ERROR, _("config file %s, line %d: syntax error in config file- missing key.\n"), - file, linenum); - ret = 1; - goto cleanup; - } - /* For each directive, compare to the camelcase string. */ - if(section == NULL) { - pm_printf(PM_LOG_ERROR, _("config file %s, line %d: All directives must belong to a section.\n"), - file, linenum); - ret = 1; - goto cleanup; - } - /* Include is allowed in both options and repo sections */ - if(strcmp(key, "Include") == 0) { - if(value == NULL) { - pm_printf(PM_LOG_ERROR, _("config file %s, line %d: directive '%s' needs a value\n"), - file, linenum, key); - ret = 1; - goto cleanup; - } - /* Ignore include failures... assume non-critical */ - int globret; - glob_t globbuf; - globret = glob(value, GLOB_NOCHECK, NULL, &globbuf); - switch(globret) { - case GLOB_NOSPACE: - pm_printf(PM_LOG_DEBUG, - "config file %s, line %d: include globbing out of space\n", - file, linenum); - break; - case GLOB_ABORTED: - pm_printf(PM_LOG_DEBUG, - "config file %s, line %d: include globbing read error for %s\n", - file, linenum, value); - break; - case GLOB_NOMATCH: - pm_printf(PM_LOG_DEBUG, - "config file %s, line %d: no include found for %s\n", - file, linenum, value); - break; - default: - 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); - } - break; - } - globfree(&globbuf); - continue; - } - if(strcmp(section, "options") == 0) { - /* we are either in options ... */ - if((ret = _parse_options(key, value, file, linenum)) != 0) { - goto cleanup; - } - } else { - /* ... or in a repo section */ - if(strcmp(key, "Server") == 0) { - if(value == NULL) { - pm_printf(PM_LOG_ERROR, _("config file %s, line %d: directive '%s' needs a value\n"), - file, linenum, key); - ret = 1; - goto cleanup; - } - if(_add_mirror(db, value) != 0) { - ret = 1; - goto cleanup; - } - } else { - pm_printf(PM_LOG_WARNING, - _("config file %s, line %d: directive '%s' in section '%s' not recognized.\n"), - file, linenum, key, section); - } - } - - } - -cleanup: - fclose(fp); - if(section){ - free(section); - } - /* call setlibpaths here to ensure we have called it at least once */ - setlibpaths(); - pm_printf(PM_LOG_DEBUG, "config: finished parsing %s\n", file); - return(ret); -} - -/** Parse a configuration file. - * @param file path to the config file. - * @return 0 on success, non-zero on error - */ -static int parseconfig(const char *file) -{ - /* call the real parseconfig function with a null section & db argument */ - return(_parseconfig(file, NULL, NULL)); + return 0; } /** print commandline to logfile @@ -1275,7 +735,7 @@ static void cl_to_log(int argc, char* argv[]) *p++ = ' '; } strcpy(p, argv[i]); - alpm_logaction("Running '%s'\n", cl_text); + alpm_logaction(config->handle, "Running '%s'\n", cl_text); free(cl_text); } @@ -1333,21 +793,6 @@ int main(int argc, char *argv[]) config->noprogressbar = 1; } - /* initialize library */ - if(alpm_initialize() == -1) { - pm_printf(PM_LOG_ERROR, _("failed to initialize alpm library (%s)\n"), - alpm_strerrorlast()); - cleanup(EXIT_FAILURE); - } - - /* Setup logging as soon as possible, to print out maximum debugging info */ - alpm_option_set_logcb(cb_log); - alpm_option_set_dlcb(cb_dl_progress); - /* define paths to reasonable defaults */ - alpm_option_set_root(ROOTDIR); - alpm_option_set_dbpath(DBPATH); - alpm_option_set_logfile(LOGFILE); - /* Priority of options: * 1. command line * 2. config file @@ -1384,7 +829,7 @@ int main(int argc, char *argv[]) } } /* check for buffer overflow */ - if (i >= PATH_MAX) { + if(i >= PATH_MAX) { pm_printf(PM_LOG_ERROR, _("buffer overflow detected in arg parsing\n")); cleanup(EXIT_FAILURE); } @@ -1394,7 +839,7 @@ int main(int argc, char *argv[]) line[i] = '\0'; pm_targets = alpm_list_add(pm_targets, strdup(line)); } - if (!freopen(ctermid(NULL), "r", stdin)) { + if(!freopen(ctermid(NULL), "r", stdin)) { pm_printf(PM_LOG_ERROR, _("failed to reopen stdin for reading: (%s)\n"), strerror(errno)); } @@ -1406,11 +851,6 @@ int main(int argc, char *argv[]) cleanup(ret); } - /* set TotalDownload callback if option enabled */ - if(config->totaldownload) { - alpm_option_set_totaldlcb(cb_dl_total); - } - /* noask is meant to be non-interactive */ if(config->noask) { config->noconfirm = 1; @@ -1435,16 +875,17 @@ int main(int argc, char *argv[]) if(config->verbose > 0) { alpm_list_t *i; - printf("Root : %s\n", alpm_option_get_root()); + printf("Root : %s\n", alpm_option_get_root(config->handle)); printf("Conf File : %s\n", config->configfile); - printf("DB Path : %s\n", alpm_option_get_dbpath()); + printf("DB Path : %s\n", alpm_option_get_dbpath(config->handle)); printf("Cache Dirs: "); - for(i = alpm_option_get_cachedirs(); i; i = alpm_list_next(i)) { - printf("%s ", (char*)alpm_list_getdata(i)); + for(i = alpm_option_get_cachedirs(config->handle); i; i = alpm_list_next(i)) { + printf("%s ", (char *)alpm_list_getdata(i)); } printf("\n"); - printf("Lock File : %s\n", alpm_option_get_lockfile()); - printf("Log File : %s\n", alpm_option_get_logfile()); + printf("Lock File : %s\n", alpm_option_get_lockfile(config->handle)); + printf("Log File : %s\n", alpm_option_get_logfile(config->handle)); + printf("GPG Dir : %s\n", alpm_option_get_signaturedir(config->handle)); list_display("Targets :", pm_targets); } @@ -1480,7 +921,7 @@ int main(int argc, char *argv[]) cleanup(ret); /* not reached */ - return(EXIT_SUCCESS); + return EXIT_SUCCESS; } /* vim: set ts=2 sw=2 noet: */ diff --git a/src/pacman/pacman.h b/src/pacman/pacman.h index f5b972bb..762e112d 100644 --- a/src/pacman/pacman.h +++ b/src/pacman/pacman.h @@ -24,6 +24,8 @@ /* database.c */ int pacman_database(alpm_list_t *targets); +/* deptest.c */ +int pacman_deptest(alpm_list_t *targets); /* query.c */ int pacman_query(alpm_list_t *targets); /* remove.c */ @@ -33,9 +35,6 @@ int pacman_sync(alpm_list_t *targets); /* upgrade.c */ int pacman_upgrade(alpm_list_t *targets); -/* deptest.c */ -int pacman_deptest(alpm_list_t *targets); - #endif /* _PM_PACMAN_H */ /* vim: set ts=2 sw=2 noet: */ diff --git a/src/pacman/query.c b/src/pacman/query.c index 6c63774f..06fd704a 100644 --- a/src/pacman/query.c +++ b/src/pacman/query.c @@ -26,7 +26,6 @@ #include <string.h> #include <sys/stat.h> #include <errno.h> -#include <unistd.h> #include <alpm.h> #include <alpm_list.h> @@ -41,17 +40,17 @@ static char *resolve_path(const char *file) { char *str = NULL; - str = calloc(PATH_MAX + 1, sizeof(char)); + str = calloc(PATH_MAX, sizeof(char)); if(!str) { - return(NULL); + return NULL; } if(!realpath(file, str)) { free(str); - return(NULL); + return NULL; } - return(str); + return str; } /* check if filename exists in PATH */ @@ -61,10 +60,10 @@ static int search_path(char **filename, struct stat *bufptr) size_t flen; if((envpath = getenv("PATH")) == NULL) { - return(-1); + return -1; } if((envpath = envpathsplit = strdup(envpath)) == NULL) { - return(-1); + return -1; } flen = strlen(*filename); @@ -80,7 +79,7 @@ static int search_path(char **filename, struct stat *bufptr) fullname = malloc(plen + flen + 2); if(!fullname) { free(envpath); - return(-1); + return -1; } sprintf(fullname, "%s/%s", path, *filename); @@ -88,12 +87,12 @@ static int search_path(char **filename, struct stat *bufptr) free(*filename); *filename = fullname; free(envpath); - return(0); + return 0; } free(fullname); } free(envpath); - return(-1); + return -1; } static void print_query_fileowner(const char *filename, pmpkg_t *info) @@ -119,18 +118,18 @@ static int query_fileowner(alpm_list_t *targets) /* This code is here for safety only */ if(targets == NULL) { pm_fprintf(stderr, PM_LOG_ERROR, _("no file was specified for --owns\n")); - return(1); + 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(); + root = alpm_option_get_root(config->handle); strncpy(path, root, PATH_MAX - 1); append = path + strlen(path); max_length = PATH_MAX - (append - path) - 1; - db_local = alpm_option_get_localdb(); + db_local = alpm_option_get_localdb(config->handle); for(t = targets; t; t = alpm_list_next(t)) { char *filename, *dname, *rpath; @@ -171,7 +170,7 @@ static int query_fileowner(alpm_list_t *targets) bname = mbasename(filename); dname = mdirname(filename); /* for files in '/', there is no directory name to match */ - if (strcmp(dname, "") == 0) { + if(strcmp(dname, "") == 0) { rpath = NULL; } else { rpath = resolve_path(dname); @@ -241,7 +240,7 @@ static int query_search(alpm_list_t *targets) { alpm_list_t *i, *searchlist; int freelist; - pmdb_t *db_local = alpm_option_get_localdb(); + pmdb_t *db_local = alpm_option_get_localdb(config->handle); /* if we have a targets list, search for packages matching it */ if(targets) { @@ -252,29 +251,21 @@ static int query_search(alpm_list_t *targets) freelist = 0; } if(searchlist == NULL) { - return(1); + return 1; } for(i = searchlist; i; i = alpm_list_next(i)) { alpm_list_t *grp; pmpkg_t *pkg = alpm_list_getdata(i); - if (!config->quiet) { + if(!config->quiet) { printf("local/%s %s", alpm_pkg_get_name(pkg), alpm_pkg_get_version(pkg)); } else { printf("%s", alpm_pkg_get_name(pkg)); } - /* print the package size with the output if ShowSize option set */ - if(!config->quiet && config->showsize) { - /* Convert byte size to MB */ - double mbsize = (double)alpm_pkg_get_size(pkg) / (1024.0 * 1024.0); - printf(" [%.2f MB]", mbsize); - } - - - if (!config->quiet) { + if(!config->quiet) { if((grp = alpm_pkg_get_groups(pkg)) != NULL) { alpm_list_t *k; printf(" ("); @@ -300,7 +291,7 @@ static int query_search(alpm_list_t *targets) if(freelist) { alpm_list_free(searchlist); } - return(0); + return 0; } static int query_group(alpm_list_t *targets) @@ -308,7 +299,7 @@ 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(); + pmdb_t *db_local = alpm_option_get_localdb(config->handle); if(targets == NULL) { for(j = alpm_db_get_grpcache(db_local); j; j = alpm_list_next(j)) { @@ -351,7 +342,7 @@ static int is_foreign(pmpkg_t *pkg) { const char *pkgname = alpm_pkg_get_name(pkg); alpm_list_t *j; - alpm_list_t *sync_dbs = alpm_option_get_syncdbs(); + alpm_list_t *sync_dbs = alpm_option_get_syncdbs(config->handle); int match = 0; for(j = sync_dbs; j; j = alpm_list_next(j)) { @@ -363,19 +354,19 @@ static int is_foreign(pmpkg_t *pkg) } } if(match == 0) { - return(1); + return 1; } - return(0); + return 0; } static int is_unrequired(pmpkg_t *pkg) { alpm_list_t *requiredby = alpm_pkg_compute_requiredby(pkg); if(requiredby == NULL) { - return(1); + return 1; } FREELIST(requiredby); - return(0); + return 0; } static int filter(pmpkg_t *pkg) @@ -383,26 +374,27 @@ static int filter(pmpkg_t *pkg) /* check if this package was explicitly installed */ if(config->op_q_explicit && alpm_pkg_get_reason(pkg) != PM_PKG_REASON_EXPLICIT) { - return(0); + return 0; } /* check if this package was installed as a dependency */ if(config->op_q_deps && alpm_pkg_get_reason(pkg) != PM_PKG_REASON_DEPEND) { - return(0); + return 0; } /* check if this pkg isn't in a sync DB */ if(config->op_q_foreign && !is_foreign(pkg)) { - return(0); + return 0; } /* check if this pkg is unrequired */ if(config->op_q_unrequired && !is_unrequired(pkg)) { - return(0); + return 0; } /* check if this pkg is outdated */ - if(config->op_q_upgrade && (alpm_sync_newversion(pkg, alpm_option_get_syncdbs()) == NULL)) { - return(0); + if(config->op_q_upgrade && (alpm_sync_newversion(pkg, + alpm_option_get_syncdbs(config->handle)) == NULL)) { + return 0; } - return(1); + return 1; } /* Loop through the packages. For each package, @@ -415,12 +407,12 @@ static int check(pmpkg_t *pkg) size_t rootlen; char f[PATH_MAX]; - root = alpm_option_get_root(); + root = alpm_option_get_root(config->handle); rootlen = strlen(root); if(rootlen + 1 > PATH_MAX) { /* we are in trouble here */ pm_fprintf(stderr, PM_LOG_ERROR, _("path too long: %s%s\n"), root, ""); - return(1); + return 1; } strcpy(f, root); @@ -454,7 +446,7 @@ static int check(pmpkg_t *pkg) (unsigned long)errors), errors); } - return(errors != 0 ? 1 : 0); + return (errors != 0 ? 1 : 0); } static int display(pmpkg_t *pkg) @@ -463,10 +455,9 @@ static int display(pmpkg_t *pkg) if(config->op_q_info) { if(config->op_q_isfile) { - /* omit info that isn't applicable for a file package */ - dump_pkg_full(pkg, 0); + dump_pkg_full(pkg, PKG_FROM_FILE, 0); } else { - dump_pkg_full(pkg, config->op_q_info); + dump_pkg_full(pkg, PKG_FROM_LOCALDB, config->op_q_info > 1); } } if(config->op_q_list) { @@ -480,13 +471,13 @@ static int display(pmpkg_t *pkg) } if(!config->op_q_info && !config->op_q_list && !config->op_q_changelog && !config->op_q_check) { - if (!config->quiet) { + if(!config->quiet) { printf("%s %s\n", alpm_pkg_get_name(pkg), alpm_pkg_get_version(pkg)); } else { printf("%s\n", alpm_pkg_get_name(pkg)); } } - return(ret); + return ret; } int pacman_query(alpm_list_t *targets) @@ -502,25 +493,25 @@ int pacman_query(alpm_list_t *targets) /* search for a package */ if(config->op_q_search) { ret = query_search(targets); - return(ret); + return ret; } /* looking for groups */ if(config->group) { ret = query_group(targets); - return(ret); + return ret; } if(config->op_q_foreign) { /* ensure we have at least one valid sync db set up */ - alpm_list_t *sync_dbs = alpm_option_get_syncdbs(); + alpm_list_t *sync_dbs = alpm_option_get_syncdbs(config->handle); if(sync_dbs == NULL || alpm_list_count(sync_dbs) == 0) { pm_printf(PM_LOG_ERROR, _("no usable package repositories configured.\n")); - return(1); + return 1; } } - db_local = alpm_option_get_localdb(); + db_local = alpm_option_get_localdb(config->handle); /* operations on all packages in the local DB * valid: no-op (plain -Q), list, info, check @@ -528,7 +519,7 @@ int pacman_query(alpm_list_t *targets) if(targets == NULL) { if(config->op_q_isfile || config->op_q_owns) { pm_printf(PM_LOG_ERROR, _("no targets specified (use -h for help)\n")); - return(1); + return 1; } for(i = alpm_db_get_pkgcache(db_local); i; i = alpm_list_next(i)) { @@ -544,7 +535,7 @@ int pacman_query(alpm_list_t *targets) if(!match) { ret = 1; } - return(ret); + return ret; } /* Second: operations that require target(s) */ @@ -552,7 +543,7 @@ int pacman_query(alpm_list_t *targets) /* determine the owner of a file */ if(config->op_q_owns) { ret = query_fileowner(targets); - return(ret); + return ret; } /* operations on named packages in the local DB @@ -561,7 +552,7 @@ int pacman_query(alpm_list_t *targets) char *strname = alpm_list_getdata(i); if(config->op_q_isfile) { - alpm_pkg_load(strname, 1, &pkg); + alpm_pkg_load(config->handle, strname, 1, PM_PGP_VERIFY_OPTIONAL, &pkg); } else { pkg = alpm_db_get_pkg(db_local, strname); } @@ -590,7 +581,7 @@ int pacman_query(alpm_list_t *targets) ret = 1; } - return(ret); + return ret; } /* vim: set ts=2 sw=2 noet: */ diff --git a/src/pacman/remove.c b/src/pacman/remove.c index fb02e242..a4e18941 100644 --- a/src/pacman/remove.c +++ b/src/pacman/remove.c @@ -31,34 +31,36 @@ #include "util.h" #include "conf.h" -static int remove_target(char *target) +static int remove_target(const char *target) { pmpkg_t *info; - pmdb_t *db_local = alpm_option_get_localdb(); + pmdb_t *db_local = alpm_option_get_localdb(config->handle); 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); + if(alpm_remove_pkg(config->handle, info) == -1) { + pm_fprintf(stderr, PM_LOG_ERROR, "'%s': %s\n", target, + alpm_strerror(alpm_errno(config->handle))); + return -1; } - return(0); + 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); + 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); + if(alpm_remove_pkg(config->handle, pkg) == -1) { + pm_fprintf(stderr, PM_LOG_ERROR, "'%s': %s\n", target, + alpm_strerror(alpm_errno(config->handle))); + return -1; } } - return(0); + return 0; } /** @@ -75,12 +77,12 @@ int pacman_remove(alpm_list_t *targets) if(targets == NULL) { pm_printf(PM_LOG_ERROR, _("no targets specified (use -h for help)\n")); - return(1); + return 1; } /* Step 0: create a new transaction */ if(trans_init(config->flags) == -1) { - return(1); + return 1; } /* Step 1: add targets to the created transaction */ @@ -99,10 +101,11 @@ int pacman_remove(alpm_list_t *targets) } /* Step 2: prepare the transaction based on its type, targets and flags */ - if(alpm_trans_prepare(&data) == -1) { + if(alpm_trans_prepare(config->handle, &data) == -1) { + enum _pmerrno_t err = alpm_errno(config->handle); pm_fprintf(stderr, PM_LOG_ERROR, _("failed to prepare transaction (%s)\n"), - alpm_strerrorlast()); - switch(pm_errno) { + alpm_strerror(err)); + switch(err) { case PM_ERR_PKG_INVALID_ARCH: for(i = data; i; i = alpm_list_next(i)) { char *pkg = alpm_list_getdata(i); @@ -118,18 +121,18 @@ int pacman_remove(alpm_list_t *targets) depstring); free(depstring); } - FREELIST(data); break; default: break; } + FREELIST(data); retval = 1; goto cleanup; } /* Search for holdpkg in target list */ int holdpkg = 0; - for(i = alpm_trans_get_remove(); i; i = alpm_list_next(i)) { + for(i = alpm_trans_get_remove(config->handle); i; i = alpm_list_next(i)) { pmpkg_t *pkg = alpm_list_getdata(i); if(alpm_list_find_str(config->holdpkg, alpm_pkg_get_name(pkg))) { pm_printf(PM_LOG_WARNING, _("%s is designated as a HoldPkg.\n"), @@ -143,7 +146,7 @@ int pacman_remove(alpm_list_t *targets) } /* Step 3: actually perform the removal */ - alpm_list_t *pkglist = alpm_trans_get_remove(); + alpm_list_t *pkglist = alpm_trans_get_remove(config->handle); if(pkglist == NULL) { printf(_(" there is nothing to do\n")); goto cleanup; /* we are done */ @@ -162,18 +165,20 @@ int pacman_remove(alpm_list_t *targets) goto cleanup; } - if(alpm_trans_commit(NULL) == -1) { + if(alpm_trans_commit(config->handle, &data) == -1) { pm_fprintf(stderr, PM_LOG_ERROR, _("failed to commit transaction (%s)\n"), - alpm_strerrorlast()); + alpm_strerror(alpm_errno(config->handle))); retval = 1; } + FREELIST(data); + /* Step 4: release transaction resources */ cleanup: if(trans_release() == -1) { retval = 1; } - return(retval); + return retval; } /* vim: set ts=2 sw=2 noet: */ diff --git a/src/pacman/sync.c b/src/pacman/sync.c index c56934b6..37b9d6e3 100644 --- a/src/pacman/sync.c +++ b/src/pacman/sync.c @@ -39,7 +39,8 @@ /* 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) { +static int sync_cleandb(const char *dbpath, int keep_used) +{ DIR *dir; struct dirent *ent; alpm_list_t *syncdbs; @@ -47,10 +48,10 @@ static int sync_cleandb(const char *dbpath, int keep_used) { dir = opendir(dbpath); if(dir == NULL) { pm_fprintf(stderr, PM_LOG_ERROR, _("could not access database directory\n")); - return(1); + return 1; } - syncdbs = alpm_option_get_syncdbs(); + syncdbs = alpm_option_get_syncdbs(config->handle); rewinddir(dir); /* step through the directory one file at a time */ @@ -84,7 +85,7 @@ static int sync_cleandb(const char *dbpath, int keep_used) { pm_fprintf(stderr, PM_LOG_ERROR, _("could not remove %s\n"), path); closedir(dir); - return(1); + return 1; } continue; } @@ -110,23 +111,24 @@ static int sync_cleandb(const char *dbpath, int keep_used) { pm_fprintf(stderr, PM_LOG_ERROR, _("could not remove %s\n"), path); closedir(dir); - return(1); + return 1; } } } closedir(dir); - return(0); + return 0; } -static int sync_cleandb_all(void) { +static int sync_cleandb_all(void) +{ const char *dbpath; char newdbpath[PATH_MAX]; int ret = 0; - dbpath = alpm_option_get_dbpath(); + dbpath = alpm_option_get_dbpath(config->handle); printf(_("Database directory: %s\n"), dbpath); if(!yesno(_("Do you want to remove unused repositories?"))) { - return(0); + return 0; } /* 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 @@ -137,18 +139,19 @@ static int sync_cleandb_all(void) { ret += sync_cleandb(newdbpath, 1); printf(_("Database directory cleaned up\n")); - return(ret); + return ret; } 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(); + alpm_list_t *sync_dbs = alpm_option_get_syncdbs(config->handle); + pmdb_t *db_local = alpm_option_get_localdb(config->handle); + alpm_list_t *cachedirs = alpm_option_get_cachedirs(config->handle); 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)); + for(i = cachedirs; i; i = alpm_list_next(i)) { + printf(_("Cache directory: %s\n"), (char *)alpm_list_getdata(i)); } if(!config->cleanmethod) { @@ -165,17 +168,17 @@ static int sync_cleancache(int level) printf(_(" All current sync database packages\n")); } if(!yesno(_("Do you want to remove all other packages from cache?"))) { - return(0); + return 0; } printf(_("removing old packages from cache...\n")); } else { if(!noyes(_("Do you want to remove ALL files from cache?"))) { - return(0); + return 0; } printf(_("removing all files from cache...\n")); } - for(i = alpm_option_get_cachedirs(); i; i = alpm_list_next(i)) { + for(i = cachedirs; i; i = alpm_list_next(i)) { const char *cachedir = alpm_list_getdata(i); DIR *dir = opendir(cachedir); struct dirent *ent; @@ -191,10 +194,10 @@ static int sync_cleancache(int level) /* step through the directory one file at a time */ while((ent = readdir(dir)) != NULL) { char path[PATH_MAX]; + size_t pathlen; int delete = 1; pmpkg_t *localpkg = NULL, *pkg = NULL; const char *local_name, *local_version; - alpm_list_t *j; if(strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0) { continue; @@ -208,11 +211,19 @@ static int sync_cleancache(int level) continue; } + /* we handle .sig files with packages, not separately */ + pathlen = strlen(path); + if(strcmp(path + pathlen - 4, ".sig") == 0) { + continue; + } + /* attempt to load the package, prompt removal on failures as we may have * files here that aren't valid packages. we also don't need a full * load of the package, just the metadata. */ - if(alpm_pkg_load(path, 0, &localpkg) != 0 || localpkg == NULL) { - if(yesno(_("File %s does not seem to be a valid package, remove it?"), path)) { + if(alpm_pkg_load(config->handle, path, 0, PM_PGP_VERIFY_NEVER, &localpkg) != 0 + || localpkg == NULL) { + if(yesno(_("File %s does not seem to be a valid package, remove it?"), + path)) { if(localpkg) { alpm_pkg_free(localpkg); } @@ -235,6 +246,7 @@ static int sync_cleancache(int level) } } if(config->cleanmethod & PM_CLEAN_KEEPCUR) { + alpm_list_t *j; /* 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); @@ -253,12 +265,17 @@ static int sync_cleancache(int level) if(delete) { unlink(path); + /* unlink a signature file if present too */ + if(PATH_MAX - 5 >= pathlen) { + strcpy(path + pathlen, ".sig"); + unlink(path); + } } } closedir(dir); } - return(ret); + return ret; } static int sync_synctree(int level, alpm_list_t *syncs) @@ -267,7 +284,7 @@ static int sync_synctree(int level, alpm_list_t *syncs) int success = 0, ret; if(trans_init(0) == -1) { - return(0); + return 0; } for(i = syncs; i; i = alpm_list_next(i)) { @@ -276,7 +293,7 @@ static int sync_synctree(int level, alpm_list_t *syncs) ret = alpm_db_update((level < 2 ? 0 : 1), db); if(ret < 0) { pm_fprintf(stderr, PM_LOG_ERROR, _("failed to update %s (%s)\n"), - alpm_db_get_name(db), alpm_strerrorlast()); + alpm_db_get_name(db), alpm_strerror(alpm_errno(config->handle))); } else if(ret == 1) { printf(_(" %s is up to date\n"), alpm_db_get_name(db)); success++; @@ -286,7 +303,7 @@ static int sync_synctree(int level, alpm_list_t *syncs) } if(trans_release() == -1) { - return(0); + return 0; } /* We should always succeed if at least one DB was upgraded - we may possibly * fail later with unresolved deps, but that should be rare, and would be @@ -295,7 +312,7 @@ static int sync_synctree(int level, alpm_list_t *syncs) if(!success) { pm_fprintf(stderr, PM_LOG_ERROR, _("failed to synchronize any databases\n")); } - return(success > 0); + return (success > 0); } static void print_installed(pmdb_t *db_local, pmpkg_t *pkg) @@ -319,7 +336,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(); + pmdb_t *db_local = alpm_option_get_localdb(config->handle); for(i = syncs; i; i = alpm_list_next(i)) { pmdb_t *db = alpm_list_getdata(i); @@ -340,22 +357,14 @@ static int sync_search(alpm_list_t *syncs, alpm_list_t *targets) alpm_list_t *grp; pmpkg_t *pkg = alpm_list_getdata(j); - if (!config->quiet) { + if(!config->quiet) { printf("%s/%s %s", alpm_db_get_name(db), alpm_pkg_get_name(pkg), alpm_pkg_get_version(pkg)); } else { printf("%s", alpm_pkg_get_name(pkg)); } - /* print the package size with the output if ShowSize option set */ - if(!config->quiet && config->showsize) { - /* Convert byte size to MB */ - double mbsize = (double)alpm_pkg_get_size(pkg) / (1024.0 * 1024.0); - - printf(" [%.2f MB]", mbsize); - } - - if (!config->quiet) { + if(!config->quiet) { if((grp = alpm_pkg_get_groups(pkg)) != NULL) { alpm_list_t *k; printf(" ("); @@ -384,7 +393,7 @@ static int sync_search(alpm_list_t *syncs, alpm_list_t *targets) } } - return(!found); + return !found; } static int sync_group(int level, alpm_list_t *syncs, alpm_list_t *targets) @@ -432,7 +441,7 @@ static int sync_group(int level, alpm_list_t *syncs, alpm_list_t *targets) } } - return(0); + return 0; } static int sync_info(alpm_list_t *syncs, alpm_list_t *targets) @@ -466,14 +475,14 @@ static int sync_info(alpm_list_t *syncs, alpm_list_t *targets) if(!db) { pm_fprintf(stderr, PM_LOG_ERROR, _("repository '%s' does not exist\n"), repo); - return(1); + return 1; } for(k = alpm_db_get_pkgcache(db); k; k = alpm_list_next(k)) { pmpkg_t *pkg = alpm_list_getdata(k); if(strcmp(alpm_pkg_get_name(pkg), pkgstr) == 0) { - dump_pkg_sync(pkg, alpm_db_get_name(db), config->op_s_info); + dump_pkg_full(pkg, PKG_FROM_SYNCDB, config->op_s_info > 1); foundpkg = 1; break; } @@ -494,7 +503,7 @@ static int sync_info(alpm_list_t *syncs, alpm_list_t *targets) pmpkg_t *pkg = alpm_list_getdata(k); if(strcmp(alpm_pkg_get_name(pkg), pkgstr) == 0) { - dump_pkg_sync(pkg, alpm_db_get_name(db), config->op_s_info); + dump_pkg_full(pkg, PKG_FROM_SYNCDB, config->op_s_info > 1); foundpkg = 1; break; } @@ -512,18 +521,19 @@ static int sync_info(alpm_list_t *syncs, alpm_list_t *targets) pmdb_t *db = alpm_list_getdata(i); for(j = alpm_db_get_pkgcache(db); j; j = alpm_list_next(j)) { - dump_pkg_sync(alpm_list_getdata(j), alpm_db_get_name(db), config->op_s_info); + pmpkg_t *pkg = alpm_list_getdata(j); + dump_pkg_full(pkg, PKG_FROM_SYNCDB, config->op_s_info > 1); } } } - return(ret); + return ret; } 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(); + pmdb_t *db_local = alpm_option_get_localdb(config->handle); if(targets) { for(i = targets; i; i = alpm_list_next(i)) { @@ -543,7 +553,7 @@ static int sync_list(alpm_list_t *syncs, alpm_list_t *targets) pm_fprintf(stderr, PM_LOG_ERROR, _("repository \"%s\" was not found.\n"),repo); alpm_list_free(ls); - return(1); + return 1; } ls = alpm_list_add(ls, db); @@ -558,7 +568,7 @@ static int sync_list(alpm_list_t *syncs, alpm_list_t *targets) for(j = alpm_db_get_pkgcache(db); j; j = alpm_list_next(j)) { pmpkg_t *pkg = alpm_list_getdata(j); - if (!config->quiet) { + if(!config->quiet) { printf("%s %s %s", alpm_db_get_name(db), alpm_pkg_get_name(pkg), alpm_pkg_get_version(pkg)); print_installed(db_local, pkg); @@ -573,12 +583,13 @@ static int sync_list(alpm_list_t *syncs, alpm_list_t *targets) alpm_list_free(ls); } - return(0); + return 0; } static alpm_list_t *syncfirst(void) { alpm_list_t *i, *res = NULL; - pmdb_t *db_local = alpm_option_get_localdb(); + pmdb_t *db_local = alpm_option_get_localdb(config->handle); + alpm_list_t *syncdbs = alpm_option_get_syncdbs(config->handle); for(i = config->syncfirst; i; i = alpm_list_next(i)) { char *pkgname = alpm_list_getdata(i); @@ -587,43 +598,44 @@ static alpm_list_t *syncfirst(void) { continue; } - if(alpm_sync_newversion(pkg, alpm_option_get_syncdbs())) { + if(alpm_sync_newversion(pkg, syncdbs)) { res = alpm_list_add(res, strdup(pkgname)); } } - return(res); + return res; } static pmdb_t *get_db(const char *dbname) { alpm_list_t *i; - for(i = alpm_option_get_syncdbs(); i; i = i->next) { + for(i = alpm_option_get_syncdbs(config->handle); i; i = i->next) { pmdb_t *db = i->data; if(strcmp(alpm_db_get_name(db), dbname) == 0) { - return(db); + return db; } } - return(NULL); + return NULL; } static int process_pkg(pmpkg_t *pkg) { - int ret = alpm_add_pkg(pkg); + int ret = alpm_add_pkg(config->handle, pkg); if(ret == -1) { - if(pm_errno == PM_ERR_TRANS_DUP_TARGET - || pm_errno == PM_ERR_PKG_IGNORED) { + enum _pmerrno_t err = alpm_errno(config->handle); + if(err == PM_ERR_TRANS_DUP_TARGET + || err == 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); + return 0; } else { pm_fprintf(stderr, PM_LOG_ERROR, "'%s': %s\n", alpm_pkg_get_name(pkg), - alpm_strerrorlast()); - return(1); + alpm_strerror(err)); + return 1; } } - return(0); + return 0; } static int process_group(alpm_list_t *dbs, char *group) @@ -635,7 +647,7 @@ static int process_group(alpm_list_t *dbs, char *group) if(!count) { pm_fprintf(stderr, PM_LOG_ERROR, _("target not found: %s\n"), group); - return(1); + return 1; } @@ -669,25 +681,26 @@ static int process_group(alpm_list_t *dbs, char *group) } cleanup: alpm_list_free(pkgs); - return(ret); + return ret; } static int process_targname(alpm_list_t *dblist, char *targname) { - pmpkg_t *pkg = alpm_find_dbs_satisfier(dblist, targname); + pmpkg_t *pkg = alpm_find_dbs_satisfier(config->handle, dblist, targname); - /* #FS23342 - skip ignored packages when user says no */ - if(pm_errno == PM_ERR_PKG_IGNORED) { + /* #FS#23342 - skip ignored packages when user says no */ + if(alpm_errno(config->handle) == PM_ERR_PKG_IGNORED) { pm_printf(PM_LOG_WARNING, _("skipping target: %s\n"), targname); - pm_errno = 0; - return(0); + /* TODO how to do this, we shouldn't be fucking with it from the frontend */ + /* pm_errno = 0; */ + return 0; } if(pkg) { - return(process_pkg(pkg)); + return process_pkg(pkg); } /* fallback on group */ - return(process_group(dblist, targname)); + return process_group(dblist, targname); } static int process_target(char *target) @@ -717,12 +730,12 @@ static int process_target(char *target) alpm_list_free(dblist); } else { targname = targstring; - dblist = alpm_option_get_syncdbs(); + dblist = alpm_option_get_syncdbs(config->handle); ret = process_targname(dblist, targname); } cleanup: free(targstring); - return(ret); + return ret; } static int sync_trans(alpm_list_t *targets) @@ -734,7 +747,7 @@ static int sync_trans(alpm_list_t *targets) /* Step 1: create a new transaction... */ if(trans_init(config->flags) == -1) { - return(1); + return 1; } /* process targets */ @@ -748,19 +761,20 @@ static int sync_trans(alpm_list_t *targets) if(config->op_s_upgrade) { printf(_(":: Starting full system upgrade...\n")); - alpm_logaction("starting full system upgrade\n"); - if(alpm_sync_sysupgrade(config->op_s_upgrade >= 2) == -1) { - pm_fprintf(stderr, PM_LOG_ERROR, "%s\n", alpm_strerrorlast()); + alpm_logaction(config->handle, "starting full system upgrade\n"); + if(alpm_sync_sysupgrade(config->handle, config->op_s_upgrade >= 2) == -1) { + pm_fprintf(stderr, PM_LOG_ERROR, "%s\n", alpm_strerror(alpm_errno(config->handle))); retval = 1; goto cleanup; } } /* Step 2: "compute" the transaction based on targets and flags */ - if(alpm_trans_prepare(&data) == -1) { + if(alpm_trans_prepare(config->handle, &data) == -1) { + enum _pmerrno_t err = alpm_errno(config->handle); pm_fprintf(stderr, PM_LOG_ERROR, _("failed to prepare transaction (%s)\n"), - alpm_strerrorlast()); - switch(pm_errno) { + alpm_strerror(err)); + switch(err) { alpm_list_t *i; case PM_ERR_PKG_INVALID_ARCH: for(i = data; i; i = alpm_list_next(i)) { @@ -799,7 +813,7 @@ static int sync_trans(alpm_list_t *targets) goto cleanup; } - packages = alpm_trans_get_add(); + packages = alpm_trans_get_add(config->handle); if(packages == NULL) { /* nothing to do: just exit without complaining */ printf(_(" there is nothing to do\n")); @@ -812,8 +826,8 @@ static int sync_trans(alpm_list_t *targets) goto cleanup; } - display_targets(alpm_trans_get_remove(), 0); - display_targets(alpm_trans_get_add(), 1); + display_targets(alpm_trans_get_remove(config->handle), 0); + display_targets(alpm_trans_get_add(config->handle), 1); printf("\n"); int confirm; @@ -826,10 +840,11 @@ static int sync_trans(alpm_list_t *targets) goto cleanup; } - if(alpm_trans_commit(&data) == -1) { + if(alpm_trans_commit(config->handle, &data) == -1) { + enum _pmerrno_t err = alpm_errno(config->handle); pm_fprintf(stderr, PM_LOG_ERROR, _("failed to commit transaction (%s)\n"), - alpm_strerrorlast()); - switch(pm_errno) { + alpm_strerror(err)); + switch(err) { alpm_list_t *i; case PM_ERR_FILE_CONFLICTS: for(i = data; i; i = alpm_list_next(i)) { @@ -874,7 +889,7 @@ cleanup: retval = 1; } - return(retval); + return retval; } int pacman_sync(alpm_list_t *targets) @@ -886,7 +901,7 @@ int pacman_sync(alpm_list_t *targets) int ret = 0; if(trans_init(0) == -1) { - return(1); + return 1; } ret += sync_cleancache(config->op_s_clean); @@ -897,55 +912,55 @@ int pacman_sync(alpm_list_t *targets) ret++; } - return(ret); + return ret; } /* ensure we have at least one valid sync db set up */ - sync_dbs = alpm_option_get_syncdbs(); + sync_dbs = alpm_option_get_syncdbs(config->handle); if(sync_dbs == NULL || alpm_list_count(sync_dbs) == 0) { pm_printf(PM_LOG_ERROR, _("no usable package repositories configured.\n")); - return(1); + return 1; } if(config->op_s_sync) { /* grab a fresh package list */ printf(_(":: Synchronizing package databases...\n")); - alpm_logaction("synchronizing package lists\n"); + alpm_logaction(config->handle, "synchronizing package lists\n"); if(!sync_synctree(config->op_s_sync, sync_dbs)) { - return(1); + return 1; } } /* search for a package */ if(config->op_s_search) { - return(sync_search(sync_dbs, targets)); + return sync_search(sync_dbs, targets); } /* look for groups */ if(config->group) { - return(sync_group(config->group, sync_dbs, targets)); + return sync_group(config->group, sync_dbs, targets); } /* get package info */ if(config->op_s_info) { - return(sync_info(sync_dbs, targets)); + return sync_info(sync_dbs, targets); } /* get a listing of files in sync DBs */ if(config->op_q_list) { - return(sync_list(sync_dbs, targets)); + return sync_list(sync_dbs, targets); } if(targets == NULL) { if(config->op_s_upgrade) { /* proceed */ } else if(config->op_s_sync) { - return(0); + return 0; } else { /* don't proceed here unless we have an operation that doesn't require a * target list */ pm_printf(PM_LOG_ERROR, _("no targets specified (use -h for help)\n")); - return(1); + return 1; } } @@ -980,7 +995,7 @@ int pacman_sync(alpm_list_t *targets) int ret = sync_trans(targs); FREELIST(targs); - return(ret); + return ret; } /* vim: set ts=2 sw=2 noet: */ diff --git a/src/pacman/upgrade.c b/src/pacman/upgrade.c index 8cd29da0..c0466456 100644 --- a/src/pacman/upgrade.c +++ b/src/pacman/upgrade.c @@ -42,22 +42,23 @@ int pacman_upgrade(alpm_list_t *targets) { alpm_list_t *i, *data = NULL; + pgp_verify_t check_sig = alpm_option_get_default_sigverify(config->handle); int retval = 0; if(targets == NULL) { pm_printf(PM_LOG_ERROR, _("no targets specified (use -h for help)\n")); - return(1); + return 1; } /* Check for URL targets and process them */ for(i = targets; i; i = alpm_list_next(i)) { if(strstr(i->data, "://")) { - char *str = alpm_fetch_pkgurl(i->data); + char *str = alpm_fetch_pkgurl(config->handle, i->data); if(str == NULL) { pm_fprintf(stderr, PM_LOG_ERROR, "'%s': %s\n", - (char *)i->data, alpm_strerrorlast()); - return(1); + (char *)i->data, alpm_strerror(alpm_errno(config->handle))); + return 1; } else { free(i->data); i->data = str; @@ -67,7 +68,7 @@ int pacman_upgrade(alpm_list_t *targets) /* Step 1: create a new transaction */ if(trans_init(config->flags) == -1) { - return(1); + return 1; } /* add targets to the created transaction */ @@ -75,27 +76,28 @@ int pacman_upgrade(alpm_list_t *targets) char *targ = alpm_list_getdata(i); pmpkg_t *pkg; - if(alpm_pkg_load(targ, 1, &pkg) != 0) { + if(alpm_pkg_load(config->handle, targ, 1, check_sig, &pkg) != 0) { pm_fprintf(stderr, PM_LOG_ERROR, "'%s': %s\n", - targ, alpm_strerrorlast()); + targ, alpm_strerror(alpm_errno(config->handle))); trans_release(); - return(1); + return 1; } - if(alpm_add_pkg(pkg) == -1) { + if(alpm_add_pkg(config->handle, pkg) == -1) { pm_fprintf(stderr, PM_LOG_ERROR, "'%s': %s\n", - targ, alpm_strerrorlast()); + targ, alpm_strerror(alpm_errno(config->handle))); alpm_pkg_free(pkg); trans_release(); - return(1); + return 1; } } /* Step 2: "compute" the transaction based on targets and flags */ /* TODO: No, compute nothing. This is stupid. */ - if(alpm_trans_prepare(&data) == -1) { + if(alpm_trans_prepare(config->handle, &data) == -1) { + enum _pmerrno_t err = alpm_errno(config->handle); pm_fprintf(stderr, PM_LOG_ERROR, _("failed to prepare transaction (%s)\n"), - alpm_strerrorlast()); - switch(pm_errno) { + alpm_strerror(err)); + switch(err) { case PM_ERR_PKG_INVALID_ARCH: for(i = data; i; i = alpm_list_next(i)) { char *pkg = alpm_list_getdata(i); @@ -135,37 +137,38 @@ int pacman_upgrade(alpm_list_t *targets) } trans_release(); FREELIST(data); - return(1); + return 1; } /* Step 3: perform the installation */ + alpm_list_t *packages = alpm_trans_get_add(config->handle); if(config->print) { - print_packages(alpm_trans_get_add()); + print_packages(packages); trans_release(); - return(0); + return 0; } /* print targets and ask user confirmation */ - alpm_list_t *packages = alpm_trans_get_add(); if(packages == NULL) { /* we are done */ printf(_(" there is nothing to do\n")); trans_release(); - return(retval); + return retval; } - display_targets(alpm_trans_get_remove(), 0); - display_targets(alpm_trans_get_add(), 1); + display_targets(alpm_trans_get_remove(config->handle), 0); + display_targets(alpm_trans_get_add(config->handle), 1); printf("\n"); int confirm = yesno(_("Proceed with installation?")); if(!confirm) { trans_release(); - return(retval); + return retval; } - if(alpm_trans_commit(&data) == -1) { + if(alpm_trans_commit(config->handle, &data) == -1) { + enum _pmerrno_t err = alpm_errno(config->handle); pm_fprintf(stderr, PM_LOG_ERROR, _("failed to commit transaction (%s)\n"), - alpm_strerrorlast()); - switch(pm_errno) { + alpm_strerror(err)); + switch(err) { alpm_list_t *i; case PM_ERR_FILE_CONFLICTS: for(i = data; i; i = alpm_list_next(i)) { @@ -197,13 +200,13 @@ int pacman_upgrade(alpm_list_t *targets) } FREELIST(data); trans_release(); - return(1); + return 1; } if(trans_release() == -1) { retval = 1; } - return(retval); + return retval; } /* vim: set ts=2 sw=2 noet: */ diff --git a/src/pacman/util.c b/src/pacman/util.c index f695ffba..5d666e21 100644 --- a/src/pacman/util.c +++ b/src/pacman/util.c @@ -31,12 +31,14 @@ #include <stdint.h> /* intmax_t */ #include <string.h> #include <errno.h> -#include <fcntl.h> #include <ctype.h> #include <dirent.h> #include <unistd.h> #include <limits.h> #include <wchar.h> +#ifdef HAVE_TERMIOS_H +#include <termios.h> /* tcflush */ +#endif #include <alpm.h> #include <alpm_list.h> @@ -51,55 +53,69 @@ int trans_init(pmtransflag_t flags) { int ret; if(config->print) { - ret = alpm_trans_init(flags, NULL, NULL, NULL); + ret = alpm_trans_init(config->handle, flags, NULL, NULL, NULL); } else { - ret = alpm_trans_init(flags, cb_trans_evt, cb_trans_conv, + ret = alpm_trans_init(config->handle, flags, cb_trans_evt, cb_trans_conv, cb_trans_progress); } if(ret == -1) { + enum _pmerrno_t err = alpm_errno(config->handle); pm_fprintf(stderr, PM_LOG_ERROR, _("failed to init transaction (%s)\n"), - alpm_strerrorlast()); - if(pm_errno == PM_ERR_HANDLE_LOCK) { + alpm_strerror(err)); + if(err == PM_ERR_HANDLE_LOCK) { fprintf(stderr, _(" if you're sure a package manager is not already\n" - " running, you can remove %s\n"), alpm_option_get_lockfile()); + " running, you can remove %s\n"), + alpm_option_get_lockfile(config->handle)); } - else if(pm_errno == PM_ERR_DB_VERSION) { + else if(err == PM_ERR_DB_VERSION) { fprintf(stderr, _(" try running pacman-db-upgrade\n")); } - return(-1); + return -1; } - return(0); + return 0; } int trans_release(void) { - if(alpm_trans_release() == -1) { + if(alpm_trans_release(config->handle) == -1) { pm_fprintf(stderr, PM_LOG_ERROR, _("failed to release transaction (%s)\n"), - alpm_strerrorlast()); - return(-1); + alpm_strerror(alpm_errno(config->handle))); + return -1; } - return(0); + return 0; } int needs_root(void) { switch(config->op) { case PM_OP_DATABASE: - return(1); + return 1; case PM_OP_UPGRADE: case PM_OP_REMOVE: - return(!config->print); + return !config->print; case PM_OP_SYNC: - return(config->op_s_clean || config->op_s_sync || + return (config->op_s_clean || config->op_s_sync || (!config->group && !config->op_s_info && !config->op_q_list && !config->op_s_search && !config->print)); default: - return(0); + return 0; } } +/* discard unhandled input on the terminal's input buffer */ +static int flush_term_input(void) { +#ifdef HAVE_TCFLUSH + if(isatty(fileno(stdin))) { + return tcflush(fileno(stdin), TCIFLUSH); + } +#endif + + /* fail silently */ + return 0; +} + /* gets the current screen column width */ int getcols(int def) { @@ -125,24 +141,24 @@ int rmrf(const char *path) DIR *dirp; if(!unlink(path)) { - return(0); + return 0; } else { if(errno == ENOENT) { - return(0); + return 0; } else if(errno == EPERM) { /* fallthrough */ } else if(errno == EISDIR) { /* fallthrough */ } else if(errno == ENOTDIR) { - return(1); + return 1; } else { /* not a directory */ - return(1); + return 1; } dirp = opendir(path); if(!dirp) { - return(1); + return 1; } for(dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) { if(dp->d_ino) { @@ -157,7 +173,7 @@ int rmrf(const char *path) if(rmdir(path)) { errflag++; } - return(errflag); + return errflag; } } @@ -170,9 +186,9 @@ const char *mbasename(const char *path) { const char *last = strrchr(path, '/'); if(last) { - return(last + 1); + return last + 1; } - return(path); + return path; } /** Parse the dirname of a program from a path. @@ -187,7 +203,7 @@ char *mdirname(const char *path) /* null or empty path */ if(path == NULL || path == '\0') { - return(strdup(".")); + return strdup("."); } ret = strdup(path); @@ -196,11 +212,11 @@ char *mdirname(const char *path) if(last != NULL) { /* we found a '/', so terminate our string */ *last = '\0'; - return(ret); + return ret; } /* no slash found */ free(ret); - return(strdup(".")); + return strdup("."); } /* output a string, but wrap words properly with a specified indentation @@ -286,7 +302,7 @@ char *strtrim(char *str) if(str == NULL || *str == '\0') { /* string is empty, so we're done. */ - return(str); + return str; } while(isspace((unsigned char)*pch)) { @@ -298,7 +314,7 @@ char *strtrim(char *str) /* check if there wasn't anything but whitespace in the string. */ if(*str == '\0') { - return(str); + return str; } pch = (str + (strlen(str) - 1)); @@ -307,7 +323,7 @@ char *strtrim(char *str) } *++pch = '\0'; - return(str); + return str; } /* Replace all occurances of 'needle' with 'replace' in 'str', returning @@ -321,7 +337,7 @@ char *strreplace(const char *str, const char *needle, const char *replace) size_t newsz; if(!str) { - return(NULL); + return NULL; } p = str; @@ -334,7 +350,7 @@ char *strreplace(const char *str, const char *needle, const char *replace) /* no occurences of needle found */ if(!list) { - return(strdup(str)); + return strdup(str); } /* size of new string = size of old string + "number of occurences of needle" * x "size difference between replace and needle" */ @@ -342,7 +358,7 @@ char *strreplace(const char *str, const char *needle, const char *replace) alpm_list_count(list) * (replacesz - needlesz); newstr = malloc(newsz); if(!newstr) { - return(NULL); + return NULL; } *newstr = '\0'; @@ -368,7 +384,7 @@ char *strreplace(const char *str, const char *needle, const char *replace) } *newp = '\0'; - return(newstr); + return newstr; } /** Splits a string into a list of strings using the chosen character as @@ -388,7 +404,7 @@ alpm_list_t *strsplit(const char *str, const char splitchar) while((str = strchr(str, splitchar))) { dup = strndup(prev, (size_t)(str - prev)); if(dup == NULL) { - return(NULL); + return NULL; } list = alpm_list_add(list, dup); @@ -398,11 +414,11 @@ alpm_list_t *strsplit(const char *str, const char splitchar) dup = strdup(prev); if(dup == NULL) { - return(NULL); + return NULL; } list = alpm_list_add(list, dup); - return(list); + return list; } static int string_length(const char *s) @@ -411,7 +427,7 @@ static int string_length(const char *s) wchar_t *wcstr; if(!s) { - return(0); + return 0; } /* len goes from # bytes -> # chars -> # cols */ len = strlen(s) + 1; @@ -420,7 +436,7 @@ static int string_length(const char *s) len = wcswidth(wcstr, len); free(wcstr); - return(len); + return len; } void string_display(const char *title, const char *string) @@ -438,6 +454,117 @@ void string_display(const char *title, const char *string) printf("\n"); } +static void table_print_line(const alpm_list_t *line, + const alpm_list_t *formats) +{ + const alpm_list_t *curformat = formats; + const alpm_list_t *curcell = line; + + while(curcell && curformat) { + printf(alpm_list_getdata(curformat), alpm_list_getdata(curcell)); + curcell = alpm_list_next(curcell); + curformat = alpm_list_next(curformat); + } + + printf("\n"); +} + +/* creates format strings by checking max cell lengths in cols */ +static alpm_list_t *table_create_format(const alpm_list_t *header, + const alpm_list_t *rows) +{ + alpm_list_t *longest_str, *longest_strs = NULL; + alpm_list_t *formats = NULL; + const alpm_list_t *i, *row, *cell; + char *str, *formatstr; + const int padding = 2; + int colwidth, totalwidth = 0; + int curcol = 0; + + /* header determines column count and initial values of longest_strs */ + for(i = header; i; i = alpm_list_next(i)) { + longest_strs = alpm_list_add(longest_strs, alpm_list_getdata(i)); + } + + /* now find the longest string in each column */ + for(longest_str = longest_strs; longest_str; + longest_str = alpm_list_next(longest_str), curcol++) { + for(i = rows; i; i = alpm_list_next(i)) { + row = alpm_list_getdata(i); + cell = alpm_list_nth(row, curcol); + str = alpm_list_getdata(cell); + + if(strlen(str) > strlen(alpm_list_getdata(longest_str))) { + longest_str->data = str; + } + } + } + + /* now use the column width info to generate format strings */ + for(i = longest_strs; i; i = alpm_list_next(i)) { + const char *display; + colwidth = strlen(alpm_list_getdata(i)) + padding; + totalwidth += colwidth; + + /* right align the last column for a cleaner table display */ + display = (alpm_list_next(i) != NULL) ? "%%-%ds" : "%%%ds"; + pm_asprintf(&formatstr, display, colwidth); + + formats = alpm_list_add(formats, formatstr); + } + + alpm_list_free(longest_strs); + + /* return NULL if terminal is not wide enough */ + if(totalwidth > getcols(80)) { + pm_fprintf(stderr, PM_LOG_WARNING, _("insufficient columns available for table display\n")); + FREELIST(formats); + return NULL; + } + + return formats; +} + +/** Displays the list in table format + * + * @param title the tables title + * @param header the column headers. column count is determined by the nr + * of headers + * @param rows the rows to display as a list of lists of strings. the outer + * list represents the rows, the inner list the cells (= columns) + * + * @return -1 if not enough terminal cols available, else 0 + */ +int table_display(const char *title, const alpm_list_t *header, + const alpm_list_t *rows) +{ + const alpm_list_t *i; + alpm_list_t *formats; + + if(rows == NULL || header == NULL) { + return 0; + } + + formats = table_create_format(header, rows); + if(formats == NULL) { + return -1; + } + + if(title != NULL) { + printf("%s\n\n", title); + } + + table_print_line(header, formats); + printf("\n"); + + for(i = rows; i; i = alpm_list_next(i)) { + table_print_line(alpm_list_getdata(i), formats); + } + + FREELIST(formats); + return 0; +} + void list_display(const char *title, const alpm_list_t *list) { const alpm_list_t *i; @@ -467,7 +594,7 @@ void list_display(const char *title, const alpm_list_t *list) for (j = 1; j <= len; j++) { printf(" "); } - } else if (cols != len) { + } else if(cols != len) { /* 2 spaces are added if this is not the first element on a line. */ printf(" "); cols += 2; @@ -506,100 +633,215 @@ void list_display_linebreak(const char *title, const alpm_list_t *list) } } } + +/* creates a header row for use with table_display */ +static alpm_list_t *create_verbose_header(int install) +{ + alpm_list_t *res = NULL; + char *str; + + pm_asprintf(&str, "%s", _("Name")); + res = alpm_list_add(res, str); + pm_asprintf(&str, "%s", _("Old Version")); + res = alpm_list_add(res, str); + if(install) { + pm_asprintf(&str, "%s", _("New Version")); + res = alpm_list_add(res, str); + } + pm_asprintf(&str, "%s", _("Size")); + res = alpm_list_add(res, str); + + return res; +} + +/* returns package info as list of strings */ +static alpm_list_t *create_verbose_row(pmpkg_t *pkg, int install) +{ + char *str; + double size; + const char *label; + alpm_list_t *ret = NULL; + pmdb_t *ldb = alpm_option_get_localdb(config->handle); + + /* a row consists of the package name, */ + pm_asprintf(&str, "%s", alpm_pkg_get_name(pkg)); + ret = alpm_list_add(ret, str); + + /* old and new versions */ + if(install) { + pmpkg_t *oldpkg = alpm_db_get_pkg(ldb, alpm_pkg_get_name(pkg)); + pm_asprintf(&str, "%s", + oldpkg != NULL ? alpm_pkg_get_version(oldpkg) : ""); + ret = alpm_list_add(ret, str); + } + + pm_asprintf(&str, "%s", alpm_pkg_get_version(pkg)); + ret = alpm_list_add(ret, str); + + /* and size */ + size = humanize_size(alpm_pkg_get_size(pkg), 'M', 1, &label); + pm_asprintf(&str, "%.2f %s", size, label); + ret = alpm_list_add(ret, str); + + return ret; +} + /* prepare a list of pkgs to display */ void display_targets(const alpm_list_t *pkgs, int install) { char *str; + const char *title, *label; + double size; const alpm_list_t *i; - off_t isize = 0, dlsize = 0; - double mbisize = 0.0, mbdlsize = 0.0; - alpm_list_t *targets = NULL; + off_t isize = 0, rsize = 0, dlsize = 0; + alpm_list_t *j, *lp, *header = NULL, *targets = NULL; + pmdb_t *db_local = alpm_option_get_localdb(config->handle); if(!pkgs) { return; } - printf("\n"); + /* gather pkg infos */ for(i = pkgs; i; i = alpm_list_next(i)) { pmpkg_t *pkg = alpm_list_getdata(i); if(install) { + pmpkg_t *lpkg = alpm_db_get_pkg(db_local, alpm_pkg_get_name(pkg)); dlsize += alpm_pkg_download_size(pkg); + if(lpkg) { + /* add up size of all removed packages */ + rsize += alpm_pkg_get_isize(lpkg); + } } isize += alpm_pkg_get_isize(pkg); - /* print the package size with the output if ShowSize option set */ - if(config->showsize) { - double mbsize = (double)alpm_pkg_get_size(pkg) / (1024.0 * 1024.0); - - pm_asprintf(&str, "%s-%s [%.2f MB]", alpm_pkg_get_name(pkg), - alpm_pkg_get_version(pkg), mbsize); + if(config->verbosepkglists) { + targets = alpm_list_add(targets, create_verbose_row(pkg, install)); } else { pm_asprintf(&str, "%s-%s", alpm_pkg_get_name(pkg), alpm_pkg_get_version(pkg)); + targets = alpm_list_add(targets, str); } - targets = alpm_list_add(targets, str); } - /* Convert byte sizes to MB */ - mbdlsize = (double)dlsize / (1024.0 * 1024.0); - mbisize = (double)isize / (1024.0 * 1024.0); + /* print to screen */ + title = install ? _("Targets (%d):") : _("Remove (%d):"); + pm_asprintf(&str, title, alpm_list_count(pkgs)); - if(install) { - pm_asprintf(&str, _("Targets (%d):"), alpm_list_count(targets)); + printf("\n"); + if(config->verbosepkglists) { + header = create_verbose_header(install); + if(table_display(str, header, targets) != 0) { + config->verbosepkglists = 0; + display_targets(pkgs, install); + goto out; + } + } else { list_display(str, targets); - free(str); - printf("\n"); + } + printf("\n"); - printf(_("Total Download Size: %.2f MB\n"), mbdlsize); + if(install) { + size = humanize_size(dlsize, 'M', 1, &label); + printf(_("Total Download Size: %.2f %s\n"), size, label); if(!(config->flags & PM_TRANS_FLAG_DOWNLOADONLY)) { - printf(_("Total Installed Size: %.2f MB\n"), mbisize); + size = humanize_size(isize, 'M', 1, &label); + printf(_("Total Installed Size: %.2f %s\n"), size, label); + /* only show this net value if different from raw installed size */ + if(rsize > 0) { + size = humanize_size(isize - rsize, 'M', 1, &label); + printf(_("Net Upgrade Size: %.2f %s\n"), size, label); + } } } else { - pm_asprintf(&str, _("Remove (%d):"), alpm_list_count(targets)); - list_display(str, targets); - free(str); - printf("\n"); - - printf(_("Total Removed Size: %.2f MB\n"), mbisize); + size = humanize_size(isize, 'M', 1, &label); + printf(_("Total Removed Size: %.2f %s\n"), size, label); } - FREELIST(targets); +out: + /* cleanup */ + if(config->verbosepkglists) { + /* targets is a list of lists of strings, free inner lists here */ + for(j = alpm_list_first(targets); j; j = alpm_list_next(j)) { + lp = alpm_list_getdata(j); + FREELIST(lp); + } + alpm_list_free(targets); + FREELIST(header); + } else { + FREELIST(targets); + } + free(str); } static off_t pkg_get_size(pmpkg_t *pkg) { switch(config->op) { case PM_OP_SYNC: - return(alpm_pkg_download_size(pkg)); + return alpm_pkg_download_size(pkg); case PM_OP_UPGRADE: - return(alpm_pkg_get_size(pkg)); + return alpm_pkg_get_size(pkg); default: - return(alpm_pkg_get_isize(pkg)); + return alpm_pkg_get_isize(pkg); } } static char *pkg_get_location(pmpkg_t *pkg) { - pmdb_t *db; - const char *dburl; - char *string; + alpm_list_t *servers; + char *string = NULL; switch(config->op) { case PM_OP_SYNC: - db = alpm_pkg_get_db(pkg); - dburl = alpm_db_get_url(db); - if(dburl) { - char *pkgurl = NULL; - pm_asprintf(&pkgurl, "%s/%s", dburl, alpm_pkg_get_filename(pkg)); - return(pkgurl); + servers = alpm_db_get_servers(alpm_pkg_get_db(pkg)); + if(servers) { + pm_asprintf(&string, "%s/%s", alpm_list_getdata(servers), + alpm_pkg_get_filename(pkg)); + return string; } case PM_OP_UPGRADE: - return(strdup(alpm_pkg_get_filename(pkg))); + return strdup(alpm_pkg_get_filename(pkg)); default: - string = NULL; pm_asprintf(&string, "%s-%s", alpm_pkg_get_name(pkg), alpm_pkg_get_version(pkg)); - return(string); + return string; + } +} + +/** Converts sizes in bytes into human readable units. + * + * @param bytes the size in bytes + * @param target_unit '\0' or a short label. If equal to one of the short unit + * labels ('B', 'K', ...) bytes is converted to target_unit; if '\0', the first + * unit which will bring the value to below a threshold of 2048 will be chosen. + * @param long_labels whether to use short ("K") or long ("KiB") unit labels + * @param label will be set to the appropriate unit label + * + * @return the size in the appropriate unit + */ +double humanize_size(off_t bytes, const char target_unit, int long_labels, + const char **label) +{ + static const char *shortlabels[] = {"B", "K", "M", "G", "T", "P"}; + static const char *longlabels[] = {"B", "KiB", "MiB", "GiB", "TiB", "PiB"}; + static const int unitcount = sizeof(shortlabels) / sizeof(shortlabels[0]); + + const char **labels = long_labels ? longlabels : shortlabels; + double val = (double)bytes; + int index; + + for(index = 0; index < unitcount - 1; index++) { + if(target_unit != '\0' && shortlabels[index][0] == target_unit) { + break; + } else if(target_unit == '\0' && val <= 2048.0 && val >= -2048.0) { + break; + } + val /= 1024.0; } + + if(label) { + *label = labels[index]; + } + + return val; } void print_packages(const alpm_list_t *packages) @@ -660,7 +902,7 @@ void print_packages(const alpm_list_t *packages) * alpm "compare func" signature */ int str_cmp(const void *s1, const void *s2) { - return(strcmp(s1, s2)); + return strcmp(s1, s2); } void display_new_optdepends(pmpkg_t *oldpkg, pmpkg_t *newpkg) @@ -729,13 +971,13 @@ static int parseindex(char *s, int *val, int min, int max) if(n < min || n > max) { fprintf(stderr, _("Invalid value: %d is not between %d and %d\n"), n, min, max); - return(-1); + return -1; } *val = n; - return(0); + return 0; } else { fprintf(stderr, _("Invalid number: %s\n"), s); - return(-1); + return -1; } } @@ -749,7 +991,7 @@ static int multiselect_parse(char *array, int count, char *response) char *ends = NULL; char *starts = strtok_r(str, " ", &saveptr); - if (starts == NULL) { + if(starts == NULL) { break; } strtrim(starts); @@ -757,7 +999,7 @@ static int multiselect_parse(char *array, int count, char *response) if(len == 0) continue; - if (*starts == '^') { + if(*starts == '^') { starts++; len--; include = 0; @@ -776,14 +1018,14 @@ static int multiselect_parse(char *array, int count, char *response) } if(parseindex(starts, &start, 1, count) != 0) - return(-1); + return -1; if(!ends) { array[start-1] = include; } else { int d; if(parseindex(ends, &end, start, count) != 0) { - return(-1); + return -1; } for(d = start; d <= end; d++) { array[d-1] = include; @@ -791,7 +1033,7 @@ static int multiselect_parse(char *array, int count, char *response) } } - return(0); + return 0; } int multiselect_question(char *array, int count) @@ -818,6 +1060,8 @@ int multiselect_question(char *array, int count) break; } + flush_term_input(); + if(fgets(response, sizeof(response), stdin)) { strtrim(response); if(strlen(response) > 0) { @@ -829,7 +1073,7 @@ int multiselect_question(char *array, int count) } break; } - return(0); + return 0; } int select_question(int count) @@ -855,19 +1099,21 @@ int select_question(int count) break; } + flush_term_input(); + 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); + return (n - 1); } } break; } - return(preset-1); + return (preset - 1); } @@ -898,23 +1144,25 @@ static int question(short preset, char *fmt, va_list args) if(config->noconfirm) { fprintf(stream, "\n"); - return(preset); + return preset; } fflush(stream); + flush_term_input(); + if(fgets(response, sizeof(response), stdin)) { strtrim(response); if(strlen(response) == 0) { - return(preset); + return preset; } if(strcasecmp(response, _("Y")) == 0 || strcasecmp(response, _("YES")) == 0) { - return(1); - } else if (strcasecmp(response, _("N")) == 0 || strcasecmp(response, _("NO")) == 0) { - return(0); + return 1; + } else if(strcasecmp(response, _("N")) == 0 || strcasecmp(response, _("NO")) == 0) { + return 0; } } - return(0); + return 0; } int yesno(char *fmt, ...) @@ -926,7 +1174,7 @@ int yesno(char *fmt, ...) ret = question(1, fmt, args); va_end(args); - return(ret); + return ret; } int noyes(char *fmt, ...) @@ -938,7 +1186,7 @@ int noyes(char *fmt, ...) ret = question(0, fmt, args); va_end(args); - return(ret); + return ret; } int pm_printf(pmloglevel_t level, const char *format, ...) @@ -951,7 +1199,7 @@ int pm_printf(pmloglevel_t level, const char *format, ...) ret = pm_vfprintf(stdout, level, format, args); va_end(args); - return(ret); + return ret; } int pm_fprintf(FILE *stream, pmloglevel_t level, const char *format, ...) @@ -964,7 +1212,7 @@ int pm_fprintf(FILE *stream, pmloglevel_t level, const char *format, ...) ret = pm_vfprintf(stream, level, format, args); va_end(args); - return(ret); + return ret; } int pm_asprintf(char **string, const char *format, ...) @@ -980,7 +1228,7 @@ int pm_asprintf(char **string, const char *format, ...) } va_end(args); - return(ret); + return ret; } int pm_vasprintf(char **string, pmloglevel_t level, const char *format, va_list args) @@ -1016,7 +1264,7 @@ int pm_vasprintf(char **string, pmloglevel_t level, const char *format, va_list } free(msg); - return(ret); + return ret; } int pm_vfprintf(FILE *stream, pmloglevel_t level, const char *format, va_list args) @@ -1064,7 +1312,7 @@ int pm_vfprintf(FILE *stream, pmloglevel_t level, const char *format, va_list ar /* print the message using va_arg list */ ret = vfprintf(stream, format, args); - return(ret); + return ret; } #ifndef HAVE_STRNDUP @@ -1073,7 +1321,7 @@ static size_t strnlen(const char *s, size_t max) { register const char *p; for(p = s; *p && max--; ++p); - return(p - s); + return (p - s); } char *strndup(const char *s, size_t n) @@ -1081,11 +1329,11 @@ char *strndup(const char *s, size_t n) size_t len = strnlen(s, n); char *new = (char *) malloc(len + 1); - if (new == NULL) + if(new == NULL) return NULL; new[len] = '\0'; - return (char *) memcpy(new, s, len); + return (char *)memcpy(new, s, len); } #endif diff --git a/src/pacman/util.h b/src/pacman/util.h index 53176fae..95c1ce92 100644 --- a/src/pacman/util.h +++ b/src/pacman/util.h @@ -52,6 +52,8 @@ char *strtrim(char *str); char *strreplace(const char *str, const char *needle, const char *replace); alpm_list_t *strsplit(const char *str, const char splitchar); void string_display(const char *title, const char *string); +double humanize_size(off_t bytes, const char target_unit, int long_labels, const char **label); +int table_display(const char *title, const alpm_list_t *header, const alpm_list_t *rows); 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); |