mirror of
https://github.com/ibm-s390-linux/s390-tools.git
synced 2026-08-05 02:14:52 +00:00
zipl/src: Fix problems when image is not on target SCSI
This patch fixes a bug in disk_get_info()
Steps to reproduce: Prepare a SCSI disk for IPL, specifying an image
("-i IMAGE_NAME") located on DASD and a target directory ("-t /mnt")
located on SCSI (dm). Don't specify "-a" option.
Actual result: Installation succeeded (resulting in unbootable setup!)
Expected result: "Error: Could not add image file 'IMAGE_NAME':
File is not on target device".
The problem is in incorrect evaluation of device number (dev_t) of
the device, where the image file is located, by the function
add_component_file_range(). To evaluate it, disk_get_info() is called
with the structure job_target_data (passed as the second argument)
previously completed by disk_get_info() called earlier to evaluate
parameters of the specified target device (SCSI dm) by the function
prepare_build_program_table_file(). Since the targetbase is already
set in the passed job_target_data (by the first call), in the second
call the source type is evaluated as "source_user", so the number of
the device where the image is located is calculated by the base SCSI
disk, which is incorrect.
Fixup: Rework disk_get_info(): introduce a dedicated function to
evaluate source type not depending on the job_target_data content.
Implement the core procedure as a switch by the evaluated source
type.
Signed-off-by: Eduard Shishkin <edward6@linux.ibm.com>
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
This commit is contained in:
committed by
Steffen Eiden
parent
08232d29b9
commit
76aaf3d4a8
+1
-9
@@ -53,13 +53,6 @@ typedef enum {
|
||||
disk_type_eckd_cdl,
|
||||
} disk_type_t;
|
||||
|
||||
/* Disk information source */
|
||||
typedef enum {
|
||||
source_auto,
|
||||
source_user,
|
||||
source_script
|
||||
} source_t;
|
||||
|
||||
/* targetbase definition */
|
||||
typedef enum {
|
||||
defined_as_device,
|
||||
@@ -79,7 +72,6 @@ struct disk_info {
|
||||
struct hd_geometry geo;
|
||||
char* name;
|
||||
char* drv_name;
|
||||
source_t source;
|
||||
definition_t targetbase;
|
||||
int is_nvme;
|
||||
};
|
||||
@@ -121,7 +113,7 @@ blocknum_t disk_write_block_buffer_align(int fd, int fd_is_basedisk,
|
||||
struct disk_info *info, int align,
|
||||
off_t *offset);
|
||||
void disk_print_devt(dev_t d);
|
||||
void disk_print_info(struct disk_info* info);
|
||||
void disk_print_info(struct disk_info *info, int source);
|
||||
int disk_is_zero_block(disk_blockptr_t* block, struct disk_info* info);
|
||||
blocknum_t disk_compact_blocklist(disk_blockptr_t* list, blocknum_t count,
|
||||
struct disk_info* info);
|
||||
|
||||
@@ -30,6 +30,14 @@ enum job_id {
|
||||
job_mvdump = 8,
|
||||
};
|
||||
|
||||
/* target information source */
|
||||
typedef enum {
|
||||
source_unknown = 0,
|
||||
source_auto = 1,
|
||||
source_user = 2,
|
||||
source_script = 3
|
||||
} source_t;
|
||||
|
||||
struct job_target_data {
|
||||
char* bootmap_dir;
|
||||
char* targetbase;
|
||||
@@ -39,6 +47,7 @@ struct job_target_data {
|
||||
int targetsectors;
|
||||
int targetblocksize;
|
||||
blocknum_t targetoffset;
|
||||
source_t source;
|
||||
};
|
||||
|
||||
struct job_common_ipl_data {
|
||||
@@ -133,6 +142,13 @@ struct job_data {
|
||||
int is_ldipl_dump;
|
||||
};
|
||||
|
||||
/**
|
||||
* Return true, if target parameters for the base disk are set
|
||||
*/
|
||||
static inline int target_parameters_are_set(struct job_target_data *td)
|
||||
{
|
||||
return td->targetbase != NULL;
|
||||
}
|
||||
|
||||
int job_get(int argc, char* argv[], struct job_data** data);
|
||||
void job_free(struct job_data* job);
|
||||
|
||||
+5
-4
@@ -1406,7 +1406,8 @@ check_dump_device(struct job_data *job, const struct disk_info *info,
|
||||
int rc, part_ext;
|
||||
|
||||
/* Check for supported disk and driver types */
|
||||
if ((info->source == source_auto) && (info->type == disk_type_diag)) {
|
||||
if (job->target.source == source_auto &&
|
||||
info->type == disk_type_diag) {
|
||||
error_reason("Unsupported disk type (%s)",
|
||||
disk_get_type_name(info->type));
|
||||
return -1;
|
||||
@@ -1474,7 +1475,7 @@ static int prepare_build_program_table_device(struct job_data *job,
|
||||
|
||||
if (verbose) {
|
||||
printf("Target device information\n");
|
||||
disk_print_info(bis->info);
|
||||
disk_print_info(bis->info, job->target.source);
|
||||
}
|
||||
if (misc_temp_dev(bis->info->device, 1, &bis->device))
|
||||
return -1;
|
||||
@@ -1563,7 +1564,7 @@ static int prepare_build_program_table_file(struct job_data *job,
|
||||
if (disk_get_info_from_file(bis->filename, &job->target, &bis->info))
|
||||
return -1;
|
||||
/* Check for supported disk and driver types */
|
||||
if (bis->info->source == source_auto &&
|
||||
if (job->target.source == source_auto &&
|
||||
bis->info->type == disk_type_diag) {
|
||||
error_reason("Unsupported disk type (%s)",
|
||||
disk_get_type_name(bis->info->type));
|
||||
@@ -1573,7 +1574,7 @@ static int prepare_build_program_table_file(struct job_data *job,
|
||||
return -1;
|
||||
if (verbose) {
|
||||
printf("Target device information\n");
|
||||
disk_print_info(bis->info);
|
||||
disk_print_info(bis->info, job->target.source);
|
||||
}
|
||||
if (misc_temp_dev(bis->info->device, 1, &bis->device))
|
||||
return -1;
|
||||
|
||||
+326
-199
@@ -116,8 +116,8 @@ read_block_by_offset(int fd, int blksize, uint64_t offset, char *buffer)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
determine_virtblk_type(struct disk_info *data, struct stat *stats)
|
||||
static int determine_virtblk_type(struct disk_info *data,
|
||||
const struct stat *stats)
|
||||
{
|
||||
char *device;
|
||||
char *buffer;
|
||||
@@ -187,171 +187,97 @@ out_err:
|
||||
return rc;
|
||||
}
|
||||
|
||||
int
|
||||
disk_get_info(const char* device, struct job_target_data* target,
|
||||
struct disk_info** info)
|
||||
static int set_target_parameters(FILE *fh, struct job_target_data *td)
|
||||
{
|
||||
struct stat stats;
|
||||
struct stat script_stats;
|
||||
struct util_proc_part_entry part_entry;
|
||||
struct util_proc_dev_entry dev_entry;
|
||||
struct dasd_information dasd_info;
|
||||
struct disk_info *data;
|
||||
int fd;
|
||||
long devsize;
|
||||
FILE *fh;
|
||||
const char *script_pre = util_libdir_path("/zipl_helper.");
|
||||
char *script_file = NULL;
|
||||
char *ppn_cmd = NULL;
|
||||
int checkparm = 0;
|
||||
char buffer[80];
|
||||
char value[40];
|
||||
|
||||
while (fgets(buffer, 80, fh)) {
|
||||
if (sscanf(buffer, "targetbase=%s", value) == 1) {
|
||||
td->targetbase = misc_strdup(value);
|
||||
checkparm++;
|
||||
}
|
||||
if (sscanf(buffer, "targettype=%s", value) == 1) {
|
||||
type_from_target(value, &td->targettype);
|
||||
checkparm++;
|
||||
}
|
||||
if (sscanf(buffer, "targetgeometry=%s", value) == 1) {
|
||||
td->targetcylinders =
|
||||
atoi(strtok(value, ","));
|
||||
td->targetheads = atoi(strtok(NULL, ","));
|
||||
td->targetsectors = atoi(strtok(NULL, ","));
|
||||
checkparm++;
|
||||
}
|
||||
if (sscanf(buffer, "targetblocksize=%s", value) == 1) {
|
||||
td->targetblocksize = atoi(value);
|
||||
checkparm++;
|
||||
}
|
||||
if (sscanf(buffer, "targetoffset=%s", value) == 1) {
|
||||
td->targetoffset = atol(value);
|
||||
checkparm++;
|
||||
}
|
||||
}
|
||||
if ((!disk_is_eckd(td->targettype) && checkparm < 4) ||
|
||||
(disk_is_eckd(td->targettype) && checkparm != 5)) {
|
||||
error_reason("Target parameters missing from script");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set disk info using ready target parameters provided either by
|
||||
* user, or by script
|
||||
*/
|
||||
static int disk_set_info_by_hint(struct job_target_data *td,
|
||||
struct disk_info *data, int fd)
|
||||
{
|
||||
int majnum, minnum;
|
||||
int checkparm;
|
||||
struct stat stats;
|
||||
|
||||
/* Get file information */
|
||||
if (stat(device, &stats)) {
|
||||
error_reason(strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
/* Open device file */
|
||||
fd = open(device, O_RDONLY);
|
||||
if (fd == -1) {
|
||||
error_reason(strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
/* Get memory for result */
|
||||
data = (struct disk_info *) misc_malloc(sizeof(struct disk_info));
|
||||
if (data == NULL) {
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
memset((void *) data, 0, sizeof(struct disk_info));
|
||||
/* Try to get device driver name */
|
||||
if (util_proc_dev_get_entry(stats.st_rdev, 1, &dev_entry) == 0) {
|
||||
data->drv_name = misc_strdup(dev_entry.name);
|
||||
util_proc_dev_free_entry(&dev_entry);
|
||||
} else {
|
||||
fprintf(stderr, "Warning: Could not determine driver name for "
|
||||
"major %d from /proc/devices\n", major(stats.st_rdev));
|
||||
fprintf(stderr, "Warning: Preparing a logical device for boot "
|
||||
"might fail\n");
|
||||
}
|
||||
data->source = source_user;
|
||||
/* Check if targetbase script is available */
|
||||
if (data->drv_name)
|
||||
misc_asprintf(&script_file, "%s%s", script_pre, data->drv_name);
|
||||
else
|
||||
misc_asprintf(&script_file, "%s", script_pre);
|
||||
if ((target->targetbase == NULL) &&
|
||||
(!stat(script_file, &script_stats))) {
|
||||
data->source = source_script;
|
||||
/* Run targetbase script */
|
||||
misc_asprintf(&ppn_cmd, "%s %d:%d",
|
||||
script_file, major(stats.st_rdev),
|
||||
minor(stats.st_rdev));
|
||||
printf("Run %s\n", ppn_cmd);
|
||||
fh = popen(ppn_cmd, "r");
|
||||
if (fh == NULL) {
|
||||
error_reason("Failed to run popen(%s,\"r\",)");
|
||||
goto out_close;
|
||||
}
|
||||
checkparm = 0;
|
||||
while (fgets(buffer, 80, fh) != NULL) {
|
||||
if (sscanf(buffer, "targetbase=%s", value) == 1) {
|
||||
target->targetbase = misc_strdup(value);
|
||||
checkparm++;
|
||||
}
|
||||
if (sscanf(buffer, "targettype=%s", value) == 1) {
|
||||
type_from_target(value, &target->targettype);
|
||||
checkparm++;
|
||||
}
|
||||
if (sscanf(buffer, "targetgeometry=%s", value) == 1) {
|
||||
target->targetcylinders =
|
||||
atoi(strtok(value, ","));
|
||||
target->targetheads = atoi(strtok(NULL, ","));
|
||||
target->targetsectors = atoi(strtok(NULL, ","));
|
||||
checkparm++;
|
||||
}
|
||||
if (sscanf(buffer, "targetblocksize=%s", value) == 1) {
|
||||
target->targetblocksize = atoi(value);
|
||||
checkparm++;
|
||||
}
|
||||
if (sscanf(buffer, "targetoffset=%s", value) == 1) {
|
||||
target->targetoffset = atol(value);
|
||||
checkparm++;
|
||||
}
|
||||
}
|
||||
switch (pclose(fh)) {
|
||||
case 0 :
|
||||
/* success */
|
||||
break;
|
||||
case -1 :
|
||||
error_reason("Failed to run pclose");
|
||||
goto out_close;
|
||||
default :
|
||||
error_reason("Script could not determine target "
|
||||
"parameters");
|
||||
goto out_close;
|
||||
}
|
||||
if ((!disk_is_eckd(target->targettype) && checkparm < 4) ||
|
||||
(disk_is_eckd(target->targettype) && checkparm != 5)) {
|
||||
error_reason("Target parameters missing from script");
|
||||
goto out_close;
|
||||
}
|
||||
}
|
||||
data->devno = -1;
|
||||
data->phy_block_size = td->targetblocksize;
|
||||
data->type = td->targettype;
|
||||
data->partnum = 0;
|
||||
|
||||
/* Get disk geometry. Note: geo.start contains a sector number
|
||||
* offset measured in physical blocks, not sectors (512 bytes) */
|
||||
if (target->targetbase != NULL) {
|
||||
data->geo.heads = target->targetheads;
|
||||
data->geo.sectors = target->targetsectors;
|
||||
data->geo.cylinders = target->targetcylinders;
|
||||
data->geo.start = target->targetoffset;
|
||||
if (sscanf(td->targetbase, "%d:%d", &majnum, &minnum) == 2) {
|
||||
data->device = makedev(majnum, minnum);
|
||||
data->targetbase = defined_as_device;
|
||||
data->partnum = minor(stats.st_rdev) - minnum;
|
||||
} else {
|
||||
data->source = source_auto;
|
||||
if (ioctl(fd, HDIO_GETGEO, &data->geo)) {
|
||||
error_reason("Could not get disk geometry");
|
||||
goto out_close;
|
||||
if (stat(td->targetbase, &stats)) {
|
||||
error_reason(strerror(errno));
|
||||
error_text("Could not get information for "
|
||||
"file '%s'", td->targetbase);
|
||||
return -1;
|
||||
}
|
||||
if (!S_ISBLK(stats.st_mode)) {
|
||||
error_reason("Target base device '%s' is not "
|
||||
"a block device",
|
||||
td->targetbase);
|
||||
return -1;
|
||||
}
|
||||
data->device = stats.st_rdev;
|
||||
data->targetbase = defined_as_name;
|
||||
}
|
||||
if ((data->source == source_user) || (data->source == source_script)) {
|
||||
data->devno = -1;
|
||||
data->phy_block_size = target->targetblocksize;
|
||||
data->type = target->targettype;
|
||||
data->partnum = 0;
|
||||
/* Get file information */
|
||||
if (sscanf(target->targetbase, "%d:%d", &majnum, &minnum)
|
||||
== 2) {
|
||||
data->device = makedev(majnum, minnum);
|
||||
data->targetbase = defined_as_device;
|
||||
data->partnum = minor(stats.st_rdev) - minnum;
|
||||
}
|
||||
else {
|
||||
if (stat(target->targetbase, &stats)) {
|
||||
error_reason(strerror(errno));
|
||||
error_text("Could not get information for "
|
||||
"file '%s'", target->targetbase);
|
||||
goto out_close;
|
||||
}
|
||||
if (!S_ISBLK(stats.st_mode)) {
|
||||
error_reason("Target base device '%s' is not "
|
||||
"a block device",
|
||||
target->targetbase);
|
||||
goto out_close;
|
||||
}
|
||||
data->device = stats.st_rdev;
|
||||
data->targetbase = defined_as_name;
|
||||
}
|
||||
if (data->type == disk_type_scsi &&
|
||||
ioctl(fd, NVME_IOCTL_ID) >= 0)
|
||||
data->is_nvme = 1;
|
||||
goto type_determined;
|
||||
}
|
||||
if (data->type == disk_type_scsi && ioctl(fd, NVME_IOCTL_ID) >= 0)
|
||||
data->is_nvme = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate target parameters in the case when no hints were provided
|
||||
*/
|
||||
static int disk_set_info_auto(struct disk_info *data,
|
||||
const struct stat *stats, int fd)
|
||||
{
|
||||
struct dasd_information dasd_info;
|
||||
|
||||
if (ioctl(fd, BLKSSZGET, &data->phy_block_size)) {
|
||||
error_reason("Could not get blocksize");
|
||||
goto out_close;
|
||||
return -1;
|
||||
}
|
||||
/* Determine disk type */
|
||||
if (!data->drv_name) {
|
||||
/* Driver name cannot be read */
|
||||
if (ioctl(fd, BIODASDINFO, &dasd_info)) {
|
||||
@@ -359,39 +285,39 @@ disk_get_info(const char* device, struct job_target_data* target,
|
||||
if (data->geo.start) {
|
||||
/* SCSI partition */
|
||||
data->type = disk_type_scsi;
|
||||
data->partnum = stats.st_rdev & SCSI_PARTN_MASK;
|
||||
data->device = stats.st_rdev & ~SCSI_PARTN_MASK;
|
||||
data->partnum = stats->st_rdev & SCSI_PARTN_MASK;
|
||||
data->device = stats->st_rdev & ~SCSI_PARTN_MASK;
|
||||
} else {
|
||||
/* SCSI disk */
|
||||
data->type = disk_type_scsi;
|
||||
data->partnum = 0;
|
||||
data->device = stats.st_rdev;
|
||||
data->device = stats->st_rdev;
|
||||
}
|
||||
} else {
|
||||
/* DASD */
|
||||
data->devno = dasd_info.devno;
|
||||
if (disk_determine_dasd_type(data, dasd_info))
|
||||
goto out_close;
|
||||
data->partnum = stats.st_rdev & DASD_PARTN_MASK;
|
||||
data->device = stats.st_rdev & ~DASD_PARTN_MASK;
|
||||
return -1;
|
||||
data->partnum = stats->st_rdev & DASD_PARTN_MASK;
|
||||
data->device = stats->st_rdev & ~DASD_PARTN_MASK;
|
||||
}
|
||||
} else if (strcmp(data->drv_name, "dasd") == 0) {
|
||||
/* Driver name is 'dasd' */
|
||||
if (ioctl(fd, BIODASDINFO, &dasd_info)) {
|
||||
error_reason("Could not determine DASD type");
|
||||
goto out_close;
|
||||
return -1;
|
||||
}
|
||||
data->devno = dasd_info.devno;
|
||||
if (disk_determine_dasd_type(data, dasd_info))
|
||||
goto out_close;
|
||||
data->partnum = stats.st_rdev & DASD_PARTN_MASK;
|
||||
data->device = stats.st_rdev & ~DASD_PARTN_MASK;
|
||||
return -1;
|
||||
data->partnum = stats->st_rdev & DASD_PARTN_MASK;
|
||||
data->device = stats->st_rdev & ~DASD_PARTN_MASK;
|
||||
} else if (strcmp(data->drv_name, "sd") == 0) {
|
||||
/* Driver name is 'sd' */
|
||||
data->devno = -1;
|
||||
data->type = disk_type_scsi;
|
||||
data->partnum = stats.st_rdev & SCSI_PARTN_MASK;
|
||||
data->device = stats.st_rdev & ~SCSI_PARTN_MASK;
|
||||
data->partnum = stats->st_rdev & SCSI_PARTN_MASK;
|
||||
data->device = stats->st_rdev & ~SCSI_PARTN_MASK;
|
||||
|
||||
} else if (strcmp(data->drv_name, "virtblk") == 0) {
|
||||
|
||||
@@ -400,10 +326,10 @@ disk_get_info(const char* device, struct job_target_data* target,
|
||||
if (ioctl(fd, BLKSSZGET, &data->phy_block_size) != 0)
|
||||
perror("Could not retrieve blocksize information.");
|
||||
|
||||
if (determine_virtblk_type(data, &stats)) {
|
||||
if (determine_virtblk_type(data, stats)) {
|
||||
error_reason("Virtblk device type not clearly "
|
||||
"determined.");
|
||||
goto out_close;
|
||||
return -1;
|
||||
}
|
||||
/* NVMe path, driver name is 'blkext' */
|
||||
} else if (strcmp(data->drv_name, "blkext") == 0 &&
|
||||
@@ -412,66 +338,268 @@ disk_get_info(const char* device, struct job_target_data* target,
|
||||
data->type = disk_type_scsi;
|
||||
data->is_nvme = 1;
|
||||
|
||||
if (util_sys_dev_is_partition(stats.st_rdev)) {
|
||||
if (util_sys_get_base_dev(stats.st_rdev, &data->device))
|
||||
goto out_close;
|
||||
data->partnum = util_sys_get_partnum(stats.st_rdev);
|
||||
if (util_sys_dev_is_partition(stats->st_rdev)) {
|
||||
if (util_sys_get_base_dev(stats->st_rdev, &data->device))
|
||||
return -1;
|
||||
data->partnum = util_sys_get_partnum(stats->st_rdev);
|
||||
if (data->partnum == -1)
|
||||
goto out_close;
|
||||
return -1;
|
||||
} else {
|
||||
data->device = stats.st_rdev;
|
||||
data->device = stats->st_rdev;
|
||||
data->partnum = 0;
|
||||
}
|
||||
} else {
|
||||
/* Driver name is unknown */
|
||||
error_reason("Unsupported device driver '%s'", data->drv_name);
|
||||
goto out_close;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluate and set source type
|
||||
*/
|
||||
static void set_source_type(struct job_target_data *td,
|
||||
const char *drv_name, char **script_file)
|
||||
{
|
||||
const char *script_prefix = util_libdir_path("zipl_helper.");
|
||||
struct stat script_stats;
|
||||
|
||||
if (td->source == source_user) {
|
||||
/* do not reset user-specified target parameters */
|
||||
return;
|
||||
}
|
||||
/* Check if targetbase script is available */
|
||||
if (drv_name)
|
||||
misc_asprintf(script_file, "%s%s", script_prefix,
|
||||
drv_name);
|
||||
else
|
||||
misc_asprintf(script_file, "%s", script_prefix);
|
||||
if (!stat(*script_file, &script_stats)) {
|
||||
/* target parameters to be evaluated by script */
|
||||
td->source = source_script;
|
||||
return;
|
||||
}
|
||||
td->source = source_auto;
|
||||
}
|
||||
|
||||
static void set_driver_name(struct disk_info *info, dev_t device)
|
||||
{
|
||||
struct util_proc_dev_entry dev_entry;
|
||||
|
||||
if (info->drv_name)
|
||||
/* already set */
|
||||
return;
|
||||
if (util_proc_dev_get_entry(device, 1, &dev_entry) == 0) {
|
||||
info->drv_name = misc_strdup(dev_entry.name);
|
||||
util_proc_dev_free_entry(&dev_entry);
|
||||
} else {
|
||||
fprintf(stderr, "Warning: Could not determine driver name for "
|
||||
"major %d from /proc/devices\n", major(device));
|
||||
fprintf(stderr, "Warning: Preparing a logical device for boot "
|
||||
"might fail\n");
|
||||
}
|
||||
}
|
||||
|
||||
static int run_targetbase_script(struct job_target_data *td,
|
||||
char *script_file, struct stat *stats)
|
||||
{
|
||||
char *ppn_cmd = NULL;
|
||||
FILE *fh;
|
||||
|
||||
misc_asprintf(&ppn_cmd, "%s %d:%d", script_file,
|
||||
major(stats->st_rdev), minor(stats->st_rdev));
|
||||
printf("Run %s\n", ppn_cmd);
|
||||
fh = popen(ppn_cmd, "r");
|
||||
free(ppn_cmd);
|
||||
|
||||
if (!fh) {
|
||||
error_reason("Failed to run popen(%s,\"r\",)");
|
||||
return -1;
|
||||
}
|
||||
/* translate the script output to target parameters */
|
||||
if (set_target_parameters(fh, td)) {
|
||||
pclose(fh);
|
||||
return -1;
|
||||
}
|
||||
switch (pclose(fh)) {
|
||||
case 0:
|
||||
/* success */
|
||||
return 0;
|
||||
case -1:
|
||||
error_reason("Failed to run pclose");
|
||||
return -1;
|
||||
default:
|
||||
error_reason("Script could not determine target "
|
||||
"parameters");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set disk geometry using target parameters provided either by
|
||||
* user, or by script.
|
||||
*
|
||||
* Note: geo.start contains a sector number offset measured in
|
||||
* physical blocks, not sectors (512 bytes)
|
||||
*/
|
||||
static int disk_set_geometry_by_hint(struct job_target_data *td,
|
||||
struct disk_info *data)
|
||||
{
|
||||
data->geo.heads = td->targetheads;
|
||||
data->geo.sectors = td->targetsectors;
|
||||
data->geo.cylinders = td->targetcylinders;
|
||||
data->geo.start = td->targetoffset;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int disk_set_geometry_auto(int fd, struct disk_info *info)
|
||||
{
|
||||
if (ioctl(fd, HDIO_GETGEO, &info->geo)) {
|
||||
error_reason("Could not get disk geometry");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* The final step of setting disk info.
|
||||
* Common for all source types
|
||||
*
|
||||
* DATA: disk info to be completed
|
||||
* Pre-condition: disk type is already known and set at DATA->type
|
||||
*/
|
||||
static int disk_set_info_complete(struct job_target_data *td,
|
||||
struct disk_info *data,
|
||||
struct stat *stats, int fd)
|
||||
{
|
||||
struct util_proc_part_entry part_entry;
|
||||
long devsize;
|
||||
|
||||
type_determined:
|
||||
/* Get size of device in sectors (512 byte) */
|
||||
if (ioctl(fd, BLKGETSIZE, &devsize)) {
|
||||
error_reason("Could not get device size");
|
||||
goto out_close;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Check for valid CHS geometry data. */
|
||||
if (disk_is_eckd(data->type) && (data->geo.cylinders == 0 ||
|
||||
data->geo.heads == 0 || data->geo.sectors == 0)) {
|
||||
error_reason("Invalid disk geometry (CHS=%d/%d/%d)",
|
||||
data->geo.cylinders, data->geo.heads,
|
||||
data->geo.sectors);
|
||||
goto out_close;
|
||||
return -1;
|
||||
}
|
||||
/* Convert device size to size in physical blocks */
|
||||
data->phy_blocks = devsize / (data->phy_block_size / 512);
|
||||
/* Adjust start on SCSI according to block_size. device-mapper devices are skipped */
|
||||
if (data->type == disk_type_scsi && target->targetbase == NULL)
|
||||
data->geo.start = data->geo.start / (data->phy_block_size / 512);
|
||||
/*
|
||||
* Adjust start on SCSI according to block_size.
|
||||
* device-mapper devices, which are evaluated only
|
||||
* in "source_script" mode, are skipped
|
||||
*/
|
||||
if (data->type == disk_type_scsi && td->source == source_auto)
|
||||
data->geo.start =
|
||||
data->geo.start / (data->phy_block_size / 512);
|
||||
if (data->partnum != 0)
|
||||
data->partition = stats.st_rdev;
|
||||
data->partition = stats->st_rdev;
|
||||
/* Try to get device name */
|
||||
if (util_proc_part_get_entry(data->device, &part_entry) == 0) {
|
||||
data->name = misc_strdup(part_entry.name);
|
||||
util_proc_part_free_entry(&part_entry);
|
||||
if (data->name == NULL)
|
||||
goto out_close;
|
||||
return -1;
|
||||
}
|
||||
/* There is no easy way to find out whether there is a file system
|
||||
* on this device, so we set the respective block size to an invalid
|
||||
* value. */
|
||||
/* Initialize file system block size with invalid value */
|
||||
data->fs_block_size = -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare INFO required to perform IPL installation on the physical
|
||||
* disk where the logical DEVICE is located.
|
||||
* Preparation is performed in 2 steps:
|
||||
*
|
||||
* 1. Find out a physical "base" disk where the logical DEVICE is
|
||||
* located. Calculate "target" parameters (type, geometry, physical
|
||||
* block size, data offset, etc);
|
||||
* 2. Complete INFO by the found base disk and target parameters.
|
||||
*
|
||||
* TD: optionally contains target parameters specified by user via
|
||||
* config file, or special "target options" of zipl tool.
|
||||
* If target parameters were specified by user, then the step 1 above
|
||||
* is skipped.
|
||||
*
|
||||
* DEVICE: logical, or physical device, optionally formated with a
|
||||
* file system.
|
||||
*/
|
||||
int disk_get_info(const char *device, struct job_target_data *td,
|
||||
struct disk_info **info)
|
||||
{
|
||||
char *script_file = NULL;
|
||||
struct disk_info *data;
|
||||
struct stat stats;
|
||||
int fd;
|
||||
|
||||
if (stat(device, &stats)) {
|
||||
error_reason(strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
fd = open(device, O_RDONLY);
|
||||
if (fd == -1) {
|
||||
error_reason(strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
data = (struct disk_info *)misc_malloc(sizeof(struct disk_info));
|
||||
if (!data)
|
||||
goto error;
|
||||
memset((void *)data, 0, sizeof(struct disk_info));
|
||||
set_driver_name(data, stats.st_rdev);
|
||||
set_source_type(td, data->drv_name, &script_file);
|
||||
switch (td->source) {
|
||||
case source_script:
|
||||
if (run_targetbase_script(td, script_file, &stats))
|
||||
goto error;
|
||||
/* target parameters were set by the script output */
|
||||
assert(target_parameters_are_set(td));
|
||||
|
||||
if (disk_set_geometry_by_hint(td, data))
|
||||
goto error;
|
||||
if (disk_set_info_by_hint(td, data, fd))
|
||||
goto error;
|
||||
break;
|
||||
case source_user:
|
||||
/*
|
||||
* target parameters were specified by user via
|
||||
* "target" options
|
||||
*/
|
||||
assert(target_parameters_are_set(td));
|
||||
|
||||
if (disk_set_geometry_by_hint(td, data))
|
||||
goto error;
|
||||
if (disk_set_info_by_hint(td, data, fd))
|
||||
goto error;
|
||||
break;
|
||||
case source_auto:
|
||||
/* no ready target parameters are available */
|
||||
if (disk_set_geometry_auto(fd, data))
|
||||
goto error;
|
||||
if (disk_set_info_auto(data, &stats, fd))
|
||||
goto error;
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
if (disk_set_info_complete(td, data, &stats, fd))
|
||||
goto error;
|
||||
free(script_file);
|
||||
close(fd);
|
||||
*info = data;
|
||||
free(script_file);
|
||||
return 0;
|
||||
out_close:
|
||||
close(fd);
|
||||
free(ppn_cmd);
|
||||
error:
|
||||
free(script_file);
|
||||
close(fd);
|
||||
free(data);
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
int
|
||||
@@ -860,11 +988,10 @@ disk_is_large_volume(struct disk_info* info)
|
||||
|
||||
|
||||
/* Print textual representation of INFO contents. */
|
||||
void
|
||||
disk_print_info(struct disk_info* info)
|
||||
void disk_print_info(struct disk_info *info, int source)
|
||||
{
|
||||
char footnote[4] = "";
|
||||
if ((info->source == source_user) || (info->source == source_script))
|
||||
if (source == source_user || source == source_script)
|
||||
strcpy(footnote, " *)");
|
||||
|
||||
printf(" Device..........................: ");
|
||||
@@ -892,7 +1019,7 @@ disk_print_info(struct disk_info* info)
|
||||
(info->type == disk_type_diag) ||
|
||||
(info->type == disk_type_eckd_ldl) ||
|
||||
(info->type == disk_type_eckd_cdl)) &&
|
||||
(info->source == source_auto)) {
|
||||
(source == source_auto)) {
|
||||
printf(" DASD device number..............: %04x\n",
|
||||
info->devno);
|
||||
}
|
||||
@@ -923,9 +1050,9 @@ disk_print_info(struct disk_info* info)
|
||||
info->phy_block_size, footnote);
|
||||
printf(" Device size in physical blocks..: %ld\n",
|
||||
(long) info->phy_blocks);
|
||||
if (info->source == source_user)
|
||||
if (source == source_user)
|
||||
printf(" *) Data provided by user.\n");
|
||||
if (info->source == source_script)
|
||||
if (source == source_script)
|
||||
printf(" *) Data provided by script.\n");
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -1140,7 +1140,7 @@ install_dump(const char *device, struct job_target_data *target, uint64_t mem,
|
||||
}
|
||||
if (verbose) {
|
||||
printf("Target device information\n");
|
||||
disk_print_info(info);
|
||||
disk_print_info(info, target->source);
|
||||
}
|
||||
rc = misc_temp_dev(info->device, 1, &tempdev);
|
||||
if (rc) {
|
||||
@@ -1299,7 +1299,7 @@ install_mvdump(char* const device[], struct job_target_data* target, int count,
|
||||
if (verbose) {
|
||||
for (i = 0; i < count; i++) {
|
||||
printf("Multi-volume dump target %d:\n", i + 1);
|
||||
disk_print_info(info[i]);
|
||||
disk_print_info(info[i], target->source);
|
||||
printf("-------------------------------------------\n");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1367,6 +1367,7 @@ get_job_from_section_data(char* data[], struct job_data* job, char* section)
|
||||
scan_keyword_targetbase]);
|
||||
if (job->target.targetbase == NULL)
|
||||
return -1;
|
||||
job->target.source = source_user;
|
||||
}
|
||||
if (data[(int) scan_keyword_targettype] != NULL) {
|
||||
if (type_from_target(
|
||||
@@ -1618,6 +1619,7 @@ get_menu_job(struct scan_token* scan, char* menu, struct job_data* job)
|
||||
scan[i].content.keyword.value);
|
||||
if (job->target.targetbase == NULL)
|
||||
return -1;
|
||||
job->target.source = source_user;
|
||||
break;
|
||||
case scan_keyword_targettype:
|
||||
if (type_from_target(
|
||||
|
||||
Reference in New Issue
Block a user