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:
Michael Holzheu
2017-08-07 16:13:17 +02:00
commit b627b8d8e1
647 changed files with 168974 additions and 0 deletions

570
zdev/src/ctc.c Normal file
View File

@@ -0,0 +1,570 @@
/*
* 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 "attrib.h"
#include "ccw.h"
#include "ccwgroup.h"
#include "ctc.h"
#include "ctc_auto.h"
#include "device.h"
#include "devtype.h"
#include "misc.h"
#include "namespace.h"
#include "path.h"
#include "setting.h"
#define DEVNAME "CTC device"
/*
* CTC device ID namespace methods.
*/
static exit_code_t ctc_parse_devid(struct ccwgroup_devid *devid_ptr,
const char *id, err_t err)
{
struct ccwgroup_devid devid;
const char *reason = NULL;
exit_code_t rc;
rc = ccwgroup_parse_devid(&devid, id, err);
if (rc)
return rc;
if (devid.num > CTC_NUM_DEVS) {
reason = "Too many CCW device IDs specified";
rc = EXIT_INVALID_ID;
} else if (devid_ptr)
*devid_ptr = devid;
if (reason) {
err_t_print(err, "Error in %s ID format: %s: %s\n", DEVNAME,
reason, id);
}
return rc;
}
static exit_code_t ctc_parse_devid_range(struct ccwgroup_devid *from_ptr,
struct ccwgroup_devid *to_ptr,
const char *range, err_t err)
{
char *from_str, *to_str;
struct ccwgroup_devid from, to;
exit_code_t rc;
const char *reason = NULL;
/* Split range. */
from_str = misc_strdup(range);
to_str = strchr(from_str, '-');
if (!to_str) {
rc = EXIT_INVALID_ID;
reason = "Missing hyphen";
goto out;
}
*to_str = 0;
to_str++;
/* Parse range start end end ID. */
rc = ctc_parse_devid(&from, from_str, err);
if (rc)
goto out;
rc = ctc_parse_devid(&to, to_str, err);
if (rc)
goto out;
/* Only allow ranges on CCWGROUP devices specified as single ID. */
if (from.num != 1 || to.num != 1) {
rc = EXIT_INVALID_ID;
reason = "Ranges only supported on single CCW device IDs";
goto out;
}
rc = EXIT_OK;
if (from_ptr)
*from_ptr = from;
if (to_ptr)
*to_ptr = to;
out:
free(from_str);
if (reason) {
err_t_print(err, "Error in %s ID range format: %s: %s\n",
DEVNAME, reason, range);
}
return rc;
}
static bool ctc_parse_devid_range_simple(struct ccwgroup_devid *from,
struct ccwgroup_devid *to,
const char *range)
{
if (ctc_parse_devid_range(from, to, range, err_ignore) == EXIT_OK)
return true;
return false;
}
static exit_code_t ctc_ns_is_id_valid(const char *id, err_t err)
{
return ctc_parse_devid(NULL, id, err);
}
static char *ctc_ns_normalize_id(const char *id)
{
struct ccwgroup_devid devid;
if (ctc_parse_devid(&devid, id, err_ignore) != EXIT_OK)
return NULL;
return ccwgroup_devid_to_str(&devid);
}
static void *ctc_ns_parse_id(const char *id, err_t err)
{
struct ccwgroup_devid *devid;
devid = misc_malloc(sizeof(struct ccwgroup_devid));
if (ctc_parse_devid(devid, id, err) != EXIT_OK) {
free(devid);
return NULL;
}
return devid;
}
static exit_code_t ctc_ns_is_id_range_valid(const char *range, err_t err)
{
return ctc_parse_devid_range(NULL, NULL, range, err);
}
static unsigned long ctc_ns_num_ids_in_range(const char *range)
{
struct ccwgroup_devid f, t;
if (!ctc_parse_devid_range_simple(&f, &t, range))
return 0;
if (f.devid[0].cssid != t.devid[0].cssid ||
f.devid[0].ssid != t.devid[0].ssid)
return 0;
if (f.devid[0].devno > t.devid[0].devno)
return 0;
return t.devid[0].devno - f.devid[0].devno + 1;
}
static void ctc_ns_range_start(struct ns_range_iterator *it, const char *range)
{
struct ccwgroup_devid from, to;
if (!ctc_parse_devid_range_simple(&from, &to, range)) {
memset(it, 0, sizeof(struct ns_range_iterator));
return;
}
it->devid = ccwgroup_copy_devid(&from);
it->devid_last = ccwgroup_copy_devid(&to);
it->id = ccwgroup_devid_to_str(it->devid);
}
static bool ctc_ns_is_id_blacklisted(const char *id)
{
struct ccwgroup_devid devid;
char *ccw_id;
unsigned int i;
bool result = false;
if (ctc_parse_devid(&devid, id, err_ignore) != EXIT_OK)
return false;
for (i = 0; i < devid.num; i++) {
ccw_id = ccw_devid_to_str(&devid.devid[i]);
result = ccw_is_id_blacklisted(ccw_id);
free(ccw_id);
if (result)
break;
}
return result;
}
static void ctc_ns_unblacklist_id(const char *id)
{
struct ccwgroup_devid devid;
char *ccw_id;
unsigned int i;
if (ctc_parse_devid(&devid, id, err_ignore) != EXIT_OK)
return;
for (i = 0; i < devid.num; i++) {
ccw_id = ccw_devid_to_str(&devid.devid[i]);
if (ccw_is_id_blacklisted(ccw_id))
ccw_unblacklist_id(ccw_id);
free(ccw_id);
}
}
/*
* CTC device ID namespace.
*/
struct namespace ctc_namespace = {
.devname = DEVNAME,
.is_id_valid = ctc_ns_is_id_valid,
.is_id_similar = ccwgroup_is_id_similar,
.cmp_ids = ccwgroup_cmp_ids,
.normalize_id = ctc_ns_normalize_id,
.parse_id = ctc_ns_parse_id,
.cmp_parsed_ids = ccwgroup_cmp_parsed_ids,
.qsort_cmp = ccwgroup_qsort_cmp,
.is_id_range_valid = ctc_ns_is_id_range_valid,
.num_ids_in_range = ctc_ns_num_ids_in_range,
.is_id_in_range = ccwgroup_is_id_in_range,
.range_start = ctc_ns_range_start,
.range_next = ccwgroup_range_next,
/* Blacklist handling. */
.is_blacklist_active = ccw_is_blacklist_active,
.is_id_blacklisted = ctc_ns_is_id_blacklisted,
.is_id_range_blacklisted = ccw_is_id_range_blacklisted,
.unblacklist_id = ctc_ns_unblacklist_id,
.unblacklist_id_range = ccw_unblacklist_id_range,
.blacklist_persist = ccw_blacklist_persist,
};
/*
* CTC device attributes.
*/
static struct attrib ctc_attr_buffer = {
.name = "buffer",
.title = "Control maximum buffer size",
.desc =
"Specify the maximum buffer size used for a CTC interface. The value\n"
"must be in the range of <minimum MTU + header size> to\n"
"<maximum MTU + header size> where a header is typically 8 bytes\n"
"long. When this attribute is set, the MTU size of the interface\n"
"is also set accordingly.\n",
.defval = "32768",
.accept = ACCEPT_ARRAY(ACCEPT_RANGE(584, 65535)),
.order_cmp = ccw_online_only_order_cmp,
.check = ccw_online_only_check,
};
static struct attrib ctc_attr_protocol = {
.name = "protocol",
.title = "Specify CTC interface protocol",
.desc =
"Specify the protocol to use for a CTC interface. The correct\n"
"protocol depends on the CTC connection peer:\n"
" 0: Non-z/OS peer such as a z/VM TCP service machine\n"
" 1: Linux peer\n"
" 3: z/OS peer\n"
" 4: MPC connection to VTAM\n",
.defval = "0",
.accept = ACCEPT_ARRAY(ACCEPT_RANGE(0, 1), ACCEPT_RANGE(3, 4)),
.order_cmp = ccw_offline_only_order_cmp,
.check = ccw_offline_only_check,
};
/*
* CTC subtype methods.
*/
/* Check if user attempts to modify an attribute of an online CTC device
* which can only be set while device is offline. */
static exit_code_t check_online_conflict(struct device *dev, config_t config)
{
struct attrib *attribs[] = {
&ctc_attr_protocol,
};
struct setting *online, *s;
unsigned int i;
exit_code_t rc;
/* All is well if:
* 1. We're not configuring the active configuration
* 2. online->actual == 0 or we don't know the actual value
* 3. online->modified && online->value == 0*/
if (!SCOPE_ACTIVE(config) || dev->active.deconfigured)
return EXIT_OK;
online = setting_list_find(dev->active.settings, ccw_attr_online.name);
if (!online)
return EXIT_OK;
if (!online->actual_value || atoi(online->actual_value) == 0)
return EXIT_OK;
if (online->modified && atoi(online->value) == 0)
return EXIT_OK;
rc = EXIT_OK;
for (i = 0; i < ARRAY_SIZE(attribs); i++) {
s = setting_list_find(dev->active.settings, attribs[i]->name);
if (!s || !s->modified)
continue;
delayed_warn("Attribute '%s' can only be changed while device "
"is offline\n", s->name);
rc = EXIT_INVALID_CONFIG;
}
return rc;
}
static exit_code_t ctc_st_check_pre_configure(struct subtype *st,
struct device *dev,
int prereq, config_t config)
{
exit_code_t rc;
rc = check_online_conflict(dev, config);
if (rc)
return rc;
return EXIT_OK;
}
static exit_code_t ctc_st_is_definable(struct subtype *st, const char *id,
err_t err)
{
struct ccwgroup_subtype_data *data = st->data;
struct ccwgroup_devid devid;
exit_code_t rc;
rc = ccwgroup_parse_devid(&devid, id, err);
if (rc)
return rc;
if (subtype_device_exists_active(st, id))
return EXIT_OK;
if (devid.num == data->num_devs)
return ctc_auto_is_possible(&devid, err);
if (devid.num == 1)
return ctc_auto_get_devid(NULL, &devid.devid[0], err);
err_t_print(err, "Invalid number of CCW device IDs\n");
return EXIT_INVALID_ID;
}
/**
* device_detect_definable - Detect configuration of definable device
* @st: Device subtype
* @dev: Device
*
* Detect the full ID and default parameters for non-existing but definable
* device @dev and update active.definable. Return %EXIT_OK on success, or an
* error code otherwise.
*/
static exit_code_t ctc_st_detect_definable(struct subtype *st,
struct device *dev)
{
struct ccwgroup_devid *devid;
exit_code_t rc;
devid = dev->devid;
if (devid->num == 1) {
/* Detect possible group for this device. */
rc = ctc_auto_get_devid(devid, &devid->devid[0],
err_delayed_print);
if (rc) {
error("Auto-detection failed for %s %s\n"
"Please be sure to specify full CCWGROUP ID!\n",
st->devname, dev->id);
return rc;
}
free(dev->id);
dev->id = ccwgroup_devid_to_str(dev->devid);
}
dev->active.definable = 1;
return EXIT_OK;
}
static void ctc_st_add_definable_ids(struct subtype *st, struct util_list *ids)
{
ctc_auto_add_ids(ids);
}
/*
* CTC subtype.
*/
static struct ccwgroup_subtype_data ctc_data = {
.ccwgroupdrv = CTC_CCWGROUPDRV_NAME,
.ccwdrv = CTC_CCWDRV_NAME,
.rootdrv = CTC_ROOTDRV_NAME,
.mod = CTC_MOD_NAME,
.num_devs = CTC_NUM_DEVS,
};
static struct subtype ctc_subtype = {
.super = &ccwgroup_subtype,
.devtype = &ctc_devtype,
.name = "ctc",
.title = "Channel-To-Channel (CTC) and CTC-MPC network "
"devices",
.devname = DEVNAME,
.modules = STRING_ARRAY(CTC_MOD_NAME),
.namespace = &ctc_namespace,
.data = &ctc_data,
.dev_attribs = ATTRIB_ARRAY(
&ccw_attr_online,
&ctc_attr_buffer,
&ctc_attr_protocol,
),
.unknown_dev_attribs = 1,
.support_definable = 1,
.check_pre_configure = &ctc_st_check_pre_configure,
.is_definable = &ctc_st_is_definable,
.detect_definable = &ctc_st_detect_definable,
.add_definable_ids = &ctc_st_add_definable_ids,
};
/*
* CTC devtype methods.
*/
/* Clean up all resources used by devtype object. */
static void ctc_devtype_exit(struct devtype *dt)
{
setting_list_free(dt->active_settings);
setting_list_free(dt->persistent_settings);
}
static exit_code_t ctc_devtype_read_settings(struct devtype *dt,
config_t config)
{
/* No kernel or module parameters exist for the ctc device driver,
* but at least determine module loaded state. */
dt->active_settings = setting_list_new();
dt->persistent_settings = setting_list_new();
if (SCOPE_ACTIVE(config))
dt->active_exists = devtype_is_module_loaded(dt);
return EXIT_OK;
}
static exit_code_t ctc_devtype_write_settings(struct devtype *dt,
config_t config)
{
/* No kernel or module parameters exist for the ctc device driver. */
return EXIT_OK;
}
/*
* CTC devtype.
*/
struct devtype ctc_devtype = {
.name = "ctc",
.title = "", /* Only use subtypes. */
.devname = "CTC",
.subtypes = SUBTYPE_ARRAY(
&ctc_subtype,
),
.type_attribs = ATTRIB_ARRAY(
),
.exit = &ctc_devtype_exit,
.read_settings = &ctc_devtype_read_settings,
.write_settings = &ctc_devtype_write_settings,
};
/*
* Helper functions.
*/
static struct util_list *ctc_list;
static void add_query(struct util_list *list, const char *cmd)
{
char *vmcp, *curr, *next, **argv;
int argc;
struct ccw_devid devid;
/* Query real CTC adapters. */
vmcp = misc_read_cmd_output(cmd, 0, 1);
if (!vmcp)
return;
next = vmcp;
while ((curr = strsep(&next, "\n"))) {
line_split(curr, &argc, &argv);
if (argc >= 2 && ccw_parse_devid_simple(&devid, argv[1]))
ptrlist_add(list, ccw_copy_devid(&devid));
line_free(argc, argv);
}
free(vmcp);
}
/* Perform a CP QUERY CTCA ALL command and return a ptrlist of CCW device IDs
* for all found CTC devices. */
static struct util_list *query_ctc(void)
{
struct util_list *list;
char *cmd;
list = ptrlist_new();
/* Query real CTC adapters. */
cmd = misc_asprintf("%s query ctca all 2>/dev/null", PATH_VMCP);
add_query(list, cmd);
free(cmd);
/* Query virtual CTC adapters. */
cmd = misc_asprintf("%s query virtual ctca 2>/dev/null", PATH_VMCP);
add_query(list, cmd);
free(cmd);
return list;
}
/* Release all allocated resources. */
void ctc_exit(void)
{
ptrlist_free(ctc_list, 1);
}
/* Try to confirm that the specified CCW device ID refers to CTC device.
* Return %true it is a CTC device, %false if it cannot be confirmed. */
bool ctc_confirm(struct ccw_devid *devid)
{
struct ptrlist_node *p;
struct ccw_devid *d;
if (devid->cssid != 0 || devid->ssid != 0 || !is_zvm())
return false;
if (!ctc_list)
ctc_list = query_ctc();
util_list_iterate(ctc_list, p) {
d = p->ptr;
if (ccw_cmp_devids(devid, d) == 0)
return true;
}
return false;
}