Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
openSUSE:Step:FrontRunner
s390-tools.19914
s390-tools-sles15sp2-dasdfmt-Fix-bad-file-descr...
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File s390-tools-sles15sp2-dasdfmt-Fix-bad-file-descriptor-error-when-running-o.patch of Package s390-tools.19914
From cb76e39cef7637bd53c4acd3182eae00fbc0d777 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20H=C3=B6ppner?= <hoeppner@linux.ibm.com> Date: Wed, 21 Oct 2020 17:24:01 +0200 Subject: [PATCH] dasdfmt: Fix bad file descriptor error when running on symlinks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When calling dasdfmt on device node symlinks like /dev/disk/by-id/ccw-0X9300, dasdfmt fails with "dasdfmt: the ioctl to get the blocksize of the device failed (Bad file descriptor)" This is because before the actual formatting process starts, the disk will be disabled calling the BIODASDDISABLE ioctl, resulting in the removal of the symlink. Trying to open this file later in the process to retrieve e.g. blocksize information results in the mentioned error, as the file doesn't exist any longer. This incorrect behaviour was introduced with commit 8826028bdce2 ("dasdfmt: Use libdasd provided ioctl functions") at which the use of a globally available file descriptor was omitted. Instead, the ioctl library functions require a device node to be passed as a function parameter and will open a file descriptor themselves. So, before that change, the global file descriptor was always valid even when the file was removed. In order to fix this without modifying the behaviour of libdasd, introduce the two global variables dev_node and dev_path. dev_path is the original device path entered by the user. dev_node on the other hand is the reliable device node under /dev/block/ using the major and minor numbers and is determined in get_device_name(). The dev_path is used for message output only and the dev_node variable is used for the actual disk operations. As these two variables are global, the device parameters for several functions are removed to make the code a bit cleaner. Fixes: 8826028bdce2 ("dasdfmt: Use libdasd provided ioctl functions") Reviewed-by: Stefan Haberland <sth@linux.ibm.com> Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com> --- dasdfmt/dasdfmt.c | 115 ++++++++++++++++++++++++---------------------- 1 file changed, 61 insertions(+), 54 deletions(-) diff --git a/dasdfmt/dasdfmt.c b/dasdfmt/dasdfmt.c index a14e99e..ef48c7a 100644 --- a/dasdfmt/dasdfmt.c +++ b/dasdfmt/dasdfmt.c @@ -15,6 +15,7 @@ #include "lib/dasd_base.h" #include "lib/dasd_sys.h" +#include "lib/util_libc.h" #include "lib/util_opt.h" #include "lib/util_prg.h" #include "lib/util_proc.h" @@ -28,7 +29,6 @@ #define SEC_PER_HOUR (60 * 60) static int filedes; -static char dev_filename[PATH_MAX]; static int disk_disabled; static format_data_t format_params; static format_mode_t mode; @@ -55,6 +55,8 @@ static const struct util_prg prg = { */ static struct dasdfmt_globals { dasd_information2_t dasd_info; + char *dev_path; /* device path entered by user */ + char *dev_node; /* reliable device node determined by dasdfmt */ int verbosity; int testmode; int withoutprompt; @@ -473,7 +475,7 @@ static void program_interrupt_signal(int sig) } printf("Rereading the partition table...\n"); - rc = dasd_reread_partition_table(dev_filename, 5); + rc = dasd_reread_partition_table(g.dev_node, 5); if (rc) { ERRMSG("%s: (signal handler) Re-reading partition table " "failed. (%s)\n", prog_name, strerror(rc)); @@ -486,12 +488,14 @@ static void program_interrupt_signal(int sig) } /* - * check given device name for blanks and some special characters + * Check given device name for blanks and some special characters. + * Retrieve reliable device node and store device information in global + * dev_node and dev_path accordingly. */ -static void get_device_name(char *devname, - int optind, int argc, char *argv[]) +static void get_device_name(int optind, int argc, char *argv[]) { struct util_proc_dev_entry dev_entry; + unsigned int maj, min; struct stat dev_stat; if (optind + 1 < argc) @@ -505,17 +509,19 @@ static void get_device_name(char *devname, if (strlen(argv[optind]) >= PATH_MAX) ERRMSG_EXIT(EXIT_MISUSE, "%s: device name too long!\n", prog_name); - strcpy(devname, argv[optind]); + util_asprintf(&g.dev_path, argv[optind]); - if (stat(devname, &dev_stat) != 0) + if (stat(g.dev_path, &dev_stat) != 0) ERRMSG_EXIT(EXIT_MISUSE, "%s: Could not get information for " - "device node %s: %s\n", prog_name, devname, + "device node %s: %s\n", prog_name, g.dev_path, strerror(errno)); - if (minor(dev_stat.st_rdev) & PARTN_MASK) { + maj = major(dev_stat.st_rdev); + min = minor(dev_stat.st_rdev); + if (min & PARTN_MASK) { ERRMSG_EXIT(EXIT_MISUSE, "%s: Unable to format partition %s. " "Please specify a device.\n", prog_name, - devname); + g.dev_path); } if (util_proc_dev_get_entry(dev_stat.st_rdev, 1, &dev_entry) == 0) { @@ -525,15 +531,17 @@ static void get_device_name(char *devname, prog_name, dev_entry.name); } else { printf("%s WARNING: Unable to get driver name for device node %s", - prog_name, devname); + prog_name, g.dev_path); } + /* Get reliable device node */ + util_asprintf(&g.dev_node, "/dev/block/%d:%d", maj, min); } -static void get_blocksize(const char *device, unsigned int *blksize) +static void get_blocksize(unsigned int *blksize) { int err; - err = dasd_get_blocksize(device, blksize); + err = dasd_get_blocksize(g.dev_node, blksize); if (err != 0) ERRMSG_EXIT(EXIT_FAILURE, "%s: the ioctl to get the blocksize " "of the device failed (%s).\n", prog_name, @@ -551,7 +559,7 @@ static void check_blocksize(unsigned int blksize) g.dasd_info.format == DASD_FORMAT_NONE) return; - get_blocksize(dev_filename, &dev_blksize); + get_blocksize(&dev_blksize); if (dev_blksize != blksize) { ERRMSG_EXIT(EXIT_FAILURE, "WARNING: Device is formatted with a " "different blocksize (%d).\nUse --mode=full to " @@ -591,12 +599,12 @@ static void check_layout(unsigned int intensity) /* * check for disk type and set some variables (e.g. usage count) */ -static void check_disk(char *devname) +static void check_disk(void) { int err; bool ro; - err = dasd_is_ro(devname, &ro); + err = dasd_is_ro(g.dev_node, &ro); if (err != 0) ERRMSG_EXIT(EXIT_FAILURE, "%s: the ioctl call to retrieve read/write " @@ -613,13 +621,13 @@ static void check_disk(char *devname) if (strncmp(g.dasd_info.type, "ECKD", 4) != 0) { ERRMSG_EXIT(EXIT_FAILURE, "%s: Unsupported disk type\n%s is not an " - "ECKD disk!\n", prog_name, devname); + "ECKD disk!\n", prog_name, g.dev_path); } - if (dasd_sys_raw_track_access(devname)) { + if (dasd_sys_raw_track_access(g.dev_node)) { ERRMSG_EXIT(EXIT_FAILURE, "%s: Device '%s' is in raw-track access mode\n", - prog_name, devname); + prog_name, g.dev_path); } } @@ -793,7 +801,7 @@ static format_check_t check_track_format(format_data_t *p) }; int err; - err = dasd_check_format(dev_filename, &cdata); + err = dasd_check_format(g.dev_node, &cdata); if (err != 0) { if (err == ENOTTY) { ERRMSG("%s: Missing kernel support for format checking", @@ -942,9 +950,8 @@ static format_data_t ask_user_for_blksize(format_data_t params) /* * print all information needed to format the device */ -static void dasdfmt_print_info(char *devname, volume_label_t *vlabel, - unsigned int cylinders, unsigned int heads, - format_data_t *p) +static void dasdfmt_print_info(volume_label_t *vlabel, unsigned int cylinders, + unsigned int heads, format_data_t *p) { char volser[6], vollbl[4]; @@ -954,7 +961,7 @@ static void dasdfmt_print_info(char *devname, volume_label_t *vlabel, printf("Device Type: %s Provisioned\n", g.ese ? "Thinly" : "Fully"); printf("\nI am going to format the device "); - printf("%s in the following way:\n", devname); + printf("%s in the following way:\n", g.dev_path); printf(" Device number of device : 0x%x\n", g.dasd_info.devno); printf(" Labelling device : %s\n", (g.writenolabel) ? "no" : "yes"); @@ -982,17 +989,17 @@ static void dasdfmt_print_info(char *devname, volume_label_t *vlabel, /* * get volser */ -static int dasdfmt_get_volser(char *devname, char *volser) +static int dasdfmt_get_volser(char *volser) { unsigned int blksize; volume_label_t vlabel; - get_blocksize(devname, &blksize); + get_blocksize(&blksize); if ((strncmp(g.dasd_info.type, "ECKD", 4) == 0) && !g.dasd_info.FBA_layout) { /* OS/390 and zOS compatible disk layout */ - vtoc_read_volume_label(devname, + vtoc_read_volume_label(g.dev_node, g.dasd_info.label_block * blksize, &vlabel); vtoc_volume_label_get_volser(&vlabel, volser); @@ -1021,14 +1028,14 @@ static void dasdfmt_write_labels(volume_label_t *vlabel, if (g.verbosity > 0) printf("Retrieving dasd information... "); - get_blocksize(dev_filename, &blksize); + get_blocksize(&blksize); /* * Don't rely on the cylinders returned by HDIO_GETGEO, they might be * to small. geo is only used to get the number of sectors, which may * vary depending on the format. */ - rc = dasd_get_geo(dev_filename, &geo); + rc = dasd_get_geo(g.dev_node, &geo); if (rc != 0) ERRMSG_EXIT(EXIT_FAILURE, "%s: (write labels) IOCTL " "HDIO_GETGEO failed (%s).\n", @@ -1058,10 +1065,10 @@ static void dasdfmt_write_labels(volume_label_t *vlabel, ipl2_record_len = sizeof(ipl2.data); } - fd = open(dev_filename, O_RDWR); + fd = open(g.dev_node, O_RDWR); if (fd < 0) ERRMSG_EXIT(EXIT_FAILURE, "%s: Unable to open device " - "'%s' (%s)\n", prog_name, dev_filename, + "'%s' (%s)\n", prog_name, g.dev_path, strerror(errno)); if (lseek(fd, 0, SEEK_SET) != 0) { @@ -1272,7 +1279,7 @@ static void dasdfmt_release_space(void) return; printf("Releasing space for the entire device...\n"); - err = dasd_release_space(dev_filename, &r); + err = dasd_release_space(g.dev_node, &r); if (err) { ERRMSG_EXIT(EXIT_FAILURE, "%s: Could not release space (%s)\n", prog_name, strerror(err)); @@ -1298,7 +1305,7 @@ static void dasdfmt_prepare_and_format(unsigned int cylinders, unsigned int head if (g.verbosity > 0) printf("Detaching the device...\n"); - disk_disable(dev_filename); + disk_disable(g.dev_node); if (g.verbosity > 0) printf("Invalidate first track...\n"); @@ -1347,7 +1354,7 @@ static void dasdfmt_expand_format(unsigned int cylinders, unsigned int heads, if (g.verbosity > 0) printf("Detaching the device...\n"); - disk_disable(dev_filename); + disk_disable(g.dev_node); process_tracks(cylinders, heads, p); @@ -1402,7 +1409,7 @@ static void dasdfmt_quick_format(unsigned int cylinders, unsigned int heads, printf("Formatting the first two tracks of the device.\n"); /* Disable the device before we do anything */ - disk_disable(dev_filename); + disk_disable(g.dev_node); /* Now do the actual formatting of our first two tracks */ err = dasd_format_disk(filedes, p); @@ -1414,10 +1421,8 @@ static void dasdfmt_quick_format(unsigned int cylinders, unsigned int heads, disk_enable(); } -static void do_format_dasd(char *devname, - volume_label_t *vlabel, - format_data_t *p, unsigned int cylinders, - unsigned int heads) +static void do_format_dasd(volume_label_t *vlabel, format_data_t *p, + unsigned int cylinders, unsigned int heads) { char inp_buffer[5]; int count, err; @@ -1438,19 +1443,19 @@ static void do_format_dasd(char *devname, } if (g.verbosity > 0 || !g.withoutprompt || g.testmode) - dasdfmt_print_info(devname, vlabel, cylinders, heads, p); + dasdfmt_print_info(vlabel, cylinders, heads, p); - count = dasd_get_host_access_count(devname); + count = dasd_get_host_access_count(g.dev_node); if (g.force_host) { if (count > 1) { ERRMSG_EXIT(EXIT_FAILURE, "\n%s: Disk %s is online on OS instances in %d different LPARs.\n" "Note: Your installation might include z/VM systems that are configured to\n" "automatically vary on disks, regardless of whether they are subsequently used.\n\n", - prog_name, devname, count); + prog_name, g.dev_path, count); } else if (count < 0) { ERRMSG("\nHosts access information not available for disk %s.\n\n", - devname); + g.dev_path); return; } } else if (count > 1) @@ -1459,7 +1464,7 @@ static void do_format_dasd(char *devname, "Ensure that the disk is not being used by a system outside your LPAR.\n" "Note: Your installation might include z/VM systems that are configured to\n" "automatically vary on disks, regardless of whether they are subsequently used.\n", - devname, count); + g.dev_path, count); if (!g.testmode) { if (!g.withoutprompt) { @@ -1498,7 +1503,7 @@ static void do_format_dasd(char *devname, dasdfmt_write_labels(vlabel, cylinders, heads); printf("Rereading the partition table... "); - err = dasd_reread_partition_table(dev_filename, 5); + err = dasd_reread_partition_table(g.dev_node, 5); if (err != 0) { ERRMSG("%s: error during rereading the partition " "table: %s.\n", prog_name, strerror(err)); @@ -1696,22 +1701,22 @@ int main(int argc, char *argv[]) if (g.print_hashmarks) PARSE_PARAM_INTO(g.hashstep, hashstep_str, 10, "hashstep"); - get_device_name(dev_filename, optind, argc, argv); + get_device_name(optind, argc, argv); - rc = dasd_get_info(dev_filename, &g.dasd_info); + rc = dasd_get_info(g.dev_node, &g.dasd_info); if (rc != 0) ERRMSG_EXIT(EXIT_FAILURE, "%s: the ioctl call to retrieve " "device information failed (%s).\n", prog_name, strerror(rc)); - g.ese = dasd_sys_ese(dev_filename); + g.ese = dasd_sys_ese(g.dev_node); eval_format_mode(); /* Either let the user specify the blksize or get it from the kernel */ if (!g.blksize_specified) { if (!(mode == FULL || g.dasd_info.format == DASD_FORMAT_NONE) || g.check) - get_blocksize(dev_filename, &format_params.blksize); + get_blocksize(&format_params.blksize); else format_params = ask_user_for_blksize(format_params); } @@ -1727,15 +1732,15 @@ int main(int argc, char *argv[]) exit(1); } - if (dasdfmt_get_volser(dev_filename, old_volser) == 0) + if (dasdfmt_get_volser(old_volser) == 0) vtoc_volume_label_set_volser(&vlabel, old_volser); else ERRMSG_EXIT(EXIT_FAILURE, "%s: VOLSER not found on device %s\n", - prog_name, dev_filename); + prog_name, g.dev_path); } - check_disk(dev_filename); + check_disk(); if (check_param(str, ERR_LENGTH, &format_params) < 0) ERRMSG_EXIT(EXIT_MISUSE, "%s: %s\n", prog_name, str); @@ -1746,8 +1751,10 @@ int main(int argc, char *argv[]) if (g.check) check_disk_format(cylinders, heads, &format_params); else - do_format_dasd(dev_filename, &vlabel, &format_params, - cylinders, heads); + do_format_dasd(&vlabel, &format_params, cylinders, heads); + + free(g.dev_path); + free(g.dev_node); return 0; } -- 2.26.2
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor