1 |
|
|
/* $OpenBSD: disk.c,v 1.55 2016/03/09 12:55:18 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/types.h> |
20 |
|
|
#include <sys/fcntl.h> |
21 |
|
|
#include <sys/ioctl.h> |
22 |
|
|
#include <sys/dkio.h> |
23 |
|
|
#include <sys/stat.h> |
24 |
|
|
#include <sys/disklabel.h> |
25 |
|
|
|
26 |
|
|
#include <err.h> |
27 |
|
|
#include <errno.h> |
28 |
|
|
#include <stdio.h> |
29 |
|
|
#include <stdint.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 |
|
|
} |