8533a286f0415b58f4121b36f5a2691711451238
[platform/upstream/libzypp.git] / zypp / target / modalias / Modalias.cc
1 /*---------------------------------------------------------------------\
2 |                          ____ _   __ __ ___                          |
3 |                         |__  / \ / / . \ . \                         |
4 |                           / / \ V /|  _/  _/                         |
5 |                          / /__ | | | | | |                           |
6 |                         /_____||_| |_| |_|                           |
7 |                                                                      |
8 \---------------------------------------------------------------------*/
9 /** \file       zypp/target/modalias/Modalias.cc
10  *
11 */
12 extern "C"
13 {
14 #include <fnmatch.h>
15 }
16
17 #include <iostream>
18 #include <fstream>
19 #include <vector>
20
21 #undef ZYPP_BASE_LOGGER_LOGGROUP
22 #define ZYPP_BASE_LOGGER_LOGGROUP "MODALIAS"
23
24 #include "zypp/base/LogTools.h"
25 #include "zypp/base/IOStream.h"
26 #include "zypp/base/InputStream.h"
27 #include "zypp/AutoDispose.h"
28 #include "zypp/PathInfo.h"
29
30 #include "zypp/target/modalias/Modalias.h"
31
32 using std::endl;
33
34 ///////////////////////////////////////////////////////////////////
35 namespace zypp
36 {
37   ///////////////////////////////////////////////////////////////////
38   namespace target
39   {
40     ///////////////////////////////////////////////////////////////////
41     namespace
42     {
43       /** Filter subtrees known to contain no modalias files */
44       inline bool isBlackListed( const Pathname & dir_r, const char * file_r )
45       {
46 #define PATH_IS( D, F ) ( ::strcmp( file_r, F ) == 0 && ::strcmp( dir_r.c_str(), D ) == 0 )
47         switch ( file_r[0] )
48         {
49           case 'm':
50             return PATH_IS( "/sys/devices/system", "memory" );  // bnc#824110: huge tree for systems with large RAM
51             break;
52         }
53         return false;
54 #undef PATH_IS
55       }
56
57       /** Recursively scan for modalias files and scan them to \a arg. */
58       void foreach_file_recursive( const Pathname & dir_r, Modalias::ModaliasList & arg )
59       {
60         AutoDispose<DIR *> dir( ::opendir( dir_r.c_str() ), ::closedir );
61         if ( ! dir )
62           return;
63
64         struct dirent * dirent = NULL;
65         while ( (dirent = ::readdir(dir)) != NULL )
66         {
67           if ( dirent->d_name[0] == '.' )
68             continue;
69
70           if ( isBlackListed( dir_r, dirent->d_name ) )
71             continue;
72
73           PathInfo pi( dir_r / dirent->d_name, PathInfo::LSTAT );
74
75           if ( pi.isDir() )
76           {
77             foreach_file_recursive( pi.path(), arg );
78           }
79           else if ( pi.isFile() && ::strcmp( dirent->d_name, "modalias" ) == 0 )
80           {
81             // read modalias line from file
82             std::ifstream str( pi.path().c_str() );
83             std::string line( iostr::getline( str ) );
84             if ( ! line.empty() )
85               arg.push_back( line );
86           }
87         }
88       }
89     } // namespace
90     ///////////////////////////////////////////////////////////////////
91
92     ///////////////////////////////////////////////////////////////////
93     //
94     //  CLASS NAME : Modalias::Impl
95     //
96     /** Modalias implementation. */
97     struct Modalias::Impl
98     {
99       /** Ctor. */
100       Impl()
101       {
102         const char * dir = getenv("ZYPP_MODALIAS_SYSFS");
103         if ( dir )
104         {
105           PathInfo pi( dir );
106           if (  pi.isFile() )
107           {
108             // Debug/testcases:
109             //   find /sys/ -type f -name modalias -print0 | xargs -0 cat >/tmp/modaliases
110             //   ZYPP_MODALIAS_SYSFS=/tmp/modaliases
111             DBG << "Using $ZYPP_MODALIAS_SYSFS modalias file: " << dir << endl;
112             iostr::forEachLine( InputStream( pi.path() ),
113                                 [&]( int num_r, std::string line_r )->bool
114                                 {
115                                   this->_modaliases.push_back( line_r );
116                                   return true;
117                                 } );
118             return;
119           }
120           DBG << "Using $ZYPP_MODALIAS_SYSFS: " << dir << endl;
121         }
122         else
123         {
124           dir = "/sys";
125           DBG << "Using /sys directory." << endl;
126         }
127
128         foreach_file_recursive( dir, _modaliases );
129       }
130
131       /** Dtor. */
132       ~Impl()
133       {}
134
135       /*
136        * Check if a device on the system matches a modalias PATTERN.
137        *
138        * Returns NULL if no matching device is found, and the modalias
139        * of the first matching device otherwise. (More than one device
140        * may match a given pattern.)
141        *
142        * On a system that has the following device,
143        *
144        *   pci:v00008086d0000265Asv00008086sd00004556bc0Csc03i00
145        *
146        * modalias_matches("pci:v00008086d0000265Asv*sd*bc*sc*i*") will
147        * return a non-NULL value.
148        */
149       bool query( const char * cap_r ) const
150       {
151         if ( cap_r && *cap_r )
152         {
153           for_( it, _modaliases.begin(), _modaliases.end() )
154           {
155             if ( fnmatch( cap_r, (*it).c_str(), 0 ) == 0 )
156               return true;
157           }
158         }
159         return false;
160       }
161
162     public:
163       ModaliasList _modaliases;
164
165     public:
166       /** Offer default Impl. */
167       static shared_ptr<Impl> nullimpl()
168       {
169         static shared_ptr<Impl> _nullimpl( new Impl );
170         return _nullimpl;
171       }
172
173     };
174     ///////////////////////////////////////////////////////////////////
175
176     /** \relates Modalias::Impl Stream output
177      * And maybe std::ostream & operator<< Modalias::Impl below too.
178      * return libhal version or something like that.
179      */
180     inline std::ostream & operator<<( std::ostream & str, const Modalias::Impl & obj )
181     {
182       return dumpRange( str << "Modaliases: (" << obj._modaliases.size() << ") ", obj._modaliases.begin(), obj._modaliases.end() );
183     }
184
185     ///////////////////////////////////////////////////////////////////
186     //
187     //  CLASS NAME : Modalias
188     //
189     ///////////////////////////////////////////////////////////////////
190
191     Modalias::Modalias()
192     : _pimpl( Impl::nullimpl() )
193     {}
194
195     Modalias::~Modalias()
196     {}
197
198     Modalias & Modalias::instance()
199     {
200       static Modalias _singleton;
201       return _singleton;
202     }
203
204     bool Modalias::query( const char * cap_r ) const
205     { return _pimpl->query( cap_r ); }
206
207     const Modalias::ModaliasList & Modalias::modaliasList() const
208     { return _pimpl->_modaliases; }
209
210     void Modalias::modaliasList( ModaliasList newlist_r )
211     { _pimpl->_modaliases.swap( newlist_r ); }
212
213     std::ostream & operator<<( std::ostream & str, const Modalias & obj )
214     { return str << *obj._pimpl; }
215
216   } // namespace target
217   ///////////////////////////////////////////////////////////////////
218 } // namespace zypp
219 ///////////////////////////////////////////////////////////////////
220