1 /* $OpenBSD: disk.c,v 1.69 2021/07/22 13:17:59 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/param.h> /* DEV_BSIZE */ 20 #include <sys/ioctl.h> 21 #include <sys/dkio.h> 22 #include <sys/stat.h> 23 #include <sys/disklabel.h> 24 25 #include <err.h> 26 #include <errno.h> 27 #include <fcntl.h> 28 #include <stdint.h> 29 #include <stdio.h> 30 #include <stdlib.h> 31 #include <string.h> 32 #include <unistd.h> 33 #include <util.h> 34 35 #include "part.h" 36 #include "disk.h" 37 #include "misc.h" 38 39 struct disk disk; 40 struct disklabel dl; 41 42 void 43 DISK_open(const char *name, const int oflags) 44 { 45 struct stat st; 46 uint64_t ns, bs, sz, spc; 47 48 disk.dk_name = strdup(name); 49 if (disk.dk_name == NULL) 50 err(1, "dk_name"); 51 disk.dk_fd = opendev(disk.dk_name, oflags, OPENDEV_PART, NULL); 52 if (disk.dk_fd == -1) 53 err(1, "opendev('%s', 0x%x)", disk.dk_name, oflags); 54 if (fstat(disk.dk_fd, &st) == -1) 55 err(1, "fstat('%s)", disk.dk_name); 56 if (!S_ISCHR(st.st_mode)) 57 errx(1, "%s is not a character device", disk.dk_name); 58 if (ioctl(disk.dk_fd, DIOCGPDINFO, &dl) == -1) 59 err(1, "DIOCGPDINFO"); 60 61 unit_types[SECTORS].ut_conversion = dl.d_secsize; 62 63 /* Set geometry to use in MBR partitions. */ 64 if (disk.dk_size > 0) { 65 /* -l has set disk size. */ 66 sz = disk.dk_size; 67 disk.dk_heads = 1; 68 disk.dk_sectors = 64; 69 disk.dk_size = DL_BLKTOSEC(&dl, sz); 70 disk.dk_cylinders = disk.dk_size / disk.dk_sectors; 71 } else if (disk.dk_cylinders > 0) { 72 /* -c/-h/-s has set disk geometry & therefore size. */ 73 sz = disk.dk_cylinders * disk.dk_heads * disk.dk_sectors; 74 disk.dk_size = DL_BLKTOSEC(&dl, sz); 75 disk.dk_sectors = DL_BLKTOSEC(&dl, disk.dk_sectors); 76 } else { 77 disk.dk_sectors = dl.d_nsectors; 78 disk.dk_cylinders = dl.d_ncylinders; 79 disk.dk_heads = dl.d_ntracks; 80 disk.dk_sectors = dl.d_nsectors; 81 /* MBR handles only first UINT32_MAX sectors. */ 82 spc = (uint64_t)disk.dk_heads * disk.dk_sectors; 83 sz = DL_GETDSIZE(&dl); 84 if (sz > UINT32_MAX) { 85 disk.dk_cylinders = UINT32_MAX / spc; 86 disk.dk_size = disk.dk_cylinders * spc; 87 } else 88 disk.dk_size = sz; 89 } 90 91 if (disk.dk_size == 0) 92 errx(1, "disk size is 0"); 93 94 if (disk.dk_bootprt.prt_ns > 0) { 95 ns = disk.dk_bootprt.prt_ns + DL_BLKSPERSEC(&dl) - 1; 96 bs = disk.dk_bootprt.prt_bs + DL_BLKSPERSEC(&dl) - 1; 97 disk.dk_bootprt.prt_ns = DL_BLKTOSEC(&dl, ns); 98 disk.dk_bootprt.prt_bs = DL_BLKTOSEC(&dl, bs); 99 } 100 } 101 102 void 103 DISK_printgeometry(const char *units) 104 { 105 const int secsize = unit_types[SECTORS].ut_conversion; 106 double size; 107 int i; 108 109 i = unit_lookup(units); 110 size = ((double)disk.dk_size * secsize) / unit_types[i].ut_conversion; 111 printf("Disk: %s\t", disk.dk_name); 112 if (disk.dk_size) { 113 printf("geometry: %d/%d/%d [%.0f ", disk.dk_cylinders, 114 disk.dk_heads, disk.dk_sectors, size); 115 if (i == SECTORS && secsize != sizeof(struct dos_mbr)) 116 printf("%d-byte ", secsize); 117 printf("%s]\n", unit_types[i].ut_lname); 118 } else 119 printf("geometry: <none>\n"); 120 } 121 122 /* 123 * The caller must free() the returned memory! 124 */ 125 char * 126 DISK_readsector(const uint64_t sector) 127 { 128 char *secbuf; 129 ssize_t len; 130 off_t off, where; 131 int secsize; 132 133 secsize = dl.d_secsize; 134 135 where = sector * secsize; 136 off = lseek(disk.dk_fd, where, SEEK_SET); 137 if (off != where) 138 return NULL; 139 140 secbuf = calloc(1, secsize); 141 if (secbuf == NULL) 142 return NULL; 143 144 len = read(disk.dk_fd, secbuf, secsize); 145 if (len == -1 || len != secsize) { 146 free(secbuf); 147 return NULL; 148 } 149 150 return secbuf; 151 } 152 153 int 154 DISK_writesector(const char *secbuf, const uint64_t sector) 155 { 156 int secsize; 157 ssize_t len; 158 off_t off, where; 159 160 len = -1; 161 secsize = dl.d_secsize; 162 163 where = secsize * sector; 164 off = lseek(disk.dk_fd, where, SEEK_SET); 165 if (off == where) 166 len = write(disk.dk_fd, secbuf, secsize); 167 168 if (len == -1 || len != secsize) { 169 errno = EIO; 170 return -1; 171 } 172 173 return 0; 174 } 175