1 /* $OpenBSD: disk.c,v 1.73 2021/09/13 15:07:51 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_sectors = dl.d_nsectors; 75 disk.dk_cylinders = dl.d_ncylinders; 76 disk.dk_heads = dl.d_ntracks; 77 disk.dk_sectors = dl.d_nsectors; 78 /* MBR handles only first UINT32_MAX sectors. */ 79 spc = (uint64_t)disk.dk_heads * disk.dk_sectors; 80 sz = DL_GETDSIZE(&dl); 81 if (sz > UINT32_MAX) { 82 disk.dk_cylinders = UINT32_MAX / spc; 83 disk.dk_size = disk.dk_cylinders * spc; 84 } else 85 disk.dk_size = sz; 86 } 87 88 if (disk.dk_size == 0) 89 errx(1, "disk size is 0"); 90 91 if (disk.dk_bootprt.prt_ns > 0) { 92 ns = disk.dk_bootprt.prt_ns + DL_BLKSPERSEC(&dl) - 1; 93 bs = disk.dk_bootprt.prt_bs + DL_BLKSPERSEC(&dl) - 1; 94 disk.dk_bootprt.prt_ns = DL_BLKTOSEC(&dl, ns); 95 disk.dk_bootprt.prt_bs = DL_BLKTOSEC(&dl, bs); 96 } 97 } 98 99 void 100 DISK_printgeometry(const char *units) 101 { 102 const struct unit_type *ut; 103 const int secsize = dl.d_secsize; 104 double size; 105 106 size = units_size(units, disk.dk_size, &ut); 107 printf("Disk: %s\tgeometry: %d/%d/%d [%.0f ", disk.dk_name, 108 disk.dk_cylinders, disk.dk_heads, disk.dk_sectors, size); 109 if (ut->ut_conversion == 0 && secsize != DEV_BSIZE) 110 printf("%d-byte ", secsize); 111 printf("%s]\n", ut->ut_lname); 112 } 113 114 /* 115 * The caller must free() the returned memory! 116 */ 117 char * 118 DISK_readsectors(const uint64_t sector, const uint32_t count) 119 { 120 char *secbuf; 121 ssize_t len; 122 off_t off, where; 123 size_t bytes; 124 125 where = sector * dl.d_secsize; 126 bytes = count * dl.d_secsize; 127 128 off = lseek(disk.dk_fd, where, SEEK_SET); 129 if (off == -1) { 130 #ifdef DEBUG 131 warn("lseek(%lld) for read", (int64_t)where); 132 #endif 133 return NULL; 134 } 135 136 secbuf = calloc(1, bytes); 137 if (secbuf == NULL) 138 return NULL; 139 140 len = read(disk.dk_fd, secbuf, bytes); 141 if (len == -1) { 142 #ifdef DEBUG 143 warn("read(%zu @ %lld)", bytes, (int64_t)where); 144 #endif 145 free(secbuf); 146 return NULL; 147 } 148 if (len != (ssize_t)bytes) { 149 #ifdef DEBUG 150 warnx("short read(%zu @ %lld)", bytes, (int64_t)where); 151 #endif 152 free(secbuf); 153 return NULL; 154 } 155 156 return secbuf; 157 } 158 159 int 160 DISK_writesectors(const char *buf, const uint64_t sector, 161 const uint32_t count) 162 { 163 ssize_t len; 164 off_t off, where; 165 size_t bytes; 166 167 where = sector * dl.d_secsize; 168 bytes = count * dl.d_secsize; 169 170 off = lseek(disk.dk_fd, where, SEEK_SET); 171 if (off == -1) { 172 #ifdef DEBUG 173 warn("lseek(%lld) for write", (int64_t)where); 174 #endif 175 return -1; 176 } 177 178 len = write(disk.dk_fd, buf, bytes); 179 if (len == -1) { 180 #ifdef DEBUG 181 warn("write(%zu @ %lld)", bytes, (int64_t)where); 182 #endif 183 return -1; 184 } 185 if (len != (ssize_t)bytes) { 186 #ifdef DEBUG 187 warnx("short write(%zu @ %lld)", bytes, (int64_t)where); 188 #endif 189 return -1; 190 } 191 192 return 0; 193 } 194