4 * Copyright (c) 2006-2013 Pacman Development Team <pacman-dev@archlinux.org>
5 * Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org>
6 * Copyright (c) 2005 by Aurelien Foret <orelien@chez.com>
7 * Copyright (c) 2005 by Christian Hamar <krics@linuxforum.hu>
8 * Copyright (c) 2006 by David Kimpe <dnaku@frugalware.org>
9 * Copyright (c) 2005, 2006 by Miklos Vajna <vmiklos@frugalware.org>
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program. If not, see <http://www.gnu.org/licenses/>.
33 #include <sys/types.h>
37 #include "alpm_list.h"
50 * @brief Add a package removal action to the transaction.
52 * @param handle the context handle
53 * @param pkg the package to uninstall
55 * @return 0 on success, -1 on error
57 int SYMEXPORT
alpm_remove_pkg(alpm_handle_t
*handle
, alpm_pkg_t
*pkg
)
64 CHECK_HANDLE(handle
, return -1);
65 ASSERT(pkg
!= NULL
, RET_ERR(handle
, ALPM_ERR_WRONG_ARGS
, -1));
66 ASSERT(handle
== pkg
->handle
, RET_ERR(handle
, ALPM_ERR_WRONG_ARGS
, -1));
67 trans
= handle
->trans
;
68 ASSERT(trans
!= NULL
, RET_ERR(handle
, ALPM_ERR_TRANS_NULL
, -1));
69 ASSERT(trans
->state
== STATE_INITIALIZED
,
70 RET_ERR(handle
, ALPM_ERR_TRANS_NOT_INITIALIZED
, -1));
74 if(alpm_pkg_find(trans
->remove
, pkgname
)) {
75 RET_ERR(handle
, ALPM_ERR_TRANS_DUP_TARGET
, -1);
78 _alpm_log(handle
, ALPM_LOG_DEBUG
, "adding package %s to the transaction remove list\n",
80 if(_alpm_pkg_dup(pkg
, ©
) == -1) {
83 trans
->remove
= alpm_list_add(trans
->remove
, copy
);
88 * @brief Add dependencies to the removal transaction for cascading.
90 * @param handle the context handle
91 * @param lp list of missing dependencies caused by the removal transaction
93 * @return 0 on success, -1 on error
95 static int remove_prepare_cascade(alpm_handle_t
*handle
, alpm_list_t
*lp
)
97 alpm_trans_t
*trans
= handle
->trans
;
101 for(i
= lp
; i
; i
= i
->next
) {
102 alpm_depmissing_t
*miss
= i
->data
;
103 alpm_pkg_t
*info
= _alpm_db_get_pkgfromcache(handle
->db_local
, miss
->target
);
106 if(!alpm_pkg_find(trans
->remove
, info
->name
)) {
107 _alpm_log(handle
, ALPM_LOG_DEBUG
, "pulling %s in target list\n",
109 if(_alpm_pkg_dup(info
, ©
) == -1) {
112 trans
->remove
= alpm_list_add(trans
->remove
, copy
);
115 _alpm_log(handle
, ALPM_LOG_ERROR
,
116 _("could not find %s in database -- skipping\n"), miss
->target
);
119 alpm_list_free_inner(lp
, (alpm_list_fn_free
)_alpm_depmiss_free
);
121 lp
= alpm_checkdeps(handle
, _alpm_db_get_pkgcache(handle
->db_local
),
122 trans
->remove
, NULL
, 1);
128 * @brief Remove needed packages from the removal transaction.
130 * @param handle the context handle
131 * @param lp list of missing dependencies caused by the removal transaction
133 static void remove_prepare_keep_needed(alpm_handle_t
*handle
, alpm_list_t
*lp
)
135 alpm_trans_t
*trans
= handle
->trans
;
137 /* Remove needed packages (which break dependencies) from target list */
140 for(i
= lp
; i
; i
= i
->next
) {
141 alpm_depmissing_t
*miss
= i
->data
;
143 alpm_pkg_t
*pkg
= alpm_pkg_find(trans
->remove
, miss
->causingpkg
);
147 trans
->remove
= alpm_list_remove(trans
->remove
, pkg
, _alpm_pkg_cmp
,
151 _alpm_log(handle
, ALPM_LOG_WARNING
, _("removing %s from target list\n"),
156 alpm_list_free_inner(lp
, (alpm_list_fn_free
)_alpm_depmiss_free
);
158 lp
= alpm_checkdeps(handle
, _alpm_db_get_pkgcache(handle
->db_local
),
159 trans
->remove
, NULL
, 1);
164 * @brief Send a callback for any optdepend being removed.
166 * @param handle the context handle
167 * @param lp list of packages to be removed
169 static void remove_notify_needed_optdepends(alpm_handle_t
*handle
, alpm_list_t
*lp
)
173 for(i
= _alpm_db_get_pkgcache(handle
->db_local
); i
; i
= alpm_list_next(i
)) {
174 alpm_pkg_t
*pkg
= i
->data
;
175 alpm_list_t
*optdeps
= alpm_pkg_get_optdepends(pkg
);
177 if(optdeps
&& !alpm_pkg_find(lp
, pkg
->name
)) {
179 for(j
= optdeps
; j
; j
= alpm_list_next(j
)) {
180 alpm_depend_t
*optdep
= j
->data
;
181 if(alpm_pkg_find(lp
, optdep
->name
)) {
182 EVENT(handle
, ALPM_EVENT_OPTDEP_REQUIRED
, pkg
, optdep
);
190 * @brief Transaction preparation for remove actions.
192 * This functions takes a pointer to a alpm_list_t which will be
193 * filled with a list of alpm_depmissing_t* objects representing
194 * the packages blocking the transaction.
196 * @param handle the context handle
197 * @param data a pointer to an alpm_list_t* to fill
199 * @return 0 on success, -1 on error
201 int _alpm_remove_prepare(alpm_handle_t
*handle
, alpm_list_t
**data
)
204 alpm_trans_t
*trans
= handle
->trans
;
205 alpm_db_t
*db
= handle
->db_local
;
207 if((trans
->flags
& ALPM_TRANS_FLAG_RECURSE
)
208 && !(trans
->flags
& ALPM_TRANS_FLAG_CASCADE
)) {
209 _alpm_log(handle
, ALPM_LOG_DEBUG
, "finding removable dependencies\n");
210 if(_alpm_recursedeps(db
, trans
->remove
,
211 trans
->flags
& ALPM_TRANS_FLAG_RECURSEALL
)) {
216 if(!(trans
->flags
& ALPM_TRANS_FLAG_NODEPS
)) {
217 EVENT(handle
, ALPM_EVENT_CHECKDEPS_START
, NULL
, NULL
);
219 _alpm_log(handle
, ALPM_LOG_DEBUG
, "looking for unsatisfied dependencies\n");
220 lp
= alpm_checkdeps(handle
, _alpm_db_get_pkgcache(db
), trans
->remove
, NULL
, 1);
223 if(trans
->flags
& ALPM_TRANS_FLAG_CASCADE
) {
224 if(remove_prepare_cascade(handle
, lp
)) {
227 } else if(trans
->flags
& ALPM_TRANS_FLAG_UNNEEDED
) {
228 /* Remove needed packages (which would break dependencies)
229 * from target list */
230 remove_prepare_keep_needed(handle
, lp
);
235 alpm_list_free_inner(lp
, (alpm_list_fn_free
)_alpm_depmiss_free
);
238 RET_ERR(handle
, ALPM_ERR_UNSATISFIED_DEPS
, -1);
243 /* re-order w.r.t. dependencies */
244 _alpm_log(handle
, ALPM_LOG_DEBUG
, "sorting by dependencies\n");
245 lp
= _alpm_sortbydeps(handle
, trans
->remove
, 1);
246 /* free the old alltargs */
247 alpm_list_free(trans
->remove
);
250 /* -Rcs == -Rc then -Rs */
251 if((trans
->flags
& ALPM_TRANS_FLAG_CASCADE
)
252 && (trans
->flags
& ALPM_TRANS_FLAG_RECURSE
)) {
253 _alpm_log(handle
, ALPM_LOG_DEBUG
, "finding removable dependencies\n");
254 if(_alpm_recursedeps(db
, trans
->remove
,
255 trans
->flags
& ALPM_TRANS_FLAG_RECURSEALL
)) {
260 /* Note packages being removed that are optdepends for installed packages */
261 remove_notify_needed_optdepends(handle
, trans
->remove
);
263 if(!(trans
->flags
& ALPM_TRANS_FLAG_NODEPS
)) {
264 EVENT(handle
, ALPM_EVENT_CHECKDEPS_DONE
, NULL
, NULL
);
271 * @brief Test if a directory is being used as a mountpoint.
273 * @param handle context handle
274 * @param directory path to test, must be absolute and include trailing '/'
275 * @param stbuf stat result for @a directory, may be NULL
277 * @return 0 if @a directory is not a mountpoint or on error, 1 if @a directory
280 static int dir_is_mountpoint(alpm_handle_t
*handle
, const char *directory
,
281 const struct stat
*stbuf
)
283 char parent_dir
[PATH_MAX
];
284 struct stat parent_stbuf
;
288 struct stat dir_stbuf
;
289 if(stat(directory
, &dir_stbuf
) < 0) {
290 _alpm_log(handle
, ALPM_LOG_DEBUG
,
291 "failed to stat directory %s: %s\n",
292 directory
, strerror(errno
));
295 dir_st_dev
= dir_stbuf
.st_dev
;
297 dir_st_dev
= stbuf
->st_dev
;
300 snprintf(parent_dir
, PATH_MAX
, "%s..", directory
);
301 if(stat(parent_dir
, &parent_stbuf
) < 0) {
302 _alpm_log(handle
, ALPM_LOG_DEBUG
,
303 "failed to stat parent of %s: %s: %s\n",
304 directory
, parent_dir
, strerror(errno
));
308 return dir_st_dev
!= parent_stbuf
.st_dev
;
312 * @brief Check if alpm can delete a file.
314 * @param handle the context handle
315 * @param file file to be removed
316 * @param skip_remove list of files that will not be removed
318 * @return 1 if the file can be deleted, 0 if it cannot be deleted
320 static int can_remove_file(alpm_handle_t
*handle
, const alpm_file_t
*file
,
321 alpm_list_t
*skip_remove
)
323 char filepath
[PATH_MAX
];
325 if(alpm_list_find(skip_remove
, file
->name
, _alpm_fnmatch
)) {
326 /* return success because we will never actually remove this file */
330 snprintf(filepath
, PATH_MAX
, "%s%s", handle
->root
, file
->name
);
332 if(file
->name
[strlen(file
->name
) - 1] == '/' &&
333 dir_is_mountpoint(handle
, filepath
, NULL
)) {
334 /* we do not remove mountpoints */
338 /* If we fail write permissions due to a read-only filesystem, abort.
339 * Assume all other possible failures are covered somewhere else */
340 if(_alpm_access(handle
, NULL
, filepath
, W_OK
) == -1) {
341 if(errno
!= EACCES
&& errno
!= ETXTBSY
&& access(filepath
, F_OK
) == 0) {
342 /* only return failure if the file ACTUALLY exists and we can't write to
343 * it - ignore "chmod -w" simple permission failures */
344 _alpm_log(handle
, ALPM_LOG_ERROR
, _("cannot remove file '%s': %s\n"),
345 filepath
, strerror(errno
));
353 static void shift_pacsave(alpm_handle_t
*handle
, const char *file
)
360 const char *basename
;
362 char oldfile
[PATH_MAX
];
363 char newfile
[PATH_MAX
];
364 char regstr
[PATH_MAX
];
366 unsigned long log_max
= 0;
369 dirname
= mdirname(file
);
374 basename
= mbasename(file
);
375 basename_len
= strlen(basename
);
377 snprintf(regstr
, PATH_MAX
, "^%s\\.pacsave\\.([[:digit:]]+)$", basename
);
378 if(regcomp(®
, regstr
, REG_EXTENDED
| REG_NEWLINE
) != 0) {
382 dir
= opendir(dirname
);
384 _alpm_log(handle
, ALPM_LOG_ERROR
, _("could not open directory: %s: %s\n"),
385 dirname
, strerror(errno
));
389 while((ent
= readdir(dir
)) != NULL
) {
390 if(strcmp(ent
->d_name
, ".") == 0 || strcmp(ent
->d_name
, "..") == 0) {
394 if(regexec(®
, ent
->d_name
, 0, 0, 0) == 0) {
395 unsigned long cur_log
;
396 cur_log
= strtoul(ent
->d_name
+ basename_len
+ strlen(".pacsave."), NULL
, 10);
397 if(cur_log
> log_max
) {
405 for(i
= log_max
+ 1; i
> 1; i
--) {
406 snprintf(oldfile
, PATH_MAX
, "%s.pacsave.%lu", file
, i
-1);
407 snprintf(newfile
, PATH_MAX
, "%s.pacsave.%lu", file
, i
);
408 rename(oldfile
, newfile
);
411 snprintf(oldfile
, PATH_MAX
, "%s.pacsave", file
);
412 if(stat(oldfile
, &st
) == 0) {
413 snprintf(newfile
, PATH_MAX
, "%s.1", oldfile
);
414 rename(oldfile
, newfile
);
426 * @brief Unlink a package file, backing it up if necessary.
428 * @param handle the context handle
429 * @param oldpkg the package being removed
430 * @param newpkg the package replacing \a oldpkg
431 * @param fileobj file to remove
432 * @param skip_remove list of files that shouldn't be removed
433 * @param nosave whether files should be backed up
435 * @return 0 on success, -1 if there was an error unlinking the file, 1 if the
436 * file was skipped or did not exist
438 static int unlink_file(alpm_handle_t
*handle
, alpm_pkg_t
*oldpkg
,
439 alpm_pkg_t
*newpkg
, const alpm_file_t
*fileobj
, alpm_list_t
*skip_remove
,
445 snprintf(file
, PATH_MAX
, "%s%s", handle
->root
, fileobj
->name
);
447 /* check the remove skip list before removing the file.
448 * see the big comment block in db_find_fileconflicts() for an
450 if(alpm_list_find(skip_remove
, fileobj
->name
, _alpm_fnmatch
)) {
451 _alpm_log(handle
, ALPM_LOG_DEBUG
,
452 "%s is in skip_remove, skipping removal\n", file
);
456 if(_alpm_lstat(file
, &buf
)) {
457 _alpm_log(handle
, ALPM_LOG_DEBUG
, "file %s does not exist\n", file
);
461 if(S_ISDIR(buf
.st_mode
)) {
462 ssize_t files
= _alpm_files_in_directory(handle
, file
, 0);
463 /* if we have files, no need to remove the directory */
465 _alpm_log(handle
, ALPM_LOG_DEBUG
, "keeping directory %s (contains files)\n",
467 } else if(files
< 0) {
468 _alpm_log(handle
, ALPM_LOG_DEBUG
,
469 "keeping directory %s (could not count files)\n", file
);
470 } else if(newpkg
&& alpm_filelist_contains(alpm_pkg_get_files(newpkg
),
472 _alpm_log(handle
, ALPM_LOG_DEBUG
,
473 "keeping directory %s (in new package)\n", file
);
474 } else if(dir_is_mountpoint(handle
, file
, &buf
)) {
475 _alpm_log(handle
, ALPM_LOG_DEBUG
,
476 "keeping directory %s (mountpoint)\n", file
);
478 /* one last check- does any other package own this file? */
479 alpm_list_t
*local
, *local_pkgs
;
481 local_pkgs
= _alpm_db_get_pkgcache(handle
->db_local
);
482 for(local
= local_pkgs
; local
&& !found
; local
= local
->next
) {
483 alpm_pkg_t
*local_pkg
= local
->data
;
484 alpm_filelist_t
*filelist
;
486 /* we duplicated the package when we put it in the removal list, so we
487 * so we can't use direct pointer comparison here. */
488 if(oldpkg
->name_hash
== local_pkg
->name_hash
489 && strcmp(oldpkg
->name
, local_pkg
->name
) == 0) {
492 filelist
= alpm_pkg_get_files(local_pkg
);
493 if(alpm_filelist_contains(filelist
, fileobj
->name
)) {
494 _alpm_log(handle
, ALPM_LOG_DEBUG
,
495 "keeping directory %s (owned by %s)\n", file
, local_pkg
->name
);
501 _alpm_log(handle
, ALPM_LOG_DEBUG
,
502 "directory removal of %s failed: %s\n", file
, strerror(errno
));
505 _alpm_log(handle
, ALPM_LOG_DEBUG
,
506 "removed directory %s (no remaining owners)\n", file
);
511 /* if the file needs backup and has been modified, back it up to .pacsave */
512 alpm_backup_t
*backup
= _alpm_needbackup(fileobj
->name
, oldpkg
);
515 _alpm_log(handle
, ALPM_LOG_DEBUG
, "transaction is set to NOSAVE, not backing up '%s'\n", file
);
517 char *filehash
= alpm_compute_md5sum(file
);
518 int cmp
= filehash
? strcmp(filehash
, backup
->hash
) : 0;
522 size_t len
= strlen(file
) + 8 + 1;
523 MALLOC(newpath
, len
, RET_ERR(handle
, ALPM_ERR_MEMORY
, -1));
524 shift_pacsave(handle
, file
);
525 snprintf(newpath
, len
, "%s.pacsave", file
);
526 if(rename(file
, newpath
)) {
527 _alpm_log(handle
, ALPM_LOG_ERROR
, _("could not rename %s to %s (%s)\n"),
528 file
, newpath
, strerror(errno
));
529 alpm_logaction(handle
, ALPM_CALLER_PREFIX
,
530 "error: could not rename %s to %s (%s)\n",
531 file
, newpath
, strerror(errno
));
535 _alpm_log(handle
, ALPM_LOG_WARNING
, _("%s saved as %s\n"), file
, newpath
);
536 alpm_logaction(handle
, ALPM_CALLER_PREFIX
,
537 "warning: %s saved as %s\n", file
, newpath
);
544 _alpm_log(handle
, ALPM_LOG_DEBUG
, "unlinking %s\n", file
);
546 if(unlink(file
) == -1) {
547 _alpm_log(handle
, ALPM_LOG_ERROR
, _("cannot remove %s (%s)\n"),
548 file
, strerror(errno
));
549 alpm_logaction(handle
, ALPM_CALLER_PREFIX
,
550 "error: cannot remove %s (%s)\n", file
, strerror(errno
));
558 * @brief Remove a package's files, optionally skipping its replacement's
561 * @param handle the context handle
562 * @param oldpkg package to remove
563 * @param newpkg package to replace \a oldpkg (optional)
564 * @param targ_count current index within the transaction (1-based)
565 * @param pkg_count the number of packages affected by the transaction
567 * @return 0 on success, -1 if alpm lacks permission to delete some of the
568 * files, >0 the number of files alpm was unable to delete
570 static int remove_package_files(alpm_handle_t
*handle
,
571 alpm_pkg_t
*oldpkg
, alpm_pkg_t
*newpkg
,
572 size_t targ_count
, size_t pkg_count
)
574 alpm_list_t
*skip_remove
;
575 alpm_filelist_t
*filelist
;
578 int nosave
= handle
->trans
->flags
& ALPM_TRANS_FLAG_NOSAVE
;
581 alpm_filelist_t
*newfiles
;
583 skip_remove
= alpm_list_join(
584 alpm_list_strdup(handle
->trans
->skip_remove
),
585 alpm_list_strdup(handle
->noupgrade
));
586 /* Add files in the NEW backup array to the skip_remove array
587 * so this removal operation doesn't kill them */
588 /* old package backup list */
589 newfiles
= alpm_pkg_get_files(newpkg
);
590 for(b
= alpm_pkg_get_backup(newpkg
); b
; b
= b
->next
) {
591 const alpm_backup_t
*backup
= b
->data
;
592 /* safety check (fix the upgrade026 pactest) */
593 if(!alpm_filelist_contains(newfiles
, backup
->name
)) {
596 _alpm_log(handle
, ALPM_LOG_DEBUG
, "adding %s to the skip_remove array\n",
598 skip_remove
= alpm_list_add(skip_remove
, strdup(backup
->name
));
601 skip_remove
= alpm_list_strdup(handle
->trans
->skip_remove
);
604 filelist
= alpm_pkg_get_files(oldpkg
);
605 for(i
= 0; i
< filelist
->count
; i
++) {
606 alpm_file_t
*file
= filelist
->files
+ i
;
607 if(!can_remove_file(handle
, file
, skip_remove
)) {
608 _alpm_log(handle
, ALPM_LOG_DEBUG
,
609 "not removing package '%s', can't remove all files\n",
611 FREELIST(skip_remove
);
612 RET_ERR(handle
, ALPM_ERR_PKG_CANT_REMOVE
, -1);
616 _alpm_log(handle
, ALPM_LOG_DEBUG
, "removing %zd files\n", filelist
->count
);
619 /* init progress bar, but only on true remove transactions */
620 PROGRESS(handle
, ALPM_PROGRESS_REMOVE_START
, oldpkg
->name
, 0,
621 pkg_count
, targ_count
);
624 /* iterate through the list backwards, unlinking files */
625 for(i
= filelist
->count
; i
> 0; i
--) {
626 alpm_file_t
*file
= filelist
->files
+ i
- 1;
627 if(unlink_file(handle
, oldpkg
, newpkg
, file
, skip_remove
, nosave
) < 0) {
632 /* update progress bar after each file */
633 int percent
= ((filelist
->count
- i
) * 100) / filelist
->count
;
634 PROGRESS(handle
, ALPM_PROGRESS_REMOVE_START
, oldpkg
->name
,
635 percent
, pkg_count
, targ_count
);
638 FREELIST(skip_remove
);
641 /* set progress to 100% after we finish unlinking files */
642 PROGRESS(handle
, ALPM_PROGRESS_REMOVE_START
, oldpkg
->name
, 100,
643 pkg_count
, targ_count
);
650 * @brief Remove a package from the filesystem.
652 * @param handle the context handle
653 * @param oldpkg package to remove
654 * @param newpkg package to replace \a oldpkg (optional)
655 * @param targ_count current index within the transaction (1-based)
656 * @param pkg_count the number of packages affected by the transaction
660 int _alpm_remove_single_package(alpm_handle_t
*handle
,
661 alpm_pkg_t
*oldpkg
, alpm_pkg_t
*newpkg
,
662 size_t targ_count
, size_t pkg_count
)
664 const char *pkgname
= oldpkg
->name
;
665 const char *pkgver
= oldpkg
->version
;
668 _alpm_log(handle
, ALPM_LOG_DEBUG
, "removing old package first (%s-%s)\n",
671 EVENT(handle
, ALPM_EVENT_REMOVE_START
, oldpkg
, NULL
);
672 _alpm_log(handle
, ALPM_LOG_DEBUG
, "removing package %s-%s\n",
675 /* run the pre-remove scriptlet if it exists */
676 if(alpm_pkg_has_scriptlet(oldpkg
) &&
677 !(handle
->trans
->flags
& ALPM_TRANS_FLAG_NOSCRIPTLET
)) {
678 char *scriptlet
= _alpm_local_db_pkgpath(handle
->db_local
,
680 _alpm_runscriptlet(handle
, scriptlet
, "pre_remove", pkgver
, NULL
, 0);
685 if(!(handle
->trans
->flags
& ALPM_TRANS_FLAG_DBONLY
)) {
686 /* TODO check returned errors if any */
687 remove_package_files(handle
, oldpkg
, newpkg
, targ_count
, pkg_count
);
690 /* run the post-remove script if it exists */
691 if(!newpkg
&& alpm_pkg_has_scriptlet(oldpkg
) &&
692 !(handle
->trans
->flags
& ALPM_TRANS_FLAG_NOSCRIPTLET
)) {
693 char *scriptlet
= _alpm_local_db_pkgpath(handle
->db_local
,
695 _alpm_runscriptlet(handle
, scriptlet
, "post_remove", pkgver
, NULL
, 0);
700 EVENT(handle
, ALPM_EVENT_REMOVE_DONE
, oldpkg
, NULL
);
703 /* remove the package from the database */
704 _alpm_log(handle
, ALPM_LOG_DEBUG
, "removing database entry '%s'\n", pkgname
);
705 if(_alpm_local_db_remove(handle
->db_local
, oldpkg
) == -1) {
706 _alpm_log(handle
, ALPM_LOG_ERROR
, _("could not remove database entry %s-%s\n"),
709 /* remove the package from the cache */
710 if(_alpm_db_remove_pkgfromcache(handle
->db_local
, oldpkg
) == -1) {
711 _alpm_log(handle
, ALPM_LOG_ERROR
, _("could not remove entry '%s' from cache\n"),
715 /* TODO: useful return values */
720 * @brief Remove packages in the current transaction.
722 * @param handle the context handle
723 * @param run_ldconfig whether to run ld_config after removing the packages
725 * @return 0 on success, -1 if errors occurred while removing files
727 int _alpm_remove_packages(alpm_handle_t
*handle
, int run_ldconfig
)
730 size_t pkg_count
, targ_count
;
731 alpm_trans_t
*trans
= handle
->trans
;
734 pkg_count
= alpm_list_count(trans
->remove
);
737 for(targ
= trans
->remove
; targ
; targ
= targ
->next
) {
738 alpm_pkg_t
*pkg
= targ
->data
;
740 if(trans
->state
== STATE_INTERRUPTED
) {
744 if(_alpm_remove_single_package(handle
, pkg
, NULL
,
745 targ_count
, pkg_count
) == -1) {
746 handle
->pm_errno
= ALPM_ERR_TRANS_ABORT
;
747 /* running ldconfig at this point could possibly screw system */
756 /* run ldconfig if it exists */
757 _alpm_ldconfig(handle
);
763 /* vim: set ts=2 sw=2 noet: */