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 that operate on partition tables.
28 */
29 #include <string.h>
30 #include <stdlib.h>
31 #include "global.h"
32 #include "partition.h"
33 #include "misc.h"
34 #include "menu_command.h"
35 #include "menu_partition.h"
36
37
38 /*
39 * Default vtoc information for non-SVr4 partitions
40 */
41 struct dk_map2 default_vtoc_map[NDKMAP] = {
42 { V_ROOT, 0 }, /* a - 0 */
43 { V_SWAP, V_UNMNT }, /* b - 1 */
44 { V_BACKUP, V_UNMNT }, /* c - 2 */
45 { V_UNASSIGNED, 0 }, /* d - 3 */
46 { V_UNASSIGNED, 0 }, /* e - 4 */
47 { V_UNASSIGNED, 0 }, /* f - 5 */
48 { V_USR, 0 }, /* g - 6 */
49 { V_UNASSIGNED, 0 }, /* h - 7 */
50
51 #if defined(_SUNOS_VTOC_16)
52
53 #if defined(i386)
54 { V_BOOT, V_UNMNT }, /* i - 8 */
55 { V_ALTSCTR, 0 }, /* j - 9 */
56
57 #else
58 #error No VTOC format defined.
59 #endif /* defined(i386) */
60
61 { V_UNASSIGNED, 0 }, /* k - 10 */
62 { V_UNASSIGNED, 0 }, /* l - 11 */
63 { V_UNASSIGNED, 0 }, /* m - 12 */
64 { V_UNASSIGNED, 0 }, /* n - 13 */
65 { V_UNASSIGNED, 0 }, /* o - 14 */
66 { V_UNASSIGNED, 0 }, /* p - 15 */
67 #endif /* defined(_SUNOS_VTOC_16) */
68 };
69
70 /*
71 * This routine finds the last usable sector in the partition table.
72 * It skips the BACKUP partition.
73 */
74 static uint64_t
maxofN(struct dk_gpt * map)75 maxofN(struct dk_gpt *map)
76 {
77 uint64_t max;
78 uint64_t sec_no[2], start[2], size[2];
79 int i;
80
81 for (i = 0; i < map->efi_nparts - 1; i++) {
82 start[0] = map->efi_parts[i].p_start;
83 size[0] = map->efi_parts[i].p_size;
84 sec_no[0] = start[0] + size[0];
85
86 start[1] = map->efi_parts[i+1].p_start;
87 size[1] = map->efi_parts[i+1].p_size;
88 sec_no[1] = start[1] + size[1];
89
90 if (map->efi_parts[i].p_tag == V_BACKUP) {
91 sec_no[0] = 0;
92 }
93 if (map->efi_parts[i+1].p_tag == V_BACKUP) {
94 sec_no[1] = 0;
95 }
96 if (i == 0) {
97 max = sec_no[1];
98 }
99 if (sec_no[0] > max) {
100 max = sec_no[0];
101 } else {
102 max = max;
103 }
104 }
105 if (max == 0)
106 max = 34;
107 return (max);
108 }
109
110 /*
111 * This routine allows the user to change the boundaries of the given
112 * partition in the current partition map.
113 */
114 void
change_partition(int num)115 change_partition(int num)
116 {
117 uint_t i;
118 uint64_t i64, j64;
119 uint_t j;
120 int deflt;
121 part_deflt_t p_deflt;
122 u_ioparam_t ioparam;
123 int tag;
124 int flag;
125 char msg[256];
126 blkaddr32_t cyl_offset = 0;
127 efi_deflt_t efi_deflt;
128
129 /*
130 * check if there exists a partition table for the disk.
131 */
132 if (cur_parts == NULL) {
133 err_print("Current Disk has no partition table.\n");
134 return;
135 }
136
137 if (cur_label == L_TYPE_EFI) {
138 if (num > cur_parts->etoc->efi_nparts - 1) {
139 err_print("Invalid partition for EFI label\n");
140 return;
141 }
142 print_efi_partition(cur_parts->etoc, num, 1);
143 fmt_print("\n");
144 /*
145 * Prompt for p_tag and p_flag values for this partition
146 */
147 deflt = cur_parts->etoc->efi_parts[num].p_tag;
148 if (deflt == V_UNASSIGNED) {
149 deflt = V_USR;
150 }
151 (void) sprintf(msg, "Enter partition id tag");
152 ioparam.io_slist = ptag_choices;
153 tag = input(FIO_SLIST, msg, ':', &ioparam, &deflt, DATA_INPUT);
154
155 deflt = cur_parts->etoc->efi_parts[num].p_flag;
156 (void) sprintf(msg, "Enter partition permission flags");
157 ioparam.io_slist = pflag_choices;
158 flag = input(FIO_SLIST, msg, ':', &ioparam, &deflt, DATA_INPUT);
159
160 ioparam.io_bounds.lower = 34;
161 ioparam.io_bounds.upper = cur_parts->etoc->efi_last_u_lba;
162
163 efi_deflt.start_sector = maxofN(cur_parts->etoc);
164 if ((cur_parts->etoc->efi_parts[num].p_start != 0) &&
165 (cur_parts->etoc->efi_parts[num].p_size != 0)) {
166 efi_deflt.start_sector =
167 cur_parts->etoc->efi_parts[num].p_start;
168 }
169 efi_deflt.end_sector = ioparam.io_bounds.upper -
170 efi_deflt.start_sector;
171 i64 = input(FIO_INT64, "Enter new starting Sector", ':', &ioparam,
172 (int *)&efi_deflt, DATA_INPUT);
173
174 ioparam.io_bounds.lower = 0;
175 ioparam.io_bounds.upper = cur_parts->etoc->efi_last_u_lba;
176 efi_deflt.end_sector = cur_parts->etoc->efi_parts[num].p_size;
177 efi_deflt.start_sector = i64;
178 j64 = input(FIO_EFI, "Enter partition size", ':', &ioparam,
179 (int *)&efi_deflt, DATA_INPUT);
180 if (j64 == 0) {
181 tag = V_UNASSIGNED;
182 i64 = 0;
183 } else if ((j64 != 0) && (tag == V_UNASSIGNED)) {
184 tag = V_USR;
185 }
186
187 if (cur_parts->pinfo_name != NULL)
188 make_partition();
189
190 cur_parts->etoc->efi_parts[num].p_tag = tag;
191 cur_parts->etoc->efi_parts[num].p_flag = flag;
192 cur_parts->etoc->efi_parts[num].p_start = i64;
193 cur_parts->etoc->efi_parts[num].p_size = j64;
194 /*
195 * We are now done with EFI part, so return now
196 */
197 return;
198 }
199 /*
200 * Print out the given partition so the user knows what he/she's
201 * getting into.
202 */
203 print_partition(cur_parts, num, 1);
204 fmt_print("\n");
205
206 /*
207 * Prompt for p_tag and p_flag values for this partition.
208 */
209 assert(cur_parts->vtoc.v_version == V_VERSION);
210 deflt = cur_parts->vtoc.v_part[num].p_tag;
211 (void) sprintf(msg, "Enter partition id tag");
212 ioparam.io_slist = ptag_choices;
213 tag = input(FIO_SLIST, msg, ':', &ioparam, &deflt, DATA_INPUT);
214
215 deflt = cur_parts->vtoc.v_part[num].p_flag;
216 (void) sprintf(msg, "Enter partition permission flags");
217 ioparam.io_slist = pflag_choices;
218 flag = input(FIO_SLIST, msg, ':', &ioparam, &deflt, DATA_INPUT);
219
220 /*
221 * Ask for the new values. The old values are the defaults, and
222 * strict bounds checking is done on the values given.
223 */
224
225 #if defined(i386)
226
227 if (tag != V_UNASSIGNED && tag != V_BACKUP && tag != V_BOOT) {
228 /*
229 * Determine cyl offset for boot and alternate partitions.
230 * Assuming that the alternate sectors partition (slice)
231 * physical location immediately follows the boot
232 * partition and partition sizes are expressed in multiples
233 * of cylinder size.
234 */
235 cyl_offset = cur_parts->pinfo_map[I_PARTITION].dkl_cylno + 1;
236 if (tag != V_ALTSCTR) {
237 if (cur_parts->pinfo_map[J_PARTITION].dkl_nblk != 0) {
238 cyl_offset =
239 cur_parts->pinfo_map[J_PARTITION].dkl_cylno +
240 ((cur_parts->pinfo_map[J_PARTITION].dkl_nblk +
241 (spc()-1)) / spc());
242 }
243 }
244 }
245 #endif /* defined(i386) */
246
247 ioparam.io_bounds.lower = 0;
248 ioparam.io_bounds.upper = ncyl - 1;
249 deflt = max(cur_parts->pinfo_map[num].dkl_cylno,
250 cyl_offset);
251 i = (uint_t)input(FIO_INT, "Enter new starting cyl", ':', &ioparam,
252 &deflt, DATA_INPUT);
253
254 ioparam.io_bounds.lower = 0;
255 ioparam.io_bounds.upper = (ncyl - i) * spc();
256
257 /* fill in defaults for the current partition */
258 p_deflt.start_cyl = i;
259 p_deflt.deflt_size =
260 min(cur_parts->pinfo_map[num].dkl_nblk,
261 ioparam.io_bounds.upper);
262
263 /* call input, passing p_deflt's address, typecast to (int *) */
264 j = (uint_t)input(FIO_ECYL, "Enter partition size", ':', &ioparam,
265 (int *)&p_deflt, DATA_INPUT);
266
267 /*
268 * If the current partition has a size of zero change the
269 * tag to Unassigned and the starting cylinder to zero
270 */
271
272 if (j == 0) {
273 tag = V_UNASSIGNED;
274 i = 0;
275 }
276
277
278 #if defined(i386)
279
280 if (i < cyl_offset && tag != V_UNASSIGNED && tag != V_BACKUP &&
281 tag != V_BOOT) {
282 /*
283 * This slice overlaps boot and/or alternates slice
284 * Check if it's the boot or alternates slice and warn
285 * accordingly
286 */
287 if (i < cur_parts->pinfo_map[I_PARTITION].dkl_cylno + 1) {
288 fmt_print("\nWarning: Partition overlaps boot ");
289 fmt_print("partition. Specify different start cyl.\n");
290 return;
291 }
292 /*
293 * Cyl offset for alternates partition was calculated before
294 */
295 if (i < cyl_offset) {
296 fmt_print("\nWarning: Partition overlaps alternates ");
297 fmt_print("partition. Specify different start cyl.\n");
298 return;
299 }
300 }
301
302 #endif /* defined(i386) */
303
304 /*
305 * If user has entered a V_BACKUP tag then the partition
306 * size should specify full disk capacity else
307 * return an Error.
308 */
309 if (tag == V_BACKUP) {
310 uint_t fullsz;
311
312 fullsz = ncyl * nhead * nsect;
313 if (fullsz != j) {
314 /*
315 * V_BACKUP Tag Partition != full disk capacity.
316 * print useful messages.
317 */
318 fmt_print("\nWarning: Partition with V_BACKUP tag should ");
319 fmt_print("specify full disk capacity. \n");
320 return;
321 }
322 }
323
324
325 /*
326 * If the current partition is named, we can't change it.
327 * We create a new current partition map instead.
328 */
329 if (cur_parts->pinfo_name != NULL)
330 make_partition();
331 /*
332 * Change the values.
333 */
334 cur_parts->pinfo_map[num].dkl_cylno = i;
335 cur_parts->pinfo_map[num].dkl_nblk = j;
336
337 #if defined(_SUNOS_VTOC_16)
338 cur_parts->vtoc.v_part[num].p_start = (daddr_t)(i * (nhead * nsect));
339 cur_parts->vtoc.v_part[num].p_size = (long)j;
340 #endif /* defined(_SUNOS_VTOC_16) */
341
342 /*
343 * Install the p_tag and p_flag values for this partition
344 */
345 assert(cur_parts->vtoc.v_version == V_VERSION);
346 cur_parts->vtoc.v_part[num].p_tag = (ushort_t)tag;
347 cur_parts->vtoc.v_part[num].p_flag = (ushort_t)flag;
348 }
349
350
351 /*
352 * This routine picks to closest partition table which matches the
353 * selected disk type. It is called each time the disk type is
354 * changed. If no match is found, it uses the first element
355 * of the partition table. If no table exists, a dummy is
356 * created.
357 */
358 int
get_partition()359 get_partition()
360 {
361 register struct partition_info *pptr;
362 register struct partition_info *parts;
363
364 /*
365 * If there are no pre-defined maps for this disk type, it's
366 * an error.
367 */
368 parts = cur_dtype->dtype_plist;
369 if (parts == NULL) {
370 err_print("No defined partition tables.\n");
371 make_partition();
372 return (-1);
373 }
374 /*
375 * Loop through the pre-defined maps searching for one which match
376 * disk type. If found copy it into unmamed partition.
377 */
378 enter_critical();
379 for (pptr = parts; pptr != NULL; pptr = pptr->pinfo_next) {
380 if (cur_dtype->dtype_asciilabel) {
381 if (pptr->pinfo_name != NULL && strcmp(pptr->pinfo_name,
382 cur_dtype->dtype_asciilabel) == 0) {
383 /*
384 * Set current partition and name it.
385 */
386 cur_disk->disk_parts = cur_parts = pptr;
387 cur_parts->pinfo_name = pptr->pinfo_name;
388 exit_critical();
389 return (0);
390 }
391 }
392 }
393 /*
394 * If we couldn't find a match, take the first one.
395 * Set current partition and name it.
396 */
397 cur_disk->disk_parts = cur_parts = cur_dtype->dtype_plist;
398 cur_parts->pinfo_name = parts->pinfo_name;
399 exit_critical();
400 return (0);
401 }
402
403
404 /*
405 * This routine creates a new partition map and sets it current. If there
406 * was a current map, the new map starts out identical to it. Otherwise
407 * the new map starts out all zeroes.
408 */
409 void
make_partition()410 make_partition()
411 {
412 register struct partition_info *pptr, *parts;
413 int i;
414
415 /*
416 * Lock out interrupts so the lists don't get mangled.
417 */
418 enter_critical();
419 /*
420 * Get space for for the new map and link it into the list
421 * of maps for the current disk type.
422 */
423 pptr = (struct partition_info *)zalloc(sizeof (struct partition_info));
424 parts = cur_dtype->dtype_plist;
425 if (parts == NULL) {
426 cur_dtype->dtype_plist = pptr;
427 } else {
428 while (parts->pinfo_next != NULL) {
429 parts = parts->pinfo_next;
430 }
431 parts->pinfo_next = pptr;
432 pptr->pinfo_next = NULL;
433 }
434 /*
435 * If there was a current map, copy its values.
436 */
437 if (cur_label == L_TYPE_EFI) {
438 struct dk_gpt *map;
439 int nparts;
440 int size;
441
442 nparts = cur_parts->etoc->efi_nparts;
443 size = sizeof (struct dk_part) * nparts + sizeof (struct dk_gpt);
444 map = zalloc(size);
445 (void) memcpy(map, cur_parts->etoc, size);
446 pptr->etoc = map;
447 cur_disk->disk_parts = cur_parts = pptr;
448 exit_critical();
449 return;
450 }
451 if (cur_parts != NULL) {
452 for (i = 0; i < NDKMAP; i++) {
453 pptr->pinfo_map[i] = cur_parts->pinfo_map[i];
454 }
455 pptr->vtoc = cur_parts->vtoc;
456 } else {
457 /*
458 * Otherwise set initial default vtoc values
459 */
460 set_vtoc_defaults(pptr);
461 }
462
463 /*
464 * Make the new one current.
465 */
466 cur_disk->disk_parts = cur_parts = pptr;
467 exit_critical();
468 }
469
470
471 /*
472 * This routine deletes a partition map from the list of maps for
473 * the given disk type.
474 */
475 void
delete_partition(struct partition_info * parts)476 delete_partition(struct partition_info *parts)
477 {
478 struct partition_info *pptr;
479
480 /*
481 * If there isn't a current map, it's an error.
482 */
483 if (cur_dtype->dtype_plist == NULL) {
484 err_print("Error: unexpected null partition list.\n");
485 fullabort();
486 }
487 /*
488 * Remove the map from the list.
489 */
490 if (cur_dtype->dtype_plist == parts)
491 cur_dtype->dtype_plist = parts->pinfo_next;
492 else {
493 for (pptr = cur_dtype->dtype_plist; pptr->pinfo_next != parts;
494 pptr = pptr->pinfo_next)
495 ;
496 pptr->pinfo_next = parts->pinfo_next;
497 }
498 /*
499 * Free the space it was using.
500 */
501 destroy_data((char *)parts);
502 }
503
504
505 /*
506 * Set all partition vtoc fields to defaults
507 */
508 void
set_vtoc_defaults(struct partition_info * part)509 set_vtoc_defaults(struct partition_info *part)
510 {
511 int i;
512
513 bzero((caddr_t)&part->vtoc, sizeof (struct dk_vtoc));
514
515 part->vtoc.v_version = V_VERSION;
516 part->vtoc.v_nparts = NDKMAP;
517 part->vtoc.v_sanity = VTOC_SANE;
518
519 for (i = 0; i < NDKMAP; i++) {
520 part->vtoc.v_part[i].p_tag = default_vtoc_map[i].p_tag;
521 part->vtoc.v_part[i].p_flag = default_vtoc_map[i].p_flag;
522 }
523 }
524