- user EA 只适用于文件或目录 (ext2~4上建立时须要:
mount -o user_xattr device dir
)- trusted
- system
- security 略
- 文件系统支持ACL须要
mount -o acl
- 简单来讲ACL是对原有文件系统权限的扩展
- 原有文件系统只针对owner,group和other, ACL支持对单独用户进行权限设置
- ACL由一系列ACE组成,ACE由三部分组成
- 标记类型
- 标记限定符(可选,通常为用户ID或组ID,下图带-表示不可选,同时只存在一条此类型)
- 权限集合
- 示例
![]()
- 最小ACL:和普通文件权限集合同样只包含ACL_XX_OBJ, ACL_OTHER
- 进程具备特权,执行权限须要至少一条ACL匹配才有,其余同普通文件权限
- 进程的有效用户ID(准确是文件ID下面略)匹配文件的属主,授予ACL_USER_OBJ的ACE指定权限
- 进程的有效用户ID匹配了一条ACL_USER,授予权限为ACL_MASK & ACE指定
- 进程组匹配相似(有效组ID和辅助组任意一匹配,只是匹配了ACL_GROUP_ACE后权限须要& ACL_MASK)
- ACL_OTHER 授予的权限
chmod以后ACL_MASK的做用及其余api调用 略太杂了以后有使用再记吧node
目录的inode示例 linux
![]()
- inode可能会有多个文件名(多个硬连接),没法经过描述符找到文件名
- inode仅在同一文件系统中惟一,硬链得在同一文件系统
- inode目录没法硬链
- _POSIX_SYMLOOP_MAX_ 解引用操做限制<limits.h>
- 软链存储的优化,路径名小于60时能够直接存在存data指针的位置
- l开头的系统调用每每操做的符号连接文件自己(可是文件的目录若是是软链,则都会解引用)
- 除了sticky设置的目录下的软链文件(/tmp)进行删除和重命名的状况外,文件的操做的权限为解引用以后的文件权限。
- 硬链了一个软链,linux不会解引用,MAC会。
即便全部指向这个inode的硬链都解除了,可是又进程持有改文件的描述符(由于能够经过打开文件的表找到对应的inode),在关闭描述符以前,系统实际不会删除改文件算法
- tmpfile 的实现大体应该相似
f = open("tmp_file", O_CREATE|O_EXCL) err =unlink("tmp_file") 复制代码
#include<unistd.h>
int remove(const char *pathname);
// pathname为文件调用unlink, 不然调用rmdir,均不解引用。
复制代码
#include<sys/inotify.h>
// return inotify fd
int inotify_init(void);
// return wd; need read privellege on pathname
int inotify_add_watch(int fd, const char *pathname, uint32_t mask);
// 删除fd里面的wd
int inotify_rm_watch(int fd, uint32_t wd);
复制代码
fd,wd一对多编程
每次调用read 读取fd ,若是不传O_NONBLOCK会阻塞,传参的话read会马上失败并报错EAGAINapi
struct inotify_event {
int wd;
uint32_t mask;
uint_32 cookie; // cookie for relate events(ex:rename())
uint32_t len; //sizeof name
char name[]; // 监控为目录时返回文件名,为文件返回空,len为0
}
复制代码
- 在事件队列末尾追加一个新事件会和当前对尾比较,若是struct一致,则合并,忽略屡次。
/proc/sys/fs/inotify/
保存inotify的各类限制
- max_queue_events
- max_user_instances
- max_user_watches
信号是事件发生时对进程的通知机制:也叫软件中断cookie
信号一般源于内核数据结构
- 硬件发生异常:被0除,内存访问错误等
- 用户键入产生异常特殊字符:Ctrl+c,Ctrl+z
- 软件事件:CPU时间超时等等
信号的分类函数
- 标准信号(内核像进程通知事件,一般是1-31)
- 实时信号
- 忽略信号
- 杀死进程(非调用exit终止)
- 产生核心转储文件并终止
- 中止进程
- 恢复中止
- 采起默认(用于恢复对默认的修改)
- 忽略默认终止信号
- 执行编写的信号处理程序(如Ctrl+c, 没法直接设置处理程序杀死进程或产生核心转储文件,能够经过间接调用abort来产生新的信号)
SIGABRT
: 调用abort()
会产生,会杀死进程并产生核心转储文件供调试SIGALARM
: 调用alarm()
或setitimer()
设置定时器到时间,内核会产生该信号SIGBUS
: 内存访问错误SICHLD|SIGCLD
: 子进程终止时发给父进程SIGCONT
: 恢复中止进程- .......
SIGTERM
:标准杀死进程信号kill|killall
会发起SIGKILL
: 必杀信号,处理程序没法将其阻塞,忽略或 捕获(测试下);kill -9|kill -KILL
会调用
#include<signal.h>
void ( *signal(int sig, void (*handler)(int))) (int);
//成功返回以前的调用函数地址或者SIG_DFL(设为默认值)或SIF_IGN(忽略),失败时返回SIG_ERR
//正常开发不要使用signal,兼容性很差
复制代码
#include<signal.h>
#include<stdio.h>
#include<stdlib.h>
static void sigHandler(int sig){
printf("Ouch\n");
}
int main(void){
if (signal(SIGINT, sigHandler)==SIG_ERR){
printf("error");
exit(-1);
}
for (;;){
printf("*****************************");
sleep(3);
}
}
复制代码
#include<signal.h>
int kill(pid_t pid, int sig);
复制代码
- pid>0, 发送给pid进程
- pid=0, 发送给同组全部进程
- pid<-1, 发送给pid绝对值进程组内全部进程
- pid=-1 发送给除了init进程和自身以外的全部有权进程
发送的权限测试
- 特权进程能够发给全部
- root用户和组运行的init进程,仅接受安装了处理器函数的信号
- 非特权进程
![]()
- SIGCONT信号忽视用户ID检测,非特权进程能够向会话内任意进程发送这一信号
sig=0,仅报告进程是否存在优化
#include<signal.h>
int raise(int sig);
//单线程下等于
kill(getpid(), sig)
//支持线程系统下
pthread_kill(pthread_self(),sig)
int killgp(pid_t pgrp, int sig);
//等同于
kill(-pgrp, sig)
复制代码
#include<signal.h>
// 初始化空的set
int sigemptyset(sigset_t *set);
// 初始化包含全部信号(包括实时信号)的set
int sigfillset(sigset_t *set);
int sigaddset(sigset_t *set, int sig);
int sigdelset(sigset_t *set, int sig);
int sigismember(const sigset_t *set, int sig);
复制代码
#define _GNU_SOURCE
#include<signal.h>
int sigandset(sigset_t *dest, sigset_t *left, sigset_t *right);
int sigorset(sigset_t *dest, sigset_t *left, sigset_t *right);
int sigisemptyset(const sigset_t *set);
复制代码
内核会为每一个进程维护一个信号掩码,即一组信号,并阻塞这些信号对进程的传递,一直延迟直至解除(每一个线程可单独控制)
#include<signal.h>
int sigprocmask(int how, const sigset_t *set, sigset_t *old_set);
// how=SIG_BLOCK, 当前进程和set取并集
// how=SIG_UNBLOCK, 移除set内信号
// how=SIG_SETMASK, 赋值为set内信号
// oldset不为空则指向以前的信号掩码
// set为空不作改动
复制代码
#include<signal.h>
#include<stdlib.h>
int main(void){
sigset_t blockSet, prevMask;
sigemptyset(&blockSet);
sigaddset(&blockSet, SIGINT);
if (sigprocmask(SIG_BLOCK, &blockSet, &prevMask)==-1){
exit(-1);
}
if (sigprocmask(SIG_SETMASK, &prevMask, NULL) == -1){
exit(-1);
}
retunn 0;
}
复制代码
获取等待信号
#include<signal.h>
int sigpending(sigset_t *set);
// 标准信号同一信号只会记录一次,实时信号以后会有排队处理见22章
复制代码
#include<signal.h>
int sigaction(int sig, const struct sigaction *act, struct sigaction *oldact);
//act 新处置的数据结构,为NULL则忽略,oldact置位将当前处置
struct sigaction{
void (*sa_handler)(int); // 调用函数地址或者SIG_DFL,SIF_IGN, 为函数地址时sa_mask和sa_flags才有效
sigset_t sa_mask; //调用函数时可额外阻塞一组信号
int sa_flags; //略....太多标记了
void (*sa_restorer)(void); //系统内部使用,供恢复上下文
}
复制代码
- 执行处理器程序时,同一信号第二次到达,若是没有设为阻塞会忽略,设为阻塞的话会保留一次
#include<unistd.h>
int pause(void);
// 进程一直中止直到有处理函数的信号,或者一个未处理信号终止进程
复制代码