Home | History | Annotate | Download | only in image_writer_private
      1 // Copyright 2013 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 <libudev.h>
      6 
      7 #include "base/file_util.h"
      8 #include "base/strings/string_number_conversions.h"
      9 #include "chrome/browser/extensions/api/image_writer_private/removable_storage_provider.h"
     10 #include "content/public/browser/browser_thread.h"
     11 
     12 namespace extensions {
     13 // TODO(haven): Udev code may be duplicated in the Chrome codebase.
     14 // https://code.google.com/p/chromium/issues/detail?id=284898
     15 
     16 // Returns the integer contained in |attr|.  Returns 0 on error.
     17 static uint64 get_int_attr(const char* attr){
     18   uint64 result = 0;
     19   // In error cases, StringToInt will set result to 0
     20   base::StringToUint64(attr, &result);
     21   return result;
     22 }
     23 
     24 static int get_device_blk_size(const std::string& path) {
     25   base::FilePath file_path(path);
     26   std::string device = file_path.BaseName().value();
     27 
     28   base::FilePath info_file_path = base::FilePath("/sys/block")
     29                                   .Append(device)
     30                                   .Append("queue/logical_block_size");
     31 
     32   std::string file_contents;
     33   int blk_size;
     34 
     35   if (!base::ReadFileToString(info_file_path, &file_contents)) {
     36     return 0;
     37   }
     38   // In error cases, StringToInt will set blk_size to 0
     39   base::StringToInt(file_contents, &blk_size);
     40 
     41   return blk_size;
     42 }
     43 
     44 bool RemovableStorageProvider::PopulateDeviceList(
     45     scoped_refptr<StorageDeviceList> device_list) {
     46   struct udev* udev;
     47   struct udev_enumerate* enumerate;
     48   struct udev_list_entry* devices, *dev_list_entry;
     49   struct udev_device* dev, *parent;
     50 
     51   udev = udev_new();
     52   if (!udev) {
     53     DLOG(ERROR) << "Can't create udev";
     54     return false;
     55   }
     56 
     57   /* Create a list of the devices in the 'block' subsystem. */
     58   enumerate = udev_enumerate_new(udev);
     59 
     60   udev_enumerate_add_match_subsystem(enumerate, "block");
     61   udev_enumerate_scan_devices(enumerate);
     62   devices = udev_enumerate_get_list_entry(enumerate);
     63 
     64   udev_list_entry_foreach(dev_list_entry, devices) {
     65     const char* path = udev_list_entry_get_name(dev_list_entry);
     66     dev = udev_device_new_from_syspath(udev, path);
     67 
     68     const char* partition = udev_device_get_sysattr_value(dev, "partition");
     69     if (partition && get_int_attr(partition)){
     70       // This is a partition of a device, not the device itself
     71       continue;
     72     }
     73 
     74     const char* removable = udev_device_get_sysattr_value(dev, "removable");
     75     if (!removable || !get_int_attr(removable)) {
     76       // This is not a removable storage device.
     77       continue;
     78     }
     79 
     80     /* Get the parent SCSI device that contains the model
     81        and manufacturer.  You can look at the hierarchy with
     82        udevadm info -a -n /dev/<device> */
     83     parent = udev_device_get_parent_with_subsystem_devtype(
     84            dev,
     85            "scsi",
     86            NULL);
     87     if (!parent) {
     88       // this is not a usb device
     89       continue;
     90     }
     91 
     92     linked_ptr<api::image_writer_private::RemovableStorageDevice> device(
     93       new api::image_writer_private::RemovableStorageDevice());
     94     device->vendor = udev_device_get_sysattr_value(parent, "vendor");
     95     device->model = udev_device_get_sysattr_value(parent, "model");
     96     // TODO (smaskell): Don't expose raw device path
     97     device->storage_unit_id = udev_device_get_devnode(dev);
     98     device->capacity = get_int_attr(udev_device_get_sysattr_value(dev, "size"))
     99       * get_device_blk_size(device->storage_unit_id);
    100 
    101     device_list->data.push_back(device);
    102 
    103     udev_device_unref(dev);
    104   }
    105   /* Free the enumerator object */
    106   udev_enumerate_unref(enumerate);
    107   udev_unref(udev);
    108 
    109   return true;
    110 }
    111 
    112 } // namespace extensions
    113