commit
b2abdaeb75
8 changed files with 323 additions and 3 deletions
@ -0,0 +1,260 @@ |
||||
/*
|
||||
* Compilation: |
||||
* gcc -Wall -O3 hypervisor.c -o hypervisor |
||||
* |
||||
* */ |
||||
|
||||
#include <stdio.h> |
||||
#include <string.h> |
||||
#include <unistd.h> |
||||
#include <stdlib.h> |
||||
|
||||
#ifdef __linux__ |
||||
#include <wait.h> |
||||
#else |
||||
#include <sys/wait.h> |
||||
#endif |
||||
|
||||
#include <errno.h> |
||||
#include <time.h> |
||||
#include <stdio.h> |
||||
#include <stdarg.h> |
||||
#include <fcntl.h> |
||||
#include <getopt.h> |
||||
|
||||
|
||||
#define MAXOPT 256 |
||||
#define INTERVAL 5 |
||||
#define MAXINTERVAL 180 |
||||
|
||||
#define USAGE() do{ \ |
||||
fprintf(stderr, "Usage : %s [--daemon] --exec=\"command arg1 arg2 arg3 ...\"\n", argv[0]); \
|
||||
}while(0) |
||||
|
||||
static char *cmd, *cmdopt[MAXOPT + 1]; |
||||
static int daemonize; |
||||
|
||||
static int parseopt(int argc, char *argv[]); |
||||
static int set_nonblock(int fd); |
||||
static int getstatus(char *buf, int size, int status); |
||||
|
||||
static int parseopt(int argc, char *argv[]) |
||||
{ |
||||
int ch, i; |
||||
char *token, *tmpptr, *cmdstr; |
||||
|
||||
cmdstr = cmd = NULL; |
||||
daemonize = 0; |
||||
for(i = 0; i < MAXOPT + 1; i++){ |
||||
cmdopt[i] = NULL; |
||||
} |
||||
|
||||
struct option long_options[] = { |
||||
{"daemon",optional_argument,NULL,'d'}, |
||||
{"exec",required_argument,NULL,'e'}, |
||||
{0,0,0,0}, |
||||
}; |
||||
|
||||
while((ch=getopt_long(argc, argv, "dec:", long_options, NULL)) != -1) { |
||||
switch(ch) |
||||
{ |
||||
case 'e': |
||||
if((cmdstr = strdup(optarg)) == NULL ) |
||||
return -1; |
||||
break; |
||||
case 'd': |
||||
daemonize = 1; |
||||
break; |
||||
default: |
||||
USAGE(); |
||||
return -1; |
||||
} |
||||
} |
||||
|
||||
if(cmdstr == NULL){ |
||||
USAGE(); |
||||
return -1; |
||||
} |
||||
|
||||
for(i = 0;i < MAXOPT + 1;cmdstr = NULL, i++){ |
||||
token = strtok_r(cmdstr, " \t\n", &tmpptr); |
||||
if(token == NULL){ |
||||
break; |
||||
} else { |
||||
cmdopt[i] = strdup(token); |
||||
|
||||
if(i == 0){ |
||||
cmd = strdup(token); |
||||
} |
||||
} |
||||
} |
||||
|
||||
if( (cmd == NULL) || (strlen(cmd) == 0) ){ |
||||
fprintf(stderr, "Error, cmd should not be empty.\n"); |
||||
return -1; |
||||
} |
||||
|
||||
if(i == MAXOPT + 1){ |
||||
fprintf(stderr, "Argument too long\n"); |
||||
return -1; |
||||
} |
||||
|
||||
cmdopt[i] = NULL; |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
static int set_nonblock(int fd) |
||||
{ |
||||
int flags = fcntl(fd, F_GETFL, 0); |
||||
if (flags == -1) { |
||||
return -1; |
||||
} |
||||
return fcntl(fd, F_SETFL, flags | O_NONBLOCK); |
||||
} |
||||
|
||||
static int getstatus(char *buf, int size, int status) |
||||
{ |
||||
int n, len; |
||||
|
||||
len = size; |
||||
|
||||
if(WIFEXITED(status)){ |
||||
n = snprintf(buf, len, "- normal termination, exit status = %d\n", WEXITSTATUS(status)); |
||||
} else if(WIFSIGNALED(status)) { |
||||
n = snprintf(buf, len, "- abnormal termination, signal number = %d%s",
|
||||
WTERMSIG(status),
|
||||
#ifdef WCOREDUMP |
||||
WCOREDUMP(status) ? "-> core file generated" : ""); |
||||
#else |
||||
""); |
||||
#endif |
||||
} else if(WIFSTOPPED(status)) { |
||||
n = snprintf(buf, len, "child stopped, signal number = %d\n", WSTOPSIG(status)); |
||||
} |
||||
|
||||
return n; |
||||
} |
||||
|
||||
|
||||
|
||||
void go_daemon() { |
||||
int fd; |
||||
|
||||
if (fork() != 0) exit(0); /* parent exits */ |
||||
setsid(); /* create a new session */ |
||||
|
||||
/* Every output goes to /dev/null. If Redis is daemonized but
|
||||
* * the 'logfile' is set to 'stdout' in the configuration file |
||||
* * it will not log at all. */ |
||||
if ((fd = open("/tmp/mongo4bls.output", O_RDWR, 0)) != -1) { |
||||
dup2(fd, STDIN_FILENO); |
||||
dup2(fd, STDOUT_FILENO); |
||||
dup2(fd, STDERR_FILENO);
|
||||
if (fd > STDERR_FILENO) close(fd); |
||||
}
|
||||
} |
||||
|
||||
|
||||
int main(int argc, char *argv[]) |
||||
{ |
||||
int ssec = INTERVAL, ret, status; |
||||
int first_start = 1; |
||||
int pipefd[2], waited, alive, isdaemon; |
||||
char buf[1024], info[4096]; |
||||
pid_t pid; |
||||
time_t now, last = time(NULL); |
||||
|
||||
if((ret = parseopt(argc, argv)) < 0 ) |
||||
exit(ret); |
||||
|
||||
daemonize ? go_daemon() : 0; |
||||
|
||||
while(1){ |
||||
if(pipe(pipefd) < 0){ |
||||
fprintf(stderr, "- make pipe error : %s\n", strerror(errno)); |
||||
exit(-1); |
||||
} |
||||
|
||||
if( (ret = set_nonblock(pipefd[0])) < 0 ){ |
||||
fprintf(stderr, "- set read nonblock error : %s\n", strerror(errno)); |
||||
exit(-1); |
||||
} |
||||
|
||||
if((pid = fork()) < 0){ |
||||
fprintf(stderr, "- call fork() error : %s\n", strerror(errno)); |
||||
exit(-1); |
||||
} else if (pid > 0){ |
||||
close(pipefd[1]); |
||||
alive = waited = 1; |
||||
isdaemon = 0; |
||||
while(alive){ |
||||
if(waited){ |
||||
if(pid != waitpid(pid, &status, 0)){ |
||||
sleep(INTERVAL); |
||||
continue; |
||||
} else { |
||||
fprintf(stderr, "- child process[%d] terminated .\n",pid); |
||||
if (first_start && (time(NULL)-last)<=5) { |
||||
fprintf(stderr,"- child process killed in %ld seconds , may wrong ! exit !\n",(time(NULL)-last)); |
||||
exit(-1); |
||||
} else |
||||
first_start = 0; |
||||
waited = 0; |
||||
} |
||||
} |
||||
|
||||
ret = read(pipefd[0], buf, sizeof(buf)); |
||||
if(ret < 0){ |
||||
if(errno == EAGAIN){ |
||||
if(isdaemon == 0){ |
||||
fprintf(stderr, "- this daemon process has no output !.\n"); |
||||
isdaemon = 1; |
||||
} |
||||
sleep(INTERVAL); |
||||
continue; |
||||
} else { |
||||
fprintf(stderr, "- read pipe error : %s\n", strerror(errno)); |
||||
exit(-1); |
||||
} |
||||
} else if(ret == 0) { |
||||
alive = 0; |
||||
close(pipefd[0]); |
||||
fprintf(stderr, "- read zero from pipe of children.\n"); |
||||
if(isdaemon == 0){ |
||||
getstatus(info, sizeof(info), status); |
||||
fprintf(stderr, "- extra info: %s\n", info); |
||||
} else { |
||||
strcpy(info, ""); |
||||
} |
||||
continue; |
||||
} else { |
||||
fprintf(stderr, " - read pipe return: %d bytes\n", ret); |
||||
exit(-1); |
||||
} |
||||
} |
||||
|
||||
fprintf(stderr, "- process: \"%s\" exit, restart it\n", cmd); |
||||
|
||||
sleep(ssec); |
||||
|
||||
now = time(NULL); |
||||
if(now - last > 3600){ |
||||
ssec = INTERVAL; |
||||
last = now; |
||||
} else { |
||||
ssec = (ssec << 1) < MAXINTERVAL ? (ssec << 1) : MAXINTERVAL; |
||||
} |
||||
} else { |
||||
close(pipefd[0]); |
||||
fprintf(stderr, "- execute: \"%s\"\n", cmd); |
||||
if(execvp(cmd, cmdopt) < 0){ |
||||
fprintf(stderr, "- execute: \"%s\" error, %s\n", cmd, strerror(errno)); |
||||
exit(-1); |
||||
} |
||||
|
||||
} |
||||
} |
||||
|
||||
return 0; |
||||
} |
@ -0,0 +1,19 @@ |
||||
#!/usr/bin/env bash |
||||
|
||||
catalog=$(dirname "$0") |
||||
|
||||
cd "${catalog}" || exit 1 |
||||
|
||||
if [ $# != 2 ] ; then |
||||
echo "USAGE: $0 [conf] [mode]" |
||||
exit 0 |
||||
fi |
||||
|
||||
name="redis-shake" |
||||
|
||||
if [ "Darwin" == "$(uname -s)" ];then |
||||
printf "\\nWARNING !!! MacOs doesn't supply to use this script, please use \"./%s -conf=config_file_name\" manual command to run\\n" "$name" |
||||
exit 1 |
||||
fi |
||||
|
||||
./hypervisor --daemon --exec="./$name -conf=$1 -type=$2 1>>$name.output 2>&1" 1>>hypervisor.output 2>&1 |
@ -0,0 +1,13 @@ |
||||
#!/usr/bin/env bash |
||||
#kill -9 "$(cat "$1")" |
||||
if [ $# != 1 ] ; then |
||||
echo "USAGE: $0 [pid filename which by default is 'redis-shake.pid']" |
||||
exit 0 |
||||
fi |
||||
ppid=$(ps -ef | awk '{if ($2=='`cat $1`') print $3}') |
||||
[ -z $ppid ] && echo "[Fail] No process number for $(cat "$1")." && exit 1 |
||||
if [ $ppid -eq 1 ];then |
||||
kill -9 "$(cat "$1")" |
||||
else |
||||
kill -9 "$ppid" "$(cat "$1")" |
||||
fi |
Loading…
Reference in new issue