在子进程中,使用memcpy或strcpy将c字符串从一个缓冲区复制到另一个缓冲区似乎不起作用

在子进程中,使用memcpy或strcpy将c字符串从一个缓冲区复制到另一个缓冲区似乎不起作用,c,C,我正在尝试编写一个模拟shell,它保存命令行历史记录并覆盖SIGINT的信号操作,以触发打印用户输入的前10个命令。据我所知,从处理所有信号到更新光标和使用execvp运行命令,一切都很好 然而,我遇到了两个问题,我很难去想办法解决 尝试将输入缓冲区的内容实际复制到我自己的c字符串向量(即histv)时遇到问题。调用read并将用户输入存储在buf中后,我尝试将buf的内容复制到histv[光标%MAX\u历史记录]的位置。(我使用模数的原因是,使用一种圆形数组似乎更容易,而不是处理光标上升到

我正在尝试编写一个模拟shell,它保存命令行历史记录并覆盖
SIGINT
的信号操作,以触发打印用户输入的前10个命令。据我所知,从处理所有信号到更新光标和使用
execvp
运行命令,一切都很好

然而,我遇到了两个问题,我很难去想办法解决

  • 尝试将输入缓冲区的内容实际复制到我自己的c字符串向量(即
    histv
    )时遇到问题。调用
    read
    并将用户输入存储在
    buf
    中后,我尝试将
    buf
    的内容复制到
    histv[光标%MAX\u历史记录]的位置。
    (我使用模数的原因是,使用一种圆形数组似乎更容易,而不是处理光标上升到大于某个数字的情况。
    MAX\u HISTORY

  • 当我尝试将进程作为后台进程运行时,我总是会收到execvp错误,即使命令有效。我知道这是在父进程收到
    SIGUSR2
    信号并创建一个新的子进程来运行命令之后发生的。因此我假设这与child pro之后发生的
    argv
    有关cess自杀并引发
    SIGUSR2

  • 下面是整个程序的代码。有些地方有点凌乱,但总体来说相当简单。我使用了所有的
    memcpy
    strcpy
    、和
    strncpy
    ,但都没有用。它们都编译和运行时没有错误,但它们似乎都没有做任何事情

    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <signal.h>
    #include <string.h>
    #include <sys/mman.h>
    #include <sys/types.h>
    #include <sys/wait.h>
    
    // limits
    #define MAX_LINE 80
    #define MAX_HISTORY 10
    
    // function headers
    void print_history(unsigned int const, char**);
    void handler_func(int);
    void read_func(char*[], char[], char**, unsigned int const);
    int parse_args(char*, char**, size_t);
    
    // globals
    volatile sig_atomic_t sig_caught = 0;
    
    void print_history (const unsigned int cursor, char **histv) {
        int temp = (cursor > MAX_HISTORY) ? (cursor - MAX_HISTORY) : 0;
    
        puts("\n\nprinting the previous ten commands...");
        printf("cursor %d", cursor);
    
        for (int i = 1; temp < cursor; temp++) {
            printf("%d%s\n", i++, histv[temp % MAX_HISTORY]);
        }
    }
    
    void handler_func(int sig)
    {   
        /* update loop control variable */
        sig_caught = 1;
    }
    
    int main(void)
    {
        // declare sigaction struct
        struct sigaction sigactor;
    
        // initialize sigaction struct
        sigactor.sa_handler = handler_func;
        sigemptyset(&sigactor.sa_mask);
        sigactor.sa_flags = 0;
    
        // set up sigaction for SIGINT
        if (sigaction(SIGINT, &sigactor, NULL) == -1) {
            perror("siagction() failed");
            _exit(EXIT_FAILURE);
        }
    
    
        // set the buffer to no buffering
        setvbuf(stdout, NULL, _IONBF, 0);
    
        unsigned int cursor = 0;
    
        /* initlialize history vector */
        char **histv = (char**)malloc(sizeof(char*) * MAX_HISTORY);
        for (int i = 0; i < MAX_HISTORY; i++) 
            histv[i] = (char*)malloc(sizeof(char) * MAX_LINE);
    
        // enter shell loop
        while (1) {
    
            /* fork process and get child pid */
            int cpid;
    
            char *argsv[MAX_LINE/2+1];
            char buf[MAX_LINE];
    
    
            while(!sig_caught) {
    
                cpid = fork();
    
                /* child */
                if (cpid == 0) {
                    read_func(argsv, buf, histv, cursor);
                }
    
                /* fork error */
                else if (cpid < 0) {
                    perror("Error forking process");
                    _exit(EXIT_FAILURE);
                }
    
                /* parent process begins here */
                else {
    
                    /* variable to store status returned from child*/
                    int cstatus;
    
                    /* suspend parent until child exits *
                     * store return status in cstatus   */
                    waitpid(cpid, &cstatus, 0);
    
                    /* get status from child process and check for SIGTERM *
                     * SIGTERM is raised by child when someone enters '!q' */
                    switch(WTERMSIG(cstatus))
                    {
                    /* user wants to quit */
                    case SIGTERM:
                        puts("User issued quit command");
                        for (int i = 0; i < MAX_HISTORY; i++) 
                            free((void *)histv[i]);
                        free((void *)histv);
                        _exit(EXIT_SUCCESS);
    
                    /* invalid string length */
                    case SIGUSR1: 
                        puts("Please enter a valid string");
                        break;
    
                    /* background process */
                    case SIGUSR2:
                        cpid = fork();
                        if (cpid < 0) perror("Error forking process...");
                        else if (cpid == 0) {
                            if (execvp(argsv[0], argsv) < 0) {
                                --cursor;
                                perror("execvp");
                                kill(getpid(), SIGUSR1);
                            }
                        }
                    }
    
                    if (!sig_caught) cursor++;
                }
    
            }// signal loop
    
            kill (cpid, SIGTERM);
            print_history(cursor, histv);
            fflush(stdout);
            sig_caught = 0;
    
        }
    }
    
    void read_func(char *argsv[], char buf[], char *histv[], unsigned int const cursor)
    {
        printf("\nCMD > ");
    
        int background = 0;
    
        size_t length = read(STDIN_FILENO, buf, MAX_LINE);
    
        if (length > 80 || length <= 0) kill(getpid(), SIGUSR1);
    
        /* copy buffer into history and update cursor */
        memcpy(histv[cursor % MAX_HISTORY], buf, length);
    
        printf("cursor %d", cursor);
        /* parse arguments and return number of arguments */
        background = parse_args(buf, argsv, length);
    
        /* user entered quit command or string is invalid */
        if (background == -1) kill(getpid(), SIGTERM);
    
        /* signal parent to run process in the background */
        if (background == 1) kill(getpid(), SIGUSR2);
    
        /* run command */
        if (execvp(argsv[0], argsv) < 0) {
            perror("execvp");
            _exit(EXIT_FAILURE);
        }
    
    }
    
    int parse_args(char buf[], char *argsv[], size_t length)
    {
    
        int i,      /* loop index for accessing buf array */
            start,  /* index where beginning of next command parameter is */
            ct,     /* index of where to place the next parameter into args[] */
            bckg;   /* background flag */
    
    
        /* read what the user enters on the command line */
        ct = 0;
        start = -1;
        bckg = 0;
    
        if (buf[0] == '!' && buf[1] == 'q') return -1;
    
        /* examine every character in the buf */
        for (i = 0; i < length; i++) {
            switch (buf[i]){
                case ' ':
                case '\t':       /* argument separators */
                    if(start != -1){
                        argsv[ct] = &buf[start];    /* set up pointer */
                        ct++;
                    }
                    buf[i] = '\0'; /* add a null char; make a C string */
                    start = -1;
                    break;
    
                case '\n':                 /* should be the final char examined */  
                    if (start != -1){
                        argsv[ct] = &buf[start];
                        ct++;
                    }
                    buf[i] = '\0';
                    argsv[ct] = NULL; /* no more arguments to this command */
                    break;
    
                case '&':
                    bckg = 1;
                    buf[i] = '\0';
                    break;
    
                default:             /* some other character */
                    if (start == -1)
                        start = i;
            }
        }
        argsv[ct] = NULL; /* just in case the input line was > 80 */
    
        return bckg;
    }
    
    
    #包括
    #包括
    #包括
    #包括
    #包括
    #包括
    #包括
    #包括
    //极限
    #定义最大行80
    #定义最大历史记录10
    //函数头
    无效打印历史记录(无符号整型常量,字符**);
    void handler_func(int);
    void read_func(char*[],char[],char**,unsigned int const);
    int parse_args(char*,char**,size_t);
    //全球的
    挥发性sig_原子sig_t sig_捕获=0;
    无效打印历史记录(常量无符号整数光标,字符**histv){
    int temp=(光标>最大历史记录)?(光标-最大历史记录):0;
    puts(“\n\n打印前十个命令…”);
    printf(“光标%d”,光标);
    对于(int i=1;温度<光标;温度++){
    printf(“%d%s\n”,i++,histv[temp%MAX_HISTORY]);
    }
    }
    无效处理程序_func(int sig)
    {   
    /*更新循环控制变量*/
    sig_=1;
    }
    内部主(空)
    {
    //声明sigaction结构
    结构sigactor;
    //初始化sigaction结构
    sigactor.sa_handler=handler_func;
    sigemptyset(&sigactor.sa_mask);
    sigactor.sa_标志=0;
    //为SIGINT设置sigaction
    if(sigaction(SIGINT,&sigactor,NULL)=-1){
    perror(“siagaction()失败”);
    _退出(退出失败);
    }
    //将缓冲区设置为无缓冲
    setvbuf(标准输出,空,0);
    无符号整数游标=0;
    /*初始化历史向量*/
    char**histv=(char**)malloc(sizeof(char*)*MAX_HISTORY);
    对于(int i=0;i”);
    int背景=0;
    大小长度=读取(标准文件号、buf、最大行);
    如果(长度>80 | |长度80*/
    返回bckg;
    }
    
    旁注,
    parse_args
    函数最初是给我们的,我对它做了一些修改,以便与程序的其余部分一起工作,但在大多数情况下,我并没有编写该函数

    请对我放松点,我已经很久没有用C来做任何事情了,我在这里做的很多事情都花了很多时间
    char **histv = (char**)malloc(sizeof(char*) * MAX_HISTORY);
    for (int i = 0; i < MAX_HISTORY; i++) 
        histv[i] = (char*)malloc(sizeof(char) * MAX_LINE);
    
    char **histv = (char**)mmap(NULL, (sizeof(char*) * MAX_HISTORY), (PROT_READ | PROT_WRITE), (MAP_SHARED | MAP_ANONYMOUS), -1, 0);
    for (int i = 0; i < MAX_HISTORY; i++) histv[i] = (char*)mmap(NULL,  (sizeof(char) * MAX_LINE), (PROT_READ | PROT_WRITE), (MAP_SHARED | MAP_ANONYMOUS), -1, 0);