]> git.ipfire.org Git - thirdparty/util-linux.git/blame - lib/loopdev.c
libmount: variable dereferenced before check [smatch scan]
[thirdparty/util-linux.git] / lib / loopdev.c
CommitLineData
10ee5932
KZ
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>
10ee5932
KZ
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 */
53int 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;
fd7f0718 61 lc->mode = 0;
10ee5932
KZ
62 lc->has_info = 0;
63 *lc->device = '\0';
fd7f0718 64 memset(&lc->info, 0, sizeof(lc->info));
10ee5932
KZ
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 *
fd7f0718
KZ
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 *
10ee5932
KZ
108 * Returns: <0 on error, 0 on success.
109 */
110int 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 */
134void 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 */
151char *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 */
163const 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 */
173struct 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 */
196int loopcxt_get_fd(struct loopdev_cxt *lc)
197{
198 if (!lc || !*lc->device)
fd7f0718 199 return -EINVAL;
10ee5932 200
fd7f0718
KZ
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 }
10ee5932
KZ
205 return lc->fd;
206}
207
fd7f0718
KZ
208int 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
10ee5932
KZ
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 */
226int 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 */
261int 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 */
286static 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
310static int cmpnum(const void *p1, const void *p2)
311{
33487796
KZ
312 return (((* (int *) p1) > (* (int *) p2)) -
313 ((* (int *) p1) < (* (int *) p2)));
10ee5932
KZ
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 */
321static 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 (*ary)[count++] = n;
373 }
374 if (count)
375 qsort(*ary, count, sizeof(int), cmpnum);
376
377 closedir(dir);
378 return count;
379}
380
381/*
382 * @lc: context, has to initialized by loopcxt_init_iterator()
383 *
384 * Returns: 0 on success, -1 on error, 1 at the end of scanning. The details
385 * about the current loop device are available by
386 * loopcxt_get_{fd,backing_file,device,offset, ...} functions.
387 */
388int loopcxt_next(struct loopdev_cxt *lc)
389{
390 struct loopdev_iter *iter;
391
392 if (!lc)
393 return -EINVAL;
394 iter = &lc->iter;
395 if (iter->done)
396 return 1;
397
398 /* A) Look for used loop devices in /proc/partitions ("losetup -a" only)
399 */
400 if (iter->flags & LOOPITER_FL_USED) {
401 char buf[BUFSIZ];
402
403 if (!iter->proc)
404 iter->proc = fopen(_PATH_PROC_PARTITIONS, "r");
405
406 while (iter->proc && fgets(buf, sizeof(buf), iter->proc)) {
407 unsigned int m;
408 char name[128];
409
410 if (sscanf(buf, " %u %*s %*s %128[^\n ]",
411 &m, name) != 2 || m != LOOPDEV_MAJOR)
412 continue;
413
414 if (loopiter_set_device(lc, name) == 0)
415 return 0;
416 }
417
418 goto done;
419 }
420
421 /* B) Classic way, try first eight loop devices (default number
422 * of loop devices). This is enough for 99% of all cases.
423 */
424 if (iter->default_check) {
425 for (++iter->ncur; iter->ncur < LOOPDEV_DEFAULT_NNODES;
426 iter->ncur++) {
427 char name[16];
428 snprintf(name, sizeof(name), "loop%d", iter->ncur);
429
430 if (loopiter_set_device(lc, name) == 0)
431 return 0;
432 }
433 iter->default_check = 0;
434 }
435
436 /* C) the worst possibility, scan whole /dev or /dev/loop/<N>
437 */
438 if (!iter->minors) {
439 iter->nminors = (lc->flags & LOOPDEV_FL_DEVSUBDIR) ?
440 loop_scandir(_PATH_DEV_LOOP, &iter->minors, 0) :
441 loop_scandir(_PATH_DEV, &iter->minors, 1);
442 iter->ncur = -1;
443 }
444 for (++iter->ncur; iter->ncur < iter->nminors; iter->ncur++) {
445 char name[16];
446 snprintf(name, sizeof(name), "loop%d", iter->minors[iter->ncur]);
447
448 if (loopiter_set_device(lc, name) == 0)
449 return 0;
450 }
451done:
452 loopcxt_deinit_iterator(lc);
453 return 1;
454}
455
456/*
457 * @device: path to device
458 */
459int is_loopdev(const char *device)
460{
461 struct stat st;
462
463 if (!device)
464 return 0;
465
466 return (stat(device, &st) == 0 &&
467 S_ISBLK(st.st_mode) &&
468 major(st.st_rdev) == LOOPDEV_MAJOR);
469}
470
471/*
472 * @lc: context
473 *
474 * Returns result from LOOP_GET_STAT64 ioctl or NULL on error.
475 */
476struct loop_info64 *loopcxt_get_info(struct loopdev_cxt *lc)
477{
478 int fd;
479
480 if (!lc)
481 return NULL;
482 if (lc->has_info)
483 return &lc->info;
484
485 fd = loopcxt_get_fd(lc);
486 if (fd < 0)
487 return NULL;
488
489 if (ioctl(fd, LOOP_GET_STATUS64, &lc->info) == 0) {
490 lc->has_info = 1;
491 return &lc->info;
492 }
493
494 return NULL;
495}
496
497/*
498 * @lc: context
499 *
500 * Returns (allocated) string with path to the file assicieted
501 * with the current loop device.
502 */
503char *loopcxt_get_backing_file(struct loopdev_cxt *lc)
504{
505 struct sysfs_cxt *sysfs = loopcxt_get_sysfs(lc);
506 char *res = NULL;
507
508 if (sysfs)
fd7f0718
KZ
509 /*
510 * This is always preffered, the loop_info64
511 * has too small buffer for the filename.
512 */
10ee5932
KZ
513 res = sysfs_strdup(sysfs, "loop/backing_file");
514
515 if (!res && loopcxt_ioctl_enabled(lc)) {
516 struct loop_info64 *lo = loopcxt_get_info(lc);
517
518 if (lo) {
519 lo->lo_file_name[LO_NAME_SIZE - 2] = '*';
520 lo->lo_file_name[LO_NAME_SIZE - 1] = '\0';
521 res = strdup((char *) lo->lo_file_name);
522 }
523 }
524 return res;
525}
526
527/*
528 * @lc: context
529 * @offset: returns offset number for the given device
530 *
531 * Returns: <0 on error, 0 on success
532 */
533int loopcxt_get_offset(struct loopdev_cxt *lc, uint64_t *offset)
534{
535 struct sysfs_cxt *sysfs = loopcxt_get_sysfs(lc);
536 int rc = -EINVAL;
537
538 if (sysfs)
539 rc = sysfs_read_u64(sysfs, "loop/offset", offset);
540
541 if (rc && loopcxt_ioctl_enabled(lc)) {
542 struct loop_info64 *lo = loopcxt_get_info(lc);
543 if (lo) {
544 if (offset)
545 *offset = lo->lo_offset;
546 return 0;
547 }
548 }
549
550 return rc;
551}
552
553/*
554 * @lc: context
555 * @sizelimit: returns size limit for the given device
556 *
557 * Returns: <0 on error, 0 on success
558 */
559int loopcxt_get_sizelimit(struct loopdev_cxt *lc, uint64_t *size)
560{
561 struct sysfs_cxt *sysfs = loopcxt_get_sysfs(lc);
562 int rc = -EINVAL;
563
564 if (sysfs)
565 rc = sysfs_read_u64(sysfs, "loop/sizelimit", size);
566
567 if (rc && loopcxt_ioctl_enabled(lc)) {
568 struct loop_info64 *lo = loopcxt_get_info(lc);
569 if (lo) {
570 if (size)
571 *size = lo->lo_sizelimit;
572 return 0;
573 }
574 }
575
576 return rc;
577}
578
579/*
580 * @lc: context
581 *
582 * Returns: 1 of the autoclear flags is set.
583 */
584int loopcxt_is_autoclear(struct loopdev_cxt *lc)
585{
586 struct sysfs_cxt *sysfs = loopcxt_get_sysfs(lc);
587
588 if (sysfs) {
589 int fl;
590 if (sysfs_read_int(sysfs, "loop/autoclear", &fl) == 0)
591 return fl;
592 }
593
594 if (loopcxt_ioctl_enabled(lc)) {
595 struct loop_info64 *lo = loopcxt_get_info(lc);
596 if (lo)
597 return lo->lo_flags & LO_FLAGS_AUTOCLEAR;
598 }
599 return 0;
600}
601
fd7f0718
KZ
602/*
603 * @lc: context
604 *
605 * Returns: 1 of the readonly flags is set.
606 */
607int loopcxt_is_readonly(struct loopdev_cxt *lc)
608{
609 struct sysfs_cxt *sysfs = loopcxt_get_sysfs(lc);
610
611 if (sysfs) {
612 int fl;
613 if (sysfs_read_int(sysfs, "ro", &fl) == 0)
614 return fl;
615 }
616
617 if (loopcxt_ioctl_enabled(lc)) {
618 struct loop_info64 *lo = loopcxt_get_info(lc);
619 if (lo)
620 return lo->lo_flags & LO_FLAGS_READ_ONLY;
621 }
622 return 0;
623}
624
625/*
626 * The setting is removed by loopcxt_set_device() loopcxt_next()!
627 */
10ee5932
KZ
628int loopcxt_set_offset(struct loopdev_cxt *lc, uint64_t offset)
629{
630 if (!lc)
631 return -EINVAL;
632 lc->info.lo_offset = offset;
633 return 0;
634}
635
fd7f0718
KZ
636/*
637 * The setting is removed by loopcxt_set_device() loopcxt_next()!
638 */
10ee5932
KZ
639int loopcxt_set_sizelimit(struct loopdev_cxt *lc, uint64_t sizelimit)
640{
641 if (!lc)
642 return -EINVAL;
643 lc->info.lo_sizelimit = sizelimit;
644 return 0;
645}
646
647/*
648 * @lc: context
649 * @flags: kernel LO_FLAGS_{READ_ONLY,USE_AOPS,AUTOCLEAR} flags
650 *
fd7f0718
KZ
651 * The setting is removed by loopcxt_set_device() loopcxt_next()!
652 *
10ee5932
KZ
653 * Returns: 0 on success, <0 on error.
654 */
655int loopcxt_set_flags(struct loopdev_cxt *lc, uint32_t flags)
656{
657 if (!lc)
658 return -EINVAL;
659 lc->info.lo_flags = flags;
660 return 0;
661}
662
663/*
664 * @lc: context
665 * @filename: backing file path (the path will be canonicalized)
666 *
fd7f0718
KZ
667 * The setting is removed by loopcxt_set_device() loopcxt_next()!
668 *
10ee5932
KZ
669 * Returns: 0 on success, <0 on error.
670 */
671int loopcxt_set_backing_file(struct loopdev_cxt *lc, const char *filename)
672{
673 if (!lc)
674 return -EINVAL;
675
676 lc->filename = canonicalize_path(filename);
677 if (!lc->filename)
678 return -errno;
679
680 strncpy((char *)lc->info.lo_file_name, lc->filename, LO_NAME_SIZE);
681 lc->info.lo_file_name[LO_NAME_SIZE- 1] = '\0';
682
683 return 0;
684}
685
686static int digits_only(const char *s)
687{
688 while (*s)
689 if (!isdigit(*s++))
690 return 0;
691 return 1;
692}
693
694/*
695 * @lc: context
696 * @encryption: encryption name / type (see lopsetup man page)
697 * @password
698 *
fd7f0718 699 * Note that the encryption functionality is deprecated an unmaintained. Use
10ee5932
KZ
700 * cryptsetup (it also supports AES-loops).
701 *
fd7f0718
KZ
702 * The setting is removed by loopcxt_set_device() loopcxt_next()!
703 *
10ee5932
KZ
704 * Returns: 0 on success, <0 on error.
705 */
706int loopcxt_set_encryption(struct loopdev_cxt *lc,
707 const char *encryption,
708 const char *password)
709{
710 if (!lc)
711 return -EINVAL;
712
713 if (encryption && *encryption) {
714 if (digits_only(encryption)) {
715 lc->info.lo_encrypt_type = atoi(encryption);
716 } else {
717 lc->info.lo_encrypt_type = LO_CRYPT_CRYPTOAPI;
718 snprintf((char *)lc->info.lo_crypt_name, LO_NAME_SIZE,
719 "%s", encryption);
720 }
721 }
722
723 switch (lc->info.lo_encrypt_type) {
724 case LO_CRYPT_NONE:
725 lc->info.lo_encrypt_key_size = 0;
726 break;
727 default:
728 memset(lc->info.lo_encrypt_key, 0, LO_KEY_SIZE);
729 strncpy((char *)lc->info.lo_encrypt_key, password, LO_KEY_SIZE);
730 lc->info.lo_encrypt_key[LO_KEY_SIZE - 1] = '\0';
731 lc->info.lo_encrypt_key_size = LO_KEY_SIZE;
732 break;
733 }
734 return 0;
735}
736
737/*
738 * @cl: context
739 *
740 * Associate the current device (see loopcxt_{set,get}_device()) with
741 * a file (see loopcxt_set_backing_file()).
742 *
fd7f0718
KZ
743 * The device is initialized read-write by default. If you want read-only
744 * device then set LO_FLAGS_READ_ONLY by loopcxt_set_flags(). The LOOPDEV_FL_*
745 * flags are ignored and modified according to LO_FLAGS_*.
746 *
747 * If the device is already open by loopcxt_get_fd() then this setup device
748 * function will re-open the device to fix read/write mode.
749 *
750 * The device is also initialized read-only if the backing file is not
751 * possible to open read-write (e.g. read-only FS).
10ee5932
KZ
752 *
753 * Returns: <0 on error, 0 on success.
754 */
755int loopcxt_setup_device(struct loopdev_cxt *lc)
756{
fd7f0718 757 int file_fd, dev_fd, mode = O_RDWR, rc = -1;
10ee5932
KZ
758
759 if (!lc || !*lc->device || !lc->filename)
760 return -EINVAL;
761
762 /*
763 * Open backing file and device
764 */
fd7f0718
KZ
765 if (lc->info.lo_flags & LO_FLAGS_READ_ONLY)
766 mode = O_RDONLY;
10ee5932
KZ
767
768 if ((file_fd = open(lc->filename, mode)) < 0) {
769 if (mode != O_RDONLY && (errno == EROFS || errno == EACCES))
770 file_fd = open(lc->filename, mode = O_RDONLY);
771
772 if (file_fd < 0)
773 return -errno;
774 }
775
fd7f0718
KZ
776 if (lc->fd != -1 && lc->mode != mode) {
777 close(lc->fd);
778 lc->fd = -1;
779 lc->mode = 0;
780 }
781
10ee5932 782 if (mode == O_RDONLY) {
fd7f0718
KZ
783 lc->flags |= LOOPDEV_FL_RDONLY; /* open() mode */
784 lc->info.lo_flags |= LO_FLAGS_READ_ONLY; /* kernel loopdev mode */
785 } else {
786 lc->flags |= LOOPDEV_FL_RDWR; /* open() mode */
787 lc->info.lo_flags &= ~LO_FLAGS_READ_ONLY;
788 lc->flags &= ~LOOPDEV_FL_RDONLY;
789 }
10ee5932
KZ
790
791 dev_fd = loopcxt_get_fd(lc);
792 if (dev_fd < 0) {
793 rc = -errno;
794 goto err;
795 }
796
797 /*
798 * Set FD
799 */
800 if (ioctl(dev_fd, LOOP_SET_FD, file_fd) < 0) {
801 rc = -errno;
802 goto err;
803 }
804 close(file_fd);
805 file_fd = -1;
806
807 if (ioctl(dev_fd, LOOP_SET_STATUS64, &lc->info))
808 goto err;
809
810 memset(&lc->info, 0, sizeof(lc->info));
811 lc->has_info = 0;
812
813 return 0;
814err:
815 if (file_fd >= 0)
816 close(file_fd);
817 if (dev_fd >= 0)
818 ioctl(dev_fd, LOOP_CLR_FD, 0);
819
820 return rc;
821}
822
823int loopcxt_delete_device(struct loopdev_cxt *lc)
824{
825 int fd = loopcxt_get_fd(lc);
826
827 if (fd < 0)
828 return -EINVAL;
829
830 if (ioctl(fd, LOOP_CLR_FD, 0) < 0)
831 return -errno;
832 return 0;
833}
834
835int loopcxt_find_unused(struct loopdev_cxt *lc)
836{
837 int rc;
838
839 rc = loopcxt_init_iterator(lc, LOOPITER_FL_FREE);
840 if (rc)
841 return rc;
842
843 rc = loopcxt_next(lc);
844 loopcxt_deinit_iterator(lc);
845
846 return rc;
847}
848
849
850
851/*
852 * Return: TRUE/FALSE
853 */
854int loopdev_is_autoclear(const char *device)
855{
856 struct loopdev_cxt lc;
857 int rc;
858
859 if (!device)
860 return 0;
861
862 loopcxt_init(&lc, 0);
863 loopcxt_set_device(&lc, device);
864 rc = loopcxt_is_autoclear(&lc);
865 loopcxt_deinit(&lc);
866
867 return rc;
868}
869
870char *loopdev_get_backing_file(const char *device)
871{
872 struct loopdev_cxt lc;
873 char *res;
874
875 if (!device)
876 return NULL;
877
878 loopcxt_init(&lc, 0);
879 loopcxt_set_device(&lc, device);
880 res = loopcxt_get_backing_file(&lc);
881 loopcxt_deinit(&lc);
882
883 return res;
884}
885
886/*
887 * Returns: TRUE/FALSE
888 */
889int loopdev_is_used(const char *device, const char *filename,
890 uint64_t offset, int flags)
891{
892 struct loopdev_cxt lc;
893 char *backing = NULL;
894 int rc = 0;
895
896 if (!device)
897 return 0;
898
899 loopcxt_init(&lc, 0);
900 loopcxt_set_device(&lc, device);
901
902 backing = loopcxt_get_backing_file(&lc);
903 if (!backing)
904 goto done;
905 if (filename && strcmp(filename, backing) != 0)
906 goto done;
907 if (flags & LOOPDEV_FL_OFFSET) {
908 uint64_t off;
909
910 if (loopcxt_get_offset(&lc, &off) != 0 || off != offset)
911 goto done;
912 }
913
914 rc = 1;
915done:
916 free(backing);
917 loopcxt_deinit(&lc);
918
919 return rc;
920}
921
922int loopdev_delete(const char *device)
923{
924 struct loopdev_cxt lc;
925 int rc;
926
927 loopcxt_init(&lc, 0);
928 rc = loopcxt_set_device(&lc, device);
929 if (!rc)
930 rc = loopcxt_delete_device(&lc);
931 loopcxt_deinit(&lc);
932 return rc;
933}
934
935/*
936 * Returns: 0 = success, < 0 error, 1 not found
937 */
938int loopcxt_find_by_backing_file(struct loopdev_cxt *lc, const char *filename,
939 uint64_t offset, int flags)
940{
941 int rc;
942
943 if (!filename)
944 return -EINVAL;
945
946 rc = loopcxt_init_iterator(lc, LOOPITER_FL_USED);
947 if (rc)
948 return rc;
949
950 while((rc = loopcxt_next(lc)) == 0) {
951 char *backing = loopcxt_get_backing_file(lc);
952
953 if (!backing || strcmp(backing, filename)) {
954 free(backing);
955 continue;
956 }
957
958 free(backing);
959
960 if (flags & LOOPDEV_FL_OFFSET) {
961 uint64_t off;
962 if (loopcxt_get_offset(lc, &off) != 0 || offset != off)
963 continue;
964 }
965
966 rc = 0;
967 break;
968 }
969
970 loopcxt_deinit_iterator(lc);
971 return rc;
972}
973
974/*
975 * Returns allocated string with device name
976 */
977char *loopdev_find_by_backing_file(const char *filename, uint64_t offset, int flags)
978{
979 struct loopdev_cxt lc;
980 char *res = NULL;
981
982 if (!filename)
983 return NULL;
984
985 loopcxt_init(&lc, 0);
986 if (loopcxt_find_by_backing_file(&lc, filename, offset, flags))
987 res = loopcxt_strdup_device(&lc);
988 loopcxt_deinit(&lc);
989
990 return res;
991}
992
993
994#ifdef TEST_PROGRAM_LOOPDEV
995#include <errno.h>
996#include <err.h>
10ee5932
KZ
997
998static void test_loop_info(const char *device, int flags)
999{
1000 struct loopdev_cxt lc;
1001 char *p;
1002 uint64_t u64;
1003
1004 loopcxt_init(&lc, flags);
1005 if (loopcxt_set_device(&lc, device))
1006 err(EXIT_FAILURE, "failed to set device");
1007
1008 p = loopcxt_get_backing_file(&lc);
1009 printf("\tBACKING FILE: %s\n", p);
1010 free(p);
1011
1012 if (loopcxt_get_offset(&lc, &u64) == 0)
1013 printf("\tOFFSET: %jd\n", u64);
1014
1015 if (loopcxt_get_sizelimit(&lc, &u64) == 0)
1016 printf("\tSIZE LIMIT: %jd\n", u64);
1017
1018 printf("\tAUTOCLEAR: %s\n", loopcxt_is_autoclear(&lc) ? "YES" : "NOT");
1019
1020 loopcxt_deinit(&lc);
1021}
1022
1023static void test_loop_scan(int flags)
1024{
1025 struct loopdev_cxt lc;
1026 int rc;
1027
1028 loopcxt_init(&lc, 0);
1029
1030 if (loopcxt_init_iterator(&lc, flags))
1031 err(EXIT_FAILURE, "iterator initlization failed");
1032
1033 while((rc = loopcxt_next(&lc)) == 0) {
1034 const char *device = loopcxt_get_device(&lc);
1035
1036 if (flags & LOOPITER_FL_USED) {
1037 char *backing = loopcxt_get_backing_file(&lc);
1038 printf("\t%s: %s\n", device, backing);
1039 free(backing);
1040 } else
1041 printf("\t%s\n", device);
1042 }
1043
1044 if (rc < 0)
1045 err(EXIT_FAILURE, "loopdevs scanning failed");
1046
1047 loopcxt_deinit(&lc);
1048}
1049
1050static int test_loop_setup(const char *filename, const char *device)
1051{
1052 struct loopdev_cxt lc;
1053 int rc = 0;
1054
1055 loopcxt_init(&lc, 0);
1056
10ee5932
KZ
1057 if (device) {
1058 rc = loopcxt_set_device(&lc, device);
1059 if (rc)
1060 err(EXIT_FAILURE, "failed to set device: %s", device);
1061 }
1062
1063 do {
1064 if (!device) {
1065 rc = loopcxt_find_unused(&lc);
1066 if (rc)
ad2d0d85 1067 err(EXIT_FAILURE, "failed to find unused device");
10ee5932
KZ
1068 printf("Trying to use '%s'\n", loopcxt_get_device(&lc));
1069 }
1070
fd7f0718
KZ
1071 if (loopcxt_set_backing_file(&lc, filename))
1072 err(EXIT_FAILURE, "failed to set backing file");
1073
10ee5932
KZ
1074 rc = loopcxt_setup_device(&lc);
1075 if (rc == 0)
1076 break; /* success */
1077
1078 if (device || rc != -EBUSY)
1079 err(EXIT_FAILURE, "failed to setup device for %s",
1080 lc.filename);
1081
1082 printf("device stolen...trying again\n");
1083 } while (1);
1084
1085 loopcxt_deinit(&lc);
1086
1087 return 0;
1088}
1089
1090int main(int argc, char *argv[])
1091{
1092 if (argc < 2)
1093 goto usage;
1094
1095 if (argc == 3 && strcmp(argv[1], "--info") == 0) {
1096 printf("---sysfs & ioctl:---\n");
1097 test_loop_info(argv[2], 0);
1098 printf("---sysfs only:---\n");
1099 test_loop_info(argv[2], LOOPDEV_FL_NOIOCTL);
1100 printf("---ioctl only:---\n");
1101 test_loop_info(argv[2], LOOPDEV_FL_NOSYSFS);
1102
1103 } else if (argc == 2 && strcmp(argv[1], "--used") == 0) {
1104 printf("---all used devices---\n");
1105 test_loop_scan(LOOPITER_FL_USED);
1106
1107 } else if (argc == 2 && strcmp(argv[1], "--free") == 0) {
1108 printf("---all free devices---\n");
1109 test_loop_scan(LOOPITER_FL_FREE);
1110
1111 } else if (argc >= 3 && strcmp(argv[1], "--setup") == 0) {
1112 test_loop_setup(argv[2], argv[3]);
1113
1114 } else if (argc == 3 && strcmp(argv[1], "--delete") == 0) {
1115 if (loopdev_delete(argv[2]))
1116 errx(EXIT_FAILURE, "failed to deinitialize device %s", argv[2]);
1117 } else
1118 goto usage;
1119
1120 return EXIT_SUCCESS;
1121
1122usage:
1123 errx(EXIT_FAILURE, "usage: \n"
1124 " %1$s --info <device>\n"
1125 " %1$s --free\n"
1126 " %1$s --used\n"
1127 " %1$s --setup <filename> [<device>]\n"
1128 " %1$s --delete\n",
1129 argv[0]);
1130}
1131
1132#endif /* TEST_PROGRAM */