rhughes@241: /* rhughes@241: * Copyright (C) 2008 Kristian Høgsberg rhughes@241: * Copyright (C) 2008 Red Hat, Inc ali@351: * Copyright (C) 2009 J. Ali Harlow rhughes@241: * rhughes@241: * This program is free software; you can redistribute it and/or modify rhughes@241: * it under the terms of the GNU General Public License as published by rhughes@241: * the Free Software Foundation; either version 2 of the License, or rhughes@241: * (at your option) any later version. rhughes@241: * rhughes@241: * This program is distributed in the hope that it will be useful, rhughes@241: * but WITHOUT ANY WARRANTY; without even the implied warranty of rhughes@241: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the rhughes@241: * GNU General Public License for more details. rhughes@241: * rhughes@241: * You should have received a copy of the GNU General Public License along rhughes@241: * with this program; if not, write to the Free Software Foundation, Inc., rhughes@241: * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. rhughes@241: */ rhughes@241: ali@327: #include "config.h" ali@327: rhughes@241: #include rhughes@241: #include rhughes@241: #include rhughes@241: #include rhughes@241: #include rhughes@241: #include rhughes@241: #include ali@330: #if HAVE_SYS_WAIT_H rhughes@241: #include ali@330: #endif rhughes@241: #include rhughes@241: #include rhughes@241: #include ali@329: #if MSWIN_API ali@335: #include /* For ntohl() */ ali@329: #else rhughes@241: #include ali@329: #endif ali@325: #include rhughes@241: #include richard@301: #include rhughes@241: rhughes@241: #include "razor.h" rhughes@241: #include "razor-internal.h" rhughes@241: ali@345: #ifndef O_BINARY ali@345: #define O_BINARY 0 ali@345: #endif ali@345: rhughes@241: #define RPM_LEAD_SIZE 96 rhughes@241: rhughes@241: enum { rhughes@241: PIPE = 1, /*!< pipe/fifo */ rhughes@241: CDEV = 2, /*!< character device */ rhughes@241: XDIR = 4, /*!< directory */ rhughes@241: BDEV = 6, /*!< block device */ rhughes@241: REG = 8, /*!< regular file */ rhughes@241: LINK = 10, /*!< hard link */ rhughes@241: SOCK = 12 /*!< socket */ rhughes@241: }; rhughes@241: rhughes@241: enum { krh@247: RPMSENSE_LESS = 1 << 1, krh@247: RPMSENSE_GREATER = 1 << 2, krh@247: RPMSENSE_EQUAL = 1 << 3, krh@247: RPMSENSE_PREREQ = 1 << 6, krh@247: RPMSENSE_SCRIPT_PRE = 1 << 9, krh@247: RPMSENSE_SCRIPT_POST = 1 << 10, krh@247: RPMSENSE_SCRIPT_PREUN = 1 << 11, krh@247: RPMSENSE_SCRIPT_POSTUN = 1 << 12, rhughes@241: }; rhughes@241: rhughes@241: enum { rhughes@241: RPMTAG_NAME = 1000, /* s */ rhughes@241: RPMTAG_VERSION = 1001, /* s */ rhughes@241: RPMTAG_RELEASE = 1002, /* s */ rhughes@241: RPMTAG_EPOCH = 1003, /* i */ rhughes@241: RPMTAG_SUMMARY = 1004, /* s{} */ rhughes@241: RPMTAG_DESCRIPTION = 1005, /* s{} */ rhughes@241: RPMTAG_BUILDTIME = 1006, /* i */ rhughes@241: RPMTAG_BUILDHOST = 1007, /* s */ rhughes@241: RPMTAG_INSTALLTIME = 1008, /* i */ rhughes@241: RPMTAG_SIZE = 1009, /* i */ rhughes@241: RPMTAG_DISTRIBUTION = 1010, /* s */ rhughes@241: RPMTAG_VENDOR = 1011, /* s */ rhughes@241: RPMTAG_GIF = 1012, /* x */ rhughes@241: RPMTAG_XPM = 1013, /* x */ rhughes@241: RPMTAG_LICENSE = 1014, /* s */ rhughes@241: RPMTAG_PACKAGER = 1015, /* s */ rhughes@241: RPMTAG_GROUP = 1016, /* s{} */ rhughes@241: RPMTAG_CHANGELOG = 1017, /*!< s[] internal */ rhughes@241: RPMTAG_SOURCE = 1018, /* s[] */ rhughes@241: RPMTAG_PATCH = 1019, /* s[] */ rhughes@241: RPMTAG_URL = 1020, /* s */ rhughes@241: RPMTAG_OS = 1021, /* s legacy used int */ rhughes@241: RPMTAG_ARCH = 1022, /* s legacy used int */ rhughes@241: RPMTAG_PREIN = 1023, /* s */ rhughes@241: RPMTAG_POSTIN = 1024, /* s */ rhughes@241: RPMTAG_PREUN = 1025, /* s */ rhughes@241: RPMTAG_POSTUN = 1026, /* s */ rhughes@241: RPMTAG_OLDFILENAMES = 1027, /* s[] obsolete */ rhughes@241: RPMTAG_FILESIZES = 1028, /* i */ rhughes@241: RPMTAG_FILESTATES = 1029, /* c */ rhughes@241: RPMTAG_FILEMODES = 1030, /* h */ rhughes@241: RPMTAG_FILEUIDS = 1031, /*!< internal */ rhughes@241: RPMTAG_FILEGIDS = 1032, /*!< internal */ rhughes@241: RPMTAG_FILERDEVS = 1033, /* h */ rhughes@241: RPMTAG_FILEMTIMES = 1034, /* i */ rhughes@241: RPMTAG_FILEMD5S = 1035, /* s[] */ rhughes@241: RPMTAG_FILELINKTOS = 1036, /* s[] */ rhughes@241: RPMTAG_FILEFLAGS = 1037, /* i */ rhughes@241: RPMTAG_ROOT = 1038, /*!< internal - obsolete */ rhughes@241: RPMTAG_FILEUSERNAME = 1039, /* s[] */ rhughes@241: RPMTAG_FILEGROUPNAME = 1040, /* s[] */ rhughes@241: RPMTAG_EXCLUDE = 1041, /*!< internal - obsolete */ rhughes@241: RPMTAG_EXCLUSIVE = 1042, /*!< internal - obsolete */ rhughes@241: RPMTAG_ICON = 1043, rhughes@241: RPMTAG_SOURCERPM = 1044, /* s */ rhughes@241: RPMTAG_FILEVERIFYFLAGS = 1045, /* i */ rhughes@241: RPMTAG_ARCHIVESIZE = 1046, /* i */ rhughes@241: RPMTAG_PROVIDENAME = 1047, /* s[] */ rhughes@241: RPMTAG_REQUIREFLAGS = 1048, /* i */ rhughes@241: RPMTAG_REQUIRENAME = 1049, /* s[] */ rhughes@241: RPMTAG_REQUIREVERSION = 1050, /* s[] */ rhughes@241: RPMTAG_NOSOURCE = 1051, /*!< internal */ rhughes@241: RPMTAG_NOPATCH = 1052, /*!< internal */ rhughes@241: RPMTAG_CONFLICTFLAGS = 1053, /* i */ rhughes@241: RPMTAG_CONFLICTNAME = 1054, /* s[] */ rhughes@241: RPMTAG_CONFLICTVERSION = 1055, /* s[] */ rhughes@241: RPMTAG_DEFAULTPREFIX = 1056, /*!< internal - deprecated */ rhughes@241: RPMTAG_BUILDROOT = 1057, /*!< internal */ rhughes@241: RPMTAG_INSTALLPREFIX = 1058, /*!< internal - deprecated */ rhughes@241: RPMTAG_EXCLUDEARCH = 1059, rhughes@241: RPMTAG_EXCLUDEOS = 1060, rhughes@241: RPMTAG_EXCLUSIVEARCH = 1061, rhughes@241: RPMTAG_EXCLUSIVEOS = 1062, rhughes@241: RPMTAG_AUTOREQPROV = 1063, /*!< internal */ rhughes@241: RPMTAG_RPMVERSION = 1064, /* s */ rhughes@241: RPMTAG_TRIGGERSCRIPTS = 1065, /* s[] */ rhughes@241: RPMTAG_TRIGGERNAME = 1066, /* s[] */ rhughes@241: RPMTAG_TRIGGERVERSION = 1067, /* s[] */ rhughes@241: RPMTAG_TRIGGERFLAGS = 1068, /* i */ rhughes@241: RPMTAG_TRIGGERINDEX = 1069, /* i */ rhughes@241: RPMTAG_VERIFYSCRIPT = 1079, /* s */ rhughes@241: RPMTAG_CHANGELOGTIME = 1080, /* i */ rhughes@241: RPMTAG_CHANGELOGNAME = 1081, /* s[] */ rhughes@241: RPMTAG_CHANGELOGTEXT = 1082, /* s[] */ rhughes@241: RPMTAG_BROKENMD5 = 1083, /*!< internal - obsolete */ rhughes@241: RPMTAG_PREREQ = 1084, /*!< internal */ rhughes@241: RPMTAG_PREINPROG = 1085, /* s */ rhughes@241: RPMTAG_POSTINPROG = 1086, /* s */ rhughes@241: RPMTAG_PREUNPROG = 1087, /* s */ rhughes@241: RPMTAG_POSTUNPROG = 1088, /* s */ rhughes@241: RPMTAG_BUILDARCHS = 1089, rhughes@241: RPMTAG_OBSOLETENAME = 1090, /* s[] */ rhughes@241: RPMTAG_VERIFYSCRIPTPROG = 1091, /* s */ rhughes@241: RPMTAG_TRIGGERSCRIPTPROG = 1092, /* s */ rhughes@241: RPMTAG_DOCDIR = 1093, /*!< internal */ rhughes@241: RPMTAG_COOKIE = 1094, /* s */ rhughes@241: RPMTAG_FILEDEVICES = 1095, /* i */ rhughes@241: RPMTAG_FILEINODES = 1096, /* i */ rhughes@241: RPMTAG_FILELANGS = 1097, /* s[] */ rhughes@241: RPMTAG_PREFIXES = 1098, /* s[] */ rhughes@241: RPMTAG_INSTPREFIXES = 1099, /* s[] */ rhughes@241: RPMTAG_TRIGGERIN = 1100, /*!< internal */ rhughes@241: RPMTAG_TRIGGERUN = 1101, /*!< internal */ rhughes@241: RPMTAG_TRIGGERPOSTUN = 1102, /*!< internal */ rhughes@241: RPMTAG_AUTOREQ = 1103, /*!< internal */ rhughes@241: RPMTAG_AUTOPROV = 1104, /*!< internal */ rhughes@241: RPMTAG_CAPABILITY = 1105, /*!< internal - obsolete */ rhughes@241: RPMTAG_SOURCEPACKAGE = 1106, /*!< i src.rpm header marker */ rhughes@241: RPMTAG_OLDORIGFILENAMES = 1107, /*!< internal - obsolete */ rhughes@241: RPMTAG_BUILDPREREQ = 1108, /*!< internal */ rhughes@241: RPMTAG_BUILDREQUIRES = 1109, /*!< internal */ rhughes@241: RPMTAG_BUILDCONFLICTS = 1110, /*!< internal */ rhughes@241: RPMTAG_BUILDMACROS = 1111, /*!< internal - unused */ rhughes@241: RPMTAG_PROVIDEFLAGS = 1112, /* i */ rhughes@241: RPMTAG_PROVIDEVERSION = 1113, /* s[] */ rhughes@241: RPMTAG_OBSOLETEFLAGS = 1114, /* i */ rhughes@241: RPMTAG_OBSOLETEVERSION = 1115, /* s[] */ rhughes@241: RPMTAG_DIRINDEXES = 1116, /* i */ rhughes@241: RPMTAG_BASENAMES = 1117, /* s[] */ rhughes@241: RPMTAG_DIRNAMES = 1118, /* s[] */ rhughes@241: RPMTAG_ORIGDIRINDEXES = 1119, /*!< internal */ rhughes@241: RPMTAG_ORIGBASENAMES = 1120, /*!< internal */ rhughes@241: RPMTAG_ORIGDIRNAMES = 1121, /*!< internal */ rhughes@241: RPMTAG_OPTFLAGS = 1122, /* s */ rhughes@241: RPMTAG_DISTURL = 1123, /* s */ rhughes@241: RPMTAG_PAYLOADFORMAT = 1124, /* s */ rhughes@241: RPMTAG_PAYLOADCOMPRESSOR = 1125, /* s */ rhughes@241: RPMTAG_PAYLOADFLAGS = 1126, /* s */ rhughes@241: RPMTAG_INSTALLCOLOR = 1127, /*!< i transaction color when installed */ rhughes@241: RPMTAG_INSTALLTID = 1128, /* i */ rhughes@241: RPMTAG_REMOVETID = 1129, /* i */ rhughes@241: RPMTAG_SHA1RHN = 1130, /*!< internal - obsolete */ rhughes@241: RPMTAG_RHNPLATFORM = 1131, /* s */ rhughes@241: RPMTAG_PLATFORM = 1132, /* s */ rhughes@241: RPMTAG_PATCHESNAME = 1133, /*!< placeholder (SuSE) */ rhughes@241: RPMTAG_PATCHESFLAGS = 1134, /*!< placeholder (SuSE) */ rhughes@241: RPMTAG_PATCHESVERSION = 1135, /*!< placeholder (SuSE) */ rhughes@241: RPMTAG_CACHECTIME = 1136, /* i */ rhughes@241: RPMTAG_CACHEPKGPATH = 1137, /* s */ rhughes@241: RPMTAG_CACHEPKGSIZE = 1138, /* i */ rhughes@241: RPMTAG_CACHEPKGMTIME = 1139, /* i */ rhughes@241: RPMTAG_FILECOLORS = 1140, /* i */ rhughes@241: RPMTAG_FILECLASS = 1141, /* i */ rhughes@241: RPMTAG_CLASSDICT = 1142, /* s[] */ rhughes@241: RPMTAG_FILEDEPENDSX = 1143, /* i */ rhughes@241: RPMTAG_FILEDEPENDSN = 1144, /* i */ rhughes@241: RPMTAG_DEPENDSDICT = 1145, /* i */ rhughes@241: RPMTAG_SOURCEPKGID = 1146, /* x */ rhughes@241: RPMTAG_FILECONTEXTS = 1147, /* s[] */ rhughes@241: RPMTAG_FSCONTEXTS = 1148, /*!< s[] extension */ rhughes@241: RPMTAG_RECONTEXTS = 1149, /*!< s[] extension */ rhughes@241: RPMTAG_POLICIES = 1150, /*!< s[] selinux *.te policy file. */ rhughes@241: RPMTAG_PRETRANS = 1151, /* s */ rhughes@241: RPMTAG_POSTTRANS = 1152, /* s */ rhughes@241: RPMTAG_PRETRANSPROG = 1153, /* s */ rhughes@241: RPMTAG_POSTTRANSPROG = 1154, /* s */ rhughes@241: RPMTAG_DISTTAG = 1155, /* s */ rhughes@241: RPMTAG_SUGGESTSNAME = 1156, /* s[] extension placeholder */ rhughes@241: RPMTAG_SUGGESTSVERSION = 1157, /* s[] extension placeholder */ rhughes@241: RPMTAG_SUGGESTSFLAGS = 1158, /* i extension placeholder */ rhughes@241: RPMTAG_ENHANCESNAME = 1159, /* s[] extension placeholder */ rhughes@241: RPMTAG_ENHANCESVERSION = 1160, /* s[] extension placeholder */ rhughes@241: RPMTAG_ENHANCESFLAGS = 1161, /* i extension placeholder */ rhughes@241: RPMTAG_PRIORITY = 1162, /* i extension placeholder */ rhughes@241: RPMTAG_CVSID = 1163, /* s */ rhughes@241: RPMTAG_TRIGGERPREIN = 1171, /*!< internal */ rhughes@241: }; rhughes@241: rhughes@241: struct rpm_header { rhughes@241: unsigned char magic[4]; rhughes@241: unsigned char reserved[4]; rhughes@241: int nindex; rhughes@241: int hsize; rhughes@241: }; rhughes@241: rhughes@241: struct rpm_header_index { rhughes@241: int tag; rhughes@241: int type; rhughes@241: int offset; rhughes@241: int count; rhughes@241: }; rhughes@241: rhughes@241: struct razor_rpm { rhughes@241: struct rpm_header *signature; rhughes@241: struct rpm_header *header; rhughes@241: const char **dirs; ali@351: unsigned int n_prefixes; ali@351: const char **prefixes; rhughes@241: const char *pool; rhughes@241: void *map; rhughes@241: size_t size; rhughes@241: void *payload; ali@351: struct razor_relocations *relocations; rhughes@241: }; rhughes@241: ali@351: enum razor_relocation_flags { ali@351: RAZOR_RELOCATION_ACTIVE = 1 << 0, ali@351: }; ali@351: ali@351: struct razor_relocation { ali@351: enum razor_relocation_flags flags; ali@351: size_t oldlen; ali@351: size_t newlen; ali@351: char *oldpath; ali@351: char *newpath; ali@351: }; ali@351: ali@351: struct razor_relocations { ali@351: /* Ordered such that if oldpath 1 starts with oldpath 2, then ali@351: * oldpath 1 is listed first (ie., /usr/bin comes before /usr) ali@351: * and terminated with a NULL oldpath. ali@351: */ ali@351: struct razor_relocation *relocations; ali@351: int n_relocations; ali@351: char *path; ali@351: }; ali@351: ali@351: RAZOR_EXPORT struct razor_relocations *razor_relocations_create(void) ali@351: { ali@351: return calloc(1, sizeof(struct razor_relocations)); ali@351: } ali@351: ali@351: RAZOR_EXPORT void razor_relocations_add(struct razor_relocations *rr, ali@351: const char *oldpath, const char *newpath) ali@351: { ali@351: int i, found = 0; ali@351: size_t len; ali@351: ali@351: if (newpath && !strcmp(oldpath, newpath)) ali@351: newpath = NULL; ali@351: ali@351: for (i = 0; i < rr->n_relocations; i++) { ali@351: len = rr->relocations[i].oldlen; ali@351: if (!strncmp(rr->relocations[i].oldpath, oldpath, len)) { ali@351: found = !strcmp(rr->relocations[i].oldpath, oldpath); ali@351: break; ali@351: } ali@351: } ali@351: ali@351: if (!newpath) { ali@351: if (found) { ali@351: free(rr->relocations[i].oldpath); ali@351: free(rr->relocations[i].newpath); ali@351: do { ali@351: rr->relocations[i] = rr->relocations[i + 1]; ali@351: } while (rr->relocations[++i].oldpath); ali@351: } ali@351: return; ali@351: } ali@351: ali@351: if (found) { ali@351: free(rr->relocations[i].newpath); ali@351: rr->relocations[i].newpath = strdup(newpath); ali@351: rr->relocations[i].newlen = strlen(newpath); ali@351: return; ali@351: } ali@351: ali@351: if (!rr->n_relocations++) ali@351: rr->relocations = calloc(1, sizeof *rr->relocations); ali@351: else { ali@351: rr->relocations = realloc(rr->relocations, ali@351: rr->n_relocations * sizeof *rr->relocations); ali@351: memmove(rr->relocations + i + 1, rr->relocations + i, ali@351: (rr->n_relocations - i - 1) * sizeof *rr->relocations); ali@351: } ali@351: ali@351: rr->relocations[i].flags = 0; ali@351: rr->relocations[i].oldpath = strdup(oldpath); ali@351: rr->relocations[i].newpath = strdup(newpath); ali@351: rr->relocations[i].oldlen = strlen(oldpath); ali@351: rr->relocations[i].newlen = strlen(newpath); ali@351: } ali@351: ali@351: RAZOR_EXPORT void ali@351: razor_relocations_set_rpm(struct razor_relocations *rr, struct razor_rpm *rpm) ali@351: { ali@351: int i, j; ali@351: ali@351: for (i = 0; i < rr->n_relocations; i++) { ali@351: rr->relocations[i].flags &= ~RAZOR_RELOCATION_ACTIVE; ali@351: for (j = 0; j < rpm->n_prefixes; j++) ali@351: if (!strcmp(rpm->prefixes[j], ali@351: rr->relocations[i].oldpath)) { ali@351: rr->relocations[i].flags |= RAZOR_RELOCATION_ACTIVE; ali@351: break; ali@351: } ali@351: } ali@351: } ali@351: ali@351: RAZOR_EXPORT const char * ali@351: razor_relocations_apply(struct razor_relocations *rr, const char *path) ali@351: { ali@351: int i; ali@351: size_t len; ali@351: ali@351: for (i = 0; i < rr->n_relocations; i++) ali@351: if (rr->relocations[i].flags & RAZOR_RELOCATION_ACTIVE && ali@351: !strncmp(path, rr->relocations[i].oldpath, ali@351: rr->relocations[i].oldlen)) ali@351: break; ali@351: ali@351: if (i < rr->n_relocations) { ali@351: free(rr->path); ali@351: len = strlen(path + rr->relocations[i].oldlen) + ali@351: rr->relocations[i].newlen; ali@351: rr->path = malloc(len + 1); ali@351: memcpy(rr->path, rr->relocations[i].newpath, ali@351: rr->relocations[i].newlen); ali@351: strcpy(rr->path + rr->relocations[i].newlen, ali@351: path + rr->relocations[i].oldlen); ali@351: return rr->path; ali@351: } else ali@351: return path; ali@351: } ali@351: ali@351: RAZOR_EXPORT void razor_relocations_destroy(struct razor_relocations *rr) ali@351: { ali@351: printf("razor_relocations_destroy(rr=%p): path=%p, rel=%p\n", ali@351: rr,rr->path,rr->relocations); ali@351: free(rr->path); ali@351: free(rr->relocations); ali@351: free(rr); ali@351: } ali@351: rhughes@241: static struct rpm_header_index * rhughes@241: razor_rpm_get_header(struct razor_rpm *rpm, unsigned int tag) rhughes@241: { rhughes@241: struct rpm_header_index *index, *end; rhughes@241: rhughes@241: index = (struct rpm_header_index *) (rpm->header + 1); rhughes@241: end = index + ntohl(rpm->header->nindex); rhughes@241: while (index < end) { rhughes@241: if (ntohl(index->tag) == tag) rhughes@241: return index; rhughes@241: index++; rhughes@241: } rhughes@241: rhughes@241: return NULL; rhughes@241: } rhughes@241: rhughes@241: static const void * rhughes@241: razor_rpm_get_indirect(struct razor_rpm *rpm, rhughes@241: unsigned int tag, unsigned int *count) rhughes@241: { rhughes@241: struct rpm_header_index *index; rhughes@241: rhughes@241: index = razor_rpm_get_header(rpm, tag); rhughes@241: if (index != NULL) { rhughes@241: if (count) rhughes@241: *count = ntohl(index->count); rhughes@241: rhughes@241: return rpm->pool + ntohl(index->offset); rhughes@241: } rhughes@241: rhughes@241: return NULL; rhughes@241: } rhughes@241: krh@247: static uint32_t rhughes@241: rpm_to_razor_flags(uint32_t flags) rhughes@241: { krh@247: uint32_t razor_flags; rhughes@241: krh@247: razor_flags = 0; krh@247: if (flags & RPMSENSE_LESS) krh@247: razor_flags |= RAZOR_PROPERTY_LESS; krh@247: if (flags & RPMSENSE_EQUAL) krh@247: razor_flags |= RAZOR_PROPERTY_EQUAL; krh@247: if (flags & RPMSENSE_GREATER) krh@247: razor_flags |= RAZOR_PROPERTY_GREATER; krh@247: krh@247: if (flags & RPMSENSE_SCRIPT_PRE) krh@247: razor_flags |= RAZOR_PROPERTY_PRE; krh@247: if (flags & RPMSENSE_SCRIPT_POST) krh@247: razor_flags |= RAZOR_PROPERTY_POST; krh@247: if (flags & RPMSENSE_SCRIPT_PREUN) krh@247: razor_flags |= RAZOR_PROPERTY_PREUN; krh@247: if (flags & RPMSENSE_SCRIPT_POSTUN) krh@247: razor_flags |= RAZOR_PROPERTY_POSTUN; krh@247: krh@247: return razor_flags; rhughes@241: } rhughes@241: rhughes@241: static void krh@247: import_properties(struct razor_importer *importer, uint32_t type, rhughes@241: struct razor_rpm *rpm, rhughes@241: int name_tag, int version_tag, int flags_tag) rhughes@241: { rhughes@241: const char *name, *version; rhughes@241: const uint32_t *flags; rhughes@241: uint32_t f; rhughes@241: unsigned int i, count; rhughes@241: rhughes@241: name = razor_rpm_get_indirect(rpm, name_tag, &count); rhughes@241: if (name == NULL) rhughes@241: return; rhughes@241: rhughes@241: flags = razor_rpm_get_indirect(rpm, flags_tag, &count); rhughes@241: rhughes@241: version = razor_rpm_get_indirect(rpm, version_tag, &count); rhughes@241: for (i = 0; i < count; i++) { rhughes@241: f = rpm_to_razor_flags(ntohl(flags[i])); krh@247: razor_importer_add_property(importer, name, f | type, version); rhughes@241: name += strlen(name) + 1; rhughes@241: version += strlen(version) + 1; rhughes@241: } rhughes@241: } rhughes@241: rhughes@241: static void rhughes@241: import_files(struct razor_importer *importer, struct razor_rpm *rpm) rhughes@241: { rhughes@241: const char *name; rhughes@241: const uint32_t *index; rhughes@241: unsigned int i, count; rhughes@241: char buffer[256]; rhughes@241: krh@246: if (rpm->dirs == NULL) krh@246: return; krh@246: rhughes@241: /* assert: count is the same for all arrays */ rhughes@241: index = razor_rpm_get_indirect(rpm, RPMTAG_DIRINDEXES, &count); rhughes@241: name = razor_rpm_get_indirect(rpm, RPMTAG_BASENAMES, &count); rhughes@241: for (i = 0; i < count; i++) { rhughes@241: snprintf(buffer, sizeof buffer, rhughes@241: "%s%s", rpm->dirs[ntohl(*index)], name); rhughes@241: razor_importer_add_file(importer, buffer); rhughes@241: name += strlen(name) + 1; rhughes@241: index++; rhughes@241: } rhughes@241: } rhughes@241: krh@269: RAZOR_EXPORT struct razor_rpm * rhughes@241: razor_rpm_open(const char *filename) rhughes@241: { rhughes@241: struct razor_rpm *rpm; rhughes@241: struct rpm_header_index *base, *index; rhughes@241: unsigned int count, i, nindex, hsize; ali@351: const char *name, *prefix; rhughes@241: richard@301: assert (filename != NULL); richard@301: rhughes@241: rpm = malloc(sizeof *rpm); krh@246: if (rpm == NULL) krh@246: return NULL; rhughes@241: memset(rpm, 0, sizeof *rpm); rhughes@241: ali@322: rpm->map = razor_file_get_contents(filename, &rpm->size); ali@322: if (!rpm->map) { ali@339: fprintf(stderr, "couldn't get contents of %s (%s)\n", filename, ali@339: strerror(errno)); rhughes@241: return NULL; rhughes@241: } rhughes@241: rhughes@241: rpm->signature = rpm->map + RPM_LEAD_SIZE; rhughes@241: nindex = ntohl(rpm->signature->nindex); rhughes@241: hsize = ntohl(rpm->signature->hsize); rhughes@241: rpm->header = (void *) (rpm->signature + 1) + rhughes@241: ALIGN(nindex * sizeof *index + hsize, 8); rhughes@241: nindex = ntohl(rpm->header->nindex); rhughes@241: hsize = ntohl(rpm->header->hsize); rhughes@241: rpm->payload = (void *) (rpm->header + 1) + rhughes@241: nindex * sizeof *index + hsize; rhughes@241: rhughes@241: base = (struct rpm_header_index *) (rpm->header + 1); rhughes@241: rpm->pool = (void *) base + nindex * sizeof *index; rhughes@241: rhughes@241: /* Look up dir names now so we can index them directly. */ rhughes@241: name = razor_rpm_get_indirect(rpm, RPMTAG_DIRNAMES, &count); rhughes@241: if (name) { rhughes@241: rpm->dirs = calloc(count, sizeof *rpm->dirs); rhughes@241: for (i = 0; i < count; i++) { rhughes@241: rpm->dirs[i] = name; rhughes@241: name += strlen(name) + 1; rhughes@241: } rhughes@241: } else { rhughes@241: name = razor_rpm_get_indirect(rpm, RPMTAG_OLDFILENAMES, rhughes@241: &count); rhughes@241: if (name) { rhughes@241: fprintf(stderr, "old filenames not supported\n"); rhughes@241: return NULL; rhughes@241: } rhughes@241: } rhughes@241: ali@351: prefix = razor_rpm_get_indirect(rpm, RPMTAG_PREFIXES, &count); ali@351: if (prefix) { ali@351: rpm->prefixes = calloc(count, sizeof *rpm->prefixes); ali@351: for (i = 0; i < count; i++) { ali@351: rpm->prefixes[i] = prefix; ali@351: prefix += strlen(prefix) + 1; ali@351: } ali@351: rpm->n_prefixes = count; ali@351: } else { ali@351: prefix = razor_rpm_get_indirect(rpm, RPMTAG_DEFAULTPREFIX, ali@351: &count); ali@351: if (prefix) { ali@351: fprintf(stderr, "default prefix not supported\n"); ali@351: return NULL; ali@351: } ali@351: } ali@351: rhughes@241: return rpm; rhughes@241: } rhughes@241: ali@351: RAZOR_EXPORT void razor_rpm_set_relocations(struct razor_rpm *rpm, ali@351: struct razor_relocations *rr) ali@351: { ali@351: assert (rpm != NULL); ali@351: ali@351: rpm->relocations = rr; ali@351: } ali@351: rhughes@241: struct cpio_file_header { rhughes@241: char magic[6]; rhughes@241: char inode[8]; rhughes@241: char mode[8]; rhughes@241: char uid[8]; rhughes@241: char gid[8]; rhughes@241: char nlink[8]; rhughes@241: char mtime[8]; rhughes@241: char filesize[8]; rhughes@241: char devmajor[8]; rhughes@241: char devminor[8]; rhughes@241: char rdevmajor[8]; rhughes@241: char rdevminor[8]; rhughes@241: char namesize[8]; rhughes@241: char checksum[8]; rhughes@241: char filename[0]; rhughes@241: }; rhughes@241: rhughes@241: /* gzip flags */ rhughes@241: #define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */ rhughes@241: #define HEAD_CRC 0x02 /* bit 1 set: header CRC present */ rhughes@241: #define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */ rhughes@241: #define ORIG_NAME 0x08 /* bit 3 set: original file name present */ rhughes@241: #define COMMENT 0x10 /* bit 4 set: file comment present */ rhughes@241: #define RESERVED 0xE0 /* bits 5..7: reserved */ rhughes@241: rhughes@241: struct installer { rhughes@241: const char *root; rhughes@241: struct razor_rpm *rpm; rhughes@241: z_stream stream; rhughes@241: unsigned char buffer[32768]; rhughes@241: size_t rest, length; rhughes@241: }; rhughes@241: rhughes@241: static int rhughes@241: installer_inflate(struct installer *installer) rhughes@241: { rhughes@241: size_t length; rhughes@241: int err; rhughes@241: rhughes@241: if (installer->rest > sizeof installer->buffer) rhughes@241: length = sizeof installer->buffer; rhughes@241: else rhughes@241: length = installer->rest; rhughes@241: rhughes@241: installer->stream.next_out = installer->buffer; rhughes@241: installer->stream.avail_out = length; rhughes@241: err = inflate(&installer->stream, Z_SYNC_FLUSH); rhughes@241: if (err != Z_OK && err != Z_STREAM_END) { ali@339: fprintf(stderr, "inflate error: %d (%s)\n", err, ali@339: strerror(errno)); rhughes@241: return -1; rhughes@241: } rhughes@241: rhughes@241: installer->rest -= length; rhughes@241: installer->length = length; rhughes@241: rhughes@241: return 0; rhughes@241: } rhughes@241: rhughes@241: static int rhughes@241: installer_align(struct installer *installer, size_t size) rhughes@241: { rhughes@241: unsigned char buffer[4]; rhughes@241: int err; rhughes@241: rhughes@241: installer->stream.next_out = buffer; rhughes@241: installer->stream.avail_out = rhughes@241: (size - installer->stream.total_out) & (size - 1); rhughes@241: rhughes@241: if (installer->stream.avail_out == 0) rhughes@241: return 0; rhughes@241: rhughes@241: err = inflate(&installer->stream, Z_SYNC_FLUSH); rhughes@241: if (err != Z_OK && err != Z_STREAM_END) { ali@339: fprintf(stderr, "inflate error: %d (%s)\n", err, ali@339: strerror(errno)); rhughes@241: return -1; rhughes@241: } rhughes@241: rhughes@241: return 0; rhughes@241: } rhughes@241: rhughes@241: static int rhughes@241: create_path(struct installer *installer, const char *path, unsigned int mode) rhughes@241: { rhughes@241: char buffer[PATH_MAX]; rhughes@241: struct stat buf; rhughes@241: int fd, ret; rhughes@241: rhughes@241: if (razor_create_dir(installer->root, path) < 0) rhughes@241: return -1; rhughes@241: rhughes@241: snprintf(buffer, sizeof buffer, "%s%s", installer->root, path); rhughes@241: rhughes@241: switch (mode >> 12) { rhughes@241: case REG: rhughes@241: /* FIXME: handle the case where a file is already there. */ ali@345: fd = open(buffer, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, ali@345: mode & 0x1ff); rhughes@241: if (fd < 0){ rhughes@241: fprintf(stderr, "failed to create file %s\n", buffer); rhughes@241: return -1; rhughes@241: } rhughes@241: while (installer->rest > 0) { rhughes@241: if (installer_inflate(installer)) { rhughes@241: fprintf(stderr, "failed to inflate\n"); rhughes@241: return -1; rhughes@241: } rhughes@241: if (razor_write(fd, installer->buffer, rhughes@241: installer->length)) { rhughes@241: fprintf(stderr, "failed to write payload\n"); rhughes@241: return -1; rhughes@241: } rhughes@241: } rhughes@241: if (close(fd) < 0) { ali@339: fprintf(stderr, "failed to close %s: %s\n", buffer, ali@339: strerror(errno)); rhughes@241: return -1; rhughes@241: } rhughes@241: return 0; rhughes@241: case XDIR: rhughes@241: ret = mkdir(buffer, mode & 0x1ff); rhughes@241: if (ret == 0 || errno != EEXIST) rhughes@241: return ret; rhughes@241: if (stat(buffer, &buf) || !S_ISDIR(buf.st_mode)) { rhughes@241: /* FIXME: also check that mode match. */ rhughes@241: fprintf(stderr, rhughes@241: "%s exists but is not a directory\n", buffer); rhughes@241: return -1; rhughes@241: } rhughes@241: return 0; rhughes@241: case LINK: ali@327: #if HAVE_SYMLINK rhughes@241: if (installer_inflate(installer)) { rhughes@241: fprintf(stderr, "failed to inflate\n"); rhughes@241: return -1; rhughes@241: } rhughes@241: if (installer->length >= sizeof installer->buffer) { rhughes@241: fprintf(stderr, "link name too long\n"); rhughes@241: return -1; rhughes@241: } rhughes@241: installer->buffer[installer->length] = '\0'; rhughes@241: if (symlink((const char *) installer->buffer, buffer)) { ali@339: perror("failed to create symlink"); rhughes@241: return -1; rhughes@241: } rhughes@241: return 0; ali@327: #else ali@327: /* fall through */ ali@327: #endif ali@327: case PIPE: ali@327: case CDEV: ali@327: case BDEV: ali@327: case SOCK: ali@327: printf("%s: unhandled file type %d\n", buffer, mode >> 12); ali@327: return 0; rhughes@241: default: rhughes@241: printf("%s: unknown file type %d\n", buffer, mode >> 12); rhughes@241: return 0; rhughes@241: } rhughes@241: } rhughes@241: rhughes@241: static int rhughes@241: run_script(struct installer *installer, rhughes@241: unsigned int program_tag, unsigned int script_tag) rhughes@241: { ali@328: #if HAVE_CHROOT rhughes@241: int pid, status, fd[2]; ali@328: #else ali@328: FILE *fp; ali@328: #endif rhughes@241: const char *script = NULL, *program = NULL; rhughes@241: rhughes@241: program = razor_rpm_get_indirect(installer->rpm, program_tag, NULL); rhughes@241: script = razor_rpm_get_indirect(installer->rpm, script_tag, NULL); rhughes@241: if (program == NULL && script == NULL) { rhughes@241: return 0; rhughes@241: } else if (program == NULL) { ali@328: #if MSWIN_API ali@328: program = getenv("COMSPEC"); ali@328: if (program) { ali@328: program = strchr(program, '='); ali@328: if (program) ali@328: program++; ali@328: } ali@328: if (!program) ali@328: program = "c:\\windows\\system32\\cmd.exe"; ali@328: #else rhughes@241: program = "/bin/sh"; ali@328: #endif rhughes@241: } rhughes@241: ali@328: #if HAVE_CHROOT rhughes@241: if (pipe(fd) < 0) { rhughes@241: fprintf(stderr, "failed to create pipe\n"); rhughes@241: return -1; rhughes@241: } rhughes@241: pid = fork(); rhughes@241: if (pid < 0) { ali@339: perror("failed to fork"); rhughes@241: } else if (pid == 0) { rhughes@241: if (dup2(fd[0], STDIN_FILENO) < 0) { ali@339: perror("failed redirect stdin"); krh@256: exit(-1); rhughes@241: } rhughes@241: if (close(fd[0]) < 0 || close(fd[1]) < 0) { ali@339: perror("failed to close pipe"); krh@256: exit(-1); rhughes@241: } rhughes@241: if (chroot(installer->root) < 0) { ali@339: fprintf(stderr, "failed to chroot to %s: %s\n", ali@339: installer->root, strerror(errno)); krh@256: exit(-1); rhughes@241: } rhughes@241: printf("executing program %s in chroot %s\n", rhughes@241: program, installer->root); rhughes@241: if (execl(program, program, NULL)) { ali@339: fprintf(stderr, "failed to exec %s: %s\n", program, ali@339: strerror(errno)); rhughes@241: exit(-1); rhughes@241: } rhughes@241: } else { rhughes@241: if (script && razor_write(fd[1], script, strlen(script)) < 0) { ali@339: perror("failed to pipe script"); rhughes@241: return -1; rhughes@241: } rhughes@241: if (close(fd[0]) || close(fd[1])) { ali@339: perror("failed to close pipe"); rhughes@241: return -1; rhughes@241: } rhughes@241: if (wait(&status) < 0) { ali@339: perror("wait for child failed"); rhughes@241: return -1; rhughes@241: } rhughes@241: if (status) rhughes@241: printf("script exited with status %d\n", status); rhughes@241: } ali@328: #else ali@328: fp = popen(program, "w"); ali@328: if (fwrite(script, strlen(script), 1, fp) != 1) { ali@339: perror("failed to pipe script"); ali@328: return -1; ali@328: } ali@328: pclose(fp); ali@328: #endif rhughes@241: rhughes@241: return 0; rhughes@241: } rhughes@241: rhughes@241: static int rhughes@241: installer_init(struct installer *installer) rhughes@241: { rhughes@241: unsigned char *gz_header; rhughes@241: int method, flags, err; rhughes@241: rhughes@241: gz_header = installer->rpm->payload; rhughes@241: if (gz_header[0] != 0x1f || gz_header[1] != 0x8b) { rhughes@241: fprintf(stderr, "payload section doesn't have gz header\n"); rhughes@241: return -1; rhughes@241: } rhughes@241: rhughes@241: method = gz_header[2]; rhughes@241: flags = gz_header[3]; rhughes@241: rhughes@241: if (method != Z_DEFLATED || flags != 0) { rhughes@241: fprintf(stderr, rhughes@241: "unknown payload compression method or flags set\n"); rhughes@241: return -1; rhughes@241: } rhughes@241: rhughes@241: installer->stream.zalloc = NULL; rhughes@241: installer->stream.zfree = NULL; rhughes@241: installer->stream.opaque = NULL; rhughes@241: rhughes@241: installer->stream.next_in = gz_header + 10; rhughes@241: installer->stream.avail_in = rhughes@241: (installer->rpm->map + installer->rpm->size) - rhughes@241: (void *) installer->stream.next_in; rhughes@241: installer->stream.next_out = NULL; rhughes@241: installer->stream.avail_out = 0; rhughes@241: rhughes@241: err = inflateInit2(&installer->stream, -MAX_WBITS); rhughes@241: if (err != Z_OK) { rhughes@241: fprintf(stderr, "inflateInit error: %d\n", err); rhughes@241: return -1; rhughes@241: } rhughes@241: rhughes@241: return 0; rhughes@241: } rhughes@241: rhughes@241: static int rhughes@241: installer_finish(struct installer *installer) rhughes@241: { rhughes@241: int err; rhughes@241: rhughes@241: err = inflateEnd(&installer->stream); rhughes@241: rhughes@241: if (err != Z_OK) { rhughes@241: fprintf(stderr, "inflateEnd error: %d\n", err); rhughes@241: return -1; rhughes@241: } rhughes@241: rhughes@241: return 0; rhughes@241: } rhughes@241: rhughes@241: static unsigned long rhughes@241: fixed_hex_to_ulong(const char *hex, int length) rhughes@241: { rhughes@241: long l; rhughes@241: int i; rhughes@241: rhughes@241: for (i = 0, l = 0; i < length; i++) { rhughes@241: if (hex[i] < 'a') rhughes@241: l = l * 16 + hex[i] - '0'; rhughes@241: else rhughes@241: l = l * 16 + hex[i] - 'a' + 10; rhughes@241: } rhughes@241: rhughes@241: return l; rhughes@241: } rhughes@241: krh@269: RAZOR_EXPORT int rhughes@241: razor_rpm_install(struct razor_rpm *rpm, const char *root) rhughes@241: { rhughes@241: struct installer installer; rhughes@241: struct cpio_file_header *header; rhughes@241: struct stat buf; rhughes@241: unsigned int mode; ali@351: const char *path; rhughes@241: size_t filesize; rhughes@241: richard@301: assert (rpm != NULL); richard@301: assert (root != NULL); richard@301: rhughes@241: installer.rpm = rpm; rhughes@241: installer.root = root; rhughes@241: rhughes@241: /* FIXME: Only do this before a transaction, not per rpm. */ ali@347: if (*root && (stat(root, &buf) < 0 || !S_ISDIR(buf.st_mode))) { rhughes@241: fprintf(stderr, rhughes@241: "root installation directory \"%s\" does not exist\n", rhughes@241: root); rhughes@241: return -1; rhughes@241: } rhughes@241: ali@351: if (rpm->relocations) ali@351: razor_relocations_set_rpm(rpm->relocations, rpm); ali@351: rhughes@241: if (installer_init(&installer)) rhughes@241: return -1; rhughes@241: rhughes@241: run_script(&installer, RPMTAG_PREINPROG, RPMTAG_PREIN); rhughes@241: rhughes@241: while (installer.stream.avail_in > 0) { rhughes@241: installer.rest = sizeof *header; rhughes@241: if (installer_inflate(&installer)) rhughes@241: return -1; rhughes@241: rhughes@241: header = (struct cpio_file_header *) installer.buffer; rhughes@241: mode = fixed_hex_to_ulong(header->mode, sizeof header->mode); rhughes@241: filesize = fixed_hex_to_ulong(header->filesize, rhughes@241: sizeof header->filesize); rhughes@241: rhughes@241: installer.rest = fixed_hex_to_ulong(header->namesize, rhughes@241: sizeof header->namesize); rhughes@241: rhughes@241: if (installer_inflate(&installer) || rhughes@241: installer_align(&installer, 4)) rhughes@241: return -1; rhughes@241: ali@351: path = (const char *) installer.buffer; rhughes@241: /* This convention is so lame... */ rhughes@241: if (strcmp(path, "TRAILER!!!") == 0) rhughes@241: break; rhughes@241: rhughes@241: installer.rest = filesize; ali@351: path++; ali@351: if (rpm->relocations) ali@351: path = razor_relocations_apply(rpm->relocations, path); ali@351: if (create_path(&installer, path, mode) < 0) rhughes@241: return -1; rhughes@241: if (installer_align(&installer, 4)) rhughes@241: return -1; rhughes@241: } rhughes@241: rhughes@241: if (installer_finish(&installer)) rhughes@241: return -1; rhughes@241: rhughes@241: run_script(&installer, RPMTAG_POSTINPROG, RPMTAG_POSTIN); rhughes@241: rhughes@241: return 0; rhughes@241: } rhughes@241: krh@269: RAZOR_EXPORT int rhughes@241: razor_rpm_close(struct razor_rpm *rpm) rhughes@241: { rhughes@241: int err; rhughes@241: richard@301: assert (rpm != NULL); richard@301: rhughes@241: free(rpm->dirs); ali@351: free(rpm->prefixes); ali@322: err = razor_file_free_contents(rpm->map, rpm->size); rhughes@241: free(rpm); rhughes@241: rhughes@241: return err; rhughes@241: } rhughes@241: krh@269: RAZOR_EXPORT int rhughes@241: razor_importer_add_rpm(struct razor_importer *importer, struct razor_rpm *rpm) rhughes@241: { jbowes@289: const char *name, *version, *release, *arch; jbowes@289: const char *summary, *description, *url, *license; rhughes@241: const uint32_t *epoch; rhughes@241: char evr[128], buf[16]; rhughes@241: richard@301: assert (importer != NULL); richard@301: assert (rpm != NULL); richard@301: rhughes@241: name = razor_rpm_get_indirect(rpm, RPMTAG_NAME, NULL); rhughes@241: epoch = razor_rpm_get_indirect(rpm, RPMTAG_EPOCH, NULL); rhughes@241: version = razor_rpm_get_indirect(rpm, RPMTAG_VERSION, NULL); rhughes@241: release = razor_rpm_get_indirect(rpm, RPMTAG_RELEASE, NULL); rhughes@241: arch = razor_rpm_get_indirect(rpm, RPMTAG_ARCH, NULL); jbowes@289: jbowes@258: summary = razor_rpm_get_indirect(rpm, RPMTAG_SUMMARY, NULL); jbowes@289: description = razor_rpm_get_indirect(rpm, RPMTAG_DESCRIPTION, NULL); jbowes@289: url = razor_rpm_get_indirect(rpm, RPMTAG_URL, NULL); jbowes@289: license = razor_rpm_get_indirect(rpm, RPMTAG_LICENSE, NULL); rhughes@241: rhughes@241: if (epoch) { ali@329: snprintf(buf, sizeof buf, "%lu", ntohl(*epoch)); rhughes@241: razor_build_evr(evr, sizeof evr, buf, version, release); rhughes@241: } else { rhughes@241: razor_build_evr(evr, sizeof evr, NULL, version, release); rhughes@241: } rhughes@241: razor_importer_begin_package(importer, name, evr, arch); rhughes@241: jbowes@289: razor_importer_add_details(importer, summary, description, url, jbowes@289: license); jbowes@289: rhughes@241: import_properties(importer, RAZOR_PROPERTY_REQUIRES, rpm, rhughes@241: RPMTAG_REQUIRENAME, rhughes@241: RPMTAG_REQUIREVERSION, rhughes@241: RPMTAG_REQUIREFLAGS); rhughes@241: rhughes@241: import_properties(importer, RAZOR_PROPERTY_PROVIDES, rpm, rhughes@241: RPMTAG_PROVIDENAME, rhughes@241: RPMTAG_PROVIDEVERSION, rhughes@241: RPMTAG_PROVIDEFLAGS); rhughes@241: rhughes@241: import_properties(importer, RAZOR_PROPERTY_OBSOLETES, rpm, rhughes@241: RPMTAG_OBSOLETENAME, rhughes@241: RPMTAG_OBSOLETEVERSION, rhughes@241: RPMTAG_OBSOLETEFLAGS); rhughes@241: rhughes@241: import_properties(importer, RAZOR_PROPERTY_CONFLICTS, rpm, rhughes@241: RPMTAG_CONFLICTNAME, rhughes@241: RPMTAG_CONFLICTVERSION, rhughes@241: RPMTAG_CONFLICTFLAGS); rhughes@241: rhughes@241: import_files(importer, rpm); rhughes@241: rhughes@241: razor_importer_finish_package(importer); rhughes@241: rhughes@241: return 0; rhughes@241: }