mirror of
git://sourceware.org/git/lvm2.git
synced 2024-12-21 13:34:40 +03:00
lvm2app: Add VG/LV name validation
C library portion for https://bugzilla.redhat.com/show_bug.cgi?id=883689 Signed-off-by: Tony Asleson <tasleson@redhat.com>
This commit is contained in:
parent
e54e70dc66
commit
0dd247502a
@ -915,6 +915,35 @@ void display_segtypes(const struct cmd_context *cmd)
|
||||
}
|
||||
}
|
||||
|
||||
void display_name_error(name_error_t name_error)
|
||||
{
|
||||
if (name_error != NAME_VALID) {
|
||||
switch(name_error) {
|
||||
case NAME_INVALID_EMPTY:
|
||||
log_error("Name is zero length");
|
||||
break;
|
||||
case NAME_INVALID_HYPEN:
|
||||
log_error("Name cannot start with hyphen");
|
||||
break;
|
||||
case NAME_INVALID_DOTS:
|
||||
log_error("Name starts with . or .. and has no "
|
||||
"following character(s)");
|
||||
break;
|
||||
case NAME_INVALID_CHARSET:
|
||||
log_error("Name contains invalid character, valid set includes: "
|
||||
"[a-zA-Z0-9.-_+]");
|
||||
break;
|
||||
case NAME_INVALID_LENGTH:
|
||||
/* Report that name length -1 to accommodate nul*/
|
||||
log_error("Name length exceeds maximum limit of %d", (NAME_LEN -1));
|
||||
break;
|
||||
default:
|
||||
log_error("Unknown error %d on name validation", name_error);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Prompt for y or n from stdin.
|
||||
* Defaults to 'no' in silent mode.
|
||||
|
@ -18,6 +18,7 @@
|
||||
|
||||
#include "metadata-exported.h"
|
||||
#include "locking.h"
|
||||
#include "lvm-string.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
@ -53,6 +54,8 @@ void vgdisplay_short(const struct volume_group *vg);
|
||||
void display_formats(const struct cmd_context *cmd);
|
||||
void display_segtypes(const struct cmd_context *cmd);
|
||||
|
||||
void display_name_error(name_error_t name_error);
|
||||
|
||||
/*
|
||||
* Allocation policy display conversion routines.
|
||||
*/
|
||||
|
@ -581,6 +581,7 @@ int pv_analyze(struct cmd_context *cmd, const char *pv_name,
|
||||
/* FIXME: move internal to library */
|
||||
uint32_t pv_list_extents_free(const struct dm_list *pvh);
|
||||
|
||||
int validate_new_vg_name(struct cmd_context *cmd, const char *vg_name);
|
||||
int vg_validate(struct volume_group *vg);
|
||||
struct volume_group *vg_create(struct cmd_context *cmd, const char *vg_name);
|
||||
int vg_remove_mdas(struct volume_group *vg);
|
||||
|
@ -435,13 +435,15 @@ int move_pvs_used_by_lv(struct volume_group *vg_from,
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int validate_new_vg_name(struct cmd_context *cmd, const char *vg_name)
|
||||
int validate_new_vg_name(struct cmd_context *cmd, const char *vg_name)
|
||||
{
|
||||
static char vg_path[PATH_MAX];
|
||||
name_error_t name_error;
|
||||
|
||||
if (!validate_name(vg_name)) {
|
||||
log_error("New volume group name \"%s\" is invalid.",
|
||||
vg_name);
|
||||
name_error = validate_name_detailed(vg_name);
|
||||
if (NAME_VALID != name_error) {
|
||||
display_name_error(name_error);
|
||||
log_error("New volume group name \"%s\" is invalid.", vg_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -4574,7 +4576,7 @@ void mda_set_ignored(struct metadata_area *mda, unsigned mda_ignored)
|
||||
else
|
||||
return; /* No change */
|
||||
|
||||
log_debug_metadata("%s ignored flag for mda %s at offset %" PRIu64 ".",
|
||||
log_debug_metadata("%s ignored flag for mda %s at offset %" PRIu64 ".",
|
||||
mda_ignored ? "Setting" : "Clearing",
|
||||
mda->ops->mda_metadata_locn_name ? mda->ops->mda_metadata_locn_name(locn) : "",
|
||||
mda->ops->mda_metadata_locn_offset ? mda->ops->mda_metadata_locn_offset(locn) : UINT64_C(0));
|
||||
|
@ -63,6 +63,31 @@ int validate_tag(const char *n)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _validate_name(const char *n)
|
||||
{
|
||||
register char c;
|
||||
register int len = 0;
|
||||
|
||||
if (!n || !*n)
|
||||
return -1;
|
||||
|
||||
/* Hyphen used as VG-LV separator - ambiguity if LV starts with it */
|
||||
if (*n == '-')
|
||||
return -2;
|
||||
|
||||
if ((*n == '.') && (!n[1] || (n[1] == '.' && !n[2]))) /* ".", ".." */
|
||||
return -3;
|
||||
|
||||
while ((len++, c = *n++))
|
||||
if (!isalnum(c) && c != '.' && c != '_' && c != '-' && c != '+')
|
||||
return -4;
|
||||
|
||||
if (len > NAME_LEN)
|
||||
return -5;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Device layer names are all of the form <vg>-<lv>-<layer>, any
|
||||
* other hyphens that appear in these names are quoted with yet
|
||||
@ -71,27 +96,7 @@ int validate_tag(const char *n)
|
||||
*/
|
||||
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 ((*n == '.') && (!n[1] || (n[1] == '.' && !n[2]))) /* ".", ".." */
|
||||
return 0;
|
||||
|
||||
while ((len++, c = *n++))
|
||||
if (!isalnum(c) && c != '.' && c != '_' && c != '-' && c != '+')
|
||||
return 0;
|
||||
|
||||
if (len > NAME_LEN)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
return (_validate_name(n) < 0 ? 0 : 1);
|
||||
}
|
||||
|
||||
int apply_lvname_restrictions(const char *name)
|
||||
@ -136,6 +141,14 @@ int apply_lvname_restrictions(const char *name)
|
||||
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)
|
||||
{
|
||||
int rc, old_suppress;
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||
* 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.
|
||||
@ -24,6 +24,11 @@
|
||||
|
||||
struct pool;
|
||||
|
||||
typedef enum name_error { NAME_VALID = 0, NAME_INVALID_EMPTY = -1,
|
||||
NAME_INVALID_HYPEN = -2, NAME_INVALID_DOTS = -3,
|
||||
NAME_INVALID_CHARSET = -4, NAME_INVALID_LENGTH = -5}
|
||||
name_error_t;
|
||||
|
||||
int emit_to_buffer(char **buffer, size_t *size, const char *fmt, ...)
|
||||
__attribute__ ((format(printf, 3, 4)));
|
||||
|
||||
@ -31,6 +36,7 @@ char *build_dm_uuid(struct dm_pool *mem, const char *lvid,
|
||||
const char *layer);
|
||||
|
||||
int validate_name(const char *n);
|
||||
name_error_t validate_name_detailed(const char *n);
|
||||
int validate_tag(const char *n);
|
||||
|
||||
int apply_lvname_restrictions(const char *name);
|
||||
|
@ -509,6 +509,21 @@ const char *lvm_vgname_from_device(lvm_t libh, const char *device);
|
||||
vg_t lvm_vg_open(lvm_t libh, const char *vgname, const char *mode,
|
||||
uint32_t flags);
|
||||
|
||||
/**
|
||||
* Validate a name to be used for new VG construction.
|
||||
*
|
||||
* This function checks that the name has no invalid characters,
|
||||
* the length doesn't exceed maximum and that the VG name isn't already in use
|
||||
* and that the name adheres to any other limitations.
|
||||
*
|
||||
* \param libh
|
||||
* Valid library handle
|
||||
*
|
||||
* \param name
|
||||
* Name to validate for new VG create.
|
||||
*/
|
||||
int lvm_vg_name_validate(lvm_t libh, const char *vg_name);
|
||||
|
||||
/**
|
||||
* Create a VG with default parameters.
|
||||
*
|
||||
@ -1553,6 +1568,23 @@ int lvm_lv_resize(const lv_t lv, uint64_t new_size);
|
||||
*/
|
||||
lv_t lvm_lv_snapshot(const lv_t lv, const char *snap_name, uint64_t max_snap_size);
|
||||
|
||||
/**
|
||||
* Validate a name to be used for LV creation.
|
||||
*
|
||||
* Validates that the name does not contain any invalid characters, max length
|
||||
* and that the LV name doesn't already exist for this VG.
|
||||
*
|
||||
* Note: You can have the same LV name in different VGs, thus the reason this
|
||||
* function requires that you specify a VG to check against.
|
||||
*
|
||||
* \param lv
|
||||
* Volume group handle.
|
||||
*
|
||||
* \param name
|
||||
* Name to validate
|
||||
*/
|
||||
int lvm_lv_name_validate(const vg_t vg, const char *lv_name);
|
||||
|
||||
/**
|
||||
* Thin provisioning discard policies
|
||||
*/
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include "lvm-version.h"
|
||||
#include "metadata-exported.h"
|
||||
#include "lvm2app.h"
|
||||
#include "lvm-string.h"
|
||||
|
||||
const char *lvm_library_get_version(void)
|
||||
{
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include "lvmetad.h"
|
||||
#include "lvm_misc.h"
|
||||
#include "lvm2app.h"
|
||||
#include "display.h"
|
||||
|
||||
int lvm_vg_add_tag(vg_t vg, const char *tag)
|
||||
{
|
||||
@ -385,3 +386,32 @@ int lvm_scan(lvm_t libh)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lvm_lv_name_validate(const vg_t vg, const char *name)
|
||||
{
|
||||
name_error_t name_error;
|
||||
|
||||
name_error = validate_name_detailed(name);
|
||||
|
||||
if (NAME_VALID == name_error) {
|
||||
if (apply_lvname_restrictions(name)) {
|
||||
if (!find_lv_in_vg(vg, name)) {
|
||||
return 0;
|
||||
} else {
|
||||
log_errno(EINVAL, "LV name exists in VG");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
display_name_error(name_error);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int lvm_vg_name_validate(lvm_t libh, const char *name)
|
||||
{
|
||||
struct cmd_context *cmd = (struct cmd_context *)libh;
|
||||
|
||||
if (validate_new_vg_name(cmd, name))
|
||||
return 0;
|
||||
return -1;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user