X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=examples%2Fsolv.c;h=8b0d6cc4db981d9adcde7c552d82fa370763c897;hb=0254042972e8b301303ad00678e5388e7722b440;hp=221a59c4464c69e7b9ebfab0c46b633b8917795b;hpb=ebb77d396a46f7b133d8074066936904c3459943;p=platform%2Fupstream%2Flibsolv.git diff --git a/examples/solv.c b/examples/solv.c index 221a59c..8b0d6cc 100644 --- a/examples/solv.c +++ b/examples/solv.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, Novell Inc. + * Copyright (c) 2009-2013, Novell Inc. * * This program is licensed under the BSD license, read LICENSE.BSD * for further information @@ -57,12 +57,16 @@ #include "solverdebug.h" #include "chksum.h" #include "repo_solv.h" +#include "selection.h" #include "repo_write.h" #ifdef ENABLE_RPMDB #include "repo_rpmdb.h" #include "pool_fileconflicts.h" #endif +#ifdef ENABLE_PUBKEY +#include "repo_pubkey.h" +#endif #ifdef ENABLE_DEBIAN #include "repo_deb.h" #endif @@ -72,11 +76,17 @@ #include "repo_updateinfoxml.h" #include "repo_deltainfoxml.h" #endif +#ifdef ENABLE_APPDATA +#include "repo_appdata.h" +#endif #ifdef ENABLE_SUSEREPO #include "repo_products.h" #include "repo_susetags.h" #include "repo_content.h" #endif +#ifdef SUSE +#include "repo_autopattern.h" +#endif #include "solv_xfopen.h" #ifdef FEDORA @@ -87,6 +97,9 @@ # define PRODUCTS_PATH "/etc/products.d" # define SOFTLOCKS_PATH "/var/lib/zypp/SoftLocks" #endif +#ifdef ENABLE_APPDATA +# define APPDATA_PATH "/usr/share/appdata" +#endif #define SOLVCACHE_PATH "/var/cache/solv" @@ -114,6 +127,7 @@ struct repoinfo { unsigned char cookie[32]; unsigned char extcookie[32]; + int incomplete; }; #ifdef FEDORA @@ -139,23 +153,28 @@ yum_substitute(Pool *pool, char *line) { if (!releaseevr) { + void *rpmstate; Queue q; queue_init(&q); - rpm_installedrpmdbids(0, "Providename", "redhat-release", &q); + rpmstate = rpm_state_create(pool, pool_get_rootdir(pool)); + rpm_installedrpmdbids(rpmstate, "Providename", "redhat-release", &q); if (q.count) { - void *handle, *state = 0; + void *handle; char *p; - handle = rpm_byrpmdbid(q.elements[0], 0, &state); - releaseevr = rpm_query(handle, SOLVABLE_EVR); - rpm_byrpmdbid(0, 0, &state); - if ((p = strchr(releaseevr, '-')) != 0) + handle = rpm_byrpmdbid(rpmstate, q.elements[0]); + releaseevr = handle ? rpm_query(handle, SOLVABLE_EVR) : 0; + if (releaseevr && (p = strchr(releaseevr, '-')) != 0) *p = 0; } + rpm_state_free(rpmstate); queue_free(&q); if (!releaseevr) - releaseevr = strdup("?"); + { + fprintf(stderr, "no installed package provides 'redhat-release', cannot determine $releasever\n"); + exit(1); + } } *p2 = 0; p = pool_tmpjoin(pool, line, releaseevr, p2 + 11); @@ -197,7 +216,6 @@ yum_substitute(Pool *pool, char *line) #define TYPE_PLAINDIR 3 #define TYPE_DEBIAN 4 -#ifndef NOSYSTEM static int read_repoinfos_sort(const void *ap, const void *bp) { @@ -205,7 +223,6 @@ read_repoinfos_sort(const void *ap, const void *bp) const struct repoinfo *b = bp; return strcmp(a->alias, b->alias); } -#endif #if defined(SUSE) || defined(FEDORA) @@ -459,15 +476,6 @@ read_repoinfos(Pool *pool, int *nrepoinfosp) #endif -#ifdef NOSYSTEM -struct repoinfo * -read_repoinfos(Pool *pool, int *nrepoinfosp) -{ - *nrepoinfosp = 0; - return 0; -} -#endif - void free_repoinfos(struct repoinfo *repoinfos, int nrepoinfos) @@ -511,7 +519,7 @@ verify_checksum(int fd, const char *file, const unsigned char *chksum, Id chksum { char buf[1024]; const unsigned char *sum; - void *h; + Chksum *h; int l; h = solv_chksum_create(chksumtype); @@ -771,13 +779,13 @@ findmirrorlisturl(FILE *fp) static inline int iscompressed(const char *name) { - int l = strlen(name); - return l > 3 && !strcmp(name + l - 3, ".gz") ? 1 : 0; + return solv_xfopen_iscompressed(name) != 0; } FILE * -curlfopen(struct repoinfo *cinfo, const char *file, int uncompress, const unsigned char *chksum, Id chksumtype, int *badchecksump) +curlfopen(struct repoinfo *cinfo, const char *file, int uncompress, const unsigned char *chksum, Id chksumtype, int markincomplete) { + FILE *fp; pid_t pid; int fd, l; int status; @@ -790,9 +798,10 @@ curlfopen(struct repoinfo *cinfo, const char *file, int uncompress, const unsign return 0; if (file != cinfo->metalink && file != cinfo->mirrorlist) { - FILE *fp = curlfopen(cinfo, cinfo->metalink ? cinfo->metalink : cinfo->mirrorlist, 0, 0, 0, 0); unsigned char mlchksum[32]; - Id mlchksumtype = 0; + Id mlchksumtype; + fp = curlfopen(cinfo, cinfo->metalink ? cinfo->metalink : cinfo->mirrorlist, 0, 0, 0, 0); + mlchksumtype = 0; if (!fp) return 0; if (cinfo->metalink) @@ -815,7 +824,7 @@ curlfopen(struct repoinfo *cinfo, const char *file, int uncompress, const unsign chksumtype = mlchksumtype; chksum = mlchksum; } - return curlfopen(cinfo, file, uncompress, chksum, chksumtype, badchecksump); + return curlfopen(cinfo, file, uncompress, chksum, chksumtype, markincomplete); } snprintf(url, sizeof(url), "%s", file); } @@ -858,22 +867,36 @@ curlfopen(struct repoinfo *cinfo, const char *file, int uncompress, const unsign if (status) { printf("%s: download error %d\n", file, status >> 8 ? status >> 8 : status); - if (badchecksump) - *badchecksump = 1; + if (markincomplete) + cinfo->incomplete = 1; close(fd); return 0; } if (chksumtype && !verify_checksum(fd, file, chksum, chksumtype)) { - if (badchecksump) - *badchecksump = 1; + if (markincomplete) + cinfo->incomplete = 1; close(fd); return 0; } - if (uncompress) - return solv_xfopen_fd(".gz", fd, "r"); fcntl(fd, F_SETFD, FD_CLOEXEC); - return fdopen(fd, "r"); + if (uncompress) + { + if (solv_xfopen_iscompressed(file) < 0) + { + printf("%s: unsupported compression\n", file); + if (markincomplete) + cinfo->incomplete = 1; + close(fd); + return 0; + } + fp = solv_xfopen_fd(file, fd, "r"); + } + else + fp = fdopen(fd, "r"); + if (!fp) + close(fd); + return fp; } #ifndef DEBIAN @@ -948,7 +971,7 @@ checksig(Pool *sigpool, FILE *fp, FILE *sigfp) lseek(fileno(fp), 0, SEEK_SET); possigfp = lseek(fileno(sigfp), 0, SEEK_CUR); lseek(fileno(sigfp), 0, SEEK_SET); - snprintf(cmd, sizeof(cmd), "gpg -q --homedir %s --verify /dev/fd/%d /dev/fd/%d >/dev/null 2>&1", gpgdir, fileno(sigfp), fileno(fp)); + snprintf(cmd, sizeof(cmd), "gpgv -q --homedir %s --keyring %s/pubring.gpg /dev/fd/%d /dev/fd/%d >/dev/null 2>&1", gpgdir, gpgdir, fileno(sigfp), fileno(fp)); fcntl(fileno(fp), F_SETFD, 0); /* clear CLOEXEC */ fcntl(fileno(sigfp), F_SETFD, 0); /* clear CLOEXEC */ r = system(cmd); @@ -962,7 +985,7 @@ checksig(Pool *sigpool, FILE *fp, FILE *sigfp) #else -int +static int checksig(Pool *sigpool, FILE *fp, FILE *sigfp) { char cmd[256]; @@ -979,13 +1002,46 @@ checksig(Pool *sigpool, FILE *fp, FILE *sigfp) #endif +static Pool * +read_sigs() +{ + Pool *sigpool = pool_create(); +#if defined(ENABLE_PUBKEY) && defined(ENABLE_RPMDB) + Repo *repo = repo_create(sigpool, "pubkeys"); + repo_add_rpmdb_pubkeys(repo, 0); +#endif + return sigpool; +} + +static int +downloadchecksig(struct repoinfo *cinfo, FILE *fp, const char *sigurl, Pool **sigpool) +{ + FILE *sigfp; + sigfp = curlfopen(cinfo, sigurl, 0, 0, 0, 0); + if (!sigfp) + { + printf(" unsigned, skipped\n"); + return 0; + } + if (!*sigpool) + *sigpool = read_sigs(); + if (!checksig(*sigpool, fp, sigfp)) + { + printf(" checksig failed, skipped\n"); + fclose(sigfp); + return 0; + } + fclose(sigfp); + return 1; +} + #define CHKSUM_IDENT "1.1" void calc_checksum_fp(FILE *fp, Id chktype, unsigned char *out) { char buf[4096]; - void *h = solv_chksum_create(chktype); + Chksum *h = solv_chksum_create(chktype); int l; solv_chksum_add(h, CHKSUM_IDENT, strlen(CHKSUM_IDENT)); @@ -996,10 +1052,12 @@ calc_checksum_fp(FILE *fp, Id chktype, unsigned char *out) } void -calc_checksum_stat(struct stat *stb, Id chktype, unsigned char *out) +calc_checksum_stat(struct stat *stb, Id chktype, unsigned char *cookie, unsigned char *out) { - void *h = solv_chksum_create(chktype); + Chksum *h = solv_chksum_create(chktype); solv_chksum_add(h, CHKSUM_IDENT, strlen(CHKSUM_IDENT)); + if (cookie) + solv_chksum_add(h, cookie, 32); solv_chksum_add(h, &stb->st_dev, sizeof(stb->st_dev)); solv_chksum_add(h, &stb->st_ino, sizeof(stb->st_ino)); solv_chksum_add(h, &stb->st_size, sizeof(stb->st_size)); @@ -1019,9 +1077,19 @@ setarch(Pool *pool) pool_setarch(pool, un.machine); } -char *calccachepath(Repo *repo, const char *repoext) +char *userhome; + +char * +calccachepath(Repo *repo, const char *repoext, int forcesystemloc) { - char *q, *p = pool_tmpjoin(repo->pool, SOLVCACHE_PATH, "/", repo->name); + char *q, *p; + int l; + if (!forcesystemloc && userhome && getuid()) + p = pool_tmpjoin(repo->pool, userhome, "/.solvcache/", 0); + else + p = pool_tmpjoin(repo->pool, SOLVCACHE_PATH, "/", 0); + l = strlen(p); + p = pool_tmpappend(repo->pool, p, repo->name, 0); if (repoext) { p = pool_tmpappend(repo->pool, p, "_", repoext); @@ -1029,7 +1097,7 @@ char *calccachepath(Repo *repo, const char *repoext) } else p = pool_tmpappend(repo->pool, p, ".solv", 0); - q = p + strlen(SOLVCACHE_PATH) + 1; + q = p + l; if (*q == '.') *q = '_'; for (; *q; q++) @@ -1046,9 +1114,19 @@ usecachedrepo(Repo *repo, const char *repoext, unsigned char *cookie, int mark) unsigned char myextcookie[32]; struct repoinfo *cinfo; int flags; + int forcesystemloc; + forcesystemloc = mark & 2 ? 0 : 1; + if (mark < 2 && userhome && getuid()) + { + /* first try home location */ + int res = usecachedrepo(repo, repoext, cookie, mark | 2); + if (res) + return res; + } + mark &= 1; cinfo = repo->appdata; - if (!(fp = fopen(calccachepath(repo, repoext), "r"))) + if (!(fp = fopen(calccachepath(repo, repoext, forcesystemloc), "r"))) return 0; if (fseek(fp, -sizeof(mycookie), SEEK_END) || fread(mycookie, sizeof(mycookie), 1, fp) != 1) { @@ -1089,7 +1167,7 @@ usecachedrepo(Repo *repo, const char *repoext, unsigned char *cookie, int mark) memcpy(cinfo->extcookie, myextcookie, sizeof(myextcookie)); } if (mark) - futimes(fileno(fp), 0); /* try to set modification time */ + futimens(fileno(fp), 0); /* try to set modification time */ fclose(fp); return 1; } @@ -1099,14 +1177,18 @@ writecachedrepo(Repo *repo, Repodata *info, const char *repoext, unsigned char * { FILE *fp; int i, fd; - char *tmpl; + char *tmpl, *cachedir; struct repoinfo *cinfo; int onepiece; cinfo = repo->appdata; - mkdir(SOLVCACHE_PATH, 0755); + if (cinfo && cinfo->incomplete) + return; + cachedir = userhome && getuid() ? pool_tmpjoin(repo->pool, userhome, "/.solvcache", 0) : SOLVCACHE_PATH; + if (access(cachedir, W_OK | X_OK) != 0 && mkdir(cachedir, 0755) == 0) + printf("[created %s]\n", cachedir); /* use dupjoin instead of tmpjoin because tmpl must survive repo_write */ - tmpl = solv_dupjoin(SOLVCACHE_PATH, "/", ".newsolv-XXXXXX"); + tmpl = solv_dupjoin(cachedir, "/", ".newsolv-XXXXXX"); fd = mkstemp(tmpl); if (fd < 0) { @@ -1150,13 +1232,8 @@ writecachedrepo(Repo *repo, Repodata *info, const char *repoext, unsigned char * /* we just need some unique ID */ struct stat stb; if (!fstat(fileno(fp), &stb)) - { - int i; - - calc_checksum_stat(&stb, REPOKEY_TYPE_SHA256, cinfo->extcookie); - for (i = 0; i < 32; i++) - cinfo->extcookie[i] ^= cookie[i]; - } + memset(&stb, 0, sizeof(stb)); + calc_checksum_stat(&stb, REPOKEY_TYPE_SHA256, cookie, cinfo->extcookie); if (cinfo->extcookie[0] == 0) cinfo->extcookie[0] = 1; } @@ -1201,35 +1278,25 @@ writecachedrepo(Repo *repo, Repodata *info, const char *repoext, unsigned char * } else { + int flags = REPO_USE_LOADING|REPO_EXTEND_SOLVABLES; /* make sure repodata contains complete repo */ /* (this is how repodata_write saves it) */ repodata_extend_block(info, repo->start, repo->end - repo->start); info->state = REPODATA_LOADING; - /* no need for LOCALPOOL as pool already contains ids */ - repo_add_solv(repo, fp, REPO_USE_LOADING|REPO_EXTEND_SOLVABLES); + if (strcmp(repoext, "DL") != 0) + flags |= REPO_LOCALPOOL; + repo_add_solv(repo, fp, flags); info->state = REPODATA_AVAILABLE; /* in case the load failed */ } fclose(fp); } } - if (!rename(tmpl, calccachepath(repo, repoext))) + if (!rename(tmpl, calccachepath(repo, repoext, 0))) unlink(tmpl); free(tmpl); } -static Pool * -read_sigs() -{ - Pool *sigpool = pool_create(); -#if defined(ENABLE_RPMDB_PUBKEY) - Repo *repo = repo_create(sigpool, "rpmdbkeys"); - repo_add_rpmdb_pubkeys(repo, 0, 0); -#endif - return sigpool; -} - - #ifdef ENABLE_RPMMD /* repomd helpers */ @@ -1311,12 +1378,10 @@ repomd_load_ext(Repo *repo, Repodata *data) strcpy(ext, "DL"); else return 0; -#if 1 printf("[%s:%s", repo->name, ext); -#endif if (usecachedrepo(repo, ext, cinfo->extcookie, 0)) { - printf(" cached]\n");fflush(stdout); + printf(" cached]\n"); fflush(stdout); return 1; } printf(" fetching]\n"); fflush(stdout); @@ -1326,7 +1391,7 @@ repomd_load_ext(Repo *repo, Repodata *data) if ((fp = curlfopen(cinfo, filename, iscompressed(filename), filechksum, filechksumtype, 0)) == 0) return 0; if (!strcmp(ext, "FL")) - r = repo_add_rpmmd(repo, fp, ext, REPO_USE_LOADING|REPO_EXTEND_SOLVABLES); + r = repo_add_rpmmd(repo, fp, ext, REPO_USE_LOADING|REPO_EXTEND_SOLVABLES|REPO_LOCALPOOL); else if (!strcmp(ext, "DL")) r = repo_add_deltainfoxml(repo, fp, REPO_USE_LOADING); fclose(fp); @@ -1446,6 +1511,7 @@ susetags_load_ext(Repo *repo, Repodata *data) struct repoinfo *cinfo; const unsigned char *filechksum; Id filechksumtype; + int flags; cinfo = repo->appdata; filename = repodata_lookup_str(data, SOLVID_META, SUSETAGS_FILE_NAME); @@ -1455,17 +1521,13 @@ susetags_load_ext(Repo *repo, Repodata *data) ext[0] = filename[9]; ext[1] = filename[10]; ext[2] = 0; -#if 1 printf("[%s:%s", repo->name, ext); -#endif if (usecachedrepo(repo, ext, cinfo->extcookie, 0)) { printf(" cached]\n"); fflush(stdout); return 1; } -#if 1 printf(" fetching]\n"); fflush(stdout); -#endif defvendor = repo_lookup_id(repo, SOLVID_META, SUSETAGS_DEFAULTVENDOR); descrdir = repo_lookup_str(repo, SOLVID_META, SUSETAGS_DESCRDIR); if (!descrdir) @@ -1474,7 +1536,10 @@ susetags_load_ext(Repo *repo, Repodata *data) filechksum = repodata_lookup_bin_checksum(data, SOLVID_META, SUSETAGS_FILE_CHECKSUM, &filechksumtype); if ((fp = curlfopen(cinfo, pool_tmpjoin(repo->pool, descrdir, "/", filename), iscompressed(filename), filechksum, filechksumtype, 0)) == 0) return 0; - if (repo_add_susetags(repo, fp, defvendor, ext, REPO_USE_LOADING|REPO_EXTEND_SOLVABLES)) + flags = REPO_USE_LOADING|REPO_EXTEND_SOLVABLES; + if (strcmp(ext, "DL") != 0) + flags |= REPO_LOCALPOOL; + if (repo_add_susetags(repo, fp, defvendor, ext, flags)) { fclose(fp); printf("%s\n", pool_errstr(repo->pool)); @@ -1638,7 +1703,6 @@ read_repos(Pool *pool, struct repoinfo *repoinfos, int nrepoinfos) struct repoinfo *cinfo; int i; FILE *fp; - FILE *sigfp; const char *filename; const unsigned char *filechksum; Id filechksumtype; @@ -1651,7 +1715,6 @@ read_repos(Pool *pool, struct repoinfo *repoinfos, int nrepoinfos) #if defined(ENABLE_SUSEREPO) || defined(ENABLE_RPMMD) Repodata *data; #endif - int badchecksum; int dorefresh; #if defined(ENABLE_DEBIAN) FILE *fpr; @@ -1659,70 +1722,59 @@ read_repos(Pool *pool, struct repoinfo *repoinfos, int nrepoinfos) #endif repo = repo_create(pool, "@System"); + memset(&stb, 0, sizeof(stb)); #if defined(ENABLE_RPMDB) && (defined(SUSE) || defined(FEDORA)) printf("rpm database:"); - if (stat("/var/lib/rpm/Packages", &stb)) - memset(&stb, 0, sizeof(&stb)); + if (stat(pool_prepend_rootdir_tmp(pool, "/var/lib/rpm/Packages"), &stb)) + memset(&stb, 0, sizeof(stb)); #endif #if defined(ENABLE_DEBIAN) && defined(DEBIAN) printf("dpgk database:"); - if (stat("/var/lib/dpkg/status", &stb)) - memset(&stb, 0, sizeof(&stb)); -#endif -#ifdef NOSYSTEM - printf("no installed database:"); - memset(&stb, 0, sizeof(&stb)); + if (stat(pool_prepend_rootdir_tmp(pool, "/var/lib/dpkg/status"), &stb)) + memset(&stb, 0, sizeof(stb)); #endif - calc_checksum_stat(&stb, REPOKEY_TYPE_SHA256, installedcookie); + calc_checksum_stat(&stb, REPOKEY_TYPE_SHA256, 0, installedcookie); if (usecachedrepo(repo, 0, installedcookie, 0)) printf(" cached\n"); else { #if defined(ENABLE_RPMDB) && (defined(SUSE) || defined(FEDORA)) - FILE *ofp; - int done = 0; + FILE *ofp = 0; #endif printf(" reading\n"); #if defined(ENABLE_RPMDB) && (defined(SUSE) || defined(FEDORA)) # if defined(ENABLE_SUSEREPO) && defined(PRODUCTS_PATH) - if (repo_add_products(repo, PRODUCTS_PATH, 0, REPO_NO_INTERNALIZE)) + if (repo_add_products(repo, PRODUCTS_PATH, REPO_REUSE_REPODATA | REPO_NO_INTERNALIZE | REPO_USE_ROOTDIR)) { fprintf(stderr, "product reading failed: %s\n", pool_errstr(pool)); exit(1); } # endif - if ((ofp = fopen(calccachepath(repo, 0), "r")) != 0) +# if defined(ENABLE_APPDATA) + if (repo_add_appdata_dir(repo, APPDATA_PATH, REPO_REUSE_REPODATA | REPO_NO_INTERNALIZE | REPO_USE_ROOTDIR)) { - Repo *ref = repo_create(pool, "@System.old"); - if (!repo_add_solv(ref, ofp, 0)) - { - if (repo_add_rpmdb(repo, ref, 0, REPO_REUSE_REPODATA)) - { - fprintf(stderr, "installed db: %s\n", pool_errstr(pool)); - exit(1); - } - done = 1; - } - fclose(ofp); - repo_free(ref, 1); + fprintf(stderr, "appdata reading failed: %s\n", pool_errstr(pool)); + exit(1); } - if (!done) +# endif + ofp = fopen(calccachepath(repo, 0, 0), "r"); + if (repo_add_rpmdb_reffp(repo, ofp, REPO_REUSE_REPODATA | REPO_NO_INTERNALIZE | REPO_USE_ROOTDIR)) { - if (repo_add_rpmdb(repo, 0, 0, REPO_REUSE_REPODATA)) - { - fprintf(stderr, "installed db: %s\n", pool_errstr(pool)); - exit(1); - } + fprintf(stderr, "installed db: %s\n", pool_errstr(pool)); + exit(1); } + if (ofp) + fclose(ofp); #endif #if defined(ENABLE_DEBIAN) && defined(DEBIAN) - if (repo_add_debdb(repo, 0, REPO_REUSE_REPODATA)) + if (repo_add_debdb(repo, REPO_REUSE_REPODATA | REPO_NO_INTERNALIZE | REPO_USE_ROOTDIR)) { fprintf(stderr, "installed db: %s\n", pool_errstr(pool)); exit(1); } #endif + repo_internalize(repo); writecachedrepo(repo, 0, 0, installedcookie); } pool_set_installed(pool, repo); @@ -1739,7 +1791,7 @@ read_repos(Pool *pool, struct repoinfo *repoinfos, int nrepoinfos) repo->priority = 99 - cinfo->priority; dorefresh = cinfo->autorefresh; - if (dorefresh && cinfo->metadata_expire && stat(calccachepath(repo, 0), &stb) == 0) + if (dorefresh && cinfo->metadata_expire && stat(calccachepath(repo, 0, 0), &stb) == 0) { if (cinfo->metadata_expire == -1 || time(0) - stb.st_mtime < cinfo->metadata_expire) dorefresh = 0; @@ -1750,7 +1802,6 @@ read_repos(Pool *pool, struct repoinfo *repoinfos, int nrepoinfos) printf(" cached\n"); continue; } - badchecksum = 0; switch (cinfo->type) { #ifdef ENABLE_RPMMD @@ -1771,25 +1822,10 @@ read_repos(Pool *pool, struct repoinfo *repoinfos, int nrepoinfos) fclose(fp); break; } - if (cinfo->repo_gpgcheck) + if (cinfo->repo_gpgcheck && !downloadchecksig(cinfo, fp, "repodata/repomd.xml.asc", &sigpool)) { - sigfp = curlfopen(cinfo, "repodata/repomd.xml.asc", 0, 0, 0, 0); - if (!sigfp) - { - printf(" unsigned, skipped\n"); - fclose(fp); - break; - } - if (!sigpool) - sigpool = read_sigs(); - if (!checksig(sigpool, fp, sigfp)) - { - printf(" checksig failed, skipped\n"); - fclose(sigfp); - fclose(fp); - break; - } - fclose(sigfp); + fclose(fp); + break; } if (repo_add_repomdxml(repo, fp, 0)) { @@ -1800,35 +1836,47 @@ read_repos(Pool *pool, struct repoinfo *repoinfos, int nrepoinfos) fclose(fp); printf(" fetching\n"); filename = repomd_find(repo, "primary", &filechksum, &filechksumtype); - if (filename && (fp = curlfopen(cinfo, filename, iscompressed(filename), filechksum, filechksumtype, &badchecksum)) != 0) + if (filename && (fp = curlfopen(cinfo, filename, iscompressed(filename), filechksum, filechksumtype, 1)) != 0) { if (repo_add_rpmmd(repo, fp, 0, 0)) { printf("primary: %s\n", pool_errstr(pool)); - badchecksum = 1; + cinfo->incomplete = 1; } fclose(fp); } - if (badchecksum) + if (cinfo->incomplete) break; /* hopeless */ filename = repomd_find(repo, "updateinfo", &filechksum, &filechksumtype); - if (filename && (fp = curlfopen(cinfo, filename, iscompressed(filename), filechksum, filechksumtype, &badchecksum)) != 0) + if (filename && (fp = curlfopen(cinfo, filename, iscompressed(filename), filechksum, filechksumtype, 1)) != 0) { if (repo_add_updateinfoxml(repo, fp, 0)) { printf("updateinfo: %s\n", pool_errstr(pool)); - badchecksum = 1; + cinfo->incomplete = 1; } fclose(fp); } +#ifdef ENABLE_APPDATA + filename = repomd_find(repo, "appdata", &filechksum, &filechksumtype); + if (filename && (fp = curlfopen(cinfo, filename, iscompressed(filename), filechksum, filechksumtype, 1)) != 0) + { + if (repo_add_appdata(repo, fp, 0)) + { + printf("appdata: %s\n", pool_errstr(pool)); + cinfo->incomplete = 1; + } + fclose(fp); + } +#endif data = repo_add_repodata(repo, 0); if (!repomd_add_ext(repo, data, "deltainfo")) repomd_add_ext(repo, data, "prestodelta"); repomd_add_ext(repo, data, "filelists"); repodata_internalize(data); - if (!badchecksum) + if (!cinfo->incomplete) writecachedrepo(repo, 0, 0, cinfo->cookie); repodata_create_stubs(repo_last_repodata(repo)); break; @@ -1854,28 +1902,10 @@ read_repos(Pool *pool, struct repoinfo *repoinfos, int nrepoinfos) fclose(fp); break; } - if (cinfo->repo_gpgcheck) + if (cinfo->repo_gpgcheck && !downloadchecksig(cinfo, fp, "content.asc", &sigpool)) { - sigfp = curlfopen(cinfo, "content.asc", 0, 0, 0, 0); - if (!sigfp) - { - printf(" unsigned, skipped\n"); - fclose(fp); - break; - } - if (sigfp) - { - if (!sigpool) - sigpool = read_sigs(); - if (!checksig(sigpool, fp, sigfp)) - { - printf(" checksig failed, skipped\n"); - fclose(sigfp); - fclose(fp); - break; - } - fclose(sigfp); - } + fclose(fp); + break; } if (repo_add_content(repo, fp, 0)) { @@ -1897,12 +1927,13 @@ read_repos(Pool *pool, struct repoinfo *repoinfos, int nrepoinfos) break; } printf(" fetching\n"); - if ((fp = curlfopen(cinfo, pool_tmpjoin(pool, descrdir, "/", filename), iscompressed(filename), filechksum, filechksumtype, &badchecksum)) == 0) + if ((fp = curlfopen(cinfo, pool_tmpjoin(pool, descrdir, "/", filename), iscompressed(filename), filechksum, filechksumtype, 1)) == 0) break; /* hopeless */ if (repo_add_susetags(repo, fp, defvendor, 0, REPO_NO_INTERNALIZE|SUSETAGS_RECORD_SHARES)) { printf("packages: %s\n", pool_errstr(pool)); fclose(fp); + cinfo->incomplete = 1; break; /* hopeless */ } fclose(fp); @@ -1912,12 +1943,12 @@ read_repos(Pool *pool, struct repoinfo *repoinfos, int nrepoinfos) filename = susetags_find(repo, "packages.en", &filechksum, &filechksumtype); if (filename) { - if ((fp = curlfopen(cinfo, pool_tmpjoin(pool, descrdir, "/", filename), iscompressed(filename), filechksum, filechksumtype, &badchecksum)) != 0) + if ((fp = curlfopen(cinfo, pool_tmpjoin(pool, descrdir, "/", filename), iscompressed(filename), filechksum, filechksumtype, 1)) != 0) { if (repo_add_susetags(repo, fp, defvendor, 0, REPO_NO_INTERNALIZE|REPO_REUSE_REPODATA|REPO_EXTEND_SOLVABLES)) { printf("packages.en: %s\n", pool_errstr(pool)); - badchecksum = 1; + cinfo->incomplete = 1; } fclose(fp); } @@ -1925,7 +1956,7 @@ read_repos(Pool *pool, struct repoinfo *repoinfos, int nrepoinfos) filename = susetags_find(repo, "patterns", &filechksum, &filechksumtype); if (filename) { - if ((fp = curlfopen(cinfo, pool_tmpjoin(pool, descrdir, "/", filename), iscompressed(filename), filechksum, filechksumtype, &badchecksum)) != 0) + if ((fp = curlfopen(cinfo, pool_tmpjoin(pool, descrdir, "/", filename), iscompressed(filename), filechksum, filechksumtype, 1)) != 0) { char pbuf[256]; while (fgets(pbuf, sizeof(pbuf), fp)) @@ -1937,12 +1968,12 @@ read_repos(Pool *pool, struct repoinfo *repoinfos, int nrepoinfos) if (!*pbuf || *pbuf == '.' || strchr(pbuf, '/') != 0) continue; filename = susetags_find(repo, pbuf, &filechksum, &filechksumtype); - if (filename && (fp2 = curlfopen(cinfo, pool_tmpjoin(pool, descrdir, "/", filename), iscompressed(filename), filechksum, filechksumtype, &badchecksum)) != 0) + if (filename && (fp2 = curlfopen(cinfo, pool_tmpjoin(pool, descrdir, "/", filename), iscompressed(filename), filechksum, filechksumtype, 1)) != 0) { if (repo_add_susetags(repo, fp2, defvendor, 0, REPO_NO_INTERNALIZE)) { printf("%s: %s\n", pbuf, pool_errstr(pool)); - badchecksum = 1; + cinfo->incomplete = 1; } fclose(fp2); } @@ -1950,11 +1981,25 @@ read_repos(Pool *pool, struct repoinfo *repoinfos, int nrepoinfos) fclose(fp); } } +#ifdef ENABLE_APPDATA + filename = susetags_find(repo, "appdata.xml.gz", &filechksum, &filechksumtype); + if (!filename) + filename = susetags_find(repo, "appdata.xml", &filechksum, &filechksumtype); + if (filename && (fp = curlfopen(cinfo, pool_tmpjoin(pool, descrdir, "/", filename), iscompressed(filename), filechksum, filechksumtype, 1)) != 0) + { + if (repo_add_appdata(repo, fp, 0)) + { + printf("appdata: %s\n", pool_errstr(pool)); + cinfo->incomplete = 1; + } + fclose(fp); + } +#endif repo_internalize(repo); data = repo_add_repodata(repo, 0); susetags_add_ext(repo, data); repodata_internalize(data); - if (!badchecksum) + if (!cinfo->incomplete) writecachedrepo(repo, 0, 0, cinfo->cookie); repodata_create_stubs(repo_last_repodata(repo)); break; @@ -1977,24 +2022,13 @@ read_repos(Pool *pool, struct repoinfo *repoinfos, int nrepoinfos) if (cinfo->repo_gpgcheck) { filename = solv_dupjoin("dists/", cinfo->name, "/Release.gpg"); - sigfp = curlfopen(cinfo, filename, 0, 0, 0, 0); - solv_free((char *)filename); - if (!sigfp) - { - printf(" unsigned, skipped\n"); - fclose(fpr); - break; - } - if (!sigpool) - sigpool = read_sigs(); - if (!checksig(sigpool, fpr, sigfp)) + if (!downloadchecksig(cinfo, fpr, filename, &sigpool)) { - printf(" checksig failed, skipped\n"); - fclose(sigfp); fclose(fpr); + solv_free((char *)filename); break; } - fclose(sigfp); + solv_free((char *)filename); } calc_checksum_fp(fpr, REPOKEY_TYPE_SHA256, cinfo->cookie); if (usecachedrepo(repo, 0, cinfo->cookie, 1)) @@ -2011,12 +2045,12 @@ read_repos(Pool *pool, struct repoinfo *repoinfos, int nrepoinfos) printf("[component %s not found]\n", cinfo->components[j]); continue; } - if ((fp = curlfopen(cinfo, filename, iscompressed(filename), filechksum, filechksumtype, &badchecksum)) != 0) + if ((fp = curlfopen(cinfo, filename, iscompressed(filename), filechksum, filechksumtype, 1)) != 0) { if (repo_add_debpackages(repo, fp, 0)) { printf("component %s: %s\n", cinfo->components[j], pool_errstr(pool)); - badchecksum = 1; + cinfo->incomplete = 1; } fclose(fp); } @@ -2024,7 +2058,7 @@ read_repos(Pool *pool, struct repoinfo *repoinfos, int nrepoinfos) solv_free((char *)filename); } fclose(fpr); - if (!badchecksum) + if (!cinfo->incomplete) writecachedrepo(repo, 0, 0, cinfo->cookie); break; #endif @@ -2040,447 +2074,109 @@ read_repos(Pool *pool, struct repoinfo *repoinfos, int nrepoinfos) pool_free(sigpool); } - -int -str2archid(Pool *pool, char *arch) -{ - Id id; - if (!*arch) - return 0; - id = pool_str2id(pool, arch, 0); - if (id == ARCH_SRC || id == ARCH_NOSRC || id == ARCH_NOARCH) - return id; - if (pool->id2arch && (id > pool->lastarch || !pool->id2arch[id])) - return 0; - return id; -} - - -#define DEPGLOB_NAME 1 -#define DEPGLOB_DEP 2 -#define DEPGLOB_NAMEDEP 3 - int -depglob(Pool *pool, char *name, Queue *job, int what) +yesno(const char *str) { - Id p, pp; - Id id = pool_str2id(pool, name, 0); - int i, match = 0; + char inbuf[128], *ip; - if (id) + for (;;) { - FOR_PROVIDES(p, pp, id) + printf("%s", str); + fflush(stdout); + *inbuf = 0; + if (!(ip = fgets(inbuf, sizeof(inbuf), stdin))) { - Solvable *s = pool->solvables + p; - match = 1; - if (s->name == id && (what & DEPGLOB_NAME) != 0) - { - queue_push2(job, SOLVER_SOLVABLE_NAME, id); - return 1; - } + printf("Abort.\n"); + exit(1); } - if (match) + while (*ip == ' ' || *ip == '\t') + ip++; + if (*ip == 'q') { - if (what == DEPGLOB_NAMEDEP) - printf("[using capability match for '%s']\n", name); - queue_push2(job, SOLVER_SOLVABLE_PROVIDES, id); - return 1; + printf("Abort.\n"); + exit(1); } + if (*ip == 'y' || *ip == 'n') + return *ip == 'y' ? 1 : 0; } +} - if (strpbrk(name, "[*?") == 0) - return 0; +#if defined(ENABLE_RPMDB) && (defined(SUSE) || defined(FEDORA)) - if ((what & DEPGLOB_NAME) != 0) - { - /* looks like a name glob. hard work. */ - for (p = 1; p < pool->nsolvables; p++) - { - Solvable *s = pool->solvables + p; - if (!s->repo || !pool_installable(pool, s)) - continue; - id = s->name; - if (fnmatch(name, pool_id2str(pool, id), 0) == 0) - { - for (i = 0; i < job->count; i += 2) - if (job->elements[i] == SOLVER_SOLVABLE_NAME && job->elements[i + 1] == id) - break; - if (i == job->count) - queue_push2(job, SOLVER_SOLVABLE_NAME, id); - match = 1; - } - } - if (match) - return 1; - } - if ((what & DEPGLOB_DEP)) +struct fcstate { + FILE **newpkgsfps; + Queue *checkq; + int newpkgscnt; + void *rpmstate; +}; + +static void * +fileconflict_cb(Pool *pool, Id p, void *cbdata) +{ + struct fcstate *fcstate = cbdata; + Solvable *s; + Id rpmdbid; + int i; + FILE *fp; + + s = pool_id2solvable(pool, p); + if (pool->installed && s->repo == pool->installed) { - /* looks like a dep glob. really hard work. */ - for (id = 1; id < pool->ss.nstrings; id++) - { - if (!pool->whatprovides[id]) - continue; - if (fnmatch(name, pool_id2str(pool, id), 0) == 0) - { - if (!match && what == DEPGLOB_NAMEDEP) - printf("[using capability match for '%s']\n", name); - for (i = 0; i < job->count; i += 2) - if (job->elements[i] == SOLVER_SOLVABLE_PROVIDES && job->elements[i + 1] == id) - break; - if (i == job->count) - queue_push2(job, SOLVER_SOLVABLE_PROVIDES, id); - match = 1; - } - } - if (match) - return 1; + if (!s->repo->rpmdbid) + return 0; + rpmdbid = s->repo->rpmdbid[p - s->repo->start]; + if (!rpmdbid) + return 0; + return rpm_byrpmdbid(fcstate->rpmstate, rpmdbid); } - return 0; + for (i = 0; i < fcstate->newpkgscnt; i++) + if (fcstate->checkq->elements[i] == p) + break; + if (i == fcstate->newpkgscnt) + return 0; + fp = fcstate->newpkgsfps[i]; + if (!fp) + return 0; + rewind(fp); + return rpm_byfp(fcstate->rpmstate, fp, pool_solvable2str(pool, s)); } -int -limitrelation(Pool *pool, Queue *job, int flags, Id evr) + +void +runrpm(const char *arg, const char *name, int dupfd3, const char *rootdir) { - int i, j; - Id p, pp; - for (i = j = 0; i < job->count; i += 2) + pid_t pid; + int status; + + if ((pid = fork()) == (pid_t)-1) { - Id select = job->elements[i] & SOLVER_SELECTMASK; - if (select != SOLVER_SOLVABLE_NAME && select != SOLVER_SOLVABLE_PROVIDES) - { - fprintf(stderr, "limitrelation only works on name/provides jobs\n"); - exit(1); - } - job->elements[i + 1] = pool_rel2id(pool, job->elements[i + 1], evr, flags, 1); - if (flags == REL_ARCH) - job->elements[i] |= SOLVER_SETARCH; - if (flags == REL_EQ && select == SOLVER_SOLVABLE_NAME && job->elements[i]) - { -#ifndef DEBIAN - const char *evrstr = pool_id2str(pool, evr); - if (!strchr(evrstr, '-')) - job->elements[i] |= SOLVER_SETEV; - else -#endif - job->elements[i] |= SOLVER_SETEVR; - } - /* make sure we still have matches */ - FOR_JOB_SELECT(p, pp, job->elements[i], job->elements[i + 1]) - break; - if (p) + perror("fork"); + exit(1); + } + if (pid == 0) + { + if (!rootdir) + rootdir = "/"; + if (dupfd3 != -1 && dupfd3 != 3) { - job->elements[j] = job->elements[i]; - job->elements[j + 1] = job->elements[i + 1]; - j += 2; + dup2(dupfd3, 3); + close(dupfd3); } + if (dupfd3 != -1) + fcntl(3, F_SETFD, 0); /* clear CLOEXEC */ + if (strcmp(arg, "-e") == 0) + execlp("rpm", "rpm", arg, "--nodeps", "--nodigest", "--nosignature", "--root", rootdir, name, (char *)0); + else + execlp("rpm", "rpm", arg, "--force", "--nodeps", "--nodigest", "--nosignature", "--root", rootdir, name, (char *)0); + perror("rpm"); + _exit(0); } - queue_truncate(job, j); - return j / 2; -} - -int -limitrelation_arch(Pool *pool, Queue *job, int flags, char *evr) -{ - char *r; - Id archid; - if ((r = strrchr(evr, '.')) != 0 && r[1] && (archid = str2archid(pool, r + 1)) != 0) + while (waitpid(pid, &status, 0) != pid) + ; + if (status) { - *r = 0; - limitrelation(pool, job, REL_ARCH, archid); - limitrelation(pool, job, flags, pool_str2id(pool, evr, 1)); - *r = '.'; - } - else - limitrelation(pool, job, flags, pool_str2id(pool, evr, 1)); - return job->count / 2; -} - -int -limitrepo(Pool *pool, Id repofilter, Queue *job) -{ - Queue mq; - Id p, pp; - int i, j; - Solvable *s; - - queue_init(&mq); - for (i = j = 0; i < job->count; i += 2) - { - queue_empty(&mq); - FOR_JOB_SELECT(p, pp, job->elements[i], job->elements[i + 1]) - { - s = pool_id2solvable(pool, p); - if (s->repo && s->repo->repoid == repofilter) - queue_push(&mq, p); - } - if (mq.count) - { - /* here we assume that repo == vendor, so we also set SOLVER_SETVENDOR */ - Id flags = (job->elements[i] & SOLVER_SETMASK) | SOLVER_SETVENDOR | SOLVER_SETREPO; - if ((job->elements[i] & SOLVER_SELECTMASK) == SOLVER_SOLVABLE_NAME) - flags |= SOLVER_SETNAME; - if (mq.count == 1) - { - job->elements[j] = SOLVER_SOLVABLE | SOLVER_NOAUTOSET | flags; - job->elements[j + 1] = mq.elements[0]; - } - else - { - job->elements[j] = SOLVER_SOLVABLE_ONE_OF | flags; - job->elements[j + 1] = pool_queuetowhatprovides(pool, &mq); - } - j += 2; - } - } - queue_truncate(job, j); - queue_free(&mq); - return j / 2; -} - -int -mkselect(Pool *pool, int mode, char *name, Queue *job) -{ - char *r, *r2; - Id archid; - - if (*name == '/') - { - Dataiterator di; - int type = strpbrk(name, "[*?") == 0 ? SEARCH_STRING : SEARCH_GLOB; - Queue q; - queue_init(&q); - dataiterator_init(&di, pool, mode == SOLVER_ERASE ? pool->installed : 0, 0, SOLVABLE_FILELIST, name, type|SEARCH_FILES|SEARCH_COMPLETE_FILELIST); - while (dataiterator_step(&di)) - { - Solvable *s = pool->solvables + di.solvid; - if (!s->repo || !pool_installable(pool, s)) - continue; - queue_push(&q, di.solvid); - dataiterator_skip_solvable(&di); - } - dataiterator_free(&di); - if (q.count) - { - printf("[using file list match for '%s']\n", name); - if (q.count > 1) - queue_push2(job, SOLVER_SOLVABLE_ONE_OF, pool_queuetowhatprovides(pool, &q)); - else - queue_push2(job, SOLVER_SOLVABLE | SOLVER_NOAUTOSET, q.elements[0]); - queue_free(&q); - return job->count / 2; - } - } - if ((r = strpbrk(name, "<=>")) != 0) - { - /* relation case, support: - * depglob rel - * depglob.arch rel - */ - int rflags = 0; - int nend = r - name; - char oldnend; - for (; *r; r++) - { - if (*r == '<') - rflags |= REL_LT; - else if (*r == '=') - rflags |= REL_EQ; - else if (*r == '>') - rflags |= REL_GT; - else - break; - } - while (*r && *r == ' ' && *r == '\t') - r++; - while (nend && (name[nend - 1] == ' ' || name[nend -1 ] == '\t')) - nend--; - if (!*name || !*r) - { - fprintf(stderr, "bad relation\n"); - exit(1); - } - oldnend = name[nend]; - name[nend] = 0; - if (depglob(pool, name, job, DEPGLOB_NAMEDEP)) - { - name[nend] = oldnend; - limitrelation(pool, job, rflags, pool_str2id(pool, r, 1)); - return job->count / 2; - } - if ((r2 = strrchr(name, '.')) != 0 && r2[1] && (archid = str2archid(pool, r2 + 1)) != 0) - { - *r2 = 0; - if (depglob(pool, name, job, DEPGLOB_NAMEDEP)) - { - name[nend] = oldnend; - *r2 = '.'; - limitrelation(pool, job, REL_ARCH, archid); - limitrelation(pool, job, rflags, pool_str2id(pool, r, 1)); - return job->count / 2; - } - *r2 = '.'; - } - name[nend] = oldnend; - } - else - { - /* no relation case, support: - * depglob - * depglob.arch - * nameglob-version - * nameglob-version.arch - * nameglob-version-release - * nameglob-version-release.arch - */ - if (depglob(pool, name, job, DEPGLOB_NAMEDEP)) - return job->count / 2; - if ((r = strrchr(name, '.')) != 0 && r[1] && (archid = str2archid(pool, r + 1)) != 0) - { - *r = 0; - if (depglob(pool, name, job, DEPGLOB_NAMEDEP)) - { - *r = '.'; - limitrelation(pool, job, REL_ARCH, archid); - return job->count / 2; - } - *r = '.'; - } - if ((r = strrchr(name, '-')) != 0) - { - *r = 0; - if (depglob(pool, name, job, DEPGLOB_NAME)) - { - /* have just the version */ - limitrelation_arch(pool, job, REL_EQ, r + 1); - *r = '-'; - return job->count / 2; - } - if ((r2 = strrchr(name, '-')) != 0) - { - *r = '-'; - *r2 = 0; - r = r2; - if (depglob(pool, name, job, DEPGLOB_NAME)) - { - /* have version-release */ - limitrelation_arch(pool, job, REL_EQ, r + 1); - *r = '-'; - return job->count / 2; - } - } - *r = '-'; - } - } - return 0; -} - - -int -yesno(const char *str) -{ - char inbuf[128], *ip; - - for (;;) - { - printf("%s", str); - fflush(stdout); - *inbuf = 0; - if (!(ip = fgets(inbuf, sizeof(inbuf), stdin))) - { - printf("Abort.\n"); - exit(1); - } - while (*ip == ' ' || *ip == '\t') - ip++; - if (*ip == 'q') - { - printf("Abort.\n"); - exit(1); - } - if (*ip == 'y' || *ip == 'n') - return *ip == 'y' ? 1 : 0; - } -} - -#if defined(ENABLE_RPMDB) && (defined(SUSE) || defined(FEDORA)) - -struct fcstate { - FILE **newpkgsfps; - Queue *checkq; - int newpkgscnt; - void *rpmdbstate; -}; - -static void * -fileconflict_cb(Pool *pool, Id p, void *cbdata) -{ - struct fcstate *fcstate = cbdata; - Solvable *s; - Id rpmdbid; - int i; - FILE *fp; - - if (!p) - { - rpm_byrpmdbid(0, 0, &fcstate->rpmdbstate); - return 0; - } - s = pool_id2solvable(pool, p); - if (pool->installed && s->repo == pool->installed) - { - if (!s->repo->rpmdbid) - return 0; - rpmdbid = s->repo->rpmdbid[p - s->repo->start]; - if (!rpmdbid) - return 0; - return rpm_byrpmdbid(rpmdbid, 0, &fcstate->rpmdbstate); - } - for (i = 0; i < fcstate->newpkgscnt; i++) - if (fcstate->checkq->elements[i] == p) - break; - if (i == fcstate->newpkgscnt) - return 0; - fp = fcstate->newpkgsfps[i]; - if (!fp) - return 0; - rewind(fp); - return rpm_byfp(fp, pool_solvable2str(pool, s), &fcstate->rpmdbstate); -} - - -void -runrpm(const char *arg, const char *name, int dupfd3) -{ - pid_t pid; - int status; - - if ((pid = fork()) == (pid_t)-1) - { - perror("fork"); - exit(1); - } - if (pid == 0) - { - if (dupfd3 != -1 && dupfd3 != 3) - { - dup2(dupfd3, 3); - close(dupfd3); - } - if (dupfd3 != -1) - fcntl(3, F_SETFD, 0); /* clear CLOEXEC */ - if (strcmp(arg, "-e") == 0) - execlp("rpm", "rpm", arg, "--nodeps", "--nodigest", "--nosignature", name, (char *)0); - else - execlp("rpm", "rpm", arg, "--force", "--nodeps", "--nodigest", "--nosignature", name, (char *)0); - perror("rpm"); - _exit(0); - } - while (waitpid(pid, &status, 0) != pid) - ; - if (status) - { - printf("rpm failed\n"); - exit(1); + printf("rpm failed\n"); + exit(1); } } @@ -2489,7 +2185,7 @@ runrpm(const char *arg, const char *name, int dupfd3) #if defined(ENABLE_DEBIAN) && defined(DEBIAN) void -rundpkg(const char *arg, const char *name, int dupfd3) +rundpkg(const char *arg, const char *name, int dupfd3, const char *rootdir) { pid_t pid; int status; @@ -2501,6 +2197,8 @@ rundpkg(const char *arg, const char *name, int dupfd3) } if (pid == 0) { + if (!rootdir) + rootdir = "/"; if (dupfd3 != -1 && dupfd3 != 3) { dup2(dupfd3, 3); @@ -2509,9 +2207,9 @@ rundpkg(const char *arg, const char *name, int dupfd3) if (dupfd3 != -1) fcntl(3, F_SETFD, 0); /* clear CLOEXEC */ if (strcmp(arg, "--install") == 0) - execlp("dpkg", "dpkg", "--install", "--force", "all", name, (char *)0); + execlp("dpkg", "dpkg", "--install", "--root", rootdir, "--force", "all", name, (char *)0); else - execlp("dpkg", "dpkg", "--remove", "--force", "all", name, (char *)0); + execlp("dpkg", "dpkg", "--remove", "--root", rootdir, "--force", "all", name, (char *)0); perror("dpkg"); _exit(0); } @@ -2526,36 +2224,28 @@ rundpkg(const char *arg, const char *name, int dupfd3) #endif +#ifdef SUSE static Id nscallback(Pool *pool, void *data, Id name, Id evr) { - if (name == NAMESPACE_PRODUCTBUDDY) +#if 0 + if (name == NAMESPACE_LANGUAGE) { - /* SUSE specific hack: each product has an associated rpm */ - Solvable *s = pool->solvables + evr; - Id p, pp, cap; - Id bestp = 0; - - cap = pool_str2id(pool, pool_tmpjoin(pool, "product(", pool_id2str(pool, s->name) + 8, ")"), 0); - if (!cap) - return 0; - cap = pool_rel2id(pool, cap, s->evr, REL_EQ, 0); - if (!cap) - return 0; - FOR_PROVIDES(p, pp, cap) - { - Solvable *ps = pool->solvables + p; - if (ps->repo == s->repo && ps->arch == s->arch) - if (!bestp || pool_evrcmp(pool, pool->solvables[bestp].evr, ps->evr, EVRCMP_COMPARE) < 0) - bestp = p; - } - return bestp; + if (!strcmp(pool_id2str(pool, evr), "ja")) + return 1; + if (!strcmp(pool_id2str(pool, evr), "de")) + return 1; + if (!strcmp(pool_id2str(pool, evr), "en")) + return 1; + if (!strcmp(pool_id2str(pool, evr), "en_US")) + return 1; } +#endif return 0; } +#endif #ifdef SOFTLOCKS_PATH - void addsoftlocks(Pool *pool, Queue *job) { @@ -2594,11 +2284,12 @@ addsoftlocks(Pool *pool, Queue *job) } fclose(fp); } - #endif -void +#if defined(ENABLE_RPMDB) + +static void rewrite_repos(Pool *pool, Queue *addedfileprovides, Queue *addedfileprovides_inst) { Repo *repo; @@ -2617,6 +2308,11 @@ rewrite_repos(Pool *pool, Queue *addedfileprovides, Queue *addedfileprovides_ins /* make sure all repodatas but the first are extensions */ if (repo->nrepodata < 2) continue; + cinfo = repo->appdata; + if (repo != pool->installed && !cinfo) + continue; + if (cinfo && cinfo->incomplete) + continue; data = repo_id2repodata(repo, 1); if (data->loadcallback) continue; @@ -2655,7 +2351,6 @@ rewrite_repos(Pool *pool, Queue *addedfileprovides, Queue *addedfileprovides_ins } repodata_set_idarray(data, SOLVID_META, REPOSITORY_ADDEDFILEPROVIDES, repo == pool->installed && addedfileprovides_inst ? addedfileprovides_inst : addedfileprovides); repodata_internalize(data); - cinfo = repo->appdata; writecachedrepo(repo, data, 0, cinfo ? cinfo->cookie : installedcookie); } queue_free(&fileprovidesq); @@ -2663,16 +2358,45 @@ rewrite_repos(Pool *pool, Queue *addedfileprovides, Queue *addedfileprovides_ins } static void -select_patches(Pool *pool, Queue *job) +addfileprovides(Pool *pool) +{ + Queue addedfileprovides; + Queue addedfileprovides_inst; + + queue_init(&addedfileprovides); + queue_init(&addedfileprovides_inst); + pool_addfileprovides_queue(pool, &addedfileprovides, &addedfileprovides_inst); + if (addedfileprovides.count || addedfileprovides_inst.count) + rewrite_repos(pool, &addedfileprovides, &addedfileprovides_inst); + queue_free(&addedfileprovides); + queue_free(&addedfileprovides_inst); +} + +#endif + +#ifdef SUSE +static void +add_autopackages(Pool *pool) +{ + int i; + Repo *repo; + FOR_REPOS(i, repo) + repo_add_autopattern(repo, 0); +} +#endif + +#if defined(SUSE) || defined(FEDORA) +static void +add_patchjobs(Pool *pool, Queue *job) { Id p, pp; int pruneyou = 0; - Map installedmap, noobsmap; + Map installedmap, multiversionmap; Solvable *s; - map_init(&noobsmap, 0); + map_init(&multiversionmap, 0); map_init(&installedmap, pool->nsolvables); - solver_calculate_noobsmap(pool, job, &noobsmap); + solver_calculate_multiversionmap(pool, job, &multiversionmap); if (pool->installed) FOR_REPO_SOLVABLES(pool->installed, p, s) MAPSET(&installedmap, p); @@ -2701,7 +2425,7 @@ select_patches(Pool *pool, Queue *job) type = solvable_lookup_str(s, SOLVABLE_PATCHCATEGORY); if (type && !strcmp(type, "optional")) continue; - r = solvable_trivial_installable_map(s, &installedmap, 0, &noobsmap); + r = solvable_trivial_installable_map(s, &installedmap, 0, &multiversionmap); if (r == -1) continue; if (solvable_lookup_bool(s, UPDATE_RESTART) && r == 0) @@ -2714,8 +2438,134 @@ select_patches(Pool *pool, Queue *job) queue_push2(job, SOLVER_SOLVABLE, p); } map_free(&installedmap); - map_free(&noobsmap); + map_free(&multiversionmap); +} +#endif + +#ifdef SUSE +static void +showdiskusagechanges(Transaction *trans) +{ + DUChanges duc[4]; + int i; + + /* XXX: use mountpoints here */ + memset(duc, 0, sizeof(duc)); + duc[0].path = "/"; + duc[1].path = "/usr/share/man"; + duc[2].path = "/sbin"; + duc[3].path = "/etc"; + transaction_calc_duchanges(trans, duc, 4); + for (i = 0; i < 4; i++) + printf("duchanges %s: %d K %d inodes\n", duc[i].path, duc[i].kbytes, duc[i].files); +} +#endif + +#if defined(ENABLE_RPMDB) +static FILE * +trydeltadownload(Solvable *s, struct repoinfo *cinfo, const char *loc) +{ + Pool *pool = s->repo->pool; + Dataiterator di; + Id pp; + const unsigned char *chksum; + Id chksumtype; + FILE *retfp = 0; + char *matchname = strdup(pool_id2str(pool, s->name)); + + dataiterator_init(&di, pool, s->repo, SOLVID_META, DELTA_PACKAGE_NAME, matchname, SEARCH_STRING); + dataiterator_prepend_keyname(&di, REPOSITORY_DELTAINFO); + while (dataiterator_step(&di)) + { + Id baseevr, op; + + dataiterator_setpos_parent(&di); + if (pool_lookup_id(pool, SOLVID_POS, DELTA_PACKAGE_EVR) != s->evr || + pool_lookup_id(pool, SOLVID_POS, DELTA_PACKAGE_ARCH) != s->arch) + continue; + baseevr = pool_lookup_id(pool, SOLVID_POS, DELTA_BASE_EVR); + FOR_PROVIDES(op, pp, s->name) + { + Solvable *os = pool->solvables + op; + if (os->repo == pool->installed && os->name == s->name && os->arch == s->arch && os->evr == baseevr) + break; + } + if (op && access("/usr/bin/applydeltarpm", X_OK) == 0) + { + /* base is installed, run sequence check */ + const char *seq; + const char *dloc; + const char *archstr; + FILE *fp; + char cmd[128]; + int newfd; + + archstr = pool_id2str(pool, s->arch); + if (strlen(archstr) > 10 || strchr(archstr, '\'') != 0) + continue; + + seq = pool_tmpjoin(pool, pool_lookup_str(pool, SOLVID_POS, DELTA_SEQ_NAME), "-", pool_lookup_str(pool, SOLVID_POS, DELTA_SEQ_EVR)); + seq = pool_tmpappend(pool, seq, "-", pool_lookup_str(pool, SOLVID_POS, DELTA_SEQ_NUM)); + if (strchr(seq, '\'') != 0) + continue; +#ifdef FEDORA + sprintf(cmd, "/usr/bin/applydeltarpm -a '%s' -c -s '", archstr); +#else + sprintf(cmd, "/usr/bin/applydeltarpm -c -s '"); +#endif + if (system(pool_tmpjoin(pool, cmd, seq, "'")) != 0) + continue; /* didn't match */ + /* looks good, download delta */ + chksumtype = 0; + chksum = pool_lookup_bin_checksum(pool, SOLVID_POS, DELTA_CHECKSUM, &chksumtype); + if (!chksumtype) + continue; /* no way! */ + dloc = pool_lookup_deltalocation(pool, SOLVID_POS, 0); + if (!dloc) + continue; +#ifdef ENABLE_SUSEREPO + if (cinfo->type == TYPE_SUSETAGS) + { + const char *datadir = repo_lookup_str(cinfo->repo, SOLVID_META, SUSETAGS_DATADIR); + dloc = pool_tmpjoin(pool, datadir ? datadir : "suse", "/", dloc); + } +#endif + if ((fp = curlfopen(cinfo, dloc, 0, chksum, chksumtype, 0)) == 0) + continue; + /* got it, now reconstruct */ + newfd = opentmpfile(); +#ifdef FEDORA + sprintf(cmd, "applydeltarpm -a '%s' /dev/fd/%d /dev/fd/%d", archstr, fileno(fp), newfd); +#else + sprintf(cmd, "applydeltarpm /dev/fd/%d /dev/fd/%d", fileno(fp), newfd); +#endif + fcntl(fileno(fp), F_SETFD, 0); + if (system(cmd)) + { + close(newfd); + fclose(fp); + continue; + } + lseek(newfd, 0, SEEK_SET); + chksumtype = 0; + chksum = solvable_lookup_bin_checksum(s, SOLVABLE_CHECKSUM, &chksumtype); + if (chksumtype && !verify_checksum(newfd, loc, chksum, chksumtype)) + { + close(newfd); + fclose(fp); + continue; + } + retfp = fdopen(newfd, "r"); + fclose(fp); + break; + } + } + dataiterator_free(&di); + solv_free(matchname); + return retfp; } +#endif + #define MODE_LIST 0 #define MODE_INSTALL 1 @@ -2743,6 +2593,9 @@ usage(int r) fprintf(stderr, " search: search name/summary/description\n"); fprintf(stderr, " update: update installed packages\n"); fprintf(stderr, " verify: check dependencies of installed packages\n"); +#if defined(SUSE) || defined(FEDORA) + fprintf(stderr, " patch: install newest patches\n"); +#endif fprintf(stderr, "\n"); exit(r); } @@ -2753,7 +2606,7 @@ main(int argc, char **argv) Pool *pool; Repo *commandlinerepo = 0; Id *commandlinepkgs = 0; - Id p, pp; + Id p; struct repoinfo *repoinfos; int nrepoinfos = 0; int mainmode = 0, mode = 0; @@ -2761,16 +2614,28 @@ main(int argc, char **argv) Queue job, checkq; Solver *solv = 0; Transaction *trans; - char inbuf[128], *ip; - int allpkgs = 0; FILE **newpkgsfps; - Queue addedfileprovides; - Queue addedfileprovides_inst; - Id repofilter = 0; + Queue repofilter; + Queue kindfilter; + Queue archfilter; + int archfilter_src = 0; int cleandeps = 0; + int forcebest = 0; + char *rootdir = 0; + char *keyname = 0; + int debuglevel = 0; argc--; argv++; + userhome = getenv("HOME"); + if (userhome && userhome[0] != '/') + userhome = 0; + while (argc && !strcmp(argv[0], "-d")) + { + debuglevel++; + argc--; + argv++; + } if (!argv[0]) usage(1); if (!strcmp(argv[0], "install") || !strcmp(argv[0], "in")) @@ -2778,17 +2643,19 @@ main(int argc, char **argv) mainmode = MODE_INSTALL; mode = SOLVER_INSTALL; } +#if defined(SUSE) || defined(FEDORA) else if (!strcmp(argv[0], "patch")) { mainmode = MODE_PATCH; mode = SOLVER_INSTALL; } +#endif else if (!strcmp(argv[0], "erase") || !strcmp(argv[0], "rm")) { mainmode = MODE_ERASE; mode = SOLVER_ERASE; } - else if (!strcmp(argv[0], "list")) + else if (!strcmp(argv[0], "list") || !strcmp(argv[0], "ls")) { mainmode = MODE_LIST; mode = 0; @@ -2798,7 +2665,7 @@ main(int argc, char **argv) mainmode = MODE_INFO; mode = 0; } - else if (!strcmp(argv[0], "search")) + else if (!strcmp(argv[0], "search") || !strcmp(argv[0], "se")) { mainmode = MODE_SEARCH; mode = 0; @@ -2816,7 +2683,7 @@ main(int argc, char **argv) else if (!strcmp(argv[0], "dist-upgrade") || !strcmp(argv[0], "dup")) { mainmode = MODE_DISTUPGRADE; - mode = SOLVER_UPDATE; + mode = SOLVER_DISTUPGRADE; } else if (!strcmp(argv[0], "repos") || !strcmp(argv[0], "repolist") || !strcmp(argv[0], "lr")) { @@ -2826,14 +2693,38 @@ main(int argc, char **argv) else usage(1); - if (argc > 1 && !strcmp(argv[1], "--clean")) + for (;;) { - cleandeps = 1; - argc--; - argv++; + if (argc > 2 && !strcmp(argv[1], "--root")) + { + rootdir = argv[2]; + argc -= 2; + argv += 2; + } + else if (argc > 1 && !strcmp(argv[1], "--clean")) + { + cleandeps = 1; + argc--; + argv++; + } + else if (argc > 1 && !strcmp(argv[1], "--best")) + { + forcebest = 1; + argc--; + argv++; + } + if (argc > 2 && !strcmp(argv[1], "--keyname")) + { + keyname = argv[2]; + argc -= 2; + argv += 2; + } + else + break; } pool = pool_create(); + pool_set_rootdir(pool, rootdir); #if 0 { @@ -2843,9 +2734,13 @@ main(int argc, char **argv) #endif pool_setloadcallback(pool, load_stub, 0); +#ifdef SUSE pool->nscallback = nscallback; - // pool_setdebuglevel(pool, 2); +#endif + if (debuglevel) + pool_setdebuglevel(pool, debuglevel); setarch(pool); + pool_set_flag(pool, POOL_FLAG_ADDFILEPROVIDESFILTERED, 1); repoinfos = read_repoinfos(pool, &nrepoinfos); if (mainmode == MODE_REPOLIST) @@ -2863,78 +2758,130 @@ main(int argc, char **argv) read_repos(pool, repoinfos, nrepoinfos); - if (argc > 2 && !strcmp(argv[1], "-r")) + /* setup filters */ + queue_init(&repofilter); + queue_init(&kindfilter); + queue_init(&archfilter); + while (argc > 1) { - const char *rname = argv[2], *rp; - for (rp = rname; *rp; rp++) - if (*rp <= '0' || *rp >= '9') - break; - if (!*rp) + if (!strcmp(argv[1], "-i")) { - /* repo specified by number */ - int rnum = atoi(rname); - for (i = 0; i < nrepoinfos; i++) - { - struct repoinfo *cinfo = repoinfos + i; - if (!cinfo->enabled) - continue; - if (--rnum == 0) - repofilter = cinfo->repo->repoid; - } + queue_push2(&repofilter, SOLVER_SOLVABLE_REPO | SOLVER_SETREPO, pool->installed->repoid); + argc--; + argv++; } - else + else if (argc > 2 && (!strcmp(argv[1], "-r") || !strcmp(argv[1], "--repo"))) { - /* repo specified by alias */ - Repo *repo; - FOR_REPOS(i, repo) + const char *rname = argv[2], *rp; + Id repoid = 0; + for (rp = rname; *rp; rp++) + if (*rp <= '0' || *rp >= '9') + break; + if (!*rp) { - if (!strcasecmp(rname, repo->name)) - repofilter = repo->repoid; + /* repo specified by number */ + int rnum = atoi(rname); + for (i = 0; i < nrepoinfos; i++) + { + struct repoinfo *cinfo = repoinfos + i; + if (!cinfo->enabled) + continue; + if (--rnum == 0) + repoid = cinfo->repo->repoid; + } } + else + { + /* repo specified by alias */ + Repo *repo; + FOR_REPOS(i, repo) + { + if (!strcasecmp(rname, repo->name)) + repoid = repo->repoid; + } + } + if (!repoid) + { + fprintf(stderr, "%s: no such repo\n", rname); + exit(1); + } + /* SETVENDOR is actually wrong but useful */ + queue_push2(&repofilter, SOLVER_SOLVABLE_REPO | SOLVER_SETREPO | SOLVER_SETVENDOR, repoid); + argc -= 2; + argv += 2; } - if (!repofilter) + else if (argc > 2 && !strcmp(argv[1], "--arch")) { - fprintf(stderr, "%s: no such repo\n", rname); - exit(1); + if (!strcmp(argv[2], "src") || !strcmp(argv[2], "nosrc")) + archfilter_src = 1; + queue_push2(&archfilter, SOLVER_SOLVABLE_PROVIDES, pool_rel2id(pool, 0, pool_str2id(pool, argv[2], 1), REL_ARCH, 1)); + argc -= 2; + argv += 2; } - argc -= 2; - argv += 2; + else if (argc > 2 && (!strcmp(argv[1], "-t") || !strcmp(argv[1], "--type"))) + { + const char *kind = argv[2]; + if (!strcmp(kind, "srcpackage")) + { + /* hey! should use --arch! */ + queue_push2(&archfilter, SOLVER_SOLVABLE_PROVIDES, pool_rel2id(pool, 0, ARCH_SRC, REL_ARCH, 1)); + archfilter_src = 1; + argc -= 2; + argv += 2; + continue; + } + if (!strcmp(kind, "package")) + kind = ""; + if (!strcmp(kind, "all")) + queue_push2(&kindfilter, SOLVER_SOLVABLE_ALL, 0); + else + queue_push2(&kindfilter, SOLVER_SOLVABLE_PROVIDES, pool_rel2id(pool, 0, pool_str2id(pool, kind, 1), REL_KIND, 1)); + argc -= 2; + argv += 2; + } + else + break; } + if (mainmode == MODE_SEARCH) { + Queue sel, q; Dataiterator di; - Map m; if (argc != 2) usage(1); - map_init(&m, pool->nsolvables); + pool_createwhatprovides(pool); + queue_init(&sel); dataiterator_init(&di, pool, 0, 0, 0, argv[1], SEARCH_SUBSTRING|SEARCH_NOCASE); dataiterator_set_keyname(&di, SOLVABLE_NAME); dataiterator_set_search(&di, 0, 0); while (dataiterator_step(&di)) - MAPSET(&m, di.solvid); + queue_push2(&sel, SOLVER_SOLVABLE, di.solvid); dataiterator_set_keyname(&di, SOLVABLE_SUMMARY); dataiterator_set_search(&di, 0, 0); while (dataiterator_step(&di)) - MAPSET(&m, di.solvid); + queue_push2(&sel, SOLVER_SOLVABLE, di.solvid); dataiterator_set_keyname(&di, SOLVABLE_DESCRIPTION); dataiterator_set_search(&di, 0, 0); while (dataiterator_step(&di)) - MAPSET(&m, di.solvid); + queue_push2(&sel, SOLVER_SOLVABLE, di.solvid); dataiterator_free(&di); - - for (p = 1; p < pool->nsolvables; p++) + if (repofilter.count) + selection_filter(pool, &sel, &repofilter); + + queue_init(&q); + selection_solvables(pool, &sel, &q); + queue_free(&sel); + for (i = 0; i < q.count; i++) { - Solvable *s = pool_id2solvable(pool, p); - if (!MAPTST(&m, p)) - continue; - printf(" - %s: %s\n", pool_solvable2str(pool, s), solvable_lookup_str(s, SOLVABLE_SUMMARY)); + Solvable *s = pool_id2solvable(pool, q.elements[i]); + printf(" - %s [%s]: %s\n", pool_solvable2str(pool, s), s->repo->name, solvable_lookup_str(s, SOLVABLE_SUMMARY)); } - map_free(&m); + queue_free(&q); exit(0); } - - if (mainmode == MODE_LIST || mainmode == MODE_INSTALL) + /* process command line packages */ + if (mainmode == MODE_LIST || mainmode == MODE_INFO || mainmode == MODE_INSTALL) { for (i = 1; i < argc; i++) { @@ -2977,20 +2924,23 @@ main(int argc, char **argv) // FOR_REPOS(i, repo) // printf("%s: %d solvables\n", repo->name, repo->nsolvables); - queue_init(&addedfileprovides); - queue_init(&addedfileprovides_inst); - pool_addfileprovides_queue(pool, &addedfileprovides, &addedfileprovides_inst); - if (addedfileprovides.count || addedfileprovides_inst.count) - rewrite_repos(pool, &addedfileprovides, &addedfileprovides_inst); - queue_free(&addedfileprovides); - queue_free(&addedfileprovides_inst); + +#if defined(ENABLE_RPMDB) + if (pool->disttype == DISTTYPE_RPM) + addfileprovides(pool); +#endif +#ifdef SUSE + add_autopackages(pool); +#endif pool_createwhatprovides(pool); + if (keyname) + keyname = solv_dupjoin("solvable:", keyname, 0); queue_init(&job); for (i = 1; i < argc; i++) { Queue job2; - int j; + int j, flags, rflags; if (commandlinepkgs && commandlinepkgs[i]) { @@ -2998,39 +2948,88 @@ main(int argc, char **argv) continue; } queue_init(&job2); - if (!mkselect(pool, mode, argv[i], &job2)) + flags = SELECTION_NAME|SELECTION_PROVIDES|SELECTION_GLOB; + flags |= SELECTION_CANON|SELECTION_DOTARCH|SELECTION_REL; + if (kindfilter.count) + flags |= SELECTION_SKIP_KIND; + if (mode == MODE_LIST || archfilter_src) + flags |= SELECTION_WITH_SOURCE; + if (argv[i][0] == '/') + flags |= SELECTION_FILELIST | (mode == MODE_ERASE ? SELECTION_INSTALLED_ONLY : 0); + if (!keyname) + rflags = selection_make(pool, &job2, argv[i], flags); + else + rflags = selection_make_matchdeps(pool, &job2, argv[i], flags, pool_str2id(pool, keyname, 1), 0); + if (repofilter.count) + selection_filter(pool, &job2, &repofilter); + if (archfilter.count) + selection_filter(pool, &job2, &archfilter); + if (kindfilter.count) + selection_filter(pool, &job2, &kindfilter); + if (!job2.count) + { + flags |= SELECTION_NOCASE; + if (!keyname) + rflags = selection_make(pool, &job2, argv[i], flags); + else + rflags = selection_make_matchdeps(pool, &job2, argv[i], flags, pool_str2id(pool, keyname, 1), 0); + if (repofilter.count) + selection_filter(pool, &job2, &repofilter); + if (archfilter.count) + selection_filter(pool, &job2, &archfilter); + if (kindfilter.count) + selection_filter(pool, &job2, &kindfilter); + if (job2.count) + printf("[ignoring case for '%s']\n", argv[i]); + } + if (!job2.count) { fprintf(stderr, "nothing matches '%s'\n", argv[i]); exit(1); } - if (repofilter && !limitrepo(pool, repofilter, &job2)) - { - fprintf(stderr, "nothing in repo matches '%s'\n", argv[i]); - exit(1); - } + if (rflags & SELECTION_FILELIST) + printf("[using file list match for '%s']\n", argv[i]); + if (rflags & SELECTION_PROVIDES) + printf("[using capability match for '%s']\n", argv[i]); for (j = 0; j < job2.count; j++) queue_push(&job, job2.elements[j]); queue_free(&job2); } + keyname = solv_free(keyname); + + if (!job.count && (mainmode == MODE_UPDATE || mainmode == MODE_DISTUPGRADE || mainmode == MODE_VERIFY || repofilter.count || archfilter.count || kindfilter.count)) + { + queue_push2(&job, SOLVER_SOLVABLE_ALL, 0); + if (repofilter.count) + selection_filter(pool, &job, &repofilter); + if (archfilter.count) + selection_filter(pool, &job, &archfilter); + if (kindfilter.count) + selection_filter(pool, &job, &kindfilter); + } + queue_free(&repofilter); + queue_free(&archfilter); + queue_free(&kindfilter); - if (!job.count && mainmode != MODE_UPDATE && mainmode != MODE_DISTUPGRADE && mainmode != MODE_VERIFY && mainmode != MODE_PATCH) + if (!job.count && mainmode != MODE_PATCH) { printf("no package matched\n"); exit(1); } - if (!job.count) - allpkgs = 1; - if (mainmode == MODE_LIST || mainmode == MODE_INFO) { /* list mode, no solver needed */ + Queue q; + queue_init(&q); for (i = 0; i < job.count; i += 2) { - Id how = job.elements[i] & SOLVER_SELECTMASK; - FOR_JOB_SELECT(p, pp, how, job.elements[i + 1]) + int j; + queue_empty(&q); + pool_job2solvables(pool, &q, job.elements[i], job.elements[i + 1]); + for (j = 0; j < q.count; j++) { - Solvable *s = pool_id2solvable(pool, p); + Solvable *s = pool_id2solvable(pool, q.elements[j]); if (mainmode == MODE_INFO) { const char *str; @@ -3043,6 +3042,11 @@ main(int argc, char **argv) str = solvable_lookup_str(s, SOLVABLE_LICENSE); if (str) printf("License: %s\n", str); +#if 0 + str = solvable_lookup_sourcepkg(s); + if (str) + printf("Source: %s\n", str); +#endif printf("Description:\n%s\n", solvable_lookup_str(s, SOLVABLE_DESCRIPTION)); printf("\n"); } @@ -3059,6 +3063,7 @@ main(int argc, char **argv) } } } + queue_free(&q); queue_free(&job); pool_free(pool); free_repoinfos(repoinfos, nrepoinfos); @@ -3069,57 +3074,31 @@ main(int argc, char **argv) exit(0); } +#if defined(SUSE) || defined(FEDORA) if (mainmode == MODE_PATCH) - select_patches(pool, &job); + add_patchjobs(pool, &job); +#endif // add mode for (i = 0; i < job.count; i += 2) { - if (mode == SOLVER_UPDATE) - { - /* make update of not installed packages an install */ - FOR_JOB_SELECT(p, pp, job.elements[i], job.elements[i + 1]) - if (pool->installed && pool->solvables[p].repo == pool->installed) - break; - if (!p) - { - job.elements[i] |= SOLVER_INSTALL; - if (cleandeps) - job.elements[i] |= SOLVER_CLEANDEPS; - continue; - } - } job.elements[i] |= mode; + if (mode == SOLVER_UPDATE && pool_isemptyupdatejob(pool, job.elements[i], job.elements[i + 1])) + job.elements[i] ^= SOLVER_UPDATE ^ SOLVER_INSTALL; if (cleandeps) job.elements[i] |= SOLVER_CLEANDEPS; - } - - if (mainmode == MODE_DISTUPGRADE && allpkgs) - { - if (repofilter) - queue_push2(&job, SOLVER_DISTUPGRADE|SOLVER_SOLVABLE_REPO, repofilter); - else - queue_push2(&job, SOLVER_DISTUPGRADE|SOLVER_SOLVABLE_ALL, 0); - } - if (mainmode == MODE_UPDATE && allpkgs) - { - if (repofilter) - queue_push2(&job, SOLVER_UPDATE|SOLVER_SOLVABLE_REPO, repofilter); - else - queue_push2(&job, SOLVER_UPDATE|SOLVER_SOLVABLE_ALL, 0); - } - if (mainmode == MODE_VERIFY && allpkgs) - { - if (repofilter) - queue_push2(&job, SOLVER_VERIFY|SOLVER_SOLVABLE_REPO, repofilter); - else - queue_push2(&job, SOLVER_VERIFY|SOLVER_SOLVABLE_ALL, 0); + if (forcebest) + job.elements[i] |= SOLVER_FORCEBEST; } // multiversion test - // queue_push2(&job, SOLVER_NOOBSOLETES|SOLVER_SOLVABLE_NAME, pool_str2id(pool, "kernel-pae", 1)); - // queue_push2(&job, SOLVER_NOOBSOLETES|SOLVER_SOLVABLE_NAME, pool_str2id(pool, "kernel-pae-base", 1)); - // queue_push2(&job, SOLVER_NOOBSOLETES|SOLVER_SOLVABLE_NAME, pool_str2id(pool, "kernel-pae-extra", 1)); + // queue_push2(&job, SOLVER_MULTIVERSION|SOLVER_SOLVABLE_NAME, pool_str2id(pool, "kernel-pae", 1)); + // queue_push2(&job, SOLVER_MULTIVERSION|SOLVER_SOLVABLE_NAME, pool_str2id(pool, "kernel-pae-base", 1)); + // queue_push2(&job, SOLVER_MULTIVERSION|SOLVER_SOLVABLE_NAME, pool_str2id(pool, "kernel-pae-extra", 1)); +#if 0 + queue_push2(&job, SOLVER_INSTALL|SOLVER_SOLVABLE_PROVIDES, pool_rel2id(pool, NAMESPACE_LANGUAGE, 0, REL_NAMESPACE, 1)); + queue_push2(&job, SOLVER_ERASE|SOLVER_CLEANDEPS|SOLVER_SOLVABLE_PROVIDES, pool_rel2id(pool, NAMESPACE_LANGUAGE, 0, REL_NAMESPACE, 1)); +#endif #ifdef SOFTLOCKS_PATH addsoftlocks(pool, &job); @@ -3128,16 +3107,20 @@ main(int argc, char **argv) #if defined(ENABLE_RPMDB) && (defined(SUSE) || defined(FEDORA)) rerunsolver: #endif + solv = solver_create(pool); + solver_set_flag(solv, SOLVER_FLAG_SPLITPROVIDES, 1); +#ifdef FEDORA + solver_set_flag(solv, SOLVER_FLAG_ALLOW_VENDORCHANGE, 1); +#endif + if (mainmode == MODE_ERASE) + solver_set_flag(solv, SOLVER_FLAG_ALLOW_UNINSTALL, 1); /* don't nag */ + solver_set_flag(solv, SOLVER_FLAG_BEST_OBEY_POLICY, 1); + for (;;) { Id problem, solution; int pcnt, scnt; - solv = solver_create(pool); - solver_set_flag(solv, SOLVER_FLAG_SPLITPROVIDES, 1); - if (mainmode == MODE_ERASE) - solver_set_flag(solv, SOLVER_FLAG_ALLOW_UNINSTALL, 1); /* don't nag */ - if (!solver_solve(solv, &job)) break; pcnt = solver_problem_count(solv); @@ -3145,7 +3128,7 @@ rerunsolver: for (problem = 1; problem <= pcnt; problem++) { int take = 0; - printf("Problem %d:\n", problem); + printf("Problem %d/%d:\n", problem, pcnt); solver_printprobleminfo(solv, problem); printf("\n"); scnt = solver_solution_count(solv, problem); @@ -3157,6 +3140,7 @@ rerunsolver: } for (;;) { + char inbuf[128], *ip; printf("Please choose a solution: "); fflush(stdout); *inbuf = 0; @@ -3188,8 +3172,6 @@ rerunsolver: continue; solver_take_solution(solv, problem, take, &job); } - solver_free(solv); - solv = 0; } trans = solver_create_transaction(solv); @@ -3207,24 +3189,13 @@ rerunsolver: #endif exit(1); } + + /* display transaction to the user and ask for confirmation */ printf("\n"); printf("Transaction summary:\n\n"); transaction_print(trans); - #if defined(SUSE) - if (1) - { - DUChanges duc[4]; - int i; - - duc[0].path = "/"; - duc[1].path = "/usr/share/man"; - duc[2].path = "/sbin"; - duc[3].path = "/etc"; - transaction_calc_duchanges(trans, duc, 4); - for (i = 0; i < 4; i++) - printf("duchanges %s: %d K %d inodes\n", duc[i].path, duc[i].kbytes, duc[i].files); - } + showdiskusagechanges(trans); #endif printf("install size change: %d K\n", transaction_calc_installsizechange(trans)); printf("\n"); @@ -3244,10 +3215,10 @@ rerunsolver: exit(1); } + /* download all new packages */ queue_init(&checkq); newpkgs = transaction_installedresult(trans, &checkq); newpkgsfps = 0; - if (newpkgs) { int downloadsize = 0; @@ -3264,18 +3235,19 @@ rerunsolver: for (i = 0; i < newpkgs; i++) { unsigned int medianr; - char *loc; + const char *loc; Solvable *s; struct repoinfo *cinfo; const unsigned char *chksum; Id chksumtype; - Dataiterator di; p = checkq.elements[i]; s = pool_id2solvable(pool, p); if (s->repo == commandlinerepo) { - loc = solvable_get_location(s, &medianr); + loc = solvable_lookup_location(s, &medianr); + if (!loc) + continue; if (!(newpkgsfps[i] = fopen(loc, "r"))) { perror(loc); @@ -3290,116 +3262,27 @@ rerunsolver: printf("%s: no repository information\n", s->repo->name); exit(1); } - loc = solvable_get_location(s, &medianr); + loc = solvable_lookup_location(s, &medianr); if (!loc) continue; - +#if defined(ENABLE_RPMDB) if (pool->installed && pool->installed->nsolvables) { - /* try a delta first */ - char *matchname = strdup(pool_id2str(pool, s->name)); - dataiterator_init(&di, pool, s->repo, SOLVID_META, DELTA_PACKAGE_NAME, matchname, SEARCH_STRING); - dataiterator_prepend_keyname(&di, REPOSITORY_DELTAINFO); - while (dataiterator_step(&di)) + if ((newpkgsfps[i] = trydeltadownload(s, cinfo, loc)) != 0) { - Id baseevr, op; - - dataiterator_setpos_parent(&di); - if (pool_lookup_id(pool, SOLVID_POS, DELTA_PACKAGE_EVR) != s->evr || - pool_lookup_id(pool, SOLVID_POS, DELTA_PACKAGE_ARCH) != s->arch) - continue; - baseevr = pool_lookup_id(pool, SOLVID_POS, DELTA_BASE_EVR); - FOR_PROVIDES(op, pp, s->name) - { - Solvable *os = pool->solvables + op; - if (os->repo == pool->installed && os->name == s->name && os->arch == s->arch && os->evr == baseevr) - break; - } - if (op && access("/usr/bin/applydeltarpm", X_OK) == 0) - { - /* base is installed, run sequence check */ - const char *seqname; - const char *seqevr; - const char *seqnum; - const char *seq; - const char *dloc; - const char *archstr; - FILE *fp; - char cmd[128]; - int newfd; - - archstr = pool_id2str(pool, s->arch); - if (strlen(archstr) > 10 || strchr(archstr, '\'') != 0) - continue; - - seqname = pool_lookup_str(pool, SOLVID_POS, DELTA_SEQ_NAME); - seqevr = pool_lookup_str(pool, SOLVID_POS, DELTA_SEQ_EVR); - seqnum = pool_lookup_str(pool, SOLVID_POS, DELTA_SEQ_NUM); - seq = pool_tmpjoin(pool, seqname, "-", seqevr); - seq = pool_tmpappend(pool, seq, "-", seqnum); - if (strchr(seq, '\'') != 0) - continue; -#ifdef FEDORA - sprintf(cmd, "/usr/bin/applydeltarpm -a '%s' -c -s '", archstr); -#else - sprintf(cmd, "/usr/bin/applydeltarpm -c -s '"); -#endif - if (system(pool_tmpjoin(pool, cmd, seq, "'")) != 0) - continue; /* didn't match */ - /* looks good, download delta */ - chksumtype = 0; - chksum = pool_lookup_bin_checksum(pool, SOLVID_POS, DELTA_CHECKSUM, &chksumtype); - if (!chksumtype) - continue; /* no way! */ - dloc = pool_lookup_str(pool, SOLVID_POS, DELTA_LOCATION_DIR); - dloc = pool_tmpappend(pool, dloc, "/", pool_lookup_str(pool, SOLVID_POS, DELTA_LOCATION_NAME)); - dloc = pool_tmpappend(pool, dloc, "-", pool_lookup_str(pool, SOLVID_POS, DELTA_LOCATION_EVR)); - dloc = pool_tmpappend(pool, dloc, ".", pool_lookup_str(pool, SOLVID_POS, DELTA_LOCATION_SUFFIX)); - if ((fp = curlfopen(cinfo, dloc, 0, chksum, chksumtype, 0)) == 0) - continue; - /* got it, now reconstruct */ - newfd = opentmpfile(); -#ifdef FEDORA - sprintf(cmd, "applydeltarpm -a '%s' /dev/fd/%d /dev/fd/%d", archstr, fileno(fp), newfd); -#else - sprintf(cmd, "applydeltarpm /dev/fd/%d /dev/fd/%d", fileno(fp), newfd); -#endif - fcntl(fileno(fp), F_SETFD, 0); - if (system(cmd)) - { - close(newfd); - fclose(fp); - continue; - } - lseek(newfd, 0, SEEK_SET); - chksumtype = 0; - chksum = solvable_lookup_bin_checksum(s, SOLVABLE_CHECKSUM, &chksumtype); - if (chksumtype && !verify_checksum(newfd, loc, chksum, chksumtype)) - { - close(newfd); - fclose(fp); - continue; - } - newpkgsfps[i] = fdopen(newfd, "r"); - fclose(fp); - break; - } + putchar('d'); + fflush(stdout); + continue; /* delta worked! */ } - dataiterator_free(&di); - solv_free(matchname); - } - - if (newpkgsfps[i]) - { - putchar('d'); - fflush(stdout); - continue; /* delta worked! */ } +#endif +#ifdef ENABLE_SUSEREPO if (cinfo->type == TYPE_SUSETAGS) { const char *datadir = repo_lookup_str(cinfo->repo, SOLVID_META, SUSETAGS_DATADIR); loc = pool_tmpjoin(pool, datadir ? datadir : "suse", "/", loc); } +#endif chksumtype = 0; chksum = solvable_lookup_bin_checksum(s, SOLVABLE_CHECKSUM, &chksumtype); if ((newpkgsfps[i] = curlfopen(cinfo, loc, 0, chksum, chksumtype, 0)) == 0) @@ -3414,6 +3297,7 @@ rerunsolver: } #if defined(ENABLE_RPMDB) && (defined(SUSE) || defined(FEDORA)) + /* check for file conflicts */ if (newpkgs) { Queue conflicts; @@ -3421,16 +3305,17 @@ rerunsolver: printf("Searching for file conflicts\n"); queue_init(&conflicts); - fcstate.rpmdbstate = 0; + fcstate.rpmstate = rpm_state_create(pool, rootdir); fcstate.newpkgscnt = newpkgs; fcstate.checkq = &checkq; fcstate.newpkgsfps = newpkgsfps; - pool_findfileconflicts(pool, &checkq, newpkgs, &conflicts, &fileconflict_cb, &fcstate); + pool_findfileconflicts(pool, &checkq, newpkgs, &conflicts, FINDFILECONFLICTS_USE_SOLVABLEFILELIST | FINDFILECONFLICTS_CHECK_DIRALIASING | FINDFILECONFLICTS_USE_ROOTDIR, &fileconflict_cb, &fcstate); + fcstate.rpmstate = rpm_state_free(fcstate.rpmstate); if (conflicts.count) { printf("\n"); - for (i = 0; i < conflicts.count; i += 5) - printf("file %s of package %s conflicts with package %s\n", pool_id2str(pool, conflicts.elements[i]), pool_solvid2str(pool, conflicts.elements[i + 1]), pool_solvid2str(pool, conflicts.elements[i + 3])); + for (i = 0; i < conflicts.count; i += 6) + printf("file %s of package %s conflicts with package %s\n", pool_id2str(pool, conflicts.elements[i]), pool_solvid2str(pool, conflicts.elements[i + 1]), pool_solvid2str(pool, conflicts.elements[i + 4])); printf("\n"); if (yesno("Re-run solver (y/n/q)? ")) { @@ -3439,8 +3324,8 @@ rerunsolver: fclose(newpkgsfps[i]); newpkgsfps = solv_free(newpkgsfps); solver_free(solv); + solv = 0; pool_add_fileconflicts_deps(pool, &conflicts); - pool_createwhatprovides(pool); /* Hmm... */ goto rerunsolver; } } @@ -3448,6 +3333,7 @@ rerunsolver: } #endif + /* and finally commit the transaction */ printf("Committing transaction:\n\n"); transaction_order(trans, 0); for (i = 0; i < trans->steps.count; i++) @@ -3458,10 +3344,11 @@ rerunsolver: Solvable *s; int j; FILE *fp; + Id type; p = trans->steps.elements[i]; s = pool_id2solvable(pool, p); - Id type = transaction_type(trans, p, SOLVER_TRANSACTION_RPM_ONLY); + type = transaction_type(trans, p, SOLVER_TRANSACTION_RPM_ONLY); switch(type) { case SOLVER_TRANSACTION_ERASE: @@ -3477,10 +3364,10 @@ rerunsolver: evr = evrp + 1; nvra = pool_tmpjoin(pool, pool_id2str(pool, s->name), "-", evr); nvra = pool_tmpappend(pool, nvra, ".", pool_id2str(pool, s->arch)); - runrpm("-e", nvra, -1); /* too bad that --querybynumber doesn't work */ + runrpm("-e", nvra, -1, rootdir); /* too bad that --querybynumber doesn't work */ #endif #if defined(ENABLE_DEBIAN) && defined(DEBIAN) - rundpkg("--remove", pool_id2str(pool, s->name), 0); + rundpkg("--remove", pool_id2str(pool, s->name), 0, rootdir); #endif break; case SOLVER_TRANSACTION_INSTALL: @@ -3495,10 +3382,10 @@ rerunsolver: rewind(fp); lseek(fileno(fp), 0, SEEK_SET); #if defined(ENABLE_RPMDB) && (defined(SUSE) || defined(FEDORA)) - runrpm(type == SOLVER_TRANSACTION_MULTIINSTALL ? "-i" : "-U", "/dev/fd/3", fileno(fp)); + runrpm(type == SOLVER_TRANSACTION_MULTIINSTALL ? "-i" : "-U", "/dev/fd/3", fileno(fp), rootdir); #endif #if defined(ENABLE_DEBIAN) && defined(DEBIAN) - rundpkg("--install", "/dev/fd/3", fileno(fp)); + rundpkg("--install", "/dev/fd/3", fileno(fp), rootdir); #endif fclose(fp); newpkgsfps[j] = 0;