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