Rename pmtrans_t to alpm_trans_t
[pacman-ng.git] / lib / libalpm / add.c
blob3455744f83554e0bf434067194793d10cd6e61dc
1 /*
2 * add.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 <stdlib.h>
24 #include <errno.h>
25 #include <time.h>
26 #include <string.h>
27 #include <limits.h>
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 #include <unistd.h>
31 #include <inttypes.h> /* int64_t */
32 #include <stdint.h> /* intmax_t */
34 /* libarchive */
35 #include <archive.h>
36 #include <archive_entry.h>
38 /* libalpm */
39 #include "add.h"
40 #include "alpm.h"
41 #include "alpm_list.h"
42 #include "handle.h"
43 #include "trans.h"
44 #include "util.h"
45 #include "log.h"
46 #include "backup.h"
47 #include "package.h"
48 #include "db.h"
49 #include "remove.h"
50 #include "handle.h"
52 /** Add a package to the transaction. */
53 int SYMEXPORT alpm_add_pkg(alpm_handle_t *handle, alpm_pkg_t *pkg)
55 const char *pkgname, *pkgver;
56 alpm_trans_t *trans;
57 alpm_pkg_t *local;
59 /* Sanity checks */
60 CHECK_HANDLE(handle, return -1);
61 ASSERT(pkg != NULL, RET_ERR(handle, PM_ERR_WRONG_ARGS, -1));
62 ASSERT(handle == pkg->handle, RET_ERR(handle, PM_ERR_WRONG_ARGS, -1));
63 trans = handle->trans;
64 ASSERT(trans != NULL, RET_ERR(handle, PM_ERR_TRANS_NULL, -1));
65 ASSERT(trans->state == STATE_INITIALIZED,
66 RET_ERR(handle, PM_ERR_TRANS_NOT_INITIALIZED, -1));
68 pkgname = pkg->name;
69 pkgver = pkg->version;
71 _alpm_log(handle, PM_LOG_DEBUG, "adding package '%s'\n", pkgname);
73 if(_alpm_pkg_find(trans->add, pkgname)) {
74 RET_ERR(handle, PM_ERR_TRANS_DUP_TARGET, -1);
77 local = _alpm_db_get_pkgfromcache(handle->db_local, pkgname);
78 if(local) {
79 const char *localpkgname = alpm_pkg_get_name(local);
80 const char *localpkgver = alpm_pkg_get_version(local);
81 int cmp = _alpm_pkg_compare_versions(pkg, local);
83 if(cmp == 0) {
84 if(trans->flags & PM_TRANS_FLAG_NEEDED) {
85 /* with the NEEDED flag, packages up to date are not reinstalled */
86 _alpm_log(handle, PM_LOG_WARNING, _("%s-%s is up to date -- skipping\n"),
87 localpkgname, localpkgver);
88 return 0;
89 } else if(!(trans->flags & PM_TRANS_FLAG_DOWNLOADONLY)) {
90 _alpm_log(handle, PM_LOG_WARNING, _("%s-%s is up to date -- reinstalling\n"),
91 localpkgname, localpkgver);
93 } else if(cmp < 0) {
94 /* local version is newer */
95 _alpm_log(handle, PM_LOG_WARNING, _("downgrading package %s (%s => %s)\n"),
96 localpkgname, localpkgver, pkgver);
100 /* add the package to the transaction */
101 pkg->reason = PM_PKG_REASON_EXPLICIT;
102 _alpm_log(handle, PM_LOG_DEBUG, "adding package %s-%s to the transaction add list\n",
103 pkgname, pkgver);
104 trans->add = alpm_list_add(trans->add, pkg);
106 return 0;
109 static int perform_extraction(alpm_handle_t *handle, struct archive *archive,
110 struct archive_entry *entry, const char *filename, const char *origname)
112 int ret;
113 const int archive_flags = ARCHIVE_EXTRACT_OWNER |
114 ARCHIVE_EXTRACT_PERM |
115 ARCHIVE_EXTRACT_TIME;
117 archive_entry_set_pathname(entry, filename);
119 ret = archive_read_extract(archive, entry, archive_flags);
120 if(ret == ARCHIVE_WARN && archive_errno(archive) != ENOSPC) {
121 /* operation succeeded but a "non-critical" error was encountered */
122 _alpm_log(handle, PM_LOG_WARNING, _("warning given when extracting %s (%s)\n"),
123 origname, archive_error_string(archive));
124 } else if(ret != ARCHIVE_OK) {
125 _alpm_log(handle, PM_LOG_ERROR, _("could not extract %s (%s)\n"),
126 origname, archive_error_string(archive));
127 alpm_logaction(handle, "error: could not extract %s (%s)\n",
128 origname, archive_error_string(archive));
129 return 1;
131 return 0;
134 static int extract_single_file(alpm_handle_t *handle, struct archive *archive,
135 struct archive_entry *entry, alpm_pkg_t *newpkg, alpm_pkg_t *oldpkg)
137 const char *entryname;
138 mode_t entrymode;
139 char filename[PATH_MAX]; /* the actual file we're extracting */
140 int needbackup = 0, notouch = 0;
141 const char *hash_orig = NULL;
142 char *entryname_orig = NULL;
143 int errors = 0;
145 entryname = archive_entry_pathname(entry);
146 entrymode = archive_entry_mode(entry);
148 memset(filename, 0, PATH_MAX); /* just to be sure */
150 if(strcmp(entryname, ".INSTALL") == 0) {
151 /* the install script goes inside the db */
152 snprintf(filename, PATH_MAX, "%s%s-%s/install",
153 _alpm_db_path(handle->db_local), newpkg->name, newpkg->version);
154 archive_entry_set_perm(entry, 0644);
155 } else if(strcmp(entryname, ".CHANGELOG") == 0) {
156 /* the changelog goes inside the db */
157 snprintf(filename, PATH_MAX, "%s%s-%s/changelog",
158 _alpm_db_path(handle->db_local), newpkg->name, newpkg->version);
159 archive_entry_set_perm(entry, 0644);
160 } else if(*entryname == '.') {
161 /* for now, ignore all files starting with '.' that haven't
162 * already been handled (for future possibilities) */
163 _alpm_log(handle, PM_LOG_DEBUG, "skipping extraction of '%s'\n", entryname);
164 archive_read_data_skip(archive);
165 return 0;
166 } else {
167 /* build the new entryname relative to handle->root */
168 snprintf(filename, PATH_MAX, "%s%s", handle->root, entryname);
171 /* if a file is in NoExtract then we never extract it */
172 if(alpm_list_find_str(handle->noextract, entryname)) {
173 _alpm_log(handle, PM_LOG_DEBUG, "%s is in NoExtract, skipping extraction\n",
174 entryname);
175 alpm_logaction(handle, "note: %s is in NoExtract, skipping extraction\n",
176 entryname);
177 archive_read_data_skip(archive);
178 return 0;
181 /* Check for file existence. This is one of the more crucial parts
182 * to get 'right'. Here are the possibilities, with the filesystem
183 * on the left and the package on the top:
184 * (F=file, N=node, S=symlink, D=dir)
185 * | F/N | S | D
186 * non-existent | 1 | 2 | 3
187 * F/N | 4 | 5 | 6
188 * S | 7 | 8 | 9
189 * D | 10 | 11 | 12
191 * 1,2,3- extract, no magic necessary. lstat (_alpm_lstat) will fail here.
192 * 4,5,6,7,8- conflict checks should have caught this. either overwrite
193 * or backup the file.
194 * 9- follow the symlink, hopefully it is a directory, check it.
195 * 10- file replacing directory- don't allow it.
196 * 11- don't extract symlink- a dir exists here. we don't want links to
197 * links, etc.
198 * 12- skip extraction, dir already exists.
201 /* do both a lstat and a stat, so we can see what symlinks point to */
202 struct stat lsbuf, sbuf;
203 if(_alpm_lstat(filename, &lsbuf) != 0 || stat(filename, &sbuf) != 0) {
204 /* cases 1,2,3: couldn't stat an existing file, skip all backup checks */
205 } else {
206 if(S_ISDIR(lsbuf.st_mode)) {
207 if(S_ISDIR(entrymode)) {
208 /* case 12: existing dir, ignore it */
209 if(lsbuf.st_mode != entrymode) {
210 /* if filesystem perms are different than pkg perms, warn user */
211 mode_t mask = 07777;
212 _alpm_log(handle, PM_LOG_WARNING, _("directory permissions differ on %s\n"
213 "filesystem: %o package: %o\n"), entryname, lsbuf.st_mode & mask,
214 entrymode & mask);
215 alpm_logaction(handle, "warning: directory permissions differ on %s\n"
216 "filesystem: %o package: %o\n", entryname, lsbuf.st_mode & mask,
217 entrymode & mask);
219 _alpm_log(handle, PM_LOG_DEBUG, "extract: skipping dir extraction of %s\n",
220 entryname);
221 archive_read_data_skip(archive);
222 return 0;
223 } else {
224 /* case 10/11: trying to overwrite dir with file/symlink, don't allow it */
225 _alpm_log(handle, PM_LOG_ERROR, _("extract: not overwriting dir with file %s\n"),
226 entryname);
227 archive_read_data_skip(archive);
228 return 1;
230 } else if(S_ISLNK(lsbuf.st_mode) && S_ISDIR(entrymode)) {
231 /* case 9: existing symlink, dir in package */
232 if(S_ISDIR(sbuf.st_mode)) {
233 /* the symlink on FS is to a directory, so we'll use it */
234 _alpm_log(handle, PM_LOG_DEBUG, "extract: skipping symlink overwrite of %s\n",
235 entryname);
236 archive_read_data_skip(archive);
237 return 0;
238 } else {
239 /* this is BAD. symlink was not to a directory */
240 _alpm_log(handle, PM_LOG_ERROR, _("extract: symlink %s does not point to dir\n"),
241 entryname);
242 archive_read_data_skip(archive);
243 return 1;
245 } else if(S_ISREG(lsbuf.st_mode) && S_ISDIR(entrymode)) {
246 /* case 6: trying to overwrite file with dir */
247 _alpm_log(handle, PM_LOG_DEBUG, "extract: overwriting file with dir %s\n",
248 entryname);
249 } else if(S_ISREG(entrymode)) {
250 /* case 4,7: */
251 /* if file is in NoUpgrade, don't touch it */
252 if(alpm_list_find_str(handle->noupgrade, entryname)) {
253 notouch = 1;
254 } else {
255 pmbackup_t *backup;
256 /* go to the backup array and see if our conflict is there */
257 /* check newpkg first, so that adding backup files is retroactive */
258 backup = _alpm_needbackup(entryname, alpm_pkg_get_backup(newpkg));
259 if(backup) {
260 needbackup = 1;
263 /* check oldpkg for a backup entry, store the hash if available */
264 if(oldpkg) {
265 backup = _alpm_needbackup(entryname, alpm_pkg_get_backup(oldpkg));
266 if(backup) {
267 hash_orig = backup->hash;
268 needbackup = 1;
272 /* if we force hash_orig to be non-NULL retroactive backup works */
273 if(needbackup && !hash_orig) {
274 hash_orig = "";
278 /* else if(S_ISLNK(entrymode)) */
279 /* case 5,8: don't need to do anything special */
282 /* we need access to the original entryname later after calls to
283 * archive_entry_set_pathname(), so we need to dupe it and free() later */
284 STRDUP(entryname_orig, entryname, RET_ERR(handle, PM_ERR_MEMORY, -1));
286 if(needbackup) {
287 char checkfile[PATH_MAX];
288 char *hash_local = NULL, *hash_pkg = NULL;
289 int ret;
291 snprintf(checkfile, PATH_MAX, "%s.paccheck", filename);
293 ret = perform_extraction(handle, archive, entry, checkfile, entryname_orig);
294 if(ret == 1) {
295 /* error */
296 FREE(entryname_orig);
297 return 1;
300 hash_local = alpm_compute_md5sum(filename);
301 hash_pkg = alpm_compute_md5sum(checkfile);
303 /* update the md5 hash in newpkg's backup (it will be the new orginal) */
304 alpm_list_t *i;
305 for(i = alpm_pkg_get_backup(newpkg); i; i = i->next) {
306 pmbackup_t *backup = i->data;
307 char *newhash;
308 if(!backup->name || strcmp(backup->name, entryname_orig) != 0) {
309 continue;
311 STRDUP(newhash, hash_pkg, RET_ERR(handle, PM_ERR_MEMORY, -1));
312 FREE(backup->hash);
313 backup->hash = newhash;
316 _alpm_log(handle, PM_LOG_DEBUG, "checking hashes for %s\n", entryname_orig);
317 _alpm_log(handle, PM_LOG_DEBUG, "current: %s\n", hash_local);
318 _alpm_log(handle, PM_LOG_DEBUG, "new: %s\n", hash_pkg);
319 _alpm_log(handle, PM_LOG_DEBUG, "original: %s\n", hash_orig);
321 if(!oldpkg) {
322 if(strcmp(hash_local, hash_pkg) != 0) {
323 /* looks like we have a local file that has a different hash as the
324 * file in the package, move it to a .pacorig */
325 char newpath[PATH_MAX];
326 snprintf(newpath, PATH_MAX, "%s.pacorig", filename);
328 /* move the existing file to the "pacorig" */
329 if(rename(filename, newpath)) {
330 _alpm_log(handle, PM_LOG_ERROR, _("could not rename %s to %s (%s)\n"),
331 filename, newpath, strerror(errno));
332 alpm_logaction(handle, "error: could not rename %s to %s (%s)\n",
333 filename, newpath, strerror(errno));
334 errors++;
335 } else {
336 /* rename the file we extracted to the real name */
337 if(rename(checkfile, filename)) {
338 _alpm_log(handle, PM_LOG_ERROR, _("could not rename %s to %s (%s)\n"),
339 checkfile, filename, strerror(errno));
340 alpm_logaction(handle, "error: could not rename %s to %s (%s)\n",
341 checkfile, filename, strerror(errno));
342 errors++;
343 } else {
344 _alpm_log(handle, PM_LOG_WARNING, _("%s saved as %s\n"), filename, newpath);
345 alpm_logaction(handle, "warning: %s saved as %s\n", filename, newpath);
348 } else {
349 /* local file is identical to pkg one, so just remove pkg one */
350 unlink(checkfile);
352 } else if(hash_orig) {
353 /* the fun part */
355 if(strcmp(hash_orig, hash_local) == 0) {
356 /* installed file has NOT been changed by user */
357 if(strcmp(hash_orig, hash_pkg) != 0) {
358 _alpm_log(handle, PM_LOG_DEBUG, "action: installing new file: %s\n",
359 entryname_orig);
361 if(rename(checkfile, filename)) {
362 _alpm_log(handle, PM_LOG_ERROR, _("could not rename %s to %s (%s)\n"),
363 checkfile, filename, strerror(errno));
364 alpm_logaction(handle, "error: could not rename %s to %s (%s)\n",
365 checkfile, filename, strerror(errno));
366 errors++;
368 } else {
369 /* there's no sense in installing the same file twice, install
370 * ONLY is the original and package hashes differ */
371 _alpm_log(handle, PM_LOG_DEBUG, "action: leaving existing file in place\n");
372 unlink(checkfile);
374 } else if(strcmp(hash_orig, hash_pkg) == 0) {
375 /* originally installed file and new file are the same - this
376 * implies the case above failed - i.e. the file was changed by a
377 * user */
378 _alpm_log(handle, PM_LOG_DEBUG, "action: leaving existing file in place\n");
379 unlink(checkfile);
380 } else if(strcmp(hash_local, hash_pkg) == 0) {
381 /* this would be magical. The above two cases failed, but the
382 * user changes just so happened to make the new file exactly the
383 * same as the one in the package... skip it */
384 _alpm_log(handle, PM_LOG_DEBUG, "action: leaving existing file in place\n");
385 unlink(checkfile);
386 } else {
387 char newpath[PATH_MAX];
388 _alpm_log(handle, PM_LOG_DEBUG, "action: keeping current file and installing"
389 " new one with .pacnew ending\n");
390 snprintf(newpath, PATH_MAX, "%s.pacnew", filename);
391 if(rename(checkfile, newpath)) {
392 _alpm_log(handle, PM_LOG_ERROR, _("could not install %s as %s (%s)\n"),
393 filename, newpath, strerror(errno));
394 alpm_logaction(handle, "error: could not install %s as %s (%s)\n",
395 filename, newpath, strerror(errno));
396 } else {
397 _alpm_log(handle, PM_LOG_WARNING, _("%s installed as %s\n"),
398 filename, newpath);
399 alpm_logaction(handle, "warning: %s installed as %s\n",
400 filename, newpath);
405 FREE(hash_local);
406 FREE(hash_pkg);
407 } else {
408 int ret;
410 /* we didn't need a backup */
411 if(notouch) {
412 /* change the path to a .pacnew extension */
413 _alpm_log(handle, PM_LOG_DEBUG, "%s is in NoUpgrade -- skipping\n", filename);
414 _alpm_log(handle, PM_LOG_WARNING, _("extracting %s as %s.pacnew\n"), filename, filename);
415 alpm_logaction(handle, "warning: extracting %s as %s.pacnew\n", filename, filename);
416 strncat(filename, ".pacnew", PATH_MAX - strlen(filename));
417 } else {
418 _alpm_log(handle, PM_LOG_DEBUG, "extracting %s\n", filename);
421 if(handle->trans->flags & PM_TRANS_FLAG_FORCE) {
422 /* if FORCE was used, unlink() each file (whether it's there
423 * or not) before extracting. This prevents the old "Text file busy"
424 * error that crops up if forcing a glibc or pacman upgrade. */
425 unlink(filename);
428 ret = perform_extraction(handle, archive, entry, filename, entryname_orig);
429 if(ret == 1) {
430 /* error */
431 FREE(entryname_orig);
432 return 1;
435 /* calculate an hash if this is in newpkg's backup */
436 alpm_list_t *i;
437 for(i = alpm_pkg_get_backup(newpkg); i; i = i->next) {
438 pmbackup_t *backup = i->data;
439 char *newhash;
440 if(!backup->name || strcmp(backup->name, entryname_orig) != 0) {
441 continue;
443 _alpm_log(handle, PM_LOG_DEBUG, "appending backup entry for %s\n", entryname_orig);
444 newhash = alpm_compute_md5sum(filename);
445 FREE(backup->hash);
446 backup->hash = newhash;
449 FREE(entryname_orig);
450 return errors;
453 static int commit_single_pkg(alpm_handle_t *handle, alpm_pkg_t *newpkg,
454 size_t pkg_current, size_t pkg_count)
456 int i, ret = 0, errors = 0;
457 char scriptlet[PATH_MAX];
458 int is_upgrade = 0;
459 alpm_pkg_t *oldpkg = NULL;
460 alpm_db_t *db = handle->db_local;
461 alpm_trans_t *trans = handle->trans;
463 snprintf(scriptlet, PATH_MAX, "%s%s-%s/install",
464 _alpm_db_path(db), alpm_pkg_get_name(newpkg),
465 alpm_pkg_get_version(newpkg));
467 /* see if this is an upgrade. if so, remove the old package first */
468 alpm_pkg_t *local = _alpm_db_get_pkgfromcache(db, newpkg->name);
469 if(local) {
470 is_upgrade = 1;
472 /* we'll need to save some record for backup checks later */
473 oldpkg = _alpm_pkg_dup(local);
474 /* make sure all infos are loaded because the database entry
475 * will be removed soon */
476 _alpm_local_db_read(oldpkg->origin_data.db, oldpkg, INFRQ_ALL);
478 EVENT(trans, PM_TRANS_EVT_UPGRADE_START, newpkg, oldpkg);
479 _alpm_log(handle, PM_LOG_DEBUG, "upgrading package %s-%s\n",
480 newpkg->name, newpkg->version);
482 /* copy over the install reason */
483 newpkg->reason = alpm_pkg_get_reason(oldpkg);
485 /* pre_upgrade scriptlet */
486 if(alpm_pkg_has_scriptlet(newpkg) && !(trans->flags & PM_TRANS_FLAG_NOSCRIPTLET)) {
487 _alpm_runscriptlet(handle, newpkg->origin_data.file,
488 "pre_upgrade", newpkg->version, oldpkg->version);
490 } else {
491 is_upgrade = 0;
493 EVENT(trans, PM_TRANS_EVT_ADD_START, newpkg, NULL);
494 _alpm_log(handle, PM_LOG_DEBUG, "adding package %s-%s\n",
495 newpkg->name, newpkg->version);
497 /* pre_install scriptlet */
498 if(alpm_pkg_has_scriptlet(newpkg) && !(trans->flags & PM_TRANS_FLAG_NOSCRIPTLET)) {
499 _alpm_runscriptlet(handle, newpkg->origin_data.file,
500 "pre_install", newpkg->version, NULL);
504 /* we override any pre-set reason if we have alldeps or allexplicit set */
505 if(trans->flags & PM_TRANS_FLAG_ALLDEPS) {
506 newpkg->reason = PM_PKG_REASON_DEPEND;
507 } else if(trans->flags & PM_TRANS_FLAG_ALLEXPLICIT) {
508 newpkg->reason = PM_PKG_REASON_EXPLICIT;
511 if(oldpkg) {
512 /* set up fake remove transaction */
513 if(_alpm_upgraderemove_package(handle, oldpkg, newpkg) == -1) {
514 handle->pm_errno = PM_ERR_TRANS_ABORT;
515 ret = -1;
516 goto cleanup;
520 /* prepare directory for database entries so permission are correct after
521 changelog/install script installation (FS#12263) */
522 if(_alpm_local_db_prepare(db, newpkg)) {
523 alpm_logaction(handle, "error: could not create database entry %s-%s\n",
524 alpm_pkg_get_name(newpkg), alpm_pkg_get_version(newpkg));
525 handle->pm_errno = PM_ERR_DB_WRITE;
526 ret = -1;
527 goto cleanup;
530 if(!(trans->flags & PM_TRANS_FLAG_DBONLY)) {
531 struct archive *archive;
532 struct archive_entry *entry;
533 char cwd[PATH_MAX] = "";
534 int restore_cwd = 0;
536 _alpm_log(handle, PM_LOG_DEBUG, "extracting files\n");
538 if((archive = archive_read_new()) == NULL) {
539 handle->pm_errno = PM_ERR_LIBARCHIVE;
540 ret = -1;
541 goto cleanup;
544 archive_read_support_compression_all(archive);
545 archive_read_support_format_all(archive);
547 _alpm_log(handle, PM_LOG_DEBUG, "archive: %s\n", newpkg->origin_data.file);
548 if(archive_read_open_filename(archive, newpkg->origin_data.file,
549 ARCHIVE_DEFAULT_BYTES_PER_BLOCK) != ARCHIVE_OK) {
550 handle->pm_errno = PM_ERR_PKG_OPEN;
551 ret = -1;
552 goto cleanup;
555 /* save the cwd so we can restore it later */
556 if(getcwd(cwd, PATH_MAX) == NULL) {
557 _alpm_log(handle, PM_LOG_ERROR, _("could not get current working directory\n"));
558 } else {
559 restore_cwd = 1;
562 /* libarchive requires this for extracting hard links */
563 if(chdir(handle->root) != 0) {
564 _alpm_log(handle, PM_LOG_ERROR, _("could not change directory to %s (%s)\n"),
565 handle->root, strerror(errno));
566 ret = -1;
567 goto cleanup;
570 /* call PROGRESS once with 0 percent, as we sort-of skip that here */
571 if(is_upgrade) {
572 PROGRESS(trans, PM_TRANS_PROGRESS_UPGRADE_START,
573 alpm_pkg_get_name(newpkg), 0, pkg_count, pkg_current);
574 } else {
575 PROGRESS(trans, PM_TRANS_PROGRESS_ADD_START,
576 alpm_pkg_get_name(newpkg), 0, pkg_count, pkg_current);
579 for(i = 0; archive_read_next_header(archive, &entry) == ARCHIVE_OK; i++) {
580 int percent;
582 if(newpkg->size != 0) {
583 /* Using compressed size for calculations here, as newpkg->isize is not
584 * exact when it comes to comparing to the ACTUAL uncompressed size
585 * (missing metadata sizes) */
586 int64_t pos = archive_position_compressed(archive);
587 percent = (pos * 100) / newpkg->size;
588 _alpm_log(handle, PM_LOG_DEBUG, "decompression progress: "
589 "%d%% (%"PRId64" / %jd)\n",
590 percent, pos, (intmax_t)newpkg->size);
591 if(percent >= 100) {
592 percent = 100;
594 } else {
595 percent = 0;
598 if(is_upgrade) {
599 PROGRESS(trans, PM_TRANS_PROGRESS_UPGRADE_START,
600 alpm_pkg_get_name(newpkg), percent, pkg_count,
601 pkg_current);
602 } else {
603 PROGRESS(trans, PM_TRANS_PROGRESS_ADD_START,
604 alpm_pkg_get_name(newpkg), percent, pkg_count,
605 pkg_current);
608 /* extract the next file from the archive */
609 errors += extract_single_file(handle, archive, entry, newpkg, oldpkg);
611 archive_read_finish(archive);
613 /* restore the old cwd if we have it */
614 if(restore_cwd && chdir(cwd) != 0) {
615 _alpm_log(handle, PM_LOG_ERROR, _("could not change directory to %s (%s)\n"), cwd, strerror(errno));
618 if(errors) {
619 ret = -1;
620 if(is_upgrade) {
621 _alpm_log(handle, PM_LOG_ERROR, _("problem occurred while upgrading %s\n"),
622 newpkg->name);
623 alpm_logaction(handle, "error: problem occurred while upgrading %s\n",
624 newpkg->name);
625 } else {
626 _alpm_log(handle, PM_LOG_ERROR, _("problem occurred while installing %s\n"),
627 newpkg->name);
628 alpm_logaction(handle, "error: problem occurred while installing %s\n",
629 newpkg->name);
634 /* make an install date (in UTC) */
635 newpkg->installdate = time(NULL);
637 _alpm_log(handle, PM_LOG_DEBUG, "updating database\n");
638 _alpm_log(handle, PM_LOG_DEBUG, "adding database entry '%s'\n", newpkg->name);
640 if(_alpm_local_db_write(db, newpkg, INFRQ_ALL)) {
641 _alpm_log(handle, PM_LOG_ERROR, _("could not update database entry %s-%s\n"),
642 alpm_pkg_get_name(newpkg), alpm_pkg_get_version(newpkg));
643 alpm_logaction(handle, "error: could not update database entry %s-%s\n",
644 alpm_pkg_get_name(newpkg), alpm_pkg_get_version(newpkg));
645 handle->pm_errno = PM_ERR_DB_WRITE;
646 ret = -1;
647 goto cleanup;
650 if(_alpm_db_add_pkgincache(db, newpkg) == -1) {
651 _alpm_log(handle, PM_LOG_ERROR, _("could not add entry '%s' in cache\n"),
652 alpm_pkg_get_name(newpkg));
655 if(is_upgrade) {
656 PROGRESS(trans, PM_TRANS_PROGRESS_UPGRADE_START,
657 alpm_pkg_get_name(newpkg), 100, pkg_count, pkg_current);
658 } else {
659 PROGRESS(trans, PM_TRANS_PROGRESS_ADD_START,
660 alpm_pkg_get_name(newpkg), 100, pkg_count, pkg_current);
663 /* run the post-install script if it exists */
664 if(alpm_pkg_has_scriptlet(newpkg)
665 && !(trans->flags & PM_TRANS_FLAG_NOSCRIPTLET)) {
666 if(is_upgrade) {
667 _alpm_runscriptlet(handle, scriptlet, "post_upgrade",
668 alpm_pkg_get_version(newpkg),
669 oldpkg ? alpm_pkg_get_version(oldpkg) : NULL);
670 } else {
671 _alpm_runscriptlet(handle, scriptlet, "post_install",
672 alpm_pkg_get_version(newpkg), NULL);
676 if(is_upgrade) {
677 EVENT(trans, PM_TRANS_EVT_UPGRADE_DONE, newpkg, oldpkg);
678 } else {
679 EVENT(trans, PM_TRANS_EVT_ADD_DONE, newpkg, oldpkg);
682 cleanup:
683 _alpm_pkg_free(oldpkg);
684 return ret;
687 int _alpm_upgrade_packages(alpm_handle_t *handle)
689 size_t pkg_count, pkg_current;
690 int skip_ldconfig = 0, ret = 0;
691 alpm_list_t *targ;
692 alpm_trans_t *trans = handle->trans;
694 if(trans->add == NULL) {
695 return 0;
698 pkg_count = alpm_list_count(trans->add);
699 pkg_current = 1;
701 /* loop through our package list adding/upgrading one at a time */
702 for(targ = trans->add; targ; targ = targ->next) {
703 alpm_pkg_t *newpkg = targ->data;
705 if(handle->trans->state == STATE_INTERRUPTED) {
706 return ret;
709 if(commit_single_pkg(handle, newpkg, pkg_current, pkg_count)) {
710 /* something screwed up on the commit, abort the trans */
711 trans->state = STATE_INTERRUPTED;
712 handle->pm_errno = PM_ERR_TRANS_ABORT;
713 /* running ldconfig at this point could possibly screw system */
714 skip_ldconfig = 1;
715 ret = -1;
718 pkg_current++;
721 if(!skip_ldconfig) {
722 /* run ldconfig if it exists */
723 _alpm_ldconfig(handle);
726 return ret;
729 /* vim: set ts=2 sw=2 noet: */