xref: /openbsd-src/sbin/fdisk/user.c (revision f1dd7b858388b4a23f4f67a4957ec5ff656ebbe8)
1 /*	$OpenBSD: user.c,v 1.55 2021/05/15 15:20:17 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 <fcntl.h>
24 #include <stdio.h>
25 #include <string.h>
26 #include <unistd.h>
27 
28 #include "part.h"
29 #include "mbr.h"
30 #include "misc.h"
31 #include "cmd.h"
32 #include "user.h"
33 #include "gpt.h"
34 #include "disk.h"
35 
36 /* Our command table */
37 struct cmd cmd_table[] = {
38 	{"help",   1, Xhelp,   "Command help list"},
39 	{"manual", 1, Xmanual, "Show entire OpenBSD man page for fdisk"},
40 	{"reinit", 1, Xreinit, "Re-initialize loaded MBR (to defaults)"},
41 	{"setpid", 1, Xsetpid, "Set the identifier of a given table entry"},
42 	{"disk",   0, Xdisk,   "Edit current drive stats"},
43 	{"edit",   1, Xedit,   "Edit given table entry"},
44 	{"flag",   1, Xflag,   "Flag given table entry as bootable"},
45 	{"update", 0, Xupdate, "Update machine code in loaded MBR"},
46 	{"select", 0, Xselect, "Select extended partition table entry MBR"},
47 	{"swap",   1, Xswap,   "Swap two partition entries"},
48 	{"print",  1, Xprint,  "Print loaded MBR partition table"},
49 	{"write",  1, Xwrite,  "Write loaded MBR to disk"},
50 	{"exit",   1, Xexit,   "Exit edit of current MBR, without saving changes"},
51 	{"quit",   1, Xquit,   "Quit edit of current MBR, saving current changes"},
52 	{"abort",  1, Xabort,  "Abort program without saving current changes"},
53 	{NULL,     0, NULL,    NULL}
54 };
55 
56 
57 int modified;
58 
59 void
60 USER_edit(off_t offset, off_t reloff)
61 {
62 	static int editlevel;
63 	struct dos_mbr dos_mbr;
64 	struct mbr mbr;
65 	char *cmd, *args;
66 	int i, st, efi, error;
67 
68 	/* One level deeper */
69 	editlevel += 1;
70 
71 	/* Read MBR & partition */
72 	error = MBR_read(offset, &dos_mbr);
73 	if (error == -1)
74 		goto done;
75 
76 	/* Parse the sucker */
77 	MBR_parse(&dos_mbr, offset, reloff, &mbr);
78 
79 	if (editlevel == 1) {
80 		memset(&gh, 0, sizeof(gh));
81 		memset(&gp, 0, sizeof(gp));
82 		efi = MBR_protective_mbr(&mbr);
83 		if (efi != -1)
84 			GPT_read(ANYGPT);
85 	}
86 
87 	printf("Enter 'help' for information\n");
88 
89 	/* Edit cycle */
90 again:
91 	do {
92 		printf("%s%s: %d> ", disk.name, modified ? "*" : "", editlevel);
93 		fflush(stdout);
94 		ask_cmd(&cmd, &args);
95 
96 		if (cmd[0] == '\0')
97 			continue;
98 		for (i = 0; cmd_table[i].cmd != NULL; i++)
99 			if (strstr(cmd_table[i].cmd, cmd) == cmd_table[i].cmd)
100 				break;
101 
102 		/* Quick hack to put in '?' == 'help' */
103 		if (!strcmp(cmd, "?"))
104 			i = 0;
105 
106 		/* Check for valid command */
107 		if ((cmd_table[i].cmd == NULL) || (letoh64(gh.gh_sig) ==
108 		    GPTSIGNATURE && cmd_table[i].gpt == 0)) {
109 			printf("Invalid command '%s'.  Try 'help'.\n", cmd);
110 			continue;
111 		}
112 
113 		/* Call function */
114 		st = cmd_table[i].fcn(args, &mbr);
115 
116 		/* Update status */
117 		if (st == CMD_EXIT)
118 			break;
119 		if (st == CMD_SAVE)
120 			break;
121 		if (st == CMD_CLEAN)
122 			modified = 0;
123 		if (st == CMD_DIRTY)
124 			modified = 1;
125 	} while (1);
126 
127 	/* Write out MBR */
128 	if (modified) {
129 		if (st == CMD_SAVE) {
130 			if (Xwrite(NULL, &mbr) == CMD_CONT)
131 				goto again;
132 		} else
133 			printf("Aborting changes to current MBR.\n");
134 	}
135 
136 done:
137 	/* One level less */
138 	editlevel -= 1;
139 }
140 
141 void
142 USER_print_disk(int verbosity)
143 {
144 	off_t offset, firstoff;
145 	int i, efi, error;
146 	struct dos_mbr dos_mbr;
147 	struct mbr mbr;
148 
149 	offset = firstoff = 0;
150 
151 	do {
152 		error = MBR_read(offset, &dos_mbr);
153 		if (error == -1)
154 			break;
155 		MBR_parse(&dos_mbr, offset, firstoff, &mbr);
156 		if (offset == 0) {
157 			efi = MBR_protective_mbr(&mbr);
158 			if (efi == -1) {
159 				/* No valid 0xEE partition means no GPT. */
160 				if (verbosity == VERBOSE) {
161 					printf("Primary GPT:\nNot Found\n");
162 					printf("\nSecondary GPT:\nNot Found\n");
163 				}
164 			} else if (verbosity == TERSE) {
165 				/* Should already have read one of Primary/Secondary GPT. */
166 				if (letoh64(gh.gh_sig) == GPTSIGNATURE) {
167 					GPT_print("s", verbosity);
168 					return;
169 				}
170 			} else {
171 				/*. Read & print both primary and secondary GPT. */
172 				printf("Primary GPT:\n");
173 				GPT_read(PRIMARYGPT);
174 				if (letoh64(gh.gh_sig) == GPTSIGNATURE)
175 					GPT_print("s", verbosity);
176 				else
177 					printf("\tNot Found\n");
178 				printf("\nSecondary GPT:\n");
179 				GPT_read(SECONDARYGPT);
180 				if (letoh64(gh.gh_sig) == GPTSIGNATURE)
181 					GPT_print("s", verbosity);
182 				else
183 					printf("\tNot Found\n");
184 			}
185 			if (verbosity == VERBOSE)
186 				printf("\nMBR:\n");
187 		}
188 
189 		MBR_print(&mbr, NULL);
190 
191 		/* Print out extended partitions too */
192 		for (offset = i = 0; i < 4; i++)
193 			if (mbr.part[i].id == DOSPTYP_EXTEND ||
194 			    mbr.part[i].id == DOSPTYP_EXTENDL) {
195 				offset = (off_t)mbr.part[i].bs;
196 				if (firstoff == 0)
197 					firstoff = offset;
198 			}
199 	} while (offset);
200 }
201