1 /* $OpenBSD: fdisk.c,v 1.107 2021/05/14 15:31:01 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 <paths.h> 25 #include <stdint.h> 26 #include <stdio.h> 27 #include <stdlib.h> 28 #include <string.h> 29 #include <unistd.h> 30 31 #include "disk.h" 32 #include "part.h" 33 #include "mbr.h" 34 #include "misc.h" 35 #include "cmd.h" 36 #include "user.h" 37 #include "gpt.h" 38 39 #define _PATH_MBR _PATH_BOOTDIR "mbr" 40 static unsigned char builtin_mbr[] = { 41 #include "mbrcode.h" 42 }; 43 44 uint32_t b_arg; 45 int y_flag; 46 47 static void 48 usage(void) 49 { 50 extern char * __progname; 51 52 fprintf(stderr, "usage: %s " 53 "[-egvy] [-i|-u] [-b #] [-c # -h # -s #] " 54 "[-f mbrfile] [-l # ] disk\n" 55 "\t-b: specify special boot partition block count; requires -i\n" 56 "\t-chs: specify disk geometry; all three must be specified\n" 57 "\t-e: interactively edit MBR or GPT\n" 58 "\t-f: specify non-standard MBR template\n" 59 "\t-g: initialize disk with GPT; requires -i\n" 60 "\t-i: initialize disk with MBR unless -g is also specified\n" 61 "\t-l: specify LBA block count; cannot be used with -chs\n" 62 "\t-u: update MBR code; preserve partition table\n" 63 "\t-v: print the MBR, the Primary GPT and the Secondary GPT\n" 64 "\t-y: do not ask questions\n" 65 "`disk' may be of the forms: sd0 or /dev/rsd0c.\n", 66 __progname); 67 exit(1); 68 } 69 70 int 71 main(int argc, char *argv[]) 72 { 73 ssize_t len; 74 int ch, fd, efi, error; 75 int e_flag = 0, g_flag = 0, i_flag = 0, u_flag = 0; 76 int verbosity = TERSE; 77 int c_arg = 0, h_arg = 0, s_arg = 0; 78 uint32_t l_arg = 0; 79 char *query; 80 #ifdef HAS_MBR 81 char *mbrfile = _PATH_MBR; 82 #else 83 char *mbrfile = NULL; 84 #endif 85 struct dos_mbr dos_mbr; 86 struct mbr mbr; 87 88 while ((ch = getopt(argc, argv, "iegpuvf:c:h:s:l:b:y")) != -1) { 89 const char *errstr; 90 91 switch(ch) { 92 case 'i': 93 i_flag = 1; 94 break; 95 case 'u': 96 u_flag = 1; 97 break; 98 case 'e': 99 e_flag = 1; 100 break; 101 case 'f': 102 mbrfile = optarg; 103 break; 104 case 'c': 105 c_arg = strtonum(optarg, 1, 262144, &errstr); 106 if (errstr) 107 errx(1, "Cylinder argument %s [1..262144].", 108 errstr); 109 disk.cylinders = c_arg; 110 disk.size = c_arg * h_arg * s_arg; 111 break; 112 case 'h': 113 h_arg = strtonum(optarg, 1, 256, &errstr); 114 if (errstr) 115 errx(1, "Head argument %s [1..256].", errstr); 116 disk.heads = h_arg; 117 disk.size = c_arg * h_arg * s_arg; 118 break; 119 case 's': 120 s_arg = strtonum(optarg, 1, 63, &errstr); 121 if (errstr) 122 errx(1, "Sector argument %s [1..63].", errstr); 123 disk.sectors = s_arg; 124 disk.size = c_arg * h_arg * s_arg; 125 break; 126 case 'g': 127 g_flag = 1; 128 break; 129 case 'b': 130 b_arg = strtonum(optarg, 64, UINT32_MAX, &errstr); 131 if (errstr) 132 errx(1, "Block argument %s [64..%u].", errstr, 133 UINT32_MAX); 134 break; 135 case 'l': 136 l_arg = strtonum(optarg, 64, UINT32_MAX, &errstr); 137 if (errstr) 138 errx(1, "Block argument %s [64..%u].", errstr, 139 UINT32_MAX); 140 disk.cylinders = l_arg / 64; 141 disk.heads = 1; 142 disk.sectors = 64; 143 disk.size = l_arg; 144 break; 145 case 'y': 146 y_flag = 1; 147 break; 148 case 'v': 149 verbosity = VERBOSE; 150 break; 151 default: 152 usage(); 153 } 154 } 155 argc -= optind; 156 argv += optind; 157 158 /* Argument checking */ 159 if (argc != 1 || (i_flag && u_flag) || 160 (i_flag == 0 && (b_arg || g_flag)) || 161 ((c_arg | h_arg | s_arg) && !(c_arg && h_arg && s_arg)) || 162 ((c_arg | h_arg | s_arg) && l_arg)) 163 usage(); 164 165 disk.name = argv[0]; 166 DISK_open(i_flag || u_flag || e_flag); 167 168 /* "proc exec" for man page display */ 169 if (pledge("stdio rpath wpath disklabel proc exec", NULL) == -1) 170 err(1, "pledge"); 171 172 error = MBR_read(0, &dos_mbr); 173 if (error) 174 errx(1, "Can't read sector 0!"); 175 MBR_parse(&dos_mbr, 0, 0, &mbr); 176 177 /* Get the GPT if present. Either primary or secondary is ok. */ 178 efi = MBR_protective_mbr(&mbr); 179 if (efi != -1) 180 GPT_read(ANYGPT); 181 182 if (!(i_flag || u_flag || e_flag)) { 183 if (pledge("stdio", NULL) == -1) 184 err(1, "pledge"); 185 USER_print_disk(verbosity); 186 goto done; 187 } 188 189 /* Create initial/default MBR. */ 190 if (mbrfile == NULL) { 191 memcpy(&dos_mbr, builtin_mbr, sizeof(dos_mbr)); 192 } else { 193 fd = open(mbrfile, O_RDONLY); 194 if (fd == -1) { 195 warn("%s", mbrfile); 196 warnx("using builtin MBR"); 197 memcpy(&dos_mbr, builtin_mbr, sizeof(dos_mbr)); 198 } else { 199 len = read(fd, &dos_mbr, sizeof(dos_mbr)); 200 close(fd); 201 if (len == -1) 202 err(1, "Unable to read MBR from '%s'", mbrfile); 203 else if (len != sizeof(dos_mbr)) 204 errx(1, "Unable to read complete MBR from '%s'", 205 mbrfile); 206 } 207 } 208 MBR_parse(&dos_mbr, 0, 0, &initial_mbr); 209 210 query = NULL; 211 if (i_flag) { 212 reinited = 1; 213 if (g_flag) { 214 MBR_init_GPT(&initial_mbr); 215 GPT_init(); 216 query = "Do you wish to write new GPT?"; 217 } else { 218 memset(&gh, 0, sizeof(gh)); 219 MBR_init(&initial_mbr); 220 query = "Do you wish to write new MBR and " 221 "partition table?"; 222 } 223 } else if (u_flag) { 224 memcpy(initial_mbr.part, mbr.part, sizeof(initial_mbr.part)); 225 query = "Do you wish to write new MBR?"; 226 } 227 if (query && ask_yn(query)) 228 Xwrite(NULL, &initial_mbr); 229 230 if (e_flag) 231 USER_edit(0, 0); 232 233 done: 234 close(disk.fd); 235 236 return (0); 237 } 238