终于把操作系统实验一:完成添加一个新的系统调用做完啦!一个什么也不懂的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++ 调用程序接口_添加系统调用(返回文件信息)相关推荐

  1. java调用easyxml接口_【技术教程】如何通过Java程序调用RTSP拉流协议视频平台EasyNVR程序接口?...

    原标题:[技术教程]如何通过Java程序调用RTSP拉流协议视频平台EasyNVR程序接口? RTSP协议视频平台EasyNVR经过多年的积累,已经是一套成熟且完善的视频平台了,用户可以通过网页直接访 ...

  2. 前端如何调用后端接口_后端开发:如何写出可靠的接口

    毕业进入现在的公司已近一年,完整参与了部门新项目两期的开发上线过程,作为一名后端开发,觉得最痛苦的是上线前和上线后的改 bug 阶段,面对各种突如其来.莫名其妙的bug,头昏脑涨.手忙脚乱.越改越懵, ...

  3. webstorm前端调用后端接口_软件测试面试题:怎么去判断一个bug是前端问题还是后端问题...

    大家好,在软件测试面试过程中,经常有面试官问到这个问题,那我们应该如何回答才好呢?少废话,直接看答案: 答案: 在页面上发现bug之后,要想判断这个问题属于后端还是前端,我就需要来判断这个页面背后调用 ...

  4. java异步调用微信接口_微信支付V3 SDK(Java版,支持同步异步调用)

    我们在开发微信支付时,发现微信官方已经对SDK做了升级,V3版本的SDK从设计上符合RESTful规范. 我们再在开源库中寻找是否有现成de开箱即用.并且支持响应式编程的SDK版本.经过一凡寻找,令我 ...

  5. c调用python接口_通过Python自带C/C++接口实现python与c/c++相互调用

    python的底层是c/c++,因此两种语言都有相互的接口,在以前已经写过一篇c++调用python接口让opencv中的cv::Mat类型在两种语言中相互传递,ubuntu下C++与Python混编 ...

  6. python接收易语言dll消息_易语言[项目开发]-插件信息提取程序源码,易语言获取DLL文件信息...

    易语言获取DLL文件信息源码 系统结构:载入动态链接库_,呼叫窗口函数地址_,取进程地址_,FreeLibrary,系统接口_取版本信息,系统接口_取接口信息,外部接口_加载窗口, ======窗口程 ...

  7. Win10系统,用C++调用OpenCV接口,播放本地视频文件,播放本地和网络摄像头

    1 前言 前边2篇文章介绍了在WIN10系统上,分别用C++和Python调用OpenCV接口,加载和显示一张静态图片.本篇我们来看一下,用C++如何调用OpenCV接口,打开和播放本地视频文件,打开 ...

  8. 计算机bios程序模拟器,怎么添加pcsx2 bios文件

    原标题:怎么添加pcsx2 bios文件 关于ps2模拟器怎么添加pcsx2 bios的这个问题,其实小编我也是前段时间才学会的.因为之前没见过都没遇到过,所以就不知道,直到前段时间看到朋友问道这个问 ...

  9. kjb文件 解析_批量修改MP3文件信息

    前两天本人在整理自己的歌单时(题外话,本人是一个热衷音乐的程序员噢,哈哈),发现之前下载的很多MP3文件里的歌手,标题等信息对不上,很多都是错的.对于患有"强迫症"的本人来说,当然 ...

  10. delphi 调用php接口_贝壳找房小程序从PHP到Golang的跃迁之路

    1. 前言 1.1 PHP是最好的语言 PHP确实有非常强大的优势.对于中小型Web服务,业务具有高度不确定性,产品迭代速度是第一目标,非常适合使用PHP作为创业启动语言. 1.2 使用PHP遇到的问 ...

最新文章

  1. (C++)1032 挖掘机技术哪家强
  2. webgl之3d动画
  3. python库怎么绘画_python基础,安装并使用matplotlib库画图
  4. android读取外部图片,Android读取本地图库与调用摄像头拍摄
  5. themleft模板库_Thymeleaf模板引擎常用总结
  6. unity中单位是米还是厘米_【一步数学】小学数学单位换算公式大全及专项训练...
  7. 小波阈值去噪原理及实现
  8. linux下svn的常用代码【转】
  9. linux多进程编程(一)
  10. C++之再探参数绑定bind、bind1st、bind2nd、placeholders占位符
  11. ssis sql_使用sp_help_revlogin和SSIS传输登录任务将SQL登录名传输到AG的辅助副本
  12. Android 12 重磅亮相!阔别 2 年的 Google I/O 开发者大会回来了
  13. icem密度盒怎么设置_哪种外卖盒最健康?常吃外卖的必知!
  14. 信息安全技术 网络安全漏洞分类分级指南(GB/T 30279-2020 )
  15. iOS 逆向编程(二)越狱入门知识
  16. 对比度 css_更好的颜色和对比度可访问性CSS技巧
  17. 【BZOJ4316】小C的独立集
  18. Rinne Loves Sequence
  19. h61 nvme硬盘_不懂SSD固态硬盘吗?1分钟教会你
  20. w ndows7安不上HP1020,Win7安装hp1020打印机后无法使用怎么办(图文)

热门文章

  1. 卧槽!新来的妹纸rm -rf把公司整个数据库删没了,整个项目组慌了~
  2. 推荐一款日志切割神器!我常用~
  3. 为什么说图形数据库是大数据时代的利器?
  4. try catch 处理异常太烦人了,我已经不用了
  5. 高性能负载均衡是如何架构的?
  6. 干货:资深架构师教你一篇文看懂Hadoop
  7. Windows中安装 Redis 解压版
  8. Nginx 自定义404 页面
  9. junit4同一时候測试多个測试类
  10. 洛谷1008 三连击