"Fossies" - the Fresh Open Source Software Archive 
Member "dosfstools-4.2/src/blkdev/blkdev.c" (31 Jan 2021, 7578 Bytes) of package /linux/misc/dosfstools-4.2.tar.gz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "blkdev.c" see the
Fossies "Dox" file reference documentation and the latest
Fossies "Diffs" side-by-side code changes report:
4.1_vs_4.2.
1 /*
2 * No copyright is claimed. This code is in the public domain; do with
3 * it what you wish.
4 *
5 * Written by Karel Zak <kzak@redhat.com>
6 */
7 #include <sys/types.h>
8 #include <sys/stat.h>
9 #include <sys/ioctl.h>
10 #include <sys/sysmacros.h>
11 #include <unistd.h>
12 #include <stdint.h>
13 #include <stdio.h>
14 #include <limits.h>
15
16 #ifdef HAVE_LINUX_HDREG_H
17 #include <linux/hdreg.h>
18 #endif
19
20 #ifdef HAVE_LINUX_FD_H
21 #include <linux/fd.h>
22 #endif
23
24 #ifdef HAVE_SYS_DISKLABEL_H
25 #include <sys/disklabel.h>
26 #endif
27
28 #ifdef HAVE_SYS_DISK_H
29 # ifdef HAVE_SYS_QUEUE_H
30 # include <sys/queue.h> /* for LIST_HEAD */
31 # endif
32 # include <sys/disk.h>
33 #endif
34
35 #include "blkdev.h"
36 #include "linux_version.h"
37
38 static long
39 blkdev_valid_offset (int fd, off_t offset) {
40 char ch;
41
42 if (lseek (fd, offset, 0) < 0)
43 return 0;
44 if (read (fd, &ch, 1) < 1)
45 return 0;
46 return 1;
47 }
48
49 int is_blkdev(int fd)
50 {
51 struct stat st;
52 return (fstat(fd, &st) == 0 && S_ISBLK(st.st_mode));
53 }
54
55 off_t
56 blkdev_find_size (int fd) {
57 uintmax_t high, low = 0;
58
59 for (high = 1024; blkdev_valid_offset (fd, high); ) {
60 if (high == UINTMAX_MAX)
61 return -1;
62
63 low = high;
64
65 if (high >= UINTMAX_MAX/2)
66 high = UINTMAX_MAX;
67 else
68 high *= 2;
69 }
70
71 while (low < high - 1)
72 {
73 uintmax_t mid = (low + high) / 2;
74
75 if (blkdev_valid_offset (fd, mid))
76 low = mid;
77 else
78 high = mid;
79 }
80 blkdev_valid_offset (fd, 0);
81 return (low + 1);
82 }
83
84 /* get size in bytes */
85 int
86 blkdev_get_size(int fd, unsigned long long *bytes)
87 {
88 #ifdef DKIOCGETBLOCKCOUNT
89 /* Apple Darwin */
90 if (ioctl(fd, DKIOCGETBLOCKCOUNT, bytes) >= 0) {
91 *bytes <<= 9;
92 return 0;
93 }
94 #endif
95
96 #ifdef BLKGETSIZE64
97 {
98 #ifdef __linux__
99 int ver = get_linux_version();
100
101 /* kernels 2.4.15-2.4.17, had a broken BLKGETSIZE64 */
102 if (ver >= KERNEL_VERSION (2,6,0) ||
103 (ver >= KERNEL_VERSION (2,4,18) && ver < KERNEL_VERSION (2,5,0)))
104 #endif
105 if (ioctl(fd, BLKGETSIZE64, bytes) >= 0)
106 return 0;
107 }
108 #endif /* BLKGETSIZE64 */
109
110 #ifdef BLKGETSIZE
111 {
112 unsigned long size;
113
114 if (ioctl(fd, BLKGETSIZE, &size) >= 0) {
115 *bytes = ((unsigned long long)size << 9);
116 return 0;
117 }
118 }
119
120 #endif /* BLKGETSIZE */
121
122 #ifdef DIOCGMEDIASIZE
123 /* FreeBSD */
124 if (ioctl(fd, DIOCGMEDIASIZE, bytes) >= 0)
125 return 0;
126 #endif
127
128 #ifdef FDGETPRM
129 {
130 struct floppy_struct this_floppy;
131
132 if (ioctl(fd, FDGETPRM, &this_floppy) >= 0) {
133 *bytes = ((unsigned long long) this_floppy.size) << 9;
134 return 0;
135 }
136 }
137 #endif /* FDGETPRM */
138
139 #ifdef HAVE_SYS_DISKLABEL_H
140 {
141 /*
142 * This code works for FreeBSD 4.11 i386, except for the full device
143 * (such as /dev/ad0). It doesn't work properly for newer FreeBSD
144 * though. FreeBSD >= 5.0 should be covered by the DIOCGMEDIASIZE
145 * above however.
146 *
147 * Note that FreeBSD >= 4.0 has disk devices as unbuffered (raw,
148 * character) devices, so we need to check for S_ISCHR, too.
149 */
150 int part = -1;
151 struct disklabel lab;
152 struct partition *pp;
153 struct stat st;
154
155 if ((fstat(fd, &st) >= 0) &&
156 (S_ISBLK(st.st_mode) || S_ISCHR(st.st_mode)))
157 part = st.st_rdev & 7;
158
159 if (part >= 0 && (ioctl(fd, DIOCGDINFO, (char *)&lab) >= 0)) {
160 pp = &lab.d_partitions[part];
161 if (pp->p_size) {
162 *bytes = pp->p_size << 9;
163 return 0;
164 }
165 }
166 }
167 #endif /* HAVE_SYS_DISKLABEL_H */
168
169 {
170 struct stat st;
171
172 if (fstat(fd, &st) == 0 && S_ISREG(st.st_mode)) {
173 *bytes = st.st_size;
174 return 0;
175 }
176 if (!S_ISBLK(st.st_mode))
177 return -1;
178 }
179
180 *bytes = blkdev_find_size(fd);
181 return 0;
182 }
183
184 /* get 512-byte sector count */
185 int
186 blkdev_get_sectors(int fd, unsigned long long *sectors)
187 {
188 unsigned long long bytes;
189
190 if (blkdev_get_size(fd, &bytes) == 0) {
191 *sectors = (bytes >> 9);
192 return 0;
193 }
194
195 return -1;
196 }
197
198 /*
199 * Get logical sector size.
200 *
201 * This is the smallest unit the storage device can
202 * address. It is typically 512 bytes.
203 */
204 int blkdev_get_sector_size(int fd, int *sector_size)
205 {
206 #ifdef BLKSSZGET
207 if (ioctl(fd, BLKSSZGET, sector_size) >= 0)
208 return 0;
209 return -1;
210 #else
211 (void)fd; /* prevent unused parameter warning */
212 *sector_size = DEFAULT_SECTOR_SIZE;
213 return 0;
214 #endif
215 }
216
217 /*
218 * Get physical block device size. The BLKPBSZGET is supported since Linux
219 * 2.6.32. For old kernels is probably the best to assume that physical sector
220 * size is the same as logical sector size.
221 *
222 * Example:
223 *
224 * rc = blkdev_get_physector_size(fd, &physec);
225 * if (rc || physec == 0) {
226 * rc = blkdev_get_sector_size(fd, &physec);
227 * if (rc)
228 * physec = DEFAULT_SECTOR_SIZE;
229 * }
230 */
231 int blkdev_get_physector_size(int fd, int *sector_size)
232 {
233 #ifdef BLKPBSZGET
234 if (ioctl(fd, BLKPBSZGET, §or_size) >= 0)
235 return 0;
236 return -1;
237 #else
238 (void)fd; /* prevent unused parameter warning */
239 *sector_size = DEFAULT_SECTOR_SIZE;
240 return 0;
241 #endif
242 }
243
244 /*
245 * Return the alignment status of a device
246 */
247 int blkdev_is_misaligned(int fd)
248 {
249 #ifdef BLKALIGNOFF
250 int aligned;
251
252 if (ioctl(fd, BLKALIGNOFF, &aligned) < 0)
253 return 0; /* probably kernel < 2.6.32 */
254 /*
255 * Note that kernel returns -1 as alignement offset if no compatible
256 * sizes and alignments exist for stacked devices
257 */
258 return aligned != 0 ? 1 : 0;
259 #else
260 (void)fd; /* prevent unused parameter warning */
261 return 0;
262 #endif
263 }
264
265 int blkdev_is_cdrom(int fd)
266 {
267 #ifdef CDROM_GET_CAPABILITY
268 int ret;
269
270 if ((ret = ioctl(fd, CDROM_GET_CAPABILITY, NULL)) < 0)
271 return 0;
272 else
273 return ret;
274 #else
275 (void)fd; /* prevent unused parameter warning */
276 return 0;
277 #endif
278 }
279
280 /*
281 * Get kernel's interpretation of the device's geometry.
282 *
283 * Returns the heads and sectors - but not cylinders
284 * as it's truncated for disks with more than 65535 tracks.
285 *
286 * Note that this is deprecated in favor of LBA addressing.
287 */
288 int blkdev_get_geometry(int fd, unsigned int *h, unsigned int *s)
289 {
290 #ifdef HDIO_GETGEO
291 {
292 struct hd_geometry geometry;
293
294 if (ioctl(fd, HDIO_GETGEO, &geometry) == 0) {
295 *h = geometry.heads;
296 *s = geometry.sectors;
297 return 0;
298 }
299 }
300 #endif
301
302 #ifdef FDGETPRM
303 {
304 struct floppy_struct fdparam;
305
306 if (ioctl(fd, FDGETPRM, &fdparam) == 0) {
307 *h = fdparam.head;
308 *s = fdparam.sect;
309 return 0;
310 }
311 }
312 #endif
313
314 (void)fd; /* prevent unused parameter warning */
315 *h = 0;
316 *s = 0;
317 return -1;
318 }
319
320 /*
321 * Get start offset of partition
322 */
323 int blkdev_get_start(int fd, dev_t rdev, unsigned long long *s)
324 {
325 #ifdef __linux__
326 {
327 char path[PATH_MAX];
328 FILE *file;
329 int ret;
330
331 snprintf(path, sizeof(path), "/sys/dev/block/%d:%d/start", major(rdev), minor(rdev));
332 file = fopen(path, "r");
333 if (file) {
334 ret = fscanf(file, "%llu", s);
335 fclose(file);
336 if (ret == 1)
337 return 0;
338 }
339 }
340 #endif
341
342 #ifdef HDIO_GETGEO
343 {
344 struct hd_geometry geometry;
345
346 if (ioctl(fd, HDIO_GETGEO, &geometry) == 0) {
347 *s = geometry.start;
348 return 0;
349 }
350 }
351 #endif
352
353 (void)rdev; /* prevent unused parameter warning */
354 (void)fd; /* prevent unused parameter warning */
355 *s = 0;
356 return -1;
357 }
358
359 /*
360 * Convert scsi type to human readable string.
361 */
362 const char *blkdev_scsi_type_to_name(int type)
363 {
364 switch (type) {
365 case SCSI_TYPE_DISK:
366 return "disk";
367 case SCSI_TYPE_TAPE:
368 return "tape";
369 case SCSI_TYPE_PRINTER:
370 return "printer";
371 case SCSI_TYPE_PROCESSOR:
372 return "processor";
373 case SCSI_TYPE_WORM:
374 return "worm";
375 case SCSI_TYPE_ROM:
376 return "rom";
377 case SCSI_TYPE_SCANNER:
378 return "scanner";
379 case SCSI_TYPE_MOD:
380 return "mo-disk";
381 case SCSI_TYPE_MEDIUM_CHANGER:
382 return "changer";
383 case SCSI_TYPE_COMM:
384 return "comm";
385 case SCSI_TYPE_RAID:
386 return "raid";
387 case SCSI_TYPE_ENCLOSURE:
388 return "enclosure";
389 case SCSI_TYPE_RBC:
390 return "rbc";
391 case SCSI_TYPE_OSD:
392 return "osd";
393 case SCSI_TYPE_NO_LUN:
394 return "no-lun";
395 default:
396 break;
397 }
398 return NULL;
399 }