1 /* $OpenBSD: disk.c,v 1.56 2018/04/26 15:55:14 guenther 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/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 <unistd.h> 32 #include <util.h> 33 34 #include "disk.h" 35 #include "misc.h" 36 37 struct disk disk; 38 struct disklabel dl; 39 40 void 41 DISK_open(int rw) 42 { 43 struct stat st; 44 u_int64_t sz, spc; 45 46 disk.fd = opendev(disk.name, rw ? O_RDWR : O_RDONLY, OPENDEV_PART, 47 NULL); 48 if (disk.fd == -1) 49 err(1, "%s", disk.name); 50 if (fstat(disk.fd, &st) == -1) 51 err(1, "%s", disk.name); 52 if (!S_ISCHR(st.st_mode)) 53 errx(1, "%s is not a character device", disk.name); 54 55 /* Get label geometry. */ 56 if (ioctl(disk.fd, DIOCGPDINFO, &dl) == -1) { 57 warn("DIOCGPDINFO"); 58 } else { 59 unit_types[SECTORS].conversion = dl.d_secsize; 60 if (disk.size == 0) { 61 /* -l or -c/-h/-s not used. Use disklabel info. */ 62 disk.cylinders = dl.d_ncylinders; 63 disk.heads = dl.d_ntracks; 64 disk.sectors = dl.d_nsectors; 65 /* MBR handles only first UINT32_MAX sectors. */ 66 spc = (u_int64_t)disk.heads * disk.sectors; 67 sz = DL_GETDSIZE(&dl); 68 if (sz > UINT32_MAX) { 69 disk.cylinders = UINT32_MAX / spc; 70 disk.size = disk.cylinders * spc; 71 } else 72 disk.size = sz; 73 } 74 } 75 76 if (disk.size == 0 || disk.cylinders == 0 || disk.heads == 0 || 77 disk.sectors == 0 || unit_types[SECTORS].conversion == 0) 78 errx(1, "Can't get disk geometry, please use [-chs] or [-l]" 79 "to specify."); 80 } 81 82 /* 83 * Print the disk geometry information. Take an optional modifier 84 * to indicate the units that should be used for display. 85 */ 86 int 87 DISK_printgeometry(char *units) 88 { 89 const int secsize = unit_types[SECTORS].conversion; 90 double size; 91 int i; 92 93 i = unit_lookup(units); 94 size = ((double)disk.size * secsize) / unit_types[i].conversion; 95 printf("Disk: %s\t", disk.name); 96 if (disk.size) { 97 printf("geometry: %d/%d/%d [%.0f ", disk.cylinders, 98 disk.heads, disk.sectors, size); 99 if (i == SECTORS && secsize != sizeof(struct dos_mbr)) 100 printf("%d-byte ", secsize); 101 printf("%s]\n", unit_types[i].lname); 102 } else 103 printf("geometry: <none>\n"); 104 105 return (0); 106 } 107 108 /* 109 * Read the sector at 'where' from the file descriptor 'fd' into newly 110 * calloc'd memory. Return a pointer to the memory if it contains the 111 * requested data, or NULL if it does not. 112 * 113 * The caller must free() the memory it gets. 114 */ 115 char * 116 DISK_readsector(off_t where) 117 { 118 int secsize; 119 char *secbuf; 120 ssize_t len; 121 off_t off; 122 123 secsize = dl.d_secsize; 124 125 where *= secsize; 126 off = lseek(disk.fd, where, SEEK_SET); 127 if (off != where) 128 return (NULL); 129 130 secbuf = calloc(1, secsize); 131 if (secbuf == NULL) 132 return (NULL); 133 134 len = read(disk.fd, secbuf, secsize); 135 if (len == -1 || len != secsize) { 136 free(secbuf); 137 return (NULL); 138 } 139 140 return (secbuf); 141 } 142 143 /* 144 * Write the sector-sized 'secbuf' to the sector 'where' on the file 145 * descriptor 'fd'. Return 0 if the write works. Return -1 and set 146 * errno if the write fails. 147 */ 148 int 149 DISK_writesector(char *secbuf, off_t where) 150 { 151 int secsize; 152 ssize_t len; 153 off_t off; 154 155 len = -1; 156 secsize = dl.d_secsize; 157 158 where *= secsize; 159 off = lseek(disk.fd, where, SEEK_SET); 160 if (off == where) 161 len = write(disk.fd, secbuf, secsize); 162 163 if (len == -1 || len != secsize) { 164 /* short read or write */ 165 errno = EIO; 166 return (-1); 167 } 168 169 return (0); 170 } 171