librazor/root.c
author J. Ali Harlow <ali@juiblex.co.uk>
Thu Feb 09 20:45:27 2012 +0000 (2012-02-09)
changeset 418 33b825d3128d
parent 403 e63951c1d0f8
child 424 8cbc438cc298
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.
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@403
     4
 * Copyright (C) 2009, 2011  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";
ali@388
    45
/*
ali@388
    46
 * system_lock_filename is chosen to be the same as the pre v0.3
ali@388
    47
 * next_repo_filename. This means that once a system has been
ali@388
    48
 * updated by a v0.3+ copy of razor all pre v0.3 versions of razor
ali@388
    49
 * will see the system as permenantly locked.
ali@388
    50
 */
ali@388
    51
static const char system_lock_filename[] = "system-next.rzdb";
ali@388
    52
static const char system_tmp_filename[] = "system.tmp";
ali@340
    53
#ifdef MSWIN_API
ali@340
    54
#define RAZOR_ROOT_PATH	NULL
ali@340
    55
#else
ali@340
    56
#define RAZOR_ROOT_PATH	"/var/lib/razor"
ali@340
    57
#endif
ali@340
    58
static const char *razor_root_path = RAZOR_ROOT_PATH;
krh@248
    59
krh@248
    60
struct razor_root {
krh@248
    61
	struct razor_set *system;
krh@248
    62
	struct razor_set *next;
ali@403
    63
	struct razor_atomic *atomic;
ali@403
    64
	int handle;
ali@403
    65
	char *path, *new_path;
krh@248
    66
};
krh@248
    67
ali@340
    68
static void
ali@340
    69
razor_root_init(void)
ali@340
    70
{
ali@340
    71
#ifdef MSWIN_API
ali@340
    72
	static char root_path[MAX_PATH];
ali@340
    73
	if (!razor_root_path) {
ali@340
    74
		SHGetFolderPath(NULL,
ali@340
    75
			CSIDL_COMMON_APPDATA | CSIDL_FLAG_DONT_VERIFY, NULL, 0,
ali@340
    76
			root_path);
ali@340
    77
		strcat(root_path, "\\Razor");
ali@340
    78
		razor_root_path = root_path;
ali@340
    79
	}
ali@340
    80
#endif
ali@340
    81
}
ali@340
    82
krh@269
    83
RAZOR_EXPORT int
krh@248
    84
razor_root_create(const char *root)
krh@248
    85
{
ali@403
    86
	int retval;
krh@248
    87
	struct stat buf;
krh@248
    88
	struct razor_set *set;
ali@403
    89
	struct razor_atomic *atomic;
ali@406
    90
	char *file, *path;
krh@248
    91
richard@301
    92
	assert (root != NULL);
richard@301
    93
ali@340
    94
	razor_root_init();
krh@317
    95
	if (root[0] == '\0') {
krh@317
    96
		/* root is file system root */
krh@317
    97
	} else if (stat(root, &buf) < 0) {
krh@248
    98
		if (mkdir(root, 0777) < 0) {
krh@248
    99
			fprintf(stderr,
krh@248
   100
				"could not create install root \"%s\"\n",
krh@248
   101
				root);
krh@248
   102
			return -1;
krh@248
   103
		}
krh@248
   104
		fprintf(stderr, "created install root \"%s\"\n", root);
krh@248
   105
	} else if (!S_ISDIR(buf.st_mode)) {
krh@248
   106
		fprintf(stderr,
krh@248
   107
			"install root \"%s\" exists, but is not a directory\n",
krh@248
   108
			root);
krh@248
   109
		return -1;
krh@248
   110
	}
krh@248
   111
ali@406
   112
	file = razor_concat(razor_root_path, "/", system_repo_filename, NULL);
ali@406
   113
	path = razor_concat(root, file, NULL);
ali@403
   114
	retval = !stat(path, &buf);
ali@403
   115
	if (retval) {
ali@403
   116
		fprintf(stderr,
ali@403
   117
			"a razor install root is already initialized\n");
ali@406
   118
		free(path);
ali@406
   119
		free(file);
ali@403
   120
		return retval;
krh@248
   121
	}
krh@248
   122
ali@403
   123
	atomic = razor_atomic_open("Create initial package set");
ali@406
   124
	razor_atomic_make_dirs(atomic, root, file);
krh@248
   125
	set = razor_set_create();
ali@403
   126
	razor_set_write(set, atomic, path, RAZOR_SECTION_ALL);
ali@403
   127
	free(path);
ali@406
   128
	free(file);
ali@403
   129
	retval = razor_atomic_commit(atomic);
ali@403
   130
	if (retval)
krh@248
   131
		fprintf(stderr, "could not write initial package set\n");
ali@403
   132
	razor_set_unref(set);
ali@403
   133
	razor_atomic_destroy(atomic);
krh@248
   134
ali@403
   135
	return retval;
krh@248
   136
}
krh@248
   137
krh@269
   138
RAZOR_EXPORT struct razor_root *
ali@403
   139
razor_root_open(const char *root, struct razor_atomic *atomic)
krh@248
   140
{
krh@248
   141
	struct razor_root *image;
ali@403
   142
	char *lock_path;
ali@403
   143
	int r;
krh@248
   144
richard@301
   145
	assert (root != NULL);
richard@301
   146
ali@340
   147
	razor_root_init();
krh@248
   148
	image = malloc(sizeof *image);
ali@403
   149
	if (image == NULL) {
ali@403
   150
		razor_atomic_abort(atomic, "Not enough memory");
krh@248
   151
		return NULL;
ali@403
   152
	}
ali@403
   153
ali@403
   154
	image->atomic = atomic;
krh@248
   155
ali@388
   156
	image->system = razor_set_create_without_root();
ali@388
   157
	if (image->system == NULL) {
ali@388
   158
		free(image);
ali@403
   159
		razor_atomic_abort(atomic, "Not enough memory");
ali@388
   160
		return NULL;
ali@388
   161
	}
ali@388
   162
ali@403
   163
	lock_path = razor_concat(root, razor_root_path, "/",
ali@403
   164
				 system_lock_filename, NULL);
ali@388
   165
ali@403
   166
	r = razor_set_aquire_lock(image->system, lock_path, 1);
ali@403
   167
ali@403
   168
	free(lock_path);
ali@403
   169
ali@403
   170
	if (r < 0) {
ali@403
   171
		razor_atomic_abort(atomic,
ali@403
   172
				   "Failed to aquire exclusive system lock");
ali@403
   173
		razor_set_unref(image->system);
ali@388
   174
		free(image);
ali@388
   175
		return NULL;
ali@388
   176
	}
ali@388
   177
ali@403
   178
	image->new_path = razor_concat(root, razor_root_path, "/",
ali@403
   179
				       system_tmp_filename, NULL);
ali@403
   180
	image->handle = razor_atomic_create_file(atomic, image->new_path,
ali@403
   181
						 S_IRWXU | S_IRWXG | S_IRWXO);
ali@403
   182
	if (image->handle < 0) {
ali@403
   183
		free(image->new_path);
ali@403
   184
		razor_set_unref(image->system);
krh@248
   185
		free(image);
krh@248
   186
		return NULL;
krh@248
   187
	}
krh@248
   188
ali@403
   189
	image->path = razor_concat(root, razor_root_path, "/",
ali@403
   190
				   system_repo_filename, NULL);
krh@317
   191
ali@403
   192
	if (razor_set_bind_sections(image->system, atomic, image->path)) {
krh@248
   193
		unlink(image->new_path);
ali@403
   194
		free(image->new_path);
ali@403
   195
		free(image->path);
ali@403
   196
		razor_set_unref(image->system);
krh@248
   197
		free(image);
krh@248
   198
		return NULL;
krh@248
   199
	}
krh@248
   200
krh@248
   201
	return image;
krh@248
   202
}
krh@248
   203
krh@269
   204
RAZOR_EXPORT struct razor_set *
ali@403
   205
razor_root_open_read_only(const char *root, struct razor_atomic *atomic)
krh@248
   206
{
ali@403
   207
	char *path;
ali@388
   208
	struct razor_set *set;
krh@248
   209
richard@301
   210
	assert (root != NULL);
richard@301
   211
ali@340
   212
	razor_root_init();
ali@388
   213
	set = razor_set_create_without_root();
ali@403
   214
	if (set == NULL) {
ali@403
   215
		razor_atomic_abort(atomic, "Not enough memory");
ali@388
   216
		return NULL;
ali@388
   217
	}
ali@388
   218
ali@403
   219
	path = razor_concat(root, razor_root_path, "/", system_lock_filename,
ali@403
   220
			    NULL);
ali@403
   221
	if (razor_set_aquire_lock(set, path, 0) < 0) {
ali@403
   222
		razor_atomic_abort(atomic, "Failed to aquire non-exclusive "
ali@403
   223
					   "system lock");
ali@403
   224
		free(path);
ali@403
   225
		razor_set_unref(set);
ali@388
   226
		return NULL;
ali@388
   227
	}
ali@388
   228
ali@403
   229
	free(path);
ali@403
   230
	path = razor_concat(root, razor_root_path, "/", system_repo_filename,
ali@403
   231
			    NULL);
ali@403
   232
ali@403
   233
	if (razor_set_bind_sections(set, atomic, path)) {
ali@403
   234
		razor_set_unref(set);
ali@403
   235
		set = NULL;
ali@403
   236
	}
ali@403
   237
ali@403
   238
	free(path);
ali@403
   239
ali@388
   240
	return set;
krh@248
   241
}
krh@248
   242
krh@269
   243
RAZOR_EXPORT struct razor_set *
krh@250
   244
razor_root_get_system_set(struct razor_root *root)
krh@248
   245
{
richard@301
   246
	assert (root != NULL);
richard@301
   247
krh@250
   248
	return root->system;
krh@248
   249
}
krh@248
   250
krh@269
   251
RAZOR_EXPORT int
krh@250
   252
razor_root_close(struct razor_root *root)
krh@248
   253
{
richard@301
   254
	assert (root != NULL);
richard@301
   255
ali@403
   256
	razor_set_unref(root->system);
ali@403
   257
	razor_atomic_close(root->atomic, root->handle);
ali@403
   258
	razor_atomic_remove(root->atomic, root->new_path);
ali@403
   259
	free(root->path);
ali@403
   260
	free(root->new_path);
krh@250
   261
	free(root);
krh@248
   262
krh@248
   263
	return 0;
krh@248
   264
}
krh@248
   265
krh@269
   266
RAZOR_EXPORT void
krh@248
   267
razor_root_update(struct razor_root *root, struct razor_set *next)
krh@248
   268
{
richard@301
   269
	assert (root != NULL);
richard@301
   270
	assert (next != NULL);
richard@301
   271
ali@340
   272
	razor_root_init();
ali@403
   273
	razor_set_write_to_handle(next, root->atomic, root->handle,
ali@403
   274
				  RAZOR_SECTION_ALL);
krh@248
   275
	root->next = next;
krh@248
   276
krh@248
   277
	/* Sync the new repo file so the new package set is on disk
krh@248
   278
	 * before we start upgrading. */
ali@403
   279
	razor_atomic_sync(root->atomic, root->handle);
krh@248
   280
}
krh@248
   281
krh@269
   282
RAZOR_EXPORT int
krh@250
   283
razor_root_commit(struct razor_root *root)
krh@248
   284
{
ali@346
   285
	int retval;
richard@301
   286
	assert (root != NULL);
richard@301
   287
ali@403
   288
	razor_atomic_close(root->atomic, root->handle);
ali@403
   289
	retval = razor_atomic_rename_file(root->atomic, root->new_path,
ali@403
   290
					  root->path);
ali@403
   291
	razor_set_unref(root->system);
ali@403
   292
	free(root->path);
ali@403
   293
	free(root->new_path);
krh@250
   294
	free(root);
krh@248
   295
ali@346
   296
	return retval;
krh@248
   297
}