diff --git a/zipl/include/disk.h b/zipl/include/disk.h index ac270692..fa562428 100644 --- a/zipl/include/disk.h +++ b/zipl/include/disk.h @@ -19,6 +19,8 @@ #include "zipl.h" #include "lib/vtoc.h" +#define FS_MAP_ERROR "Could not get file mapping" + /* Type for representing disk block numbers */ typedef uint64_t blocknum_t; @@ -102,6 +104,7 @@ int disk_type_is_eckd_ldl(struct disk_ext_type *ext_type); int disk_type_is_nvme(struct disk_ext_type *ext_type); int disk_type_is_eckd(disk_type_t type); +int disk_info_set_fs_block(const char *filename, struct disk_info *info); int disk_get_info_from_file(const char* filename, struct job_target_data* target, struct disk_info** info); diff --git a/zipl/include/error.h b/zipl/include/error.h index c008d810..adca93be 100644 --- a/zipl/include/error.h +++ b/zipl/include/error.h @@ -20,5 +20,6 @@ void error_text(const char* fmt, ...); void error_clear_reason(void); void error_clear_text(void); void error_print(void); +int is_error(const char *this); #endif /* not ERROR_H */ diff --git a/zipl/include/job.h b/zipl/include/job.h index 001d6b2f..5d9d2f72 100644 --- a/zipl/include/job.h +++ b/zipl/include/job.h @@ -261,5 +261,6 @@ int check_job_images_ngdump(struct job_dump_data* dump, char* name); void job_dump_check_set_ngdump(struct job_data *job, struct disk_ext_type *ext_type); bool job_dump_is_ngdump(struct job_data *job); +void ngdump_delete_meta(const char *path); #endif /* not JOB_H */ diff --git a/zipl/include/misc.h b/zipl/include/misc.h index 61148fcf..572dd1b8 100644 --- a/zipl/include/misc.h +++ b/zipl/include/misc.h @@ -33,8 +33,6 @@ void* misc_malloc(size_t size); int misc_asprintf(char **out, const char *fmt, ...); void* misc_calloc(size_t n, size_t size); char* misc_strdup(const char* s); -int misc_open_exclusive(const char* filename); -int misc_open_simulate(const char *filename, struct misc_fd *mfd); int misc_open_device(const char *filename, struct misc_fd *mfd, int simulate); int misc_read(int fd, void* buffer, size_t count); int misc_read_file(const char* filename, char** buffer, size_t* size, @@ -49,7 +47,7 @@ int misc_get_file_buffer(const char* filename, struct misc_file_buffer* buffer); void misc_free_file_buffer(struct misc_file_buffer* file); int misc_get_char(struct misc_file_buffer* file, off_t readahead); -char* misc_make_path(char* dirname, char* filename); +char *misc_make_path(const char *dirname, char *filename); int misc_temp_dev(dev_t dev, int blockdev, char** devno); int misc_temp_dev_from_file(char* file, char** devno); void misc_free_temp_dev(char* device); diff --git a/zipl/include/zipl.h b/zipl/include/zipl.h index cd71e9dd..65e18354 100644 --- a/zipl/include/zipl.h +++ b/zipl/include/zipl.h @@ -25,7 +25,9 @@ #define BOOTMAP_FILENAME "bootmap" #define BOOTMAP_TEMPLATE_FILENAME "bootmap_temp.XXXXXX" +#define DUMP_TEMP_MOUNT_POINT_DIR "/tmp" #define DUMP_TEMP_MOUNT_POINT_NAME "zipl-dump-mount-point-XXXXXX" +#define DUMP_META_FILE_NAME "ngdump.meta" #define DEFAULTBOOT_SECTION "defaultboot" diff --git a/zipl/man/zipl.8.in b/zipl/man/zipl.8.in index 472617dd..38f23032 100644 --- a/zipl/man/zipl.8.in +++ b/zipl/man/zipl.8.in @@ -366,6 +366,13 @@ error-checking is still done. Note that when working with tapes, the current device position will be changed even when specifying this option. +When working with ngdumps, the directory specified by the shell environment +variable TMPDIR is used for simulating the dump job. This directory should +belong to a "real" file system managing disk space addresses (like ext4, or +xfs), and have enough free space (matching the size of the specified dump +device). If TMPDIR is not set, then "/tmp" is used, which can lead to errors, +e.g. in case when it belongs to tmpfs. + .TP .BR "\-f" " or " "\-\-force" Omit validity checking while producing a multi-volume dump. diff --git a/zipl/src/bootmap.c b/zipl/src/bootmap.c index 56eb02cd..ed3834b7 100644 --- a/zipl/src/bootmap.c +++ b/zipl/src/bootmap.c @@ -1542,11 +1542,39 @@ static int prepare_build_program_table_file(struct job_data *job, return -1; } bis->tmp_filename_created = 1; - /* Retrieve target device information. Note that we have to - * call disk_get_info_from_file() to also get the file system - * block size. */ - if (disk_get_info_from_file(bis->filename, &job->target, &bis->info)) - return -1; + /* + * Retrieve target device information and + * complete the info with the file system block size + */ + if (job->id == job_dump_partition && dry_run) { + /* + * ngdump job in dry-run mode. + * + * The dump device has read-only status. + * The bootmap and the meta-file to be created + * directly at the temporary mount point wthout + * mounting anything to it (thus, the mentioned + * files to be actually created in the "proxy" + * file system. + * + * Retrieve info from the dump device + * Retrieve file system block size from the proxy + * file system + */ + if (disk_get_info(job->data.dump.device, + &job->target, &bis->info)) + return -1; + if (disk_info_set_fs_block(bis->filename, bis->info)) + return -1; + } else { + /* + * ngdump or ipl job. + */ + if (disk_get_info_from_file(bis->filename, + &job->target, + &bis->info)) + return -1; + } if (!disk_is_appropriate(job, bis->info)) return -1; if (verbose) { @@ -1627,8 +1655,17 @@ static int bootmap_create_file(struct job_data *job, struct install_set *bis, return 0; } +void ngdump_delete_meta(const char *dir) +{ + char *filename = NULL; + + filename = misc_make_path(dir, DUMP_META_FILE_NAME); + unlink(filename); + free(filename); +} + /** - * Create a file with the short name "ngdump.meta" in the directory PATH. + * Create a file with the short name DUMP_META_FILE_NAME in the directory PATH. * This file is required for NGDump stand-alone dumper, it's read/written * by the dumper when it starts. */ @@ -1638,13 +1675,13 @@ static int ngdump_create_meta(const char *path) FILE *fp; int rc; - util_asprintf(&filename, "%s/ngdump.meta", path); + filename = misc_make_path(path, DUMP_META_FILE_NAME); fp = fopen(filename, "w"); if (!fp) { - free(filename); error_reason(strerror(errno)); error_text("Could not create file '%s'", filename); + free(filename); return -1; } free(filename); @@ -1665,6 +1702,40 @@ static int ngdump_create_meta(const char *path) return 0; } +static int ngdump_mount_device(struct job_data *job) +{ + if (dry_run) + /* + * the bootmap and the meta-file to be stored + * directly at the temporary mount point without + * mounting any partition + */ + return 0; + /* + * the bootmap and the meta-file to be stored on the + * formatted and mounted dump partition + */ + if (mount(job->data.dump.device, job->target.bootmap_dir, + NGDUMP_FSTYPE, 0, NULL)) { + error_reason(strerror(errno)); + error_text("Could not mount partition '%s':", + job->data.dump.device); + return -1; + } + job->dump_mounted = 1; + return 0; +} + +static char *ngdump_dir(void) +{ + return getenv("TMPDIR") ? : DUMP_TEMP_MOUNT_POINT_DIR; +} + +static char *build_mount_point_pathname(void) +{ + return misc_make_path(ngdump_dir(), DUMP_TEMP_MOUNT_POINT_NAME); +} + static int prepare_bootloader_ngdump(struct job_data *job, struct install_set *bis) { @@ -1679,8 +1750,7 @@ static int prepare_bootloader_ngdump(struct job_data *job, return -1; assert(!job->target.bootmap_dir); - job->target.bootmap_dir = misc_make_path("/tmp", - DUMP_TEMP_MOUNT_POINT_NAME); + job->target.bootmap_dir = build_mount_point_pathname(); if (!job->target.bootmap_dir) { error_reason(strerror(errno)); error_text("Could not make path for '%s'", @@ -1695,25 +1765,20 @@ static int prepare_bootloader_ngdump(struct job_data *job, return -1; } job->bootmap_dir_created = 1; - /* - * Mount partition where bootmap file and also a dump file will - * be stored. - */ - if (mount(job->data.dump.device, job->target.bootmap_dir, - NGDUMP_FSTYPE, 0, NULL)) { - error_reason(strerror(errno)); - error_text("Could not mount partition '%s':", - job->data.dump.device); + if (ngdump_mount_device(job)) return -1; - } - job->dump_mounted = 1; /* * Build a single program table for List-Directed IPL * See comments before install_bootloader() for details */ bis->print_details = 1; - if (bootmap_create_file(job, bis, BLKPTR_FORMAT_ID)) + if (bootmap_create_file(job, bis, BLKPTR_FORMAT_ID)) { + if (dry_run && is_error(FS_MAP_ERROR)) + fprintf(stderr, + "'%s' doesn't satisfy the requirements. Set TMPDIR properly\n", + ngdump_dir()); return -1; + } return ngdump_create_meta(job->target.bootmap_dir); } diff --git a/zipl/src/disk.c b/zipl/src/disk.c index bb72fdab..a9318463 100644 --- a/zipl/src/disk.c +++ b/zipl/src/disk.c @@ -811,20 +811,15 @@ int disk_type_is_eckd(disk_type_t type) type == disk_type_eckd_cdl); } -int -disk_get_info_from_file(const char* filename, struct job_target_data* target, - struct disk_info** info) +/** + * Retrieve and set block size of the file system which contains FILENAME + */ +int disk_info_set_fs_block(const char *filename, struct disk_info *info) { - struct stat stats; - char* device; int blocksize; int fd; int rc; - if (stat(filename, &stats)) { - error_reason(strerror(errno)); - return -1; - } /* Retrieve file system block size */ fd = open(filename, O_RDONLY); if (fd == -1) { @@ -838,17 +833,33 @@ disk_get_info_from_file(const char* filename, struct job_target_data* target, filename); return -1; } - /* Create temporary device file */ - rc = misc_temp_dev(stats.st_dev, 1, &device); - if (rc) + info->fs_block_size = blocksize; + return 0; +} + +/** + * Retrieve disk info of the device which contains FILENAME + * and set the filesystem block size + */ +int disk_get_info_from_file(const char *filename, + struct job_target_data *target, + struct disk_info **info) +{ + struct stat stats; + char *device; + + if (stat(filename, &stats)) { + error_reason(strerror(errno)); return -1; - /* Get device info */ - rc = disk_get_info(device, target, info); - if (rc == 0) - (*info)->fs_block_size = blocksize; - /* Clean up */ + } + if (misc_temp_dev(stats.st_dev, 1, &device)) + return -1; + if (disk_get_info(device, target, info)) { + misc_free_temp_dev(device); + return -1; + } misc_free_temp_dev(device); - return rc; + return disk_info_set_fs_block(filename, *info); } void disk_free_info(struct disk_info *info) diff --git a/zipl/src/error.c b/zipl/src/error.c index 7638b483..2532f862 100644 --- a/zipl/src/error.c +++ b/zipl/src/error.c @@ -82,3 +82,8 @@ error_print(void) else fprintf(stderr, "Error: An unspecified error occurred\n"); } + +int is_error(const char *this) +{ + return strcmp(error_reason_string, this) == 0; +} diff --git a/zipl/src/fs-map.c b/zipl/src/fs-map.c index e2a418e1..21c505c0 100644 --- a/zipl/src/fs-map.c +++ b/zipl/src/fs-map.c @@ -96,7 +96,7 @@ int fs_map(int fd, uint64_t offset, blocknum_t *mapped, /* FIEMAP failed, fall back to FIBMAP */ block = offset / fs_block_size; if (ioctl(fd, FIBMAP, &block)) { - error_reason("Could not get file mapping"); + error_reason(FS_MAP_ERROR); free(fiemap); return -1; } diff --git a/zipl/src/install.c b/zipl/src/install.c index 148175e3..c88f0ddd 100644 --- a/zipl/src/install.c +++ b/zipl/src/install.c @@ -1119,8 +1119,9 @@ install_dump(const char *device, struct job_target_data *target, uint64_t mem, stage2dump_parms.mem_upper_limit = mem; stage2dump_parms.no_compress = no_compress; - mfd.fd = misc_open_exclusive(device); - if (mfd.fd == -1) { + + /* Check if @device is a tape device */ + if (misc_open_device(device, &mfd, 0) == -1) { error_text("Could not open dump device '%s'", device); return -1; } diff --git a/zipl/src/job.c b/zipl/src/job.c index 9268a92c..32cd3f54 100644 --- a/zipl/src/job.c +++ b/zipl/src/job.c @@ -459,17 +459,24 @@ free_mvdump_data(struct job_mvdump_data* data) free(data->device[i]); } - -void -job_free(struct job_data* job) +void job_free(struct job_data *job) { - - if (job->dump_mounted && umount(job->target.bootmap_dir)) - fprintf(stderr, "Could not umount dump device at %s", - job->target.bootmap_dir); - if (job->bootmap_dir_created && rmdir(job->target.bootmap_dir)) - fprintf(stderr, "Could not remove directory %s", - job->target.bootmap_dir); + if (job->dump_mounted && umount(job->target.bootmap_dir)) { + fprintf(stderr, + "Could not umount dump device at %s(%s)\n", + job->target.bootmap_dir, + strerror(errno)); + } + if (job->bootmap_dir_created) { + /* remove the meta-file created in dry-run mode */ + ngdump_delete_meta(job->target.bootmap_dir); + if (rmdir(job->target.bootmap_dir)) { + fprintf(stderr, + "Could not remove directory %s(%s)\n", + job->target.bootmap_dir, + strerror(errno)); + } + } free_target_data(&job->target); free_envblk_data(&job->envblk); free(job->name); diff --git a/zipl/src/misc.c b/zipl/src/misc.c index 750fae50..236f55af 100644 --- a/zipl/src/misc.c +++ b/zipl/src/misc.c @@ -88,8 +88,7 @@ misc_strdup(const char* s) /* Open file exclusive */ -int -misc_open_exclusive(const char* filename) +static int misc_open_exclusive(const char *filename) { int fd; @@ -104,7 +103,7 @@ misc_open_exclusive(const char* filename) /** * Open file FILENAME for write simulation */ -int misc_open_simulate(const char *filename, struct misc_fd *mfd) +static int misc_open_simulate(const char *filename, struct misc_fd *mfd) { /* * In write simulation mode actual data are not written to the file, @@ -301,7 +300,7 @@ misc_get_char(struct misc_file_buffer* file, off_t readahead) char* -misc_make_path(char* dirname, char* filename) +misc_make_path(const char *dirname, char *filename) { char* result; size_t len;