00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "config.h"
00025
00026 #include <stdlib.h>
00027 #include <errno.h>
00028 #include <time.h>
00029 #include <fcntl.h>
00030 #include <string.h>
00031 #include <limits.h>
00032 #include <unistd.h>
00033 #include <sys/stat.h>
00034
00035
00036 #include "remove.h"
00037 #include "alpm_list.h"
00038 #include "trans.h"
00039 #include "util.h"
00040 #include "error.h"
00041 #include "log.h"
00042 #include "backup.h"
00043 #include "package.h"
00044 #include "db.h"
00045 #include "cache.h"
00046 #include "deps.h"
00047 #include "handle.h"
00048 #include "alpm.h"
00049
00050 int _alpm_remove_loadtarget(pmtrans_t *trans, pmdb_t *db, char *name)
00051 {
00052 pmpkg_t *info;
00053
00054 ALPM_LOG_FUNC;
00055
00056 ASSERT(db != NULL, RET_ERR(PM_ERR_DB_NULL, -1));
00057 ASSERT(trans != NULL, RET_ERR(PM_ERR_TRANS_NULL, -1));
00058 ASSERT(name != NULL, RET_ERR(PM_ERR_WRONG_ARGS, -1));
00059
00060 if(_alpm_pkg_find(name, trans->packages)) {
00061 RET_ERR(PM_ERR_TRANS_DUP_TARGET, -1);
00062 }
00063
00064 if((info = _alpm_db_scan(db, name)) == NULL) {
00065
00066 _alpm_log(PM_LOG_DEBUG, "could not find %s in database\n", name);
00067 RET_ERR(PM_ERR_PKG_NOT_FOUND, -1);
00068 }
00069
00070
00071 if((trans == handle->trans)
00072 && alpm_list_find_str(handle->holdpkg, info->name)) {
00073 int resp = 0;
00074 QUESTION(trans, PM_TRANS_CONV_REMOVE_HOLDPKG, info, NULL, NULL, &resp);
00075 if(!resp) {
00076 RET_ERR(PM_ERR_PKG_HOLD, -1);
00077 }
00078 }
00079
00080 _alpm_log(PM_LOG_DEBUG, "adding %s in the targets list\n", info->name);
00081 trans->packages = alpm_list_add(trans->packages, info);
00082
00083 return(0);
00084 }
00085
00086 int _alpm_remove_prepare(pmtrans_t *trans, pmdb_t *db, alpm_list_t **data)
00087 {
00088 alpm_list_t *lp;
00089
00090 ALPM_LOG_FUNC;
00091
00092 ASSERT(db != NULL, RET_ERR(PM_ERR_DB_NULL, -1));
00093 ASSERT(trans != NULL, RET_ERR(PM_ERR_TRANS_NULL, -1));
00094
00095
00096 if(trans->type == PM_TRANS_TYPE_REMOVEUPGRADE) {
00097 return(0);
00098 }
00099
00100 if(!(trans->flags & PM_TRANS_FLAG_NODEPS)) {
00101 EVENT(trans, PM_TRANS_EVT_CHECKDEPS_START, NULL, NULL);
00102
00103 _alpm_log(PM_LOG_DEBUG, "looking for unsatisfied dependencies\n");
00104 lp = alpm_checkdeps(db, 1, trans->packages, NULL);
00105 if(lp != NULL) {
00106 if(trans->flags & PM_TRANS_FLAG_CASCADE) {
00107 while(lp) {
00108 alpm_list_t *i;
00109 for(i = lp; i; i = i->next) {
00110 pmdepmissing_t *miss = (pmdepmissing_t *)i->data;
00111 pmpkg_t *info = _alpm_db_scan(db, miss->target);
00112 if(info) {
00113 if(!_alpm_pkg_find(alpm_pkg_get_name(info), trans->packages)) {
00114 _alpm_log(PM_LOG_DEBUG, "pulling %s in the targets list\n",
00115 alpm_pkg_get_name(info));
00116 trans->packages = alpm_list_add(trans->packages, info);
00117 }
00118 } else {
00119 _alpm_log(PM_LOG_ERROR, _("could not find %s in database -- skipping\n"),
00120 miss->target);
00121 }
00122 }
00123 alpm_list_free_inner(lp, (alpm_list_fn_free)_alpm_depmiss_free);
00124 alpm_list_free(lp);
00125 lp = alpm_checkdeps(db, 1, trans->packages, NULL);
00126 }
00127 } else {
00128 if(data) {
00129 *data = lp;
00130 } else {
00131 FREELIST(lp);
00132 }
00133 RET_ERR(PM_ERR_UNSATISFIED_DEPS, -1);
00134 }
00135 }
00136 }
00137
00138
00139 _alpm_log(PM_LOG_DEBUG, "sorting by dependencies\n");
00140 lp = _alpm_sortbydeps(trans->packages, PM_TRANS_TYPE_REMOVE);
00141
00142 alpm_list_free(trans->packages);
00143 trans->packages = lp;
00144
00145 if(trans->flags & PM_TRANS_FLAG_RECURSE) {
00146 _alpm_log(PM_LOG_DEBUG, "finding removable dependencies\n");
00147 _alpm_recursedeps(db, trans->packages, 0);
00148 }
00149
00150 if(!(trans->flags & PM_TRANS_FLAG_NODEPS)) {
00151 EVENT(trans, PM_TRANS_EVT_CHECKDEPS_DONE, NULL, NULL);
00152 }
00153
00154 return(0);
00155 }
00156
00157 static int can_remove_file(pmtrans_t *trans, const char *path)
00158 {
00159 char file[PATH_MAX+1];
00160
00161 snprintf(file, PATH_MAX, "%s%s", handle->root, path);
00162
00163 if(alpm_list_find_str(trans->skip_remove, file)) {
00164
00165 return(1);
00166 }
00167
00168
00169 if(access(file, W_OK) == -1) {
00170 if(errno != EACCES && errno != ETXTBSY && access(file, F_OK) == 0) {
00171
00172
00173 _alpm_log(PM_LOG_ERROR, _("cannot remove file '%s': %s\n"),
00174 file, strerror(errno));
00175 return(0);
00176 }
00177 }
00178
00179 return(1);
00180 }
00181
00182
00183
00184 static void unlink_file(pmpkg_t *info, alpm_list_t *lp, pmtrans_t *trans)
00185 {
00186 struct stat buf;
00187 int needbackup = 0;
00188 char file[PATH_MAX+1];
00189
00190 ALPM_LOG_FUNC;
00191
00192 char *hash = _alpm_needbackup(lp->data, alpm_pkg_get_backup(info));
00193 if(hash) {
00194 needbackup = 1;
00195 FREE(hash);
00196 }
00197
00198 snprintf(file, PATH_MAX, "%s%s", handle->root, (char *)lp->data);
00199
00200 if(trans->type == PM_TRANS_TYPE_REMOVEUPGRADE) {
00201
00202 if(alpm_list_find_str(handle->noupgrade, lp->data)) {
00203 _alpm_log(PM_LOG_DEBUG, "Skipping removal of '%s' due to NoUpgrade\n",
00204 file);
00205 return;
00206 }
00207 }
00208
00209
00210
00211
00212
00213 if(lstat(file, &buf)) {
00214 _alpm_log(PM_LOG_DEBUG, "file %s does not exist\n", file);
00215 return;
00216 }
00217
00218 if(S_ISDIR(buf.st_mode)) {
00219 if(rmdir(file)) {
00220
00221 _alpm_log(PM_LOG_DEBUG, "keeping directory %s\n", file);
00222 } else {
00223 _alpm_log(PM_LOG_DEBUG, "removing directory %s\n", file);
00224 }
00225 } else {
00226
00227
00228
00229 if(alpm_list_find_str(trans->skip_remove, file)) {
00230 _alpm_log(PM_LOG_DEBUG, "%s is in trans->skip_remove, skipping removal\n",
00231 file);
00232 return;
00233 } else if(needbackup) {
00234
00235 if(!(trans->flags & PM_TRANS_FLAG_NOSAVE)) {
00236 char newpath[PATH_MAX];
00237 snprintf(newpath, PATH_MAX, "%s.pacsave", file);
00238 rename(file, newpath);
00239 _alpm_log(PM_LOG_WARNING, _("%s saved as %s\n"), file, newpath);
00240 return;
00241 } else {
00242 _alpm_log(PM_LOG_DEBUG, "transaction is set to NOSAVE, not backing up '%s'\n", file);
00243 }
00244 }
00245 _alpm_log(PM_LOG_DEBUG, "unlinking %s\n", file);
00246
00247 if(unlink(file) == -1) {
00248 _alpm_log(PM_LOG_ERROR, _("cannot remove file '%s': %s\n"),
00249 (char *)lp->data, strerror(errno));
00250 }
00251 }
00252 }
00253
00254 int _alpm_remove_commit(pmtrans_t *trans, pmdb_t *db)
00255 {
00256 pmpkg_t *info;
00257 alpm_list_t *targ, *lp;
00258 int pkg_count;
00259
00260 ALPM_LOG_FUNC;
00261
00262 ASSERT(db != NULL, RET_ERR(PM_ERR_DB_NULL, -1));
00263 ASSERT(trans != NULL, RET_ERR(PM_ERR_TRANS_NULL, -1));
00264
00265 pkg_count = alpm_list_count(trans->packages);
00266
00267 for(targ = trans->packages; targ; targ = targ->next) {
00268 int position = 0;
00269 char scriptlet[PATH_MAX];
00270 alpm_list_t *files;
00271 info = (pmpkg_t*)targ->data;
00272 const char *pkgname = NULL;
00273
00274 if(handle->trans->state == STATE_INTERRUPTED) {
00275 return(0);
00276 }
00277
00278
00279 pkgname = alpm_pkg_get_name(info);
00280 snprintf(scriptlet, PATH_MAX, "%s%s-%s/install", db->path,
00281 pkgname, alpm_pkg_get_version(info));
00282
00283 if(trans->type != PM_TRANS_TYPE_REMOVEUPGRADE) {
00284 EVENT(trans, PM_TRANS_EVT_REMOVE_START, info, NULL);
00285 _alpm_log(PM_LOG_DEBUG, "removing package %s-%s\n",
00286 pkgname, alpm_pkg_get_version(info));
00287
00288
00289 if(alpm_pkg_has_scriptlet(info) && !(trans->flags & PM_TRANS_FLAG_NOSCRIPTLET)) {
00290 _alpm_runscriptlet(handle->root, scriptlet, "pre_remove",
00291 alpm_pkg_get_version(info), NULL, trans);
00292 }
00293 }
00294
00295 files = alpm_pkg_get_files(info);
00296
00297 if(!(trans->flags & PM_TRANS_FLAG_DBONLY)) {
00298 for(lp = files; lp; lp = lp->next) {
00299 if(!can_remove_file(trans, lp->data)) {
00300 _alpm_log(PM_LOG_DEBUG, "not removing package '%s', can't remove all files\n",
00301 pkgname);
00302 RET_ERR(PM_ERR_PKG_CANT_REMOVE, -1);
00303 }
00304 }
00305
00306 int filenum = alpm_list_count(files);
00307 double percent = 0.0;
00308 alpm_list_t *newfiles;
00309 _alpm_log(PM_LOG_DEBUG, "removing %d files\n", filenum);
00310
00311
00312 newfiles = alpm_list_reverse(files);
00313 for(lp = newfiles; lp; lp = alpm_list_next(lp)) {
00314 unlink_file(info, lp, trans);
00315
00316
00317 percent = (double)position / (double)filenum;
00318 PROGRESS(trans, PM_TRANS_PROGRESS_REMOVE_START, info->name,
00319 (double)(percent * 100), pkg_count,
00320 (pkg_count - alpm_list_count(targ) + 1));
00321 position++;
00322 }
00323 alpm_list_free(newfiles);
00324 }
00325
00326
00327 PROGRESS(trans, PM_TRANS_PROGRESS_REMOVE_START, pkgname, 100,
00328 pkg_count, (pkg_count - alpm_list_count(targ) + 1));
00329
00330 if(trans->type != PM_TRANS_TYPE_REMOVEUPGRADE) {
00331
00332 if(alpm_pkg_has_scriptlet(info) && !(trans->flags & PM_TRANS_FLAG_NOSCRIPTLET)) {
00333 _alpm_runscriptlet(handle->root, scriptlet, "post_remove",
00334 alpm_pkg_get_version(info), NULL, trans);
00335 }
00336 }
00337
00338
00339 _alpm_log(PM_LOG_DEBUG, "updating database\n");
00340 _alpm_log(PM_LOG_DEBUG, "removing database entry '%s'\n", pkgname);
00341 if(_alpm_db_remove(db, info) == -1) {
00342 _alpm_log(PM_LOG_ERROR, _("could not remove database entry %s-%s\n"),
00343 pkgname, alpm_pkg_get_version(info));
00344 }
00345
00346 if(_alpm_db_remove_pkgfromcache(db, info) == -1) {
00347 _alpm_log(PM_LOG_ERROR, _("could not remove entry '%s' from cache\n"),
00348 pkgname);
00349 }
00350
00351
00352 if(trans->type != PM_TRANS_TYPE_REMOVEUPGRADE) {
00353 EVENT(trans, PM_TRANS_EVT_REMOVE_DONE, info, NULL);
00354 }
00355 }
00356
00357
00358 if(trans->type != PM_TRANS_TYPE_REMOVEUPGRADE) {
00359 _alpm_log(PM_LOG_DEBUG, "running \"ldconfig -r %s\"\n", handle->root);
00360 _alpm_ldconfig(handle->root);
00361 }
00362
00363 return(0);
00364 }
00365
00366