diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/db.c | 1 | ||||
-rw-r--r-- | src/list.c | 12 | ||||
-rw-r--r-- | src/list.h | 1 | ||||
-rw-r--r-- | src/package.c | 1 | ||||
-rw-r--r-- | src/pacman.c | 462 | ||||
-rw-r--r-- | src/pacman.h | 4 | ||||
-rw-r--r-- | src/pacsync.c | 230 | ||||
-rw-r--r-- | src/pacsync.h | 25 | ||||
-rw-r--r-- | src/util.c | 145 |
9 files changed, 594 insertions, 287 deletions
@@ -31,6 +31,7 @@ #include "package.h" #include "db.h" #include "util.h" +#include "pacsync.h" #include "pacman.h" extern PMList *pm_packages; @@ -93,6 +93,18 @@ int list_count(PMList *list) return(i); } +int list_isin(PMList *haystack, void *needle) +{ + PMList *lp; + + for(lp = haystack; lp; lp = lp->next) { + if(lp->data == needle) { + return(1); + } + } + return(0); +} + /* List one is extended and returned * List two is freed (but not its data) */ @@ -12,6 +12,7 @@ PMList* list_new(); void list_free(PMList* list); PMList* list_add(PMList* list, void* data); int list_count(PMList* list); +int list_isin(PMList *haystack, void *needle); PMList* list_merge(PMList *one, PMList *two); PMList* list_last(PMList* list); diff --git a/src/package.c b/src/package.c index 69461f67..95913b14 100644 --- a/src/package.c +++ b/src/package.c @@ -30,6 +30,7 @@ #include "package.h" #include "db.h" #include "util.h" +#include "pacsync.h" #include "pacman.h" extern tartype_t gztype; diff --git a/src/pacman.c b/src/pacman.c index 7c70cacd..053c5081 100644 --- a/src/pacman.c +++ b/src/pacman.c @@ -72,25 +72,24 @@ unsigned short pmo_s_upgrade = 0; unsigned short pmo_s_sync = 0; unsigned short pmo_s_search = 0; unsigned short pmo_s_clean = 0; +PMList *pmo_noupgrade = NULL; -/* configuration options */ -char pmc_syncserver[512] = ""; -char pmc_syncpath[512] = ""; -char pmc_syncname[512] = ""; - -char *lckfile = "/tmp/pacman.lck"; +/* list of sync_t structs for sync locations */ +PMList *pmc_syncs = NULL; /* list of installed packages */ PMList *pm_packages = NULL; - /* list of targets specified on command line */ -PMList *pm_targets = NULL; +PMList *pm_targets = NULL; + +char *lckfile = "/tmp/pacman.lck"; int main(int argc, char *argv[]) { int ret = 0; char *ptr = NULL; char *dbpath = NULL; + char path[PATH_MAX]; pacdb_t *db_local = NULL; PMList *lp; @@ -141,6 +140,12 @@ int main(int argc, char *argv[]) signal(SIGINT, cleanup); signal(SIGTERM, cleanup); + /* parse the system-wide config file */ + snprintf(path, PATH_MAX, "/%s", PACCONF); + if(parseconfig(path)) { + cleanup(1); + } + /* check for db existence */ /* add a trailing '/' if there isn't one */ if(pmo_root[strlen(pmo_root)-1] != '/') { @@ -249,37 +254,18 @@ int pacman_deptest(pacdb_t *db, PMList *targets) int pacman_sync(pacdb_t *db, PMList *targets) { - char url[1024]; - char *dbpath = NULL; + char dbpath[PATH_MAX]; int allgood = 1, confirm = 0; - pacdb_t *db_sync = NULL; - PMList *pkgcache = NULL; - PMList *i, *j; + int cols; + PMList *i, *j, *k; PMList *final = NULL; PMList *trail = NULL; - PMList *deps = NULL; - int cols; + PMList *databases = NULL; - /* parse the system-wide config file */ - snprintf(url, 511, "/%s", PACCONF); - if(parseconfig(url)) { + if(!list_count(pmc_syncs)) { + fprintf(stderr, "error: no usable package repositories configured.\n"); return(1); } - if(!strlen(pmc_syncserver)) { - fprintf(stderr, "error: no Sync_Server specified in %s\n", url); - return(1); - } - if(!strlen(pmc_syncname)) { - fprintf(stderr, "error: no Sync_Tree_Name specified in %s\n", url); - return(1); - } - if(!strlen(pmc_syncpath)) { - fprintf(stderr, "error: no Sync_Tree_Path specified in %s\n", url); - return(1); - } - if(pmc_syncpath[0] != '/') { - sprintf(pmc_syncpath, "/%s", pmc_syncpath); - } if(pmo_s_clean) { mode_t oldmask; @@ -303,54 +289,61 @@ int pacman_sync(pacdb_t *db, PMList *targets) if(pmo_s_sync && !pmo_s_search) { /* grab a fresh package list */ - printf(":: Synchronizing remote package tree... \n"); + printf(":: Synchronizing package databases... \n"); sync_synctree(); - printf("\n"); - } - - /* open the sync db */ - MALLOC(dbpath, PATH_MAX); - snprintf(dbpath, PATH_MAX-1, "%s%s", pmo_root, PKGDIR); - db_sync = db_open(dbpath, pmc_syncname); - if(db_sync == NULL) { - fprintf(stderr, "error: could not open the sync database.\n"); - fprintf(stderr, " have you used --refresh yet?\n"); - return(1); } - /* cache packages */ - pkgcache = db_loadpkgs(db_sync, pkgcache); - if(db_sync == NULL) { - fprintf(stderr, "error: could not open sync database (%s/%s)\n", dbpath, pmc_syncname); - return(1); + /* open the database(s) */ + for(i = pmc_syncs; i; i = i->next) { + pacdb_t *db_sync = NULL; + dbsync_t *dbs = NULL; + sync_t *sync = (sync_t*)i->data; + + snprintf(dbpath, PATH_MAX, "%s%s", pmo_root, PKGDIR); + db_sync = db_open(dbpath, sync->treename); + if(db_sync == NULL) { + fprintf(stderr, "error: could not open sync database: %s\n", sync->treename); + fprintf(stderr, " have you used --refresh yet?\n"); + return(1); + } + MALLOC(dbs, sizeof(dbsync_t)); + dbs->sync = sync; + dbs->db = db_sync; + /* cache packages */ + dbs->pkgcache = NULL; + dbs->pkgcache = db_loadpkgs(db_sync, dbs->pkgcache); + databases = list_add(databases, dbs); } final = list_new(); trail = list_new(); if(pmo_s_search) { - /* search sync db */ + /* search sync databases */ for(i = targets; i; i = i->next) { char *targ = strdup(i->data); strtoupper(targ); - for(j = pkgcache; j; j = j->next) { - pkginfo_t *pkg = (pkginfo_t*)j->data; - char *haystack; - /* check name */ - haystack = strdup(pkg->name); - strtoupper(haystack); - if(strstr(haystack, targ)) { - printf("%s %s\n", pkg->name, pkg->version); - } else { - /* check description */ - FREE(haystack); - haystack = strdup(pkg->desc); + for(j = databases; j; j = j->next) { + dbsync_t *dbs = (dbsync_t*)j->data; + for(k = dbs->pkgcache; k; k = k->next) { + pkginfo_t *pkg = (pkginfo_t*)k->data; + char *haystack; + /* check name */ + haystack = strdup(pkg->name); strtoupper(haystack); if(strstr(haystack, targ)) { printf("%s %s\n", pkg->name, pkg->version); + } else { + /* check description */ + FREE(haystack); + haystack = strdup(pkg->desc); + strtoupper(haystack); + if(strstr(haystack, targ)) { + printf("%s %s\n", pkg->name, pkg->version); + } } + FREE(haystack); } - FREE(haystack); } FREE(targ); } @@ -359,18 +352,18 @@ int pacman_sync(pacdb_t *db, PMList *targets) for(i = pm_packages; i && allgood; i = i->next) { int cmp, found = 0; pkginfo_t *local = (pkginfo_t*)i->data; - pkginfo_t *sync = NULL; - - for(j = pkgcache; !found && j; j = j->next) { - sync = (pkginfo_t*)j->data; - if(local == NULL || local->name == NULL) { - vprint("local is NULL!\n"); - } - if(sync == NULL || sync->name == NULL) { - vprint("sync is NULL!\n"); - } - if(!strcmp(local->name, sync->name)) { - found = 1; + syncpkg_t *sync = NULL; + MALLOC(sync, sizeof(syncpkg_t)); + + for(j = databases; !found && j; j = j->next) { + dbsync_t *dbs = (dbsync_t*)j->data; + for(k = dbs->pkgcache; !found && k; k = k->next) { + pkginfo_t *pkg = (pkginfo_t*)k->data; + if(!strcmp(local->name, pkg->name)) { + found = 1; + sync->pkg = pkg; + sync->dbs = dbs; + } } } if(!found) { @@ -378,7 +371,7 @@ int pacman_sync(pacdb_t *db, PMList *targets) continue; } /* compare versions and see if we need to upgrade */ - cmp = rpmvercmp(local->version, sync->version); + cmp = rpmvercmp(local->version, sync->pkg->version); if(cmp > 0) { /* local version is newer */ fprintf(stderr, ":: %s-%s: local version is newer\n", @@ -390,12 +383,12 @@ int pacman_sync(pacdb_t *db, PMList *targets) continue; } else { /* re-fetch the package record with dependency info */ - sync = db_scan(db_sync, sync->name, INFRQ_DESC | INFRQ_DEPENDS); + sync->pkg = db_scan(sync->dbs->db, sync->pkg->name, INFRQ_DESC | INFRQ_DEPENDS); /* add to the targets list */ - if(!is_pkgin(sync, final)) { - allgood = !resolvedeps(db, db_sync, sync, final, trail); + if(!list_isin(final, sync)) { + allgood = !resolvedeps(db, databases, sync, final, trail); /* check again, as resolvedeps could have added our target for us */ - if(!is_pkgin(sync, final)) { + if(!list_isin(final, sync)) { final = list_add(final, sync); } } @@ -408,19 +401,35 @@ int pacman_sync(pacdb_t *db, PMList *targets) /* process targets */ for(i = targets; i && allgood; i = i->next) { if(i->data) { - int cmp; + int cmp, found = 0; pkginfo_t *local; - pkginfo_t *sync; + syncpkg_t *sync = NULL; + MALLOC(sync, sizeof(syncpkg_t)); local = db_scan(db, (char*)i->data, INFRQ_DESC); - sync = db_scan(db_sync, (char*)i->data, INFRQ_DESC | INFRQ_DEPENDS); - if(sync == NULL) { - fprintf(stderr, ":: %s: not found in sync db\n", (char*)i->data); + //sync = db_scan(db_sync, (char*)i->data, INFRQ_DESC | INFRQ_DEPENDS); + for(j = databases; !found && j; j = j->next) { + dbsync_t *dbs = (dbsync_t*)j->data; + for(k = dbs->pkgcache; !found && k; k = k->next) { + pkginfo_t *pkg = (pkginfo_t*)k->data; + if(!strcmp((char*)i->data, pkg->name)) { + found = 1; + sync->dbs = dbs; + /* re-fetch the package record with dependency info */ + sync->pkg = db_scan(sync->dbs->db, pkg->name, INFRQ_DESC | INFRQ_DEPENDS); + if(sync->pkg == NULL) { + found = 0; + } + } + } + } + if(!found) { + fprintf(stderr, "%s: not found in sync db\n", (char*)i->data); continue; } if(local) { /* this is an upgrade, compare versions and determine if it is necessary */ - cmp = rpmvercmp(local->version, sync->version); + cmp = rpmvercmp(local->version, sync->pkg->version); if(cmp > 0) { /* local version is newer - get confirmation first */ if(!yesno(":: %s-%s: local version is newer. Upgrade anyway? [Y/n] ", local->name, local->version)) { @@ -434,10 +443,24 @@ int pacman_sync(pacdb_t *db, PMList *targets) } } /* add to targets list */ - if(!is_pkgin(sync, final)) { - allgood = !resolvedeps(db, db_sync, sync, final, trail); + found = 0; + for(j = final; j; j = j->next) { + syncpkg_t *tmp = (syncpkg_t*)j->data; + if(tmp && !strcmp(tmp->pkg->name, sync->pkg->name)) { + found = 1; + } + } + if(!found) { + allgood = !resolvedeps(db, databases, sync, final, trail); /* check again, as resolvedeps could have added our target for us */ - if(!is_pkgin(sync, final)) { + found = 0; + for(j = final; j; j = j->next) { + syncpkg_t *tmp = (syncpkg_t*)j->data; + if(tmp && !strcmp(tmp->pkg->name, sync->pkg->name)) { + found = 1; + } + } + if(!found) { final = list_add(final, sync); } } @@ -447,7 +470,16 @@ int pacman_sync(pacdb_t *db, PMList *targets) if(allgood) { /* check for inter-conflicts and whatnot */ - deps = checkdeps(db, PM_UPGRADE, final); + PMList *deps = NULL; + PMList *list = NULL; + + for(i = final; i; i = i->next) { + syncpkg_t *s = (syncpkg_t*)i->data; + if(s) { + list = list_add(list, s->pkg); + } + } + deps = checkdeps(db, PM_UPGRADE, list); if(deps) { fprintf(stderr, "error: unresolvable conflicts/dependencies:\n"); for(i = deps; i; i = i->next) { @@ -474,6 +506,12 @@ int pacman_sync(pacdb_t *db, PMList *targets) /* abort mission */ allgood = 0; } + /* cleanup */ + for(i = list; i; i = i->next) { + i->data = NULL; + } + list_free(list); + list = NULL; /* list targets */ if(final && final->data) { @@ -481,18 +519,18 @@ int pacman_sync(pacdb_t *db, PMList *targets) } cols = 9; for(i = final; allgood && i; i = i->next) { - pkginfo_t *p = (pkginfo_t*)i->data; - if(p) { + syncpkg_t *s = (syncpkg_t*)i->data; + if(s && s->pkg) { char t[PATH_MAX]; - int s; - snprintf(t, PATH_MAX, "%s-%s ", p->name, p->version); - s = strlen(t); - if(s+cols > 78) { + int len; + snprintf(t, PATH_MAX, "%s-%s ", s->pkg->name, s->pkg->version); + len = strlen(t); + if(len+cols > 78) { cols = 9; fprintf(stderr, "\n%9s", " "); } fprintf(stderr, "%s", t); - cols += s; + cols += len; } } printf("\n"); @@ -504,66 +542,96 @@ int pacman_sync(pacdb_t *db, PMList *targets) } } - if(allgood && confirm) { - PMList *files = NULL; + if(allgood && confirm && final && final->data) { char ldir[PATH_MAX]; int varcache = 1; + int done = 0; + int count = 0; + sync_t *current = NULL; + PMList *processed = NULL; + PMList *files = NULL; - /* download targets */ - for(i = final; i; i = i->next) { - pkginfo_t *p = (pkginfo_t*)i->data; - if(p) { - struct stat buf; - char path[PATH_MAX]; - - snprintf(path, PATH_MAX, "%svar/cache/pacman/pkg/%s-%s.pkg.tar.gz", - pmo_root, p->name, p->version); - if(stat(path, &buf)) { - /* file is not in the cache dir, so add it to the list */ - snprintf(path, PATH_MAX, "%s-%s.pkg.tar.gz", p->name, p->version); - files = list_add(files, strdup(path)); - } + /* group sync records by repository and download */ + while(!done) { + if(current) { + processed = list_add(processed, current); + current = NULL; } - } - snprintf(ldir, PATH_MAX, "%svar/cache/pacman/pkg", pmo_root); + for(i = final; i; i = i->next) { + syncpkg_t *sync = (syncpkg_t*)i->data; + if(current == NULL) { + /* we're starting on a new repository */ + if(!list_isin(processed, sync->dbs->sync)) { + current = sync->dbs->sync; + } + } + if(current && !strcmp(current->treename, sync->dbs->sync->treename)) { + struct stat buf; + char path[PATH_MAX]; - if(files) { - struct stat buf; - - printf("\n:: Downloading packages...\n"); fflush(stdout); - if(stat(ldir, &buf)) { - mode_t oldmask; - char parent[PATH_MAX]; - - /* no cache directory.... try creating it */ - snprintf(parent, PATH_MAX, "%svar/cache/pacman", pmo_root); - fprintf(stderr, "warning: no %s cache exists. creating...\n", ldir); - oldmask = umask(0000); - if(mkdir(parent, 0755) || mkdir(ldir, 0755)) { - /* couldn't mkdir the cache directory, so fall back to /tmp and unlink - * the package afterwards. - */ - fprintf(stderr, "warning: couldn't create package cache, using /tmp instead\n"); - snprintf(ldir, PATH_MAX, "/tmp"); - varcache = 0; + snprintf(path, PATH_MAX, "%svar/cache/pacman/pkg/%s-%s.pkg.tar.gz", + pmo_root, sync->pkg->name, sync->pkg->version); + if(stat(path, &buf)) { + /* file is not in the cache dir, so add it to the list */ + snprintf(path, PATH_MAX, "%s-%s.pkg.tar.gz", sync->pkg->name, sync->pkg->version); + files = list_add(files, strdup(path)); + } else { + count++; + } } - umask(oldmask); } - if(downloadfiles(pmc_syncserver, pmc_syncpath, ldir, files)) { - fprintf(stderr, "error: ftp transfer failed.\n"); - allgood = 0; + snprintf(ldir, PATH_MAX, "%svar/cache/pacman/pkg", pmo_root); + + if(files) { + struct stat buf; + + printf("\n:: Retrieving packages from %s...\n", current->treename); + fflush(stdout); + if(stat(ldir, &buf)) { + mode_t oldmask; + char parent[PATH_MAX]; + + /* no cache directory.... try creating it */ + snprintf(parent, PATH_MAX, "%svar/cache/pacman", pmo_root); + fprintf(stderr, "warning: no %s cache exists. creating...\n", ldir); + oldmask = umask(0000); + mkdir(parent, 0755); + if(mkdir(ldir, 0755)) { + /* couldn't mkdir the cache directory, so fall back to /tmp and unlink + * the package afterwards. + */ + fprintf(stderr, "warning: couldn't create package cache, using /tmp instead\n"); + snprintf(ldir, PATH_MAX, "/tmp"); + varcache = 0; + } + umask(oldmask); + } + if(downloadfiles(current->servers, ldir, files)) { + fprintf(stderr, "error: failed to retrieve some files from %s.\n", current->treename); + allgood = 0; + } + count += list_count(files); + list_free(files); + files = NULL; } + if(count == list_count(final)) { + done = 1; + } + } + printf("\n"); + + /* double-check */ + if(files) { list_free(files); files = NULL; } - /* install targets */ for(i = final; allgood && i; i = i->next) { char *str; - pkginfo_t *p = (pkginfo_t*)i->data; - if(p) { + syncpkg_t *sync = (syncpkg_t*)i->data; + if(sync->pkg) { MALLOC(str, PATH_MAX); - snprintf(str, PATH_MAX, "%s/%s-%s.pkg.tar.gz", ldir, p->name, p->version); + snprintf(str, PATH_MAX, "%s/%s-%s.pkg.tar.gz", ldir, sync->pkg->name, sync->pkg->version); files = list_add(files, str); } } @@ -580,22 +648,26 @@ int pacman_sync(pacdb_t *db, PMList *targets) } /* cleanup */ - for(i = pkgcache; i; i = i->next) { - if(i->data) freepkg((pkginfo_t*)i->data); - i->data = NULL; - } for(i = final; i; i = i->next) { - if(i->data) freepkg((pkginfo_t*)i->data); + syncpkg_t *sync = (syncpkg_t*)i->data; + if(sync) freepkg(sync->pkg); + free(sync); i->data = NULL; } for(i = trail; i; i = i->next) { /* this list used the same pointers as final, so they're already freed */ i->data = NULL; } - list_free(pkgcache); + for(i = databases; i; i = i->next) { + dbsync_t *dbs = (dbsync_t*)i->data; + db_close(dbs->db); + list_free(dbs->pkgcache); + free(dbs); + i->data = NULL; + } + list_free(databases); list_free(final); list_free(trail); - db_close(db_sync); return(!allgood); } @@ -726,6 +798,7 @@ int pacman_add(pacdb_t *db, PMList *targets) vprint("extracting files...\n"); for(i = 0; !th_read(tar); i++) { int nb = 0; + int notouch = 0; char *md5_orig = NULL; char pathname[PATH_MAX]; strncpy(pathname, th_get_pathname(tar), PATH_MAX); @@ -746,13 +819,17 @@ int pacman_add(pacdb_t *db, PMList *targets) if(!stat(expath, &buf) && !S_ISDIR(buf.st_mode)) { /* file already exists */ - if(!pmo_upgrade) { - nb = is_in(pathname, info->backup); + if(is_in(pathname, pmo_noupgrade)) { + notouch = 1; } else { - /* op == PM_UPGRADE */ - md5_orig = needbackup(pathname, oldpkg->backup); - if(md5_orig) { - nb = 1; + if(!pmo_upgrade) { + nb = is_in(pathname, info->backup); + } else { + /* op == PM_UPGRADE */ + md5_orig = needbackup(pathname, oldpkg->backup); + if(md5_orig) { + nb = 1; + } } } } @@ -857,7 +934,14 @@ int pacman_add(pacdb_t *db, PMList *targets) unlink(temp); FREE(temp); } else { - /*vprint(" %s\n", expath);*/ + if(!notouch) { + /*vprint(" %s\n", expath);*/ + } else { + vprint("%s is in NoUpgrade - skipping\n", pathname); + strncat(expath, ".pacnew", PATH_MAX); + fprintf(stderr, "warning: extracting %s%s as %s\n", pmo_root, pathname, expath); + /*tar_skip_regfile(tar);*/ + } if(tar_extract_file(tar, expath)) { fprintf(stderr, "could not extract %s: %s\n", pathname, strerror(errno)); errors++; @@ -1026,6 +1110,12 @@ int pacman_remove(pacdb_t *db, PMList *targets) if(needbackup((char*)lp->data, info->backup)) { nb = 1; } + if(!nb && pmo_upgrade) { + /* check pmo_noupgrade */ + if(is_in((char*)lp->data, pmo_noupgrade)) { + nb = 1; + } + } snprintf(line, PATH_MAX, "%s%s", pmo_root, (char*)lp->data); if(lstat(line, &buf)) { vprint("file %s does not exist\n", line); @@ -1312,31 +1402,53 @@ int pacman_upgrade(pacdb_t *db, PMList *targets) } /* populates *list with packages that need to be installed to satisfy all - * dependencies (recursive) for *package + * dependencies (recursive) for *syncpkg->pkg * * make sure *list and *trail are already initialized */ -int resolvedeps(pacdb_t *local, pacdb_t *sync, pkginfo_t *package, PMList *list, PMList *trail) +int resolvedeps(pacdb_t *local, PMList *databases, syncpkg_t *syncpkg, PMList *list, PMList *trail) { - pkginfo_t *info; - PMList *i; + PMList *i, *j, *k; PMList *targ = NULL; PMList *deps = NULL; targ = list_new(); - targ = list_add(targ, package); + targ = list_add(targ, syncpkg->pkg); deps = checkdeps(local, PM_ADD, targ); targ->data = NULL; list_free(targ); for(i = deps; i; i = i->next) { + int found = 0; + syncpkg_t *sync = NULL; depmissing_t *miss = (depmissing_t*)i->data; - info = db_scan(sync, miss->depend.name, INFRQ_DESC | INFRQ_DEPENDS); - if(info == NULL) { + MALLOC(sync, sizeof(syncpkg_t)); + + /* find the package in one of the repositories */ + for(j = databases; !found && j; j = j->next) { + dbsync_t *dbs = (dbsync_t*)j->data; + for(k = dbs->pkgcache; !found && k; k = k->next) { + pkginfo_t *pkg = (pkginfo_t*)k->data; + if(!strcmp(miss->depend.name, pkg->name)) { + found = 1; + /* re-fetch the package record with dependency info */ + sync->pkg = db_scan(dbs->db, pkg->name, INFRQ_DESC | INFRQ_DEPENDS); + sync->dbs = dbs; + } + } + } + if(!found) { fprintf(stderr, "error: cannot resolve dependencies for \"%s\":\n", miss->target); fprintf(stderr, " \"%s\" is not in the package set\n", miss->depend.name); return(1); } - if(is_pkgin(info, list) == 1) { + found = 0; + for(j = list; j; j = j->next) { + syncpkg_t *tmp = (syncpkg_t*)j->data; + if(tmp && !strcmp(tmp->pkg->name, sync->pkg->name)) { + found = 1; + } + } + if(found) { /* this dep is already in the target list */ continue; } @@ -1344,13 +1456,21 @@ int resolvedeps(pacdb_t *local, pacdb_t *sync, pkginfo_t *package, PMList *list, fprintf(stderr, "error: %s conflicts with %s\n", miss->target, miss->depend.name); return(1); } else if(miss->type == DEPEND) { - /*printf("resolving %s\n", info->name); fflush(stdout);*/ - if(!is_pkgin(info, trail)) { - list_add(trail, info); - if(resolvedeps(local, sync, info, list, trail)) { + /*printf("resolving %s\n", sync->pkg->name); fflush(stdout);*/ + found = 0; + for(j = trail; j; j = j->next) { + syncpkg_t *tmp = (syncpkg_t*)j->data; + if(tmp && !strcmp(tmp->pkg->name, sync->pkg->name)) { + found = 1; + } + } + if(!found) { + list_add(trail, sync); + if(resolvedeps(local, databases, sync, list, trail)) { return(1); } - list_add(list, info); + vprint("adding %s-%s\n", sync->pkg->name, sync->pkg->version); + list_add(list, sync); } else { /* cycle detected -- skip it */ /*printf("cycle detected\n"); fflush(stdout);*/ @@ -1398,7 +1518,7 @@ PMList* checkdeps(pacdb_t *db, unsigned short op, PMList *targets) if((p = db_scan(db, j->data, INFRQ_DESC | INFRQ_DEPENDS)) == NULL) { continue; } - for(k = p->depends; k; k = k->next) { + for(k = p->depends; k && !found; k = k->next) { if(splitdep(k->data, &depend)) { continue; } diff --git a/src/pacman.h b/src/pacman.h index 330969ce..37b86853 100644 --- a/src/pacman.h +++ b/src/pacman.h @@ -22,7 +22,7 @@ #define _PAC_PACMAN_H #ifndef PACVER -#define PACVER "2.0" +#define PACVER "2.1" #endif #ifndef PKGDIR @@ -50,7 +50,7 @@ int pacman_sync(pacdb_t *db, PMList *targets); int pacman_deptest(pacdb_t *db, PMList *targets); PMList* checkdeps(pacdb_t *db, unsigned short op, PMList *targets); -int resolvedeps(pacdb_t *local, pacdb_t *sync, pkginfo_t *package, PMList *list, PMList *trail); +int resolvedeps(pacdb_t *local, PMList *databases, syncpkg_t *sync, PMList *list, PMList *trail); int splitdep(char *depstr, depend_t *depend); int lckmk(char *file, int retries, unsigned int sleep_secs); diff --git a/src/pacsync.c b/src/pacsync.c index 224528f8..a76da444 100644 --- a/src/pacsync.c +++ b/src/pacsync.c @@ -41,125 +41,171 @@ static char sync_fnm[25]; /* pacman options */ extern char *pmo_root; -/* configuration options */ -extern char pmc_syncserver[512]; -extern char pmc_syncpath[512]; -extern char pmc_syncname[512]; + +/* sync servers */ +extern PMList *pmc_syncs; int sync_synctree() { char ldir[PATH_MAX] = ""; char path[PATH_MAX]; mode_t oldmask; - char *str; PMList *files = NULL; - - snprintf(ldir, PATH_MAX, "%s%s/%s", pmo_root, PKGDIR, pmc_syncname); - - /* remove the old dir */ - vprint("Removing %s (if it exists)\n", ldir); - rmrf(ldir); - - /* make the new dir */ - oldmask = umask(0000); - mkdir(ldir, 0755); - umask(oldmask); - - /* build out list of one */ - snprintf(path, PATH_MAX, "%s.db.tar.gz", pmc_syncname); - str = strdup(path); - files = list_add(files, str); - if(downloadfiles(pmc_syncserver, pmc_syncpath, ldir, files)) { + PMList *i; + int success = 0; + + for(i = pmc_syncs; i; i = i->next) { + sync_t *sync = (sync_t*)i->data; + snprintf(ldir, PATH_MAX, "%s%s", pmo_root, PKGDIR); + + /* build a one-element list */ + snprintf(path, PATH_MAX, "%s.db.tar.gz", sync->treename); + files = list_add(files, strdup(path)); + + success = 1; + if(downloadfiles(sync->servers, ldir, files)) { + fprintf(stderr, "failed to synchronize %s\n", sync->treename); + success = 0; + } + /*printf("\n");*/ list_free(files); - return(1); - } - - /* uncompress the sync database */ - snprintf(path, PATH_MAX, "%s/%s", ldir, (char*)files->data); - list_free(files); - vprint("Unpacking %s...\n", path); - if(unpack(path, ldir)) { - return(1); + files = NULL; + snprintf(path, PATH_MAX, "%s/%s.db.tar.gz", ldir, sync->treename); + + if(success) { + snprintf(ldir, PATH_MAX, "%s%s/%s", pmo_root, PKGDIR, sync->treename); + /* remove the old dir */ + vprint("removing %s (if it exists)\n", ldir); + rmrf(ldir); + + /* make the new dir */ + oldmask = umask(0000); + mkdir(ldir, 0755); + umask(oldmask); + + /* uncompress the sync database */ + vprint("Unpacking %s...\n", path); + if(unpack(path, ldir)) { + return(1); + } + } + /* remove the .tar.gz */ + unlink(path); } - /* remove the .tar.gz */ - unlink(path); - - return(0); + return(!success); } -int downloadfiles(char *server, char *remotepath, char *localpath, PMList *files) +int downloadfiles(PMList *servers, char *localpath, PMList *files) { int fsz; netbuf *control = NULL; PMList *lp; - int ret = 0; + int done = 0; + PMList *complete = NULL; + PMList *i; if(files == NULL) { return(0); } - FtpInit(); - if(!FtpConnect(server, &control)) { - fprintf(stderr, "error: cannot connect to %s\n", server); - return(1); - } - if(!FtpLogin("anonymous", "arch@guest", control)) { - fprintf(stderr, "error: anonymous login failed\n"); - FtpQuit(control); - return(1); - } - - - if(!FtpChdir(remotepath, control)) { - fprintf(stderr, "error: could not cwd to %s: %s\n", remotepath, - FtpLastResponse(control)); - return(1); - } - - /* get each file in the list */ - for(lp = files; lp; lp = lp->next) { - char output[PATH_MAX]; - int j; - - snprintf(output, PATH_MAX, "%s/%s", localpath, (char*)lp->data); - - /* passive mode */ - /* TODO: make passive ftp an option */ - if(!FtpOptions(FTPLIB_CONNMODE, FTPLIB_PASSIVE, control)) { - fprintf(stderr, "warning: failed to set passive mode\n"); + for(i = servers; i && !done; i = i->next) { + server_t *server = (server_t*)i->data; + + if(!server->islocal) { + FtpInit(); + if(!FtpConnect(server->server, &control)) { + fprintf(stderr, "error: cannot connect to %s\n", server->server); + continue; + } + if(!FtpLogin("anonymous", "arch@guest", control)) { + fprintf(stderr, "error: anonymous login failed\n"); + FtpQuit(control); + continue; + } + if(!FtpChdir(server->path, control)) { + fprintf(stderr, "error: could not cwd to %s: %s\n", server->path, + FtpLastResponse(control)); + continue; + } } - if(!FtpSize((char*)lp->data, &fsz, FTPLIB_IMAGE, control)) { - fprintf(stderr, "warning: failed to get filesize for %s\n", (char*)lp->data); - } - - /* set up our progress bar's callback */ - FtpOptions(FTPLIB_CALLBACK, (long)log_progress, control); - FtpOptions(FTPLIB_IDLETIME, (long)1000, control); - FtpOptions(FTPLIB_CALLBACKARG, (long)&fsz, control); - FtpOptions(FTPLIB_CALLBACKBYTES, (10*1024), control); + /* get each file in the list */ + for(lp = files; lp; lp = lp->next) { + char output[PATH_MAX]; + int j; + char *fn = (char*)lp->data; + + if(is_in(fn, complete)) { + continue; + } + + snprintf(output, PATH_MAX, "%s/%s", localpath, fn); + strncpy(sync_fnm, lp->data, 24); + for(j = strlen(sync_fnm); j < 24; j++) { + sync_fnm[j] = ' '; + } + sync_fnm[24] = '\0'; + + if(!server->islocal) { + /* passive mode */ + /* TODO: make passive ftp an option */ + if(!FtpOptions(FTPLIB_CONNMODE, FTPLIB_PASSIVE, control)) { + fprintf(stderr, "warning: failed to set passive mode\n"); + } + if(!FtpSize(fn, &fsz, FTPLIB_IMAGE, control)) { + fprintf(stderr, "warning: failed to get filesize for %s\n", fn); + } + /* set up our progress bar's callback */ + FtpOptions(FTPLIB_CALLBACK, (long)log_progress, control); + FtpOptions(FTPLIB_IDLETIME, (long)1000, control); + FtpOptions(FTPLIB_CALLBACKARG, (long)&fsz, control); + FtpOptions(FTPLIB_CALLBACKBYTES, (10*1024), control); - strncpy(sync_fnm, lp->data, 24); - for(j = strlen(sync_fnm); j < 24; j++) { - sync_fnm[j] = ' '; + if(!FtpGet(output, lp->data, FTPLIB_IMAGE, control)) { + fprintf(stderr, "\nfailed downloading %s from %s: %s\n", + fn, server->server, FtpLastResponse(control)); + /* unlink the file */ + unlink(output); + } else { + log_progress(control, fsz, &fsz); + complete = list_add(complete, fn); + } + printf("\n"); + fflush(stdout); + } else { + /* local repository, just copy the file */ + char src[PATH_MAX], dest[PATH_MAX]; + snprintf(src, PATH_MAX, "%s%s", server->path, fn); + snprintf(dest, PATH_MAX, "%s/%s", localpath, fn); + vprint("copying %s to %s\n", src, dest); + if(copyfile(src, dest)) { + fprintf(stderr, "failed copying %s\n", src); + } else { + char out[56]; + printf("%s [", sync_fnm); + strncpy(out, server->path, 33); + printf("%s", out); + for(j = strlen(out); j < 33; j++) { + printf(" "); + } + fputs("] 100% | LOCAL\n", stdout); + fflush(stdout); + + complete = list_add(complete, fn); + } + } + } + if(list_count(complete) == list_count(files)) { + done = 1; } - sync_fnm[24] = '\0'; - if(!FtpGet(output, lp->data, FTPLIB_IMAGE, control)) { - fprintf(stderr, "\nerror: could not download %s: %s\n", (char*)lp->data, - FtpLastResponse(control)); - /* unlink the file */ - unlink(output); - ret = 1; - } else { - log_progress(control, fsz, &fsz); + + if(!server->islocal) { + FtpQuit(control); } - printf("\n"); - fflush(stdout); } - - FtpQuit(control); - return(ret); + + return(!done); } static int log_progress(netbuf *ctl, int xfered, void *arg) diff --git a/src/pacsync.h b/src/pacsync.h index d7c666f3..1838a684 100644 --- a/src/pacsync.h +++ b/src/pacsync.h @@ -21,8 +21,31 @@ #ifndef _PAC_PACSYNC_H #define _PAC_PACSYNC_H +typedef struct __server_t { + unsigned short islocal; + char* server; + char* path; +} server_t; + +typedef struct __sync_t { + char* treename; + PMList *servers; +} sync_t; + +/* linking structs */ +typedef struct __dbsync_t { + pacdb_t *db; + sync_t *sync; + PMList *pkgcache; +} dbsync_t; + +typedef struct __syncpkg_t { + pkginfo_t *pkg; + dbsync_t *dbs; +} syncpkg_t; + int sync_synctree(); -int downloadfiles(char *server, char *remotepath, char *localpath, PMList *files); +int downloadfiles(PMList *servers, char *localpath, PMList *files); #endif @@ -34,6 +34,7 @@ #include "package.h" #include "db.h" #include "util.h" +#include "pacsync.h" #include "pacman.h" extern char* pmo_root; @@ -54,11 +55,9 @@ extern unsigned short pmo_s_sync; extern unsigned short pmo_s_search; extern unsigned short pmo_s_clean; extern unsigned short pmo_s_upgrade; +extern PMList *pmo_noupgrade; -extern char pmc_syncserver[512]; -extern char pmc_syncname[512]; -extern char pmc_syncpath[512]; - +extern PMList *pmc_syncs; extern PMList *pm_targets; /* borrowed and modifed from Per Liden's pkgutils (http://crux.nu) */ @@ -221,6 +220,7 @@ int parseargs(int op, int argc, char **argv) return(0); } +#define min(X, Y) ((X) < (Y) ? (X) : (Y)) int parseconfig(char *configfile) { FILE *fp = NULL; @@ -228,6 +228,8 @@ int parseconfig(char *configfile) char *ptr = NULL; char *key = NULL; int linenum = 0; + char section[256] = ""; + sync_t *sync = NULL; if((fp = fopen(configfile, "r")) == NULL) { perror(configfile); @@ -243,25 +245,126 @@ int parseconfig(char *configfile) if(line[0] == '#') { continue; } - ptr = line; - key = strsep(&ptr, "="); - if(key == NULL || ptr == NULL) { - fprintf(stderr, "syntax error in config file (line %d)\n", linenum); + if(line[0] == '[' && line[strlen(line)-1] == ']') { + /* new config section */ + ptr = line; + ptr++; + strncpy(section, ptr, min(255, strlen(ptr)-1)); + section[min(255, strlen(ptr)-1)] = '\0'; + vprint("config: new section '%s'\n", section); + if(!strlen(section)) { + fprintf(stderr, "config: line %d: bad section name\n", linenum); + return(1); + } + if(!strcmp(section, "local")) { + fprintf(stderr, "config: line %d: %s is reserved and cannot be used as a package tree\n", + linenum, section); + return(1); + } + if(strcmp(section, "options")) { + /* start a new sync record */ + MALLOC(sync, sizeof(sync_t)); + sync->treename = strdup(section); + sync->servers = NULL; + pmc_syncs = list_add(pmc_syncs, sync); + } } else { - trim(key); - key = strtoupper(key); - trim(ptr); - if(!strcmp(key, "SYNC_SERVER")) { - strncpy(pmc_syncserver, ptr, sizeof(pmc_syncserver)-1); - } else if(!strcmp(key, "SYNC_TREE_PATH")) { - strncpy(pmc_syncpath, ptr, sizeof(pmc_syncpath)-1); - } else if(!strcmp(key, "SYNC_TREE_NAME")) { - strncpy(pmc_syncname, ptr, sizeof(pmc_syncname)-1); + /* directive */ + if(!strlen(section)) { + fprintf(stderr, "config: line %d: all directives must belong to a section\n", linenum); + return(1); + } + ptr = line; + key = strsep(&ptr, "="); + if(key == NULL || ptr == NULL) { + fprintf(stderr, "config: line %d: syntax error\n", linenum); + return(1); } else { - fprintf(stderr, "Syntax error in description file line %d\n", linenum); + trim(key); + key = strtoupper(key); + trim(ptr); + if(!strcmp(section, "options")) { + if(!strcmp(key, "NOUPGRADE")) { + char *p = ptr; + char *q; + while((q = strchr(p, ' '))) { + *q = '\0'; + pmo_noupgrade = list_add(pmo_noupgrade, strdup(p)); + vprint("config: noupgrade: %s\n", p); + p = q; + p++; + } + pmo_noupgrade = list_add(pmo_noupgrade, strdup(p)); + vprint("config: noupgrade: %s\n", p); + } else { + fprintf(stderr, "config: line %d: syntax error\n", linenum); + return(1); + } + } else { + if(!strcmp(key, "SERVER")) { + /* parse our special url */ + server_t *server; + char *p; + + MALLOC(server, sizeof(server_t)); + server->server = server->path = NULL; + server->islocal = 0; + + p = strstr(ptr, "://"); + if(p == NULL) { + fprintf(stderr, "config: line %d: bad server location\n", linenum); + return(1); + } + *p = '\0'; + p++; p++; p++; + if(p == NULL || *p == '\0') { + fprintf(stderr, "config: line %d: bad server location\n", linenum); + return(1); + } + server->islocal = !strcmp(ptr, "local"); + if(!server->islocal) { + char *slash; + /* no http support yet */ + if(strcmp(ptr, "ftp")) { + fprintf(stderr, "config: line %d: protocol %s is not supported\n", linenum, ptr); + return(1); + } + /* split the url into domain and path */ + slash = strchr(p, '/'); + if(slash == NULL) { + /* no path included, default to / */ + server->path = strdup("/"); + } else { + /* add a trailing slash if we need to */ + if(slash[strlen(slash)-1] == '/') { + server->path = strdup(slash); + } else { + MALLOC(server->path, strlen(slash)+2); + sprintf(server->path, "%s/", slash); + } + *slash = '\0'; + } + server->server = strdup(p); + } else { + /* add a trailing slash if we need to */ + if(p[strlen(p)-1] == '/') { + server->path = strdup(p); + } else { + MALLOC(server->path, strlen(p)+2); + sprintf(server->path, "%s/", p); + } + } + /* add to the list */ + vprint("config: %s: server: %s %s\n", section, server->server, server->path); + sync->servers = list_add(sync->servers, server); + } else { + fprintf(stderr, "config: line %d: syntax error\n", linenum); + return(1); + } + } + line[0] = '\0'; } } - line[0] = '\0'; } fclose(fp); @@ -272,7 +375,7 @@ int copyfile(char *src, char *dest) { FILE *in, *out; size_t len; - char buf[1025]; + char buf[4097]; in = fopen(src, "r"); if(in == NULL) { @@ -283,7 +386,7 @@ int copyfile(char *src, char *dest) return(1); } - while((len = fread(buf, 1, 1024, in))) { + while((len = fread(buf, 1, 4096, in))) { fwrite(buf, 1, len, out); } |