(root)/
util-linux-2.39/
libblkid/
src/
tag.c
       1  /*
       2   * tag.c - allocation/initialization/free routines for tag structs
       3   *
       4   * Copyright (C) 2001 Andreas Dilger
       5   * Copyright (C) 2003 Theodore Ts'o
       6   *
       7   * %Begin-Header%
       8   * This file may be redistributed under the terms of the
       9   * GNU Lesser General Public License.
      10   * %End-Header%
      11   */
      12  
      13  #include <unistd.h>
      14  #include <stdlib.h>
      15  #include <string.h>
      16  #include <stdio.h>
      17  
      18  #include "blkidP.h"
      19  
      20  static blkid_tag blkid_new_tag(void)
      21  {
      22  	blkid_tag tag;
      23  
      24  	if (!(tag = calloc(1, sizeof(struct blkid_struct_tag))))
      25  		return NULL;
      26  
      27  	DBG(TAG, ul_debugobj(tag, "alloc"));
      28  	INIT_LIST_HEAD(&tag->bit_tags);
      29  	INIT_LIST_HEAD(&tag->bit_names);
      30  
      31  	return tag;
      32  }
      33  
      34  void blkid_free_tag(blkid_tag tag)
      35  {
      36  	if (!tag)
      37  		return;
      38  
      39  	DBG(TAG, ul_debugobj(tag, "freeing tag %s (%s)", tag->bit_name, tag->bit_val));
      40  
      41  	list_del(&tag->bit_tags);	/* list of tags for this device */
      42  	list_del(&tag->bit_names);	/* list of tags with this type */
      43  
      44  	free(tag->bit_name);
      45  	free(tag->bit_val);
      46  
      47  	free(tag);
      48  }
      49  
      50  /*
      51   * Find the desired tag on a device.  If value is NULL, then the
      52   * first such tag is returned, otherwise return only exact tag if found.
      53   */
      54  blkid_tag blkid_find_tag_dev(blkid_dev dev, const char *type)
      55  {
      56  	struct list_head *p;
      57  
      58  	list_for_each(p, &dev->bid_tags) {
      59  		blkid_tag tmp = list_entry(p, struct blkid_struct_tag,
      60  					   bit_tags);
      61  
      62  		if (!strcmp(tmp->bit_name, type))
      63  			return tmp;
      64  	}
      65  	return NULL;
      66  }
      67  
      68  int blkid_dev_has_tag(blkid_dev dev, const char *type,
      69  			     const char *value)
      70  {
      71  	blkid_tag		tag;
      72  
      73  	tag = blkid_find_tag_dev(dev, type);
      74  	if (!value)
      75  		return (tag != NULL);
      76  	if (!tag || strcmp(tag->bit_val, value) != 0)
      77  		return 0;
      78  	return 1;
      79  }
      80  
      81  /*
      82   * Find the desired tag type in the cache.
      83   * We return the head tag for this tag type.
      84   */
      85  static blkid_tag blkid_find_head_cache(blkid_cache cache, const char *type)
      86  {
      87  	blkid_tag head = NULL, tmp;
      88  	struct list_head *p;
      89  
      90  	if (!cache || !type)
      91  		return NULL;
      92  
      93  	list_for_each(p, &cache->bic_tags) {
      94  		tmp = list_entry(p, struct blkid_struct_tag, bit_tags);
      95  		if (!strcmp(tmp->bit_name, type)) {
      96  			DBG(TAG, ul_debug("found cache tag head %s", type));
      97  			head = tmp;
      98  			break;
      99  		}
     100  	}
     101  	return head;
     102  }
     103  
     104  /*
     105   * Set a tag on an existing device.
     106   *
     107   * If value is NULL, then delete the tags from the device.
     108   */
     109  int blkid_set_tag(blkid_dev dev, const char *name,
     110  		  const char *value, const int vlength)
     111  {
     112  	blkid_tag	t = NULL, head = NULL;
     113  	char		*val = NULL;
     114  	char		**dev_var = NULL;
     115  
     116  	if (value && !(val = strndup(value, vlength)))
     117  		return -BLKID_ERR_MEM;
     118  
     119  	/*
     120  	 * Certain common tags are linked directly to the device struct
     121  	 * We need to know what they are before we do anything else because
     122  	 * the function name parameter might get freed later on.
     123  	 */
     124  	if (!strcmp(name, "TYPE"))
     125  		dev_var = &dev->bid_type;
     126  	else if (!strcmp(name, "LABEL"))
     127  		dev_var = &dev->bid_label;
     128  	else if (!strcmp(name, "UUID"))
     129  		dev_var = &dev->bid_uuid;
     130  
     131  	t = blkid_find_tag_dev(dev, name);
     132  	if (!value) {
     133  		if (t)
     134  			blkid_free_tag(t);
     135  	} else if (t) {
     136  		if (!strcmp(t->bit_val, val)) {
     137  			/* Same thing, exit */
     138  			free(val);
     139  			return 0;
     140  		}
     141  		DBG(TAG, ul_debugobj(t, "update (%s) '%s' -> '%s'", t->bit_name, t->bit_val, val));
     142  		free(t->bit_val);
     143  		t->bit_val = val;
     144  	} else {
     145  		/* Existing tag not present, add to device */
     146  		if (!(t = blkid_new_tag()))
     147  			goto errout;
     148  		t->bit_name = strdup(name);
     149  		t->bit_val = val;
     150  		t->bit_dev = dev;
     151  
     152  		DBG(TAG, ul_debugobj(t, "setting (%s) '%s'", t->bit_name, t->bit_val));
     153  		list_add_tail(&t->bit_tags, &dev->bid_tags);
     154  
     155  		if (dev->bid_cache) {
     156  			head = blkid_find_head_cache(dev->bid_cache,
     157  						     t->bit_name);
     158  			if (!head) {
     159  				head = blkid_new_tag();
     160  				if (!head)
     161  					goto errout;
     162  
     163  				DBG(TAG, ul_debugobj(head, "creating new cache tag head %s", name));
     164  				head->bit_name = strdup(name);
     165  				if (!head->bit_name)
     166  					goto errout;
     167  				list_add_tail(&head->bit_tags,
     168  					      &dev->bid_cache->bic_tags);
     169  			}
     170  			list_add_tail(&t->bit_names, &head->bit_names);
     171  		}
     172  	}
     173  
     174  	/* Link common tags directly to the device struct */
     175  	if (dev_var)
     176  		*dev_var = val;
     177  
     178  	if (dev->bid_cache)
     179  		dev->bid_cache->bic_flags |= BLKID_BIC_FL_CHANGED;
     180  	return 0;
     181  
     182  errout:
     183  	if (t)
     184  		blkid_free_tag(t);
     185  	else
     186  		free(val);
     187  	if (head)
     188  		blkid_free_tag(head);
     189  	return -BLKID_ERR_MEM;
     190  }
     191  
     192  
     193  /*
     194   * Parse a "NAME=value" string.  This is slightly different than
     195   * parse_token, because that will end an unquoted value at a space, while
     196   * this will assume that an unquoted value is the rest of the token (e.g.
     197   * if we are passed an already quoted string from the command-line we don't
     198   * have to both quote and escape quote so that the quotes make it to
     199   * us).
     200   *
     201   * Returns 0 on success, and -1 on failure.
     202   */
     203  int blkid_parse_tag_string(const char *token, char **ret_type, char **ret_val)
     204  {
     205  	char *name, *value, *cp;
     206  
     207  	DBG(TAG, ul_debug("trying to parse '%s' as a tag", token));
     208  
     209  	if (!token || !(cp = strchr(token, '=')))
     210  		return -1;
     211  
     212  	name = strdup(token);
     213  	if (!name)
     214  		return -1;
     215  	value = name + (cp - token);
     216  	*value++ = '\0';
     217  	if (*value == '"' || *value == '\'') {
     218  		char c = *value++;
     219  		if (!(cp = strrchr(value, c)))
     220  			goto errout; /* missing closing quote */
     221  		*cp = '\0';
     222  	}
     223  
     224  	if (ret_val) {
     225  		value = *value ? strdup(value) : NULL;
     226  		if (!value)
     227  			goto errout;
     228  		*ret_val = value;
     229  	}
     230  
     231  	if (ret_type)
     232  		*ret_type = name;
     233  	else
     234  		free(name);
     235  
     236  	return 0;
     237  
     238  errout:
     239  	DBG(TAG, ul_debug("parse error: '%s'", token));
     240  	free(name);
     241  	return -1;
     242  }
     243  
     244  /*
     245   * Tag iteration routines for the public libblkid interface.
     246   *
     247   * These routines do not expose the list.h implementation, which are a
     248   * contamination of the namespace, and which force us to reveal far, far
     249   * too much of our internal implementation.  I'm not convinced I want
     250   * to keep list.h in the long term, anyway.  It's fine for kernel
     251   * programming, but performance is not the #1 priority for this
     252   * library, and I really don't like the trade-off of type-safety for
     253   * performance for this application.  [tytso:20030125.2007EST]
     254   */
     255  
     256  /*
     257   * This series of functions iterate over all tags in a device
     258   */
     259  #define TAG_ITERATE_MAGIC	0x01a5284c
     260  
     261  struct blkid_struct_tag_iterate {
     262  	int			magic;
     263  	blkid_dev		dev;
     264  	struct list_head	*p;
     265  };
     266  
     267  blkid_tag_iterate blkid_tag_iterate_begin(blkid_dev dev)
     268  {
     269  	blkid_tag_iterate	iter;
     270  
     271  	if (!dev) {
     272  		errno = EINVAL;
     273  		return NULL;
     274  	}
     275  
     276  	iter = malloc(sizeof(struct blkid_struct_tag_iterate));
     277  	if (iter) {
     278  		iter->magic = TAG_ITERATE_MAGIC;
     279  		iter->dev = dev;
     280  		iter->p	= dev->bid_tags.next;
     281  	}
     282  	return (iter);
     283  }
     284  
     285  /*
     286   * Return 0 on success, -1 on error
     287   */
     288  int blkid_tag_next(blkid_tag_iterate iter,
     289  			  const char **type, const char **value)
     290  {
     291  	blkid_tag tag;
     292  
     293  	if (!type || !value ||
     294  	    !iter || iter->magic != TAG_ITERATE_MAGIC ||
     295  	    iter->p == &iter->dev->bid_tags)
     296  		return -1;
     297  
     298  	*type = NULL;
     299  	*value = NULL;
     300  	tag = list_entry(iter->p, struct blkid_struct_tag, bit_tags);
     301  	*type = tag->bit_name;
     302  	*value = tag->bit_val;
     303  	iter->p = iter->p->next;
     304  	return 0;
     305  }
     306  
     307  void blkid_tag_iterate_end(blkid_tag_iterate iter)
     308  {
     309  	if (!iter || iter->magic != TAG_ITERATE_MAGIC)
     310  		return;
     311  	iter->magic = 0;
     312  	free(iter);
     313  }
     314  
     315  /*
     316   * This function returns a device which matches a particular
     317   * type/value pair.  If there is more than one device that matches the
     318   * search specification, it returns the one with the highest priority
     319   * value.  This allows us to give preference to EVMS or LVM devices.
     320   */
     321  blkid_dev blkid_find_dev_with_tag(blkid_cache cache,
     322  					 const char *type,
     323  					 const char *value)
     324  {
     325  	blkid_tag	head;
     326  	blkid_dev	dev;
     327  	int		pri;
     328  	struct list_head *p;
     329  	int		probe_new = 0, probe_all = 0;
     330  
     331  	if (!cache || !type || !value)
     332  		return NULL;
     333  
     334  	blkid_read_cache(cache);
     335  
     336  	DBG(TAG, ul_debug("looking for tag %s=%s in cache", type, value));
     337  
     338  try_again:
     339  	pri = -1;
     340  	dev = NULL;
     341  	head = blkid_find_head_cache(cache, type);
     342  
     343  	if (head) {
     344  		list_for_each(p, &head->bit_names) {
     345  			blkid_tag tmp = list_entry(p, struct blkid_struct_tag,
     346  						   bit_names);
     347  
     348  			if (!strcmp(tmp->bit_val, value) &&
     349  			    (tmp->bit_dev->bid_pri > pri) &&
     350  			    !access(tmp->bit_dev->bid_name, F_OK)) {
     351  				dev = tmp->bit_dev;
     352  				pri = dev->bid_pri;
     353  			}
     354  		}
     355  	}
     356  	if (dev && !(dev->bid_flags & BLKID_BID_FL_VERIFIED)) {
     357  		dev = blkid_verify(cache, dev);
     358  		if (!dev || dev->bid_flags & BLKID_BID_FL_VERIFIED)
     359  			goto try_again;
     360  	}
     361  
     362  	if (!dev && !probe_new) {
     363  		if (blkid_probe_all_new(cache) < 0)
     364  			return NULL;
     365  		probe_new++;
     366  		goto try_again;
     367  	}
     368  
     369  	if (!dev && !probe_all
     370  	    && !(cache->bic_flags & BLKID_BIC_FL_PROBED)) {
     371  		if (blkid_probe_all(cache) < 0)
     372  			return NULL;
     373  		probe_all++;
     374  		goto try_again;
     375  	}
     376  	return dev;
     377  }
     378  
     379  #ifdef TEST_PROGRAM
     380  #ifdef HAVE_GETOPT_H
     381  #include <getopt.h>
     382  #else
     383  extern char *optarg;
     384  extern int optind;
     385  #endif
     386  
     387  static void __attribute__((__noreturn__)) usage(char *prog)
     388  {
     389  	fprintf(stderr, "Usage: %s [-f blkid_file] [-m debug_mask] device "
     390  		"[type value]\n",
     391  		prog);
     392  	fprintf(stderr, "\tList all tags for a device and exit\n");
     393  	exit(1);
     394  }
     395  
     396  int main(int argc, char **argv)
     397  {
     398  	blkid_tag_iterate	iter;
     399  	blkid_cache 		cache = NULL;
     400  	blkid_dev		dev;
     401  	int			c, ret, found;
     402  	int			flags = BLKID_DEV_FIND;
     403  	char			*tmp;
     404  	char			*file = NULL;
     405  	char			*devname = NULL;
     406  	char			*search_type = NULL;
     407  	char			*search_value = NULL;
     408  	const char		*type, *value;
     409  
     410  	while ((c = getopt (argc, argv, "m:f:")) != EOF)
     411  		switch (c) {
     412  		case 'f':
     413  			file = optarg;
     414  			break;
     415  		case 'm':
     416  		{
     417  			int mask = strtoul (optarg, &tmp, 0);
     418  			if (*tmp) {
     419  				fprintf(stderr, "Invalid debug mask: %s\n",
     420  					optarg);
     421  				exit(1);
     422  			}
     423  			blkid_init_debug(mask);
     424  			break;
     425  		}
     426  		case '?':
     427  			usage(argv[0]);
     428  		}
     429  	if (argc > optind)
     430  		devname = argv[optind++];
     431  	if (argc > optind)
     432  		search_type = argv[optind++];
     433  	if (argc > optind)
     434  		search_value = argv[optind++];
     435  	if (!devname || (argc != optind))
     436  		usage(argv[0]);
     437  
     438  	if ((ret = blkid_get_cache(&cache, file)) != 0) {
     439  		fprintf(stderr, "%s: error creating cache (%d)\n",
     440  			argv[0], ret);
     441  		exit(1);
     442  	}
     443  
     444  	dev = blkid_get_dev(cache, devname, flags);
     445  	if (!dev) {
     446  		fprintf(stderr, "%s: cannot find device in blkid cache\n",
     447  			devname);
     448  		exit(1);
     449  	}
     450  	if (search_type) {
     451  		found = blkid_dev_has_tag(dev, search_type, search_value);
     452  		printf("Device %s: (%s, %s) %s\n", blkid_dev_devname(dev),
     453  		       search_type, search_value ? search_value : "NULL",
     454  		       found ? "FOUND" : "NOT FOUND");
     455  		return(!found);
     456  	}
     457  	printf("Device %s...\n", blkid_dev_devname(dev));
     458  
     459  	iter = blkid_tag_iterate_begin(dev);
     460  	while (blkid_tag_next(iter, &type, &value) == 0) {
     461  		printf("\tTag %s has value %s\n", type, value);
     462  	}
     463  	blkid_tag_iterate_end(iter);
     464  
     465  	blkid_put_cache(cache);
     466  	return (0);
     467  }
     468  #endif