25 #include <sys/sysinfo.h>
30 #include <mach/mach.h>
34 #include <sys/mount.h>
35 #include <sys/sysctl.h>
40 #include <QReadWriteLock>
41 #include <QNetworkProxy>
42 #include <QStringList>
43 #include <QDataStream>
49 #include <QHostAddress>
50 #include <QRegularExpression>
51 #include <QRegularExpressionMatchIterator>
69 struct sysinfo sinfo {};
70 if (sysinfo(&sinfo) == -1)
72 LOG(VB_GENERAL, LOG_ERR,
"sysinfo() error");
75 uptime = std::chrono::seconds(sinfo.uptime);
77 #elif defined(__FreeBSD__) || defined(Q_OS_DARWIN)
79 std::array<int,2> mib { CTL_KERN, KERN_BOOTTIME };
80 struct timeval bootTime;
85 len =
sizeof(bootTime);
86 if (sysctl(mib.data(), 2, &bootTime, &len,
nullptr, 0) == -1)
88 LOG(VB_GENERAL, LOG_ERR,
"sysctl() error");
91 uptime = std::chrono::seconds(time(
nullptr) - bootTime.tv_sec);
93 uptime = std::chrono::seconds(::GetTickCount() / 1000);
96 LOG(VB_GENERAL, LOG_NOTICE,
"Unknown platform. How do I get the uptime?");
109 bool getMemStats(
int &totalMB,
int &freeMB,
int &totalVM,
int &freeVM)
112 static constexpr
size_t MB { 1024LL * 1024 };
113 struct sysinfo sinfo {};
114 if (sysinfo(&sinfo) == -1)
116 LOG(VB_GENERAL, LOG_ERR,
117 "getMemStats(): Error, sysinfo() call failed.");
121 totalMB = (int)((sinfo.totalram * sinfo.mem_unit)/MB);
122 freeMB = (int)((sinfo.freeram * sinfo.mem_unit)/MB);
123 totalVM = (int)((sinfo.totalswap * sinfo.mem_unit)/MB);
124 freeVM = (int)((sinfo.freeswap * sinfo.mem_unit)/MB);
126 #elif defined(Q_OS_DARWIN)
128 mach_msg_type_number_t count;
130 vm_statistics_data_t s;
132 mp = mach_host_self();
135 if (host_page_size(mp, &pageSize) != KERN_SUCCESS)
138 count = HOST_VM_INFO_COUNT;
139 if (host_statistics(mp, HOST_VM_INFO,
140 (host_info_t)&s, &count) != KERN_SUCCESS)
142 LOG(VB_GENERAL, LOG_ERR,
"getMemStats(): Error, "
143 "failed to get virtual memory statistics.");
148 totalMB = (s.active_count + s.inactive_count +
149 s.wire_count + s.free_count) * pageSize / 1024;
150 freeMB = s.free_count * pageSize / 1024;
156 int64_t total, used, free;
158 totalVM = (int)(total >> 10);
159 freeVM = (int)(free >> 10);
178 #if !defined(_WIN32) && !defined(Q_OS_ANDROID)
180 if (
getloadavg(loads.data(), loads.size()) != -1)
203 QString cmd = QString(
"%systemroot%\\system32\\ping.exe -w %1 -n 1 %2>NUL")
204 .arg(
timeout.count()) .arg(host);
211 QHostAddress addr = QHostAddress(addrstr);
212 #if defined(__FreeBSD__) || defined(Q_OS_DARWIN)
213 QString timeoutparam(
"-t");
216 QString timeoutparam(
"-w");
219 addr.protocol() == QAbstractSocket::IPv6Protocol ?
"ping6" :
"ping";
220 QString cmd = QString(
"%1 %2 %3 -c 1 %4 >/dev/null 2>&1")
221 .arg(pingcmd, timeoutparam,
222 QString::number(duration_cast<std::chrono::seconds>(
timeout).count()),
233 bool telnet(
const QString &host,
int port)
237 bool connected = s->ConnectToHost(host, port);
267 char *buf =
new char[buflen];
274 if (!dst.isWritable() && !dst.isOpen())
276 odst = dst.open(QIODevice::Unbuffered |
277 QIODevice::WriteOnly |
278 QIODevice::Truncate);
281 if (!src.isReadable() && !src.isOpen())
282 osrc = src.open(QIODevice::Unbuffered|QIODevice::ReadOnly);
284 bool ok = dst.isWritable() && src.isReadable();
285 long long total_bytes = 0LL;
289 long long rlen = src.read(buf, buflen);
292 LOG(VB_GENERAL, LOG_ERR,
"read error");
301 while ((rlen-off>0) && ok)
303 long long wlen = dst.write(buf + off, rlen - off);
308 LOG(VB_GENERAL, LOG_ERR,
"write error");
321 return (ok) ? total_bytes : -1LL;
330 char tempfilename[MAX_PATH] =
"";
333 if (GetTempFileNameA(
temppath,
"mth", 0, tempfilename))
338 unlink(tempfilename);
339 ret = mkdir(tempfilename);
342 ret = open(tempfilename, O_CREAT | O_RDWR, S_IREAD | S_IWRITE);
344 QString tmpFileName(tempfilename);
346 QByteArray safe_name_template = name_template.toLatin1();
347 const char *
tmp = safe_name_template.constData();
348 char *ctemplate = strdup(
tmp);
352 ret = (mkdtemp(ctemplate)) ? 0 : -1;
356 mode_t cur_umask = umask(S_IRWXO | S_IRWXG);
357 ret = mkstemp(ctemplate);
361 QString tmpFileName(ctemplate);
367 LOG(VB_GENERAL, LOG_ERR, QString(
"createTempFile(%1), Error ")
368 .arg(name_template) +
ENO);
369 return name_template;
372 if (!dir && (ret >= 0))
398 QByteArray fname =
filename.toLatin1();
399 int ret = chmod(fname.constData(), 0666);
402 LOG(VB_GENERAL, LOG_ERR, QString(
"Unable to change permissions on file. (%1)").arg(
filename));
413 QByteArray
tmp = query.toLocal8Bit();
414 std::cout <<
tmp.constData();
416 tmp = def.toLocal8Bit();
418 std::cout <<
" [" <<
tmp.constData() <<
"] ";
422 if (!isatty(fileno(stdin)) || !isatty(fileno(
stdout)))
424 std::cout << std::endl <<
"[console is not interactive, using default '"
425 <<
tmp.constData() <<
"']" << std::endl;
429 QTextStream stream(stdin);
430 QString qresponse = stream.readLine();
432 if (qresponse.isEmpty())
443 QString str_resp =
getResponse(query, QString(
"%1").arg(def));
444 if (str_resp.isEmpty())
447 int resp = str_resp.toInt(&ok);
448 return (ok ? resp : def);
453 QStringList *intermediaries,
457 LOG(VB_GENERAL, LOG_DEBUG,
458 QString(
"getSymlinkTarget('%1', 0x%2, %3)")
459 .arg(start_file).arg((uint64_t)intermediaries,0,16)
464 QString cur_file = start_file;
465 QFileInfo fi(cur_file);
469 intermediaries->clear();
470 intermediaries->push_back(start_file);
473 for (
uint i = 0; (i <= maxLinks) && fi.isSymLink() &&
474 !(link = fi.symLinkTarget()).isEmpty(); i++)
476 cur_file = (link[0] ==
'/') ?
478 fi.absoluteDir().absolutePath() +
"/" + link;
480 if (intermediaries && !intermediaries->contains(cur_file))
481 intermediaries->push_back(cur_file);
483 fi = QFileInfo(cur_file);
489 for (
uint i = 0; i < intermediaries->size(); i++)
491 LOG(VB_GENERAL, LOG_DEBUG, QString(
" inter%1: %2")
492 .arg(i).arg((*intermediaries)[i]));
496 LOG(VB_GENERAL, LOG_DEBUG,
497 QString(
"getSymlinkTarget() -> '%1'")
498 .arg((!fi.isSymLink()) ? cur_file : QString()));
501 return (!fi.isSymLink()) ? cur_file : QString();
506 QStringList tokens = MAC.split(
':');
507 if (tokens.size() != 6)
509 LOG(VB_NETWORK, LOG_ERR,
510 QString(
"IsMACAddress(%1) = false, doesn't have 6 parts").arg(MAC));
514 for (
int y = 0; y < 6; y++)
516 if (tokens[y].isEmpty())
518 LOG(VB_NETWORK, LOG_ERR,
519 QString(
"IsMACAddress(%1) = false, part #%2 is empty.")
525 int value = tokens[y].toInt(&ok, 16);
528 LOG(VB_NETWORK, LOG_ERR,
529 QString(
"IsMACAddress(%1) = false, unable to "
530 "convert part '%2' to integer.")
531 .arg(MAC, tokens[y]));
537 LOG(VB_NETWORK, LOG_ERR,
538 QString(
"IsMACAddress(%1) = false, part #%2 "
539 "evaluates to %3 which is higher than 255.")
540 .arg(MAC).arg(y).arg(value));
545 LOG(VB_NETWORK, LOG_DEBUG, QString(
"IsMACAddress(%1) = true").arg(MAC));
552 QFileInfo fileinfo(
file);
553 qint64 initialsize = fileinfo.size();
556 if (initialsize == 0)
559 if (
file.open(QIODevice::ReadOnly))
563 LOG(VB_GENERAL, LOG_ERR,
564 "Error: Unable to open selected file, missing read permissions?");
569 QDataStream stream(&
file);
570 stream.setByteOrder(QDataStream::LittleEndian);
571 for (quint64
tmp = 0, i = 0; i < 65536/
sizeof(
tmp); i++)
577 file.seek(initialsize - 65536);
578 for (quint64
tmp = 0, i = 0; i < 65536/
sizeof(
tmp); i++)
586 QString
output = QString(
"%1").arg(hash, 0, 16);
592 std::vector<char> msg(6,
static_cast<char>(0xFF));
593 std::array<char,6> macaddr {};
594 QStringList tokens = MAC.split(
':');
596 if (tokens.size() != 6)
598 LOG(VB_GENERAL, LOG_ERR,
599 QString(
"WakeOnLan(%1): Incorrect MAC length").arg(MAC));
603 for (
int y = 0; y < 6; y++)
606 macaddr[y] = tokens[y].toInt(&ok, 16);
610 LOG(VB_GENERAL, LOG_ERR,
611 QString(
"WakeOnLan(%1): Invalid MAC address").arg(MAC));
617 for (
int x = 0; x < 16; x++)
618 msg.insert(msg.end(), macaddr.cbegin(), macaddr.cend());
620 LOG(VB_NETWORK, LOG_INFO,
621 QString(
"WakeOnLan(): Sending WOL packet to %1").arg(MAC));
623 QUdpSocket udp_socket;
624 qlonglong msglen = msg.size();
625 return udp_socket.writeDatagram(
626 msg.data(), msglen, QHostAddress::Broadcast, 32767) == msglen;
645 #if defined(Q_OS_DARWIN) || defined(__FreeBSD__) || defined(__OpenBSD__)
646 const char *command =
"ps -ax | grep -i pulseaudio | grep -v grep > /dev/null";
648 const char *command =
"ps ch -C pulseaudio -o pid > /dev/null";
662 if ((-1 == ret) && (0 != errno) && (val >= 0))
664 LOG(VB_GENERAL, LOG_ERR,
"Failed to nice process" +
ENO);
673 #ifdef _POSIX_PRIORITY_SCHEDULING
698 #if defined(__linux__) && ( defined(__i386__) || defined(__ppc__) || \
699 defined(__x86_64__) || defined(__ia64__) )
703 #include <sys/ptrace.h>
704 #include <sys/syscall.h>
705 #if __has_include(<linux/ioprio.h>)
706 #include <linux/ioprio.h>
708 static constexpr int8_t IOPRIO_BITS { 16 };
709 static constexpr int8_t IOPRIO_CLASS_SHIFT { 13 };
710 static constexpr
int IOPRIO_PRIO_MASK { (1UL << IOPRIO_CLASS_SHIFT) - 1 };
711 static constexpr
int IOPRIO_PRIO_CLASS(
int mask)
712 {
return mask >> IOPRIO_CLASS_SHIFT; };
713 static constexpr
int IOPRIO_PRIO_DATA(
int mask)
714 {
return mask & IOPRIO_PRIO_MASK; };
715 static constexpr
int IOPRIO_PRIO_VALUE(
int pclass,
int data)
716 {
return (pclass << IOPRIO_CLASS_SHIFT) | data; };
718 enum { IOPRIO_CLASS_NONE,IOPRIO_CLASS_RT,IOPRIO_CLASS_BE,IOPRIO_CLASS_IDLE, };
719 enum { IOPRIO_WHO_PROCESS = 1, IOPRIO_WHO_PGRP, IOPRIO_WHO_USER, };
720 #endif // has_include(<linux/ioprio.h>)
724 int new_ioclass = (val < 0) ? IOPRIO_CLASS_RT :
725 (val > 7) ? IOPRIO_CLASS_IDLE : IOPRIO_CLASS_BE;
726 int new_iodata = (new_ioclass == IOPRIO_CLASS_BE) ? val : 0;
727 int new_ioprio = IOPRIO_PRIO_VALUE(new_ioclass, new_iodata);
730 int old_ioprio = syscall(SYS_ioprio_get, IOPRIO_WHO_PROCESS, pid);
731 if (old_ioprio == new_ioprio)
734 int ret = syscall(SYS_ioprio_set, IOPRIO_WHO_PROCESS, pid, new_ioprio);
736 if (-1 == ret && EPERM == errno && IOPRIO_CLASS_BE != new_ioclass)
738 new_iodata = (new_ioclass == IOPRIO_CLASS_RT) ? 0 : 7;
739 new_ioprio = IOPRIO_PRIO_VALUE(IOPRIO_CLASS_BE, new_iodata);
740 ret = syscall(SYS_ioprio_set, IOPRIO_WHO_PROCESS, pid, new_ioprio);
757 QFileInfoList entries = aDir.entryInfoList(QDir::NoDotAndDotDot |
758 QDir::Dirs | QDir::Files);
759 int count = entries.size();
760 bool has_err =
false;
762 for (
int idx = 0; idx < count && !has_err; idx++)
764 QFileInfo entryInfo = entries[idx];
765 QString path = entryInfo.absoluteFilePath();
766 if (entryInfo.isDir())
779 if (!has_err && !aDir.rmdir(aDir.absolutePath()))
798 QString
LOC =
"setHttpProxy() - ";
801 QString var(qEnvironmentVariable(
"http_proxy"));
803 var = qEnvironmentVariable(
"HTTP_PROXY");
806 if (!var.startsWith(
"http://"))
807 var.prepend(
"http://");
809 QUrl url = QUrl(var, QUrl::TolerantMode);
810 QString host = url.host();
811 int port = url.port();
824 LOG(VB_NETWORK, LOG_INFO,
LOC +
825 QString(
"assuming port %1 on host %2") .arg(port).arg(host));
828 else if (!
ping(host, 1s))
830 LOG(VB_GENERAL, LOG_ERR,
LOC +
831 QString(
"cannot locate host %1").arg(host) +
832 "\n\t\t\tPlease check HTTP_PROXY environment variable!");
834 else if (!
telnet(host,port))
836 LOG(VB_GENERAL, LOG_ERR,
LOC +
837 QString(
"%1:%2 - cannot connect!").arg(host).arg(port) +
838 "\n\t\t\tPlease check HTTP_PROXY environment variable!");
842 LOG(VB_NETWORK, LOG_DEBUG,
LOC + QString(
"using http://%1:%2@%3:%4")
843 .arg(url.userName()).arg(url.password())
844 .arg(host).arg(port));
847 QNetworkProxy(QNetworkProxy::HttpCachingProxy,
848 host, port, url.userName(), url.password());
849 QNetworkProxy::setApplicationProxy(
p);
853 LOG(VB_NETWORK, LOG_DEBUG,
LOC +
"no HTTP_PROXY environment var.");
858 QNetworkProxyQuery query(QUrl(
"http://www.mythtv.org"));
860 proxies = QNetworkProxyFactory::systemProxyForQuery(query);
862 for (
const auto&
p : qAsConst(
proxies))
864 QString host =
p.hostName();
867 if (
p.type() == QNetworkProxy::NoProxy)
872 LOG(VB_NETWORK, LOG_ERR,
LOC +
873 "failed to contact proxy host " + host);
877 LOG(VB_NETWORK, LOG_INFO,
LOC + QString(
"using proxy host %1:%2")
878 .arg(host).arg(port));
879 QNetworkProxy::setApplicationProxy(
p);
885 if (!
p.user().isEmpty())
887 url =
"http://%1:%2@%3:%4",
888 url = url.arg(
p.user(),
p.password());
892 url =
"http://%1:%2";
895 url = url.arg(
p.hostName()).arg(
p.port());
896 setenv(
"HTTP_PROXY", url.toLatin1(), 1);
897 setenv(
"http_proxy", url.toLatin1(), 0);
902 LOG(VB_NETWORK, LOG_ERR,
LOC +
"failed to find a network proxy");