PracticeDev/study_clang/Mimic/app_migrate_class/migrate_criu.cpp

388 lines
12 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*************************************************************************
> File Name: migrate.cpp
> Author: TianLun Song
> Mail: songtianlun@frytea.com
> Blog: https://blog.frytea.com
> Created Time: Wed 23 Dec 2020 07:10:09 PM CST
************************************************************************/
#include<iostream>
#include<algorithm> /* sort() */
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>
#include<string.h>
#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/socket.h>
class CMigrateApp
{
#define CRIU_BINARY "/usr/sbin/criu"
#define CRIU_DIR "/tmp/criu"
#define IMG_DIR "images"
#define DUMP_LOG_FILE "dump.log"
#define RESTORE_LOG_FILE "restore.log"
#define RESTORE_PID_FILE "restore.pid"
#define INHERIT_FD_OPTION "--inherit-fd"
#define OLD_LOG_FILE "/tmp/criu/oldlog"
#define NEW_LOG_FILE "/tmp/criu/newlog"
public:
// CMigrateApp(int iPid = 0);
CMigrateApp(char *sCMD, int iPid = 0);
~CMigrateApp(){}
char *GetCMD();
char *GetImgDir();
int Checkout();
int Restore();
int GetPid();
int GetUnixNum();
private:
int GetPidByCMD(char * sCMD);
int SetPidByCMD(char * sCMD);
void GetCMDByPid(int iPid, char *sCMD);
int isUnixActivity(unsigned int iNode, char * cPid);
int SetUnixByPid(int iPid);
void Mkdir_safe(char *dirname, int mode);
private:
int i_criu_pid;
int i_unix_num;
char s_criu_cmd[64];
char s_criu_pid[8];
char s_criu_img[64];
char s_criu_dump_log[64];
char s_criu_restore_log[64];
char s_criu_restore_pidfile[64];
char s_external_sk_ino[1024];
char s_inh_unixsk_arg[1024];
const char *s_dump_argv[15] = {
"criu", "dump", "-j",
"-D", s_criu_img, "-o", s_criu_dump_log,
"-v4", "-x", "--lib /root/stl/lib",
"--tcp-established",
s_external_sk_ino,
"-t", s_criu_pid,
NULL };
const char *s_restore_argv[18] = {
"criu", "restore", "-d","-j",
"-D", s_criu_img, "-o", s_criu_restore_log,
"--pidfile", s_criu_restore_pidfile,
"-v4", "-x", "--lib /root/stl/lib",
"--tcp-established",
s_inh_unixsk_arg,
NULL };
};
CMigrateApp::CMigrateApp(char* sCMD, int iPid)
{
char sMkdir[64] = {0};
// init data
memset(s_criu_img, 0x00, sizeof s_criu_img);
memset(s_criu_dump_log, 0x00, sizeof s_criu_dump_log);
memset(s_criu_restore_log, 0x00, sizeof s_criu_restore_log);
memset(s_criu_restore_pidfile, 0x00, sizeof s_criu_restore_pidfile);
memset(s_criu_cmd, 0x00, sizeof s_criu_cmd);
i_criu_pid = 0;
i_unix_num = 0;
memset(s_criu_pid, 0x00, sizeof s_criu_pid);
memset(s_external_sk_ino, 0x00, sizeof s_external_sk_ino);
memset(s_inh_unixsk_arg, 0x00, sizeof s_inh_unixsk_arg);
if( 0 != iPid )
{
GetCMDByPid(iPid, s_criu_cmd);
i_criu_pid = iPid;
snprintf(s_criu_pid, sizeof s_criu_pid, "%d", i_criu_pid);
}
else if( NULL != sCMD )
{
strcpy(s_criu_cmd, sCMD);
SetPidByCMD(s_criu_cmd);
}
else
{
printf("Error of [iPid: %d] or [sCMD: %s] ", iPid, sCMD);
}
snprintf(s_criu_img, sizeof s_criu_img, "%s/%s/%s", CRIU_DIR, s_criu_cmd, IMG_DIR);
snprintf(s_criu_dump_log, sizeof s_criu_dump_log, "%s/%s/%s", CRIU_DIR, s_criu_cmd, DUMP_LOG_FILE);
snprintf(s_criu_restore_log, sizeof s_criu_restore_log, "%s/%s/%s", CRIU_DIR, s_criu_cmd, RESTORE_LOG_FILE);
snprintf(s_criu_restore_pidfile, sizeof s_criu_restore_pidfile, "%s/%s/%s", CRIU_DIR, s_criu_cmd, RESTORE_PID_FILE);
i_unix_num = SetUnixByPid(i_criu_pid);
// printf("PCMD: %s, Unix Sum: %d\n",sCMD, i_unix_num);
sprintf(sMkdir,"mkdir -p %s &", s_criu_img);
system(sMkdir);
printf("App will be to Migrate: [iPid: %d] [CMD: %s] [Unix Num: %d]\n", i_criu_pid, s_criu_cmd, i_unix_num);
}
int CMigrateApp::Checkout()
{
char sCmd[2048] = {0};
char sCpCMd[64] = {0};
if(0 >= i_criu_pid)
{
printf("Error Pid! Dump failed!\n");
return -1;
}
for (int i = 0; s_dump_argv[i] != NULL; i++)
sprintf(sCmd, "%s %s", sCmd, s_dump_argv[i]);
strcat(sCmd,"&");
printf("Dump [CMD:%s] [PID:%d] [Unix Num:%d] cmd: %s\n",s_criu_cmd,i_criu_pid, i_unix_num, sCmd);
system(sCmd);
snprintf(sCpCMd, sizeof sCpCMd, "cp /tmp/1 /tmp/criu/%s/", s_criu_cmd);
system(sCpCMd);
return 0;
}
int CMigrateApp::Restore()
{
char sCmd[2048] = {0};
char sCpCmd[64] = {0};
if(0 >= i_criu_pid)
{
printf("Error Pid! Restore neet to right dump!\n");
return -1;
}
for (int i = 0; s_restore_argv[i] != NULL; i++)
sprintf(sCmd, "%s %s", sCmd, s_restore_argv[i]);
strcat(sCmd,"&");
/* 进程有几个socket就创建几次 */
for (int i = 0; i < i_unix_num; i++)
socket(AF_UNIX, SOCK_STREAM, 0);
/* 将该进程转储时的/tmp/1 复制到指定路径下 */
snprintf(sCpCmd, sizeof sCpCmd, "cp /tmp/criu/%s/1 /tmp/1", s_criu_cmd);
system(sCpCmd);
system("chmod 644 /tmp/1");
/* 恢复 */
printf("Restore [CMD:%s] [Unix Num:%d] cmd: %s\n",s_criu_cmd, i_unix_num, sCmd);
system(sCmd);
return 0;
}
int CMigrateApp::GetPidByCMD(char *sCMD)
{
char cPid[62] = {0};
char sSeekCmd[64] = {0};
FILE *fPid = NULL;
int iPid = -1;
sprintf(sSeekCmd, "pgrep %s | head -1",sCMD);
fPid = popen(sSeekCmd, "r");
if(NULL == fPid)
return -1;
fgets(cPid, sizeof(cPid), fPid);
iPid = atoi(cPid);
// printf("SeekCmd: %s, Pid: %d, cPid: %s\n",sSeekCmd,iPid,cPid);
return iPid;
}
void CMigrateApp::GetCMDByPid(int iPid, char *sCMD)
{
FILE *fcmd = NULL;
char sGetCMD[64] = {0};
snprintf(sGetCMD, sizeof sGetCMD, "grep 'Name' /proc/%d/status | awk '{print $2}'", iPid);
fcmd = popen(sGetCMD, "r");
fgets(sCMD, sizeof(sCMD), fcmd);
}
int CMigrateApp::SetPidByCMD(char *sCMD)
{
char cPid[62] = {0};
char sSeekCmd[64] = {0};
FILE *fPid = NULL;
int iPid = -1;
sprintf(sSeekCmd, "pgrep %s | head -1", sCMD);
fPid = popen(sSeekCmd, "r");
if(NULL == fPid)
return -1;
fgets(cPid, sizeof(cPid), fPid);
iPid = atoi(cPid);
i_criu_pid = atoi(cPid);
snprintf(s_criu_pid, sizeof s_criu_pid, "%d", iPid);
// strcpy(s_criu_pid, cPid);
pclose(fPid);
//printf("SeekCmd: %s, Pid: %d, cPid: %s\n",sSeekCmd,iPid,cPid);
return iPid;
}
int CMigrateApp::SetUnixByPid(int iPid)
{
char sUnixStatCmd[64] = {0};
char sNowCriuUnixCmd[64] = {0};
char sNosRestoreUnixCmd[64] = {0};
FILE *fpUnixStat;
int iFdNum = 3;
char tmp[2048]; //存储每一行输出
unsigned int iNode;
int iSumUnix = 0;
// int i = 0;
if( iPid <=0 )
return 0;
sprintf(sUnixStatCmd, "cat /proc/%d/net/unix | awk '{print $7}'", iPid);
fpUnixStat = popen(sUnixStatCmd, "r");
if (fpUnixStat == NULL) {
return -1;
}
// 跳过第一条无效数据
fgets(tmp, sizeof(tmp) - 1, fpUnixStat);
// i = 0;
// 输出检查状态
// printf("check unix ..");
// fflush(stdout);
while (fgets(tmp, sizeof(tmp) - 1, fpUnixStat)) {
// 输出检查状态
// switch(i++){
// case 1:
// printf(".");
// fflush(stdout);
// break;
// case 5:
// printf("\b");
// fflush(stdout);
// break;
// case 10:
// i=0;
// default:
// break;
// };
sscanf(tmp, "%u", &iNode);
if(!isUnixActivity(iNode,s_criu_cmd))
continue;
if(iNode==0)
continue;
// printf("iPid: %d, Unix iNode: %d, is activity.\n", iPid,iNode);
snprintf(sNowCriuUnixCmd, sizeof(sNowCriuUnixCmd), "--ext-unix-sk=%u ",
(unsigned int)iNode);
snprintf(sNowCriuUnixCmd, sizeof(sNowCriuUnixCmd), "--external unix[%u] ",
(unsigned int)iNode);
snprintf(sNosRestoreUnixCmd, sizeof sNosRestoreUnixCmd, "--inherit-fd fd[%d]:socket:[%u] ",
iFdNum++,(unsigned int)iNode);
strcat(s_external_sk_ino, sNowCriuUnixCmd);
strcat(s_inh_unixsk_arg, sNosRestoreUnixCmd);
iSumUnix++;
}
// printf("\r"); // 清空 check unix 状态字符打印
pclose(fpUnixStat);
return iSumUnix;
}
int CMigrateApp::isUnixActivity(unsigned int iNode, char * cPid)
{
char sCheckUnixCmd[64] = {0};
FILE *fpCheckUnix;
char tmp[2048];
// 检查当前 unix socket 是否处于活跃状态
sprintf(sCheckUnixCmd, "netstat -xap | grep %s | grep %u", cPid, iNode);
fpCheckUnix = popen(sCheckUnixCmd, "r");
if (fpCheckUnix == NULL) {
return -1;
}
memset(tmp, 0x0, sizeof(tmp));
fgets(tmp, sizeof(tmp) - 1, fpCheckUnix);
pclose(fpCheckUnix);
printf("Check Cmd: %s, Rst len: %d", sCheckUnixCmd, (int)strlen(tmp));
fflush(stdout);
printf("%40s\r"," "); // 使用空格清理脏字符并回退光标至行首
fflush(stdout);
if(strlen(tmp)>1)
return 1;
return 0;
}
int CMigrateApp::GetPid()
{
return i_criu_pid;
}
int CMigrateApp::GetUnixNum()
{
return i_unix_num;
}
char *CMigrateApp::GetCMD()
{
return s_criu_cmd;
}
char *CMigrateApp::GetImgDir()
{
return s_criu_img;
}
void CMigrateApp::Mkdir_safe(char *dirname, int mode)
{
if (mkdir(dirname, mode) == -1 && errno != EEXIST)
printf("Success to mkdir dirname=%s mode=0x%x\n", dirname, mode);
else
printf("Fail to make dir %s", dirname);
}
// 自定义对象比较函数根据unix个数排序
bool cmp(CMigrateApp a, CMigrateApp b)
{
return a.GetUnixNum() < b.GetUnixNum();
}
void MigrateMySelf()
{
char sRestoreCmd[128] = {0};
CMigrateApp CMigrateMySelf(NULL, getpid());
snprintf(sRestoreCmd, sizeof sRestoreCmd, "criu restore -D %s -j", CMigrateMySelf.GetImgDir());
printf("Run cmd when restore: %s\n", sRestoreCmd);
CMigrateMySelf.Checkout();
}
int main()
{
char piggie_cmd[21][64] = {
/* create ipc unix socket */
"arpd", "dhcp", "lldpd", "ospfd", "ripd", "snmptrap", "rmon", "ripngd", "mstp", "lag","master","zebra","pidmonitor",
"ntpclient", "snmpd", "udpsvd", "brctl", "l2monitor", "vtysh", "configmanage", "udhcpd"};
std::vector <CMigrateApp> vMigrateApps;
// 清空进程检查点数据文件夹,避免遗留文件影响进程恢复
system("rm -rf /tmp/criu/*");
for(int i = 0; i < 21; i++)
{
CMigrateApp iC(piggie_cmd[i]);
vMigrateApps.push_back(iC);
// printf("%s [PID %d] will be push back, vector size: %d\n", iC.GetCMD(),iC.GetPid(), (int)vMigrateApps.size());
}
printf("-----------------------after sort-----------------------\n");
for(auto v : vMigrateApps)
{
printf("[%s:%d] has %d unix socket\n", v.GetCMD(), v.GetPid(), v.GetUnixNum());
}
// sort(vMigrateApps.begin(), vMigrateApps.end(),cmp);
printf("-------------------------- dump -------------------------\n");
for(auto v : vMigrateApps)
{
v.Checkout();
}
for(int j=10;j>0;j--)
{
printf("Waiting for start restore....%d\n",j);
if(j==5)
MigrateMySelf();
sleep(1);
}
printf("Enter any character to continue\n");
getchar();
printf("------------------------ restore ------------------------\n");
for(auto v : vMigrateApps)
{
if(v.GetPid()<=0)
{
printf("failed to dump, jump %s.\n", v.GetCMD());
continue;
}
v.Restore();
}
return 0;
}