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?");
110 [[maybe_unused]]
int &freeMB,
111 [[maybe_unused]]
int &totalVM,
112 [[maybe_unused]]
int &freeVM)
115 static constexpr
size_t MB { 1024LL * 1024 };
116 struct sysinfo sinfo {};
117 if (sysinfo(&sinfo) == -1)
119 LOG(VB_GENERAL, LOG_ERR,
120 "getMemStats(): Error, sysinfo() call failed.");
124 totalMB = (int)((sinfo.totalram * sinfo.mem_unit)/MB);
125 freeMB = (int)((sinfo.freeram * sinfo.mem_unit)/MB);
126 totalVM = (int)((sinfo.totalswap * sinfo.mem_unit)/MB);
127 freeVM = (int)((sinfo.freeswap * sinfo.mem_unit)/MB);
129 #elif defined(Q_OS_DARWIN)
131 mach_msg_type_number_t count;
133 vm_statistics_data_t s;
135 mp = mach_host_self();
138 if (host_page_size(mp, &pageSize) != KERN_SUCCESS)
141 count = HOST_VM_INFO_COUNT;
142 if (host_statistics(mp, HOST_VM_INFO,
143 (host_info_t)&s, &count) != KERN_SUCCESS)
145 LOG(VB_GENERAL, LOG_ERR,
"getMemStats(): Error, "
146 "failed to get virtual memory statistics.");
151 totalMB = (s.active_count + s.inactive_count +
152 s.wire_count + s.free_count) * pageSize / 1024;
153 freeMB = s.free_count * pageSize / 1024;
159 int64_t total, used, free;
161 totalVM = (int)(total >> 10);
162 freeVM = (int)(free >> 10);
177 #if !defined(_WIN32) && !defined(Q_OS_ANDROID)
179 if (
getloadavg(loads.data(), loads.size()) != -1)
202 QString cmd = QString(
"%systemroot%\\system32\\ping.exe -w %1 -n 1 %2>NUL")
203 .arg(
timeout.count()) .arg(host);
210 QHostAddress addr = QHostAddress(addrstr);
211 #if defined(__FreeBSD__) || defined(Q_OS_DARWIN)
212 QString timeoutparam(
"-t");
215 QString timeoutparam(
"-w");
218 addr.protocol() == QAbstractSocket::IPv6Protocol ?
"ping6" :
"ping";
219 QString cmd = QString(
"%1 %2 %3 -c 1 %4 >/dev/null 2>&1")
220 .arg(pingcmd, timeoutparam,
221 QString::number(duration_cast<std::chrono::seconds>(
timeout).count()),
232 bool telnet(
const QString &host,
int port)
236 bool connected = s->ConnectToHost(host, port);
266 char *buf =
new char[buflen];
273 if (!dst.isWritable() && !dst.isOpen())
275 odst = dst.open(QIODevice::Unbuffered |
276 QIODevice::WriteOnly |
277 QIODevice::Truncate);
280 if (!src.isReadable() && !src.isOpen())
281 osrc = src.open(QIODevice::Unbuffered|QIODevice::ReadOnly);
283 bool ok = dst.isWritable() && src.isReadable();
284 long long total_bytes = 0LL;
288 long long rlen = src.read(buf, buflen);
291 LOG(VB_GENERAL, LOG_ERR,
"read error");
300 while ((rlen-off>0) && ok)
302 long long wlen = dst.write(buf + off, rlen - off);
307 LOG(VB_GENERAL, LOG_ERR,
"write error");
320 return (ok) ? total_bytes : -1LL;
329 char tempfilename[MAX_PATH] =
"";
332 if (GetTempFileNameA(
temppath,
"mth", 0, tempfilename))
337 unlink(tempfilename);
338 ret = mkdir(tempfilename);
341 ret = open(tempfilename, O_CREAT | O_RDWR, S_IREAD | S_IWRITE);
343 QString tmpFileName(tempfilename);
345 QByteArray safe_name_template = name_template.toLatin1();
346 const char *
tmp = safe_name_template.constData();
347 char *ctemplate = strdup(
tmp);
351 ret = (mkdtemp(ctemplate)) ? 0 : -1;
355 mode_t cur_umask = umask(S_IRWXO | S_IRWXG);
356 ret = mkstemp(ctemplate);
360 QString tmpFileName(ctemplate);
366 LOG(VB_GENERAL, LOG_ERR, QString(
"createTempFile(%1), Error ")
367 .arg(name_template) +
ENO);
368 return name_template;
371 if (!dir && (ret >= 0))
397 QByteArray fname =
filename.toLatin1();
398 int ret = chmod(fname.constData(), 0666);
401 LOG(VB_GENERAL, LOG_ERR, QString(
"Unable to change permissions on file. (%1)").arg(
filename));
412 QByteArray
tmp = query.toLocal8Bit();
413 std::cout <<
tmp.constData();
415 tmp = def.toLocal8Bit();
417 std::cout <<
" [" <<
tmp.constData() <<
"] ";
421 if (!isatty(fileno(stdin)) || !isatty(fileno(
stdout)))
423 std::cout << std::endl <<
"[console is not interactive, using default '"
424 <<
tmp.constData() <<
"']" << std::endl;
428 QTextStream stream(stdin);
429 QString qresponse = stream.readLine();
431 if (qresponse.isEmpty())
442 QString str_resp =
getResponse(query, QString(
"%1").arg(def));
443 if (str_resp.isEmpty())
446 int resp = str_resp.toInt(&ok);
447 return (ok ? resp : def);
452 QStringList *intermediaries,
456 LOG(VB_GENERAL, LOG_DEBUG,
457 QString(
"getSymlinkTarget('%1', 0x%2, %3)")
458 .arg(start_file).arg((uint64_t)intermediaries,0,16)
463 QString cur_file = start_file;
464 QFileInfo fi(cur_file);
468 intermediaries->clear();
469 intermediaries->push_back(start_file);
472 for (
uint i = 0; (i <= maxLinks) && fi.isSymLink() &&
473 !(link = fi.symLinkTarget()).isEmpty(); i++)
475 cur_file = (link[0] ==
'/') ?
477 fi.absoluteDir().absolutePath() +
"/" + link;
479 if (intermediaries && !intermediaries->contains(cur_file))
480 intermediaries->push_back(cur_file);
482 fi = QFileInfo(cur_file);
488 for (
uint i = 0; i < intermediaries->size(); i++)
490 LOG(VB_GENERAL, LOG_DEBUG, QString(
" inter%1: %2")
491 .arg(i).arg((*intermediaries)[i]));
495 LOG(VB_GENERAL, LOG_DEBUG,
496 QString(
"getSymlinkTarget() -> '%1'")
497 .arg((!fi.isSymLink()) ? cur_file : QString()));
500 return (!fi.isSymLink()) ? cur_file : QString();
505 QStringList tokens = MAC.split(
':');
506 if (tokens.size() != 6)
508 LOG(VB_NETWORK, LOG_ERR,
509 QString(
"IsMACAddress(%1) = false, doesn't have 6 parts").arg(MAC));
513 for (
int y = 0; y < 6; y++)
515 if (tokens[y].isEmpty())
517 LOG(VB_NETWORK, LOG_ERR,
518 QString(
"IsMACAddress(%1) = false, part #%2 is empty.")
524 int value = tokens[y].toInt(&ok, 16);
527 LOG(VB_NETWORK, LOG_ERR,
528 QString(
"IsMACAddress(%1) = false, unable to "
529 "convert part '%2' to integer.")
530 .arg(MAC, tokens[y]));
536 LOG(VB_NETWORK, LOG_ERR,
537 QString(
"IsMACAddress(%1) = false, part #%2 "
538 "evaluates to %3 which is higher than 255.")
539 .arg(MAC).arg(y).arg(value));
544 LOG(VB_NETWORK, LOG_DEBUG, QString(
"IsMACAddress(%1) = true").arg(MAC));
551 QFileInfo fileinfo(
file);
552 qint64 initialsize = fileinfo.size();
555 if (initialsize == 0)
558 if (
file.open(QIODevice::ReadOnly))
562 LOG(VB_GENERAL, LOG_ERR,
563 "Error: Unable to open selected file, missing read permissions?");
568 QDataStream stream(&
file);
569 stream.setByteOrder(QDataStream::LittleEndian);
570 for (quint64
tmp = 0, i = 0; i < 65536/
sizeof(
tmp); i++)
576 file.seek(initialsize - 65536);
577 for (quint64
tmp = 0, i = 0; i < 65536/
sizeof(
tmp); i++)
585 QString
output = QString(
"%1").arg(hash, 0, 16);
591 std::vector<char> msg(6,
static_cast<char>(0xFF));
592 std::array<char,6> macaddr {};
593 QStringList tokens = MAC.split(
':');
595 if (tokens.size() != 6)
597 LOG(VB_GENERAL, LOG_ERR,
598 QString(
"WakeOnLan(%1): Incorrect MAC length").arg(MAC));
602 for (
int y = 0; y < 6; y++)
605 macaddr[y] = tokens[y].toInt(&ok, 16);
609 LOG(VB_GENERAL, LOG_ERR,
610 QString(
"WakeOnLan(%1): Invalid MAC address").arg(MAC));
616 for (
int x = 0; x < 16; x++)
617 msg.insert(msg.end(), macaddr.cbegin(), macaddr.cend());
619 LOG(VB_NETWORK, LOG_INFO,
620 QString(
"WakeOnLan(): Sending WOL packet to %1").arg(MAC));
622 QUdpSocket udp_socket;
623 qlonglong msglen = msg.size();
624 return udp_socket.writeDatagram(
625 msg.data(), msglen, QHostAddress::Broadcast, 32767) == msglen;
644 #if defined(Q_OS_DARWIN) || defined(__FreeBSD__) || defined(__OpenBSD__)
645 const char *command =
"ps -ax | grep -i pulseaudio | grep -v grep > /dev/null";
647 const char *command =
"ps ch -C pulseaudio -o pid > /dev/null";
661 if ((-1 == ret) && (0 != errno) && (val >= 0))
663 LOG(VB_GENERAL, LOG_ERR,
"Failed to nice process" +
ENO);
672 #ifdef _POSIX_PRIORITY_SCHEDULING
697 #if defined(__linux__) && ( defined(__i386__) || defined(__ppc__) || \
698 defined(__x86_64__) || defined(__ia64__) )
702 #include <sys/ptrace.h>
703 #include <sys/syscall.h>
704 #if __has_include(<linux/ioprio.h>)
709 #include <linux/ioprio.h>
712 static constexpr int8_t IOPRIO_BITS { 16 };
713 static constexpr int8_t IOPRIO_CLASS_SHIFT { 13 };
714 static constexpr
int IOPRIO_PRIO_MASK { (1UL << IOPRIO_CLASS_SHIFT) - 1 };
715 static constexpr
int IOPRIO_PRIO_CLASS(
int mask)
716 {
return mask >> IOPRIO_CLASS_SHIFT; };
717 static constexpr
int IOPRIO_PRIO_DATA(
int mask)
718 {
return mask & IOPRIO_PRIO_MASK; };
719 static constexpr
int IOPRIO_PRIO_VALUE(
int pclass,
int data)
720 {
return (pclass << IOPRIO_CLASS_SHIFT) | data; };
722 enum { IOPRIO_CLASS_NONE,IOPRIO_CLASS_RT,IOPRIO_CLASS_BE,IOPRIO_CLASS_IDLE, };
723 enum { IOPRIO_WHO_PROCESS = 1, IOPRIO_WHO_PGRP, IOPRIO_WHO_USER, };
724 #endif // has_include(<linux/ioprio.h>)
728 int new_ioclass {IOPRIO_CLASS_BE};
730 new_ioclass = IOPRIO_CLASS_RT;
732 new_ioclass = IOPRIO_CLASS_IDLE;
733 int new_iodata = (new_ioclass == IOPRIO_CLASS_BE) ? val : 0;
734 int new_ioprio = IOPRIO_PRIO_VALUE(new_ioclass, new_iodata);
737 int old_ioprio = syscall(SYS_ioprio_get, IOPRIO_WHO_PROCESS, pid);
738 if (old_ioprio == new_ioprio)
741 int ret = syscall(SYS_ioprio_set, IOPRIO_WHO_PROCESS, pid, new_ioprio);
743 if (-1 == ret && EPERM == errno && IOPRIO_CLASS_BE != new_ioclass)
745 new_iodata = (new_ioclass == IOPRIO_CLASS_RT) ? 0 : 7;
746 new_ioprio = IOPRIO_PRIO_VALUE(IOPRIO_CLASS_BE, new_iodata);
747 ret = syscall(SYS_ioprio_set, IOPRIO_WHO_PROCESS, pid, new_ioprio);
764 QFileInfoList entries = aDir.entryInfoList(QDir::NoDotAndDotDot |
765 QDir::Dirs | QDir::Files);
766 int count = entries.size();
767 bool has_err =
false;
769 for (
int idx = 0; idx < count && !has_err; idx++)
771 const QFileInfo& entryInfo = entries[idx];
772 QString path = entryInfo.absoluteFilePath();
773 if (entryInfo.isDir())
786 if (!has_err && !aDir.rmdir(aDir.absolutePath()))
805 QString
LOC =
"setHttpProxy() - ";
808 QString var(qEnvironmentVariable(
"http_proxy"));
810 var = qEnvironmentVariable(
"HTTP_PROXY");
813 if (!var.startsWith(
"http://"))
814 var.prepend(
"http://");
816 QUrl url = QUrl(var, QUrl::TolerantMode);
817 QString host = url.host();
818 int port = url.port();
831 LOG(VB_NETWORK, LOG_INFO,
LOC +
832 QString(
"assuming port %1 on host %2") .arg(port).arg(host));
835 else if (!
ping(host, 1s))
837 LOG(VB_GENERAL, LOG_ERR,
LOC +
838 QString(
"cannot locate host %1").arg(host) +
839 "\n\t\t\tPlease check HTTP_PROXY environment variable!");
841 else if (!
telnet(host,port))
843 LOG(VB_GENERAL, LOG_ERR,
LOC +
844 QString(
"%1:%2 - cannot connect!").arg(host).arg(port) +
845 "\n\t\t\tPlease check HTTP_PROXY environment variable!");
849 LOG(VB_NETWORK, LOG_DEBUG,
LOC + QString(
"using http://%1:%2@%3:%4")
850 .arg(url.userName()).arg(url.password())
851 .arg(host).arg(port));
854 QNetworkProxy(QNetworkProxy::HttpCachingProxy,
855 host, port, url.userName(), url.password());
856 QNetworkProxy::setApplicationProxy(
p);
860 LOG(VB_NETWORK, LOG_DEBUG,
LOC +
"no HTTP_PROXY environment var.");
865 QNetworkProxyQuery query(QUrl(
"http://www.mythtv.org"));
867 proxies = QNetworkProxyFactory::systemProxyForQuery(query);
869 for (
const auto&
p : std::as_const(
proxies))
871 QString host =
p.hostName();
874 if (
p.type() == QNetworkProxy::NoProxy)
879 LOG(VB_NETWORK, LOG_ERR,
LOC +
880 "failed to contact proxy host " + host);
884 LOG(VB_NETWORK, LOG_INFO,
LOC + QString(
"using proxy host %1:%2")
885 .arg(host).arg(port));
886 QNetworkProxy::setApplicationProxy(
p);
892 if (!
p.user().isEmpty())
894 url =
"http://%1:%2@%3:%4",
895 url = url.arg(
p.user(),
p.password());
899 url =
"http://%1:%2";
902 url = url.arg(
p.hostName()).arg(
p.port());
903 setenv(
"HTTP_PROXY", url.toLatin1(), 1);
904 setenv(
"http_proxy", url.toLatin1(), 0);
909 LOG(VB_NETWORK, LOG_ERR,
LOC +
"failed to find a network proxy");