2
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
3
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
5
* This file is part of the device-mapper userspace tools.
7
* This copyrighted material is made available to anyone wishing to use,
8
* modify, copy, or redistribute it subject to the terms and conditions
9
* of the GNU Lesser General Public License v.2.1.
11
* You should have received a copy of the GNU Lesser General Public License
12
* along with this program; if not, write to the Free Software Foundation,
13
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16
#include "libdevmapper.h"
24
#include <sys/param.h>
26
#include <sys/types.h>
28
#include <linux/kdev_t.h>
29
#include <linux/device-mapper.h>
31
#include "libdm-targets.h"
32
#include "libdm-common.h"
40
* Join n path components together with /'s.
42
static char *mkpath(int n, ...)
49
for (i = 0; i < n; i++)
50
len += strlen(va_arg(va, char *)) + 1;
54
if (!(r = str = malloc(len))) {
55
log_error("mkpath: malloc(%d) failed", len);
60
for (i = 0; i < n; i++)
61
str += sprintf(str, "%s%s", i ? "/" : "", va_arg(va, char *));
67
void dm_task_destroy(struct dm_task *dmt)
71
for (t = dmt->head; t; t = n) {
82
int dm_task_get_info(struct dm_task *dmt, struct dm_info *info)
84
memcpy(info, &dmt->info, sizeof(struct dm_info));
88
int dm_task_set_ro(struct dm_task *dmt)
90
log_error("Read-only attribute ignored by filesystem interface");
94
int dm_task_set_newname(struct dm_task *dmt, const char *newname)
96
log_error("Renaming is not yet supported by the filesystem interface");
100
int dm_task_get_driver_version(struct dm_task *dmt, char *version, size_t size)
102
log_error("The filesystem interface cannot return its version yet");
106
struct target *create_target(uint64_t start,
107
uint64_t len, const char *type, const char *params)
110
int size = strlen(params) + strlen(type);
113
size += 64; /* Guess at max size of start and len */
115
t = malloc(size + sizeof(struct target));
117
log_error("create_target: malloc(%d) failed",
118
size + sizeof(struct target));
122
memset(t, 0, size + sizeof(struct target));
123
t->str = (char *) (t + 1);
125
ret = sprintf(t->str, "%" PRIu64 " %" PRIu64 " %s %s\n", start, len,
128
/* This should be impossible, but check anyway */
129
log_error("create_target internal error: Ran out of buffer space");
137
static int do_suspend(char *mnt, char *name, int on)
144
if (!(path = mkpath(3, mnt, name, "suspend")))
147
if ((fp = fopen(path, "w"))) {
149
if (fputc(c, fp) == (int)c)
152
log_error("%s: fputc failed: %s", path, strerror(errno));
155
log_error("%s: fopen failed: %s", path, strerror(errno));
162
static int do_newold(char *mnt, char *name, do_newold_t create)
164
char *path = mkpath(2, mnt, name);
170
if (create == DIR_CREATE) {
171
if ((ret = mkdir(path, 0750)) < 0) {
173
if (errno == EEXIST && !stat(path, &st) &&
176
log_error("%s: mkdir failed: %s", path, strerror(errno));
178
} else if ((ret = rmdir(path)) < 0)
179
log_error("%s: rmdir failed: %s", path, strerror(errno));
183
return (ret < 0) ? 0 : 1;
186
static int do_device(char *mnt, char *name, struct dm_info *info)
191
if (!(path = mkpath(3, mnt, name, "device")))
194
if (!stat(path, &st)) {
195
info->major = MAJOR(st.st_rdev);
196
info->minor = MINOR(st.st_rdev);
205
static int do_suspend_state(char *mnt, char *name, struct dm_info *info)
211
if (!(path = mkpath(3, mnt, name, "suspend")))
214
if ((fp = fopen(path, "r"))) {
215
if (fscanf(fp, "%d", &info->suspended) == 1)
218
log_error("%s fscanf failed: %s", path, strerror(errno));
221
log_error("%s: fopen failed: %s", path, strerror(errno));
228
static int do_info(char *mnt, char *name, struct dm_info *info)
230
memset(info, 0, sizeof(struct dm_info));
232
if (!do_device(mnt, name, info))
235
if (info->exists && !do_suspend_state(mnt, name, info))
239
info->target_count = -1;
240
info->open_count = -1;
247
* Writes a buffer out to a file, returns 0 on failure.
249
static int write_buffer(int fd, const void *buf, size_t count)
254
while (tot < count) {
256
n = write(fd, buf, count - tot);
257
while ((n < 0) && ((errno == EINTR) || (errno == EAGAIN)));
269
static int write_data(int fd, struct dm_task *dmt)
273
for (t = dmt->head; t; t = t->next)
274
if (!write_buffer(fd, t->str, strlen(t->str)))
280
static int do_load(char *mnt, char *name, struct dm_task *dmt)
285
if (!(path = mkpath(3, mnt, name, "table")))
288
if ((fd = open(path, O_RDWR)) != -1) {
289
if (!(ret = write_data(fd, dmt)))
290
log_error("%s: write failed: %s", path, strerror(errno));
299
static void strip_nl(char *str)
301
while (*str && *str != '\n' && *str != '\r')
306
static int do_error_check(char *mnt, char *name)
313
if (!(path = mkpath(3, mnt, name, "error")))
316
if (!(fp = fopen(path, "r"))) {
317
log_error("%s: fopen failed: %s", path, strerror(errno));
322
while (fgets(buf, sizeof(buf), fp)) {
333
static char *find_mount_point(void)
336
static char mpoint[4096];
339
if (!(fp = fopen("/proc/mounts", "r"))) {
340
log_error("/proc/mounts: fopen failed: %s", strerror(errno));
344
while (fscanf(fp, "%*s%4096s%30s%*s%*d%*d", mpoint, fstype) == 2) {
345
if (!strcmp(fstype, "dmfs")) {
354
int dm_task_run(struct dm_task *dmt)
356
char *mnt = find_mount_point();
359
/* FIXME Mount it temporarily if not mounted */
360
log_error("Cannot find mount point for dmfs or dmfs not mounted");
364
if (!dmt->dev_name || !*dmt->dev_name) {
365
log_error("dm_task_run: Device name not supplied");
370
case DM_DEVICE_CREATE:
371
if (!do_newold(mnt, dmt->dev_name, DIR_CREATE) ||
372
!do_load(mnt, dmt->dev_name, dmt) ||
373
!do_error_check(mnt, dmt->dev_name) ||
374
!do_suspend(mnt, dmt->dev_name, 0) ||
375
!do_info(mnt, dmt->dev_name, &dmt->info))
377
add_dev_node(dmt->dev_name,
378
MKDEV(dmt->info.major, dmt->info.minor));
381
case DM_DEVICE_RELOAD:
382
if (!do_load(mnt, dmt->dev_name, dmt) ||
383
!do_error_check(mnt, dmt->dev_name)) return 0;
386
case DM_DEVICE_REMOVE:
387
if (!do_newold(mnt, dmt->dev_name, DIR_REMOVE) ||
388
!do_info(mnt, dmt->dev_name, &dmt->info))
390
rm_dev_node(dmt->dev_name);
393
case DM_DEVICE_SUSPEND:
394
if (!do_suspend(mnt, dmt->dev_name, 1))
398
case DM_DEVICE_RESUME:
399
if (!do_suspend(mnt, dmt->dev_name, 0))
404
if (!do_info(mnt, dmt->dev_name, &dmt->info))
409
log_error("Internal error: unknown device-mapper task %d", dmt->type);