libzypp 9.41.1
|
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 #define BNC925501 1 00037 00038 namespace zypp { 00039 namespace media { 00040 #if ( BNC925501 ) 00041 namespace 00042 { 00043 bool bnc925501ExtraDebug = false; 00044 } 00045 #endif 00046 00047 std::ostream & operator<<( std::ostream & str, const MountEntry & obj ) 00048 { 00049 str << obj.src << " on " << obj.dir << " type " << obj.type; 00050 if ( ! obj.opts.empty() ) 00051 str << " (" << obj.opts << ")"; 00052 return str; 00053 } 00054 00055 00056 Mount::Mount() 00057 { 00058 process = 0; 00059 exit_code = -1; 00060 } 00061 00062 Mount::~Mount() 00063 { 00064 MIL << "~Mount()" << endl; 00065 00066 if ( process ) 00067 delete process; 00068 00069 process = NULL; 00070 00071 MIL << "~Mount() end" << endl; 00072 } 00073 00074 void Mount::mount( const std::string & source, 00075 const std::string & target, 00076 const std::string & filesystem, 00077 const std::string & options, 00078 const Environment & environment ) 00079 { 00080 const char *const argv[] = { 00081 "/bin/mount", 00082 "-t", filesystem.c_str(), 00083 "-o", options.c_str(), 00084 source.c_str(), 00085 target.c_str(), 00086 NULL 00087 }; 00088 00089 std::string err; 00090 00091 this->run(argv, environment, ExternalProgram::Stderr_To_Stdout); 00092 00093 if ( process == NULL ) 00094 { 00095 ZYPP_THROW(MediaMountException("Mounting media failed", source, target)); 00096 } 00097 00098 string value; 00099 string output = process->receiveLine(); 00100 00101 // parse error messages 00102 while ( output.length() > 0) 00103 { 00104 string::size_type ret; 00105 00106 // extract \n 00107 ret = output.find_first_of ( "\n" ); 00108 if ( ret != string::npos ) 00109 { 00110 value.assign ( output, 0, ret ); 00111 } 00112 else 00113 { 00114 value = output; 00115 } 00116 00117 DBG << "stdout: " << value << endl; 00118 00119 if ( value.find ( "is already mounted on" ) != string::npos ) 00120 { 00121 err = "Media already mounted"; 00122 } 00123 else if ( value.find ( "ermission denied" ) != string::npos ) 00124 { 00125 err = "Permission denied"; 00126 } 00127 else if ( value.find ( "wrong fs type" ) != string::npos ) 00128 { 00129 err = "Invalid filesystem on media"; 00130 } 00131 else if ( value.find ( "No medium found" ) != string::npos ) 00132 { 00133 err = "No medium found"; 00134 } 00135 else if ( value.find ( "Not a directory" ) != string::npos ) 00136 { 00137 if( filesystem == "nfs" || filesystem == "nfs4" ) 00138 { 00139 err = "Nfs path is not a directory"; 00140 } 00141 else 00142 { 00143 err = "Unable to find directory on the media"; 00144 } 00145 } 00146 #if ( BNC925501 ) 00147 else if ( value.find ( "already mounted or" ) ) 00148 { 00149 bnc925501ExtraDebug = true; 00150 } 00151 #endif 00152 00153 output = process->receiveLine(); 00154 } 00155 00156 int status = Status(); 00157 00158 if ( status == 0 ) 00159 { 00160 // return codes overwites parsed error message 00161 err = ""; 00162 } 00163 else if ( status != 0 && err == "" ) 00164 { 00165 err = "Mounting media failed"; 00166 } 00167 00168 if ( err != "" ) { 00169 WAR << "mount " << source << " " << target << ": " << err << endl; 00170 #if ( BNC925501 ) 00171 if ( bnc925501ExtraDebug ) 00172 { 00173 Mount::getEntries(); 00174 } 00175 #endif 00176 ZYPP_THROW(MediaMountException(err, source, target, value)); 00177 } else { 00178 MIL << "mounted " << source << " " << target << endl; 00179 } 00180 } 00181 00182 void Mount::umount( const std::string & path ) 00183 { 00184 const char *const argv[] = { 00185 "/bin/umount", 00186 path.c_str(), 00187 NULL 00188 }; 00189 00190 std::string err; 00191 00192 this->run(argv, ExternalProgram::Stderr_To_Stdout); 00193 00194 if ( process == NULL ) 00195 { 00196 ZYPP_THROW(MediaUnmountException("E_mount_failed", path)); 00197 } 00198 00199 string value; 00200 string output = process->receiveLine(); 00201 00202 // parse error messages 00203 while ( output.length() > 0) 00204 { 00205 string::size_type ret; 00206 00207 // extract \n 00208 ret = output.find_first_of ( "\n" ); 00209 if ( ret != string::npos ) 00210 { 00211 value.assign ( output, 0, ret ); 00212 } 00213 else 00214 { 00215 value = output; 00216 } 00217 00218 DBG << "stdout: " << value << endl; 00219 00220 // if ( value.find ( "not mounted" ) != string::npos ) 00221 // { 00222 // err = Error::E_already_mounted; 00223 // } 00224 00225 if ( value.find ( "device is busy" ) != string::npos ) 00226 { 00227 err = "Device is busy"; 00228 } 00229 00230 output = process->receiveLine(); 00231 } 00232 00233 int status = Status(); 00234 00235 if ( status == 0 ) 00236 { 00237 // return codes overwites parsed error message 00238 err = ""; 00239 } 00240 else if ( status != 0 && err == "" ) 00241 { 00242 err = "Unmounting media failed"; 00243 } 00244 00245 if ( err != "") { 00246 WAR << "umount " << path << ": " << err << endl; 00247 ZYPP_THROW(MediaUnmountException(err, path)); 00248 } else { 00249 MIL << "unmounted " << path << endl; 00250 } 00251 } 00252 00253 void Mount::run( const char *const *argv, const Environment& environment, 00254 ExternalProgram::Stderr_Disposition disp ) 00255 { 00256 exit_code = -1; 00257 00258 if ( process != NULL ) 00259 { 00260 delete process; 00261 process = NULL; 00262 } 00263 // Launch the program 00264 00265 process = new ExternalProgram(argv, environment, disp, false, -1, true); 00266 } 00267 00268 /*--------------------------------------------------------------*/ 00269 /* Return the exit status of the Mount process, closing the */ 00270 /* connection if not already done */ 00271 /*--------------------------------------------------------------*/ 00272 int Mount::Status() 00273 { 00274 if ( process == NULL ) 00275 return -1; 00276 00277 exit_code = process->close(); 00278 process->kill(); 00279 delete process; 00280 process = 0; 00281 00282 DBG << "exit code: " << exit_code << endl; 00283 00284 return exit_code; 00285 } 00286 00287 /* Forcably kill the process */ 00288 void Mount::Kill() 00289 { 00290 if (process) process->kill(); 00291 } 00292 00293 // STATIC 00294 MountEntries 00295 Mount::getEntries(const std::string &mtab) 00296 { 00297 MountEntries entries; 00298 std::vector<std::string> mtabs; 00299 bool verbose = false; 00300 #if ( BNC925501 ) 00301 verbose = bnc925501ExtraDebug; 00302 #endif 00303 00304 if( mtab.empty()) 00305 { 00306 mtabs.push_back("/proc/mounts"); 00307 // Also read /etc/mtab if it is a file (on newer sytems 00308 // mtab is a symlink to /proc/mounts). 00309 // Reason for this is the different representation of 00310 // mounted loop devices: 00311 // /etc/mtab: /tmp/SLES-11-SP2-MINI-ISO-x86_64-Beta2-DVD.iso on /mnt type iso9660 (ro,loop=/dev/loop0) 00312 // /proc/mounts: /dev/loop0 /mnt iso9660 ro,relatime 0 0 00313 if ( PathInfo( "/etc/mtab", PathInfo::LSTAT ).isFile() ) 00314 mtabs.push_back("/etc/mtab"); 00315 } 00316 else 00317 { 00318 mtabs.push_back(mtab); 00319 } 00320 00321 std::vector<std::string>::const_iterator t; 00322 for( t=mtabs.begin(); t != mtabs.end(); ++t) 00323 { 00324 if( verbose) 00325 { 00326 DBG << "Reading mount table from '" << *t << "'" << std::endl; 00327 } 00328 FILE *fp = setmntent(t->c_str(), "r"); 00329 if( fp) 00330 { 00331 char buf[PATH_MAX * 4]; 00332 struct mntent ent; 00333 00334 memset(buf, 0, sizeof(buf)); 00335 memset(&ent, 0, sizeof(ent)); 00336 00337 while( getmntent_r(fp, &ent, buf, sizeof(buf)) != NULL) 00338 { 00339 if( ent.mnt_fsname && *ent.mnt_fsname && 00340 ent.mnt_dir && *ent.mnt_dir && 00341 ent.mnt_type && *ent.mnt_type && 00342 ent.mnt_opts && *ent.mnt_opts) 00343 { 00344 MountEntry entry( 00345 ent.mnt_fsname, ent.mnt_dir, 00346 ent.mnt_type, ent.mnt_opts, 00347 ent.mnt_freq, ent.mnt_passno 00348 ); 00349 00350 // Attempt quick fix for bnc#710269: 00351 // MountEntry is "//dist/install/ on /var/adm/mount/AP_0x00000001 type cifs (ro,relatime,unc=\dist\install,username=,domain=suse.de" 00352 // but looking for "Looking for media(cifs<//dist/install>)attached(*/var/adm/mount/AP_0x00000001)" 00353 // Kick the trailing '/' in "//dist/install/" 00354 // TODO: Check and fix comparison in MediaHandler::checkAttached instead. 00355 if ( entry.src.size() > 1 // not for "/" 00356 && entry.src[entry.src.size()-1] == '/' ) 00357 { 00358 entry.src.erase( entry.src.size()-1 ); 00359 } 00360 entries.push_back(entry); 00361 #if ( BNC925501 ) 00362 if ( bnc925501ExtraDebug ) 00363 DBG << "Add MountEntry " << entry << endl; 00364 #endif 00365 } 00366 else 00367 { 00368 WAR << "Suspicious MountEntry |" 00369 << ( ent.mnt_fsname ? ent.mnt_fsname : "NULL" ) << "|" 00370 << ( ent.mnt_dir ? ent.mnt_dir : "NULL" ) << "|" 00371 << ( ent.mnt_type ? ent.mnt_type : "NULL" ) << "|" 00372 << ( ent.mnt_opts ? ent.mnt_opts : "NULL" ) << "|" 00373 << endl; 00374 } 00375 memset(buf, 0, sizeof(buf)); 00376 memset(&ent, 0, sizeof(ent)); 00377 } 00378 endmntent(fp); 00379 00380 if( entries.empty()) 00381 { 00382 WAR << "Unable to read any entry from the mount table '" << *t << "'" 00383 << std::endl; 00384 } 00385 else 00386 { 00387 // OK, have a non-empty mount table. 00388 t = mtabs.end(); 00389 break; 00390 } 00391 } 00392 else 00393 { 00394 int err = errno; 00395 verbose = true; 00396 WAR << "Failed to read the mount table '" << *t << "': " 00397 << ::strerror(err) 00398 << std::endl; 00399 errno = err; 00400 } 00401 } 00402 return entries; 00403 } 00404 00405 } // namespace media 00406 } // namespace zypp