sysfs.cc
1 /* 2 * sysfs.cc 3 * 4 * 5 */ 6 7 #include "version.h" 8 #include "sysfs.h" 9 #include "osutils.h" 10 #include <limits.h> 11 #include <unistd.h> 12 #include <stdlib.h> 13 #include <stdio.h> 14 #include <string.h> 15 #include <dirent.h> 16 #include <sys/stat.h> 17 #include <sys/types.h> 18 #include <sys/mount.h> 19 20 21 __ID("@(#) $Id$"); 22 23 using namespace sysfs; 24 25 struct sysfs::entry_i 26 { 27 string devpath; 28 }; 29 30 struct sysfs_t 31 { 32 sysfs_t():path("/sys"), 33 temporary(false), 34 has_sysfs(false) 35 { 36 has_sysfs = exists(path + "/class/."); 37 38 if (!has_sysfs) // sysfs doesn't seem to be mounted 39 // try to mount it in a temporary directory 40 { 41 char buffer[50]; 42 char *tmpdir = NULL; 43 44 strncpy(buffer, 45 "/var/tmp/sys-XXXXXX", 46 sizeof(buffer)); 47 tmpdir = mkdtemp(buffer); 48 49 if (tmpdir) 50 { 51 temporary = true; 52 path = string(tmpdir); 53 chmod(tmpdir, 54 0000); // to make clear it is a mount point 55 mount("none", 56 path.c_str(), 57 "sysfs", 58 0, 59 NULL); 60 } 61 62 has_sysfs = exists(path + "/class/."); 63 } 64 } 65 66 ~sysfs_t() 67 { 68 if (temporary) 69 { 70 umount(path.c_str()); 71 rmdir(path.c_str()); 72 } 73 } 74 75 string path; 76 bool temporary; 77 bool has_sysfs; 78 }; 79 80 static sysfs_t fs; 81 82 static string sysfs_getbustype(const string & path) 83 { 84 struct dirent **namelist; 85 int i, n; 86 string bustype = ""; 87 88 /* 89 to determine to which kind of bus a device is connected: 90 - for each subdirectory of /sys/bus, 91 - look in ./devices/ for a link with the same basename as 'path' 92 - check if this link and 'path' point to the same inode 93 - if they do, the bus type is the name of the current directory 94 */ 95 pushd(fs.path + "/bus"); 96 n = scandir(".", &namelist, selectdir, alphasort); 97 popd(); 98 99 if (n <= 0) 100 return ""; 101 102 for (i = 0; i < n; i++) 103 { 104 string devname = 105 string(fs.path + "/bus/") + string(namelist[i]->d_name) + 106 "/devices/" + shortname(path); 107 108 if (samefile(devname, path)) 109 { 110 bustype = string(namelist[i]->d_name); 111 break; 112 } 113 free(namelist[i]); 114 } 115 116 for (int j = i; j < n; j++) 117 free(namelist[j]); 118 free(namelist); 119 120 return bustype; 121 } 122 123 124 static string sysfstopci(const string & path) 125 { 126 if (path.length() > strlen("XXXX:XX:XX.X")) 127 return "pci@" + path.substr(path.length() - strlen("XXXX:XX:XX.X")); 128 else 129 return ""; 130 } 131 132 133 static string sysfstoide(const string & path) 134 { 135 if (path.substr(0, 3) == "ide") 136 return "ide@" + path.substr(path.length() - 3); 137 else 138 return "ide@" + path; 139 } 140 141 142 static string sysfstobusinfo(const string & path) 143 { 144 string bustype = sysfs_getbustype(path); 145 146 if (bustype == "pci") 147 return sysfstopci(path); 148 149 if (bustype == "ide") 150 return sysfstoide(path); 151 152 if (bustype == "usb") 153 { 154 string name = shortname(path); 155 if (matches(name, "^[0-9]+-[0-9]+(\\.[0-9]+)*:[0-9]+\\.[0-9]+$")) 156 { 157 size_t colon = name.rfind(":"); 158 size_t dash = name.find("-"); 159 return "usb@" + name.substr(0, dash) + ":" + name.substr(dash+1, colon-dash-1); 160 } 161 } 162 163 if (bustype == "virtio") 164 { 165 string name = shortname(path); 166 if (name.compare(0, 6, "virtio") == 0) 167 return "virtio@" + name.substr(6); 168 else 169 return "virtio@" + name; 170 } 171 172 if (bustype == "vio") 173 return string("vio@") + shortname(path); 174 175 if (bustype == "ccw") 176 return string("ccw@") + shortname(path); 177 178 if (bustype == "ccwgroup") 179 { 180 // just report businfo for the first device in the group 181 // because the group doesn't really fit into lshw's tree model 182 string firstdev = realpath(path + "/cdev0"); 183 return sysfstobusinfo(firstdev); 184 } 185 186 return ""; 187 } 188 189 190 string entry::businfo() const 191 { 192 if(!This) return ""; 193 string result = sysfstobusinfo(This->devpath); 194 if (result.empty()) 195 result = sysfstobusinfo(dirname(This->devpath)); 196 return result; 197 } 198 199 200 static string finddevice(const string & name, const string & root = "") 201 { 202 struct dirent **namelist; 203 int n; 204 string result = ""; 205 206 if(exists(name)) 207 return root + "/" + name; 208 209 n = scandir(".", &namelist, selectdir, alphasort); 210 211 for (int i = 0; i < n; i++) 212 { 213 pushd(namelist[i]->d_name); 214 string findinchild = finddevice(name, root + "/" + string(namelist[i]->d_name)); 215 popd(); 216 217 free(namelist[i]); 218 if(findinchild != "") 219 { 220 result = findinchild; 221 } 222 } 223 free(namelist); 224 225 return result; 226 } 227 228 229 string sysfs_finddevice(const string & name) 230 { 231 string devices = fs.path + string("/devices/"); 232 string result = ""; 233 234 if(!pushd(devices)) 235 return ""; 236 result = finddevice(name); 237 popd(); 238 239 return result; 240 } 241 242 entry entry::leaf() const 243 { 244 if (hassubdir("device")) 245 return entry(This->devpath+"/device"); 246 247 return entry(This->devpath); 248 } 249 250 string entry::driver() const 251 { 252 string driverlink = This->devpath + "/driver"; 253 if (!exists(driverlink)) 254 return ""; 255 return shortname(readlink(driverlink)); 256 } 257 258 259 entry entry::byBus(string devbus, string devname) 260 { 261 entry e(fs.path + "/bus/" + devbus + "/devices/" + devname); 262 return e; 263 } 264 265 266 entry entry::byClass(string devclass, string devname) 267 { 268 entry e(fs.path + "/class/" + devclass + "/" + devname); 269 return e; 270 } 271 272 273 entry entry::byPath(string path) 274 { 275 entry e(fs.path + "/devices" + path); 276 return e; 277 } 278 279 280 entry::entry(const string & devpath) 281 { 282 This = new entry_i; 283 This->devpath = realpath(devpath); 284 } 285 286 287 entry & entry::operator =(const entry & e) 288 { 289 290 *This = *(e.This); 291 return *this; 292 } 293 294 295 entry::entry(const entry & e) 296 { 297 This = new entry_i; 298 299 *This = *(e.This); 300 } 301 302 303 entry::~entry() 304 { 305 delete This; 306 } 307 308 bool entry::hassubdir(const string & s) const 309 { 310 return exists(This->devpath + "/" + s); 311 } 312 313 314 string entry::name_in_class(const string & classname) const 315 { 316 string result = ""; 317 318 string classdir = This->devpath + "/" + classname; 319 if (!pushd(classdir)) 320 return result; 321 322 struct dirent **namelist = NULL; 323 int count = scandir(".", &namelist, selectdir, alphasort); 324 popd(); 325 326 if (count < 0) 327 return result; 328 329 // there should be at most one 330 for (int i = 0; i < count; i++) 331 { 332 result = namelist[i]->d_name; 333 free(namelist[i]); 334 } 335 free(namelist); 336 337 return result; 338 } 339 340 341 string entry::name() const 342 { 343 return shortname(This->devpath); 344 } 345 346 347 entry entry::parent() const 348 { 349 entry e(dirname(This->devpath)); 350 return e; 351 } 352 353 string entry::classname() const 354 { 355 return shortname(dirname(This->devpath)); 356 } 357 358 string entry::subsystem() const 359 { 360 return shortname(realpath(This->devpath+"/subsystem")); 361 } 362 363 bool entry::isvirtual() const 364 { 365 return shortname(dirname(dirname(This->devpath))) == "virtual"; 366 } 367 368 string entry::string_attr(const string & name, const string & def) const 369 { 370 return hw::strip(get_string(This->devpath + "/" + name, def)); 371 } 372 373 374 unsigned long long entry::hex_attr(const string & name, unsigned long long def) const 375 { 376 string val = string_attr(name, ""); 377 if (val.empty()) 378 return def; 379 return strtoull(val.c_str(), NULL, 16); 380 } 381 382 383 vector < string > entry::multiline_attr(const string & name) const 384 { 385 vector < string > lines; 386 loadfile(This->devpath + "/" + name, lines); 387 return lines; 388 } 389 390 391 string entry::modalias() const 392 { 393 return get_string(This->devpath+"/modalias"); 394 } 395 396 string entry::device() const 397 { 398 return get_string(This->devpath+"/device"); 399 } 400 401 string entry::vendor() const 402 { 403 return get_string(This->devpath+"/vendor"); 404 } 405 406 vector < entry > entry::devices() const 407 { 408 vector < entry > result; 409 410 if (!pushd(This->devpath)) 411 return result; 412 413 struct dirent **namelist; 414 int count = scandir(".", &namelist, selectdir, alphasort); 415 for (int i = 0; i < count; i ++) 416 { 417 entry e = sysfs::entry(This->devpath + "/" + string(namelist[i]->d_name)); 418 if(e.hassubdir("subsystem")) 419 result.push_back(e); 420 free(namelist[i]); 421 } 422 if (namelist) 423 free(namelist); 424 425 if(pushd("block")) 426 { 427 int count = scandir(".", &namelist, selectdir, alphasort); 428 for (int i = 0; i < count; i ++) 429 { 430 entry e = sysfs::entry(This->devpath + "/block/" + string(namelist[i]->d_name)); 431 if(e.hassubdir("subsystem")) 432 result.push_back(e); 433 free(namelist[i]); 434 } 435 if (namelist) 436 free(namelist); 437 popd(); 438 } 439 popd(); 440 return result; 441 } 442 443 vector < entry > sysfs::entries_by_bus(const string & busname) 444 { 445 vector < entry > result; 446 447 if (!pushd(fs.path + "/bus/" + busname + "/devices")) 448 return result; 449 450 struct dirent **namelist; 451 int count; 452 count = scandir(".", &namelist, selectlink, alphasort); 453 for (int i = 0; i < count; i ++) 454 { 455 entry e = sysfs::entry::byBus(busname, namelist[i]->d_name); 456 result.push_back(e); 457 free(namelist[i]); 458 } 459 popd(); 460 if (namelist) 461 free(namelist); 462 return result; 463 } 464 465 vector < entry > sysfs::entries_by_class(const string & classname) 466 { 467 vector < entry > result; 468 469 if (!pushd(fs.path + "/class/" + classname)) 470 return result; 471 472 struct dirent **namelist; 473 int count; 474 count = scandir(".", &namelist, selectlink, alphasort); 475 for (int i = 0; i < count; i ++) 476 { 477 entry e = sysfs::entry::byClass(classname, namelist[i]->d_name); 478 result.push_back(e); 479 free(namelist[i]); 480 } 481 popd(); 482 if (namelist) 483 free(namelist); 484 return result; 485 } 486 487 bool scan_sysfs(hwNode & n) 488 { 489 return false; 490 }