Files
s390-tools/dasdfmt/dasdfmt.c
Michael Holzheu b627b8d8e1 Initial s390-tools-2.0.0 import
This commit is based on the s390-tools-1.39.0 version.

Changes on top of s390-tools-1.39.0:

 - Add MIT license to all source files
 - Add LICENSE file
 - Transform REAMDE to README.md (markdown)
 - Add AUTHORS.md file
 - Add CONTRIBUTING.md file
 - Move changelog from README to CHANGELOG.md file

Reviewed-by: Stefan Haberland <sth@linux.vnet.ibm.com>
Signed-off-by: Michael Holzheu <holzheu@linux.vnet.ibm.com>
2017-08-21 10:55:40 +02:00

1714 lines
46 KiB
C

/*
* dasdfmt - Format DASD ECKD devices for use by Linux
*
* Copyright IBM Corp. 1999, 2017
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#include <linux/version.h>
#include <sys/sysmacros.h>
#include <sys/time.h>
#include <sys/utsname.h>
#include "lib/dasd_sys.h"
#include "lib/util_opt.h"
#include "lib/util_prg.h"
#include "lib/util_proc.h"
#include "lib/vtoc.h"
#include "lib/zt_common.h"
#include "dasdfmt.h"
#define BUSIDSIZE 8
#define SEC_PER_DAY (60 * 60 * 24)
#define SEC_PER_HOUR (60 * 60)
static int filedes;
static int disk_disabled;
static format_data_t format_params;
static format_mode_t mode;
static char *prog_name;
static volatile sig_atomic_t program_interrupt_in_progress;
static int reqsize;
static const struct util_prg prg = {
.desc = "Use dasdfmt to format a DASD ECKD device for use by Linux.\n"
"DEVICE is the node of the device (e.g. '/dev/dasda').",
.args = "DEVICE",
.copyright_vec = {
{
.owner = "IBM Corp.",
.pub_first = 1999,
.pub_last = 2016,
},
UTIL_PRG_COPYRIGHT_END
}
};
/* Defines for options with no short command */
#define OPT_CHECK 128
#define OPT_NOZERO 129
static struct util_opt opt_vec[] = {
UTIL_OPT_SECTION("FORMAT ACTIONS"),
{
.option = { "mode", required_argument, NULL, 'M' },
.argument = "MODE",
.desc = "Specify scope of operation using MODE:\n"
" full: Full device (default)\n"
" quick: Only the first two tracks\n"
" expand: Unformatted tracks at device end",
},
{
.option = { "check", no_argument, NULL, OPT_CHECK },
.desc = "Perform complete format check on device",
.flags = UTIL_OPT_FLAG_NOSHORT,
},
UTIL_OPT_SECTION("FORMAT OPTIONS"),
{
.option = { "blocksize", required_argument, NULL, 'b' },
.argument = "SIZE",
.desc = "Format blocks to SIZE bytes (default 4096)",
},
{
.option = { "disk_layout", required_argument, NULL, 'd' },
.argument = "LAYOUT",
.desc = "Specify the disk layout:\n"
" cdl: Compatible Disk Layout (default)\n"
" ldl: Linux Disk Layout",
},
{
.option = { "keep_volser", no_argument, NULL, 'k' },
.desc = "Do not change the current volume serial",
},
{
.option = { "label", required_argument, NULL, 'l' },
.argument = "VOLSER",
.desc = "Specify volume serial number",
},
{
.option = { "no_label", no_argument, NULL, 'L' },
.desc = "Don't write a disk label",
},
{
.option = { "requestsize", required_argument, NULL, 'r' },
.argument = "NUM",
.desc = "Process NUM cylinders in one formatting step",
},
{
.option = { "norecordzero", no_argument, NULL, OPT_NOZERO },
.desc = "Prevent storage server from modifying record 0",
.flags = UTIL_OPT_FLAG_NOSHORT,
},
{
.option = { NULL, no_argument, NULL, 'y' },
.desc = "Start formatting without further user-confirmation",
.flags = UTIL_OPT_FLAG_NOLONG,
},
UTIL_OPT_SECTION("DISPLAY PROGRESS"),
{
.option = { "hashmarks", required_argument, NULL, 'm' },
.argument = "NUM",
.desc = "Show a hashmark every NUM cylinders",
},
{
.option = { "progressbar", no_argument, NULL, 'p' },
.desc = "Show a progressbar",
},
{
.option = { "percentage", no_argument, NULL, 'P' },
.desc = "Show progress in percent",
},
UTIL_OPT_SECTION("MISC"),
{
.option = { "check_host_count", no_argument, NULL, 'C' },
.desc = "Check if device is in use by other hosts",
},
{
.option = { "force", no_argument, NULL, 'F' },
.desc = "Format without performing sanity checking",
},
{
.option = { "test", no_argument, NULL, 't' },
.desc = "Run in dry-run mode without modifying the DASD",
},
{
.option = { NULL, no_argument, NULL, 'v' },
.desc = "Print verbose messages when executing",
.flags = UTIL_OPT_FLAG_NOLONG,
},
UTIL_OPT_HELP,
{
.option = { "version", no_argument, NULL, 'V' },
.desc = "Print version information, then exit",
},
UTIL_OPT_END
};
/*
* Helper function to calculate the days, hours, minutes, and seconds
* for a given timestamp in seconds
*/
static void calc_time(time_t time, int *d, int *h, int *m, int *s)
{
*d = time / SEC_PER_DAY;
time %= SEC_PER_DAY;
*h = time / SEC_PER_HOUR;
time %= SEC_PER_HOUR;
*m = time / 60;
*s = time % 60;
}
/*
* This function calculates and prints the estimated time of accomplishment.
*/
static void print_eta(int p_new, int started)
{
static struct timeval start;
struct timeval now;
time_t time_elapsed;
time_t time_end;
int d, h, m, s;
static int p_init;
int p;
if (!started) {
gettimeofday(&start, NULL);
p_init = p_new;
}
gettimeofday(&now, NULL);
time_elapsed = now.tv_sec - start.tv_sec;
/*
* We might start somewhere in the middle with an initial percentage
* value of i.e. 60%. Therefore we need to calculate the relative
* percentage of p_new within that remaining range (100 - 60) in order
* to correctly estimate the remaining time.
*/
if (p_init == 100)
p = p_init;
else
p = 100 * (p_new - p_init) / (100 - p_init);
if (p == 0)
time_end = time_elapsed;
else
time_end = time_elapsed * (100 - p) / p;
/* Calculate days, hours, minutes, and seconds */
calc_time(time_end, &d, &h, &m, &s);
if (p_new == 100)
calc_time(time_elapsed, &d, &h, &m, &s);
/* Avoid printing leading zeros */
if (d > 0)
printf(" [%dd %dh %dm %ds%-4s", d, h, m, s, "]");
else if (h > 0)
printf(" [%dh %dm %ds%-7s", h, m, s, "]");
else if (m > 0)
printf(" [%dm %ds%-6s", m, s, "]");
else if (s > 0 || p > 50)
printf(" [%ds%-5s", s, "]");
else
printf(" [--%-1s", "]");
}
/*
* Draw the progress indicator depending on what command line argument is set.
* This can either be a progressbar, hashmarks, or percentage.
*/
static void draw_progress(dasdfmt_info_t *info, int cyl, unsigned int cylinders,
int aborted)
{
static int hashcount;
static int started;
static int p_old;
int p_new = 0;
int barlength;
int i;
if (info->print_progressbar) {
printf("cyl %7d of %7d |", cyl, cylinders);
p_new = cyl * 100 / cylinders;
if (p_new != p_old || !started || aborted) {
/* percent value has changed */
p_old = p_new;
barlength = cyl * 33 / cylinders;
for (i = 1; i <= barlength; i++)
printf("#");
for (i = barlength + 1; i <= 33; i++)
printf("-");
printf("|%3d%%", p_new);
if (aborted)
p_new = 100;
print_eta(p_new, started);
started = 1;
}
printf("\r");
fflush(stdout);
}
if (info->print_hashmarks &&
(cyl / info->hashstep - hashcount) != 0) {
printf("#");
fflush(stdout);
hashcount++;
}
if (info->print_percentage) {
printf("cyl %7d of %7d |%3d%%\n", cyl, cylinders,
cyl * 100 / cylinders);
fflush(stdout);
}
}
static int reread_partition_table(void)
{
int i = 0;
int rc = -1;
/* If the BLKRRPART ioctl fails, it is most likely due to
the device just beeing in use by udev. So it is worthwhile
to retry the ioctl after a second as it is likely to succeed.
*/
while (rc && (i < 5)) {
++i;
rc = ioctl(filedes, BLKRRPART, NULL);
if (rc)
sleep(1);
}
return rc;
}
/*
* Helper function for recs_per_track.
*/
static inline unsigned int ceil_quot(unsigned int d1, unsigned int d2)
{
return (d1 + (d2 - 1)) / d2;
}
/*
* Calculate records per track depending on the device characteristics.
*/
static unsigned int recs_per_track(struct dasd_eckd_characteristics *rdc,
unsigned int kl, unsigned int dl)
{
int dn, kn;
switch (rdc->dev_type) {
case 0x3380:
if (kl)
return 1499 / (15 + 7 + ceil_quot(kl + 12, 32) +
ceil_quot(dl + 12, 32));
else
return 1499 / (15 + ceil_quot(dl + 12, 32));
case 0x3390:
dn = ceil_quot(dl + 6, 232) + 1;
if (kl) {
kn = ceil_quot(kl + 6, 232) + 1;
return 1729 / (10 + 9 + ceil_quot(kl + 6 * kn, 34) +
9 + ceil_quot(dl + 6 * dn, 34));
} else
return 1729 / (10 + 9 + ceil_quot(dl + 6 * dn, 34));
case 0x9345:
dn = ceil_quot(dl + 6, 232) + 1;
if (kl) {
kn = ceil_quot(kl + 6, 232) + 1;
return 1420 / (18 + 7 + ceil_quot(kl + 6 * kn, 34) +
ceil_quot(dl + 6 * dn, 34));
} else
return 1420 / (18 + 7 + ceil_quot(dl + 6 * dn, 34));
}
return 0;
}
/*
* Evaluate errors recognized by format checks and print appropriate error
* messages depending on the content of cdata.
*/
static void evaluate_format_error(dasdfmt_info_t *info, format_check_t *cdata,
unsigned int heads)
{
struct dasd_eckd_characteristics *rdc;
/* Special blocksize values of the first 3 records of trk 0 of cyl 0 */
const int blksizes_trk0[] = { 24, 144, 80 };
/* Special blocksize value of trk 1 cyl 0 */
const int blksize_trk1 = 96;
unsigned int cyl;
unsigned int head;
unsigned int rpt;
unsigned int kl = 0;
int blksize = cdata->expect.blksize;
if (info->print_progressbar || info->print_hashmarks)
printf("\n");
/*
* If mode is not QUICK and a device format couldn't be determined, the
* device is considered not formatted.
* Also, reading record zero will never happen. If the record in error
* is 0 nonetheless, the device is not formatted at all as well!
*/
if ((info->dasd_info.format == DASD_FORMAT_NONE && mode != QUICK) ||
cdata->rec == 0) {
ERRMSG("WARNING: The specified device is not "
"formatted at all.\n");
return;
}
cyl = cdata->unit / heads;
head = cyl >> 16;
head <<= 4;
head |= cdata->unit % heads;
/*
* Set special expected values for the first 3 records of trk 0 of cyl 0
* and trk 1 of cyl 0 when checking a CDL formatted device.
*/
if ((cdata->expect.intensity & DASD_FMT_INT_COMPAT) &&
cyl == 0 && head == 0 && cdata->rec < 4) {
kl = 4;
blksize = blksizes_trk0[cdata->rec - 1];
}
if ((cdata->expect.intensity & DASD_FMT_INT_COMPAT) &&
cyl == 0 && head == 1) {
kl = 44;
blksize = blksize_trk1;
}
rdc = (struct dasd_eckd_characteristics *)
&info->dasd_info.characteristics;
rpt = recs_per_track(rdc, kl, cdata->expect.blksize);
ERRMSG("WARNING: The specified device is not formatted as expected.\n");
switch (cdata->result) {
case DASD_FMT_ERR_TOO_FEW_RECORDS:
ERRMSG("Too few records (found %d, expected %d) "
"at cyl: %d trk: %d rec: %d.\n",
cdata->num_records, rpt, cyl, head, cdata->rec);
break;
case DASD_FMT_ERR_TOO_MANY_RECORDS:
ERRMSG("Too many records (found %d, expected %d) "
"at cyl: %d trk: %d rec: %d.\n",
cdata->num_records, rpt, cyl, head, cdata->rec);
break;
case DASD_FMT_ERR_BLKSIZE:
ERRMSG("Invalid blocksize (found %d, expected %d) "
"at cyl: %d trk: %d rec: %d.\n",
cdata->blksize, blksize, cyl, head, cdata->rec);
break;
case DASD_FMT_ERR_RECORD_ID:
ERRMSG("Invalid record ID at cyl: %d trk: %d rec: %d.\n",
cyl, head, cdata->rec);
break;
case DASD_FMT_ERR_KEY_LENGTH:
ERRMSG("Invalid key length (found %d, expected %d) "
"at cyl: %d trk: %d rec: %d.\n",
cdata->key_length, kl, cyl, head, cdata->rec);
break;
}
}
/*
* signal handler:
* enables the disk again in case of SIGTERM, SIGINT and SIGQUIT
*/
static void program_interrupt_signal(int sig)
{
int rc;
if (program_interrupt_in_progress)
raise(sig);
program_interrupt_in_progress = 1;
if (disk_disabled) {
printf("Re-accessing the device...\n");
rc = ioctl(filedes, BIODASDENABLE, &format_params);
if (rc)
ERRMSG_EXIT(EXIT_FAILURE, "%s: (signal handler) IOCTL "
"BIODASDENABLE failed (%s)\n", prog_name,
strerror(errno));
}
printf("Rereading the partition table...\n");
rc = reread_partition_table();
if (rc) {
ERRMSG("%s: (signal handler) Re-reading partition table "
"failed. (%s)\n", prog_name, strerror(errno));
} else {
printf("Exiting...\n");
}
rc = close(filedes);
if (rc)
ERRMSG("%s: (signal handler) Unable to close device (%s)\n",
prog_name, strerror(errno));
signal(sig, SIG_DFL);
raise(sig);
}
/*
* check given device name for blanks and some special characters
*/
static void get_device_name(dasdfmt_info_t *info, char *name, int argc,
char *argv[])
{
struct util_proc_dev_entry dev_entry;
struct stat dev_stat;
if (info->device_id + 1 < argc)
ERRMSG_EXIT(EXIT_MISUSE,
"%s: More than one device specified!\n", prog_name);
if (info->device_id >= argc)
ERRMSG_EXIT(EXIT_MISUSE, "%s: No device specified!\n",
prog_name);
if (info->device_id < argc) {
strcpy(info->devname, argv[info->device_id]);
} else {
if ((strchr(name, ' ') != NULL) || (strchr(name, '#') != NULL) ||
(strchr(name, '[') != NULL) || (strchr(name, ']') != NULL) ||
(strchr(name, '!') != NULL) || (strchr(name, '>') != NULL) ||
(strchr(name, '(') != NULL) || (strchr(name, '<') != NULL) ||
(strchr(name, ')') != NULL) || (strchr(name, ':') != NULL) ||
(strchr(name, '&') != NULL) || (strchr(name, ';') != NULL))
ERRMSG_EXIT(EXIT_MISUSE, "%s: Your filename contains "
"blanks or special characters!\n",
prog_name);
strncpy(info->devname, name, PATH_MAX - 1);
info->devname[PATH_MAX - 1] = '\0';
}
if (stat(info->devname, &dev_stat) != 0)
ERRMSG_EXIT(EXIT_MISUSE, "%s: Could not get information for "
"device node %s: %s\n", prog_name, info->devname,
strerror(errno));
if (minor(dev_stat.st_rdev) & PARTN_MASK) {
ERRMSG_EXIT(EXIT_MISUSE, "%s: Unable to format partition %s. "
"Please specify a device.\n", prog_name,
info->devname);
}
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, info->devname);
}
}
/*
* Retrieve DASD information
*/
static void get_device_info(dasdfmt_info_t *info)
{
dasd_information2_t dasd_info;
if (ioctl(filedes, BIODASDINFO2, &dasd_info))
ERRMSG_EXIT(EXIT_FAILURE, "%s: the ioctl call to retrieve "
"device information failed (%s).\n",
prog_name, strerror(errno));
info->dasd_info = dasd_info;
}
/*
* Retrieve blocksize of device
*/
static void get_blocksize(unsigned int *blksize)
{
if (ioctl(filedes, BLKSSZGET, blksize) != 0)
ERRMSG_EXIT(EXIT_FAILURE, "%s: the ioctl to get the blocksize "
"of the device failed (%s).\n", prog_name,
strerror(errno));
}
/*
* Check whether a specified blocksize matches the blocksize of the device
*/
static void check_blocksize(dasdfmt_info_t *info, unsigned int blksize)
{
unsigned int dev_blksize;
if (!info->blksize_specified ||
info->dasd_info.format == DASD_FORMAT_NONE)
return;
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 "
"perform a clean format.\n", dev_blksize);
}
}
/*
* Check whether a specified layout matches the layout
* a device is formatted with.
*/
static void check_layout(dasdfmt_info_t *info, unsigned int intensity)
{
char layout[4];
if (!info->layout_specified ||
info->dasd_info.format == DASD_FORMAT_NONE)
return;
if ((intensity & DASD_FMT_INT_COMPAT) &&
info->dasd_info.format == DASD_FORMAT_CDL)
return;
if (!(intensity & DASD_FMT_INT_COMPAT) &&
info->dasd_info.format == DASD_FORMAT_LDL)
return;
if (info->dasd_info.format == DASD_FORMAT_CDL)
sprintf(layout, "CDL");
if (info->dasd_info.format == DASD_FORMAT_LDL)
sprintf(layout, "LDL");
ERRMSG_EXIT(EXIT_FAILURE, "WARNING: Device is formatted with a "
"different layout (%s).\n", layout);
}
/*
* check for disk type and set some variables (e.g. usage count)
*/
static void check_disk(dasdfmt_info_t *info)
{
int ro, errno_save;
if (ioctl(filedes, BLKROGET, &ro) != 0) {
errno_save = errno;
close(filedes);
ERRMSG_EXIT(EXIT_FAILURE,
"%s: the ioctl call to retrieve read/write "
"status information failed (%s)\n",
prog_name, strerror(errno_save));
}
if (ro)
ERRMSG_EXIT(EXIT_FAILURE, "Disk is read only!\n");
if (!info->force)
if (info->dasd_info.open_count > 1)
ERRMSG_EXIT(EXIT_BUSY, "Disk in use!\n");
if (strncmp(info->dasd_info.type, "ECKD", 4) != 0) {
ERRMSG_EXIT(EXIT_FAILURE,
"%s: Unsupported disk type\n%s is not an "
"ECKD disk!\n", prog_name, info->devname);
}
if (dasd_sys_raw_track_access(info->devname)) {
ERRMSG_EXIT(EXIT_FAILURE,
"%s: Device '%s' is in raw-track access mode\n",
prog_name, info->devname);
}
}
/*
* check the volume serial for special
* characters and move blanks to the end
*/
static int check_volser(char *s, int devno)
{
int i, j;
for (i = 0; i < 6; i++) {
if ((s[i] < 0x20) || (s[i] > 0x7a) ||
((s[i] >= 0x21) && (s[i] <= 0x22)) || /* !" */
((s[i] >= 0x26) && (s[i] <= 0x2f)) || /* &'()*+,-./ */
((s[i] >= 0x3a) && (s[i] <= 0x3f)) || /* :;<=>? */
((s[i] >= 0x5b) && (s[i] <= 0x60))) /* \]^_` */
s[i] = ' ';
s[i] = toupper(s[i]);
}
s[6] = 0x00;
for (i = 0; i < 6; i++) {
if (s[i] == ' ')
for (j = i; j < 6; j++)
if (s[j] != ' ') {
s[i] = s[j];
s[j] = ' ';
break;
}
}
if (s[0] == ' ') {
printf("Usage error, switching to default.\n");
sprintf(s, "0X%04x", devno);
for (i = 0; i < 6; i++)
s[i] = toupper(s[i]);
return -1;
}
return 0;
}
/*
* do some blocksize checks
*/
static int check_param(char *s, size_t buffsize, format_data_t *data)
{
int tmp = data->blksize;
if ((tmp < 512) || (tmp > 4096)) {
strncpy(s, "Blocksize must be one of the following positive "
"integers:\n512, 1024, 2048, 4096.", buffsize);
if (buffsize > 0)
s[buffsize - 1] = '\0';
return -1;
}
while (tmp > 0) {
if ((tmp % 2) && (tmp != 1)) {
strncpy(s, "Blocksize must be a power of 2.", buffsize);
if (buffsize > 0)
s[buffsize - 1] = '\0';
return -1;
}
tmp /= 2;
}
return 0;
}
/*
* Retrieve disk information and set cylinders and heads accordingly.
*/
static void set_geo(dasdfmt_info_t *info, unsigned int *cylinders,
unsigned int *heads)
{
struct dasd_eckd_characteristics *characteristics;
if (info->verbosity > 0)
printf("Retrieving disk geometry...\n");
characteristics = (struct dasd_eckd_characteristics *)
&info->dasd_info.characteristics;
if (characteristics->no_cyl == LV_COMPAT_CYL &&
characteristics->long_no_cyl)
*cylinders = characteristics->long_no_cyl;
else
*cylinders = characteristics->no_cyl;
*heads = characteristics->trk_per_cyl;
}
/*
* Set VTOC label information
*/
static void set_label(dasdfmt_info_t *info, volume_label_t *vlabel,
format_data_t *p, unsigned int cylinders)
{
char inp_buffer[5];
if (info->writenolabel) {
if (cylinders > LV_COMPAT_CYL && !info->withoutprompt) {
printf("\n--->> ATTENTION! <<---\n");
printf("You specified to write no labels to a"
" volume with more then %u cylinders.\n"
"Cylinders above this limit will not be"
" accessible as a linux partition!\n"
"Type \"yes\" to continue, no will leave"
" the disk untouched: ", LV_COMPAT_CYL);
if (fgets(inp_buffer, sizeof(inp_buffer), stdin) == NULL)
return;
if (strcasecmp(inp_buffer, "yes") &&
strcasecmp(inp_buffer, "yes\n")) {
printf("Omitting ioctl call (disk will "
"NOT be formatted).\n");
return;
}
}
} else {
if (!info->labelspec && !info->keep_volser) {
char buf[7];
sprintf(buf, "0X%04x", info->dasd_info.devno);
check_volser(buf, info->dasd_info.devno);
vtoc_volume_label_set_volser(vlabel, buf);
}
if (p->intensity & DASD_FMT_INT_COMPAT) {
info->cdl_format = 1;
vtoc_volume_label_set_label(vlabel, "VOL1");
vtoc_volume_label_set_key(vlabel, "VOL1");
vtoc_set_cchhb(&vlabel->vtoc, 0x0000, 0x0001, 0x01);
} else {
vtoc_volume_label_set_label(vlabel, "LNX1");
}
}
}
/*
* Check whether hashsteps are within the correct interval.
*/
static void check_hashmarks(dasdfmt_info_t *info)
{
if (info->print_hashmarks) {
if (info->hashstep < reqsize)
info->hashstep = reqsize;
if ((info->hashstep < 1) || (info->hashstep > 1000)) {
printf("Hashmark increment is not in range <1,1000>, "
"using the default.\n");
info->hashstep = 10;
}
printf("Printing hashmark every %d cylinders.\n",
info->hashstep);
}
}
/*
* 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)
{
format_check_t cdata = {
.expect = {
.blksize = p->blksize,
.intensity = p->intensity,
.start_unit = p->start_unit,
.stop_unit = p->stop_unit
}, 0
};
if (ioctl(filedes, BIODASDCHECKFMT, &cdata)) {
if (errno == ENOTTY) {
ERRMSG("%s: Missing kernel support for format checking",
prog_name);
if (mode == EXPAND) {
ERRMSG(". Mode 'expand' cannot be used");
} else if (!info->check) {
ERRMSG(" (--force to override)");
}
ERRMSG_EXIT(EXIT_FAILURE, ".\n");
}
ERRMSG_EXIT(EXIT_FAILURE, "%s: Could no check format: %s\n",
prog_name, strerror(errno));
}
return cdata;
}
/*
* Either do the actual format or check depending on the check-value.
*/
static int process_tracks(dasdfmt_info_t *info, unsigned int cylinders,
unsigned int heads, format_data_t *format_params)
{
format_check_t cdata = { .expect = {0}, 0};
format_data_t step = *format_params;
unsigned long step_value;
unsigned long cur_trk;
int cyl = 0;
check_hashmarks(info);
cur_trk = format_params->start_unit;
while (cur_trk < format_params->stop_unit) {
step_value = reqsize * heads - (cur_trk % heads);
step.start_unit = cur_trk;
if (cur_trk + heads * reqsize >= format_params->stop_unit)
step.stop_unit = format_params->stop_unit;
else
step.stop_unit = cur_trk + step_value - 1;
if (info->check) {
cdata = check_track_format(info, &step);
if (cdata.result) {
cyl = cur_trk / heads + 1;
draw_progress(info, cyl, cylinders, 1);
evaluate_format_error(info, &cdata, heads);
break;
}
} else {
if (ioctl(filedes, BIODASDFMT, &step) != 0)
ERRMSG_EXIT(EXIT_FAILURE, "%s: the ioctl call "
"to format tracks failed. (%s)\n",
prog_name, strerror(errno));
}
cyl = cur_trk / heads + 1;
draw_progress(info, cyl, cylinders, 0);
cur_trk += step_value;
}
/* We're done, draw the 100% mark */
if (!cdata.result) {
cyl = step.stop_unit / heads + 1;
draw_progress(info, cyl, cylinders, 0);
printf("\n");
}
return cdata.result;
}
/*
* This function checks the format of the entire disk.
*/
static void check_disk_format(dasdfmt_info_t *info, unsigned int cylinders,
unsigned int heads, format_data_t *check_params)
{
check_params->start_unit = 0;
check_params->stop_unit = (cylinders * heads) - 1;
printf("Checking format of the entire disk...\n");
if (info->testmode) {
printf("Test mode active, omitting ioctl.\n");
return;
}
check_blocksize(info, check_params->blksize);
check_layout(info, check_params->intensity);
/*
* If no layout was specified, set the intensity
* according to what the layout seems to be.
*/
if (!info->layout_specified) {
if (info->dasd_info.format == DASD_FORMAT_CDL)
check_params->intensity |= DASD_FMT_INT_COMPAT;
else if (info->dasd_info.format == DASD_FORMAT_LDL)
check_params->intensity &= ~DASD_FMT_INT_COMPAT;
}
if (process_tracks(info, cylinders, heads, check_params)) {
ERRMSG_EXIT(EXIT_FAILURE, "Use --mode=full to perform a "
"clean format.\n");
}
printf("Done. Disk is fine.\n");
}
/*
* ask the user to specify a blocksize
*/
static format_data_t ask_user_for_blksize(format_data_t params)
{
char c, str[ERR_LENGTH], buffer[20];
int i, rc;
i = params.blksize;
do {
params.blksize = i;
printf("Please enter the blocksize of the formatting [%d]: ", i);
if (fgets(buffer, sizeof(buffer), stdin) == NULL)
break;
rc = sscanf(buffer, "%d%c", &params.blksize, &c);
if ((rc == 2) && (c == '\n'))
rc = 1;
if (rc == -1)
rc = 1; /* this happens, if enter is pressed */
if (rc != 1)
printf(" -- wrong input, try again.\n");
if (check_param(str, ERR_LENGTH, &params) < 0) {
printf(" -- %s\n", str);
rc = 0;
}
} while (rc != 1);
return params;
}
/*
* print all information needed to format the device
*/
static void dasdfmt_print_info(dasdfmt_info_t *info, volume_label_t *vlabel,
unsigned int cylinders, unsigned int heads,
format_data_t *p)
{
char volser[6], vollbl[4];
printf("Drive Geometry: %d Cylinders * %d Heads = %d Tracks\n",
cylinders, heads, (cylinders * heads));
printf("\nI am going to format the device ");
printf("%s in the following way:\n", info->devname);
printf(" Device number of device : 0x%x\n", info->dasd_info.devno);
printf(" Labelling device : %s\n",
(info->writenolabel) ? "no" : "yes");
if (!info->writenolabel) {
vtoc_volume_label_get_label(vlabel, vollbl);
printf(" Disk label : %.4s\n", vollbl);
vtoc_volume_label_get_volser(vlabel, volser);
printf(" Disk identifier : %.6s\n", volser);
}
printf(" Extent start (trk no) : %u\n", p->start_unit);
printf(" Extent end (trk no) : %u\n", p->stop_unit);
printf(" Compatible Disk Layout : %s\n",
(p->intensity & DASD_FMT_INT_COMPAT) ? "yes" : "no");
printf(" Blocksize : %d\n", p->blksize);
printf(" Mode : %s\n", mode_str[mode]);
if (info->testmode)
printf("Test mode active, omitting ioctl.\n");
}
/*
* get volser
*/
static int dasdfmt_get_volser(dasdfmt_info_t *info, char *volser)
{
unsigned int blksize;
int f;
volume_label_t vlabel;
f = open(info->devname, O_RDONLY);
if (f == -1)
ERRMSG_EXIT(EXIT_FAILURE, "%s: Unable to open device %s: %s\n",
prog_name, info->devname, strerror(errno));
get_blocksize(&blksize);
if (close(f) != 0)
ERRMSG("%s: error during close: %s\ncontinuing...\n",
prog_name, strerror(errno));
if ((strncmp(info->dasd_info.type, "ECKD", 4) == 0) &&
(!info->dasd_info.FBA_layout)) {
/* OS/390 and zOS compatible disk layout */
vtoc_read_volume_label(info->devname,
info->dasd_info.label_block * blksize,
&vlabel);
vtoc_volume_label_get_volser(&vlabel, volser);
return 0;
} else {
return -1;
}
}
/*
* do all the labeling (volume label and initial VTOC)
*/
static void dasdfmt_write_labels(dasdfmt_info_t *info, volume_label_t *vlabel,
unsigned int cylinders, unsigned int heads)
{
int label_position;
struct hd_geometry geo;
format4_label_t f4;
format5_label_t f5;
format7_label_t f7;
unsigned int blksize;
int rc;
void *ipl1_record, *ipl2_record;
int ipl1_record_len, ipl2_record_len;
if (info->verbosity > 0)
printf("Retrieving dasd information... ");
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.
*/
if (ioctl(filedes, HDIO_GETGEO, &geo) != 0)
ERRMSG_EXIT(EXIT_FAILURE, "%s: (write labels) IOCTL "
"HDIO_GETGEO failed (%s).\n",
prog_name, strerror(errno));
if (info->verbosity > 0)
printf("ok\n");
/* write empty bootstrap (initial IPL records) */
if (info->verbosity > 0)
printf("Writing empty bootstrap...\n");
/*
* Note: ldl labels do not contain the key field
*/
if (info->cdl_format) {
/* Prepare copy with key (CDL) */
ipl1_record = &ipl1;
ipl2_record = &ipl2;
ipl1_record_len = sizeof(ipl1);
ipl2_record_len = sizeof(ipl2);
} else {
/* Prepare copy without key (LDL) */
ipl1_record = ipl1.data;
ipl2_record = ipl2.data;
ipl1_record_len = sizeof(ipl1.data);
ipl2_record_len = sizeof(ipl2.data);
}
if (lseek(filedes, 0, SEEK_SET) != 0)
ERRMSG_EXIT(EXIT_FAILURE, "%s: lseek command 0 failed "
"(%s)\n", prog_name, strerror(errno));
rc = write(filedes, ipl1_record, ipl1_record_len);
if (rc != ipl1_record_len)
ERRMSG_EXIT(EXIT_FAILURE, "%s: Writing the bootstrap IPL1 "
"failed, only wrote %d bytes.\n", prog_name, rc);
label_position = blksize;
rc = lseek(filedes, label_position, SEEK_SET);
if (rc != label_position)
ERRMSG_EXIT(EXIT_FAILURE, "%s: lseek command to %i failed "
"(%s).\n", prog_name, label_position,
strerror(errno));
rc = write(filedes, ipl2_record, ipl2_record_len);
if (rc != ipl2_record_len)
ERRMSG_EXIT(EXIT_FAILURE, "%s: Writing the bootstrap IPL2 "
"failed, only wrote %d bytes.\n", prog_name, rc);
/* write VTOC */
vtoc_init_format4_label(&f4, geo.cylinders, cylinders, heads,
geo.sectors, blksize, info->dasd_info.dev_type);
vtoc_init_format5_label(&f5);
vtoc_init_format7_label(&f7);
vtoc_set_freespace(&f4, &f5, &f7, '+', 0, FIRST_USABLE_TRK,
(cylinders * heads - 1), cylinders, heads);
label_position = info->dasd_info.label_block * blksize;
if (info->verbosity > 0)
printf("Writing label...\n");
rc = lseek(filedes, label_position, SEEK_SET);
if (rc != label_position)
ERRMSG_EXIT(EXIT_FAILURE, "%s: lseek command to %i failed "
"(%s).\n", prog_name, label_position,
strerror(errno));
/*
* Note: cdl volume labels do not contain the 'formatted_blocks' part
* and ldl labels do not contain the key field
*/
if (info->cdl_format) {
rc = write(filedes, vlabel, (sizeof(*vlabel) -
sizeof(vlabel->formatted_blocks)));
} else {
vlabel->ldl_version = 0xf2; /* EBCDIC '2' */
vlabel->formatted_blocks = cylinders * heads * geo.sectors;
rc = write(filedes, &vlabel->vollbl, (sizeof(*vlabel)
- sizeof(vlabel->volkey)));
}
if (((rc != sizeof(*vlabel) - sizeof(vlabel->formatted_blocks)) &&
info->cdl_format) ||
((rc != (sizeof(*vlabel) - sizeof(vlabel->volkey))) &&
(!info->cdl_format)))
ERRMSG_EXIT(EXIT_FAILURE, "%s: Error writing volume label "
"(%d).\n", prog_name, rc);
if (info->verbosity > 0)
printf("Writing VTOC... ");
label_position = (VTOC_START_CC * heads + VTOC_START_HH) *
geo.sectors * blksize;
rc = lseek(filedes, label_position, SEEK_SET);
if (rc != label_position)
ERRMSG_EXIT(EXIT_FAILURE, "%s: lseek command to %i failed "
"(%s).\n", prog_name, label_position,
strerror(errno));
/* write VTOC FMT4 DSCB */
rc = write(filedes, &f4, sizeof(format4_label_t));
if (rc != sizeof(format4_label_t))
ERRMSG_EXIT(EXIT_FAILURE, "%s: Error writing FMT4 label "
"(%d).\n", prog_name, rc);
label_position += blksize;
rc = lseek(filedes, label_position, SEEK_SET);
if (rc != label_position)
ERRMSG_EXIT(EXIT_FAILURE, "%s: lseek to %i failed (%s).\n",
prog_name, label_position, strerror(errno));
/* write VTOC FMT5 DSCB */
rc = write(filedes, &f5, sizeof(format5_label_t));
if (rc != sizeof(format5_label_t))
ERRMSG_EXIT(EXIT_FAILURE, "%s: Error writing FMT5 label "
"(%d).\n", prog_name, rc);
if ((cylinders * heads) > BIG_DISK_SIZE) {
label_position += blksize;
rc = lseek(filedes, label_position, SEEK_SET);
if (rc != label_position)
ERRMSG_EXIT(EXIT_FAILURE, "%s: lseek to %i failed "
"(%s).\n", prog_name, label_position,
strerror(errno));
/* write VTOC FMT 7 DSCB (only on big disks) */
rc = write(filedes, &f7, sizeof(format7_label_t));
if (rc != sizeof(format7_label_t))
ERRMSG_EXIT(EXIT_FAILURE, "%s: Error writing FMT7 "
"label (rc=%d).\n", prog_name, rc);
}
fsync(filedes);
if (info->verbosity > 0)
printf("ok\n");
}
/*
* This function will search for the beginning of an unformatted area
* on the device. It checks selected tracks beforehand and makes sure
* 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,
unsigned heads, format_data_t *format_params)
{
format_check_t cdata;
unsigned int middle;
unsigned int left = 2;
unsigned int right = (cylinders * heads) - 1;
unsigned int first = left;
check_blocksize(info, format_params->blksize);
format_params->start_unit = 0;
format_params->stop_unit = 4;
cdata = check_track_format(info, format_params);
if (cdata.result) {
evaluate_format_error(info, &cdata, heads);
ERRMSG_EXIT(EXIT_FAILURE, "Use --mode=full to perform a "
"clean format.\n");
}
printf("Expansion mode active. Searching for starting position...\n");
while (left <= right) {
/* new track number to look at */
middle = left + ((right - left) / 2);
format_params->start_unit = middle;
format_params->stop_unit = middle;
cdata = check_track_format(info, format_params);
if (cdata.blksize != format_params->blksize) {
first = middle;
right = middle - 1;
} else {
left = middle + 1;
}
}
if (first == 2 && cdata.blksize == format_params->blksize)
ERRMSG_EXIT(EXIT_FAILURE,
"No unformatted part found, aborting.\n");
printf("Done. Unformatted part starts at track %d.\n", first);
/* return format_params with start_unit set to the correct value */
format_params->start_unit = first;
}
/*
* formats the disk cylinderwise
*/
static void dasdfmt_format(dasdfmt_info_t *info, unsigned int cylinders,
unsigned int heads, format_data_t *format_params)
{
process_tracks(info, cylinders, heads, format_params);
}
static void dasdfmt_prepare_and_format(dasdfmt_info_t *info,
unsigned int cylinders,
unsigned int heads, format_data_t *p)
{
format_data_t temp = {
.start_unit = 0,
.stop_unit = 0,
.blksize = p->blksize,
.intensity = ((p->intensity & ~DASD_FMT_INT_FMT_NOR0)
| DASD_FMT_INT_INVAL)
};
if (!((info->withoutprompt) && (info->verbosity < 1)))
printf("Formatting the device. This may take a while "
"(get yourself a coffee).\n");
if (info->verbosity > 0)
printf("Detaching the device...\n");
if (ioctl(filedes, BIODASDDISABLE, p) != 0)
ERRMSG_EXIT(EXIT_FAILURE, "%s: (prepare device) IOCTL "
"BIODASDDISABLE failed. (%s)\n", prog_name,
strerror(errno));
disk_disabled = 1;
if (info->verbosity > 0)
printf("Invalidate first track...\n");
if (ioctl(filedes, BIODASDFMT, &temp) != 0)
ERRMSG_EXIT(EXIT_FAILURE, "%s: (invalidate first track) IOCTL "
"BIODASDFMT failed. (%s)\n", prog_name,
strerror(errno));
/* except track 0 from standard formatting procss */
p->start_unit = 1;
dasdfmt_format(info, cylinders, heads, p);
if (info->verbosity > 0)
printf("formatting tracks complete...\n");
temp.intensity = p->intensity;
if (info->verbosity > 0)
printf("Revalidate first track...\n");
if (ioctl(filedes, BIODASDFMT, &temp) != 0)
ERRMSG_EXIT(EXIT_FAILURE, "%s: (re-validate first track) IOCTL"
" BIODASDFMT failed (%s)\n", prog_name,
strerror(errno));
if (info->verbosity > 0)
printf("Re-accessing the device...\n");
if (ioctl(filedes, BIODASDENABLE, p) != 0)
ERRMSG_EXIT(EXIT_FAILURE, "%s: (prepare device) IOCTL "
"BIODASDENABLE failed. (%s)\n", prog_name,
strerror(errno));
disk_disabled = 0;
}
/*
* This function will start the expand format process.
*/
static void dasdfmt_expand_format(dasdfmt_info_t *info, unsigned int cylinders,
unsigned int heads, format_data_t *p)
{
if (!((info->withoutprompt) && (info->verbosity < 1)))
printf("Formatting the device. This may take a while "
"(get yourself a coffee).\n");
if (info->verbosity > 0)
printf("Detaching the device...\n");
if (ioctl(filedes, BIODASDDISABLE, p) != 0)
ERRMSG_EXIT(EXIT_FAILURE, "%s: (prepare device) IOCTL "
"BIODASDDISABLE failed. (%s)\n", prog_name,
strerror(errno));
disk_disabled = 1;
dasdfmt_format(info, cylinders, heads, p);
if (info->verbosity > 0)
printf("Formatting tracks complete...\n");
if (info->verbosity > 0)
printf("Re-accessing the device...\n");
if (ioctl(filedes, BIODASDENABLE, p) != 0)
ERRMSG_EXIT(EXIT_FAILURE, "%s: (prepare device) IOCTL "
"BIODASDENABLE failed. (%s)\n", prog_name,
strerror(errno));
disk_disabled = 0;
}
/*
* 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,
unsigned int heads, format_data_t *p)
{
format_check_t cdata = { .expect = {0}, 0 };
format_data_t tmp = *p;
if (info->force) {
printf("Skipping format check due to --force.\n");
} else {
check_blocksize(info, 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);
if (!cdata.result) {
tmp.start_unit = (cylinders * heads) - 3;
tmp.stop_unit = (cylinders * heads) - 1;
cdata = check_track_format(info, &tmp);
}
if (cdata.result) {
evaluate_format_error(info, &cdata, heads);
ERRMSG_EXIT(EXIT_FAILURE, "Use --mode=full to perform "
"a clean format.\n");
} else {
printf("Done. Disk seems fine.\n");
}
}
if (!((info->withoutprompt) && (info->verbosity < 1)))
printf("Formatting the first two tracks of the device.\n");
/* Disable the device before we do anything */
if (ioctl(filedes, BIODASDDISABLE, p))
ERRMSG_EXIT(EXIT_FAILURE, "%s: the ioctl to disable the device "
"failed. (%s)\n", prog_name, strerror(errno));
disk_disabled = 1;
/* Now do the actual formatting of our first two tracks */
if (ioctl(filedes, BIODASDFMT, p))
ERRMSG_EXIT(EXIT_FAILURE, "%s: the ioctl to format the device "
"failed. (%s)\n", prog_name, strerror(errno));
/* Re-Enable the device so that we can continue working with it */
if (ioctl(filedes, BIODASDENABLE, p))
ERRMSG_EXIT(EXIT_FAILURE, "%s: the ioctl to enable the device "
"failed. (%s)\n", prog_name, strerror(errno));
disk_disabled = 0;
}
static void do_format_dasd(dasdfmt_info_t *info, volume_label_t *vlabel,
format_data_t *p, unsigned int cylinders,
unsigned int heads)
{
char inp_buffer[5];
int count;
p->start_unit = 0;
switch (mode) {
case FULL: /* all tracks */
p->stop_unit = (cylinders * heads) - 1;
break;
case QUICK: /* just the first two */
p->stop_unit = 1;
break;
case EXPAND: /* only the end of the disk */
dasdfmt_find_start(info, cylinders, heads, p);
p->stop_unit = (cylinders * heads) - 1;
break;
}
if ((info->verbosity > 0) || !info->withoutprompt || info->testmode)
dasdfmt_print_info(info, vlabel, cylinders, heads, p);
count = u2s_get_host_access_count(info->devname);
if (info->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, info->devname, count);
} else if (count < 0) {
ERRMSG("\nHosts access information not available for disk %s.\n\n",
info->devname);
return;
}
} else if (count > 1)
ERRMSG("\nWARNING:\n"
"Disk %s is online on operating system instances in %d different LPARs.\n"
"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",
info->devname, count);
if (!info->testmode) {
if (!info->withoutprompt) {
printf("\n");
if (mode != EXPAND)
printf("--->> ATTENTION! <<---\nAll data of "
"that device will be lost.\n");
printf("Type \"yes\" to continue, no will leave the "
"disk untouched: ");
if (fgets(inp_buffer, sizeof(inp_buffer), stdin) == NULL)
return;
if (strcasecmp(inp_buffer, "yes") &&
strcasecmp(inp_buffer, "yes\n")) {
printf("Omitting ioctl call (disk will "
"NOT be formatted).\n");
return;
}
}
switch (mode) {
case FULL:
dasdfmt_prepare_and_format(info, cylinders, heads, p);
break;
case QUICK:
dasdfmt_quick_format(info, cylinders, heads, p);
break;
case EXPAND:
dasdfmt_expand_format(info, cylinders, heads, p);
break;
}
printf("Finished formatting the device.\n");
if (!(info->writenolabel || mode == EXPAND))
dasdfmt_write_labels(info, vlabel, cylinders, heads);
printf("Rereading the partition table... ");
if (reread_partition_table()) {
ERRMSG("%s: error during rereading the partition "
"table: %s.\n", prog_name, strerror(errno));
} else {
printf("ok\n");
}
}
}
int main(int argc, char *argv[])
{
dasdfmt_info_t info = {
.dasd_info = {0},
{0}
};
volume_label_t vlabel;
char old_volser[7];
char dev_filename[PATH_MAX];
char str[ERR_LENGTH];
char buf[7];
char *blksize_param_str = NULL;
char *reqsize_param_str = NULL;
char *hashstep_str = NULL;
int rc;
unsigned int cylinders, heads;
/* Establish a handler for interrupt signals. */
signal(SIGTERM, program_interrupt_signal);
signal(SIGINT, program_interrupt_signal);
signal(SIGQUIT, program_interrupt_signal);
/******************* initialization ********************/
prog_name = argv[0];
util_prg_init(&prg);
util_opt_init(opt_vec, NULL);
/* set default values */
vtoc_volume_label_init(&vlabel);
format_params.blksize = DEFAULT_BLOCKSIZE;
format_params.intensity = DASD_FMT_INT_COMPAT;
mode = FULL;
/*************** parse parameters **********************/
while (1) {
rc = util_opt_getopt_long(argc, argv);
switch (rc) {
case 'F':
info.force = 1;
break;
case 'd':
if (strcasecmp(optarg, "cdl") == 0) {
format_params.intensity |= DASD_FMT_INT_COMPAT;
if (info.writenolabel) {
printf("WARNING: using the cdl "
"format without writing a "
"label doesn't make much "
"sense!\n");
exit(1);
}
} else if (strcasecmp(optarg, "ldl") == 0) {
format_params.intensity &= ~DASD_FMT_INT_COMPAT;
} else {
printf("%s is not a valid option!\n", optarg);
exit(1);
}
info.layout_specified = 1;
break;
case 'y':
info.withoutprompt = 1;
break;
case OPT_NOZERO:
format_params.intensity |= DASD_FMT_INT_FMT_NOR0;
break;
case 't':
info.testmode = 1;
break;
case 'p':
if (!(info.print_hashmarks || info.print_percentage))
info.print_progressbar = 1;
break;
case 'm':
if (!(info.print_progressbar || info.print_percentage)) {
hashstep_str = optarg;
info.print_hashmarks = 1;
}
break;
case 'P':
if (!(info.print_hashmarks || info.print_progressbar))
info.print_percentage = 1;
break;
case 'v':
info.verbosity = 1;
break;
case 'h':
util_prg_print_help();
util_opt_print_help();
exit(EXIT_SUCCESS);
case 'V':
util_prg_print_version();
exit(EXIT_SUCCESS);
case 'l':
strncpy(buf, optarg, 6);
if (check_volser(buf, 0) < 0)
break;
vtoc_volume_label_set_volser(&vlabel, buf);
info.labelspec = 1;
break;
case 'L':
if (format_params.intensity & DASD_FMT_INT_COMPAT) {
printf("WARNING: using the cdl format "
"without writing a label doesn't "
"make much sense!\n");
exit(1);
}
info.writenolabel = 1;
break;
case 'b':
blksize_param_str = optarg;
info.blksize_specified = 1;
break;
case 'r':
reqsize_param_str = optarg;
info.reqsize_specified = 1;
break;
case 'k':
info.keep_volser = 1;
break;
case 'C':
info.force_host = 1;
break;
case 'M':
if (strcasecmp(optarg, "full") == 0)
mode = FULL;
else if (strcasecmp(optarg, "quick") == 0)
mode = QUICK;
else if (strcasecmp(optarg, "expand") == 0)
mode = EXPAND;
else
ERRMSG_EXIT(EXIT_FAILURE,
"%s: The specified mode '%s' is "
"invalid. Consult the man page for "
"more information.\n",
prog_name, optarg);
break;
case OPT_CHECK:
info.check = 1;
break;
case -1:
/* End of options string - start of devices list */
info.device_id = optind;
break;
default:
ERRMSG_EXIT(EXIT_MISUSE, "Try '%s --help' for more"
" information.\n", prog_name);
}
if (rc == -1)
break; /* exit loop if finished */
}
CHECK_SPEC_MAX_ONCE(info.blksize_specified, "blocksize");
CHECK_SPEC_MAX_ONCE(info.labelspec, "label");
CHECK_SPEC_MAX_ONCE(info.writenolabel, "omit-label-writing flag");
if (info.blksize_specified)
PARSE_PARAM_INTO(format_params.blksize, blksize_param_str, 10,
"blocksize");
if (info.reqsize_specified) {
PARSE_PARAM_INTO(reqsize, reqsize_param_str, 10, "requestsize");
if (reqsize < 1 || reqsize > 255)
ERRMSG_EXIT(EXIT_FAILURE,
"invalid requestsize %d specified\n",
reqsize);
} else {
reqsize = DEFAULT_REQUESTSIZE;
}
if (info.print_hashmarks)
PARSE_PARAM_INTO(info.hashstep, hashstep_str, 10, "hashstep");
get_device_name(&info, dev_filename, argc, argv);
filedes = open(info.devname, O_RDWR);
if (filedes == -1)
ERRMSG_EXIT(EXIT_FAILURE, "%s: Unable to open device %s: %s\n",
prog_name, info.devname, strerror(errno));
get_device_info(&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(&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(&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, info.devname);
}
check_disk(&info);
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, &vlabel, &format_params, cylinders, heads);
if (close(filedes) != 0)
ERRMSG("%s: error during close: %s\ncontinuing...\n",
prog_name, strerror(errno));
return 0;
}