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:
Eduard Shishkin
2024-04-24 11:47:40 +02:00
committed by Steffen Eiden
parent 08232d29b9
commit 76aaf3d4a8
6 changed files with 352 additions and 214 deletions
+1 -9
View File
@@ -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);
+16
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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");
}
}
+2
View File
@@ -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(