diff options
author | Anas Nashif <anas.nashif@intel.com> | 2013-03-05 01:43:20 -0800 |
---|---|---|
committer | Anas Nashif <anas.nashif@intel.com> | 2013-03-05 01:43:20 -0800 |
commit | 8bd28eea831fd5215c12e6fcecc8e9a772398ed9 (patch) | |
tree | 2579ba0d9921953cadfc17006c47ff419382898a /lib/misc/lvm-string.c | |
download | device-mapper-8bd28eea831fd5215c12e6fcecc8e9a772398ed9.tar.gz device-mapper-8bd28eea831fd5215c12e6fcecc8e9a772398ed9.tar.bz2 device-mapper-8bd28eea831fd5215c12e6fcecc8e9a772398ed9.zip |
Imported Upstream version 2.02.79upstream/2.02.79
Diffstat (limited to 'lib/misc/lvm-string.c')
-rw-r--r-- | lib/misc/lvm-string.c | 382 |
1 files changed, 382 insertions, 0 deletions
diff --git a/lib/misc/lvm-string.c b/lib/misc/lvm-string.c new file mode 100644 index 0000000..8fd2c04 --- /dev/null +++ b/lib/misc/lvm-string.c @@ -0,0 +1,382 @@ +/* + * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. + * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved. + * + * This file is part of LVM2. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU Lesser General Public License v.2.1. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "lib.h" +#include "lvm-string.h" + +#include <ctype.h> + +int emit_to_buffer(char **buffer, size_t *size, const char *fmt, ...) +{ + int n; + va_list ap; + + va_start(ap, fmt); + n = vsnprintf(*buffer, *size, fmt, ap); + va_end(ap); + + /* + * Revert to old glibc behaviour (version <= 2.0.6) where snprintf + * returned -1 if buffer was too small. From glibc 2.1 it returns number + * of chars that would have been written had there been room. + */ + if (n < 0 || ((unsigned) n + 1 > *size)) + n = -1; + + if (n < 0 || ((size_t)n == *size)) + return 0; + + *buffer += n; + *size -= n; + return 1; +} + +/* + * Count occurences of 'c' in 'str' until we reach a null char. + * + * Returns: + * len - incremented for each char we encounter. + * count - number of occurrences of 'c' and 'c2'. + */ +static void _count_chars(const char *str, size_t *len, int *count, + const int c1, const int c2) +{ + const char *ptr; + + for (ptr = str; *ptr; ptr++, (*len)++) + if (*ptr == c1 || *ptr == c2) + (*count)++; +} + +/* + * Count occurences of 'c' in 'str' of length 'size'. + * + * Returns: + * Number of occurrences of 'c' + */ +unsigned count_chars(const char *str, size_t len, const int c) +{ + size_t i; + unsigned count = 0; + + for (i = 0; i < len; i++) + if (str[i] == c) + count++; + + return count; +} + +/* + * Length of string after escaping double quotes and backslashes. + */ +size_t escaped_len(const char *str) +{ + size_t len = 1; + int count = 0; + + _count_chars(str, &len, &count, '\"', '\\'); + + return count + len; +} + +/* + * Copies a string, quoting orig_char with quote_char. + * Optionally also quote quote_char. + */ +static void _quote_characters(char **out, const char *src, + const int orig_char, const int quote_char, + int quote_quote_char) +{ + while (*src) { + if (*src == orig_char || + (*src == quote_char && quote_quote_char)) + *(*out)++ = quote_char; + + *(*out)++ = *src++; + } +} + +static void _unquote_one_character(char *src, const char orig_char, + const char quote_char) +{ + char *out; + char s, n; + + /* Optimise for the common case where no changes are needed. */ + while ((s = *src++)) { + if (s == quote_char && + ((n = *src) == orig_char || n == quote_char)) { + out = src++; + *(out - 1) = n; + + while ((s = *src++)) { + if (s == quote_char && + ((n = *src) == orig_char || n == quote_char)) { + s = n; + src++; + } + *out = s; + out++; + } + + *out = '\0'; + return; + } + } +} + +/* + * Unquote each character given in orig_char array and unquote quote_char + * as well. Also save the first occurrence of each character from orig_char + * that was found unquoted in arr_substr_first_unquoted array. This way we can + * process several characters in one go. + */ +static void _unquote_characters(char *src, const char *orig_chars, + const int num_orig_chars, + const char quote_char, + char *arr_substr_first_unquoted[]) +{ + char *out = src; + char c, s, n; + unsigned i; + + while ((s = *src++)) { + for (i = 0; i < num_orig_chars; i++) { + c = orig_chars[i]; + if (s == quote_char && + ((n = *src) == c || n == quote_char)) { + s = n; + src++; + break; + } + if (arr_substr_first_unquoted && (s == c) && + !arr_substr_first_unquoted[i]) + arr_substr_first_unquoted[i] = out; + }; + *out++ = s; + } + + *out = '\0'; +} + +/* + * Copies a string, quoting hyphens with hyphens. + */ +static void _quote_hyphens(char **out, const char *src) +{ + _quote_characters(out, src, '-', '-', 0); +} + +/* + * <vg>-<lv>-<layer> or if !layer just <vg>-<lv>. + */ +char *build_dm_name(struct dm_pool *mem, const char *vgname, + const char *lvname, const char *layer) +{ + size_t len = 1; + int hyphens = 1; + char *r, *out; + + _count_chars(vgname, &len, &hyphens, '-', 0); + _count_chars(lvname, &len, &hyphens, '-', 0); + + if (layer && *layer) { + _count_chars(layer, &len, &hyphens, '-', 0); + hyphens++; + } + + len += hyphens; + + if (!(r = dm_pool_alloc(mem, len))) { + log_error("build_dm_name: Allocation failed for %" PRIsize_t + " for %s %s %s.", len, vgname, lvname, layer); + return NULL; + } + + out = r; + _quote_hyphens(&out, vgname); + *out++ = '-'; + _quote_hyphens(&out, lvname); + + if (layer && *layer) { + /* No hyphen if the layer begins with _ e.g. _mlog */ + if (*layer != '_') + *out++ = '-'; + _quote_hyphens(&out, layer); + } + *out = '\0'; + + return r; +} + +char *build_dm_uuid(struct dm_pool *mem, const char *lvid, const char *layer) +{ + char *dmuuid; + size_t len; + + if (!layer) + layer = ""; + + len = sizeof(UUID_PREFIX) + strlen(lvid) + strlen(layer) + 1; + + if (!(dmuuid = dm_pool_alloc(mem, len))) { + log_error("build_dm_name: Allocation failed for %" PRIsize_t + " %s %s.", len, lvid, layer); + return NULL; + } + + sprintf(dmuuid, UUID_PREFIX "%s%s%s", lvid, (*layer) ? "-" : "", layer); + + return dmuuid; +} + +/* + * Copies a string, quoting double quotes with backslashes. + */ +char *escape_double_quotes(char *out, const char *src) +{ + char *buf = out; + + _quote_characters(&buf, src, '\"', '\\', 1); + *buf = '\0'; + + return out; +} + +/* + * Undo quoting in situ. + */ +void unescape_double_quotes(char *src) +{ + _unquote_one_character(src, '\"', '\\'); +} + +/* + * Unescape colons and "at" signs in situ and save the substrings + * starting at the position of the first unescaped colon and the + * first unescaped "at" sign. This is normally used to unescape + * device names used as PVs. + */ +void unescape_colons_and_at_signs(char *src, + char **substr_first_unquoted_colon, + char **substr_first_unquoted_at_sign) +{ + const char *orig_chars = ":@"; + char *arr_substr_first_unquoted[] = {NULL, NULL, NULL}; + + _unquote_characters(src, orig_chars, 2, '\\', arr_substr_first_unquoted); + + if (substr_first_unquoted_colon) + *substr_first_unquoted_colon = arr_substr_first_unquoted[0]; + + if (substr_first_unquoted_at_sign) + *substr_first_unquoted_at_sign = arr_substr_first_unquoted[1]; +} + +/* + * A-Za-z0-9._-+/=!:&# + */ +int validate_tag(const char *n) +{ + register char c; + register int len = 0; + + if (!n || !*n) + return 0; + + while ((len++, c = *n++)) + if (!isalnum(c) && c != '.' && c != '_' && c != '-' && c != '+' && c != '/' + && c != '=' && c != '!' && c != ':' && c != '&' && c != '#') + return 0; + + return 1; +} + +/* + * Device layer names are all of the form <vg>-<lv>-<layer>, any + * other hyphens that appear in these names are quoted with yet + * another hyphen. The top layer of any device has no layer + * name. eg, vg0-lvol0. + */ +int validate_name(const char *n) +{ + register char c; + register int len = 0; + + if (!n || !*n) + return 0; + + /* Hyphen used as VG-LV separator - ambiguity if LV starts with it */ + if (*n == '-') + return 0; + + if (!strcmp(n, ".") || !strcmp(n, "..")) + return 0; + + while ((len++, c = *n++)) + if (!isalnum(c) && c != '.' && c != '_' && c != '-' && c != '+') + return 0; + + if (len > NAME_LEN) + return 0; + + return 1; +} + +int apply_lvname_restrictions(const char *name) +{ + if (!strncmp(name, "snapshot", 8)) { + log_error("Names starting \"snapshot\" are reserved. " + "Please choose a different LV name."); + return 0; + } + + if (!strncmp(name, "pvmove", 6)) { + log_error("Names starting \"pvmove\" are reserved. " + "Please choose a different LV name."); + return 0; + } + + if (strstr(name, "_mlog")) { + log_error("Names including \"_mlog\" are reserved. " + "Please choose a different LV name."); + return 0; + } + + if (strstr(name, "_mimage")) { + log_error("Names including \"_mimage\" are reserved. " + "Please choose a different LV name."); + return 0; + } + + if (strstr(name, "_vorigin")) { + log_error("Names including \"_vorigin\" are reserved. " + "Please choose a different LV name."); + return 0; + } + + return 1; +} + +int is_reserved_lvname(const char *name) +{ + int rc, old_suppress; + + old_suppress = log_suppress(2); + rc = !apply_lvname_restrictions(name); + log_suppress(old_suppress); + + return rc; +} |