1:255.16-alt1
[systemd_ALT.git] / src / shutdown / detach-dm.c
blobd6bc78df418f426d5f199977d22d192f0bdcd73c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2 /***
3 Copyright © 2010 ProFUSION embedded systems
4 ***/
6 #include <linux/dm-ioctl.h>
7 #include <sys/ioctl.h>
9 #include "sd-device.h"
11 #include "alloc-util.h"
12 #include "blockdev-util.h"
13 #include "detach-dm.h"
14 #include "device-util.h"
15 #include "devnum-util.h"
16 #include "errno-util.h"
17 #include "fd-util.h"
18 #include "shutdown.h"
20 typedef struct DeviceMapper {
21 char *path;
22 dev_t devnum;
23 LIST_FIELDS(struct DeviceMapper, device_mapper);
24 } DeviceMapper;
26 static void device_mapper_free(DeviceMapper **head, DeviceMapper *m) {
27 assert(head);
28 assert(m);
30 LIST_REMOVE(device_mapper, *head, m);
32 free(m->path);
33 free(m);
36 static void device_mapper_list_free(DeviceMapper **head) {
37 assert(head);
39 while (*head)
40 device_mapper_free(head, *head);
43 static int dm_list_get(DeviceMapper **head) {
44 _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
45 int r;
47 assert(head);
49 r = sd_device_enumerator_new(&e);
50 if (r < 0)
51 return r;
53 r = sd_device_enumerator_allow_uninitialized(e);
54 if (r < 0)
55 return r;
57 r = sd_device_enumerator_add_match_subsystem(e, "block", true);
58 if (r < 0)
59 return r;
61 r = sd_device_enumerator_add_match_sysname(e, "dm-*");
62 if (r < 0)
63 return r;
65 FOREACH_DEVICE(e, d) {
66 _cleanup_free_ char *p = NULL;
67 const char *dn;
68 DeviceMapper *m;
69 dev_t devnum;
71 if (sd_device_get_devnum(d, &devnum) < 0 ||
72 sd_device_get_devname(d, &dn) < 0)
73 continue;
75 p = strdup(dn);
76 if (!p)
77 return -ENOMEM;
79 m = new(DeviceMapper, 1);
80 if (!m)
81 return -ENOMEM;
83 *m = (DeviceMapper) {
84 .path = TAKE_PTR(p),
85 .devnum = devnum,
88 LIST_PREPEND(device_mapper, *head, m);
91 return 0;
94 static int delete_dm(DeviceMapper *m) {
95 _cleanup_close_ int fd = -EBADF;
97 assert(m);
98 assert(major(m->devnum) != 0);
99 assert(m->path);
101 fd = open(m->path, O_RDONLY|O_CLOEXEC|O_NONBLOCK);
102 if (fd < 0)
103 log_debug_errno(errno, "Failed to open DM block device %s for syncing, ignoring: %m", m->path);
104 else {
105 (void) sync_with_progress(fd);
106 fd = safe_close(fd);
109 fd = open("/dev/mapper/control", O_RDWR|O_CLOEXEC);
110 if (fd < 0)
111 return log_debug_errno(errno, "Failed to open /dev/mapper/control: %m");
113 return RET_NERRNO(ioctl(fd, DM_DEV_REMOVE, &(struct dm_ioctl) {
114 .version = {
115 DM_VERSION_MAJOR,
116 DM_VERSION_MINOR,
117 DM_VERSION_PATCHLEVEL
119 .data_size = sizeof(struct dm_ioctl),
120 .dev = m->devnum,
121 }));
124 static int dm_points_list_detach(DeviceMapper **head, bool *changed, bool last_try) {
125 int n_failed = 0, r;
126 dev_t rootdev = 0, usrdev = 0;
128 assert(head);
129 assert(changed);
131 (void) get_block_device("/", &rootdev);
132 (void) get_block_device("/usr", &usrdev);
134 LIST_FOREACH(device_mapper, m, *head) {
135 if ((major(rootdev) != 0 && rootdev == m->devnum) ||
136 (major(usrdev) != 0 && usrdev == m->devnum)) {
137 log_debug("Not detaching DM %s that backs the OS itself, skipping.", m->path);
138 n_failed ++;
139 continue;
142 log_info("Detaching DM %s (" DEVNUM_FORMAT_STR ").", m->path, DEVNUM_FORMAT_VAL(m->devnum));
143 r = delete_dm(m);
144 if (r < 0) {
145 log_full_errno(last_try ? LOG_ERR : LOG_INFO, r, "Could not detach DM %s: %m", m->path);
146 n_failed++;
147 continue;
150 *changed = true;
151 device_mapper_free(head, m);
154 return n_failed;
157 int dm_detach_all(bool *changed, bool last_try) {
158 _cleanup_(device_mapper_list_free) LIST_HEAD(DeviceMapper, dm_list_head);
159 int r;
161 assert(changed);
163 LIST_HEAD_INIT(dm_list_head);
165 r = dm_list_get(&dm_list_head);
166 if (r < 0)
167 return r;
169 return dm_points_list_detach(&dm_list_head, changed, last_try);