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