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