#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <limits.h>
#include <sys/wait.h>
#include <sys/time.h>
#include <vector>
#include <string>
static std::string GetCurrentPath()
{
char buf[PATH_MAX] = {0};
int len = readlink("/proc/self/exe", buf, PATH_MAX);
if(len < 0 || len >= PATH_MAX)
{
fprintf(stderr, "readlink len=%d, error=%s\n", len, strerror(errno));
return "";
}
buf[len] = '\0';
for(int i = len; i >= 0; --i)
{
if (buf[i] == '/')
{
buf[i+1] = '\0';
break;
}
}
return buf;
}
#define MAX_WRITE_INFO 100
static void WriteInfo(const char * szInfo)
{
std::vector<std::string> strMsgs;
{
struct timeval tv;
gettimeofday(&tv, NULL);
struct tm tmtime;
gmtime_r(&tv.tv_sec, &tmtime);
char szTime[64] = {0};
snprintf(szTime, sizeof(szTime)-1, "%4d%02d%02d %02d:%02d:%02d.%06ld", tmtime.tm_year + 1900, tmtime.tm_mon + 1, tmtime.tm_mday, tmtime.tm_hour, tmtime.tm_min, tmtime.tm_sec, tv.tv_usec);
char szMsg[1024] = {0};
snprintf(szMsg, sizeof(szMsg)-1, "%s - %s\n", szTime, szInfo);
strMsgs.emplace_back(szMsg);
FILE * fp = fopen("daemon.log", "r");
if(fp)
{
char szMsg[1024] = {0};
for(size_t i = 0; i < MAX_WRITE_INFO-1 && !feof(fp); ++i)
{
fgets(szMsg, sizeof(szMsg), fp);
strMsgs.emplace_back(szMsg);
}
fclose(fp);
}
}
{
FILE * fp = fopen("daemon.log", "w");
if(!fp)
{
return;
}
for(size_t i = 0; i < strMsgs.size(); ++i)
{
fwrite(strMsgs[i].c_str(), strMsgs[i].size(), sizeof(char), fp);
}
fclose(fp);
}
}
static bool SingleInstance(const char * instance)
{
const char * name = strrchr(instance, '/');
if(!name)
{
name = instance;
}
char path[PATH_MAX] = {0};
snprintf(path, sizeof(path), "%s.%s.lck", GetCurrentPath().c_str(), name);
int fd = open(path, O_CREAT|O_RDWR, 0666);
if(fd < 0)
{
fprintf(stderr, "open=%s, error=%s", path, strerror(errno));
return false;
}
int lock_result = lockf(fd, F_TLOCK, 0);
if(lock_result < 0)
{
return false;
}
return true;
}
static void PrintUsage(char* name)
{
fprintf(stderr,
"\n ----- \n\n"
"Usage:\n"
" %s program_name \n\n"
"Where:\n"
" %s - Name of this Daemon loader.\n"
" program_name - Name (including path) of the program you want to load as daemon.\n\n"
"Example:\n"
" %s ./atprcmgr - Launch program 'atprcmgr' in current directory as daemon. \n\n\n\n",
name, name, name);
}
static pid_t g_child_pid = 0;
static void HandleSignal(int signo)
{
if(signo == SIGTERM)
{
if(g_child_pid != 0)
{
fprintf(stderr, "\nbegin killing child program=%d\n", g_child_pid);
kill(g_child_pid, SIGTERM);
}
else
{
fprintf(stderr, "\nchild program not running\n");
}
exit(0);
}
}
int main(int argc, char* argv[])
{
fprintf(stderr, "\nDaemon loader\n- Launch specified program as daemon.\n");
if(argc < 2)
{
fprintf(stderr, "* Missing parameter : daemon program name not specified!\n");
PrintUsage(argv[0]);
return 0;
}
switch(fork())
{
case 0: break;
case -1:
fprintf(stderr, "\n! Create daemon programm %s error=%s. \n", argv[1], strerror(errno));
return -1;
default: exit(0);
}
if(setsid() < 0)
{
fprintf(stderr, "\n! Create daemon programm %s error=%s. \n", argv[1], strerror(errno));
return -1;
}
if(!SingleInstance(argv[1]))
{
fprintf(stderr, "\nthe program %s was runing already!!!\n\n\n", argv[1]);
return 0;
}
signal(SIGTERM, HandleSignal);
fprintf(stderr, "- Loading %s as daemon, please wait ......\n\n\n", argv[1]);
while(true)
{
pid_t pid = fork();
if(pid == 0)
{
signal(SIGCHLD, SIG_IGN);
WriteInfo("programm running!!!");
if(execv(argv[1], argv+1) != 0 )
{
fprintf(stderr, "\n! Can't Excute The programm %s. \n", argv[1]);
WriteInfo("programm exit!!!");
return -1;
}
fprintf(stderr, "\n! Excute daemon programm %s exit. \n", argv[1]);
WriteInfo("programm exit!!!");
}
else if(pid > 0)
{
g_child_pid = pid;
int status = 0;
wait(&status);
g_child_pid = 0;
fprintf(stderr, "\n! status=%d, Restart daemon programm %s after 10s. \n", status, argv[1]);
sleep(10);
}
else
{
fprintf(stderr, "\n! Create daemon programm %s error=%s. \n", argv[1], strerror(errno));
break;
}
}
return 0;
}