static void print_record(struct udev_device *device) { const char *str; int i; struct udev_list_entry *list_entry; printf("P: %s\n", udev_device_get_devpath(device)); str = udev_device_get_devnode(device); if (str != NULL) printf("N: %s\n", str + STRLEN("/dev/")); i = udev_device_get_devlink_priority(device); if (i != 0) printf("L: %i\n", i); udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(device)) printf("S: %s\n", udev_list_entry_get_name(list_entry) + STRLEN("/dev/")); udev_list_entry_foreach(list_entry, udev_device_get_properties_list_entry(device)) printf("E: %s=%s\n", udev_list_entry_get_name(list_entry), udev_list_entry_get_value(list_entry)); printf("\n"); }
int udev_node_remove(struct udev_device *dev) { struct udev *udev = udev_device_get_udev(dev); struct udev_list_entry *list_entry; const char *devnode; struct stat stats; struct udev_device *dev_check; char filename[UTIL_PATH_SIZE]; int err = 0; /* remove/update symlinks, remove symlinks from name index */ udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(dev)) link_update(dev, udev_list_entry_get_name(list_entry), 0); devnode = udev_device_get_devnode(dev); if (devnode == NULL) goto out; if (stat(devnode, &stats) != 0) { info(udev, "device node '%s' not found\n", devnode); goto out; } if (stats.st_rdev != udev_device_get_devnum(dev)) { info(udev, "device node '%s' points to a different device, skip removal\n", devnode); err = -1; goto out; } dev_check = udev_device_new_from_syspath(udev, udev_device_get_syspath(dev)); if (dev_check != NULL) { /* do not remove device node if the same sys-device is re-created in the meantime */ info(udev, "keeping device node of existing device'%s'\n", devnode); udev_device_unref(dev_check); goto out; } info(udev, "removing device node '%s'\n", devnode); err = util_unlink_secure(udev, devnode); if (err == 0) util_delete_path(udev, devnode); /* remove /dev/{block,char}/$major:$minor */ snprintf(filename, sizeof(filename), "%s/%s/%u:%u", udev_get_dev_path(udev), strcmp(udev_device_get_subsystem(dev), "block") == 0 ? "block" : "char", major(udev_device_get_devnum(dev)), minor(udev_device_get_devnum(dev))); unlink(filename); out: return err; }
void udev_node_remove(struct udev_device *dev) { struct udev_list_entry *list_entry; char filename[UTIL_PATH_SIZE]; /* remove/update symlinks, remove symlinks from name index */ udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(dev)) link_update(dev, udev_list_entry_get_name(list_entry), false); /* remove /dev/{block,char}/$major:$minor */ snprintf(filename, sizeof(filename), "/dev/%s/%u:%u", streq(udev_device_get_subsystem(dev), "block") ? "block" : "char", major(udev_device_get_devnum(dev)), minor(udev_device_get_devnum(dev))); unlink(filename); }
void udev_node_remove(struct udev_device *dev) { struct udev_list_entry *list_entry; char filename[DEV_NUM_PATH_MAX]; /* remove/update symlinks, remove symlinks from name index */ udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(dev)) link_update(dev, udev_list_entry_get_name(list_entry), false); /* remove /dev/{block,char}/$major:$minor */ xsprintf_dev_num_path(filename, streq(udev_device_get_subsystem(dev), "block") ? "block" : "char", udev_device_get_devnum(dev)); unlink(filename); }
int udev_node_remove(struct udev_device *dev) { struct udev *udev = udev_device_get_udev(dev); struct udev_list_entry *list_entry; const char *devnode; char partitionname[UTIL_PATH_SIZE]; struct stat stats; int err = 0; int num; /* remove,update symlinks, remove symlinks from name index */ udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(dev)) link_update(dev, udev_list_entry_get_name(list_entry), 0); devnode = udev_device_get_devnode(dev); if (devnode == NULL) return 0; if (stat(devnode, &stats) != 0) { info(udev, "device node '%s' not found\n", devnode); return 0; } if (stats.st_rdev != udev_device_get_devnum(dev)) { info(udev, "device node '%s' points to a different device, skip removal\n", devnode); return -1; } info(udev, "removing device node '%s'\n", devnode); err = util_unlink_secure(udev, devnode); if (err) return err; num = udev_device_get_num_fake_partitions(dev); if (num > 0) { int i; info(udev, "removing all_partitions '%s[1-%i]'\n", devnode, num); if (num > 255) return -1; for (i = 1; i <= num; i++) { snprintf(partitionname, sizeof(partitionname), "%s%d", devnode, i); partitionname[sizeof(partitionname)-1] = '\0'; util_unlink_secure(udev, partitionname); } } util_delete_path(udev, devnode); return err; }
void udev_node_remove(struct udev_device *dev) { struct udev *udev = udev_device_get_udev(dev); struct udev_list_entry *list_entry; const char *devnode; struct stat stats; struct udev_device *dev_check; char filename[UTIL_PATH_SIZE]; /* remove/update symlinks, remove symlinks from name index */ udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(dev)) link_update(dev, udev_list_entry_get_name(list_entry), 0); /* remove /dev/{block,char}/$major:$minor */ snprintf(filename, sizeof(filename), "%s/%s/%u:%u", udev_get_dev_path(udev), strcmp(udev_device_get_subsystem(dev), "block") == 0 ? "block" : "char", major(udev_device_get_devnum(dev)), minor(udev_device_get_devnum(dev))); unlink(filename); }
static void print_device(struct udev_device *device, const char *source, int prop) { struct timespec ts; assert_se(clock_gettime(CLOCK_MONOTONIC, &ts) == 0); printf("%-6s[%"PRI_TIME".%06"PRI_NSEC"] %-8s %s (%s)\n", source, ts.tv_sec, (nsec_t)ts.tv_nsec/1000, udev_device_get_action(device), udev_device_get_devpath(device), udev_device_get_subsystem(device)); if (prop) { struct udev_list_entry *list_entry; udev_list_entry_foreach(list_entry, udev_device_get_properties_list_entry(device)) printf("%s=%s\n", udev_list_entry_get_name(list_entry), udev_list_entry_get_value(list_entry)); printf("\n"); } }
static void print_device(struct udev_device *device, const char *source, int prop) { struct timespec ts; clock_gettime(CLOCK_MONOTONIC, &ts); printf("%-6s[%llu.%06u] %-8s %s (%s)\n", source, (unsigned long long) ts.tv_sec, (unsigned int) ts.tv_nsec/1000, udev_device_get_action(device), udev_device_get_devpath(device), udev_device_get_subsystem(device)); if (prop) { struct udev_list_entry *list_entry; udev_list_entry_foreach(list_entry, udev_device_get_properties_list_entry(device)) printf("%s=%s\n", udev_list_entry_get_name(list_entry), udev_list_entry_get_value(list_entry)); printf("\n"); } }
void udev_node_add(struct udev_device *dev, bool apply, mode_t mode, uid_t uid, gid_t gid) { char filename[UTIL_PATH_SIZE]; struct udev_list_entry *list_entry; log_debug("handling device node '%s', devnum=%s, mode=%#o, uid=%d, gid=%d\n", udev_device_get_devnode(dev), udev_device_get_id_filename(dev), mode, uid, gid); if (node_permissions_apply(dev, apply, mode, uid, gid) < 0) return; /* always add /dev/{block,char}/$major:$minor */ snprintf(filename, sizeof(filename), "/dev/%s/%u:%u", streq(udev_device_get_subsystem(dev), "block") ? "block" : "char", major(udev_device_get_devnum(dev)), minor(udev_device_get_devnum(dev))); node_symlink(dev, udev_device_get_devnode(dev), filename); /* create/update symlinks, add symlinks to name index */ udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(dev)) link_update(dev, udev_list_entry_get_name(list_entry), true); }
void udev_node_add(struct udev_device *dev, bool apply, mode_t mode, uid_t uid, gid_t gid, struct udev_list *seclabel_list) { char filename[DEV_NUM_PATH_MAX]; struct udev_list_entry *list_entry; log_debug("handling device node '%s', devnum=%s, mode=%#o, uid="UID_FMT", gid="GID_FMT, udev_device_get_devnode(dev), udev_device_get_id_filename(dev), mode, uid, gid); if (node_permissions_apply(dev, apply, mode, uid, gid, seclabel_list) < 0) return; /* always add /dev/{block,char}/$major:$minor */ xsprintf_dev_num_path(filename, streq(udev_device_get_subsystem(dev), "block") ? "block" : "char", udev_device_get_devnum(dev)); node_symlink(dev, udev_device_get_devnode(dev), filename); /* create/update symlinks, add symlinks to name index */ udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(dev)) link_update(dev, udev_list_entry_get_name(list_entry), true); }
static int64_t trie_store_nodes(struct trie_f *trie, struct trie_node *node) { uint64_t i; struct trie_node_f n = { .prefix_off = htole64(trie->strings_off + node->prefix_off), .children_count = node->children_count, .values_count = htole64(node->values_count), }; struct trie_child_entry_f *children = NULL; int64_t node_off; if (node->children_count) { children = new0(struct trie_child_entry_f, node->children_count); if (!children) return -ENOMEM; } /* post-order recursion */ for (i = 0; i < node->children_count; i++) { int64_t child_off; child_off = trie_store_nodes(trie, node->children[i].child); if (child_off < 0) { free(children); return child_off; } children[i].c = node->children[i].c; children[i].child_off = htole64(child_off); } /* write node */ node_off = ftello(trie->f); if (fwrite(&n, sizeof(struct trie_node_f), 1, trie->f) != 1) log_error("Failed to write sizeof struct trie_node_f to n in %s\n", "[udevadm-hwdb.c:trie_store_nodes]"); trie->nodes_count++; /* append children array */ if (node->children_count) { if (fwrite(children, sizeof(struct trie_child_entry_f), node->children_count, trie->f) != node->children_count) log_error("Failed to write children_count in %s\n", "[udevadm-hwdb.c:trie_store_nodes]"); trie->children_count += node->children_count; free(children); } /* append values array */ for (i = 0; i < node->values_count; i++) { struct trie_value_entry_f v = { .key_off = htole64(trie->strings_off + node->values[i].key_off), .value_off = htole64(trie->strings_off + node->values[i].value_off), }; if (fwrite(&v, sizeof(struct trie_value_entry_f), 1, trie->f) != 1) log_error("Failed to write sizeof trie_value_entry_f to v in %s\n", "[udevadm-hwdb.c:trie_store_nodes]"); trie->values_count++; } return node_off; } static int trie_store(struct trie *trie, const char *filename) { struct trie_f t = { .trie = trie, }; char *filename_tmp; int64_t pos; int64_t root_off; int64_t size; struct trie_header_f h = { .signature = HWDB_SIG, .tool_version = htole64(atoi(VERSION)), .header_size = htole64(sizeof(struct trie_header_f)), .node_size = htole64(sizeof(struct trie_node_f)), .child_entry_size = htole64(sizeof(struct trie_child_entry_f)), .value_entry_size = htole64(sizeof(struct trie_value_entry_f)), }; int err; /* calculate size of header, nodes, children entries, value entries */ t.strings_off = sizeof(struct trie_header_f); trie_store_nodes_size(&t, trie->root); err = fopen_temporary(filename , &t.f, &filename_tmp); if (err < 0) return err; fchmod(fileno(t.f), 0444); /* write nodes */ fseeko(t.f, sizeof(struct trie_header_f), SEEK_SET); root_off = trie_store_nodes(&t, trie->root); h.nodes_root_off = htole64(root_off); pos = ftello(t.f); h.nodes_len = htole64(pos - sizeof(struct trie_header_f)); /* write string buffer */ if (fwrite(trie->strings->buf, trie->strings->len, 1, t.f) != 1) log_error("Failed to write into trie->strings->buf in %s\n", "[udevadm-hwdb.c:trie_store]"); h.strings_len = htole64(trie->strings->len); /* write header */ size = ftello(t.f); h.file_size = htole64(size); fseeko(t.f, 0, SEEK_SET); if (fwrite(&h, sizeof(struct trie_header_f), 1, t.f) != 1) log_error("Failed to write into h in %s\n", "[udevadm-hwdb.c:trie_store]"); err = ferror(t.f); if (err) err = -errno; fclose(t.f); if (err < 0 || rename(filename_tmp, filename) < 0) { unlink(filename_tmp); goto out; } log_debug("=== trie on-disk ===\n"); log_debug("size: %8llu bytes\n", (unsigned long long)size); log_debug("header: %8zu bytes\n", sizeof(struct trie_header_f)); log_debug("nodes: %8llu bytes (%8llu)\n", (unsigned long long)t.nodes_count * sizeof(struct trie_node_f), (unsigned long long)t.nodes_count); log_debug("child pointers: %8llu bytes (%8llu)\n", (unsigned long long)t.children_count * sizeof(struct trie_child_entry_f), (unsigned long long)t.children_count); log_debug("value pointers: %8llu bytes (%8llu)\n", (unsigned long long)t.values_count * sizeof(struct trie_value_entry_f), (unsigned long long)t.values_count); log_debug("string store: %8llu bytes\n", (unsigned long long)trie->strings->len); log_debug("strings start: %8llu\n", (unsigned long long) t.strings_off); out: free(filename_tmp); return err; } static int insert_data(struct trie *trie, struct udev_list *match_list, char *line, const char *filename) { char *value; struct udev_list_entry *entry; value = strchr(line, '='); if (!value) { log_error("Error, key/value pair expected but got '%s' in '%s':\n", line, filename); return -EINVAL; } value[0] = '\0'; value++; if (line[0] == '\0' || value[0] == '\0') { log_error("Error, empty key or value '%s' in '%s':\n", line, filename); return -EINVAL; } udev_list_entry_foreach(entry, udev_list_get_entry(match_list)) trie_insert(trie, trie->root, udev_list_entry_get_name(entry), line, value); return 0; } static int import_file(struct udev *udev, struct trie *trie, const char *filename) { enum { HW_MATCH, HW_DATA, HW_NONE, } state = HW_NONE; FILE *f; char line[LINE_MAX]; struct udev_list match_list; udev_list_init(udev, &match_list, false); f = fopen(filename, "re"); if (f == NULL) return -errno; while (fgets(line, sizeof(line), f)) { size_t len; char *pos; /* comment line */ if (line[0] == '#') continue; /* strip trailing comment */ pos = strchr(line, '#'); if (pos) pos[0] = '\0'; /* strip trailing whitespace */ len = strlen(line); while (len > 0 && isspace(line[len-1])) len--; line[len] = '\0'; switch (state) { case HW_NONE: if (len == 0) break; if (line[0] == ' ') { log_error("Error, MATCH expected but got '%s' in '%s':\n", line, filename); break; } /* start of record, first match */ state = HW_MATCH; udev_list_entry_add(&match_list, line, NULL); break; case HW_MATCH: if (len == 0) { log_error("Error, DATA expected but got empty line in '%s':\n", filename); state = HW_NONE; udev_list_cleanup(&match_list); break; } /* another match */ if (line[0] != ' ') { udev_list_entry_add(&match_list, line, NULL); break; } /* first data */ state = HW_DATA; insert_data(trie, &match_list, line, filename); break; case HW_DATA: /* end of record */ if (len == 0) { state = HW_NONE; udev_list_cleanup(&match_list); break; } if (line[0] != ' ') { log_error("Error, DATA expected but got '%s' in '%s':\n", line, filename); state = HW_NONE; udev_list_cleanup(&match_list); break; } insert_data(trie, &match_list, line, filename); break; }; } fclose(f); udev_list_cleanup(&match_list); return 0; } static void help(void) { printf("Usage: udevadm hwdb OPTIONS\n" " --update update the hardware database\n" " --test=<modalias> query database and print result\n" " --root=<path> alternative root path in the filesystem\n" " --help\n\n"); }
int pa__init(pa_module *m) { struct userdata *u = NULL; pa_modargs *ma; struct udev_enumerate *enumerate = NULL; struct udev_list_entry *item = NULL, *first = NULL; int fd; bool use_tsched = true, fixed_latency_range = false, ignore_dB = false, deferred_volume = m->core->deferred_volume; bool use_ucm = true; pa_assert(m); if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { pa_log("Failed to parse module arguments"); goto fail; } m->userdata = u = pa_xnew0(struct userdata, 1); u->core = m->core; u->devices = pa_hashmap_new_full(pa_idxset_string_hash_func, pa_idxset_string_compare_func, NULL, (pa_free_cb_t) device_free); u->inotify_fd = -1; if (pa_modargs_get_value_boolean(ma, "tsched", &use_tsched) < 0) { pa_log("Failed to parse tsched= argument."); goto fail; } u->use_tsched = use_tsched; if (pa_modargs_get_value(ma, "tsched_buffer_size", NULL)) { if (pa_modargs_get_value_u32(ma, "tsched_buffer_size", &u->tsched_buffer_size) < 0) { pa_log("Failed to parse tsched_buffer_size= argument."); goto fail; } u->tsched_buffer_size_valid = true; } if (pa_modargs_get_value_boolean(ma, "fixed_latency_range", &fixed_latency_range) < 0) { pa_log("Failed to parse fixed_latency_range= argument."); goto fail; } u->fixed_latency_range = fixed_latency_range; if (pa_modargs_get_value_boolean(ma, "ignore_dB", &ignore_dB) < 0) { pa_log("Failed to parse ignore_dB= argument."); goto fail; } u->ignore_dB = ignore_dB; if (pa_modargs_get_value_boolean(ma, "deferred_volume", &deferred_volume) < 0) { pa_log("Failed to parse deferred_volume= argument."); goto fail; } u->deferred_volume = deferred_volume; if (pa_modargs_get_value_boolean(ma, "use_ucm", &use_ucm) < 0) { pa_log("Failed to parse use_ucm= argument."); goto fail; } u->use_ucm = use_ucm; if (!(u->udev = udev_new())) { pa_log("Failed to initialize udev library."); goto fail; } if (setup_inotify(u) < 0) goto fail; if (!(u->monitor = udev_monitor_new_from_netlink(u->udev, "udev"))) { pa_log("Failed to initialize monitor."); goto fail; } if (udev_monitor_filter_add_match_subsystem_devtype(u->monitor, "sound", NULL) < 0) { pa_log("Failed to subscribe to sound devices."); goto fail; } errno = 0; if (udev_monitor_enable_receiving(u->monitor) < 0) { pa_log("Failed to enable monitor: %s", pa_cstrerror(errno)); if (errno == EPERM) pa_log_info("Most likely your kernel is simply too old and " "allows only privileged processes to listen to device events. " "Please upgrade your kernel to at least 2.6.30."); goto fail; } if ((fd = udev_monitor_get_fd(u->monitor)) < 0) { pa_log("Failed to get udev monitor fd."); goto fail; } pa_assert_se(u->udev_io = u->core->mainloop->io_new(u->core->mainloop, fd, PA_IO_EVENT_INPUT, monitor_cb, u)); if (!(enumerate = udev_enumerate_new(u->udev))) { pa_log("Failed to initialize udev enumerator."); goto fail; } if (udev_enumerate_add_match_subsystem(enumerate, "sound") < 0) { pa_log("Failed to match to subsystem."); goto fail; } if (udev_enumerate_scan_devices(enumerate) < 0) { pa_log("Failed to scan for devices."); goto fail; } first = udev_enumerate_get_list_entry(enumerate); udev_list_entry_foreach(item, first) process_path(u, udev_list_entry_get_name(item)); udev_enumerate_unref(enumerate); pa_log_info("Found %u cards.", pa_hashmap_size(u->devices)); pa_modargs_free(ma); return 0; fail: if (enumerate) udev_enumerate_unref(enumerate); if (ma) pa_modargs_free(ma); pa__done(m); return -1; }
int dissect_image(int fd, const void *root_hash, size_t root_hash_size, DissectedImage **ret) { #ifdef HAVE_BLKID sd_id128_t root_uuid = SD_ID128_NULL, verity_uuid = SD_ID128_NULL; _cleanup_udev_enumerate_unref_ struct udev_enumerate *e = NULL; bool is_gpt, is_mbr, generic_rw, multiple_generic = false; _cleanup_udev_device_unref_ struct udev_device *d = NULL; _cleanup_(dissected_image_unrefp) DissectedImage *m = NULL; _cleanup_blkid_free_probe_ blkid_probe b = NULL; _cleanup_udev_unref_ struct udev *udev = NULL; _cleanup_free_ char *generic_node = NULL; const char *pttype = NULL, *usage = NULL; struct udev_list_entry *first, *item; blkid_partlist pl; int r, generic_nr; struct stat st; unsigned i; assert(fd >= 0); assert(ret); assert(root_hash || root_hash_size == 0); /* Probes a disk image, and returns information about what it found in *ret. * * Returns -ENOPKG if no suitable partition table or file system could be found. * Returns -EADDRNOTAVAIL if a root hash was specified but no matching root/verity partitions found. */ if (root_hash) { /* If a root hash is supplied, then we use the root partition that has a UUID that match the first * 128bit of the root hash. And we use the verity partition that has a UUID that match the final * 128bit. */ if (root_hash_size < sizeof(sd_id128_t)) return -EINVAL; memcpy(&root_uuid, root_hash, sizeof(sd_id128_t)); memcpy(&verity_uuid, (const uint8_t*) root_hash + root_hash_size - sizeof(sd_id128_t), sizeof(sd_id128_t)); if (sd_id128_is_null(root_uuid)) return -EINVAL; if (sd_id128_is_null(verity_uuid)) return -EINVAL; } if (fstat(fd, &st) < 0) return -errno; if (!S_ISBLK(st.st_mode)) return -ENOTBLK; b = blkid_new_probe(); if (!b) return -ENOMEM; errno = 0; r = blkid_probe_set_device(b, fd, 0, 0); if (r != 0) { if (errno == 0) return -ENOMEM; return -errno; } blkid_probe_enable_superblocks(b, 1); blkid_probe_set_superblocks_flags(b, BLKID_SUBLKS_TYPE|BLKID_SUBLKS_USAGE); blkid_probe_enable_partitions(b, 1); blkid_probe_set_partitions_flags(b, BLKID_PARTS_ENTRY_DETAILS); errno = 0; r = blkid_do_safeprobe(b); if (r == -2 || r == 1) { log_debug("Failed to identify any partition table."); return -ENOPKG; } if (r != 0) { if (errno == 0) return -EIO; return -errno; } m = new0(DissectedImage, 1); if (!m) return -ENOMEM; (void) blkid_probe_lookup_value(b, "USAGE", &usage, NULL); if (STRPTR_IN_SET(usage, "filesystem", "crypto")) { _cleanup_free_ char *t = NULL, *n = NULL; const char *fstype = NULL; /* OK, we have found a file system, that's our root partition then. */ (void) blkid_probe_lookup_value(b, "TYPE", &fstype, NULL); if (fstype) { t = strdup(fstype); if (!t) return -ENOMEM; } if (asprintf(&n, "/dev/block/%u:%u", major(st.st_rdev), minor(st.st_rdev)) < 0) return -ENOMEM; m->partitions[PARTITION_ROOT] = (DissectedPartition) { .found = true, .rw = true, .partno = -1, .architecture = _ARCHITECTURE_INVALID, .fstype = t, .node = n, }; t = n = NULL; m->encrypted = streq(fstype, "crypto_LUKS"); *ret = m; m = NULL; return 0; } (void) blkid_probe_lookup_value(b, "PTTYPE", &pttype, NULL); if (!pttype) return -ENOPKG; is_gpt = streq_ptr(pttype, "gpt"); is_mbr = streq_ptr(pttype, "dos"); if (!is_gpt && !is_mbr) return -ENOPKG; errno = 0; pl = blkid_probe_get_partitions(b); if (!pl) { if (errno == 0) return -ENOMEM; return -errno; } udev = udev_new(); if (!udev) return -errno; d = udev_device_new_from_devnum(udev, 'b', st.st_rdev); if (!d) return -ENOMEM; for (i = 0;; i++) { int n, z; if (i >= 10) { log_debug("Kernel partitions never appeared."); return -ENXIO; } e = udev_enumerate_new(udev); if (!e) return -errno; r = udev_enumerate_add_match_parent(e, d); if (r < 0) return r; r = udev_enumerate_scan_devices(e); if (r < 0) return r; /* Count the partitions enumerated by the kernel */ n = 0; first = udev_enumerate_get_list_entry(e); udev_list_entry_foreach(item, first) n++; /* Count the partitions enumerated by blkid */ z = blkid_partlist_numof_partitions(pl); if (n == z + 1) break; if (n > z + 1) { log_debug("blkid and kernel partition list do not match."); return -EIO; } if (n < z + 1) { unsigned j; /* The kernel has probed fewer partitions than blkid? Maybe the kernel prober is still running * or it got EBUSY because udev already opened the device. Let's reprobe the device, which is a * synchronous call that waits until probing is complete. */ for (j = 0; j < 20; j++) { r = ioctl(fd, BLKRRPART, 0); if (r < 0) r = -errno; if (r >= 0 || r != -EBUSY) break; /* If something else has the device open, such as an udev rule, the ioctl will return * EBUSY. Since there's no way to wait until it isn't busy anymore, let's just wait a * bit, and try again. * * This is really something they should fix in the kernel! */ usleep(50 * USEC_PER_MSEC); } if (r < 0) return r; } e = udev_enumerate_unref(e); } first = udev_enumerate_get_list_entry(e); udev_list_entry_foreach(item, first) { _cleanup_udev_device_unref_ struct udev_device *q; unsigned long long flags; blkid_partition pp; const char *node; dev_t qn; int nr; q = udev_device_new_from_syspath(udev, udev_list_entry_get_name(item)); if (!q) return -errno; qn = udev_device_get_devnum(q); if (major(qn) == 0) continue; if (st.st_rdev == qn) continue; node = udev_device_get_devnode(q); if (!node) continue; pp = blkid_partlist_devno_to_partition(pl, qn); if (!pp) continue; flags = blkid_partition_get_flags(pp); nr = blkid_partition_get_partno(pp); if (nr < 0) continue; if (is_gpt) { int designator = _PARTITION_DESIGNATOR_INVALID, architecture = _ARCHITECTURE_INVALID; const char *stype, *sid, *fstype = NULL; sd_id128_t type_id, id; bool rw = true; if (flags & GPT_FLAG_NO_AUTO) continue; sid = blkid_partition_get_uuid(pp); if (!sid) continue; if (sd_id128_from_string(sid, &id) < 0) continue; stype = blkid_partition_get_type_string(pp); if (!stype) continue; if (sd_id128_from_string(stype, &type_id) < 0) continue; if (sd_id128_equal(type_id, GPT_HOME)) { designator = PARTITION_HOME; rw = !(flags & GPT_FLAG_READ_ONLY); } else if (sd_id128_equal(type_id, GPT_SRV)) { designator = PARTITION_SRV; rw = !(flags & GPT_FLAG_READ_ONLY); } else if (sd_id128_equal(type_id, GPT_ESP)) { designator = PARTITION_ESP; fstype = "vfat"; } #ifdef GPT_ROOT_NATIVE else if (sd_id128_equal(type_id, GPT_ROOT_NATIVE)) { /* If a root ID is specified, ignore everything but the root id */ if (!sd_id128_is_null(root_uuid) && !sd_id128_equal(root_uuid, id)) continue; designator = PARTITION_ROOT; architecture = native_architecture(); rw = !(flags & GPT_FLAG_READ_ONLY); } else if (sd_id128_equal(type_id, GPT_ROOT_NATIVE_VERITY)) { m->can_verity = true; /* Ignore verity unless a root hash is specified */ if (sd_id128_is_null(verity_uuid) || !sd_id128_equal(verity_uuid, id)) continue; designator = PARTITION_ROOT_VERITY; fstype = "DM_verity_hash"; architecture = native_architecture(); rw = false; } #endif #ifdef GPT_ROOT_SECONDARY else if (sd_id128_equal(type_id, GPT_ROOT_SECONDARY)) { /* If a root ID is specified, ignore everything but the root id */ if (!sd_id128_is_null(root_uuid) && !sd_id128_equal(root_uuid, id)) continue; designator = PARTITION_ROOT_SECONDARY; architecture = SECONDARY_ARCHITECTURE; rw = !(flags & GPT_FLAG_READ_ONLY); } else if (sd_id128_equal(type_id, GPT_ROOT_SECONDARY_VERITY)) { m->can_verity = true; /* Ignore verity unless root has is specified */ if (sd_id128_is_null(verity_uuid) || !sd_id128_equal(verity_uuid, id)) continue; designator = PARTITION_ROOT_SECONDARY_VERITY; fstype = "DM_verity_hash"; architecture = SECONDARY_ARCHITECTURE; rw = false; } #endif else if (sd_id128_equal(type_id, GPT_SWAP)) { designator = PARTITION_SWAP; fstype = "swap"; } else if (sd_id128_equal(type_id, GPT_LINUX_GENERIC)) { if (generic_node) multiple_generic = true; else { generic_nr = nr; generic_rw = !(flags & GPT_FLAG_READ_ONLY); generic_node = strdup(node); if (!generic_node) return -ENOMEM; } } if (designator != _PARTITION_DESIGNATOR_INVALID) { _cleanup_free_ char *t = NULL, *n = NULL; /* First one wins */ if (m->partitions[designator].found) continue; if (fstype) { t = strdup(fstype); if (!t) return -ENOMEM; } n = strdup(node); if (!n) return -ENOMEM; m->partitions[designator] = (DissectedPartition) { .found = true, .partno = nr, .rw = rw, .architecture = architecture, .node = n, .fstype = t, }; n = t = NULL; } } else if (is_mbr) {