Отслеживание ошибок при исполнении переданной команды в execv()
Пытаюсь понять, как отслеживать ошибки в программе.
-> я пытаюсь создать дочерний процесс и, если, требуемая комманда имеется в заданной директории - попытаться ее выполнить.
Проблемы: 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");
}
}






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

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()
'ов.