1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "components/metrics/drive_metrics_provider.h"
6 
7 #if defined(OS_BSD)
8 #include <sys/types.h>
9 #define MAJOR(dev) major(dev)
10 #define MINOR(dev) minor(dev)
11 #else
12 #include <linux/kdev_t.h>  // For MAJOR()/MINOR().
13 #endif
14 #include <sys/stat.h>
15 #include <string>
16 
17 #include "base/files/file.h"
18 #include "base/files/file_path.h"
19 #include "base/files/file_util.h"
20 #include "base/strings/string_util.h"
21 #include "base/strings/stringprintf.h"
22 #include "build/build_config.h"
23 
24 namespace metrics {
25 
26 namespace {
27 
28 // See http://www.kernel.org/doc/Documentation/devices.txt for more info.
29 const int kFirstScsiMajorNumber = 8;
30 const int kPartitionsPerScsiDevice = 16;
31 const char kRotationalFormat[] = "/sys/block/sd%c/queue/rotational";
32 
33 }  // namespace
34 
35 // static
HasSeekPenalty(const base::FilePath & path,bool * has_seek_penalty)36 bool DriveMetricsProvider::HasSeekPenalty(const base::FilePath& path,
37                                           bool* has_seek_penalty) {
38   base::File file(path, base::File::FLAG_OPEN | base::File::FLAG_READ);
39   if (!file.IsValid())
40     return false;
41 
42   struct stat path_stat;
43   int error = fstat(file.GetPlatformFile(), &path_stat);
44   if (error < 0 || MAJOR(path_stat.st_dev) != kFirstScsiMajorNumber) {
45     // TODO(dbeam): support more SCSI major numbers (e.g. /dev/sdq+) and LVM?
46     return false;
47   }
48 
49   char sdX = 'a' + MINOR(path_stat.st_dev) / kPartitionsPerScsiDevice;
50   std::string rotational_path = base::StringPrintf(kRotationalFormat, sdX);
51   std::string rotates;
52   if (!base::ReadFileToString(base::FilePath(rotational_path), &rotates))
53     return false;
54 
55   *has_seek_penalty = rotates.substr(0, 1) == "1";
56   return true;
57 }
58 
59 }  // namespace metrics
60