1 /* $OpenBSD: disk.c,v 1.74 2021/10/10 15:34:21 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 void 42 DISK_open(const char *name, const int oflags) 43 { 44 struct stat st; 45 uint64_t ns, bs, sz, spc; 46 47 disk.dk_name = strdup(name); 48 if (disk.dk_name == NULL) 49 err(1, "dk_name"); 50 disk.dk_fd = opendev(disk.dk_name, oflags, OPENDEV_PART, NULL); 51 if (disk.dk_fd == -1) 52 err(1, "opendev('%s', 0x%x)", disk.dk_name, oflags); 53 if (fstat(disk.dk_fd, &st) == -1) 54 err(1, "fstat('%s)", disk.dk_name); 55 if (!S_ISCHR(st.st_mode)) 56 errx(1, "%s is not a character device", disk.dk_name); 57 if (ioctl(disk.dk_fd, DIOCGPDINFO, &dl) == -1) 58 err(1, "DIOCGPDINFO"); 59 60 /* Set geometry to use in MBR partitions. */ 61 if (disk.dk_size > 0) { 62 /* -l has set disk size. */ 63 sz = disk.dk_size; 64 disk.dk_heads = 1; 65 disk.dk_sectors = 64; 66 disk.dk_size = DL_BLKTOSEC(&dl, sz); 67 disk.dk_cylinders = disk.dk_size / disk.dk_sectors; 68 } else if (disk.dk_cylinders > 0) { 69 /* -c/-h/-s has set disk geometry & therefore size. */ 70 sz = disk.dk_cylinders * disk.dk_heads * disk.dk_sectors; 71 disk.dk_size = DL_BLKTOSEC(&dl, sz); 72 disk.dk_sectors = DL_BLKTOSEC(&dl, disk.dk_sectors); 73 } else { 74 disk.dk_cylinders = dl.d_ncylinders; 75 disk.dk_heads = dl.d_ntracks; 76 disk.dk_sectors = dl.d_nsectors; 77 /* MBR handles only first UINT32_MAX sectors. */ 78 spc = (uint64_t)disk.dk_heads * disk.dk_sectors; 79 sz = DL_GETDSIZE(&dl); 80 if (sz > UINT32_MAX) { 81 disk.dk_cylinders = UINT32_MAX / spc; 82 disk.dk_size = disk.dk_cylinders * spc; 83 } else 84 disk.dk_size = sz; 85 } 86 87 if (disk.dk_size == 0) 88 errx(1, "disk size is 0"); 89 90 if (disk.dk_bootprt.prt_ns > 0) { 91 ns = disk.dk_bootprt.prt_ns + DL_BLKSPERSEC(&dl) - 1; 92 bs = disk.dk_bootprt.prt_bs + DL_BLKSPERSEC(&dl) - 1; 93 disk.dk_bootprt.prt_ns = DL_BLKTOSEC(&dl, ns); 94 disk.dk_bootprt.prt_bs = DL_BLKTOSEC(&dl, bs); 95 } 96 } 97 98 void 99 DISK_printgeometry(const char *units) 100 { 101 const struct unit_type *ut; 102 const int secsize = dl.d_secsize; 103 double size; 104 105 size = units_size(units, disk.dk_size, &ut); 106 printf("Disk: %s\tgeometry: %d/%d/%d [%.0f ", disk.dk_name, 107 disk.dk_cylinders, disk.dk_heads, disk.dk_sectors, size); 108 if (ut->ut_conversion == 0 && secsize != DEV_BSIZE) 109 printf("%d-byte ", secsize); 110 printf("%s]\n", ut->ut_lname); 111 } 112 113 /* 114 * The caller must free() the returned memory! 115 */ 116 char * 117 DISK_readsectors(const uint64_t sector, const uint32_t count) 118 { 119 char *secbuf; 120 ssize_t len; 121 off_t off, where; 122 size_t bytes; 123 124 where = sector * dl.d_secsize; 125 bytes = count * dl.d_secsize; 126 127 off = lseek(disk.dk_fd, where, SEEK_SET); 128 if (off == -1) { 129 #ifdef DEBUG 130 warn("lseek(%lld) for read", (int64_t)where); 131 #endif 132 return NULL; 133 } 134 135 secbuf = calloc(1, bytes); 136 if (secbuf == NULL) 137 return NULL; 138 139 len = read(disk.dk_fd, secbuf, bytes); 140 if (len == -1) { 141 #ifdef DEBUG 142 warn("read(%zu @ %lld)", bytes, (int64_t)where); 143 #endif 144 free(secbuf); 145 return NULL; 146 } 147 if (len != (ssize_t)bytes) { 148 #ifdef DEBUG 149 warnx("short read(%zu @ %lld)", bytes, (int64_t)where); 150 #endif 151 free(secbuf); 152 return NULL; 153 } 154 155 return secbuf; 156 } 157 158 int 159 DISK_writesectors(const char *buf, const uint64_t sector, 160 const uint32_t count) 161 { 162 ssize_t len; 163 off_t off, where; 164 size_t bytes; 165 166 where = sector * dl.d_secsize; 167 bytes = count * dl.d_secsize; 168 169 off = lseek(disk.dk_fd, where, SEEK_SET); 170 if (off == -1) { 171 #ifdef DEBUG 172 warn("lseek(%lld) for write", (int64_t)where); 173 #endif 174 return -1; 175 } 176 177 len = write(disk.dk_fd, buf, bytes); 178 if (len == -1) { 179 #ifdef DEBUG 180 warn("write(%zu @ %lld)", bytes, (int64_t)where); 181 #endif 182 return -1; 183 } 184 if (len != (ssize_t)bytes) { 185 #ifdef DEBUG 186 warnx("short write(%zu @ %lld)", bytes, (int64_t)where); 187 #endif 188 return -1; 189 } 190 191 return 0; 192 } 193