X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=examples%2Fsolv.c;h=8d3511759af493c6bfe9d4a464b204a851badf3e;hb=0254042972e8b301303ad00678e5388e7722b440;hp=1646da3dc18d70f11a9fd3290b51aef7ad814869;hpb=180a7cc50ba32c83e6a05d3560850ba228d2afcb;p=platform%2Fupstream%2Flibsolv.git diff --git a/examples/solv.c b/examples/solv.c index 1646da3..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 @@ -7,7 +7,18 @@ /* solv, a little software installer demoing the sat solver library */ -/* things available in the library but missing from solv: +/* things it does: + * - understands globs for package names / dependencies + * - understands .arch suffix + * - installation of commandline packages + * - repository data caching + * - on demand loading of secondary repository data + * - gpg and checksum verification + * - file conflicts + * - deltarpm support + * - fastestmirror implementation + * + * things available in the library but missing from solv: * - vendor policy loading * - soft locks file handling * - multi version handling @@ -28,6 +39,8 @@ #include #include #include +#include +#include #include #include @@ -44,30 +57,53 @@ #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 "repo_products.h" +#include "pool_fileconflicts.h" +#endif +#ifdef ENABLE_PUBKEY +#include "repo_pubkey.h" +#endif +#ifdef ENABLE_DEBIAN +#include "repo_deb.h" +#endif +#ifdef ENABLE_RPMMD #include "repo_rpmmd.h" -#include "repo_susetags.h" #include "repo_repomdxml.h" #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" -#include "pool_fileconflicts.h" - +#endif +#ifdef SUSE +#include "repo_autopattern.h" +#endif +#include "solv_xfopen.h" #ifdef FEDORA # define REPOINFO_PATH "/etc/yum.repos.d" -#else +#endif +#ifdef SUSE # define REPOINFO_PATH "/etc/zypp/repos.d" # 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" -#define METADATA_EXPIRE (60 * 90) +#define METADATA_EXPIRE (60 * 15) struct repoinfo { Repo *repo; @@ -86,9 +122,12 @@ struct repoinfo { int priority; int keeppackages; int metadata_expire; + char **components; + int ncomponents; unsigned char cookie[32]; unsigned char extcookie[32]; + int incomplete; }; #ifdef FEDORA @@ -101,9 +140,9 @@ yum_substitute(Pool *pool, char *line) if (!line) { - sat_free(releaseevr); + solv_free(releaseevr); releaseevr = 0; - sat_free(basearch); + solv_free(basearch); basearch = 0; return 0; } @@ -114,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); @@ -170,6 +214,7 @@ yum_substitute(Pool *pool, char *line) #define TYPE_SUSETAGS 1 #define TYPE_RPMMD 2 #define TYPE_PLAINDIR 3 +#define TYPE_DEBIAN 4 static int read_repoinfos_sort(const void *ap, const void *bp) @@ -179,9 +224,12 @@ read_repoinfos_sort(const void *ap, const void *bp) return strcmp(a->alias, b->alias); } +#if defined(SUSE) || defined(FEDORA) + struct repoinfo * -read_repoinfos(Pool *pool, const char *reposdir, int *nrepoinfosp) +read_repoinfos(Pool *pool, int *nrepoinfosp) { + const char *reposdir = REPOINFO_PATH; char buf[4096]; char buf2[4096], *kp, *vp, *kpe; DIR *dir; @@ -200,6 +248,8 @@ read_repoinfos(Pool *pool, const char *reposdir, int *nrepoinfosp) } while ((ent = readdir(dir)) != 0) { + if (ent->d_name[0] == '.') + continue; l = strlen(ent->d_name); if (l < 6 || rdlen + 2 + l >= sizeof(buf) || strcmp(ent->d_name + l - 5, ".repo") != 0) continue; @@ -232,12 +282,13 @@ read_repoinfos(Pool *pool, const char *reposdir, int *nrepoinfosp) if (!vp) continue; *vp = 0; - repoinfos = sat_extend(repoinfos, nrepoinfos, 1, sizeof(*repoinfos), 15); + repoinfos = solv_extend(repoinfos, nrepoinfos, 1, sizeof(*repoinfos), 15); cinfo = repoinfos + nrepoinfos++; memset(cinfo, 0, sizeof(*cinfo)); cinfo->alias = strdup(kp + 1); cinfo->type = TYPE_RPMMD; cinfo->autorefresh = 1; + cinfo->priority = 99; #ifndef FEDORA cinfo->repo_gpgcheck = 1; #endif @@ -307,21 +358,143 @@ read_repoinfos(Pool *pool, const char *reposdir, int *nrepoinfosp) return repoinfos; } +#endif + +#ifdef DEBIAN + +struct repoinfo * +read_repoinfos(Pool *pool, int *nrepoinfosp) +{ + FILE *fp; + char buf[4096]; + char buf2[4096]; + int l; + char *kp, *url, *distro; + struct repoinfo *repoinfos = 0, *cinfo; + int nrepoinfos = 0; + DIR *dir = 0; + struct dirent *ent; + + fp = fopen("/etc/apt/sources.list", "r"); + while (1) + { + if (!fp) + { + if (!dir) + { + dir = opendir("/etc/apt/sources.list.d"); + if (!dir) + break; + } + if ((ent = readdir(dir)) == 0) + { + closedir(dir); + break; + } + if (ent->d_name[0] == '.') + continue; + l = strlen(ent->d_name); + if (l < 5 || strcmp(ent->d_name + l - 5, ".list") != 0) + continue; + snprintf(buf, sizeof(buf), "%s/%s", "/etc/apt/sources.list.d", ent->d_name); + if (!(fp = fopen(buf, "r"))) + continue; + } + while(fgets(buf2, sizeof(buf2), fp)) + { + l = strlen(buf2); + if (l == 0) + continue; + while (l && (buf2[l - 1] == '\n' || buf2[l - 1] == ' ' || buf2[l - 1] == '\t')) + buf2[--l] = 0; + kp = buf2; + while (*kp == ' ' || *kp == '\t') + kp++; + if (!*kp || *kp == '#') + continue; + if (strncmp(kp, "deb", 3) != 0) + continue; + kp += 3; + if (*kp != ' ' && *kp != '\t') + continue; + while (*kp == ' ' || *kp == '\t') + kp++; + if (!*kp) + continue; + url = kp; + while (*kp && *kp != ' ' && *kp != '\t') + kp++; + if (*kp) + *kp++ = 0; + while (*kp == ' ' || *kp == '\t') + kp++; + if (!*kp) + continue; + distro = kp; + while (*kp && *kp != ' ' && *kp != '\t') + kp++; + if (*kp) + *kp++ = 0; + while (*kp == ' ' || *kp == '\t') + kp++; + if (!*kp) + continue; + repoinfos = solv_extend(repoinfos, nrepoinfos, 1, sizeof(*repoinfos), 15); + cinfo = repoinfos + nrepoinfos++; + memset(cinfo, 0, sizeof(*cinfo)); + cinfo->baseurl = strdup(url); + cinfo->alias = solv_dupjoin(url, "/", distro); + cinfo->name = strdup(distro); + cinfo->type = TYPE_DEBIAN; + cinfo->enabled = 1; + cinfo->autorefresh = 1; + cinfo->repo_gpgcheck = 1; + cinfo->metadata_expire = METADATA_EXPIRE; + while (*kp) + { + char *compo; + while (*kp == ' ' || *kp == '\t') + kp++; + if (!*kp) + break; + compo = kp; + while (*kp && *kp != ' ' && *kp != '\t') + kp++; + if (*kp) + *kp++ = 0; + cinfo->components = solv_extend(cinfo->components, cinfo->ncomponents, 1, sizeof(*cinfo->components), 15); + cinfo->components[cinfo->ncomponents++] = strdup(compo); + } + } + fclose(fp); + fp = 0; + } + qsort(repoinfos, nrepoinfos, sizeof(*repoinfos), read_repoinfos_sort); + *nrepoinfosp = nrepoinfos; + return repoinfos; +} + +#endif + + void free_repoinfos(struct repoinfo *repoinfos, int nrepoinfos) { - int i; + int i, j; for (i = 0; i < nrepoinfos; i++) { struct repoinfo *cinfo = repoinfos + i; - sat_free(cinfo->name); - sat_free(cinfo->alias); - sat_free(cinfo->path); - sat_free(cinfo->metalink); - sat_free(cinfo->mirrorlist); - sat_free(cinfo->baseurl); - } - sat_free(repoinfos); + solv_free(cinfo->name); + solv_free(cinfo->alias); + solv_free(cinfo->path); + solv_free(cinfo->metalink); + solv_free(cinfo->mirrorlist); + solv_free(cinfo->baseurl); + for (j = 0; j < cinfo->ncomponents; j++) + solv_free(cinfo->components[j]); + solv_free(cinfo->components); + } + solv_free(repoinfos); } static inline int @@ -345,28 +518,28 @@ static int verify_checksum(int fd, const char *file, const unsigned char *chksum, Id chksumtype) { char buf[1024]; - unsigned char *sum; - void *h; + const unsigned char *sum; + Chksum *h; int l; - h = sat_chksum_create(chksumtype); + h = solv_chksum_create(chksumtype); if (!h) { printf("%s: unknown checksum type\n", file); return 0; } while ((l = read(fd, buf, sizeof(buf))) > 0) - sat_chksum_add(h, buf, l); + solv_chksum_add(h, buf, l); lseek(fd, 0, SEEK_SET); l = 0; - sum = sat_chksum_get(h, &l); + sum = solv_chksum_get(h, &l); if (memcmp(sum, chksum, l)) { printf("%s: checksum mismatch\n", file); - sat_chksum_free(h, 0); + solv_chksum_free(h, 0); return 0; } - sat_chksum_free(h, 0); + solv_chksum_free(h, 0); return 1; } @@ -380,8 +553,8 @@ findfastest(char **urls, int nurls) char portstr[16]; struct addrinfo hints, *result;; - fds = sat_calloc(nurls, sizeof(*fds)); - socks = sat_calloc(nurls, sizeof(*socks)); + fds = solv_calloc(nurls, sizeof(*fds)); + socks = solv_calloc(nurls, sizeof(*socks)); for (i = 0; i < nurls; i++) { socks[i] = -1; @@ -521,23 +694,8 @@ findmetalinkurl(FILE *fp, unsigned char *chksump, Id *chksumtypep) bp++; if (chksumtypep && !*chksumtypep && !strncmp(bp, "", 20)) { - int i; - bp += 20; - memset(chksump, 0, 32); - for (i = 0; i < 64; i++) - { - int c = *bp++; - if (c >= '0' && c <= '9') - chksump[i / 2] = chksump[i / 2] * 16 + (c - '0'); - else if (c >= 'a' && c <= 'f') - chksump[i / 2] = chksump[i / 2] * 16 + (c - ('a' - 10)); - else if (c >= 'A' && c <= 'F') - chksump[i / 2] = chksump[i / 2] * 16 + (c - ('A' - 10)); - else - break; - } - if (i == 64) + if (solv_hex2bin((const char **)&bp, chksump, 32) == 32) *chksumtypep = REPOKEY_TYPE_SHA256; continue; } @@ -553,7 +711,7 @@ findmetalinkurl(FILE *fp, unsigned char *chksump, Id *chksumtypep) *ep = 0; if (strncmp(bp, "http", 4)) continue; - urls = sat_extend(urls, nurls, 1, sizeof(*urls), 15); + urls = solv_extend(urls, nurls, 1, sizeof(*urls), 15); urls[nurls++] = strdup(bp); } if (nurls) @@ -563,8 +721,8 @@ findmetalinkurl(FILE *fp, unsigned char *chksump, Id *chksumtypep) bp = urls[0]; urls[0] = 0; for (i = 0; i < nurls; i++) - sat_free(urls[i]); - sat_free(urls); + solv_free(urls[i]); + solv_free(urls); ep = strchr(bp, '/'); if ((ep = strchr(ep + 2, '/')) != 0) { @@ -594,7 +752,7 @@ findmirrorlisturl(FILE *fp) l = strlen(bp); while (l > 0 && (bp[l - 1] == ' ' || bp[l - 1] == '\t' || bp[l - 1] == '\n')) bp[--l] = 0; - urls = sat_extend(urls, nurls, 1, sizeof(*urls), 15); + urls = solv_extend(urls, nurls, 1, sizeof(*urls), 15); urls[nurls++] = strdup(bp); } if (nurls) @@ -604,8 +762,8 @@ findmirrorlisturl(FILE *fp) bp = urls[0]; urls[0] = 0; for (i = 0; i < nurls; i++) - sat_free(urls[i]); - sat_free(urls); + solv_free(urls[i]); + solv_free(urls); ep = strchr(bp, '/'); if ((ep = strchr(ep + 2, '/')) != 0) { @@ -618,21 +776,16 @@ findmirrorlisturl(FILE *fp) return 0; } -static ssize_t -cookie_gzread(void *cookie, char *buf, size_t nbytes) -{ - return gzread((gzFile *)cookie, buf, nbytes); -} - -static int -cookie_gzclose(void *cookie) +static inline int +iscompressed(const char *name) { - return gzclose((gzFile *)cookie); + 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; @@ -645,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) @@ -670,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); } @@ -713,41 +867,40 @@ 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; } + fcntl(fd, F_SETFD, FD_CLOEXEC); if (uncompress) { - char tmpl[100]; - cookie_io_functions_t cio; - gzFile *gzf; - - sprintf(tmpl, "/dev/fd/%d", fd); - gzf = gzopen(tmpl, "r"); - close(fd); - if (!gzf) + if (solv_xfopen_iscompressed(file) < 0) { - fprintf(stderr, "could not open /dev/fd/%d, /proc not mounted?\n", fd); - exit(1); + printf("%s: unsupported compression\n", file); + if (markincomplete) + cinfo->incomplete = 1; + close(fd); + return 0; } - memset(&cio, 0, sizeof(cio)); - cio.read = cookie_gzread; - cio.close = cookie_gzclose; - return fopencookie(gzf, "r", cio); + fp = solv_xfopen_fd(file, fd, "r"); } - fcntl(fd, F_SETFD, FD_CLOEXEC); - return fdopen(fd, "r"); + else + fp = fdopen(fd, "r"); + if (!fp) + close(fd); + return fp; } +#ifndef DEBIAN + static void cleanupgpg(char *gpgdir) { @@ -818,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); @@ -830,32 +983,86 @@ checksig(Pool *sigpool, FILE *fp, FILE *sigfp) return r == 0 ? 1 : 0; } +#else + +static int +checksig(Pool *sigpool, FILE *fp, FILE *sigfp) +{ + char cmd[256]; + int r; + + snprintf(cmd, sizeof(cmd), "gpgv -q --keyring /etc/apt/trusted.gpg /dev/fd/%d /dev/fd/%d >/dev/null 2>&1", fileno(sigfp), fileno(fp)); + fcntl(fileno(fp), F_SETFD, 0); /* clear CLOEXEC */ + fcntl(fileno(sigfp), F_SETFD, 0); /* clear CLOEXEC */ + r = system(cmd); + fcntl(fileno(fp), F_SETFD, FD_CLOEXEC); + fcntl(fileno(sigfp), F_SETFD, FD_CLOEXEC); + return r == 0 ? 1 : 0; +} + +#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 = sat_chksum_create(chktype); + Chksum *h = solv_chksum_create(chktype); int l; - sat_chksum_add(h, CHKSUM_IDENT, strlen(CHKSUM_IDENT)); + solv_chksum_add(h, CHKSUM_IDENT, strlen(CHKSUM_IDENT)); while ((l = fread(buf, 1, sizeof(buf), fp)) > 0) - sat_chksum_add(h, buf, l); + solv_chksum_add(h, buf, l); rewind(fp); - sat_chksum_free(h, out); + solv_chksum_free(h, 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 = sat_chksum_create(chktype); - sat_chksum_add(h, CHKSUM_IDENT, strlen(CHKSUM_IDENT)); - sat_chksum_add(h, &stb->st_dev, sizeof(stb->st_dev)); - sat_chksum_add(h, &stb->st_ino, sizeof(stb->st_ino)); - sat_chksum_add(h, &stb->st_size, sizeof(stb->st_size)); - sat_chksum_add(h, &stb->st_mtime, sizeof(stb->st_mtime)); - sat_chksum_free(h, out); + 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)); + solv_chksum_add(h, &stb->st_mtime, sizeof(stb->st_mtime)); + solv_chksum_free(h, out); } void @@ -870,17 +1077,27 @@ 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_tmpjoin(repo->pool, p, "_", repoext); - p = pool_tmpjoin(repo->pool, p, ".solvx", 0); + p = pool_tmpappend(repo->pool, p, "_", repoext); + p = pool_tmpappend(repo->pool, p, ".solvx", 0); } else - p = pool_tmpjoin(repo->pool, p, ".solv", 0); - q = p + strlen(SOLVCACHE_PATH) + 1; + p = pool_tmpappend(repo->pool, p, ".solv", 0); + q = p + l; if (*q == '.') *q = '_'; for (; *q; q++) @@ -897,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) { @@ -923,11 +1150,13 @@ usecachedrepo(Repo *repo, const char *repoext, unsigned char *cookie, int mark) flags = 0; if (repoext) - flags = REPO_USE_LOADING|REPO_EXTEND_SOLVABLES; - if (repoext && strcmp(repoext, "DL") != 0) - flags |= REPO_LOCALPOOL; /* no local pool for DL so that we can compare IDs */ + { + flags = REPO_USE_LOADING|REPO_EXTEND_SOLVABLES; + if (strcmp(repoext, "DL") != 0) + flags |= REPO_LOCALPOOL; /* no local pool for DL so that we can compare IDs */ + } - if (repo_add_solv_flags(repo, fp, flags)) + if (repo_add_solv(repo, fp, flags)) { fclose(fp); return 0; @@ -938,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; } @@ -948,13 +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); - tmpl = sat_dupjoin(SOLVCACHE_PATH, "/", ".newsolv-XXXXXX"); + 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(cachedir, "/", ".newsolv-XXXXXX"); fd = mkstemp(tmpl); if (fd < 0) { @@ -978,14 +1212,14 @@ writecachedrepo(Repo *repo, Repodata *info, const char *repoext, unsigned char * onepiece = 0; if (!info) - repo_write(repo, fp, repo_write_stdkeyfilter, 0, 0); + repo_write(repo, fp); else if (repoext) - repodata_write(info, fp, repo_write_stdkeyfilter, 0); + repodata_write(info, fp); else { int oldnrepodata = repo->nrepodata; - repo->nrepodata = 1; /* XXX: do this right */ - repo_write(repo, fp, repo_write_stdkeyfilter, 0, 0); + repo->nrepodata = oldnrepodata > 2 ? 2 : oldnrepodata; /* XXX: do this right */ + repo_write(repo, fp); repo->nrepodata = oldnrepodata; onepiece = 0; } @@ -998,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; } @@ -1040,7 +1269,7 @@ writecachedrepo(Repo *repo, Repodata *info, const char *repoext, unsigned char * { /* main repo */ repo_empty(repo, 1); - if (repo_add_solv_flags(repo, fp, SOLV_ADD_NO_STUBS)) + if (repo_add_solv(repo, fp, SOLV_ADD_NO_STUBS)) { /* oops, no way to recover from here */ fprintf(stderr, "internal error\n"); @@ -1049,33 +1278,26 @@ 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_flags(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(); - Repo *repo = repo_create(sigpool, "rpmdbkeys"); - repo_add_rpmdb_pubkeys(repo, 0, 0); - return sigpool; -} - - +#ifdef ENABLE_RPMMD /* repomd helpers */ static inline const char * @@ -1108,34 +1330,19 @@ repomd_find(Repo *repo, const char *what, const unsigned char **chksump, Id *chk int repomd_add_ext(Repo *repo, Repodata *data, const char *what) { - Pool *pool = repo->pool; - Dataiterator di; Id chksumtype, handle; const unsigned char *chksum; const char *filename; - dataiterator_init(&di, pool, repo, SOLVID_META, REPOSITORY_REPOMD_TYPE, what, SEARCH_STRING); - dataiterator_prepend_keyname(&di, REPOSITORY_REPOMD); - if (!dataiterator_step(&di)) - { - dataiterator_free(&di); - return 0; - } + filename = repomd_find(repo, what, &chksum, &chksumtype); + if (!filename) + return 0; if (!strcmp(what, "prestodelta")) what = "deltainfo"; - dataiterator_setpos_parent(&di); - filename = pool_lookup_str(pool, SOLVID_POS, REPOSITORY_REPOMD_LOCATION); - chksum = pool_lookup_bin_checksum(pool, SOLVID_POS, REPOSITORY_REPOMD_CHECKSUM, &chksumtype); - if (!filename || !chksum) - { - dataiterator_free(&di); - return 0; - } handle = repodata_new_handle(data); repodata_set_poolstr(data, handle, REPOSITORY_REPOMD_TYPE, what); repodata_set_str(data, handle, REPOSITORY_REPOMD_LOCATION, filename); - if (chksumtype) - repodata_set_bin_checksum(data, handle, REPOSITORY_REPOMD_CHECKSUM, chksumtype, chksum); + repodata_set_bin_checksum(data, handle, REPOSITORY_REPOMD_CHECKSUM, chksumtype, chksum); if (!strcmp(what, "deltainfo")) { repodata_add_idarray(data, handle, REPOSITORY_KEYS, REPOSITORY_DELTAINFO); @@ -1146,12 +1353,61 @@ repomd_add_ext(Repo *repo, Repodata *data, const char *what) repodata_add_idarray(data, handle, REPOSITORY_KEYS, SOLVABLE_FILELIST); repodata_add_idarray(data, handle, REPOSITORY_KEYS, REPOKEY_TYPE_DIRSTRARRAY); } - dataiterator_free(&di); repodata_add_flexarray(data, SOLVID_META, REPOSITORY_EXTERNAL, handle); return 1; } +int +repomd_load_ext(Repo *repo, Repodata *data) +{ + const char *filename, *repomdtype; + char ext[3]; + FILE *fp; + struct repoinfo *cinfo; + const unsigned char *filechksum; + Id filechksumtype; + int r = 0; + + cinfo = repo->appdata; + repomdtype = repodata_lookup_str(data, SOLVID_META, REPOSITORY_REPOMD_TYPE); + if (!repomdtype) + return 0; + if (!strcmp(repomdtype, "filelists")) + strcpy(ext, "FL"); + else if (!strcmp(repomdtype, "deltainfo")) + strcpy(ext, "DL"); + else + return 0; + printf("[%s:%s", repo->name, ext); + if (usecachedrepo(repo, ext, cinfo->extcookie, 0)) + { + printf(" cached]\n"); fflush(stdout); + return 1; + } + printf(" fetching]\n"); fflush(stdout); + filename = repodata_lookup_str(data, SOLVID_META, REPOSITORY_REPOMD_LOCATION); + filechksumtype = 0; + filechksum = repodata_lookup_bin_checksum(data, SOLVID_META, REPOSITORY_REPOMD_CHECKSUM, &filechksumtype); + 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|REPO_LOCALPOOL); + else if (!strcmp(ext, "DL")) + r = repo_add_deltainfoxml(repo, fp, REPO_USE_LOADING); + fclose(fp); + if (r) + { + printf("%s\n", pool_errstr(repo->pool)); + return 0; + } + writecachedrepo(repo, data, ext, cinfo->extcookie); + return 1; +} + +#endif + +#ifdef ENABLE_SUSEREPO /* susetags helpers */ static inline const char * @@ -1207,11 +1463,15 @@ susetags_add_ext(Repo *repo, Repodata *data) { if (strncmp(di.kv.str, "packages.", 9) != 0) continue; + if (!strcmp(di.kv.str + 9, "gz")) + continue; if (!di.kv.str[9] || !di.kv.str[10] || (di.kv.str[11] && di.kv.str[11] != '.')) continue; ext[0] = di.kv.str[9]; ext[1] = di.kv.str[10]; ext[2] = 0; + if (!strcmp(ext, "en")) + continue; if (!susetags_find(repo, di.kv.str, &filechksum, &filechksumtype)) continue; handle = repodata_new_handle(data); @@ -1223,7 +1483,7 @@ susetags_add_ext(Repo *repo, Repodata *data) repodata_add_idarray(data, handle, REPOSITORY_KEYS, SOLVABLE_DISKUSAGE); repodata_add_idarray(data, handle, REPOSITORY_KEYS, REPOKEY_TYPE_DIRNUMNUMARRAY); } - if (!strcmp(ext, "FL")) + else if (!strcmp(ext, "FL")) { repodata_add_idarray(data, handle, REPOSITORY_KEYS, SOLVABLE_FILELIST); repodata_add_idarray(data, handle, REPOSITORY_KEYS, REPOKEY_TYPE_DIRSTRARRAY); @@ -1241,13 +1501,56 @@ susetags_add_ext(Repo *repo, Repodata *data) dataiterator_free(&di); } - -static inline int -iscompressed(const char *name) +int +susetags_load_ext(Repo *repo, Repodata *data) { - int l = strlen(name); - return l > 3 && !strcmp(name + l - 3, ".gz") ? 1 : 0; + const char *filename, *descrdir; + Id defvendor; + char ext[3]; + FILE *fp; + struct repoinfo *cinfo; + const unsigned char *filechksum; + Id filechksumtype; + int flags; + + cinfo = repo->appdata; + filename = repodata_lookup_str(data, SOLVID_META, SUSETAGS_FILE_NAME); + if (!filename) + return 0; + /* susetags load */ + ext[0] = filename[9]; + ext[1] = filename[10]; + ext[2] = 0; + printf("[%s:%s", repo->name, ext); + if (usecachedrepo(repo, ext, cinfo->extcookie, 0)) + { + printf(" cached]\n"); fflush(stdout); + return 1; + } + printf(" fetching]\n"); fflush(stdout); + defvendor = repo_lookup_id(repo, SOLVID_META, SUSETAGS_DEFAULTVENDOR); + descrdir = repo_lookup_str(repo, SOLVID_META, SUSETAGS_DESCRDIR); + if (!descrdir) + descrdir = "suse/setup/descr"; + filechksumtype = 0; + 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; + 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)); + return 0; + } + fclose(fp); + writecachedrepo(repo, data, ext, cinfo->extcookie); + return 1; } +#endif + /* load callback */ @@ -1255,84 +1558,143 @@ iscompressed(const char *name) int load_stub(Pool *pool, Repodata *data, void *dp) { - const char *filename, *descrdir, *repomdtype; - const unsigned char *filechksum; - Id filechksumtype; - struct repoinfo *cinfo; - FILE *fp; - Id defvendor; - char ext[3]; - - cinfo = data->repo->appdata; - - filename = repodata_lookup_str(data, SOLVID_META, SUSETAGS_FILE_NAME); - if (filename) + struct repoinfo *cinfo = data->repo->appdata; + switch (cinfo->type) { - /* susetags load */ - ext[0] = filename[9]; - ext[1] = filename[10]; - ext[2] = 0; -#if 1 - printf("[%s:%s", data->repo->name, ext); +#ifdef ENABLE_SUSEREPO + case TYPE_SUSETAGS: + return susetags_load_ext(data->repo, data); #endif - if (usecachedrepo(data->repo, ext, cinfo->extcookie, 0)) - { - printf(" cached]\n"); fflush(stdout); - return 1; - } -#if 1 - printf(" fetching]\n"); fflush(stdout); -#endif - defvendor = repo_lookup_id(data->repo, SOLVID_META, SUSETAGS_DEFAULTVENDOR); - descrdir = repo_lookup_str(data->repo, SOLVID_META, SUSETAGS_DESCRDIR); - if (!descrdir) - descrdir = "suse/setup/descr"; - filechksumtype = 0; - filechksum = repodata_lookup_bin_checksum(data, SOLVID_META, SUSETAGS_FILE_CHECKSUM, &filechksumtype); - if ((fp = curlfopen(cinfo, pool_tmpjoin(pool, descrdir, "/", filename), iscompressed(filename), filechksum, filechksumtype, 0)) == 0) - return 0; - repo_add_susetags(data->repo, fp, defvendor, ext, REPO_USE_LOADING|REPO_EXTEND_SOLVABLES); - fclose(fp); - writecachedrepo(data->repo, data, ext, cinfo->extcookie); - return 1; +#ifdef ENABLE_RPMMD + case TYPE_RPMMD: + return repomd_load_ext(data->repo, data); +#endif + default: + return 0; } +} - repomdtype = repodata_lookup_str(data, SOLVID_META, REPOSITORY_REPOMD_TYPE); - if (repomdtype) +static unsigned char installedcookie[32]; + +#ifdef ENABLE_DEBIAN + +const char * +debian_find_component(struct repoinfo *cinfo, FILE *fp, char *comp, const unsigned char **chksump, Id *chksumtypep) +{ + char buf[4096]; + Id chksumtype; + unsigned char *chksum; + Id curchksumtype; + int l, compl; + char *ch, *fn, *bp; + char *filename; + static char *basearch; + char *binarydir; + int lbinarydir; + + if (!basearch) { - if (!strcmp(repomdtype, "filelists")) - strcpy(ext, "FL"); - else if (!strcmp(repomdtype, "deltainfo")) - strcpy(ext, "DL"); - else - return 0; -#if 1 - printf("[%s:%s", data->repo->name, ext); -#endif - if (usecachedrepo(data->repo, ext, cinfo->extcookie, 0)) + struct utsname un; + if (uname(&un)) { - printf(" cached]\n");fflush(stdout); - return 1; + perror("uname"); + exit(1); } - printf(" fetching]\n"); fflush(stdout); - filename = repodata_lookup_str(data, SOLVID_META, REPOSITORY_REPOMD_LOCATION); - filechksumtype = 0; - filechksum = repodata_lookup_bin_checksum(data, SOLVID_META, REPOSITORY_REPOMD_CHECKSUM, &filechksumtype); - if ((fp = curlfopen(cinfo, filename, iscompressed(filename), filechksum, filechksumtype, 0)) == 0) - return 0; - if (!strcmp(ext, "FL")) - repo_add_rpmmd(data->repo, fp, ext, REPO_USE_LOADING|REPO_EXTEND_SOLVABLES); - else if (!strcmp(ext, "DL")) - repo_add_deltainfoxml(data->repo, fp, REPO_USE_LOADING); - fclose(fp); - writecachedrepo(data->repo, data, ext, cinfo->extcookie); - return 1; + basearch = strdup(un.machine); + if (basearch[0] == 'i' && basearch[1] && !strcmp(basearch + 2, "86")) + basearch[1] = '3'; } - - return 0; + binarydir = solv_dupjoin("binary-", basearch, "/"); + lbinarydir = strlen(binarydir); + compl = strlen(comp); + rewind(fp); + curchksumtype = 0; + filename = 0; + chksum = solv_malloc(32); + chksumtype = 0; + while(fgets(buf, sizeof(buf), fp)) + { + l = strlen(buf); + if (l == 0) + continue; + while (l && (buf[l - 1] == '\n' || buf[l - 1] == ' ' || buf[l - 1] == '\t')) + buf[--l] = 0; + if (!strncasecmp(buf, "MD5Sum:", 7)) + { + curchksumtype = REPOKEY_TYPE_MD5; + continue; + } + if (!strncasecmp(buf, "SHA1:", 5)) + { + curchksumtype = REPOKEY_TYPE_SHA1; + continue; + } + if (!strncasecmp(buf, "SHA256:", 7)) + { + curchksumtype = REPOKEY_TYPE_SHA256; + continue; + } + if (!curchksumtype) + continue; + bp = buf; + if (*bp++ != ' ') + { + curchksumtype = 0; + continue; + } + ch = bp; + while (*bp && *bp != ' ' && *bp != '\t') + bp++; + if (!*bp) + continue; + *bp++ = 0; + while (*bp == ' ' || *bp == '\t') + bp++; + while (*bp && *bp != ' ' && *bp != '\t') + bp++; + if (!*bp) + continue; + while (*bp == ' ' || *bp == '\t') + bp++; + fn = bp; + if (strncmp(fn, comp, compl) != 0 || fn[compl] != '/') + continue; + bp += compl + 1; + if (strncmp(bp, binarydir, lbinarydir)) + continue; + bp += lbinarydir; + if (!strcmp(bp, "Packages") || !strcmp(bp, "Packages.gz")) + { + unsigned char curchksum[32]; + int curl; + if (filename && !strcmp(bp, "Packages")) + continue; + curl = solv_chksum_len(curchksumtype); + if (!curl || (chksumtype && solv_chksum_len(chksumtype) > curl)) + continue; + if (solv_hex2bin((const char **)&ch, curchksum, sizeof(curchksum)) != curl) + continue; + solv_free(filename); + filename = strdup(fn); + chksumtype = curchksumtype; + memcpy(chksum, curchksum, curl); + } + } + free(binarydir); + if (filename) + { + fn = solv_dupjoin("/", filename, 0); + solv_free(filename); + filename = solv_dupjoin("dists/", cinfo->name, fn); + solv_free(fn); + } + if (!chksumtype) + chksum = solv_free(chksum); + *chksump = chksum; + *chksumtypep = chksumtype; + return filename; } - -static unsigned char installedcookie[32]; +#endif void read_repos(Pool *pool, struct repoinfo *repoinfos, int nrepoinfos) @@ -1341,47 +1703,78 @@ 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; +#ifdef ENABLE_SUSEREPO const char *descrdir; int defvendor; +#endif struct stat stb; Pool *sigpool = 0; +#if defined(ENABLE_SUSEREPO) || defined(ENABLE_RPMMD) Repodata *data; - int badchecksum; +#endif int dorefresh; +#if defined(ENABLE_DEBIAN) + FILE *fpr; + int j; +#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)); - calc_checksum_stat(&stb, REPOKEY_TYPE_SHA256, installedcookie); + 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(pool_prepend_rootdir_tmp(pool, "/var/lib/dpkg/status"), &stb)) + memset(&stb, 0, sizeof(stb)); +#endif + calc_checksum_stat(&stb, REPOKEY_TYPE_SHA256, 0, installedcookie); if (usecachedrepo(repo, 0, installedcookie, 0)) printf(" cached\n"); else { - FILE *ofp; +#if defined(ENABLE_RPMDB) && (defined(SUSE) || defined(FEDORA)) + FILE *ofp = 0; +#endif printf(" reading\n"); - int done = 0; -#ifdef PRODUCTS_PATH - repo_add_products(repo, PRODUCTS_PATH, 0, REPO_NO_INTERNALIZE); +#if defined(ENABLE_RPMDB) && (defined(SUSE) || defined(FEDORA)) +# if defined(ENABLE_SUSEREPO) && defined(PRODUCTS_PATH) + 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 defined(ENABLE_APPDATA) + if (repo_add_appdata_dir(repo, APPDATA_PATH, REPO_REUSE_REPODATA | REPO_NO_INTERNALIZE | REPO_USE_ROOTDIR)) + { + fprintf(stderr, "appdata reading failed: %s\n", pool_errstr(pool)); + exit(1); + } +# endif + ofp = fopen(calccachepath(repo, 0, 0), "r"); + if (repo_add_rpmdb_reffp(repo, ofp, REPO_REUSE_REPODATA | REPO_NO_INTERNALIZE | REPO_USE_ROOTDIR)) + { + fprintf(stderr, "installed db: %s\n", pool_errstr(pool)); + exit(1); + } + if (ofp) + fclose(ofp); #endif - if ((ofp = fopen(calccachepath(repo, 0), "r")) != 0) +#if defined(ENABLE_DEBIAN) && defined(DEBIAN) + if (repo_add_debdb(repo, REPO_REUSE_REPODATA | REPO_NO_INTERNALIZE | REPO_USE_ROOTDIR)) { - Repo *ref = repo_create(pool, "@System.old"); - if (!repo_add_solv(ref, ofp)) - { - repo_add_rpmdb(repo, ref, 0, REPO_REUSE_REPODATA); - done = 1; - } - fclose(ofp); - repo_free(ref, 1); + fprintf(stderr, "installed db: %s\n", pool_errstr(pool)); + exit(1); } - if (!done) - repo_add_rpmdb(repo, 0, 0, REPO_REUSE_REPODATA); +#endif + repo_internalize(repo); writecachedrepo(repo, 0, 0, installedcookie); } pool_set_installed(pool, repo); @@ -1398,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; @@ -1409,9 +1802,9 @@ read_repos(Pool *pool, struct repoinfo *repoinfos, int nrepoinfos) printf(" cached\n"); continue; } - badchecksum = 0; switch (cinfo->type) { +#ifdef ENABLE_RPMMD case TYPE_RPMMD: printf("rpmmd repo '%s':", cinfo->alias); fflush(stdout); @@ -1429,55 +1822,67 @@ 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)) + { + printf("repomd.xml: %s\n", pool_errstr(pool)); + fclose(fp); + break; /* hopeless */ } - repo_add_repomdxml(repo, fp, 0); 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) { - repo_add_rpmmd(repo, fp, 0, 0); + if (repo_add_rpmmd(repo, fp, 0, 0)) + { + printf("primary: %s\n", pool_errstr(pool)); + 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) { - repo_add_updateinfoxml(repo, fp, 0); + if (repo_add_updateinfoxml(repo, fp, 0)) + { + printf("updateinfo: %s\n", pool_errstr(pool)); + 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; +#endif +#ifdef ENABLE_SUSEREPO case TYPE_SUSETAGS: printf("susetags repo '%s':", cinfo->alias); fflush(stdout); @@ -1497,30 +1902,17 @@ 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)) + { + printf("content: %s\n", pool_errstr(pool)); + fclose(fp); + break; /* hopeless */ } - repo_add_content(repo, fp, 0); fclose(fp); defvendor = repo_lookup_id(repo, SOLVID_META, SUSETAGS_DEFAULTVENDOR); descrdir = repo_lookup_str(repo, SOLVID_META, SUSETAGS_DESCRDIR); @@ -1535,346 +1927,153 @@ 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 */ - repo_add_susetags(repo, fp, defvendor, 0, 0); - fclose(fp); - data = repo_add_repodata(repo, 0); - susetags_add_ext(repo, data); - repodata_internalize(data); - if (!badchecksum) - writecachedrepo(repo, 0, 0, cinfo->cookie); - repodata_create_stubs(repo_last_repodata(repo)); - break; - default: - printf("unsupported repo '%s': skipped\n", cinfo->alias); - repo_free(repo, 1); - cinfo->repo = 0; - break; - } - } - if (sigpool) - pool_free(sigpool); -} - - -int -str2archid(Pool *pool, char *arch) -{ - Id id; - if (!*arch) - return 0; - id = 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; -} - -int -depglob(Pool *pool, char *name, Queue *job) -{ - Id p, pp; - Id id = str2id(pool, name, 0); - int i, match = 0; - - if (id) - { - FOR_PROVIDES(p, pp, id) - { - Solvable *s = pool->solvables + p; - match = 1; - if (s->name == id) - { - queue_push2(job, SOLVER_SOLVABLE_NAME, id); - return 1; - } - } - if (match) - { - printf("[using capability match for '%s']\n", name); - queue_push2(job, SOLVER_SOLVABLE_PROVIDES, id); - return 1; - } - } - - if (strpbrk(name, "[*?") == 0) - return 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, 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; - /* looks like a dep glob. really hard work. */ - for (id = 1; id < pool->ss.nstrings; id++) - { - if (!pool->whatprovides[id]) - continue; - if (fnmatch(name, id2str(pool, id), 0) == 0) - { - if (!match) - 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; - return 0; -} - -void -addrelation(Pool *pool, Queue *job, int flags, Id evr) -{ - int i; - for (i = 0; i < job->count; i += 2) - { - if (job->elements[i] != SOLVER_SOLVABLE_NAME && job->elements[i] != SOLVER_SOLVABLE_PROVIDES) - continue; - job->elements[i + 1] = rel2id(pool, job->elements[i + 1], evr, flags, 1); - } -} - -int -limitevr(Pool *pool, char *evr, Queue *job, Id archid) -{ - Queue mq; - Id p, pp, evrid; - int matched = 0; - int i, j; - Solvable *s; - const char *sevr; - - queue_init(&mq); - for (i = 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 (archid && s->arch != archid) - continue; - sevr = id2str(pool, s->evr); - if (!strchr(evr, ':') && strchr(sevr, ':')) - sevr = strchr(sevr, ':') + 1; - if (evrcmp_str(pool, sevr, evr, EVRCMP_MATCH) == 0) - queue_push(&mq, p); - } - if (mq.count) - { - if (!matched && i) - { - queue_deleten(job, 0, i); - i = 0; - } - matched = 1; - /* if all solvables have the same evr */ - s = pool_id2solvable(pool, mq.elements[0]); - evrid = s->evr; - for (j = 0; j < mq.count; j++) + if (repo_add_susetags(repo, fp, defvendor, 0, REPO_NO_INTERNALIZE|SUSETAGS_RECORD_SHARES)) { - s = pool_id2solvable(pool, mq.elements[j]); - if (s->evr != evrid) - break; - } - if (j == mq.count && j > 1) - { - prune_to_best_arch(pool, &mq); - // prune_to_highest_prio(pool, &mq); - mq.count = 1; + printf("packages: %s\n", pool_errstr(pool)); + fclose(fp); + cinfo->incomplete = 1; + break; /* hopeless */ } - if (mq.count > 1) + fclose(fp); + /* add default language */ + filename = susetags_find(repo, "packages.en.gz", &filechksum, &filechksumtype); + if (!filename) + filename = susetags_find(repo, "packages.en", &filechksum, &filechksumtype); + if (filename) { - job->elements[i] = SOLVER_SOLVABLE_ONE_OF; - job->elements[i + 1] = pool_queuetowhatprovides(pool, &mq); + 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)); + cinfo->incomplete = 1; + } + fclose(fp); + } } - else + filename = susetags_find(repo, "patterns", &filechksum, &filechksumtype); + if (filename) { - job->elements[i] = SOLVER_SOLVABLE; - job->elements[i + 1] = mq.elements[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)) + { + int l = strlen(pbuf); + FILE *fp2; + if (l && pbuf[l - 1] == '\n') + pbuf[--l] = 0; + 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, 1)) != 0) + { + if (repo_add_susetags(repo, fp2, defvendor, 0, REPO_NO_INTERNALIZE)) + { + printf("%s: %s\n", pbuf, pool_errstr(pool)); + cinfo->incomplete = 1; + } + fclose(fp2); + } + } + fclose(fp); + } } - } - else if (matched) - { - queue_deleten(job, i, 2); - i -= 2; - } - } - queue_free(&mq); - if (matched) - return 1; - if (!archid) - { - char *r; - if ((r = strrchr(evr, '.')) != 0 && r[1] && (archid = str2archid(pool, r + 1)) != 0) - { - *r = 0; - if (limitevr(pool, evr, job, archid)) +#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) { - *r = '.'; - return 1; + if (repo_add_appdata(repo, fp, 0)) + { + printf("appdata: %s\n", pool_errstr(pool)); + cinfo->incomplete = 1; + } + fclose(fp); } - *r = '.'; - } - } - return 0; -} - -void -mkselect(Pool *pool, int mode, char *name, Queue *job) -{ - char *r, *r2; - Id archid; - - if (*name == '/') - { - Dataiterator di; - Queue q; - int match = 0; +#endif + repo_internalize(repo); + data = repo_add_repodata(repo, 0); + susetags_add_ext(repo, data); + repodata_internalize(data); + if (!cinfo->incomplete) + writecachedrepo(repo, 0, 0, cinfo->cookie); + repodata_create_stubs(repo_last_repodata(repo)); + break; +#endif - queue_init(&q); - dataiterator_init(&di, pool, mode == SOLVER_ERASE ? pool->installed : 0, 0, SOLVABLE_FILELIST, name, SEARCH_STRING|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); - match = 1; - if (q.count > 1) - queue_push2(job, SOLVER_SOLVABLE_ONE_OF, pool_queuetowhatprovides(pool, &q)); - else - queue_push2(job, SOLVER_SOLVABLE, q.elements[0]); - } - queue_free(&q); - if (match) - return; - } - if ((r = strpbrk(name, "<=>")) != 0) - { - /* relation case, support: - * depglob rel - * depglob.rpm rel - */ - int rflags = 0; - int nend = r - name; - 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--; - name[nend] = 0; - if (!*name || !*r) - { - fprintf(stderr, "bad relation\n"); - exit(1); - } - if (depglob(pool, name, job)) - { - addrelation(pool, job, rflags, str2id(pool, r, 1)); - return; - } - if ((r2 = strrchr(name, '.')) != 0 && r2[1] && (archid = str2archid(pool, r2 + 1)) != 0) - { - *r2 = 0; - if (depglob(pool, name, job)) +#if defined(ENABLE_DEBIAN) + case TYPE_DEBIAN: + printf("debian repo '%s':", cinfo->alias); + fflush(stdout); + filename = solv_dupjoin("dists/", cinfo->name, "/Release"); + if ((fpr = curlfopen(cinfo, filename, 0, 0, 0, 0)) == 0) { - *r2 = '.'; - addrelation(pool, job, REL_ARCH, archid); - addrelation(pool, job, rflags, str2id(pool, r, 1)); - return; + printf(" no Release file, skipped\n"); + repo_free(repo, 1); + cinfo->repo = 0; + free((char *)filename); + break; } - *r2 = '.'; - } - } - else - { - /* no relation case, support: - * depglob - * depglob.arch - * depglob-version-release - * depglob-version-release.arch - */ - if (depglob(pool, name, job)) - return; - archid = 0; - if ((r = strrchr(name, '.')) != 0 && r[1] && (archid = str2archid(pool, r + 1)) != 0) - { - *r = 0; - if (depglob(pool, name, job)) + solv_free((char *)filename); + if (cinfo->repo_gpgcheck) { - *r = '.'; - addrelation(pool, job, REL_ARCH, archid); - return; + filename = solv_dupjoin("dists/", cinfo->name, "/Release.gpg"); + if (!downloadchecksig(cinfo, fpr, filename, &sigpool)) + { + fclose(fpr); + solv_free((char *)filename); + break; + } + solv_free((char *)filename); } - *r = '.'; - } - if ((r = strrchr(name, '-')) != 0) - { - *r = 0; - if (depglob(pool, name, job)) + calc_checksum_fp(fpr, REPOKEY_TYPE_SHA256, cinfo->cookie); + if (usecachedrepo(repo, 0, cinfo->cookie, 1)) { - /* have just the version */ - *r = '-'; - if (limitevr(pool, r + 1, job, 0)) - return; + printf(" cached\n"); + fclose(fpr); + break; } - if ((r2 = strrchr(name, '-')) != 0) + printf(" fetching\n"); + for (j = 0; j < cinfo->ncomponents; j++) { - *r = '-'; - *r2 = 0; - if (depglob(pool, name, job)) + if (!(filename = debian_find_component(cinfo, fpr, cinfo->components[j], &filechksum, &filechksumtype))) { - *r2 = '-'; - if (limitevr(pool, r2 + 1, job, 0)) - return; + printf("[component %s not found]\n", cinfo->components[j]); + continue; } - *r2 = '-'; + 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)); + cinfo->incomplete = 1; + } + fclose(fp); + } + solv_free((char *)filechksum); + solv_free((char *)filename); } - *r = '-'; + fclose(fpr); + if (!cinfo->incomplete) + writecachedrepo(repo, 0, 0, cinfo->cookie); + break; +#endif + + default: + printf("unsupported repo '%s': skipped\n", cinfo->alias); + repo_free(repo, 1); + cinfo->repo = 0; + break; } } - fprintf(stderr, "nothing matches '%s'\n", name); - exit(1); + if (sigpool) + pool_free(sigpool); } - int yesno(const char *str) { @@ -1902,11 +2101,13 @@ yesno(const char *str) } } +#if defined(ENABLE_RPMDB) && (defined(SUSE) || defined(FEDORA)) + struct fcstate { FILE **newpkgsfps; Queue *checkq; int newpkgscnt; - void *rpmdbstate; + void *rpmstate; }; static void * @@ -1918,11 +2119,6 @@ fileconflict_cb(Pool *pool, Id p, void *cbdata) 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) { @@ -1931,7 +2127,7 @@ fileconflict_cb(Pool *pool, Id p, void *cbdata) rpmdbid = s->repo->rpmdbid[p - s->repo->start]; if (!rpmdbid) return 0; - return rpm_byrpmdbid(rpmdbid, 0, &fcstate->rpmdbstate); + return rpm_byrpmdbid(fcstate->rpmstate, rpmdbid); } for (i = 0; i < fcstate->newpkgscnt; i++) if (fcstate->checkq->elements[i] == p) @@ -1942,11 +2138,12 @@ fileconflict_cb(Pool *pool, Id p, void *cbdata) if (!fp) return 0; rewind(fp); - return rpm_byfp(fp, solvable2str(pool, s), &fcstate->rpmdbstate); + return rpm_byfp(fcstate->rpmstate, fp, pool_solvable2str(pool, s)); } + void -runrpm(const char *arg, const char *name, int dupfd3) +runrpm(const char *arg, const char *name, int dupfd3, const char *rootdir) { pid_t pid; int status; @@ -1958,6 +2155,8 @@ runrpm(const char *arg, const char *name, int dupfd3) } if (pid == 0) { + if (!rootdir) + rootdir = "/"; if (dupfd3 != -1 && dupfd3 != 3) { dup2(dupfd3, 3); @@ -1966,9 +2165,9 @@ runrpm(const char *arg, const char *name, int 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); + execlp("rpm", "rpm", arg, "--nodeps", "--nodigest", "--nosignature", "--root", rootdir, name, (char *)0); else - execlp("rpm", "rpm", arg, "--force", "--nodeps", "--nodigest", "--nosignature", name, (char *)0); + execlp("rpm", "rpm", arg, "--force", "--nodeps", "--nodigest", "--nosignature", "--root", rootdir, name, (char *)0); perror("rpm"); _exit(0); } @@ -1981,34 +2180,72 @@ runrpm(const char *arg, const char *name, int dupfd3) } } +#endif + +#if defined(ENABLE_DEBIAN) && defined(DEBIAN) + +void +rundpkg(const char *arg, const char *name, int dupfd3, const char *rootdir) +{ + pid_t pid; + int status; + + if ((pid = fork()) == (pid_t)-1) + { + perror("fork"); + exit(1); + } + if (pid == 0) + { + if (!rootdir) + rootdir = "/"; + if (dupfd3 != -1 && dupfd3 != 3) + { + dup2(dupfd3, 3); + close(dupfd3); + } + if (dupfd3 != -1) + fcntl(3, F_SETFD, 0); /* clear CLOEXEC */ + if (strcmp(arg, "--install") == 0) + execlp("dpkg", "dpkg", "--install", "--root", rootdir, "--force", "all", name, (char *)0); + else + execlp("dpkg", "dpkg", "--remove", "--root", rootdir, "--force", "all", name, (char *)0); + perror("dpkg"); + _exit(0); + } + while (waitpid(pid, &status, 0) != pid) + ; + if (status) + { + printf("dpkg failed\n"); + exit(1); + } +} + +#endif + +#ifdef SUSE static Id nscallback(Pool *pool, void *data, Id name, Id evr) { - if (name == NAMESPACE_PRODUCTBUDDY) - { - /* SUSE specific hack: each product has an associated rpm */ - Solvable *s = pool->solvables + evr; - Id p, pp, cap; - - cap = str2id(pool, pool_tmpjoin(pool, "product(", id2str(pool, s->name) + 8, ")"), 0); - if (!cap) - return 0; - cap = 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) - break; - } - return p; +#if 0 + if (name == NAMESPACE_LANGUAGE) + { + 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) { @@ -2034,65 +2271,301 @@ addsoftlocks(Pool *pool, Queue *job) type = SOLVER_SOLVABLE_PROVIDES; bp += 9; } - id = str2id(pool, bp, 1); + id = pool_str2id(pool, bp, 1); if (pool->installed) { - FOR_JOB_SELECT(p, pp, type, id) - if (pool->solvables[p].repo == pool->installed) - break; - if (p) - continue; /* ignore, as it is already installed */ + FOR_JOB_SELECT(p, pp, type, id) + if (pool->solvables[p].repo == pool->installed) + break; + if (p) + continue; /* ignore, as it is already installed */ + } + queue_push2(job, SOLVER_LOCK|SOLVER_WEAK|type, id); + } + fclose(fp); +} +#endif + + +#if defined(ENABLE_RPMDB) + +static void +rewrite_repos(Pool *pool, Queue *addedfileprovides, Queue *addedfileprovides_inst) +{ + Repo *repo; + Repodata *data; + Map providedids; + Queue fileprovidesq; + int i, j, n; + struct repoinfo *cinfo; + + map_init(&providedids, pool->ss.nstrings); + queue_init(&fileprovidesq); + for (i = 0; i < addedfileprovides->count; i++) + MAPSET(&providedids, addedfileprovides->elements[i]); + FOR_REPOS(i, repo) + { + /* 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; + for (j = 2; j < repo->nrepodata; j++) + { + Repodata *edata = repo_id2repodata(repo, j); + if (!edata->loadcallback) + break; + } + if (j < repo->nrepodata) + continue; /* found a non-externsion repodata, can't rewrite */ + if (repodata_lookup_idarray(data, SOLVID_META, REPOSITORY_ADDEDFILEPROVIDES, &fileprovidesq)) + { + if (repo == pool->installed && addedfileprovides_inst) + { + for (j = 0; j < addedfileprovides->count; j++) + MAPCLR(&providedids, addedfileprovides->elements[j]); + for (j = 0; j < addedfileprovides_inst->count; j++) + MAPSET(&providedids, addedfileprovides_inst->elements[j]); + } + n = 0; + for (j = 0; j < fileprovidesq.count; j++) + if (MAPTST(&providedids, fileprovidesq.elements[j])) + n++; + if (repo == pool->installed && addedfileprovides_inst) + { + for (j = 0; j < addedfileprovides_inst->count; j++) + MAPCLR(&providedids, addedfileprovides_inst->elements[j]); + for (j = 0; j < addedfileprovides->count; j++) + MAPSET(&providedids, addedfileprovides->elements[j]); + if (n == addedfileprovides_inst->count) + continue; /* nothing new added */ + } + else if (n == addedfileprovides->count) + continue; /* nothing new added */ + } + repodata_set_idarray(data, SOLVID_META, REPOSITORY_ADDEDFILEPROVIDES, repo == pool->installed && addedfileprovides_inst ? addedfileprovides_inst : addedfileprovides); + repodata_internalize(data); + writecachedrepo(repo, data, 0, cinfo ? cinfo->cookie : installedcookie); + } + queue_free(&fileprovidesq); + map_free(&providedids); +} + +static void +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, multiversionmap; + Solvable *s; + + map_init(&multiversionmap, 0); + map_init(&installedmap, pool->nsolvables); + solver_calculate_multiversionmap(pool, job, &multiversionmap); + if (pool->installed) + FOR_REPO_SOLVABLES(pool->installed, p, s) + MAPSET(&installedmap, p); + + /* install all patches */ + for (p = 1; p < pool->nsolvables; p++) + { + const char *type; + int r; + Id p2; + + s = pool->solvables + p; + if (strncmp(pool_id2str(pool, s->name), "patch:", 6) != 0) + continue; + FOR_PROVIDES(p2, pp, s->name) + { + Solvable *s2 = pool->solvables + p2; + if (s2->name != s->name) + continue; + r = pool_evrcmp(pool, s->evr, s2->evr, EVRCMP_COMPARE); + if (r < 0 || (r == 0 && p > p2)) + break; + } + if (p2) + continue; + type = solvable_lookup_str(s, SOLVABLE_PATCHCATEGORY); + if (type && !strcmp(type, "optional")) + continue; + r = solvable_trivial_installable_map(s, &installedmap, 0, &multiversionmap); + if (r == -1) + continue; + if (solvable_lookup_bool(s, UPDATE_RESTART) && r == 0) + { + if (!pruneyou++) + queue_empty(job); } - queue_push2(job, SOLVER_LOCK|SOLVER_WEAK|type, id); + else if (pruneyou) + continue; + queue_push2(job, SOLVER_SOLVABLE, p); } - fclose(fp); + map_free(&installedmap); + map_free(&multiversionmap); } - #endif +#ifdef SUSE +static void +showdiskusagechanges(Transaction *trans) +{ + DUChanges duc[4]; + int i; -void -rewrite_repos(Pool *pool, Id *addedfileprovides) + /* 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) { - Repo *repo; - Repodata *data; - Map providedids; - Queue fileprovidesq; - Id id; - int i, j, n, nprovidedids; - struct repoinfo *cinfo; + 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)); - map_init(&providedids, pool->ss.nstrings); - queue_init(&fileprovidesq); - for (nprovidedids = 0; (id = addedfileprovides[nprovidedids]) != 0; nprovidedids++) - MAPSET(&providedids, id); - FOR_REPOS(i, repo) + dataiterator_init(&di, pool, s->repo, SOLVID_META, DELTA_PACKAGE_NAME, matchname, SEARCH_STRING); + dataiterator_prepend_keyname(&di, REPOSITORY_DELTAINFO); + while (dataiterator_step(&di)) { - /* make sure this repo has just one main repodata */ - if (!repo->nrepodata) - continue; - cinfo = repo->appdata; - data = repo->repodata + 0; - if (data->store.pagefd == -1) + 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; - if (repodata_lookup_idarray(data, SOLVID_META, REPOSITORY_ADDEDFILEPROVIDES, &fileprovidesq)) + baseevr = pool_lookup_id(pool, SOLVID_POS, DELTA_BASE_EVR); + FOR_PROVIDES(op, pp, s->name) { - n = 0; - for (j = 0; j < fileprovidesq.count; j++) - if (MAPTST(&providedids, fileprovidesq.elements[j])) - n++; - if (n == nprovidedids) - continue; /* nothing new added */ + 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; } - /* oh my! */ - for (j = 0; addedfileprovides[j]; j++) - repodata_add_idarray(data, SOLVID_META, REPOSITORY_ADDEDFILEPROVIDES, addedfileprovides[j]); - repodata_internalize(data); - writecachedrepo(repo, data, 0, cinfo ? cinfo->cookie : installedcookie); } - queue_free(&fileprovidesq); - map_free(&providedids); + dataiterator_free(&di); + solv_free(matchname); + return retfp; } +#endif + #define MODE_LIST 0 #define MODE_INSTALL 1 @@ -2110,16 +2583,19 @@ usage(int r) { fprintf(stderr, "Usage: solv COMMAND