简单shell中的分段错误

时间:2021-02-27 08:53:05

I am writing code for a simplistic c shell. It stores the history of the last 10 command. If 'r' is entered as a command, then it should run the most recent command from the history. Also, if 'r x' is entered, where 'x' is the first letter of the command to be executed from history, then it runs the most recent command that start with that letter.

我正在编写一个简单的c shell代码。它存储了最后10个命令的历史记录。如果输入“r”作为命令,则它应该从历史记录中运行最新的命令。此外,如果输入“r x”,其中“x”是要从历史记录执行的命令的第一个字母,则它将运行以该字母开头的最新命令。

I've run into an issue copying from the history to the inputBuffer; it gives a segmentation fault when I try to do it.

我遇到了从历史复制到inputBuffer的问题;当我尝试这样做时,它会出现分段错误。

Here is the code (it's messy I've been trying a lot of different things in hopes of fixing it). Any advice would be greatly appreciated!

这是代码(它很混乱,我一直在尝试很多不同的东西,希望修复它)。任何建议将不胜感激!

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>


#define MAX_LINE 80 /* 80 chars per line, per command, should be enough. */
#define BUFFER_SIZE 50

#define buffer "Command History:\n"

char history[10][MAX_LINE];
int count = 0;
int caught = 0;
int ct =0;
int rFlag =0;

/**
* setup() reads in the next command line, separating it into distinct tokens
 * using whitespace as delimiters. setup() sets the args parameter as a 
 * null-terminated string.
 */

void shell(void);

void printHistory()
{
      int i;
  int j = 0;
  int hcount = count;

      for (i = 0; i<10;i++)
    {
      printf("%d. ", hcount);
      while (history[i][j] != '\n' && history[i][j] != '\0'){
      printf("%c", history[i][j]);
      j++;
    }
   printf("\n");
   j = 0;   

   hcount--;
   if (hcount ==  0)
    break;
   }


}   

/* the signal handler function */
void handle_SIGINT() 
{
  write(STDOUT_FILENO,buffer,sizeof(buffer));
  printHistory();
  printf("\nCOMMAND->");
  caught = 1;
}


void setup(char inputBuffer[], char *args[],int *background)
{
  int k;
  int length, /* # of characters in the command line */
    i,     /* loop index for accessing inputBuffer array */
    start;  /* index where beginning of next command parameter is */
  //ct     /* index of where to place the next parameter into args[] */

  ct = 0;

  printf("Setup");

  /* read what the user enters on the command line */
  if (rFlag!=1)
    {
  length = read(STDIN_FILENO, inputBuffer, MAX_LINE); 
  rFlag = 0;
    }
   printf("buff=%i", strlen(inputBuffer));
  if (caught == 1)
{
  length = read(STDIN_FILENO, inputBuffer, MAX_LINE);
  caught = 0;
}

  if ((strcmp(inputBuffer,"r\n\0")!=0) && (strncmp(inputBuffer, "r x", 2)!=0))
    {
      for (i = 9;i>0; i--)
    {
      strcpy(history[i], history[i-1]);
    }
      strcpy(history[0],inputBuffer); //this works
      count++;
    }


start = -1;
 if (length == 0)
  exit(0);            /* ^d was entered, end of user command stream */
if (length < 0){ 
  perror("error reading the command\n");
  exit(-1);           /* terminate with error code of -1 */
}


  /* examine every character in the inputBuffer */

       printf("beforeCase");
for (i=0;i<length;i++) 
  {
switch (inputBuffer[i])
  {
  case ' ':
  case '\t' :               /* argument separators */
    if(start != -1)
      {
    args[ct] = &inputBuffer[start];    /* set up pointer */
    ct++;
      }
    inputBuffer[i] = '\0'; /* add a null char; make a C string */
    start = -1;
    break;

  case '\n':                 /* should be the final char examined */
    if (start != -1){
      args[ct] = &inputBuffer[start];     
      ct++;
    }
    inputBuffer[i] = '\0';
    args[ct] = NULL; /* no more arguments to this command */
    break;  

  default :             /* some other character */
    if (start == -1)
      start = i;
    if (inputBuffer[i] == '&'){
      *background  = 1;
      inputBuffer[i] = '\0';
    }
  } 
  }    

args[ct] = NULL; /* just in case the input line was > 80 */

}

int main(void)
{
  char inputBuffer[MAX_LINE]; /* buffer to hold the command entered */
  int background;             /* equals 1 if a command is followed by '&' */
  char *args[MAX_LINE/+1];/* command line (of 80) has max of 40 arguments */
  pid_t pid;
  char iBuffer2[MAX_LINE];
  int i;

  /* set up the signal handler */
  struct sigaction handler;
  handler.sa_handler = handle_SIGINT; 
  sigaction(SIGINT, &handler, NULL);
  while (1){            /* Program terminates normally inside setup */
   background = 0;
    printf("COMMAND->");
   fflush(0);
   setup(inputBuffer, args, &background);/* get next command */

   if ((strcmp(args[0],"r")==0) && (ct==1))
   {
    fflush(0);
  rFlag = 1;
  background = 0;
  printf("strlen=%i", strlen(history[0]));
  setup(history[0], args, &background);
  printf("AFTER");

}

if (strcmp(args[0],"exit")==0)break; //exits if args[0]=="exit"
pid_t pid = fork();
if (pid < 0) { //Error Occured
  fprintf(stderr, "Fork Failed");
  exit(-1);
}
else if (pid == 0) {//Child Process
  execvp(args[0], args); // Execute command in args
  printf("%s: Command not found.\n", args[0]); //If invalid command
  exit(0);
}
  else { // Parent Process
if (background == 0) { // case with No '&'
  wait(NULL);
}
  }
printf("\nFinish\n");
}
}

2 个解决方案

#1


2  

catchsegv can be used to create a stack trace when a program terminates with a segmentation fault. http://www.linuxfromscratch.org/lfs/view/stable/chapter06/glibc.html

当程序以分段错误终止时,catchsegv可用于创建堆栈跟踪。 http://www.linuxfromscratch.org/lfs/view/stable/chapter06/glibc.html

#2


2  

If you are going to use low level i/o then it is your responsibility to NUL terminate the data after doing a read() before doing any string operations on the data read.

如果您要使用低级别的i / o,那么在对数据读取执行任何字符串操作之前,NUL在执行read()之后终止数据是您的责任。

length = read(STDIN_FILENO, inputBuffer, MAX_LINE-1);
if (length > 0)
   inputBuffer[length] = '\0';
else
   inputBuffer[0] = '\0';

But read() is probably not what you want to be using in the first place, as you seem to be expecting to be given a line at a time. Try using fgets() instead.

但是read()可能不是你想要首先使用的东西,因为你似乎希望一次得到一条线。请尝试使用fgets()。

#1


2  

catchsegv can be used to create a stack trace when a program terminates with a segmentation fault. http://www.linuxfromscratch.org/lfs/view/stable/chapter06/glibc.html

当程序以分段错误终止时,catchsegv可用于创建堆栈跟踪。 http://www.linuxfromscratch.org/lfs/view/stable/chapter06/glibc.html

#2


2  

If you are going to use low level i/o then it is your responsibility to NUL terminate the data after doing a read() before doing any string operations on the data read.

如果您要使用低级别的i / o,那么在对数据读取执行任何字符串操作之前,NUL在执行read()之后终止数据是您的责任。

length = read(STDIN_FILENO, inputBuffer, MAX_LINE-1);
if (length > 0)
   inputBuffer[length] = '\0';
else
   inputBuffer[0] = '\0';

But read() is probably not what you want to be using in the first place, as you seem to be expecting to be given a line at a time. Try using fgets() instead.

但是read()可能不是你想要首先使用的东西,因为你似乎希望一次得到一条线。请尝试使用fgets()。