xref: /openbsd-src/sbin/fdisk/disk.c (revision adf35c805063bdae2645f1ef12aa003e59773899)
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