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