librazor/rpm.c
author J. Ali Harlow <ali@juiblex.co.uk>
Sat Oct 04 18:12:58 2014 +0100 (2014-10-04)
changeset 454 56ff755c268c
parent 442 c4bcba8023a9
child 458 3f841a46eab5
permissions -rw-r--r--
Only export symbols starting with razor_ in dynamic library.

Apart from being good practice to avoid clashes with higher-level
libraries and the application, this also fixes an obscure bug: The
gnulib library is used both by librazor (the dynamic library) and
by razor (the executable). In doing so, we want to have two separate
copies of the library despite the code duplication this involves.
Without the explicit limit to export only razor_ symbols, the razor
executable under mingw64 was picking up the getopt_long function
from librazor and the optind variable from libgnu which meant that
it did not see optind changing. Hiding librazor's copy of getopt
causes the linker to find libgnu's copy and everything works.

Note that under mingw librazor-#.dll still contains undocumented
(private) razor_ symbols but these will do no harm as long as nobody
tries to use them.
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@422
     4
 * Copyright (C) 2009, 2011, 2012  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@426
   605
razor_rpm_open(const char *filename, struct razor_error **error)
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;
rhughes@241
   611
richard@301
   612
	assert (filename != NULL);
richard@301
   613
ali@403
   614
	rpm = zalloc(sizeof *rpm);
ali@403
   615
	if (rpm == NULL) {
ali@447
   616
		razor_set_error(error, RAZOR_POSIX_ERROR, ENOMEM, NULL,
ali@447
   617
				"Not enough memory");
krh@246
   618
		return NULL;
ali@403
   619
	}
rhughes@241
   620
	memset(rpm, 0, sizeof *rpm);
rhughes@241
   621
ali@426
   622
	rpm->map = razor_file_get_contents(filename, &rpm->size, 0, error);
ali@322
   623
	if (!rpm->map) {
ali@403
   624
		free(rpm);
rhughes@241
   625
		return NULL;
rhughes@241
   626
	}
rhughes@241
   627
rhughes@241
   628
	rpm->signature = rpm->map + RPM_LEAD_SIZE;
rhughes@241
   629
	nindex = ntohl(rpm->signature->nindex);
rhughes@241
   630
	hsize = ntohl(rpm->signature->hsize);
rhughes@241
   631
	rpm->header = (void *) (rpm->signature + 1) +
rhughes@241
   632
		ALIGN(nindex * sizeof *index + hsize, 8);
rhughes@241
   633
	nindex = ntohl(rpm->header->nindex);
rhughes@241
   634
	hsize = ntohl(rpm->header->hsize);
rhughes@241
   635
	rpm->payload = (void *) (rpm->header + 1) +
rhughes@241
   636
		nindex * sizeof *index + hsize;
rhughes@241
   637
rhughes@241
   638
	base = (struct rpm_header_index *) (rpm->header + 1);
rhughes@241
   639
	rpm->pool = (void *) base + nindex * sizeof *index;
rhughes@241
   640
rhughes@241
   641
	/* Look up dir names now so we can index them directly. */
rhughes@241
   642
	name = razor_rpm_get_indirect(rpm, RPMTAG_DIRNAMES, &count);
rhughes@241
   643
	if (name) {
rhughes@241
   644
		rpm->dirs = calloc(count, sizeof *rpm->dirs);
rhughes@241
   645
		for (i = 0; i < count; i++) {
rhughes@241
   646
			rpm->dirs[i] = name;
rhughes@241
   647
			name += strlen(name) + 1;
rhughes@241
   648
		}
rhughes@241
   649
	} else {
rhughes@241
   650
		name = razor_rpm_get_indirect(rpm, RPMTAG_OLDFILENAMES,
rhughes@241
   651
					      &count);
rhughes@241
   652
		if (name) {
ali@403
   653
			razor_rpm_close(rpm);
ali@447
   654
			razor_set_error(error, RAZOR_GENERAL_ERROR,
ali@447
   655
					RAZOR_GENERAL_ERROR_RPM_UNSUPPORTED,
ali@447
   656
					filename,
ali@426
   657
					"Old filenames not supported");
rhughes@241
   658
			return NULL;
rhughes@241
   659
		}
rhughes@241
   660
	}
rhughes@241
   661
ali@351
   662
	prefix = razor_rpm_get_indirect(rpm, RPMTAG_PREFIXES, &count);
ali@351
   663
	if (prefix) {
ali@372
   664
		rpm->prefixes = calloc(count + 1, sizeof *rpm->prefixes);
ali@351
   665
		for (i = 0; i < count; i++) {
ali@351
   666
			rpm->prefixes[i] = prefix;
ali@351
   667
			prefix += strlen(prefix) + 1;
ali@351
   668
		}
ali@372
   669
		rpm->prefixes[i] = NULL;
ali@351
   670
		rpm->n_prefixes = count;
ali@351
   671
	} else {
ali@351
   672
		prefix = razor_rpm_get_indirect(rpm, RPMTAG_DEFAULTPREFIX,
ali@351
   673
						&count);
ali@351
   674
		if (prefix) {
ali@403
   675
			razor_rpm_close(rpm);
ali@447
   676
			razor_set_error(error, RAZOR_GENERAL_ERROR,
ali@447
   677
					RAZOR_GENERAL_ERROR_RPM_UNSUPPORTED,
ali@447
   678
					filename,
ali@426
   679
					"Default prefix not supported");
ali@351
   680
			return NULL;
ali@351
   681
		}
ali@351
   682
	}
ali@351
   683
rhughes@241
   684
	return rpm;
rhughes@241
   685
}
rhughes@241
   686
ali@351
   687
RAZOR_EXPORT void razor_rpm_set_relocations(struct razor_rpm *rpm,
ali@351
   688
					    struct razor_relocations *rr)
ali@351
   689
{
ali@351
   690
	assert (rpm != NULL);
ali@351
   691
ali@351
   692
	rpm->relocations = rr;
ali@351
   693
}
ali@351
   694
rhughes@241
   695
struct cpio_file_header {
rhughes@241
   696
	char magic[6];
rhughes@241
   697
	char inode[8];
rhughes@241
   698
	char mode[8];
rhughes@241
   699
	char uid[8];
rhughes@241
   700
	char gid[8];
rhughes@241
   701
	char nlink[8];
rhughes@241
   702
	char mtime[8];
rhughes@241
   703
	char filesize[8];
rhughes@241
   704
	char devmajor[8];
rhughes@241
   705
	char devminor[8];
rhughes@241
   706
	char rdevmajor[8];
rhughes@241
   707
	char rdevminor[8];
rhughes@241
   708
	char namesize[8];
rhughes@241
   709
	char checksum[8];
rhughes@241
   710
	char filename[0];
rhughes@241
   711
};
rhughes@241
   712
rhughes@241
   713
/* gzip flags */
rhughes@241
   714
#define ASCII_FLAG   0x01 /* bit 0 set: file probably ascii text */
rhughes@241
   715
#define HEAD_CRC     0x02 /* bit 1 set: header CRC present */
rhughes@241
   716
#define EXTRA_FIELD  0x04 /* bit 2 set: extra field present */
rhughes@241
   717
#define ORIG_NAME    0x08 /* bit 3 set: original file name present */
rhughes@241
   718
#define COMMENT      0x10 /* bit 4 set: file comment present */
rhughes@241
   719
#define RESERVED     0xE0 /* bits 5..7: reserved */
rhughes@241
   720
rhughes@241
   721
struct installer {
rhughes@241
   722
	const char *root;
rhughes@241
   723
	struct razor_rpm *rpm;
ali@403
   724
	struct razor_atomic *atomic;
rhughes@241
   725
	z_stream stream;
rhughes@241
   726
	unsigned char buffer[32768];
rhughes@241
   727
	size_t rest, length;
rhughes@241
   728
};
rhughes@241
   729
rhughes@241
   730
static int
rhughes@241
   731
installer_inflate(struct installer *installer)
rhughes@241
   732
{
rhughes@241
   733
	size_t length;
rhughes@241
   734
	int err;
rhughes@241
   735
rhughes@241
   736
	if (installer->rest > sizeof installer->buffer)
rhughes@241
   737
		length = sizeof installer->buffer;
rhughes@241
   738
	else
rhughes@241
   739
		length = installer->rest;
rhughes@241
   740
rhughes@241
   741
	installer->stream.next_out = installer->buffer;
rhughes@241
   742
	installer->stream.avail_out = length;
rhughes@241
   743
	err = inflate(&installer->stream, Z_SYNC_FLUSH);
rhughes@241
   744
	if (err != Z_OK && err != Z_STREAM_END) {
ali@447
   745
		razor_atomic_abort(installer->atomic, RAZOR_ZLIB_ERROR, err,
ali@447
   746
				   "Failed to inflate");
rhughes@241
   747
		return -1;
rhughes@241
   748
	}
rhughes@241
   749
rhughes@241
   750
	installer->rest -= length;
rhughes@241
   751
	installer->length = length;
rhughes@241
   752
rhughes@241
   753
	return 0;
rhughes@241
   754
}
rhughes@241
   755
rhughes@241
   756
static int
rhughes@241
   757
installer_align(struct installer *installer, size_t size)
rhughes@241
   758
{
rhughes@241
   759
	unsigned char buffer[4];
rhughes@241
   760
	int err;
rhughes@241
   761
rhughes@241
   762
	installer->stream.next_out = buffer;
rhughes@241
   763
	installer->stream.avail_out =
rhughes@241
   764
		(size - installer->stream.total_out) & (size - 1);
rhughes@241
   765
rhughes@241
   766
	if (installer->stream.avail_out == 0)
rhughes@241
   767
		return 0;
rhughes@241
   768
rhughes@241
   769
	err = inflate(&installer->stream, Z_SYNC_FLUSH);
rhughes@241
   770
	if (err != Z_OK && err != Z_STREAM_END) {
ali@447
   771
		razor_atomic_abort(installer->atomic, RAZOR_ZLIB_ERROR, err,
ali@447
   772
				   "Failed to inflate");
rhughes@241
   773
		return -1;
rhughes@241
   774
	}
rhughes@241
   775
rhughes@241
   776
	return 0;
rhughes@241
   777
}
rhughes@241
   778
rhughes@241
   779
static int
rhughes@241
   780
create_path(struct installer *installer, const char *path, unsigned int mode)
rhughes@241
   781
{
ali@403
   782
	char *s, *buffer;
ali@403
   783
	int h, ret;
rhughes@241
   784
ali@403
   785
	if (razor_atomic_make_dirs(installer->atomic, installer->root, path))
rhughes@241
   786
		return -1;
rhughes@241
   787
ali@403
   788
	buffer = razor_concat(installer->root, path, NULL);
rhughes@241
   789
rhughes@241
   790
	switch (mode >> 12) {
rhughes@241
   791
	case REG:
rhughes@241
   792
		/* FIXME: handle the case where a file is already there. */
ali@403
   793
		h = razor_atomic_create_file(installer->atomic, buffer, mode);
ali@403
   794
		free(buffer);
ali@403
   795
		if (h < 0)
rhughes@241
   796
			return -1;
ali@403
   797
		while (installer->rest > 0) {
ali@403
   798
			if (installer_inflate(installer))
ali@403
   799
				return -1;
ali@403
   800
			if (razor_atomic_write(installer->atomic, h,
ali@403
   801
					       installer->buffer,
ali@403
   802
					       installer->length))
ali@403
   803
				return -1;
rhughes@241
   804
		}
ali@403
   805
		return razor_atomic_close(installer->atomic, h);
rhughes@241
   806
	case XDIR:
ali@403
   807
		ret = razor_atomic_create_dir(installer->atomic, buffer, mode);
ali@403
   808
		free(buffer);
ali@403
   809
		return ret;
rhughes@241
   810
	case LINK:
ali@327
   811
#if HAVE_SYMLINK
ali@403
   812
		if (installer_inflate(installer))
rhughes@241
   813
			return -1;
rhughes@241
   814
		if (installer->length >= sizeof installer->buffer) {
ali@403
   815
			razor_atomic_abort(installer->atomic,
ali@447
   816
			  RAZOR_GENERAL_ERROR,
ali@447
   817
			  RAZOR_GENERAL_ERROR_RPM_UNSUPPORTED,
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@447
   836
		razor_atomic_abort(installer->atomic, RAZOR_GENERAL_ERROR,
ali@447
   837
		  RAZOR_GENERAL_ERROR_RPM_UNSUPPORTED, buffer);
ali@403
   838
		free(buffer);
ali@403
   839
		return -1;
ali@327
   840
	case CDEV:
ali@403
   841
		s = "Character devices";
ali@403
   842
		goto unsupported;
ali@327
   843
	case BDEV:
ali@403
   844
		s = "Block devices";
ali@403
   845
		goto unsupported;
ali@327
   846
	case SOCK:
ali@403
   847
		s = "Named sockets";
ali@403
   848
		goto unsupported;
rhughes@241
   849
	default:
ali@403
   850
		free(buffer);
ali@447
   851
		razor_atomic_abort(installer->atomic, RAZOR_GENERAL_ERROR,
ali@447
   852
		  RAZOR_GENERAL_ERROR_RPM_UNSUPPORTED, "Unknown file type");
ali@403
   853
		return -1;
rhughes@241
   854
	}
rhughes@241
   855
}
rhughes@241
   856
ali@353
   857
static int chroot_push(const char *root)
ali@353
   858
{
ali@353
   859
	int fd;
ali@353
   860
#if HAVE_CHROOT
ali@353
   861
	if (geteuid() == 0) {
ali@353
   862
		fd = open("/", O_RDONLY, 0);
ali@353
   863
		if (chroot(root) < 0) {
ali@353
   864
			fprintf(stderr, "failed to chroot to %s: %s\n",
ali@353
   865
				root, strerror(errno));
ali@353
   866
			exit(-1);
ali@353
   867
		}
ali@353
   868
	} else
ali@353
   869
#endif
ali@353
   870
		fd = -1;
ali@353
   871
	return fd;
ali@353
   872
}
ali@353
   873
ali@353
   874
static void chroot_pop(int fd)
rhughes@241
   875
{
ali@328
   876
#if HAVE_CHROOT
ali@353
   877
	if (fd >= 0) {
ali@353
   878
		fchdir(fd);
ali@353
   879
		close(fd);
ali@353
   880
		chroot(".");
ali@353
   881
	}
ali@353
   882
#endif
ali@353
   883
}
ali@353
   884
ali@353
   885
static int
ali@376
   886
run_script_lua(const char *root, unsigned int script_tag, const char *script,
ali@376
   887
	       int arg1)
ali@353
   888
{
ali@353
   889
	int root_fd, retval;
ali@352
   890
#if HAVE_LUA
ali@353
   891
	const char *name;
ali@353
   892
ali@353
   893
	switch(script_tag) {
ali@353
   894
		case RPMTAG_PREIN:
ali@353
   895
			name = "%pre";
ali@353
   896
			break;
ali@353
   897
		case RPMTAG_POSTIN:
ali@353
   898
			name = "%post";
ali@353
   899
			break;
ali@353
   900
		case RPMTAG_PREUN:
ali@353
   901
			name = "%preun";
ali@353
   902
			break;
ali@353
   903
		case RPMTAG_POSTUN:
ali@353
   904
			name = "%postun";
ali@353
   905
			break;
ali@353
   906
		default:
ali@353
   907
			name = "script";
ali@353
   908
			break;
ali@353
   909
	}
ali@353
   910
	root_fd = chroot_push(root);
ali@376
   911
	retval = run_lua_script(root_fd < 0 ? root : NULL, name, script, -1,
ali@376
   912
				arg1);
ali@353
   913
	chroot_pop(root_fd);
ali@353
   914
#else	/* HAVE_LUA */
ali@353
   915
	fprintf(stderr, "lua not available to run script\n");
ali@353
   916
	retval = -1;
ali@353
   917
#endif	/* HAVE_LUA */
ali@353
   918
ali@353
   919
	return retval;
ali@353
   920
}
ali@353
   921
ali@353
   922
static int
ali@376
   923
run_script_external(const char *root, const char *program, const char *script,
ali@376
   924
		    int arg1)
ali@353
   925
{
ali@353
   926
	int root_fd, retval;
ali@328
   927
	FILE *fp;
ali@376
   928
	char buf[32], *command;
rhughes@241
   929
ali@353
   930
	if (program == NULL) {
ali@328
   931
#if MSWIN_API
ali@328
   932
		program = getenv("COMSPEC");
ali@328
   933
		if (program) {
ali@328
   934
			program = strchr(program, '=');
ali@328
   935
			if (program)
ali@328
   936
				program++;
ali@328
   937
		}
ali@328
   938
		if (!program)
ali@328
   939
			program = "c:\\windows\\system32\\cmd.exe";
ali@328
   940
#else
rhughes@241
   941
		program = "/bin/sh";
ali@328
   942
#endif
rhughes@241
   943
	}
rhughes@241
   944
ali@353
   945
	root_fd = chroot_push(root);
ali@376
   946
	if (arg1 >= 0) {
ali@376
   947
		sprintf(buf, "%d", arg1);
ali@376
   948
		command = malloc(strlen(program) + strlen(buf) + 2);
ali@376
   949
		sprintf(command, "%s %s", program, buf);
ali@376
   950
	} else
ali@376
   951
		command = strdup(program);
ali@376
   952
	fp = popen(command, "w");
ali@376
   953
	free(command);
rhughes@241
   954
ali@353
   955
	if (!fp) {
ali@353
   956
		perror(program);
ali@353
   957
		retval = -1;
ali@370
   958
	} else if (script && fwrite(script, strlen(script), 1, fp) != 1) {
ali@353
   959
		perror("failed to write script to program");
ali@353
   960
		retval = -1;
ali@353
   961
	} else
ali@353
   962
		retval = 0;
ali@353
   963
ali@353
   964
	if (fp)
ali@353
   965
		pclose(fp);
ali@353
   966
	chroot_pop(root_fd);
ali@353
   967
ali@353
   968
	return retval;
ali@353
   969
}
ali@353
   970
ali@353
   971
static int
ali@353
   972
run_script(struct installer *installer,
ali@376
   973
	   unsigned int program_tag, unsigned int script_tag, int arg1)
ali@353
   974
{
ali@362
   975
	int i, retval;
ali@362
   976
	struct razor_rpm *rpm = installer->rpm;
ali@362
   977
	const char *script = NULL, *program = NULL, *prefix;
ali@376
   978
	char buf[32];
ali@372
   979
	struct environment env;
ali@353
   980
ali@362
   981
	program = razor_rpm_get_indirect(rpm, program_tag, NULL);
ali@362
   982
	script = razor_rpm_get_indirect(rpm, script_tag, NULL);
ali@353
   983
	if (program == NULL && script == NULL)
ali@362
   984
		return 0;
ali@362
   985
ali@362
   986
	if (rpm->relocations) {
ali@372
   987
		environment_init(&env);
ali@362
   988
		for(i = 0; i < rpm->n_prefixes; i++) {
ali@362
   989
			prefix = razor_relocations_apply(rpm->relocations,
ali@362
   990
							 rpm->prefixes[i]);
ali@362
   991
			sprintf(buf, "RPM_INSTALL_PREFIX%d", i);
ali@372
   992
			environment_add_variable(&env, buf, prefix);
ali@362
   993
		}
ali@372
   994
		environment_set(&env);
ali@362
   995
	}
ali@362
   996
ali@369
   997
	if (program && strcmp(program, "<lua>") == 0)
ali@376
   998
		retval = run_script_lua(installer->root, script_tag, script,
ali@376
   999
					arg1);
ali@353
  1000
	else
ali@376
  1001
		retval = run_script_external(installer->root, program, script,
ali@376
  1002
					     arg1);
ali@353
  1003
ali@362
  1004
	if (rpm->relocations) {
ali@372
  1005
		environment_unset(&env);
ali@372
  1006
		environment_release(&env);
ali@362
  1007
	}
ali@362
  1008
ali@353
  1009
	return retval;
rhughes@241
  1010
}
rhughes@241
  1011
ali@369
  1012
int
ali@369
  1013
razor_run_script(const char *root, enum razor_property_flags script,
ali@376
  1014
		 const char *program, const char *body, int arg1)
ali@369
  1015
{
ali@369
  1016
	int retval;
ali@369
  1017
	unsigned int script_tag;
ali@369
  1018
ali@369
  1019
	if (program && !*program)
ali@369
  1020
		program = NULL;
ali@369
  1021
	if (body && !*body)
ali@369
  1022
		body = NULL;
ali@369
  1023
	if (program == NULL && body == NULL)
ali@369
  1024
		return 0;
ali@369
  1025
ali@369
  1026
	if (program && strcmp(program, "<lua>") == 0)
ali@369
  1027
	{
ali@369
  1028
		switch(script) {
ali@369
  1029
		case RAZOR_PROPERTY_PRE:
ali@369
  1030
			script_tag = RPMTAG_PREIN;
ali@369
  1031
			break;
ali@369
  1032
		case RAZOR_PROPERTY_POST:
ali@369
  1033
			script_tag = RPMTAG_POSTIN;
ali@369
  1034
			break;
ali@369
  1035
		case RAZOR_PROPERTY_PREUN:
ali@369
  1036
			script_tag = RPMTAG_PREUN;
ali@369
  1037
			break;
ali@369
  1038
		case RAZOR_PROPERTY_POSTUN:
ali@369
  1039
			script_tag = RPMTAG_POSTUN;
ali@369
  1040
			break;
ali@369
  1041
		default:
ali@369
  1042
			script_tag = 0;
ali@369
  1043
			break;
ali@369
  1044
		}
ali@376
  1045
		retval = run_script_lua(root, script_tag, body, arg1);
ali@369
  1046
	}
ali@369
  1047
	else
ali@376
  1048
		retval = run_script_external(root, program, body, arg1);
ali@369
  1049
ali@369
  1050
	return retval;
ali@369
  1051
}
ali@369
  1052
rhughes@241
  1053
static int
rhughes@241
  1054
installer_init(struct installer *installer)
rhughes@241
  1055
{
rhughes@241
  1056
	unsigned char *gz_header;
rhughes@241
  1057
	int method, flags, err;
ali@403
  1058
	char buffer[32], *s;
rhughes@241
  1059
rhughes@241
  1060
	gz_header = installer->rpm->payload;
rhughes@241
  1061
	if (gz_header[0] != 0x1f || gz_header[1] != 0x8b) {
ali@447
  1062
		razor_atomic_abort(installer->atomic, RAZOR_GENERAL_ERROR,
ali@447
  1063
				   RAZOR_GENERAL_ERROR_RPM_UNSUPPORTED,
ali@403
  1064
				   "Payload section doesn't have gz header");
rhughes@241
  1065
		return -1;
rhughes@241
  1066
	}
rhughes@241
  1067
rhughes@241
  1068
	method = gz_header[2];
rhughes@241
  1069
	flags = gz_header[3];
rhughes@241
  1070
rhughes@241
  1071
	if (method != Z_DEFLATED || flags != 0) {
ali@447
  1072
		razor_atomic_abort(installer->atomic, RAZOR_GENERAL_ERROR,
ali@447
  1073
				   RAZOR_GENERAL_ERROR_RPM_UNSUPPORTED,
ali@403
  1074
				   "Unknown payload compression method or "
ali@403
  1075
				   "flags set");
rhughes@241
  1076
		return -1;
rhughes@241
  1077
	}
rhughes@241
  1078
rhughes@241
  1079
	installer->stream.zalloc = NULL;
rhughes@241
  1080
	installer->stream.zfree = NULL;
rhughes@241
  1081
	installer->stream.opaque = NULL;
rhughes@241
  1082
rhughes@241
  1083
	installer->stream.next_in  = gz_header + 10;
rhughes@241
  1084
	installer->stream.avail_in =
rhughes@241
  1085
		(installer->rpm->map + installer->rpm->size) -
rhughes@241
  1086
		(void *) installer->stream.next_in;
rhughes@241
  1087
	installer->stream.next_out = NULL;
rhughes@241
  1088
	installer->stream.avail_out = 0;
rhughes@241
  1089
rhughes@241
  1090
	err = inflateInit2(&installer->stream, -MAX_WBITS);
rhughes@241
  1091
	if (err != Z_OK) {
ali@403
  1092
		sprintf(buffer, "%d", err);
ali@442
  1093
		s = razor_concat("inflateEnd error: ", buffer, NULL);
ali@447
  1094
		razor_atomic_abort(installer->atomic, RAZOR_ZLIB_ERROR, err, s);
ali@403
  1095
		free(s);
rhughes@241
  1096
		return -1;
rhughes@241
  1097
	}
rhughes@241
  1098
rhughes@241
  1099
	return 0;
rhughes@241
  1100
}
rhughes@241
  1101
rhughes@241
  1102
static int
rhughes@241
  1103
installer_finish(struct installer *installer)
rhughes@241
  1104
{
rhughes@241
  1105
	int err;
ali@403
  1106
	char buffer[32], *s;
rhughes@241
  1107
rhughes@241
  1108
	err = inflateEnd(&installer->stream);
rhughes@241
  1109
rhughes@241
  1110
	if (err != Z_OK) {
ali@403
  1111
		sprintf(buffer, "%d", err);
ali@442
  1112
		s = razor_concat("inflateEnd error: ", buffer, NULL);
ali@447
  1113
		razor_atomic_abort(installer->atomic, RAZOR_ZLIB_ERROR, err, s);
ali@403
  1114
		free(s);
rhughes@241
  1115
	}
rhughes@241
  1116
ali@403
  1117
	return razor_atomic_in_error_state(installer->atomic);
rhughes@241
  1118
}
rhughes@241
  1119
rhughes@241
  1120
static unsigned long
rhughes@241
  1121
fixed_hex_to_ulong(const char *hex, int length)
rhughes@241
  1122
{
rhughes@241
  1123
	long l;
rhughes@241
  1124
	int i;
rhughes@241
  1125
rhughes@241
  1126
	for (i = 0, l = 0; i < length; i++) {
rhughes@241
  1127
		if (hex[i] < 'a')
rhughes@241
  1128
			l = l * 16 + hex[i] - '0';
rhughes@241
  1129
		else
rhughes@241
  1130
			l = l * 16 + hex[i] - 'a' + 10;
rhughes@241
  1131
	}
rhughes@241
  1132
rhughes@241
  1133
	return l;
rhughes@241
  1134
}
rhughes@241
  1135
krh@269
  1136
RAZOR_EXPORT int
ali@403
  1137
razor_rpm_install(struct razor_rpm *rpm, struct razor_atomic *atomic,
ali@403
  1138
		  const char *root, int install_count,
ali@403
  1139
		  enum razor_stage_type stage)
rhughes@241
  1140
{
rhughes@241
  1141
	struct installer installer;
rhughes@241
  1142
	struct cpio_file_header *header;
rhughes@241
  1143
	struct stat buf;
rhughes@241
  1144
	unsigned int mode;
ali@424
  1145
	const char *path;
rhughes@241
  1146
	size_t filesize;
ali@403
  1147
	char *s;
ali@447
  1148
	int retval = 0, code;
rhughes@241
  1149
richard@301
  1150
	assert (rpm != NULL);
richard@301
  1151
	assert (root != NULL);
richard@301
  1152
rhughes@241
  1153
	installer.rpm = rpm;
rhughes@241
  1154
	installer.root = root;
ali@403
  1155
	installer.atomic = atomic;
rhughes@241
  1156
rhughes@241
  1157
	/* FIXME: Only do this before a transaction, not per rpm. */
ali@447
  1158
	if (*root && ((retval = stat(root, &buf)) || !S_ISDIR(buf.st_mode))) {
ali@447
  1159
		code = retval ? errno : ENOTDIR;
ali@403
  1160
		s = razor_concat(root, ": Directory does not exist", NULL);
ali@447
  1161
		razor_atomic_abort(atomic, RAZOR_POSIX_ERROR, code, s);
ali@403
  1162
		free(s);
rhughes@241
  1163
		return -1;
rhughes@241
  1164
	}
rhughes@241
  1165
ali@351
  1166
	if (rpm->relocations)
ali@351
  1167
		razor_relocations_set_rpm(rpm->relocations, rpm);
ali@351
  1168
ali@403
  1169
	if (stage & RAZOR_STAGE_SCRIPTS_PRE)
ali@422
  1170
		retval = run_script(&installer, RPMTAG_PREINPROG, RPMTAG_PREIN,
ali@422
  1171
				    install_count);
rhughes@241
  1172
ali@422
  1173
	if (!retval && (stage & RAZOR_STAGE_FILES)) {
ali@403
  1174
		if (installer_init(&installer))
rhughes@241
  1175
			return -1;
rhughes@241
  1176
ali@403
  1177
		while (installer.stream.avail_in > 0) {
ali@403
  1178
			installer.rest = sizeof *header;
ali@403
  1179
			if (installer_inflate(&installer))
ali@403
  1180
				break;
rhughes@241
  1181
ali@403
  1182
			header = (struct cpio_file_header *) installer.buffer;
ali@403
  1183
			mode = fixed_hex_to_ulong(header->mode,
ali@403
  1184
						  sizeof header->mode);
ali@403
  1185
			filesize = fixed_hex_to_ulong(header->filesize,
ali@403
  1186
						      sizeof header->filesize);
rhughes@241
  1187
ali@403
  1188
			installer.rest =
ali@403
  1189
			  fixed_hex_to_ulong(header->namesize,
ali@403
  1190
					     sizeof header->namesize);
rhughes@241
  1191
ali@403
  1192
			if (installer_inflate(&installer) ||
ali@403
  1193
			    installer_align(&installer, 4))
ali@403
  1194
				break;
rhughes@241
  1195
ali@403
  1196
			path = (const char *) installer.buffer;
ali@403
  1197
			/* This convention is so lame... */
ali@403
  1198
			if (strcmp(path, "TRAILER!!!") == 0)
ali@403
  1199
				break;
ali@403
  1200
ali@403
  1201
			installer.rest = filesize;
ali@403
  1202
			path++;
ali@403
  1203
			if (rpm->relocations)
ali@403
  1204
				path = razor_relocations_apply(rpm->relocations,
ali@403
  1205
							       path);
ali@403
  1206
			if (create_path(&installer, path, mode))
ali@403
  1207
				break;
ali@403
  1208
			if (installer_align(&installer, 4))
ali@403
  1209
				break;
ali@403
  1210
		}
ali@403
  1211
ali@403
  1212
		if (installer_finish(&installer))
rhughes@241
  1213
			return -1;
ali@422
  1214
ali@422
  1215
		retval = razor_atomic_in_error_state(atomic);
rhughes@241
  1216
	}
rhughes@241
  1217
ali@422
  1218
	if (!retval && (stage & RAZOR_STAGE_SCRIPTS_POST))
ali@422
  1219
		retval = run_script(&installer, RPMTAG_POSTINPROG,
ali@422
  1220
				    RPMTAG_POSTIN, install_count);
rhughes@241
  1221
ali@422
  1222
	return retval;
rhughes@241
  1223
}
rhughes@241
  1224
krh@269
  1225
RAZOR_EXPORT int
rhughes@241
  1226
razor_rpm_close(struct razor_rpm *rpm)
rhughes@241
  1227
{
rhughes@241
  1228
	int err;
rhughes@241
  1229
richard@301
  1230
	assert (rpm != NULL);
richard@301
  1231
rhughes@241
  1232
	free(rpm->dirs);
ali@351
  1233
	free(rpm->prefixes);
ali@322
  1234
	err = razor_file_free_contents(rpm->map, rpm->size);
ali@369
  1235
	free(rpm->evr);
rhughes@241
  1236
	free(rpm);
rhughes@241
  1237
rhughes@241
  1238
	return err;
rhughes@241
  1239
}
rhughes@241
  1240
krh@269
  1241
RAZOR_EXPORT int
rhughes@241
  1242
razor_importer_add_rpm(struct razor_importer *importer, struct razor_rpm *rpm)
rhughes@241
  1243
{
ali@369
  1244
	const char *name, *version, *arch;
jbowes@289
  1245
	const char *summary, *description, *url, *license;
rhughes@241
  1246
richard@301
  1247
	assert (importer != NULL);
richard@301
  1248
	assert (rpm != NULL);
richard@301
  1249
ali@369
  1250
	razor_rpm_get_details(rpm,
ali@369
  1251
			      RAZOR_DETAIL_NAME, &name,
ali@369
  1252
			      RAZOR_DETAIL_VERSION, &version,
ali@369
  1253
			      RAZOR_DETAIL_ARCH, &arch,
ali@369
  1254
			      RAZOR_DETAIL_SUMMARY, &summary,
ali@369
  1255
			      RAZOR_DETAIL_DESCRIPTION, &description,
ali@369
  1256
			      RAZOR_DETAIL_URL, &url,
ali@369
  1257
			      RAZOR_DETAIL_LICENSE, &license,
ali@369
  1258
			      RAZOR_DETAIL_LAST);
jbowes@289
  1259
ali@369
  1260
	razor_importer_begin_package(importer, name, version, arch);
rhughes@241
  1261
jbowes@289
  1262
	razor_importer_add_details(importer, summary, description, url,
jbowes@289
  1263
				   license);
jbowes@289
  1264
rhughes@241
  1265
	import_properties(importer, RAZOR_PROPERTY_REQUIRES, rpm,
rhughes@241
  1266
			  RPMTAG_REQUIRENAME,
rhughes@241
  1267
			  RPMTAG_REQUIREVERSION,
rhughes@241
  1268
			  RPMTAG_REQUIREFLAGS);
rhughes@241
  1269
rhughes@241
  1270
	import_properties(importer, RAZOR_PROPERTY_PROVIDES, rpm,
rhughes@241
  1271
			  RPMTAG_PROVIDENAME,
rhughes@241
  1272
			  RPMTAG_PROVIDEVERSION,
rhughes@241
  1273
			  RPMTAG_PROVIDEFLAGS);
rhughes@241
  1274
rhughes@241
  1275
	import_properties(importer, RAZOR_PROPERTY_OBSOLETES, rpm,
rhughes@241
  1276
			  RPMTAG_OBSOLETENAME,
rhughes@241
  1277
			  RPMTAG_OBSOLETEVERSION,
rhughes@241
  1278
			  RPMTAG_OBSOLETEFLAGS);
rhughes@241
  1279
rhughes@241
  1280
	import_properties(importer, RAZOR_PROPERTY_CONFLICTS, rpm,
rhughes@241
  1281
			  RPMTAG_CONFLICTNAME,
rhughes@241
  1282
			  RPMTAG_CONFLICTVERSION,
rhughes@241
  1283
			  RPMTAG_CONFLICTFLAGS);
rhughes@241
  1284
rhughes@241
  1285
	import_files(importer, rpm);
rhughes@241
  1286
rhughes@241
  1287
	razor_importer_finish_package(importer);
rhughes@241
  1288
rhughes@241
  1289
	return 0;
rhughes@241
  1290
}