I want to check the content of a file from Linux Kernel v3.0.8 knowing only struct inode *. I only need to read the beginning of a file pointed by this inode, then close and return. I don't care about additional information like filename/mountpoint etc.. In fact, the file may not have the name (like deleted but still open). Is it possible?
I finally did it like this:
This is needed.
struct path root;
struct file *filerd;
Get the init task fs root.
task_lock(&init_task);
get_fs_root(init_task.fs, &root);
task_unlock(&init_task);
Change dentry to this file:
root.dentry = d_find_alias(inode);
Open file:
filerd = file_open_root(root.dentry->d_parent, root.mnt,
root.dentry->d_name.name, O_RDONLY);
It worked for every process I tested and for different mount points, which surprised me.
Related
I'm writing a program that iterates through a directory tree depth first (similar to the GNU find program) by recursively constructing paths to each file in the tree and stores the relative paths of encountered files. It also collects some statistics about these files. For this purpose I'm using the stat function.
I've notices that this fails for very deep directory hierarchies, i.e. long file paths, in accordance with stat's documentation.
Now my question is: what alternative approach could I use here that is guaranteed to work for paths of any length? (I don't need working code, just a rough outline would be sufficient).
As you are traversing, open each directory you traverse.
You can then get information about a file in that directory using fstatat. The fstatat function takes an additional parameter, dirfd. If you pass a handle to an open directory in that parameter, the path is interpreted as relative to that directory.
int fstatat(int dirfd, const char *pathname, struct stat *buf,
int flags);
The basic usage is:
int dirfd = open("directory path", O_RDONLY);
struct stat st;
int r = fstatat(dirfd, "relative file path", &st, 0);
You can, of course, also use openat instead of open, as you recurse. And the special value AT_FDCWD can be passed as dirfd to refer to the current working directory.
Caveats
It is easy to get into symlink loops and recurse forever. It is not uncommon to find symlink loops in practice. On my system, /usr/bin/X11 is a symlink to /usr/bin.
Alternatives
There are easier ways to traverse file hierarchies. Use ftw or fts instead, if you can.
First, a little background information to provide some motivation for this question: I've got a program that runs on a headless Linux server and reads/writes files on several removable external hard drives, each of which is formatted with ext4 filesystem. Very occasionally, the filesystem metadata on one of these drives gets corrupted for whatever reason (ext4 journalling notwithstanding), which can cause the ext4 filesystem drive to detect a problem and remount the partition as read-only, presumably as a precaution against cascading errors corrupting the drive further.
Okay, fair enough; but what I'd like to do now is add a function to my program that can detect when the drive is in this remounted-read-only state, so that it can pro-actively notify the user that his drive is in trouble.
My question is, what is an elegant/supported way to query a filesystem to find out if it is mounted read-only?
Attempting to write a file to the filesystem isn't good enough, because that could fail for other reasons, and also because I don't want to write to the filesystem if I don't have to.
My program could fopen("/proc/mounts", "r") and parse the lines of text that it generates (grepping for the "rw," token on the line corresponding to my partition), and I will if I have to, but that solution seems a bit hacky (too much like screen-scraping, liable to break if the text format ever changes).
So, is there some lightweight/purpose-built Linux system call that I could use that would tell me whether a given filesystem mount point (e.g. "/dev/sda1") is currently mounted read-only? It seems like stat() might be able to do it, but I can't see how.
The getmntent() family should meet your needs.
NAME
getmntent, setmntent, addmntent, endmntent, hasmntopt, getmntent_r -
get filesystem descriptor file entry
SYNOPSIS
#include <stdio.h>
#include <mntent.h>
FILE *setmntent(const char *filename, const char *type);
struct mntent *getmntent(FILE *stream);
int addmntent(FILE *stream, const struct mntent *mnt);
int endmntent(FILE *streamp);
char *hasmntopt(const struct mntent *mnt, const char *opt);
/* GNU extension */
#include <mntent.h>
struct mntent *getmntent_r(FILE *streamp, struct mntent *mntbuf,
char *buf, int buflen);
DESCRIPTION
These routines are used to access the filesystem description file
/etc/fstab and the mounted filesystem description file /etc/mtab.
The setmntent() function opens the filesystem description file
filename and returns a file pointer which can be used by getmntent().
The argument type is the type of access required and can take the same
values as the mode argument of fopen(3).
The getmntent() function reads the next line of the filesystem
description file from stream and returns a pointer to a structure
containing the broken out fields from a line in the file. The pointer
points to a static area of memory which is overwritten by subsequent
calls to getmntent().
The addmntent() function adds the mntent structure mnt to the end of
the open stream.
The endmntent() function closes the stream associated with the
filesystem description file.
The hasmntopt() function scans the mnt_opts field (see below) of the
mntent structure mnt for a substring that matches opt. See
and mount(8) for valid mount options.
The reentrant getmntent_r() function is similar to getmntent(), but
stores the struct mount in the provided *mntbuf and stores the strings
pointed to by the entries in that struct in the provided array buf of
size buflen.
The mntent structure is defined in as follows:
struct mntent {
char *mnt_fsname; /* name of mounted filesystem */
char *mnt_dir; /* filesystem path prefix */
char *mnt_type; /* mount type (see mntent.h) */
char *mnt_opts; /* mount options (see mntent.h) */
int mnt_freq; /* dump frequency in days */
int mnt_passno; /* pass number on parallel fsck */
};
...
The easiest way to check that the filesystem of an open file for writing has become mounted read-only is to check the errno variable for EROFS error.
If you don't have the possibility of having a writable directory or file in that filesystem, you cannot get a portable way of checking if the filesystem has become read only (more if it has become so due to device errors)
Another way is to ask the administrator to check, or try to read the /proc/mounts file yourself. But this is linux specific only.
How does the process of creating a file in ext2 file system look like?
I am trying to make a simple syscall which takes a path and creates given file - like touch.
For example, the code:
int main(void)
{
syscall(MY_SYSCALL_NUMBER, "/tmp/file");
}
Should create a file called "file" in /tmp.
Now how should the syscall itself work?
My work so far (I ommited error checking for readibility here):
asmlinkage long sys_ccp(const char __user *arg)
{
struct path path;
struct inode *new_inode;
struct qstring qname;
//ommited copy from user for simplicity
qname.name = arg;
qname.len = length(arg);
kern_path(src, LOOKUP_FOLLOW, &path);
new_inode = ext2_new_inode(path.dentry->d_parent->d_inode, S_IFREG, &qname);
}
This seems to work (I can see in logs that an inode is allocated), however, when I call ls on the directory I can't see the file there.
My idea was to add the new inode to struct dentry of directory, so I added this code:
struct dentry *new_dentry;
new_dentry = d_alloc(path.dentry->d_parent, &qname);
d_instantiate(new_dentry, new_inode);
However, this still doesn't seem to work (I can't see the file using ls).
How to implement this syscall correctly, what am I missing?
EDIT:
Regarding R.. answer - purpuse of this syscall is to play around with ext2 and learn about its design, so we can assumie that path is always valid, the filesystem is indeed ext2 and so on.
You're completely mixing up the abstraction layers involved. If something like your code could even work at all (not sure if it can), it would blow up badly and crash the kernel or lead to runaway wrong code execution if someone happened to make this syscall on a path that didn't actually correspond to an ext2 filesystem.
In the kernel's fs abstraction, the fact that the underlying filesystem is ext2 (or whatever it is) is irrelevant to the task of making a file on it. Rather all of this has to go through fs-type-agnostic layers which in turn end up using the fs-type-specific backends for the fs mounted at the path.
In Linux we have 'mode' for each file/folder
if we do:
struct stat buf;
fstat("file_or_folder_name", &buf);
Then fstat function will fill the buf with lots of info including st_mode;
As I know this st_mode contains information about permission and the file type(tells if it is a file or a folder)
So I want to know If I have to generate/make/cook an st_mode from scratch, how can I make sure that it will tell it's
a file and some other time it will tell that it is a folder? That type I will know by doing: S_ISDIR(buf.st_mode)
ex:
mode_t my_file_mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH;
but that only tells about permission.
I want to make it to tell the file type also.
Also I have to fill other members of: struct stat
So what data I can assign to st_dev and st_ino etc any idea?
Actually the file does not exist on disk, I will be reading the objects from cloud, and I will tell the caller if its a file or a folder along with other info.
I think you are looking for S_IFMT
Its available in mode_t.
Predefined values are:
S_IFBLK Block special.
S_IFCHR Character special.
S_IFIFO FIFO special.
S_IFREG Regular.
S_IFDIR Directory.
S_IFLNK Symbolic link.
S_IFSOCK Socket.
Reference
I'm using Linux (Ubuntu 11.10).
Well, when I call the system call open, for example in a C program:
size_t filedesc = open("testfile.txt",O_CREAT | O_WRONLY,0640);
How can I access the partition, I mean is there a way to return the partition used?
The system call open is the defined above:
SYSCALL_DEFINE3(open, const char __user *, filename, int, flags, int, mode)
If I want, I can put a printk("%s",filename) and see the path. But how I can access the partition?
An example: I have two archives example.txt in two different partitions (for example /dev/sda1 and /dev/sda2).
Then I call the system call open: Lets suppose I called the example.txt in the partition /dev/sda2.
Is there a way to acess the partition (for example, printk(KERN_ALERT "%s",partition)) using the open system call?
There's nothing as simple as you might hope.
Within the do_sys_open() function, immediately before return fd;, the struct file *f points to a legitimate, opened, struct file.
The struct file contains a struct path f_path.
The struct path contains a struct vfsmount *mnt. struct vfsmount represents every mounted filesystem on the system.
The struct vfsmount contains a struct super_block *mnt_sb.
The struct super_block contains a struct block_device *s_bdev.
The struct block_device contains a struct hd_struct *bd_part.
The struct hd_struct contains a struct device __dev and an int partno. Together, these two define which partition your file is located on.
Update
I had originally stopped looking when I found the device and partition number references, since I assumed that was all that was required to put together the human-friendly string. But when looking again with fresh eyes, I see there is more:
The struct hd_struct contains a struct partition_meta_info *info.
The struct partition_meta_info contains a field:
u8 volname[PARTITION_META_INFO_VOLNAMELTH];
This field is name of the device you're after.
Thru a shell, df /some/dir gives you the file-system involved. Programmatically, with stat system call, you get the st_dev field.
(added:) I don't guess what you want to do exactly, but perhaps doing that using FUSE could be simpler.