/// <summary> /// Gets the sysfs partitions. /// </summary> /// <returns> /// The sysfs partitions. /// </returns> /// <param name='diskPath'> /// Disk path. (eg /sys/devices/virtual/block/loop0) /// </param> /// <param name='diskName'> /// Disk name. (eg loop0) /// </param> internal List <Partition> GetSysfsPartitions(string diskPath, string diskName) { List <Partition> parts = new List <Partition>(); Mono.Unix.UnixDirectoryInfo diskDir = new Mono.Unix.UnixDirectoryInfo(diskPath); foreach (Mono.Unix.Native.Dirent part in diskDir.GetEntries(diskName + ".*")) { Partition p = new Partition(); p.Path = "/dev/" + part.d_name; p.Offset = ulong.Parse(File.ReadAllText(diskPath + "/" + part.d_name + "/start")); p.Size = long.Parse(File.ReadAllText(diskPath + "/" + part.d_name + "/size")); parts.Add(p); } return(parts); }
/// <summary> /// returns the partition name (sdX format) from any by-xxxx value (by-path, by-uuid...) /// </summary> /// <param name='partitionName'> /// Partition name. /// </param>/ private string GetPartitionFromPathOrUuid(string partitionName) { string[] disksBy = new string[] { "by-uuid", "by-path", "by-label", "by-id" }; foreach (string byType in disksBy) { Mono.Unix.UnixDirectoryInfo byUuidParts = new Mono.Unix.UnixDirectoryInfo("/dev/disk/" + byType); foreach (Mono.Unix.Native.Dirent d in byUuidParts.GetEntries()) { //Console.WriteLine ("______GetPartitionFromPathOrUuid looking cur entry="+d.d_name+", type="+d.d_type); if (d.d_type == 10 /*Mono.Unix.FileTypes.SymbolicLink*/) { string partOnlyName = ""; if (partitionName.LastIndexOf("/") >= 0) { partOnlyName = partitionName.Substring(partitionName.LastIndexOf("/") + 1); } else if (partitionName.IndexOf("UUID=") == 0) { partOnlyName = partitionName.Replace("UUID=", ""); } else { partOnlyName = partitionName; } //Console.WriteLine ("______GetPartitionFromPathOrUuid :d_name="+d.d_name+", partonlyname="+partOnlyName); if (d.d_name == partOnlyName) { Mono.Unix.UnixSymbolicLinkInfo devLink = new Mono.Unix.UnixSymbolicLinkInfo(byUuidParts + "/" + d.d_name); //Console.WriteLine ("______GetPartitionFromPathOrUuid : "+partitionName+" --> /dev/"+devLink.ContentsPath.Substring(devLink.ContentsPath.LastIndexOf('/')+1)); return("/dev/" + devLink.ContentsPath.Substring(devLink.ContentsPath.LastIndexOf('/') + 1)); } } } } // partition was probably referenced by its devics (/dev/sdXX) path, nothing to do return(partitionName); }
/// <summary> /// Snapshots the VM and gets its (maybe partial) StorageLayout /// </summary> /// <returns> /// The physical disks. /// </returns> retrieve a public StorageLayout BuildStorageLayout() { List <FileSystem> fsList = new List <FileSystem>(); if (this.loopDevices == null) // local layout { fsList = GetMountedFilesystems(); } /*else * fsList = MountLoopFilesystems();*/ Mono.Unix.UnixDirectoryInfo ud = new Mono.Unix.UnixDirectoryInfo(sysfsRoot); foreach (Mono.Unix.Native.Dirent scsiDevice in ud.GetEntries()) { if (this.IsLayoutLoop && !loopDevices.Contains(scsiDevice.d_name)) { continue; } Console.WriteLine("device subsystem name : " + scsiDevice.d_name); Disk disk = new Disk(); string path = ""; if (this.IsLayoutLoop) { path = sysfsRoot + "/" + scsiDevice; } else { path = sysfsRoot + "/" + scsiDevice + "/device/block"; } if (!Directory.Exists(path)) { disk.Enabled = false; } else { disk.Enabled = true; } string diskName = ""; if (this.IsLayoutLoop) { diskName = scsiDevice.d_name; } else { Mono.Unix.UnixDirectoryInfo scsiPath = new Mono.Unix.UnixDirectoryInfo(path); diskName = scsiPath.GetEntries()[0].d_name; path += "/" + diskName; } disk.Path = "/dev/" + diskName; disk.Size = long.Parse(File.ReadAllText(path + "/size")); //disk.Enabled = File.ReadAllText(path+"/removable").StartsWith("0"); if (!File.ReadAllText(path + "/removable").StartsWith("0")) // exclude removable devices (external drives, usb keys...) { continue; } disk.Enabled = true; disk.SectorSize = uint.Parse(File.ReadAllText(path + "/queue/hw_sector_size")); if (this.IsLayoutLoop) { disk.Type = DiskType.Loop; } try{ disk.BlockStream = new FileStream(disk.Path, System.IO.FileMode.Open); } catch (Exception e) { Console.WriteLine("ERROR : " + e.Message); } //MBR mbr = new MBR(disk.MbrBytes); // gather what MBR sees //disk.Children.AddRange(StorageLayoutManager.GetPartitionsFromMBR(disk)); // now compare with what is inside sysfs and complete information List <Partition> sysfsParts = GetSysfsPartitions(path, diskName); foreach (Partition sysfsP in sysfsParts) { //Console.WriteLine ("@@@@@@@@@@@@@@@@ GetSysfsPartitions SYS current="+sysfsP.Offset+" ("+sysfsP.Path+")"); //foreach(Partition p in disk.Children){ //Console.WriteLine ("@@@@@@@@@@@@@@@@ GetSysfsPartitions MBR current="+p.Offset); //if (p.Offset != sysfsP.Offset) continue; //Console.WriteLine ("@@@@@@@@@@@@@@@@ GetSysfsPartitions MATCHED MBR partition "+sysfsP.Path); //p.Path = sysfsP.Path; //p.Size = sysfsP.Size; foreach (FileSystem f in fsList) { string fsDevName = GetPartitionFromPathOrUuid(f.Path); //Console.WriteLine ("@@@@@@@@@@@@@@@@ GetSysfsPartitions FS current="+f.Path+", mntpt="+f.MountPoint+", mapped="+fsDevName); if (fsDevName == sysfsP.Path) { sysfsP.AddChild(f); //Console.WriteLine ("@@@@@@@@@@@@@@@@ GetSysfsPartitions FS MATCHED"+Environment.NewLine); } } //break; disk.AddChild(sysfsP); //} } layout.Entries.Add(disk); } // end foreach // if using loop devices, try to detect fses and mount only now that we have a complete view and access to disks and parts. // doing it so late allows to detect things like LVM volumes spread on multiple partitions or disks if (fsList.Count == 0) { //1- try to mount the loop partitions foreach (Partition p in layout.GetAllPartitions(null)) { // quick, hackish and dirty way to avoid mounting an 'extended' partition, // which sould result in an endless loop while burning 100% cPU in zombie state. Yup. Kernel bug? if (p.Size == 2) { continue; } FileSystem mountedFS = MountLoopFilesystem(p); if (mountedFS != null) { p.AddChild(mountedFS); } } // 2- try to access and read VM /etc/fstab, from there guess the original loop FS mountpoint Dictionary <string, string> originalMountpoints = TryGuessOriginalMountPoint(layout.GetAllFileSystems(null)); foreach (FileSystem fs in layout.GetAllFileSystems(null)) { foreach (KeyValuePair <string, string> mp in originalMountpoints) { string fsBlockDevice = GetPartitionFromPathOrUuid(mp.Key); //Console.WriteLine ("ORIGINAL LAYOUT FS: mountpoint key="+mp.Key+", value="+mp.Value+", fromuuid="+fsBlockDevice+", fs.path="+fs.Path+", fs.mountpoint="+fs.MountPoint); if (fsBlockDevice == fs.Path) { fs.OriginalMountPoint = mp.Value; if (LogEvent != null) { LogEvent(this, new LogEventArgs(0, Severity.DEBUG, "Filesystem at mountpoint '" + fs.MountPoint + "' was originally mounted as '" + fs.OriginalMountPoint + "'")); } break;; } } } } return(layout); }