Back to index

lshw  02.16
sysfs.cc
Go to the documentation of this file.
00001 /*
00002  * sysfs.cc
00003  *
00004  *
00005  */
00006 
00007 #include "version.h"
00008 #include "sysfs.h"
00009 #include "osutils.h"
00010 #include <limits.h>
00011 #include <unistd.h>
00012 #include <stdlib.h>
00013 #include <stdio.h>
00014 #include <string.h>
00015 #include <dirent.h>
00016 #include <libgen.h>
00017 #include <sys/stat.h>
00018 #include <sys/types.h>
00019 #include <sys/mount.h>
00020 
00021 __ID("@(#) $Id: sysfs.cc 2433 2012-01-10 22:01:30Z lyonel $");
00022 
00023 using namespace sysfs;
00024 
00025 struct sysfs::entry_i
00026 {
00027   string devclass;
00028   string devbus;
00029   string devname;
00030 };
00031 
00032 struct sysfs_t
00033 {
00034   sysfs_t():path("/sys"),
00035     temporary(false),
00036     has_sysfs(false)
00037   {
00038     has_sysfs = exists(path + "/class/.");
00039 
00040     if (!has_sysfs)                               // sysfs doesn't seem to be mounted
00041 // try to mount it in a temporary directory
00042     {
00043       char buffer[50];
00044       char *tmpdir = NULL;
00045 
00046       strncpy(buffer,
00047         "/var/tmp/sys-XXXXXX",
00048         sizeof(buffer));
00049       tmpdir = mkdtemp(buffer);
00050 
00051       if (tmpdir)
00052       {
00053         temporary = true;
00054         path = string(tmpdir);
00055         chmod(tmpdir,
00056           0000);                                  // to make clear it is a mount point
00057         mount("none",
00058           path.c_str(),
00059           "sysfs",
00060           0,
00061           NULL);
00062       }
00063 
00064       has_sysfs = exists(path + "/classes/.");
00065     }
00066   }
00067 
00068   ~sysfs_t()
00069   {
00070     if (temporary)
00071     {
00072       umount(path.c_str());
00073       rmdir(path.c_str());
00074     }
00075   }
00076 
00077   string path;
00078   bool temporary;
00079   bool has_sysfs;
00080 };
00081 
00082 static sysfs_t fs;
00083 
00084 static string sysfs_getbustype(const string & path)
00085 {
00086   struct dirent **namelist;
00087   int i, n;
00088   string devname;
00089 
00090 /*
00091   to determine to which kind of bus a device is connected:
00092   - for each subdirectory of /sys/bus,
00093   - look in ./devices/ for a link with the same basename as 'path'
00094   - check if this link and 'path' point to the same inode
00095   - if they do, the bus type is the name of the current directory
00096  */
00097   pushd(fs.path + "/bus");
00098   n = scandir(".", &namelist, selectdir, alphasort);
00099   popd();
00100 
00101   for (i = 0; i < n; i++)
00102   {
00103     devname =
00104       string(fs.path + "/bus/") + string(namelist[i]->d_name) +
00105       "/devices/" + basename((char *) path.c_str());
00106 
00107     if (samefile(devname, path))
00108       return string(namelist[i]->d_name);
00109   }
00110 
00111   return "";
00112 }
00113 
00114 
00115 static string sysfstopci(const string & path)
00116 {
00117   if (path.length() > strlen("XXXX:XX:XX.X"))
00118     return "pci@" + path.substr(path.length() - strlen("XXXX:XX:XX.X"));
00119   else
00120     return "";
00121 }
00122 
00123 
00124 static string sysfstoide(const string & path)
00125 {
00126   if (path.substr(0, 3) == "ide")
00127     return "ide@" + path.substr(path.length() - 3);
00128   else
00129     return "ide@" + path;
00130 }
00131 
00132 
00133 static string sysfstobusinfo(const string & path)
00134 {
00135   string bustype = sysfs_getbustype(path);
00136 
00137   if (bustype == "pci")
00138     return sysfstopci(path);
00139 
00140   if (bustype == "ide")
00141     return sysfstoide(path);
00142 
00143   return "";
00144 }
00145 
00146 
00147 static string sysfs_getbusinfo_byclass(const string & devclass, const string & devname)
00148 {
00149   string device =
00150     fs.path + string("/class/") + devclass + string("/") + devname + "/device";
00151   string result = "";
00152   int i = 0;
00153 
00154   while((result == "") && (i<2))                  // device may point to /businfo or /businfo/devname
00155   {
00156     if(!exists(device)) return "";
00157     result = sysfstobusinfo(realpath(device));
00158     device += "/../" + devname + "/..";
00159     i++;
00160   }
00161 
00162   return result;
00163 }
00164 
00165 
00166 static string sysfs_getbusinfo_bybus(const string & devbus, const string & devname)
00167 {
00168   string device =
00169     fs.path + string("/bus/") + devbus + string("/devices/") + devname;
00170   char buffer[PATH_MAX + 1];
00171 
00172   if (!realpath(device.c_str(), buffer))
00173     return "";
00174 
00175   return sysfstobusinfo(hw::strip(buffer));
00176 }
00177 
00178 
00179 string sysfs_getbusinfo(const entry & e)
00180 {
00181   if(e.This->devclass != "")
00182     return sysfs_getbusinfo_byclass(e.This->devclass, e.This->devname);
00183   if(e.This->devbus != "")
00184     return sysfs_getbusinfo_bybus(e.This->devbus, e.This->devname);
00185   return "";
00186 }
00187 
00188 
00189 static string finddevice(const string & name, const string & root = "")
00190 {
00191   struct dirent **namelist;
00192   int n;
00193   string result = "";
00194 
00195   if(exists(name))
00196     return root + "/" + name;
00197 
00198   n = scandir(".", &namelist, selectdir, alphasort);
00199 
00200   for (int i = 0; i < n; i++)
00201   {
00202     pushd(namelist[i]->d_name);
00203     string findinchild = finddevice(name, root + "/" + string(namelist[i]->d_name));
00204     popd();
00205 
00206     free(namelist[i]);
00207     if(findinchild != "")
00208     {
00209       result = findinchild;
00210     }
00211   }
00212   free(namelist);
00213 
00214   return result;
00215 }
00216 
00217 
00218 string sysfs_finddevice(const string & name)
00219 {
00220   string devices = fs.path + string("/devices/");
00221   string result = "";
00222 
00223   if(!pushd(devices))
00224     return "";
00225   result = finddevice(name);
00226   popd();
00227 
00228   return result;
00229 }
00230 
00231 
00232 string sysfs_getdriver(const string & devclass,
00233 const string & devname)
00234 {
00235   string driverpath =
00236     fs.path + string("/class/") + devclass + string("/") + devname + "/";
00237   string driver = driverpath + "/driver";
00238   char buffer[PATH_MAX + 1];
00239   int namelen = 0;
00240 
00241   if ((namelen = readlink(driver.c_str(), buffer, sizeof(buffer))) < 0)
00242     return "";
00243 
00244   return string(basename(buffer));
00245 }
00246 
00247 
00248 entry entry::byBus(string devbus, string devname)
00249 {
00250   entry e;
00251 
00252   e.This->devbus = devbus;
00253   e.This->devname = devname;
00254 
00255   return e;
00256 }
00257 
00258 
00259 entry entry::byClass(string devclass, string devname)
00260 {
00261   entry e;
00262 
00263   e.This->devclass = devclass;
00264   e.This->devname = devname;
00265 
00266   return e;
00267 }
00268 
00269 
00270 entry::entry()
00271 {
00272   This = new entry_i;
00273 }
00274 
00275 
00276 entry & entry::operator =(const entry & e)
00277 {
00278 
00279   *This = *(e.This);
00280   return *this;
00281 }
00282 
00283 
00284 entry::entry(const entry & e)
00285 {
00286   This = new entry_i;
00287 
00288   *This = *(e.This);
00289 }
00290 
00291 
00292 entry::~entry()
00293 {
00294   delete This;
00295 }
00296 
00297 bool entry::hassubdir(const string & s)
00298 {
00299   if(This->devclass != "")
00300     return exists(fs.path + string("/class/") + This->devclass + string("/") + This->devname + "/" + s);
00301   
00302   if(This->devbus != "")
00303     return exists(fs.path + string("/bus/") + This->devbus + string("/devices/") + This->devname + string("/") + s);
00304 
00305   return false;
00306 }
00307 
00308 bool scan_sysfs(hwNode & n)
00309 {
00310   return false;
00311 }