xref: /openbsd-src/sbin/fdisk/user.c (revision 24bb5fcea3ed904bc467217bdaadb5dfc618d5bf)
1 /*	$OpenBSD: user.c,v 1.67 2021/07/21 12:22:54 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 const struct cmd		cmd_table[] = {
37 	{"help",   1, Xhelp,   "Command help list"},
38 	{"manual", 1, Xmanual, "Show entire OpenBSD man page for fdisk"},
39 	{"reinit", 1, Xreinit, "Re-initialize loaded MBR (to defaults)"},
40 	{"setpid", 1, Xsetpid, "Set the identifier of a given table entry"},
41 	{"disk",   0, Xdisk,   "Edit current drive stats"},
42 	{"edit",   1, Xedit,   "Edit given table entry"},
43 	{"flag",   1, Xflag,   "Flag given table entry as bootable"},
44 	{"update", 0, Xupdate, "Update machine code in loaded MBR"},
45 	{"select", 0, Xselect, "Select extended partition table entry MBR"},
46 	{"swap",   1, Xswap,   "Swap two partition entries"},
47 	{"print",  1, Xprint,  "Print loaded MBR partition table"},
48 	{"write",  1, Xwrite,  "Write loaded MBR to disk"},
49 	{"exit",   1, Xexit,   "Exit edit of current MBR, without saving changes"},
50 	{"quit",   1, Xquit,   "Quit edit of current MBR, saving current changes"},
51 	{"abort",  1, Xabort,  "Abort program without saving current changes"},
52 	{NULL,     0, NULL,    NULL}
53 };
54 
55 
56 int			modified;
57 
58 void			ask_cmd(char **, char **);
59 
60 void
61 USER_edit(const uint64_t lba_self, const uint64_t lba_firstembr)
62 {
63 	struct mbr		 mbr;
64 	char			*cmd, *args;
65 	int			 i, st, error;
66 	static int		 editlevel;
67 
68 	/* One level deeper */
69 	editlevel += 1;
70 
71 	error = MBR_read(lba_self, lba_firstembr, &mbr);
72 	if (error == -1)
73 		goto done;
74 
75 	if (editlevel == 1)
76 		GPT_read(ANYGPT);
77 
78 	printf("Enter 'help' for information\n");
79 
80 again:
81 	do {
82 		printf("%s%s: %d> ", disk.dk_name, modified ? "*" : "", editlevel);
83 		fflush(stdout);
84 		ask_cmd(&cmd, &args);
85 
86 		if (cmd[0] == '\0')
87 			continue;
88 		for (i = 0; cmd_table[i].cmd_name != NULL; i++)
89 			if (strstr(cmd_table[i].cmd_name, cmd) == cmd_table[i].cmd_name)
90 				break;
91 
92 		/* Quick hack to put in '?' == 'help' */
93 		if (!strcmp(cmd, "?"))
94 			i = 0;
95 
96 		if ((cmd_table[i].cmd_name == NULL) || (letoh64(gh.gh_sig) ==
97 		    GPTSIGNATURE && cmd_table[i].cmd_gpt == 0)) {
98 			printf("Invalid command '%s'.  Try 'help'.\n", cmd);
99 			continue;
100 		}
101 
102 		st = cmd_table[i].cmd_fcn(args, &mbr);
103 
104 		/* Update status */
105 		if (st == CMD_EXIT)
106 			break;
107 		if (st == CMD_SAVE)
108 			break;
109 		if (st == CMD_CLEAN)
110 			modified = 0;
111 		if (st == CMD_DIRTY)
112 			modified = 1;
113 	} while (1);
114 
115 	if (modified) {
116 		if (st == CMD_SAVE) {
117 			if (Xwrite(NULL, &mbr) == CMD_CONT)
118 				goto again;
119 		} else
120 			printf("Aborting changes to current MBR.\n");
121 	}
122 
123 done:
124 	editlevel -= 1;
125 }
126 
127 void
128 USER_print_disk(const int verbosity)
129 {
130 	struct mbr		mbr;
131 	uint64_t		lba_self, lba_firstembr;
132 	int			i, error;
133 
134 	lba_self = lba_firstembr = 0;
135 
136 	do {
137 		error = MBR_read(lba_self, lba_firstembr, &mbr);
138 		if (error == -1)
139 			break;
140 		if (lba_self == 0) {
141 			if (GPT_read(ANYGPT)) {
142 				if (verbosity == VERBOSE) {
143 					printf("Primary GPT:\nNot Found\n");
144 					printf("\nSecondary GPT:\nNot Found\n");
145 				}
146 			} else if (verbosity == TERSE) {
147 				GPT_print("s", verbosity);
148 				return;
149 			} else {
150 				printf("Primary GPT:\n");
151 				GPT_read(PRIMARYGPT);
152 				if (letoh64(gh.gh_sig) == GPTSIGNATURE)
153 					GPT_print("s", verbosity);
154 				else
155 					printf("\tNot Found\n");
156 				printf("\nSecondary GPT:\n");
157 				GPT_read(SECONDARYGPT);
158 				if (letoh64(gh.gh_sig) == GPTSIGNATURE)
159 					GPT_print("s", verbosity);
160 				else
161 					printf("\tNot Found\n");
162 			}
163 			if (verbosity == VERBOSE)
164 				printf("\nMBR:\n");
165 		}
166 
167 		MBR_print(&mbr, NULL);
168 
169 		for (lba_self = i = 0; i < 4; i++)
170 			if (mbr.mbr_prt[i].prt_id == DOSPTYP_EXTEND ||
171 			    mbr.mbr_prt[i].prt_id == DOSPTYP_EXTENDL) {
172 				lba_self = mbr.mbr_prt[i].prt_bs;
173 				if (lba_firstembr == 0)
174 					lba_firstembr = lba_self;
175 			}
176 	} while (lba_self);
177 }
178 
179 void
180 ask_cmd(char **cmd, char **arg)
181 {
182 	static char		lbuf[100];
183 	size_t			cmdstart, cmdend, argstart;
184 
185 	if (string_from_line(lbuf, sizeof(lbuf)))
186 		errx(1, "eof");
187 
188 	cmdstart = strspn(lbuf, " \t");
189 	cmdend = cmdstart + strcspn(&lbuf[cmdstart], " \t");
190 	argstart = cmdend + strspn(&lbuf[cmdend], " \t");
191 
192 	/* *cmd and *arg may be set to point at final NUL! */
193 	*cmd = &lbuf[cmdstart];
194 	lbuf[cmdend] = '\0';
195 	*arg = &lbuf[argstart];
196 }
197