Отслеживание ошибок при исполнении переданной команды в execv()

Отслеживание ошибок при исполнении переданной команды в execv()

04.11.2018 10:13:06 Просмотров 28 Источник

Пытаюсь понять, как отслеживать ошибки в программе.

-> я пытаюсь создать дочерний процесс и, если, требуемая комманда имеется в заданной директории - попытаться ее выполнить.

Проблемы: 1) Я туплю и не понимаю, как с помощью stat определить, могу ли я использовать эту программу, даже если она там есть. (То есть, mode_t st_mode, понятно, но как понять, что именно оно сообщает/или где об этом написано - нет)

2) Я не понимаю, как надо определять, сможет ли команда выполниться: Например, при вызове execv("mkdir", args), где args пустой массив, execv возвращает 0, но при этом выпечатывется сообщение о некоректном использовании: usage: mkdir [-pv] [-m mode] directory ... Тоже самое в случае других ошибок (особенно критических, тип память закончилась).

В идеале - так быть не должно. Программа должна ловить это usage, сообщать пользователю об ошибке - и завершаться.

Код:

char* path = createPath(path, args[0]);
struct stat buff;

if(stat(path, &buff)!=-1){

    pid_t pid = fork();

    if (pid == -1)
    {
        // error, failed to fork()
    } 
    else if (pid > 0)
    {
        int status;
        waitpid(pid, &status, 0);
        free(path);
    }
    else 
    {
        // we are the child
        if(execv(path, args)==-1){
            reportError();
        }
        printf("Oy!\n");
    }

}
У вопроса есть решение - Посмотреть?

https://ru.stackoverflow.com/questions/902301/%d0%9e%d1%82%d1%81%d0%bb%d0%b5%d0%b6%d0%b8%d0%b2%d0%b0%d0%bd%d0%b8%d0%b5-%d0%be%d1%88%d0%b8%d0%b1%d0%be%d0%ba-%d0%bf%d1%80%d0%b8-%d0%b8%d1%81%d0%bf%d0%be%d0%bb%d0%bd%d0%b5%d0%bd%d0%b8%d0%b8-%d0%bf%d0%b5%d1%80%d0%b5%d0%b4%d0%b0%d0%bd%d0%bd%d0%be%d0%b9-%d0%ba%d0%be%d0%bc%d0%b0%d0%bd%d0%b4%d1%8b-%d0%b2-execv#comment1479726_902301
Если сейчас все пойму - вам памятник.
https://ru.stackoverflow.com/questions/902301/%d0%9e%d1%82%d1%81%d0%bb%d0%b5%d0%b6%d0%b8%d0%b2%d0%b0%d0%bd%d0%b8%d0%b5-%d0%be%d1%88%d0%b8%d0%b1%d0%be%d0%ba-%d0%bf%d1%80%d0%b8-%d0%b8%d1%81%d0%bf%d0%be%d0%bb%d0%bd%d0%b5%d0%bd%d0%b8%d0%b8-%d0%bf%d0%b5%d1%80%d0%b5%d0%b4%d0%b0%d0%bd%d0%bd%d0%be%d0%b9-%d0%ba%d0%be%d0%bc%d0%b0%d0%bd%d0%b4%d1%8b-%d0%b2-execv#comment1479729_902301
А можно комментарий, пожалуйста? if (fout) { (void) dup2(fileno(fout), 1); }
https://ru.stackoverflow.com/questions/902301/%d0%9e%d1%82%d1%81%d0%bb%d0%b5%d0%b6%d0%b8%d0%b2%d0%b0%d0%bd%d0%b8%d0%b5-%d0%be%d1%88%d0%b8%d0%b1%d0%be%d0%ba-%d0%bf%d1%80%d0%b8-%d0%b8%d1%81%d0%bf%d0%be%d0%bb%d0%bd%d0%b5%d0%bd%d0%b8%d0%b8-%d0%bf%d0%b5%d1%80%d0%b5%d0%b4%d0%b0%d0%bd%d0%bd%d0%be%d0%b9-%d0%ba%d0%be%d0%bc%d0%b0%d0%bd%d0%b4%d1%8b-%d0%b2-execv#comment1479738_902301
Если определен файл (fout), это файловый дескриптор FILE*, в вашем случае можно явно его открыть прямо в этом месте, или как вам удобнее. В этот файл пишется результат вывода запускаемой программы.
https://ru.stackoverflow.com/questions/902301/%d0%9e%d1%82%d1%81%d0%bb%d0%b5%d0%b6%d0%b8%d0%b2%d0%b0%d0%bd%d0%b8%d0%b5-%d0%be%d1%88%d0%b8%d0%b1%d0%be%d0%ba-%d0%bf%d1%80%d0%b8-%d0%b8%d1%81%d0%bf%d0%be%d0%bb%d0%bd%d0%b5%d0%bd%d0%b8%d0%b8-%d0%bf%d0%b5%d1%80%d0%b5%d0%b4%d0%b0%d0%bd%d0%bd%d0%be%d0%b9-%d0%ba%d0%be%d0%bc%d0%b0%d0%bd%d0%b4%d1%8b-%d0%b2-execv#comment1479747_902301
То есть, все ошибки будут записываться в файл?
https://ru.stackoverflow.com/questions/902301/%d0%9e%d1%82%d1%81%d0%bb%d0%b5%d0%b6%d0%b8%d0%b2%d0%b0%d0%bd%d0%b8%d0%b5-%d0%be%d1%88%d0%b8%d0%b1%d0%be%d0%ba-%d0%bf%d1%80%d0%b8-%d0%b8%d1%81%d0%bf%d0%be%d0%bb%d0%bd%d0%b5%d0%bd%d0%b8%d0%b8-%d0%bf%d0%b5%d1%80%d0%b5%d0%b4%d0%b0%d0%bd%d0%bd%d0%be%d0%b9-%d0%ba%d0%be%d0%bc%d0%b0%d0%bd%d0%b4%d1%8b-%d0%b2-execv#comment1479753_902301
Все что выводит программа будет записано в файл, переопределяются stdout (1) и stderr (2) на ваш открытый файл.

Ответы - Отслеживание ошибок при исполнении переданной команды в execv() / Отслеживание ошибок при исполнении переданной команды в execv()

Является ответом!
Fat-Zer

07.11.2018 09:44:47

1) Я туплю и не понимаю, как с помощью stat определить, могу ли я использовать эту программу, даже если она там есть.

Для этого нужен не stat(), а access(). Использование для проверки на право исполнения вполне тривиальное:

if (access (path, X_OK) != 0) {
  fprintf (strerr, "Failed to access file '%s': %s (%d)", path, strerror (errno), errno);
}

Хотя в 9 случаях из 10 это избыточно — проще просить прощения, чем разрешения — хорошей практикой, как обычно, является просто попробовать что-то сделать и в случае-чего получить по загривку...

2) Я не понимаю, как надо определять, сможет ли команда выполниться: Например, при вызове execv("mkdir", args), где args пустой массив, execv возвращает 0, но при этом выпечатывется сообщение о некоректном использовании...

Если программа правильно написана, то при некорректном завершении она возвращает ненулевой код завершения. Данный код возвращается родительскому процессу в waitpid ().

pid_t pid = fork();

if (pid > 0) {
  int wstatus, w;
  w = waitpid(pid, &status, 0);
  if (w < 0) {
    fprintf (strerr, "waitpid() failed: %s (%d)", strerror (errno), errno);
    exit (EXIT_FAILURE);
  } else if (WIFEXITED (wstatus) && WEXITSTATUS (wstatus)) {
    fprintf (stderr, "child process exited with status=%d\n", WEXITSTATUS(wstatus));
    exit (EXIT_FAILURE);
  } else if (WIFSIGNALED (wstatus)) {
    fprintf (stderr, "child process killed wth signal %d\n", WTERMSIG (wstatus));
    exit (EXIT_FAILURE);
  }

  // ... Нормальное поведение ...
} else if (pid == 0) {
  // код ребёнка
}

но при этом выпечатывется сообщение о некоректном использовании: usage: mkdir [-pv] [-m mode] directory ... Тоже самое в случае других ошибок (особенно критических, тип память закончилась).

Если стоит задача подавить/получить вывод дочернего процесса, то это делается с помощью переоткрытия дескрипторов. Для подавления традиционно используется /dev/null.

pid_t pid = fork();
int rc;

if (pid > 0) {
  // ... код родителя ...
} if (pid == 0) {
  int fd;

  rc = close (1); assert (rc == 0);
  rc = close (2); assert (rc == 0);

  fd = open ("/dev/null", O_WRONLY); assert (fd == 1);
  fd = dup(fd); assert (fd == 2);

  rc = execv(path, args);

  assert (rc<0); // Exec shouldn't return; assume an error;
  fprintf (strerr, "exec() failed: %s (%d)", strerror (errno), errno);
  exit (EXIT_FAILURE);

} 

Получение вывода делается во сути аналогично с помощью каналов (см. man pipe(2)) и dup()'ов.

Закрыть X