Require handle for alpm_pkg_load()
[pacman-ng.git] / src / pacman / sync.c
blobbe6f147f7305562d887f8f04a37f4b5fd4025693
1 /*
2 * sync.c
4 * Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org>
5 * Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org>
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
21 #include "config.h"
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <limits.h>
27 #include <unistd.h>
28 #include <dirent.h>
29 #include <sys/stat.h>
31 #include <alpm.h>
32 #include <alpm_list.h>
34 /* pacman */
35 #include "pacman.h"
36 #include "util.h"
37 #include "package.h"
38 #include "conf.h"
40 /* if keep_used != 0, then the db files which match an used syncdb
41 * will be kept */
42 static int sync_cleandb(const char *dbpath, int keep_used)
44 DIR *dir;
45 struct dirent *ent;
46 alpm_list_t *syncdbs;
48 dir = opendir(dbpath);
49 if(dir == NULL) {
50 pm_fprintf(stderr, PM_LOG_ERROR, _("could not access database directory\n"));
51 return 1;
54 syncdbs = alpm_option_get_syncdbs(config->handle);
56 rewinddir(dir);
57 /* step through the directory one file at a time */
58 while((ent = readdir(dir)) != NULL) {
59 char path[PATH_MAX];
60 struct stat buf;
61 int found = 0;
62 const char *dname = ent->d_name;
63 size_t len;
65 if(strcmp(dname, ".") == 0 || strcmp(dname, "..") == 0) {
66 continue;
68 /* skip the local and sync directories */
69 if(strcmp(dname, "sync") == 0 || strcmp(dname, "local") == 0) {
70 continue;
72 /* skip the db.lck file */
73 if(strcmp(dname, "db.lck") == 0) {
74 continue;
77 /* build the full path */
78 snprintf(path, PATH_MAX, "%s%s", dbpath, dname);
80 /* remove all non-skipped directories and non-database files */
81 stat(path, &buf);
82 len = strlen(path);
83 if(S_ISDIR(buf.st_mode) || strcmp(path + len - 3, ".db") != 0) {
84 if(rmrf(path)) {
85 pm_fprintf(stderr, PM_LOG_ERROR,
86 _("could not remove %s\n"), path);
87 closedir(dir);
88 return 1;
90 continue;
93 if(keep_used) {
94 alpm_list_t *i;
95 len = strlen(dname);
96 char *dbname = strndup(dname, len - 3);
97 for(i = syncdbs; i && !found; i = alpm_list_next(i)) {
98 pmdb_t *db = alpm_list_getdata(i);
99 found = !strcmp(dbname, alpm_db_get_name(db));
101 free(dbname);
103 /* We have a database that doesn't match any syncdb.
104 * Ask the user if he wants to remove it. */
105 if(!found) {
106 if(!yesno(_("Do you want to remove %s?"), path)) {
107 continue;
110 if(rmrf(path)) {
111 pm_fprintf(stderr, PM_LOG_ERROR,
112 _("could not remove %s\n"), path);
113 closedir(dir);
114 return 1;
118 closedir(dir);
119 return 0;
122 static int sync_cleandb_all(void)
124 const char *dbpath;
125 char newdbpath[PATH_MAX];
126 int ret = 0;
128 dbpath = alpm_option_get_dbpath(config->handle);
129 printf(_("Database directory: %s\n"), dbpath);
130 if(!yesno(_("Do you want to remove unused repositories?"))) {
131 return 0;
133 /* The sync dbs were previously put in dbpath/ but are now in dbpath/sync/.
134 * We will clean everything in dbpath/ except local/, sync/ and db.lck, and
135 * only the unused sync dbs in dbpath/sync/ */
136 ret += sync_cleandb(dbpath, 0);
138 sprintf(newdbpath, "%s%s", dbpath, "sync/");
139 ret += sync_cleandb(newdbpath, 1);
141 printf(_("Database directory cleaned up\n"));
142 return ret;
145 static int sync_cleancache(int level)
147 alpm_list_t *i;
148 alpm_list_t *sync_dbs = alpm_option_get_syncdbs(config->handle);
149 pmdb_t *db_local = alpm_option_get_localdb(config->handle);
150 alpm_list_t *cachedirs = alpm_option_get_cachedirs(config->handle);
151 int ret = 0;
153 for(i = cachedirs; i; i = alpm_list_next(i)) {
154 printf(_("Cache directory: %s\n"), (char *)alpm_list_getdata(i));
157 if(!config->cleanmethod) {
158 /* default to KeepInstalled if user did not specify */
159 config->cleanmethod = PM_CLEAN_KEEPINST;
162 if(level == 1) {
163 printf(_("Packages to keep:\n"));
164 if(config->cleanmethod & PM_CLEAN_KEEPINST) {
165 printf(_(" All locally installed packages\n"));
167 if(config->cleanmethod & PM_CLEAN_KEEPCUR) {
168 printf(_(" All current sync database packages\n"));
170 if(!yesno(_("Do you want to remove all other packages from cache?"))) {
171 return 0;
173 printf(_("removing old packages from cache...\n"));
174 } else {
175 if(!noyes(_("Do you want to remove ALL files from cache?"))) {
176 return 0;
178 printf(_("removing all files from cache...\n"));
181 for(i = cachedirs; i; i = alpm_list_next(i)) {
182 const char *cachedir = alpm_list_getdata(i);
183 DIR *dir = opendir(cachedir);
184 struct dirent *ent;
186 if(dir == NULL) {
187 pm_fprintf(stderr, PM_LOG_ERROR,
188 _("could not access cache directory %s\n"), cachedir);
189 ret++;
190 continue;
193 rewinddir(dir);
194 /* step through the directory one file at a time */
195 while((ent = readdir(dir)) != NULL) {
196 char path[PATH_MAX];
197 size_t pathlen;
198 int delete = 1;
199 pmpkg_t *localpkg = NULL, *pkg = NULL;
200 const char *local_name, *local_version;
202 if(strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0) {
203 continue;
205 /* build the full filepath */
206 snprintf(path, PATH_MAX, "%s%s", cachedir, ent->d_name);
208 /* short circuit for removing all packages from cache */
209 if(level > 1) {
210 unlink(path);
211 continue;
214 /* we handle .sig files with packages, not separately */
215 pathlen = strlen(path);
216 if(strcmp(path + pathlen - 4, ".sig") == 0) {
217 continue;
220 /* attempt to load the package, prompt removal on failures as we may have
221 * files here that aren't valid packages. we also don't need a full
222 * load of the package, just the metadata. */
223 if(alpm_pkg_load(config->handle, path, 0, PM_PGP_VERIFY_NEVER, &localpkg) != 0
224 || localpkg == NULL) {
225 if(yesno(_("File %s does not seem to be a valid package, remove it?"),
226 path)) {
227 if(localpkg) {
228 alpm_pkg_free(localpkg);
230 unlink(path);
232 continue;
234 local_name = alpm_pkg_get_name(localpkg);
235 local_version = alpm_pkg_get_version(localpkg);
237 if(config->cleanmethod & PM_CLEAN_KEEPINST) {
238 /* check if this package is in the local DB */
239 pkg = alpm_db_get_pkg(db_local, local_name);
240 if(pkg != NULL && alpm_pkg_vercmp(local_version,
241 alpm_pkg_get_version(pkg)) == 0) {
242 /* package was found in local DB and version matches, keep it */
243 pm_printf(PM_LOG_DEBUG, "pkg %s-%s found in local db\n",
244 local_name, local_version);
245 delete = 0;
248 if(config->cleanmethod & PM_CLEAN_KEEPCUR) {
249 alpm_list_t *j;
250 /* check if this package is in a sync DB */
251 for(j = sync_dbs; j && delete; j = alpm_list_next(j)) {
252 pmdb_t *db = alpm_list_getdata(j);
253 pkg = alpm_db_get_pkg(db, local_name);
254 if(pkg != NULL && alpm_pkg_vercmp(local_version,
255 alpm_pkg_get_version(pkg)) == 0) {
256 /* package was found in a sync DB and version matches, keep it */
257 pm_printf(PM_LOG_DEBUG, "pkg %s-%s found in sync db\n",
258 local_name, local_version);
259 delete = 0;
263 /* free the local file package */
264 alpm_pkg_free(localpkg);
266 if(delete) {
267 unlink(path);
268 /* unlink a signature file if present too */
269 if(PATH_MAX - 5 >= pathlen) {
270 strcpy(path + pathlen, ".sig");
271 unlink(path);
275 closedir(dir);
278 return ret;
281 static int sync_synctree(int level, alpm_list_t *syncs)
283 alpm_list_t *i;
284 int success = 0, ret;
286 if(trans_init(0) == -1) {
287 return 0;
290 for(i = syncs; i; i = alpm_list_next(i)) {
291 pmdb_t *db = alpm_list_getdata(i);
293 ret = alpm_db_update((level < 2 ? 0 : 1), db);
294 if(ret < 0) {
295 pm_fprintf(stderr, PM_LOG_ERROR, _("failed to update %s (%s)\n"),
296 alpm_db_get_name(db), alpm_strerrorlast());
297 } else if(ret == 1) {
298 printf(_(" %s is up to date\n"), alpm_db_get_name(db));
299 success++;
300 } else {
301 success++;
305 if(trans_release() == -1) {
306 return 0;
308 /* We should always succeed if at least one DB was upgraded - we may possibly
309 * fail later with unresolved deps, but that should be rare, and would be
310 * expected
312 if(!success) {
313 pm_fprintf(stderr, PM_LOG_ERROR, _("failed to synchronize any databases\n"));
315 return (success > 0);
318 static void print_installed(pmdb_t *db_local, pmpkg_t *pkg)
320 const char *pkgname = alpm_pkg_get_name(pkg);
321 const char *pkgver = alpm_pkg_get_version(pkg);
322 pmpkg_t *lpkg = alpm_db_get_pkg(db_local, pkgname);
323 if(lpkg) {
324 const char *lpkgver = alpm_pkg_get_version(lpkg);
325 if(strcmp(lpkgver,pkgver) == 0) {
326 printf(" [%s]", _("installed"));
327 } else {
328 printf(" [%s: %s]", _("installed"), lpkgver);
333 /* search the sync dbs for a matching package */
334 static int sync_search(alpm_list_t *syncs, alpm_list_t *targets)
336 alpm_list_t *i, *j, *ret;
337 int freelist;
338 int found = 0;
339 pmdb_t *db_local = alpm_option_get_localdb(config->handle);
341 for(i = syncs; i; i = alpm_list_next(i)) {
342 pmdb_t *db = alpm_list_getdata(i);
343 /* if we have a targets list, search for packages matching it */
344 if(targets) {
345 ret = alpm_db_search(db, targets);
346 freelist = 1;
347 } else {
348 ret = alpm_db_get_pkgcache(db);
349 freelist = 0;
351 if(ret == NULL) {
352 continue;
353 } else {
354 found = 1;
356 for(j = ret; j; j = alpm_list_next(j)) {
357 alpm_list_t *grp;
358 pmpkg_t *pkg = alpm_list_getdata(j);
360 if(!config->quiet) {
361 printf("%s/%s %s", alpm_db_get_name(db), alpm_pkg_get_name(pkg),
362 alpm_pkg_get_version(pkg));
363 } else {
364 printf("%s", alpm_pkg_get_name(pkg));
367 if(!config->quiet) {
368 if((grp = alpm_pkg_get_groups(pkg)) != NULL) {
369 alpm_list_t *k;
370 printf(" (");
371 for(k = grp; k; k = alpm_list_next(k)) {
372 const char *group = alpm_list_getdata(k);
373 printf("%s", group);
374 if(alpm_list_next(k)) {
375 /* only print a spacer if there are more groups */
376 printf(" ");
379 printf(")");
382 print_installed(db_local, pkg);
384 /* we need a newline and initial indent first */
385 printf("\n ");
386 indentprint(alpm_pkg_get_desc(pkg), 4);
388 printf("\n");
390 /* we only want to free if the list was a search list */
391 if(freelist) {
392 alpm_list_free(ret);
396 return !found;
399 static int sync_group(int level, alpm_list_t *syncs, alpm_list_t *targets)
401 alpm_list_t *i, *j, *k;
403 if(targets) {
404 for(i = targets; i; i = alpm_list_next(i)) {
405 const char *grpname = alpm_list_getdata(i);
406 for(j = syncs; j; j = alpm_list_next(j)) {
407 pmdb_t *db = alpm_list_getdata(j);
408 pmgrp_t *grp = alpm_db_readgrp(db, grpname);
410 if(grp) {
411 /* get names of packages in group */
412 for(k = alpm_grp_get_pkgs(grp); k; k = alpm_list_next(k)) {
413 if(!config->quiet) {
414 printf("%s %s\n", grpname,
415 alpm_pkg_get_name(alpm_list_getdata(k)));
416 } else {
417 printf("%s\n", alpm_pkg_get_name(alpm_list_getdata(k)));
423 } else {
424 for(i = syncs; i; i = alpm_list_next(i)) {
425 pmdb_t *db = alpm_list_getdata(i);
427 for(j = alpm_db_get_grpcache(db); j; j = alpm_list_next(j)) {
428 pmgrp_t *grp = alpm_list_getdata(j);
429 const char *grpname = alpm_grp_get_name(grp);
431 if(level > 1) {
432 for(k = alpm_grp_get_pkgs(grp); k; k = alpm_list_next(k)) {
433 printf("%s %s\n", grpname,
434 alpm_pkg_get_name(alpm_list_getdata(k)));
436 } else {
437 /* print grp names only, no package names */
438 printf("%s\n", grpname);
444 return 0;
447 static int sync_info(alpm_list_t *syncs, alpm_list_t *targets)
449 alpm_list_t *i, *j, *k;
450 int ret = 0;
452 if(targets) {
453 for(i = targets; i; i = alpm_list_next(i)) {
454 pmdb_t *db = NULL;
455 int foundpkg = 0;
457 char target[512]; /* TODO is this enough space? */
458 char *repo = NULL, *pkgstr = NULL;
460 strncpy(target, i->data, 512);
461 pkgstr = strchr(target, '/');
462 if(pkgstr) {
463 repo = target;
464 *pkgstr = '\0';
465 ++pkgstr;
467 for(j = syncs; j; j = alpm_list_next(j)) {
468 db = alpm_list_getdata(j);
469 if(strcmp(repo, alpm_db_get_name(db)) == 0) {
470 break;
472 db = NULL;
475 if(!db) {
476 pm_fprintf(stderr, PM_LOG_ERROR,
477 _("repository '%s' does not exist\n"), repo);
478 return 1;
481 for(k = alpm_db_get_pkgcache(db); k; k = alpm_list_next(k)) {
482 pmpkg_t *pkg = alpm_list_getdata(k);
484 if(strcmp(alpm_pkg_get_name(pkg), pkgstr) == 0) {
485 dump_pkg_full(pkg, PKG_FROM_SYNCDB, config->op_s_info > 1);
486 foundpkg = 1;
487 break;
491 if(!foundpkg) {
492 pm_fprintf(stderr, PM_LOG_ERROR,
493 _("package '%s' was not found in repository '%s'\n"), pkgstr, repo);
494 ret++;
496 } else {
497 pkgstr = target;
499 for(j = syncs; j; j = alpm_list_next(j)) {
500 pmdb_t *db = alpm_list_getdata(j);
502 for(k = alpm_db_get_pkgcache(db); k; k = alpm_list_next(k)) {
503 pmpkg_t *pkg = alpm_list_getdata(k);
505 if(strcmp(alpm_pkg_get_name(pkg), pkgstr) == 0) {
506 dump_pkg_full(pkg, PKG_FROM_SYNCDB, config->op_s_info > 1);
507 foundpkg = 1;
508 break;
512 if(!foundpkg) {
513 pm_fprintf(stderr, PM_LOG_ERROR,
514 _("package '%s' was not found\n"), pkgstr);
515 ret++;
519 } else {
520 for(i = syncs; i; i = alpm_list_next(i)) {
521 pmdb_t *db = alpm_list_getdata(i);
523 for(j = alpm_db_get_pkgcache(db); j; j = alpm_list_next(j)) {
524 pmpkg_t *pkg = alpm_list_getdata(j);
525 dump_pkg_full(pkg, PKG_FROM_SYNCDB, config->op_s_info > 1);
530 return ret;
533 static int sync_list(alpm_list_t *syncs, alpm_list_t *targets)
535 alpm_list_t *i, *j, *ls = NULL;
536 pmdb_t *db_local = alpm_option_get_localdb(config->handle);
538 if(targets) {
539 for(i = targets; i; i = alpm_list_next(i)) {
540 const char *repo = alpm_list_getdata(i);
541 pmdb_t *db = NULL;
543 for(j = syncs; j; j = alpm_list_next(j)) {
544 pmdb_t *d = alpm_list_getdata(j);
546 if(strcmp(repo, alpm_db_get_name(d)) == 0) {
547 db = d;
548 break;
552 if(db == NULL) {
553 pm_fprintf(stderr, PM_LOG_ERROR,
554 _("repository \"%s\" was not found.\n"),repo);
555 alpm_list_free(ls);
556 return 1;
559 ls = alpm_list_add(ls, db);
561 } else {
562 ls = syncs;
565 for(i = ls; i; i = alpm_list_next(i)) {
566 pmdb_t *db = alpm_list_getdata(i);
568 for(j = alpm_db_get_pkgcache(db); j; j = alpm_list_next(j)) {
569 pmpkg_t *pkg = alpm_list_getdata(j);
571 if(!config->quiet) {
572 printf("%s %s %s", alpm_db_get_name(db), alpm_pkg_get_name(pkg),
573 alpm_pkg_get_version(pkg));
574 print_installed(db_local, pkg);
575 printf("\n");
576 } else {
577 printf("%s\n", alpm_pkg_get_name(pkg));
582 if(targets) {
583 alpm_list_free(ls);
586 return 0;
589 static alpm_list_t *syncfirst(void) {
590 alpm_list_t *i, *res = NULL;
591 pmdb_t *db_local = alpm_option_get_localdb(config->handle);
592 alpm_list_t *syncdbs = alpm_option_get_syncdbs(config->handle);
594 for(i = config->syncfirst; i; i = alpm_list_next(i)) {
595 char *pkgname = alpm_list_getdata(i);
596 pmpkg_t *pkg = alpm_db_get_pkg(db_local, pkgname);
597 if(pkg == NULL) {
598 continue;
601 if(alpm_sync_newversion(pkg, syncdbs)) {
602 res = alpm_list_add(res, strdup(pkgname));
606 return res;
609 static pmdb_t *get_db(const char *dbname)
611 alpm_list_t *i;
612 for(i = alpm_option_get_syncdbs(config->handle); i; i = i->next) {
613 pmdb_t *db = i->data;
614 if(strcmp(alpm_db_get_name(db), dbname) == 0) {
615 return db;
618 return NULL;
621 static int process_pkg(pmpkg_t *pkg)
623 int ret = alpm_add_pkg(config->handle, pkg);
625 if(ret == -1) {
626 if(pm_errno == PM_ERR_TRANS_DUP_TARGET
627 || pm_errno == PM_ERR_PKG_IGNORED) {
628 /* just skip duplicate or ignored targets */
629 pm_printf(PM_LOG_WARNING, _("skipping target: %s\n"), alpm_pkg_get_name(pkg));
630 return 0;
631 } else {
632 pm_fprintf(stderr, PM_LOG_ERROR, "'%s': %s\n", alpm_pkg_get_name(pkg),
633 alpm_strerrorlast());
634 return 1;
637 return 0;
640 static int process_group(alpm_list_t *dbs, char *group)
642 int ret = 0;
643 alpm_list_t *i;
644 alpm_list_t *pkgs = alpm_find_grp_pkgs(dbs, group);
645 int count = alpm_list_count(pkgs);
647 if(!count) {
648 pm_fprintf(stderr, PM_LOG_ERROR, _("target not found: %s\n"), group);
649 return 1;
653 if(config->print == 0) {
654 printf(_(":: There are %d members in group %s:\n"), count,
655 group);
656 select_display(pkgs);
657 char *array = malloc(count);
658 multiselect_question(array, count);
659 int n = 0;
660 for(i = pkgs; i; i = alpm_list_next(i)) {
661 if(array[n++] == 0)
662 continue;
663 pmpkg_t *pkg = alpm_list_getdata(i);
665 if(process_pkg(pkg) == 1) {
666 ret = 1;
667 free(array);
668 goto cleanup;
671 } else {
672 for(i = pkgs; i; i = alpm_list_next(i)) {
673 pmpkg_t *pkg = alpm_list_getdata(i);
675 if(process_pkg(pkg) == 1) {
676 ret = 1;
677 goto cleanup;
681 cleanup:
682 alpm_list_free(pkgs);
683 return ret;
686 static int process_targname(alpm_list_t *dblist, char *targname)
688 pmpkg_t *pkg = alpm_find_dbs_satisfier(dblist, targname);
690 /* #FS23342 - skip ignored packages when user says no */
691 if(pm_errno == PM_ERR_PKG_IGNORED) {
692 pm_printf(PM_LOG_WARNING, _("skipping target: %s\n"), targname);
693 pm_errno = 0;
694 return 0;
697 if(pkg) {
698 return process_pkg(pkg);
700 /* fallback on group */
701 return process_group(dblist, targname);
704 static int process_target(char *target)
706 /* process targets */
707 char *targstring = strdup(target);
708 char *targname = strchr(targstring, '/');
709 char *dbname = NULL;
710 int ret = 0;
711 alpm_list_t *dblist = NULL;
713 if(targname) {
714 pmdb_t *db = NULL;
716 *targname = '\0';
717 targname++;
718 dbname = targstring;
719 db = get_db(dbname);
720 if(!db) {
721 pm_fprintf(stderr, PM_LOG_ERROR, _("database not found: %s\n"),
722 dbname);
723 ret = 1;
724 goto cleanup;
726 dblist = alpm_list_add(dblist, db);
727 ret = process_targname(dblist, targname);
728 alpm_list_free(dblist);
729 } else {
730 targname = targstring;
731 dblist = alpm_option_get_syncdbs(config->handle);
732 ret = process_targname(dblist, targname);
734 cleanup:
735 free(targstring);
736 return ret;
739 static int sync_trans(alpm_list_t *targets)
741 int retval = 0;
742 alpm_list_t *data = NULL;
743 alpm_list_t *packages = NULL;
744 alpm_list_t *i;
746 /* Step 1: create a new transaction... */
747 if(trans_init(config->flags) == -1) {
748 return 1;
751 /* process targets */
752 for(i = targets; i; i = alpm_list_next(i)) {
753 char *targ = alpm_list_getdata(i);
754 if(process_target(targ) == 1) {
755 retval = 1;
756 goto cleanup;
760 if(config->op_s_upgrade) {
761 printf(_(":: Starting full system upgrade...\n"));
762 alpm_logaction(config->handle, "starting full system upgrade\n");
763 if(alpm_sync_sysupgrade(config->handle, config->op_s_upgrade >= 2) == -1) {
764 pm_fprintf(stderr, PM_LOG_ERROR, "%s\n", alpm_strerrorlast());
765 retval = 1;
766 goto cleanup;
770 /* Step 2: "compute" the transaction based on targets and flags */
771 if(alpm_trans_prepare(config->handle, &data) == -1) {
772 pm_fprintf(stderr, PM_LOG_ERROR, _("failed to prepare transaction (%s)\n"),
773 alpm_strerrorlast());
774 switch(pm_errno) {
775 alpm_list_t *i;
776 case PM_ERR_PKG_INVALID_ARCH:
777 for(i = data; i; i = alpm_list_next(i)) {
778 char *pkg = alpm_list_getdata(i);
779 printf(_(":: package %s does not have a valid architecture\n"), pkg);
781 break;
782 case PM_ERR_UNSATISFIED_DEPS:
783 for(i = data; i; i = alpm_list_next(i)) {
784 pmdepmissing_t *miss = alpm_list_getdata(i);
785 pmdepend_t *dep = alpm_miss_get_dep(miss);
786 char *depstring = alpm_dep_compute_string(dep);
787 printf(_(":: %s: requires %s\n"), alpm_miss_get_target(miss),
788 depstring);
789 free(depstring);
791 break;
792 case PM_ERR_CONFLICTING_DEPS:
793 for(i = data; i; i = alpm_list_next(i)) {
794 pmconflict_t *conflict = alpm_list_getdata(i);
795 const char *package1 = alpm_conflict_get_package1(conflict);
796 const char *package2 = alpm_conflict_get_package2(conflict);
797 const char *reason = alpm_conflict_get_reason(conflict);
798 /* only print reason if it contains new information */
799 if(strcmp(package1, reason) == 0 || strcmp(package2, reason) == 0) {
800 printf(_(":: %s and %s are in conflict\n"), package1, package2);
801 } else {
802 printf(_(":: %s and %s are in conflict (%s)\n"), package1, package2, reason);
805 break;
806 default:
807 break;
809 retval = 1;
810 goto cleanup;
813 packages = alpm_trans_get_add(config->handle);
814 if(packages == NULL) {
815 /* nothing to do: just exit without complaining */
816 printf(_(" there is nothing to do\n"));
817 goto cleanup;
820 /* Step 3: actually perform the operation */
821 if(config->print) {
822 print_packages(packages);
823 goto cleanup;
826 display_targets(alpm_trans_get_remove(config->handle), 0);
827 display_targets(alpm_trans_get_add(config->handle), 1);
828 printf("\n");
830 int confirm;
831 if(config->op_s_downloadonly) {
832 confirm = yesno(_("Proceed with download?"));
833 } else {
834 confirm = yesno(_("Proceed with installation?"));
836 if(!confirm) {
837 goto cleanup;
840 if(alpm_trans_commit(config->handle, &data) == -1) {
841 pm_fprintf(stderr, PM_LOG_ERROR, _("failed to commit transaction (%s)\n"),
842 alpm_strerrorlast());
843 switch(pm_errno) {
844 alpm_list_t *i;
845 case PM_ERR_FILE_CONFLICTS:
846 for(i = data; i; i = alpm_list_next(i)) {
847 pmfileconflict_t *conflict = alpm_list_getdata(i);
848 switch(alpm_fileconflict_get_type(conflict)) {
849 case PM_FILECONFLICT_TARGET:
850 printf(_("%s exists in both '%s' and '%s'\n"),
851 alpm_fileconflict_get_file(conflict),
852 alpm_fileconflict_get_target(conflict),
853 alpm_fileconflict_get_ctarget(conflict));
854 break;
855 case PM_FILECONFLICT_FILESYSTEM:
856 printf(_("%s: %s exists in filesystem\n"),
857 alpm_fileconflict_get_target(conflict),
858 alpm_fileconflict_get_file(conflict));
859 break;
862 break;
863 case PM_ERR_PKG_INVALID:
864 case PM_ERR_DLT_INVALID:
865 for(i = data; i; i = alpm_list_next(i)) {
866 char *filename = alpm_list_getdata(i);
867 printf(_("%s is invalid or corrupted\n"), filename);
869 break;
870 default:
871 break;
873 /* TODO: stderr? */
874 printf(_("Errors occurred, no packages were upgraded.\n"));
875 retval = 1;
876 goto cleanup;
879 /* Step 4: release transaction resources */
880 cleanup:
881 if(data) {
882 FREELIST(data);
884 if(trans_release() == -1) {
885 retval = 1;
888 return retval;
891 int pacman_sync(alpm_list_t *targets)
893 alpm_list_t *sync_dbs = NULL;
895 /* clean the cache */
896 if(config->op_s_clean) {
897 int ret = 0;
899 if(trans_init(0) == -1) {
900 return 1;
903 ret += sync_cleancache(config->op_s_clean);
904 printf("\n");
905 ret += sync_cleandb_all();
907 if(trans_release() == -1) {
908 ret++;
911 return ret;
914 /* ensure we have at least one valid sync db set up */
915 sync_dbs = alpm_option_get_syncdbs(config->handle);
916 if(sync_dbs == NULL || alpm_list_count(sync_dbs) == 0) {
917 pm_printf(PM_LOG_ERROR, _("no usable package repositories configured.\n"));
918 return 1;
921 if(config->op_s_sync) {
922 /* grab a fresh package list */
923 printf(_(":: Synchronizing package databases...\n"));
924 alpm_logaction(config->handle, "synchronizing package lists\n");
925 if(!sync_synctree(config->op_s_sync, sync_dbs)) {
926 return 1;
930 /* search for a package */
931 if(config->op_s_search) {
932 return sync_search(sync_dbs, targets);
935 /* look for groups */
936 if(config->group) {
937 return sync_group(config->group, sync_dbs, targets);
940 /* get package info */
941 if(config->op_s_info) {
942 return sync_info(sync_dbs, targets);
945 /* get a listing of files in sync DBs */
946 if(config->op_q_list) {
947 return sync_list(sync_dbs, targets);
950 if(targets == NULL) {
951 if(config->op_s_upgrade) {
952 /* proceed */
953 } else if(config->op_s_sync) {
954 return 0;
955 } else {
956 /* don't proceed here unless we have an operation that doesn't require a
957 * target list */
958 pm_printf(PM_LOG_ERROR, _("no targets specified (use -h for help)\n"));
959 return 1;
963 alpm_list_t *targs = alpm_list_strdup(targets);
964 if(!(config->flags & PM_TRANS_FLAG_DOWNLOADONLY) && !config->print) {
965 /* check for newer versions of packages to be upgraded first */
966 alpm_list_t *packages = syncfirst();
967 if(packages) {
968 /* Do not ask user if all the -S targets are SyncFirst packages, see FS#15810 */
969 alpm_list_t *tmp = NULL;
970 if(config->op_s_upgrade || (tmp = alpm_list_diff(targets, packages, (alpm_list_fn_cmp)strcmp))) {
971 alpm_list_free(tmp);
972 printf(_(":: The following packages should be upgraded first :\n"));
973 list_display(" ", packages);
974 if(yesno(_(":: Do you want to cancel the current operation\n"
975 ":: and upgrade these packages now?"))) {
976 FREELIST(targs);
977 targs = packages;
978 config->flags = 0;
979 config->op_s_upgrade = 0;
980 } else {
981 FREELIST(packages);
983 printf("\n");
984 } else {
985 pm_printf(PM_LOG_DEBUG, "skipping SyncFirst dialog\n");
986 FREELIST(packages);
991 int ret = sync_trans(targs);
992 FREELIST(targs);
994 return ret;
997 /* vim: set ts=2 sw=2 noet: */