]>
git.ipfire.org Git - thirdparty/systemd.git/blob - src/shared/loop-util.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
5 #include <linux/loop.h>
9 #include "alloc-util.h"
11 #include "loop-util.h"
12 #include "stat-util.h"
14 int loop_device_make(int fd
, int open_flags
, LoopDevice
**ret
) {
15 const struct loop_info64 info
= {
16 .lo_flags
= LO_FLAGS_AUTOCLEAR
|LO_FLAGS_PARTSCAN
|(open_flags
== O_RDONLY
? LO_FLAGS_READ_ONLY
: 0),
19 _cleanup_close_
int control
= -1, loop
= -1;
20 _cleanup_free_
char *loopdev
= NULL
;
27 assert(IN_SET(open_flags
, O_RDWR
, O_RDONLY
));
29 if (fstat(fd
, &st
) < 0)
32 if (S_ISBLK(st
.st_mode
)) {
35 /* If this is already a block device, store a copy of the fd as it is */
37 copy
= fcntl(fd
, F_DUPFD_CLOEXEC
, 3);
41 d
= new0(LoopDevice
, 1);
48 .relinquished
= true, /* It's not allocated by us, don't destroy it when this object is freed */
55 r
= stat_verify_regular(&st
);
59 control
= open("/dev/loop-control", O_RDWR
|O_CLOEXEC
|O_NOCTTY
|O_NONBLOCK
);
63 nr
= ioctl(control
, LOOP_CTL_GET_FREE
);
67 if (asprintf(&loopdev
, "/dev/loop%i", nr
) < 0)
70 loop
= open(loopdev
, O_CLOEXEC
|O_NONBLOCK
|O_NOCTTY
|open_flags
);
74 if (ioctl(loop
, LOOP_SET_FD
, fd
) < 0)
77 if (ioctl(loop
, LOOP_SET_STATUS64
, &info
) < 0)
80 d
= new(LoopDevice
, 1);
86 .node
= TAKE_PTR(loopdev
),
94 int loop_device_make_by_path(const char *path
, int open_flags
, LoopDevice
**ret
) {
95 _cleanup_close_
int fd
= -1;
99 assert(IN_SET(open_flags
, O_RDWR
, O_RDONLY
));
101 fd
= open(path
, O_CLOEXEC
|O_NONBLOCK
|O_NOCTTY
|open_flags
);
105 return loop_device_make(fd
, open_flags
, ret
);
108 LoopDevice
* loop_device_unref(LoopDevice
*d
) {
114 if (d
->nr
>= 0 && !d
->relinquished
) {
115 if (ioctl(d
->fd
, LOOP_CLR_FD
) < 0)
116 log_debug_errno(errno
, "Failed to clear loop device: %m");
123 if (d
->nr
>= 0 && !d
->relinquished
) {
124 _cleanup_close_
int control
= -1;
126 control
= open("/dev/loop-control", O_RDWR
|O_CLOEXEC
|O_NOCTTY
|O_NONBLOCK
);
128 log_debug_errno(errno
, "Failed to open loop control device: %m");
130 if (ioctl(control
, LOOP_CTL_REMOVE
, d
->nr
) < 0)
131 log_debug_errno(errno
, "Failed to remove loop device: %m");
139 void loop_device_relinquish(LoopDevice
*d
) {
142 /* Don't attempt to clean up the loop device anymore from this point on. Leave the clean-ing up to the kernel
143 * itself, using the loop device "auto-clear" logic we already turned on when creating the device. */
145 d
->relinquished
= true;