1 /* $OpenBSD: disk.c,v 1.75 2022/04/25 17:10:09 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 <fcntl.h> 27 #include <stdint.h> 28 #include <stdio.h> 29 #include <stdlib.h> 30 #include <string.h> 31 #include <unistd.h> 32 #include <util.h> 33 34 #include "part.h" 35 #include "disk.h" 36 #include "misc.h" 37 38 struct disk disk; 39 struct disklabel dl; 40 41 char *readsectors(const uint64_t, const uint32_t); 42 int writesectors(const void *, const uint64_t, const uint32_t); 43 44 void 45 DISK_open(const char *name, const int oflags) 46 { 47 struct stat st; 48 uint64_t ns, bs, sz, spc; 49 50 disk.dk_name = strdup(name); 51 if (disk.dk_name == NULL) 52 err(1, "dk_name"); 53 disk.dk_fd = opendev(disk.dk_name, oflags, OPENDEV_PART, NULL); 54 if (disk.dk_fd == -1) 55 err(1, "opendev('%s', 0x%x)", disk.dk_name, oflags); 56 if (fstat(disk.dk_fd, &st) == -1) 57 err(1, "fstat('%s)", disk.dk_name); 58 if (!S_ISCHR(st.st_mode)) 59 errx(1, "%s is not a character device", disk.dk_name); 60 if (ioctl(disk.dk_fd, DIOCGPDINFO, &dl) == -1) 61 err(1, "DIOCGPDINFO"); 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_cylinders = dl.d_ncylinders; 78 disk.dk_heads = dl.d_ntracks; 79 disk.dk_sectors = dl.d_nsectors; 80 /* MBR handles only first UINT32_MAX sectors. */ 81 spc = (uint64_t)disk.dk_heads * disk.dk_sectors; 82 sz = DL_GETDSIZE(&dl); 83 if (sz > UINT32_MAX) { 84 disk.dk_cylinders = UINT32_MAX / spc; 85 disk.dk_size = disk.dk_cylinders * spc; 86 } else 87 disk.dk_size = sz; 88 } 89 90 if (disk.dk_size == 0) 91 errx(1, "disk size is 0"); 92 93 if (disk.dk_bootprt.prt_ns > 0) { 94 ns = disk.dk_bootprt.prt_ns + DL_BLKSPERSEC(&dl) - 1; 95 bs = disk.dk_bootprt.prt_bs + DL_BLKSPERSEC(&dl) - 1; 96 disk.dk_bootprt.prt_ns = DL_BLKTOSEC(&dl, ns); 97 disk.dk_bootprt.prt_bs = DL_BLKTOSEC(&dl, bs); 98 } 99 } 100 101 void 102 DISK_printgeometry(const char *units) 103 { 104 const struct unit_type *ut; 105 const int secsize = dl.d_secsize; 106 double size; 107 108 size = units_size(units, disk.dk_size, &ut); 109 printf("Disk: %s\tgeometry: %d/%d/%d [%.0f ", disk.dk_name, 110 disk.dk_cylinders, disk.dk_heads, disk.dk_sectors, size); 111 if (ut->ut_conversion == 0 && secsize != DEV_BSIZE) 112 printf("%d-byte ", secsize); 113 printf("%s]\n", ut->ut_lname); 114 } 115 116 /* 117 * The caller must free() the returned memory! 118 */ 119 char * 120 readsectors(const uint64_t sector, const uint32_t count) 121 { 122 char *secbuf; 123 ssize_t len; 124 off_t off, where; 125 size_t bytes; 126 127 where = sector * dl.d_secsize; 128 bytes = count * dl.d_secsize; 129 130 off = lseek(disk.dk_fd, where, SEEK_SET); 131 if (off == -1) { 132 #ifdef DEBUG 133 warn("lseek(%lld) for read", (int64_t)where); 134 #endif 135 return NULL; 136 } 137 138 secbuf = calloc(1, bytes); 139 if (secbuf == NULL) 140 return NULL; 141 142 len = read(disk.dk_fd, secbuf, bytes); 143 if (len == -1) { 144 #ifdef DEBUG 145 warn("read(%zu @ %lld)", bytes, (int64_t)where); 146 #endif 147 free(secbuf); 148 return NULL; 149 } 150 if (len != (ssize_t)bytes) { 151 #ifdef DEBUG 152 warnx("short read(%zu @ %lld)", bytes, (int64_t)where); 153 #endif 154 free(secbuf); 155 return NULL; 156 } 157 158 return secbuf; 159 } 160 161 int 162 writesectors(const void *buf, const uint64_t sector, const uint32_t count) 163 { 164 ssize_t len; 165 off_t off, where; 166 size_t bytes; 167 168 where = sector * dl.d_secsize; 169 bytes = count * dl.d_secsize; 170 171 off = lseek(disk.dk_fd, where, SEEK_SET); 172 if (off == -1) { 173 #ifdef DEBUG 174 warn("lseek(%lld) for write", (int64_t)where); 175 #endif 176 return -1; 177 } 178 179 len = write(disk.dk_fd, buf, bytes); 180 if (len == -1) { 181 #ifdef DEBUG 182 warn("write(%zu @ %lld)", bytes, (int64_t)where); 183 #endif 184 return -1; 185 } 186 if (len != (ssize_t)bytes) { 187 #ifdef DEBUG 188 warnx("short write(%zu @ %lld)", bytes, (int64_t)where); 189 #endif 190 return -1; 191 } 192 193 return 0; 194 } 195 196 int 197 DISK_readbytes(void *buf, const uint64_t sector, const size_t sz) 198 { 199 char *secbuf; 200 uint32_t count; 201 202 count = (sz + dl.d_secsize - 1) / dl.d_secsize; 203 204 secbuf = readsectors(sector, count); 205 if (secbuf == NULL) 206 return -1; 207 208 memcpy(buf, secbuf, sz); 209 free(secbuf); 210 211 return 0; 212 } 213 214 int 215 DISK_writebytes(const void *buf, const uint64_t sector, const size_t sz) 216 { 217 char *secbuf; 218 uint32_t count; 219 int rslt; 220 221 count = (sz + dl.d_secsize - 1) / dl.d_secsize; 222 223 secbuf = readsectors(sector, count); 224 if (secbuf == NULL) 225 return -1; 226 227 memcpy(secbuf, buf, sz); 228 rslt = writesectors(secbuf, sector, count); 229 free(secbuf); 230 231 return rslt; 232 } 233