@Jebati

Как запустить приложение через forkpty?

Здравствуйте.

Сейчас у программы такой код:
#include <pty.h>
#include <unistd.h>
#include <thread>
#include <future>
#include <iostream>
#include <string>

int fd[2][2];
ssize_t sz = 1;

int main()
{
  pipe(fd[0]);
  pipe(fd[1]);
  
  //pid_t pid_fork = forkpty(&fd[0][1], NULL, NULL, NULL);
  pid_t pid_fork = fork();

  if (!pid_fork) {
    // Дочерний процесс
    dup2(fd[0][0], STDIN_FILENO);
    dup2(fd[1][1], STDOUT_FILENO);
    dup2(fd[1][1], STDERR_FILENO);
    execl("/bin/sh", "sh", "-c", "cd srv; java -DIReallyKnowWhatIAmDoingISwear -jar Spigot-1.12.2.jar", NULL);
  } else {
    // Родительский процесс
    char buf[1024];

    // Async
    auto future = std::async(std::launch::async, []() {
      std::string line;
      while (sz) {
        std::getline(std::cin, line);
        line = line  + "\n";
        write(fd[0][1], line.c_str(), line.size()); // Нужно направить в дочерний процесс как stdin
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
      }
    });

    while (sz = read(fd[1][0], buf, sizeof(buf))) {
      write(STDOUT_FILENO, buf, sz); // Вывод из дочернего процесса stdout
      std::this_thread::sleep_for(std::chrono::milliseconds(100));
    }

    exit(0);
  }
}

Слева - код выше, справа - запуск через обычный putty
5dbec24dd3454569494863.png

Но проблема в том, что данная программа не понимает цвета. Нужен псевдо терминал. Я нашел forkpty, но не смог переделать так, чтобы всё работало так же, и выводило нормально цвета. Подскажите, как быть.
  • Вопрос задан
  • 118 просмотров
Решения вопроса 1
jcmvbkbc
@jcmvbkbc
"I'm here to consult you" © Dogbert
может быть так?

#include <pty.h>
#include <unistd.h>
#include <thread>
#include <future>
#include <iostream>
#include <string>

ssize_t sz = 1;

int main()
{
  int mfd;

  pid_t pid_fork = forkpty(&mfd, NULL, NULL, NULL);

  if (!pid_fork) {
    // Дочерний процесс
    execl("/bin/sh", "-", NULL);
  } else {
    // Родительский процесс
    char buf[1024];

    // Async
    auto future = std::async(std::launch::async, [mfd]() {
      std::string line;
      while (sz) {
        std::getline(std::cin, line);
        line = line  + "\n";
        write(mfd, line.c_str(), line.size()); // Нужно направить в дочерний процесс как stdin
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
      }
    });

    while (sz = read(mfd, buf, sizeof(buf))) {
      write(STDOUT_FILENO, buf, sz); // Вывод из дочернего процесса stdout
      std::this_thread::sleep_for(std::chrono::milliseconds(100));
    }

    exit(0);
  }
}

Поскольку это теперь терминал, то имеет смысл установить размеры pty такими же, как у терминала вызывающей программы, например так:

...
#include <sys/ioctl.h>
...
  struct winsize ws, *pws = NULL;

  if (ioctl(1, TIOCGWINSZ, &ws) >= 0)
    pws = &ws;
  pid_t pid_fork = forkpty(&mfd, NULL, NULL, pws);


Кроме того, sleep_for в циклах чтения и записи не нужен, поскольку операции чтения присутствующие в обоих циклах -- блокирующие. Но нужна проверка того, что записались все прочитанные данные.
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы