Home | History | Annotate | Line # | Download | only in misc
lvm-string.c revision 1.1.1.1
      1 /*	$NetBSD: lvm-string.c,v 1.1.1.1 2008/12/22 00:18:13 haad Exp $	*/
      2 
      3 /*
      4  * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
      5  * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
      6  *
      7  * This file is part of LVM2.
      8  *
      9  * This copyrighted material is made available to anyone wishing to use,
     10  * modify, copy, or redistribute it subject to the terms and conditions
     11  * of the GNU Lesser General Public License v.2.1.
     12  *
     13  * You should have received a copy of the GNU Lesser General Public License
     14  * along with this program; if not, write to the Free Software Foundation,
     15  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
     16  */
     17 
     18 #include "lib.h"
     19 #include "lvm-string.h"
     20 
     21 #include <ctype.h>
     22 
     23 int emit_to_buffer(char **buffer, size_t *size, const char *fmt, ...)
     24 {
     25 	int n;
     26 	va_list ap;
     27 
     28 	va_start(ap, fmt);
     29 	n = vsnprintf(*buffer, *size, fmt, ap);
     30 	va_end(ap);
     31 
     32 	if (n < 0 || ((size_t)n == *size))
     33 		return 0;
     34 
     35 	*buffer += n;
     36 	*size -= n;
     37 	return 1;
     38 }
     39 
     40 /*
     41  * Count occurences of 'c' in 'str' until we reach a null char.
     42  *
     43  * Returns:
     44  *  len - incremented for each char we encounter.
     45  *  count - number of occurrences of 'c' and 'c2'.
     46  */
     47 static void _count_chars(const char *str, size_t *len, int *count,
     48 			 const int c1, const int c2)
     49 {
     50 	const char *ptr;
     51 
     52 	for (ptr = str; *ptr; ptr++, (*len)++)
     53 		if (*ptr == c1 || *ptr == c2)
     54 			(*count)++;
     55 }
     56 
     57 /*
     58  * Count occurences of 'c' in 'str' of length 'size'.
     59  *
     60  * Returns:
     61  *   Number of occurrences of 'c'
     62  */
     63 unsigned count_chars(const char *str, size_t len, const int c)
     64 {
     65 	size_t i;
     66 	unsigned count = 0;
     67 
     68 	for (i = 0; i < len; i++)
     69 		if (str[i] == c)
     70 			count++;
     71 
     72 	return count;
     73 }
     74 
     75 /*
     76  * Length of string after escaping double quotes and backslashes.
     77  */
     78 size_t escaped_len(const char *str)
     79 {
     80 	size_t len = 1;
     81 	int count = 0;
     82 
     83 	_count_chars(str, &len, &count, '\"', '\\');
     84 
     85 	return count + len;
     86 }
     87 
     88 /*
     89  * Copies a string, quoting orig_char with quote_char.
     90  * Optionally also quote quote_char.
     91  */
     92 static void _quote_characters(char **out, const char *src,
     93 			      const int orig_char, const int quote_char,
     94 			      int quote_quote_char)
     95 {
     96 	while (*src) {
     97 		if (*src == orig_char ||
     98 		    (*src == quote_char && quote_quote_char))
     99 			*(*out)++ = quote_char;
    100 
    101 		*(*out)++ = *src++;
    102 	}
    103 }
    104 
    105 /*
    106  * Unquote orig_char in string.
    107  * Also unquote quote_char.
    108  */
    109 static void _unquote_characters(char *src, const int orig_char,
    110 				const int quote_char)
    111 {
    112 	char *out = src;
    113 
    114 	while (*src) {
    115 		if (*src == quote_char &&
    116 		    (*(src + 1) == orig_char || *(src + 1) == quote_char))
    117 			src++;
    118 
    119 		*out++ = *src++;
    120 	}
    121 
    122 	*out = '\0';
    123 }
    124 
    125 /*
    126  * Copies a string, quoting hyphens with hyphens.
    127  */
    128 static void _quote_hyphens(char **out, const char *src)
    129 {
    130 	return _quote_characters(out, src, '-', '-', 0);
    131 }
    132 
    133 /*
    134  * <vg>-<lv>-<layer> or if !layer just <vg>-<lv>.
    135  */
    136 char *build_dm_name(struct dm_pool *mem, const char *vgname,
    137 		    const char *lvname, const char *layer)
    138 {
    139 	size_t len = 1;
    140 	int hyphens = 1;
    141 	char *r, *out;
    142 
    143 	_count_chars(vgname, &len, &hyphens, '-', 0);
    144 	_count_chars(lvname, &len, &hyphens, '-', 0);
    145 
    146 	if (layer && *layer) {
    147 		_count_chars(layer, &len, &hyphens, '-', 0);
    148 		hyphens++;
    149 	}
    150 
    151 	len += hyphens;
    152 
    153 	if (!(r = dm_pool_alloc(mem, len))) {
    154 		log_error("build_dm_name: Allocation failed for %" PRIsize_t
    155 			  " for %s %s %s.", len, vgname, lvname, layer);
    156 		return NULL;
    157 	}
    158 
    159 	out = r;
    160 	_quote_hyphens(&out, vgname);
    161 	*out++ = '-';
    162 	_quote_hyphens(&out, lvname);
    163 
    164 	if (layer && *layer) {
    165 		/* No hyphen if the layer begins with _ e.g. _mlog */
    166 		if (*layer != '_')
    167 			*out++ = '-';
    168 		_quote_hyphens(&out, layer);
    169 	}
    170 	*out = '\0';
    171 
    172 	return r;
    173 }
    174 
    175 /*
    176  * Copies a string, quoting double quotes with backslashes.
    177  */
    178 char *escape_double_quotes(char *out, const char *src)
    179 {
    180 	char *buf = out;
    181 
    182 	_quote_characters(&buf, src, '\"', '\\', 1);
    183 	*buf = '\0';
    184 
    185 	return out;
    186 }
    187 
    188 /*
    189  * Undo quoting in situ.
    190  */
    191 void unescape_double_quotes(char *src)
    192 {
    193 	_unquote_characters(src, '\"', '\\');
    194 }
    195 
    196 /*
    197  * Device layer names are all of the form <vg>-<lv>-<layer>, any
    198  * other hyphens that appear in these names are quoted with yet
    199  * another hyphen.  The top layer of any device has no layer
    200  * name.  eg, vg0-lvol0.
    201  */
    202 int validate_name(const char *n)
    203 {
    204 	register char c;
    205 	register int len = 0;
    206 
    207 	if (!n || !*n)
    208 		return 0;
    209 
    210 	/* Hyphen used as VG-LV separator - ambiguity if LV starts with it */
    211 	if (*n == '-')
    212 		return 0;
    213 
    214 	if (!strcmp(n, ".") || !strcmp(n, ".."))
    215 		return 0;
    216 
    217 	while ((len++, c = *n++))
    218 		if (!isalnum(c) && c != '.' && c != '_' && c != '-' && c != '+')
    219 			return 0;
    220 
    221 	if (len > NAME_LEN)
    222 		return 0;
    223 
    224 	return 1;
    225 }
    226