mdadm/SOURCES/0155-mdadm-refactor-ident-n...

254 lines
7.1 KiB
Diff

From 67417d9222c505103357191bb0e0ae300892e8a9 Mon Sep 17 00:00:00 2001
From: Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>
Date: Thu, 1 Jun 2023 09:27:48 +0200
Subject: [PATCH 155/165] mdadm: refactor ident->name handling
Create dedicated setter for name in mddev_ident and propagate it.
Following changes are made:
- move duplicated code from config.c and mdadm.c into new function.
- Add error enum in mdadm.h.
- Use MD_NAME_MAX instead of hardcoded value in mddev_ident.
- Use secure functions.
- Add more detailed verification of the name.
- make error messages reusable for cmdline and config:
- for cmdline, these are errors so use pr_err().
- for config, these are just warnings, so use pr_info().
Signed-off-by: Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>
Signed-off-by: Jes Sorensen <jes@trained-monkey.org>
---
config.c | 77 ++++++++++++++++++++++++++++++++++++++++++++++++++------
lib.c | 18 +++++++++++++
mdadm.c | 12 +++------
mdadm.h | 20 ++++++++++-----
4 files changed, 104 insertions(+), 23 deletions(-)
diff --git a/config.c b/config.c
index 450880e3..a9a0b4f7 100644
--- a/config.c
+++ b/config.c
@@ -131,6 +131,34 @@ bool is_devname_ignore(char *devname)
return false;
}
+/**
+ * ident_log() - generate and write message to the user.
+ * @param_name: name of the property.
+ * @value: value of the property.
+ * @reason: meaningful description.
+ * @cmdline: context dependent actions, see below.
+ *
+ * The function is made to provide similar error handling for both config and cmdline. The behavior
+ * is configurable via @cmdline. Message has following format:
+ * "Value "@value" cannot be set for @param_name. Reason: @reason."
+ *
+ * If cmdline is on:
+ * - message is written to stderr.
+ * otherwise:
+ * - message is written to stdout.
+ * - "Value ignored" is added at the end of the message.
+ */
+static void ident_log(const char *param_name, const char *value, const char *reason,
+ const bool cmdline)
+{
+ if (cmdline == true)
+ pr_err("Value \"%s\" cannot be set as %s. Reason: %s.\n", value, param_name,
+ reason);
+ else
+ pr_info("Value \"%s\" cannot be set as %s. Reason: %s. Value ignored.\n", value,
+ param_name, reason);
+}
+
/**
* ident_init() - Set defaults.
* @ident: ident pointer, not NULL.
@@ -159,6 +187,46 @@ inline void ident_init(struct mddev_ident *ident)
ident->uuid_set = 0;
}
+/**
+ * _ident_set_name()- set name in &mddev_ident.
+ * @ident: pointer to &mddev_ident.
+ * @name: name to be set.
+ * @cmdline: context dependent actions.
+ *
+ * If criteria passed, set name in @ident.
+ *
+ * Return: %MDADM_STATUS_SUCCESS or %MDADM_STATUS_ERROR.
+ */
+static mdadm_status_t _ident_set_name(struct mddev_ident *ident, const char *name,
+ const bool cmdline)
+{
+ assert(name);
+ assert(ident);
+
+ const char *prop_name = "name";
+
+ if (ident->name[0]) {
+ ident_log(prop_name, name, "Already defined", cmdline);
+ return MDADM_STATUS_ERROR;
+ }
+
+ if (is_string_lq(name, MD_NAME_MAX + 1) == false) {
+ ident_log(prop_name, name, "Too long or empty", cmdline);
+ return MDADM_STATUS_ERROR;
+ }
+
+ snprintf(ident->name, MD_NAME_MAX + 1, "%s", name);
+ return MDADM_STATUS_SUCCESS;
+}
+
+/**
+ * ident_set_name()- exported, for cmdline.
+ */
+mdadm_status_t ident_set_name(struct mddev_ident *ident, const char *name)
+{
+ return _ident_set_name(ident, name, true);
+}
+
struct conf_dev {
struct conf_dev *next;
char *name;
@@ -444,14 +512,7 @@ void arrayline(char *line)
mis.super_minor = minor;
}
} else if (strncasecmp(w, "name=", 5) == 0) {
- if (mis.name[0])
- pr_err("only specify name once, %s ignored.\n",
- w);
- else if (strlen(w + 5) > 32)
- pr_err("name too long, ignoring %s\n", w);
- else
- strcpy(mis.name, w + 5);
-
+ _ident_set_name(&mis, w + 5, false);
} else if (strncasecmp(w, "bitmap=", 7) == 0) {
if (mis.bitmap_file)
pr_err("only specify bitmap file once. %s ignored\n",
diff --git a/lib.c b/lib.c
index 8a4b48e0..03198e2d 100644
--- a/lib.c
+++ b/lib.c
@@ -27,6 +27,24 @@
#include <ctype.h>
#include <limits.h>
+/**
+ * is_string_lq() - Check if string length with NULL byte is lower or equal to requested.
+ * @str: string to check.
+ * @max_len: max length.
+ *
+ * @str length must be bigger than 0 and be lower or equal @max_len, including termination byte.
+ */
+bool is_string_lq(const char * const str, size_t max_len)
+{
+ assert(str);
+
+ size_t _len = strnlen(str, max_len);
+
+ if (_len > 0 && _len < max_len)
+ return true;
+ return false;
+}
+
bool is_dev_alive(char *path)
{
if (!path)
diff --git a/mdadm.c b/mdadm.c
index 0a56ed26..8bc9304e 100644
--- a/mdadm.c
+++ b/mdadm.c
@@ -690,20 +690,14 @@ int main(int argc, char *argv[])
case O(CREATE,'N'):
case O(ASSEMBLE,'N'):
case O(MISC,'N'):
- if (ident.name[0]) {
- pr_err("name cannot be set twice. Second value %s.\n", optarg);
- exit(2);
- }
if (mode == MISC && !c.subarray) {
pr_err("-N/--name only valid with --update-subarray in misc mode\n");
exit(2);
}
- if (strlen(optarg) > 32) {
- pr_err("name '%s' is too long, 32 chars max.\n",
- optarg);
+
+ if (ident_set_name(&ident, optarg) != MDADM_STATUS_SUCCESS)
exit(2);
- }
- strcpy(ident.name, optarg);
+
continue;
case O(ASSEMBLE,'m'): /* super-minor for array */
diff --git a/mdadm.h b/mdadm.h
index 5678eb11..bbf386d6 100644
--- a/mdadm.h
+++ b/mdadm.h
@@ -294,6 +294,11 @@ static inline void __put_unaligned32(__u32 val, void *p)
#define KIB_TO_BYTES(x) ((x) << 10)
#define SEC_TO_BYTES(x) ((x) << 9)
+/**
+ * This is true for native and DDF, IMSM allows 16.
+ */
+#define MD_NAME_MAX 32
+
extern const char Name[];
struct md_bb_entry {
@@ -425,6 +430,12 @@ struct spare_criteria {
unsigned int sector_size;
};
+typedef enum mdadm_status {
+ MDADM_STATUS_SUCCESS = 0,
+ MDADM_STATUS_ERROR,
+ MDADM_STATUS_UNDEF,
+} mdadm_status_t;
+
enum mode {
ASSEMBLE=1,
BUILD,
@@ -593,7 +604,7 @@ struct mddev_ident {
int uuid_set;
int uuid[4];
- char name[33];
+ char name[MD_NAME_MAX + 1];
int super_minor;
@@ -1609,6 +1620,7 @@ extern int check_partitions(int fd, char *dname,
extern int fstat_is_blkdev(int fd, char *devname, dev_t *rdev);
extern int stat_is_blkdev(char *devname, dev_t *rdev);
+extern bool is_string_lq(const char * const str, size_t max_len);
extern bool is_dev_alive(char *path);
extern int get_mdp_major(void);
extern int get_maj_min(char *dev, int *major, int *minor);
@@ -1626,6 +1638,7 @@ extern void manage_fork_fds(int close_all);
extern int continue_via_systemd(char *devnm, char *service_name, char *prefix);
extern void ident_init(struct mddev_ident *ident);
+extern mdadm_status_t ident_set_name(struct mddev_ident *ident, const char *name);
extern int parse_auto(char *str, char *msg, int config);
extern struct mddev_ident *conf_get_ident(char *dev);
@@ -2002,11 +2015,6 @@ enum r0layout {
/* And another special number needed for --data_offset=variable */
#define VARIABLE_OFFSET 3
-/**
- * This is true for native and DDF, IMSM allows 16.
- */
-#define MD_NAME_MAX 32
-
/**
* is_container() - check if @level is &LEVEL_CONTAINER
* @level: level value
--
2.40.1