1 /*---------------------------------------------------------------------\
3 | |__ / \ / / . \ . \ |
8 \---------------------------------------------------------------------*/
9 /** \file zypp/media/Mount.cc
23 #include <zypp/base/ExternalDataSource.h>
24 #include <zypp/base/Logger.h>
25 #include <zypp/media/Mount.h>
26 #include <zypp/media/MediaException.h>
28 #include <zypp/PathInfo.h>
40 std::ostream & operator<<( std::ostream & str, const MountEntry & obj )
42 str << obj.src << " on " << obj.dir << " type " << obj.type;
43 if ( ! obj.opts.empty() )
44 str << " (" << obj.opts << ")";
57 MIL << "~Mount()" << endl;
64 MIL << "~Mount() end" << endl;
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 )
73 const char *const argv[] = {
75 "-t", filesystem.c_str(),
76 "-o", options.c_str(),
84 this->run(argv, environment, ExternalProgram::Stderr_To_Stdout);
86 if ( process == NULL )
88 ZYPP_THROW(MediaMountException("Mounting media failed", source, target));
92 std::string output = process->receiveLine();
94 // parse error messages
95 while ( output.length() > 0)
97 std::string::size_type ret;
100 ret = output.find_first_of ( "\n" );
101 if ( ret != std::string::npos )
103 value.assign ( output, 0, ret );
110 DBG << "stdout: " << value << endl;
112 if ( value.find ( "is already mounted on" ) != std::string::npos )
114 err = "Media already mounted";
116 else if ( value.find ( "ermission denied" ) != std::string::npos )
118 err = "Permission denied";
120 else if ( value.find ( "wrong fs type" ) != std::string::npos )
122 err = "Invalid filesystem on media";
124 else if ( value.find ( "No medium found" ) != std::string::npos )
126 err = "No medium found";
128 else if ( value.find ( "Not a directory" ) != std::string::npos )
130 if( filesystem == "nfs" || filesystem == "nfs4" )
132 err = "Nfs path is not a directory";
136 err = "Unable to find directory on the media";
140 output = process->receiveLine();
143 int status = Status();
147 // return codes overwites parsed error message
150 else if ( status != 0 && err == "" )
152 err = "Mounting media failed";
156 WAR << "mount " << source << " " << target << ": " << err << endl;
157 ZYPP_THROW(MediaMountException(err, source, target, value));
159 MIL << "mounted " << source << " " << target << endl;
163 void Mount::umount( const std::string & path )
165 const char *const argv[] = {
173 this->run(argv, ExternalProgram::Stderr_To_Stdout);
175 if ( process == NULL )
177 ZYPP_THROW(MediaUnmountException("E_mount_failed", path));
181 std::string output = process->receiveLine();
183 // parse error messages
184 while ( output.length() > 0)
186 std::string::size_type ret;
189 ret = output.find_first_of ( "\n" );
190 if ( ret != std::string::npos )
192 value.assign ( output, 0, ret );
199 DBG << "stdout: " << value << endl;
201 // if ( value.find ( "not mounted" ) != std::string::npos )
203 // err = Error::E_already_mounted;
206 if ( value.find ( "device is busy" ) != std::string::npos )
208 err = "Device is busy";
211 output = process->receiveLine();
214 int status = Status();
218 // return codes overwites parsed error message
221 else if ( status != 0 && err == "" )
223 err = "Unmounting media failed";
227 WAR << "umount " << path << ": " << err << endl;
228 ZYPP_THROW(MediaUnmountException(err, path));
230 MIL << "unmounted " << path << endl;
234 void Mount::run( const char *const *argv, const Environment& environment,
235 ExternalProgram::Stderr_Disposition disp )
239 if ( process != NULL )
244 // Launch the program
246 process = new ExternalProgram(argv, environment, disp, false, -1, true);
249 /*--------------------------------------------------------------*/
250 /* Return the exit status of the Mount process, closing the */
251 /* connection if not already done */
252 /*--------------------------------------------------------------*/
255 if ( process == NULL )
258 exit_code = process->close();
263 DBG << "exit code: " << exit_code << endl;
268 /* Forcably kill the process */
271 if (process) process->kill();
276 Mount::getEntries(const std::string &mtab)
278 MountEntries entries;
279 std::vector<std::string> mtabs;
280 bool verbose = false;
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");
296 mtabs.push_back(mtab);
299 std::vector<std::string>::const_iterator t;
300 for( t=mtabs.begin(); t != mtabs.end(); ++t)
304 DBG << "Reading mount table from '" << *t << "'" << std::endl;
306 FILE *fp = setmntent(t->c_str(), "re");
309 char buf[PATH_MAX * 4];
312 memset(buf, 0, sizeof(buf));
313 memset(&ent, 0, sizeof(ent));
315 while( getmntent_r(fp, &ent, buf, sizeof(buf)) != NULL)
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)
323 ent.mnt_fsname, ent.mnt_dir,
324 ent.mnt_type, ent.mnt_opts,
325 ent.mnt_freq, ent.mnt_passno
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] == '/' )
336 entry.src.erase( entry.src.size()-1 );
338 entries.push_back(entry);
340 memset(buf, 0, sizeof(buf));
341 memset(&ent, 0, sizeof(ent));
348 WAR << "Unable to read any entry from the mount table '" << *t << "'"
353 // OK, have a non-empty mount table.
362 WAR << "Failed to read the mount table '" << *t << "': "