1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
|
(* guestfs-inspection
* Copyright (C) 2009-2020 Red Hat Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*)
open Printf
open Unix
open Std_utils
open Utils
let map_block_devices f =
(* We need to get the devices in translated order. Use the
* same command that we use in device-name-translation.c.
*)
let path = "/dev/disk/by-path" in
let devs = command "ls" ["-1v"; path] in
let devs = String.trimr devs in
let devs = String.nsplit "\n" devs in
(* Delete entries for partitions. *)
let devs = List.filter (fun dev -> String.find dev "-part" = (-1)) devs in
let devs =
List.filter_map (
fun file ->
let dev = Unix_utils.Realpath.realpath (sprintf "%s/%s" path file) in
(* Ignore non-/dev devices, and return without /dev/ prefix. *)
if String.is_prefix dev "/dev/" then
Some (String.sub dev 5 (String.length dev - 5))
else
None
) devs in
let devs = List.filter (
fun dev ->
String.is_prefix dev "sd" ||
String.is_prefix dev "hd" ||
String.is_prefix dev "ubd" ||
String.is_prefix dev "vd" ||
String.is_prefix dev "sr"
) devs in
(* Ignore the root device. *)
let devs =
List.filter (fun dev -> not (is_root_device ("/dev/" ^ dev))) devs in
(* RHBZ#514505: Some versions of qemu <= 0.10 add a
* CD-ROM device even though we didn't request it. Try to
* detect this by seeing if the device contains media.
*)
let devs =
List.filter (
fun dev ->
try
with_openfile ("/dev/" ^ dev) [O_RDONLY; O_CLOEXEC] 0
(fun _ -> true)
with _ -> false
) devs in
(* Call the map function for the devices left in the list. *)
List.map f devs
(* md devices are not listed under /dev/disk/by-path, so won't *
* appear in the list above. Instead we look for them in /sys/block.
* We don't have to do anything special about device name translation.
*)
let map_md_devices f =
let devs = Sys.readdir "/sys/block" in
let devs = Array.to_list devs in
let devs = List.filter (
fun dev ->
String.is_prefix dev "md" &&
String.length dev >= 3 && Char.isdigit dev.[2]
) devs in
List.map f devs
let list_devices () =
(* For backwards compatibility, don't return MD devices in the list
* returned by guestfs_list_devices. This is because most API users
* expect that this list is effectively the same as the list of
* devices added by guestfs_add_drive.
*
* Also, MD devices are special devices - unlike the devices exposed
* by QEMU, and there is a special API for them,
* guestfs_list_md_devices.
*)
map_block_devices ((^) "/dev/")
let rec list_partitions () =
let partitions = map_block_devices add_partitions in
let md_partitions = map_md_devices add_partitions in
List.flatten partitions @ List.flatten md_partitions
and add_partitions dev =
(* Open the device's directory under /sys/block *)
let parts = Sys.readdir ("/sys/block/" ^ dev) in
let parts = Array.to_list parts in
(* Look in /sys/block/<device>/ for entries starting with
* <device>, eg. /sys/block/sda/sda1.
*)
let parts = List.filter (fun part -> String.is_prefix part dev) parts in
let parts = List.map ((^) "/dev/") parts in
sort_device_names parts
let nr_devices () = List.length (list_devices ())
let part_to_dev part =
let dev, part = split_device_partition part in
if part = 0 then
failwithf "device name is not a partition";
"/dev/" ^ dev
let part_to_partnum part =
let _, part = split_device_partition part in
if part = 0 then
failwithf "device name is not a partition";
part
let is_whole_device device =
(* A 'whole' block device will have a symlink to the device in its
* /sys/block directory
*)
assert (String.is_prefix device "/dev/");
let device = String.sub device 5 (String.length device - 5) in
let devpath = sprintf "/sys/block/%s/device" device in
try ignore (stat devpath); true
with Unix_error ((ENOENT|ENOTDIR), _, _) -> false
|