Qt浅谈之四十六QemuQuestAgent的应用

2023-11-08

一、简介

        qemu-ga是在虚拟机中安装的一个agent,宿主机host通过通道(unix socket)与虚拟机vm内部的agent进行通信,这样宿主机就有了一种从外部控制/获取虚拟机的手段。比如:host可以向vm下发执行修改hostname的指令,或者获取vm内所有进程信息的指令。
        qemu-ga时刻监听这个unix socket,一旦发现有指令发送来,分析该指令,并执行,通过unix socket返回执行结果,传输的是json字符串。

二、详解

1、centos6下使用qemu-ga

(1)虚拟机连接本机及网络,然后在虚拟机中安装qemu-ga(windows是qemu-ga.exe)
yum install qemu-guest-agent
(2)修改安装后的qemu-ga配置文件
#修改/etc/sysconfig/qemu-ga文件
将 
# Enable fsfreeze hook. See the --fsfreeze-hook option in "qemu-ga --help".
FSFREEZE_HOOK_ENABLE=0
改为
# Enable fsfreeze hook. See the --fsfreeze-hook option in "qemu-ga --help".
FSFREEZE_HOOK_ENABLE=1
#修改/etc/sysconfig/qemu-ga,注释掉BLACKLIST_RPC这一行,将所有功能开放
将
BLACKLIST_RPC="guest-file-open,guest-file-close,guest-file-read,guest-file-write,guest-file-seek,guest-file-flush"
改为
#BLACKLIST_RPC="guest-file-open,guest-file-close,guest-file-read,guest-file-write,guest-file-seek,guest-file-flush"
(3)将虚拟机关机,在虚拟机配置文件libvirt.xml中的<devices>下面添加下述配置,并重新启动虚拟机
<channel type='unix'>
   <source mode='bind' path='/var/lib/libvirt/qemu/f16x86_64.agent'/>
   <target type='virtio' name='org.qemu.guest_agent.0'/>
</channel>
(4)测试是否正常
#得到虚拟机对应的domain id
[root@node-12 ~]# virsh list
 Id    名称                         状态
----------------------------------------------------
 90    instance-0000209f              running
 
#使用命令进行测试
[root@node-12 ~]# virsh qemu-agent-command 90 '{"execute":"guest-info"}'
{"return":{"version":"0.12.1","supported_commands":[{"enabled":true,"name":"guest-set-vcpus"},{"enabled":true}...
(5)freeze文件系统的方法
#直接用virsh命令,freeze文件系统
[root@node-12 ~]# virsh qemu-agent-command 90 '{"execute":"guest-fsfreeze-freeze"}'
{"return":1}
 
#freeze后,可以查询当前虚拟机文件系统的状态,表明是frozen
[root@node-12 ~]# virsh qemu-agent-command 90 '{"execute":"guest-fsfreeze-status"}'
{"return":"frozen"}
 
#thaw(解封)文件系统
[root@node-12 ~]# virsh qemu-agent-command 90 '{"execute":"guest-fsfreeze-thaw"}'
{"return":1}
 
#thaw后,文件系统为解封状态
[root@node-12 ~]# virsh qemu-agent-command 90 '{"execute":"guest-fsfreeze-status"}'
{"return":"thawed"}

2、python使用qemu-ga(类实现)

from commands import getstatusoutput
import logger
import os, sys, stat
import json  
import base64  
import crypt  
import string
import random  
import re
import socket

########################Configure############################
FILE_OPEN_READ="""{"execute":"guest-file-open", "arguments":{"path":"%s","mode":"r"}}"""  
FILE_OPEN_WRITE="""{"execute":"guest-file-open", "arguments":{"path":"%s","mode":"%s"}}"""  
FILE_READ="""{"execute":"guest-file-read", "arguments":{"handle":%s,"count":%d}}"""
FILE_WRITE="""{"execute":"guest-file-write", "arguments":{"handle":%s,"buf-b64":"%s"}}"""   
FILE_CLOSE="""{"execute":"guest-file-close", "arguments":{"handle":%s}}""" 
class QemuQuestAgent:
    def __init__(self):
        self.__socketFileName = ""
        self.__totalSize = 0
        self.__currentSize = 0

    def setSocketFile(self, filename):
        self.socketFileName = filename
        if not os.path.exists(self.socketFileName):
            logger.error("%s do not exist!", self.socketFileName)
            return False
        return True
        
    def resetPassWord(self, newPassword):
        passwordFile = "/etc/shadow"
        content = self._QemuQuestAgent__guestFileRead(passwordFile)
        if not content.strip():
            return False 
        content = base64.standard_b64decode(content)
        user_array = re.split("\n",content)  
        for iter,line in enumerate(user_array):  
            info = line.split(":")  
            if info[0] == "root":  
                info[1] = self._QemuQuestAgent__generationPwd(newPassword)  
                user_array[iter] = ":".join(info)  
                break
        content = base64.standard_b64encode("\n".join(user_array))
        write_count = self._QemuQuestAgent__guestFileWrite(passwordFile, content, "w+")
        if write_count > 0:
            logger.info("change password successfully!")
            return True
        else:
            return False
          
    def putFileToVM(self, fileName, vmFilePathName):
        if not os.path.exists(fileName):
            logger.error("%s do not exist" % (fileName))
            return False
        if vmFilePathName[-1] == "/":
            vmFilePathName += fileName.split("/")[-1]
        filestats = os.stat(fileName)
        self.__totalSize = filestats[stat.ST_SIZE]
        if self.__totalSize <= 0:
            logger.error("%s is Empty!" % (fileName))
            return False
        fd = open(fileName, "r")
        self.__currentSize = 0
        total = 0
        while True:
            content = fd.read(4096)
            total += 4096;
            self.__currentSize += len(content)   #<=4096
            content = base64.standard_b64encode(content)      
            write_count = self._QemuQuestAgent__guestFileWrite(vmFilePathName, content, "a+")
            if write_count <= 0:
                fd.close()
                return False
            if total >= self.__totalSize:
                break
        fd.close()
        return True
    
    def processWrite(self):
        return (self.__currentSize, self.__totalSize)
        
    def __getResult(self, command, fileName = ""):
        resultStr = ""
        if fileName.strip():
            self.socketFileName = fileName
        if not os.path.exists(self.socketFileName):
            return None;
       
        sockfd = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
        server_address = self.socketFileName
        try:
            sockfd.connect(server_address)
        except socket.error, msg:
            logger.error("guestagent:%s,%s", socket.error, msg)
            return None
        try:
            sockfd.send(command)
            resultStr = sockfd.recv(10240)
        finally:
            sockfd.close()
        return None if not resultStr else json.loads(resultStr);
    
        
    def __generationPwd(self, pwd):
        salt=''.join(random.choice(string.ascii_letters + string.digits + "./") for _ in range(16))  
        return crypt.crypt(pwd, "$6$%s" % salt)
    
    def __guestFileRead(self, path):
        file_handle = -1
        content = self._QemuQuestAgent__getResult(FILE_OPEN_READ % (path))
        if not content:
           return ""
        file_handle = content["return"]
        if file_handle == -1:
            return ""
        file_content = self._QemuQuestAgent__getResult(FILE_READ % (file_handle,102400))["return"]["buf-b64"]
        self._QemuQuestAgent__getResult(FILE_CLOSE % file_handle) 
        if not file_content:
            return ""
        else:
            return file_content

    def __guestFileWrite(self, path, content, mode):  
        file_handle = -1  
        content = self._QemuQuestAgent__getResult(FILE_OPEN_WRITE % (path, mode))
        if not content:
           return -1
        file_handle = content["return"]
        if file_handle == -1:
            return -2
        write_count = self._QemuQuestAgent__getResult(FILE_WRITE % (file_handle,content))["return"]["count"]
        self._QemuQuestAgent__getResult(FILE_CLOSE % file_handle)  
        return write_count 

########################test############################
def testagent():
    instance = QemuQuestAgent()
    if instance.setSocketFile("/var/lib/libvirt/qemu/test.agent"):
        if instance.resetPassWord("abc123"):
            return True
        if instance.putFileToVM("test.py", "/root/test.py"):
            return True
    return False

if __name__ == '__main__':  
    testagent()

3、Qt使用qemu-ga

(1)qemuquestagent.h
#ifndef QEMUQUESTAGENT_H
#define QEMUQUESTAGENT_H
#include <QString>
#include <QDebug>
#include <QStringList>
#include <QDebug>

/***********************
 *<channel type='unix'>
 *  <source mode='bind' path='/var/lib/libvirt/qemu/test.agent'/>
 *  <target type='virtio' name='com.163.spice.0'/>
 *</channel>
 *
 * qemu-ga --daemonize -m virtio-serial -p /dev/virtio-ports/org.qemu.guest_agent.0
 *
 **********************/

/*************QemuQuestAgent*****************/
class HostConnectVM;
class ResetPassWord;
class FileManager;
class QemuQuestAgent
{
public:
    QemuQuestAgent();
    ~QemuQuestAgent();
    void getQGACommandAll();
    void resetPassWord();
    void fileOperation();
private:
    HostConnectVM *hostVM;
    ResetPassWord *passWord;
    FileManager *fileManager;
    QString socketFileName;
};

/*************ResetPassWord*****************/
class ResetPassWord
{
public:
    ResetPassWord(HostConnectVM *host);
    ~ResetPassWord();
    int checkOldPassWord(const QString &password);
    int setNewPassWord(const QString &password);

private:
    QString passwdFileRead();
    bool passwdFileWrite(const QString &password);
    bool openFile(QString mode);
    void closeFile();
    QString generationNewPassWord(const QString &password);

private:
    int fileHandle;
    QString filePasswd;
    HostConnectVM *pwHost;
    QStringList lineContent;
};
/*************FileManager*****************/
class FileManager
{
public:
    FileManager(HostConnectVM *host);
    ~FileManager();
    int getFile(const QString &filePathName, const QString &localPath = "");
    int putFile(const QString &localPathName, const QString &clientPathName);

    bool getFileContent(const QString &filename, const QString &localPathName);
    bool putFileContent(const QString &localName, const QString &clientName);

private:
    int openFile(const QString &filename, const QString &mode);

private:
    HostConnectVM *fmHost;
};
#endif // QEMUQUESTAGENT_H
(2)qemuquestagent.cpp
#include <shadow.h>
#include <unistd.h>
#include "qemuquestagent.h"
#include "questagentcomponent.h"
#include "defineconstants.h"
#include "jsonparse.h"
#include "base64.h"

/*************QemuQuestAgent*****************/
QemuQuestAgent::QemuQuestAgent()
{
    socketFileName = "/var/lib/libvirt/qemu/test.agent";
    hostVM = new HostConnectVM(socketFileName);
    passWord = new ResetPassWord(hostVM);
    fileManager = new FileManager(hostVM);
}

QemuQuestAgent::~QemuQuestAgent()
{
    if (hostVM) {
        delete hostVM;
        hostVM = NULL;
    }
    if (passWord) {
        delete passWord;
        passWord = NULL;
    }
    if (fileManager) {
        delete fileManager;
        fileManager = NULL;
    }
}

void QemuQuestAgent::getQGACommandAll()
{
    QString info = hostVM->getResult(GUEST_INFO);
    qDebug() << __FUNCTION__<<__LINE__ << info;
    if (info == "error2") {
        qDebug() << "can not conncet to the client of VM";
    }
}

void QemuQuestAgent::resetPassWord()
{
    QString oldPassWord = "abc123";
    QString newPassWord = "abc124";
    int flag = passWord->checkOldPassWord(oldPassWord);
    if (flag == 1) {
        qDebug() << "old password is wrong";
    }
    else if (flag == 0){
        qDebug() << "password is right";
        if (passWord->setNewPassWord(newPassWord) == 0) {
            qDebug() << "set newpassword succeed";
        }
        else {
            qDebug() << "set newpassword failed";
        }
    }
    else {
        //qDebug() << __LINE__ << "the client of VM is off";
    }
}

void QemuQuestAgent::fileOperation()
{
    qDebug() << "---fileOperation---";
    QString file = "/tmp/test1K.iso";
    fileManager->getFile(file, "/tmp/abc/");
    //fileManager->putFile("/tmp/abc/test1M.iso", "/tmp/");
}

/*************ResetPassWord*****************/
ResetPassWord::ResetPassWord(HostConnectVM *host)
    : fileHandle(-1)
{
    filePasswd = "/etc/shadow";
    pwHost = host;
}

ResetPassWord::~ResetPassWord()
{

}

int ResetPassWord::checkOldPassWord(const QString &password)
{
    if (openFile("r") == false) {
        return -1;
    }
    QString fileContent = passwdFileRead();
    closeFile();
    lineContent.clear();
    lineContent = fileContent.split("\n");
    for (int index = 0; index < lineContent.size(); ++index) {
        QStringList fields = lineContent.at(index).split(":");
        if (fields.at(0) == "root") {
            QStringList passwdList = fields.at(1).trimmed().split("$");
            QString saltBuff = QString("$%1$%2").arg(passwdList[1]).arg(passwdList[2]);
            char *shadowPwd = crypt(password.toStdString().data(), saltBuff.toStdString().data());
            if (!strcmp(shadowPwd, fields.at(1).trimmed().toStdString().data())) {   //compare old and new password
                return 0;
            }
            else {
                return 1;
            }
        }
    }
    return false;
}

int ResetPassWord::setNewPassWord(const QString &password)
{
    for (int index = 0; index < lineContent.size(); ++index) {
        QStringList fields = lineContent.at(index).split(":");
        if (fields.at(0) == "root") {
            fields[1] = generationNewPassWord(password);
            lineContent[index] = fields.join(":");
            break;
        }
    }
    QString newFileContent = "";
    if (lineContent.size() > 0) {
        newFileContent = lineContent.join("\n");
    }
    if (openFile("r+") == false && newFileContent.isEmpty()) {
        return -1;
    }
    if (passwdFileWrite(newFileContent) == false) {
        return 1;
    }
    lineContent.clear();
    closeFile();
    return 0;
}

QString ResetPassWord::passwdFileRead()
{
    QString resultStr = pwHost->getResult(FILE_READ.arg(fileHandle).arg(1400));
    //qDebug() << "**********" << resultStr<<"****";
    QMap<QString, QString>resultMap = JsonParse::jsonParseEnter(resultStr);
    // {"return": {"buf-b64": "aGVsbG8gd29ybGQhCg==", "count": 13, "eof": true}}
    if (resultMap.count() != 3) {
        qDebug() << "JsonParse failed!" <<endl;
        return false;
    }
    else {
        if (resultMap["eof"] != "true") {
            qDebug() << "qga readfile failed!" <<endl;
            return false;
        }
        string outResult = "";
        Base64TransCode::Base64Decode(resultMap["buf-b64"].toStdString(), &outResult);
        return QString::fromStdString(outResult);
    }
}

bool ResetPassWord::passwdFileWrite(const QString &password)
{
    string outResult = "";
    Base64TransCode::Base64Encode(password.toStdString(), &outResult);
    QString resultStr = pwHost->getResult(FILE_WRITE.arg(fileHandle).arg(QString::fromStdString(outResult)));
    QMap<QString, QString>resultMap = JsonParse::jsonParseEnter(resultStr);
    // {"return": {"count": 13, "eof": false}}
    qDebug() << "&&&" << resultMap.count() << resultMap["eof"] << resultMap["count"] << QString::fromStdString(outResult) << outResult.size();
    if (resultMap.count() == 2 && resultMap["eof"] == "false") {
        qDebug() << "change password successed";
        return true;
    }
    else {
        return false;
    }
}

bool ResetPassWord::openFile(QString mode)
{
    QString resultStr = pwHost->getResult(FILE_OPEN.arg(filePasswd).arg(mode));
    if (resultStr == "error2") {
        qDebug() << "can not conncet to the client of VM";
        return false;
    }
    //qDebug() << "aoyang---------------" << resultStr;
    QMap<QString, QString> resultMap = JsonParse::jsonParseEnter(resultStr);
    fileHandle = resultMap.begin().value().toInt();
    if (fileHandle < 0) {
        return false;
    }
    return true;
}

void ResetPassWord::closeFile()
{
    pwHost->getResult(FILE_FLUSH.arg(fileHandle));
    pwHost->getResult(FILE_CLOSE.arg(fileHandle));
}

QString ResetPassWord::generationNewPassWord(const QString &password)
{
    char seqCode[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789./";
    QString verifyCode = "$6$";
    QTime time= QTime::currentTime();
    qsrand(time.msec()+time.second()*1000);
    for(int i = 0; i < 16; i++) {
        int num = qrand() % strlen(seqCode);
        verifyCode += seqCode[num];
    }
    QString shadowPwd = crypt(password.toStdString().data(), verifyCode.toStdString().data());
    return shadowPwd;
}

/*************FileManager*****************/
FileManager::FileManager(HostConnectVM *host)
{
    fmHost = host;
}

FileManager::~FileManager()
{

}

int FileManager::getFile(const QString &filePathName, const QString &localPath)
{
    if (filePathName.isEmpty()) {
        return -1;
    }
    QFileInfo info(filePathName);
    QString locaFilename = localPath;
    if (localPath.isEmpty()) {
        locaFilename = QDir::currentPath();
        locaFilename += "/";
        locaFilename += info.fileName();
    }
    else if (localPath.right(1) == "/"){      //path
         locaFilename += info.fileName();
    }
    QFileInfo loaclInfo(locaFilename);
    QString dirName = loaclInfo.absolutePath();
    QDir dir(dirName);
    if (!dir.exists()) {
        dir.mkpath(dirName);
    }
    //write content to file
    //qDebug() << "locaFilename=" << locaFilename << "filePathName=" <<filePathName;
    getFileContent(filePathName, locaFilename);

    return 0;
}

bool FileManager::getFileContent(const QString &filename, const QString &localPathName)
{
    int handle = openFile(filename, "r");
    if (handle < 0) {
        return false;
    }
    QFile file(localPathName);
    file.open(QIODevice::WriteOnly | QIODevice::Text);
    QTextStream out(&file);

    while(true) {
        QString resultStr = fmHost->getResult(FILE_READ.arg(handle).arg(1400));
        //qDebug() << "--------" << resultStr<<"---------";
        QMap<QString, QString>resultMap = JsonParse::jsonParseEnter(resultStr);
        // {"return": {"buf-b64": "aGVsbG8gd29ybGQhCg==", "count": 13, "eof": false}}
        if (resultMap.count() != 3) {
            qDebug() << "JsonParse failed!" <<endl;
            return false;
        }
        else {
            //qDebug() << "++++++++++++++++++++" << resultMap["count"];
            if (resultMap["count"].toInt() < 0) {
                qDebug() << "qga readfile failed!" <<endl;
                return false;
            }
            string outResult = "";
            Base64TransCode::Base64Decode(resultMap["buf-b64"].toStdString(), &outResult);
            //qDebug() << "out-------put====" << QString::fromStdString(outResult);
            out << QString::fromStdString(outResult);
            file.flush();
            if (resultMap["eof"] == "true") {
                file.close();
                fmHost->getResult(FILE_CLOSE.arg(handle));
                return true;
            }
        }
    }
    return false;
}

int FileManager::putFile(const QString &localPathName, const QString &clientPathName)
{
    QFileInfo localFile(localPathName);
    if (!localFile.isFile()) {
        qDebug() << "file is not existed";
        return -1;
    }
    //long fileSize = localFile.size();

    QString clientFileName = clientPathName;

    if (clientPathName.right(1) == "/") {
        clientFileName += localFile.fileName();
    }
    putFileContent(localPathName, clientFileName);
}

bool FileManager::putFileContent(const QString &localName, const QString &clientName)
{
    QFile file(localName);
    long fileSize = file.size();
    if (fileSize <= 0) {
        return false;
    }
    if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
        return false;
    }
    int handle = openFile(clientName, "w");
    if (handle < 0) {
        return false;
    }
    int total = 0;
    do {
        string fileContent = file.read(10240).data();
        total += 10240;
        string outResult = "";
        Base64TransCode::Base64Encode(fileContent, &outResult);
        QString resultStr = fmHost->getResult(FILE_WRITE.arg(handle).arg(QString::fromStdString(outResult)));
        fmHost->getResult(FILE_FLUSH.arg(handle));

        QMap<QString, QString>resultMap = JsonParse::jsonParseEnter(resultStr);
        // {"return": {"count": 13, "eof": false}}
        //qDebug() << "&&&" << resultMap.count() << resultMap["eof"] << resultMap["count"]<< outResult.size();

        if (resultMap.count() != 2 || resultMap["count"].toInt() <= 0) {
            qDebug() << "write file error";
            fmHost->getResult(FILE_CLOSE.arg(handle));
            return false;
        }
    }while(total < fileSize);
    fmHost->getResult(FILE_CLOSE.arg(handle));
}

int FileManager::openFile(const QString &filename, const QString &mode)
{
    QString resultStr = fmHost->getResult(FILE_OPEN.arg(filename).arg(mode));
    qDebug() << FILE_OPEN.arg(filename).arg(mode);
    if (resultStr == "error2") {
        qDebug() << "can not conncet to the client of VM";
        return -2;
    }
    QMap<QString, QString> resultMap = JsonParse::jsonParseEnter(resultStr);
    int fileHandle = resultMap.begin().value().toInt();
    if (fileHandle <= 0) {
        qDebug() << "open file failed!";
        return -1;
    }
    return fileHandle;
}
(3)questagentcomponent.cpp
socket通讯,发送命令返回结果
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
#include <QDebug>
#include "questagentcomponent.h"

HostConnectVM::HostConnectVM(const QString &file)
{
    socketFile = file;
}

HostConnectVM::~HostConnectVM()
{

}

QString HostConnectVM::getResult(QString command, QString file)
{
    if (!file.isEmpty()) {
        socketFile = file;
    }
    QString resultStr = "";
    /* create a socket */
    struct sockaddr_un address;
    address.sun_family = AF_UNIX;
    strcpy(address.sun_path, socketFile.toStdString().data());
    sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
    if (sockfd == -1) {
        qDebug() << "create socket failed";
        resultStr = "error1";
        return resultStr;
    }
    /* connect to the server */
    int result = connect(sockfd, (struct sockaddr *)&address, sizeof(address));
    if(result == -1)  {
         qDebug() << "connect socket failed";
         resultStr = "error2";
         return resultStr;
    }

    if((result = write(sockfd, command.toStdString().data(), command.length())) != command.length()) {
        qDebug() << "write socket failed";
        resultStr = "error3";
        return resultStr;
    }
    char buff[10240] = {0};
    if ((result = read(sockfd, buff, 10240)) == -1) {
        qDebug() << "read socket failed";
        resultStr = "error4";
        return resultStr;
    }
    resultStr = buff;
    resultStr = resultStr.trimmed();
    close(sockfd);
    return resultStr;
}
(4)jsonparse.cpp
传输数据格式json的封装和解析
#include "jsonparse.h"

JsonParse::JsonParse()
{

}

JsonParse::~JsonParse()
{

}

QMap<QString, QString> JsonParse::jsonParseEnter(const QString &str)
{
    QMap<QString, QString> map;
    map.clear();
    if (str.trimmed().isEmpty()) {
        return map;
    }
    QScriptEngine engine;
    QScriptValue source = engine.evaluate("value="+str);
    QScriptValue valueReturn = source.property("return");
    if (valueReturn.isObject()) {
        QScriptValueIterator it(valueReturn);
        while(it.hasNext()) {
            it.next();
            map.insert(it.name(), it.value().toString());
        }
    }
    else {
        map.insert("return", valueReturn.toString());
    }
#ifndef PRINT_DEBUG
    QMap<QString, QString>::const_iterator iter = map.constBegin();
    for(;iter != map.constEnd(); iter++) {
        qDebug() << "---key=" << iter.key() << ", value=" << iter.value();
    }
#endif
}
(5)base64.cpp
        base64将字符串以MIME BASE64编码,此种编码是为了使二进制数据可以通过非纯8-bit的传输层传输,可以让中文字或者图片也能在网络上顺利传输,例如电子邮件的主体。在BASE64编码后的字符串只包含英文字母大小写、阿拉伯数字、加号与反斜线,共64个基本字符,不包含其它特殊的字符,因而才取名BASE64。编码后的字符串比原来的字符串长度再加1/3左右。
#include <string.h>
#include "base64.h"

bool Base64TransCode::Base64Encode(const string& input, string* output)
{
  string temp;
  temp.resize(modp_b64_encode_len(input.size()));    // makes room for null byte

  // null terminates result since result is base64 text!
  int input_size = static_cast<int>(input.size());
  int output_size= modp_b64_encode(&(temp[0]), input.data(), input_size);

  if (output_size < 0)  return false;

  temp.resize(output_size);  // strips off null byte
  output->swap(temp);
  return true;
}

bool Base64TransCode::Base64Decode(const string& input, string* output)
{
  string temp;
  temp.resize(modp_b64_decode_len(input.size()));

  // does not null terminate result since result is binary data!
  int input_size = static_cast<int>(input.size());
  int output_size = modp_b64_decode(&(temp[0]), input.data(), input_size);

  if (output_size < 0) return false;

  temp.resize(output_size);
  output->swap(temp);
  return true;
}
(6)main.cpp
#include <QCoreApplication>
#include "qemuquestagent.h"

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    QemuQuestAgent w;
    //w.resetPassWord();
    w.getQGACommandAll();
    //w.fileOperation();
    return a.exec();
}

三、总结

(1)参考:http://www.zoues.com/index.php/2015/10/13/qemu-guest-agent/http://www.csdn123.com/html/itweb/20130729/27101_27081_27076.htmhttp://blog.csdn.net/taiyang1987912/article/details/45191153
(2)若有问题或建议,请留言,在此感谢!

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Qt浅谈之四十六QemuQuestAgent的应用 的相关文章

  • 大多数 Linux 系统头文件与 C++ 兼容吗?

    大多数 Linux 系统头文件 API C 兼容吗 今天我试图做这样的事情 include
  • 我可以从命令行打印 html 文件(带有图像、css)吗?

    我想从脚本中打印带有图像的样式化 html 页面 谁能建议一个开源解决方案 我使用的是 Linux Ubuntu 8 04 但也对其他操作系统的解决方案感兴趣 你可以给html2ps http user it uu se jan html2
  • 从 Qt4 中的文本文件中逐字读取

    我想在 Qt4 中逐字读取一个文本文件 说实话我对它很陌生 我想在另一个文件中每行一个字写入 我可以在 C 中做到这一点 没有任何问题 但是当我尝试在 Qt4 中使用 ifstream 和 ofstream 时 我遇到了错误 这是我的 Qt
  • QSerialPort 中的 readAll() 不包括最后发送的响应

    我正在使用 Qt 来控制串行设备 如果我向串行设备发送命令 我会执行类似的操作serial gt write command r n 我制作了一个按钮 它将纯文本小部件内的文本更改为串行端口的响应 为了获得串口的响应 我使用serial g
  • linux perf:如何解释和查找热点

    我尝试了linux perf https perf wiki kernel org index php Main Page今天很实用 但在解释其结果时遇到了困难 我习惯了 valgrind 的 callgrind 这当然是与基于采样的 pe
  • 添加要在给定命令中运行的 .env 变量

    我有一个 env 文件 其中包含如下变量 HELLO world SOMETHING nothing 前几天我发现了这个很棒的脚本 它将这些变量放入当前会话中 所以当我运行这样的东西时 cat env grep v xargs node t
  • vector 超出范围后不清除内存

    我遇到了以下问题 我不确定我是否错了或者它是一个非常奇怪的错误 我填充了一个巨大的字符串数组 并希望在某个点将其清除 这是一个最小的例子 include
  • 尝试安装 LESS 时出现“请尝试以 root/管理员身份再次运行此命令”错误

    我正在尝试在我的计算机上安装 LESS 并且已经安装了节点 但是 当我输入 node install g less 时 出现以下错误 并且不知道该怎么办 FPaulMAC bin paul npm install g less npm ER
  • Discord.net 无法在 Linux 上运行

    我正在尝试让在 Linux VPS 上运行的 Discord net 中编码的不和谐机器人 我通过单声道运行 但我不断收到此错误 Unhandled Exception System Exception Connection lost at
  • 两种情况或 if 哪个更快? [关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 我必须制作一个 非常 轻的脚本 它将接受用户的选项并调用脚本中的函数来执行一些任务 现在我可以使用 IF 和 CASE 选项 但我想知道两
  • Linux 内核标识符中前导和尾随下划线的含义是什么?

    我不断遇到一些小约定 比如 KERNEL Are the 在这种情况下 是内核开发人员使用的命名约定 还是以这种方式命名宏的语法特定原因 整个代码中有很多这样的例子 例如 某些函数和变量以 甚至 这有什么具体原因吗 它似乎被广泛使用 我只需
  • 如何为 Windows 构建静态 Qt 库并将其与 Qt Creator 一起使用

    我已经下载了以下 Qt 源 http download qt nokia com qt source qt everywhere opensource src 4 7 3 zip http download qt nokia com qt
  • 将 PDF 转换为 600dpi 的 TIFF 和 jpg 96 dpi

    我想使用 ImageMagick 从 Python 脚本将 pdf 转换为 600 dpi 的 tiff 和 96 dpi 的 jpg 我使用 imagemagick 命令行完成了这项任务 但我想使用python中的Imagemagick将
  • 静态变量中的 qt tr()

    我在 qt 中的翻译方面遇到问题 我的项目中的所有翻译都工作正常 但有一个翻译位于类的静态变量中 相应部分代码如下 头文件类似于这样 typedef struct int type QString problematicString inf
  • Linux 可执行文件与 OS X“兼容”吗?

    如果您在基于 Linux 的平台上用 C 语言编译一个程序 然后将其移植以使用 MacOS 库 它会工作吗 来自编译器的核心机器代码在 Mac 和 Linux 上兼容吗 我问这个问题的原因是因为两者都是 基于 UNIX 的 所以我认为这是真
  • Linux:如何从特定端口发送TCP数据包?

    如何打开原始套接字以从特定 TCP 端口发送 我希望所有连接始终来自临时端口以下的一系列端口 如果您正在使用raw套接字 然后只需在数据包标头中填写正确的 TCP 源端口即可 相反 如果您使用 TCP 套接字接口 socket connec
  • 是否可以在 Qt Creator 中将 Qt 样式表与升级的小部件一起使用?

    我正在尝试使用 Qt 样式表对标准小部件进行一些重大的重新设计 因此 在为不同的小部件手动完成大部分工作之后 objectName选择器 我决定以某种方式对类似的小部件进行分组 例如我有多个QFrames其作用类似于内部表单中的标题 我希望
  • 如何通过保持目录结构完整来同步路径中匹配模式的文件?

    我想将所有文件从服务器 A 复制到服务器 B 这些文件在不同级别的文件系统层次结构中具有相同的父目录名称 例如 var lib data sub1 sub2 commonname filetobecopied foo var lib dat
  • 查找哪些页面不再与写入时复制共享

    假设我在 Linux 中有一个进程 我从中fork 另一个相同的过程 后forking 因为原始进程将开始写入内存 Linux写时复制机制将为进程提供与分叉进程使用的不同的唯一物理内存页 在执行的某个时刻 我如何知道原始进程的哪些页面已被写
  • 我的线程图像生成应用程序如何将其数据传输到 GUI?

    Mandelbrot 生成器的缓慢多精度实现 线程化 使用 POSIX 线程 Gtk 图形用户界面 我有点失落了 这是我第一次尝试编写线程程序 我实际上并没有尝试转换它的单线程版本 只是尝试实现基本框架 到目前为止它是如何工作的简要描述 M

随机推荐

  • PHP使用原生sql语句实现七天连续签到

    PHP原生使用原生sql语句实现七天连续签到 准备 一张放用户签到的数据表 字段包括id userid 用户id signtime 签到时间 时间戳 days 连续签到时间 七天连续签到 public function sign useri
  • MySQL 性能监控 4 大指标

    编者按 本文作者为 John Matson 主要介绍 mysql 性能监控应该关注的 4 大指标 文章系国内 ITOM 管理平台 OneAPM 编译呈现 MySQL 是什么 MySQL 是现而今最流行的开源关系型数据库服务器 由 Oracl
  • Temporary failure in name resolution 错误解决方法 运行sudo 命令 can not resovle host xxx

    Temporary failure in name resolution 错误解决方法 vim etc resolv conf nameserver 114 114 114 114 nameserver 8 8 8 8 运行sudo 命令
  • 你是否也无法在Thebrain 11中打开旧版数据?看看正确过渡新版方式

    TheBrain是一款与众不同的思维导图软件 其所有信息通过一个又一个的节点进行联系 最终形成一个杂而不乱的网状结构 一旦你搜索并点击一个想法后 与之相关的所有关联信息将一目了然 与传统的树形思维导图相比 TheBrain更有助于整合零散的
  • Robot Framework 学习(1)- 简单网站兼容性测试

    Robot Framework 简单网站兼容性测试 0 Robot Framework 简介 Robot Framework 是一个通用的自动化测试框架 主要用于 验收测试 和 验收测试驱动开发 ATDD 会其它文章中会详细介绍ATDD 它
  • SecureCRT发送AT指令

    1 首先安装驱动 MTK提供的驱动 会在设备管理器里面显示 2 打开secureCRT 选择连接类型为serial串口 3 设置secureCRT可以输入文本 4 然后就可以输入指令测试看看了 整个过程结束 但可能在第4步时输出没反应 这是
  • VS2017配置QT5.14.2

    一 QT下载 需要注意的是VS与QT的版本对应 VS2017对应的最新的QT版本是5 14 以后的版本适应的是VS2019 本文以VS2017 QT5 14为例 QT5 14 下载地址 Index of archive qt 5 14 5
  • 单片机——蜂鸣器(生日快乐歌)

    基础知识 改变单片机引脚输出波形的频率 就可以调整控制蜂鸣器音调 产生各种不同音色 音调的声音 改变输出电平的高低电平占空比 占空比是指一个周期内高电平所占的时间 则可以控制蜂鸣器的声音大小 单片机采用的是无源蜂鸣器 需要产生一定的脉冲才能
  • Acwing-873. 欧拉函数

    欧拉函数的证明使用了容斥原理 include
  • IDA反汇编之栈帧例释

    目录 1 例释环境和预备知识 1 1 运行环境 1 2 IDA版本 1 3 预备知识 2 函数调用约定 3 函数局部变量布局 4 函数栈帧示例 5 IDA栈视图 1 例释环境和预备知识 1 1 运行环境 本示例运行环境为Windows 10
  • VLAN(虚拟局域网)的用法与配置

    一 交换机的作用 区别集线器 HUB HUB为物理层设备 只能直接转发电流 交换机为数据链路层设备 可以将电流与二进制转换 实现了以下功能 1 无限的传输距离 2 彻底解决了冲突 所有接口可以同时收发数据 3 二层单薄 物理寻址 在一个交换
  • Eigen:基础入门到使用

    文章目录 一 基础介绍 1 1 安装 1 2 框架 二 矩阵基础 2 1 矩阵和向量 2 2 动态矩阵 2 3 定义 2 4访问矩阵元素 2 5 重置矩阵大小 2 6 怎么选择固定矩阵和动态矩阵 三 矩阵的运算 3 1 加法和减法 3 2
  • android studio jvm设置,如何使用gradle和kotlin为android studio设置jvm目标?

    尝试编译用kotlin编写的单元测试时出现以下错误 任务 app compileDebugUnitTestKotlin失败 无法将使用JVM target 1 7构建的字节码内联到使用JVM target 1 6构建的字节码中 请指定正确的
  • 一款可以完美替代浏览器自带起始页的新标签页插件:Wetab

    现在打开你们的浏览器 映入眼帘的是不是一片空白的自带起始页 或者是乱七八糟布满网站快捷方式的页面 Wetab新标签页是一款没有广告并且免费使用的浏览器插件 还原一个干净纯粹的浏览器体验 一 为什么要用wetab 本人已经被那些乱七八糟的起始
  • 递归超时怎么办?递归与递推的区别?递归的优化之道

    递归超时怎么办 递归的优化之道 平时在做题的时候 我们经常都要用到递归来解题 因为递归能最快速的让计算机知道我们想让他做什么 解放了我们的思维量 但在一定程度上加重了计算机的计算量 这也是可能超时的原因所在 方便我们阅读理解和修改 这里我想
  • 算法训练营第十四天(7.26)

    目录 LeeCode102 Binary Tree Level Order Traversal LeeCode226 Invert Binary Tree LeeCode101 Symmetric Tree LeeCode102 Binar
  • 将字符串以单词为单位逆序"I am a Student" 解法

    网上有个题目 将字符串以单词为单位逆序 例如 I am a Student 要变成 Student a am I 解法大致为 先将字符串整体逆序第一个字符和最后一个交换 第二个与倒数第二个交换 一直到完成整个串逆序 即 tnedutS a
  • 什么叫做项目孵化_【热点】孵化100个项目成功95个,创新工场凭什么?

    原标题 热点 孵化100个项目成功95个 创新工场凭什么 向死而生 我修的死亡学分 李开复 本文约3500字 建议阅读时间8分钟 2016年春节过后 创新工场创始人 董事长李开复带领工场内100多名创业者 15天里拜访了26位硅谷科技大咖
  • 使用腾讯手游助手作为开发测试模拟器的方案---以及部分问题的解决方案-1

    目录 前言 一 目录结构 二 注册表研究 1 HKEY LOCAL MACHINE SOFTWARE WOW6432Node Tencent MobileGamePC 2 HKEY CURRENT USER Software Tencent
  • Qt浅谈之四十六QemuQuestAgent的应用

    一 简介 qemu ga是在虚拟机中安装的一个agent 宿主机host通过通道 unix socket 与虚拟机vm内部的agent进行通信 这样宿主机就有了一种从外部控制 获取虚拟机的手段 比如 host可以向vm下发执行修改hostn