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,¤tPidListLen,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; }
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; }