2014-03-28 2 views
0

C 코드로 셸을 만드는 작업이 있으며 대부분의 경우 작동하는 솔루션이 있습니다. 내 솔루션은 프로그램이 존재하는 경우 작동하며 Control-D 또는 종료를 입력하여 쉘을 종료 할 수 있습니다. 그러나 내가 알지 못하는 명령을 실행하려고하면 쉘이 명령을 찾을 수 없다는 오류 메시지를 출력하지만 exit 나 press를 입력해야합니다. Control-D 유효하지 않은 명령과 동일한 시간이 경과했습니다. 즉, 잘못된 명령을 3 번 입력하면 컨트롤 -D 번을 3 번 누르십시오. 나는 정말로 여기서 무슨 일이 일어나고 있는지 모른다. Control-D을 누르면 모든 변수를 검사하고 -1이 읽히지 만 if 문은 건너 뛴 것처럼 보입니다.execvp()가 실패한 후 필자가 작성한 셸이 올바르게 종료되지 않는다.

comp20200Shell.c

#include "comp20200Shell_header.h" 
#include <signal.h> 


/* 
* Name: **** 
* Student Number: **** 
* Email: **** 
* 
* This is the main function of my shell implementation. 
* 
*/ 
int main(void) 
{ 
    bool end_program = false; 
    size_t length = 0; 
    ssize_t read; 
    char* current_directory = NULL; 
    char* current_time = NULL; 

    /* Sets up signal handler to catch SIGINT*/ 
    if(signal(SIGINT, sigintHandler) == SIG_ERR) 
    { 
     error("An error occured while setting a signal handler\n"); 
    } 

    /* Infinitive loop, so after command or invalid comman will prompt again*/ 
    while(end_program != true) 
    { 
     char* input = NULL; 

     /* Gets current working directory */ 
     current_directory = return_current_directory(); 

     /* Gets current date and time */ 
     current_time = return_time(); 

     /* Prints Prompt */ 
     printf("%s\x5b%s\x5d %s%s %s%s%s", MAGENTA_TEXT, current_time, GREEN_TEXT, current_directory, BLUE_TEXT, PROMPT, RESET_COLOUR); 

     /* Frees the pointers returned by return_time() and return_current_directory() */ 
     free(current_time); 
     free(current_directory); 

     /* Reads one line from standard input */ 
     read = getline(&input, &length, stdin); 

     /* Checks if ctrl d, i.e. end of file is found or exit is typed */ 
     if(strcmp(input, "exit\n") == 0 || read == -1) 
     { 
      if(read == -1) 
      { 
       putchar('\n'); 
      } 
      /* Frees input */ 
      free(input); 
      return(0); 
     } 

     /* Removes newline character that will be at the end */ 
     remove_trailing_newline(input); 

     /* Passes input to process input, and the return value is passed in to process errors */ 
     process_errors(process_input(&input)); 

     /* Frees input */ 
     free(input); 
    } 

    return(0); 
} 

process_input.c

#include "comp20200Shell_header.h" 
#include <sys/wait.h> 
#include <sys/types.h> 
#include <sys/stat.h> 
#include <fcntl.h> 

/* 
* Name: **** 
* Student Number: **** 
* Email: **** 
* 
* This function is used to process the command entered by the user 
* 
* return: the error value or 0 when everything whent ok 
* arguments: the command entered by the user 
* 
*/ 
int process_input(char** input) 
{ 
    bool redirect_stdout = false; 
    bool redirect_stderr = false; 

    pid_t child_pid; 
    int child_status; 
    char** argument = malloc(sizeof(char*)); 
    int count = 0; 

    char* temp = strtok(*input, " "); 
    while(temp != NULL) 
    { 
     argument[count] = temp; 
     count ++; 
     argument = realloc(argument, (count+2) * sizeof(char *)); 
     temp = strtok(NULL, " "); 
    } 
    argument[count] = NULL; 

    if(argument[0] == NULL) 
    { 
     return(0); 
    } 
    else if(strcmp(argument[0], "cd") == 0) 
    { 
     return(change_directory(argument[1])); 
    } 

    int index; 
    for(index = 1; argument[index] != NULL; index++) 
    { 
     if(strcmp(argument[index], ">0") == 0) 
     { 
      if(argument[index + 1] == NULL) 
      { 
       return(EINVAL); 
      } 
      redirect_stdout = true; 
      break; 
     } 
     else if(strcmp(argument[index], ">2") == 0) 
     { 
      if(argument[index + 1] == NULL) 
      { 
       return(EINVAL); 
      } 
      redirect_stderr = true; 
      break; 
     } 
    } 


    child_pid = fork(); 
    if(child_pid == 0) 
    { 
     int file; 
     if(redirect_stdout == true) 
     { 
      file = open(argument[index + 1], O_WRONLY|O_CREAT|O_TRUNC, 0666); 
      dup2(file, 1); 
      edit_arguments(argument, index); 
      execvp(argument[0], argument); 
      return(-1); 
     } 
     else if(redirect_stderr == true) 
     { 
      file = open(argument[index + 1], O_WRONLY|O_CREAT|O_TRUNC, 0666); 
      dup2(file, 2); 
      edit_arguments(argument, index); 
      execvp(argument[0], argument); 
      return(-1); 
     } 

     execvp(argument[0], argument); 
     return(-1); 
    } 
    else 
    { 
     wait(&child_status); 
    } 

    return(child_status); 
} 

comp20200Shell_header.h

: 여기

내가 문제가있는 생각 내 소스 코드의 일부입니다
/* 
* Name: **** 
* Student Number: **** 
* Email: **** 
* 
* This is my header file, It includes all common used headerfiles on the top. 
* Any specific header file that is only used once will be included with the .c file that needs it. 
* 
*/ 

/* included headerfiles begin */ 
#include <ctype.h> 
#include <string.h> 
#include <stdlib.h> 
#include <stdio.h> 
#include <unistd.h> 
#include <errno.h> 
#include <stdbool.h> 
/* included headerfiles end */ 

/* defenitions begin */ 
#define PROMPT "# " 
#define BUFFER_SIZE 1024 
#define BLUE_TEXT "\x1B[34m" 
#define MAGENTA_TEXT "\x1B[35m" 
#define GREEN_TEXT "\x1B[32m" 
#define RESET_COLOUR "\x1B[0m" 
/* defenitions end */ 

/* Function prototypes begin */ 
void remove_trailing_newline(char *input); 
void sigintHandler(int sig_num); 
int process_input(char** input); 
char* return_time(void); 
void error(const char *fmt, ...); 
int change_directory(char* path); 
char* return_current_directory(void); 
void process_errors(int return_value); 
void edit_arguments(char** argument, int index); 
/* Function prototypes end */ 

나는 문제가 있다고 생각하지 않기 때문에 나머지 소스 코드를 생략했다.

답변

3

자녀가 execvp으로 전화 한 후에는 return -1; 대신 exit(EXIT_FAILURE);으로 전화해야합니다. 그렇지 않으면 자녀가 계속 실행되고 다음 명령을 해석하게됩니다. 따라서 N 번을 종료해야합니다 (여기서 N은 호출하려는 명령의 수임).

변경 후 부모 프로세스는 자식이 0이 아닌 반환 코드로 종료되었음을보고 오류 코드를 해석해야합니다. execvp (존재하지 않는 명령으로 인해) 또는 호출 된 프로세스에서 오류를 구별하는 실제적인 방법은 없습니다. exit 이전에 자녀가있는 경우 오류를 execvp에서 인쇄하는 것이 좋습니다.

execvp이 성공하면 결코 반환되지 않으므로 execvp을 호출 한 코드는 명령이 실패한 경우에만 실행할 수 있습니다.

그래서, 내 추천이 일을한다 : 당신은 exit(1); 또는 이에 상응하는 대신 return(-1);을 일을해야

if(child_pid == 0) 
{ 
    int file; 
    if(redirect_stdout == true) 
    { 
     file = open(argument[index + 1], O_WRONLY|O_CREAT|O_TRUNC, 0666); 
     dup2(file, 1); 
     edit_arguments(argument, index); 
     execvp(argument[0], argument); 
     perror("execvp"); 
     exit(EXIT_FAILURE); 
    } 
    else if(redirect_stderr == true) 
    { 
     file = open(argument[index + 1], O_WRONLY|O_CREAT|O_TRUNC, 0666); 
     dup2(file, 2); 
     edit_arguments(argument, index); 
     execvp(argument[0], argument); 
     perror("execvp"); 
     exit(EXIT_FAILURE); 
    } 

    execvp(argument[0], argument); 
    perror("execvp"); 
    exit(EXIT_FAILURE); 
} 
else 
{ 
    wait(&child_status); 
} 
1

. _exit(1); 또는 _exit(255); (또는 _exit(-1);, 그러나 _exit(255);과 동일)을 사용할 수 있습니다. 종료하기 전에 표준 오류에 오류 메시지를 인쇄하려고 할 수도 있습니다.

끝내지 않으면 터미널에서 입력을 읽으려는 2 명, 3 명, 그리고 나서 N 개의 셸로 끝납니다. 당신은 Control-D으로 EOF를 표시함으로써 각각 하나씩 종료해야합니다. 명령 입력을 시도했다면 껍질이 각 문자를 얻는 복권이되어 혼돈을 일으킬 수 있습니다 (중대한 위험, grep fungible form.file | tr -d 'fr' > /tmp/x33을 입력했다고 생각할 수 있지만 껍질 중 하나에 rm -fr /이있는 경우 문제가 발생했습니다!).

+0

자식과 아버지는 백그라운드 작업을 지원하지 않으므로 (즉, 아버지가 포크 직후에 wait (& child_status)를 수행하므로) 구현에서 싸우지 않게됩니다. –

0

대신 -1을 반환하면 오류로 인해 실행에 실패하면 exit (1) 또는 exit (-1)을 사용하여 해당 부분을 종료 할 수 있습니다.