【问题标题】:execvp: bad address errorexecvp:错误地址错误
【发布时间】:2013-12-25 07:07:16
【问题描述】:

我正在使用 linux 来创建一个使用各种命令服务的 shell。 我有不同的内置命令,其中之一是“历史”。 我有一个reshist() 函数来重置包含用户输入的输入的数组。 我还想启用使用execvp() 的系统命令以及多管道操作。

reshist() 函数和多管道操作在不在一起时效果很好,但是当我同时使用它们时,会导致execvp() 引发“错误地址”错误。

我知道 reshist() 函数不能正确地将输入添加到列表中,但这没什么大不了的。 问题是我收到错误的原因。

可能是什么原因?有什么更好的想法可以让它们一起工作?

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdbool.h>
#include <sys/types.h>
#include <signal.h>
#include <errno.h>

#define MAX_BUFFER 129                       // max line buffer
#define MAX_ARGS 32                            // max # args
#define SEPARATORS " \t\n"                     // token sparators
char *args[MAX_ARGS];

int print[16];
int get[16];
int fd[2];

char histarr[10][129];  // History array
char histel[129];

void reshist(void)
{
  //HISTORY RESORTING

  int counter = 0;
  while (counter < 10)
  {  //shifting all elements by one from the last element of the list
    if (histarr[counter] == NULL )
    {
      strcpy(histarr[counter], histel); //first element of the history will contain the last command
      break;
    }
    counter++;
  }
  if (counter == 10)
  {
    counter = 1;
    while (counter < 10)
    {
      strcpy(histarr[counter - 1], histarr[counter]);
      counter++;
    }
    strcpy(histarr[9], histel);
  }

  memset(histel, 0, 127);
  //HISTORY RESORT ENDS
}

void setup(void)
{

  char buf[MAX_BUFFER];                      // line buffer
  //char * args[MAX_ARGS];                     // pointers to arg strings
  char ** arg;                               // working pointer thru args
  char * prompt = "333.sh>";                    // shell prompt

  /* keep reading input until "quit" command or eof of redirected input */

  while (!feof(stdin))
  {

    /* get command line from input */
    fputs(prompt, stdout);                // write prompt
    if (fgets(buf, MAX_BUFFER, stdin))
    { // read a line

      /* tokenize the input into args array */

      arg = args;
      *arg++ = strtok(buf, SEPARATORS);   // tokenize input
      while ((*arg++ = strtok(NULL, SEPARATORS)))
        ;
      // last entry will be NULL 

      strcpy(histel, buf);
      reshist();

      pid_t pid;
      int print[16];
      int get[16];
      int fd[2];

      int count = 0;
      int i = 0;
      while (args[i] != NULL )
      {
        if (0 == strcmp(args[i], "|"))
        {
          count++;
        }
        i++;
      }

      char *arrays[count + 1][i - count]; // array lines bordered as arrays[numberOfPipes+1][numberofArguments-numberOfPipes]

      i = 0;
      int x = 0;
      int y = 0;
      while (args[i] != NULL )
      {
        if (strcmp(args[i], "|") != 0)
        {
          arrays[x][y] = args[i]; //builting arrays that is going to be sent to the each process, each row of the matrix is an array to be sent to another process
          y++;
        }
        else
        {
          x++;
          y = 0;
        }
        i++;
      }

      int h = 0;
      int a = 0;
      int k = 0;
      for (k = 0; k <= count; k++)
      {

        get[k] = -1;
        print[k] = -1;
      }
      //create required number of pipes
      for (a = 0; a < count; a++)
      {
        if (pipe(fd) == -1)
        {
          perror("Pipe failure");
          continue;
        }
        get[a + 1] = fd[0];
        print[a] = fd[1];
      }

      for (k = 0; k <= count; k++)
      {

        pid = fork();

        if (pid < 0)
        {
          printf("fork failed\n");
        }
        else if (pid == 0)
        {
          if (print[k] != -1)
          {

            if (dup2(print[k], 1) == -1)
            {
              perror("dup2 error");
              exit(1);
            }
          }

          if (get[k] != -1)
          {

            if (dup2(get[k], 0) == -1)
            {
              perror("dup2read error");
              exit(1);
            }
          }

          for (h = 0; h <= count; h++)
          {
            close(print[h]);
            close(get[h]);
          }

          if (execvp((const char*) arrays[k][0], arrays[k]) < 1)
          {
            perror("error");
            exit(1);
          }

          exit(0);
        }
        else
        {
          int stat;
          close(print[k]);
          close(get[k]);
          waitpid(pid, &stat, 0);

        }

      }

    } // system command else ends         

  }
}

int main(void)
{
  setup();
  /**
   * After reading user input, the steps are:
   * (1) fork a child process using fork()
   * (2) the child process will invoke execvp()
   * (3) if command included &, parent will invoke wait()
   */
  return 0;
}

【问题讨论】:

  • 什么错误?你能把这个包括在你的问题中吗?
  • 请注意,当strtok() 将其切碎时,strcpy(histel, buf) 调用只会将第一个单词复制到histel。这也是一些人(比如我)不喜欢或不使用strtok()的原因之一。
  • 实际上while ((*arg++ = strtok(NULL, SEPARATORS))) ; 循环什么也不做,除了增加 arg 几次并将其指向缓冲区。在循环之后,缓冲区将恢复到其原始状态,并且指针将指向子字符串,所有这些都指向行尾。 (确实:strtok() 很糟糕)

标签: c linux shell exec


【解决方案1】:

代码似乎错过了NULL-终止arrays[k]。使arrays[k] 中的最后一个条目带有NULL


更新

这个

  if (execvp((const char*) arrays[k][0], arrays[k]) < 1)

应该是

  if (execvp(arrays[k][0], arrays[k]) == -1)

更直接的:

  execvp(arrays[k][0], arrays[k]);
  perror("execvp() failed");

作为exec*()-family 函数的成员返回错误。

【讨论】:

    猜你喜欢
    • 2017-07-21
    • 2019-06-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-16
    • 1970-01-01
    • 1970-01-01
    • 2010-09-08
    相关资源
    最近更新 更多