rpm.c
author Kristian H?gsberg <krh@redhat.com>
Thu Dec 27 17:45:18 2007 -0500 (2007-12-27)
changeset 86 e44ccd213756
parent 85 c5041a93b91a
child 87 c1e04d4e3bc9
permissions -rw-r--r--
Extend installer implementation further.
krh@74
     1
#include <stdio.h>
krh@84
     2
#include <stddef.h>
krh@74
     3
#include <string.h>
krh@74
     4
#include <sys/stat.h>
krh@74
     5
#include <sys/mman.h>
krh@85
     6
#include <sys/types.h>
krh@85
     7
#include <sys/wait.h>
krh@74
     8
#include <fcntl.h>
krh@74
     9
#include <unistd.h>
krh@74
    10
#include <arpa/inet.h>
krh@74
    11
#include <rpm/rpmlib.h>
krh@77
    12
#include <zlib.h>
krh@74
    13
krh@75
    14
#include "razor.h"
krh@75
    15
krh@74
    16
#define	RPM_LEAD_SIZE 96
krh@74
    17
krh@74
    18
struct rpm_lead {
krh@74
    19
	unsigned char magic[4];
krh@74
    20
	unsigned char major;
krh@74
    21
	unsigned char minor;
krh@74
    22
	short type;
krh@74
    23
	short archnum;
krh@74
    24
	char name[66];
krh@74
    25
	short osnum;
krh@74
    26
	short signature_type;
krh@74
    27
	char reserved[16];
krh@74
    28
};
krh@74
    29
krh@74
    30
struct rpm_header {
krh@74
    31
	unsigned char magic[4];
krh@74
    32
	unsigned char reserved[4];
krh@74
    33
	int nindex;
krh@74
    34
	int hsize;
krh@74
    35
};
krh@74
    36
krh@74
    37
struct rpm_header_index {
krh@74
    38
	int tag;
krh@74
    39
	int type;
krh@74
    40
	int offset;
krh@74
    41
	int count;
krh@74
    42
};
krh@74
    43
krh@75
    44
struct properties {
krh@75
    45
	struct rpm_header_index *name;
krh@75
    46
	struct rpm_header_index *version;
krh@75
    47
	struct rpm_header_index *flags;
krh@75
    48
};
krh@75
    49
krh@77
    50
struct razor_rpm {
krh@75
    51
	struct rpm_header *signature;
krh@75
    52
	struct rpm_header *header;
krh@75
    53
krh@75
    54
	struct rpm_header_index *name;
krh@75
    55
	struct rpm_header_index *version;
krh@75
    56
	struct rpm_header_index *release;
krh@75
    57
krh@75
    58
	struct rpm_header_index *dirnames;
krh@75
    59
	struct rpm_header_index *dirindexes;
krh@75
    60
	struct rpm_header_index *basenames;
krh@77
    61
	struct rpm_header_index *filesizes;
krh@77
    62
	struct rpm_header_index *filemodes;
krh@86
    63
	struct rpm_header_index *fileflags;
krh@77
    64
	const char **dirs;
krh@75
    65
krh@75
    66
	struct properties provides;
krh@75
    67
	struct properties requires;
krh@75
    68
	struct properties obsoletes;
krh@75
    69
	struct properties conflicts;
krh@75
    70
krh@75
    71
	const char *pool;
krh@75
    72
	void *map;
krh@75
    73
	size_t size;
krh@77
    74
	void *payload;
krh@75
    75
};
krh@75
    76
krh@74
    77
#define ALIGN(value, base) (((value) + (base - 1)) & ~((base) - 1))
krh@74
    78
krh@75
    79
static void
krh@75
    80
import_properties(struct razor_importer *importer,
krh@75
    81
		  struct properties *properties,
krh@75
    82
		  const char *pool, unsigned long type)
krh@75
    83
{
krh@75
    84
	const char *name, *version;
krh@75
    85
	int i, count;
krh@75
    86
krh@75
    87
	/* assert: count is the same for all arrays */
krh@75
    88
krh@75
    89
	if (properties->name == NULL)
krh@75
    90
		return;
krh@75
    91
krh@75
    92
	count = ntohl(properties->name->count);
krh@75
    93
	name = pool + ntohl(properties->name->offset);
krh@75
    94
	version = pool + ntohl(properties->version->offset);
krh@75
    95
	for (i = 0; i < count; i++) {
krh@75
    96
		razor_importer_add_property(importer, name, version, type);
krh@75
    97
		name += strlen(name) + 1;
krh@75
    98
		version += strlen(version) + 1;
krh@75
    99
	}
krh@75
   100
}
krh@75
   101
krh@75
   102
static void
krh@77
   103
import_files(struct razor_importer *importer, struct razor_rpm *rpm)
krh@75
   104
{
krh@77
   105
	const char *name;
krh@75
   106
	unsigned long *index;
krh@75
   107
	int i, count;
krh@75
   108
	char buffer[256];
krh@75
   109
krh@75
   110
	/* assert: count is the same for all arrays */
krh@75
   111
krh@75
   112
	if (rpm->dirnames == NULL)
krh@75
   113
		return;
krh@75
   114
krh@75
   115
	count = ntohl(rpm->basenames->count);
krh@75
   116
	index = (unsigned long *) (rpm->pool + ntohl(rpm->dirindexes->offset));
krh@75
   117
	name = rpm->pool + ntohl(rpm->basenames->offset);
krh@75
   118
	for (i = 0; i < count; i++) {
krh@75
   119
		snprintf(buffer, sizeof buffer,
krh@77
   120
			 "%s%s", rpm->dirs[ntohl(*index)], name);
krh@75
   121
		razor_importer_add_file(importer, buffer);
krh@75
   122
		name += strlen(name) + 1;
krh@75
   123
		index++;
krh@75
   124
	}
krh@75
   125
}
krh@75
   126
krh@84
   127
#define MAP_ENTRY(field, tag) { offsetof(struct razor_rpm, field), tag }
krh@84
   128
krh@84
   129
static struct index_map {
krh@84
   130
	unsigned int offset;
krh@84
   131
	unsigned int tag;
krh@84
   132
} index_map[] =	{
krh@84
   133
	MAP_ENTRY(name, RPMTAG_NAME),
krh@84
   134
	MAP_ENTRY(version, RPMTAG_VERSION),
krh@84
   135
	MAP_ENTRY(release, RPMTAG_RELEASE),
krh@84
   136
	MAP_ENTRY(requires.name, RPMTAG_REQUIRENAME),
krh@84
   137
	MAP_ENTRY(requires.version, RPMTAG_REQUIREVERSION),
krh@84
   138
	MAP_ENTRY(requires.flags, RPMTAG_REQUIREFLAGS),
krh@84
   139
	MAP_ENTRY(provides.name, RPMTAG_PROVIDENAME),
krh@84
   140
	MAP_ENTRY(provides.version, RPMTAG_PROVIDEVERSION),
krh@84
   141
	MAP_ENTRY(provides.flags, RPMTAG_PROVIDEFLAGS),
krh@84
   142
	MAP_ENTRY(obsoletes.name, RPMTAG_OBSOLETENAME),
krh@84
   143
	MAP_ENTRY(obsoletes.version, RPMTAG_OBSOLETEVERSION),
krh@84
   144
	MAP_ENTRY(obsoletes.flags, RPMTAG_OBSOLETEFLAGS),
krh@84
   145
	MAP_ENTRY(conflicts.name, RPMTAG_CONFLICTNAME),
krh@84
   146
	MAP_ENTRY(conflicts.version, RPMTAG_CONFLICTVERSION),
krh@84
   147
	MAP_ENTRY(conflicts.flags, RPMTAG_CONFLICTFLAGS),
krh@84
   148
	MAP_ENTRY(dirindexes, RPMTAG_DIRINDEXES),
krh@84
   149
	MAP_ENTRY(basenames, RPMTAG_BASENAMES),
krh@84
   150
	MAP_ENTRY(dirnames, RPMTAG_DIRNAMES),
krh@84
   151
	MAP_ENTRY(filesizes, RPMTAG_FILESIZES),
krh@84
   152
	MAP_ENTRY(filemodes, RPMTAG_FILEMODES),
krh@86
   153
	MAP_ENTRY(fileflags, RPMTAG_FILEFLAGS),
krh@84
   154
};
krh@84
   155
krh@85
   156
static struct rpm_header_index *
krh@85
   157
razor_rpm_get_header(struct razor_rpm *rpm, unsigned int tag)
krh@85
   158
{
krh@85
   159
	struct rpm_header_index *index, *end;
krh@85
   160
krh@85
   161
	index = (struct rpm_header_index *) (rpm->header + 1);
krh@85
   162
	end = index + ntohl(rpm->header->nindex);
krh@85
   163
	while (index < end) {
krh@85
   164
		if (ntohl(index->tag) == tag)
krh@85
   165
			return index;
krh@85
   166
		index++;
krh@85
   167
	}
krh@85
   168
krh@85
   169
	return NULL;
krh@85
   170
}
krh@85
   171
krh@77
   172
struct razor_rpm *
krh@77
   173
razor_rpm_open(const char *filename)
krh@74
   174
{
krh@77
   175
	struct razor_rpm *rpm;
krh@74
   176
	struct rpm_header_index *base, *index;
krh@75
   177
	struct stat buf;
krh@84
   178
	int fd, nindex, hsize, i, j, count;
krh@77
   179
	const char *name;
krh@74
   180
krh@77
   181
	rpm = malloc(sizeof *rpm);
krh@75
   182
	memset(rpm, 0, sizeof *rpm);
krh@75
   183
	if (stat(filename, &buf) < 0) {
krh@75
   184
		fprintf(stderr, "no such file %s (%m)\n", filename);
krh@77
   185
		return NULL;
krh@75
   186
	}
krh@74
   187
krh@75
   188
	fd = open(filename, O_RDONLY);
krh@75
   189
	if (fd < 0) {
krh@75
   190
		fprintf(stderr, "couldn't open %s\n", filename);
krh@77
   191
		return NULL;
krh@75
   192
	}
krh@75
   193
	rpm->size = buf.st_size;
krh@75
   194
	rpm->map = mmap(NULL, rpm->size, PROT_READ, MAP_PRIVATE, fd, 0);
krh@75
   195
	if (rpm->map == MAP_FAILED) {
krh@75
   196
		fprintf(stderr, "couldn't mmap %s\n", filename);
krh@77
   197
		return NULL;
krh@75
   198
	}
krh@75
   199
	close(fd);
krh@75
   200
krh@75
   201
	rpm->signature = rpm->map + RPM_LEAD_SIZE;
krh@75
   202
	nindex = ntohl(rpm->signature->nindex);
krh@75
   203
	hsize = ntohl(rpm->signature->hsize);
krh@75
   204
	rpm->header = (void *) (rpm->signature + 1) +
krh@75
   205
		ALIGN(nindex * sizeof *index + hsize, 8);
krh@77
   206
	nindex = ntohl(rpm->header->nindex);
krh@77
   207
	hsize = ntohl(rpm->header->hsize);
krh@77
   208
	rpm->payload = (void *) (rpm->header + 1) +
krh@77
   209
		nindex * sizeof *index + hsize;
krh@75
   210
krh@75
   211
	base = (struct rpm_header_index *) (rpm->header + 1);
krh@75
   212
	rpm->pool = (void *) base + nindex * sizeof *index;
krh@75
   213
krh@74
   214
	for (i = 0; i < nindex; i++) {
krh@74
   215
		index = base + i;
krh@84
   216
		for (j = 0; j < ARRAY_SIZE(index_map); j++) {
krh@84
   217
			struct rpm_header_index **p;
krh@84
   218
			if (index_map[j].tag == ntohl(index->tag)) {
krh@84
   219
				p = (void *) rpm + index_map[j].offset;
krh@84
   220
				*p = index;
krh@84
   221
			}
krh@84
   222
		}				 
krh@74
   223
	}
krh@75
   224
krh@77
   225
	/* Look up dir names now so we can index them directly. */
krh@77
   226
	if (rpm->dirnames != NULL) {
krh@77
   227
		count = ntohl(rpm->dirnames->count);
krh@77
   228
		rpm->dirs = calloc(count, sizeof *rpm->dirs);
krh@77
   229
		name = rpm->pool + ntohl(rpm->dirnames->offset);
krh@77
   230
		for (i = 0; i < count; i++) {
krh@77
   231
			rpm->dirs[i] = name;
krh@77
   232
			name += strlen(name) + 1;
krh@77
   233
		}
krh@77
   234
	}
krh@77
   235
krh@77
   236
	return rpm;
krh@77
   237
}
krh@77
   238
krh@77
   239
struct cpio_file_header {
krh@77
   240
	char magic[6];
krh@77
   241
	char inode[8];
krh@77
   242
	char mode[8];
krh@77
   243
	char uid[8];
krh@77
   244
	char gid[8];
krh@77
   245
	char nlink[8];
krh@77
   246
	char mtime[8];
krh@77
   247
	char filesize[8];
krh@77
   248
	char devmajor[8];
krh@77
   249
	char devminor[8];
krh@77
   250
	char rdevmajor[8];
krh@77
   251
	char rdevminor[8];
krh@77
   252
	char namesize[8];
krh@77
   253
	char checksum[8];
krh@77
   254
	char filename[0];
krh@77
   255
};
krh@77
   256
krh@77
   257
/* gzip flags */
krh@77
   258
#define ASCII_FLAG   0x01 /* bit 0 set: file probably ascii text */
krh@77
   259
#define HEAD_CRC     0x02 /* bit 1 set: header CRC present */
krh@77
   260
#define EXTRA_FIELD  0x04 /* bit 2 set: extra field present */
krh@77
   261
#define ORIG_NAME    0x08 /* bit 3 set: original file name present */
krh@77
   262
#define COMMENT      0x10 /* bit 4 set: file comment present */
krh@77
   263
#define RESERVED     0xE0 /* bits 5..7: reserved */
krh@77
   264
krh@86
   265
struct installer {
krh@86
   266
	const char *root;
krh@86
   267
	struct razor_rpm *rpm;
krh@86
   268
	z_stream stream;
krh@86
   269
	unsigned char buffer[32768];
krh@86
   270
	size_t rest, length;
krh@86
   271
};
krh@86
   272
krh@77
   273
static int
krh@86
   274
installer_inflate(struct installer *installer)
krh@86
   275
{
krh@86
   276
	size_t length;
krh@86
   277
	int err;
krh@86
   278
krh@86
   279
	if (ALIGN(installer->rest, 4) > sizeof installer->buffer)
krh@86
   280
		length = sizeof installer->buffer;
krh@86
   281
	else
krh@86
   282
		length = installer->rest;
krh@86
   283
krh@86
   284
	installer->stream.next_out = installer->buffer;
krh@86
   285
	installer->stream.avail_out = ALIGN(length, 4);
krh@86
   286
	err = inflate(&installer->stream, Z_SYNC_FLUSH);
krh@86
   287
	if (err != Z_OK && err != Z_STREAM_END) {
krh@86
   288
		fprintf(stderr, "inflate error: %d (%m)\n", err);
krh@86
   289
		return -1;
krh@86
   290
	}
krh@86
   291
krh@86
   292
	installer->rest -= length;
krh@86
   293
	installer->length = length;
krh@86
   294
krh@86
   295
	return 0;
krh@86
   296
}
krh@86
   297
krh@86
   298
static int
krh@86
   299
xwrite(int fd, const void *data, size_t size)
krh@86
   300
{
krh@86
   301
	size_t rest;
krh@86
   302
	ssize_t written;
krh@86
   303
	const unsigned char *p;
krh@86
   304
krh@86
   305
	rest = size;
krh@86
   306
	p = data;
krh@86
   307
	while (rest > 0) {
krh@86
   308
		written = write(fd, p, rest);
krh@86
   309
		if (written < 0) {
krh@86
   310
			fprintf(stderr, "write error: %m\n");
krh@86
   311
			return -1;
krh@86
   312
		}
krh@86
   313
		rest -= written;
krh@86
   314
		p += written;
krh@86
   315
	}
krh@86
   316
krh@86
   317
	return 0;
krh@86
   318
}
krh@86
   319
krh@86
   320
static int
krh@86
   321
create_path(struct installer *installer,
krh@86
   322
	    const char *path, const char *name, unsigned int mode)
krh@77
   323
{
krh@77
   324
	char buffer[256], *p;
krh@77
   325
	const char *slash, *next;
krh@77
   326
	struct stat buf;
krh@86
   327
	int fd;
krh@77
   328
krh@77
   329
	/* Create all sub-directories in dir and then create name. We
krh@77
   330
	 * know root exists and is a dir, root does not end in a '/',
krh@77
   331
	 * and path has a leading '/'. */
krh@77
   332
krh@86
   333
	strcpy(buffer, installer->root);
krh@77
   334
	p = buffer + strlen(buffer);
krh@77
   335
	slash = path;
krh@77
   336
	for (slash = path; slash[1] != '\0'; slash = next) {
krh@77
   337
		next = strchr(slash + 1, '/');
krh@77
   338
		memcpy(p, slash, next - slash);
krh@77
   339
		p += next - slash;
krh@77
   340
		*p = '\0';
krh@77
   341
krh@77
   342
		if (stat(buffer, &buf) == 0) {
krh@77
   343
			if (!S_ISDIR(buf.st_mode)) {
krh@77
   344
				fprintf(stderr,
krh@77
   345
					"%s exists but is not a directory\n",
krh@77
   346
					buffer);
krh@77
   347
				return -1;
krh@77
   348
			}
krh@77
   349
		} else if (mkdir(buffer, 0777) < 0) {
krh@77
   350
			fprintf(stderr, "failed to make directory %s: %m\n",
krh@77
   351
				buffer);
krh@77
   352
			return -1;
krh@77
   353
		}
krh@77
   354
		/* FIXME: permissions */
krh@77
   355
	}
krh@77
   356
krh@77
   357
	*p++ = '/';
krh@77
   358
	strcpy(p, name);
krh@77
   359
krh@77
   360
	switch (mode >> 12) {
krh@77
   361
	case REG:
krh@86
   362
		fd = open(buffer, O_WRONLY | O_CREAT | O_TRUNC, mode & 0x1ff);
krh@86
   363
		if (fd < 0){
krh@86
   364
			fprintf(stderr, "failed to create file %s\n", buffer);
krh@86
   365
			return -1;
krh@86
   366
		}
krh@86
   367
		while (installer->rest > 0) {
krh@86
   368
			if (installer_inflate(installer)) {
krh@86
   369
				fprintf(stderr, "failed to inflate\n");
krh@86
   370
				return -1;
krh@86
   371
			}
krh@86
   372
			if (xwrite(fd, installer->buffer, installer->length)) {
krh@86
   373
				fprintf(stderr, "failed to write payload\n");
krh@86
   374
				return -1;
krh@86
   375
			}
krh@86
   376
		}
krh@86
   377
		if (close(fd) < 0) {
krh@86
   378
			fprintf(stderr, "failed to close %s: %m\n", buffer);
krh@86
   379
			return -1;
krh@86
   380
		}
krh@86
   381
		return 0;
krh@86
   382
	case XDIR:
krh@86
   383
		return mkdir(buffer, mode & 0x1ff);
krh@86
   384
	case PIPE:
krh@86
   385
	case CDEV:
krh@86
   386
	case BDEV:
krh@86
   387
	case SOCK:
krh@86
   388
		printf("%s: unhandled file type %d\n", buffer, mode >> 12);
krh@86
   389
		return 0;
krh@86
   390
	case LINK:
krh@86
   391
		if (installer_inflate(installer)) {
krh@86
   392
			fprintf(stderr, "failed to inflate\n");
krh@86
   393
			return -1;
krh@86
   394
		}
krh@86
   395
		if (installer->length >= sizeof installer->buffer) {
krh@86
   396
			fprintf(stderr, "link name too long\n");
krh@86
   397
			return -1;
krh@86
   398
		}
krh@86
   399
		installer->buffer[installer->length] = '\0';
krh@86
   400
		if (symlink((const char *) installer->buffer, buffer)) {
krh@86
   401
			fprintf(stderr, "failed to create symlink, %m\n");
krh@86
   402
			return -1;
krh@86
   403
		}
krh@86
   404
		return 0;
krh@77
   405
	default:
krh@86
   406
		printf("%s: unknown file type %d\n", buffer, mode >> 12);
krh@86
   407
		return 0;
krh@77
   408
	}
krh@77
   409
}
krh@77
   410
krh@85
   411
static int
krh@86
   412
run_script(struct installer *installer,
krh@86
   413
	   unsigned int program_tag, unsigned int script_tag)
krh@85
   414
{
krh@85
   415
	struct rpm_header_index *index;
krh@85
   416
	int pid, status, fd[2];
krh@86
   417
	const char *script = NULL, *program = NULL;
krh@85
   418
krh@86
   419
	index = razor_rpm_get_header(installer->rpm, program_tag);
krh@86
   420
	if (index != NULL)
krh@86
   421
		program = installer->rpm->pool + ntohl(index->offset);
krh@86
   422
krh@86
   423
	index = razor_rpm_get_header(installer->rpm, script_tag);
krh@86
   424
	if (index != NULL)
krh@86
   425
		script = installer->rpm->pool + ntohl(index->offset);
krh@86
   426
krh@86
   427
	if (program == NULL && script == NULL) {
krh@86
   428
		printf("no script or program for tags %d and %d\n",
krh@86
   429
		       program_tag, script_tag);
krh@86
   430
		return -1;
krh@86
   431
	} else if (program == NULL) {
krh@86
   432
		program = "/bin/sh";
krh@85
   433
	}
krh@85
   434
krh@85
   435
	if (pipe(fd) < 0) {
krh@85
   436
		fprintf(stderr, "failed to create pipe\n");
krh@85
   437
		return -1;
krh@85
   438
	}
krh@85
   439
	pid = fork();
krh@85
   440
	if (pid < 0) {
krh@85
   441
		fprintf(stderr, "failed to fork, %m\n");
krh@85
   442
	} else if (pid == 0) {
krh@85
   443
		if (dup2(fd[0], STDIN_FILENO) < 0) {
krh@85
   444
			fprintf(stderr, "failed redirect stdin, %m\n");
krh@85
   445
			return -1;
krh@85
   446
		}
krh@85
   447
		if (close(fd[0]) < 0 || close(fd[1]) < 0) {
krh@85
   448
			fprintf(stderr, "failed to close pipe, %m\n");
krh@85
   449
			exit(-1);
krh@85
   450
		}
krh@86
   451
		if (chroot(installer->root) < 0) {
krh@86
   452
			fprintf(stderr, "failed to chroot to %s, %m\n",
krh@86
   453
				installer->root);
krh@85
   454
			return -1;
krh@85
   455
		}
krh@86
   456
		printf("executing program %s in chroot %s\n",
krh@86
   457
		       program, installer->root);
krh@86
   458
		if (execl(program, program, NULL)) {
krh@86
   459
			fprintf(stderr, "failed to exec %s, %m\n", program);
krh@85
   460
			return -1;
krh@85
   461
		}
krh@85
   462
	} else {
krh@86
   463
		if (script && write(fd[1], script, strlen(script)) < 0) {
krh@85
   464
			fprintf(stderr, "failed to pipe script, %m\n");
krh@85
   465
			return -1;
krh@85
   466
		}
krh@85
   467
		if (close(fd[0]) || close(fd[1])) {
krh@85
   468
			fprintf(stderr, "failed to close pipe, %m\n");
krh@85
   469
			return -1;
krh@85
   470
		}
krh@85
   471
		if (wait(&status) < 0) {
krh@85
   472
			fprintf(stderr, "wait for child failed, %m");
krh@85
   473
			return -1;
krh@85
   474
		}
krh@85
   475
		printf("script exited with status %d\n", status);
krh@85
   476
	}
krh@85
   477
krh@85
   478
	return 0;
krh@85
   479
}
krh@85
   480
krh@86
   481
static int
krh@86
   482
installer_init(struct installer *installer)
krh@77
   483
{
krh@86
   484
	unsigned char *gz_header;
krh@86
   485
	int method, flags, err;
krh@77
   486
krh@86
   487
	gz_header = installer->rpm->payload;
krh@77
   488
	if (gz_header[0] != 0x1f || gz_header[1] != 0x8b) {
krh@77
   489
		fprintf(stderr, "payload section doesn't have gz header\n");
krh@77
   490
		return -1;
krh@77
   491
	}
krh@77
   492
krh@77
   493
	method = gz_header[2];
krh@77
   494
	flags = gz_header[3];
krh@77
   495
krh@77
   496
	if (method != Z_DEFLATED || flags != 0) {
krh@77
   497
		fprintf(stderr,
krh@77
   498
			"unknown payload compression method or flags set\n");
krh@77
   499
		return -1;
krh@77
   500
	}
krh@77
   501
krh@86
   502
	installer->stream.zalloc = NULL;
krh@86
   503
	installer->stream.zfree = NULL;
krh@86
   504
	installer->stream.opaque = NULL;
krh@85
   505
krh@86
   506
	installer->stream.next_in  = gz_header + 10;
krh@86
   507
	installer->stream.avail_in =
krh@86
   508
		(installer->rpm->map + installer->rpm->size) -
krh@86
   509
		(void *) installer->stream.next_in;
krh@86
   510
	installer->stream.next_out = NULL;
krh@86
   511
	installer->stream.avail_out = 0;
krh@77
   512
krh@86
   513
	err = inflateInit2(&installer->stream, -MAX_WBITS);
krh@77
   514
	if (err != Z_OK) {
krh@77
   515
		fprintf(stderr, "inflateInit error: %d\n", err);
krh@77
   516
		return -1;
krh@77
   517
	}
krh@77
   518
krh@86
   519
	return 0;
krh@86
   520
}
krh@77
   521
krh@86
   522
static int
krh@86
   523
installer_finish(struct installer *installer)
krh@86
   524
{
krh@86
   525
	int err;
krh@77
   526
krh@86
   527
	err = inflateEnd(&installer->stream);
krh@77
   528
krh@77
   529
	if (err != Z_OK) {
krh@77
   530
		fprintf(stderr, "inflateEnd error: %d\n", err);
krh@77
   531
		return -1;
krh@77
   532
	}	    
krh@77
   533
krh@86
   534
	return 0;
krh@86
   535
}
krh@86
   536
krh@86
   537
int
krh@86
   538
razor_rpm_install(struct razor_rpm *rpm, const char *root)
krh@86
   539
{
krh@86
   540
	struct installer installer;
krh@86
   541
	int count, i;
krh@86
   542
	struct cpio_file_header *header;
krh@86
   543
	unsigned long *size, *index, length, *flags;
krh@86
   544
	unsigned short *mode;
krh@86
   545
	const char *name, *dir;
krh@86
   546
	struct stat buf;
krh@86
   547
krh@86
   548
	installer.rpm = rpm;
krh@86
   549
	installer.root = root;
krh@86
   550
krh@86
   551
	/* FIXME: Only do this before a transaction, not per rpm. */
krh@86
   552
	if (stat(root, &buf) < 0 || !S_ISDIR(buf.st_mode)) {
krh@86
   553
		fprintf(stderr,
krh@86
   554
			"root installation directory \"%s\" does not exist\n",
krh@86
   555
			root);
krh@86
   556
		return -1;
krh@86
   557
	}
krh@86
   558
krh@86
   559
	if (installer_init(&installer))
krh@86
   560
		return -1;
krh@86
   561
krh@86
   562
	run_script(&installer, RPMTAG_PREINPROG, RPMTAG_PREIN);
krh@86
   563
krh@86
   564
	count = ntohl(rpm->basenames->count);
krh@86
   565
	size = (unsigned long *) (rpm->pool + ntohl(rpm->filesizes->offset));
krh@86
   566
	index = (unsigned long *) (rpm->pool + ntohl(rpm->dirindexes->offset));
krh@86
   567
	mode = (unsigned short *) (rpm->pool + ntohl(rpm->filemodes->offset));
krh@86
   568
	flags = (unsigned long *) (rpm->pool + ntohl(rpm->fileflags->offset));
krh@86
   569
krh@86
   570
	name = rpm->pool + ntohl(rpm->basenames->offset);
krh@86
   571
	for (i = 0; i < count; i++) {
krh@86
   572
		dir = rpm->dirs[ntohl(*index)];
krh@86
   573
krh@86
   574
		/* Skip past the cpio header block unless it's a ghost file,
krh@86
   575
		 * in which case doesn't appear in the cpio archive. */
krh@86
   576
		if (!(ntohl(*flags) & RPMFILE_GHOST)) {
krh@86
   577
			/* Plus two for the leading '.' and the terminating NUL. */
krh@86
   578
			length = sizeof *header + strlen(dir) + strlen(name) + 2;
krh@86
   579
			installer.rest = ALIGN(length, 4);
krh@86
   580
			if (installer_inflate(&installer))
krh@86
   581
				return -1;
krh@86
   582
		}
krh@86
   583
krh@86
   584
		installer.rest = ntohl(*size);
krh@86
   585
		if (create_path(&installer, dir, name, ntohs(*mode)) < 0)
krh@86
   586
			return -1;
krh@86
   587
krh@86
   588
		name += strlen(name) + 1;
krh@86
   589
		index++;
krh@86
   590
		size++;
krh@86
   591
		mode++;
krh@86
   592
		flags++;
krh@86
   593
	}
krh@86
   594
krh@86
   595
	if (installer_finish(&installer))
krh@86
   596
		return -1;
krh@86
   597
krh@86
   598
	run_script(&installer, RPMTAG_POSTINPROG, RPMTAG_POSTIN);
krh@85
   599
krh@75
   600
	return 0;
krh@74
   601
}
krh@74
   602
krh@77
   603
int
krh@77
   604
razor_rpm_close(struct razor_rpm *rpm)
krh@74
   605
{
krh@77
   606
	int err;
krh@77
   607
krh@77
   608
	free(rpm->dirs);
krh@77
   609
	err = munmap(rpm->map, rpm->size);
krh@77
   610
	free(rpm);
krh@77
   611
krh@77
   612
	return err;
krh@75
   613
}
krh@74
   614
krh@75
   615
int
krh@77
   616
razor_importer_add_rpm(struct razor_importer *importer, struct razor_rpm *rpm)
krh@75
   617
{
krh@77
   618
	razor_importer_begin_package(importer,
krh@77
   619
				     rpm->pool + ntohl(rpm->name->offset),
krh@77
   620
				     rpm->pool + ntohl(rpm->version->offset));
krh@75
   621
krh@77
   622
	import_properties(importer, &rpm->requires,
krh@77
   623
			  rpm->pool, RAZOR_PROPERTY_REQUIRES);
krh@77
   624
	import_properties(importer, &rpm->provides,
krh@77
   625
			  rpm->pool, RAZOR_PROPERTY_PROVIDES);
krh@77
   626
	import_properties(importer, &rpm->conflicts,
krh@77
   627
			  rpm->pool, RAZOR_PROPERTY_CONFLICTS);
krh@77
   628
	import_properties(importer, &rpm->obsoletes,
krh@77
   629
			  rpm->pool, RAZOR_PROPERTY_OBSOLETES);
krh@77
   630
	import_files(importer, rpm);
krh@74
   631
krh@75
   632
	razor_importer_finish_package(importer);
krh@74
   633
krh@75
   634
	return 0;
krh@74
   635
}