|
libzypp
9.1.2
|
00001 /*---------------------------------------------------------------------\ 00002 | ____ _ __ __ ___ | 00003 | |__ / \ / / . \ . \ | 00004 | / / \ V /| _/ _/ | 00005 | / /__ | | | | | | | 00006 | /_____||_| |_| |_| | 00007 | | 00008 \---------------------------------------------------------------------*/ 00012 #include <iostream> 00013 #include "zypp/base/LogTools.h" 00014 #include "zypp/base/String.h" 00015 #include "zypp/base/Exception.h" 00016 00017 #include "zypp/PathInfo.h" 00018 #include "zypp/ExternalProgram.h" 00019 00020 #include "zypp/misc/CheckAccessDeleted.h" 00021 00022 using std::endl; 00023 00024 #undef ZYPP_BASE_LOGGER_LOGGROUP 00025 #define ZYPP_BASE_LOGGER_LOGGROUP "zypp::misc" 00026 00028 namespace zypp 00029 { 00030 00032 namespace 00033 { 00034 // 00035 // lsof output lines are a sequence of NUL terminated fields, 00036 // where the 1st char determines the fiels type. 00037 // 00038 // (pcuL) pid command userid loginname 00039 // (ftkn).filedescriptor type linkcount filename 00040 // 00042 00046 inline void addDataIf( std::vector<CheckAccessDeleted::ProcInfo> & data_r, CheckAccessDeleted::ProcInfo & cache_r ) 00047 { 00048 if ( cache_r.files.empty() ) 00049 return; 00050 00051 // at least one file access so keep it: 00052 data_r.push_back( CheckAccessDeleted::ProcInfo() ); 00053 CheckAccessDeleted::ProcInfo & pinfo( data_r.back() ); 00054 00055 std::string pline; 00056 cache_r.pid.swap( pline ); 00057 cache_r.files.swap( pinfo.files ); // clears cache.files 00058 00059 for_( ch, pline.begin(), pline.end() ) 00060 { 00061 switch ( *ch ) 00062 { 00063 case 'p': 00064 pinfo.pid = &*(ch+1); 00065 break; 00066 case 'R': 00067 pinfo.ppid = &*(ch+1); 00068 break; 00069 case 'u': 00070 pinfo.puid = &*(ch+1); 00071 break; 00072 case 'L': 00073 pinfo.login = &*(ch+1); 00074 break; 00075 case 'c': 00076 pinfo.command = &*(ch+1); 00077 break; 00078 } 00079 if ( *ch == '\n' ) break; // end of data 00080 do { ++ch; } while ( *ch != '\0' ); // skip to next field 00081 } 00082 00083 if ( pinfo.command.size() == 15 ) 00084 { 00085 // the command name might be truncated, so we check against /proc/<pid>/exe 00086 Pathname command( filesystem::readlink( Pathname("/proc")/pinfo.pid/"exe" ) ); 00087 if ( ! command.empty() ) 00088 pinfo.command = command.basename(); 00089 } 00090 00091 //MIL << " Take " << pinfo << endl; 00092 } 00093 00099 inline void addCacheIf( CheckAccessDeleted::ProcInfo & cache_r, const std::string & line_r, bool verbose_r ) 00100 { 00101 const char * f = 0; 00102 const char * t = 0; 00103 const char * n = 0; 00104 00105 for_( ch, line_r.c_str(), ch+line_r.size() ) 00106 { 00107 switch ( *ch ) 00108 { 00109 case 'k': 00110 if ( *(ch+1) != '0' ) // skip non-zero link counts 00111 return; 00112 break; 00113 case 'f': 00114 f = ch+1; 00115 break; 00116 case 't': 00117 t = ch+1; 00118 break; 00119 case 'n': 00120 n = ch+1; 00121 break; 00122 } 00123 if ( *ch == '\n' ) break; // end of data 00124 do { ++ch; } while ( *ch != '\0' ); // skip to next field 00125 } 00126 00127 if ( !t || !f || !n ) 00128 return; // wrong filedescriptor/type/name 00129 00130 if ( !( ( *t == 'R' && *(t+1) == 'E' && *(t+2) == 'G' && *(t+3) == '\0' ) 00131 || ( *t == 'D' && *(t+1) == 'E' && *(t+2) == 'L' && *(t+3) == '\0' ) ) ) 00132 return; // wrong type 00133 00134 if ( !( ( *f == 'm' && *(f+1) == 'e' && *(f+2) == 'm' && *(f+3) == '\0' ) 00135 || ( *f == 't' && *(f+1) == 'x' && *(f+2) == 't' && *(f+3) == '\0' ) 00136 || ( *f == 'D' && *(f+1) == 'E' && *(f+2) == 'L' && *(f+3) == '\0' ) 00137 || ( *f == 'l' && *(f+1) == 't' && *(f+2) == 'x' && *(f+3) == '\0' ) ) ) 00138 return; // wrong filedescriptor type 00139 00140 if ( str::contains( n, "(stat: Permission denied)" ) ) 00141 return; // Avoid reporting false positive due to insufficient permission. 00142 00143 if ( ! verbose_r ) 00144 { 00145 if ( ! ( str::contains( n, "/lib" ) || str::contains( n, "bin/" ) ) ) 00146 return; // Try to avoid reporting false positive unless verbose. 00147 } 00148 00149 if ( *f == 'm' || *f == 'D' ) // skip some wellknown nonlibrary memorymapped files 00150 { 00151 static const char * black[] = { 00152 "/SYSV" 00153 , "/var/run/" 00154 , "/dev/" 00155 }; 00156 for_( it, arrayBegin( black ), arrayEnd( black ) ) 00157 { 00158 if ( str::hasPrefix( n, *it ) ) 00159 return; 00160 } 00161 } 00162 00163 if ( std::find( cache_r.files.begin(), cache_r.files.end(), n ) == cache_r.files.end() ) 00164 { 00165 // Add if no duplicate 00166 cache_r.files.push_back( n ); 00167 } 00168 } 00170 } // namespace 00172 00173 CheckAccessDeleted::size_type CheckAccessDeleted::check( bool verbose_r ) 00174 { 00175 _data.clear(); 00176 std::vector<ProcInfo> data; 00177 00178 static const char* argv[] = 00179 { 00180 "lsof", "-n", "-FpcuLRftkn0", NULL 00181 }; 00182 ExternalProgram prog( argv, ExternalProgram::Discard_Stderr ); 00183 00184 CheckAccessDeleted::ProcInfo cache; 00185 for( std::string line = prog.receiveLine(); ! line.empty(); line = prog.receiveLine() ) 00186 { 00187 if ( line[0] == 'p' ) 00188 { 00189 addDataIf( data, cache ); 00190 cache.pid = line; // 00191 } 00192 else 00193 { 00194 addCacheIf( cache, line, verbose_r ); 00195 } 00196 } 00197 addDataIf( data, cache ); 00198 00199 int ret = prog.close(); 00200 if ( ret != 0 ) 00201 { 00202 Exception err( str::form("Executing 'lsof' failed (%d).", ret) ); 00203 err.remember( prog.execError() ); 00204 ZYPP_THROW( err ); 00205 } 00206 00207 _data.swap( data ); 00208 return _data.size(); 00209 } 00210 00211 std::string CheckAccessDeleted::findService( const Pathname & command_r ) 00212 { 00213 ProcInfo p; 00214 p.command = command_r.basename(); 00215 return p.service(); 00216 } 00217 std::string CheckAccessDeleted::findService( const char * command_r ) 00218 { return findService( Pathname( command_r ) ); } 00219 00220 std::string CheckAccessDeleted::findService( const std::string & command_r ) 00221 { return findService( Pathname( command_r ) ); } 00222 00223 std::string CheckAccessDeleted::findService( pid_t pid_r ) 00224 { return findService( filesystem::readlink( Pathname("/proc")/str::numstring(pid_r)/"exe" ) ); } 00225 00227 namespace 00228 { 00229 00230 } // namespace 00232 00233 std::string CheckAccessDeleted::ProcInfo::service() const 00234 { 00235 if ( command.empty() ) 00236 return std::string(); 00237 // TODO: This needs to be implemented smarter... be carefull 00238 // as we don't know whether the target is up. 00239 00240 static const Pathname initD( "/etc/init.d" ); 00241 { // init.d script with same name 00242 PathInfo pi( initD/command ); 00243 if ( pi.isFile() && pi.isX() ) 00244 return command; 00245 } 00246 { // init.d script with name + 'd' 00247 std::string alt( command+"d" ); 00248 PathInfo pi( initD/alt ); 00249 if ( pi.isFile() && pi.isX() ) 00250 return alt; 00251 } 00252 if ( *command.rbegin() == 'd' ) 00253 { // init.d script with name - trailing'd' 00254 std::string alt( command ); 00255 alt.erase( alt.size()-1 ); 00256 PathInfo pi( initD/alt ); 00257 WAR <<pi << endl; 00258 if ( pi.isFile() && pi.isX() ) 00259 return alt; 00260 } 00261 return std::string(); 00262 } 00263 00264 /****************************************************************** 00265 ** 00266 ** FUNCTION NAME : operator<< 00267 ** FUNCTION TYPE : std::ostream & 00268 */ 00269 std::ostream & operator<<( std::ostream & str, const CheckAccessDeleted & obj ) 00270 { 00271 return dumpRange( str << "CheckAccessDeleted ", 00272 obj.begin(), 00273 obj.end() ); 00274 } 00275 00276 /****************************************************************** 00277 ** 00278 ** FUNCTION NAME : operator<< 00279 ** FUNCTION TYPE : std::ostream & 00280 */ 00281 std::ostream & operator<<( std::ostream & str, const CheckAccessDeleted::ProcInfo & obj ) 00282 { 00283 if ( obj.pid.empty() ) 00284 return str << "<NoProc>"; 00285 00286 return dumpRangeLine( str << obj.command 00287 << '<' << obj.pid 00288 << '|' << obj.ppid 00289 << '|' << obj.puid 00290 << '|' << obj.login 00291 << '>', 00292 obj.files.begin(), 00293 obj.files.end() ); 00294 } 00295 00297 } // namespace zypp
1.7.6.1