Modalias.cc

Go to the documentation of this file.
00001 /*---------------------------------------------------------------------\
00002 |                          ____ _   __ __ ___                          |
00003 |                         |__  / \ / / . \ . \                         |
00004 |                           / / \ V /|  _/  _/                         |
00005 |                          / /__ | | | | | |                           |
00006 |                         /_____||_| |_| |_|                           |
00007 |                                                                      |
00008 \---------------------------------------------------------------------*/
00012 #include <iostream>
00013 
00014 #undef ZYPP_BASE_LOGGER_LOGGROUP
00015 #define ZYPP_BASE_LOGGER_LOGGROUP "MODALIAS"
00016 #include "zypp/base/Logger.h"
00017 
00018 #include "zypp/target/modalias/Modalias.h"
00019 
00020 #include <cstdlib>
00021 #include <stdio.h>
00022 #include <sys/types.h>
00023 #include <sys/stat.h>
00024 #include <fcntl.h>
00025 #include <unistd.h>
00026 #include <dirent.h>
00027 #include <fnmatch.h>
00028 #include <cstring>
00029 #include <cerrno>
00030 
00031 using std::endl;
00032 using std::string;
00033 
00034 
00036 namespace zypp
00037 { 
00038 
00039   namespace target
00040   { 
00041 
00042     namespace modalias
00043     { 
00044 
00045 /*
00046  * For each file in the directory PATH other than . and .., call
00047  * FUNC with the arguments PATH, the file's name, and ARG.
00048  *
00049  * If FUNC returns a non-zero return value, stop reading the directory
00050  * and return that value. Returns -1 if an error occurs.
00051  */
00052 static int
00053 foreach_file(const char *path, int (*func)(const char *, const char *, void *),
00054              void *arg)
00055 {
00056         DIR *dir;
00057         struct dirent *dirent;
00058         int ret = 0;
00059 
00060         if (!(dir = opendir(path)))
00061                 return -1;
00062         while ((dirent = readdir(dir)) != NULL) {
00063 
00064                 if (strcmp(dirent->d_name, ".") == 0 ||
00065                     strcmp(dirent->d_name, "..") == 0)
00066                         continue;
00067                 if ((ret = func(path, dirent->d_name, arg)) != 0)
00068                         break;
00069         }
00070         if (closedir(dir) != 0)
00071                 return -1;
00072         return ret;
00073 }
00074 
00075 struct modalias_list {
00076         char *modalias;
00077         struct modalias_list *next;
00078 };
00079 
00080 /*
00081  * If the device identified by /sys/bus/BUS/devices/DEVICE has a
00082  * module aliases, remember that alias on the linked modalias list
00083  * passed in in ARG.
00084  */
00085 static int
00086 iterate_devices(const char *dir, const char *file, void *arg)
00087 {
00088         char path[PATH_MAX];
00089         int fd;
00090         ssize_t len;
00091         char modalias[PATH_MAX];
00092         struct modalias_list **list = (struct modalias_list **)arg, *entry;
00093         int ret = 0;
00094 
00095         snprintf(path, sizeof(path), "%s/%s/modalias", dir, file);
00096         if ((fd = open(path, O_RDONLY)) == -1)
00097                 return 0;
00098         len = read(fd, modalias, sizeof(modalias) - 1);
00099         if (len < 0)
00100                 goto out;
00101         while (len > 0 && modalias[len - 1] == '\n')
00102                 len--;
00103         modalias[len] = 0;
00104 
00105         if ((entry = (struct modalias_list *)malloc(sizeof(*entry))) == NULL) {
00106                 ret = -1;
00107                 goto out;
00108         }
00109         if ((entry->modalias = strdup(modalias)) == NULL) {
00110                 free(entry);
00111                 ret = -1;
00112                 goto out;
00113         }
00114         entry->next = *list;
00115         *list = entry;
00116         XXX << "system modalias: " << entry->modalias << endl;
00117 
00118 out:
00119         (void) close(fd);
00120         return 0;
00121 }
00122 
00123 /*
00124  * Iterate over all devices on a bus (/sys/bus/BUS/devices/<*>)
00125  * and remembers all module aliases for those devices on
00126  * the linked modalias list passed in in ARG.
00127  */
00128 static int
00129 iterate_busses(const char *dir, const char *file, void *arg)
00130 {
00131         char path[PATH_MAX];
00132 
00133         snprintf(path, sizeof(path), "%s/%s/devices", dir, file);
00134         (void) foreach_file(path, iterate_devices, arg);
00135         return 0;
00136 }
00137 
00139 //
00140 //      CLASS NAME : Modalias::Impl
00141 //
00143 struct Modalias::Impl
00144 {
00145     struct modalias_list *_modaliases;
00146 
00148     Impl()
00149         : _modaliases(0)
00150     {
00151         foreach_file( "/sys/bus", iterate_busses, &_modaliases );
00152         char path[PATH_MAX];
00153         const char *dir = getenv("ZYPP_MODALIAS_SYSFS");
00154         snprintf(path, sizeof(path), "%s/bus", dir ? dir : "/sys");
00155         DBG << "Using /sys path : " << path << endl;
00156         foreach_file( path, iterate_busses, &_modaliases );
00157     }
00158 
00160     ~Impl()
00161     {
00162         while (_modaliases != NULL) {
00163             struct modalias_list *l = _modaliases;
00164             _modaliases = _modaliases->next;
00165             free(l->modalias);
00166             free(l);
00167         }
00168     }
00169 
00174     bool query( const std::string & cap_r ) const
00175     { return query( cap_r, Rel::ANY, std::string() ); }
00176 
00180     bool  query( const std::string & cap_r,
00181                Rel op_r,
00182                const std::string & val_r ) const
00183     {
00184 
00185         /*
00186          * Check if a device on the system matches a modalias PATTERN.
00187          *
00188          * Returns NULL if no matching device is found, and the modalias
00189          * of the first matching device otherwise. (More than one device
00190          * may match a given pattern.)
00191          *
00192          * On a system that has the following device,
00193          *
00194          *   pci:v00008086d0000265Asv00008086sd00004556bc0Csc03i00
00195          *
00196          * modalias_matches("pci:v00008086d0000265Asv*sd*bc*sc*i*") will
00197          * return a non-NULL value.
00198          */
00199 
00200         struct modalias_list *l;
00201         for (l = _modaliases; l; l = l->next) {
00202             if ( fnmatch( cap_r.c_str(), l->modalias, 0 ) == 0 )
00203                 return true;
00204         }
00205         return false;
00206 
00207 #if 0           // once we get a capabilities values, we can compare it ...
00208             if (value) {
00209                 string lhs (value);
00210                 int cmp = (lhs != rhs) ? ((lhs < rhs) ? -1 : 1) : 0;
00211 
00212                 switch ( relation.inSwitch() )
00213                 {
00214                     case Rel::EQ_e:
00215                         res = (cmp == 0);
00216                         break;
00217                     case Rel::NE_e:
00218                         res = (cmp != 0);
00219                         break;
00220                     case Rel::LT_e:
00221                         res = (cmp == -1);
00222                         break;
00223                     case Rel::LE_e:
00224                         res = (cmp != 1);
00225                         break;
00226                     case Rel::GT_e:
00227                         res = (cmp == 1);
00228                         break;
00229                     case Rel::GE_e:
00230                         res = (cmp != -1);
00231                         break;
00232                     case Rel::ANY_e:
00233                         res = true;
00234                         break;
00235                     case Rel::NONE_e:
00236                         res = false;
00237                         break;
00238                     default:
00239                         // We shouldn't get here.
00240                         INT << "Unknown relational opertor '" << relation << "' treated as  'NONE'" << endl;
00241                         break;
00242                 }
00243             }
00244 #endif
00245 
00246     }
00247 
00248   public:
00250     static shared_ptr<Impl> nullimpl()
00251     {
00252         static shared_ptr<Impl> _nullimpl( new Impl );
00253         return _nullimpl;
00254     }
00255 
00256 };  // struct Modalias::Impl
00257 
00259 
00264 inline std::ostream & operator<<( std::ostream & str, const Modalias::Impl & obj )
00265 {
00266   return str << "Modalias::Impl";
00267 }
00268 
00270 //
00271 //      CLASS NAME : Modalias
00272 //
00274 
00276 //
00277 //      METHOD NAME : Modalias::Modalias
00278 //      METHOD TYPE : Ctor
00279 //
00280 Modalias::Modalias()
00281 : _pimpl( Impl::nullimpl() )
00282 {}
00283 
00285 //
00286 //      METHOD NAME : Modalias::~Modalias
00287 //      METHOD TYPE : Dtor
00288 //
00289 Modalias::~Modalias()
00290 {}
00291 
00293 //
00294 //      METHOD NAME : Modalias::instance
00295 //      METHOD TYPE : Modalias &
00296 //
00297 Modalias & Modalias::instance()
00298 {
00299   static Modalias _singleton;
00300   return _singleton;
00301 }
00302 
00304 // Foreward to implenemtation
00306 
00307 bool Modalias::query( const std::string & cap_r ) const
00308 { return _pimpl->query( cap_r ); }
00309 
00310 bool Modalias::query( const std::string & cap_r,
00311                  Rel op_r,
00312                  const std::string & val_r ) const
00313 { return _pimpl->query( cap_r, op_r, val_r ); }
00314 
00315 /******************************************************************
00316 **
00317 **      FUNCTION NAME : operator<<
00318 **      FUNCTION TYPE : std::ostream &
00319 */
00320 std::ostream & operator<<( std::ostream & str, const Modalias & obj )
00321 {
00322   return str << *obj._pimpl;
00323 }
00324 
00326     } // namespace modalias
00329   } // namespace target
00332 } // namespace zypp
00334 

Generated on Tue Sep 25 19:23:09 2007 for libzypp by  doxygen 1.5.3