1 /* $OpenBSD: fdisk.c,v 1.140 2021/10/19 19:38:10 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 <ctype.h> 23 #include <err.h> 24 #include <fcntl.h> 25 #include <paths.h> 26 #include <stdint.h> 27 #include <stdio.h> 28 #include <stdlib.h> 29 #include <string.h> 30 #include <unistd.h> 31 32 #include "part.h" 33 #include "disk.h" 34 #include "mbr.h" 35 #include "cmd.h" 36 #include "misc.h" 37 #include "user.h" 38 #include "gpt.h" 39 40 #define INIT_GPT 1 41 #define INIT_GPTPARTITIONS 2 42 #define INIT_MBR 3 43 #define INIT_MBRBOOTCODE 4 44 45 #define _PATH_MBR _PATH_BOOTDIR "mbr" 46 47 int y_flag; 48 49 void parse_bootprt(const char *); 50 void get_default_dmbr(const char *); 51 52 static void 53 usage(void) 54 { 55 extern char * __progname; 56 57 fprintf(stderr, "usage: %s " 58 "[-evy] [-A | -g | -i | -u] [-b blocks[@offset[:type]]]\n" 59 "\t[-l blocks | -c cylinders -h heads -s sectors] [-f mbrfile] disk\n", 60 __progname); 61 exit(1); 62 } 63 64 int 65 main(int argc, char *argv[]) 66 { 67 struct mbr mbr; 68 const char *mbrfile = NULL; 69 const char *errstr; 70 int ch; 71 int e_flag = 0, init = 0; 72 int verbosity = TERSE; 73 int oflags = O_RDONLY; 74 75 while ((ch = getopt(argc, argv, "Ab:c:ef:gh:il:s:uvy")) != -1) { 76 switch(ch) { 77 case 'A': 78 init = INIT_GPTPARTITIONS; 79 break; 80 case 'b': 81 parse_bootprt(optarg); 82 break; 83 case 'c': 84 disk.dk_cylinders = strtonum(optarg, 1, 262144, &errstr); 85 if (errstr) 86 errx(1, "Cylinder argument %s [1..262144].", 87 errstr); 88 disk.dk_size = 0; 89 break; 90 case 'e': 91 e_flag = 1; 92 break; 93 case 'f': 94 mbrfile = optarg; 95 break; 96 case 'g': 97 init = INIT_GPT; 98 break; 99 case 'h': 100 disk.dk_heads = strtonum(optarg, 1, 256, &errstr); 101 if (errstr) 102 errx(1, "Head argument %s [1..256].", errstr); 103 disk.dk_size = 0; 104 break; 105 case 'i': 106 init = INIT_MBR; 107 break; 108 case 'l': 109 disk.dk_size = strtonum(optarg, BLOCKALIGNMENT, UINT32_MAX, &errstr); 110 if (errstr) 111 errx(1, "Block argument %s [%u..%u].", errstr, 112 BLOCKALIGNMENT, UINT32_MAX); 113 disk.dk_cylinders = disk.dk_heads = disk.dk_sectors = 0; 114 break; 115 case 's': 116 disk.dk_sectors = strtonum(optarg, 1, 63, &errstr); 117 if (errstr) 118 errx(1, "Sector argument %s [1..63].", errstr); 119 disk.dk_size = 0; 120 break; 121 case 'u': 122 init = INIT_MBRBOOTCODE; 123 break; 124 case 'v': 125 verbosity = VERBOSE; 126 break; 127 case 'y': 128 y_flag = 1; 129 break; 130 default: 131 usage(); 132 } 133 } 134 argc -= optind; 135 argv += optind; 136 137 if (argc != 1) 138 usage(); 139 140 if ((disk.dk_cylinders || disk.dk_heads || disk.dk_sectors) && 141 (disk.dk_cylinders * disk.dk_heads * disk.dk_sectors == 0)) 142 usage(); 143 144 if (init || e_flag) 145 oflags = O_RDWR; 146 147 get_default_dmbr(mbrfile); 148 149 DISK_open(argv[0], oflags); 150 if (oflags == O_RDONLY) { 151 if (pledge("stdio", NULL) == -1) 152 err(1, "pledge"); 153 USER_print_disk(verbosity); 154 goto done; 155 } 156 157 /* 158 * "stdio" to talk to the outside world. 159 * "proc exec" for man page display. 160 * "disklabel" for DIOCRLDINFO. 161 */ 162 if (pledge("stdio disklabel proc exec", NULL) == -1) 163 err(1, "pledge"); 164 165 switch (init) { 166 case INIT_GPT: 167 GPT_init(GHANDGP); 168 if (ask_yn("Do you wish to write new GPT?")) 169 Xwrite(NULL, &gmbr); 170 break; 171 case INIT_GPTPARTITIONS: 172 if (GPT_read(ANYGPT)) 173 errx(1, "-A requires a valid GPT"); 174 GPT_init(GPONLY); 175 if (ask_yn("Do you wish to write new GPT?")) 176 Xwrite(NULL, &gmbr); 177 break; 178 case INIT_MBR: 179 mbr.mbr_lba_self = mbr.mbr_lba_firstembr = 0; 180 MBR_init(&mbr); 181 if (ask_yn("Do you wish to write new MBR?")) 182 Xwrite(NULL, &mbr); 183 break; 184 case INIT_MBRBOOTCODE: 185 if (MBR_read(0, 0, &mbr)) 186 errx(1, "Can't read MBR!"); 187 memcpy(mbr.mbr_code, default_dmbr.dmbr_boot, 188 sizeof(mbr.mbr_code)); 189 if (ask_yn("Do you wish to write new MBR?")) 190 Xwrite(NULL, &mbr); 191 break; 192 default: 193 break; 194 } 195 196 if (e_flag) 197 USER_edit(0, 0); 198 199 done: 200 close(disk.dk_fd); 201 202 return 0; 203 } 204 205 void 206 parse_bootprt(const char *arg) 207 { 208 const char *errstr; 209 char *poffset, *ptype; 210 int partitiontype; 211 uint32_t blockcount, blockoffset; 212 213 blockoffset = BLOCKALIGNMENT; 214 partitiontype = DOSPTYP_EFISYS; 215 ptype = NULL; 216 217 /* First number: # of 512-byte blocks in boot partition. */ 218 poffset = strchr(arg, '@'); 219 if (poffset != NULL) 220 *poffset++ = '\0'; 221 if (poffset != NULL) { 222 ptype = strchr(poffset, ':'); 223 if (ptype != NULL) 224 *ptype++ = '\0'; 225 } 226 227 blockcount = strtonum(arg, 1, UINT32_MAX, &errstr); 228 if (errstr) 229 errx(1, "Block argument %s [%u..%u].", errstr, 1, UINT32_MAX); 230 231 if (poffset == NULL) 232 goto done; 233 234 /* Second number: # of 512-byte blocks to offset partition start. */ 235 blockoffset = strtonum(poffset, 1, UINT32_MAX, &errstr); 236 if (errstr) 237 errx(1, "Block offset argument %s [%u..%u].", errstr, 1, 238 UINT32_MAX); 239 240 if (ptype == NULL) 241 goto done; 242 243 partitiontype = hex_octet(ptype); 244 if (partitiontype == -1) 245 errx(1, "Block type is not a 1-2 digit hex value"); 246 247 done: 248 disk.dk_bootprt.prt_ns = blockcount; 249 disk.dk_bootprt.prt_bs = blockoffset; 250 disk.dk_bootprt.prt_id = partitiontype; 251 } 252 253 void 254 get_default_dmbr(const char *mbrfile) 255 { 256 struct dos_mbr *dmbr = &default_dmbr; 257 ssize_t len, sz; 258 int fd; 259 260 if (mbrfile == NULL) 261 #ifdef HAS_MBR 262 mbrfile = _PATH_MBR; 263 #else 264 return; 265 #endif 266 267 fd = open(mbrfile, O_RDONLY); 268 if (fd == -1) 269 err(1, "%s", mbrfile); 270 271 sz = sizeof(*dmbr); 272 len = read(fd, dmbr, sz); 273 close(fd); 274 275 if (len == -1) 276 err(1, "read('%s')", mbrfile); 277 else if (len != sz) 278 errx(1, "read('%s'): read %zd bytes of %zd", mbrfile, len, sz); 279 } 280