00001
00002
00003
00004
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
00092 while ( output.length() > 0)
00093 {
00094 string::size_type ret;
00095
00096
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
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
00181 while ( output.length() > 0)
00182 {
00183 string::size_type ret;
00184
00185
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
00199
00200
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
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
00242
00243 process = new ExternalProgram(argv, environment, disp, false, -1, true);
00244 }
00245
00246
00247
00248
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
00266 void Mount::Kill()
00267 {
00268 if (process) process->kill();
00269 }
00270
00271
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
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 }
00352 }