rhughes@241: /* rhughes@241: * Copyright (C) 2008 Kristian Høgsberg rhughes@241: * Copyright (C) 2008 Red Hat, Inc 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 rhughes@241: #include rhughes@241: #include rhughes@241: #include rhughes@241: #include rhughes@241: #include ali@325: #include rhughes@241: #include richard@301: #include rhughes@241: rhughes@241: #include "razor.h" rhughes@241: #include "razor-internal.h" rhughes@241: 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; rhughes@241: const char *pool; rhughes@241: void *map; rhughes@241: size_t size; rhughes@241: void *payload; rhughes@241: }; rhughes@241: 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; rhughes@241: const char *name; 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@322: fprintf(stderr, "couldn't get contents of %s (%m)\n", filename); 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: rhughes@241: return rpm; rhughes@241: } rhughes@241: 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) { rhughes@241: fprintf(stderr, "inflate error: %d (%m)\n", err); 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) { rhughes@241: fprintf(stderr, "inflate error: %d (%m)\n", err); 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. */ rhughes@241: fd = open(buffer, O_WRONLY | O_CREAT | O_TRUNC, 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) { rhughes@241: fprintf(stderr, "failed to close %s: %m\n", buffer); 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)) { rhughes@241: fprintf(stderr, "failed to create symlink, %m\n"); 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: { rhughes@241: int pid, status, fd[2]; 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) { rhughes@241: program = "/bin/sh"; rhughes@241: } rhughes@241: 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) { rhughes@241: fprintf(stderr, "failed to fork, %m\n"); rhughes@241: } else if (pid == 0) { rhughes@241: if (dup2(fd[0], STDIN_FILENO) < 0) { rhughes@241: fprintf(stderr, "failed redirect stdin, %m\n"); krh@256: exit(-1); rhughes@241: } rhughes@241: if (close(fd[0]) < 0 || close(fd[1]) < 0) { rhughes@241: fprintf(stderr, "failed to close pipe, %m\n"); krh@256: exit(-1); rhughes@241: } rhughes@241: if (chroot(installer->root) < 0) { rhughes@241: fprintf(stderr, "failed to chroot to %s, %m\n", rhughes@241: installer->root); 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)) { rhughes@241: fprintf(stderr, "failed to exec %s, %m\n", program); rhughes@241: exit(-1); rhughes@241: } rhughes@241: } else { rhughes@241: if (script && razor_write(fd[1], script, strlen(script)) < 0) { rhughes@241: fprintf(stderr, "failed to pipe script, %m\n"); rhughes@241: return -1; rhughes@241: } rhughes@241: if (close(fd[0]) || close(fd[1])) { rhughes@241: fprintf(stderr, "failed to close pipe, %m\n"); rhughes@241: return -1; rhughes@241: } rhughes@241: if (wait(&status) < 0) { rhughes@241: fprintf(stderr, "wait for child failed, %m"); rhughes@241: return -1; rhughes@241: } rhughes@241: if (status) rhughes@241: printf("script exited with status %d\n", status); rhughes@241: } 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; rhughes@241: 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. */ rhughes@241: if (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: 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: rhughes@241: path = (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; rhughes@241: if (create_path(&installer, path + 1, 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@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) { rhughes@241: snprintf(buf, sizeof buf, "%u", 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: }