[Решено] Пропадает часть вывода от udevadm запущенного через QProcess

mnemo

New member
Сообщения
20
#1
Здравствуйте!

В приложении на основе QMainWindow создаётся объект , который запускает процесс udevadm с аргументами info --name=/dev/sdb --query=property.
Сигналы QProcess::readyReadStandardOutput и QProcess::readyReadStandardError связаны со слотами в MainWondow.
Слоты читают вывод процесса и посредством метода append виджета QTextEdit, принадлежащего MainWondow, выводят в приложение.

C++:
void MainWindow::OnNewGetidData()
{
    QString str(_proc_getid->readAllStandardOutput());
    ui->m_teDisplay->append(str);
}
C++:
void MainWindow::OnNewGetidErrorData()
{
    QString str(_proc_getid->readAllStandardError());
    ui->m_teDisplay->append(str);
}
где _proc_getid - указатель на объект QProcess

результат получается таков:
Код:
DEVNAME=/dev/sdb
DEVPATH=/devices/pci0000:00/0000:00:0c.0/usb2/2-1/2-1:1.0/host3/target3:0:0/3:0:0:0/block/sdb
DEVTYPE=disk
DISKSEQ=122
MAJOR=8
MINOR=16
SUBSYSTEM=block
При этом, если udevadm info --name=/dev/sdb --query=property запустить просто в консоли, то вывод будет следующим:
Код:
DEVLINKS=/dev/disk/by-path/pci-0000:00:0c.0-usb-0:1:1.0-scsi-0:0:0:0-part1 /dev/disk/by-label/ESD-ISO /dev/disk/by-uuid/F2C27FADC27F7527 /dev/disk/by-id/usb-JetFlash_Transcend_32GB_15XD4FB3
4MCZS0CF-0:0-part1 /dev/disk/by-partuuid/0b7a7f10-01
DEVNAME=/dev/sdb1
DEVPATH=/devices/pci0000:00/0000:00:0c.0/usb2/2-1/2-1:1.0/host3/target3:0:0/3:0:0:0/block/sdb/sdb1
DEVTYPE=partition
DISKSEQ=101
ID_BUS=usb
ID_DRIVE_THUMB=1
ID_FS_LABEL=ESD-ISO
ID_FS_LABEL_ENC=ESD-ISO
ID_FS_TYPE=ntfs
ID_FS_USAGE=filesystem
ID_FS_UUID=F2C27FADC27F7527
ID_FS_UUID_ENC=F2C27FADC27F7527
ID_INSTANCE=0:0
ID_MODEL=Transcend_32GB
ID_MODEL_ENC=Transcend\x2032GB\x20\x20
ID_MODEL_ID=1000
ID_PART_ENTRY_DISK=8:16
ID_PART_ENTRY_FLAGS=0x80
ID_PART_ENTRY_NUMBER=1
ID_PART_ENTRY_OFFSET=2048
ID_PART_ENTRY_SCHEME=dos
ID_PART_ENTRY_SIZE=59723776
ID_PART_ENTRY_TYPE=0x7
ID_PART_ENTRY_UUID=0b7a7f10-01
ID_PART_TABLE_TYPE=dos
ID_PART_TABLE_UUID=0b7a7f10
ID_PATH=pci-0000:00:0c.0-usb-0:1:1.0-scsi-0:0:0:0
ID_PATH_TAG=pci-0000_00_0c_0-usb-0_1_1_0-scsi-0_0_0_0
ID_REVISION=1100
ID_SERIAL=JetFlash_Transcend_32GB_15XD4FB34MCZS0CF-0:0
ID_SERIAL_SHORT=15XD4FB34MCZS0CF
ID_TYPE=disk
ID_USB_DRIVER=usb-storage
ID_USB_INTERFACES=:080650:
ID_USB_INTERFACE_NUM=00
ID_VENDOR=JetFlash
ID_VENDOR_ENC=JetFlash
ID_VENDOR_ID=8564
MAJOR=8
MINOR=17
PARTN=1
SUBSYSTEM=block
TAGS=:systemd:
USEC_INITIALIZED=18861823047
net.ifnames=0
Ни как не могу понять куда в выводе QProcess девается середина:
Код:
ID_BUS=usb
ID_DRIVE_THUMB=1
ID_INSTANCE=0:0
ID_MODEL=Transcend_32GB
ID_MODEL_ENC=Transcend\x2032GB\x20\x20
ID_MODEL_ID=1000
ID_PART_TABLE_TYPE=dos
ID_PART_TABLE_UUID=0b7a7f10
ID_PATH=pci-0000:00:0c.0-usb-0:1:1.0-scsi-0:0:0:0
ID_PATH_TAG=pci-0000_00_0c_0-usb-0_1_1_0-scsi-0_0_0_0
ID_REVISION=1100
ID_SERIAL=JetFlash_Transcend_32GB_15XD4FB34MCZS0CF-0:0
ID_SERIAL_SHORT=15XD4FB34MCZS0CF
ID_TYPE=disk
ID_USB_DRIVER=usb-storage
ID_USB_INTERFACES=:080650:
ID_USB_INTERFACE_NUM=00
ID_VENDOR=JetFlash
ID_VENDOR_ENC=JetFlash
ID_VENDOR_ID=8564
Ради неё всё и затевалось.. :(
 

mnemo

New member
Сообщения
20
#2
Исходники (сумбурны, так-как это учебный пример для отработки техники, которая должна быть использована в чистовом приложении)

main.cpp

C++:
#include "mainwindow.h"
#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show();

    return a.exec();
}
 

mnemo

New member
Сообщения
20
#3
mainwindow.h

C++:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QProcess>
#include <QString>
#include <QStringList>

namespace Ui {
    class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

    public:
        explicit MainWindow(QWidget *parent = 0);
        ~MainWindow();

    protected:
        void GetDeviceID();


    private:
        Ui::MainWindow *ui;
        QProcess *_proc;
        QProcess *_proc_getid;
        QString _devname;
        QString _pid;
        QString _vid;
        QString _serial;

        // Constants
        QString PROG_FILE_NAME=QString("udevadm");
        QStringList PROG_ARGUMENTS=QStringList()<<"monitor";

    public slots:
        void OnProcStarted();
        void OnProcStartError(QProcess::ProcessError error);
        void OnNewData();
        void OnNewGetidData();
        void OnNewGetidErrorData();
        void OnFinished(int exitcode, QProcess::ExitStatus exitstatus);
        void OnGetidFinished(int exitcode, QProcess::ExitStatus exitstatus);

    signals:
};

#endif // MAINWINDOW_H
 

mnemo

New member
Сообщения
20
#4
mainwindow.cpp

C++:
#include "mainwindow.h"
#include "ui_mainwindow.h"

#include <QDebug>
#include <QChar>
#include <QProcess>
#include <QProcessEnvironment>
#include <QString>
#include <QStringList>

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow),
    _proc(nullptr)
{
    ui->setupUi(this);
    _proc=new QProcess();
    _proc_getid=new QProcess();

    connect(_proc,&QProcess::started,this,&MainWindow::OnProcStarted);
    connect(_proc,QOverload<int,QProcess::ExitStatus>::of(&QProcess::finished),this,&MainWindow::OnFinished);
    connect(_proc_getid,QOverload<int,QProcess::ExitStatus>::of(&QProcess::finished),this,&MainWindow::OnGetidFinished);
    connect(_proc,&QProcess::errorOccurred,this,&MainWindow::OnProcStartError);
    connect(_proc,&QProcess::readyRead,this,&MainWindow::OnNewData);
    connect(_proc_getid,&QProcess::readyReadStandardOutput,this,&MainWindow::OnNewGetidData);
    connect(_proc_getid,&QProcess::readyReadStandardError,this,&MainWindow::OnNewGetidErrorData);
    _proc_getid->setProcessChannelMode(QProcess::SeparateChannels);
    _devname.clear();
    _pid.clear();
    _vid.clear();
    _serial.clear();
    ui->m_teDisplay->append("Starting process: udevadm monitor");
    _proc->start(PROG_FILE_NAME,PROG_ARGUMENTS);
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::GetDeviceID()
{
    QString str;
    if(_devname.size()<1) return;
    //disconnect(_proc,&QProcess::readyRead,this,&MainWindow::OnNewData);
    //disconnect(_proc,&QProcess::errorOccurred,this,&MainWindow::OnProcStartError);
    //disconnect(_proc,&QProcess::started,this,&MainWindow::OnProcStarted);
    _proc->terminate();
    ui->m_teDisplay->append("Process udevadm killed");

    QStringList args;
    //args<<QString("info --query=property ")+QString("--name=")+_devname+QString(" ");
    args<<"info"<<QString("--name=")+_devname<<"--query=property";
    //_proc_getid->setArguments(args);
    str=QString("Starting process: ")+PROG_FILE_NAME+QString(" ");
    for(int i=0;i<args.count();i++) str+=args.at(i)+QString(" ");
    ui->m_teDisplay->append(str);
    _proc_getid->start(PROG_FILE_NAME,args);
    //_proc_getid->start("printenv",QStringList());
}

void MainWindow::OnProcStarted()
{
    ui->m_teDisplay->append("success");
}

void MainWindow::OnProcStartError(QProcess::ProcessError error)
{
    QString str;
    switch(error)
    {
        case QProcess::FailedToStart:
            str=QString("The process failed to start. Either the invoked program is missing, or you may have insufficient permissions to invoke the program.");
            break;
        case QProcess::Crashed:
            str=QString("The process crashed some time after starting successfully.");
            break;
        case QProcess::Timedout:
            str=QString("The last waitFor...() function timed out. The state of QProcess is unchanged, and you can try calling waitFor...() again.");
            break;
        case QProcess::WriteError:
            str=QString("An error occurred when attempting to write to the process. For example, the process may not be running, or it may have closed its input channel.");
            break;
        case QProcess::ReadError:
            str=QString("An error occurred when attempting to read from the process. For example, the process may not be running.");
            break;
        case QProcess::UnknownError:
            str=QString("An unknown error occurred. This is the default return value of error().");
            break;
    }
    ui->m_teDisplay->append(str);
}

void MainWindow::OnNewData()
{
    QString str(_proc->readAll());
    QStringList output;
    int start=0;
    int current=0;

    if(str.size()<1) return;
    while(current<str.size())
    {
        if(str.at(current)==QChar('\n'))
        {
            output<<str.mid(start,current-start);
            start=current+1;
        }
        current++;
    }

    for(int i=0;i<output.count();i++)
    {
        QString device;
        QString tmp=output.at(i);
        if(tmp.contains("KERNEL")&&tmp.contains("(block)")&&tmp.contains(" add "))
        {
//ui->m_teDisplay->append(tmp);
            start=current=tmp.size()-1;
            while(current>=0)
            {
                if(tmp.at(current)==QChar(' '))
                {
                    start=current-1;
                    break;
                }
                current--;
            }
            current=start;
            while(current>=0)
            {
                if(tmp.at(current)==QChar('/')) break;
                current--;
            }

            device=tmp.mid(current+1,start-current);


            if(!(device.at(device.size()-1)>=QChar('0')&&device.at(device.size()-1)<=QChar('9')))
            {
                ui->m_teDisplay->append(QString("/dev/")+device);
                ui->m_teDisplay->append("Flash found!!!");
                _devname=QString("/dev/")+device;
                GetDeviceID();
            }
        }
    }
}

void MainWindow::OnNewGetidData()
{
    QString str(_proc_getid->readAllStandardOutput()); //
qDebug()<<str;
    ui->m_teDisplay->append(str);
}

void MainWindow::OnNewGetidErrorData()
{
    QString str(_proc_getid->readAllStandardError()); //
qDebug()<<str;
    ui->m_teDisplay->append(str);
}

void MainWindow::OnFinished(int exitcode,QProcess::ExitStatus exitstatus)
{
    ui->m_teDisplay->append("Process finished...");
    QString str(_proc->readAll());
    QStringList output;
    int start=0;
    int current=0;

    if(str.size()<1) return;
    while(current<str.size())
    {
        if(str.at(current)==QChar('\n'))
        {
            output<<str.mid(start,current-start);
            start=current+1;
        }
        current++;
    }

    for(int i=0;i<output.count();i++) ui->m_teDisplay->append(output.at(i));
}

void MainWindow::OnGetidFinished(int exitcode, QProcess::ExitStatus exitstatus)
{
    ui->m_teDisplay->append("Process finished...");
    QString str(_proc_getid->readAllStandardOutput());
    ui->m_teDisplay->append(str);
}
 

Карл

New member
Сообщения
491
#5
сделай полный своей проект в tar.gz файле и прикрепи к сообщения, чтобы можно было собрать его
 

Карл

New member
Сообщения
491
#10
попробуй так:
Код:
	QProcess p;
	p.start("udevadm", {{"info"},  {"--name=/dev/sdd"},  {"--query=property"}});
	p.waitForFinished();
	qDebug() << QString(p.readAllStandardOutput());
 

mnemo

New member
Сообщения
20
#11
Ровным счётом ничего не меняется... :(
Сырой массив QByteArray, который "выплёвывает" readAllStandardOutput() содержит следующее:

Код:
"DEVNAME=/dev/sdb\nDEVPATH=/devices/pci0000:00/0000:00:0c.0/usb2/2-1/2-1:1.0/host3/target3:0:0/3:0:0:0/block/sdb\nDEVTYPE=disk\nDISKSEQ=38\nMAJOR=8\nMINOR=16\nSUBSYSTEM=block\n"
Потеряна самая первая строка вывода:

Код:
DEVLINKS=/dev/disk/by-id/usb-JetFlash_Transcend_32GB_15XD4FB34MCZS0CF-0:0 /dev/disk/by-path/pci-0000:00:0c.0-usb-0:1:1.0-scsi-0:0:0:0
всё, что начинается с ID_
Код:
ID_BUS=usb
ID_DRIVE_THUMB=1
ID_INSTANCE=0:0
ID_MODEL=Transcend_32GB
ID_MODEL_ENC=Transcend\x2032GB\x20\x20
ID_MODEL_ID=1000
ID_PART_TABLE_TYPE=dos
ID_PART_TABLE_UUID=0b7a7f10
ID_PATH=pci-0000:00:0c.0-usb-0:1:1.0-scsi-0:0:0:0
ID_PATH_TAG=pci-0000_00_0c_0-usb-0_1_1_0-scsi-0_0_0_0
ID_REVISION=1100
ID_SERIAL=JetFlash_Transcend_32GB_15XD4FB34MCZS0CF-0:0
ID_SERIAL_SHORT=15XD4FB34MCZS0CF
ID_TYPE=disk
ID_USB_DRIVER=usb-storage
ID_USB_INTERFACES=:080650:
ID_USB_INTERFACE_NUM=00
ID_VENDOR=JetFlash
ID_VENDOR_ENC=JetFlash
ID_VENDOR_ID=8564
и три строки в конце вывода:

Код:
TAGS=:systemd:
USEC_INITIALIZED=11029280767
net.ifnames=0
Куда это девается и почему в таком странном порядке (чуть-чуть с начала, кусок в середине и чуть-чуть в конце) я ни как понять не могу...:confused:
 
Последнее редактирование:

mnemo

New member
Сообщения
20
#13
Да, действительно работает как надо..
Начал переписывать всё с нуля, пока работает.. Походу, где-то в коде накосячил... Буду разбираться.

Спасибо!!!! :)
 

mnemo

New member
Сообщения
20
#14
Мда, это всё хорошо работает, пока осуществляется единственный вызов udevadm.
По логике работы программы сначала должен осуществляться запуск первого процесса udevadm с ключом monitor, который ждёт подключения USB-носителя и по его выводу определяет имя, которое получило устройство в системе при подключении (это может быть /dev/sdb, /dev/sdc и т.п. и оно может быть разным раз от раза). Запуск этого процесса осуществляется в своём персональном объекте класса QProcess.
Далее в отдельном объекте класса QProcess запускается другой процесс udevadm с ключом info --name=<имя_устройства_полученное_в_результате_работы_первого_процесса> и из его вывода должны читаться параметры, начинающиеся с ID_...
НО!!!! В выводе второго процесса снова теряются часть строк, как это было описано ранее.... Если udevadm info --name=<...> запустить первым, то вывод получается полным, а если после вызова udevadm monitor, то вывод получается не весь..
При этом следует заметить, то процессы запускаются из двух разных независимых друг от друга объектов QProcess. Я даже пробовал перез запуском второго процесса удалять объект первого процесса - не помогает...
 

mnemo

New member
Сообщения
20
#15
Ларчик просто открывался... :)
Жизненный цикл этих двух процессов пересекался. Первый процесс завершался вызовом QProcess::terminate(), а в обработчике сигнала осуществлялся запуск второго процесса по результатам работы первого. Но, видимо, полностью завершиться не успевал до начала работы второго.
Строка
QThread::sleep(1);
добавленная в обработчик сигнала finished() первого процесса перед запуском второго процесса полностью решила проблему...
Вот так..