1 module unde.lsblk; 2 3 import unde.lib; 4 import unde.slash; 5 6 import std.conv; 7 import std..string; 8 import std.process; 9 import std.array; 10 import std.regex; 11 12 version (Windows) 13 { 14 import core.sys.windows.winbase; 15 import core.sys.windows.winnt; 16 import core.stdc.stdarg; 17 import std.utf; 18 import std.stdio; 19 import std.format; 20 } 21 22 struct LsblkInfo{ 23 string name; 24 string mountpoint; 25 string fstype; 26 string label; 27 string uuid; 28 ulong size; 29 ulong used; 30 ulong avail; 31 } 32 33 version (Posix) 34 { 35 private string slashXToString(string str) 36 { 37 string res = ""; 38 for (int i=0; i < str.length; i++) 39 { 40 if (str.length - i >= 4) 41 { 42 if (str[i] == '\\' && str[i+1] == 'x') 43 { 44 string s; 45 res ~= parse!ubyte(s=str[i+2..i+4], 16); 46 i+=3; 47 continue; 48 } 49 } 50 res ~= str[i]; 51 } 52 return res; 53 } 54 55 unittest 56 { 57 assert(slashXToString("a\\x20b") == "a b"); 58 assert(slashXToString("ab\\x20") == "ab "); 59 assert(slashXToString("ab\\x2") == "ab\\x2"); 60 } 61 62 void df(ref LsblkInfo lsblk_info) 63 { 64 auto df_pipes = pipeProcess(["df", "--output=size,used,avail", lsblk_info.mountpoint], Redirect.stdout); 65 scope(exit) wait(df_pipes.pid); 66 67 int l=0; 68 foreach (df_line; df_pipes.stdout.byLine) 69 { 70 if (l == 1) 71 { 72 auto match = matchFirst(df_line, regex(`(\d+) +(\d+) +(\d+)`)); 73 if (match) 74 { 75 lsblk_info.size = to!ulong(match[1])*1024; 76 lsblk_info.used = to!ulong(match[2])*1024; 77 lsblk_info.avail = to!ulong(match[3])*1024; 78 } 79 } 80 l++; 81 } 82 } 83 } 84 85 version(Windows) 86 { 87 void df(ref LsblkInfo lsblk_info) 88 { 89 uint sectors_per_cluster; 90 uint bytes_per_sector; 91 uint number_of_free_clusters; 92 uint total_number_of_clusters; 93 94 auto res = GetDiskFreeSpace( 95 toUTF16z(lsblk_info.name~"\\"), 96 §ors_per_cluster, 97 &bytes_per_sector, 98 &number_of_free_clusters, 99 &total_number_of_clusters); 100 if (!res) 101 { 102 throw new Exception("GetDiskFreeSpace: "~GetErrorMessage()); 103 } 104 105 lsblk_info.size = cast(ulong)total_number_of_clusters * sectors_per_cluster * bytes_per_sector; 106 lsblk_info.avail = cast(ulong)number_of_free_clusters * sectors_per_cluster * bytes_per_sector; 107 lsblk_info.used = lsblk_info.size - lsblk_info.avail; 108 } 109 } 110 111 void lsblk(ref LsblkInfo[string] lsblk) 112 { 113 version(Posix) 114 { 115 auto pipes = pipeProcess(["lsblk", "-rno", "NAME,MOUNTPOINT,FSTYPE,LABEL,UUID"], Redirect.stdout); 116 scope(exit) wait(pipes.pid); 117 118 foreach (line; pipes.stdout.byLine) 119 { 120 LsblkInfo lsblk_info; 121 122 foreach(i, arg; split(line, " ")) 123 { 124 string im_arg = arg.idup(); 125 switch (i) 126 { 127 case 0: 128 lsblk_info.name = slashXToString(im_arg); 129 break; 130 case 1: 131 lsblk_info.mountpoint = slashXToString(im_arg); 132 break; 133 case 2: 134 lsblk_info.fstype = slashXToString(im_arg); 135 break; 136 case 3: 137 lsblk_info.label = slashXToString(im_arg); 138 break; 139 case 4: 140 lsblk_info.uuid = slashXToString(im_arg); 141 break; 142 default: 143 assert(0, "lsblk returned line with more than 2 spaces"); 144 } 145 } 146 147 if (lsblk_info.mountpoint > "" && lsblk_info.mountpoint != "[SWAP]") 148 { 149 df(lsblk_info); 150 lsblk[lsblk_info.mountpoint] = lsblk_info; 151 } 152 } 153 } 154 else version(Windows) 155 { 156 LsblkInfo lsblk_info; 157 lsblk_info.name = "My Computer"; 158 lsblk_info.mountpoint = SL; 159 lsblk_info.uuid = "my_computer"; 160 lsblk[lsblk_info.mountpoint] = lsblk_info; 161 LsblkInfo *mycomp_info = &lsblk[lsblk_info.mountpoint]; 162 163 auto drives = GetLogicalDrives(); 164 if (drives == 0) 165 { 166 throw new Exception("GetLogicalDrives: "~GetErrorMessage()); 167 } 168 foreach (i; 0..32) 169 { 170 char letter = cast(char)('A' + i); 171 if (drives & (1 << i)) 172 { 173 wchar[1024] volumename; 174 uint serialnumber; 175 uint maximum_components_length; 176 uint file_system_flags; 177 wchar[1024] file_system_name; 178 179 auto res = GetVolumeInformation( 180 toUTF16z(letter~":\\"), 181 volumename.ptr, 182 volumename.length, 183 &serialnumber, 184 &maximum_components_length, 185 &file_system_flags, 186 file_system_name.ptr, 187 file_system_name.length); 188 lsblk_info = LsblkInfo(); 189 lsblk_info.name = letter~":"; 190 lsblk_info.mountpoint = letter~":"; 191 if (res) 192 { 193 lsblk_info.fstype = to!(char[])(from_char_array(file_system_name)); 194 lsblk_info.uuid = format("%X", serialnumber); 195 lsblk_info.label = to!string(from_char_array(volumename)); 196 197 df(lsblk_info); 198 199 /*writefln("%s:", letter); 200 writefln("\tvolumename=%s", to!string(from_char_array(volumename))); 201 writefln("\tserialnumber=%X", serialnumber); 202 writefln("\tmaximum_components_length=%d", maximum_components_length); 203 writefln("\tfile_system_flags=%X", file_system_flags); 204 writefln("\tfile_system_name=%s", to!(char[])(from_char_array(file_system_name))); 205 writefln("\tsize=%s", lsblk_info.size); 206 writefln("\tused=%s", lsblk_info.used); 207 writefln("\tavail=%s", lsblk_info.avail);*/ 208 209 mycomp_info.size += lsblk_info.size; 210 mycomp_info.used += lsblk_info.used; 211 mycomp_info.avail += lsblk_info.avail; 212 } 213 else 214 { 215 lsblk_info.label = GetErrorMessage(); 216 //writefln("%s: %s", letter, lsblk_info.label); 217 } 218 lsblk[lsblk_info.mountpoint] = lsblk_info; 219 220 } 221 } 222 } 223 }