LCOV - code coverage report
Current view: top level - src - File.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 180 482 37.3 %
Date: 2010-12-13 Functions: 21 49 42.9 %
Branches: 85 412 20.6 %

           Branch data     Line data    Source code
       1                 :            : // $Id: File.cc 6942 2009-11-16 03:54:08Z vern $
       2                 :            : //
       3                 :            : // See the file "COPYING" in the main distribution directory for copyright.
       4                 :            : 
       5                 :            : #include "config.h"
       6                 :            : 
       7                 :            : #include <sys/types.h>
       8                 :            : #ifdef TIME_WITH_SYS_TIME
       9                 :            : # include <sys/time.h>
      10                 :            : # include <time.h>
      11                 :            : #else
      12                 :            : # ifdef HAVE_SYS_TIME_H
      13                 :            : #  include <sys/time.h>
      14                 :            : # else
      15                 :            : #  include <time.h>
      16                 :            : # endif
      17                 :            : #endif
      18                 :            : #include <sys/resource.h>
      19                 :            : #include <sys/stat.h>
      20                 :            : #include <errno.h>
      21                 :            : #include <unistd.h>
      22                 :            : 
      23                 :            : #include "File.h"
      24                 :            : #include "Type.h"
      25                 :            : #include "Timer.h"
      26                 :            : #include "Expr.h"
      27                 :            : #include "NetVar.h"
      28                 :            : #include "Net.h"
      29                 :            : #include "Serializer.h"
      30                 :            : #include "Event.h"
      31                 :            : 
      32                 :            : // Timer which on dispatching rotates the file.
      33                 :            : class RotateTimer : public Timer {
      34                 :            : public:
      35                 :          0 :         RotateTimer(double t, BroFile* f, bool arg_raise) : Timer(t, TIMER_ROTATE)
      36                 :          0 :                 { file = f; raise = arg_raise; name = copy_string(f->Name()); }
      37                 :            :         ~RotateTimer();
      38                 :            : 
      39                 :            :         void Dispatch(double t, int is_expire);
      40                 :            : 
      41                 :            : protected:
      42                 :            :         BroFile* file;
      43                 :            :         bool raise;
      44                 :            :         const char* name;
      45                 :            : };
      46                 :            : 
      47                 :          0 : RotateTimer::~RotateTimer()
      48                 :            :         {
      49 [ #  # ][ #  # ]:          0 :         if ( file->rotate_timer == this )
                 [ #  # ]
      50                 :          0 :                 file->rotate_timer = 0;
      51                 :            : 
      52 [ #  # ][ #  # ]:          0 :         delete [] name;
                 [ #  # ]
      53 [ #  # ][ #  # ]:          0 :         }
                 [ #  # ]
      54                 :            : 
      55                 :          0 : void RotateTimer::Dispatch(double t, int is_expire)
      56                 :            :         {
      57                 :          0 :         file->rotate_timer = 0;
      58                 :            : 
      59         [ #  # ]:          0 :         if ( ! is_expire )
      60                 :            :                 {
      61         [ #  # ]:          0 :                 if ( raise )
      62                 :            :                         {
      63                 :          0 :                         val_list* vl = new val_list;
      64                 :          0 :                         Ref(file);
      65                 :          0 :                         vl->append(new Val(file));
      66                 :          0 :                         mgr.QueueEvent(rotate_interval, vl);
      67                 :            :                         }
      68                 :            : 
      69                 :          0 :                 file->InstallRotateTimer();
      70                 :            :                 }
      71                 :          0 :         }
      72                 :            : 
      73                 :            : 
      74                 :            : // The following could in principle be part of a "file manager" object.
      75                 :            : 
      76                 :            : #define MAX_FILE_CACHE_SIZE 32
      77                 :            : static int num_files_in_cache = 0;
      78                 :            : static int max_files_in_cache = 0;
      79                 :            : static BroFile* head = 0;
      80                 :            : static BroFile* tail = 0;
      81                 :            : 
      82                 :            : double BroFile::default_rotation_interval = 0;
      83                 :            : double BroFile::default_rotation_size = 0;
      84                 :            : 
      85                 :            : // Maximizes the number of open file descriptors and returns the number
      86                 :            : // that we should use for the cache.
      87                 :          2 : static int maximize_num_fds()
      88                 :            :         {
      89                 :            : #ifdef NO_HAVE_SETRLIMIT
      90                 :            :         return MAX_FILE_CACHE_SIZE;
      91                 :            : #else
      92                 :            :         struct rlimit rl;
      93         [ -  + ]:          2 :         if ( getrlimit(RLIMIT_NOFILE, &rl) < 0 )
      94                 :          0 :                 internal_error("maximize_num_fds(): getrlimit failed");
      95                 :            : 
      96         [ +  - ]:          2 :         if ( rl.rlim_max == RLIM_INFINITY )
      97                 :            :                 {
      98                 :            :                 // Don't try raising the current limit.
      99         [ -  + ]:          2 :                 if ( rl.rlim_cur == RLIM_INFINITY )
     100                 :            :                         // Let's not be too ambitious.
     101                 :          0 :                         return MAX_FILE_CACHE_SIZE;
     102                 :            :                 else
     103                 :          2 :                         return rl.rlim_cur / 2;
     104                 :            :                 }
     105                 :            : 
     106                 :            :         // See if we can raise the current to the maximum.
     107                 :          0 :         rl.rlim_cur = rl.rlim_max;
     108                 :            : 
     109         [ #  # ]:          0 :         if ( setrlimit(RLIMIT_NOFILE, &rl) < 0 )
     110                 :          0 :                 internal_error("maximize_num_fds(): setrlimit failed");
     111                 :            : 
     112                 :          2 :         return rl.rlim_cur / 2;
     113                 :            : #endif
     114                 :            :         }
     115                 :            : 
     116                 :            : 
     117                 :          2 : BroFile::BroFile(FILE* arg_f)
     118                 :            :         {
     119                 :          2 :         Init();
     120                 :          2 :         f = arg_f;
     121                 :          2 :         name = access = 0;
     122                 :          2 :         t = base_type(TYPE_STRING);
     123                 :          2 :         is_open = (f != 0);
     124                 :            : 
     125   [ +  -  #  # ]:          2 :         if ( f )
     126                 :          2 :                 UpdateFileSize();
     127                 :          2 :         }
     128                 :            : 
     129                 :          0 : BroFile::BroFile(FILE* arg_f, const char* arg_name, const char* arg_access)
     130                 :            :         {
     131                 :          0 :         Init();
     132                 :          0 :         f = arg_f;
     133                 :          0 :         name = copy_string(arg_name);
     134                 :          0 :         access = copy_string(arg_access);
     135                 :          0 :         t = base_type(TYPE_STRING);
     136                 :          0 :         is_open = (f != 0);
     137                 :            : 
     138   [ #  #  #  # ]:          0 :         if ( f )
     139                 :          0 :                 UpdateFileSize();
     140                 :          0 :         }
     141                 :            : 
     142                 :         49 : BroFile::BroFile(const char* arg_name, const char* arg_access, BroType* arg_t)
     143                 :            :         {
     144                 :         49 :         Init();
     145                 :            : 
     146                 :         49 :         name = copy_string(arg_name);
     147                 :         49 :         access = copy_string(arg_access);
     148 [ +  - ][ #  # ]:         49 :         t = arg_t ? arg_t : base_type(TYPE_STRING);
     149 [ -  + ][ #  # ]:         49 :         if ( ! Open() )
     150                 :            :                 {
     151                 :          0 :                 error(fmt("cannot open %s: %s", name, strerror(errno)));
     152                 :          0 :                 is_open = 0;
     153                 :          0 :                 okay_to_manage = 0;
     154                 :            :                 }
     155                 :         49 :         }
     156                 :            : 
     157                 :          5 : const char* BroFile::Name() const
     158                 :            :         {
     159         [ +  - ]:          5 :         if ( name )
     160                 :          5 :                 return name;
     161                 :            : 
     162         [ #  # ]:          0 :         if ( f == stdin )
     163                 :          0 :                 return"/dev/stdin";
     164                 :            : 
     165         [ #  # ]:          0 :         if ( f == stdout )
     166                 :          0 :                 return "/dev/stdout";
     167                 :            : 
     168         [ #  # ]:          0 :         if ( f == stderr )
     169                 :          0 :                 return "/dev/stderr";
     170                 :            : 
     171                 :          5 :         return 0;
     172                 :            :         }
     173                 :            : 
     174                 :         49 : bool BroFile::Open(FILE* file)
     175                 :            :         {
     176         [ +  - ]:         49 :         open_time = network_time ? network_time : current_time();
     177                 :            : 
     178         [ +  + ]:         49 :         if ( ! max_files_in_cache )
     179                 :            :                 // Haven't initialized yet.
     180                 :          2 :                 max_files_in_cache = maximize_num_fds();
     181                 :            : 
     182         [ -  + ]:         49 :         if ( num_files_in_cache >= max_files_in_cache )
     183                 :          0 :                 PurgeCache();
     184                 :            : 
     185                 :         49 :         f = file;
     186                 :            : 
     187 [ -  + ][ #  # ]:         49 :         if ( default_rotation_interval &&
         [ #  # ][ -  + ]
     188                 :            :              (! attrs || ! attrs->FindAttr(ATTR_ROTATE_INTERVAL)) )
     189                 :          0 :                 rotate_interval = default_rotation_interval;
     190                 :            : 
     191 [ -  + ][ #  # ]:         49 :         if ( default_rotation_size &&
         [ #  # ][ -  + ]
     192                 :            :              (! attrs || ! attrs->FindAttr(ATTR_ROTATE_SIZE)) )
     193                 :          0 :                 rotate_size = default_rotation_size;
     194                 :            : 
     195                 :         49 :         InstallRotateTimer();
     196                 :            : 
     197         [ +  - ]:         49 :         if ( ! f )
     198                 :            :                 {
     199                 :         49 :                 f = fopen(name, access);
     200                 :         49 :                 SetBuf(buffered);
     201                 :            :                 }
     202                 :            : 
     203         [ +  - ]:         49 :         if ( f )
     204                 :            :                 {
     205                 :            :                 // These are the only files we manage, because we open them
     206                 :            :                 // ourselves and hence don't have any surprises regarding
     207                 :            :                 // whether we're allowed to close them.
     208                 :         49 :                 is_open = okay_to_manage = 1;
     209                 :            : 
     210                 :         49 :                 InsertAtBeginning();
     211                 :         49 :                 UpdateFileSize();
     212                 :            :                 }
     213                 :            :         else
     214                 :            :                 {
     215                 :            :                 // No point managing it.
     216                 :          0 :                 is_open = okay_to_manage = 0;
     217                 :         49 :                 return false;
     218                 :            :                 }
     219                 :            : 
     220                 :         49 :         RaiseOpenEvent();
     221                 :            : 
     222                 :         49 :         return true;
     223                 :            :         }
     224                 :            : 
     225                 :          1 : BroFile::~BroFile()
     226                 :            :         {
     227                 :          1 :         Close();
     228                 :          1 :         Unref(t);
     229                 :          1 :         Unref(attrs);
     230                 :            : 
     231   [ -  +  #  # ]:          1 :         delete [] name;
                 [ #  # ]
     232 [ -  + ][ #  # ]:          1 :         delete [] access;
                 [ #  # ]
     233 [ -  + ][ #  # ]:          1 :         delete [] cipher_buffer;
                 [ #  # ]
     234                 :            : 
     235                 :            : #ifdef USE_PERFTOOLS
     236                 :            :         heap_checker->UnIgnoreObject(this);
     237                 :            : #endif
     238 [ +  - ][ #  # ]:          1 :         }
                 [ #  # ]
     239                 :            : 
     240                 :         51 : void BroFile::Init()
     241                 :            :         {
     242                 :         51 :         is_open = okay_to_manage = is_in_cache = 0;
     243                 :         51 :         position = 0;
     244                 :         51 :         next = prev = 0;
     245                 :         51 :         rotate_timer = 0;
     246                 :         51 :         rotate_interval = 0.0;
     247                 :         51 :         rotate_size = current_size = 0.0;
     248                 :         51 :         open_time = 0;
     249                 :         51 :         attrs = 0;
     250                 :         51 :         buffered = true;
     251                 :         51 :         print_hook = true;
     252                 :         51 :         raw_output = false;
     253                 :         51 :         t = 0;
     254                 :         51 :         pub_key = 0;
     255                 :         51 :         cipher_ctx = 0;
     256                 :         51 :         cipher_buffer = 0;
     257                 :            : 
     258                 :            : #ifdef USE_PERFTOOLS
     259                 :            :         heap_checker->IgnoreObject(this);
     260                 :            : #endif
     261                 :         51 :         }
     262                 :            : 
     263                 :          0 : FILE* BroFile::File()
     264                 :            :         {
     265 [ #  # ][ #  # ]:          0 :         if ( okay_to_manage && ! is_in_cache )
     266                 :          0 :                 f = BringIntoCache();
     267                 :            : 
     268                 :          0 :         return f;
     269                 :            :         }
     270                 :            : 
     271                 :          0 : FILE* BroFile::BringIntoCache()
     272                 :            :         {
     273         [ #  # ]:          0 :         if ( f )
     274                 :          0 :                 internal_error("BroFile non-nil non-open file");
     275                 :            : 
     276         [ #  # ]:          0 :         if ( num_files_in_cache >= max_files_in_cache )
     277                 :          0 :                 PurgeCache();
     278                 :            : 
     279         [ #  # ]:          0 :         if ( position == 0 )
     280                 :            :                 // Need to truncate it.
     281                 :          0 :                 f = fopen(name, access);
     282                 :            :         else
     283                 :            :                 // Don't clobber it.
     284                 :          0 :                 f = fopen(name, "a");
     285                 :            : 
     286         [ #  # ]:          0 :         if ( ! f )
     287                 :            :                 {
     288                 :          0 :                 run_time("can't open %s", this);
     289                 :            : 
     290                 :          0 :                 f = fopen("/dev/null", "w");
     291                 :            : 
     292         [ #  # ]:          0 :                 if ( ! f )
     293                 :          0 :                         internal_error("out of file descriptors");
     294                 :            : 
     295                 :          0 :                 okay_to_manage = 0;
     296                 :          0 :                 return f;
     297                 :            :                 }
     298                 :            : 
     299                 :          0 :         RaiseOpenEvent();
     300                 :          0 :         UpdateFileSize();
     301                 :            : 
     302         [ #  # ]:          0 :         if ( fseek(f, position, SEEK_SET) < 0 )
     303                 :          0 :                 run_time("reopen seek failed", this);
     304                 :            : 
     305                 :          0 :         InsertAtBeginning();
     306                 :            : 
     307                 :          0 :         return f;
     308                 :            :         }
     309                 :            : 
     310                 :          0 : FILE* BroFile::Seek(long new_position)
     311                 :            :         {
     312         [ #  # ]:          0 :         if ( ! File() )
     313                 :          0 :                 return 0;
     314                 :            : 
     315         [ #  # ]:          0 :         if ( fseek(f, new_position, SEEK_SET) < 0 )
     316                 :          0 :                 run_time("seek failed", this);
     317                 :            : 
     318                 :          0 :         return f;
     319                 :            :         }
     320                 :            : 
     321                 :         49 : void BroFile::SetBuf(bool arg_buffered)
     322                 :            :         {
     323         [ -  + ]:         49 :         if ( ! f )
     324                 :          0 :                 return;
     325                 :            : 
     326 [ +  - ][ -  + ]:         49 :         if ( setvbuf(f, NULL, arg_buffered ? _IOFBF : _IOLBF, 0) != 0 )
     327                 :          0 :                 run_time("setvbuf failed", this);
     328                 :            : 
     329                 :         49 :         buffered = arg_buffered;
     330                 :            :         }
     331                 :            : 
     332                 :          9 : int BroFile::Close()
     333                 :            :         {
     334         [ -  + ]:          9 :         if ( rotate_timer )
     335                 :            :                 {
     336                 :          0 :                 timer_mgr->Cancel(rotate_timer);
     337                 :          0 :                 rotate_timer = 0;
     338                 :            :                 }
     339                 :            : 
     340         [ -  + ]:          9 :         if ( ! is_open )
     341                 :          0 :                 return 1;
     342                 :            : 
     343                 :          9 :         FinishEncrypt();
     344                 :            : 
     345                 :            :         // Do not close stdout/stderr.
     346   [ +  -  +  + ]:          9 :         if ( f == stdout || f == stderr )
     347                 :          1 :                 return 0;
     348                 :            : 
     349         [ +  - ]:          8 :         if ( is_in_cache )
     350                 :            :                 {
     351                 :          8 :                 Unlink();
     352         [ +  - ]:          8 :                 if ( f )
     353                 :            :                         {
     354                 :          8 :                         fclose(f);
     355                 :          8 :                         f = 0;
     356                 :          8 :                         open_time = 0;
     357                 :            :                         }
     358                 :            : 
     359                 :          8 :                 is_open = 0;
     360                 :          8 :                 okay_to_manage = 0; // no longer managed since will never reopen
     361                 :            : 
     362                 :          8 :                 return 1;
     363                 :            :                 }
     364                 :            : 
     365                 :            :         // Not managed.
     366         [ #  # ]:          0 :         if ( ! f )
     367                 :          0 :                 return 0;
     368                 :            : 
     369                 :          0 :         fclose(f);
     370                 :          0 :         f = 0;
     371                 :            : 
     372                 :          9 :         return 1;
     373                 :            :         }
     374                 :            : 
     375                 :          0 : void BroFile::Suspend()
     376                 :            :         {
     377         [ #  # ]:          0 :         if ( ! is_in_cache )
     378                 :          0 :                 internal_error("BroFile::Suspend() called for non-cached file");
     379         [ #  # ]:          0 :         if ( ! is_open )
     380                 :          0 :                 internal_error("BroFile::Suspend() called for non-open file");
     381                 :            : 
     382                 :          0 :         Unlink();
     383                 :            : 
     384         [ #  # ]:          0 :         if ( ! f )
     385                 :          0 :                 internal_error("BroFile::Suspend() called for nil file");
     386                 :            : 
     387         [ #  # ]:          0 :         if ( (position = ftell(f)) < 0 )
     388                 :            :                 {
     389                 :          0 :                 run_time("ftell failed", this);
     390                 :          0 :                 position = 0;
     391                 :            :                 }
     392                 :            : 
     393                 :          0 :         fclose(f);
     394                 :          0 :         f = 0;
     395                 :          0 :         }
     396                 :            : 
     397                 :          0 : void BroFile::PurgeCache()
     398                 :            :         {
     399         [ #  # ]:          0 :         if ( ! tail )
     400                 :          0 :                 internal_error("BroFile purge of empty cache");
     401                 :            : 
     402                 :          0 :         tail->Suspend();
     403                 :          0 :         }
     404                 :            : 
     405                 :          8 : void BroFile::Unlink()
     406                 :            :         {
     407         [ +  - ]:          8 :         if ( is_in_cache )
     408                 :            :                 {
     409         [ +  + ]:          8 :                 if ( head == this )
     410                 :          7 :                         head = Next();
     411                 :            :                 else
     412                 :          1 :                         Prev()->SetNext(next);
     413                 :            : 
     414         [ +  + ]:          8 :                 if ( tail == this )
     415                 :          1 :                         tail = Prev();
     416                 :            :                 else
     417                 :          7 :                         Next()->SetPrev(prev);
     418                 :            : 
     419 [ +  + ][ -  + ]:          8 :                 if ( (head || tail) && ! (head && tail) )
         [ +  - ][ -  + ]
     420                 :          0 :                         internal_error("BroFile link list botch");
     421                 :            : 
     422                 :          8 :                 is_in_cache = 0;
     423                 :          8 :                 prev = next = 0;
     424                 :            : 
     425         [ -  + ]:          8 :                 if ( --num_files_in_cache < 0 )
     426                 :          0 :                         internal_error("BroFile underflow of file cache");
     427                 :            :                 }
     428                 :          8 :         }
     429                 :            : 
     430                 :         49 : void BroFile::InsertAtBeginning()
     431                 :            :         {
     432         [ +  + ]:         49 :         if ( ! head )
     433                 :            :                 {
     434                 :          2 :                 head = tail = this;
     435                 :          2 :                 next = prev = 0;
     436                 :            :                 }
     437                 :            :         else
     438                 :            :                 {
     439                 :         47 :                 SetNext(head);
     440                 :         47 :                 SetPrev(0);
     441                 :         47 :                 head->SetPrev(this);
     442                 :         47 :                 head = this;
     443                 :            :                 }
     444                 :            : 
     445         [ -  + ]:         49 :         if ( ++num_files_in_cache > max_files_in_cache )
     446                 :          0 :                 internal_error("BroFile overflow of file cache");
     447                 :            : 
     448                 :         49 :         is_in_cache = 1;
     449                 :         49 :         }
     450                 :            : 
     451                 :          0 : void BroFile::MoveToBeginning()
     452                 :            :         {
     453         [ #  # ]:          0 :         if ( head == this )
     454                 :          0 :                 return; // already at the beginning
     455                 :            : 
     456 [ #  # ][ #  # ]:          0 :         if ( ! is_in_cache || ! prev )
     457                 :          0 :                 internal_error("BroFile inconsistency in MoveToBeginning()");
     458                 :            : 
     459                 :          0 :         Unlink();
     460                 :          0 :         InsertAtBeginning();
     461                 :            :         }
     462                 :            : 
     463                 :          0 : void BroFile::Describe(ODesc* d) const
     464                 :            :         {
     465                 :          0 :         d->AddSP("file");
     466                 :            : 
     467         [ #  # ]:          0 :         if ( name )
     468                 :            :                 {
     469                 :          0 :                 d->Add("\"");
     470                 :          0 :                 d->Add(name);
     471                 :          0 :                 d->AddSP("\"");
     472                 :            :                 }
     473                 :            : 
     474                 :          0 :         d->AddSP("of");
     475         [ #  # ]:          0 :         if ( t )
     476                 :          0 :                 t->Describe(d);
     477                 :            :         else
     478                 :          0 :                 d->Add("(no type)");
     479                 :          0 :         }
     480                 :            : 
     481                 :         38 : void BroFile::SetAttrs(Attributes* arg_attrs)
     482                 :            :         {
     483         [ -  + ]:         38 :         if ( ! arg_attrs )
     484                 :          0 :                 return;
     485                 :            : 
     486                 :         38 :         attrs = arg_attrs;
     487                 :         38 :         Ref(attrs);
     488                 :            : 
     489                 :         38 :         Attr* ef = attrs->FindAttr(ATTR_ROTATE_INTERVAL);
     490         [ -  + ]:         38 :         if ( ef )
     491                 :          0 :                 rotate_interval = ef->AttrExpr()->ExprVal()->AsInterval();
     492                 :            : 
     493                 :         38 :         ef = attrs->FindAttr(ATTR_ROTATE_SIZE);
     494         [ -  + ]:         38 :         if ( ef )
     495                 :          0 :                 rotate_size = ef->AttrExpr()->ExprVal()->AsDouble();
     496                 :            : 
     497                 :         38 :         ef = attrs->FindAttr(ATTR_ENCRYPT);
     498         [ -  + ]:         38 :         if ( ef )
     499                 :            :                 {
     500         [ #  # ]:          0 :                 if ( ef->AttrExpr() )
     501                 :          0 :                         InitEncrypt(ef->AttrExpr()->ExprVal()->AsString()->CheckString());
     502                 :            :                 else
     503                 :          0 :                         InitEncrypt(log_encryption_key->AsString()->CheckString());
     504                 :            :                 }
     505                 :            : 
     506         [ -  + ]:         38 :         if ( attrs->FindAttr(ATTR_DISABLE_PRINT_HOOK) )
     507                 :          0 :                 DisablePrintHook();
     508                 :            : 
     509         [ -  + ]:         38 :         if ( attrs->FindAttr(ATTR_RAW_OUTPUT) )
     510                 :          0 :                 EnableRawOutput();
     511                 :            :         
     512                 :         38 :         InstallRotateTimer();
     513                 :            :         }
     514                 :            : 
     515                 :          0 : void BroFile::SetRotateInterval(double secs)
     516                 :            :         {
     517                 :          0 :         rotate_interval = secs;
     518                 :          0 :         InstallRotateTimer();
     519                 :          0 :         }
     520                 :            : 
     521                 :          0 : RecordVal* BroFile::Rotate()
     522                 :            :         {
     523         [ #  # ]:          0 :         if ( ! is_open )
     524                 :          0 :                 return 0;
     525                 :            : 
     526 [ #  # ][ #  # ]:          0 :         if ( okay_to_manage && ! is_in_cache )
     527                 :          0 :                 BringIntoCache();
     528                 :            : 
     529                 :          0 :         RecordVal* info = new RecordVal(rotate_info);
     530                 :          0 :         FILE* newf = rotate_file(name, info);
     531                 :            : 
     532         [ #  # ]:          0 :         if ( ! newf )
     533                 :            :                 {
     534                 :          0 :                 Unref(info);
     535                 :          0 :                 return 0;
     536                 :            :                 }
     537                 :            : 
     538                 :          0 :         info->Assign(2, new Val(open_time, TYPE_TIME));
     539                 :            : 
     540                 :          0 :         Unlink();
     541                 :          0 :         fclose(f);
     542                 :          0 :         f = 0;
     543                 :            : 
     544                 :          0 :         Open(newf);
     545                 :          0 :         return info;
     546                 :            :         }
     547                 :            : 
     548                 :         95 : void BroFile::InstallRotateTimer()
     549                 :            :         {
     550         [ -  + ]:         95 :         if ( terminating )
     551                 :          0 :                 return;
     552                 :            : 
     553         [ -  + ]:         95 :         if ( rotate_timer )
     554                 :            :                 {
     555                 :          0 :                 timer_mgr->Cancel(rotate_timer);
     556                 :          0 :                 rotate_timer = 0;
     557                 :            :                 }
     558                 :            : 
     559         [ -  + ]:         95 :         if ( rotate_interval )
     560                 :            :                 {
     561                 :            :                 // When this is called for the first time, network_time can
     562                 :            :                 // still be zero. If so, we set a timer which fires
     563                 :            :                 // immediately but doesn't rotate when it expires.
     564                 :            : 
     565         [ #  # ]:          0 :                 if ( ! network_time )
     566                 :          0 :                         rotate_timer = new RotateTimer(1, this, false);
     567                 :            :                 else
     568                 :            :                         {
     569         [ #  # ]:          0 :                         if ( ! open_time )
     570                 :          0 :                                 open_time = network_time;
     571                 :            : 
     572                 :            :                         const char* base_time = log_rotate_base_time ?
     573         [ #  # ]:          0 :                                 log_rotate_base_time->AsString()->CheckString() : 0;
     574                 :            : 
     575                 :            :                         double delta_t =
     576                 :          0 :                                 calc_next_rotate(rotate_interval, base_time);
     577                 :            :                         rotate_timer = new RotateTimer(network_time + delta_t,
     578                 :          0 :                                                         this, true);
     579                 :            :                         }
     580                 :            : 
     581                 :         95 :                 timer_mgr->Add(rotate_timer);
     582                 :            :                 }
     583                 :            :         }
     584                 :            : 
     585                 :          1 : void BroFile::SetDefaultRotation(double interval, double max_size)
     586                 :            :         {
     587         [ +  + ]:          9 :         for ( BroFile* f = head; f; f = f->next )
     588                 :            :                 {
     589 [ +  + ][ +  - ]:          8 :                 if ( ! (f->attrs && f->attrs->FindAttr(ATTR_ROTATE_INTERVAL)) )
                 [ +  - ]
     590                 :            :                         {
     591                 :          8 :                         f->rotate_interval = interval;
     592                 :          8 :                         f->InstallRotateTimer();
     593                 :            :                         }
     594                 :            : 
     595 [ +  + ][ +  - ]:          8 :                 if ( ! (f->attrs && f->attrs->FindAttr(ATTR_ROTATE_SIZE)) )
                 [ +  - ]
     596                 :          8 :                         f->rotate_size = max_size;
     597                 :            :                 }
     598                 :            : 
     599                 :          1 :         default_rotation_interval = interval;
     600                 :          1 :         default_rotation_size = max_size;
     601                 :          1 :         }
     602                 :            : 
     603                 :          1 : void BroFile::CloseCachedFiles()
     604                 :            :         {
     605                 :            :         BroFile* next;
     606         [ +  + ]:          8 :         for ( BroFile* f = head; f; f = next )
     607                 :            :                 {
     608                 :            :                 // Send final rotate events (immediately).
     609         [ -  + ]:          7 :                 if ( f->rotate_interval )
     610                 :            :                         {
     611                 :          0 :                         val_list* vl = new val_list;
     612                 :          0 :                         Ref(f);
     613                 :          0 :                         vl->append(new Val(f));
     614                 :          0 :                         Event* event = new Event(::rotate_interval, vl);
     615                 :          0 :                         mgr.Dispatch(event, true);
     616                 :            :                         }
     617                 :            : 
     618         [ -  + ]:          7 :                 if ( f->rotate_size )
     619                 :            :                         {
     620                 :          0 :                         val_list* vl = new val_list;
     621                 :          0 :                         Ref(f);
     622                 :          0 :                         vl->append(new Val(f));
     623                 :          0 :                         Event* event = new ::Event(::rotate_size, vl);
     624                 :          0 :                         mgr.Dispatch(event, true);
     625                 :            :                         }
     626                 :            : 
     627                 :          7 :                 next = f->next;
     628         [ +  - ]:          7 :                 if ( f->is_in_cache )
     629                 :          7 :                         f->Close();
     630                 :            :                 }
     631                 :          1 :         }
     632                 :            : 
     633                 :          0 : void BroFile::InitEncrypt(const char* keyfile)
     634                 :            :         {
     635   [ #  #  #  # ]:          0 :         if ( ! (pub_key || keyfile) )
     636                 :          0 :                 return;
     637                 :            : 
     638         [ #  # ]:          0 :         if ( ! pub_key )
     639                 :            :                 {
     640                 :          0 :                 FILE* key = fopen(keyfile, "r");
     641                 :            : 
     642         [ #  # ]:          0 :                 if ( ! key )
     643                 :            :                         {
     644                 :          0 :                         error(fmt("can't open key file %s: %s", keyfile, strerror(errno)));
     645                 :          0 :                         Close();
     646                 :            :                         return;
     647                 :            :                         }
     648                 :            : 
     649                 :          0 :                 pub_key = PEM_read_PUBKEY(key, 0, 0, 0);
     650         [ #  # ]:          0 :                 if ( ! pub_key )
     651                 :            :                         {
     652                 :            :                         error(fmt("can't read key from %s: %s", keyfile,
     653                 :          0 :                                         ERR_error_string(ERR_get_error(), 0)));
     654                 :          0 :                         Close();
     655                 :            :                         return;
     656                 :            :                         }
     657                 :            :                 }
     658                 :            : 
     659                 :            :         // Depending on the OpenSSL version, EVP_*_cbc()
     660                 :            :         // returns a const or a non-const.
     661                 :          0 :         EVP_CIPHER* cipher_type = (EVP_CIPHER*) EVP_bf_cbc();
     662                 :          0 :         cipher_ctx = new EVP_CIPHER_CTX;
     663                 :            : 
     664                 :          0 :         unsigned char secret[EVP_PKEY_size(pub_key)];
     665                 :          0 :         unsigned char* psecret = secret;
     666                 :            :         unsigned long secret_len;
     667                 :            : 
     668                 :          0 :         int iv_len = EVP_CIPHER_iv_length(cipher_type);
     669                 :          0 :         unsigned char iv[iv_len];
     670                 :            : 
     671         [ #  # ]:          0 :         if ( ! EVP_SealInit(cipher_ctx, cipher_type, &psecret,
     672                 :            :                                 (int*) &secret_len, iv, &pub_key, 1) )
     673                 :            :                 {
     674                 :            :                 error(fmt("can't init cipher context for %s: %s", keyfile,
     675                 :          0 :                                 ERR_error_string(ERR_get_error(), 0)));
     676                 :          0 :                 Close();
     677                 :            :                 return;
     678                 :            :                 }
     679                 :            : 
     680                 :          0 :         secret_len = htonl(secret_len);
     681                 :            : 
     682   [ #  #  #  # ]:          0 :         if ( ! (fwrite("BROENC1", 7, 1, f) &&
         [ #  # ][ #  # ]
                 [ #  # ]
     683                 :            :                 fwrite(&secret_len, sizeof(secret_len), 1, f) &&
     684                 :            :                 fwrite(secret, ntohl(secret_len), 1, f) &&
     685                 :            :                 fwrite(iv, iv_len, 1, f)) )
     686                 :            :                 {
     687                 :            :                 error(fmt("can't write header to log file %s: %s",
     688                 :          0 :                                 name, strerror(errno)));
     689                 :          0 :                 Close();
     690                 :            :                 return;
     691                 :            :                 }
     692                 :            : 
     693                 :          0 :         int buf_size = MIN_BUFFER_SIZE + EVP_CIPHER_block_size(cipher_type);
     694         [ #  # ]:          0 :         cipher_buffer = new unsigned char[buf_size];
     695                 :            :         }
     696                 :            : 
     697                 :          9 : void BroFile::FinishEncrypt()
     698                 :            :         {
     699         [ -  + ]:          9 :         if ( ! is_open )
     700                 :          0 :                 return;
     701                 :            : 
     702         [ +  - ]:          9 :         if ( ! pub_key )
     703                 :          9 :                 return;
     704                 :            : 
     705         [ #  # ]:          0 :         if ( cipher_ctx )
     706                 :            :                 {
     707                 :            :                 int outl;
     708                 :          0 :                 EVP_SealFinal(cipher_ctx, cipher_buffer, &outl);
     709                 :            : 
     710   [ #  #  #  # ]:          0 :                 if ( outl && ! fwrite(cipher_buffer, outl, 1, f) )
                 [ #  # ]
     711                 :            :                         {
     712                 :            :                         run_time(fmt("write error for %s: %s",
     713                 :          0 :                                         name, strerror(errno)));
     714                 :          0 :                         return;
     715                 :            :                         }
     716                 :            : 
     717                 :          0 :                 delete cipher_ctx;
     718                 :          9 :                 cipher_ctx = 0;
     719                 :            :                 }
     720                 :            :         }
     721                 :            : 
     722                 :            : 
     723                 :      11309 : int BroFile::Write(const char* data, int len)
     724                 :            :         {
     725         [ -  + ]:      11309 :         if ( ! is_open )
     726                 :          0 :                 return 0;
     727                 :            : 
     728 [ +  + ][ -  + ]:      11309 :         if ( ! is_in_cache && okay_to_manage )
     729                 :          0 :                 BringIntoCache();
     730                 :            : 
     731         [ +  + ]:      11309 :         if ( ! len )
     732                 :       1379 :                 len = strlen(data);
     733                 :            : 
     734         [ -  + ]:      11309 :         if ( cipher_ctx )
     735                 :            :                 {
     736         [ #  # ]:          0 :                 while ( len )
     737                 :            :                         {
     738                 :            :                         int outl;
     739                 :          0 :                         int inl = min(MIN_BUFFER_SIZE, len);
     740                 :            : 
     741         [ #  # ]:          0 :                         if ( ! EVP_SealUpdate(cipher_ctx, cipher_buffer, &outl,
     742                 :            :                                                 (unsigned char*)data, inl) )
     743                 :            :                                 {
     744                 :            :                                 run_time(fmt("encryption error for %s: %s",
     745                 :            :                                         name,
     746                 :          0 :                                         ERR_error_string(ERR_get_error(), 0)));
     747                 :          0 :                                 Close();
     748                 :          0 :                                 return 0;
     749                 :            :                                 }
     750                 :            : 
     751 [ #  # ][ #  # ]:          0 :                         if ( outl && ! fwrite(cipher_buffer, outl, 1, f) )
                 [ #  # ]
     752                 :            :                                 {
     753                 :            :                                 run_time(fmt("write error for %s: %s",
     754                 :          0 :                                                 name, strerror(errno)));
     755                 :          0 :                                 Close();
     756                 :          0 :                                 return 0;
     757                 :            :                                 }
     758                 :            : 
     759                 :          0 :                         data += inl;
     760                 :          0 :                         len -= inl;
     761                 :            :                         }
     762                 :            : 
     763                 :          0 :                 return 1;
     764                 :            :                 }
     765                 :            : 
     766                 :      11309 :         len = fwrite(data, 1, len, f);
     767         [ -  + ]:      11309 :         if ( len <= 0 )
     768                 :          0 :                 return false;
     769                 :            : 
     770 [ -  + ][ #  # ]:      11309 :         if ( rotate_size && current_size < rotate_size && current_size + len >= rotate_size )
                 [ #  # ]
     771                 :            :                 {
     772                 :          0 :                 val_list* vl = new val_list;
     773                 :          0 :                 vl->append(new Val(this));
     774                 :          0 :                 mgr.QueueEvent(::rotate_size, vl);
     775                 :            :                 }
     776                 :            : 
     777                 :            :         // This does not work if we seek around. But none of the logs does that
     778                 :            :         // and we avoid stat()'ing the file all the time.
     779                 :      11309 :         current_size += len;
     780                 :            : 
     781                 :      11309 :         return true;
     782                 :            :         }
     783                 :            : 
     784                 :         49 : void BroFile::RaiseOpenEvent()
     785                 :            :         {
     786         [ +  + ]:         49 :         if ( ! ::file_opened )
     787                 :         49 :                 return;
     788                 :            : 
     789                 :          5 :         val_list* vl = new val_list;
     790                 :          5 :         Ref(this);
     791                 :          5 :         vl->append(new Val(this));
     792                 :          5 :         Event* event = new ::Event(::file_opened, vl);
     793                 :          5 :         mgr.Dispatch(event, true);
     794                 :            :         }
     795                 :            : 
     796                 :         51 : void BroFile::UpdateFileSize()
     797                 :            :         {
     798                 :            :         struct stat s;
     799         [ -  + ]:         51 :         if ( fstat(fileno(f), &s) < 0 )
     800                 :            :                 {
     801                 :          0 :                 run_time(fmt("can't stat fd for %s: %s", name, strerror(errno)));
     802                 :          0 :                 current_size = 0;
     803                 :          0 :                 return;
     804                 :            :                 }
     805                 :            : 
     806                 :         51 :         current_size = double(s.st_size);
     807                 :            :         }
     808                 :            : 
     809                 :          0 : bool BroFile::Serialize(SerialInfo* info) const
     810                 :            :         {
     811                 :          0 :         return SerialObj::Serialize(info);
     812                 :            :         }
     813                 :            : 
     814                 :          0 : BroFile* BroFile::GetFile(const char* name)
     815                 :            :         {
     816         [ #  # ]:          0 :         for ( BroFile* f = head; f; f = f->next )
     817                 :            :                 {
     818 [ #  # ][ #  # ]:          0 :                 if ( f->name && streq(name, f->name) )
                 [ #  # ]
     819                 :          0 :                         return f;
     820                 :            :                 }
     821                 :            : 
     822                 :          0 :         return new BroFile(name, "w", 0);
     823                 :            :         }
     824                 :            : 
     825                 :          0 : BroFile* BroFile::Unserialize(UnserialInfo* info)
     826                 :            :         {
     827                 :          0 :         BroFile* file = (BroFile*) SerialObj::Unserialize(info, SER_BRO_FILE);
     828                 :            : 
     829         [ #  # ]:          0 :         if ( ! file )
     830                 :          0 :                 return 0;
     831                 :            : 
     832         [ #  # ]:          0 :         if ( file->is_open )
     833                 :          0 :                 return file;
     834                 :            : 
     835                 :            :         // If there is already an object for this file, return it.
     836         [ #  # ]:          0 :         if ( file->name )
     837                 :            :                 {
     838         [ #  # ]:          0 :                 for ( BroFile* f = head; f; f = f->next )
     839                 :            :                         {
     840 [ #  # ][ #  # ]:          0 :                         if ( f->name && streq(file->name, f->name) )
                 [ #  # ]
     841                 :            :                                 {
     842                 :          0 :                                 Unref(file);
     843                 :          0 :                                 Ref(f);
     844                 :          0 :                                 return f;
     845                 :            :                                 }
     846                 :            :                         }
     847                 :            :                 }
     848                 :            : 
     849                 :            :         // Otherwise, open.
     850         [ #  # ]:          0 :         if ( ! file->Open() )
     851                 :            :                 {
     852                 :            :                 info->s->Error(fmt("cannot open %s: %s",
     853                 :          0 :                                         file->name, strerror(errno)));
     854                 :          0 :                 return 0;
     855                 :            :                 }
     856                 :            : 
     857                 :            :         // Here comes a hack.  This method will return a pointer to a newly
     858                 :            :         // instantiated file object.  As soon as this pointer is Unref'ed, the
     859                 :            :         // file will be closed.  That means that when we unserialize the same
     860                 :            :         // file next time, we will re-open it and thereby delete the first one,
     861                 :            :         // i.e., we will be keeping to delete what we've written just before.
     862                 :            :         //
     863                 :            :         // To avoid this loop, we do an extra Ref here, i.e., this file will
     864                 :            :         // *never* be closed anymore (as long the file cache does not overflow).
     865                 :          0 :         Ref(file);
     866                 :            : 
     867                 :            :         // We deliberately override log rotation attributes with our defaults.
     868                 :          0 :         file->rotate_interval = log_rotate_interval;
     869                 :          0 :         file->rotate_size = log_max_size;
     870                 :          0 :         file->InstallRotateTimer();
     871                 :          0 :         file->SetBuf(file->buffered);
     872                 :            : 
     873                 :          0 :         return file;
     874                 :            :         }
     875                 :            : 
     876                 :          3 : IMPLEMENT_SERIAL(BroFile, SER_BRO_FILE);
     877                 :            : 
     878                 :          0 : bool BroFile::DoSerialize(SerialInfo* info) const
     879                 :            :         {
     880 [ #  # ][ #  # ]:          0 :         DO_SERIALIZE(SER_BRO_FILE, BroObj);
     881                 :            : 
     882                 :          0 :         const char* s = name;
     883                 :            : 
     884         [ #  # ]:          0 :         if ( ! okay_to_manage )
     885                 :            :                 {
     886                 :            :                 // We can handle stdin/stdout/stderr but no others.
     887         [ #  # ]:          0 :                 if ( f == stdin )
     888                 :          0 :                         s = "/dev/stdin";
     889         [ #  # ]:          0 :                 else if ( f == stdout )
     890                 :          0 :                         s = "/dev/stdout";
     891         [ #  # ]:          0 :                 else if ( f == stderr )
     892                 :          0 :                         s = "/dev/stderr";
     893                 :            :                 else
     894                 :            :                         {
     895                 :            :                         // We don't manage the file, and therefore don't
     896                 :            :                         // really know how to pass it on to the other side.
     897                 :            :                         // However, in order to not abort communication
     898                 :            :                         // when this happens, we still send the name if we
     899                 :            :                         // have one; or if we don't, we create a special
     900                 :            :                         // "dont-have-a-file" file to be created on the
     901                 :            :                         // receiver side.
     902         [ #  # ]:          0 :                         if ( ! s )
     903                 :          0 :                                 s = "unmanaged-bro-output-file.log";
     904                 :            :                         }
     905                 :            :                 }
     906                 :            : 
     907 [ #  # ][ #  # ]:          0 :         if ( ! (SERIALIZE(s) && SERIALIZE(buffered)) )
                 [ #  # ]
     908                 :          0 :                 return false;
     909                 :            : 
     910 [ #  # ][ #  # ]:          0 :         SERIALIZE_OPTIONAL_STR(access);
         [ #  # ][ #  # ]
                 [ #  # ]
     911                 :            : 
     912         [ #  # ]:          0 :         if ( ! t->Serialize(info) )
     913                 :          0 :                 return false;
     914                 :            : 
     915 [ #  # ][ #  # ]:          0 :         SERIALIZE_OPTIONAL(attrs);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     916                 :          0 :         return true;
     917                 :            :         }
     918                 :            : 
     919                 :          0 : bool BroFile::DoUnserialize(UnserialInfo* info)
     920                 :            :         {
     921         [ #  # ]:          0 :         DO_UNSERIALIZE(BroObj);
     922                 :            : 
     923 [ #  # ][ #  # ]:          0 :         if ( ! (UNSERIALIZE_STR(&name, 0) && UNSERIALIZE(&buffered)) )
                 [ #  # ]
     924                 :          0 :                 return false;
     925                 :            : 
     926 [ #  # ][ #  # ]:          0 :         UNSERIALIZE_OPTIONAL_STR(access);
                 [ #  # ]
     927                 :            : 
     928                 :          0 :         t = BroType::Unserialize(info);
     929         [ #  # ]:          0 :         if ( ! t )
     930                 :          0 :                 return false;
     931                 :            : 
     932 [ #  # ][ #  # ]:          0 :         UNSERIALIZE_OPTIONAL(attrs, Attributes::Unserialize(info));
                 [ #  # ]
     933                 :            : 
     934                 :            :         // Parse attributes.
     935                 :          0 :         SetAttrs(attrs);
     936                 :            :         // SetAttrs() has ref'ed attrs again.
     937                 :          0 :         Unref(attrs);
     938                 :            : 
     939                 :            :         // Bind stdin/stdout/stderr.
     940                 :          0 :         FILE* file = 0;
     941                 :          0 :         is_open = false;
     942                 :          0 :         f = 0;
     943                 :            : 
     944         [ #  # ]:          0 :         if ( streq(name, "/dev/stdin") )
     945                 :          0 :                 file = stdin;
     946         [ #  # ]:          0 :         else if ( streq(name, "/dev/stdout") )
     947                 :          0 :                 file = stdout;
     948         [ #  # ]:          0 :         else if ( streq(name, "/dev/stderr") )
     949                 :          0 :                 file = stderr;
     950                 :            : 
     951         [ #  # ]:          0 :         if ( file )
     952                 :            :                 {
     953         [ #  # ]:          0 :                 delete [] name;
     954                 :          0 :                 name = 0;
     955                 :          0 :                 f = file;
     956                 :          0 :                 is_open = true;
     957                 :            :                 }
     958                 :            : 
     959                 :          0 :         return true;
     960 [ +  - ][ +  - ]:          6 :         }

Generated by: LCOV version 1.8