static void pk_backend_transaction_upgrade_done (PkBackend *self, alpm_pkg_t *pkg, alpm_pkg_t *old, gint direction) { const gchar *name, *pre, *post; g_return_if_fail (self != NULL); g_return_if_fail (pkg != NULL); g_return_if_fail (old != NULL || direction == 0); g_return_if_fail (alpm != NULL); name = alpm_pkg_get_name (pkg); if (direction != 0) { pre = alpm_pkg_get_version (old); } post = alpm_pkg_get_version (pkg); if (direction > 0) { alpm_logaction (alpm, PK_LOG_PREFIX, "upgraded %s (%s -> %s)\n", name, pre, post); } else if (direction < 0) { alpm_logaction (alpm, PK_LOG_PREFIX, "downgraded %s (%s -> %s)\n", name, pre, post); } else { alpm_logaction (alpm, PK_LOG_PREFIX, "reinstalled %s (%s)\n", name, post); } pk_backend_pkg (self, pkg, PK_INFO_ENUM_FINISHED); if (direction != 0) { pk_backend_transaction_process_new_optdepends (self, pkg, old); } pk_backend_output_end (self); }
static void pk_backend_transaction_add_done (PkBackend *self, alpm_pkg_t *pkg) { const gchar *name, *version; const alpm_list_t *i, *optdepends; g_return_if_fail (self != NULL); g_return_if_fail (pkg != NULL); g_return_if_fail (alpm != NULL); name = alpm_pkg_get_name (pkg); version = alpm_pkg_get_version (pkg); alpm_logaction (alpm, PK_LOG_PREFIX, "installed %s (%s)\n", name, version); pk_backend_pkg (self, pkg, PK_INFO_ENUM_FINISHED); optdepends = alpm_pkg_get_optdepends (pkg); if (optdepends != NULL) { pk_backend_output (self, "Optional dependencies:\n"); for (i = optdepends; i != NULL; i = i->next) { gchar *depend = alpm_dep_compute_string (i->data); gchar *output = g_strdup_printf ("%s\n", depend); free (depend); pk_backend_output (self, output); g_free (output); } } pk_backend_output_end (self); }
int pu_log_command(alpm_handle_t *handle, const char *caller, int argc, char **argv) { int i; char *cmd, *c; size_t cmdlen = 0; for(i = 0; i < argc; ++i) { cmdlen += strlen(argv[i]) + 1; } cmd = c = malloc(cmdlen + 1); if(!cmd) { return -1; } for(i = 0; i < argc; ++i) { c = stpcpy(c, " "); c = stpcpy(c, argv[i]); } alpm_logaction(handle, caller, "Running%s\n", cmd); free(cmd); return 0; }
/** Print command line to logfile. * @param argc * @param argv */ static void cl_to_log(int argc, char *argv[]) { size_t size = 0; int i; for(i = 0; i < argc; i++) { size += strlen(argv[i]) + 1; } if(!size) { return; } char *cl_text = malloc(size); if(!cl_text) { return; } char *p = cl_text; for(i = 0; i < argc - 1; i++) { strcpy(p, argv[i]); p += strlen(argv[i]); *p++ = ' '; } strcpy(p, argv[i]); alpm_logaction(config->handle, PACMAN_CALLER_PREFIX, "Running '%s'\n", cl_text); free(cl_text); }
/** Release a transaction. */ int SYMEXPORT alpm_trans_release(alpm_handle_t *handle) { alpm_trans_t *trans; /* Sanity checks */ CHECK_HANDLE(handle, return -1); trans = handle->trans; ASSERT(trans != NULL, RET_ERR(handle, ALPM_ERR_TRANS_NULL, -1)); ASSERT(trans->state != STATE_IDLE, RET_ERR(handle, ALPM_ERR_TRANS_NULL, -1)); int nolock_flag = trans->flags & ALPM_TRANS_FLAG_NOLOCK; _alpm_trans_free(trans); handle->trans = NULL; /* unlock db */ if(!nolock_flag) { if(_alpm_handle_unlock(handle)) { _alpm_log(handle, ALPM_LOG_WARNING, _("could not remove lock file %s\n"), alpm_option_get_lockfile(handle)); alpm_logaction(handle, "warning: could not remove lock file %s\n", alpm_option_get_lockfile(handle)); } } return 0; }
/** Release a transaction. * @return 0 on success, -1 on error (pm_errno is set accordingly) */ int SYMEXPORT alpm_trans_release() { pmtrans_t *trans; ALPM_LOG_FUNC; /* Sanity checks */ ASSERT(handle != NULL, RET_ERR(PM_ERR_HANDLE_NULL, -1)); trans = handle->trans; ASSERT(trans != NULL, RET_ERR(PM_ERR_TRANS_NULL, -1)); ASSERT(trans->state != STATE_IDLE, RET_ERR(PM_ERR_TRANS_NULL, -1)); _alpm_trans_free(trans); handle->trans = NULL; /* unlock db */ if(handle->lckfd != -1) { while(close(handle->lckfd) == -1 && errno == EINTR); handle->lckfd = -1; } if(_alpm_lckrm()) { _alpm_log(PM_LOG_WARNING, _("could not remove lock file %s\n"), alpm_option_get_lockfile()); alpm_logaction("warning: could not remove lock file %s\n", alpm_option_get_lockfile()); } return(0); }
static int perform_extraction(alpm_handle_t *handle, struct archive *archive, struct archive_entry *entry, const char *filename) { int ret; const int archive_flags = ARCHIVE_EXTRACT_OWNER | ARCHIVE_EXTRACT_PERM | ARCHIVE_EXTRACT_TIME | ARCHIVE_EXTRACT_UNLINK | ARCHIVE_EXTRACT_SECURE_SYMLINKS; archive_entry_set_pathname(entry, filename); ret = archive_read_extract(archive, entry, archive_flags); if(ret == ARCHIVE_WARN && archive_errno(archive) != ENOSPC) { /* operation succeeded but a "non-critical" error was encountered */ _alpm_log(handle, ALPM_LOG_WARNING, _("warning given when extracting %s (%s)\n"), filename, archive_error_string(archive)); } else if(ret != ARCHIVE_OK) { _alpm_log(handle, ALPM_LOG_ERROR, _("could not extract %s (%s)\n"), filename, archive_error_string(archive)); alpm_logaction(handle, ALPM_CALLER_PREFIX, "error: could not extract %s (%s)\n", filename, archive_error_string(archive)); return 1; } return 0; }
static int try_rename(alpm_handle_t *handle, const char *src, const char *dest) { if(rename(src, dest)) { _alpm_log(handle, ALPM_LOG_ERROR, _("could not rename %s to %s (%s)\n"), src, dest, strerror(errno)); alpm_logaction(handle, ALPM_CALLER_PREFIX, "error: could not rename %s to %s (%s)\n", src, dest, strerror(errno)); return 1; } return 0; }
static gboolean pk_backend_update_databases (PkBackend *self, gint force, GError **error) { alpm_cb_download dlcb; alpm_cb_totaldl totaldlcb; const alpm_list_t *i; g_return_val_if_fail (self != NULL, FALSE); if (!pk_backend_transaction_initialize (self, 0, error)) { return FALSE; } alpm_logaction ("synchronizing package lists\n"); dlcb = alpm_option_get_dlcb (); totaldlcb = alpm_option_get_totaldlcb (); /* set total size to minus the number of databases */ i = alpm_option_get_syncdbs (); totaldlcb (-alpm_list_count (i)); for (; i != NULL; i = i->next) { gint result; if (pk_backend_cancelled (self)) { /* pretend to be finished */ i = NULL; break; } result = alpm_db_update (force, i->data); if (result > 0) { /* fake the download when already up to date */ dlcb ("", 1, 1); } else if (result < 0) { g_set_error (error, ALPM_ERROR, pm_errno, "[%s]: %s", alpm_db_get_name (i->data), alpm_strerrorlast ()); break; } } totaldlcb (0); if (i == NULL) { return pk_backend_transaction_end (self, error); } else { pk_backend_transaction_end (self, NULL); return FALSE; } }
int pacman_files(alpm_list_t *targets) { alpm_list_t *files_dbs = NULL; if(check_syncdbs(1, 0)) { return 1; } files_dbs = alpm_get_syncdbs(config->handle); if(config->op_s_sync) { /* grab a fresh package list */ colon_printf(_("Synchronizing package databases...\n")); alpm_logaction(config->handle, PACMAN_CALLER_PREFIX, "synchronizing package lists\n"); if(!sync_syncdbs(config->op_s_sync, files_dbs)) { return 1; } } if(targets == NULL && (config->op_q_owns | config->op_s_search)) { pm_printf(ALPM_LOG_ERROR, _("no targets specified (use -h for help)\n")); return 1; } /* determine the owner of a file */ if(config->op_q_owns) { return files_fileowner(files_dbs, targets); } /* search for a file */ if(config->op_s_search) { return files_search(files_dbs, targets, config->op_f_regex); } /* get a listing of files in sync DBs */ if(config->op_q_list) { return files_list(files_dbs, targets); } if(targets != NULL) { pm_printf(ALPM_LOG_ERROR, _("no options specified (use -h for help)\n")); return 1; } return 0; }
static void pk_backend_transaction_remove_done (PkBackend *self, alpm_pkg_t *pkg) { const gchar *name, *version; g_return_if_fail (self != NULL); g_return_if_fail (pkg != NULL); g_return_if_fail (alpm != NULL); name = alpm_pkg_get_name (pkg); version = alpm_pkg_get_version (pkg); alpm_logaction (alpm, PK_LOG_PREFIX, "removed %s (%s)\n", name, version); pk_backend_pkg (self, pkg, PK_INFO_ENUM_FINISHED); pk_backend_output_end (self); }
int ipacman_refresh_databases(void) { alpm_list_t *sync_dbs = NULL; alpm_list_t *i; unsigned int success = 0; sync_dbs = alpm_get_syncdbs(handle); if(sync_dbs == NULL) { printf("no usable package repositories configured.\n"); return -1; } printf("Synchronizing package databases...\n"); alpm_logaction(handle, PACMAN_CALLER_PREFIX, "synchronizing package lists\n"); for(i = sync_dbs; i; i = alpm_list_next(i)) { alpm_db_t *db = i->data; int ret = alpm_db_update(1, db); if(ret < 0) { printf("failed to update %s (%s)\n", alpm_db_get_name(db), alpm_strerror(alpm_errno(handle))); } else if(ret == 1) { printf(" %s is up to date\n", alpm_db_get_name(db)); success++; } else { success++; } } /* We should always succeed if at least one DB was upgraded - we may possibly * fail later with unresolved deps, but that should be rare, and would be * expected */ if(!success) { printf("failed to synchronize any databases\n"); trans_init_error(handle); return success; } return 0; }
/** Execute a command with arguments in a chroot. * @param handle the context handle * @param cmd command to execute * @param argv arguments to pass to cmd * @return 0 on success, 1 on error */ int _alpm_run_chroot(alpm_handle_t *handle, const char *cmd, char *const argv[]) { pid_t pid; int pipefd[2], cwdfd; int retval = 0; /* save the cwd so we can restore it later */ OPEN(cwdfd, ".", O_RDONLY); if(cwdfd < 0) { _alpm_log(handle, ALPM_LOG_ERROR, _("could not get current working directory\n")); } /* just in case our cwd was removed in the upgrade operation */ if(chdir(handle->root) != 0) { _alpm_log(handle, ALPM_LOG_ERROR, _("could not change directory to %s (%s)\n"), handle->root, strerror(errno)); goto cleanup; } _alpm_log(handle, ALPM_LOG_DEBUG, "executing \"%s\" under chroot \"%s\"\n", cmd, handle->root); /* Flush open fds before fork() to avoid cloning buffers */ fflush(NULL); if(pipe(pipefd) == -1) { _alpm_log(handle, ALPM_LOG_ERROR, _("could not create pipe (%s)\n"), strerror(errno)); retval = 1; goto cleanup; } /* fork- parent and child each have seperate code blocks below */ pid = fork(); if(pid == -1) { _alpm_log(handle, ALPM_LOG_ERROR, _("could not fork a new process (%s)\n"), strerror(errno)); retval = 1; goto cleanup; } if(pid == 0) { /* this code runs for the child only (the actual chroot/exec) */ CLOSE(1); CLOSE(2); while(dup2(pipefd[1], 1) == -1 && errno == EINTR); while(dup2(pipefd[1], 2) == -1 && errno == EINTR); CLOSE(pipefd[0]); CLOSE(pipefd[1]); /* use fprintf instead of _alpm_log to send output through the parent */ if(chroot(handle->root) != 0) { fprintf(stderr, _("could not change the root directory (%s)\n"), strerror(errno)); exit(1); } if(chdir("/") != 0) { fprintf(stderr, _("could not change directory to %s (%s)\n"), "/", strerror(errno)); exit(1); } umask(0022); execv(cmd, argv); /* execv only returns if there was an error */ fprintf(stderr, _("call to execv failed (%s)\n"), strerror(errno)); exit(1); } else { /* this code runs for the parent only (wait on the child) */ int status; FILE *pipe_file; CLOSE(pipefd[1]); pipe_file = fdopen(pipefd[0], "r"); if(pipe_file == NULL) { CLOSE(pipefd[0]); retval = 1; } else { while(!feof(pipe_file)) { char line[PATH_MAX]; if(fgets(line, PATH_MAX, pipe_file) == NULL) break; alpm_logaction(handle, "%s", line); EVENT(handle, ALPM_EVENT_SCRIPTLET_INFO, line, NULL); } fclose(pipe_file); } while(waitpid(pid, &status, 0) == -1) { if(errno != EINTR) { _alpm_log(handle, ALPM_LOG_ERROR, _("call to waitpid failed (%s)\n"), strerror(errno)); retval = 1; goto cleanup; } } /* report error from above after the child has exited */ if(retval != 0) { _alpm_log(handle, ALPM_LOG_ERROR, _("could not open pipe (%s)\n"), strerror(errno)); goto cleanup; } /* check the return status, make sure it is 0 (success) */ if(WIFEXITED(status)) { _alpm_log(handle, ALPM_LOG_DEBUG, "call to waitpid succeeded\n"); if(WEXITSTATUS(status) != 0) { _alpm_log(handle, ALPM_LOG_ERROR, _("command failed to execute correctly\n")); retval = 1; } } } cleanup: if(cwdfd >= 0) { if(fchdir(cwdfd) != 0) { _alpm_log(handle, ALPM_LOG_ERROR, _("could not restore working directory (%s)\n"), strerror(errno)); } CLOSE(cwdfd); } return retval; }
static int extract_single_file(alpm_handle_t *handle, struct archive *archive, struct archive_entry *entry, alpm_pkg_t *newpkg, alpm_pkg_t *oldpkg) { const char *entryname = archive_entry_pathname(entry); mode_t entrymode = archive_entry_mode(entry); alpm_backup_t *backup = _alpm_needbackup(entryname, newpkg); char filename[PATH_MAX]; /* the actual file we're extracting */ int needbackup = 0, notouch = 0; const char *hash_orig = NULL; int isnewfile = 0, errors = 0; struct stat lsbuf; size_t filename_len; if(*entryname == '.') { return extract_db_file(handle, archive, entry, newpkg, entryname); } if (!alpm_filelist_contains(&newpkg->files, entryname)) { _alpm_log(handle, ALPM_LOG_WARNING, _("file not found in file list for package %s. skipping extraction of %s\n"), newpkg->name, entryname); return 0; } /* build the new entryname relative to handle->root */ filename_len = snprintf(filename, PATH_MAX, "%s%s", handle->root, entryname); if(filename_len >= PATH_MAX) { _alpm_log(handle, ALPM_LOG_ERROR, _("unable to extract %s%s: path too long"), handle->root, entryname); return 1; } /* if a file is in NoExtract then we never extract it */ if(_alpm_fnmatch_patterns(handle->noextract, entryname) == 0) { _alpm_log(handle, ALPM_LOG_DEBUG, "%s is in NoExtract," " skipping extraction of %s\n", entryname, filename); archive_read_data_skip(archive); return 0; } /* Check for file existence. This is one of the more crucial parts * to get 'right'. Here are the possibilities, with the filesystem * on the left and the package on the top: * (F=file, N=node, S=symlink, D=dir) * | F/N | D * non-existent | 1 | 2 * F/N | 3 | 4 * D | 5 | 6 * * 1,2- extract, no magic necessary. lstat (llstat) will fail here. * 3,4- conflict checks should have caught this. either overwrite * or backup the file. * 5- file replacing directory- don't allow it. * 6- skip extraction, dir already exists. */ isnewfile = llstat(filename, &lsbuf) != 0; if(isnewfile) { /* cases 1,2: file doesn't exist, skip all backup checks */ } else if(S_ISDIR(lsbuf.st_mode) && S_ISDIR(entrymode)) { #if 0 uid_t entryuid = archive_entry_uid(entry); gid_t entrygid = archive_entry_gid(entry); #endif /* case 6: existing dir, ignore it */ if(lsbuf.st_mode != entrymode) { /* if filesystem perms are different than pkg perms, warn user */ mode_t mask = 07777; _alpm_log(handle, ALPM_LOG_WARNING, _("directory permissions differ on %s\n" "filesystem: %o package: %o\n"), filename, lsbuf.st_mode & mask, entrymode & mask); alpm_logaction(handle, ALPM_CALLER_PREFIX, "warning: directory permissions differ on %s\n" "filesystem: %o package: %o\n", filename, lsbuf.st_mode & mask, entrymode & mask); } #ifndef __MSYS__ #if 0 /* Disable this warning until our user management in packages has improved. Currently many packages have to create users in post_install and chown the directories. These all resulted in "false-positive" warnings. */ if((entryuid != lsbuf.st_uid) || (entrygid != lsbuf.st_gid)) { _alpm_log(handle, ALPM_LOG_WARNING, _("directory ownership differs on %s\n" "filesystem: %u:%u package: %u:%u\n"), filename, lsbuf.st_uid, lsbuf.st_gid, entryuid, entrygid); alpm_logaction(handle, ALPM_CALLER_PREFIX, "warning: directory ownership differs on %s\n" "filesystem: %u:%u package: %u:%u\n", filename, lsbuf.st_uid, lsbuf.st_gid, entryuid, entrygid); } #endif #endif _alpm_log(handle, ALPM_LOG_DEBUG, "extract: skipping dir extraction of %s\n", filename); archive_read_data_skip(archive); return 0; } else if(S_ISDIR(lsbuf.st_mode)) { /* case 5: trying to overwrite dir with file, don't allow it */ _alpm_log(handle, ALPM_LOG_ERROR, _("extract: not overwriting dir with file %s\n"), filename); archive_read_data_skip(archive); return 1; } else if(S_ISDIR(entrymode)) { /* case 4: trying to overwrite file with dir */ _alpm_log(handle, ALPM_LOG_DEBUG, "extract: overwriting file with dir %s\n", filename); } else { /* case 3: trying to overwrite file with file */ /* if file is in NoUpgrade, don't touch it */ if(_alpm_fnmatch_patterns(handle->noupgrade, entryname) == 0) { notouch = 1; } else { alpm_backup_t *oldbackup; if(oldpkg && (oldbackup = _alpm_needbackup(entryname, oldpkg))) { hash_orig = oldbackup->hash; needbackup = 1; } else if(backup) { /* allow adding backup files retroactively */ needbackup = 1; } } } if(notouch || needbackup) { if(filename_len + strlen(".pacnew") >= PATH_MAX) { _alpm_log(handle, ALPM_LOG_ERROR, _("unable to extract %s.pacnew: path too long"), filename); return 1; } strcpy(filename + filename_len, ".pacnew"); isnewfile = (llstat(filename, &lsbuf) != 0 && errno == ENOENT); } _alpm_log(handle, ALPM_LOG_DEBUG, "extracting %s\n", filename); if(perform_extraction(handle, archive, entry, filename)) { errors++; return errors; } if(backup) { FREE(backup->hash); backup->hash = alpm_compute_md5sum(filename); } if(notouch) { alpm_event_pacnew_created_t event = { .type = ALPM_EVENT_PACNEW_CREATED, .from_noupgrade = 1, .oldpkg = oldpkg, .newpkg = newpkg, .file = filename }; /* "remove" the .pacnew suffix */ filename[filename_len] = '\0'; EVENT(handle, &event); alpm_logaction(handle, ALPM_CALLER_PREFIX, "warning: %s installed as %s.pacnew\n", filename, filename); } else if(needbackup) { char *hash_local = NULL, *hash_pkg = NULL; char origfile[PATH_MAX] = ""; strncat(origfile, filename, filename_len); hash_local = alpm_compute_md5sum(origfile); hash_pkg = backup ? backup->hash : alpm_compute_md5sum(filename); _alpm_log(handle, ALPM_LOG_DEBUG, "checking hashes for %s\n", origfile); _alpm_log(handle, ALPM_LOG_DEBUG, "current: %s\n", hash_local); _alpm_log(handle, ALPM_LOG_DEBUG, "new: %s\n", hash_pkg); _alpm_log(handle, ALPM_LOG_DEBUG, "original: %s\n", hash_orig); if(hash_local && hash_pkg && strcmp(hash_local, hash_pkg) == 0) { /* local and new files are the same, updating anyway to get * correct timestamps */ _alpm_log(handle, ALPM_LOG_DEBUG, "action: installing new file: %s\n", origfile); if(try_rename(handle, filename, origfile)) { errors++; } } else if(hash_orig && hash_pkg && strcmp(hash_orig, hash_pkg) == 0) { /* original and new files are the same, leave the local version alone, * including any user changes */ _alpm_log(handle, ALPM_LOG_DEBUG, "action: leaving existing file in place\n"); if(isnewfile) { unlink(filename); } } else if(hash_orig && hash_local && strcmp(hash_orig, hash_local) == 0) { /* installed file has NOT been changed by user, * update to the new version */ _alpm_log(handle, ALPM_LOG_DEBUG, "action: installing new file: %s\n", origfile); if(try_rename(handle, filename, origfile)) { errors++; } } else { /* none of the three files matched another, leave the unpacked * file alongside the local file */ alpm_event_pacnew_created_t event = { .type = ALPM_EVENT_PACNEW_CREATED, .from_noupgrade = 0, .oldpkg = oldpkg, .newpkg = newpkg, .file = origfile }; _alpm_log(handle, ALPM_LOG_DEBUG, "action: keeping current file and installing" " new one with .pacnew ending\n"); EVENT(handle, &event); alpm_logaction(handle, ALPM_CALLER_PREFIX, "warning: %s installed as %s\n", origfile, filename); } free(hash_local); if(!backup) { free(hash_pkg); } } return errors; } static int commit_single_pkg(alpm_handle_t *handle, alpm_pkg_t *newpkg, size_t pkg_current, size_t pkg_count) { int i, ret = 0, errors = 0; int is_upgrade = 0; alpm_pkg_t *oldpkg = NULL; alpm_db_t *db = handle->db_local; alpm_trans_t *trans = handle->trans; alpm_progress_t progress = ALPM_PROGRESS_ADD_START; alpm_event_package_operation_t event; const char *log_msg = "adding"; const char *pkgfile; ASSERT(trans != NULL, return -1); /* see if this is an upgrade. if so, remove the old package first */ if((oldpkg = newpkg->oldpkg)) { int cmp = _alpm_pkg_compare_versions(newpkg, oldpkg); if(cmp < 0) { log_msg = "downgrading"; progress = ALPM_PROGRESS_DOWNGRADE_START; event.operation = ALPM_PACKAGE_DOWNGRADE; } else if(cmp == 0) { log_msg = "reinstalling"; progress = ALPM_PROGRESS_REINSTALL_START; event.operation = ALPM_PACKAGE_REINSTALL; } else { log_msg = "upgrading"; progress = ALPM_PROGRESS_UPGRADE_START; event.operation = ALPM_PACKAGE_UPGRADE; } is_upgrade = 1; /* copy over the install reason */ newpkg->reason = alpm_pkg_get_reason(oldpkg); } else { event.operation = ALPM_PACKAGE_INSTALL; } event.type = ALPM_EVENT_PACKAGE_OPERATION_START; event.oldpkg = oldpkg; event.newpkg = newpkg; EVENT(handle, &event); pkgfile = newpkg->origin_data.file; _alpm_log(handle, ALPM_LOG_DEBUG, "%s package %s-%s\n", log_msg, newpkg->name, newpkg->version); /* pre_install/pre_upgrade scriptlet */ if(alpm_pkg_has_scriptlet(newpkg) && !(trans->flags & ALPM_TRANS_FLAG_NOSCRIPTLET)) { const char *scriptlet_name = is_upgrade ? "pre_upgrade" : "pre_install"; _alpm_runscriptlet(handle, pkgfile, scriptlet_name, newpkg->version, oldpkg ? oldpkg->version : NULL, 1); } /* we override any pre-set reason if we have alldeps or allexplicit set */ if(trans->flags & ALPM_TRANS_FLAG_ALLDEPS) { newpkg->reason = ALPM_PKG_REASON_DEPEND; } else if(trans->flags & ALPM_TRANS_FLAG_ALLEXPLICIT) { newpkg->reason = ALPM_PKG_REASON_EXPLICIT; } if(oldpkg) { /* set up fake remove transaction */ if(_alpm_remove_single_package(handle, oldpkg, newpkg, 0, 0) == -1) { handle->pm_errno = ALPM_ERR_TRANS_ABORT; ret = -1; goto cleanup; } } /* prepare directory for database entries so permission are correct after changelog/install script installation */ if(_alpm_local_db_prepare(db, newpkg)) { alpm_logaction(handle, ALPM_CALLER_PREFIX, "error: could not create database entry %s-%s\n", newpkg->name, newpkg->version); handle->pm_errno = ALPM_ERR_DB_WRITE; ret = -1; goto cleanup; } if(!(trans->flags & ALPM_TRANS_FLAG_DBONLY)) { struct archive *archive; struct archive_entry *entry; struct stat buf; int fd, cwdfd; _alpm_log(handle, ALPM_LOG_DEBUG, "extracting files\n"); fd = _alpm_open_archive(db->handle, pkgfile, &buf, &archive, ALPM_ERR_PKG_OPEN); if(fd < 0) { ret = -1; goto cleanup; } /* save the cwd so we can restore it later */ OPEN(cwdfd, ".", O_RDONLY | O_CLOEXEC); if(cwdfd < 0) { _alpm_log(handle, ALPM_LOG_ERROR, _("could not get current working directory\n")); } /* libarchive requires this for extracting hard links */ if(chdir(handle->root) != 0) { _alpm_log(handle, ALPM_LOG_ERROR, _("could not change directory to %s (%s)\n"), handle->root, strerror(errno)); _alpm_archive_read_free(archive); close(fd); ret = -1; goto cleanup; } /* call PROGRESS once with 0 percent, as we sort-of skip that here */ PROGRESS(handle, progress, newpkg->name, 0, pkg_count, pkg_current); for(i = 0; archive_read_next_header(archive, &entry) == ARCHIVE_OK; i++) { int percent; if(newpkg->size != 0) { /* Using compressed size for calculations here, as newpkg->isize is not * exact when it comes to comparing to the ACTUAL uncompressed size * (missing metadata sizes) */ int64_t pos = _alpm_archive_compressed_ftell(archive); percent = (pos * 100) / newpkg->size; if(percent >= 100) { percent = 100; } } else { percent = 0; } PROGRESS(handle, progress, newpkg->name, percent, pkg_count, pkg_current); /* extract the next file from the archive */ errors += extract_single_file(handle, archive, entry, newpkg, oldpkg); } _alpm_archive_read_free(archive); close(fd); /* restore the old cwd if we have it */ if(cwdfd >= 0) { if(fchdir(cwdfd) != 0) { _alpm_log(handle, ALPM_LOG_ERROR, _("could not restore working directory (%s)\n"), strerror(errno)); } close(cwdfd); } if(errors) { ret = -1; if(is_upgrade) { _alpm_log(handle, ALPM_LOG_ERROR, _("problem occurred while upgrading %s\n"), newpkg->name); alpm_logaction(handle, ALPM_CALLER_PREFIX, "error: problem occurred while upgrading %s\n", newpkg->name); } else { _alpm_log(handle, ALPM_LOG_ERROR, _("problem occurred while installing %s\n"), newpkg->name); alpm_logaction(handle, ALPM_CALLER_PREFIX, "error: problem occurred while installing %s\n", newpkg->name); } } } /* make an install date (in UTC) */ newpkg->installdate = time(NULL); _alpm_log(handle, ALPM_LOG_DEBUG, "updating database\n"); _alpm_log(handle, ALPM_LOG_DEBUG, "adding database entry '%s'\n", newpkg->name); if(_alpm_local_db_write(db, newpkg, INFRQ_ALL)) { _alpm_log(handle, ALPM_LOG_ERROR, _("could not update database entry %s-%s\n"), newpkg->name, newpkg->version); alpm_logaction(handle, ALPM_CALLER_PREFIX, "error: could not update database entry %s-%s\n", newpkg->name, newpkg->version); handle->pm_errno = ALPM_ERR_DB_WRITE; ret = -1; goto cleanup; } if(_alpm_db_add_pkgincache(db, newpkg) == -1) { _alpm_log(handle, ALPM_LOG_ERROR, _("could not add entry '%s' in cache\n"), newpkg->name); } PROGRESS(handle, progress, newpkg->name, 100, pkg_count, pkg_current); switch(event.operation) { case ALPM_PACKAGE_INSTALL: alpm_logaction(handle, ALPM_CALLER_PREFIX, "installed %s (%s)\n", newpkg->name, newpkg->version); break; case ALPM_PACKAGE_DOWNGRADE: alpm_logaction(handle, ALPM_CALLER_PREFIX, "downgraded %s (%s -> %s)\n", newpkg->name, oldpkg->version, newpkg->version); break; case ALPM_PACKAGE_REINSTALL: alpm_logaction(handle, ALPM_CALLER_PREFIX, "reinstalled %s (%s)\n", newpkg->name, newpkg->version); break; case ALPM_PACKAGE_UPGRADE: alpm_logaction(handle, ALPM_CALLER_PREFIX, "upgraded %s (%s -> %s)\n", newpkg->name, oldpkg->version, newpkg->version); break; default: /* we should never reach here */ break; } /* run the post-install script if it exists */ if(alpm_pkg_has_scriptlet(newpkg) && !(trans->flags & ALPM_TRANS_FLAG_NOSCRIPTLET)) { char *scriptlet = _alpm_local_db_pkgpath(db, newpkg, "install"); const char *scriptlet_name = is_upgrade ? "post_upgrade" : "post_install"; _alpm_runscriptlet(handle, scriptlet, scriptlet_name, newpkg->version, oldpkg ? oldpkg->version : NULL, 0); free(scriptlet); } event.type = ALPM_EVENT_PACKAGE_OPERATION_DONE; EVENT(handle, &event); cleanup: return ret; }
/** * @brief Unlink a package file, backing it up if necessary. * * @param handle the context handle * @param oldpkg the package being removed * @param newpkg the package replacing \a oldpkg * @param fileobj file to remove * @param skip_remove list of files that shouldn't be removed * @param nosave whether files should be backed up * * @return 0 on success, -1 if there was an error unlinking the file, 1 if the * file was skipped or did not exist */ static int unlink_file(alpm_handle_t *handle, alpm_pkg_t *oldpkg, alpm_pkg_t *newpkg, const alpm_file_t *fileobj, alpm_list_t *skip_remove, int nosave) { struct stat buf; char file[PATH_MAX]; snprintf(file, PATH_MAX, "%s%s", handle->root, fileobj->name); /* check the remove skip list before removing the file. * see the big comment block in db_find_fileconflicts() for an * explanation. */ if(alpm_list_find(skip_remove, fileobj->name, _alpm_fnmatch)) { _alpm_log(handle, ALPM_LOG_DEBUG, "%s is in skip_remove, skipping removal\n", file); return 1; } if(_alpm_lstat(file, &buf)) { _alpm_log(handle, ALPM_LOG_DEBUG, "file %s does not exist\n", file); return 1; } if(S_ISDIR(buf.st_mode)) { ssize_t files = _alpm_files_in_directory(handle, file, 0); /* if we have files, no need to remove the directory */ if(files > 0) { _alpm_log(handle, ALPM_LOG_DEBUG, "keeping directory %s (contains files)\n", file); } else if(files < 0) { _alpm_log(handle, ALPM_LOG_DEBUG, "keeping directory %s (could not count files)\n", file); } else if(newpkg && alpm_filelist_contains(alpm_pkg_get_files(newpkg), fileobj->name)) { _alpm_log(handle, ALPM_LOG_DEBUG, "keeping directory %s (in new package)\n", file); } else if(dir_is_mountpoint(handle, file, &buf)) { _alpm_log(handle, ALPM_LOG_DEBUG, "keeping directory %s (mountpoint)\n", file); } else { /* one last check- does any other package own this file? */ alpm_list_t *local, *local_pkgs; int found = 0; local_pkgs = _alpm_db_get_pkgcache(handle->db_local); for(local = local_pkgs; local && !found; local = local->next) { alpm_pkg_t *local_pkg = local->data; alpm_filelist_t *filelist; /* we duplicated the package when we put it in the removal list, so we * so we can't use direct pointer comparison here. */ if(oldpkg->name_hash == local_pkg->name_hash && strcmp(oldpkg->name, local_pkg->name) == 0) { continue; } filelist = alpm_pkg_get_files(local_pkg); if(alpm_filelist_contains(filelist, fileobj->name)) { _alpm_log(handle, ALPM_LOG_DEBUG, "keeping directory %s (owned by %s)\n", file, local_pkg->name); found = 1; } } if(!found) { if(rmdir(file)) { _alpm_log(handle, ALPM_LOG_DEBUG, "directory removal of %s failed: %s\n", file, strerror(errno)); return -1; } else { _alpm_log(handle, ALPM_LOG_DEBUG, "removed directory %s (no remaining owners)\n", file); } } } } else { /* if the file needs backup and has been modified, back it up to .pacsave */ alpm_backup_t *backup = _alpm_needbackup(fileobj->name, oldpkg); if(backup) { if(nosave) { _alpm_log(handle, ALPM_LOG_DEBUG, "transaction is set to NOSAVE, not backing up '%s'\n", file); } else { char *filehash = alpm_compute_md5sum(file); int cmp = filehash ? strcmp(filehash, backup->hash) : 0; FREE(filehash); if(cmp != 0) { char *newpath; size_t len = strlen(file) + 8 + 1; MALLOC(newpath, len, RET_ERR(handle, ALPM_ERR_MEMORY, -1)); shift_pacsave(handle, file); snprintf(newpath, len, "%s.pacsave", file); if(rename(file, newpath)) { _alpm_log(handle, ALPM_LOG_ERROR, _("could not rename %s to %s (%s)\n"), file, newpath, strerror(errno)); alpm_logaction(handle, ALPM_CALLER_PREFIX, "error: could not rename %s to %s (%s)\n", file, newpath, strerror(errno)); free(newpath); return -1; } _alpm_log(handle, ALPM_LOG_WARNING, _("%s saved as %s\n"), file, newpath); alpm_logaction(handle, ALPM_CALLER_PREFIX, "warning: %s saved as %s\n", file, newpath); free(newpath); return 0; } } } _alpm_log(handle, ALPM_LOG_DEBUG, "unlinking %s\n", file); if(unlink(file) == -1) { _alpm_log(handle, ALPM_LOG_ERROR, _("cannot remove %s (%s)\n"), file, strerror(errno)); alpm_logaction(handle, ALPM_CALLER_PREFIX, "error: cannot remove %s (%s)\n", file, strerror(errno)); return -1; } } return 0; }
/* callback to handle messages/notifications from libalpm transactions */ static void cb_event(alpm_event_t event, void *data1, void *data2) { switch(event) { case ALPM_EVENT_CHECKDEPS_START: printf("checking dependencies...\n"); break; case ALPM_EVENT_FILECONFLICTS_START: printf("checking for file conflicts...\n"); break; case ALPM_EVENT_RESOLVEDEPS_START: printf("resolving dependencies...\n"); break; case ALPM_EVENT_INTERCONFLICTS_START: printf("looking for inter-conflicts...\n"); break; case ALPM_EVENT_ADD_START: printf("installing %s...\n", alpm_pkg_get_name(data1)); break; case ALPM_EVENT_ADD_DONE: alpm_logaction(handle, PACMAN_CALLER_PREFIX, "installed %s (%s)\n", alpm_pkg_get_name(data1), alpm_pkg_get_version(data1)); break; case ALPM_EVENT_REMOVE_START: printf("removing %s...\n", alpm_pkg_get_name(data1)); break; case ALPM_EVENT_REMOVE_DONE: alpm_logaction(handle, PACMAN_CALLER_PREFIX, "removed %s (%s)\n", alpm_pkg_get_name(data1), alpm_pkg_get_version(data1)); break; case ALPM_EVENT_UPGRADE_START: printf("upgrading %s...\n", alpm_pkg_get_name(data1)); break; case ALPM_EVENT_UPGRADE_DONE: alpm_logaction(handle, PACMAN_CALLER_PREFIX, "upgraded %s (%s -> %s)\n", alpm_pkg_get_name(data1), alpm_pkg_get_version(data2), alpm_pkg_get_version(data1)); break; case ALPM_EVENT_DOWNGRADE_START: printf("downgrading %s...\n", alpm_pkg_get_name(data1)); break; case ALPM_EVENT_DOWNGRADE_DONE: alpm_logaction(handle, PACMAN_CALLER_PREFIX, "downgraded %s (%s -> %s)\n", alpm_pkg_get_name(data1), alpm_pkg_get_version(data2), alpm_pkg_get_version(data1)); break; case ALPM_EVENT_REINSTALL_START: printf("reinstalling %s...\n", alpm_pkg_get_name(data1)); break; case ALPM_EVENT_REINSTALL_DONE: alpm_logaction(handle, PACMAN_CALLER_PREFIX, "reinstalled %s (%s)\n", alpm_pkg_get_name(data1), alpm_pkg_get_version(data1)); break; case ALPM_EVENT_INTEGRITY_START: printf("checking package integrity...\n"); break; case ALPM_EVENT_KEYRING_START: printf("checking keyring...\n"); break; case ALPM_EVENT_KEY_DOWNLOAD_START: printf("downloading required keys...\n"); break; case ALPM_EVENT_LOAD_START: printf("loading package files...\n"); break; case ALPM_EVENT_DELTA_INTEGRITY_START: printf("checking delta integrity...\n"); break; case ALPM_EVENT_DELTA_PATCHES_START: printf("applying deltas...\n"); break; case ALPM_EVENT_DELTA_PATCH_START: printf("generating %s with %s... ", (char *)data1, (char *)data2); break; case ALPM_EVENT_DELTA_PATCH_DONE: printf("success!\n"); break; case ALPM_EVENT_DELTA_PATCH_FAILED: printf("failed.\n"); break; case ALPM_EVENT_SCRIPTLET_INFO: fputs((const char *)data1, stdout); break; case ALPM_EVENT_RETRIEVE_START: printf("Retrieving packages ...\n"); break; case ALPM_EVENT_DISKSPACE_START: printf("checking available disk space...\n"); break; case ALPM_EVENT_OPTDEP_REQUIRED: printf("%s optionally requires %s\n", alpm_pkg_get_name(data1), alpm_dep_compute_string(data2)); break; case ALPM_EVENT_DATABASE_MISSING: printf("database file for '%s' does not exist\n", (char *)data1); break; /* all the simple done events, with fallthrough for each */ case ALPM_EVENT_FILECONFLICTS_DONE: case ALPM_EVENT_CHECKDEPS_DONE: case ALPM_EVENT_RESOLVEDEPS_DONE: case ALPM_EVENT_INTERCONFLICTS_DONE: case ALPM_EVENT_INTEGRITY_DONE: case ALPM_EVENT_KEYRING_DONE: case ALPM_EVENT_KEY_DOWNLOAD_DONE: case ALPM_EVENT_LOAD_DONE: case ALPM_EVENT_DELTA_INTEGRITY_DONE: case ALPM_EVENT_DELTA_PATCHES_DONE: case ALPM_EVENT_DISKSPACE_DONE: /* nothing */ break; } fflush(stdout); }
/** Commit a transaction. */ int SYMEXPORT alpm_trans_commit(alpm_handle_t *handle, alpm_list_t **data) { alpm_trans_t *trans; alpm_event_any_t event; /* Sanity checks */ CHECK_HANDLE(handle, return -1); trans = handle->trans; ASSERT(trans != NULL, RET_ERR(handle, ALPM_ERR_TRANS_NULL, -1)); ASSERT(trans->state == STATE_PREPARED, RET_ERR(handle, ALPM_ERR_TRANS_NOT_PREPARED, -1)); ASSERT(!(trans->flags & ALPM_TRANS_FLAG_NOLOCK), RET_ERR(handle, ALPM_ERR_TRANS_NOT_LOCKED, -1)); /* If there's nothing to do, return without complaining */ if(trans->add == NULL && trans->remove == NULL) { return 0; } if(trans->add) { if(_alpm_sync_load(handle, data) != 0) { /* pm_errno is set by _alpm_sync_load() */ return -1; } if(trans->flags & ALPM_TRANS_FLAG_DOWNLOADONLY) { return 0; } if(_alpm_sync_check(handle, data) != 0) { /* pm_errno is set by _alpm_sync_check() */ return -1; } } if(_alpm_hook_run(handle, ALPM_HOOK_PRE_TRANSACTION) != 0) { RET_ERR(handle, ALPM_ERR_TRANS_HOOK_FAILED, -1); } trans->state = STATE_COMMITING; alpm_logaction(handle, ALPM_CALLER_PREFIX, "transaction started\n"); event.type = ALPM_EVENT_TRANSACTION_START; EVENT(handle, (void *)&event); if(trans->add == NULL) { if(_alpm_remove_packages(handle, 1) == -1) { /* pm_errno is set by _alpm_remove_packages() */ alpm_errno_t save = handle->pm_errno; alpm_logaction(handle, ALPM_CALLER_PREFIX, "transaction failed\n"); handle->pm_errno = save; return -1; } } else { if(_alpm_sync_commit(handle) == -1) { /* pm_errno is set by _alpm_sync_commit() */ alpm_errno_t save = handle->pm_errno; alpm_logaction(handle, ALPM_CALLER_PREFIX, "transaction failed\n"); handle->pm_errno = save; return -1; } } if(trans->state == STATE_INTERRUPTED) { alpm_logaction(handle, ALPM_CALLER_PREFIX, "transaction interrupted\n"); } else { event.type = ALPM_EVENT_TRANSACTION_DONE; EVENT(handle, (void *)&event); alpm_logaction(handle, ALPM_CALLER_PREFIX, "transaction completed\n"); _alpm_hook_run(handle, ALPM_HOOK_POST_TRANSACTION); } trans->state = STATE_COMMITED; return 0; }
static int extract_single_file(alpm_handle_t *handle, struct archive *archive, struct archive_entry *entry, alpm_pkg_t *newpkg, alpm_pkg_t *oldpkg) { const char *entryname; mode_t entrymode; char filename[PATH_MAX]; /* the actual file we're extracting */ int needbackup = 0, notouch = 0; const char *hash_orig = NULL; char *entryname_orig = NULL; int errors = 0; entryname = archive_entry_pathname(entry); entrymode = archive_entry_mode(entry); if(strcmp(entryname, ".INSTALL") == 0) { /* the install script goes inside the db */ snprintf(filename, PATH_MAX, "%s%s-%s/install", _alpm_db_path(handle->db_local), newpkg->name, newpkg->version); archive_entry_set_perm(entry, 0644); } else if(strcmp(entryname, ".CHANGELOG") == 0) { /* the changelog goes inside the db */ snprintf(filename, PATH_MAX, "%s%s-%s/changelog", _alpm_db_path(handle->db_local), newpkg->name, newpkg->version); archive_entry_set_perm(entry, 0644); } else if(strcmp(entryname, ".MTREE") == 0) { /* the mtree file goes inside the db */ snprintf(filename, PATH_MAX, "%s%s-%s/mtree", _alpm_db_path(handle->db_local), newpkg->name, newpkg->version); archive_entry_set_perm(entry, 0644); } else if(*entryname == '.') { /* for now, ignore all files starting with '.' that haven't * already been handled (for future possibilities) */ _alpm_log(handle, ALPM_LOG_DEBUG, "skipping extraction of '%s'\n", entryname); archive_read_data_skip(archive); return 0; } else { /* build the new entryname relative to handle->root */ snprintf(filename, PATH_MAX, "%s%s", handle->root, entryname); } /* if a file is in NoExtract then we never extract it */ if(_alpm_fnmatch_patterns(handle->noextract, entryname) == 0) { _alpm_log(handle, ALPM_LOG_DEBUG, "%s is in NoExtract," " skipping extraction of %s\n", entryname, filename); alpm_logaction(handle, ALPM_CALLER_PREFIX, "note: %s is in NoExtract, skipping extraction\n", entryname); archive_read_data_skip(archive); return 0; } /* Check for file existence. This is one of the more crucial parts * to get 'right'. Here are the possibilities, with the filesystem * on the left and the package on the top: * (F=file, N=node, S=symlink, D=dir) * | F/N | D * non-existent | 1 | 2 * F/N | 3 | 4 * D | 5 | 6 * * 1,2- extract, no magic necessary. lstat (_alpm_lstat) will fail here. * 3,4- conflict checks should have caught this. either overwrite * or backup the file. * 5- file replacing directory- don't allow it. * 6- skip extraction, dir already exists. */ struct stat lsbuf; if(_alpm_lstat(filename, &lsbuf) != 0) { /* cases 1,2: file doesn't exist, skip all backup checks */ } else { if(S_ISDIR(lsbuf.st_mode)) { if(S_ISDIR(entrymode)) { uid_t entryuid = archive_entry_uid(entry); gid_t entrygid = archive_entry_gid(entry); /* case 6: existing dir, ignore it */ if(lsbuf.st_mode != entrymode) { /* if filesystem perms are different than pkg perms, warn user */ mode_t mask = 07777; _alpm_log(handle, ALPM_LOG_WARNING, _("directory permissions differ on %s\n" "filesystem: %o package: %o\n"), filename, lsbuf.st_mode & mask, entrymode & mask); alpm_logaction(handle, ALPM_CALLER_PREFIX, "warning: directory permissions differ on %s\n" "filesystem: %o package: %o\n", filename, lsbuf.st_mode & mask, entrymode & mask); } if((entryuid != lsbuf.st_uid) || (entrygid != lsbuf.st_gid)) { _alpm_log(handle, ALPM_LOG_WARNING, _("directory ownership differs on %s\n" "filesystem: %u:%u package: %u:%u\n"), filename, lsbuf.st_uid, lsbuf.st_gid, entryuid, entrygid); alpm_logaction(handle, ALPM_CALLER_PREFIX, "warning: directory ownership differs on %s\n" "filesystem: %u:%u package: %u:%u\n", filename, lsbuf.st_uid, lsbuf.st_gid, entryuid, entrygid); } _alpm_log(handle, ALPM_LOG_DEBUG, "extract: skipping dir extraction of %s\n", filename); archive_read_data_skip(archive); return 0; } else { /* case 5: trying to overwrite dir with file, don't allow it */ _alpm_log(handle, ALPM_LOG_ERROR, _("extract: not overwriting dir with file %s\n"), filename); archive_read_data_skip(archive); return 1; } } else if(S_ISDIR(entrymode)) { /* case 4: trying to overwrite file with dir */ _alpm_log(handle, ALPM_LOG_DEBUG, "extract: overwriting file with dir %s\n", filename); } else { /* case 3: */ /* if file is in NoUpgrade, don't touch it */ if(_alpm_fnmatch_patterns(handle->noupgrade, entryname) == 0) { notouch = 1; } else { alpm_backup_t *backup; /* go to the backup array and see if our conflict is there */ /* check newpkg first, so that adding backup files is retroactive */ backup = _alpm_needbackup(entryname, newpkg); if(backup) { needbackup = 1; } /* check oldpkg for a backup entry, store the hash if available */ if(oldpkg) { backup = _alpm_needbackup(entryname, oldpkg); if(backup) { hash_orig = backup->hash; needbackup = 1; } } } } } /* we need access to the original entryname later after calls to * archive_entry_set_pathname(), so we need to dupe it and free() later */ STRDUP(entryname_orig, entryname, RET_ERR(handle, ALPM_ERR_MEMORY, -1)); if(needbackup) { char *checkfile; char *hash_local = NULL, *hash_pkg = NULL; size_t len; len = strlen(filename) + 10; MALLOC(checkfile, len, errors++; handle->pm_errno = ALPM_ERR_MEMORY; goto needbackup_cleanup); snprintf(checkfile, len, "%s.paccheck", filename); if(perform_extraction(handle, archive, entry, checkfile, entryname_orig)) { errors++; goto needbackup_cleanup; } hash_local = alpm_compute_md5sum(filename); hash_pkg = alpm_compute_md5sum(checkfile); /* update the md5 hash in newpkg's backup (it will be the new original) */ alpm_list_t *i; for(i = alpm_pkg_get_backup(newpkg); i; i = i->next) { alpm_backup_t *backup = i->data; char *newhash; if(!backup->name || strcmp(backup->name, entryname_orig) != 0) { continue; } STRDUP(newhash, hash_pkg, RET_ERR(handle, ALPM_ERR_MEMORY, -1)); FREE(backup->hash); backup->hash = newhash; } _alpm_log(handle, ALPM_LOG_DEBUG, "checking hashes for %s\n", entryname_orig); _alpm_log(handle, ALPM_LOG_DEBUG, "current: %s\n", hash_local); _alpm_log(handle, ALPM_LOG_DEBUG, "new: %s\n", hash_pkg); _alpm_log(handle, ALPM_LOG_DEBUG, "original: %s\n", hash_orig); if(hash_local && hash_pkg && strcmp(hash_local, hash_pkg) == 0) { /* local and new files are the same, updating anyway to get * correct timestamps */ _alpm_log(handle, ALPM_LOG_DEBUG, "action: installing new file: %s\n", entryname_orig); if(try_rename(handle, checkfile, filename)) { errors++; } } else if(hash_orig && hash_pkg && strcmp(hash_orig, hash_pkg) == 0) { /* original and new files are the same, leave the local version alone, * including any user changes */ _alpm_log(handle, ALPM_LOG_DEBUG, "action: leaving existing file in place\n"); unlink(checkfile); } else if(hash_orig && hash_local && strcmp(hash_orig, hash_local) == 0) { /* installed file has NOT been changed by user, * update to the new version */ _alpm_log(handle, ALPM_LOG_DEBUG, "action: installing new file: %s\n", entryname_orig); if(try_rename(handle, checkfile, filename)) { errors++; } } else { /* none of the three files matched another, unpack the new file alongside * the local file */ if(oldpkg) { char *newpath; size_t newlen = strlen(filename) + strlen(".pacnew") + 1; _alpm_log(handle, ALPM_LOG_DEBUG, "action: keeping current file and installing" " new one with .pacnew ending\n"); MALLOC(newpath, newlen, errors++; handle->pm_errno = ALPM_ERR_MEMORY; goto needbackup_cleanup); snprintf(newpath, newlen, "%s.pacnew", filename); if(try_rename(handle, checkfile, newpath)) { errors++; } else { _alpm_log(handle, ALPM_LOG_WARNING, _("%s installed as %s\n"), filename, newpath); alpm_logaction(handle, ALPM_CALLER_PREFIX, "warning: %s installed as %s\n", filename, newpath); } free(newpath); } else { char *newpath; size_t newlen = strlen(filename) + strlen(".pacorig") + 1; _alpm_log(handle, ALPM_LOG_DEBUG, "action: saving existing file with a .pacorig ending" " and installing a new one\n"); MALLOC(newpath, newlen, errors++; handle->pm_errno = ALPM_ERR_MEMORY; goto needbackup_cleanup); snprintf(newpath, newlen, "%s.pacorig", filename); /* move the existing file to the "pacorig" */ if(try_rename(handle, filename, newpath)) { errors++; /* failed rename filename -> filename.pacorig */ errors++; /* failed rename checkfile -> filename */ } else { /* rename the file we extracted to the real name */ if(try_rename(handle, checkfile, filename)) { errors++; } else { _alpm_log(handle, ALPM_LOG_WARNING, _("%s saved as %s\n"), filename, newpath); alpm_logaction(handle, ALPM_CALLER_PREFIX, "warning: %s saved as %s\n", filename, newpath); } } free(newpath); } } needbackup_cleanup: free(checkfile); free(hash_local); free(hash_pkg); } else {
int _alpm_runscriptlet(const char *root, const char *installfn, const char *script, const char *ver, const char *oldver, pmtrans_t *trans) { char scriptfn[PATH_MAX]; char cmdline[PATH_MAX]; char tmpdir[PATH_MAX]; char cwd[PATH_MAX]; char *scriptpath; pid_t pid; int clean_tmpdir = 0; int restore_cwd = 0; int retval = 0; ALPM_LOG_FUNC; if(access(installfn, R_OK)) { /* not found */ _alpm_log(PM_LOG_DEBUG, "scriptlet '%s' not found\n", installfn); return(0); } /* NOTE: popen will use the PARENT's /bin/sh, not the chroot's */ if(access("/bin/sh", X_OK)) { /* not found */ _alpm_log(PM_LOG_ERROR, _("No /bin/sh in parent environment, aborting scriptlet\n")); return(0); } /* creates a directory in $root/tmp/ for copying/extracting the scriptlet */ snprintf(tmpdir, PATH_MAX, "%stmp/", root); if(access(tmpdir, F_OK) != 0) { _alpm_makepath_mode(tmpdir, 01777); } snprintf(tmpdir, PATH_MAX, "%stmp/alpm_XXXXXX", root); if(mkdtemp(tmpdir) == NULL) { _alpm_log(PM_LOG_ERROR, _("could not create temp directory\n")); return(1); } else { clean_tmpdir = 1; } /* either extract or copy the scriptlet */ snprintf(scriptfn, PATH_MAX, "%s/.INSTALL", tmpdir); if(!strcmp(script, "pre_upgrade") || !strcmp(script, "pre_install")) { if(_alpm_unpack(installfn, tmpdir, ".INSTALL")) { retval = 1; } } else { if(_alpm_copyfile(installfn, scriptfn)) { _alpm_log(PM_LOG_ERROR, _("could not copy tempfile to %s (%s)\n"), scriptfn, strerror(errno)); retval = 1; } } if(retval == 1) { goto cleanup; } /* chop off the root so we can find the tmpdir in the chroot */ scriptpath = scriptfn + strlen(root) - 1; if(!grep(scriptfn, script)) { /* script not found in scriptlet file */ goto cleanup; } /* save the cwd so we can restore it later */ if(getcwd(cwd, PATH_MAX) == NULL) { _alpm_log(PM_LOG_ERROR, _("could not get current working directory\n")); } else { restore_cwd = 1; } /* just in case our cwd was removed in the upgrade operation */ if(chdir(root) != 0) { _alpm_log(PM_LOG_ERROR, _("could not change directory to %s (%s)\n"), root, strerror(errno)); goto cleanup; } _alpm_log(PM_LOG_DEBUG, "executing %s script...\n", script); if(oldver) { snprintf(cmdline, PATH_MAX, ". %s; %s %s %s", scriptpath, script, ver, oldver); } else { snprintf(cmdline, PATH_MAX, ". %s; %s %s", scriptpath, script, ver); } _alpm_log(PM_LOG_DEBUG, "%s\n", cmdline); /* fork- parent and child each have seperate code blocks below */ pid = fork(); if(pid == -1) { _alpm_log(PM_LOG_ERROR, _("could not fork a new process (%s)\n"), strerror(errno)); retval = 1; goto cleanup; } if(pid == 0) { FILE *pipe; /* this code runs for the child only (the actual chroot/exec) */ _alpm_log(PM_LOG_DEBUG, "chrooting in %s\n", root); if(chroot(root) != 0) { _alpm_log(PM_LOG_ERROR, _("could not change the root directory (%s)\n"), strerror(errno)); exit(1); } if(chdir("/") != 0) { _alpm_log(PM_LOG_ERROR, _("could not change directory to / (%s)\n"), strerror(errno)); exit(1); } umask(0022); _alpm_log(PM_LOG_DEBUG, "executing \"%s\"\n", cmdline); /* execl("/bin/sh", "sh", "-c", cmdline, (char *)NULL); */ pipe = popen(cmdline, "r"); if(!pipe) { _alpm_log(PM_LOG_ERROR, _("call to popen failed (%s)"), strerror(errno)); exit(1); } while(!feof(pipe)) { char line[PATH_MAX]; if(fgets(line, PATH_MAX, pipe) == NULL) break; alpm_logaction("%s", line); EVENT(trans, PM_TRANS_EVT_SCRIPTLET_INFO, line, NULL); } retval = pclose(pipe); exit(WEXITSTATUS(retval)); } else { /* this code runs for the parent only (wait on the child) */ pid_t retpid; int status; while((retpid = waitpid(pid, &status, 0)) == -1 && errno == EINTR); if(retpid == -1) { _alpm_log(PM_LOG_ERROR, _("call to waitpid failed (%s)\n"), strerror(errno)); retval = 1; goto cleanup; } else { /* check the return status, make sure it is 0 (success) */ if(WIFEXITED(status)) { _alpm_log(PM_LOG_DEBUG, "call to waitpid succeeded\n"); if(WEXITSTATUS(status) != 0) { _alpm_log(PM_LOG_ERROR, _("scriptlet failed to execute correctly\n")); retval = 1; } } } } cleanup: if(clean_tmpdir && _alpm_rmrf(tmpdir)) { _alpm_log(PM_LOG_WARNING, _("could not remove tmpdir %s\n"), tmpdir); } if(restore_cwd) { chdir(cwd); } return(retval); }
/* callback to handle messages/notifications from libalpm transactions */ void cb_trans_evt(pmtransevt_t event, void *data1, void *data2) { switch(event) { case PM_TRANS_EVT_CHECKDEPS_START: printf(_("checking dependencies...\n")); break; case PM_TRANS_EVT_FILECONFLICTS_START: if(config->noprogressbar) { printf(_("checking for file conflicts...\n")); } break; case PM_TRANS_EVT_RESOLVEDEPS_START: printf(_("resolving dependencies...\n")); break; case PM_TRANS_EVT_INTERCONFLICTS_START: printf(_("looking for inter-conflicts...\n")); break; case PM_TRANS_EVT_ADD_START: if(config->noprogressbar) { printf(_("installing %s...\n"), alpm_pkg_get_name(data1)); } break; case PM_TRANS_EVT_ADD_DONE: alpm_logaction(config->handle, "installed %s (%s)\n", alpm_pkg_get_name(data1), alpm_pkg_get_version(data1)); display_optdepends(data1); break; case PM_TRANS_EVT_REMOVE_START: if(config->noprogressbar) { printf(_("removing %s...\n"), alpm_pkg_get_name(data1)); } break; case PM_TRANS_EVT_REMOVE_DONE: alpm_logaction(config->handle, "removed %s (%s)\n", alpm_pkg_get_name(data1), alpm_pkg_get_version(data1)); break; case PM_TRANS_EVT_UPGRADE_START: if(config->noprogressbar) { printf(_("upgrading %s...\n"), alpm_pkg_get_name(data1)); } break; case PM_TRANS_EVT_UPGRADE_DONE: alpm_logaction(config->handle, "upgraded %s (%s -> %s)\n", (char *)alpm_pkg_get_name(data1), (char *)alpm_pkg_get_version(data2), (char *)alpm_pkg_get_version(data1)); display_new_optdepends(data2,data1); break; case PM_TRANS_EVT_INTEGRITY_START: if(config->noprogressbar) { printf(_("checking package integrity...\n")); } break; case PM_TRANS_EVT_DELTA_INTEGRITY_START: printf(_("checking delta integrity...\n")); break; case PM_TRANS_EVT_DELTA_PATCHES_START: printf(_("applying deltas...\n")); break; case PM_TRANS_EVT_DELTA_PATCH_START: printf(_("generating %s with %s... "), (char *)data1, (char *)data2); break; case PM_TRANS_EVT_DELTA_PATCH_DONE: printf(_("success!\n")); break; case PM_TRANS_EVT_DELTA_PATCH_FAILED: printf(_("failed.\n")); break; case PM_TRANS_EVT_SCRIPTLET_INFO: printf("%s", (char *)data1); break; case PM_TRANS_EVT_RETRIEVE_START: printf(_(":: Retrieving packages from %s...\n"), (char *)data1); break; case PM_TRANS_EVT_DISKSPACE_START: if(config->noprogressbar) { printf(_("checking available disk space...\n")); } break; /* all the simple done events, with fallthrough for each */ case PM_TRANS_EVT_FILECONFLICTS_DONE: case PM_TRANS_EVT_CHECKDEPS_DONE: case PM_TRANS_EVT_RESOLVEDEPS_DONE: case PM_TRANS_EVT_INTERCONFLICTS_DONE: case PM_TRANS_EVT_INTEGRITY_DONE: case PM_TRANS_EVT_DELTA_INTEGRITY_DONE: case PM_TRANS_EVT_DELTA_PATCHES_DONE: case PM_TRANS_EVT_DISKSPACE_DONE: /* nothing */ break; } fflush(stdout); }
static void pacman_transaction_event_cb (pmtransevt_t event, gpointer data1, gpointer data2) { PacmanTransaction *transaction; g_return_if_fail (pacman_manager != NULL); transaction = pacman_manager_get_transaction (pacman_manager); g_return_if_fail (transaction != NULL); switch (event) { case PM_TRANS_EVT_CHECKDEPS_START: { pacman_transaction_tell (transaction, PACMAN_TRANSACTION_STATUS_DEPENDENCY_CHECK_START, _("Checking dependencies")); break; } case PM_TRANS_EVT_CHECKDEPS_DONE: { pacman_transaction_tell (transaction, PACMAN_TRANSACTION_STATUS_DEPENDENCY_CHECK_END, _("Finished checking dependencies")); break; } case PM_TRANS_EVT_FILECONFLICTS_START: { pacman_transaction_tell (transaction, PACMAN_TRANSACTION_STATUS_FILE_CONFLICT_CHECK_START, _("Checking for file conflicts")); break; } case PM_TRANS_EVT_FILECONFLICTS_DONE: { pacman_transaction_tell (transaction, PACMAN_TRANSACTION_STATUS_FILE_CONFLICT_CHECK_END, _("Finished checking for file conflicts")); break; } case PM_TRANS_EVT_RESOLVEDEPS_START: { pacman_transaction_tell (transaction, PACMAN_TRANSACTION_STATUS_DEPENDENCY_RESOLVE_START, _("Resolving dependencies")); break; } case PM_TRANS_EVT_RESOLVEDEPS_DONE: { pacman_transaction_tell (transaction, PACMAN_TRANSACTION_STATUS_DEPENDENCY_RESOLVE_END, _("Finished resolving dependencies")); break; } case PM_TRANS_EVT_INTERCONFLICTS_START: { pacman_transaction_tell (transaction, PACMAN_TRANSACTION_STATUS_CONFLICT_CHECK_START, _("Checking for conflicts")); break; } case PM_TRANS_EVT_INTERCONFLICTS_DONE: { pacman_transaction_tell (transaction, PACMAN_TRANSACTION_STATUS_CONFLICT_CHECK_END, _("Finished checking for conflicts")); break; } case PM_TRANS_EVT_ADD_START: { pacman_transaction_set_marked_packages (transaction, pacman_list_add (NULL, data1)); pacman_transaction_tell (transaction, PACMAN_TRANSACTION_STATUS_INSTALL_START, _("Installing %s"), pacman_package_get_name ((PacmanPackage *) data1)); pacman_transaction_set_marked_packages (transaction, NULL); break; } case PM_TRANS_EVT_ADD_DONE: { PacmanPackage *package = (PacmanPackage *) data1; const PacmanList *optional_dependencies, *i; alpm_logaction ("installed %s (%s)\n", pacman_package_get_name (package), pacman_package_get_version (package)); pacman_transaction_set_marked_packages (transaction, pacman_list_add (NULL, data1)); pacman_transaction_tell (transaction, PACMAN_TRANSACTION_STATUS_INSTALL_END, _("Finished installing %s"), pacman_package_get_name (package)); pacman_transaction_set_marked_packages (transaction, NULL); optional_dependencies = pacman_package_get_optional_dependencies (package); if (optional_dependencies != NULL) { GString *depends = g_string_new (""); gchar *message; g_string_append_printf (depends, _("Optional dependencies for %s:\n"), pacman_package_get_name (package)); for (i = optional_dependencies; i != NULL; i = pacman_list_next (i)) { const gchar *line = (const gchar *) pacman_list_get (i); g_string_append_printf (depends, "%s\n", line); } message = g_string_free (depends, FALSE); g_message ("%s", message); g_free (message); } break; } case PM_TRANS_EVT_REMOVE_START: { pacman_transaction_set_marked_packages (transaction, pacman_list_add (NULL, data1)); pacman_transaction_tell (transaction, PACMAN_TRANSACTION_STATUS_REMOVE_START, _("Removing %s"), pacman_package_get_name ((PacmanPackage *) data1)); pacman_transaction_set_marked_packages (transaction, NULL); break; } case PM_TRANS_EVT_REMOVE_DONE: { PacmanPackage *package = (PacmanPackage *) data1; alpm_logaction ("removed %s (%s)\n", pacman_package_get_name (package), pacman_package_get_version (package)); pacman_transaction_set_marked_packages (transaction, pacman_list_add (NULL, data1)); pacman_transaction_tell (transaction, PACMAN_TRANSACTION_STATUS_REMOVE_END, _("Finished removing %s"), pacman_package_get_name (package)); pacman_transaction_set_marked_packages (transaction, NULL); break; } case PM_TRANS_EVT_UPGRADE_START: { PacmanList *new_then_old = NULL; new_then_old = pacman_list_add (new_then_old, data1); new_then_old = pacman_list_add (new_then_old, data2); pacman_transaction_set_marked_packages (transaction, new_then_old); pacman_transaction_tell (transaction, PACMAN_TRANSACTION_STATUS_UPGRADE_START, _("Upgrading %s"), pacman_package_get_name ((PacmanPackage *) data1)); pacman_transaction_set_marked_packages (transaction, NULL); break; } case PM_TRANS_EVT_UPGRADE_DONE: { PacmanPackage *package = (PacmanPackage *) data1, *old_package = (PacmanPackage *) data2; PacmanList *optional_dependencies, *i, *new_then_old = NULL; alpm_logaction ("upgraded %s (%s -> %s)\n", pacman_package_get_name (package), pacman_package_get_version (old_package), pacman_package_get_version (package)); new_then_old = pacman_list_add (new_then_old, data1); new_then_old = pacman_list_add (new_then_old, data2); pacman_transaction_set_marked_packages (transaction, new_then_old); pacman_transaction_tell (transaction, PACMAN_TRANSACTION_STATUS_UPGRADE_END, _("Finished upgrading %s"), pacman_package_get_name (package)); pacman_transaction_set_marked_packages (transaction, NULL); optional_dependencies = pacman_list_diff (pacman_package_get_optional_dependencies (package), pacman_package_get_optional_dependencies (old_package), (GCompareFunc) g_strcmp0); if (optional_dependencies != NULL) { GString *depends = g_string_new (""); gchar *message; g_string_append_printf (depends, _("New optional dependencies for %s\n"), pacman_package_get_name (package)); for (i = optional_dependencies; i != NULL; i = pacman_list_next (i)) { const gchar *line = (const gchar *) pacman_list_get (i); g_string_append_printf (depends, "%s\n", line); } message = g_string_free (depends, FALSE); g_message ("%s", message); g_free (message); pacman_list_free (optional_dependencies); } break; } case PM_TRANS_EVT_INTEGRITY_START: { pacman_transaction_tell (transaction, PACMAN_TRANSACTION_STATUS_PACKAGE_INTEGRITY_CHECK_START, _("Checking package integrity")); break; } case PM_TRANS_EVT_INTEGRITY_DONE: { pacman_transaction_tell (transaction, PACMAN_TRANSACTION_STATUS_PACKAGE_INTEGRITY_CHECK_END, _("Finished checking package integrity")); break; } case PM_TRANS_EVT_DELTA_INTEGRITY_START: { pacman_transaction_tell (transaction, PACMAN_TRANSACTION_STATUS_DELTA_INTEGRITY_CHECK_START, _("Checking delta integrity")); break; } case PM_TRANS_EVT_DELTA_INTEGRITY_DONE: { pacman_transaction_tell (transaction, PACMAN_TRANSACTION_STATUS_DELTA_INTEGRITY_CHECK_END, _("Finished checking delta integrity")); break; } case PM_TRANS_EVT_DELTA_PATCHES_START: { pacman_transaction_tell (transaction, PACMAN_TRANSACTION_STATUS_DELTA_PATCHING_START, _("Applying delta patches")); break; } case PM_TRANS_EVT_DELTA_PATCHES_DONE: { pacman_transaction_tell (transaction, PACMAN_TRANSACTION_STATUS_DELTA_PATCHING_END, _("Finished applying delta patches")); break; } case PM_TRANS_EVT_DELTA_PATCH_START: { pacman_transaction_tell (transaction, PACMAN_TRANSACTION_STATUS_DELTA_PATCH_START, _("Creating %s from the delta patch %s"), (const gchar *) data1, (const gchar *) data2); break; } case PM_TRANS_EVT_DELTA_PATCH_DONE: { pacman_transaction_tell (transaction, PACMAN_TRANSACTION_STATUS_DELTA_PATCH_END, _("Finished applying delta patch")); break; } case PM_TRANS_EVT_DELTA_PATCH_FAILED: { /* already reported as an error */ break; } case PM_TRANS_EVT_SCRIPTLET_INFO: { g_message ("%s\n", (const gchar *) data1); break; } case PM_TRANS_EVT_RETRIEVE_START: { pacman_transaction_tell (transaction, PACMAN_TRANSACTION_STATUS_DOWNLOAD_FROM, _("Downloading packages from [%s]"), (const gchar *) data1); break; } default: { g_debug ("Unrecognised event: %d\n", event); break; } } }