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