In the implemention of xxx_readdir() in FUSE, I use the codes below:
static int hello_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
off_t offset, struct fuse_file_info *fi)
{
DIR *dp;
struct dirent *de;
(void) offset;
(void) fi;
dp = opendir(path);
if (dp == NULL)
return -errno;
while ((de = readdir(dp)) != NULL) {
struct stat st;
memset(&st, 0, sizeof(st));
st.st_ino = de->d_ino;
st.st_mode = de->d_type << 12;
if (filler(buf, de->d_name, &st, 0))
break;
}
closedir(dp);
return 0;
}
Then, compile and execute on a foler:
./hello /tmp/hello/
When I use ls /tmp/hello/ command, the results are as below:
bin dev home lib64 media opt root sbin sys usr
boot etc lib lost+found mnt proc run srv tmp var
However, I have not created any file or directory in /tmp/hello/. So, why are these direcoties reside on it when I use the ls command?
You call:
dp = opendir(path);
to begin your readdir implementation. When you call that path is relative to the root of your filesystem, not an absolute path on your system.
So in /tmp/hello/ the value of path will be '/' because it doesn't make sense for filesystems to need to know the details of where they're mounted. There's a deliberate abstraction there that makes it such that each filesystem is only concerned with things it stores.
Related
Can't get fd or dirfd from params, they are always be -100.
The kernel module is developed under CentOS 8.3, Linux kernel version 4.18.
The result is -100
I am a little confused why this will happen.
The reason why I need dfd is I want to get the absolute path, when input pathname alike "../".
asmlinkage int modified_unlinkat(const struct pt_regs *regs) {
int result;
int dfd = (int)regs->di;
char *tmp = (char*)__get_free_page(256);
struct file *files = fget(dfd);
if (!files) {
conivent_printf("%d", dfd);
return -EACCES;
}
char *path = d_path(&files->f_path, tmp, PAGE_SIZE);
conivent_printf("%s", path);
return -EACCESS;
}
If anyone could provide help, I will be extremely appreciate.
I was trying to read/write a file from my kernel module (I know it is dangerous and not suggested at all, but I need to do it for various reasons)
I followed this answer How to read/write files within a Linux kernel module?, and it works fine.
This is the code that I execute to test if the basic functions work:
void test_file(){
struct file * f = file_open("./test.txt", O_CREAT | O_RDWR |
O_APPEND, S_IRWXU | S_IRWXG | S_IRWXO);
if(f != NULL){
char arr[100];
char * str = "I just wrote something";
file_write(f,0, str, strlen(str));
memset(arr, '\0', 100);
file_read(f, 0, arr, 20);
printk(KERN_INFO "Read %s\n",arr);
file_close(f);
}else{
printk(KERN_ERR "Error! Cannot write into file\n");
}
}
If I execute this code inside my __init function, test.txt is created/updated inside the current folder where the .ko file is.
However, I noticed that if I execute this code in a new kthread, the file is created in / folder, and I need to provide the absolute path in order to get it in the current location.
void test_function(){
test_file(); // creates test.txt in /
}
static int __init file_init(void) {
struct task_struct * test_thread = kthread_run((void *)test_function, NULL, "Test");
test_file(); // creates test.txt in .
}
module_init(file_init)
Definitions of file_write, file_read, file_close and file_open are given in the linked stackoverflow answer
Anybody knows how to give a relative path also in the kthread?
This is what I did:
struct file * f;
void test_file(){
if(f != NULL){
char arr[100];
char * str = "I just wrote something";
file_write(f,0, str, strlen(str));
memset(arr, '\0', 100);
file_read(f, 0, arr, 20);
printk(KERN_INFO "Read %s\n",arr);
file_close(f);
}else{
printk(KERN_ERR "Error! Cannot open file\n");
}
}
void test_function(){
test_file(); // access the file from the kthread
}
static int __init file_init(void) {
// Create and open the file in user space
f = file_open("./test.txt", O_CREAT | O_RDWR | O_APPEND, \
S_IRWXU | S_IRWXG | S_IRWXO);
struct task_struct * test_thread = kthread_run((void *)test_function, \
NULL, "Test");
}
module_init(file_init)
I am working on a module to read a files xattributes on open. I have hooked the sys_open and due to this I need to get the dentry of the file without opening the file. In brief I have the inode and the absolute path but having trouble to figure out; how to get a dentry from these. All comments are very much appreciated.
OK. Other answers didn't cover how to obtain a dentry from pathname/absolute path. The following code snippet could it.
int ret = 0;
struct path path;
ret = kern_path("/proc/", LOOKUP_DIRECTORY, &path);
if (ret)
pr_err("Failed to lookup /proc/ err %d\n", ret);
else {
if (PROC_SUPER_MAGIC != path.mnt->mnt_sb->s_magic)
printk("BUG /proc is not mounted as Proc FS, magic %lx\n", path.mnt->mnt_sb->s_magic);
path_put(&path);
}
As per my understating you are trying to get the dentry path from your driver module during the open callback function . If so; then before putting down the way I am adding the structure list which are required to access the the dentry information.
include/linux/fs.h
Struct file{
struct path f_path;
};
include/linux/path.h
struct path {
struct vfsmount *mnt;
struct dentry *dentry;
};
include/linux/dcache.h
struct dentry {
};
So you can do like this.
static int sample_open(struct inode *inode, struct file *file)
{
char *path, *dentry,*par_dentry;
char buff[256];
dentry = file->f_path.dentry->d_iname;
pr_info("dentry :%s\n",dentry);
par_dentry = file->f_path.dentry->d_parent->d_iname;
pr_info("parent dentry :%s\n",par_dentry);
path=dentry_path_raw(file->f_path.dentry,buff,256);
pr_info("Dentry path %s\n",path);
}
I was wondering if it was possible to know if the rootfile system has been mounted from the kernel. Im trying to read a file from /bin but it doesnt work on boot.
static int ret_my_file() is in fs/exec.c
static int ret_my_file()
{
struct file* f;
char *dbtext;
struct path dbpath;
mm_segment_t oldfs;
struct kstat dbstat;
kern_path("/bin/myfile", 0, &dbpath);
vfs_getattr(&dbpath, &dbstat);
dbtext = vmalloc(dbstat.size*sizeof(char));
f=filp_open("/bin/myfile", O_RDONLY, 0);
oldfs=get_fs();
set_fs (KERNEL_DS);
vfs_read(f, dbtext, dbstat.size, &f->f_pos);
set_fs(oldfs);
printk(KERN_CRIT "Db value is");
printk(KERN_CRIT "%s\n",dbtext);
vfree(dbtext);
return 0;
}
called in the function do_execveat_common() also in fs/exec.c as
static int do_execveat_common(int fd, struct filename *filename,
struct user_arg_ptr argv,
struct user_arg_ptr envp,
int flags)
{
char *pathbuf = NULL;
struct linux_binprm *bprm;
struct file *file;
struct files_struct *displaced;
int retval;
retval=ret_my_file();
......}
but the function do_execveat_common() is called during boot up so i wanted to put a condition before retval=ret_my_file(); so that it only runs after the root filesystem has been mounted
I'm doing a course on operating systems and we work in Linux Red Hat 8.0
AS part of an assignment I had to change sys close and sys open. Changes to sys close passed without an incident, but when I introduce the changes to sys close suddenly the OS encounters an error during booting, claiming it cannot mount root fs, and invokes panic. EIP is reportedly at sys close when this happens.
Here are the changes I made (look for the "HW1 additions" comment):
In fs/open.c:
asmlinkage long sys_open(const char * filename, int flags, int mode)
{
char * tmp;
int fd, error;
event_t* new_event;
#if BITS_PER_LONG != 32
flags |= O_LARGEFILE;
#endif
tmp = getname(filename);
fd = PTR_ERR(tmp);
if (!IS_ERR(tmp)) {
fd = get_unused_fd();
if (fd >= 0) {
struct file *f = filp_open(tmp, flags, mode);
error = PTR_ERR(f);
if (IS_ERR(f))
goto out_error;
fd_install(fd, f);
}
/* HW1 additions */
if (current->record_flag==1){
new_event=(event_t*)kmalloc(sizeof(event_t), GFP_KERNEL);
if (!new_event){
new_event->type=Open;
strcpy(new_event->filename, tmp);
file_queue_add(*new_event, current->queue);
}
}
/* End HW1 additions */
out:
putname(tmp);
}
return fd;
out_error:
put_unused_fd(fd);
fd = error;
goto out;
}
asmlinkage long sys_close(unsigned int fd)
{
struct file * filp;
struct files_struct *files = current->files;
event_t* new_event;
char* tmp = files->fd[fd]->f_dentry->d_name.name;
write_lock(&files->file_lock);
if (fd >= files->max_fds)
goto out_unlock;
filp = files->fd[fd];
if (!filp)
goto out_unlock;
files->fd[fd] = NULL;
FD_CLR(fd, files->close_on_exec);
__put_unused_fd(files, fd);
write_unlock(&files->file_lock);
/* HW1 additions */
if(current->record_flag == 1){
new_event=(event_t*)kmalloc(sizeof(event_t), GFP_KERNEL);
if (!new_event){
new_event->type=Close;
strcpy(new_event->filename, tmp);
file_queue_add(*new_event, current->queue);
}
}
/* End HW1 additions */
return filp_close(filp, files);
out_unlock:
write_unlock(&files->file_lock);
return -EBADF;
}
The task_struct defined in schedule.h was changed at the end to include:
unsigned int record_flag; /* when zero: do not record. when one: record. */
file_queue* queue;
And file queue as well as event t are defined in a separate file as follows:
typedef enum {Open, Close} EventType;
typedef struct event_t{
EventType type;
char filename[256];
}event_t;
typedef struct file_quque_t{
event_t queue[101];
int head, tail;
}file_queue;
file queue add works like this:
void file_queue_add(event_t event, file_queue* queue){
queue->queue[queue->head]=event;
queue->head = (queue->head+1) % 101;
if (queue->head==queue->tail){
queue->tail=(queue->tail+1) % 101;
}
}
if (!new_event) {
new_event->type = …
That's equivalent to if (new_event == NULL). I think you mean if (new_event != NULL), which the kernel folks typically write as if (new_event).
Can you please post the stackdump of the error. I don't see a place where queue_info structure is allocated memory. One more thing is you cannot be sure that process record_flag will be always zero if unassigned in kernel, because kernel is a long running program and memory contains garbage.
Its also possible to check the exact location in the function is occurring by looking at the stack trace.