[C] implementation shell unix (fork, pipe)

implementation shell unix (fork, pipe) [C] - C - Programmation

Marsh Posté le 29-04-2004 à 17:01:13    

J'ai un programme à faire en C qui doit être capable d'exécuter les commandes de base suivantes :  
 
#  % ls
# % ls > filelist
# % cat filelist
# % cat < filelist
# % ls | wc
# % ls | cat | cat | cat | wc
 
les quatres premiers types de commandes fonctionnent (simples, redirections), mais j'ai des problèmes avec les pipes
 
J'avais une structure de base avec des fonctions déjà opérationnelles : parser...
 
donc il reste deux fonctions importantes :
 

Code :
  1. static char* progname;  /* name of this shell program. */
  2. static char input_buf[MAXBUF]; /* input is placed here. */
  3. static char token_buf[2 * MAXBUF]; /* tokens are placed here. */
  4. static char* input_char;  /* next character to check. */
  5. static char* token;   /* a token such as /bin/ls */
  6. static list_t* path_dir_list;  /* list of directories in PATH. */
  7. static int input_fd;  /* for i/o redirection or pipe. */
  8. static int output_fd;  /* for i/o redirection or pipe */
  9. /* run_program: fork and exec a program. */
  10. void run_program(char** argv, int argc, bool foreground, bool doing_pipe)
  11. {
  12. /* you need to fork, search for the command in argv[0],
  13.          * setup stdin and stdout of the child process, execv it.
  14.          * the parent should sometimes wait and sometimes not wait for
  15.  * the child process (you must figure out when). if foreground
  16.  * is true then basically you should wait but when we are
  17.  * running a command in a pipe such as PROG1 | PROG2 you might
  18.  * not want to wait for each of PROG1 and PROG2...
  19.  *  
  20.  * hints:
  21.  *  sprintf is useful for constructing strings.
  22.  *  access is useful for checking wether a path refers to an  
  23.  *      executable program.
  24.  *  
  25.  *  
  26.  */
  27.  int  child_pid;
  28.  char   file[MAXBUF];
  29.  sprintf(file,"/usr/bin/%s",argv[0]);
  30. if (doing_pipe) {
  31. printf("pipe\n" );
  32.  if (access(file,X_OK) == 0) {
  33.   if ((child_pid = fork()) < 0) {
  34.    perror("fork failed" );
  35.    exit(1);
  36.   }
  37.   else if (child_pid == 0) {
  38.    if (output_fd != 0) {
  39.     dup2(output_fd,1);  // > case
  40.    }
  41.    if (input_fd != 0) {
  42.     dup2(input_fd,0);  // < case
  43.    }
  44.    execv(file,argv);
  45.   }
  46.  }
  47.  else {
  48.    printf("command does not exist : %s \n",argv[0]);
  49.   }
  50. }
  51. else {
  52.  if (access(file,X_OK) == 0) {
  53.   if ((child_pid = fork()) < 0) {
  54.    perror("fork failed" );
  55.    exit(1);
  56.   }
  57.   else if (child_pid == 0) {
  58.    if (output_fd != 0) {
  59.     dup2(output_fd,1);  // > case
  60.    }
  61.    if (input_fd != 0) {
  62.     dup2(input_fd,0);  // < case
  63.    }
  64.    execv(file,argv);
  65.   }
  66.  }
  67.  else {
  68.    printf("command does not exist : %s \n",argv[0]);
  69.   }
  70. }
  71. }
  72. void parse_line(void)
  73. {
  74. char*  argv[MAX_ARG + 1];
  75. int  argc;
  76. int  pipe_fd[2]; /* 1 for producer and 0 for consumer. */
  77. token_type_t type;
  78. bool  foreground;
  79. bool  doing_pipe;
  80. input_fd = 0;
  81. output_fd = 0;
  82. argc  = 0;
  83. for (;;) {
  84.  foreground = true;
  85.  doing_pipe = false;
  86.  type = gettoken(&argv[argc]);
  87.  switch (type) {
  88.  case NORMAL:
  89.   argc += 1;
  90.   break;
  91.  case INPUT:
  92.   type = gettoken(&argv[argc]);
  93.   if (type != NORMAL) {
  94.    error("expected file name: but found %s",
  95.     argv[argc]);
  96.    return;
  97.   }
  98.   input_fd = open(argv[argc], O_RDONLY);
  99.   if (input_fd < 0)
  100.    error("cannot read from %s", argv[argc]);
  101.   break;
  102.  case OUTPUT:
  103.   type = gettoken(&argv[argc]);
  104.   if (type != NORMAL) {
  105.    error("expected file name: but found %s",
  106.     argv[argc]);
  107.    return;
  108.   }
  109.   output_fd = open(argv[argc], O_CREAT | O_WRONLY, PERM);
  110.   if (output_fd < 0)
  111.    error("cannot write to %s", argv[argc]);
  112.   break;
  113.  case PIPE:
  114.   doing_pipe = true;
  115.   pipe(pipe_fd);
  116.   output_fd = pipe_fd[1];
  117.   printf("output_fd : %d \n",output_fd);
  118.   /*FALLTHROUGH*/
  119.  case AMPERSAND:
  120.   foreground = false;
  121.   /*FALLTHROUGH*/
  122.  case NEWLINE:
  123.  case SEMICOLON:
  124.   if (argc == 0)
  125.    return;
  126.   argv[argc] = NULL;
  127.   run_program(argv, argc, foreground, doing_pipe);
  128.   input_fd = 0;
  129.   output_fd = 0;
  130.   argc  = 0;
  131.   input_fd = pipe_fd[0];
  132.   printf("input_fd : %d \n",input_fd);
  133.   if (type == NEWLINE)
  134.    return;
  135.   break;
  136.  }
  137. }
  138. }


 
 
j'explique un peu le principe : la fonction parse_line analyse la ligne de commande et place les arguments (nom de commande,"<",">","|","&",fin de ligne) dans un tableau.
Ensuite run_program est appelé. Elle a pour but de créer le nouveau processus. La partie redirection fonctionne, c'est pour la gestion des pipes que je ne m'en sors pas.


Message édité par frabill le 29-04-2004 à 18:18:47
Reply

Marsh Posté le 29-04-2004 à 17:01:13   

Reply

Marsh Posté le 29-04-2004 à 17:04:10    

1) utilise les balises de formatage de code si tu le peux
2) c'est quoi ta question?


Message édité par Moktar1er le 29-04-2004 à 17:04:38
Reply

Marsh Posté le 29-04-2004 à 17:16:40    

en fait c'est déjà du point de vue algorithmie que je ne suis pas sûr d'avoir compris
 
si je souhaite implémenter "ls | wc", le principe c'est :
1) créer un pipe : pipe (int fd[2])
2) remplacer le file descriptor 1 (stdout) de ls par fd[1]
3) remplacer le file descriptor 0 (stdin) de wc par fd[0]
 
mais avec la structure imposée je n'arrive pas à mettre ça correctement en place

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed