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