~ubuntu-branches/ubuntu/intrepid/devmapper/intrepid

« back to all changes in this revision

Viewing changes to lib/fs/libdevmapper.c

  • Committer: Bazaar Package Importer
  • Author(s): Martin Pitt
  • Date: 2008-06-02 17:22:40 UTC
  • mfrom: (1.1.6 upstream)
  • Revision ID: james.westby@ubuntu.com-20080602172240-tb5pinmq9zxghxyb
Tags: 2:1.02.25-1ubuntu1
* Merge from Debian unstable. Remaining Ubuntu changes:
  - Call dmsetup from udev rules to name the device, so udev creates them
    if they do not already exist, and fill in information about the
    filesystem on the device afterwards.
    (forwarded to Debian #455746):
    + Add debian/dmsetup.udev: Naming udev rules.
    + debian/rules: Call dh_installudev to install above file.
    + debian/control: Add Recommends: dmsetup to the library and the udeb.
  - Support udev-controlled devmapper in initramfs, for consistent device
    discovery/naming during boot and hotplug:
    + Add debian/dmsetup.initramfs: Hook for copying dmsetup and udev rules
      to the initramfs.
    + debian/rules: Copy hook to build directory.
    + debian/dmsetup.install: Install above file from build directory.
    + debian/dmsetup.postinst: Call update-initramfs.
  - debian/rules: Copy po/device-mapper.po to device-mapper.pot so Rosetta
    has a POT file to import.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
3
 
 * Copyright (C) 2004 Red Hat, Inc. All rights reserved.
4
 
 *
5
 
 * This file is part of the device-mapper userspace tools.
6
 
 *
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.
10
 
 *
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
14
 
 */
15
 
 
16
 
#include "libdevmapper.h"
17
 
 
18
 
#include <stdio.h>
19
 
#include <stdlib.h>
20
 
#include <stdarg.h>
21
 
#include <string.h>
22
 
#include <unistd.h>
23
 
#include <fcntl.h>
24
 
#include <sys/param.h>
25
 
#include <sys/stat.h>
26
 
#include <sys/types.h>
27
 
#include <errno.h>
28
 
#include <linux/kdev_t.h>
29
 
#include <linux/device-mapper.h>
30
 
 
31
 
#include "libdm-targets.h"
32
 
#include "libdm-common.h"
33
 
 
34
 
typedef enum {
35
 
        DIR_CREATE,
36
 
        DIR_REMOVE
37
 
} do_newold_t;
38
 
 
39
 
/*
40
 
 * Join n path components together with /'s.
41
 
 */
42
 
static char *mkpath(int n, ...)
43
 
{
44
 
        va_list va;
45
 
        int len = 0, i;
46
 
        char *str, *r;
47
 
 
48
 
        va_start(va, n);
49
 
        for (i = 0; i < n; i++)
50
 
                len += strlen(va_arg(va, char *)) + 1;
51
 
 
52
 
        va_end(va);
53
 
 
54
 
        if (!(r = str = malloc(len))) {
55
 
                log_error("mkpath: malloc(%d) failed", len);
56
 
                return NULL;
57
 
        }
58
 
 
59
 
        va_start(va, n);
60
 
        for (i = 0; i < n; i++)
61
 
                str += sprintf(str, "%s%s", i ? "/" : "", va_arg(va, char *));
62
 
        va_end(va);
63
 
 
64
 
        return r;
65
 
}
66
 
 
67
 
void dm_task_destroy(struct dm_task *dmt)
68
 
{
69
 
        struct target *t, *n;
70
 
 
71
 
        for (t = dmt->head; t; t = n) {
72
 
                n = t->next;
73
 
                free(t);
74
 
        }
75
 
 
76
 
        if (dmt->dev_name)
77
 
                free(dmt->dev_name);
78
 
 
79
 
        free(dmt);
80
 
}
81
 
 
82
 
int dm_task_get_info(struct dm_task *dmt, struct dm_info *info)
83
 
{
84
 
        memcpy(info, &dmt->info, sizeof(struct dm_info));
85
 
        return 1;
86
 
}
87
 
 
88
 
int dm_task_set_ro(struct dm_task *dmt)
89
 
{
90
 
        log_error("Read-only attribute ignored by filesystem interface");
91
 
        return 1;
92
 
}
93
 
 
94
 
int dm_task_set_newname(struct dm_task *dmt, const char *newname)
95
 
{
96
 
        log_error("Renaming is not yet supported by the filesystem interface");
97
 
        return 0;
98
 
}
99
 
 
100
 
int dm_task_get_driver_version(struct dm_task *dmt, char *version, size_t size)
101
 
{
102
 
        log_error("The filesystem interface cannot return its version yet");
103
 
        return 0;
104
 
}
105
 
 
106
 
struct target *create_target(uint64_t start,
107
 
                             uint64_t len, const char *type, const char *params)
108
 
{
109
 
        struct target *t;
110
 
        int size = strlen(params) + strlen(type);
111
 
        int ret;
112
 
 
113
 
        size += 64;             /* Guess at max size of start and len */
114
 
 
115
 
        t = malloc(size + sizeof(struct target));
116
 
        if (!t) {
117
 
                log_error("create_target: malloc(%d) failed",
118
 
                    size + sizeof(struct target));
119
 
                return NULL;
120
 
        }
121
 
 
122
 
        memset(t, 0, size + sizeof(struct target));
123
 
        t->str = (char *) (t + 1);
124
 
 
125
 
        ret = sprintf(t->str, "%" PRIu64 " %" PRIu64 " %s %s\n", start, len,
126
 
                      type, params);
127
 
        if (ret > size) {
128
 
                /* This should be impossible, but check anyway */
129
 
                log_error("create_target internal error: Ran out of buffer space");
130
 
                free(t);
131
 
                return NULL;
132
 
        }
133
 
 
134
 
        return t;
135
 
}
136
 
 
137
 
static int do_suspend(char *mnt, char *name, int on)
138
 
{
139
 
        char *path;
140
 
        FILE *fp;
141
 
        int ret = 0;
142
 
        char c;
143
 
 
144
 
        if (!(path = mkpath(3, mnt, name, "suspend")))
145
 
                return 0;
146
 
 
147
 
        if ((fp = fopen(path, "w"))) {
148
 
                c = on ? '1' : '0';
149
 
                if (fputc(c, fp) == (int)c)
150
 
                        ret = 1;
151
 
                else
152
 
                        log_error("%s: fputc failed: %s", path, strerror(errno));
153
 
                fclose(fp);
154
 
        } else
155
 
                log_error("%s: fopen failed: %s", path, strerror(errno));
156
 
 
157
 
        free(path);
158
 
 
159
 
        return ret;
160
 
}
161
 
 
162
 
static int do_newold(char *mnt, char *name, do_newold_t create)
163
 
{
164
 
        char *path = mkpath(2, mnt, name);
165
 
        int ret;
166
 
 
167
 
        if (!path)
168
 
                return 0;
169
 
 
170
 
        if (create == DIR_CREATE) {
171
 
                if ((ret = mkdir(path, 0750)) < 0) {
172
 
                        struct stat st;
173
 
                        if (errno == EEXIST && !stat(path, &st) &&
174
 
                            S_ISDIR(st.st_mode)) 
175
 
                                ret = 1;
176
 
                        log_error("%s: mkdir failed: %s", path, strerror(errno));
177
 
                }
178
 
        } else if ((ret = rmdir(path)) < 0)
179
 
                log_error("%s: rmdir failed: %s", path, strerror(errno));
180
 
 
181
 
        free(path);
182
 
 
183
 
        return (ret < 0) ? 0 : 1;
184
 
}
185
 
 
186
 
static int do_device(char *mnt, char *name, struct dm_info *info)
187
 
{
188
 
        char *path;
189
 
        struct stat st;
190
 
 
191
 
        if (!(path = mkpath(3, mnt, name, "device")))
192
 
                return 0;
193
 
 
194
 
        if (!stat(path, &st)) {
195
 
                info->major = MAJOR(st.st_rdev);
196
 
                info->minor = MINOR(st.st_rdev);
197
 
                info->exists = 1;
198
 
        } else
199
 
                info->exists = 0;
200
 
 
201
 
        free(path);
202
 
        return 1;
203
 
}
204
 
 
205
 
static int do_suspend_state(char *mnt, char *name, struct dm_info *info)
206
 
{
207
 
        char *path;
208
 
        FILE *fp;
209
 
        int ret = 0;
210
 
 
211
 
        if (!(path = mkpath(3, mnt, name, "suspend")))
212
 
                return 0;
213
 
 
214
 
        if ((fp = fopen(path, "r"))) {
215
 
                if (fscanf(fp, "%d", &info->suspended) == 1)
216
 
                        ret = 1;
217
 
                else
218
 
                        log_error("%s fscanf failed: %s", path, strerror(errno));
219
 
                fclose(fp);
220
 
        } else
221
 
                log_error("%s: fopen failed: %s", path, strerror(errno));
222
 
 
223
 
        free(path);
224
 
 
225
 
        return ret;
226
 
}
227
 
 
228
 
static int do_info(char *mnt, char *name, struct dm_info *info)
229
 
{
230
 
        memset(info, 0, sizeof(struct dm_info));
231
 
 
232
 
        if (!do_device(mnt, name, info))
233
 
                return 0;
234
 
 
235
 
        if (info->exists && !do_suspend_state(mnt, name, info))
236
 
                return 0;
237
 
 
238
 
        /* Unsupported */
239
 
        info->target_count = -1;
240
 
        info->open_count = -1;
241
 
        info->read_only = 0;
242
 
 
243
 
        return 1;
244
 
}
245
 
 
246
 
/*
247
 
 * Writes a buffer out to a file, returns 0 on failure.
248
 
 */
249
 
static int write_buffer(int fd, const void *buf, size_t count)
250
 
{
251
 
        size_t n = 0;
252
 
        int tot = 0;
253
 
 
254
 
        while (tot < count) {
255
 
                do
256
 
                        n = write(fd, buf, count - tot);
257
 
                while ((n < 0) && ((errno == EINTR) || (errno == EAGAIN)));
258
 
 
259
 
                if (n <= 0)
260
 
                        return 0;
261
 
 
262
 
                tot += n;
263
 
                buf += n;
264
 
        }
265
 
 
266
 
        return 1;
267
 
}
268
 
 
269
 
static int write_data(int fd, struct dm_task *dmt)
270
 
{
271
 
        struct target *t;
272
 
 
273
 
        for (t = dmt->head; t; t = t->next)
274
 
                if (!write_buffer(fd, t->str, strlen(t->str)))
275
 
                        return 0;
276
 
 
277
 
        return 1;
278
 
}
279
 
 
280
 
static int do_load(char *mnt, char *name, struct dm_task *dmt)
281
 
{
282
 
        char *path;
283
 
        int fd, ret = 0;
284
 
 
285
 
        if (!(path = mkpath(3, mnt, name, "table")))
286
 
                return 0;
287
 
 
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));
291
 
                close(fd);
292
 
        }
293
 
 
294
 
        free(path);
295
 
 
296
 
        return ret;
297
 
}
298
 
 
299
 
static void strip_nl(char *str)
300
 
{
301
 
        while (*str && *str != '\n' && *str != '\r')
302
 
                str++;
303
 
        *str = 0;
304
 
}
305
 
 
306
 
static int do_error_check(char *mnt, char *name)
307
 
{
308
 
        char *path;
309
 
        FILE *fp;
310
 
        int ret = 1;
311
 
        char buf[1024];
312
 
 
313
 
        if (!(path = mkpath(3, mnt, name, "error")))
314
 
                return 0;
315
 
 
316
 
        if (!(fp = fopen(path, "r"))) {
317
 
                log_error("%s: fopen failed: %s", path, strerror(errno));
318
 
                free(path);
319
 
                return 0;
320
 
        }
321
 
 
322
 
        while (fgets(buf, sizeof(buf), fp)) {
323
 
                strip_nl(buf);
324
 
                log_error(buf);
325
 
                ret = 0;
326
 
        }
327
 
 
328
 
        fclose(fp);
329
 
        free(path);
330
 
        return ret;
331
 
}
332
 
 
333
 
static char *find_mount_point(void)
334
 
{
335
 
        FILE *fp;
336
 
        static char mpoint[4096];
337
 
        char fstype[30];
338
 
 
339
 
        if (!(fp = fopen("/proc/mounts", "r"))) {
340
 
                log_error("/proc/mounts: fopen failed: %s", strerror(errno));
341
 
                return NULL;
342
 
        }
343
 
 
344
 
        while (fscanf(fp, "%*s%4096s%30s%*s%*d%*d", mpoint, fstype) == 2) {
345
 
                if (!strcmp(fstype, "dmfs")) {
346
 
                        fclose(fp);
347
 
                        return mpoint;
348
 
                }
349
 
        }
350
 
        fclose(fp);
351
 
        return NULL;
352
 
}
353
 
 
354
 
int dm_task_run(struct dm_task *dmt)
355
 
{
356
 
        char *mnt = find_mount_point();
357
 
 
358
 
        if (mnt == NULL) {
359
 
                /* FIXME Mount it temporarily if not mounted */
360
 
                log_error("Cannot find mount point for dmfs or dmfs not mounted");
361
 
                return 0;
362
 
        }
363
 
 
364
 
        if (!dmt->dev_name || !*dmt->dev_name) {
365
 
                log_error("dm_task_run: Device name not supplied");
366
 
                return 0;
367
 
        }
368
 
 
369
 
        switch (dmt->type) {
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))
376
 
                        return 0;
377
 
                add_dev_node(dmt->dev_name,
378
 
                             MKDEV(dmt->info.major, dmt->info.minor));
379
 
                break;
380
 
 
381
 
        case DM_DEVICE_RELOAD:
382
 
                if (!do_load(mnt, dmt->dev_name, dmt) ||
383
 
                    !do_error_check(mnt, dmt->dev_name)) return 0;
384
 
                break;
385
 
 
386
 
        case DM_DEVICE_REMOVE:
387
 
                if (!do_newold(mnt, dmt->dev_name, DIR_REMOVE) ||
388
 
                    !do_info(mnt, dmt->dev_name, &dmt->info))
389
 
                        return 0;
390
 
                rm_dev_node(dmt->dev_name);
391
 
                break;
392
 
 
393
 
        case DM_DEVICE_SUSPEND:
394
 
                if (!do_suspend(mnt, dmt->dev_name, 1))
395
 
                        return 0;
396
 
                break;
397
 
 
398
 
        case DM_DEVICE_RESUME:
399
 
                if (!do_suspend(mnt, dmt->dev_name, 0))
400
 
                        return 0;
401
 
                break;
402
 
 
403
 
        case DM_DEVICE_INFO:
404
 
                if (!do_info(mnt, dmt->dev_name, &dmt->info))
405
 
                        return 0;
406
 
                break;
407
 
 
408
 
        default:
409
 
                log_error("Internal error: unknown device-mapper task %d", dmt->type);
410
 
                return 0;
411
 
        }
412
 
 
413
 
        return 1;
414
 
}