~ubuntu-branches/ubuntu/trusty/util-linux/trusty-proposed

« back to all changes in this revision

Viewing changes to lib/loopdev.c

  • Committer: Package Import Robot
  • Author(s): LaMont Jones
  • Date: 2011-11-03 15:38:23 UTC
  • mto: (4.5.5 sid) (1.6.4)
  • mto: This revision was merged to the branch mainline in revision 85.
  • Revision ID: package-import@ubuntu.com-20111103153823-10sx16jprzxlhkqf
ImportĀ upstreamĀ versionĀ 2.20.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C) 2011 Karel Zak <kzak@redhat.com>
 
3
 *
 
4
 * -- based on mount/losetup.c
 
5
 *
 
6
 * Simple library for work with loop devices.
 
7
 *
 
8
 *  - requires kernel 2.6.x
 
9
 *  - reads info from /sys/block/loop<N>/loop/<attr> (new kernels)
 
10
 *  - reads info by ioctl
 
11
 *  - supports *unlimited* number of loop devices
 
12
 *  - supports /dev/loop<N> as well as /dev/loop/<N>
 
13
 *  - minimize overhead (fd, loopinfo, ... are shared for all operations)
 
14
 *  - setup (associate device and backing file)
 
15
 *  - delete (dis-associate file)
 
16
 *  - old LOOP_{SET,GET}_STATUS (32bit) ioctls are unsupported
 
17
 *  - extendible
 
18
 */
 
19
#include <stdio.h>
 
20
#include <stdint.h>
 
21
#include <string.h>
 
22
#include <ctype.h>
 
23
#include <fcntl.h>
 
24
#include <stdlib.h>
 
25
#include <unistd.h>
 
26
#include <sys/ioctl.h>
 
27
#include <sys/stat.h>
 
28
#include <sys/mman.h>
 
29
#include <sys/sysmacros.h>
 
30
#include <inttypes.h>
 
31
#include <dirent.h>
 
32
#include <linux/posix_types.h>
 
33
 
 
34
#include "linux_version.h"
 
35
#include "c.h"
 
36
#include "sysfs.h"
 
37
#include "pathnames.h"
 
38
#include "loopdev.h"
 
39
#include "canonicalize.h"
 
40
 
 
41
#define loopcxt_ioctl_enabled(_lc)      (!((_lc)->flags & LOOPDEV_FL_NOIOCTL))
 
42
 
 
43
/*
 
44
 * @lc: context
 
45
 * @device: device name, absolute device path or NULL to reset the current setting
 
46
 *
 
47
 * Sets device, absolute paths (e.g. "/dev/loop<N>") are unchanged, device
 
48
 * names ("loop<N>") are converted to the path (/dev/loop<N> or to
 
49
 * /dev/loop/<N>)
 
50
 *
 
51
 * Returns: <0 on error, 0 on success
 
52
 */
 
53
int loopcxt_set_device(struct loopdev_cxt *lc, const char *device)
 
54
{
 
55
        if (!lc)
 
56
                return -EINVAL;
 
57
 
 
58
        if (lc->fd >= 0)
 
59
                close(lc->fd);
 
60
        lc->fd = -1;
 
61
        lc->mode = 0;
 
62
        lc->has_info = 0;
 
63
        *lc->device = '\0';
 
64
        memset(&lc->info, 0, sizeof(lc->info));
 
65
 
 
66
        /* set new */
 
67
        if (device) {
 
68
                if (*device != '/') {
 
69
                        const char *dir = _PATH_DEV;
 
70
 
 
71
                        /* compose device name for /dev/loop<n> or /dev/loop/<n> */
 
72
                        if (lc->flags & LOOPDEV_FL_DEVSUBDIR) {
 
73
                                if (strlen(device) < 5)
 
74
                                        return -1;
 
75
                                device += 4;
 
76
                                dir = _PATH_DEV_LOOP "/";       /* _PATH_DEV uses tailing slash */
 
77
                        }
 
78
                        snprintf(lc->device, sizeof(lc->device), "%s%s",
 
79
                                dir, device);
 
80
                } else {
 
81
                        strncpy(lc->device, device, sizeof(lc->device));
 
82
                        lc->device[sizeof(lc->device) - 1] = '\0';
 
83
                }
 
84
        }
 
85
 
 
86
        sysfs_deinit(&lc->sysfs);
 
87
        return 0;
 
88
}
 
89
 
 
90
/*
 
91
 * @lc: context
 
92
 * @flags: LOOPDEV_FL_* flags
 
93
 *
 
94
 * Initilize loop handler.
 
95
 *
 
96
 * We have two sets of the flags:
 
97
 *
 
98
 *      * LOOPDEV_FL_* flags control loopcxt_* API behavior
 
99
 *
 
100
 *      * LO_FLAGS_* are kernel flags used for LOOP_{SET,GET}_STAT64 ioctls
 
101
 *
 
102
 * Note about LOOPDEV_FL_{RDONLY,RDWR} flags. These flags are used for open(2)
 
103
 * syscall to open loop device. By default is the device open read-only.
 
104
 *
 
105
 * The expection is loopcxt_setup_device(), where the device is open read-write
 
106
 * if LO_FLAGS_READ_ONLY flags is not set (see loopcxt_set_flags()).
 
107
 *
 
108
 * Returns: <0 on error, 0 on success.
 
109
 */
 
110
int loopcxt_init(struct loopdev_cxt *lc, int flags)
 
111
{
 
112
        if (!lc)
 
113
                return -EINVAL;
 
114
 
 
115
        memset(lc, 0, sizeof(*lc));
 
116
        lc->flags = flags;
 
117
        loopcxt_set_device(lc, NULL);
 
118
 
 
119
        if (!(lc->flags & LOOPDEV_FL_NOSYSFS) &&
 
120
            get_linux_version() >= KERNEL_VERSION(2,6,37))
 
121
                /*
 
122
                 * Use only sysfs for basic information about loop devices
 
123
                 */
 
124
                lc->flags |= LOOPDEV_FL_NOIOCTL;
 
125
 
 
126
        return 0;
 
127
}
 
128
 
 
129
/*
 
130
 * @lc: context
 
131
 *
 
132
 * Deinitialize loop context
 
133
 */
 
134
void loopcxt_deinit(struct loopdev_cxt *lc)
 
135
{
 
136
        if (!lc)
 
137
                return;
 
138
 
 
139
        free(lc->filename);
 
140
        lc->filename = NULL;
 
141
 
 
142
        loopcxt_set_device(lc, NULL);
 
143
        loopcxt_deinit_iterator(lc);
 
144
}
 
145
 
 
146
/*
 
147
 * @lc: context
 
148
 *
 
149
 * Returns newly allocated device path.
 
150
 */
 
151
char *loopcxt_strdup_device(struct loopdev_cxt *lc)
 
152
{
 
153
        if (!lc || !*lc->device)
 
154
                return NULL;
 
155
        return strdup(lc->device);
 
156
}
 
157
 
 
158
/*
 
159
 * @lc: context
 
160
 *
 
161
 * Returns pointer device name in the @lc struct.
 
162
 */
 
163
const char *loopcxt_get_device(struct loopdev_cxt *lc)
 
164
{
 
165
        return lc ? lc->device : NULL;
 
166
}
 
167
 
 
168
/*
 
169
 * @lc: context
 
170
 *
 
171
 * Returns pointer to the sysfs context (see lib/sysfs.c)
 
172
 */
 
173
struct sysfs_cxt *loopcxt_get_sysfs(struct loopdev_cxt *lc)
 
174
{
 
175
        if (!lc || !*lc->device || (lc->flags & LOOPDEV_FL_NOSYSFS))
 
176
                return NULL;
 
177
 
 
178
        if (!lc->sysfs.devno) {
 
179
                dev_t devno = sysfs_devname_to_devno(lc->device, NULL);
 
180
                if (!devno)
 
181
                        return NULL;
 
182
 
 
183
                if (sysfs_init(&lc->sysfs, devno, NULL))
 
184
                        return NULL;
 
185
        }
 
186
        return &lc->sysfs;
 
187
}
 
188
 
 
189
/*
 
190
 * @lc: context
 
191
 *
 
192
 * Returns: file descriptor to the open loop device or <0 on error. The mode
 
193
 *          depends on LOOPDEV_FL_{RDWR,RDONLY} context flags. Default is
 
194
 *          read-only.
 
195
 */
 
196
int loopcxt_get_fd(struct loopdev_cxt *lc)
 
197
{
 
198
        if (!lc || !*lc->device)
 
199
                return -EINVAL;
 
200
 
 
201
        if (lc->fd < 0) {
 
202
                lc->mode = lc->flags & LOOPDEV_FL_RDWR ? O_RDWR : O_RDONLY;
 
203
                lc->fd = open(lc->device, lc->mode);
 
204
        }
 
205
        return lc->fd;
 
206
}
 
207
 
 
208
int loopcxt_set_fd(struct loopdev_cxt *lc, int fd, int mode)
 
209
{
 
210
        if (!lc)
 
211
                return -EINVAL;
 
212
 
 
213
        lc->fd = fd;
 
214
        lc->mode = mode;
 
215
        return 0;
 
216
}
 
217
 
 
218
/*
 
219
 * @lc: context
 
220
 * @flags: LOOPITER_FL_* flags
 
221
 *
 
222
 * Iterator allows to scan list of the free or used loop devices.
 
223
 *
 
224
 * Returns: <0 on error, 0 on success
 
225
 */
 
226
int loopcxt_init_iterator(struct loopdev_cxt *lc, int flags)
 
227
{
 
228
        struct loopdev_iter *iter;
 
229
        struct stat st;
 
230
 
 
231
        if (!lc)
 
232
                return -EINVAL;
 
233
 
 
234
        iter = &lc->iter;
 
235
 
 
236
        /* always zeroize
 
237
         */
 
238
        memset(iter, 0, sizeof(*iter));
 
239
        iter->ncur = -1;
 
240
        iter->flags = flags;
 
241
        iter->default_check = 1;
 
242
 
 
243
        if (!lc->extra_check) {
 
244
                /*
 
245
                 * Check for /dev/loop/<N> subdirectory
 
246
                 */
 
247
                if (!(lc->flags & LOOPDEV_FL_DEVSUBDIR) &&
 
248
                    stat(_PATH_DEV_LOOP, &st) == 0 && S_ISDIR(st.st_mode))
 
249
                        lc->flags |= LOOPDEV_FL_DEVSUBDIR;
 
250
 
 
251
                lc->extra_check = 1;
 
252
        }
 
253
        return 0;
 
254
}
 
255
 
 
256
/*
 
257
 * @lc: context
 
258
 *
 
259
 * Returns: <0 on error, 0 on success
 
260
 */
 
261
int loopcxt_deinit_iterator(struct loopdev_cxt *lc)
 
262
{
 
263
        struct loopdev_iter *iter = &lc->iter;
 
264
 
 
265
        if (!lc)
 
266
                return -EINVAL;
 
267
 
 
268
        iter = &lc->iter;
 
269
 
 
270
        free(iter->minors);
 
271
        if (iter->proc)
 
272
                fclose(iter->proc);
 
273
        iter->minors = NULL;
 
274
        iter->proc = NULL;
 
275
        iter->done = 1;
 
276
        return 0;
 
277
}
 
278
 
 
279
/*
 
280
 * Same as loopcxt_set_device, but also checks if the device is
 
281
 * associeted with any file.
 
282
 *
 
283
 * Returns: <0 on error, 0 on success, 1 device does not match with
 
284
 *         LOOPITER_FL_{USED,FREE} flags.
 
285
 */
 
286
static int loopiter_set_device(struct loopdev_cxt *lc, const char *device)
 
287
{
 
288
        int rc = loopcxt_set_device(lc, device);
 
289
        int used;
 
290
 
 
291
        if (rc)
 
292
                return rc;
 
293
 
 
294
        if (!(lc->iter.flags & LOOPITER_FL_USED) &&
 
295
            !(lc->iter.flags & LOOPITER_FL_FREE))
 
296
                return 0;       /* caller does not care about device status */
 
297
 
 
298
        used = loopcxt_get_offset(lc, NULL) == 0;
 
299
 
 
300
        if ((lc->iter.flags & LOOPITER_FL_USED) && used)
 
301
                return 0;
 
302
 
 
303
        if ((lc->iter.flags & LOOPITER_FL_FREE) && !used)
 
304
                return 0;
 
305
 
 
306
        loopcxt_set_device(lc, NULL);
 
307
        return 1;
 
308
}
 
309
 
 
310
static int cmpnum(const void *p1, const void *p2)
 
311
{
 
312
        return (((* (int *) p1) > (* (int *) p2)) -
 
313
                        ((* (int *) p1) < (* (int *) p2)));
 
314
}
 
315
 
 
316
/*
 
317
 * The classic scandir() is more expensive and less portable.
 
318
 * We needn't full loop device names -- loop numbers (loop<N>)
 
319
 * are enough.
 
320
 */
 
321
static int loop_scandir(const char *dirname, int **ary, int hasprefix)
 
322
{
 
323
        DIR *dir;
 
324
        struct dirent *d;
 
325
        unsigned int n, count = 0, arylen = 0;
 
326
 
 
327
        if (!dirname || !ary)
 
328
                return 0;
 
329
        dir = opendir(dirname);
 
330
        if (!dir)
 
331
                return 0;
 
332
 
 
333
        free(*ary);
 
334
        *ary = NULL;
 
335
 
 
336
        while((d = readdir(dir))) {
 
337
#ifdef _DIRENT_HAVE_D_TYPE
 
338
                if (d->d_type != DT_BLK && d->d_type != DT_UNKNOWN &&
 
339
                    d->d_type != DT_LNK)
 
340
                        continue;
 
341
#endif
 
342
                if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
 
343
                        continue;
 
344
 
 
345
                if (hasprefix) {
 
346
                        /* /dev/loop<N> */
 
347
                        if (sscanf(d->d_name, "loop%u", &n) != 1)
 
348
                                continue;
 
349
                } else {
 
350
                        /* /dev/loop/<N> */
 
351
                        char *end = NULL;
 
352
 
 
353
                        n = strtol(d->d_name, &end, 10);
 
354
                        if (d->d_name == end || (end && *end) || errno)
 
355
                                continue;
 
356
                }
 
357
                if (n < LOOPDEV_DEFAULT_NNODES)
 
358
                        continue;                       /* ignore loop<0..7> */
 
359
 
 
360
                if (count + 1 > arylen) {
 
361
                        int *tmp;
 
362
 
 
363
                        arylen += 1;
 
364
 
 
365
                        tmp = realloc(*ary, arylen * sizeof(int));
 
366
                        if (!tmp) {
 
367
                                free(*ary);
 
368
                                return -1;
 
369
                        }
 
370
                        *ary = tmp;
 
371
                }
 
372
                if (*ary)
 
373
                        (*ary)[count++] = n;
 
374
        }
 
375
        if (count && *ary)
 
376
                qsort(*ary, count, sizeof(int), cmpnum);
 
377
 
 
378
        closedir(dir);
 
379
        return count;
 
380
}
 
381
 
 
382
/*
 
383
 * @lc: context, has to initialized by loopcxt_init_iterator()
 
384
 *
 
385
 * Returns: 0 on success, -1 on error, 1 at the end of scanning. The details
 
386
 *          about the current loop device are available by
 
387
 *          loopcxt_get_{fd,backing_file,device,offset, ...} functions.
 
388
 */
 
389
int loopcxt_next(struct loopdev_cxt *lc)
 
390
{
 
391
        struct loopdev_iter *iter;
 
392
 
 
393
        if (!lc)
 
394
                return -EINVAL;
 
395
        iter = &lc->iter;
 
396
        if (iter->done)
 
397
                return 1;
 
398
 
 
399
        /* A) Look for used loop devices in /proc/partitions ("losetup -a" only)
 
400
         */
 
401
        if (iter->flags & LOOPITER_FL_USED) {
 
402
                char buf[BUFSIZ];
 
403
 
 
404
                if (!iter->proc)
 
405
                        iter->proc = fopen(_PATH_PROC_PARTITIONS, "r");
 
406
 
 
407
                while (iter->proc && fgets(buf, sizeof(buf), iter->proc)) {
 
408
                        unsigned int m;
 
409
                        char name[128];
 
410
 
 
411
                        if (sscanf(buf, " %u %*s %*s %128[^\n ]",
 
412
                                   &m, name) != 2 || m != LOOPDEV_MAJOR)
 
413
                                continue;
 
414
 
 
415
                        if (loopiter_set_device(lc, name) == 0)
 
416
                                return 0;
 
417
                }
 
418
 
 
419
                goto done;
 
420
        }
 
421
 
 
422
        /* B) Classic way, try first eight loop devices (default number
 
423
         *    of loop devices). This is enough for 99% of all cases.
 
424
         */
 
425
        if (iter->default_check) {
 
426
                for (++iter->ncur; iter->ncur < LOOPDEV_DEFAULT_NNODES;
 
427
                                                        iter->ncur++) {
 
428
                        char name[16];
 
429
                        snprintf(name, sizeof(name), "loop%d", iter->ncur);
 
430
 
 
431
                        if (loopiter_set_device(lc, name) == 0)
 
432
                                return 0;
 
433
                }
 
434
                iter->default_check = 0;
 
435
        }
 
436
 
 
437
        /* C) the worst possibility, scan whole /dev or /dev/loop/<N>
 
438
         */
 
439
        if (!iter->minors) {
 
440
                iter->nminors = (lc->flags & LOOPDEV_FL_DEVSUBDIR) ?
 
441
                        loop_scandir(_PATH_DEV_LOOP, &iter->minors, 0) :
 
442
                        loop_scandir(_PATH_DEV, &iter->minors, 1);
 
443
                iter->ncur = -1;
 
444
        }
 
445
        for (++iter->ncur; iter->ncur < iter->nminors; iter->ncur++) {
 
446
                char name[16];
 
447
                snprintf(name, sizeof(name), "loop%d", iter->minors[iter->ncur]);
 
448
 
 
449
                if (loopiter_set_device(lc, name) == 0)
 
450
                        return 0;
 
451
        }
 
452
done:
 
453
        loopcxt_deinit_iterator(lc);
 
454
        return 1;
 
455
}
 
456
 
 
457
/*
 
458
 * @device: path to device
 
459
 */
 
460
int is_loopdev(const char *device)
 
461
{
 
462
        struct stat st;
 
463
 
 
464
        if (!device)
 
465
                return 0;
 
466
 
 
467
        return (stat(device, &st) == 0 &&
 
468
                S_ISBLK(st.st_mode) &&
 
469
                major(st.st_rdev) == LOOPDEV_MAJOR);
 
470
}
 
471
 
 
472
/*
 
473
 * @lc: context
 
474
 *
 
475
 * Returns result from LOOP_GET_STAT64 ioctl or NULL on error.
 
476
 */
 
477
struct loop_info64 *loopcxt_get_info(struct loopdev_cxt *lc)
 
478
{
 
479
        int fd;
 
480
 
 
481
        if (!lc)
 
482
                return NULL;
 
483
        if (lc->has_info)
 
484
                return &lc->info;
 
485
 
 
486
        fd = loopcxt_get_fd(lc);
 
487
        if (fd < 0)
 
488
                return NULL;
 
489
 
 
490
        if (ioctl(fd, LOOP_GET_STATUS64, &lc->info) == 0) {
 
491
                lc->has_info = 1;
 
492
                return &lc->info;
 
493
        }
 
494
 
 
495
        return NULL;
 
496
}
 
497
 
 
498
/*
 
499
 * @lc: context
 
500
 *
 
501
 * Returns (allocated) string with path to the file assicieted
 
502
 * with the current loop device.
 
503
 */
 
504
char *loopcxt_get_backing_file(struct loopdev_cxt *lc)
 
505
{
 
506
        struct sysfs_cxt *sysfs = loopcxt_get_sysfs(lc);
 
507
        char *res = NULL;
 
508
 
 
509
        if (sysfs)
 
510
                /*
 
511
                 * This is always preffered, the loop_info64
 
512
                 * has too small buffer for the filename.
 
513
                 */
 
514
                res = sysfs_strdup(sysfs, "loop/backing_file");
 
515
 
 
516
        if (!res && loopcxt_ioctl_enabled(lc)) {
 
517
                struct loop_info64 *lo = loopcxt_get_info(lc);
 
518
 
 
519
                if (lo) {
 
520
                        lo->lo_file_name[LO_NAME_SIZE - 2] = '*';
 
521
                        lo->lo_file_name[LO_NAME_SIZE - 1] = '\0';
 
522
                        res = strdup((char *) lo->lo_file_name);
 
523
                }
 
524
        }
 
525
        return res;
 
526
}
 
527
 
 
528
/*
 
529
 * @lc: context
 
530
 * @offset: returns offset number for the given device
 
531
 *
 
532
 * Returns: <0 on error, 0 on success
 
533
 */
 
534
int loopcxt_get_offset(struct loopdev_cxt *lc, uint64_t *offset)
 
535
{
 
536
        struct sysfs_cxt *sysfs = loopcxt_get_sysfs(lc);
 
537
        int rc = -EINVAL;
 
538
 
 
539
        if (sysfs)
 
540
                rc = sysfs_read_u64(sysfs, "loop/offset", offset);
 
541
 
 
542
        if (rc && loopcxt_ioctl_enabled(lc)) {
 
543
                struct loop_info64 *lo = loopcxt_get_info(lc);
 
544
                if (lo) {
 
545
                        if (offset)
 
546
                                *offset = lo->lo_offset;
 
547
                        return 0;
 
548
                }
 
549
        }
 
550
 
 
551
        return rc;
 
552
}
 
553
 
 
554
/*
 
555
 * @lc: context
 
556
 * @sizelimit: returns size limit for the given device
 
557
 *
 
558
 * Returns: <0 on error, 0 on success
 
559
 */
 
560
int loopcxt_get_sizelimit(struct loopdev_cxt *lc, uint64_t *size)
 
561
{
 
562
        struct sysfs_cxt *sysfs = loopcxt_get_sysfs(lc);
 
563
        int rc = -EINVAL;
 
564
 
 
565
        if (sysfs)
 
566
                rc = sysfs_read_u64(sysfs, "loop/sizelimit", size);
 
567
 
 
568
        if (rc && loopcxt_ioctl_enabled(lc)) {
 
569
                struct loop_info64 *lo = loopcxt_get_info(lc);
 
570
                if (lo) {
 
571
                        if (size)
 
572
                                *size = lo->lo_sizelimit;
 
573
                        return 0;
 
574
                }
 
575
        }
 
576
 
 
577
        return rc;
 
578
}
 
579
 
 
580
/*
 
581
 * @lc: context
 
582
 *
 
583
 * Returns: 1 of the autoclear flags is set.
 
584
 */
 
585
int loopcxt_is_autoclear(struct loopdev_cxt *lc)
 
586
{
 
587
        struct sysfs_cxt *sysfs = loopcxt_get_sysfs(lc);
 
588
 
 
589
        if (sysfs) {
 
590
                int fl;
 
591
                if (sysfs_read_int(sysfs, "loop/autoclear", &fl) == 0)
 
592
                        return fl;
 
593
        }
 
594
 
 
595
        if (loopcxt_ioctl_enabled(lc)) {
 
596
                struct loop_info64 *lo = loopcxt_get_info(lc);
 
597
                if (lo)
 
598
                        return lo->lo_flags & LO_FLAGS_AUTOCLEAR;
 
599
        }
 
600
        return 0;
 
601
}
 
602
 
 
603
/*
 
604
 * @lc: context
 
605
 *
 
606
 * Returns: 1 of the readonly flags is set.
 
607
 */
 
608
int loopcxt_is_readonly(struct loopdev_cxt *lc)
 
609
{
 
610
        struct sysfs_cxt *sysfs = loopcxt_get_sysfs(lc);
 
611
 
 
612
        if (sysfs) {
 
613
                int fl;
 
614
                if (sysfs_read_int(sysfs, "ro", &fl) == 0)
 
615
                        return fl;
 
616
        }
 
617
 
 
618
        if (loopcxt_ioctl_enabled(lc)) {
 
619
                struct loop_info64 *lo = loopcxt_get_info(lc);
 
620
                if (lo)
 
621
                        return lo->lo_flags & LO_FLAGS_READ_ONLY;
 
622
        }
 
623
        return 0;
 
624
}
 
625
 
 
626
/*
 
627
 * The setting is removed by loopcxt_set_device() loopcxt_next()!
 
628
 */
 
629
int loopcxt_set_offset(struct loopdev_cxt *lc, uint64_t offset)
 
630
{
 
631
        if (!lc)
 
632
                return -EINVAL;
 
633
        lc->info.lo_offset = offset;
 
634
        return 0;
 
635
}
 
636
 
 
637
/*
 
638
 * The setting is removed by loopcxt_set_device() loopcxt_next()!
 
639
 */
 
640
int loopcxt_set_sizelimit(struct loopdev_cxt *lc, uint64_t sizelimit)
 
641
{
 
642
        if (!lc)
 
643
                return -EINVAL;
 
644
        lc->info.lo_sizelimit = sizelimit;
 
645
        return 0;
 
646
}
 
647
 
 
648
/*
 
649
 * @lc: context
 
650
 * @flags: kernel LO_FLAGS_{READ_ONLY,USE_AOPS,AUTOCLEAR} flags
 
651
 *
 
652
 * The setting is removed by loopcxt_set_device() loopcxt_next()!
 
653
 *
 
654
 * Returns: 0 on success, <0 on error.
 
655
 */
 
656
int loopcxt_set_flags(struct loopdev_cxt *lc, uint32_t flags)
 
657
{
 
658
        if (!lc)
 
659
                return -EINVAL;
 
660
        lc->info.lo_flags = flags;
 
661
        return 0;
 
662
}
 
663
 
 
664
/*
 
665
 * @lc: context
 
666
 * @filename: backing file path (the path will be canonicalized)
 
667
 *
 
668
 * The setting is removed by loopcxt_set_device() loopcxt_next()!
 
669
 *
 
670
 * Returns: 0 on success, <0 on error.
 
671
 */
 
672
int loopcxt_set_backing_file(struct loopdev_cxt *lc, const char *filename)
 
673
{
 
674
        if (!lc)
 
675
                return -EINVAL;
 
676
 
 
677
        lc->filename = canonicalize_path(filename);
 
678
        if (!lc->filename)
 
679
                return -errno;
 
680
 
 
681
        strncpy((char *)lc->info.lo_file_name, lc->filename, LO_NAME_SIZE);
 
682
        lc->info.lo_file_name[LO_NAME_SIZE- 1] = '\0';
 
683
 
 
684
        return 0;
 
685
}
 
686
 
 
687
static int digits_only(const char *s)
 
688
{
 
689
        while (*s)
 
690
                if (!isdigit(*s++))
 
691
                        return 0;
 
692
        return 1;
 
693
}
 
694
 
 
695
/*
 
696
 * @lc: context
 
697
 * @encryption: encryption name / type (see lopsetup man page)
 
698
 * @password
 
699
 *
 
700
 * Note that the encryption functionality is deprecated an unmaintained. Use
 
701
 * cryptsetup (it also supports AES-loops).
 
702
 *
 
703
 * The setting is removed by loopcxt_set_device() loopcxt_next()!
 
704
 *
 
705
 * Returns: 0 on success, <0 on error.
 
706
 */
 
707
int loopcxt_set_encryption(struct loopdev_cxt *lc,
 
708
                           const char *encryption,
 
709
                           const char *password)
 
710
{
 
711
        if (!lc)
 
712
                return -EINVAL;
 
713
 
 
714
        if (encryption && *encryption) {
 
715
                if (digits_only(encryption)) {
 
716
                        lc->info.lo_encrypt_type = atoi(encryption);
 
717
                } else {
 
718
                        lc->info.lo_encrypt_type = LO_CRYPT_CRYPTOAPI;
 
719
                        snprintf((char *)lc->info.lo_crypt_name, LO_NAME_SIZE,
 
720
                                 "%s", encryption);
 
721
                }
 
722
        }
 
723
 
 
724
        switch (lc->info.lo_encrypt_type) {
 
725
        case LO_CRYPT_NONE:
 
726
                lc->info.lo_encrypt_key_size = 0;
 
727
                break;
 
728
        default:
 
729
                memset(lc->info.lo_encrypt_key, 0, LO_KEY_SIZE);
 
730
                strncpy((char *)lc->info.lo_encrypt_key, password, LO_KEY_SIZE);
 
731
                lc->info.lo_encrypt_key[LO_KEY_SIZE - 1] = '\0';
 
732
                lc->info.lo_encrypt_key_size = LO_KEY_SIZE;
 
733
                break;
 
734
        }
 
735
        return 0;
 
736
}
 
737
 
 
738
/*
 
739
 * @cl: context
 
740
 *
 
741
 * Associate the current device (see loopcxt_{set,get}_device()) with
 
742
 * a file (see loopcxt_set_backing_file()).
 
743
 *
 
744
 * The device is initialized read-write by default. If you want read-only
 
745
 * device then set LO_FLAGS_READ_ONLY by loopcxt_set_flags(). The LOOPDEV_FL_*
 
746
 * flags are ignored and modified according to LO_FLAGS_*.
 
747
 *
 
748
 * If the device is already open by loopcxt_get_fd() then this setup device
 
749
 * function will re-open the device to fix read/write mode.
 
750
 *
 
751
 * The device is also initialized read-only if the backing file is not
 
752
 * possible to open read-write (e.g. read-only FS).
 
753
 *
 
754
 * Returns: <0 on error, 0 on success.
 
755
 */
 
756
int loopcxt_setup_device(struct loopdev_cxt *lc)
 
757
{
 
758
        int file_fd, dev_fd, mode = O_RDWR, rc = -1;
 
759
 
 
760
        if (!lc || !*lc->device || !lc->filename)
 
761
                return -EINVAL;
 
762
 
 
763
        /*
 
764
         * Open backing file and device
 
765
         */
 
766
        if (lc->info.lo_flags & LO_FLAGS_READ_ONLY)
 
767
                mode = O_RDONLY;
 
768
 
 
769
        if ((file_fd = open(lc->filename, mode)) < 0) {
 
770
                if (mode != O_RDONLY && (errno == EROFS || errno == EACCES))
 
771
                        file_fd = open(lc->filename, mode = O_RDONLY);
 
772
 
 
773
                if (file_fd < 0)
 
774
                        return -errno;
 
775
        }
 
776
 
 
777
        if (lc->fd != -1 && lc->mode != mode) {
 
778
                close(lc->fd);
 
779
                lc->fd = -1;
 
780
                lc->mode = 0;
 
781
        }
 
782
 
 
783
        if (mode == O_RDONLY) {
 
784
                lc->flags |= LOOPDEV_FL_RDONLY;                 /* open() mode */
 
785
                lc->info.lo_flags |= LO_FLAGS_READ_ONLY;        /* kernel loopdev mode */
 
786
        } else {
 
787
                lc->flags |= LOOPDEV_FL_RDWR;                   /* open() mode */
 
788
                lc->info.lo_flags &= ~LO_FLAGS_READ_ONLY;
 
789
                lc->flags &= ~LOOPDEV_FL_RDONLY;
 
790
        }
 
791
 
 
792
        dev_fd = loopcxt_get_fd(lc);
 
793
        if (dev_fd < 0) {
 
794
                rc = -errno;
 
795
                goto err;
 
796
        }
 
797
 
 
798
        /*
 
799
         * Set FD
 
800
         */
 
801
        if (ioctl(dev_fd, LOOP_SET_FD, file_fd) < 0) {
 
802
                rc = -errno;
 
803
                goto err;
 
804
        }
 
805
        close(file_fd);
 
806
        file_fd = -1;
 
807
 
 
808
        if (ioctl(dev_fd, LOOP_SET_STATUS64, &lc->info))
 
809
                goto err;
 
810
 
 
811
        memset(&lc->info, 0, sizeof(lc->info));
 
812
        lc->has_info = 0;
 
813
 
 
814
        return 0;
 
815
err:
 
816
        if (file_fd >= 0)
 
817
                close(file_fd);
 
818
        if (dev_fd >= 0)
 
819
                ioctl(dev_fd, LOOP_CLR_FD, 0);
 
820
 
 
821
        return rc;
 
822
}
 
823
 
 
824
int loopcxt_delete_device(struct loopdev_cxt *lc)
 
825
{
 
826
        int fd = loopcxt_get_fd(lc);
 
827
 
 
828
        if (fd < 0)
 
829
                return -EINVAL;
 
830
 
 
831
        if (ioctl(fd, LOOP_CLR_FD, 0) < 0)
 
832
                return -errno;
 
833
        return 0;
 
834
}
 
835
 
 
836
int loopcxt_find_unused(struct loopdev_cxt *lc)
 
837
{
 
838
        int rc;
 
839
 
 
840
        rc = loopcxt_init_iterator(lc, LOOPITER_FL_FREE);
 
841
        if (rc)
 
842
                return rc;
 
843
 
 
844
        rc = loopcxt_next(lc);
 
845
        loopcxt_deinit_iterator(lc);
 
846
 
 
847
        return rc;
 
848
}
 
849
 
 
850
 
 
851
 
 
852
/*
 
853
 * Return: TRUE/FALSE
 
854
 */
 
855
int loopdev_is_autoclear(const char *device)
 
856
{
 
857
        struct loopdev_cxt lc;
 
858
        int rc;
 
859
 
 
860
        if (!device)
 
861
                return 0;
 
862
 
 
863
        loopcxt_init(&lc, 0);
 
864
        loopcxt_set_device(&lc, device);
 
865
        rc = loopcxt_is_autoclear(&lc);
 
866
        loopcxt_deinit(&lc);
 
867
 
 
868
        return rc;
 
869
}
 
870
 
 
871
char *loopdev_get_backing_file(const char *device)
 
872
{
 
873
        struct loopdev_cxt lc;
 
874
        char *res;
 
875
 
 
876
        if (!device)
 
877
                return NULL;
 
878
 
 
879
        loopcxt_init(&lc, 0);
 
880
        loopcxt_set_device(&lc, device);
 
881
        res = loopcxt_get_backing_file(&lc);
 
882
        loopcxt_deinit(&lc);
 
883
 
 
884
        return res;
 
885
}
 
886
 
 
887
/*
 
888
 * Returns: TRUE/FALSE
 
889
 */
 
890
int loopdev_is_used(const char *device, const char *filename,
 
891
                    uint64_t offset, int flags)
 
892
{
 
893
        struct loopdev_cxt lc;
 
894
        char *backing = NULL;
 
895
        int rc = 0;
 
896
 
 
897
        if (!device)
 
898
                return 0;
 
899
 
 
900
        loopcxt_init(&lc, 0);
 
901
        loopcxt_set_device(&lc, device);
 
902
 
 
903
        backing = loopcxt_get_backing_file(&lc);
 
904
        if (!backing)
 
905
                goto done;
 
906
        if (filename && strcmp(filename, backing) != 0)
 
907
                goto done;
 
908
        if (flags & LOOPDEV_FL_OFFSET) {
 
909
                uint64_t off;
 
910
 
 
911
                if (loopcxt_get_offset(&lc, &off) != 0 || off != offset)
 
912
                        goto done;
 
913
        }
 
914
 
 
915
        rc = 1;
 
916
done:
 
917
        free(backing);
 
918
        loopcxt_deinit(&lc);
 
919
 
 
920
        return rc;
 
921
}
 
922
 
 
923
int loopdev_delete(const char *device)
 
924
{
 
925
        struct loopdev_cxt lc;
 
926
        int rc;
 
927
 
 
928
        loopcxt_init(&lc, 0);
 
929
        rc = loopcxt_set_device(&lc, device);
 
930
        if (!rc)
 
931
                rc = loopcxt_delete_device(&lc);
 
932
        loopcxt_deinit(&lc);
 
933
        return rc;
 
934
}
 
935
 
 
936
/*
 
937
 * Returns: 0 = success, < 0 error, 1 not found
 
938
 */
 
939
int loopcxt_find_by_backing_file(struct loopdev_cxt *lc, const char *filename,
 
940
                                 uint64_t offset, int flags)
 
941
{
 
942
        int rc;
 
943
 
 
944
        if (!filename)
 
945
                return -EINVAL;
 
946
 
 
947
        rc = loopcxt_init_iterator(lc, LOOPITER_FL_USED);
 
948
        if (rc)
 
949
                return rc;
 
950
 
 
951
        while((rc = loopcxt_next(lc)) == 0) {
 
952
                char *backing = loopcxt_get_backing_file(lc);
 
953
 
 
954
                if (!backing || strcmp(backing, filename)) {
 
955
                        free(backing);
 
956
                        continue;
 
957
                }
 
958
 
 
959
                free(backing);
 
960
 
 
961
                if (flags & LOOPDEV_FL_OFFSET) {
 
962
                        uint64_t off;
 
963
                        if (loopcxt_get_offset(lc, &off) != 0 || offset != off)
 
964
                                continue;
 
965
                }
 
966
 
 
967
                rc = 0;
 
968
                break;
 
969
        }
 
970
 
 
971
        loopcxt_deinit_iterator(lc);
 
972
        return rc;
 
973
}
 
974
 
 
975
/*
 
976
 * Returns allocated string with device name
 
977
 */
 
978
char *loopdev_find_by_backing_file(const char *filename, uint64_t offset, int flags)
 
979
{
 
980
        struct loopdev_cxt lc;
 
981
        char *res = NULL;
 
982
 
 
983
        if (!filename)
 
984
                return NULL;
 
985
 
 
986
        loopcxt_init(&lc, 0);
 
987
        if (loopcxt_find_by_backing_file(&lc, filename, offset, flags))
 
988
                res = loopcxt_strdup_device(&lc);
 
989
        loopcxt_deinit(&lc);
 
990
 
 
991
        return res;
 
992
}
 
993
 
 
994
 
 
995
#ifdef TEST_PROGRAM_LOOPDEV
 
996
#include <errno.h>
 
997
#include <err.h>
 
998
 
 
999
static void test_loop_info(const char *device, int flags)
 
1000
{
 
1001
        struct loopdev_cxt lc;
 
1002
        char *p;
 
1003
        uint64_t u64;
 
1004
 
 
1005
        loopcxt_init(&lc, flags);
 
1006
        if (loopcxt_set_device(&lc, device))
 
1007
                err(EXIT_FAILURE, "failed to set device");
 
1008
 
 
1009
        p = loopcxt_get_backing_file(&lc);
 
1010
        printf("\tBACKING FILE: %s\n", p);
 
1011
        free(p);
 
1012
 
 
1013
        if (loopcxt_get_offset(&lc, &u64) == 0)
 
1014
                printf("\tOFFSET: %jd\n", u64);
 
1015
 
 
1016
        if (loopcxt_get_sizelimit(&lc, &u64) == 0)
 
1017
                printf("\tSIZE LIMIT: %jd\n", u64);
 
1018
 
 
1019
        printf("\tAUTOCLEAR: %s\n", loopcxt_is_autoclear(&lc) ? "YES" : "NOT");
 
1020
 
 
1021
        loopcxt_deinit(&lc);
 
1022
}
 
1023
 
 
1024
static void test_loop_scan(int flags)
 
1025
{
 
1026
        struct loopdev_cxt lc;
 
1027
        int rc;
 
1028
 
 
1029
        loopcxt_init(&lc, 0);
 
1030
 
 
1031
        if (loopcxt_init_iterator(&lc, flags))
 
1032
                err(EXIT_FAILURE, "iterator initlization failed");
 
1033
 
 
1034
        while((rc = loopcxt_next(&lc)) == 0) {
 
1035
                const char *device = loopcxt_get_device(&lc);
 
1036
 
 
1037
                if (flags & LOOPITER_FL_USED) {
 
1038
                        char *backing = loopcxt_get_backing_file(&lc);
 
1039
                        printf("\t%s: %s\n", device, backing);
 
1040
                        free(backing);
 
1041
                } else
 
1042
                        printf("\t%s\n", device);
 
1043
        }
 
1044
 
 
1045
        if (rc < 0)
 
1046
                err(EXIT_FAILURE, "loopdevs scanning failed");
 
1047
 
 
1048
        loopcxt_deinit(&lc);
 
1049
}
 
1050
 
 
1051
static int test_loop_setup(const char *filename, const char *device)
 
1052
{
 
1053
        struct loopdev_cxt lc;
 
1054
        int rc = 0;
 
1055
 
 
1056
        loopcxt_init(&lc, 0);
 
1057
 
 
1058
        if (device) {
 
1059
                rc = loopcxt_set_device(&lc, device);
 
1060
                if (rc)
 
1061
                        err(EXIT_FAILURE, "failed to set device: %s", device);
 
1062
        }
 
1063
 
 
1064
        do {
 
1065
                if (!device) {
 
1066
                        rc = loopcxt_find_unused(&lc);
 
1067
                        if (rc)
 
1068
                                err(EXIT_FAILURE, "failed to find unused device");
 
1069
                        printf("Trying to use '%s'\n", loopcxt_get_device(&lc));
 
1070
                }
 
1071
 
 
1072
                if (loopcxt_set_backing_file(&lc, filename))
 
1073
                        err(EXIT_FAILURE, "failed to set backing file");
 
1074
 
 
1075
                rc = loopcxt_setup_device(&lc);
 
1076
                if (rc == 0)
 
1077
                        break;          /* success */
 
1078
 
 
1079
                if (device || rc != -EBUSY)
 
1080
                        err(EXIT_FAILURE, "failed to setup device for %s",
 
1081
                                        lc.filename);
 
1082
 
 
1083
                printf("device stolen...trying again\n");
 
1084
        } while (1);
 
1085
 
 
1086
        loopcxt_deinit(&lc);
 
1087
 
 
1088
        return 0;
 
1089
}
 
1090
 
 
1091
int main(int argc, char *argv[])
 
1092
{
 
1093
        if (argc < 2)
 
1094
                goto usage;
 
1095
 
 
1096
        if (argc == 3 && strcmp(argv[1], "--info") == 0) {
 
1097
                printf("---sysfs & ioctl:---\n");
 
1098
                test_loop_info(argv[2], 0);
 
1099
                printf("---sysfs only:---\n");
 
1100
                test_loop_info(argv[2], LOOPDEV_FL_NOIOCTL);
 
1101
                printf("---ioctl only:---\n");
 
1102
                test_loop_info(argv[2], LOOPDEV_FL_NOSYSFS);
 
1103
 
 
1104
        } else if (argc == 2 && strcmp(argv[1], "--used") == 0) {
 
1105
                printf("---all used devices---\n");
 
1106
                test_loop_scan(LOOPITER_FL_USED);
 
1107
 
 
1108
        } else if (argc == 2 && strcmp(argv[1], "--free") == 0) {
 
1109
                printf("---all free devices---\n");
 
1110
                test_loop_scan(LOOPITER_FL_FREE);
 
1111
 
 
1112
        } else if (argc >= 3 && strcmp(argv[1], "--setup") == 0) {
 
1113
                test_loop_setup(argv[2], argv[3]);
 
1114
 
 
1115
        } else if (argc == 3 && strcmp(argv[1], "--delete") == 0) {
 
1116
                if (loopdev_delete(argv[2]))
 
1117
                        errx(EXIT_FAILURE, "failed to deinitialize device %s", argv[2]);
 
1118
        } else
 
1119
                goto usage;
 
1120
 
 
1121
        return EXIT_SUCCESS;
 
1122
 
 
1123
usage:
 
1124
        errx(EXIT_FAILURE, "usage: \n"
 
1125
                           "  %1$s --info <device>\n"
 
1126
                           "  %1$s --free\n"
 
1127
                           "  %1$s --used\n"
 
1128
                           "  %1$s --setup <filename> [<device>]\n"
 
1129
                           "  %1$s --delete\n",
 
1130
                           argv[0]);
 
1131
}
 
1132
 
 
1133
#endif /* TEST_PROGRAM */