GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: sbin/fdisk/cmd.c Lines: 0 272 0.0 %
Date: 2017-11-07 Branches: 0 132 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: cmd.c,v 1.97 2016/09/03 17:46:19 krw Exp $	*/
2
3
/*
4
 * Copyright (c) 1997 Tobias Weingartner
5
 *
6
 * Permission to use, copy, modify, and distribute this software for any
7
 * purpose with or without fee is hereby granted, provided that the above
8
 * copyright notice and this permission notice appear in all copies.
9
 *
10
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17
 */
18
19
#include <sys/types.h>
20
#include <sys/disklabel.h>
21
22
#include <err.h>
23
#include <signal.h>
24
#include <stdint.h>
25
#include <stdio.h>
26
#include <stdlib.h>
27
#include <string.h>
28
#include <uuid.h>
29
30
#include "disk.h"
31
#include "misc.h"
32
#include "part.h"
33
#include "mbr.h"
34
#include "gpt.h"
35
#include "user.h"
36
#include "cmd.h"
37
38
int reinited;
39
40
/* Some helper functions for GPT handling. */
41
int Xgedit(char *);
42
int Xgsetpid(char *);
43
44
int
45
Xreinit(char *args, struct mbr *mbr)
46
{
47
	struct dos_mbr dos_mbr;
48
	int dogpt;
49
50
	if (strncasecmp(args, "gpt", 3) == 0)
51
		dogpt = 1;
52
	else if (strncasecmp(args, "mbr", 3) == 0)
53
		dogpt = 0;
54
	else if (strlen(args) > 0) {
55
		printf("Unrecognized modifier '%s'\n", args);
56
		return (CMD_CONT);
57
	} else if (MBR_protective_mbr(mbr) == 0)
58
		dogpt = 1;
59
	else
60
		dogpt = 0;
61
62
	MBR_make(&initial_mbr, &dos_mbr);
63
	MBR_parse(&dos_mbr, mbr->offset, mbr->reloffset, mbr);
64
65
	if (dogpt) {
66
		MBR_init_GPT(mbr);
67
		GPT_init();
68
		GPT_print("s", 0);
69
	} else {
70
		MBR_init(mbr);
71
		MBR_print(mbr, "s");
72
	}
73
	reinited = 1;
74
75
	printf("Use 'write' to update disk.\n");
76
77
	return (CMD_DIRTY);
78
}
79
80
int
81
Xdisk(char *args, struct mbr *mbr)
82
{
83
	int maxcyl  = 1024;
84
	int maxhead = 256;
85
	int maxsec  = 63;
86
87
	/* Print out disk info */
88
	DISK_printgeometry(args);
89
90
#if defined (__powerpc__) || defined (__mips__)
91
	maxcyl  = 9999999;
92
	maxhead = 9999999;
93
	maxsec  = 9999999;
94
#endif
95
96
	/* Ask for new info */
97
	if (ask_yn("Change disk geometry?")) {
98
		disk.cylinders = ask_num("BIOS Cylinders",
99
		    disk.cylinders, 1, maxcyl);
100
		disk.heads = ask_num("BIOS Heads",
101
		    disk.heads, 1, maxhead);
102
		disk.sectors = ask_num("BIOS Sectors",
103
		    disk.sectors, 1, maxsec);
104
105
		disk.size = disk.cylinders * disk.heads * disk.sectors;
106
	}
107
108
	return (CMD_CONT);
109
}
110
111
int
112
Xswap(char *args, struct mbr *mbr)
113
{
114
	const char *errstr;
115
	char *from, *to;
116
	int pf, pt, maxpn;
117
	struct prt pp;
118
	struct gpt_partition gg;
119
120
	to = args;
121
	from = strsep(&to, " \t");
122
123
	if (to == NULL) {
124
		printf("partition number is invalid:\n");
125
		return (CMD_CONT);
126
	}
127
128
	if (letoh64(gh.gh_sig) == GPTSIGNATURE)
129
		maxpn = NGPTPARTITIONS - 1;
130
	else
131
		maxpn = NDOSPART - 1;
132
133
	pf = strtonum(from, 0, maxpn, &errstr);
134
	if (errstr) {
135
		printf("partition number is %s: %s\n", errstr, from);
136
		return (CMD_CONT);
137
	}
138
	pt = strtonum(to, 0, maxpn, &errstr);
139
	if (errstr) {
140
		printf("partition number is %s: %s\n", errstr, to);
141
		return (CMD_CONT);
142
	}
143
144
	if (pt == pf) {
145
		printf("%d same partition as %d, doing nothing.\n", pt, pf);
146
		return (CMD_CONT);
147
	}
148
149
	if (letoh64(gh.gh_sig) == GPTSIGNATURE) {
150
		gg = gp[pt];
151
		gp[pt] = gp[pf];
152
		gp[pf] = gg;
153
	} else {
154
		pp = mbr->part[pt];
155
		mbr->part[pt] = mbr->part[pf];
156
		mbr->part[pf] = pp;
157
	}
158
159
	return (CMD_DIRTY);
160
}
161
162
int
163
Xgedit(char *args)
164
{
165
	struct gpt_partition oldpart;
166
	const char *errstr;
167
	struct gpt_partition *gg;
168
	char *name;
169
	u_int16_t *utf;
170
	u_int64_t bs, ns;
171
	int i, pn;
172
173
	pn = strtonum(args, 0, NGPTPARTITIONS - 1, &errstr);
174
	if (errstr) {
175
		printf("partition number is %s: %s\n", errstr, args);
176
		return (CMD_CONT);
177
	}
178
	gg = &gp[pn];
179
	oldpart = *gg;
180
181
	Xgsetpid(args);
182
	if (uuid_is_nil(&gg->gp_type, NULL)) {
183
		if (uuid_is_nil(&oldpart.gp_type, NULL) == 0) {
184
			memset(gg, 0, sizeof(struct gpt_partition));
185
			printf("Partition %d is disabled.\n", pn);
186
		}
187
		goto done;
188
	}
189
190
	bs = getuint64("Partition offset", letoh64(gg->gp_lba_start),
191
	    letoh64(gh.gh_lba_start), letoh64(gh.gh_lba_end));
192
	ns = getuint64("Partition size", letoh64(gg->gp_lba_end) - bs + 1,
193
	    1, letoh64(gh.gh_lba_end) - bs + 1);
194
195
	gg->gp_lba_start = htole64(bs);
196
	gg->gp_lba_end = htole64(bs + ns - 1);
197
198
	name = ask_string("Partition name", utf16le_to_string(gg->gp_name));
199
	if (strlen(name) >= GPTPARTNAMESIZE) {
200
		printf("partition name must be < %d characters\n",
201
		    GPTPARTNAMESIZE);
202
		goto done;
203
	}
204
	/*
205
	 * N.B.: simple memcpy() could copy trash from static buf! This
206
	 * would create false positives for the partition having changed.
207
	 */
208
	utf = string_to_utf16le(name);
209
	for (i = 0; i < GPTPARTNAMESIZE; i++) {
210
		gg->gp_name[i] = utf[i];
211
		if (utf[i] == 0)
212
			break;
213
	}
214
215
done:
216
	if (memcmp(gg, &oldpart, sizeof(*gg)))
217
		return (CMD_DIRTY);
218
	else
219
		return (CMD_CONT);
220
}
221
222
int
223
Xedit(char *args, struct mbr *mbr)
224
{
225
	struct prt oldpart;
226
	const char *errstr;
227
	struct prt *pp;
228
	int pn;
229
230
	if (letoh64(gh.gh_sig) == GPTSIGNATURE)
231
		return (Xgedit(args));
232
233
	pn = strtonum(args, 0, 3, &errstr);
234
	if (errstr) {
235
		printf("partition number is %s: %s\n", errstr, args);
236
		return (CMD_CONT);
237
	}
238
	pp = &mbr->part[pn];
239
	oldpart = *pp;
240
241
	Xsetpid(args, mbr);
242
	if (pp->id == DOSPTYP_UNUSED) {
243
		if (oldpart.id != DOSPTYP_UNUSED) {
244
			memset(pp, 0, sizeof(*pp));
245
			printf("Partition %d is disabled.\n", pn);
246
		}
247
		goto done;
248
	}
249
250
	if (ask_yn("Do you wish to edit in CHS mode?")) {
251
		pp->scyl = ask_num("BIOS Starting cylinder", pp->scyl,  0,
252
		    disk.cylinders - 1);
253
		pp->shead = ask_num("BIOS Starting head",    pp->shead, 0,
254
		    disk.heads - 1);
255
		pp->ssect = ask_num("BIOS Starting sector",  pp->ssect, 1,
256
		    disk.sectors);
257
258
		pp->ecyl = ask_num("BIOS Ending cylinder",   pp->ecyl,
259
		    pp->scyl, disk.cylinders - 1);
260
		pp->ehead = ask_num("BIOS Ending head",      pp->ehead,
261
		    (pp->scyl == pp->ecyl) ? pp->shead : 0, disk.heads - 1);
262
		pp->esect = ask_num("BIOS Ending sector",    pp->esect,
263
		    (pp->scyl == pp->ecyl && pp->shead == pp->ehead) ? pp->ssect
264
		    : 1, disk.sectors);
265
266
		/* Fix up off/size values */
267
		PRT_fix_BN(pp, pn);
268
		/* Fix up CHS values for LBA */
269
		PRT_fix_CHS(pp);
270
	} else {
271
		pp->bs = getuint64("Partition offset", pp->bs, 0, disk.size);
272
		pp->ns = getuint64("Partition size",   pp->ns, 1,
273
		    disk.size - pp->bs);
274
275
		/* Fix up CHS values */
276
		PRT_fix_CHS(pp);
277
	}
278
279
done:
280
	if (memcmp(pp, &oldpart, sizeof(*pp)))
281
		return (CMD_DIRTY);
282
	else
283
		return (CMD_CONT);
284
}
285
286
int
287
Xgsetpid(char *args)
288
{
289
	const char *errstr;
290
	struct uuid guid;
291
	struct gpt_partition *gg;
292
	int pn, num, status;
293
294
	pn = strtonum(args, 0, NGPTPARTITIONS - 1, &errstr);
295
	if (errstr) {
296
		printf("partition number is %s: %s\n", errstr, args);
297
		return (CMD_CONT);
298
	}
299
	gg = &gp[pn];
300
301
	/* Print out current table entry */
302
	GPT_print_parthdr(0);
303
	GPT_print_part(pn, "s", 0);
304
305
	/* Ask for partition type or GUID. */
306
	uuid_dec_le(&gg->gp_type, &guid);
307
	num = ask_pid(PRT_uuid_to_type(&guid), &guid);
308
	if (num <= 0xff)
309
		guid = *(PRT_type_to_uuid(num));
310
	uuid_enc_le(&gg->gp_type, &guid);
311
312
	if (uuid_is_nil(&gg->gp_guid, NULL)) {
313
		uuid_create(&guid, &status);
314
		if (status != uuid_s_ok) {
315
			printf("could not create guid for partition\n");
316
			return (CMD_CONT);
317
		}
318
		uuid_enc_le(&gg->gp_guid, &guid);
319
	}
320
321
	return (CMD_DIRTY);
322
}
323
324
int
325
Xsetpid(char *args, struct mbr *mbr)
326
{
327
	const char *errstr;
328
	int pn, num;
329
	struct prt *pp;
330
331
	if (letoh64(gh.gh_sig) == GPTSIGNATURE)
332
		return (Xgsetpid(args));
333
334
	pn = strtonum(args, 0, 3, &errstr);
335
	if (errstr) {
336
		printf("partition number is %s: %s\n", errstr, args);
337
		return (CMD_CONT);
338
	}
339
	pp = &mbr->part[pn];
340
341
	/* Print out current table entry */
342
	PRT_print(0, NULL, NULL);
343
	PRT_print(pn, pp, NULL);
344
345
	/* Ask for MBR partition type */
346
	num = ask_pid(pp->id, NULL);
347
	if (num == pp->id)
348
		return (CMD_CONT);
349
350
	pp->id = num;
351
352
	return (CMD_DIRTY);
353
}
354
355
int
356
Xselect(char *args, struct mbr *mbr)
357
{
358
	const char *errstr;
359
	static off_t firstoff = 0;
360
	off_t off;
361
	int pn;
362
363
	pn = strtonum(args, 0, 3, &errstr);
364
	if (errstr) {
365
		printf("partition number is %s: %s\n", errstr, args);
366
		return (CMD_CONT);
367
	}
368
369
	off = mbr->part[pn].bs;
370
371
	/* Sanity checks */
372
	if ((mbr->part[pn].id != DOSPTYP_EXTEND) &&
373
	    (mbr->part[pn].id != DOSPTYP_EXTENDL)) {
374
		printf("Partition %d is not an extended partition.\n", pn);
375
		return (CMD_CONT);
376
	}
377
378
	if (firstoff == 0)
379
		firstoff = off;
380
381
	if (!off) {
382
		printf("Loop to offset 0!  Not selected.\n");
383
		return (CMD_CONT);
384
	} else {
385
		printf("Selected extended partition %d\n", pn);
386
		printf("New MBR at offset %lld.\n", (long long)off);
387
	}
388
389
	/* Recursion is beautiful! */
390
	USER_edit(off, firstoff);
391
392
	return (CMD_CONT);
393
}
394
395
int
396
Xprint(char *args, struct mbr *mbr)
397
{
398
399
	if (MBR_protective_mbr(mbr) == 0 && letoh64(gh.gh_sig) == GPTSIGNATURE)
400
		GPT_print(args, 1);
401
	else
402
		MBR_print(mbr, args);
403
404
	return (CMD_CONT);
405
}
406
407
int
408
Xwrite(char *args, struct mbr *mbr)
409
{
410
	struct dos_mbr dos_mbr;
411
	int i, n;
412
413
	for (i = 0, n = 0; i < NDOSPART; i++)
414
		if (mbr->part[i].id == 0xA6)
415
			n++;
416
	if (n >= 2) {
417
		warnx("MBR contains more than one OpenBSD partition!");
418
		if (!ask_yn("Write MBR anyway?"))
419
			return (CMD_CONT);
420
	}
421
422
	MBR_make(mbr, &dos_mbr);
423
424
	printf("Writing MBR at offset %lld.\n", (long long)mbr->offset);
425
	if (MBR_write(mbr->offset, &dos_mbr) == -1) {
426
		warn("error writing MBR");
427
		return (CMD_CONT);
428
	}
429
430
	if (letoh64(gh.gh_sig) == GPTSIGNATURE) {
431
		printf("Writing GPT.\n");
432
		if (GPT_write() == -1) {
433
			warn("error writing GPT");
434
			return (CMD_CONT);
435
		}
436
	} else if (reinited) {
437
		/* Make sure GPT doesn't get in the way. */
438
		MBR_zapgpt(&dos_mbr, DL_GETDSIZE(&dl) - 1);
439
	}
440
441
	/* Refresh in memory copy to reflect what was just written. */
442
	MBR_parse(&dos_mbr, mbr->offset, mbr->reloffset, mbr);
443
444
	return (CMD_CLEAN);
445
}
446
447
int
448
Xquit(char *args, struct mbr *mbr)
449
{
450
	return (CMD_SAVE);
451
}
452
453
int
454
Xabort(char *args, struct mbr *mbr)
455
{
456
	exit(0);
457
}
458
459
int
460
Xexit(char *args, struct mbr *mbr)
461
{
462
	return (CMD_EXIT);
463
}
464
465
int
466
Xhelp(char *args, struct mbr *mbr)
467
{
468
	char help[80];
469
	char *mbrstr;
470
	int i;
471
472
	for (i = 0; cmd_table[i].cmd != NULL; i++) {
473
		strlcpy(help, cmd_table[i].help, sizeof(help));
474
		if (letoh64(gh.gh_sig) == GPTSIGNATURE) {
475
			if (cmd_table[i].gpt == 0)
476
				continue;
477
			mbrstr = strstr(help, "MBR");
478
			if (mbrstr)
479
				memcpy(mbrstr, "GPT", 3);
480
		}
481
		printf("\t%s\t\t%s\n", cmd_table[i].cmd, help);
482
	}
483
484
	return (CMD_CONT);
485
}
486
487
int
488
Xupdate(char *args, struct mbr *mbr)
489
{
490
	/* Update code */
491
	memcpy(mbr->code, initial_mbr.code, sizeof(mbr->code));
492
	mbr->signature = DOSMBR_SIGNATURE;
493
	printf("Machine code updated.\n");
494
	return (CMD_DIRTY);
495
}
496
497
int
498
Xflag(char *args, struct mbr *mbr)
499
{
500
	const char *errstr;
501
	int i, maxpn, pn = -1;
502
	long long val = -1;
503
	char *part, *flag;
504
505
	flag = args;
506
	part = strsep(&flag, " \t");
507
508
	if (letoh64(gh.gh_sig) == GPTSIGNATURE)
509
		maxpn = NGPTPARTITIONS - 1;
510
	else
511
		maxpn = NDOSPART - 1;
512
513
	pn = strtonum(part, 0, maxpn, &errstr);
514
	if (errstr) {
515
		printf("partition number is %s: %s.\n", errstr, part);
516
		return (CMD_CONT);
517
	}
518
519
	if (flag != NULL) {
520
		/* Set flag to value provided. */
521
		if (letoh64(gh.gh_sig) == GPTSIGNATURE)
522
			val = strtonum(flag, 0, INT64_MAX, &errstr);
523
		else
524
			val = strtonum(flag, 0, 0xff, &errstr);
525
		if (errstr) {
526
			printf("flag value is %s: %s.\n", errstr, flag);
527
			return (CMD_CONT);
528
		}
529
		if (letoh64(gh.gh_sig) == GPTSIGNATURE)
530
			gp[pn].gp_attrs = htole64(val);
531
		else
532
			mbr->part[pn].flag = val;
533
		printf("Partition %d flag value set to 0x%llx.\n", pn, val);
534
	} else {
535
		/* Set active flag */
536
		if (letoh64(gh.gh_sig) == GPTSIGNATURE) {
537
			for (i = 0; i < NGPTPARTITIONS; i++) {
538
				if (i == pn)
539
					gp[i].gp_attrs = htole64(GPTDOSACTIVE);
540
				else
541
					gp[i].gp_attrs = htole64(0);
542
			}
543
		} else {
544
			for (i = 0; i < NDOSPART; i++) {
545
				if (i == pn)
546
					mbr->part[i].flag = DOSACTIVE;
547
				else
548
					mbr->part[i].flag = 0x00;
549
			}
550
		}
551
		printf("Partition %d marked active.\n", pn);
552
	}
553
554
	return (CMD_DIRTY);
555
}
556
557
int
558
Xmanual(char *args, struct mbr *mbr)
559
{
560
	char *pager = "/usr/bin/less";
561
	char *p;
562
	sig_t opipe;
563
	extern const unsigned char manpage[];
564
	extern const int manpage_sz;
565
	FILE *f;
566
567
	opipe = signal(SIGPIPE, SIG_IGN);
568
	if ((p = getenv("PAGER")) != NULL && (*p != '\0'))
569
		pager = p;
570
	if (asprintf(&p, "gunzip -qc|%s", pager) != -1) {
571
		f = popen(p, "w");
572
		if (f) {
573
			fwrite(manpage, manpage_sz, 1, f);
574
			pclose(f);
575
		}
576
		free(p);
577
	}
578
579
	signal(SIGPIPE, opipe);
580
581
	return (CMD_CONT);
582
}