1*adf35c80Skrw /* $OpenBSD: disk.c,v 1.75 2022/04/25 17:10:09 krw Exp $ */
2a1705421Sweingart
3a1705421Sweingart /*
410a68084Skrw * Copyright (c) 1997 Tobias Weingartner
5a1705421Sweingart *
610a68084Skrw * Permission to use, copy, modify, and distribute this software for any
710a68084Skrw * purpose with or without fee is hereby granted, provided that the above
810a68084Skrw * copyright notice and this permission notice appear in all copies.
9a1705421Sweingart *
1010a68084Skrw * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1110a68084Skrw * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1210a68084Skrw * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1310a68084Skrw * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1410a68084Skrw * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1510a68084Skrw * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1610a68084Skrw * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17a1705421Sweingart */
18a1705421Sweingart
19f9336ec7Skrw #include <sys/param.h> /* DEV_BSIZE */
20e8252b55Skrw #include <sys/ioctl.h>
21a7568474Sderaadt #include <sys/dkio.h>
22a7568474Sderaadt #include <sys/stat.h>
23a7568474Sderaadt #include <sys/disklabel.h>
24729290c0Skrw
25a1705421Sweingart #include <err.h>
266316a812Sguenther #include <fcntl.h>
27729290c0Skrw #include <stdint.h>
286316a812Sguenther #include <stdio.h>
29a1705421Sweingart #include <stdlib.h>
30f9336ec7Skrw #include <string.h>
31e8252b55Skrw #include <unistd.h>
32729290c0Skrw #include <util.h>
33abc6f793Skrw
34199eafeaSkrw #include "part.h"
35a1705421Sweingart #include "disk.h"
368ce00868Skjell #include "misc.h"
37a1705421Sweingart
38ac519580Skrw struct disk disk;
39afe4b3d4Skrw struct disklabel dl;
40afe4b3d4Skrw
41*adf35c80Skrw char *readsectors(const uint64_t, const uint32_t);
42*adf35c80Skrw int writesectors(const void *, const uint64_t, const uint32_t);
43*adf35c80Skrw
440468c08fSkrw void
DISK_open(const char * name,const int oflags)45f9336ec7Skrw DISK_open(const char *name, const int oflags)
46a1705421Sweingart {
47a1705421Sweingart struct stat st;
48199eafeaSkrw uint64_t ns, bs, sz, spc;
49a1705421Sweingart
50f9336ec7Skrw disk.dk_name = strdup(name);
51f9336ec7Skrw if (disk.dk_name == NULL)
5217bb819eSkrw err(1, "dk_name");
53f9336ec7Skrw disk.dk_fd = opendev(disk.dk_name, oflags, OPENDEV_PART, NULL);
5433e90638Skrw if (disk.dk_fd == -1)
5517bb819eSkrw err(1, "opendev('%s', 0x%x)", disk.dk_name, oflags);
5633e90638Skrw if (fstat(disk.dk_fd, &st) == -1)
5717bb819eSkrw err(1, "fstat('%s)", disk.dk_name);
580a9d837bSkrw if (!S_ISCHR(st.st_mode))
5933e90638Skrw errx(1, "%s is not a character device", disk.dk_name);
60f9336ec7Skrw if (ioctl(disk.dk_fd, DIOCGPDINFO, &dl) == -1)
61f9336ec7Skrw err(1, "DIOCGPDINFO");
627126966cSkrw
63f9336ec7Skrw /* Set geometry to use in MBR partitions. */
64f9336ec7Skrw if (disk.dk_size > 0) {
65f9336ec7Skrw /* -l has set disk size. */
6662d4fabcSkrw sz = disk.dk_size;
67f9336ec7Skrw disk.dk_heads = 1;
68f9336ec7Skrw disk.dk_sectors = 64;
6962d4fabcSkrw disk.dk_size = DL_BLKTOSEC(&dl, sz);
7062d4fabcSkrw disk.dk_cylinders = disk.dk_size / disk.dk_sectors;
71f9336ec7Skrw } else if (disk.dk_cylinders > 0) {
7262d4fabcSkrw /* -c/-h/-s has set disk geometry & therefore size. */
73f9336ec7Skrw sz = disk.dk_cylinders * disk.dk_heads * disk.dk_sectors;
7462d4fabcSkrw disk.dk_size = DL_BLKTOSEC(&dl, sz);
75f9336ec7Skrw disk.dk_sectors = DL_BLKTOSEC(&dl, disk.dk_sectors);
76f9336ec7Skrw } else {
7762d4fabcSkrw disk.dk_cylinders = dl.d_ncylinders;
7833e90638Skrw disk.dk_heads = dl.d_ntracks;
7933e90638Skrw disk.dk_sectors = dl.d_nsectors;
8062d4fabcSkrw /* MBR handles only first UINT32_MAX sectors. */
8162d4fabcSkrw spc = (uint64_t)disk.dk_heads * disk.dk_sectors;
8262d4fabcSkrw sz = DL_GETDSIZE(&dl);
8362d4fabcSkrw if (sz > UINT32_MAX) {
8462d4fabcSkrw disk.dk_cylinders = UINT32_MAX / spc;
8562d4fabcSkrw disk.dk_size = disk.dk_cylinders * spc;
8662d4fabcSkrw } else
8762d4fabcSkrw disk.dk_size = sz;
88a1705421Sweingart }
89a1705421Sweingart
90f9336ec7Skrw if (disk.dk_size == 0)
9162d4fabcSkrw errx(1, "disk size is 0");
92199eafeaSkrw
93199eafeaSkrw if (disk.dk_bootprt.prt_ns > 0) {
94199eafeaSkrw ns = disk.dk_bootprt.prt_ns + DL_BLKSPERSEC(&dl) - 1;
95199eafeaSkrw bs = disk.dk_bootprt.prt_bs + DL_BLKSPERSEC(&dl) - 1;
96199eafeaSkrw disk.dk_bootprt.prt_ns = DL_BLKTOSEC(&dl, ns);
97199eafeaSkrw disk.dk_bootprt.prt_bs = DL_BLKTOSEC(&dl, bs);
98199eafeaSkrw }
99c4a7c6b7Skrw }
100c4a7c6b7Skrw
10139351f7aSkrw void
DISK_printgeometry(const char * units)102859be6c9Skrw DISK_printgeometry(const char *units)
103a1705421Sweingart {
1043e9b7d6bSkrw const struct unit_type *ut;
1051629ab0bSkrw const int secsize = dl.d_secsize;
1068ce00868Skjell double size;
107d1f880e6Skrw
1083e9b7d6bSkrw size = units_size(units, disk.dk_size, &ut);
1093e9b7d6bSkrw printf("Disk: %s\tgeometry: %d/%d/%d [%.0f ", disk.dk_name,
1103e9b7d6bSkrw disk.dk_cylinders, disk.dk_heads, disk.dk_sectors, size);
1113e9b7d6bSkrw if (ut->ut_conversion == 0 && secsize != DEV_BSIZE)
112d1f880e6Skrw printf("%d-byte ", secsize);
1133e9b7d6bSkrw printf("%s]\n", ut->ut_lname);
114a1705421Sweingart }
115c2348643Skrw
116c2348643Skrw /*
117206308ccSkrw * The caller must free() the returned memory!
118c2348643Skrw */
119c2348643Skrw char *
readsectors(const uint64_t sector,const uint32_t count)120*adf35c80Skrw readsectors(const uint64_t sector, const uint32_t count)
121c2348643Skrw {
122c2348643Skrw char *secbuf;
123c2348643Skrw ssize_t len;
1240cd9e2afSkrw off_t off, where;
125605b5690Skrw size_t bytes;
126c2348643Skrw
127605b5690Skrw where = sector * dl.d_secsize;
128605b5690Skrw bytes = count * dl.d_secsize;
129c2348643Skrw
13033e90638Skrw off = lseek(disk.dk_fd, where, SEEK_SET);
131605b5690Skrw if (off == -1) {
132605b5690Skrw #ifdef DEBUG
133605b5690Skrw warn("lseek(%lld) for read", (int64_t)where);
134605b5690Skrw #endif
1352a536aa2Skrw return NULL;
136605b5690Skrw }
137c2348643Skrw
138605b5690Skrw secbuf = calloc(1, bytes);
139c2348643Skrw if (secbuf == NULL)
1402a536aa2Skrw return NULL;
141c2348643Skrw
142605b5690Skrw len = read(disk.dk_fd, secbuf, bytes);
143605b5690Skrw if (len == -1) {
144605b5690Skrw #ifdef DEBUG
145605b5690Skrw warn("read(%zu @ %lld)", bytes, (int64_t)where);
146605b5690Skrw #endif
147605b5690Skrw free(secbuf);
148605b5690Skrw return NULL;
149605b5690Skrw }
150605b5690Skrw if (len != (ssize_t)bytes) {
151605b5690Skrw #ifdef DEBUG
152605b5690Skrw warnx("short read(%zu @ %lld)", bytes, (int64_t)where);
153605b5690Skrw #endif
154c2348643Skrw free(secbuf);
1552a536aa2Skrw return NULL;
156c2348643Skrw }
157c2348643Skrw
1582a536aa2Skrw return secbuf;
159c2348643Skrw }
160c2348643Skrw
161c2348643Skrw int
writesectors(const void * buf,const uint64_t sector,const uint32_t count)162*adf35c80Skrw writesectors(const void *buf, const uint64_t sector, const uint32_t count)
163c2348643Skrw {
164c2348643Skrw ssize_t len;
1650cd9e2afSkrw off_t off, where;
166605b5690Skrw size_t bytes;
167c2348643Skrw
168605b5690Skrw where = sector * dl.d_secsize;
169605b5690Skrw bytes = count * dl.d_secsize;
170c2348643Skrw
17133e90638Skrw off = lseek(disk.dk_fd, where, SEEK_SET);
172605b5690Skrw if (off == -1) {
173605b5690Skrw #ifdef DEBUG
174605b5690Skrw warn("lseek(%lld) for write", (int64_t)where);
175605b5690Skrw #endif
176605b5690Skrw return -1;
177605b5690Skrw }
178c2348643Skrw
179605b5690Skrw len = write(disk.dk_fd, buf, bytes);
180605b5690Skrw if (len == -1) {
181605b5690Skrw #ifdef DEBUG
182605b5690Skrw warn("write(%zu @ %lld)", bytes, (int64_t)where);
183605b5690Skrw #endif
184605b5690Skrw return -1;
185605b5690Skrw }
186605b5690Skrw if (len != (ssize_t)bytes) {
187605b5690Skrw #ifdef DEBUG
188605b5690Skrw warnx("short write(%zu @ %lld)", bytes, (int64_t)where);
189605b5690Skrw #endif
1902a536aa2Skrw return -1;
191c2348643Skrw }
192c2348643Skrw
1932a536aa2Skrw return 0;
194c2348643Skrw }
195*adf35c80Skrw
196*adf35c80Skrw int
DISK_readbytes(void * buf,const uint64_t sector,const size_t sz)197*adf35c80Skrw DISK_readbytes(void *buf, const uint64_t sector, const size_t sz)
198*adf35c80Skrw {
199*adf35c80Skrw char *secbuf;
200*adf35c80Skrw uint32_t count;
201*adf35c80Skrw
202*adf35c80Skrw count = (sz + dl.d_secsize - 1) / dl.d_secsize;
203*adf35c80Skrw
204*adf35c80Skrw secbuf = readsectors(sector, count);
205*adf35c80Skrw if (secbuf == NULL)
206*adf35c80Skrw return -1;
207*adf35c80Skrw
208*adf35c80Skrw memcpy(buf, secbuf, sz);
209*adf35c80Skrw free(secbuf);
210*adf35c80Skrw
211*adf35c80Skrw return 0;
212*adf35c80Skrw }
213*adf35c80Skrw
214*adf35c80Skrw int
DISK_writebytes(const void * buf,const uint64_t sector,const size_t sz)215*adf35c80Skrw DISK_writebytes(const void *buf, const uint64_t sector, const size_t sz)
216*adf35c80Skrw {
217*adf35c80Skrw char *secbuf;
218*adf35c80Skrw uint32_t count;
219*adf35c80Skrw int rslt;
220*adf35c80Skrw
221*adf35c80Skrw count = (sz + dl.d_secsize - 1) / dl.d_secsize;
222*adf35c80Skrw
223*adf35c80Skrw secbuf = readsectors(sector, count);
224*adf35c80Skrw if (secbuf == NULL)
225*adf35c80Skrw return -1;
226*adf35c80Skrw
227*adf35c80Skrw memcpy(secbuf, buf, sz);
228*adf35c80Skrw rslt = writesectors(secbuf, sector, count);
229*adf35c80Skrw free(secbuf);
230*adf35c80Skrw
231*adf35c80Skrw return rslt;
232*adf35c80Skrw }
233