19#if QT_VERSION >= QT_VERSION_CHECK(6,5,0)
20#include <QtEnvironmentVariables>
21#include <QtProcessorDetection>
22#include <QtSystemDetection>
26#include <sys/sysinfo.h>
34#include <sys/sysctl.h>
38#include <QReadWriteLock>
39#include <QNetworkProxy>
47#include <QHostAddress>
48#include <QRegularExpression>
49#include <QRegularExpressionMatchIterator>
67 struct sysinfo sinfo {};
68 if (sysinfo(&sinfo) == -1)
70 LOG(VB_GENERAL, LOG_ERR,
"sysinfo() error");
73 uptime = std::chrono::seconds(sinfo.uptime);
75#elif defined(Q_OS_BSD4)
76 std::array<int,2> mib { CTL_KERN, KERN_BOOTTIME };
77 struct timeval bootTime;
82 len =
sizeof(bootTime);
83 if (sysctl(mib.data(), 2, &bootTime, &len,
nullptr, 0) == -1)
85 LOG(VB_GENERAL, LOG_ERR,
"sysctl() error");
88 uptime = std::chrono::seconds(time(
nullptr) - bootTime.tv_sec);
89#elif defined(Q_OS_WINDOWS)
90 uptime = std::chrono::seconds(::GetTickCount() / 1000);
93 LOG(VB_GENERAL, LOG_NOTICE,
"Unknown platform. How do I get the uptime?");
108 [[maybe_unused]]
int &freeMB,
109 [[maybe_unused]]
int &totalVM,
110 [[maybe_unused]]
int &freeVM)
113 static constexpr size_t MB { 1024LL * 1024 };
114 struct sysinfo sinfo {};
115 if (sysinfo(&sinfo) == -1)
117 LOG(VB_GENERAL, LOG_ERR,
118 "getMemStats(): Error, sysinfo() call failed.");
122 totalMB = (int)((sinfo.totalram * sinfo.mem_unit)/MB);
123 freeMB = (int)((sinfo.freeram * sinfo.mem_unit)/MB);
124 totalVM = (int)((sinfo.totalswap * sinfo.mem_unit)/MB);
125 freeVM = (int)((sinfo.freeswap * sinfo.mem_unit)/MB);
127#elif defined(Q_OS_DARWIN)
129 mach_msg_type_number_t count = 0;
130 vm_size_t pageSize = 0;
131 vm_statistics_data_t s;
133 mp = mach_host_self();
136 if (host_page_size(mp, &pageSize) != KERN_SUCCESS)
139 count = HOST_VM_INFO_COUNT;
140 if (host_statistics(mp, HOST_VM_INFO,
141 (host_info_t)&s, &count) != KERN_SUCCESS)
143 LOG(VB_GENERAL, LOG_ERR,
"getMemStats(): Error, "
144 "failed to get virtual memory statistics.");
149 totalMB = (s.active_count + s.inactive_count +
150 s.wire_count + s.free_count) * pageSize / 1024;
151 freeMB = s.free_count * pageSize / 1024;
159 totalVM = (int)(fsInfo.getTotalSpace() >> 10);
160 freeVM = (int)(fsInfo.getFreeSpace() >> 10);
176#if !defined(Q_OS_WINDOWS) && !defined(Q_OS_ANDROID)
178 if (
getloadavg(loads.data(), loads.size()) != -1)
186 QStringList strlist(QString(
"QUERY_LOAD"));
190 load[0] = strlist[0].toDouble();
191 load[1] = strlist[1].toDouble();
192 load[2] = strlist[2].toDouble();
201 QStringList strlist(QString(
"QUERY_UPTIME"));
206 if (strlist[0].isEmpty() || !strlist[0].at(0).isNumber())
209 if (
sizeof(std::chrono::seconds::rep) ==
sizeof(
long long))
210 uptime = std::chrono::seconds(strlist[0].toLongLong());
211 else if (
sizeof(std::chrono::seconds::rep) ==
sizeof(
long))
212 uptime = std::chrono::seconds(strlist[0].toLong());
213 else if (
sizeof(std::chrono::seconds::rep) ==
sizeof(
int))
214 uptime = std::chrono::seconds(strlist[0].toInt());
221 QStringList strlist(QString(
"QUERY_MEMSTATS"));
225 totalMB = strlist[0].toInt();
226 freeMB = strlist[1].toInt();
227 totalVM = strlist[2].toInt();
228 freeVM = strlist[3].toInt();
252 QString cmd = QString(
"%systemroot%\\system32\\ping.exe -w %1 -n 1 %2>NUL")
253 .arg(
timeout.count()) .arg(host);
260 QHostAddress addr = QHostAddress(addrstr);
261#if defined(Q_OS_FREEBSD) || defined(Q_OS_DARWIN)
262 QString timeoutparam(
"-t");
265 QString timeoutparam(
"-w");
268 addr.protocol() == QAbstractSocket::IPv6Protocol ?
"ping6" :
"ping";
269 QString cmd = QString(
"%1 %2 %3 -c 1 %4 >/dev/null 2>&1")
270 .arg(pingcmd, timeoutparam,
271 QString::number(duration_cast<std::chrono::seconds>(
timeout).count()),
282bool telnet(
const QString &host,
int port)
286 bool connected = s->ConnectToHost(host, port);
316 char *buf =
new char[buflen];
323 if (!dst.isWritable() && !dst.isOpen())
325 odst = dst.open(QIODevice::Unbuffered |
326 QIODevice::WriteOnly |
327 QIODevice::Truncate);
330 if (!src.isReadable() && !src.isOpen())
331 osrc = src.open(QIODevice::Unbuffered|QIODevice::ReadOnly);
333 bool ok = dst.isWritable() && src.isReadable();
334 long long total_bytes = 0LL;
338 long long rlen = src.read(buf, buflen);
341 LOG(VB_GENERAL, LOG_ERR,
"read error");
350 while ((rlen-off>0) && ok)
352 long long wlen = dst.write(buf + off, rlen - off);
357 LOG(VB_GENERAL, LOG_ERR,
"write error");
370 return ok ? total_bytes : -1LL;
379 char tempfilename[MAX_PATH] =
"";
382 if (GetTempFileNameA(
temppath,
"mth", 0, tempfilename))
387 unlink(tempfilename);
388 ret = mkdir(tempfilename);
391 ret = open(tempfilename, O_CREAT | O_RDWR, S_IREAD | S_IWRITE);
393 QString tmpFileName(tempfilename);
395 QByteArray safe_name_template = name_template.toLatin1();
396 std::string ctemplate = safe_name_template.constData();
400 ret = (mkdtemp(ctemplate.data())) ? 0 : -1;
404 mode_t cur_umask = umask(S_IRWXO | S_IRWXG);
405 ret = mkstemp(ctemplate.data());
409 QString tmpFileName = QString::fromStdString(ctemplate);
414 LOG(VB_GENERAL, LOG_ERR, QString(
"createTempFile(%1), Error ")
415 .arg(name_template) +
ENO);
416 return name_template;
419 if (!dir && (ret >= 0))
445 QByteArray fname =
filename.toLatin1();
446 int ret = chmod(fname.constData(), 0666);
449 LOG(VB_GENERAL, LOG_ERR, QString(
"Unable to change permissions on file. (%1)").arg(
filename));
460 QByteArray tmp = query.toLocal8Bit();
461 std::cout << tmp.constData();
463 tmp = def.toLocal8Bit();
465 std::cout <<
" [" << tmp.constData() <<
"] ";
469 if (!isatty(fileno(stdin)) || !isatty(fileno(
stdout)))
471 std::cout <<
"\n[console is not interactive, using default '"
472 << tmp.constData() <<
"']\n";
476 QTextStream stream(stdin);
477 QString qresponse = stream.readLine();
479 if (qresponse.isEmpty())
490 QString str_resp =
getResponse(query, QString(
"%1").arg(def));
491 if (str_resp.isEmpty())
494 int resp = str_resp.toInt(&ok);
495 return (ok ? resp : def);
500 QStringList *intermediaries,
504 LOG(VB_GENERAL, LOG_DEBUG,
505 QString(
"getSymlinkTarget('%1', 0x%2, %3)")
506 .arg(start_file).arg((uint64_t)intermediaries,0,16)
511 QString cur_file = start_file;
512 QFileInfo fi(cur_file);
516 intermediaries->clear();
517 intermediaries->push_back(start_file);
520 for (
uint i = 0; (i <= maxLinks) && fi.isSymLink() &&
521 !(link = fi.symLinkTarget()).isEmpty(); i++)
523 cur_file = (link[0] ==
'/') ?
525 fi.absoluteDir().absolutePath() +
"/" + link;
527 if (intermediaries && !intermediaries->contains(cur_file))
528 intermediaries->push_back(cur_file);
530 fi = QFileInfo(cur_file);
536 for (
uint i = 0; i < intermediaries->size(); i++)
538 LOG(VB_GENERAL, LOG_DEBUG, QString(
" inter%1: %2")
539 .arg(i).arg((*intermediaries)[i]));
543 LOG(VB_GENERAL, LOG_DEBUG,
544 QString(
"getSymlinkTarget() -> '%1'")
545 .arg((!fi.isSymLink()) ? cur_file : QString()));
548 return (!fi.isSymLink()) ? cur_file : QString();
553 QStringList tokens = MAC.split(
':');
554 if (tokens.size() != 6)
556 LOG(VB_NETWORK, LOG_ERR,
557 QString(
"IsMACAddress(%1) = false, doesn't have 6 parts").arg(MAC));
561 for (
int y = 0; y < 6; y++)
563 if (tokens[y].isEmpty())
565 LOG(VB_NETWORK, LOG_ERR,
566 QString(
"IsMACAddress(%1) = false, part #%2 is empty.")
572 int value = tokens[y].toInt(&ok, 16);
575 LOG(VB_NETWORK, LOG_ERR,
576 QString(
"IsMACAddress(%1) = false, unable to "
577 "convert part '%2' to integer.")
578 .arg(MAC, tokens[y]));
584 LOG(VB_NETWORK, LOG_ERR,
585 QString(
"IsMACAddress(%1) = false, part #%2 "
586 "evaluates to %3 which is higher than 255.")
587 .arg(MAC).arg(y).arg(value));
592 LOG(VB_NETWORK, LOG_DEBUG, QString(
"IsMACAddress(%1) = true").arg(MAC));
599 QFileInfo fileinfo(
file);
600 qint64 initialsize = fileinfo.size();
603 if (initialsize == 0)
606 if (
file.open(QIODevice::ReadOnly))
612 LOG(VB_GENERAL, LOG_ERR,
613 "Error: Unable to open selected file, missing read permissions?");
618 QDataStream stream(&
file);
619 stream.setByteOrder(QDataStream::LittleEndian);
620 for (quint64 tmp = 0, i = 0; i < 65536/
sizeof(tmp); i++)
626 file.seek(initialsize - 65536);
627 for (quint64 tmp = 0, i = 0; i < 65536/
sizeof(tmp); i++)
635 QString
output = QString(
"%1").arg(hash, 0, 16);
641 std::vector<char> msg(6,
static_cast<char>(0xFF));
642 std::array<char,6> macaddr {};
643 QStringList tokens = MAC.split(
':');
645 if (tokens.size() != 6)
647 LOG(VB_GENERAL, LOG_ERR,
648 QString(
"WakeOnLan(%1): Incorrect MAC length").arg(MAC));
652 for (
int y = 0; y < 6; y++)
655 macaddr[y] = tokens[y].toInt(&ok, 16);
659 LOG(VB_GENERAL, LOG_ERR,
660 QString(
"WakeOnLan(%1): Invalid MAC address").arg(MAC));
666 for (
int x = 0; x < 16; x++)
667 msg.insert(msg.end(), macaddr.cbegin(), macaddr.cend());
669 LOG(VB_NETWORK, LOG_INFO,
670 QString(
"WakeOnLan(): Sending WOL packet to %1").arg(MAC));
672 QUdpSocket udp_socket;
673 qlonglong msglen = msg.size();
674 return udp_socket.writeDatagram(
675 msg.data(), msglen, QHostAddress::Broadcast, 32767) == msglen;
695 const char *command =
"ps -ax | grep -i pulseaudio | grep -v grep > /dev/null";
697 const char *command =
"ps ch -C pulseaudio -o pid > /dev/null";
711 if ((-1 == ret) && (0 != errno) && (val >= 0))
713 LOG(VB_GENERAL, LOG_ERR,
"Failed to nice process" +
ENO);
722#ifdef _POSIX_PRIORITY_SCHEDULING
724 std::this_thread::sleep_for(5ms);
726 std::this_thread::sleep_for(5ms);
747#if defined(Q_OS_LINUX) && ( defined(Q_PROCESSOR_X86) || defined(Q_PROCESSOR_POWER) || \
748 defined(Q_PROCESSOR_IA64) )
752#include <sys/ptrace.h>
753#include <sys/syscall.h>
754#if __has_include(<linux/ioprio.h>)
759#include <linux/ioprio.h>
762static constexpr int8_t IOPRIO_BITS { 16 };
763static constexpr int8_t IOPRIO_CLASS_SHIFT { 13 };
764static constexpr int IOPRIO_PRIO_MASK { (1UL << IOPRIO_CLASS_SHIFT) - 1 };
765static constexpr int IOPRIO_PRIO_CLASS(
int mask)
766 {
return mask >> IOPRIO_CLASS_SHIFT; };
767static constexpr int IOPRIO_PRIO_DATA(
int mask)
768 {
return mask & IOPRIO_PRIO_MASK; };
769static constexpr int IOPRIO_PRIO_VALUE(
int pclass,
int data)
770 {
return (pclass << IOPRIO_CLASS_SHIFT) | data; };
772enum { IOPRIO_CLASS_NONE,IOPRIO_CLASS_RT,IOPRIO_CLASS_BE,IOPRIO_CLASS_IDLE, };
773enum { IOPRIO_WHO_PROCESS = 1, IOPRIO_WHO_PGRP, IOPRIO_WHO_USER, };
778 int new_ioclass {IOPRIO_CLASS_BE};
780 new_ioclass = IOPRIO_CLASS_RT;
782 new_ioclass = IOPRIO_CLASS_IDLE;
783 int new_iodata = (new_ioclass == IOPRIO_CLASS_BE) ? val : 0;
784 int new_ioprio = IOPRIO_PRIO_VALUE(new_ioclass, new_iodata);
787 int old_ioprio = syscall(SYS_ioprio_get, IOPRIO_WHO_PROCESS, pid);
788 if (old_ioprio == new_ioprio)
791 int ret = syscall(SYS_ioprio_set, IOPRIO_WHO_PROCESS, pid, new_ioprio);
793 if (-1 == ret && EPERM == errno && IOPRIO_CLASS_BE != new_ioclass)
795 new_iodata = (new_ioclass == IOPRIO_CLASS_RT) ? 0 : 7;
796 new_ioprio = IOPRIO_PRIO_VALUE(IOPRIO_CLASS_BE, new_iodata);
797 ret = syscall(SYS_ioprio_set, IOPRIO_WHO_PROCESS, pid, new_ioprio);
814 QFileInfoList entries = aDir.entryInfoList(QDir::NoDotAndDotDot |
815 QDir::Dirs | QDir::Files);
816 int count = entries.size();
817 bool has_err =
false;
819 for (
int idx = 0; idx < count && !has_err; idx++)
821 const QFileInfo& entryInfo = entries[idx];
822 QString path = entryInfo.absoluteFilePath();
823 if (entryInfo.isDir())
836 if (!has_err && !aDir.rmdir(aDir.absolutePath()))
855 QString
LOC =
"setHttpProxy() - ";
858 QString var(qEnvironmentVariable(
"http_proxy"));
860 var = qEnvironmentVariable(
"HTTP_PROXY");
863 if (!var.startsWith(
"http://"))
864 var.prepend(
"http://");
866 QUrl url = QUrl(var, QUrl::TolerantMode);
867 QString host = url.host();
868 int port = url.port();
881 LOG(VB_NETWORK, LOG_INFO,
LOC +
882 QString(
"assuming port %1 on host %2") .arg(port).arg(host));
885 else if (!
ping(host, 1s))
887 LOG(VB_GENERAL, LOG_ERR,
LOC +
888 QString(
"cannot locate host %1").arg(host) +
889 "\n\t\t\tPlease check HTTP_PROXY environment variable!");
891 else if (!
telnet(host,port))
893 LOG(VB_GENERAL, LOG_ERR,
LOC +
894 QString(
"%1:%2 - cannot connect!").arg(host).arg(port) +
895 "\n\t\t\tPlease check HTTP_PROXY environment variable!");
899 LOG(VB_NETWORK, LOG_DEBUG,
LOC + QString(
"using http://%1:%2@%3:%4")
900 .arg(url.userName()).arg(url.password())
901 .arg(host).arg(port));
904 QNetworkProxy(QNetworkProxy::HttpCachingProxy,
905 host, port, url.userName(), url.password());
906 QNetworkProxy::setApplicationProxy(
p);
910 LOG(VB_NETWORK, LOG_DEBUG,
LOC +
"no HTTP_PROXY environment var.");
915 QNetworkProxyQuery query(QUrl(
"http://www.mythtv.org"));
917 proxies = QNetworkProxyFactory::systemProxyForQuery(query);
919 for (
const auto&
p : std::as_const(
proxies))
921 QString host =
p.hostName();
924 if (
p.type() == QNetworkProxy::NoProxy)
929 LOG(VB_NETWORK, LOG_ERR,
LOC +
930 "failed to contact proxy host " + host);
934 LOG(VB_NETWORK, LOG_INFO,
LOC + QString(
"using proxy host %1:%2")
935 .arg(host).arg(port));
936 QNetworkProxy::setApplicationProxy(
p);
942 if (!
p.user().isEmpty())
944 url =
"http://%1:%2@%3:%4",
945 url = url.arg(
p.user(),
p.password());
949 url =
"http://%1:%2";
952 url = url.arg(
p.hostName()).arg(
p.port());
953 qputenv(
"HTTP_PROXY", url.toLocal8Bit().constData());
954 if (!qEnvironmentVariableIsSet(
"http_proxy"))
956 qputenv(
"http_proxy", url.toLocal8Bit().constData());
962 LOG(VB_NETWORK, LOG_ERR,
LOC +
"failed to find a network proxy");
static QString resolveAddress(const QString &host, ResolveType type=ResolveAny, bool keepscope=false)
if host is an IP address, it will be returned or resolved otherwise.
bool SendReceiveStringList(QStringList &strlist, bool quickTimeout=false, bool block=true)
Send a message to the backend and wait for a response.
Class for communcating between myth backends and frontends.
@ GENERIC_EXIT_OK
Exited with no error.
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
#define ENO
This can be appended to the LOG args with "+".
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
bool RemoteGetUptime(std::chrono::seconds &uptime)
bool getMemStats(int &totalMB, int &freeMB, int &totalVM, int &freeVM)
Returns memory statistics in megabytes.
loadArray getLoadAvgs(void)
Returns the system load averages.
bool RemoteGetLoad(loadArray &load)
bool MythWakeup(const QString &wakeUpCommand, uint flags, std::chrono::seconds timeout)
bool MythRemoveDirectory(QDir &aDir)
bool IsMACAddress(const QString &MAC)
int intResponse(const QString &query, int def)
In an interactive shell, prompt the user to input a number.
bool getUptime(std::chrono::seconds &uptime)
Returns uptime statistics.
QString getResponse(const QString &query, const QString &def)
In an interactive shell, prompt the user to input a string.
bool IsPulseAudioRunning(void)
Is A/V Sync destruction daemon is running on this host?
QString getSymlinkTarget(const QString &start_file, QStringList *intermediaries, unsigned maxLinks)
void setHttpProxy(void)
Get network proxy settings from OS, and use for [Q]Http[Comms].
bool WakeOnLAN(const QString &MAC)
QString FileHash(const QString &filename)
bool telnet(const QString &host, int port)
Can we talk to port on host?
bool RemoteGetMemStats(int &totalMB, int &freeMB, int &totalVM, int &freeVM)
bool ping(const QString &host, std::chrono::milliseconds timeout)
Can we ping host within timeout seconds?
bool myth_ioprio(int)
Allows setting the I/O priority of the current process/thread.
bool makeFileAccessible(const QString &filename)
QString createTempFile(QString name_template, bool dir)
std::array< double, 3 > loadArray
@ kMSDontBlockInputDevs
avoid blocking LIRC & Joystick Menu
@ kMSProcessEvents
process events while waiting
@ kMSDontDisableDrawing
avoid disabling UI drawing
uint myth_system(const QString &command, uint flags, std::chrono::seconds timeout)
MBASE_PUBLIC long long copy(QFile &dst, QFile &src, uint block_size=0)
Copies src file to dst file.