/****************************************************************************
 *  Copyright(c) 2013 DTS INSIGHT CORPORATION

 Function: System Macro Trace Device Driver : Software Model

 Note:

 Modification history
 +-------------- Historical number (000 to 999)
 |    +--------- Modified System Version
 |    |     +--- Classification of New, Modify, Append, Delete
 v    v     v
 No  Ver  Class Date            Description
 ---+-----+----+----------+--------------------------------------------------
 000 01.00 New  2013/03/22  New
 001 02.12 Mod  2015/02/16  #13699
 004 07.02 Mod  2021/01/08  SMTNEW-637(kring mode)
*****************************************************************************/

/* Include specification ****************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/statvfs.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <unistd.h>
#include <signal.h>
#include <errno.h>
#include <pthread.h>
#include <string.h>
#include <linux/types.h>
#include "smtconfig.h"
#include <limits.h>

/* Constant definition ******************************************************/
#define SMT_DAT_DEVICE		"/proc/driver/smtdat"
#define SMT_SW_DEVICE			"/proc/smtsw"

#define SMT_BUF_SIZE		0x40000	/* _SMT_UNSIGNED_32BIT_INTEGER(32bit) size count */
								/* 4Kbyte(=PAGE_SIZE) */

#define	_SMT_OK			0
#define	_SMT_NG			-1

#define _SMT_STAT_IDLE		0
#define _SMT_STAT_LOGGING	1
#define _SMT_STAT_LOGERR	2
#define _SMT_STAT_LOGWAIT	3
#define _SMT_STAT_LOGSTOP	4

#define _SMT_THREAD_ON	1
#define _SMT_THREAD_OFF	0

#define SMT_MAX_PATH_SIZE 1024

#define SMT_THREAD_WORK_CYCLE 10 //per second

#define SMT_FILENAME_SLOG "%s/smt%s.slog"
#define SMT_FILENAME_CLOG "%s/smt%010ld.clog"
#define SMT_FILENAME_IIDX "%s/smt.iidx"

#define SMT_IIDXFILE_DATA "smt%010ld.clog\n"

#define SMT_FILENAME_RING0 "ring0"
#define SMT_FILENAME_RING1 "ring1"
#define SMT_FILENAME_KRING  "kring"
/* Internal variables *******************************************************/
static int smt_dat_fd = -1;
static int smt_sw_fd  = -1;
static int smtLogFileDescriptor = -1;
static int smtIndexFileDescriptor = -1;

static int thred_status = _SMT_THREAD_OFF;
static int smt_open_stat = 0;
static int disable_status_flag = 0;

static int switchFileSwitchStatus = 0;//0 is output log file.1is output log2 file
void *buffer;
int smt_log_stat = _SMT_STAT_IDLE;
pthread_cond_t cond;
pthread_mutex_t mutex;

off_t endtime_pos = 0;

static int buffer_size = 0;
static _SMT_UNSIGNED_32BIT_INTEGER currentSMTLogByteSize = 0;

static _SMT_UNSIGNED_32BIT_INTEGER fileNumber = 0;
static int SMTDaemonMode = 0;
#define ONE_TIME_MODE 0
#define FILE_RING_MODE 1
#define CONTINUOUS_MODE 2
#define FILE_KRING_MODE 3
/*Option related variables*/
static int trace_time = 0;
static char  *output_directory = SMT_LOG_FILE_OUTPUT_DIRECTORY;
static _SMT_UNSIGNED_32BIT_INTEGER max_output_file_size = SMT_OUTPUT_MAX_FILE_SIZE;
/* Function prototypes ******************************************************/
float GetStorageCapacity(const char* dir);
int SMTLogFileOpen(const char* fullPathFileName);
int SMTLogFileClose(void);
int SMTIndexFileOpen(const char* fullPathFileName);
int SMTIndexFileClose(void);
int _SMT_Datdev_Open(void);
int _SMT_Datdev_Close(void);
void SMT_disable(void);
int analyze_head_info (void  * data,unsigned int size);
int _SMT_Logging(void);
void *smt_log_thread(void *param);
int main(int argc,char *argv[]);
int LogPostscript(const char* fileName, const int dst_fd);
int SlogCat();
int mkdir_path(const char *filepath, mode_t mode);
int stat_mkdir(const char *filepath, mode_t mode);
int WriteTimeString(const char *str);

float GetStorageCapacity(const char* dir)
{
	struct statvfs buf;
	statvfs(dir, &buf);
	float available = (float)buf.f_frsize*buf.f_bavail;
	return available;
}

/*********************************************
**	logfile open/close function impliment   **
*********************************************/
int SMTLogFileOpen(const char* fullPathFileName) {
	if (max_output_file_size >= GetStorageCapacity(output_directory)) {
		printf("[SMTD] You do not have the capacity to save\n");
		return (_SMT_NG);
	}
	smtLogFileDescriptor = open(fullPathFileName, O_CREAT | O_WRONLY | O_TRUNC,0666);

	if (smtLogFileDescriptor < 0) {
		printf("[SMTD] %s file open error %d ! \n",fullPathFileName,smtLogFileDescriptor);
		return( _SMT_NG );
	}
	printf("[SMTD] file output name is %s \n",fullPathFileName);
	return( _SMT_OK );
}

int SMTLogFileClose(void) {
	int ret = _SMT_OK;
	if( smtLogFileDescriptor < 0 ){
		return( _SMT_OK );
	}

	if (SMTDaemonMode == CONTINUOUS_MODE) {
		if (smtIndexFileDescriptor != -1) {
			char  fileName[SMT_MAX_PATH_SIZE];
			sprintf(fileName, SMT_IIDXFILE_DATA, fileNumber);
			ret = write(smtIndexFileDescriptor, fileName, strlen(fileName));
		}
	}

	//ret = syncfs(smtLogFileDescriptor);
	sync();
	//if(ret != 0) {
	//	printf("[SMTD] file sync error ! \n");
	//}
	ret = close(smtLogFileDescriptor);
	if(ret != 0) {
		printf("[SMTD] file close error ! \n");
		return (_SMT_NG);
	}
	smtLogFileDescriptor = -1;

	return( _SMT_OK );
}

int SMTIndexFileOpen(const char* fullPathFileName) {
	smtIndexFileDescriptor = open(fullPathFileName, O_CREAT | O_WRONLY | O_TRUNC,0666);

	if (smtIndexFileDescriptor < 0) {
		printf("[SMTD] %s file open error %d ! \n",fullPathFileName,smtIndexFileDescriptor);
		return( _SMT_NG );
	}
	printf("[SMTD] file output name is %s \n",fullPathFileName);

	WriteTimeString("start");
	endtime_pos = lseek(smtIndexFileDescriptor, 0, SEEK_CUR);
	WriteTimeString("end");
	char* split = "split_size=32768\n";
	int ret = write(smtIndexFileDescriptor, split, strlen(split));

	return( _SMT_OK );
}

int SMTIndexFileClose(void) {
	int ret = _SMT_OK;
	if( smtIndexFileDescriptor < 0 ){
		return( _SMT_OK );
	}
	lseek(smtIndexFileDescriptor, endtime_pos, SEEK_SET);
	WriteTimeString("end");
	ret = close(smtIndexFileDescriptor);
	if(ret != 0) {
		printf("[SMTD] file close error ! \n");
		return (_SMT_NG);
	}
	smtIndexFileDescriptor = -1;

	return( _SMT_OK );
}

/*
**********************
** trace off function
**********************
*/
void SMT_disable(void) {

	int ret = 0;
	char off_val[3]="0\n";

	if (disable_status_flag == 1) {
		return;
	}
	disable_status_flag = 1;
	smt_sw_fd = open(SMT_SW_DEVICE,O_RDWR,S_IRUSR | S_IWUSR);
	if (smt_sw_fd  < 0) {
		printf("[SMTD] /proc/smtsw open error!! \n" );
		return;
	}

	ret = write(smt_sw_fd,off_val,sizeof(off_val));
	if( ret < 0 ){
		printf("[SMTD] /proc/smtsw write error!! \n" );
	}

	close(smt_sw_fd);

	return;
}

/*****************************************************************************
* /proc/driver/smtdat Open
*****************************************************************************/
int _SMT_Datdev_Open( void ) {
	/* data device */
	if(smt_dat_fd>=0){
		return( _SMT_NG );
	}
	smt_dat_fd = open(SMT_DAT_DEVICE,O_RDWR,S_IRUSR | S_IWUSR);
	if (smt_dat_fd < 0) {
		printf("[SMTD] %s open error ! \n",SMT_DAT_DEVICE);
		return( _SMT_NG );
	}
	return( _SMT_OK );
}


/*****************************************************************************
* /proc/driver/smtdat close
*****************************************************************************/
int _SMT_Datdev_Close( void ) {
	if( smt_dat_fd<0 ){
		return( _SMT_OK );
	}
	close(smt_dat_fd);
	return( _SMT_OK );
}

#define GET_API_SIZE(x) ((0x0FE00000 & x) >>21)
#define RECORD_API_HEADER_OFFSET  3
#define API_HEADER_ATR_POSITION  28
int getAPIDataSize(_SMT_UNSIGNED_32BIT_INTEGER APIHeadData) {
		unsigned int APIAttribute = 0;
		int APIDataSize = 0;
		APIAttribute = (APIHeadData& 0xF0000000) >> API_HEADER_ATR_POSITION;
		switch (APIAttribute) {
			case 0x0:
			case 0x6:
			case 0xD:
			case 0xF:
				APIDataSize = 1;
				break;
			case 0x2:
			case 0x3:
			case 0x4:
			case 0x5:
			case 0x7:
			case 0x8:
			case 0x9:
			case 0xA:
			case 0xB:
			case 0xC:
				APIDataSize = GET_API_SIZE(APIHeadData) + 1;
				break;
			case 0xE:
				APIDataSize = 2;
		}
		return APIDataSize;
}

/*****************************************************************************
* logging
*****************************************************************************/
int getWriteSize(void* data, int len)
{
	_SMT_UNSIGNED_32BIT_INTEGER *smtData  = (_SMT_UNSIGNED_32BIT_INTEGER *)data;
	int pos = 0;
	int size = 0;
	while (1)
	{
		pos += RECORD_API_HEADER_OFFSET;
		pos += getAPIDataSize(smtData[pos]);
		if (pos > (len / sizeof(_SMT_UNSIGNED_32BIT_INTEGER))) {
			return (size * sizeof(_SMT_UNSIGNED_32BIT_INTEGER));
		}
		size = pos;
	}
}
int dataShift(void* sta, void* end, int size)
{
	char* s = (char*)sta;
	char* e = (char*)end;
	int i;
	for (i = 0; i < size; i++)
	{
		*s = *e;
		s++;
		e++;
	}
}

int _SMT_Log_Start( void )
{
	int ret;
	char outputLogFileName[SMT_MAX_PATH_SIZE];
	char outputIndexFileName[SMT_MAX_PATH_SIZE];
	buffer_size = 0;
	currentSMTLogByteSize = 0;
	disable_status_flag = 0;
	switchFileSwitchStatus = 0;
	smt_log_stat =_SMT_STAT_LOGGING;
	smt_open_stat = _SMT_OK;

	if (SMTDaemonMode == CONTINUOUS_MODE) {
		fileNumber = 0;
		sprintf(outputLogFileName, SMT_FILENAME_CLOG, output_directory, fileNumber);
	} else if (SMTDaemonMode == FILE_RING_MODE) {
		sprintf(outputLogFileName, SMT_FILENAME_SLOG, output_directory, SMT_FILENAME_RING0);
	} else if (SMTDaemonMode == FILE_KRING_MODE) {
		sprintf(outputLogFileName, SMT_FILENAME_SLOG, output_directory, SMT_FILENAME_KRING);
	} else {
		//default ONE_TIME_MODE
		sprintf(outputLogFileName, SMT_FILENAME_SLOG, output_directory, "");
	}
	ret = SMTLogFileOpen(outputLogFileName);
	if (ret == _SMT_NG) {
		printf("[SMTD] SMT_LOG_OPEN error \n");
		smt_open_stat = _SMT_NG;
		smt_log_stat =_SMT_STAT_LOGERR;
	}

	if (smt_open_stat == _SMT_OK) {
		if (SMTDaemonMode == CONTINUOUS_MODE) {
			sprintf(outputIndexFileName, SMT_FILENAME_IIDX, output_directory);
			ret = SMTIndexFileOpen(outputIndexFileName);
			if (ret == _SMT_NG) {
				printf("[SMTD] SMT_INDEX_OPEN error \n");
				smt_open_stat = _SMT_NG;
				smt_log_stat =_SMT_STAT_LOGERR;
			}
		}
	}

	return ret;
}

int _SMT_Logging( void ) {
	int ret;
	int size = 0;
	int writeSize = 0;
	char  fileName[SMT_MAX_PATH_SIZE];
	while (1)
	{
		void* end = buffer+buffer_size;
		size = read(smt_dat_fd, end, sizeof(_SMT_UNSIGNED_32BIT_INTEGER)*SMT_BUF_SIZE);
		if (size < 0) {
			printf("[SMTD] /proc/smt/smtdat read error! \n");
			ret =  _SMT_NG;
    		break;
		}
		
		if (size == 0) {
			ret =  _SMT_OK;
			break;
		}

		lseek(smt_dat_fd, 0, SEEK_SET);
		
		buffer_size += size;
		
		writeSize = getWriteSize(buffer, buffer_size);

		//current total output size check and switch file.
		if ((max_output_file_size - currentSMTLogByteSize) <= writeSize) {
			printf("[SMTD] file limit reached switch output logfile  \n");
			if (SMTDaemonMode == FILE_RING_MODE) {
				SMTLogFileClose();
				if (switchFileSwitchStatus == 0) {
					switchFileSwitchStatus = 1;
					sprintf(fileName, SMT_FILENAME_SLOG, output_directory, SMT_FILENAME_RING1);
				}
				else {
					switchFileSwitchStatus = 0;
					sprintf(fileName, SMT_FILENAME_SLOG, output_directory, SMT_FILENAME_RING0);
				}
				ret = SMTLogFileOpen(fileName);
				currentSMTLogByteSize = 0;
				if (ret == _SMT_NG) {
					break;
				}

			} else if(SMTDaemonMode == CONTINUOUS_MODE){
				SMTLogFileClose();//current smtx.slog close
				fileNumber++;
				sprintf(fileName, SMT_FILENAME_CLOG, output_directory, fileNumber);
				ret = SMTLogFileOpen(fileName);//Nes smtx.slog open
				currentSMTLogByteSize = 0;
				if (ret == _SMT_NG) {
					break;
				}

			} else {
				//one time mode
				//kring mode
				writeSize = getWriteSize(buffer, max_output_file_size - currentSMTLogByteSize);
				if (0 <= writeSize) {
					ret = write(smtLogFileDescriptor, buffer, writeSize);
				}
			 	//printf("[SMTD] file limit reached  \n");
			 	lseek(smt_dat_fd, 0, SEEK_SET);
				currentSMTLogByteSize = 0;
				ret = _SMT_NG;
			 	break;
			}
		}
		currentSMTLogByteSize += writeSize;
		
		ret = write(smtLogFileDescriptor, buffer, writeSize);
		if (ret < 0) {
			printf("[SMTD] file write error ! \n");
			ret =  _SMT_NG;
			break;
		}
		
		buffer_size = buffer_size - writeSize;
		dataShift(buffer, (buffer+writeSize), buffer_size);
		
		//printf("size = %d, writeSize = %d, buffer_size = %d\n", size, writeSize, buffer_size);
	}
	return( ret );
}

/*****************************************************************************
* Logging Thread.
*****************************************************************************/
void *smt_log_thread(void *param)
{
	int pid;
	pthread_t thread_id;
	int ret;

	thred_status = _SMT_THREAD_ON;
	pthread_cond_wait(&cond, &mutex);

	while(1){
		sleep(SMT_THREAD_WORK_CYCLE);
		if (smt_log_stat == _SMT_STAT_LOGERR) {
			SMT_disable();
			break;
		}

		if (SMTDaemonMode != FILE_KRING_MODE){
			ret = _SMT_Logging();
			if( ret == _SMT_NG ){
				SMT_disable();
				break;
			}
		}
		
		if(	smt_log_stat == _SMT_STAT_LOGSTOP ) {
			ret = _SMT_Logging();
			if( ret == _SMT_NG ){
				SMT_disable();
				break;
			}
			break;
		}
	}

	thred_status = _SMT_THREAD_OFF;

	pthread_exit(0);

}

void alarm_handler(int signal)
{

	alarm(0);
	SMT_disable();
}

/*****************************************************************************
* Main
*****************************************************************************/
/*
Signal from kernel.
	SIGUSR1		log start (by kernel side)
	SIGUSR2		smt disable::: echo off > /proc/smtsw
*/
int main(int argc,char *argv[]) {
	int ret;
	sigset_t ss;
	int signo;
	int pid;
	int main_loop = 1;
	char *e;
  	static int current_status=0;
 	pthread_t thread;
 	int i = 0;
 	int ch;
 	extern char	*optarg;
 	extern int	optind, opterr;
	int base = 10;
	int bootmode = -1;
	int procinfo[2];
	int tmpmode = ONE_TIME_MODE;
	output_directory= SMT_LOG_FILE_OUTPUT_DIRECTORY;
 	//option check
 	SMTDaemonMode = ONE_TIME_MODE;
	while ((ch = getopt(argc, argv, "hs:d:t:m:")) != -1) {
		switch(ch) {
			case 'd':
				if(optarg != NULL)
					output_directory = optarg;
				break;
			case 'm':
				if (strcmp(optarg,"continuous") == 0) {
					printf("[SMTD] Continuous Mode.\n");
					SMTDaemonMode = CONTINUOUS_MODE;
				} else if (strcmp(optarg,"ring") == 0) {
					printf("[SMTD] Ring Mode.\n");
					SMTDaemonMode = FILE_RING_MODE;
				} else if (strcmp(optarg,"kring") == 0) {
					printf("[SMTD] kring Mode.\n");
					SMTDaemonMode = FILE_KRING_MODE;
				} else {
					printf("[SMTD] One time Mode.\n");
					SMTDaemonMode = ONE_TIME_MODE;
				}
				break;

			case 't':
				trace_time = atoi(optarg);
				if (optarg <= 0) {
					trace_time = 0;
				}
				break;
			case 'h':
				printf("smtex(daemon for outputting SMT log file)\n");
				printf("Usage: smtex[Options]\n");
				printf("Options:\n");
				printf(" -d <DIRECTORY>\n");
				printf(" -t <TIME(seconds)>\n");
				printf(" -s <FILE SIZE>\n");
				printf(" -m <MODE>\n");
				printf(" -h help\n");
				printf("\n");
				printf("MODE:\n");
				printf("   continuous :Data from starting the trace to end is collected.\n");
				printf("   ring       :The latest SMT_OUTPUT_MAX_FILE_SIZE|<FILE SIZE> data from starting the trace to end is collected.\n");
				printf("   onetime    :Data specified by SMT_OUTPUT_MAX_FILE_SIZE|<FILE SIZE> from starting the trace is collected.(default)\n");
				printf("   kring      :The latest data until the end trigger occurs is collected for SMT_BUF_SIZE.\n");
				return 0;
				break;
			case 's' :
				if (SMTDaemonMode == FILE_KRING_MODE){
					printf("In kring mode, the s option has no effect.\n");
					printf("The size is defined by SMT_BUF_SIZE in kernel land.\n");
					return 0;
				}
				if (strlen(optarg) >= 2) {
					if (optarg[0] == '0' && (optarg[1] == 'x' || optarg[1] == 'X')) {
						base = 16;
					}
				}
				max_output_file_size = strtoul(optarg,&e,base);
				if (max_output_file_size  < 0x100000) {
					max_output_file_size = 0x100000;
				}
				if (max_output_file_size > 0xFFFFFFFF) {
					max_output_file_size = 0xFFFFFFFF;
				}
				printf("[SMTD] output file size : %lubyte\n", max_output_file_size);
			default:
				break;
		}
	}

	if (strlen(output_directory) > 1004) {
		printf("[SMTD] The path can be up to 1004characters\n");
		goto fin;
	}
	if (mkdir_path(output_directory, 0777) == _SMT_NG) {
		printf("[SMTD] Failed to create directory\n");
		goto fin;
	}

	printf("[SMTD] Logging daemon start ! \n");

	// Open data device.
	ret = _SMT_Datdev_Open();
	if( ret != 0 ){
		return ret;
	}
	
	// Set up buffer
	buffer = (int *)calloc( SMT_BUF_SIZE+(69*2), sizeof(int) );
	if( buffer == NULL ){
		printf("[SMTD] calloc error \n" );
		goto fin;
	}

	// Log thread.
	pthread_mutex_init(&mutex, NULL);
	pthread_cond_init(&cond, NULL);

	// Setup signal
	sigemptyset(&ss);
	signal(SIGALRM,alarm_handler);
	sigaddset(&ss, SIGUSR1);
	sigaddset(&ss, SIGUSR2);
	ret = pthread_sigmask(SIG_BLOCK, &ss, NULL);
	if (ret != 0){
		printf("[SMTD]pthread_sigmask failed \n");
	}
	if( pthread_create(&thread , NULL , smt_log_thread , NULL) !=0) {
		printf("[SMTD] pthread create error \n" );
	}
startpoint:
	// Get driver's status
	smt_sw_fd = open(SMT_SW_DEVICE,O_RDWR,S_IRUSR | S_IWUSR);
	if (smt_sw_fd < 0) {
		printf("[SMTD] smtsw open error\n");
	} else {
		read(smt_sw_fd, &bootmode, sizeof(int));
		close(smt_sw_fd);
	}

	// Get pid & Notify for Kernel
	pid = (int)getpid();

	procinfo[0] = pid;
	procinfo[1] = SMTDaemonMode;

	ret = write( smt_dat_fd, procinfo, sizeof(procinfo) );
	if( ret < 0 ){
		printf("[SMTD] pid write error \n" );
		goto fin;
	}

	smt_log_stat = _SMT_STAT_IDLE;
	if ((0 < bootmode) && (0 < trace_time)) {
		alarm(trace_time);
	}
	/* main loop */
	current_status= 0;
	while( main_loop ) {
		if( sigwait( &ss, &signo ) == 0){
			switch( signo ) {
				case SIGUSR1:
					bootmode = 0;
					ret = _SMT_Log_Start();
					if( pthread_create(&thread , NULL , smt_log_thread , NULL) !=0)
						printf("[SMTD] pthread create error \n" );
					pthread_cond_signal(&cond);
					if (0 < trace_time) {
						alarm(trace_time);
					}
					break;
				case SIGUSR2:
					//printf("[SMTD] SIGUSR2 signal recept %d \n",signo );
					alarm(0);
					disable_status_flag = 1;
					if (0 < bootmode) {
						tmpmode = SMTDaemonMode;
						SMTDaemonMode = FILE_KRING_MODE;
						ret = _SMT_Log_Start();
						if( pthread_create(&thread , NULL , smt_log_thread , NULL) !=0)
							printf("[SMTD] pthread create error \n" );
						pthread_cond_signal(&cond);
					}
					smt_log_stat = _SMT_STAT_LOGSTOP;
					while (1) {
						if (thred_status ==_SMT_THREAD_OFF ) {
							break;
						}
						sleep(1);
					}

					main_loop = 0;
					break;
				default:
					//printf("[SMTD] ??? signal recept %d \n",signo );
					break;
			}

		}
	}
	main_loop = 1;
	alarm(0);
	ret = SMTLogFileClose();
	if (ret == _SMT_NG) {
		printf("[SMTD] SMT log file close error\n");
	}
	if (smt_open_stat == _SMT_OK) {
		printf("[SMTD]SMT data output Finished!! \n ");
	} else {
		printf("[SMTD]SMT data output Failed \n ");
	}

	if (SMTDaemonMode == CONTINUOUS_MODE) {
		ret = SMTIndexFileClose();
		if (ret == _SMT_NG) {
			printf("[SMTD]SMT index file close error\n");
		}
	}
	if (SMTDaemonMode == FILE_RING_MODE) {
		SlogCat();
	}

	if (0 < bootmode) {
		SMTDaemonMode = tmpmode;
	}

	goto startpoint;

fin:
	pthread_join(thread , NULL);
	ret = SMTLogFileClose();
	if (ret == _SMT_NG) {
		printf("[SMTD] SMT log file close error\n");
	}

	if (SMTDaemonMode == CONTINUOUS_MODE) {
		ret = SMTIndexFileClose();
		if (ret == _SMT_NG) {
			printf("[SMTD]SMT index file close error\n");
		}
	}
	if (SMTDaemonMode == FILE_RING_MODE) {
		SlogCat();
	}

	free(buffer);
	_SMT_Datdev_Close();
	printf("[SMTD] Logging daemon end ! \n");
	sleep(1);
	exit(0);
}

int LogPostscript(const char* fileName, const int dst_fd) {
	int ret = _SMT_OK;

	int fd = open(fileName, O_RDONLY, 0666);
	if (fd < 0) {
		printf("[SMTD] file open error%s\n", fileName);
		return _SMT_NG;
	}

	const int buf_size = 0x1000;
	char buf[buf_size];
	int size = 0;
	while (1) {
		size = read(fd, buf, buf_size);
		if (size <= 0) {
			break;
		}
		if (write(dst_fd, buf, size) < 0) {
			printf("[SMTD] ring mode write error %s\n", fileName);
			ret = _SMT_NG;
		}
	}

	close(fd);

	if (remove(fileName) == -1) {
		printf("[SMTD] file delete error %s\n", fileName);
		ret = _SMT_NG;
	}

	return ret;
}

int SlogCat() {
	int ret = _SMT_OK;
	char fileName[SMT_MAX_PATH_SIZE];
	sprintf(fileName, SMT_FILENAME_SLOG, output_directory, "");
	int fd = open(fileName, O_CREAT | O_WRONLY | O_TRUNC,0666);
	if (fd < 0) {
		printf("[SMTD] file ring mode output error\n");
		return (_SMT_NG);
	}

	if (switchFileSwitchStatus == 0) {
		sprintf(fileName, SMT_FILENAME_SLOG, output_directory, SMT_FILENAME_RING1);
		LogPostscript(fileName, fd);
		sprintf(fileName, SMT_FILENAME_SLOG, output_directory, SMT_FILENAME_RING0);
		LogPostscript(fileName, fd);
	}
	else {
		sprintf(fileName, SMT_FILENAME_SLOG, output_directory, SMT_FILENAME_RING0);
		LogPostscript(fileName, fd);
		sprintf(fileName, SMT_FILENAME_SLOG, output_directory, SMT_FILENAME_RING1);
		LogPostscript(fileName, fd);
	}

	close(fd);

	return ret;
}

int mkdir_path(const char *filepath, mode_t mode) {
	char *p = NULL;
	char *buf = NULL;
	int rc = 0;

	buf = (char *)malloc(strlen(filepath) + 4);
	if (buf == NULL) {
		return _SMT_NG;
	}
	sprintf(buf, "%s/", filepath);

	for (p = strchr(buf+1, '/'); p; p = strchr(p+1, '/')) {
		*p = '\0';
		rc = stat_mkdir(buf, mode);
		if (rc == _SMT_NG) {
			free(buf);
			return _SMT_NG;
		}
		*p = '/';
	}

	free(buf);
	return _SMT_OK;
}

int stat_mkdir(const char *filepath, mode_t mode) {
	struct stat sb = {0};
	int rc = 0;

	rc = stat(filepath, &sb);
	if (rc == 0) {
		if (!S_ISDIR(sb.st_mode)) {
			return _SMT_NG;
		}
		return _SMT_OK;
	}

	rc = mkdir(filepath, mode);
	if (rc < 0) {
		printf("[SMTD] mkdir(%d) %s: %s\n", errno, strerror(errno), filepath);
		return _SMT_NG;
	}
	return _SMT_OK;
}

int WriteTimeString(const char *str) {
	char time_str[64];

	time_t timer = time(NULL);
	struct tm *local = localtime(&timer);

	sprintf(time_str, "%s: %4d/%2d/%2d %2d:%2d:%2d\n"
					, str
					, local->tm_year + 1900
					, local->tm_mon + 1
					, local->tm_mday
					, local->tm_hour
					, local->tm_min
					, local->tm_sec);

	int ret = write(smtIndexFileDescriptor, time_str, strlen(time_str));
	if (ret < 0) {
		return _SMT_NG;
	}
	return _SMT_OK;
}
