]>
Commit | Line | Data |
---|---|---|
e7145211 | 1 | /* SPDX-License-Identifier: GPL-2.0+ */ |
81dadce5 KS |
2 | /* |
3 | * probe disks for filesystems and partitions | |
4 | * | |
810adae9 | 5 | * Copyright © 2011 Karel Zak <kzak@redhat.com> |
81dadce5 KS |
6 | */ |
7 | ||
81dadce5 KS |
8 | #include <errno.h> |
9 | #include <fcntl.h> | |
c38a141b | 10 | #include <getopt.h> |
07630cea LP |
11 | #include <stdio.h> |
12 | #include <stdlib.h> | |
81dadce5 | 13 | #include <sys/stat.h> |
81dadce5 | 14 | |
cbd353ce | 15 | #include "sd-id128.h" |
07630cea | 16 | |
b5efdb8a | 17 | #include "alloc-util.h" |
a1bb2402 | 18 | #include "blkid-util.h" |
5c614b79 | 19 | #include "device-util.h" |
0bb2f0f1 | 20 | #include "efi-loader.h" |
66855de7 | 21 | #include "errno-util.h" |
3ffd4af2 | 22 | #include "fd-util.h" |
07630cea | 23 | #include "gpt.h" |
6c1a6df3 | 24 | #include "parse-util.h" |
07630cea | 25 | #include "string-util.h" |
07a26e42 YW |
26 | #include "strxcpyx.h" |
27 | #include "udev-builtin.h" | |
81dadce5 | 28 | |
29fefe2d | 29 | static void print_property(sd_device *dev, bool test, const char *name, const char *value) { |
d13394a8 | 30 | char s[256]; |
81dadce5 | 31 | |
912541b0 | 32 | s[0] = '\0'; |
81dadce5 | 33 | |
33502ffe | 34 | if (streq(name, "TYPE")) { |
29fefe2d | 35 | udev_builtin_add_property(dev, test, "ID_FS_TYPE", value); |
81dadce5 | 36 | |
33502ffe | 37 | } else if (streq(name, "USAGE")) { |
29fefe2d | 38 | udev_builtin_add_property(dev, test, "ID_FS_USAGE", value); |
e5d8ce91 | 39 | |
33502ffe | 40 | } else if (streq(name, "VERSION")) { |
29fefe2d | 41 | udev_builtin_add_property(dev, test, "ID_FS_VERSION", value); |
81dadce5 | 42 | |
33502ffe | 43 | } else if (streq(name, "UUID")) { |
912541b0 | 44 | blkid_safe_string(value, s, sizeof(s)); |
29fefe2d | 45 | udev_builtin_add_property(dev, test, "ID_FS_UUID", s); |
912541b0 | 46 | blkid_encode_string(value, s, sizeof(s)); |
29fefe2d | 47 | udev_builtin_add_property(dev, test, "ID_FS_UUID_ENC", s); |
81dadce5 | 48 | |
33502ffe | 49 | } else if (streq(name, "UUID_SUB")) { |
912541b0 | 50 | blkid_safe_string(value, s, sizeof(s)); |
29fefe2d | 51 | udev_builtin_add_property(dev, test, "ID_FS_UUID_SUB", s); |
912541b0 | 52 | blkid_encode_string(value, s, sizeof(s)); |
29fefe2d | 53 | udev_builtin_add_property(dev, test, "ID_FS_UUID_SUB_ENC", s); |
81dadce5 | 54 | |
33502ffe | 55 | } else if (streq(name, "LABEL")) { |
912541b0 | 56 | blkid_safe_string(value, s, sizeof(s)); |
29fefe2d | 57 | udev_builtin_add_property(dev, test, "ID_FS_LABEL", s); |
912541b0 | 58 | blkid_encode_string(value, s, sizeof(s)); |
29fefe2d | 59 | udev_builtin_add_property(dev, test, "ID_FS_LABEL_ENC", s); |
81dadce5 | 60 | |
33502ffe | 61 | } else if (streq(name, "PTTYPE")) { |
29fefe2d | 62 | udev_builtin_add_property(dev, test, "ID_PART_TABLE_TYPE", value); |
81dadce5 | 63 | |
894a156d | 64 | } else if (streq(name, "PTUUID")) { |
29fefe2d | 65 | udev_builtin_add_property(dev, test, "ID_PART_TABLE_UUID", value); |
894a156d | 66 | |
33502ffe | 67 | } else if (streq(name, "PART_ENTRY_NAME")) { |
912541b0 | 68 | blkid_encode_string(value, s, sizeof(s)); |
29fefe2d | 69 | udev_builtin_add_property(dev, test, "ID_PART_ENTRY_NAME", s); |
81dadce5 | 70 | |
33502ffe | 71 | } else if (streq(name, "PART_ENTRY_TYPE")) { |
912541b0 | 72 | blkid_encode_string(value, s, sizeof(s)); |
29fefe2d | 73 | udev_builtin_add_property(dev, test, "ID_PART_ENTRY_TYPE", s); |
81dadce5 | 74 | |
33502ffe | 75 | } else if (startswith(name, "PART_ENTRY_")) { |
d5a89d7d | 76 | strscpyl(s, sizeof(s), "ID_", name, NULL); |
29fefe2d | 77 | udev_builtin_add_property(dev, test, s, value); |
ddb5bee1 ZAK |
78 | |
79 | } else if (streq(name, "SYSTEM_ID")) { | |
80 | blkid_encode_string(value, s, sizeof(s)); | |
29fefe2d | 81 | udev_builtin_add_property(dev, test, "ID_FS_SYSTEM_ID", s); |
ddb5bee1 ZAK |
82 | |
83 | } else if (streq(name, "PUBLISHER_ID")) { | |
84 | blkid_encode_string(value, s, sizeof(s)); | |
29fefe2d | 85 | udev_builtin_add_property(dev, test, "ID_FS_PUBLISHER_ID", s); |
ddb5bee1 ZAK |
86 | |
87 | } else if (streq(name, "APPLICATION_ID")) { | |
88 | blkid_encode_string(value, s, sizeof(s)); | |
29fefe2d | 89 | udev_builtin_add_property(dev, test, "ID_FS_APPLICATION_ID", s); |
ddb5bee1 ZAK |
90 | |
91 | } else if (streq(name, "BOOT_SYSTEM_ID")) { | |
92 | blkid_encode_string(value, s, sizeof(s)); | |
29fefe2d | 93 | udev_builtin_add_property(dev, test, "ID_FS_BOOT_SYSTEM_ID", s); |
912541b0 | 94 | } |
81dadce5 KS |
95 | } |
96 | ||
29fefe2d | 97 | static int find_gpt_root(sd_device *dev, blkid_probe pr, bool test) { |
cbd353ce | 98 | |
349cc4a5 | 99 | #if defined(GPT_ROOT_NATIVE) && ENABLE_EFI |
cbd353ce LP |
100 | |
101 | _cleanup_free_ char *root_id = NULL; | |
102 | bool found_esp = false; | |
103 | blkid_partlist pl; | |
104 | int i, nvals, r; | |
105 | ||
106 | assert(pr); | |
107 | ||
108 | /* Iterate through the partitions on this disk, and see if the | |
109 | * EFI ESP we booted from is on it. If so, find the first root | |
110 | * disk, and add a property indicating its partition UUID. */ | |
111 | ||
112 | errno = 0; | |
113 | pl = blkid_probe_get_partitions(pr); | |
114 | if (!pl) | |
66855de7 | 115 | return errno_or_else(ENOMEM); |
cbd353ce LP |
116 | |
117 | nvals = blkid_partlist_numof_partitions(pl); | |
118 | for (i = 0; i < nvals; i++) { | |
119 | blkid_partition pp; | |
120 | const char *stype, *sid; | |
121 | sd_id128_t type; | |
122 | ||
123 | pp = blkid_partlist_get_partition(pl, i); | |
124 | if (!pp) | |
125 | continue; | |
126 | ||
127 | sid = blkid_partition_get_uuid(pp); | |
128 | if (!sid) | |
129 | continue; | |
130 | ||
131 | stype = blkid_partition_get_type_string(pp); | |
132 | if (!stype) | |
133 | continue; | |
134 | ||
135 | if (sd_id128_from_string(stype, &type) < 0) | |
136 | continue; | |
137 | ||
138 | if (sd_id128_equal(type, GPT_ESP)) { | |
139 | sd_id128_t id, esp; | |
140 | ||
141 | /* We found an ESP, let's see if it matches | |
142 | * the ESP we booted from. */ | |
143 | ||
144 | if (sd_id128_from_string(sid, &id) < 0) | |
145 | continue; | |
146 | ||
147 | r = efi_loader_get_device_part_uuid(&esp); | |
148 | if (r < 0) | |
149 | return r; | |
150 | ||
151 | if (sd_id128_equal(id, esp)) | |
152 | found_esp = true; | |
153 | ||
154 | } else if (sd_id128_equal(type, GPT_ROOT_NATIVE)) { | |
a3071999 LP |
155 | unsigned long long flags; |
156 | ||
157 | flags = blkid_partition_get_flags(pp); | |
158 | if (flags & GPT_FLAG_NO_AUTO) | |
159 | continue; | |
cbd353ce LP |
160 | |
161 | /* We found a suitable root partition, let's | |
162 | * remember the first one. */ | |
163 | ||
164 | if (!root_id) { | |
165 | root_id = strdup(sid); | |
166 | if (!root_id) | |
167 | return -ENOMEM; | |
168 | } | |
169 | } | |
170 | } | |
171 | ||
172 | /* We found the ESP on this disk, and also found a root | |
329f7803 | 173 | * partition, nice! Let's export its UUID */ |
cbd353ce | 174 | if (found_esp && root_id) |
29fefe2d | 175 | udev_builtin_add_property(dev, test, "ID_PART_GPT_AUTO_ROOT_UUID", root_id); |
cbd353ce LP |
176 | #endif |
177 | ||
178 | return 0; | |
179 | } | |
180 | ||
9ec6e95b | 181 | static int probe_superblocks(blkid_probe pr) { |
912541b0 KS |
182 | struct stat st; |
183 | int rc; | |
81dadce5 | 184 | |
d354690e YW |
185 | /* TODO: Return negative errno. */ |
186 | ||
912541b0 | 187 | if (fstat(blkid_probe_get_fd(pr), &st)) |
dd7e1d62 | 188 | return -errno; |
81dadce5 | 189 | |
912541b0 | 190 | blkid_probe_enable_partitions(pr, 1); |
81dadce5 | 191 | |
d13394a8 LP |
192 | if (!S_ISCHR(st.st_mode) && |
193 | blkid_probe_get_size(pr) <= 1024 * 1440 && | |
912541b0 KS |
194 | blkid_probe_is_wholedisk(pr)) { |
195 | /* | |
196 | * check if the small disk is partitioned, if yes then | |
197 | * don't probe for filesystems. | |
198 | */ | |
199 | blkid_probe_enable_superblocks(pr, 0); | |
81dadce5 | 200 | |
912541b0 KS |
201 | rc = blkid_do_fullprobe(pr); |
202 | if (rc < 0) | |
d13394a8 | 203 | return rc; /* -1 = error, 1 = nothing, 0 = success */ |
81dadce5 | 204 | |
912541b0 KS |
205 | if (blkid_probe_lookup_value(pr, "PTTYPE", NULL, NULL) == 0) |
206 | return 0; /* partition table detected */ | |
207 | } | |
81dadce5 | 208 | |
912541b0 KS |
209 | blkid_probe_set_partitions_flags(pr, BLKID_PARTS_ENTRY_DETAILS); |
210 | blkid_probe_enable_superblocks(pr, 1); | |
81dadce5 | 211 | |
912541b0 | 212 | return blkid_do_safeprobe(pr); |
81dadce5 KS |
213 | } |
214 | ||
3fc2e9a2 | 215 | static int builtin_blkid(sd_device *dev, int argc, char *argv[], bool test) { |
29fefe2d | 216 | const char *devnode, *root_partition = NULL, *data, *name; |
8e766630 | 217 | _cleanup_(blkid_free_probep) blkid_probe pr = NULL; |
29fefe2d YW |
218 | bool noraid = false, is_gpt = false; |
219 | _cleanup_close_ int fd = -1; | |
220 | int64_t offset = 0; | |
221 | int nvals, i, r; | |
912541b0 KS |
222 | |
223 | static const struct option options[] = { | |
6c1a6df3 | 224 | { "offset", required_argument, NULL, 'o' }, |
912541b0 KS |
225 | { "noraid", no_argument, NULL, 'R' }, |
226 | {} | |
227 | }; | |
228 | ||
229 | for (;;) { | |
230 | int option; | |
231 | ||
6c1a6df3 | 232 | option = getopt_long(argc, argv, "o:R", options, NULL); |
912541b0 KS |
233 | if (option == -1) |
234 | break; | |
235 | ||
236 | switch (option) { | |
237 | case 'o': | |
29fefe2d YW |
238 | r = safe_atoi64(optarg, &offset); |
239 | if (r < 0) | |
5c614b79 | 240 | return log_device_error_errno(dev, r, "Failed to parse '%s' as an integer: %m", optarg); |
d354690e | 241 | if (offset < 0) |
a1193286 | 242 | return log_device_error_errno(dev, SYNTHETIC_ERRNO(ERANGE), "Invalid offset %"PRIi64": %m", offset); |
912541b0 KS |
243 | break; |
244 | case 'R': | |
245 | noraid = true; | |
246 | break; | |
247 | } | |
248 | } | |
249 | ||
d354690e | 250 | errno = 0; |
912541b0 | 251 | pr = blkid_new_probe(); |
b49d9b50 | 252 | if (!pr) |
5c614b79 | 253 | return log_device_debug_errno(dev, errno > 0 ? errno : ENOMEM, "Failed to create blkid prober: %m"); |
912541b0 KS |
254 | |
255 | blkid_probe_set_superblocks_flags(pr, | |
256 | BLKID_SUBLKS_LABEL | BLKID_SUBLKS_UUID | | |
257 | BLKID_SUBLKS_TYPE | BLKID_SUBLKS_SECTYPE | | |
1f47f550 | 258 | BLKID_SUBLKS_USAGE | BLKID_SUBLKS_VERSION); |
912541b0 KS |
259 | |
260 | if (noraid) | |
261 | blkid_probe_filter_superblocks_usage(pr, BLKID_FLTR_NOTIN, BLKID_USAGE_RAID); | |
262 | ||
29fefe2d YW |
263 | r = sd_device_get_devname(dev, &devnode); |
264 | if (r < 0) | |
5c614b79 | 265 | return log_device_debug_errno(dev, r, "Failed to get device name: %m"); |
29fefe2d | 266 | |
581e2d96 | 267 | fd = open(devnode, O_RDONLY|O_CLOEXEC|O_NONBLOCK); |
d354690e | 268 | if (fd < 0) |
5c614b79 | 269 | return log_device_debug_errno(dev, errno, "Failed to open block device %s: %m", devnode); |
912541b0 | 270 | |
d354690e | 271 | errno = 0; |
29fefe2d YW |
272 | r = blkid_probe_set_device(pr, fd, offset, 0); |
273 | if (r < 0) | |
5c614b79 | 274 | return log_device_debug_errno(dev, errno > 0 ? errno : ENOMEM, "Failed to set device to blkid prober: %m"); |
912541b0 | 275 | |
5c614b79 | 276 | log_device_debug(dev, "Probe %s with %sraid and offset=%"PRIi64, devnode, noraid ? "no" : "", offset); |
912541b0 | 277 | |
29fefe2d YW |
278 | r = probe_superblocks(pr); |
279 | if (r < 0) | |
5c614b79 | 280 | return log_device_debug_errno(dev, r, "Failed to probe superblocks: %m"); |
912541b0 | 281 | |
5c614b79 | 282 | /* If the device is a partition then its parent passed the root partition UUID to the device */ |
29fefe2d | 283 | (void) sd_device_get_property_value(dev, "ID_PART_GPT_AUTO_ROOT_UUID", &root_partition); |
329f7803 | 284 | |
5c614b79 | 285 | errno = 0; |
912541b0 | 286 | nvals = blkid_probe_numof_values(pr); |
5c614b79 YW |
287 | if (nvals < 0) |
288 | return log_device_debug_errno(dev, errno > 0 ? errno : ENOMEM, "Failed to get number of probed values: %m"); | |
289 | ||
912541b0 | 290 | for (i = 0; i < nvals; i++) { |
5c614b79 | 291 | if (blkid_probe_get_value(pr, i, &name, &data, NULL) < 0) |
912541b0 | 292 | continue; |
cbd353ce | 293 | |
8a39439e | 294 | print_property(dev, test, name, data); |
cbd353ce | 295 | |
329f7803 | 296 | /* Is this a disk with GPT partition table? */ |
cbd353ce LP |
297 | if (streq(name, "PTTYPE") && streq(data, "gpt")) |
298 | is_gpt = true; | |
329f7803 LP |
299 | |
300 | /* Is this a partition that matches the root partition | |
5c614b79 | 301 | * property inherited from the parent? */ |
329f7803 | 302 | if (root_partition && streq(name, "PART_ENTRY_UUID") && streq(data, root_partition)) |
29fefe2d | 303 | udev_builtin_add_property(dev, test, "ID_PART_GPT_AUTO_ROOT", "1"); |
912541b0 KS |
304 | } |
305 | ||
cbd353ce LP |
306 | if (is_gpt) |
307 | find_gpt_root(dev, pr, test); | |
308 | ||
d354690e | 309 | return 0; |
81dadce5 KS |
310 | } |
311 | ||
25de7aa7 | 312 | const UdevBuiltin udev_builtin_blkid = { |
912541b0 KS |
313 | .name = "blkid", |
314 | .cmd = builtin_blkid, | |
5ac0162c | 315 | .help = "Filesystem and partition probing", |
912541b0 | 316 | .run_once = true, |
81dadce5 | 317 | }; |