xref: /openbsd-src/sbin/fdisk/disk.c (revision 24bb5fcea3ed904bc467217bdaadb5dfc618d5bf)
1 /*	$OpenBSD: disk.c,v 1.69 2021/07/22 13:17:59 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 <errno.h>
27 #include <fcntl.h>
28 #include <stdint.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <unistd.h>
33 #include <util.h>
34 
35 #include "part.h"
36 #include "disk.h"
37 #include "misc.h"
38 
39 struct disk		disk;
40 struct disklabel	dl;
41 
42 void
43 DISK_open(const char *name, const int oflags)
44 {
45 	struct stat		st;
46 	uint64_t		ns, bs, sz, spc;
47 
48 	disk.dk_name = strdup(name);
49 	if (disk.dk_name == NULL)
50 		err(1, "dk_name");
51 	disk.dk_fd = opendev(disk.dk_name, oflags, OPENDEV_PART, NULL);
52 	if (disk.dk_fd == -1)
53 		err(1, "opendev('%s', 0x%x)", disk.dk_name, oflags);
54 	if (fstat(disk.dk_fd, &st) == -1)
55 		err(1, "fstat('%s)", disk.dk_name);
56 	if (!S_ISCHR(st.st_mode))
57 		errx(1, "%s is not a character device", disk.dk_name);
58 	if (ioctl(disk.dk_fd, DIOCGPDINFO, &dl) == -1)
59 		err(1, "DIOCGPDINFO");
60 
61 	unit_types[SECTORS].ut_conversion = dl.d_secsize;
62 
63 	/* Set geometry to use in MBR partitions. */
64 	if (disk.dk_size > 0) {
65 		/* -l has set disk size. */
66 		sz = disk.dk_size;
67 		disk.dk_heads = 1;
68 		disk.dk_sectors = 64;
69 		disk.dk_size = DL_BLKTOSEC(&dl, sz);
70 		disk.dk_cylinders = disk.dk_size / disk.dk_sectors;
71 	} else if (disk.dk_cylinders > 0) {
72 		/* -c/-h/-s has set disk geometry & therefore size. */
73 		sz = disk.dk_cylinders * disk.dk_heads * disk.dk_sectors;
74 		disk.dk_size = DL_BLKTOSEC(&dl, sz);
75 		disk.dk_sectors = DL_BLKTOSEC(&dl, disk.dk_sectors);
76 	} else {
77 		disk.dk_sectors = dl.d_nsectors;
78 		disk.dk_cylinders = dl.d_ncylinders;
79 		disk.dk_heads = dl.d_ntracks;
80 		disk.dk_sectors = dl.d_nsectors;
81 		/* MBR handles only first UINT32_MAX sectors. */
82 		spc = (uint64_t)disk.dk_heads * disk.dk_sectors;
83 		sz = DL_GETDSIZE(&dl);
84 		if (sz > UINT32_MAX) {
85 			disk.dk_cylinders = UINT32_MAX / spc;
86 			disk.dk_size = disk.dk_cylinders * spc;
87 		} else
88 			disk.dk_size = sz;
89 	}
90 
91 	if (disk.dk_size == 0)
92 		errx(1, "disk size is 0");
93 
94 	if (disk.dk_bootprt.prt_ns > 0) {
95 		ns = disk.dk_bootprt.prt_ns + DL_BLKSPERSEC(&dl) - 1;
96 		bs = disk.dk_bootprt.prt_bs + DL_BLKSPERSEC(&dl) - 1;
97 		disk.dk_bootprt.prt_ns = DL_BLKTOSEC(&dl, ns);
98 		disk.dk_bootprt.prt_bs = DL_BLKTOSEC(&dl, bs);
99 	}
100 }
101 
102 void
103 DISK_printgeometry(const char *units)
104 {
105 	const int		secsize = unit_types[SECTORS].ut_conversion;
106 	double			size;
107 	int			i;
108 
109 	i = unit_lookup(units);
110 	size = ((double)disk.dk_size * secsize) / unit_types[i].ut_conversion;
111 	printf("Disk: %s\t", disk.dk_name);
112 	if (disk.dk_size) {
113 		printf("geometry: %d/%d/%d [%.0f ", disk.dk_cylinders,
114 		    disk.dk_heads, disk.dk_sectors, size);
115 		if (i == SECTORS && secsize != sizeof(struct dos_mbr))
116 			printf("%d-byte ", secsize);
117 		printf("%s]\n", unit_types[i].ut_lname);
118 	} else
119 		printf("geometry: <none>\n");
120 }
121 
122 /*
123  * The caller must free() the returned memory!
124  */
125 char *
126 DISK_readsector(const uint64_t sector)
127 {
128 	char			*secbuf;
129 	ssize_t			 len;
130 	off_t			 off, where;
131 	int			 secsize;
132 
133 	secsize = dl.d_secsize;
134 
135 	where = sector * secsize;
136 	off = lseek(disk.dk_fd, where, SEEK_SET);
137 	if (off != where)
138 		return NULL;
139 
140 	secbuf = calloc(1, secsize);
141 	if (secbuf == NULL)
142 		return NULL;
143 
144 	len = read(disk.dk_fd, secbuf, secsize);
145 	if (len == -1 || len != secsize) {
146 		free(secbuf);
147 		return NULL;
148 	}
149 
150 	return secbuf;
151 }
152 
153 int
154 DISK_writesector(const char *secbuf, const uint64_t sector)
155 {
156 	int			secsize;
157 	ssize_t			len;
158 	off_t			off, where;
159 
160 	len = -1;
161 	secsize = dl.d_secsize;
162 
163 	where = secsize * sector;
164 	off = lseek(disk.dk_fd, where, SEEK_SET);
165 	if (off == where)
166 		len = write(disk.dk_fd, secbuf, secsize);
167 
168 	if (len == -1 || len != secsize) {
169 		errno = EIO;
170 		return -1;
171 	}
172 
173 	return 0;
174 }
175