/* * Copyright (C) 2008 Kristian Høgsberg * Copyright (C) 2008 Red Hat, Inc * Copyright (C) 2009, 2011 J. Ali Harlow * * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "config.h" #include #include #include #include #include #include #include #if HAVE_SYS_WAIT_H #include #endif #include #include #include #if MSWIN_API #include /* For ntohl() */ #else #include #endif #include #include #include #include "razor.h" #include "razor-internal.h" #ifndef O_BINARY #define O_BINARY 0 #endif #define RPM_LEAD_SIZE 96 enum { PIPE = 1, /*!< pipe/fifo */ CDEV = 2, /*!< character device */ XDIR = 4, /*!< directory */ BDEV = 6, /*!< block device */ REG = 8, /*!< regular file */ LINK = 10, /*!< hard link */ SOCK = 12 /*!< socket */ }; enum { RPMSENSE_LESS = 1 << 1, RPMSENSE_GREATER = 1 << 2, RPMSENSE_EQUAL = 1 << 3, RPMSENSE_PREREQ = 1 << 6, RPMSENSE_SCRIPT_PRE = 1 << 9, RPMSENSE_SCRIPT_POST = 1 << 10, RPMSENSE_SCRIPT_PREUN = 1 << 11, RPMSENSE_SCRIPT_POSTUN = 1 << 12, }; enum { RPMTAG_NAME = 1000, /* s */ RPMTAG_VERSION = 1001, /* s */ RPMTAG_RELEASE = 1002, /* s */ RPMTAG_EPOCH = 1003, /* i */ RPMTAG_SUMMARY = 1004, /* s{} */ RPMTAG_DESCRIPTION = 1005, /* s{} */ RPMTAG_BUILDTIME = 1006, /* i */ RPMTAG_BUILDHOST = 1007, /* s */ RPMTAG_INSTALLTIME = 1008, /* i */ RPMTAG_SIZE = 1009, /* i */ RPMTAG_DISTRIBUTION = 1010, /* s */ RPMTAG_VENDOR = 1011, /* s */ RPMTAG_GIF = 1012, /* x */ RPMTAG_XPM = 1013, /* x */ RPMTAG_LICENSE = 1014, /* s */ RPMTAG_PACKAGER = 1015, /* s */ RPMTAG_GROUP = 1016, /* s{} */ RPMTAG_CHANGELOG = 1017, /*!< s[] internal */ RPMTAG_SOURCE = 1018, /* s[] */ RPMTAG_PATCH = 1019, /* s[] */ RPMTAG_URL = 1020, /* s */ RPMTAG_OS = 1021, /* s legacy used int */ RPMTAG_ARCH = 1022, /* s legacy used int */ RPMTAG_PREIN = 1023, /* s */ RPMTAG_POSTIN = 1024, /* s */ RPMTAG_PREUN = 1025, /* s */ RPMTAG_POSTUN = 1026, /* s */ RPMTAG_OLDFILENAMES = 1027, /* s[] obsolete */ RPMTAG_FILESIZES = 1028, /* i */ RPMTAG_FILESTATES = 1029, /* c */ RPMTAG_FILEMODES = 1030, /* h */ RPMTAG_FILEUIDS = 1031, /*!< internal */ RPMTAG_FILEGIDS = 1032, /*!< internal */ RPMTAG_FILERDEVS = 1033, /* h */ RPMTAG_FILEMTIMES = 1034, /* i */ RPMTAG_FILEMD5S = 1035, /* s[] */ RPMTAG_FILELINKTOS = 1036, /* s[] */ RPMTAG_FILEFLAGS = 1037, /* i */ RPMTAG_ROOT = 1038, /*!< internal - obsolete */ RPMTAG_FILEUSERNAME = 1039, /* s[] */ RPMTAG_FILEGROUPNAME = 1040, /* s[] */ RPMTAG_EXCLUDE = 1041, /*!< internal - obsolete */ RPMTAG_EXCLUSIVE = 1042, /*!< internal - obsolete */ RPMTAG_ICON = 1043, RPMTAG_SOURCERPM = 1044, /* s */ RPMTAG_FILEVERIFYFLAGS = 1045, /* i */ RPMTAG_ARCHIVESIZE = 1046, /* i */ RPMTAG_PROVIDENAME = 1047, /* s[] */ RPMTAG_REQUIREFLAGS = 1048, /* i */ RPMTAG_REQUIRENAME = 1049, /* s[] */ RPMTAG_REQUIREVERSION = 1050, /* s[] */ RPMTAG_NOSOURCE = 1051, /*!< internal */ RPMTAG_NOPATCH = 1052, /*!< internal */ RPMTAG_CONFLICTFLAGS = 1053, /* i */ RPMTAG_CONFLICTNAME = 1054, /* s[] */ RPMTAG_CONFLICTVERSION = 1055, /* s[] */ RPMTAG_DEFAULTPREFIX = 1056, /*!< internal - deprecated */ RPMTAG_BUILDROOT = 1057, /*!< internal */ RPMTAG_INSTALLPREFIX = 1058, /*!< internal - deprecated */ RPMTAG_EXCLUDEARCH = 1059, RPMTAG_EXCLUDEOS = 1060, RPMTAG_EXCLUSIVEARCH = 1061, RPMTAG_EXCLUSIVEOS = 1062, RPMTAG_AUTOREQPROV = 1063, /*!< internal */ RPMTAG_RPMVERSION = 1064, /* s */ RPMTAG_TRIGGERSCRIPTS = 1065, /* s[] */ RPMTAG_TRIGGERNAME = 1066, /* s[] */ RPMTAG_TRIGGERVERSION = 1067, /* s[] */ RPMTAG_TRIGGERFLAGS = 1068, /* i */ RPMTAG_TRIGGERINDEX = 1069, /* i */ RPMTAG_VERIFYSCRIPT = 1079, /* s */ RPMTAG_CHANGELOGTIME = 1080, /* i */ RPMTAG_CHANGELOGNAME = 1081, /* s[] */ RPMTAG_CHANGELOGTEXT = 1082, /* s[] */ RPMTAG_BROKENMD5 = 1083, /*!< internal - obsolete */ RPMTAG_PREREQ = 1084, /*!< internal */ RPMTAG_PREINPROG = 1085, /* s */ RPMTAG_POSTINPROG = 1086, /* s */ RPMTAG_PREUNPROG = 1087, /* s */ RPMTAG_POSTUNPROG = 1088, /* s */ RPMTAG_BUILDARCHS = 1089, RPMTAG_OBSOLETENAME = 1090, /* s[] */ RPMTAG_VERIFYSCRIPTPROG = 1091, /* s */ RPMTAG_TRIGGERSCRIPTPROG = 1092, /* s */ RPMTAG_DOCDIR = 1093, /*!< internal */ RPMTAG_COOKIE = 1094, /* s */ RPMTAG_FILEDEVICES = 1095, /* i */ RPMTAG_FILEINODES = 1096, /* i */ RPMTAG_FILELANGS = 1097, /* s[] */ RPMTAG_PREFIXES = 1098, /* s[] */ RPMTAG_INSTPREFIXES = 1099, /* s[] */ RPMTAG_TRIGGERIN = 1100, /*!< internal */ RPMTAG_TRIGGERUN = 1101, /*!< internal */ RPMTAG_TRIGGERPOSTUN = 1102, /*!< internal */ RPMTAG_AUTOREQ = 1103, /*!< internal */ RPMTAG_AUTOPROV = 1104, /*!< internal */ RPMTAG_CAPABILITY = 1105, /*!< internal - obsolete */ RPMTAG_SOURCEPACKAGE = 1106, /*!< i src.rpm header marker */ RPMTAG_OLDORIGFILENAMES = 1107, /*!< internal - obsolete */ RPMTAG_BUILDPREREQ = 1108, /*!< internal */ RPMTAG_BUILDREQUIRES = 1109, /*!< internal */ RPMTAG_BUILDCONFLICTS = 1110, /*!< internal */ RPMTAG_BUILDMACROS = 1111, /*!< internal - unused */ RPMTAG_PROVIDEFLAGS = 1112, /* i */ RPMTAG_PROVIDEVERSION = 1113, /* s[] */ RPMTAG_OBSOLETEFLAGS = 1114, /* i */ RPMTAG_OBSOLETEVERSION = 1115, /* s[] */ RPMTAG_DIRINDEXES = 1116, /* i */ RPMTAG_BASENAMES = 1117, /* s[] */ RPMTAG_DIRNAMES = 1118, /* s[] */ RPMTAG_ORIGDIRINDEXES = 1119, /*!< internal */ RPMTAG_ORIGBASENAMES = 1120, /*!< internal */ RPMTAG_ORIGDIRNAMES = 1121, /*!< internal */ RPMTAG_OPTFLAGS = 1122, /* s */ RPMTAG_DISTURL = 1123, /* s */ RPMTAG_PAYLOADFORMAT = 1124, /* s */ RPMTAG_PAYLOADCOMPRESSOR = 1125, /* s */ RPMTAG_PAYLOADFLAGS = 1126, /* s */ RPMTAG_INSTALLCOLOR = 1127, /*!< i transaction color when installed */ RPMTAG_INSTALLTID = 1128, /* i */ RPMTAG_REMOVETID = 1129, /* i */ RPMTAG_SHA1RHN = 1130, /*!< internal - obsolete */ RPMTAG_RHNPLATFORM = 1131, /* s */ RPMTAG_PLATFORM = 1132, /* s */ RPMTAG_PATCHESNAME = 1133, /*!< placeholder (SuSE) */ RPMTAG_PATCHESFLAGS = 1134, /*!< placeholder (SuSE) */ RPMTAG_PATCHESVERSION = 1135, /*!< placeholder (SuSE) */ RPMTAG_CACHECTIME = 1136, /* i */ RPMTAG_CACHEPKGPATH = 1137, /* s */ RPMTAG_CACHEPKGSIZE = 1138, /* i */ RPMTAG_CACHEPKGMTIME = 1139, /* i */ RPMTAG_FILECOLORS = 1140, /* i */ RPMTAG_FILECLASS = 1141, /* i */ RPMTAG_CLASSDICT = 1142, /* s[] */ RPMTAG_FILEDEPENDSX = 1143, /* i */ RPMTAG_FILEDEPENDSN = 1144, /* i */ RPMTAG_DEPENDSDICT = 1145, /* i */ RPMTAG_SOURCEPKGID = 1146, /* x */ RPMTAG_FILECONTEXTS = 1147, /* s[] */ RPMTAG_FSCONTEXTS = 1148, /*!< s[] extension */ RPMTAG_RECONTEXTS = 1149, /*!< s[] extension */ RPMTAG_POLICIES = 1150, /*!< s[] selinux *.te policy file. */ RPMTAG_PRETRANS = 1151, /* s */ RPMTAG_POSTTRANS = 1152, /* s */ RPMTAG_PRETRANSPROG = 1153, /* s */ RPMTAG_POSTTRANSPROG = 1154, /* s */ RPMTAG_DISTTAG = 1155, /* s */ RPMTAG_SUGGESTSNAME = 1156, /* s[] extension placeholder */ RPMTAG_SUGGESTSVERSION = 1157, /* s[] extension placeholder */ RPMTAG_SUGGESTSFLAGS = 1158, /* i extension placeholder */ RPMTAG_ENHANCESNAME = 1159, /* s[] extension placeholder */ RPMTAG_ENHANCESVERSION = 1160, /* s[] extension placeholder */ RPMTAG_ENHANCESFLAGS = 1161, /* i extension placeholder */ RPMTAG_PRIORITY = 1162, /* i extension placeholder */ RPMTAG_CVSID = 1163, /* s */ RPMTAG_TRIGGERPREIN = 1171, /*!< internal */ }; struct rpm_header { unsigned char magic[4]; unsigned char reserved[4]; int nindex; int hsize; }; struct rpm_header_index { int tag; int type; int offset; int count; }; struct razor_rpm { struct rpm_header *signature; struct rpm_header *header; const char **dirs; unsigned int n_prefixes; const char **prefixes; const char *pool; void *map; size_t size; void *payload; struct razor_relocations *relocations; char *evr; }; enum razor_relocation_flags { RAZOR_RELOCATION_ACTIVE = 1 << 0, }; struct razor_relocation { enum razor_relocation_flags flags; size_t oldlen; size_t newlen; char *oldpath; char *newpath; }; struct razor_relocations { /* Ordered such that if oldpath 1 starts with oldpath 2, then * oldpath 1 is listed first (ie., /usr/bin comes before /usr) * and terminated with a NULL oldpath. */ struct razor_relocation *relocations; int n_relocations; char *path; }; RAZOR_EXPORT struct razor_relocations *razor_relocations_create(void) { return calloc(1, sizeof(struct razor_relocations)); } RAZOR_EXPORT void razor_relocations_add(struct razor_relocations *rr, const char *oldpath, const char *newpath) { int i, found = 0; size_t len; if (newpath && !strcmp(oldpath, newpath)) newpath = NULL; for (i = 0; i < rr->n_relocations; i++) { len = rr->relocations[i].oldlen; if (!strncmp(rr->relocations[i].oldpath, oldpath, len)) { found = !strcmp(rr->relocations[i].oldpath, oldpath); break; } } if (!newpath) { if (found) { free(rr->relocations[i].oldpath); free(rr->relocations[i].newpath); do { rr->relocations[i] = rr->relocations[i + 1]; } while (rr->relocations[++i].oldpath); } return; } if (found) { free(rr->relocations[i].newpath); rr->relocations[i].newpath = strdup(newpath); rr->relocations[i].newlen = strlen(newpath); return; } if (!rr->n_relocations++) rr->relocations = calloc(1, sizeof *rr->relocations); else { rr->relocations = realloc(rr->relocations, rr->n_relocations * sizeof *rr->relocations); memmove(rr->relocations + i + 1, rr->relocations + i, (rr->n_relocations - i - 1) * sizeof *rr->relocations); } rr->relocations[i].flags = 0; rr->relocations[i].oldpath = strdup(oldpath); rr->relocations[i].newpath = strdup(newpath); rr->relocations[i].oldlen = strlen(oldpath); rr->relocations[i].newlen = strlen(newpath); } RAZOR_EXPORT void razor_relocations_set_rpm(struct razor_relocations *rr, struct razor_rpm *rpm) { int i, j; for (i = 0; i < rr->n_relocations; i++) { rr->relocations[i].flags &= ~RAZOR_RELOCATION_ACTIVE; for (j = 0; j < rpm->n_prefixes; j++) if (!strcmp(rpm->prefixes[j], rr->relocations[i].oldpath)) { rr->relocations[i].flags |= RAZOR_RELOCATION_ACTIVE; break; } } } RAZOR_EXPORT const char * razor_relocations_apply(struct razor_relocations *rr, const char *path) { int i; size_t len; for (i = 0; i < rr->n_relocations; i++) if (rr->relocations[i].flags & RAZOR_RELOCATION_ACTIVE && !strncmp(path, rr->relocations[i].oldpath, rr->relocations[i].oldlen)) break; if (i < rr->n_relocations) { free(rr->path); len = strlen(path + rr->relocations[i].oldlen) + rr->relocations[i].newlen; rr->path = malloc(len + 1); memcpy(rr->path, rr->relocations[i].newpath, rr->relocations[i].newlen); strcpy(rr->path + rr->relocations[i].newlen, path + rr->relocations[i].oldlen); return rr->path; } else return path; } RAZOR_EXPORT void razor_relocations_destroy(struct razor_relocations *rr) { free(rr->path); free(rr->relocations); free(rr); } static struct rpm_header_index * razor_rpm_get_header(struct razor_rpm *rpm, unsigned int tag) { struct rpm_header_index *index, *end; index = (struct rpm_header_index *) (rpm->header + 1); end = index + ntohl(rpm->header->nindex); while (index < end) { if (ntohl(index->tag) == tag) return index; index++; } return NULL; } static const void * razor_rpm_get_indirect(struct razor_rpm *rpm, unsigned int tag, unsigned int *count) { struct rpm_header_index *index; index = razor_rpm_get_header(rpm, tag); if (index != NULL) { if (count) *count = ntohl(index->count); return rpm->pool + ntohl(index->offset); } return NULL; } static uint32_t rpm_to_razor_flags(uint32_t flags) { uint32_t razor_flags; razor_flags = 0; if (flags & RPMSENSE_LESS) razor_flags |= RAZOR_PROPERTY_LESS; if (flags & RPMSENSE_EQUAL) razor_flags |= RAZOR_PROPERTY_EQUAL; if (flags & RPMSENSE_GREATER) razor_flags |= RAZOR_PROPERTY_GREATER; if (flags & RPMSENSE_SCRIPT_PRE) razor_flags |= RAZOR_PROPERTY_PRE; if (flags & RPMSENSE_SCRIPT_POST) razor_flags |= RAZOR_PROPERTY_POST; if (flags & RPMSENSE_SCRIPT_PREUN) razor_flags |= RAZOR_PROPERTY_PREUN; if (flags & RPMSENSE_SCRIPT_POSTUN) razor_flags |= RAZOR_PROPERTY_POSTUN; return razor_flags; } static void import_properties(struct razor_importer *importer, uint32_t type, struct razor_rpm *rpm, int name_tag, int version_tag, int flags_tag) { const char *name, *version; const uint32_t *flags; uint32_t f; unsigned int i, count; name = razor_rpm_get_indirect(rpm, name_tag, &count); if (name == NULL) return; flags = razor_rpm_get_indirect(rpm, flags_tag, &count); version = razor_rpm_get_indirect(rpm, version_tag, &count); for (i = 0; i < count; i++) { f = rpm_to_razor_flags(ntohl(flags[i])); razor_importer_add_property(importer, name, f | type, version); name += strlen(name) + 1; version += strlen(version) + 1; } } static void import_files(struct razor_importer *importer, struct razor_rpm *rpm) { const char *name; const uint32_t *index; unsigned int i, count; char buffer[256]; if (rpm->dirs == NULL) return; /* assert: count is the same for all arrays */ index = razor_rpm_get_indirect(rpm, RPMTAG_DIRINDEXES, &count); name = razor_rpm_get_indirect(rpm, RPMTAG_BASENAMES, &count); for (i = 0; i < count; i++) { snprintf(buffer, sizeof buffer, "%s%s", rpm->dirs[ntohl(*index)], name); razor_importer_add_file(importer, buffer); name += strlen(name) + 1; index++; } } static void razor_rpm_build_evr(struct razor_rpm *rpm) { const char *version, *release; const uint32_t *epoch; char evr[128], buf[16]; epoch = razor_rpm_get_indirect(rpm, RPMTAG_EPOCH, NULL); version = razor_rpm_get_indirect(rpm, RPMTAG_VERSION, NULL); release = razor_rpm_get_indirect(rpm, RPMTAG_RELEASE, NULL); if (epoch) snprintf(buf, sizeof buf, "%lu", (unsigned long)ntohl(*epoch)); razor_build_evr(evr, sizeof evr, epoch ? buf : NULL, version, release); rpm->evr = strdup(evr); } static const char * razor_rpm_get_details_string(struct razor_rpm *rpm, enum razor_detail_type type) { switch(type) { case RAZOR_DETAIL_NAME: return razor_rpm_get_indirect(rpm, RPMTAG_NAME, NULL); case RAZOR_DETAIL_VERSION: if (!rpm->evr) razor_rpm_build_evr(rpm); return rpm->evr; case RAZOR_DETAIL_ARCH: return razor_rpm_get_indirect(rpm, RPMTAG_ARCH, NULL); case RAZOR_DETAIL_SUMMARY: return razor_rpm_get_indirect(rpm, RPMTAG_SUMMARY, NULL); case RAZOR_DETAIL_DESCRIPTION: return razor_rpm_get_indirect(rpm, RPMTAG_DESCRIPTION, NULL); case RAZOR_DETAIL_URL: return razor_rpm_get_indirect(rpm, RPMTAG_URL, NULL); case RAZOR_DETAIL_LICENSE: return razor_rpm_get_indirect(rpm, RPMTAG_LICENSE, NULL); case RAZOR_DETAIL_PREUNPROG: return razor_rpm_get_indirect(rpm, RPMTAG_PREUNPROG, NULL); case RAZOR_DETAIL_PREUN: return razor_rpm_get_indirect(rpm, RPMTAG_PREUN, NULL); case RAZOR_DETAIL_POSTUNPROG: return razor_rpm_get_indirect(rpm, RPMTAG_POSTUNPROG, NULL); case RAZOR_DETAIL_POSTUN: return razor_rpm_get_indirect(rpm, RPMTAG_POSTUN, NULL); default: fprintf(stderr, "type %u not found\n", type); return NULL; } } static const char *const * razor_rpm_get_details_array(struct razor_rpm *rpm, enum razor_detail_type type) { switch(type) { case RAZOR_DETAIL_PREFIXES: return rpm->prefixes; default: /* Impossible */ fprintf(stderr, "type %u not found\n", type); return NULL; } } void razor_rpm_get_details_varg(struct razor_rpm *rpm, va_list args) { int i; enum razor_detail_type type; const char **string; const char *const **array; for (i = 0;; i += 2) { type = va_arg(args, enum razor_detail_type); if (type == RAZOR_DETAIL_LAST) break; if (type == RAZOR_DETAIL_PREFIXES) { array = va_arg(args, const char *const **); *array = razor_rpm_get_details_array(rpm, type); } else { string = va_arg(args, const char **); *string = razor_rpm_get_details_string(rpm, type); } } } RAZOR_EXPORT void razor_rpm_get_details(struct razor_rpm *rpm, ...) { va_list args; assert(rpm != NULL); va_start(args, rpm); razor_rpm_get_details_varg(rpm, args); va_end(args); } RAZOR_EXPORT struct razor_rpm * razor_rpm_open(const char *filename, struct razor_atomic *atomic) { struct razor_rpm *rpm; struct rpm_header_index *base, *index; unsigned int count, i, nindex, hsize; const char *name, *prefix; char *s; assert (filename != NULL); rpm = zalloc(sizeof *rpm); if (rpm == NULL) { razor_atomic_abort(atomic, "Not enough memory"); return NULL; } memset(rpm, 0, sizeof *rpm); rpm->map = razor_file_get_contents(filename, &rpm->size); if (!rpm->map) { s = razor_concat(filename, ": ", strerror(errno), NULL); razor_atomic_abort(atomic, s); free(s); free(rpm); return NULL; } rpm->signature = rpm->map + RPM_LEAD_SIZE; nindex = ntohl(rpm->signature->nindex); hsize = ntohl(rpm->signature->hsize); rpm->header = (void *) (rpm->signature + 1) + ALIGN(nindex * sizeof *index + hsize, 8); nindex = ntohl(rpm->header->nindex); hsize = ntohl(rpm->header->hsize); rpm->payload = (void *) (rpm->header + 1) + nindex * sizeof *index + hsize; base = (struct rpm_header_index *) (rpm->header + 1); rpm->pool = (void *) base + nindex * sizeof *index; /* Look up dir names now so we can index them directly. */ name = razor_rpm_get_indirect(rpm, RPMTAG_DIRNAMES, &count); if (name) { rpm->dirs = calloc(count, sizeof *rpm->dirs); for (i = 0; i < count; i++) { rpm->dirs[i] = name; name += strlen(name) + 1; } } else { name = razor_rpm_get_indirect(rpm, RPMTAG_OLDFILENAMES, &count); if (name) { razor_rpm_close(rpm); s = razor_concat(filename, ": Old filenames not supported", NULL); razor_atomic_abort(atomic, s); free(s); return NULL; } } prefix = razor_rpm_get_indirect(rpm, RPMTAG_PREFIXES, &count); if (prefix) { rpm->prefixes = calloc(count + 1, sizeof *rpm->prefixes); for (i = 0; i < count; i++) { rpm->prefixes[i] = prefix; prefix += strlen(prefix) + 1; } rpm->prefixes[i] = NULL; rpm->n_prefixes = count; } else { prefix = razor_rpm_get_indirect(rpm, RPMTAG_DEFAULTPREFIX, &count); if (prefix) { razor_rpm_close(rpm); s = razor_concat(filename, ": Default prefix not supported", NULL); razor_atomic_abort(atomic, s); free(s); return NULL; } } return rpm; } RAZOR_EXPORT void razor_rpm_set_relocations(struct razor_rpm *rpm, struct razor_relocations *rr) { assert (rpm != NULL); rpm->relocations = rr; } struct cpio_file_header { char magic[6]; char inode[8]; char mode[8]; char uid[8]; char gid[8]; char nlink[8]; char mtime[8]; char filesize[8]; char devmajor[8]; char devminor[8]; char rdevmajor[8]; char rdevminor[8]; char namesize[8]; char checksum[8]; char filename[0]; }; /* gzip flags */ #define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */ #define HEAD_CRC 0x02 /* bit 1 set: header CRC present */ #define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */ #define ORIG_NAME 0x08 /* bit 3 set: original file name present */ #define COMMENT 0x10 /* bit 4 set: file comment present */ #define RESERVED 0xE0 /* bits 5..7: reserved */ struct installer { const char *root; struct razor_rpm *rpm; struct razor_atomic *atomic; z_stream stream; unsigned char buffer[32768]; size_t rest, length; }; static int installer_inflate(struct installer *installer) { size_t length; int err; if (installer->rest > sizeof installer->buffer) length = sizeof installer->buffer; else length = installer->rest; installer->stream.next_out = installer->buffer; installer->stream.avail_out = length; err = inflate(&installer->stream, Z_SYNC_FLUSH); if (err != Z_OK && err != Z_STREAM_END) { razor_atomic_abort(installer->atomic, "Failed to inflate"); return -1; } installer->rest -= length; installer->length = length; return 0; } static int installer_align(struct installer *installer, size_t size) { unsigned char buffer[4]; int err; installer->stream.next_out = buffer; installer->stream.avail_out = (size - installer->stream.total_out) & (size - 1); if (installer->stream.avail_out == 0) return 0; err = inflate(&installer->stream, Z_SYNC_FLUSH); if (err != Z_OK && err != Z_STREAM_END) { razor_atomic_abort(installer->atomic, "Failed to inflate"); return -1; } return 0; } static int create_path(struct installer *installer, const char *path, unsigned int mode) { char *s, *buffer; int h, ret; if (razor_atomic_make_dirs(installer->atomic, installer->root, path)) return -1; buffer = razor_concat(installer->root, path, NULL); switch (mode >> 12) { case REG: /* FIXME: handle the case where a file is already there. */ h = razor_atomic_create_file(installer->atomic, buffer, mode); free(buffer); if (h < 0) return -1; while (installer->rest > 0) { if (installer_inflate(installer)) return -1; if (razor_atomic_write(installer->atomic, h, installer->buffer, installer->length)) return -1; } return razor_atomic_close(installer->atomic, h); case XDIR: ret = razor_atomic_create_dir(installer->atomic, buffer, mode); free(buffer); return ret; case LINK: #if HAVE_SYMLINK if (installer_inflate(installer)) return -1; if (installer->length >= sizeof installer->buffer) { razor_atomic_abort(installer->atomic, "Link target too long"); return -1; } installer->buffer[installer->length] = '\0'; ret = razor_atomic_create_symlink(installer->atomic, (const char *)installer->buffer, buffer); free(buffer); return ret; #else s = "Symbolic links"; goto unsupported; #endif case PIPE: s = "Named pipes"; unsupported: free(buffer); buffer = razor_concat(s, " are not supported on this platform", NULL); razor_atomic_abort(installer->atomic, buffer); free(buffer); return -1; case CDEV: s = "Character devices"; goto unsupported; case BDEV: s = "Block devices"; goto unsupported; case SOCK: s = "Named sockets"; goto unsupported; default: free(buffer); razor_atomic_abort(installer->atomic, "Unknown file type"); return -1; } } static int chroot_push(const char *root) { int fd; #if HAVE_CHROOT if (geteuid() == 0) { fd = open("/", O_RDONLY, 0); if (chroot(root) < 0) { fprintf(stderr, "failed to chroot to %s: %s\n", root, strerror(errno)); exit(-1); } } else #endif fd = -1; return fd; } static void chroot_pop(int fd) { #if HAVE_CHROOT if (fd >= 0) { fchdir(fd); close(fd); chroot("."); } #endif } static int run_script_lua(const char *root, unsigned int script_tag, const char *script, int arg1) { int root_fd, retval; #if HAVE_LUA const char *name; switch(script_tag) { case RPMTAG_PREIN: name = "%pre"; break; case RPMTAG_POSTIN: name = "%post"; break; case RPMTAG_PREUN: name = "%preun"; break; case RPMTAG_POSTUN: name = "%postun"; break; default: name = "script"; break; } root_fd = chroot_push(root); retval = run_lua_script(root_fd < 0 ? root : NULL, name, script, -1, arg1); chroot_pop(root_fd); #else /* HAVE_LUA */ fprintf(stderr, "lua not available to run script\n"); retval = -1; #endif /* HAVE_LUA */ return retval; } static int run_script_external(const char *root, const char *program, const char *script, int arg1) { int root_fd, retval; FILE *fp; char buf[32], *command; if (program == NULL) { #if MSWIN_API program = getenv("COMSPEC"); if (program) { program = strchr(program, '='); if (program) program++; } if (!program) program = "c:\\windows\\system32\\cmd.exe"; #else program = "/bin/sh"; #endif } root_fd = chroot_push(root); if (arg1 >= 0) { sprintf(buf, "%d", arg1); command = malloc(strlen(program) + strlen(buf) + 2); sprintf(command, "%s %s", program, buf); } else command = strdup(program); fp = popen(command, "w"); free(command); if (!fp) { perror(program); retval = -1; } else if (script && fwrite(script, strlen(script), 1, fp) != 1) { perror("failed to write script to program"); retval = -1; } else retval = 0; if (fp) pclose(fp); chroot_pop(root_fd); return retval; } static int run_script(struct installer *installer, unsigned int program_tag, unsigned int script_tag, int arg1) { int i, retval; struct razor_rpm *rpm = installer->rpm; const char *script = NULL, *program = NULL, *prefix; char buf[32]; struct environment env; program = razor_rpm_get_indirect(rpm, program_tag, NULL); script = razor_rpm_get_indirect(rpm, script_tag, NULL); if (program == NULL && script == NULL) return 0; if (rpm->relocations) { environment_init(&env); for(i = 0; i < rpm->n_prefixes; i++) { prefix = razor_relocations_apply(rpm->relocations, rpm->prefixes[i]); sprintf(buf, "RPM_INSTALL_PREFIX%d", i); environment_add_variable(&env, buf, prefix); } environment_set(&env); } if (program && strcmp(program, "") == 0) retval = run_script_lua(installer->root, script_tag, script, arg1); else retval = run_script_external(installer->root, program, script, arg1); if (rpm->relocations) { environment_unset(&env); environment_release(&env); } return retval; } int razor_run_script(const char *root, enum razor_property_flags script, const char *program, const char *body, int arg1) { int retval; unsigned int script_tag; if (program && !*program) program = NULL; if (body && !*body) body = NULL; if (program == NULL && body == NULL) return 0; if (program && strcmp(program, "") == 0) { switch(script) { case RAZOR_PROPERTY_PRE: script_tag = RPMTAG_PREIN; break; case RAZOR_PROPERTY_POST: script_tag = RPMTAG_POSTIN; break; case RAZOR_PROPERTY_PREUN: script_tag = RPMTAG_PREUN; break; case RAZOR_PROPERTY_POSTUN: script_tag = RPMTAG_POSTUN; break; default: script_tag = 0; break; } retval = run_script_lua(root, script_tag, body, arg1); } else retval = run_script_external(root, program, body, arg1); return retval; } static int installer_init(struct installer *installer) { unsigned char *gz_header; int method, flags, err; char buffer[32], *s; gz_header = installer->rpm->payload; if (gz_header[0] != 0x1f || gz_header[1] != 0x8b) { razor_atomic_abort(installer->atomic, "Payload section doesn't have gz header"); return -1; } method = gz_header[2]; flags = gz_header[3]; if (method != Z_DEFLATED || flags != 0) { razor_atomic_abort(installer->atomic, "Unknown payload compression method or " "flags set"); return -1; } installer->stream.zalloc = NULL; installer->stream.zfree = NULL; installer->stream.opaque = NULL; installer->stream.next_in = gz_header + 10; installer->stream.avail_in = (installer->rpm->map + installer->rpm->size) - (void *) installer->stream.next_in; installer->stream.next_out = NULL; installer->stream.avail_out = 0; err = inflateInit2(&installer->stream, -MAX_WBITS); if (err != Z_OK) { sprintf(buffer, "%d", err); s = razor_concat("inflateEnd error: ", s, NULL); razor_atomic_abort(installer->atomic, s); free(s); return -1; } return 0; } static int installer_finish(struct installer *installer) { int err; char buffer[32], *s; err = inflateEnd(&installer->stream); if (err != Z_OK) { sprintf(buffer, "%d", err); s = razor_concat("inflateEnd error: ", s, NULL); razor_atomic_abort(installer->atomic, s); free(s); } return razor_atomic_in_error_state(installer->atomic); } static unsigned long fixed_hex_to_ulong(const char *hex, int length) { long l; int i; for (i = 0, l = 0; i < length; i++) { if (hex[i] < 'a') l = l * 16 + hex[i] - '0'; else l = l * 16 + hex[i] - 'a' + 10; } return l; } RAZOR_EXPORT int razor_rpm_install(struct razor_rpm *rpm, struct razor_atomic *atomic, const char *root, int install_count, enum razor_stage_type stage) { struct installer installer; struct cpio_file_header *header; struct stat buf; unsigned int mode; const char *path, *name; size_t filesize; char *s; assert (rpm != NULL); assert (root != NULL); installer.rpm = rpm; installer.root = root; installer.atomic = atomic; /* FIXME: Only do this before a transaction, not per rpm. */ if (*root && (stat(root, &buf) < 0 || !S_ISDIR(buf.st_mode))) { s = razor_concat(root, ": Directory does not exist", NULL); razor_atomic_abort(stderr, s); free(s); return -1; } if (rpm->relocations) razor_relocations_set_rpm(rpm->relocations, rpm); if (stage & RAZOR_STAGE_SCRIPTS_PRE) run_script(&installer, RPMTAG_PREINPROG, RPMTAG_PREIN, install_count); if (stage & RAZOR_STAGE_FILES) { if (installer_init(&installer)) return -1; while (installer.stream.avail_in > 0) { installer.rest = sizeof *header; if (installer_inflate(&installer)) break; header = (struct cpio_file_header *) installer.buffer; mode = fixed_hex_to_ulong(header->mode, sizeof header->mode); filesize = fixed_hex_to_ulong(header->filesize, sizeof header->filesize); installer.rest = fixed_hex_to_ulong(header->namesize, sizeof header->namesize); if (installer_inflate(&installer) || installer_align(&installer, 4)) break; path = (const char *) installer.buffer; /* This convention is so lame... */ if (strcmp(path, "TRAILER!!!") == 0) break; installer.rest = filesize; path++; if (rpm->relocations) path = razor_relocations_apply(rpm->relocations, path); if (create_path(&installer, path, mode)) break; if (installer_align(&installer, 4)) break; } if (installer_finish(&installer)) return -1; } if (stage & RAZOR_STAGE_SCRIPTS_POST) run_script(&installer, RPMTAG_POSTINPROG, RPMTAG_POSTIN, install_count); return 0; } RAZOR_EXPORT int razor_rpm_close(struct razor_rpm *rpm) { int err; assert (rpm != NULL); free(rpm->dirs); free(rpm->prefixes); err = razor_file_free_contents(rpm->map, rpm->size); free(rpm->evr); free(rpm); return err; } RAZOR_EXPORT int razor_importer_add_rpm(struct razor_importer *importer, struct razor_rpm *rpm) { const char *name, *version, *arch; const char *summary, *description, *url, *license; assert (importer != NULL); assert (rpm != NULL); razor_rpm_get_details(rpm, RAZOR_DETAIL_NAME, &name, RAZOR_DETAIL_VERSION, &version, RAZOR_DETAIL_ARCH, &arch, RAZOR_DETAIL_SUMMARY, &summary, RAZOR_DETAIL_DESCRIPTION, &description, RAZOR_DETAIL_URL, &url, RAZOR_DETAIL_LICENSE, &license, RAZOR_DETAIL_LAST); razor_importer_begin_package(importer, name, version, arch); razor_importer_add_details(importer, summary, description, url, license); import_properties(importer, RAZOR_PROPERTY_REQUIRES, rpm, RPMTAG_REQUIRENAME, RPMTAG_REQUIREVERSION, RPMTAG_REQUIREFLAGS); import_properties(importer, RAZOR_PROPERTY_PROVIDES, rpm, RPMTAG_PROVIDENAME, RPMTAG_PROVIDEVERSION, RPMTAG_PROVIDEFLAGS); import_properties(importer, RAZOR_PROPERTY_OBSOLETES, rpm, RPMTAG_OBSOLETENAME, RPMTAG_OBSOLETEVERSION, RPMTAG_OBSOLETEFLAGS); import_properties(importer, RAZOR_PROPERTY_CONFLICTS, rpm, RPMTAG_CONFLICTNAME, RPMTAG_CONFLICTVERSION, RPMTAG_CONFLICTFLAGS); import_files(importer, rpm); razor_importer_finish_package(importer); return 0; }