xref: /openbsd/sbin/fdisk/user.c (revision 5f7fe693)
1 /*	$OpenBSD: user.c,v 1.85 2023/03/04 21:22:51 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_valid;
37 	int	(*cmd_fcn)(const char *, struct mbr *);
38 	char	*cmd_help;
39 };
40 
41 const struct cmd		cmd_table[] = {
42 	{"help",   2, Xhelp,   "Display summary of available commands"},
43 	{"manual", 2, Xmanual, "Display fdisk man page"},
44 	{"reinit", 2, Xreinit, "Initialize the partition table"},
45 	{"setpid", 1, Xsetpid, "Set identifier of table entry"},
46 	{"edit",   1, Xedit,   "Edit table entry"},
47 	{"flag",   1, Xflag,   "Set flag value of table entry"},
48 	{"update", 0, Xupdate, "Update MBR bootcode"},
49 	{"select", 0, Xselect, "Select MBR extended table entry"},
50 	{"swap",   1, Xswap,   "Swap two table entries"},
51 	{"print",  2, Xprint,  "Print partition table"},
52 	{"write",  1, Xwrite,  "Write partition table to disk"},
53 	{"exit",   1, Xexit,   "Discard changes and exit edit level"},
54 	{"quit",   1, Xquit,   "Save changes and exit edit level"},
55 	{"abort",  2, Xabort,  "Discard changes and terminate fdisk"},
56 };
57 
58 #define	ANY_CMD(_i)	(cmd_table[(_i)].cmd_valid > 1)
59 #define	GPT_CMD(_i)	(cmd_table[(_i)].cmd_valid > 0)
60 
61 int			modified;
62 
63 int			ask_cmd(const struct mbr *, char **);
64 
65 void
USER_edit(const uint64_t lba_self,const uint64_t lba_firstembr)66 USER_edit(const uint64_t lba_self, const uint64_t lba_firstembr)
67 {
68 	struct mbr		 mbr;
69 	char			*args;
70 	int			 i, st;
71 	static int		 editlevel;
72 
73 	if (MBR_read(lba_self, lba_firstembr, &mbr))
74 		return;
75 
76 	editlevel += 1;
77 
78 	if (editlevel == 1)
79 		GPT_read(ANYGPT);
80 
81 	printf("Enter 'help' for information\n");
82 
83 	for (;;) {
84 		if (gh.gh_sig == GPTSIGNATURE && editlevel > 1)
85 			break;	/* 'reinit gpt'. Unwind recursion! */
86 
87 		printf("%s%s: %d> ", disk.dk_name, modified ? "*" : "",
88 		    editlevel);
89 		fflush(stdout);
90 		i = ask_cmd(&mbr, &args);
91 		if (i == -1)
92 			continue;
93 
94 		st = cmd_table[i].cmd_fcn(args ? args : "", &mbr);
95 
96 		if (st == CMD_EXIT) {
97 			if (modified)
98 				printf("Aborting changes to current MBR\n");
99 			break;
100 		}
101 		if (st == CMD_QUIT) {
102 			if (modified && Xwrite(NULL, &mbr) == CMD_CONT)
103 				continue;
104 			break;
105 		}
106 		if (st == CMD_CLEAN)
107 			modified = 0;
108 		if (st == CMD_DIRTY)
109 			modified = 1;
110 	}
111 
112 	editlevel -= 1;
113 }
114 
115 void
USER_print_disk(const int verbosity)116 USER_print_disk(const int verbosity)
117 {
118 	struct mbr		mbr;
119 	uint64_t		lba_self, lba_firstembr;
120 	unsigned int		i;
121 
122 	lba_self = lba_firstembr = 0;
123 
124 	do {
125 		if (MBR_read(lba_self, lba_firstembr, &mbr))
126 			break;
127 		if (lba_self == DOSBBSECTOR) {
128 			if (MBR_valid_prt(&mbr) == 0) {
129 				DISK_printgeometry("s");
130 				printf("Offset: %d\tSignature: 0x%X.\t"
131 				    "No MBR or GPT.\n", DOSBBSECTOR,
132 				    (int)mbr.mbr_signature);
133 				return;
134 			}
135 			if (GPT_read(ANYGPT)) {
136 				if (verbosity == VERBOSE) {
137 					printf("Primary GPT:\nNot Found\n");
138 					printf("\nSecondary GPT:\nNot Found\n");
139 				}
140 			} else if (verbosity == TERSE) {
141 				GPT_print("s", verbosity);
142 				return;
143 			} else {
144 				printf("Primary GPT:\n");
145 				GPT_read(PRIMARYGPT);
146 				if (gh.gh_sig == GPTSIGNATURE)
147 					GPT_print("s", verbosity);
148 				else
149 					printf("\tNot Found\n");
150 				printf("\nSecondary GPT:\n");
151 				GPT_read(SECONDARYGPT);
152 				if (gh.gh_sig == GPTSIGNATURE)
153 					GPT_print("s", verbosity);
154 				else
155 					printf("\tNot Found\n");
156 			}
157 			if (verbosity == VERBOSE)
158 				printf("\nMBR:\n");
159 		}
160 
161 		MBR_print(&mbr, "s");
162 
163 		for (lba_self = i = 0; i < nitems(mbr.mbr_prt); i++)
164 			if (mbr.mbr_prt[i].prt_id == DOSPTYP_EXTEND ||
165 			    mbr.mbr_prt[i].prt_id == DOSPTYP_EXTENDL) {
166 				lba_self = mbr.mbr_prt[i].prt_bs;
167 				if (lba_firstembr == 0)
168 					lba_firstembr = lba_self;
169 			}
170 	} while (lba_self);
171 }
172 
173 void
USER_help(const struct mbr * mbr)174 USER_help(const struct mbr *mbr)
175 {
176 	unsigned int		i;
177 
178 	for (i = 0; i < nitems(cmd_table); i++) {
179 		if (gh.gh_sig == GPTSIGNATURE && GPT_CMD(i) == 0)
180 				continue;
181 		if (MBR_valid_prt(mbr) == 0 && ANY_CMD(i) == 0)
182 			continue;
183 		printf("\t%s\t\t%s\n", cmd_table[i].cmd_name,
184 		    cmd_table[i].cmd_help);
185 	}
186 }
187 
188 int
ask_cmd(const struct mbr * mbr,char ** arg)189 ask_cmd(const struct mbr *mbr, char **arg)
190 {
191 	static char		 lbuf[LINEBUFSZ];
192 	char			*cmd;
193 	unsigned int		 i;
194 
195 	string_from_line(lbuf, sizeof(lbuf), TRIMMED);
196 
197 	*arg = lbuf;
198 	cmd = strsep(arg, WHITESPACE);
199 
200 	if (*arg != NULL)
201 		*arg += strspn(*arg, WHITESPACE);
202 
203 	if (strlen(cmd) == 0)
204 		return -1;
205 	if (strcmp(cmd, "?") == 0)
206 		cmd = "help";
207 
208 	for (i = 0; i < nitems(cmd_table); i++) {
209 		if (gh.gh_sig == GPTSIGNATURE && GPT_CMD(i) == 0)
210 			continue;
211 		if (MBR_valid_prt(mbr) == 0 && ANY_CMD(i) == 0)
212 			continue;
213 		if (strstr(cmd_table[i].cmd_name, cmd) == cmd_table[i].cmd_name)
214 			return i;
215 	}
216 
217 	printf("Invalid command '%s", cmd);
218 	if (*arg && strlen(*arg) > 0)
219 		printf(" %s", *arg);
220 	printf("'. Try 'help'.\n");
221 
222 	return -1;
223 }
224