Subject: [PATCH] [FEAT LS1501] dasdfmt: Add new formatting modes From: Jan Höppner Summary: dasdfmt: Add new formatting modes Description: Introduce new formatting modes 'quick' and 'expand' to either format an earlier formatted DASD that could potentially be re-initialized very easily or format unformatted tracks at the end of a device that was previously extended. Also add the command line argument --check to provide a function that checks a DASD volume for correct formatting. Upstream-ID: - Problem-ID: LS1501 Upstream-Description: dasdfmt: Make progress output reusable and add ETR The progress indicator (in form of a progressbar, hashmarks or percentages) is created within the formatting loop. Put the drawing of the progress into a separate function to make it reusable. Clean up the formatting loop while at it and make it more readable. Also, add the estimated time remaining to the output. Signed-off-by: Jan Höppner Signed-off-by: Stefan Haberland Signed-off-by: Jan Höppner --- dasdfmt/dasdfmt.c | 198 +++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 138 insertions(+), 60 deletions(-) --- a/dasdfmt/dasdfmt.c +++ b/dasdfmt/dasdfmt.c @@ -11,6 +11,7 @@ #include #include +#include #include "zt_common.h" #include "dasdfmt.h" @@ -20,6 +21,8 @@ #include #define BUSIDSIZE 8 +#define SEC_PER_DAY (60 * 60 * 24) +#define SEC_PER_HOUR (60 * 60) /* Full tool name */ static const char tool_name[] = "dasdfmt: zSeries DASD format program"; @@ -88,6 +91,120 @@ static void exit_usage(int exitcode) exit(exitcode); } +/* + * 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 remaining. + */ +static void print_etr(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) +{ + 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) { + /* 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); + print_etr(p_new, started); + started = 1; + } + printf("\r"); + fflush(stdout); + } + + if (info->print_hashmarks && + (cyl / info->hashstep - hashcount) != 0) { + printf("%d|", info->procnum); + 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; @@ -906,9 +1023,10 @@ static void dasdfmt_write_labels(dasdfmt static void dasdfmt_format(dasdfmt_info_t *info, unsigned int cylinders, unsigned int heads, format_data_t *format_params) { - format_data_t format_step; - int j, cyl, tmp, p1, p2, hashcount = 0; - unsigned int k; + unsigned int step_value; + unsigned long cur_trk; + format_data_t step; + int cyl = 0; if (info->print_hashmarks) { if (info->hashstep < reqsize) @@ -923,73 +1041,33 @@ static void dasdfmt_format(dasdfmt_info_ info->hashstep); } - format_step.blksize = format_params->blksize; - format_step.intensity = format_params->intensity; - - k = 0; - cyl = 1; - if ((info->print_progressbar || info->print_hashmarks) && !info->yast_mode) - printf("\n"); - - while (1) { - p1 = -1; - p2 = 0; - if (k + heads * reqsize >= format_params->stop_unit) - reqsize = 1; - format_step.start_unit = k; - format_step.stop_unit = k + reqsize * heads - 1; + step = *format_params; + cur_trk = format_params->start_unit; - if (cyl == 1) - format_step.start_unit += 1; + while (cur_trk < format_params->stop_unit) { + step_value = reqsize * heads - (cur_trk % heads); + step.start_unit = cur_trk; + if (cur_trk + reqsize * heads >= format_params->stop_unit) + step.stop_unit = format_params->stop_unit; + else + step.stop_unit = cur_trk + step_value - 1; - if (ioctl(filedes, BIODASDFMT, &format_step) != 0) + if (ioctl(filedes, BIODASDFMT, &step) != 0) ERRMSG_EXIT(EXIT_FAILURE, "%s: (format cylinder) IOCTL " "BIODASDFMT failed. (%s)\n", prog_name, strerror(errno)); - if (info->print_progressbar) { - printf("cyl %7d of %7d |", cyl, cylinders); - p2 = p1; - p1 = cyl * 100 / cylinders; - if (p1 != p2) { - /* percent value has changed */ - tmp = cyl * 50 / cylinders; - for (j = 1; j <= tmp; j++) - printf("#"); - for (j = tmp + 1; j <= 50; j++) - printf("-"); - printf("|%3d%%", p1); - } - printf("\r"); - fflush(stdout); - } - - if (info->print_hashmarks) - if ((cyl / info->hashstep - hashcount) != 0) { - printf("%d|",info->procnum); - fflush(stdout); - hashcount++; - } - - if (info->print_percentage) { - printf("cyl %7d of %7d |%3d%%\n", cyl, cylinders, - cyl*100/cylinders); - fflush(stdout); - } + cyl = cur_trk / heads + 1; + draw_progress(info, cyl, cylinders); - if (k % heads == 0) { - k += reqsize * heads; - cyl += reqsize; - } else { - k += format_params->stop_unit % heads; - } - - if (k > format_params->stop_unit) - break; + cur_trk += step_value; } + /* We're done, draw the 100% mark */ + cyl = step.stop_unit / heads + 1; + draw_progress(info, cyl, cylinders); if ((info->print_progressbar || info->print_hashmarks) && !info->yast_mode) - printf("\n\n"); + printf("\n"); } static void dasdfmt_prepare_and_format(dasdfmt_info_t *info,