]>
git.ipfire.org Git - thirdparty/systemd.git/blob - src/shared/loop-util.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2016 Lennart Poettering
10 #include <linux/loop.h>
11 #include <sys/ioctl.h>
14 #include "alloc-util.h"
16 #include "loop-util.h"
17 #include "stat-util.h"
19 int loop_device_make(int fd
, int open_flags
, LoopDevice
**ret
) {
20 const struct loop_info64 info
= {
21 .lo_flags
= LO_FLAGS_AUTOCLEAR
|LO_FLAGS_PARTSCAN
|(open_flags
== O_RDONLY
? LO_FLAGS_READ_ONLY
: 0),
24 _cleanup_close_
int control
= -1, loop
= -1;
25 _cleanup_free_
char *loopdev
= NULL
;
32 assert(IN_SET(open_flags
, O_RDWR
, O_RDONLY
));
34 if (fstat(fd
, &st
) < 0)
37 if (S_ISBLK(st
.st_mode
)) {
40 /* If this is already a block device, store a copy of the fd as it is */
42 copy
= fcntl(fd
, F_DUPFD_CLOEXEC
, 3);
46 d
= new0(LoopDevice
, 1);
60 r
= stat_verify_regular(&st
);
64 control
= open("/dev/loop-control", O_RDWR
|O_CLOEXEC
|O_NOCTTY
|O_NONBLOCK
);
68 nr
= ioctl(control
, LOOP_CTL_GET_FREE
);
72 if (asprintf(&loopdev
, "/dev/loop%i", nr
) < 0)
75 loop
= open(loopdev
, O_CLOEXEC
|O_NONBLOCK
|O_NOCTTY
|open_flags
);
79 if (ioctl(loop
, LOOP_SET_FD
, fd
) < 0)
82 if (ioctl(loop
, LOOP_SET_STATUS64
, &info
) < 0)
85 d
= new(LoopDevice
, 1);
91 .node
= TAKE_PTR(loopdev
),
100 int loop_device_make_by_path(const char *path
, int open_flags
, LoopDevice
**ret
) {
101 _cleanup_close_
int fd
= -1;
105 assert(IN_SET(open_flags
, O_RDWR
, O_RDONLY
));
107 fd
= open(path
, O_CLOEXEC
|O_NONBLOCK
|O_NOCTTY
|open_flags
);
111 return loop_device_make(fd
, open_flags
, ret
);
114 LoopDevice
* loop_device_unref(LoopDevice
*d
) {
120 if (d
->nr
>= 0 && !d
->relinquished
) {
121 if (ioctl(d
->fd
, LOOP_CLR_FD
) < 0)
122 log_debug_errno(errno
, "Failed to clear loop device: %m");
129 if (d
->nr
>= 0 && !d
->relinquished
) {
130 _cleanup_close_
int control
= -1;
132 control
= open("/dev/loop-control", O_RDWR
|O_CLOEXEC
|O_NOCTTY
|O_NONBLOCK
);
134 log_debug_errno(errno
, "Failed to open loop control device: %m");
136 if (ioctl(control
, LOOP_CTL_REMOVE
, d
->nr
) < 0)
137 log_debug_errno(errno
, "Failed to remove loop device: %m");
145 void loop_device_relinquish(LoopDevice
*d
) {
148 /* Don't attempt to clean up the loop device anymore from this point on. Leave the clean-ing up to the kernel
149 * itself, using the loop device "auto-clear" logic we already turned on when creating the device. */
151 d
->relinquished
= true;