bool Log::makeNewLogFile ( ) {
	// prevent deadlock. don't log since we are in the middle of logging.
	// otherwise, safebuf, which is used when renaming files, might
	// call logR().
	g_loggingEnabled = false;

	// . rename old log file like log000 to log000-2013_11_04-18:19:32
	// . returns false on error
	bool status = renameCurrentLogFile();

	// re-enable logging since nothing below should call logR() indirectly
	g_loggingEnabled = true;

	if ( ! status ) return false;

	// close old fd
	if ( m_fd >= 0 ) ::close ( m_fd );
	// invalidate
	m_fd = -1;
	// reset
	m_logFileSize = 0;
	// open it for appending.
	// create with -rw-rw-r-- permissions if it's not there.
	m_fd = open ( m_filename , 
		      O_APPEND | O_CREAT | O_RDWR ,
		      getFileCreationFlags() );
	if ( m_fd >= 0 ) return true;
	// bitch to stderr and return false on error
	fprintf(stderr,"could not open new log file %s for appending\n",
		m_filename);
	return false;
}
bool Log::init ( const char *filename ) {
	// init these
	m_fd        = -1;
	m_disabled  = false;

	// is there a filename to log our errors to?
	m_filename = filename;
	if ( ! m_filename ) return true;

	//
	// RENAME log000 to log000-20131104-181932
	//
	if ( g_conf.m_logToFile ) {
		// returns false on error
		if ( ! renameCurrentLogFile() ) return false;
	}

	// get size of current file. getFileSize() is defined in File.h.
	m_logFileSize = getFileSize ( m_filename );

	if ( strcmp(m_filename,"/dev/stderr") == 0 ) {
		m_fd = STDERR_FILENO; // 2; // stderr
		return true;
	}

	// open it for appending.
	// create with -rw-rw-r-- permissions if it's not there.
	m_fd = open ( m_filename , 
		      O_APPEND | O_CREAT | O_RDWR ,
		      getFileCreationFlags() );
	if ( m_fd >= 0 ) return true;
	// bitch to stderr and return false on error
	fprintf(stderr,"could not open log file %s for appending\n",
		m_filename);
	return false;
}
void handleRequest ( UdpSlot *slot , int32_t netnice ) {
	char *p = slot->m_readBuf;

	int32_t numBytes = *(int32_t*)p;
	p += sizeof(int32_t);


	char *filename = g_hostdb.m_logFilename;

	// running just ./gb will log to stderr...
	if ( strcmp(filename ,"/dev/stderr") == 0 ) {
		g_errno = EBADFILE;
		log(LOG_ERROR,"%s:%s:%d: call sendErrorReply.", __FILE__, __func__, __LINE__);
		g_udpServer.sendErrorReply ( slot, g_errno ); 
		return;
	}

	int32_t fd = open ( filename , O_RDONLY ,
			    getFileCreationFlags() );
			 // S_IRUSR |S_IWUSR |S_IRGRP |S_IWGRP| S_IROTH );
	if ( ! fd ) {
		log(LOG_DEBUG, "logviewer: Failed to open %s for reading: ",
		    filename);
		g_errno = EBADFILE;
		log(LOG_ERROR,"%s:%s:%d: call sendErrorReply.", __FILE__, __func__, __LINE__);
		g_udpServer.sendErrorReply ( slot, g_errno ); 
		return;
	}

	char stackSpace[LOG_WINDOW];
	char *buf = stackSpace;
	char *allocBuf = NULL;
	int32_t allocBufSize = 0;

	if(numBytes > LOG_WINDOW) {
		buf = (char*)mmalloc(numBytes, "Msg1fA");
		if(!buf) {
			log(LOG_INFO, 
			    "admin: malloc of %" PRId32" bytes failed "
			    "for logview,"
			    " falling back on stack buffer.",
			    numBytes);
			buf = stackSpace;
			numBytes = LOG_WINDOW;
		}
		else {
			allocBuf     = buf;
			allocBufSize = numBytes;
		}
	}

	lseek(fd, -1 * numBytes, SEEK_END);
	if(errno == EINVAL) {
		//oops! we seeked to before the begining of the file
		//log(LOG_WARN, "bad seek!");
		lseek(fd, 0, SEEK_SET);
	}

	int32_t numRead = read(fd, buf, numBytes-1);
	close(fd);
	if(numRead > 0)	buf[numRead-1] = '\0';
	else          {  
		buf[0] = '\0'; 
		numRead = 0;
		if(allocBuf) mfree(allocBuf,	allocBufSize, "Msg1fA");
		allocBufSize = 0;
		allocBuf = NULL;
		log(LOG_ERROR,"%s:%s:%d: call sendErrorReply.", __FILE__, __func__, __LINE__);
		g_udpServer.sendErrorReply ( slot, EBADFILE ); 
		return;
	}
	//log(LOG_DEBUG, "bytes read! %" PRId32" ", numRead);

	g_udpServer.sendReply_ass (buf, numRead, allocBuf,allocBufSize, slot); //send
}
void Images::thumbStart_r ( bool amThread ) {

	int64_t start = gettimeofdayInMilliseconds();

	//static char  scmd[200] = "%stopnm %s | "
	//                         "pnmscale -xysize 100 100 - | "
	//                         "ppmtojpeg - > %s";

	
	log( LOG_DEBUG, "image: thumbStart_r entered." );

	//DIR  *d;
	//char  cmd[2500];
	//sprintf( cmd, "%strash", g_hostdb.m_dir );

	makeTrashDir();

	// get thread id. pthread_t is 64 bit and pid_t is 32 bit on
	// 64 bit oses
	pthread_t id = pthread_self();

	// pass the input to the program through this file
	// rather than a pipe, since popen() seems broken.
	// m_dir ends in / so this should work.
	char in[364];
	snprintf ( in , 363,"%strash/in.%" PRId64
		   , g_hostdb.m_dir, (int64_t)id );
	unlink ( in );

	log( LOG_DEBUG, "image: thumbStart_r create in file." );

	// collect the output from the filter from this file
	// m_dir ends in / so this should work.
	char out[364];
	snprintf ( out , 363,"%strash/out.%" PRId64
		   , g_hostdb.m_dir, (int64_t)id );
        unlink ( out );

	log( LOG_DEBUG, "image: thumbStart_r create out file." );

        // ignore errno from those unlinks        
        errno = 0;

        // Open/Create temporary file to store image to
        int   fhndl;
        if( (fhndl = open( in, O_RDWR+O_CREAT ,
			   getFileCreationFlags()
			   // //			   S_IWUSR+S_IRUSR 
			   )) < 0 ) {
               log( "image: Could not open file, %s, for writing: %s - %d.",
       		    in, mstrerror( m_errno ), fhndl );
	       m_imgDataSize = 0;
       	       return;
        }

        // Write image data into temporary file
        if( write( fhndl, m_imgData, m_imgDataSize ) < 0 ) {
               log( "image: Could not write to file, %s: %s.",
       		    in, mstrerror( m_errno ) );
       	       close( fhndl );
	       unlink( in );
	       m_imgDataSize = 0;
       	       return;
        }

        // Close temporary image file now that we have finished writing
        if( close( fhndl ) < 0 ) {
               log( "image: Could not close file, %s, for writing: %s.",
       	            in, mstrerror( m_errno ) );
	       unlink( in );
	       m_imgDataSize = 0;
      	       return;
        }
	fhndl = 0;

        // Grab content type from mime
	//int32_t imgType = mime.getContentType();
        char  ext[5];
        switch( m_imgType ) {
               case CT_GIF:
		       strcpy( ext, "gif" );
	               break;
               case CT_JPG:
		       strcpy( ext, "jpeg" );
		       break;
               case CT_PNG:
		       strcpy( ext, "png" );
		       break;
               case CT_TIFF:
		       strcpy( ext, "tiff" );
		       break;
	       case CT_BMP:
		       strcpy( ext, "bmp" );
		       break;
        } 

	// i hope 2500 is big enough!
	char  cmd[2501];

	//sprintf( cmd, scmd, ext, in, out);
	char *wdir = g_hostdb.m_dir;
	// can be /dev/stderr or like /var/gigablast/data/log000 etc.
	const char *logFile = g_log.getFilename();
	// wdir ends in / so this should work.
	snprintf( cmd, 2500 ,
		 "LD_LIBRARY_PATH=%s %s%stopnm %s 2>> %s | "
		 "LD_LIBRARY_PATH=%s %spnmscale -xysize %" PRId32" %" PRId32" - 2>> %s | "
		  // put all its stderr msgs into /dev/null
		  // so "jpegtopnm: WRITING PPM FILE" doesn't clog console
		 "LD_LIBRARY_PATH=%s %sppmtojpeg - > %s 2>> %s"
		  , wdir , wdir , ext , in , logFile
		  , wdir , wdir , m_xysize , m_xysize , logFile
		  , wdir , wdir , out , logFile
		 );

	// if they already have netpbm package installed use that then
	static bool s_checked = false;
	static bool s_hasNetpbm = false;
	if ( ! s_checked ) {
		s_checked = true;
		File f;
		f.set("/usr/bin/pnmscale");
		s_hasNetpbm = f.doesExist() ;
	}
	if ( s_hasNetpbm )
		snprintf( cmd, 2500 ,
			  "%stopnm %s 2>> %s | "
			  "pnmscale -xysize %" PRId32" %" PRId32" - 2>> %s | "
			  "ppmtojpeg - > %s 2>> %s"
			  , ext , in , logFile
			  , m_xysize , m_xysize , logFile
			  , out , logFile
			  );
		
        
        // Call clone function for the shell to execute command
	int err = system( cmd ); // m_thmbconvTimeout );

	//if( (m_dx != 0) && (m_dy != 0) )
	//	unlink( in );
	unlink ( in );

	if ( err == 127 ) {
		m_errno = EBADENGINEER;
		log("image: /bin/sh does not exist.");
		unlink ( out );
		m_stopDownloading = true;
		return;
	}
	// this will happen if you don't upgrade glibc to 2.2.4-32 or above
	if ( err != 0 ) {
		m_errno = EBADENGINEER;
		log("image: Call to system(\"%s\") had error.",cmd);
		unlink ( out );
		m_stopDownloading = true;
		return;
	}

        // Open new file with thumbnail image
        if( (fhndl = open( out, O_RDONLY )) < 0 ) {
               log( "image: Could not open file, %s, for reading: %s.",
		    out, mstrerror( m_errno ) );
		unlink ( out );
		m_stopDownloading = true;
	       return;
        }

	if( (m_thumbnailSize = lseek( fhndl, 0, SEEK_END )) < 0 ) {
		log( "image: Seek of file, %s, returned invalid size: %" PRId32,
		     out, m_thumbnailSize );
		m_stopDownloading = true;
		close(fhndl);
		unlink ( out );
		return;
	}

	if( m_thumbnailSize > m_imgReplyMaxLen ) {
		log(LOG_DEBUG,"image: Image thumbnail larger than buffer!" );
		log(LOG_DEBUG,"image: File Read Bytes: %" PRId32, m_thumbnailSize);
		log(LOG_DEBUG,"image: Buf Max Bytes  : %" PRId32,m_imgReplyMaxLen );
		log(LOG_DEBUG,"image: -----------------------" );
		log(LOG_DEBUG,"image: Diff           : %" PRId32,
		     m_imgReplyMaxLen-m_thumbnailSize );
		close(fhndl);
		unlink ( out );
		return;

	}

	if( lseek( fhndl, 0, SEEK_SET ) < 0 ) {
		log( "image: Seek couldn't rewind file, %s.", out );
		m_stopDownloading = true;
		close(fhndl);
		unlink ( out );
		return;
	}

        // . Read contents back into image ptr
	// . this is somewhat of a hack since it overwrites the original img
        if( (m_thumbnailSize = read( fhndl, m_imgData, m_imgDataSize )) < 0 ) {
                log( "image: Could not read from file, %s: %s.",
 		     out, mstrerror( m_errno ) );
	        close( fhndl );
		m_stopDownloading = true;
		unlink( out );
	        return;
        }

        if( close( fhndl ) < 0 ) {
                log( "image: Could not close file, %s, for reading: %s.",
 		     out, mstrerror( m_errno ) );
		unlink( out );
		m_stopDownloading = true;
		unlink ( out );
 	        return;
        }
	fhndl = 0;
       	unlink( out );
	int64_t stop = gettimeofdayInMilliseconds();
	// tell the loop above not to download anymore, we got one
	m_thumbnailValid = true;

	// MDW: this was m_imgReply
	getImageInfo ( m_imgData , m_thumbnailSize , &m_tdx , &m_tdy , NULL );

	// now make the meta data struct
	// <imageUrl>\0<width><height><thumbnailData>
	


	log( LOG_DEBUG, "image: Thumbnail size: %" PRId32" bytes.", m_imgDataSize );
	log( LOG_DEBUG, "image: Thumbnail dx=%" PRId32" dy=%" PRId32".", m_tdx,m_tdy );
	log( LOG_DEBUG, "image: Thumbnail generated in %" PRId64"ms.", stop-start );
}
// . get the fd of this file
// . if it was closed by us we reopen it
// . may re-open a virtual fd whose real fd was closed
// . if we hit our max # of real fds allowed we'll have to close 
//   the least used of those so we can open this one
// . return -2 if never been opened
// . return -1 on other errors
// . otherwise, return the file descriptor
int File::getfd () {
	// if m_vfd is -1 it's never been opened
	if ( ! m_calledOpen ) { // m_vfd < 0 ) {
		g_errno = EBADENGINEER;
		log(LOG_LOGIC,"disk: getfd: Must call open() first.");
		char *xx=NULL; *xx=0; 
		return -2;
	}

	// if someone closed our fd, why didn't our m_fd get set to -1 ??!?!?!!
	if ( m_fd >= 0 && m_closeCount != s_closeCounts[m_fd] ) {
		log(LOG_DEBUG,"disk: invalidating existing fd %i "
		    "for %s this=0x%"PTRFMT" ccSaved=%i ccNow=%i", 
		    (int)m_fd,getFilename(),(PTRTYPE)this,
		    (int)m_closeCount,
		    (int)s_closeCounts[m_fd]);
		m_fd = -1;
	}

	// . sanity check
	// . no caller should call open/getfd after unlink was queued for thred
	//if ( m_gone ) { char *xx = NULL; *xx = 0; }
	// get the real fd from the virtual fd
	//int fd = s_fds [ m_vfd ];
	// return true if it's already opened
	if ( m_fd >=  0 ) { 
		// debug msg
		if ( g_conf.m_logDebugDisk )
			log(LOG_DEBUG,"disk: returning existing fd %i for %s "
			    "this=0x%"PTRFMT" ccSaved=%i ccNow=%i", 
			    (int)m_fd,getFilename(),(PTRTYPE)this,
			    (int)m_closeCount,
			    (int)s_closeCounts[m_fd]);
		if ( m_fd >= MAX_NUM_FDS ) { char *xx=NULL;*xx=0; }
		// but update the timestamp to reduce chance it closes on us
		//s_timestamps [ m_vfd ] = getTime();
		s_timestamps [ m_fd ] = gettimeofdayInMillisecondsLocal();
		return m_fd;
	}
	// if fd is -2 it's marked as available
	// if ( fd != -1 ) {
	// 	g_errno = EBADENGINEER;
	// 	log (LOG_LOGIC, "disk: getfd: fd is available?!?!" );
	// 	return -2;
	// }
	// . a real fd of -1 means it's been closed and we gotta reopen it
	// . we have to close someone if we don't have enough room
	while ( s_numOpenFiles >= s_maxNumOpenFiles )  {
		if ( g_conf.m_logDebugDisk ) sanityCheck();
		if ( ! closeLeastUsed() ) return -1;
		if ( g_conf.m_logDebugDisk ) sanityCheck();
	}
	// what was the filename/mode of this timed-out fd?
	//char *filename    = s_filenames   [ m_vfd ];
	// time the calls to open just in case they are hurting us
	int64_t t1 = -1LL;
	// . re-open the sleeping file descriptor
	// . if a rename thread was queued or spawned, try old guy first
	//if ( m_oldFilename[0] ) {
	//	t1 = gettimeofdayInMilliseconds();
	//	fd = ::open ( m_oldFilename , m_flags , m_permissions );
	//}
	int fd = -1;
	// then try to open the new name
	if ( fd == -1 ) {
		t1 = gettimeofdayInMilliseconds();
 retry7:
		fd = ::open ( getFilename() , m_flags,getFileCreationFlags());
		// valgrind
		if ( fd == -1 && errno == EINTR ) goto retry7;
		// 0 means stdout, right? why am i seeing it get assigned???
		if ( fd == 0 ) 
			log("disk: Got fd of 0 when opening %s.",
			    getFilename());
		if ( fd == 0 )
		       fd=::open(getFilename(),m_flags,getFileCreationFlags());
		if ( fd == 0 ) 
			log("disk: Got fd of 0 when opening2 %s.",
			    getFilename());
		if ( fd >= MAX_NUM_FDS )
			log("disk: got fd of %i out of bounds 1 of %i",
			    (int)fd,(int)MAX_NUM_FDS);

		// if we got someone else's fd that called close1_r() in a
		// thread but did not have time to call close2() to fix
		// up these member vars, then do it here. close2() will 
		// see that s_filePtrs[fd] does not equal the file ptr any more
		// and it will not update s_numOpenFiles in that case.
		if ( fd >= 0 && s_open [ fd ] ) {
			File *f = s_filePtrs [ fd ];
			if ( g_conf.m_logDebugDisk )
				log("disk: swiping fd %i from %s before "
				    "his close thread returned "
				    "this=0x%"PTRFMT,
				    fd,
				    f->getFilename(),
				    (PTRTYPE)f);
			// he only incs/decs his counters if he owns it so in
			// close2() so dec this global counter here
			s_numOpenFiles--;
			s_open[fd] = 0;
			s_filePtrs[fd] = NULL;
			if ( g_conf.m_logDebugDisk ) sanityCheck();
		}

		// sanity. how can we get an fd already opened?
		// because it was closed in a thread in close1_r()
		if ( fd >= 0 && s_open[fd] ) { char *xx=NULL;*xx=0; }
		// . now inc that count in case there was someone reading on
		//   that fd right before it was closed and we got it
		// . ::close() call can now happen in a thread, so we
		//   need to inc this guy here now, too
		// . so when that read returns it will know to re-do
		// . this should really be named s_openCounts!!
		if ( fd >= 0 ) s_closeCounts [ fd ]++;
		// . we now record this
		// . that way if our fd gets closed in closeLeastUsed() or
		//   in close1_r() due to a rename/unlink then we know it!
		// . this fixes a race condition of closeCounts in Threads.cpp
		//   where we did not know that the fd had been stolen from
		//   us and assigned to another file because our close1_r()
		//   had called ::close() on our fd and our closeCount algo
		//   failed us. see the top of this file for more description
		//   into this bug fix.
		m_closeCount = s_closeCounts[fd];
	}
	if ( t1 >= 0 ) {
		int64_t dt = gettimeofdayInMilliseconds() - t1 ;
		if ( dt > 1 ) log(LOG_INFO,
				  "disk: call to open(%s) blocked for "
				  "%"INT64" ms.",getFilename(),dt);
	}
	// copy errno to g_errno
	if ( fd <= -1 ) {
		g_errno = errno;
		log("disk: error open(%s) : %s fd %i",
		    getFilename(),strerror(g_errno),(int)fd);
		return -1;
	}

	if ( g_conf.m_logDebugDisk ) sanityCheck();

	// we're another open file
	s_numOpenFiles++;

	// debug log
	if ( g_conf.m_logDebugDisk )
		log("disk: opened1 fd %i for %s #openfiles=%i this=0x%"PTRFMT,
		    (int)fd,getFilename(),(int)s_numOpenFiles,(PTRTYPE)this);

	// set this file descriptor, the other stuff remains the same
	//s_fds [ m_vfd ] = fd;
	m_fd = fd;
	// 0 means stdout, right? why am i seeing it get assigned???
	if ( fd == 0 ) 
		log("disk: Found fd of 0 when opening %s.",getFilename());
	// reset
	s_writing   [ fd ] = 0;
	s_unlinking [ fd ] = 0;
	// update the time stamp
	s_timestamps [ fd ] = gettimeofdayInMillisecondsLocal();
	s_open       [ fd ] = true;
	s_filePtrs   [ fd ] = this;

	if ( g_conf.m_logDebugDisk ) sanityCheck();
	// add file to linked list of active files
	//addFileToLinkedList ( this );
	return fd;
}