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 "chrome/browser/extensions/api/music_manager_private/device_id.h" 6 7#include <CoreFoundation/CoreFoundation.h> 8#include <DiskArbitration/DASession.h> 9#include <DiskArbitration/DADisk.h> 10#include <sys/mount.h> 11 12#include "base/bind.h" 13#include "base/mac/foundation_util.h" 14#include "base/mac/scoped_cftyperef.h" 15#include "base/strings/sys_string_conversions.h" 16#include "content/public/browser/browser_thread.h" 17 18namespace { 19 20const char kRootDirectory[] = "/"; 21 22// Return the BSD name (e.g. '/dev/disk1') of the root directory by enumerating 23// through the mounted volumes . 24// Return "" if an error occured. 25std::string FindBSDNameOfSystemDisk() { 26 struct statfs* mounted_volumes; 27 int num_volumes = getmntinfo(&mounted_volumes, 0); 28 if (num_volumes == 0) { 29 VLOG(1) << "Cannot enumerate list of mounted volumes."; 30 return std::string(); 31 } 32 33 for (int i = 0; i < num_volumes; i++) { 34 struct statfs* vol = &mounted_volumes[i]; 35 if (std::string(vol->f_mntonname) == kRootDirectory) { 36 return std::string(vol->f_mntfromname); 37 } 38 } 39 40 VLOG(1) << "Cannot find disk mounted as '" << kRootDirectory << "'."; 41 return std::string(); 42} 43 44// Return the Volume UUID property of a BSD disk name (e.g. '/dev/disk1'). 45// Return "" if an error occured. 46std::string GetVolumeUUIDFromBSDName(const std::string& bsd_name) { 47 const CFAllocatorRef allocator = NULL; 48 49 base::ScopedCFTypeRef<DASessionRef> session(DASessionCreate(allocator)); 50 if (session.get() == NULL) { 51 VLOG(1) << "Error creating DA Session."; 52 return std::string(); 53 } 54 55 base::ScopedCFTypeRef<DADiskRef> disk( 56 DADiskCreateFromBSDName(allocator, session, bsd_name.c_str())); 57 if (disk.get() == NULL) { 58 VLOG(1) << "Error creating DA disk from BSD disk name."; 59 return std::string(); 60 } 61 62 base::ScopedCFTypeRef<CFDictionaryRef> disk_description( 63 DADiskCopyDescription(disk)); 64 if (disk_description.get() == NULL) { 65 VLOG(1) << "Error getting disk description."; 66 return std::string(); 67 } 68 69 CFUUIDRef volume_uuid = base::mac::GetValueFromDictionary<CFUUIDRef>( 70 disk_description, 71 kDADiskDescriptionVolumeUUIDKey); 72 if (volume_uuid == NULL) { 73 VLOG(1) << "Error getting volume UUID of disk."; 74 return std::string(); 75 } 76 77 base::ScopedCFTypeRef<CFStringRef> volume_uuid_string( 78 CFUUIDCreateString(allocator, volume_uuid)); 79 if (volume_uuid_string.get() == NULL) { 80 VLOG(1) << "Error creating string from CSStringRef."; 81 return std::string(); 82 } 83 84 return base::SysCFStringRefToUTF8(volume_uuid_string.get()); 85} 86 87// Return Volume UUID property of disk mounted as "/". 88void GetVolumeUUID(const extensions::api::DeviceId::IdCallback& callback) { 89 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE)); 90 91 std::string result; 92 std::string bsd_name = FindBSDNameOfSystemDisk(); 93 if (!bsd_name.empty()) { 94 VLOG(4) << "BSD name of root directory: '" << bsd_name << "'"; 95 result = GetVolumeUUIDFromBSDName(bsd_name); 96 } 97 content::BrowserThread::PostTask( 98 content::BrowserThread::UI, 99 FROM_HERE, 100 base::Bind(callback, result)); 101} 102 103} 104 105namespace extensions { 106namespace api { 107 108// MacOS: Return Volume UUID property of disk mounted as "/". 109/* static */ 110void DeviceId::GetMachineId(const IdCallback& callback) { 111 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 112 113 content::BrowserThread::PostTask( 114 content::BrowserThread::FILE, 115 FROM_HERE, 116 base::Bind(GetVolumeUUID, callback)); 117} 118 119} // namespace api 120} // namespace extensions 121