Mount.cc

Go to the documentation of this file.
00001 /*---------------------------------------------------------------------\
00002 |                          ____ _   __ __ ___                          |
00003 |                         |__  / \ / / . \ . \                         |
00004 |                           / / \ V /|  _/  _/                         |
00005 |                          / /__ | | | | | |                           |
00006 |                         /_____||_| |_| |_|                           |
00007 |                                                                      |
00008 \---------------------------------------------------------------------*/
00013 #include <mntent.h>
00014 
00015 #include <cstdio>
00016 #include <climits>
00017 #include <cerrno>
00018 
00019 #include <iostream>
00020 #include <fstream>
00021 #include <string>
00022 
00023 #include "zypp/base/ExternalDataSource.h"
00024 #include "zypp/base/Logger.h"
00025 #include "zypp/media/Mount.h"
00026 #include "zypp/media/MediaException.h"
00027 
00028 #ifndef N_
00029 #define N_(STR) STR
00030 #endif
00031 
00032 using namespace std;
00033 
00034 namespace zypp {
00035   namespace media {
00036 
00037     std::ostream & operator<<( std::ostream & str, const MountEntry & obj )
00038     {
00039       str << obj.src << " on " << obj.dir << " type " << obj.type;
00040       if ( ! obj.opts.empty() )
00041         str << " (" << obj.opts << ")";
00042       return str;
00043     }
00044 
00045 
00046 Mount::Mount()
00047 {
00048     process = 0;
00049     exit_code = -1;
00050 }
00051 
00052 Mount::~Mount()
00053 {
00054    MIL <<  "~Mount()" << endl;
00055 
00056    if ( process )
00057       delete process;
00058 
00059    process = NULL;
00060 
00061    MIL << "~Mount() end" << endl;
00062 }
00063 
00064 void Mount::mount( const std::string & source,
00065                    const std::string & target,
00066                    const std::string & filesystem,
00067                    const std::string & options,
00068                    const Environment & environment )
00069 {
00070     const char *const argv[] = {
00071         "/bin/mount",
00072         "-t", filesystem.c_str(),
00073         "-o", options.c_str(),
00074         source.c_str(),
00075         target.c_str(),
00076         NULL
00077      };
00078 
00079     std::string err;
00080 
00081     this->run(argv, environment, ExternalProgram::Stderr_To_Stdout);
00082 
00083     if ( process == NULL )
00084     {
00085       ZYPP_THROW(MediaMountException("Mounting media failed", source, target));
00086     }
00087 
00088     string value;
00089     string output = process->receiveLine();
00090 
00091     // parse error messages
00092     while ( output.length() > 0)
00093     {
00094         string::size_type       ret;
00095 
00096         // extract \n
00097         ret = output.find_first_of ( "\n" );
00098         if ( ret != string::npos )
00099         {
00100             value.assign ( output, 0, ret );
00101         }
00102         else
00103         {
00104             value = output;
00105         }
00106 
00107         DBG << "stdout: " << value << endl;
00108 
00109         if  ( value.find ( "is already mounted on" ) != string::npos )
00110         {
00111             err = "Media already mounted";
00112         }
00113         else if  ( value.find ( "ermission denied" ) != string::npos )
00114         {
00115             err = "Permission denied";
00116         }
00117         else if  ( value.find ( "wrong fs type" ) != string::npos )
00118         {
00119             err = "Invalid filesystem on media";
00120         }
00121         else if  ( value.find ( "No medium found" ) != string::npos )
00122         {
00123             err = "No medium found";
00124         }
00125         else if  ( value.find ( "Not a directory" ) != string::npos )
00126         {
00127             if( filesystem == "nfs" || filesystem == "nfs4" )
00128             {
00129                 err = "Nfs path is not a directory";
00130             }
00131             else
00132             {
00133                err = "Unable to find directory on the media";
00134             }
00135         }
00136 
00137         output = process->receiveLine();
00138     }
00139 
00140     int status = Status();
00141 
00142     if ( status == 0 )
00143     {
00144         // return codes overwites parsed error message
00145         err = "";
00146     }
00147     else if ( status != 0 && err == "" )
00148     {
00149         err = "Mounting media failed";
00150     }
00151 
00152     if ( err != "" ) {
00153       WAR << "mount " << source << " " << target << ": " << err << endl;
00154       ZYPP_THROW(MediaMountException(err, source, target, value));
00155     } else {
00156       MIL << "mounted " << source << " " << target << endl;
00157     }
00158 }
00159 
00160 void Mount::umount( const std::string & path )
00161 {
00162     const char *const argv[] = {
00163         "/bin/umount",
00164         path.c_str(),
00165         NULL
00166      };
00167 
00168     std::string err;
00169 
00170     this->run(argv, ExternalProgram::Stderr_To_Stdout);
00171 
00172     if ( process == NULL )
00173     {
00174         ZYPP_THROW(MediaUnmountException("E_mount_failed", path));
00175     }
00176 
00177     string value;
00178     string output = process->receiveLine();
00179 
00180     // parse error messages
00181     while ( output.length() > 0)
00182     {
00183         string::size_type       ret;
00184 
00185         // extract \n
00186         ret = output.find_first_of ( "\n" );
00187         if ( ret != string::npos )
00188         {
00189             value.assign ( output, 0, ret );
00190         }
00191         else
00192         {
00193             value = output;
00194         }
00195 
00196         DBG << "stdout: " << value << endl;
00197 
00198         // if  ( value.find ( "not mounted" ) != string::npos )
00199         // {
00200         //    err = Error::E_already_mounted;
00201         // }
00202 
00203         if  ( value.find ( "device is busy" ) != string::npos )
00204         {
00205             err = "Device is busy";
00206         }
00207 
00208         output = process->receiveLine();
00209     }
00210 
00211     int status = Status();
00212 
00213     if ( status == 0 )
00214     {
00215         // return codes overwites parsed error message
00216         err = "";
00217     }
00218     else if ( status != 0 && err == "" )
00219     {
00220         err = "Unmounting media failed";
00221     }
00222 
00223     if ( err != "") {
00224       WAR << "umount " << path << ": " << err << endl;
00225       ZYPP_THROW(MediaUnmountException(err, path));
00226     } else {
00227       MIL << "unmounted " << path << endl;
00228     }
00229 }
00230 
00231 void Mount::run( const char *const *argv, const Environment& environment,
00232                  ExternalProgram::Stderr_Disposition disp )
00233 {
00234   exit_code = -1;
00235 
00236   if ( process != NULL )
00237   {
00238      delete process;
00239      process = NULL;
00240   }
00241   // Launch the program
00242 
00243   process = new ExternalProgram(argv, environment, disp, false, -1, true);
00244 }
00245 
00246 /*--------------------------------------------------------------*/
00247 /* Return the exit status of the Mount process, closing the     */
00248 /* connection if not already done                               */
00249 /*--------------------------------------------------------------*/
00250 int Mount::Status()
00251 {
00252    if ( process == NULL )
00253       return -1;
00254 
00255    exit_code = process->close();
00256    process->kill();
00257    delete process;
00258    process = 0;
00259 
00260    DBG << "exit code: " << exit_code << endl;
00261 
00262    return exit_code;
00263 }
00264 
00265 /* Forcably kill the process */
00266 void Mount::Kill()
00267 {
00268   if (process) process->kill();
00269 }
00270 
00271 // STATIC
00272 MountEntries
00273 Mount::getEntries(const std::string &mtab)
00274 {
00275   MountEntries             entries;
00276   std::vector<std::string> mtabs;
00277   bool                     verbose = false;
00278 
00279   if( mtab.empty())
00280   {
00281     mtabs.push_back("/etc/mtab");
00282     mtabs.push_back("/proc/mounts");
00283   }
00284   else
00285   {
00286     mtabs.push_back(mtab);
00287   }
00288 
00289   std::vector<std::string>::const_iterator t;
00290   for( t=mtabs.begin(); t != mtabs.end(); ++t)
00291   {
00292     if( verbose)
00293     {
00294       DBG << "Reading mount table from '" << *t << "'" << std::endl;
00295     }
00296     FILE *fp = setmntent(t->c_str(), "r");
00297     if( fp)
00298     {
00299       char          buf[PATH_MAX * 4];
00300       struct mntent ent;
00301 
00302       memset(buf,  0, sizeof(buf));
00303       memset(&ent, 0, sizeof(ent));
00304 
00305       while( getmntent_r(fp, &ent, buf, sizeof(buf)) != NULL)
00306       {
00307         if( ent.mnt_fsname && *ent.mnt_fsname &&
00308             ent.mnt_dir    && *ent.mnt_dir    &&
00309             ent.mnt_type   && *ent.mnt_type   &&
00310             ent.mnt_opts   && *ent.mnt_opts)
00311         {
00312           MountEntry entry(
00313             ent.mnt_fsname, ent.mnt_dir,
00314             ent.mnt_type,   ent.mnt_opts,
00315             ent.mnt_freq,   ent.mnt_passno
00316           );
00317 
00318           entries.push_back(entry);
00319 
00320           memset(buf,  0, sizeof(buf));
00321           memset(&ent, 0, sizeof(ent));
00322         }
00323       }
00324       endmntent(fp);
00325 
00326       if( entries.empty())
00327       {
00328         WAR << "Unable to read any entry from the mount table '" << *t << "'"
00329             << std::endl;
00330       }
00331       else
00332       {
00333         // OK, have a non-empty mount table.
00334         t = mtabs.end();
00335         break;
00336       }
00337     }
00338     else
00339     {
00340       int err = errno;
00341       verbose = true;
00342       WAR << "Failed to read the mount table '" << *t << "': "
00343           << ::strerror(err)
00344           << std::endl;
00345       errno = err;
00346     }
00347   }
00348   return entries;
00349 }
00350 
00351   } // namespace media
00352 } // namespace zypp

doxygen