librazor/rpm.c
author J. Ali Harlow <ali@juiblex.co.uk>
Thu Feb 09 20:45:27 2012 +0000 (2012-02-09)
changeset 418 33b825d3128d
parent 376 d15a16347c77
child 422 6fa783097ca1
permissions -rw-r--r--
Add transaction barriers
These allow packages to be installed and removed which have scripts
that depend on each other when atomic transactions are involved.
Note that yum supports pre, but not other requires flags. post will
need similar support to the post scripts themselves pulling in the
requires flags from the rpms. Likewise preun and postun will need
similar handling to those scrips since the requires flags will need
to be stored in the razor database.
rhughes@241
     1
/*
rhughes@241
     2
 * Copyright (C) 2008  Kristian Høgsberg <krh@redhat.com>
rhughes@241
     3
 * Copyright (C) 2008  Red Hat, Inc
ali@403
     4
 * Copyright (C) 2009, 2011  J. Ali Harlow <ali@juiblex.co.uk>
rhughes@241
     5
 *
rhughes@241
     6
 * This program is free software; you can redistribute it and/or modify
rhughes@241
     7
 * it under the terms of the GNU General Public License as published by
rhughes@241
     8
 * the Free Software Foundation; either version 2 of the License, or
rhughes@241
     9
 * (at your option) any later version.
rhughes@241
    10
 *
rhughes@241
    11
 * This program is distributed in the hope that it will be useful,
rhughes@241
    12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
rhughes@241
    13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
rhughes@241
    14
 * GNU General Public License for more details.
rhughes@241
    15
 *
rhughes@241
    16
 * You should have received a copy of the GNU General Public License along
rhughes@241
    17
 * with this program; if not, write to the Free Software Foundation, Inc.,
rhughes@241
    18
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
rhughes@241
    19
 */
rhughes@241
    20
ali@327
    21
#include "config.h"
ali@327
    22
rhughes@241
    23
#include <stdio.h>
rhughes@241
    24
#include <stddef.h>
rhughes@241
    25
#include <stdlib.h>
rhughes@241
    26
#include <string.h>
rhughes@241
    27
#include <errno.h>
rhughes@241
    28
#include <sys/stat.h>
rhughes@241
    29
#include <sys/types.h>
ali@330
    30
#if HAVE_SYS_WAIT_H
rhughes@241
    31
#include <sys/wait.h>
ali@330
    32
#endif
rhughes@241
    33
#include <fcntl.h>
rhughes@241
    34
#include <dirent.h>
rhughes@241
    35
#include <unistd.h>
ali@329
    36
#if MSWIN_API
ali@335
    37
#include <winsock2.h>	/* For ntohl() */
ali@329
    38
#else
rhughes@241
    39
#include <arpa/inet.h>
ali@329
    40
#endif
ali@325
    41
#include <limits.h>
rhughes@241
    42
#include <zlib.h>
richard@301
    43
#include <assert.h>
rhughes@241
    44
rhughes@241
    45
#include "razor.h"
rhughes@241
    46
#include "razor-internal.h"
rhughes@241
    47
ali@345
    48
#ifndef O_BINARY
ali@345
    49
#define O_BINARY	0
ali@345
    50
#endif
ali@345
    51
rhughes@241
    52
#define	RPM_LEAD_SIZE 96
rhughes@241
    53
rhughes@241
    54
enum {
rhughes@241
    55
    PIPE	=  1,	/*!< pipe/fifo */
rhughes@241
    56
    CDEV	=  2,	/*!< character device */
rhughes@241
    57
    XDIR	=  4,	/*!< directory */
rhughes@241
    58
    BDEV	=  6,	/*!< block device */
rhughes@241
    59
    REG		=  8,	/*!< regular file */
rhughes@241
    60
    LINK	= 10,	/*!< hard link */
rhughes@241
    61
    SOCK	= 12	/*!< socket */
rhughes@241
    62
};
rhughes@241
    63
rhughes@241
    64
enum {
krh@247
    65
    RPMSENSE_LESS		= 1 << 1,
krh@247
    66
    RPMSENSE_GREATER		= 1 << 2,
krh@247
    67
    RPMSENSE_EQUAL		= 1 << 3,
krh@247
    68
    RPMSENSE_PREREQ		= 1 << 6,
krh@247
    69
    RPMSENSE_SCRIPT_PRE		= 1 << 9,
krh@247
    70
    RPMSENSE_SCRIPT_POST	= 1 << 10,
krh@247
    71
    RPMSENSE_SCRIPT_PREUN	= 1 << 11,
krh@247
    72
    RPMSENSE_SCRIPT_POSTUN	= 1 << 12,
rhughes@241
    73
};
rhughes@241
    74
rhughes@241
    75
enum {
rhughes@241
    76
    RPMTAG_NAME  		= 1000,	/* s */
rhughes@241
    77
    RPMTAG_VERSION		= 1001,	/* s */
rhughes@241
    78
    RPMTAG_RELEASE		= 1002,	/* s */
rhughes@241
    79
    RPMTAG_EPOCH   		= 1003,	/* i */
rhughes@241
    80
    RPMTAG_SUMMARY		= 1004,	/* s{} */
rhughes@241
    81
    RPMTAG_DESCRIPTION		= 1005,	/* s{} */
rhughes@241
    82
    RPMTAG_BUILDTIME		= 1006,	/* i */
rhughes@241
    83
    RPMTAG_BUILDHOST		= 1007,	/* s */
rhughes@241
    84
    RPMTAG_INSTALLTIME		= 1008,	/* i */
rhughes@241
    85
    RPMTAG_SIZE			= 1009,	/* i */
rhughes@241
    86
    RPMTAG_DISTRIBUTION		= 1010,	/* s */
rhughes@241
    87
    RPMTAG_VENDOR		= 1011,	/* s */
rhughes@241
    88
    RPMTAG_GIF			= 1012,	/* x */
rhughes@241
    89
    RPMTAG_XPM			= 1013,	/* x */
rhughes@241
    90
    RPMTAG_LICENSE		= 1014,	/* s */
rhughes@241
    91
    RPMTAG_PACKAGER		= 1015,	/* s */
rhughes@241
    92
    RPMTAG_GROUP		= 1016,	/* s{} */
rhughes@241
    93
    RPMTAG_CHANGELOG		= 1017, /*!< s[] internal */
rhughes@241
    94
    RPMTAG_SOURCE		= 1018,	/* s[] */
rhughes@241
    95
    RPMTAG_PATCH		= 1019,	/* s[] */
rhughes@241
    96
    RPMTAG_URL			= 1020,	/* s */
rhughes@241
    97
    RPMTAG_OS			= 1021,	/* s legacy used int */
rhughes@241
    98
    RPMTAG_ARCH			= 1022,	/* s legacy used int */
rhughes@241
    99
    RPMTAG_PREIN		= 1023,	/* s */
rhughes@241
   100
    RPMTAG_POSTIN		= 1024,	/* s */
rhughes@241
   101
    RPMTAG_PREUN		= 1025,	/* s */
rhughes@241
   102
    RPMTAG_POSTUN		= 1026,	/* s */
rhughes@241
   103
    RPMTAG_OLDFILENAMES		= 1027, /* s[] obsolete */
rhughes@241
   104
    RPMTAG_FILESIZES		= 1028,	/* i */
rhughes@241
   105
    RPMTAG_FILESTATES		= 1029, /* c */
rhughes@241
   106
    RPMTAG_FILEMODES		= 1030,	/* h */
rhughes@241
   107
    RPMTAG_FILEUIDS		= 1031, /*!< internal */
rhughes@241
   108
    RPMTAG_FILEGIDS		= 1032, /*!< internal */
rhughes@241
   109
    RPMTAG_FILERDEVS		= 1033,	/* h */
rhughes@241
   110
    RPMTAG_FILEMTIMES		= 1034, /* i */
rhughes@241
   111
    RPMTAG_FILEMD5S		= 1035,	/* s[] */
rhughes@241
   112
    RPMTAG_FILELINKTOS		= 1036,	/* s[] */
rhughes@241
   113
    RPMTAG_FILEFLAGS		= 1037,	/* i */
rhughes@241
   114
    RPMTAG_ROOT			= 1038, /*!< internal - obsolete */
rhughes@241
   115
    RPMTAG_FILEUSERNAME		= 1039,	/* s[] */
rhughes@241
   116
    RPMTAG_FILEGROUPNAME	= 1040,	/* s[] */
rhughes@241
   117
    RPMTAG_EXCLUDE		= 1041, /*!< internal - obsolete */
rhughes@241
   118
    RPMTAG_EXCLUSIVE		= 1042, /*!< internal - obsolete */
rhughes@241
   119
    RPMTAG_ICON			= 1043,
rhughes@241
   120
    RPMTAG_SOURCERPM		= 1044,	/* s */
rhughes@241
   121
    RPMTAG_FILEVERIFYFLAGS	= 1045,	/* i */
rhughes@241
   122
    RPMTAG_ARCHIVESIZE		= 1046,	/* i */
rhughes@241
   123
    RPMTAG_PROVIDENAME		= 1047,	/* s[] */
rhughes@241
   124
    RPMTAG_REQUIREFLAGS		= 1048,	/* i */
rhughes@241
   125
    RPMTAG_REQUIRENAME		= 1049,	/* s[] */
rhughes@241
   126
    RPMTAG_REQUIREVERSION	= 1050,	/* s[] */
rhughes@241
   127
    RPMTAG_NOSOURCE		= 1051, /*!< internal */
rhughes@241
   128
    RPMTAG_NOPATCH		= 1052, /*!< internal */
rhughes@241
   129
    RPMTAG_CONFLICTFLAGS	= 1053, /* i */
rhughes@241
   130
    RPMTAG_CONFLICTNAME		= 1054,	/* s[] */
rhughes@241
   131
    RPMTAG_CONFLICTVERSION	= 1055,	/* s[] */
rhughes@241
   132
    RPMTAG_DEFAULTPREFIX	= 1056, /*!< internal - deprecated */
rhughes@241
   133
    RPMTAG_BUILDROOT		= 1057, /*!< internal */
rhughes@241
   134
    RPMTAG_INSTALLPREFIX	= 1058, /*!< internal - deprecated */
rhughes@241
   135
    RPMTAG_EXCLUDEARCH		= 1059,
rhughes@241
   136
    RPMTAG_EXCLUDEOS		= 1060,
rhughes@241
   137
    RPMTAG_EXCLUSIVEARCH	= 1061,
rhughes@241
   138
    RPMTAG_EXCLUSIVEOS		= 1062,
rhughes@241
   139
    RPMTAG_AUTOREQPROV		= 1063, /*!< internal */
rhughes@241
   140
    RPMTAG_RPMVERSION		= 1064,	/* s */
rhughes@241
   141
    RPMTAG_TRIGGERSCRIPTS	= 1065,	/* s[] */
rhughes@241
   142
    RPMTAG_TRIGGERNAME		= 1066,	/* s[] */
rhughes@241
   143
    RPMTAG_TRIGGERVERSION	= 1067,	/* s[] */
rhughes@241
   144
    RPMTAG_TRIGGERFLAGS		= 1068,	/* i */
rhughes@241
   145
    RPMTAG_TRIGGERINDEX		= 1069,	/* i */
rhughes@241
   146
    RPMTAG_VERIFYSCRIPT		= 1079,	/* s */
rhughes@241
   147
    RPMTAG_CHANGELOGTIME	= 1080,	/* i */
rhughes@241
   148
    RPMTAG_CHANGELOGNAME	= 1081,	/* s[] */
rhughes@241
   149
    RPMTAG_CHANGELOGTEXT	= 1082,	/* s[] */
rhughes@241
   150
    RPMTAG_BROKENMD5		= 1083, /*!< internal - obsolete */
rhughes@241
   151
    RPMTAG_PREREQ		= 1084, /*!< internal */
rhughes@241
   152
    RPMTAG_PREINPROG		= 1085,	/* s */
rhughes@241
   153
    RPMTAG_POSTINPROG		= 1086,	/* s */
rhughes@241
   154
    RPMTAG_PREUNPROG		= 1087,	/* s */
rhughes@241
   155
    RPMTAG_POSTUNPROG		= 1088,	/* s */
rhughes@241
   156
    RPMTAG_BUILDARCHS		= 1089,
rhughes@241
   157
    RPMTAG_OBSOLETENAME		= 1090,	/* s[] */
rhughes@241
   158
    RPMTAG_VERIFYSCRIPTPROG	= 1091,	/* s */
rhughes@241
   159
    RPMTAG_TRIGGERSCRIPTPROG	= 1092,	/* s */
rhughes@241
   160
    RPMTAG_DOCDIR		= 1093, /*!< internal */
rhughes@241
   161
    RPMTAG_COOKIE		= 1094,	/* s */
rhughes@241
   162
    RPMTAG_FILEDEVICES		= 1095,	/* i */
rhughes@241
   163
    RPMTAG_FILEINODES		= 1096,	/* i */
rhughes@241
   164
    RPMTAG_FILELANGS		= 1097,	/* s[] */
rhughes@241
   165
    RPMTAG_PREFIXES		= 1098,	/* s[] */
rhughes@241
   166
    RPMTAG_INSTPREFIXES		= 1099,	/* s[] */
rhughes@241
   167
    RPMTAG_TRIGGERIN		= 1100, /*!< internal */
rhughes@241
   168
    RPMTAG_TRIGGERUN		= 1101, /*!< internal */
rhughes@241
   169
    RPMTAG_TRIGGERPOSTUN	= 1102, /*!< internal */
rhughes@241
   170
    RPMTAG_AUTOREQ		= 1103, /*!< internal */
rhughes@241
   171
    RPMTAG_AUTOPROV		= 1104, /*!< internal */
rhughes@241
   172
    RPMTAG_CAPABILITY		= 1105, /*!< internal - obsolete */
rhughes@241
   173
    RPMTAG_SOURCEPACKAGE	= 1106, /*!< i src.rpm header marker */
rhughes@241
   174
    RPMTAG_OLDORIGFILENAMES	= 1107, /*!< internal - obsolete */
rhughes@241
   175
    RPMTAG_BUILDPREREQ		= 1108, /*!< internal */
rhughes@241
   176
    RPMTAG_BUILDREQUIRES	= 1109, /*!< internal */
rhughes@241
   177
    RPMTAG_BUILDCONFLICTS	= 1110, /*!< internal */
rhughes@241
   178
    RPMTAG_BUILDMACROS		= 1111, /*!< internal - unused */
rhughes@241
   179
    RPMTAG_PROVIDEFLAGS		= 1112,	/* i */
rhughes@241
   180
    RPMTAG_PROVIDEVERSION	= 1113,	/* s[] */
rhughes@241
   181
    RPMTAG_OBSOLETEFLAGS	= 1114,	/* i */
rhughes@241
   182
    RPMTAG_OBSOLETEVERSION	= 1115,	/* s[] */
rhughes@241
   183
    RPMTAG_DIRINDEXES		= 1116,	/* i */
rhughes@241
   184
    RPMTAG_BASENAMES		= 1117,	/* s[] */
rhughes@241
   185
    RPMTAG_DIRNAMES		= 1118,	/* s[] */
rhughes@241
   186
    RPMTAG_ORIGDIRINDEXES	= 1119, /*!< internal */
rhughes@241
   187
    RPMTAG_ORIGBASENAMES	= 1120, /*!< internal */
rhughes@241
   188
    RPMTAG_ORIGDIRNAMES		= 1121, /*!< internal */
rhughes@241
   189
    RPMTAG_OPTFLAGS		= 1122,	/* s */
rhughes@241
   190
    RPMTAG_DISTURL		= 1123,	/* s */
rhughes@241
   191
    RPMTAG_PAYLOADFORMAT	= 1124,	/* s */
rhughes@241
   192
    RPMTAG_PAYLOADCOMPRESSOR	= 1125,	/* s */
rhughes@241
   193
    RPMTAG_PAYLOADFLAGS		= 1126,	/* s */
rhughes@241
   194
    RPMTAG_INSTALLCOLOR		= 1127, /*!< i transaction color when installed */
rhughes@241
   195
    RPMTAG_INSTALLTID		= 1128,	/* i */
rhughes@241
   196
    RPMTAG_REMOVETID		= 1129,	/* i */
rhughes@241
   197
    RPMTAG_SHA1RHN		= 1130, /*!< internal - obsolete */
rhughes@241
   198
    RPMTAG_RHNPLATFORM		= 1131,	/* s */
rhughes@241
   199
    RPMTAG_PLATFORM		= 1132,	/* s */
rhughes@241
   200
    RPMTAG_PATCHESNAME		= 1133, /*!< placeholder (SuSE) */
rhughes@241
   201
    RPMTAG_PATCHESFLAGS		= 1134, /*!< placeholder (SuSE) */
rhughes@241
   202
    RPMTAG_PATCHESVERSION	= 1135, /*!< placeholder (SuSE) */
rhughes@241
   203
    RPMTAG_CACHECTIME		= 1136,	/* i */
rhughes@241
   204
    RPMTAG_CACHEPKGPATH		= 1137,	/* s */
rhughes@241
   205
    RPMTAG_CACHEPKGSIZE		= 1138,	/* i */
rhughes@241
   206
    RPMTAG_CACHEPKGMTIME	= 1139,	/* i */
rhughes@241
   207
    RPMTAG_FILECOLORS		= 1140,	/* i */
rhughes@241
   208
    RPMTAG_FILECLASS		= 1141,	/* i */
rhughes@241
   209
    RPMTAG_CLASSDICT		= 1142,	/* s[] */
rhughes@241
   210
    RPMTAG_FILEDEPENDSX		= 1143,	/* i */
rhughes@241
   211
    RPMTAG_FILEDEPENDSN		= 1144,	/* i */
rhughes@241
   212
    RPMTAG_DEPENDSDICT		= 1145,	/* i */
rhughes@241
   213
    RPMTAG_SOURCEPKGID		= 1146,	/* x */
rhughes@241
   214
    RPMTAG_FILECONTEXTS		= 1147,	/* s[] */
rhughes@241
   215
    RPMTAG_FSCONTEXTS		= 1148,	/*!< s[] extension */
rhughes@241
   216
    RPMTAG_RECONTEXTS		= 1149,	/*!< s[] extension */
rhughes@241
   217
    RPMTAG_POLICIES		= 1150,	/*!< s[] selinux *.te policy file. */
rhughes@241
   218
    RPMTAG_PRETRANS		= 1151,	/* s */
rhughes@241
   219
    RPMTAG_POSTTRANS		= 1152,	/* s */
rhughes@241
   220
    RPMTAG_PRETRANSPROG		= 1153,	/* s */
rhughes@241
   221
    RPMTAG_POSTTRANSPROG	= 1154,	/* s */
rhughes@241
   222
    RPMTAG_DISTTAG		= 1155,	/* s */
rhughes@241
   223
    RPMTAG_SUGGESTSNAME		= 1156,	/* s[] extension placeholder */
rhughes@241
   224
    RPMTAG_SUGGESTSVERSION	= 1157,	/* s[] extension placeholder */
rhughes@241
   225
    RPMTAG_SUGGESTSFLAGS	= 1158,	/* i   extension placeholder */
rhughes@241
   226
    RPMTAG_ENHANCESNAME		= 1159,	/* s[] extension placeholder */
rhughes@241
   227
    RPMTAG_ENHANCESVERSION	= 1160,	/* s[] extension placeholder */
rhughes@241
   228
    RPMTAG_ENHANCESFLAGS	= 1161,	/* i   extension placeholder */
rhughes@241
   229
    RPMTAG_PRIORITY		= 1162, /* i   extension placeholder */
rhughes@241
   230
    RPMTAG_CVSID		= 1163, /* s */
rhughes@241
   231
    RPMTAG_TRIGGERPREIN		= 1171, /*!< internal */
rhughes@241
   232
};
rhughes@241
   233
rhughes@241
   234
struct rpm_header {
rhughes@241
   235
	unsigned char magic[4];
rhughes@241
   236
	unsigned char reserved[4];
rhughes@241
   237
	int nindex;
rhughes@241
   238
	int hsize;
rhughes@241
   239
};
rhughes@241
   240
rhughes@241
   241
struct rpm_header_index {
rhughes@241
   242
	int tag;
rhughes@241
   243
	int type;
rhughes@241
   244
	int offset;
rhughes@241
   245
	int count;
rhughes@241
   246
};
rhughes@241
   247
rhughes@241
   248
struct razor_rpm {
rhughes@241
   249
	struct rpm_header *signature;
rhughes@241
   250
	struct rpm_header *header;
rhughes@241
   251
	const char **dirs;
ali@351
   252
	unsigned int n_prefixes;
ali@351
   253
	const char **prefixes;
rhughes@241
   254
	const char *pool;
rhughes@241
   255
	void *map;
rhughes@241
   256
	size_t size;
rhughes@241
   257
	void *payload;
ali@351
   258
	struct razor_relocations *relocations;
ali@369
   259
	char *evr;
rhughes@241
   260
};
rhughes@241
   261
ali@351
   262
enum razor_relocation_flags {
ali@351
   263
	RAZOR_RELOCATION_ACTIVE		= 1 << 0,
ali@351
   264
};
ali@351
   265
ali@351
   266
struct razor_relocation {
ali@351
   267
	enum razor_relocation_flags flags;
ali@351
   268
	size_t oldlen;
ali@351
   269
	size_t newlen;
ali@351
   270
	char *oldpath;
ali@351
   271
	char *newpath;
ali@351
   272
};
ali@351
   273
ali@351
   274
struct razor_relocations {
ali@351
   275
	/* Ordered such that if oldpath 1 starts with oldpath 2, then
ali@351
   276
	 * oldpath 1 is listed first (ie., /usr/bin comes before /usr)
ali@351
   277
	 * and terminated with a NULL oldpath.
ali@351
   278
	 */
ali@351
   279
	struct razor_relocation *relocations;
ali@351
   280
	int n_relocations;
ali@351
   281
	char *path;
ali@351
   282
};
ali@351
   283
ali@351
   284
RAZOR_EXPORT struct razor_relocations *razor_relocations_create(void)
ali@351
   285
{
ali@351
   286
	return calloc(1, sizeof(struct razor_relocations));
ali@351
   287
}
ali@351
   288
ali@351
   289
RAZOR_EXPORT void razor_relocations_add(struct razor_relocations *rr,
ali@351
   290
			   const char *oldpath, const char *newpath)
ali@351
   291
{
ali@351
   292
	int i, found = 0;
ali@351
   293
	size_t len;
ali@351
   294
ali@351
   295
	if (newpath && !strcmp(oldpath, newpath))
ali@351
   296
		newpath = NULL;
ali@351
   297
ali@351
   298
	for (i = 0; i < rr->n_relocations; i++) {
ali@351
   299
		len = rr->relocations[i].oldlen;
ali@351
   300
		if (!strncmp(rr->relocations[i].oldpath, oldpath, len)) {
ali@351
   301
			found = !strcmp(rr->relocations[i].oldpath, oldpath);
ali@351
   302
			break;
ali@351
   303
		}
ali@351
   304
	}
ali@351
   305
ali@351
   306
	if (!newpath) {
ali@351
   307
		if (found) {
ali@351
   308
			free(rr->relocations[i].oldpath);
ali@351
   309
			free(rr->relocations[i].newpath);
ali@351
   310
			do {
ali@351
   311
				rr->relocations[i] = rr->relocations[i + 1];
ali@351
   312
			} while (rr->relocations[++i].oldpath);
ali@351
   313
		}
ali@351
   314
		return;
ali@351
   315
	}
ali@351
   316
ali@351
   317
	if (found) {
ali@351
   318
		free(rr->relocations[i].newpath);
ali@351
   319
		rr->relocations[i].newpath = strdup(newpath);
ali@351
   320
		rr->relocations[i].newlen = strlen(newpath);
ali@351
   321
		return;
ali@351
   322
	}
ali@351
   323
ali@351
   324
	if (!rr->n_relocations++)
ali@351
   325
		rr->relocations = calloc(1, sizeof *rr->relocations);
ali@351
   326
	else {
ali@351
   327
		rr->relocations = realloc(rr->relocations,
ali@351
   328
					  rr->n_relocations * sizeof *rr->relocations);
ali@351
   329
		memmove(rr->relocations + i + 1, rr->relocations + i,
ali@351
   330
			(rr->n_relocations - i - 1) * sizeof *rr->relocations);
ali@351
   331
	}
ali@351
   332
ali@351
   333
	rr->relocations[i].flags = 0;
ali@351
   334
	rr->relocations[i].oldpath = strdup(oldpath);
ali@351
   335
	rr->relocations[i].newpath = strdup(newpath);
ali@351
   336
	rr->relocations[i].oldlen = strlen(oldpath);
ali@351
   337
	rr->relocations[i].newlen = strlen(newpath);
ali@351
   338
}
ali@351
   339
ali@351
   340
RAZOR_EXPORT void
ali@351
   341
razor_relocations_set_rpm(struct razor_relocations *rr, struct razor_rpm *rpm)
ali@351
   342
{
ali@351
   343
	int i, j;
ali@351
   344
ali@351
   345
	for (i = 0; i < rr->n_relocations; i++) {
ali@351
   346
		rr->relocations[i].flags &= ~RAZOR_RELOCATION_ACTIVE;
ali@351
   347
		for (j = 0; j < rpm->n_prefixes; j++)
ali@351
   348
			if (!strcmp(rpm->prefixes[j],
ali@351
   349
				    rr->relocations[i].oldpath)) {
ali@351
   350
				rr->relocations[i].flags |= RAZOR_RELOCATION_ACTIVE;
ali@351
   351
				break;
ali@351
   352
			}
ali@351
   353
	}
ali@351
   354
}
ali@351
   355
ali@351
   356
RAZOR_EXPORT const char *
ali@351
   357
razor_relocations_apply(struct razor_relocations *rr, const char *path)
ali@351
   358
{
ali@351
   359
	int i;
ali@351
   360
	size_t len;
ali@351
   361
ali@351
   362
	for (i = 0; i < rr->n_relocations; i++)
ali@351
   363
		if (rr->relocations[i].flags & RAZOR_RELOCATION_ACTIVE &&
ali@351
   364
		    !strncmp(path, rr->relocations[i].oldpath,
ali@351
   365
			     rr->relocations[i].oldlen))
ali@351
   366
			break;
ali@351
   367
ali@351
   368
	if (i < rr->n_relocations) {
ali@351
   369
		free(rr->path);
ali@351
   370
		len = strlen(path + rr->relocations[i].oldlen) +
ali@351
   371
		      rr->relocations[i].newlen;
ali@351
   372
		rr->path = malloc(len + 1);
ali@351
   373
		memcpy(rr->path, rr->relocations[i].newpath,
ali@351
   374
		       rr->relocations[i].newlen);
ali@351
   375
		strcpy(rr->path + rr->relocations[i].newlen,
ali@351
   376
		       path + rr->relocations[i].oldlen);
ali@351
   377
		return rr->path;
ali@351
   378
	} else
ali@351
   379
		return path;
ali@351
   380
}
ali@351
   381
ali@351
   382
RAZOR_EXPORT void razor_relocations_destroy(struct razor_relocations *rr)
ali@351
   383
{
ali@351
   384
	free(rr->path);
ali@351
   385
	free(rr->relocations);
ali@351
   386
	free(rr);
ali@351
   387
}
ali@351
   388
rhughes@241
   389
static struct rpm_header_index *
rhughes@241
   390
razor_rpm_get_header(struct razor_rpm *rpm, unsigned int tag)
rhughes@241
   391
{
rhughes@241
   392
	struct rpm_header_index *index, *end;
rhughes@241
   393
rhughes@241
   394
	index = (struct rpm_header_index *) (rpm->header + 1);
rhughes@241
   395
	end = index + ntohl(rpm->header->nindex);
rhughes@241
   396
	while (index < end) {
rhughes@241
   397
		if (ntohl(index->tag) == tag)
rhughes@241
   398
			return index;
rhughes@241
   399
		index++;
rhughes@241
   400
	}
rhughes@241
   401
rhughes@241
   402
	return NULL;
rhughes@241
   403
}
rhughes@241
   404
rhughes@241
   405
static const void *
rhughes@241
   406
razor_rpm_get_indirect(struct razor_rpm *rpm,
rhughes@241
   407
		       unsigned int tag, unsigned int *count)
rhughes@241
   408
{
rhughes@241
   409
	struct rpm_header_index *index;
rhughes@241
   410
rhughes@241
   411
	index = razor_rpm_get_header(rpm, tag);
rhughes@241
   412
	if (index != NULL) {
rhughes@241
   413
		if (count)
rhughes@241
   414
			*count = ntohl(index->count);
rhughes@241
   415
rhughes@241
   416
		return rpm->pool + ntohl(index->offset);
rhughes@241
   417
	}
rhughes@241
   418
rhughes@241
   419
	return NULL;
rhughes@241
   420
}
rhughes@241
   421
krh@247
   422
static uint32_t
rhughes@241
   423
rpm_to_razor_flags(uint32_t flags)
rhughes@241
   424
{
krh@247
   425
	uint32_t razor_flags;
rhughes@241
   426
krh@247
   427
	razor_flags = 0;
krh@247
   428
	if (flags & RPMSENSE_LESS)
krh@247
   429
		razor_flags |= RAZOR_PROPERTY_LESS;
krh@247
   430
	if (flags & RPMSENSE_EQUAL)
krh@247
   431
		razor_flags |= RAZOR_PROPERTY_EQUAL;
krh@247
   432
	if (flags & RPMSENSE_GREATER)
krh@247
   433
		razor_flags |= RAZOR_PROPERTY_GREATER;
krh@247
   434
krh@247
   435
	if (flags & RPMSENSE_SCRIPT_PRE)
krh@247
   436
		razor_flags |= RAZOR_PROPERTY_PRE;
krh@247
   437
	if (flags & RPMSENSE_SCRIPT_POST)
krh@247
   438
		razor_flags |= RAZOR_PROPERTY_POST;
krh@247
   439
	if (flags & RPMSENSE_SCRIPT_PREUN)
krh@247
   440
		razor_flags |= RAZOR_PROPERTY_PREUN;
krh@247
   441
	if (flags & RPMSENSE_SCRIPT_POSTUN)
krh@247
   442
		razor_flags |= RAZOR_PROPERTY_POSTUN;
krh@247
   443
	
krh@247
   444
	return razor_flags;
rhughes@241
   445
}
rhughes@241
   446
rhughes@241
   447
static void
krh@247
   448
import_properties(struct razor_importer *importer, uint32_t type,
rhughes@241
   449
		  struct razor_rpm *rpm,
rhughes@241
   450
		  int name_tag, int version_tag, int flags_tag)
rhughes@241
   451
{
rhughes@241
   452
	const char *name, *version;
rhughes@241
   453
	const uint32_t *flags;
rhughes@241
   454
	uint32_t f;
rhughes@241
   455
	unsigned int i, count;
rhughes@241
   456
rhughes@241
   457
	name = razor_rpm_get_indirect(rpm, name_tag, &count);
rhughes@241
   458
	if (name == NULL)
rhughes@241
   459
		return;
rhughes@241
   460
rhughes@241
   461
	flags = razor_rpm_get_indirect(rpm, flags_tag, &count);
rhughes@241
   462
rhughes@241
   463
	version = razor_rpm_get_indirect(rpm, version_tag, &count);
rhughes@241
   464
	for (i = 0; i < count; i++) {
rhughes@241
   465
		f = rpm_to_razor_flags(ntohl(flags[i]));
krh@247
   466
		razor_importer_add_property(importer, name, f | type, version);
rhughes@241
   467
		name += strlen(name) + 1;
rhughes@241
   468
		version += strlen(version) + 1;
rhughes@241
   469
	}
rhughes@241
   470
}
rhughes@241
   471
rhughes@241
   472
static void
rhughes@241
   473
import_files(struct razor_importer *importer, struct razor_rpm *rpm)
rhughes@241
   474
{
rhughes@241
   475
	const char *name;
rhughes@241
   476
	const uint32_t *index;
rhughes@241
   477
	unsigned int i, count;
rhughes@241
   478
	char buffer[256];
rhughes@241
   479
krh@246
   480
	if (rpm->dirs == NULL)
krh@246
   481
		return;
krh@246
   482
rhughes@241
   483
	/* assert: count is the same for all arrays */
rhughes@241
   484
	index = razor_rpm_get_indirect(rpm, RPMTAG_DIRINDEXES, &count);
rhughes@241
   485
	name = razor_rpm_get_indirect(rpm, RPMTAG_BASENAMES, &count);
rhughes@241
   486
	for (i = 0; i < count; i++) {
rhughes@241
   487
		snprintf(buffer, sizeof buffer,
rhughes@241
   488
			 "%s%s", rpm->dirs[ntohl(*index)], name);
rhughes@241
   489
		razor_importer_add_file(importer, buffer);
rhughes@241
   490
		name += strlen(name) + 1;
rhughes@241
   491
		index++;
rhughes@241
   492
	}
rhughes@241
   493
}
rhughes@241
   494
ali@369
   495
static void
ali@369
   496
razor_rpm_build_evr(struct razor_rpm *rpm)
ali@369
   497
{
ali@369
   498
	const char *version, *release;
ali@369
   499
	const uint32_t *epoch;
ali@369
   500
	char evr[128], buf[16];
ali@369
   501
ali@369
   502
	epoch = razor_rpm_get_indirect(rpm, RPMTAG_EPOCH, NULL);
ali@369
   503
	version = razor_rpm_get_indirect(rpm, RPMTAG_VERSION, NULL);
ali@369
   504
	release = razor_rpm_get_indirect(rpm, RPMTAG_RELEASE, NULL);
ali@369
   505
	if (epoch)
ali@369
   506
		snprintf(buf, sizeof buf, "%lu", (unsigned long)ntohl(*epoch));
ali@369
   507
	razor_build_evr(evr, sizeof evr, epoch ? buf : NULL, version, release);
ali@369
   508
	rpm->evr = strdup(evr);
ali@369
   509
}
ali@369
   510
ali@369
   511
static const char *
ali@372
   512
razor_rpm_get_details_string(struct razor_rpm *rpm, enum razor_detail_type type)
ali@369
   513
{
ali@369
   514
	switch(type) {
ali@369
   515
	case RAZOR_DETAIL_NAME:
ali@369
   516
		return razor_rpm_get_indirect(rpm, RPMTAG_NAME, NULL);
ali@369
   517
ali@369
   518
	case RAZOR_DETAIL_VERSION:
ali@369
   519
		if (!rpm->evr)
ali@369
   520
			razor_rpm_build_evr(rpm);
ali@369
   521
		return rpm->evr;
ali@369
   522
ali@369
   523
	case RAZOR_DETAIL_ARCH:
ali@369
   524
		return razor_rpm_get_indirect(rpm, RPMTAG_ARCH, NULL);
ali@369
   525
ali@369
   526
	case RAZOR_DETAIL_SUMMARY:
ali@369
   527
		return razor_rpm_get_indirect(rpm, RPMTAG_SUMMARY, NULL);
ali@369
   528
ali@369
   529
	case RAZOR_DETAIL_DESCRIPTION:
ali@369
   530
		return razor_rpm_get_indirect(rpm, RPMTAG_DESCRIPTION, NULL);
ali@369
   531
ali@369
   532
	case RAZOR_DETAIL_URL:
ali@369
   533
		return razor_rpm_get_indirect(rpm, RPMTAG_URL, NULL);
ali@369
   534
ali@369
   535
	case RAZOR_DETAIL_LICENSE:
ali@369
   536
		return razor_rpm_get_indirect(rpm, RPMTAG_LICENSE, NULL);
ali@369
   537
ali@369
   538
	case RAZOR_DETAIL_PREUNPROG:
ali@369
   539
		return razor_rpm_get_indirect(rpm, RPMTAG_PREUNPROG, NULL);
ali@369
   540
ali@369
   541
	case RAZOR_DETAIL_PREUN:
ali@369
   542
		return razor_rpm_get_indirect(rpm, RPMTAG_PREUN, NULL);
ali@369
   543
ali@369
   544
	case RAZOR_DETAIL_POSTUNPROG:
ali@369
   545
		return razor_rpm_get_indirect(rpm, RPMTAG_POSTUNPROG, NULL);
ali@369
   546
ali@369
   547
	case RAZOR_DETAIL_POSTUN:
ali@369
   548
		return razor_rpm_get_indirect(rpm, RPMTAG_POSTUN, NULL);
ali@369
   549
ali@369
   550
	default:
ali@369
   551
		fprintf(stderr, "type %u not found\n", type);
ali@369
   552
		return NULL;
ali@369
   553
	}
ali@369
   554
}
ali@369
   555
ali@372
   556
static const char *const *
ali@372
   557
razor_rpm_get_details_array(struct razor_rpm *rpm, enum razor_detail_type type)
ali@372
   558
{
ali@372
   559
	switch(type) {
ali@372
   560
	case RAZOR_DETAIL_PREFIXES:
ali@372
   561
		return rpm->prefixes;
ali@372
   562
ali@372
   563
	default:
ali@372
   564
		/* Impossible */
ali@372
   565
		fprintf(stderr, "type %u not found\n", type);
ali@372
   566
		return NULL;
ali@372
   567
	}
ali@372
   568
}
ali@372
   569
ali@369
   570
void
ali@369
   571
razor_rpm_get_details_varg(struct razor_rpm *rpm, va_list args)
ali@369
   572
{
ali@369
   573
	int i;
ali@369
   574
	enum razor_detail_type type;
ali@372
   575
	const char **string;
ali@372
   576
	const char *const **array;
ali@369
   577
ali@369
   578
	for (i = 0;; i += 2) {
ali@369
   579
		type = va_arg(args, enum razor_detail_type);
ali@369
   580
		if (type == RAZOR_DETAIL_LAST)
ali@369
   581
			break;
ali@372
   582
		if (type == RAZOR_DETAIL_PREFIXES) {
ali@372
   583
			array = va_arg(args, const char *const **);
ali@372
   584
			*array = razor_rpm_get_details_array(rpm, type);
ali@372
   585
		} else {
ali@372
   586
			string = va_arg(args, const char **);
ali@372
   587
			*string = razor_rpm_get_details_string(rpm, type);
ali@372
   588
		}
ali@369
   589
        }
ali@369
   590
}
ali@369
   591
ali@369
   592
RAZOR_EXPORT void
ali@369
   593
razor_rpm_get_details(struct razor_rpm *rpm, ...)
ali@369
   594
{
ali@369
   595
	va_list args;
ali@369
   596
ali@369
   597
	assert(rpm != NULL);
ali@369
   598
ali@369
   599
	va_start(args, rpm);
ali@369
   600
	razor_rpm_get_details_varg(rpm, args);
ali@369
   601
	va_end(args);
ali@369
   602
}
ali@369
   603
krh@269
   604
RAZOR_EXPORT struct razor_rpm *
ali@403
   605
razor_rpm_open(const char *filename, struct razor_atomic *atomic)
rhughes@241
   606
{
rhughes@241
   607
	struct razor_rpm *rpm;
rhughes@241
   608
	struct rpm_header_index *base, *index;
rhughes@241
   609
	unsigned int count, i, nindex, hsize;
ali@351
   610
	const char *name, *prefix;
ali@403
   611
	char *s;
rhughes@241
   612
richard@301
   613
	assert (filename != NULL);
richard@301
   614
ali@403
   615
	rpm = zalloc(sizeof *rpm);
ali@403
   616
	if (rpm == NULL) {
ali@403
   617
		razor_atomic_abort(atomic, "Not enough memory");
krh@246
   618
		return NULL;
ali@403
   619
	}
rhughes@241
   620
	memset(rpm, 0, sizeof *rpm);
rhughes@241
   621
ali@322
   622
	rpm->map = razor_file_get_contents(filename, &rpm->size);
ali@322
   623
	if (!rpm->map) {
ali@403
   624
		s = razor_concat(filename, ": ", strerror(errno), NULL);
ali@403
   625
		razor_atomic_abort(atomic, s);
ali@403
   626
		free(s);
ali@403
   627
		free(rpm);
rhughes@241
   628
		return NULL;
rhughes@241
   629
	}
rhughes@241
   630
rhughes@241
   631
	rpm->signature = rpm->map + RPM_LEAD_SIZE;
rhughes@241
   632
	nindex = ntohl(rpm->signature->nindex);
rhughes@241
   633
	hsize = ntohl(rpm->signature->hsize);
rhughes@241
   634
	rpm->header = (void *) (rpm->signature + 1) +
rhughes@241
   635
		ALIGN(nindex * sizeof *index + hsize, 8);
rhughes@241
   636
	nindex = ntohl(rpm->header->nindex);
rhughes@241
   637
	hsize = ntohl(rpm->header->hsize);
rhughes@241
   638
	rpm->payload = (void *) (rpm->header + 1) +
rhughes@241
   639
		nindex * sizeof *index + hsize;
rhughes@241
   640
rhughes@241
   641
	base = (struct rpm_header_index *) (rpm->header + 1);
rhughes@241
   642
	rpm->pool = (void *) base + nindex * sizeof *index;
rhughes@241
   643
rhughes@241
   644
	/* Look up dir names now so we can index them directly. */
rhughes@241
   645
	name = razor_rpm_get_indirect(rpm, RPMTAG_DIRNAMES, &count);
rhughes@241
   646
	if (name) {
rhughes@241
   647
		rpm->dirs = calloc(count, sizeof *rpm->dirs);
rhughes@241
   648
		for (i = 0; i < count; i++) {
rhughes@241
   649
			rpm->dirs[i] = name;
rhughes@241
   650
			name += strlen(name) + 1;
rhughes@241
   651
		}
rhughes@241
   652
	} else {
rhughes@241
   653
		name = razor_rpm_get_indirect(rpm, RPMTAG_OLDFILENAMES,
rhughes@241
   654
					      &count);
rhughes@241
   655
		if (name) {
ali@403
   656
			razor_rpm_close(rpm);
ali@403
   657
			s = razor_concat(filename,
ali@403
   658
					 ": Old filenames not supported", NULL);
ali@403
   659
			razor_atomic_abort(atomic, s);
ali@403
   660
			free(s);
rhughes@241
   661
			return NULL;
rhughes@241
   662
		}
rhughes@241
   663
	}
rhughes@241
   664
ali@351
   665
	prefix = razor_rpm_get_indirect(rpm, RPMTAG_PREFIXES, &count);
ali@351
   666
	if (prefix) {
ali@372
   667
		rpm->prefixes = calloc(count + 1, sizeof *rpm->prefixes);
ali@351
   668
		for (i = 0; i < count; i++) {
ali@351
   669
			rpm->prefixes[i] = prefix;
ali@351
   670
			prefix += strlen(prefix) + 1;
ali@351
   671
		}
ali@372
   672
		rpm->prefixes[i] = NULL;
ali@351
   673
		rpm->n_prefixes = count;
ali@351
   674
	} else {
ali@351
   675
		prefix = razor_rpm_get_indirect(rpm, RPMTAG_DEFAULTPREFIX,
ali@351
   676
						&count);
ali@351
   677
		if (prefix) {
ali@403
   678
			razor_rpm_close(rpm);
ali@403
   679
			s = razor_concat(filename,
ali@403
   680
					 ": Default prefix not supported",
ali@403
   681
					 NULL);
ali@403
   682
			razor_atomic_abort(atomic, s);
ali@403
   683
			free(s);
ali@351
   684
			return NULL;
ali@351
   685
		}
ali@351
   686
	}
ali@351
   687
rhughes@241
   688
	return rpm;
rhughes@241
   689
}
rhughes@241
   690
ali@351
   691
RAZOR_EXPORT void razor_rpm_set_relocations(struct razor_rpm *rpm,
ali@351
   692
					    struct razor_relocations *rr)
ali@351
   693
{
ali@351
   694
	assert (rpm != NULL);
ali@351
   695
ali@351
   696
	rpm->relocations = rr;
ali@351
   697
}
ali@351
   698
rhughes@241
   699
struct cpio_file_header {
rhughes@241
   700
	char magic[6];
rhughes@241
   701
	char inode[8];
rhughes@241
   702
	char mode[8];
rhughes@241
   703
	char uid[8];
rhughes@241
   704
	char gid[8];
rhughes@241
   705
	char nlink[8];
rhughes@241
   706
	char mtime[8];
rhughes@241
   707
	char filesize[8];
rhughes@241
   708
	char devmajor[8];
rhughes@241
   709
	char devminor[8];
rhughes@241
   710
	char rdevmajor[8];
rhughes@241
   711
	char rdevminor[8];
rhughes@241
   712
	char namesize[8];
rhughes@241
   713
	char checksum[8];
rhughes@241
   714
	char filename[0];
rhughes@241
   715
};
rhughes@241
   716
rhughes@241
   717
/* gzip flags */
rhughes@241
   718
#define ASCII_FLAG   0x01 /* bit 0 set: file probably ascii text */
rhughes@241
   719
#define HEAD_CRC     0x02 /* bit 1 set: header CRC present */
rhughes@241
   720
#define EXTRA_FIELD  0x04 /* bit 2 set: extra field present */
rhughes@241
   721
#define ORIG_NAME    0x08 /* bit 3 set: original file name present */
rhughes@241
   722
#define COMMENT      0x10 /* bit 4 set: file comment present */
rhughes@241
   723
#define RESERVED     0xE0 /* bits 5..7: reserved */
rhughes@241
   724
rhughes@241
   725
struct installer {
rhughes@241
   726
	const char *root;
rhughes@241
   727
	struct razor_rpm *rpm;
ali@403
   728
	struct razor_atomic *atomic;
rhughes@241
   729
	z_stream stream;
rhughes@241
   730
	unsigned char buffer[32768];
rhughes@241
   731
	size_t rest, length;
rhughes@241
   732
};
rhughes@241
   733
rhughes@241
   734
static int
rhughes@241
   735
installer_inflate(struct installer *installer)
rhughes@241
   736
{
rhughes@241
   737
	size_t length;
rhughes@241
   738
	int err;
rhughes@241
   739
rhughes@241
   740
	if (installer->rest > sizeof installer->buffer)
rhughes@241
   741
		length = sizeof installer->buffer;
rhughes@241
   742
	else
rhughes@241
   743
		length = installer->rest;
rhughes@241
   744
rhughes@241
   745
	installer->stream.next_out = installer->buffer;
rhughes@241
   746
	installer->stream.avail_out = length;
rhughes@241
   747
	err = inflate(&installer->stream, Z_SYNC_FLUSH);
rhughes@241
   748
	if (err != Z_OK && err != Z_STREAM_END) {
ali@403
   749
		razor_atomic_abort(installer->atomic, "Failed to inflate");
rhughes@241
   750
		return -1;
rhughes@241
   751
	}
rhughes@241
   752
rhughes@241
   753
	installer->rest -= length;
rhughes@241
   754
	installer->length = length;
rhughes@241
   755
rhughes@241
   756
	return 0;
rhughes@241
   757
}
rhughes@241
   758
rhughes@241
   759
static int
rhughes@241
   760
installer_align(struct installer *installer, size_t size)
rhughes@241
   761
{
rhughes@241
   762
	unsigned char buffer[4];
rhughes@241
   763
	int err;
rhughes@241
   764
rhughes@241
   765
	installer->stream.next_out = buffer;
rhughes@241
   766
	installer->stream.avail_out =
rhughes@241
   767
		(size - installer->stream.total_out) & (size - 1);
rhughes@241
   768
rhughes@241
   769
	if (installer->stream.avail_out == 0)
rhughes@241
   770
		return 0;
rhughes@241
   771
rhughes@241
   772
	err = inflate(&installer->stream, Z_SYNC_FLUSH);
rhughes@241
   773
	if (err != Z_OK && err != Z_STREAM_END) {
ali@403
   774
		razor_atomic_abort(installer->atomic, "Failed to inflate");
rhughes@241
   775
		return -1;
rhughes@241
   776
	}
rhughes@241
   777
rhughes@241
   778
	return 0;
rhughes@241
   779
}
rhughes@241
   780
rhughes@241
   781
static int
rhughes@241
   782
create_path(struct installer *installer, const char *path, unsigned int mode)
rhughes@241
   783
{
ali@403
   784
	char *s, *buffer;
ali@403
   785
	int h, ret;
rhughes@241
   786
ali@403
   787
	if (razor_atomic_make_dirs(installer->atomic, installer->root, path))
rhughes@241
   788
		return -1;
rhughes@241
   789
ali@403
   790
	buffer = razor_concat(installer->root, path, NULL);
rhughes@241
   791
rhughes@241
   792
	switch (mode >> 12) {
rhughes@241
   793
	case REG:
rhughes@241
   794
		/* FIXME: handle the case where a file is already there. */
ali@403
   795
		h = razor_atomic_create_file(installer->atomic, buffer, mode);
ali@403
   796
		free(buffer);
ali@403
   797
		if (h < 0)
rhughes@241
   798
			return -1;
ali@403
   799
		while (installer->rest > 0) {
ali@403
   800
			if (installer_inflate(installer))
ali@403
   801
				return -1;
ali@403
   802
			if (razor_atomic_write(installer->atomic, h,
ali@403
   803
					       installer->buffer,
ali@403
   804
					       installer->length))
ali@403
   805
				return -1;
rhughes@241
   806
		}
ali@403
   807
		return razor_atomic_close(installer->atomic, h);
rhughes@241
   808
	case XDIR:
ali@403
   809
		ret = razor_atomic_create_dir(installer->atomic, buffer, mode);
ali@403
   810
		free(buffer);
ali@403
   811
		return ret;
rhughes@241
   812
	case LINK:
ali@327
   813
#if HAVE_SYMLINK
ali@403
   814
		if (installer_inflate(installer))
rhughes@241
   815
			return -1;
rhughes@241
   816
		if (installer->length >= sizeof installer->buffer) {
ali@403
   817
			razor_atomic_abort(installer->atomic,
ali@403
   818
			  "Link target too long");
rhughes@241
   819
			return -1;
rhughes@241
   820
		}
rhughes@241
   821
		installer->buffer[installer->length] = '\0';
ali@403
   822
		ret = razor_atomic_create_symlink(installer->atomic,
ali@403
   823
		  (const char *)installer->buffer, buffer);
ali@403
   824
		free(buffer);
ali@403
   825
		return ret;
ali@327
   826
#else
ali@403
   827
		s = "Symbolic links";
ali@403
   828
		goto unsupported;
ali@327
   829
#endif
ali@327
   830
	case PIPE:
ali@403
   831
		s = "Named pipes";
ali@403
   832
unsupported:
ali@403
   833
		free(buffer);
ali@403
   834
		buffer = razor_concat(s, " are not supported on this platform",
ali@403
   835
		  NULL);
ali@403
   836
		razor_atomic_abort(installer->atomic, buffer);
ali@403
   837
		free(buffer);
ali@403
   838
		return -1;
ali@327
   839
	case CDEV:
ali@403
   840
		s = "Character devices";
ali@403
   841
		goto unsupported;
ali@327
   842
	case BDEV:
ali@403
   843
		s = "Block devices";
ali@403
   844
		goto unsupported;
ali@327
   845
	case SOCK:
ali@403
   846
		s = "Named sockets";
ali@403
   847
		goto unsupported;
rhughes@241
   848
	default:
ali@403
   849
		free(buffer);
ali@403
   850
		razor_atomic_abort(installer->atomic, "Unknown file type");
ali@403
   851
		return -1;
rhughes@241
   852
	}
rhughes@241
   853
}
rhughes@241
   854
ali@353
   855
static int chroot_push(const char *root)
ali@353
   856
{
ali@353
   857
	int fd;
ali@353
   858
#if HAVE_CHROOT
ali@353
   859
	if (geteuid() == 0) {
ali@353
   860
		fd = open("/", O_RDONLY, 0);
ali@353
   861
		if (chroot(root) < 0) {
ali@353
   862
			fprintf(stderr, "failed to chroot to %s: %s\n",
ali@353
   863
				root, strerror(errno));
ali@353
   864
			exit(-1);
ali@353
   865
		}
ali@353
   866
	} else
ali@353
   867
#endif
ali@353
   868
		fd = -1;
ali@353
   869
	return fd;
ali@353
   870
}
ali@353
   871
ali@353
   872
static void chroot_pop(int fd)
rhughes@241
   873
{
ali@328
   874
#if HAVE_CHROOT
ali@353
   875
	if (fd >= 0) {
ali@353
   876
		fchdir(fd);
ali@353
   877
		close(fd);
ali@353
   878
		chroot(".");
ali@353
   879
	}
ali@353
   880
#endif
ali@353
   881
}
ali@353
   882
ali@353
   883
static int
ali@376
   884
run_script_lua(const char *root, unsigned int script_tag, const char *script,
ali@376
   885
	       int arg1)
ali@353
   886
{
ali@353
   887
	int root_fd, retval;
ali@352
   888
#if HAVE_LUA
ali@353
   889
	const char *name;
ali@353
   890
ali@353
   891
	switch(script_tag) {
ali@353
   892
		case RPMTAG_PREIN:
ali@353
   893
			name = "%pre";
ali@353
   894
			break;
ali@353
   895
		case RPMTAG_POSTIN:
ali@353
   896
			name = "%post";
ali@353
   897
			break;
ali@353
   898
		case RPMTAG_PREUN:
ali@353
   899
			name = "%preun";
ali@353
   900
			break;
ali@353
   901
		case RPMTAG_POSTUN:
ali@353
   902
			name = "%postun";
ali@353
   903
			break;
ali@353
   904
		default:
ali@353
   905
			name = "script";
ali@353
   906
			break;
ali@353
   907
	}
ali@353
   908
	root_fd = chroot_push(root);
ali@376
   909
	retval = run_lua_script(root_fd < 0 ? root : NULL, name, script, -1,
ali@376
   910
				arg1);
ali@353
   911
	chroot_pop(root_fd);
ali@353
   912
#else	/* HAVE_LUA */
ali@353
   913
	fprintf(stderr, "lua not available to run script\n");
ali@353
   914
	retval = -1;
ali@353
   915
#endif	/* HAVE_LUA */
ali@353
   916
ali@353
   917
	return retval;
ali@353
   918
}
ali@353
   919
ali@353
   920
static int
ali@376
   921
run_script_external(const char *root, const char *program, const char *script,
ali@376
   922
		    int arg1)
ali@353
   923
{
ali@353
   924
	int root_fd, retval;
ali@328
   925
	FILE *fp;
ali@376
   926
	char buf[32], *command;
rhughes@241
   927
ali@353
   928
	if (program == NULL) {
ali@328
   929
#if MSWIN_API
ali@328
   930
		program = getenv("COMSPEC");
ali@328
   931
		if (program) {
ali@328
   932
			program = strchr(program, '=');
ali@328
   933
			if (program)
ali@328
   934
				program++;
ali@328
   935
		}
ali@328
   936
		if (!program)
ali@328
   937
			program = "c:\\windows\\system32\\cmd.exe";
ali@328
   938
#else
rhughes@241
   939
		program = "/bin/sh";
ali@328
   940
#endif
rhughes@241
   941
	}
rhughes@241
   942
ali@353
   943
	root_fd = chroot_push(root);
ali@376
   944
	if (arg1 >= 0) {
ali@376
   945
		sprintf(buf, "%d", arg1);
ali@376
   946
		command = malloc(strlen(program) + strlen(buf) + 2);
ali@376
   947
		sprintf(command, "%s %s", program, buf);
ali@376
   948
	} else
ali@376
   949
		command = strdup(program);
ali@376
   950
	fp = popen(command, "w");
ali@376
   951
	free(command);
rhughes@241
   952
ali@353
   953
	if (!fp) {
ali@353
   954
		perror(program);
ali@353
   955
		retval = -1;
ali@370
   956
	} else if (script && fwrite(script, strlen(script), 1, fp) != 1) {
ali@353
   957
		perror("failed to write script to program");
ali@353
   958
		retval = -1;
ali@353
   959
	} else
ali@353
   960
		retval = 0;
ali@353
   961
ali@353
   962
	if (fp)
ali@353
   963
		pclose(fp);
ali@353
   964
	chroot_pop(root_fd);
ali@353
   965
ali@353
   966
	return retval;
ali@353
   967
}
ali@353
   968
ali@353
   969
static int
ali@353
   970
run_script(struct installer *installer,
ali@376
   971
	   unsigned int program_tag, unsigned int script_tag, int arg1)
ali@353
   972
{
ali@362
   973
	int i, retval;
ali@362
   974
	struct razor_rpm *rpm = installer->rpm;
ali@362
   975
	const char *script = NULL, *program = NULL, *prefix;
ali@376
   976
	char buf[32];
ali@372
   977
	struct environment env;
ali@353
   978
ali@362
   979
	program = razor_rpm_get_indirect(rpm, program_tag, NULL);
ali@362
   980
	script = razor_rpm_get_indirect(rpm, script_tag, NULL);
ali@353
   981
	if (program == NULL && script == NULL)
ali@362
   982
		return 0;
ali@362
   983
ali@362
   984
	if (rpm->relocations) {
ali@372
   985
		environment_init(&env);
ali@362
   986
		for(i = 0; i < rpm->n_prefixes; i++) {
ali@362
   987
			prefix = razor_relocations_apply(rpm->relocations,
ali@362
   988
							 rpm->prefixes[i]);
ali@362
   989
			sprintf(buf, "RPM_INSTALL_PREFIX%d", i);
ali@372
   990
			environment_add_variable(&env, buf, prefix);
ali@362
   991
		}
ali@372
   992
		environment_set(&env);
ali@362
   993
	}
ali@362
   994
ali@369
   995
	if (program && strcmp(program, "<lua>") == 0)
ali@376
   996
		retval = run_script_lua(installer->root, script_tag, script,
ali@376
   997
					arg1);
ali@353
   998
	else
ali@376
   999
		retval = run_script_external(installer->root, program, script,
ali@376
  1000
					     arg1);
ali@353
  1001
ali@362
  1002
	if (rpm->relocations) {
ali@372
  1003
		environment_unset(&env);
ali@372
  1004
		environment_release(&env);
ali@362
  1005
	}
ali@362
  1006
ali@353
  1007
	return retval;
rhughes@241
  1008
}
rhughes@241
  1009
ali@369
  1010
int
ali@369
  1011
razor_run_script(const char *root, enum razor_property_flags script,
ali@376
  1012
		 const char *program, const char *body, int arg1)
ali@369
  1013
{
ali@369
  1014
	int retval;
ali@369
  1015
	unsigned int script_tag;
ali@369
  1016
ali@369
  1017
	if (program && !*program)
ali@369
  1018
		program = NULL;
ali@369
  1019
	if (body && !*body)
ali@369
  1020
		body = NULL;
ali@369
  1021
	if (program == NULL && body == NULL)
ali@369
  1022
		return 0;
ali@369
  1023
ali@369
  1024
	if (program && strcmp(program, "<lua>") == 0)
ali@369
  1025
	{
ali@369
  1026
		switch(script) {
ali@369
  1027
		case RAZOR_PROPERTY_PRE:
ali@369
  1028
			script_tag = RPMTAG_PREIN;
ali@369
  1029
			break;
ali@369
  1030
		case RAZOR_PROPERTY_POST:
ali@369
  1031
			script_tag = RPMTAG_POSTIN;
ali@369
  1032
			break;
ali@369
  1033
		case RAZOR_PROPERTY_PREUN:
ali@369
  1034
			script_tag = RPMTAG_PREUN;
ali@369
  1035
			break;
ali@369
  1036
		case RAZOR_PROPERTY_POSTUN:
ali@369
  1037
			script_tag = RPMTAG_POSTUN;
ali@369
  1038
			break;
ali@369
  1039
		default:
ali@369
  1040
			script_tag = 0;
ali@369
  1041
			break;
ali@369
  1042
		}
ali@376
  1043
		retval = run_script_lua(root, script_tag, body, arg1);
ali@369
  1044
	}
ali@369
  1045
	else
ali@376
  1046
		retval = run_script_external(root, program, body, arg1);
ali@369
  1047
ali@369
  1048
	return retval;
ali@369
  1049
}
ali@369
  1050
rhughes@241
  1051
static int
rhughes@241
  1052
installer_init(struct installer *installer)
rhughes@241
  1053
{
rhughes@241
  1054
	unsigned char *gz_header;
rhughes@241
  1055
	int method, flags, err;
ali@403
  1056
	char buffer[32], *s;
rhughes@241
  1057
rhughes@241
  1058
	gz_header = installer->rpm->payload;
rhughes@241
  1059
	if (gz_header[0] != 0x1f || gz_header[1] != 0x8b) {
ali@403
  1060
		razor_atomic_abort(installer->atomic, 
ali@403
  1061
				   "Payload section doesn't have gz header");
rhughes@241
  1062
		return -1;
rhughes@241
  1063
	}
rhughes@241
  1064
rhughes@241
  1065
	method = gz_header[2];
rhughes@241
  1066
	flags = gz_header[3];
rhughes@241
  1067
rhughes@241
  1068
	if (method != Z_DEFLATED || flags != 0) {
ali@403
  1069
		razor_atomic_abort(installer->atomic, 
ali@403
  1070
				   "Unknown payload compression method or "
ali@403
  1071
				   "flags set");
rhughes@241
  1072
		return -1;
rhughes@241
  1073
	}
rhughes@241
  1074
rhughes@241
  1075
	installer->stream.zalloc = NULL;
rhughes@241
  1076
	installer->stream.zfree = NULL;
rhughes@241
  1077
	installer->stream.opaque = NULL;
rhughes@241
  1078
rhughes@241
  1079
	installer->stream.next_in  = gz_header + 10;
rhughes@241
  1080
	installer->stream.avail_in =
rhughes@241
  1081
		(installer->rpm->map + installer->rpm->size) -
rhughes@241
  1082
		(void *) installer->stream.next_in;
rhughes@241
  1083
	installer->stream.next_out = NULL;
rhughes@241
  1084
	installer->stream.avail_out = 0;
rhughes@241
  1085
rhughes@241
  1086
	err = inflateInit2(&installer->stream, -MAX_WBITS);
rhughes@241
  1087
	if (err != Z_OK) {
ali@403
  1088
		sprintf(buffer, "%d", err);
ali@403
  1089
		s = razor_concat("inflateEnd error: ", s, NULL);
ali@403
  1090
		razor_atomic_abort(installer->atomic, s);
ali@403
  1091
		free(s);
rhughes@241
  1092
		return -1;
rhughes@241
  1093
	}
rhughes@241
  1094
rhughes@241
  1095
	return 0;
rhughes@241
  1096
}
rhughes@241
  1097
rhughes@241
  1098
static int
rhughes@241
  1099
installer_finish(struct installer *installer)
rhughes@241
  1100
{
rhughes@241
  1101
	int err;
ali@403
  1102
	char buffer[32], *s;
rhughes@241
  1103
rhughes@241
  1104
	err = inflateEnd(&installer->stream);
rhughes@241
  1105
rhughes@241
  1106
	if (err != Z_OK) {
ali@403
  1107
		sprintf(buffer, "%d", err);
ali@403
  1108
		s = razor_concat("inflateEnd error: ", s, NULL);
ali@403
  1109
		razor_atomic_abort(installer->atomic, s);
ali@403
  1110
		free(s);
rhughes@241
  1111
	}
rhughes@241
  1112
ali@403
  1113
	return razor_atomic_in_error_state(installer->atomic);
rhughes@241
  1114
}
rhughes@241
  1115
rhughes@241
  1116
static unsigned long
rhughes@241
  1117
fixed_hex_to_ulong(const char *hex, int length)
rhughes@241
  1118
{
rhughes@241
  1119
	long l;
rhughes@241
  1120
	int i;
rhughes@241
  1121
rhughes@241
  1122
	for (i = 0, l = 0; i < length; i++) {
rhughes@241
  1123
		if (hex[i] < 'a')
rhughes@241
  1124
			l = l * 16 + hex[i] - '0';
rhughes@241
  1125
		else
rhughes@241
  1126
			l = l * 16 + hex[i] - 'a' + 10;
rhughes@241
  1127
	}
rhughes@241
  1128
rhughes@241
  1129
	return l;
rhughes@241
  1130
}
rhughes@241
  1131
krh@269
  1132
RAZOR_EXPORT int
ali@403
  1133
razor_rpm_install(struct razor_rpm *rpm, struct razor_atomic *atomic,
ali@403
  1134
		  const char *root, int install_count,
ali@403
  1135
		  enum razor_stage_type stage)
rhughes@241
  1136
{
rhughes@241
  1137
	struct installer installer;
rhughes@241
  1138
	struct cpio_file_header *header;
rhughes@241
  1139
	struct stat buf;
rhughes@241
  1140
	unsigned int mode;
ali@403
  1141
	const char *path, *name;
rhughes@241
  1142
	size_t filesize;
ali@403
  1143
	char *s;
rhughes@241
  1144
richard@301
  1145
	assert (rpm != NULL);
richard@301
  1146
	assert (root != NULL);
richard@301
  1147
rhughes@241
  1148
	installer.rpm = rpm;
rhughes@241
  1149
	installer.root = root;
ali@403
  1150
	installer.atomic = atomic;
rhughes@241
  1151
rhughes@241
  1152
	/* FIXME: Only do this before a transaction, not per rpm. */
ali@347
  1153
	if (*root && (stat(root, &buf) < 0 || !S_ISDIR(buf.st_mode))) {
ali@403
  1154
		s = razor_concat(root, ": Directory does not exist", NULL);
ali@403
  1155
		razor_atomic_abort(stderr, s);
ali@403
  1156
		free(s);
rhughes@241
  1157
		return -1;
rhughes@241
  1158
	}
rhughes@241
  1159
ali@351
  1160
	if (rpm->relocations)
ali@351
  1161
		razor_relocations_set_rpm(rpm->relocations, rpm);
ali@351
  1162
ali@403
  1163
	if (stage & RAZOR_STAGE_SCRIPTS_PRE)
ali@403
  1164
		run_script(&installer, RPMTAG_PREINPROG, RPMTAG_PREIN,
ali@403
  1165
			   install_count);
rhughes@241
  1166
ali@403
  1167
	if (stage & RAZOR_STAGE_FILES) {
ali@403
  1168
		if (installer_init(&installer))
rhughes@241
  1169
			return -1;
rhughes@241
  1170
ali@403
  1171
		while (installer.stream.avail_in > 0) {
ali@403
  1172
			installer.rest = sizeof *header;
ali@403
  1173
			if (installer_inflate(&installer))
ali@403
  1174
				break;
rhughes@241
  1175
ali@403
  1176
			header = (struct cpio_file_header *) installer.buffer;
ali@403
  1177
			mode = fixed_hex_to_ulong(header->mode,
ali@403
  1178
						  sizeof header->mode);
ali@403
  1179
			filesize = fixed_hex_to_ulong(header->filesize,
ali@403
  1180
						      sizeof header->filesize);
rhughes@241
  1181
ali@403
  1182
			installer.rest =
ali@403
  1183
			  fixed_hex_to_ulong(header->namesize,
ali@403
  1184
					     sizeof header->namesize);
rhughes@241
  1185
ali@403
  1186
			if (installer_inflate(&installer) ||
ali@403
  1187
			    installer_align(&installer, 4))
ali@403
  1188
				break;
rhughes@241
  1189
ali@403
  1190
			path = (const char *) installer.buffer;
ali@403
  1191
			/* This convention is so lame... */
ali@403
  1192
			if (strcmp(path, "TRAILER!!!") == 0)
ali@403
  1193
				break;
ali@403
  1194
ali@403
  1195
			installer.rest = filesize;
ali@403
  1196
			path++;
ali@403
  1197
			if (rpm->relocations)
ali@403
  1198
				path = razor_relocations_apply(rpm->relocations,
ali@403
  1199
							       path);
ali@403
  1200
			if (create_path(&installer, path, mode))
ali@403
  1201
				break;
ali@403
  1202
			if (installer_align(&installer, 4))
ali@403
  1203
				break;
ali@403
  1204
		}
ali@403
  1205
ali@403
  1206
		if (installer_finish(&installer))
rhughes@241
  1207
			return -1;
rhughes@241
  1208
	}
rhughes@241
  1209
ali@403
  1210
	if (stage & RAZOR_STAGE_SCRIPTS_POST)
ali@403
  1211
		run_script(&installer, RPMTAG_POSTINPROG, RPMTAG_POSTIN,
ali@403
  1212
			   install_count);
rhughes@241
  1213
rhughes@241
  1214
	return 0;
rhughes@241
  1215
}
rhughes@241
  1216
krh@269
  1217
RAZOR_EXPORT int
rhughes@241
  1218
razor_rpm_close(struct razor_rpm *rpm)
rhughes@241
  1219
{
rhughes@241
  1220
	int err;
rhughes@241
  1221
richard@301
  1222
	assert (rpm != NULL);
richard@301
  1223
rhughes@241
  1224
	free(rpm->dirs);
ali@351
  1225
	free(rpm->prefixes);
ali@322
  1226
	err = razor_file_free_contents(rpm->map, rpm->size);
ali@369
  1227
	free(rpm->evr);
rhughes@241
  1228
	free(rpm);
rhughes@241
  1229
rhughes@241
  1230
	return err;
rhughes@241
  1231
}
rhughes@241
  1232
krh@269
  1233
RAZOR_EXPORT int
rhughes@241
  1234
razor_importer_add_rpm(struct razor_importer *importer, struct razor_rpm *rpm)
rhughes@241
  1235
{
ali@369
  1236
	const char *name, *version, *arch;
jbowes@289
  1237
	const char *summary, *description, *url, *license;
rhughes@241
  1238
richard@301
  1239
	assert (importer != NULL);
richard@301
  1240
	assert (rpm != NULL);
richard@301
  1241
ali@369
  1242
	razor_rpm_get_details(rpm,
ali@369
  1243
			      RAZOR_DETAIL_NAME, &name,
ali@369
  1244
			      RAZOR_DETAIL_VERSION, &version,
ali@369
  1245
			      RAZOR_DETAIL_ARCH, &arch,
ali@369
  1246
			      RAZOR_DETAIL_SUMMARY, &summary,
ali@369
  1247
			      RAZOR_DETAIL_DESCRIPTION, &description,
ali@369
  1248
			      RAZOR_DETAIL_URL, &url,
ali@369
  1249
			      RAZOR_DETAIL_LICENSE, &license,
ali@369
  1250
			      RAZOR_DETAIL_LAST);
jbowes@289
  1251
ali@369
  1252
	razor_importer_begin_package(importer, name, version, arch);
rhughes@241
  1253
jbowes@289
  1254
	razor_importer_add_details(importer, summary, description, url,
jbowes@289
  1255
				   license);
jbowes@289
  1256
rhughes@241
  1257
	import_properties(importer, RAZOR_PROPERTY_REQUIRES, rpm,
rhughes@241
  1258
			  RPMTAG_REQUIRENAME,
rhughes@241
  1259
			  RPMTAG_REQUIREVERSION,
rhughes@241
  1260
			  RPMTAG_REQUIREFLAGS);
rhughes@241
  1261
rhughes@241
  1262
	import_properties(importer, RAZOR_PROPERTY_PROVIDES, rpm,
rhughes@241
  1263
			  RPMTAG_PROVIDENAME,
rhughes@241
  1264
			  RPMTAG_PROVIDEVERSION,
rhughes@241
  1265
			  RPMTAG_PROVIDEFLAGS);
rhughes@241
  1266
rhughes@241
  1267
	import_properties(importer, RAZOR_PROPERTY_OBSOLETES, rpm,
rhughes@241
  1268
			  RPMTAG_OBSOLETENAME,
rhughes@241
  1269
			  RPMTAG_OBSOLETEVERSION,
rhughes@241
  1270
			  RPMTAG_OBSOLETEFLAGS);
rhughes@241
  1271
rhughes@241
  1272
	import_properties(importer, RAZOR_PROPERTY_CONFLICTS, rpm,
rhughes@241
  1273
			  RPMTAG_CONFLICTNAME,
rhughes@241
  1274
			  RPMTAG_CONFLICTVERSION,
rhughes@241
  1275
			  RPMTAG_CONFLICTFLAGS);
rhughes@241
  1276
rhughes@241
  1277
	import_files(importer, rpm);
rhughes@241
  1278
rhughes@241
  1279
	razor_importer_finish_package(importer);
rhughes@241
  1280
rhughes@241
  1281
	return 0;
rhughes@241
  1282
}