Вывод трассировки показывает, каких файлов не хватает.
Так что просто установите все отсутствующие файлы, указанные в трассировке, и проверьте еще раз... повторяйте это, пока не закончите.
Вам просто нужно проверить все системные вызовы после chroot()
, которые создают ENOENT
.
Поскольку вы уже работаете с C, я бы посоветовал вам также управлять stockchess
на C. Существует библиотечная функция popen()
, которая даст вам однонаправленный канал к процессу --, который не подходит для вашего варианта использования. Однако вы можете настроить его самостоятельно.
Рассмотрим следующий пример программы:
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
/**
* Creates two pipes, forks, and runns the given command. One pipe is
* connected between the given *out and the standard input stream of the child;
* the other pipe is connected between the given *in and the standard output
* stream of the child.
*
* Returns the pid of the child on success, -1 otherwise. On error, errno
* will be set accordingly.
*/
int bi_popen(const char* const command, FILE** const in, FILE** const out)
{
const int READ_END = 0;
const int WRITE_END = 1;
const int INVALID_FD = -1;
int to_child[2] = { INVALID_FD, INVALID_FD };
int to_parent[2] = { INVALID_FD, INVALID_FD };
*in = NULL;
*out = NULL;
if (command == NULL || in == NULL || out == NULL) {
errno = EINVAL;
goto bail;
}
if (pipe(to_child) < 0) {
goto bail;
}
if (pipe(to_parent) < 0) {
goto bail;
}
const pid_t pid = fork();
if (pid < 0) {
goto bail;
}
if (pid == 0) { // Child
if (dup2(to_child[READ_END], STDIN_FILENO) < 0) {
perror("dup2");
exit(1);
}
close(to_child[READ_END]);
close(to_child[WRITE_END]);
if (dup2(to_parent[WRITE_END], STDOUT_FILENO) < 0) {
perror("dup2");
exit(1);
}
close(to_parent[READ_END]);
close(to_parent[WRITE_END]);
execlp(command, command, NULL);
perror("execlp");
exit(1);
}
// Parent
close(to_child[READ_END]);
to_child[READ_END] = INVALID_FD;
close(to_parent[WRITE_END]);
to_parent[WRITE_END] = INVALID_FD;
*in = fdopen(to_parent[READ_END], "r");
if (*in == NULL) {
goto bail;
}
to_parent[READ_END] = INVALID_FD;
*out = fdopen(to_child[WRITE_END], "w");
if (*out == NULL) {
goto bail;
}
to_child[WRITE_END] = INVALID_FD;
setvbuf(*out, NULL, _IONBF, BUFSIZ);
return pid;
bail:
; // Goto label must be a statement, this is an empty statement
const int old_errno = errno;
if (*in != NULL) {
fclose(*in);
}
if (*out != NULL) {
fclose(*out);
}
for (int i = 0; i < 2; ++i) {
if (to_child[i] != INVALID_FD) {
close(to_child[i]);
}
if (to_parent[i] != INVALID_FD) {
close(to_parent[i]);
}
}
errno = old_errno;
return -1;
}
int main(void)
{
FILE* in = NULL;
FILE* out = NULL;
char* line = NULL;
size_t size = 0;
const int pid = bi_popen("/bin/bash", &in, &out);
if (pid < 0) {
perror("bi_popen");
return 1;
}
fprintf(out, "ls -l a.out\n");
getline(&line, &size, in);
printf("-> %s", line);
fprintf(out, "pwd\n");
getline(&line, &size, in);
printf("-> %s", line);
fprintf(out, "date\n");
getline(&line, &size, in);
printf("-> %s", line);
// Since in this case we can tell the child to terminate, we'll do so
// and wait for it to terminate before we close down.
fprintf(out, "exit\n");
waitpid(pid, NULL, 0);
fclose(in);
fclose(out);
return 0;
}
В программе я определил функцию bi_popen
. Функция принимает в качестве входных данных путь запускаемой программы, а также дваFILE*
:in
для ввода из команды и out
для вывода в команды.
bi_popen
устанавливает два канала, один для связи от родительского процесса к дочернему процессу, а другой для связи от дочернего процесса к родительскому процессу.
Далее,bi_popen
fork
с, создание нового процесса. Дочерний процесс подключает свой стандартный вывод к концу записи -канала родительского процесса и подключает свой стандартный ввод к концу канала чтения -родительского процесса. Затем он очищает старые дескрипторы файлов канала и использует execlp
для замены запущенного процесса данной командой. Эта новая программа наследует стандартную конфигурацию ввода/вывода с каналами. В случае успеха execlp
никогда не возвращается.
В случае родительского ---, когда fork
возвращает не -нулевое значение ---, родительский процесс закрывает ненужные концы канала и использует fdopen
для создания FILE*
связанных с соответствующими дескрипторами файла канала. Он обновляет выходные параметры in
и out
этими значениями. Наконец, он использует execlp
на выходе FILE*
, чтобы сделать его небуферизованным (, чтобы вам не приходилось явно сбрасывать содержимое, которое вы отправляете дочернему процессу ).
Функция main
является примером использования функции bi_popen
. Он вызывает bi_popen
с командой как /bin/bash
. Все, что записывается в поток out
, отправляется в bash для выполнения. Все, что bash выводит на стандартный вывод, доступно для чтения из in
.
Вот пример запуска программы:
$./a.out
-> -rwxr-xr-x 1 user group 20400 Aug 29 17:09 a.out
-> /home/user/src/bidirecitonal_popen
-> Sat Aug 29 05:10:52 PM EDT 2020
Обратите внимание, что main
записывает серию команд в дочерний процесс (здесь, bash
), и команда отвечает ожидаемым результатом.
В вашем случае вы можете заменить «/bin/bash» на «вяленую рыбу», а затем использовать out
для записи команд в stockfish
и in
для чтения ответов.