Example #1
0
static inline void probe_filesystem(struct format *target)
{
  blkid_probe probe = 0;
  static char *filesystems[] =
  {
    "ext2",
    "ext3",
    "ext4",
    "reiserfs",
    "jfs",
    "xfs",
    "btrfs",
    "swap",
    0
  };
  const char *filesystem = "unknown";
  const char *result = 0;
  
  if((probe = blkid_new_probe_from_filename(target->devicepath)) == 0)
    goto bail;
    
  if(blkid_probe_enable_superblocks(probe,true) == -1)
    goto bail;

  if(blkid_probe_filter_superblocks_type(probe,BLKID_FLTR_ONLYIN,filesystems) == -1)
    goto bail;

  if(blkid_probe_set_superblocks_flags(probe,BLKID_SUBLKS_TYPE) == -1)
    goto bail;

  if(blkid_do_probe(probe) == -1)
    goto bail;

  if(blkid_probe_lookup_value(probe,"TYPE",&result,0) == -1)
    goto bail;

  filesystem = result;

bail:

  if(probe != 0)
    blkid_free_probe(probe);

  target->filesystem = strdup(filesystem);
}
Example #2
0
/*
 * Returns new libblkid prober. This function call exit() on error.
 */
static blkid_probe get_swap_prober(const char *devname)
{
	blkid_probe pr;
	int rc;
	const char *version = NULL;
	char *swap_filter[] = { "swap", NULL };

	pr = blkid_new_probe_from_filename(devname);
	if (!pr) {
		warn(_("%s: unable to probe device"), devname);
		return NULL;
	}

	blkid_probe_enable_superblocks(pr, TRUE);
	blkid_probe_set_superblocks_flags(pr,
			BLKID_SUBLKS_LABEL | BLKID_SUBLKS_UUID |
			BLKID_SUBLKS_VERSION);

	blkid_probe_filter_superblocks_type(pr, BLKID_FLTR_ONLYIN, swap_filter);

	rc = blkid_do_safeprobe(pr);
	if (rc == -1)
		warn(_("%s: unable to probe device"), devname);
	else if (rc == -2)
		warnx(_("%s: ambivalent probing result, use wipefs(8)"), devname);
	else if (rc == 1)
		warnx(_("%s: not a valid swap partition"), devname);

	if (rc == 0) {
		/* supported is SWAPSPACE2 only */
		if (blkid_probe_lookup_value(pr, "VERSION", &version, NULL) == 0
		    && version
		    && strcmp(version, "2"))
			warnx(_("%s: unsupported swap version '%s'"),
						devname, version);
		else
			return pr;
	}

	blkid_free_probe(pr);
	return NULL;
}
Example #3
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;
}
Example #4
0
int main(int argc, char **argv)
{
	blkid_cache cache = NULL;
	char *devices[128] = { NULL, };
	char *show[128] = { NULL, };
	char *search_type = NULL, *search_value = NULL;
	char *read = NULL;
	char *write = NULL;
	int fltr_usage = 0;
	char **fltr_type = NULL;
	int fltr_flag = BLKID_FLTR_ONLYIN;
	unsigned int numdev = 0, numtag = 0;
	int version = 0;
	int err = 4;
	unsigned int i;
	int output_format = 0;
	int lookup = 0, gc = 0, lowprobe = 0, eval = 0;
	int c;
	uintmax_t offset = 0, size = 0;

	show[0] = NULL;

	while ((c = getopt (argc, argv, "c:f:ghilL:n:o:O:ps:S:t:u:U:w:v")) != EOF)
		switch (c) {
		case 'c':
			if (optarg && !*optarg)
				read = NULL;
			else
				read = optarg;
			if (!write)
				write = read;
			break;
		case 'L':
			eval++;
			search_value = strdup(optarg);
			search_type = strdup("LABEL");
			break;
		case 'n':
			if (fltr_usage) {
				fprintf(stderr, "error: -u and -n options are mutually exclusive\n");
				exit(4);
			}
			fltr_type = list_to_types(optarg, &fltr_flag);
			break;
		case 'u':
			if (fltr_type) {
				fprintf(stderr, "error: -u and -n options are mutually exclusive\n");
				exit(4);
			}
			fltr_usage = list_to_usage(optarg, &fltr_flag);
			break;
		case 'U':
			eval++;
			search_value = strdup(optarg);
			search_type = strdup("UUID");
			break;
		case 'i':
			lowprobe |= LOWPROBE_TOPOLOGY;
			break;
		case 'l':
			lookup++;
			break;
		case 'g':
			gc = 1;
			break;
		case 'o':
			if (!strcmp(optarg, "value"))
				output_format = OUTPUT_VALUE_ONLY;
			else if (!strcmp(optarg, "device"))
				output_format = OUTPUT_DEVICE_ONLY;
			else if (!strcmp(optarg, "list"))
				output_format = OUTPUT_PRETTY_LIST;
			else if (!strcmp(optarg, "udev"))
				output_format = OUTPUT_UDEV_LIST;
			else if (!strcmp(optarg, "export"))
				output_format = OUTPUT_EXPORT_LIST;
			else if (!strcmp(optarg, "full"))
				output_format = 0;
			else {
				fprintf(stderr, "Invalid output format %s. "
					"Choose from value,\n\t"
					"device, list, udev or full\n", optarg);
				exit(4);
			}
			break;
		case 'O':
			if (strtosize(optarg, &offset))
				fprintf(stderr,
					"Invalid offset '%s' specified\n",
					optarg);
			break;
		case 'p':
			lowprobe |= LOWPROBE_SUPERBLOCKS;
			break;
		case 's':
			if (numtag + 1 >= sizeof(show) / sizeof(*show)) {
				fprintf(stderr, "Too many tags specified\n");
				usage(err);
			}
			show[numtag++] = optarg;
			show[numtag] = NULL;
			break;
		case 'S':
			if (strtosize(optarg, &size))
				fprintf(stderr,
					"Invalid size '%s' specified\n",
					optarg);
			break;
		case 't':
			if (search_type) {
				fprintf(stderr, "Can only search for "
						"one NAME=value pair\n");
				usage(err);
			}
			if (blkid_parse_tag_string(optarg,
						   &search_type,
						   &search_value)) {
				fprintf(stderr, "-t needs NAME=value pair\n");
				usage(err);
			}
			break;
		case 'v':
			version = 1;
			break;
		case 'w':
			if (optarg && !*optarg)
				write = NULL;
			else
				write = optarg;
			break;
		case 'h':
			err = 0;
		default:
			usage(err);
		}

	while (optind < argc)
		devices[numdev++] = argv[optind++];

	if (version) {
		print_version(stdout);
		goto exit;
	}

	/* convert LABEL/UUID lookup to evaluate request */
	if (lookup && output_format == OUTPUT_DEVICE_ONLY && search_type &&
	    (!strcmp(search_type, "LABEL") || !strcmp(search_type, "UUID"))) {
		eval++;
		lookup = 0;
	}

	if (!lowprobe && !eval && blkid_get_cache(&cache, read) < 0)
		goto exit;

	if (gc) {
		blkid_gc_cache(cache);
		err = 0;
		goto exit;
	}
	err = 2;

	if (eval == 0 && (output_format & OUTPUT_PRETTY_LIST)) {
		if (lowprobe) {
			fprintf(stderr, "The low-level probing mode does not "
					"support 'list' output format\n");
			exit(4);
		}
		pretty_print_dev(NULL);
	}

	if (lowprobe) {
		/*
		 * Low-level API
		 */
		blkid_probe pr;

		if (!numdev) {
			fprintf(stderr, "The low-level probing mode "
					"requires a device\n");
			exit(4);
		}

		/* automatically enable 'export' format for I/O Limits */
		if (!output_format  && (lowprobe & LOWPROBE_TOPOLOGY))
			output_format = OUTPUT_EXPORT_LIST;

		pr = blkid_new_probe();
		if (!pr)
			goto exit;

		if (lowprobe & LOWPROBE_SUPERBLOCKS) {
			blkid_probe_set_superblocks_flags(pr,
				BLKID_SUBLKS_LABEL | BLKID_SUBLKS_UUID |
				BLKID_SUBLKS_TYPE | BLKID_SUBLKS_SECTYPE |
				BLKID_SUBLKS_USAGE | BLKID_SUBLKS_VERSION);

			if (fltr_usage && blkid_probe_filter_superblocks_usage(
						pr, fltr_flag, fltr_usage))
				goto exit;

			else if (fltr_type && blkid_probe_filter_superblocks_type(
						pr, fltr_flag, fltr_type))
				goto exit;
		}

		for (i = 0; i < numdev; i++)
			err = lowprobe_device(pr, devices[i], lowprobe, show,
					output_format,
					(blkid_loff_t) offset,
					(blkid_loff_t) size);
		blkid_free_probe(pr);
	} else if (eval) {
		/*
		 * Evaluate API
		 */
		char *res = blkid_evaluate_tag(search_type, search_value, NULL);
		if (res) {
			err = 0;
			printf("%s\n", res);
		}
	} else if (lookup) {
		/*
		 * Classic (cache based) API
		 */
		blkid_dev dev;

		if (!search_type) {
			fprintf(stderr, "The lookup option requires a "
				"search type specified using -t\n");
			exit(4);
		}
		/* Load any additional devices not in the cache */
		for (i = 0; i < numdev; i++)
			blkid_get_dev(cache, devices[i], BLKID_DEV_NORMAL);

		if ((dev = blkid_find_dev_with_tag(cache, search_type,
						   search_value))) {
			print_tags(dev, show, output_format);
			err = 0;
		}
	/* If we didn't specify a single device, show all available devices */
	} else if (!numdev) {
		blkid_dev_iterate	iter;
		blkid_dev		dev;

		blkid_probe_all(cache);

		iter = blkid_dev_iterate_begin(cache);
		blkid_dev_set_search(iter, search_type, search_value);
		while (blkid_dev_next(iter, &dev) == 0) {
			dev = blkid_verify(cache, dev);
			if (!dev)
				continue;
			print_tags(dev, show, output_format);
			err = 0;
		}
		blkid_dev_iterate_end(iter);
	/* Add all specified devices to cache (optionally display tags) */
	} else for (i = 0; i < numdev; i++) {
		blkid_dev dev = blkid_get_dev(cache, devices[i],
						  BLKID_DEV_NORMAL);

		if (dev) {
			if (search_type &&
			    !blkid_dev_has_tag(dev, search_type,
					       search_value))
				continue;
			print_tags(dev, show, output_format);
			err = 0;
		}
	}

exit:
	free(search_type);
	free(search_value);
	free_types_list(fltr_type);
	if (!lowprobe && !eval)
		blkid_put_cache(cache);
	return err;
}
Example #5
0
static virStoragePoolProbeResult
virStorageBackendFileSystemProbe(const char *device,
                                 const char *format) {

    virStoragePoolProbeResult ret = FILESYSTEM_PROBE_ERROR;
    blkid_probe probe = NULL;
    const char *fstype = NULL;
    char *names[2], *libblkid_format = NULL;

    VIR_DEBUG("Probing for existing filesystem of type %s on device %s",
              format, device);

    if (blkid_known_fstype(format) == 0) {
        virStorageReportError(VIR_ERR_STORAGE_PROBE_FAILED,
                              _("Not capable of probing for "
                                "filesystem of type %s"),
                              format);
        goto error;
    }

    probe = blkid_new_probe_from_filename(device);
    if (probe == NULL) {
        virStorageReportError(VIR_ERR_STORAGE_PROBE_FAILED,
                                  _("Failed to create filesystem probe "
                                  "for device %s"),
                                  device);
        goto error;
    }

    if ((libblkid_format = strdup(format)) == NULL) {
        virReportOOMError();
        goto error;
    }

    names[0] = libblkid_format;
    names[1] = NULL;

    blkid_probe_filter_superblocks_type(probe,
                                        BLKID_FLTR_ONLYIN,
                                        names);

    if (blkid_do_probe(probe) != 0) {
        VIR_INFO("No filesystem of type '%s' found on device '%s'",
                 format, device);
        ret = FILESYSTEM_PROBE_NOT_FOUND;
    } else if (blkid_probe_lookup_value(probe, "TYPE", &fstype, NULL) == 0) {
        virStorageReportError(VIR_ERR_STORAGE_POOL_BUILT,
                              _("Existing filesystem of type '%s' found on "
                                "device '%s'"),
                              fstype, device);
        ret = FILESYSTEM_PROBE_FOUND;
    }

    if (blkid_do_probe(probe) != 1) {
        virStorageReportError(VIR_ERR_STORAGE_PROBE_FAILED,
                                  _("Found additional probes to run, "
                                    "filesystem probing may be incorrect"));
        ret = FILESYSTEM_PROBE_ERROR;
    }

error:
    VIR_FREE(libblkid_format);

    if (probe != NULL) {
        blkid_free_probe(probe);
    }

    return ret;
}
Example #6
0
int main(int argc, char **argv)
{
	blkid_cache cache = NULL;
	char **devices = NULL;
	char *show[128] = { NULL, };
	char *search_type = NULL, *search_value = NULL;
	char *read = NULL;
	int fltr_usage = 0;
	char **fltr_type = NULL;
	int fltr_flag = BLKID_FLTR_ONLYIN;
	unsigned int numdev = 0, numtag = 0;
	int version = 0;
	int err = BLKID_EXIT_OTHER;
	unsigned int i;
	int output_format = 0;
	int lookup = 0, gc = 0, lowprobe = 0, eval = 0;
	int c;
	uintmax_t offset = 0, size = 0;

	static const ul_excl_t excl[] = {       /* rows and cols in in ASCII order */
		{ 'n','u' },
		{ 0 }
	};
	int excl_st[ARRAY_SIZE(excl)] = UL_EXCL_STATUS_INIT;

	show[0] = NULL;
	atexit(close_stdout);

	while ((c = getopt (argc, argv,
			    "c:df:ghilL:n:ko:O:ps:S:t:u:U:w:Vv")) != EOF) {

		err_exclusive_options(c, NULL, excl, excl_st);

		switch (c) {
		case 'c':
			if (optarg && !*optarg)
				read = NULL;
			else
				read = optarg;
			break;
		case 'd':
			raw_chars = 1;
			break;
		case 'L':
			eval++;
			search_value = xstrdup(optarg);
			search_type = xstrdup("LABEL");
			break;
		case 'n':
			fltr_type = list_to_types(optarg, &fltr_flag);
			break;
		case 'u':
			fltr_usage = list_to_usage(optarg, &fltr_flag);
			break;
		case 'U':
			eval++;
			search_value = xstrdup(optarg);
			search_type = xstrdup("UUID");
			break;
		case 'i':
			lowprobe |= LOWPROBE_TOPOLOGY;
			break;
		case 'l':
			lookup++;
			break;
		case 'g':
			gc = 1;
			break;
		case 'k':
		{
			size_t idx = 0;
			const char *name = NULL;

			while (blkid_superblocks_get_name(idx++, &name, NULL) == 0)
				printf("%s\n", name);
			exit(EXIT_SUCCESS);
		}
		case 'o':
			if (!strcmp(optarg, "value"))
				output_format = OUTPUT_VALUE_ONLY;
			else if (!strcmp(optarg, "device"))
				output_format = OUTPUT_DEVICE_ONLY;
			else if (!strcmp(optarg, "list"))
				output_format = OUTPUT_PRETTY_LIST;	/* deprecated */
			else if (!strcmp(optarg, "udev"))
				output_format = OUTPUT_UDEV_LIST;
			else if (!strcmp(optarg, "export"))
				output_format = OUTPUT_EXPORT_LIST;
			else if (!strcmp(optarg, "full"))
				output_format = 0;
			else {
				fprintf(stderr, "Invalid output format %s. "
					"Choose from value,\n\t"
					"device, list, udev or full\n", optarg);
				exit(BLKID_EXIT_OTHER);
			}
			break;
		case 'O':
			offset = strtosize_or_err(optarg, "invalid offset argument");
			break;
		case 'p':
			lowprobe |= LOWPROBE_SUPERBLOCKS;
			break;
		case 's':
			if (numtag + 1 >= sizeof(show) / sizeof(*show)) {
				fprintf(stderr, "Too many tags specified\n");
				usage(err);
			}
			show[numtag++] = optarg;
			show[numtag] = NULL;
			break;
		case 'S':
			size = strtosize_or_err(optarg, "invalid size argument");
			break;
		case 't':
			if (search_type) {
				fprintf(stderr, "Can only search for "
						"one NAME=value pair\n");
				usage(err);
			}
			if (blkid_parse_tag_string(optarg,
						   &search_type,
						   &search_value)) {
				fprintf(stderr, "-t needs NAME=value pair\n");
				usage(err);
			}
			break;
		case 'V':
		case 'v':
			version = 1;
			break;
		case 'w':
			/* ignore - backward compatibility */
			break;
		case 'h':
			err = 0;
			/* fallthrough */
		default:
			usage(err);
		}
	}


	/* The rest of the args are device names */
	if (optind < argc) {
		devices = xcalloc(argc - optind, sizeof(char *));
		while (optind < argc)
			devices[numdev++] = argv[optind++];
	}

	if (version) {
		print_version(stdout);
		goto exit;
	}

	/* convert LABEL/UUID lookup to evaluate request */
	if (lookup && output_format == OUTPUT_DEVICE_ONLY && search_type &&
	    (!strcmp(search_type, "LABEL") || !strcmp(search_type, "UUID"))) {
		eval++;
		lookup = 0;
	}

	if (!lowprobe && !eval && blkid_get_cache(&cache, read) < 0)
		goto exit;

	if (gc) {
		blkid_gc_cache(cache);
		err = 0;
		goto exit;
	}
	err = BLKID_EXIT_NOTFOUND;

	if (eval == 0 && (output_format & OUTPUT_PRETTY_LIST)) {
		if (lowprobe) {
			fprintf(stderr, "The low-level probing mode does not "
					"support 'list' output format\n");
			exit(BLKID_EXIT_OTHER);
		}
		pretty_print_dev(NULL);
	}

	if (lowprobe) {
		/*
		 * Low-level API
		 */
		blkid_probe pr;

		if (!numdev) {
			fprintf(stderr, "The low-level probing mode "
					"requires a device\n");
			exit(BLKID_EXIT_OTHER);
		}

		/* automatically enable 'export' format for I/O Limits */
		if (!output_format  && (lowprobe & LOWPROBE_TOPOLOGY))
			output_format = OUTPUT_EXPORT_LIST;

		pr = blkid_new_probe();
		if (!pr)
			goto exit;

		if (lowprobe & LOWPROBE_SUPERBLOCKS) {
			blkid_probe_set_superblocks_flags(pr,
				BLKID_SUBLKS_LABEL | BLKID_SUBLKS_UUID |
				BLKID_SUBLKS_TYPE | BLKID_SUBLKS_SECTYPE |
				BLKID_SUBLKS_USAGE | BLKID_SUBLKS_VERSION);

			if (fltr_usage && blkid_probe_filter_superblocks_usage(
						pr, fltr_flag, fltr_usage))
				goto exit;

			else if (fltr_type && blkid_probe_filter_superblocks_type(
						pr, fltr_flag, fltr_type))
				goto exit;
		}

		for (i = 0; i < numdev; i++) {
			err = lowprobe_device(pr, devices[i], lowprobe, show,
					output_format,
					(blkid_loff_t) offset,
					(blkid_loff_t) size);
			if (err)
				break;
		}
		blkid_free_probe(pr);
	} else if (eval) {
		/*
		 * Evaluate API
		 */
		char *res = blkid_evaluate_tag(search_type, search_value, NULL);
		if (res) {
			err = 0;
			printf("%s\n", res);
		}
	} else if (lookup) {
		/*
		 * Classic (cache based) API
		 */
		blkid_dev dev;

		if (!search_type) {
			fprintf(stderr, "The lookup option requires a "
				"search type specified using -t\n");
			exit(BLKID_EXIT_OTHER);
		}
		/* Load any additional devices not in the cache */
		for (i = 0; i < numdev; i++)
			blkid_get_dev(cache, devices[i], BLKID_DEV_NORMAL);

		if ((dev = blkid_find_dev_with_tag(cache, search_type,
						   search_value))) {
			print_tags(dev, show, output_format);
			err = 0;
		}
	/* If we didn't specify a single device, show all available devices */
	} else if (!numdev) {
		blkid_dev_iterate	iter;
		blkid_dev		dev;

		blkid_probe_all(cache);

		iter = blkid_dev_iterate_begin(cache);
		blkid_dev_set_search(iter, search_type, search_value);
		while (blkid_dev_next(iter, &dev) == 0) {
			dev = blkid_verify(cache, dev);
			if (!dev)
				continue;
			print_tags(dev, show, output_format);
			err = 0;
		}
		blkid_dev_iterate_end(iter);
	/* Add all specified devices to cache (optionally display tags) */
	} else for (i = 0; i < numdev; i++) {
		blkid_dev dev = blkid_get_dev(cache, devices[i],
						  BLKID_DEV_NORMAL);

		if (dev) {
			if (search_type &&
			    !blkid_dev_has_tag(dev, search_type,
					       search_value))
				continue;
			print_tags(dev, show, output_format);
			err = 0;
		}
	}

exit:
	free(search_type);
	free(search_value);
	free_types_list(fltr_type);
	if (!lowprobe && !eval)
		blkid_put_cache(cache);
	free(devices);
	return err;
}