libzypp 8.13.6
|
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 #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 // parse error messages 00092 while ( output.length() > 0) 00093 { 00094 string::size_type ret; 00095 00096 // extract \n 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 // return codes overwites parsed error message 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 // parse error messages 00181 while ( output.length() > 0) 00182 { 00183 string::size_type ret; 00184 00185 // extract \n 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 // if ( value.find ( "not mounted" ) != string::npos ) 00199 // { 00200 // err = Error::E_already_mounted; 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 // return codes overwites parsed error message 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 // Launch the program 00242 00243 process = new ExternalProgram(argv, environment, disp, false, -1, true); 00244 } 00245 00246 /*--------------------------------------------------------------*/ 00247 /* Return the exit status of the Mount process, closing the */ 00248 /* connection if not already done */ 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 /* Forcably kill the process */ 00266 void Mount::Kill() 00267 { 00268 if (process) process->kill(); 00269 } 00270 00271 // STATIC 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 // Attempt quick fix for bnc#710269: 00319 // MountEntry is "//dist/install/ on /var/adm/mount/AP_0x00000001 type cifs (ro,relatime,unc=\dist\install,username=,domain=suse.de" 00320 // but looking for "Looking for media(cifs<//dist/install>)attached(*/var/adm/mount/AP_0x00000001)" 00321 // Kick the trailing '/' in "//dist/install/" 00322 // TODO: Check and fix comparison in MediaHandler::checkAttached instead. 00323 if ( entry.src.size() > 1 // not for "/" 00324 && entry.src[entry.src.size()-1] == '/' ) 00325 { 00326 entry.src.erase( entry.src.size()-1 ); 00327 } 00328 entries.push_back(entry); 00329 00330 memset(buf, 0, sizeof(buf)); 00331 memset(&ent, 0, sizeof(ent)); 00332 } 00333 } 00334 endmntent(fp); 00335 00336 if( entries.empty()) 00337 { 00338 WAR << "Unable to read any entry from the mount table '" << *t << "'" 00339 << std::endl; 00340 } 00341 else 00342 { 00343 // OK, have a non-empty mount table. 00344 t = mtabs.end(); 00345 break; 00346 } 00347 } 00348 else 00349 { 00350 int err = errno; 00351 verbose = true; 00352 WAR << "Failed to read the mount table '" << *t << "': " 00353 << ::strerror(err) 00354 << std::endl; 00355 errno = err; 00356 } 00357 } 00358 return entries; 00359 } 00360 00361 } // namespace media 00362 } // namespace zypp