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 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 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 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 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