librazor/root.c
author J. Ali Harlow <ali@juiblex.co.uk>
Wed Apr 29 17:00:01 2009 +0100 (2009-04-29)
changeset 361 2523d03a840e
parent 345 edd9b0fa63ca
child 373 fda83d91e600
permissions -rw-r--r--
Add support for preloading lua modules. This is useful both when
providing lua bindings to applications based on librazor and when
producing static binaries using librazor (where otherwise the lua
POSIX library would need to be included as an additional dynamic
object).
richard@300
     1
/*
richard@300
     2
 * Copyright (C) 2008  Kristian Høgsberg <krh@redhat.com>
richard@300
     3
 * Copyright (C) 2008  Red Hat, Inc
ali@340
     4
 * Copyright (C) 2009  J. Ali Harlow <ali@juiblex.co.uk>
richard@300
     5
 *
richard@300
     6
 * This program is free software; you can redistribute it and/or modify
richard@300
     7
 * it under the terms of the GNU General Public License as published by
richard@300
     8
 * the Free Software Foundation; either version 2 of the License, or
richard@300
     9
 * (at your option) any later version.
richard@300
    10
 *
richard@300
    11
 * This program is distributed in the hope that it will be useful,
richard@300
    12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
richard@300
    13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
richard@300
    14
 * GNU General Public License for more details.
richard@300
    15
 *
richard@300
    16
 * You should have received a copy of the GNU General Public License along
richard@300
    17
 * with this program; if not, write to the Free Software Foundation, Inc.,
richard@300
    18
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
richard@300
    19
 */
richard@300
    20
ali@340
    21
#include "config.h"
ali@340
    22
krh@248
    23
#include <stdlib.h>
krh@248
    24
#include <stdint.h>
krh@248
    25
#include <stdio.h>
krh@317
    26
#include <string.h>
krh@248
    27
#include <sys/stat.h>
krh@248
    28
#include <dirent.h>
krh@248
    29
#include <unistd.h>
krh@248
    30
#include <fcntl.h>
ali@325
    31
#include <limits.h>
richard@301
    32
#include <assert.h>
ali@340
    33
#ifdef MSWIN_API
ali@340
    34
#include <shlobj.h>
ali@340
    35
#endif
richard@301
    36
krh@248
    37
#include "razor.h"
krh@248
    38
#include "razor-internal.h"
krh@248
    39
ali@345
    40
#ifndef O_BINARY
ali@345
    41
#define O_BINARY	0
ali@345
    42
#endif
ali@345
    43
richard@310
    44
static const char system_repo_filename[] = "system.rzdb";
richard@310
    45
static const char system_repo_details_filename[] = "system-details.rzdb";
richard@310
    46
static const char system_repo_files_filename[] = "system-files.rzdb";
jbowes@273
    47
richard@310
    48
static const char next_repo_filename[] = "system-next.rzdb";
ali@340
    49
#ifdef MSWIN_API
ali@340
    50
#define RAZOR_ROOT_PATH	NULL
ali@340
    51
#else
ali@340
    52
#define RAZOR_ROOT_PATH	"/var/lib/razor"
ali@340
    53
#endif
ali@340
    54
static const char *razor_root_path = RAZOR_ROOT_PATH;
krh@248
    55
krh@248
    56
struct razor_root {
krh@248
    57
	struct razor_set *system;
krh@248
    58
	struct razor_set *next;
krh@248
    59
	int fd;
krh@317
    60
	char root[PATH_MAX];
krh@248
    61
	char path[PATH_MAX];
krh@248
    62
	char new_path[PATH_MAX];
krh@248
    63
};
krh@248
    64
ali@340
    65
static void
ali@340
    66
razor_root_init(void)
ali@340
    67
{
ali@340
    68
#ifdef MSWIN_API
ali@340
    69
	static char root_path[MAX_PATH];
ali@340
    70
	if (!razor_root_path) {
ali@340
    71
		SHGetFolderPath(NULL,
ali@340
    72
			CSIDL_COMMON_APPDATA | CSIDL_FLAG_DONT_VERIFY, NULL, 0,
ali@340
    73
			root_path);
ali@340
    74
		strcat(root_path, "\\Razor");
ali@340
    75
		razor_root_path = root_path;
ali@340
    76
	}
ali@340
    77
#endif
ali@340
    78
}
ali@340
    79
krh@269
    80
RAZOR_EXPORT int
krh@248
    81
razor_root_create(const char *root)
krh@248
    82
{
krh@248
    83
	struct stat buf;
krh@248
    84
	struct razor_set *set;
jbowes@273
    85
	char path[PATH_MAX], details_path[PATH_MAX], files_path[PATH_MAX];
krh@248
    86
richard@301
    87
	assert (root != NULL);
richard@301
    88
ali@340
    89
	razor_root_init();
krh@317
    90
	if (root[0] == '\0') {
krh@317
    91
		/* root is file system root */
krh@317
    92
	} else if (stat(root, &buf) < 0) {
krh@248
    93
		if (mkdir(root, 0777) < 0) {
krh@248
    94
			fprintf(stderr,
krh@248
    95
				"could not create install root \"%s\"\n",
krh@248
    96
				root);
krh@248
    97
			return -1;
krh@248
    98
		}
krh@248
    99
		fprintf(stderr, "created install root \"%s\"\n", root);
krh@248
   100
	} else if (!S_ISDIR(buf.st_mode)) {
krh@248
   101
		fprintf(stderr,
krh@248
   102
			"install root \"%s\" exists, but is not a directory\n",
krh@248
   103
			root);
krh@248
   104
		return -1;
krh@248
   105
	}
krh@248
   106
krh@248
   107
	snprintf(path, sizeof path, "%s/%s",
krh@248
   108
		 razor_root_path, system_repo_filename);
krh@248
   109
	if (razor_create_dir(root, path) < 0) {
krh@248
   110
		fprintf(stderr, "could not create %s%s\n",
krh@248
   111
			root, razor_root_path);
krh@248
   112
		return -1;
krh@248
   113
	}
krh@248
   114
krh@248
   115
	set = razor_set_create();
krh@248
   116
	snprintf(path, sizeof path, "%s%s/%s",
krh@248
   117
		 root, razor_root_path, system_repo_filename);
jbowes@273
   118
	snprintf(details_path, sizeof details_path, "%s%s/%s",
jbowes@273
   119
		 root, razor_root_path, system_repo_details_filename);
jbowes@273
   120
	snprintf(files_path, sizeof files_path, "%s%s/%s",
jbowes@273
   121
		 root, razor_root_path, system_repo_files_filename);
krh@248
   122
	if (stat(path, &buf) == 0) {
krh@248
   123
		fprintf(stderr,
krh@248
   124
			"a razor install root is already initialized\n");
krh@248
   125
		return -1;
krh@248
   126
	}
jbowes@273
   127
	if (razor_set_write(set, path, RAZOR_REPO_FILE_MAIN) < 0 ||
jbowes@273
   128
	    razor_set_write(set, details_path, RAZOR_REPO_FILE_DETAILS) < 0 ||
jbowes@273
   129
	    razor_set_write(set, files_path, RAZOR_REPO_FILE_FILES) < 0 ) {
krh@248
   130
		fprintf(stderr, "could not write initial package set\n");
krh@248
   131
		return -1;
krh@248
   132
	}
krh@248
   133
	razor_set_destroy(set);
krh@248
   134
krh@248
   135
	return 0;
krh@248
   136
}
krh@248
   137
krh@269
   138
RAZOR_EXPORT struct razor_root *
krh@250
   139
razor_root_open(const char *root)
krh@248
   140
{
krh@248
   141
	struct razor_root *image;
krh@315
   142
	char details_path[PATH_MAX], files_path[PATH_MAX];
krh@248
   143
richard@301
   144
	assert (root != NULL);
richard@301
   145
ali@340
   146
	razor_root_init();
krh@248
   147
	image = malloc(sizeof *image);
krh@248
   148
	if (image == NULL)
krh@248
   149
		return NULL;
krh@248
   150
krh@248
   151
	/* Create the new next repo file up front to ensure exclusive
krh@248
   152
	 * access. */
krh@248
   153
	snprintf(image->new_path, sizeof image->new_path,
krh@248
   154
		 "%s%s/%s", root, razor_root_path, next_repo_filename);
krh@248
   155
	image->fd = open(image->new_path,
ali@345
   156
			 O_CREAT | O_WRONLY | O_TRUNC | O_EXCL | O_BINARY,
ali@345
   157
			 0666);
krh@248
   158
	if (image->fd < 0) {
krh@248
   159
		fprintf(stderr, "failed to get lock file, "
krh@248
   160
			"maybe previous operation crashed?\n");
krh@248
   161
krh@248
   162
		/* FIXME: Use fcntl advisory locking on the system
krh@248
   163
		 * package set file to figure out whether previous
krh@248
   164
		 * operation crashed or is still in progress. */
krh@248
   165
krh@248
   166
		free(image);
krh@248
   167
		return NULL;
krh@248
   168
	}
krh@248
   169
krh@248
   170
	snprintf(image->path, sizeof image->path,
krh@248
   171
		 "%s%s/%s", root, razor_root_path, system_repo_filename);
krh@315
   172
	snprintf(details_path, sizeof details_path,
krh@315
   173
		 "%s%s/%s", root, razor_root_path, system_repo_details_filename);
krh@315
   174
	snprintf(files_path, sizeof files_path,
krh@315
   175
		 "%s%s/%s", root, razor_root_path, system_repo_files_filename);
krh@315
   176
krh@317
   177
	/* FIXME: We store the root path to make the hack in
krh@317
   178
	 * razor_root_update() work.  Need to get rid of this. */
krh@317
   179
	strcpy(image->root, root);
krh@317
   180
krh@248
   181
	image->system = razor_set_open(image->path);
krh@315
   182
	if (image->system == NULL ||
krh@315
   183
	    razor_set_open_details(image->system, details_path) ||
krh@315
   184
	    razor_set_open_files(image->system, files_path)) {
krh@248
   185
		unlink(image->new_path);
krh@248
   186
		close(image->fd);
krh@248
   187
		free(image);
krh@248
   188
		return NULL;
krh@248
   189
	}
krh@248
   190
krh@248
   191
	return image;
krh@248
   192
}
krh@248
   193
krh@269
   194
RAZOR_EXPORT struct razor_set *
krh@248
   195
razor_root_open_read_only(const char *root)
krh@248
   196
{
krh@317
   197
	char path[PATH_MAX], details_path[PATH_MAX], files_path[PATH_MAX];
krh@317
   198
	struct razor_set *set;
krh@248
   199
richard@301
   200
	assert (root != NULL);
richard@301
   201
ali@340
   202
	razor_root_init();
krh@248
   203
	snprintf(path, sizeof path, "%s%s/%s",
krh@248
   204
		 root, razor_root_path, system_repo_filename);
krh@317
   205
	snprintf(details_path, sizeof details_path,
krh@317
   206
		 "%s%s/%s", root, razor_root_path, system_repo_details_filename);
krh@317
   207
	snprintf(files_path, sizeof files_path,
krh@317
   208
		 "%s%s/%s", root, razor_root_path, system_repo_files_filename);
krh@248
   209
krh@317
   210
krh@317
   211
	set = razor_set_open(path);
krh@317
   212
	if (set == NULL)
krh@317
   213
		return NULL;
krh@317
   214
krh@317
   215
	if (razor_set_open_details(set, details_path) ||
krh@317
   216
	    razor_set_open_files(set, files_path)) {
krh@317
   217
		razor_set_destroy(set);
krh@317
   218
		return NULL;
krh@317
   219
	}
krh@317
   220
krh@317
   221
	return set;
krh@248
   222
}
krh@248
   223
krh@269
   224
RAZOR_EXPORT struct razor_set *
krh@250
   225
razor_root_get_system_set(struct razor_root *root)
krh@248
   226
{
richard@301
   227
	assert (root != NULL);
richard@301
   228
krh@250
   229
	return root->system;
krh@248
   230
}
krh@248
   231
krh@269
   232
RAZOR_EXPORT int
krh@250
   233
razor_root_close(struct razor_root *root)
krh@248
   234
{
richard@301
   235
	assert (root != NULL);
richard@301
   236
krh@250
   237
	razor_set_destroy(root->system);
ali@341
   238
	close(root->fd);
krh@250
   239
	unlink(root->new_path);
krh@250
   240
	free(root);
krh@248
   241
krh@248
   242
	return 0;
krh@248
   243
}
krh@248
   244
krh@269
   245
RAZOR_EXPORT void
krh@248
   246
razor_root_update(struct razor_root *root, struct razor_set *next)
krh@248
   247
{
krh@317
   248
	char path[PATH_MAX];
krh@317
   249
richard@301
   250
	assert (root != NULL);
richard@301
   251
	assert (next != NULL);
richard@301
   252
ali@340
   253
	razor_root_init();
jbowes@258
   254
	razor_set_write_to_fd(next, root->fd, RAZOR_REPO_FILE_MAIN);
krh@248
   255
	root->next = next;
krh@248
   256
krh@317
   257
	/* FIXME: This is a pretty bad hack that just overwrites the
krh@317
   258
	 * system details and files rzdb files before the transaction
krh@317
   259
	 * succeeds.  We need to fix this by merging the separate
krh@317
   260
	 * details and files rzdb files back into the main rzdb
krh@317
   261
	 * file. */
krh@317
   262
	snprintf(path, sizeof path,
krh@317
   263
		 "%s%s/%s", root->root, razor_root_path, system_repo_details_filename);
krh@317
   264
	razor_set_write(next, path, RAZOR_REPO_FILE_DETAILS);
krh@317
   265
	snprintf(path, sizeof path,
krh@317
   266
		 "%s%s/%s", root->root, razor_root_path, system_repo_files_filename);
krh@317
   267
	razor_set_write(next, path, RAZOR_REPO_FILE_FILES);
krh@317
   268
krh@248
   269
	/* Sync the new repo file so the new package set is on disk
krh@248
   270
	 * before we start upgrading. */
krh@248
   271
	fsync(root->fd);
krh@248
   272
	printf("wrote %s\n", root->new_path);
krh@248
   273
}
krh@248
   274
krh@269
   275
RAZOR_EXPORT int
krh@250
   276
razor_root_commit(struct razor_root *root)
krh@248
   277
{
ali@346
   278
	int retval;
richard@301
   279
	assert (root != NULL);
richard@301
   280
krh@248
   281
	/* Make it so. */
ali@346
   282
	close(root->fd);
ali@346
   283
#ifdef MSWIN_API
ali@346
   284
	/* Rename is not atomic under MS-Windows */
ali@346
   285
	remove(root->path);
ali@346
   286
#endif
ali@346
   287
	retval = rename(root->new_path, root->path);
ali@346
   288
	if (retval)
ali@346
   289
		perror(root->path);
ali@346
   290
	else
ali@346
   291
		printf("renamed %s to %s\n", root->new_path, root->path);
krh@250
   292
	razor_set_destroy(root->system);
krh@250
   293
	free(root);
krh@248
   294
ali@346
   295
	return retval;
krh@248
   296
}