execlp () не работает должным образом после fork () - PullRequest
0 голосов
/ 08 февраля 2020

Я пишу функцию, которая принимает значение в связанном списке, затем разветвляет процесс и запускает новый процесс, используя параметры, переданные в командную строку. Вот код, который у меня есть для prog2b. cc:

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "cplist.h"
#include <sys/time.h>
#include <iostream>
#include <sys/wait.h>
#include <errno.h>

struct timeval start, end;
char *key;

int launch_children(cplist *head){
    pid_t cpid;
    double execution_times = 0; 
    if(cpid = fork()  < 0 ){   // Important to trap errors
            std::cerr << "ARGH I'm likely in trouble, get me out of here!" << std::endl;
            exit(1);  // Important to exit on errors
        }else if (cpid == 0 ){
            std::cout << "Child process "<< getpid() << ". Running grep on " << key << head->path << std::endl;
            execlp("prog2b", "prog2b", "grep", "-R", key, head->path, NULL); 
            std::cerr << "Exec failed.. Why?" << std::endl;
            exit(1); // VERY IMPORTANT - DON'T LET CHILD KEEP RUNNING
    } else { // parent
            head->cpid = cpid;
            wait(NULL); 
            std::cout << "Child "<< cpid << "has terminated in " << execution_times;
    }
}



int main(int argc, char *argv[]){
    int i;
    int j = 0;
    cplist *head = (cplist*) malloc(sizeof(cplist));
    head->path = NULL;
    head->next = NULL;

    if(strcmp(argv[1], "-v") == 0){
        key = argv[2];
        for(i = 3; i < argc; i++){
            cpl_add(head, argv[i]);
            j++;
        }
    } else {
        key = argv[1];
        for(i = 2; i < argc; i++){
            cpl_add(head, argv[i]);
            j++;
        }
    }

    printf("key: %s\n", key);
    launch_children(head);


return(0);
}

Моя программа должна принимать значения ключа и пути из командной строки, тогда дочерний процесс должен выполнить execlp, используя 'grep' ' -r ', и значения переданы. Я изо всех сил пытаюсь заставить exe c работать должным образом. Я потратил много времени на странице руководства для менеджеров, пытаясь понять их лучше и протестировать других, но я застрял. Процесс exe c не будет запущен. Вот пример, чтобы показать, как это работает прямо сейчас:

Когда я запускаю: ./prog2b 5678 /hw1/02/ из командной строки, мой вывод:

key: 5678
Child process 70788. Running grep on 5678 /hw1/02
Exec failed.. Why?
key: 5678
Child process 70789. Running grep on 5678 /hw1/02
Exec failed.. Why?

Правильный вывод должен быть:

key: 5678
Child process nnnnn. Running grep -R 5678 hw1/02

../../hw1/02/nYyLimCI:5678
../../hw1/02/ANFGmj97:5678
../../hw1/02/oFrtX8Sy:5678
../../hw1/02/UrYt9aBz:5678
../../hw1/02/wE1AMVeh:5678
../../hw1/02/F6TGJEiJ:5678
../../hw1/02/v1HG6zmh:5678
../../hw1/02/YyOSKcJG:5678


Child process nnnnn has terminated in a.bbbbbb seconds

Я знаю, что exe c не работает, и я попытался использовать errno, и он выдал «Нет такого файла или каталога». Я понял, что это относится к первому prog2b, но когда его изменили на ./prog2b, я считаю, что это вызывает бомбу-вилку. Я также не совсем понял, как выполнить поиск в exe c, и я чувствую, что это может быть проблемой. Надеюсь, это поможет прояснить мои проблемы с форком и exe c. У меня есть файл заголовка и класс функций связанного списка с _add и _dump, но я не верю, что именно это и является причиной ошибки

1 Ответ

1 голос
/ 08 февраля 2020

Тот факт, что для errno установлено значение ENOENT (такого файла или каталога нет), говорит о том, что execlp() не удалось найти исполняемый файл.

Из страницы руководства :

Функции execlp(), execvp() и execvpe() дублируют действия оболочки при поиске исполняемого файла, если указанное имя файла не содержит sla sh (/) символ. Файл ищется в списке разделенных двоеточиями каталогов, указанных в переменной среды PATH. Если эта переменная не определена, по умолчанию в списке путей указан текущий каталог, за которым следует список каталогов, возвращаемый confstr(_CS_PATH). (Этот вызов confstr(3) обычно возвращает значение "/bin:/usr/bin".)

Ваш текущий рабочий каталог, скорее всего, не в вашем PATH, и поэтому исполняемый файл не является нашел. Простое решение - просто добавить ./ перед его именем:

execlp("./prog2b", "prog2b", "grep", "-R", "key","head->path", NULL); 
// here ^^

Совет на будущее: вы можете точно увидеть, где exec*() пытается посмотреть, используя strace:

$ strace -f -e execve ./prog2b 5678 /hw1/02/
execve("./prog2b ", ["./prog2b", "5678", "/hw1/02/"], [/* 40 vars */]) = 0
key: 5678
Child process 70788. Running grep on 5678 /hw1/02
execve("/usr/local/bin/prog2b", ["prog2b", "grep", "-R", "key","head->path"], [/* 40 vars */]) = -1 ENOENT (No such file or directory)
execve("/usr/bin/prog2b", ["prog2b", "grep", "-R", "key","head->path"], [/* 40 vars */]) = -1 ENOENT (No such file or directory)
execve("/bin/prog2b", ["prog2b", "grep", "-R", "key","head->path"], [/* 40 vars */]) = -1 ENOENT (No such file or directory)
execve("/usr/local/games/prog2b", ["prog2b", "grep", "-R", "key","head->path"], [/* 40 vars */]) = -1 ENOENT (No such file or directory)
execve("/usr/games/prog2b", ["prog2b", "grep", "-R", "key","head->path"], [/* 40 vars */]) = -1 ENOENT (No such file or directory)
Exec failed.. Why?
+++ exited with 1 +++
...