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);
}
示例#3
0
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;
}
示例#4
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);
}
示例#5
0
/** 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;
}
示例#6
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);
}
示例#7
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;
}
示例#8
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;
}
示例#9
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;
	}
}
示例#10
0
文件: files.c 项目: AWhetter/pacman
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);
}
示例#12
0
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;
}
示例#13
0
文件: util.c 项目: sandsmark/pacman
/** 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;
}
示例#14
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 = 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;
}
示例#15
0
/**
 * @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;
}
示例#16
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);
}
示例#17
0
/** 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;
}
示例#18
0
文件: add.c 项目: jhuntwork/pacman
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 {
示例#19
0
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);
}
示例#20
0
文件: callback.c 项目: mineo/pacman
/* 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;
		}
	}
}