18 #include <sys/select.h>
23 #include <QCoreApplication>
27 #include <QStringList>
35 #if !defined(__syscall_slong_t)
63 static inline void CLOSE(
int& fd)
69 delete fdMap.value(fd);
91 LOG(VB_GENERAL, LOG_INFO, QString(
"Starting IO manager (%1)")
92 .arg(
m_read ?
"read" :
"write"));
108 nanosleep(&ts,
nullptr);
122 retval = select(
m_maxfd+1, &fds,
nullptr,
nullptr, &tv);
124 retval = select(
m_maxfd+1,
nullptr, &fds,
nullptr, &tv);
128 LOG(VB_SYSTEM, LOG_ERR,
129 QString(
"MythSystemLegacyIOHandler: select(%1, %2) failed: %3")
133 else if( retval > 0 )
135 auto it =
m_pMap.keyValueBegin();
136 while (it !=
m_pMap.keyValueEnd())
138 auto [fd, buffer] = *it;
140 if( FD_ISSET(fd, &fds) )
162 if( errno != EAGAIN )
170 buff->buffer().append(
m_readbuf.data(), len);
177 if (fdType ==
nullptr)
197 int pos = buff->pos();
198 int len = buff->size() - pos;
199 len = (len > 32768 ? 32768 : len);
201 int rlen =
write(fd, buff->read(len).constData(), len);
204 if( errno != EAGAIN )
212 else if( rlen != len )
213 buff->seek(pos+rlen);
228 while (
m_pMap.contains(fd))
266 FD_SET(i.key(), &
m_fds);
274 LOG(VB_GENERAL, LOG_INFO,
"Starting process manager");
297 while( (pid = waitpid(-1, &status, WNOHANG)) > 0 )
301 if( !
m_pMap.contains(pid) )
303 LOG(VB_SYSTEM, LOG_INFO,
304 QString(
"Unmanaged child (PID: %1) has exited!") .arg(pid));
317 LOG(VB_SYSTEM, LOG_ERR,
318 QString(
"Structure for child PID %1 already deleted!")
337 status = ((status & 0x00FF) << 8) | ((status & 0xFF00) >> 8);
338 LOG(VB_SYSTEM, LOG_INFO,
339 QString(
"Odd return value: swapping from %1 to %2")
340 .arg(oldstatus) .arg(status));
347 LOG(VB_SYSTEM, LOG_INFO,
348 QString(
"Managed child (PID: %1) has exited! "
349 "command=%2, status=%3, result=%4")
350 .arg(pid) .arg(ms->
GetLogCmd()) .arg(status)
363 LOG(VB_SYSTEM, LOG_INFO,
364 QString(
"Managed child (PID: %1) has signalled! "
365 "command=%2, status=%3, result=%4, signal=%5")
366 .arg(pid) .arg(ms->
GetLogCmd()) .arg(status)
374 LOG(VB_SYSTEM, LOG_ERR,
375 QString(
"Managed child (PID: %1) has terminated! "
376 "command=%2, status=%3, result=%4")
377 .arg(pid) .arg(ms->
GetLogCmd()) .arg(status)
385 MSMap_t::iterator next;
386 auto now = SystemClock::now();
390 auto it =
m_pMap.keyValueBegin();
391 while (it !=
m_pMap.keyValueEnd())
393 auto [pid2, ms] = *it;
399 if( ms->m_timeout.time_since_epoch() > 0s && ms->m_timeout < now )
404 LOG(VB_SYSTEM, LOG_INFO,
405 QString(
"Managed child (PID: %1) timed out"
406 ", issuing KILL signal").arg(pid2));
415 LOG(VB_SYSTEM, LOG_INFO,
416 QString(
"Managed child (PID: %1) timed out"
417 ", issuing TERM signal").arg(pid2));
419 ms->m_timeout = now + 1s;
424 if (
m_jumpAbort && ms->GetSetting(
"AbortOnJump") )
458 QByteArray ba = ms->
GetBuffer(0)->data();
460 wtb.open(QIODevice::ReadOnly);
500 LOG(VB_GENERAL, LOG_INFO,
"Starting process signal handler");
504 nanosleep(&ts,
nullptr);
600 QList<QChar> whitespace; whitespace <<
' ' <<
'\t' <<
'\n' <<
'\r';
601 QList<QChar> whitechr; whitechr <<
't' <<
'n' <<
'r';
603 QChar hardquote =
'\'';
606 bool hardquoted =
false;
607 bool escaped =
false;
610 QString::const_iterator i = cmd.begin();
611 while (i != cmd.end())
613 if (quoted || hardquoted)
617 if ((quote == *i) || (
escape == *i) ||
618 whitespace.contains(*i))
623 else if (whitechr.contains(*i))
626 tmp += whitespace[whitechr.indexOf(*i)+1];
651 else if ((quoted && (*i == quote)) ||
652 (hardquoted && (*i == hardquote)))
655 quoted = hardquoted =
false;
666 if ((*i == quote) || (*i == hardquote) || (*i ==
escape) ||
667 whitespace.contains(*i))
672 else if (whitechr.contains(*i))
675 tmp += whitespace[whitechr.indexOf(*i)+1];
687 else if (quote == *i)
689 else if (hardquote == *i)
697 else if (whitespace.contains(*i) && !
tmp.isEmpty())
711 if (quoted || hardquoted || escaped)
724 abscmd =
args.takeFirst();
725 if (!abscmd.startsWith(
'/'))
728 QStringList path = qEnvironmentVariable(
"PATH").split(
':');
729 for (
const auto& pit : qAsConst(path))
731 QFile
file(QString(
"%1/%2").arg(pit, abscmd));
734 abscmd =
file.fileName();
749 LOG(VB_GENERAL, LOG_DEBUG, QString(
"Terminate skipped. Status: %1")
769 LOG(VB_GENERAL, LOG_DEBUG, QString(
"Signal skipped. Status: %1")
774 LOG(VB_GENERAL, LOG_INFO, QString(
"Child PID %1 killed with %2")
775 .arg(
m_pid).arg(strsignal(sig)));
784 std::string locerr = qPrintable(
LOC_ERR);
786 LOG(VB_SYSTEM, LOG_DEBUG, QString(
"Launching: %1").arg(
GetLogCmd()));
788 std::array<int,2> p_stdin {-1,-1};
789 std::array<int,2> p_stdout {-1,-1};
790 std::array<int,2> p_stderr {-1,-1};
795 if( pipe(p_stdin.data()) == -1 )
797 LOG(VB_SYSTEM, LOG_ERR,
LOC_ERR +
"stdin pipe() failed");
802 int flags = fcntl(p_stdin[1], F_GETFL, 0);
806 "fcntl on stdin pipe getting flags failed" +
812 if(fcntl(p_stdin[1], F_SETFL, flags) == -1)
815 "fcntl on stdin pipe setting non-blocking failed" +
823 if( pipe(p_stdout.data()) == -1 )
825 LOG(VB_SYSTEM, LOG_ERR,
LOC_ERR +
"stdout pipe() failed");
830 int flags = fcntl(p_stdout[0], F_GETFL, 0);
834 "fcntl on stdout pipe getting flags failed" +
840 if(fcntl(p_stdout[0], F_SETFL, flags) == -1)
843 "fcntl on stdout pipe setting non-blocking failed" +
851 if( pipe(p_stderr.data()) == -1 )
853 LOG(VB_SYSTEM, LOG_ERR,
LOC_ERR +
"stderr pipe() failed");
858 int flags = fcntl(p_stderr[0], F_GETFL, 0);
862 "fcntl on stderr pipe getting flags failed" +
868 if(fcntl(p_stderr[0], F_SETFL, flags) == -1)
871 "fcntl on stderr pipe setting non-blocking failed" +
881 QStringList
args = QStringList(
"-c");
884 QString cmd =
"/bin/sh";
892 char *command = strdup(cmdUTF8.constData());
894 char **cmdargs = (
char **)malloc((
args.size() + 1) *
sizeof(
char *));
899 for (
auto it =
args.constBegin(); it !=
args.constEnd(); ++it)
901 cmdargs[i++] = strdup(it->toUtf8().constData());
903 cmdargs[i] = (
char *)
nullptr;
908 "Failed to allocate memory for cmdargs " +
914 char *directory =
nullptr;
916 if (
GetSetting(
"SetDirectory") && !dir.isEmpty())
917 directory = strdup(dir.toUtf8().constData());
920 int ioprioval =
m_parent->GetIOPrio();
925 : SystemClock::time_point();
928 pid_t child = fork();
933 LOG(VB_SYSTEM, LOG_ERR,
"fork() failed: " +
ENO);
943 LOG(VB_SYSTEM, LOG_INFO,
944 QString(
"Managed child (PID: %1) has started! "
945 "%2%3 command=%4, timeout=%5")
946 .arg(QString::number(
m_pid),
950 QString::number(
timeout.count())));
955 if (p_stdout[1] >= 0)
957 if (p_stderr[1] >= 0)
981 if( p_stdin[0] >= 0 )
984 if( dup2(p_stdin[0], 0) < 0 )
987 <<
"Cannot redirect input pipe to standard input: "
988 << strerror(errno) << std::endl;
995 int fd = open(
"/dev/null", O_RDONLY);
1001 <<
"Cannot redirect /dev/null to standard input,"
1002 "\n\t\t\tfailed to duplicate file descriptor: "
1003 << strerror(errno) << std::endl;
1010 <<
"Unable to close stdin redirect /dev/null: "
1011 << strerror(errno) << std::endl;
1018 <<
"Cannot redirect /dev/null to standard input, "
1020 << strerror(errno) << std::endl;
1025 if( p_stdout[1] >= 0 )
1028 if( dup2(p_stdout[1], 1) < 0)
1031 <<
"Cannot redirect output pipe to standard output: "
1032 << strerror(errno) << std::endl;
1039 int fd = open(
"/dev/null", O_WRONLY);
1042 if( dup2(fd, 1) < 0)
1045 <<
"Cannot redirect standard output to /dev/null,"
1046 "\n\t\t\tfailed to duplicate file descriptor: "
1047 << strerror(errno) << std::endl;
1054 <<
"Unable to close stdout redirect /dev/null: "
1055 << strerror(errno) << std::endl;
1062 <<
"Cannot redirect standard output to /dev/null, "
1064 << strerror(errno) << std::endl;
1069 if( p_stderr[1] >= 0 )
1072 if( dup2(p_stderr[1], 2) < 0)
1075 <<
"Cannot redirect error pipe to standard error: "
1076 << strerror(errno) << std::endl;
1083 int fd = open(
"/dev/null", O_WRONLY);
1086 if( dup2(fd, 2) < 0)
1089 <<
"Cannot redirect standard error to /dev/null,"
1090 "\n\t\t\tfailed to duplicate file descriptor: "
1091 << strerror(errno) << std::endl;
1098 <<
"Unable to close stderr redirect /dev/null: "
1099 << strerror(errno) << std::endl;
1106 <<
"Cannot redirect standard error to /dev/null, "
1108 << strerror(errno) << std::endl;
1113 for(
int fd = sysconf(_SC_OPEN_MAX) - 1; fd > 2; fd-- )
1117 if( directory && chdir(directory) < 0 )
1120 <<
"chdir() failed: "
1121 << strerror(errno) << std::endl;
1131 if( execv(command, cmdargs) < 0 )
1135 <<
"execv() failed: "
1136 << strerror(errno) << std::endl;
1152 for (
int i = 0; cmdargs[i]; i++)