1 /*
2 * CDDL HEADER START
3 *
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.
7 *
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.
12 *
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]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright (c) 1991, 2010, Oracle and/or its affiliates. All rights reserved.
24 */
25
26 /*
27 * This file contains functions to implement the partition menu commands.
28 */
29 #include <stdlib.h>
30 #include <string.h>
31 #include "global.h"
32 #include "partition.h"
33 #include "menu_partition.h"
34 #include "menu_command.h"
35 #include "modify_partition.h"
36 #include "checkdev.h"
37 #include "misc.h"
38 #include "label.h"
39 #include "auto_sense.h"
40
41 #ifdef __STDC__
42
43 /* Function prototypes for ANSI C Compilers */
44
45 static void adj_cyl_offset(struct dk_map32 *map);
46 static int check_map(struct dk_map32 *map);
47 static void get_user_map(struct dk_map32 *map, int float_part);
48 static void get_user_map_efi(struct dk_gpt *map, int float_part);
49
50 #else /* __STDC__ */
51
52 /* Function prototypes for non-ANSI C Compilers */
53
54 static void adj_cyl_offset();
55 static int check_map();
56 static void get_user_map();
57 static void get_user_map_efi();
58
59 #endif /* __STDC__ */
60
61 static char *partn_list[] = { "0", "1", "2", "3", "4", "5", "6", "7", NULL };
62
63 static char *sel_list[] = { "0", "1", "2", "3", NULL };
64
65 #define MBYTE (1024*1024)
66
67
68 /*
69 * Modify/Create a predefined partition table.
70 */
71 int
p_modify()72 p_modify()
73 {
74 struct partition_info tmp_pinfo[1];
75 struct dk_map32 *map = tmp_pinfo->pinfo_map;
76 u_ioparam_t ioparam;
77 int inpt_dflt = 0;
78 int free_hog = -1;
79 int i;
80 char tmpstr[80];
81 char tmpstr2[300];
82 int sel_type = 0;
83
84 /*
85 * There must be a current disk type (and therefore a current disk).
86 */
87 if (cur_dtype == NULL) {
88 err_print("Current Disk Type is not set.\n");
89 return (-1);
90 }
91
92 /*
93 * check if there exists a partition table for the disk.
94 */
95 if (cur_parts == NULL) {
96 err_print("Current Disk has no partition table.\n");
97 return (-1);
98 }
99
100
101 /*
102 * If the disk has mounted partitions, cannot modify
103 */
104 if (checkmount((diskaddr_t)-1, (diskaddr_t)-1)) {
105 err_print(
106 "Cannot modify disk partitions while it has mounted partitions.\n\n");
107 return (-1);
108 }
109
110 /*
111 * If the disk has partitions currently being used for
112 * swapping, cannot modify
113 */
114 if (checkswap((diskaddr_t)-1, (diskaddr_t)-1)) {
115 err_print(
116 "Cannot modify disk partitions while it is \
117 currently being used for swapping.\n");
118 return (-1);
119 }
120
121 /*
122 * Check to see if any partitions used for svm, vxvm, ZFS zpool
123 * or live upgrade are on the disk.
124 */
125 if (checkdevinuse(cur_disk->disk_name, (diskaddr_t)-1,
126 (diskaddr_t)-1, 0, 0)) {
127 err_print("Cannot modify disk partition when "
128 "partitions are in use as described.\n");
129 return (-1);
130 }
131
132 /*
133 * prompt user for a partition table base
134 */
135 if (cur_parts->pinfo_name != NULL) {
136 (void) snprintf(tmpstr, sizeof (tmpstr),
137 "\t0. Current partition table (%s)",
138 cur_parts->pinfo_name);
139 } else {
140 (void) sprintf(tmpstr,
141 "\t0. Current partition table (unnamed)");
142 }
143
144 (void) snprintf(tmpstr2, sizeof (tmpstr2),
145 "Select partitioning base:\n%s\n"
146 "\t1. All Free Hog\n"
147 "Choose base (enter number) ",
148 tmpstr);
149
150 ioparam.io_charlist = sel_list;
151 sel_type = input(FIO_MSTR, tmpstr2, '?', &ioparam,
152 &sel_type, DATA_INPUT);
153
154 switch (cur_label) {
155 case L_TYPE_SOLARIS:
156 if (sel_type == 0) {
157 /*
158 * Check for invalid parameters but do
159 * not modify the table.
160 */
161 if (check_map(cur_parts->pinfo_map)) {
162 err_print("\
163 Warning: Fix, or select a different partition table.\n");
164 return (0);
165 }
166 /*
167 * Create partition map from existing map
168 */
169 tmp_pinfo->vtoc = cur_parts->vtoc;
170 for (i = 0; i < NDKMAP; i++) {
171 map[i].dkl_nblk = cur_parts->pinfo_map[i].dkl_nblk;
172 map[i].dkl_cylno = cur_parts->pinfo_map[i].dkl_cylno;
173 }
174 } else {
175 /*
176 * Make an empty partition map, with all the space
177 * in the c partition.
178 */
179 set_vtoc_defaults(tmp_pinfo);
180 for (i = 0; i < NDKMAP; i++) {
181 map[i].dkl_nblk = 0;
182 map[i].dkl_cylno = 0;
183 }
184 map[C_PARTITION].dkl_nblk = ncyl * spc();
185
186 #if defined(i386)
187 /*
188 * Adjust for the boot and possibly alternates partitions
189 */
190 map[I_PARTITION].dkl_nblk = spc();
191 map[I_PARTITION].dkl_cylno = 0;
192 if (cur_ctype->ctype_ctype != DKC_SCSI_CCS) {
193 map[J_PARTITION].dkl_nblk = 2 * spc();
194 map[J_PARTITION].dkl_cylno = spc() / spc();
195 }
196 #endif /* defined(i386) */
197 }
198 break;
199 case L_TYPE_EFI:
200 if (sel_type == 1) {
201 for (i = 0; i < cur_parts->etoc->efi_nparts; i++) {
202 cur_parts->etoc->efi_parts[i].p_start = 0;
203 cur_parts->etoc->efi_parts[i].p_size = 0;
204 }
205 }
206 break;
207 }
208
209 fmt_print("\n");
210 if (cur_label == L_TYPE_SOLARIS) {
211 print_map(tmp_pinfo);
212 } else {
213 print_map(cur_parts);
214 }
215
216 ioparam.io_charlist = confirm_list;
217 if (input(FIO_MSTR,
218 "Do you wish to continue creating a new partition\ntable based on above table",
219 '?', &ioparam, &inpt_dflt, DATA_INPUT)) {
220 return (0);
221 }
222
223 /*
224 * get Free Hog partition
225 */
226 inpt_dflt = 1;
227 while ((free_hog < 0) && (cur_label == L_TYPE_SOLARIS)) {
228 free_hog = G_PARTITION; /* default to g partition */
229 ioparam.io_charlist = partn_list;
230 free_hog = input(FIO_MSTR, "Free Hog partition", '?',
231 &ioparam, &free_hog, DATA_INPUT);
232 /* disallow c partition */
233 if (free_hog == C_PARTITION) {
234 fmt_print("'%c' cannot be the 'Free Hog' partition.\n",
235 C_PARTITION + PARTITION_BASE);
236 free_hog = -1;
237 continue;
238 }
239 /*
240 * If user selected all float set the
241 * float to be the whole disk.
242 */
243 if (sel_type == 1) {
244 map[free_hog].dkl_nblk = map[C_PARTITION].dkl_nblk;
245 #if defined(i386)
246 map[free_hog].dkl_nblk -= map[I_PARTITION].dkl_nblk;
247 if (cur_ctype->ctype_ctype != DKC_SCSI_CCS) {
248 map[free_hog].dkl_nblk -=
249 map[J_PARTITION].dkl_nblk;
250 }
251 #endif /* defined(i386) */
252 break;
253 }
254 /*
255 * Warn the user if there is no free space in
256 * the float partition.
257 */
258 if (map[free_hog].dkl_nblk == 0) {
259 err_print("\
260 Warning: No space available from Free Hog partition.\n");
261 ioparam.io_charlist = confirm_list;
262 if (input(FIO_MSTR, "Continue", '?',
263 &ioparam, &inpt_dflt, DATA_INPUT)) {
264 free_hog = -1;
265 }
266 }
267 }
268 inpt_dflt = 0;
269
270 if (cur_label == L_TYPE_EFI) {
271 free_hog = G_PARTITION; /* default to g partition */
272 ioparam.io_charlist = partn_list;
273 free_hog = input(FIO_MSTR, "Free Hog partition", '?',
274 &ioparam, &free_hog, DATA_INPUT);
275 /* disallow c partition */
276 if (free_hog == C_PARTITION) {
277 fmt_print("'%c' cannot be the 'Free Hog' partition.\n",
278 C_PARTITION + PARTITION_BASE);
279 return (-1);
280 }
281 get_user_map_efi(cur_parts->etoc, free_hog);
282 print_map(cur_parts);
283 if (check("Ready to label disk, continue")) {
284 return (-1);
285 }
286 fmt_print("\n");
287 if (write_label()) {
288 err_print("Writing label failed\n");
289 return (-1);
290 }
291 return (0);
292 }
293 /*
294 * get user modified partition table
295 */
296 get_user_map(map, free_hog);
297
298 /*
299 * Update cylno offsets
300 */
301 adj_cyl_offset(map);
302
303 fmt_print("\n");
304 print_map(tmp_pinfo);
305
306 ioparam.io_charlist = confirm_list;
307 if (input(FIO_MSTR, "\
308 Okay to make this the current partition table", '?',
309 &ioparam, &inpt_dflt, DATA_INPUT)) {
310 return (0);
311 } else {
312 make_partition();
313 /*
314 * Update new partition map
315 */
316 for (i = 0; i < NDKMAP; i++) {
317 cur_parts->pinfo_map[i].dkl_nblk = map[i].dkl_nblk;
318 cur_parts->pinfo_map[i].dkl_cylno = map[i].dkl_cylno;
319 #ifdef i386
320 cur_parts->vtoc.v_part[i].p_start =
321 map[i].dkl_cylno * nhead * nsect;
322 cur_parts->vtoc.v_part[i].p_size =
323 map[i].dkl_nblk;
324 #endif
325 }
326 (void) p_name();
327
328 /*
329 * Label the disk now
330 */
331 if (check("Ready to label disk, continue")) {
332 return (-1);
333 }
334 fmt_print("\n");
335 if (write_label()) {
336 err_print("Writing label failed\n");
337 return (-1);
338 }
339 return (0);
340 }
341 }
342
343
344
345 /*
346 * Adjust cylinder offsets
347 */
348 static void
adj_cyl_offset(map)349 adj_cyl_offset(map)
350 struct dk_map32 *map;
351 {
352 int i;
353 int cyloffset = 0;
354
355
356 /*
357 * Update cylno offsets
358 */
359
360 #if defined(_SUNOS_VTOC_16)
361 /*
362 * Correct cylinder allocation for having the boot and alternates
363 * slice in the beginning of the disk
364 */
365 for (i = NDKMAP/2; i < NDKMAP; i++) {
366 if (i != C_PARTITION && map[i].dkl_nblk) {
367 map[i].dkl_cylno = cyloffset;
368 cyloffset += (map[i].dkl_nblk + (spc()-1))/spc();
369 } else if (map[i].dkl_nblk == 0) {
370 map[i].dkl_cylno = 0;
371 }
372 }
373 for (i = 0; i < NDKMAP/2; i++) {
374
375 #else /* !defined(_SUNOS_VTOC_16) */
376 for (i = 0; i < NDKMAP; i++) {
377 #endif /* defined(_SUNOS_VTOC_16) */
378
379 if (i != C_PARTITION && map[i].dkl_nblk) {
380 map[i].dkl_cylno = cyloffset;
381 cyloffset += (map[i].dkl_nblk + (spc()-1))/spc();
382 } else if (map[i].dkl_nblk == 0) {
383 map[i].dkl_cylno = 0;
384 }
385 }
386 }
387
388
389 /*
390 * Check partition table
391 */
392 static int
check_map(map)393 check_map(map)
394 struct dk_map32 *map;
395 {
396 int i;
397 int cyloffset = 0;
398 blkaddr32_t tot_blks = 0;
399
400 #ifdef i386
401 /*
402 * On x86, we must account for the boot and alternates
403 */
404 cyloffset = map[0].dkl_cylno;
405 tot_blks = map[0].dkl_nblk;
406 #endif
407
408 /*
409 * Do some checks for invalid parameters but do
410 * not modify the table.
411 */
412 for (i = 0; i < NDKMAP; i++) {
413 if (map[i].dkl_cylno > (blkaddr32_t)ncyl-1) {
414 err_print("\
415 Warning: Partition %c starting cylinder %d is out of range.\n",
416 (PARTITION_BASE+i), map[i].dkl_cylno);
417 return (-1);
418 }
419 if (map[i].dkl_nblk >
420 (blkaddr32_t)(ncyl - map[i].dkl_cylno) * spc()) {
421 err_print("\
422 Warning: Partition %c, specified # of blocks, %u, is out of range.\n",
423 (PARTITION_BASE+i), map[i].dkl_nblk);
424 return (-1);
425 }
426 if (i != C_PARTITION && map[i].dkl_nblk) {
427 #ifdef i386
428 if (i == I_PARTITION || i == J_PARTITION)
429 continue;
430 #endif
431 if (map[i].dkl_cylno < cyloffset) {
432 err_print(
433 "Warning: Overlapping partition (%c) in table.\n", PARTITION_BASE+i);
434 return (-1);
435 } else if (map[i].dkl_cylno > cyloffset) {
436 err_print(
437 "Warning: Non-contiguous partition (%c) in table.\n", PARTITION_BASE+i);
438 }
439 cyloffset += (map[i].dkl_nblk + (spc()-1))/spc();
440 tot_blks = map[i].dkl_nblk;
441 }
442 }
443 if (tot_blks > map[C_PARTITION].dkl_nblk) {
444 err_print("\
445 Warning: Total blocks used is greater than number of blocks in '%c'\n\
446 \tpartition.\n", C_PARTITION + PARTITION_BASE);
447 return (-1);
448 }
449 return (0);
450 }
451
452
453
454 /*
455 * get user defined partitions
456 */
457 static void
get_user_map(map,float_part)458 get_user_map(map, float_part)
459 struct dk_map32 *map;
460 int float_part;
461 {
462 int i;
463 blkaddr32_t newsize;
464 blkaddr32_t deflt;
465 char tmpstr[80];
466 u_ioparam_t ioparam;
467
468 /*
469 * Get partition sizes
470 */
471 for (i = 0; i < NDKMAP; i++) {
472 if (partn_list[i] == NULL)
473 break;
474 if ((i == C_PARTITION) || (i == float_part))
475 continue;
476 else {
477 ioparam.io_bounds.lower = 0;
478 ioparam.io_bounds.upper = map[i].dkl_nblk +
479 map[float_part].dkl_nblk;
480 deflt = map[i].dkl_nblk;
481 if (ioparam.io_bounds.upper == 0) {
482 err_print("\
483 Warning: no space available for '%s' from Free Hog partition\n",
484 partn_list[i]);
485 continue;
486 }
487 (void) snprintf(tmpstr, sizeof (tmpstr),
488 "Enter size of partition '%s' ",
489 partn_list[i]);
490 newsize = (blkaddr32_t)input(FIO_CYL, tmpstr, ':',
491 &ioparam, (int *)&deflt, DATA_INPUT);
492 map[float_part].dkl_nblk -= (newsize - map[i].dkl_nblk);
493 map[i].dkl_nblk = newsize;
494 }
495 }
496 }
497
498 static struct partition_info *
build_partition(tptr)499 build_partition(tptr)
500 struct disk_type *tptr;
501 {
502 struct partition_info *part;
503 struct dk_label *label;
504 int i;
505
506 #ifdef DEBUG
507 fmt_print("Creating Default Partition for the disk \n");
508 #endif
509 /*
510 * construct a label and pass it on to
511 * build_default_partition() which builds the
512 * default partition list.
513 */
514 label = zalloc(sizeof (struct dk_label));
515 label->dkl_pcyl = tptr->dtype_pcyl;
516 label->dkl_ncyl = tptr->dtype_ncyl;
517 label->dkl_acyl = tptr->dtype_acyl;
518 label->dkl_nhead = tptr->dtype_nhead;
519 label->dkl_nsect = tptr->dtype_nsect;
520 label->dkl_apc = apc;
521 label->dkl_intrlv = 1;
522 label->dkl_rpm = tptr->dtype_rpm;
523
524 if (!build_default_partition(label, cur_ctype->ctype_ctype))
525 return (NULL);
526
527 part = (struct partition_info *)
528 zalloc(sizeof (struct partition_info));
529 part->pinfo_name = alloc_string(tptr->dtype_asciilabel);
530 /*
531 * Fill in the partition info from the label
532 */
533 for (i = 0; i < NDKMAP; i++) {
534 #if defined(_SUNOS_VTOC_8)
535 part->pinfo_map[i] = label->dkl_map[i];
536 #else
537 part->pinfo_map[i].dkl_cylno =
538 label->dkl_vtoc.v_part[i].p_start /
539 (blkaddr32_t)(tptr->dtype_nhead * tptr->dtype_nsect - apc);
540 part->pinfo_map[i].dkl_nblk =
541 label->dkl_vtoc.v_part[i].p_size;
542 #endif /* ifdefined(_SUNOS_VTOC_8) */
543 }
544 part->vtoc = label->dkl_vtoc;
545 return (part);
546 }
547
548 /*
549 * build new partition table for given disk type
550 */
551 static void
get_user_map_efi(map,float_part)552 get_user_map_efi(map, float_part)
553 struct dk_gpt *map;
554 int float_part;
555 {
556
557 int i;
558 efi_deflt_t efi_deflt;
559 u_ioparam_t ioparam;
560 char tmpstr[80];
561 uint64_t i64;
562 uint64_t start_lba = 34;
563
564 for (i = 0; i < map->efi_nparts - 1; i++) {
565 if (i == float_part)
566 continue;
567 else {
568 ioparam.io_bounds.lower = start_lba;
569 ioparam.io_bounds.upper = map->efi_last_u_lba;
570 efi_deflt.start_sector = ioparam.io_bounds.lower;
571 efi_deflt.end_sector = map->efi_parts[i].p_size;
572 (void) sprintf(tmpstr,
573 "Enter size of partition %d ", i);
574 i64 = input(FIO_EFI, tmpstr, ':',
575 &ioparam, (int *)&efi_deflt, DATA_INPUT);
576 if (i64 == 0) {
577 map->efi_parts[i].p_tag = V_UNASSIGNED;
578 } else if ((i64 != 0) && (map->efi_parts[i].p_tag ==
579 V_UNASSIGNED)) {
580 map->efi_parts[i].p_tag = V_USR;
581 }
582 if (i64 == 0) {
583 map->efi_parts[i].p_start = 0;
584 } else {
585 map->efi_parts[i].p_start = start_lba;
586 }
587 map->efi_parts[i].p_size = i64;
588 start_lba += i64;
589 }
590 }
591 map->efi_parts[float_part].p_start = start_lba;
592 map->efi_parts[float_part].p_size = map->efi_last_u_lba -
593 start_lba - (1024 * 16);
594 map->efi_parts[float_part].p_tag = V_USR;
595 if (map->efi_parts[float_part].p_size == UINT_MAX64) {
596 map->efi_parts[float_part].p_size = 0;
597 map->efi_parts[float_part].p_start = 0;
598 map->efi_parts[float_part].p_tag = V_UNASSIGNED;
599 fmt_print("Warning: No space left for HOG\n");
600 }
601
602 for (i = 0; i < map->efi_nparts; i++) {
603 if (map->efi_parts[i].p_tag == V_RESERVED) {
604 map->efi_parts[i].p_start = map->efi_last_u_lba -
605 (1024 * 16);
606 map->efi_parts[i].p_size = (1024 * 16);
607 break;
608 }
609 }
610 }
611
612
613 void
new_partitiontable(tptr,oldtptr)614 new_partitiontable(tptr, oldtptr)
615 struct disk_type *tptr, *oldtptr;
616 {
617 struct partition_info *part;
618
619 /*
620 * check if disk geometry has changed , if so add new
621 * partition table else copy the old partition table.(best guess).
622 */
623 if ((oldtptr != NULL) &&
624 (tptr->dtype_ncyl == oldtptr->dtype_ncyl) &&
625 (tptr->dtype_nhead == oldtptr->dtype_nhead) &&
626 (tptr->dtype_nsect == oldtptr->dtype_nsect)) {
627
628 part = (struct partition_info *)
629 zalloc(sizeof (struct partition_info));
630 bcopy((char *)cur_parts, (char *)part,
631 sizeof (struct partition_info));
632 part->pinfo_next = tptr->dtype_plist;
633 tptr->dtype_plist = part;
634 } else {
635
636 #ifdef DEBUG
637 if (cur_parts != NULL) {
638 fmt_print("Warning: Partition Table is set");
639 fmt_print("to default partition table. \n");
640 }
641 #endif
642 if (tptr->dtype_plist == NULL) {
643 part = (struct partition_info *)build_partition(tptr);
644 if (part != NULL) {
645 part->pinfo_next = tptr->dtype_plist;
646 tptr->dtype_plist = part;
647 }
648 }
649 }
650 }
651