diff options
Diffstat (limited to 'libblkid/probe.c')
-rw-r--r-- | libblkid/probe.c | 1779 |
1 files changed, 0 insertions, 1779 deletions
diff --git a/libblkid/probe.c b/libblkid/probe.c deleted file mode 100644 index 77e8b860c..000000000 --- a/libblkid/probe.c +++ /dev/null @@ -1,1779 +0,0 @@ -/* - * Low-level libblkid probing API - * - * Copyright (C) 2008-2009 Karel Zak <kzak@redhat.com> - * - * This file may be redistributed under the terms of the - * GNU Lesser General Public License. - */ - -/** - * SECTION: lowprobe - * @title: Low-level probing - * @short_description: low-level prober initialization - * - * The low-level probing routines always and directly read information from - * the selected (see blkid_probe_set_device()) device. - * - * The probing routines are grouped together into separate chains. Currently, - * the library provides superblocks, partitions and topology chains. - * - * The probing routines is possible to filter (enable/disable) by type (e.g. - * fstype "vfat" or partype "gpt") or by usage flags (e.g. BLKID_USAGE_RAID). - * These filters are per-chain. Note that always when you touch the chain - * filter the current probing position is reset and probing starts from - * scratch. It means that the chain filter should not be modified during - * probing, for example in loop where you call blkid_do_probe(). - * - * For more details see the chain specific documentation. - * - * The low-level API provides two ways how access to probing results. - * - * 1. The NAME=value (tag) interface. This interface is older and returns all data - * as strings. This interface is generic for all chains. - * - * 2. The binary interfaces. These interfaces return data in the native formats. - * The interface is always specific to the probing chain. - * - * Note that the previous probing result (binary or NAME=value) is always - * zeroized when a chain probing function is called. For example: - * - * <informalexample> - * <programlisting> - * blkid_probe_enable_partitions(pr, TRUE); - * blkid_probe_enable_superblocks(pr, FALSE); - * - * blkid_do_safeprobe(pr); - * </programlisting> - * </informalexample> - * - * overwrites the previous probing result for the partitions chain, the superblocks - * result is not modified. - */ - -/** - * SECTION: lowprobe-tags - * @title: Low-level tags - * @short_description: generic NAME=value interface. - * - * The probing routines inside the chain are mutually exclusive by default -- - * only few probing routines are marked as "tolerant". The "tolerant" probing - * routines are used for filesystem which can share the same device with any - * other filesystem. The blkid_do_safeprobe() checks for the "tolerant" flag. - * - * The SUPERBLOCKS chain is enabled by default. The all others chains is - * necessary to enable by blkid_probe_enable_'CHAINNAME'(). See chains specific - * documentation. - * - * The blkid_do_probe() function returns a result from only one probing - * routine, and the next call from the next probing routine. It means you need - * to call the function in loop, for example: - * - * <informalexample> - * <programlisting> - * while((blkid_do_probe(pr) == 0) - * ... use result ... - * </programlisting> - * </informalexample> - * - * The blkid_do_safeprobe() is the same as blkid_do_probe(), but returns only - * first probing result for every enabled chain. This function checks for - * ambivalent results (e.g. more "intolerant" filesystems superblocks on the - * device). - * - * The probing result is set of NAME=value pairs (the NAME is always unique). - */ - -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <unistd.h> -#include <fcntl.h> -#include <ctype.h> -#include <sys/types.h> -#ifdef HAVE_LINUX_CDROM_H -#include <linux/cdrom.h> -#endif -#ifdef HAVE_SYS_STAT_H -#include <sys/stat.h> -#endif -#ifdef HAVE_ERRNO_H -#include <errno.h> -#endif -#include <inttypes.h> -#include <stdint.h> -#include <stdarg.h> - -#ifdef HAVE_LIBUUID -# include <uuid.h> -#endif - -#include "blkidP.h" -#include "all-io.h" - -/* chains */ -extern const struct blkid_chaindrv superblocks_drv; -extern const struct blkid_chaindrv topology_drv; -extern const struct blkid_chaindrv partitions_drv; - -/* - * All supported chains - */ -static const struct blkid_chaindrv *chains_drvs[] = { - [BLKID_CHAIN_SUBLKS] = &superblocks_drv, - [BLKID_CHAIN_TOPLGY] = &topology_drv, - [BLKID_CHAIN_PARTS] = &partitions_drv -}; - -static void blkid_probe_reset_vals(blkid_probe pr); -static void blkid_probe_reset_buffer(blkid_probe pr); - -/** - * blkid_new_probe: - * - * Returns: a pointer to the newly allocated probe struct or NULL in case of error. - */ -blkid_probe blkid_new_probe(void) -{ - int i; - blkid_probe pr; - - blkid_init_debug(0); - pr = calloc(1, sizeof(struct blkid_struct_probe)); - if (!pr) - return NULL; - - DBG(DEBUG_LOWPROBE, printf("allocate a new probe %p\n", pr)); - - /* initialize chains */ - for (i = 0; i < BLKID_NCHAINS; i++) { - pr->chains[i].driver = chains_drvs[i]; - pr->chains[i].flags = chains_drvs[i]->dflt_flags; - pr->chains[i].enabled = chains_drvs[i]->dflt_enabled; - } - INIT_LIST_HEAD(&pr->buffers); - return pr; -} - -/* - * Clone @parent, the new clone shares all, but except: - * - * - probing result - * - bufferes if another device (or offset) is set to the prober - */ -blkid_probe blkid_clone_probe(blkid_probe parent) -{ - blkid_probe pr; - - if (!parent) - return NULL; - - DBG(DEBUG_LOWPROBE, printf("allocate a probe clone\n")); - - pr = blkid_new_probe(); - if (!pr) - return NULL; - - pr->fd = parent->fd; - pr->off = parent->off; - pr->size = parent->size; - pr->devno = parent->devno; - pr->disk_devno = parent->disk_devno; - pr->blkssz = parent->blkssz; - pr->flags = parent->flags; - pr->parent = parent; - - pr->flags &= ~BLKID_FL_PRIVATE_FD; - - return pr; -} - - - -/** - * blkid_new_probe_from_filename: - * @filename: device or regular file - * - * This function is same as call open(filename), blkid_new_probe() and - * blkid_probe_set_device(pr, fd, 0, 0). - * - * The @filename is closed by blkid_free_probe() or by the - * blkid_probe_set_device() call. - * - * Returns: a pointer to the newly allocated probe struct or NULL in case of - * error. - */ -blkid_probe blkid_new_probe_from_filename(const char *filename) -{ - int fd = -1; - blkid_probe pr = NULL; - - if (!filename) - return NULL; - - fd = open(filename, O_RDONLY|O_CLOEXEC); - if (fd < 0) - return NULL; - - pr = blkid_new_probe(); - if (!pr) - goto err; - - if (blkid_probe_set_device(pr, fd, 0, 0)) - goto err; - - pr->flags |= BLKID_FL_PRIVATE_FD; - return pr; -err: - if (fd >= 0) - close(fd); - blkid_free_probe(pr); - return NULL; -} - -/** - * blkid_free_probe: - * @pr: probe - * - * Deallocates the probe struct, buffers and all allocated - * data that are associated with this probing control struct. - */ -void blkid_free_probe(blkid_probe pr) -{ - int i; - - if (!pr) - return; - - for (i = 0; i < BLKID_NCHAINS; i++) { - struct blkid_chain *ch = &pr->chains[i]; - - if (ch->driver->free_data) - ch->driver->free_data(pr, ch->data); - free(ch->fltr); - } - - if ((pr->flags & BLKID_FL_PRIVATE_FD) && pr->fd >= 0) - close(pr->fd); - blkid_probe_reset_buffer(pr); - blkid_free_probe(pr->disk_probe); - - DBG(DEBUG_LOWPROBE, printf("free probe %p\n", pr)); - free(pr); -} - - -/* - * Removes chain values from probing result. - */ -void blkid_probe_chain_reset_vals(blkid_probe pr, struct blkid_chain *chn) -{ - int nvals = pr->nvals; - int i, x; - - for (x = 0, i = 0; i < pr->nvals; i++) { - struct blkid_prval *v = &pr->vals[i]; - - if (v->chain != chn && x == i) { - x++; - continue; - } - if (v->chain == chn) { - --nvals; - continue; - } - memcpy(&pr->vals[x++], v, sizeof(struct blkid_prval)); - } - pr->nvals = nvals; -} - -static void blkid_probe_chain_reset_position(struct blkid_chain *chn) -{ - if (chn) - chn->idx = -1; -} - -/* - * Copies chain values from probing result to @vals, the max size of @vals is - * @nvals and returns real number of values. - */ -int blkid_probe_chain_copy_vals(blkid_probe pr, struct blkid_chain *chn, - struct blkid_prval *vals, int nvals) -{ - int i, x; - - for (x = 0, i = 0; i < pr->nvals && x < nvals; i++) { - struct blkid_prval *v = &pr->vals[i]; - - if (v->chain != chn) - continue; - memcpy(&vals[x++], v, sizeof(struct blkid_prval)); - } - return x; -} - -/* - * Appends values from @vals to the probing result - */ -void blkid_probe_append_vals(blkid_probe pr, struct blkid_prval *vals, int nvals) -{ - int i = 0; - - while (i < nvals && pr->nvals < BLKID_NVALS) { - memcpy(&pr->vals[pr->nvals++], &vals[i++], - sizeof(struct blkid_prval)); - } -} - -static void blkid_probe_reset_vals(blkid_probe pr) -{ - memset(pr->vals, 0, sizeof(pr->vals)); - pr->nvals = 0; -} - -struct blkid_chain *blkid_probe_get_chain(blkid_probe pr) -{ - return pr->cur_chain; -} - -void *blkid_probe_get_binary_data(blkid_probe pr, struct blkid_chain *chn) -{ - int rc, org_prob_flags; - struct blkid_chain *org_chn; - - if (!pr || !chn) - return NULL; - - /* save the current setting -- the binary API has to be completely - * independent on the current probing status - */ - org_chn = pr->cur_chain; - org_prob_flags = pr->prob_flags; - - pr->cur_chain = chn; - pr->prob_flags = 0; - chn->binary = TRUE; - blkid_probe_chain_reset_position(chn); - - rc = chn->driver->probe(pr, chn); - - chn->binary = FALSE; - blkid_probe_chain_reset_position(chn); - - /* restore the original setting - */ - pr->cur_chain = org_chn; - pr->prob_flags = org_prob_flags; - - if (rc != 0) - return NULL; - - DBG(DEBUG_LOWPROBE, - printf("returning %s binary data\n", chn->driver->name)); - return chn->data; -} - - -/** - * blkid_reset_probe: - * @pr: probe - * - * Zeroize probing results and resets the current probing (this has impact to - * blkid_do_probe() only). This function does not touch probing filters and - * keeps assigned device. - */ -void blkid_reset_probe(blkid_probe pr) -{ - int i; - - if (!pr) - return; - - blkid_probe_reset_vals(pr); - blkid_probe_set_wiper(pr, 0, 0); - - pr->cur_chain = NULL; - - for (i = 0; i < BLKID_NCHAINS; i++) - blkid_probe_chain_reset_position(&pr->chains[i]); -} - -/*** -static int blkid_probe_dump_filter(blkid_probe pr, int chain) -{ - struct blkid_chain *chn; - int i; - - if (!pr || chain < 0 || chain >= BLKID_NCHAINS) - return -1; - - chn = &pr->chains[chain]; - - if (!chn->fltr) - return -1; - - for (i = 0; i < chn->driver->nidinfos; i++) { - const struct blkid_idinfo *id = chn->driver->idinfos[i]; - - DBG(DEBUG_LOWPROBE, printf("%d: %s: %s\n", - i, - id->name, - blkid_bmp_get_item(chn->fltr, i) - ? "disabled" : "enabled <--")); - } - return 0; -} -***/ - -/* - * Returns properly initialized chain filter - */ -unsigned long *blkid_probe_get_filter(blkid_probe pr, int chain, int create) -{ - struct blkid_chain *chn; - - if (!pr || chain < 0 || chain >= BLKID_NCHAINS) - return NULL; - - chn = &pr->chains[chain]; - - /* always when you touch the chain filter all indexes are reset and - * probing starts from scratch - */ - blkid_probe_chain_reset_position(chn); - pr->cur_chain = NULL; - - if (!chn->driver->has_fltr || (!chn->fltr && !create)) - return NULL; - - if (!chn->fltr) - chn->fltr = calloc(1, blkid_bmp_nbytes(chn->driver->nidinfos)); - else - memset(chn->fltr, 0, blkid_bmp_nbytes(chn->driver->nidinfos)); - - /* blkid_probe_dump_filter(pr, chain); */ - return chn->fltr; -} - -/* - * Generic private functions for filter setting - */ -int __blkid_probe_invert_filter(blkid_probe pr, int chain) -{ - size_t i; - struct blkid_chain *chn; - - if (!pr) - return -1; - - chn = &pr->chains[chain]; - - if (!chn->driver->has_fltr || !chn->fltr) - return -1; - - for (i = 0; i < blkid_bmp_nwords(chn->driver->nidinfos); i++) - chn->fltr[i] = ~chn->fltr[i]; - - DBG(DEBUG_LOWPROBE, printf("probing filter inverted\n")); - /* blkid_probe_dump_filter(pr, chain); */ - return 0; -} - -int __blkid_probe_reset_filter(blkid_probe pr, int chain) -{ - return blkid_probe_get_filter(pr, chain, FALSE) ? 0 : -1; -} - -int __blkid_probe_filter_types(blkid_probe pr, int chain, int flag, char *names[]) -{ - unsigned long *fltr; - struct blkid_chain *chn; - size_t i; - - fltr = blkid_probe_get_filter(pr, chain, TRUE); - if (!fltr) - return -1; - - chn = &pr->chains[chain]; - - for (i = 0; i < chn->driver->nidinfos; i++) { - int has = 0; - const struct blkid_idinfo *id = chn->driver->idinfos[i]; - char **n; - - for (n = names; *n; n++) { - if (!strcmp(id->name, *n)) { - has = 1; - break; - } - } - if (flag & BLKID_FLTR_ONLYIN) { - if (!has) - blkid_bmp_set_item(fltr, i); - } else if (flag & BLKID_FLTR_NOTIN) { - if (has) - blkid_bmp_set_item(fltr, i); - } - } - - DBG(DEBUG_LOWPROBE, - printf("%s: a new probing type-filter initialized\n", - chn->driver->name)); - /* blkid_probe_dump_filter(pr, chain); */ - return 0; -} - -unsigned char *blkid_probe_get_buffer(blkid_probe pr, - blkid_loff_t off, blkid_loff_t len) -{ - struct list_head *p; - struct blkid_bufinfo *bf = NULL; - - if (pr->size <= 0) - return NULL; - - if (pr->parent && - pr->parent->devno == pr->devno && - pr->parent->off <= pr->off && - pr->parent->off + pr->parent->size >= pr->off + pr->size) { - /* - * This is a cloned prober and points to the same area as - * parent. Let's use parent's buffers. - * - * Note that pr->off (and pr->parent->off) is always from the - * beginig of the device. - */ - return blkid_probe_get_buffer(pr->parent, - pr->off + off - pr->parent->off, len); - } - - list_for_each(p, &pr->buffers) { - struct blkid_bufinfo *x = - list_entry(p, struct blkid_bufinfo, bufs); - - if (x->off <= off && off + len <= x->off + x->len) { - DBG(DEBUG_LOWPROBE, - printf("\treuse buffer: off=%jd len=%jd pr=%p\n", - x->off, x->len, pr)); - bf = x; - break; - } - } - if (!bf) { - ssize_t ret; - - if (blkid_llseek(pr->fd, pr->off + off, SEEK_SET) < 0) - return NULL; - - /* allocate info and space for data by why call */ - bf = calloc(1, sizeof(struct blkid_bufinfo) + len); - if (!bf) - return NULL; - - bf->data = ((unsigned char *) bf) + sizeof(struct blkid_bufinfo); - bf->len = len; - bf->off = off; - INIT_LIST_HEAD(&bf->bufs); - - DBG(DEBUG_LOWPROBE, - printf("\tbuffer read: off=%jd len=%jd pr=%p\n", - off, len, pr)); - - ret = read(pr->fd, bf->data, len); - if (ret != (ssize_t) len) { - free(bf); - return NULL; - } - list_add_tail(&bf->bufs, &pr->buffers); - } - - return off ? bf->data + (off - bf->off) : bf->data; -} - - -static void blkid_probe_reset_buffer(blkid_probe pr) -{ - uint64_t read_ct = 0, len_ct = 0; - - if (!pr || list_empty(&pr->buffers)) - return; - - DBG(DEBUG_LOWPROBE, printf("reseting probing buffers pr=%p\n", pr)); - - while (!list_empty(&pr->buffers)) { - struct blkid_bufinfo *bf = list_entry(pr->buffers.next, - struct blkid_bufinfo, bufs); - read_ct++; - len_ct += bf->len; - list_del(&bf->bufs); - free(bf); - } - - DBG(DEBUG_LOWPROBE, - printf("buffers summary: %"PRIu64" bytes " - "by %"PRIu64" read() call(s)\n", - len_ct, read_ct)); - - INIT_LIST_HEAD(&pr->buffers); -} - -/* - * Small devices need a special care. - */ -int blkid_probe_is_tiny(blkid_probe pr) -{ - return pr && (pr->flags & BLKID_FL_TINY_DEV); -} - -/* - * CDROMs may fail when probed for RAID (last sector problem) - */ -int blkid_probe_is_cdrom(blkid_probe pr) -{ - return pr && (pr->flags & BLKID_FL_CDROM_DEV); -} - -/** - * blkid_probe_set_device: - * @pr: probe - * @fd: device file descriptor - * @off: begin of probing area - * @size: size of probing area (zero means whole device/file) - * - * Assigns the device to probe control struct, resets internal buffers and - * resets the current probing. - * - * Returns: -1 in case of failure, or 0 on success. - */ -int blkid_probe_set_device(blkid_probe pr, int fd, - blkid_loff_t off, blkid_loff_t size) -{ - struct stat sb; - - if (!pr) - return -1; - - blkid_reset_probe(pr); - blkid_probe_reset_buffer(pr); - - if ((pr->flags & BLKID_FL_PRIVATE_FD) && pr->fd >= 0) - close(pr->fd); - - pr->flags &= ~BLKID_FL_PRIVATE_FD; - pr->flags &= ~BLKID_FL_TINY_DEV; - pr->flags &= ~BLKID_FL_CDROM_DEV; - pr->prob_flags = 0; - pr->fd = fd; - pr->off = off; - pr->size = 0; - pr->devno = 0; - pr->disk_devno = 0; - pr->mode = 0; - pr->blkssz = 0; - pr->wipe_off = 0; - pr->wipe_size = 0; - pr->wipe_chain = NULL; - -#if defined(POSIX_FADV_RANDOM) && defined(HAVE_POSIX_FADVISE) - /* Disable read-ahead */ - posix_fadvise(fd, 0, 0, POSIX_FADV_RANDOM); -#endif - if (fstat(fd, &sb)) - goto err; - - if (!S_ISBLK(sb.st_mode) && !S_ISCHR(sb.st_mode) && !S_ISREG(sb.st_mode)) - goto err; - - pr->mode = sb.st_mode; - if (S_ISBLK(sb.st_mode) || S_ISCHR(sb.st_mode)) - pr->devno = sb.st_rdev; - - if (size) - pr->size = size; - else { - if (S_ISBLK(sb.st_mode)) { - if (blkdev_get_size(fd, (unsigned long long *) &pr->size)) { - DBG(DEBUG_LOWPROBE, printf( - "failed to get device size\n")); - goto err; - } - } else if (S_ISCHR(sb.st_mode)) - pr->size = 1; /* UBI devices are char... */ - else if (S_ISREG(sb.st_mode)) - pr->size = sb.st_size; /* regular file */ - - if (pr->off > pr->size) - goto err; - - /* The probing area cannot be larger than whole device, pr->off - * is offset within the device */ - pr->size -= pr->off; - } - - if (pr->size <= 1440 * 1024 && !S_ISCHR(sb.st_mode)) - pr->flags |= BLKID_FL_TINY_DEV; - -#ifdef CDROM_GET_CAPABILITY - if (S_ISBLK(sb.st_mode) && - !blkid_probe_is_tiny(pr) && - blkid_probe_is_wholedisk(pr) && - ioctl(fd, CDROM_GET_CAPABILITY, NULL) >= 0) - pr->flags |= BLKID_FL_CDROM_DEV; -#endif - - DBG(DEBUG_LOWPROBE, printf("ready for low-probing, offset=%jd, size=%jd\n", - pr->off, pr->size)); - DBG(DEBUG_LOWPROBE, printf("whole-disk: %s, regfile: %s\n", - blkid_probe_is_wholedisk(pr) ?"YES" : "NO", - S_ISREG(pr->mode) ? "YES" : "NO")); - - return 0; -err: - DBG(DEBUG_LOWPROBE, - printf("failed to prepare a device for low-probing\n")); - return -1; - -} - -int blkid_probe_get_dimension(blkid_probe pr, - blkid_loff_t *off, blkid_loff_t *size) -{ - if (!pr) - return -1; - - *off = pr->off; - *size = pr->size; - return 0; -} - -int blkid_probe_set_dimension(blkid_probe pr, - blkid_loff_t off, blkid_loff_t size) -{ - if (!pr) - return -1; - - DBG(DEBUG_LOWPROBE, printf( - "changing probing area pr=%p: size=%llu, off=%llu " - "-to-> size=%llu, off=%llu\n", - pr, - (unsigned long long) pr->size, - (unsigned long long) pr->off, - (unsigned long long) size, - (unsigned long long) off)); - - pr->off = off; - pr->size = size; - pr->flags &= ~BLKID_FL_TINY_DEV; - - if (pr->size <= 1440 * 1024 && !S_ISCHR(pr->mode)) - pr->flags |= BLKID_FL_TINY_DEV; - - blkid_probe_reset_buffer(pr); - - return 0; -} - -int blkid_probe_get_idmag(blkid_probe pr, const struct blkid_idinfo *id, - blkid_loff_t *offset, const struct blkid_idmag **res) -{ - const struct blkid_idmag *mag = NULL; - blkid_loff_t off = 0; - - if (id) - mag = &id->magics[0]; - if (res) - *res = NULL; - - /* try to detect by magic string */ - while(mag && mag->magic) { - unsigned char *buf; - - off = (mag->kboff + (mag->sboff >> 10)) << 10; - buf = blkid_probe_get_buffer(pr, off, 1024); - - if (buf && !memcmp(mag->magic, - buf + (mag->sboff & 0x3ff), mag->len)) { - DBG(DEBUG_LOWPROBE, printf( - "\tmagic sboff=%u, kboff=%ld\n", - mag->sboff, mag->kboff)); - if (offset) - *offset = off + (mag->sboff & 0x3ff); - if (res) - *res = mag; - return 0; - } - mag++; - } - - if (id && id->magics[0].magic) - /* magic string(s) defined, but not found */ - return 1; - - return 0; -} - -static inline void blkid_probe_start(blkid_probe pr) -{ - if (pr) { - DBG(DEBUG_LOWPROBE, printf("%p: start probe\n", pr)); - pr->cur_chain = NULL; - pr->prob_flags = 0; - blkid_probe_set_wiper(pr, 0, 0); - } -} - -static inline void blkid_probe_end(blkid_probe pr) -{ - if (pr) { - DBG(DEBUG_LOWPROBE, printf("%p: end probe\n", pr)); - pr->cur_chain = NULL; - pr->prob_flags = 0; - blkid_probe_set_wiper(pr, 0, 0); - } -} - -/** - * blkid_do_probe: - * @pr: prober - * - * Calls probing functions in all enabled chains. The superblocks chain is - * enabled by default. The blkid_do_probe() stores result from only one - * probing function. It's necessary to call this routine in a loop to get - * results from all probing functions in all chains. The probing is reset - * by blkid_reset_probe() or by filter functions. - * - * This is string-based NAME=value interface only. - * - * <example> - * <title>basic case - use the first result only</title> - * <programlisting> - * - * if (blkid_do_probe(pr) == 0) { - * int nvals = blkid_probe_numof_values(pr); - * for (n = 0; n < nvals; n++) { - * if (blkid_probe_get_value(pr, n, &name, &data, &len) == 0) - * printf("%s = %s\n", name, data); - * } - * } - * </programlisting> - * </example> - * - * <example> - * <title>advanced case - probe for all signatures</title> - * <programlisting> - * - * while (blkid_do_probe(pr) == 0) { - * int nvals = blkid_probe_numof_values(pr); - * ... - * } - * </programlisting> - * </example> - * - * See also blkid_reset_probe(). - * - * Returns: 0 on success, 1 when probing is done and -1 in case of error. - */ -int blkid_do_probe(blkid_probe pr) -{ - int rc = 1; - - if (!pr) - return -1; - - do { - struct blkid_chain *chn = pr->cur_chain; - - if (!chn) { - blkid_probe_start(pr); - chn = pr->cur_chain = &pr->chains[0]; - } - /* we go to the next chain only when the previous probing - * result was nothing (rc == 1) and when the current chain is - * disabled or we are at end of the current chain (chain->idx + - * 1 == sizeof chain) or the current chain bailed out right at - * the start (chain->idx == -1) - */ - else if (rc == 1 && (chn->enabled == FALSE || - chn->idx + 1 == (int) chn->driver->nidinfos || - chn->idx == -1)) { - - size_t idx = chn->driver->id + 1; - - if (idx < BLKID_NCHAINS) - chn = pr->cur_chain = &pr->chains[idx]; - else { - blkid_probe_end(pr); - return 1; /* all chains already probed */ - } - } - - chn->binary = FALSE; /* for sure... */ - - DBG(DEBUG_LOWPROBE, printf("chain probe %s %s (idx=%d)\n", - chn->driver->name, - chn->enabled? "ENABLED" : "DISABLED", - chn->idx)); - - if (!chn->enabled) - continue; - - /* rc: -1 = error, 0 = success, 1 = no result */ - rc = chn->driver->probe(pr, chn); - - } while (rc == 1); - - return rc; -} - -/** - * blkid_do_wipe: - * @pr: prober - * @dryrun: if TRUE then don't touch the device. - * - * This function erases the current signature detected by @pr. The @pr has to - * be open in O_RDWR mode, BLKID_SUBLKS_MAGIC or/and BLKID_PARTS_MAGIC flags - * has to be enabled. - * - * After successful signature removing the @pr prober will be moved one step - * back and the next blkid_do_probe() call will again call previously called - * probing function. - * - * <example> - * <title>wipe all filesystems or raids from the device</title> - * <programlisting> - * fd = open(devname, O_RDWR|O_CLOEXEC); - * blkid_probe_set_device(pr, fd, 0, 0); - * - * blkid_probe_enable_superblocks(pr, 1); - * blkid_probe_set_superblocks_flags(pr, BLKID_SUBLKS_MAGIC); - * - * while (blkid_do_probe(pr) == 0) - * blkid_do_wipe(pr, FALSE); - * </programlisting> - * </example> - * - * See also blkid_probe_step_back() if you cannot use this build-in wipe - * function, but you want to use libblkid probing as a source for wiping. - * - * Returns: 0 on success, and -1 in case of error. - */ -int blkid_do_wipe(blkid_probe pr, int dryrun) -{ - const char *off = NULL; - size_t len = 0; - loff_t offset, l; - char buf[BUFSIZ]; - int fd, rc = 0; - struct blkid_chain *chn; - - if (!pr) - return -1; - - chn = pr->cur_chain; - if (!chn) - return -1; - - switch (chn->driver->id) { - case BLKID_CHAIN_SUBLKS: - rc = blkid_probe_lookup_value(pr, "SBMAGIC_OFFSET", &off, NULL); - if (!rc) - rc = blkid_probe_lookup_value(pr, "SBMAGIC", NULL, &len); - break; - case BLKID_CHAIN_PARTS: - rc = blkid_probe_lookup_value(pr, "PTMAGIC_OFFSET", &off, NULL); - if (!rc) - rc = blkid_probe_lookup_value(pr, "PTMAGIC", NULL, &len); - break; - default: - return 0; - } - - if (rc || len == 0 || off == NULL) - return 0; - - offset = strtoll(off, NULL, 10); - fd = blkid_probe_get_fd(pr); - if (fd < 0) - return -1; - - if (len > sizeof(buf)) - len = sizeof(buf); - - DBG(DEBUG_LOWPROBE, printf( - "do_wipe [offset=0x%jx, len=%zd, chain=%s, idx=%d, dryrun=%s]\n", - offset, len, chn->driver->name, chn->idx, dryrun ? "yes" : "not")); - - l = lseek(fd, offset, SEEK_SET); - if (l == (off_t) -1) - return -1; - - memset(buf, 0, len); - - if (!dryrun && len) { - if (write_all(fd, buf, len)) - return -1; - fsync(fd); - return blkid_probe_step_back(pr); - } - - return 0; -} - -/** - * blkid_probe_step_back(): - * @pr: prober - * - * This function move pointer to the probing chain one step back -- it means - * that the previously used probing function will be called again in the next - * blkid_do_probe() call. - * - * This is necessary for example if you erase or modify on-disk superblock - * according to the current libblkid probing result. - * - * <example> - * <title>wipe all superblock, but use libblkid only for probing</title> - * <programlisting> - * pr = blkid_new_probe_from_filename(devname); - * - * blkid_probe_enable_superblocks(pr, 1); - * blkid_probe_set_superblocks_flags(pr, BLKID_SUBLKS_MAGIC); - * - * while (blkid_do_probe(pr) == 0) { - * const char *ostr = NULL; - * size_t len = 0; - * - * // superblocks - * if (blkid_probe_lookup_value(pr, "SBMAGIC_OFFSET", &ostr, NULL) == 0) - * blkid_probe_lookup_value(pr, "SBMAGIC", NULL, &len); - * - * // partition tables - * if (len == 0 && blkid_probe_lookup_value(pr, "PTMAGIC_OFFSET", &ostr, NULL) == 0) - * blkid_probe_lookup_value(pr, "PTMAGIC", NULL, &len); - * - * if (!len || !str) - * continue; - * - * // convert ostr to the real offset by off = strtoll(ostr, NULL, 10); - * // use your stuff to errase @len bytes at the @off - * .... - * - * // retry the last probing to check for backup superblocks ..etc. - * blkid_probe_step_back(pr); - * } - * </programlisting> - * </example> - * - * Returns: 0 on success, and -1 in case of error. - */ -int blkid_probe_step_back(blkid_probe pr) -{ - struct blkid_chain *chn; - - if (!pr) - return -1; - - chn = pr->cur_chain; - if (!chn) - return -1; - - blkid_probe_reset_buffer(pr); - - if (chn->idx >= 0) { - chn->idx--; - DBG(DEBUG_LOWPROBE, - printf("step back: moving %s chain index to %d\n", - chn->driver->name, - chn->idx)); - } - - if (chn->idx == -1) { - /* blkid_do_probe() goes to the next chain if the index - * of the current chain is -1, so we have to set the - * chain pointer to the previous chain. - */ - size_t idx = chn->driver->id > 0 ? chn->driver->id - 1 : 0; - - DBG(DEBUG_LOWPROBE, printf("step back: moving to previous chain\n")); - - if (idx > 0) - pr->cur_chain = &pr->chains[idx]; - else if (idx == 0) - pr->cur_chain = NULL; - } - - return 0; -} - -/** - * blkid_do_safeprobe: - * @pr: prober - * - * This function gathers probing results from all enabled chains and checks - * for ambivalent results (e.g. more filesystems on the device). - * - * This is string-based NAME=value interface only. - * - * Note about suberblocks chain -- the function does not check for filesystems - * when a RAID signature is detected. The function also does not check for - * collision between RAIDs. The first detected RAID is returned. The function - * checks for collision between partition table and RAID signature -- it's - * recommended to enable partitions chain together with superblocks chain. - * - * Returns: 0 on success, 1 if nothing is detected, -2 if ambivalen result is - * detected and -1 on case of error. - */ -int blkid_do_safeprobe(blkid_probe pr) -{ - int i, count = 0, rc = 0; - - if (!pr) - return -1; - - blkid_probe_start(pr); - - pr->prob_flags |= BLKID_PROBE_FL_IGNORE_BACKUP; - - for (i = 0; i < BLKID_NCHAINS; i++) { - struct blkid_chain *chn; - - chn = pr->cur_chain = &pr->chains[i]; - chn->binary = FALSE; /* for sure... */ - - DBG(DEBUG_LOWPROBE, printf("chain safeprobe %s %s\n", - chn->driver->name, - chn->enabled? "ENABLED" : "DISABLED")); - - if (!chn->enabled) - continue; - - blkid_probe_chain_reset_position(chn); - - rc = chn->driver->safeprobe(pr, chn); - - blkid_probe_chain_reset_position(chn); - - /* rc: -2 ambivalent, -1 = error, 0 = success, 1 = no result */ - if (rc < 0) - goto done; /* error */ - if (rc == 0) - count++; /* success */ - } - -done: - blkid_probe_end(pr); - if (rc < 0) - return rc; - return count ? 0 : 1; -} - -/** - * blkid_do_fullprobe: - * @pr: prober - * - * This function gathers probing results from all enabled chains. Same as - * blkid_do_safeprobe() but does not check for collision between probing - * result. - * - * This is string-based NAME=value interface only. - * - * Returns: 0 on success, 1 if nothing is detected or -1 on case of error. - */ -int blkid_do_fullprobe(blkid_probe pr) -{ - int i, count = 0, rc = 0; - - if (!pr) - return -1; - - blkid_probe_start(pr); - - for (i = 0; i < BLKID_NCHAINS; i++) { - struct blkid_chain *chn; - - chn = pr->cur_chain = &pr->chains[i]; - chn->binary = FALSE; /* for sure... */ - - DBG(DEBUG_LOWPROBE, printf("chain fullprobe %s: %s\n", - chn->driver->name, - chn->enabled? "ENABLED" : "DISABLED")); - - if (!chn->enabled) - continue; - - blkid_probe_chain_reset_position(chn); - - rc = chn->driver->probe(pr, chn); - - blkid_probe_chain_reset_position(chn); - - /* rc: -1 = error, 0 = success, 1 = no result */ - if (rc < 0) - goto done; /* error */ - if (rc == 0) - count++; /* success */ - } - -done: - blkid_probe_end(pr); - if (rc < 0) - return rc; - return count ? 0 : 1; -} - -/* same sa blkid_probe_get_buffer() but works with 512-sectors */ -unsigned char *blkid_probe_get_sector(blkid_probe pr, unsigned int sector) -{ - return pr ? blkid_probe_get_buffer(pr, - ((blkid_loff_t) sector) << 9, 0x200) : NULL; -} - -struct blkid_prval *blkid_probe_assign_value( - blkid_probe pr, const char *name) -{ - struct blkid_prval *v; - - if (!name) - return NULL; - if (pr->nvals >= BLKID_NVALS) - return NULL; - - v = &pr->vals[pr->nvals]; - v->name = name; - v->chain = pr->cur_chain; - pr->nvals++; - - DBG(DEBUG_LOWPROBE, - printf("assigning %s [%s]\n", name, v->chain->driver->name)); - return v; -} - -int blkid_probe_reset_last_value(blkid_probe pr) -{ - struct blkid_prval *v; - - if (pr == NULL || pr->nvals == 0) - return -1; - - v = &pr->vals[pr->nvals - 1]; - - DBG(DEBUG_LOWPROBE, - printf("un-assigning %s [%s]\n", v->name, v->chain->driver->name)); - - memset(v, 0, sizeof(struct blkid_prval)); - pr->nvals--; - - return 0; - -} - -int blkid_probe_set_value(blkid_probe pr, const char *name, - unsigned char *data, size_t len) -{ - struct blkid_prval *v; - - if (len > BLKID_PROBVAL_BUFSIZ) - len = BLKID_PROBVAL_BUFSIZ; - - v = blkid_probe_assign_value(pr, name); - if (!v) - return -1; - - memcpy(v->data, data, len); - v->len = len; - return 0; -} - -int blkid_probe_vsprintf_value(blkid_probe pr, const char *name, - const char *fmt, va_list ap) -{ - struct blkid_prval *v; - ssize_t len; - - v = blkid_probe_assign_value(pr, name); - if (!v) - return -1; - - len = vsnprintf((char *) v->data, sizeof(v->data), fmt, ap); - - if (len <= 0 || (size_t) len >= sizeof(v->data)) { - blkid_probe_reset_last_value(pr); - return -1; - } - v->len = len + 1; - return 0; -} - -int blkid_probe_sprintf_value(blkid_probe pr, const char *name, - const char *fmt, ...) -{ - int rc; - va_list ap; - - va_start(ap, fmt); - rc = blkid_probe_vsprintf_value(pr, name, fmt, ap); - va_end(ap); - - return rc; -} - -int blkid_probe_set_magic(blkid_probe pr, blkid_loff_t offset, - size_t len, unsigned char *magic) -{ - int rc = 0; - struct blkid_chain *chn = blkid_probe_get_chain(pr); - - if (!chn || !magic || !len || chn->binary) - return 0; - - switch (chn->driver->id) { - case BLKID_CHAIN_SUBLKS: - if (!(chn->flags & BLKID_SUBLKS_MAGIC)) - return 0; - rc = blkid_probe_set_value(pr, "SBMAGIC", magic, len); - if (!rc) - rc = blkid_probe_sprintf_value(pr, - "SBMAGIC_OFFSET", "%llu", (unsigned long long)offset); - break; - case BLKID_CHAIN_PARTS: - if (!(chn->flags & BLKID_PARTS_MAGIC)) - return 0; - rc = blkid_probe_set_value(pr, "PTMAGIC", magic, len); - if (!rc) - rc = blkid_probe_sprintf_value(pr, - "PTMAGIC_OFFSET", "%llu", (unsigned long long)offset); - break; - default: - break; - } - - return rc; -} - -/** - * blkid_probe_get_devno: - * @pr: probe - * - * Returns: block device number, or 0 for regular files. - */ -dev_t blkid_probe_get_devno(blkid_probe pr) -{ - return pr->devno; -} - -/** - * blkid_probe_get_wholedisk_devno: - * @pr: probe - * - * Returns: device number of the wholedisk, or 0 for regular files. - */ -dev_t blkid_probe_get_wholedisk_devno(blkid_probe pr) -{ - if (!pr->disk_devno) { - dev_t devno, disk_devno = 0; - - devno = blkid_probe_get_devno(pr); - if (!devno) - return 0; - - if (blkid_devno_to_wholedisk(devno, NULL, 0, &disk_devno) == 0) - pr->disk_devno = disk_devno; - } - return pr->disk_devno; -} - -/** - * blkid_probe_is_wholedisk: - * @pr: probe - * - * Returns: 1 if the device is whole-disk or 0. - */ -int blkid_probe_is_wholedisk(blkid_probe pr) -{ - dev_t devno, disk_devno; - - devno = blkid_probe_get_devno(pr); - if (!devno) - return 0; - - disk_devno = blkid_probe_get_wholedisk_devno(pr); - if (!disk_devno) - return 0; - - return devno == disk_devno; -} - -blkid_probe blkid_probe_get_wholedisk_probe(blkid_probe pr) -{ - dev_t disk; - - if (blkid_probe_is_wholedisk(pr)) - return NULL; /* this is not partition */ - - if (pr->parent) - /* this is cloned blkid_probe, use parent's stuff */ - return blkid_probe_get_wholedisk_probe(pr->parent); - - disk = blkid_probe_get_wholedisk_devno(pr); - - if (pr->disk_probe && pr->disk_probe->devno != disk) { - /* we have disk prober, but for another disk... close it */ - blkid_free_probe(pr->disk_probe); - pr->disk_probe = NULL; - } - - if (!pr->disk_probe) { - /* Open a new disk prober */ - char *disk_path = blkid_devno_to_devname(disk); - - if (!disk_path) - return NULL; - - DBG(DEBUG_LOWPROBE, printf("allocate a wholedisk probe\n")); - - pr->disk_probe = blkid_new_probe_from_filename(disk_path); - - free(disk_path); - - if (!pr->disk_probe) - return NULL; /* ENOMEM? */ - } - - return pr->disk_probe; -} - -/** - * blkid_probe_get_size: - * @pr: probe - * - * This function returns size of probing area as defined by blkid_probe_set_device(). - * If the size of the probing area is unrestricted then this function returns - * the real size of device. See also blkid_get_dev_size(). - * - * Returns: size in bytes or -1 in case of error. - */ -blkid_loff_t blkid_probe_get_size(blkid_probe pr) -{ - return pr ? pr->size : -1; -} - -/** - * blkid_probe_get_offset: - * @pr: probe - * - * This function returns offset of probing area as defined by blkid_probe_set_device(). - * - * Returns: offset in bytes or -1 in case of error. - */ -blkid_loff_t blkid_probe_get_offset(blkid_probe pr) -{ - return pr ? pr->off : -1; -} - -/** - * blkid_probe_get_fd: - * @pr: probe - * - * Returns: file descriptor for assigned device/file or -1 in case of error. - */ -int blkid_probe_get_fd(blkid_probe pr) -{ - return pr ? pr->fd : -1; -} - -/** - * blkid_probe_get_sectorsize: - * @pr: probe or NULL (for NULL returns 512) - * - * Returns: block device logical sector size (BLKSSZGET ioctl, default 512). - */ -unsigned int blkid_probe_get_sectorsize(blkid_probe pr) -{ - if (!pr) - return DEFAULT_SECTOR_SIZE; /*... and good luck! */ - - if (pr->blkssz) - return pr->blkssz; - - if (S_ISBLK(pr->mode) && - blkdev_get_sector_size(pr->fd, (int *) &pr->blkssz) == 0) - return pr->blkssz; - - pr->blkssz = DEFAULT_SECTOR_SIZE; - return pr->blkssz; -} - -/** - * blkid_probe_get_sectors: - * @pr: probe - * - * Returns: 512-byte sector count or -1 in case of error. - */ -blkid_loff_t blkid_probe_get_sectors(blkid_probe pr) -{ - return pr ? pr->size >> 9 : -1; -} - -/** - * blkid_probe_numof_values: - * @pr: probe - * - * Returns: number of values in probing result or -1 in case of error. - */ -int blkid_probe_numof_values(blkid_probe pr) -{ - if (!pr) - return -1; - return pr->nvals; -} - -/** - * blkid_probe_get_value: - * @pr: probe - * @num: wanted value in range 0..N, where N is blkid_probe_numof_values() - 1 - * @name: pointer to return value name or NULL - * @data: pointer to return value data or NULL - * @len: pointer to return value length or NULL - * - * Note, the @len returns length of the @data, including the terminating - * '\0' character. - * - * Returns: 0 on success, or -1 in case of error. - */ -int blkid_probe_get_value(blkid_probe pr, int num, const char **name, - const char **data, size_t *len) -{ - struct blkid_prval *v = __blkid_probe_get_value(pr, num); - - if (!v) - return -1; - if (name) - *name = v->name; - if (data) - *data = (char *) v->data; - if (len) - *len = v->len; - - DBG(DEBUG_LOWPROBE, printf("returning %s value\n", v->name)); - return 0; -} - -/** - * blkid_probe_lookup_value: - * @pr: probe - * @name: name of value - * @data: pointer to return value data or NULL - * @len: pointer to return value length or NULL - * - * Note, the @len returns length of the @data, including the terminating - * '\0' character. - * - * Returns: 0 on success, or -1 in case of error. - */ -int blkid_probe_lookup_value(blkid_probe pr, const char *name, - const char **data, size_t *len) -{ - struct blkid_prval *v = __blkid_probe_lookup_value(pr, name); - - if (!v) - return -1; - if (data) - *data = (char *) v->data; - if (len) - *len = v->len; - return 0; -} - -/** - * blkid_probe_has_value: - * @pr: probe - * @name: name of value - * - * Returns: 1 if value exist in probing result, otherwise 0. - */ -int blkid_probe_has_value(blkid_probe pr, const char *name) -{ - if (blkid_probe_lookup_value(pr, name, NULL, NULL) == 0) - return 1; - return 0; -} - -struct blkid_prval *__blkid_probe_get_value(blkid_probe pr, int num) -{ - if (!pr || num < 0 || num >= pr->nvals) - return NULL; - - return &pr->vals[num]; -} - -struct blkid_prval *__blkid_probe_lookup_value(blkid_probe pr, const char *name) -{ - int i; - - if (!pr || !pr->nvals || !name) - return NULL; - - for (i = 0; i < pr->nvals; i++) { - struct blkid_prval *v = &pr->vals[i]; - - if (v->name && strcmp(name, v->name) == 0) { - DBG(DEBUG_LOWPROBE, printf("returning %s value\n", v->name)); - return v; - } - } - return NULL; -} - - -/* converts DCE UUID (uuid[16]) to human readable string - * - the @len should be always 37 */ -#ifdef HAVE_LIBUUID -void blkid_unparse_uuid(const unsigned char *uuid, char *str, - size_t len __attribute__((__unused__))) -{ - uuid_unparse(uuid, str); -} -#else -void blkid_unparse_uuid(const unsigned char *uuid, char *str, size_t len) -{ - snprintf(str, len, - "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x", - uuid[0], uuid[1], uuid[2], uuid[3], - uuid[4], uuid[5], - uuid[6], uuid[7], - uuid[8], uuid[9], - uuid[10], uuid[11], uuid[12], uuid[13], uuid[14],uuid[15]); -} -#endif - - -/* Removes whitespace from the right-hand side of a string (trailing - * whitespace). - * - * Returns size of the new string (without \0). - */ -size_t blkid_rtrim_whitespace(unsigned char *str) -{ - size_t i = strlen((char *) str); - - while (i--) { - if (!isspace(str[i])) - break; - } - str[++i] = '\0'; - return i; -} - -/* Removes whitespace from the left-hand side of a string. - * - * Returns size of the new string (without \0). - */ -size_t blkid_ltrim_whitespace(unsigned char *str) -{ - size_t len; - unsigned char *p; - - for (p = str; p && isspace(*p); p++); - - len = strlen((char *) p); - - if (len && p > str) - memmove(str, p, len + 1); - - return len; -} -/* - * Some mkfs-like utils wipe some parts (usually begin) of the device. - * For example LVM (pvcreate) or mkswap(8). This information could be used - * for later resolution to conflicts between superblocks. - * - * For example we found valid LVM superblock, LVM wipes 8KiB at the begin of - * the device. If we found another signature (for example MBR) within the - * wiped area then the signature has been added later and LVM superblock - * should be ignore. - * - * Note that this heuristic is not 100% reliable, for example "pvcreate --zero - * n" allows to keep the begin of the device unmodified. It's probably better - * to use this heuristic for conflicts between superblocks and partition tables - * than for conflicts between filesystem superblocks -- existence of unwanted - * partition table is very unusual, because PT is pretty visible (parsed and - * interpreted by kernel). - * - * Note that we usually expect only one signature on the device, it means that - * we have to remember only one wiped area from previously successfully - * detected signature. - * - * blkid_probe_set_wiper() -- defines wiped area (e.g. LVM) - * blkid_probe_use_wiper() -- try to use area (e.g. MBR) - * - * Note that there is not relation between _wiper and blkid_to_wipe(). - * - */ -void blkid_probe_set_wiper(blkid_probe pr, blkid_loff_t off, blkid_loff_t size) -{ - struct blkid_chain *chn; - - if (!pr) - return; - - if (!size) { - DBG(DEBUG_LOWPROBE, printf("zeroize wiper\n")); - pr->wipe_size = pr->wipe_off = 0; - pr->wipe_chain = NULL; - return; - } - - chn = pr->cur_chain; - - if (!chn || !chn->driver || - chn->idx < 0 || (size_t) chn->idx >= chn->driver->nidinfos) - return; - - pr->wipe_size = size; - pr->wipe_off = off; - pr->wipe_chain = chn; - - DBG(DEBUG_LOWPROBE, - printf("wiper set to %s::%s off=%jd size=%jd\n", - chn->driver->name, - chn->driver->idinfos[chn->idx]->name, - pr->wipe_off, pr->wipe_size)); - return; -} - -/* - * Returns 1 if the <@off,@size> area was wiped - */ -int blkid_probe_is_wiped(blkid_probe pr, struct blkid_chain **chn, - blkid_loff_t off, blkid_loff_t size) -{ - if (!pr || !size) - return 0; - - if (pr->wipe_off <= off && off + size <= pr->wipe_off + pr->wipe_size) { - if (chn) - *chn = pr->wipe_chain; - return 1; - } - return 0; -} - -/* - * Try to use any area -- if the area has been previously wiped then the - * previous probing result should be ignored (reseted). - */ -void blkid_probe_use_wiper(blkid_probe pr, blkid_loff_t off, blkid_loff_t size) -{ - struct blkid_chain *chn = NULL; - - if (blkid_probe_is_wiped(pr, &chn, off, size) && chn) { - DBG(DEBUG_LOWPROBE, printf("previously wiped area modified " - " -- ignore previous results\n")); - blkid_probe_set_wiper(pr, 0, 0); - blkid_probe_chain_reset_vals(pr, chn); - } -} - -int blkid_probe_ignore_backup(blkid_probe pr) -{ - return pr && (pr->prob_flags & BLKID_PROBE_FL_IGNORE_BACKUP); -} |