标签 Linux 下的文章

几乎每次跟新都会有问题。

certbot每次生成的新证书会放在/etc/letsencrypt/archive/<site-domain>-0001/下面,这个0001会随着次数增加,所以每次更新的证书都不是在apache原配置文件指向的位置,所以得更新。
(certbot生成的结果一般显示/etc/letsencrypt/live/...,但实际上这里只保存软连接,真实文件在archive下)

sudo nano /etc/apache2/sites-available/default-ssl.conf

有时候是什么000-default-ssl.conf文件,自己辨别一下
比如我有次更新的是:

        ServerName grav1ty.cn
        # 使得 Apache 能够识别来自该域名的请求

        SSLCertificateFile /etc/letsencrypt/live/<site-domain>-0002/fullchain.pem
        SSLCertificateKeyFile /etc/letsencrypt/live/<site-domain>-0002/privkey.pem
        Include /etc/letsencrypt/options-ssl-apache.conf
        # 包含了 Let’s Encrypt 提供的 SSL 配置选项,这通常是推荐的做法,可以提高 SSL 配置的安全性

把里面0002换成0003即可。

检查的时候可以用

openssl s_client -connect :443
查看证书信息,不用每次用浏览器还要清空缓存什么的。

另记:

        SSLCertificateFile      /etc/ssl/certs/ssl-cert-snakeoil.pem
        SSLCertificateKeyFile   /etc/ssl/private/ssl-cert-snakeoil.key

这是apache默认的文件。


此次更新archlinux,又出现了kwallet输入密码且wifi密码需要重新输入的问题。
kwallet是kde管理密码的工具,不只是钱包。
解决办法是

yay -S kwallet-pam

更新报错

xxx签名未知/已过期/不受信任

解决方法

sudo pacman -S archlinux-keyring
sudo pacman-key --refresh-keys
sudo pacman-key --init
sudo pacman-key --populate
sudo pacman -Scc

然后再次更新即可


更新发现KDE只支持2K60Hz,但显示器支持2K165Hz。

#生成一个模型ine,然后使用输出结果中的信息添加模式
cvt 2560 1440 165

#eg.
☁  ~  cvt 2560 1440 165

# 2560x1440 164.90 Hz (CVT) hsync: 261.86 kHz; pclk: 938.50 MHz
Modeline "2560x1440_165.00"  938.50  2560 2792 3072 3584  1440 1443 1448 1588 -hsync +vsync
#!/bin/bash
# 添加新模式: 使用生成的模型线来添加新的显示模式
xrandr --newmode "2560x1440_165.00"  938.50  2560 2792 3072 3584  1440 1443 1448 1588 -hsync +vsync
# 将模式添加到显示器: 然后将该模式添加到你的HDMI-A-2输出
xrandr --addmode HDMI-A-2 "2560x1440_165.00"
# 切换到新的模式
xrandr --output HDMI-A-2 --mode "2560x1440_165.00"

如果还无效,尝试添加或修改X配置/etc/X11/xorg.conf.d/10-monitor.conf:

Section "Monitor"
    Identifier "HDMI-A-2"
    Modeline "2560x1440_165.00"  938.50  2560 2792 3072 3584  1440 1443 1448 1588 -hsync +vsync
    Option "PreferredMode" "2560x1440_165.00"
EndSection

Section "Screen"
    Identifier "Screen0"
    Monitor "HDMI-A-2"
EndSection

另记:
使用 sudo systemctl restart display-manager 会重启图形登录管理器,这将导致当前用户的会话被终止,并结束所有与该用户相关的进程。这样会关闭所有打开的应用程序和窗口,所以在执行此命令之前,最好先保存你的工作并关闭不需要的程序。

Linux

1.__attribute__((constructor)) and __attribute__((destructor))

void __attribute__((constructor)) my_constructor()
{
    printf("加载\n");
}

void __attribute__((destructor)) my_destructor()
{
    printf("卸载\n");
}

constructor会在dll被加载的时候执行,但是要注意一点:

void* dlopen(const char* filename, int flags);
//flags: RTLD_NOW, RTLD_LAZY

RTLD_NOW的时候constructor立即被执行,RTLD_LAZY当so中函数被调用的时候才会执行constructor。

2.执行了两次destructor

__attribute__((destructor))在使用 dlclose() 显式关闭共享库句柄时会在共享库被卸载之前调用,在程序结束时,无论是否显式调用了 dlclose(),共享库句柄会被自动关闭,__attribute__((destructor)) 声明的函数也会在共享库被卸载之前被调用。
这就意味着destructor可能被执行两次

void* handle = dlopen("./libexample.so", RTLD_LAZY);
dlclose(handle);

此时若只希望执行一次,可以考虑:

bool is_destructor_called = false;

void __attribute__((destructor)) my_destructor()
{
    if (!is_destructor_called) {
        // 执行析构操作
        is_destructor_called = true;
    }
}

[WARNING]不要显式调用__attribute__((constructor))/__attribute__((destructor))!


Windows

1.BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved);

DllMain是DLL的入口点函数,当DLL被加载、卸载、线程附加或线程分离时,系统会自动调用DllMain函数。

hModule:表示当前被加载的DLL模块的句柄。

ul_reason_for_call:标识了调用DllMain的原因,它可能取以下值:
    DLL_PROCESS_ATTACH:表示DLL被加载到进程时调用。
    DLL_PROCESS_DETACH:表示DLL从进程中卸载时调用。
    DLL_THREAD_ATTACH:表示DLL被线程附加时调用。
    DLL_THREAD_DETACH:表示DLL从线程中分离时调用。

lpReserved:保留参数,一般情况下不使用,应设置为NULL。

一般进入DllMain可以首先switch:

BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved){
    switch (ul_reason_for_call){
        case DLL_PROCESS_ATTACH:
            // 此处处理动态链接库被进程加载的事件
            // 可以在这里进行一些初始化操作
            break;

        case DLL_PROCESS_DETACH:
            // 此处处理动态链接库被进程卸载的事件
            // 可以在这里进行一些清理操作
            break;

        case DLL_THREAD_ATTACH:
            // 此处处理动态链接库被线程加载的事件
            break;

        case DLL_THREAD_DETACH:
            // 此处处理动态链接库被线程卸载的事件
            break;
    }
    return TRUE;
}

2.__declspec(dllexport)

根据编译器的不同,没有经过__declspec(dllexport)声明的函数可能不会导出到dll的导出表。
此点可为debug用。

3.白加黑不要轻易修改DllMain()

如果修改,可能导致死锁。

// 声明函数指针类型
typedef void (*FuncPtr)();

int main()
{
    // 加载 DLL
    HINSTANCE hDll = LoadLibrary("mydll.dll");
    if (hDll == NULL)
    {
        // 处理加载 DLL 失败的情况
        return 1;
    }
    // 获取函数指针
    FuncPtr pFunc2 = (FuncPtr)GetProcAddress(hDll, "func2");
    if (pFunc2 == NULL)
    {
        // 处理获取函数指针失败的情况
        // 释放 DLL
        FreeLibrary(hDll);
        return 1;
    }
    // 调用 func2 函数
    pFunc2();
    // 释放 DLL
    FreeLibrary(hDll);

    return 0;
}

当一个线程调用 LoadLibrary 加载被注入DLL时,操作系统会自动调用被注入DLL中的 DllMain 函数,并传递 DLL_PROCESS_ATTACH 参数。在 DllMain 函数中,可能会进行一些初始化操作或创建线程等。此时,如果同时有另一个线程尝试修改或替换被注入DLL,也会触发 LoadLibrary 调用,并导致另一个 DllMain 函数的调用。
由于 DllMain 函数没有进行适当的同步处理,多个线程同时调用 DllMain 函数时,可能会发生死锁。