static int lowprobe_superblocks(blkid_probe pr) { struct stat st; int rc; if (fstat(blkid_probe_get_fd(pr), &st)) return -1; blkid_probe_enable_partitions(pr, 1); blkid_probe_set_partitions_flags(pr, BLKID_PARTS_ENTRY_DETAILS); if (!S_ISCHR(st.st_mode) && blkid_probe_get_size(pr) <= 1024 * 1440) { /* * check if the small disk is partitioned, if yes then * don't probe for filesystems. */ blkid_probe_enable_superblocks(pr, 0); rc = blkid_do_fullprobe(pr); if (rc < 0) return rc; /* -1 = error, 1 = nothing, 0 = succes */ if (blkid_probe_lookup_value(pr, "PTTYPE", NULL, NULL) == 0) return 0; /* partition table detected */ /* small whole-disk is unpartitioned, probe for filesystems only */ blkid_probe_enable_partitions(pr, 0); } blkid_probe_enable_superblocks(pr, 1); return blkid_do_safeprobe(pr); }
static int check_partition_table(const char *device) { blkid_probe pr; const char *value; int ret; pr = blkid_new_probe_from_filename(device); if (!pr) return -1; ret = blkid_probe_enable_partitions(pr, 1); if (ret < 0) goto errout; ret = blkid_probe_enable_superblocks(pr, 0); if (ret < 0) goto errout; ret = blkid_do_fullprobe(pr); if (ret < 0) goto errout; ret = blkid_probe_lookup_value(pr, "PTTYPE", &value, NULL); if (ret == 0) fprintf(stderr, _("Found a %s partition table in %s\n"), value, device); else ret = 1; errout: blkid_free_probe(pr); return ret; }
static blkid_probe new_probe(const char *devname, int mode) { blkid_probe pr; if (!devname) return NULL; if (mode) { int fd = open(devname, mode); if (fd < 0) goto error; pr = blkid_new_probe(); if (pr && blkid_probe_set_device(pr, fd, 0, 0)) goto error; } else pr = blkid_new_probe_from_filename(devname); if (!pr) goto error; blkid_probe_enable_superblocks(pr, 1); blkid_probe_set_superblocks_flags(pr, BLKID_SUBLKS_MAGIC | BLKID_SUBLKS_TYPE | BLKID_SUBLKS_USAGE | BLKID_SUBLKS_LABEL | BLKID_SUBLKS_UUID); blkid_probe_enable_partitions(pr, 1); blkid_probe_set_partitions_flags(pr, BLKID_PARTS_MAGIC); return pr; error: err(EXIT_FAILURE, _("error: %s: probing initialization failed"), devname); return NULL; }
gboolean type_by_device(const gchar* device, gchar** type) { gboolean result = false; const char *devtype = NULL; blkid_probe probe = NULL; *type = NULL; probe = blkid_new_probe_from_filename(device); if(!probe) { LOG(MOD "Probe from filename failed!\n"); return false; } if (blkid_probe_enable_partitions(probe, true) != 0) { LOG(MOD "Enable partitions failed!\n"); goto fail; } if (blkid_do_fullprobe(probe) != 0) { LOG(MOD "Fullprobe failed!\n"); goto fail; } if (blkid_probe_lookup_value(probe, "TYPE", &devtype, NULL) != 0) { LOG(MOD "Lookup value failed!\n"); goto fail; } *type = g_strdup(devtype); result = true; fail: blkid_free_probe(probe); return result; }
static int _wipe_known_signatures_with_blkid(struct device *dev, const char *name, uint32_t types_to_exclude, uint32_t types_no_prompt, int yes, force_t force, int *wiped) { blkid_probe probe = NULL; int found = 0, left = 0, wiped_tmp; int r_wipe; int r = 0; if (!wiped) wiped = &wiped_tmp; *wiped = 0; /* TODO: Should we check for valid dev - _dev_is_valid(dev)? */ if (!(probe = blkid_new_probe_from_filename(dev_name(dev)))) { log_error("Failed to create a new blkid probe for device %s.", dev_name(dev)); goto out; } blkid_probe_enable_partitions(probe, 1); blkid_probe_set_partitions_flags(probe, BLKID_PARTS_MAGIC); blkid_probe_enable_superblocks(probe, 1); blkid_probe_set_superblocks_flags(probe, BLKID_SUBLKS_LABEL | BLKID_SUBLKS_UUID | BLKID_SUBLKS_TYPE | BLKID_SUBLKS_USAGE | BLKID_SUBLKS_VERSION | BLKID_SUBLKS_MAGIC | BLKID_SUBLKS_BADCSUM); while (!blkid_do_probe(probe)) { if ((r_wipe = _blkid_wipe(probe, dev, name, types_to_exclude, types_no_prompt, yes, force)) == 1) { (*wiped)++; if (blkid_probe_step_back(probe)) { log_error("Failed to step back blkid probe to check just wiped signature."); goto out; } } /* do not count excluded types */ if (r_wipe != 2) found++; } if (!found) r = 1; left = found - *wiped; if (!left) r = 1; else log_warn("%d existing signature%s left on the device.", left, left > 1 ? "s" : ""); out: if (probe) blkid_free_probe(probe); return r; }
int main(int argc, char *argv[]) { int rc; char *devname; blkid_probe pr; blkid_topology tp; if (argc < 2) { fprintf(stderr, "usage: %s <device> " "-- checks based on libblkid for mkfs-like programs.\n", program_invocation_short_name); return EXIT_FAILURE; } devname = argv[1]; pr = blkid_new_probe_from_filename(devname); if (!pr) err(EXIT_FAILURE, "%s: faild to create a new libblkid probe", devname); /* * check Filesystems / Partitions overwrite */ /* enable partitions probing (superblocks are enabled by default) */ blkid_probe_enable_partitions(pr, TRUE); rc = blkid_do_fullprobe(pr); if (rc == -1) errx(EXIT_FAILURE, "%s: blkid_do_fullprobe() failed", devname); else if (rc == 0) { const char *type; if (!blkid_probe_lookup_value(pr, "TYPE", &type, NULL)) errx(EXIT_FAILURE, "%s: appears to contain an existing " "%s superblock", devname, type); if (!blkid_probe_lookup_value(pr, "PTTYPE", &type, NULL)) errx(EXIT_FAILURE, "%s: appears to contain an partition " "table (%s)", devname, type); } /* * get topology details */ tp = blkid_probe_get_topology(pr); if (!tp) errx(EXIT_FAILURE, "%s: failed to read topology", devname); /* ... your mkfs.<type> code or so ... off = blkid_topology_get_alignment_offset(tp); */ blkid_free_probe(pr); return EXIT_SUCCESS; }
static int lowprobe_topology(blkid_probe pr) { /* enable topology probing only */ blkid_probe_enable_topology(pr, 1); blkid_probe_enable_superblocks(pr, 0); blkid_probe_enable_partitions(pr, 0); return blkid_do_fullprobe(pr); }
static struct wipe_desc * read_offsets(struct wipe_desc *wp, const char *fname, int zap) { blkid_probe pr; int rc; if (!fname) return NULL; pr = blkid_new_probe_from_filename(fname); if (!pr) errx(EXIT_FAILURE, _("error: %s: probing initialization failed"), fname); blkid_probe_enable_superblocks(pr, 0); /* enabled by default ;-( */ blkid_probe_enable_partitions(pr, 1); rc = blkid_do_fullprobe(pr); blkid_probe_enable_partitions(pr, 0); if (rc == 0) { const char *type = NULL; blkid_probe_lookup_value(pr, "PTTYPE", &type, NULL); warnx(_("WARNING: %s: appears to contain '%s' " "partition table"), fname, type); } blkid_probe_enable_superblocks(pr, 1); blkid_probe_set_superblocks_flags(pr, BLKID_SUBLKS_MAGIC | BLKID_SUBLKS_TYPE | BLKID_SUBLKS_USAGE | BLKID_SUBLKS_LABEL | BLKID_SUBLKS_UUID); while (blkid_do_probe(pr) == 0) { wp = get_offset_from_probe(wp, pr, zap); if (!wp) break; } blkid_free_probe(pr); return wp; }
/* * This function prints a warning if the device is not wiped (e.g. wipefs(8). * Please don't call this function if there is already a PT. * * Returns: 0 if nothing found, < 0 on error, 1 if found a signature */ static int warn_wipe(struct fdisk_context *cxt) { #ifdef HAVE_LIBBLKID blkid_probe pr; #endif int rc = 0; assert(cxt); if (fdisk_dev_has_disklabel(cxt) || cxt->dev_fd < 0) return -EINVAL; #ifdef HAVE_LIBBLKID DBG(LABEL, dbgprint("wipe check: initialize libblkid prober")); pr = blkid_new_probe(); if (!pr) return -ENOMEM; rc = blkid_probe_set_device(pr, cxt->dev_fd, 0, 0); if (rc) return rc; blkid_probe_enable_superblocks(pr, 1); blkid_probe_set_superblocks_flags(pr, BLKID_SUBLKS_TYPE); blkid_probe_enable_partitions(pr, 1); /* we care about the first found FS/raid, so don't call blkid_do_probe() * in loop or don't use blkid_do_fullprobe() ... */ rc = blkid_do_probe(pr); if (rc == 0) { const char *name = NULL; if (blkid_probe_lookup_value(pr, "TYPE", &name, 0) == 0 || blkid_probe_lookup_value(pr, "PTTYPE", &name, 0) == 0) { fdisk_warnx(cxt, _( "%s: device contains a valid '%s' signature, it's " "strongly recommended to wipe the device by command wipefs(8) " "if this setup is unexpected to avoid " "possible collisions."), cxt->dev_path, name); rc = 1; } } blkid_free_probe(pr); #endif return rc; }
static lgfs2_rgrps_t rgrps_init(struct gfs2_sbd *sdp) { int ret; int error; uint64_t al_base = 0; uint64_t al_off = 0; struct stat st; blkid_probe pr = blkid_new_probe(); if (pr == NULL || blkid_probe_set_device(pr, sdp->device_fd, 0, 0) != 0 || blkid_probe_enable_superblocks(pr, TRUE) != 0 || blkid_probe_enable_partitions(pr, TRUE) != 0) { fprintf(stderr, _("Failed to create probe\n")); return NULL; } error = fstat(sdp->device_fd, &st); if (error < 0) { fprintf(stderr, _("fstat failed\n")); return NULL; } if (!S_ISREG(st.st_mode) && blkid_probe_enable_topology(pr, TRUE) != 0) { fprintf(stderr, _("Failed to create probe\n")); return NULL; } ret = blkid_do_fullprobe(pr); if (ret == 0 && !S_ISREG(st.st_mode)) { blkid_topology tp = blkid_probe_get_topology(pr); if (tp != NULL) { unsigned long min_io_sz = blkid_topology_get_minimum_io_size(tp); unsigned long opt_io_sz = blkid_topology_get_optimal_io_size(tp); unsigned long phy_sector_sz = blkid_topology_get_physical_sector_size(tp); if ((min_io_sz > phy_sector_sz) && (opt_io_sz > phy_sector_sz)) { al_base = opt_io_sz / sdp->bsize; al_off = min_io_sz / sdp->bsize; } } } blkid_free_probe(pr); return lgfs2_rgrps_init(sdp, al_base, al_off); }
/* * This function prints a warning if the device is not wiped (e.g. wipefs(8). * Please don't call this function if there is already a PT. * * Returns: 0 if nothing found, < 0 on error, 1 if found a signature */ static int check_collisions(struct fdisk_context *cxt) { #ifdef HAVE_LIBBLKID int rc = 0; blkid_probe pr; assert(cxt); assert(cxt->dev_fd >= 0); DBG(CXT, ul_debugobj(cxt, "wipe check: initialize libblkid prober")); pr = blkid_new_probe(); if (!pr) return -ENOMEM; rc = blkid_probe_set_device(pr, cxt->dev_fd, 0, 0); if (rc) return rc; blkid_probe_enable_superblocks(pr, 1); blkid_probe_set_superblocks_flags(pr, BLKID_SUBLKS_TYPE); blkid_probe_enable_partitions(pr, 1); /* we care about the first found FS/raid, so don't call blkid_do_probe() * in loop or don't use blkid_do_fullprobe() ... */ rc = blkid_do_probe(pr); if (rc == 0) { const char *name = NULL; if (blkid_probe_lookup_value(pr, "TYPE", &name, 0) == 0 || blkid_probe_lookup_value(pr, "PTTYPE", &name, 0) == 0) { cxt->collision = strdup(name); if (!cxt->collision) rc = -ENOMEM; } } blkid_free_probe(pr); return rc; #else return 0; #endif }
static blkid_probe new_probe(const char *devname, int mode) { blkid_probe pr = NULL; if (!devname) return NULL; if (mode) { int fd = open(devname, mode); if (fd < 0) goto error; pr = blkid_new_probe(); if (pr && blkid_probe_set_device(pr, fd, 0, 0)) { close(fd); goto error; } } else pr = blkid_new_probe_from_filename(devname); if (!pr) goto error; blkid_probe_enable_superblocks(pr, 1); blkid_probe_set_superblocks_flags(pr, BLKID_SUBLKS_MAGIC | /* return magic string and offset */ BLKID_SUBLKS_TYPE | /* return superblock type */ BLKID_SUBLKS_USAGE | /* return USAGE= */ BLKID_SUBLKS_LABEL | /* return LABEL= */ BLKID_SUBLKS_UUID | /* return UUID= */ BLKID_SUBLKS_BADCSUM); /* accept bad checksums */ blkid_probe_enable_partitions(pr, 1); blkid_probe_set_partitions_flags(pr, BLKID_PARTS_MAGIC); return pr; error: blkid_free_probe(pr); err(EXIT_FAILURE, _("error: %s: probing initialization failed"), devname); return NULL; }
/* returns zero when the device has NAME=value (LABEL/UUID) */ static int verify_tag(const char *devname, const char *name, const char *value) { blkid_probe pr; int fd = -1, rc = -1; size_t len; const char *data; int errsv = 0; pr = blkid_new_probe(); if (!pr) return -1; blkid_probe_enable_superblocks(pr, TRUE); blkid_probe_set_superblocks_flags(pr, BLKID_SUBLKS_LABEL | BLKID_SUBLKS_UUID); blkid_probe_enable_partitions(pr, TRUE); blkid_probe_set_partitions_flags(pr, BLKID_PARTS_ENTRY_DETAILS); fd = open(devname, O_RDONLY|O_CLOEXEC); if (fd < 0) { errsv = errno; goto done; } if (blkid_probe_set_device(pr, fd, 0, 0)) goto done; rc = blkid_do_safeprobe(pr); if (rc) goto done; rc = blkid_probe_lookup_value(pr, name, &data, &len); if (!rc) rc = memcmp(value, data, len); done: DBG(EVALUATE, ul_debug("%s: %s verification %s", devname, name, rc == 0 ? "PASS" : "FAILED")); if (fd >= 0) close(fd); blkid_free_probe(pr); /* for non-root users we use unverified udev links */ return errsv == EACCES ? 0 : rc; }
static void zap_bootbits(int fd, const char *devname, int force, int is_blkdev) { char *type = NULL; int whole = 0; int zap = 1; if (!force) { if (lseek(fd, 0, SEEK_SET) != 0) die(_("unable to rewind swap-device")); if (is_blkdev && is_whole_disk_fd(fd, devname)) { /* don't zap bootbits on whole disk -- we know nothing * about bootloaders on the device */ whole = 1; zap = 0; } else { #ifdef HAVE_LIBBLKID_INTERNAL blkid_probe pr = blkid_new_probe(); if (!pr) die(_("unable to alloc new libblkid probe")); if (blkid_probe_set_device(pr, fd, 0, 0)) die(_("unable to assign device to libblkid probe")); blkid_probe_enable_partitions(pr, 1); blkid_probe_enable_superblocks(pr, 0); if (blkid_do_fullprobe(pr) == 0) blkid_probe_lookup_value(pr, "PTTYPE", (const char **) &type, NULL); if (type) { type = strdup(type); zap = 0; } blkid_free_probe(pr); #else /* don't zap if compiled without libblkid */ zap = 0; #endif } } if (zap) { char buf[1024]; if (lseek(fd, 0, SEEK_SET) != 0) die(_("unable to rewind swap-device")); memset(buf, 0, sizeof(buf)); if (write_all(fd, buf, sizeof(buf))) die(_("unable to erase bootbits sectors")); return; } fprintf(stderr, _("%s: %s: warning: don't erase bootbits sectors\n"), program_name, devname); if (type) fprintf(stderr, _(" (%s partition table detected). "), type); else if (whole) fprintf(stderr, _(" on whole disk. ")); else fprintf(stderr, _(" (compiled without libblkid). ")); fprintf(stderr, "Use -f to force.\n"); }
static void wipe_device(int fd, const char *devname, int force) { char *type = NULL; int zap = 1; #ifdef HAVE_LIBBLKID blkid_probe pr = NULL; #endif if (!force) { if (lseek(fd, 0, SEEK_SET) != 0) errx(EXIT_FAILURE, _("unable to rewind swap-device")); #ifdef HAVE_LIBBLKID pr = new_prober(fd); blkid_probe_enable_partitions(pr, 1); blkid_probe_enable_superblocks(pr, 0); if (blkid_do_fullprobe(pr) == 0 && blkid_probe_lookup_value(pr, "PTTYPE", (const char **) &type, NULL) == 0 && type) { type = xstrdup(type); zap = 0; } #else /* don't zap if compiled without libblkid */ zap = 0; #endif } if (zap) { /* * Wipe boodbits */ char buf[1024]; const char *data = NULL; if (lseek(fd, 0, SEEK_SET) != 0) errx(EXIT_FAILURE, _("unable to rewind swap-device")); memset(buf, 0, sizeof(buf)); if (write_all(fd, buf, sizeof(buf))) errx(EXIT_FAILURE, _("unable to erase bootbits sectors")); #ifdef HAVE_LIBBLKID /* * Wipe rest of the device */ if (!pr) pr = new_prober(fd); blkid_probe_enable_superblocks(pr, 1); blkid_probe_enable_partitions(pr, 0); blkid_probe_set_superblocks_flags(pr, BLKID_SUBLKS_MAGIC|BLKID_SUBLKS_TYPE); while (blkid_do_probe(pr) == 0) { if (blkid_probe_lookup_value(pr, "TYPE", &data, NULL) == 0 && data) warnx(_("%s: warning: wiping old %s signature."), devname, data); blkid_do_wipe(pr, 0); } #endif } else { warnx(_("%s: warning: don't erase bootbits sectors"), devname); if (type) fprintf(stderr, _(" (%s partition table detected). "), type); else fprintf(stderr, _(" (compiled without libblkid). ")); fprintf(stderr, _("Use -f to force.\n")); } #ifdef HAVE_LIBBLKID blkid_free_probe(pr); #endif }
static void write_sb(char *dev, unsigned block_size, unsigned bucket_size, bool writeback, bool discard, bool wipe_bcache, unsigned cache_replacement_policy, uint64_t data_offset, uuid_t set_uuid, bool bdev) { int fd; char uuid_str[40], set_uuid_str[40], zeroes[SB_START] = {0}; struct cache_sb sb; blkid_probe pr; if ((fd = open(dev, O_RDWR|O_EXCL)) == -1) { fprintf(stderr, "Can't open dev %s: %s\n", dev, strerror(errno)); exit(EXIT_FAILURE); } if (pread(fd, &sb, sizeof(sb), SB_START) != sizeof(sb)) exit(EXIT_FAILURE); if (!memcmp(sb.magic, bcache_magic, 16) && !wipe_bcache) { fprintf(stderr, "Already a bcache device on %s, " "overwrite with --wipe-bcache\n", dev); exit(EXIT_FAILURE); } if (!(pr = blkid_new_probe())) exit(EXIT_FAILURE); if (blkid_probe_set_device(pr, fd, 0, 0)) exit(EXIT_FAILURE); /* enable ptable probing; superblock probing is enabled by default */ if (blkid_probe_enable_partitions(pr, true)) exit(EXIT_FAILURE); if (!blkid_do_probe(pr)) { /* XXX wipefs doesn't know how to remove partition tables */ fprintf(stderr, "Device %s already has a non-bcache superblock, " "remove it using wipefs and wipefs -a\n", dev); exit(EXIT_FAILURE); } memset(&sb, 0, sizeof(struct cache_sb)); sb.offset = SB_SECTOR; sb.version = bdev ? BCACHE_SB_VERSION_BDEV : BCACHE_SB_VERSION_CDEV; memcpy(sb.magic, bcache_magic, 16); uuid_generate(sb.uuid); memcpy(sb.set_uuid, set_uuid, sizeof(sb.set_uuid)); sb.bucket_size = bucket_size; sb.block_size = block_size; uuid_unparse(sb.uuid, uuid_str); uuid_unparse(sb.set_uuid, set_uuid_str); if (SB_IS_BDEV(&sb)) { SET_BDEV_CACHE_MODE( &sb, writeback ? CACHE_MODE_WRITEBACK : CACHE_MODE_WRITETHROUGH); if (data_offset != BDEV_DATA_START_DEFAULT) { sb.version = BCACHE_SB_VERSION_BDEV_WITH_OFFSET; sb.data_offset = data_offset; } printf("UUID: %s\n" "Set UUID: %s\n" "version: %u\n" "block_size: %u\n" "data_offset: %ju\n", uuid_str, set_uuid_str, (unsigned) sb.version, sb.block_size, data_offset); } else { sb.nbuckets = getblocks(fd) / sb.bucket_size; sb.nr_in_set = 1; sb.first_bucket = (23 / sb.bucket_size) + 1; if (sb.nbuckets < 1 << 7) { fprintf(stderr, "Not enough buckets: %ju, need %u\n", sb.nbuckets, 1 << 7); exit(EXIT_FAILURE); } SET_CACHE_DISCARD(&sb, discard); SET_CACHE_REPLACEMENT(&sb, cache_replacement_policy); printf("UUID: %s\n" "Set UUID: %s\n" "version: %u\n" "nbuckets: %ju\n" "block_size: %u\n" "bucket_size: %u\n" "nr_in_set: %u\n" "nr_this_dev: %u\n" "first_bucket: %u\n", uuid_str, set_uuid_str, (unsigned) sb.version, sb.nbuckets, sb.block_size, sb.bucket_size, sb.nr_in_set, sb.nr_this_dev, sb.first_bucket); } sb.csum = csum_set(&sb); /* Zero start of disk */ if (pwrite(fd, zeroes, SB_START, 0) != SB_START) { perror("write error\n"); exit(EXIT_FAILURE); } /* Write superblock */ if (pwrite(fd, &sb, sizeof(sb), SB_START) != sizeof(sb)) { perror("write error\n"); exit(EXIT_FAILURE); } fsync(fd); close(fd); }
int main(int argc, char **argv) { bool udev = false; int i, o; extern char *optarg; struct cache_sb sb; char uuid[40]; blkid_probe pr; while ((o = getopt(argc, argv, "o:")) != EOF) switch (o) { case 'o': if (strcmp("udev", optarg)) { printf("Invalid output format %s\n", optarg); exit(EXIT_FAILURE); } udev = true; break; } argv += optind; argc -= optind; for (i = 0; i < argc; i++) { int fd = open(argv[i], O_RDONLY); if (fd == -1) continue; if (!(pr = blkid_new_probe())) continue; if (blkid_probe_set_device(pr, fd, 0, 0)) continue; /* probe partitions too */ if (blkid_probe_enable_partitions(pr, true)) continue; /* bail if anything was found * probe-bcache isn't needed once blkid recognizes bcache */ if (!blkid_do_probe(pr)) { continue; } if (pread(fd, &sb, sizeof(sb), SB_START) != sizeof(sb)) continue; if (memcmp(sb.magic, bcache_magic, 16)) continue; uuid_unparse(sb.uuid, uuid); if (udev) printf("ID_FS_UUID=%s\n" "ID_FS_UUID_ENC=%s\n" "ID_FS_TYPE=bcache\n", uuid, uuid); else printf("%s: UUID=\"\" TYPE=\"bcache\"\n", uuid); } return 0; }
static int enumerate_partitions(dev_t devnum) { _cleanup_udev_enumerate_unref_ struct udev_enumerate *e = NULL; _cleanup_udev_device_unref_ struct udev_device *d = NULL; _cleanup_blkid_free_probe_ blkid_probe b = NULL; _cleanup_udev_unref_ struct udev *udev = NULL; _cleanup_free_ char *home = NULL, *srv = NULL; struct udev_list_entry *first, *item; struct udev_device *parent = NULL; const char *node, *pttype, *devtype; int home_nr = -1, srv_nr = -1; blkid_partlist pl; int r, k; dev_t pn; udev = udev_new(); if (!udev) return log_oom(); d = udev_device_new_from_devnum(udev, 'b', devnum); if (!d) return log_oom(); parent = udev_device_get_parent(d); if (!parent) return log_oom(); /* Does it have a devtype? */ devtype = udev_device_get_devtype(parent); if (!devtype) return 0; /* Is this a disk or a partition? We only care for disks... */ if (!streq(devtype, "disk")) return 0; /* Does it have a device node? */ node = udev_device_get_devnode(parent); if (!node) return 0; log_debug("Root device %s.", node); pn = udev_device_get_devnum(parent); if (major(pn) == 0) return 0; errno = 0; b = blkid_new_probe_from_filename(node); if (!b) { if (errno == 0) return log_oom(); log_error("Failed allocate prober: %m"); return -errno; } blkid_probe_enable_superblocks(b, 1); blkid_probe_set_superblocks_flags(b, BLKID_SUBLKS_TYPE); 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) /* no result or uncertain */ return 0; else if (r != 0) { if (errno == 0) errno = EIO; log_error("Failed to probe %s: %m", node); return -errno; } errno = 0; r = blkid_probe_lookup_value(b, "PTTYPE", &pttype, NULL); if (r != 0) { if (errno == 0) errno = EIO; log_error("Failed to determine partition table type of %s: %m", node); return -errno; } /* We only do this all for GPT... */ if (!streq_ptr(pttype, "gpt")) return 0; errno = 0; pl = blkid_probe_get_partitions(b); if (!pl) { if (errno == 0) return log_oom(); log_error("Failed to list partitions of %s: %m", node); return -errno; } e = udev_enumerate_new(udev); if (!e) return log_oom(); r = udev_enumerate_add_match_parent(e, parent); if (r < 0) return log_oom(); r = udev_enumerate_add_match_subsystem(e, "block"); if (r < 0) return log_oom(); r = udev_enumerate_scan_devices(e); if (r < 0) { log_error("Failed to enumerate partitions on %s: %s", node, strerror(-r)); return r; } first = udev_enumerate_get_list_entry(e); udev_list_entry_foreach(item, first) { _cleanup_udev_device_unref_ struct udev_device *q; const char *stype, *subnode; sd_id128_t type_id; blkid_partition pp; dev_t qn; int nr; q = udev_device_new_from_syspath(udev, udev_list_entry_get_name(item)); if (!q) continue; qn = udev_device_get_devnum(q); if (major(qn) == 0) continue; if (qn == devnum) continue; if (qn == pn) continue; subnode = udev_device_get_devnode(q); if (!subnode) continue; pp = blkid_partlist_devno_to_partition(pl, qn); if (!pp) continue; nr = blkid_partition_get_partno(pp); if (nr < 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_SWAP)) { k = add_swap(subnode); if (k < 0) r = k; } else if (sd_id128_equal(type_id, GPT_HOME)) { /* We only care for the first /home partition */ if (home && nr >= home_nr) continue; home_nr = nr; free(home); home = strdup(subnode); if (!home) return log_oom(); } else if (sd_id128_equal(type_id, GPT_SRV)) { /* We only care for the first /srv partition */ if (srv && nr >= srv_nr) continue; srv_nr = nr; free(srv); srv = strdup(node); if (!srv) return log_oom(); } }
static int verify_esp(const char *p, uint32_t *part, uint64_t *pstart, uint64_t *psize, sd_id128_t *uuid) { struct statfs sfs; struct stat st, st2; _cleanup_free_ char *t = NULL; _cleanup_blkid_free_probe_ blkid_probe b = NULL; int r; const char *v, *t2; if (statfs(p, &sfs) < 0) return log_error_errno(errno, "Failed to check file system type of \"%s\": %m", p); if (sfs.f_type != 0x4d44) { log_error("File system \"%s\" is not a FAT EFI System Partition (ESP) file system.", p); return -ENODEV; } if (stat(p, &st) < 0) return log_error_errno(errno, "Failed to determine block device node of \"%s\": %m", p); if (major(st.st_dev) == 0) { log_error("Block device node of %p is invalid.", p); return -ENODEV; } t2 = strjoina(p, "/.."); r = stat(t2, &st2); if (r < 0) return log_error_errno(errno, "Failed to determine block device node of parent of \"%s\": %m", p); if (st.st_dev == st2.st_dev) { log_error("Directory \"%s\" is not the root of the EFI System Partition (ESP) file system.", p); return -ENODEV; } r = asprintf(&t, "/dev/block/%u:%u", major(st.st_dev), minor(st.st_dev)); if (r < 0) return log_oom(); errno = 0; b = blkid_new_probe_from_filename(t); if (!b) { if (errno == 0) return log_oom(); return log_error_errno(errno, "Failed to open file system \"%s\": %m", p); } blkid_probe_enable_superblocks(b, 1); blkid_probe_set_superblocks_flags(b, BLKID_SUBLKS_TYPE); 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) { log_error("File system \"%s\" is ambiguous.", p); return -ENODEV; } else if (r == 1) { log_error("File system \"%s\" does not contain a label.", p); return -ENODEV; } else if (r != 0) { r = errno ? -errno : -EIO; return log_error_errno(r, "Failed to probe file system \"%s\": %m", p); } errno = 0; r = blkid_probe_lookup_value(b, "TYPE", &v, NULL); if (r != 0) { r = errno ? -errno : -EIO; return log_error_errno(r, "Failed to probe file system type \"%s\": %m", p); } if (!streq(v, "vfat")) { log_error("File system \"%s\" is not FAT.", p); return -ENODEV; } errno = 0; r = blkid_probe_lookup_value(b, "PART_ENTRY_SCHEME", &v, NULL); if (r != 0) { r = errno ? -errno : -EIO; return log_error_errno(r, "Failed to probe partition scheme \"%s\": %m", p); } if (!streq(v, "gpt")) { log_error("File system \"%s\" is not on a GPT partition table.", p); return -ENODEV; } errno = 0; r = blkid_probe_lookup_value(b, "PART_ENTRY_TYPE", &v, NULL); if (r != 0) { r = errno ? -errno : -EIO; return log_error_errno(r, "Failed to probe partition type UUID \"%s\": %m", p); } if (!streq(v, "c12a7328-f81f-11d2-ba4b-00a0c93ec93b")) { log_error("File system \"%s\" has wrong type for an EFI System Partition (ESP).", p); return -ENODEV; } errno = 0; r = blkid_probe_lookup_value(b, "PART_ENTRY_UUID", &v, NULL); if (r != 0) { r = errno ? -errno : -EIO; return log_error_errno(r, "Failed to probe partition entry UUID \"%s\": %m", p); } r = sd_id128_from_string(v, uuid); if (r < 0) { log_error("Partition \"%s\" has invalid UUID \"%s\".", p, v); return -EIO; } errno = 0; r = blkid_probe_lookup_value(b, "PART_ENTRY_NUMBER", &v, NULL); if (r != 0) { r = errno ? -errno : -EIO; return log_error_errno(r, "Failed to probe partition number \"%s\": m", p); } *part = strtoul(v, NULL, 10); errno = 0; r = blkid_probe_lookup_value(b, "PART_ENTRY_OFFSET", &v, NULL); if (r != 0) { r = errno ? -errno : -EIO; return log_error_errno(r, "Failed to probe partition offset \"%s\": %m", p); } *pstart = strtoul(v, NULL, 10); errno = 0; r = blkid_probe_lookup_value(b, "PART_ENTRY_SIZE", &v, NULL); if (r != 0) { r = errno ? -errno : -EIO; return log_error_errno(r, "Failed to probe partition size \"%s\": %m", p); } *psize = strtoul(v, NULL, 10); return 0; }
static int enumerate_partitions(dev_t devnum) { _cleanup_udev_enumerate_unref_ struct udev_enumerate *e = NULL; _cleanup_udev_device_unref_ struct udev_device *d = NULL; _cleanup_blkid_free_probe_ blkid_probe b = NULL; _cleanup_udev_unref_ struct udev *udev = NULL; _cleanup_free_ char *boot = NULL, *home = NULL, *srv = NULL; struct udev_list_entry *first, *item; struct udev_device *parent = NULL; const char *name, *node, *pttype, *devtype; int boot_nr = -1, home_nr = -1, srv_nr = -1; bool home_rw = true, srv_rw = true; blkid_partlist pl; int r, k; dev_t pn; udev = udev_new(); if (!udev) return log_oom(); d = udev_device_new_from_devnum(udev, 'b', devnum); if (!d) return log_oom(); name = udev_device_get_devnode(d); if (!name) name = udev_device_get_syspath(d); if (!name) { log_debug("Device %u:%u does not have a name, ignoring.", major(devnum), minor(devnum)); return 0; } parent = udev_device_get_parent(d); if (!parent) { log_debug("%s: not a partitioned device, ignoring.", name); return 0; } /* Does it have a devtype? */ devtype = udev_device_get_devtype(parent); if (!devtype) { log_debug("%s: parent doesn't have a device type, ignoring.", name); return 0; } /* Is this a disk or a partition? We only care for disks... */ if (!streq(devtype, "disk")) { log_debug("%s: parent isn't a raw disk, ignoring.", name); return 0; } /* Does it have a device node? */ node = udev_device_get_devnode(parent); if (!node) { log_debug("%s: parent device does not have device node, ignoring.", name); return 0; } log_debug("%s: root device %s.", name, node); pn = udev_device_get_devnum(parent); if (major(pn) == 0) return 0; errno = 0; b = blkid_new_probe_from_filename(node); if (!b) { if (errno == 0) return log_oom(); return log_error_errno(errno, "%s: failed to allocate prober: %m", node); } 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 == 1) return 0; /* no results */ else if (r == -2) { log_warning("%s: probe gave ambiguous results, ignoring", node); return 0; } else if (r != 0) return log_error_errno(errno ?: EIO, "%s: failed to probe: %m", node); errno = 0; r = blkid_probe_lookup_value(b, "PTTYPE", &pttype, NULL); if (r != 0) return log_error_errno(errno ?: EIO, "%s: failed to determine partition table type: %m", node); /* We only do this all for GPT... */ if (!streq_ptr(pttype, "gpt")) { log_debug("%s: not a GPT partition table, ignoring.", node); return 0; } errno = 0; pl = blkid_probe_get_partitions(b); if (!pl) { if (errno == 0) return log_oom(); return log_error_errno(errno, "%s: failed to list partitions: %m", node); } e = udev_enumerate_new(udev); if (!e) return log_oom(); r = udev_enumerate_add_match_parent(e, parent); if (r < 0) return log_oom(); r = udev_enumerate_add_match_subsystem(e, "block"); if (r < 0) return log_oom(); r = udev_enumerate_scan_devices(e); if (r < 0) return log_error_errno(r, "%s: failed to enumerate partitions: %m", node); 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; const char *stype, *subnode; sd_id128_t type_id; blkid_partition pp; dev_t qn; int nr; q = udev_device_new_from_syspath(udev, udev_list_entry_get_name(item)); if (!q) continue; qn = udev_device_get_devnum(q); if (major(qn) == 0) continue; if (qn == devnum) continue; if (qn == pn) continue; subnode = udev_device_get_devnode(q); if (!subnode) continue; pp = blkid_partlist_devno_to_partition(pl, qn); if (!pp) continue; nr = blkid_partition_get_partno(pp); if (nr < 0) continue; stype = blkid_partition_get_type_string(pp); if (!stype) continue; if (sd_id128_from_string(stype, &type_id) < 0) continue; flags = blkid_partition_get_flags(pp); if (sd_id128_equal(type_id, GPT_SWAP)) { if (flags & GPT_FLAG_NO_AUTO) continue; if (flags & GPT_FLAG_READ_ONLY) { log_debug("%s marked as read-only swap partition, which is bogus. Ignoring.", subnode); continue; } k = add_swap(subnode); if (k < 0) r = k; } else if (sd_id128_equal(type_id, GPT_ESP)) { /* We only care for the first /boot partition */ if (boot && nr >= boot_nr) continue; /* Note that we do not honour the "no-auto" * flag for the ESP, as it is often unset, to * hide it from Windows. */ boot_nr = nr; r = free_and_strdup(&boot, subnode); if (r < 0) return log_oom(); } else if (sd_id128_equal(type_id, GPT_HOME)) { if (flags & GPT_FLAG_NO_AUTO) continue; /* We only care for the first /home partition */ if (home && nr >= home_nr) continue; home_nr = nr; home_rw = !(flags & GPT_FLAG_READ_ONLY), r = free_and_strdup(&home, subnode); if (r < 0) return log_oom(); } else if (sd_id128_equal(type_id, GPT_SRV)) { if (flags & GPT_FLAG_NO_AUTO) continue; /* We only care for the first /srv partition */ if (srv && nr >= srv_nr) continue; srv_nr = nr; srv_rw = !(flags & GPT_FLAG_READ_ONLY), r = free_and_strdup(&srv, subnode); if (r < 0) return log_oom(); } }
static int lowprobe_device(blkid_probe pr, const char *devname, char *show[], int output, blkid_loff_t offset, blkid_loff_t size) { const char *data; const char *name; int nvals = 0, n, num = 1; size_t len; int fd; int rc = 0; struct stat st; fd = open(devname, O_RDONLY); if (fd < 0) { fprintf(stderr, "error: %s: %s\n", devname, strerror(errno)); return 2; } if (blkid_probe_set_device(pr, fd, offset, size)) goto done; if (fstat(fd, &st)) goto done; /* * partitions probing */ blkid_probe_enable_superblocks(pr, 0); /* enabled by default ;-( */ blkid_probe_enable_partitions(pr, 1); rc = blkid_do_fullprobe(pr); blkid_probe_enable_partitions(pr, 0); if (rc < 0) goto done; /* -1 = error, 1 = nothing, 0 = succes */ /* * Don't probe for FS/RAIDs on small devices */ if (rc || S_ISCHR(st.st_mode) || blkid_probe_get_size(pr) > 1024 * 1440) { /* * filesystems/RAIDs probing */ blkid_probe_enable_superblocks(pr, 1); rc = blkid_do_safeprobe(pr); if (rc < 0) goto done; } nvals = blkid_probe_numof_values(pr); if (output & OUTPUT_DEVICE_ONLY) { printf("%s\n", devname); goto done; } for (n = 0; n < nvals; n++) { if (blkid_probe_get_value(pr, n, &name, &data, &len)) continue; if (show[0] && !has_item(show, name)) continue; len = strnlen((char *) data, len); print_value(output, num++, devname, (char *) data, name, len); } if (nvals >= 1 && !(output & (OUTPUT_VALUE_ONLY | OUTPUT_UDEV_LIST))) printf("\n"); done: if (rc == -2) { if (output & OUTPUT_UDEV_LIST) print_udev_ambivalent(pr); else fprintf(stderr, "%s: ambivalent result (probably more " "filesystems on the device, use wipefs(8) " "to see more details)\n", devname); } close(fd); return !nvals ? 2 : 0; }
/* * Verify that the data in dev is consistent with what is on the actual * block device (using the devname field only). Normally this will be * called when finding items in the cache, but for long running processes * is also desirable to revalidate an item before use. * * If we are unable to revalidate the data, we return the old data and * do not set the BLKID_BID_FL_VERIFIED flag on it. */ blkid_dev blkid_verify(blkid_cache cache, blkid_dev dev) { struct stat st; time_t diff, now; char *fltr[2]; int fd; if (!dev) return NULL; now = time(0); diff = now - dev->bid_time; if (stat(dev->bid_name, &st) < 0) { DBG(DEBUG_PROBE, printf("blkid_verify: error %m (%d) while " "trying to stat %s\n", errno, dev->bid_name)); open_err: if ((errno == EPERM) || (errno == EACCES) || (errno == ENOENT)) { /* We don't have read permission, just return cache data. */ DBG(DEBUG_PROBE, printf("returning unverified data for %s\n", dev->bid_name)); return dev; } blkid_free_dev(dev); return NULL; } if (now >= dev->bid_time && #ifdef HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC (st.st_mtime < dev->bid_time || (st.st_mtime == dev->bid_time && st.st_mtim.tv_nsec / 1000 <= dev->bid_utime)) && #else st.st_mtime <= dev->bid_time && #endif (diff < BLKID_PROBE_MIN || (dev->bid_flags & BLKID_BID_FL_VERIFIED && diff < BLKID_PROBE_INTERVAL))) return dev; #ifndef HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC DBG(DEBUG_PROBE, printf("need to revalidate %s (cache time %lu, stat time %lu,\n\t" "time since last check %lu)\n", dev->bid_name, (unsigned long)dev->bid_time, (unsigned long)st.st_mtime, (unsigned long)diff)); #else DBG(DEBUG_PROBE, printf("need to revalidate %s (cache time %lu.%lu, stat time %lu.%lu,\n\t" "time since last check %lu)\n", dev->bid_name, (unsigned long)dev->bid_time, (unsigned long)dev->bid_utime, (unsigned long)st.st_mtime, (unsigned long)st.st_mtim.tv_nsec / 1000, (unsigned long)diff)); #endif if (!cache->probe) { cache->probe = blkid_new_probe(); if (!cache->probe) { blkid_free_dev(dev); return NULL; } } fd = open(dev->bid_name, O_RDONLY|O_CLOEXEC); if (fd < 0) { DBG(DEBUG_PROBE, printf("blkid_verify: error %m (%d) while " "opening %s\n", errno, dev->bid_name)); goto open_err; } if (blkid_probe_set_device(cache->probe, fd, 0, 0)) { /* failed to read the device */ close(fd); blkid_free_dev(dev); return NULL; } blkid_probe_enable_superblocks(cache->probe, TRUE); blkid_probe_set_superblocks_flags(cache->probe, BLKID_SUBLKS_LABEL | BLKID_SUBLKS_UUID | BLKID_SUBLKS_TYPE | BLKID_SUBLKS_SECTYPE); blkid_probe_enable_partitions(cache->probe, TRUE); blkid_probe_set_partitions_flags(cache->probe, BLKID_PARTS_ENTRY_DETAILS); /* * If we already know the type, then try that first. */ if (dev->bid_type) { blkid_tag_iterate iter; const char *type, *value; fltr[0] = dev->bid_type; fltr[1] = NULL; blkid_probe_filter_superblocks_type(cache->probe, BLKID_FLTR_ONLYIN, fltr); if (!blkid_do_probe(cache->probe)) goto found_type; blkid_probe_invert_superblocks_filter(cache->probe); /* * Zap the device filesystem information and try again */ DBG(DEBUG_PROBE, printf("previous fs type %s not valid, " "trying full probe\n", dev->bid_type)); iter = blkid_tag_iterate_begin(dev); while (blkid_tag_next(iter, &type, &value) == 0) blkid_set_tag(dev, type, 0, 0); blkid_tag_iterate_end(iter); } /* * Probe for all types. */ if (blkid_do_safeprobe(cache->probe)) { /* found nothing or error */ blkid_free_dev(dev); dev = NULL; } found_type: if (dev) { #ifdef HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC struct timeval tv; if (!gettimeofday(&tv, NULL)) { dev->bid_time = tv.tv_sec; dev->bid_utime = tv.tv_usec; } else #endif dev->bid_time = time(0); dev->bid_devno = st.st_rdev; dev->bid_flags |= BLKID_BID_FL_VERIFIED; cache->bic_flags |= BLKID_BIC_FL_CHANGED; blkid_probe_to_tags(cache->probe, dev); DBG(DEBUG_PROBE, printf("%s: devno 0x%04llx, type %s\n", dev->bid_name, (long long)st.st_rdev, dev->bid_type)); } blkid_reset_probe(cache->probe); blkid_probe_reset_superblocks_filter(cache->probe); close(fd); return dev; }
static int verify_esp(const char *p, uint32_t *part, uint64_t *pstart, uint64_t *psize, sd_id128_t *uuid) { struct statfs sfs; struct stat st, st2; char *t; blkid_probe b = NULL; int r; const char *v; if (statfs(p, &sfs) < 0) { fprintf(stderr, "Failed to check file system type of %s: %m\n", p); return -errno; } if (sfs.f_type != 0x4d44) { fprintf(stderr, "File system %s is not a FAT EFI System Partition (ESP) file system.\n", p); return -ENODEV; } if (stat(p, &st) < 0) { fprintf(stderr, "Failed to determine block device node of %s: %m\n", p); return -errno; } if (major(st.st_dev) == 0) { fprintf(stderr, "Block device node of %p is invalid.\n", p); return -ENODEV; } r = asprintf(&t, "%s/..", p); if (r < 0) { fprintf(stderr, "Out of memory.\n"); return -ENOMEM; } r = stat(t, &st2); free(t); if (r < 0) { fprintf(stderr, "Failed to determine block device node of parent of %s: %m\n", p); return -errno; } if (st.st_dev == st2.st_dev) { fprintf(stderr, "Directory %s is not the root of the EFI System Partition (ESP) file system.\n", p); return -ENODEV; } r = asprintf(&t, "/dev/block/%u:%u", major(st.st_dev), minor(st.st_dev)); if (r < 0) { fprintf(stderr, "Out of memory.\n"); return -ENOMEM; } errno = 0; b = blkid_new_probe_from_filename(t); free(t); if (!b) { if (errno != 0) { fprintf(stderr, "Failed to open file system %s: %m\n", p); return -errno; } fprintf(stderr, "Out of memory.\n"); return -ENOMEM; } blkid_probe_enable_superblocks(b, 1); blkid_probe_set_superblocks_flags(b, BLKID_SUBLKS_TYPE); 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) { fprintf(stderr, "File system %s is ambigious.\n", p); r = -ENODEV; goto fail; } else if (r == 1) { fprintf(stderr, "File system %s does not contain a label.\n", p); r = -ENODEV; goto fail; } else if (r != 0) { r = errno ? -errno : -EIO; fprintf(stderr, "Failed to probe file system %s: %s\n", p, strerror(-r)); goto fail; } errno = 0; r = blkid_probe_lookup_value(b, "TYPE", &v, NULL); if (r != 0) { r = errno ? -errno : -EIO; fprintf(stderr, "Failed to probe file system type %s: %s\n", p, strerror(-r)); goto fail; } if (strcmp(v, "vfat") != 0) { fprintf(stderr, "File system %s is not a FAT EFI System Partition (ESP) file system after all.\n", p); r = -ENODEV; goto fail; } errno = 0; r = blkid_probe_lookup_value(b, "PART_ENTRY_SCHEME", &v, NULL); if (r != 0) { r = errno ? -errno : -EIO; fprintf(stderr, "Failed to probe partition scheme %s: %s\n", p, strerror(-r)); goto fail; } if (strcmp(v, "gpt") != 0) { fprintf(stderr, "File system %s is not on a GPT partition table.\n", p); r = -ENODEV; goto fail; } errno = 0; r = blkid_probe_lookup_value(b, "PART_ENTRY_TYPE", &v, NULL); if (r != 0) { r = errno ? -errno : -EIO; fprintf(stderr, "Failed to probe partition type UUID %s: %s\n", p, strerror(-r)); goto fail; } if (strcmp(v, "c12a7328-f81f-11d2-ba4b-00a0c93ec93b") != 0) { r = -ENODEV; fprintf(stderr, "File system %s is not an EFI System Partition (ESP).\n", p); goto fail; } errno = 0; r = blkid_probe_lookup_value(b, "PART_ENTRY_UUID", &v, NULL); if (r != 0) { r = errno ? -errno : -EIO; fprintf(stderr, "Failed to probe partition entry UUID %s: %s\n", p, strerror(-r)); goto fail; } r = sd_id128_from_string(v, uuid); if (r < 0) { fprintf(stderr, "Partition %s has invalid UUID: %s\n", p, v); r = -EIO; goto fail; } errno = 0; r = blkid_probe_lookup_value(b, "PART_ENTRY_NUMBER", &v, NULL); if (r != 0) { r = errno ? -errno : -EIO; fprintf(stderr, "Failed to probe partition number %s: %s\n", p, strerror(-r)); goto fail; } *part = strtoul(v, NULL, 10); errno = 0; r = blkid_probe_lookup_value(b, "PART_ENTRY_OFFSET", &v, NULL); if (r != 0) { r = errno ? -errno : -EIO; fprintf(stderr, "Failed to probe partition offset %s: %s\n", p, strerror(-r)); goto fail; } *pstart = strtoul(v, NULL, 10); errno = 0; r = blkid_probe_lookup_value(b, "PART_ENTRY_SIZE", &v, NULL); if (r != 0) { r = errno ? -errno : -EIO; fprintf(stderr, "Failed to probe partition size %s: %s\n", p, strerror(-r)); goto fail; } *psize = strtoul(v, NULL, 10); blkid_free_probe(b); return 0; fail: if (b) blkid_free_probe(b); return r; }
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) {
/** * mnt_cache_read_tags * @cache: pointer to struct libmnt_cache instance * @devname: path device * * Reads @devname LABEL and UUID to the @cache. * * Returns: 0 if at least one tag was added, 1 if no tag was added or * negative number in case of error. */ int mnt_cache_read_tags(struct libmnt_cache *cache, const char *devname) { blkid_probe pr; size_t i, ntags = 0; int rc; const char *tags[] = { "LABEL", "UUID", "TYPE", "PARTUUID", "PARTLABEL" }; const char *blktags[] = { "LABEL", "UUID", "TYPE", "PART_ENTRY_UUID", "PART_ENTRY_NAME" }; if (!cache || !devname) return -EINVAL; DBG(CACHE, ul_debugobj(cache, "tags for %s requested", devname)); /* check if device is already cached */ for (i = 0; i < cache->nents; i++) { struct mnt_cache_entry *e = &cache->ents[i]; if (!(e->flag & MNT_CACHE_TAGREAD)) continue; if (strcmp(e->value, devname) == 0) /* tags have already been read */ return 0; } pr = blkid_new_probe_from_filename(devname); if (!pr) return -1; blkid_probe_enable_superblocks(pr, 1); blkid_probe_set_superblocks_flags(pr, BLKID_SUBLKS_LABEL | BLKID_SUBLKS_UUID | BLKID_SUBLKS_TYPE); blkid_probe_enable_partitions(pr, 1); blkid_probe_set_partitions_flags(pr, BLKID_PARTS_ENTRY_DETAILS); rc = blkid_do_safeprobe(pr); if (rc) goto error; DBG(CACHE, ul_debugobj(cache, "reading tags for: %s", devname)); for (i = 0; i < ARRAY_SIZE(tags); i++) { const char *data; char *dev; if (cache_find_tag_value(cache, devname, tags[i])) { DBG(CACHE, ul_debugobj(cache, "\ntag %s already cached", tags[i])); continue; } if (blkid_probe_lookup_value(pr, blktags[i], &data, NULL)) continue; dev = strdup(devname); if (!dev) goto error; if (cache_add_tag(cache, tags[i], data, dev, MNT_CACHE_TAGREAD)) { free(dev); goto error; } ntags++; } DBG(CACHE, ul_debugobj(cache, "\tread %zd tags", ntags)); blkid_free_probe(pr); return ntags ? 0 : 1; error: blkid_free_probe(pr); return rc < 0 ? rc : -1; }
static int add_boot(const char *what) { _cleanup_blkid_free_probe_ blkid_probe b = NULL; const char *fstype = NULL, *uuid = NULL; sd_id128_t id, type_id; int r; assert(what); if (!is_efi_boot()) { log_debug("Not an EFI boot, ignoring /boot."); return 0; } if (in_initrd()) { log_debug("In initrd, ignoring /boot."); return 0; } if (detect_container() > 0) { log_debug("In a container, ignoring /boot."); return 0; } /* We create an .automount which is not overridden by the .mount from the fstab generator. */ if (fstab_is_mount_point("/boot")) { log_debug("/boot specified in fstab, ignoring."); return 0; } if (path_is_busy("/boot")) { log_debug("/boot already populated, ignoring."); return 0; } r = efi_loader_get_device_part_uuid(&id); if (r == -ENOENT) { log_debug("EFI loader partition unknown."); return 0; } if (r < 0) { log_error_errno(r, "Failed to read ESP partition UUID: %m"); return r; } errno = 0; b = blkid_new_probe_from_filename(what); if (!b) { if (errno == 0) return log_oom(); return log_error_errno(errno, "Failed to allocate prober: %m"); } 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) /* no result or uncertain */ return 0; else if (r != 0) return log_error_errno(errno ?: EIO, "Failed to probe %s: %m", what); (void) blkid_probe_lookup_value(b, "TYPE", &fstype, NULL); if (!streq(fstype, "vfat")) { log_debug("Partition for /boot is not a FAT filesystem, ignoring."); return 0; } r = blkid_probe_lookup_value(b, "PART_ENTRY_UUID", &uuid, NULL); if (r != 0) { log_debug_errno(r, "Partition for /boot does not have a UUID, ignoring. %m"); return 0; } if (sd_id128_from_string(uuid, &type_id) < 0) { log_debug("Partition for /boot does not have a valid UUID, ignoring."); return 0; } if (!sd_id128_equal(type_id, id)) { log_debug("Partition for /boot does not appear to be the partition we are booted from."); return 0; } r = add_automount("boot", what, "/boot", "vfat", true, "umask=0077", "EFI System Partition Automount", 120 * USEC_PER_SEC); return r; }