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