2 * No copyright is claimed. This code is in the public domain; do with
5 * Written by Karel Zak <kzak@redhat.com>
10 #include <sys/ioctl.h>
14 #ifdef HAVE_LINUX_FD_H
18 #ifdef HAVE_SYS_DISKLABEL_H
19 #include <sys/disklabel.h>
22 #ifdef HAVE_SYS_DISK_H
23 # include <sys/disk.h>
27 # define EBADFD 77 /* File descriptor in bad state */
32 #include "linux_version.h"
33 #include "fileutils.h"
37 blkdev_valid_offset (int fd
, off_t offset
) {
40 if (lseek (fd
, offset
, 0) < 0)
42 if (read (fd
, &ch
, 1) < 1)
50 return (fstat(fd
, &st
) == 0 && S_ISBLK(st
.st_mode
));
54 blkdev_find_size (int fd
) {
55 uintmax_t high
, low
= 0;
57 for (high
= 1024; blkdev_valid_offset (fd
, high
); ) {
58 if (high
== UINTMAX_MAX
)
63 if (high
>= UINTMAX_MAX
/2)
69 while (low
< high
- 1)
71 uintmax_t mid
= (low
+ high
) / 2;
73 if (blkdev_valid_offset (fd
, mid
))
78 blkdev_valid_offset (fd
, 0);
82 /* get size in bytes */
84 blkdev_get_size(int fd
, unsigned long long *bytes
)
86 #ifdef DKIOCGETBLOCKCOUNT
88 if (ioctl(fd
, DKIOCGETBLOCKCOUNT
, bytes
) >= 0) {
95 if (ioctl(fd
, BLKGETSIZE64
, bytes
) >= 0)
103 if (ioctl(fd
, BLKGETSIZE
, &size
) >= 0) {
104 *bytes
= ((unsigned long long)size
<< 9);
109 #endif /* BLKGETSIZE */
111 #ifdef DIOCGMEDIASIZE
113 if (ioctl(fd
, DIOCGMEDIASIZE
, bytes
) >= 0)
119 struct floppy_struct this_floppy
;
121 if (ioctl(fd
, FDGETPRM
, &this_floppy
) >= 0) {
122 *bytes
= ((unsigned long long) this_floppy
.size
) << 9;
126 #endif /* FDGETPRM */
128 #if defined(HAVE_SYS_DISKLABEL_H) && defined(DIOCGDINFO)
131 * This code works for FreeBSD 4.11 i386, except for the full device
132 * (such as /dev/ad0). It doesn't work properly for newer FreeBSD
133 * though. FreeBSD >= 5.0 should be covered by the DIOCGMEDIASIZE
136 * Note that FreeBSD >= 4.0 has disk devices as unbuffered (raw,
137 * character) devices, so we need to check for S_ISCHR, too.
140 struct disklabel lab
;
141 struct partition
*pp
;
144 if ((fstat(fd
, &st
) >= 0) &&
145 (S_ISBLK(st
.st_mode
) || S_ISCHR(st
.st_mode
)))
146 part
= st
.st_rdev
& 7;
148 if (part
>= 0 && (ioctl(fd
, DIOCGDINFO
, (char *)&lab
) >= 0)) {
149 pp
= &lab
.d_partitions
[part
];
151 *bytes
= pp
->p_size
<< 9;
156 #endif /* defined(HAVE_SYS_DISKLABEL_H) && defined(DIOCGDINFO) */
161 if (fstat(fd
, &st
) == 0 && S_ISREG(st
.st_mode
)) {
165 if (!S_ISBLK(st
.st_mode
))
169 *bytes
= blkdev_find_size(fd
);
173 /* get 512-byte sector count */
175 blkdev_get_sectors(int fd
, unsigned long long *sectors
)
177 unsigned long long bytes
;
179 if (blkdev_get_size(fd
, &bytes
) == 0) {
180 *sectors
= (bytes
>> 9);
188 * Get logical sector size.
190 * This is the smallest unit the storage device can
191 * address. It is typically 512 bytes.
194 int blkdev_get_sector_size(int fd
, int *sector_size
)
196 if (ioctl(fd
, BLKSSZGET
, sector_size
) >= 0)
201 int blkdev_get_sector_size(int fd
__attribute__((__unused__
)), int *sector_size
)
203 *sector_size
= DEFAULT_SECTOR_SIZE
;
209 * Get physical block device size. The BLKPBSZGET is supported since Linux
210 * 2.6.32. For old kernels is probably the best to assume that physical sector
211 * size is the same as logical sector size.
215 * rc = blkdev_get_physector_size(fd, &physec);
216 * if (rc || physec == 0) {
217 * rc = blkdev_get_sector_size(fd, &physec);
219 * physec = DEFAULT_SECTOR_SIZE;
223 int blkdev_get_physector_size(int fd
, int *sector_size
)
225 if (ioctl(fd
, BLKPBSZGET
, §or_size
) >= 0)
230 int blkdev_get_physector_size(int fd
__attribute__((__unused__
)), int *sector_size
)
232 *sector_size
= DEFAULT_SECTOR_SIZE
;
238 * Return the alignment status of a device
241 int blkdev_is_misaligned(int fd
)
245 if (ioctl(fd
, BLKALIGNOFF
, &aligned
) < 0)
246 return 0; /* probably kernel < 2.6.32 */
248 * Note that kernel returns -1 as alignment offset if no compatible
249 * sizes and alignments exist for stacked devices
251 return aligned
!= 0 ? 1 : 0;
254 int blkdev_is_misaligned(int fd
__attribute__((__unused__
)))
260 int open_blkdev_or_file(const struct stat
*st
, const char *name
, const int oflag
)
264 if (S_ISBLK(st
->st_mode
)) {
265 fd
= open(name
, oflag
| O_EXCL
);
267 fd
= open(name
, oflag
);
268 if (-1 < fd
&& !is_same_inode(fd
, st
)) {
273 if (-1 < fd
&& S_ISBLK(st
->st_mode
) && blkdev_is_misaligned(fd
))
274 warnx(_("warning: %s is misaligned"), name
);
278 #ifdef CDROM_GET_CAPABILITY
279 int blkdev_is_cdrom(int fd
)
283 if ((ret
= ioctl(fd
, CDROM_GET_CAPABILITY
, NULL
)) < 0)
289 int blkdev_is_cdrom(int fd
__attribute__((__unused__
)))
296 * Get kernel's interpretation of the device's geometry.
298 * Returns the heads and sectors - but not cylinders
299 * as it's truncated for disks with more than 65535 tracks.
301 * Note that this is deprecated in favor of LBA addressing.
304 int blkdev_get_geometry(int fd
, unsigned int *h
, unsigned int *s
)
306 struct hd_geometry geometry
;
308 if (ioctl(fd
, HDIO_GETGEO
, &geometry
) == 0) {
310 *s
= geometry
.sectors
;
314 int blkdev_get_geometry(int fd
__attribute__((__unused__
)),
315 unsigned int *h
, unsigned int *s
)
324 * Convert scsi type to human readable string.
326 const char *blkdev_scsi_type_to_name(int type
)
333 case SCSI_TYPE_PRINTER
:
335 case SCSI_TYPE_PROCESSOR
:
341 case SCSI_TYPE_SCANNER
:
345 case SCSI_TYPE_MEDIUM_CHANGER
:
351 case SCSI_TYPE_ENCLOSURE
:
357 case SCSI_TYPE_NO_LUN
:
365 /* return 0 on success */
366 int blkdev_lock(int fd
, const char *devname
, const char *lockmode
)
368 int oper
, rc
, msg
= 0;
371 lockmode
= getenv("LOCK_BLOCK_DEVICE");
375 if (strcasecmp(lockmode
, "yes") == 0 ||
376 strcmp(lockmode
, "1") == 0)
379 else if (strcasecmp(lockmode
, "nonblock") == 0)
380 oper
= LOCK_EX
| LOCK_NB
;
382 else if (strcasecmp(lockmode
, "no") == 0 ||
383 strcmp(lockmode
, "0") == 0)
386 warnx(_("unsupported lock mode: %s"), lockmode
);
390 if (!(oper
& LOCK_NB
)) {
391 /* Try non-block first to provide message */
392 rc
= flock(fd
, oper
| LOCK_NB
);
395 if (rc
!= 0 && errno
== EWOULDBLOCK
) {
396 fprintf(stderr
, _("%s: %s: device already locked, waiting to get lock ... "),
397 program_invocation_short_name
, devname
);
401 rc
= flock(fd
, oper
);
404 case EWOULDBLOCK
: /* LOCK_NB */
405 warnx(_("%s: device already locked"), devname
);
408 warn(_("%s: failed to get lock"), devname
);
411 fprintf(stderr
, _("OK\n"));
416 #ifdef TEST_PROGRAM_BLKDEV
421 main(int argc
, char **argv
)
423 unsigned long long bytes
;
424 unsigned long long sectors
;
425 int sector_size
, phy_sector_size
;
429 fprintf(stderr
, "usage: %s device\n", argv
[0]);
433 if ((fd
= open(argv
[1], O_RDONLY
|O_CLOEXEC
)) < 0)
434 err(EXIT_FAILURE
, "open %s failed", argv
[1]);
436 if (blkdev_get_size(fd
, &bytes
) < 0)
437 err(EXIT_FAILURE
, "blkdev_get_size() failed");
438 if (blkdev_get_sectors(fd
, §ors
) < 0)
439 err(EXIT_FAILURE
, "blkdev_get_sectors() failed");
440 if (blkdev_get_sector_size(fd
, §or_size
) < 0)
441 err(EXIT_FAILURE
, "blkdev_get_sector_size() failed");
442 if (blkdev_get_physector_size(fd
, &phy_sector_size
) < 0)
443 err(EXIT_FAILURE
, "blkdev_get_physector_size() failed");
445 printf(" bytes: %llu\n", bytes
);
446 printf(" sectors: %llu\n", sectors
);
447 printf(" sector size: %d\n", sector_size
);
448 printf("phy-sector size: %d\n", phy_sector_size
);
452 #endif /* TEST_PROGRAM_BLKDEV */