summaryrefslogblamecommitdiffstats
path: root/lib/fsprobe.c
blob: 77211806d38b5a897709d4fd8cbe9be4e11995e2 (plain) (tree)
1
2
3
4
5
6
7
8
9








                      


                         
                  
      





                         

                           
                             



















                                                                  
      




                                                                               



                                                               


                      

                                                                 
 


                 
      








                                                                         
                                   





                                                                    

                            





                                       











                                          
                             

















                                                       
             


                                                        
                                











                                                      





                                                                            








                                                                 
      




                                                   
      




                                                  
      




                                                  
      

                                             
                                                          

 
      

                                               
                                                            

 
                                   

  
                                                                 










                                           
      







                                                        
      







                                                          
      


                                                  
                 














                                                                              
      







                                                              
      







                                                             
                                    
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <stdlib.h>

#ifdef HAVE_BLKID_BLKID_H
#include <blkid/blkid.h>
#else
#include <blkid.h>
#endif

#include "blkdev.h"
#include "canonicalize.h"
#include "pathnames.h"
#include "fsprobe.h"

static blkid_cache blcache;

#ifdef HAVE_LIBBLKID_INTERNAL
/* ask kernel developers why we need such ugly open() method... */
static int
open_device(const char *devname)
{
	int retries = 0;

	do {
		int fd = open(devname, O_RDONLY);
		if (fd >= 0)
			return fd;
		if (errno != ENOMEDIUM)
			break;
		if (retries >= CRDOM_NOMEDIUM_RETRIES)
			break;
		++retries;
		sleep(3);
	} while(1);

	return -1;
}
#endif

/*
 * Parses NAME=value, returns -1 on parse error, 0 success. The success is also
 * when the 'spec' doesn't contain name=value pair (because the spec could be
 * a devname too). In particular case the pointer 'name' is set to NULL.
 */
int
fsprobe_parse_spec(const char *spec, char **name, char **value)
{
	*name = NULL;
	*value = NULL;

	if (strchr(spec, '='))
		return blkid_parse_tag_string(spec, name, value);

	return 0;
}

char *
fsprobe_get_devname_by_spec(const char *spec)
{
	char *name, *value;

	if (!spec)
		return NULL;
	if (fsprobe_parse_spec(spec, &name, &value) != 0)
		return NULL;				/* parse error */
	if (name) {
		char *nspec = NULL;

		if (!strcmp(name,"LABEL"))
			nspec = fsprobe_get_devname_by_label(value);
		else if (!strcmp(name,"UUID"))
			nspec = fsprobe_get_devname_by_uuid(value);

		free(name);
		free(value);
		return nspec;
	}

	return canonicalize_path(spec);
}

void
fsprobe_init(void)
{
	blcache = NULL;
}

int
fsprobe_known_fstype(const char *fstype)
{
	return blkid_known_fstype(fstype);
}

#ifdef HAVE_LIBBLKID_INTERNAL
/*
 * libblkid from util-linux-ng
 * -- recommended
 */
static blkid_probe blprobe;

void
fsprobe_exit(void)
{
	if (blprobe)
		blkid_free_probe(blprobe);
	if (blcache)
		blkid_put_cache(blcache);
}

/* returns device LABEL, UUID, FSTYPE, ... by low-level
 * probing interface
 */
static char *
fsprobe_get_value(const char *name, const char *devname)
{
	int fd;
	const char *data = NULL;

	if (!devname || !name)
		return NULL;
	fd = open_device(devname);
	if (fd < 0)
		return NULL;
	if (!blprobe)
		blprobe = blkid_new_probe();
	if (!blprobe)
		goto done;
	if (blkid_probe_set_device(blprobe, fd, 0, 0))
		goto done;

	blkid_probe_enable_superblocks(blprobe, 1);

	blkid_probe_set_superblocks_flags(blprobe,
		BLKID_SUBLKS_LABEL | BLKID_SUBLKS_UUID | BLKID_SUBLKS_TYPE);

	if (blkid_do_safeprobe(blprobe))
		goto done;
	if (blkid_probe_lookup_value(blprobe, name, &data, NULL))
		goto done;
done:
	close(fd);
	return data ? strdup((char *) data) : NULL;
}

char *
fsprobe_get_label_by_devname(const char *devname)
{
	return fsprobe_get_value("LABEL", devname);
}

char *
fsprobe_get_uuid_by_devname(const char *devname)
{
	return fsprobe_get_value("UUID", devname);
}

char *
fsprobe_get_fstype_by_devname(const char *devname)
{
	return fsprobe_get_value("TYPE", devname);
}

char *
fsprobe_get_devname_by_uuid(const char *uuid)
{
	return blkid_evaluate_tag("UUID", uuid, &blcache);
}

char *
fsprobe_get_devname_by_label(const char *label)
{
	return blkid_evaluate_tag("LABEL", label, &blcache);
}

#else /* !HAVE_LIBBLKID_INTERNAL */

/*
 * Classic libblkid (from e2fsprogs) without blkid_evaluate_tag()
 * -- deprecated
 */
#define BLKID_EMPTY_CACHE	"/dev/null"

void
fsprobe_exit(void)
{
	if (blcache)
		blkid_put_cache(blcache);
}

char *
fsprobe_get_devname_by_uuid(const char *uuid)
{
	if (!blcache)
		blkid_get_cache(&blcache, NULL);

	return blkid_get_devname(blcache, "UUID", uuid);
}

char *
fsprobe_get_devname_by_label(const char *label)
{
	if (!blcache)
		blkid_get_cache(&blcache, NULL);

	return blkid_get_devname(blcache, "LABEL", label);
}

char *
fsprobe_get_fstype_by_devname(const char *devname)
{
	blkid_cache c;
	char *tp;

	if (blcache)
		return blkid_get_tag_value(blcache, "TYPE", devname);

	/* The cache is not initialized yet. Use empty cache rather than waste
	 * time with /etc/blkid.tab. It seems that probe FS is faster than
	 * parse the cache file.  -- kzak (17-May-2007)
	 */
	blkid_get_cache(&c, BLKID_EMPTY_CACHE);
	tp = blkid_get_tag_value(c, "TYPE", devname);
	blkid_put_cache(c);

	return tp;
}

char *
fsprobe_get_label_by_devname(const char *devname)
{
	if (!blcache)
		blkid_get_cache(&blcache, NULL);

	return blkid_get_tag_value(blcache, "LABEL", devname);
}

char *
fsprobe_get_uuid_by_devname(const char *devname)
{
	if (!blcache)
		blkid_get_cache(&blcache, NULL);

	return blkid_get_tag_value(blcache, "UUID", devname);
}

#endif /* !HAVE_LIBBLKID_INTERNAL */