запись STDIN приложения bash из программы на c

#c #linux #bash #stdin

#c #linux #bash #stdin

Вопрос:

Я хотел бы открыть приложение bash (prog1) и отправить команду этому приложению с помощью программы C. Я попробовал и написал следующий код.

 #include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
int main()
{
    FILE * fp;
    char message[10] = "command1n";
    fp = popen("sudo prog1","r");
    write(STDIN_FILENO, message, 10);
    pclose(fp);
    execlp("sudo prog1", "sudo prog1", "-l", NULL);
    return 0;
}
 

Этот код выдает вывод:

 Linux:~$ ./ prog 2 // running the code
command            // prints "command"
prog1->            // Then opens "prog1" (prog1 waits for user commands)
 

Но я хочу, чтобы это было

 Linux:~$ ./ prog 2 // running the code
prog1-> command    // open "prog1" and write command (instead of getting it from user)
 

Он либо записывает после выхода из prog1, либо перед запуском prog1. Пожалуйста, дайте мне знать, как написать «команду» в prog1, после открытия приложения prog1. Спасибо.

Примечание: если я сделаю

 fp = popen("sudo prog1","w");  //to write
 

Он выдает следующую ошибку
tcgetattr: Неподходящий ioctl для устройства

Комментарии:

1. Как насчет записи в STDIN запускаемой вами программы, а не в свою собственную? Это должно сделать это. Кроме того, я думаю, что вы execlp сирота, кроме того, вы даете ему плохие аргументы. Или у вас есть программа с именем «sudo prog1»?

2. У меня есть программа с именем «prog1», но если я не включу «sudo», она скажет «невозможно открыть файл: отказано в разрешении»

3. Это проблема с разрешениями и связана с вопросом, который вы задали. Вы создали prog1 как root до того, как начали работать как обычный пользователь? sudo предоставляет вам привилегии root для области действия команды. Вероятно, вам нужно «sudo chown <myuser> prog1», где <myuser> — ваше имя пользователя.

4. @user2216209: Пожалуйста, прочитайте немного внимательнее. execlp ожидает, что вы проанализируете строку ommand, поэтому он пытается выполнить программу с именем «sudo prog1», если вы ее попросите. Это означает, что имя программы содержит пробел!

5. @Deduplicator: я удалил «execlp» из программы.

Ответ №1:

Ваша основная ошибка заключается в том, что popen() каким-то образом связывает ваш дочерний процесс с вашим STDIN_FILENO. Это не так. STDIN_FILENO не связан с вашим дочерним элементом «sudo prog1». Для этого вам нужно будет создать канал, дублировать дескрипторы в stdin / stdout и fork exec. Но вы использовали popen(), так что и этого не делайте.

Вместо этого вы должны писать и читать из fp.

Что — то вроде:

   fprintf(fp, message);
  fgets(response, 100, fp);
 

Поскольку функция fprintf() буферизована, вы должны использовать n в конце строки или fflush() .

Кроме того, нет смысла использовать exec/execlp в конце, когда вы уже вызвали popen(). Похоже, вы, возможно, смешиваете два подхода, которые вы видели на примере.

popen() по существу выполняет комбинацию (pipe, dup stdin / stdout / stderr, fork, execl), чтобы позаботиться о перенаправлении дочернего процесса в поток файлов, подключенный к родительскому. Так что нет необходимости переопределять, если вам не нужна другая семантика, чем popen().

Технически вы реализуете «ожидаемую» функциональность, поэтому, возможно, вам захочется изучить expect или expect модули для разных языков. Expect входит в состав дистрибутивов Linux, но обычно является необязательным.

http://expect.sourceforge.net/

http://search.cpan.org /~rgiersig/Ожидать-1.21/Expect.pod

И не говоря уже о том, что в Perl уже есть модуль Sudo.

http://search.cpan.org /~landman/Sudo-0.21/библиотека/Sudo.pm

Комментарии:

1. Спасибо за быстрый и подробный ответ. Я удалил «execlp». Программа работает так же. Я использую язык C. fprintf и fgets не помогают. Если popen() позаботится о dup и pipe. Пожалуйста, дайте мне знать, как я должен передавать команды в prog1?