libzypp  17.14.0
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 
24 #include "zypp/base/Logger.h"
25 #include "zypp/media/Mount.h"
27 
28 #include "zypp/PathInfo.h"
29 
30 #ifndef N_
31 #define N_(STR) STR
32 #endif
33 
34 using namespace std;
35 
36 namespace zypp {
37  namespace media {
38 
39  std::ostream & operator<<( std::ostream & str, const MountEntry & obj )
40  {
41  str << obj.src << " on " << obj.dir << " type " << obj.type;
42  if ( ! obj.opts.empty() )
43  str << " (" << obj.opts << ")";
44  return str;
45  }
46 
47 
48 Mount::Mount()
49 {
50  process = 0;
51  exit_code = -1;
52 }
53 
54 Mount::~Mount()
55 {
56  MIL << "~Mount()" << endl;
57 
58  if ( process )
59  delete process;
60 
61  process = NULL;
62 
63  MIL << "~Mount() end" << endl;
64 }
65 
66 void Mount::mount( const std::string & source,
67  const std::string & target,
68  const std::string & filesystem,
69  const std::string & options,
70  const Environment & environment )
71 {
72  const char *const argv[] = {
73  "/bin/mount",
74  "-t", filesystem.c_str(),
75  "-o", options.c_str(),
76  source.c_str(),
77  target.c_str(),
78  NULL
79  };
80 
81  std::string err;
82 
83  this->run(argv, environment, ExternalProgram::Stderr_To_Stdout);
84 
85  if ( process == NULL )
86  {
87  ZYPP_THROW(MediaMountException("Mounting media failed", source, target));
88  }
89 
90  string value;
91  string output = process->receiveLine();
92 
93  // parse error messages
94  while ( output.length() > 0)
95  {
97 
98  // extract \n
99  ret = output.find_first_of ( "\n" );
100  if ( ret != string::npos )
101  {
102  value.assign ( output, 0, ret );
103  }
104  else
105  {
106  value = output;
107  }
108 
109  DBG << "stdout: " << value << endl;
110 
111  if ( value.find ( "is already mounted on" ) != string::npos )
112  {
113  err = "Media already mounted";
114  }
115  else if ( value.find ( "ermission denied" ) != string::npos )
116  {
117  err = "Permission denied";
118  }
119  else if ( value.find ( "wrong fs type" ) != string::npos )
120  {
121  err = "Invalid filesystem on media";
122  }
123  else if ( value.find ( "No medium found" ) != string::npos )
124  {
125  err = "No medium found";
126  }
127  else if ( value.find ( "Not a directory" ) != string::npos )
128  {
129  if( filesystem == "nfs" || filesystem == "nfs4" )
130  {
131  err = "Nfs path is not a directory";
132  }
133  else
134  {
135  err = "Unable to find directory on the media";
136  }
137  }
138 
139  output = process->receiveLine();
140  }
141 
142  int status = Status();
143 
144  if ( status == 0 )
145  {
146  // return codes overwites parsed error message
147  err = "";
148  }
149  else if ( status != 0 && err == "" )
150  {
151  err = "Mounting media failed";
152  }
153 
154  if ( err != "" ) {
155  WAR << "mount " << source << " " << target << ": " << err << endl;
156  ZYPP_THROW(MediaMountException(err, source, target, value));
157  } else {
158  MIL << "mounted " << source << " " << target << endl;
159  }
160 }
161 
162 void Mount::umount( const std::string & path )
163 {
164  const char *const argv[] = {
165  "/bin/umount",
166  path.c_str(),
167  NULL
168  };
169 
170  std::string err;
171 
172  this->run(argv, ExternalProgram::Stderr_To_Stdout);
173 
174  if ( process == NULL )
175  {
176  ZYPP_THROW(MediaUnmountException("E_mount_failed", path));
177  }
178 
179  string value;
180  string output = process->receiveLine();
181 
182  // parse error messages
183  while ( output.length() > 0)
184  {
185  string::size_type ret;
186 
187  // extract \n
188  ret = output.find_first_of ( "\n" );
189  if ( ret != string::npos )
190  {
191  value.assign ( output, 0, ret );
192  }
193  else
194  {
195  value = output;
196  }
197 
198  DBG << "stdout: " << value << endl;
199 
200  // if ( value.find ( "not mounted" ) != string::npos )
201  // {
202  // err = Error::E_already_mounted;
203  // }
204 
205  if ( value.find ( "device is busy" ) != string::npos )
206  {
207  err = "Device is busy";
208  }
209 
210  output = process->receiveLine();
211  }
212 
213  int status = Status();
214 
215  if ( status == 0 )
216  {
217  // return codes overwites parsed error message
218  err = "";
219  }
220  else if ( status != 0 && err == "" )
221  {
222  err = "Unmounting media failed";
223  }
224 
225  if ( err != "") {
226  WAR << "umount " << path << ": " << err << endl;
227  ZYPP_THROW(MediaUnmountException(err, path));
228  } else {
229  MIL << "unmounted " << path << endl;
230  }
231 }
232 
233 void Mount::run( const char *const *argv, const Environment& environment,
235 {
236  exit_code = -1;
237 
238  if ( process != NULL )
239  {
240  delete process;
241  process = NULL;
242  }
243  // Launch the program
244 
245  process = new ExternalProgram(argv, environment, disp, false, -1, true);
246 }
247 
248 /*--------------------------------------------------------------*/
249 /* Return the exit status of the Mount process, closing the */
250 /* connection if not already done */
251 /*--------------------------------------------------------------*/
253 {
254  if ( process == NULL )
255  return -1;
256 
257  exit_code = process->close();
258  process->kill();
259  delete process;
260  process = 0;
261 
262  DBG << "exit code: " << exit_code << endl;
263 
264  return exit_code;
265 }
266 
267 /* Forcably kill the process */
268 void Mount::Kill()
269 {
270  if (process) process->kill();
271 }
272 
273 // STATIC
274 MountEntries
275 Mount::getEntries(const std::string &mtab)
276 {
277  MountEntries entries;
278  std::vector<std::string> mtabs;
279  bool verbose = false;
280 
281  if( mtab.empty())
282  {
283  mtabs.push_back("/proc/mounts");
284  // Also read /etc/mtab if it is a file (on newer sytems
285  // mtab is a symlink to /proc/mounts).
286  // Reason for this is the different representation of
287  // mounted loop devices:
288  // /etc/mtab: /tmp/SLES-11-SP2-MINI-ISO-x86_64-Beta2-DVD.iso on /mnt type iso9660 (ro,loop=/dev/loop0)
289  // /proc/mounts: /dev/loop0 /mnt iso9660 ro,relatime 0 0
290  if ( PathInfo( "/etc/mtab", PathInfo::LSTAT ).isFile() )
291  mtabs.push_back("/etc/mtab");
292  }
293  else
294  {
295  mtabs.push_back(mtab);
296  }
297 
298  std::vector<std::string>::const_iterator t;
299  for( t=mtabs.begin(); t != mtabs.end(); ++t)
300  {
301  if( verbose)
302  {
303  DBG << "Reading mount table from '" << *t << "'" << std::endl;
304  }
305  FILE *fp = setmntent(t->c_str(), "re");
306  if( fp)
307  {
308  char buf[PATH_MAX * 4];
309  struct mntent ent;
310 
311  memset(buf, 0, sizeof(buf));
312  memset(&ent, 0, sizeof(ent));
313 
314  while( getmntent_r(fp, &ent, buf, sizeof(buf)) != NULL)
315  {
316  if( ent.mnt_fsname && *ent.mnt_fsname &&
317  ent.mnt_dir && *ent.mnt_dir &&
318  ent.mnt_type && *ent.mnt_type &&
319  ent.mnt_opts && *ent.mnt_opts)
320  {
321  MountEntry entry(
322  ent.mnt_fsname, ent.mnt_dir,
323  ent.mnt_type, ent.mnt_opts,
324  ent.mnt_freq, ent.mnt_passno
325  );
326 
327  // Attempt quick fix for bnc#710269:
328  // MountEntry is "//dist/install/ on /var/adm/mount/AP_0x00000001 type cifs (ro,relatime,unc=\dist\install,username=,domain=suse.de"
329  // but looking for "Looking for media(cifs<//dist/install>)attached(*/var/adm/mount/AP_0x00000001)"
330  // Kick the trailing '/' in "//dist/install/"
331  // TODO: Check and fix comparison in MediaHandler::checkAttached instead.
332  if ( entry.src.size() > 1 // not for "/"
333  && entry.src[entry.src.size()-1] == '/' )
334  {
335  entry.src.erase( entry.src.size()-1 );
336  }
337  entries.push_back(entry);
338 
339  memset(buf, 0, sizeof(buf));
340  memset(&ent, 0, sizeof(ent));
341  }
342  }
343  endmntent(fp);
344 
345  if( entries.empty())
346  {
347  WAR << "Unable to read any entry from the mount table '" << *t << "'"
348  << std::endl;
349  }
350  else
351  {
352  // OK, have a non-empty mount table.
353  t = mtabs.end();
354  break;
355  }
356  }
357  else
358  {
359  int err = errno;
360  verbose = true;
361  WAR << "Failed to read the mount table '" << *t << "': "
362  << ::strerror(err)
363  << std::endl;
364  errno = err;
365  }
366  }
367  return entries;
368 }
369 
370  } // namespace media
371 } // namespace zypp
#define MIL
Definition: Logger.h:79
Status
UI status Status values calculated by Selectable.
Definition: Status.h:34
#define ZYPP_THROW(EXCPT)
Drops a logline and throws the Exception.
Definition: Exception.h:392
ExternalProgram::Environment Environment
For passing additional environment variables to mount.
Definition: Mount.h:77
String related utilities and Regular expression matching.
Definition: Arch.h:344
std::string type
filesystem / mount type
Definition: Mount.h:52
Execute a program and give access to its io An object of this class encapsulates the execution of an ...
#define WAR
Definition: Logger.h:80
Stderr_Disposition
Define symbols for different policies on the handling of stderr.
SolvableIdType size_type
Definition: PoolMember.h:126
std::ostream & operator<<(std::ostream &str, const zypp::shared_ptr< void > &obj)
Definition: PtrTypes.h:134
std::string opts
mount options
Definition: Mount.h:53
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
std::string src
name of mounted file system
Definition: Mount.h:50
std::string dir
file system path prefix
Definition: Mount.h:51
#define DBG
Definition: Logger.h:78