libalpm
Arch Linux Package Manager Library
|
00001 /* 00002 * add.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 <stdlib.h> 00022 #include <errno.h> 00023 #include <string.h> 00024 #include <limits.h> 00025 #include <fcntl.h> 00026 #include <sys/types.h> 00027 #include <sys/stat.h> 00028 #include <unistd.h> 00029 #include <stdint.h> /* int64_t */ 00030 00031 /* libarchive */ 00032 #include <archive.h> 00033 #include <archive_entry.h> 00034 00035 /* libalpm */ 00036 #include "add.h" 00037 #include "alpm.h" 00038 #include "alpm_list.h" 00039 #include "handle.h" 00040 #include "trans.h" 00041 #include "util.h" 00042 #include "log.h" 00043 #include "backup.h" 00044 #include "package.h" 00045 #include "db.h" 00046 #include "remove.h" 00047 #include "handle.h" 00048 00049 /** Add a package to the transaction. */ 00050 int SYMEXPORT alpm_add_pkg(alpm_handle_t *handle, alpm_pkg_t *pkg) 00051 { 00052 const char *pkgname, *pkgver; 00053 alpm_trans_t *trans; 00054 alpm_pkg_t *local; 00055 00056 /* Sanity checks */ 00057 CHECK_HANDLE(handle, return -1); 00058 ASSERT(pkg != NULL, RET_ERR(handle, ALPM_ERR_WRONG_ARGS, -1)); 00059 ASSERT(handle == pkg->handle, RET_ERR(handle, ALPM_ERR_WRONG_ARGS, -1)); 00060 trans = handle->trans; 00061 ASSERT(trans != NULL, RET_ERR(handle, ALPM_ERR_TRANS_NULL, -1)); 00062 ASSERT(trans->state == STATE_INITIALIZED, 00063 RET_ERR(handle, ALPM_ERR_TRANS_NOT_INITIALIZED, -1)); 00064 00065 pkgname = pkg->name; 00066 pkgver = pkg->version; 00067 00068 _alpm_log(handle, ALPM_LOG_DEBUG, "adding package '%s'\n", pkgname); 00069 00070 if(_alpm_pkg_find(trans->add, pkgname)) { 00071 RET_ERR(handle, ALPM_ERR_TRANS_DUP_TARGET, -1); 00072 } 00073 00074 local = _alpm_db_get_pkgfromcache(handle->db_local, pkgname); 00075 if(local) { 00076 const char *localpkgname = local->name; 00077 const char *localpkgver = local->version; 00078 int cmp = _alpm_pkg_compare_versions(pkg, local); 00079 00080 if(cmp == 0) { 00081 if(trans->flags & ALPM_TRANS_FLAG_NEEDED) { 00082 /* with the NEEDED flag, packages up to date are not reinstalled */ 00083 _alpm_log(handle, ALPM_LOG_WARNING, _("%s-%s is up to date -- skipping\n"), 00084 localpkgname, localpkgver); 00085 return 0; 00086 } else if(!(trans->flags & ALPM_TRANS_FLAG_DOWNLOADONLY)) { 00087 _alpm_log(handle, ALPM_LOG_WARNING, _("%s-%s is up to date -- reinstalling\n"), 00088 localpkgname, localpkgver); 00089 } 00090 } else if(cmp < 0) { 00091 /* local version is newer */ 00092 _alpm_log(handle, ALPM_LOG_WARNING, _("downgrading package %s (%s => %s)\n"), 00093 localpkgname, localpkgver, pkgver); 00094 } 00095 } 00096 00097 /* add the package to the transaction */ 00098 pkg->reason = ALPM_PKG_REASON_EXPLICIT; 00099 _alpm_log(handle, ALPM_LOG_DEBUG, "adding package %s-%s to the transaction add list\n", 00100 pkgname, pkgver); 00101 trans->add = alpm_list_add(trans->add, pkg); 00102 00103 return 0; 00104 } 00105 00106 static int perform_extraction(alpm_handle_t *handle, struct archive *archive, 00107 struct archive_entry *entry, const char *filename, const char *origname) 00108 { 00109 int ret; 00110 const int archive_flags = ARCHIVE_EXTRACT_OWNER | 00111 ARCHIVE_EXTRACT_PERM | 00112 ARCHIVE_EXTRACT_TIME; 00113 00114 archive_entry_set_pathname(entry, filename); 00115 00116 ret = archive_read_extract(archive, entry, archive_flags); 00117 if(ret == ARCHIVE_WARN && archive_errno(archive) != ENOSPC) { 00118 /* operation succeeded but a "non-critical" error was encountered */ 00119 _alpm_log(handle, ALPM_LOG_WARNING, _("warning given when extracting %s (%s)\n"), 00120 origname, archive_error_string(archive)); 00121 } else if(ret != ARCHIVE_OK) { 00122 _alpm_log(handle, ALPM_LOG_ERROR, _("could not extract %s (%s)\n"), 00123 origname, archive_error_string(archive)); 00124 alpm_logaction(handle, "error: could not extract %s (%s)\n", 00125 origname, archive_error_string(archive)); 00126 return 1; 00127 } 00128 return 0; 00129 } 00130 00131 static int try_rename(alpm_handle_t *handle, const char *src, const char *dest) 00132 { 00133 if(rename(src, dest)) { 00134 _alpm_log(handle, ALPM_LOG_ERROR, _("could not rename %s to %s (%s)\n"), 00135 src, dest, strerror(errno)); 00136 alpm_logaction(handle, "error: could not rename %s to %s (%s)\n", 00137 src, dest, strerror(errno)); 00138 return 1; 00139 } 00140 return 0; 00141 } 00142 00143 static int extract_single_file(alpm_handle_t *handle, struct archive *archive, 00144 struct archive_entry *entry, alpm_pkg_t *newpkg, alpm_pkg_t *oldpkg) 00145 { 00146 const char *entryname; 00147 mode_t entrymode; 00148 char filename[PATH_MAX]; /* the actual file we're extracting */ 00149 int needbackup = 0, notouch = 0; 00150 const char *hash_orig = NULL; 00151 char *entryname_orig = NULL; 00152 int errors = 0; 00153 00154 entryname = archive_entry_pathname(entry); 00155 entrymode = archive_entry_mode(entry); 00156 00157 if(strcmp(entryname, ".INSTALL") == 0) { 00158 /* the install script goes inside the db */ 00159 snprintf(filename, PATH_MAX, "%s%s-%s/install", 00160 _alpm_db_path(handle->db_local), newpkg->name, newpkg->version); 00161 archive_entry_set_perm(entry, 0644); 00162 } else if(strcmp(entryname, ".CHANGELOG") == 0) { 00163 /* the changelog goes inside the db */ 00164 snprintf(filename, PATH_MAX, "%s%s-%s/changelog", 00165 _alpm_db_path(handle->db_local), newpkg->name, newpkg->version); 00166 archive_entry_set_perm(entry, 0644); 00167 } else if(*entryname == '.') { 00168 /* for now, ignore all files starting with '.' that haven't 00169 * already been handled (for future possibilities) */ 00170 _alpm_log(handle, ALPM_LOG_DEBUG, "skipping extraction of '%s'\n", entryname); 00171 archive_read_data_skip(archive); 00172 return 0; 00173 } else { 00174 /* build the new entryname relative to handle->root */ 00175 snprintf(filename, PATH_MAX, "%s%s", handle->root, entryname); 00176 } 00177 00178 /* if a file is in NoExtract then we never extract it */ 00179 if(alpm_list_find(handle->noextract, entryname, _alpm_fnmatch)) { 00180 _alpm_log(handle, ALPM_LOG_DEBUG, "%s is in NoExtract, skipping extraction\n", 00181 entryname); 00182 alpm_logaction(handle, "note: %s is in NoExtract, skipping extraction\n", 00183 entryname); 00184 archive_read_data_skip(archive); 00185 return 0; 00186 } 00187 00188 /* Check for file existence. This is one of the more crucial parts 00189 * to get 'right'. Here are the possibilities, with the filesystem 00190 * on the left and the package on the top: 00191 * (F=file, N=node, S=symlink, D=dir) 00192 * | F/N | S | D 00193 * non-existent | 1 | 2 | 3 00194 * F/N | 4 | 5 | 6 00195 * S | 7 | 8 | 9 00196 * D | 10 | 11 | 12 00197 * 00198 * 1,2,3- extract, no magic necessary. lstat (_alpm_lstat) will fail here. 00199 * 4,5,6,7,8- conflict checks should have caught this. either overwrite 00200 * or backup the file. 00201 * 9- follow the symlink, hopefully it is a directory, check it. 00202 * 10- file replacing directory- don't allow it. 00203 * 11- don't extract symlink- a dir exists here. we don't want links to 00204 * links, etc. 00205 * 12- skip extraction, dir already exists. 00206 */ 00207 00208 /* do both a lstat and a stat, so we can see what symlinks point to */ 00209 struct stat lsbuf, sbuf; 00210 if(_alpm_lstat(filename, &lsbuf) != 0 || stat(filename, &sbuf) != 0) { 00211 /* cases 1,2,3: couldn't stat an existing file, skip all backup checks */ 00212 } else { 00213 if(S_ISDIR(lsbuf.st_mode)) { 00214 if(S_ISDIR(entrymode)) { 00215 /* case 12: existing dir, ignore it */ 00216 if(lsbuf.st_mode != entrymode) { 00217 /* if filesystem perms are different than pkg perms, warn user */ 00218 mode_t mask = 07777; 00219 _alpm_log(handle, ALPM_LOG_WARNING, _("directory permissions differ on %s\n" 00220 "filesystem: %o package: %o\n"), entryname, lsbuf.st_mode & mask, 00221 entrymode & mask); 00222 alpm_logaction(handle, "warning: directory permissions differ on %s\n" 00223 "filesystem: %o package: %o\n", entryname, lsbuf.st_mode & mask, 00224 entrymode & mask); 00225 } 00226 _alpm_log(handle, ALPM_LOG_DEBUG, "extract: skipping dir extraction of %s\n", 00227 entryname); 00228 archive_read_data_skip(archive); 00229 return 0; 00230 } else { 00231 /* case 10/11: trying to overwrite dir with file/symlink, don't allow it */ 00232 _alpm_log(handle, ALPM_LOG_ERROR, _("extract: not overwriting dir with file %s\n"), 00233 entryname); 00234 archive_read_data_skip(archive); 00235 return 1; 00236 } 00237 } else if(S_ISLNK(lsbuf.st_mode) && S_ISDIR(entrymode)) { 00238 /* case 9: existing symlink, dir in package */ 00239 if(S_ISDIR(sbuf.st_mode)) { 00240 /* the symlink on FS is to a directory, so we'll use it */ 00241 _alpm_log(handle, ALPM_LOG_DEBUG, "extract: skipping symlink overwrite of %s\n", 00242 entryname); 00243 archive_read_data_skip(archive); 00244 return 0; 00245 } else { 00246 /* this is BAD. symlink was not to a directory */ 00247 _alpm_log(handle, ALPM_LOG_ERROR, _("extract: symlink %s does not point to dir\n"), 00248 entryname); 00249 archive_read_data_skip(archive); 00250 return 1; 00251 } 00252 } else if(S_ISREG(lsbuf.st_mode) && S_ISDIR(entrymode)) { 00253 /* case 6: trying to overwrite file with dir */ 00254 _alpm_log(handle, ALPM_LOG_DEBUG, "extract: overwriting file with dir %s\n", 00255 entryname); 00256 } else if(S_ISREG(entrymode)) { 00257 /* case 4,7: */ 00258 /* if file is in NoUpgrade, don't touch it */ 00259 if(alpm_list_find(handle->noupgrade, entryname, _alpm_fnmatch)) { 00260 notouch = 1; 00261 } else { 00262 alpm_backup_t *backup; 00263 /* go to the backup array and see if our conflict is there */ 00264 /* check newpkg first, so that adding backup files is retroactive */ 00265 backup = _alpm_needbackup(entryname, newpkg); 00266 if(backup) { 00267 /* if we force hash_orig to be non-NULL retroactive backup works */ 00268 hash_orig = ""; 00269 needbackup = 1; 00270 } 00271 00272 /* check oldpkg for a backup entry, store the hash if available */ 00273 if(oldpkg) { 00274 backup = _alpm_needbackup(entryname, oldpkg); 00275 if(backup) { 00276 hash_orig = backup->hash; 00277 needbackup = 1; 00278 } 00279 } 00280 } 00281 } 00282 /* else if(S_ISLNK(entrymode)) */ 00283 /* case 5,8: don't need to do anything special */ 00284 } 00285 00286 /* we need access to the original entryname later after calls to 00287 * archive_entry_set_pathname(), so we need to dupe it and free() later */ 00288 STRDUP(entryname_orig, entryname, RET_ERR(handle, ALPM_ERR_MEMORY, -1)); 00289 00290 if(needbackup) { 00291 char *checkfile; 00292 char *hash_local = NULL, *hash_pkg = NULL; 00293 size_t len; 00294 00295 len = strlen(filename) + 10; 00296 MALLOC(checkfile, len, 00297 errors++; handle->pm_errno = ALPM_ERR_MEMORY; goto needbackup_cleanup); 00298 snprintf(checkfile, len, "%s.paccheck", filename); 00299 00300 if(perform_extraction(handle, archive, entry, checkfile, entryname_orig)) { 00301 errors++; 00302 goto needbackup_cleanup; 00303 } 00304 00305 hash_local = alpm_compute_md5sum(filename); 00306 hash_pkg = alpm_compute_md5sum(checkfile); 00307 00308 /* update the md5 hash in newpkg's backup (it will be the new orginal) */ 00309 alpm_list_t *i; 00310 for(i = alpm_pkg_get_backup(newpkg); i; i = i->next) { 00311 alpm_backup_t *backup = i->data; 00312 char *newhash; 00313 if(!backup->name || strcmp(backup->name, entryname_orig) != 0) { 00314 continue; 00315 } 00316 STRDUP(newhash, hash_pkg, RET_ERR(handle, ALPM_ERR_MEMORY, -1)); 00317 FREE(backup->hash); 00318 backup->hash = newhash; 00319 } 00320 00321 _alpm_log(handle, ALPM_LOG_DEBUG, "checking hashes for %s\n", entryname_orig); 00322 _alpm_log(handle, ALPM_LOG_DEBUG, "current: %s\n", hash_local); 00323 _alpm_log(handle, ALPM_LOG_DEBUG, "new: %s\n", hash_pkg); 00324 _alpm_log(handle, ALPM_LOG_DEBUG, "original: %s\n", hash_orig); 00325 00326 if(!oldpkg) { 00327 if(hash_local && hash_pkg && strcmp(hash_local, hash_pkg) != 0) { 00328 /* looks like we have a local file that has a different hash as the 00329 * file in the package, move it to a .pacorig */ 00330 char *newpath; 00331 size_t newlen = strlen(filename) + 9; 00332 MALLOC(newpath, newlen, 00333 errors++; handle->pm_errno = ALPM_ERR_MEMORY; goto needbackup_cleanup); 00334 snprintf(newpath, newlen, "%s.pacorig", filename); 00335 00336 /* move the existing file to the "pacorig" */ 00337 if(try_rename(handle, filename, newpath)) { 00338 errors++; 00339 errors++; 00340 } else { 00341 /* rename the file we extracted to the real name */ 00342 if(try_rename(handle, checkfile, filename)) { 00343 errors++; 00344 } else { 00345 _alpm_log(handle, ALPM_LOG_WARNING, _("%s saved as %s\n"), filename, newpath); 00346 alpm_logaction(handle, "warning: %s saved as %s\n", filename, newpath); 00347 } 00348 } 00349 free(newpath); 00350 } else { 00351 /* local file is identical to pkg one, so just remove pkg one */ 00352 unlink(checkfile); 00353 } 00354 } else if(hash_orig) { 00355 /* the fun part */ 00356 00357 if(hash_local && strcmp(hash_orig, hash_local) == 0) { 00358 /* installed file has NOT been changed by user */ 00359 if(hash_pkg && strcmp(hash_orig, hash_pkg) != 0) { 00360 _alpm_log(handle, ALPM_LOG_DEBUG, "action: installing new file: %s\n", 00361 entryname_orig); 00362 00363 if(try_rename(handle, checkfile, filename)) { 00364 errors++; 00365 } 00366 } else { 00367 /* no sense in installing the same file twice, install 00368 * ONLY if the original and package hashes differ */ 00369 _alpm_log(handle, ALPM_LOG_DEBUG, "action: leaving existing file in place\n"); 00370 unlink(checkfile); 00371 } 00372 } else if(hash_pkg && strcmp(hash_orig, hash_pkg) == 0) { 00373 /* originally installed file and new file are the same - this 00374 * implies the case above failed - i.e. the file was changed by a 00375 * user */ 00376 _alpm_log(handle, ALPM_LOG_DEBUG, "action: leaving existing file in place\n"); 00377 unlink(checkfile); 00378 } else if(hash_local && hash_pkg && strcmp(hash_local, hash_pkg) == 0) { 00379 /* this would be magical. The above two cases failed, but the 00380 * user changes just so happened to make the new file exactly the 00381 * same as the one in the package... skip it */ 00382 _alpm_log(handle, ALPM_LOG_DEBUG, "action: leaving existing file in place\n"); 00383 unlink(checkfile); 00384 } else { 00385 char *newpath; 00386 size_t newlen = strlen(filename) + 8; 00387 _alpm_log(handle, ALPM_LOG_DEBUG, "action: keeping current file and installing" 00388 " new one with .pacnew ending\n"); 00389 MALLOC(newpath, newlen, 00390 errors++; handle->pm_errno = ALPM_ERR_MEMORY; goto needbackup_cleanup); 00391 snprintf(newpath, newlen, "%s.pacnew", filename); 00392 if(try_rename(handle, checkfile, newpath)) { 00393 errors++; 00394 } else { 00395 _alpm_log(handle, ALPM_LOG_WARNING, _("%s installed as %s\n"), 00396 filename, newpath); 00397 alpm_logaction(handle, "warning: %s installed as %s\n", 00398 filename, newpath); 00399 } 00400 free(newpath); 00401 } 00402 } 00403 00404 needbackup_cleanup: 00405 free(checkfile); 00406 free(hash_local); 00407 free(hash_pkg); 00408 } else { 00409 /* we didn't need a backup */ 00410 if(notouch) { 00411 /* change the path to a .pacnew extension */ 00412 _alpm_log(handle, ALPM_LOG_DEBUG, "%s is in NoUpgrade -- skipping\n", filename); 00413 _alpm_log(handle, ALPM_LOG_WARNING, _("extracting %s as %s.pacnew\n"), filename, filename); 00414 alpm_logaction(handle, "warning: extracting %s as %s.pacnew\n", filename, filename); 00415 strncat(filename, ".pacnew", PATH_MAX - strlen(filename)); 00416 } else { 00417 _alpm_log(handle, ALPM_LOG_DEBUG, "extracting %s\n", filename); 00418 } 00419 00420 if(handle->trans->flags & ALPM_TRANS_FLAG_FORCE) { 00421 /* if FORCE was used, unlink() each file (whether it's there 00422 * or not) before extracting. This prevents the old "Text file busy" 00423 * error that crops up if forcing a glibc or pacman upgrade. */ 00424 unlink(filename); 00425 } 00426 00427 if(perform_extraction(handle, archive, entry, filename, entryname_orig)) { 00428 /* error */ 00429 free(entryname_orig); 00430 errors++; 00431 return errors; 00432 } 00433 00434 /* calculate an hash if this is in newpkg's backup */ 00435 alpm_list_t *i; 00436 for(i = alpm_pkg_get_backup(newpkg); i; i = i->next) { 00437 alpm_backup_t *backup = i->data; 00438 char *newhash; 00439 if(!backup->name || strcmp(backup->name, entryname_orig) != 0) { 00440 continue; 00441 } 00442 _alpm_log(handle, ALPM_LOG_DEBUG, "appending backup entry for %s\n", entryname_orig); 00443 newhash = alpm_compute_md5sum(filename); 00444 FREE(backup->hash); 00445 backup->hash = newhash; 00446 } 00447 } 00448 free(entryname_orig); 00449 return errors; 00450 } 00451 00452 static int commit_single_pkg(alpm_handle_t *handle, alpm_pkg_t *newpkg, 00453 size_t pkg_current, size_t pkg_count) 00454 { 00455 int i, ret = 0, errors = 0; 00456 int is_upgrade; 00457 alpm_pkg_t *oldpkg = NULL; 00458 alpm_db_t *db = handle->db_local; 00459 alpm_trans_t *trans = handle->trans; 00460 const char *pkgfile; 00461 00462 ASSERT(trans != NULL, return -1); 00463 00464 /* see if this is an upgrade. if so, remove the old package first */ 00465 alpm_pkg_t *local = _alpm_db_get_pkgfromcache(db, newpkg->name); 00466 if(local) { 00467 is_upgrade = 1; 00468 00469 /* we'll need to save some record for backup checks later */ 00470 if(_alpm_pkg_dup(local, &oldpkg) == -1) { 00471 ret = -1; 00472 goto cleanup; 00473 } 00474 00475 /* copy over the install reason */ 00476 newpkg->reason = alpm_pkg_get_reason(local); 00477 00478 EVENT(handle, ALPM_EVENT_UPGRADE_START, newpkg, local); 00479 } else { 00480 is_upgrade = 0; 00481 EVENT(handle, ALPM_EVENT_ADD_START, newpkg, NULL); 00482 } 00483 00484 pkgfile = newpkg->origin_data.file; 00485 00486 _alpm_log(handle, ALPM_LOG_DEBUG, "%s package %s-%s\n", 00487 is_upgrade ? "upgrading" : "adding", newpkg->name, newpkg->version); 00488 /* pre_install/pre_upgrade scriptlet */ 00489 if(alpm_pkg_has_scriptlet(newpkg) && 00490 !(trans->flags & ALPM_TRANS_FLAG_NOSCRIPTLET)) { 00491 const char *scriptlet_name = is_upgrade ? "pre_upgrade" : "pre_install"; 00492 _alpm_runscriptlet(handle, pkgfile, 00493 scriptlet_name, newpkg->version, NULL, 1); 00494 } 00495 00496 /* we override any pre-set reason if we have alldeps or allexplicit set */ 00497 if(trans->flags & ALPM_TRANS_FLAG_ALLDEPS) { 00498 newpkg->reason = ALPM_PKG_REASON_DEPEND; 00499 } else if(trans->flags & ALPM_TRANS_FLAG_ALLEXPLICIT) { 00500 newpkg->reason = ALPM_PKG_REASON_EXPLICIT; 00501 } 00502 00503 if(oldpkg) { 00504 /* set up fake remove transaction */ 00505 if(_alpm_remove_single_package(handle, oldpkg, newpkg, 0, 0) == -1) { 00506 handle->pm_errno = ALPM_ERR_TRANS_ABORT; 00507 ret = -1; 00508 goto cleanup; 00509 } 00510 } 00511 00512 /* prepare directory for database entries so permission are correct after 00513 changelog/install script installation (FS#12263) */ 00514 if(_alpm_local_db_prepare(db, newpkg)) { 00515 alpm_logaction(handle, "error: could not create database entry %s-%s\n", 00516 newpkg->name, newpkg->version); 00517 handle->pm_errno = ALPM_ERR_DB_WRITE; 00518 ret = -1; 00519 goto cleanup; 00520 } 00521 00522 if(!(trans->flags & ALPM_TRANS_FLAG_DBONLY)) { 00523 struct archive *archive; 00524 struct archive_entry *entry; 00525 struct stat buf; 00526 int fd, cwdfd; 00527 00528 _alpm_log(handle, ALPM_LOG_DEBUG, "extracting files\n"); 00529 00530 fd = _alpm_open_archive(db->handle, pkgfile, &buf, 00531 &archive, ALPM_ERR_PKG_OPEN); 00532 if(fd < 0) { 00533 ret = -1; 00534 goto cleanup; 00535 } 00536 00537 /* save the cwd so we can restore it later */ 00538 OPEN(cwdfd, ".", O_RDONLY); 00539 if(cwdfd < 0) { 00540 _alpm_log(handle, ALPM_LOG_ERROR, _("could not get current working directory\n")); 00541 } 00542 00543 /* libarchive requires this for extracting hard links */ 00544 if(chdir(handle->root) != 0) { 00545 _alpm_log(handle, ALPM_LOG_ERROR, _("could not change directory to %s (%s)\n"), 00546 handle->root, strerror(errno)); 00547 archive_read_finish(archive); 00548 CLOSE(fd); 00549 ret = -1; 00550 goto cleanup; 00551 } 00552 00553 /* call PROGRESS once with 0 percent, as we sort-of skip that here */ 00554 if(is_upgrade) { 00555 PROGRESS(handle, ALPM_PROGRESS_UPGRADE_START, 00556 newpkg->name, 0, pkg_count, pkg_current); 00557 } else { 00558 PROGRESS(handle, ALPM_PROGRESS_ADD_START, 00559 newpkg->name, 0, pkg_count, pkg_current); 00560 } 00561 00562 for(i = 0; archive_read_next_header(archive, &entry) == ARCHIVE_OK; i++) { 00563 int percent; 00564 00565 if(newpkg->size != 0) { 00566 /* Using compressed size for calculations here, as newpkg->isize is not 00567 * exact when it comes to comparing to the ACTUAL uncompressed size 00568 * (missing metadata sizes) */ 00569 int64_t pos = archive_position_compressed(archive); 00570 percent = (pos * 100) / newpkg->size; 00571 if(percent >= 100) { 00572 percent = 100; 00573 } 00574 } else { 00575 percent = 0; 00576 } 00577 00578 if(is_upgrade) { 00579 PROGRESS(handle, ALPM_PROGRESS_UPGRADE_START, 00580 newpkg->name, percent, pkg_count, pkg_current); 00581 } else { 00582 PROGRESS(handle, ALPM_PROGRESS_ADD_START, 00583 newpkg->name, percent, pkg_count, pkg_current); 00584 } 00585 00586 /* extract the next file from the archive */ 00587 errors += extract_single_file(handle, archive, entry, newpkg, oldpkg); 00588 } 00589 archive_read_finish(archive); 00590 CLOSE(fd); 00591 00592 /* restore the old cwd if we have it */ 00593 if(cwdfd >= 0) { 00594 if(fchdir(cwdfd) != 0) { 00595 _alpm_log(handle, ALPM_LOG_ERROR, 00596 _("could not restore working directory (%s)\n"), strerror(errno)); 00597 } 00598 CLOSE(cwdfd); 00599 } 00600 00601 if(errors) { 00602 ret = -1; 00603 if(is_upgrade) { 00604 _alpm_log(handle, ALPM_LOG_ERROR, _("problem occurred while upgrading %s\n"), 00605 newpkg->name); 00606 alpm_logaction(handle, "error: problem occurred while upgrading %s\n", 00607 newpkg->name); 00608 } else { 00609 _alpm_log(handle, ALPM_LOG_ERROR, _("problem occurred while installing %s\n"), 00610 newpkg->name); 00611 alpm_logaction(handle, "error: problem occurred while installing %s\n", 00612 newpkg->name); 00613 } 00614 } 00615 } 00616 00617 /* make an install date (in UTC) */ 00618 newpkg->installdate = time(NULL); 00619 00620 _alpm_log(handle, ALPM_LOG_DEBUG, "updating database\n"); 00621 _alpm_log(handle, ALPM_LOG_DEBUG, "adding database entry '%s'\n", newpkg->name); 00622 00623 if(_alpm_local_db_write(db, newpkg, INFRQ_ALL)) { 00624 _alpm_log(handle, ALPM_LOG_ERROR, _("could not update database entry %s-%s\n"), 00625 newpkg->name, newpkg->version); 00626 alpm_logaction(handle, "error: could not update database entry %s-%s\n", 00627 newpkg->name, newpkg->version); 00628 handle->pm_errno = ALPM_ERR_DB_WRITE; 00629 ret = -1; 00630 goto cleanup; 00631 } 00632 00633 if(_alpm_db_add_pkgincache(db, newpkg) == -1) { 00634 _alpm_log(handle, ALPM_LOG_ERROR, _("could not add entry '%s' in cache\n"), 00635 newpkg->name); 00636 } 00637 00638 if(is_upgrade) { 00639 PROGRESS(handle, ALPM_PROGRESS_UPGRADE_START, 00640 newpkg->name, 100, pkg_count, pkg_current); 00641 } else { 00642 PROGRESS(handle, ALPM_PROGRESS_ADD_START, 00643 newpkg->name, 100, pkg_count, pkg_current); 00644 } 00645 00646 /* run the post-install script if it exists */ 00647 if(alpm_pkg_has_scriptlet(newpkg) 00648 && !(trans->flags & ALPM_TRANS_FLAG_NOSCRIPTLET)) { 00649 char *scriptlet = _alpm_local_db_pkgpath(db, newpkg, "install"); 00650 const char *scriptlet_name = is_upgrade ? "post_upgrade" : "post_install"; 00651 00652 _alpm_runscriptlet(handle, scriptlet, scriptlet_name, 00653 newpkg->version, oldpkg ? oldpkg->version : NULL, 0); 00654 free(scriptlet); 00655 } 00656 00657 if(is_upgrade) { 00658 EVENT(handle, ALPM_EVENT_UPGRADE_DONE, newpkg, oldpkg); 00659 } else { 00660 EVENT(handle, ALPM_EVENT_ADD_DONE, newpkg, oldpkg); 00661 } 00662 00663 cleanup: 00664 _alpm_pkg_free(oldpkg); 00665 return ret; 00666 } 00667 00668 int _alpm_upgrade_packages(alpm_handle_t *handle) 00669 { 00670 size_t pkg_count, pkg_current; 00671 int skip_ldconfig = 0, ret = 0; 00672 alpm_list_t *targ; 00673 alpm_trans_t *trans = handle->trans; 00674 00675 if(trans->add == NULL) { 00676 return 0; 00677 } 00678 00679 pkg_count = alpm_list_count(trans->add); 00680 pkg_current = 1; 00681 00682 /* loop through our package list adding/upgrading one at a time */ 00683 for(targ = trans->add; targ; targ = targ->next) { 00684 alpm_pkg_t *newpkg = targ->data; 00685 00686 if(handle->trans->state == STATE_INTERRUPTED) { 00687 return ret; 00688 } 00689 00690 if(commit_single_pkg(handle, newpkg, pkg_current, pkg_count)) { 00691 /* something screwed up on the commit, abort the trans */ 00692 trans->state = STATE_INTERRUPTED; 00693 handle->pm_errno = ALPM_ERR_TRANS_ABORT; 00694 /* running ldconfig at this point could possibly screw system */ 00695 skip_ldconfig = 1; 00696 ret = -1; 00697 } 00698 00699 pkg_current++; 00700 } 00701 00702 if(!skip_ldconfig) { 00703 /* run ldconfig if it exists */ 00704 _alpm_ldconfig(handle); 00705 } 00706 00707 return ret; 00708 } 00709 00710 /* vim: set ts=2 sw=2 noet: */