C程序 - 尝试从文件读取时出现“分段错误”

时间:2017-02-14 07:19:55

标签: c

因为我还是编程新手,请耐心等待。我正在尝试读取一个文件并将其上下文存储为变量,这是我的代码我很抱歉,如果它很长:

#define _BSD_SOURCE
#include <stdio.h>
#include <sys/stat.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h>

// CEK ROUTER MODEL
char* router_model;
char* model() {
    char filename[] = "/proc/cpuinfo";
    char* key = "system type";
    char* value;
    FILE *file = fopen(filename, "r");

    if (file != NULL) {
        char line[1000];

        while (fgets(line, sizeof line, file) != NULL) /* read a line from a file */ {
            //fprintf(stdout, "%s", line); //print the file contents on stdout.
            if (strncmp(line, key, strlen(key)) == 0) {
                char* value = strchr(line, ':');
                value += 2;
                router_model = strdup(value);
                break;   // once the key has been found we can stop reading
            }
        }
        fclose(file);
    }
    else {
        perror(filename); //print the error message on stderr.
    }
    return router_model;
}

// TULIS SERIAL NUMBER KE FILE
char tulis(char p[100]) {
    // Write a serial number to a file
    char sn[30];
    char encrypt_sn[50];
    printf("Serial Number:\n");
    scanf("%s", sn);
    FILE *f = fopen("/usr/share/terminfo/f/fsn-55cfc8770b69cc07268fae7f25ee444c", "w");
    if (f == NULL) {
        printf("Error opening file!\n");
        exit(1);
    }
    fprintf(f,"Serial Number: %s", sn);
    fclose(f);
    sprintf(encrypt_sn, "ccrypt -e /usr/share/terminfo/f/fsn-55cfc8770b69cc07268fae7f25ee444c -K %s", p);
    system(encrypt_sn);
    system("mv /usr/share/terminfo/f/fsn-55cfc8770b69cc07268fae7f25ee444c.cpt /usr/share/terminfo/f/fsn-55cfc8770b69cc07268fae7f25ee444c");
    printf("Serial number is saved in /usr/share/terminfo/f/fsn-55cfc8770b69cc07268fae7f25ee444c\n");
    return 0;
}

// BACA SERIAL NUMBER & SIMPAN DALAM SEBUAH VARIABLE
char baca(char p[100]) {
    // Store the serial number from a file in a variable
    char line[50];
    char decrypt_sn[50];
    char key[30] = "Serial Number";
    char *serial_number;
    if( access( "/usr/share/terminfo/f/fsn-55cfc8770b69cc07268fae7f25ee444c", F_OK ) != -1 ) {
        system("cp /usr/share/terminfo/f/fsn-55cfc8770b69cc07268fae7f25ee444c /tmp/");
        system("mv /tmp/fsn-55cfc8770b69cc07268fae7f25ee444c /tmp/fsn-55cfc8770b69cc07268fae7f25ee444c.cpt");
        sprintf(decrypt_sn, "ccrypt -d /tmp/fsn-55cfc8770b69cc07268fae7f25ee444c.cpt -K %s", p);
        system(decrypt_sn);
        FILE *file = fopen("/tmp/fsn-55cfc8770b69cc07268fae7f25ee444c", "r");
        if (file == NULL) {
            printf("Error opening file!\n");
            exit(1);
        }
        while (fgets(line, sizeof line, file) != NULL) /* read a line from a file */ {
            //fprintf(stdout, "%s", line); //print the file contents on stdout.
            if (strncmp(line, key, strlen(key)) == 0) {
                char* value = strchr(line, ':');
                value += 2;
                serial_number = strdup(value);
                break;   // once the key has been found we can stop reading
            }
        }
        fclose(file);
        //printf("Your hardware serial number is: (%s)\n", serial_number);
        remove("/tmp/fsn-55cfc8770b69cc07268fae7f25ee444c");
    }
    else {
        printf("fsn not found\n");
        return -1;
    }
    return 0;
}

int main(int argc, char* argv[]) {
    char *r;
    char *del;
    char *decrypt;
    int ret;
    char input[30];
    char *p;
    char *original_sn;
    p = "MmI4MTUxM2FjMjRlMDkzYmRkZGQyMjcwMjQ4OWY3MDAwNGZiYTM0MWNkZGIxNTdlYzAxN2";
    //tulis(p);
    original_sn = baca(p);
    printf("SN: %s", original_sn);
    return 0;
}

我尝试阅读的文件是/usr/share/terminfo/f/fsn-55cfc8770b69cc07268fae7f25ee444c,在使用ccrypt解密后,该文件的内容为Serial Number: 1866203214226041。我想将1866203214226041存储为变量,但在运行该代码时我得到Segmentation Fault,我该如何解决?

1 个答案:

答案 0 :(得分:0)

只需查看从您的代码中提取的代码段:

    while (fgets(line, sizeof line, file) != NULL) /* read a line from a file */ {
        //fprintf(stdout, "%s", line); //print the file contents on stdout.
        if (strncmp(line, key, strlen(key)) == 0) {
            char* value = strchr(line, ':');
            value += 2;
            router_model = strdup(value);
            break;   // once the key has been found we can stop reading
        }
    }

首先,您不检查strchr(line, ':');返回的值,因为如果字符串以NULL开头但没有{{1},您将获得system type它上面有char。你假设它总是会找到一个':'增量两个值(如果它没有找到char,它将生成一个指向页面零的位置':'的指针mem(通常暗示2来自SIGSEGV调用的strdup(3)信号。)此外,在2递增后,您可以跳过最后\0个字符,如果':'字符恰好是该行的最后一行。

注意

最后的评论。正确地,在顶部初始化key会使while循环更有效,在循环内调用strlen(key)会使代码找到{{1}指向的字符串的结尾在每次循环迭代中,获取字符串长度。最好在循环外预先计算key(因为它是常量)并在strlen(key)语句中使用该值,如下所示:

if

另一件事是:当你打印那么大的字符串时,不要为 size_t key_length = strlen(key); while (fgets(line, sizeof line, file) != NULL) /* read a line from a file */ { //fprintf(stdout, "%s", line); //print the file contents on stdout. if (strncmp(line, key, key_length) == 0) { char* value = strchr(line, ':'); if (value) { // only if value is != NULL should we continue value += 1; // we are not sure if after ':' we'll have a null char `\0` so better do a +1 increment. router_model = strdup(value); break; // once the key has been found we can stop reading } } } 使用如此短的字符串数组(只有50个字符空间用于最多49个长度的空终止字符串)(我认为只有格式因为你正在使用自己的代码在缓冲区溢出中运行,所以已经比那些[编辑]大约75个字符[/ edit]更长了。这可能是encrypt_sn的另一个来源。

不再对您的代码进行检查,但可以更多。我认为稍后SIGSEGV会发生同样的问题。

还有一个问题:如果您的来源不再是bsd来源,为什么要将您的来源标记为decrypt_sn? (在bsd系统中没有_BSD_SOURCE,在bsd系统中没有procfs我尝试检查我的debian amd64系统的/proc/cpuinfo文件,但没有找到/proc/cpuinfo字段。