+++ /dev/null
-/*
- * Ceph - scalable distributed file system
- *
- * Copyright (c) 2015 Hewlett-Packard Development Company, L.P.
- *
- * 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
- * Foundation. See file COPYING.
- *
- */
-
-#include <errno.h>
-#include <sys/ioctl.h>
-#include <sys/stat.h>
-#include <dirent.h>
-#include "include/uuid.h"
-
-#ifdef __linux__
-#include <linux/fs.h>
-#include <blkid/blkid.h>
-
-#define UUID_LEN 36
-
-static const char *sandbox_dir = "";
-
-void set_block_device_sandbox_dir(const char *dir)
-{
- if (dir)
- sandbox_dir = dir;
- else
- sandbox_dir = "";
-}
-
-int get_block_device_size(int fd, int64_t *psize)
-{
-#ifdef BLKGETSIZE64
- int ret = ::ioctl(fd, BLKGETSIZE64, psize);
-#elif defined(BLKGETSIZE)
- unsigned long sectors = 0;
- int ret = ::ioctl(fd, BLKGETSIZE, §ors);
- *psize = sectors * 512ULL;
-#else
-// cppcheck-suppress preprocessorErrorDirective
-# error "Linux configuration error (get_block_device_size)"
-#endif
- if (ret < 0)
- ret = -errno;
- return ret;
-}
-
-/**
- * get the base device (strip off partition suffix and /dev/ prefix)
- * e.g.,
- * /dev/sda3 -> sda
- * /dev/cciss/c0d1p2 -> cciss/c0d1
- * dev can a symbolic link.
- */
-int get_block_device_base(const char *dev, char *out, size_t out_len)
-{
- struct stat st;
- int r = 0;
- DIR *dir;
- char devname[PATH_MAX] = {0}, fn[PATH_MAX] = {0};
- char *p;
- char realname[PATH_MAX] = {0};
-
- if (strncmp(dev, "/dev/", 5) != 0) {
- if (realpath(dev, realname) == NULL || (strncmp(realname, "/dev/", 5) != 0)) {
- return -EINVAL;
- }
- }
-
- if (strlen(realname))
- strncpy(devname, realname + 5, PATH_MAX - 5);
- else
- strncpy(devname, dev + 5, strlen(dev) - 5);
-
- devname[PATH_MAX - 1] = '\0';
-
- for (p = devname; *p; ++p)
- if (*p == '/')
- *p = '!';
-
- snprintf(fn, sizeof(fn), "%s/sys/block/%s", sandbox_dir, devname);
- if (stat(fn, &st) == 0) {
- if (strlen(devname) + 1 > out_len) {
- return -ERANGE;
- }
- strncpy(out, devname, out_len);
- return 0;
- }
-
- snprintf(fn, sizeof(fn), "%s/sys/block", sandbox_dir);
- dir = opendir(fn);
- if (!dir)
- return -errno;
-
- struct dirent *de = nullptr;
- while ((de = ::readdir(dir))) {
- if (de->d_name[0] == '.')
- continue;
- snprintf(fn, sizeof(fn), "%s/sys/block/%s/%s", sandbox_dir, de->d_name,
- devname);
-
- if (stat(fn, &st) == 0) {
- // match!
- if (strlen(de->d_name) + 1 > out_len) {
- r = -ERANGE;
- goto out;
- }
- strncpy(out, de->d_name, out_len);
- r = 0;
- goto out;
- }
- }
- r = -ENOENT;
-
- out:
- closedir(dir);
- return r;
-}
-
-/**
- * get a block device property as a string
- *
- * store property in *val, up to maxlen chars
- * return 0 on success
- * return negative error on error
- */
-int64_t get_block_device_string_property(const char *devname,
- const char *property,
- char *val, size_t maxlen)
-{
- char filename[PATH_MAX];
- snprintf(filename, sizeof(filename),
- "%s/sys/block/%s/%s", sandbox_dir, devname, property);
-
- FILE *fp = fopen(filename, "r");
- if (fp == NULL) {
- return -errno;
- }
-
- int r = 0;
- if (fgets(val, maxlen - 1, fp)) {
- // truncate at newline
- char *p = val;
- while (*p && *p != '\n')
- ++p;
- *p = 0;
- } else {
- r = -EINVAL;
- }
- fclose(fp);
- return r;
-}
-
-/**
- * get a block device property
- *
- * return the value (we assume it is positive)
- * return negative error on error
- */
-int64_t get_block_device_int_property(const char *devname, const char *property)
-{
- char buff[256] = {0};
- int r = get_block_device_string_property(devname, property, buff, sizeof(buff));
- if (r < 0)
- return r;
- // take only digits
- for (char *p = buff; *p; ++p) {
- if (!isdigit(*p)) {
- *p = 0;
- break;
- }
- }
- char *endptr = 0;
- r = strtoll(buff, &endptr, 10);
- if (endptr != buff + strlen(buff))
- r = -EINVAL;
- return r;
-}
-
-bool block_device_support_discard(const char *devname)
-{
- return get_block_device_int_property(devname, "queue/discard_granularity") > 0;
-}
-
-int block_device_discard(int fd, int64_t offset, int64_t len)
-{
- uint64_t range[2] = {(uint64_t)offset, (uint64_t)len};
- return ioctl(fd, BLKDISCARD, range);
-}
-
-bool block_device_is_rotational(const char *devname)
-{
- return get_block_device_int_property(devname, "queue/rotational") > 0;
-}
-
-int block_device_model(const char *devname, char *model, size_t max)
-{
- return get_block_device_string_property(devname, "device/model", model, max);
-}
-
-int get_device_by_uuid(uuid_d dev_uuid, const char* label, char* partition,
- char* device)
-{
- char uuid_str[UUID_LEN+1];
- char basename[PATH_MAX];
- const char* temp_partition_ptr = NULL;
- blkid_cache cache = NULL;
- blkid_dev dev = NULL;
- int rc = 0;
-
- dev_uuid.print(uuid_str);
-
- if (blkid_get_cache(&cache, NULL) >= 0)
- dev = blkid_find_dev_with_tag(cache, label, (const char*)uuid_str);
- else
- return -EINVAL;
-
- if (dev) {
- temp_partition_ptr = blkid_dev_devname(dev);
- strncpy(partition, temp_partition_ptr, PATH_MAX);
- rc = get_block_device_base(partition, basename,
- sizeof(basename));
- if (rc >= 0) {
- strncpy(device, basename, sizeof(basename));
- rc = 0;
- } else {
- rc = -ENODEV;
- }
- } else {
- rc = -EINVAL;
- }
-
- /* From what I can tell, blkid_put_cache cleans up dev, which
- * appears to be a pointer into cache, as well */
- if (cache)
- blkid_put_cache(cache);
- return rc;
-}
-
-int get_device_by_fd(int fd, char *partition, char *device, size_t max)
-{
- struct stat st;
- int r = fstat(fd, &st);
- if (r < 0) {
- return -EINVAL; // hrm.
- }
- dev_t devid = S_ISBLK(st.st_mode) ? st.st_rdev : st.st_dev;
- char *t = blkid_devno_to_devname(devid);
- if (!t) {
- return -EINVAL;
- }
- strncpy(partition, t, max);
- free(t);
- dev_t diskdev;
- r = blkid_devno_to_wholedisk(devid, device, max, &diskdev);
- if (r < 0) {
- return -EINVAL;
- }
- return 0;
-}
-
-#elif defined(__APPLE__)
-#include <sys/disk.h>
-
-int get_block_device_size(int fd, int64_t *psize)
-{
- unsigned long blocksize = 0;
- int ret = ::ioctl(fd, DKIOCGETBLOCKSIZE, &blocksize);
- if (!ret) {
- unsigned long nblocks;
- ret = ::ioctl(fd, DKIOCGETBLOCKCOUNT, &nblocks);
- if (!ret)
- *psize = (int64_t)nblocks * blocksize;
- }
- if (ret < 0)
- ret = -errno;
- return ret;
-}
-
-bool block_device_support_discard(const char *devname)
-{
- return false;
-}
-
-int block_device_discard(int fd, int64_t offset, int64_t len)
-{
- return -EOPNOTSUPP;
-}
-
-bool block_device_is_rotational(const char *devname)
-{
- return false;
-}
-
-int get_device_by_uuid(uuid_d dev_uuid, const char* label, char* partition,
- char* device)
-{
- return -EOPNOTSUPP;
-}
-#elif defined(__FreeBSD__)
-#include <sys/disk.h>
-
-int get_block_device_size(int fd, int64_t *psize)
-{
- int ret = ::ioctl(fd, DIOCGMEDIASIZE, psize);
- if (ret < 0)
- ret = -errno;
- return ret;
-}
-
-bool block_device_support_discard(const char *devname)
-{
- return false;
-}
-
-int block_device_discard(int fd, int64_t offset, int64_t len)
-{
- return -EOPNOTSUPP;
-}
-
-bool block_device_is_rotational(const char *devname)
-{
- return false;
-}
-
-int get_device_by_uuid(uuid_d dev_uuid, const char* label, char* partition,
- char* device)
-{
- return -EOPNOTSUPP;
-}
-int get_device_by_fd(int fd, char *partition, char *device, size_t max)
-{
- return -EOPNOTSUPP;
-}
-#else
-int get_block_device_size(int fd, int64_t *psize)
-{
- return -EOPNOTSUPP;
-}
-
-bool block_device_support_discard(const char *devname)
-{
- return false;
-}
-
-int block_device_discard(int fd, int64_t offset, int64_t len)
-{
- return -EOPNOTSUPP;
-}
-
-bool block_device_is_rotational(const char *devname)
-{
- return false;
-}
-
-int get_device_by_uuid(uuid_d dev_uuid, const char* label, char* partition,
- char* device)
-{
- return -EOPNOTSUPP;
-}
-
-int get_device_by_fd(int fd, char *partition, char *device, size_t max)
-{
- return -EOPNOTSUPP;
-}
-#endif