Как я могу получить возвращаемое значение / bin / ls -R, если я запускаю его с помощью execl ()? - PullRequest
0 голосов
/ 02 мая 2020

Итак, у меня есть задание для Uni, в Linux C. Программа должна вызвать дочерний процесс, который должен выполнить команду /bin/ls -R, а затем записать возвращаемое значение в родительский процесс, который не может быть 0. До сих пор я мог только заставить его работать, используя system() позвони, но я не могу это использовать. Строка wait(&value) работает с функцией system(), но не с execl. Код, который я придумал до сих пор:

int main(){
    int value=0;
    if(fork() == 0){
        printf("Running command, please wait..\n");
        sleep(2);
        char *path = "/bin/ls";
        char *arg1 = "-R";
        execl(path, arg1, NULL);
        exit(1);
    }

    wait(&value); 
    printf("\nProcessing return value, please wait..\n");
    sleep(2);
    printf("\nThe return value of the child: %d \n", value); 
}

1 Ответ

2 голосов
/ 02 мая 2020

Как я могу получить возвращаемое значение / bin / ls -R, если я запускаю его с помощью execl ()?

Если вы правильно wait() (см. Нижнюю часть моего ответа) ) тогда вы получаете возвращаемое значение /bin/ls -R.

, которое не может быть 0

Не уверен, что вы подразумеваете под этим , но состояние выхода 0 означает, что процесс завершился правильно. Что-то отличное от 0 означает, что произошла ошибка, поэтому вы обычно хотите, чтобы все завершалось с 0, а не с чем-то другим.

Семейство функций exec*() не возвращается при успешном выполнении. Прочтите страницу руководства , чтобы узнать больше.

Если вы хотите, чтобы ребенок потерпел неудачу, то передайте неверный путь к execl, чтобы он потерпел неудачу, или просто return 1 сразу. Чтобы заставить ls -R возвращать что-то отличное от 0, вы можете передать третий аргумент execl(), указывающий путь, к которому у вас нет доступа, как, например, /root.


Я также не совсем уверен, что не так с вашим кодом, поскольку он компилируется и работает правильно на моей машине, , но , вот несколько практических правил, которым нужно следовать, чтобы найти проблему и избежать это в первую очередь:

  1. Всегда читайте руководство (в данном случае man 2 wait):

    If  wstatus  is  not NULL, wait() and waitpid() store status information in the int to which it points.  This
    integer can be inspected with the following macros (which take the integer  itself  as  an  argument,  not  a
    pointer to it, as is done in wait() and waitpid()!):
    
    WIFEXITED(wstatus)
          returns  true if the child terminated normally, that is, by calling exit(3) or _exit(2), or by return‐
          ing from main().
    
    WEXITSTATUS(wstatus)
          returns the exit status of the child.  This consists of the least significant 8  bits  of  the  status
          argument  that  the  child  specified in a call to exit(3) or _exit(2) or as the argument for a return
          statement in main().  This macro should be employed only if WIFEXITED returned true.
    
  2. Всегда проверяйте наличие ошибок в функциях, которые могут не работать. Подсказка: в основном 99% системных вызовов могут дать сбой, fork и wait - некоторые из них.

    pid_t child_pid = fork();
    if (child_pid == -1) {
        perror("fork() failed");
        return 1;
    }
    
    // ...
    
    pid_t res = wait(&child_status);
    if (res != child_pid) {
        perror("wait() failed");
        return 1;
    }
    
  3. Всегда компилировать включающие предупреждения: gcc -Wall -Wextra -pedantic.

Применение приведенных выше правил в большинстве случаев - все, что вам нужно, чтобы выяснить, в чем проблема. Вот рабочая версия вашей программы после их применения:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>

int main(void) {
    pid_t child_pid, res;
    int child_status;

    child_pid = fork();
    if (child_pid == -1) {
        perror("fork() failed");
        return 1;
    }

    if(child_pid == 0) {
        sleep(123);
        execl("/bin/ls", "-R", NULL);
        perror("execl() failed");
        exit(1);
    }

    res = wait(&child_status);
    if (res != child_pid) {
        perror("wait() failed");
        return 1;
    }

    if (WIFEXITED(child_status))
        printf("Child exited with status %d.\n", WEXITSTATUS(child_status));
    else if (WIFSIGNALED(child_status))
        printf("Child killed by signal %d.\n", WTERMSIG(child_status));
    else {
        puts("This should never happen! Something's really wrong.");
        return 1;
    }

    return 0;
}
...