MythTV  master
mythmiscutil.cpp
Go to the documentation of this file.
1 
2 #include "mythmiscutil.h"
3 
4 // C++ headers
5 #include <array>
6 #include <cerrno>
7 #include <cstdlib>
8 #include <ctime>
9 #include <iostream>
10 
11 // POSIX
12 #include <unistd.h>
13 #include <fcntl.h>
14 #include <sched.h>
15 
16 // System specific C headers
17 #include "compat.h"
18 
19 #ifdef linux
20 #include <sys/vfs.h>
21 #include <sys/sysinfo.h>
22 #include <sys/stat.h> // for umask, chmod
23 #endif
24 
25 #if CONFIG_DARWIN
26 #include <mach/mach.h>
27 #endif
28 
29 #ifdef BSD
30 #include <sys/mount.h> // for struct statfs
31 #include <sys/sysctl.h>
32 #include <sys/stat.h> // for umask, chmod
33 #endif
34 
35 // Qt headers
36 #include <QReadWriteLock>
37 #include <QNetworkProxy>
38 #include <QStringList>
39 #include <QDataStream>
40 #include <QUdpSocket>
41 #include <QFileInfo>
42 #include <QFile>
43 #include <QDir>
44 #include <QUrl>
45 #include <QHostAddress>
46 #include <QDataStream>
47 #include <QRegularExpression>
48 #include <QRegularExpressionMatchIterator>
49 
50 // Myth headers
51 #include "mythcorecontext.h"
52 #include "exitcodes.h"
53 #include "mythlogging.h"
54 #include "mythsocket.h"
55 #include "mythcoreutil.h"
56 #include "mythsystemlegacy.h"
57 
58 #include "mythconfig.h" // for CONFIG_DARWIN
59 
64 bool getUptime(time_t &uptime)
65 {
66 #ifdef __linux__
67  struct sysinfo sinfo {};
68  if (sysinfo(&sinfo) == -1)
69  {
70  LOG(VB_GENERAL, LOG_ERR, "sysinfo() error");
71  return false;
72  }
73  uptime = sinfo.uptime;
74 
75 #elif defined(__FreeBSD__) || CONFIG_DARWIN
76 
77  std::array<int,2> mib { CTL_KERN, KERN_BOOTTIME };
78  struct timeval bootTime;
79  size_t len;
80 
81  // Uptime is calculated. Get this machine's boot time
82  // and subtract it from the current machine time
83  len = sizeof(bootTime);
84  if (sysctl(mib.data(), 2, &bootTime, &len, nullptr, 0) == -1)
85  {
86  LOG(VB_GENERAL, LOG_ERR, "sysctl() error");
87  return false;
88  }
89  uptime = time(nullptr) - bootTime.tv_sec;
90 #elif defined(_WIN32)
91  uptime = ::GetTickCount() / 1000;
92 #else
93  // Hmmm. Not Linux, not FreeBSD or Darwin. What else is there :-)
94  LOG(VB_GENERAL, LOG_NOTICE, "Unknown platform. How do I get the uptime?");
95  return false;
96 #endif
97 
98  return true;
99 }
100 
107 bool getMemStats(int &totalMB, int &freeMB, int &totalVM, int &freeVM)
108 {
109 #ifdef __linux__
110  const size_t MB = (1024*1024);
111  struct sysinfo sinfo {};
112  if (sysinfo(&sinfo) == -1)
113  {
114  LOG(VB_GENERAL, LOG_ERR,
115  "getMemStats(): Error, sysinfo() call failed.");
116  return false;
117  }
118 
119  totalMB = (int)((sinfo.totalram * sinfo.mem_unit)/MB);
120  freeMB = (int)((sinfo.freeram * sinfo.mem_unit)/MB);
121  totalVM = (int)((sinfo.totalswap * sinfo.mem_unit)/MB);
122  freeVM = (int)((sinfo.freeswap * sinfo.mem_unit)/MB);
123  return true;
124 #elif CONFIG_DARWIN
125  mach_port_t mp;
126  mach_msg_type_number_t count;
127  vm_size_t pageSize;
128  vm_statistics_data_t s;
129 
130  mp = mach_host_self();
131 
132  // VM page size
133  if (host_page_size(mp, &pageSize) != KERN_SUCCESS)
134  pageSize = 4096; // If we can't look it up, 4K is a good guess
135 
136  count = HOST_VM_INFO_COUNT;
137  if (host_statistics(mp, HOST_VM_INFO,
138  (host_info_t)&s, &count) != KERN_SUCCESS)
139  {
140  LOG(VB_GENERAL, LOG_ERR, "getMemStats(): Error, "
141  "failed to get virtual memory statistics.");
142  return false;
143  }
144 
145  pageSize >>= 10; // This gives usages in KB
146  totalMB = (s.active_count + s.inactive_count +
147  s.wire_count + s.free_count) * pageSize / 1024;
148  freeMB = s.free_count * pageSize / 1024;
149 
150 
151  // This is a real hack. I have not found a way to ask the kernel how much
152  // swap it is using, and the dynamic_pager daemon doesn't even seem to be
153  // able to report what filesystem it is using for the swapfiles. So, we do:
154  int64_t total, used, free;
155  free = getDiskSpace("/private/var/vm", total, used);
156  totalVM = (int)(total >> 10);
157  freeVM = (int)(free >> 10);
158  return true;
159 #else
160  Q_UNUSED(totalMB);
161  Q_UNUSED(freeMB);
162  Q_UNUSED(totalVM);
163  Q_UNUSED(freeVM);
164  return false;
165 #endif
166 }
167 
175 {
176 #if !defined(_WIN32) && !defined(Q_OS_ANDROID)
177  loadArray loads;
178  if (getloadavg(loads.data(), loads.size()) != -1)
179  return loads;
180 #endif
181  return {-1, -1, -1};
182 }
183 
191 bool hasUtf8(const char *str)
192 {
193  const uchar *c = (uchar *) str;
194 
195  while (*c++)
196  {
197  // ASCII is < 0x80.
198  // 0xC2..0xF4 is probably UTF-8.
199  // Anything else probably ISO-8859-1 (Latin-1, Unicode)
200 
201  if (*c > 0xC1 && *c < 0xF5)
202  {
203  int bytesToCheck = 2; // Assume 0xC2-0xDF (2 byte sequence)
204 
205  if (*c > 0xDF) // Maybe 0xE0-0xEF (3 byte sequence)
206  ++bytesToCheck;
207  if (*c > 0xEF) // Matches 0xF0-0xF4 (4 byte sequence)
208  ++bytesToCheck;
209 
210  while (bytesToCheck--)
211  {
212  ++c;
213 
214  if (! *c) // String ended in middle
215  return false; // Not valid UTF-8
216 
217  if (*c < 0x80 || *c > 0xBF) // Bad UTF-8 sequence
218  break; // Keep checking in outer loop
219  }
220 
221  if (!bytesToCheck) // Have checked all the bytes in the sequence
222  return true; // Hooray! We found valid UTF-8!
223  }
224  }
225 
226  return false;
227 }
228 
243 bool ping(const QString &host, int timeout)
244 {
245 #ifdef _WIN32
246  QString cmd = QString("%systemroot%\\system32\\ping.exe -w %1 -n 1 %2>NUL")
247  .arg(timeout*1000).arg(host);
248 
251 #else
252  QString addrstr =
254  QHostAddress addr = QHostAddress(addrstr);
255 #if defined(__FreeBSD__) || CONFIG_DARWIN
256  QString timeoutparam("-t");
257 #else
258  // Linux, NetBSD, OpenBSD
259  QString timeoutparam("-w");
260 #endif
261  QString pingcmd =
262  addr.protocol() == QAbstractSocket::IPv6Protocol ? "ping6" : "ping";
263  QString cmd = QString("%1 %2 %3 -c 1 %4 >/dev/null 2>&1")
264  .arg(pingcmd).arg(timeoutparam).arg(timeout).arg(host);
265 
268 #endif
269 }
270 
274 bool telnet(const QString &host, int port)
275 {
276  auto *s = new MythSocket();
277 
278  bool connected = s->ConnectToHost(host, port);
279  s->DecrRef();
280 
281  return connected;
282 }
283 
305 long long copy(QFile &dst, QFile &src, uint block_size)
306 {
307  uint buflen = (block_size < 1024) ? (16 * 1024) : block_size;
308  char *buf = new char[buflen];
309  bool odst = false;
310  bool osrc = false;
311 
312  if (!buf)
313  return -1LL;
314 
315  if (!dst.isWritable() && !dst.isOpen())
316  {
317  odst = dst.open(QIODevice::Unbuffered |
318  QIODevice::WriteOnly |
319  QIODevice::Truncate);
320  }
321 
322  if (!src.isReadable() && !src.isOpen())
323  osrc = src.open(QIODevice::Unbuffered|QIODevice::ReadOnly);
324 
325  bool ok = dst.isWritable() && src.isReadable();
326  long long total_bytes = 0LL;
327  while (ok)
328  {
329  long long off = 0;
330  long long rlen = src.read(buf, buflen);
331  if (rlen<0)
332  {
333  LOG(VB_GENERAL, LOG_ERR, "read error");
334  ok = false;
335  break;
336  }
337  if (rlen==0)
338  break;
339 
340  total_bytes += rlen;
341 
342  while ((rlen-off>0) && ok)
343  {
344  long long wlen = dst.write(buf + off, rlen - off);
345  if (wlen>=0)
346  off+= wlen;
347  if (wlen<0)
348  {
349  LOG(VB_GENERAL, LOG_ERR, "write error");
350  ok = false;
351  }
352  }
353  }
354  delete[] buf;
355 
356  if (odst)
357  dst.close();
358 
359  if (osrc)
360  src.close();
361 
362  return (ok) ? total_bytes : -1LL;
363 }
364 
365 QString createTempFile(QString name_template, bool dir)
366 {
367  int ret = -1;
368 
369 #ifdef _WIN32
370  char temppath[MAX_PATH] = ".";
371  char tempfilename[MAX_PATH] = "";
372  // if GetTempPath fails, use current dir
373  GetTempPathA(MAX_PATH, temppath);
374  if (GetTempFileNameA(temppath, "mth", 0, tempfilename))
375  {
376  if (dir)
377  {
378  // GetTempFileNameA creates the file, so delete it before mkdir
379  unlink(tempfilename);
380  ret = mkdir(tempfilename);
381  }
382  else
383  ret = open(tempfilename, O_CREAT | O_RDWR, S_IREAD | S_IWRITE);
384  }
385  QString tmpFileName(tempfilename);
386 #else
387  QByteArray safe_name_template = name_template.toLatin1();
388  const char *tmp = safe_name_template.constData();
389  char *ctemplate = strdup(tmp);
390 
391  if (dir)
392  {
393  ret = (mkdtemp(ctemplate)) ? 0 : -1;
394  }
395  else
396  {
397  mode_t cur_umask = umask(S_IRWXO | S_IRWXG);
398  ret = mkstemp(ctemplate);
399  umask(cur_umask);
400  }
401 
402  QString tmpFileName(ctemplate);
403  free(ctemplate);
404 #endif
405 
406  if (ret == -1)
407  {
408  LOG(VB_GENERAL, LOG_ERR, QString("createTempFile(%1), Error ")
409  .arg(name_template) + ENO);
410  return name_template;
411  }
412 
413  if (!dir && (ret >= 0))
414  close(ret);
415 
416  return tmpFileName;
417 }
418 
437 bool makeFileAccessible(const QString& filename)
438 {
439  QByteArray fname = filename.toLatin1();
440  int ret = chmod(fname.constData(), 0666);
441  if (ret == -1)
442  {
443  LOG(VB_GENERAL, LOG_ERR, QString("Unable to change permissions on file. (%1)").arg(filename));
444  return false;
445  }
446  return true;
447 }
448 
452 QString getResponse(const QString &query, const QString &def)
453 {
454  QByteArray tmp = query.toLocal8Bit();
455  std::cout << tmp.constData();
456 
457  tmp = def.toLocal8Bit();
458  if (!def.isEmpty())
459  std::cout << " [" << tmp.constData() << "] ";
460  else
461  std::cout << " ";
462 
463  if (!isatty(fileno(stdin)) || !isatty(fileno(stdout)))
464  {
465  std::cout << std::endl << "[console is not interactive, using default '"
466  << tmp.constData() << "']" << std::endl;
467  return def;
468  }
469 
470  QTextStream stream(stdin);
471  QString qresponse = stream.readLine();
472 
473  if (qresponse.isEmpty())
474  qresponse = def;
475 
476  return qresponse;
477 }
478 
482 int intResponse(const QString &query, int def)
483 {
484  QString str_resp = getResponse(query, QString("%1").arg(def));
485  if (str_resp.isEmpty())
486  return def;
487  bool ok = false;
488  int resp = str_resp.toInt(&ok);
489  return (ok ? resp : def);
490 }
491 
492 
493 QString getSymlinkTarget(const QString &start_file,
494  QStringList *intermediaries,
495  unsigned maxLinks)
496 {
497 #if 0
498  LOG(VB_GENERAL, LOG_DEBUG,
499  QString("getSymlinkTarget('%1', 0x%2, %3)")
500  .arg(start_file).arg((uint64_t)intermediaries,0,16)
501  .arg(maxLinks));
502 #endif
503 
504  QString link;
505  QString cur_file = start_file;
506  QFileInfo fi(cur_file);
507 
508  if (intermediaries)
509  {
510  intermediaries->clear();
511  intermediaries->push_back(start_file);
512  }
513 
514  for (uint i = 0; (i <= maxLinks) && fi.isSymLink() &&
515  !(link = fi.symLinkTarget()).isEmpty(); i++)
516  {
517  cur_file = (link[0] == '/') ?
518  link : // absolute link
519  fi.absoluteDir().absolutePath() + "/" + link; // relative link
520 
521  if (intermediaries && !intermediaries->contains(cur_file))
522  intermediaries->push_back(cur_file);
523 
524  fi = QFileInfo(cur_file);
525  }
526 
527 #if 0
528  if (intermediaries)
529  {
530  for (uint i = 0; i < intermediaries->size(); i++)
531  {
532  LOG(VB_GENERAL, LOG_DEBUG, QString(" inter%1: %2")
533  .arg(i).arg((*intermediaries)[i]));
534  }
535  }
536 
537  LOG(VB_GENERAL, LOG_DEBUG,
538  QString("getSymlinkTarget() -> '%1'")
539  .arg((!fi.isSymLink()) ? cur_file : QString()));
540 #endif
541 
542  return (!fi.isSymLink()) ? cur_file : QString();
543 }
544 
545 bool IsMACAddress(const QString& MAC)
546 {
547  QStringList tokens = MAC.split(':');
548  if (tokens.size() != 6)
549  {
550  LOG(VB_NETWORK, LOG_ERR,
551  QString("IsMACAddress(%1) = false, doesn't have 6 parts").arg(MAC));
552  return false;
553  }
554 
555  for (int y = 0; y < 6; y++)
556  {
557  if (tokens[y].isEmpty())
558  {
559  LOG(VB_NETWORK, LOG_ERR,
560  QString("IsMACAddress(%1) = false, part #%2 is empty.")
561  .arg(MAC).arg(y));
562  return false;
563  }
564 
565  bool ok = false;
566  int value = tokens[y].toInt(&ok, 16);
567  if (!ok)
568  {
569  LOG(VB_NETWORK, LOG_ERR,
570  QString("IsMACAddress(%1) = false, unable to "
571  "convert part '%2' to integer.")
572  .arg(MAC).arg(tokens[y]));
573  return false;
574  }
575 
576  if (value > 255)
577  {
578  LOG(VB_NETWORK, LOG_ERR,
579  QString("IsMACAddress(%1) = false, part #%2 "
580  "evaluates to %3 which is higher than 255.")
581  .arg(MAC).arg(y).arg(value));
582  return false;
583  }
584  }
585 
586  LOG(VB_NETWORK, LOG_DEBUG, QString("IsMACAddress(%1) = true").arg(MAC));
587  return true;
588 }
589 
590 QString FileHash(const QString& filename)
591 {
592  QFile file(filename);
593  QFileInfo fileinfo(file);
594  qint64 initialsize = fileinfo.size();
595  quint64 hash = 0;
596 
597  if (initialsize == 0)
598  return QString("NULL");
599 
600  if (file.open(QIODevice::ReadOnly))
601  hash = initialsize;
602  else
603  {
604  LOG(VB_GENERAL, LOG_ERR,
605  "Error: Unable to open selected file, missing read permissions?");
606  return QString("NULL");
607  }
608 
609  file.seek(0);
610  QDataStream stream(&file);
611  stream.setByteOrder(QDataStream::LittleEndian);
612  for (quint64 tmp = 0, i = 0; i < 65536/sizeof(tmp); i++)
613  {
614  stream >> tmp;
615  hash += tmp;
616  }
617 
618  file.seek(initialsize - 65536);
619  for (quint64 tmp = 0, i = 0; i < 65536/sizeof(tmp); i++)
620  {
621  stream >> tmp;
622  hash += tmp;
623  }
624 
625  file.close();
626 
627  QString output = QString("%1").arg(hash, 0, 16);
628  return output;
629 }
630 
631 bool WakeOnLAN(const QString& MAC)
632 {
633  std::vector<char> msg(6, static_cast<char>(0xFF));
634  std::array<char,6> macaddr {};
635  QStringList tokens = MAC.split(':');
636 
637  if (tokens.size() != 6)
638  {
639  LOG(VB_GENERAL, LOG_ERR,
640  QString( "WakeOnLan(%1): Incorrect MAC length").arg(MAC));
641  return false;
642  }
643 
644  for (int y = 0; y < 6; y++)
645  {
646  bool ok = false;
647  macaddr[y] = tokens[y].toInt(&ok, 16);
648 
649  if (!ok)
650  {
651  LOG(VB_GENERAL, LOG_ERR,
652  QString( "WakeOnLan(%1): Invalid MAC address").arg(MAC));
653  return false;
654  }
655  }
656 
657  msg.reserve(1024);
658  for (int x = 0; x < 16; x++)
659  msg.insert(msg.end(), macaddr.cbegin(), macaddr.cend());
660 
661  LOG(VB_NETWORK, LOG_INFO,
662  QString("WakeOnLan(): Sending WOL packet to %1").arg(MAC));
663 
664  QUdpSocket udp_socket;
665  qlonglong msglen = msg.size();
666  return udp_socket.writeDatagram(
667  msg.data(), msglen, QHostAddress::Broadcast, 32767) == msglen;
668 }
669 
670 // Wake up either by command or by MAC address
671 // return true = success
672 bool MythWakeup(const QString &wakeUpCommand, uint flags, uint timeout)
673 {
674  if (!IsMACAddress(wakeUpCommand))
675  return myth_system(wakeUpCommand, flags, timeout) == 0U;
676 
677  return WakeOnLAN(wakeUpCommand);
678 }
679 
681 {
682 #ifdef _WIN32
683  return false;
684 #else
685 
686 #if CONFIG_DARWIN || (__FreeBSD__) || defined(__OpenBSD__)
687  const char *command = "ps -ax | grep -i pulseaudio | grep -v grep > /dev/null";
688 #else
689  const char *command = "ps ch -C pulseaudio -o pid > /dev/null";
690 #endif
691  // Do NOT use kMSProcessEvents here, it will cause deadlock
692  uint res = myth_system(command, kMSDontBlockInputDevs |
694  return (res == GENERIC_EXIT_OK);
695 #endif // _WIN32
696 }
697 
698 bool myth_nice(int val)
699 {
700  errno = 0;
701  int ret = nice(val);
702 
703  if ((-1 == ret) && (0 != errno) && (val >= 0))
704  {
705  LOG(VB_GENERAL, LOG_ERR, "Failed to nice process" + ENO);
706  return false;
707  }
708 
709  return true;
710 }
711 
712 void myth_yield(void)
713 {
714 #ifdef _POSIX_PRIORITY_SCHEDULING
715  if (sched_yield()<0)
716  usleep(5000);
717 #else
718  usleep(5000);
719 #endif
720 }
721 
739 #if defined(__linux__) && ( defined(__i386__) || defined(__ppc__) || \
740  defined(__x86_64__) || defined(__ia64__) )
741 
742 #include <cstdio>
743 #include <cstdlib>
744 #include <cerrno>
745 #include <getopt.h>
746 #include <unistd.h>
747 #include <sys/ptrace.h>
748 #include <asm/unistd.h>
749 
750 #if defined(__i386__)
751 # define NR_ioprio_set 289
752 # define NR_ioprio_get 290
753 #elif defined(__ppc__)
754 # define NR_ioprio_set 273
755 # define NR_ioprio_get 274
756 #elif defined(__x86_64__)
757 # define NR_ioprio_set 251
758 # define NR_ioprio_get 252
759 #elif defined(__ia64__)
760 # define NR_ioprio_set 1274
761 # define NR_ioprio_get 1275
762 #endif
763 
764 #define IOPRIO_BITS (16)
765 #define IOPRIO_CLASS_SHIFT (13)
766 #define IOPRIO_PRIO_MASK ((1UL << IOPRIO_CLASS_SHIFT) - 1)
767 #define IOPRIO_PRIO_CLASS(mask) ((mask) >> IOPRIO_CLASS_SHIFT)
768 #define IOPRIO_PRIO_DATA(mask) ((mask) & IOPRIO_PRIO_MASK)
769 #define IOPRIO_PRIO_VALUE(class, data) (((class) << IOPRIO_CLASS_SHIFT) | (data))
770 
771 enum { IOPRIO_CLASS_NONE,IOPRIO_CLASS_RT,IOPRIO_CLASS_BE,IOPRIO_CLASS_IDLE, };
772 enum { IOPRIO_WHO_PROCESS = 1, IOPRIO_WHO_PGRP, IOPRIO_WHO_USER, };
773 
774 bool myth_ioprio(int val)
775 {
776  int new_ioclass = (val < 0) ? IOPRIO_CLASS_RT :
777  (val > 7) ? IOPRIO_CLASS_IDLE : IOPRIO_CLASS_BE;
778  int new_iodata = (new_ioclass == IOPRIO_CLASS_BE) ? val : 0;
779  int new_ioprio = IOPRIO_PRIO_VALUE(new_ioclass, new_iodata);
780 
781  int pid = getpid();
782  int old_ioprio = syscall(NR_ioprio_get, IOPRIO_WHO_PROCESS, pid);
783  if (old_ioprio == new_ioprio)
784  return true;
785 
786  int ret = syscall(NR_ioprio_set, IOPRIO_WHO_PROCESS, pid, new_ioprio);
787 
788  if (-1 == ret && EPERM == errno && IOPRIO_CLASS_BE != new_ioclass)
789  {
790  new_iodata = (new_ioclass == IOPRIO_CLASS_RT) ? 0 : 7;
791  new_ioprio = IOPRIO_PRIO_VALUE(IOPRIO_CLASS_BE, new_iodata);
792  ret = syscall(NR_ioprio_set, IOPRIO_WHO_PROCESS, pid, new_ioprio);
793  }
794 
795  return 0 == ret;
796 }
797 
798 #else
799 
800 bool myth_ioprio(int) { return true; }
801 
802 #endif
803 
804 bool MythRemoveDirectory(QDir &aDir)
805 {
806  if (!aDir.exists())//QDir::NoDotAndDotDot
807  return false;
808 
809  QFileInfoList entries = aDir.entryInfoList(QDir::NoDotAndDotDot |
810  QDir::Dirs | QDir::Files);
811  int count = entries.size();
812  bool has_err = false;
813 
814  for (int idx = 0; idx < count && !has_err; idx++)
815  {
816  QFileInfo entryInfo = entries[idx];
817  QString path = entryInfo.absoluteFilePath();
818  if (entryInfo.isDir())
819  {
820  QDir dir(path);
821  has_err = MythRemoveDirectory(dir);
822  }
823  else
824  {
825  QFile file(path);
826  if (!file.remove())
827  has_err = true;
828  }
829  }
830 
831  if (!has_err && !aDir.rmdir(aDir.absolutePath()))
832  has_err = true;
833 
834  return(has_err);
835 }
836 
848 void setHttpProxy(void)
849 {
850  QString LOC = "setHttpProxy() - ";
851 
852  // Set http proxy for the application if specified in environment variable
853  QString var(getenv("http_proxy"));
854  if (var.isEmpty())
855  var = getenv("HTTP_PROXY"); // Sadly, some OS envs are case sensitive
856  if (!var.isEmpty())
857  {
858  if (!var.startsWith("http://")) // i.e. just a host name
859  var.prepend("http://");
860 
861  QUrl url = QUrl(var, QUrl::TolerantMode);
862  QString host = url.host();
863  int port = url.port();
864 
865  if (port == -1) // Parsing error
866  {
867  port = 0; // The default when creating a QNetworkProxy
868 
869  if (telnet(host, 1080)) // Socks?
870  port = 1080;
871  if (telnet(host, 3128)) // Squid
872  port = 3128;
873  if (telnet(host, 8080)) // MS ISA
874  port = 8080;
875 
876  LOG(VB_NETWORK, LOG_INFO, LOC +
877  QString("assuming port %1 on host %2") .arg(port).arg(host));
878  url.setPort(port);
879  }
880  else if (!ping(host, 1))
881  {
882  LOG(VB_GENERAL, LOG_ERR, LOC +
883  QString("cannot locate host %1").arg(host) +
884  "\n\t\t\tPlease check HTTP_PROXY environment variable!");
885  }
886  else if (!telnet(host,port))
887  {
888  LOG(VB_GENERAL, LOG_ERR, LOC +
889  QString("%1:%2 - cannot connect!").arg(host).arg(port) +
890  "\n\t\t\tPlease check HTTP_PROXY environment variable!");
891  }
892 
893 #if 0
894  LOG(VB_NETWORK, LOG_DEBUG, LOC + QString("using http://%1:%2@%3:%4")
895  .arg(url.userName()).arg(url.password())
896  .arg(host).arg(port));
897 #endif
898  QNetworkProxy p =
899  QNetworkProxy(QNetworkProxy::HttpCachingProxy,
900  host, port, url.userName(), url.password());
901  QNetworkProxy::setApplicationProxy(p);
902  return;
903  }
904 
905  LOG(VB_NETWORK, LOG_DEBUG, LOC + "no HTTP_PROXY environment var.");
906 
907  // Use Qt to look for user proxy settings stored by the OS or browser:
908 
909  QList<QNetworkProxy> proxies;
910  QNetworkProxyQuery query(QUrl("http://www.mythtv.org"));
911 
912  proxies = QNetworkProxyFactory::systemProxyForQuery(query);
913 
914  for (const auto& p : qAsConst(proxies))
915  {
916  QString host = p.hostName();
917  int port = p.port();
918 
919  if (p.type() == QNetworkProxy::NoProxy)
920  continue;
921 
922  if (!telnet(host, port))
923  {
924  LOG(VB_NETWORK, LOG_ERR, LOC +
925  "failed to contact proxy host " + host);
926  continue;
927  }
928 
929  LOG(VB_NETWORK, LOG_INFO, LOC + QString("using proxy host %1:%2")
930  .arg(host).arg(port));
931  QNetworkProxy::setApplicationProxy(p);
932 
933  // Allow sub-commands to use this proxy
934  // via myth_system(command), by setting HTTP_PROXY
935  QString url;
936 
937  if (!p.user().isEmpty())
938  {
939  url = "http://%1:%2@%3:%4",
940  url = url.arg(p.user()).arg(p.password());
941  }
942  else
943  {
944  url = "http://%1:%2";
945  }
946 
947  url = url.arg(p.hostName()).arg(p.port());
948  setenv("HTTP_PROXY", url.toLatin1(), 1);
949  setenv("http_proxy", url.toLatin1(), 0);
950 
951  return;
952  }
953 
954  LOG(VB_NETWORK, LOG_ERR, LOC + "failed to find a network proxy");
955 }
956 
957 void wrapList(QStringList &list, int width)
958 {
959  // if this is triggered, something has gone seriously wrong
960  // the result won't really be usable, but at least it won't crash
961  width = std::max(width, 5);
962 
963  for (int i = 0; i < list.size(); i++)
964  {
965  QString string = list.at(i);
966 
967  if( string.size() <= width )
968  continue;
969 
970  QString left = string.left(width);
971  bool inserted = false;
972 
973  while( !inserted && !left.endsWith(" " ))
974  {
975  if( string.mid(left.size(), 1) == " " )
976  {
977  list.replace(i, left);
978  list.insert(i+1, string.mid(left.size()).trimmed());
979  inserted = true;
980  }
981  else
982  {
983  left.chop(1);
984  if( !left.contains(" ") )
985  {
986  // Line is too long, just hyphenate it
987  list.replace(i, left + "-");
988  list.insert(i+1, string.mid(left.size()));
989  inserted = true;
990  }
991  }
992  }
993 
994  if( !inserted )
995  {
996  left.chop(1);
997  list.replace(i, left);
998  list.insert(i+1, string.mid(left.size()).trimmed());
999  }
1000  }
1001 }
1002 
1003 QString xml_indent(uint level)
1004 {
1005  static QReadWriteLock s_rwLock;
1006  static QMap<uint,QString> s_cache;
1007 
1008  s_rwLock.lockForRead();
1009  QMap<uint,QString>::const_iterator it = s_cache.constFind(level);
1010  if (it != s_cache.constEnd())
1011  {
1012  QString tmp = *it;
1013  s_rwLock.unlock();
1014  return tmp;
1015  }
1016  s_rwLock.unlock();
1017 
1018  QString ret = "";
1019  for (uint i = 0; i < level; i++)
1020  ret += " ";
1021 
1022  s_rwLock.lockForWrite();
1023  s_cache[level] = ret;
1024  s_rwLock.unlock();
1025 
1026  return ret;
1027 }
1028 
1029 int naturalCompare(const QString &_a, const QString &_b, Qt::CaseSensitivity caseSensitivity)
1030 {
1031  // This method chops the input a and b into pieces of
1032  // digits and non-digits (a1.05 becomes a | 1 | . | 05)
1033  // and compares these pieces of a and b to each other
1034  // (first with first, second with second, ...).
1035  //
1036  // This is based on the natural sort order code code by Martin Pool
1037  // http://sourcefrog.net/projects/natsort/
1038  // Martin Pool agreed to license this under LGPL or GPL.
1039 
1040  // FIXME: Using toLower() to implement case insensitive comparison is
1041  // sub-optimal, but is needed because we compare strings with
1042  // localeAwareCompare(), which does not know about case sensitivity.
1043  // A task has been filled for this in Qt Task Tracker with ID 205990.
1044  // http://trolltech.com/developer/task-tracker/index_html?method=entry&id=205990
1045 
1046  QString a;
1047  QString b;
1048 
1049  if (caseSensitivity == Qt::CaseSensitive)
1050  {
1051  a = _a;
1052  b = _b;
1053  }
1054  else
1055  {
1056  a = _a.toLower();
1057  b = _b.toLower();
1058  }
1059 
1060  const QChar* currA = a.unicode(); // iterator over a
1061  const QChar* currB = b.unicode(); // iterator over b
1062 
1063  if (currA == currB)
1064  {
1065  return 0;
1066  }
1067 
1068  while (!currA->isNull() && !currB->isNull())
1069  {
1070  const QChar* begSeqA = currA; // beginning of a new character sequence of a
1071  const QChar* begSeqB = currB;
1072 
1073  if (currA->unicode() == QChar::ObjectReplacementCharacter)
1074  {
1075  return 1;
1076  }
1077 
1078  if (currB->unicode() == QChar::ObjectReplacementCharacter)
1079  {
1080  return -1;
1081  }
1082 
1083  if (currA->unicode() == QChar::ReplacementCharacter)
1084  {
1085  return 1;
1086  }
1087 
1088  if (currB->unicode() == QChar::ReplacementCharacter)
1089  {
1090  return -1;
1091  }
1092 
1093  // find sequence of characters ending at the first non-character
1094  while (!currA->isNull() && !currA->isDigit() && !currA->isPunct() &&
1095  !currA->isSpace())
1096  {
1097  ++currA;
1098  }
1099 
1100  while (!currB->isNull() && !currB->isDigit() && !currB->isPunct() &&
1101  !currB->isSpace())
1102  {
1103  ++currB;
1104  }
1105 
1106  // compare these sequences
1107  const QStringRef& subA(a.midRef(begSeqA - a.unicode(), currA - begSeqA));
1108  const QStringRef& subB(b.midRef(begSeqB - b.unicode(), currB - begSeqB));
1109  const int cmp = QStringRef::localeAwareCompare(subA, subB);
1110 
1111  if (cmp != 0)
1112  {
1113  return cmp < 0 ? -1 : +1;
1114  }
1115 
1116  if (currA->isNull() || currB->isNull())
1117  {
1118  break;
1119  }
1120 
1121  // find sequence of characters ending at the first non-character
1122  while ((currA->isPunct() || currA->isSpace()) &&
1123  (currB->isPunct() || currB->isSpace()))
1124  {
1125  if (*currA != *currB)
1126  {
1127  return (*currA < *currB) ? -1 : +1;
1128  }
1129  ++currA;
1130  ++currB;
1131  if (currA->isNull() || currB->isNull())
1132  {
1133  break;
1134  }
1135  }
1136 
1137  // now some digits follow...
1138  if ((*currA == QLatin1Char('0')) || (*currB == QLatin1Char('0')))
1139  {
1140  // one digit-sequence starts with 0 -> assume we are in a fraction part
1141  // do left aligned comparison (numbers are considered left aligned)
1142  while (true)
1143  {
1144  if (!currA->isDigit() && !currB->isDigit())
1145  {
1146  break;
1147  }
1148  if (!currA->isDigit())
1149  {
1150  return +1;
1151  }
1152  if (!currB->isDigit())
1153  {
1154  return -1;
1155  }
1156  if (*currA < *currB)
1157  {
1158  return -1;
1159  }
1160  if (*currA > *currB)
1161  {
1162  return + 1;
1163  }
1164  ++currA;
1165  ++currB;
1166  }
1167  }
1168  else
1169  {
1170  // No digit-sequence starts with 0 -> assume we are looking at some integer
1171  // do right aligned comparison.
1172  //
1173  // The longest run of digits wins. That aside, the greatest
1174  // value wins, but we can't know that it will until we've scanned
1175  // both numbers to know that they have the same magnitude.
1176 
1177  bool isFirstRun = true;
1178  int weight = 0;
1179 
1180  while (true)
1181  {
1182  if (!currA->isDigit() && !currB->isDigit())
1183  {
1184  if (weight != 0)
1185  {
1186  return weight;
1187  }
1188  break;
1189  }
1190  if (!currA->isDigit())
1191  {
1192  if (isFirstRun)
1193  {
1194  return *currA < *currB ? -1 : +1;
1195  }
1196  return -1;
1197  }
1198  if (!currB->isDigit())
1199  {
1200  if (isFirstRun)
1201  {
1202  return *currA < *currB ? -1 : +1;
1203  }
1204  return +1;
1205  }
1206  if ((*currA < *currB) && (weight == 0))
1207  {
1208  weight = -1;
1209  }
1210  else if ((*currA > *currB) && (weight == 0))
1211  {
1212  weight = + 1;
1213  }
1214  ++currA;
1215  ++currB;
1216  isFirstRun = false;
1217  }
1218  }
1219  }
1220 
1221  if (currA->isNull() && currB->isNull())
1222  {
1223  return 0;
1224  }
1225 
1226  return currA->isNull() ? -1 : + 1;
1227 }
1228 
1229 QString MythFormatTimeMs(int msecs, const QString& fmt)
1230 {
1231  return QTime::fromMSecsSinceStartOfDay(msecs).toString(fmt);
1232 }
1233 
1234 QString MythFormatTime(int secs, const QString& fmt)
1235 {
1236  return QTime::fromMSecsSinceStartOfDay(secs*1000).toString(fmt);
1237 }
1238 
1239 /*
1240  * States for the command line parser.
1241  */
1242 enum states {
1243  START, // No current token.
1244  INTEXT, // Collecting token text.
1245  INSQUOTE, // Collecting token, inside single quotes.
1246  INDQUOTE, // Collecting token, inside double quotes.
1247  ESCTEXT, // Saw backslash. Returns to generic text.
1248  ESCSQUOTE, // Saw backslash. Returns to single quotes.
1249  ESCDQUOTE, // Saw backslash. Returns to double quotes.
1250 };
1251 
1252 /*
1253  * Parse a string into separate tokens. This function understands
1254  * quoting and the escape character.
1255  */
1256 QStringList MythSplitCommandString(const QString &line)
1257 {
1258  QStringList fields;
1259  states state = START;
1260  int tokenStart = -1;
1261 
1262  for (int i = 0; i < line.size(); i++)
1263  {
1264  const QChar c = line.at(i);
1265 
1266  switch (state) {
1267  case START:
1268  tokenStart = i;
1269  if (c.isSpace()) break;
1270  if (c == '\'') state = INSQUOTE;
1271  else if (c == '\"') state = INDQUOTE;
1272  else if (c == '\\') state = ESCTEXT;
1273  else state = INTEXT;
1274  break;
1275  case INTEXT:
1276  if (c.isSpace()) {
1277  fields += line.mid(tokenStart, i - tokenStart);
1278  state = START;
1279  break;
1280  }
1281  else if (c == '\'') state = INSQUOTE;
1282  else if (c == '\"') state = INDQUOTE;
1283  else if (c == '\\') state = ESCTEXT;
1284  break;
1285  case INSQUOTE:
1286  if (c == '\'') state = INTEXT;
1287  else if (c == '\\') state = ESCSQUOTE;
1288  break;
1289  case INDQUOTE:
1290  if (c == '\"') state = INTEXT;
1291  else if (c == '\\') state = ESCDQUOTE;
1292  break;
1293  case ESCTEXT: state = INTEXT; break;
1294  case ESCSQUOTE: state = INSQUOTE; break;
1295  case ESCDQUOTE: state = INDQUOTE; break;
1296  }
1297  }
1298 
1299  if (state != START)
1300  fields += line.mid(tokenStart);
1301  return fields;
1302 }
1303 
1304 /* vim: set expandtab tabstop=4 shiftwidth=4: */
MythFormatTimeMs
QString MythFormatTimeMs(int msecs, const QString &fmt)
Format a milliseconds time value.
Definition: mythmiscutil.cpp:1229
ENO
#define ENO
This can be appended to the LOG args with "+".
Definition: mythlogging.h:72
myth_system
uint myth_system(const QString &command, uint flags, uint timeout)
Definition: mythsystemlegacy.cpp:501
hardwareprofile.smolt.timeout
float timeout
Definition: smolt.py:103
GENERIC_EXIT_OK
#define GENERIC_EXIT_OK
Exited with no error.
Definition: exitcodes.h:10
setHttpProxy
void setHttpProxy(void)
Get network proxy settings from OS, and use for [Q]Http[Comms].
Definition: mythmiscutil.cpp:848
copy
long long copy(QFile &dst, QFile &src, uint block_size)
Copies src file to dst file.
Definition: mythmiscutil.cpp:305
kMSDontBlockInputDevs
@ kMSDontBlockInputDevs
avoid blocking LIRC & Joystick Menu
Definition: mythsystem.h:34
getDiskSpace
int64_t getDiskSpace(const QString &file_on_disk, int64_t &total, int64_t &used)
Definition: mythcoreutil.cpp:43
myth_ioprio
bool myth_ioprio(int)
Allows setting the I/O priority of the current process/thread.
Definition: mythmiscutil.cpp:800
mythcoreutil.h
getLoadAvgs
loadArray getLoadAvgs(void)
Returns the system load averages.
Definition: mythmiscutil.cpp:174
LOC
#define LOC
Definition: audioconvert.cpp:38
setenv
#define setenv(x, y, z)
Definition: compat.h:157
arg
arg(title).arg(filename).arg(doDelete))
getSymlinkTarget
QString getSymlinkTarget(const QString &start_file, QStringList *intermediaries, unsigned maxLinks)
Definition: mythmiscutil.cpp:493
WakeOnLAN
bool WakeOnLAN(const QString &MAC)
Definition: mythmiscutil.cpp:631
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:23
build_compdb.file
file
Definition: build_compdb.py:55
telnet
bool telnet(const QString &host, int port)
Can we talk to port on host?
Definition: mythmiscutil.cpp:274
ESCDQUOTE
@ ESCDQUOTE
Definition: mythmiscutil.cpp:1249
getloadavg
#define getloadavg(x, y)
Definition: compat.h:323
close
#define close
Definition: compat.h:16
tmp
static guint32 * tmp
Definition: goom_core.cpp:31
mythsystemlegacy.h
IsPulseAudioRunning
bool IsPulseAudioRunning(void)
Is A/V Sync destruction daemon is running on this host?
Definition: mythmiscutil.cpp:680
MythSocket
Class for communcating between myth backends and frontends.
Definition: mythsocket.h:27
MythRemoveDirectory
bool MythRemoveDirectory(QDir &aDir)
Definition: mythmiscutil.cpp:804
MythWakeup
bool MythWakeup(const QString &wakeUpCommand, uint flags, uint timeout)
Definition: mythmiscutil.cpp:672
wrapList
void wrapList(QStringList &list, int width)
Definition: mythmiscutil.cpp:957
INSQUOTE
@ INSQUOTE
Definition: mythmiscutil.cpp:1245
mythlogging.h
hardwareprofile.config.p
p
Definition: config.py:33
compat.h
MythFormatTime
QString MythFormatTime(int secs, const QString &fmt)
Format a seconds time value.
Definition: mythmiscutil.cpp:1234
START
@ START
Definition: mythmiscutil.cpp:1243
createTempFile
QString createTempFile(QString name_template, bool dir)
Definition: mythmiscutil.cpp:365
getResponse
QString getResponse(const QString &query, const QString &def)
In an interactive shell, prompt the user to input a string.
Definition: mythmiscutil.cpp:452
filename
QString filename
Definition: mythplugins/mytharchive/mytharchivehelper/main.cpp:637
loadArray
std::array< double, 3 > loadArray
Definition: mythmiscutil.h:36
hardwareprofile.distros.mythtv_data.main.stdout
stdout
Definition: main.py:87
naturalCompare
int naturalCompare(const QString &_a, const QString &_b, Qt::CaseSensitivity caseSensitivity)
Definition: mythmiscutil.cpp:1029
uint
unsigned int uint
Definition: compat.h:140
gCoreContext
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
Definition: mythcorecontext.cpp:56
getUptime
bool getUptime(time_t &uptime)
Returns uptime statistics.
Definition: mythmiscutil.cpp:64
states
states
Definition: mythmiscutil.cpp:1242
MythCoreContext::resolveAddress
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.
Definition: mythcorecontext.cpp:1197
block_size
unsigned int block_size
Definition: freesurround.cpp:47
ESCSQUOTE
@ ESCSQUOTE
Definition: mythmiscutil.cpp:1248
hasUtf8
bool hasUtf8(const char *str)
Guess whether a string is UTF-8.
Definition: mythmiscutil.cpp:191
INDQUOTE
@ INDQUOTE
Definition: mythmiscutil.cpp:1246
mythmiscutil.h
makeFileAccessible
bool makeFileAccessible(const QString &filename)
Definition: mythmiscutil.cpp:437
mythcorecontext.h
dir
QDir dir
Definition: mythplugins/mytharchive/mytharchivehelper/main.cpp:1174
intResponse
int intResponse(const QString &query, int def)
In an interactive shell, prompt the user to input a number.
Definition: mythmiscutil.cpp:482
kMSProcessEvents
@ kMSProcessEvents
process events while waiting
Definition: mythsystem.h:37
xml_indent
QString xml_indent(uint level)
Definition: mythmiscutil.cpp:1003
INTEXT
@ INTEXT
Definition: mythmiscutil.cpp:1244
nice
#define nice(x)
Definition: compat.h:196
getMemStats
bool getMemStats(int &totalMB, int &freeMB, int &totalVM, int &freeVM)
Returns memory statistics in megabytes.
Definition: mythmiscutil.cpp:107
myth_nice
bool myth_nice(int val)
Definition: mythmiscutil.cpp:698
MythSplitCommandString
QStringList MythSplitCommandString(const QString &line)
Definition: mythmiscutil.cpp:1256
mythburn.temppath
string temppath
Definition: mythburn.py:161
kMSDontDisableDrawing
@ kMSDontDisableDrawing
avoid disabling UI drawing
Definition: mythsystem.h:35
exitcodes.h
FileHash
QString FileHash(const QString &filename)
Definition: mythmiscutil.cpp:590
IsMACAddress
bool IsMACAddress(const QString &MAC)
Definition: mythmiscutil.cpp:545
mythsocket.h
hardwareprofile.smolt.proxies
proxies
Definition: smolt.py:104
query
MSqlQuery query(MSqlQuery::InitCon())
output
#define output
Definition: synaesthesia.cpp:220
ESCTEXT
@ ESCTEXT
Definition: mythmiscutil.cpp:1247
MythCoreContext::ResolveAny
@ ResolveAny
Definition: mythcorecontext.h:193
myth_yield
void myth_yield(void)
Definition: mythmiscutil.cpp:712
ping
bool ping(const QString &host, int timeout)
Can we ping host within timeout seconds?
Definition: mythmiscutil.cpp:243