/[base]/head/usr.sbin/bsdinstall/partedit/gpart_ops.c
ViewVC logotype

Contents of /head/usr.sbin/bsdinstall/partedit/gpart_ops.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 285679 - (show annotations) (download)
Sat Jul 18 18:49:44 2015 UTC (8 years, 11 months ago) by allanjude
File MIME type: text/plain
File size: 38614 byte(s)
Add support for two workarounds for known issues booting GPT in legacy mode on some hardware

For Lenovo laptops with buggy bios (x220, t420, t520):
	Write the 0xee entry into the second slot in the pmbr instead of the first

For some Dell and HP models:
	The BIOS gives a warning message when booting in legacy mode from a GPT partitioned disk where the 0xee partition in the pmbr is not flagged active
	For models known to have this problem, mark the pmbr active during installation

Use smbios data to identify machines known to be affected by any of the above, and offer the user the option to apply the workaround

In bsdinstall's ufs auto mode (autopart partition wizard):
	Allow users to select which type of partition table to use
	Keep current defaults: MBR for BIOS, GPT for UEFI
	This allows users to choose GPT for legacy boot if they wish

PR:		184910
PR:		194359
Reviewed by:	Michael Dexter
Approved by:	marcel
MFC after:	3 days
X-MFC-With:	r285594
Relnotes:	yes
Sponsored by:	ScaleEngine Inc.
Differential Revision:	https://reviews.freebsd.org/D3091

1 /*-
2 * Copyright (c) 2011 Nathan Whitehorn
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 * $FreeBSD$
27 */
28
29 #include <sys/param.h>
30 #include <sys/stat.h>
31 #include <errno.h>
32 #include <libutil.h>
33 #include <inttypes.h>
34
35 #include <libgeom.h>
36 #include <dialog.h>
37 #include <dlg_keys.h>
38
39 #include "partedit.h"
40
41 #define GPART_FLAGS "x" /* Do not commit changes by default */
42
43 static void
44 gpart_show_error(const char *title, const char *explanation, const char *errstr)
45 {
46 char *errmsg;
47 char message[512];
48 int error;
49
50 if (explanation == NULL)
51 explanation = "";
52
53 error = strtol(errstr, &errmsg, 0);
54 if (errmsg != errstr) {
55 while (errmsg[0] == ' ')
56 errmsg++;
57 if (errmsg[0] != '\0')
58 sprintf(message, "%s%s. %s", explanation,
59 strerror(error), errmsg);
60 else
61 sprintf(message, "%s%s", explanation, strerror(error));
62 } else {
63 sprintf(message, "%s%s", explanation, errmsg);
64 }
65
66 dialog_msgbox(title, message, 0, 0, TRUE);
67 }
68
69 static int
70 scheme_supports_labels(const char *scheme)
71 {
72 if (strcmp(scheme, "APM") == 0)
73 return (1);
74 if (strcmp(scheme, "GPT") == 0)
75 return (1);
76 if (strcmp(scheme, "PC98") == 0)
77 return (1);
78
79 return (0);
80 }
81
82 static void
83 newfs_command(const char *fstype, char *command, int use_default)
84 {
85 if (strcmp(fstype, "freebsd-ufs") == 0) {
86 int i;
87 DIALOG_LISTITEM items[] = {
88 {"UFS1", "UFS Version 1",
89 "Use version 1 of the UFS file system instead "
90 "of version 2 (not recommended)", 0 },
91 {"SU", "Softupdates",
92 "Enable softupdates (default)", 1 },
93 {"SUJ", "Softupdates journaling",
94 "Enable file system journaling (default - "
95 "turn off for SSDs)", 1 },
96 {"TRIM", "Enable SSD TRIM support",
97 "Enable TRIM support, useful on solid-state drives",
98 0 },
99 };
100
101 if (!use_default) {
102 int choice;
103 choice = dlg_checklist("UFS Options", "", 0, 0, 0,
104 sizeof(items)/sizeof(items[0]), items, NULL,
105 FLAG_CHECK, &i);
106 if (choice == 1) /* Cancel */
107 return;
108 }
109
110 strcpy(command, "newfs ");
111 for (i = 0; i < (int)(sizeof(items)/sizeof(items[0])); i++) {
112 if (items[i].state == 0)
113 continue;
114 if (strcmp(items[i].name, "UFS1") == 0)
115 strcat(command, "-O1 ");
116 else if (strcmp(items[i].name, "SU") == 0)
117 strcat(command, "-U ");
118 else if (strcmp(items[i].name, "SUJ") == 0)
119 strcat(command, "-j ");
120 else if (strcmp(items[i].name, "TRIM") == 0)
121 strcat(command, "-t ");
122 }
123 } else if (strcmp(fstype, "freebsd-zfs") == 0) {
124 int i;
125 DIALOG_LISTITEM items[] = {
126 {"fletcher4", "checksum algorithm: fletcher4",
127 "Use fletcher4 for data integrity checking. "
128 "(default)", 1 },
129 {"fletcher2", "checksum algorithm: fletcher2",
130 "Use fletcher2 for data integrity checking. "
131 "(not recommended)", 0 },
132 {"sha256", "checksum algorithm: sha256",
133 "Use sha256 for data integrity checking. "
134 "(not recommended)", 0 },
135 {"atime", "Update atimes for files",
136 "Disable atime update", 0 },
137 };
138
139 if (!use_default) {
140 int choice;
141 choice = dlg_checklist("ZFS Options", "", 0, 0, 0,
142 sizeof(items)/sizeof(items[0]), items, NULL,
143 FLAG_CHECK, &i);
144 if (choice == 1) /* Cancel */
145 return;
146 }
147
148 strcpy(command, "zpool create -f -m none ");
149 if (getenv("BSDINSTALL_TMPBOOT") != NULL) {
150 char zfsboot_path[MAXPATHLEN];
151 sprintf(zfsboot_path, "%s/zfs",
152 getenv("BSDINSTALL_TMPBOOT"));
153 mkdir(zfsboot_path, S_IRWXU | S_IRGRP | S_IXGRP |
154 S_IROTH | S_IXOTH);
155 sprintf(command, "%s -o cachefile=%s/zpool.cache ",
156 command, zfsboot_path);
157 }
158 for (i = 0; i < (int)(sizeof(items)/sizeof(items[0])); i++) {
159 if (items[i].state == 0)
160 continue;
161 if (strcmp(items[i].name, "fletcher4") == 0)
162 strcat(command, "-O checksum=fletcher4 ");
163 else if (strcmp(items[i].name, "fletcher2") == 0)
164 strcat(command, "-O checksum=fletcher2 ");
165 else if (strcmp(items[i].name, "sha256") == 0)
166 strcat(command, "-O checksum=sha256 ");
167 else if (strcmp(items[i].name, "atime") == 0)
168 strcat(command, "-O atime=off ");
169 }
170 } else if (strcmp(fstype, "fat32") == 0 || strcmp(fstype, "efi") == 0) {
171 int i;
172 DIALOG_LISTITEM items[] = {
173 {"FAT32", "FAT Type 32",
174 "Create a FAT32 filesystem (default)", 1 },
175 {"FAT16", "FAT Type 16",
176 "Create a FAT16 filesystem", 0 },
177 {"FAT12", "FAT Type 12",
178 "Create a FAT12 filesystem", 0 },
179 };
180
181 if (!use_default) {
182 int choice;
183 choice = dlg_checklist("FAT Options", "", 0, 0, 0,
184 sizeof(items)/sizeof(items[0]), items, NULL,
185 FLAG_RADIO, &i);
186 if (choice == 1) /* Cancel */
187 return;
188 }
189
190 strcpy(command, "newfs_msdos ");
191 for (i = 0; i < (int)(sizeof(items)/sizeof(items[0])); i++) {
192 if (items[i].state == 0)
193 continue;
194 if (strcmp(items[i].name, "FAT32") == 0)
195 strcat(command, "-F 32 ");
196 else if (strcmp(items[i].name, "FAT16") == 0)
197 strcat(command, "-F 16 ");
198 else if (strcmp(items[i].name, "FAT12") == 0)
199 strcat(command, "-F 12 ");
200 }
201 } else {
202 if (!use_default)
203 dialog_msgbox("Error", "No configurable options exist "
204 "for this filesystem.", 0, 0, TRUE);
205 command[0] = '\0';
206 }
207 }
208
209 const char *
210 choose_part_type(const char *def_scheme)
211 {
212 int cancel, choice;
213 const char *scheme = NULL;
214
215 DIALOG_LISTITEM items[] = {
216 {"APM", "Apple Partition Map",
217 "Bootable on PowerPC Apple Hardware", 0 },
218 {"BSD", "BSD Labels",
219 "Bootable on most x86 systems", 0 },
220 {"GPT", "GUID Partition Table",
221 "Bootable on most x86 systems", 0 },
222 {"MBR", "DOS Partitions",
223 "Bootable on most x86 systems", 0 },
224 {"PC98", "NEC PC9801 Partition Table",
225 "Bootable on NEC PC9801 systems", 0 },
226 {"VTOC8", "Sun VTOC8 Partition Table",
227 "Bootable on Sun SPARC systems", 0 },
228 };
229
230 parttypemenu:
231 dialog_vars.default_item = __DECONST(char *, def_scheme);
232 cancel = dlg_menu("Partition Scheme",
233 "Select a partition scheme for this volume:", 0, 0, 0,
234 sizeof(items) / sizeof(items[0]), items, &choice, NULL);
235 dialog_vars.default_item = NULL;
236
237 if (cancel)
238 return NULL;
239
240 if (!is_scheme_bootable(items[choice].name)) {
241 char message[512];
242 sprintf(message, "This partition scheme (%s) is not "
243 "bootable on this platform. Are you sure you want "
244 "to proceed?", items[choice].name);
245 dialog_vars.defaultno = TRUE;
246 cancel = dialog_yesno("Warning", message, 0, 0);
247 dialog_vars.defaultno = FALSE;
248 if (cancel) /* cancel */
249 goto parttypemenu;
250 }
251
252 scheme = items[choice].name;
253
254 return scheme;
255 }
256
257 int
258 gpart_partition(const char *lg_name, const char *scheme)
259 {
260 int cancel;
261 struct gctl_req *r;
262 const char *errstr;
263
264 schememenu:
265 if (scheme == NULL) {
266 scheme = choose_part_type(default_scheme());
267
268 if (scheme == NULL)
269 return (-1);
270
271 if (!is_scheme_bootable(scheme)) {
272 char message[512];
273 sprintf(message, "This partition scheme (%s) is not "
274 "bootable on this platform. Are you sure you want "
275 "to proceed?", scheme);
276 dialog_vars.defaultno = TRUE;
277 cancel = dialog_yesno("Warning", message, 0, 0);
278 dialog_vars.defaultno = FALSE;
279 if (cancel) { /* cancel */
280 /* Reset scheme so user can choose another */
281 scheme = NULL;
282 goto schememenu;
283 }
284 }
285 }
286
287 r = gctl_get_handle();
288 gctl_ro_param(r, "class", -1, "PART");
289 gctl_ro_param(r, "arg0", -1, lg_name);
290 gctl_ro_param(r, "flags", -1, GPART_FLAGS);
291 gctl_ro_param(r, "scheme", -1, scheme);
292 gctl_ro_param(r, "verb", -1, "create");
293
294 errstr = gctl_issue(r);
295 if (errstr != NULL && errstr[0] != '\0') {
296 gpart_show_error("Error", NULL, errstr);
297 gctl_free(r);
298 scheme = NULL;
299 goto schememenu;
300 }
301 gctl_free(r);
302
303 if (bootcode_path(scheme) != NULL)
304 get_part_metadata(lg_name, 1)->bootcode = 1;
305 return (0);
306 }
307
308 static void
309 gpart_activate(struct gprovider *pp)
310 {
311 struct gconfig *gc;
312 struct gctl_req *r;
313 const char *errstr, *scheme;
314 const char *attribute = NULL;
315 intmax_t idx;
316
317 /*
318 * Some partition schemes need this partition to be marked 'active'
319 * for it to be bootable.
320 */
321 LIST_FOREACH(gc, &pp->lg_geom->lg_config, lg_config) {
322 if (strcmp(gc->lg_name, "scheme") == 0) {
323 scheme = gc->lg_val;
324 break;
325 }
326 }
327
328 if (strcmp(scheme, "MBR") == 0 || strcmp(scheme, "EBR") == 0 ||
329 strcmp(scheme, "PC98") == 0)
330 attribute = "active";
331 else
332 return;
333
334 LIST_FOREACH(gc, &pp->lg_config, lg_config) {
335 if (strcmp(gc->lg_name, "index") == 0) {
336 idx = atoi(gc->lg_val);
337 break;
338 }
339 }
340
341 r = gctl_get_handle();
342 gctl_ro_param(r, "class", -1, "PART");
343 gctl_ro_param(r, "arg0", -1, pp->lg_geom->lg_name);
344 gctl_ro_param(r, "verb", -1, "set");
345 gctl_ro_param(r, "attrib", -1, attribute);
346 gctl_ro_param(r, "index", sizeof(idx), &idx);
347
348 errstr = gctl_issue(r);
349 if (errstr != NULL && errstr[0] != '\0')
350 gpart_show_error("Error", "Error marking partition active:",
351 errstr);
352 gctl_free(r);
353 }
354
355 void
356 gpart_set_root(const char *lg_name, const char *attribute)
357 {
358 struct gctl_req *r;
359 const char *errstr;
360
361 r = gctl_get_handle();
362 gctl_ro_param(r, "class", -1, "PART");
363 gctl_ro_param(r, "arg0", -1, lg_name);
364 gctl_ro_param(r, "flags", -1, "C");
365 gctl_ro_param(r, "verb", -1, "set");
366 gctl_ro_param(r, "attrib", -1, attribute);
367
368 errstr = gctl_issue(r);
369 if (errstr != NULL && errstr[0] != '\0')
370 gpart_show_error("Error", "Error setting parameter on disk:",
371 errstr);
372 gctl_free(r);
373 }
374
375 static void
376 gpart_bootcode(struct ggeom *gp)
377 {
378 const char *bootcode;
379 struct gconfig *gc;
380 struct gctl_req *r;
381 const char *errstr, *scheme;
382 uint8_t *boot;
383 size_t bootsize, bytes;
384 int bootfd;
385
386 /*
387 * Write default bootcode to the newly partitioned disk, if that
388 * applies on this platform.
389 */
390 LIST_FOREACH(gc, &gp->lg_config, lg_config) {
391 if (strcmp(gc->lg_name, "scheme") == 0) {
392 scheme = gc->lg_val;
393 break;
394 }
395 }
396
397 bootcode = bootcode_path(scheme);
398 if (bootcode == NULL)
399 return;
400
401 bootfd = open(bootcode, O_RDONLY);
402 if (bootfd < 0) {
403 dialog_msgbox("Bootcode Error", strerror(errno), 0, 0,
404 TRUE);
405 return;
406 }
407
408 bootsize = lseek(bootfd, 0, SEEK_END);
409 boot = malloc(bootsize);
410 lseek(bootfd, 0, SEEK_SET);
411 bytes = 0;
412 while (bytes < bootsize)
413 bytes += read(bootfd, boot + bytes, bootsize - bytes);
414 close(bootfd);
415
416 r = gctl_get_handle();
417 gctl_ro_param(r, "class", -1, "PART");
418 gctl_ro_param(r, "arg0", -1, gp->lg_name);
419 gctl_ro_param(r, "verb", -1, "bootcode");
420 gctl_ro_param(r, "bootcode", bootsize, boot);
421
422 errstr = gctl_issue(r);
423 if (errstr != NULL && errstr[0] != '\0')
424 gpart_show_error("Bootcode Error", NULL, errstr);
425 gctl_free(r);
426 free(boot);
427 }
428
429 static void
430 gpart_partcode(struct gprovider *pp, const char *fstype)
431 {
432 struct gconfig *gc;
433 const char *scheme;
434 const char *indexstr;
435 char message[255], command[255];
436
437 LIST_FOREACH(gc, &pp->lg_geom->lg_config, lg_config) {
438 if (strcmp(gc->lg_name, "scheme") == 0) {
439 scheme = gc->lg_val;
440 break;
441 }
442 }
443
444 /* Make sure this partition scheme needs partcode on this platform */
445 if (partcode_path(scheme, fstype) == NULL)
446 return;
447
448 LIST_FOREACH(gc, &pp->lg_config, lg_config) {
449 if (strcmp(gc->lg_name, "index") == 0) {
450 indexstr = gc->lg_val;
451 break;
452 }
453 }
454
455 /* Shell out to gpart for partcode for now */
456 sprintf(command, "gpart bootcode -p %s -i %s %s",
457 partcode_path(scheme, fstype), indexstr, pp->lg_geom->lg_name);
458 if (system(command) != 0) {
459 sprintf(message, "Error installing partcode on partition %s",
460 pp->lg_name);
461 dialog_msgbox("Error", message, 0, 0, TRUE);
462 }
463 }
464
465 void
466 gpart_destroy(struct ggeom *lg_geom)
467 {
468 struct gctl_req *r;
469 struct gprovider *pp;
470 const char *errstr;
471 int force = 1;
472
473 /* Delete all child metadata */
474 LIST_FOREACH(pp, &lg_geom->lg_provider, lg_provider)
475 gpart_delete(pp);
476
477 /* Revert any local changes to get this geom into a pristine state */
478 r = gctl_get_handle();
479 gctl_ro_param(r, "class", -1, "PART");
480 gctl_ro_param(r, "arg0", -1, lg_geom->lg_name);
481 gctl_ro_param(r, "verb", -1, "undo");
482 gctl_issue(r); /* Ignore errors -- these are non-fatal */
483 gctl_free(r);
484
485 /* Now destroy the geom itself */
486 r = gctl_get_handle();
487 gctl_ro_param(r, "class", -1, "PART");
488 gctl_ro_param(r, "arg0", -1, lg_geom->lg_name);
489 gctl_ro_param(r, "flags", -1, GPART_FLAGS);
490 gctl_ro_param(r, "force", sizeof(force), &force);
491 gctl_ro_param(r, "verb", -1, "destroy");
492 errstr = gctl_issue(r);
493 if (errstr != NULL && errstr[0] != '\0') {
494 /*
495 * Check if we reverted away the existence of the geom
496 * altogether. Show all other errors to the user.
497 */
498 if (strtol(errstr, NULL, 0) != EINVAL)
499 gpart_show_error("Error", NULL, errstr);
500 }
501 gctl_free(r);
502
503 /* And any metadata associated with the partition scheme itself */
504 delete_part_metadata(lg_geom->lg_name);
505 }
506
507 void
508 gpart_edit(struct gprovider *pp)
509 {
510 struct gctl_req *r;
511 struct gconfig *gc;
512 struct gconsumer *cp;
513 struct ggeom *geom;
514 const char *errstr, *oldtype, *scheme;
515 struct partition_metadata *md;
516 char sizestr[32];
517 char newfs[255];
518 intmax_t idx;
519 int hadlabel, choice, junk, nitems;
520 unsigned i;
521
522 DIALOG_FORMITEM items[] = {
523 {0, "Type:", 5, 0, 0, FALSE, "", 11, 0, 12, 15, 0,
524 FALSE, "Filesystem type (e.g. freebsd-ufs, freebsd-zfs, "
525 "freebsd-swap)", FALSE},
526 {0, "Size:", 5, 1, 0, FALSE, "", 11, 1, 12, 0, 0,
527 FALSE, "Partition size. Append K, M, G for kilobytes, "
528 "megabytes or gigabytes.", FALSE},
529 {0, "Mountpoint:", 11, 2, 0, FALSE, "", 11, 2, 12, 15, 0,
530 FALSE, "Path at which to mount this partition (leave blank "
531 "for swap, set to / for root filesystem)", FALSE},
532 {0, "Label:", 7, 3, 0, FALSE, "", 11, 3, 12, 15, 0, FALSE,
533 "Partition name. Not all partition schemes support this.",
534 FALSE},
535 };
536
537 /*
538 * Find the PART geom we are manipulating. This may be a consumer of
539 * this provider, or its parent. Check the consumer case first.
540 */
541 geom = NULL;
542 LIST_FOREACH(cp, &pp->lg_consumers, lg_consumers)
543 if (strcmp(cp->lg_geom->lg_class->lg_name, "PART") == 0) {
544 /* Check for zombie geoms, treating them as blank */
545 scheme = NULL;
546 LIST_FOREACH(gc, &cp->lg_geom->lg_config, lg_config) {
547 if (strcmp(gc->lg_name, "scheme") == 0) {
548 scheme = gc->lg_val;
549 break;
550 }
551 }
552 if (scheme == NULL || strcmp(scheme, "(none)") == 0) {
553 gpart_partition(cp->lg_geom->lg_name, NULL);
554 return;
555 }
556
557 /* If this is a nested partition, edit as usual */
558 if (strcmp(pp->lg_geom->lg_class->lg_name, "PART") == 0)
559 break;
560
561 /* Destroy the geom and all sub-partitions */
562 gpart_destroy(cp->lg_geom);
563
564 /* Now re-partition and return */
565 gpart_partition(cp->lg_geom->lg_name, NULL);
566 return;
567 }
568
569 if (geom == NULL && strcmp(pp->lg_geom->lg_class->lg_name, "PART") == 0)
570 geom = pp->lg_geom;
571
572 if (geom == NULL) {
573 /* Disk not partitioned, so partition it */
574 gpart_partition(pp->lg_name, NULL);
575 return;
576 }
577
578 LIST_FOREACH(gc, &geom->lg_config, lg_config) {
579 if (strcmp(gc->lg_name, "scheme") == 0) {
580 scheme = gc->lg_val;
581 break;
582 }
583 }
584
585 nitems = scheme_supports_labels(scheme) ? 4 : 3;
586
587 /* Edit editable parameters of a partition */
588 hadlabel = 0;
589 LIST_FOREACH(gc, &pp->lg_config, lg_config) {
590 if (strcmp(gc->lg_name, "type") == 0) {
591 oldtype = gc->lg_val;
592 items[0].text = gc->lg_val;
593 }
594 if (strcmp(gc->lg_name, "label") == 0 && gc->lg_val != NULL) {
595 hadlabel = 1;
596 items[3].text = gc->lg_val;
597 }
598 if (strcmp(gc->lg_name, "index") == 0)
599 idx = atoi(gc->lg_val);
600 }
601
602 TAILQ_FOREACH(md, &part_metadata, metadata) {
603 if (md->name != NULL && strcmp(md->name, pp->lg_name) == 0) {
604 if (md->fstab != NULL)
605 items[2].text = md->fstab->fs_file;
606 break;
607 }
608 }
609
610 humanize_number(sizestr, 7, pp->lg_mediasize, "B", HN_AUTOSCALE,
611 HN_NOSPACE | HN_DECIMAL);
612 items[1].text = sizestr;
613
614 editpart:
615 choice = dlg_form("Edit Partition", "", 0, 0, 0, nitems, items, &junk);
616
617 if (choice) /* Cancel pressed */
618 goto endedit;
619
620 /* Check if the label has a / in it */
621 if (strchr(items[3].text, '/') != NULL) {
622 dialog_msgbox("Error", "Label contains a /, which is not an "
623 "allowed character.", 0, 0, TRUE);
624 goto editpart;
625 }
626
627 r = gctl_get_handle();
628 gctl_ro_param(r, "class", -1, "PART");
629 gctl_ro_param(r, "arg0", -1, geom->lg_name);
630 gctl_ro_param(r, "flags", -1, GPART_FLAGS);
631 gctl_ro_param(r, "verb", -1, "modify");
632 gctl_ro_param(r, "index", sizeof(idx), &idx);
633 if (hadlabel || items[3].text[0] != '\0')
634 gctl_ro_param(r, "label", -1, items[3].text);
635 gctl_ro_param(r, "type", -1, items[0].text);
636 errstr = gctl_issue(r);
637 if (errstr != NULL && errstr[0] != '\0') {
638 gpart_show_error("Error", NULL, errstr);
639 gctl_free(r);
640 goto editpart;
641 }
642 gctl_free(r);
643
644 newfs_command(items[0].text, newfs, 1);
645 set_default_part_metadata(pp->lg_name, scheme, items[0].text,
646 items[2].text, (strcmp(oldtype, items[0].text) != 0) ?
647 newfs : NULL);
648
649 endedit:
650 if (strcmp(oldtype, items[0].text) != 0 && cp != NULL)
651 gpart_destroy(cp->lg_geom);
652 if (strcmp(oldtype, items[0].text) != 0 && strcmp(items[0].text,
653 "freebsd") == 0)
654 gpart_partition(pp->lg_name, "BSD");
655
656 for (i = 0; i < (sizeof(items) / sizeof(items[0])); i++)
657 if (items[i].text_free)
658 free(items[i].text);
659 }
660
661 void
662 set_default_part_metadata(const char *name, const char *scheme,
663 const char *type, const char *mountpoint, const char *newfs)
664 {
665 struct partition_metadata *md;
666 char *zpool_name = NULL;
667 int i;
668
669 /* Set part metadata */
670 md = get_part_metadata(name, 1);
671
672 if (newfs) {
673 if (md->newfs != NULL) {
674 free(md->newfs);
675 md->newfs = NULL;
676 }
677
678 if (newfs != NULL && newfs[0] != '\0') {
679 md->newfs = malloc(strlen(newfs) + strlen(" /dev/") +
680 strlen(mountpoint) + 5 + strlen(name) + 1);
681 if (strcmp("freebsd-zfs", type) == 0) {
682 zpool_name = strdup((strlen(mountpoint) == 1) ?
683 "root" : &mountpoint[1]);
684 for (i = 0; zpool_name[i] != 0; i++)
685 if (!isalnum(zpool_name[i]))
686 zpool_name[i] = '_';
687 sprintf(md->newfs, "%s %s /dev/%s", newfs,
688 zpool_name, name);
689 } else {
690 sprintf(md->newfs, "%s /dev/%s", newfs, name);
691 }
692 }
693 }
694
695 if (strcmp(type, "freebsd-swap") == 0)
696 mountpoint = "none";
697 if (strcmp(type, bootpart_type(scheme)) == 0)
698 md->bootcode = 1;
699
700 /* VTOC8 needs partcode at the start of partitions */
701 if (strcmp(scheme, "VTOC8") == 0 && (strcmp(type, "freebsd-ufs") == 0
702 || strcmp(type, "freebsd-zfs") == 0))
703 md->bootcode = 1;
704
705 if (mountpoint == NULL || mountpoint[0] == '\0') {
706 if (md->fstab != NULL) {
707 free(md->fstab->fs_spec);
708 free(md->fstab->fs_file);
709 free(md->fstab->fs_vfstype);
710 free(md->fstab->fs_mntops);
711 free(md->fstab->fs_type);
712 free(md->fstab);
713 md->fstab = NULL;
714 }
715 } else {
716 if (md->fstab == NULL) {
717 md->fstab = malloc(sizeof(struct fstab));
718 } else {
719 free(md->fstab->fs_spec);
720 free(md->fstab->fs_file);
721 free(md->fstab->fs_vfstype);
722 free(md->fstab->fs_mntops);
723 free(md->fstab->fs_type);
724 }
725 if (strcmp("freebsd-zfs", type) == 0) {
726 md->fstab->fs_spec = strdup(zpool_name);
727 } else {
728 md->fstab->fs_spec = malloc(strlen(name) +
729 strlen("/dev/") + 1);
730 sprintf(md->fstab->fs_spec, "/dev/%s", name);
731 }
732 md->fstab->fs_file = strdup(mountpoint);
733 /* Get VFS from text after freebsd-, if possible */
734 if (strncmp("freebsd-", type, 8) == 0)
735 md->fstab->fs_vfstype = strdup(&type[8]);
736 else if (strcmp("fat32", type) == 0 || strcmp("efi", type) == 0)
737 md->fstab->fs_vfstype = strdup("msdosfs");
738 else
739 md->fstab->fs_vfstype = strdup(type); /* Guess */
740 if (strcmp(type, "freebsd-swap") == 0) {
741 md->fstab->fs_type = strdup(FSTAB_SW);
742 md->fstab->fs_freq = 0;
743 md->fstab->fs_passno = 0;
744 } else if (strcmp(type, "freebsd-zfs") == 0) {
745 md->fstab->fs_type = strdup(FSTAB_RW);
746 md->fstab->fs_freq = 0;
747 md->fstab->fs_passno = 0;
748 } else {
749 md->fstab->fs_type = strdup(FSTAB_RW);
750 if (strcmp(mountpoint, "/") == 0) {
751 md->fstab->fs_freq = 1;
752 md->fstab->fs_passno = 1;
753 } else {
754 md->fstab->fs_freq = 2;
755 md->fstab->fs_passno = 2;
756 }
757 }
758 md->fstab->fs_mntops = strdup(md->fstab->fs_type);
759 }
760
761 if (zpool_name != NULL)
762 free(zpool_name);
763 }
764
765 static
766 int part_compare(const void *xa, const void *xb)
767 {
768 struct gprovider **a = (struct gprovider **)xa;
769 struct gprovider **b = (struct gprovider **)xb;
770 intmax_t astart, bstart;
771 struct gconfig *gc;
772
773 astart = bstart = 0;
774 LIST_FOREACH(gc, &(*a)->lg_config, lg_config)
775 if (strcmp(gc->lg_name, "start") == 0) {
776 astart = strtoimax(gc->lg_val, NULL, 0);
777 break;
778 }
779 LIST_FOREACH(gc, &(*b)->lg_config, lg_config)
780 if (strcmp(gc->lg_name, "start") == 0) {
781 bstart = strtoimax(gc->lg_val, NULL, 0);
782 break;
783 }
784
785 if (astart < bstart)
786 return -1;
787 else if (astart > bstart)
788 return 1;
789 else
790 return 0;
791 }
792
793 intmax_t
794 gpart_max_free(struct ggeom *geom, intmax_t *npartstart)
795 {
796 struct gconfig *gc;
797 struct gprovider *pp, **providers;
798 intmax_t lastend;
799 intmax_t start, end;
800 intmax_t maxsize, maxstart;
801 intmax_t partstart, partend;
802 int i, nparts;
803
804 /* Now get the maximum free size and free start */
805 start = end = 0;
806 LIST_FOREACH(gc, &geom->lg_config, lg_config) {
807 if (strcmp(gc->lg_name, "first") == 0)
808 start = strtoimax(gc->lg_val, NULL, 0);
809 if (strcmp(gc->lg_name, "last") == 0)
810 end = strtoimax(gc->lg_val, NULL, 0);
811 }
812
813 i = nparts = 0;
814 LIST_FOREACH(pp, &geom->lg_provider, lg_provider)
815 nparts++;
816 providers = calloc(nparts, sizeof(providers[0]));
817 LIST_FOREACH(pp, &geom->lg_provider, lg_provider)
818 providers[i++] = pp;
819 qsort(providers, nparts, sizeof(providers[0]), part_compare);
820
821 lastend = start - 1;
822 maxsize = 0;
823 for (i = 0; i < nparts; i++) {
824 pp = providers[i];
825
826 LIST_FOREACH(gc, &pp->lg_config, lg_config) {
827 if (strcmp(gc->lg_name, "start") == 0)
828 partstart = strtoimax(gc->lg_val, NULL, 0);
829 if (strcmp(gc->lg_name, "end") == 0)
830 partend = strtoimax(gc->lg_val, NULL, 0);
831 }
832
833 if (partstart - lastend > maxsize) {
834 maxsize = partstart - lastend - 1;
835 maxstart = lastend + 1;
836 }
837
838 lastend = partend;
839 }
840
841 if (end - lastend > maxsize) {
842 maxsize = end - lastend - 1;
843 maxstart = lastend + 1;
844 }
845
846 pp = LIST_FIRST(&geom->lg_consumer)->lg_provider;
847
848 /* Compute beginning of new partition and maximum available space */
849 if (pp->lg_stripesize > 0 &&
850 (maxstart*pp->lg_sectorsize % pp->lg_stripesize) != 0) {
851 intmax_t offset = (pp->lg_stripesize -
852 ((maxstart*pp->lg_sectorsize) % pp->lg_stripesize)) /
853 pp->lg_sectorsize;
854 maxstart += offset;
855 maxsize -= offset;
856 }
857
858 if (npartstart != NULL)
859 *npartstart = maxstart;
860
861 return (maxsize);
862 }
863
864 void
865 gpart_create(struct gprovider *pp, char *default_type, char *default_size,
866 char *default_mountpoint, char **partname, int interactive)
867 {
868 struct gctl_req *r;
869 struct gconfig *gc;
870 struct gconsumer *cp;
871 struct ggeom *geom;
872 const char *errstr, *scheme;
873 char sizestr[32], startstr[32], output[64], *newpartname;
874 char newfs[255], options_fstype[64];
875 intmax_t maxsize, size, sector, firstfree, stripe;
876 uint64_t bytes;
877 int nitems, choice, junk;
878 unsigned i;
879
880 DIALOG_FORMITEM items[] = {
881 {0, "Type:", 5, 0, 0, FALSE, "freebsd-ufs", 11, 0, 12, 15, 0,
882 FALSE, "Filesystem type (e.g. freebsd-ufs, freebsd-zfs, "
883 "freebsd-swap)", FALSE},
884 {0, "Size:", 5, 1, 0, FALSE, "", 11, 1, 12, 15, 0,
885 FALSE, "Partition size. Append K, M, G for kilobytes, "
886 "megabytes or gigabytes.", FALSE},
887 {0, "Mountpoint:", 11, 2, 0, FALSE, "", 11, 2, 12, 15, 0,
888 FALSE, "Path at which to mount partition (blank for "
889 "swap, / for root filesystem)", FALSE},
890 {0, "Label:", 7, 3, 0, FALSE, "", 11, 3, 12, 15, 0, FALSE,
891 "Partition name. Not all partition schemes support this.",
892 FALSE},
893 };
894
895 if (partname != NULL)
896 *partname = NULL;
897
898 /* Record sector and stripe sizes */
899 sector = pp->lg_sectorsize;
900 stripe = pp->lg_stripesize;
901
902 /*
903 * Find the PART geom we are manipulating. This may be a consumer of
904 * this provider, or its parent. Check the consumer case first.
905 */
906 geom = NULL;
907 LIST_FOREACH(cp, &pp->lg_consumers, lg_consumers)
908 if (strcmp(cp->lg_geom->lg_class->lg_name, "PART") == 0) {
909 geom = cp->lg_geom;
910 break;
911 }
912
913 if (geom == NULL && strcmp(pp->lg_geom->lg_class->lg_name, "PART") == 0)
914 geom = pp->lg_geom;
915
916 /* Now get the partition scheme */
917 scheme = NULL;
918 if (geom != NULL) {
919 LIST_FOREACH(gc, &geom->lg_config, lg_config)
920 if (strcmp(gc->lg_name, "scheme") == 0)
921 scheme = gc->lg_val;
922 }
923
924 if (geom == NULL || scheme == NULL || strcmp(scheme, "(none)") == 0) {
925 if (gpart_partition(pp->lg_name, NULL) == 0)
926 dialog_msgbox("",
927 "The partition table has been successfully created."
928 " Please press Create again to create partitions.",
929 0, 0, TRUE);
930
931 return;
932 }
933
934 /*
935 * If we still don't have a geom, either the user has
936 * canceled partitioning or there has been an error which has already
937 * been displayed, so bail.
938 */
939 if (geom == NULL)
940 return;
941
942 maxsize = size = gpart_max_free(geom, &firstfree);
943 if (size <= 0) {
944 dialog_msgbox("Error", "No free space left on device.", 0, 0,
945 TRUE);
946 return;
947 }
948
949 humanize_number(sizestr, 7, size*sector, "B", HN_AUTOSCALE,
950 HN_NOSPACE | HN_DECIMAL);
951 items[1].text = sizestr;
952
953 /* Special-case the MBR default type for nested partitions */
954 if (strcmp(scheme, "MBR") == 0 || strcmp(scheme, "PC98") == 0) {
955 items[0].text = "freebsd";
956 items[0].help = "Filesystem type (e.g. freebsd, fat32)";
957 }
958
959 nitems = scheme_supports_labels(scheme) ? 4 : 3;
960
961 if (default_type != NULL)
962 items[0].text = default_type;
963 if (default_size != NULL)
964 items[1].text = default_size;
965 if (default_mountpoint != NULL)
966 items[2].text = default_mountpoint;
967
968 /* Default options */
969 strncpy(options_fstype, items[0].text,
970 sizeof(options_fstype));
971 newfs_command(options_fstype, newfs, 1);
972 addpartform:
973 if (interactive) {
974 dialog_vars.extra_label = "Options";
975 dialog_vars.extra_button = TRUE;
976 choice = dlg_form("Add Partition", "", 0, 0, 0, nitems,
977 items, &junk);
978 dialog_vars.extra_button = FALSE;
979 switch (choice) {
980 case 0: /* OK */
981 break;
982 case 1: /* Cancel */
983 return;
984 case 3: /* Options */
985 strncpy(options_fstype, items[0].text,
986 sizeof(options_fstype));
987 newfs_command(options_fstype, newfs, 0);
988 goto addpartform;
989 }
990 }
991
992 /*
993 * If the user changed the fs type after specifying options, undo
994 * their choices in favor of the new filesystem's defaults.
995 */
996 if (strcmp(options_fstype, items[0].text) != 0) {
997 strncpy(options_fstype, items[0].text, sizeof(options_fstype));
998 newfs_command(options_fstype, newfs, 1);
999 }
1000
1001 size = maxsize;
1002 if (strlen(items[1].text) > 0) {
1003 if (expand_number(items[1].text, &bytes) != 0) {
1004 char error[512];
1005
1006 sprintf(error, "Invalid size: %s\n", strerror(errno));
1007 dialog_msgbox("Error", error, 0, 0, TRUE);
1008 goto addpartform;
1009 }
1010 size = MIN((intmax_t)(bytes/sector), maxsize);
1011 }
1012
1013 /* Check if the label has a / in it */
1014 if (strchr(items[3].text, '/') != NULL) {
1015 dialog_msgbox("Error", "Label contains a /, which is not an "
1016 "allowed character.", 0, 0, TRUE);
1017 goto addpartform;
1018 }
1019
1020 /* Warn if no mountpoint set */
1021 if (strcmp(items[0].text, "freebsd-ufs") == 0 &&
1022 items[2].text[0] != '/') {
1023 dialog_vars.defaultno = TRUE;
1024 choice = dialog_yesno("Warning",
1025 "This partition does not have a valid mountpoint "
1026 "(for the partition from which you intend to boot the "
1027 "operating system, the mountpoint should be /). Are you "
1028 "sure you want to continue?"
1029 , 0, 0);
1030 dialog_vars.defaultno = FALSE;
1031 if (choice == 1) /* cancel */
1032 goto addpartform;
1033 }
1034
1035 /*
1036 * Error if this scheme needs nested partitions, this is one, and
1037 * a mountpoint was set.
1038 */
1039 if (strcmp(items[0].text, "freebsd") == 0 &&
1040 strlen(items[2].text) > 0) {
1041 dialog_msgbox("Error", "Partitions of type \"freebsd\" are "
1042 "nested BSD-type partition schemes and cannot have "
1043 "mountpoints. After creating one, select it and press "
1044 "Create again to add the actual file systems.", 0, 0, TRUE);
1045 goto addpartform;
1046 }
1047
1048 /* If this is the root partition, check that this scheme is bootable */
1049 if (strcmp(items[2].text, "/") == 0 && !is_scheme_bootable(scheme)) {
1050 char message[512];
1051 sprintf(message, "This partition scheme (%s) is not bootable "
1052 "on this platform. Are you sure you want to proceed?",
1053 scheme);
1054 dialog_vars.defaultno = TRUE;
1055 choice = dialog_yesno("Warning", message, 0, 0);
1056 dialog_vars.defaultno = FALSE;
1057 if (choice == 1) /* cancel */
1058 goto addpartform;
1059 }
1060
1061 /* If this is the root partition, check that this fs is bootable */
1062 if (strcmp(items[2].text, "/") == 0 && !is_fs_bootable(scheme,
1063 items[0].text)) {
1064 char message[512];
1065 sprintf(message, "This file system (%s) is not bootable "
1066 "on this system. Are you sure you want to proceed?",
1067 items[0].text);
1068 dialog_vars.defaultno = TRUE;
1069 choice = dialog_yesno("Warning", message, 0, 0);
1070 dialog_vars.defaultno = FALSE;
1071 if (choice == 1) /* cancel */
1072 goto addpartform;
1073 }
1074
1075 /*
1076 * If this is the root partition, and we need a boot partition, ask
1077 * the user to add one.
1078 */
1079
1080 /* Check for existing freebsd-boot partition */
1081 LIST_FOREACH(pp, &geom->lg_provider, lg_provider) {
1082 struct partition_metadata *md;
1083 md = get_part_metadata(pp->lg_name, 0);
1084 if (md == NULL || !md->bootcode)
1085 continue;
1086 LIST_FOREACH(gc, &pp->lg_config, lg_config)
1087 if (strcmp(gc->lg_name, "type") == 0)
1088 break;
1089 if (gc != NULL && strcmp(gc->lg_val,
1090 bootpart_type(scheme)) == 0)
1091 break;
1092 }
1093
1094 /* If there isn't one, and we need one, ask */
1095 if ((strcmp(items[0].text, "freebsd") == 0 ||
1096 strcmp(items[2].text, "/") == 0) && bootpart_size(scheme) > 0 &&
1097 pp == NULL) {
1098 if (interactive)
1099 choice = dialog_yesno("Boot Partition",
1100 "This partition scheme requires a boot partition "
1101 "for the disk to be bootable. Would you like to "
1102 "make one now?", 0, 0);
1103 else
1104 choice = 0;
1105
1106 if (choice == 0) { /* yes */
1107 r = gctl_get_handle();
1108 gctl_ro_param(r, "class", -1, "PART");
1109 gctl_ro_param(r, "arg0", -1, geom->lg_name);
1110 gctl_ro_param(r, "flags", -1, GPART_FLAGS);
1111 gctl_ro_param(r, "verb", -1, "add");
1112 gctl_ro_param(r, "type", -1, bootpart_type(scheme));
1113 snprintf(sizestr, sizeof(sizestr), "%jd",
1114 bootpart_size(scheme) / sector);
1115 gctl_ro_param(r, "size", -1, sizestr);
1116 snprintf(startstr, sizeof(startstr), "%jd", firstfree);
1117 gctl_ro_param(r, "start", -1, startstr);
1118 gctl_rw_param(r, "output", sizeof(output), output);
1119 errstr = gctl_issue(r);
1120 if (errstr != NULL && errstr[0] != '\0')
1121 gpart_show_error("Error", NULL, errstr);
1122 gctl_free(r);
1123
1124 get_part_metadata(strtok(output, " "), 1)->bootcode = 1;
1125
1126 /* Now adjust the part we are really adding forward */
1127 firstfree += bootpart_size(scheme) / sector;
1128 size -= (bootpart_size(scheme) + stripe)/sector;
1129 if (stripe > 0 && (firstfree*sector % stripe) != 0)
1130 firstfree += (stripe - ((firstfree*sector) %
1131 stripe)) / sector;
1132 }
1133 }
1134
1135 r = gctl_get_handle();
1136 gctl_ro_param(r, "class", -1, "PART");
1137 gctl_ro_param(r, "arg0", -1, geom->lg_name);
1138 gctl_ro_param(r, "flags", -1, GPART_FLAGS);
1139 gctl_ro_param(r, "verb", -1, "add");
1140
1141 gctl_ro_param(r, "type", -1, items[0].text);
1142 snprintf(sizestr, sizeof(sizestr), "%jd", size);
1143 gctl_ro_param(r, "size", -1, sizestr);
1144 snprintf(startstr, sizeof(startstr), "%jd", firstfree);
1145 gctl_ro_param(r, "start", -1, startstr);
1146 if (items[3].text[0] != '\0')
1147 gctl_ro_param(r, "label", -1, items[3].text);
1148 gctl_rw_param(r, "output", sizeof(output), output);
1149 errstr = gctl_issue(r);
1150 if (errstr != NULL && errstr[0] != '\0') {
1151 gpart_show_error("Error", NULL, errstr);
1152 gctl_free(r);
1153 goto addpartform;
1154 }
1155 newpartname = strtok(output, " ");
1156 gctl_free(r);
1157
1158 /*
1159 * Try to destroy any geom that gpart picked up already here from
1160 * dirty blocks.
1161 */
1162 r = gctl_get_handle();
1163 gctl_ro_param(r, "class", -1, "PART");
1164 gctl_ro_param(r, "arg0", -1, newpartname);
1165 gctl_ro_param(r, "flags", -1, GPART_FLAGS);
1166 junk = 1;
1167 gctl_ro_param(r, "force", sizeof(junk), &junk);
1168 gctl_ro_param(r, "verb", -1, "destroy");
1169 gctl_issue(r); /* Error usually expected and non-fatal */
1170 gctl_free(r);
1171
1172 if (strcmp(items[0].text, bootpart_type(scheme)) == 0)
1173 get_part_metadata(newpartname, 1)->bootcode = 1;
1174 else if (strcmp(items[0].text, "freebsd") == 0)
1175 gpart_partition(newpartname, "BSD");
1176 else
1177 set_default_part_metadata(newpartname, scheme,
1178 items[0].text, items[2].text, newfs);
1179
1180 for (i = 0; i < (sizeof(items) / sizeof(items[0])); i++)
1181 if (items[i].text_free)
1182 free(items[i].text);
1183
1184 if (partname != NULL)
1185 *partname = strdup(newpartname);
1186 }
1187
1188 void
1189 gpart_delete(struct gprovider *pp)
1190 {
1191 struct gconfig *gc;
1192 struct ggeom *geom;
1193 struct gconsumer *cp;
1194 struct gctl_req *r;
1195 const char *errstr;
1196 intmax_t idx;
1197 int is_partition;
1198
1199 /* Is it a partition? */
1200 is_partition = (strcmp(pp->lg_geom->lg_class->lg_name, "PART") == 0);
1201
1202 /* Find out if this is the root of a gpart geom */
1203 geom = NULL;
1204 LIST_FOREACH(cp, &pp->lg_consumers, lg_consumers)
1205 if (strcmp(cp->lg_geom->lg_class->lg_name, "PART") == 0) {
1206 geom = cp->lg_geom;
1207 break;
1208 }
1209
1210 /* If so, destroy all children */
1211 if (geom != NULL) {
1212 gpart_destroy(geom);
1213
1214 /* If this is a partition, revert it, so it can be deleted */
1215 if (is_partition) {
1216 r = gctl_get_handle();
1217 gctl_ro_param(r, "class", -1, "PART");
1218 gctl_ro_param(r, "arg0", -1, geom->lg_name);
1219 gctl_ro_param(r, "verb", -1, "undo");
1220 gctl_issue(r); /* Ignore non-fatal errors */
1221 gctl_free(r);
1222 }
1223 }
1224
1225 /*
1226 * If this is not a partition, see if that is a problem, complain if
1227 * necessary, and return always, since we need not do anything further,
1228 * error or no.
1229 */
1230 if (!is_partition) {
1231 if (geom == NULL)
1232 dialog_msgbox("Error",
1233 "Only partitions can be deleted.", 0, 0, TRUE);
1234 return;
1235 }
1236
1237 r = gctl_get_handle();
1238 gctl_ro_param(r, "class", -1, pp->lg_geom->lg_class->lg_name);
1239 gctl_ro_param(r, "arg0", -1, pp->lg_geom->lg_name);
1240 gctl_ro_param(r, "flags", -1, GPART_FLAGS);
1241 gctl_ro_param(r, "verb", -1, "delete");
1242
1243 LIST_FOREACH(gc, &pp->lg_config, lg_config) {
1244 if (strcmp(gc->lg_name, "index") == 0) {
1245 idx = atoi(gc->lg_val);
1246 gctl_ro_param(r, "index", sizeof(idx), &idx);
1247 break;
1248 }
1249 }
1250
1251 errstr = gctl_issue(r);
1252 if (errstr != NULL && errstr[0] != '\0') {
1253 gpart_show_error("Error", NULL, errstr);
1254 gctl_free(r);
1255 return;
1256 }
1257
1258 gctl_free(r);
1259
1260 delete_part_metadata(pp->lg_name);
1261 }
1262
1263 void
1264 gpart_revert_all(struct gmesh *mesh)
1265 {
1266 struct gclass *classp;
1267 struct gconfig *gc;
1268 struct ggeom *gp;
1269 struct gctl_req *r;
1270 const char *modified;
1271
1272 LIST_FOREACH(classp, &mesh->lg_class, lg_class) {
1273 if (strcmp(classp->lg_name, "PART") == 0)
1274 break;
1275 }
1276
1277 if (strcmp(classp->lg_name, "PART") != 0) {
1278 dialog_msgbox("Error", "gpart not found!", 0, 0, TRUE);
1279 return;
1280 }
1281
1282 LIST_FOREACH(gp, &classp->lg_geom, lg_geom) {
1283 modified = "true"; /* XXX: If we don't know (kernel too old),
1284 * assume there are modifications. */
1285 LIST_FOREACH(gc, &gp->lg_config, lg_config) {
1286 if (strcmp(gc->lg_name, "modified") == 0) {
1287 modified = gc->lg_val;
1288 break;
1289 }
1290 }
1291
1292 if (strcmp(modified, "false") == 0)
1293 continue;
1294
1295 r = gctl_get_handle();
1296 gctl_ro_param(r, "class", -1, "PART");
1297 gctl_ro_param(r, "arg0", -1, gp->lg_name);
1298 gctl_ro_param(r, "verb", -1, "undo");
1299
1300 gctl_issue(r);
1301 gctl_free(r);
1302 }
1303 }
1304
1305 void
1306 gpart_commit(struct gmesh *mesh)
1307 {
1308 struct partition_metadata *md;
1309 struct gclass *classp;
1310 struct ggeom *gp;
1311 struct gconfig *gc;
1312 struct gconsumer *cp;
1313 struct gprovider *pp;
1314 struct gctl_req *r;
1315 const char *errstr;
1316 const char *modified;
1317 const char *rootfs;
1318
1319 LIST_FOREACH(classp, &mesh->lg_class, lg_class) {
1320 if (strcmp(classp->lg_name, "PART") == 0)
1321 break;
1322 }
1323
1324 /* Figure out what filesystem / uses */
1325 rootfs = "ufs"; /* Assume ufs if nothing else present */
1326 TAILQ_FOREACH(md, &part_metadata, metadata) {
1327 if (md->fstab != NULL && strcmp(md->fstab->fs_file, "/") == 0) {
1328 rootfs = md->fstab->fs_vfstype;
1329 break;
1330 }
1331 }
1332
1333 if (strcmp(classp->lg_name, "PART") != 0) {
1334 dialog_msgbox("Error", "gpart not found!", 0, 0, TRUE);
1335 return;
1336 }
1337
1338 LIST_FOREACH(gp, &classp->lg_geom, lg_geom) {
1339 modified = "true"; /* XXX: If we don't know (kernel too old),
1340 * assume there are modifications. */
1341 LIST_FOREACH(gc, &gp->lg_config, lg_config) {
1342 if (strcmp(gc->lg_name, "modified") == 0) {
1343 modified = gc->lg_val;
1344 break;
1345 }
1346 }
1347
1348 if (strcmp(modified, "false") == 0)
1349 continue;
1350
1351 /* Add bootcode if necessary, before the commit */
1352 md = get_part_metadata(gp->lg_name, 0);
1353 if (md != NULL && md->bootcode)
1354 gpart_bootcode(gp);
1355
1356 /* Now install partcode on its partitions, if necessary */
1357 LIST_FOREACH(pp, &gp->lg_provider, lg_provider) {
1358 md = get_part_metadata(pp->lg_name, 0);
1359 if (md == NULL || !md->bootcode)
1360 continue;
1361
1362 /* Mark this partition active if that's required */
1363 gpart_activate(pp);
1364
1365 /* Check if the partition has sub-partitions */
1366 LIST_FOREACH(cp, &pp->lg_consumers, lg_consumers)
1367 if (strcmp(cp->lg_geom->lg_class->lg_name,
1368 "PART") == 0)
1369 break;
1370
1371 if (cp == NULL) /* No sub-partitions */
1372 gpart_partcode(pp, rootfs);
1373 }
1374
1375 r = gctl_get_handle();
1376 gctl_ro_param(r, "class", -1, "PART");
1377 gctl_ro_param(r, "arg0", -1, gp->lg_name);
1378 gctl_ro_param(r, "verb", -1, "commit");
1379
1380 errstr = gctl_issue(r);
1381 if (errstr != NULL && errstr[0] != '\0')
1382 gpart_show_error("Error", NULL, errstr);
1383 gctl_free(r);
1384 }
1385 }
1386

Properties

Name Value
svn:keywords FreeBSD=%H

  ViewVC Help
Powered by ViewVC 1.1.27