| /* |
| * 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 "metadata-exported.h" |
| |
| #include <ctype.h> |
| #include <stdarg.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; |
| } |
| |
| /* |
| * A-Za-z0-9._-+/=!:&# |
| */ |
| int validate_tag(const char *n) |
| { |
| register char c; |
| /* int len = 0; */ |
| |
| if (!n || !*n) |
| return 0; |
| |
| /* FIXME: Is unlimited tag size support needed ? */ |
| while ((/* len++, */ c = *n++)) |
| if (!isalnum(c) && c != '.' && c != '_' && c != '-' && c != '+' && c != '/' |
| && c != '=' && c != '!' && c != ':' && c != '&' && c != '#') |
| return 0; |
| |
| return 1; |
| } |
| |
| static name_error_t _validate_name(const char *n) |
| { |
| register char c; |
| register int len = 0; |
| |
| if (!n || !*n) |
| return NAME_INVALID_EMPTY; |
| |
| /* Hyphen used as VG-LV separator - ambiguity if LV starts with it */ |
| if (*n == '-') |
| return NAME_INVALID_HYPHEN; |
| |
| if ((*n == '.') && (!n[1] || (n[1] == '.' && !n[2]))) /* ".", ".." */ |
| return NAME_INVALID_DOTS; |
| |
| while ((len++, c = *n++)) |
| if (!isalnum(c) && c != '.' && c != '_' && c != '-' && c != '+') |
| return NAME_INVALID_CHARSET; |
| |
| if (len > NAME_LEN) |
| return NAME_INVALID_LENGTH; |
| |
| return NAME_VALID; |
| } |
| |
| /* |
| * 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) |
| { |
| return (_validate_name(n) == NAME_VALID) ? 1 : 0; |
| } |
| |
| /* |
| * Copy valid systemid characters from source to destination. |
| * Invalid characters are skipped. Copying is stopped |
| * when NAME_LEN characters have been copied. |
| * A terminating NUL is appended. |
| */ |
| void copy_systemid_chars(const char *src, char *dst) |
| { |
| const char *s = src; |
| char *d = dst; |
| int len = 0; |
| char c; |
| |
| if (!s || !*s) |
| return; |
| |
| /* Skip non-alphanumeric starting characters */ |
| while (*s && !isalnum(*s)) |
| s++; |
| |
| while ((c = *s++)) { |
| if (!isalnum(c) && c != '.' && c != '_' && c != '-' && c != '+') |
| continue; |
| |
| *d++ = c; |
| |
| if (++len >= NAME_LEN) |
| break; |
| } |
| |
| *d = '\0'; |
| } |
| |
| static const char *_lvname_has_reserved_prefix(const char *lvname) |
| { |
| static const char _prefixes[][12] = { |
| "pvmove", |
| "snapshot" |
| }; |
| unsigned i; |
| |
| for (i = 0; i < DM_ARRAY_SIZE(_prefixes); ++i) |
| if (!strncmp(lvname, _prefixes[i], strlen(_prefixes[i]))) |
| return _prefixes[i]; |
| |
| return NULL; |
| } |
| |
| static const char *_lvname_has_reserved_string(const char *lvname) |
| { |
| static const char _strings[][12] = { |
| "_cdata", |
| "_cmeta", |
| "_corig", |
| "_mimage", |
| "_mlog", |
| "_pmspare", |
| "_rimage", |
| "_rmeta", |
| "_tdata", |
| "_tmeta", |
| "_vorigin" |
| }; |
| unsigned i; |
| |
| for (i = 0; i < DM_ARRAY_SIZE(_strings); ++i) |
| if (strstr(lvname, _strings[i])) |
| return _strings[i]; |
| |
| return NULL; |
| } |
| |
| |
| int apply_lvname_restrictions(const char *name) |
| { |
| const char *s; |
| |
| if ((s = _lvname_has_reserved_prefix(name))) { |
| log_error("Names starting \"%s\" are reserved. " |
| "Please choose a different LV name.", s); |
| return 0; |
| } |
| |
| if ((s = _lvname_has_reserved_string(name))) { |
| log_error("Names including \"%s\" are reserved. " |
| "Please choose a different LV name.", s); |
| return 0; |
| } |
| |
| return 1; |
| } |
| |
| /* |
| * Validates name and returns an emunerated reason for name validataion failure. |
| */ |
| name_error_t validate_name_detailed(const char *name) |
| { |
| return _validate_name(name); |
| } |
| |
| int is_reserved_lvname(const char *name) |
| { |
| return (_lvname_has_reserved_prefix(name) || |
| _lvname_has_reserved_string(name)) ? 1 : 0; |
| } |
| |
| char *build_dm_uuid(struct dm_pool *mem, const struct logical_volume *lv, |
| const char *layer) |
| { |
| const char *lvid = lv->lvid.s; |
| |
| if (!layer) { |
| /* |
| * Mark internal LVs with layer suffix |
| * so tools like blkid may immeditelly see it's |
| * an internal LV they should not scan. |
| * Should also make internal detection simpler. |
| */ |
| /* Suffixes used here MUST match lib/activate/dev_manager.c */ |
| layer = lv_is_cache_origin(lv) ? "real" : |
| (lv_is_cache(lv) && lv_is_pending_delete(lv)) ? "real" : |
| lv_is_cache_pool_data(lv) ? "cdata" : |
| lv_is_cache_pool_metadata(lv) ? "cmeta" : |
| // FIXME: dm-tree needs fixes for mirrors/raids |
| //lv_is_mirror_image(lv) ? "mimage" : |
| //lv_is_mirror_log(lv) ? "mlog" : |
| //lv_is_raid_image(lv) ? "rimage" : |
| //lv_is_raid_metadata(lv) ? "rmeta" : |
| lv_is_thin_pool(lv) ? "pool" : |
| lv_is_thin_pool_data(lv) ? "tdata" : |
| lv_is_thin_pool_metadata(lv) ? "tmeta" : |
| NULL; |
| } |
| |
| return dm_build_dm_uuid(mem, UUID_PREFIX, lvid, layer); |
| } |