diff options
Diffstat (limited to 'src/pacman')
-rw-r--r-- | src/pacman/callback.c | 26 | ||||
-rw-r--r-- | src/pacman/conf.h | 20 | ||||
-rw-r--r-- | src/pacman/pacman.c | 172 | ||||
-rw-r--r-- | src/pacman/remove.c | 85 | ||||
-rw-r--r-- | src/pacman/sync.c | 216 | ||||
-rw-r--r-- | src/pacman/upgrade.c | 82 | ||||
-rw-r--r-- | src/pacman/util.c | 214 | ||||
-rw-r--r-- | src/pacman/util.h | 4 |
8 files changed, 431 insertions, 388 deletions
diff --git a/src/pacman/callback.c b/src/pacman/callback.c index 1cdb1153..858bfdf4 100644 --- a/src/pacman/callback.c +++ b/src/pacman/callback.c @@ -259,10 +259,20 @@ void cb_trans_conv(pmtransconv_t event, void *data1, void *data2, alpm_pkg_get_name(data2)); break; case PM_TRANS_CONV_CONFLICT_PKG: - *response = yesno(_(":: %s conflicts with %s. Remove %s?"), - (char *)data1, - (char *)data2, - (char *)data2); + /* data parameters: target package, local package, conflict (strings) */ + /* print conflict only if it contains new information */ + if(!strcmp(data1, data3) || !strcmp(data2, data3)) { + *response = noyes(_(":: %s and %s are in conflict. Remove %s?"), + (char *)data1, + (char *)data2, + (char *)data2); + } else { + *response = noyes(_(":: %s and %s are in conflict (%s). Remove %s?"), + (char *)data1, + (char *)data2, + (char *)data3, + (char *)data2); + } break; case PM_TRANS_CONV_REMOVE_PKGS: { @@ -275,7 +285,7 @@ void cb_trans_conv(pmtransconv_t event, void *data1, void *data2, printf(_(":: the following package(s) cannot be upgraded due to " "unresolvable dependencies:\n")); list_display(" ", namelist); - *response = yesno(_("\nDo you want to skip the above " + *response = noyes(_("\nDo you want to skip the above " "package(s) for this upgrade?")); alpm_list_free(namelist); } @@ -294,6 +304,12 @@ void cb_trans_conv(pmtransconv_t event, void *data1, void *data2, (char *)data1); break; } + if(config->noask) { + if(config->ask & event) { + /* inverse the default answer */ + *response = !*response; + } + } } /* callback to handle display of transaction progress */ diff --git a/src/pacman/conf.h b/src/pacman/conf.h index 2d3de987..c97e5d78 100644 --- a/src/pacman/conf.h +++ b/src/pacman/conf.h @@ -63,6 +63,8 @@ typedef struct __config_t { unsigned short group; pmtransflag_t flags; + unsigned short noask; + unsigned int ask; /* conf file options */ unsigned short chomp; /* I Love Candy! */ @@ -86,6 +88,24 @@ enum { PM_OP_DEPTEST }; +/* Long Operations */ +enum { + OP_NOCONFIRM = 1000, + OP_CONFIG, + OP_IGNORE, + OP_DEBUG, + OP_NOPROGRESSBAR, + OP_NOSCRIPTLET, + OP_ASK, + OP_CACHEDIR, + OP_ASDEPS, + OP_LOGFILE, + OP_IGNOREGROUP, + OP_NEEDED, + OP_ASEXPLICIT, + OP_ARCH +}; + /* clean method */ enum { PM_CLEAN_KEEPINST = 0, /* default */ diff --git a/src/pacman/pacman.c b/src/pacman/pacman.c index 4c556a7d..f4f80449 100644 --- a/src/pacman/pacman.c +++ b/src/pacman/pacman.c @@ -149,6 +149,7 @@ static void usage(int op, const char * const myname) printf(_(" -r, --root <path> set an alternate installation root\n")); printf(_(" -b, --dbpath <path> set an alternate database location\n")); printf(_(" --cachedir <dir> set an alternate package cache location\n")); + printf(_(" --arch <arch> set an alternate architecture\n")); } } @@ -195,6 +196,19 @@ 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 @@ -364,18 +378,20 @@ static int parseargs(int argc, char *argv[]) {"verbose", no_argument, 0, 'v'}, {"downloadonly", no_argument, 0, 'w'}, {"refresh", no_argument, 0, 'y'}, - {"noconfirm", no_argument, 0, 1000}, - {"config", required_argument, 0, 1001}, - {"ignore", required_argument, 0, 1002}, - {"debug", optional_argument, 0, 1003}, - {"noprogressbar", no_argument, 0, 1004}, - {"noscriptlet", no_argument, 0, 1005}, - {"cachedir", required_argument, 0, 1007}, - {"asdeps", no_argument, 0, 1008}, - {"logfile", required_argument, 0, 1009}, - {"ignoregroup", required_argument, 0, 1010}, - {"needed", no_argument, 0, 1011}, - {"asexplicit", no_argument, 0, 1012}, + {"noconfirm", no_argument, 0, OP_NOCONFIRM}, + {"config", required_argument, 0, OP_CONFIG}, + {"ignore", required_argument, 0, OP_IGNORE}, + {"debug", optional_argument, 0, OP_DEBUG}, + {"noprogressbar", no_argument, 0, OP_NOPROGRESSBAR}, + {"noscriptlet", no_argument, 0, OP_NOSCRIPTLET}, + {"ask", required_argument, 0, OP_ASK}, + {"cachedir", required_argument, 0, OP_CACHEDIR}, + {"asdeps", no_argument, 0, OP_ASDEPS}, + {"logfile", required_argument, 0, OP_LOGFILE}, + {"ignoregroup", required_argument, 0, OP_IGNOREGROUP}, + {"needed", no_argument, 0, OP_NEEDED}, + {"asexplicit", no_argument, 0, OP_ASEXPLICIT}, + {"arch", required_argument, 0, OP_ARCH}, {0, 0, 0, 0} }; @@ -387,21 +403,21 @@ static int parseargs(int argc, char *argv[]) } switch(opt) { case 0: break; - case 1000: config->noconfirm = 1; break; - case 1001: + case OP_NOCONFIRM: config->noconfirm = 1; break; + case OP_CONFIG: if(config->configfile) { free(config->configfile); } config->configfile = strndup(optarg, PATH_MAX); break; - case 1002: + case OP_IGNORE: list = strsplit(optarg, ','); for(item = list; item; item = alpm_list_next(item)) { alpm_option_add_ignorepkg((char *)alpm_list_getdata(item)); } FREELIST(list); break; - case 1003: + case OP_DEBUG: /* debug levels are made more 'human readable' than using a raw logmask * here, error and warning are set in config_new, though perhaps a * --quiet option will remove these later */ @@ -424,32 +440,36 @@ static int parseargs(int argc, char *argv[]) /* progress bars get wonky with debug on, shut them off */ config->noprogressbar = 1; break; - case 1004: config->noprogressbar = 1; break; - case 1005: config->flags |= PM_TRANS_FLAG_NOSCRIPTLET; break; - case 1007: + case OP_NOPROGRESSBAR: config->noprogressbar = 1; break; + case OP_NOSCRIPTLET: config->flags |= PM_TRANS_FLAG_NOSCRIPTLET; break; + case OP_ASK: config->noask = 1; config->ask = atoi(optarg); break; + case OP_CACHEDIR: if(alpm_option_add_cachedir(optarg) != 0) { pm_printf(PM_LOG_ERROR, _("problem adding cachedir '%s' (%s)\n"), optarg, alpm_strerrorlast()); return(1); } break; - case 1008: + case OP_ASDEPS: config->flags |= PM_TRANS_FLAG_ALLDEPS; break; - case 1009: + case OP_LOGFILE: config->logfile = strndup(optarg, PATH_MAX); break; - case 1010: + case OP_IGNOREGROUP: list = strsplit(optarg, ','); for(item = list; item; item = alpm_list_next(item)) { alpm_option_add_ignoregrp((char *)alpm_list_getdata(item)); } FREELIST(list); break; - case 1011: config->flags |= PM_TRANS_FLAG_NEEDED; break; - case 1012: + case OP_NEEDED: config->flags |= PM_TRANS_FLAG_NEEDED; break; + case OP_ASEXPLICIT: config->flags |= PM_TRANS_FLAG_ALLEXPLICIT; break; + case OP_ARCH: + setarch(optarg); + break; case 'Q': config->op = (config->op != PM_OP_MAIN ? 0 : PM_OP_QUERY); break; case 'R': config->op = (config->op != PM_OP_MAIN ? 0 : PM_OP_REMOVE); break; case 'S': config->op = (config->op != PM_OP_MAIN ? 0 : PM_OP_SYNC); break; @@ -592,7 +612,7 @@ static char *get_filename(const char *url) { static char *get_destfile(const char *path, const char *filename) { char *destfile; /* len = localpath len + filename len + null */ - int len = strlen(path) + strlen(filename) + 1; + size_t len = strlen(path) + strlen(filename) + 1; destfile = calloc(len, sizeof(char)); snprintf(destfile, len, "%s%s", path, filename); @@ -602,7 +622,7 @@ static char *get_destfile(const char *path, const char *filename) { static char *get_tempfile(const char *path, const char *filename) { char *tempfile; /* len = localpath len + filename len + '.part' len + null */ - int len = strlen(path) + strlen(filename) + 6; + size_t len = strlen(path) + strlen(filename) + 6; tempfile = calloc(len, sizeof(char)); snprintf(tempfile, len, "%s%s.part", path, filename); @@ -615,9 +635,7 @@ int download_with_xfercommand(const char *url, const char *localpath, int ret = 0; int retval; int usepart = 0; - char *ptr1, *ptr2; - char origCmd[PATH_MAX]; - char parsedCmd[PATH_MAX] = ""; + char *parsedcmd,*tempcmd; char cwd[PATH_MAX]; char *destfile, *tempfile, *filename; @@ -632,28 +650,18 @@ int download_with_xfercommand(const char *url, const char *localpath, destfile = get_destfile(localpath, filename); tempfile = get_tempfile(localpath, filename); - strncpy(origCmd, config->xfercommand, sizeof(origCmd)); + tempcmd = strdup(config->xfercommand); /* replace all occurrences of %o with fn.part */ - ptr1 = origCmd; - while((ptr2 = strstr(ptr1, "%o"))) { + if(strstr(tempcmd, "%o")) { usepart = 1; - ptr2[0] = '\0'; - strcat(parsedCmd, ptr1); - strcat(parsedCmd, tempfile); - ptr1 = ptr2 + 2; + parsedcmd = strreplace(tempcmd, "%o", tempfile); + free(tempcmd); + tempcmd = parsedcmd; } - strcat(parsedCmd, ptr1); /* replace all occurrences of %u with the download URL */ - strncpy(origCmd, parsedCmd, sizeof(origCmd)); - parsedCmd[0] = '\0'; - ptr1 = origCmd; - while((ptr2 = strstr(ptr1, "%u"))) { - ptr2[0] = '\0'; - strcat(parsedCmd, ptr1); - strcat(parsedCmd, url); - ptr1 = ptr2 + 2; - } - strcat(parsedCmd, ptr1); + parsedcmd = strreplace(tempcmd, "%u", url); + free(tempcmd); + /* cwd to the download directory */ getcwd(cwd, PATH_MAX); if(chdir(localpath)) { @@ -662,8 +670,8 @@ int download_with_xfercommand(const char *url, const char *localpath, goto cleanup; } /* execute the parsed command via /bin/sh -c */ - pm_printf(PM_LOG_DEBUG, "running command: %s\n", parsedCmd); - retval = system(parsedCmd); + 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")); @@ -689,6 +697,7 @@ cleanup: } free(destfile); free(tempfile); + free(parsedcmd); return(ret); } @@ -749,11 +758,8 @@ static int _parseconfig(const char *file, const char *givensection, ret = 1; goto cleanup; } - /* if we are not looking at the options section, register a db and also - * ensure we have set all of our library paths as the library is too stupid - * at the moment to do lazy opening of the databases */ + /* if we are not looking at the options section, register a db */ if(strcmp(section, "options") != 0) { - setlibpaths(); db = alpm_db_register_sync(section); if(db == NULL) { pm_printf(PM_LOG_ERROR, _("could not register '%s' database (%s)\n"), @@ -787,10 +793,7 @@ static int _parseconfig(const char *file, const char *givensection, } if(ptr == NULL && strcmp(section, "options") == 0) { /* directives without settings, all in [options] */ - if(strcmp(key, "NoPassiveFtp") == 0) { - alpm_option_set_nopassiveftp(1); - pm_printf(PM_LOG_DEBUG, "config: nopassiveftp\n"); - } else if(strcmp(key, "UseSyslog") == 0) { + if(strcmp(key, "UseSyslog") == 0) { alpm_option_set_usesyslog(1); pm_printf(PM_LOG_DEBUG, "config: usesyslog\n"); } else if(strcmp(key, "ILoveCandy") == 0) { @@ -830,6 +833,10 @@ static int _parseconfig(const char *file, const char *givensection, setrepeatingoption(ptr, "HoldPkg", option_add_holdpkg); } else if(strcmp(key, "SyncFirst") == 0) { setrepeatingoption(ptr, "SyncFirst", option_add_syncfirst); + } else if(strcmp(key, "Architecture") == 0) { + if(!alpm_option_get_arch()) { + setarch(ptr); + } } else if(strcmp(key, "DBPath") == 0) { /* don't overwrite a path specified on the command line */ if(!config->dbpath) { @@ -878,7 +885,23 @@ static int _parseconfig(const char *file, const char *givensection, } } else if(strcmp(key, "Server") == 0) { /* let's attempt a replacement for the current repo */ - char *server = strreplace(ptr, "$repo", section); + char *temp = strreplace(ptr, "$repo", section); + /* 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"), ptr); + ret = 1; + goto cleanup; + } + server = temp; + } if(alpm_db_setserver(db, server) != 0) { /* pm_errno is set by alpm_db_setserver */ @@ -923,6 +946,29 @@ static int parseconfig(const char *file) return(_parseconfig(file, NULL, NULL)); } +/** print commandline to logfile + */ +static void cl_to_log(int argc, char* argv[]) +{ + size_t size = 0; + int i; + for(i = 0; i<argc; i++) { + size += strlen(argv[i]) + 1; + } + char *cl_text = malloc(size); + if(!cl_text) + return; + char *p = cl_text; + for(i = 0; i<argc-1; i++) { + strcpy(p, argv[i]); + p += strlen(argv[i]); + *p++ = ' '; + } + strcpy(p, argv[i]); + alpm_logaction("Running '%s'\n", cl_text); + free(cl_text); +} + /** Main function. * @param argc argc * @param argv argv @@ -1018,6 +1064,11 @@ int main(int argc, char *argv[]) alpm_option_set_totaldlcb(cb_dl_total); } + /* noask is meant to be non-interactive */ + if(config->noask) { + config->noconfirm = 1; + } + #if defined(HAVE_GETEUID) && !defined(CYGWIN) /* check if we have sufficient permission for the requested operation */ if(myuid > 0 && needs_root()) { @@ -1049,6 +1100,11 @@ int main(int argc, char *argv[]) cleanup(EXIT_FAILURE); } + /* Log commandline */ + if(needs_root()) { + cl_to_log(argc, argv); + } + /* start the requested operation */ switch(config->op) { case PM_OP_REMOVE: diff --git a/src/pacman/remove.c b/src/pacman/remove.c index 0efbd94e..6d44350b 100644 --- a/src/pacman/remove.c +++ b/src/pacman/remove.c @@ -51,50 +51,23 @@ int pacman_remove(alpm_list_t *targets) } /* Step 0: create a new transaction */ - if(trans_init(PM_TRANS_TYPE_REMOVE, config->flags) == -1) { + if(trans_init(config->flags) == -1) { return(1); } /* Step 1: add targets to the created transaction */ for(i = targets; i; i = alpm_list_next(i)) { - char *targ = alpm_list_getdata(i); - if(alpm_trans_addtarget(targ) == -1) { - if(pm_errno == PM_ERR_PKG_NOT_FOUND) { - printf(_("%s not found, searching for group...\n"), targ); - pmgrp_t *grp = alpm_db_readgrp(db_local, targ); - if(grp == NULL) { - pm_fprintf(stderr, PM_LOG_ERROR, _("'%s': not found in local db\n"), targ); - retval = 1; - goto cleanup; - } else { - alpm_list_t *p, *pkgnames = NULL; - /* convert packages to package names */ - for(p = alpm_grp_get_pkgs(grp); p; p = alpm_list_next(p)) { - pmpkg_t *pkg = alpm_list_getdata(p); - pkgnames = alpm_list_add(pkgnames, (void *)alpm_pkg_get_name(pkg)); - } - printf(_(":: group %s:\n"), targ); - list_display(" ", pkgnames); - int all = yesno(_(" Remove whole content?")); - for(p = pkgnames; p; p = alpm_list_next(p)) { - char *pkgn = alpm_list_getdata(p); - if(all || yesno(_(":: Remove %s from group %s?"), pkgn, targ)) { - if(alpm_trans_addtarget(pkgn) == -1) { - pm_fprintf(stderr, PM_LOG_ERROR, "'%s': %s\n", targ, - alpm_strerrorlast()); - retval = 1; - alpm_list_free(pkgnames); - goto cleanup; - } - } - } - alpm_list_free(pkgnames); - } - } else { - pm_fprintf(stderr, PM_LOG_ERROR, "'%s': %s\n", targ, alpm_strerrorlast()); - retval = 1; - goto cleanup; - } + char *target = alpm_list_getdata(i); + char *targ = strchr(target, '/'); + if(targ && strncmp(target, "local", 5) == 0) { + targ++; + } else { + targ = target; + } + if(alpm_remove_target(targ) == -1) { + pm_fprintf(stderr, PM_LOG_ERROR, "'%s': %s\n", targ, alpm_strerrorlast()); + retval = 1; + goto cleanup; } } @@ -103,6 +76,12 @@ int pacman_remove(alpm_list_t *targets) pm_fprintf(stderr, PM_LOG_ERROR, _("failed to prepare transaction (%s)\n"), alpm_strerrorlast()); switch(pm_errno) { + case PM_ERR_PKG_INVALID_ARCH: + for(i = data; i; i = alpm_list_next(i)) { + char *pkg = alpm_list_getdata(i); + printf(_(":: package %s does not have a valid architecture\n"), pkg); + } + break; case PM_ERR_UNSATISFIED_DEPS: for(i = data; i; i = alpm_list_next(i)) { pmdepmissing_t *miss = alpm_list_getdata(i); @@ -123,7 +102,7 @@ int pacman_remove(alpm_list_t *targets) /* Search for holdpkg in target list */ int holdpkg = 0; - for(i = alpm_trans_get_pkgs(); i; i = alpm_list_next(i)) { + for(i = alpm_trans_get_remove(); 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"), @@ -136,23 +115,19 @@ int pacman_remove(alpm_list_t *targets) goto cleanup; } - /* Warn user in case of dangerous operation */ - if(config->flags & PM_TRANS_FLAG_RECURSE || - config->flags & PM_TRANS_FLAG_CASCADE) { - /* list transaction targets */ - alpm_list_t *pkglist = alpm_trans_get_pkgs(); - - display_targets(pkglist, 0); - printf("\n"); - - /* get confirmation */ - if(yesno(_("Do you want to remove these packages?")) == 0) { - retval = 1; - goto cleanup; - } + /* Step 3: actually perform the removal */ + alpm_list_t *pkglist = alpm_trans_get_remove(); + if(pkglist == NULL) { + goto cleanup; /* we are done */ + } + /* print targets and ask user confirmation */ + display_targets(pkglist, 0); + printf("\n"); + if(yesno(_("Do you want to remove these packages?")) == 0) { + retval = 1; + goto cleanup; } - /* Step 3: actually perform the removal */ if(alpm_trans_commit(NULL) == -1) { pm_fprintf(stderr, PM_LOG_ERROR, _("failed to commit transaction (%s)\n"), alpm_strerrorlast()); diff --git a/src/pacman/sync.c b/src/pacman/sync.c index 12f67df2..a2ef616d 100644 --- a/src/pacman/sync.c +++ b/src/pacman/sync.c @@ -93,18 +93,21 @@ static int sync_cleandb(const char *dbpath, int keep_used) { if(rmrf(path)) { pm_fprintf(stderr, PM_LOG_ERROR, _("could not remove repository directory\n")); + closedir(dir); return(1); } } - } + closedir(dir); return(0); } static int sync_cleandb_all(void) { - const char *dbpath = alpm_option_get_dbpath(); + const char *dbpath; char newdbpath[PATH_MAX]; + int ret = 0; + dbpath = alpm_option_get_dbpath(); printf(_("Database directory: %s\n"), dbpath); if(!yesno(_("Do you want to remove unused repositories?"))) { return(0); @@ -112,28 +115,26 @@ static int sync_cleandb_all(void) { /* The sync dbs were previously put in dbpath/, but are now in dbpath/sync/, * so we will clean everything in dbpath/ (except dbpath/local/ and dbpath/sync/, * and only the unused sync dbs in dbpath/sync/ */ - sync_cleandb(dbpath, 0); + ret += sync_cleandb(dbpath, 0); sprintf(newdbpath, "%s%s", dbpath, "sync/"); - sync_cleandb(newdbpath, 1); + ret += sync_cleandb(newdbpath, 1); printf(_("Database directory cleaned up\n")); - return(0); + return(ret); } static int sync_cleancache(int level) { - /* TODO for now, just mess with the first cache directory */ - alpm_list_t* cachedirs = alpm_option_get_cachedirs(); - const char *cachedir = alpm_list_getdata(cachedirs); + alpm_list_t *i; + alpm_list_t *sync_dbs = alpm_option_get_syncdbs(); + int ret = 0; + + for(i = alpm_option_get_cachedirs(); i; i = alpm_list_next(i)) { + printf(_("Cache directory: %s\n"), (char*)alpm_list_getdata(i)); + } if(level == 1) { - /* incomplete cleanup */ - DIR *dir; - struct dirent *ent; - /* Open up each package and see if it should be deleted, - * depending on the clean method used */ - printf(_("Cache directory: %s\n"), cachedir); switch(config->cleanmethod) { case PM_CLEAN_KEEPINST: if(!yesno(_("Do you want to remove uninstalled packages from cache?"))) { @@ -150,11 +151,23 @@ static int sync_cleancache(int level) return(1); } printf(_("removing old packages from cache...\n")); + } else { + if(!noyes(_("Do you want to remove ALL files from cache?"))) { + return(0); + } + printf(_("removing all files from cache...\n")); + } + + for(i = alpm_option_get_cachedirs(); i; i = alpm_list_next(i)) { + const char *cachedir = alpm_list_getdata(i); + DIR *dir = opendir(cachedir); + struct dirent *ent; - dir = opendir(cachedir); if(dir == NULL) { - pm_fprintf(stderr, PM_LOG_ERROR, _("could not access cache directory\n")); - return(1); + pm_fprintf(stderr, PM_LOG_ERROR, + _("could not access cache directory %s\n"), cachedir); + ret++; + continue; } rewinddir(dir); @@ -163,7 +176,6 @@ static int sync_cleancache(int level) char path[PATH_MAX]; int delete = 1; pmpkg_t *localpkg = NULL, *pkg = NULL; - alpm_list_t *sync_dbs = alpm_option_get_syncdbs(); alpm_list_t *j; if(!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, "..")) { @@ -172,11 +184,20 @@ static int sync_cleancache(int level) /* build the full filepath */ snprintf(path, PATH_MAX, "%s%s", cachedir, ent->d_name); + /* short circuit for removing all packages from cache */ + if(level > 1) { + unlink(path); + 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(localpkg) { + alpm_pkg_free(localpkg); + } unlink(path); } continue; @@ -215,26 +236,10 @@ static int sync_cleancache(int level) unlink(path); } } - } else { - /* full cleanup */ - printf(_("Cache directory: %s\n"), cachedir); - if(!noyes(_("Do you want to remove ALL files from cache?"))) { - return(0); - } - printf(_("removing all files from cache...\n")); - - if(rmrf(cachedir)) { - pm_fprintf(stderr, PM_LOG_ERROR, _("could not remove cache directory\n")); - return(1); - } - - if(makepath(cachedir)) { - pm_fprintf(stderr, PM_LOG_ERROR, _("could not create new cache directory\n")); - return(1); - } + closedir(dir); } - return(0); + return(ret); } static int sync_synctree(int level, alpm_list_t *syncs) @@ -242,7 +247,7 @@ static int sync_synctree(int level, alpm_list_t *syncs) alpm_list_t *i; int success = 0, ret; - if(trans_init(PM_TRANS_TYPE_SYNC, 0) == -1) { + if(trans_init(0) == -1) { return(0); } @@ -548,89 +553,68 @@ static alpm_list_t *syncfirst() { return(res); } +static int process_target(char *target) +{ + /* process targets */ + char *targstring = strdup(target); + char *targname = strchr(targstring, '/'); + char *dbname = NULL; + int ret = 0; + if(targname) { + *targname = '\0'; + targname++; + dbname = targstring; + ret = alpm_sync_dbtarget(dbname,targname); + } else { + targname = targstring; + ret = alpm_sync_target(targname); + } + + if(ret == -1) { + if(pm_errno == PM_ERR_TRANS_DUP_TARGET + || pm_errno == PM_ERR_PKG_IGNORED) { + /* just skip duplicate or ignored targets */ + pm_printf(PM_LOG_WARNING, _("skipping target: %s\n"), target); + } else { + pm_fprintf(stderr, PM_LOG_ERROR, "'%s': %s\n", target, + alpm_strerrorlast()); + ret = 1; + } + } + + free(targstring); + return(ret); +} + static int sync_trans(alpm_list_t *targets) { int retval = 0; alpm_list_t *data = NULL; - alpm_list_t *sync_dbs = alpm_option_get_syncdbs(); alpm_list_t *packages = NULL; + alpm_list_t *i; /* Step 1: create a new transaction... */ - if(trans_init(PM_TRANS_TYPE_SYNC, config->flags) == -1) { + if(trans_init(config->flags) == -1) { return(1); } + /* process targets */ + for(i = targets; i; i = alpm_list_next(i)) { + char *targ = alpm_list_getdata(i); + if(process_target(targ) == 1) { + retval = 1; + goto cleanup; + } + } + if(config->op_s_upgrade) { printf(_(":: Starting full system upgrade...\n")); alpm_logaction("starting full system upgrade\n"); - if(alpm_trans_sysupgrade(config->op_s_upgrade >= 2) == -1) { + if(alpm_sync_sysupgrade(config->op_s_upgrade >= 2) == -1) { pm_fprintf(stderr, PM_LOG_ERROR, "%s\n", alpm_strerrorlast()); retval = 1; goto cleanup; } - } else { - alpm_list_t *i; - - /* process targets */ - for(i = targets; i; i = alpm_list_next(i)) { - char *targ = alpm_list_getdata(i); - if(alpm_trans_addtarget(targ) == -1) { - pmgrp_t *grp = NULL; - int found = 0; - alpm_list_t *j; - - if(pm_errno == PM_ERR_TRANS_DUP_TARGET || pm_errno == PM_ERR_PKG_IGNORED) { - /* just skip duplicate or ignored targets */ - pm_printf(PM_LOG_WARNING, _("skipping target: %s\n"), targ); - continue; - } - if(pm_errno != PM_ERR_PKG_NOT_FOUND) { - pm_fprintf(stderr, PM_LOG_ERROR, "'%s': %s\n", - targ, alpm_strerrorlast()); - retval = 1; - goto cleanup; - } - /* target not found: check if it's a group */ - printf(_("%s package not found, searching for group...\n"), targ); - for(j = sync_dbs; j; j = alpm_list_next(j)) { - pmdb_t *db = alpm_list_getdata(j); - grp = alpm_db_readgrp(db, targ); - if(grp) { - alpm_list_t *k, *pkgnames = NULL; - - found++; - printf(_(":: group %s (including ignored packages):\n"), targ); - /* remove dupe entries in case a package exists in multiple repos */ - alpm_list_t *grppkgs = alpm_grp_get_pkgs(grp); - alpm_list_t *pkgs = alpm_list_remove_dupes(grppkgs); - for(k = pkgs; k; k = alpm_list_next(k)) { - pkgnames = alpm_list_add(pkgnames, - (char*)alpm_pkg_get_name(k->data)); - } - list_display(" ", pkgnames); - if(yesno(_(":: Install whole content?"))) { - for(k = pkgnames; k; k = alpm_list_next(k)) { - targets = alpm_list_add(targets, strdup(alpm_list_getdata(k))); - } - } else { - for(k = pkgnames; k; k = alpm_list_next(k)) { - char *pkgname = alpm_list_getdata(k); - if(yesno(_(":: Install %s from group %s?"), pkgname, targ)) { - targets = alpm_list_add(targets, strdup(pkgname)); - } - } - } - alpm_list_free(pkgnames); - alpm_list_free(pkgs); - } - } - if(!found) { - pm_fprintf(stderr, PM_LOG_ERROR, _("'%s': not found in sync db\n"), targ); - retval = 1; - goto cleanup; - } - } - } } /* Step 2: "compute" the transaction based on targets and flags */ @@ -639,6 +623,12 @@ static int sync_trans(alpm_list_t *targets) alpm_strerrorlast()); switch(pm_errno) { alpm_list_t *i; + case PM_ERR_PKG_INVALID_ARCH: + for(i = data; i; i = alpm_list_next(i)) { + char *pkg = alpm_list_getdata(i); + printf(_(":: package %s does not have a valid architecture\n"), pkg); + } + break; case PM_ERR_UNSATISFIED_DEPS: for(i = data; i; i = alpm_list_next(i)) { pmdepmissing_t *miss = alpm_list_getdata(i); @@ -650,10 +640,17 @@ static int sync_trans(alpm_list_t *targets) } break; case PM_ERR_CONFLICTING_DEPS: - for(i = data; i; i = alpm_list_next(i)) { + for(i = data; i; i = alpm_list_next(i)) { pmconflict_t *conflict = alpm_list_getdata(i); - printf(_(":: %s: conflicts with %s\n"), - alpm_conflict_get_package1(conflict), alpm_conflict_get_package2(conflict)); + const char *package1 = alpm_conflict_get_package1(conflict); + const char *package2 = alpm_conflict_get_package2(conflict); + const char *reason = alpm_conflict_get_reason(conflict); + /* only print reason if it contains new information */ + if(!strcmp(package1, reason) || !strcmp(package2, reason)) { + printf(_(":: %s and %s are in conflict\n"), package1, package2); + } else { + printf(_(":: %s and %s are in conflict (%s)\n"), package1, package2, reason); + } } break; default: @@ -663,7 +660,7 @@ static int sync_trans(alpm_list_t *targets) goto cleanup; } - packages = alpm_trans_get_pkgs(); + packages = alpm_trans_get_add(); if(packages == NULL) { /* nothing to do: just exit without complaining */ printf(_(" local database is up to date\n")); @@ -691,7 +688,8 @@ static int sync_trans(alpm_list_t *targets) goto cleanup; } - display_synctargets(packages); + display_targets(alpm_trans_get_remove(), 0); + display_targets(alpm_trans_get_add(), 1); printf("\n"); int confirm; @@ -768,7 +766,7 @@ int pacman_sync(alpm_list_t *targets) if(config->op_s_clean) { int ret = 0; - if(trans_init(PM_TRANS_TYPE_SYNC, 0) == -1) { + if(trans_init(0) == -1) { return(1); } diff --git a/src/pacman/upgrade.c b/src/pacman/upgrade.c index 1570f95e..57c7b790 100644 --- a/src/pacman/upgrade.c +++ b/src/pacman/upgrade.c @@ -42,7 +42,6 @@ int pacman_upgrade(alpm_list_t *targets) { alpm_list_t *i, *data = NULL; - pmtranstype_t transtype = PM_TRANS_TYPE_UPGRADE; int retval = 0; if(targets == NULL) { @@ -65,7 +64,7 @@ int pacman_upgrade(alpm_list_t *targets) } /* Step 1: create a new transaction */ - if(trans_init(transtype, config->flags) == -1) { + if(trans_init(config->flags) == -1) { return(1); } @@ -73,7 +72,7 @@ int pacman_upgrade(alpm_list_t *targets) printf(_("loading package data...\n")); for(i = targets; i; i = alpm_list_next(i)) { char *targ = alpm_list_getdata(i); - if(alpm_trans_addtarget(targ) == -1) { + if(alpm_add_target(targ) == -1) { pm_fprintf(stderr, PM_LOG_ERROR, "'%s': %s\n", targ, alpm_strerrorlast()); trans_release(); @@ -87,6 +86,12 @@ int pacman_upgrade(alpm_list_t *targets) pm_fprintf(stderr, PM_LOG_ERROR, _("failed to prepare transaction (%s)\n"), alpm_strerrorlast()); switch(pm_errno) { + case PM_ERR_PKG_INVALID_ARCH: + for(i = data; i; i = alpm_list_next(i)) { + char *pkg = alpm_list_getdata(i); + printf(_(":: package %s does not have a valid architecture\n"), pkg); + } + break; case PM_ERR_UNSATISFIED_DEPS: for(i = data; i; i = alpm_list_next(i)) { pmdepmissing_t *miss = alpm_list_getdata(i); @@ -104,42 +109,75 @@ int pacman_upgrade(alpm_list_t *targets) case PM_ERR_CONFLICTING_DEPS: for(i = data; i; i = alpm_list_next(i)) { pmconflict_t *conflict = alpm_list_getdata(i); - printf(_(":: %s: conflicts with %s\n"), - alpm_conflict_get_package1(conflict), alpm_conflict_get_package2(conflict)); + const char *package1 = alpm_conflict_get_package1(conflict); + const char *package2 = alpm_conflict_get_package2(conflict); + const char *reason = alpm_conflict_get_reason(conflict); + /* only print reason if it contains new information */ + if(!strcmp(package1, reason) || !strcmp(package2, reason)) { + printf(_(":: %s and %s are in conflict\n"), package1, package2); + } else { + printf(_(":: %s and %s are in conflict (%s)\n"), package1, package2, reason); + } } break; + default: + break; + } + trans_release(); + FREELIST(data); + return(1); + } + + /* Step 3: perform the installation */ + /* print targets and ask user confirmation */ + alpm_list_t *packages = alpm_trans_get_add(); + if(packages == NULL) { /* we are done */ + trans_release(); + return(retval); + } + display_targets(alpm_trans_get_remove(), 0); + display_targets(alpm_trans_get_add(), 1); + printf("\n"); + int confirm = yesno(_("Proceed with installation?")); + if(!confirm) { + trans_release(); + return(retval); + } + + if(alpm_trans_commit(&data) == -1) { + pm_fprintf(stderr, PM_LOG_ERROR, _("failed to commit transaction (%s)\n"), + alpm_strerrorlast()); + switch(pm_errno) { + alpm_list_t *i; case PM_ERR_FILE_CONFLICTS: for(i = data; i; i = alpm_list_next(i)) { pmfileconflict_t *conflict = alpm_list_getdata(i); switch(alpm_fileconflict_get_type(conflict)) { case PM_FILECONFLICT_TARGET: printf(_("%s exists in both '%s' and '%s'\n"), - alpm_fileconflict_get_file(conflict), - alpm_fileconflict_get_target(conflict), - alpm_fileconflict_get_ctarget(conflict)); - break; + alpm_fileconflict_get_file(conflict), + alpm_fileconflict_get_target(conflict), + alpm_fileconflict_get_ctarget(conflict)); + break; case PM_FILECONFLICT_FILESYSTEM: printf(_("%s: %s exists in filesystem\n"), - alpm_fileconflict_get_target(conflict), - alpm_fileconflict_get_file(conflict)); - break; + alpm_fileconflict_get_target(conflict), + alpm_fileconflict_get_file(conflict)); + break; } } - printf(_("\nerrors occurred, no packages were upgraded.\n")); + break; + case PM_ERR_PKG_INVALID: + case PM_ERR_DLT_INVALID: + for(i = data; i; i = alpm_list_next(i)) { + char *filename = alpm_list_getdata(i); + printf(_("%s is invalid or corrupted\n"), filename); + } break; default: break; } - trans_release(); FREELIST(data); - return(1); - } - alpm_list_free(data); - - /* Step 3: perform the installation */ - if(alpm_trans_commit(NULL) == -1) { - pm_fprintf(stderr, PM_LOG_ERROR, _("failed to commit transaction (%s)\n"), - alpm_strerrorlast()); trans_release(); return(1); } diff --git a/src/pacman/util.c b/src/pacman/util.c index c68e6841..115b3673 100644 --- a/src/pacman/util.c +++ b/src/pacman/util.c @@ -45,9 +45,9 @@ #include "callback.h" -int trans_init(pmtranstype_t type, pmtransflag_t flags) +int trans_init(pmtransflag_t flags) { - if(alpm_trans_init(type, flags, cb_trans_evt, + if(alpm_trans_init(flags, cb_trans_evt, cb_trans_conv, cb_trans_progress) == -1) { pm_fprintf(stderr, PM_LOG_ERROR, _("failed to init transaction (%s)\n"), alpm_strerrorlast()); @@ -85,70 +85,18 @@ int needs_root(void) /* gets the current screen column width */ int getcols(void) { - if(!isatty(1)) { - /* We will default to 80 columns if we're not a tty - * this seems a fairly standard file width. - */ - return 80; - } else { #ifdef TIOCGSIZE - struct ttysize win; - if(ioctl(1, TIOCGSIZE, &win) == 0) { - return win.ts_cols; - } -#elif defined(TIOCGWINSZ) - struct winsize win; - if(ioctl(1, TIOCGWINSZ, &win) == 0) { - return win.ws_col; - } -#endif - /* If we can't figure anything out, we'll just assume 80 columns */ - /* TODO any problems caused by this assumption? */ - return 80; - } - /* Original envvar way - prone to display issues - const char *cenv = getenv("COLUMNS"); - if(cenv != NULL) { - return atoi(cenv); + struct ttysize win; + if(ioctl(1, TIOCGSIZE, &win) == 0) { + return win.ts_cols; } - return -1; - */ -} - -/* does the same thing as 'mkdir -p' */ -int makepath(const char *path) -{ - /* A bit of pointer hell here. Descriptions: - * orig - a copy of path so we can safely butcher it with strsep - * str - the current position in the path string (after the delimiter) - * ptr - the original position of str after calling strsep - * incr - incrementally generated path for use in access/mkdir call - */ - char *orig, *str, *ptr, *incr; - mode_t oldmask = umask(0000); - int ret = 0; - - orig = strdup(path); - incr = calloc(strlen(orig) + 1, sizeof(char)); - str = orig; - while((ptr = strsep(&str, "/"))) { - if(strlen(ptr)) { - /* we have another path component- append the newest component to - * existing string and create one more level of dir structure */ - strcat(incr, "/"); - strcat(incr, ptr); - if(access(incr, F_OK)) { - if(mkdir(incr, 0755)) { - ret = 1; - break; - } - } - } +#elif defined(TIOCGWINSZ) + struct winsize win; + if(ioctl(1, TIOCGWINSZ, &win) == 0) { + return win.ws_col; } - free(orig); - free(incr); - umask(oldmask); - return(ret); +#endif + return 0; } /* does the same thing as 'rm -rf' */ @@ -257,6 +205,14 @@ void indentprint(const char *str, int indent) return; } + cols = getcols(); + + /* if we're not a tty, print without indenting */ + if(cols == 0) { + printf("%s", str); + return; + } + len = strlen(str) + 1; wcstr = calloc(len, sizeof(wchar_t)); len = mbstowcs(wcstr, str, len); @@ -266,7 +222,6 @@ void indentprint(const char *str, int indent) if(!p) { return; } - cols = getcols(); while(*p) { if(*p == L' ') { @@ -285,7 +240,7 @@ void indentprint(const char *str, int indent) } if(len > (cols - cidx - 1)) { /* wrap to a newline and reindent */ - fprintf(stdout, "\n%-*s", indent, ""); + printf("\n%-*s", indent, ""); cidx = indent; } else { printf(" "); @@ -293,7 +248,7 @@ void indentprint(const char *str, int indent) } continue; } - fprintf(stdout, "%lc", (wint_t)*p); + printf("%lc", (wint_t)*p); cidx += wcwidth(*p); p++; } @@ -307,7 +262,7 @@ char *strtoupper(char *str) char *ptr = str; while(*ptr) { - (*ptr) = toupper(*ptr); + (*ptr) = toupper((unsigned char)*ptr); ptr++; } return str; @@ -324,7 +279,7 @@ char *strtrim(char *str) return(str); } - while(isspace(*pch)) { + while(isspace((unsigned char)*pch)) { pch++; } if(pch != str) { @@ -337,7 +292,7 @@ char *strtrim(char *str) } pch = (str + (strlen(str) - 1)); - while(isspace(*pch)) { + while(isspace((unsigned char)*pch)) { pch--; } *++pch = '\0'; @@ -345,48 +300,65 @@ char *strtrim(char *str) return(str); } -/* Helper function for strreplace */ -static void _strnadd(char **str, const char *append, unsigned int count) -{ - if(*str) { - *str = realloc(*str, strlen(*str) + count + 1); - } else { - *str = calloc(sizeof(char), count + 1); - } - - strncat(*str, append, count); -} - /* Replace all occurances of 'needle' with 'replace' in 'str', returning * a new string (must be free'd) */ char *strreplace(const char *str, const char *needle, const char *replace) { - const char *p, *q; - p = q = str; + const char *p = NULL, *q = NULL; + char *newstr = NULL, *newp = NULL; + alpm_list_t *i = NULL, *list = NULL; + size_t needlesz = strlen(needle), replacesz = strlen(replace); + size_t newsz; - char *newstr = NULL; - unsigned int needlesz = strlen(needle), - replacesz = strlen(replace); + if(!str) { + return(NULL); + } - while (1) { + p = str; + q = strstr(p, needle); + while(q) { + list = alpm_list_add(list, (char *)q); + p = q + needlesz; q = strstr(p, needle); - if(!q) { /* not found */ - if(*p) { - /* add the rest of 'p' */ - _strnadd(&newstr, p, strlen(p)); - } - break; - } else { /* found match */ - if(q > p){ - /* add chars between this occurance and last occurance, if any */ - _strnadd(&newstr, p, q - p); - } - _strnadd(&newstr, replace, replacesz); - p = q + needlesz; + } + + /* no occurences of needle found */ + if(!list) { + return(strdup(str)); + } + /* size of new string = size of old string + "number of occurences of needle" + * x "size difference between replace and needle" */ + newsz = strlen(str) + 1 + + alpm_list_count(list) * (replacesz - needlesz); + newstr = malloc(newsz); + if(!newstr) { + return(NULL); + } + *newstr = '\0'; + + p = str; + newp = newstr; + for(i = list; i; i = alpm_list_next(i)) { + q = alpm_list_getdata(i); + if(q > p){ + /* add chars between this occurence and last occurence, if any */ + strncpy(newp, p, q - p); + newp += q - p; } + strncpy(newp, replace, replacesz); + newp += replacesz; + p = q + needlesz; } + alpm_list_free(list); - return newstr; + if(*p) { + /* add the rest of 'p' */ + strcpy(newp, p); + newp += strlen(p); + } + *newp = '\0'; + + return(newstr); } /** Splits a string into a list of strings using the chosen character as @@ -446,13 +418,13 @@ void string_display(const char *title, const char *string) int len = 0; if(title) { - /* compute the length of title + a space */ - len = string_length(title) + 1; printf("%s ", title); } if(string == NULL || string[0] == '\0') { printf(_("None")); } else { + /* compute the length of title + a space */ + len = string_length(title) + 1; indentprint(string, len); } printf("\n"); @@ -477,7 +449,7 @@ void list_display(const char *title, const alpm_list_t *list) /* two additional spaces are added to the length */ s += 2; int maxcols = getcols(); - if(s + cols > maxcols) { + if(s + cols > maxcols && maxcols > 0) { int j; cols = len; printf("\n"); @@ -577,37 +549,6 @@ void display_targets(const alpm_list_t *pkgs, int install) FREELIST(targets); } -/* Display a list of transaction targets. - * `pkgs` should be a list of pmpkg_t's, - * retrieved from a transaction object - */ -void display_synctargets(const alpm_list_t *syncpkgs) -{ - const alpm_list_t *i, *j; - alpm_list_t *pkglist = NULL, *rpkglist = NULL; - - for(i = syncpkgs; i; i = alpm_list_next(i)) { - pmpkg_t *pkg = alpm_list_getdata(i); - pkglist = alpm_list_add(pkglist, pkg); - - /* The removes member contains a list of packages to be removed - * due to the package that is being installed. */ - alpm_list_t *to_replace = alpm_pkg_get_removes(pkg); - - for(j = to_replace; j; j = alpm_list_next(j)) { - pmpkg_t *rp = alpm_list_getdata(j); - rpkglist = alpm_list_add(rpkglist, rp); - } - } - - /* start displaying information */ - display_targets(rpkglist, 0); - display_targets(pkglist, 1); - - alpm_list_free(pkglist); - alpm_list_free(rpkglist); -} - /* Helper function for comparing strings using the * alpm "compare func" signature */ int str_cmp(const void *s1, const void *s2) @@ -640,6 +581,7 @@ void display_optdepends(pmpkg_t *pkg) static int question(short preset, char *fmt, va_list args) { char response[32]; + int sresponse = sizeof(response)-1; FILE *stream; if(config->noconfirm) { @@ -662,7 +604,7 @@ static int question(short preset, char *fmt, va_list args) return(preset); } - if(fgets(response, 32, stdin)) { + if(fgets(response, sresponse, stdin)) { strtrim(response); if(strlen(response) == 0) { return(preset); diff --git a/src/pacman/util.h b/src/pacman/util.h index 12824221..7a8c39d1 100644 --- a/src/pacman/util.h +++ b/src/pacman/util.h @@ -37,11 +37,10 @@ /* update speed for the fill_progress based functions */ #define UPDATE_SPEED_SEC 0.2f -int trans_init(pmtranstype_t type, pmtransflag_t flags); +int trans_init(pmtransflag_t flags); int trans_release(void); int needs_root(void); int getcols(void); -int makepath(const char *path); int rmrf(const char *path); char *mbasename(const char *path); char *mdirname(const char *path); @@ -54,7 +53,6 @@ void string_display(const char *title, const char *string); void list_display(const char *title, const alpm_list_t *list); void list_display_linebreak(const char *title, const alpm_list_t *list); void display_targets(const alpm_list_t *pkgs, int install); -void display_synctargets(const alpm_list_t *syncpkgs); void display_new_optdepends(pmpkg_t *oldpkg, pmpkg_t *newpkg); void display_optdepends(pmpkg_t *pkg); int yesno(char *fmt, ...); |