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