将参数传递给execvp()时出错

时间:2018-02-16 05:39:56

标签: c

我一直在努力工作几个小时,当我输入“ls”并将参数args传递给execvp()函数时,我收到错误消息“ls:无法访问'':没有这样的文件或目录”。当我在args中打印char数组时,它似乎都正确,但是当我手动输入args [0] =“ls”和args [1] =“ - l”时,一切正常。这是代码:

#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
/*
 * 
 */
int main() {
    char buffer[25];
    char exit[5] = {'e', 'x', 'i', 't', '\0'};
    while(strcmp(buffer, exit) != 0){
        //save stdin to buffer
        int i = 0, numwords = 0, k = 0, l = 0, j =0;
        char ** args;
        memset(buffer, 0, strlen(buffer));
        printf("?: ");
        while((buffer[i] = getchar()) != '\n'){
                i++;
        }
        buffer[i] = '\0';
        i = 0;
        printf("%s", buffer); 
        //start parsing and save to a char[][] args
        //get the number of words
        while( buffer[i] != '\0'){
            if(buffer[i] == ' '){
                    i++;
            }
            else if(buffer[i] != ' ' && buffer[i] != '\0'){
                numwords++;
                while(buffer[i] != ' ' && buffer[i] != '\0'){
                    i++;
                }
            }
            else{
                i++;
            }
        }
            numwords += 1; //for the null char '\0'
        args =  malloc((sizeof(char*))*numwords);

         i = 0;
        while(i < numwords){
            args[i] = malloc((sizeof(char))*(50));
            i++;
        }
        i = 0;
        printf("%d", numwords);

        //get each word from buffer and save it to temp then save temp to the array
        while( buffer[i] != '\0'){
            char temp[15];
            if(buffer[i] == ' '){
                i++;
            }
            else if(buffer[i] != ' ' && buffer[i] != '\0'){
                while(buffer[i] != ' ' && buffer[i] != '\0'){
                    temp[k] = buffer[i];
                    k++;
                    i++;
                }
            }
            else{
                i++;
            }
            if(k != 0){
                int j = 0;
                while(j < k){
                    (args)[l][j] = temp[j];
                    j++;
                }
                (args)[l][j] = '\0';
                memset(temp, 0 , strlen(temp));
                k = 0;
                l++;
            }
        }
        (args)[l][0] = '\0';
        execvp(args[0], args);
        //check printing!
//        for(i = 0; i< numwords; i++){
//            for(j = 0; j< numwords-1; j++){
//                printf("%s", args[j]);
//            }
//      printf("%s", args[1]);
//      printf("%s", args[0]);
    }
    printf("Logout Success\n");
    return 0;
}

2 个答案:

答案 0 :(得分:0)

简单的回答,当我将空字符添加到我放入的数组列表的末尾时:

args[l][0] = '\0'. 

我需要放的只是

args[l] = '\0'.

我做到了这一点并且有效!

答案 1 :(得分:0)

static void free_string_list(char** strings) {
   if (!strings)
      return;

   for (char** p = strings; *p; ++p)
      free(*p);

   free(strings);
}


// Correctly handles leading spaces.
// Correctly handles trailing spaces.
// Correctly handles multiple spaces.
// Return NULL and sets errno on error.
// Free result with free_string_list otherwise.
static char** split_into_words(const char* s) {
   size_t count = 0;
   {
      const char *src = s;
      while (1) {
         while (*src && *src == ' ')
            ++src;

         if (!*src)
            break;

         while (*src && *src != ' ')
            ++src;

         ++count;
      }
   }

   char** words = malloc(sizeof(char*) * (count+1));
   if (!words)
      goto ERROR;

   {
      const char *src = s;
      char** dst = words;
      while (1) {
         while (*src && *src == ' ')
            ++src;

         if (!*src)
            break;

         const char* src_s = src;

         while (*src && *src != ' ')
            ++src;

         const char* src_e = src;
         size_t len = src_e - src_s;
         char* dst_word = *dst = malloc(len+1);
         if (!dst_word)
            goto ERROR;

         memcpy(dst_word, src_s, len);
         dst_word[len] = 0;
         ++dst;
      }

      *dst = NULL;
   }

   return words;

ERROR:
   free_string_list(words);
   return NULL;
}


// Correctly handles exec failures (e.g. command not found and permission errors).
// Outputs error message on error.
// -1 = Error creating child or executing command.
//  0 = ok.
//  1 = Child killed or program returned an error.
int execute_command(char** cmd) {
   int pipefd[2];  // r,w
   pipefd[0] = -1;
   pipefd[1] = -1;
   if (pipe(pipefd) == -1) {
      perror("pipe");
      goto EXEC_ERROR;
   }

   {
      int flags = fcntl(pipefd[1], F_GETFD, 0);
      if (flags == -1) {
         perror("fcntl F_GETFD");
         goto EXEC_ERROR;
      }

      if (fcntl(pipefd[1], F_SETFD, flags | FD_CLOEXEC) == -1) {
         perror("fcntl F_SETFD");
         goto EXEC_ERROR;
      }
   }

   pid_t pid = fork();
   if (pid == -1) {
      perror("fork");
      goto EXEC_ERROR;
   }

   if (pid == 0) {
      close(pipefd[0]);
      execvp(cmd[0], cmd);
      int exec_errno = errno;
      perror("exec");
      write(pipe, &exec_errno, sizeof(exec_errno));
      _exit(1);
   }

   close(pipefd[1]);
   pipefd[1] = -1;

   {
      int exec_errno;
      ssize_t bytes_read = read(pipefd[0], &exec_errno, sizeof(exec_errno));
      if (bytes_read == -1) {
         perror("read");
         goto EXEC_ERROR;
      }

      if (bytes_read != 0) {
         errno = exec_errno;
         perror("exec");
         goto EXEC_ERROR;
      }
   }

   close(pipefd[0]);
   pipefd[0] = -1;

   int status;
   if (waitpid(pid, &status, 0) == -1) {
      perror("waitpid");
      goto EXEC_ERROR;
   }

   if (WIFSIGNALED(status)) {
      fprintf(stderr, "Child killed by signal %d\n", WTERMSIG(status));
      goto PROGRAM_ERROR;
   }

   if (WEXITSTATUS(status) > 0) {
      fprintf(stderr, "Child exited with error %d\n", WEXITSTATUS(status));
      goto PROGRAM_ERROR;
   }

   return 0;

EXEC_ERROR:
   if (pipefd[0] != -1) close(pipefd[0]);
   if (pipefd[1] != -1) close(pipefd[1]);
   return -1;

PROGRAM_ERROR:
   return 1;
}

int main(void) {
   int rv = 1;
   char* line = NULL;
   size_t line_size = 0;
   char** cmd = NULL;

   while (1) {
      ssize_t num_read = getline(&line, &line_size, stdin);
      if (num_read == -1) {
         if (errno) {
            perror("getline");
            goto ERROR;
         }

         break;
      }

      if (line[num_read-1] == '\n')
         line[num_read-1] = 0;

      char** cmd = split_into_words(line);
      if (!cmd) {
         perror("malloc");
         goto ERROR;
      }

      if (strcmp(cmd[0], "exit") == 0)
         break;

      if (execute_command(cmd) == -1)
         goto ERROR;

      free_string_list(cmd);
      cmd = NULL;
   }

   rv = 0;
ERROR:
   free_string_list(cmd);
   free(line);
   return rv;
}

未测试。