2025/10/29

Inspect the SQLite schema in an application to prevent vulnerabilities caused by malicious tampering.

 SQLite 是以檔案系統為基礎的資料庫, 因此除了檔案權限, 無法做到其他權限管理. 很難防止惡意變更 schema 來進行破壞的行為. 因此應用程式需要對 schema 進行檢查, 以避免 schema 受污染而產生漏洞.

 SQLite is a file system-based database, so beyond file permissions, it cannot implement other permission management mechanisms. It is difficult to prevent malicious modifications to the schema for destructive purposes. Therefore, applications must perform schema checks to avoid vulnerabilities arising from schema corruption.

這個保護的方法是將 schema 的主要內容, 以 FNA-1a 算法產生一個 32bits 的 hash code. 應用程式在開啟資料庫時可以檢查該 hash code 來判斷 schema 有沒有被汙染.

This protection method involves generating a 32-bit hash code for the schema's main content using the FNA-1a algorithm. Applications can verify this hash code when opening the database to determine whether the schema has been tampered with.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sqlite3.h>

#define FNV_32_PRIME 0x01000193U
#define FNV_32_OFFSET_BASIS 0x811C9DC5U
#define MAX_SCHEMA_SIZE	16384

uint32_t fnv1a_32_hash(const void *data, size_t len) {
	const unsigned char *bp = (const unsigned char *)data;
	uint32_t hash = FNV_32_OFFSET_BASIS;

	for (size_t i = 0; i < len; i++) {
		hash ^= (uint32_t)bp[i];
		hash *= FNV_32_PRIME;
	}
	return hash;
}

uint32_t calculate_schema_hash(sqlite3 *db, char **err_msg_out) {
	sqlite3_stmt *stmt = NULL;
	int rc;
	char schema_buffer[MAX_SCHEMA_SIZE] = {0};
	const char *sql_query = 
		"SELECT sql FROM sqlite_master "
		"WHERE type='table' AND name NOT LIKE 'sqlite_%';"

	rc = sqlite3_prepare_v2(db, sql_query, -1, &stmt, NULL);
	if (rc != SQLITE_OK) {
		if (err_msg_out) {
			*err_msg_out = strdup(sqlite3_errmsg(db));
		}
		free(schema_buffer);
		return 0;
	}

	while ((rc = sqlite3_step(stmt)) == SQLITE_ROW) {
		const char *schema_sql = (const char *)sqlite3_column_text(stmt, 0);
        
		if (schema_sql) {
			// Check buffer space and append new SQL statements to the buffer.
			size_t current_len = strlen(schema_buffer);
			size_t sql_len = strlen(schema_sql);

			if (current_len + sql_len + 1 < MAX_SCHEMA_SIZE) {
				// Concatenate all schema definition strings directly as raw fingerprint data.
				strcat(schema_buffer, schema_sql);
			} else {
				if (err_msg_out) {
					*err_msg_out = strdup("Schema buffer overflow. Increase MAX_SCHEMA_SIZE.");
				}					
				sqlite3_finalize(stmt);
				free(schema_buffer);
				return 0;
			}
		}
	}

	sqlite3_finalize(stmt);

	if (rc != SQLITE_DONE) {
		// Handling other errors that may occur during the traversal process
		if (err_msg_out) {
			*err_msg_out = strdup(sqlite3_errmsg(db));
		}
		free(schema_buffer);
		return 0;
	}

	// Calculate FNV-1a Hash
	uint32_t final_hash = 0;
	final_hash = fnv1a_32_hash(schema_buffer, strlen(schema_buffer));

	free(schema_buffer);

	return final_hash;
}


2025/05/27

使用 netem 和 ifb 進行 ingress 的網路交通模擬

因為 qdisc 只能控制 egress 的流量, 所以將 enp0s25 的 ingress 導向到 ifb0, 再控制 ifb0 的 egress. 來達成 ingress 的網路模擬.

建立新的 ifb 介面

sudo modprobe ifb numifbs=1
    # numifbs=1 表示建立 1 個新的 ifb 介面. 
    # 在建立的前後使用 ifconfig -a 可以檢視新建立的 ifb 介面名稱. 
    # 如果還沒建立任何 ifb 介面, 則新建立的名稱會是 ifb0.

sudo ip link set dev ifb0 up
    # 喚醒 ifb0

將 enp025 的 ingress 流量導向 ifb0

sudo tc qdisc del dev enp0s25 ingress &> /dev/null
    # 清除 enp0s25 的所有 qdisc

sudo tc qdisc add dev enp0s25 handle ffff: ingress
    # 在 enp0s25 建立 ingress 的 qdisc

sudo tc filter add dev enp0s25 parent ffff: protocol ip u32 match u32 0 0 action mirred egress redirect dev ifb0
    # 將 enp0s25 的所有 ingress 流量重新導向到 ifb0
# sudo tc filter add dev enp0s25 parent ffff: protocol ip u32 match ip protocol 17 0xff action mirred egress redirect dev ifb0
    ## 如果只想要處理 UDP 封包的話, 可以將 match 改成 ip protocol 17 0xff

透過 tc 設定流量控制

sudo tc qdisc del dev ifb0 root &> /dev/null
    # 清除 ifb0 的所有 qdisc

sudo tc qdisc add dev ifb0 root handle 1: netem delay 180ms 30ms loss 5% duplicate 3%
    # 模擬 180ms 延遲, 30ms 抖動, 5% 遺失和 3% 重複

2025/02/18

C Check that the pointer is in range of the memory.

It's hard to say. It's important to protect yourself.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// Function to check if a pointer is within the process's mapped memory regions
int is_pointer_in_memory_range(void *ptr) {
    FILE *fp = fopen("/proc/self/maps", "r");
    if (!fp) {
        perror("fopen");
        return 0;
    }

    char line[256];
    uintptr_t addr = (uintptr_t)ptr;
    uintptr_t start, end;
    while (fgets(line, sizeof(line), fp)) {
        if (sscanf(line, "%lx-%lx", &start, &end) == 2) {
            if (addr >= start && addr < end) {
                fclose(fp);
                return 1; // Pointer is in a valid range
            }
        }
    }

    fclose(fp);
    return 0; // Pointer is not in the mapped memory range
}


2024/10/08

LINE Notify 的替代方案

 LINE Notify 割韭菜了.

只好拿稍微麻煩一點的 pushbullet 來用.

產生 token:

登入 pushbullet 主頁.


在帳號的設定頁面建立 token.



請牢記你的 token, 保管好並且不要洩漏.
然後點選你想接收訊息的裝置

URL 最後就是你的裝置 ID.
接下來就是透過 curl 傳遞我們想要傳送的訊息:
curl -X POST https://api.pushbullet.com/v2/pushes \
-H "Authorization: Bearer ${你的token}>" \
-H "Content-Type: application/json" \
-d "{\"type\": \"note\", \"title\": \"${訊息抬頭}\", \"body\": \"${訊息內容}\", \"device_iden\": \"${你的裝置ID}\"}"



2024/04/18

[C] chek cpu endian

1
2
3
4
5
6
7
8
#include <stdint.h>

static uint8_t is_little_endian(void)
{
    uint16_t value = 0x0001;
    uint8_t *byte_ptr = (uint8_t *)&value;
    return (*byte_ptr == 0x01); // If the system is little endian, the least significant byte is 0x01.
}


2024/04/09

[C] Create a folder even if the parent folder does not exist.

 

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
static int my_dirname(char *path) {
    char *p = strrchr(path, '/');
    if (p == NULL || p == path) {
        return -1;
    }
    *p = '\0';
    return 0;
}

static int my_mkdir(char *path) {
    struct  stat    st;
    char            p[128];
    char            l[128];

    mkdir(path, 0775);
    while ((stat(path, &st) != 0)) {
        memset(p, 0, 128);
        memcpy(p, path, strlen(path));
        if (0 != my_dirname(p)) {
            return (-1);
        }
        while ((stat(p, &st) != 0)) {
            memset(l, 0, 128);
            memcpy(l, p, strlen(p));  // save the last not exist parent path.
            if (0 != my_dirname(p)) {
                return (-1);
            }
        }
        mkdir(l, 0775);
        if (stat(l, &st) != 0) {
            return (-1);
        }
        mkdir(path, 0775);
    }
    return (0);
}

 

2023/06/20

Use tc and netem to simulate network delay, jitter and packet loss.

netem relies on kernel module:
CONFIG_IFB
CONFIG_NET_SCHED
CONFIG_NET_SCH_NETEM.

tc qdisc add dev br-lan root handle 1: htb

  1. This will create a root qdisc on the br-lan interface for htb

tc class add dev br-lan parent 1: classid 1:1 htb rate 1000mbit
tc qdisc add dev br-lan parent 1:1 netem delay 100ms 10ms
tc filter add dev br-lan parent 1:0 protocol ip u32 match ip sport 5101 0xffff flowid 1:1

  1. Create a class 1:1 under 1: of br-lan and set the speed limit to 1000bps.
  2. For class 1:1 set its netem to delay 100ms and jitter 10ms.
  3. Direct the packet with src port 5101 of the br-lan interface to class 1:1.

tc class add dev br-lan parent 1: classid 1:2 htb rate 1000mbit
tc qdisc add dev br-lan parent 1:2 netem loss 0% duplicate 0% delay 30ms 20ms
tc filter add dev br-lan parent 1:0 protocol ip u32 match ip sport 5001 0xffff flowid 1:2

  1. Create a class 1:2 under 1: of br-lan and set the speed limit to 1000bps.
  2. For class 1:2 set its netem to loss 0%, duplicate 0%, delay 30ms and jitter 20ms.
  3. Direct the packet with src port 5001 of the br-lan interface to class 1:2.

2023/04/21

[C] 16進制字串與 byte 陣列戶轉

 Convert between hex string and byte array.

以空間換取時間, 盡量減少計算跟比較.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
static uint8_t HEX_VALUE[256] = {
//  x0 x1 x2 x3 x4 x5 x6 x7   x8 x9 xA xB xC xD xE xF
     0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0,  // 0x
     0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0,  // 1x
     0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0,  // 2x
     0, 1, 2, 3, 4, 5, 6, 7,   8, 9, 0, 0, 0, 0, 0, 0,  // 3x
     0,10,11,12,13,14,15, 0,   0, 0, 0, 0, 0, 0, 0, 0,  // 4x
     0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0,  // 5x
     0,10,11,12,13,14,15, 0,   0, 0, 0, 0, 0, 0, 0, 0,  // 6x
     0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0,  // 7x
     0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0,  // 8x
     0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0,  // 9x
     0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0,  // Ax
     0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0,  // Bx
     0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0,  // Cx
     0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0,  // Dx
     0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0,  // Ex
     0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0   // Fx
};

static uint8_t HEX_CHAR[16] = {
    '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
};

void bytes2hex(uint8_t* src, char* dest, uint8_t srcsize) {
    uint8_t flag;
    uint8_t pos;

    flag = 0;
    pos = 0;
    while (srcsize--) {
if (flag || src[srcsize]) {
dest[pos++] = HEX_CHAR[src[srcsize]>>4];
dest[pos++] = HEX_CHAR[src[srcsize]&0xf];
} } } void hex2bytes(char *src, uint8_t* dest, uint8_t destsize) { uint8_t len; uint8_t pos; uint8_t hilo; uint8_t byte; uint8_t lohi[2]; char *cptr; len = strlen(src); if (len > (destsize* 2)) {
return; } cptr = src + len; pos = 0; ++len; while (len) { memset(lohi, 0, 2); hilo = 2; while (hilo-- && --len) { lohi[hilo] = HEX_VALUE[*--cptr]; } dest[pos++] = lohi[1] | (lohi[0] << 4); } return; }




2023/03/16

Docker 筆記

列出所有 container

    docker ps -a


啟動即停止 container

    docker start container_id/name

    docker stop container_id/name


刪除 container

    docker rm container_id/name


在目前路徑執行 container 指令 (通常用於編譯)

    docker --workdir $PWD container_id/name command

--------------------------------------------------------------------------------

docker --help

Usage: docker [OPTIONS] COMMAND

A self-sufficient runtime for containers

Options:
      --config string      Location of client config files (default "/home/jwang/.docker")
  -D, --debug              Enable debug mode
  -H, --host list          Daemon socket(s) to connect to
  -l, --log-level string   Set the logging level ("debug"|"info"|"warn"|"error"|"fatal") (default "info")
      --tls                Use TLS; implied by --tlsverify
      --tlscacert string   Trust certs signed only by this CA (default "/home/jwang/.docker/ca.pem")
      --tlscert string     Path to TLS certificate file (default "/home/jwang/.docker/cert.pem")
      --tlskey string      Path to TLS key file (default "/home/jwang/.docker/key.pem")
      --tlsverify          Use TLS and verify the remote
  -v, --version            Print version information and quit

Management Commands:
  builder     Manage builds
  config      Manage Docker configs
  container   Manage containers
  engine      Manage the docker engine
  image       Manage images
  network     Manage networks
  node        Manage Swarm nodes
  plugin      Manage plugins
  secret      Manage Docker secrets
  service     Manage services
  stack       Manage Docker stacks
  swarm       Manage Swarm
  system      Manage Docker
  trust       Manage trust on Docker images
  volume      Manage volumes

Commands:
  attach      Attach local standard input, output, and error streams to a running container
  build       Build an image from a Dockerfile
  commit      Create a new image from a container's changes
  cp          Copy files/folders between a container and the local filesystem
  create      Create a new container
  diff        Inspect changes to files or directories on a container's filesystem
  events      Get real time events from the server
  exec        Run a command in a running container
  export      Export a container's filesystem as a tar archive
  history     Show the history of an image
  images      List images
  import      Import the contents from a tarball to create a filesystem image
  info        Display system-wide information
  inspect     Return low-level information on Docker objects
  kill        Kill one or more running containers
  load        Load an image from a tar archive or STDIN
  login       Log in to a Docker registry
  logout      Log out from a Docker registry
  logs        Fetch the logs of a container
  pause       Pause all processes within one or more containers
  port        List port mappings or a specific mapping for the container
  ps          List containers
  pull        Pull an image or a repository from a registry
  push        Push an image or a repository to a registry
  rename      Rename a container
  restart     Restart one or more containers
  rm          Remove one or more containers
  rmi         Remove one or more images
  run         Run a command in a new container
  save        Save one or more images to a tar archive (streamed to STDOUT by default)
  search      Search the Docker Hub for images
  start       Start one or more stopped containers
  stats       Display a live stream of container(s) resource usage statistics
  stop        Stop one or more running containers
  tag         Create a tag TARGET_IMAGE that refers to SOURCE_IMAGE
  top         Display the running processes of a container
  unpause     Unpause all processes within one or more containers
  update      Update configuration of one or more containers
  version     Show the Docker version information
  wait        Block until one or more containers stop, then print their exit codes

Run 'docker COMMAND --help' for more information on a command.

2023/02/08

用 gdb 找 Segmentation fault 的位置

編譯 elf 時不要 strip

STRIP := /usr/bin/true

產生 coredump

ulimit -c 設定 user 的 core上限, 記憶體足夠的情況下, 直接設定成無限. 

$ulimit -c unlimited

發生 Segmentation fault

讓程式發生 Segmentation fault, 如果有產生 core 檔, 會在 stdout 看到 Segmentation fault (core dumped).
core 文件會放在 /tmp/process_name.xxxxxx.core

預設存放路徑
UBUNTU 22.04:    /var/lib/apport/coredump

用 gdb 載入 core

$ gdb <elf> <core>

跑到錯誤點

如果一個 page 跑不到, 直接按 c 跑到錯誤點.
--Type <RET> for more, q to quit, c to continue without paging--

用 Back Trace (bt) 查看 call stack

如果 elf 經過 strip 減肥, 會看不到 symbol.

2022/02/14

SVN 筆記

checkout

    從 server 拉來本地, 簡寫 co
    checkout URL[@REV]... [PATH]
    例:
        svn co svn+ssh://repo/home/svn/mybranch mybranch 

    直接 checkout 指定版本
        svn co -r version svn+ssh://repo/home/svn/mybranch mybranch

commit

    將本地的修改推到 server, 簡寫 ci
    commit [PATH...]
    例:
        svn ci file1 file2 path1/file3

copy

    複製成新的 branch, 簡寫 cp
    copy SRC[@REV]... DST
    例:
        svn cp svn+ssh://repo/home/svn/mybranch svn+ssh://repo/home/svn/newbranch

status

    檔案狀態, 簡寫 st
    svn st [PATH...]
    例:
        svn st

merge

    合併,
    svn merge [-c M[,N...] | -r N:M ...] SOURCE[@REV] [TARGET_WCPATH]
    例: 把 trunk 的修改合併進來.
        svn merge svn+ssh://repo/trunk
    例: 退回 oldver. 完成後重新 commit. 可以保留原先變更的版本參考
        svn merge -r 123:115 svn+ssh://repo/develop
    例: 檔案退回 oldver. 完成後重新 commit 可以保留原先變更的版本參考
        svn merge -r 123:115 path/filename

update

    更新,
    svn update [PATH...]
    例:
        svn up
    例:
        svn up -r 115

cherry-pick

    摘櫻桃
    svn merge -r N:M SOURCE

    例: (從 repo/develop 摘取從 r98 到 r99 所做的變更)
        svn merge -r 98:99 svn+ssh://repo/develop

svn merge 出現下列訊息:

    svn local file obstruction incoming file add upon merge
        這是因為本地跟merge源個別 add 檔案造成的, 解決方法:
            先手動比較兩個版本的差異, 並將檔案修改到最終想要的版本. 然後執行
                svn resolve --accept working <file>
            意思是接受 working 的版本來解決衝突.


2022/01/26

Mount sshfs on linux or windows

 Linux

    Install fuse and sshfs
        #sudo apt-get install fuse sshfs

    Mount
        usage: sshfs [user@]host:[dir] mountpoint [options]
        example:
            #sshfs aimwang@192.168.1.253:/home/aimwang /home/aimwang/nas1

    If you want to give the host direct access in WSL, you need to enable user_allow_other.

        Enable user_allow_other:
            Edit /etc/fuse.conf
            Uncomment user_allow_other

        Mount by your id
            Get user/group id number
                #id -u aimwang
                #id -g aimwang
        Mount with a specific user and group id
                #sshfs -o uid=1000,gid=1000,allow_other nas1:/home/aimwang /home/aimwang/nas1

Windows

    Install WinFsp, SSHFS-Win and SSHFS-Win-Manager.

    Execute SSHFS-Win-Manager
        

    
    Click [Add Connection]


    Fill the connection information.


    Click the connect button.
            



    You can see that it is mounted on the specified disk letter, when the connected.





2022/01/24

使用 WSL2 建構 Ubuntu 16.04 的環境

安裝

    公司的編譯伺服器使用 Ubuntu 16.04, 為了減低編譯環境造成的影響, 所以在本機編譯環境也採用相同的版本.

    Windows Store 沒有提供 Ubuntu 16.04, 所以要手動安裝

        1. 下載 Ubuntu 16.04 的 appx. (連結)

        2. 執行 Windows PowerShell, 切換到下載目錄.

        3. 在 PowerShell 裡面執行 Add-AppxPackage .\Ubuntu_1604.2019.523.0_x64.appx

    完成後就可以看到 Ubuntu 16.04 的應用程式. 第一次執行要設定使用者.


檔案系統

    打開檔案總管應該就能看到 WSL 的資夾, 各資料夾進去都是對到 / 根目錄.

    如果沒有看到, 也可以使用 \\wsl$ 進入.

    這真是太方便了, winsshfs 跟 samba 都省下來了.


sudo 免密碼

    #echo "aimwang ALL=(ALL:ALL) NOPASSWD:ALL" | sudo tee /etc/sudoers.d/aimwang


固定IP

    [無效]
    為了方便使用慣用的 ssh client, 還是要設定成固定 IP
    #sudo nano /etc/network/interfaces.d/eth0.cfg
    auto eth0
        iface eth0 inet static
        address 172.19.240.2
        netmask 255.255.240.0
        gateway 172.19.240.1
        dns-nameservers 172.19.240.1


    [host 端的 vEthernet 沒有固定 IP 無意義]

    執行, 或加入開機 task
        
wsl -d Ubuntu-16.04 -u root ifconfig eth0 172.19.240.2 netmask 255.255.240.0
        wsl -d Ubuntu-16.04 -u root rout add default gw 172.19.240.1

啟動 SSH server

    立即啟動 ssh server
    #service ssh start

    開機自動啟動
    #sudo systemctl enable ssh
        無效, 提示改用
            #/lib/systemd/systemd-sysv-install enable ssh
            也是無效
            rc?.d 裡面有看到 S02ssh, 但是似乎沒有去執行.
            ? 系統採用 sysv 的 /init, 但是沒看到 /etc/inittab
    
    手動執行
        wsl -d Ubuntu-16.04 -u root /etc/init.d/ssh start
    建一個任務在開機的時候自動執行, 至少每次 Windows 重開會自動起來一次. 基於 wsl -t 也不常用, 足夠目前的使用情境了.

重新啟動

    wsl -t Ubuntu-16.04
    下次開 shell 的時候就會自動重啟

解除安裝

在 cmd 裡列出已經安裝的套件清單
    wsl --list

執行 unregister 取消登錄並刪除根檔案系統
    wsl --unregister Ubuntu-16.04

安裝開發基本包

    預設是 64-bit 架構, i386 架構要手動增加
    #sudo dpkg --add-architecture i386
    #sudo apt-get update

    安裝常用 packages
    #sudo apt-get install openssh-client openssh-server subversion git make gcc g++ gawk wget python curl


編譯錯誤訊息與解方

    fatal error: sys/cdefs.h: No such file or directory

        缺乏 libc-dev. 連同 i386 一起安裝
        #sudo apt-get install libc6-dev libc6-dev:i386

    fatal error: openssl/ssl.h: No such file or directory

compilation terminated.

        缺乏 libssl-dev
        #sudo apt-get install libssl-dev libssl-dev:i386

    cannot find -lasound

        缺乏 libasound2
        #sudo apt-get install libasound2-dev libasound2-dev:i386

    cannot find -lstdc++
    cannot find -lgcc_s
    cannot find -lgcc

        需要安裝 lib 包
        #sudo apt-get install g++-multilib gcc-multilib

    Please install ncurses. (Missing libncurses.so or ncurses.h)

        #sudo apt-get install libncurses5-dev

    Please install 'unzip'

        #sudo apt-get install unzip

    fatal: unable to access 'xxx': server certificate verification failed.

        伺服器憑證不被信任.
        下 git 指令之前先執行
            #export GIT_SSL_NO_VERIFY=1

        或永遠不檢查憑證    
            #git config --global http.sslverify false

        或將該站設定為信任. (未完成)

    "__DATE__" might prevent reproducible builds
    "__TIME__" might prevent reproducible builds

        除錯的時候常常要將編譯的日期時間放進去參考, 使用的時候忽略報錯.
        CFLAGS += -Wno-error=date-time

2021/07/13

Ubuntu 20.04 在 Command line 模式設定 static ip

在沒有桌面環境的情況下, 只能用 command line 模式設定網路介面.

Ubuntu 是透過 netplan 來設定.

    #sudo nano /etc/netplan/01-network-manager-all.yaml

以下內容設定 enp8s0
  ip: 192.168.1.140/24
  gw: 192.168.1.1
  dns: 8.8.8.8 1.1.1.1

# Let NetworkManager manage all devices on this system
network:
  version: 2
  renderer: networkd
  ethernets:
    enp8s0:
      addresses: [192.168.1.140/24]
      gateway4: 192.168.1.1
      nameservers:
        addresses: [8.8.8.8, 1.1.1.1]


修改完成後可以 apply 立即生效
    # sudo netplan apply

2021/07/09

Geany 搭配 sshfs-win 儲存檔案時出現 Permission denied 的解決方法

Geany

sshfs-win

使用sshfs比samba安全方便. 但是 Geany 存取 sshfs-win 掛載進來的檔案, 在存檔時會抱怨 Permission denied.


解決的方式是撤銷 use_gio_unsafe_file_saving. 操作如下:

1. 拉下【編輯(E)】選單, 點擊【偏好設定(S)】


2. 切換到【各種類型】, 取消勾選 files.use_gio_unsafe_file_saving. 然後套用並確定.



參考資訊:

2021/05/26

debug function for LUCI

 local debug = 0

function dbg_print(...)

if 1 == debug then

local dbg = io.open("/dev/console", "w")

    if dbg then

        dbg:write(os.date("[%H:%M:%S]: "))

        for _, o in ipairs({...}) do

            dbg:write(tostring(o)..'  ')

        end

        dbg:write("\n")

        dbg:close()

    end

end

end


2021/03/17

C 將 stdout 轉給 console

daemon 的除錯訊息被殼層吃掉的時候, 將訊息丟到 console 可以方便除錯, 如果是每次呼叫 debug 時都 openfile 和 closefile 會有點浪費資源, 所以直接將 stdout 轉給 console, 就能繼續用 printf 來送出除錯訊息了.

做法就是開個 file handler 給 console, 然後重新將 stdout 設定給 console 的 file handler. 範例程式如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
#include <stdio.h>
int main()
{
	FILE *stdout_bk;
	FILE *fpout = fopen("/dev/console" ,"w" );
	stdout_bk = stdout;
	printf("printf not to console\n");
	stdout = fpout;
	printf("printf to console\n");
	stdout = stdout_bk;
	return 0;
}


做成 MACRO

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
#ifdef AIMDBG
#undef AIMDBG
#endif
#define AIMDBG(fmt,...) \
do { \
    FILE *console = fopen("/dev/console" ,"w" ); \
    if (console) { \
        fprintf(console, fmt, __VA_ARGS__); \
        fflush(console); \
        fclose(console); \
    } \
} while(0)


追加 Hexdump

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
static void hexdump (uint8_t* ptr, int len) {
    int i;
    for (i=0; i<len; i++) {
        if (15 == (i % 16)) {
            AIMDBG("%02X\n", ptr[i]);
        }
        else if (7 == (i % 8)) {
            AIMDBG("%02X   ", ptr[i]);
        }
        else {
            AIMDBG("%02X ", ptr[i]);
        }
    }
    AIMDBG("%s", "\n");
}


類似 printf 的用法直接輸出到 console
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
void console_debug(const char *fmt, ...)
{
    static FILE *console_fp = NULL;
    static int tried_open = 0;

    if (!tried_open) {
        console_fp = fopen("/dev/console", "w");
        if (console_fp == NULL) {
            perror("Warning: Cannot open /dev/console, fallback to stderr");
            console_fp = stderr;
        }
        tried_open = 1;
    }
    char log_buf[1024];
    va_list args;
    va_start(args, fmt);
    vsnprintf(log_buf, sizeof(log_buf), fmt, args);
    va_end(args);
    fprintf(console_fp, "[SYSLOGD] %s", log_buf);
    fflush(console_fp);
}