#include "ace/Logging_Strategy.h" #include "ace/Service_Config.h" #include "ace/ACE.h" #include "ace/ACE_export.h" #include "ace/Get_Opt.h" // FUZZ: disable check_for_streams_include #include "ace/streams.h" #include "ace/Lib_Find.h" #include "ace/Log_Category.h" #include "ace/Reactor.h" #include "ace/OS_NS_string.h" #include "ace/OS_NS_stdio.h" #include "ace/OS_NS_unistd.h" ACE_BEGIN_VERSIONED_NAMESPACE_DECL // Parse the string containing (thread) priorities and set them // accordingly. void ACE_Logging_Strategy::priorities (ACE_TCHAR *priority_string, ACE_Log_Msg::MASK_TYPE mask) { u_long priority_mask = 0; // Choose priority mask to change. if (mask == ACE_Log_Msg::PROCESS) priority_mask = process_priority_mask_; else priority_mask = thread_priority_mask_; ACE_TCHAR *strtokp = 0; // Parse string and alternate priority mask. for (ACE_TCHAR *priority = ACE_OS::strtok_r (priority_string, ACE_TEXT ("|"), &strtokp); priority != 0; priority = ACE_OS::strtok_r (0, ACE_TEXT ("|"), &strtokp)) { if (ACE_OS::strcmp (priority, ACE_TEXT ("SHUTDOWN")) == 0) ACE_SET_BITS (priority_mask, LM_SHUTDOWN); else if (ACE_OS::strcmp (priority, ACE_TEXT ("~SHUTDOWN")) == 0) ACE_CLR_BITS (priority_mask, LM_SHUTDOWN); else if (ACE_OS::strcmp (priority, ACE_TEXT ("TRACE")) == 0) ACE_SET_BITS (priority_mask, LM_TRACE); else if (ACE_OS::strcmp (priority, ACE_TEXT ("~TRACE")) == 0) ACE_CLR_BITS (priority_mask, LM_TRACE); else if (ACE_OS::strcmp (priority, ACE_TEXT ("DEBUG")) == 0) ACE_SET_BITS (priority_mask, LM_DEBUG); else if (ACE_OS::strcmp (priority, ACE_TEXT ("~DEBUG")) == 0) ACE_CLR_BITS (priority_mask, LM_DEBUG); else if (ACE_OS::strcmp (priority, ACE_TEXT ("INFO")) == 0) ACE_SET_BITS (priority_mask, LM_INFO); else if (ACE_OS::strcmp (priority, ACE_TEXT ("~INFO")) == 0) ACE_CLR_BITS (priority_mask, LM_INFO); else if (ACE_OS::strcmp (priority, ACE_TEXT ("NOTICE")) == 0) ACE_SET_BITS (priority_mask, LM_NOTICE); else if (ACE_OS::strcmp (priority, ACE_TEXT ("~NOTICE")) == 0) ACE_CLR_BITS (priority_mask, LM_NOTICE); else if (ACE_OS::strcmp (priority, ACE_TEXT ("WARNING")) == 0) ACE_SET_BITS (priority_mask, LM_WARNING); else if (ACE_OS::strcmp (priority, ACE_TEXT ("~WARNING")) == 0) ACE_CLR_BITS (priority_mask, LM_WARNING); else if (ACE_OS::strcmp (priority, ACE_TEXT ("STARTUP")) == 0) ACE_SET_BITS (priority_mask, LM_STARTUP); else if (ACE_OS::strcmp (priority, ACE_TEXT ("~STARTUP")) == 0) ACE_CLR_BITS (priority_mask, LM_STARTUP); else if (ACE_OS::strcmp (priority, ACE_TEXT ("ERROR")) == 0) ACE_SET_BITS (priority_mask, LM_ERROR); else if (ACE_OS::strcmp (priority, ACE_TEXT ("~ERROR")) == 0) ACE_CLR_BITS (priority_mask, LM_ERROR); else if (ACE_OS::strcmp (priority, ACE_TEXT ("CRITICAL")) == 0) ACE_SET_BITS (priority_mask, LM_CRITICAL); else if (ACE_OS::strcmp (priority, ACE_TEXT ("~CRITICAL")) == 0) ACE_CLR_BITS (priority_mask, LM_CRITICAL); else if (ACE_OS::strcmp (priority, ACE_TEXT ("ALERT")) == 0) ACE_SET_BITS (priority_mask, LM_ALERT); else if (ACE_OS::strcmp (priority, ACE_TEXT ("~ALERT")) == 0) ACE_CLR_BITS (priority_mask, LM_ALERT); else if (ACE_OS::strcmp (priority, ACE_TEXT ("EMERGENCY")) == 0) ACE_SET_BITS (priority_mask, LM_EMERGENCY); else if (ACE_OS::strcmp (priority, ACE_TEXT ("~EMERGENCY")) == 0) ACE_CLR_BITS (priority_mask, LM_EMERGENCY); } // Affect right priority mask. if (mask == ACE_Log_Msg::PROCESS) process_priority_mask_ = priority_mask; else thread_priority_mask_ = priority_mask; } // Parse the string containing all the flags and set the flags // accordingly. void ACE_Logging_Strategy::tokenize (ACE_TCHAR *flag_string) { ACE_TCHAR *strtokp; for (ACE_TCHAR *flag = ACE_OS::strtok_r (flag_string, ACE_TEXT ("|"), &strtokp); flag != 0; flag = ACE_OS::strtok_r (0, ACE_TEXT ("|"), &strtokp)) { if (ACE_OS::strcmp (flag, ACE_TEXT ("STDERR")) == 0) ACE_SET_BITS (this->flags_, ACE_Log_Msg::STDERR); else if (ACE_OS::strcmp (flag, ACE_TEXT ("LOGGER")) == 0) ACE_SET_BITS (this->flags_, ACE_Log_Msg::LOGGER); else if (ACE_OS::strcmp (flag, ACE_TEXT ("OSTREAM")) == 0) ACE_SET_BITS (this->flags_, ACE_Log_Msg::OSTREAM); else if (ACE_OS::strcmp (flag, ACE_TEXT ("VERBOSE")) == 0) ACE_SET_BITS (this->flags_, ACE_Log_Msg::VERBOSE); else if (ACE_OS::strcmp (flag, ACE_TEXT ("VERBOSE_LITE")) == 0) ACE_SET_BITS (this->flags_, ACE_Log_Msg::VERBOSE_LITE); else if (ACE_OS::strcmp (flag, ACE_TEXT ("SILENT")) == 0) ACE_SET_BITS (this->flags_, ACE_Log_Msg::SILENT); else if (ACE_OS::strcmp (flag, ACE_TEXT ("SYSLOG")) == 0) ACE_SET_BITS (this->flags_, ACE_Log_Msg::SYSLOG); } } int ACE_Logging_Strategy::parse_args (int argc, ACE_TCHAR *argv[]) { ACE_TRACE ("ACE_Logging_Strategy::parse_args"); ACE_TCHAR *temp; // Perform data member initializations. BTW, do *not* initialize // or here to avoid // unduing the behavior in , where these are set by // . this->flags_ = 0; this->wipeout_logfile_ = false; this->count_ = 0; this->fixed_number_ = false; this->order_files_ = false; this->max_file_number_ = 1; this->interval_ = ACE_DEFAULT_LOGFILE_POLL_INTERVAL; this->max_size_ = 0; ACE_Get_Opt get_opt (argc, argv, ACE_TEXT ("f:i:k:m:n:N:op:s:t:w"), 0); for (int c; (c = get_opt ()) != -1; ) { switch (c) { case 'f': temp = get_opt.opt_arg (); // Now tokenize the string to get all the flags this->tokenize (temp); // If LOGGER was specified, set up the default logger key. // The key can be changed by the -k option also, so if it's // been set already, don't set it. if (ACE_BIT_ENABLED (this->flags_, ACE_Log_Msg::LOGGER) && this->logger_key_ == 0) this->logger_key_ = ACE::strnew (ACE_DEFAULT_LOGGER_KEY); break; case 'i': // Interval (in secs) at which logfile size is sampled. this->interval_ = ACE_OS::strtoul (get_opt.opt_arg (), 0, 10); break; case 'k': // Ensure that the LOGGER flag is set ACE_SET_BITS (this->flags_, ACE_Log_Msg::LOGGER); #if defined (ACE_HAS_ALLOC_HOOKS) ACE_Allocator::instance()->free(this->logger_key_); #else delete [] this->logger_key_; #endif /* ACE_HAS_ALLOC_HOOKS */ this->logger_key_ = ACE::strnew (get_opt.opt_arg ()); break; case 'm': // Maximum logfile size (in KB). Must be a non-zero value. this->max_size_ = ACE_OS::strtoul (get_opt.opt_arg (), 0, 10); this->max_size_ <<= 10; // convert from KB to bytes. break; case 'n': #if defined (ACE_HAS_ALLOC_HOOKS) ACE_Allocator::instance()->free(this->program_name_); #else delete [] this->program_name_; #endif /* ACE_HAS_ALLOC_HOOKS */ this->program_name_ = ACE::strnew (get_opt.opt_arg ()); break; case 'N': // The max number for the log_file being created this->max_file_number_ = ACE_OS::atoi (get_opt.opt_arg ()) - 1; this->fixed_number_ = true; break; case 'o': // Log_files generation order this->order_files_ = true; break; case 'p': temp = get_opt.opt_arg (); // Now tokenize the string to setup process log priority this->priorities (temp, ACE_Log_Msg::PROCESS); break; case 's': // Ensure that the OSTREAM flag is set ACE_SET_BITS (this->flags_, ACE_Log_Msg::OSTREAM); #if defined (ACE_HAS_ALLOC_HOOKS) ACE_Allocator::instance()->free(this->filename_); #else delete [] this->filename_; #endif /* ACE_HAS_ALLOC_HOOKS */ this->filename_ = ACE::strnew (get_opt.opt_arg ()); break; case 't': temp = get_opt.opt_arg (); // Now tokenize the string to setup thread log priority this->priorities (temp, ACE_Log_Msg::THREAD); break; case 'w': // Cause the logfile to be wiped out, both on startup and on // reconfigure. this->wipeout_logfile_ = true; break; default: break; } } return 0; } ACE_Logging_Strategy::ACE_Logging_Strategy () : thread_priority_mask_ (0), process_priority_mask_ (0), flags_ (0), filename_ (0), logger_key_ (0), program_name_ (0), wipeout_logfile_ (false), fixed_number_ (false), order_files_ (false), count_ (0), max_file_number_ (1), // 2 files by default (max file number + 1) interval_ (ACE_DEFAULT_LOGFILE_POLL_INTERVAL), max_size_ (0), log_msg_ (ACE_Log_Msg::instance ()) { #if defined (ACE_DEFAULT_LOGFILE) this->filename_ = ACE::strnew (ACE_DEFAULT_LOGFILE); #else /* ACE_DEFAULT_LOGFILE */ #if defined (ACE_HAS_ALLOC_HOOKS) ACE_ALLOCATOR (this->filename_, static_cast(ACE_Allocator::instance()->malloc(sizeof(ACE_TCHAR) * (MAXPATHLEN + 1)))); #else ACE_NEW (this->filename_, ACE_TCHAR[MAXPATHLEN + 1]); #endif /* ACE_HAS_ALLOC_HOOKS */ // Get the temporary directory if (ACE::get_temp_dir (this->filename_, MAXPATHLEN - 7) == -1) // 7 for "logfile" { ACELIB_ERROR ((LM_ERROR, ACE_TEXT ("Temporary path too long, ") ACE_TEXT ("defaulting to current directory\n"))); this->filename_[0] = 0; } // Add the filename to the end ACE_OS::strcat (this->filename_, ACE_TEXT ("logfile")); #endif /* ACE_DEFAULT_LOGFILE */ } ACE_Logging_Strategy::~ACE_Logging_Strategy () { // This is allocated in constructor, so it must be deallocated in // the destructor! #if defined (ACE_HAS_ALLOC_HOOKS) ACE_Allocator::instance()->free(this->filename_); #else delete [] this->filename_; #endif /* ACE_HAS_ALLOC_HOOKS */ } int ACE_Logging_Strategy::fini () { #if defined (ACE_HAS_ALLOC_HOOKS) ACE_Allocator::instance()->free(this->filename_); #else delete [] this->filename_; #endif /* ACE_HAS_ALLOC_HOOKS */ this->filename_ = 0; // Avoid double deletions. #if defined (ACE_HAS_ALLOC_HOOKS) ACE_Allocator::instance()->free(this->logger_key_); ACE_Allocator::instance()->free(this->program_name_); #else delete [] this->logger_key_; delete [] this->program_name_; #endif /* ACE_HAS_ALLOC_HOOKS */ if (this->reactor () && this->interval_ > 0 && this->max_size_ > 0) this->reactor ()->cancel_timer (this); return 0; } int ACE_Logging_Strategy::init (int argc, ACE_TCHAR *argv[]) { ACE_TRACE ("ACE_Logging_Strategy::init"); // Store current priority masks for changes in . this->process_priority_mask_ = this->log_msg_->priority_mask (ACE_Log_Msg::PROCESS); this->thread_priority_mask_ = this->log_msg_->priority_mask (ACE_Log_Msg::THREAD); // Use the options hook to parse the command line arguments. this->parse_args (argc, argv); // Setup priorities (to original if not specified on command line) this->log_msg_->priority_mask (thread_priority_mask_, ACE_Log_Msg::THREAD); this->log_msg_->priority_mask (process_priority_mask_, ACE_Log_Msg::PROCESS); // Check if any flags were specified. If none were specified, let // the default behavior take effect. if (this->flags_ != 0) { // Clear all flags this->log_msg_->clr_flags (ACE_Log_Msg::STDERR | ACE_Log_Msg::LOGGER | ACE_Log_Msg::OSTREAM | ACE_Log_Msg::VERBOSE | ACE_Log_Msg::VERBOSE_LITE | ACE_Log_Msg::SILENT | ACE_Log_Msg::SYSLOG); // Check if OSTREAM bit is set if (ACE_BIT_ENABLED (this->flags_, ACE_Log_Msg::OSTREAM)) { int delete_ostream = 0; #if defined (ACE_LACKS_IOSTREAM_TOTALLY) FILE *output_file = this->log_msg_->msg_ostream (); if (wipeout_logfile_) { // close and re-open a stream if such exits if (output_file && ACE_OS::fclose (output_file) == -1) return -1; output_file = ACE_OS::fopen (this->filename_, ACE_TEXT ("wt")); } // open a stream only if such doesn't exists else if (output_file == 0) output_file = ACE_OS::fopen (this->filename_, ACE_TEXT ("at")); if (output_file == 0) return -1; #else ostream *output_file = this->log_msg_->msg_ostream (); // Create a new ofstream to direct output to the file. if (wipeout_logfile_) { ACE_NEW_RETURN (output_file, ofstream (ACE_TEXT_ALWAYS_CHAR (this->filename_)), -1); delete_ostream = 1; } else if (output_file == 0) { ACE_NEW_RETURN (output_file, ofstream (ACE_TEXT_ALWAYS_CHAR (this->filename_), ios::app | ios::out), -1); delete_ostream = 1; } if (output_file->rdstate () != ios::goodbit) { if (delete_ostream) delete output_file; return -1; } #endif /* ACE_LACKS_IOSTREAM_TOTALLY */ // Set the that'll be used by the rest of the // code. this->log_msg_->msg_ostream (output_file, delete_ostream); // Setup a timeout handler to perform the maximum file size // check (if required). if (this->interval_ > 0 && this->max_size_ > 0) { if (this->reactor () == 0) // Use singleton. this->reactor (ACE_Reactor::instance ()); } } // Now set the flags for Log_Msg this->log_msg_->set_flags (this->flags_); } return this->log_msg_->open (this->program_name_, this->log_msg_->flags (), this->logger_key_); } int ACE_Logging_Strategy::handle_timeout (const ACE_Time_Value &, const void *) { #if defined (ACE_LACKS_IOSTREAM_TOTALLY) if ((size_t) ACE_OS::ftell (this->log_msg_->msg_ostream ()) > this->max_size_) #else if ((size_t) this->log_msg_->msg_ostream ()->tellp () > this->max_size_) #endif /* ACE_LACKS_IOSTREAM_TOTALLY */ { // Lock out any other logging. if (this->log_msg_->acquire ()) ACELIB_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("Cannot acquire lock!\n")), -1); // Close the current ostream. #if defined (ACE_LACKS_IOSTREAM_TOTALLY) FILE *output_file = (FILE *) this->log_msg_->msg_ostream (); ACE_OS::fclose (output_file); // We'll call msg_ostream() modifier later. #else ofstream *output_file = (ofstream *) this->log_msg_->msg_ostream (); output_file->close (); #endif /* ACE_LACKS_IOSTREAM_TOTALLY */ // Save current logfile to logfile.old analyze if it was set any // fixed number for the log_files. if (fixed_number_) { if (max_file_number_ < 1) //we only want one file { // Just unlink the file. ACE_OS::unlink (this->filename_); // Open a new log file with the same name. #if defined (ACE_LACKS_IOSTREAM_TOTALLY) output_file = ACE_OS::fopen (this->filename_, ACE_TEXT ("wt")); if (output_file == 0) return -1; this->log_msg_->msg_ostream (output_file); #else output_file->open (ACE_TEXT_ALWAYS_CHAR (this->filename_), ios::out); #endif /* ACE_LACKS_IOSTREAM_TOTALLY */ // Release the lock previously acquired. this->log_msg_->release (); return 0; } } count_++; // Set the number of digits of the log_files labels. int digits = 1, res = count_; while((res = (res / 10))>0) digits++; if (ACE_OS::strlen (this->filename_) + digits <= MAXPATHLEN) { ACE_TCHAR backup[MAXPATHLEN+1]; // analyse if it was chosen the mode which will order the // log_files if (order_files_) { ACE_TCHAR to_backup[MAXPATHLEN+1]; // reorder the logs starting at the oldest (the biggest // number) watch if we reached max_file_number_. int max_num; if (fixed_number_ && count_ > max_file_number_) // count_ will always be bigger than max_file_number_, // so do nothing so to always reorder files from // max_file_number_. max_num = max_file_number_; else max_num = count_; for (int i = max_num ; i > 1 ;i--) { ACE_OS::snprintf (backup, MAXPATHLEN + 1, ACE_TEXT ("%s.%d"), this->filename_, i); ACE_OS::snprintf (to_backup, MAXPATHLEN + 1, ACE_TEXT ("%s.%d"), this->filename_, i - 1); // Remove any existing old file; ignore error as // file may not exist. ACE_OS::unlink (backup); // Rename the current log file to the name of the // backup log file. ACE_OS::rename (to_backup, backup); } ACE_OS::snprintf (backup, MAXPATHLEN + 1, ACE_TEXT ("%s.1"), this->filename_); } else { if (fixed_number_ && count_>max_file_number_) count_ = 1; // start over from 1 ACE_OS::snprintf (backup, MAXPATHLEN + 1, ACE_TEXT ("%s.%d"), this->filename_, count_); } // Remove any existing old file; ignore error as file may // not exist. ACE_OS::unlink (backup); // Rename the current log file to the name of the backup log // file. ACE_OS::rename (this->filename_, backup); } else ACELIB_ERROR ((LM_ERROR, ACE_TEXT ("Backup file name too long; ") ACE_TEXT ("backup logfile not saved.\n"))); // Open a new log file by the same name #if defined (ACE_LACKS_IOSTREAM_TOTALLY) output_file = ACE_OS::fopen (this->filename_, ACE_TEXT ("wt")); if (output_file == 0) return -1; this->log_msg_->msg_ostream (output_file); #else output_file->open (ACE_TEXT_ALWAYS_CHAR (this->filename_), ios::out); #endif /* ACE_LACKS_IOSTREAM_TOTALLY */ // Release the lock previously acquired. this->log_msg_->release (); } return 0; } int ACE_Logging_Strategy::handle_close (ACE_HANDLE, ACE_Reactor_Mask) { // This will reset reactor member and cancel timer events. this->reactor (0); return 0; } void ACE_Logging_Strategy::reactor (ACE_Reactor *r) { if (this->reactor () != r) { if (this->reactor () && this->interval_ > 0 && this->max_size_ > 0) { this->reactor ()->cancel_timer (this); } ACE_Service_Object::reactor (r); if (this->reactor ()) { this->reactor ()->schedule_timer (this, 0, ACE_Time_Value (this->interval_), ACE_Time_Value (this->interval_)); } } } ACE_Reactor * ACE_Logging_Strategy::reactor () const { return ACE_Service_Object::reactor (); } void ACE_Logging_Strategy::log_msg (ACE_Log_Msg *log_msg) { this->log_msg_ = log_msg; } // The following is a "Factory" used by the ACE_Service_Config and // svc.conf file to dynamically initialize the state of the // Logging_Strategy. ACE_STATIC_SVC_DEFINE (ACE_Logging_Strategy, ACE_TEXT ("Logging_Strategy"), ACE_Service_Type::SERVICE_OBJECT, &ACE_SVC_NAME (ACE_Logging_Strategy), ACE_Service_Type::DELETE_THIS | ACE_Service_Type::DELETE_OBJ, 0) ACE_FACTORY_DEFINE (ACE, ACE_Logging_Strategy) ACE_END_VERSIONED_NAMESPACE_DECL // _get_dll_unload_policy() prevents ACE from being unloaded and having its // framework components run down if/when the Logging Strategy is unloaded. extern "C" ACE_Export int _get_dll_unload_policy() { return ACE_DLL_UNLOAD_POLICY_LAZY; }