2015-11-12 5 views
-2

Я хочу создать оболочку, где дочерний процесс запускает команды linux (с помощью execvp), такие как «ls» и т. Д. Я также хочу иметь возможность запускать команды с такими аргументами, как «ls -a "или" ls -l/tmp " Родитель должен ждать, пока ребенок выполнит заданную команду с" waitpid ". Когда я пытаюсь запустить оболочку с помощью «ls -a», она принимает это как две отдельные команды. Вывод: Ls $ -a $Выполнение команд из дочернего процесса

#include "stdio.h" 
#include "unistd.h" 
#include "stdlib.h" 

int main(int argc, char **argv) 
{ 
    char input[64]; 
    pid_t pid; 
    char *status; 
    char *args[64]; 
    char **next = args; 
    char *temp; 

    while (1) { 
     printf("$"); 
     fgets(input,"exit",stdin); 
     if (strcmp(input, "exit") == 0) { 
     exit(0) 
     } 
     pid = fork(); 

     if (pid == 0) { 
      //child 

      *temp = strtok(input, " "); 


      while (temp != NULL) { 
       *next++ = temp; 
       *temp = strtok(NULL, " "); 
      } 


      if (execvp(args[0], args) == -1) { 
       perror("Execvp Error"); 
      } 
      exit(0); 

     }else if (pid < 0) { 
      printf("error during fork"); 
     }else { 
      //parent 
      waitpid(pid, &status, 0); 
     } 
    } 
} 
+2

Великий. У вас возникли вопросы? –

+0

вы начинаете с 'while (strcmp (input,« exit »)), но ничего не вводится в' input'. После этого вы читаете 'input' и fork. Даже если пользователь вводит «выход» (скажем). Глобальная логика не «логична». – hexasoft

+0

Всякий раз, когда я запускаю программу, я не могу увидеть результат моей команды ... также, если поместить там ложную команду, ее не показывать никаких ошибок. – purkavlos

ответ

-2

Я думаю, что здесь purkavlos дал нам пример кода (который не является полностью функциональным еще) для того, чтобы нам, чтобы показать ему логику выполнения команд через дочерний процесс .. просто исправляющие части кода не очень помогают.

Решение: Использование gets() вместо scanf() решит вашу первую проблему, чтобы вы могли принять строку с такими пробелами, как Павел. Проверьте, работает ли это для вас, поскольку я вижу, что токенизация верна. После этого команда должна работать, но я не уверен в выходе, вы получаете ее через ребенка?

+0

Это комментарий, а не ответ. И если вы хотите быть «очень помогающим», рекомендуя, чтобы кто-то использовал 'gets()', это не способ сделать это. –

+0

означает fgets bro ... – yakushi

+0

Ребята PLS остановить downvoting всех. Это мой первый пост, и я пытаюсь сделать то, что вы мне скажите. В любом случае, когда я пытаюсь запустить оболочку с помощью «ls -a», она принимает это как 2 отдельных commans output: ls $ -a $ – purkavlos

0

Если вы напишите несколько вспомогательных функций и придумаете подходящую структуру данных, она станет тривиальной. Например:

main.c:

#define _POSIX_C_SOURCE 200809L 

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <errno.h> 
#include <unistd.h> 
#include <sys/types.h> 
#include <sys/wait.h> 
#include "stringlist.h" 
#include "io.h" 


int main(void) 
{ 
    StringList list = NULL; 
    get_input(&list); 

    while (strcmp(stringlist_string_at_index(list, 0), "exit")) { 
     pid_t p = fork(); 

     if (p < 0) { 
      perror("fork() error"); 
      exit(EXIT_FAILURE); 
     } 
     else if (p == 0) { 
      char ** args = stringlist_raw_list(list); 
      execvp(args[0], args); 
      switch (errno) { 
       case EACCES: 
        printf("Error: access denied.\n"); 
        break; 

       case ENOENT: 
        printf("Error: file not found.\n"); 
        break; 

       default: 
        printf("Error: couldn't fulfill request.\n"); 
        break; 
      } 
      exit(EXIT_FAILURE); 
     } 
     else { 
      int status; 
      waitpid(p, &status, 0); 
     } 

     get_input(&list); 
    } 

    stringlist_destroy(list); 
    return EXIT_SUCCESS; 
} 

с вспомогательными файлами:

io.h:

#ifndef IO_H 
#define IO_H 

#include "stringlist.h" 

void get_input(StringList * list); 

#endif  /* IO_H */ 

io.c:

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include "io.h" 
#include "stringlist.h" 


#define MAX_INPUT_LENGTH 256 

static void get_input_line(char * buffer, const size_t buffer_size); 
static void output_prompt(void); 
static StringList tokenize_input(void); 


/* Prompts for and gets input from standard input. 
* 
* If the StringList pointed to by `list` is not NULL, it will 
* be destroyed. The StringList pointed to by `list` will be 
* modified to point to a new StringList created from the input. 
* If no input is entered, function will prompt for it again. 
* 
* Note: the input is tokenized purely by space characters, so input 
* resembling: 
* 
*  cat "Filename with spaces" 
* 
* will return four tokens, not two. This simple method of tokenizing 
* will be unsuitable for many applications. 
*/ 

void get_input(StringList * list) 
{ 
    if (*list) { 
     stringlist_destroy(*list); 
    } 

    do { 
     output_prompt(); 
     *list = tokenize_input(); 
    } while (stringlist_length(*list) == 0); 
} 


/* Gets a line of input from standard input. 
* 
* Function strips the trailing newline, if present, and 
* exits the program on error. 
*/ 

static void get_input_line(char * buffer, const size_t buffer_size) 
{ 
    if (!fgets(buffer, buffer_size, stdin)) { 
     fprintf(stderr, "error getting input\n"); 
     exit(EXIT_FAILURE); 
    } 

    const size_t len = strlen(buffer); 
    if (len > 0 && buffer[len - 1] == '\n') { 
     buffer[len - 1] = 0; 
    } 
} 


/* Outputs the shell prompt */ 

static void output_prompt(void) 
{ 
    printf("shell$ "); 
    fflush(stdout); 
} 


/* Gets a line of input from standard input and tokenizes it */ 

static StringList tokenize_input(void) 
{ 
    StringList list = stringlist_create(); 

    char input[MAX_INPUT_LENGTH]; 
    get_input_line(input, MAX_INPUT_LENGTH); 

    char * t = strtok(input, " "); 
    while (t) { 
     stringlist_add(list, t); 
     t = strtok(NULL, " "); 
    } 

    return list; 
} 

stringlist.h:

#ifndef STRING_LIST_H 
#define STRING_LIST_H 

#include <stddef.h> 
#include <stdbool.h> 

typedef struct stringlist * StringList; 

StringList stringlist_create(void); 
bool stringlist_delete_last(StringList list); 
void stringlist_destroy(StringList list); 
size_t stringlist_length(StringList list); 
char * stringlist_string_at_index(StringList list, const size_t index); 
char ** stringlist_raw_list(StringList list); 
void stringlist_add(StringList list, const char * str); 

#endif  /* STRING_LIST_H */ 

stringlist.c:

#define _POSIX_C_SOURCE 200809L 

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <stdbool.h> 
#include "stringlist.h" 

#define DEFAULT_LIST_SIZE 8 

struct stringlist { 
    char ** list;  /* Pointer to list of strings  */ 
    size_t size;  /* Current capacity of list  */ 
    size_t top;   /* Lowest empty element of list */ 
}; 


/* Creates a new list of default capacity */ 

StringList stringlist_create(void) 
{ 
    struct stringlist * new_list = malloc(sizeof *new_list); 
    if (!new_list) { 
     perror("memory allocation failed"); 
     exit(EXIT_FAILURE); 
    } 

    new_list->size = DEFAULT_LIST_SIZE; 
    new_list->top = 0; 

    char ** list = calloc(new_list->size, sizeof *list); 
    if (!list) { 
     perror("memory allocation failed"); 
     exit(EXIT_FAILURE); 
    } 

    new_list->list = list; 

    return new_list; 
} 


/* Deletes the last string in the list. 
* 
* Returns false if the list was empty, otherwise true. 
*/ 

bool stringlist_delete_last(StringList list) 
{ 
    if (list->top) { 
     list->top -= 1; 
     free(list->list[list->top]); 
     list->list[list->top] = NULL; 
     return true; 
    } 
    return false; 
} 


/* Destroys the list and frees all resources */ 

void stringlist_destroy(StringList list) 
{ 
    while (stringlist_delete_last(list)) { 
     ; 
    } 
    free(list->list); 
    free(list); 
} 


/* Returns the number of strings currently in the list */ 

size_t stringlist_length(StringList list) 
{ 
    return list->top; 
} 


/* Returns the string at the specified index of the list */ 

char * stringlist_string_at_index(StringList list, const size_t index) 
{ 
    return list->list[index]; 
} 


/* Returns a pointer to the raw list of strings. 
* 
* This raw list will be NULL-terminated, that is, if the raw 
* list contains `length` strings, then raw_list[length] == NULL. 
* This makes the raw list suitable for passing, for instance, to 
* execv() and friends. 
*/ 

char ** stringlist_raw_list(StringList list) 
{ 
    return list->list; 
} 


/* Adds a string to the list. 
* 
* The raw list will be dynamically resized, if necessary. 
*/ 

void stringlist_add(StringList list, const char * str) 
{ 
    if (list->top + 1 >= list->size) { 
     char ** new_array = realloc(list->list, 
            list->size * 2 * sizeof *new_array); 
     if (!new_array) { 
      perror("memory allocation failed"); 
      exit(EXIT_FAILURE); 
     } 
     list->list = new_array; 
     list->size *= 2; 
    } 

    char * duped = strdup(str); 
    if (!duped) { 
     perror("memory allocation failed"); 
     exit(EXIT_FAILURE); 
    } 

    list->list[list->top] = duped; 
    list->top += 1; 
    list->list[list->top] = NULL; 
} 

Это добавляет некоторые проверки ошибок для пустого ввода, и отвечает на вызовы не удалось execvp() в более значимым образом.

Пример сессии:

[email protected]:~/Documents/src/sandbox/simple_shell$ ./ss 
shell$ 
shell$ 
shell$ ./Fakefile 
Error: file not found. 
shell$ ./Makefile 
Error: access denied. 
shell$ ls -alF 
total 96 
drwxr-xr-x 12 Paul staff 408 Nov 12 21:18 ./ 
drwxr-xr-x 6 Paul staff 204 Nov 12 20:42 ../ 
-rw-r--r-- 1 Paul staff 368 Nov 12 21:07 Makefile 
-rw-r--r-- 1 Paul staff 2016 Nov 12 21:18 io.c 
-rw-r--r-- 1 Paul staff 113 Nov 12 21:10 io.h 
-rw-r--r-- 1 Paul staff 2240 Nov 12 21:18 io.o 
-rw-r--r-- 1 Paul staff 1214 Nov 12 21:08 main.c 
-rw-r--r-- 1 Paul staff 1608 Nov 12 21:11 main.o 
-rwxr-xr-x 1 Paul staff 10032 Nov 12 21:18 ss* 
-rw-r--r-- 1 Paul staff 2799 Nov 12 20:52 stringlist.c 
-rw-r--r-- 1 Paul staff 504 Nov 12 20:53 stringlist.h 
-rw-r--r-- 1 Paul staff 2492 Nov 12 21:11 stringlist.o 
shell$ ps 
    PID TTY   TIME CMD 
75221 ttys002 0:00.19 -bash 
75678 ttys002 0:00.00 ./ss 
shell$ echo Hello, world! 
Hello, world! 
shell$ cat "Tokenizing input with spaces is generally bad.txt" 
cat: "Tokenizing: No such file or directory 
cat: input: No such file or directory 
cat: with: No such file or directory 
cat: spaces: No such file or directory 
cat: is: No such file or directory 
cat: generally: No such file or directory 
cat: bad.txt": No such file or directory 
shell$ exit 
[email protected]:~/Documents/src/sandbox/simple_shell$ 
Смежные вопросы