c++ 调用程序接口_添加系统调用(返回文件信息)
终于把操作系统实验一:完成添加一个新的系统调用做完啦!一个什么也不懂的linux小白,从一开始觉得做完实验遥遥无期,甚至在想会不会挂科,到现在终于编译成功,心情也是一波三折。故以此篇记录第一次实验完成的情况。
要求:添加一个新的系统调用,返回指定文件的相关信息,如索引节点编号、硬连接数、文件所有者标识符、文件的字节数和访问方式等。
什么是系统调用
系统调用也叫程序接口,是应用程序请求OS内核完成某功能时的一种过程调用,是用户程序对OS内核功能进行调用的一种手段。
Linux中系统调用的处理过程如下:
1)首先有封装例程设置系统调用功能号和参数,并存到相应寄存器中;
2)执行封装例程中的int 0x80指令,系统产生软中断(或陷入),由中断硬件完成部分现场信息保护:PSW的值和PC寄存器的值;并通过中断向量转向一个中断处理程序system_call()完成其他CPU现场信息的保存:如陷入类型、参数表指针、其他CPU寄存器的值等;
3)使用系统调用功能号查找系统调用入口表,找到相应系统调用的服务例程的入口地址sys_xxx();
4)执行系统调用服务例程sys_xxx(),完毕后返回执行成功与否以及成功时的执行结果给调用者;恢复被中断进程或新调度进程的CPU现场,返回被中断进程或新调度进程执行。
添加系统调用步骤
1、以下载的linux内核文件夹为base dir,首先在./arch/x86/entry/syscalls/syscall_64.tbl文件中添加一个系统调用号,包括系统调用名称、服务例程入口。
2、在./include/linux/syscalls.h文件中添加服务例程的原型声明。
3、在./kernel/sys.c中添加系统调用服务例程。
添加の源码
系统调用服务例程
SYSCALL_DEFINE6(checkfile,char __user*,filename,void __user*,innode,void __user*,lnnum,void __user*,owner,void __user*,size,void __user*,method){printk("checkfile:n");struct kstat* myfilestat;myfilestat =(struct kstat *) kmalloc(sizeof(struct kstat),GFP_KERNEL);vfs_stat(filename,myfilestat);printk("done,then copy to user...n");unsigned long ker_ino =myfilestat->ino;unsigned long ker_nlink=myfilestat->nlink;unsigned long ker_uid=(myfilestat->uid).val;unsigned long ker_size=myfilestat->size;unsigned short ker_mode=myfilestat->mode;copy_to_user(innode, &ker_ino, sizeof(ker_ino));copy_to_user(lnnum, &ker_nlink, sizeof(ker_nlink));copy_to_user(owner,&ker_uid,sizeof(ker_uid));copy_to_user(size,&ker_size,sizeof(ker_size));copy_to_user(method,&ker_mode,sizeof(ker_mode));return 0;
}
测试程序
#include<stdio.h>
#include<unistd.h>
#include<sys/syscall.h>
#include<stdlib.h>#define _SYSCALL_MYNUM 336
int modecode[16];
void print_short(unsigned short *a){for(int i=0;i<16;i++){int k=(*a)&(1<<(15-i))?1:0;printf("%d",k);if(i==3||i==6||i==9||i==12) printf(" ");modecode[i]=k;}printf("n");
}int main(){unsigned long innode,lnlink,owner,size;unsigned short method;char array[16];char s[50];printf("Want to checkfile for you? Just input the path!");scanf("%s",s);printf("The infomation of the file:%s",s);syscall(_SYSCALL_MYNUM,s,&innode,&lnlink,&owner,&size,&method);printf("n");printf("innode: %lun",innode);printf("lnlink: %lun",lnlink);printf("uid: %lun",owner);printf("size: %lubytesn",size);printf("mode: %un",method);printf("mode(binary code 16bits):");print_short(&method);printf("access:");for(int j=7;j<16;j++){if(j%3==1)printf("%c",modecode[j]==1?'r':'-');else if(j%3==2)printf("%c",modecode[j]==1?'w':'-');else if(j%3==0)printf("%c",modecode[j]==1?'x':'-');}printf("n");printf(" donen");return 0;
}
所使用的内核源码解释
源码版本4.16.3
参考服务例程代码
SYSCALL_DEFINE2(stat64, const char __user *, filename,struct stat64 __user *, statbuf)
{struct kstat stat;int error = vfs_stat(filename, &stat);if (!error)error = cp_new_stat64(&stat, statbuf);return error;
}
正常时,返回0
include/linux/stat.h —— kstat结构体定义
struct kstat {u32 result_mask; /* What fields the user got */umode_t mode; //保护模式unsigned int nlink; //硬链接数uint32_t blksize; /* Preferred I/O size 系统块的大小*/u64 attributes;u64 attributes_mask;
#define KSTAT_ATTR_FS_IOC_FLAGS (STATX_ATTR_COMPRESSED | STATX_ATTR_IMMUTABLE | STATX_ATTR_APPEND | STATX_ATTR_NODUMP | STATX_ATTR_ENCRYPTED )/* Attrs corresponding to FS_*_FL flags */u64 ino;dev_t dev; //文件所在设备的iddev_t rdev; //设备号 针对设备文件kuid_t uid;kgid_t gid; //group idloff_t size; //文件大小struct timespec atime; //最近存取时间struct timespec mtime; //最近修改时间struct timespec ctime;struct timespec btime; /* File creation time */u64 blocks; // 文件所占块数
};
include/linux/fs.h
vfs_stat
static inline int vfs_stat(const char __user *filename, struct kstat *stat)
{return vfs_statx(AT_FDCWD, filename, AT_NO_AUTOMOUNT,stat, STATX_BASIC_STATS);
}
AT_FDCWD:相对于当前进程工作空间
AT_NO_AUTOMOUNT: 和挂载点有关,允许收集挂载点的属性。
STATX_BASIC_STATS:查询基本信息
fs/stat.c
vfs_statx
/*** vfs_statx - Get basic and extra attributes by filename* @dfd: A file descriptor representing the base dir for a relative filename表示相对文件名的基本目录的文件描述符* @filename: The name of the file of interest* @flags: Flags to control the query* @stat: The result structure to fill in.* @request_mask: STATX_xxx flags indicating what the caller wants** This function is a wrapper around vfs_getattr(). The main difference is* that it uses a filename and base directory to determine the file location.* Additionally, the use of AT_SYMLINK_NOFOLLOW in flags will prevent a symlink* at the given name from being referenced.* 这个函数是vfs_getattr()的包装器。主要区别在于,它使用文件名和基目录来确定文件的位置。* 此外,在标志中使用AT_SYMLINK_NOFOLLOW将防止给定名称处的符号链接被引用。* 0 will be returned on success, and a -ve error code if unsuccessful.*/
int vfs_statx(int dfd, const char __user *filename, int flags,struct kstat *stat, u32 request_mask)
{struct path path;int error = -EINVAL;//EINVAL表示 无效的参数,即为 invalid argument ,包括参数值、类型或数目无效等unsigned int lookup_flags = LOOKUP_FOLLOW | LOOKUP_AUTOMOUNT;//根据flag 更新需要查找的flag值lookup_flagsif ((flags & ~(AT_SYMLINK_NOFOLLOW | AT_NO_AUTOMOUNT |AT_EMPTY_PATH | KSTAT_QUERY_FLAGS)) != 0)return -EINVAL;if (flags & AT_SYMLINK_NOFOLLOW)lookup_flags &= ~LOOKUP_FOLLOW;if (flags & AT_NO_AUTOMOUNT)lookup_flags &= ~LOOKUP_AUTOMOUNT;if (flags & AT_EMPTY_PATH)lookup_flags |= LOOKUP_EMPTY;retry://查找文件所在的patherror = user_path_at(dfd, filename, lookup_flags, &path);if (error)goto out;//根据path得到文件的属性信息并保存到stat中,返回给用户error = vfs_getattr(&path, stat, request_mask, flags);path_put(&path);//在查找到文件属性的正常情况下error 等于零if (retry_estale(error, lookup_flags)) {lookup_flags |= LOOKUP_REVAL;goto retry;}
out:return error;
}
EXPORT_SYMBOL(vfs_statx);
查找文件所在的path,填入path结构体
struct path {struct vfsmount *mnt;struct dentry *dentry;
} __randomize_layout;
vfsmount结构描述的是一个独立文件系统的挂载信息,每个不同挂载点对应一个独立的vfsmount结构,属于同一文件系统的所有目录和文件隶属于同一个vfsmount,该vfsmount结构对应于该文件系统顶层目录,即挂载目录;
dentry:目录的相关信息
详见 https://blog.csdn.net/dongcheng123456789/article/details/100125707
user_path_at
static inline int user_path_at(int dfd, const char __user *name, unsigned flags,struct path *path)
{return user_path_at_empty(dfd, name, flags, path, NULL);
}
user_path_at_empty
int user_path_at_empty(int dfd, const char __user *name, unsigned flags,struct path *path, int *empty)
{return filename_lookup(dfd, getname_flags(name, flags, empty),flags, path, NULL);
}
EXPORT_SYMBOL(user_path_at_empty);
filename_lookup
static int filename_lookup(int dfd, struct filename *name, unsigned flags,struct path *path, struct path *root)
{int retval;struct nameidata nd;if (IS_ERR(name))return PTR_ERR(name);if (unlikely(root)) {nd.root = *root;flags |= LOOKUP_ROOT;}set_nameidata(&nd, dfd, name);retval = path_lookupat(&nd, flags | LOOKUP_RCU, path);if (unlikely(retval == -ECHILD))retval = path_lookupat(&nd, flags, path);if (unlikely(retval == -ESTALE))retval = path_lookupat(&nd, flags | LOOKUP_REVAL, path);if (likely(!retval))audit_inode(name, path->dentry, flags & LOOKUP_PARENT);restore_nameidata();putname(name);return retval;
}
fs/stat.c
vfs_getattr()
/** vfs_getattr - Get the enhanced basic attributes of a file* @path: The file of interest* @stat: Where to return the statistics* @request_mask: STATX_xxx flags indicating what the caller wants* @query_flags: Query mode (KSTAT_QUERY_FLAGS)** Ask the filesystem for a file's attributes. The caller must indicate in* request_mask and query_flags to indicate what they want.* 向文件系统询问文件的属性。调用者必须在request_mask和query_flags中指出他们需要什么。** If the file is remote, the filesystem can be forced to update the attributes* from the backing store by passing AT_STATX_FORCE_SYNC in query_flags or can* suppress the update by passing AT_STATX_DONT_SYNC.** Bits must have been set in request_mask to indicate which attributes the* caller wants retrieving. Any such attribute not requested may be returned* anyway, but the value may be approximate, and, if remote, may not have been* synchronised with the server.** 0 will be returned on success, and a -ve error code if unsuccessful.*/
int vfs_getattr(const struct path *path, struct kstat *stat,u32 request_mask, unsigned int query_flags)
{int retval;retval = security_inode_getattr(path);if (retval)return retval;return vfs_getattr_nosec(path, stat, request_mask, query_flags);
}
EXPORT_SYMBOL(vfs_getattr);
security_inode_getattr
int security_inode_getattr(const struct path *path)
{if (unlikely(IS_PRIVATE(d_backing_inode(path->dentry))))return 0;return call_int_hook(inode_getattr, 0, path);
}#define call_int_hook(FUNC, IRC, ...) ({ int RC = IRC; do { struct security_hook_list *P; list_for_each_entry(P, &security_hook_heads.FUNC, list) { RC = P->hook.FUNC(__VA_ARGS__); if (RC != 0) break; } } while (0); RC;
})
vfs_getattr_nosec
d_backing_inode 函数 会获得 inode
/*** vfs_getattr_nosec - getattr without security checks* @path: file to get attributes from* @stat: structure to return attributes in* @request_mask: STATX_xxx flags indicating what the caller wants* @query_flags: Query mode (KSTAT_QUERY_FLAGS)** Get attributes without calling security_inode_getattr.** Currently the only caller other than vfs_getattr is internal to the* filehandle lookup code, which uses only the inode number and returns no* attributes to any user. Any other code probably wants vfs_getattr.*/
int vfs_getattr_nosec(const struct path *path, struct kstat *stat,u32 request_mask, unsigned int query_flags)
{//得到path 表示文件的inodestruct inode *inode = d_backing_inode(path->dentry);//清零stat,因为stat 会保存扩展属性返回给用户memset(stat, 0, sizeof(*stat));stat->result_mask |= STATX_BASIC_STATS;request_mask &= STATX_ALL;query_flags &= KSTAT_QUERY_FLAGS;//若文件的扩展属性可以保存到inode上,则通过inode 提供的函数返回给用户if (inode->i_op->getattr)return inode->i_op->getattr(path, stat, request_mask,query_flags);//如果inode上没有保存,则调用文件系统提供的通用函数获得文件的扩展属性generic_fillattr(inode, stat);return 0;
}
EXPORT_SYMBOL(vfs_getattr_nosec);
generic_fillattr
/*** generic_fillattr - Fill in the basic attributes from the inode struct* @inode: Inode to use as the source* @stat: Where to fill in the attributes** Fill in the basic attributes in the kstat structure from data that's to be* found on the VFS inode structure. This is the default if no getattr inode* operation is supplied.*/
void generic_fillattr(struct inode *inode, struct kstat *stat)
{stat->dev = inode->i_sb->s_dev;stat->ino = inode->i_ino;stat->mode = inode->i_mode;stat->nlink = inode->i_nlink;stat->uid = inode->i_uid;stat->gid = inode->i_gid;stat->rdev = inode->i_rdev;stat->size = i_size_read(inode);stat->atime = inode->i_atime;stat->mtime = inode->i_mtime;stat->ctime = inode->i_ctime;stat->blksize = i_blocksize(inode);stat->blocks = inode->i_blocks;if (IS_NOATIME(inode))stat->result_mask &= ~STATX_ATIME;if (IS_AUTOMOUNT(inode))stat->attributes |= STATX_ATTR_AUTOMOUNT;
}
EXPORT_SYMBOL(generic_fillattr);
c++ 调用程序接口_添加系统调用(返回文件信息)相关推荐
- java调用easyxml接口_【技术教程】如何通过Java程序调用RTSP拉流协议视频平台EasyNVR程序接口?...
原标题:[技术教程]如何通过Java程序调用RTSP拉流协议视频平台EasyNVR程序接口? RTSP协议视频平台EasyNVR经过多年的积累,已经是一套成熟且完善的视频平台了,用户可以通过网页直接访 ...
- 前端如何调用后端接口_后端开发:如何写出可靠的接口
毕业进入现在的公司已近一年,完整参与了部门新项目两期的开发上线过程,作为一名后端开发,觉得最痛苦的是上线前和上线后的改 bug 阶段,面对各种突如其来.莫名其妙的bug,头昏脑涨.手忙脚乱.越改越懵, ...
- webstorm前端调用后端接口_软件测试面试题:怎么去判断一个bug是前端问题还是后端问题...
大家好,在软件测试面试过程中,经常有面试官问到这个问题,那我们应该如何回答才好呢?少废话,直接看答案: 答案: 在页面上发现bug之后,要想判断这个问题属于后端还是前端,我就需要来判断这个页面背后调用 ...
- java异步调用微信接口_微信支付V3 SDK(Java版,支持同步异步调用)
我们在开发微信支付时,发现微信官方已经对SDK做了升级,V3版本的SDK从设计上符合RESTful规范. 我们再在开源库中寻找是否有现成de开箱即用.并且支持响应式编程的SDK版本.经过一凡寻找,令我 ...
- c调用python接口_通过Python自带C/C++接口实现python与c/c++相互调用
python的底层是c/c++,因此两种语言都有相互的接口,在以前已经写过一篇c++调用python接口让opencv中的cv::Mat类型在两种语言中相互传递,ubuntu下C++与Python混编 ...
- python接收易语言dll消息_易语言[项目开发]-插件信息提取程序源码,易语言获取DLL文件信息...
易语言获取DLL文件信息源码 系统结构:载入动态链接库_,呼叫窗口函数地址_,取进程地址_,FreeLibrary,系统接口_取版本信息,系统接口_取接口信息,外部接口_加载窗口, ======窗口程 ...
- Win10系统,用C++调用OpenCV接口,播放本地视频文件,播放本地和网络摄像头
1 前言 前边2篇文章介绍了在WIN10系统上,分别用C++和Python调用OpenCV接口,加载和显示一张静态图片.本篇我们来看一下,用C++如何调用OpenCV接口,打开和播放本地视频文件,打开 ...
- 计算机bios程序模拟器,怎么添加pcsx2 bios文件
原标题:怎么添加pcsx2 bios文件 关于ps2模拟器怎么添加pcsx2 bios的这个问题,其实小编我也是前段时间才学会的.因为之前没见过都没遇到过,所以就不知道,直到前段时间看到朋友问道这个问 ...
- kjb文件 解析_批量修改MP3文件信息
前两天本人在整理自己的歌单时(题外话,本人是一个热衷音乐的程序员噢,哈哈),发现之前下载的很多MP3文件里的歌手,标题等信息对不上,很多都是错的.对于患有"强迫症"的本人来说,当然 ...
- delphi 调用php接口_贝壳找房小程序从PHP到Golang的跃迁之路
1. 前言 1.1 PHP是最好的语言 PHP确实有非常强大的优势.对于中小型Web服务,业务具有高度不确定性,产品迭代速度是第一目标,非常适合使用PHP作为创业启动语言. 1.2 使用PHP遇到的问 ...
最新文章
- (C++)1032 挖掘机技术哪家强
- webgl之3d动画
- python库怎么绘画_python基础,安装并使用matplotlib库画图
- android读取外部图片,Android读取本地图库与调用摄像头拍摄
- themleft模板库_Thymeleaf模板引擎常用总结
- unity中单位是米还是厘米_【一步数学】小学数学单位换算公式大全及专项训练...
- 小波阈值去噪原理及实现
- linux下svn的常用代码【转】
- linux多进程编程(一)
- C++之再探参数绑定bind、bind1st、bind2nd、placeholders占位符
- ssis sql_使用sp_help_revlogin和SSIS传输登录任务将SQL登录名传输到AG的辅助副本
- Android 12 重磅亮相!阔别 2 年的 Google I/O 开发者大会回来了
- icem密度盒怎么设置_哪种外卖盒最健康?常吃外卖的必知!
- 信息安全技术 网络安全漏洞分类分级指南(GB/T 30279-2020 )
- iOS 逆向编程(二)越狱入门知识
- 对比度 css_更好的颜色和对比度可访问性CSS技巧
- 【BZOJ4316】小C的独立集
- Rinne Loves Sequence
- h61 nvme硬盘_不懂SSD固态硬盘吗?1分钟教会你
- w ndows7安不上HP1020,Win7安装hp1020打印机后无法使用怎么办(图文)