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