diff --git a/zipl/include/disk.h b/zipl/include/disk.h index 5eca0130..89979418 100644 --- a/zipl/include/disk.h +++ b/zipl/include/disk.h @@ -56,13 +56,14 @@ typedef enum { /* targetbase definition */ typedef enum { defined_as_device, - defined_as_name + defined_as_name, + undefined } definition_t; /* Disk information type */ struct disk_info { disk_type_t type; - dev_t device; + dev_t device; /* logical device for bootmap creation */ dev_t partition; int devno; int partnum; @@ -72,8 +73,11 @@ struct disk_info { struct hd_geometry geo; char* name; char* drv_name; - definition_t targetbase; + definition_t targetbase_def; int is_nvme; + dev_t basedisks[MAX_TARGETS]; /* array of physical disks for + * bootstrap blocks recording + */ }; struct file_range { @@ -113,6 +117,9 @@ 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_devname(dev_t d); +void prepare_footnote_ptr(int source, char *ptr); +void print_footnote_ref(int source, const char *prefix); 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, @@ -122,7 +129,6 @@ blocknum_t disk_get_blocklist_from_file(const char* filename, disk_blockptr_t** blocklist, struct disk_info* pinfo); int disk_check_subchannel_set(int devno, dev_t device, char* dev_name); -void disk_print_geo(struct disk_info *data); int fs_map(int fd, uint64_t offset, blocknum_t *mapped, int fs_block_size); #endif /* not DISK_H */ diff --git a/zipl/include/install.h b/zipl/include/install.h index 8e0a4921..d40971d8 100644 --- a/zipl/include/install.h +++ b/zipl/include/install.h @@ -71,7 +71,7 @@ struct install_set { struct program_component *components[NR_PROGRAM_COMPONENTS]; int nr_menu_entries; int fd; - char *device; + char *basetmp[MAX_TARGETS]; char *filename; unsigned int tmp_filename_created:1; unsigned int skip_prepare:1; diff --git a/zipl/include/job.h b/zipl/include/job.h index e46788ba..b8ffad87 100644 --- a/zipl/include/job.h +++ b/zipl/include/job.h @@ -18,7 +18,6 @@ #include "disk.h" #include "zipl.h" - enum job_id { job_print_usage = 1, job_print_version = 2, @@ -30,6 +29,21 @@ enum job_id { job_mvdump = 8, }; +/* + * Set of parameters per physical disk, which are provided + * either by user, or by helper script + */ +struct target { + char *targetbase; + disk_type_t targettype; + int targetcylinders; + int targetheads; + int targetsectors; + int targetblocksize; + blocknum_t targetoffset; + int check_params; +}; + /* target information source */ typedef enum { source_unknown = 0, @@ -39,17 +53,21 @@ typedef enum { } source_t; struct job_target_data { - char* bootmap_dir; - char* targetbase; - disk_type_t targettype; - int targetcylinders; - int targetheads; - int targetsectors; - int targetblocksize; - blocknum_t targetoffset; + char *bootmap_dir; + int nr_targets; + struct target targets[MAX_TARGETS]; source_t source; }; +enum target_params { + TARGET_BASE, + TARGET_TYPE, + TARGET_GEOMETRY, + TARGET_BLOCKSIZE, + TARGET_OFFSET, + LAST_TARGET_PARAM +}; + struct job_common_ipl_data { char* image; char* parmline; @@ -142,12 +160,94 @@ struct job_data { int is_ldipl_dump; }; +static inline struct target *target_at(struct job_target_data *data, + int index) +{ + return index >= MAX_TARGETS ? NULL : &data->targets[index]; +} + +static inline char *get_targetbase(struct job_target_data *data, int index) +{ + return target_at(data, index)->targetbase; +} + +static inline void set_targetbase(struct job_target_data *data, int index, + char *value) +{ + target_at(data, index)->targetbase = value; +} + +static inline disk_type_t get_targettype(struct job_target_data *data, + int index) +{ + return target_at(data, index)->targettype; +} + +int set_targettype(struct job_target_data *data, int index, char *value); + +static inline char *job_get_targetbase(struct job_data *job) +{ + return get_targetbase(&job->target, 0); +} + +static inline void job_set_targetbase(struct job_data *job, char *value) +{ + set_targetbase(&job->target, 0, value); +} + +static inline int job_get_nr_targets(struct job_data *job) +{ + return job->target.nr_targets; +} + +static inline void job_set_nr_targets(struct job_data *job, int value) +{ + job->target.nr_targets = value; +} + +static inline disk_type_t job_get_targettype(struct job_data *job) +{ + return get_targettype(&job->target, 0); +} + +int job_set_targettype(struct job_data *job, char *value); + +#define define_target_param_ops(_TYPE_, _PARAM_) \ +static inline _TYPE_ get_target##_PARAM_(struct job_target_data *data, \ + int index) \ +{ \ + return target_at(data, index)->target##_PARAM_; \ +} \ + \ +static inline void set_target##_PARAM_(struct job_target_data *data, \ + int index, _TYPE_ value) \ +{ \ + target_at(data, index)->target##_PARAM_ = value; \ +} \ + \ +static inline _TYPE_ job_get_target##_PARAM_(struct job_data *job) \ +{ \ + return get_target##_PARAM_(&job->target, 0); \ +} \ + \ +static inline void job_set_target##_PARAM_(struct job_data *job, \ + _TYPE_ value) \ +{ \ + set_target##_PARAM_(&job->target, 0, value); \ +} + +define_target_param_ops(int, cylinders) +define_target_param_ops(int, heads) +define_target_param_ops(int, sectors) +define_target_param_ops(int, blocksize) +define_target_param_ops(blocknum_t, offset) + /** - * Return true, if target parameters for the base disk are set + * Return true, if target parameters are set at least for one target base disk */ static inline int target_parameters_are_set(struct job_target_data *td) { - return td->targetbase != NULL; + return get_targetbase(td, 0) != NULL; } int job_get(int argc, char* argv[], struct job_data** data); diff --git a/zipl/include/zipl.h b/zipl/include/zipl.h index f3f5c6f0..cd71e9dd 100644 --- a/zipl/include/zipl.h +++ b/zipl/include/zipl.h @@ -41,6 +41,7 @@ #define MENU_DEFAULT_TIMEOUT 0 #define MAX_DUMP_VOLUMES 32 +#define MAX_TARGETS 32 #define SECURE_BOOT_UNDEFINED -1 #define SECURE_BOOT_DISABLED 0 diff --git a/zipl/src/bootmap.c b/zipl/src/bootmap.c index 17a3d462..b2402f9b 100644 --- a/zipl/src/bootmap.c +++ b/zipl/src/bootmap.c @@ -1489,9 +1489,9 @@ static int prepare_build_program_table_device(struct job_data *job, printf("Target device information\n"); disk_print_info(bis->info, job->target.source); } - if (misc_temp_dev(bis->info->device, 1, &bis->device)) + if (misc_temp_dev(bis->info->device, 1, &bis->basetmp[0])) return -1; - if (check_dump_device(job, bis->info, bis->device)) + if (check_dump_device(job, bis->info, bis->basetmp[0])) return -1; printf("Building bootmap directly on partition '%s'%s\n", bis->filename, @@ -1555,6 +1555,8 @@ static int prepare_bootloader_device(struct job_data *job, static int prepare_build_program_table_file(struct job_data *job, struct install_set *bis) { + int i; + if (bis->skip_prepare) /* skip the preparation work */ return 0; @@ -1588,8 +1590,12 @@ static int prepare_build_program_table_file(struct job_data *job, printf("Target device information\n"); disk_print_info(bis->info, job->target.source); } - if (misc_temp_dev(bis->info->device, 1, &bis->device)) - return -1; + for (i = 0; i < job_get_nr_targets(job); i++) { + if (misc_temp_dev(bis->info->basedisks[i], + 1, + &bis->basetmp[i])) + return -1; + } /* Check configuration number limits */ if (job->id == job_menu) { if (check_menu_positions(&job->data.menu, job->name, @@ -1704,9 +1710,9 @@ static int prepare_bootloader_ngdump(struct job_data *job, /* Retrieve target device information */ if (disk_get_info(job->data.dump.device, &job->target, &info)) return -1; - if (misc_temp_dev(info->device, 1, &bis->device)) + if (misc_temp_dev(info->device, 1, &bis->basetmp[0])) return -1; - if (check_dump_device(job, info, bis->device)) + if (check_dump_device(job, info, bis->basetmp[0])) return -1; assert(!job->target.bootmap_dir); @@ -1856,6 +1862,9 @@ void free_bootloader(struct install_set *bis) if (bis->tmp_filename_created) misc_free_temp_file(bis->filename); free(bis->filename); - misc_free_temp_dev(bis->device); + for (i = 0; i < MAX_TARGETS; i++) { + if (bis->basetmp[i]) + misc_free_temp_dev(bis->basetmp[i]); + } disk_free_info(bis->info); } diff --git a/zipl/src/disk.c b/zipl/src/disk.c index b4bd49ad..60fc8753 100644 --- a/zipl/src/disk.c +++ b/zipl/src/disk.c @@ -187,43 +187,134 @@ out_err: return rc; } +/** + * Process a script output represented by FH and consisting + * of pairs 'key=value' (each such pair is on a separate line). + * Check its consistency and set the extracted target parameters + * to the array of "targets" at TD. + * + * NOTE: this function defines specifications on valid output of + * zipl helper scripts. See zipl-support-for-mirrored-devices.txt + * for details. Before modifying this function, make sure that it + * won't lead to format change. + */ static int set_target_parameters(FILE *fh, struct job_target_data *td) { - int checkparm = 0; + int idx[LAST_TARGET_PARAM] = {0}; + struct target *t; char buffer[80]; char value[40]; + char *error; + int i; + /** + * Process a stream of 'key=value' pairs and distribute + * them into groups. + * The i-th occurrence of some "key" in the stream means + * that the respective pair belongs to the group #i + */ + error = "Exceeded the maximum number of base disks"; while (fgets(buffer, 80, fh)) { if (sscanf(buffer, "targetbase=%s", value) == 1) { - td->targetbase = misc_strdup(value); - checkparm++; + t = target_at(td, idx[TARGET_BASE]++); + if (!t) + goto error; + t->targetbase = misc_strdup(value); + goto found; } if (sscanf(buffer, "targettype=%s", value) == 1) { - type_from_target(value, &td->targettype); - checkparm++; + t = target_at(td, idx[TARGET_TYPE]++); + if (!t) + goto error; + type_from_target(value, &t->targettype); + goto found; } if (sscanf(buffer, "targetgeometry=%s", value) == 1) { - td->targetcylinders = - atoi(strtok(value, ",")); - td->targetheads = atoi(strtok(NULL, ",")); - td->targetsectors = atoi(strtok(NULL, ",")); - checkparm++; + t = target_at(td, idx[TARGET_GEOMETRY]++); + if (!t) + goto error; + t->targetcylinders = atoi(strtok(value, ",")); + t->targetheads = atoi(strtok(NULL, ",")); + t->targetsectors = atoi(strtok(NULL, ",")); + goto found; } if (sscanf(buffer, "targetblocksize=%s", value) == 1) { - td->targetblocksize = atoi(value); - checkparm++; + t = target_at(td, idx[TARGET_BLOCKSIZE]++); + if (!t) + goto error; + t->targetblocksize = atoi(value); + goto found; } if (sscanf(buffer, "targetoffset=%s", value) == 1) { - td->targetoffset = atol(value); - checkparm++; + t = target_at(td, idx[TARGET_OFFSET]++); + if (!t) + goto error; + t->targetoffset = atol(value); + goto found; } + continue; +found: + t->check_params++; } - if ((!disk_is_eckd(td->targettype) && checkparm < 4) || - (disk_is_eckd(td->targettype) && checkparm != 5)) { - error_reason("Target parameters missing from script"); - return -1; + /* Check for consistency */ + error = "Inconsistent script output"; + /* + * First, calculate total number of groups + */ + td->nr_targets = 0; + for (i = 0; i < MAX_TARGETS; i++) { + t = target_at(td, i); + if (t->check_params == 0) + break; + td->nr_targets++; + } + if (!td->nr_targets) + /* No keywords found in the stream */ + goto error; + /* + * Each group has to include targetbase, targettype, + * targetblocksize and targetoffset. + */ + if (td->nr_targets != idx[TARGET_BASE] || + td->nr_targets != idx[TARGET_TYPE] || + td->nr_targets != idx[TARGET_BLOCKSIZE] || + td->nr_targets != idx[TARGET_OFFSET]) + goto error; + /* + * In addition, any group of "ECKD" type has to include + * targetgeometry + */ + for (i = 0; i < td->nr_targets; i++) { + t = target_at(td, i); + assert(t->check_params >= 4); + if (disk_is_eckd(t->targettype) && t->check_params != 5) + goto error; } return 0; +error: + error_reason("%s", error); + return -1; +} + +static void print_base_disk_params(struct job_target_data *td, int index) +{ + disk_type_t type = get_targettype(td, index); + + if (!verbose) + return; + { + fprintf(stderr, "Base disk '%s':\n", get_targetbase(td, index)); + fprintf(stderr, " layout........: %s\n", disk_get_type_name(type)); + } + if (disk_is_eckd(type)) { + fprintf(stderr, " heads.........: %u\n", get_targetheads(td, index)); + fprintf(stderr, " sectors.......: %u\n", get_targetsectors(td, index)); + fprintf(stderr, " cylinders.....: %u\n", get_targetcylinders(td, index)); + } + { + fprintf(stderr, " start.........: %lu\n", get_targetoffset(td, index)); + fprintf(stderr, " blksize.......: %u\n", get_targetblocksize(td, index)); + } } /** @@ -235,31 +326,57 @@ static int disk_set_info_by_hint(struct job_target_data *td, { int majnum, minnum; struct stat stats; - + int i; + /* + * Currently multiple base disks with different parameters + * are not supported + */ data->devno = -1; - data->phy_block_size = td->targetblocksize; - data->type = td->targettype; - data->partnum = 0; + data->phy_block_size = get_targetblocksize(td, 0); + data->type = get_targettype(td, 0); - 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 { - if (stat(td->targetbase, &stats)) { - error_reason(strerror(errno)); - error_text("Could not get information for " - "file '%s'", td->targetbase); + assert(td->nr_targets != 0); + for (i = 1; i < td->nr_targets; i++) { + if (data->type != get_targettype(td, i) || + data->phy_block_size != get_targetblocksize(td, i)) { + print_base_disk_params(td, 0); + print_base_disk_params(td, i); + error_reason("Inconsistent base disk geometry in target device"); return -1; } - if (!S_ISBLK(stats.st_mode)) { - error_reason("Target base device '%s' is not " - "a block device", - td->targetbase); + } + data->partnum = 0; + data->targetbase_def = undefined; + + for (i = 0; i < td->nr_targets; i++) { + definition_t defined_as; + + if (sscanf(get_targetbase(td, i), + "%d:%d", &majnum, &minnum) == 2) { + data->basedisks[i] = makedev(majnum, minnum); + defined_as = defined_as_device; + } else { + if (stat(get_targetbase(td, i), &stats)) { + error_reason(strerror(errno)); + error_text("Could not get information for " + "file '%s'", get_targetbase(td, i)); + return -1; + } + if (!S_ISBLK(stats.st_mode)) { + error_reason("Target base device '%s' is not " + "a block device", + get_targetbase(td, i)); + return -1; + } + data->basedisks[i] = stats.st_rdev; + defined_as = defined_as_name; + } + if (data->targetbase_def != undefined && + data->targetbase_def != defined_as) { + error_reason("Target base disks are defined by different ways"); return -1; } - data->device = stats.st_rdev; - data->targetbase = defined_as_name; + data->targetbase_def = defined_as; } if (data->type == disk_type_scsi && ioctl(fd, NVME_IOCTL_ID) >= 0) data->is_nvme = 1; @@ -446,11 +563,28 @@ static int run_targetbase_script(struct job_target_data *td, 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; + int i; + /* + * Currently multiple base disks with different parameters + * are not supported + */ + data->geo.heads = get_targetheads(td, 0); + data->geo.sectors = get_targetsectors(td, 0); + data->geo.cylinders = get_targetcylinders(td, 0); + data->geo.start = get_targetoffset(td, 0); + assert(td->nr_targets != 0); + for (i = 1; i < td->nr_targets; i++) { + if (data->geo.heads != get_targetheads(td, i) || + data->geo.sectors != get_targetsectors(td, i) || + data->geo.cylinders != get_targetcylinders(td, i) || + data->geo.start != get_targetoffset(td, i)) { + print_base_disk_params(td, 0); + print_base_disk_params(td, i); + error_reason("Inconsistent base disk geometry in target device"); + return -1; + } + } return 0; } @@ -515,14 +649,16 @@ static int disk_set_info_complete(struct job_target_data *td, } /** - * Prepare INFO required to perform IPL installation on the physical - * disk where the logical DEVICE is located. + * Prepare INFO required to perform IPL installation on physical disks + * participating in the logical DEVICE. * 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. + * 1. Find out a set of physical "base" disks participating in the + * logical DEVICE. For each found disk calculate "target" parameters + * (type, geometry, physical block size, data offset, etc) and store + * it in the array of "targets" of TD; + * 2. Complete INFO using the found base disks and calculated target + * parameters. * * TD: optionally contains target parameters specified by user via * config file, or special "target options" of zipl tool. @@ -569,6 +705,7 @@ int disk_get_info(const char *device, struct job_target_data *td, goto error; if (disk_set_info_by_hint(td, data, fd)) goto error; + data->device = stats.st_rdev; break; case source_user: /* @@ -581,6 +718,12 @@ int disk_get_info(const char *device, struct job_target_data *td, goto error; if (disk_set_info_by_hint(td, data, fd)) goto error; + /* + * multiple base disks are not supported + * with this source type + */ + assert(td->nr_targets == 1); + data->device = data->basedisks[0]; break; case source_auto: /* no ready target parameters are available */ @@ -588,6 +731,12 @@ int disk_get_info(const char *device, struct job_target_data *td, goto error; if (disk_set_info_auto(data, &stats, fd)) goto error; + /* + * multiple base disks are not supported + * with this source type + */ + data->basedisks[0] = data->device; + td->nr_targets = 1; break; default: assert(0); @@ -943,6 +1092,33 @@ disk_print_devt(dev_t d) printf("%02x:%02x", major(d), minor(d)); } +void disk_print_devname(dev_t dev) +{ + struct util_proc_part_entry part_entry; + + if (!util_proc_part_get_entry(dev, &part_entry)) { + printf("%s", part_entry.name); + util_proc_part_free_entry(&part_entry); + } else { + disk_print_devt(dev); + } +} + +void prepare_footnote_ptr(int source, char *ptr) +{ + if (source == source_user || source == source_script) + strcpy(ptr, " *)"); + else + strcpy(ptr, ""); +} + +void print_footnote_ref(int source, const char *prefix) +{ + if (source == source_user) + printf("%s*) Data provided by user.\n", prefix); + else if (source == source_script) + printf("%s*) Data provided by script.\n", prefix); +} /* Return a name for a given disk TYPE. */ char * @@ -994,12 +1170,11 @@ disk_is_large_volume(struct disk_info* info) void disk_print_info(struct disk_info *info, int source) { char footnote[4] = ""; - if (source == source_user || source == source_script) - strcpy(footnote, " *)"); + prepare_footnote_ptr(source, footnote); printf(" Device..........................: "); disk_print_devt(info->device); - if (info->targetbase == defined_as_device) + if (info->targetbase_def == defined_as_device) printf("%s", footnote); printf("\n"); if (info->partnum != 0) { @@ -1010,7 +1185,7 @@ void disk_print_info(struct disk_info *info, int source) if (info->name) { printf(" Device name.....................: %s", info->name); - if (info->targetbase == defined_as_name) + if (info->targetbase_def == defined_as_name) printf("%s", footnote); printf("\n"); } @@ -1053,21 +1228,7 @@ void disk_print_info(struct disk_info *info, int source) info->phy_block_size, footnote); printf(" Device size in physical blocks..: %ld\n", (long) info->phy_blocks); - if (source == source_user) - printf(" *) Data provided by user.\n"); - if (source == source_script) - printf(" *) Data provided by script.\n"); -} - -/* Print textual representation of geo structure. */ -void -disk_print_geo(struct disk_info *data) -{ - printf(" geo.heads.........:%u\n", data->geo.heads); - printf(" geo.sectors.......:%u\n", data->geo.sectors); - printf(" geo.cylinders.....:%u\n", data->geo.cylinders); - printf(" geo.start.........:%lu\n", data->geo.start); - printf(" blksize...........:%u\n", data->phy_block_size); + print_footnote_ref(source, " "); } /* Check whether a block is a zero block which identifies a hole in a file. diff --git a/zipl/src/install.c b/zipl/src/install.c index 066b7ddf..e36e82ac 100644 --- a/zipl/src/install.c +++ b/zipl/src/install.c @@ -434,11 +434,14 @@ int install_bootloader(struct job_data *job, struct install_set *bis) { disk_blockptr_t *scsi_dump_sb_blockptr = &bis->scsi_dump_sb_blockptr; struct disk_info *info = bis->info; - char *device = bis->device; - int fd, rc; + char footnote[4]; + int rc; + int i; if (!info) return 0; + + prepare_footnote_ptr(job->target.source, footnote); /* Inform user about what we're up to */ printf("Preparing boot device for %s%s: ", disk_get_ipl_type(info->type, @@ -455,40 +458,58 @@ int install_bootloader(struct job_data *job, struct install_set *bis) disk_print_devt(info->device); printf(".\n"); } - /* Open device file */ - fd = open(device, O_RDWR); - if (fd == -1) { - error_reason(strerror(errno)); - error_text("Could not open temporary device file '%s'", - device); - return -1; - } - /* Ensure that potential cache inconsistencies between disk and - * partition are resolved by flushing the corresponding buffers. */ - if (!dry_run) { - if (ioctl(fd, BLKFLSBUF)) { - fprintf(stderr, "Warning: Could not flush disk " - "caches.\n"); - } - } - /* - * 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) - */ - if (job->id == job_dump_partition) { - rc = install_bootloader_dump(bis->tables, info, - scsi_dump_sb_blockptr, - is_ngdump_enabled(job), - fd); - } else { - rc = install_bootloader_ipl(bis->tables, info, fd); - } + /* Install independently on each physical target base */ - if (fsync(fd)) - error_text("Could not sync device file '%s'", device); - if (close(fd)) - error_text("Could not close device file '%s'", device); + for (i = 0; i < job_get_nr_targets(job); i++) { + int fd; + + if (verbose) { + printf("Installing on base disk: "); + disk_print_devname(info->basedisks[i]); + printf("%s.\n", footnote); + } + /* Open device file */ + fd = open(bis->basetmp[i], O_RDWR); + if (fd == -1) { + error_reason(strerror(errno)); + error_text("Could not open temporary device file '%s'", + bis->basetmp[i]); + return -1; + } + /* Ensure that potential cache inconsistencies between disk and + * partition are resolved by flushing the corresponding buffers. + */ + if (!dry_run) { + if (ioctl(fd, BLKFLSBUF)) { + fprintf(stderr, "Warning: Could not flush disk " + "caches.\n"); + } + } + /* + * 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) + */ + if (job->id == job_dump_partition) { + rc = install_bootloader_dump(bis->tables, info, + scsi_dump_sb_blockptr, + is_ngdump_enabled(job), + fd); + } else { + rc = install_bootloader_ipl(bis->tables, info, + fd); + } + if (fsync(fd)) + error_text("Could not sync device file '%s'", + bis->basetmp[i]); + if (close(fd)) + error_text("Could not close device file '%s'", + bis->basetmp[i]); + if (rc) + break; + } + if (verbose) + print_footnote_ref(job->target.source, ""); if (!dry_run && rc == 0) { if (info->devno >= 0) diff --git a/zipl/src/job.c b/zipl/src/job.c index 20664026..38035d41 100644 --- a/zipl/src/job.c +++ b/zipl/src/job.c @@ -369,11 +369,13 @@ get_command_line(int argc, char* argv[], struct command_line* line) return 0; } - void free_target_data(struct job_target_data *data) { + int i; + free(data->bootmap_dir); - free(data->targetbase); + for (i = 0; i < data->nr_targets; i++) + free(get_targetbase(data, i)); } static void @@ -1345,6 +1347,27 @@ type_from_target(char *target, disk_type_t *type) } } +int set_targettype(struct job_target_data *data, int index, char *value) +{ + return type_from_target(value, + &target_at(data, index)->targettype); +} + +int job_set_targettype(struct job_data *job, char *value) +{ + return set_targettype(&job->target, 0, value); +} + +static int job_set_target(struct job_data *job, char *value) +{ + job_set_targetbase(job, value); + if (!job_get_targetbase(job)) + return -1; + job_set_nr_targets(job, 1); + job->target.source = source_user; + return 0; +} + static int get_job_from_section_data(char* data[], struct job_data* job, char* section) { @@ -1361,32 +1384,28 @@ get_job_from_section_data(char* data[], struct job_data* job, char* section) return -1; /* Fill in target */ if (data[(int) scan_keyword_targetbase] != NULL) { - job->target.targetbase = - misc_strdup(data[(int) - scan_keyword_targetbase]); - if (job->target.targetbase == NULL) + if (job_set_target(job, misc_strdup(data[(int) + scan_keyword_targetbase]))) return -1; - job->target.source = source_user; } if (data[(int) scan_keyword_targettype] != NULL) { - if (type_from_target( - data[(int) scan_keyword_targettype], - &job->target.targettype)) + if (job_set_targettype(job, + data[(int) scan_keyword_targettype])) return -1; } if (data[(int) scan_keyword_targetgeometry] != NULL) { - job->target.targetcylinders = + job_set_targetcylinders(job, atoi(strtok(data[(int) - scan_keyword_targetgeometry], ",")); - job->target.targetheads = atoi(strtok(NULL, ",")); - job->target.targetsectors = atoi(strtok(NULL, ",")); + scan_keyword_targetgeometry], ","))); + job_set_targetheads(job, atoi(strtok(NULL, ","))); + job_set_targetsectors(job, atoi(strtok(NULL, ","))); } if (data[(int) scan_keyword_targetblocksize] != NULL) - job->target.targetblocksize = - atoi(data[(int) scan_keyword_targetblocksize]); + job_set_targetblocksize(job, + atoi(data[(int) scan_keyword_targetblocksize])); if (data[(int) scan_keyword_targetoffset] != NULL) - job->target.targetoffset = - atol(data[(int) scan_keyword_targetoffset]); + job_set_targetoffset(job, + atol(data[(int) scan_keyword_targetoffset])); /* Fill in name and address of image file */ job->data.ipl.common.image = misc_strdup( @@ -1614,37 +1633,32 @@ get_menu_job(struct scan_token* scan, char* menu, struct job_data* job) return -1; break; case scan_keyword_targetbase: - job->target.targetbase = misc_strdup( - scan[i].content.keyword.value); - if (job->target.targetbase == NULL) + if (job_set_target(job, misc_strdup( + scan[i].content.keyword.value))) return -1; - job->target.source = source_user; break; case scan_keyword_targettype: - if (type_from_target( - scan[i].content.keyword.value, - &job->target.targettype)) + if (job_set_targettype(job, + scan[i].content.keyword.value)) return -1; break; case scan_keyword_targetgeometry: - job->target.targetcylinders = + job_set_targetcylinders(job, atoi(strtok( scan[i].content.keyword.value, - ",")); - job->target.targetheads = - atoi(strtok(NULL, ",")); - job->target.targetsectors = - atoi(strtok(NULL, ",")); + ","))); + job_set_targetheads(job, + atoi(strtok(NULL, ","))); + job_set_targetsectors(job, + atoi(strtok(NULL, ","))); break; case scan_keyword_targetblocksize: - job->target.targetblocksize = - atoi( - scan[i].content.keyword.value); + job_set_targetblocksize(job, atoi( + scan[i].content.keyword.value)); break; case scan_keyword_targetoffset: - job->target.targetoffset = - atol( - scan[i].content.keyword.value); + job_set_targetoffset(job, atol( + scan[i].content.keyword.value)); break; default: /* Should not happen */