mirror of
https://github.com/moparisthebest/pacman
synced 2024-11-10 03:25:01 -05:00
4e6a03c4f6
This code assumed that DBPath was under RootDir, while this is not necessarily the case : pacman doesn't enforce anymore than DBPath is under RootDir. So now, all scriptlets will be put somewhere in RootDir/tmp/, so that when it chroots in RootDir, the scriptlets are still available inside the chroot. This also removes the need of normalizing both dbpath and rootdir, in order to do computation on the paths. Signed-off-by: Chantry Xavier <shiningxc@gmail.com>
711 lines
18 KiB
C
711 lines
18 KiB
C
/*
|
|
* trans.c
|
|
*
|
|
* Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org>
|
|
* Copyright (c) 2005 by Aurelien Foret <orelien@chez.com>
|
|
* Copyright (c) 2005 by Christian Hamar <krics@linuxforum.hu>
|
|
* Copyright (c) 2005, 2006 by Miklos Vajna <vmiklos@frugalware.org>
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
|
* USA.
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <sys/wait.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/statvfs.h>
|
|
#include <unistd.h>
|
|
#include <errno.h>
|
|
|
|
/* libalpm */
|
|
#include "trans.h"
|
|
#include "alpm_list.h"
|
|
#include "error.h"
|
|
#include "package.h"
|
|
#include "util.h"
|
|
#include "log.h"
|
|
#include "handle.h"
|
|
#include "add.h"
|
|
#include "remove.h"
|
|
#include "sync.h"
|
|
#include "alpm.h"
|
|
#include "deps.h"
|
|
#include "cache.h"
|
|
#include "provide.h"
|
|
|
|
/** \addtogroup alpm_trans Transaction Functions
|
|
* @brief Functions to manipulate libalpm transactions
|
|
* @{
|
|
*/
|
|
|
|
/** Initialize the transaction.
|
|
* @param type type of the transaction
|
|
* @param flags flags of the transaction (like nodeps, etc)
|
|
* @param event event callback function pointer
|
|
* @param conv question callback function pointer
|
|
* @param progress progress callback function pointer
|
|
* @return 0 on success, -1 on error (pm_errno is set accordingly)
|
|
*/
|
|
int SYMEXPORT alpm_trans_init(pmtranstype_t type, pmtransflag_t flags,
|
|
alpm_trans_cb_event event, alpm_trans_cb_conv conv,
|
|
alpm_trans_cb_progress progress)
|
|
{
|
|
ALPM_LOG_FUNC;
|
|
|
|
/* Sanity checks */
|
|
ASSERT(handle != NULL, RET_ERR(PM_ERR_HANDLE_NULL, -1));
|
|
|
|
ASSERT(handle->trans == NULL, RET_ERR(PM_ERR_TRANS_NOT_NULL, -1));
|
|
|
|
/* lock db */
|
|
handle->lckfd = _alpm_lckmk();
|
|
if(handle->lckfd == -1) {
|
|
RET_ERR(PM_ERR_HANDLE_LOCK, -1);
|
|
}
|
|
|
|
handle->trans = _alpm_trans_new();
|
|
if(handle->trans == NULL) {
|
|
RET_ERR(PM_ERR_MEMORY, -1);
|
|
}
|
|
|
|
return(_alpm_trans_init(handle->trans, type, flags, event, conv, progress));
|
|
}
|
|
|
|
/** Search for packages to upgrade and add them to the transaction.
|
|
* @return 0 on success, -1 on error (pm_errno is set accordingly)
|
|
*/
|
|
int SYMEXPORT alpm_trans_sysupgrade()
|
|
{
|
|
pmtrans_t *trans;
|
|
|
|
ALPM_LOG_FUNC;
|
|
|
|
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_INITIALIZED, RET_ERR(PM_ERR_TRANS_NOT_INITIALIZED, -1));
|
|
ASSERT(trans->type == PM_TRANS_TYPE_SYNC, RET_ERR(PM_ERR_TRANS_TYPE, -1));
|
|
|
|
return(_alpm_trans_sysupgrade(trans));
|
|
}
|
|
|
|
/** Add a target to the transaction.
|
|
* @param target the name of the target to add
|
|
* @return 0 on success, -1 on error (pm_errno is set accordingly)
|
|
*/
|
|
int SYMEXPORT alpm_trans_addtarget(char *target)
|
|
{
|
|
pmtrans_t *trans;
|
|
|
|
ALPM_LOG_FUNC;
|
|
|
|
/* Sanity checks */
|
|
ASSERT(handle != NULL, RET_ERR(PM_ERR_HANDLE_NULL, -1));
|
|
ASSERT(target != NULL && strlen(target) != 0, RET_ERR(PM_ERR_WRONG_ARGS, -1));
|
|
|
|
trans = handle->trans;
|
|
ASSERT(trans != NULL, RET_ERR(PM_ERR_TRANS_NULL, -1));
|
|
ASSERT(trans->state == STATE_INITIALIZED, RET_ERR(PM_ERR_TRANS_NOT_INITIALIZED, -1));
|
|
|
|
return(_alpm_trans_addtarget(trans, target));
|
|
}
|
|
|
|
/** Prepare a transaction.
|
|
* @param data the address of an alpm_list where detailed description
|
|
* of an error can be dumped (ie. list of conflicting files)
|
|
* @return 0 on success, -1 on error (pm_errno is set accordingly)
|
|
*/
|
|
int SYMEXPORT alpm_trans_prepare(alpm_list_t **data)
|
|
{
|
|
ALPM_LOG_FUNC;
|
|
|
|
/* Sanity checks */
|
|
ASSERT(handle != NULL, RET_ERR(PM_ERR_HANDLE_NULL, -1));
|
|
ASSERT(data != NULL, RET_ERR(PM_ERR_WRONG_ARGS, -1));
|
|
|
|
ASSERT(handle->trans != NULL, RET_ERR(PM_ERR_TRANS_NULL, -1));
|
|
ASSERT(handle->trans->state == STATE_INITIALIZED, RET_ERR(PM_ERR_TRANS_NOT_INITIALIZED, -1));
|
|
|
|
return(_alpm_trans_prepare(handle->trans, data));
|
|
}
|
|
|
|
/** Commit a transaction.
|
|
* @param data the address of an alpm_list where detailed description
|
|
* of an error can be dumped (ie. list of conflicting files)
|
|
* @return 0 on success, -1 on error (pm_errno is set accordingly)
|
|
*/
|
|
int SYMEXPORT alpm_trans_commit(alpm_list_t **data)
|
|
{
|
|
ALPM_LOG_FUNC;
|
|
|
|
/* Sanity checks */
|
|
ASSERT(handle != NULL, RET_ERR(PM_ERR_HANDLE_NULL, -1));
|
|
|
|
ASSERT(handle->trans != NULL, RET_ERR(PM_ERR_TRANS_NULL, -1));
|
|
ASSERT(handle->trans->state == STATE_PREPARED, RET_ERR(PM_ERR_TRANS_NOT_PREPARED, -1));
|
|
|
|
return(_alpm_trans_commit(handle->trans, data));
|
|
}
|
|
|
|
/** Interrupt a transaction.
|
|
* @return 0 on success, -1 on error (pm_errno is set accordingly)
|
|
*/
|
|
int SYMEXPORT alpm_trans_interrupt()
|
|
{
|
|
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_COMMITING || trans->state == STATE_INTERRUPTED,
|
|
RET_ERR(PM_ERR_TRANS_TYPE, -1));
|
|
|
|
trans->state = STATE_INTERRUPTED;
|
|
|
|
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) {
|
|
close(handle->lckfd);
|
|
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",
|
|
alpm_option_get_lockfile());
|
|
}
|
|
|
|
return(0);
|
|
}
|
|
|
|
/** @} */
|
|
|
|
pmtrans_t *_alpm_trans_new()
|
|
{
|
|
pmtrans_t *trans;
|
|
|
|
ALPM_LOG_FUNC;
|
|
|
|
if((trans = malloc(sizeof(pmtrans_t))) == NULL) {
|
|
_alpm_log(PM_LOG_ERROR, _("malloc failure: could not allocate %d bytes\n"), sizeof(pmtrans_t));
|
|
return(NULL);
|
|
}
|
|
|
|
trans->targets = NULL;
|
|
trans->packages = NULL;
|
|
trans->skip_add = NULL;
|
|
trans->skip_remove = NULL;
|
|
trans->type = 0;
|
|
trans->flags = 0;
|
|
trans->cb_event = NULL;
|
|
trans->cb_conv = NULL;
|
|
trans->cb_progress = NULL;
|
|
trans->state = STATE_IDLE;
|
|
|
|
return(trans);
|
|
}
|
|
|
|
void _alpm_trans_free(pmtrans_t *trans)
|
|
{
|
|
ALPM_LOG_FUNC;
|
|
|
|
if(trans == NULL) {
|
|
return;
|
|
}
|
|
|
|
FREELIST(trans->targets);
|
|
if(trans->type == PM_TRANS_TYPE_SYNC) {
|
|
alpm_list_t *i;
|
|
for(i = trans->packages; i; i = alpm_list_next(i)) {
|
|
_alpm_sync_free(i->data);
|
|
i->data = NULL;
|
|
}
|
|
FREELIST(trans->packages);
|
|
} else {
|
|
alpm_list_t *tmp;
|
|
for(tmp = trans->packages; tmp; tmp = alpm_list_next(tmp)) {
|
|
_alpm_pkg_free(tmp->data);
|
|
tmp->data = NULL;
|
|
}
|
|
}
|
|
trans->packages = NULL;
|
|
|
|
FREELIST(trans->skip_add);
|
|
FREELIST(trans->skip_remove);
|
|
|
|
FREE(trans);
|
|
}
|
|
|
|
int _alpm_trans_init(pmtrans_t *trans, pmtranstype_t type, pmtransflag_t flags,
|
|
alpm_trans_cb_event event, alpm_trans_cb_conv conv,
|
|
alpm_trans_cb_progress progress)
|
|
{
|
|
ALPM_LOG_FUNC;
|
|
|
|
/* Sanity checks */
|
|
ASSERT(trans != NULL, RET_ERR(PM_ERR_TRANS_NULL, -1));
|
|
|
|
trans->type = type;
|
|
trans->flags = flags;
|
|
trans->cb_event = event;
|
|
trans->cb_conv = conv;
|
|
trans->cb_progress = progress;
|
|
trans->state = STATE_INITIALIZED;
|
|
|
|
return(0);
|
|
}
|
|
|
|
int _alpm_trans_sysupgrade(pmtrans_t *trans)
|
|
{
|
|
ALPM_LOG_FUNC;
|
|
|
|
/* Sanity checks */
|
|
ASSERT(trans != NULL, RET_ERR(PM_ERR_TRANS_NULL, -1));
|
|
|
|
return(_alpm_sync_sysupgrade(trans, handle->db_local, handle->dbs_sync));
|
|
}
|
|
|
|
/** Add a target to the transaction.
|
|
* @param trans the current transaction
|
|
* @param target the name of the target to add
|
|
* @return 0 on success, -1 on error (pm_errno is set accordingly)
|
|
*/
|
|
int _alpm_trans_addtarget(pmtrans_t *trans, char *target)
|
|
{
|
|
ALPM_LOG_FUNC;
|
|
|
|
/* Sanity checks */
|
|
ASSERT(trans != NULL, RET_ERR(PM_ERR_TRANS_NULL, -1));
|
|
ASSERT(target != NULL, RET_ERR(PM_ERR_WRONG_ARGS, -1));
|
|
|
|
if(alpm_list_find_str(trans->targets, target)) {
|
|
return(0);
|
|
//RET_ERR(PM_ERR_TRANS_DUP_TARGET, -1);
|
|
}
|
|
|
|
switch(trans->type) {
|
|
case PM_TRANS_TYPE_ADD:
|
|
case PM_TRANS_TYPE_UPGRADE:
|
|
if(_alpm_add_loadtarget(trans, handle->db_local, target) == -1) {
|
|
/* pm_errno is set by _alpm_add_loadtarget() */
|
|
return(-1);
|
|
}
|
|
break;
|
|
case PM_TRANS_TYPE_REMOVE:
|
|
case PM_TRANS_TYPE_REMOVEUPGRADE:
|
|
if(_alpm_remove_loadtarget(trans, handle->db_local, target) == -1) {
|
|
/* pm_errno is set by _alpm_remove_loadtarget() */
|
|
return(-1);
|
|
}
|
|
break;
|
|
case PM_TRANS_TYPE_SYNC:
|
|
if(_alpm_sync_addtarget(trans, handle->db_local, handle->dbs_sync, target) == -1) {
|
|
/* pm_errno is set by _alpm_sync_loadtarget() */
|
|
return(-1);
|
|
}
|
|
break;
|
|
}
|
|
|
|
trans->targets = alpm_list_add(trans->targets, strdup(target));
|
|
|
|
return(0);
|
|
}
|
|
|
|
int _alpm_trans_prepare(pmtrans_t *trans, alpm_list_t **data)
|
|
{
|
|
*data = NULL;
|
|
|
|
ALPM_LOG_FUNC;
|
|
|
|
/* Sanity checks */
|
|
ASSERT(trans != NULL, RET_ERR(PM_ERR_TRANS_NULL, -1));
|
|
|
|
/* If there's nothing to do, return without complaining */
|
|
if(trans->packages == NULL) {
|
|
return(0);
|
|
}
|
|
|
|
switch(trans->type) {
|
|
case PM_TRANS_TYPE_ADD:
|
|
case PM_TRANS_TYPE_UPGRADE:
|
|
if(_alpm_add_prepare(trans, handle->db_local, data) == -1) {
|
|
/* pm_errno is set by _alpm_add_prepare() */
|
|
return(-1);
|
|
}
|
|
break;
|
|
case PM_TRANS_TYPE_REMOVE:
|
|
case PM_TRANS_TYPE_REMOVEUPGRADE:
|
|
if(_alpm_remove_prepare(trans, handle->db_local, data) == -1) {
|
|
/* pm_errno is set by _alpm_remove_prepare() */
|
|
return(-1);
|
|
}
|
|
break;
|
|
case PM_TRANS_TYPE_SYNC:
|
|
if(_alpm_sync_prepare(trans, handle->db_local, handle->dbs_sync, data) == -1) {
|
|
/* pm_errno is set by _alpm_sync_prepare() */
|
|
return(-1);
|
|
}
|
|
break;
|
|
}
|
|
|
|
trans->state = STATE_PREPARED;
|
|
|
|
return(0);
|
|
}
|
|
|
|
int _alpm_trans_commit(pmtrans_t *trans, alpm_list_t **data)
|
|
{
|
|
ALPM_LOG_FUNC;
|
|
|
|
if(data!=NULL)
|
|
*data = NULL;
|
|
|
|
/* Sanity checks */
|
|
ASSERT(trans != NULL, RET_ERR(PM_ERR_TRANS_NULL, -1));
|
|
|
|
/* If there's nothing to do, return without complaining */
|
|
if(trans->packages == NULL) {
|
|
return(0);
|
|
}
|
|
|
|
trans->state = STATE_COMMITING;
|
|
|
|
switch(trans->type) {
|
|
case PM_TRANS_TYPE_ADD:
|
|
case PM_TRANS_TYPE_UPGRADE:
|
|
if(_alpm_add_commit(trans, handle->db_local) == -1) {
|
|
/* pm_errno is set by _alpm_add_commit() */
|
|
return(-1);
|
|
}
|
|
break;
|
|
case PM_TRANS_TYPE_REMOVE:
|
|
case PM_TRANS_TYPE_REMOVEUPGRADE:
|
|
if(_alpm_remove_commit(trans, handle->db_local) == -1) {
|
|
/* pm_errno is set by _alpm_remove_commit() */
|
|
return(-1);
|
|
}
|
|
break;
|
|
case PM_TRANS_TYPE_SYNC:
|
|
if(_alpm_sync_commit(trans, handle->db_local, data) == -1) {
|
|
/* pm_errno is set by _alpm_sync_commit() */
|
|
return(-1);
|
|
}
|
|
break;
|
|
}
|
|
|
|
trans->state = STATE_COMMITED;
|
|
|
|
return(0);
|
|
}
|
|
|
|
/* A depends on B through n depends <=> A listed in B's requiredby n times
|
|
* n == 0 or 1 in almost all cases */
|
|
int _alpm_trans_update_depends(pmtrans_t *trans, pmpkg_t *pkg)
|
|
{
|
|
alpm_list_t *i, *j;
|
|
alpm_list_t *depends = NULL;
|
|
const char *pkgname;
|
|
pmdb_t *localdb;
|
|
|
|
ALPM_LOG_FUNC;
|
|
|
|
/* Sanity checks */
|
|
ASSERT(trans != NULL, RET_ERR(PM_ERR_TRANS_NULL, -1));
|
|
ASSERT(pkg != NULL, RET_ERR(PM_ERR_PKG_INVALID, -1));
|
|
|
|
pkgname = alpm_pkg_get_name(pkg);
|
|
depends = alpm_pkg_get_depends(pkg);
|
|
|
|
if(depends) {
|
|
_alpm_log(PM_LOG_DEBUG, "updating dependency packages 'requiredby' fields for %s-%s\n",
|
|
pkgname, pkg->version);
|
|
} else {
|
|
_alpm_log(PM_LOG_DEBUG, "package has no dependencies, no other packages to update\n");
|
|
}
|
|
|
|
localdb = alpm_option_get_localdb();
|
|
for(i = depends; i; i = i->next) {
|
|
if(!i->data) {
|
|
continue;
|
|
}
|
|
pmdepend_t* dep = alpm_splitdep(i->data);
|
|
if(dep == NULL) {
|
|
continue;
|
|
}
|
|
for(j = _alpm_db_get_pkgcache(localdb); j; j = j->next) {
|
|
pmpkg_t *deppkg = j->data;
|
|
if(deppkg && alpm_depcmp(deppkg, dep)) {
|
|
/* this is cheating... we call this function to populate the package */
|
|
alpm_list_t *rqdby = alpm_pkg_get_requiredby(deppkg);
|
|
|
|
_alpm_log(PM_LOG_DEBUG, "updating 'requiredby' field for package '%s'\n",
|
|
alpm_pkg_get_name(deppkg));
|
|
|
|
if(trans->type == PM_TRANS_TYPE_REMOVE
|
|
|| trans->type == PM_TRANS_TYPE_REMOVEUPGRADE) {
|
|
void *data = NULL;
|
|
rqdby = alpm_list_remove(rqdby, pkgname, _alpm_str_cmp, &data);
|
|
FREE(data);
|
|
deppkg->requiredby = rqdby;
|
|
} else {
|
|
rqdby = alpm_list_add(rqdby, strdup(pkgname));
|
|
deppkg->requiredby = rqdby;
|
|
}
|
|
|
|
if(_alpm_db_write(localdb, deppkg, INFRQ_DEPENDS)) {
|
|
_alpm_log(PM_LOG_ERROR, _("could not update 'requiredby' database entry %s-%s\n"),
|
|
alpm_pkg_get_name(deppkg), alpm_pkg_get_version(deppkg));
|
|
}
|
|
}
|
|
}
|
|
FREE(dep);
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
/* A cheap grep for text files, returns 1 if a substring
|
|
* was found in the text file fn, 0 if it wasn't
|
|
*/
|
|
static int grep(const char *fn, const char *needle)
|
|
{
|
|
FILE *fp;
|
|
|
|
if((fp = fopen(fn, "r")) == NULL) {
|
|
return(0);
|
|
}
|
|
while(!feof(fp)) {
|
|
char line[1024];
|
|
fgets(line, 1024, fp);
|
|
if(feof(fp)) {
|
|
continue;
|
|
}
|
|
if(strstr(line, needle)) {
|
|
fclose(fp);
|
|
return(1);
|
|
}
|
|
}
|
|
fclose(fp);
|
|
return(0);
|
|
}
|
|
|
|
int _alpm_runscriptlet(const char *root, const char *installfn,
|
|
const char *script, const char *ver,
|
|
const char *oldver)
|
|
{
|
|
char scriptfn[PATH_MAX];
|
|
char cmdline[PATH_MAX];
|
|
char tmpdir[PATH_MAX] = "";
|
|
char *scriptpath;
|
|
struct stat buf;
|
|
char cwd[PATH_MAX] = "";
|
|
pid_t pid;
|
|
int retval = 0;
|
|
|
|
ALPM_LOG_FUNC;
|
|
|
|
if(stat(installfn, &buf)) {
|
|
/* not found */
|
|
_alpm_log(PM_LOG_DEBUG, "scriptlet '%s' not found\n", installfn);
|
|
return(0);
|
|
}
|
|
|
|
snprintf(tmpdir, PATH_MAX, "%sbin/sh", root);
|
|
if(stat(tmpdir, &buf)) {
|
|
/* not found */
|
|
_alpm_log(PM_LOG_ERROR, _("No /bin/sh in root dir (%s), aborting scriptlet\n"), root);
|
|
return(0);
|
|
}
|
|
|
|
/* creates a directory in $root/tmp/ for copying/extracting the scriptlet */
|
|
snprintf(tmpdir, PATH_MAX, "%stmp/", root);
|
|
if(stat(tmpdir, &buf)) {
|
|
_alpm_makepath(tmpdir);
|
|
}
|
|
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);
|
|
}
|
|
|
|
/* either extract or copy the scriptlet */
|
|
snprintf(scriptfn, PATH_MAX, "%s/.INSTALL", tmpdir);
|
|
if(!strcmp(script, "pre_upgrade") || !strcmp(script, "pre_install")) {
|
|
_alpm_unpack(installfn, tmpdir, ".INSTALL");
|
|
} else {
|
|
if(_alpm_copyfile(installfn, scriptfn)) {
|
|
_alpm_log(PM_LOG_ERROR, _("could not copy tempfile to %s (%s)\n"), scriptfn, strerror(errno));
|
|
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"));
|
|
/* in case of error, cwd content is undefined: so we set it to something */
|
|
cwd[0] = 0;
|
|
}
|
|
|
|
/* 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, "source %s %s %s %s",
|
|
scriptpath, script, ver, oldver);
|
|
} else {
|
|
snprintf(cmdline, PATH_MAX, "source %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) {
|
|
/* 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);
|
|
exit(0);
|
|
} else {
|
|
/* this code runs for the parent only (wait on the child) */
|
|
pid_t retpid;
|
|
int status;
|
|
retpid = waitpid(pid, &status, 0);
|
|
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(strlen(tmpdir) && _alpm_rmrf(tmpdir)) {
|
|
_alpm_log(PM_LOG_WARNING, _("could not remove tmpdir %s\n"), tmpdir);
|
|
}
|
|
if(strlen(cwd)) {
|
|
chdir(cwd);
|
|
}
|
|
|
|
return(retval);
|
|
}
|
|
|
|
pmtranstype_t SYMEXPORT alpm_trans_get_type()
|
|
{
|
|
/* Sanity checks */
|
|
ASSERT(handle != NULL, return(-1));
|
|
ASSERT(handle->trans != NULL, return(-1));
|
|
|
|
return handle->trans->type;
|
|
}
|
|
|
|
unsigned int SYMEXPORT alpm_trans_get_flags()
|
|
{
|
|
/* Sanity checks */
|
|
ASSERT(handle != NULL, return(-1));
|
|
ASSERT(handle->trans != NULL, return(-1));
|
|
|
|
return handle->trans->flags;
|
|
}
|
|
|
|
alpm_list_t SYMEXPORT * alpm_trans_get_targets()
|
|
{
|
|
/* Sanity checks */
|
|
ASSERT(handle != NULL, return(NULL));
|
|
ASSERT(handle->trans != NULL, return(NULL));
|
|
|
|
return handle->trans->targets;
|
|
}
|
|
|
|
alpm_list_t SYMEXPORT * alpm_trans_get_pkgs()
|
|
{
|
|
/* Sanity checks */
|
|
ASSERT(handle != NULL, return(NULL));
|
|
ASSERT(handle->trans != NULL, return(NULL));
|
|
|
|
return handle->trans->packages;
|
|
}
|
|
/* vim: set ts=2 sw=2 noet: */
|