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