So, the real user id is who you really are (the one who owns the process), and the effective user id is what the operating system looks at to make a decision whether or not you are allowed to do something (most of the time, there are some exceptions).
貼一個(gè)試驗(yàn)代碼, 子進(jìn)程直接獲取鎖, 若獲取不到則輸出錯(cuò)誤; 父進(jìn)程睡3秒后退出.
- 如果該文件是自己創(chuàng)建的, 無法獲取鎖, 且錯(cuò)誤為
Resource temporarily unavailable. - 如果該文件是進(jìn)程創(chuàng)建的, 可以獲取到鎖.
- 在本例中, 我們讓
aa.txt由進(jìn)程創(chuàng)建, 讓a.txt由用戶創(chuàng)建. 則前者可以獲取鎖, 后者不能, 本文將分析原因.
#include<unistd.h>
#include<stdio.h>
#include<sys/file.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include <errno.h>
#include<string.h>
extern int errno ;
int main() {
int fd = open("a.txt", O_CREAT| O_RDWR);
pid_t ret = fork();
if (ret == 0) {
// child lock ex.
printf("child try get ex lock.\n");
uid_t uid = getuid();
uid_t euid = geteuid();
printf("%d %d\n", uid, euid);
if (flock(fd, LOCK_EX | LOCK_NB) != 0) {
printf("lock ex failed.\n");
} else {
printf("child get ex lock.\n");
}
int err = errno;
printf("error no. %d\n", err);
printf("err msg: %s.\n", strerror( err ));
// fprintf(stdout, "Error opening file: %s\n", strerror( errno ));
while (1) {
printf("child sleep 10s.\n");
sleep(10);
}
return 0; // 直接退出, 此時(shí)父進(jìn)程仍持有鎖.
} else {
// parent lock shared.
sleep(3);
return 0;
// if (flock(fd, LOCK_SH) != 0) {
// printf("lock sh failed.\n");
// return 0;
// }
// printf("parent get shared lock.");
// fflush(stdout);
// while(1) {
// printf("parent sleep 10s\n");
// sleep(20);
// }
}
}
輸出為:
child try get ex lock.
1000 1000
lock ex failed.
error no. 11
err msg: Resource temporarily unavailable.
child sleep 10s.
查看可知進(jìn)程用戶是自己:
[~/codes]$ id rasak
uid=1000(rasak) gid=1000(rasak) 組=1000(rasak),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),106(input),113(lpadmin),128(sambashare),999(docker)
權(quán)限問題?
我一度懷疑是權(quán)限問題, 導(dǎo)致無法獲取鎖, 于是查閱了不少關(guān)于權(quán)限的資料.
查看文件權(quán)限, 值得在意的是s, 和T. 查閱文獻(xiàn)得知s是指setuid, T指sticky bit:
Real, Effective and Saved UserID in Linux 詳細(xì)講了三者的作用.
setuid
當(dāng)執(zhí)行該文件時(shí), 執(zhí)行者會(huì)擁有root權(quán)限. 如果讓該文件能被所有用戶執(zhí)行, 就可以讓所有用戶以root身份去執(zhí)行該文件的指令. 比如sudo:
root@host [~]# ls -l /usr/bin/sudo
-rwsr-xr-x 1 root root 136808 Jan 31 13:37 /usr/bin/sudo
它的執(zhí)行內(nèi)容需要root權(quán)限, 但它能被所有人執(zhí)行.
If uid is the same as the real UID or the saved set-user-ID of the process, setuid() always succeeds and sets the effective UID. the real user ID and saved set-user-ID will remain unchanged.
Sticky BIT 權(quán)限: 總結(jié)一句話作用, 就是在文件上設(shè)置, 防止被文件夾寫權(quán)限者誤刪.
---srwx--T 1 rasak rasak 0 2月 25 11:28 aa.txt
-rw-rw-r-- 1 rasak rasak 8 2月 24 05:22 a.txt
What does directory permission 'S' mean? (not lower case, but in upper case), 大寫S代表setgid被設(shè)置, 小寫s代表它還有組執(zhí)行權(quán)限(也就是S+x). 應(yīng)該t也同理.
'S' = The directory's setgid bit is set, but the execute bit isn't set.
's' = The directory's setgid bit is set, and the execute bit is set.
chmod用法總結(jié)了一些常用做法, 這里也記錄以下:
所有人都獲取讀權(quán)限, 此處a代表所有人, r代表讀權(quán)限:
chmod a+r file1.txt
效果等于如下, 其中u代表文件擁有者, g代表同群組, o代表其它群組的人:
chmod ugo+r file1.txt
將檔案file1.txt和file2.txt設(shè)為該檔案擁有者, 與其所屬同一個(gè)群體者可寫入, 帶其它人不可寫入:
chmod ug+w,o-w file1.txt file2.txt
進(jìn)程問題
其實(shí)原因是父進(jìn)程退出時(shí), 沒有發(fā)送信號(hào)給子進(jìn)程讓其終止, 導(dǎo)致后者成為了孤兒進(jìn)程.
批量查找刪除進(jìn)程可用如下命令(另見xargs命令):
ps aux | grep -i process_name_to_kill | awk '{print $2}' | xargs sudo kill -9
另一種可參照Linux下批量殺掉篩選進(jìn)程
ps -ef| grep override |grep -v grep |awk '{print $2}' | xargs kill -9
問題總結(jié)
與文件的執(zhí)行權(quán)限并無關(guān)系, 之所以無法獲取鎖, 只是因?yàn)楦高M(jìn)程退出后, 沒有子進(jìn)程變?yōu)楣聝哼M(jìn)程, 且沒有退出.
實(shí)驗(yàn)
子進(jìn)程獲取ex鎖后, 父進(jìn)程獲取sh鎖會(huì)成功, 并覆蓋為sh鎖.
此時(shí)啟動(dòng)另一個(gè)進(jìn)程嘗試獲取sh鎖會(huì)成功.
override_flock.c
#include<unistd.h>
#include<stdio.h>
#include<sys/file.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include <errno.h>
#include<string.h>
extern int errno ;
int main() {
int fd = open("a.txt", O_CREAT| O_RDWR);
pid_t ret = fork();
if (ret == 0) {
// child lock ex.
printf("child try get ex lock.\n");
if (flock(fd, LOCK_EX | LOCK_NB) != 0) {
printf("lock ex failed.\n");
} else {
printf("child get ex lock.\n");
}
printf("child sleep 10s.\n");
sleep(15);
printf("child exit.\n");
} else {
// parent lock shared.
sleep(1);
if (flock(fd, LOCK_SH) != 0) {
printf("lock sh failed.\n");
return 0;
} else {
printf("parent get shared lock.\n");
}
printf("parent sleep 10s\n");
sleep(15);
}
}
override_flock_wait.c
#include<unistd.h>
#include<stdio.h>
#include<sys/file.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<malloc.h>
int main() {
printf("wait_process start.\n");
int fd = open("a.txt", O_RDONLY);
char *buf = (char *)malloc(sizeof(char) * 3);
flock(fd, LOCK_SH);
int ret = read(fd, buf, 5);
if (ret > 0) {
printf("read success\n");
printf(buf);
} else {
printf("read failed.\n");
}
}
實(shí)驗(yàn)結(jié)論
flock的鎖視為持有人是open file description, 當(dāng)fork后持有相同open file description的進(jìn)程先后調(diào)用flock, 則都會(huì)成功, 且視為覆蓋鎖形式.
也就是說, 父進(jìn)程獲取ex鎖后, 子進(jìn)程獲取sh鎖, 則視為sh鎖.