libzypp  17.31.31
mount.cc
Go to the documentation of this file.
1 /*---------------------------------------------------------------------\
2 | ____ _ __ __ ___ |
3 | |__ / \ / / . \ . \ |
4 | / / \ V /| _/ _/ |
5 | / /__ | | | | | | |
6 | /_____||_| |_| |_| |
7 | |
8 \---------------------------------------------------------------------*/
13 #include <mntent.h>
14 
15 #include <cstdio>
16 #include <climits>
17 #include <cerrno>
18 
19 #include <iostream>
20 #include <fstream>
21 #include <string>
22 
23 #include <zypp-media/Mount>
24 #include <zypp/base/ExternalDataSource.h>
25 #include <zypp/base/Logger.h>
26 #include <zypp-media/MediaException>
27 
28 #include <zypp/PathInfo.h>
29 
30 using std::endl;
31 
32 #ifndef N_
33 #define N_(STR) STR
34 #endif
35 
36 
37 namespace zypp {
38  namespace media {
39 
40  std::ostream & operator<<( std::ostream & str, const MountEntry & obj )
41  {
42  str << obj.src << " on " << obj.dir << " type " << obj.type;
43  if ( ! obj.opts.empty() )
44  str << " (" << obj.opts << ")";
45  return str;
46  }
47 
48 
49 
51 {
52  PathInfo dev_info;
53  return ( str::hasPrefix( Pathname(src).asString(), "/dev/" ) && dev_info(src) && dev_info.isBlk() );
54 }
55 
57 {}
58 
60 {}
61 
62 void Mount::mount( const std::string & source,
63  const std::string & target,
64  const std::string & filesystem,
65  const std::string & options,
66  const Environment & environment )
67 {
68  const char *const argv[] = {
69  "/bin/mount",
70  "-t", filesystem.c_str(),
71  "-o", options.c_str(),
72  source.c_str(),
73  target.c_str(),
74  NULL
75  };
76 
77  std::string err; // Error summary
78  std::string value; // legacy: Exception collects just the last output line
79  ExternalProgram prog { argv, environment, ExternalProgram::Stderr_To_Stdout, false, -1, true };
80  for ( std::string output = prog.receiveLine(); output.length(); output = prog.receiveLine() ) {
81  output[output.size()-1] = '\0'; // clip tailing NL
82  value = std::move( output );
83  DBG << "stdout: " << value << endl;
84 
85  if ( value.find( "is already mounted on" ) != std::string::npos ) {
86  err = "Media already mounted";
87  }
88  else if ( value.find( "ermission denied" ) != std::string::npos ) {
89  err = "Permission denied";
90  }
91  else if ( value.find( "wrong fs type" ) != std::string::npos ) {
92  err = "Invalid filesystem on media";
93  }
94  else if ( value.find( "No medium found" ) != std::string::npos ) {
95  err = "No medium found";
96  }
97  else if ( value.find( "Not a directory" ) != std::string::npos ) {
98  if ( filesystem == "nfs" || filesystem == "nfs4" ) {
99  err = "NFS path is not a directory";
100  }
101  else {
102  err = "Unable to find directory on the media";
103  }
104  }
105  }
106  int exitCode = prog.close();
107 
108  if ( exitCode != 0 ) {
109  if ( err.empty() ) err = "Mounting media failed";
110  WAR << "mount " << source << " " << target << ": " << exitCode << ": " << err << endl;
111  ZYPP_THROW(MediaMountException(err, source, target, value));
112  }
113  else
114  MIL << "mounted " << source << " " << target << endl;
115 }
116 
117 void Mount::umount( const std::string & path )
118 {
119  const char *const argv[] = {
120  "/bin/umount",
121  path.c_str(),
122  NULL
123  };
124 
125  std::string err; // Error summary
126  int exitCode = -1;
127 
128  bool doRetry = false;
129  unsigned numRetry = 2;
130  do {
131  if ( doRetry ) {
132  if ( numRetry-- ) {
133  WAR << "umount " << path << ": " << exitCode << ": " << err << " - retrying in 1 sec." << endl;
134  sleep( 1 );
135  err.clear();
136  doRetry = false;
137  }
138  else {
139  WAR << "umount " << path << ": " << exitCode << ": " << err << " - giving up" << endl;
140  break;
141  }
142  }
143 
144  ExternalProgram prog { argv, ExternalProgram::Stderr_To_Stdout, false, -1, true };
145  for ( std::string output = prog.receiveLine(); output.length(); output = prog.receiveLine() ) {
146  output.pop_back(); // clip tailing NL
147  DBG << "stdout: " << output << endl;
148 
149  if ( output.find ( " is busy" ) != std::string::npos ) { // 'device|target is busy'
150  err = "Device is busy";
151  doRetry = true;
152  }
153  }
154  exitCode = prog.close();
155 
156  } while( exitCode != 0 && doRetry );
157 
158  if ( exitCode != 0 ) {
159  if ( err.empty() ) err = "Unmounting media failed";
160  WAR << "umount " << path << ": " << exitCode << ": " << err << endl;
161  ZYPP_THROW(MediaUnmountException(err, path));
162  }
163  else
164  MIL << "unmounted " << path << endl;
165 }
166 
167 // STATIC
168 MountEntries
169 Mount::getEntries(const std::string &mtab)
170 {
171  MountEntries entries;
172  std::vector<std::string> mtabs;
173  bool verbose = false;
174 
175  if( mtab.empty())
176  {
177  mtabs.push_back("/proc/mounts");
178  // Also read /etc/mtab if it is a file (on newer sytems
179  // mtab is a symlink to /proc/mounts).
180  // Reason for this is the different representation of
181  // mounted loop devices:
182  // /etc/mtab: /tmp/SLES-11-SP2-MINI-ISO-x86_64-Beta2-DVD.iso on /mnt type iso9660 (ro,loop=/dev/loop0)
183  // /proc/mounts: /dev/loop0 /mnt iso9660 ro,relatime 0 0
184  if ( PathInfo( "/etc/mtab", PathInfo::LSTAT ).isFile() )
185  mtabs.push_back("/etc/mtab");
186  }
187  else
188  {
189  mtabs.push_back(mtab);
190  }
191 
192  std::vector<std::string>::const_iterator t;
193  for( t=mtabs.begin(); t != mtabs.end(); ++t)
194  {
195  if( verbose)
196  {
197  DBG << "Reading mount table from '" << *t << "'" << std::endl;
198  }
199  FILE *fp = setmntent(t->c_str(), "re");
200  if( fp)
201  {
202  char buf[PATH_MAX * 4];
203  struct mntent ent;
204 
205  memset(buf, 0, sizeof(buf));
206  memset(&ent, 0, sizeof(ent));
207 
208  while( getmntent_r(fp, &ent, buf, sizeof(buf)) != NULL)
209  {
210  if( ent.mnt_fsname && *ent.mnt_fsname &&
211  ent.mnt_dir && *ent.mnt_dir &&
212  ent.mnt_type && *ent.mnt_type &&
213  ent.mnt_opts && *ent.mnt_opts)
214  {
215  MountEntry entry(
216  ent.mnt_fsname, ent.mnt_dir,
217  ent.mnt_type, ent.mnt_opts,
218  ent.mnt_freq, ent.mnt_passno
219  );
220 
221  // Attempt quick fix for bnc#710269:
222  // MountEntry is "//dist/install/ on /var/adm/mount/AP_0x00000001 type cifs (ro,relatime,unc=\dist\install,username=,domain=suse.de"
223  // but looking for "Looking for media(cifs<//dist/install>)attached(*/var/adm/mount/AP_0x00000001)"
224  // Kick the trailing '/' in "//dist/install/"
225  // TODO: Check and fix comparison in MediaHandler::checkAttached instead.
226  if ( entry.src.size() > 1 // not for "/"
227  && entry.src[entry.src.size()-1] == '/' )
228  {
229  entry.src.erase( entry.src.size()-1 );
230  }
231  entries.push_back(entry);
232 
233  memset(buf, 0, sizeof(buf));
234  memset(&ent, 0, sizeof(ent));
235  }
236  }
237  endmntent(fp);
238 
239  if( entries.empty())
240  {
241  WAR << "Unable to read any entry from the mount table '" << *t << "'"
242  << std::endl;
243  }
244  else
245  {
246  // OK, have a non-empty mount table.
247  t = mtabs.end();
248  break;
249  }
250  }
251  else
252  {
253  int err = errno;
254  verbose = true;
255  WAR << "Failed to read the mount table '" << *t << "': "
256  << ::strerror(err)
257  << std::endl;
258  errno = err;
259  }
260  }
261  return entries;
262 }
263 
265 {
266  time_t mtime = zypp::PathInfo("/etc/mtab").mtime();
267  if( mtime <= 0)
268  {
269  WAR << "Failed to retrieve modification time of '/etc/mtab'"
270  << std::endl;
271  }
272  return mtime;
273 }
274 
275  } // namespace media
276 } // namespace zypp
std::string asString(const Patch::Category &obj)
Definition: Patch.cc:122
#define MIL
Definition: Logger.h:96
std::ostream & operator<<(std::ostream &str, const MediaHandler &obj)
#define ZYPP_THROW(EXCPT)
Drops a logline and throws the Exception.
Definition: Exception.h:428
~Mount()
Clean up.
Definition: mount.cc:59
ExternalProgram::Environment Environment
For passing additional environment variables to mount.
Definition: mount.h:82
time_t mtime() const
Definition: PathInfo.h:376
String related utilities and Regular expression matching.
bool isBlockDevice() const
Returns true if the src part points to a block device in /dev.
Definition: mount.cc:50
void mount(const std::string &source, const std::string &target, const std::string &filesystem, const std::string &options, const Environment &environment=Environment())
mount device
Definition: mount.cc:62
std::string type
filesystem / mount type
Definition: mount.h:57
Execute a program and give access to its io An object of this class encapsulates the execution of an ...
#define WAR
Definition: Logger.h:97
Mount()
Create an new instance.
Definition: mount.cc:56
static time_t getMTime()
Get the modification time of the /etc/mtab file.
Definition: mount.cc:264
std::string opts
mount options
Definition: mount.h:58
static MountEntries getEntries(const std::string &mtab="")
Return mount entries from /etc/mtab or /etc/fstab file.
Definition: mount.cc:169
A "struct mntent" like mount entry structure, but using std::strings.
Definition: mount.h:34
Wrapper class for ::stat/::lstat.
Definition: PathInfo.h:220
std::string strerror(int errno_r)
Return string describing the error_r code.
Definition: String.cc:53
Easy-to use interface to the ZYPP dependency resolver.
Definition: CodePitfalls.doc: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
std::string src
name of mounted file system
Definition: mount.h:55
void umount(const std::string &path)
umount device
Definition: mount.cc:117
std::string dir
file system path prefix
Definition: mount.h:56
#define DBG
Definition: Logger.h:95