libzypp 17.37.17
devicedriver.cc
Go to the documentation of this file.
1/*---------------------------------------------------------------------\
2| ____ _ __ __ ___ |
3| |__ / \ / / . \ . \ |
4| / / \ V /| _/ _/ |
5| / /__ | | | | | | |
6| /_____||_| |_| |_| |
7| |
8\---------------------------------------------------------------------*/
9
10#include "devicedriver.h"
13#include <zypp-media/ng/MediaVerifier>
14#include <zypp-media/MediaException>
17#include <zypp-core/Date.h>
18
19#undef ZYPP_BASE_LOGGER_LOGGROUP
20#define ZYPP_BASE_LOGGER_LOGGROUP "zyppng::worker::DeviceDriver"
21
23{
24
28
29 void DeviceDriver::setProvider ( ProvideWorkerWeakRef workerRef )
30 {
31 _parentWorker = workerRef;
32 }
33
35 {
36 if ( const auto &i = conf.find( std::string(zyppng::ATTACH_POINT) ); i != conf.end() ) {
37 const auto &val = i->second;
38 MIL << "Got attachpoint from controller: " << val << std::endl;
40 } else {
42 }
43
44 _config = conf;
45
47 caps.set_worker_type ( _wType );
48 caps.set_cfg_flags(
53 )
54 );
55
57 }
58
59 bool DeviceDriver::detachMedia ( const std::string &attachId )
60 {
61 auto i = _attachedMedia.find( attachId );
62 if ( i == _attachedMedia.end() )
63 return false;
64
65 _attachedMedia.erase(i);
66 return true;
67 }
68
70 {
71 for ( auto i = _sysDevs.begin (); i != _sysDevs.end(); ) {
72 if ( i->use_count() == 1 && !(*i)->_mountPoint.empty() ) {
73 MIL << "Unmounting device " << (*i)->_name << " since its not used anymore" << std::endl;
74 unmountDevice(*(*i));
75 if ( (*i)->_ephemeral ) {
76 i = _sysDevs.erase(i);
77 continue;
78 }
79 }
80 ++i;
81 }
82 }
83
85 {
86 return;
87 }
88
89 std::vector<std::shared_ptr<Device>> &DeviceDriver::knownDevices()
90 {
91 return _sysDevs;
92 }
93
94 const std::vector<std::shared_ptr<Device>> &DeviceDriver::knownDevices() const
95 {
96 return _sysDevs;
97 }
98
99 std::unordered_map<std::string, AttachedMedia> &DeviceDriver::attachedMedia()
100 {
101 return _attachedMedia;
102 }
103
105 {
106 // here we need to unmount everything
107 for ( auto i = _sysDevs.begin (); i != _sysDevs.end(); ) {
108 unmountDevice(*(*i));
109 if ( (*i)->_ephemeral ) {
110 i = _sysDevs.erase(i);
111 continue;
112 }
113 ++i;
114 }
115 _attachedMedia.clear();
116 }
117
118 ProvideWorkerRef DeviceDriver::parentWorker () const
119 {
120 return _parentWorker.lock();
121 }
122
124 {
125 if ( dev._mountPoint.empty () )
126 return;
127 try {
128 zypp::media::Mount mount;
129 mount.umount( dev._mountPoint.asString() );
131 } catch (const zypp::media::MediaException & excpt_r) {
132 ERR << "Failed to unmount device: " << dev._name << std::endl;
133 ZYPP_CAUGHT(excpt_r);
134 }
136 }
137
139 {
140 return false;
141 }
142
144 {
145 _attachRoot = root;
146 }
147
149 {
150 if ( _attachRoot.empty() ) {
151 MIL << "Attach root is empty" << std::endl;
152 return zypp::Pathname(".").realpath();
153 }
154 return _attachRoot;
155 }
156
158 {
159 return _config;
160 }
161
162 zyppng::expected<void> DeviceDriver::isDesiredMedium ( const zypp::Url &deviceUrl, const zypp::Pathname &mountPoint, const zyppng::MediaDataVerifierRef &verifier, uint mediaNr )
163 {
164 if ( !verifier ) {
165 // at least the requested path must exist on the medium
166 zypp::PathInfo p( mountPoint );
167 if ( p.isExist() && p.isDir() )
168 return zyppng::expected<void>::success(); // we have no valid data
170 }
171
172 auto devVerifier = verifier->clone();
173 if ( !devVerifier ) {
174 // unlikely to happen
175 return zyppng::expected<void>::error( ZYPP_EXCPT_PTR( zypp::Exception("Failed to clone verifier") ) );
176 }
177
178 // bsc#1180851: If there is just one not-volatile medium in the set
179 // tolerate a missing (vanished) media identifier and let the URL rule.
180 bool relaxed = verifier->totalMedia() == 1 && !isVolatile();
181
182 const auto &relMediaPath = devVerifier->mediaFilePath( mediaNr );
183 zypp::Pathname mediaFile { mountPoint / relMediaPath };
184 zypp::PathInfo pi( mediaFile );
185 if ( !pi.isExist() ) {
186 if ( relaxed )
188 auto excpt = zypp::media::MediaFileNotFoundException( deviceUrl, relMediaPath ) ;
189 excpt.addHistory( verifier->expectedAsUserString( mediaNr ) );
190 return zyppng::expected<void>::error( ZYPP_EXCPT_PTR( std::move(excpt) ) );
191 }
192 if ( !pi.isFile() ) {
193 if ( relaxed )
195 auto excpt = zypp::media::MediaNotAFileException( deviceUrl, relMediaPath ) ;
196 excpt.addHistory( verifier->expectedAsUserString( mediaNr ) );
197 return zyppng::expected<void>::error( ZYPP_EXCPT_PTR( std::move(excpt) ) );
198 }
199
200 if ( !devVerifier->load( mediaFile ) ) {
201 return zyppng::expected<void>::error( ZYPP_EXCPT_PTR( zypp::Exception("Failed to load media information from medium") ) );
202 }
203 if ( !verifier->matches( devVerifier ) ) {
205 }
207 }
208
210 {
211 zypp::Pathname apoint;
212
213 if( attach_root.empty() || !attach_root.absolute()) {
214 ERR << "Create attach point: invalid attach root: '"
215 << attach_root << "'" << std::endl;
216 return apoint;
217 }
218
219 zypp::PathInfo adir( attach_root );
220 if( !adir.isDir() || (geteuid() != 0 && !adir.userMayRWX())) {
221 DBG << "Create attach point: attach root is not a writable directory: '"
222 << attach_root << "'" << std::endl;
223 return apoint;
224 }
225
226 static bool cleanup_once( true );
227 if ( cleanup_once )
228 {
229 cleanup_once = false;
230 DBG << "Look for orphaned attach points in " << adir << std::endl;
231 std::list<std::string> entries;
232 zypp::filesystem::readdir( entries, attach_root, false );
233 for ( const std::string & entry : entries )
234 {
235 if ( ! zypp::str::hasPrefix( entry, "AP_0x" ) )
236 continue;
237 zypp::PathInfo sdir( attach_root + entry );
238 if ( sdir.isDir()
239 && sdir.dev() == adir.dev()
240 && ( zypp::Date::now()-sdir.mtime() > zypp::Date::month ) )
241 {
242 DBG << "Remove orphaned attach point " << sdir << std::endl;
244 }
245 }
246 }
247
248 zypp::filesystem::TmpDir tmpdir( attach_root, "AP_0x" );
249 if ( tmpdir )
250 {
251 apoint = tmpdir.path().asString();
252 if ( ! apoint.empty() )
253 {
254 tmpdir.autoCleanup( false ); // Take responsibility for cleanup.
255 }
256 else
257 {
258 ERR << "Unable to resolve real path for attach point " << tmpdir << std::endl;
259 }
260 }
261 else
262 {
263 ERR << "Unable to create attach point below " << attach_root << std::endl;
264 }
265 return apoint;
266 }
267
269 {
270 if( !attachRoot.empty() &&
272 attachRoot != "/" ) {
273 int res = rmdir( attachRoot );
274 if ( res == 0 ) {
275 MIL << "Deleted default attach point " << attachRoot << std::endl;
276 } else {
277 ERR << "Failed to Delete default attach point " << attachRoot
278 << " errno(" << res << ")" << std::endl;
279 }
280 }
281 }
282
283 bool DeviceDriver::checkAttached ( const zypp::filesystem::Pathname &mountPoint, const std::function<bool (const zypp::media::MountEntry &)> predicate )
284 {
285 bool isAttached = false;
286 time_t old_mtime = _attach_mtime;
288 if( !(old_mtime <= 0 || _attach_mtime != old_mtime) ) {
289 // OK, skip the check (we've seen it at least once)
290 isAttached = true;
291 } else {
292 if( old_mtime > 0)
293 DBG << "Mount table changed - rereading it" << std::endl;
294 else
295 DBG << "Forced check of the mount table" << std::endl;
296
297 for( const auto &entry : zypp::media::Mount::getEntries() ) {
298
299 if ( mountPoint != zypp::Pathname(entry.dir) )
300 continue; // at least the mount points must match
301 if ( predicate(entry) ) {
302 isAttached = true;
303 break;
304 }
305 }
306 }
307
308 // force recheck
309 if ( !isAttached )
310 _attach_mtime = 0;
311
312 return isAttached;
313 }
314
315 const std::function<bool (const zypp::media::MountEntry &)> DeviceDriver::devicePredicate( unsigned int majNr, unsigned int minNr )
316 {
317 return [ majNr, minNr ]( const zypp::media::MountEntry &entry ) -> bool {
318 if( entry.isBlockDevice() ) {
319 zypp::PathInfo dev_info( entry.src );
320 if ( dev_info.devMajor () == majNr && dev_info.devMinor () == minNr ) {
321 DBG << "Found device "
322 << majNr << ":" << minNr
323 << " in the mount table as " << entry.src << std::endl;
324 return true;
325 }
326 }
327 return false;
328 };
329 }
330
331 const std::function<bool (const zypp::media::MountEntry &)> DeviceDriver::fstypePredicate( const std::string &src, const std::vector<std::string> &fstypes )
332 {
333 return [ srcdev=src, fst=fstypes ]( const zypp::media::MountEntry &entry ) -> bool {
334 if( !entry.isBlockDevice() ) {
335 if ( std::find( fst.begin(), fst.end(), entry.type ) != fst.end() ) {
336 if ( srcdev == entry.src ) {
337 DBG << "Found media mount"
338 << " in the mount table as " << entry.src << std::endl;
339 return true;
340 }
341 }
342 }
343 return false;
344 };
345 }
346
347 const std::function<bool (const zypp::media::MountEntry &)> DeviceDriver::bindMountPredicate( const std::string &src )
348 {
349 return [ srcdev=src ]( const zypp::media::MountEntry &entry ) -> bool {
350 if( !entry.isBlockDevice() ) {
351 if ( srcdev == entry.src ) {
352 DBG << "Found bound media "
353 << " in the mount table as " << entry.src << std::endl;
354 return true;
355 }
356 }
357 return false;
358 };
359 }
360
361 AttachError::AttachError ( const MessageCodes code, const std::string &reason, const bool transient, const HeaderValueMap &extra)
362 : _code( code ),
363 _reason( reason ),
364 _transient( transient ),
365 _extra( extra )
366 {
367
368 }
369
370 AttachError::AttachError ( const MessageCodes code, const bool transient, const zypp::Exception &e )
371 : _code( code ),
372 _reason( e.asUserString() ),
373 _transient( transient )
374 {
375 if ( !e.historyEmpty() ) {
376 _extra = { { std::string(zyppng::ErrMsgFields::History), { zyppng::HeaderValueMap::Value(e.historyAsString()) }} };
377 }
378 }
379
380
381}
static const ValueType month
Definition Date.h:49
static Date now()
Return the current time.
Definition Date.h:78
Base class for Exception.
Definition Exception.h:153
bool historyEmpty() const
Whether the history list is empty.
Definition Exception.h:273
Url manipulation class.
Definition Url.h:93
Wrapper class for stat/lstat.
Definition PathInfo.h:226
const Pathname & path() const
Return current Pathname.
Definition PathInfo.h:251
unsigned int devMinor() const
Definition PathInfo.cc:252
bool isExist() const
Return whether valid stat info exists.
Definition PathInfo.h:286
unsigned int devMajor() const
Definition PathInfo.cc:242
bool absolute() const
Test for an absolute path.
Definition Pathname.h:118
const std::string & asString() const
String representation.
Definition Pathname.h:93
bool empty() const
Test for an empty path.
Definition Pathname.h:116
Pathname realpath() const
Returns this path as the absolute canonical pathname.
Definition Pathname.cc:231
Provide a new empty temporary directory and recursively delete it when no longer needed.
Definition TmpPath.h:188
Pathname path() const
Definition TmpPath.cc:152
bool autoCleanup() const
Whether path is valid and deleted when the last reference drops.
Definition TmpPath.cc:169
Just inherits Exception to separate media exceptions.
Interface to the mount program.
Definition mount.h:76
void umount(const std::string &path)
umount device
Definition mount.cc:117
static MountEntries getEntries(const std::string &mtab="")
Return mount entries from /etc/mtab or /etc/fstab file.
Definition mount.cc:169
static time_t getMTime()
Get the modification time of the /etc/mtab file.
Definition mount.cc:264
void set_worker_type(WorkerType t)
void set_cfg_flags(Flags f)
static expected success(ConsParams &&...params)
Definition expected.h:115
zypp::Pathname attachRoot() const
zypp::Pathname createAttachPoint(const zypp::Pathname &attach_root) const
virtual zyppng::expected< WorkerCaps > initialize(const zyppng::worker::Configuration &conf)
static const std::function< bool(const zypp::media::MountEntry &)> fstypePredicate(const std::string &src, const std::vector< std::string > &fstypes)
bool checkAttached(const zypp::Pathname &mountPoint, const std::function< bool(const zypp::media::MountEntry &)> predicate)
ProvideWorkerWeakRef _parentWorker
bool detachMedia(const std::string &attachId)
DeviceDriver(WorkerCaps::WorkerType wType)
virtual bool isVolatile() const
void setProvider(ProvideWorkerWeakRef workerRef)
zyppng::expected< void > isDesiredMedium(const zypp::Url &deviceUrl, const zypp::Pathname &mountPoint, const zyppng::MediaDataVerifierRef &verifier, uint mediaNr=1)
WorkerCaps::WorkerType _wType
static const std::function< bool(const zypp::media::MountEntry &)> bindMountPredicate(const std::string &src)
std::unordered_map< std::string, AttachedMedia > & attachedMedia()
std::vector< std::shared_ptr< Device > > & knownDevices()
const zyppng::worker::Configuration & config() const
void removeAttachPoint(const zypp::Pathname &attach_pt) const
std::vector< std::shared_ptr< Device > > _sysDevs
ProviderConfiguration _config
std::unordered_map< std::string, AttachedMedia > _attachedMedia
ProvideWorkerRef parentWorker() const
static const std::function< bool(const zypp::media::MountEntry &)> devicePredicate(unsigned int majNr, unsigned int minNr)
void setAttachRoot(const zypp::Pathname &root)
virtual void unmountDevice(Device &dev)
int recursive_rmdir(const Pathname &path)
Like 'rm -r DIR'.
Definition PathInfo.cc:417
int readdir(std::list< std::string > &retlist_r, const Pathname &path_r, bool dots_r)
Return content of directory via retlist.
Definition PathInfo.cc:610
bool hasPrefix(const C_Str &str_r, const C_Str &prefix_r)
Return whether str_r has prefix prefix_r.
Definition String.h:1097
std::string asUserString(VendorSupportOption opt)
converts the support option to a name intended to be printed to the user.
zyppng::ProviderConfiguration Configuration
zyppng::WorkerCaps WorkerCaps
constexpr std::string_view ATTACH_POINT("zconfig://media/AttachPoint")
A "struct mntent" like mount entry structure, but using std::strings.
Definition mount.h:36
AttachError(const MessageCodes code, const std::string &reason, const bool transient, const HeaderValueMap &extra={})
std::string _name
Path of the device node or URL for e.g. nfs devices.
zypp::Pathname _mountPoint
Mountpoint of the device, if empty dev is not mounted.
#define ZYPP_CAUGHT(EXCPT)
Drops a logline telling the Exception was caught (in order to handle it).
Definition Exception.h:475
#define ZYPP_EXCPT_PTR(EXCPT)
Drops a logline and returns Exception as a std::exception_ptr.
Definition Exception.h:463
#define DBG
Definition Logger.h:99
#define MIL
Definition Logger.h:100
#define ERR
Definition Logger.h:102