libzypp
10.5.0
|
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 #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 // parse error messages 00094 while ( output.length() > 0) 00095 { 00096 string::size_type ret; 00097 00098 // extract \n 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 // return codes overwites parsed error message 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 // parse error messages 00183 while ( output.length() > 0) 00184 { 00185 string::size_type ret; 00186 00187 // extract \n 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 // if ( value.find ( "not mounted" ) != string::npos ) 00201 // { 00202 // err = Error::E_already_mounted; 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 // return codes overwites parsed error message 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 // Launch the program 00244 00245 process = new ExternalProgram(argv, environment, disp, false, -1, true); 00246 } 00247 00248 /*--------------------------------------------------------------*/ 00249 /* Return the exit status of the Mount process, closing the */ 00250 /* connection if not already done */ 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 /* Forcably kill the process */ 00268 void Mount::Kill() 00269 { 00270 if (process) process->kill(); 00271 } 00272 00273 // STATIC 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 // Also read /etc/mtab if it is a file (on newer sytems 00285 // mtab is a symlink to /proc/mounts). 00286 // Reason for this is the different representation of 00287 // mounted loop devices: 00288 // /etc/mtab: /tmp/SLES-11-SP2-MINI-ISO-x86_64-Beta2-DVD.iso on /mnt type iso9660 (ro,loop=/dev/loop0) 00289 // /proc/mounts: /dev/loop0 /mnt iso9660 ro,relatime 0 0 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(), "re"); 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 // Attempt quick fix for bnc#710269: 00328 // MountEntry is "//dist/install/ on /var/adm/mount/AP_0x00000001 type cifs (ro,relatime,unc=\dist\install,username=,domain=suse.de" 00329 // but looking for "Looking for media(cifs<//dist/install>)attached(*/var/adm/mount/AP_0x00000001)" 00330 // Kick the trailing '/' in "//dist/install/" 00331 // TODO: Check and fix comparison in MediaHandler::checkAttached instead. 00332 if ( entry.src.size() > 1 // not for "/" 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 // OK, have a non-empty mount table. 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 } // namespace media 00371 } // namespace zypp