接續檔案 I/O,本文整理 Linux 進程環境操作、動態記憶體分配族群、用戶/群組資料庫查詢三大核心 API 群組,附帶常見陷阱與安全實務。
| 函式 | 原型 | 說明 |
|---|---|---|
getpid | pid_t getpid(void); | 取得當前進程 ID,永遠成功 |
getenv | char *getenv(const char *name); | 查詢環境變數,不存在回傳 NULL,回傳指標指向進程環境表,勿修改/釋放 |
putenv | int putenv(char *string); | 格式 "NAME=value",**string 直接成為環境表一部分**,必須靜態/動態分配,不可用區域陣列 |
setenv | int setenv(const char *name, const char *value, int overwrite); | 更安全:核心複製字串,overwrite=1 覆蓋既有,回傳 0 成功 |
unsetenv | int unsetenv(const char *name); | 移除環境變數,回傳 0 成功 |
陷阱:
putenv傳入區域變數指標 → 函數返回後指標失效 → 環境表損毀。永遠使用setenv或確保字串生命週期覆蓋進程壽命。
| 函式 | 原型 | 特性 |
|---|---|---|
malloc | void *malloc(size_t size); | 分配 size 位元組,**不初始化**,內容不定 |
free | void free(void *ptr); | 釋放,**同一指標釋放兩次導致未定義行為 (double free)** |
calloc | void *calloc(size_t nmemb, size_t size); | 分配 nmemb × size 位元組,**全零初始化**,整數溢位檢查較 malloc 完整 |
realloc | void *realloc(void *ptr, size_t size); | 調整大小,**可能移動記憶體**,舊指標失效,**必須用回傳值更新指標** |
void *xmalloc(size_t size) {
void *p = malloc(size);
if (!p) { perror("malloc"); exit(EXIT_FAILURE); }
return p;
}
void *xrealloc(void *ptr, size_t size) {
void *p = realloc(ptr, size);
if (!p) { perror("realloc"); exit(EXIT_FAILURE); }
return p;
}
void xfree(void *ptr) { if (ptr) free(ptr); } // 可容忍 NULL
/etc/passwd, /etc/shadow, /etc/group)| 函式族群 | 關鍵函式 | 說明 |
|---|---|---|
| 用戶查詢 | getpwnam, getpwuid | 依名稱/UID 查詢,回傳 struct passwd* 指向靜態緩衝區,**非執行緒安全** |
| 用戶遍歷 | setpwent, getpwent, endpwent | 順序讀取 /etc/passwd,**單執行緒迭代器**,並發需鎖定 |
| 群組查詢 | getgrnam, getgrgid | 依名稱/GID 查詢,回傳 struct group* |
| 群組遍歷 | setgrent, getgrent, endgrent | 順序讀取 /etc/group |
| Shadow 密碼 | getspnam, getspent 族群 | 需 root 權限讀取 /etc/shadow,含加密密碼、過期資訊 |
getpwnam_r, getpwuid_r:呼叫者提供緩衝區getgrnam_r, getgrgid_rint 錯誤碼,結果經輸出參數回傳| 概念 | 取得函式 | 設定函式 | 說明 |
|---|---|---|---|
| 真實 UID | getuid() | setuid(uid_t) | 進程啟動者身分 |
| 有效 UID | geteuid() | seteuid(uid_t) | 決定檔案存取權限檢查 |
| 真實 GID | getgid() | setgid(gid_t) | 進程啟動者群組 |
| 有效 GID | getegid() | setegid(gid_t) | 決定檔案存取權限檢查 |
// 暫時放棄 root 權限執行敏感操作
uid_t ruid, euid, suid;
getresuid(&ruid, &euid, &suid);
seteuid(ruid); // 降級為真實用戶
// 執行不需特權的操作 (如開啟用戶檔案)
seteuid(euid); // 恢復特權
原則:最小權限、盡快降級、用畢即還。
PATH, LD_LIBRARY_PATH) 執行外部程式getpwnam 等非 _r 版本在多執行緒程式中並發調用導致資料競爭realloc 失敗未檢查,導致記憶體洩漏 (舊指標未釋放)geteuid 即執行危險操作掌握環境、記憶體、身分三大核心子系統 API,是編寫健壯、安全 Linux 系統軟體(Daemon、Container Runtime、CLI 工具)的基石。