int CDevWatchdog::Open( const void* devName )
{
	if ( ! devName )
		devName=DEV_WATCHDOG ;

	m_nDevFd = open((const char*)devName, O_RDWR ) ;
	if ( -1 == m_nDevFd )
	{
		PERR( "Unable to open device file[%s]", (const char*)devName ) ;
		return false ;
	}
	struct watchdog_info ident ;
	ioctl(m_nDevFd, WDIOC_GETSUPPORT, &ident);

	if ( ! (ident.options & (WDIOF_KEEPALIVEPING|WDIOF_SETTIMEOUT) )
	   )
	{
		ERR( "features missing: KEEPALIVEPING and SETTIMEOUT");
		systemf_to( 20, "log2flash 'WTD: ERR: features missing: KEEPALIVEPING and SETTIMEOUT'&");
		close(m_nDevFd);
		m_nDevFd = -1 ;
		return false ;
	}
	ioctl(m_nDevFd, WDIOC_GETTIMEOUT, &m_lPingInterval);

	LOG("Found [%s] with %lu seconds timeout", ident.identity, m_lPingInterval);
	systemf_to( 20,"log2flash 'WTD: Found [%s] with %lu seconds timeout'&", ident.identity, m_lPingInterval);
	Ping() ;
	return true ;
}
int CWatchdogMngr::LoadPidList()
{
	CIniParser oIniParser;

	if ( !oIniParser.Load(m_pPidListFile) )
	{
		throw CWatchdog::exception::exception("Unable to load pidListFile") ;
	}

	LOG("Loaded pidListFile [%s]", m_pPidListFile);

	char*  currentPidList[WTD_PIDLIST_ENTRIES]={0,};
	size_t currentPidListLen=0;
	char   pidFile[256];
	for ( unsigned pos=0
		; oIniParser.GetVar("WTD", "watch", pidFile, sizeof(pidFile), pos)
		  && currentPidListLen < WTD_PIDLIST_ENTRIES
		;  ++pos )
	{
		void*key=pidFile;
		void *el=lfind( &key,currentPidList,&currentPidListLen,sizeof(currentPidList[0]),qsortcmp ) ;
		if ( NULL == el )
		{
			currentPidList[currentPidListLen] = strdup(pidFile);
			LOG( WTD"fw.cfg:[%s]", currentPidList[currentPidListLen] );
			++currentPidListLen ;
		}
	}
	qsort( currentPidList, currentPidListLen, sizeof(currentPidList[0]), qsortcmp );

	/// Check if any pidFile from m_ppPidList is missing from currentPidList.
	for (   unsigned j=0; j < m_nPidListLength && m_ppPidList[j]; ++j )
	{
		void *el=bsearch( &m_ppPidList[j], currentPidList, currentPidListLen, sizeof(currentPidList[0]), qsortcmp) ;
		if ( NULL == el )
		{
			LOG( WTD "STOP watching pid[%s]", m_ppPidList[j]);
			systemf_to( 20, "log2flash 'WTD: STOP watching pid[%s]'&", m_ppPidList[j]);
		}
	}
	/// Free the old list to prepare the copy of the new one.
	clearPidList() ;

	m_nPidListLength=currentPidListLen ;
	m_ppPidList[m_nPidListLength] = 0;

	LOG( WTD"WATCH:%d modules", m_nPidListLength );
	if ( !m_nPidListLength )
	{
		return true ;
	}
	memmove(m_ppPidList, currentPidList, WTD_PIDLIST_ENTRIES*sizeof(currentPidList[0]) );
	for ( unsigned j = 0; j< m_nPidListLength ; j++)
	{
		LOG( WTD "WATCH:[%s]", m_ppPidList[j]);
	}
	return true ;
}
int CWatchdogMngr::addFileWatch(const char* pidListFile)
{
	if ( -1 == access(pidListFile, R_OK) && m_status&CFG_ENABLED )
	{
		PERR( WTD "Disabling WTD: addFileWatch->access");
		systemf_to( 20, "log2flash 'WTD: Disabling WTD: addFileWatch(%s) access->[%s]' &", pidListFile, strerror(errno) );
		m_status&=~CFG_ENABLED ;
		return false ;
	}

	m_wd = inotify_add_watch( m_fd, pidListFile, IN_MODIFY) ;
	if (m_wd < 0)
	{
		PERR( WTD "inotify_add_watch");
		systemf_to( 20, "log2flash 'WTD: inotify_add_watch(%s) failed [%s]' &", pidListFile, strerror(errno) );
		throw CWatchdog::exception::exception("Unable to add notify watch") ;
	}
	return true ;
}
int CWatchdogMngr::PidMissing()
{
	char szBlockedModules[256]={0,} ;
	if ( checkDelPidFiles((const char**)m_ppPidList,szBlockedModules) )
	{
		return false ;
	}
	ERR("Pids missing:[%s]",szBlockedModules);
	systemf_to( 20, "log2flash 'WTD: ERR:Pids missing:[%s]. Force REBOOT.'&",szBlockedModules) ;
	return true ;
}
//////////////////////////////////////////////////////////////////////////////
/// This closes and properly disables the watchdog
//////////////////////////////////////////////////////////////////////////////
int CDevWatchdog::Close()
{
	LOG("Stop Dev watchdog.");
	systemf_to( 20, "log2flash 'WTD: Stop Dev watchdog.'&");
	if ( m_nDevFd <= 0 ) return m_nDevFd ;

	int rv = write( m_nDevFd, "V", 1);
	if ( rv != 1 )
	{
		static int p1; if (!p1) { printf("WTD: FAIL:Unable to write stop char to /dev/watchdog[%s]", strerror(errno));p1=1; }
		FWARN("FAIL:Unable to write stop char to /dev/watchdog[%s]", strerror(errno));
		systemf_to( 20, "log2flash 'WTD: FAIL:Unable to write stop char to /dev/watchdog[%s]'&", strerror(errno));
	}
	rv = close(m_nDevFd);
	if ( rv != 0 )
	{
		systemf_to( 20, "log2flash 'WTD: FAIL:Unable to close /dev/watchdog[%s]'&", strerror(errno));
	}
	m_nDevFd = -1 ;
	return rv ;
}
void CWatchdogMngr::OnQuit()
{
	CSimpleTimer t ;

	Ping(); //to make sure that prepare_for_reboot.sh has time to run
	systemf_to( ON_QUIT_DELAY, NIVIS_FIRMWARE "prepare_for_reboot.sh&"  );
	LOG("Waiting[%u seconds] for prepare_for_reboot.sh",ON_QUIT_DELAY) ;

	int nTimeLeftToPing = ON_QUIT_DELAY;

	if (FileIsExecutable(FTP_SCRIPT))
	{
		nTimeLeftToPing = ON_QUIT_DELAY_FTP_LOGS;
	}

	t.SetTimer( nTimeLeftToPing) ;
	while( ! t.IsSignaling() )
	{
		Ping() ;
		Sleep() ;
	}
	Ping() ;
	systemf_to( 20, "log2flash 'WTD: Finished running quit procedure.'&");
}
void CWatchdogMngr::Ping()
{
#define _USEC_IN_SEC 1000000 /* Microseconds in a second */
	struct timeval now;
	gettimeofday(&now, (struct timezone *)NULL);

	int usecDiff = (now.tv_usec + now.tv_sec*_USEC_IN_SEC) - (m_nLastPingTime.tv_usec + m_nLastPingTime.tv_sec*_USEC_IN_SEC);
	usecDiff -= m_nTimeout*_USEC_IN_SEC ;
	if ( usecDiff > 600000 /* we alow a 600msec drift*/ )
	{
		LOG("I was %d uSeconds late on ping.", usecDiff );
		systemf_to( 20, "log2flash 'WTD: I was %d uSeconds late on ping.' &", usecDiff);
	}
	m_nLastPingTime = now;

	if ( m_nCurrentWtd < __MAX_WATCHDOGS )
		m_wdg[m_nCurrentWtd]->Ping() ;

	for ( uint8_t i=0; i< m_nInsertPos && m_nCurrentWtd==CWatchdog::WTD_ALL; ++i )
		m_wdg[i]->Ping() ;

#undef _USEC_IN_SEC
}
//////////////////////////////////////////////////////////////////////////////
/// @brief removes all the pidfiles specified, but not too frequently
/// @author	Mihai Buha ([email protected])
/// @param[in]	p_pszNames null-terminated array of filenames
/// @param[out]	p_szMissNames if not null, fill with names of
///			missing files. Take care to allocate enough memory for
///			"Watchdog: <all filenames in p_pszNames> " or else bad
///			things will happen.
/// @retval true  All pidfiles existed or timeout not expired
/// @retval false Some pidfile was missing (controlling app was dead -
///			did not create a file during latest 2 intervals)
//////////////////////////////////////////////////////////////////////////////
bool CWatchdogMngr::checkDelPidFiles (const char** p_pszNames, char* p_szMissNames)
{
	clock_t timestamp ;
	static clock_t sStartTime = GetClockTicks();
	static clock_t last_checked;
	static bool last_existed = true;
	bool status = true;
	bool exists = true;

	timestamp = GetClockTicks();
	if( timestamp < last_checked)
	{ // large uptime overflowed the clock_t
		last_checked = timestamp;
		sStartTime = timestamp;
	}
	if( (timestamp - last_checked < WTD_PID_VRFY_INTERVAL * sysconf(_SC_CLK_TCK)) 
		|| (timestamp - sStartTime < WTD_PID_VRFY_INTERVAL * sysconf(_SC_CLK_TCK))
		)
	{
		return true;
	}

	last_checked = timestamp;
	for( unsigned i=0; p_pszNames[i]; ++i)
	{
		int nFileLen = GetFileLen(p_pszNames[i]);

		if (nFileLen == 0)
		{	
			usleep(30*1000);//wait a little maybe in process of writing the pid file
			nFileLen = GetFileLen(p_pszNames[i]);
		}

		if ( nFileLen > 0)
		{	unlink( p_pszNames[i]);
			continue;
		}
		if (nFileLen == 0)
		{	
			ERR("checkDelPidFiles: pidfile[%s] len==0",  p_pszNames[i]);
			systemf_to( 20 ,"log2flash 'WTD: ERR:checkDelPidFiles: pidfile[%s] len==0' &",  p_pszNames[i]);
			unlink( p_pszNames[i]);			
		}

		LOG( "ERR:Missing [%s]", p_pszNames[i]);

		if ( exists )
		{
			exists = false;
		}

		if( p_szMissNames )
		{
			strcat( p_szMissNames, p_pszNames[i]);
			strcat( p_szMissNames, ",");
		}
	}
	// Take snapshot if any of the pidfiles is missing.
	if (! exists)
	{
		system_to( 60, NIVIS_TMP"take_system_snapshot.sh "ACTIVITY_DATA_PATH"snapshot_warning.txt &");
	}

	status = exists || last_existed;
	last_existed = exists;
	return status;
}
Esempio n. 9
0
static bool log2flash_fa(const char *fname, const char *fmt, va_list arglist)
{
  bool retcode=false;                // assume operation failed.
  int fd;
  time_t cur_time;
  time_t duration=0;
  struct tm *ptm;                    // structure to obtain date information
  char printbuf[MAX_WRITE_CHAR+2];   // size + '\n' + '\0'
  int bytes_to_write;
  int lock_to;                       // time out for flock()

  DPRINT( "log2flash_fa() called\n" );
  fd = open(fname, O_RDWR|O_CREAT|O_NONBLOCK, 00644);
  
  if (fd == -1) {
    LOG_ERR("log2flash ERROR: Unable to open file.");
    goto EXIT;
  }

  lock_to = FLOCK_TIMEOUT;
  while( flock(fd, LOCK_EX | LOCK_NB)  != 0 ) {
    sleep(1);
    lock_to--;
    if (lock_to < 0) {
      LOG_ERR("log2flash ERROR: lock timeout");
      goto CLOSE_EXIT;
    }
  }

  if ( lseek(fd, 0, SEEK_END) == -1 ) {
    LOG_ERR("log2flash ERROR: unable to seek to the end of file. errno=%d", errno);
    goto CLOSE_EXIT;
  }

  cur_time=time(NULL);
  ptm=gmtime(&cur_time);
  
  // tm_year from 1900, tm_mon [0-11]
  // it takes 20 characters spaces.
  sprintf(printbuf, "%d-%02d-%02d %02d:%02d:%02d ", 
	  ptm->tm_year+1900, ptm->tm_mon+1, ptm->tm_mday,
	  ptm->tm_hour, ptm->tm_min, ptm->tm_sec);

  // generate the buffer string.
  vsnprintf(printbuf+20, MAX_WRITE_CHAR-20, fmt, arglist);

  bytes_to_write = strlen(printbuf);
  printbuf[bytes_to_write] = '\n';
  printbuf[++bytes_to_write] = 0;
  DPRINT( printbuf );

  // gather statistic

  struct stat f_stat;
  if ( fstat(fd, &f_stat) == -1 ) {
    LOG_ERR("log2flash ERROR: unable to gatter statistic for %s. errno=%d", fname, errno);
    goto CLOSE_EXIT;
  }

  // if write failed, goto CLOSE_EXIT
  if (loop_write(fd, printbuf, bytes_to_write) != true) goto CLOSE_EXIT;

  if ( f_stat.st_size + strlen(printbuf) > LOG_LIMIT) {    // starting to rotate
	DPRINT( "File Size exceeded LOG_LIMIT - Perform rotation\n" );
	char from[PATH_MAX];
	char to[PATH_MAX];
	for( int i=ROTATE_MAX; i>0; --i)
	{
		sprintf( from, "%s.%d", fname, i-1);
		sprintf( to, "%s.%d", fname, i);
		rename( from, to);
	}
	duration = time(NULL);
	Copy( fname, from, LOG_LIMIT );
	unlink( fname );
	duration -= time(NULL);

	if (FileIsExecutable(FTP_SCRIPT))
	{
		char sBaseFile[PATH_MAX];
		char sFileName[PATH_MAX];

		sprintf(sBaseFile,NIVIS_TMP"activity.log");

		AttachDatetime(sBaseFile,sFileName);

		Copy(from,sFileName);
		systemf_to(5, FTP_SCRIPT" %s &", sFileName);
	}


  }
  retcode=true;

 CLOSE_EXIT:
  flock(fd, LOCK_UN);
  close(fd);
  if (duration < -10) { //it really is negative :) we only convert it when we need to show it, below
	log2flash("Logfile rotation took quite long: %d seconds", -duration);
  }

 EXIT:
  return retcode;
}