librazor/root.c
author J. Ali Harlow <ali@juiblex.co.uk>
Mon Mar 05 20:35:27 2018 +0000 (2018-03-05)
changeset 494 889dc38157ac
parent 447 0a5e583393e1
child 499 c89e5edb8eae
permissions -rw-r--r--
Fix bug causing invalid URI to be passed to razor_atomic_remove
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@475
     4
 * Copyright (C) 2009, 2011, 2012, 2014, 2016  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 <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
ali@445
    44
#ifndef FALSE
ali@445
    45
#define FALSE 0
ali@445
    46
#endif
ali@445
    47
ali@445
    48
#ifndef TRUE
ali@445
    49
#define TRUE (!FALSE)
ali@445
    50
#endif
ali@445
    51
richard@310
    52
static const char system_repo_filename[] = "system.rzdb";
ali@388
    53
/*
ali@388
    54
 * system_lock_filename is chosen to be the same as the pre v0.3
ali@388
    55
 * next_repo_filename. This means that once a system has been
ali@388
    56
 * updated by a v0.3+ copy of razor all pre v0.3 versions of razor
ali@388
    57
 * will see the system as permenantly locked.
ali@388
    58
 */
ali@388
    59
static const char system_lock_filename[] = "system-next.rzdb";
ali@340
    60
#ifdef MSWIN_API
ali@475
    61
#define RAZOR_DATABASE_URI	NULL
ali@340
    62
#else
ali@475
    63
/*
ali@475
    64
 * The non-MSWIN default is a relative-ref and thus affected by the root
ali@475
    65
 */
ali@475
    66
#define RAZOR_DATABASE_URI	"var/lib/razor"
ali@340
    67
#endif
ali@475
    68
static char *razor_database_uri = RAZOR_DATABASE_URI;
ali@475
    69
static int razor_database_uri_alloced = FALSE;
krh@248
    70
krh@248
    71
struct razor_root {
krh@248
    72
	struct razor_set *system;
ali@475
    73
	char *uri;
krh@248
    74
};
krh@248
    75
ali@340
    76
static void
ali@340
    77
razor_root_init(void)
ali@340
    78
{
ali@340
    79
#ifdef MSWIN_API
ali@475
    80
	/*
ali@475
    81
	 * The MSWIN default is an absolute-URI and thus unaffected by the root
ali@475
    82
	 */
ali@475
    83
	char database_path[MAX_PATH];
ali@475
    84
	if (!razor_database_uri) {
ali@340
    85
		SHGetFolderPath(NULL,
ali@340
    86
			CSIDL_COMMON_APPDATA | CSIDL_FLAG_DONT_VERIFY, NULL, 0,
ali@445
    87
			database_path);
ali@445
    88
		strcat(database_path, "\\Razor");
ali@475
    89
		razor_database_uri = razor_path_to_uri(database_path);
ali@475
    90
		razor_database_uri_alloced = TRUE;
ali@340
    91
	}
ali@340
    92
#endif
ali@340
    93
}
ali@340
    94
ali@475
    95
RAZOR_EXPORT const char *razor_get_database_uri(void)
ali@445
    96
{
ali@445
    97
	razor_root_init();
ali@475
    98
	return razor_database_uri;
ali@445
    99
}
ali@445
   100
ali@445
   101
RAZOR_EXPORT void
ali@475
   102
razor_set_database_uri(const char *database_uri)
ali@445
   103
{
ali@475
   104
	if (razor_database_uri_alloced)
ali@475
   105
		free(razor_database_uri);
ali@445
   106
ali@475
   107
	if (database_uri) {
ali@475
   108
		razor_database_uri = strdup(database_uri);
ali@475
   109
		razor_database_uri_alloced = TRUE;
ali@445
   110
	} else {
ali@475
   111
		razor_database_uri = RAZOR_DATABASE_URI;
ali@475
   112
		razor_database_uri_alloced = FALSE;
ali@445
   113
	}
ali@445
   114
}
ali@445
   115
ali@475
   116
char *razor_resolve_database_file(const char *root_uri, const char *filename,
ali@475
   117
				  struct razor_error **error)
ali@475
   118
{
ali@475
   119
	char *s, *uri;
ali@475
   120
ali@475
   121
	razor_root_init();
ali@475
   122
ali@475
   123
	s = razor_concat(razor_database_uri, "/", filename, NULL);
ali@475
   124
ali@475
   125
	uri = razor_resolve_uri_root(root_uri, s, -1, error);
ali@475
   126
ali@475
   127
	free(s);
ali@475
   128
ali@475
   129
	return uri;
ali@475
   130
}
ali@475
   131
krh@269
   132
RAZOR_EXPORT int
ali@475
   133
razor_root_create(const char *root_uri, struct razor_error **error)
krh@248
   134
{
ali@475
   135
	int retval, is_within_root, is_directory;
krh@248
   136
	struct razor_set *set;
ali@403
   137
	struct razor_atomic *atomic;
ali@475
   138
	struct razor_error *tmp_err = NULL;
ali@475
   139
	char *uri;
krh@248
   140
ali@475
   141
	uri = razor_resolve_database_file(root_uri, system_repo_filename,
ali@475
   142
					  error);
richard@301
   143
ali@475
   144
	if (!uri)
ali@475
   145
		return -1;
ali@475
   146
ali@475
   147
	if (razor_uri_is_directory(uri, NULL) >= 0) {
ali@475
   148
		razor_set_error(error, RAZOR_GENERAL_ERROR,
ali@475
   149
				RAZOR_GENERAL_ERROR_DATABASE_EXISTS, NULL,
ali@475
   150
				"A razor install root is already initialized");
ali@475
   151
		free(uri);
ali@475
   152
		return -1;
ali@475
   153
	}
ali@475
   154
ali@475
   155
	is_within_root = root_uri && strchr(root_uri, '/') &&
ali@475
   156
			 str_has_prefix(uri, root_uri);
ali@475
   157
ali@475
   158
	atomic = razor_atomic_open("Create initial package set");
ali@475
   159
ali@475
   160
	if (is_within_root) {
ali@475
   161
		is_directory = razor_uri_is_directory(root_uri, NULL);
ali@475
   162
ali@475
   163
		if (!is_directory) {
ali@475
   164
			razor_set_error(error, RAZOR_POSIX_ERROR, ENOTDIR,
ali@475
   165
					root_uri, "Not a directory");
ali@475
   166
			return -1;
ali@475
   167
		} else if (is_directory < 0 &&
ali@475
   168
			   razor_uri_mkdir(root_uri, 0777, &tmp_err) < 0) {
ali@475
   169
			razor_set_error(error,
ali@475
   170
					razor_error_get_domain(tmp_err),
ali@475
   171
					razor_error_get_code(tmp_err),
ali@475
   172
					root_uri,
ali@425
   173
					"Could not create install root");
krh@248
   174
			return -1;
krh@248
   175
		}
krh@248
   176
ali@475
   177
		razor_atomic_make_dirs(atomic, root_uri,
ali@475
   178
				       uri + strlen(root_uri));
ali@475
   179
	} else
ali@475
   180
		razor_atomic_make_dirs(atomic, "", uri);
krh@248
   181
krh@248
   182
	set = razor_set_create();
ali@475
   183
	razor_set_write(set, atomic, uri, RAZOR_SECTION_ALL);
ali@475
   184
	free(uri);
ali@403
   185
	retval = razor_atomic_commit(atomic);
ali@403
   186
	if (retval)
ali@439
   187
		razor_propagate_error(error,
ali@439
   188
				      razor_atomic_get_error(atomic),
ali@439
   189
				      "Could not write initial package set");
ali@403
   190
	razor_set_unref(set);
ali@403
   191
	razor_atomic_destroy(atomic);
krh@248
   192
ali@403
   193
	return retval;
krh@248
   194
}
krh@248
   195
krh@269
   196
RAZOR_EXPORT struct razor_root *
ali@475
   197
razor_root_open(const char *root_uri, struct razor_error **error)
krh@248
   198
{
krh@248
   199
	struct razor_root *image;
ali@475
   200
	char *lock_uri;
ali@403
   201
	int r;
krh@248
   202
ali@475
   203
	lock_uri = razor_resolve_database_file(root_uri, system_lock_filename,
ali@475
   204
					       error);
richard@301
   205
ali@475
   206
	if (!lock_uri)
ali@475
   207
		return NULL;
ali@475
   208
krh@248
   209
	image = malloc(sizeof *image);
ali@403
   210
	if (image == NULL) {
ali@475
   211
		free(lock_uri);
ali@447
   212
		razor_set_error(error, RAZOR_POSIX_ERROR, ENOMEM, NULL,
ali@447
   213
				"Not enough memory");
krh@248
   214
		return NULL;
ali@403
   215
	}
ali@403
   216
ali@388
   217
	image->system = razor_set_create_without_root();
ali@388
   218
	if (image->system == NULL) {
ali@388
   219
		free(image);
ali@475
   220
		free(lock_uri);
ali@447
   221
		razor_set_error(error, RAZOR_POSIX_ERROR, ENOMEM, NULL,
ali@447
   222
				"Not enough memory");
ali@388
   223
		return NULL;
ali@388
   224
	}
ali@388
   225
ali@475
   226
	r = razor_set_acquire_lock(image->system, lock_uri, 1);
ali@388
   227
ali@475
   228
	free(lock_uri);
ali@403
   229
ali@403
   230
	if (r < 0) {
ali@447
   231
		razor_set_error(error, RAZOR_GENERAL_ERROR,
ali@447
   232
				RAZOR_GENERAL_ERROR_DATABASE_LOCKED, NULL,
ali@475
   233
				"Failed to acquire exclusive system lock");
ali@403
   234
		razor_set_unref(image->system);
krh@248
   235
		free(image);
krh@248
   236
		return NULL;
krh@248
   237
	}
krh@248
   238
ali@475
   239
	image->uri = razor_resolve_database_file(root_uri, system_repo_filename,
ali@475
   240
						 error);
krh@317
   241
ali@475
   242
	if (!image->uri) {
ali@475
   243
		razor_set_unref(image->system);
ali@475
   244
		free(image);
ali@475
   245
		return NULL;
ali@475
   246
	}
ali@475
   247
ali@475
   248
	if (razor_set_bind_sections(image->system, image->uri,
ali@424
   249
				    RAZOR_SET_PRIVATE, error)) {
ali@475
   250
		free(image->uri);
ali@403
   251
		razor_set_unref(image->system);
krh@248
   252
		free(image);
krh@248
   253
		return NULL;
krh@248
   254
	}
krh@248
   255
krh@248
   256
	return image;
krh@248
   257
}
krh@248
   258
krh@269
   259
RAZOR_EXPORT struct razor_set *
ali@475
   260
razor_root_open_read_only(const char *root_uri, struct razor_error **error)
krh@248
   261
{
ali@475
   262
	int r;
ali@475
   263
	char *uri;
ali@388
   264
	struct razor_set *set;
krh@248
   265
ali@475
   266
	uri = razor_resolve_database_file(root_uri, system_lock_filename,
ali@475
   267
					  error);
richard@301
   268
ali@475
   269
	if (!uri)
ali@475
   270
		return NULL;
ali@475
   271
ali@388
   272
	set = razor_set_create_without_root();
ali@403
   273
	if (set == NULL) {
ali@475
   274
		free(uri);
ali@447
   275
		razor_set_error(error, RAZOR_POSIX_ERROR, ENOMEM, NULL,
ali@447
   276
				"Not enough memory");
ali@388
   277
		return NULL;
ali@388
   278
	}
ali@388
   279
ali@475
   280
	r = razor_set_acquire_lock(set, uri, 0);
ali@441
   281
ali@475
   282
	free(uri);
ali@475
   283
ali@475
   284
	if (r < 0) {
ali@447
   285
		razor_set_error(error, RAZOR_GENERAL_ERROR,
ali@447
   286
				RAZOR_GENERAL_ERROR_DATABASE_LOCKED, NULL,
ali@475
   287
				"Failed to acquire non-exclusive system lock");
ali@403
   288
		razor_set_unref(set);
ali@388
   289
		return NULL;
ali@388
   290
	}
ali@388
   291
ali@475
   292
	uri = razor_resolve_database_file(root_uri, system_repo_filename,
ali@475
   293
					  error);
ali@441
   294
ali@475
   295
	if (!uri || razor_set_bind_sections(set, uri, 0, error)) {
ali@403
   296
		razor_set_unref(set);
ali@403
   297
		set = NULL;
ali@403
   298
	}
ali@403
   299
ali@475
   300
	free(uri);
ali@403
   301
ali@388
   302
	return set;
krh@248
   303
}
krh@248
   304
krh@269
   305
RAZOR_EXPORT struct razor_set *
krh@250
   306
razor_root_get_system_set(struct razor_root *root)
krh@248
   307
{
richard@301
   308
	assert (root != NULL);
richard@301
   309
krh@250
   310
	return root->system;
krh@248
   311
}
krh@248
   312
krh@269
   313
RAZOR_EXPORT int
krh@250
   314
razor_root_close(struct razor_root *root)
krh@248
   315
{
richard@301
   316
	assert (root != NULL);
richard@301
   317
ali@403
   318
	razor_set_unref(root->system);
ali@475
   319
	free(root->uri);
krh@250
   320
	free(root);
krh@248
   321
krh@248
   322
	return 0;
krh@248
   323
}
krh@248
   324
ali@424
   325
RAZOR_EXPORT int
ali@424
   326
razor_root_update(struct razor_root *root, struct razor_set *next,
ali@424
   327
		  struct razor_atomic *atomic)
krh@248
   328
{
ali@424
   329
	int handle, retval;
ali@424
   330
richard@301
   331
	assert (root != NULL);
richard@301
   332
	assert (next != NULL);
richard@301
   333
ali@475
   334
	handle = razor_atomic_create_file(atomic, root->uri,
ali@424
   335
					  S_IRWXU | S_IRWXG | S_IRWXO);
ali@424
   336
	if (handle < 0)
ali@424
   337
		return handle;
krh@248
   338
ali@424
   339
	razor_set_write_to_handle(next, atomic, handle, RAZOR_SECTION_ALL);
krh@248
   340
ali@424
   341
	retval = razor_atomic_close(atomic, handle);
richard@301
   342
ali@424
   343
	if (!retval) {
ali@424
   344
		razor_set_unref(root->system);
ali@424
   345
		root->system = razor_set_ref(next);
ali@424
   346
	}
krh@248
   347
ali@346
   348
	return retval;
krh@248
   349
}