*
* This is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
- * License version 2.1, as published by the Free Software
+ * License version 2.1, as published by the Free Software
* Foundation. See file COPYING.
- *
+ *
*/
+#ifdef __FreeBSD__
+#include <sys/param.h>
+#include <geom/geom_disk.h>
+#include <sys/disk.h>
+#include <fcntl.h>
+#endif
+
#include <errno.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#endif
-static const char *blkdev_props2strings[] = {
- [BLKDEV_PROP_DEV] = "dev",
- [BLKDEV_PROP_DISCARD_GRANULARITY] = "queue/discard_granularity",
- [BLKDEV_PROP_MODEL] = "device/model",
- [BLKDEV_PROP_ROTATIONAL] = "queue/rotational",
- [BLKDEV_PROP_SERIAL] = "device/serial",
- [BLKDEV_PROP_VENDOR] = "device/vendor",
-};
BlkDev::BlkDev(int f)
: fd(f)
: devname(devname)
{}
-const char *BlkDev::sysfsdir() const {
- return "/sys";
-}
-
int BlkDev::get_devid(dev_t *id) const {
struct stat st;
}
#elif defined(__FreeBSD__)
-#include <sys/disk.h>
const char *BlkDev::sysfsdir() const {
assert(false); // Should never be called on FreeBSD
bool BlkDev::support_discard() const
{
+#ifdef FREEBSD_WITH_TRIM
+ // there is no point to claim support of discard, but
+ // unable to do so.
+ struct diocgattr_arg arg;
+
+ strlcpy(arg.name, "GEOM::candelete", sizeof(arg.name));
+ arg.len = sizeof(arg.value.i);
+ if (ioctl(fd, DIOCGATTR, &arg) == 0) {
+ return (arg.value.i != 0);
+ } else {
+ return false;
+ }
+#endif
return false;
}
bool BlkDev::is_rotational() const
{
- return false;
+#if __FreeBSD_version >= 1200049
+ struct diocgattr_arg arg;
+
+ strlcpy(arg.name, "GEOM::rotation_rate", sizeof(arg.name));
+ arg.len = sizeof(arg.value.u16);
+
+ int ioctl_ret = ioctl(fd, DIOCGATTR, &arg);
+ bool ret;
+ if (ioctl_ret < 0 || arg.value.u16 == DISK_RR_UNKNOWN)
+ // DISK_RR_UNKNOWN usually indicates an old drive, which is usually spinny
+ ret = true;
+ else if (arg.value.u16 == DISK_RR_NON_ROTATING)
+ ret = false;
+ else if (arg.value.u16 >= DISK_RR_MIN && arg.value.u16 <= DISK_RR_MAX)
+ ret = true;
+ else
+ ret = true; // Invalid value. Probably spinny?
+
+ return ret;
+#else
+ return true; // When in doubt, it's probably spinny
+#endif
}
int BlkDev::model(char *model, size_t max) const
{
- return false;
+ struct diocgattr_arg arg;
+
+ strlcpy(arg.name, "GEOM::descr", sizeof(arg.name));
+ arg.len = sizeof(arg.value.str);
+ if (ioctl(fd, DIOCGATTR, &arg) < 0) {
+ return -errno;
+ }
+
+ // The GEOM description is of the form "vendor product" for SCSI disks
+ // and "ATA device_model" for ATA disks. Some vendors choose to put the
+ // vendor name in device_model, and some don't. Strip the first bit.
+ char *p = arg.value.str;
+ if (p == NULL || *p == '\0') {
+ *model = '\0';
+ } else {
+ (void) strsep(&p, " ");
+ snprintf(model, max, "%s", p);
+ }
+
+ return 0;
}
-int BlkDev::serial(char *serial, size_t max) const
+int BlkDev::serial(char *serial, size_t max)
{
- return -EOPNOTSUPP;
+ char ident[DISK_IDENT_SIZE];
+
+ if (ioctl(fd, DIOCGIDENT, ident) < 0)
+ return -errno;
+
+ snprintf(serial, max, "%s", ident);
+
+ return 0;
}
void get_dm_parents(const std::string& dev, std::set<std::string> *ls)
if (r < 0)
return -errno;
if (S_ISBLK(st.st_mode)) {
- char buffer[1024] = {0};
- BlkDev blkdev(fd_buffered);
-
(*pm)[prefix + "access_mode"] = "blk";
+ char buffer[1024] = {0};
+ BlkDev blkdev{fd_buffered};
+ if (r = blkdev.partition(buffer, sizeof(buffer)); r) {
+ (*pm)[prefix + "partition_path"] = "unknown";
+ } else {
+ (*pm)[prefix + "partition_path"] = buffer;
+ }
+ buffer[0] = '\0';
+ if (r = blkdev.partition(buffer, sizeof(buffer)); r) {
+ (*pm)[prefix + "dev_node"] = "unknown";
+ } else {
+ (*pm)[prefix + "dev_node"] = buffer;
+ }
+ if (!r) {
+ return 0;
+ }
+ buffer[0] = '\0';
blkdev.model(buffer, sizeof(buffer));
(*pm)[prefix + "model"] = buffer;