mirror of
https://github.com/ibm-s390-linux/s390-tools.git
synced 2026-08-05 02:14:52 +00:00
Compare commits
29 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f75c923627 | ||
|
|
bca8fa3f9c | ||
|
|
d713ea6389 | ||
|
|
f9fbe79e4f | ||
|
|
3cc0b4cdea | ||
|
|
eef9f622c0 | ||
|
|
889293e557 | ||
|
|
0c5b9f5d11 | ||
|
|
02af069d48 | ||
|
|
5e0056db8d | ||
|
|
4b5937f142 | ||
|
|
8d8d5e9746 | ||
|
|
5bdabe3e06 | ||
|
|
8a1db94d37 | ||
|
|
1911cba130 | ||
|
|
f4ed0b0ec6 | ||
|
|
6e42c527d7 | ||
|
|
f7d2339c6a | ||
|
|
cf5f373142 | ||
|
|
e09c675b70 | ||
|
|
6bd93f475c | ||
|
|
3f12bdf4c7 | ||
|
|
3aa7f6e298 | ||
|
|
4e28047eb4 | ||
|
|
f654b971d0 | ||
|
|
e742d1c9ae | ||
|
|
803b87e324 | ||
|
|
5107a7be16 | ||
|
|
1178291686 |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -95,6 +95,9 @@ zdev/src/chzdev_usage.c
|
||||
zdev/src/lszdev
|
||||
zdev/src/lszdev_usage.c
|
||||
zdsfs/zdsfs
|
||||
zdump/.check_dep_fuse
|
||||
zdump/.check_dep_zgetdump
|
||||
zdump/.detect_openssl.dep.c
|
||||
zdump/zgetdump
|
||||
zfcpdump/10-zfcpdump.install
|
||||
zfcpdump/cpioinit
|
||||
|
||||
@@ -21,6 +21,7 @@ List of all individuals having contributed content to s390-tools
|
||||
- Colin Walters
|
||||
- Dan Horak
|
||||
- Dan Horák
|
||||
- Daniel S. Haischt
|
||||
- Despina Papadopoulou
|
||||
- Dimitri John Ledkov
|
||||
- Eberhard Pasch
|
||||
|
||||
14
CHANGELOG.md
14
CHANGELOG.md
@@ -1,6 +1,20 @@
|
||||
Release history for s390-tools (MIT version)
|
||||
--------------------------------------------
|
||||
|
||||
* __v2.25.0 (2022-12-08)__
|
||||
|
||||
For Linux kernel version: 6.1
|
||||
|
||||
Changes of existing tools:
|
||||
- ap_tools: Use new mdevctl installation location
|
||||
- lsdasd/tunedasd/zdev: Add support to handle copy pair relations presented by the DASD driver
|
||||
- zdev: Add --shell command line switch to generate output suitable for shell environments
|
||||
- zipl: Add List-Directed IPL from ECKD DASD to support secure boot
|
||||
|
||||
Bug Fixes:
|
||||
- ipl_tools: Fix chreipl node for NVMes with CONFIG_NVME_MULTIPATH
|
||||
- libdasd: Fix bug that prevented positive ioctl return codes
|
||||
|
||||
* __v2.24.0 (2022-11-09)__
|
||||
|
||||
For Linux kernel version: 6.0
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
include ../common.mak
|
||||
|
||||
MDEVCTL_DIR = /etc/mdevctl.d/
|
||||
MDEVCTL_SCRIPTS = /etc/mdevctl.d/scripts.d/
|
||||
MDEVCTL_CALLOUTS = /etc/mdevctl.d/scripts.d/callouts/
|
||||
MDEVCTL_DIR = /usr/lib/mdevctl/
|
||||
MDEVCTL_SCRIPTS = /usr/lib/mdevctl/scripts.d/
|
||||
MDEVCTL_CALLOUTS = /usr/lib/mdevctl/scripts.d/callouts/
|
||||
MDEVCTL_DEP_DIR = /etc/mdevctl.d/
|
||||
MDEVCTL_DEP_SCRIPTS = /etc/mdevctl.d/scripts.d/
|
||||
MDEVCTL_DEP_CALLOUTS = /etc/mdevctl.d/scripts.d/callouts/
|
||||
|
||||
libs = $(rootdir)/libap/libap.a \
|
||||
$(rootdir)/libutil/libutil.a
|
||||
@@ -32,6 +35,17 @@ install: all
|
||||
fi; \
|
||||
$(INSTALL) -g $(GROUP) -o $(OWNER) -m 755 ap-check \
|
||||
$(DESTDIR)$(MDEVCTL_CALLOUTS)
|
||||
@if [ ! -d $(DESTDIR)$(MDEVCTL_DEP_CALLOUTS) ]; then \
|
||||
mkdir -p $(DESTDIR)$(MDEVCTL_DEP_CALLOUTS); \
|
||||
chown $(OWNER).$(GROUP) $(DESTDIR)$(MDEVCTL_DEP_DIR); \
|
||||
chown $(OWNER).$(GROUP) $(DESTDIR)$(MDEVCTL_DEP_SCRIPTS); \
|
||||
chown $(OWNER).$(GROUP) $(DESTDIR)$(MDEVCTL_DEP_CALLOUTS); \
|
||||
chmod 755 $(DESTDIR)$(MDEVCTL_DEP_DIR); \
|
||||
chmod 755 $(DESTDIR)$(MDEVCTL_DEP_SCRIPTS); \
|
||||
chmod 755 $(DESTDIR)$(MDEVCTL_DEP_CALLOUTS); \
|
||||
fi; \
|
||||
$(INSTALL) -g $(GROUP) -o $(OWNER) -m 755 ap-check.sh \
|
||||
$(DESTDIR)$(MDEVCTL_DEP_CALLOUTS)
|
||||
endif
|
||||
|
||||
clean:
|
||||
|
||||
15
ap_tools/ap-check.sh
Normal file
15
ap_tools/ap-check.sh
Normal file
@@ -0,0 +1,15 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# ap-check.sh - Wrapper script for 'ap-check' binary
|
||||
#
|
||||
# mdevctl has deprecated the /etc/mdevctl.d/scripts.d/callouts/ location in
|
||||
# newer releases. This wrapper ensures that mdevctl 1.2.0 and older can
|
||||
# still access 'ap-check' for now, and will be removed at a later time.
|
||||
#
|
||||
# Copyright 2022 IBM Corp.
|
||||
#
|
||||
# s390-tools is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the MIT license. See LICENSE for details.
|
||||
#
|
||||
|
||||
[ -e /usr/lib/mdevctl/scripts.d/callouts/ap-check ] && /usr/lib/mdevctl/scripts.d/callouts/ap-check "$@"
|
||||
@@ -5,7 +5,7 @@ COMMON_INCLUDED = true
|
||||
# The variable "DISTRELEASE" should be overwritten in rpm spec files with:
|
||||
# "make DISTRELEASE=%{release}" and "make install DISTRELEASE=%{release}"
|
||||
VERSION = 2
|
||||
RELEASE = 24
|
||||
RELEASE = 25
|
||||
PATCHLEVEL = 0
|
||||
DISTRELEASE = build-$(shell date +%Y%m%d)
|
||||
S390_TOOLS_RELEASE = $(VERSION).$(RELEASE).$(PATCHLEVEL)-$(DISTRELEASE)
|
||||
@@ -60,8 +60,10 @@ endef
|
||||
|
||||
$(eval $(call cmd_define, AS," AS ",$(CROSS_COMPILE)as))
|
||||
$(eval $(call cmd_define, CC," CC ",$(CROSS_COMPILE)gcc))
|
||||
$(eval $(call cmd_define, LINK," LINK ",$(CC)))
|
||||
$(eval $(call cmd_define, HOSTCC," HOSTCC ",gcc))
|
||||
$(eval $(call cmd_define, CXX," CXX ",$(CROSS_COMPILE)g++))
|
||||
$(eval $(call cmd_define, LINKXX," LINKXX ",$(CXX)))
|
||||
$(eval $(call cmd_define, CPP," CPP ",$(CROSS_COMPILE)gcc -E))
|
||||
$(eval $(call cmd_define, AR," AR ",$(CROSS_COMPILE)ar))
|
||||
$(eval $(call cmd_define, NM," NM ",$(CROSS_COMPILE)nm))
|
||||
@@ -81,8 +83,6 @@ CHECKTOOL = $(call echocmd," CHECK ",/$@)$(CHECK_SILENT)
|
||||
SKIP = echo " SKIP $(call reldir) due to"
|
||||
|
||||
INSTALL = install
|
||||
LINK = $(CC)
|
||||
LINKXX = $(CXX)
|
||||
CP = cp
|
||||
ifneq ("${V}","1")
|
||||
MAKEFLAGS += --quiet
|
||||
|
||||
@@ -57,11 +57,41 @@ struct linear_blockptr {
|
||||
uint8_t reserved[4];
|
||||
} __packed;
|
||||
|
||||
/*
|
||||
* Format of a boot record on ECKD DASD for List-Directed IPL
|
||||
*/
|
||||
struct eckd_boot_record {
|
||||
uint8_t magic[4];
|
||||
uint32_t version_id;
|
||||
uint8_t unused[8];
|
||||
uint8_t program_table_pointer[16];
|
||||
uint8_t reserved[478];
|
||||
uint16_t os_id;
|
||||
} __packed;
|
||||
|
||||
/*
|
||||
* Layout of block pointer for cylinder/head/sector devices
|
||||
* e.g. ECKD
|
||||
*/
|
||||
struct eckd_blockptr {
|
||||
|
||||
enum blkptr_format_id {
|
||||
/*
|
||||
* this is the old format which serves only CCW-type IPL,
|
||||
* and doesn't fit List-Directed IPL. Still supported for
|
||||
* compatibility reasons.
|
||||
*/
|
||||
LEGACY_BLKPTR_FORMAT_ID,
|
||||
/*
|
||||
* this is the "new" format which serves only List-Directed IPL,
|
||||
* but is also suitable for CCW-type IPL.
|
||||
*/
|
||||
BLKPTR_FORMAT_ID
|
||||
};
|
||||
|
||||
/*
|
||||
* Block pointers format identified as LEGACY_BLKPTR_FORMAT_ID.
|
||||
*/
|
||||
struct eckd_blockptr_legacy {
|
||||
uint16_t cyl;
|
||||
uint16_t head;
|
||||
uint8_t sec;
|
||||
@@ -70,10 +100,22 @@ struct eckd_blockptr {
|
||||
uint8_t reserved[8];
|
||||
} __packed;
|
||||
|
||||
/*
|
||||
* Block pointers format identified as BLKPTR_FORMAT_ID.
|
||||
*/
|
||||
struct eckd_blockptr {
|
||||
uint32_t cyl;
|
||||
uint8_t head;
|
||||
uint8_t sec;
|
||||
uint8_t reserved1[4];
|
||||
uint16_t blockct;
|
||||
uint8_t reserved2[4];
|
||||
} __packed;
|
||||
|
||||
typedef enum {
|
||||
COMPONENT_EXECUTE = 0x01,
|
||||
COMPONENT_LOAD = 0x02,
|
||||
COMPONENT_SIGNATURE = 0x03
|
||||
COMPONENT_TYPE_EXECUTE = 0x01,
|
||||
COMPONENT_TYPE_LOAD = 0x02,
|
||||
COMPONENT_TYPE_SIGNATURE = 0x03
|
||||
} component_type;
|
||||
|
||||
typedef enum {
|
||||
@@ -117,7 +159,8 @@ struct scsi_dump_sb {
|
||||
uint64_t csum_offset;
|
||||
uint64_t csum_size;
|
||||
uint64_t csum;
|
||||
} __packed;
|
||||
};
|
||||
STATIC_ASSERT(sizeof(struct scsi_dump_sb) == 72);
|
||||
|
||||
#define SCSI_DUMP_SB_MAGIC 0x5a46435044554d50ULL /* ZFCPDUMP */
|
||||
/* To avoid a csum entry of 0 a seed is used */
|
||||
@@ -153,6 +196,7 @@ struct boot_info_bp_dump {
|
||||
|
||||
struct boot_info_bp_ipl {
|
||||
union {
|
||||
struct eckd_blockptr_legacy eckd_legacy;
|
||||
struct eckd_blockptr eckd;
|
||||
struct linear_blockptr lin;
|
||||
} bm_ptr;
|
||||
|
||||
@@ -20,8 +20,8 @@
|
||||
#include <stdio.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
/* A bus id of a DASD is 8 characters long. E.g. 0.0.4711 */
|
||||
#define DASD_BUS_ID_SIZE 9
|
||||
/* the definition of a BUSID in the DASD driver is 20 */
|
||||
#define DASD_BUS_ID_SIZE 20
|
||||
|
||||
typedef struct dasd_information2_t {
|
||||
unsigned int devno; /* S/390 devno */
|
||||
@@ -187,6 +187,68 @@ typedef struct format_check_t {
|
||||
#define DASD_FMT_ERR_RECORD_ID 4
|
||||
#define DASD_FMT_ERR_KEY_LENGTH 5
|
||||
|
||||
/*
|
||||
* struct profile_info_t
|
||||
* holds the profiling information
|
||||
*/
|
||||
typedef struct dasd_profile_info_t {
|
||||
unsigned int dasd_io_reqs; /* # of requests processed at all */
|
||||
unsigned int dasd_io_sects; /* # of sectors processed at all */
|
||||
unsigned int dasd_io_secs[32]; /* request's sizes */
|
||||
unsigned int dasd_io_times[32]; /* requests's times */
|
||||
unsigned int dasd_io_timps[32]; /* requests's times per sector */
|
||||
unsigned int dasd_io_time1[32]; /* time from build to start */
|
||||
unsigned int dasd_io_time2[32]; /* time from start to irq */
|
||||
unsigned int dasd_io_time2ps[32]; /* time from start to irq */
|
||||
unsigned int dasd_io_time3[32]; /* time from irq to end */
|
||||
unsigned int dasd_io_nr_req[32]; /* # of requests in chanq */
|
||||
} dasd_profile_info_t;
|
||||
|
||||
/*
|
||||
* struct attrib_data_t
|
||||
* represents the operation (cache) bits for the device.
|
||||
* Used in DE to influence caching of the DASD.
|
||||
*/
|
||||
typedef struct attrib_data_t {
|
||||
unsigned char operation : 3; /* cache operation mode */
|
||||
unsigned char reserved : 5;
|
||||
unsigned short nr_cyl; /* no of cyliners for read ahaed */
|
||||
unsigned char reserved2[29]; /* for future use */
|
||||
} __attribute__((packed)) attrib_data_t;
|
||||
|
||||
/* definition of operation (cache) bits within attributes of DE */
|
||||
#define DASD_NORMAL_CACHE 0x0
|
||||
#define DASD_BYPASS_CACHE 0x1
|
||||
#define DASD_INHIBIT_LOAD 0x2
|
||||
#define DASD_SEQ_ACCESS 0x3
|
||||
#define DASD_SEQ_PRESTAGE 0x4
|
||||
#define DASD_REC_ACCESS 0x5
|
||||
|
||||
/*
|
||||
* Data returned by Sense Path Group ID (SNID)
|
||||
*/
|
||||
struct dasd_snid_data {
|
||||
struct {
|
||||
__u8 group : 2;
|
||||
__u8 reserve : 2;
|
||||
__u8 mode : 1;
|
||||
__u8 res : 3;
|
||||
} __attribute__((packed)) path_state;
|
||||
__u8 pgid[11];
|
||||
} __attribute__((packed));
|
||||
|
||||
struct dasd_snid_ioctl_data {
|
||||
struct dasd_snid_data data;
|
||||
__u8 path_mask;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct dasd_copypair_swap_data {
|
||||
char primary[DASD_BUS_ID_SIZE]; /* BUSID of primary */
|
||||
char secondary[DASD_BUS_ID_SIZE]; /* BUSID of secondary */
|
||||
/* Reserved for future updates. */
|
||||
char reserved[64];
|
||||
};
|
||||
|
||||
#ifndef __linux__
|
||||
/* definition from hdreg.h */
|
||||
struct hd_geometry {
|
||||
@@ -207,27 +269,29 @@ struct hd_geometry {
|
||||
#define BIODASDRSRV _IO(DASD_IOCTL_LETTER, 2)
|
||||
/* Release the device for the current LPAR */
|
||||
#define BIODASDRLSE _IO(DASD_IOCTL_LETTER, 3)
|
||||
/* Unconditional reserve the device for the current LPAR */
|
||||
#define BIODASDSLCK _IO(DASD_IOCTL_LETTER, 4)
|
||||
/* reset profiling information of a device */
|
||||
#define BIODASDPRRST _IO(DASD_IOCTL_LETTER, 5)
|
||||
/* retrieve profiling information of a device */
|
||||
#define BIODASDPRRD _IOR(DASD_IOCTL_LETTER, 2, dasd_profile_info_t)
|
||||
/* Get information on a dasd device (enhanced) */
|
||||
#define BIODASDINFO2 _IOR(DASD_IOCTL_LETTER, 3, dasd_information2_t)
|
||||
/* Get Attributes (cache operations) */
|
||||
#define BIODASDGATTR _IOR(DASD_IOCTL_LETTER, 5, attrib_data_t)
|
||||
/* #define BIODASDFORMAT _IOW(IOCTL_LETTER,0,format_data_t) , deprecated */
|
||||
#define BIODASDFMT _IOW(DASD_IOCTL_LETTER, 1, format_data_t)
|
||||
/* Set Attributes (cache operations) */
|
||||
#define BIODASDSATTR _IOW(DASD_IOCTL_LETTER, 2, attrib_data_t)
|
||||
/* Release Allocated Space */
|
||||
#define BIODASDRAS _IOW(DASD_IOCTL_LETTER, 3, format_data_t)
|
||||
/* Swap copy pair */
|
||||
#define BIODASDPPRCSWAP _IOW(DASD_IOCTL_LETTER, 4, struct dasd_copypair_swap_data)
|
||||
/* Get Sense Path Group ID (SNID) data */
|
||||
#define BIODASDSNID _IOWR(DASD_IOCTL_LETTER, 1, struct dasd_snid_ioctl_data)
|
||||
/* Check device format according to format_data_t */
|
||||
#define BIODASDCHECKFMT _IOWR(DASD_IOCTL_LETTER, 2, format_check_t)
|
||||
|
||||
/********************************************************************************
|
||||
* SECTION: Further IOCTL Definitions (see fs.h and hdreq.h)
|
||||
*******************************************************************************/
|
||||
/* get read-only status (0 = read_write) */
|
||||
#define BLKROGET _IO(0x12, 94)
|
||||
/* re-read partition table */
|
||||
#define BLKRRPART _IO(0x12, 95)
|
||||
/* get block device sector size */
|
||||
#define BLKSSZGET _IO(0x12, 104)
|
||||
/* return device size in bytes (u64 *arg) */
|
||||
#define BLKGETSIZE64 _IOR(0x12, 114, size_t)
|
||||
|
||||
#ifndef __linux__ /* from <linux/hdreg.h> */
|
||||
#define HDIO_GETGEO 0x0301
|
||||
#endif
|
||||
@@ -245,5 +309,12 @@ int dasd_is_ro(const char *device, bool *ro);
|
||||
int dasd_reread_partition_table(const char *device, int ntries);
|
||||
int dasd_disk_reserve(const char *device);
|
||||
int dasd_disk_release(const char *device);
|
||||
int dasd_slock(const char *device);
|
||||
int dasd_get_cache(const char *device, attrib_data_t *attrib_data);
|
||||
int dasd_set_cache(const char *device, attrib_data_t *attrib_data);
|
||||
int dasd_query_reserve(const char *device);
|
||||
int dasd_profile(const char *device, dasd_profile_info_t *dasd_profile_info);
|
||||
int dasd_reset_profile(const char *device);
|
||||
int dasd_copy_swap(const char *device, struct dasd_copypair_swap_data *data);
|
||||
|
||||
#endif /* LIB_DASD_BASE_H */
|
||||
|
||||
@@ -97,6 +97,24 @@ typedef struct volume_label
|
||||
unsigned long long formatted_blocks; /* valid when ldl_version >= f2 */
|
||||
} __attribute__ ((packed)) volume_label_t;
|
||||
|
||||
/**
|
||||
* This represents a volume label specific for OS/390 compatible disk layout
|
||||
*/
|
||||
struct vol_label_cdl {
|
||||
char volkey[4];
|
||||
char vollbl[4];
|
||||
char opaq[70];
|
||||
cchhb_t br; /* boot record address */
|
||||
char stdv[1]; /* standard version ID */
|
||||
} __attribute__ ((packed));
|
||||
|
||||
static inline int is_vol1(char *this)
|
||||
{
|
||||
char vol1[] = {0xe5, 0xd6, 0xd3, 0xf1, 0x00} /* "VOL1" in EBCDIC */;
|
||||
|
||||
return !strncmp(this, vol1, 4);
|
||||
}
|
||||
|
||||
typedef struct extent
|
||||
{
|
||||
u_int8_t typeind; /* extent type indicator */
|
||||
|
||||
@@ -75,6 +75,7 @@ extern void fcp_busid_get(const char *device, char *devno);
|
||||
* NVME
|
||||
*/
|
||||
#define FID_MAX_LEN 11 /* 8 characters + 0x + null */
|
||||
#define NVME_DEV_MAX_LEN 15 /* "nvme" + u32 in decimal + null */
|
||||
#define NVME_PATH_MAX (PATH_MAX + NAME_MAX + 1)
|
||||
|
||||
extern void nvme_fid_get(const char *device, char *fid);
|
||||
|
||||
@@ -18,15 +18,31 @@
|
||||
#include "lib/util_file.h"
|
||||
#include "ipl_tools.h"
|
||||
|
||||
static void nvme_dev_from_bdev(char *dev_name)
|
||||
{
|
||||
char *delim = strrchr(dev_name, 'n');
|
||||
|
||||
if (delim)
|
||||
*delim = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the fid of a device
|
||||
*/
|
||||
void nvme_fid_get(const char *device, char *fid)
|
||||
{
|
||||
char path[PATH_MAX], buf[FID_MAX_LEN];
|
||||
char nvme_dev[NVME_DEV_MAX_LEN];
|
||||
|
||||
snprintf(path, PATH_MAX, "/sys/block/%s/device/device/function_id",
|
||||
device);
|
||||
/*
|
||||
* An NVMe may present multiple namespaces and thus block devices, even
|
||||
* before partitioning, so we need the nvme<NUM> part of the block
|
||||
* device name to get to the PCI function ID.
|
||||
*/
|
||||
util_strlcpy(nvme_dev, device, sizeof(nvme_dev));
|
||||
nvme_dev_from_bdev(nvme_dev);
|
||||
|
||||
snprintf(path, PATH_MAX, "/sys/class/nvme/%s/device/function_id", nvme_dev);
|
||||
if (util_file_read_line(buf, FID_MAX_LEN, path))
|
||||
ERR_EXIT_ERRNO("Could not read from \"%s\"", path);
|
||||
|
||||
|
||||
@@ -15,7 +15,9 @@
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/mount.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "lib/dasd_base.h"
|
||||
|
||||
@@ -27,11 +29,13 @@
|
||||
|
||||
#define RUN_IOCTL(fd, req, argp) \
|
||||
do { \
|
||||
if (ioctl(fd, req, argp) != 0) { \
|
||||
int err = errno; \
|
||||
if (err != EBADF) \
|
||||
int rc = ioctl(fd, req, argp); \
|
||||
if (rc != 0) { \
|
||||
if (rc == -1) \
|
||||
rc = errno; \
|
||||
if (rc != EBADF) \
|
||||
dasd_close_device(fd); \
|
||||
return err; \
|
||||
return rc; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
@@ -321,3 +325,159 @@ int dasd_disk_release(const char *device)
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Unconditionally reserve DASD disk
|
||||
*
|
||||
* An existing reserve lock is lifted (steal lock) and the device
|
||||
* is reserved.
|
||||
*
|
||||
* @param[in] device node device node's name
|
||||
*
|
||||
* @retval 0 in case of success
|
||||
* @retval errno in case of failure
|
||||
*/
|
||||
int dasd_slock(const char *device)
|
||||
{
|
||||
int fd;
|
||||
|
||||
fd = dasd_open_device(device, O_RDONLY);
|
||||
RUN_IOCTL(fd, BIODASDSLCK, NULL);
|
||||
dasd_close_device(fd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the caching algorithm used for the channel programs of this device.
|
||||
*
|
||||
* @param[in] device node device node's name
|
||||
* @param[out] attrib_data pointer to dasd attrib data with:
|
||||
* 'cache' is the caching mode
|
||||
* 'no_cyl' the number of cylinders to be cached.
|
||||
*
|
||||
* @retval 0 in case of success
|
||||
* @retval errno in case of failure
|
||||
*/
|
||||
int dasd_get_cache(const char *device, attrib_data_t *attrib_data)
|
||||
{
|
||||
int fd;
|
||||
|
||||
fd = dasd_open_device(device, O_RDONLY);
|
||||
RUN_IOCTL(fd, BIODASDGATTR, attrib_data);
|
||||
dasd_close_device(fd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the caching algorithm used for the channel programs of this device.
|
||||
*
|
||||
* @param[in] device node device node's name
|
||||
* @param[in] attrib_data pointer to dasd attrib data with:
|
||||
* 'cache' is the caching mode
|
||||
* 'no_cyl' the number of cylinders to be cached.
|
||||
*
|
||||
* @retval 0 in case of success
|
||||
* @retval errno in case of failure
|
||||
*/
|
||||
int dasd_set_cache(const char *device, attrib_data_t *attrib_data)
|
||||
{
|
||||
int fd;
|
||||
|
||||
fd = dasd_open_device(device, O_RDONLY);
|
||||
RUN_IOCTL(fd, BIODASDSATTR, attrib_data);
|
||||
dasd_close_device(fd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get reserve status of device.
|
||||
*
|
||||
* @param[in] device node device node's name
|
||||
*
|
||||
* @retval errno in case of failure
|
||||
* @retval 0 unreserved
|
||||
* @retval 1 implicit reserved
|
||||
* @retval 2 other reservation
|
||||
* @retval 3 reserved
|
||||
*/
|
||||
int dasd_query_reserve(const char *device)
|
||||
{
|
||||
struct dasd_snid_ioctl_data snid = { 0 };
|
||||
int fd;
|
||||
|
||||
fd = dasd_open_device(device, O_RDONLY);
|
||||
RUN_IOCTL(fd, BIODASDSNID, &snid);
|
||||
dasd_close_device(fd);
|
||||
|
||||
return snid.data.path_state.reserve;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get and print the profiling info of the device.
|
||||
*
|
||||
* @param[in] device node device node's name
|
||||
* @param[in] dasd_profile_info pointer to dasd profile info
|
||||
*
|
||||
* @retval 0 in case of success
|
||||
* @retval errno in case of failure
|
||||
*/
|
||||
int dasd_profile(const char *device, dasd_profile_info_t *dasd_profile_info)
|
||||
{
|
||||
int fd;
|
||||
|
||||
fd = dasd_open_device(device, O_RDONLY);
|
||||
RUN_IOCTL(fd, BIODASDPRRD, dasd_profile_info);
|
||||
dasd_close_device(fd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reset the profiling counters of the device.
|
||||
*
|
||||
* @param[in] device node device node's name
|
||||
*
|
||||
* @retval 0 in case of success
|
||||
* @retval errno in case of failure
|
||||
*/
|
||||
int dasd_reset_profile(const char *device)
|
||||
{
|
||||
int fd;
|
||||
|
||||
fd = dasd_open_device(device, O_RDONLY);
|
||||
RUN_IOCTL(fd, BIODASDPRRST, NULL);
|
||||
dasd_close_device(fd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initiate the swap of a copy pairs primary,secondary relation.
|
||||
* The old secondary will become the new primary and vice versa.
|
||||
*
|
||||
* @param[in] device node device node's name
|
||||
* @param[in] copy_pair data pointer to dasd copypair data with:
|
||||
* 'primary' old primary, becoming secondary
|
||||
* 'secondary' old secondary, becoming primary.
|
||||
*
|
||||
* @retval errno in case of failure
|
||||
* @retval 0 in case of success
|
||||
* @retval 1 swap data invalid
|
||||
* @retval 2 no active device found
|
||||
* @retval 3 wrong primary specified
|
||||
* @retval 4 secondary device not found
|
||||
* @retval 5 swap already running
|
||||
*/
|
||||
int dasd_copy_swap(const char *device, struct dasd_copypair_swap_data *data)
|
||||
{
|
||||
int fd;
|
||||
|
||||
fd = dasd_open_device(device, O_RDONLY);
|
||||
RUN_IOCTL(fd, BIODASDPPRCSWAP, data);
|
||||
dasd_close_device(fd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "lib/util_libc.h"
|
||||
#include "lib/util_lockfile.h"
|
||||
|
||||
@@ -1419,7 +1419,6 @@ int lzds_dasd_read_rawvtoc(struct dasd *dasd, struct raw_vtoc *rawvtoc)
|
||||
|
||||
volume_label_t *vlabel = NULL;
|
||||
char *trackdata = NULL;
|
||||
char vol1[] = {0xe5, 0xd6, 0xd3, 0xf1, 0x00}; /* "VOL1" in EBCDIC */
|
||||
|
||||
errorlog_clear(dasd->log);
|
||||
|
||||
@@ -1431,8 +1430,7 @@ int lzds_dasd_read_rawvtoc(struct dasd *dasd, struct raw_vtoc *rawvtoc)
|
||||
goto cleanup;
|
||||
}
|
||||
/* verify that we have a proper VOL1 label */
|
||||
if (strncmp(vlabel->volkey, vol1, 4) ||
|
||||
strncmp(vlabel->vollbl, vol1, 4)) {
|
||||
if (!is_vol1(vlabel->volkey) || !is_vol1(vlabel->vollbl)) {
|
||||
rc = EINVAL;
|
||||
errorlog_add_message(
|
||||
&dasd->log, NULL, rc,
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
include ../common.mak
|
||||
|
||||
ALL_CFLAGS += -Wno-address-of-packed-member
|
||||
|
||||
all: mon_fsstatd mon_procd
|
||||
|
||||
mon_fsstatd: mon_fsstatd.o
|
||||
|
||||
@@ -24,7 +24,7 @@ Prints usage information, then exits.
|
||||
.B
|
||||
\fB-k\fP, \fB--host-key-document\fP=\fBFILE\fP
|
||||
Specify one or more host key documents. At least one is required.
|
||||
Specify this option multiple times to enable the image to run on more than one host.
|
||||
Specify this option multiple times to create an attestation request control block that is usable on multiple hosts.
|
||||
.TP
|
||||
.B
|
||||
\fB-C\fP, \fB--cert\fP=\fBFILE\fP
|
||||
|
||||
@@ -14,6 +14,8 @@ set -o pipefail
|
||||
set -o nounset
|
||||
set -e
|
||||
|
||||
XDUMP='od -A x -t x2z -v'
|
||||
|
||||
usage() {
|
||||
cat <<-EOF
|
||||
Usage: $(basename "$0") FILE
|
||||
@@ -33,16 +35,16 @@ function check_is_pvattest_binary() {
|
||||
exit 1
|
||||
fi
|
||||
|
||||
xxd -l 16 "${input}" | grep -q pvattest ||
|
||||
${XDUMP} --read-bytes 16 -- "${input}" 2>/dev/null | grep -q pvattest ||
|
||||
{ echo "ERROR: ${input} does not contain a pvattest binary output." >&2 && exit 1; }
|
||||
|
||||
size=$(xxd -s 12 -l 4 "${input}" | awk 'NR==1 {print "0x" $2 $3}')
|
||||
size=$(${XDUMP} --skip-bytes 12 --read-bytes 4 -- "${input}" 2>/dev/null | awk 'NR==1 {print "0x" $2 $3}')
|
||||
if [ $((size)) -lt 64 ]; then
|
||||
echo "ERROR: ${input} does not contain a pvattest binary output." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
version=$(xxd -s 8 -l 4 "$input")
|
||||
version=$(${XDUMP} --skip-bytes 8 --read-bytes 4 -- "$input" 2>/dev/null)
|
||||
echo "$version" | grep -q "0000 0100" ||
|
||||
{ echo -n "WARNING: unknown hdr version " >&2 &&
|
||||
echo "$version" | awk '{print "0x" $2 $3}'>&2 ; }
|
||||
@@ -55,24 +57,28 @@ function print_entry() {
|
||||
local size
|
||||
local off
|
||||
|
||||
size=$(xxd -s $((file_off)) -l 4 "${input}" | awk 'NR==1 {print "0x" $2 $3}')
|
||||
off=$(xxd -s $((file_off + 4)) -l 4 "${input}" | awk 'NR==1 {print "0x" $2 $3}')
|
||||
size=$(${XDUMP} --skip-bytes $((file_off)) --read-bytes 4 -- "${input}" 2>/dev/null |
|
||||
awk 'NR==1 {print "0x" $2 $3}')
|
||||
off=$(${XDUMP} --skip-bytes $((file_off + 4)) --read-bytes 4 -- "${input}" 2>/dev/null |
|
||||
awk 'NR==1 {print "0x" $2 $3}')
|
||||
|
||||
if [[ $size != "0x00000000" ]] || [[ $off != "0x00000000" ]]; then
|
||||
echo "${text}:"
|
||||
xxd -s $((off)) -l $((size)) -p "${input}"
|
||||
od -A n -w$((size)) -t x8 --skip-bytes $((off)) --read-bytes $((size)) -- "${input}" 2>/dev/null |\
|
||||
sed -e 's/\s//g'
|
||||
fi
|
||||
}
|
||||
|
||||
function require_command() {
|
||||
local cmd="$1"
|
||||
|
||||
command -v "$cmd" >/dev/null 2>&1 || { echo >&2 "ERROR: $cmd required but not installed."; exit 1; }
|
||||
command -v "$cmd" >/dev/null 2>&1 || \
|
||||
{ echo >&2 "ERROR: $cmd required but not installed."; exit 1; }
|
||||
}
|
||||
|
||||
require_command xxd
|
||||
require_command awk
|
||||
require_command wc
|
||||
require_command od
|
||||
|
||||
if [ $# -eq 0 ]; then
|
||||
echo "ERROR: Input not set. Use '$(basename "$0") [FILE]' to specify the Input file" >&2
|
||||
|
||||
@@ -14,7 +14,9 @@ set -o pipefail
|
||||
set -o nounset
|
||||
set -e
|
||||
|
||||
def_output="sehdr.bin"
|
||||
XDUMP='od -A x -t x2z -v'
|
||||
|
||||
def_output='sehdr.bin'
|
||||
def_skip=0x14
|
||||
def_len=0x4
|
||||
|
||||
@@ -37,11 +39,22 @@ function check_file() {
|
||||
function check_hdr_ver() {
|
||||
local hdr_start="$1"
|
||||
local input="$2"
|
||||
xxd -s $((hdr_start + 8)) -l 4 "$input" | grep -q "000 0100" ||
|
||||
${XDUMP} --skip-bytes $((hdr_start + 8)) --read-bytes 4 -- "$input" 2>/dev/null | grep -q "000 0100" ||
|
||||
{ echo -n "WARNING: unknown hdr version " &&
|
||||
xxd -s $((hdr_start + 8)) -l 4 "$input" | awk '{print "0x" $2 $3}'; }
|
||||
${XDUMP} --skip-bytes $((hdr_start + 8)) --read_bytes 4 -- "$input" 2>/dev/null | awk '{print "0x" $2 $3}'; }
|
||||
}
|
||||
|
||||
function require_command() {
|
||||
local cmd="$1"
|
||||
|
||||
command -v "$cmd" >/dev/null 2>&1 || \
|
||||
{ echo >&2 "ERROR: $cmd required but not installed."; exit 1; }
|
||||
}
|
||||
|
||||
require_command od
|
||||
require_command awk
|
||||
require_command grep
|
||||
|
||||
output=${def_output}
|
||||
parsed_skip=${def_skip}
|
||||
parsed_len=${def_len}
|
||||
@@ -77,13 +90,15 @@ if [ $# -eq 0 ]; then
|
||||
fi
|
||||
|
||||
check_file "$input"
|
||||
hdr_start=$(xxd -s $((skip)) -l $((len)) "${input}" | grep IBMSecEx || { echo ERROR: "${input} does not contain an SE header." >&2 && exit 1; })
|
||||
hdr_start=$(${XDUMP} --skip-bytes $((skip)) --read-bytes $((len)) -- "${input}" 2>/dev/null | grep IBMSecEx ||
|
||||
{ echo ERROR: "${input} does not contain an SE header." >&2 && exit 1; })
|
||||
hdr_start=$(echo "${hdr_start}" | awk '{print "0x" $1}' | cut -c 1-10)
|
||||
echo "SE header found at offset ${hdr_start}"
|
||||
|
||||
check_hdr_ver "$hdr_start" "$input"
|
||||
|
||||
size=$(xxd -s $((hdr_start + 12)) -l 4 "${input}" | awk 'NR==1 {print "0x" $2 $3}')
|
||||
size=$(${XDUMP} --skip-bytes $((hdr_start + 12)) --read-bytes 4 -- "${input}" 2>/dev/null |
|
||||
awk 'NR==1 {print "0x" $2 $3}')
|
||||
|
||||
dd if="${input}" of="${output}" bs=1 count=$((size)) skip=$((hdr_start)) status=none
|
||||
echo "SE header written to '${output}' ($((size)) bytes)"
|
||||
|
||||
@@ -1192,6 +1192,10 @@ post_processing() {
|
||||
rm -f "${file_name}"
|
||||
fi
|
||||
done
|
||||
|
||||
echo "log work directory state after post processing:"
|
||||
echo "du summary: $(du -ks ${WORKPATH})"
|
||||
df -k ${WORKPATH}
|
||||
}
|
||||
|
||||
########################################
|
||||
|
||||
@@ -31,6 +31,7 @@ int disk_query_reserve_status(char* device);
|
||||
int disk_profile (char* device, char* prof_item);
|
||||
int disk_reset_prof(char *device);
|
||||
int disk_reset_chpid(char *device, char *chpid);
|
||||
int disk_copy_swap(char *device, char *copy_pair);
|
||||
|
||||
#endif /* not DISK_H */
|
||||
|
||||
|
||||
@@ -174,6 +174,14 @@ Reset all channel paths of the selected device. The channel paths
|
||||
might be suspended due to high IFCC error rates or a High Performance
|
||||
FICON failure. Use this option to resume considering all defined
|
||||
channel paths for I/O.
|
||||
.TP
|
||||
.BR "\-s" " or " "\-\-copy\-pair\-swap <copy_pair>"
|
||||
Swap the copy roles of the specified copy pair. The <copy_pair> has to
|
||||
be a comma separated pair of \fBPRIMARY,SECONDARY\fR where
|
||||
\fBPRIMARY\fR is the old primary device that will become a secondary
|
||||
automatically. The old \fBSECONDARY\fR device will become the new
|
||||
primary device. Both devices have to be online for this operation to
|
||||
succeed.
|
||||
.\"
|
||||
.\".TP
|
||||
.\".BR "\-o" " or " "\-\-online"
|
||||
@@ -197,6 +205,12 @@ channel paths for I/O.
|
||||
.br
|
||||
|
||||
tunedasd -p 45 /dev/dasdc
|
||||
|
||||
.br
|
||||
4. Scenario: Swap copy pair 0.0.9700 and 0.0.9740
|
||||
.br
|
||||
|
||||
tunedasd -s 0.0.9700,0.0.9740 /dev/dasdc
|
||||
.br
|
||||
.SH "SEE ALSO"
|
||||
.BR dasdview (8),
|
||||
|
||||
@@ -19,98 +19,13 @@
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "lib/dasd_base.h"
|
||||
#include "lib/dasd_sys.h"
|
||||
#include "lib/util_libc.h"
|
||||
|
||||
#include "disk.h"
|
||||
#include "tunedasd.h"
|
||||
|
||||
#define BUS_ID_SIZE 30
|
||||
|
||||
/*
|
||||
* DASD DEFINITIONS (copied from dasd.h)
|
||||
*/
|
||||
|
||||
#define DASD_IOCTL_LETTER 'D'
|
||||
|
||||
/*
|
||||
* struct profile_info_t
|
||||
* holds the profiling information
|
||||
*/
|
||||
typedef struct dasd_profile_info_t {
|
||||
unsigned int dasd_io_reqs; /* # of requests processed at all */
|
||||
unsigned int dasd_io_sects; /* # of sectors processed at all */
|
||||
unsigned int dasd_io_secs[32]; /* request's sizes */
|
||||
unsigned int dasd_io_times[32]; /* requests's times */
|
||||
unsigned int dasd_io_timps[32]; /* requests's times per sector */
|
||||
unsigned int dasd_io_time1[32]; /* time from build to start */
|
||||
unsigned int dasd_io_time2[32]; /* time from start to irq */
|
||||
unsigned int dasd_io_time2ps[32]; /*time from start to irq */
|
||||
unsigned int dasd_io_time3[32]; /* time from irq to end */
|
||||
unsigned int dasd_io_nr_req[32]; /* # of requests in chanq */
|
||||
} dasd_profile_info_t;
|
||||
|
||||
|
||||
/*
|
||||
* struct attrib_data_t
|
||||
* represents the operation (cache) bits for the device.
|
||||
* Used in DE to influence caching of the DASD.
|
||||
*/
|
||||
typedef struct attrib_data_t {
|
||||
unsigned char operation:3; /* cache operation mode */
|
||||
unsigned char reserved:5;
|
||||
unsigned short nr_cyl; /* no of cyliners for read ahaed */
|
||||
unsigned char reserved2[29]; /* for future use */
|
||||
} __attribute__ ((packed)) attrib_data_t;
|
||||
|
||||
/* definition of operation (cache) bits within attributes of DE */
|
||||
#define DASD_NORMAL_CACHE 0x0
|
||||
#define DASD_BYPASS_CACHE 0x1
|
||||
#define DASD_INHIBIT_LOAD 0x2
|
||||
#define DASD_SEQ_ACCESS 0x3
|
||||
#define DASD_SEQ_PRESTAGE 0x4
|
||||
#define DASD_REC_ACCESS 0x5
|
||||
|
||||
/*
|
||||
* Data returned by Sense Path Group ID (SNID)
|
||||
*/
|
||||
struct dasd_snid_data {
|
||||
struct {
|
||||
__u8 group:2;
|
||||
__u8 reserve:2;
|
||||
__u8 mode:1;
|
||||
__u8 res:3;
|
||||
} __attribute__ ((packed)) path_state;
|
||||
__u8 pgid[11];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct dasd_snid_ioctl_data {
|
||||
struct dasd_snid_data data;
|
||||
__u8 path_mask;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
|
||||
/*
|
||||
* DASD-IOCTLs (copied from dasd.h)
|
||||
*/
|
||||
/* Issue a reserve/release command, rsp. */
|
||||
#define BIODASDRSRV _IO (DASD_IOCTL_LETTER,2) /* reserve */
|
||||
#define BIODASDRLSE _IO (DASD_IOCTL_LETTER,3) /* release */
|
||||
#define BIODASDSLCK _IO (DASD_IOCTL_LETTER,4) /* steal lock */
|
||||
/* reset profiling information of a device */
|
||||
#define BIODASDPRRST _IO (DASD_IOCTL_LETTER,5)
|
||||
|
||||
/* retrieve profiling information of a device */
|
||||
#define BIODASDPRRD _IOR (DASD_IOCTL_LETTER,2,dasd_profile_info_t)
|
||||
/* Get Attributes (cache operations) */
|
||||
#define BIODASDGATTR _IOR(DASD_IOCTL_LETTER,5,attrib_data_t)
|
||||
|
||||
/* Set Attributes (cache operations) */
|
||||
#define BIODASDSATTR _IOW (DASD_IOCTL_LETTER,2,attrib_data_t)
|
||||
|
||||
/* Get Sense Path Group ID (SNID) data */
|
||||
#define BIODASDSNID _IOWR(DASD_IOCTL_LETTER, 1, struct dasd_snid_ioctl_data)
|
||||
|
||||
|
||||
/* id definition for profile items */
|
||||
enum prof_id {
|
||||
prof_reqs = 0,
|
||||
@@ -241,48 +156,33 @@ check_prof_item (char* prof_item)
|
||||
* 'cache' is the caching mode (see ESS docu for more info) and 'no_cyl'
|
||||
* the number of cylinders to be cached.
|
||||
*/
|
||||
int
|
||||
disk_get_cache (char* device)
|
||||
int disk_get_cache(char *device)
|
||||
{
|
||||
int fd;
|
||||
attrib_data_t attrib_data;
|
||||
|
||||
/* Open device file */
|
||||
fd = open (device, O_RDONLY);
|
||||
if (fd == -1) {
|
||||
error_print ("<%s> - %s", device, strerror (errno));
|
||||
return -1;
|
||||
}
|
||||
int rc;
|
||||
|
||||
/* Get the given caching attributes */
|
||||
if (ioctl (fd, BIODASDGATTR, &attrib_data)) {
|
||||
error_print ("Could not get cache attributes for device <%s>",
|
||||
device);
|
||||
close (fd);
|
||||
return -1;
|
||||
}
|
||||
rc = dasd_get_cache(device, &attrib_data);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
printf ("%s (%i cyl)\n",
|
||||
get_cache_name(attrib_data.operation),
|
||||
attrib_data.nr_cyl);
|
||||
|
||||
close (fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Set the caching algorithm used for the channel programs of this device.
|
||||
* 'cache' is the caching mode (see ESS docu for more info) and 'no_cyl'
|
||||
* the number of cylinders to be cached.
|
||||
*/
|
||||
int
|
||||
disk_set_cache (char* device, char* cache, char* no_cyl)
|
||||
int disk_set_cache(char *device, char *cache, char *no_cyl)
|
||||
{
|
||||
int fd;
|
||||
attrib_data_t attrib_data;
|
||||
|
||||
/* get caching mode and # cylinders */
|
||||
int rc;
|
||||
|
||||
/* get caching mode and # cylinders */
|
||||
attrib_data.operation = check_cache (cache);
|
||||
attrib_data.nr_cyl = check_no_cyl (no_cyl);
|
||||
|
||||
@@ -292,52 +192,34 @@ disk_set_cache (char* device, char* cache, char* no_cyl)
|
||||
attrib_data.nr_cyl);
|
||||
}
|
||||
|
||||
/* Open device file */
|
||||
fd = open (device, O_RDONLY);
|
||||
if (fd == -1) {
|
||||
error_print ("<%s> - %s", device, strerror (errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Set the given caching attributes */
|
||||
printf ("Setting cache mode for device <%s>...\n", device);
|
||||
if (ioctl (fd, BIODASDSATTR, &attrib_data)) {
|
||||
error_print ("Could not set caching for device <%s>", device);
|
||||
close (fd);
|
||||
rc = dasd_set_cache(device, &attrib_data);
|
||||
if (rc) {
|
||||
error_print("Could not set caching for device <%s>", device);
|
||||
return -1;
|
||||
}
|
||||
|
||||
printf ("Done.\n");
|
||||
close (fd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Reserve the device.
|
||||
*/
|
||||
int
|
||||
disk_reserve (char* device)
|
||||
int disk_reserve(char *device)
|
||||
{
|
||||
int fd;
|
||||
|
||||
/* Open device file */
|
||||
fd = open (device, O_RDONLY);
|
||||
if (fd == -1) {
|
||||
error_print ("<%s> - %s", device, strerror (errno));
|
||||
return -1;
|
||||
}
|
||||
int rc;
|
||||
|
||||
/* Reserve device */
|
||||
printf ("Reserving device <%s>...\n", device);
|
||||
if (ioctl (fd, BIODASDRSRV)) {
|
||||
error_print ("Could not reserve device <%s>", device);
|
||||
close (fd);
|
||||
rc = dasd_disk_reserve(device);
|
||||
if (rc) {
|
||||
error_print("Could not reserve device <%s>", device);
|
||||
return -1;
|
||||
}
|
||||
|
||||
printf ("Done.\n");
|
||||
close (fd);
|
||||
printf("Done.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -345,28 +227,18 @@ disk_reserve (char* device)
|
||||
/*
|
||||
* Release the device.
|
||||
*/
|
||||
int
|
||||
disk_release (char* device)
|
||||
int disk_release(char *device)
|
||||
{
|
||||
int fd;
|
||||
int rc;
|
||||
|
||||
/* Open device file */
|
||||
fd = open (device, O_RDONLY);
|
||||
if (fd == -1) {
|
||||
error_print ("<%s> - %s", device, strerror (errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Release device */
|
||||
printf ("Releasing device <%s>...\n", device);
|
||||
if (ioctl (fd, BIODASDRLSE)) {
|
||||
error_print ("Could not release device <%s>", device);
|
||||
close (fd);
|
||||
rc = dasd_disk_release(device);
|
||||
if (rc) {
|
||||
error_print("Could not release device <%s>", device);
|
||||
return -1;
|
||||
}
|
||||
|
||||
printf ("Done.\n");
|
||||
close (fd);
|
||||
printf("Done.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -376,29 +248,19 @@ disk_release (char* device)
|
||||
* This means to reserve the device even if it was already reserved.
|
||||
* The current reserve is broken (steal lock).
|
||||
*/
|
||||
int
|
||||
disk_slock (char* device)
|
||||
int disk_slock(char *device)
|
||||
{
|
||||
int fd;
|
||||
|
||||
/* Open device file */
|
||||
fd = open (device, O_RDONLY);
|
||||
if (fd == -1) {
|
||||
error_print ("<%s> - %s", device, strerror (errno));
|
||||
return -1;
|
||||
}
|
||||
int rc;
|
||||
|
||||
/* Unconditional reserve device */
|
||||
printf ("Unconditional reserving device <%s>...\n", device);
|
||||
if (ioctl (fd, BIODASDSLCK)) {
|
||||
error_print ("Could not unconditional reserve device <%s>",
|
||||
device);
|
||||
close (fd);
|
||||
rc = dasd_slock(device);
|
||||
if (rc) {
|
||||
error_print("Could not unconditional reserve device <%s>", device);
|
||||
return -1;
|
||||
}
|
||||
|
||||
printf ("Done.\n");
|
||||
close (fd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -407,27 +269,16 @@ disk_slock (char* device)
|
||||
* Uses the Sense Path Group ID (SNID) ioctl to find out if
|
||||
* a device is reserved to it's path group.
|
||||
*/
|
||||
int
|
||||
disk_query_reserve_status(char* device)
|
||||
int disk_query_reserve_status(char *device)
|
||||
{
|
||||
int fd;
|
||||
struct dasd_snid_ioctl_data snid;
|
||||
int rc;
|
||||
|
||||
/* Open device file */
|
||||
fd = open (device, O_RDONLY);
|
||||
if (fd == -1) {
|
||||
error_print ("<%s> - %s", device, strerror (errno));
|
||||
rc = dasd_query_reserve(device);
|
||||
if (rc < 0) {
|
||||
error_print("Could not read reserve status for device <%s>", device);
|
||||
return -1;
|
||||
}
|
||||
snid.path_mask = 0;
|
||||
/* Release device */
|
||||
if (ioctl(fd, BIODASDSNID, &snid)) {
|
||||
error_print("Could not read reserve status"
|
||||
" for device <%s>", device);
|
||||
close (fd);
|
||||
return -1;
|
||||
}
|
||||
switch (snid.data.path_state.reserve) {
|
||||
switch (rc) {
|
||||
case 0:
|
||||
printf("none\n");
|
||||
break;
|
||||
@@ -441,7 +292,7 @@ disk_query_reserve_status(char* device)
|
||||
printf("reserved\n");
|
||||
break;
|
||||
}
|
||||
close (fd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -615,21 +466,14 @@ static int disk_profile_item(dasd_profile_info_t dasd_profile_info,
|
||||
/*
|
||||
* Get and print the profiling info of the device.
|
||||
*/
|
||||
int
|
||||
disk_profile (char* device, char* prof_item)
|
||||
int disk_profile(char *device, char *prof_item)
|
||||
{
|
||||
int fd, rc;
|
||||
dasd_profile_info_t dasd_profile_info;
|
||||
|
||||
/* Open device file */
|
||||
fd = open (device, O_RDONLY);
|
||||
if (fd == -1) {
|
||||
error_print ("<%s> - %s", device, strerror (errno));
|
||||
return -1;
|
||||
}
|
||||
int rc;
|
||||
|
||||
/* Get the profile info */
|
||||
if (ioctl (fd, BIODASDPRRD, &dasd_profile_info)) {
|
||||
rc = dasd_profile(device, &dasd_profile_info);
|
||||
if (rc) {
|
||||
switch (errno) {
|
||||
case EIO: /* profiling is not active */
|
||||
error_print ("Profiling (on device <%s>) is not "
|
||||
@@ -639,7 +483,6 @@ disk_profile (char* device, char* prof_item)
|
||||
error_print ("Could not get profile info for device "
|
||||
"<%s>.", device);
|
||||
}
|
||||
close (fd);
|
||||
return -1;
|
||||
}
|
||||
/* Check for profile item or summary */
|
||||
@@ -648,38 +491,26 @@ disk_profile (char* device, char* prof_item)
|
||||
} else {
|
||||
rc = disk_profile_item (dasd_profile_info, prof_item);
|
||||
}
|
||||
|
||||
close (fd);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Reset the profiling counters of the device.
|
||||
*/
|
||||
int
|
||||
disk_reset_prof (char* device)
|
||||
int disk_reset_prof(char *device)
|
||||
{
|
||||
int fd;
|
||||
|
||||
/* Open device file */
|
||||
fd = open (device, O_RDONLY);
|
||||
if (fd == -1) {
|
||||
error_print ("<%s> - %s", device, strerror (errno));
|
||||
return -1;
|
||||
}
|
||||
int rc;
|
||||
|
||||
/* reset profile info */
|
||||
printf ("Resetting profile info for device <%s>...\n", device);
|
||||
if (ioctl (fd, BIODASDPRRST)) {
|
||||
error_print ("Could not reset profile info for device <%s>",
|
||||
device);
|
||||
close (fd);
|
||||
rc = dasd_reset_profile(device);
|
||||
if (rc) {
|
||||
error_print("Could not reset profile info for device <%s>", device);
|
||||
return -1;
|
||||
}
|
||||
|
||||
printf ("Done.\n");
|
||||
close (fd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -717,3 +548,50 @@ int disk_reset_chpid(char *device, char *chpid)
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int disk_copy_swap(char *device, char *copy_pair)
|
||||
{
|
||||
struct dasd_copypair_swap_data data = { 0 };
|
||||
char *primary, *secondary;
|
||||
int rc = 0;
|
||||
|
||||
primary = strtok(copy_pair, ",");
|
||||
secondary = strtok(NULL, ",");
|
||||
|
||||
if (!primary || !secondary) {
|
||||
error_print("%s: Error parsing Copy Pair %s", device, copy_pair);
|
||||
return -1;
|
||||
}
|
||||
|
||||
util_strlcpy(data.primary, primary, DASD_BUS_ID_SIZE);
|
||||
util_strlcpy(data.secondary, secondary, DASD_BUS_ID_SIZE);
|
||||
|
||||
printf("Swapping copy pair %s %s on device <%s>...\n", primary, secondary, device);
|
||||
rc = dasd_copy_swap(device, &data);
|
||||
|
||||
switch (rc) {
|
||||
case 0:
|
||||
printf("Done.\n");
|
||||
return 0;
|
||||
case 1:
|
||||
error_print("Swap data invalid");
|
||||
break;
|
||||
case 2:
|
||||
error_print("No active device found");
|
||||
break;
|
||||
case 3:
|
||||
error_print("Wrong primary device specified");
|
||||
break;
|
||||
case 4:
|
||||
error_print("Secondary device not found");
|
||||
break;
|
||||
case 5:
|
||||
error_print("Swap already running");
|
||||
break;
|
||||
default:
|
||||
error_print("Swap not successful rc %d", rc);
|
||||
break;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -119,12 +119,17 @@ static struct util_opt opt_vec[] = {
|
||||
.desc = "Reset all channel paths of a device",
|
||||
.flags = UTIL_OPT_FLAG_NOSHORT,
|
||||
},
|
||||
{
|
||||
.option = { "copy-pair-swap", required_argument, NULL, 's' },
|
||||
.argument = "COPY_PAIR",
|
||||
.desc = "Swap a specified, comma separated copy pair.",
|
||||
},
|
||||
UTIL_OPT_HELP,
|
||||
UTIL_OPT_VERSION,
|
||||
UTIL_OPT_END
|
||||
};
|
||||
|
||||
#define CMD_KEYWORD_NUM 16
|
||||
#define CMD_KEYWORD_NUM 17
|
||||
#define DEVICES_NUM 256
|
||||
|
||||
enum cmd_keyword_id {
|
||||
@@ -144,6 +149,7 @@ enum cmd_keyword_id {
|
||||
cmd_keyword_path_all,
|
||||
cmd_keyword_enable_stats,
|
||||
cmd_keyword_disable_stats,
|
||||
cmd_keyword_copy_swap,
|
||||
};
|
||||
|
||||
|
||||
@@ -167,7 +173,8 @@ static const struct {
|
||||
{ "path_reset", cmd_keyword_path },
|
||||
{ "path_reset_all", cmd_keyword_path_all },
|
||||
{ "enable-stats", cmd_keyword_enable_stats },
|
||||
{ "disable-stats", cmd_keyword_disable_stats }
|
||||
{ "disable-stats", cmd_keyword_disable_stats },
|
||||
{ "copy-swap", cmd_keyword_copy_swap },
|
||||
};
|
||||
|
||||
|
||||
@@ -180,26 +187,27 @@ enum cmd_key_state {
|
||||
|
||||
/* Determines which combination of keywords are valid */
|
||||
static enum cmd_key_state cmd_key_table[CMD_KEYWORD_NUM][CMD_KEYWORD_NUM] = {
|
||||
/* help vers get_ cach no_c rese rele sloc prof prof rese quer path path
|
||||
* ion cach e yl rve ase k ile _ite t_pr y_re _all
|
||||
* e m of serv
|
||||
/* help vers get_ cach no_c rese rele sloc prof prof rese quer path path enab disa copy
|
||||
* ion cach e yl rve ase k ile _ite t_pr y_re _all le-s ble- -swa
|
||||
* e m of serv tats stat p
|
||||
*/
|
||||
/* help */ { req, opt, opt, opt, opt, opt, opt, opt, opt, opt, opt, inv, inv, inv, inv, inv },
|
||||
/* version */ { inv, req, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv },
|
||||
/* get_cache */ { opt, opt, req, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv },
|
||||
/* cache */ { opt, opt, inv, req, opt, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv },
|
||||
/* no_cyl */ { opt, opt, inv, req, req, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv },
|
||||
/* reserve */ { opt, opt, inv, inv, inv, req, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv },
|
||||
/* release */ { opt, opt, inv, inv, inv, inv, req, inv, inv, inv, inv, inv, inv, inv, inv, inv },
|
||||
/* slock */ { opt, opt, inv, inv, inv, inv, inv, req, inv, inv, inv, inv, inv, inv, inv, inv },
|
||||
/* profile */ { opt, opt, inv, inv, inv, inv, inv, inv, req, opt, inv, inv, inv, inv, inv, inv },
|
||||
/* prof_item */ { opt, opt, inv, inv, inv, inv, inv, inv, req, req, inv, inv, inv, inv, inv, inv },
|
||||
/* reset_prof */ { opt, opt, inv, inv, inv, inv, inv, inv, inv, inv, req, inv, inv, inv, inv, inv },
|
||||
/* query_reserve */ { inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, req, inv, inv, inv, inv },
|
||||
/* path */ { inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, req, inv, inv, inv },
|
||||
/* path_all */ { inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, req, inv, inv },
|
||||
/* enable-stats */ { inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, req, inv },
|
||||
/* disable-stats */ { inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, req },
|
||||
/* help */ { req, opt, opt, opt, opt, opt, opt, opt, opt, opt, opt, inv, inv, inv, inv, inv, inv },
|
||||
/* version */ { inv, req, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv },
|
||||
/* get_cache */ { opt, opt, req, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv },
|
||||
/* cache */ { opt, opt, inv, req, opt, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv },
|
||||
/* no_cyl */ { opt, opt, inv, req, req, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv },
|
||||
/* reserve */ { opt, opt, inv, inv, inv, req, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv },
|
||||
/* release */ { opt, opt, inv, inv, inv, inv, req, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv },
|
||||
/* slock */ { opt, opt, inv, inv, inv, inv, inv, req, inv, inv, inv, inv, inv, inv, inv, inv, inv },
|
||||
/* profile */ { opt, opt, inv, inv, inv, inv, inv, inv, req, opt, inv, inv, inv, inv, inv, inv, inv },
|
||||
/* prof_item */ { opt, opt, inv, inv, inv, inv, inv, inv, req, req, inv, inv, inv, inv, inv, inv, inv },
|
||||
/* reset_prof */ { opt, opt, inv, inv, inv, inv, inv, inv, inv, inv, req, inv, inv, inv, inv, inv, inv },
|
||||
/* query_reserve */ { inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, req, inv, inv, inv, inv, inv },
|
||||
/* path */ { inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, req, inv, inv, inv, inv },
|
||||
/* path_all */ { inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, req, inv, inv, inv },
|
||||
/* enable-stats */ { inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, req, inv, inv },
|
||||
/* disable-stats */ { inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, req, inv },
|
||||
/* copy-swap */ { inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, req },
|
||||
};
|
||||
|
||||
struct parameter {
|
||||
@@ -439,7 +447,9 @@ static int get_command_line(int argc, char *argv[], struct command_line *line)
|
||||
rc = store_option (&cmdline, cmd_keyword_query_reserve,
|
||||
optarg);
|
||||
break;
|
||||
|
||||
case 's':
|
||||
rc = store_option(&cmdline, cmd_keyword_copy_swap, optarg);
|
||||
break;
|
||||
case -1:
|
||||
/* End of options string - start of devices list */
|
||||
cmdline.device_id = optind;
|
||||
@@ -508,6 +518,9 @@ static int do_command(char *device, struct command_line cmdline)
|
||||
case cmd_keyword_path_all:
|
||||
rc = disk_reset_chpid(device, NULL);
|
||||
break;
|
||||
case cmd_keyword_copy_swap:
|
||||
rc = disk_copy_swap(device, cmdline.parm[cmd_keyword_copy_swap].data);
|
||||
break;
|
||||
default:
|
||||
error_print ("Unknown command '%s' specified",
|
||||
get_keyword_name (i));
|
||||
|
||||
158
zconf/lsdasd
158
zconf/lsdasd
@@ -35,6 +35,8 @@ function PrintUsage() {
|
||||
Print extended information about DASDs.
|
||||
-H|--host-access-list
|
||||
Print information about hosts accessing DASDs.
|
||||
-P|--copy-pairs
|
||||
Print information about copy pairs.
|
||||
-v|--verbose
|
||||
For compatibility/future use. Currently ignored.
|
||||
--version
|
||||
@@ -146,6 +148,62 @@ function findDASDDebugfsDirectorie() {
|
||||
fi
|
||||
}
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# The blockpath can usually be found over the DEVPATH
|
||||
# In case of a swapped Copy Pair device the blockdev is likely associated
|
||||
# with one of the secondary devices
|
||||
# this function checks if the blockdev is associated with the primary device
|
||||
# and if not search for it in the secondary device list
|
||||
#------------------------------------------------------------------------------
|
||||
function setCorrectBlockPath() {
|
||||
local DRIVERECKD="$SYSFSDIR/bus/ccw/drivers/dasd-eckd/"
|
||||
local DRIVERFBA="$SYSFSDIR/bus/ccw/drivers/dasd-fba/"
|
||||
local SEARCHDIRS=
|
||||
local SEARCHLIST=
|
||||
|
||||
if [[ "$COPYROLE" == "none" ]] || [[ -d "$DEVPATH/block" ]]; then
|
||||
BLOCKPATH="$DEVPATH"/block/dasd*
|
||||
return
|
||||
fi
|
||||
|
||||
if [[ -d "$DRIVERECKD" ]]; then
|
||||
SEARCHDIRS="$DRIVERECKD"
|
||||
fi
|
||||
if [[ -d "$DRIVERFBA" ]]; then
|
||||
SEARCHDIRS="$SEARCHDIRS $DRIVERFBA"
|
||||
fi
|
||||
|
||||
SEARCHLIST=$(echo $SECONDARY_LIST | sed 's/,/ /g')
|
||||
for SEARCHDEV in $SEARCHLIST
|
||||
do
|
||||
if [[ -n "$SEARCHDIRS" ]]; then
|
||||
PRIM_DEVPATH=$(find $SEARCHDIRS -type l -name $SEARCHDEV \
|
||||
-printf "%h/%l\n" 2> /dev/null)
|
||||
if [[ -d "$PRIM_DEVPATH/block" ]]; then
|
||||
break
|
||||
fi
|
||||
else
|
||||
# The above paths may become invalid in the future, so we keep the
|
||||
# following query as backup:
|
||||
PRIM_DEVPATH=$(find "$SYSFSDIR/devices" -type l -name $SEARCHDEV \
|
||||
"driver" -lname "*/dasd*" -printf "%h\n" \
|
||||
2> /dev/null)
|
||||
fi
|
||||
done
|
||||
|
||||
BLOCKPATH="$PRIM_DEVPATH"/block/dasd*
|
||||
}
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# gather Copy Pair related data
|
||||
#------------------------------------------------------------------------------
|
||||
function gatherCopyPairData() {
|
||||
read COPYPAIR 2> /dev/null < $DEVPATH/copy_pair
|
||||
PRIMARY_UID=`echo $COPYPAIR | cut -d " " -f1 | cut -d "," -f1`
|
||||
COPYPAIR=`echo "$COPYPAIR" | sed 's/ /,/g' | sed 's/^,//' `
|
||||
SECONDARY_LIST=`echo ${COPYPAIR//$PRIMARY_UID","/} `
|
||||
}
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# gather device data and call appropriate output function
|
||||
#------------------------------------------------------------------------------
|
||||
@@ -165,16 +223,18 @@ function gatherDeviceData() {
|
||||
read READONLY 2> /dev/null < $DEVPATH/readonly || continue
|
||||
read DISCIPLINE 2> /dev/null < $DEVPATH/discipline || continue
|
||||
read ESE 2> /dev/null < $DEVPATH/ese
|
||||
read COPYROLE 2> /dev/null < $DEVPATH/copy_role
|
||||
|
||||
if [[ "$COPYROLE" != "none" ]]; then
|
||||
gatherCopyPairData
|
||||
fi
|
||||
# Block device specific information is only available for
|
||||
# devices that are online and not a PAV alias
|
||||
if [[ ! "$ONLINE" == 0 ]] && [[ ! "$ALIAS" == 1 ]]; then
|
||||
#find device Path to the block device
|
||||
if [[ -d "$DEVPATH/block" ]]; then
|
||||
set - "$DEVPATH"/block/dasd*
|
||||
else
|
||||
set - "$DEVPATH"/block:dasd*
|
||||
fi
|
||||
if [[ ! "$ONLINE" == 0 ]] && [[ ! "$ALIAS" == 1 ]] &&
|
||||
[[ ! "$COPYROLE" == "secondary" ]]; then
|
||||
#find device Path to the block device
|
||||
setCorrectBlockPath
|
||||
set - $BLOCKPATH
|
||||
MAJMIN=
|
||||
MAJOR=
|
||||
MINOR=
|
||||
@@ -194,10 +254,12 @@ function gatherDeviceData() {
|
||||
fi
|
||||
fi
|
||||
else
|
||||
# BLOCKNAME for offline and alias devices will not be
|
||||
# printed, it's just a key for sorting
|
||||
# BLOCKNAME for offline, alias and secondary devices
|
||||
# will not be printed, it's just a key for sorting
|
||||
if [[ "$ONLINE" == 0 ]]; then
|
||||
BLOCKNAME=""
|
||||
elif [[ "$COPYROLE" == "secondary" ]]; then
|
||||
BLOCKNAME="b"
|
||||
else
|
||||
BLOCKNAME="a"
|
||||
fi
|
||||
@@ -232,6 +294,8 @@ function gatherDeviceData() {
|
||||
uid
|
||||
elif [[ "$OUTPUT" == "host" ]]; then
|
||||
host
|
||||
elif [[ "$OUTPUT" == "copy" ]]; then
|
||||
copy
|
||||
else
|
||||
newoutput
|
||||
fi
|
||||
@@ -261,6 +325,15 @@ function newoutput()
|
||||
return
|
||||
fi
|
||||
|
||||
if [[ "$COPYROLE" == "secondary" ]]; then
|
||||
printf "%s:%s:%-8s secondary %-8s %13s\n" \
|
||||
"$SORTKEYLEN" "$SORTKEY" \
|
||||
"$BUSID" \
|
||||
"$PRIMARY_BLOCKNAME" \
|
||||
"$DISCIPLINE"
|
||||
return
|
||||
fi
|
||||
|
||||
if [[ "$READONLY" == 0 ]]; then
|
||||
ROSTRING=""
|
||||
else
|
||||
@@ -519,10 +592,14 @@ function extended()
|
||||
"${HPF_PATHS[@]}" \
|
||||
"${IFCC_PATHS[@]}" ;
|
||||
return
|
||||
elif [[ "$ALIAS" == 1 ]]; then
|
||||
if [[ "$BASEONLY" == "false" ]]; then
|
||||
ACTIVE="alias"
|
||||
printf "%s:%s:%s# status:\t\t\t\t%s# type: \t\t\t\t%s# use_diag:\t\t\t\t%s# readonly:\t\t\t\t%s# eer_enabled:\t\t\t\t%s# erplog:\t\t\t\t%s# hpf:\t\t\t\t\t%s # uid: \t\t\t\t%s# fc_security: \t\t\t\t%s# paths_installed: \t\t\t%s %s %s %s %s %s %s %s# paths_in_use: \t\t\t%s %s %s %s %s %s %s %s# paths_non_preferred: \t\t\t%s %s %s %s %s %s %s %s# paths_invalid_cabling: \t\t%s %s %s %s %s %s %s %s# paths_cuir_quiesced: \t\t\t%s %s %s %s %s %s %s %s# paths_invalid_hpf_characteristics: \t%s %s %s %s %s %s %s %s# paths_error_threshold_exceeded: \t%s %s %s %s %s %s %s %s#\n" \
|
||||
elif [[ "$ALIAS" == 1 ]] || [[ "$COPYROLE" == "secondary" ]]; then
|
||||
if [[ "$BASEONLY" == "false" ]] || [[ "$COPYROLE" == "secondary" ]]; then
|
||||
if [[ "$COPYROLE" == "secondary" ]]; then
|
||||
ACTIVE="secondary"
|
||||
else
|
||||
ACTIVE="alias"
|
||||
fi
|
||||
printf "%s:%s:%s# status:\t\t\t\t%s# type: \t\t\t\t%s# use_diag:\t\t\t\t%s# readonly:\t\t\t\t%s# eer_enabled:\t\t\t\t%s# erplog:\t\t\t\t%s# hpf:\t\t\t\t\t%s # uid: \t\t\t\t%s# fc_security: \t\t\t\t%s# paths_installed: \t\t\t%s %s %s %s %s %s %s %s# paths_in_use: \t\t\t%s %s %s %s %s %s %s %s# paths_non_preferred: \t\t\t%s %s %s %s %s %s %s %s# paths_invalid_cabling: \t\t%s %s %s %s %s %s %s %s# paths_cuir_quiesced: \t\t\t%s %s %s %s %s %s %s %s# paths_invalid_hpf_characteristics: \t%s %s %s %s %s %s %s %s# paths_error_threshold_exceeded: \t%s %s %s %s %s %s %s %s# copy_pairs:\t\t\t\t%s#\n" \
|
||||
"$SORTKEYLEN" "$SORTKEY" \
|
||||
"$BUSID" \
|
||||
"$ACTIVE" \
|
||||
@@ -540,7 +617,8 @@ function extended()
|
||||
"${CABLE_PATHS[@]}" \
|
||||
"${CUIR_PATHS[@]}" \
|
||||
"${HPF_PATHS[@]}" \
|
||||
"${IFCC_PATHS[@]}" ;
|
||||
"${IFCC_PATHS[@]}" \
|
||||
"${COPYPAIR}" ;
|
||||
fi
|
||||
return
|
||||
elif [[ -z "$BLOCKNAME" ]] || [[ -z "$SIZE" ]]; then
|
||||
@@ -565,7 +643,7 @@ function extended()
|
||||
DISCIPLINE="${DISCIPLINE} (ESE)"
|
||||
fi
|
||||
|
||||
printf "%s:%s:%s/%s/%s%s%s# status:\t\t\t\t%s# type: \t\t\t\t%s# blksz:\t\t\t\t%s# size: \t\t\t\t%s# blocks:\t\t\t\t%s# extent_size:\t\t\t\t%s# logical_capacity:\t\t\t%s# space_allocated:\t\t\t%s# use_diag:\t\t\t\t%s# readonly:\t\t\t\t%s# eer_enabled:\t\t\t\t%s# erplog:\t\t\t\t%s# hpf:\t\t\t\t\t%s# uid: \t\t\t\t%s# fc_security: \t\t\t\t%s# paths_installed: \t\t\t%s %s %s %s %s %s %s %s# paths_in_use: \t\t\t%s %s %s %s %s %s %s %s# paths_non_preferred: \t\t\t%s %s %s %s %s %s %s %s# paths_invalid_cabling: \t\t%s %s %s %s %s %s %s %s# paths_cuir_quiesced: \t\t\t%s %s %s %s %s %s %s %s# paths_invalid_hpf_characteristics: \t%s %s %s %s %s %s %s %s# paths_error_threshold_exceeded: \t%s %s %s %s %s %s %s %s#\n" \
|
||||
printf "%s:%s:%s/%s/%s%s%s# status:\t\t\t\t%s# type: \t\t\t\t%s# blksz:\t\t\t\t%s# size: \t\t\t\t%s# blocks:\t\t\t\t%s# extent_size:\t\t\t\t%s# logical_capacity:\t\t\t%s# space_allocated:\t\t\t%s# use_diag:\t\t\t\t%s# readonly:\t\t\t\t%s# eer_enabled:\t\t\t\t%s# erplog:\t\t\t\t%s# hpf:\t\t\t\t\t%s# uid: \t\t\t\t%s# fc_security: \t\t\t\t%s# paths_installed: \t\t\t%s %s %s %s %s %s %s %s# paths_in_use: \t\t\t%s %s %s %s %s %s %s %s# paths_non_preferred: \t\t\t%s %s %s %s %s %s %s %s# paths_invalid_cabling: \t\t%s %s %s %s %s %s %s %s# paths_cuir_quiesced: \t\t\t%s %s %s %s %s %s %s %s# paths_invalid_hpf_characteristics: \t%s %s %s %s %s %s %s %s# paths_error_threshold_exceeded: \t%s %s %s %s %s %s %s %s# copy_pairs:\t\t\t\t%s#\n" \
|
||||
"$SORTKEYLEN" "$SORTKEY" \
|
||||
"$BUSID" \
|
||||
"$BLOCKNAME" \
|
||||
@@ -593,7 +671,8 @@ function extended()
|
||||
"${CABLE_PATHS[@]}" \
|
||||
"${CUIR_PATHS[@]}" \
|
||||
"${HPF_PATHS[@]}" \
|
||||
"${IFCC_PATHS[@]}" ;
|
||||
"${IFCC_PATHS[@]}" \
|
||||
"${COPYPAIR}" ;
|
||||
}
|
||||
|
||||
function host()
|
||||
@@ -694,6 +773,41 @@ printf "\n";
|
||||
rm -f $temp
|
||||
}
|
||||
|
||||
# pad sortkey with given number zeroes
|
||||
function padSortKey()
|
||||
{
|
||||
local LEN=$1
|
||||
for (( i=0; i<$LEN; i++ ))
|
||||
do
|
||||
printf -v SORTKEY "%s0" $SORTKEY
|
||||
done
|
||||
}
|
||||
|
||||
function copy()
|
||||
{
|
||||
if [[ "$COPYROLE" == "none" ]]; then
|
||||
return
|
||||
fi
|
||||
|
||||
SORTKEYLEN=$((${#PRIMARY_UID}+${#DEV_UID}))
|
||||
if [[ "$COPYROLE" == "secondary" ]]; then
|
||||
SORTKEY=$PRIMARY_UID$DEV_UID
|
||||
PAIREDDEVICES=$PRIMARY_UID
|
||||
BLOCKNAME=""
|
||||
else
|
||||
SORTKEY=$PRIMARY_UID
|
||||
padSortKey ${#DEV_UID}
|
||||
PAIREDDEVICES=$SECONDARY_LIST
|
||||
fi
|
||||
|
||||
printf "%s:%s:%-8s %-10s %-8s %-8s %s \n" \
|
||||
"$SORTKEYLEN" "$SORTKEY" \
|
||||
"$BUSID" \
|
||||
"$COPYROLE" \
|
||||
"$BLOCKNAME" \
|
||||
"$PAIREDDEVICES";
|
||||
}
|
||||
|
||||
function uid()
|
||||
{
|
||||
#-------------------------------------------#
|
||||
@@ -710,7 +824,11 @@ function uid()
|
||||
fi
|
||||
fi
|
||||
|
||||
printf "%s:%s:%-8s %-8s %s\n" \
|
||||
if [[ "$COPYROLE" == "secondary" ]]; then
|
||||
BLOCKNAME="secondary"
|
||||
fi
|
||||
|
||||
printf "%s:%s:%-8s %-10s %s\n" \
|
||||
"$SORTKEYLEN" "$SORTKEY" \
|
||||
"$BUSID" \
|
||||
"$BLOCKNAME" \
|
||||
@@ -756,6 +874,9 @@ while [ $# -gt 0 ]; do
|
||||
--host-access-list|-H)
|
||||
OUTPUT="host"
|
||||
;;
|
||||
--copy-pairs|-P)
|
||||
OUTPUT="copy"
|
||||
;;
|
||||
--version)
|
||||
PrintVersion
|
||||
exit 0
|
||||
@@ -810,6 +931,9 @@ if [[ "$PRINTUID" == "true" ]] && [[ "$OUTPUT" != "old" ]]; then
|
||||
elif [[ "$OUTPUT" == "new" ]]; then
|
||||
printf "Bus-ID Status Name Device Type BlkSz Size Blocks\n"
|
||||
printf "================================================================================\n"
|
||||
elif [[ "$OUTPUT" == "copy" ]]; then
|
||||
printf "Bus-ID Role Name Paired devices\n";
|
||||
printf "================================================================================\n";
|
||||
elif [[ "$OUTPUT" == "extended" ]]; then
|
||||
PROCESSING=" $PROCESSING | sed 's/#/\n/g' "
|
||||
fi
|
||||
|
||||
@@ -66,7 +66,7 @@ typedef char *(*table_value_cb_t)(void *item, int id, const char *heading,
|
||||
struct column *table_get_column(struct column *, const char *);
|
||||
exit_code_t table_print(struct column *, table_value_cb_t, void *,
|
||||
struct util_list *, struct util_list *, int, int, int,
|
||||
int);
|
||||
int, int);
|
||||
exit_code_t table_check_columns(struct column *, struct util_list *);
|
||||
void table_print_columns(struct column *, struct util_list *, int, int);
|
||||
void table_set_default(struct column *, int, int);
|
||||
|
||||
@@ -23,7 +23,7 @@ struct table_attrib {
|
||||
};
|
||||
|
||||
struct table_attrib *table_attrib_new(struct subtype *, struct attrib *);
|
||||
void table_attribs_show(struct util_list *, int, int, struct devtype *);
|
||||
void table_attribs_show(struct util_list *, int, int, int, struct devtype *);
|
||||
void table_attribs_show_details(struct util_list *, struct devtype *);
|
||||
|
||||
#endif /* TABLE_ATTRIBS_H */
|
||||
|
||||
@@ -423,6 +423,17 @@ with the name of the corresponding column. Values are enclosed in double
|
||||
quotation marks. Any quotation marks or slashes in the value string are
|
||||
escaped by placing a slash in front of it.
|
||||
.PP
|
||||
|
||||
.OD shell "" ""
|
||||
Produces KEY="VALUE" format usable as shell variables.
|
||||
|
||||
You can use this option together with the --pairs option to generate
|
||||
output that is suitable to be sourced in a shell environment. This
|
||||
option generates similar output as it would be provided by the --pairs
|
||||
option but it would take care of replacing any character of a column
|
||||
name that would not be appropriate to be used as part of a shell
|
||||
variable name by an underscore.
|
||||
.PP
|
||||
.
|
||||
.OD persistent "p" ""
|
||||
List information from the persistent configuration only.
|
||||
|
||||
@@ -2532,7 +2532,7 @@ static exit_code_t do_list_attribs(struct options *opts)
|
||||
remove_duplicate_attribs(attribs, devtype_count_subtypes(dt));
|
||||
|
||||
if (attribs) {
|
||||
table_attribs_show(attribs, 1, 0, dt);
|
||||
table_attribs_show(attribs, 1, 0, 0, dt);
|
||||
ptrlist_free(attribs, 1);
|
||||
} else
|
||||
rc = EXIT_ATTRIB_NOT_FOUND;
|
||||
|
||||
@@ -137,6 +137,21 @@ static struct attrib dasd_attr_readonly = {
|
||||
.accept = ACCEPT_ARRAY(ACCEPT_RANGE(0, 1)),
|
||||
};
|
||||
|
||||
static struct attrib dasd_attr_copy_pair = {
|
||||
.name = "copy_pair",
|
||||
.title = "Modify copy-pair relations",
|
||||
.desc = "Make a copy-pair relation for this device known to the DASD "
|
||||
"driver.\n"
|
||||
"A copy-pair is a comma-separated pair of device bus-IDs\n"
|
||||
"<primary>,<secondary>.\n"
|
||||
"Example: 0.0.1000,0.0.2000\n"
|
||||
"Up to 4 copy-pairs are accepted by the DASD driver for each "
|
||||
"device.\n",
|
||||
.unstable = 1,
|
||||
.multi = 1,
|
||||
.activerem = 1,
|
||||
};
|
||||
|
||||
static struct attrib dasd_attr_erplog = {
|
||||
.name = "erplog",
|
||||
.title = "Enable logging of Error Recovery Processing",
|
||||
@@ -600,6 +615,81 @@ persistent:
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Remove all entries from the copy_pair attribute by writing 'clear' to it. */
|
||||
static void dasd_clear_copy_pair(struct setting *s)
|
||||
{
|
||||
free(s->value);
|
||||
s->value = misc_strdup("clear");
|
||||
strlist_free(s->values);
|
||||
s->values = strlist_new();
|
||||
strlist_add(s->values, "clear");
|
||||
s->removed = 0;
|
||||
s->modified = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy-pair values may contain multiple values in one line
|
||||
* those need to be split up and put in multiple values entries
|
||||
* delimiter is " " and "\n" depending on the source
|
||||
* values read from sysfs have " " as delimiter and values from
|
||||
* zdev have "\n"
|
||||
*/
|
||||
static void dasd_split_copy_pair(struct setting *s)
|
||||
{
|
||||
struct util_list *new = NULL;
|
||||
struct strlist_node *node;
|
||||
|
||||
new = strlist_new();
|
||||
util_list_iterate(s->values, node)
|
||||
strlist_add_multi(new, node->str, "\n ", 0);
|
||||
|
||||
strlist_free(s->values);
|
||||
s->values = new;
|
||||
}
|
||||
|
||||
/*
|
||||
* For persistent configurations one value per values[] entry is required
|
||||
* to achieve a correct multi-line copy-pair statement in the resulting
|
||||
* udev-rule.
|
||||
*/
|
||||
static exit_code_t dasd_st_configure_persistent(struct subtype *st,
|
||||
struct device *dev)
|
||||
{
|
||||
struct setting *s;
|
||||
|
||||
util_list_iterate(&dev->persistent.settings->list, s) {
|
||||
if (strcmp(s->name, "copy_pair") == 0)
|
||||
dasd_split_copy_pair(s);
|
||||
}
|
||||
|
||||
return st->super->configure_persistent(st, dev);
|
||||
}
|
||||
|
||||
/*
|
||||
* For active configurations one value per values[] entry is required to
|
||||
* correctly operate the sysfs attribute.
|
||||
*
|
||||
* In case of removal the string "clear" has to be written to the
|
||||
* value and values[] entry.
|
||||
*/
|
||||
static exit_code_t dasd_st_configure_active(struct subtype *st,
|
||||
struct device *dev)
|
||||
{
|
||||
struct setting *s;
|
||||
|
||||
util_list_iterate(&dev->active.settings->list, s) {
|
||||
if (strcmp(s->name, "copy_pair") != 0)
|
||||
continue;
|
||||
|
||||
if (s->removed)
|
||||
dasd_clear_copy_pair(s);
|
||||
else
|
||||
dasd_split_copy_pair(s);
|
||||
}
|
||||
|
||||
return st->super->configure_active(st, dev);
|
||||
}
|
||||
|
||||
/*
|
||||
* DASD device sub-types.
|
||||
*/
|
||||
@@ -634,10 +724,13 @@ struct subtype dasd_subtype_eckd = {
|
||||
&dasd_attr_last_known_reservation_state,
|
||||
&dasd_attr_safe_offline,
|
||||
&dasd_attr_fc_security,
|
||||
&dasd_attr_copy_pair,
|
||||
&internal_attr_early,
|
||||
),
|
||||
.unknown_dev_attribs = 1,
|
||||
|
||||
.configure_active = &dasd_st_configure_active,
|
||||
.configure_persistent = &dasd_st_configure_persistent,
|
||||
.check_pre_configure = &dasd_st_check_pre_configure,
|
||||
.add_modules = &dasd_st_add_modules,
|
||||
};
|
||||
|
||||
@@ -70,6 +70,7 @@ struct options {
|
||||
unsigned int no_headings:1;
|
||||
struct util_list *base; /* List of struct strlist_node */
|
||||
unsigned int pairs:1;
|
||||
unsigned int shell:1;
|
||||
unsigned int verbose:1;
|
||||
unsigned int quiet:1;
|
||||
unsigned int site_id;
|
||||
@@ -106,6 +107,7 @@ enum {
|
||||
OPT_VERBOSE = 'V',
|
||||
OPT_QUIET = 'q',
|
||||
OPT_PAIRS = 'P',
|
||||
OPT_SHELL = (OPT_ANONYMOUS_BASE+__COUNTER__),
|
||||
OPT_AUTO_CONF = (OPT_ANONYMOUS_BASE+__COUNTER__),
|
||||
OPT_SITE = 's',
|
||||
};
|
||||
@@ -167,6 +169,7 @@ static const struct option opt_list[] = {
|
||||
{ "no-headings", no_argument, NULL, OPT_NO_HEADINGS },
|
||||
{ "base", required_argument, NULL, OPT_BASE },
|
||||
{ "pairs", no_argument, NULL, OPT_PAIRS },
|
||||
{ "shell", no_argument, NULL, OPT_SHELL },
|
||||
{ "verbose", no_argument, NULL, OPT_VERBOSE },
|
||||
{ "quiet", no_argument, NULL, OPT_QUIET },
|
||||
{ "site", required_argument, NULL, OPT_SITE },
|
||||
@@ -699,6 +702,11 @@ static exit_code_t parse_options(struct options *opts, int argc, char *argv[])
|
||||
opts->pairs = 1;
|
||||
break;
|
||||
|
||||
case OPT_SHELL:
|
||||
/* --shell */
|
||||
opts->shell = 1;
|
||||
break;
|
||||
|
||||
case OPT_VERBOSE:
|
||||
/* --verbose */
|
||||
opts->verbose = 1;
|
||||
@@ -761,6 +769,13 @@ static exit_code_t parse_options(struct options *opts, int argc, char *argv[])
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
/* check whether --pairs and --columns is used */
|
||||
if (opts->shell == 1 && (opts->pairs != 1 || util_list_is_empty(opts->columns))) {
|
||||
syntax("'--shell' must be used together with "
|
||||
"'--pairs' and '--columns'\n");
|
||||
return EXIT_USAGE_ERROR;
|
||||
}
|
||||
|
||||
/* Determine configuration set. */
|
||||
if (!opts->active && !opts->persistent && !opts->auto_conf) {
|
||||
/* Default display targets are active + persistent - note that
|
||||
@@ -1209,7 +1224,7 @@ static exit_code_t do_list_devices(struct options *opts)
|
||||
/* Display table. */
|
||||
rc = table_print(dev_table, dev_table_get_value, opts, items,
|
||||
opts->columns, !opts->no_headings, opts->pairs, 0,
|
||||
util_list_is_empty(opts->columns));
|
||||
util_list_is_empty(opts->columns), opts->shell);
|
||||
ptrlist_free(items, 0);
|
||||
|
||||
return rc;
|
||||
@@ -1443,7 +1458,7 @@ static void settings_table_print(struct setting_list *active,
|
||||
data.pairs = opts->pairs;
|
||||
|
||||
table_print(settings_table, settings_table_get_value, &data, items,
|
||||
NULL, 1, opts->pairs, ind, 0);
|
||||
NULL, 1, opts->pairs, ind, 0, opts->shell);
|
||||
|
||||
out:
|
||||
ptrlist_free(items, 1);
|
||||
|
||||
@@ -41,6 +41,7 @@ OPTIONS
|
||||
-n, --no-headings Do not print column headings
|
||||
--base PATH Use PATH as base for accessing files
|
||||
--pairs Produce output in KEY="VALUE" format
|
||||
--shell Produces KEY="VALUE" format usable as shell variables
|
||||
--auto-conf Only show auto-configuration data
|
||||
-s, --site ID Only show data configured for the specified site
|
||||
-V, --verbose Print additional run-time information
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
* it under the terms of the MIT license. See LICENSE for details.
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
@@ -116,6 +117,40 @@ static struct cell *cells_get_default(struct column *columns)
|
||||
return cells;
|
||||
}
|
||||
|
||||
bool is_shell_char(const char c)
|
||||
{
|
||||
/* check whether character is alphabetic */
|
||||
if (tolower(c) >= 'a' && tolower(c) <= 'z')
|
||||
return true;
|
||||
if (isdigit(c) || c == '_')
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/* replaces bad characters that won't work if using them
|
||||
* as part of variable names in a shell environment
|
||||
*/
|
||||
char *replace_bad_chars(const char *value)
|
||||
{
|
||||
int i;
|
||||
char *copy, c;
|
||||
|
||||
/* remove bad characters and replace them by an underscore */
|
||||
copy = misc_strdup(value);
|
||||
for (i = 0; (c = value[i]); i++) {
|
||||
/*
|
||||
* check whether character is alphabetic,
|
||||
* first character of an env var can't be a digit
|
||||
*/
|
||||
if (!is_shell_char(c) || (i == 0 && isdigit(c)))
|
||||
c = '_';
|
||||
/* copy character into string copy */
|
||||
copy[i] = c;
|
||||
}
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
/* Return a newly allocated array of struct cells containing a struct cell for
|
||||
* each column definition whose name was specified in strlist @names. */
|
||||
static struct cell *cells_get(struct column *columns, struct util_list *names)
|
||||
@@ -320,17 +355,23 @@ do_print:
|
||||
}
|
||||
|
||||
/* Print all cells in a row in pairs format. */
|
||||
static void print_row_pairs(struct cell *cells)
|
||||
static void print_row_pairs(struct cell *cells, int shell)
|
||||
{
|
||||
int i;
|
||||
struct cell *c;
|
||||
char *val;
|
||||
char *heading;
|
||||
|
||||
for (i = 0; cells[i].heading; i++) {
|
||||
c = &cells[i];
|
||||
val = quote_str(c->value ? c->value : "", 1);
|
||||
printf("%s%s=%s", i > 0 ? " " : "", c->heading, val);
|
||||
if (shell)
|
||||
heading = replace_bad_chars(c->heading);
|
||||
else
|
||||
heading = misc_strdup(c->heading);
|
||||
printf("%s%s=%s", i > 0 ? " " : "", heading, val);
|
||||
free(val);
|
||||
free(heading);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
@@ -342,7 +383,7 @@ static void print_row_pairs(struct cell *cells)
|
||||
exit_code_t table_print(struct column *columns, table_value_cb_t get_value_cb,
|
||||
void *data, struct util_list *items,
|
||||
struct util_list *names, int heading, int pairs,
|
||||
int indent, int wrap)
|
||||
int indent, int wrap, int shell)
|
||||
{
|
||||
struct cell *cells;
|
||||
struct ptrlist_node *p;
|
||||
@@ -372,7 +413,7 @@ exit_code_t table_print(struct column *columns, table_value_cb_t get_value_cb,
|
||||
util_list_iterate(items, p) {
|
||||
cells_get_values(cells, p->ptr, get_value_cb, data);
|
||||
if (pairs)
|
||||
print_row_pairs(cells);
|
||||
print_row_pairs(cells, shell);
|
||||
else
|
||||
print_row(cells, space, indent, wrap);
|
||||
}
|
||||
@@ -434,7 +475,7 @@ void table_print_columns(struct column *columns, struct util_list *names,
|
||||
for (i = 0; columns[i].name; i++)
|
||||
ptrlist_add(items, &columns[i]);
|
||||
table_print(columns_table, columns_table_get_value, NULL, items, names,
|
||||
heading, pairs, 0, 0);
|
||||
heading, pairs, 0, 0, 0);
|
||||
ptrlist_free(items, 0);
|
||||
}
|
||||
|
||||
|
||||
@@ -115,7 +115,7 @@ void print_type(struct devtype *dt, struct subtype *st, bool multiple)
|
||||
|
||||
/* Display table of attributes. */
|
||||
void table_attribs_show(struct util_list *attribs, int headings, int pairs,
|
||||
struct devtype *dt)
|
||||
int shell, struct devtype *dt)
|
||||
{
|
||||
struct util_list *subtypes, *subattribs;
|
||||
struct ptrlist_node *p;
|
||||
@@ -145,7 +145,7 @@ void table_attribs_show(struct util_list *attribs, int headings, int pairs,
|
||||
print_type(dt, st, multiple);
|
||||
|
||||
table_print(table_attribs, table_attribs_get_value, st,
|
||||
subattribs, NULL, headings, pairs, indent, 0);
|
||||
subattribs, NULL, headings, pairs, shell, indent, 0);
|
||||
|
||||
ptrlist_free(subattribs, 0);
|
||||
}
|
||||
|
||||
@@ -83,7 +83,7 @@ exit_code_t table_types_show(struct util_list *columns, int headings, int pairs)
|
||||
|
||||
items = table_types_build();
|
||||
rc = table_print(table_types, table_types_get_value, NULL,
|
||||
items, columns, headings, pairs, 0, 0);
|
||||
items, columns, headings, pairs, 0, 0, 0);
|
||||
ptrlist_free(items, 1);
|
||||
|
||||
return rc;
|
||||
|
||||
@@ -221,6 +221,7 @@ static void write_attr_to_file(FILE *fd, struct device_state *state, const char
|
||||
struct ptrlist_node *p;
|
||||
struct setting *s;
|
||||
struct util_list *list = NULL;
|
||||
struct strlist_node *str;
|
||||
|
||||
/* Apply attributes in correct order. */
|
||||
list = setting_list_get_sorted(state->settings);
|
||||
@@ -229,8 +230,13 @@ static void write_attr_to_file(FILE *fd, struct device_state *state, const char
|
||||
s = p->ptr;
|
||||
if (s->removed)
|
||||
continue;
|
||||
if ((s->attrib && s->attrib->internal) ||
|
||||
internal_by_name(s->name)) {
|
||||
if (s->values) {
|
||||
util_list_iterate(s->values, str) {
|
||||
fprintf(fd, "ATTR{[ccw/%s]%s}=\"%s\"\n",
|
||||
id, s->name, str->str);
|
||||
}
|
||||
} else if ((s->attrib && s->attrib->internal) ||
|
||||
internal_by_name(s->name)) {
|
||||
fprintf(fd, "ENV{zdev_%s}=\"%s\"\n",
|
||||
internal_get_name(s->name), s->value);
|
||||
} else {
|
||||
|
||||
@@ -7,17 +7,18 @@ ALL_CFLAGS += -Wno-address-of-packed-member
|
||||
#
|
||||
ifeq (${HAVE_FUSE},0)
|
||||
|
||||
check_dep_fuse:
|
||||
|
||||
.check_dep_fuse:
|
||||
touch $@
|
||||
else
|
||||
|
||||
check_dep_fuse:
|
||||
.check_dep_fuse:
|
||||
$(call check_dep, \
|
||||
"zgetdump mount support", \
|
||||
"fuse.h", \
|
||||
"fuse3-devel or libfuse3-dev", \
|
||||
"HAVE_FUSE=0", \
|
||||
"-DFUSE_USE_VERSION=30")
|
||||
touch $@
|
||||
endif
|
||||
|
||||
.detect_openssl.dep.c:
|
||||
@@ -30,7 +31,7 @@ endif
|
||||
echo " EVP_MD_CTX_free(ctx);" >> $@
|
||||
echo "}" >> $@
|
||||
|
||||
.check_dep_zgetdump: .detect_openssl.dep.c check_dep_fuse
|
||||
.check_dep_zgetdump: .detect_openssl.dep.c .check_dep_fuse
|
||||
$(call check_dep, \
|
||||
"zgetdump", \
|
||||
"zlib.h", \
|
||||
@@ -131,6 +132,6 @@ install-zgetdump: zgetdump
|
||||
install: $(INSTALL_TARGETS)
|
||||
|
||||
clean:
|
||||
rm -f -- *.o *~ zgetdump core.* .detect_openssl.dep.c .check_dep_zgetdump
|
||||
rm -f -- *.o *~ zgetdump core.* .detect_openssl.dep.c .check_dep_zgetdump .check_dep_fuse
|
||||
|
||||
.PHONY: all install clean check_dep_fuse check_dep_zlib skip-zgetdump install-zgetdump
|
||||
.PHONY: all install clean skip-zgetdump install-zgetdump
|
||||
|
||||
@@ -121,7 +121,8 @@ Elf64_Shdr *read_elf_shdrs(const struct zg_fh *fh, const Elf64_Ehdr *ehdr, unsig
|
||||
return shdrs;
|
||||
}
|
||||
|
||||
unsigned char *read_elf_section_data(const struct zg_fh *fh, const Elf64_Shdr *shdr, size_t *size)
|
||||
unsigned char *read_elf_section_data(const struct zg_fh *fh, const Elf64_Shdr *shdr, size_t *size,
|
||||
const size_t max_size)
|
||||
{
|
||||
const size_t sh_size = shdr->sh_size;
|
||||
unsigned char *ret;
|
||||
@@ -133,6 +134,9 @@ unsigned char *read_elf_section_data(const struct zg_fh *fh, const Elf64_Shdr *s
|
||||
if (shdr->sh_offset > OFF_T_MAX)
|
||||
ERR_EXIT("Unsupported offset");
|
||||
|
||||
if (sh_size > max_size)
|
||||
ERR_EXIT("Unsupported section size: %#lx > %#lx", sh_size, max_size);
|
||||
|
||||
ret = util_malloc(sh_size);
|
||||
zg_seek(fh, (off_t)shdr->sh_offset, ZG_CHECK);
|
||||
zg_read(fh, ret, sh_size, ZG_CHECK);
|
||||
@@ -141,7 +145,8 @@ unsigned char *read_elf_section_data(const struct zg_fh *fh, const Elf64_Shdr *s
|
||||
}
|
||||
|
||||
char *read_elf_shstrtab(const struct zg_fh *fh, const Elf64_Ehdr *ehdr, const Elf64_Shdr *shdrs,
|
||||
const unsigned int shnum, size_t *shstrtab_size)
|
||||
const unsigned int shnum, size_t *shstrtab_size,
|
||||
const size_t max_shstrtab_size)
|
||||
{
|
||||
const size_t shstrndx = ehdr->e_shstrndx;
|
||||
Elf64_Xword tmp_shstrtab_size;
|
||||
@@ -166,6 +171,10 @@ char *read_elf_shstrtab(const struct zg_fh *fh, const Elf64_Ehdr *ehdr, const El
|
||||
ERR_EXIT("Unsupported offset");
|
||||
|
||||
tmp_shstrtab_size = shdrs[shstrndx].sh_size;
|
||||
if (tmp_shstrtab_size > max_shstrtab_size)
|
||||
ERR_EXIT("Unsupported shstrtab size: %#lx > %#lx", tmp_shstrtab_size,
|
||||
max_shstrtab_size);
|
||||
|
||||
shstrtab = util_malloc(tmp_shstrtab_size);
|
||||
zg_seek(fh, (off_t)shstrndx_off, ZG_CHECK);
|
||||
zg_read(fh, shstrtab, tmp_shstrtab_size, ZG_CHECK);
|
||||
|
||||
@@ -195,7 +195,8 @@ Elf64_Shdr *read_elf_shdrs(const struct zg_fh *fh, const Elf64_Ehdr *ehdr,
|
||||
*
|
||||
* To read the section content the offset of @fh is changed.
|
||||
*/
|
||||
unsigned char *read_elf_section_data(const struct zg_fh *fh, const Elf64_Shdr *shdr, size_t *size);
|
||||
unsigned char *read_elf_section_data(const struct zg_fh *fh, const Elf64_Shdr *shdr, size_t *size,
|
||||
const size_t max_size);
|
||||
|
||||
/*
|
||||
* Read ELF section header string table
|
||||
@@ -203,7 +204,8 @@ unsigned char *read_elf_section_data(const struct zg_fh *fh, const Elf64_Shdr *s
|
||||
* To read the section header string table the offset of @fh is changed.
|
||||
*/
|
||||
char *read_elf_shstrtab(const struct zg_fh *fh, const Elf64_Ehdr *ehdr, const Elf64_Shdr *shdrs,
|
||||
const unsigned int shnum, size_t *shstrtab_size);
|
||||
const unsigned int shnum, size_t *shstrtab_size,
|
||||
const size_t max_shstrtab_size);
|
||||
|
||||
/*
|
||||
* Find ELF section header by section name
|
||||
|
||||
@@ -46,17 +46,19 @@ WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(Elf64_Ehdr, free);
|
||||
* read_elf_section_data_as_gbytes:
|
||||
* @fh: (not nullable): open input file
|
||||
* @shdr: (not nullable): section header of the section to read
|
||||
* @max_size: maximum section data size in bytes
|
||||
*
|
||||
* Try to read section data and return it as #GBytes.
|
||||
*
|
||||
* Returns: #GBytes on success, %NULL if an error occurred
|
||||
*/
|
||||
static GBytes *read_elf_section_data_as_gbytes(const struct zg_fh *fh, const Elf64_Shdr *shdr)
|
||||
static GBytes *read_elf_section_data_as_gbytes(const struct zg_fh *fh, const Elf64_Shdr *shdr,
|
||||
const size_t max_size)
|
||||
{
|
||||
unsigned char *data;
|
||||
size_t size;
|
||||
|
||||
data = read_elf_section_data(fh, shdr, &size);
|
||||
data = read_elf_section_data(fh, shdr, &size, max_size);
|
||||
if (!data)
|
||||
return NULL;
|
||||
return g_bytes_new_with_free_func(data, size, free, data);
|
||||
@@ -106,6 +108,12 @@ static dfi_cpu_t *nt_s390_pv_cpu_data_read(const struct zg_fh *fh, const Elf64_N
|
||||
|
||||
g_assert(dump_key);
|
||||
|
||||
if (note_descsz > PV_MAX_NT_S390_PV_CPU_DATA_SIZE) {
|
||||
g_set_error(error, ZDUMP_PV_UTILS_ERROR, ZDUMP_ERR_CORRUPTED_NOTE,
|
||||
_("Unable to read confidential CPU data. Dump probably corrupted."));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
note_data = g_malloc(note_descsz);
|
||||
if (nt_read(fh, note_hdr, note_data, note_descsz) < 0) {
|
||||
g_set_error(error, ZDUMP_PV_UTILS_ERROR, ZDUMP_ERR_CORRUPTED_NOTE,
|
||||
@@ -164,7 +172,7 @@ static int pt_notes_add(const struct zg_fh *fh, const Elf64_Phdr *phdr, const un
|
||||
dfi_cpu_add(g_steal_pointer(&cpu_current));
|
||||
break;
|
||||
default:
|
||||
util_log_print(UTIL_LOG_WARN, _("Unknown ELF-Note %#x"), note.n_type);
|
||||
util_log_print(UTIL_LOG_WARN, _("Unknown ELF-Note %#x\n"), note.n_type);
|
||||
__attribute__((fallthrough));
|
||||
case NT_PRSTATUS:
|
||||
case NT_FPREGSET:
|
||||
@@ -224,7 +232,7 @@ static int dfi_pv_elf_init(void)
|
||||
if (!shdrs)
|
||||
return -ENODEV;
|
||||
|
||||
shstrtab = read_elf_shstrtab(fh, ehdr, shdrs, shnum, &shstrtab_size);
|
||||
shstrtab = read_elf_shstrtab(fh, ehdr, shdrs, shnum, &shstrtab_size, PV_MAX_SHSTRTAB_SIZE);
|
||||
if (!shstrtab)
|
||||
return -ENODEV;
|
||||
|
||||
@@ -255,7 +263,8 @@ static int dfi_pv_elf_init(void)
|
||||
return -EINVAL;
|
||||
|
||||
/* Read the PV completion configuration section data */
|
||||
completion_sdata = read_elf_section_data_as_gbytes(fh, completion_shdr);
|
||||
completion_sdata =
|
||||
read_elf_section_data_as_gbytes(fh, completion_shdr, PV_MAX_COMPL_DATA_SIZE);
|
||||
if (!completion_sdata)
|
||||
return -EINVAL;
|
||||
|
||||
@@ -263,9 +272,9 @@ static int dfi_pv_elf_init(void)
|
||||
* completion configuration data and store it in `@cpl_conf_decr`. In addition, mmap the
|
||||
* configuration storage state area and use the `tweak_nonce`.
|
||||
*/
|
||||
if (pv_process_section_data(fh->fh, completion_sdata, storage_state_shdr->sh_offset,
|
||||
storage_state_shdr->sh_size, key, &cpl_conf_decr, &dump_key,
|
||||
&storage_state_data, &error) < 0) {
|
||||
if (pv_process_section_data(fh->fh, fh->sb.st_size, completion_sdata,
|
||||
storage_state_shdr->sh_offset, storage_state_shdr->sh_size, key,
|
||||
&cpl_conf_decr, &dump_key, &storage_state_data, &error) < 0) {
|
||||
ERR(_("Unable to read decryption information:" ERR_NEWLINE "%s."), error->message);
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -313,7 +322,8 @@ static int dfi_pv_elf_init(void)
|
||||
}
|
||||
break;
|
||||
default:
|
||||
util_log_print(UTIL_LOG_WARN, _("Unknown ELF-PHDR type %#x"), phdr->p_type);
|
||||
util_log_print(UTIL_LOG_WARN, _("Unknown ELF-PHDR type %#x\n"),
|
||||
phdr->p_type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -271,7 +271,7 @@ int ngdump_get_dump_part(struct zg_fh *zg_fh)
|
||||
__func__, comp_entry.type,
|
||||
comp_entry.compdat.load_address);
|
||||
/* Is this a kernel image ? */
|
||||
if (comp_entry.type == COMPONENT_LOAD &&
|
||||
if (comp_entry.type == COMPONENT_TYPE_LOAD &&
|
||||
comp_entry.compdat.load_address == IMAGE_ENTRY)
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -20,6 +20,16 @@
|
||||
#define PV_ELF_SECTION_NAME_COMPL "pv_compl"
|
||||
#define PV_ELF_SECTION_NAME_TWEAKS "pv_mem_meta"
|
||||
|
||||
/* Maximum size (in bytes) of completion section data */
|
||||
#define PV_MAX_COMPL_DATA_SIZE ROUNDUP(sizeof(pv_dump_completion_data_v1_t), PAGE_SIZE)
|
||||
/* Maximum size (in bytes) of section header string table */
|
||||
#define PV_MAX_SHSTRTAB_SIZE \
|
||||
ROUNDUP(sizeof(PV_ELF_SECTION_NAME_COMPL) + sizeof(PV_ELF_SECTION_NAME_TWEAKS) + \
|
||||
sizeof(".shstrtab"), \
|
||||
PAGE_SIZE)
|
||||
/* Maximum size of NT_S390_PV_CPU_DATA */
|
||||
#define PV_MAX_NT_S390_PV_CPU_DATA_SIZE ROUNDUP(sizeof(pv_cpu_dump_v1_t), PAGE_SIZE)
|
||||
|
||||
#define PV_COMPL_DATA_VERSION_1 ((uint32_t)1)
|
||||
#define PV_SEC_CPU_DATA_VERSION_1 ((uint32_t)1)
|
||||
|
||||
|
||||
@@ -239,7 +239,7 @@ dfi_cpu_t *pv_decrypt_cpu_note_data(const unsigned int expected_version, GBytes
|
||||
/* Check dump flags */
|
||||
if (pv_cpu->has_osii)
|
||||
util_log_print(UTIL_LOG_WARN,
|
||||
_("CPU state may contain partial instruction results"));
|
||||
_("CPU state may contain partial instruction results\n"));
|
||||
|
||||
return pv_dfi_cpu_from_pv_cpu(pv_cpu);
|
||||
}
|
||||
@@ -608,14 +608,26 @@ ssize_t pv_process_pglist(pv_crypto_ctx_t *ctx, BIO *output,
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
g_assert(!(page_state & ~PV_ZERO_PAGE));
|
||||
if (page_state & ~PV_ZERO_PAGE) {
|
||||
g_set_error(error, ZDUMP_PV_UTILS_ERROR,
|
||||
ZDUMP_ERR_PGLIST_INVAL_STATE,
|
||||
_("Invalid page state. page-idx: %#lx, state: %#lx"),
|
||||
page_idx, page_state);
|
||||
return -1;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (page_state & PV_SHARED_PAGE) {
|
||||
/* shared pages are not encrypted */
|
||||
input = ctx->input;
|
||||
g_assert(!(page_state & ~PV_SHARED_PAGE));
|
||||
if (page_state & ~PV_SHARED_PAGE) {
|
||||
g_set_error(error, ZDUMP_PV_UTILS_ERROR,
|
||||
ZDUMP_ERR_PGLIST_INVAL_STATE,
|
||||
_("Invalid page state. page-idx: %#lx, state: %#lx"),
|
||||
page_idx, page_state);
|
||||
return -1;
|
||||
}
|
||||
} else if (page_state & PV_ENCRYPTED_PAGE) {
|
||||
input = ctx->filter;
|
||||
calculate_tweak(tweak_comp, ctx->nonce, &ctx->tweak_scratch);
|
||||
@@ -624,7 +636,13 @@ ssize_t pv_process_pglist(pv_crypto_ctx_t *ctx, BIO *output,
|
||||
if (update_tweak(ctx, error) < 0)
|
||||
return -1;
|
||||
|
||||
g_assert(!(page_state & ~PV_ENCRYPTED_PAGE));
|
||||
if (page_state & ~PV_ENCRYPTED_PAGE) {
|
||||
g_set_error(error, ZDUMP_PV_UTILS_ERROR,
|
||||
ZDUMP_ERR_PGLIST_INVAL_STATE,
|
||||
_("Invalid page state. page-idx: %#lx, state: %#lx"),
|
||||
page_idx, page_state);
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
g_set_error(error, ZDUMP_PV_UTILS_ERROR, ZDUMP_ERR_PGLIST_INVAL_STATE,
|
||||
_("Invalid page state. page-idx: %#lx, state: %#lx"), page_idx,
|
||||
@@ -659,10 +677,10 @@ struct _storage_state_mmap {
|
||||
gatomicrefcount ref_count;
|
||||
};
|
||||
|
||||
storage_state_mmap_t *storage_state_mmap_new(const int fd, const u64 offset, const u64 size,
|
||||
GError **error)
|
||||
storage_state_mmap_t *storage_state_mmap_new(const int fd, const size_t file_size, const u64 offset,
|
||||
const u64 size, GError **error)
|
||||
{
|
||||
size_t tweak_components_cnt, start_addr, in_page_offset, mmapped_size;
|
||||
size_t tweak_components_cnt, start_addr, min_size, in_page_offset, mmapped_size;
|
||||
g_autoptr(storage_state_mmap_t) ret = NULL;
|
||||
int saved_errno = 0;
|
||||
u8 *ptr;
|
||||
@@ -688,6 +706,19 @@ storage_state_mmap_t *storage_state_mmap_new(const int fd, const u64 offset, con
|
||||
start_addr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (G_UNLIKELY(!g_uint64_checked_add(&min_size, start_addr, mmapped_size))) {
|
||||
g_set_error(error, ZDUMP_PV_UTILS_ERROR, ZDUMP_ERR_PAGE_END_ADDR_OVERFLOW,
|
||||
_("UInt overflow detected: %s: start_addr %#lx mmap_size %#lx"),
|
||||
__func__, start_addr, mmapped_size);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (file_size < min_size) {
|
||||
g_set_error(error, ZDUMP_PV_UTILS_ERROR, ZDUMP_ERR_MMAP,
|
||||
_("mmap failed: file too small"));
|
||||
return NULL;
|
||||
}
|
||||
ptr = mmap(NULL, mmapped_size, PROT_READ, MAP_POPULATE | MAP_PRIVATE, fd,
|
||||
(ssize_t)start_addr);
|
||||
saved_errno = errno;
|
||||
@@ -722,7 +753,7 @@ void storage_state_mmap_unref(storage_state_mmap_t *storage_state)
|
||||
if (storage_state->first_page_ptr) {
|
||||
int rc = munmap(storage_state->first_page_ptr, storage_state->mapped_size);
|
||||
if (rc != 0)
|
||||
util_log_print(UTIL_LOG_WARN, _("munmap has failed"));
|
||||
util_log_print(UTIL_LOG_WARN, _("munmap has failed\n"));
|
||||
}
|
||||
g_free(storage_state);
|
||||
}
|
||||
@@ -796,9 +827,9 @@ static long completion_data_get_version(GBytes *cpl_data, GError **error)
|
||||
return *version;
|
||||
}
|
||||
|
||||
int pv_process_section_data(const int fd, GBytes *completion_sec, const u64 storage_state_offset,
|
||||
const size_t storage_state_size, GBytes *cck,
|
||||
pv_dump_completion_t **completion_decr, GBytes **dump_key,
|
||||
int pv_process_section_data(const int fd, const size_t file_size, GBytes *completion_sec,
|
||||
const u64 storage_state_offset, const size_t storage_state_size,
|
||||
GBytes *cck, pv_dump_completion_t **completion_decr, GBytes **dump_key,
|
||||
storage_state_mmap_t **storage_state, GError **error)
|
||||
{
|
||||
g_autoptr(pv_dump_completion_t) _completion_decr = NULL;
|
||||
@@ -852,8 +883,8 @@ int pv_process_section_data(const int fd, GBytes *completion_sec, const u64 stor
|
||||
return -1;
|
||||
}
|
||||
|
||||
_storage_state_data =
|
||||
storage_state_mmap_new(fd, storage_state_offset, storage_state_size, error);
|
||||
_storage_state_data = storage_state_mmap_new(fd, file_size, storage_state_offset,
|
||||
storage_state_size, error);
|
||||
if (!_storage_state_data)
|
||||
return -1;
|
||||
|
||||
|
||||
@@ -258,9 +258,9 @@ bool pv_is_pv_elf(const Elf64_Shdr *shdrs, const unsigned int shnum, const char
|
||||
*
|
||||
* Returns: 0 in case of success, -1 otherwise.
|
||||
*/
|
||||
int pv_process_section_data(const int fd, GBytes *completion_sec, const u64 storage_state_offset,
|
||||
const size_t storage_state_size, GBytes *cck,
|
||||
pv_dump_completion_t **completion_decr, GBytes **dump_key,
|
||||
int pv_process_section_data(const int fd, const size_t file_size, GBytes *completion_sec,
|
||||
const u64 storage_state_offset, const size_t storage_state_size,
|
||||
GBytes *cck, pv_dump_completion_t **completion_decr, GBytes **dump_key,
|
||||
storage_state_mmap_t **storage_state_data, GError **error);
|
||||
|
||||
/**
|
||||
@@ -283,14 +283,15 @@ int pv_elf_read(const pv_elf_ctx_t *elf_ctx, const u64 start_addr, void *dst, co
|
||||
/**
|
||||
* storage_state_mmap_new:
|
||||
* @fd: file descriptor for which to create the mapping
|
||||
* @file_size: file size in bytes
|
||||
* @offset: offset in fd to pv_mem_meta section
|
||||
* @size: size of mapping (and pv_mem_meta section)
|
||||
* @error: return value for GError
|
||||
*
|
||||
* Returns: new storage_state_mmap context
|
||||
*/
|
||||
storage_state_mmap_t *storage_state_mmap_new(const int fd, const u64 offset, const u64 size,
|
||||
GError **error);
|
||||
storage_state_mmap_t *storage_state_mmap_new(const int fd, const size_t file_size, const u64 offset,
|
||||
const u64 size, GError **error);
|
||||
|
||||
/**
|
||||
* storage_state_ref:
|
||||
|
||||
@@ -43,17 +43,17 @@ ziorep_utilization: ziorep_utilization.o ziorep_framer.o ziorep_frameset.o \
|
||||
install: all
|
||||
$(SED) -e 's/%S390_TOOLS_VERSION%/$(S390_TOOLS_RELEASE)/' \
|
||||
< ziomon > $(DESTDIR)$(USRSBINDIR)/ziomon;
|
||||
chown $(OWNER).$(GROUP) $(DESTDIR)$(USRSBINDIR)/ziomon;
|
||||
chown $(OWNER):$(GROUP) $(DESTDIR)$(USRSBINDIR)/ziomon;
|
||||
chmod 755 $(DESTDIR)$(USRSBINDIR)/ziomon;
|
||||
$(SED) -e \
|
||||
's/%S390_TOOLS_VERSION%/$(S390_TOOLS_RELEASE)/' \
|
||||
< ziomon_fcpconf > $(DESTDIR)$(USRSBINDIR)/ziomon_fcpconf;
|
||||
chown $(OWNER).$(GROUP) $(DESTDIR)$(USRSBINDIR)/ziomon_fcpconf;
|
||||
chown $(OWNER):$(GROUP) $(DESTDIR)$(USRSBINDIR)/ziomon_fcpconf;
|
||||
chmod 755 $(DESTDIR)$(USRSBINDIR)/ziomon_fcpconf;
|
||||
$(SED) -e \
|
||||
's/%S390_TOOLS_VERSION%/$(S390_TOOLS_RELEASE)/' \
|
||||
< ziorep_config > $(DESTDIR)$(USRSBINDIR)/ziorep_config;
|
||||
chown $(OWNER).$(GROUP) $(DESTDIR)$(USRSBINDIR)/ziorep_config;
|
||||
chown $(OWNER):$(GROUP) $(DESTDIR)$(USRSBINDIR)/ziorep_config;
|
||||
chmod 755 $(DESTDIR)$(USRSBINDIR)/ziorep_config;
|
||||
$(INSTALL) -g $(GROUP) -o $(OWNER) -m 644 ziomon.8 \
|
||||
$(DESTDIR)$(MANDIR)/man8
|
||||
|
||||
@@ -15,14 +15,16 @@
|
||||
|
||||
int extract_length(void *data)
|
||||
{
|
||||
struct eckd_blockptr *blockptr = (struct eckd_blockptr *)data;
|
||||
struct eckd_blockptr_legacy *blockptr =
|
||||
(struct eckd_blockptr_legacy *)data;
|
||||
|
||||
return blockptr->size * (blockptr->blockct + 1);
|
||||
}
|
||||
|
||||
int is_zero_block(void *data)
|
||||
{
|
||||
struct eckd_blockptr *blockptr = (struct eckd_blockptr *)data;
|
||||
struct eckd_blockptr_legacy *blockptr =
|
||||
(struct eckd_blockptr_legacy *)data;
|
||||
|
||||
return blockptr->cyl || blockptr->head || blockptr->sec;
|
||||
}
|
||||
@@ -30,7 +32,7 @@ int is_zero_block(void *data)
|
||||
void * load_direct(disk_blockptr_t *data, struct subchannel_id subchannel_id,
|
||||
void *load_addr)
|
||||
{
|
||||
struct eckd_blockptr *blockptr = &data->eckd;
|
||||
struct eckd_blockptr_legacy *blockptr = &data->eckd;
|
||||
struct ccw1 *ccws;
|
||||
unsigned long record_size;
|
||||
struct seek_arg seek_addr;
|
||||
|
||||
@@ -120,9 +120,9 @@ void __noreturn start(void)
|
||||
/* skip header */
|
||||
entry = (struct component_entry *)
|
||||
(load_address + sizeof(struct component_header));
|
||||
while (entry->type == COMPONENT_LOAD ||
|
||||
entry->type == COMPONENT_SIGNATURE) {
|
||||
if (entry->type == COMPONENT_SIGNATURE) {
|
||||
while (entry->type == COMPONENT_TYPE_LOAD ||
|
||||
entry->type == COMPONENT_TYPE_SIGNATURE) {
|
||||
if (entry->type == COMPONENT_TYPE_SIGNATURE) {
|
||||
/* Skip unhandled signature components */
|
||||
entry++;
|
||||
continue;
|
||||
@@ -132,7 +132,7 @@ void __noreturn start(void)
|
||||
load_blocklist(entry, subchannel_id, load_address);
|
||||
entry++;
|
||||
}
|
||||
if (entry->type != COMPONENT_EXECUTE)
|
||||
if (entry->type != COMPONENT_TYPE_EXECUTE)
|
||||
panic(EWRONGTYPE, "");
|
||||
|
||||
load_psw = entry->compdat.load_psw;
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
#include "error.h"
|
||||
|
||||
typedef union {
|
||||
struct eckd_blockptr eckd;
|
||||
struct eckd_blockptr_legacy eckd;
|
||||
struct linear_blockptr linear;
|
||||
} disk_blockptr_t;
|
||||
|
||||
|
||||
@@ -158,8 +158,8 @@ struct mvdump_parm_table {
|
||||
|
||||
void boot_get_dump_info(struct boot_info *boot_info, uint8_t dev_type,
|
||||
void *param);
|
||||
void boot_get_ipl_info(struct boot_info *boot_info, uint8_t dev_type,
|
||||
disk_blockptr_t *bm_ptr, struct disk_info *info);
|
||||
void boot_get_ipl_info_ccw(struct boot_info *boot_info, uint8_t dev_type,
|
||||
disk_blockptr_t *bm_ptr, struct disk_info *info);
|
||||
|
||||
int boot_check_data(void);
|
||||
int boot_init_fba_stage0(struct boot_fba_stage0* stage0,
|
||||
@@ -187,6 +187,8 @@ int boot_get_tape_ipl(void** data, size_t* size, address_t parm_addr,
|
||||
address_t initrd_addr, address_t image_addr);
|
||||
int boot_get_tape_dump(void** data, size_t* size, uint64_t mem);
|
||||
int boot_get_eckd_dump_stage2(void** data, size_t* size, uint64_t mem);
|
||||
int boot_get_eckd_ld_ipl_br(void **br_ptr, size_t *size_ptr,
|
||||
disk_blockptr_t *table, struct disk_info *info);
|
||||
int boot_get_eckd_mvdump_stage2(void** data, size_t* size, uint64_t mem,
|
||||
uint8_t force, struct mvdump_parm_table);
|
||||
int boot_get_fba_dump_stage2(void** data, size_t* size, uint64_t mem);
|
||||
|
||||
@@ -51,11 +51,7 @@ struct file_signature {
|
||||
int bootmap_header_init(int fd);
|
||||
int bootmap_header_read(int fd, struct bootmap_header *bh);
|
||||
int bootmap_header_write(int fd, struct bootmap_header *bh);
|
||||
int bootmap_create(struct job_data* job, disk_blockptr_t* program_table,
|
||||
disk_blockptr_t *scsi_dump_sb_blockptr,
|
||||
disk_blockptr_t** stage2_list, blocknum_t* stage2_count,
|
||||
char** device, struct disk_info** new_info);
|
||||
void bootmap_store_blockptr(void* buffer, disk_blockptr_t* ptr,
|
||||
struct disk_info* info);
|
||||
void bootmap_store_blockptr(void *buffer, disk_blockptr_t *ptr,
|
||||
struct disk_info *info, int fid);
|
||||
|
||||
#endif /* if not BOOTMAP_H */
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "zipl.h"
|
||||
#include "lib/vtoc.h"
|
||||
|
||||
|
||||
/* Type for representing disk block numbers */
|
||||
@@ -23,7 +24,7 @@ typedef uint64_t blocknum_t;
|
||||
|
||||
/* Pointer to block on a disk with cyl/head/sec layout */
|
||||
struct disk_blockptr_chs {
|
||||
int cyl;
|
||||
unsigned int cyl;
|
||||
int head;
|
||||
int sec;
|
||||
int size;
|
||||
@@ -52,14 +53,6 @@ typedef enum {
|
||||
disk_type_eckd_cdl,
|
||||
} disk_type_t;
|
||||
|
||||
/* from linux/hdregs.h */
|
||||
struct hd_geometry {
|
||||
unsigned char heads;
|
||||
unsigned char sectors;
|
||||
unsigned short cylinders;
|
||||
unsigned long start;
|
||||
};
|
||||
|
||||
/* Disk information source */
|
||||
typedef enum {
|
||||
source_auto,
|
||||
@@ -108,6 +101,7 @@ int disk_get_info_from_file(const char* filename,
|
||||
struct disk_info** info);
|
||||
void disk_free_info(struct disk_info* info);
|
||||
char* disk_get_type_name(disk_type_t type);
|
||||
char *disk_get_ipl_type(disk_type_t type);
|
||||
int disk_is_large_volume(struct disk_info* info);
|
||||
int disk_cyl_from_blocknum(blocknum_t blocknum, struct disk_info* info);
|
||||
int disk_head_from_blocknum(blocknum_t blocknum, struct disk_info* info);
|
||||
|
||||
@@ -15,12 +15,90 @@
|
||||
#include "disk.h"
|
||||
#include "job.h"
|
||||
#include "zipl.h"
|
||||
#include "boot/boot_defs.h"
|
||||
|
||||
/*
|
||||
* For compatibility reasons zIPL can build multiple "similar"
|
||||
* program tables, which differ only in block pointers format
|
||||
*/
|
||||
enum program_table_id {
|
||||
PROGRAM_TABLE_0,
|
||||
PROGRAM_TABLE_1,
|
||||
NR_PROGRAM_TABLES
|
||||
};
|
||||
|
||||
int install_bootloader(const char* device, disk_blockptr_t* program_table,
|
||||
disk_blockptr_t* scsi_dump_sb_blockptr,
|
||||
disk_blockptr_t* stage2_data, blocknum_t stage2_count,
|
||||
struct disk_info* info, struct job_data* job);
|
||||
enum program_component_id {
|
||||
COMPONENT_ID_HEAP_AREA,
|
||||
COMPONENT_ID_STACK_AREA,
|
||||
COMPONENT_ID_LOADER_SIGNATURE,
|
||||
COMPONENT_ID_LOADER,
|
||||
COMPONENT_ID_PARAMETERS,
|
||||
COMPONENT_ID_IMAGE_SIGNATURE,
|
||||
COMPONENT_ID_KERNEL_IMAGE,
|
||||
COMPONENT_ID_PARMLINE,
|
||||
COMPONENT_ID_RAMDISK_SIGNATURE,
|
||||
COMPONENT_ID_RAMDISK,
|
||||
COMPONENT_ID_ENVBLK,
|
||||
COMPONENT_ID_SEGMENT_FILE,
|
||||
NR_PROGRAM_COMPONENTS
|
||||
};
|
||||
|
||||
struct component_loc {
|
||||
address_t addr;
|
||||
size_t size;
|
||||
};
|
||||
|
||||
struct component_footer {
|
||||
component_type type;
|
||||
const char *desc;
|
||||
};
|
||||
|
||||
struct program_component {
|
||||
struct component_loc loc;
|
||||
disk_blockptr_t *list;
|
||||
blocknum_t count;
|
||||
};
|
||||
|
||||
struct program_table {
|
||||
disk_blockptr_t table;
|
||||
disk_blockptr_t *stage1b_list;
|
||||
blocknum_t stage1b_count;
|
||||
};
|
||||
|
||||
/* Bootloader Installation Set */
|
||||
struct install_set {
|
||||
struct program_table tables[NR_PROGRAM_TABLES];
|
||||
struct program_component *components[NR_PROGRAM_COMPONENTS];
|
||||
int nr_tables; /* number of "similar" program tables to be installed */
|
||||
int nr_menu_entries;
|
||||
int fd;
|
||||
char *device;
|
||||
char *filename;
|
||||
struct disk_info *info;
|
||||
disk_blockptr_t scsi_dump_sb_blockptr;
|
||||
};
|
||||
|
||||
extern struct component_footer component_footers[NR_PROGRAM_COMPONENTS];
|
||||
|
||||
static inline component_type component_type_by_id(enum program_component_id id)
|
||||
{
|
||||
return component_footers[id].type;
|
||||
}
|
||||
|
||||
static inline const char *component_desc_by_id(enum program_component_id id)
|
||||
{
|
||||
return component_footers[id].desc;
|
||||
}
|
||||
|
||||
static inline struct program_component *get_component(struct install_set *bis,
|
||||
int i, int j)
|
||||
{
|
||||
return bis->components[i] + j;
|
||||
}
|
||||
|
||||
int prepare_bootloader(struct job_data *job, struct install_set *bis);
|
||||
int install_bootloader(struct job_data *job, struct install_set *bis);
|
||||
void free_bootloader(struct install_set *bis);
|
||||
int install_tapeloader(const char* device, const char* image,
|
||||
const char* parmline, const char* ramdisk,
|
||||
address_t image_addr, address_t parm_addr,
|
||||
|
||||
@@ -7,7 +7,8 @@ ALL_CPPFLAGS += -I../include -I../boot \
|
||||
-D_FILE_OFFSET_BITS=64 $(NO_PIE_CFLAGS)
|
||||
ALL_LDFLAGS += -Wl,-z,noexecstack $(NO_PIE_LDFLAGS)
|
||||
|
||||
libs = $(rootdir)/libutil/libutil.a
|
||||
libs = $(rootdir)/libutil/libutil.a \
|
||||
$(rootdir)/libvtoc/libvtoc.a \
|
||||
|
||||
objects = misc.o error.o scan.o job.o boot.o bootmap.o fs-map.o disk.o \
|
||||
bootmap_header.o envblk.o install.o zipl.o $(rootdir)/zipl/boot/data.o
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
#include "lib/util_libc.h"
|
||||
|
||||
#include "stage3.h"
|
||||
|
||||
@@ -560,9 +561,12 @@ boot_get_dump_info(struct boot_info *boot_info, uint8_t dev_type, void *param)
|
||||
sizeof(boot_info->bp.dump.param));
|
||||
}
|
||||
|
||||
/*
|
||||
* Helper function to install a boot record for CCW-type IPL from DASD
|
||||
*/
|
||||
void
|
||||
boot_get_ipl_info(struct boot_info *boot_info, uint8_t dev_type,
|
||||
disk_blockptr_t *bm_ptr, struct disk_info *info)
|
||||
boot_get_ipl_info_ccw(struct boot_info *boot_info, uint8_t dev_type,
|
||||
disk_blockptr_t *bm_ptr, struct disk_info *info)
|
||||
{
|
||||
memset(boot_info, 0, sizeof(*boot_info));
|
||||
memcpy(&boot_info->magic, BOOT_INFO_MAGIC, sizeof(boot_info->magic));
|
||||
@@ -570,6 +574,30 @@ boot_get_ipl_info(struct boot_info *boot_info, uint8_t dev_type,
|
||||
boot_info->dev_type = dev_type;
|
||||
boot_info->bp_type = BOOT_INFO_BP_TYPE_IPL;
|
||||
boot_info->version = BOOT_INFO_VERSION;
|
||||
bootmap_store_blockptr(&boot_info->bp, bm_ptr, info);
|
||||
bootmap_store_blockptr(&boot_info->bp, bm_ptr, info,
|
||||
LEGACY_BLKPTR_FORMAT_ID);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocate and initialize a boot record for List-Directed IPL from DASD
|
||||
*
|
||||
* TABLE: address of an actual program table
|
||||
*/
|
||||
int boot_get_eckd_ld_ipl_br(void **br_ptr, size_t *size_ptr,
|
||||
disk_blockptr_t *table, struct disk_info *info)
|
||||
{
|
||||
struct eckd_boot_record *br;
|
||||
|
||||
br = util_zalloc(info->phy_block_size);
|
||||
if (!br)
|
||||
return -1;
|
||||
|
||||
memcpy(&br->magic, ZIPL_MAGIC, ZIPL_MAGIC_SIZE);
|
||||
br->version_id = DISK_LAYOUT_ID;
|
||||
bootmap_store_blockptr(&br->program_table_pointer, table, info,
|
||||
BLKPTR_FORMAT_ID);
|
||||
br->os_id = 0x55aa; /* LINUX */
|
||||
*br_ptr = br;
|
||||
*size_ptr = info->phy_block_size;
|
||||
return 0;
|
||||
}
|
||||
|
||||
1274
zipl/src/bootmap.c
1274
zipl/src/bootmap.c
File diff suppressed because it is too large
Load Diff
@@ -28,6 +28,7 @@
|
||||
|
||||
#include "lib/util_proc.h"
|
||||
#include "lib/util_sys.h"
|
||||
#include "lib/util_libc.h"
|
||||
#include "disk.h"
|
||||
#include "error.h"
|
||||
#include "install.h"
|
||||
@@ -755,7 +756,6 @@ disk_write_block_buffer_align(int fd, int fd_is_basedisk, const void *buffer,
|
||||
size_t bytecount, disk_blockptr_t **blocklist,
|
||||
struct disk_info *info, int align, off_t *offset)
|
||||
{
|
||||
disk_blockptr_t* list;
|
||||
blocknum_t count;
|
||||
blocknum_t i;
|
||||
size_t written;
|
||||
@@ -764,13 +764,12 @@ disk_write_block_buffer_align(int fd, int fd_is_basedisk, const void *buffer,
|
||||
int rc;
|
||||
|
||||
count = (bytecount + info->phy_block_size - 1) / info->phy_block_size;
|
||||
list = (disk_blockptr_t *) misc_malloc(sizeof(disk_blockptr_t) *
|
||||
count);
|
||||
if (list == NULL) {
|
||||
*blocklist = (disk_blockptr_t *)util_zalloc(sizeof(disk_blockptr_t) *
|
||||
count);
|
||||
if (*blocklist == NULL) {
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
memset((void *) list, 0, sizeof(disk_blockptr_t) * count);
|
||||
/* Build list */
|
||||
for (i=0, written=0; i < count; i++, written += chunk_size) {
|
||||
chunk_size = bytecount - written;
|
||||
@@ -778,17 +777,15 @@ disk_write_block_buffer_align(int fd, int fd_is_basedisk, const void *buffer,
|
||||
chunk_size = info->phy_block_size;
|
||||
rc = disk_write_block_aligned_base(fd, fd_is_basedisk,
|
||||
VOID_ADD(buffer, written),
|
||||
chunk_size, &list[i], info,
|
||||
chunk_size, &(*blocklist)[i],
|
||||
info,
|
||||
i == 0 ? align : info->phy_block_size,
|
||||
&pos);
|
||||
if (rc) {
|
||||
free(list);
|
||||
if (rc)
|
||||
return 0;
|
||||
}
|
||||
if (offset != NULL && i == 0)
|
||||
*offset = pos;
|
||||
}
|
||||
*blocklist = list;
|
||||
return count;
|
||||
}
|
||||
|
||||
@@ -830,6 +827,21 @@ disk_get_type_name(disk_type_t type)
|
||||
}
|
||||
}
|
||||
|
||||
/* Return IPL types supported for a given disk TYPE */
|
||||
char *disk_get_ipl_type(disk_type_t type)
|
||||
{
|
||||
switch (type) {
|
||||
case disk_type_scsi:
|
||||
return "LD-";
|
||||
case disk_type_fba:
|
||||
case disk_type_eckd_ldl:
|
||||
return "CCW-";
|
||||
case disk_type_eckd_cdl:
|
||||
return "CCW- and LD-";
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
/* Return non-zero for ECKD large volumes. */
|
||||
int
|
||||
@@ -1050,7 +1062,6 @@ disk_get_blocklist_from_file(const char *filename, struct file_range *reg,
|
||||
disk_blockptr_t **blocklist,
|
||||
struct disk_info* info)
|
||||
{
|
||||
disk_blockptr_t* list;
|
||||
struct stat stats;
|
||||
int fd;
|
||||
off_t off;
|
||||
@@ -1094,24 +1105,21 @@ disk_get_blocklist_from_file(const char *filename, struct file_range *reg,
|
||||
blk_count = ((blocknum_t) count +
|
||||
info->phy_block_size - 1) / info->phy_block_size;
|
||||
|
||||
list = (disk_blockptr_t *) misc_malloc(sizeof(disk_blockptr_t) *
|
||||
blk_count);
|
||||
if (list == NULL) {
|
||||
*blocklist = (disk_blockptr_t *)util_zalloc(sizeof(disk_blockptr_t) *
|
||||
blk_count);
|
||||
if (*blocklist == NULL) {
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
memset((void *) list, 0, sizeof(disk_blockptr_t) * blk_count);
|
||||
/* Build list */
|
||||
for (i = 0; i < blk_count; i++) {
|
||||
if (disk_get_blocknum(fd, 0, blk_off + i, &blocknum, info)) {
|
||||
free(list);
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
disk_blockptr_from_blocknum(&list[i], blocknum, info);
|
||||
disk_blockptr_from_blocknum(&(*blocklist)[i], blocknum, info);
|
||||
}
|
||||
close(fd);
|
||||
*blocklist = list;
|
||||
return blk_count;
|
||||
}
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
|
||||
#include "lib/zt_common.h"
|
||||
#include "lib/util_sys.h"
|
||||
#include "lib/vtoc.h"
|
||||
|
||||
#include "boot.h"
|
||||
#include "bootmap.h"
|
||||
@@ -109,7 +110,8 @@ update_scsi_mbr(void* bootblock, disk_blockptr_t* table,
|
||||
memset(buffer, 0, sizeof(struct scsi_mbr));
|
||||
memcpy(&mbr->magic, ZIPL_MAGIC, ZIPL_MAGIC_SIZE);
|
||||
mbr->version_id = DISK_LAYOUT_ID;
|
||||
bootmap_store_blockptr(&mbr->program_table_pointer, table, info);
|
||||
bootmap_store_blockptr(&mbr->program_table_pointer, table, info,
|
||||
0 /* this argument is ignored for scsi */);
|
||||
if (scsi_dump_sb_blockptr->linear.block != 0) {
|
||||
/* Write dump boot_info */
|
||||
param.block = scsi_dump_sb_blockptr->linear.block *
|
||||
@@ -168,11 +170,11 @@ install_scsi(int fd, disk_blockptr_t* program_table, struct disk_info* info,
|
||||
}
|
||||
|
||||
|
||||
/* Install bootloader for initial program load from an FBA type disk. */
|
||||
/* Install bootloader for CCW-type IPL from a FBA type disk */
|
||||
static int
|
||||
install_fba(int fd, disk_blockptr_t *program_table,
|
||||
disk_blockptr_t *stage1b_list, blocknum_t stage1b_count,
|
||||
struct disk_info *info)
|
||||
install_fba_ccw(int fd, disk_blockptr_t *program_table,
|
||||
disk_blockptr_t *stage1b_list, blocknum_t stage1b_count,
|
||||
struct disk_info *info)
|
||||
{
|
||||
struct boot_fba_stage0 stage0;
|
||||
|
||||
@@ -180,8 +182,8 @@ install_fba(int fd, disk_blockptr_t *program_table,
|
||||
if (boot_init_fba_stage0(&stage0, stage1b_list, stage1b_count))
|
||||
return -1;
|
||||
|
||||
boot_get_ipl_info(&stage0.boot_info, BOOT_INFO_DEV_TYPE_FBA,
|
||||
program_table, info);
|
||||
boot_get_ipl_info_ccw(&stage0.boot_info, BOOT_INFO_DEV_TYPE_FBA,
|
||||
program_table, info);
|
||||
|
||||
if (DRY_RUN_FUNC(misc_pwrite(fd, &stage0, sizeof(stage0), 0)))
|
||||
return -1;
|
||||
@@ -218,12 +220,14 @@ out:
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Install bootloader for initial program load from an ECKD type disk with
|
||||
* Linux Disk Layout. */
|
||||
/*
|
||||
* Install bootloader for CCW-type IPL from ECKD type disk with
|
||||
* Linux Disk Layout
|
||||
*/
|
||||
static int
|
||||
install_eckd_ldl(int fd, disk_blockptr_t *program_table,
|
||||
disk_blockptr_t *stage1b_list, blocknum_t stage1b_count,
|
||||
struct disk_info *info)
|
||||
install_eckd_ldl_ccw(int fd, disk_blockptr_t *program_table,
|
||||
disk_blockptr_t *stage1b_list, blocknum_t stage1b_count,
|
||||
struct disk_info *info)
|
||||
{
|
||||
struct boot_eckd_ldl_stage0 stage0;
|
||||
struct boot_eckd_stage1 stage1;
|
||||
@@ -236,8 +240,8 @@ install_eckd_ldl(int fd, disk_blockptr_t *program_table,
|
||||
if (boot_init_eckd_stage1(&stage1, stage1b_list, stage1b_count))
|
||||
return -1;
|
||||
|
||||
boot_get_ipl_info(&stage1.boot_info, BOOT_INFO_DEV_TYPE_ECKD,
|
||||
program_table, info);
|
||||
boot_get_ipl_info_ccw(&stage1.boot_info, BOOT_INFO_DEV_TYPE_ECKD,
|
||||
program_table, info);
|
||||
|
||||
if (DRY_RUN_FUNC(misc_pwrite(fd, &stage1, sizeof(stage1),
|
||||
sizeof(stage0))))
|
||||
@@ -246,12 +250,14 @@ install_eckd_ldl(int fd, disk_blockptr_t *program_table,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Install bootloader for initial program load from an ECKD type disk with
|
||||
* OS/390 compatible disk layout. */
|
||||
static int
|
||||
install_eckd_cdl(int fd, disk_blockptr_t *program_table,
|
||||
disk_blockptr_t *stage1b_list, blocknum_t stage1b_count,
|
||||
struct disk_info *info)
|
||||
/**
|
||||
* Install bootloader for CCW-type IPL from ECKD type disk with
|
||||
* OS/390 compatible disk layout
|
||||
*/
|
||||
static int install_eckd_cdl_ccw(int fd, disk_blockptr_t *program_table,
|
||||
disk_blockptr_t *stage1b_list,
|
||||
blocknum_t stage1b_count,
|
||||
struct disk_info *info)
|
||||
{
|
||||
struct boot_eckd_cdl_stage0 stage0;
|
||||
struct boot_eckd_stage1 stage1;
|
||||
@@ -264,8 +270,8 @@ install_eckd_cdl(int fd, disk_blockptr_t *program_table,
|
||||
if (boot_init_eckd_stage1(&stage1, stage1b_list, stage1b_count))
|
||||
return -1;
|
||||
|
||||
boot_get_ipl_info(&stage1.boot_info, BOOT_INFO_DEV_TYPE_ECKD,
|
||||
program_table, info);
|
||||
boot_get_ipl_info_ccw(&stage1.boot_info, BOOT_INFO_DEV_TYPE_ECKD,
|
||||
program_table, info);
|
||||
|
||||
if (DRY_RUN_FUNC(misc_pwrite(fd, &stage1, sizeof(stage1),
|
||||
4 + info->phy_block_size)))
|
||||
@@ -273,16 +279,74 @@ install_eckd_cdl(int fd, disk_blockptr_t *program_table,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
install_bootloader(const char *device, disk_blockptr_t *program_table,
|
||||
disk_blockptr_t *scsi_dump_sb_blockptr,
|
||||
disk_blockptr_t *stage1b_list, blocknum_t stage1b_count,
|
||||
struct disk_info *info, struct job_data *job)
|
||||
/**
|
||||
* Install a program table for List-Directed IPL on a CDL-formatted DASD.
|
||||
*
|
||||
* The installation means storing an actual boot record address in the
|
||||
* volume label.
|
||||
*
|
||||
* BR: represents an actual boot record address.
|
||||
*/
|
||||
static int install_eckd_cdl_ld(int fd, disk_blockptr_t *br,
|
||||
struct disk_info *info)
|
||||
{
|
||||
struct vol_label_cdl vl;
|
||||
int rc;
|
||||
|
||||
/* Read a volume label from CDL-formatted DASD */
|
||||
if (misc_seek(fd, 2 * info->phy_block_size))
|
||||
return -1;
|
||||
rc = misc_read(fd, &vl, sizeof(vl));
|
||||
if (rc) {
|
||||
error_text("Could not read volume label");
|
||||
return rc;
|
||||
}
|
||||
/* Verify that we have a VOL1 label */
|
||||
if (!is_vol1(vl.vollbl)) {
|
||||
error_text("Volume label 'vol1' not initialized");
|
||||
return -1;
|
||||
}
|
||||
/* Pack the actual boot record address */
|
||||
vtoc_set_cchhb(&vl.br, br->chs.cyl, br->chs.head, br->chs.sec);
|
||||
|
||||
/* Write out the updated volume label */
|
||||
if (misc_seek(fd, 2 * info->phy_block_size))
|
||||
return -1;
|
||||
rc = DRY_RUN_FUNC(misc_write(fd, &vl, sizeof(vl)));
|
||||
if (rc)
|
||||
error_text("Could not update volume lablel 'vol1'");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Install a "compatible" boot record referring one, or two "similar"
|
||||
* program tables.
|
||||
*
|
||||
* The picture below shows which program table is used for IPL
|
||||
* of specified type from disk of specified type.
|
||||
* E.g. program table "0" is used for CCW-type IPL from ECKD DASD,
|
||||
* LD-IPL from DASD FBA is unsupported (respectively, only one program
|
||||
* table "0" is used), etc.
|
||||
*
|
||||
* CCW-IPL LD-IPL
|
||||
*
|
||||
* SCSI X 0
|
||||
* DASD FBA 0 X
|
||||
* ECKD DASD LDL 0 X
|
||||
* ECKD DASD CDL 0 1
|
||||
*/
|
||||
int install_bootloader(struct job_data *job, struct install_set *bis)
|
||||
{
|
||||
disk_blockptr_t *scsi_dump_sb_blockptr = &bis->scsi_dump_sb_blockptr;
|
||||
struct program_table *pt0 = &bis->tables[PROGRAM_TABLE_0];
|
||||
struct program_table *pt1 = &bis->tables[PROGRAM_TABLE_1];
|
||||
struct disk_info *info = bis->info;
|
||||
char *device = bis->device;
|
||||
int fd, rc;
|
||||
|
||||
/* Inform user about what we're up to */
|
||||
printf("Preparing boot device: ");
|
||||
printf("Preparing boot device for %sIPL: ",
|
||||
disk_get_ipl_type(info->type));
|
||||
if (info->name) {
|
||||
printf("%s", info->name);
|
||||
if (info->devno >= 0)
|
||||
@@ -310,27 +374,40 @@ install_bootloader(const char *device, disk_blockptr_t *program_table,
|
||||
"caches.\n");
|
||||
}
|
||||
}
|
||||
/* Call disk specific install functions */
|
||||
/*
|
||||
* Depending on disk type, install one or two program tables
|
||||
* for CCW-type IPL and (or) for List-Directed IPL (see the
|
||||
* picture in comments above)
|
||||
*/
|
||||
rc = -1;
|
||||
switch (info->type) {
|
||||
case disk_type_scsi:
|
||||
rc = install_scsi(fd, program_table, info,
|
||||
rc = install_scsi(fd, &pt0->table, info,
|
||||
scsi_dump_sb_blockptr);
|
||||
if (rc == 0 && job->id == job_dump_partition &&
|
||||
!is_ngdump_enabled(device, &job->target))
|
||||
rc = overwrite_partition_start(fd, info, 0);
|
||||
break;
|
||||
case disk_type_fba:
|
||||
rc = install_fba(fd, program_table, stage1b_list,
|
||||
stage1b_count, info);
|
||||
rc = install_fba_ccw(fd,
|
||||
&pt0->table,
|
||||
pt0->stage1b_list,
|
||||
pt0->stage1b_count, info);
|
||||
break;
|
||||
case disk_type_eckd_ldl:
|
||||
rc = install_eckd_ldl(fd, program_table, stage1b_list,
|
||||
stage1b_count, info);
|
||||
rc = install_eckd_ldl_ccw(fd,
|
||||
&pt0->table,
|
||||
pt0->stage1b_list,
|
||||
pt0->stage1b_count, info);
|
||||
break;
|
||||
case disk_type_eckd_cdl:
|
||||
rc = install_eckd_cdl(fd, program_table, stage1b_list,
|
||||
stage1b_count, info);
|
||||
rc = install_eckd_cdl_ccw(fd,
|
||||
&pt0->table,
|
||||
pt0->stage1b_list,
|
||||
pt0->stage1b_count, info);
|
||||
if (rc)
|
||||
break;
|
||||
rc = install_eckd_cdl_ld(fd, pt1->stage1b_list, info);
|
||||
break;
|
||||
case disk_type_diag:
|
||||
/* Should not happen */
|
||||
|
||||
@@ -126,11 +126,8 @@ check_for_root(void)
|
||||
int
|
||||
main(int argc, char* argv[])
|
||||
{
|
||||
struct disk_info* info;
|
||||
disk_blockptr_t program_table, scsi_dump_sb_blockptr, *stage1b_list;
|
||||
blocknum_t stage1b_count;
|
||||
struct install_set bis;
|
||||
struct job_data* job;
|
||||
char* device;
|
||||
int rc;
|
||||
|
||||
/* Check internals */
|
||||
@@ -197,21 +194,11 @@ main(int argc, char* argv[])
|
||||
case job_ipl:
|
||||
case job_segment:
|
||||
case job_menu:
|
||||
/* Create bootmap */
|
||||
stage1b_list = NULL;
|
||||
rc = bootmap_create(job, &program_table, &scsi_dump_sb_blockptr,
|
||||
&stage1b_list, &stage1b_count, &device,
|
||||
&info);
|
||||
rc = prepare_bootloader(job, &bis);
|
||||
if (rc)
|
||||
break;
|
||||
/* Install boot loader */
|
||||
rc = install_bootloader(device, &program_table,
|
||||
&scsi_dump_sb_blockptr, stage1b_list,
|
||||
stage1b_count, info, job);
|
||||
if (stage1b_list != NULL)
|
||||
free(stage1b_list);
|
||||
misc_free_temp_dev(device);
|
||||
disk_free_info(info);
|
||||
rc = install_bootloader(job, &bis);
|
||||
free_bootloader(&bis);
|
||||
break;
|
||||
case job_ipl_tape:
|
||||
rc = install_tapeloader(job->data.ipl_tape.device,
|
||||
@@ -251,3 +238,57 @@ main(int argc, char* argv[])
|
||||
job_free(job);
|
||||
return abs(rc);
|
||||
}
|
||||
|
||||
/**
|
||||
* Program Component Footers
|
||||
*/
|
||||
struct component_footer component_footers[NR_PROGRAM_COMPONENTS] = {
|
||||
[COMPONENT_ID_HEAP_AREA] = {
|
||||
.type = COMPONENT_TYPE_LOAD,
|
||||
.desc = "heap area"
|
||||
},
|
||||
[COMPONENT_ID_STACK_AREA] = {
|
||||
.type = COMPONENT_TYPE_LOAD,
|
||||
.desc = "stack area"
|
||||
},
|
||||
[COMPONENT_ID_LOADER_SIGNATURE] = {
|
||||
.type = COMPONENT_TYPE_SIGNATURE,
|
||||
.desc = "loader signature"
|
||||
},
|
||||
[COMPONENT_ID_LOADER] = {
|
||||
.type = COMPONENT_TYPE_LOAD,
|
||||
.desc = "internal loader"
|
||||
},
|
||||
[COMPONENT_ID_PARAMETERS] = {
|
||||
.type = COMPONENT_TYPE_LOAD,
|
||||
.desc = "parameters"
|
||||
},
|
||||
[COMPONENT_ID_IMAGE_SIGNATURE] = {
|
||||
.type = COMPONENT_TYPE_SIGNATURE,
|
||||
.desc = "image signature"
|
||||
},
|
||||
[COMPONENT_ID_KERNEL_IMAGE] = {
|
||||
.type = COMPONENT_TYPE_LOAD,
|
||||
.desc = "kernel image"
|
||||
},
|
||||
[COMPONENT_ID_PARMLINE] = {
|
||||
.type = COMPONENT_TYPE_LOAD,
|
||||
.desc = "parmline"
|
||||
},
|
||||
[COMPONENT_ID_RAMDISK_SIGNATURE] = {
|
||||
.type = COMPONENT_TYPE_SIGNATURE,
|
||||
.desc = "ramdisk signature"
|
||||
},
|
||||
[COMPONENT_ID_RAMDISK] = {
|
||||
.type = COMPONENT_TYPE_LOAD,
|
||||
.desc = "initial ramdisk"
|
||||
},
|
||||
[COMPONENT_ID_ENVBLK] = {
|
||||
.type = COMPONENT_TYPE_LOAD,
|
||||
.desc = "environment blk"
|
||||
},
|
||||
[COMPONENT_ID_SEGMENT_FILE] = {
|
||||
.type = COMPONENT_TYPE_EXECUTE,
|
||||
.desc = "segment file"
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user