Фоновый процесс в моей собственной программе оболочки, чтобы игнорировать стандартный ввод - PullRequest
0 голосов
/ 30 января 2020

Я работаю над своей собственной маленькой программой на C. Когда я запускаю дочерний процесс как фоновый процесс, я хотел бы игнорировать входные данные пользователя, поступающие из родительского процесса. В настоящее время я пытаюсь передать его, а затем закрыть стандартный ввод для дочернего элемента, но ввод по-прежнему направляется дочернему элементу.

    else // A process
    {
        pid_t child_pid;
        char lastArgument = args[currArgsIndex-1][0];
        if (lastArgument != '&'){ //Normal process
            if((child_pid = fork()) == 0) {
                execvp(filepath, args);
                exit(0);
            }
            else
            {
                while(wait(NULL) != child_pid);
            }
        }
        else { // Background
            args[currArgsIndex-1] = NULL; 
            int process_pipe[2];
            pipe(process_pipe); // Piping
            if((child_pid = fork()) == 0) {
                close(process_pipe[0]); // Ignore stdin for child
                execvp(filepath, args);
                exit(0);
            }
        }
    }

1 Ответ

0 голосов
/ 30 января 2020

Вы создаете канал и закрываете конец чтения, но никогда не говорите, что канал должен быть стандартным.

Звучит так, как будто вы намеревались вместо этого: 1. открыть канал только в дочернем элементе, 2. закройте конец write, чтобы данные не могли быть прочитаны, 3. установите конец чтения как стандартный:

    else { // Background
        args[currArgsIndex-1] = NULL; 
        if((child_pid = fork()) == 0) {
            int process_pipe[2];
            pipe(process_pipe); // Piping
            dup2(process_pipe[0], 0); // Copy read end as stdin
            close(process_pipe[0]);   // Close FD that is now unused
            close(process_pipe[1]);   // Close write end so no data can be read
            execvp(filepath, args);
            perror("execvp failed");
            exit(1); // exit with error 
        }
    }

Хотя нет смысла иметь канал. Вы можете более просто открыть /dev/null для чтения и установки как stdin. В качестве альтернативы, просто закройте stdin полностью (некоторые программы будут жаловаться):

    else { // Background
        args[currArgsIndex-1] = NULL; 
        if((child_pid = fork()) == 0) {
            close(0); // Close stdin
            execvp(filepath, args);
            /* error handling */
    }

Имейте в виду, что реальные оболочки позволяют перенаправлять на фоновые процессы, и в этом случае ничего из вышеперечисленного не будет работать:

wc -l < myfile &

Реальные оболочки фактически не будут закрывать или перенаправлять стандартный ввод, но помещают команду в свою собственную группу процессов, которая не управляет терминалом. Затем процесс получит SIGTSTP при попытке чтения из стандартного ввода, а затем вы можете использовать fg, чтобы вывести его на передний план и начать вводить данные.

...