Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/lib/geom/part/geom_part.c
105955 views
1
/*-
2
* SPDX-License-Identifier: BSD-2-Clause
3
*
4
* Copyright (c) 2007, 2008 Marcel Moolenaar
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 AUTHORS 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 AUTHORS 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/cdefs.h>
30
#include <sys/stat.h>
31
32
#include <assert.h>
33
#include <ctype.h>
34
#include <err.h>
35
#include <errno.h>
36
#include <fcntl.h>
37
#include <libgeom.h>
38
#include <libutil.h>
39
#include <paths.h>
40
#include <signal.h>
41
#include <stdint.h>
42
#include <stdio.h>
43
#include <stdlib.h>
44
#include <limits.h>
45
#include <inttypes.h>
46
#include <string.h>
47
#include <strings.h>
48
#include <unistd.h>
49
50
#include <libxo/xo.h>
51
52
#include "core/geom.h"
53
#include "misc/subr.h"
54
55
#ifdef STATIC_GEOM_CLASSES
56
#define PUBSYM(x) gpart_##x
57
#else
58
#define PUBSYM(x) x
59
#endif
60
61
uint32_t PUBSYM(lib_version) = G_LIB_VERSION;
62
uint32_t PUBSYM(version) = 0;
63
64
static char sstart[32];
65
static char ssize[32];
66
volatile sig_atomic_t undo_restore;
67
68
#define GPART_AUTOFILL "*"
69
#define GPART_FLAGS "C"
70
71
#define GPART_PARAM_BOOTCODE "bootcode"
72
#define GPART_PARAM_INDEX "index"
73
#define GPART_PARAM_PARTCODE "partcode"
74
#define GPART_PARAM_SKIP_DSN "skip_dsn"
75
76
static struct gclass *find_class(struct gmesh *, const char *);
77
static struct ggeom * find_geom(struct gclass *, const char *);
78
static int geom_is_withered(struct ggeom *);
79
static const char *find_geomcfg(struct ggeom *, const char *);
80
static const char *find_provcfg(struct gprovider *, const char *);
81
static struct gprovider *find_provider(struct ggeom *, off_t);
82
static int gpart_autofill(struct gctl_req *);
83
static int gpart_autofill_resize(struct gctl_req *);
84
static void gpart_bootcode(struct gctl_req *, unsigned int);
85
static void *gpart_bootfile_read(const char *, ssize_t *);
86
static _Noreturn void gpart_issue(struct gctl_req *, unsigned int);
87
static void gpart_show(struct gctl_req *, unsigned int);
88
static void gpart_show_geom(struct ggeom *, const char *, int);
89
static int gpart_show_hasopt(struct gctl_req *, const char *, const char *);
90
static void gpart_write_partcode(struct gctl_req *, int, void *, ssize_t);
91
static void gpart_print_error(const char *);
92
static void gpart_backup(struct gctl_req *, unsigned int);
93
static void gpart_restore(struct gctl_req *, unsigned int);
94
95
struct g_command PUBSYM(class_commands)[] = {
96
{ "add", 0, gpart_issue, {
97
{ 'a', "alignment", GPART_AUTOFILL, G_TYPE_STRING },
98
{ 'b', "start", GPART_AUTOFILL, G_TYPE_STRING },
99
{ 's', "size", GPART_AUTOFILL, G_TYPE_STRING },
100
{ 't', "type", NULL, G_TYPE_STRING },
101
{ 'i', GPART_PARAM_INDEX, G_VAL_OPTIONAL, G_TYPE_NUMBER },
102
{ 'l', "label", G_VAL_OPTIONAL, G_TYPE_STRING },
103
{ 'f', "flags", GPART_FLAGS, G_TYPE_STRING },
104
G_OPT_SENTINEL },
105
"-t type [-a alignment] [-b start] [-s size] [-i index] "
106
"[-l label] [-f flags] geom"
107
},
108
{ "backup", 0, gpart_backup, G_NULL_OPTS,
109
"geom"
110
},
111
{ "bootcode", 0, gpart_bootcode, {
112
{ 'b', GPART_PARAM_BOOTCODE, G_VAL_OPTIONAL, G_TYPE_STRING },
113
{ 'p', GPART_PARAM_PARTCODE, G_VAL_OPTIONAL, G_TYPE_STRING },
114
{ 'i', GPART_PARAM_INDEX, G_VAL_OPTIONAL, G_TYPE_NUMBER },
115
{ 'f', "flags", GPART_FLAGS, G_TYPE_STRING },
116
{ 'N', GPART_PARAM_SKIP_DSN, NULL, G_TYPE_BOOL },
117
G_OPT_SENTINEL },
118
"[-N] [-b bootcode] [-p partcode -i index] [-f flags] geom"
119
},
120
{ "commit", 0, gpart_issue, G_NULL_OPTS,
121
"geom"
122
},
123
{ "create", 0, gpart_issue, {
124
{ 's', "scheme", NULL, G_TYPE_STRING },
125
{ 'n', "entries", G_VAL_OPTIONAL, G_TYPE_NUMBER },
126
{ 'f', "flags", GPART_FLAGS, G_TYPE_STRING },
127
G_OPT_SENTINEL },
128
"-s scheme [-n entries] [-f flags] provider"
129
},
130
{ "delete", 0, gpart_issue, {
131
{ 'i', GPART_PARAM_INDEX, NULL, G_TYPE_NUMBER },
132
{ 'f', "flags", GPART_FLAGS, G_TYPE_STRING },
133
G_OPT_SENTINEL },
134
"-i index [-f flags] geom"
135
},
136
{ "destroy", 0, gpart_issue, {
137
{ 'F', "force", NULL, G_TYPE_BOOL },
138
{ 'f', "flags", GPART_FLAGS, G_TYPE_STRING },
139
G_OPT_SENTINEL },
140
"[-F] [-f flags] geom"
141
},
142
{ "modify", 0, gpart_issue, {
143
{ 'i', GPART_PARAM_INDEX, NULL, G_TYPE_NUMBER },
144
{ 'l', "label", G_VAL_OPTIONAL, G_TYPE_STRING },
145
{ 't', "type", G_VAL_OPTIONAL, G_TYPE_STRING },
146
{ 'f', "flags", GPART_FLAGS, G_TYPE_STRING },
147
G_OPT_SENTINEL },
148
"-i index [-l label] [-t type] [-f flags] geom"
149
},
150
{ "set", 0, gpart_issue, {
151
{ 'a', "attrib", NULL, G_TYPE_STRING },
152
{ 'i', GPART_PARAM_INDEX, G_VAL_OPTIONAL, G_TYPE_NUMBER },
153
{ 'f', "flags", GPART_FLAGS, G_TYPE_STRING },
154
G_OPT_SENTINEL },
155
"-a attrib [-i index] [-f flags] geom"
156
},
157
{ "show", 0, gpart_show, {
158
{ 'l', "show_label", NULL, G_TYPE_BOOL },
159
{ 'r', "show_rawtype", NULL, G_TYPE_BOOL },
160
{ 'p', "show_providers", NULL, G_TYPE_BOOL },
161
G_OPT_SENTINEL },
162
"[-l | -r] [-p] [geom ...]"
163
},
164
{ "undo", 0, gpart_issue, G_NULL_OPTS,
165
"geom"
166
},
167
{ "unset", 0, gpart_issue, {
168
{ 'a', "attrib", NULL, G_TYPE_STRING },
169
{ 'i', GPART_PARAM_INDEX, G_VAL_OPTIONAL, G_TYPE_NUMBER },
170
{ 'f', "flags", GPART_FLAGS, G_TYPE_STRING },
171
G_OPT_SENTINEL },
172
"-a attrib [-i index] [-f flags] geom"
173
},
174
{ "resize", 0, gpart_issue, {
175
{ 'a', "alignment", GPART_AUTOFILL, G_TYPE_STRING },
176
{ 's', "size", GPART_AUTOFILL, G_TYPE_STRING },
177
{ 'i', GPART_PARAM_INDEX, NULL, G_TYPE_NUMBER },
178
{ 'f', "flags", GPART_FLAGS, G_TYPE_STRING },
179
G_OPT_SENTINEL },
180
"-i index [-a alignment] [-s size] [-f flags] geom"
181
},
182
{ "restore", 0, gpart_restore, {
183
{ 'F', "force", NULL, G_TYPE_BOOL },
184
{ 'l', "restore_labels", NULL, G_TYPE_BOOL },
185
{ 'f', "flags", GPART_FLAGS, G_TYPE_STRING },
186
G_OPT_SENTINEL },
187
"[-lF] [-f flags] provider [...]"
188
},
189
{ "recover", 0, gpart_issue, {
190
{ 'f', "flags", GPART_FLAGS, G_TYPE_STRING },
191
G_OPT_SENTINEL },
192
"[-f flags] geom"
193
},
194
G_CMD_SENTINEL
195
};
196
197
static struct gclass *
198
find_class(struct gmesh *mesh, const char *name)
199
{
200
struct gclass *classp;
201
202
LIST_FOREACH(classp, &mesh->lg_class, lg_class) {
203
if (strcmp(classp->lg_name, name) == 0)
204
return (classp);
205
}
206
return (NULL);
207
}
208
209
static struct ggeom *
210
find_geom(struct gclass *classp, const char *name)
211
{
212
struct ggeom *gp, *wgp;
213
214
if (strncmp(name, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0)
215
name += sizeof(_PATH_DEV) - 1;
216
wgp = NULL;
217
LIST_FOREACH(gp, &classp->lg_geom, lg_geom) {
218
if (strcmp(gp->lg_name, name) != 0)
219
continue;
220
if (!geom_is_withered(gp))
221
return (gp);
222
else
223
wgp = gp;
224
}
225
return (wgp);
226
}
227
228
static int
229
geom_is_withered(struct ggeom *gp)
230
{
231
struct gconfig *gc;
232
233
LIST_FOREACH(gc, &gp->lg_config, lg_config) {
234
if (!strcmp(gc->lg_name, "wither"))
235
return (1);
236
}
237
return (0);
238
}
239
240
static const char *
241
find_geomcfg(struct ggeom *gp, const char *cfg)
242
{
243
struct gconfig *gc;
244
245
LIST_FOREACH(gc, &gp->lg_config, lg_config) {
246
if (!strcmp(gc->lg_name, cfg))
247
return (gc->lg_val);
248
}
249
return (NULL);
250
}
251
252
static const char *
253
find_provcfg(struct gprovider *pp, const char *cfg)
254
{
255
struct gconfig *gc;
256
257
LIST_FOREACH(gc, &pp->lg_config, lg_config) {
258
if (!strcmp(gc->lg_name, cfg))
259
return (gc->lg_val);
260
}
261
return (NULL);
262
}
263
264
static struct gprovider *
265
find_provider(struct ggeom *gp, off_t minsector)
266
{
267
struct gprovider *pp, *bestpp;
268
const char *s;
269
off_t sector, bestsector;
270
271
bestpp = NULL;
272
bestsector = 0;
273
LIST_FOREACH(pp, &gp->lg_provider, lg_provider) {
274
s = find_provcfg(pp, "start");
275
sector = (off_t)strtoimax(s, NULL, 0);
276
if (sector < minsector)
277
continue;
278
if (bestpp != NULL && sector >= bestsector)
279
continue;
280
281
bestpp = pp;
282
bestsector = sector;
283
}
284
return (bestpp);
285
}
286
287
static const char *
288
fmtattrib(struct gprovider *pp)
289
{
290
static char buf[128];
291
struct gconfig *gc;
292
u_int idx;
293
294
buf[0] = '\0';
295
idx = 0;
296
LIST_FOREACH(gc, &pp->lg_config, lg_config) {
297
if (strcmp(gc->lg_name, "attrib") != 0)
298
continue;
299
idx += snprintf(buf + idx, sizeof(buf) - idx, "%s%s",
300
(idx == 0) ? " [" : ",", gc->lg_val);
301
}
302
if (idx > 0)
303
snprintf(buf + idx, sizeof(buf) - idx, "] ");
304
return (buf);
305
}
306
307
#define ALIGNDOWN(d, a) ((d) - (d) % (a))
308
#define ALIGNUP(d, a) ((d) % (a) ? (d) - (d) % (a) + (a): (d))
309
310
static int
311
gpart_autofill_resize(struct gctl_req *req)
312
{
313
struct gmesh mesh;
314
struct gclass *cp;
315
struct ggeom *gp;
316
struct gprovider *pp;
317
off_t last, size, start, new_size;
318
off_t lba, new_lba, alignment, offset;
319
const char *g, *s;
320
int error, idx, has_alignment;
321
322
idx = (int)gctl_get_intmax(req, GPART_PARAM_INDEX);
323
if (idx < 1)
324
errx(EXIT_FAILURE, "invalid partition index");
325
326
s = gctl_get_ascii(req, "class");
327
if (s == NULL)
328
abort();
329
g = gctl_get_ascii(req, "arg0");
330
if (g == NULL)
331
abort();
332
error = geom_gettree_geom(&mesh, s, g, 1);
333
if (error)
334
return (error);
335
cp = find_class(&mesh, s);
336
if (cp == NULL)
337
errx(EXIT_FAILURE, "Class %s not found.", s);
338
gp = find_geom(cp, g);
339
if (gp == NULL)
340
errx(EXIT_FAILURE, "No such geom: %s.", g);
341
pp = LIST_FIRST(&gp->lg_consumer)->lg_provider;
342
if (pp == NULL)
343
errx(EXIT_FAILURE, "Provider for geom %s not found.", g);
344
345
s = gctl_get_ascii(req, "alignment");
346
has_alignment = (*s == '*') ? 0 : 1;
347
alignment = 1;
348
if (has_alignment) {
349
error = g_parse_lba(s, pp->lg_sectorsize, &alignment);
350
if (error)
351
errc(EXIT_FAILURE, error, "Invalid alignment param");
352
if (alignment == 0)
353
errx(EXIT_FAILURE, "Invalid alignment param");
354
} else {
355
lba = pp->lg_stripesize / pp->lg_sectorsize;
356
if (lba > 0)
357
alignment = lba;
358
}
359
error = gctl_delete_param(req, "alignment");
360
if (error)
361
errc(EXIT_FAILURE, error, "internal error");
362
363
s = gctl_get_ascii(req, "size");
364
if (*s == '*')
365
new_size = 0;
366
else {
367
error = g_parse_lba(s, pp->lg_sectorsize, &new_size);
368
if (error)
369
errc(EXIT_FAILURE, error, "Invalid size param");
370
/* no autofill necessary. */
371
if (has_alignment == 0)
372
goto done;
373
}
374
375
offset = (pp->lg_stripeoffset / pp->lg_sectorsize) % alignment;
376
s = find_geomcfg(gp, "last");
377
if (s == NULL)
378
errx(EXIT_FAILURE, "Final block not found for geom %s",
379
gp->lg_name);
380
last = (off_t)strtoimax(s, NULL, 0);
381
LIST_FOREACH(pp, &gp->lg_provider, lg_provider) {
382
s = find_provcfg(pp, "index");
383
if (s == NULL)
384
continue;
385
if (atoi(s) == idx)
386
break;
387
}
388
if (pp == NULL)
389
errx(EXIT_FAILURE, "invalid partition index");
390
391
s = find_provcfg(pp, "start");
392
start = (off_t)strtoimax(s, NULL, 0);
393
s = find_provcfg(pp, "end");
394
lba = (off_t)strtoimax(s, NULL, 0);
395
size = lba - start + 1;
396
397
pp = find_provider(gp, lba + 1);
398
if (new_size > 0 && (new_size <= size || pp == NULL)) {
399
/* The start offset may be not aligned, so we align the end
400
* offset and then calculate the size.
401
*/
402
new_size = ALIGNDOWN(start + offset + new_size,
403
alignment) - start - offset;
404
goto done;
405
}
406
if (pp == NULL) {
407
new_size = ALIGNDOWN(last + offset + 1, alignment) -
408
start - offset;
409
if (new_size < size)
410
return (ENOSPC);
411
} else {
412
s = find_provcfg(pp, "start");
413
new_lba = (off_t)strtoimax(s, NULL, 0);
414
/*
415
* Is there any free space between current and
416
* next providers?
417
*/
418
new_lba = ALIGNDOWN(new_lba + offset, alignment) - offset;
419
if (new_lba > lba)
420
new_size = new_lba - start;
421
else {
422
geom_deletetree(&mesh);
423
return (ENOSPC);
424
}
425
}
426
done:
427
snprintf(ssize, sizeof(ssize), "%jd", (intmax_t)new_size);
428
gctl_change_param(req, "size", -1, ssize);
429
geom_deletetree(&mesh);
430
return (0);
431
}
432
433
static int
434
gpart_autofill(struct gctl_req *req)
435
{
436
struct gmesh mesh;
437
struct gclass *cp;
438
struct ggeom *gp;
439
struct gprovider *pp;
440
off_t first, last, a_first;
441
off_t size, start, a_lba;
442
off_t lba, len, alignment, offset;
443
uintmax_t grade;
444
const char *g, *s;
445
int error, has_size, has_start, has_alignment;
446
447
s = gctl_get_ascii(req, "verb");
448
if (strcmp(s, "resize") == 0)
449
return gpart_autofill_resize(req);
450
if (strcmp(s, "add") != 0)
451
return (0);
452
453
s = gctl_get_ascii(req, "class");
454
if (s == NULL)
455
abort();
456
g = gctl_get_ascii(req, "arg0");
457
if (g == NULL)
458
abort();
459
error = geom_gettree_geom(&mesh, s, g, 1);
460
if (error)
461
return (error);
462
cp = find_class(&mesh, s);
463
if (cp == NULL)
464
errx(EXIT_FAILURE, "Class %s not found.", s);
465
gp = find_geom(cp, g);
466
if (gp == NULL) {
467
if (g_device_path(g) == NULL) {
468
errx(EXIT_FAILURE, "No such geom %s.", g);
469
} else {
470
/*
471
* We don't free memory allocated by g_device_path() as
472
* we are about to exit.
473
*/
474
errx(EXIT_FAILURE,
475
"No partitioning scheme found on geom %s. Create one first using 'gpart create'.",
476
g);
477
}
478
}
479
pp = LIST_FIRST(&gp->lg_consumer)->lg_provider;
480
if (pp == NULL)
481
errx(EXIT_FAILURE, "Provider for geom %s not found.", g);
482
483
s = gctl_get_ascii(req, "alignment");
484
has_alignment = (*s == '*') ? 0 : 1;
485
alignment = 1;
486
if (has_alignment) {
487
error = g_parse_lba(s, pp->lg_sectorsize, &alignment);
488
if (error)
489
errc(EXIT_FAILURE, error, "Invalid alignment param");
490
if (alignment == 0)
491
errx(EXIT_FAILURE, "Invalid alignment param");
492
}
493
error = gctl_delete_param(req, "alignment");
494
if (error)
495
errc(EXIT_FAILURE, error, "internal error");
496
497
s = gctl_get_ascii(req, "size");
498
has_size = (*s == '*') ? 0 : 1;
499
size = 0;
500
if (has_size) {
501
error = g_parse_lba(s, pp->lg_sectorsize, &size);
502
if (error)
503
errc(EXIT_FAILURE, error, "Invalid size param");
504
}
505
506
s = gctl_get_ascii(req, "start");
507
has_start = (*s == '*') ? 0 : 1;
508
start = 0ULL;
509
if (has_start) {
510
error = g_parse_lba(s, pp->lg_sectorsize, &start);
511
if (error)
512
errc(EXIT_FAILURE, error, "Invalid start param");
513
}
514
515
/* No autofill necessary. */
516
if (has_size && has_start && !has_alignment)
517
goto done;
518
519
len = pp->lg_stripesize / pp->lg_sectorsize;
520
if (len > 0 && !has_alignment)
521
alignment = len;
522
523
/* Adjust parameters to stripeoffset */
524
offset = (pp->lg_stripeoffset / pp->lg_sectorsize) % alignment;
525
start = ALIGNUP(start + offset, alignment);
526
if (size > alignment)
527
size = ALIGNDOWN(size, alignment);
528
529
s = find_geomcfg(gp, "first");
530
if (s == NULL)
531
errx(EXIT_FAILURE, "Starting block not found for geom %s",
532
gp->lg_name);
533
first = (off_t)strtoimax(s, NULL, 0);
534
s = find_geomcfg(gp, "last");
535
if (s == NULL)
536
errx(EXIT_FAILURE, "Final block not found for geom %s",
537
gp->lg_name);
538
last = (off_t)strtoimax(s, NULL, 0);
539
grade = ~0ULL;
540
a_first = ALIGNUP(first + offset, alignment);
541
last = ALIGNDOWN(last + offset + 1, alignment) - 1;
542
if (a_first < start)
543
a_first = start;
544
while ((pp = find_provider(gp, first)) != NULL) {
545
s = find_provcfg(pp, "start");
546
lba = (off_t)strtoimax(s, NULL, 0);
547
a_lba = ALIGNDOWN(lba + offset, alignment);
548
if (first < a_lba && a_first < a_lba) {
549
/* Free space [first, lba> */
550
len = a_lba - a_first;
551
if (has_size) {
552
if (len >= size &&
553
(uintmax_t)(len - size) < grade) {
554
start = a_first;
555
grade = len - size;
556
}
557
} else if (has_start) {
558
if (start >= a_first && start < a_lba) {
559
size = a_lba - start;
560
grade = start - a_first;
561
}
562
} else {
563
if (grade == ~0ULL || len > size) {
564
start = a_first;
565
size = len;
566
grade = 0;
567
}
568
}
569
}
570
571
s = find_provcfg(pp, "end");
572
first = (off_t)strtoimax(s, NULL, 0) + 1;
573
if (first + offset > a_first)
574
a_first = ALIGNUP(first + offset, alignment);
575
}
576
if (a_first <= last) {
577
/* Free space [first-last] */
578
len = ALIGNDOWN(last - a_first + 1, alignment);
579
if (has_size) {
580
if (len >= size &&
581
(uintmax_t)(len - size) < grade) {
582
start = a_first;
583
grade = len - size;
584
}
585
} else if (has_start) {
586
if (start >= a_first && start <= last) {
587
size = ALIGNDOWN(last - start + 1, alignment);
588
grade = start - a_first;
589
}
590
} else {
591
if (grade == ~0ULL || len > size) {
592
start = a_first;
593
size = len;
594
grade = 0;
595
}
596
}
597
}
598
if (grade == ~0ULL) {
599
geom_deletetree(&mesh);
600
return (ENOSPC);
601
}
602
start -= offset; /* Return back to real offset */
603
done:
604
snprintf(ssize, sizeof(ssize), "%jd", (intmax_t)size);
605
gctl_change_param(req, "size", -1, ssize);
606
snprintf(sstart, sizeof(sstart), "%jd", (intmax_t)start);
607
gctl_change_param(req, "start", -1, sstart);
608
geom_deletetree(&mesh);
609
return (0);
610
}
611
612
static void
613
gpart_show_geom(struct ggeom *gp, const char *element, int show_providers)
614
{
615
struct gprovider *pp;
616
struct gconfig *gc;
617
const char *s, *scheme;
618
off_t first, last, sector, end;
619
off_t length, secsz;
620
int idx, wblocks, wname, wmax;
621
622
if (geom_is_withered(gp))
623
return;
624
scheme = find_geomcfg(gp, "scheme");
625
if (scheme == NULL)
626
errx(EXIT_FAILURE, "Scheme not found for geom %s", gp->lg_name);
627
s = find_geomcfg(gp, "first");
628
if (s == NULL)
629
errx(EXIT_FAILURE, "Starting block not found for geom %s",
630
gp->lg_name);
631
first = (off_t)strtoimax(s, NULL, 0);
632
s = find_geomcfg(gp, "last");
633
if (s == NULL)
634
errx(EXIT_FAILURE, "Final block not found for geom %s",
635
gp->lg_name);
636
last = (off_t)strtoimax(s, NULL, 0);
637
wblocks = strlen(s);
638
s = find_geomcfg(gp, "state");
639
if (s == NULL)
640
errx(EXIT_FAILURE, "State not found for geom %s", gp->lg_name);
641
if (s != NULL && *s != 'C')
642
s = NULL;
643
wmax = strlen(gp->lg_name);
644
if (show_providers) {
645
LIST_FOREACH(pp, &gp->lg_provider, lg_provider) {
646
wname = strlen(pp->lg_name);
647
if (wname > wmax)
648
wmax = wname;
649
}
650
}
651
wname = wmax;
652
pp = LIST_FIRST(&gp->lg_consumer)->lg_provider;
653
secsz = pp->lg_sectorsize;
654
xo_open_instance("part");
655
xo_emit("=>{t:start/%*jd} {t:sectors/%*jd} "
656
"{t:name/%*s} {:scheme} ({h:size/%jd})"
657
"{t:state}\n",
658
wblocks, (intmax_t)first, wblocks, (intmax_t)(last - first + 1),
659
wname, gp->lg_name, scheme, (intmax_t)pp->lg_mediasize,
660
s ? " [CORRUPT]": "");
661
662
xo_open_list("partitions");
663
while ((pp = find_provider(gp, first)) != NULL) {
664
s = find_provcfg(pp, "start");
665
sector = (off_t)strtoimax(s, NULL, 0);
666
667
s = find_provcfg(pp, "end");
668
end = (off_t)strtoimax(s, NULL, 0);
669
length = end - sector + 1;
670
671
s = find_provcfg(pp, "index");
672
idx = atoi(s);
673
if (first < sector) {
674
xo_open_instance(s);
675
xo_emit(" {t:start/%*jd} "
676
"{t:sectors/%*jd} "
677
"{P:/%*s} "
678
"{ne:free}- free - ({h:size/%jd})\n",
679
wblocks, (intmax_t)first,
680
wblocks, (intmax_t)(sector - first),
681
wname, "",
682
"true", (intmax_t)(sector - first) * secsz);
683
xo_close_instance(s);
684
}
685
xo_open_instance(s);
686
xo_emit(" {t:start/%*jd} {t:sectors/%*jd}",
687
wblocks, (intmax_t)sector, wblocks, (intmax_t)length);
688
if (show_providers) {
689
xo_emit(" {t:name/%*s}{e:index/%d}",
690
wname, pp->lg_name, idx);
691
} else {
692
xo_emit(" {t:index/%*d}{e:name}",
693
wname, idx, pp->lg_name);
694
}
695
696
if (strcmp(element, "label") == 0) {
697
xo_emit(" {:label}{e:type}{e:rawtype}",
698
find_provcfg(pp, element),
699
find_provcfg(pp, "type"),
700
find_provcfg(pp, "rawtype"));
701
} else if (strcmp(element, "type") == 0) {
702
xo_emit(" {:type}{e:label}{e:rawtype}",
703
find_provcfg(pp, element),
704
find_provcfg(pp, "label"),
705
find_provcfg(pp, "rawtype"));
706
} else {
707
xo_emit(" {:rawtype}{e:type}{e:label}",
708
find_provcfg(pp, element),
709
find_provcfg(pp, "type"),
710
find_provcfg(pp, "label"));
711
}
712
713
idx = 0;
714
LIST_FOREACH(gc, &pp->lg_config, lg_config) {
715
if (strcmp(gc->lg_name, "attrib") != 0)
716
continue;
717
idx++;
718
if (idx == 1)
719
xo_emit(" [");
720
else
721
xo_emit(",");
722
xo_emit("{l:attribute}", gc->lg_val);
723
}
724
if (idx)
725
xo_emit("]");
726
xo_emit(" ({h:size/%jd})\n", (intmax_t)pp->lg_mediasize);
727
xo_close_instance(s);
728
first = end + 1;
729
}
730
731
if (first <= last) {
732
xo_open_instance("unallocated");
733
length = last - first + 1;
734
xo_emit(" {t:start/%*jd} {t:sectors/%*jd} "
735
"{P:/%*s} {ne:free}- free - ({h:size/%jd})\n",
736
wblocks, (intmax_t)first, wblocks, (intmax_t)length,
737
wname, "", "true", (intmax_t)length * secsz);
738
xo_close_instance("unallocated");
739
}
740
xo_close_list("partitions");
741
xo_close_instance("part");
742
xo_emit("\n");
743
}
744
745
static int
746
gpart_show_hasopt(struct gctl_req *req, const char *opt, const char *elt)
747
{
748
749
if (!gctl_get_int(req, "%s", opt))
750
return (0);
751
752
if (elt != NULL)
753
errx(EXIT_FAILURE, "-l and -r are mutually exclusive");
754
755
return (1);
756
}
757
758
static void
759
gpart_show(struct gctl_req *req, unsigned int fl __unused)
760
{
761
struct gmesh mesh;
762
struct gclass *classp;
763
struct ggeom *gp;
764
const char *element, *name;
765
int error, i, nargs, show_providers;
766
767
element = NULL;
768
if (gpart_show_hasopt(req, "show_label", element))
769
element = "label";
770
if (gpart_show_hasopt(req, "show_rawtype", element))
771
element = "rawtype";
772
if (element == NULL)
773
element = "type";
774
775
name = gctl_get_ascii(req, "class");
776
if (name == NULL)
777
abort();
778
nargs = gctl_get_int(req, "nargs");
779
if (nargs == 1) {
780
error = geom_gettree_geom(&mesh, name,
781
gctl_get_ascii(req, "arg0"), 1);
782
} else
783
error = geom_gettree(&mesh);
784
if (error != 0)
785
errc(EXIT_FAILURE, error, "Cannot get GEOM tree");
786
classp = find_class(&mesh, name);
787
if (classp == NULL) {
788
geom_deletetree(&mesh);
789
errx(EXIT_FAILURE, "Class %s not found.", name);
790
}
791
show_providers = gctl_get_int(req, "show_providers");
792
xo_open_list(name);
793
if (nargs > 0) {
794
for (i = 0; i < nargs; i++) {
795
name = gctl_get_ascii(req, "arg%d", i);
796
gp = find_geom(classp, name);
797
if (gp != NULL)
798
gpart_show_geom(gp, element, show_providers);
799
else
800
errx(EXIT_FAILURE, "No such geom: %s.", name);
801
}
802
} else {
803
LIST_FOREACH(gp, &classp->lg_geom, lg_geom) {
804
gpart_show_geom(gp, element, show_providers);
805
}
806
}
807
xo_close_list(name);
808
geom_deletetree(&mesh);
809
}
810
811
static void
812
gpart_backup(struct gctl_req *req, unsigned int fl __unused)
813
{
814
struct gmesh mesh;
815
struct gclass *classp;
816
struct gprovider *pp;
817
struct ggeom *gp;
818
const char *g, *s, *scheme;
819
off_t sector, end;
820
off_t length;
821
int error, i, windex, wblocks, wtype;
822
823
if (gctl_get_int(req, "nargs") != 1)
824
errx(EXIT_FAILURE, "Invalid number of arguments.");
825
s = gctl_get_ascii(req, "class");
826
if (s == NULL)
827
abort();
828
g = gctl_get_ascii(req, "arg0");
829
if (g == NULL)
830
abort();
831
error = geom_gettree_geom(&mesh, s, g, 0);
832
if (error != 0)
833
errc(EXIT_FAILURE, error, "Cannot get GEOM tree");
834
classp = find_class(&mesh, s);
835
if (classp == NULL) {
836
geom_deletetree(&mesh);
837
errx(EXIT_FAILURE, "Class %s not found.", s);
838
}
839
gp = find_geom(classp, g);
840
if (gp == NULL)
841
errx(EXIT_FAILURE, "No such geom: %s.", g);
842
scheme = find_geomcfg(gp, "scheme");
843
if (scheme == NULL)
844
abort();
845
s = find_geomcfg(gp, "last");
846
if (s == NULL)
847
abort();
848
wblocks = strlen(s);
849
wtype = 0;
850
LIST_FOREACH(pp, &gp->lg_provider, lg_provider) {
851
s = find_provcfg(pp, "type");
852
i = strlen(s);
853
if (i > wtype)
854
wtype = i;
855
}
856
s = find_geomcfg(gp, "entries");
857
if (s == NULL)
858
abort();
859
windex = strlen(s);
860
printf("%s %s\n", scheme, s);
861
LIST_FOREACH(pp, &gp->lg_provider, lg_provider) {
862
s = find_provcfg(pp, "start");
863
sector = (off_t)strtoimax(s, NULL, 0);
864
865
s = find_provcfg(pp, "end");
866
end = (off_t)strtoimax(s, NULL, 0);
867
length = end - sector + 1;
868
869
s = find_provcfg(pp, "label");
870
printf("%-*s %*s %*jd %*jd %s %s\n",
871
windex, find_provcfg(pp, "index"),
872
wtype, find_provcfg(pp, "type"),
873
wblocks, (intmax_t)sector,
874
wblocks, (intmax_t)length,
875
(s != NULL) ? s: "", fmtattrib(pp));
876
}
877
geom_deletetree(&mesh);
878
}
879
880
static int
881
skip_line(const char *p)
882
{
883
884
while (*p != '\0') {
885
if (*p == '#')
886
return (1);
887
if (isspace(*p) == 0)
888
return (0);
889
p++;
890
}
891
return (1);
892
}
893
894
static void
895
gpart_sighndl(int sig __unused)
896
{
897
undo_restore = 1;
898
}
899
900
static void
901
gpart_restore(struct gctl_req *req, unsigned int fl __unused)
902
{
903
struct gmesh mesh;
904
struct gclass *classp;
905
struct gctl_req *r;
906
struct ggeom *gp;
907
struct sigaction si_sa;
908
const char *s, *flags, *errstr, *label;
909
char **ap, *argv[6], line[BUFSIZ], *pline;
910
int error, forced, i, l, nargs, created, rl;
911
intmax_t n;
912
913
nargs = gctl_get_int(req, "nargs");
914
if (nargs < 1)
915
errx(EXIT_FAILURE, "Invalid number of arguments.");
916
917
forced = gctl_get_int(req, "force");
918
flags = gctl_get_ascii(req, "flags");
919
rl = gctl_get_int(req, "restore_labels");
920
s = gctl_get_ascii(req, "class");
921
if (s == NULL)
922
abort();
923
error = geom_gettree(&mesh);
924
if (error != 0)
925
errc(EXIT_FAILURE, error, "Cannot get GEOM tree");
926
classp = find_class(&mesh, s);
927
if (classp == NULL) {
928
geom_deletetree(&mesh);
929
errx(EXIT_FAILURE, "Class %s not found.", s);
930
}
931
932
sigemptyset(&si_sa.sa_mask);
933
si_sa.sa_flags = 0;
934
si_sa.sa_handler = gpart_sighndl;
935
if (sigaction(SIGINT, &si_sa, 0) == -1)
936
err(EXIT_FAILURE, "sigaction SIGINT");
937
938
if (forced) {
939
/* destroy existent partition table before restore */
940
for (i = 0; i < nargs; i++) {
941
s = gctl_get_ascii(req, "arg%d", i);
942
gp = find_geom(classp, s);
943
if (gp != NULL) {
944
r = gctl_get_handle();
945
gctl_ro_param(r, "class", -1,
946
classp->lg_name);
947
gctl_ro_param(r, "verb", -1, "destroy");
948
gctl_ro_param(r, "flags", -1, "restore");
949
gctl_ro_param(r, "force", sizeof(forced),
950
&forced);
951
gctl_ro_param(r, "arg0", -1, s);
952
errstr = gctl_issue(r);
953
if (errstr != NULL && errstr[0] != '\0') {
954
gpart_print_error(errstr);
955
gctl_free(r);
956
goto backout;
957
}
958
gctl_free(r);
959
}
960
}
961
}
962
created = 0;
963
while (undo_restore == 0 &&
964
fgets(line, sizeof(line) - 1, stdin) != NULL) {
965
/* Format of backup entries:
966
* <scheme name> <number of entries>
967
* <index> <type> <start> <size> [label] ['['attrib[,attrib]']']
968
*/
969
pline = (char *)line;
970
pline[strlen(line) - 1] = 0;
971
if (skip_line(pline))
972
continue;
973
for (ap = argv;
974
(*ap = strsep(&pline, " \t")) != NULL;)
975
if (**ap != '\0' && ++ap >= &argv[6])
976
break;
977
l = ap - &argv[0];
978
label = pline = NULL;
979
if (l == 1 || l == 2) { /* create table */
980
if (created)
981
errx(EXIT_FAILURE, "Incorrect backup format.");
982
if (l == 2)
983
n = strtoimax(argv[1], NULL, 0);
984
for (i = 0; i < nargs; i++) {
985
s = gctl_get_ascii(req, "arg%d", i);
986
r = gctl_get_handle();
987
gctl_ro_param(r, "class", -1,
988
classp->lg_name);
989
gctl_ro_param(r, "verb", -1, "create");
990
gctl_ro_param(r, "scheme", -1, argv[0]);
991
if (l == 2)
992
gctl_ro_param(r, "entries",
993
sizeof(n), &n);
994
gctl_ro_param(r, "flags", -1, "restore");
995
gctl_ro_param(r, "arg0", -1, s);
996
errstr = gctl_issue(r);
997
if (errstr != NULL && errstr[0] != '\0') {
998
gpart_print_error(errstr);
999
gctl_free(r);
1000
goto backout;
1001
}
1002
gctl_free(r);
1003
}
1004
created = 1;
1005
continue;
1006
} else if (l < 4 || created == 0)
1007
errx(EXIT_FAILURE, "Incorrect backup format.");
1008
else if (l == 5) {
1009
if (strchr(argv[4], '[') == NULL)
1010
label = argv[4];
1011
else
1012
pline = argv[4];
1013
} else if (l == 6) {
1014
label = argv[4];
1015
pline = argv[5];
1016
}
1017
/* Add partitions to each table */
1018
for (i = 0; i < nargs; i++) {
1019
s = gctl_get_ascii(req, "arg%d", i);
1020
r = gctl_get_handle();
1021
n = strtoimax(argv[0], NULL, 0);
1022
gctl_ro_param(r, "class", -1, classp->lg_name);
1023
gctl_ro_param(r, "verb", -1, "add");
1024
gctl_ro_param(r, "flags", -1, "restore");
1025
gctl_ro_param(r, GPART_PARAM_INDEX, sizeof(n), &n);
1026
gctl_ro_param(r, "type", -1, argv[1]);
1027
gctl_ro_param(r, "start", -1, argv[2]);
1028
gctl_ro_param(r, "size", -1, argv[3]);
1029
if (rl != 0 && label != NULL)
1030
gctl_ro_param(r, "label", -1, argv[4]);
1031
gctl_ro_param(r, "alignment", -1, GPART_AUTOFILL);
1032
gctl_ro_param(r, "arg0", -1, s);
1033
error = gpart_autofill(r);
1034
if (error != 0)
1035
errc(EXIT_FAILURE, error, "autofill");
1036
errstr = gctl_issue(r);
1037
if (errstr != NULL && errstr[0] != '\0') {
1038
gpart_print_error(errstr);
1039
gctl_free(r);
1040
goto backout;
1041
}
1042
gctl_free(r);
1043
}
1044
if (pline == NULL || *pline != '[')
1045
continue;
1046
/* set attributes */
1047
pline++;
1048
for (ap = argv;
1049
(*ap = strsep(&pline, ",]")) != NULL;)
1050
if (**ap != '\0' && ++ap >= &argv[6])
1051
break;
1052
for (i = 0; i < nargs; i++) {
1053
l = ap - &argv[0];
1054
s = gctl_get_ascii(req, "arg%d", i);
1055
while (l > 0) {
1056
r = gctl_get_handle();
1057
gctl_ro_param(r, "class", -1, classp->lg_name);
1058
gctl_ro_param(r, "verb", -1, "set");
1059
gctl_ro_param(r, "flags", -1, "restore");
1060
gctl_ro_param(r, GPART_PARAM_INDEX,
1061
sizeof(n), &n);
1062
gctl_ro_param(r, "attrib", -1, argv[--l]);
1063
gctl_ro_param(r, "arg0", -1, s);
1064
errstr = gctl_issue(r);
1065
if (errstr != NULL && errstr[0] != '\0') {
1066
gpart_print_error(errstr);
1067
gctl_free(r);
1068
goto backout;
1069
}
1070
gctl_free(r);
1071
}
1072
}
1073
}
1074
if (undo_restore)
1075
goto backout;
1076
/* commit changes if needed */
1077
if (strchr(flags, 'C') != NULL) {
1078
for (i = 0; i < nargs; i++) {
1079
s = gctl_get_ascii(req, "arg%d", i);
1080
r = gctl_get_handle();
1081
gctl_ro_param(r, "class", -1, classp->lg_name);
1082
gctl_ro_param(r, "verb", -1, "commit");
1083
gctl_ro_param(r, "arg0", -1, s);
1084
errstr = gctl_issue(r);
1085
if (errstr != NULL && errstr[0] != '\0') {
1086
gpart_print_error(errstr);
1087
gctl_free(r);
1088
goto backout;
1089
}
1090
gctl_free(r);
1091
}
1092
}
1093
gctl_free(req);
1094
geom_deletetree(&mesh);
1095
exit(EXIT_SUCCESS);
1096
1097
backout:
1098
for (i = 0; i < nargs; i++) {
1099
s = gctl_get_ascii(req, "arg%d", i);
1100
r = gctl_get_handle();
1101
gctl_ro_param(r, "class", -1, classp->lg_name);
1102
gctl_ro_param(r, "verb", -1, "undo");
1103
gctl_ro_param(r, "arg0", -1, s);
1104
gctl_issue(r);
1105
gctl_free(r);
1106
}
1107
gctl_free(req);
1108
geom_deletetree(&mesh);
1109
exit(EXIT_FAILURE);
1110
}
1111
1112
static void *
1113
gpart_bootfile_read(const char *bootfile, ssize_t *size)
1114
{
1115
struct stat sb;
1116
void *code;
1117
int fd;
1118
1119
if (stat(bootfile, &sb) == -1)
1120
err(EXIT_FAILURE, "%s", bootfile);
1121
if (!S_ISREG(sb.st_mode))
1122
errx(EXIT_FAILURE, "%s: not a regular file", bootfile);
1123
if (sb.st_size == 0)
1124
errx(EXIT_FAILURE, "%s: empty file", bootfile);
1125
if (*size > 0 && sb.st_size > *size)
1126
errx(EXIT_FAILURE, "%s: file too big (%zd limit)", bootfile,
1127
*size);
1128
1129
*size = sb.st_size;
1130
1131
fd = open(bootfile, O_RDONLY);
1132
if (fd == -1)
1133
err(EXIT_FAILURE, "%s", bootfile);
1134
code = malloc(*size);
1135
if (code == NULL)
1136
err(EXIT_FAILURE, NULL);
1137
if (read(fd, code, *size) != *size)
1138
err(EXIT_FAILURE, "%s", bootfile);
1139
close(fd);
1140
1141
return (code);
1142
}
1143
1144
static void
1145
gpart_write_partcode(struct gctl_req *req, int idx, void *code, ssize_t size)
1146
{
1147
char dsf[128];
1148
struct gmesh mesh;
1149
struct gclass *classp;
1150
struct ggeom *gp;
1151
struct gprovider *pp;
1152
const char *g, *s;
1153
char *buf;
1154
off_t bsize;
1155
int error, fd;
1156
1157
s = gctl_get_ascii(req, "class");
1158
if (s == NULL)
1159
abort();
1160
g = gctl_get_ascii(req, "arg0");
1161
if (g == NULL)
1162
abort();
1163
error = geom_gettree_geom(&mesh, s, g, 0);
1164
if (error != 0)
1165
errc(EXIT_FAILURE, error, "Cannot get GEOM tree");
1166
classp = find_class(&mesh, s);
1167
if (classp == NULL) {
1168
geom_deletetree(&mesh);
1169
errx(EXIT_FAILURE, "Class %s not found.", s);
1170
}
1171
gp = find_geom(classp, g);
1172
if (gp == NULL)
1173
errx(EXIT_FAILURE, "No such geom: %s.", g);
1174
s = find_geomcfg(gp, "scheme");
1175
if (s == NULL)
1176
errx(EXIT_FAILURE, "Scheme not found for geom %s", gp->lg_name);
1177
1178
LIST_FOREACH(pp, &gp->lg_provider, lg_provider) {
1179
s = find_provcfg(pp, "index");
1180
if (s == NULL)
1181
continue;
1182
if (atoi(s) == idx)
1183
break;
1184
}
1185
1186
if (pp != NULL) {
1187
snprintf(dsf, sizeof(dsf), "/dev/%s", pp->lg_name);
1188
if (pp->lg_mediasize < size)
1189
errx(EXIT_FAILURE, "%s: not enough space", dsf);
1190
fd = open(dsf, O_WRONLY);
1191
if (fd == -1)
1192
err(EXIT_FAILURE, "%s", dsf);
1193
/*
1194
* When writing to a disk device, the write must be
1195
* sector aligned and not write to any partial sectors,
1196
* so round up the buffer size to the next sector and zero it.
1197
*/
1198
bsize = (size + pp->lg_sectorsize - 1) /
1199
pp->lg_sectorsize * pp->lg_sectorsize;
1200
buf = calloc(1, bsize);
1201
if (buf == NULL)
1202
err(EXIT_FAILURE, "%s", dsf);
1203
bcopy(code, buf, size);
1204
if (write(fd, buf, bsize) != bsize)
1205
err(EXIT_FAILURE, "%s", dsf);
1206
free(buf);
1207
close(fd);
1208
printf("partcode written to %s\n", pp->lg_name);
1209
} else
1210
errx(EXIT_FAILURE, "invalid partition index");
1211
1212
geom_deletetree(&mesh);
1213
}
1214
1215
static void
1216
gpart_bootcode(struct gctl_req *req, unsigned int fl)
1217
{
1218
const char *s;
1219
void *bootcode, *partcode;
1220
size_t bootsize, partsize;
1221
int error, idx;
1222
1223
if (gctl_get_int(req, "nargs") != 1)
1224
errx(EXIT_FAILURE, "Invalid number of arguments.");
1225
1226
if (gctl_has_param(req, GPART_PARAM_BOOTCODE)) {
1227
s = gctl_get_ascii(req, GPART_PARAM_BOOTCODE);
1228
bootsize = 800 * 1024; /* Arbitrary limit. */
1229
bootcode = gpart_bootfile_read(s, &bootsize);
1230
error = gctl_change_param(req, GPART_PARAM_BOOTCODE, bootsize,
1231
bootcode);
1232
if (error)
1233
errc(EXIT_FAILURE, error, "internal error");
1234
} else
1235
bootcode = NULL;
1236
1237
if (!gctl_has_param(req, GPART_PARAM_PARTCODE)) {
1238
if (bootcode == NULL)
1239
errx(EXIT_FAILURE, "neither -b nor -p specified");
1240
if (gctl_has_param(req, GPART_PARAM_INDEX))
1241
errx(EXIT_FAILURE, "-i is only valid with -p");
1242
goto nopartcode;
1243
}
1244
1245
if (gctl_has_param(req, GPART_PARAM_INDEX)) {
1246
idx = (int)gctl_get_intmax(req, GPART_PARAM_INDEX);
1247
if (idx < 1)
1248
errx(EXIT_FAILURE, "invalid partition index");
1249
error = gctl_delete_param(req, GPART_PARAM_INDEX);
1250
if (error)
1251
errc(EXIT_FAILURE, error, "internal error");
1252
} else
1253
idx = 0;
1254
1255
if (gctl_has_param(req, GPART_PARAM_PARTCODE)) {
1256
s = gctl_get_ascii(req, GPART_PARAM_PARTCODE);
1257
partsize = 1024 * 1024; /* Arbitrary limit. */
1258
partcode = gpart_bootfile_read(s, &partsize);
1259
error = gctl_delete_param(req, GPART_PARAM_PARTCODE);
1260
if (error)
1261
errc(EXIT_FAILURE, error, "internal error");
1262
if (idx == 0)
1263
errx(EXIT_FAILURE, "missing -i option");
1264
gpart_write_partcode(req, idx, partcode, partsize);
1265
free(partcode);
1266
}
1267
1268
nopartcode:
1269
if (bootcode != NULL)
1270
gpart_issue(req, fl);
1271
}
1272
1273
static void
1274
gpart_print_error(const char *errstr)
1275
{
1276
char *errmsg;
1277
int error;
1278
1279
error = strtol(errstr, &errmsg, 0);
1280
if (errmsg != errstr) {
1281
while (errmsg[0] == ' ')
1282
errmsg++;
1283
if (errmsg[0] != '\0')
1284
warnc(error, "%s", errmsg);
1285
else
1286
warnc(error, NULL);
1287
} else
1288
warnx("%s", errmsg);
1289
}
1290
1291
static _Noreturn void
1292
gpart_issue(struct gctl_req *req, unsigned int fl __unused)
1293
{
1294
char buf[4096];
1295
const char *errstr;
1296
int error, status;
1297
1298
if (gctl_get_int(req, "nargs") != 1)
1299
errx(EXIT_FAILURE, "Invalid number of arguments.");
1300
(void)gctl_delete_param(req, "nargs");
1301
1302
/* autofill parameters (if applicable). */
1303
error = gpart_autofill(req);
1304
if (error) {
1305
warnc(error, "autofill");
1306
status = EXIT_FAILURE;
1307
goto done;
1308
}
1309
1310
buf[0] = '\0';
1311
gctl_add_param(req, "output", sizeof(buf), buf,
1312
GCTL_PARAM_WR | GCTL_PARAM_ASCII);
1313
errstr = gctl_issue(req);
1314
if (errstr == NULL || errstr[0] == '\0') {
1315
if (buf[0] != '\0')
1316
printf("%s", buf);
1317
status = EXIT_SUCCESS;
1318
goto done;
1319
}
1320
1321
gpart_print_error(errstr);
1322
status = EXIT_FAILURE;
1323
1324
done:
1325
gctl_free(req);
1326
exit(status);
1327
}
1328
1329