Modalias.cc

Go to the documentation of this file.
00001 /*---------------------------------------------------------------------\
00002 |                          ____ _   __ __ ___                          |
00003 |                         |__  / \ / / . \ . \                         |
00004 |                           / / \ V /|  _/  _/                         |
00005 |                          / /__ | | | | | |                           |
00006 |                         /_____||_| |_| |_|                           |
00007 |                                                                      |
00008 \---------------------------------------------------------------------*/
00012 extern "C"
00013 {
00014 #include <sys/types.h>
00015 #include <sys/stat.h>
00016 #include <fcntl.h>
00017 #include <unistd.h>
00018 #include <dirent.h>
00019 #include <fnmatch.h>
00020 }
00021 #include <cstdlib>
00022 #include <cstdio>
00023 #include <cstring>
00024 #include <cerrno>
00025 
00026 #include <iostream>
00027 
00028 #undef ZYPP_BASE_LOGGER_LOGGROUP
00029 #define ZYPP_BASE_LOGGER_LOGGROUP "MODALIAS"
00030 #include "zypp/base/Logger.h"
00031 
00032 #include "zypp/target/modalias/Modalias.h"
00033 #include "zypp/PathInfo.h"
00034 
00035 
00036 using std::endl;
00037 using std::string;
00038 
00039 
00041 namespace zypp
00042 { 
00043 
00044   namespace target
00045   { 
00046 
00047 struct modalias_list {
00048         char *modalias;
00049         struct modalias_list *next;
00050 };
00051 
00053     namespace
00054     { 
00055 
00056 /*
00057  * For each file in the directory PATH other than . and .., call
00058  * FUNC with the arguments PATH, the file's name, and ARG.
00059  *
00060  * If FUNC returns a non-zero return value, stop reading the directory
00061  * and return that value. Returns -1 if an error occurs.
00062  */
00063 
00064 int
00065 foreach_file_recursive(const char *path_rec, int (*func)(const char *, const char *, void *),
00066              void *arg)
00067 {
00068         DIR *dir;
00069         struct dirent *dirent;
00070         char path_tmp[PATH_MAX];
00071         int ret = 0;
00072 
00073         if (!(dir = opendir(path_rec)))
00074                 return -1;
00075         while ((dirent = readdir(dir)) != NULL) {
00076 
00077                 if (strcmp(dirent->d_name, ".") == 0 ||
00078                     strcmp(dirent->d_name, "..") == 0)
00079                         continue;
00080                 snprintf(path_tmp, sizeof(path_tmp), "%s/%s", path_rec, dirent->d_name);
00081 
00082                 PathInfo path(path_tmp, PathInfo::LSTAT);
00083 
00084                 if (path.isLink ()) {
00085                         continue;
00086                 }
00087                 if (path.isDir ()){
00088                         (void) foreach_file_recursive(path_tmp, func, arg);
00089                 }else if (path.isFile ()){
00090                         if ((ret = func(path_rec, dirent->d_name, arg)) != 0)
00091                                 break;
00092                 }else{
00093                         continue;
00094                 }
00095         }
00096         if (closedir(dir) != 0)
00097                 return -1;
00098         return ret;
00099 }
00100 
00101 /*
00102  * If DIR/FILE/modalias exists, remember this modalias on the linked modalias list
00103  * passed in in ARG. Never returns an error.
00104  */
00105 int
00106 read_modalias(const char *dir, const char *file, void *arg)
00107 {
00108         char path[PATH_MAX];
00109         int fd;
00110         ssize_t len;
00111         char modalias[PATH_MAX];
00112         struct modalias_list **list = (struct modalias_list **)arg, *entry;
00113 
00114         if (strcmp(file, "modalias") != 0){
00115                 return 0;
00116         }
00117         snprintf(path, sizeof(path), "%s/%s", dir, file);
00118         if ((fd = open(path, O_RDONLY)) == -1)
00119                 return 0;
00120         len = read(fd, modalias, sizeof(modalias) - 1);
00121         if (len < 0)
00122                 goto out;
00123         while (len > 0 && modalias[len - 1] == '\n')
00124                 len--;
00125         modalias[len] = 0;
00126 
00127         if ((entry = (struct modalias_list *)malloc(sizeof(*entry))) == NULL)
00128                 goto out;
00129         if ((entry->modalias = strdup(modalias)) == NULL) {
00130                 free(entry);
00131                 goto out;
00132         }
00133         entry->next = *list;
00134         *list = entry;
00135         XXX << "system modalias: " << entry->modalias << endl;
00136 
00137 out:
00138         (void) close(fd);
00139         return 0;
00140 }
00141 
00143     } // namespace
00145 
00147 //
00148 //      CLASS NAME : Modalias::Impl
00149 //
00151 struct Modalias::Impl
00152 {
00153     struct modalias_list *_modaliases;
00154 
00156     Impl()
00157         : _modaliases(0)
00158     {
00159         const char *dir;
00160         char path[PATH_MAX];
00161 
00162         dir = getenv("ZYPP_MODALIAS_SYSFS");
00163         if (!dir)
00164                 dir = "/sys";
00165         DBG << "Using /sys directory : " << dir << endl;
00166 
00167         snprintf(path, sizeof(path), "%s", dir);
00168         foreach_file_recursive( path, read_modalias, &_modaliases );
00169 
00170     }
00171 
00173     ~Impl()
00174     {
00175         while (_modaliases != NULL) {
00176             struct modalias_list *l = _modaliases;
00177             _modaliases = _modaliases->next;
00178             free(l->modalias);
00179             free(l);
00180         }
00181     }
00182 
00183     /*
00184      * Check if a device on the system matches a modalias PATTERN.
00185      *
00186      * Returns NULL if no matching device is found, and the modalias
00187      * of the first matching device otherwise. (More than one device
00188      * may match a given pattern.)
00189      *
00190      * On a system that has the following device,
00191      *
00192      *   pci:v00008086d0000265Asv00008086sd00004556bc0Csc03i00
00193      *
00194      * modalias_matches("pci:v00008086d0000265Asv*sd*bc*sc*i*") will
00195      * return a non-NULL value.
00196      */
00197     bool query( const char * cap_r ) const
00198     {
00199         if ( cap_r )
00200         {
00201           struct modalias_list *l;
00202           for (l = _modaliases; l; l = l->next) {
00203             if ( fnmatch( cap_r, l->modalias, 0 ) == 0 )
00204               return true;
00205           }
00206         }
00207         return false;
00208     }
00209 
00210   public:
00212     static shared_ptr<Impl> nullimpl()
00213     {
00214         static shared_ptr<Impl> _nullimpl( new Impl );
00215         return _nullimpl;
00216     }
00217 
00218 };  // struct Modalias::Impl
00219 
00221 
00226 inline std::ostream & operator<<( std::ostream & str, const Modalias::Impl & obj )
00227 {
00228   return str << "Modalias::Impl";
00229 }
00230 
00232 //
00233 //      CLASS NAME : Modalias
00234 //
00236 
00238 //
00239 //      METHOD NAME : Modalias::Modalias
00240 //      METHOD TYPE : Ctor
00241 //
00242 Modalias::Modalias()
00243 : _pimpl( Impl::nullimpl() )
00244 {}
00245 
00247 //
00248 //      METHOD NAME : Modalias::~Modalias
00249 //      METHOD TYPE : Dtor
00250 //
00251 Modalias::~Modalias()
00252 {}
00253 
00255 //
00256 //      METHOD NAME : Modalias::instance
00257 //      METHOD TYPE : Modalias &
00258 //
00259 Modalias & Modalias::instance()
00260 {
00261   static Modalias _singleton;
00262   return _singleton;
00263 }
00264 
00266 // Foreward to implenemtation
00268 
00269 bool Modalias::query( const char * cap_r ) const
00270 { return _pimpl->query( cap_r ); }
00271 
00272 /******************************************************************
00273 **
00274 **      FUNCTION NAME : operator<<
00275 **      FUNCTION TYPE : std::ostream &
00276 */
00277 std::ostream & operator<<( std::ostream & str, const Modalias & obj )
00278 {
00279   return str << *obj._pimpl;
00280 }
00281 
00283   } // namespace target
00286 } // namespace zypp
00288 

doxygen