首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

C語言實戰:密碼驗證結合命令列參數解析與文件讀寫

     編輯:關於C語言

專案概覽

一個精簡的控制台工具,展示 密碼驗證 → 命令列參數分派 → 文本文件讀取/命令匹配/執行 的完整流程。適用於嵌入式裝置維護介面、自動化腳本前置驗證等場景。

核心功能流程

  1. 密碼驗證:預設密碼 test,最多 15 字元,錯誤即退出
  2. 參數判斷:
    • 無額外參數(argc < 2)→ 列印 command.txt 全部內容
    • 有參數 → 逐行匹配 argv[1],成功則拼接所有參數並模擬執行
  3. 文件操作:以唯讀開啟 command.txt,逐行 fgets 處理

完整代碼(已修正潛在缺陷)

/* cmd_tool.c */
#define _POSIX_C_SOURCE 200809L  /* 確保 strdup 等可用 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>   /* isatty, read */

#define MAX_LINE 1024
#define PASSWD "test"

static void secure_getpass(char *buf, size_t sz) {
    /* 簡易版:關閉回顯(POSIX) */
    if (isatty(STDIN_FILENO)) {
        system("stty -echo");
        fgets(buf, sz, stdin);
        system("stty echo");
        putchar('\n');
    } else {
        fgets(buf, sz, stdin);
    }
    buf[strcspn(buf, "\r\n")] = '\0';  /* 去除換行 */
}

int main(int argc, char *argv[]) {
    char input[32];

    /* 1. 密碼驗證 */
    while (1) {
        printf("please input password to login: ");
        secure_getpass(input, sizeof(input));
        if (strcmp(input, PASSWD) == 0) {
            puts("Enjoy it!");
            break;
        }
        puts("your password can't login.");
        return EXIT_FAILURE;
    }

    /* 2. 開啟命令檔 */
    FILE *fp = fopen("command.txt", "r");
    if (!fp) {
        perror("command.txt");
        return EXIT_FAILURE;
    }

    char line[MAX_LINE];

    /* 3. 無參數 → 列表模式 */
    if (argc < 2) {
        puts("Command List:");
        while (fgets(line, sizeof(line), fp))
            fputs(line, stdout);
        fclose(fp);
        return EXIT_SUCCESS;
    }

    /* 4. 有參數 → 匹配模式 */
    int found = 0;
    while (fgets(line, sizeof(line), fp)) {
        line[strcspn(line, "\r\n")] = '\0';  /* 去除換行再比較 */
        if (strcmp(argv[1], line) == 0) {
            found = 1;
            break;
        }
    }
    fclose(fp);

    if (!found) {
        fprintf(stderr, "sorry, can't find your command: %s\n", argv[1]);
        return EXIT_FAILURE;
    }

    /* 5. 拼接完整命令列並輸出(實際專案可改為 execvp 或系統 API 呼叫) */
    char cmd[MAX_LINE] = {0};
    for (int i = 1; i < argc; ++i) {
        strncat(cmd, argv[i], sizeof(cmd) - strlen(cmd) - 1);
        if (i + 1 < argc)
            strncat(cmd, " ", sizeof(cmd) - strlen(cmd) - 1);
    }
    printf("find the command.\nthe command is: %s\n", cmd);

    /* TODO: 實際執行邏輯,例如:
     * pid_t pid = fork();
     * if (pid == 0) { execvp(argv[1], &argv[1]); perror("exec"); _exit(127); }
     * waitpid(pid, NULL, 0);
     */
    return EXIT_SUCCESS;
}

關鍵改進點說明

原版問題改進方案
scanf("%s") 會截斷空白、無緩衝區保護自訂 secure_getpass,支援關閉回顯、防溢出、跨平台 fgets 回退
strncmp(argv[1], Buffer, strlen(Buffer)-1) 邏輯錯誤(長度含換行)先 strcspn 去除換行,再用 strcmp 精確匹配
ReceiveCommand 未初始化導致 UB初始化 char cmd[MAX_LINE] = {0};,改用 strncat 防溢出
硬編碼 exit(0/1)改用 EXIT_SUCCESS/FAILURE,語意更清晰
無錯誤碼區分perror 輸出系統錯誤碼,便於診斷

編譯與測試

$ gcc -Wall -Wextra -std=c11 cmd_tool.c -o cmd_tool
$ echo -e "backup\nrestart\nstatus" > command.txt
$ ./cmd_tool
please input password to login: test
Enjoy it!
Command List:
backup
restart
status
$ ./cmd_tool backup now
please input password to login: test
Enjoy it!
find the command.
the command is: backup now

擴展建議

  • 密碼安全:改用 crypt(3) / argon2 雜湊存儲,避免明文硬編碼
  • 命令執行:引入 fork()+execvp() 或 posix_spawn() 真正執行子程式
  • 配置檔增強:支援 # 註解、key=value 格式、INI/JSON 解析
  • 日誌系統:整合 syslog 或輕量級日誌庫(如 log.c)
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved