Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sbin/fdisk/fdisk.c
39475 views
1
/*
2
* Mach Operating System
3
* Copyright (c) 1992 Carnegie Mellon University
4
* All Rights Reserved.
5
*
6
* Permission to use, copy, modify and distribute this software and its
7
* documentation is hereby granted, provided that both the copyright
8
* notice and this permission notice appear in all copies of the
9
* software, derivative works or modified versions, and any portions
10
* thereof, and that both notices appear in supporting documentation.
11
*
12
* CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
13
* CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
14
* ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
15
*
16
* Carnegie Mellon requests users of this software to return to
17
*
18
* Software Distribution Coordinator or [email protected]
19
* School of Computer Science
20
* Carnegie Mellon University
21
* Pittsburgh PA 15213-3890
22
*
23
* any improvements or extensions that they make and grant Carnegie Mellon
24
* the rights to redistribute these changes.
25
*/
26
27
#include <sys/cdefs.h>
28
#include <sys/disk.h>
29
#include <sys/disklabel.h>
30
#include <sys/diskmbr.h>
31
#include <sys/endian.h>
32
#include <sys/param.h>
33
#include <sys/stat.h>
34
#include <sys/mount.h>
35
#include <ctype.h>
36
#include <fcntl.h>
37
#include <err.h>
38
#include <errno.h>
39
#include <libgeom.h>
40
#include <paths.h>
41
#include <regex.h>
42
#include <stdint.h>
43
#include <stdio.h>
44
#include <stdlib.h>
45
#include <string.h>
46
#include <unistd.h>
47
48
#include "fdisk_mbr_enc.h"
49
50
static int iotest;
51
52
#define NO_DISK_SECTORS ((u_int32_t)-1)
53
#define NO_TRACK_CYLINDERS 1023
54
#define NO_TRACK_HEADS 255
55
#define NO_TRACK_SECTORS 63
56
#define LBUF 100
57
static char lbuf[LBUF];
58
59
/*
60
*
61
* Ported to 386bsd by Julian Elischer Thu Oct 15 20:26:46 PDT 1992
62
*
63
* 14-Dec-89 Robert Baron (rvb) at Carnegie-Mellon University
64
* Copyright (c) 1989 Robert. V. Baron
65
* Created.
66
*/
67
68
#define Decimal(str, ans, tmp, maxval) if (decimal(str, &tmp, ans, maxval)) ans = tmp
69
70
#define MAX_SEC_SIZE 65536 /* maximum sector size that is supported */
71
#define MIN_SEC_SIZE 512 /* the sector size to start sensing at */
72
static int secsize = 0; /* the sensed sector size */
73
74
static char *disk;
75
76
static int cyls, sectors, heads, cylsecs;
77
static u_int32_t disksecs;
78
79
struct mboot {
80
unsigned char *bootinst; /* boot code */
81
off_t bootinst_size;
82
struct dos_partition parts[NDOSPART];
83
};
84
85
static struct mboot mboot;
86
static int fd;
87
88
#define ACTIVE 0x80
89
90
static uint dos_cyls;
91
static uint dos_heads;
92
static uint dos_sectors;
93
static uint dos_cylsecs;
94
95
#define DOSSECT(s,c) ((s & 0x3f) | ((c >> 2) & 0xc0))
96
#define DOSCYL(c) (c & 0xff)
97
98
#define MAX_ARGS 10
99
100
static int current_line_number;
101
102
static int geom_processed = 0;
103
static int part_processed = 0;
104
static int active_processed = 0;
105
106
typedef struct cmd {
107
char cmd;
108
int n_args;
109
struct arg {
110
char argtype;
111
unsigned long arg_val;
112
char * arg_str;
113
} args[MAX_ARGS];
114
} CMD;
115
116
static int B_flag = 0; /* replace boot code */
117
static int I_flag = 0; /* use entire disk for FreeBSD */
118
static int a_flag = 0; /* set active partition */
119
static char *b_flag = NULL; /* path to boot code */
120
static int i_flag = 0; /* replace partition data */
121
static int q_flag = 0; /* Be quiet */
122
static int u_flag = 0; /* update partition data */
123
static int s_flag = 0; /* Print a summary and exit */
124
static int t_flag = 0; /* test only */
125
static char *f_flag = NULL; /* Read config info from file */
126
static int v_flag = 0; /* Be verbose */
127
static int print_config_flag = 0;
128
129
/*
130
* A list of partition types, probably outdated.
131
*/
132
static const char *const part_types[256] = {
133
[0x00] = "unused",
134
[0x01] = "Primary DOS with 12 bit FAT",
135
[0x02] = "XENIX / file system",
136
[0x03] = "XENIX /usr file system",
137
[0x04] = "Primary DOS with 16 bit FAT (< 32MB)",
138
[0x05] = "Extended DOS",
139
[0x06] = "Primary DOS, 16 bit FAT (>= 32MB)",
140
[0x07] = "NTFS, OS/2 HPFS, QNX-2 (16 bit) or Advanced UNIX",
141
[0x08] = "AIX file system or SplitDrive",
142
[0x09] = "AIX boot partition or Coherent",
143
[0x0A] = "OS/2 Boot Manager, OPUS or Coherent swap",
144
[0x0B] = "DOS or Windows 95 with 32 bit FAT",
145
[0x0C] = "DOS or Windows 95 with 32 bit FAT (LBA)",
146
[0x0E] = "Primary 'big' DOS (>= 32MB, LBA)",
147
[0x0F] = "Extended DOS (LBA)",
148
[0x10] = "OPUS",
149
[0x11] = "OS/2 BM: hidden DOS with 12-bit FAT",
150
[0x12] = "Compaq diagnostics",
151
[0x14] = "OS/2 BM: hidden DOS with 16-bit FAT (< 32MB)",
152
[0x16] = "OS/2 BM: hidden DOS with 16-bit FAT (>= 32MB)",
153
[0x17] = "OS/2 BM: hidden IFS (e.g. HPFS)",
154
[0x18] = "AST Windows swapfile",
155
[0x1b] = "ASUS Recovery partition (NTFS)",
156
[0x24] = "NEC DOS",
157
[0x3C] = "PartitionMagic recovery",
158
[0x39] = "plan9",
159
[0x40] = "VENIX 286",
160
[0x41] = "Linux/MINIX (sharing disk with DRDOS)",
161
[0x42] = "SFS or Linux swap (sharing disk with DRDOS)",
162
[0x43] = "Linux native (sharing disk with DRDOS)",
163
[0x4D] = "QNX 4.2 Primary",
164
[0x4E] = "QNX 4.2 Secondary",
165
[0x4F] = "QNX 4.2 Tertiary",
166
[0x50] = "DM (disk manager)",
167
[0x51] = "DM6 Aux1 (or Novell)",
168
[0x52] = "CP/M or Microport SysV/AT",
169
[0x53] = "DM6 Aux3",
170
[0x54] = "DM6",
171
[0x55] = "EZ-Drive (disk manager)",
172
[0x56] = "Golden Bow (disk manager)",
173
[0x5c] = "Priam Edisk (disk manager)", /* according to S. Widlake */
174
[0x61] = "SpeedStor",
175
[0x63] = "System V/386 (such as ISC UNIX), GNU HURD or Mach",
176
[0x64] = "Novell Netware/286 2.xx",
177
[0x65] = "Novell Netware/386 3.xx",
178
[0x6C] = "DragonFlyBSD",
179
[0x70] = "DiskSecure Multi-Boot",
180
[0x75] = "PCIX",
181
[0x77] = "QNX4.x",
182
[0x78] = "QNX4.x 2nd part",
183
[0x79] = "QNX4.x 3rd part",
184
[0x80] = "Minix until 1.4a",
185
[0x81] = "Minix since 1.4b, early Linux partition or Mitac disk manager",
186
[0x82] = "Linux swap or Solaris x86",
187
[0x83] = "Linux native",
188
[0x84] = "OS/2 hidden C: drive",
189
[0x85] = "Linux extended",
190
[0x86] = "NTFS volume set??",
191
[0x87] = "NTFS volume set??",
192
[0x93] = "Amoeba file system",
193
[0x94] = "Amoeba bad block table",
194
[0x9F] = "BSD/OS",
195
[0xA0] = "Suspend to Disk",
196
[0xA5] = "FreeBSD/NetBSD/386BSD",
197
[0xA6] = "OpenBSD",
198
[0xA7] = "NeXTSTEP",
199
[0xA9] = "NetBSD",
200
[0xAC] = "IBM JFS",
201
[0xAF] = "HFS+",
202
[0xB7] = "BSDI BSD/386 file system",
203
[0xB8] = "BSDI BSD/386 swap",
204
[0xBE] = "Solaris x86 boot",
205
[0xBF] = "Solaris x86 (new)",
206
[0xC1] = "DRDOS/sec with 12-bit FAT",
207
[0xC4] = "DRDOS/sec with 16-bit FAT (< 32MB)",
208
[0xC6] = "DRDOS/sec with 16-bit FAT (>= 32MB)",
209
[0xC7] = "Syrinx",
210
[0xDB] = "CP/M, Concurrent CP/M, Concurrent DOS or CTOS",
211
[0xDE] = "DELL Utilities - FAT filesystem",
212
[0xE1] = "DOS access or SpeedStor with 12-bit FAT extended partition",
213
[0xE3] = "DOS R/O or SpeedStor",
214
[0xE4] = "SpeedStor with 16-bit FAT extended partition < 1024 cyl.",
215
[0xEB] = "BeOS file system",
216
[0xEE] = "EFI GPT",
217
[0xEF] = "EFI System Partition",
218
[0xF1] = "SpeedStor",
219
[0xF2] = "DOS 3.3+ Secondary",
220
[0xF4] = "SpeedStor large partition",
221
[0xFB] = "VMware VMFS",
222
[0xFE] = "SpeedStor >1024 cyl. or LANstep",
223
[0xFF] = "Xenix bad blocks table",
224
};
225
226
static const char *
227
get_type(int t)
228
{
229
const char *ret;
230
231
ret = (t >= 0 && t <= 255) ? part_types[t] : NULL;
232
return ret ? ret : "unknown";
233
}
234
235
236
static int geom_class_available(const char *);
237
static void print_s0(void);
238
static void print_part(const struct dos_partition *);
239
static void init_sector0(unsigned long start);
240
static void init_boot(void);
241
static void change_part(int i);
242
static void print_params(void);
243
static void change_active(int which);
244
static void change_code(void);
245
static void get_params_to_use(void);
246
static char *get_rootdisk(void);
247
static void dos(struct dos_partition *partp);
248
static int open_disk(int flag);
249
static ssize_t read_disk(off_t sector, void *buf);
250
static int write_disk(off_t sector, void *buf);
251
static int get_params(void);
252
static int read_s0(void);
253
static int write_s0(void);
254
static int ok(const char *str);
255
static int decimal(const char *str, int *num, int deflt, uint32_t maxval);
256
static int read_config(char *config_file);
257
static void reset_boot(void);
258
static int sanitize_partition(struct dos_partition *);
259
static void usage(void) __dead2;
260
261
int
262
main(int argc, char *argv[])
263
{
264
int c, i;
265
int partition = -1;
266
struct dos_partition *partp;
267
268
fprintf(stderr,
269
"WARNING: fdisk is deprecated and is not available in FreeBSD 15 or later.\n"
270
"Please use gpart instead.\n\n");
271
272
while ((c = getopt(argc, argv, "BIab:f:ipqstuv1234")) != -1)
273
switch (c) {
274
case 'B':
275
B_flag = 1;
276
break;
277
case 'I':
278
I_flag = 1;
279
break;
280
case 'a':
281
a_flag = 1;
282
break;
283
case 'b':
284
b_flag = optarg;
285
break;
286
case 'f':
287
f_flag = optarg;
288
break;
289
case 'i':
290
i_flag = 1;
291
break;
292
case 'p':
293
print_config_flag = 1;
294
break;
295
case 'q':
296
q_flag = 1;
297
break;
298
case 's':
299
s_flag = 1;
300
break;
301
case 't':
302
t_flag = 1;
303
break;
304
case 'u':
305
u_flag = 1;
306
break;
307
case 'v':
308
v_flag = 1;
309
break;
310
case '1':
311
case '2':
312
case '3':
313
case '4':
314
partition = c - '0';
315
break;
316
default:
317
usage();
318
}
319
if (f_flag || i_flag)
320
u_flag = 1;
321
if (t_flag)
322
v_flag = 1;
323
argc -= optind;
324
argv += optind;
325
326
if (argc == 0) {
327
disk = get_rootdisk();
328
} else {
329
disk = g_device_path(argv[0]);
330
if (disk == NULL)
331
err(1, "unable to get correct path for %s", argv[0]);
332
}
333
if (open_disk(u_flag) < 0)
334
err(1, "cannot open disk %s", disk);
335
336
/* (abu)use mboot.bootinst to probe for the sector size */
337
if ((mboot.bootinst = malloc(MAX_SEC_SIZE)) == NULL)
338
err(1, "cannot allocate buffer to determine disk sector size");
339
if (read_disk(0, mboot.bootinst) == -1)
340
errx(1, "could not detect sector size");
341
free(mboot.bootinst);
342
mboot.bootinst = NULL;
343
344
if (print_config_flag) {
345
if (read_s0())
346
err(1, "read_s0");
347
348
printf("# %s\n", disk);
349
printf("g c%d h%d s%d\n", dos_cyls, dos_heads, dos_sectors);
350
351
for (i = 0; i < NDOSPART; i++) {
352
partp = &mboot.parts[i];
353
354
if (partp->dp_start == 0 && partp->dp_size == 0)
355
continue;
356
357
printf("p %d 0x%02x %lu %lu\n", i + 1, partp->dp_typ,
358
(u_long)partp->dp_start, (u_long)partp->dp_size);
359
360
/* Fill flags for the partition. */
361
if (partp->dp_flag & 0x80)
362
printf("a %d\n", i + 1);
363
}
364
exit(0);
365
}
366
if (s_flag) {
367
if (read_s0())
368
err(1, "read_s0");
369
printf("%s: %d cyl %d hd %d sec\n", disk, dos_cyls, dos_heads,
370
dos_sectors);
371
printf("Part %11s %11s Type Flags\n", "Start", "Size");
372
for (i = 0; i < NDOSPART; i++) {
373
partp = &mboot.parts[i];
374
if (partp->dp_start == 0 && partp->dp_size == 0)
375
continue;
376
printf("%4d: %11lu %11lu 0x%02x 0x%02x\n", i + 1,
377
(u_long) partp->dp_start,
378
(u_long) partp->dp_size, partp->dp_typ,
379
partp->dp_flag);
380
}
381
exit(0);
382
}
383
384
printf("******* Working on device %s *******\n",disk);
385
386
if (I_flag) {
387
if (read_s0())
388
warnx("Ignoring bad existing MBR.");
389
reset_boot();
390
partp = &mboot.parts[0];
391
partp->dp_typ = DOSPTYP_386BSD;
392
partp->dp_flag = ACTIVE;
393
partp->dp_start = dos_sectors;
394
partp->dp_size = rounddown(disksecs, dos_cylsecs) -
395
dos_sectors;
396
dos(partp);
397
if (v_flag)
398
print_s0();
399
if (!t_flag)
400
write_s0();
401
exit(0);
402
}
403
if (f_flag) {
404
if (read_s0() || i_flag)
405
reset_boot();
406
if (!read_config(f_flag))
407
exit(1);
408
if (v_flag)
409
print_s0();
410
if (!t_flag)
411
write_s0();
412
} else {
413
if(u_flag)
414
get_params_to_use();
415
else
416
print_params();
417
418
if (read_s0()) {
419
printf("Will replace existing bad MBR\n");
420
init_sector0(dos_sectors);
421
}
422
423
printf("Media sector size is %d\n", secsize);
424
printf("Warning: BIOS sector numbering starts with sector 1\n");
425
printf("Information from DOS bootblock is:\n");
426
if (partition == -1)
427
for (i = 1; i <= NDOSPART; i++)
428
change_part(i);
429
else
430
change_part(partition);
431
432
if (u_flag || a_flag)
433
change_active(partition);
434
435
if (B_flag)
436
change_code();
437
438
if (u_flag || a_flag || B_flag) {
439
if (!t_flag) {
440
printf("\nWe haven't changed the partition table yet. ");
441
printf("This is your last chance.\n");
442
}
443
print_s0();
444
if (!t_flag) {
445
if (ok("Should we write new partition table?"))
446
write_s0();
447
} else {
448
printf("\n-t flag specified -- partition table not written.\n");
449
}
450
}
451
}
452
453
exit(0);
454
}
455
456
static void
457
usage(void)
458
{
459
fprintf(stderr, "%s%s",
460
"usage: fdisk [-BIaipqstu] [-b bootcode] [-1234] [disk]\n",
461
" fdisk -f configfile [-itv] [disk]\n");
462
exit(1);
463
}
464
465
static void
466
print_s0(void)
467
{
468
int i;
469
470
print_params();
471
printf("Information from DOS bootblock is:\n");
472
for (i = 1; i <= NDOSPART; i++) {
473
printf("%d: ", i);
474
print_part(&mboot.parts[i - 1]);
475
}
476
}
477
478
static struct dos_partition mtpart;
479
480
static void
481
print_part(const struct dos_partition *partp)
482
{
483
u_int64_t part_mb;
484
485
if (!bcmp(partp, &mtpart, sizeof (struct dos_partition))) {
486
printf("<UNUSED>\n");
487
return;
488
}
489
/*
490
* Be careful not to overflow.
491
*/
492
part_mb = partp->dp_size;
493
part_mb *= secsize;
494
part_mb /= (1024 * 1024);
495
printf("sysid %d (%#04x),(%s)\n", partp->dp_typ, partp->dp_typ,
496
get_type(partp->dp_typ));
497
printf(" start %lu, size %lu (%ju Meg), flag %x%s\n",
498
(u_long)partp->dp_start,
499
(u_long)partp->dp_size,
500
(uintmax_t)part_mb,
501
partp->dp_flag,
502
partp->dp_flag == ACTIVE ? " (active)" : "");
503
printf("\tbeg: cyl %d/ head %d/ sector %d;\n\tend: cyl %d/ head %d/ sector %d\n"
504
,DPCYL(partp->dp_scyl, partp->dp_ssect)
505
,partp->dp_shd
506
,DPSECT(partp->dp_ssect)
507
,DPCYL(partp->dp_ecyl, partp->dp_esect)
508
,partp->dp_ehd
509
,DPSECT(partp->dp_esect));
510
}
511
512
513
static void
514
init_boot(void)
515
{
516
const char *fname;
517
int fdesc, n;
518
struct stat sb;
519
520
fname = b_flag ? b_flag : "/boot/mbr";
521
if ((fdesc = open(fname, O_RDONLY)) == -1 ||
522
fstat(fdesc, &sb) == -1)
523
err(1, "%s", fname);
524
if (sb.st_size == 0)
525
errx(1, "%s is empty, must not be.", fname);
526
if ((mboot.bootinst_size = sb.st_size) % secsize != 0)
527
errx(1, "%s: length must be a multiple of sector size", fname);
528
if (mboot.bootinst != NULL)
529
free(mboot.bootinst);
530
if ((mboot.bootinst = malloc(mboot.bootinst_size = sb.st_size)) == NULL)
531
errx(1, "%s: unable to allocate read buffer", fname);
532
if ((n = read(fdesc, mboot.bootinst, mboot.bootinst_size)) == -1 ||
533
close(fdesc))
534
err(1, "%s", fname);
535
if (n != mboot.bootinst_size)
536
errx(1, "%s: short read", fname);
537
}
538
539
540
static void
541
init_sector0(unsigned long start)
542
{
543
struct dos_partition *partp = &mboot.parts[0];
544
545
init_boot();
546
547
partp->dp_typ = DOSPTYP_386BSD;
548
partp->dp_flag = ACTIVE;
549
start = roundup(start, dos_sectors);
550
if(start == 0)
551
start = dos_sectors;
552
partp->dp_start = start;
553
partp->dp_size = rounddown(disksecs, dos_cylsecs) - start;
554
555
dos(partp);
556
}
557
558
static void
559
change_part(int i)
560
{
561
struct dos_partition *partp = &mboot.parts[i - 1];
562
563
printf("The data for partition %d is:\n", i);
564
print_part(partp);
565
566
if (u_flag && ok("Do you want to change it?")) {
567
int tmp;
568
569
if (i_flag) {
570
bzero(partp, sizeof (*partp));
571
if (i == 1) {
572
init_sector0(1);
573
printf("\nThe static data for the slice 1 has been reinitialized to:\n");
574
print_part(partp);
575
}
576
}
577
578
do {
579
Decimal("sysid (165=FreeBSD)", partp->dp_typ, tmp, 255);
580
Decimal("start", partp->dp_start, tmp, NO_DISK_SECTORS);
581
Decimal("size", partp->dp_size, tmp, NO_DISK_SECTORS);
582
if (!sanitize_partition(partp)) {
583
warnx("ERROR: failed to adjust; setting sysid to 0");
584
partp->dp_typ = 0;
585
}
586
587
if (ok("Explicitly specify beg/end address ?"))
588
{
589
int tsec,tcyl,thd;
590
tcyl = DPCYL(partp->dp_scyl,partp->dp_ssect);
591
thd = partp->dp_shd;
592
tsec = DPSECT(partp->dp_ssect);
593
Decimal("beginning cylinder", tcyl, tmp, NO_TRACK_CYLINDERS);
594
Decimal("beginning head", thd, tmp, NO_TRACK_HEADS);
595
Decimal("beginning sector", tsec, tmp, NO_TRACK_SECTORS);
596
partp->dp_scyl = DOSCYL(tcyl);
597
partp->dp_ssect = DOSSECT(tsec,tcyl);
598
partp->dp_shd = thd;
599
600
tcyl = DPCYL(partp->dp_ecyl,partp->dp_esect);
601
thd = partp->dp_ehd;
602
tsec = DPSECT(partp->dp_esect);
603
Decimal("ending cylinder", tcyl, tmp, NO_TRACK_CYLINDERS);
604
Decimal("ending head", thd, tmp, NO_TRACK_HEADS);
605
Decimal("ending sector", tsec, tmp, NO_TRACK_SECTORS);
606
partp->dp_ecyl = DOSCYL(tcyl);
607
partp->dp_esect = DOSSECT(tsec,tcyl);
608
partp->dp_ehd = thd;
609
} else
610
dos(partp);
611
612
print_part(partp);
613
} while (!ok("Are we happy with this entry?"));
614
}
615
}
616
617
static void
618
print_params(void)
619
{
620
printf("parameters extracted from in-core disklabel are:\n");
621
printf("cylinders=%d heads=%d sectors/track=%d (%d blks/cyl)\n\n"
622
,cyls,heads,sectors,cylsecs);
623
if (dos_cyls > 1023 || dos_heads > 255 || dos_sectors > 63)
624
printf("Figures below won't work with BIOS for partitions not in cyl 1\n");
625
printf("parameters to be used for BIOS calculations are:\n");
626
printf("cylinders=%d heads=%d sectors/track=%d (%d blks/cyl)\n\n"
627
,dos_cyls,dos_heads,dos_sectors,dos_cylsecs);
628
}
629
630
static void
631
change_active(int which)
632
{
633
struct dos_partition *partp = &mboot.parts[0];
634
int active, i, new, tmp;
635
636
active = -1;
637
for (i = 0; i < NDOSPART; i++) {
638
if ((partp[i].dp_flag & ACTIVE) == 0)
639
continue;
640
printf("Partition %d is marked active\n", i + 1);
641
if (active == -1)
642
active = i + 1;
643
}
644
if (a_flag && which != -1)
645
active = which;
646
else if (active == -1)
647
active = 1;
648
649
if (!ok("Do you want to change the active partition?"))
650
return;
651
setactive:
652
do {
653
new = active;
654
Decimal("active partition", new, tmp, 0);
655
if (new < 1 || new > 4) {
656
printf("Active partition number must be in range 1-4."
657
" Try again.\n");
658
goto setactive;
659
}
660
active = new;
661
} while (!ok("Are you happy with this choice"));
662
for (i = 0; i < NDOSPART; i++)
663
partp[i].dp_flag = 0;
664
if (active > 0 && active <= NDOSPART)
665
partp[active-1].dp_flag = ACTIVE;
666
}
667
668
static void
669
change_code(void)
670
{
671
if (ok("Do you want to change the boot code?"))
672
init_boot();
673
}
674
675
void
676
get_params_to_use(void)
677
{
678
int tmp;
679
print_params();
680
if (ok("Do you want to change our idea of what BIOS thinks ?"))
681
{
682
do
683
{
684
Decimal("BIOS's idea of #cylinders", dos_cyls, tmp, 0);
685
Decimal("BIOS's idea of #heads", dos_heads, tmp, 0);
686
Decimal("BIOS's idea of #sectors", dos_sectors, tmp, 0);
687
dos_cylsecs = dos_heads * dos_sectors;
688
print_params();
689
}
690
while(!ok("Are you happy with this choice"));
691
}
692
}
693
694
695
/***********************************************\
696
* Change real numbers into strange dos numbers *
697
\***********************************************/
698
static void
699
dos(struct dos_partition *partp)
700
{
701
int cy, sec;
702
u_int32_t end;
703
704
if (partp->dp_typ == 0 && partp->dp_start == 0 && partp->dp_size == 0) {
705
memcpy(partp, &mtpart, sizeof(*partp));
706
return;
707
}
708
709
/* Start c/h/s. */
710
partp->dp_shd = partp->dp_start % dos_cylsecs / dos_sectors;
711
cy = partp->dp_start / dos_cylsecs;
712
sec = partp->dp_start % dos_sectors + 1;
713
partp->dp_scyl = DOSCYL(cy);
714
partp->dp_ssect = DOSSECT(sec, cy);
715
716
/* End c/h/s. */
717
end = partp->dp_start + partp->dp_size - 1;
718
partp->dp_ehd = end % dos_cylsecs / dos_sectors;
719
cy = end / dos_cylsecs;
720
sec = end % dos_sectors + 1;
721
partp->dp_ecyl = DOSCYL(cy);
722
partp->dp_esect = DOSSECT(sec, cy);
723
}
724
725
static int
726
open_disk(int flag)
727
{
728
int rwmode;
729
730
/* Write mode if one of these flags are set. */
731
rwmode = (a_flag || I_flag || B_flag || flag);
732
fd = g_open(disk, rwmode);
733
/* If the mode fails, try read-only if we didn't. */
734
if (fd == -1 && errno == EPERM && rwmode)
735
fd = g_open(disk, 0);
736
if (fd == -1 && errno == ENXIO)
737
return -2;
738
if (fd == -1) {
739
warnx("can't open device %s", disk);
740
return -1;
741
}
742
if (get_params() == -1) {
743
warnx("can't get disk parameters on %s", disk);
744
return -1;
745
}
746
return fd;
747
}
748
749
static ssize_t
750
read_disk(off_t sector, void *buf)
751
{
752
753
lseek(fd, (sector * 512), 0);
754
if (secsize == 0)
755
for (secsize = MIN_SEC_SIZE; secsize <= MAX_SEC_SIZE;
756
secsize *= 2) {
757
/* try the read */
758
int size = read(fd, buf, secsize);
759
if (size == secsize)
760
/* it worked so return */
761
return secsize;
762
}
763
else
764
return read(fd, buf, secsize);
765
766
/* we failed to read at any of the sizes */
767
return -1;
768
}
769
770
static int
771
geom_class_available(const char *name)
772
{
773
struct gclass *class;
774
struct gmesh mesh;
775
int error;
776
777
error = geom_gettree(&mesh);
778
if (error != 0)
779
errc(1, error, "Cannot get GEOM tree");
780
781
LIST_FOREACH(class, &mesh.lg_class, lg_class) {
782
if (strcmp(class->lg_name, name) == 0) {
783
geom_deletetree(&mesh);
784
return (1);
785
}
786
}
787
788
geom_deletetree(&mesh);
789
790
return (0);
791
}
792
793
static int
794
write_disk(off_t sector, void *buf)
795
{
796
ssize_t wr;
797
798
/*
799
* Try to write MBR directly. This may help when disk
800
* is not in use.
801
* XXX: hardcoded sectorsize
802
*/
803
wr = pwrite(fd, buf, secsize, (sector * 512));
804
if (wr == secsize)
805
return (0);
806
807
if (geom_class_available("PART") != 0)
808
warnx("Failed to write MBR. Try to use gpart(8).");
809
else
810
warnx("Failed to write sector zero");
811
return(EINVAL);
812
}
813
814
static int
815
get_params(void)
816
{
817
int error;
818
u_int u;
819
off_t o;
820
821
error = ioctl(fd, DIOCGFWSECTORS, &u);
822
if (error == 0)
823
sectors = dos_sectors = u;
824
else
825
sectors = dos_sectors = 63;
826
827
error = ioctl(fd, DIOCGFWHEADS, &u);
828
if (error == 0)
829
heads = dos_heads = u;
830
else
831
heads = dos_heads = 255;
832
833
dos_cylsecs = cylsecs = heads * sectors;
834
disksecs = cyls * heads * sectors;
835
836
u = g_sectorsize(fd);
837
if (u <= 0)
838
return (-1);
839
840
o = g_mediasize(fd);
841
if (o < 0)
842
return (-1);
843
if (o / u <= NO_DISK_SECTORS)
844
disksecs = o / u;
845
else
846
disksecs = NO_DISK_SECTORS;
847
cyls = dos_cyls = o / (u * dos_heads * dos_sectors);
848
849
return (0);
850
}
851
852
static int
853
read_s0(void)
854
{
855
int i;
856
857
mboot.bootinst_size = secsize;
858
if (mboot.bootinst != NULL)
859
free(mboot.bootinst);
860
if ((mboot.bootinst = malloc(mboot.bootinst_size)) == NULL) {
861
warnx("unable to allocate buffer to read fdisk "
862
"partition table");
863
return -1;
864
}
865
if (read_disk(0, mboot.bootinst) == -1) {
866
warnx("can't read fdisk partition table");
867
return -1;
868
}
869
if (le16dec(&mboot.bootinst[DOSMAGICOFFSET]) != DOSMAGIC) {
870
warnx("invalid fdisk partition table found");
871
/* So should we initialize things */
872
return -1;
873
}
874
for (i = 0; i < NDOSPART; i++)
875
dos_partition_dec(
876
&mboot.bootinst[DOSPARTOFF + i * DOSPARTSIZE],
877
&mboot.parts[i]);
878
return 0;
879
}
880
881
static int
882
write_s0(void)
883
{
884
int sector, i;
885
886
if (iotest) {
887
print_s0();
888
return 0;
889
}
890
for(i = 0; i < NDOSPART; i++)
891
dos_partition_enc(&mboot.bootinst[DOSPARTOFF + i * DOSPARTSIZE],
892
&mboot.parts[i]);
893
le16enc(&mboot.bootinst[DOSMAGICOFFSET], DOSMAGIC);
894
for(sector = 0; sector < mboot.bootinst_size / secsize; sector++)
895
if (write_disk(sector,
896
&mboot.bootinst[sector * secsize]) == -1) {
897
warn("can't write fdisk partition table");
898
return -1;
899
}
900
return(0);
901
}
902
903
904
static int
905
ok(const char *str)
906
{
907
printf("%s [n] ", str);
908
fflush(stdout);
909
if (fgets(lbuf, LBUF, stdin) == NULL)
910
exit(1);
911
lbuf[strlen(lbuf)-1] = 0;
912
913
if (*lbuf &&
914
(!strcmp(lbuf, "yes") || !strcmp(lbuf, "YES") ||
915
!strcmp(lbuf, "y") || !strcmp(lbuf, "Y")))
916
return 1;
917
else
918
return 0;
919
}
920
921
static int
922
decimal(const char *str, int *num, int deflt, uint32_t maxval)
923
{
924
long long acc;
925
int c;
926
char *cp;
927
928
while (1) {
929
acc = 0;
930
printf("Supply a decimal value for \"%s\" [%d] ", str, deflt);
931
fflush(stdout);
932
if (fgets(lbuf, LBUF, stdin) == NULL)
933
exit(1);
934
lbuf[strlen(lbuf)-1] = 0;
935
936
if (!*lbuf)
937
return 0;
938
939
cp = lbuf;
940
while ((c = *cp) && (c == ' ' || c == '\t')) cp++;
941
if (!c)
942
return 0;
943
while ((c = *cp++)) {
944
if (c <= '9' && c >= '0') {
945
if (acc <= maxval || maxval == 0)
946
acc = acc * 10 + c - '0';
947
} else
948
break;
949
}
950
if (c == ' ' || c == '\t')
951
while ((c = *cp) && (c == ' ' || c == '\t')) cp++;
952
if (!c) {
953
if (maxval > 0 && acc > maxval) {
954
acc = maxval;
955
printf("%s exceeds maximum value allowed for "
956
"this field. The value has been reduced "
957
"to %lld\n", lbuf, acc);
958
}
959
*num = acc;
960
return 1;
961
} else
962
printf("%s is an invalid decimal number. Try again.\n",
963
lbuf);
964
}
965
}
966
967
968
static void
969
parse_config_line(char *line, CMD *command)
970
{
971
char *cp, *end;
972
973
cp = line;
974
while (1) {
975
memset(command, 0, sizeof(*command));
976
977
while (isspace(*cp)) ++cp;
978
if (*cp == '\0' || *cp == '#')
979
break;
980
command->cmd = *cp++;
981
982
/*
983
* Parse args
984
*/
985
while (1) {
986
while (isspace(*cp)) ++cp;
987
if (*cp == '\0')
988
break; /* eol */
989
if (*cp == '#')
990
break; /* found comment */
991
if (isalpha(*cp))
992
command->args[command->n_args].argtype = *cp++;
993
end = NULL;
994
command->args[command->n_args].arg_val = strtoul(cp, &end, 0);
995
if (cp == end || (!isspace(*end) && *end != '\0')) {
996
char ch;
997
end = cp;
998
while (!isspace(*end) && *end != '\0') ++end;
999
ch = *end; *end = '\0';
1000
command->args[command->n_args].arg_str = strdup(cp);
1001
*end = ch;
1002
} else
1003
command->args[command->n_args].arg_str = NULL;
1004
cp = end;
1005
command->n_args++;
1006
}
1007
break;
1008
}
1009
}
1010
1011
1012
static int
1013
process_geometry(CMD *command)
1014
{
1015
int status = 1, i;
1016
1017
while (1) {
1018
geom_processed = 1;
1019
if (part_processed) {
1020
warnx(
1021
"ERROR line %d: the geometry specification line must occur before\n\
1022
all partition specifications",
1023
current_line_number);
1024
status = 0;
1025
break;
1026
}
1027
if (command->n_args != 3) {
1028
warnx("ERROR line %d: incorrect number of geometry args",
1029
current_line_number);
1030
status = 0;
1031
break;
1032
}
1033
dos_cyls = 0;
1034
dos_heads = 0;
1035
dos_sectors = 0;
1036
for (i = 0; i < 3; ++i) {
1037
switch (command->args[i].argtype) {
1038
case 'c':
1039
dos_cyls = command->args[i].arg_val;
1040
break;
1041
case 'h':
1042
dos_heads = command->args[i].arg_val;
1043
break;
1044
case 's':
1045
dos_sectors = command->args[i].arg_val;
1046
break;
1047
default:
1048
warnx(
1049
"ERROR line %d: unknown geometry arg type: '%c' (0x%02x)",
1050
current_line_number, command->args[i].argtype,
1051
command->args[i].argtype);
1052
status = 0;
1053
break;
1054
}
1055
}
1056
if (status == 0)
1057
break;
1058
1059
dos_cylsecs = dos_heads * dos_sectors;
1060
1061
/*
1062
* Do sanity checks on parameter values
1063
*/
1064
if (dos_cyls == 0) {
1065
warnx("ERROR line %d: number of cylinders not specified",
1066
current_line_number);
1067
status = 0;
1068
}
1069
if (dos_cyls > 1024) {
1070
warnx(
1071
"WARNING line %d: number of cylinders (%d) may be out-of-range\n\
1072
(must be within 1-1024 for normal BIOS operation, unless the entire disk\n\
1073
is dedicated to FreeBSD)",
1074
current_line_number, dos_cyls);
1075
}
1076
1077
if (dos_heads == 0) {
1078
warnx("ERROR line %d: number of heads not specified",
1079
current_line_number);
1080
status = 0;
1081
} else if (dos_heads > 256) {
1082
warnx("ERROR line %d: number of heads must be within (1-256)",
1083
current_line_number);
1084
status = 0;
1085
}
1086
1087
if (dos_sectors == 0) {
1088
warnx("ERROR line %d: number of sectors not specified",
1089
current_line_number);
1090
status = 0;
1091
} else if (dos_sectors > 63) {
1092
warnx("ERROR line %d: number of sectors must be within (1-63)",
1093
current_line_number);
1094
status = 0;
1095
}
1096
1097
break;
1098
}
1099
return (status);
1100
}
1101
1102
static u_int32_t
1103
str2sectors(const char *str)
1104
{
1105
char *end;
1106
unsigned long val;
1107
1108
val = strtoul(str, &end, 0);
1109
if (str == end || *end == '\0') {
1110
warnx("ERROR line %d: unexpected size: \'%s\'",
1111
current_line_number, str);
1112
return NO_DISK_SECTORS;
1113
}
1114
1115
if (*end == 'K')
1116
val *= 1024UL / secsize;
1117
else if (*end == 'M')
1118
val *= 1024UL * 1024UL / secsize;
1119
else if (*end == 'G')
1120
val *= 1024UL * 1024UL * 1024UL / secsize;
1121
else {
1122
warnx("ERROR line %d: unexpected modifier: %c "
1123
"(not K/M/G)", current_line_number, *end);
1124
return NO_DISK_SECTORS;
1125
}
1126
1127
return val;
1128
}
1129
1130
static int
1131
process_partition(CMD *command)
1132
{
1133
int status = 0, partition;
1134
u_int32_t prev_head_boundary, prev_cyl_boundary;
1135
u_int32_t adj_size, max_end;
1136
struct dos_partition *partp;
1137
1138
while (1) {
1139
part_processed = 1;
1140
if (command->n_args != 4) {
1141
warnx("ERROR line %d: incorrect number of partition args",
1142
current_line_number);
1143
break;
1144
}
1145
partition = command->args[0].arg_val;
1146
if (partition < 1 || partition > 4) {
1147
warnx("ERROR line %d: invalid partition number %d",
1148
current_line_number, partition);
1149
break;
1150
}
1151
partp = &mboot.parts[partition - 1];
1152
bzero(partp, sizeof (*partp));
1153
partp->dp_typ = command->args[1].arg_val;
1154
if (command->args[2].arg_str != NULL) {
1155
if (strcmp(command->args[2].arg_str, "*") == 0) {
1156
int i;
1157
partp->dp_start = dos_sectors;
1158
for (i = 1; i < partition; i++) {
1159
struct dos_partition *prev_partp;
1160
prev_partp = ((struct dos_partition *)
1161
&mboot.parts) + i - 1;
1162
if (prev_partp->dp_typ != 0)
1163
partp->dp_start = prev_partp->dp_start +
1164
prev_partp->dp_size;
1165
}
1166
if (partp->dp_start % dos_sectors != 0) {
1167
prev_head_boundary = rounddown(partp->dp_start,
1168
dos_sectors);
1169
partp->dp_start = prev_head_boundary +
1170
dos_sectors;
1171
}
1172
} else {
1173
partp->dp_start = str2sectors(command->args[2].arg_str);
1174
if (partp->dp_start == NO_DISK_SECTORS)
1175
break;
1176
}
1177
} else
1178
partp->dp_start = command->args[2].arg_val;
1179
1180
if (command->args[3].arg_str != NULL) {
1181
if (strcmp(command->args[3].arg_str, "*") == 0)
1182
partp->dp_size = rounddown(disksecs, dos_cylsecs) -
1183
partp->dp_start;
1184
else {
1185
partp->dp_size = str2sectors(command->args[3].arg_str);
1186
if (partp->dp_size == NO_DISK_SECTORS)
1187
break;
1188
}
1189
prev_cyl_boundary = rounddown(partp->dp_start + partp->dp_size,
1190
dos_cylsecs);
1191
if (prev_cyl_boundary > partp->dp_start)
1192
partp->dp_size = prev_cyl_boundary - partp->dp_start;
1193
} else
1194
partp->dp_size = command->args[3].arg_val;
1195
1196
max_end = partp->dp_start + partp->dp_size;
1197
1198
if (partp->dp_typ == 0) {
1199
/*
1200
* Get out, the partition is marked as unused.
1201
*/
1202
/*
1203
* Insure that it's unused.
1204
*/
1205
bzero(partp, sizeof(*partp));
1206
status = 1;
1207
break;
1208
}
1209
1210
/*
1211
* Adjust start upwards, if necessary, to fall on a head boundary.
1212
*/
1213
if (partp->dp_start % dos_sectors != 0) {
1214
prev_head_boundary = rounddown(partp->dp_start, dos_sectors);
1215
if (max_end < dos_sectors ||
1216
prev_head_boundary > max_end - dos_sectors) {
1217
/*
1218
* Can't go past end of partition
1219
*/
1220
warnx(
1221
"ERROR line %d: unable to adjust start of partition %d to fall on\n\
1222
a head boundary",
1223
current_line_number, partition);
1224
break;
1225
}
1226
warnx(
1227
"WARNING: adjusting start offset of partition %d\n\
1228
from %u to %u, to fall on a head boundary",
1229
partition, (u_int)partp->dp_start,
1230
(u_int)(prev_head_boundary + dos_sectors));
1231
partp->dp_start = prev_head_boundary + dos_sectors;
1232
}
1233
1234
/*
1235
* Adjust size downwards, if necessary, to fall on a cylinder
1236
* boundary.
1237
*/
1238
prev_cyl_boundary = rounddown(partp->dp_start + partp->dp_size,
1239
dos_cylsecs);
1240
if (prev_cyl_boundary > partp->dp_start)
1241
adj_size = prev_cyl_boundary - partp->dp_start;
1242
else {
1243
warnx(
1244
"ERROR: could not adjust partition to start on a head boundary\n\
1245
and end on a cylinder boundary.");
1246
return (0);
1247
}
1248
if (adj_size != partp->dp_size) {
1249
warnx(
1250
"WARNING: adjusting size of partition %d from %u to %u\n\
1251
to end on a cylinder boundary",
1252
partition, (u_int)partp->dp_size, (u_int)adj_size);
1253
partp->dp_size = adj_size;
1254
}
1255
if (partp->dp_size == 0) {
1256
warnx("ERROR line %d: size of partition %d is zero",
1257
current_line_number, partition);
1258
break;
1259
}
1260
1261
dos(partp);
1262
status = 1;
1263
break;
1264
}
1265
return (status);
1266
}
1267
1268
1269
static int
1270
process_active(CMD *command)
1271
{
1272
int status = 0, partition, i;
1273
struct dos_partition *partp;
1274
1275
while (1) {
1276
active_processed = 1;
1277
if (command->n_args != 1) {
1278
warnx("ERROR line %d: incorrect number of active args",
1279
current_line_number);
1280
status = 0;
1281
break;
1282
}
1283
partition = command->args[0].arg_val;
1284
if (partition < 1 || partition > 4) {
1285
warnx("ERROR line %d: invalid partition number %d",
1286
current_line_number, partition);
1287
break;
1288
}
1289
/*
1290
* Reset active partition
1291
*/
1292
partp = mboot.parts;
1293
for (i = 0; i < NDOSPART; i++)
1294
partp[i].dp_flag = 0;
1295
partp[partition-1].dp_flag = ACTIVE;
1296
1297
status = 1;
1298
break;
1299
}
1300
return (status);
1301
}
1302
1303
1304
static int
1305
process_line(char *line)
1306
{
1307
CMD command;
1308
int status = 1;
1309
1310
while (1) {
1311
parse_config_line(line, &command);
1312
switch (command.cmd) {
1313
case 0:
1314
/*
1315
* Comment or blank line
1316
*/
1317
break;
1318
case 'g':
1319
/*
1320
* Set geometry
1321
*/
1322
status = process_geometry(&command);
1323
break;
1324
case 'p':
1325
status = process_partition(&command);
1326
break;
1327
case 'a':
1328
status = process_active(&command);
1329
break;
1330
default:
1331
status = 0;
1332
break;
1333
}
1334
break;
1335
}
1336
return (status);
1337
}
1338
1339
1340
static int
1341
read_config(char *config_file)
1342
{
1343
FILE *fp = NULL;
1344
int status = 1;
1345
char buf[1010];
1346
1347
while (1) {
1348
if (strcmp(config_file, "-") != 0) {
1349
/*
1350
* We're not reading from stdin
1351
*/
1352
if ((fp = fopen(config_file, "r")) == NULL) {
1353
status = 0;
1354
break;
1355
}
1356
} else {
1357
fp = stdin;
1358
}
1359
current_line_number = 0;
1360
while (!feof(fp)) {
1361
if (fgets(buf, sizeof(buf), fp) == NULL)
1362
break;
1363
++current_line_number;
1364
status = process_line(buf);
1365
if (status == 0)
1366
break;
1367
}
1368
break;
1369
}
1370
if (fp) {
1371
/*
1372
* It doesn't matter if we're reading from stdin, as we've reached EOF
1373
*/
1374
fclose(fp);
1375
}
1376
return (status);
1377
}
1378
1379
1380
static void
1381
reset_boot(void)
1382
{
1383
int i;
1384
struct dos_partition *partp;
1385
1386
init_boot();
1387
for (i = 0; i < 4; ++i) {
1388
partp = &mboot.parts[i];
1389
bzero(partp, sizeof(*partp));
1390
}
1391
}
1392
1393
static int
1394
sanitize_partition(struct dos_partition *partp)
1395
{
1396
u_int32_t prev_head_boundary, prev_cyl_boundary;
1397
u_int32_t max_end, size, start;
1398
1399
start = partp->dp_start;
1400
size = partp->dp_size;
1401
max_end = start + size;
1402
/* Only allow a zero size if the partition is being marked unused. */
1403
if (size == 0) {
1404
if (start == 0 && partp->dp_typ == 0)
1405
return (1);
1406
warnx("ERROR: size of partition is zero");
1407
return (0);
1408
}
1409
/* Return if no adjustment is necessary. */
1410
if (start % dos_sectors == 0 && (start + size) % dos_sectors == 0)
1411
return (1);
1412
1413
if (start == 0) {
1414
warnx("WARNING: partition overlaps with partition table");
1415
if (ok("Correct this automatically?"))
1416
start = dos_sectors;
1417
}
1418
if (start % dos_sectors != 0)
1419
warnx("WARNING: partition does not start on a head boundary");
1420
if ((start +size) % dos_sectors != 0)
1421
warnx("WARNING: partition does not end on a cylinder boundary");
1422
warnx("WARNING: this may confuse the BIOS or some operating systems");
1423
if (!ok("Correct this automatically?"))
1424
return (1);
1425
1426
/*
1427
* Adjust start upwards, if necessary, to fall on a head boundary.
1428
*/
1429
if (start % dos_sectors != 0) {
1430
prev_head_boundary = rounddown(start, dos_sectors);
1431
if (max_end < dos_sectors ||
1432
prev_head_boundary >= max_end - dos_sectors) {
1433
/*
1434
* Can't go past end of partition
1435
*/
1436
warnx(
1437
"ERROR: unable to adjust start of partition to fall on a head boundary");
1438
return (0);
1439
}
1440
start = prev_head_boundary + dos_sectors;
1441
}
1442
1443
/*
1444
* Adjust size downwards, if necessary, to fall on a cylinder
1445
* boundary.
1446
*/
1447
prev_cyl_boundary = rounddown(start + size, dos_cylsecs);
1448
if (prev_cyl_boundary > start)
1449
size = prev_cyl_boundary - start;
1450
else {
1451
warnx("ERROR: could not adjust partition to start on a head boundary\n\
1452
and end on a cylinder boundary.");
1453
return (0);
1454
}
1455
1456
/* Finally, commit any changes to partp and return. */
1457
if (start != partp->dp_start) {
1458
warnx("WARNING: adjusting start offset of partition to %u",
1459
(u_int)start);
1460
partp->dp_start = start;
1461
}
1462
if (size != partp->dp_size) {
1463
warnx("WARNING: adjusting size of partition to %u", (u_int)size);
1464
partp->dp_size = size;
1465
}
1466
1467
return (1);
1468
}
1469
1470
/*
1471
* Try figuring out the root device's canonical disk name.
1472
* The following choices are considered:
1473
* /dev/ad0s1a => /dev/ad0
1474
* /dev/da0a => /dev/da0
1475
* A ".eli" part is removed if it exists (see geli(8)).
1476
* A ".journal" ending is removed if it exists (see gjournal(8)).
1477
*/
1478
static char *
1479
get_rootdisk(void)
1480
{
1481
struct statfs rootfs;
1482
regex_t re;
1483
#define NMATCHES 2
1484
regmatch_t rm[NMATCHES];
1485
char dev[PATH_MAX], *s;
1486
int rv;
1487
1488
if (statfs("/", &rootfs) == -1)
1489
err(1, "statfs(\"/\")");
1490
1491
if ((rv = regcomp(&re, "^(/dev/[a-z/]+[0-9]+)([sp][0-9]+)?[a-h]?(\\.journal)?$",
1492
REG_EXTENDED)) != 0)
1493
errx(1, "regcomp() failed (%d)", rv);
1494
strlcpy(dev, rootfs.f_mntfromname, sizeof (dev));
1495
if ((s = strstr(dev, ".eli")) != NULL)
1496
memmove(s, s+4, strlen(s + 4) + 1);
1497
1498
if ((rv = regexec(&re, dev, NMATCHES, rm, 0)) != 0)
1499
errx(1,
1500
"mounted root fs resource doesn't match expectations (regexec returned %d)",
1501
rv);
1502
if ((s = malloc(rm[1].rm_eo - rm[1].rm_so + 1)) == NULL)
1503
errx(1, "out of memory");
1504
memcpy(s, rootfs.f_mntfromname + rm[1].rm_so,
1505
rm[1].rm_eo - rm[1].rm_so);
1506
s[rm[1].rm_eo - rm[1].rm_so] = 0;
1507
1508
return s;
1509
}
1510
1511