Merge remote-tracking branch 'origin/master'
[unleashed/lotheac.git] / usr / src / cmd / format / menu_partition.c
blob69b878d301043a6af23d94c4d34100276e99430a
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
19 * CDDL HEADER END
22 * Copyright (c) 1991, 2010, Oracle and/or its affiliates. All rights reserved.
26 * This file contains functions to implement the partition menu commands.
28 #include "global.h"
29 #include <stdlib.h>
30 #include <string.h>
32 #include "partition.h"
33 #include "menu_partition.h"
34 #include "menu_command.h"
35 #include "misc.h"
36 #include "param.h"
38 #ifdef __STDC__
40 /* Function prototypes for ANSI C Compilers */
41 static void nspaces(int);
42 static int ndigits(uint64_t);
44 #else /* __STDC__ */
46 /* Function prototypes for non-ANSI C Compilers */
47 static void nspaces();
48 static int ndigits();
50 #endif /* __STDC__ */
53 * This routine implements the 'a' command. It changes the 'a' partition.
55 int
56 p_apart()
59 change_partition(0);
60 return (0);
64 * This routine implements the 'b' command. It changes the 'b' partition.
66 int
67 p_bpart()
70 change_partition(1);
71 return (0);
75 * This routine implements the 'c' command. It changes the 'c' partition.
77 int
78 p_cpart()
81 change_partition(2);
82 return (0);
86 * This routine implements the 'd' command. It changes the 'd' partition.
88 int
89 p_dpart()
92 change_partition(3);
93 return (0);
97 * This routine implements the 'e' command. It changes the 'e' partition.
99 int
100 p_epart()
103 change_partition(4);
104 return (0);
108 * This routine implements the 'f' command. It changes the 'f' partition.
111 p_fpart()
114 change_partition(5);
115 return (0);
119 * This routine implements the 'g' command. It changes the 'g' partition.
122 p_gpart()
125 change_partition(6);
126 return (0);
130 * This routine implements the 'h' command. It changes the 'h' partition.
133 p_hpart()
136 change_partition(7);
137 return (0);
141 * This routine implements the 'i' command. It is valid only for EFI
142 * labeled disks. This can be used only in expert mode.
145 p_ipart()
147 change_partition(8);
148 return (0);
151 #if defined(i386)
153 * This routine implements the 'j' command. It changes the 'j' partition.
156 p_jpart()
159 change_partition(9);
160 return (0);
162 #endif /* defined(i386) */
165 p_expand()
167 uint64_t delta;
168 uint_t nparts;
169 struct dk_gpt *efi_label = cur_parts->etoc;
171 if (cur_parts->etoc->efi_altern_lba == 1 ||
172 (cur_parts->etoc->efi_altern_lba >=
173 cur_parts->etoc->efi_last_lba)) {
174 err_print("Warning: No expanded capacity is found.\n");
175 return (0);
178 delta = efi_label->efi_last_lba - efi_label->efi_altern_lba;
179 nparts = efi_label->efi_nparts;
181 enter_critical();
182 efi_label->efi_parts[nparts - 1].p_start += delta;
183 efi_label->efi_last_u_lba += delta;
184 efi_label->efi_altern_lba = cur_parts->etoc->efi_last_lba;
185 exit_critical();
187 fmt_print("The expanded capacity is added to the unallocated space.\n");
188 return (0);
192 * This routine implements the 'select' command. It allows the user
193 * to make a pre-defined partition map the current map.
196 p_select()
198 struct partition_info *pptr, *parts;
199 u_ioparam_t ioparam;
200 int i, index, deflt, *defltptr = NULL;
201 blkaddr_t b_cylno;
202 #if defined(i386)
203 blkaddr_t cyl_offset;
204 #endif
206 parts = cur_dtype->dtype_plist;
208 * If there are no pre-defined maps for this disk type, it's
209 * an error.
211 if (parts == NULL) {
212 err_print("No defined partition tables.\n");
213 return (-1);
217 * Loop through the pre-defined maps and list them by name. If
218 * the current map is one of them, make it the default. If any
219 * the maps are unnamed, label them as such.
221 for (i = 0, pptr = parts; pptr != NULL; pptr = pptr->pinfo_next) {
222 if (cur_parts == pptr) {
223 deflt = i;
224 defltptr = &deflt;
226 if (pptr->pinfo_name == NULL)
227 fmt_print(" %d. unnamed\n", i++);
228 else
229 fmt_print(" %d. %s\n", i++, pptr->pinfo_name);
231 ioparam.io_bounds.lower = 0;
232 ioparam.io_bounds.upper = i - 1;
234 * Ask which map should be made current.
236 index = input(FIO_INT, "Specify table (enter its number)", ':',
237 &ioparam, defltptr, DATA_INPUT);
238 for (i = 0, pptr = parts; i < index; i++, pptr = pptr->pinfo_next)
240 if (cur_label == L_TYPE_EFI) {
241 enter_critical();
242 cur_disk->disk_parts = cur_parts = pptr;
243 exit_critical();
244 fmt_print("\n");
245 return (0);
247 #if defined(i386)
249 * Adjust for the boot and alternate sectors partition - assuming that
250 * the alternate sectors partition physical location follows
251 * immediately the boot partition and partition sizes are
252 * expressed in multiple of cylinder size.
254 cyl_offset = pptr->pinfo_map[I_PARTITION].dkl_cylno + 1;
255 if (pptr->pinfo_map[J_PARTITION].dkl_nblk != 0) {
256 cyl_offset = pptr->pinfo_map[J_PARTITION].dkl_cylno +
257 ((pptr->pinfo_map[J_PARTITION].dkl_nblk +
258 (spc() - 1)) / spc());
260 #else /* !defined(i386) */
262 b_cylno = 0;
264 #endif /* defined(i386) */
267 * Before we blow the current map away, do some limits checking.
269 for (i = 0; i < NDKMAP; i++) {
271 #if defined(i386)
272 if (i == I_PARTITION || i == J_PARTITION || i == C_PARTITION) {
273 b_cylno = 0;
274 } else if (pptr->pinfo_map[i].dkl_nblk == 0) {
276 * Always accept starting cyl 0 if the size is 0 also
278 b_cylno = 0;
279 } else {
280 b_cylno = cyl_offset;
282 #endif /* defined(i386) */
283 if (pptr->pinfo_map[i].dkl_cylno < b_cylno ||
284 pptr->pinfo_map[i].dkl_cylno > (ncyl-1)) {
285 err_print(
286 "partition %c: starting cylinder %d is out of range\n",
287 (PARTITION_BASE+i),
288 pptr->pinfo_map[i].dkl_cylno);
289 return (0);
291 if (pptr->pinfo_map[i].dkl_nblk > ((ncyl -
292 pptr->pinfo_map[i].dkl_cylno) * spc())) {
293 err_print(
294 "partition %c: specified # of blocks, %u, "
295 "is out of range\n",
296 (PARTITION_BASE+i),
297 pptr->pinfo_map[i].dkl_nblk);
298 return (0);
302 * Lock out interrupts so the lists don't get mangled.
304 enter_critical();
306 * If the old current map is unnamed, delete it.
308 if (cur_parts != NULL && cur_parts != pptr &&
309 cur_parts->pinfo_name == NULL)
310 delete_partition(cur_parts);
312 * Make the selected map current.
314 cur_disk->disk_parts = cur_parts = pptr;
316 #if defined(_SUNOS_VTOC_16)
317 for (i = 0; i < NDKMAP; i++) {
318 cur_parts->vtoc.v_part[i].p_start =
319 (blkaddr_t)(cur_parts->pinfo_map[i].dkl_cylno *
320 (nhead * nsect));
321 cur_parts->vtoc.v_part[i].p_size =
322 (blkaddr_t)cur_parts->pinfo_map[i].dkl_nblk;
324 #endif /* defined(_SUNOS_VTOC_16) */
326 exit_critical();
327 fmt_print("\n");
328 return (0);
332 * This routine implements the 'name' command. It allows the user
333 * to name the current partition map. If the map was already named,
334 * the name is changed. Once a map is named, the values of the partitions
335 * cannot be changed. Attempts to change them will cause another map
336 * to be created.
339 p_name()
341 char *name;
344 * check if there exists a partition table for the disk.
346 if (cur_parts == NULL) {
347 err_print("Current Disk has no partition table.\n");
348 return (-1);
353 * Ask for the name. Note that the input routine will malloc
354 * space for the name since we are using the OSTR input type.
356 name = (char *)(uintptr_t)input(FIO_OSTR,
357 "Enter table name (remember quotes)",
358 ':', (u_ioparam_t *)NULL, NULL, DATA_INPUT);
360 * Lock out interrupts.
362 enter_critical();
364 * If it was already named, destroy the old name.
366 if (cur_parts->pinfo_name != NULL)
367 destroy_data(cur_parts->pinfo_name);
369 * Set the name.
371 cur_parts->pinfo_name = name;
372 exit_critical();
373 fmt_print("\n");
374 return (0);
379 * This routine implements the 'print' command. It lists the values
380 * for all the partitions in the current partition map.
383 p_print()
386 * check if there exists a partition table for the disk.
388 if (cur_parts == NULL) {
389 err_print("Current Disk has no partition table.\n");
390 return (-1);
394 * Print the volume name, if it appears to be set
396 if (chk_volname(cur_disk)) {
397 fmt_print("Volume: ");
398 print_volname(cur_disk);
399 fmt_print("\n");
402 * Print the name of the current map.
404 if ((cur_parts->pinfo_name != NULL) && (cur_label == L_TYPE_SOLARIS)) {
405 fmt_print("Current partition table (%s):\n",
406 cur_parts->pinfo_name);
407 fmt_print("Total disk cylinders available: %d + %d "
408 "(reserved cylinders)\n\n", ncyl, acyl);
409 } else if (cur_label == L_TYPE_SOLARIS) {
410 fmt_print("Current partition table (unnamed):\n");
411 fmt_print("Total disk cylinders available: %d + %d "
412 "(reserved cylinders)\n\n", ncyl, acyl);
413 } else if (cur_label == L_TYPE_EFI) {
414 fmt_print("Current partition table (%s):\n",
415 cur_parts->pinfo_name != NULL ?
416 cur_parts->pinfo_name : "unnamed");
417 fmt_print("Total disk sectors available: %llu + %d "
418 "(reserved sectors)\n\n",
419 cur_parts->etoc->efi_last_u_lba - EFI_MIN_RESV_SIZE -
420 cur_parts->etoc->efi_first_u_lba + 1, EFI_MIN_RESV_SIZE);
425 * Print the partition map itself
427 print_map(cur_parts);
428 return (0);
433 * Print a partition map
435 void
436 print_map(struct partition_info *map)
438 int i;
439 int want_header;
440 struct dk_gpt *vtoc64;
442 if (cur_label == L_TYPE_EFI) {
443 vtoc64 = map->etoc;
444 want_header = 1;
445 for (i = 0; i < vtoc64->efi_nparts; i++) {
447 * we want to print partitions above 7 in expert mode only
448 * or if the partition is reserved
450 if (i >= 7 && !expert_mode &&
451 ((int)vtoc64->efi_parts[i].p_tag !=
452 V_RESERVED)) {
453 continue;
456 print_efi_partition(vtoc64, i, want_header);
457 want_header = 0;
459 fmt_print("\n");
460 return;
463 * Loop through each partition, printing the header
464 * the first time.
466 want_header = 1;
467 for (i = 0; i < NDKMAP; i++) {
468 if (i > 9) {
469 break;
471 print_partition(map, i, want_header);
472 want_header = 0;
475 fmt_print("\n");
479 * Print out one line of partition information,
480 * with optional header for EFI type disks.
482 /*ARGSUSED*/
483 void
484 print_efi_partition(struct dk_gpt *map, int partnum, int want_header)
486 int ncyl2_digits = 0;
487 float scaled;
488 char *s;
489 uint64_t secsize;
491 ncyl2_digits = ndigits(map->efi_last_u_lba);
492 if (want_header) {
493 fmt_print("Part ");
494 fmt_print("Tag Flag ");
495 fmt_print("First Sector");
496 nspaces(ncyl2_digits);
497 fmt_print("Size");
498 nspaces(ncyl2_digits);
499 fmt_print("Last Sector\n");
502 fmt_print(" %d ", partnum);
503 s = find_string(ptag_choices,
504 (int)map->efi_parts[partnum].p_tag);
505 if (s == NULL)
506 s = "-";
507 nspaces(10 - (int)strlen(s));
508 fmt_print("%s", s);
510 s = find_string(pflag_choices,
511 (int)map->efi_parts[partnum].p_flag);
512 if (s == NULL)
513 s = "-";
514 nspaces(6 - (int)strlen(s));
515 fmt_print("%s", s);
517 nspaces(2);
519 secsize = map->efi_parts[partnum].p_size;
520 if (secsize == 0) {
521 fmt_print("%16llu", map->efi_parts[partnum].p_start);
522 nspaces(ncyl2_digits);
523 fmt_print(" 0 ");
524 } else {
525 fmt_print("%16llu", map->efi_parts[partnum].p_start);
526 scaled = bn2mb(secsize);
527 nspaces(ncyl2_digits - 5);
528 if (scaled >= (float)1024.0 * 1024) {
529 fmt_print("%8.2fTB", scaled/((float)1024.0 * 1024));
530 } else if (scaled >= (float)1024.0) {
531 fmt_print("%8.2fGB", scaled/(float)1024.0);
532 } else {
533 fmt_print("%8.2fMB", scaled);
536 nspaces(ncyl2_digits);
537 if ((map->efi_parts[partnum].p_start+secsize - 1) ==
538 UINT_MAX64) {
539 fmt_print(" 0 \n");
540 } else {
541 fmt_print(" %llu \n",
542 map->efi_parts[partnum].p_start+secsize - 1);
547 * Print out one line of partition information,
548 * with optional header.
550 /*ARGSUSED*/
551 void
552 print_partition(struct partition_info *pinfo, int partnum, int want_header)
554 int i;
555 blkaddr_t nblks;
556 int cyl1;
557 int cyl2;
558 float scaled;
559 int maxcyl2;
560 int ncyl2_digits;
561 char *s;
562 blkaddr_t maxnblks = 0;
563 blkaddr_t len;
566 * To align things nicely, we need to know the maximum
567 * width of the number of cylinders field.
569 maxcyl2 = 0;
570 for (i = 0; i < NDKMAP; i++) {
571 nblks = (uint_t)pinfo->pinfo_map[i].dkl_nblk;
572 cyl1 = pinfo->pinfo_map[i].dkl_cylno;
573 cyl2 = cyl1 + (nblks / spc()) - 1;
574 if (nblks > 0) {
575 maxcyl2 = max(cyl2, maxcyl2);
576 maxnblks = max(nblks, maxnblks);
580 * Get the number of digits required
582 ncyl2_digits = ndigits(maxcyl2);
585 * Print the header, if necessary
587 if (want_header) {
588 fmt_print("Part ");
589 fmt_print("Tag Flag ");
590 fmt_print("Cylinders");
591 nspaces(ncyl2_digits);
592 fmt_print(" Size Blocks\n");
596 * Print the partition information
598 nblks = pinfo->pinfo_map[partnum].dkl_nblk;
599 cyl1 = pinfo->pinfo_map[partnum].dkl_cylno;
600 cyl2 = cyl1 + (nblks / spc()) - 1;
602 fmt_print(" %x ", partnum);
605 * Print the partition tag. If invalid, print -
607 s = find_string(ptag_choices,
608 (int)pinfo->vtoc.v_part[partnum].p_tag);
609 if (s == NULL)
610 s = "-";
611 nspaces(10 - (int)strlen(s));
612 fmt_print("%s", s);
615 * Print the partition flag. If invalid print -
617 s = find_string(pflag_choices,
618 (int)pinfo->vtoc.v_part[partnum].p_flag);
619 if (s == NULL)
620 s = "-";
621 nspaces(6 - (int)strlen(s));
622 fmt_print("%s", s);
624 nspaces(2);
626 if (nblks == 0) {
627 fmt_print("%6d ", cyl1);
628 nspaces(ncyl2_digits);
629 fmt_print(" 0 ");
630 } else {
631 fmt_print("%6d - ", cyl1);
632 nspaces(ncyl2_digits - ndigits(cyl2));
633 fmt_print("%d ", cyl2);
634 scaled = bn2mb(nblks);
635 if (scaled > (float)1024.0 * 1024.0) {
636 fmt_print("%8.2fTB ",
637 scaled/((float)1024.0 * 1024.0));
638 } else if (scaled > (float)1024.0) {
639 fmt_print("%8.2fGB ", scaled/(float)1024.0);
640 } else {
641 fmt_print("%8.2fMB ", scaled);
644 fmt_print("(");
645 pr_dblock(fmt_print, nblks);
646 fmt_print(")");
648 nspaces(ndigits(maxnblks/spc()) - ndigits(nblks/spc()));
650 * Allocates size of the printf format string.
651 * ndigits(ndigits(maxblks)) gives the byte size of
652 * the printf width field for maxnblks.
654 len = strlen(" %") + ndigits(ndigits(maxnblks)) + strlen("d\n") + 1;
655 s = zalloc(len);
656 (void) snprintf(s, len, "%s%u%s", " %", ndigits(maxnblks), "u\n");
657 fmt_print(s, nblks);
658 (void) free(s);
663 * Return true if a disk has a volume name
666 chk_volname(disk)
667 struct disk_info *disk;
669 return (disk->v_volume[0] != 0);
674 * Print the volume name, if it appears to be set
676 void
677 print_volname(disk)
678 struct disk_info *disk;
680 int i;
681 char *p;
683 p = disk->v_volume;
684 for (i = 0; i < LEN_DKL_VVOL; i++, p++) {
685 if (*p == 0)
686 break;
687 fmt_print("%c", *p);
693 * Print a number of spaces
695 static void
696 nspaces(n)
697 int n;
699 while (n-- > 0)
700 fmt_print(" ");
704 * Return the number of digits required to print a number
706 static int
707 ndigits(n)
708 uint64_t n;
710 int i;
712 i = 0;
713 while (n > 0) {
714 n /= 10;
715 i++;
718 return (i == 0 ? 1 : i);