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