1 /*
2 * add.c
3 *
4 * Copyright (c) 2006-2018 Pacman Development Team <pacman-dev@archlinux.org>
5 * Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org>
6 *
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.
11 *
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.
16 *
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/>.
19 */
20
21 #include <stdlib.h>
22 #include <errno.h>
23 #include <string.h>
24 #include <limits.h>
25 #include <fcntl.h>
26 #include <sys/types.h>
27 #include <sys/stat.h>
28 #include <unistd.h>
29 #include <stdint.h> /* int64_t */
30
31 /* libarchive */
32 #include <archive.h>
33 #include <archive_entry.h>
34
35 /* libalpm */
36 #include "add.h"
37 #include "alpm.h"
38 #include "alpm_list.h"
39 #include "handle.h"
40 #include "libarchive-compat.h"
41 #include "trans.h"
42 #include "util.h"
43 #include "log.h"
44 #include "backup.h"
45 #include "package.h"
46 #include "db.h"
47 #include "remove.h"
48 #include "handle.h"
49
50 /** Add a package to the transaction. */
alpm_add_pkg(alpm_handle_t * handle,alpm_pkg_t * pkg)51 int SYMEXPORT alpm_add_pkg(alpm_handle_t *handle, alpm_pkg_t *pkg)
52 {
53 const char *pkgname, *pkgver;
54 alpm_trans_t *trans;
55 alpm_pkg_t *local;
56
57 /* Sanity checks */
58 CHECK_HANDLE(handle, return -1);
59 ASSERT(pkg != NULL, RET_ERR(handle, ALPM_ERR_WRONG_ARGS, -1));
60 ASSERT(pkg->origin != ALPM_PKG_FROM_LOCALDB,
61 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));
67
68 pkgname = pkg->name;
69 pkgver = pkg->version;
70
71 _alpm_log(handle, ALPM_LOG_DEBUG, "adding package '%s'\n", pkgname);
72
73 if(alpm_pkg_find(trans->add, pkgname)) {
74 RET_ERR(handle, ALPM_ERR_TRANS_DUP_TARGET, -1);
75 }
76
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);
82
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);
92 }
93 } else if(cmp < 0 && !(trans->flags & ALPM_TRANS_FLAG_DOWNLOADONLY)) {
94 /* local version is newer */
95 _alpm_log(handle, ALPM_LOG_WARNING, _("downgrading package %s (%s => %s)\n"),
96 localpkgname, localpkgver, pkgver);
97 }
98 }
99
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);
105
106 return 0;
107 }
108
perform_extraction(alpm_handle_t * handle,struct archive * archive,struct archive_entry * entry,const char * filename)109 static int perform_extraction(alpm_handle_t *handle, struct archive *archive,
110 struct archive_entry *entry, const char *filename)
111 {
112 int ret;
113 struct archive *archive_writer;
114 const int archive_flags = ARCHIVE_EXTRACT_OWNER |
115 ARCHIVE_EXTRACT_PERM |
116 ARCHIVE_EXTRACT_TIME |
117 ARCHIVE_EXTRACT_UNLINK |
118 ARCHIVE_EXTRACT_SECURE_SYMLINKS;
119
120 archive_entry_set_pathname(entry, filename);
121
122 archive_writer = archive_write_disk_new();
123 if (archive_writer == NULL) {
124 _alpm_log(handle, ALPM_LOG_ERROR, _("cannot allocate disk archive object"));
125 alpm_logaction(handle, ALPM_CALLER_PREFIX,
126 "error: cannot allocate disk archive object");
127 return 1;
128 }
129
130 archive_write_disk_set_options(archive_writer, archive_flags);
131
132 ret = archive_read_extract2(archive, entry, archive_writer);
133
134 archive_write_free(archive_writer);
135
136 if(ret == ARCHIVE_WARN && archive_errno(archive) != ENOSPC) {
137 /* operation succeeded but a "non-critical" error was encountered */
138 _alpm_log(handle, ALPM_LOG_WARNING, _("warning given when extracting %s (%s)\n"),
139 filename, archive_error_string(archive));
140 } else if(ret != ARCHIVE_OK) {
141 _alpm_log(handle, ALPM_LOG_ERROR, _("could not extract %s (%s)\n"),
142 filename, archive_error_string(archive));
143 alpm_logaction(handle, ALPM_CALLER_PREFIX,
144 "error: could not extract %s (%s)\n",
145 filename, archive_error_string(archive));
146 return 1;
147 }
148 return 0;
149 }
150
try_rename(alpm_handle_t * handle,const char * src,const char * dest)151 static int try_rename(alpm_handle_t *handle, const char *src, const char *dest)
152 {
153 if(rename(src, dest)) {
154 _alpm_log(handle, ALPM_LOG_ERROR, _("could not rename %s to %s (%s)\n"),
155 src, dest, strerror(errno));
156 alpm_logaction(handle, ALPM_CALLER_PREFIX,
157 "error: could not rename %s to %s (%s)\n", src, dest, strerror(errno));
158 return 1;
159 }
160 return 0;
161 }
162
extract_db_file(alpm_handle_t * handle,struct archive * archive,struct archive_entry * entry,alpm_pkg_t * newpkg,const char * entryname)163 static int extract_db_file(alpm_handle_t *handle, struct archive *archive,
164 struct archive_entry *entry, alpm_pkg_t *newpkg, const char *entryname)
165 {
166 char filename[PATH_MAX]; /* the actual file we're extracting */
167 const char *dbfile = NULL;
168 if(strcmp(entryname, ".INSTALL") == 0) {
169 dbfile = "install";
170 } else if(strcmp(entryname, ".CHANGELOG") == 0) {
171 dbfile = "changelog";
172 } else if(strcmp(entryname, ".MTREE") == 0) {
173 dbfile = "mtree";
174 } else if(*entryname == '.') {
175 /* reserve all files starting with '.' for future possibilities */
176 _alpm_log(handle, ALPM_LOG_DEBUG, "skipping extraction of '%s'\n", entryname);
177 archive_read_data_skip(archive);
178 return 0;
179 }
180 archive_entry_set_perm(entry, 0644);
181 snprintf(filename, PATH_MAX, "%s%s-%s/%s",
182 _alpm_db_path(handle->db_local), newpkg->name, newpkg->version, dbfile);
183 return perform_extraction(handle, archive, entry, filename);
184 }
185
extract_single_file(alpm_handle_t * handle,struct archive * archive,struct archive_entry * entry,alpm_pkg_t * newpkg,alpm_pkg_t * oldpkg)186 static int extract_single_file(alpm_handle_t *handle, struct archive *archive,
187 struct archive_entry *entry, alpm_pkg_t *newpkg, alpm_pkg_t *oldpkg)
188 {
189 const char *entryname = archive_entry_pathname(entry);
190 mode_t entrymode = archive_entry_mode(entry);
191 alpm_backup_t *backup = _alpm_needbackup(entryname, newpkg);
192 char filename[PATH_MAX]; /* the actual file we're extracting */
193 int needbackup = 0, notouch = 0;
194 const char *hash_orig = NULL;
195 int isnewfile = 0, errors = 0;
196 struct stat lsbuf;
197 size_t filename_len;
198
199 if(*entryname == '.') {
200 return extract_db_file(handle, archive, entry, newpkg, entryname);
201 }
202
203 if (!alpm_filelist_contains(&newpkg->files, entryname)) {
204 _alpm_log(handle, ALPM_LOG_WARNING,
205 _("file not found in file list for package %s. skipping extraction of %s\n"),
206 newpkg->name, entryname);
207 return 0;
208 }
209
210 /* build the new entryname relative to handle->root */
211 filename_len = snprintf(filename, PATH_MAX, "%s%s", handle->root, entryname);
212 if(filename_len >= PATH_MAX) {
213 _alpm_log(handle, ALPM_LOG_ERROR,
214 _("unable to extract %s%s: path too long"), handle->root, entryname);
215 return 1;
216 }
217
218 /* if a file is in NoExtract then we never extract it */
219 if(_alpm_fnmatch_patterns(handle->noextract, entryname) == 0) {
220 _alpm_log(handle, ALPM_LOG_DEBUG, "%s is in NoExtract,"
221 " skipping extraction of %s\n",
222 entryname, filename);
223 archive_read_data_skip(archive);
224 return 0;
225 }
226
227 /* Check for file existence. This is one of the more crucial parts
228 * to get 'right'. Here are the possibilities, with the filesystem
229 * on the left and the package on the top:
230 * (F=file, N=node, S=symlink, D=dir)
231 * | F/N | D
232 * non-existent | 1 | 2
233 * F/N | 3 | 4
234 * D | 5 | 6
235 *
236 * 1,2- extract, no magic necessary. lstat (llstat) will fail here.
237 * 3,4- conflict checks should have caught this. either overwrite
238 * or backup the file.
239 * 5- file replacing directory- don't allow it.
240 * 6- skip extraction, dir already exists.
241 */
242
243 isnewfile = llstat(filename, &lsbuf) != 0;
244 if(isnewfile) {
245 /* cases 1,2: file doesn't exist, skip all backup checks */
246 } else if(S_ISDIR(lsbuf.st_mode) && S_ISDIR(entrymode)) {
247 #if 0
248 uid_t entryuid = archive_entry_uid(entry);
249 gid_t entrygid = archive_entry_gid(entry);
250 #endif
251
252 /* case 6: existing dir, ignore it */
253 if(lsbuf.st_mode != entrymode) {
254 /* if filesystem perms are different than pkg perms, warn user */
255 mode_t mask = 07777;
256 _alpm_log(handle, ALPM_LOG_WARNING, _("directory permissions differ on %s\n"
257 "filesystem: %o package: %o\n"), filename, lsbuf.st_mode & mask,
258 entrymode & mask);
259 alpm_logaction(handle, ALPM_CALLER_PREFIX,
260 "warning: directory permissions differ on %s\n"
261 "filesystem: %o package: %o\n", filename, lsbuf.st_mode & mask,
262 entrymode & mask);
263 }
264
265 #if 0
266 /* Disable this warning until our user management in packages has improved.
267 Currently many packages have to create users in post_install and chown the
268 directories. These all resulted in "false-positive" warnings. */
269
270 if((entryuid != lsbuf.st_uid) || (entrygid != lsbuf.st_gid)) {
271 _alpm_log(handle, ALPM_LOG_WARNING, _("directory ownership differs on %s\n"
272 "filesystem: %u:%u package: %u:%u\n"), filename,
273 lsbuf.st_uid, lsbuf.st_gid, entryuid, entrygid);
274 alpm_logaction(handle, ALPM_CALLER_PREFIX,
275 "warning: directory ownership differs on %s\n"
276 "filesystem: %u:%u package: %u:%u\n", filename,
277 lsbuf.st_uid, lsbuf.st_gid, entryuid, entrygid);
278 }
279 #endif
280
281 _alpm_log(handle, ALPM_LOG_DEBUG, "extract: skipping dir extraction of %s\n",
282 filename);
283 archive_read_data_skip(archive);
284 return 0;
285 } else if(S_ISDIR(lsbuf.st_mode)) {
286 /* case 5: trying to overwrite dir with file, don't allow it */
287 _alpm_log(handle, ALPM_LOG_ERROR, _("extract: not overwriting dir with file %s\n"),
288 filename);
289 archive_read_data_skip(archive);
290 return 1;
291 } else if(S_ISDIR(entrymode)) {
292 /* case 4: trying to overwrite file with dir */
293 _alpm_log(handle, ALPM_LOG_DEBUG, "extract: overwriting file with dir %s\n",
294 filename);
295 } else {
296 /* case 3: trying to overwrite file with file */
297 /* if file is in NoUpgrade, don't touch it */
298 if(_alpm_fnmatch_patterns(handle->noupgrade, entryname) == 0) {
299 notouch = 1;
300 } else {
301 alpm_backup_t *oldbackup;
302 if(oldpkg && (oldbackup = _alpm_needbackup(entryname, oldpkg))) {
303 hash_orig = oldbackup->hash;
304 needbackup = 1;
305 } else if(backup) {
306 /* allow adding backup files retroactively */
307 needbackup = 1;
308 }
309 }
310 }
311
312 if(notouch || needbackup) {
313 if(filename_len + strlen(".pacnew") >= PATH_MAX) {
314 _alpm_log(handle, ALPM_LOG_ERROR,
315 _("unable to extract %s.pacnew: path too long"), filename);
316 return 1;
317 }
318 strcpy(filename + filename_len, ".pacnew");
319 isnewfile = (llstat(filename, &lsbuf) != 0 && errno == ENOENT);
320 }
321
322 _alpm_log(handle, ALPM_LOG_DEBUG, "extracting %s\n", filename);
323 if(perform_extraction(handle, archive, entry, filename)) {
324 errors++;
325 return errors;
326 }
327
328 if(backup) {
329 FREE(backup->hash);
330 backup->hash = alpm_compute_md5sum(filename);
331 }
332
333 if(notouch) {
334 alpm_event_pacnew_created_t event = {
335 .type = ALPM_EVENT_PACNEW_CREATED,
336 .from_noupgrade = 1,
337 .oldpkg = oldpkg,
338 .newpkg = newpkg,
339 .file = filename
340 };
341 /* "remove" the .pacnew suffix */
342 filename[filename_len] = '\0';
343 EVENT(handle, &event);
344 alpm_logaction(handle, ALPM_CALLER_PREFIX,
345 "warning: %s installed as %s.pacnew\n", filename, filename);
346 } else if(needbackup) {
347 char *hash_local = NULL, *hash_pkg = NULL;
348 char origfile[PATH_MAX] = "";
349
350 strncat(origfile, filename, filename_len);
351
352 hash_local = alpm_compute_md5sum(origfile);
353 hash_pkg = backup ? backup->hash : alpm_compute_md5sum(filename);
354
355 _alpm_log(handle, ALPM_LOG_DEBUG, "checking hashes for %s\n", origfile);
356 _alpm_log(handle, ALPM_LOG_DEBUG, "current: %s\n", hash_local);
357 _alpm_log(handle, ALPM_LOG_DEBUG, "new: %s\n", hash_pkg);
358 _alpm_log(handle, ALPM_LOG_DEBUG, "original: %s\n", hash_orig);
359
360 if(hash_local && hash_pkg && strcmp(hash_local, hash_pkg) == 0) {
361 /* local and new files are the same, updating anyway to get
362 * correct timestamps */
363 _alpm_log(handle, ALPM_LOG_DEBUG, "action: installing new file: %s\n",
364 origfile);
365 if(try_rename(handle, filename, origfile)) {
366 errors++;
367 }
368 } else if(hash_orig && hash_pkg && strcmp(hash_orig, hash_pkg) == 0) {
369 /* original and new files are the same, leave the local version alone,
370 * including any user changes */
371 _alpm_log(handle, ALPM_LOG_DEBUG,
372 "action: leaving existing file in place\n");
373 if(isnewfile) {
374 unlink(filename);
375 }
376 } else if(hash_orig && hash_local && strcmp(hash_orig, hash_local) == 0) {
377 /* installed file has NOT been changed by user,
378 * update to the new version */
379 _alpm_log(handle, ALPM_LOG_DEBUG, "action: installing new file: %s\n",
380 origfile);
381 if(try_rename(handle, filename, origfile)) {
382 errors++;
383 }
384 } else {
385 /* none of the three files matched another, leave the unpacked
386 * file alongside the local file */
387 alpm_event_pacnew_created_t event = {
388 .type = ALPM_EVENT_PACNEW_CREATED,
389 .from_noupgrade = 0,
390 .oldpkg = oldpkg,
391 .newpkg = newpkg,
392 .file = origfile
393 };
394 _alpm_log(handle, ALPM_LOG_DEBUG,
395 "action: keeping current file and installing"
396 " new one with .pacnew ending\n");
397 EVENT(handle, &event);
398 alpm_logaction(handle, ALPM_CALLER_PREFIX,
399 "warning: %s installed as %s\n", origfile, filename);
400 }
401
402 free(hash_local);
403 if(!backup) {
404 free(hash_pkg);
405 }
406 }
407 return errors;
408 }
409
commit_single_pkg(alpm_handle_t * handle,alpm_pkg_t * newpkg,size_t pkg_current,size_t pkg_count)410 static int commit_single_pkg(alpm_handle_t *handle, alpm_pkg_t *newpkg,
411 size_t pkg_current, size_t pkg_count)
412 {
413 int i, ret = 0, errors = 0;
414 int is_upgrade = 0;
415 alpm_pkg_t *oldpkg = NULL;
416 alpm_db_t *db = handle->db_local;
417 alpm_trans_t *trans = handle->trans;
418 alpm_progress_t progress = ALPM_PROGRESS_ADD_START;
419 alpm_event_package_operation_t event;
420 const char *log_msg = "adding";
421 const char *pkgfile;
422 struct archive *archive;
423 struct archive_entry *entry;
424 int fd, cwdfd;
425 struct stat buf;
426
427 ASSERT(trans != NULL, return -1);
428
429 /* see if this is an upgrade. if so, remove the old package first */
430 if((oldpkg = newpkg->oldpkg)) {
431 int cmp = _alpm_pkg_compare_versions(newpkg, oldpkg);
432 if(cmp < 0) {
433 log_msg = "downgrading";
434 progress = ALPM_PROGRESS_DOWNGRADE_START;
435 event.operation = ALPM_PACKAGE_DOWNGRADE;
436 } else if(cmp == 0) {
437 log_msg = "reinstalling";
438 progress = ALPM_PROGRESS_REINSTALL_START;
439 event.operation = ALPM_PACKAGE_REINSTALL;
440 } else {
441 log_msg = "upgrading";
442 progress = ALPM_PROGRESS_UPGRADE_START;
443 event.operation = ALPM_PACKAGE_UPGRADE;
444 }
445 is_upgrade = 1;
446
447 /* copy over the install reason */
448 newpkg->reason = alpm_pkg_get_reason(oldpkg);
449 } else {
450 event.operation = ALPM_PACKAGE_INSTALL;
451 }
452
453 event.type = ALPM_EVENT_PACKAGE_OPERATION_START;
454 event.oldpkg = oldpkg;
455 event.newpkg = newpkg;
456 EVENT(handle, &event);
457
458 pkgfile = newpkg->origin_data.file;
459
460 _alpm_log(handle, ALPM_LOG_DEBUG, "%s package %s-%s\n",
461 log_msg, newpkg->name, newpkg->version);
462 /* pre_install/pre_upgrade scriptlet */
463 if(alpm_pkg_has_scriptlet(newpkg) &&
464 !(trans->flags & ALPM_TRANS_FLAG_NOSCRIPTLET)) {
465 const char *scriptlet_name = is_upgrade ? "pre_upgrade" : "pre_install";
466
467 _alpm_runscriptlet(handle, pkgfile, scriptlet_name,
468 newpkg->version, oldpkg ? oldpkg->version : NULL, 1);
469 }
470
471 /* we override any pre-set reason if we have alldeps or allexplicit set */
472 if(trans->flags & ALPM_TRANS_FLAG_ALLDEPS) {
473 newpkg->reason = ALPM_PKG_REASON_DEPEND;
474 } else if(trans->flags & ALPM_TRANS_FLAG_ALLEXPLICIT) {
475 newpkg->reason = ALPM_PKG_REASON_EXPLICIT;
476 }
477
478 if(oldpkg) {
479 /* set up fake remove transaction */
480 if(_alpm_remove_single_package(handle, oldpkg, newpkg, 0, 0) == -1) {
481 handle->pm_errno = ALPM_ERR_TRANS_ABORT;
482 ret = -1;
483 goto cleanup;
484 }
485 }
486
487 /* prepare directory for database entries so permissions are correct after
488 changelog/install script installation */
489 if(_alpm_local_db_prepare(db, newpkg)) {
490 alpm_logaction(handle, ALPM_CALLER_PREFIX,
491 "error: could not create database entry %s-%s\n",
492 newpkg->name, newpkg->version);
493 handle->pm_errno = ALPM_ERR_DB_WRITE;
494 ret = -1;
495 goto cleanup;
496 }
497
498 fd = _alpm_open_archive(db->handle, pkgfile, &buf,
499 &archive, ALPM_ERR_PKG_OPEN);
500 if(fd < 0) {
501 ret = -1;
502 goto cleanup;
503 }
504
505 /* save the cwd so we can restore it later */
506 OPEN(cwdfd, ".", O_RDONLY | O_CLOEXEC);
507 if(cwdfd < 0) {
508 _alpm_log(handle, ALPM_LOG_ERROR, _("could not get current working directory\n"));
509 }
510
511 /* libarchive requires this for extracting hard links */
512 if(chdir(handle->root) != 0) {
513 _alpm_log(handle, ALPM_LOG_ERROR, _("could not change directory to %s (%s)\n"),
514 handle->root, strerror(errno));
515 _alpm_archive_read_free(archive);
516 if(cwdfd >= 0) {
517 close(cwdfd);
518 }
519 close(fd);
520 ret = -1;
521 goto cleanup;
522 }
523
524 if(trans->flags & ALPM_TRANS_FLAG_DBONLY) {
525 _alpm_log(handle, ALPM_LOG_DEBUG, "extracting db files\n");
526 while(archive_read_next_header(archive, &entry) == ARCHIVE_OK) {
527 const char *entryname = archive_entry_pathname(entry);
528 if(entryname[0] == '.') {
529 errors += extract_db_file(handle, archive, entry, newpkg, entryname);
530 } else {
531 archive_read_data_skip(archive);
532 }
533 }
534 } else {
535 _alpm_log(handle, ALPM_LOG_DEBUG, "extracting files\n");
536
537 /* call PROGRESS once with 0 percent, as we sort-of skip that here */
538 PROGRESS(handle, progress, newpkg->name, 0, pkg_count, pkg_current);
539
540 for(i = 0; archive_read_next_header(archive, &entry) == ARCHIVE_OK; i++) {
541 int percent;
542
543 if(newpkg->size != 0) {
544 /* Using compressed size for calculations here, as newpkg->isize is not
545 * exact when it comes to comparing to the ACTUAL uncompressed size
546 * (missing metadata sizes) */
547 int64_t pos = _alpm_archive_compressed_ftell(archive);
548 percent = (pos * 100) / newpkg->size;
549 if(percent >= 100) {
550 percent = 100;
551 }
552 } else {
553 percent = 0;
554 }
555
556 PROGRESS(handle, progress, newpkg->name, percent, pkg_count, pkg_current);
557
558 /* extract the next file from the archive */
559 errors += extract_single_file(handle, archive, entry, newpkg, oldpkg);
560 }
561 }
562
563 _alpm_archive_read_free(archive);
564 close(fd);
565
566 /* restore the old cwd if we have it */
567 if(cwdfd >= 0) {
568 if(fchdir(cwdfd) != 0) {
569 _alpm_log(handle, ALPM_LOG_ERROR,
570 _("could not restore working directory (%s)\n"), strerror(errno));
571 }
572 close(cwdfd);
573 }
574
575 if(errors) {
576 ret = -1;
577 if(is_upgrade) {
578 _alpm_log(handle, ALPM_LOG_ERROR, _("problem occurred while upgrading %s\n"),
579 newpkg->name);
580 alpm_logaction(handle, ALPM_CALLER_PREFIX,
581 "error: problem occurred while upgrading %s\n",
582 newpkg->name);
583 } else {
584 _alpm_log(handle, ALPM_LOG_ERROR, _("problem occurred while installing %s\n"),
585 newpkg->name);
586 alpm_logaction(handle, ALPM_CALLER_PREFIX,
587 "error: problem occurred while installing %s\n",
588 newpkg->name);
589 }
590 }
591
592 /* make an install date (in UTC) */
593 newpkg->installdate = time(NULL);
594
595 _alpm_log(handle, ALPM_LOG_DEBUG, "updating database\n");
596 _alpm_log(handle, ALPM_LOG_DEBUG, "adding database entry '%s'\n", newpkg->name);
597
598 if(_alpm_local_db_write(db, newpkg, INFRQ_ALL)) {
599 _alpm_log(handle, ALPM_LOG_ERROR, _("could not update database entry %s-%s\n"),
600 newpkg->name, newpkg->version);
601 alpm_logaction(handle, ALPM_CALLER_PREFIX,
602 "error: could not update database entry %s-%s\n",
603 newpkg->name, newpkg->version);
604 handle->pm_errno = ALPM_ERR_DB_WRITE;
605 ret = -1;
606 goto cleanup;
607 }
608
609 if(_alpm_db_add_pkgincache(db, newpkg) == -1) {
610 _alpm_log(handle, ALPM_LOG_ERROR, _("could not add entry '%s' in cache\n"),
611 newpkg->name);
612 }
613
614 PROGRESS(handle, progress, newpkg->name, 100, pkg_count, pkg_current);
615
616 switch(event.operation) {
617 case ALPM_PACKAGE_INSTALL:
618 alpm_logaction(handle, ALPM_CALLER_PREFIX, "installed %s (%s)\n",
619 newpkg->name, newpkg->version);
620 break;
621 case ALPM_PACKAGE_DOWNGRADE:
622 alpm_logaction(handle, ALPM_CALLER_PREFIX, "downgraded %s (%s -> %s)\n",
623 newpkg->name, oldpkg->version, newpkg->version);
624 break;
625 case ALPM_PACKAGE_REINSTALL:
626 alpm_logaction(handle, ALPM_CALLER_PREFIX, "reinstalled %s (%s)\n",
627 newpkg->name, newpkg->version);
628 break;
629 case ALPM_PACKAGE_UPGRADE:
630 alpm_logaction(handle, ALPM_CALLER_PREFIX, "upgraded %s (%s -> %s)\n",
631 newpkg->name, oldpkg->version, newpkg->version);
632 break;
633 default:
634 /* we should never reach here */
635 break;
636 }
637
638 /* run the post-install script if it exists */
639 if(alpm_pkg_has_scriptlet(newpkg)
640 && !(trans->flags & ALPM_TRANS_FLAG_NOSCRIPTLET)) {
641 char *scriptlet = _alpm_local_db_pkgpath(db, newpkg, "install");
642 const char *scriptlet_name = is_upgrade ? "post_upgrade" : "post_install";
643
644 _alpm_runscriptlet(handle, scriptlet, scriptlet_name,
645 newpkg->version, oldpkg ? oldpkg->version : NULL, 0);
646 free(scriptlet);
647 }
648
649 event.type = ALPM_EVENT_PACKAGE_OPERATION_DONE;
650 EVENT(handle, &event);
651
652 cleanup:
653 return ret;
654 }
655
_alpm_upgrade_packages(alpm_handle_t * handle)656 int _alpm_upgrade_packages(alpm_handle_t *handle)
657 {
658 size_t pkg_count, pkg_current;
659 int skip_ldconfig = 0, ret = 0;
660 alpm_list_t *targ;
661 alpm_trans_t *trans = handle->trans;
662
663 if(trans->add == NULL) {
664 return 0;
665 }
666
667 pkg_count = alpm_list_count(trans->add);
668 pkg_current = 1;
669
670 /* loop through our package list adding/upgrading one at a time */
671 for(targ = trans->add; targ; targ = targ->next) {
672 alpm_pkg_t *newpkg = targ->data;
673
674 if(handle->trans->state == STATE_INTERRUPTED) {
675 return ret;
676 }
677
678 if(commit_single_pkg(handle, newpkg, pkg_current, pkg_count)) {
679 /* something screwed up on the commit, abort the trans */
680 trans->state = STATE_INTERRUPTED;
681 handle->pm_errno = ALPM_ERR_TRANS_ABORT;
682 /* running ldconfig at this point could possibly screw system */
683 skip_ldconfig = 1;
684 ret = -1;
685 }
686
687 pkg_current++;
688 }
689
690 if(!skip_ldconfig) {
691 /* run ldconfig if it exists */
692 _alpm_ldconfig(handle);
693 }
694
695 return ret;
696 }
697