openssl3.2 - linux脚本(.sh)调用openssl命令行参数的简单确认方法

这篇具有很好参考价值的文章主要介绍了openssl3.2 - linux脚本(.sh)调用openssl命令行参数的简单确认方法。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

openssl3.2 - linux脚本(.sh)调用openssl命令行参数的简单确认方法

概述

在琢磨官方工程中的/test/certs中的2个脚本(setup.sh, mkcert.sh)
这2个脚本有不到500个openssl命令行调用, 应该是openssl内部测试证书操作的脚本.
确定这2个脚本是好东西(将证书操作一网打尽, 弄清了这2个脚本, 就没有不会的证书操作了).

但是脚本调用, 到了调用openssl时, 参数拼接很烦人, 我只想看具体到了openssl的可执行文件, 到底给了啥命令行参数.
有一些参数是用管道给的, 用stdin给的一个buffer代表一个参数文件, 这很烦啊.
官方给用户的正式例子, 都是用 in 参数, 然后给一个文件名. 这样多清爽.
.sh又不熟, 想将.sh改成可以传文件名给openssl的例子, 可能要花多一些时间.
一直在琢磨是否有更好的方法能确定最终的openssl命令行参数, 突然想到, 为啥不直接将openssl实现给改了, 在程序入口, 写几句日志, 将命令行参数记录下来, 这不一了百了啊. 研究啥.sh怎么写啊.
只要确定给了啥命令行参数, 那就好办了.
我已经编译好了在windows下可用的VS2019的openssl.exe的工程, 那就在自己工程中, 舒舒服服的调试好了(openssl3.2 - 自己构建openssl.exe的VS工程(在编译完的源码版本上), openssl3.2 - 在VS2019下源码调试openssl.exe).

笔记

修改openssl实现的前置条件

已经在debian12.4下, 配置, 编译, 测试, 安装都通过了.
且配置了debian12.4, 让本地普通目录中运行openssl命令行已经好使(openssl3.2 - 编译).

修改debian12.4下编译好的openssl实现, 将入口参数记录下来

参照我重建的win版openssl.exe工程, 可知 main()函数在openssl.c
去debian12.4下原版源码目录中确定是./apps/openssl.c

修改如下, 只在程序入口处, 加了一段日志文件的操作, 将openssl可执行文件的命令行参数附加到日志文件.

static char *help_argv[] = { "help", NULL };
static char *version_argv[] = { "version", NULL };

int main(int argc, char *argv[])
{
    FUNCTION f, *fp;
    LHASH_OF(FUNCTION) *prog = NULL;
    char *pname;
    const char *fname;
    ARGS arg;
    int global_help = 0;
    int global_version = 0;
    int ret = 0;

    int i = 0;
    FILE* pfLog = NULL;

    // 将入参全部写入文件待调试, 去看.sh太繁琐了
    if (1)
    {
        pfLog = fopen("/home/lostspeed/openssl/my_openssl_log.txt", "a");
        if (NULL != pfLog)
        {
            for (i = 0; i < argc; i++)
            {
                fwrite(argv[i], sizeof(char), strlen(argv[i]), pfLog);
                // 每个参数中间加一个空格
                fwrite(" ", sizeof(char), 1, pfLog);
            }

            // 追加完一次openssl命令行调用, 换一行
            fwrite("\r\n", sizeof(char), 2, pfLog);

            fclose(pfLog);
            pfLog = NULL;
        }
    }

    arg.argv = NULL;
    arg.size = 0;

在正常的工程中, 只进行make, make install

测试效果

在普通目录中运行了2个命令

openssl version -a 
openssl --help

查看自己指定的位置确实有日志文件.

lostspeed@debian12d4x64:~/openssl$ pwd
/home/lostspeed/openssl
lostspeed@debian12d4x64:~/openssl$ ls -l
总计 488136
-rw-r--r--  1 lostspeed lostspeed        38  1月20日 22:29 my_openssl_log.txt
drwxr-xr-x 26 lostspeed lostspeed      4096  1月20日 21:13 openssl-3.2.0_debian
-rw-r--r--  1 lostspeed lostspeed 482136966  1月20日 21:17 openssl-3.2.0_debian.tar.gz
-rwxr-xr-x  1 root      root       17698352  1月20日 13:55 openssl-3.2.0.tar.gz

查看此日志文件

lostspeed@debian12d4x64:~/openssl$ cat ./my_openssl_log.txt 
openssl version -a 
openssl --help 
lostspeed@debian12d4x64:~/openssl$ 

备注

这方法好使.
那我下一步就将setup.sh改成每次只执行一个命令的版本. e.g. setup1.sh, setup2.sh.
知道了具体的命令行操作, 那么就可以去win版的openssl.exe工程去查, 将stdin给出的参数文件流内容, 改为可以落地的参数和文件名.
那我也不用去改debian12.4下的那2个.sh脚本了, 调试强度一下子就降低好多.

补充 - 将管道文件记录到本地文件

脚本传递文件时, 到了openssl入口, 可以看到传进来的是一个管道文件名.

openssl req -new -sha256 -key root-key.pem -config /dev/fd/63

需要将这个管道文件也保存到日志中, 这样就知道了openssl命令行的所有参数, 就可以在windows下的openssl.exe的vs2019中开心的调试了.
将openssl.c又完善了一下, 对openssl.c的修改部分如下:

static char *help_argv[] = { "help", NULL };
static char *version_argv[] = { "version", NULL };

// /home/lostspeed/openssl/openssl-3.2.0_debian/test/certs/my_openssl_linux_log.txt
// D:\\my_dev\\my_local_git_prj\\study\\openSSL\\test_certs\\my_openssl_win_log.txt


#ifdef _WIN32
#define MY_LOG_DIR "D:\\my_dev\\my_local_git_prj\\study\\openSSL\\test_certs"
#define MY_LOG_FILE "my_openssl_win_log.txt"
#define MY_LOG_FILE_PATH_NAME MY_LOG_DIR "\\" MY_LOG_FILE

#define MY_PIPE_FILE "cmd_line_pipe_in_win.txt"
#define MY_PIPE_FILE_OUT_PATH_NAME MY_LOG_DIR "\\" MY_PIPE_FILE
#else
// -config /dev/fd/63
#define MY_LOG_DIR "/home/lostspeed/openssl/openssl-3.2.0_debian/test/certs"
#define MY_LOG_FILE "my_openssl_linux_log.txt"
#define MY_LOG_FILE_PATH_NAME MY_LOG_DIR "/" MY_LOG_FILE

#define MY_PIPE_FILE "cmd_line_pipe_in_linux.txt"
#define MY_PIPE_FILE_OUT_PATH_NAME MY_LOG_DIR "/" MY_PIPE_FILE
#endif // #ifdef _WIN32

void read_file_write_to_another(const char* pszFileSrc, const char* pszFileDst)
{
    FILE* fpSrc = NULL;
    FILE* fpDst = NULL;
    char szBuf[4096];
    size_t nRdBk = 0;

    do {
        if ((NULL == pszFileSrc) || (NULL == pszFileDst))
        {
            break;
        }
          
        fpSrc = fopen(pszFileSrc, "r");
        if (NULL == fpSrc)
        {
            break;
        }

        fpDst = fopen(pszFileDst, "a");
        if (NULL == fpDst) 
        {
            break;
        }

        // 在向管道记录文件附加新内容之前, 在每个文件前面加3个空行, 可以区分出多个文件
        fwrite("\r\n", sizeof(char), 2, fpDst);
        fwrite("\r\n", sizeof(char), 2, fpDst);
        fwrite("\r\n", sizeof(char), 2, fpDst);

        do {
            nRdBk = fread(szBuf, sizeof(char), sizeof(szBuf), fpSrc);
            if (nRdBk <= 0)
            {
                break;
            }

            fwrite(szBuf, sizeof(char), nRdBk, fpDst);

        } while (1);

    } while (0);

    if (NULL != fpSrc)
    {
        fclose(fpSrc);
        fpSrc = NULL;
    }

    if (NULL != fpDst)
    {
        fclose(fpDst);
        fpDst = NULL;
    }
}

void wirte_cmd_line_param_to_log_file(int argc, char* argv[])
{
    int i = 0;
    FILE* pfLog = NULL;
    const char* psz_argv = NULL;

    // 将入参全部写入文件待调试, 去看.sh太繁琐了
    if (1)
    {
        // 将程序的命令行参数记录进日志文件
        pfLog = fopen(MY_LOG_FILE_PATH_NAME, "a");
        if (NULL != pfLog)
        {
            for (i = 0; i < argc; i++)
            {
                // 程序的名称都为"openssl"
                psz_argv = ((0 != i) ? argv[i] : "openssl");
                fwrite(psz_argv, sizeof(char), strlen(psz_argv), pfLog);
                

                // 每个参数中间加一个空格
                fwrite(" ", sizeof(char), 1, pfLog);
            }

            // 追加完一次openssl命令行调用, 换一行
            fwrite("\r\n", sizeof(char), 2, pfLog);

            fclose(pfLog);
            pfLog = NULL;
        }

        // 将管道文件记录进配置文件
        for (i = 0; i < argc; i++)
        {
            // -config /dev/fd/63
            if (0 == strcmp(argv[i], "-config"))
            {
                if ((i + 1) < argc)
                {
                    if (0 == strcmp(argv[i + 1], "/dev/fd/63"))
                    {
                        read_file_write_to_another(argv[i + 1], MY_PIPE_FILE_OUT_PATH_NAME);
                    }
                }

                break;
            }
        }
    }
}

int main(int argc, char *argv[])
{
    FUNCTION f, *fp;
    LHASH_OF(FUNCTION) *prog = NULL;
    char *pname;
    const char *fname;
    ARGS arg;
    int global_help = 0;
    int global_version = 0;
    int ret = 0;

    wirte_cmd_line_param_to_log_file(argc, argv);

    arg.argv = NULL;
    arg.size = 0;

修改后的openssl.c在windows下和debian12.4下是通用的. 编译安装后, 好使.

效果

lostspeed@debian12d4x64:~/openssl/openssl-3.2.0_debian/test/certs$ pwd
/home/lostspeed/openssl/openssl-3.2.0_debian/test/certs
lostspeed@debian12d4x64:~/openssl/openssl-3.2.0_debian/test/certs$ ls -l
总计 104
-rwxr-xr-x 1 lostspeed lostspeed 11679  1月21日 14:05 mkcert.sh
-rwxr-xr-x 1 lostspeed lostspeed 11679  1月21日 14:05 mkcert.sh.bk
-rwxr-xr-x 1 lostspeed lostspeed   111  1月21日 14:05 my_lib.sh
-rwxr-xr-x 1 lostspeed lostspeed 17315  1月21日 14:05 openssl.c
-rwxr-xr-x 1 lostspeed lostspeed  1704  1月21日 14:05 root-key.pem
-rwxr-xr-x 1 lostspeed lostspeed   388  1月21日 14:05 setup001.sh
-rwxr-xr-x 1 lostspeed lostspeed 23948  1月21日 14:05 setup.sh
-rwxr-xr-x 1 lostspeed lostspeed 23948  1月21日 14:05 setup.sh.bk
lostspeed@debian12d4x64:~/openssl/openssl-3.2.0_debian/test/certs$ 

lostspeed@debian12d4x64:~/openssl/openssl-3.2.0_debian/test/certs$ cat ./setup001.sh 
#! /bin/bash

# \file setup001.sh

# printf "%s\n" "hello openssl"

# my_lib.sh fn_to_file <(printf "hello 1")
# ./my_lib.sh fn_to_file param1 param2

# fn_to_file()
#{
#    printf ">> fn_to_file\n"
#
#    printf "%s\n" "$@"
#}

# printf ">> setup001.sh\n"
# fn_to_file < <(printf "stdin to function\n")

# Primary root: root-cert
./mkcert.sh genroot "Root CA" root-key root-cert

exit 0

lostspeed@debian12d4x64:~/openssl/openssl-3.2.0_debian/test/certs$ ./setup001.sh 


lostspeed@debian12d4x64:~/openssl/openssl-3.2.0_debian/test/certs$ ls -l
总计 112
-rw-r--r-- 1 lostspeed lostspeed    87  1月21日 14:13 cmd_line_pipe_in_linux.txt // 记录管道输入给命令行的配置文件
-rwxr-xr-x 1 lostspeed lostspeed 11679  1月21日 14:05 mkcert.sh
-rwxr-xr-x 1 lostspeed lostspeed 11679  1月21日 14:05 mkcert.sh.bk
-rwxr-xr-x 1 lostspeed lostspeed   111  1月21日 14:05 my_lib.sh
-rw-r--r-- 1 lostspeed lostspeed    64  1月21日 14:13 my_openssl_linux_log.txt // 记录命令行的日志文件
-rwxr-xr-x 1 lostspeed lostspeed 17315  1月21日 14:05 openssl.c
-rwxr-xr-x 1 lostspeed lostspeed  1704  1月21日 14:05 root-key.pem // 干活后的输出文件
-rwxr-xr-x 1 lostspeed lostspeed   388  1月21日 14:05 setup001.sh
-rwxr-xr-x 1 lostspeed lostspeed 23948  1月21日 14:05 setup.sh
-rwxr-xr-x 1 lostspeed lostspeed 23948  1月21日 14:05 setup.sh.bk

lostspeed@debian12d4x64:~/openssl/openssl-3.2.0_debian/test/certs$ cat ./my_openssl_linux_log.txt 
openssl req -new -sha256 -key root-key.pem -config /dev/fd/63 

lostspeed@debian12d4x64:~/openssl/openssl-3.2.0_debian/test/certs$ cat ./cmd_line_pipe_in_linux.txt 



string_mask=utf8only
[req]
prompt = no
distinguished_name = dn
[dn]
CN = Root CA

备注

调试材料的准备:
将cmd_line_pipe_in_linux.txt中的原来管道传来的配置文件内容保存成一个配置文件. e.g. tmp.cfg
将my_openssl_linux_log.txt 记录的openssl命令行参数中的管道配置文件 /dev/fd/63 改为tmp.cfg
新的可以在本地单步调试的命令行为 : openssl req -new -sha256 -key root-key.pem -config tmp.cfg

这就可以正常单步调试了.
剩下的事情, 就是将官方原来的/test/certs/setup.sh中的不到500条证书操作命令, 全部整理成单条的脚本.
然后单独运行一条脚本, 得到一组openssl的命令行, 自己单步跟一下, 知道了openssl对命令行参数的要求就行了.

一天搞50个, 10天搞定:P

补充 - 要考虑到管道的读

管道读, 读一个字节, 管道里面少一个字节.
如果想将管道中的东西保存成文件供调试用, 那么程序用的管道数据就没有了.
想了一个解决方法, 我从管道读出的内容, 我是知道的. 将管道读出的内容保存成文件供调试.
然后再将自己读出的buffer, 再写入管道. 模拟自己没动过管道的数据
试了一下好使, 不影响openssl自带的功能.

#endif /* OPENSSL_NO_TRACE */

static char *help_argv[] = { "help", NULL };
static char *version_argv[] = { "version", NULL };

// /home/lostspeed/openssl/openssl-3.2.0_debian/test/certs/my_openssl_linux_log.txt
// D:\\my_dev\\my_local_git_prj\\study\\openSSL\\test_certs\\my_openssl_win_log.txt


#ifdef _WIN32
#define MY_LOG_DIR "D:\\my_dev\\my_local_git_prj\\study\\openSSL\\test_certs"
#define MY_LOG_FILE "my_openssl_win_log.txt"
#define MY_LOG_FILE_PATH_NAME MY_LOG_DIR "\\" MY_LOG_FILE

#define MY_PIPE_FILE "cmd_line_pipe_in_win.txt"
#define MY_PIPE_FILE_OUT_PATH_NAME MY_LOG_DIR "\\" MY_PIPE_FILE
#else
// -config /dev/fd/63
#define MY_LOG_DIR "/home/lostspeed/openssl/openssl-3.2.0_debian/test/certs"
#define MY_LOG_FILE "my_openssl_linux_log.txt"
#define MY_LOG_FILE_PATH_NAME MY_LOG_DIR "/" MY_LOG_FILE

#define MY_PIPE_FILE "cmd_line_pipe_in_linux.txt"
#define MY_PIPE_FILE_OUT_PATH_NAME MY_LOG_DIR "/" MY_PIPE_FILE
#endif // #ifdef _WIN32

void read_file_write_to_another(const char* pszFileSrc, const char* pszFileDst)
{
#define MY_BUFFER_SIZE (1024 * 1024)
    FILE* fpSrc = NULL;
    FILE* fpDst = NULL;

    char* pSzBuf = NULL; // 开个1MB的空间, 从管道中读出来后, 保存进文件, 再写进管道, 这样相当于没有动管道
    size_t nRdBk = 0;
    size_t nWrBk = 0;
    size_t nRdBkAll = 0;

    do {
        if ((NULL == pszFileSrc) || (NULL == pszFileDst))
        {
            break;
        }

        pSzBuf = malloc(MY_BUFFER_SIZE);
        if (NULL == pSzBuf)
        {
            break;
        }
          
        fpSrc = fopen(pszFileSrc, "r");
        if (NULL == fpSrc)
        {
            break;
        }

        fpDst = fopen(pszFileDst, "a");
        if (NULL == fpDst) 
        {
            break;
        }

        // 在向管道记录文件附加新内容之前, 在每个文件前面加3个空行, 可以区分出多个文件
        fwrite("\r\n", sizeof(char), 2, fpDst);
        fwrite("\r\n", sizeof(char), 2, fpDst);
        fwrite("\r\n", sizeof(char), 2, fpDst);

        nRdBkAll = 0;
        do {
            nRdBk = fread(pSzBuf + nRdBkAll, sizeof(char), 1024, fpSrc);
            if (nRdBk <= 0)
            {
                break;
            }

            nWrBk = fwrite(pSzBuf, sizeof(char), nRdBk, fpDst);
            if (nWrBk != nRdBk)
            {
                printf("error : write to fpDst => write to = %zu, return form write = %zu\n", nRdBk, nWrBk);
                break;
            }

            nRdBkAll += nRdBk;
        } while (1);
        

        fclose(fpSrc); // 关掉源文件

        // 管道读之后, 指针挪动了. 尝试将指针移动到管道开头
        // fseek(fpSrc, 0, 0); // 不好使, 从管道中读了东西后, 管道中的东西就没有了

        // 管道中的东西, 读出来后, 就消失了, 再模拟将读出来的东西, 写进入试试. 模拟我没动管道中的东西
        fpSrc = fopen(pszFileSrc, "w");
        if (NULL == fpSrc)
        {
            break;
        }

        nRdBk = fwrite(pSzBuf, sizeof(char), nRdBkAll, fpSrc); 
        if (nRdBk != nRdBkAll)
        {
            printf("error : rewrite to pipe => nRdBkAll = %zu, nRdBk = %zu\n", nRdBkAll, nRdBk);
        }
    } while (0);

    if (NULL != pSzBuf)
    {
        free(pSzBuf);
        pSzBuf = NULL;
    }

    if (NULL != fpSrc)
    {
        fclose(fpSrc);
        fpSrc = NULL;
    }

    if (NULL != fpDst)
    {
        fclose(fpDst);
        fpDst = NULL;
    }
}

void wirte_cmd_line_param_to_log_file(int argc, char* argv[])
{
    int i = 0;
    FILE* pfLog = NULL;
    const char* psz_argv = NULL;

    // 将入参全部写入文件待调试, 去看.sh太繁琐了
    if (1)
    {
        // 将程序的命令行参数记录进日志文件
        pfLog = fopen(MY_LOG_FILE_PATH_NAME, "a");
        if (NULL != pfLog)
        {
            for (i = 0; i < argc; i++)
            {
                // 程序的名称都为"openssl"
                psz_argv = ((0 != i) ? argv[i] : "openssl");
                fwrite(psz_argv, sizeof(char), strlen(psz_argv), pfLog);
                

                // 每个参数中间加一个空格
                fwrite(" ", sizeof(char), 1, pfLog);
            }

            // 追加完一次openssl命令行调用, 换一行
            fwrite("\r\n", sizeof(char), 2, pfLog);

            fclose(pfLog);
            pfLog = NULL;
        }

        // 将管道文件记录进配置文件
        for (i = 0; i < argc; i++)
        {
            // -config /dev/fd/63
            if (0 == strcmp(argv[i], "-config"))
            {
                if ((i + 1) < argc)
                {
                    if (0 == strcmp(argv[i + 1], "/dev/fd/63"))
                    {
                        read_file_write_to_another(argv[i + 1], MY_PIPE_FILE_OUT_PATH_NAME);

                        // 如果将管道指着移动到管道的头部还好使, 那就和未修改程序前相同
                        // 管道中的东西, 读出来就没有了, 不过, 我已经又将读出来的东西, 又写回去了
                        // read_file_write_to_another(argv[i + 1], MY_PIPE_FILE_OUT_PATH_NAME);
                    }
                }

                break;
            }
        }
    }
}

int main(int argc, char *argv[])
{
    FUNCTION f, *fp;
    LHASH_OF(FUNCTION) *prog = NULL;
    char *pname;
    const char *fname;
    ARGS arg;
    int global_help = 0;
    int global_version = 0;
    int ret = 0;

    // 打印自己的版本号标记
    if ((2 == argc) && (0 == strcmp("-v", argv[1])))
    {
        printf("ls modify openSSL3.2.0_build_002 last build 2024/1/21 17:27:00\n");
    }

    wirte_cmd_line_param_to_log_file(argc, argv);

    arg.argv = NULL;
    arg.size = 0;

    /* Set up some of the environment. */
    bio_in = dup_bio_in(FORMAT_TEXT);
    bio_out = dup_bio_out(FORMAT_TEXT);
    bio_err = dup_bio_err(FORMAT_TEXT);

bug_fix - 补充-extfile时的管道

调试着, 发现有点不对劲.
看着官方.sh, 每个openssl命令行用管道传进来的东西都不应该为空啊.
查了一下, 原来管道进来时, 前面参数是 -config 或者 -extfile, 这2个参数后面跟的才是管道名.
我看花眼了, 只处理了 -config后面的管道文件内容记录.
修正了一下.

static char *help_argv[] = { "help", NULL };
static char *version_argv[] = { "version", NULL };

// /home/lostspeed/openssl/openssl-3.2.0_debian/test/certs/my_openssl_linux_log.txt
// D:\\my_dev\\my_local_git_prj\\study\\openSSL\\test_certs\\my_openssl_win_log.txt


#ifdef _WIN32
#define MY_LOG_DIR "D:\\my_dev\\my_local_git_prj\\study\\openSSL\\test_certs"
#define MY_LOG_FILE "my_openssl_win_log.txt"
#define MY_LOG_FILE_PATH_NAME MY_LOG_DIR "\\" MY_LOG_FILE

#define MY_PIPE_FILE "cmd_line_pipe_in_win.txt"
#define MY_PIPE_FILE_OUT_PATH_NAME MY_LOG_DIR "\\" MY_PIPE_FILE
#else
// -config /dev/fd/63
#define MY_LOG_DIR "/home/lostspeed/openssl/openssl-3.2.0_debian/test/certs"
#define MY_LOG_FILE "my_openssl_linux_log.txt"
#define MY_LOG_FILE_PATH_NAME MY_LOG_DIR "/" MY_LOG_FILE

#define MY_PIPE_FILE "cmd_line_pipe_in_linux.txt"
#define MY_PIPE_FILE_OUT_PATH_NAME MY_LOG_DIR "/" MY_PIPE_FILE
#endif // #ifdef _WIN32

void read_file_write_to_another(const char* pszCfgName, const char* pszFileSrc, const char* pszFileDst)
{
#define MY_BUFFER_SIZE (1024 * 1024)
    FILE* fpSrc = NULL;
    FILE* fpDst = NULL;

    char* pSzBuf = NULL; // 开个1MB的空间, 从管道中读出来后, 保存进文件, 再写进管道, 这样相当于没有动管道
    size_t nRdBk = 0;
    size_t nWrBk = 0;
    size_t nRdBkAll = 0;

    do {
        if ((NULL == pszCfgName) || (NULL == pszFileSrc) || (NULL == pszFileDst))
        {
            break;
        }

        pSzBuf = malloc(MY_BUFFER_SIZE);
        if (NULL == pSzBuf)
        {
            break;
        }
          
        fpSrc = fopen(pszFileSrc, "r");
        if (NULL == fpSrc)
        {
            break;
        }

        fpDst = fopen(pszFileDst, "a");
        if (NULL == fpDst) 
        {
            break;
        }

        // 在向管道记录文件附加新内容之前, 在每个文件前面加3个空行, 可以区分出多个文件
        fwrite("\r\n", sizeof(char), 2, fpDst);
        fprintf(fpDst, "%s %s => %s\n", pszCfgName, pszFileSrc, pszFileDst); // tip msg
        fwrite("\r\n", sizeof(char), 2, fpDst);
        fwrite("\r\n", sizeof(char), 2, fpDst);
        fwrite("\r\n", sizeof(char), 2, fpDst);

        nRdBkAll = 0;
        do {
            nRdBk = fread(pSzBuf + nRdBkAll, sizeof(char), 1024, fpSrc);
            if (nRdBk <= 0)
            {
                break;
            }

            nWrBk = fwrite(pSzBuf, sizeof(char), nRdBk, fpDst);
            if (nWrBk != nRdBk)
            {
                printf("error : write to fpDst => write to = %zu, return form write = %zu\n", nRdBk, nWrBk);
                break;
            }

            nRdBkAll += nRdBk;
        } while (1);
        

        fclose(fpSrc); // 关掉源文件

        // 管道读之后, 指针挪动了. 尝试将指针移动到管道开头
        // fseek(fpSrc, 0, 0); // 不好使, 从管道中读了东西后, 管道中的东西就没有了

        // 管道中的东西, 读出来后, 就消失了, 再模拟将读出来的东西, 写进入试试. 模拟我没动管道中的东西
        fpSrc = fopen(pszFileSrc, "w");
        if (NULL == fpSrc)
        {
            break;
        }

        nRdBk = fwrite(pSzBuf, sizeof(char), nRdBkAll, fpSrc); 
        if (nRdBk != nRdBkAll)
        {
            printf("error : rewrite to pipe => nRdBkAll = %zu, nRdBk = %zu\n", nRdBkAll, nRdBk);
        }
    } while (0);

    if (NULL != pSzBuf)
    {
        free(pSzBuf);
        pSzBuf = NULL;
    }

    if (NULL != fpSrc)
    {
        fclose(fpSrc);
        fpSrc = NULL;
    }

    if (NULL != fpDst)
    {
        fclose(fpDst);
        fpDst = NULL;
    }
}

void wirte_cmd_line_param_to_log_file(int argc, char* argv[])
{
    int i = 0;
    FILE* pfLog = NULL;
    const char* psz_argv = NULL;

    // 将入参全部写入文件待调试, 去看.sh太繁琐了
    if (1)
    {
        // 将程序的命令行参数记录进日志文件
        pfLog = fopen(MY_LOG_FILE_PATH_NAME, "a");
        if (NULL != pfLog)
        {
            for (i = 0; i < argc; i++)
            {
                // 程序的名称都为"openssl"
                psz_argv = ((0 != i) ? argv[i] : "openssl");
                fwrite(psz_argv, sizeof(char), strlen(psz_argv), pfLog);
                

                // 每个参数中间加一个空格
                fwrite(" ", sizeof(char), 1, pfLog);
            }

            // 追加完一次openssl命令行调用, 换一行
            fwrite("\r\n", sizeof(char), 2, pfLog);

            fclose(pfLog);
            pfLog = NULL;
        }

        // 将管道文件记录进配置文件
        for (i = 0; i < argc; i++)
        {
            // -config /dev/fd/63
            if (
                (0 == strcmp(argv[i], "-config"))
                || (0 == strcmp(argv[i], "-extfile"))
                ) 
            {
                if ((i + 1) < argc)
                {
                    // if (0 == strcmp(argv[i + 1], "/dev/fd/63"))
                    {
                        read_file_write_to_another(argv[i], argv[i + 1], MY_PIPE_FILE_OUT_PATH_NAME);

                        // 如果将管道指着移动到管道的头部还好使, 那就和未修改程序前相同
                        // 管道中的东西, 读出来就没有了, 不过, 我已经又将读出来的东西, 又写回去了
                        // read_file_write_to_another(argv[i + 1], MY_PIPE_FILE_OUT_PATH_NAME);
                    }
                }

                break;
            }
        }
    }
}

int main(int argc, char *argv[])
{
    FUNCTION f, *fp;
    LHASH_OF(FUNCTION) *prog = NULL;
    char *pname;
    const char *fname;
    ARGS arg;
    int global_help = 0;
    int global_version = 0;
    int ret = 0;

    // 打印自己的版本号标记
    if ((2 == argc) && (0 == strcmp("-v", argv[1])))
    {
        printf("ls modify openSSL3.2.0_build_003 last build 2024/1/22 10:23:00\n");
    }

    wirte_cmd_line_param_to_log_file(argc, argv);

    arg.argv = NULL;
    arg.size = 0;

修正 - 将日志文件改为一个文件

将openssl程序入口截取的到所有内容都记录到一个日志文件中, 否则调试时太不方便了.

static char *help_argv[] = { "help", NULL };
static char *version_argv[] = { "version", NULL };

// /home/lostspeed/openssl/openssl-3.2.0_debian/test/certs/my_openssl_linux_log.txt
// D:\\my_dev\\my_local_git_prj\\study\\openSSL\\test_certs\\my_openssl_win_log.txt


// 将命令行和管道内容都记录到一个日志文件中, 方便调试
#ifdef _WIN32
#define MY_LOG_DIR "D:\\my_dev\\my_local_git_prj\\study\\openSSL\\test_certs"
#define MY_LOG_FILE "my_openssl_win_log.txt"
#define MY_LOG_FILE_PATH_NAME MY_LOG_DIR "\\" MY_LOG_FILE

#else
// -config /dev/fd/63
#define MY_LOG_DIR "/home/lostspeed/openssl/openssl-3.2.0_debian/test/certs"
#define MY_LOG_FILE "my_openssl_linux_log.txt"
#define MY_LOG_FILE_PATH_NAME MY_LOG_DIR "/" MY_LOG_FILE

#endif // #ifdef _WIN32

void read_file_write_to_another(const char* pszCfgName, const char* pszFileSrc, const char* pszFileDst)
{
#define MY_BUFFER_SIZE (1024 * 1024)
    FILE* fpSrc = NULL;
    FILE* fpDst = NULL;

    char* pSzBuf = NULL; // 开个1MB的空间, 从管道中读出来后, 保存进文件, 再写进管道, 这样相当于没有动管道
    size_t nRdBk = 0;
    size_t nWrBk = 0;
    size_t nRdBkAll = 0;

    do {
        if ((NULL == pszCfgName) || (NULL == pszFileSrc) || (NULL == pszFileDst))
        {
            break;
        }

        pSzBuf = malloc(MY_BUFFER_SIZE);
        if (NULL == pSzBuf)
        {
            break;
        }
          
        fpSrc = fopen(pszFileSrc, "r");
        if (NULL == fpSrc)
        {
            break;
        }

        fpDst = fopen(pszFileDst, "a");
        if (NULL == fpDst) 
        {
            break;
        }

        // 在向管道记录文件附加新内容之前, 在每个文件前面加3个空行, 可以区分出多个文件
        fwrite("\r\n", sizeof(char), 2, fpDst);
        fprintf(fpDst, "%s %s => %s\n", pszCfgName, pszFileSrc, pszFileDst); // tip msg
        fwrite("\r\n", sizeof(char), 2, fpDst);
        fwrite("\r\n", sizeof(char), 2, fpDst);
        fwrite("\r\n", sizeof(char), 2, fpDst);

        nRdBkAll = 0;
        do {
            nRdBk = fread(pSzBuf + nRdBkAll, sizeof(char), 1024, fpSrc);
            if (nRdBk <= 0)
            {
                break;
            }

            nWrBk = fwrite(pSzBuf, sizeof(char), nRdBk, fpDst);
            if (nWrBk != nRdBk)
            {
                printf("error : write to fpDst => write to = %zu, return form write = %zu\n", nRdBk, nWrBk);
                break;
            }

            nRdBkAll += nRdBk;
        } while (1);
        

        fclose(fpSrc); // 关掉源文件

        // 管道读之后, 指针挪动了. 尝试将指针移动到管道开头
        // fseek(fpSrc, 0, 0); // 不好使, 从管道中读了东西后, 管道中的东西就没有了

        // 管道中的东西, 读出来后, 就消失了, 再模拟将读出来的东西, 写进入试试. 模拟我没动管道中的东西
        fpSrc = fopen(pszFileSrc, "w");
        if (NULL == fpSrc)
        {
            break;
        }

        nRdBk = fwrite(pSzBuf, sizeof(char), nRdBkAll, fpSrc); 
        if (nRdBk != nRdBkAll)
        {
            printf("error : rewrite to pipe => nRdBkAll = %zu, nRdBk = %zu\n", nRdBkAll, nRdBk);
        }
    } while (0);

    if (NULL != pSzBuf)
    {
        free(pSzBuf);
        pSzBuf = NULL;
    }

    if (NULL != fpSrc)
    {
        fclose(fpSrc);
        fpSrc = NULL;
    }

    if (NULL != fpDst)
    {
        fclose(fpDst);
        fpDst = NULL;
    }
}

void wirte_cmd_line_param_to_log_file(int argc, char* argv[])
{
    int i = 0;
    FILE* pfLog = NULL;
    const char* psz_argv = NULL;

    // 将入参全部写入文件待调试, 去看.sh太繁琐了
    if (1)
    {
        // 将程序的命令行参数记录进日志文件
        pfLog = fopen(MY_LOG_FILE_PATH_NAME, "a");
        if (NULL != pfLog)
        {
            for (i = 0; i < argc; i++)
            {
                // 程序的名称都为"openssl"
                psz_argv = ((0 != i) ? argv[i] : "openssl");
                fwrite(psz_argv, sizeof(char), strlen(psz_argv), pfLog);
                

                // 每个参数中间加一个空格
                fwrite(" ", sizeof(char), 1, pfLog);
            }

            // 追加完一次openssl命令行调用, 换一行
            fwrite("\r\n", sizeof(char), 2, pfLog);

            fclose(pfLog);
            pfLog = NULL;
        }

        // 将管道文件记录进配置文件
        for (i = 0; i < argc; i++)
        {
            // -config /dev/fd/63
            if (
                (0 == strcmp(argv[i], "-config"))
                || (0 == strcmp(argv[i], "-extfile"))
                ) 
            {
                if ((i + 1) < argc)
                {
                    // if (0 == strcmp(argv[i + 1], "/dev/fd/63"))
                    {
                        read_file_write_to_another(argv[i], argv[i + 1], MY_LOG_FILE_PATH_NAME);

                        // 如果将管道指着移动到管道的头部还好使, 那就和未修改程序前相同
                        // 管道中的东西, 读出来就没有了, 不过, 我已经又将读出来的东西, 又写回去了
                        // read_file_write_to_another(argv[i + 1], MY_PIPE_FILE_OUT_PATH_NAME);
                    }
                }

                break;
            }
        }
    }
}

int main(int argc, char *argv[])
{
    FUNCTION f, *fp;
    LHASH_OF(FUNCTION) *prog = NULL;
    char *pname;
    const char *fname;
    ARGS arg;
    int global_help = 0;
    int global_version = 0;
    int ret = 0;

    // 打印自己的版本号标记
    if ((2 == argc) && (0 == strcmp("-v", argv[1])))
    {
        printf("ls modify openSSL3.2.0_build_005 last build 2024/1/22 13:06:00\n");
    }

    wirte_cmd_line_param_to_log_file(argc, argv);

    arg.argv = NULL;
    arg.size = 0;

修正 - 需要考虑同一选项出现多次的情况

在调试官方脚本时发现, 居然可以同一选项出现多次. e.g. -extfile 在有些脚本调用openssl时, 一个命令行中出现了2次.
只能将选项从头找到尾.文章来源地址https://www.toymoban.com/news/detail-812130.html

static char *help_argv[] = { "help", NULL };
static char *version_argv[] = { "version", NULL };

// /home/lostspeed/openssl/openssl-3.2.0_debian/test/certs/my_openssl_linux_log.txt
// D:\\my_dev\\my_local_git_prj\\study\\openSSL\\test_certs\\my_openssl_win_log.txt


// 将命令行和管道内容都记录到一个日志文件中, 方便调试
#ifdef _WIN32
#define MY_LOG_DIR "D:\\my_dev\\my_local_git_prj\\study\\openSSL\\test_certs"
#define MY_LOG_FILE "my_openssl_win_log.txt"
#define MY_LOG_FILE_PATH_NAME MY_LOG_DIR "\\" MY_LOG_FILE

#else
// -config /dev/fd/63
#define MY_LOG_DIR "/home/lostspeed/openssl/openssl-3.2.0_debian/test/certs"
#define MY_LOG_FILE "my_openssl_linux_log.txt"
#define MY_LOG_FILE_PATH_NAME MY_LOG_DIR "/" MY_LOG_FILE

#endif // #ifdef _WIN32

void read_file_write_to_another(const char* pszCfgName, const char* pszFileSrc, const char* pszFileDst)
{
#define MY_BUFFER_SIZE (1024 * 1024)
    FILE* fpSrc = NULL;
    FILE* fpDst = NULL;

    char* pSzBuf = NULL; // 开个1MB的空间, 从管道中读出来后, 保存进文件, 再写进管道, 这样相当于没有动管道
    size_t nRdBk = 0;
    size_t nWrBk = 0;
    size_t nRdBkAll = 0;

    do {
        if ((NULL == pszCfgName) || (NULL == pszFileSrc) || (NULL == pszFileDst))
        {
            break;
        }

        pSzBuf = malloc(MY_BUFFER_SIZE);
        if (NULL == pSzBuf)
        {
            break;
        }
          
        fpSrc = fopen(pszFileSrc, "r");
        if (NULL == fpSrc)
        {
            break;
        }

        fpDst = fopen(pszFileDst, "a");
        if (NULL == fpDst) 
        {
            break;
        }

        // 在向管道记录文件附加新内容之前, 在每个文件前面加3个空行, 可以区分出多个文件
        fwrite("\r\n", sizeof(char), 2, fpDst);
        fprintf(fpDst, "%s %s => %s\n", pszCfgName, pszFileSrc, pszFileDst); // tip msg
        fwrite("\r\n", sizeof(char), 2, fpDst);
        fwrite("\r\n", sizeof(char), 2, fpDst);
        fwrite("\r\n", sizeof(char), 2, fpDst);

        nRdBkAll = 0;
        do {
            nRdBk = fread(pSzBuf + nRdBkAll, sizeof(char), 1024, fpSrc);
            if (nRdBk <= 0)
            {
                break;
            }

            nWrBk = fwrite(pSzBuf, sizeof(char), nRdBk, fpDst);
            if (nWrBk != nRdBk)
            {
                printf("error : write to fpDst => write to = %zu, return form write = %zu\n", nRdBk, nWrBk);
                break;
            }

            nRdBkAll += nRdBk;
        } while (1);
        

        fclose(fpSrc); // 关掉源文件

        // 管道读之后, 指针挪动了. 尝试将指针移动到管道开头
        // fseek(fpSrc, 0, 0); // 不好使, 从管道中读了东西后, 管道中的东西就没有了

        // 管道中的东西, 读出来后, 就消失了, 再模拟将读出来的东西, 写进入试试. 模拟我没动管道中的东西
        fpSrc = fopen(pszFileSrc, "w");
        if (NULL == fpSrc)
        {
            break;
        }

        nRdBk = fwrite(pSzBuf, sizeof(char), nRdBkAll, fpSrc); 
        if (nRdBk != nRdBkAll)
        {
            printf("error : rewrite to pipe => nRdBkAll = %zu, nRdBk = %zu\n", nRdBkAll, nRdBk);
        }
    } while (0);

    if (NULL != pSzBuf)
    {
        free(pSzBuf);
        pSzBuf = NULL;
    }

    if (NULL != fpSrc)
    {
        fclose(fpSrc);
        fpSrc = NULL;
    }

    if (NULL != fpDst)
    {
        fclose(fpDst);
        fpDst = NULL;
    }
}

void wirte_cmd_line_param_to_log_file(int argc, char* argv[])
{
    int i = 0;
    FILE* pfLog = NULL;
    const char* psz_argv = NULL;

    // 将入参全部写入文件待调试, 去看.sh太繁琐了
    if (1)
    {
        // 将程序的命令行参数记录进日志文件
        pfLog = fopen(MY_LOG_FILE_PATH_NAME, "a");
        if (NULL != pfLog)
        {
            for (i = 0; i < argc; i++)
            {
                // 程序的名称都为"openssl"
                psz_argv = ((0 != i) ? argv[i] : "openssl");
                fwrite(psz_argv, sizeof(char), strlen(psz_argv), pfLog);
                

                // 每个参数中间加一个空格
                fwrite(" ", sizeof(char), 1, pfLog);
            }

            // 追加完一次openssl命令行调用, 换一行
            fwrite("\r\n", sizeof(char), 2, pfLog);

            fclose(pfLog);
            pfLog = NULL;
        }

        // 将管道文件记录进配置文件
        for (i = 0; i < argc; i++)
        {
            // -config /dev/fd/63
            if (
                (0 == strcmp(argv[i], "-config"))
                || (0 == strcmp(argv[i], "-extfile"))
                ) 
            {
                if ((i + 1) < argc)
                {
                    // if (0 == strcmp(argv[i + 1], "/dev/fd/63"))
                    {
                        read_file_write_to_another(argv[i], argv[i + 1], MY_LOG_FILE_PATH_NAME);

                        // 如果将管道指着移动到管道的头部还好使, 那就和未修改程序前相同
                        // 管道中的东西, 读出来就没有了, 不过, 我已经又将读出来的东西, 又写回去了
                        // read_file_write_to_another(argv[i + 1], MY_PIPE_FILE_OUT_PATH_NAME);
                    }
                }

                // 这里不能break, 发现一个openssl命令行可以跟多个 -extfile 选项
            }
        }
    }
}

int main(int argc, char *argv[])
{
    FUNCTION f, *fp;
    LHASH_OF(FUNCTION) *prog = NULL;
    char *pname;
    const char *fname;
    ARGS arg;
    int global_help = 0;
    int global_version = 0;
    int ret = 0;

    // 打印自己的版本号标记
    if ((2 == argc) && (0 == strcmp("-v", argv[1])))
    {
        printf("ls modify openSSL3.2.0_build_006 last build 2024/1/23 18:01:00\n");
    }

    wirte_cmd_line_param_to_log_file(argc, argv);

    arg.argv = NULL;
    arg.size = 0;

END

到了这里,关于openssl3.2 - linux脚本(.sh)调用openssl命令行参数的简单确认方法的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • linux中编写.sh脚本并赋权限问题

    以项目启动、重启、终止脚本为例: 步骤: 首先 vi start.sh 、 vi restart.sh 、 vi stop.sh 或者使用 vim 编辑器; 编辑内容: 启动: vi start.sh 重启: vi restart.sh 关闭: vi stop.sh 保存并退出; chmod +x start.sh restart.sh stop.sh 赋予可执行权限; 输入 ./start.sh 、 ./restart.sh 、 ./stop.sh 执行脚

    2024年02月04日
    浏览(36)
  • Linux执行sh脚本文件提示Permission denied

    在Linux终端运行脚本文件时,提示Permission denied,意思是权限不足。 解决方法:检查文件权限,权限不足时,赋予执行权限 使用chmod更改文件权限:      -R:是级联应用到目录里的所有子目录和文件      777:是所有用户都拥有最高权限

    2024年02月16日
    浏览(62)
  • Linux终端执行.sh脚本,提示权限不够的解决办法

    错误提示如下: [root]# ./run_train_p bash: ./run_train_p: 权限不够 解决方法 [root]# chmod 777 ./run_train_p [root]# ./run_train_p

    2024年02月14日
    浏览(47)
  • 如何写一个sh脚本将一个本地文件通过 scp命令上传到远程的 centos服务器?

    这篇博文分享如何使用 scp 和 expect 命令写一个脚本来自动填充密码并实现自动登录并上传文件到服务器。 假设目标服务器: 192.168.159.175 远程文件服务器登录账号假设是 root 远程文件服务器登录密码假设是 toor /Users/zhaoqingfeng/downloads/test/dist/ 是前端打包部署文件夹 将 /Users/

    2024年02月09日
    浏览(54)
  • [含完整代码]Linux使用.sh脚本自动部署(启动|停止|状态|日志)项目[超详细]

    个人博客: www.wdcdbd.com   我们在linux部署.jar项目时,都需要通过java -jar的形式来部署,每次都要手动停止,部署,这样用起来会很麻烦。所以,这篇文章就是自己通过.sh脚本一键 启动 , 停止 , 重启 , 查看状态 , 查看日志 。这样会方便一些。  将你的java项目放到你lin

    2024年01月19日
    浏览(55)
  • 远程Linux/ubuntu服务器后台不间断运行py文件/sh脚本

    通常我们在生产环境中运行一些项目时需要将程序不间断的运行在服务器上,并且将日志文件打印到某个文件中,直到程序运行结束,下面介绍了在Linux服务器上不间断运行py文件的方式,以及如何保存相应的日志信息。 对于 .py 文件,在对应路径下运行远程终端命令行指令:

    2024年02月10日
    浏览(47)
  • linux命令之sh的用法

    shell简介:sh命令就是shell,而我们知道shell的作用是什么?shell就是用来解释linux命令的,我们输入命令,指示linux帮我们做什么,而linux本身是看不懂我们输入的命令的,它只认识01,而事实显然不是如此, 那么在用户和linux之间必然有个桥梁起到了转换的作用,这里的桥梁就

    2024年02月09日
    浏览(31)
  • 【Linux】为.sh脚本制作桌面快捷方式(.desktop,可双击执行),且替换显示图标(图文详情)

    目录 0.背景+环境 1、原理 2、详细步骤  1)创建.desktop快捷方式 2) 给test.desktop快捷方式增加可执行权限 3)编辑test.desktop内容和参数 4)修改快捷方式属性为双击可执行 5)将桌面快捷方式发送到桌面 ubuntu 16.04 项目需求,目前有一个可执行程序(test.sh),test.sh这个脚本是执

    2024年02月13日
    浏览(46)
  • jenkins 设置参数和调用bat脚本

    例如 路径为:F:Program Files (x86)lua-5.4.4_Win64_binWorkSpaceDoTestLua.bat 在对应流水线触发脚本里写: cd /d 后面输入指定需要执行文件的绝对路径 最后调用 call 调用文件bat 即可 1.先创建一个 freeStyle 2.在 This progject is parametterized 勾上 选择你需要的参数类型 我这里选String Parameter 3.然

    2024年02月02日
    浏览(41)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包