libzypp  17.34.1
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 
22 namespace zyppng::worker
23 {
24 
26  : _wType( wType )
27  { }
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 {
41  return zyppng::expected<zyppng::worker::WorkerCaps>::error(ZYPP_EXCPT_PTR( zypp::Exception("Attach point required to work.") ));
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  }
135  dev._mountPoint = zypp::Pathname();
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 uint 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 uint code, const bool transient, const zypp::Exception &e )
371  : _code( code ),
372  _reason( e.asUserString() ),
373  _transient( transient )
374  {
375  if ( !e.historyEmpty() ) {
377  }
378  }
379 
380 
381 }
DeviceDriver(WorkerCaps::WorkerType wType)
Definition: devicedriver.cc:25
#define MIL
Definition: Logger.h:98
bool autoCleanup() const
Whether path is valid and deleted when the last reference drops.
Definition: TmpPath.cc:167
Interface to the mount program.
Definition: mount.h:75
const Pathname & path() const
Return current Pathname.
Definition: PathInfo.h:247
bool detachMedia(const std::string &attachId)
Definition: devicedriver.cc:59
Pathname realpath() const
Returns this path as the absolute canonical pathname.
Definition: Pathname.cc:231
ProviderConfiguration _config
Definition: devicedriver.h:189
std::unordered_map< std::string, AttachedMedia > & attachedMedia()
Definition: devicedriver.cc:99
ProvideWorkerWeakRef _parentWorker
Definition: devicedriver.h:194
zypp::Pathname attachRoot() const
void set_cfg_flags(Flags f)
constexpr std::string_view ATTACH_POINT("zconfig://media/AttachPoint")
CURLcode _code
std::vector< std::shared_ptr< Device > > _sysDevs
Definition: devicedriver.h:192
time_t mtime() const
Definition: PathInfo.h:377
Pathname path() const
Definition: TmpPath.cc:150
WorkerCaps::WorkerType _wType
Definition: devicedriver.h:188
unsigned int devMinor() const
Definition: PathInfo.cc:252
#define ZYPP_EXCPT_PTR(EXCPT)
Drops a logline and returns Exception as a std::exception_ptr.
Definition: Exception.h:433
std::string asUserString(VendorSupportOption opt)
converts the support option to a name intended to be printed to the user.
virtual void immediateShutdown()
int recursive_rmdir(const Pathname &path)
Like &#39;rm -r DIR&#39;.
Definition: PathInfo.cc:417
virtual zyppng::expected< WorkerCaps > initialize(const zyppng::worker::Configuration &conf)
Definition: devicedriver.cc:34
#define ERR
Definition: Logger.h:100
std::unordered_map< std::string, AttachedMedia > _attachedMedia
Definition: devicedriver.h:193
ProvideWorkerRef parentWorker() const
static const ValueType month
Definition: Date.h:49
static const std::function< bool(const zypp::media::MountEntry &)> bindMountPredicate(const std::string &src)
void set_worker_type(WorkerType t)
const zyppng::worker::Configuration & config() const
bool empty() const
Test for an empty path.
Definition: Pathname.h:116
Provide a new empty temporary directory and recursively delete it when no longer needed.
Definition: TmpPath.h:181
const std::string & asString() const
String representation.
Definition: Pathname.h:93
bool isExist() const
Return whether valid stat info exists.
Definition: PathInfo.h:282
Just inherits Exception to separate media exceptions.
std::string _name
Path of the device node or URL for e.g. nfs devices.
Definition: devicedriver.h:31
void removeAttachPoint(const zypp::Pathname &attach_pt) const
bool historyEmpty() const
Whether the history list is empty.
Definition: Exception.h:263
std::string historyAsString() const
The history as string.
Definition: Exception.cc:165
bool absolute() const
Test for an absolute path.
Definition: Pathname.h:118
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
std::vector< std::shared_ptr< Device > > & knownDevices()
Definition: devicedriver.cc:89
static time_t getMTime()
Get the modification time of the /etc/mtab file.
Definition: mount.cc:264
static expected success(ConsParams &&...params)
Definition: expected.h:115
zypp::Pathname createAttachPoint(const zypp::Pathname &attach_root) const
void setAttachRoot(const zypp::Pathname &root)
#define ZYPP_CAUGHT(EXCPT)
Drops a logline telling the Exception was caught (in order to handle it).
Definition: Exception.h:437
bool checkAttached(const zypp::Pathname &mountPoint, const std::function< bool(const zypp::media::MountEntry &)> predicate)
Base class for Exception.
Definition: Exception.h:146
static const std::function< bool(const zypp::media::MountEntry &)> devicePredicate(unsigned int majNr, unsigned int minNr)
static MountEntries getEntries(const std::string &mtab="")
Return mount entries from /etc/mtab or /etc/fstab file.
Definition: mount.cc:169
static Date now()
Return the current time.
Definition: Date.h:78
Predicate predicate
Definition: PoolQuery.cc:314
MediaVerifierRef verifier
A "struct mntent" like mount entry structure, but using std::strings.
Definition: mount.h:35
unsigned int devMajor() const
Definition: PathInfo.cc:242
Wrapper class for ::stat/::lstat.
Definition: PathInfo.h:221
constexpr std::string_view History("history")
zypp::Pathname _mountPoint
Mountpoint of the device, if empty dev is not mounted.
Definition: devicedriver.h:34
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)
bool hasPrefix(const C_Str &str_r, const C_Str &prefix_r)
Return whether str_r has prefix prefix_r.
Definition: String.h:1027
virtual bool isVolatile() const
int rmdir(const Pathname &path)
Like &#39;rmdir&#39;.
Definition: PathInfo.cc:371
static const std::function< bool(const zypp::media::MountEntry &)> fstypePredicate(const std::string &src, const std::vector< std::string > &fstypes)
bool userMayRWX() const
Definition: PathInfo.h:354
Url manipulation class.
Definition: Url.h:91
void umount(const std::string &path)
umount device
Definition: mount.cc:117
virtual void unmountDevice(Device &dev)
#define DBG
Definition: Logger.h:97
AttachError(const uint code, const std::string &reason, const bool transient, const HeaderValueMap &extra={})