librazor/root.c
author J. Ali Harlow <ali@juiblex.co.uk>
Thu Oct 09 17:27:41 2014 +0100 (2014-10-09)
changeset 455 df914f383f5c
parent 445 aada48958b92
child 475 008c75a5e08d
permissions -rw-r--r--
Support downloading from local repository even without libcurl

Using the --url option of the razor executable, it is possible
to specify a yum repository on the local machine (eg., on installation
media) and import from there, eg.,:

C> razor --url file:///d:/ import-yum

This will be handled by libcurl if available but if not, an internal
copy routine will be used.

Note that if Microsoft's KTM implementation of atomic transactions is
used, then the current directory must support atomic transactions
(also improve error messages for this, and other, cases).
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@445
     4
 * Copyright (C) 2009, 2011, 2012, 2014  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>
ali@447
    27
#include <errno.h>
krh@248
    28
#include <sys/stat.h>
krh@248
    29
#include <dirent.h>
krh@248
    30
#include <unistd.h>
krh@248
    31
#include <fcntl.h>
ali@325
    32
#include <limits.h>
richard@301
    33
#include <assert.h>
ali@340
    34
#ifdef MSWIN_API
ali@340
    35
#include <shlobj.h>
ali@340
    36
#endif
richard@301
    37
krh@248
    38
#include "razor.h"
krh@248
    39
#include "razor-internal.h"
krh@248
    40
ali@345
    41
#ifndef O_BINARY
ali@345
    42
#define O_BINARY	0
ali@345
    43
#endif
ali@345
    44
ali@445
    45
#ifndef FALSE
ali@445
    46
#define FALSE 0
ali@445
    47
#endif
ali@445
    48
ali@445
    49
#ifndef TRUE
ali@445
    50
#define TRUE (!FALSE)
ali@445
    51
#endif
ali@445
    52
richard@310
    53
static const char system_repo_filename[] = "system.rzdb";
ali@388
    54
/*
ali@388
    55
 * system_lock_filename is chosen to be the same as the pre v0.3
ali@388
    56
 * next_repo_filename. This means that once a system has been
ali@388
    57
 * updated by a v0.3+ copy of razor all pre v0.3 versions of razor
ali@388
    58
 * will see the system as permenantly locked.
ali@388
    59
 */
ali@388
    60
static const char system_lock_filename[] = "system-next.rzdb";
ali@340
    61
#ifdef MSWIN_API
ali@445
    62
#define RAZOR_DATABASE_PATH	NULL
ali@340
    63
#else
ali@445
    64
#define RAZOR_DATABASE_PATH	"/var/lib/razor"
ali@340
    65
#endif
ali@445
    66
static char *razor_database_path = RAZOR_DATABASE_PATH;
ali@445
    67
static int razor_database_path_alloced = FALSE;
krh@248
    68
krh@248
    69
struct razor_root {
krh@248
    70
	struct razor_set *system;
ali@424
    71
	char *path;
krh@248
    72
};
krh@248
    73
ali@340
    74
static void
ali@340
    75
razor_root_init(void)
ali@340
    76
{
ali@340
    77
#ifdef MSWIN_API
ali@445
    78
	static char database_path[MAX_PATH];
ali@445
    79
	if (!razor_database_path) {
ali@340
    80
		SHGetFolderPath(NULL,
ali@340
    81
			CSIDL_COMMON_APPDATA | CSIDL_FLAG_DONT_VERIFY, NULL, 0,
ali@445
    82
			database_path);
ali@445
    83
		strcat(database_path, "\\Razor");
ali@445
    84
		razor_database_path = database_path;
ali@445
    85
		razor_database_path_alloced = FALSE;
ali@340
    86
	}
ali@340
    87
#endif
ali@340
    88
}
ali@340
    89
ali@445
    90
RAZOR_EXPORT const char *
ali@445
    91
razor_get_database_path()
ali@445
    92
{
ali@445
    93
	razor_root_init();
ali@445
    94
ali@445
    95
	return razor_database_path;
ali@445
    96
}
ali@445
    97
ali@445
    98
RAZOR_EXPORT void
ali@445
    99
razor_set_database_path(const char *database_path)
ali@445
   100
{
ali@445
   101
	if (razor_database_path_alloced)
ali@445
   102
		free(razor_database_path);
ali@445
   103
ali@445
   104
	if (database_path) {
ali@445
   105
		razor_database_path = strdup(database_path);
ali@445
   106
		razor_database_path_alloced = TRUE;
ali@445
   107
	} else {
ali@445
   108
		razor_database_path = RAZOR_DATABASE_PATH;
ali@445
   109
		razor_database_path_alloced = FALSE;
ali@445
   110
	}
ali@445
   111
}
ali@445
   112
krh@269
   113
RAZOR_EXPORT int
ali@425
   114
razor_root_create(const char *root, struct razor_error **error)
krh@248
   115
{
ali@403
   116
	int retval;
krh@248
   117
	struct stat buf;
krh@248
   118
	struct razor_set *set;
ali@403
   119
	struct razor_atomic *atomic;
ali@406
   120
	char *file, *path;
krh@248
   121
richard@301
   122
	assert (root != NULL);
richard@301
   123
ali@340
   124
	razor_root_init();
krh@317
   125
	if (root[0] == '\0') {
krh@317
   126
		/* root is file system root */
krh@317
   127
	} else if (stat(root, &buf) < 0) {
krh@248
   128
		if (mkdir(root, 0777) < 0) {
ali@447
   129
			razor_set_error(error, RAZOR_POSIX_ERROR, errno, root,
ali@425
   130
					"Could not create install root");
krh@248
   131
			return -1;
krh@248
   132
		}
krh@248
   133
	} else if (!S_ISDIR(buf.st_mode)) {
ali@447
   134
		razor_set_error(error, RAZOR_POSIX_ERROR, ENOTDIR, root,
ali@447
   135
				"Not a directory");
krh@248
   136
		return -1;
krh@248
   137
	}
krh@248
   138
ali@445
   139
	file = razor_concat(razor_database_path, "/", system_repo_filename,
ali@445
   140
			    NULL);
ali@441
   141
	path = razor_path_add_root(file, root);
ali@403
   142
	retval = !stat(path, &buf);
ali@403
   143
	if (retval) {
ali@447
   144
		razor_set_error(error, RAZOR_GENERAL_ERROR,
ali@447
   145
				RAZOR_GENERAL_ERROR_DATABASE_EXISTS, NULL,
ali@425
   146
				"A razor install root is already initialized");
ali@406
   147
		free(path);
ali@406
   148
		free(file);
ali@403
   149
		return retval;
krh@248
   150
	}
krh@248
   151
ali@403
   152
	atomic = razor_atomic_open("Create initial package set");
ali@406
   153
	razor_atomic_make_dirs(atomic, root, file);
krh@248
   154
	set = razor_set_create();
ali@403
   155
	razor_set_write(set, atomic, path, RAZOR_SECTION_ALL);
ali@403
   156
	free(path);
ali@406
   157
	free(file);
ali@403
   158
	retval = razor_atomic_commit(atomic);
ali@403
   159
	if (retval)
ali@439
   160
		razor_propagate_error(error,
ali@439
   161
				      razor_atomic_get_error(atomic),
ali@439
   162
				      "Could not write initial package set");
ali@403
   163
	razor_set_unref(set);
ali@403
   164
	razor_atomic_destroy(atomic);
krh@248
   165
ali@403
   166
	return retval;
krh@248
   167
}
krh@248
   168
krh@269
   169
RAZOR_EXPORT struct razor_root *
ali@424
   170
razor_root_open(const char *root, struct razor_error **error)
krh@248
   171
{
krh@248
   172
	struct razor_root *image;
ali@441
   173
	char *s, *lock_path;
ali@403
   174
	int r;
krh@248
   175
richard@301
   176
	assert (root != NULL);
richard@301
   177
ali@340
   178
	razor_root_init();
krh@248
   179
	image = malloc(sizeof *image);
ali@403
   180
	if (image == NULL) {
ali@447
   181
		razor_set_error(error, RAZOR_POSIX_ERROR, ENOMEM, NULL,
ali@447
   182
				"Not enough memory");
krh@248
   183
		return NULL;
ali@403
   184
	}
ali@403
   185
ali@388
   186
	image->system = razor_set_create_without_root();
ali@388
   187
	if (image->system == NULL) {
ali@388
   188
		free(image);
ali@447
   189
		razor_set_error(error, RAZOR_POSIX_ERROR, ENOMEM, NULL,
ali@447
   190
				"Not enough memory");
ali@388
   191
		return NULL;
ali@388
   192
	}
ali@388
   193
ali@445
   194
	s = razor_concat(razor_database_path, "/", system_lock_filename, NULL);
ali@441
   195
	lock_path = razor_path_add_root(s, root);
ali@441
   196
	free(s);
ali@388
   197
ali@403
   198
	r = razor_set_aquire_lock(image->system, lock_path, 1);
ali@403
   199
ali@403
   200
	free(lock_path);
ali@403
   201
ali@403
   202
	if (r < 0) {
ali@447
   203
		razor_set_error(error, RAZOR_GENERAL_ERROR,
ali@447
   204
				RAZOR_GENERAL_ERROR_DATABASE_LOCKED, NULL,
ali@424
   205
				"Failed to aquire exclusive system lock");
ali@403
   206
		razor_set_unref(image->system);
krh@248
   207
		free(image);
krh@248
   208
		return NULL;
krh@248
   209
	}
krh@248
   210
ali@445
   211
	s = razor_concat(razor_database_path, "/", system_repo_filename, NULL);
ali@441
   212
	image->path = razor_path_add_root(s, root);
ali@441
   213
	free(s);
krh@317
   214
ali@424
   215
	if (razor_set_bind_sections(image->system, image->path,
ali@424
   216
				    RAZOR_SET_PRIVATE, error)) {
ali@403
   217
		free(image->path);
ali@403
   218
		razor_set_unref(image->system);
krh@248
   219
		free(image);
krh@248
   220
		return NULL;
krh@248
   221
	}
krh@248
   222
krh@248
   223
	return image;
krh@248
   224
}
krh@248
   225
krh@269
   226
RAZOR_EXPORT struct razor_set *
ali@424
   227
razor_root_open_read_only(const char *root, struct razor_error **error)
krh@248
   228
{
ali@441
   229
	char *s, *path;
ali@388
   230
	struct razor_set *set;
krh@248
   231
richard@301
   232
	assert (root != NULL);
richard@301
   233
ali@340
   234
	razor_root_init();
ali@388
   235
	set = razor_set_create_without_root();
ali@403
   236
	if (set == NULL) {
ali@447
   237
		razor_set_error(error, RAZOR_POSIX_ERROR, ENOMEM, NULL,
ali@447
   238
				"Not enough memory");
ali@388
   239
		return NULL;
ali@388
   240
	}
ali@388
   241
ali@445
   242
	s = razor_concat(razor_database_path, "/", system_lock_filename, NULL);
ali@441
   243
	path = razor_path_add_root(s, root);
ali@441
   244
	free(s);
ali@441
   245
ali@403
   246
	if (razor_set_aquire_lock(set, path, 0) < 0) {
ali@447
   247
		razor_set_error(error, RAZOR_GENERAL_ERROR,
ali@447
   248
				RAZOR_GENERAL_ERROR_DATABASE_LOCKED, NULL,
ali@424
   249
				"Failed to aquire non-exclusive system lock");
ali@403
   250
		free(path);
ali@403
   251
		razor_set_unref(set);
ali@388
   252
		return NULL;
ali@388
   253
	}
ali@388
   254
ali@403
   255
	free(path);
ali@441
   256
ali@445
   257
	s = razor_concat(razor_database_path, "/", system_repo_filename, NULL);
ali@441
   258
	path = razor_path_add_root(s, root);
ali@441
   259
	free(s);
ali@403
   260
ali@424
   261
	if (razor_set_bind_sections(set, path, 0, error)) {
ali@403
   262
		razor_set_unref(set);
ali@403
   263
		set = NULL;
ali@403
   264
	}
ali@403
   265
ali@403
   266
	free(path);
ali@403
   267
ali@388
   268
	return set;
krh@248
   269
}
krh@248
   270
krh@269
   271
RAZOR_EXPORT struct razor_set *
krh@250
   272
razor_root_get_system_set(struct razor_root *root)
krh@248
   273
{
richard@301
   274
	assert (root != NULL);
richard@301
   275
krh@250
   276
	return root->system;
krh@248
   277
}
krh@248
   278
krh@269
   279
RAZOR_EXPORT int
krh@250
   280
razor_root_close(struct razor_root *root)
krh@248
   281
{
richard@301
   282
	assert (root != NULL);
richard@301
   283
ali@403
   284
	razor_set_unref(root->system);
ali@403
   285
	free(root->path);
krh@250
   286
	free(root);
krh@248
   287
krh@248
   288
	return 0;
krh@248
   289
}
krh@248
   290
ali@424
   291
RAZOR_EXPORT int
ali@424
   292
razor_root_update(struct razor_root *root, struct razor_set *next,
ali@424
   293
		  struct razor_atomic *atomic)
krh@248
   294
{
ali@424
   295
	int handle, retval;
ali@424
   296
richard@301
   297
	assert (root != NULL);
richard@301
   298
	assert (next != NULL);
richard@301
   299
ali@424
   300
	handle = razor_atomic_create_file(atomic, root->path,
ali@424
   301
					  S_IRWXU | S_IRWXG | S_IRWXO);
ali@424
   302
	if (handle < 0)
ali@424
   303
		return handle;
krh@248
   304
ali@424
   305
	razor_set_write_to_handle(next, atomic, handle, RAZOR_SECTION_ALL);
krh@248
   306
ali@424
   307
	retval = razor_atomic_close(atomic, handle);
richard@301
   308
ali@424
   309
	if (!retval) {
ali@424
   310
		razor_set_unref(root->system);
ali@424
   311
		root->system = razor_set_ref(next);
ali@424
   312
	}
krh@248
   313
ali@346
   314
	return retval;
krh@248
   315
}