pacman: list all unknown targets on removal operation
[pacman-ng.git] / lib / libalpm / add.c
blob78615bb1db7dd3de7171fd81695d6658b4b0ca30
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 <string.h>
26 #include <limits.h>
27 #include <fcntl.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, ALPM_ERR_WRONG_ARGS, -1));
62 ASSERT(handle == pkg->handle, RET_ERR(handle, ALPM_ERR_WRONG_ARGS, -1));
63 trans = handle->trans;
64 ASSERT(trans != NULL, RET_ERR(handle, ALPM_ERR_TRANS_NULL, -1));
65 ASSERT(trans->state == STATE_INITIALIZED,
66 RET_ERR(handle, ALPM_ERR_TRANS_NOT_INITIALIZED, -1));
68 pkgname = pkg->name;
69 pkgver = pkg->version;
71 _alpm_log(handle, ALPM_LOG_DEBUG, "adding package '%s'\n", pkgname);
73 if(_alpm_pkg_find(trans->add, pkgname)) {
74 RET_ERR(handle, ALPM_ERR_TRANS_DUP_TARGET, -1);
77 local = _alpm_db_get_pkgfromcache(handle->db_local, pkgname);
78 if(local) {
79 const char *localpkgname = local->name;
80 const char *localpkgver = local->version;
81 int cmp = _alpm_pkg_compare_versions(pkg, local);
83 if(cmp == 0) {
84 if(trans->flags & ALPM_TRANS_FLAG_NEEDED) {
85 /* with the NEEDED flag, packages up to date are not reinstalled */
86 _alpm_log(handle, ALPM_LOG_WARNING, _("%s-%s is up to date -- skipping\n"),
87 localpkgname, localpkgver);
88 return 0;
89 } else if(!(trans->flags & ALPM_TRANS_FLAG_DOWNLOADONLY)) {
90 _alpm_log(handle, ALPM_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, ALPM_LOG_WARNING, _("downgrading package %s (%s => %s)\n"),
96 localpkgname, localpkgver, pkgver);
100 /* add the package to the transaction */
101 pkg->reason = ALPM_PKG_REASON_EXPLICIT;
102 _alpm_log(handle, ALPM_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, ALPM_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, ALPM_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 try_rename(alpm_handle_t *handle, const char *src, const char *dest)
136 if(rename(src, dest)) {
137 _alpm_log(handle, ALPM_LOG_ERROR, _("could not rename %s to %s (%s)\n"),
138 src, dest, strerror(errno));
139 alpm_logaction(handle, "error: could not rename %s to %s (%s)\n",
140 src, dest, strerror(errno));
141 return 1;
143 return 0;
146 static int extract_single_file(alpm_handle_t *handle, struct archive *archive,
147 struct archive_entry *entry, alpm_pkg_t *newpkg, alpm_pkg_t *oldpkg)
149 const char *entryname;
150 mode_t entrymode;
151 char filename[PATH_MAX]; /* the actual file we're extracting */
152 int needbackup = 0, notouch = 0;
153 const char *hash_orig = NULL;
154 char *entryname_orig = NULL;
155 int errors = 0;
157 entryname = archive_entry_pathname(entry);
158 entrymode = archive_entry_mode(entry);
160 if(strcmp(entryname, ".INSTALL") == 0) {
161 /* the install script goes inside the db */
162 snprintf(filename, PATH_MAX, "%s%s-%s/install",
163 _alpm_db_path(handle->db_local), newpkg->name, newpkg->version);
164 archive_entry_set_perm(entry, 0644);
165 } else if(strcmp(entryname, ".CHANGELOG") == 0) {
166 /* the changelog goes inside the db */
167 snprintf(filename, PATH_MAX, "%s%s-%s/changelog",
168 _alpm_db_path(handle->db_local), newpkg->name, newpkg->version);
169 archive_entry_set_perm(entry, 0644);
170 } else if(*entryname == '.') {
171 /* for now, ignore all files starting with '.' that haven't
172 * already been handled (for future possibilities) */
173 _alpm_log(handle, ALPM_LOG_DEBUG, "skipping extraction of '%s'\n", entryname);
174 archive_read_data_skip(archive);
175 return 0;
176 } else {
177 /* build the new entryname relative to handle->root */
178 snprintf(filename, PATH_MAX, "%s%s", handle->root, entryname);
181 /* if a file is in NoExtract then we never extract it */
182 if(alpm_list_find(handle->noextract, entryname, _alpm_fnmatch)) {
183 _alpm_log(handle, ALPM_LOG_DEBUG, "%s is in NoExtract, skipping extraction\n",
184 entryname);
185 alpm_logaction(handle, "note: %s is in NoExtract, skipping extraction\n",
186 entryname);
187 archive_read_data_skip(archive);
188 return 0;
191 /* Check for file existence. This is one of the more crucial parts
192 * to get 'right'. Here are the possibilities, with the filesystem
193 * on the left and the package on the top:
194 * (F=file, N=node, S=symlink, D=dir)
195 * | F/N | S | D
196 * non-existent | 1 | 2 | 3
197 * F/N | 4 | 5 | 6
198 * S | 7 | 8 | 9
199 * D | 10 | 11 | 12
201 * 1,2,3- extract, no magic necessary. lstat (_alpm_lstat) will fail here.
202 * 4,5,6,7,8- conflict checks should have caught this. either overwrite
203 * or backup the file.
204 * 9- follow the symlink, hopefully it is a directory, check it.
205 * 10- file replacing directory- don't allow it.
206 * 11- don't extract symlink- a dir exists here. we don't want links to
207 * links, etc.
208 * 12- skip extraction, dir already exists.
211 /* do both a lstat and a stat, so we can see what symlinks point to */
212 struct stat lsbuf, sbuf;
213 if(_alpm_lstat(filename, &lsbuf) != 0 || stat(filename, &sbuf) != 0) {
214 /* cases 1,2,3: couldn't stat an existing file, skip all backup checks */
215 } else {
216 if(S_ISDIR(lsbuf.st_mode)) {
217 if(S_ISDIR(entrymode)) {
218 /* case 12: existing dir, ignore it */
219 if(lsbuf.st_mode != entrymode) {
220 /* if filesystem perms are different than pkg perms, warn user */
221 mode_t mask = 07777;
222 _alpm_log(handle, ALPM_LOG_WARNING, _("directory permissions differ on %s\n"
223 "filesystem: %o package: %o\n"), entryname, lsbuf.st_mode & mask,
224 entrymode & mask);
225 alpm_logaction(handle, "warning: directory permissions differ on %s\n"
226 "filesystem: %o package: %o\n", entryname, lsbuf.st_mode & mask,
227 entrymode & mask);
229 _alpm_log(handle, ALPM_LOG_DEBUG, "extract: skipping dir extraction of %s\n",
230 entryname);
231 archive_read_data_skip(archive);
232 return 0;
233 } else {
234 /* case 10/11: trying to overwrite dir with file/symlink, don't allow it */
235 _alpm_log(handle, ALPM_LOG_ERROR, _("extract: not overwriting dir with file %s\n"),
236 entryname);
237 archive_read_data_skip(archive);
238 return 1;
240 } else if(S_ISLNK(lsbuf.st_mode) && S_ISDIR(entrymode)) {
241 /* case 9: existing symlink, dir in package */
242 if(S_ISDIR(sbuf.st_mode)) {
243 /* the symlink on FS is to a directory, so we'll use it */
244 _alpm_log(handle, ALPM_LOG_DEBUG, "extract: skipping symlink overwrite of %s\n",
245 entryname);
246 archive_read_data_skip(archive);
247 return 0;
248 } else {
249 /* this is BAD. symlink was not to a directory */
250 _alpm_log(handle, ALPM_LOG_ERROR, _("extract: symlink %s does not point to dir\n"),
251 entryname);
252 archive_read_data_skip(archive);
253 return 1;
255 } else if(S_ISREG(lsbuf.st_mode) && S_ISDIR(entrymode)) {
256 /* case 6: trying to overwrite file with dir */
257 _alpm_log(handle, ALPM_LOG_DEBUG, "extract: overwriting file with dir %s\n",
258 entryname);
259 } else if(S_ISREG(entrymode)) {
260 /* case 4,7: */
261 /* if file is in NoUpgrade, don't touch it */
262 if(alpm_list_find(handle->noupgrade, entryname, _alpm_fnmatch)) {
263 notouch = 1;
264 } else {
265 alpm_backup_t *backup;
266 /* go to the backup array and see if our conflict is there */
267 /* check newpkg first, so that adding backup files is retroactive */
268 backup = _alpm_needbackup(entryname, newpkg);
269 if(backup) {
270 /* if we force hash_orig to be non-NULL retroactive backup works */
271 hash_orig = "";
272 needbackup = 1;
275 /* check oldpkg for a backup entry, store the hash if available */
276 if(oldpkg) {
277 backup = _alpm_needbackup(entryname, oldpkg);
278 if(backup) {
279 hash_orig = backup->hash;
280 needbackup = 1;
285 /* else if(S_ISLNK(entrymode)) */
286 /* case 5,8: don't need to do anything special */
289 /* we need access to the original entryname later after calls to
290 * archive_entry_set_pathname(), so we need to dupe it and free() later */
291 STRDUP(entryname_orig, entryname, RET_ERR(handle, ALPM_ERR_MEMORY, -1));
293 if(needbackup) {
294 char *checkfile;
295 char *hash_local = NULL, *hash_pkg = NULL;
296 size_t len;
298 len = strlen(filename) + 10;
299 MALLOC(checkfile, len,
300 errors++; handle->pm_errno = ALPM_ERR_MEMORY; goto needbackup_cleanup);
301 snprintf(checkfile, len, "%s.paccheck", filename);
303 if(perform_extraction(handle, archive, entry, checkfile, entryname_orig)) {
304 errors++;
305 goto needbackup_cleanup;
308 hash_local = alpm_compute_md5sum(filename);
309 hash_pkg = alpm_compute_md5sum(checkfile);
311 /* update the md5 hash in newpkg's backup (it will be the new orginal) */
312 alpm_list_t *i;
313 for(i = alpm_pkg_get_backup(newpkg); i; i = i->next) {
314 alpm_backup_t *backup = i->data;
315 char *newhash;
316 if(!backup->name || strcmp(backup->name, entryname_orig) != 0) {
317 continue;
319 STRDUP(newhash, hash_pkg, RET_ERR(handle, ALPM_ERR_MEMORY, -1));
320 FREE(backup->hash);
321 backup->hash = newhash;
324 _alpm_log(handle, ALPM_LOG_DEBUG, "checking hashes for %s\n", entryname_orig);
325 _alpm_log(handle, ALPM_LOG_DEBUG, "current: %s\n", hash_local);
326 _alpm_log(handle, ALPM_LOG_DEBUG, "new: %s\n", hash_pkg);
327 _alpm_log(handle, ALPM_LOG_DEBUG, "original: %s\n", hash_orig);
329 if(!oldpkg) {
330 if(hash_local && hash_pkg && strcmp(hash_local, hash_pkg) != 0) {
331 /* looks like we have a local file that has a different hash as the
332 * file in the package, move it to a .pacorig */
333 char *newpath;
334 size_t newlen = strlen(filename) + 9;
335 MALLOC(newpath, newlen,
336 errors++; handle->pm_errno = ALPM_ERR_MEMORY; goto needbackup_cleanup);
337 snprintf(newpath, newlen, "%s.pacorig", filename);
339 /* move the existing file to the "pacorig" */
340 if(try_rename(handle, filename, newpath)) {
341 errors++;
342 errors++;
343 } else {
344 /* rename the file we extracted to the real name */
345 if(try_rename(handle, checkfile, filename)) {
346 errors++;
347 } else {
348 _alpm_log(handle, ALPM_LOG_WARNING, _("%s saved as %s\n"), filename, newpath);
349 alpm_logaction(handle, "warning: %s saved as %s\n", filename, newpath);
352 free(newpath);
353 } else {
354 /* local file is identical to pkg one, so just remove pkg one */
355 unlink(checkfile);
357 } else if(hash_orig) {
358 /* the fun part */
360 if(hash_local && strcmp(hash_orig, hash_local) == 0) {
361 /* installed file has NOT been changed by user */
362 if(hash_pkg && strcmp(hash_orig, hash_pkg) != 0) {
363 _alpm_log(handle, ALPM_LOG_DEBUG, "action: installing new file: %s\n",
364 entryname_orig);
366 if(try_rename(handle, checkfile, filename)) {
367 errors++;
369 } else {
370 /* no sense in installing the same file twice, install
371 * ONLY if the original and package hashes differ */
372 _alpm_log(handle, ALPM_LOG_DEBUG, "action: leaving existing file in place\n");
373 unlink(checkfile);
375 } else if(hash_pkg && strcmp(hash_orig, hash_pkg) == 0) {
376 /* originally installed file and new file are the same - this
377 * implies the case above failed - i.e. the file was changed by a
378 * user */
379 _alpm_log(handle, ALPM_LOG_DEBUG, "action: leaving existing file in place\n");
380 unlink(checkfile);
381 } else if(hash_local && hash_pkg && strcmp(hash_local, hash_pkg) == 0) {
382 /* this would be magical. The above two cases failed, but the
383 * user changes just so happened to make the new file exactly the
384 * same as the one in the package... skip it */
385 _alpm_log(handle, ALPM_LOG_DEBUG, "action: leaving existing file in place\n");
386 unlink(checkfile);
387 } else {
388 char *newpath;
389 size_t newlen = strlen(filename) + 8;
390 _alpm_log(handle, ALPM_LOG_DEBUG, "action: keeping current file and installing"
391 " new one with .pacnew ending\n");
392 MALLOC(newpath, newlen,
393 errors++; handle->pm_errno = ALPM_ERR_MEMORY; goto needbackup_cleanup);
394 snprintf(newpath, newlen, "%s.pacnew", filename);
395 if(try_rename(handle, checkfile, newpath)) {
396 errors++;
397 } else {
398 _alpm_log(handle, ALPM_LOG_WARNING, _("%s installed as %s\n"),
399 filename, newpath);
400 alpm_logaction(handle, "warning: %s installed as %s\n",
401 filename, newpath);
403 free(newpath);
407 needbackup_cleanup:
408 free(checkfile);
409 free(hash_local);
410 free(hash_pkg);
411 } else {
412 /* we didn't need a backup */
413 if(notouch) {
414 /* change the path to a .pacnew extension */
415 _alpm_log(handle, ALPM_LOG_DEBUG, "%s is in NoUpgrade -- skipping\n", filename);
416 _alpm_log(handle, ALPM_LOG_WARNING, _("extracting %s as %s.pacnew\n"), filename, filename);
417 alpm_logaction(handle, "warning: extracting %s as %s.pacnew\n", filename, filename);
418 strncat(filename, ".pacnew", PATH_MAX - strlen(filename));
419 } else {
420 _alpm_log(handle, ALPM_LOG_DEBUG, "extracting %s\n", filename);
423 if(handle->trans->flags & ALPM_TRANS_FLAG_FORCE) {
424 /* if FORCE was used, unlink() each file (whether it's there
425 * or not) before extracting. This prevents the old "Text file busy"
426 * error that crops up if forcing a glibc or pacman upgrade. */
427 unlink(filename);
430 if(perform_extraction(handle, archive, entry, filename, entryname_orig)) {
431 /* error */
432 free(entryname_orig);
433 errors++;
434 return errors;
437 /* calculate an hash if this is in newpkg's backup */
438 alpm_list_t *i;
439 for(i = alpm_pkg_get_backup(newpkg); i; i = i->next) {
440 alpm_backup_t *backup = i->data;
441 char *newhash;
442 if(!backup->name || strcmp(backup->name, entryname_orig) != 0) {
443 continue;
445 _alpm_log(handle, ALPM_LOG_DEBUG, "appending backup entry for %s\n", entryname_orig);
446 newhash = alpm_compute_md5sum(filename);
447 FREE(backup->hash);
448 backup->hash = newhash;
451 free(entryname_orig);
452 return errors;
455 static int commit_single_pkg(alpm_handle_t *handle, alpm_pkg_t *newpkg,
456 size_t pkg_current, size_t pkg_count)
458 int i, ret = 0, errors = 0;
459 int is_upgrade;
460 alpm_pkg_t *oldpkg = NULL;
461 alpm_db_t *db = handle->db_local;
462 alpm_trans_t *trans = handle->trans;
463 const char *pkgfile;
465 ASSERT(trans != NULL, return -1);
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 if(_alpm_pkg_dup(local, &oldpkg) == -1) {
474 ret = -1;
475 goto cleanup;
478 /* copy over the install reason */
479 newpkg->reason = alpm_pkg_get_reason(local);
481 EVENT(handle, ALPM_EVENT_UPGRADE_START, newpkg, local);
482 } else {
483 is_upgrade = 0;
484 EVENT(handle, ALPM_EVENT_ADD_START, newpkg, NULL);
487 pkgfile = newpkg->origin_data.file;
489 _alpm_log(handle, ALPM_LOG_DEBUG, "%s package %s-%s\n",
490 is_upgrade ? "upgrading" : "adding", newpkg->name, newpkg->version);
491 /* pre_install/pre_upgrade scriptlet */
492 if(alpm_pkg_has_scriptlet(newpkg) &&
493 !(trans->flags & ALPM_TRANS_FLAG_NOSCRIPTLET)) {
494 const char *scriptlet_name = is_upgrade ? "pre_upgrade" : "pre_install";
495 _alpm_runscriptlet(handle, pkgfile,
496 scriptlet_name, newpkg->version, NULL, 1);
499 /* we override any pre-set reason if we have alldeps or allexplicit set */
500 if(trans->flags & ALPM_TRANS_FLAG_ALLDEPS) {
501 newpkg->reason = ALPM_PKG_REASON_DEPEND;
502 } else if(trans->flags & ALPM_TRANS_FLAG_ALLEXPLICIT) {
503 newpkg->reason = ALPM_PKG_REASON_EXPLICIT;
506 if(oldpkg) {
507 /* set up fake remove transaction */
508 if(_alpm_remove_single_package(handle, oldpkg, newpkg, 0, 0) == -1) {
509 handle->pm_errno = ALPM_ERR_TRANS_ABORT;
510 ret = -1;
511 goto cleanup;
515 /* prepare directory for database entries so permission are correct after
516 changelog/install script installation (FS#12263) */
517 if(_alpm_local_db_prepare(db, newpkg)) {
518 alpm_logaction(handle, "error: could not create database entry %s-%s\n",
519 newpkg->name, newpkg->version);
520 handle->pm_errno = ALPM_ERR_DB_WRITE;
521 ret = -1;
522 goto cleanup;
525 if(!(trans->flags & ALPM_TRANS_FLAG_DBONLY)) {
526 struct archive *archive;
527 struct archive_entry *entry;
528 struct stat buf;
529 int fd, cwdfd;
531 _alpm_log(handle, ALPM_LOG_DEBUG, "extracting files\n");
533 fd = _alpm_open_archive(db->handle, pkgfile, &buf,
534 &archive, ALPM_ERR_PKG_OPEN);
535 if(fd < 0) {
536 ret = -1;
537 goto cleanup;
540 /* save the cwd so we can restore it later */
541 OPEN(cwdfd, ".", O_RDONLY);
542 if(cwdfd < 0) {
543 _alpm_log(handle, ALPM_LOG_ERROR, _("could not get current working directory\n"));
546 /* libarchive requires this for extracting hard links */
547 if(chdir(handle->root) != 0) {
548 _alpm_log(handle, ALPM_LOG_ERROR, _("could not change directory to %s (%s)\n"),
549 handle->root, strerror(errno));
550 archive_read_finish(archive);
551 CLOSE(fd);
552 ret = -1;
553 goto cleanup;
556 /* call PROGRESS once with 0 percent, as we sort-of skip that here */
557 if(is_upgrade) {
558 PROGRESS(handle, ALPM_PROGRESS_UPGRADE_START,
559 newpkg->name, 0, pkg_count, pkg_current);
560 } else {
561 PROGRESS(handle, ALPM_PROGRESS_ADD_START,
562 newpkg->name, 0, pkg_count, pkg_current);
565 for(i = 0; archive_read_next_header(archive, &entry) == ARCHIVE_OK; i++) {
566 int percent;
568 if(newpkg->size != 0) {
569 /* Using compressed size for calculations here, as newpkg->isize is not
570 * exact when it comes to comparing to the ACTUAL uncompressed size
571 * (missing metadata sizes) */
572 int64_t pos = archive_position_compressed(archive);
573 percent = (pos * 100) / newpkg->size;
574 if(percent >= 100) {
575 percent = 100;
577 } else {
578 percent = 0;
581 if(is_upgrade) {
582 PROGRESS(handle, ALPM_PROGRESS_UPGRADE_START,
583 newpkg->name, percent, pkg_count, pkg_current);
584 } else {
585 PROGRESS(handle, ALPM_PROGRESS_ADD_START,
586 newpkg->name, percent, pkg_count, pkg_current);
589 /* extract the next file from the archive */
590 errors += extract_single_file(handle, archive, entry, newpkg, oldpkg);
592 archive_read_finish(archive);
593 CLOSE(fd);
595 /* restore the old cwd if we have it */
596 if(cwdfd >= 0) {
597 if(fchdir(cwdfd) != 0) {
598 _alpm_log(handle, ALPM_LOG_ERROR,
599 _("could not restore working directory (%s)\n"), strerror(errno));
601 CLOSE(cwdfd);
604 if(errors) {
605 ret = -1;
606 if(is_upgrade) {
607 _alpm_log(handle, ALPM_LOG_ERROR, _("problem occurred while upgrading %s\n"),
608 newpkg->name);
609 alpm_logaction(handle, "error: problem occurred while upgrading %s\n",
610 newpkg->name);
611 } else {
612 _alpm_log(handle, ALPM_LOG_ERROR, _("problem occurred while installing %s\n"),
613 newpkg->name);
614 alpm_logaction(handle, "error: problem occurred while installing %s\n",
615 newpkg->name);
620 /* make an install date (in UTC) */
621 newpkg->installdate = time(NULL);
623 _alpm_log(handle, ALPM_LOG_DEBUG, "updating database\n");
624 _alpm_log(handle, ALPM_LOG_DEBUG, "adding database entry '%s'\n", newpkg->name);
626 if(_alpm_local_db_write(db, newpkg, INFRQ_ALL)) {
627 _alpm_log(handle, ALPM_LOG_ERROR, _("could not update database entry %s-%s\n"),
628 newpkg->name, newpkg->version);
629 alpm_logaction(handle, "error: could not update database entry %s-%s\n",
630 newpkg->name, newpkg->version);
631 handle->pm_errno = ALPM_ERR_DB_WRITE;
632 ret = -1;
633 goto cleanup;
636 if(_alpm_db_add_pkgincache(db, newpkg) == -1) {
637 _alpm_log(handle, ALPM_LOG_ERROR, _("could not add entry '%s' in cache\n"),
638 newpkg->name);
641 if(is_upgrade) {
642 PROGRESS(handle, ALPM_PROGRESS_UPGRADE_START,
643 newpkg->name, 100, pkg_count, pkg_current);
644 } else {
645 PROGRESS(handle, ALPM_PROGRESS_ADD_START,
646 newpkg->name, 100, pkg_count, pkg_current);
649 /* run the post-install script if it exists */
650 if(alpm_pkg_has_scriptlet(newpkg)
651 && !(trans->flags & ALPM_TRANS_FLAG_NOSCRIPTLET)) {
652 char *scriptlet = _alpm_local_db_pkgpath(db, newpkg, "install");
653 const char *scriptlet_name = is_upgrade ? "post_upgrade" : "post_install";
655 _alpm_runscriptlet(handle, scriptlet, scriptlet_name,
656 newpkg->version, oldpkg ? oldpkg->version : NULL, 0);
657 free(scriptlet);
660 if(is_upgrade) {
661 EVENT(handle, ALPM_EVENT_UPGRADE_DONE, newpkg, oldpkg);
662 } else {
663 EVENT(handle, ALPM_EVENT_ADD_DONE, newpkg, oldpkg);
666 cleanup:
667 _alpm_pkg_free(oldpkg);
668 return ret;
671 int _alpm_upgrade_packages(alpm_handle_t *handle)
673 size_t pkg_count, pkg_current;
674 int skip_ldconfig = 0, ret = 0;
675 alpm_list_t *targ;
676 alpm_trans_t *trans = handle->trans;
678 if(trans->add == NULL) {
679 return 0;
682 pkg_count = alpm_list_count(trans->add);
683 pkg_current = 1;
685 /* loop through our package list adding/upgrading one at a time */
686 for(targ = trans->add; targ; targ = targ->next) {
687 alpm_pkg_t *newpkg = targ->data;
689 if(handle->trans->state == STATE_INTERRUPTED) {
690 return ret;
693 if(commit_single_pkg(handle, newpkg, pkg_current, pkg_count)) {
694 /* something screwed up on the commit, abort the trans */
695 trans->state = STATE_INTERRUPTED;
696 handle->pm_errno = ALPM_ERR_TRANS_ABORT;
697 /* running ldconfig at this point could possibly screw system */
698 skip_ldconfig = 1;
699 ret = -1;
702 pkg_current++;
705 if(!skip_ldconfig) {
706 /* run ldconfig if it exists */
707 _alpm_ldconfig(handle);
710 return ret;
713 /* vim: set ts=2 sw=2 noet: */