zdev: Improve handling of invalid udev rules

Add basic checking when reading udev rules and print a warning when an
invalid udev rule file is found. This addresses the current inconsistent
behavior:

  - CCW devices: invalid udev rules are considered valid
  - CCW group devices: invalid udev rules are silently ignored
  - zFCP LUNs: invalid rules cause chzdev/lszdev to silently terminate
    with non-zero exit code

Checks include a test for empty or truncated rule files that might be
the result of an interrupted chzdev operation, or a file system or I/O
error.

Note: The recommended way to correct invalid udev rules is to either
remove the offending rules file, or to repeat the associated persistent
configuration step.

Signed-off-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Reported-by: Steffen Maier <maier@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
This commit is contained in:
Peter Oberparleiter
2019-07-31 13:39:19 +02:00
committed by Jan Höppner
parent 5693c16894
commit 8b3cc6e4c1
5 changed files with 45 additions and 10 deletions

View File

@@ -40,6 +40,7 @@ struct udev_file {
};
exit_code_t udev_read_file(const char *, struct udev_file **);
bool udev_file_is_empty(struct udev_file *file);
void udev_free_file(struct udev_file *);
void udev_file_print(struct udev_file *);

View File

@@ -346,6 +346,21 @@ exit_code_t udev_read_file(const char *path, struct udev_file **file_ptr)
return EXIT_OK;
}
/* Check if a udev file does not contain any statements. */
bool udev_file_is_empty(struct udev_file *file)
{
struct udev_line_node *l;
if (!file)
return true;
util_list_iterate(&file->lines, l) {
if (l->line[0])
return false;
}
return true;
}
static bool get_ids_cb(const char *filename, void *data)
{
char *prefix = data;

View File

@@ -108,8 +108,13 @@ exit_code_t udev_ccw_read_device(struct device *dev, bool autoconf)
rc = udev_read_file(path, &file);
if (rc)
goto out;
udev_file_get_settings(file, st->dev_attribs, state->settings);
state->exists = 1;
if (udev_file_is_empty(file)) {
warn_once("Warning: Invalid udev rule: %s\n", path);
state->exists = 0;
} else {
udev_file_get_settings(file, st->dev_attribs, state->settings);
state->exists = 1;
}
udev_free_file(file);
out:

View File

@@ -163,9 +163,14 @@ exit_code_t udev_ccwgroup_read_device(struct device *dev, bool autoconf)
rc = udev_read_file(path, &file);
if (rc)
goto out;
udev_file_get_settings(file, st->dev_attribs, state->settings);
expand_id(dev, file);
state->exists = 1;
if (udev_file_is_empty(file)) {
warn_once("Warning: Invalid udev rule: %s\n", path);
state->exists = 0;
} else {
udev_file_get_settings(file, st->dev_attribs, state->settings);
expand_id(dev, file);
state->exists = 1;
}
udev_free_file(file);
out:
@@ -344,6 +349,9 @@ static char *read_full_id(const char *path)
out:
free(text);
if (!id)
warn_once("Warning: Invalid udev rule: %s\n", path);
return id;
}

View File

@@ -393,6 +393,9 @@ static exit_code_t udev_read_zfcp_lun_rule(const char *filename,
out:
udev_free_file(file);
if (!node)
warn_once("Warning: Invalid udev rule: %s\n", filename);
return rc;
}
@@ -475,11 +478,17 @@ static void zfcp_lun_node_to_state(struct zfcp_lun_node *node,
struct attrib *a;
char *name;
state->exists = 1;
state->modified = 0;
state->deconfigured = 0;
state->definable = 0;
if (!node) {
state->exists = 0;
return;
}
state->exists = 1;
util_list_iterate(&node->fc_settings->list, s) {
a = attrib_find(attribs, s->name);
setting_list_add(state->settings,
@@ -519,10 +528,7 @@ exit_code_t udev_zfcp_lun_read_device(struct device *dev, bool autoconf)
goto out;
node = zfcp_lun_node_find(luns, dev->devid);
if (node)
zfcp_lun_node_to_state(node, st->dev_attribs, state);
else
rc = EXIT_DEVICE_NOT_FOUND;
zfcp_lun_node_to_state(node, st->dev_attribs, state);
out:
zfcp_lun_node_list_free(luns);