PracticeDev/study_clang/Mimic/app_migrate_class/migrate_criu.cpp

388 lines
12 KiB
C++
Raw Normal View History

2022-12-20 17:31:11 +08:00
/*************************************************************************
> 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;
}