xref: /openbsd-src/sbin/fdisk/user.c (revision 824adb5411e4389b29bae28eba5c2c2bbd147f34)
1 /*	$OpenBSD: user.c,v 1.78 2021/09/10 15:26:36 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 <stdio.h>
24 #include <string.h>
25 
26 #include "part.h"
27 #include "mbr.h"
28 #include "misc.h"
29 #include "cmd.h"
30 #include "user.h"
31 #include "gpt.h"
32 #include "disk.h"
33 
34 struct cmd {
35 	char	*cmd_name;
36 	int	 cmd_gpt;
37 	int	(*cmd_fcn)(char *, struct mbr *);
38 	char	*cmd_help;
39 };
40 
41 const struct cmd		cmd_table[] = {
42 	{"help",   1, Xhelp,   "Command help list"},
43 	{"manual", 1, Xmanual, "Show entire OpenBSD man page for fdisk"},
44 	{"reinit", 1, Xreinit, "Re-initialize loaded MBR (to defaults)"},
45 	{"setpid", 1, Xsetpid, "Set the identifier of a given table entry"},
46 	{"disk",   0, Xdisk,   "Edit current drive stats"},
47 	{"edit",   1, Xedit,   "Edit given table entry"},
48 	{"flag",   1, Xflag,   "Flag given table entry as bootable"},
49 	{"update", 0, Xupdate, "Update machine code in loaded MBR"},
50 	{"select", 0, Xselect, "Select extended partition table entry MBR"},
51 	{"swap",   1, Xswap,   "Swap two partition entries"},
52 	{"print",  1, Xprint,  "Print loaded MBR partition table"},
53 	{"write",  1, Xwrite,  "Write loaded MBR to disk"},
54 	{"exit",   1, Xexit,   "Exit edit of current MBR, without saving changes"},
55 	{"quit",   1, Xquit,   "Quit edit of current MBR, saving current changes"},
56 	{"abort",  1, Xabort,  "Abort program without saving current changes"},
57 };
58 
59 int			modified;
60 
61 int			ask_cmd(const int, char **);
62 
63 void
64 USER_edit(const uint64_t lba_self, const uint64_t lba_firstembr)
65 {
66 	struct mbr		 mbr;
67 	char			*args;
68 	int			 i, st;
69 	static int		 editlevel;
70 
71 	if (MBR_read(lba_self, lba_firstembr, &mbr))
72 		return;
73 
74 	editlevel += 1;
75 
76 	if (editlevel == 1)
77 		GPT_read(ANYGPT);
78 
79 	printf("Enter 'help' for information\n");
80 
81 	for (;;) {
82 		if (letoh64(gh.gh_sig) == GPTSIGNATURE && editlevel > 1)
83 			break;	/* 'reinit gpt'. Unwind recursion! */
84 
85 		i = ask_cmd(editlevel, &args);
86 		if (i == -1)
87 			continue;
88 
89 		st = cmd_table[i].cmd_fcn(args ? args : "", &mbr);
90 
91 		if (st == CMD_EXIT) {
92 			if (modified)
93 				printf("Aborting changes to current MBR\n");
94 			break;
95 		}
96 		if (st == CMD_QUIT) {
97 			if (modified && Xwrite(NULL, &mbr) == CMD_CONT)
98 				continue;
99 			break;
100 		}
101 		if (st == CMD_CLEAN)
102 			modified = 0;
103 		if (st == CMD_DIRTY)
104 			modified = 1;
105 	}
106 
107 	editlevel -= 1;
108 }
109 
110 void
111 USER_print_disk(const int verbosity)
112 {
113 	struct mbr		mbr;
114 	uint64_t		lba_self, lba_firstembr;
115 	int			i;
116 
117 	lba_self = lba_firstembr = 0;
118 
119 	do {
120 		if (MBR_read(lba_self, lba_firstembr, &mbr))
121 			break;
122 		if (lba_self == 0) {
123 			if (GPT_read(ANYGPT)) {
124 				if (verbosity == VERBOSE) {
125 					printf("Primary GPT:\nNot Found\n");
126 					printf("\nSecondary GPT:\nNot Found\n");
127 				}
128 			} else if (verbosity == TERSE) {
129 				GPT_print("s", verbosity);
130 				return;
131 			} else {
132 				printf("Primary GPT:\n");
133 				GPT_read(PRIMARYGPT);
134 				if (letoh64(gh.gh_sig) == GPTSIGNATURE)
135 					GPT_print("s", verbosity);
136 				else
137 					printf("\tNot Found\n");
138 				printf("\nSecondary GPT:\n");
139 				GPT_read(SECONDARYGPT);
140 				if (letoh64(gh.gh_sig) == GPTSIGNATURE)
141 					GPT_print("s", verbosity);
142 				else
143 					printf("\tNot Found\n");
144 			}
145 			if (verbosity == VERBOSE)
146 				printf("\nMBR:\n");
147 		}
148 
149 		MBR_print(&mbr, "s");
150 
151 		for (lba_self = i = 0; i < 4; i++)
152 			if (mbr.mbr_prt[i].prt_id == DOSPTYP_EXTEND ||
153 			    mbr.mbr_prt[i].prt_id == DOSPTYP_EXTENDL) {
154 				lba_self = mbr.mbr_prt[i].prt_bs;
155 				if (lba_firstembr == 0)
156 					lba_firstembr = lba_self;
157 			}
158 	} while (lba_self);
159 }
160 
161 void
162 USER_help(void)
163 {
164 	char			 help[80];
165 	char			*mbrstr;
166 	int			 i;
167 
168 	for (i = 0; i < nitems(cmd_table); i++) {
169 		strlcpy(help, cmd_table[i].cmd_help, sizeof(help));
170 		if (letoh64(gh.gh_sig) == GPTSIGNATURE) {
171 			if (cmd_table[i].cmd_gpt == 0)
172 				continue;
173 			mbrstr = strstr(help, "MBR");
174 			if (mbrstr)
175 				memcpy(mbrstr, "GPT", 3);
176 		}
177 		printf("\t%s\t\t%s\n", cmd_table[i].cmd_name, help);
178 	}
179 }
180 
181 int
182 ask_cmd(const int editlevel, char **arg)
183 {
184 	static char		 lbuf[100];
185 	char			*cmd;
186 	unsigned int		 i, gpt;
187 
188 	printf("%s%s: %d> ", disk.dk_name, modified ? "*" : "", editlevel);
189 	fflush(stdout);
190 	string_from_line(lbuf, sizeof(lbuf), TRIMMED);
191 
192 	*arg = lbuf;
193 	cmd = strsep(arg, WHITESPACE);
194 
195 	if (*arg != NULL)
196 		*arg += strspn(*arg, WHITESPACE);
197 
198 	if (strlen(cmd) == 0)
199 		return -1;
200 	if (strcmp(cmd, "?") == 0)
201 		cmd = "help";
202 
203 	gpt = letoh64(gh.gh_sig) == GPTSIGNATURE;
204 	for (i = 0; i < nitems(cmd_table); i++) {
205 		if (gpt && cmd_table[i].cmd_gpt == 0)
206 			continue;
207 		if (strstr(cmd_table[i].cmd_name, cmd) == cmd_table[i].cmd_name)
208 			return i;
209 	}
210 
211 	printf("Invalid command '%s", cmd);
212 	if (*arg && strlen(*arg) > 0)
213 		printf(" %s", *arg);
214 	printf("'. Try 'help'.\n");
215 
216 	return -1;
217 }
218