libalpm
Arch Linux Package Manager Library
sync.c
Go to the documentation of this file.
00001 /*
00002  *  sync.c
00003  *
00004  *  Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org>
00005  *  Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org>
00006  *
00007  *  This program is free software; you can redistribute it and/or modify
00008  *  it under the terms of the GNU General Public License as published by
00009  *  the Free Software Foundation; either version 2 of the License, or
00010  *  (at your option) any later version.
00011  *
00012  *  This program is distributed in the hope that it will be useful,
00013  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  *  GNU General Public License for more details.
00016  *
00017  *  You should have received a copy of the GNU General Public License
00018  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
00019  */
00020 
00021 #include <stdio.h>
00022 #include <stdlib.h>
00023 #include <string.h>
00024 #include <limits.h>
00025 #include <unistd.h>
00026 #include <dirent.h>
00027 #include <sys/stat.h>
00028 
00029 #include <alpm.h>
00030 #include <alpm_list.h>
00031 
00032 /* pacman */
00033 #include "pacman.h"
00034 #include "util.h"
00035 #include "package.h"
00036 #include "conf.h"
00037 
00038 /* if keep_used != 0, then the db files which match an used syncdb
00039  * will be kept  */
00040 static int sync_cleandb(const char *dbpath, int keep_used)
00041 {
00042     DIR *dir;
00043     struct dirent *ent;
00044     alpm_list_t *syncdbs;
00045 
00046     dir = opendir(dbpath);
00047     if(dir == NULL) {
00048         pm_printf(ALPM_LOG_ERROR, _("could not access database directory\n"));
00049         return 1;
00050     }
00051 
00052     syncdbs = alpm_option_get_syncdbs(config->handle);
00053 
00054     rewinddir(dir);
00055     /* step through the directory one file at a time */
00056     while((ent = readdir(dir)) != NULL) {
00057         char path[PATH_MAX];
00058         struct stat buf;
00059         int found = 0;
00060         const char *dname = ent->d_name;
00061         size_t len;
00062 
00063         if(strcmp(dname, ".") == 0 || strcmp(dname, "..") == 0) {
00064             continue;
00065         }
00066         /* skip the local and sync directories */
00067         if(strcmp(dname, "sync") == 0 || strcmp(dname, "local") == 0) {
00068             continue;
00069         }
00070         /* skip the db.lck file */
00071         if(strcmp(dname, "db.lck") == 0) {
00072             continue;
00073         }
00074 
00075         /* build the full path */
00076         snprintf(path, PATH_MAX, "%s%s", dbpath, dname);
00077 
00078         /* remove all non-skipped directories and non-database files */
00079         stat(path, &buf);
00080         len = strlen(path);
00081         if(S_ISDIR(buf.st_mode) || strcmp(path + len - 3, ".db") != 0) {
00082             if(rmrf(path)) {
00083                 pm_printf(ALPM_LOG_ERROR,
00084                     _("could not remove %s\n"), path);
00085                 closedir(dir);
00086                 return 1;
00087             }
00088             continue;
00089         }
00090 
00091         if(keep_used) {
00092             alpm_list_t *i;
00093             len = strlen(dname);
00094             char *dbname = strndup(dname, len - 3);
00095             for(i = syncdbs; i && !found; i = alpm_list_next(i)) {
00096                 alpm_db_t *db = i->data;
00097                 found = !strcmp(dbname, alpm_db_get_name(db));
00098             }
00099             free(dbname);
00100         }
00101         /* We have a database that doesn't match any syncdb.
00102          * Ask the user if he wants to remove it. */
00103         if(!found) {
00104             if(!yesno(_("Do you want to remove %s?"), path)) {
00105                 continue;
00106             }
00107 
00108             if(rmrf(path)) {
00109                 pm_printf(ALPM_LOG_ERROR,
00110                     _("could not remove %s\n"), path);
00111                 closedir(dir);
00112                 return 1;
00113             }
00114         }
00115     }
00116     closedir(dir);
00117     return 0;
00118 }
00119 
00120 static int sync_cleandb_all(void)
00121 {
00122     const char *dbpath;
00123     char *newdbpath;
00124     int ret = 0;
00125 
00126     dbpath = alpm_option_get_dbpath(config->handle);
00127     printf(_("Database directory: %s\n"), dbpath);
00128     if(!yesno(_("Do you want to remove unused repositories?"))) {
00129         return 0;
00130     }
00131     /* The sync dbs were previously put in dbpath/ but are now in dbpath/sync/.
00132      * We will clean everything in dbpath/ except local/, sync/ and db.lck, and
00133      * only the unused sync dbs in dbpath/sync/ */
00134     ret += sync_cleandb(dbpath, 0);
00135 
00136     if(asprintf(&newdbpath, "%s%s", dbpath, "sync/") < 0) {
00137         ret += 1;
00138         return ret;
00139     }
00140     ret += sync_cleandb(newdbpath, 1);
00141     free(newdbpath);
00142 
00143     printf(_("Database directory cleaned up\n"));
00144     return ret;
00145 }
00146 
00147 static int sync_cleancache(int level)
00148 {
00149     alpm_list_t *i;
00150     alpm_list_t *sync_dbs = alpm_option_get_syncdbs(config->handle);
00151     alpm_db_t *db_local = alpm_option_get_localdb(config->handle);
00152     alpm_list_t *cachedirs = alpm_option_get_cachedirs(config->handle);
00153     int ret = 0;
00154 
00155     for(i = cachedirs; i; i = alpm_list_next(i)) {
00156         printf(_("Cache directory: %s\n"), (const char *)i->data);
00157     }
00158 
00159     if(!config->cleanmethod) {
00160         /* default to KeepInstalled if user did not specify */
00161         config->cleanmethod = PM_CLEAN_KEEPINST;
00162     }
00163 
00164     if(level == 1) {
00165         printf(_("Packages to keep:\n"));
00166         if(config->cleanmethod & PM_CLEAN_KEEPINST) {
00167             printf(_("  All locally installed packages\n"));
00168         }
00169         if(config->cleanmethod & PM_CLEAN_KEEPCUR) {
00170             printf(_("  All current sync database packages\n"));
00171         }
00172         if(!yesno(_("Do you want to remove all other packages from cache?"))) {
00173             return 0;
00174         }
00175         printf(_("removing old packages from cache...\n"));
00176     } else {
00177         if(!noyes(_("Do you want to remove ALL files from cache?"))) {
00178             return 0;
00179         }
00180         printf(_("removing all files from cache...\n"));
00181     }
00182 
00183     for(i = cachedirs; i; i = alpm_list_next(i)) {
00184         const char *cachedir = i->data;
00185         DIR *dir = opendir(cachedir);
00186         struct dirent *ent;
00187 
00188         if(dir == NULL) {
00189             pm_printf(ALPM_LOG_ERROR,
00190                     _("could not access cache directory %s\n"), cachedir);
00191             ret++;
00192             continue;
00193         }
00194 
00195         rewinddir(dir);
00196         /* step through the directory one file at a time */
00197         while((ent = readdir(dir)) != NULL) {
00198             char path[PATH_MAX];
00199             size_t pathlen;
00200             int delete = 1;
00201             alpm_pkg_t *localpkg = NULL, *pkg = NULL;
00202             const char *local_name, *local_version;
00203 
00204             if(strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0) {
00205                 continue;
00206             }
00207             /* build the full filepath */
00208             snprintf(path, PATH_MAX, "%s%s", cachedir, ent->d_name);
00209 
00210             /* short circuit for removing all packages from cache */
00211             if(level > 1) {
00212                 unlink(path);
00213                 continue;
00214             }
00215 
00216             /* we handle .sig files with packages, not separately */
00217             pathlen = strlen(path);
00218             if(strcmp(path + pathlen - 4, ".sig") == 0) {
00219                 continue;
00220             }
00221 
00222             /* attempt to load the package, prompt removal on failures as we may have
00223              * files here that aren't valid packages. we also don't need a full
00224              * load of the package, just the metadata. */
00225             if(alpm_pkg_load(config->handle, path, 0, 0, &localpkg) != 0
00226                     || localpkg == NULL) {
00227                 if(yesno(_("File %s does not seem to be a valid package, remove it?"),
00228                             path)) {
00229                     if(localpkg) {
00230                         alpm_pkg_free(localpkg);
00231                     }
00232                     unlink(path);
00233                 }
00234                 continue;
00235             }
00236             local_name = alpm_pkg_get_name(localpkg);
00237             local_version = alpm_pkg_get_version(localpkg);
00238 
00239             if(config->cleanmethod & PM_CLEAN_KEEPINST) {
00240                 /* check if this package is in the local DB */
00241                 pkg = alpm_db_get_pkg(db_local, local_name);
00242                 if(pkg != NULL && alpm_pkg_vercmp(local_version,
00243                             alpm_pkg_get_version(pkg)) == 0) {
00244                     /* package was found in local DB and version matches, keep it */
00245                     pm_printf(ALPM_LOG_DEBUG, "pkg %s-%s found in local db\n",
00246                             local_name, local_version);
00247                     delete = 0;
00248                 }
00249             }
00250             if(config->cleanmethod & PM_CLEAN_KEEPCUR) {
00251                 alpm_list_t *j;
00252                 /* check if this package is in a sync DB */
00253                 for(j = sync_dbs; j && delete; j = alpm_list_next(j)) {
00254                     alpm_db_t *db = j->data;
00255                     pkg = alpm_db_get_pkg(db, local_name);
00256                     if(pkg != NULL && alpm_pkg_vercmp(local_version,
00257                                 alpm_pkg_get_version(pkg)) == 0) {
00258                         /* package was found in a sync DB and version matches, keep it */
00259                         pm_printf(ALPM_LOG_DEBUG, "pkg %s-%s found in sync db\n",
00260                                 local_name, local_version);
00261                         delete = 0;
00262                     }
00263                 }
00264             }
00265             /* free the local file package */
00266             alpm_pkg_free(localpkg);
00267 
00268             if(delete) {
00269                 unlink(path);
00270                 /* unlink a signature file if present too */
00271                 if(PATH_MAX - 5 >= pathlen) {
00272                     strcpy(path + pathlen, ".sig");
00273                     unlink(path);
00274                 }
00275             }
00276         }
00277         closedir(dir);
00278     }
00279 
00280     return ret;
00281 }
00282 
00283 static int sync_synctree(int level, alpm_list_t *syncs)
00284 {
00285     alpm_list_t *i;
00286     int success = 0, ret;
00287 
00288     for(i = syncs; i; i = alpm_list_next(i)) {
00289         alpm_db_t *db = i->data;
00290 
00291         ret = alpm_db_update((level < 2 ? 0 : 1), db);
00292         if(ret < 0) {
00293             pm_printf(ALPM_LOG_ERROR, _("failed to update %s (%s)\n"),
00294                     alpm_db_get_name(db), alpm_strerror(alpm_errno(config->handle)));
00295         } else if(ret == 1) {
00296             printf(_(" %s is up to date\n"), alpm_db_get_name(db));
00297             success++;
00298         } else {
00299             success++;
00300         }
00301     }
00302 
00303     /* We should always succeed if at least one DB was upgraded - we may possibly
00304      * fail later with unresolved deps, but that should be rare, and would be
00305      * expected
00306      */
00307     if(!success) {
00308         pm_printf(ALPM_LOG_ERROR, _("failed to synchronize any databases\n"));
00309         trans_init_error();
00310     }
00311     return (success > 0);
00312 }
00313 
00314 static void print_installed(alpm_db_t *db_local, alpm_pkg_t *pkg)
00315 {
00316     const char *pkgname = alpm_pkg_get_name(pkg);
00317     const char *pkgver = alpm_pkg_get_version(pkg);
00318     alpm_pkg_t *lpkg = alpm_db_get_pkg(db_local, pkgname);
00319     if(lpkg) {
00320         const char *lpkgver = alpm_pkg_get_version(lpkg);
00321         if(strcmp(lpkgver,pkgver) == 0) {
00322             printf(" [%s]", _("installed"));
00323         } else {
00324             printf(" [%s: %s]", _("installed"), lpkgver);
00325         }
00326     }
00327 }
00328 
00329 /* search the sync dbs for a matching package */
00330 static int sync_search(alpm_list_t *syncs, alpm_list_t *targets)
00331 {
00332     alpm_list_t *i, *j, *ret;
00333     int freelist;
00334     int found = 0;
00335     alpm_db_t *db_local = alpm_option_get_localdb(config->handle);
00336 
00337     for(i = syncs; i; i = alpm_list_next(i)) {
00338         alpm_db_t *db = i->data;
00339         /* if we have a targets list, search for packages matching it */
00340         if(targets) {
00341             ret = alpm_db_search(db, targets);
00342             freelist = 1;
00343         } else {
00344             ret = alpm_db_get_pkgcache(db);
00345             freelist = 0;
00346         }
00347         if(ret == NULL) {
00348             continue;
00349         } else {
00350             found = 1;
00351         }
00352         for(j = ret; j; j = alpm_list_next(j)) {
00353             alpm_list_t *grp;
00354             alpm_pkg_t *pkg = j->data;
00355 
00356             if(!config->quiet) {
00357                 printf("%s/%s %s", alpm_db_get_name(db), alpm_pkg_get_name(pkg),
00358                              alpm_pkg_get_version(pkg));
00359             } else {
00360                 fputs(alpm_pkg_get_name(pkg), stdout);
00361             }
00362 
00363             if(!config->quiet) {
00364                 if((grp = alpm_pkg_get_groups(pkg)) != NULL) {
00365                     alpm_list_t *k;
00366                     fputs(" (", stdout);
00367                     for(k = grp; k; k = alpm_list_next(k)) {
00368                         const char *group = k->data;
00369                         fputs(group, stdout);
00370                         if(alpm_list_next(k)) {
00371                             /* only print a spacer if there are more groups */
00372                             putchar(' ');
00373                         }
00374                     }
00375                     putchar(')');
00376                 }
00377 
00378                 print_installed(db_local, pkg);
00379 
00380                 /* we need a newline and initial indent first */
00381                 printf("\n    ");
00382                 indentprint(alpm_pkg_get_desc(pkg), 4);
00383             }
00384             printf("\n");
00385         }
00386         /* we only want to free if the list was a search list */
00387         if(freelist) {
00388             alpm_list_free(ret);
00389         }
00390     }
00391 
00392     return !found;
00393 }
00394 
00395 static int sync_group(int level, alpm_list_t *syncs, alpm_list_t *targets)
00396 {
00397     alpm_list_t *i, *j, *k;
00398 
00399     if(targets) {
00400         for(i = targets; i; i = alpm_list_next(i)) {
00401             const char *grpname = i->data;
00402             for(j = syncs; j; j = alpm_list_next(j)) {
00403                 alpm_db_t *db = j->data;
00404                 alpm_group_t *grp = alpm_db_readgroup(db, grpname);
00405 
00406                 if(grp) {
00407                     /* get names of packages in group */
00408                     for(k = grp->packages; k; k = alpm_list_next(k)) {
00409                         if(!config->quiet) {
00410                             printf("%s %s\n", grpname,
00411                                     alpm_pkg_get_name(k->data));
00412                         } else {
00413                             printf("%s\n", alpm_pkg_get_name(k->data));
00414                         }
00415                     }
00416                 }
00417             }
00418         }
00419     } else {
00420         for(i = syncs; i; i = alpm_list_next(i)) {
00421             alpm_db_t *db = i->data;
00422 
00423             for(j = alpm_db_get_groupcache(db); j; j = alpm_list_next(j)) {
00424                 alpm_group_t *grp = j->data;
00425 
00426                 if(level > 1) {
00427                     for(k = grp->packages; k; k = alpm_list_next(k)) {
00428                         printf("%s %s\n", grp->name,
00429                                 alpm_pkg_get_name(k->data));
00430                     }
00431                 } else {
00432                     /* print grp names only, no package names */
00433                     printf("%s\n", grp->name);
00434                 }
00435             }
00436         }
00437     }
00438 
00439     return 0;
00440 }
00441 
00442 static int sync_info(alpm_list_t *syncs, alpm_list_t *targets)
00443 {
00444     alpm_list_t *i, *j, *k;
00445     int ret = 0;
00446 
00447     if(targets) {
00448         for(i = targets; i; i = alpm_list_next(i)) {
00449             const char *target = i->data;
00450             char *name = strdup(target);
00451             char *repo, *pkgstr;
00452             int foundpkg = 0, founddb = 0;
00453 
00454             pkgstr = strchr(name, '/');
00455             if(pkgstr) {
00456                 repo = name;
00457                 *pkgstr = '\0';
00458                 ++pkgstr;
00459             } else {
00460                 repo = NULL;
00461                 pkgstr = name;
00462             }
00463 
00464             for(j = syncs; j; j = alpm_list_next(j)) {
00465                 alpm_db_t *db = j->data;
00466                 if(repo && strcmp(repo, alpm_db_get_name(db)) != 0) {
00467                     continue;
00468                 }
00469                 founddb = 1;
00470 
00471                 for(k = alpm_db_get_pkgcache(db); k; k = alpm_list_next(k)) {
00472                     alpm_pkg_t *pkg = k->data;
00473 
00474                     if(strcmp(alpm_pkg_get_name(pkg), pkgstr) == 0) {
00475                         dump_pkg_full(pkg, config->op_s_info > 1);
00476                         foundpkg = 1;
00477                         break;
00478                     }
00479                 }
00480             }
00481 
00482             if(!founddb) {
00483                 pm_printf(ALPM_LOG_ERROR,
00484                         _("repository '%s' does not exist\n"), repo);
00485                 ret++;
00486             }
00487             if(!foundpkg) {
00488                 pm_printf(ALPM_LOG_ERROR,
00489                         _("package '%s' was not found\n"), target);
00490                 ret++;
00491             }
00492             free(name);
00493         }
00494     } else {
00495         for(i = syncs; i; i = alpm_list_next(i)) {
00496             alpm_db_t *db = i->data;
00497 
00498             for(j = alpm_db_get_pkgcache(db); j; j = alpm_list_next(j)) {
00499                 alpm_pkg_t *pkg = j->data;
00500                 dump_pkg_full(pkg, config->op_s_info > 1);
00501             }
00502         }
00503     }
00504 
00505     return ret;
00506 }
00507 
00508 static int sync_list(alpm_list_t *syncs, alpm_list_t *targets)
00509 {
00510     alpm_list_t *i, *j, *ls = NULL;
00511     alpm_db_t *db_local = alpm_option_get_localdb(config->handle);
00512 
00513     if(targets) {
00514         for(i = targets; i; i = alpm_list_next(i)) {
00515             const char *repo = i->data;
00516             alpm_db_t *db = NULL;
00517 
00518             for(j = syncs; j; j = alpm_list_next(j)) {
00519                 alpm_db_t *d = j->data;
00520 
00521                 if(strcmp(repo, alpm_db_get_name(d)) == 0) {
00522                     db = d;
00523                     break;
00524                 }
00525             }
00526 
00527             if(db == NULL) {
00528                 pm_printf(ALPM_LOG_ERROR,
00529                     _("repository \"%s\" was not found.\n"),repo);
00530                 alpm_list_free(ls);
00531                 return 1;
00532             }
00533 
00534             ls = alpm_list_add(ls, db);
00535         }
00536     } else {
00537         ls = syncs;
00538     }
00539 
00540     for(i = ls; i; i = alpm_list_next(i)) {
00541         alpm_db_t *db = i->data;
00542 
00543         for(j = alpm_db_get_pkgcache(db); j; j = alpm_list_next(j)) {
00544             alpm_pkg_t *pkg = j->data;
00545 
00546             if(!config->quiet) {
00547                 printf("%s %s %s", alpm_db_get_name(db), alpm_pkg_get_name(pkg),
00548                         alpm_pkg_get_version(pkg));
00549                 print_installed(db_local, pkg);
00550                 printf("\n");
00551             } else {
00552                 printf("%s\n", alpm_pkg_get_name(pkg));
00553             }
00554         }
00555     }
00556 
00557     if(targets) {
00558         alpm_list_free(ls);
00559     }
00560 
00561     return 0;
00562 }
00563 
00564 static alpm_list_t *syncfirst(void) {
00565     alpm_list_t *i, *res = NULL;
00566     alpm_db_t *db_local = alpm_option_get_localdb(config->handle);
00567     alpm_list_t *syncdbs = alpm_option_get_syncdbs(config->handle);
00568 
00569     for(i = config->syncfirst; i; i = alpm_list_next(i)) {
00570         const char *pkgname = i->data;
00571         alpm_pkg_t *pkg = alpm_db_get_pkg(db_local, pkgname);
00572         if(pkg == NULL) {
00573             continue;
00574         }
00575 
00576         if(alpm_sync_newversion(pkg, syncdbs)) {
00577             res = alpm_list_add(res, strdup(pkgname));
00578         }
00579     }
00580 
00581     return res;
00582 }
00583 
00584 static alpm_db_t *get_db(const char *dbname)
00585 {
00586     alpm_list_t *i;
00587     for(i = alpm_option_get_syncdbs(config->handle); i; i = i->next) {
00588         alpm_db_t *db = i->data;
00589         if(strcmp(alpm_db_get_name(db), dbname) == 0) {
00590             return db;
00591         }
00592     }
00593     return NULL;
00594 }
00595 
00596 static int process_pkg(alpm_pkg_t *pkg)
00597 {
00598     int ret = alpm_add_pkg(config->handle, pkg);
00599 
00600     if(ret == -1) {
00601         alpm_errno_t err = alpm_errno(config->handle);
00602         if(err == ALPM_ERR_TRANS_DUP_TARGET
00603                 || err == ALPM_ERR_PKG_IGNORED) {
00604             /* just skip duplicate or ignored targets */
00605             pm_printf(ALPM_LOG_WARNING, _("skipping target: %s\n"), alpm_pkg_get_name(pkg));
00606             return 0;
00607         } else {
00608             pm_printf(ALPM_LOG_ERROR, "'%s': %s\n", alpm_pkg_get_name(pkg),
00609                     alpm_strerror(err));
00610             return 1;
00611         }
00612     }
00613     config->explicit_adds = alpm_list_add(config->explicit_adds, pkg);
00614     return 0;
00615 }
00616 
00617 static int process_group(alpm_list_t *dbs, const char *group, int error)
00618 {
00619     int ret = 0;
00620     alpm_list_t *i;
00621     alpm_list_t *pkgs = alpm_find_group_pkgs(dbs, group);
00622     int count = alpm_list_count(pkgs);
00623 
00624     if(!count) {
00625         pm_printf(ALPM_LOG_ERROR, _("target not found: %s\n"), group);
00626         return 1;
00627     }
00628 
00629     if(error) {
00630         /* we already know another target errored. there is no reason to prompt the
00631          * user here; we already validated the group name so just move on since we
00632          * won't actually be installing anything anyway. */
00633         goto cleanup;
00634     }
00635 
00636     if(config->print == 0) {
00637         printf(_(":: There are %d members in group %s:\n"), count,
00638                 group);
00639         select_display(pkgs);
00640         char *array = malloc(count);
00641         if(!array) {
00642             ret = 1;
00643             goto cleanup;
00644         }
00645         if(multiselect_question(array, count)) {
00646             ret = 1;
00647             free(array);
00648             goto cleanup;
00649         }
00650         int n = 0;
00651         for(i = pkgs; i; i = alpm_list_next(i)) {
00652             if(array[n++] == 0)
00653                 continue;
00654             alpm_pkg_t *pkg = i->data;
00655 
00656             if(process_pkg(pkg) == 1) {
00657                 ret = 1;
00658                 free(array);
00659                 goto cleanup;
00660             }
00661         }
00662         free(array);
00663     } else {
00664         for(i = pkgs; i; i = alpm_list_next(i)) {
00665             alpm_pkg_t *pkg = i->data;
00666 
00667             if(process_pkg(pkg) == 1) {
00668                 ret = 1;
00669                 goto cleanup;
00670             }
00671         }
00672     }
00673 
00674 cleanup:
00675     alpm_list_free(pkgs);
00676     return ret;
00677 }
00678 
00679 static int process_targname(alpm_list_t *dblist, const char *targname,
00680         int error)
00681 {
00682     alpm_pkg_t *pkg = alpm_find_dbs_satisfier(config->handle, dblist, targname);
00683 
00684     /* #FS#23342 - skip ignored packages when user says no */
00685     if(alpm_errno(config->handle) == ALPM_ERR_PKG_IGNORED) {
00686             pm_printf(ALPM_LOG_WARNING, _("skipping target: %s\n"), targname);
00687             return 0;
00688     }
00689 
00690     if(pkg) {
00691         return process_pkg(pkg);
00692     }
00693     /* fallback on group */
00694     return process_group(dblist, targname, error);
00695 }
00696 
00697 static int process_target(const char *target, int error)
00698 {
00699     /* process targets */
00700     char *targstring = strdup(target);
00701     char *targname = strchr(targstring, '/');
00702     int ret = 0;
00703     alpm_list_t *dblist;
00704 
00705     if(targname && targname != targstring) {
00706         alpm_db_t *db;
00707         const char *dbname;
00708 
00709         *targname = '\0';
00710         targname++;
00711         dbname = targstring;
00712         db = get_db(dbname);
00713         if(!db) {
00714             pm_printf(ALPM_LOG_ERROR, _("database not found: %s\n"),
00715                     dbname);
00716             ret = 1;
00717             goto cleanup;
00718         }
00719         dblist = alpm_list_add(NULL, db);
00720         ret = process_targname(dblist, targname, error);
00721         alpm_list_free(dblist);
00722     } else {
00723         targname = targstring;
00724         dblist = alpm_option_get_syncdbs(config->handle);
00725         ret = process_targname(dblist, targname, error);
00726     }
00727 
00728 cleanup:
00729     free(targstring);
00730     if(ret && access(target, R_OK) == 0) {
00731         pm_printf(ALPM_LOG_WARNING,
00732                 _("'%s' is a file, did you mean %s instead of %s?\n"),
00733                 target, "-U/--upgrade", "-S/--sync");
00734     }
00735     return ret;
00736 }
00737 
00738 static int sync_trans(alpm_list_t *targets)
00739 {
00740     int retval = 0;
00741     alpm_list_t *i;
00742 
00743     /* Step 1: create a new transaction... */
00744     if(trans_init(config->flags, 1) == -1) {
00745         return 1;
00746     }
00747 
00748     /* process targets */
00749     for(i = targets; i; i = alpm_list_next(i)) {
00750         const char *targ = i->data;
00751         if(process_target(targ, retval) == 1) {
00752             retval = 1;
00753         }
00754     }
00755 
00756     if(retval) {
00757         trans_release();
00758         return retval;
00759     }
00760 
00761     if(config->op_s_upgrade) {
00762         printf(_(":: Starting full system upgrade...\n"));
00763         alpm_logaction(config->handle, "starting full system upgrade\n");
00764         if(alpm_sync_sysupgrade(config->handle, config->op_s_upgrade >= 2) == -1) {
00765             pm_printf(ALPM_LOG_ERROR, "%s\n", alpm_strerror(alpm_errno(config->handle)));
00766             trans_release();
00767             return 1;
00768         }
00769     }
00770 
00771     return sync_prepare_execute();
00772 }
00773 
00774 int sync_prepare_execute(void)
00775 {
00776     alpm_list_t *i, *packages, *data = NULL;
00777     int retval = 0;
00778 
00779     /* Step 2: "compute" the transaction based on targets and flags */
00780     if(alpm_trans_prepare(config->handle, &data) == -1) {
00781         alpm_errno_t err = alpm_errno(config->handle);
00782         pm_printf(ALPM_LOG_ERROR, _("failed to prepare transaction (%s)\n"),
00783                 alpm_strerror(err));
00784         switch(err) {
00785             case ALPM_ERR_PKG_INVALID_ARCH:
00786                 for(i = data; i; i = alpm_list_next(i)) {
00787                     const char *pkg = i->data;
00788                     printf(_(":: package %s does not have a valid architecture\n"), pkg);
00789                 }
00790                 break;
00791             case ALPM_ERR_UNSATISFIED_DEPS:
00792                 for(i = data; i; i = alpm_list_next(i)) {
00793                     alpm_depmissing_t *miss = i->data;
00794                     char *depstring = alpm_dep_compute_string(miss->depend);
00795                     printf(_(":: %s: requires %s\n"), miss->target, depstring);
00796                     free(depstring);
00797                 }
00798                 break;
00799             case ALPM_ERR_CONFLICTING_DEPS:
00800                 for(i = data; i; i = alpm_list_next(i)) {
00801                     alpm_conflict_t *conflict = i->data;
00802                     /* only print reason if it contains new information */
00803                     if(conflict->reason->mod == ALPM_DEP_MOD_ANY) {
00804                         printf(_(":: %s and %s are in conflict\n"),
00805                                 conflict->package1, conflict->package2);
00806                     } else {
00807                         char *reason = alpm_dep_compute_string(conflict->reason);
00808                         printf(_(":: %s and %s are in conflict (%s)\n"),
00809                                 conflict->package1, conflict->package2, reason);
00810                         free(reason);
00811                     }
00812                 }
00813                 break;
00814             default:
00815                 break;
00816         }
00817         retval = 1;
00818         goto cleanup;
00819     }
00820 
00821     packages = alpm_trans_get_add(config->handle);
00822     if(packages == NULL) {
00823         /* nothing to do: just exit without complaining */
00824         if(!config->print) {
00825             printf(_(" there is nothing to do\n"));
00826         }
00827         goto cleanup;
00828     }
00829 
00830     /* Step 3: actually perform the operation */
00831     if(config->print) {
00832         print_packages(packages);
00833         goto cleanup;
00834     }
00835 
00836     display_targets();
00837     printf("\n");
00838 
00839     int confirm;
00840     if(config->op_s_downloadonly) {
00841         confirm = yesno(_("Proceed with download?"));
00842     } else {
00843         confirm = yesno(_("Proceed with installation?"));
00844     }
00845     if(!confirm) {
00846         goto cleanup;
00847     }
00848 
00849     if(alpm_trans_commit(config->handle, &data) == -1) {
00850         alpm_errno_t err = alpm_errno(config->handle);
00851         pm_printf(ALPM_LOG_ERROR, _("failed to commit transaction (%s)\n"),
00852                 alpm_strerror(err));
00853         switch(err) {
00854             case ALPM_ERR_FILE_CONFLICTS:
00855                 for(i = data; i; i = alpm_list_next(i)) {
00856                     alpm_fileconflict_t *conflict = i->data;
00857                     switch(conflict->type) {
00858                         case ALPM_FILECONFLICT_TARGET:
00859                             printf(_("%s exists in both '%s' and '%s'\n"),
00860                                     conflict->file, conflict->target, conflict->ctarget);
00861                             break;
00862                         case ALPM_FILECONFLICT_FILESYSTEM:
00863                             printf(_("%s: %s exists in filesystem\n"),
00864                                     conflict->target, conflict->file);
00865                             break;
00866                     }
00867                 }
00868                 break;
00869             case ALPM_ERR_PKG_INVALID:
00870             case ALPM_ERR_PKG_INVALID_CHECKSUM:
00871             case ALPM_ERR_PKG_INVALID_SIG:
00872             case ALPM_ERR_DLT_INVALID:
00873                 for(i = data; i; i = alpm_list_next(i)) {
00874                     const char *filename = i->data;
00875                     printf(_("%s is invalid or corrupted\n"), filename);
00876                 }
00877                 break;
00878             default:
00879                 break;
00880         }
00881         /* TODO: stderr? */
00882         printf(_("Errors occurred, no packages were upgraded.\n"));
00883         retval = 1;
00884         goto cleanup;
00885     }
00886 
00887     /* Step 4: release transaction resources */
00888 cleanup:
00889     if(data) {
00890         FREELIST(data);
00891     }
00892     if(trans_release() == -1) {
00893         retval = 1;
00894     }
00895 
00896     return retval;
00897 }
00898 
00899 int pacman_sync(alpm_list_t *targets)
00900 {
00901     alpm_list_t *sync_dbs = NULL;
00902 
00903     /* clean the cache */
00904     if(config->op_s_clean) {
00905         int ret = 0;
00906 
00907         if(trans_init(0, 0) == -1) {
00908             return 1;
00909         }
00910 
00911         ret += sync_cleancache(config->op_s_clean);
00912         printf("\n");
00913         ret += sync_cleandb_all();
00914 
00915         if(trans_release() == -1) {
00916             ret++;
00917         }
00918 
00919         return ret;
00920     }
00921 
00922     if(check_syncdbs(1, 0)) {
00923         return 1;
00924     }
00925 
00926     sync_dbs = alpm_option_get_syncdbs(config->handle);
00927 
00928     if(config->op_s_sync) {
00929         /* grab a fresh package list */
00930         printf(_(":: Synchronizing package databases...\n"));
00931         alpm_logaction(config->handle, "synchronizing package lists\n");
00932         if(!sync_synctree(config->op_s_sync, sync_dbs)) {
00933             return 1;
00934         }
00935     }
00936 
00937     if(check_syncdbs(1, 1)) {
00938         return 1;
00939     }
00940 
00941     /* search for a package */
00942     if(config->op_s_search) {
00943         return sync_search(sync_dbs, targets);
00944     }
00945 
00946     /* look for groups */
00947     if(config->group) {
00948         return sync_group(config->group, sync_dbs, targets);
00949     }
00950 
00951     /* get package info */
00952     if(config->op_s_info) {
00953         return sync_info(sync_dbs, targets);
00954     }
00955 
00956     /* get a listing of files in sync DBs */
00957     if(config->op_q_list) {
00958         return sync_list(sync_dbs, targets);
00959     }
00960 
00961     if(targets == NULL) {
00962         if(config->op_s_upgrade) {
00963             /* proceed */
00964         } else if(config->op_s_sync) {
00965             return 0;
00966         } else {
00967             /* don't proceed here unless we have an operation that doesn't require a
00968              * target list */
00969             pm_printf(ALPM_LOG_ERROR, _("no targets specified (use -h for help)\n"));
00970             return 1;
00971         }
00972     }
00973 
00974     alpm_list_t *targs = alpm_list_strdup(targets);
00975     if(!config->op_s_downloadonly && !config->print) {
00976         /* check for newer versions of packages to be upgraded first */
00977         alpm_list_t *packages = syncfirst();
00978         if(packages) {
00979             /* Do not ask user if all the -S targets are SyncFirst packages, see FS#15810 */
00980             alpm_list_t *tmp = NULL;
00981             if(config->op_s_upgrade || (tmp = alpm_list_diff(targets, packages, (alpm_list_fn_cmp)strcmp))) {
00982                 alpm_list_free(tmp);
00983                 printf(_(":: The following packages should be upgraded first :\n"));
00984                 list_display("   ", packages);
00985                 if(yesno(_(":: Do you want to cancel the current operation\n"
00986                                 ":: and upgrade these packages now?"))) {
00987                     FREELIST(targs);
00988                     targs = packages;
00989                     config->flags = 0;
00990                     config->flags |= ALPM_TRANS_FLAG_RECURSE;
00991                     config->flags |= ALPM_TRANS_FLAG_NEEDED;
00992                     config->op_s_upgrade = 0;
00993                 } else {
00994                     FREELIST(packages);
00995                 }
00996                 printf("\n");
00997             } else {
00998                 pm_printf(ALPM_LOG_DEBUG, "skipping SyncFirst dialog\n");
00999                 FREELIST(packages);
01000             }
01001         }
01002     }
01003 
01004     int ret = sync_trans(targs);
01005     FREELIST(targs);
01006 
01007     return ret;
01008 }
01009 
01010 /* vim: set ts=2 sw=2 noet: */