1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/librazor/rpm.c Mon Jun 16 22:35:09 2008 -0400
1.3 @@ -0,0 +1,813 @@
1.4 +/*
1.5 + * Copyright (C) 2008 Kristian Høgsberg <krh@redhat.com>
1.6 + * Copyright (C) 2008 Red Hat, Inc
1.7 + *
1.8 + * This program is free software; you can redistribute it and/or modify
1.9 + * it under the terms of the GNU General Public License as published by
1.10 + * the Free Software Foundation; either version 2 of the License, or
1.11 + * (at your option) any later version.
1.12 + *
1.13 + * This program is distributed in the hope that it will be useful,
1.14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
1.15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1.16 + * GNU General Public License for more details.
1.17 + *
1.18 + * You should have received a copy of the GNU General Public License along
1.19 + * with this program; if not, write to the Free Software Foundation, Inc.,
1.20 + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
1.21 + */
1.22 +
1.23 +#include <stdio.h>
1.24 +#include <stddef.h>
1.25 +#include <stdlib.h>
1.26 +#include <string.h>
1.27 +#include <errno.h>
1.28 +#include <sys/stat.h>
1.29 +#include <sys/mman.h>
1.30 +#include <sys/types.h>
1.31 +#include <sys/wait.h>
1.32 +#include <fcntl.h>
1.33 +#include <dirent.h>
1.34 +#include <unistd.h>
1.35 +#include <arpa/inet.h>
1.36 +#include <zlib.h>
1.37 +
1.38 +#include "razor.h"
1.39 +#include "razor-internal.h"
1.40 +
1.41 +#define RPM_LEAD_SIZE 96
1.42 +
1.43 +enum {
1.44 + PIPE = 1, /*!< pipe/fifo */
1.45 + CDEV = 2, /*!< character device */
1.46 + XDIR = 4, /*!< directory */
1.47 + BDEV = 6, /*!< block device */
1.48 + REG = 8, /*!< regular file */
1.49 + LINK = 10, /*!< hard link */
1.50 + SOCK = 12 /*!< socket */
1.51 +};
1.52 +
1.53 +enum {
1.54 + RPMSENSE_LESS = (1 << 1),
1.55 + RPMSENSE_GREATER = (1 << 2),
1.56 + RPMSENSE_EQUAL = (1 << 3),
1.57 +};
1.58 +
1.59 +enum {
1.60 + RPMTAG_NAME = 1000, /* s */
1.61 + RPMTAG_VERSION = 1001, /* s */
1.62 + RPMTAG_RELEASE = 1002, /* s */
1.63 + RPMTAG_EPOCH = 1003, /* i */
1.64 + RPMTAG_SUMMARY = 1004, /* s{} */
1.65 + RPMTAG_DESCRIPTION = 1005, /* s{} */
1.66 + RPMTAG_BUILDTIME = 1006, /* i */
1.67 + RPMTAG_BUILDHOST = 1007, /* s */
1.68 + RPMTAG_INSTALLTIME = 1008, /* i */
1.69 + RPMTAG_SIZE = 1009, /* i */
1.70 + RPMTAG_DISTRIBUTION = 1010, /* s */
1.71 + RPMTAG_VENDOR = 1011, /* s */
1.72 + RPMTAG_GIF = 1012, /* x */
1.73 + RPMTAG_XPM = 1013, /* x */
1.74 + RPMTAG_LICENSE = 1014, /* s */
1.75 + RPMTAG_PACKAGER = 1015, /* s */
1.76 + RPMTAG_GROUP = 1016, /* s{} */
1.77 + RPMTAG_CHANGELOG = 1017, /*!< s[] internal */
1.78 + RPMTAG_SOURCE = 1018, /* s[] */
1.79 + RPMTAG_PATCH = 1019, /* s[] */
1.80 + RPMTAG_URL = 1020, /* s */
1.81 + RPMTAG_OS = 1021, /* s legacy used int */
1.82 + RPMTAG_ARCH = 1022, /* s legacy used int */
1.83 + RPMTAG_PREIN = 1023, /* s */
1.84 + RPMTAG_POSTIN = 1024, /* s */
1.85 + RPMTAG_PREUN = 1025, /* s */
1.86 + RPMTAG_POSTUN = 1026, /* s */
1.87 + RPMTAG_OLDFILENAMES = 1027, /* s[] obsolete */
1.88 + RPMTAG_FILESIZES = 1028, /* i */
1.89 + RPMTAG_FILESTATES = 1029, /* c */
1.90 + RPMTAG_FILEMODES = 1030, /* h */
1.91 + RPMTAG_FILEUIDS = 1031, /*!< internal */
1.92 + RPMTAG_FILEGIDS = 1032, /*!< internal */
1.93 + RPMTAG_FILERDEVS = 1033, /* h */
1.94 + RPMTAG_FILEMTIMES = 1034, /* i */
1.95 + RPMTAG_FILEMD5S = 1035, /* s[] */
1.96 + RPMTAG_FILELINKTOS = 1036, /* s[] */
1.97 + RPMTAG_FILEFLAGS = 1037, /* i */
1.98 + RPMTAG_ROOT = 1038, /*!< internal - obsolete */
1.99 + RPMTAG_FILEUSERNAME = 1039, /* s[] */
1.100 + RPMTAG_FILEGROUPNAME = 1040, /* s[] */
1.101 + RPMTAG_EXCLUDE = 1041, /*!< internal - obsolete */
1.102 + RPMTAG_EXCLUSIVE = 1042, /*!< internal - obsolete */
1.103 + RPMTAG_ICON = 1043,
1.104 + RPMTAG_SOURCERPM = 1044, /* s */
1.105 + RPMTAG_FILEVERIFYFLAGS = 1045, /* i */
1.106 + RPMTAG_ARCHIVESIZE = 1046, /* i */
1.107 + RPMTAG_PROVIDENAME = 1047, /* s[] */
1.108 + RPMTAG_REQUIREFLAGS = 1048, /* i */
1.109 + RPMTAG_REQUIRENAME = 1049, /* s[] */
1.110 + RPMTAG_REQUIREVERSION = 1050, /* s[] */
1.111 + RPMTAG_NOSOURCE = 1051, /*!< internal */
1.112 + RPMTAG_NOPATCH = 1052, /*!< internal */
1.113 + RPMTAG_CONFLICTFLAGS = 1053, /* i */
1.114 + RPMTAG_CONFLICTNAME = 1054, /* s[] */
1.115 + RPMTAG_CONFLICTVERSION = 1055, /* s[] */
1.116 + RPMTAG_DEFAULTPREFIX = 1056, /*!< internal - deprecated */
1.117 + RPMTAG_BUILDROOT = 1057, /*!< internal */
1.118 + RPMTAG_INSTALLPREFIX = 1058, /*!< internal - deprecated */
1.119 + RPMTAG_EXCLUDEARCH = 1059,
1.120 + RPMTAG_EXCLUDEOS = 1060,
1.121 + RPMTAG_EXCLUSIVEARCH = 1061,
1.122 + RPMTAG_EXCLUSIVEOS = 1062,
1.123 + RPMTAG_AUTOREQPROV = 1063, /*!< internal */
1.124 + RPMTAG_RPMVERSION = 1064, /* s */
1.125 + RPMTAG_TRIGGERSCRIPTS = 1065, /* s[] */
1.126 + RPMTAG_TRIGGERNAME = 1066, /* s[] */
1.127 + RPMTAG_TRIGGERVERSION = 1067, /* s[] */
1.128 + RPMTAG_TRIGGERFLAGS = 1068, /* i */
1.129 + RPMTAG_TRIGGERINDEX = 1069, /* i */
1.130 + RPMTAG_VERIFYSCRIPT = 1079, /* s */
1.131 + RPMTAG_CHANGELOGTIME = 1080, /* i */
1.132 + RPMTAG_CHANGELOGNAME = 1081, /* s[] */
1.133 + RPMTAG_CHANGELOGTEXT = 1082, /* s[] */
1.134 + RPMTAG_BROKENMD5 = 1083, /*!< internal - obsolete */
1.135 + RPMTAG_PREREQ = 1084, /*!< internal */
1.136 + RPMTAG_PREINPROG = 1085, /* s */
1.137 + RPMTAG_POSTINPROG = 1086, /* s */
1.138 + RPMTAG_PREUNPROG = 1087, /* s */
1.139 + RPMTAG_POSTUNPROG = 1088, /* s */
1.140 + RPMTAG_BUILDARCHS = 1089,
1.141 + RPMTAG_OBSOLETENAME = 1090, /* s[] */
1.142 + RPMTAG_VERIFYSCRIPTPROG = 1091, /* s */
1.143 + RPMTAG_TRIGGERSCRIPTPROG = 1092, /* s */
1.144 + RPMTAG_DOCDIR = 1093, /*!< internal */
1.145 + RPMTAG_COOKIE = 1094, /* s */
1.146 + RPMTAG_FILEDEVICES = 1095, /* i */
1.147 + RPMTAG_FILEINODES = 1096, /* i */
1.148 + RPMTAG_FILELANGS = 1097, /* s[] */
1.149 + RPMTAG_PREFIXES = 1098, /* s[] */
1.150 + RPMTAG_INSTPREFIXES = 1099, /* s[] */
1.151 + RPMTAG_TRIGGERIN = 1100, /*!< internal */
1.152 + RPMTAG_TRIGGERUN = 1101, /*!< internal */
1.153 + RPMTAG_TRIGGERPOSTUN = 1102, /*!< internal */
1.154 + RPMTAG_AUTOREQ = 1103, /*!< internal */
1.155 + RPMTAG_AUTOPROV = 1104, /*!< internal */
1.156 + RPMTAG_CAPABILITY = 1105, /*!< internal - obsolete */
1.157 + RPMTAG_SOURCEPACKAGE = 1106, /*!< i src.rpm header marker */
1.158 + RPMTAG_OLDORIGFILENAMES = 1107, /*!< internal - obsolete */
1.159 + RPMTAG_BUILDPREREQ = 1108, /*!< internal */
1.160 + RPMTAG_BUILDREQUIRES = 1109, /*!< internal */
1.161 + RPMTAG_BUILDCONFLICTS = 1110, /*!< internal */
1.162 + RPMTAG_BUILDMACROS = 1111, /*!< internal - unused */
1.163 + RPMTAG_PROVIDEFLAGS = 1112, /* i */
1.164 + RPMTAG_PROVIDEVERSION = 1113, /* s[] */
1.165 + RPMTAG_OBSOLETEFLAGS = 1114, /* i */
1.166 + RPMTAG_OBSOLETEVERSION = 1115, /* s[] */
1.167 + RPMTAG_DIRINDEXES = 1116, /* i */
1.168 + RPMTAG_BASENAMES = 1117, /* s[] */
1.169 + RPMTAG_DIRNAMES = 1118, /* s[] */
1.170 + RPMTAG_ORIGDIRINDEXES = 1119, /*!< internal */
1.171 + RPMTAG_ORIGBASENAMES = 1120, /*!< internal */
1.172 + RPMTAG_ORIGDIRNAMES = 1121, /*!< internal */
1.173 + RPMTAG_OPTFLAGS = 1122, /* s */
1.174 + RPMTAG_DISTURL = 1123, /* s */
1.175 + RPMTAG_PAYLOADFORMAT = 1124, /* s */
1.176 + RPMTAG_PAYLOADCOMPRESSOR = 1125, /* s */
1.177 + RPMTAG_PAYLOADFLAGS = 1126, /* s */
1.178 + RPMTAG_INSTALLCOLOR = 1127, /*!< i transaction color when installed */
1.179 + RPMTAG_INSTALLTID = 1128, /* i */
1.180 + RPMTAG_REMOVETID = 1129, /* i */
1.181 + RPMTAG_SHA1RHN = 1130, /*!< internal - obsolete */
1.182 + RPMTAG_RHNPLATFORM = 1131, /* s */
1.183 + RPMTAG_PLATFORM = 1132, /* s */
1.184 + RPMTAG_PATCHESNAME = 1133, /*!< placeholder (SuSE) */
1.185 + RPMTAG_PATCHESFLAGS = 1134, /*!< placeholder (SuSE) */
1.186 + RPMTAG_PATCHESVERSION = 1135, /*!< placeholder (SuSE) */
1.187 + RPMTAG_CACHECTIME = 1136, /* i */
1.188 + RPMTAG_CACHEPKGPATH = 1137, /* s */
1.189 + RPMTAG_CACHEPKGSIZE = 1138, /* i */
1.190 + RPMTAG_CACHEPKGMTIME = 1139, /* i */
1.191 + RPMTAG_FILECOLORS = 1140, /* i */
1.192 + RPMTAG_FILECLASS = 1141, /* i */
1.193 + RPMTAG_CLASSDICT = 1142, /* s[] */
1.194 + RPMTAG_FILEDEPENDSX = 1143, /* i */
1.195 + RPMTAG_FILEDEPENDSN = 1144, /* i */
1.196 + RPMTAG_DEPENDSDICT = 1145, /* i */
1.197 + RPMTAG_SOURCEPKGID = 1146, /* x */
1.198 + RPMTAG_FILECONTEXTS = 1147, /* s[] */
1.199 + RPMTAG_FSCONTEXTS = 1148, /*!< s[] extension */
1.200 + RPMTAG_RECONTEXTS = 1149, /*!< s[] extension */
1.201 + RPMTAG_POLICIES = 1150, /*!< s[] selinux *.te policy file. */
1.202 + RPMTAG_PRETRANS = 1151, /* s */
1.203 + RPMTAG_POSTTRANS = 1152, /* s */
1.204 + RPMTAG_PRETRANSPROG = 1153, /* s */
1.205 + RPMTAG_POSTTRANSPROG = 1154, /* s */
1.206 + RPMTAG_DISTTAG = 1155, /* s */
1.207 + RPMTAG_SUGGESTSNAME = 1156, /* s[] extension placeholder */
1.208 + RPMTAG_SUGGESTSVERSION = 1157, /* s[] extension placeholder */
1.209 + RPMTAG_SUGGESTSFLAGS = 1158, /* i extension placeholder */
1.210 + RPMTAG_ENHANCESNAME = 1159, /* s[] extension placeholder */
1.211 + RPMTAG_ENHANCESVERSION = 1160, /* s[] extension placeholder */
1.212 + RPMTAG_ENHANCESFLAGS = 1161, /* i extension placeholder */
1.213 + RPMTAG_PRIORITY = 1162, /* i extension placeholder */
1.214 + RPMTAG_CVSID = 1163, /* s */
1.215 + RPMTAG_TRIGGERPREIN = 1171, /*!< internal */
1.216 +};
1.217 +
1.218 +struct rpm_header {
1.219 + unsigned char magic[4];
1.220 + unsigned char reserved[4];
1.221 + int nindex;
1.222 + int hsize;
1.223 +};
1.224 +
1.225 +struct rpm_header_index {
1.226 + int tag;
1.227 + int type;
1.228 + int offset;
1.229 + int count;
1.230 +};
1.231 +
1.232 +struct razor_rpm {
1.233 + struct rpm_header *signature;
1.234 + struct rpm_header *header;
1.235 + const char **dirs;
1.236 + const char *pool;
1.237 + void *map;
1.238 + size_t size;
1.239 + void *payload;
1.240 +};
1.241 +
1.242 +static struct rpm_header_index *
1.243 +razor_rpm_get_header(struct razor_rpm *rpm, unsigned int tag)
1.244 +{
1.245 + struct rpm_header_index *index, *end;
1.246 +
1.247 + index = (struct rpm_header_index *) (rpm->header + 1);
1.248 + end = index + ntohl(rpm->header->nindex);
1.249 + while (index < end) {
1.250 + if (ntohl(index->tag) == tag)
1.251 + return index;
1.252 + index++;
1.253 + }
1.254 +
1.255 + return NULL;
1.256 +}
1.257 +
1.258 +static const void *
1.259 +razor_rpm_get_indirect(struct razor_rpm *rpm,
1.260 + unsigned int tag, unsigned int *count)
1.261 +{
1.262 + struct rpm_header_index *index;
1.263 +
1.264 + index = razor_rpm_get_header(rpm, tag);
1.265 + if (index != NULL) {
1.266 + if (count)
1.267 + *count = ntohl(index->count);
1.268 +
1.269 + return rpm->pool + ntohl(index->offset);
1.270 + }
1.271 +
1.272 + return NULL;
1.273 +}
1.274 +
1.275 +static enum razor_version_relation
1.276 +rpm_to_razor_flags(uint32_t flags)
1.277 +{
1.278 + switch (flags & (RPMSENSE_LESS | RPMSENSE_EQUAL | RPMSENSE_GREATER)) {
1.279 + case RPMSENSE_LESS:
1.280 + return RAZOR_VERSION_LESS;
1.281 + case RPMSENSE_LESS|RPMSENSE_EQUAL:
1.282 + return RAZOR_VERSION_LESS_OR_EQUAL;
1.283 + case RPMSENSE_EQUAL:
1.284 + return RAZOR_VERSION_EQUAL;
1.285 + case RPMSENSE_GREATER|RPMSENSE_EQUAL:
1.286 + return RAZOR_VERSION_GREATER_OR_EQUAL;
1.287 + case RPMSENSE_GREATER:
1.288 + return RAZOR_VERSION_GREATER;
1.289 + }
1.290 +
1.291 + /* FIXME? */
1.292 + return RAZOR_VERSION_EQUAL;
1.293 +}
1.294 +
1.295 +static void
1.296 +import_properties(struct razor_importer *importer, unsigned long type,
1.297 + struct razor_rpm *rpm,
1.298 + int name_tag, int version_tag, int flags_tag)
1.299 +{
1.300 + const char *name, *version;
1.301 + const uint32_t *flags;
1.302 + uint32_t f;
1.303 + unsigned int i, count;
1.304 +
1.305 + name = razor_rpm_get_indirect(rpm, name_tag, &count);
1.306 + if (name == NULL)
1.307 + return;
1.308 +
1.309 + flags = razor_rpm_get_indirect(rpm, flags_tag, &count);
1.310 +
1.311 + version = razor_rpm_get_indirect(rpm, version_tag, &count);
1.312 + for (i = 0; i < count; i++) {
1.313 + f = rpm_to_razor_flags(ntohl(flags[i]));
1.314 + razor_importer_add_property(importer, name, f, version, type);
1.315 + name += strlen(name) + 1;
1.316 + version += strlen(version) + 1;
1.317 + }
1.318 +}
1.319 +
1.320 +static void
1.321 +import_files(struct razor_importer *importer, struct razor_rpm *rpm)
1.322 +{
1.323 + const char *name;
1.324 + const uint32_t *index;
1.325 + unsigned int i, count;
1.326 + char buffer[256];
1.327 +
1.328 + /* assert: count is the same for all arrays */
1.329 +
1.330 + index = razor_rpm_get_indirect(rpm, RPMTAG_DIRINDEXES, &count);
1.331 + name = razor_rpm_get_indirect(rpm, RPMTAG_BASENAMES, &count);
1.332 + for (i = 0; i < count; i++) {
1.333 + snprintf(buffer, sizeof buffer,
1.334 + "%s%s", rpm->dirs[ntohl(*index)], name);
1.335 + razor_importer_add_file(importer, buffer);
1.336 + name += strlen(name) + 1;
1.337 + index++;
1.338 + }
1.339 +}
1.340 +
1.341 +struct razor_rpm *
1.342 +razor_rpm_open(const char *filename)
1.343 +{
1.344 + struct razor_rpm *rpm;
1.345 + struct rpm_header_index *base, *index;
1.346 + struct stat buf;
1.347 + unsigned int count, i, nindex, hsize;
1.348 + const char *name;
1.349 + int fd;
1.350 +
1.351 + rpm = malloc(sizeof *rpm);
1.352 + memset(rpm, 0, sizeof *rpm);
1.353 +
1.354 + fd = open(filename, O_RDONLY);
1.355 + if (fd < 0) {
1.356 + fprintf(stderr, "couldn't open %s\n", filename);
1.357 + return NULL;
1.358 + }
1.359 +
1.360 + if (fstat(fd, &buf) < 0) {
1.361 + fprintf(stderr, "failed to stat %s (%m)\n", filename);
1.362 + return NULL;
1.363 + }
1.364 +
1.365 + rpm->size = buf.st_size;
1.366 + rpm->map = mmap(NULL, rpm->size, PROT_READ, MAP_PRIVATE, fd, 0);
1.367 + if (rpm->map == MAP_FAILED) {
1.368 + fprintf(stderr, "couldn't mmap %s\n", filename);
1.369 + return NULL;
1.370 + }
1.371 + close(fd);
1.372 +
1.373 + rpm->signature = rpm->map + RPM_LEAD_SIZE;
1.374 + nindex = ntohl(rpm->signature->nindex);
1.375 + hsize = ntohl(rpm->signature->hsize);
1.376 + rpm->header = (void *) (rpm->signature + 1) +
1.377 + ALIGN(nindex * sizeof *index + hsize, 8);
1.378 + nindex = ntohl(rpm->header->nindex);
1.379 + hsize = ntohl(rpm->header->hsize);
1.380 + rpm->payload = (void *) (rpm->header + 1) +
1.381 + nindex * sizeof *index + hsize;
1.382 +
1.383 + base = (struct rpm_header_index *) (rpm->header + 1);
1.384 + rpm->pool = (void *) base + nindex * sizeof *index;
1.385 +
1.386 + /* Look up dir names now so we can index them directly. */
1.387 + name = razor_rpm_get_indirect(rpm, RPMTAG_DIRNAMES, &count);
1.388 + if (name) {
1.389 + rpm->dirs = calloc(count, sizeof *rpm->dirs);
1.390 + for (i = 0; i < count; i++) {
1.391 + rpm->dirs[i] = name;
1.392 + name += strlen(name) + 1;
1.393 + }
1.394 + } else {
1.395 + name = razor_rpm_get_indirect(rpm, RPMTAG_OLDFILENAMES,
1.396 + &count);
1.397 + if (name) {
1.398 + fprintf(stderr, "old filenames not supported\n");
1.399 + return NULL;
1.400 + }
1.401 + }
1.402 +
1.403 + return rpm;
1.404 +}
1.405 +
1.406 +struct cpio_file_header {
1.407 + char magic[6];
1.408 + char inode[8];
1.409 + char mode[8];
1.410 + char uid[8];
1.411 + char gid[8];
1.412 + char nlink[8];
1.413 + char mtime[8];
1.414 + char filesize[8];
1.415 + char devmajor[8];
1.416 + char devminor[8];
1.417 + char rdevmajor[8];
1.418 + char rdevminor[8];
1.419 + char namesize[8];
1.420 + char checksum[8];
1.421 + char filename[0];
1.422 +};
1.423 +
1.424 +/* gzip flags */
1.425 +#define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */
1.426 +#define HEAD_CRC 0x02 /* bit 1 set: header CRC present */
1.427 +#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */
1.428 +#define ORIG_NAME 0x08 /* bit 3 set: original file name present */
1.429 +#define COMMENT 0x10 /* bit 4 set: file comment present */
1.430 +#define RESERVED 0xE0 /* bits 5..7: reserved */
1.431 +
1.432 +struct installer {
1.433 + const char *root;
1.434 + struct razor_rpm *rpm;
1.435 + z_stream stream;
1.436 + unsigned char buffer[32768];
1.437 + size_t rest, length;
1.438 +};
1.439 +
1.440 +static int
1.441 +installer_inflate(struct installer *installer)
1.442 +{
1.443 + size_t length;
1.444 + int err;
1.445 +
1.446 + if (installer->rest > sizeof installer->buffer)
1.447 + length = sizeof installer->buffer;
1.448 + else
1.449 + length = installer->rest;
1.450 +
1.451 + installer->stream.next_out = installer->buffer;
1.452 + installer->stream.avail_out = length;
1.453 + err = inflate(&installer->stream, Z_SYNC_FLUSH);
1.454 + if (err != Z_OK && err != Z_STREAM_END) {
1.455 + fprintf(stderr, "inflate error: %d (%m)\n", err);
1.456 + return -1;
1.457 + }
1.458 +
1.459 + installer->rest -= length;
1.460 + installer->length = length;
1.461 +
1.462 + return 0;
1.463 +}
1.464 +
1.465 +static int
1.466 +installer_align(struct installer *installer, size_t size)
1.467 +{
1.468 + unsigned char buffer[4];
1.469 + int err;
1.470 +
1.471 + installer->stream.next_out = buffer;
1.472 + installer->stream.avail_out =
1.473 + (size - installer->stream.total_out) & (size - 1);
1.474 +
1.475 + if (installer->stream.avail_out == 0)
1.476 + return 0;
1.477 +
1.478 + err = inflate(&installer->stream, Z_SYNC_FLUSH);
1.479 + if (err != Z_OK && err != Z_STREAM_END) {
1.480 + fprintf(stderr, "inflate error: %d (%m)\n", err);
1.481 + return -1;
1.482 + }
1.483 +
1.484 + return 0;
1.485 +}
1.486 +
1.487 +static int
1.488 +create_path(struct installer *installer, const char *path, unsigned int mode)
1.489 +{
1.490 + char buffer[PATH_MAX];
1.491 + struct stat buf;
1.492 + int fd, ret;
1.493 +
1.494 + if (razor_create_dir(installer->root, path) < 0)
1.495 + return -1;
1.496 +
1.497 + snprintf(buffer, sizeof buffer, "%s%s", installer->root, path);
1.498 +
1.499 + switch (mode >> 12) {
1.500 + case REG:
1.501 + /* FIXME: handle the case where a file is already there. */
1.502 + fd = open(buffer, O_WRONLY | O_CREAT | O_TRUNC, mode & 0x1ff);
1.503 + if (fd < 0){
1.504 + fprintf(stderr, "failed to create file %s\n", buffer);
1.505 + return -1;
1.506 + }
1.507 + while (installer->rest > 0) {
1.508 + if (installer_inflate(installer)) {
1.509 + fprintf(stderr, "failed to inflate\n");
1.510 + return -1;
1.511 + }
1.512 + if (razor_write(fd, installer->buffer,
1.513 + installer->length)) {
1.514 + fprintf(stderr, "failed to write payload\n");
1.515 + return -1;
1.516 + }
1.517 + }
1.518 + if (close(fd) < 0) {
1.519 + fprintf(stderr, "failed to close %s: %m\n", buffer);
1.520 + return -1;
1.521 + }
1.522 + return 0;
1.523 + case XDIR:
1.524 + ret = mkdir(buffer, mode & 0x1ff);
1.525 + if (ret == 0 || errno != EEXIST)
1.526 + return ret;
1.527 + if (stat(buffer, &buf) || !S_ISDIR(buf.st_mode)) {
1.528 + /* FIXME: also check that mode match. */
1.529 + fprintf(stderr,
1.530 + "%s exists but is not a directory\n", buffer);
1.531 + return -1;
1.532 + }
1.533 + return 0;
1.534 + case PIPE:
1.535 + case CDEV:
1.536 + case BDEV:
1.537 + case SOCK:
1.538 + printf("%s: unhandled file type %d\n", buffer, mode >> 12);
1.539 + return 0;
1.540 + case LINK:
1.541 + if (installer_inflate(installer)) {
1.542 + fprintf(stderr, "failed to inflate\n");
1.543 + return -1;
1.544 + }
1.545 + if (installer->length >= sizeof installer->buffer) {
1.546 + fprintf(stderr, "link name too long\n");
1.547 + return -1;
1.548 + }
1.549 + installer->buffer[installer->length] = '\0';
1.550 + if (symlink((const char *) installer->buffer, buffer)) {
1.551 + fprintf(stderr, "failed to create symlink, %m\n");
1.552 + return -1;
1.553 + }
1.554 + return 0;
1.555 + default:
1.556 + printf("%s: unknown file type %d\n", buffer, mode >> 12);
1.557 + return 0;
1.558 + }
1.559 +}
1.560 +
1.561 +static int
1.562 +run_script(struct installer *installer,
1.563 + unsigned int program_tag, unsigned int script_tag)
1.564 +{
1.565 + int pid, status, fd[2];
1.566 + const char *script = NULL, *program = NULL;
1.567 +
1.568 + program = razor_rpm_get_indirect(installer->rpm, program_tag, NULL);
1.569 + script = razor_rpm_get_indirect(installer->rpm, script_tag, NULL);
1.570 + if (program == NULL && script == NULL) {
1.571 + return 0;
1.572 + } else if (program == NULL) {
1.573 + program = "/bin/sh";
1.574 + }
1.575 +
1.576 + if (pipe(fd) < 0) {
1.577 + fprintf(stderr, "failed to create pipe\n");
1.578 + return -1;
1.579 + }
1.580 + pid = fork();
1.581 + if (pid < 0) {
1.582 + fprintf(stderr, "failed to fork, %m\n");
1.583 + } else if (pid == 0) {
1.584 + if (dup2(fd[0], STDIN_FILENO) < 0) {
1.585 + fprintf(stderr, "failed redirect stdin, %m\n");
1.586 + return -1;
1.587 + }
1.588 + if (close(fd[0]) < 0 || close(fd[1]) < 0) {
1.589 + fprintf(stderr, "failed to close pipe, %m\n");
1.590 + return -1;
1.591 + }
1.592 + if (chroot(installer->root) < 0) {
1.593 + fprintf(stderr, "failed to chroot to %s, %m\n",
1.594 + installer->root);
1.595 + return -1;
1.596 + }
1.597 + printf("executing program %s in chroot %s\n",
1.598 + program, installer->root);
1.599 + if (execl(program, program, NULL)) {
1.600 + fprintf(stderr, "failed to exec %s, %m\n", program);
1.601 + exit(-1);
1.602 + }
1.603 + } else {
1.604 + if (script && razor_write(fd[1], script, strlen(script)) < 0) {
1.605 + fprintf(stderr, "failed to pipe script, %m\n");
1.606 + return -1;
1.607 + }
1.608 + if (close(fd[0]) || close(fd[1])) {
1.609 + fprintf(stderr, "failed to close pipe, %m\n");
1.610 + return -1;
1.611 + }
1.612 + if (wait(&status) < 0) {
1.613 + fprintf(stderr, "wait for child failed, %m");
1.614 + return -1;
1.615 + }
1.616 + if (status)
1.617 + printf("script exited with status %d\n", status);
1.618 + }
1.619 +
1.620 + return 0;
1.621 +}
1.622 +
1.623 +static int
1.624 +installer_init(struct installer *installer)
1.625 +{
1.626 + unsigned char *gz_header;
1.627 + int method, flags, err;
1.628 +
1.629 + gz_header = installer->rpm->payload;
1.630 + if (gz_header[0] != 0x1f || gz_header[1] != 0x8b) {
1.631 + fprintf(stderr, "payload section doesn't have gz header\n");
1.632 + return -1;
1.633 + }
1.634 +
1.635 + method = gz_header[2];
1.636 + flags = gz_header[3];
1.637 +
1.638 + if (method != Z_DEFLATED || flags != 0) {
1.639 + fprintf(stderr,
1.640 + "unknown payload compression method or flags set\n");
1.641 + return -1;
1.642 + }
1.643 +
1.644 + installer->stream.zalloc = NULL;
1.645 + installer->stream.zfree = NULL;
1.646 + installer->stream.opaque = NULL;
1.647 +
1.648 + installer->stream.next_in = gz_header + 10;
1.649 + installer->stream.avail_in =
1.650 + (installer->rpm->map + installer->rpm->size) -
1.651 + (void *) installer->stream.next_in;
1.652 + installer->stream.next_out = NULL;
1.653 + installer->stream.avail_out = 0;
1.654 +
1.655 + err = inflateInit2(&installer->stream, -MAX_WBITS);
1.656 + if (err != Z_OK) {
1.657 + fprintf(stderr, "inflateInit error: %d\n", err);
1.658 + return -1;
1.659 + }
1.660 +
1.661 + return 0;
1.662 +}
1.663 +
1.664 +static int
1.665 +installer_finish(struct installer *installer)
1.666 +{
1.667 + int err;
1.668 +
1.669 + err = inflateEnd(&installer->stream);
1.670 +
1.671 + if (err != Z_OK) {
1.672 + fprintf(stderr, "inflateEnd error: %d\n", err);
1.673 + return -1;
1.674 + }
1.675 +
1.676 + return 0;
1.677 +}
1.678 +
1.679 +static unsigned long
1.680 +fixed_hex_to_ulong(const char *hex, int length)
1.681 +{
1.682 + long l;
1.683 + int i;
1.684 +
1.685 + for (i = 0, l = 0; i < length; i++) {
1.686 + if (hex[i] < 'a')
1.687 + l = l * 16 + hex[i] - '0';
1.688 + else
1.689 + l = l * 16 + hex[i] - 'a' + 10;
1.690 + }
1.691 +
1.692 + return l;
1.693 +}
1.694 +
1.695 +int
1.696 +razor_rpm_install(struct razor_rpm *rpm, const char *root)
1.697 +{
1.698 + struct installer installer;
1.699 + struct cpio_file_header *header;
1.700 + struct stat buf;
1.701 + unsigned int mode;
1.702 + char *path;
1.703 + size_t filesize;
1.704 +
1.705 + installer.rpm = rpm;
1.706 + installer.root = root;
1.707 +
1.708 + /* FIXME: Only do this before a transaction, not per rpm. */
1.709 + if (stat(root, &buf) < 0 || !S_ISDIR(buf.st_mode)) {
1.710 + fprintf(stderr,
1.711 + "root installation directory \"%s\" does not exist\n",
1.712 + root);
1.713 + return -1;
1.714 + }
1.715 +
1.716 + if (installer_init(&installer))
1.717 + return -1;
1.718 +
1.719 + run_script(&installer, RPMTAG_PREINPROG, RPMTAG_PREIN);
1.720 +
1.721 + while (installer.stream.avail_in > 0) {
1.722 + installer.rest = sizeof *header;
1.723 + if (installer_inflate(&installer))
1.724 + return -1;
1.725 +
1.726 + header = (struct cpio_file_header *) installer.buffer;
1.727 + mode = fixed_hex_to_ulong(header->mode, sizeof header->mode);
1.728 + filesize = fixed_hex_to_ulong(header->filesize,
1.729 + sizeof header->filesize);
1.730 +
1.731 + installer.rest = fixed_hex_to_ulong(header->namesize,
1.732 + sizeof header->namesize);
1.733 +
1.734 + if (installer_inflate(&installer) ||
1.735 + installer_align(&installer, 4))
1.736 + return -1;
1.737 +
1.738 + path = (char *) installer.buffer;
1.739 + /* This convention is so lame... */
1.740 + if (strcmp(path, "TRAILER!!!") == 0)
1.741 + break;
1.742 +
1.743 + installer.rest = filesize;
1.744 + if (create_path(&installer, path + 1, mode) < 0)
1.745 + return -1;
1.746 + if (installer_align(&installer, 4))
1.747 + return -1;
1.748 + }
1.749 +
1.750 + if (installer_finish(&installer))
1.751 + return -1;
1.752 +
1.753 + run_script(&installer, RPMTAG_POSTINPROG, RPMTAG_POSTIN);
1.754 +
1.755 + return 0;
1.756 +}
1.757 +
1.758 +int
1.759 +razor_rpm_close(struct razor_rpm *rpm)
1.760 +{
1.761 + int err;
1.762 +
1.763 + free(rpm->dirs);
1.764 + err = munmap(rpm->map, rpm->size);
1.765 + free(rpm);
1.766 +
1.767 + return err;
1.768 +}
1.769 +
1.770 +int
1.771 +razor_importer_add_rpm(struct razor_importer *importer, struct razor_rpm *rpm)
1.772 +{
1.773 + const char *name, *version, *release, *arch;
1.774 + const uint32_t *epoch;
1.775 + char evr[128], buf[16];
1.776 +
1.777 + name = razor_rpm_get_indirect(rpm, RPMTAG_NAME, NULL);
1.778 + epoch = razor_rpm_get_indirect(rpm, RPMTAG_EPOCH, NULL);
1.779 + version = razor_rpm_get_indirect(rpm, RPMTAG_VERSION, NULL);
1.780 + release = razor_rpm_get_indirect(rpm, RPMTAG_RELEASE, NULL);
1.781 + arch = razor_rpm_get_indirect(rpm, RPMTAG_ARCH, NULL);
1.782 +
1.783 + if (epoch) {
1.784 + snprintf(buf, sizeof buf, "%u", ntohl(*epoch));
1.785 + razor_build_evr(evr, sizeof evr, buf, version, release);
1.786 + } else {
1.787 + razor_build_evr(evr, sizeof evr, NULL, version, release);
1.788 + }
1.789 + razor_importer_begin_package(importer, name, evr, arch);
1.790 +
1.791 + import_properties(importer, RAZOR_PROPERTY_REQUIRES, rpm,
1.792 + RPMTAG_REQUIRENAME,
1.793 + RPMTAG_REQUIREVERSION,
1.794 + RPMTAG_REQUIREFLAGS);
1.795 +
1.796 + import_properties(importer, RAZOR_PROPERTY_PROVIDES, rpm,
1.797 + RPMTAG_PROVIDENAME,
1.798 + RPMTAG_PROVIDEVERSION,
1.799 + RPMTAG_PROVIDEFLAGS);
1.800 +
1.801 + import_properties(importer, RAZOR_PROPERTY_OBSOLETES, rpm,
1.802 + RPMTAG_OBSOLETENAME,
1.803 + RPMTAG_OBSOLETEVERSION,
1.804 + RPMTAG_OBSOLETEFLAGS);
1.805 +
1.806 + import_properties(importer, RAZOR_PROPERTY_CONFLICTS, rpm,
1.807 + RPMTAG_CONFLICTNAME,
1.808 + RPMTAG_CONFLICTVERSION,
1.809 + RPMTAG_CONFLICTFLAGS);
1.810 +
1.811 + import_files(importer, rpm);
1.812 +
1.813 + razor_importer_finish_package(importer);
1.814 +
1.815 + return 0;
1.816 +}