mirror of
https://github.com/ibm-s390-linux/s390-tools.git
synced 2026-08-05 02:14:52 +00:00
Initial s390-tools-2.0.0 import
This commit is based on the s390-tools-1.39.0 version. Changes on top of s390-tools-1.39.0: - Add MIT license to all source files - Add LICENSE file - Transform REAMDE to README.md (markdown) - Add AUTHORS.md file - Add CONTRIBUTING.md file - Move changelog from README to CHANGELOG.md file Reviewed-by: Stefan Haberland <sth@linux.vnet.ibm.com> Signed-off-by: Michael Holzheu <holzheu@linux.vnet.ibm.com>
This commit is contained in:
412
zdev/src/devtype.c
Normal file
412
zdev/src/devtype.c
Normal file
@@ -0,0 +1,412 @@
|
||||
/*
|
||||
* zdev - Modify and display the persistent configuration of devices
|
||||
*
|
||||
* Copyright IBM Corp. 2016, 2017
|
||||
*
|
||||
* s390-tools is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the MIT license. See LICENSE for details.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
|
||||
#include "attrib.h"
|
||||
#include "ctc.h"
|
||||
#include "dasd.h"
|
||||
#include "device.h"
|
||||
#include "devnode.h"
|
||||
#include "devtype.h"
|
||||
#include "generic_ccw.h"
|
||||
#include "lcs.h"
|
||||
#include "misc.h"
|
||||
#include "module.h"
|
||||
#include "namespace.h"
|
||||
#include "qeth.h"
|
||||
#include "select.h"
|
||||
#include "setting.h"
|
||||
#include "subtype.h"
|
||||
#include "zfcp.h"
|
||||
|
||||
/* Array of pointers to known device types. */
|
||||
struct devtype *devtypes[] = {
|
||||
&dasd_devtype,
|
||||
&zfcp_devtype,
|
||||
&qeth_devtype,
|
||||
&ctc_devtype,
|
||||
&lcs_devtype,
|
||||
&generic_ccw_devtype, /* Generic types should come last. */
|
||||
NULL
|
||||
};
|
||||
|
||||
/* Call the init() function of each registered devtype and subtype. */
|
||||
void devtypes_init(void)
|
||||
{
|
||||
struct devtype *dt;
|
||||
struct subtype *st;
|
||||
int i, j;
|
||||
|
||||
for (i = 0; (dt = devtypes[i]); i++) {
|
||||
if (dt->init)
|
||||
dt->init(dt);
|
||||
for (j = 0; (st = dt->subtypes[j]); j++)
|
||||
subtype_init(st);
|
||||
}
|
||||
}
|
||||
|
||||
/* Call the exit() function of each registered devtype and subtype. */
|
||||
void devtypes_exit(void)
|
||||
{
|
||||
struct devtype *dt;
|
||||
struct subtype *st;
|
||||
int i, j;
|
||||
|
||||
for (i = 0; (dt = devtypes[i]); i++) {
|
||||
if (dt->exit)
|
||||
dt->exit(dt);
|
||||
for (j = 0; (st = dt->subtypes[j]); j++)
|
||||
subtype_exit(st);
|
||||
}
|
||||
}
|
||||
|
||||
/* Return struct devtype associated with NAME or NULL if type could not
|
||||
* be found. */
|
||||
struct devtype *devtype_find(const char *name)
|
||||
{
|
||||
int i;
|
||||
struct devtype *dt;
|
||||
|
||||
for (i = 0; (dt = devtypes[i]); i++) {
|
||||
if (strcasecmp(dt->name, name) == 0)
|
||||
return dt;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Search for a device type attribute named STR. */
|
||||
struct attrib *devtype_find_type_attrib(struct devtype *devtype,
|
||||
const char *str)
|
||||
{
|
||||
struct attrib *a;
|
||||
int i;
|
||||
|
||||
for (i = 0; (a = devtype->type_attribs[i]); i++) {
|
||||
if (strcmp(str, a->name) == 0)
|
||||
return a;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Search for a device attribute named STR in any subtype of DT. */
|
||||
struct attrib *devtype_find_dev_attrib(struct devtype *dt, const char *str)
|
||||
{
|
||||
struct attrib *a;
|
||||
struct subtype *st;
|
||||
int i, j;
|
||||
|
||||
for (i = 0; (st = dt->subtypes[i]); i++) {
|
||||
for (j = 0; (a = st->dev_attribs[j]); j++) {
|
||||
if (strcmp(str, a->name) == 0)
|
||||
return a;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Apply device type settings string list to settings list. */
|
||||
static exit_code_t apply_setting(struct devtype *dt, config_t config,
|
||||
const char *key, const char *value,
|
||||
struct util_list *processed)
|
||||
{
|
||||
struct attrib *a;
|
||||
|
||||
/* Check for known attribute. */
|
||||
a = devtype_find_type_attrib(dt, key);
|
||||
if (a) {
|
||||
/* Check for acceptable value of known attribute. */
|
||||
if (!force && !attrib_check_value(a, value))
|
||||
goto err_invalid_forceable;
|
||||
/* Check for activeonly. */
|
||||
if (!force && SCOPE_PERSISTENT(config) && a->activeonly)
|
||||
goto err_activeonly_forceable;
|
||||
/* Check for multiple values. */
|
||||
if (!force && !a->multi && strlist_find(processed, key))
|
||||
goto err_multi_forceable;
|
||||
} else {
|
||||
/* Handle unknown attribute. */
|
||||
if (!dt->unknown_type_attribs)
|
||||
goto err_unknown;
|
||||
if (!force)
|
||||
goto err_unknown_forceable;
|
||||
}
|
||||
|
||||
strlist_add(processed, "%s", key);
|
||||
|
||||
/* Apply to active config. */
|
||||
if (SCOPE_ACTIVE(config)) {
|
||||
setting_list_apply_specified(dt->active_settings, a, key,
|
||||
value);
|
||||
}
|
||||
|
||||
/* Apply to persistent config. */
|
||||
if (SCOPE_PERSISTENT(config)) {
|
||||
setting_list_apply_specified(dt->persistent_settings, a, key,
|
||||
value);
|
||||
}
|
||||
|
||||
return EXIT_OK;
|
||||
|
||||
err_invalid_forceable:
|
||||
delayed_forceable("Invalid value for attribute '%s': %s\n", key, value);
|
||||
return EXIT_INVALID_SETTING;
|
||||
|
||||
err_multi_forceable:
|
||||
delayed_forceable("Cannot specify multiple values for attribute '%s'\n",
|
||||
key);
|
||||
return EXIT_INVALID_SETTING;
|
||||
|
||||
err_unknown:
|
||||
delayed_err("Unknown device type attribute specified: %s\n", key);
|
||||
return EXIT_ATTRIB_NOT_FOUND;
|
||||
|
||||
err_unknown_forceable:
|
||||
delayed_forceable("Unknown device type attribute specified: %s\n", key);
|
||||
return EXIT_ATTRIB_NOT_FOUND;
|
||||
|
||||
err_activeonly_forceable:
|
||||
delayed_forceable("Device type attribute should only be changed in the "
|
||||
"active configuration: %s\n", a->name);
|
||||
return EXIT_INVALID_SETTING;
|
||||
}
|
||||
|
||||
/* Apply device type settings from strlist to devtype. */
|
||||
exit_code_t devtype_apply_strlist(struct devtype *dt, config_t config,
|
||||
struct util_list *settings)
|
||||
{
|
||||
struct util_list *processed;
|
||||
struct strlist_node *s;
|
||||
exit_code_t rc;
|
||||
char *key, *value;
|
||||
|
||||
/* Apply settings. */
|
||||
processed = strlist_new();
|
||||
rc = EXIT_OK;
|
||||
util_list_iterate(settings, s) {
|
||||
key = misc_strdup(s->str);
|
||||
value = strchr(key, '=');
|
||||
*value = 0;
|
||||
value++;
|
||||
|
||||
rc = apply_setting(dt, config, key, value, processed);
|
||||
free(key);
|
||||
|
||||
if (rc)
|
||||
break;
|
||||
}
|
||||
|
||||
strlist_free(processed);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Apply device type settings from setting_list to devtype. */
|
||||
exit_code_t devtype_apply_settings(struct devtype *dt, config_t config,
|
||||
struct util_list *settings)
|
||||
{
|
||||
struct util_list *processed;
|
||||
struct setting *s;
|
||||
exit_code_t rc;
|
||||
|
||||
/* Apply settings. */
|
||||
processed = strlist_new();
|
||||
rc = EXIT_OK;
|
||||
util_list_iterate(settings, s) {
|
||||
rc = apply_setting(dt, config, s->name, s->value, processed);
|
||||
if (rc)
|
||||
break;
|
||||
}
|
||||
|
||||
strlist_free(processed);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Check if a device ID is valid for a subtype of the specified devtype. */
|
||||
bool devtype_is_id_valid(struct devtype *dt, const char *id)
|
||||
{
|
||||
int i;
|
||||
struct subtype *st;
|
||||
|
||||
for (i = 0; (st = dt->subtypes[i]); i++) {
|
||||
if (ns_is_id_valid(st->namespace, id))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Check if a device ID range is valid for a subtype of the specified
|
||||
* devtype. */
|
||||
bool devtype_is_id_range_valid(struct devtype *dt, const char *id)
|
||||
{
|
||||
int i;
|
||||
struct subtype *st;
|
||||
|
||||
for (i = 0; (st = dt->subtypes[i]); i++) {
|
||||
if (st->namespace->is_id_range_valid(id, err_ignore) == EXIT_OK)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Check if a device type configuration needs to be written. */
|
||||
bool devtype_needs_writing(struct devtype *dt, config_t config)
|
||||
{
|
||||
if (SCOPE_ACTIVE(config) && dt->active_settings &&
|
||||
setting_list_modified(dt->active_settings))
|
||||
return true;
|
||||
if (SCOPE_PERSISTENT(config) && dt->persistent_settings &&
|
||||
setting_list_modified(dt->persistent_settings))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void devtype_print(struct devtype *dt, int indent)
|
||||
{
|
||||
int i;
|
||||
struct subtype *st;
|
||||
|
||||
printf("%*sdevtype at %p\n", indent, "", (void *) dt);
|
||||
if (!dt)
|
||||
return;
|
||||
indent += 2;
|
||||
printf("%*sname=%s proc=%d\n", indent, "", dt->name, dt->processed);
|
||||
printf("%*sactive_settings exists=%d:\n", indent, "",
|
||||
dt->active_exists);
|
||||
setting_list_print(dt->active_settings, indent + 2);
|
||||
printf("%*spersistent_settings exists=%d:\n", indent, "",
|
||||
dt->persistent_exists);
|
||||
setting_list_print(dt->persistent_settings, indent + 2);
|
||||
printf("%*ssubtypes:\n", indent, "");
|
||||
for (i = 0; (st = dt->subtypes[i]); i++)
|
||||
subtype_print(st, indent + 2);
|
||||
}
|
||||
|
||||
/* Add name of all modules required by devtype @dt to strlist @modules.
|
||||
* If @subtypes is set, also add modules required by all subtypes. */
|
||||
void devtype_add_modules(struct util_list *modules, struct devtype *dt,
|
||||
int subtypes)
|
||||
{
|
||||
const char **mod = dt->modules;
|
||||
int i;
|
||||
struct subtype *st;
|
||||
|
||||
if (!mod)
|
||||
goto out;
|
||||
|
||||
for (i = 0; mod[i]; i++)
|
||||
strlist_add_unique(modules, "%s", mod[i]);
|
||||
|
||||
out:
|
||||
if (subtypes) {
|
||||
for (i = 0; (st = dt->subtypes[i]); i++)
|
||||
subtype_add_static_modules(modules, st);
|
||||
}
|
||||
}
|
||||
|
||||
/* Check if any of the kernel modules used by devtype @dt is loaded. */
|
||||
bool devtype_is_module_loaded(struct devtype *dt)
|
||||
{
|
||||
struct util_list *modules;
|
||||
struct strlist_node *s;
|
||||
bool result = false;
|
||||
|
||||
modules = strlist_new();
|
||||
devtype_add_modules(modules, dt, 1);
|
||||
util_list_iterate(modules, s) {
|
||||
if (module_loaded(s->str)) {
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
strlist_free(modules);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Return the number of different namespaces found in subtypes of @dt. */
|
||||
int devtype_count_namespaces(struct devtype *dt)
|
||||
{
|
||||
int found[NUM_NAMESPACES];
|
||||
int i, j, num;
|
||||
struct subtype *st;
|
||||
|
||||
/* Reset array. */
|
||||
for (i = 0; i < NUM_NAMESPACES; i++)
|
||||
found[i] = 0;
|
||||
|
||||
/* Set array entries for namespaces found. */
|
||||
for (i = 0; (st = dt->subtypes[i]); i++) {
|
||||
j = namespaces_index(st->namespace);
|
||||
if (j < 0)
|
||||
continue;
|
||||
found[j] = 1;
|
||||
}
|
||||
|
||||
/* Count namespaces. */
|
||||
num = 0;
|
||||
for (i = 0; i < NUM_NAMESPACES; i++) {
|
||||
if (found[i])
|
||||
num++;
|
||||
}
|
||||
|
||||
return num;
|
||||
}
|
||||
|
||||
/* Return the number of subtypes defined for devtype @dt. */
|
||||
int devtype_count_subtypes(struct devtype *dt)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; dt->subtypes[i]; i++) ;
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
/* Try to find namespace in which @ID is could be an ID. Return %NULL if no
|
||||
* namespace or more than one namespace was found. */
|
||||
struct namespace *devtype_most_similar_namespace(struct devtype *only_dt,
|
||||
struct subtype *only_st,
|
||||
const char *id)
|
||||
{
|
||||
struct namespace *match = NULL;
|
||||
struct devtype *dt;
|
||||
struct subtype *st;
|
||||
int i, j;
|
||||
|
||||
for (i = 0; (dt = devtypes[i]); i++) {
|
||||
if (only_dt && dt != only_dt)
|
||||
continue;
|
||||
for (j = 0; (st = dt->subtypes[j]); j++) {
|
||||
if (only_st && st != only_st)
|
||||
continue;
|
||||
|
||||
if (ns_is_id_valid(st->namespace, id))
|
||||
goto found;
|
||||
if (!st->namespace->is_id_similar ||
|
||||
!st->namespace->is_id_similar(id))
|
||||
continue;
|
||||
found:
|
||||
if (match && match != st->namespace) {
|
||||
/* Multiple matches. */
|
||||
return NULL;
|
||||
}
|
||||
match = st->namespace;
|
||||
}
|
||||
}
|
||||
|
||||
return match;
|
||||
}
|
||||
Reference in New Issue
Block a user