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 )
214 else if( rlen != len )
216 buff->seek(pos+rlen);
232 while (
m_pMap.contains(fd))
270 FD_SET(i.key(), &
m_fds);
278 LOG(VB_GENERAL, LOG_INFO,
"Starting process manager");
301 while( (pid = waitpid(-1, &status, WNOHANG)) > 0 )
305 if( !
m_pMap.contains(pid) )
307 LOG(VB_SYSTEM, LOG_INFO,
308 QString(
"Unmanaged child (PID: %1) has exited!") .arg(pid));
321 LOG(VB_SYSTEM, LOG_ERR,
322 QString(
"Structure for child PID %1 already deleted!")
341 status = ((status & 0x00FF) << 8) | ((status & 0xFF00) >> 8);
342 LOG(VB_SYSTEM, LOG_INFO,
343 QString(
"Odd return value: swapping from %1 to %2")
344 .arg(oldstatus) .arg(status));
351 LOG(VB_SYSTEM, LOG_INFO,
352 QString(
"Managed child (PID: %1) has exited! "
353 "command=%2, status=%3, result=%4")
354 .arg(pid) .arg(ms->
GetLogCmd()) .arg(status)
367 LOG(VB_SYSTEM, LOG_INFO,
368 QString(
"Managed child (PID: %1) has signalled! "
369 "command=%2, status=%3, result=%4, signal=%5")
370 .arg(pid) .arg(ms->
GetLogCmd()) .arg(status)
378 LOG(VB_SYSTEM, LOG_ERR,
379 QString(
"Managed child (PID: %1) has terminated! "
380 "command=%2, status=%3, result=%4")
381 .arg(pid) .arg(ms->
GetLogCmd()) .arg(status)
389 MSMap_t::iterator next;
390 auto now = SystemClock::now();
394 auto it =
m_pMap.keyValueBegin();
395 while (it !=
m_pMap.keyValueEnd())
397 auto [pid2, ms] = *it;
403 if( ms->m_timeout.time_since_epoch() > 0s && ms->m_timeout < now )
408 LOG(VB_SYSTEM, LOG_INFO,
409 QString(
"Managed child (PID: %1) timed out"
410 ", issuing KILL signal").arg(pid2));
419 LOG(VB_SYSTEM, LOG_INFO,
420 QString(
"Managed child (PID: %1) timed out"
421 ", issuing TERM signal").arg(pid2));
423 ms->m_timeout = now + 1s;
428 if (
m_jumpAbort && ms->GetSetting(
"AbortOnJump") )
462 QByteArray ba = ms->
GetBuffer(0)->data();
464 wtb.open(QIODevice::ReadOnly);
504 LOG(VB_GENERAL, LOG_INFO,
"Starting process signal handler");
508 nanosleep(&ts,
nullptr);
604 QList<QChar> whitespace; whitespace <<
' ' <<
'\t' <<
'\n' <<
'\r';
605 QList<QChar> whitechr; whitechr <<
't' <<
'n' <<
'r';
607 QChar hardquote =
'\'';
610 bool hardquoted =
false;
611 bool escaped =
false;
614 QString::const_iterator i = cmd.begin();
615 while (i != cmd.end())
617 if (quoted || hardquoted)
621 if ((quote == *i) || (
escape == *i) ||
622 whitespace.contains(*i))
627 else if (whitechr.contains(*i))
630 tmp += whitespace[whitechr.indexOf(*i)+1];
655 else if ((quoted && (*i == quote)) ||
656 (hardquoted && (*i == hardquote)))
659 quoted = hardquoted =
false;
670 if ((*i == quote) || (*i == hardquote) || (*i ==
escape) ||
671 whitespace.contains(*i))
676 else if (whitechr.contains(*i))
679 tmp += whitespace[whitechr.indexOf(*i)+1];
691 else if (quote == *i)
695 else if (hardquote == *i)
705 else if (whitespace.contains(*i) && !
tmp.isEmpty())
721 if (quoted || hardquoted || escaped)
734 abscmd =
args.takeFirst();
735 if (!abscmd.startsWith(
'/'))
738 QStringList path = qEnvironmentVariable(
"PATH").split(
':');
739 for (
const auto& pit : std::as_const(path))
741 QFile
file(QString(
"%1/%2").arg(pit, abscmd));
744 abscmd =
file.fileName();
759 LOG(VB_GENERAL, LOG_DEBUG, QString(
"Terminate skipped. Status: %1")
779 LOG(VB_GENERAL, LOG_DEBUG, QString(
"Signal skipped. Status: %1")
784 LOG(VB_GENERAL, LOG_INFO, QString(
"Child PID %1 killed with %2")
785 .arg(
m_pid).arg(strsignal(sig)));
794 std::string locerr = qPrintable(
LOC_ERR);
796 LOG(VB_SYSTEM, LOG_DEBUG, QString(
"Launching: %1").arg(
GetLogCmd()));
798 std::array<int,2> p_stdin {-1,-1};
799 std::array<int,2> p_stdout {-1,-1};
800 std::array<int,2> p_stderr {-1,-1};
805 if( pipe(p_stdin.data()) == -1 )
807 LOG(VB_SYSTEM, LOG_ERR,
LOC_ERR +
"stdin pipe() failed");
812 int flags = fcntl(p_stdin[1], F_GETFL, 0);
816 "fcntl on stdin pipe getting flags failed" +
822 if(fcntl(p_stdin[1], F_SETFL, flags) == -1)
825 "fcntl on stdin pipe setting non-blocking failed" +
833 if( pipe(p_stdout.data()) == -1 )
835 LOG(VB_SYSTEM, LOG_ERR,
LOC_ERR +
"stdout pipe() failed");
840 int flags = fcntl(p_stdout[0], F_GETFL, 0);
844 "fcntl on stdout pipe getting flags failed" +
850 if(fcntl(p_stdout[0], F_SETFL, flags) == -1)
853 "fcntl on stdout pipe setting non-blocking failed" +
861 if( pipe(p_stderr.data()) == -1 )
863 LOG(VB_SYSTEM, LOG_ERR,
LOC_ERR +
"stderr pipe() failed");
868 int flags = fcntl(p_stderr[0], F_GETFL, 0);
872 "fcntl on stderr pipe getting flags failed" +
878 if(fcntl(p_stderr[0], F_SETFL, flags) == -1)
881 "fcntl on stderr pipe setting non-blocking failed" +
891 QStringList
args = QStringList(
"-c");
894 QString cmd =
"/bin/sh";
902 char *command = strdup(cmdUTF8.constData());
904 char **cmdargs = (
char **)malloc((
args.size() + 1) *
sizeof(
char *));
909 for (
auto it =
args.constBegin(); it !=
args.constEnd(); ++it)
911 cmdargs[i++] = strdup(it->toUtf8().constData());
913 cmdargs[i] = (
char *)
nullptr;
918 "Failed to allocate memory for cmdargs " +
924 char *directory =
nullptr;
926 if (
GetSetting(
"SetDirectory") && !dir.isEmpty())
927 directory = strdup(dir.toUtf8().constData());
930 int ioprioval =
m_parent->GetIOPrio();
935 : SystemClock::time_point();
938 pid_t child = fork();
943 LOG(VB_SYSTEM, LOG_ERR,
"fork() failed: " +
ENO);
953 LOG(VB_SYSTEM, LOG_INFO,
954 QString(
"Managed child (PID: %1) has started! "
955 "%2%3 command=%4, timeout=%5")
956 .arg(QString::number(
m_pid),
960 QString::number(
timeout.count())));
965 if (p_stdout[1] >= 0)
967 if (p_stderr[1] >= 0)
991 if( p_stdin[0] >= 0 )
994 if( dup2(p_stdin[0], 0) < 0 )
997 <<
"Cannot redirect input pipe to standard input: "
998 << strerror(errno) << std::endl;
1005 int fd = open(
"/dev/null", O_RDONLY);
1008 if( dup2(fd, 0) < 0)
1011 <<
"Cannot redirect /dev/null to standard input,"
1012 "\n\t\t\tfailed to duplicate file descriptor: "
1013 << strerror(errno) << std::endl;
1020 <<
"Unable to close stdin redirect /dev/null: "
1021 << strerror(errno) << std::endl;
1028 <<
"Cannot redirect /dev/null to standard input, "
1030 << strerror(errno) << std::endl;
1035 if( p_stdout[1] >= 0 )
1038 if( dup2(p_stdout[1], 1) < 0)
1041 <<
"Cannot redirect output pipe to standard output: "
1042 << strerror(errno) << std::endl;
1049 int fd = open(
"/dev/null", O_WRONLY);
1052 if( dup2(fd, 1) < 0)
1055 <<
"Cannot redirect standard output to /dev/null,"
1056 "\n\t\t\tfailed to duplicate file descriptor: "
1057 << strerror(errno) << std::endl;
1064 <<
"Unable to close stdout redirect /dev/null: "
1065 << strerror(errno) << std::endl;
1072 <<
"Cannot redirect standard output to /dev/null, "
1074 << strerror(errno) << std::endl;
1079 if( p_stderr[1] >= 0 )
1082 if( dup2(p_stderr[1], 2) < 0)
1085 <<
"Cannot redirect error pipe to standard error: "
1086 << strerror(errno) << std::endl;
1093 int fd = open(
"/dev/null", O_WRONLY);
1096 if( dup2(fd, 2) < 0)
1099 <<
"Cannot redirect standard error to /dev/null,"
1100 "\n\t\t\tfailed to duplicate file descriptor: "
1101 << strerror(errno) << std::endl;
1108 <<
"Unable to close stderr redirect /dev/null: "
1109 << strerror(errno) << std::endl;
1116 <<
"Cannot redirect standard error to /dev/null, "
1118 << strerror(errno) << std::endl;
1123 #if HAVE_CLOSE_RANGE
1124 close_range(3, sysconf(_SC_OPEN_MAX) - 1, 0);
1126 for(
int fd = sysconf(_SC_OPEN_MAX) - 1; fd > 2; fd-- )
1131 if( directory && chdir(directory) < 0 )
1134 <<
"chdir() failed: "
1135 << strerror(errno) << std::endl;
1145 if( execv(command, cmdargs) < 0 )
1149 <<
"execv() failed: "
1150 << strerror(errno) << std::endl;
1166 for (
int i = 0; cmdargs[i]; i++)
1168 free(
reinterpret_cast<void*
>(cmdargs) );