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