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