From d6582bbaf0f3986a42f562046dc0caa9de89c75e Mon Sep 17 00:00:00 2001
From: Hannes Reinecke <hare@suse.de>
Date: Fri, 6 Oct 2017 08:58:17 +0200
Subject: [PATCH] dasdfmt: Allow multiple device arguments

Allow the user to specify several devices as arguments to dasdfmt.

Signed-off-by: Hannes Reinecke <hare@suse.com>
---
 dasdfmt/dasdfmt.8 |   5 +-
 dasdfmt/dasdfmt.c | 175 ++++++++++++++++++++++++++++++------------------------
 2 files changed, 100 insertions(+), 80 deletions(-)

diff --git a/dasdfmt/dasdfmt.8 b/dasdfmt/dasdfmt.8
index 99da9ed..e7fc501 100644
--- a/dasdfmt/dasdfmt.8
+++ b/dasdfmt/dasdfmt.8
@@ -11,14 +11,15 @@ dasdfmt \- formatting of DASD (ECKD) disk drives.
 .br
         [-r \fIcylinder\fR] [-b \fIblksize\fR] [-l \fIvolser\fR] [-d \fIlayout\fR]
 .br
-        [-L] [-V] [-F] [-k] [-C] [-M \fImode\fR] \fIdevice\fR
+        [-L] [-V] [-F] [-k] [-C] [-M \fImode\fR] \fIdevice\fR [\fIdevice\fR]
 
 .SH DESCRIPTION
-\fBdasdfmt\fR formats a DASD (ECKD) disk drive to prepare it
+\fBdasdfmt\fR formats one or several DASD (ECKD) disk drive to prepare it
 for usage with Linux for S/390. 
 The \fIdevice\fR is the node of the device (e.g. '/dev/dasda').
 Any device node created by udev for kernel 2.6 can be used 
 (e.g. '/dev/dasd/0.0.b100/disc').
+It is possible to specify up to 512 devices.
 .br
 
 \fBWARNING\fR: Careless usage of \fBdasdfmt\fR can result in 
diff --git a/dasdfmt/dasdfmt.c b/dasdfmt/dasdfmt.c
index b79cff0..607fd1c 100644
--- a/dasdfmt/dasdfmt.c
+++ b/dasdfmt/dasdfmt.c
@@ -23,6 +23,7 @@
 
 #include "dasdfmt.h"
 
+#define MAX_DEVICES 512
 #define BUSIDSIZE  8
 #define SEC_PER_DAY (60 * 60 * 24)
 #define SEC_PER_HOUR (60 * 60)
@@ -463,44 +464,40 @@ static void program_interrupt_signal(int sig)
 /*
  * check given device name for blanks and some special characters
  */
-static void get_device_name(char *devname,
-			    int optind, int argc, char *argv[])
+static void get_device_name(char **devname, int numdev,
+			    char argv[])
 {
 	struct util_proc_dev_entry dev_entry;
 	struct stat dev_stat;
 
-	if (optind + 1 < argc)
-		ERRMSG_EXIT(EXIT_MISUSE,
-			    "%s: More than one device specified!\n", prog_name);
-
-	if (optind >= argc)
-		ERRMSG_EXIT(EXIT_MISUSE, "%s: No device specified!\n",
-			    prog_name);
-
-	if (strlen(argv[optind]) >= PATH_MAX)
+	if (strlen(argv) >= PATH_MAX)
 		ERRMSG_EXIT(EXIT_MISUSE, "%s: device name too long!\n",
 			    prog_name);
-	strcpy(devname, argv[optind]);
 
-	if (stat(devname, &dev_stat) != 0)
-		ERRMSG_EXIT(EXIT_MISUSE, "%s: Could not get information for "
-			    "device node %s: %s\n", prog_name, devname,
-			    strerror(errno));
+	devname[numdev] = argv;
+	if (stat(devname[numdev], &dev_stat) != 0)
+		ERRMSG_EXIT(EXIT_MISUSE,
+			    "%s: Could not get information for "
+			    "device node %s: %s\n", prog_name,
+			    devname[numdev], strerror(errno));
 
 	if (minor(dev_stat.st_rdev) & PARTN_MASK) {
-		ERRMSG_EXIT(EXIT_MISUSE, "%s: Unable to format partition %s. "
+		ERRMSG_EXIT(EXIT_MISUSE,
+			    "%s: Unable to format partition %s. "
 			    "Please specify a device.\n", prog_name,
-			    devname);
+			    devname[numdev]);
 	}
 
-	if (util_proc_dev_get_entry(dev_stat.st_rdev, 1, &dev_entry) == 0) {
+	if (util_proc_dev_get_entry(dev_stat.st_rdev, 1,
+				    &dev_entry) == 0) {
 		if (strncmp(dev_entry.name, "dasd", 4) != 0)
 			ERRMSG_EXIT(EXIT_MISUSE,
 				    "%s: Unsupported device type '%s'.\n",
 				    prog_name, dev_entry.name);
 	} else {
-		printf("%s WARNING: Unable to get driver name for device node %s",
-		       prog_name, devname);
+		printf("%s WARNING: Unable to get driver name"
+		       " for device node %s",
+		       prog_name, devname[numdev]);
 	}
 }
 
@@ -518,7 +515,7 @@ static void get_blocksize(const char *de
 /*
  * Check whether a specified blocksize matches the blocksize of the device
  */
-static void check_blocksize(dasdfmt_info_t *info, unsigned int blksize)
+static void check_blocksize(dasdfmt_info_t *info, char *dev_filename, unsigned int blksize)
 {
 	unsigned int dev_blksize;
 
@@ -756,7 +753,7 @@ static void check_hashmarks(dasdfmt_info
  * This function checks whether a range of tracks is in regular format
  * with the specified block size.
  */
-static format_check_t check_track_format(dasdfmt_info_t *info, format_data_t *p)
+static format_check_t check_track_format(dasdfmt_info_t *info, char *dev_filename, format_data_t *p)
 {
 	format_check_t cdata = {
 		.expect = {
@@ -812,7 +809,7 @@ static int process_tracks(dasdfmt_info_t
 			step.stop_unit = cur_trk + step_value - 1;
 
 		if (info->check) {
-			cdata = check_track_format(info, &step);
+			cdata = check_track_format(info, dev_filename, &step);
 			if (cdata.result) {
 				cyl = cur_trk / heads + 1;
 				draw_progress(info, cyl, cylinders, 1);
@@ -858,7 +855,7 @@ static void check_disk_format(dasdfmt_in
 		return;
 	}
 
-	check_blocksize(info, check_params->blksize);
+	check_blocksize(info, dev_filename, check_params->blksize);
 	check_layout(info, check_params->intensity);
 
 	/*
@@ -1188,7 +1185,7 @@ static void dasdfmt_write_labels(dasdfmt
  * that the device is formatted to a certain extent. Otherwise the
  * process is terminated.
  */
-static void dasdfmt_find_start(dasdfmt_info_t *info, unsigned int cylinders,
+static void dasdfmt_find_start(dasdfmt_info_t *info, char *dev_filename, unsigned int cylinders,
 			       unsigned heads, format_data_t *format_params)
 {
 	format_check_t cdata;
@@ -1197,11 +1194,11 @@ static void dasdfmt_find_start(dasdfmt_i
 	unsigned int right = (cylinders * heads) - 1;
 	unsigned int first = left;
 
-	check_blocksize(info, format_params->blksize);
+	check_blocksize(info, dev_filename, format_params->blksize);
 
 	format_params->start_unit = 0;
 	format_params->stop_unit = 4;
-	cdata = check_track_format(info, format_params);
+	cdata = check_track_format(info, dev_filename, format_params);
 
 	if (cdata.result) {
 		evaluate_format_error(info, &cdata, heads);
@@ -1217,7 +1214,7 @@ static void dasdfmt_find_start(dasdfmt_i
 
 		format_params->start_unit = middle;
 		format_params->stop_unit = middle;
-		cdata = check_track_format(info, format_params);
+		cdata = check_track_format(info, dev_filename, format_params);
 		if (cdata.blksize != format_params->blksize) {
 			first = middle;
 			right = middle - 1;
@@ -1266,6 +1263,7 @@ static void dasdfmt_release_space(dasdfm
 }
 
 static void dasdfmt_prepare_and_format(dasdfmt_info_t *info,
+				       char *dev_filename,
 				       unsigned int cylinders,
 				       unsigned int heads, format_data_t *p)
 {
@@ -1324,7 +1322,7 @@ static void dasdfmt_prepare_and_format(d
 /*
  * This function will start the expand format process.
  */
-static void dasdfmt_expand_format(dasdfmt_info_t *info, unsigned int cylinders,
+static void dasdfmt_expand_format(dasdfmt_info_t *info, char *dev_filename, unsigned int cylinders,
 				  unsigned int heads, format_data_t *p)
 {
 	if (!(info->withoutprompt && (info->verbosity < 1)))
@@ -1351,7 +1349,7 @@ static void dasdfmt_expand_format(dasdfm
  * This function will only format the first two tracks of a DASD.
  * The rest of the DASD is untouched and left as is.
  */
-static void dasdfmt_quick_format(dasdfmt_info_t *info, unsigned int cylinders,
+static void dasdfmt_quick_format(dasdfmt_info_t *info, char *dev_filename, unsigned int cylinders,
 				 unsigned int heads, format_data_t *p)
 {
 	format_check_t cdata = { .expect = {0}, 0 };
@@ -1363,18 +1361,18 @@ static void dasdfmt_quick_format(dasdfmt
 	} else if (info->ese) {
 		printf("Skipping format check due to thin-provisioned device.\n");
 	} else {
-		check_blocksize(info, p->blksize);
+		check_blocksize(info, dev_filename, p->blksize);
 
 		printf("Checking the format of selected tracks...\n");
 
 		/* Check device format on the first and last 3 regular tracks */
 		tmp.start_unit = 2;
 		tmp.stop_unit = 4;
-		cdata = check_track_format(info, &tmp);
+		cdata = check_track_format(info, dev_filename, &tmp);
 		if (!cdata.result) {
 			tmp.start_unit = (cylinders * heads) - 3;
 			tmp.stop_unit = (cylinders * heads) - 1;
-			cdata = check_track_format(info, &tmp);
+			cdata = check_track_format(info, dev_filename, &tmp);
 		}
 		if (cdata.result) {
 			evaluate_format_error(info, &cdata, heads);
@@ -1419,7 +1417,7 @@ static void do_format_dasd(dasdfmt_info_
 		p->stop_unit = 1;
 		break;
 	case EXPAND: /* only the end of the disk */
-		dasdfmt_find_start(info, cylinders, heads, p);
+		dasdfmt_find_start(info, devname, cylinders, heads, p);
 		p->stop_unit  = (cylinders * heads) - 1;
 		break;
 	}
@@ -1468,24 +1466,24 @@ static void do_format_dasd(dasdfmt_info_
 
 		switch (mode) {
 		case FULL:
-			dasdfmt_prepare_and_format(info, cylinders, heads, p);
+			dasdfmt_prepare_and_format(info, devname, cylinders, heads, p);
 			break;
 		case QUICK:
 			dasdfmt_release_space(info);
-			dasdfmt_quick_format(info, cylinders, heads, p);
+			dasdfmt_quick_format(info, devname, cylinders, heads, p);
 			break;
 		case EXPAND:
-			dasdfmt_expand_format(info, cylinders, heads, p);
+			dasdfmt_expand_format(info, devname, cylinders, heads, p);
 			break;
 		}
 
 		printf("Finished formatting the device.\n");
 
 		if (!(info->writenolabel || mode == EXPAND))
-			dasdfmt_write_labels(info, vlabel, cylinders, heads);
+			dasdfmt_write_labels(info, devname, vlabel, cylinders, heads);
 
 		printf("Rereading the partition table... ");
-		err = dasd_reread_partition_table(dev_filename, 5);
+		err = dasd_reread_partition_table(devname, 5);
 		if (err != 0) {
 			ERRMSG("%s: error during rereading the partition "
 			       "table: %s.\n", prog_name, strerror(err));
@@ -1508,23 +1506,91 @@ static void do_format_dasd(dasdfmt_info_t *info, char *devname,
 		mode = info->ese ? QUICK : FULL;
 }
 
+void do_dasdfmt(char *dev_filename, dasdfmt_info_t info,
+		volume_label_t *orig_vlabel, format_data_t format_params)
+{
+	volume_label_t vlabel;
+	char old_volser[7];
+	char str[ERR_LENGTH];
+	unsigned int cylinders, heads; int rc;
+
+	filedes = open(dev_filename, O_RDWR);
+	if (filedes == -1)
+		ERRMSG_EXIT(EXIT_FAILURE, "%s: Unable to open device %s: %s\n",
+			    prog_name, dev_filename, strerror(errno));
+	close(filedes);
+
+	rc = dasd_get_info(dev_filename, &info.dasd_info);
+	if (rc != 0)
+		ERRMSG_EXIT(EXIT_FAILURE, "%s: the ioctl call to retrieve "
+			    "device information for %s failed (%s).\n",
+			    prog_name, dev_filename, strerror(rc));
+
+	info.ese = dasd_sys_ese(dev_filename);
+	eval_format_mode(&info);
+
+	memcpy(&vlabel, orig_vlabel, sizeof(vlabel));
+	/* Either let the user specify the blksize or get it from the kernel */
+	if (!info.blksize_specified) {
+		if (!(mode == FULL ||
+		      info.dasd_info.format == DASD_FORMAT_NONE)
+		    || info.check)
+			get_blocksize(dev_filename, &format_params.blksize);
+		else
+			format_params = ask_user_for_blksize(format_params);
+	}
+
+	if (info.keep_volser) {
+		if (info.labelspec) {
+			ERRMSG_EXIT(EXIT_MISUSE, "%s: The -k and -l options "
+				    "are mutually exclusive\n", prog_name);
+		}
+		if (!(format_params.intensity & DASD_FMT_INT_COMPAT)) {
+			printf("WARNING: VOLSER cannot be kept "
+			       "when using the ldl format!\n");
+			exit(1);
+		}
+
+		if (dasdfmt_get_volser(dev_filename,
+				       &info.dasd_info, 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);
+	}
+
+	check_disk(&info, dev_filename);
+
+	if (check_param(str, ERR_LENGTH, &format_params) < 0)
+		ERRMSG_EXIT(EXIT_MISUSE, "%s: %s\n", prog_name, str);
+
+	set_geo(&info, &cylinders, &heads);
+	set_label(&info, &vlabel, &format_params, cylinders);
+
+	if (info.check)
+		check_disk_format(&info, cylinders, heads, &format_params);
+	else
+		do_format_dasd(&info, dev_filename, &vlabel,
+			       &format_params, cylinders, heads);
+
+}
+
 int main(int argc, char *argv[])
 {
 	dasdfmt_info_t info = {
 		.dasd_info = {0},
 	};
 	volume_label_t vlabel;
-	char old_volser[7];
 
-	char str[ERR_LENGTH];
+	char *dev_filename[MAX_DEVICES];
 	char buf[7];
 
 	char *blksize_param_str = NULL;
 	char *reqsize_param_str = NULL;
 	char *hashstep_str      = NULL;
 
-	int rc;
-	unsigned int cylinders, heads;
+	int rc, numdev = 0, i;
 
 	/* Establish a handler for interrupt signals. */
 	signal(SIGTERM, program_interrupt_signal);
@@ -1686,59 +1751,21 @@ int main(int argc, char *argv[])
 	if (info.print_hashmarks)
 		PARSE_PARAM_INTO(info.hashstep, hashstep_str, 10, "hashstep");
 
-	get_device_name(dev_filename, optind, argc, argv);
-
-	rc = dasd_get_info(dev_filename, &info.dasd_info);
-	if (rc != 0)
-		ERRMSG_EXIT(EXIT_FAILURE, "%s: the ioctl call to retrieve "
-			    "device information failed (%s).\n",
-			    prog_name, strerror(rc));
-
-	info.ese = dasd_sys_ese(dev_filename);
-	eval_format_mode(&info);
-
-	/* Either let the user specify the blksize or get it from the kernel */
-	if (!info.blksize_specified) {
-		if (!(mode == FULL ||
-		      info.dasd_info.format == DASD_FORMAT_NONE) || info.check)
-			get_blocksize(dev_filename, &format_params.blksize);
-		else
-			format_params = ask_user_for_blksize(format_params);
-	}
-
-	if (info.keep_volser) {
-		if (info.labelspec) {
-			ERRMSG_EXIT(EXIT_MISUSE, "%s: The -k and -l options "
-				    "are mutually exclusive\n", prog_name);
-		}
-		if (!(format_params.intensity & DASD_FMT_INT_COMPAT)) {
-			printf("WARNING: VOLSER cannot be kept "
-			       "when using the ldl format!\n");
-			exit(1);
-		}
-
-		if (dasdfmt_get_volser(dev_filename,
-				       &info.dasd_info, 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);
+	while (optind < argc) {
+		if (optind >= argc)
+			ERRMSG_EXIT(EXIT_MISUSE, "%s: No device specified!\n",
+				    prog_name);
+
+		get_device_name(dev_filename, numdev, argv[optind]);
+		optind++;
+		numdev++;
 	}

-	check_disk(&info, dev_filename);
-
-	if (check_param(str, ERR_LENGTH, &format_params) < 0)
-		ERRMSG_EXIT(EXIT_MISUSE, "%s: %s\n", prog_name, str);
-
-	set_geo(&info, &cylinders, &heads);
-	set_label(&info, &vlabel, &format_params, cylinders);
-
-	if (info.check)
-		check_disk_format(&info, cylinders, heads, &format_params);
-	else
-		do_format_dasd(&info, dev_filename, &vlabel,
-			       &format_params, cylinders, heads);
+	if (!numdev)
+		ERRMSG_EXIT(EXIT_MISUSE, "%s: No device specified!\n",
+			    prog_name);
 
+	for (i = 0; i < numdev; i++)
+		do_dasdfmt(dev_filename[i], info, &vlabel, format_params);
 	return 0;
 }
-- 
1.7.12.4

