librazor/atomic-emulate.c
author J. Ali Harlow <ali@juiblex.co.uk>
Thu Feb 09 20:45:27 2012 +0000 (2012-02-09)
changeset 418 33b825d3128d
child 423 6112bcc5d1cf
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.
ali@416
     1
/*
ali@416
     2
 * Copyright (C) 2012  J. Ali Harlow <ali@juiblex.co.uk>
ali@416
     3
 *
ali@416
     4
 * This program is free software; you can redistribute it and/or modify
ali@416
     5
 * it under the terms of the GNU General Public License as published by
ali@416
     6
 * the Free Software Foundation; either version 2 of the License, or
ali@416
     7
 * (at your option) any later version.
ali@416
     8
 *
ali@416
     9
 * This program is distributed in the hope that it will be useful,
ali@416
    10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
ali@416
    11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
ali@416
    12
 * GNU General Public License for more details.
ali@416
    13
 *
ali@416
    14
 * You should have received a copy of the GNU General Public License along
ali@416
    15
 * with this program; if not, write to the Free Software Foundation, Inc.,
ali@416
    16
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
ali@416
    17
 */
ali@416
    18
ali@416
    19
#include "config.h"
ali@416
    20
ali@416
    21
#if ENABLE_ATOMIC && !HAVE_WINDOWS_KTM
ali@416
    22
ali@416
    23
#include <stdlib.h>
ali@416
    24
#include <string.h>
ali@416
    25
#include <unistd.h>
ali@416
    26
#include <sys/types.h>
ali@416
    27
#include <sys/stat.h>
ali@416
    28
#include <fcntl.h>
ali@416
    29
#include <dirent.h>
ali@416
    30
#include <errno.h>
ali@416
    31
#include "razor-internal.h"
ali@416
    32
ali@416
    33
/*
ali@416
    34
 * Emulated atomic support
ali@416
    35
 *
ali@416
    36
 * This implementation is better than nothing, but is certainly not atomic.
ali@416
    37
 * It does have a couple of advantages over atomic-none:
ali@416
    38
 *	- If a file operation fails while a package is being installed we
ali@416
    39
 *	  have a good chance of being able to rollback the transaction to
ali@416
    40
 *	  a well-known state.
ali@416
    41
 *	- We behave similarly to atomic-ktm in that changes are not visible
ali@416
    42
 *	  on disk to non-atomic operations (eg., scripts) until the atomic
ali@416
    43
 *	  is committed. This makes the testsuite more likely to pick up
ali@416
    44
 *	  problems that would otherwise only be found when using razor on
ali@416
    45
 *	  an MS-Windows system which supports KTM.
ali@416
    46
 */
ali@416
    47
ali@416
    48
#ifndef O_BINARY
ali@416
    49
#define O_BINARY	0
ali@416
    50
#endif
ali@416
    51
ali@416
    52
static void recursive_remove(const char *directory)
ali@416
    53
{
ali@416
    54
	DIR *dp;
ali@416
    55
	struct dirent *dirp;
ali@416
    56
	char *buf;
ali@416
    57
ali@416
    58
	dp = opendir(directory);
ali@416
    59
	while((dirp = readdir(dp))) {
ali@416
    60
		if (strcmp(dirp->d_name, ".") && strcmp(dirp->d_name, "..")) {
ali@416
    61
			buf = malloc(strlen(directory) + strlen(dirp->d_name)
ali@416
    62
				     + 2);
ali@416
    63
			sprintf(buf, "%s/%s", directory, dirp->d_name);
ali@416
    64
			if (remove(buf) < 0)
ali@416
    65
				recursive_remove(buf);
ali@416
    66
			free(buf);
ali@416
    67
		}
ali@416
    68
	}
ali@416
    69
ali@416
    70
	rmdir(directory);
ali@416
    71
}
ali@416
    72
ali@416
    73
RAZOR_EXPORT struct razor_atomic *razor_atomic_open(const char *description)
ali@416
    74
{
ali@416
    75
	struct razor_atomic *atomic;
ali@416
    76
ali@416
    77
	atomic = zalloc(sizeof *atomic);
ali@416
    78
ali@416
    79
	atomic->toplevel = strdup(".atomic-XXXXXX");
ali@416
    80
	if (!mkdtemp(atomic->toplevel)) {
ali@416
    81
		free(atomic->toplevel);
ali@416
    82
		free(atomic);
ali@416
    83
		return NULL;
ali@416
    84
	}
ali@416
    85
ali@416
    86
	atomic->description = strdup(description);
ali@416
    87
ali@416
    88
	return atomic;
ali@416
    89
}
ali@416
    90
ali@416
    91
RAZOR_EXPORT int razor_atomic_commit(struct razor_atomic *atomic)
ali@416
    92
{
ali@416
    93
	struct atomic_action *actions;
ali@416
    94
ali@416
    95
	if (razor_atomic_in_error_state(atomic))
ali@416
    96
		return -1;
ali@416
    97
ali@416
    98
	if (atomic->actions) {
ali@416
    99
		actions = atomic_action_list_reverse(atomic->actions);
ali@416
   100
		atomic->actions = NULL;
ali@416
   101
		actions = atomic_action_do(atomic, actions);
ali@416
   102
		atomic_action_free(actions);
ali@416
   103
	}
ali@416
   104
ali@416
   105
	if (atomic->toplevel) {
ali@416
   106
		recursive_remove(atomic->toplevel);
ali@416
   107
		free(atomic->toplevel);
ali@416
   108
		atomic->toplevel = NULL;
ali@416
   109
	}
ali@416
   110
ali@416
   111
	return !!atomic->error_str;
ali@416
   112
}
ali@416
   113
ali@416
   114
RAZOR_EXPORT void razor_atomic_destroy(struct razor_atomic *atomic)
ali@416
   115
{
ali@416
   116
	if (atomic->toplevel) {
ali@416
   117
		recursive_remove(atomic->toplevel);
ali@416
   118
		free(atomic->toplevel);
ali@416
   119
		atomic->toplevel = NULL;
ali@416
   120
	}
ali@416
   121
ali@416
   122
	free(atomic->error_path);
ali@416
   123
	free(atomic->error_str);
ali@416
   124
	free(atomic->error_msg);
ali@416
   125
	free(atomic);
ali@416
   126
}
ali@416
   127
ali@416
   128
RAZOR_EXPORT int
ali@416
   129
razor_atomic_make_dirs(struct razor_atomic *atomic, const char *root,
ali@416
   130
		       const char *path)
ali@416
   131
{
ali@416
   132
	struct atomic_action *a;
ali@416
   133
ali@416
   134
	if (razor_atomic_in_error_state(atomic))
ali@416
   135
		return -1;
ali@416
   136
ali@416
   137
	a = atomic_action_new(ACTION_MAKE_DIRS);
ali@416
   138
	a->args.path = strdup(path);
ali@416
   139
	a->args.u.make_dirs.root = strdup(root);
ali@416
   140
	atomic->actions = atomic_action_list_prepend(atomic->actions, a);
ali@416
   141
ali@416
   142
	return 0;
ali@416
   143
}
ali@416
   144
ali@416
   145
RAZOR_EXPORT int
ali@416
   146
razor_atomic_remove(struct razor_atomic *atomic, const char *path)
ali@416
   147
{
ali@416
   148
	struct atomic_action *a;
ali@416
   149
ali@416
   150
	if (razor_atomic_in_error_state(atomic))
ali@416
   151
		return -1;
ali@416
   152
ali@416
   153
	a = atomic_action_new(ACTION_REMOVE);
ali@416
   154
	a->args.path = strdup(path);
ali@416
   155
	atomic->actions = atomic_action_list_prepend(atomic->actions, a);
ali@416
   156
ali@416
   157
	return 0;
ali@416
   158
}
ali@416
   159
ali@416
   160
RAZOR_EXPORT int
ali@416
   161
razor_atomic_rename_file(struct razor_atomic *atomic, const char *oldpath,
ali@416
   162
			 const char *newpath)
ali@416
   163
{
ali@416
   164
	struct atomic_action *a;
ali@416
   165
ali@416
   166
	if (razor_atomic_in_error_state(atomic))
ali@416
   167
		return -1;
ali@416
   168
ali@416
   169
	a = atomic_action_new(ACTION_MOVE);
ali@416
   170
	a->args.path = strdup(oldpath);
ali@416
   171
	a->args.u.move.dest = strdup(newpath);
ali@416
   172
	atomic->actions = atomic_action_list_prepend(atomic->actions, a);
ali@416
   173
ali@416
   174
	return 0;
ali@416
   175
}
ali@416
   176
ali@416
   177
RAZOR_EXPORT int
ali@416
   178
razor_atomic_create_dir(struct razor_atomic *atomic, const char *dirname,
ali@416
   179
			mode_t mode)
ali@416
   180
{
ali@416
   181
	struct atomic_action *a;
ali@416
   182
ali@416
   183
	if (razor_atomic_in_error_state(atomic))
ali@416
   184
		return -1;
ali@416
   185
ali@416
   186
	a = atomic_action_new(ACTION_CREATE_DIR);
ali@416
   187
	a->args.path = strdup(dirname);
ali@416
   188
	a->args.u.create_dir.mode = mode;
ali@416
   189
	atomic->actions = atomic_action_list_prepend(atomic->actions, a);
ali@416
   190
ali@416
   191
	return 0;
ali@416
   192
}
ali@416
   193
ali@416
   194
RAZOR_EXPORT int
ali@416
   195
razor_atomic_create_symlink(struct razor_atomic *atomic, const char *target,
ali@416
   196
			    const char *path)
ali@416
   197
{
ali@416
   198
#if HAVE_SYMLINK
ali@416
   199
	struct atomic_action *a;
ali@416
   200
#endif
ali@416
   201
ali@416
   202
	if (razor_atomic_in_error_state(atomic))
ali@416
   203
		return -1;
ali@416
   204
ali@416
   205
#if HAVE_SYMLINK
ali@416
   206
	a = atomic_action_new(ACTION_CREATE_SYMLINK);
ali@416
   207
	a->args.path = strdup(path);
ali@416
   208
	a->args.u.create_symlink.target = strdup(target);
ali@416
   209
	atomic->actions = atomic_action_list_prepend(atomic->actions, a);
ali@416
   210
ali@416
   211
	return 0;
ali@416
   212
#else
ali@416
   213
	razor_atomic_set_error_str(atomic, NULL, "Symbolic links not supported "
ali@416
   214
						 "on this platform");
ali@416
   215
ali@416
   216
	return -1;
ali@416
   217
#endif
ali@416
   218
}
ali@416
   219
ali@416
   220
RAZOR_EXPORT int
ali@416
   221
razor_atomic_create_file(struct razor_atomic *atomic, const char *filename,
ali@416
   222
                         mode_t mode)
ali@416
   223
{
ali@416
   224
	int fd;
ali@416
   225
	struct atomic_action *a;
ali@416
   226
	char *tmpnam;
ali@416
   227
ali@416
   228
	if (razor_atomic_in_error_state(atomic))
ali@416
   229
		return -1;
ali@416
   230
ali@416
   231
	atomic->error_path = strdup(filename);
ali@416
   232
	tmpnam = atomic_action_attic_tmpnam(atomic);
ali@416
   233
	fd = open(tmpnam, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
ali@416
   234
		  mode & (S_IRWXU | S_IRWXG | S_IRWXO));
ali@416
   235
ali@416
   236
	if (fd == -1)
ali@416
   237
		razor_atomic_set_error_str(atomic, NULL, strerror(errno));
ali@416
   238
	else {
ali@416
   239
		a = atomic_action_new(ACTION_MOVE);
ali@416
   240
		a->args.path = tmpnam;
ali@416
   241
		a->args.u.move.dest = strdup(filename);
ali@416
   242
		atomic->actions = atomic_action_list_prepend(atomic->actions,
ali@416
   243
							     a);
ali@416
   244
	}
ali@416
   245
ali@416
   246
	return fd;
ali@416
   247
}
ali@416
   248
ali@416
   249
#endif	/* ENABLE_ATOMIC && !HAVE_WINDOWS_KTM */