I'm doing a school assignment and the task at hand is to count the files and folders recursively. I use the readdir() function, it seems to iterate through the directory I gave it.
int listdir(const char *path)
{
struct dirent *entry;
DIR *dp;
dp = opendir(path);
if (dp == NULL)
{
perror("opendir");
return -1;
}
while((entry = readdir(dp)))
puts(entry->d_name);
closedir(dp);
return 0;
}
I want to see the "something++;" step of this function, there should be one, right? All I can find is this line in glibc's dirent/dirent.h
extern struct dirent *readdir (DIR *__dirp) __nonnull ((1));
and
struct dirent *
__readdir (DIR *dirp)
{
__set_errno (ENOSYS);
return NULL;
}
weak_alias (__readdir, readdir)
in dirent/readdir.c
Where does the iteration happen?
Maybe a duplicate of How readdir function is working inside while loop in C?
I tried to grep through glibc source code for readdir - didn't find, searched the Internet - didn't find, although some say there is an obsolete linux system call also called readdir.
There is also this
"
The readdir() function returns a pointer to a dirent structure
representing the next directory entry in the directory stream
pointed to by dirp. It returns NULL on reaching the end of the
directory stream or if an error occurred."
and this
"
The order in which filenames are read by successive calls to readdir()
depends on the filesystem implementation; it is unlikely that the names
will be sorted in any fashion."
in man readdir .
From this answer - https://stackoverflow.com/a/9344137/12847376
I assume OS can hijack functions with LD_PRELOAD, I see no such variable in my default shell. And too many hits in the Debian source search.
I also grepped through the Linux kernel for LD_PRELOAD and readdir and got too many results on the syscall.
I'm not sure exactly what you are trying to accomplish. I have implemented something similar to this for another language's core library, so I can say there is not a ++something. The reason for that, is that the structures returned by the operating system do not have a consistent size. The structure is something like the following:
struct dirent {
long d_ino;
off_t d_off;
unsigned short d_reclen;
char d_type;
char d_name[];
};
You pass a buffer to the system call (I used getdents64), and it fills it in with a bunch of these dirent structures. That d_name[] does not have an officially known size. The size of the entire structure is defined by that d_reclen member of the struct.
In memory, you could have many struct dirent like this:
[0] [1] [2]
44,0,24,DT_REG,"a.txt",41,0,47,DT_DIR,"a_really_long_directory_name",...
Here is a rough translation of how it works:
uint8_t buf[BUFLEN];
long n = getdents64(dfd, buf, BUFLEN);
if (n < 0) {
// error
}
// buf now holds dirent structs
struct dirent* d = buf;
int i = 0;
for (; i < res; i += d->d_reclen) { // <<<< this is the trick
d = &buf[i];
// do something with the d
}
Notice the way we increment i. Since the d_name member does not have an official size, we cannot just say struct dirent d[COUNT];. We don't know how big each struct will be.
Where does the iteration happen?
On Linux, it happens here. As you can see, the code repeatedly calls getdents (system call) to obtain a set of entries from the kernel, and "advances" the dp by updating dirp->offset, etc.
24 /* Read a directory entry from DIRP. */
25 struct dirent *
26 __readdir_unlocked (DIR *dirp)
27 {
28 struct dirent *dp;
29 int saved_errno = errno;
30
31 if (dirp->offset >= dirp->size)
32 {
33 /* We've emptied out our buffer. Refill it. */
34
35 size_t maxread = dirp->allocation;
36 ssize_t bytes;
37
38 bytes = __getdents (dirp->fd, dirp->data, maxread);
39 if (bytes <= 0)
40 {
41 /* Linux may fail with ENOENT on some file systems if the
42 directory inode is marked as dead (deleted). POSIX
43 treats this as a regular end-of-directory condition, so
44 do not set errno in that case, to indicate success. */
45 if (bytes == 0 || errno == ENOENT)
46 __set_errno (saved_errno);
47 return NULL;
48 }
49 dirp->size = (size_t) bytes;
50
51 /* Reset the offset into the buffer. */
52 dirp->offset = 0;
53 }
54
55 dp = (struct dirent *) &dirp->data[dirp->offset];
56 dirp->offset += dp->d_reclen;
57 dirp->filepos = dp->d_off;
58
59 return dp;
60 }
Related
I am writing an user space process that will read data from the configfs entry continuously. I have defined callback function for read in kernel.
When I invoke read in a loop, only for the first time callback is called and for the next iterations control is not hitting the callback.
Kernel callback for read is simple function that will return a character.
static ssize_t show(struct config_item *item, char *page)
{
static char a = 'a';
printk("reading data\n");
page[0] = a++;
return 1;
}
User space process will read the data and display it on the screen.
int main()
{
int fd = open("/sys/kernel/config/sample/showme", O_RDONLY);
int ret;
int i = 5;
char receive[8];
if (fd < 0) {
perror("Failed to open the device...");
return errno;
}
while(i--) {
ret = read(fd, receive, 1);
if (ret < 0) {
perror("Failed to read the message\n");
return errno;
}
printf("Message is %x with size %d\n", receive[0], ret);
}
close(fd);
}
output:
Message is 61 with size 1
Message is 61 with size 0
Message is 61 with size 0
Message is 61 with size 0
Message is 61 with size 0
Note: The flow goes well if I close and open the file for all reads.
How to fix the above problem? I want the data to be reflected on all read.
A file under configfs filesystem is interpreted as an attribute, which have specific finite content at any moment.
E.g., a file may have content:
"123" at moment 1ns
"abc" at moment 2ns
"" (empty) at moment 3ns
and so on.
Moreover, configfs filesystem ensures, that after opening the file, any read() performed by the user will see portion of data consistent with other read()s. Assuming the example above, user won't read first symbol "1" (as at moment 1ns), 2nd symbol "b" (as at moment 2ns) and then found 3d symbol to be absent (as at moment 3ns).
So, after opening the file, .show() method is called once, and is expected to return whole content of the file. This content (or an appropriate portion of it) is returned upon futher read requests from the user.
Consistency guarantee is cleared at closing the file; so when you open it again, .show() will be called once more, and user's read requests will return updated content of the file.
I am writing an user space process that will read data from the configfs entry continuously.
With this semantic abstraction of finite file's content is lost, so you cannot implement that for configfs files.
However, you may implement this semantic with any "general" filesystem, which allows directly to set file_operations callbacks. You may create a file, e.g., under debugfs (/sys/kernel/debug/):
ssize_t my_read (struct file * filp, char __user * buf, size_t size, loff_t * offp)
{
static char a = 'a';
printk("reading data\n");
a++;
copy_to_user(buf, &a, 1);
return 1;
}
struct file_operations my_ops = {
.owner = THIS_MODULE,
.read = &my_read
};
int module_init(void)
{
debugfs_create_file("showme", S_IRUGO, NULL, NULL, &my_ops);
...
}
I've seen the following snippet of code used repeatedly for Linux hwmon devices:
return sprintf(buf, "%d\n", in_input);
Where buf is a pointer to char char *buf, and in_input usually an int or u16. The purpose is to copy the value read back from the device to the sysfs file created for this device attribute.
As an example, you can take a look at Linux/drivers/hwmon/mcp3021.c (or any hwmon device previous to 4.9 kernel really). You can see the function at line 81 returns a u16, and on line 99 the code stores the u16 into the char *buf.
81 static inline u16 volts_from_reg(struct mcp3021_data *data, u16 val)
82 {
83 return DIV_ROUND_CLOSEST(data->vdd * val, 1 << data->output_res);
84 }
85
86 static ssize_t show_in_input(struct device *dev, struct device_attribute *attr,
87 char *buf)
88 {
89 struct i2c_client *client = to_i2c_client(dev);
90 struct mcp3021_data *data = i2c_get_clientdata(client);
91 int reg, in_input;
92
93 reg = mcp3021_read16(client);
94 if (reg < 0)
95 return reg;
96
97 in_input = volts_from_reg(data, reg);
98
99 return sprintf(buf, "%d\n", in_input);
100 }
Wouldn't this code always cause buffer overflow? We are always storing a u16 into a buffer allocated for char 8-bits. Why is this permitted in Linux device drivers?
Note that with my driver that does the exact same thing, sysfs displays the returned value correctly even though it cannot possibly be stored as a char (8-bits). So wondering if the char * representation is not accurate?
According to the documentation in sysfs.txt, the buffer passed to the show function is of size PAGE_SIZE:
sysfs allocates a buffer of size (PAGE_SIZE) and passes it to the method. Sysfs will call the method exactly once for each read or write.
Since PAGE_SIZE is certainly bigger than the length of a small integer, there is no practical possibility of a buffer overflow.
The posted code shows poor programming style, but if buf is known to point to an array of at least 8 bytes, the behavior is defined and sprintf will not cause a buffer overflow.
Note that show_in_input does not receive the size of the destination buffer, the API would need to be changed for snprintf() to be used.
For a lab we are required to read in from binary files using low level io (open/lseek/close not fopen/fseek/fclose) and manipulate the data. My question is how do I read or write structs using these methods.
The struct is as follows
typedef struct Entry {
char title[33];
char artist[17];
int val;
int cost;
} Entry_T;
I originally planned on creating a buffer of sizeof(Entry_T) and read the struct simply, but I don't think that's possible using low level I/O. Am I supposed to create 4 buffers and fill them sequentially, use one buffer and reallocate it for the right sizes, or is it something else entirely. An example of writing would be helpful as well, but I think I may be able to figure it out after I see a read example.
Because your structures contain no pointers and all elements are fixed size, you can simply write and read the structures. Error checking omitted for brevity:
const char *filename = "...";
int fd = open(filename, O_RDWR|O_CREAT, 0644);
Entry_t ent1 = { "Spanish Train", "Chris De Burgh", 100, 30 };
ssize_t w_bytes = write(fd, &ent1, sizeof(ent1));
lseek(fd, 0L, SEEK_SET);
Entry_t ent2;
ssize_t r_bytes = read(fd, &ent2, sizeof(ent2));
assert(w_bytes == r_bytes);
assert(w_bytes == sizeof(ent1));
assert(strcmp(ent1.title, ent2.title) == 0);
assert(strcmp(ent1.artist, ent2.artist) == 0);
assert(ent1.val == ent2.val && ent1.cost == ent2.cost);
close(fd);
If your structures contain pointers or variable length members (flexible array members), you have to work harder.
Data written like this is not portable unless all the data is in strings. If you migrate the data between a big-endian and little-endian machine, one side will misinterpret what the other thinks it wrote. Similarly, there can be problems when moving data between 32-bit and 64-bit builds on a single machine architecture (if you have long data, for example, then the 32-bit system probably uses sizeof(long) == 4) but the 64-bit system probably uses sizeof(long) == 8 — unless you're on Windows.
The low-level functions might be OS specific. However they are generally these:
fopen() -> open()
fread() -> read()
fwrite() -> write()
fclose() -> close()
Note that while the 'fopen()' set of functions use a 'FILE *' as a token to represent the file, the 'open()' set of functions use an integer (int).
Using read() and write(), you may write entire structures. So, for:
typedef struct Entry {
char title[33];
char artist[17];
int val;
int cost;
} Entry_T;
You may elect to read, or write as follows:
{
int fd = (-1);
Entry_T entry;
...
fd=open(...);
...
read(fd, &entry, sizeof(entry));
...
write(fd, &entry, sizeof(entry));
...
if((-1) != fd)
close(fd);
}
Here you go:
Entry_T t;
int fd = open("file_name", _O_RDONLY, _S_IREAD);
if (fd == -1) //error
{
}
read(fd, &t, sizeof(t));
close(fd);
I've been following a tutorial for opening files from userspace from a Linux kernel module at http://www.howtoforge.com/reading-files-from-the-linux-kernel-space-module-driver-fedora-14
The code is the following:
#include <linux/module.h> // Needed by all modules
#include <linux/kernel.h> // Needed for KERN_INFO
#include <linux/fs.h> // Needed by filp
#include <asm/uaccess.h> // Needed by segment descriptors
int init_module(void)
{
// Create variables
struct file *f;
char buf[128];
mm_segment_t fs;
int i;
// Init the buffer with 0
for(i=0;i<128;i++)
buf[i] = 0;
// To see in /var/log/messages that the module is operating
printk(KERN_INFO "My module is loaded\n");
// I am using Fedora and for the test I have chosen following file
// Obviously it is much smaller than the 128 bytes, but hell with it =)
f = filp_open("/etc/fedora-release", O_RDONLY, 0);
if(f == NULL)
printk(KERN_ALERT "filp_open error!!.\n");
else{
// Get current segment descriptor
fs = get_fs();
// Set segment descriptor associated to kernel space
set_fs(get_ds());
// Read the file
f->f_op->read(f, buf, 128, &f->f_pos);
// Restore segment descriptor
set_fs(fs);
// See what we read from file
printk(KERN_INFO "buf:%s\n",buf);
}
filp_close(f,NULL);
return 0;
}
void cleanup_module(void)
{
printk(KERN_INFO "My module is unloaded\n");
}
The code is copy-pasted from the link above. On my machine, running Fedora 19 with 3.11.10-200 kernel, it seems that filp_open isn't run, providing the buf variable with null values.
What could be wrong? I am still learning the ropes of Linux kernel module development.
First thing you should do is to check if any errors are returned from filp_open (in fact, checking for NULL is probably an outright mistake when modern kernels are concerned). The proper sequence should be:
f = filp_open("/etc/fedora-release", O_RDONLY, 0);
if (IS_ERR(f)) {
// inspect the value of PTR_ERR(f), get the necessary clues
// negative values represent various errors
// as defined in asm-generic/errno-base.h
}
Only then you can move on to diagnosing the read.
977 struct file *filp_open(const char *filename, int flags, umode_t mode)
978 {
979 struct filename *name = getname_kernel(filename);
980 struct file *file = ERR_CAST(name);
981
982 if (!IS_ERR(name)) {
983 file = file_open_name(name, flags, mode);
984 putname(name);
985 }
986 return file;
987 }
Probably the error is in how you put the parameters, the flags parameter is in mode parameter position and vice versa, mode in falgs position.
source: http://lxr.free-electrons.com/source/fs/open.c#L977
For example I opened up 2 devices in an array of devices..
NODES are /dev/ttyUSB0, /dev/ttyUSB1 etc..
#define MAXDEV 4
devlist[MAXDEV];
const char *devices[] = {"/dev/ttyUSB0","/dev/ttyUSB1");
for(loop =0; loop<sizeof(devices); loop++){
fd= open(devices[loop]);
}
Now I add them to the list of fds;
for(i=0; i<MAXDEV; i++){
if(devlist[i] != 0){
devlist[i] = fd;
fd = -1;
}
}
Now I read on the devices for data.
for(iter=0; iter<MAXDEV; iter++){
if(FD_ISSET(devlist[iter],&fds)){
if ((nbytes = read(devlist[iter], buf, sizeof(buf)-1)) > 0 && nbytes != 0)
{
buf[nbytes] = '\0';
printf("Data Received on Node ???");
}
if(nbytes < 0){
printf("connection reset\n");
FD_CLR(devlist[iter], &fds);
close(devlist[iter]);
devlist[iter] = 0;
}
if(nbytes ==0){
printf("Device Removed on Node ???\n");
FD_CLR(devlist[iter], &fds);
close(devlist[iter]);
devlist[iter] = 0;
}
}
}
Now how do I get the device node using its fd?.. Thanks.
The proper way to do this is to do your own book-keeping. That would allow you to log the device node name exactly as supplied by the user, rather than provide an equivalent, yet confusingly different one.
For example you could use a hash table, to associate file descriptor numbers to char arrays with the device name used for the corresponding open() call.
A simpler, but far more fragile and definitely not recommended, solution might involve using a simple array of pointers to char with an inordinately large size, in the hopes that any file descriptor value that you may encounter can be used as an index to the appropriate string without going beyond the array bounds. This is slightly easier to code than a hash table, but it will cause your program to die horribly if a file descriptor value exceeds the maximum allowed index in your string array.
If your program is bound to the Linux platform anyway, you might be able to, uh, cheat by using the /dev/fd directory or the /proc filesystem (more specifically the /proc/self/fd directory to which /dev/fd is usually a symbolic link). Both contain symbolic links that associate file descriptor values to canonical versions of the paths that where used to open the corresponding files. For example consider the following transcript:
$ ls -l /proc/self/fd
total 0
lrwx------ 1 user user 64 Nov 9 23:21 0 -> /dev/pts/10
l-wx------ 1 user user 64 Nov 9 23:21 1 -> /dev/pts/10
lrwx------ 1 user user 64 Nov 9 23:21 2 -> /dev/pts/10
lr-x------ 1 user user 64 Nov 9 23:21 3 -> /proc/16437/fd/
You can use the readlink() system call to retrieve the target of the link that corresponds to a file descriptor of interest.
You need the fstat(2) syscall, perhaps also fstatfs(2). Check that it succeeded.
struct stat st;
memset (&st, 0, sizeof(st));
if (fstat (fd, &st))
perror("fstat");
else {
// use st, notably st.st_rdev
}
Remember that you could have a device outside of /dev. If you are sure that your device is in it, you could stat(2) every entry in it, and compare their st_rdev
Read also Advanced Linux Programming (it is online under a free license, but you may want to buy the book).
Well I can see this question is about 1 year old. But right now I was looking for a way of doing this. And I found it. For getting the device node using the file descritor you can combine stat and libudev here is an example:
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <libudev.h>
#include <iostream>
#include <fcntl.h>
int main(int argc, char *argv[])
{
struct stat sb;
// Get a file descriptor to the file.
int fd = open(argv[1], O_RDWR);
// Get stats for that file descriptor.
if (fstat(fd, &sb) == -1) {
perror("stat");
exit(EXIT_FAILURE);
}
// Create the udev context.
struct udev *udev;
udev = udev_new();
// Create de udev_device from the dev_t obtained from stat.
struct udev_device *dev;
dev = udev_device_new_from_devnum(udev, 'b', sb.st_dev);
// Finally obtain the node.
const char* node = udev_device_get_devnode(dev);
udev_unref(udev);
std::cout << "The file is in: " << node << std::endl;
return 0;
}