CheckAccessDeleted.cc
Go to the documentation of this file.00001
00002
00003
00004
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
00036
00037
00038
00039
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
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 );
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;
00080 do { ++ch; } while ( *ch != '\0' );
00081 }
00082
00083 if ( pinfo.command.size() == 15 )
00084 {
00085
00086 Pathname command( filesystem::readlink( Pathname("/proc")/pinfo.pid/"exe" ) );
00087 if ( ! command.empty() )
00088 pinfo.command = command.basename();
00089 }
00090
00091
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' )
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;
00124 do { ++ch; } while ( *ch != '\0' );
00125 }
00126
00127 if ( !t || !f || !n )
00128 return;
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;
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;
00139
00140 if ( str::contains( n, "(stat: Permission denied)" ) )
00141 return;
00142
00143 if ( ! verbose_r )
00144 {
00145 if ( ! ( str::contains( n, "/lib" ) || str::contains( n, "bin/" ) ) )
00146 return;
00147 }
00148
00149 if ( *f == 'm' || *f == 'D' )
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
00166 cache_r.files.push_back( n );
00167 }
00168 }
00170 }
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 }
00232
00233 std::string CheckAccessDeleted::ProcInfo::service() const
00234 {
00235 if ( command.empty() )
00236 return std::string();
00237
00238
00239
00240 static const Pathname initD( "/etc/init.d" );
00241 {
00242 PathInfo pi( initD/command );
00243 if ( pi.isFile() && pi.isX() )
00244 return command;
00245 }
00246 {
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 {
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
00267
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
00279
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 }