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