Import version 1.8.3
[s390-tools.git] / fdasd / fdasd.c
blobaa16659b22a104253e7b8787f7d796cefb371ca0
1 /*
2 * File...........: s390-tools/fdasd/fdasd.c
3 * Author(s)......: Volker Sameske <sameske@de.ibm.com>
4 * Horst Hummel <horst.hummel@de.ibm.com>
5 * Gerhard Tonn <ton@de.ibm.com>
6 * Copyright IBM Corp. 2001,2007
7 */
9 #include <getopt.h>
11 #include "zt_common.h"
12 #include "vtoc.h"
13 #include "fdasd.h"
15 /* global variables */
16 struct hd_geometry geo;
17 char line_buffer[LINE_LENGTH];
18 char *line_ptr = line_buffer;
20 /* Full tool name */
21 static const char tool_name[] = "fdasd: zSeries DASD partitioning program";
23 /* Copyright notice */
24 static const char copyright_notice[] = "Copyright IBM Corp. 2001, 2006";
27 * Print version information.
29 static void
30 print_version (void)
32 printf ("%s version %s\n", tool_name, RELEASE_STRING);
33 printf ("%s\n", copyright_notice);
36 static int
37 getpos (fdasd_anchor_t *anc, int dsn)
39 return anc->partno[dsn];
42 static int
43 getdsn (fdasd_anchor_t *anc, int pos)
45 int i;
47 for (i=0; i<USABLE_PARTITIONS; i++) {
48 if (anc->partno[i] == pos)
49 return i;
52 return -1;
55 static void
56 setpos (fdasd_anchor_t *anc, int dsn, int pos)
58 anc->partno[dsn] = pos;
61 static u_int32_t get_usable_cylinders(fdasd_anchor_t *anc)
63 u_int32_t cyl;
65 /* large volume */
66 if (anc->f4->DS4DEVCT.DS4DSCYL == LV_COMPAT_CYL &&
67 anc->f4->DS4DCYL > anc->f4->DS4DEVCT.DS4DSCYL)
68 return anc->f4->DS4DCYL;
69 /* normal volume */
70 if (anc->f4->DS4DEVCT.DS4DEVFG & ALTERNATE_CYLINDERS_USED)
71 cyl = anc->f4->DS4DEVCT.DS4DSCYL -
72 (u_int16_t) anc->f4->DS4DEVAC;
73 else
74 cyl = anc->f4->DS4DEVCT.DS4DSCYL;
75 return cyl;
78 static void get_addr_of_highest_f1_f8_label(fdasd_anchor_t *anc, cchhb_t *addr)
81 u_int8_t record;
82 /* We have to count the follwing labels:
83 * one format 4
84 * one format 5
85 * format 7 only if we have moren then BIG_DISK_SIZE tracks
86 * one for each format 1 or format 8 label == one for each partition
87 * one for each format 9 label before the last format 8
88 * We assume that all partitions use format 8 labels when
89 * anc->formatted_cylinders > LV_COMPAT_CYL
90 * Note: Record zero is special, so block 0 on our disk is record 1!
93 record = anc->used_partitions + 2;
94 if (anc->big_disk)
95 record++;
96 if (anc->formatted_cylinders > LV_COMPAT_CYL)
97 record += anc->used_partitions - 1;
98 vtoc_set_cchhb(addr, VTOC_START_CC, VTOC_START_HH, record);
102 * Check for valid volume serial characters (max. 6) - remove invalid.
103 * If volser is empty, fill with default volser.
105 static void
106 fdasd_check_volser(char *volser, int devno)
108 int from, to;
110 for (from=0, to=0; volser[from] && from < VOLSER_LENGTH; from++)
111 if ((volser[from] >= 0x23 &&
112 volser[from] <= 0x25) || /* # $ % */
113 (volser[from] >= 0x30 &&
114 volser[from] <= 0x39) || /* 0-9 */
115 (volser[from] >= 0x40 &&
116 volser[from] <= 0x5a) || /* @ A-Z */
117 (volser[from] >= 0x61 &&
118 volser[from] <= 0x7a)) /* a-z */
119 volser[to++] = toupper(volser[from]);
121 volser[to] = 0x00;
123 if (volser[0] == 0x00) {
124 sprintf(volser, "0X%04x", devno);
130 * Free memory of fdasd anchor struct.
132 static void
133 fdasd_cleanup (fdasd_anchor_t *anchor)
135 partition_info_t *part_info, *next;
136 int i;
138 if (anchor == NULL) return;
140 if (anchor->f4 != NULL) free(anchor->f4);
141 if (anchor->f5 != NULL) free(anchor->f5);
142 if (anchor->f7 != NULL) free(anchor->f7);
143 if (anchor->vlabel != NULL) free(anchor->vlabel);
145 part_info = anchor->first;
146 for (i = 1; i <= USABLE_PARTITIONS && part_info != NULL; i++) {
147 next = part_info->next;
148 free(part_info);
149 part_info = next;
155 * Exit fdasd.
157 static void
158 fdasd_exit (fdasd_anchor_t *anchor, int rc)
160 fdasd_cleanup(anchor);
161 exit(rc);
168 static void
169 fdasd_error(fdasd_anchor_t *anc, enum fdasd_failure why, char *str)
171 char err_str[ERROR_STRING_SIZE];
173 switch (why) {
174 case parser_failed:
175 snprintf(err_str, ERROR_STRING_SIZE,
176 "%s parser error\n%s\n", FDASD_ERROR, str);
177 break;
178 case unable_to_open_disk:
179 snprintf(err_str, ERROR_STRING_SIZE,
180 "%s open error\n%s\n", FDASD_ERROR, str);
181 break;
182 case unable_to_seek_disk:
183 snprintf(err_str, ERROR_STRING_SIZE,
184 "%s seek error\n%s\n", FDASD_ERROR, str);
185 break;
186 case unable_to_read_disk:
187 snprintf(err_str, ERROR_STRING_SIZE,
188 "%s read error\n%s\n", FDASD_ERROR, str);
189 break;
190 case read_only_disk:
191 snprintf(err_str, ERROR_STRING_SIZE,
192 "%s write error\n%s\n", FDASD_ERROR, str);
193 break;
194 case unable_to_ioctl:
195 snprintf(err_str, ERROR_STRING_SIZE,
196 "%s IOCTL error\n%s\n", FDASD_ERROR, str);
197 break;
198 case wrong_disk_type:
199 snprintf(err_str, ERROR_STRING_SIZE,
200 "%s Unsupported disk type\n%s\n",
201 FDASD_ERROR, str);
202 break;
203 case wrong_disk_format:
204 snprintf(err_str, ERROR_STRING_SIZE,
205 "%s Unsupported disk format\n%s\n",
206 FDASD_ERROR, str);
207 break;
208 case disk_in_use:
209 snprintf(err_str, ERROR_STRING_SIZE,
210 "%s Disk in use\n%s\n", FDASD_ERROR, str);
211 break;
212 case config_syntax_error:
213 snprintf(err_str, ERROR_STRING_SIZE,
214 "%s Config file syntax error\n%s\n",
215 FDASD_ERROR, str);
216 break;
217 case vlabel_corrupted:
218 snprintf(err_str, ERROR_STRING_SIZE,
219 "%s Volume label is corrupted.\n%s\n",
220 FDASD_ERROR, str);
221 break;
222 case dsname_corrupted:
223 snprintf(err_str, ERROR_STRING_SIZE,
224 "%s a data set name is corrupted.\n%s\n",
225 FDASD_ERROR, str);
226 break;
227 case malloc_failed:
228 snprintf(err_str, ERROR_STRING_SIZE,
229 "%s space allocation\n%s\n", FDASD_ERROR, str);
230 break;
231 case device_verification_failed:
232 snprintf(err_str, ERROR_STRING_SIZE,
233 "%s device verification failed\n%s\n",
234 FDASD_ERROR, str);
235 break;
236 case volser_not_found:
237 snprintf(err_str, ERROR_STRING_SIZE,
238 "%s VOLSER not found on device %s\n",
239 FDASD_ERROR, str);
240 break;
241 default:
242 snprintf(err_str, ERROR_STRING_SIZE,
243 "%s Fatal error\n%s\n",
244 FDASD_ERROR, str);
247 fputc('\n', stderr);
248 fputs(err_str, stderr);
250 fdasd_exit(anc, -1);
255 * Read line from stdin into global line_buffer
256 * and set global line_ptr to first printing character except space.
258 static int
259 read_line(void)
261 bzero(line_buffer, LINE_LENGTH);
262 line_ptr = line_buffer;
263 if (!fgets(line_buffer, LINE_LENGTH, stdin))
264 return 0;
265 while (*line_ptr && !isgraph(*line_ptr))
266 line_ptr++;
267 return *line_ptr;
274 static char
275 read_char(char *mesg)
277 fputs(mesg, stdout);
278 read_line();
280 return *line_ptr;
285 * Print question string an enforce y/n answer.
287 static int
288 yes_no(char *question_str)
290 char answer;
291 int rc;
292 while (1) {
293 printf("%s (y/n): ", question_str);
294 rc = scanf("%c", &answer);
295 if (rc != 1)
296 return -1;
297 if (answer == 'y') return 0;
298 if (answer == 'n') return 1;
306 static char *
307 fdasd_partition_type (char *str)
309 if (strncmp("NATIVE", str, 6) == 0)
310 strcpy(str, "Linux native");
311 else if (strncmp("NEW ", str, 6) == 0)
312 strcpy(str, "Linux native");
313 else if (strncmp("SWAP ", str, 6) == 0)
314 strcpy(str, "Linux swap");
315 else
316 strcpy(str, "unknown");
318 return str;
323 * prints out the usage text
325 static void
326 fdasd_usage (void)
328 printf ("\nUsage: fdasd [OPTIONS] [DEVICE]\n"
329 "\n"
330 "Partition a DASD device either in interactive mode or "
331 "automatically.\n"
332 "DEVICE is the node of the device (e.g. '/dev/dasda')\n"
333 "\n"
334 "-h, --help Print this help, then exit\n"
335 "-v, --version Print version information, "
336 "then exit\n"
337 "-s, --silent Suppress messages\n"
338 "-r, --verbose Provide more verbose output\n"
339 "-a, --auto Automatically create a partition "
340 "using the entire disk\n"
341 "-k, --keep_volser Keep current volume serial when "
342 "performing automatic\n"
343 " partitioning\n"
344 "-l, --label VOLSER Set the volume serial to VOLSER "
345 "when performing\n"
346 " automatic partitioning\n"
347 "-c, --config CONFIGFILE Automatically create partition(s) "
348 "using information\n"
349 " found in CONFIGFILE\n"
350 "-i, --volser Print volume serial\n"
351 "-p, --table Print partition table\n");
356 * prints the menu
358 static void
359 fdasd_menu (void)
361 printf("Command action\n"
362 " m print this menu\n"
363 " p print the partition table\n"
364 " n add a new partition\n"
365 " d delete a partition\n"
366 " v change volume serial\n"
367 " t change partition type\n"
368 " r re-create VTOC and delete all partitions\n"
369 " u re-create VTOC re-using existing partition sizes\n"
370 " s show mapping (partition number - data set name)\n"
371 " q quit without saving changes\n"
372 " w write table to disk and exit\n");
377 * initializes the anchor structure and allocates some
378 * memory for the labels
380 static void
381 fdasd_initialize_anchor (fdasd_anchor_t *anc)
383 partition_info_t *part_info, *prev_part_info;
384 volume_label_t *vlabel;
385 int i;
387 bzero(anc, sizeof(fdasd_anchor_t));
389 for (i=0; i<USABLE_PARTITIONS; i++)
390 setpos(anc, i, -1);
392 anc->f4 = malloc(sizeof(format4_label_t));
393 if (anc->f4 == NULL)
394 fdasd_error(anc, malloc_failed,
395 "FMT4 DSCB memory allocation failed.");
397 anc->f5 = malloc(sizeof(format5_label_t));
398 if (anc->f5 == NULL)
399 fdasd_error(anc, malloc_failed,
400 "FMT5 DSCB memory allocation failed.");
402 anc->f7 = malloc(sizeof(format7_label_t));
403 if (anc->f7 == NULL)
404 fdasd_error(anc, malloc_failed,
405 "FMT7 DSCB memory allocation failed.");
407 /* template for all format 9 labels */
408 anc->f9 = malloc(sizeof(format9_label_t));
409 if (anc->f9 == NULL)
410 fdasd_error(anc, malloc_failed,
411 "FMT9 DSCB memory allocation failed.");
413 bzero(anc->f4, sizeof(format4_label_t));
414 bzero(anc->f5, sizeof(format5_label_t));
415 bzero(anc->f7, sizeof(format7_label_t));
416 bzero(anc->f9, sizeof(format9_label_t));
417 vtoc_init_format9_label(anc->f9);
419 vlabel = malloc(sizeof(volume_label_t));
420 if (vlabel == NULL)
421 fdasd_error(anc, malloc_failed,
422 "Volume label memory allocation failed.");
423 bzero(vlabel, sizeof(volume_label_t));
424 anc->vlabel = vlabel;
426 for (i=1; i<=USABLE_PARTITIONS; i++) {
427 part_info = malloc(sizeof(partition_info_t));
428 if (part_info == NULL)
429 fdasd_error(anc, malloc_failed,
430 "Partition info memory allocation failed.");
431 part_info->used = 0x00;
432 part_info->len_trk = 0;
433 part_info->start_trk = 0;
434 part_info->fspace_trk = 0;
436 /* add part_info to double pointered list */
437 if (i == 1) {
438 anc->first = part_info;
439 part_info->prev = NULL;
441 else if (i == USABLE_PARTITIONS) {
442 anc->last = part_info;
443 part_info->next = NULL;
444 part_info->prev = prev_part_info;
445 prev_part_info->next = part_info;
447 else {
448 part_info->prev = prev_part_info;
449 prev_part_info->next = part_info;
452 part_info->f1 = malloc(sizeof(format1_label_t));
453 if (part_info->f1 == NULL)
454 fdasd_error(anc, malloc_failed,
455 "FMT1 DSCB memory allocation failed.");
456 bzero(part_info->f1, sizeof(format1_label_t));
458 prev_part_info = part_info;
460 anc->hw_cylinders = 0;
461 anc->formatted_cylinders = 0;
466 * parses the command line options
468 static void
469 fdasd_parse_options (fdasd_anchor_t *anc, struct fdasd_options *options,
470 int argc, char *argv[])
472 int opt, index;
474 do {
475 opt = getopt_long(argc, argv, option_string,
476 fdasd_long_options, &index);
477 switch (opt) {
478 case 'v':
479 print_version();
480 fdasd_exit(anc, 0);
481 case 'h':
482 fdasd_usage ();
483 fdasd_exit(anc, 0);
484 case 'l':
485 if (options->volser)
486 fdasd_error(anc, parser_failed,
487 "Option 'label' specified more "
488 "than once.\n");
489 options->volser = optarg;
490 break;
491 case 'a':
492 anc->auto_partition++;
493 break;
494 case 's':
495 anc->silent++;
496 break;
497 case 'r':
498 anc->verbose++;
499 break;
500 case 'p':
501 anc->print_table++;
502 break;
503 case 'i':
504 anc->print_volser++;
505 anc->silent++;
506 break;
507 case 'c':
508 if (options->conffile)
509 fdasd_error(anc, parser_failed,
510 "Option 'config' specified more"
511 " than once.\n");
512 options->conffile = optarg;
513 break;
514 case 'k':
515 anc->keep_volser++;
516 break;
517 case -1:
518 /* End of options string - start of devices list */
519 break;
520 default:
521 fprintf(stderr, "Try 'fdasd --help' for more"
522 " information.\n");
523 fdasd_exit(anc, 1);
525 } while (opt != -1);
527 /* save device */
528 if (optind >= argc)
529 fdasd_error(anc, parser_failed,
530 "No device speficied.\n");
531 if (optind + 1 < argc)
532 fdasd_error(anc, parser_failed,
533 "More than one device speficied.\n");
534 options->device = argv[optind];
539 * parses config file
541 static int
542 fdasd_parse_conffile(fdasd_anchor_t *anc, struct fdasd_options *options)
544 char buffer[USABLE_PARTITIONS * LINE_LENGTH];
545 char err_str[ERROR_STRING_SIZE], *c1, *c2;
546 int fd, rc;
547 unsigned i=0;
549 /* if name of config file was not specified, select the default */
550 if (options->conffile == NULL)
551 options->conffile = DEFAULT_FDASD_CONF;
553 if (!anc->silent)
554 printf("parsing config file '%s'...\n", options->conffile);
555 fd = open(options->conffile, O_RDONLY);
556 if (fd < 0) {
557 snprintf(err_str, ERROR_STRING_SIZE,
558 "Could not open config file '%s' "
559 "in read-only mode!\n", options->conffile);
560 fdasd_error(anc, unable_to_open_disk, err_str);
563 bzero(buffer, sizeof(buffer));
564 rc = read(fd, buffer, sizeof(buffer));
565 if (rc < 0)
566 return -1;
567 close(fd);
570 for (i=0; i<sizeof(buffer); i++)
571 buffer[i] = toupper(buffer[i]);
573 c1 = buffer;
575 for (i=0; i<USABLE_PARTITIONS; i++) {
576 char *token, *stopstring;
578 c1 = strchr(c1, '[');
579 if (c1 == NULL) {
580 if (!anc->silent)
581 printf("no config file entry for " \
582 "partition %d found...\n", i+1);
583 break;
585 c1 += 1;
587 c2 = strchr(c1, ']');
588 if (c2 == NULL) {
589 snprintf(err_str, ERROR_STRING_SIZE,
590 "']' missing in config file " \
591 "%s\n", options->conffile);
592 fdasd_error(anc, config_syntax_error, err_str);
594 strcpy(c2, "");
596 token = strtok(c1, ",");
597 if (strstr(token, "FIRST") != NULL)
598 anc->confdata[i].start=FIRST_USABLE_TRK;
599 else
600 anc->confdata[i].start=strtol(token, &stopstring, 10);
602 token = strtok(NULL, ",");
603 if (strstr(token, "LAST") != NULL)
604 anc->confdata[i].stop = anc->formatted_cylinders
605 * geo.heads - 1;
606 else
607 anc->confdata[i].stop = strtol(token, &stopstring, 10);
608 c1 = c2 + 1;
611 return 0;
616 * checks input from config file
618 static void
619 fdasd_check_conffile_input (fdasd_anchor_t *anc,
620 struct fdasd_options *options)
622 partition_info_t *part_info = anc->first;
623 int i;
625 if (anc->verbose) printf("checking config file data...\n");
626 for (i=0; i<USABLE_PARTITIONS; i++) {
627 unsigned long start, stop, first_trk, last_trk;
628 char err_str[ERROR_STRING_SIZE];
630 start = anc->confdata[i].start;
631 stop = anc->confdata[i].stop;
633 if ((start == 0) || (stop == 0)) break;
635 first_trk = FIRST_USABLE_TRK;
636 last_trk = anc->formatted_cylinders * geo.heads - 1;
638 if ((start < first_trk) || (start > last_trk)) {
639 snprintf(err_str, ERROR_STRING_SIZE,
640 "One of the lower partition limits "
641 "(%ld) is not within the range of \n "
642 "available tracks on disk (%ld-%ld)!\n",
643 start, first_trk, last_trk);
644 fdasd_error(anc, config_syntax_error, err_str);
647 if ((stop < first_trk) || (stop > last_trk)) {
648 snprintf(err_str, ERROR_STRING_SIZE,
649 "One of the upper partition limits "
650 "(%ld) is not within the range of \n "
651 "available tracks on disk (%ld-%ld)!\n",
652 stop, first_trk, last_trk);
653 fdasd_error(anc, config_syntax_error, err_str);
656 if (start >= stop) {
657 snprintf(err_str, ERROR_STRING_SIZE,
658 "Lower partition limit (%ld) is not "
659 "less than upper partition \nlimit (%ld) "
660 "in config file %s!\n",
661 start, stop, options->conffile);
662 fdasd_error(anc, config_syntax_error, err_str);
665 if ((i > 0) && (start <= anc->confdata[i-1].stop)) {
666 snprintf(err_str, ERROR_STRING_SIZE,
667 "Partitions overlap or are not in "
668 "ascending order!\n");
669 fdasd_error(anc, config_syntax_error, err_str);
672 if ((i < (USABLE_PARTITIONS - 1)) &&
673 (anc->confdata[i+1].start > 0) &&
674 (stop >= anc->confdata[i+1].start)) {
675 snprintf(err_str, ERROR_STRING_SIZE,
676 "Partitions overlap or are not in "
677 "ascending order!\n");
678 fdasd_error(anc, config_syntax_error, err_str);
681 part_info->used = 0x01;
682 part_info->start_trk = start;
683 part_info->end_trk = stop;
684 part_info->len_trk = stop - start + 1;
686 /* update the current free space counter */
687 if (i == 0)
688 anc->fspace_trk = start - FIRST_USABLE_TRK;
690 if (i < USABLE_PARTITIONS - 1) {
691 if (anc->confdata[i+1].start != 0)
692 part_info->fspace_trk =
693 anc->confdata[i+1].start-stop-1;
694 else
695 part_info->fspace_trk = last_trk - stop;
697 else if (i == USABLE_PARTITIONS - 1)
698 part_info->fspace_trk = last_trk - stop;
700 part_info = part_info->next;
702 return;
707 * Verifies the specified block device.
709 static void
710 fdasd_verify_device (fdasd_anchor_t *anc, char *name)
712 struct stat dst;
713 char err_str[ERROR_STRING_SIZE];
715 if ((stat(name, &dst)) < 0 ) {
716 snprintf(err_str, ERROR_STRING_SIZE,
717 "Unable to get device status for device '%s'\n",
718 name);
719 fdasd_error(anc, device_verification_failed, err_str);
722 if (!(S_ISBLK (dst.st_mode))) {
723 snprintf(err_str, ERROR_STRING_SIZE,
724 "Device '%s' (%d/%d) is not a block device\n", name,
725 (unsigned short) major(dst.st_rdev),
726 (unsigned short) minor(dst.st_rdev));
727 fdasd_error(anc, device_verification_failed, err_str);
730 if (minor (dst.st_rdev) & PARTN_MASK) {
731 snprintf(err_str, ERROR_STRING_SIZE,
732 "Partition '%s' (%d/%d) detected where device is "
733 "required\n", name,
734 (unsigned short) major(dst.st_rdev),
735 (unsigned short) minor(dst.st_rdev));
737 fdasd_error(anc, device_verification_failed, err_str);
740 if (anc->verbose)
741 printf("Verification successful for '%s' (%d/%d)\n", name,
742 (unsigned short) major(dst.st_rdev),
743 (unsigned short) minor(dst.st_rdev));
748 * Verifies the specified fdasd command line option
749 * combinations.
751 * Note:
752 * - 'version' and 'help' are priority options.
753 * All other paramters are ignored in that case.
754 * - 'silent' and 'verbose' are allways allowed in any
755 * combination.
758 static void
759 fdasd_verify_options (fdasd_anchor_t *anc)
761 /* Checked option combinations */
762 /* (inv = invalid / req = required / opt = optional) */
763 /* */
764 /* vols labe keep auto conf tabl */
765 /* er l _vol if e */
766 /* ser */
767 /* */
768 /* volser - inv INV inv inv inv */
769 /* label - inv REQ INV inv */
770 /* keep_volser - REQ INV inv */
771 /* auto - inv inv */
772 /* config - inv */
773 /* table - */
775 if (anc->print_volser &&
776 (options.volser || anc->keep_volser || anc->auto_partition ||
777 options.conffile || anc->print_table)) {
778 fdasd_error(anc, parser_failed,
779 "Option 'volser' cannot be used with other"
780 " options.\n");
783 if (options.volser) {
784 if (!anc->auto_partition) {
785 fdasd_error(anc, parser_failed,
786 "Option 'auto' required when specifying"
787 " 'label'\n");
789 if ((anc->keep_volser || options.conffile ||
790 anc->print_table)) {
791 fdasd_error(anc, parser_failed,
792 "Option 'label' cannot be used with "
793 "'keep_volser', 'config' and 'table'.\n");
797 if (anc->keep_volser) {
798 if (!anc->auto_partition) {
799 fdasd_error(anc, parser_failed,
800 "Option 'auto' required when specifying"
801 " 'keep_volser'\n");
803 if (options.conffile || anc->print_table) {
804 fdasd_error(anc, parser_failed,
805 "Option 'keep_volser' cannot be used"
806 " with 'config' and 'table'.\n");
809 if (anc->auto_partition &&
810 (options.conffile || anc->print_table)) {
811 fdasd_error(anc, parser_failed,
812 "Option 'auto' cannot be used with "
813 "'config' and 'table'.\n");
816 if (options.conffile &&
817 (anc->print_table)) {
818 fdasd_error(anc, parser_failed,
819 "Option 'config' cannot be used with"
820 " 'table'.\n");
826 * print mapping: partition number - data set name
828 static void
829 fdasd_show_mapping (fdasd_anchor_t *anc)
831 char str[20], *dev, dsname[45], *strp;
832 partition_info_t *part_info;
833 int i=0, j=0, dev_len;
835 printf("\ndevice .........: %s\n",options.device);
836 bzero(str, sizeof(str));
837 vtoc_volume_label_get_label(anc->vlabel, str);
838 printf("volume label ...: %.4s\n", str);
839 bzero(str, sizeof(str));
840 vtoc_volume_label_get_volser(anc->vlabel, str);
841 printf("volume serial ..: %s\n\n", str);
843 dev_len = strlen(options.device);
844 dev = malloc(dev_len + 10);
845 if (!dev)
846 fdasd_error(anc, malloc_failed,
847 "Show mapping: memory allocation failed.");
848 strcpy(dev, options.device);
849 if (((strp = strstr(dev,DISC)) != NULL) ||
850 ((strp = strstr(dev,DEVICE)) != NULL))
851 strcpy(strp, PART);
853 printf("WARNING: This mapping may be NOT up-to-date,\n"
854 " if you have NOT saved your last changes!\n\n");
856 for (part_info = anc->first ; part_info != NULL;
857 part_info = part_info->next) {
858 i++;
859 if (part_info->used != 0x01)
860 continue;
862 bzero(dsname, sizeof(dsname));
863 strncpy(dsname, part_info->f1->DS1DSNAM, 44);
864 vtoc_ebcdic_dec(dsname, dsname, 44);
866 if (getdsn(anc, i-1) < 0)
867 sprintf(dsname, "new data set");
869 printf("%s%-2d - %-44s\n", dev, i, dsname);
870 j++;
873 if (j == 0) printf("No partitions defined.\n");
874 free(dev);
879 * prints only the volume serial
881 static void
882 fdasd_print_volser (fdasd_anchor_t *anc)
884 char volser[VOLSER_LENGTH + 1];
886 bzero(volser, VOLSER_LENGTH);
887 vtoc_ebcdic_dec(anc->vlabel->volid, volser, VOLSER_LENGTH);
888 printf("%6.6s\n", volser);
893 * print partition table
895 static void
896 fdasd_list_partition_table (fdasd_anchor_t *anc)
898 partition_info_t *part_info;
899 char str[20], *dev, *strp, *ch;
900 int i=0, dev_len = strlen(options.device);
902 if (!anc->silent) {
903 printf("\nDisk %s: \n"
904 " cylinders ............: %d\n"
905 " tracks per cylinder ..: %d\n"
906 " blocks per track .....: %d\n"
907 " bytes per block ......: %d\n",
908 options.device, anc->formatted_cylinders, geo.heads,
909 geo.sectors, anc->blksize);
911 vtoc_volume_label_get_label(anc->vlabel, str);
912 printf(" volume label .........: %s\n", str);
914 vtoc_volume_label_get_volser(anc->vlabel, str);
916 printf(" volume serial ........: %s\n", str);
917 printf(" max partitions .......: %d\n\n", USABLE_PARTITIONS);
920 if (dev_len < 20)
921 dev_len = 20;
923 if (!anc->silent) {
924 printf(" ------------------------------- tracks"
925 " -------------------------------\n");
926 printf("%*s start end length Id System\n",
927 dev_len + 1, "Device");
930 dev = malloc(dev_len + 10);
931 if (!dev)
932 fdasd_error(anc, malloc_failed,
933 "Print partition table: memory allocation failed.");
934 strcpy(dev, options.device);
935 if (((strp = strstr(dev,DISC)) != NULL) ||
936 ((strp = strstr(dev,DEVICE)) != NULL))
937 strcpy(strp, PART);
939 for (part_info = anc->first; part_info != NULL;
940 part_info = part_info->next) {
941 i++;
943 if ((part_info == anc->first) && (anc->fspace_trk > 0))
944 printf("%*s %9ld%9ld%9ld unused\n",dev_len,"",
945 (unsigned long) FIRST_USABLE_TRK,
946 (unsigned long) FIRST_USABLE_TRK +
947 anc->fspace_trk - 1,
948 anc->fspace_trk);
950 if (part_info->used != 0x01)
951 continue;
953 vtoc_ebcdic_dec(part_info->f1->DS1DSNAM,
954 part_info->f1->DS1DSNAM, 44);
955 ch = strstr(part_info->f1->DS1DSNAM, "PART");
956 if (ch != NULL) {
957 strncpy(str, ch + 9, 6);
958 str[6] = '\0';
959 } else
960 strcpy(str, "error");
962 vtoc_ebcdic_enc(part_info->f1->DS1DSNAM,
963 part_info->f1->DS1DSNAM, 44);
965 printf("%*s%-2d %9ld%9ld%9ld %2x %6s\n",
966 dev_len, dev, i, part_info->start_trk,
967 part_info->end_trk, part_info->len_trk, i,
968 fdasd_partition_type(str));
970 if (part_info->fspace_trk > 0)
971 printf("%*s %9ld%9ld%9ld unused\n",
972 dev_len , "" , part_info->end_trk + 1,
973 part_info->end_trk + part_info->fspace_trk,
974 part_info->fspace_trk);
976 free(dev);
980 * get volser from vtoc
982 static int
983 fdasd_get_volser(fdasd_anchor_t *anc, char *devname, char *volser)
985 dasd_information_t dasd_info;
986 int blksize;
987 int fd;
988 volume_label_t vlabel;
989 char err_str[ERROR_STRING_SIZE];
991 if ((fd = open(devname, O_RDONLY)) == -1) {
992 snprintf(err_str, ERROR_STRING_SIZE,
993 "Could not open device '%s' "
994 "in read-only mode!\n", devname);
995 fdasd_error(anc, unable_to_open_disk, err_str);
998 if (ioctl(fd, BIODASDINFO, &dasd_info) != 0) {
999 close(fd);
1000 fdasd_error(anc, unable_to_ioctl,
1001 "Could not retrieve disk information.");
1004 if (ioctl(fd, BLKSSZGET, &blksize) != 0) {
1005 close(fd);
1006 fdasd_error(anc, unable_to_ioctl,
1007 "Could not retrieve blocksize information.");
1010 close(fd);
1012 if ((strncmp(dasd_info.type, "ECKD", 4) == 0) &&
1013 (!dasd_info.FBA_layout)) {
1014 /* OS/390 and zOS compatible disk layout */
1015 vtoc_read_volume_label(options.device,
1016 dasd_info.label_block * blksize,
1017 &vlabel);
1018 vtoc_volume_label_get_volser(&vlabel, volser);
1019 return 0;
1021 else {
1022 return -1;
1028 * call IOCTL to re-read the partition table
1030 static void
1031 fdasd_reread_partition_table (fdasd_anchor_t *anc)
1033 char err_str[ERROR_STRING_SIZE];
1034 int fd;
1036 if (!anc->silent) printf("rereading partition table...\n");
1038 if ((fd = open(options.device, O_RDONLY)) < 0) {
1039 snprintf(err_str, ERROR_STRING_SIZE,
1040 "Could not open device '%s' "
1041 "in read-only mode!\n", options.device);
1042 fdasd_error(anc, unable_to_open_disk, err_str);
1045 if (ioctl(fd, BLKRRPART, NULL) != 0) {
1046 close(fd);
1047 fdasd_error(anc, unable_to_ioctl, "Error while rereading "
1048 "partition table.\nPlease reboot!");
1050 close(fd);
1055 * writes all changes to dasd
1057 static void
1058 fdasd_write_vtoc_labels (fdasd_anchor_t *anc)
1060 partition_info_t *part_info;
1061 unsigned long blk, maxblk;
1062 char dsno[6], volser[VOLSER_LENGTH + 1], s2[45], *c1, *c2, *ch;
1063 int i=0, k=0;
1064 cchhb_t f9addr;
1065 format1_label_t emptyf1;
1067 if (!anc->silent) printf("writing VTOC...\n");
1068 if (anc->verbose) printf("DSCBs: ");
1070 blk = (cchhb2blk(&anc->vlabel->vtoc, &geo) - 1) * anc->blksize;
1071 if (blk <= 0)
1072 fdasd_error(anc, vlabel_corrupted, "");
1073 maxblk = blk + anc->blksize * 9; /* f4+f5+f7+3*f8+3*f9 */
1075 /* write FMT4 DSCB */
1076 vtoc_write_label(options.device, blk, NULL, anc->f4, NULL, NULL, NULL);
1077 if (anc->verbose) printf("f4 ");
1078 blk += anc->blksize;
1080 /* write FMT5 DSCB */
1081 vtoc_write_label(options.device, blk, NULL, NULL, anc->f5, NULL, NULL);
1082 if (anc->verbose) printf("f5 ");
1083 blk += anc->blksize;
1085 /* write FMT7 DSCB */
1086 if (anc->big_disk) {
1087 vtoc_write_label(options.device, blk, NULL, NULL,
1088 NULL, anc->f7, NULL);
1089 if (anc->verbose) printf("f7 ");
1090 blk += anc->blksize;
1093 /* loop over all partitions (format 1 or format 8 DCB) */
1094 for (part_info = anc->first; part_info != NULL;
1095 part_info = part_info->next) {
1097 if (part_info->used != 0x01) {
1098 continue;
1101 i++;
1102 strncpy((char *)part_info->f1->DS1DSSN, anc->vlabel->volid,
1103 VOLSER_LENGTH);
1105 ch = part_info->f1->DS1DSNAM;
1106 vtoc_ebcdic_dec(ch, ch, 44);
1107 c1 = ch + 7;
1109 if (getdsn(anc, i-1) > -1) {
1110 /* re-use the existing data set name */
1111 c2 = strchr(c1, '.');
1112 if (c2 != NULL)
1113 strncpy(s2, c2, 31);
1114 else
1115 fdasd_error(anc, dsname_corrupted, "");
1117 strncpy(volser, anc->vlabel->volid, VOLSER_LENGTH);
1118 vtoc_ebcdic_dec(volser, volser, VOLSER_LENGTH);
1119 volser[VOLSER_LENGTH] = ' ';
1120 strncpy(c1, volser, VOLSER_LENGTH + 1);
1121 c1 = strchr(ch, ' ');
1122 strncpy(c1, s2, 31);
1124 else {
1125 char *tmp = strstr(ch, "SWAP");
1127 /* create a new data set name */
1128 while (getpos(anc, k) > -1)
1129 k++;
1131 setpos(anc, k, i-1);
1133 strncpy(ch, "LINUX.V "
1134 " ", 44);
1136 strncpy(volser, anc->vlabel->volid, VOLSER_LENGTH);
1137 vtoc_ebcdic_dec(volser, volser, VOLSER_LENGTH);
1138 strncpy(c1, volser, VOLSER_LENGTH);
1140 c1 = strchr(ch, ' ');
1141 strncpy(c1, ".PART", 5);
1142 c1 += 5;
1144 sprintf(dsno,"%04d", k+1);
1145 strncpy(c1, dsno, 4);
1147 c1 += 4;
1148 if (tmp)
1149 strncpy(c1, ".SWAP", 5);
1150 else
1151 strncpy(c1, ".NATIVE", 7);
1153 vtoc_ebcdic_enc(ch, ch, 44);
1154 if (anc->verbose) printf("%2x ", part_info->f1->DS1FMTID);
1156 if (part_info->f1->DS1FMTID == 0xf8) {
1157 /* Now as we know where which label will be written, we
1158 * can add the address of the format 9 label to the
1159 * format 8 label. The f9 record will be written to the
1160 * block after the current blk. Remember: records are of
1161 * by one, so we have to add 2 and not just one.
1163 vtoc_set_cchhb(&f9addr, VTOC_START_CC, VTOC_START_HH,
1164 ((blk / anc->blksize) % geo.sectors)
1165 + 2);
1166 vtoc_update_format8_label(&f9addr, part_info->f1);
1167 vtoc_write_label(options.device, blk, part_info->f1,
1168 NULL, NULL, NULL, NULL);
1169 blk += anc->blksize;
1170 vtoc_write_label(options.device, blk, NULL, NULL,
1171 NULL, NULL, anc->f9);
1172 if (anc->verbose) printf("f9 ");
1173 blk += anc->blksize;
1174 } else {
1175 vtoc_write_label(options.device, blk, part_info->f1,
1176 NULL, NULL, NULL, NULL);
1177 blk += anc->blksize;
1181 /* write empty labels to the rest of the blocks */
1182 bzero(&emptyf1, sizeof(emptyf1));
1183 while (blk < maxblk) {
1184 vtoc_write_label(options.device, blk, &emptyf1, NULL,
1185 NULL, NULL, NULL);
1186 if (anc->verbose) printf("empty ");
1187 blk += anc->blksize;
1190 if (anc->verbose) printf("\n");
1195 * writes all changes to dasd
1197 static void
1198 fdasd_write_labels (fdasd_anchor_t *anc)
1200 if (anc->vlabel_changed) {
1201 if (!anc->silent) printf("writing volume label...\n");
1202 vtoc_write_volume_label(options.device, anc->label_pos,
1203 anc->vlabel);
1206 if (anc->vtoc_changed)
1207 fdasd_write_vtoc_labels(anc);
1209 if ((anc->vtoc_changed)||(anc->vlabel_changed))
1210 fdasd_reread_partition_table(anc);
1215 * re-creates the VTOC and deletes all partitions
1217 static void fdasd_recreate_vtoc_unconditional(fdasd_anchor_t *anc)
1219 partition_info_t *part_info = anc->first;
1220 int i;
1222 vtoc_init_format4_label(anc->f4, USABLE_PARTITIONS,
1223 geo.cylinders, anc->formatted_cylinders,
1224 geo.heads, geo.sectors,
1225 anc->blksize, anc->dev_type);
1227 vtoc_init_format5_label(anc->f5);
1228 vtoc_init_format7_label(anc->f7);
1229 vtoc_set_freespace(anc->f4,anc->f5, anc->f7, '+', anc->verbose,
1230 FIRST_USABLE_TRK,
1231 anc->formatted_cylinders * geo.heads - 1,
1232 anc->formatted_cylinders, geo.heads);
1234 while (part_info != NULL) {
1236 bzero(part_info->f1, sizeof(format1_label_t));
1238 if (part_info->used == 0x01) {
1239 part_info->used = 0x00;
1240 part_info->start_trk = 0;
1241 part_info->end_trk = 0;
1242 part_info->len_trk = 0;
1243 part_info->fspace_trk = 0;
1246 part_info = part_info->next;
1249 anc->used_partitions = 0;
1250 anc->fspace_trk = anc->formatted_cylinders * geo.heads
1251 - FIRST_USABLE_TRK;
1253 for (i=0; i<USABLE_PARTITIONS; i++)
1254 setpos(anc, i, -1);
1256 anc->vtoc_changed++;
1260 * asks user for confirmation before recreating the vtoc
1262 static void fdasd_recreate_vtoc(fdasd_anchor_t *anc)
1264 char str[INPUT_BUF_SIZE];
1266 if (!anc->silent) {
1267 snprintf(str, INPUT_BUF_SIZE,
1268 "WARNING: All partitions on device '%s' will be "
1269 "deleted!\nDo you want to continue?",
1270 options.device);
1272 if (yes_no(str) != 0)
1273 return;
1275 printf("creating new VTOC... ");
1277 fdasd_recreate_vtoc_unconditional(anc);
1278 if (!anc->silent) printf("ok\n");
1283 * re-create all VTOC labels, but use the partition information
1284 * from existing VTOC
1286 static void
1287 fdasd_reuse_vtoc(fdasd_anchor_t *anc)
1289 partition_info_t *part_info = anc->first;
1290 format1_label_t f1;
1291 format4_label_t f4;
1292 format5_label_t f5;
1293 format7_label_t f7;
1294 char str[INPUT_BUF_SIZE];
1296 if (!anc->silent) {
1297 snprintf(str, INPUT_BUF_SIZE,
1298 "WARNING: this will re-create your VTOC "
1299 "entries using the partition\n "
1300 "information of your existing VTOC. Continue?");
1302 if (yes_no(str) != 0)
1303 return;
1306 if (!anc->silent) printf("re-creating VTOC... ");
1308 vtoc_init_format4_label(&f4, USABLE_PARTITIONS,
1309 geo.cylinders, anc->formatted_cylinders,
1310 geo.heads, geo.sectors,
1311 anc->blksize, anc->dev_type);
1313 /* reuse some FMT4 values */
1314 f4.DS4HPCHR = anc->f4->DS4HPCHR;
1315 f4.DS4DSREC = anc->f4->DS4DSREC;
1317 /* re-initialize both free-space labels */
1318 vtoc_init_format5_label(&f5);
1319 vtoc_init_format7_label(&f7);
1321 if (anc->fspace_trk > 0)
1322 vtoc_set_freespace(&f4, &f5, &f7, '+', anc->verbose,
1323 FIRST_USABLE_TRK,
1324 FIRST_USABLE_TRK + anc->fspace_trk - 1,
1325 anc->formatted_cylinders, geo.heads);
1327 while (part_info != NULL) {
1328 if (part_info->used != 0x01) {
1329 part_info = part_info->next;
1330 continue;
1333 if (anc->formatted_cylinders > LV_COMPAT_CYL)
1334 vtoc_init_format8_label(anc->vlabel->volid,
1335 anc->blksize,
1336 &part_info->f1->DS1EXT1, &f1);
1337 else
1338 vtoc_init_format1_label(anc->vlabel->volid,
1339 anc->blksize,
1340 &part_info->f1->DS1EXT1, &f1);
1343 strncpy(f1.DS1DSNAM, part_info->f1->DS1DSNAM, 44);
1344 strncpy((char *)f1.DS1DSSN, (char *)part_info->f1->DS1DSSN, 6);
1345 f1.DS1CREDT = part_info->f1->DS1CREDT;
1347 memcpy(part_info->f1, &f1, sizeof(format1_label_t));
1349 if (part_info->fspace_trk > 0)
1350 vtoc_set_freespace(&f4, &f5, &f7, '+', anc->verbose,
1351 part_info->end_trk + 1,
1352 part_info->end_trk +
1353 part_info->fspace_trk,
1354 anc->formatted_cylinders, geo.heads);
1356 part_info = part_info->next;
1359 /* over-write old labels with new ones */
1360 memcpy(anc->f4, &f4, sizeof(format4_label_t));
1361 memcpy(anc->f5, &f5, sizeof(format5_label_t));
1362 memcpy(anc->f7, &f7, sizeof(format7_label_t));
1364 if (!anc->silent) printf("ok\n");
1365 anc->vtoc_changed++;
1367 return;
1372 * Changes the volume serial (menu option)
1374 static void
1375 fdasd_change_volser (fdasd_anchor_t *anc)
1377 char volser[VOLSER_LENGTH + 1];
1379 vtoc_volume_label_get_volser(anc->vlabel, volser);
1380 printf("Please specify new volume serial (6 characters).\n");
1381 printf("current : %-6.6s\nnew [0X%04x]: ", volser, anc->devno);
1383 read_line();
1384 fdasd_check_volser(line_ptr, anc->devno);
1386 printf("\nvolume identifier changed to '%-6s'\n",line_ptr);
1387 vtoc_volume_label_set_volser(anc->vlabel, line_ptr);
1389 vtoc_set_cchhb(&anc->vlabel->vtoc, VTOC_START_CC, VTOC_START_HH, 0x01);
1390 anc->vlabel_changed++;
1391 anc->vtoc_changed++;
1396 * changes the partition type
1398 static void
1399 fdasd_change_part_type (fdasd_anchor_t *anc)
1401 unsigned int part_id, part_type, i;
1402 char str[20], *ch;
1403 partition_info_t *part_info;
1405 fdasd_list_partition_table(anc);
1407 /* ask for partition number */
1408 printf("\nchange partition type\n");
1409 while (!isdigit(part_id = read_char("partition id (use 0 to exit): ")))
1410 printf("Invalid partition id '%c' detected.\n", part_id);
1412 part_id -= 48;
1413 printf("\n");
1414 if (part_id == 0)
1415 return;
1416 if (part_id > anc->used_partitions) {
1417 printf("'%d' is not a valid partition id!\n", part_id);
1418 return;
1421 part_info = anc->first;
1422 for (i=1; i < part_id; i++)
1423 part_info = part_info->next;
1425 /* ask for partition type */
1426 vtoc_ebcdic_dec(part_info->f1->DS1DSNAM, part_info->f1->DS1DSNAM, 44);
1427 ch = strstr(part_info->f1->DS1DSNAM, "PART") + 9;
1428 if (ch != NULL) {
1429 strncpy(str, ch, 6);
1430 str[6] = '\0';
1431 } else
1432 strcpy(str, "error");
1434 printf("current partition type is: %s\n\n", fdasd_partition_type(str));
1435 printf(" 1 Linux native\n" \
1436 " 2 Linux swap\n\n");
1437 part_type = 0;
1438 while ((part_type < 1) || (part_type > 2)) {
1439 while (!isdigit(part_type =
1440 read_char("new partition type: ")));
1441 part_type -= 48;
1444 switch (part_type) {
1445 case 1:
1446 strncpy(str, "NATIVE", 6);
1447 break;
1448 case 2:
1449 strncpy(str, "SWAP ", 6);
1450 break;
1451 default:
1452 printf("'%d' is not supported!\n", part_type);
1455 ch = strstr(part_info->f1->DS1DSNAM, "PART") + 9;
1456 if (ch != NULL)
1457 strncpy(ch, str, 6);
1458 vtoc_ebcdic_enc(part_info->f1->DS1DSNAM, part_info->f1->DS1DSNAM, 44);
1459 anc->vtoc_changed++;
1465 * initialize the VOL1 volume label
1467 static void
1468 fdasd_init_volume_label (fdasd_anchor_t *anc)
1470 volume_label_t *vlabel = anc->vlabel;
1471 char old_volser[VOLSER_LENGTH + 1];
1473 vtoc_volume_label_init(vlabel);
1474 vtoc_volume_label_set_key(vlabel, "VOL1");
1475 vtoc_volume_label_set_label(vlabel, "VOL1");
1477 if (anc->keep_volser) {
1478 if(fdasd_get_volser(anc, options.device, old_volser) == 0)
1479 vtoc_volume_label_set_volser(vlabel, old_volser);
1480 else {
1481 fdasd_error(anc, volser_not_found, options.device);
1484 else {
1485 if (options.volser == NULL) {
1486 printf("\nPlease specify volume serial (6 characters)"
1487 "[0X%04x]: ",
1488 anc->devno);
1489 read_line();
1490 fdasd_check_volser(line_ptr, anc->devno);
1491 vtoc_volume_label_set_volser(vlabel, line_ptr);
1492 } else {
1493 fdasd_check_volser(options.volser, anc->devno);
1494 vtoc_volume_label_set_volser(vlabel, options.volser);
1499 vtoc_set_cchhb(&vlabel->vtoc, VTOC_START_CC, VTOC_START_HH, 0x01);
1500 anc->vlabel_changed++;
1505 * sets some important partition data
1506 * (like used, start_trk, end_trk, len_trk)
1507 * by calculating these values with the
1508 * information provided in the labels
1510 static void
1511 fdasd_update_partition_info (fdasd_anchor_t *anc)
1513 partition_info_t *prev_part_info = NULL, *part_info = anc->first;
1514 unsigned long max = anc->formatted_cylinders * geo.heads - 1;
1515 int i;
1517 anc->used_partitions = geo.sectors - 2 - anc->f4->DS4DSREC;
1519 for (i=1; i<=USABLE_PARTITIONS; i++) {
1520 if (part_info->f1->DS1FMTID != 0xf1 &&
1521 part_info->f1->DS1FMTID != 0xf8) {
1522 if (i == 1)
1523 /* there is no partition at all */
1524 anc->fspace_trk = max - FIRST_USABLE_TRK + 1;
1525 else
1526 /* previous partition was the last one */
1527 prev_part_info->fspace_trk =
1528 max - prev_part_info->end_trk;
1529 break;
1532 /* this is a valid format 1 label */
1533 part_info->used = 0x01;
1534 part_info->start_trk = cchh2trk(&part_info->f1->DS1EXT1.llimit,
1535 &geo);
1536 part_info->end_trk = cchh2trk(&part_info->f1->DS1EXT1.ulimit,
1537 &geo);
1539 part_info->len_trk = part_info->end_trk -
1540 part_info->start_trk + 1;
1542 if (i == 1)
1543 /* first partition, there is at least one */
1544 anc->fspace_trk =
1545 part_info->start_trk - FIRST_USABLE_TRK;
1546 else {
1547 if (i == USABLE_PARTITIONS)
1548 /* last possible partition */
1549 part_info->fspace_trk =
1550 max - part_info->end_trk;
1552 /* set free space values of previous partition */
1553 prev_part_info->fspace_trk = part_info->start_trk -
1554 prev_part_info->end_trk - 1;
1557 prev_part_info = part_info;
1558 part_info = part_info->next;
1563 * reorganizes all FMT1s, move all empty labels to the end
1565 static void
1566 fdasd_reorganize_FMT1s (fdasd_anchor_t *anc)
1568 int i, j;
1569 format1_label_t *f1_label;
1570 partition_info_t *part_info;
1572 for (i=1; i<=USABLE_PARTITIONS - 1; i++) {
1573 part_info = anc->first;
1574 for (j=1; j<=USABLE_PARTITIONS - i; j++) {
1575 if (part_info->f1->DS1FMTID <
1576 part_info->next->f1->DS1FMTID) {
1577 f1_label = part_info->f1;
1578 part_info->f1 = part_info->next->f1;
1579 part_info->next->f1 = f1_label;
1581 part_info = part_info->next;
1588 * we have a invalid FMT4 DSCB and therefore we will re-create the VTOC
1590 static void
1591 fdasd_process_invalid_vtoc(fdasd_anchor_t *anc)
1593 printf(" invalid\ncreating new VTOC...\n");
1594 if (anc->hw_cylinders > LV_COMPAT_CYL) {
1595 printf("Warning: Device has more then %u cylinders!\n",
1596 LV_COMPAT_CYL);
1597 if (yes_no("Are you sure it was completely"
1598 " formatted with dasdfmt?") == 1) {
1599 if (!anc->silent) printf("exiting...\n");
1600 fdasd_exit(anc, 0);
1603 anc->formatted_cylinders = anc->hw_cylinders;
1604 anc->fspace_trk = anc->formatted_cylinders * geo.heads
1605 - FIRST_USABLE_TRK;
1606 vtoc_init_format4_label(anc->f4, USABLE_PARTITIONS,
1607 geo.cylinders, anc->formatted_cylinders,
1608 geo.heads, geo.sectors,
1609 anc->blksize, anc->dev_type);
1611 vtoc_init_format5_label(anc->f5);
1612 vtoc_init_format7_label(anc->f7);
1613 vtoc_set_freespace(anc->f4, anc->f5, anc->f7, '+', anc->verbose,
1614 FIRST_USABLE_TRK,
1615 anc->formatted_cylinders * geo.heads - 1,
1616 anc->formatted_cylinders, geo.heads);
1618 anc->vtoc_changed++;
1625 static void
1626 fdasd_process_valid_vtoc(fdasd_anchor_t *anc, unsigned long blk)
1628 int f1_counter = 0, f7_counter = 0, f5_counter = 0;
1629 int i, part_no, f1_size = sizeof(format1_label_t);
1630 partition_info_t *part_info = anc->first;
1631 format1_label_t f1_label;
1632 char part_no_str[5], *part_pos;
1634 if (!anc->silent) printf(" ok\n");
1636 if (anc->f4->DS4DEVCT.DS4DSCYL == LV_COMPAT_CYL &&
1637 anc->f4->DS4DCYL > anc->f4->DS4DEVCT.DS4DSCYL)
1638 anc->formatted_cylinders = anc->f4->DS4DCYL;
1639 else
1640 anc->formatted_cylinders = anc->f4->DS4DEVCT.DS4DSCYL;
1641 anc->fspace_trk = anc->formatted_cylinders * geo.heads
1642 - FIRST_USABLE_TRK;
1643 blk += anc->blksize;
1645 if (anc->formatted_cylinders < anc->hw_cylinders)
1646 printf("WARNING: This device is not fully formatted! "
1647 "Only %u of %u cylinders are available.\n",
1648 anc->formatted_cylinders, anc->hw_cylinders);
1650 if (anc->verbose) printf("VTOC DSCBs : ");
1652 for (i = 1; i <= geo.sectors; i++) {
1653 bzero(&f1_label, f1_size);
1654 vtoc_read_label(options.device, blk, &f1_label, NULL, NULL,
1655 NULL);
1657 switch (f1_label.DS1FMTID) {
1658 case 0xf1:
1659 case 0xf8:
1660 if (anc->verbose)
1661 printf("%s ",
1662 f1_label.DS1FMTID == 0xf1 ? "f1" : "f8");
1663 if (part_info == NULL)
1664 break;
1665 memcpy(part_info->f1, &f1_label, f1_size);
1667 part_no = -1;
1668 vtoc_ebcdic_dec(part_info->f1->DS1DSNAM,
1669 part_info->f1->DS1DSNAM, 44);
1670 part_pos = strstr(part_info->f1->DS1DSNAM, "PART");
1671 if (part_pos != NULL) {
1672 strncpy(part_no_str, part_pos + 4, 4);
1673 part_no_str[4] = '\0';
1674 part_no = atoi(part_no_str) - 1;
1677 vtoc_ebcdic_enc(part_info->f1->DS1DSNAM,
1678 part_info->f1->DS1DSNAM, 44);
1680 if ((part_no < 0) || (part_no >= USABLE_PARTITIONS))
1681 printf("WARNING: partition number (%i) found "
1682 "in data set name of an existing "
1683 "partition\ndoes not match range of "
1684 "possible partition numbers (1-%d)\n\n",
1685 part_no + 1, USABLE_PARTITIONS);
1686 else
1687 setpos(anc, part_no, f1_counter);
1689 part_info = part_info->next;
1690 f1_counter++;
1691 break;
1692 case 0xf5:
1693 if (anc->verbose) printf("f5 ");
1694 memcpy(anc->f5, &f1_label, f1_size);
1695 f5_counter++;
1696 break;
1697 case 0xf7:
1698 if (anc->verbose) printf("f7 ");
1699 if (f7_counter == 0)
1700 memcpy(anc->f7, &f1_label, f1_size);
1701 f7_counter++;
1702 break;
1703 case 0xf9:
1704 /* each format 8 lable has an associated format 9 lable,
1705 * but they are of no further use to us.
1707 if (anc->verbose) printf("f9 ");
1708 break;
1709 default:
1710 if (f1_label.DS1FMTID > 0)
1711 printf("'%d' is not supported!\n",
1712 f1_label.DS1FMTID);
1714 blk += anc->blksize;
1717 if (anc->verbose) printf("\n");
1719 if ((f5_counter == 0) || (anc->big_disk))
1720 vtoc_init_format5_label(anc->f5);
1722 if (f7_counter == 0)
1723 vtoc_init_format7_label(anc->f7);
1725 fdasd_reorganize_FMT1s(anc);
1726 fdasd_update_partition_info(anc);
1731 * we have a valid VTOC pointer, let's go and read the VTOC labels
1733 static int
1734 fdasd_valid_vtoc_pointer(fdasd_anchor_t *anc, unsigned long blk)
1736 /* VOL1 label contains valid VTOC pointer */
1737 if (!anc->silent)
1738 printf("reading vtoc ..........:");
1740 vtoc_read_label(options.device, blk, NULL, anc->f4, NULL, NULL);
1742 if (anc->f4->DS4IDFMT != 0xf4) {
1743 if (anc->print_table) {
1744 printf("Your VTOC is corrupted!\n");
1745 return -1;
1747 fdasd_process_invalid_vtoc(anc);
1748 } else
1749 fdasd_process_valid_vtoc(anc, blk);
1751 return 0;
1758 static void
1759 fdasd_invalid_vtoc_pointer(fdasd_anchor_t *anc)
1761 /* VOL1 label doesn't contain valid VTOC pointer */
1762 if (yes_no("There is no VTOC yet, should I create one?") == 1) {
1763 if (!anc->silent) printf("exiting...\n");
1764 fdasd_exit(anc, 0);
1767 if (anc->hw_cylinders > LV_COMPAT_CYL) {
1768 printf("Warning: Device has more then %u cylinders!\n",
1769 LV_COMPAT_CYL);
1770 if (yes_no("Are you sure it was completely"
1771 " formatted with dasdfmt?") == 1) {
1772 if (!anc->silent) printf("exiting...\n");
1773 fdasd_exit(anc, 0);
1776 anc->formatted_cylinders = anc->hw_cylinders;
1777 anc->fspace_trk = anc->formatted_cylinders * geo.heads
1778 - FIRST_USABLE_TRK;
1779 vtoc_init_format4_label(anc->f4, USABLE_PARTITIONS,
1780 geo.cylinders, anc->formatted_cylinders,
1781 geo.heads, geo.sectors,
1782 anc->blksize, anc->dev_type);
1784 vtoc_init_format5_label(anc->f5);
1785 vtoc_init_format7_label(anc->f7);
1787 vtoc_set_freespace(anc->f4, anc->f5, anc->f7, '+', anc->verbose,
1788 FIRST_USABLE_TRK,
1789 anc->formatted_cylinders * geo.heads - 1,
1790 anc->formatted_cylinders, geo.heads);
1792 vtoc_set_cchhb(&anc->vlabel->vtoc, VTOC_START_CC, VTOC_START_HH, 0x01);
1794 anc->vtoc_changed++;
1795 anc->vlabel_changed++;
1800 * check the dasd for a volume label
1802 static int
1803 fdasd_check_volume (fdasd_anchor_t *anc)
1805 volume_label_t *vlabel = anc->vlabel;
1806 long long blk = -1;
1807 char str[LINE_LENGTH];
1808 char inp_buf[INPUT_BUF_SIZE];
1810 if (!anc->silent)
1811 printf("reading volume label ..:");
1813 vtoc_read_volume_label(options.device, anc->label_pos, vlabel);
1815 if (strncmp(vlabel->vollbl, vtoc_ebcdic_enc("VOL1",str,4),4) == 0) {
1816 /* found VOL1 volume label */
1817 if (!anc->silent)
1818 printf(" VOL1\n");
1820 blk = (cchhb2blk(&vlabel->vtoc, &geo) - 1) * anc->blksize;
1821 if (blk > 0) {
1822 int rc;
1823 rc = fdasd_valid_vtoc_pointer(anc, blk);
1825 if (anc->print_table && (rc < 0))
1826 return -1;
1828 else {
1829 if (anc->print_table) {
1830 printf("\nFound invalid VTOC pointer.\n");
1831 return -1;
1833 fdasd_invalid_vtoc_pointer(anc);
1835 } else {
1836 /* didn't find VOL1 volume label */
1838 if (anc->print_table) {
1839 printf("\nCould not find VOL1 volume label.\n");
1840 return -1;
1843 if (strncmp(vlabel->vollbl,
1844 vtoc_ebcdic_enc("LNX1",str,4),4) == 0) {
1845 if (!anc->silent)
1846 printf(" LNX1\n");
1847 strcpy(inp_buf,"Overwrite inapplicable label?");
1849 else {
1850 if (!anc->silent)
1851 printf(" no known label\n");
1852 strcpy(inp_buf,"Should I create a new one?");
1854 if ((!anc->print_volser) && (!anc->print_table) &&
1855 (yes_no(inp_buf) == 1)) {
1856 printf("You need a VOL1 volume label for " \
1857 "partitioning\nexiting...\n");
1858 fdasd_exit(anc, -1);
1861 if (anc->hw_cylinders > LV_COMPAT_CYL) {
1862 printf("Warning: Device has more then %u cylinders!\n",
1863 LV_COMPAT_CYL);
1864 if (yes_no("Are you sure it was completely"
1865 " formatted with dasdfmt?") == 1) {
1866 if (!anc->silent) printf("exiting...\n");
1867 fdasd_exit(anc, 0);
1870 anc->formatted_cylinders = anc->hw_cylinders;
1871 anc->fspace_trk = anc->formatted_cylinders * geo.heads
1872 - FIRST_USABLE_TRK;
1874 fdasd_init_volume_label(anc);
1876 vtoc_init_format4_label(anc->f4, USABLE_PARTITIONS,
1877 geo.cylinders, anc->formatted_cylinders,
1878 geo.heads, geo.sectors,
1879 anc->blksize, anc->dev_type);
1881 vtoc_init_format5_label(anc->f5);
1882 vtoc_init_format7_label(anc->f7);
1884 vtoc_set_freespace(anc->f4, anc->f5, anc->f7, '+',
1885 anc->verbose, FIRST_USABLE_TRK,
1886 anc->formatted_cylinders * geo.heads - 1,
1887 anc->formatted_cylinders, geo.heads);
1889 anc->vtoc_changed++;
1892 if (!anc->silent)
1893 printf("\n");
1895 return 0;
1900 * check disk access
1902 static void
1903 fdasd_check_disk_access (fdasd_anchor_t *anc)
1905 char err_str[ERROR_STRING_SIZE];
1906 format1_label_t f1;
1907 int fd, pos, ro;
1909 if ((fd = open(options.device, O_RDWR)) == -1) {
1910 snprintf(err_str, ERROR_STRING_SIZE,
1911 "Could not open device '%s' " \
1912 "in read-only mode!\n", options.device);
1913 fdasd_error(anc, unable_to_open_disk, err_str);
1916 pos = anc->blksize * (2 * geo.heads - 1);
1917 /* last block in the second track */
1918 if (lseek(fd, pos, SEEK_SET) == -1) {
1919 close(fd);
1920 snprintf(err_str, ERROR_STRING_SIZE,
1921 "Could not seek device '%s'.", options.device);
1922 fdasd_error(anc, unable_to_seek_disk, err_str);
1925 if (read(fd, &f1, sizeof(format1_label_t)) !=
1926 sizeof(format1_label_t)) {
1927 close(fd);
1928 snprintf(err_str, ERROR_STRING_SIZE,
1929 "Could not read from device '%s'.", options.device);
1930 fdasd_error(anc, unable_to_read_disk, err_str);
1933 if (lseek(fd, pos, SEEK_SET) == -1) {
1934 close(fd);
1935 snprintf(err_str, ERROR_STRING_SIZE,
1936 "Could not seek device '%s'.", options.device);
1937 fdasd_error(anc, unable_to_seek_disk, err_str);
1940 if (ioctl(fd, BLKROGET, &ro) != 0) {
1941 snprintf(err_str, ERROR_STRING_SIZE,
1942 "Could not get read-only status for device '%s'.",
1943 options.device);
1944 fdasd_error(anc, unable_to_ioctl, err_str);
1946 if (ro && !anc->print_volser && !anc->print_table)
1947 printf("\nWARNING: Device '%s' is a read-only device!\n"
1948 "You will not be able to save any changes.\n\n",
1949 options.device);
1951 close(fd);
1956 * reads dasd geometry data
1958 static void
1959 fdasd_get_geometry (fdasd_anchor_t *anc)
1961 int fd, blksize = 0;
1962 dasd_information_t dasd_info;
1963 char err_str[ERROR_STRING_SIZE];
1964 u_int64_t device_size;
1966 if ((fd = open(options.device,O_RDONLY)) < 0) {
1967 snprintf(err_str, ERROR_STRING_SIZE,
1968 "Could not open device '%s' "
1969 "in read-only mode!\n", options.device);
1970 fdasd_error(anc, unable_to_open_disk, err_str);
1973 if (ioctl(fd, HDIO_GETGEO, &geo) != 0) {
1974 close(fd);
1975 fdasd_error(anc, unable_to_ioctl,
1976 "Could not retrieve disk geometry information.");
1979 if (ioctl(fd, BLKSSZGET, &blksize) != 0) {
1980 close(fd);
1981 fdasd_error(anc, unable_to_ioctl,
1982 "Could not retrieve blocksize information.");
1985 if (ioctl(fd, BLKGETSIZE64, &device_size) != 0) {
1986 close(fd);
1987 fdasd_error(anc, unable_to_ioctl,
1988 "Could not retrieve device size information.");
1991 anc->hw_cylinders = ((device_size / blksize) / geo.sectors) / geo.heads;
1993 /* get disk type */
1994 if (ioctl(fd, BIODASDINFO, &dasd_info) != 0) {
1995 close(fd);
1996 fdasd_error(anc, unable_to_ioctl,
1997 "Could not retrieve disk information.");
2000 close(fd);
2002 if (strncmp(dasd_info.type, "ECKD", 4) != 0) {
2003 snprintf(err_str, ERROR_STRING_SIZE,
2004 "%s is not an ECKD disk! This disk type "
2005 "is not supported!", options.device);
2006 fdasd_error(anc,wrong_disk_type, err_str);
2009 if (anc->verbose) printf("disk type check : ok\n");
2011 if (dasd_info.FBA_layout != 0) {
2012 snprintf(err_str, ERROR_STRING_SIZE,
2013 "%s is not formatted with z/OS compatible "
2014 "disk layout!", options.device);
2015 fdasd_error(anc, wrong_disk_format, err_str);
2018 if (anc->verbose) printf("disk layout check : ok\n");
2020 if (dasd_info.open_count > 1) {
2021 if (anc->auto_partition) {
2022 snprintf(err_str, ERROR_STRING_SIZE,
2023 "DASD '%s' is in use. Unmount it first!",
2024 options.device);
2025 fdasd_error(anc, disk_in_use, err_str);
2026 } else {
2027 printf("\nWARNING: Your DASD '%s' is in use.\n"
2028 " If you proceed, you can heavily "
2029 "damage your system.\n If possible exit"
2030 " all applications using this disk\n "
2031 "and/or unmount it.\n\n", options.device);
2035 if (anc->verbose) printf("usage count check : ok\n");
2037 anc->dev_type = dasd_info.dev_type;
2038 anc->blksize = blksize;
2039 anc->label_pos = dasd_info.label_block * blksize;
2040 anc->devno = dasd_info.devno;
2045 * asks for partition boundaries
2047 static unsigned long
2048 fdasd_read_int (unsigned long low, unsigned long dflt, unsigned long high,
2049 enum offset base, char *mesg, fdasd_anchor_t *anc)
2051 unsigned long long trk = 0;
2052 unsigned int use_default = 1;
2053 char msg_txt[70];
2055 switch(base) {
2056 case lower:
2057 sprintf(msg_txt, "%s ([%ld]-%ld): ", mesg, low, high);
2058 break;
2059 case upper:
2060 sprintf(msg_txt, "%s (%ld-[%ld]): ", mesg, low, high);
2061 break;
2062 default:
2063 sprintf(msg_txt, "%s (%ld-%ld): ", mesg, low, high);
2064 break;
2067 while (1) {
2068 while (!isdigit(read_char(msg_txt))
2069 && (*line_ptr != '-' &&
2070 *line_ptr != '+' &&
2071 *line_ptr != '\0'))
2072 continue;
2073 if ((*line_ptr == '+' || *line_ptr == '-') &&
2074 base != lower) {
2075 if (*line_ptr == '+')
2076 ++line_ptr;
2077 trk = atoi(line_ptr);
2078 while (isdigit(*line_ptr)) {
2079 line_ptr++;
2080 use_default = 0;
2083 switch (*line_ptr) {
2084 case 'c':
2085 case 'C':
2086 trk *= geo.heads;
2087 break;
2088 case 'k':
2089 case 'K':
2090 trk *= 1024;
2091 trk /= anc->blksize;
2092 trk /= geo.sectors;
2093 break;
2094 case 'm':
2095 case 'M':
2096 trk *= (1024*1024);
2097 trk /= anc->blksize;
2098 trk /= geo.sectors;
2099 break;
2100 case 0x0a:
2101 break;
2102 default:
2103 printf("WARNING: '%c' is not a "
2104 "valid appendix and probably "
2105 "not what you want!\n",
2106 *line_ptr);
2107 break;
2110 trk += (low - 1);
2113 else if (*line_ptr == '\0') {
2114 switch(base) {
2115 case lower: trk = low; break;
2116 case upper: trk = high; break;
2119 else {
2120 if (*line_ptr == '+' || *line_ptr == '-') {
2121 printf("\nWARNING: '%c' is not valid in \n"
2122 "this case and will be ignored!\n",
2123 *line_ptr);
2124 ++line_ptr;
2127 trk = atoi(line_ptr);
2128 while (isdigit(*line_ptr)) {
2129 line_ptr++;
2130 use_default = 0;
2133 if (*line_ptr != 0x0a)
2134 printf("\nWARNING: '%c' is not a valid "
2135 "appendix and probably not what "
2136 "you want!\n", *line_ptr);
2138 if (use_default)
2139 printf("Using default value %lld\n", trk = dflt);
2140 else
2141 printf("You have selected track %lld\n", trk);
2143 if (trk >= low && trk <= high)
2144 break;
2145 else
2146 printf("Value out of range.\n");
2148 return trk;
2153 * returns unused partition info pointer if there
2154 * is a free partition, otherwise NULL
2156 static partition_info_t *
2157 fdasd_get_empty_f1_label (fdasd_anchor_t * anc)
2159 if (anc->used_partitions < USABLE_PARTITIONS)
2160 return anc->last;
2161 else
2162 return NULL;
2167 * asks for and sets some important partition data
2169 static int
2170 fdasd_get_partition_data (fdasd_anchor_t *anc, extent_t *part_extent,
2171 partition_info_t *part_info)
2173 unsigned long start, stop, limit;
2174 u_int32_t cc, cyl;
2175 u_int16_t hh, head;
2176 cchh_t llimit,ulimit;
2177 partition_info_t *part_tmp;
2178 char mesg[48];
2179 u_int8_t b1, b2;
2181 start = FIRST_USABLE_TRK;
2183 cyl = get_usable_cylinders(anc);
2184 head = anc->f4->DS4DEVCT.DS4DSTRK;
2185 limit = (head * cyl - 1);
2187 sprintf(mesg, "First track (1 track = %d KByte)",
2188 geo.sectors * anc->blksize / 1024);
2190 /* find default start value */
2191 for (part_tmp = anc->first; part_tmp->next != NULL;
2192 part_tmp = part_tmp->next) {
2193 if ((start >= part_tmp->start_trk) &&
2194 (start <= part_tmp->end_trk))
2195 start = part_tmp->end_trk + 1;
2198 if (start > limit) {
2199 printf("Not that easy, no free tracks available.\n");
2200 return -1;
2203 /* read start value */
2204 start = fdasd_read_int(start, start, limit, lower, mesg, anc);
2206 /* check start value from user */
2207 for (part_tmp = anc->first; part_tmp->next != NULL;
2208 part_tmp = part_tmp->next) {
2209 if (start >= part_tmp->start_trk &&
2210 start <= part_tmp->end_trk) {
2211 /* start is within another partition */
2212 start = part_tmp->end_trk + 1;
2213 if (start > limit) {
2214 start = FIRST_USABLE_TRK;
2215 part_tmp = anc->first;
2218 printf("value within another partition, " \
2219 "using %ld instead\n", start);
2222 if (start < part_tmp->start_trk) {
2223 limit = part_tmp->start_trk - 1;
2224 break;
2229 if (start == limit)
2230 stop = start;
2231 else {
2232 sprintf(mesg, "Last track or +size[c|k|M]");
2233 stop = fdasd_read_int(start, limit, limit, upper, mesg, anc);
2236 /* update partition info */
2237 part_info->len_trk = stop - start + 1;
2238 part_info->start_trk = start;
2239 part_info->end_trk = stop;
2241 cc = start / geo.heads;
2242 hh = start - (cc * geo.heads);
2243 vtoc_set_cchh(&llimit, cc, hh);
2245 /* check for cylinder boundary */
2246 if (hh == 0)
2247 b1 = 0x81;
2248 else
2249 b1 = 0x01;
2251 cc = stop / geo.heads;
2252 hh = stop - cc * geo.heads;
2253 vtoc_set_cchh(&ulimit, cc, hh);
2255 /* it is always the 1st extent */
2256 b2 = 0x00;
2258 vtoc_set_extent(part_extent, b1, b2, &llimit, &ulimit);
2260 return 0;
2267 static void
2268 fdasd_enqueue_new_partition (fdasd_anchor_t *anc)
2270 partition_info_t *part_tmp = anc->first, *part_info = anc->last;
2271 int i, k = 0;
2273 for (i = 1; i < USABLE_PARTITIONS; i++) {
2274 if ((part_tmp->end_trk == 0) ||
2275 (part_info->start_trk < part_tmp->start_trk))
2276 break;
2277 else {
2278 part_tmp = part_tmp->next;
2279 k++;
2283 if (anc->first == part_tmp) anc->first = part_info;
2285 if (part_info != part_tmp) {
2286 anc->last->prev->next = NULL;
2287 anc->last = anc->last->prev;
2289 part_info->next = part_tmp;
2290 part_info->prev = part_tmp->prev;
2291 part_tmp->prev = part_info;
2293 if (part_info->prev != NULL)
2294 part_info->prev->next = part_info;
2297 part_info->used = 0x01;
2299 for (i=0; i<USABLE_PARTITIONS; i++) {
2300 int j = getpos(anc, i);
2301 if (j >= k) setpos(anc, i, j + 1);
2304 /* update free-space counters */
2305 if (anc->first == part_info) {
2306 /* partition is the first used partition */
2307 if (part_info->start_trk == FIRST_USABLE_TRK) {
2308 /* partition starts right behind VTOC */
2309 part_info->fspace_trk = anc->fspace_trk -
2310 part_info->len_trk;
2311 anc->fspace_trk = 0;
2313 else {
2314 /* there is some space between VTOC and partition */
2316 part_info->fspace_trk = anc->fspace_trk -
2317 part_info->len_trk - part_info->start_trk +
2318 FIRST_USABLE_TRK;
2319 anc->fspace_trk = part_info->start_trk -
2320 FIRST_USABLE_TRK;
2323 else {
2324 /* there are partitons in front of the new one */
2325 if (part_info->start_trk == part_info->prev->end_trk + 1) {
2326 /* new partition is right behind the previous one */
2327 part_info->fspace_trk = part_info->prev->fspace_trk -
2328 part_info->len_trk;
2329 part_info->prev->fspace_trk = 0;
2331 else {
2332 /* there is some space between new and prev. part. */
2333 part_info->fspace_trk = part_info->prev->fspace_trk -
2334 part_info->len_trk - part_info->start_trk +
2335 part_info->prev->end_trk + 1;
2336 part_info->prev->fspace_trk = part_info->start_trk -
2337 part_info->prev->end_trk - 1;
2346 static void
2347 fdasd_dequeue_old_partition (fdasd_anchor_t *anc, partition_info_t *part_info,
2348 int k)
2350 int i;
2352 if (part_info != anc->first && part_info != anc->last) {
2353 /* dequeue any non-special element */
2354 part_info->prev->next = part_info->next;
2355 part_info->next->prev = part_info->prev;
2358 if (part_info == anc->first) {
2359 /* dequeue first element */
2360 anc->first = part_info->next;
2361 part_info->next->prev = NULL;
2362 anc->fspace_trk += (part_info->len_trk +
2363 part_info->fspace_trk);
2364 } else
2365 part_info->prev->fspace_trk += (part_info->len_trk +
2366 part_info->fspace_trk);
2368 if (part_info != anc->last) {
2369 part_info->prev = anc->last;
2370 part_info->next = NULL;
2371 anc->last->next = part_info;
2372 anc->last = part_info;
2375 for (i=0; i<USABLE_PARTITIONS; i++) {
2376 int j = getpos(anc, i);
2377 if (j >= k) setpos(anc, i, j - 1);
2380 part_info->used = 0x00;
2381 part_info->len_trk = 0x0;
2382 part_info->start_trk = 0x0;
2383 part_info->end_trk = 0x0;
2384 part_info->fspace_trk = 0x0;
2385 bzero(part_info->f1, sizeof(format1_label_t));
2390 * adds a new partition to the 'partition table'
2392 static void
2393 fdasd_add_partition (fdasd_anchor_t *anc)
2395 cchhb_t hf1;
2396 partition_info_t *part_info;
2397 extent_t ext;
2398 unsigned long start, stop;
2400 if ((part_info = fdasd_get_empty_f1_label(anc)) == NULL) {
2401 printf("No more free partitions left,\n"
2402 "you have to delete one first!");
2403 return;
2406 if (fdasd_get_partition_data(anc, &ext, part_info) != 0)
2407 return;
2409 if (anc->formatted_cylinders > LV_COMPAT_CYL) {
2410 vtoc_init_format8_label(anc->vlabel->volid, anc->blksize, &ext,
2411 part_info->f1);
2412 } else
2413 vtoc_init_format1_label(anc->vlabel->volid, anc->blksize, &ext,
2414 part_info->f1);
2416 fdasd_enqueue_new_partition(anc);
2417 anc->used_partitions += 1;
2419 get_addr_of_highest_f1_f8_label(anc, &hf1);
2420 vtoc_update_format4_label(anc->f4, &hf1, anc->f4->DS4DSREC - 1);
2422 start = cchh2trk(&ext.llimit, &geo);
2423 stop = cchh2trk(&ext.ulimit, &geo);
2425 vtoc_set_freespace(anc->f4, anc->f5, anc->f7, '-', anc->verbose,
2426 start, stop, anc->formatted_cylinders, geo.heads);
2428 anc->vtoc_changed++;
2433 * removes a partition from the 'partition table'
2435 static void
2436 fdasd_remove_partition (fdasd_anchor_t *anc)
2438 cchhb_t hf1;
2439 unsigned int part_id, i;
2440 unsigned long start, stop;
2441 partition_info_t *part_info = anc->first;
2443 fdasd_list_partition_table(anc);
2445 while (!isdigit(part_id = read_char("\ndelete partition with id "
2446 "(use 0 to exit): ")))
2447 printf("Invalid partition id '%c' detected.\n", part_id);
2449 printf("\n");
2450 part_id -= 48;
2451 if (part_id == 0) return;
2452 if (part_id > anc->used_partitions) {
2453 printf("'%d' is not a valid partition id!\n", part_id);
2454 return;
2457 printf("deleting partition number '%d'...\n", part_id);
2459 setpos(anc, part_id-1, -1);
2460 for (i=1; i<part_id; i++) part_info=part_info->next;
2462 start = cchh2trk(&part_info->f1->DS1EXT1.llimit, &geo);
2463 stop = cchh2trk(&part_info->f1->DS1EXT1.ulimit, &geo);
2465 fdasd_dequeue_old_partition (anc, part_info, part_id-1);
2466 anc->used_partitions -= 1;
2468 if (anc->used_partitions != 0)
2469 get_addr_of_highest_f1_f8_label(anc, &hf1);
2470 else
2471 bzero(&hf1, sizeof(struct cchhb));
2473 vtoc_update_format4_label(anc->f4, &hf1, anc->f4->DS4DSREC + 1);
2474 vtoc_set_freespace(anc->f4, anc->f5, anc->f7, '+', anc->verbose,
2475 start, stop, anc->formatted_cylinders, geo.heads);
2477 anc->vtoc_changed++;
2482 * writes a standard volume label and a standard VTOC with
2483 * only one partition to disc. With this function is it
2484 * possible to create one partiton in non-interactive mode,
2485 * which can be used within shell scripts
2487 static void
2488 fdasd_auto_partition(fdasd_anchor_t *anc)
2490 volume_label_t *vlabel = anc->vlabel;
2491 partition_info_t *part_info = anc->first;
2492 cchh_t llimit,ulimit;
2493 cchhb_t hf1;
2494 extent_t ext;
2495 char volser[VOLSER_LENGTH + 1];
2496 u_int32_t cyl;
2497 u_int16_t head;
2498 char old_volser[VOLSER_LENGTH + 1];
2500 if (!anc->silent)
2501 printf("auto-creating one partition for the whole disk...\n");
2503 vtoc_volume_label_init(vlabel);
2504 vtoc_volume_label_set_key(vlabel, "VOL1");
2505 vtoc_volume_label_set_label(vlabel, "VOL1");
2507 if (anc->keep_volser) {
2508 if(fdasd_get_volser(anc, options.device, old_volser) == 0)
2509 vtoc_volume_label_set_volser(vlabel, old_volser);
2510 else {
2511 fdasd_error(anc, volser_not_found, options.device);
2514 else {
2515 if (options.volser == NULL)
2516 sprintf(volser, "0X%04x", anc->devno);
2517 else {
2518 bzero(volser, VOLSER_LENGTH + 1);
2519 strncpy(volser, options.volser, VOLSER_LENGTH);
2520 fdasd_check_volser(volser, anc->devno);
2522 vtoc_volume_label_set_volser(vlabel, volser);
2526 vtoc_set_cchhb(&vlabel->vtoc, VTOC_START_CC, VTOC_START_HH, 0x01);
2528 if (anc->verbose) printf("initializing labels...\n");
2529 vtoc_init_format4_label(anc->f4, USABLE_PARTITIONS,
2530 geo.cylinders, anc->formatted_cylinders,
2531 geo.heads, geo.sectors,
2532 anc->blksize, anc->dev_type);
2534 vtoc_init_format5_label(anc->f5);
2535 vtoc_init_format7_label(anc->f7);
2537 cyl = get_usable_cylinders(anc);
2538 head = anc->f4->DS4DEVCT.DS4DSTRK;
2540 part_info->used = 0x01;
2541 part_info->fspace_trk = 0;
2542 part_info->len_trk = head * cyl - FIRST_USABLE_TRK;
2543 part_info->start_trk = FIRST_USABLE_TRK;
2544 part_info->end_trk = head * cyl - 1;
2546 vtoc_set_cchh(&llimit, 0, FIRST_USABLE_TRK);
2547 vtoc_set_cchh(&ulimit, cyl - 1, head - 1);
2549 vtoc_set_extent(&ext, 0x01, 0x00, &llimit, &ulimit);
2551 if (anc->formatted_cylinders > LV_COMPAT_CYL) {
2552 vtoc_init_format8_label(anc->vlabel->volid, anc->blksize, &ext,
2553 part_info->f1);
2554 } else
2555 vtoc_init_format1_label(anc->vlabel->volid, anc->blksize, &ext,
2556 part_info->f1);
2557 anc->fspace_trk = 0;
2558 anc->used_partitions = 1;
2560 get_addr_of_highest_f1_f8_label(anc, &hf1);
2561 vtoc_update_format4_label(anc->f4, &hf1, anc->f4->DS4DSREC - 1);
2563 anc->vlabel_changed++;
2564 anc->vtoc_changed++;
2566 fdasd_write_labels(anc);
2567 fdasd_exit(anc, 0);
2572 * does the partitioning regarding to the config file
2574 static void
2575 fdasd_auto_partition_conffile(fdasd_anchor_t *anc)
2577 volume_label_t *vlabel = anc->vlabel;
2578 partition_info_t *part_info = anc->first;
2579 char volser[VOLSER_LENGTH + 1];
2580 cchh_t llimit,ulimit;
2581 unsigned long start, stop;
2582 extent_t ext;
2583 cchhb_t hf1;
2584 char old_volser[VOLSER_LENGTH + 1];
2586 vtoc_volume_label_init(vlabel);
2587 vtoc_volume_label_set_key(vlabel, "VOL1");
2588 vtoc_volume_label_set_label(vlabel, "VOL1");
2590 if (anc->keep_volser) {
2591 if(fdasd_get_volser(anc, options.device, old_volser) == 0)
2592 vtoc_volume_label_set_volser(vlabel, old_volser);
2593 else {
2594 fdasd_error(anc, volser_not_found, options.device);
2597 else {
2598 if (options.volser == NULL)
2599 sprintf(volser, "0X%04x", anc->devno);
2600 else {
2601 bzero(volser, VOLSER_LENGTH + 1);
2602 strncpy(volser, options.volser, VOLSER_LENGTH);
2603 fdasd_check_volser(volser, anc->devno);
2605 vtoc_volume_label_set_volser(vlabel, volser);
2608 vtoc_set_cchhb(&vlabel->vtoc, VTOC_START_CC, VTOC_START_HH, 0x01);
2610 if (anc->verbose) printf("initializing labels...\n");
2611 vtoc_init_format4_label(anc->f4, USABLE_PARTITIONS,
2612 geo.cylinders, anc->formatted_cylinders,
2613 geo.heads, geo.sectors,
2614 anc->blksize, anc->dev_type);
2616 vtoc_init_format5_label(anc->f5);
2617 vtoc_init_format7_label(anc->f7);
2619 if (anc->fspace_trk != 0) {
2620 start = FIRST_USABLE_TRK;
2621 stop = start + anc->fspace_trk - 1;
2623 vtoc_set_freespace(anc->f4, anc->f5, anc->f7, '+',
2624 anc->verbose, start, stop,
2625 anc->formatted_cylinders, geo.heads);
2628 do {
2629 if (part_info->used != 0x01)
2630 continue;
2632 vtoc_set_cchh(&llimit,
2633 part_info->start_trk / geo.heads,
2634 part_info->start_trk % geo.heads);
2635 vtoc_set_cchh(&ulimit,
2636 part_info->end_trk / geo.heads,
2637 part_info->end_trk % geo.heads);
2639 vtoc_set_extent(&ext, (vtoc_get_head_from_cchh(&llimit) == 0
2640 ? 0x81 : 0x01),
2641 0x00, &llimit, &ulimit);
2643 if (anc->formatted_cylinders > LV_COMPAT_CYL) {
2644 vtoc_init_format8_label(vlabel->volid, anc->blksize,
2645 &ext, part_info->f1);
2646 } else
2647 vtoc_init_format1_label(vlabel->volid, anc->blksize,
2648 &ext, part_info->f1);
2649 anc->used_partitions += 1;
2651 get_addr_of_highest_f1_f8_label(anc, &hf1);
2652 vtoc_update_format4_label(anc->f4, &hf1,anc->f4->DS4DSREC - 1);
2654 /* update free space labels */
2655 if (part_info->fspace_trk != 0) {
2656 start = part_info->end_trk + 1;
2657 stop = start + part_info->fspace_trk -1;
2659 vtoc_set_freespace(anc->f4, anc->f5, anc->f7, '+',
2660 anc->verbose, start, stop,
2661 anc->formatted_cylinders, geo.heads);
2663 } while ((part_info = part_info->next) != NULL);
2665 anc->vlabel_changed++;
2666 anc->vtoc_changed++;
2668 fdasd_write_labels(anc);
2669 fdasd_exit(anc, 0);
2673 * quits fdasd without saving
2675 static void
2676 fdasd_quit(fdasd_anchor_t *anc)
2678 char str[INPUT_BUF_SIZE];
2680 if ((anc->vtoc_changed)||(anc->vlabel_changed)) {
2681 snprintf(str, INPUT_BUF_SIZE,
2682 "All changes will be lost! "
2683 "Do you really want to quit?");
2685 if (yes_no(str) == 1)
2686 return;
2688 printf("exiting without saving...\n");
2690 else
2691 if (!anc->silent) printf("exiting...\n");
2693 fdasd_exit(anc, 0);
2700 main(int argc, char *argv[])
2702 fdasd_anchor_t anchor;
2703 int rc=0;
2705 fdasd_initialize_anchor(&anchor);
2707 fdasd_parse_options (&anchor, &options, argc, argv);
2708 fdasd_verify_device (&anchor, options.device);
2709 fdasd_verify_options (&anchor);
2710 fdasd_get_geometry(&anchor);
2711 fdasd_check_disk_access(&anchor);
2713 /* check dasd for labels and vtoc */
2714 rc = fdasd_check_volume(&anchor);
2716 if ((anchor.formatted_cylinders * geo.heads) > BIG_DISK_SIZE)
2717 anchor.big_disk++;
2719 if (anchor.auto_partition) {
2720 fdasd_recreate_vtoc_unconditional(&anchor);
2721 fdasd_auto_partition(&anchor);
2724 if (options.conffile) {
2725 fdasd_recreate_vtoc_unconditional(&anchor);
2726 fdasd_parse_conffile(&anchor, &options);
2727 fdasd_check_conffile_input(&anchor, &options);
2728 fdasd_auto_partition_conffile(&anchor);
2731 if (anchor.print_table) {
2732 if (rc == 0)
2733 fdasd_list_partition_table(&anchor);
2734 fdasd_quit(&anchor);
2737 if (anchor.print_volser) {
2738 fdasd_print_volser(&anchor);
2739 fdasd_quit(&anchor);
2742 fdasd_menu();
2744 while (1) {
2745 putchar('\n');
2746 switch (tolower(read_char("Command (m for help): "))) {
2747 case 'd':
2748 fdasd_remove_partition(&anchor);
2749 break;
2750 case 'n':
2751 fdasd_add_partition(&anchor);
2752 break;
2753 case 'v':
2754 fdasd_change_volser(&anchor);
2755 break;
2756 case 't':
2757 fdasd_change_part_type(&anchor);
2758 break;
2759 case 'p':
2760 fdasd_list_partition_table(&anchor);
2761 break;
2762 case 's':
2763 fdasd_show_mapping(&anchor);
2764 break;
2765 case 'u':
2766 anchor.option_reuse++;
2767 break;
2768 case 'r':
2769 anchor.option_recreate++;
2770 break;
2771 case 'm':
2772 fdasd_menu();
2773 break;
2774 case 'q':
2775 fdasd_quit(&anchor);
2776 break;
2777 case 'w':
2778 fdasd_write_labels(&anchor);
2779 fdasd_exit(&anchor, 0);
2780 default:
2781 printf("please use one of the following commands:\n");
2782 fdasd_menu();
2785 if (anchor.option_reuse) {
2786 fdasd_reuse_vtoc(&anchor);
2787 anchor.option_reuse = 0;
2790 if (anchor.option_recreate) {
2791 fdasd_recreate_vtoc(&anchor);
2792 anchor.option_recreate = 0;
2797 return -1;