660 lines
13 KiB
Plaintext
660 lines
13 KiB
Plaintext
#include <stdio.h>
|
|
#include "rpmlib.h"
|
|
#include "rpmcli.h"
|
|
|
|
#ifdef RPM2_RPM41
|
|
#include "rpmts.h"
|
|
#include "rpmte.h"
|
|
#endif
|
|
|
|
#include "header.h"
|
|
#include "rpmdb.h"
|
|
#include "misc.h"
|
|
|
|
#include "EXTERN.h"
|
|
#include "perl.h"
|
|
#include "XSUB.h"
|
|
|
|
#if !defined(RPM2_RPM41) && !defined(RPM2_RPM40)
|
|
#error Must define one of RPM2_RPM41 or RPM2_RPM40; perhaps Makefile.PL could not guess your RPM API version?
|
|
#endif
|
|
|
|
/* Chip, this is somewhat stripped down from the default callback used by
|
|
the rpmcli. It has to be here to insure that we open the pkg again.
|
|
If we don't do this we get segfaults. I also, kept the updating of some
|
|
of the rpmcli static vars, but I may not have needed to do this.
|
|
|
|
Also, we probably want to give a nice interface such that we could allow
|
|
users of RPM2 to do their own callback, but that will have to come later.
|
|
*/
|
|
void * _null_callback(
|
|
const void * arg,
|
|
const rpmCallbackType what,
|
|
const unsigned long amount,
|
|
const unsigned long total,
|
|
fnpyKey key,
|
|
rpmCallbackData data)
|
|
{
|
|
Header h = (Header) arg;
|
|
char * s;
|
|
int flags = (int) ((long)data);
|
|
void * rc = NULL;
|
|
const char * filename = (const char *)key;
|
|
static FD_t fd = NULL;
|
|
int xx;
|
|
|
|
/* Code stolen from rpminstall.c and modified */
|
|
switch(what) {
|
|
case RPMCALLBACK_INST_OPEN_FILE:
|
|
if (filename == NULL || filename[0] == '\0')
|
|
return NULL;
|
|
fd = Fopen(filename, "r.ufdio");
|
|
/* FIX: still necessary? */
|
|
if (fd == NULL || Ferror(fd)) {
|
|
fprintf(stderr, "open of %s failed!\n", filename);
|
|
if (fd != NULL) {
|
|
xx = Fclose(fd);
|
|
fd = NULL;
|
|
}
|
|
} else
|
|
fd = fdLink(fd, "persist (showProgress)");
|
|
return (void *)fd;
|
|
break;
|
|
|
|
case RPMCALLBACK_INST_CLOSE_FILE:
|
|
/* FIX: still necessary? */
|
|
fd = fdFree(fd, "persist (showProgress)");
|
|
if (fd != NULL) {
|
|
xx = Fclose(fd);
|
|
fd = NULL;
|
|
}
|
|
break;
|
|
|
|
case RPMCALLBACK_INST_START:
|
|
rpmcliHashesCurrent = 0;
|
|
if (h == NULL || !(flags & INSTALL_LABEL))
|
|
break;
|
|
break;
|
|
|
|
case RPMCALLBACK_TRANS_PROGRESS:
|
|
case RPMCALLBACK_INST_PROGRESS:
|
|
break;
|
|
|
|
case RPMCALLBACK_TRANS_START:
|
|
rpmcliHashesCurrent = 0;
|
|
rpmcliProgressTotal = 1;
|
|
rpmcliProgressCurrent = 0;
|
|
break;
|
|
|
|
case RPMCALLBACK_TRANS_STOP:
|
|
rpmcliProgressTotal = rpmcliPackagesTotal;
|
|
rpmcliProgressCurrent = 0;
|
|
break;
|
|
|
|
case RPMCALLBACK_REPACKAGE_START:
|
|
rpmcliHashesCurrent = 0;
|
|
rpmcliProgressTotal = total;
|
|
rpmcliProgressCurrent = 0;
|
|
break;
|
|
|
|
case RPMCALLBACK_REPACKAGE_PROGRESS:
|
|
break;
|
|
|
|
case RPMCALLBACK_REPACKAGE_STOP:
|
|
rpmcliProgressTotal = total;
|
|
rpmcliProgressCurrent = total;
|
|
rpmcliProgressTotal = rpmcliPackagesTotal;
|
|
rpmcliProgressCurrent = 0;
|
|
break;
|
|
|
|
case RPMCALLBACK_UNINST_PROGRESS:
|
|
break;
|
|
case RPMCALLBACK_UNINST_START:
|
|
break;
|
|
case RPMCALLBACK_UNINST_STOP:
|
|
break;
|
|
case RPMCALLBACK_UNPACK_ERROR:
|
|
break;
|
|
case RPMCALLBACK_CPIO_ERROR:
|
|
break;
|
|
case RPMCALLBACK_UNKNOWN:
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
void
|
|
_populate_header_tags(HV *href)
|
|
{
|
|
int i = 0;
|
|
|
|
for (i = 0; i < rpmTagTableSize; i++) {
|
|
hv_store(href, rpmTagTable[i].name, strlen(rpmTagTable[i].name), newSViv(rpmTagTable[i].val), 0);
|
|
}
|
|
}
|
|
|
|
void
|
|
_populate_constant(HV *href, char *name, int val)
|
|
{
|
|
hv_store(href, name, strlen(name), newSViv(val), 0);
|
|
}
|
|
|
|
#define REGISTER_CONSTANT(name) _populate_constant(constants, #name, name)
|
|
|
|
MODULE = RPM2 PACKAGE = RPM2
|
|
|
|
PROTOTYPES: ENABLE
|
|
BOOT:
|
|
{
|
|
HV *header_tags, *constants;
|
|
rpmReadConfigFiles(NULL, NULL);
|
|
|
|
header_tags = perl_get_hv("RPM2::header_tag_map", TRUE);
|
|
_populate_header_tags(header_tags);
|
|
|
|
constants = perl_get_hv("RPM2::constants", TRUE);
|
|
|
|
/* not the 'standard' way of doing perl constants, but a lot easier to maintain */
|
|
#ifdef RPM2_RPM41
|
|
REGISTER_CONSTANT(RPMVSF_DEFAULT);
|
|
REGISTER_CONSTANT(RPMVSF_NOHDRCHK);
|
|
REGISTER_CONSTANT(RPMVSF_NEEDPAYLOAD);
|
|
REGISTER_CONSTANT(RPMVSF_NOSHA1HEADER);
|
|
REGISTER_CONSTANT(RPMVSF_NOMD5HEADER);
|
|
REGISTER_CONSTANT(RPMVSF_NODSAHEADER);
|
|
REGISTER_CONSTANT(RPMVSF_NORSAHEADER);
|
|
REGISTER_CONSTANT(RPMVSF_NOSHA1);
|
|
REGISTER_CONSTANT(RPMVSF_NOMD5);
|
|
REGISTER_CONSTANT(RPMVSF_NODSA);
|
|
REGISTER_CONSTANT(RPMVSF_NORSA);
|
|
REGISTER_CONSTANT(_RPMVSF_NODIGESTS);
|
|
REGISTER_CONSTANT(_RPMVSF_NOSIGNATURES);
|
|
REGISTER_CONSTANT(_RPMVSF_NOHEADER);
|
|
REGISTER_CONSTANT(_RPMVSF_NOPAYLOAD);
|
|
REGISTER_CONSTANT(TR_ADDED);
|
|
REGISTER_CONSTANT(TR_REMOVED);
|
|
#endif
|
|
|
|
REGISTER_CONSTANT(RPMSENSE_ANY);
|
|
REGISTER_CONSTANT(RPMSENSE_SERIAL);
|
|
REGISTER_CONSTANT(RPMSENSE_LESS);
|
|
REGISTER_CONSTANT(RPMSENSE_GREATER);
|
|
REGISTER_CONSTANT(RPMSENSE_EQUAL);
|
|
REGISTER_CONSTANT(RPMSENSE_PROVIDES);
|
|
REGISTER_CONSTANT(RPMSENSE_CONFLICTS);
|
|
REGISTER_CONSTANT(RPMSENSE_PREREQ);
|
|
REGISTER_CONSTANT(RPMSENSE_OBSOLETES);
|
|
REGISTER_CONSTANT(RPMSENSE_INTERP);
|
|
REGISTER_CONSTANT(RPMSENSE_SCRIPT_PRE);
|
|
REGISTER_CONSTANT(RPMSENSE_SCRIPT_POST);
|
|
REGISTER_CONSTANT(RPMSENSE_SCRIPT_PREUN);
|
|
REGISTER_CONSTANT(RPMSENSE_SCRIPT_POSTUN);
|
|
REGISTER_CONSTANT(RPMSENSE_SCRIPT_VERIFY);
|
|
REGISTER_CONSTANT(RPMSENSE_FIND_REQUIRES);
|
|
REGISTER_CONSTANT(RPMSENSE_FIND_PROVIDES);
|
|
REGISTER_CONSTANT(RPMSENSE_TRIGGERIN);
|
|
REGISTER_CONSTANT(RPMSENSE_TRIGGERUN);
|
|
REGISTER_CONSTANT(RPMSENSE_TRIGGERPOSTUN);
|
|
REGISTER_CONSTANT(RPMSENSE_SCRIPT_PREP);
|
|
REGISTER_CONSTANT(RPMSENSE_SCRIPT_BUILD);
|
|
REGISTER_CONSTANT(RPMSENSE_SCRIPT_INSTALL);
|
|
REGISTER_CONSTANT(RPMSENSE_SCRIPT_CLEAN);
|
|
REGISTER_CONSTANT(RPMSENSE_RPMLIB);
|
|
REGISTER_CONSTANT(RPMSENSE_TRIGGERPREIN);
|
|
REGISTER_CONSTANT(RPMSENSE_KEYRING);
|
|
REGISTER_CONSTANT(RPMSENSE_PATCHES);
|
|
REGISTER_CONSTANT(RPMSENSE_CONFIG);
|
|
|
|
}
|
|
|
|
double
|
|
rpm_api_version(pkg)
|
|
char * pkg
|
|
CODE:
|
|
#if defined(RPM2_RPM41) && ! defined(RPM2_RPM40)
|
|
RETVAL = (double)4.1;
|
|
#endif
|
|
#if ! defined(RPM2_RPM41) && defined(RPM2_RPM40)
|
|
RETVAL = (double)4.0;
|
|
#endif
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
|
|
void
|
|
add_macro(pkg, name, val)
|
|
char * pkg
|
|
char * name
|
|
char * val
|
|
CODE:
|
|
addMacro(NULL, name, NULL, val, RMIL_DEFAULT);
|
|
|
|
void
|
|
delete_macro(pkg, name)
|
|
char * pkg
|
|
char * name
|
|
CODE:
|
|
delMacro(NULL, name);
|
|
|
|
void
|
|
expand_macro(pkg, str)
|
|
char * pkg
|
|
char * str
|
|
PREINIT:
|
|
char *ret;
|
|
PPCODE:
|
|
ret = rpmExpand(str, NULL);
|
|
PUSHs(sv_2mortal(newSVpv(ret, 0)));
|
|
free(ret);
|
|
|
|
int
|
|
rpmvercmp(one, two)
|
|
char* one
|
|
char* two
|
|
|
|
void
|
|
_read_package_info(fp, vsflags)
|
|
FILE *fp
|
|
int vsflags
|
|
PREINIT:
|
|
#ifdef RPM2_RPM41
|
|
rpmts ts;
|
|
#endif
|
|
Header ret;
|
|
Header sigs;
|
|
rpmRC rc;
|
|
FD_t fd;
|
|
PPCODE:
|
|
#ifdef RPM2_RPM41
|
|
ts = rpmtsCreate();
|
|
#endif
|
|
|
|
/* XXX Determine type of signature verification when reading
|
|
vsflags |= _RPMTS_VSF_NOLEGACY;
|
|
vsflags |= _RPMTS_VSF_NODIGESTS;
|
|
vsflags |= _RPMTS_VSF_NOSIGNATURES;
|
|
xx = rpmtsSetVerifySigFlags(ts, vsflags);
|
|
*/
|
|
|
|
fd = fdDup(fileno(fp));
|
|
#ifdef RPM2_RPM41
|
|
rpmtsSetVSFlags(ts, vsflags);
|
|
rc = rpmReadPackageFile(ts, fd, "filename or other identifier", &ret);
|
|
#else
|
|
rc = rpmReadPackageInfo(fd, NULL, &ret);
|
|
#endif
|
|
|
|
Fclose(fd);
|
|
|
|
if (rc == RPMRC_OK) {
|
|
SV *h_sv;
|
|
|
|
EXTEND(SP, 1);
|
|
|
|
h_sv = sv_newmortal();
|
|
sv_setref_pv(h_sv, "RPM2::C::Header", (void *)ret);
|
|
|
|
PUSHs(h_sv);
|
|
}
|
|
else {
|
|
croak("error reading package (%d)", rc);
|
|
}
|
|
#ifdef RPM2_RPM41
|
|
ts = rpmtsFree(ts);
|
|
#endif
|
|
|
|
void
|
|
_create_transaction(vsflags)
|
|
int vsflags
|
|
PREINIT:
|
|
rpmts ret;
|
|
SV *h_sv;
|
|
PPCODE:
|
|
/* Looking at librpm, it does not look like this ever
|
|
returns error (though maybe it should).
|
|
*/
|
|
ret = rpmtsCreate();
|
|
|
|
/* Should I save the old vsflags aside? */
|
|
rpmtsSetVSFlags(ret, vsflags);
|
|
|
|
/* Convert and throw the results on the stack */
|
|
EXTEND(SP, 1);
|
|
|
|
h_sv = sv_newmortal();
|
|
sv_setref_pv(h_sv, "RPM2::C::Transaction", (void *)ret);
|
|
|
|
PUSHs(h_sv);
|
|
|
|
void
|
|
_read_from_file(fp)
|
|
FILE *fp
|
|
PREINIT:
|
|
SV *h_sv;
|
|
FD_t fd;
|
|
Header h;
|
|
PPCODE:
|
|
fd = fdDup(fileno(fp));
|
|
h = headerRead(fd, HEADER_MAGIC_YES);
|
|
|
|
if (h) {
|
|
EXTEND(SP, 1);
|
|
|
|
h_sv = sv_newmortal();
|
|
sv_setref_pv(h_sv, "RPM2::C::Header", (void *)h);
|
|
|
|
PUSHs(h_sv);
|
|
}
|
|
Fclose(fd);
|
|
|
|
|
|
rpmdb
|
|
_open_rpm_db(for_write)
|
|
int for_write
|
|
PREINIT:
|
|
rpmdb db;
|
|
CODE:
|
|
if (rpmdbOpen(NULL, &db, for_write ? O_RDWR | O_CREAT : O_RDONLY, 0644)) {
|
|
croak("rpmdbOpen failed");
|
|
RETVAL = NULL;
|
|
}
|
|
RETVAL = db;
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
MODULE = RPM2 PACKAGE = RPM2::C::DB
|
|
|
|
void
|
|
DESTROY(db)
|
|
rpmdb db
|
|
CODE:
|
|
rpmdbClose(db);
|
|
|
|
void
|
|
_close_rpm_db(self)
|
|
rpmdb self
|
|
CODE:
|
|
rpmdbClose(self);
|
|
|
|
rpmdbMatchIterator
|
|
_init_iterator(db, rpmtag, key, len)
|
|
rpmdb db
|
|
int rpmtag
|
|
char *key
|
|
size_t len
|
|
CODE:
|
|
RETVAL = rpmdbInitIterator(db, rpmtag, key && *key ? key : NULL, len);
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
MODULE = RPM2 PACKAGE = RPM2::C::PackageIterator
|
|
Header
|
|
_iterator_next(i)
|
|
rpmdbMatchIterator i
|
|
PREINIT:
|
|
Header ret;
|
|
SV * h_sv;
|
|
unsigned int offset;
|
|
PPCODE:
|
|
ret = rpmdbNextIterator(i);
|
|
if (ret)
|
|
headerLink(ret);
|
|
if(ret != NULL)
|
|
offset = rpmdbGetIteratorOffset(i);
|
|
else
|
|
offset = 0;
|
|
|
|
EXTEND(SP, 2);
|
|
h_sv = sv_newmortal();
|
|
sv_setref_pv(h_sv, "RPM2::C::Header", (void *)ret);
|
|
PUSHs(h_sv);
|
|
PUSHs(sv_2mortal(newSViv(offset)));
|
|
|
|
void
|
|
DESTROY(i)
|
|
rpmdbMatchIterator i
|
|
CODE:
|
|
rpmdbFreeIterator(i);
|
|
|
|
|
|
MODULE = RPM2 PACKAGE = RPM2::C::Header
|
|
|
|
void
|
|
DESTROY(h)
|
|
Header h
|
|
CODE:
|
|
headerFree(h);
|
|
|
|
void
|
|
tag_by_id(h, tag)
|
|
Header h
|
|
int tag
|
|
PREINIT:
|
|
void *ret = NULL;
|
|
int type;
|
|
int n;
|
|
int ok;
|
|
PPCODE:
|
|
ok = headerGetEntry(h, tag, &type, &ret, &n);
|
|
|
|
if (!ok) {
|
|
/* nop, empty stack */
|
|
}
|
|
else {
|
|
switch(type)
|
|
{
|
|
case RPM_STRING_ARRAY_TYPE:
|
|
{
|
|
int i;
|
|
char **s;
|
|
|
|
EXTEND(SP, n);
|
|
s = (char **)ret;
|
|
|
|
for (i = 0; i < n; i++) {
|
|
PUSHs(sv_2mortal(newSVpv(s[i], 0)));
|
|
}
|
|
}
|
|
break;
|
|
case RPM_STRING_TYPE:
|
|
PUSHs(sv_2mortal(newSVpv((char *)ret, 0)));
|
|
break;
|
|
case RPM_CHAR_TYPE:
|
|
case RPM_INT8_TYPE:
|
|
case RPM_INT16_TYPE:
|
|
case RPM_INT32_TYPE:
|
|
{
|
|
int i;
|
|
int *r;
|
|
|
|
EXTEND(SP, n);
|
|
r = (int *)ret;
|
|
|
|
for (i = 0; i < n; i++) {
|
|
PUSHs(sv_2mortal(newSViv(r[i])));
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
croak("unknown rpm tag type %d", type);
|
|
}
|
|
}
|
|
headerFreeData(ret, type);
|
|
|
|
int
|
|
_header_compare(h1, h2)
|
|
Header h1
|
|
Header h2
|
|
CODE:
|
|
RETVAL = rpmVersionCompare(h1, h2);
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
int
|
|
_header_is_source(h)
|
|
Header h
|
|
CODE:
|
|
RETVAL = headerIsEntry(h, RPMTAG_SOURCEPACKAGE);
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
void
|
|
_header_sprintf(h, format)
|
|
Header h
|
|
char * format
|
|
PREINIT:
|
|
char * s;
|
|
PPCODE:
|
|
s = headerSprintf(h, format, rpmTagTable, rpmHeaderFormats, NULL);
|
|
PUSHs(sv_2mortal(newSVpv((char *)s, 0)));
|
|
s = _free(s);
|
|
|
|
void
|
|
_unload(h)
|
|
Header h
|
|
PREINIT:
|
|
char *buf;
|
|
unsigned int size;
|
|
PPCODE:
|
|
size = headerSizeof(h, 0);
|
|
buf = headerUnload(h);
|
|
PUSHs(sv_2mortal(newSVpv(buf, size)));
|
|
|
|
MODULE = RPM2 PACKAGE = RPM2::C::Transaction
|
|
|
|
void
|
|
DESTROY(t)
|
|
rpmts t
|
|
CODE:
|
|
t = rpmtsFree(t);
|
|
|
|
# XXX: Add relocations some day.
|
|
int
|
|
_add_install(t, h, fn, upgrade)
|
|
rpmts t
|
|
Header h
|
|
char * fn
|
|
int upgrade
|
|
PREINIT:
|
|
rpmRC rc = 0;
|
|
CODE:
|
|
rc = rpmtsAddInstallElement(t, h, (fnpyKey) fn, upgrade, NULL);
|
|
RETVAL = (rc == RPMRC_OK) ? 1 : 0;
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
int
|
|
_add_delete(t, h, offset)
|
|
rpmts t
|
|
Header h
|
|
unsigned int offset
|
|
PREINIT:
|
|
rpmRC rc = 0;
|
|
CODE:
|
|
rc = rpmtsAddEraseElement(t, h, offset);
|
|
RETVAL = (rc == RPMRC_OK) ? 1 : 0;
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
int
|
|
_element_count(t)
|
|
rpmts t
|
|
PREINIT:
|
|
int ret;
|
|
CODE:
|
|
ret = rpmtsNElements(t);
|
|
RETVAL = ret;
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
int
|
|
_close_db(t)
|
|
rpmts t
|
|
PREINIT:
|
|
int ret;
|
|
CODE:
|
|
ret = rpmtsCloseDB(t);
|
|
RETVAL = (ret == 0) ? 1 : 0;
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
int
|
|
_check(t)
|
|
rpmts t
|
|
PREINIT:
|
|
int ret;
|
|
CODE:
|
|
ret = rpmtsCheck(t);
|
|
RETVAL = (ret == 0) ? 1 : 0;
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
int
|
|
_order(t)
|
|
rpmts t
|
|
PREINIT:
|
|
int ret;
|
|
CODE:
|
|
ret = rpmtsOrder(t);
|
|
/* XXX: May want to do something different here. It actually
|
|
returns the number of non-ordered elements...maybe we
|
|
want this?
|
|
*/
|
|
RETVAL = (ret == 0) ? 1 : 0;
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
void
|
|
_elements(t, type)
|
|
rpmts t;
|
|
rpmElementType type;
|
|
PREINIT:
|
|
rpmtsi i;
|
|
rpmte te;
|
|
const char * NEVR;
|
|
PPCODE:
|
|
i = rpmtsiInit(t);
|
|
if(i == NULL) {
|
|
printf("Did not get a thing!\n");
|
|
return;
|
|
} else {
|
|
while((te = rpmtsiNext(i, type)) != NULL) {
|
|
NEVR = rpmteNEVR(te);
|
|
XPUSHs(sv_2mortal(newSVpv(NEVR, 0)));
|
|
}
|
|
i = rpmtsiFree(i);
|
|
}
|
|
|
|
int
|
|
_run(t, ok_probs, prob_filter)
|
|
rpmts t
|
|
rpmprobFilterFlags prob_filter
|
|
PREINIT:
|
|
int i;
|
|
rpmProblem p;
|
|
int ret;
|
|
CODE:
|
|
/* Make sure we could run this transactions */
|
|
ret = rpmtsCheck(t);
|
|
if (ret != 0) {
|
|
RETVAL = 0;
|
|
return;
|
|
}
|
|
ret = rpmtsOrder(t);
|
|
if (ret != 0) {
|
|
RETVAL = 0;
|
|
return;
|
|
}
|
|
|
|
/* XXX: Should support callbacks eventually */
|
|
(void) rpmtsSetNotifyCallback(t, _null_callback, (void *) ((long)0));
|
|
ret = rpmtsRun(t, NULL, prob_filter);
|
|
RETVAL = (ret == 0) ? 1 : 0;
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
|