2016-01-16 2 views
0

Я создаю linux-подобную оболочку, и я пытаюсь выполнить внешние команды так же, как в linux с «./» в начале.Заменить строковое значение переменной в execl и остановить выполнение

Это, как я прочитал команды:

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

#include "commands/commands.h" 

bool starts_with(const char *a, const char *b){ 
if(strncmp(a,b,strlen(b)) == 0){ 
    return 1; 
} 

return 0; 
} 

int main(int argc, char *argv[]){ 

char cmd[500]; 

do{ 
    printf("$ > "); 
    fgets(cmd, 499, stdin); 

    if(starts_with(cmd, "./")){ 
     execute_external_command(cmd); 
    }else{ 
     //execute_interal_command(cmd); 
    } 


}while(strcmp(cmd, "exit\n") != 0); 

return 0; 
} 

И это как мой дочерний процесс заменяется новым процессом, программа под названием «Привет». Он просто печатает «Hello World» на экране.

else{ 
    //Child process 
    dup2(commpipe[0],0); 
    close(commpipe[1]); 

    //Replace child process with a new process 
    if(execl("hello", "hello", NULL) == -1){ 
     fprintf(stderr, "Error executing new process!\n"); 
     exit(3); 
    } 
} 

}

Он работает просто отлично. Но я хочу заменить эту «привет» переменной, например, когда я набираю «./hello», чтобы получить «привет» часть оттуда и использовать ее как переменную в функции execl().

Я попытался сделать это так, но, похоже, он не может найти это «привет». Я попробовал распечатать его на экране, и он печатает «привет», как должен. Любые идеи, почему процесс не выполняется?

else{ 
    //Child process 
    dup2(commpipe[0],0); 
    close(commpipe[1]); 

    char program[10]; 
    int len = strlen(cmd) - 2; 
    memcpy(program, &cmd[2],len); 

    //Replace child process with a new process 
    if(execl(program, program, NULL) == -1){ 
     fprintf(stderr, "Error executing new process!\n"); 
     exit(3); 
    } 
} 

}

Второй вопрос: В моем первом способе исполнения оно выполняется только в порядке с «привет» в виде строки в execl() funcntion. Я всегда печатаю строку «$>» на экране, которая запрашивает ввод. Но когда дочерний процесс заканчивает свое исполнение, вся программа останавливается. Как я могу заставить его снова напечатать строку «$>» на экране, чтобы я мог выполнять другие команды, если захочу. Заранее спасибо

ОБНОВЛЕНИЕ: Функция, которая выполняет внешние команды

void execute_external_command(char cmd[]){ 

pid_t pid; 
int rv; 
int commpipe[2]; 

//Creting pipe 
if(pipe(commpipe)){ 
    fprintf(stderr, "Error creating pipe!!\n"); 
    exit(1); 
} 

if((pid=fork()) == -1){ 
    fprintf(stderr, "Error forking ew process!\n"); 
    exit(2); 
} 

if(pid){ 
    //Parent process 
    dup2(commpipe[1],1); 
    close(commpipe[0]); 
    setvbuf(stdout,(char*)NULL,_IONBF,0); 
    wait(&rv); 
    fprintf(stderr, "Child exited with a %d value", rv); 
}else{ 
    //Child process 
    dup2(commpipe[0],0); 
    close(commpipe[1]); 

    int len = strlen(cmd) - 2; 
    char program[len]; 
    memcpy(program, &cmd[2],len); 
    program[len-1] = '\0'; 

    //Replace child process with a new process 
    if(execl(program, program, NULL) == -1){ 
     fprintf(stderr, "Error executing new process!\n"); 
     exit(3); 
    } 
} 
} 
+0

Перед тем, как остановиться, он печатает 'Ребенок, выходящий со значением% d'? – Ctx

+0

Нет, это не так. –

+0

относительно этой строки: 'if (execl (program, program, NULL) == -1) {'. функции 'exec *()' никогда не возвращаются, если не возникает ошибка. поэтому строка должна быть: 'execl (program, program, NULL);' – user3629249

ответ

2

fgets включает в себя символ новой строки в строке. Вы должны разбить его, чтобы правильно вызвать бинарный файл. Кроме того, ваш memcpy не копирует нужный zerobyte в качестве ограничителя строк. Попытка:

program[len-1] = '\0'; 

после memcpy(). Это должно помочь.

Другое примечание: этот код подвержен переполнению буфера, поскольку программа зафиксирована на 10 байт, в то время как cmd может быть намного длиннее. Вы можете сделать:

int len = strlen(cmd) - 2; 
char program[len]; 
memcpy(program, &cmd[2],len); 
program[len-1] = '\0'; 

, чтобы не допустить этого. Если вы не заботитесь об изменении ЦМД, вы также можете сделать:

cmd[strlen(cmd)-1] = '\0'; 

if (execl(cmd+2, cmd+2, NULL) ... 

Еще одна вещь:

Это даже не нужно, чтобы удалить ./ -часть, execl будет прекрасно работать с ним.

Здесь в родительском процессе:

if(pid){ 
    //Parent process 
    dup2(commpipe[1],1); 

вы установили стандартный вывод вашего процесса в commpipe. Таким образом, все последующие printf будут пытаться писать в сломанный канал, и, следовательно, SIGPIPE завершает ваш родительский процесс. Я вообще не вижу, зачем вам здесь нужна труба, я думаю, вы можете полностью ее покинуть.

+0

Ну, это было просто. Я забыл, что использовал «fgets». Большое спасибо. Но можете ли вы мне помочь и со вторым вопросом? Так что моя программа возобновляет запрос на ввод пользователя? –

+0

@OlarAndrei это помогает? Если нет, укажите другой контекст кода. – Ctx

+0

Я обновил свой код. Вот как выглядит моя вся функция. Можете ли вы рассказать мне более точно, как сообщить родителям, что ребенок выполнен? И как программа должна идти дальше, отображая эту строку «$>» с самого начала, чтобы получить ввод пользователя, а не убивать программу после того, как ребенок выполнил выполнение? –

Смежные вопросы