1// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd.
2//
3// SPDX-License-Identifier: GPL-3.0-or-later
4
5#include "processutil.h"
6
7#include <QProcess>
8#include <QFileInfo>
9#include <QDirIterator>
10#include <QDebug>
11#include <QUrl>
12
13bool ProcessUtil::execute(const QString &program,
14 const QStringList &arguments,
15 ProcessUtil::ReadCallBack func)
16{
17 return ProcessUtil::execute(program, arguments, "", func);
18}
19
20bool ProcessUtil::execute(const QString &program,
21 const QStringList &arguments,
22 const QString &workdir,
23 ProcessUtil::ReadCallBack func)
24{
25 return execute(program, arguments, workdir, QProcess().processEnvironment(), func);
26}
27
28bool ProcessUtil::execute(const QString &program,
29 const QStringList &arguments,
30 const QString &workdir,
31 const QProcessEnvironment &env,
32 ProcessUtil::ReadCallBack func)
33{
34 bool ret = true;
35 QProcess process;
36 process.setWorkingDirectory(workdir);
37 process.setProgram(program);
38 process.setArguments(arguments);
39 process.setProcessEnvironment(env);
40 process.connect(&process, QOverload<int, QProcess::ExitStatus >::of(&QProcess::finished),
41 [&](int exitCode, QProcess::ExitStatus exitStatus){
42 if (exitCode != 0)
43 ret = false;
44 qInfo() << program << arguments.join(" ")
45 << "exitCode: " << exitCode
46 << "exitStatus: " << exitStatus;
47 });
48 process.connect(&process, &QProcess::errorOccurred,
49 [&](QProcess::ProcessError error){
50 ret = false;
51 qCritical() << program << arguments.join(" ")
52 << "error: " << error
53 << "errorString: " << process.errorString();
54 });
55
56 process.start();
57 process.waitForFinished();
58
59 if (func) {
60 QByteArray array = process.readAll();
61 func(array.trimmed());
62 }
63
64 return ret;
65}
66
67QString ProcessUtil::execute(const QStringList &commands, bool cascade)
68{
69 auto executeCascade = [&](QString command, QString arg)->QString{
70 QString ret;
71 execute("bash", QStringList() << "-c" << (command + " " + arg), [&](const QByteArray &output){
72 ret = output;
73 });
74 return ret;
75 };
76
77 QString ret;
78 foreach (QString command, commands) {
79 if (cascade) {
80 ret = executeCascade(command, ret);
81 } else{
82 executeCascade(command, {});
83 }
84 }
85 return ret;
86}
87
88bool ProcessUtil::exists(const QString &name)
89{
90 bool ret = false;
91#ifdef linux
92 auto outCallback = [&ret, &name](const QByteArray &array) {
93 QList<QByteArray> rmSearch = array.split(' ');
94 foreach (QByteArray rmProcess, rmSearch) {
95 QFileInfo info(rmProcess.trimmed());
96 if (info.exists() && info.fileName() == name && info.isExecutable()) {
97 if (!ret) {
98 ret = true;
99 break;
100 }
101 } else {
102 ret = false;
103 }
104 }
105 };
106 ProcessUtil::execute("whereis", {name}, outCallback);
107#else
108#endif
109 return ret;
110}
111
112QString ProcessUtil::version(const QString &name)
113{
114 QString retOut;
115#ifdef linux
116 auto outCallback = [&retOut](const QByteArray &array) {
117 retOut = QString ::fromLatin1(array);
118 };
119 ProcessUtil::execute(name, {"-version"}, outCallback);
120#else
121#endif
122 return retOut;
123}
124
125bool ProcessUtil::hasGio()
126{
127 return exists("gio");
128}
129
130bool ProcessUtil::moveToTrash(const QString &filePath)
131{
132#ifdef linux
133 if (!hasGio())
134 return false;
135 return ProcessUtil::execute("gio", {"trash", filePath});
136#else
137
138#endif
139}
140
141bool ProcessUtil::recoverFromTrash(const QString &filePath)
142{
143#ifdef linux
144 if (!hasGio() || filePath.isEmpty())
145 return false;
146
147 QDirIterator itera(QDir::homePath() + QDir::separator() + ".local/share/Trash/files");
148 while (itera.hasNext()){
149 itera.next();
150 QFileInfo info(filePath);
151 if(info.suffix() == itera.fileInfo().suffix()
152 && info.baseName() == itera.fileInfo().baseName()) {
153 QByteArray readArray;
154 auto readCB = [&](const QByteArray array){readArray = array;};
155 QString trashFileUri = QString("trash:///%0").arg(info.fileName());
156 QStringList queryArgs;
157 queryArgs << "info";
158 queryArgs << trashFileUri;
159 queryArgs << "| grep trash::orig-path";
160 bool execResult = ProcessUtil::execute("gio", queryArgs, readCB);
161 if (!execResult && readArray.isEmpty()) {
162 qCritical() << "Unknown Error";
163 abort();
164 }
165 readArray = readArray.replace(" ", "");
166 auto list = readArray.split('\n');
167 auto itera = list.rbegin();
168 while (itera != list.rend()) {
169 if (itera->startsWith("trash::orig-path:")) {
170 readArray = *itera;
171 break;
172 }
173 itera ++;
174 }
175 if (!readArray.startsWith("trash::orig-path:")) {
176 qCritical() << "Error from: " <<QString::fromUtf8(readArray);
177 abort();
178 }
179 readArray = readArray.replace("trash::orig-path:", "");
180 if (readArray == filePath) {
181 QStringList args;
182 args << "move";
183 args << trashFileUri;
184 args << QUrl::fromLocalFile(filePath).toString();
185 return ProcessUtil::execute("gio", args);
186 }
187 }
188 }
189
190#else
191
192#endif
193 return false;
194}
195
196bool ProcessUtil::portOverhead(unsigned int port)
197{
198 bool ret = true;
199#ifdef linux
200 auto outCallback = [&ret](const QByteArray &array) {
201 qInfo() << qPrintable(array);
202 if (array.isEmpty()) {
203 ret = false;
204 }
205 };
206 ProcessUtil::execute("/bin/bash", {"-c", "ss -ntlp|grep " + QString::number(port)}, outCallback);
207#else
208#endif
209 return ret;
210}
211
212QString ProcessUtil::localPlatform()
213{
214 // get location platform
215 QString platform = "";
216 bool platfromQueRes = ProcessUtil::execute("arch", {}, [&](const QByteArray &data){
217 platform = QString(data).replace("\n","");
218 });
219 if (!platfromQueRes)
220 qCritical() << "usr command arch failed, please check tool program arch";
221 else if (platform.isEmpty())
222 qCritical() << "query local platform failed, not support \"arch\" command?";
223 return platform;
224}
225
226