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