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).
贴一个试验代码, 子进程直接获取锁, 若获取不到则输出错误; 父进程睡3秒后退出.
Resource temporarily unavailable
.aa.txt
由进程创建, 让a.txt
由用户创建. 则前者可以获取锁, 后者不能, 本文将分析原因.#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; // 直接退出, 此时父进程仍持有锁.
} 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.
查看可知进程用户是自己:
[~/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)
我一度怀疑是权限问题, 导致无法获取锁, 于是查阅了不少关于权限的资料.
查看文件权限, 值得在意的是s
, 和T
. 查阅文献得知s是指setuid, T指sticky bit:
Real, Effective and Saved UserID in Linux 详细讲了三者的作用.
setuid
当执行该文件时, 执行者会拥有root权限. 如果让该文件能被所有用户执行, 就可以让所有用户以root身份去执行该文件的指令. 比如sudo
:
root@host [~]# ls -l /usr/bin/sudo
-rwsr-xr-x 1 root root 136808 Jan 31 13:37 /usr/bin/sudo
它的执行内容需要root
权限, 但它能被所有人执行.
setuid是否有权限:
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 权限: 总结一句话作用, 就是在文件上设置, 防止被文件夹写权限者误删.
---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被设置, 小写s代表它还有组执行权限(也就是S+x). 应该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用法总结了一些常用做法, 这里也记录以下: 所有人都获取读权限, 此处a代表所有人, r代表读权限:
chmod a+r file1.txt
效果等于如下, 其中u代表文件拥有者, g代表同群组, o代表其它群组的人:
chmod ugo+r file1.txt
将档案file1.txt和file2.txt设为该档案拥有者, 与其所属同一个群体者可写入, 带其它人不可写入:
chmod ug+w,o-w file1.txt file2.txt
其实原因是父进程退出时, 没有发送信号给子进程让其终止, 导致后者成为了孤儿进程.
ps aux | grep -i process_name_to_kill | awk '{print $2}' | xargs sudo kill -9
另一种可参照Linux下批量杀掉筛选进程
ps -ef| grep override |grep -v grep |awk '{print $2}' | xargs kill -9
与文件的执行权限并无关系, 之所以无法获取锁, 只是因为父进程退出后, 没有子进程变为孤儿进程, 且没有退出.
子进程获取ex锁后, 父进程获取sh锁会成功, 并覆盖为sh锁. 此时启动另一个进程尝试获取sh锁会成功. 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");
}
}
实验结论 flock的锁视为持有人是open file description, 当fork后持有相同open file description的进程先后调用flock, 则都会成功, 且视为覆盖锁形式. 也就是说, 父进程获取ex锁后, 子进程获取sh锁, 则视为sh锁.