Why is the Filesystem not recognised? - c

I 'm trying to print the disk status of my current linux partition.Using the following C code:
#include <stdio.h>
#include <stdlib.h>
#include <sys/statfs.h>
struct statfs S;
int main(int argc,char *argv[]){
int i = statfs("/dev/sda3",&S);
if (i!=0){
printf("File path error!!\n");
exit(0);
}
if(S.f_type == 0xEF53){
printf("The file system is ext_fs");
}
if (S.f_type == 0x4d44)
printf("The Partition is MS DOS super magic\n");
else
printf("Some other partition\n");
printf("Optimum transfer Blocks: %ld\n",S.f_bsize);
return 0;
**The problem is that the line if(S.f_type == 0xEF53) doesn't work correctly i.e. the condition returns false even when i pass /dev/sda4 partition (My linux partition ext4).
I searched a lot but was unable to solve the problem.Please guide me here....
EDIT The value of S.f_type is 16914836

The statfs() system call returns information about a mounted filesystem. path is the pathname of any file within the mounted filesystem.
Instead, you are using it on a device, thus you aren't getting information about it, but about the filesystem where /dev resides (edit: the magic number you reported corresponds to TMPFS_MAGIC, so your /dev is a tmpfs filesystem).
You have to first mount /dev/sda3 (if it's not already mounted) and call statfs over the mountpoint or any file below it to get information about the file system through this syscall.

statfs() returns information about the filesystem containing the file pointed to by its path argument. From statfs(2) manual:
The function statfs() returns information about a mounted filesystem. path is the pathname of any file within the mounted filesystem.
When the first argument is a regular file within the filesystem you wish to interrogate your code works as expected.
I also recommend you use a switch statement and use the constants such as EXT4_SUPER_MAGIC instead of hardcoding values such as 0xEF53.

Related

What happens if you try to read/write a mapping with a deleted / disconnected backing file or device?

If I perform a mmap() on some file or a device in /dev/ that exposes memory, what happens to that mapping if the file is deleted or that device disconnected?
I've written a test program to experiment but I can't find any solid documentation on what should happen. The test program does the following
#include <stdio.h>
#include <fcntl.h>
#include <stdint.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/mman.h>
int main()
{
int fd = open("test_file", O_CREAT | O_RDWR);
uint32_t data[10000] = {0};
data[3] = 22;
write(fd, data, sizeof data);
sync();
struct stat s;
fstat(fd, &s);
uint32_t *map = (uint32_t *)mmap(NULL, s.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
close(fd);
sleep(10);
printf("%u\n", *(map+3));
*(map+9000) = 91;
printf("%u\n", *(map+9000));
return 0;
}
My page size is 4096 bytes so I made the file larger than that so the map would span multiple pages. During that 10s sleep I run the following commands:
$ rm test_file
$ sync; echo 3 > /proc/sys/vm/drop_caches
Which I believe should destroy the backing file of the map and remove all pages so that it must seek the backing file out to perform any operations on it. Then after that 10s sleep the program attempts to read from page 1 and w/r to page 3.
Surprisingly the 2 values I get printed back out are 22 and 91
Why does this happen, is this behavior guaranteed or undefined? Is it because I was using a regular file and not a device? What if the mapping was really large, would things change? Should I expect to get a SIGSEGV or a SIGBUS under some conditions?
rm just unlinks the file from a location in the filesystem (removes it from a directory). If there are other references to the file (such as a process that has it open), the file won't actually be removed -- the OS keeps a reference count of all the references to the file and only deletes it when the reference count drop to 0.
So in this case, the reference count will still be non-zero after the rm as the process has the file open. Only when the files is unmapped and closed (which happens when the process exits) will the file actually be deleted.
In the case of a device, the device file (in the filesystem) is similarly just a reference to the device driver. Removing it won't have any effect. However, if the device itself has some concept of being removed (such as removable storage), doing that will result in future access returning some error.
What happens if you try to read/write a mapping with a deleted ... file
You will still write to that file. rm only unlinks the name from the directory, the file still exists.
disconnected backing ... device?
The process will receive a SIGBUS signal.
Why does this happen, is this behavior guaranteed or undefined?
Guaranteed, files keep reference count since always.
Is it because I was using a regular file and not a device?
No. A device kind of is a regular file. You can open("/dev/sda" and write to it and rm /dev/sda. In Linux almost everything is a regular file. A file has only one more layer of indirection in kernel - a filesystem.
What if the mapping was really large, would things change?
Should I expect to get a SIGSEGV or a SIGBUS under some conditions?
See man mmap. Search for SIGBUS.

How to skip mounted files when walking through a directory tree with readdir_r

I am writing a function that recursively deletes all files and sub-directories in a directory tree, and this function will be used in multithread environment, so I would prefer opendir/readdir_r than nftw (the code is for Linux/Mac OSX/Solaris, while nftw is not thread-safe on some platform).
Since the function is deleting files, security is a great concern. If there's a link pointing to a sensitive location (e.g., the /usr/lib system directory), I don't want my function to try to delete the files under that directory. For symbolic/hard link files, lstat then S_ISLNK will do the job. However, if there's a mount point, S_ISDIR just returns true on it.
Maybe setmntent/getmntent would help, but my experiment on Linux found it can't handle following situation:
mount //192.168.0.1/share at ~/work/share (need root privilege)
mv ~/work /tmp/work (does not need root privilege)
now getmntent still reports ~/work/share as the mount point
What I want is like the FTW_MOUNT flag to nftw:
man nftw:
...
FTW_MOUNT
If set, stay within the same file system.
I am not sure if the st_dev field from struct stat is good for this, I don't know if the dev numbers are always different beyond a mount point.
with readdir_r is there a way to figure out mounted points?
Thank you!
From the Single Unix Specification - Issue 7:
3.228 Mount Point
Either the system root directory or a directory for which the st_dev field of
structure stat differs from that of its parent directory.
Note:
The stat structure is defined in detail in <sys/stat.h>.
In other words, yes, you can rely upon the device ID to determine whether you're at a mount point or not. The key to understand what a mount point is involves understanding that if something like /usr resides on the same file system as /, you will never type mount device /usr.
A simple example where /home, /tmp, /usr, and /usr/src are all on different devices:
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
int main(int argc, char *argv[])
{
struct stat stbuf;
if (stat(".", &stbuf) == -1) {
perror("couldn't get working directory");
return 1;
}
printf("Device ID for directory .: %lX\n", stbuf.st_dev);
/* Loop through the command line arguments. */
while (*++argv) {
if (stat(*argv, &stbuf) == -1) {
fprintf(stderr, "error: couldn't get device ID for directory '%s': %s\n", *argv, strerror(error));
continue;
}
printf("Device ID for directory %s: %lX\n", *argv, stbuf.st_dev);
}
return 0;
}
Sample run:
sh$ ./a.out /usr ~/misc\ files /nonexistent/path /usr/src /tmp
Device ID for directory .: 807
Device ID for directory /usr: 803
Device ID for directory /home/kit/misc files: 807
error: couldn't get device ID for directory '/nonexistent/path': No such file or directory
Device ID for directory /usr/src: 805
Device ID for directory /tmp: 802

Writing my own HTTP Server - How to find relative path of a file

I'm currently writing an HTTP Server over UNIX Sockets in C, and I'm about to implement the part of the GET request that checks the requested file to make sure it has appropriate permissions.
Before I knew anything about HTTP servers, I set up an Apache server, and it is my understanding that there is a single directory which the HTTP server looks to find a requested file. I do not know if this is because the server somehow has no permissions outside of the directory, or if it actually validates the path to ensure it is inside the directory.
Now that I am about to implement this on my own, I'm not sure how to properly handle this. Is there a function in C that will allow me to determine if a path is inside a given directory (e.g. is foo/bar/../../baz inside foo/)?
In python, I would use os.path.relpath and check if the result starts with .., to ensure that the path is not outside the given directory.
For example, if the directory is /foo/bar/htdocs, and the given path is index.html/../../passwords.txt, I want ../passwords.txt, so I can see from the leading .. that the file is outside the /foo/bar/htdocs directory.
You'd be surprised how much of Python's I/O functionality more or less maps directly to what POSIX can do. :)
In other words, look up realpath().
It's awesome when POSIX has the more descriptive name for a function, with that extra letter included! :)
How to get the absolute path for a given relative path programmatically in Linux?
#include <stdlib.h>
#include <stdio.h>
int main()
{
char resolved_path[100];
realpath("../../", resolved_path);
printf("\n%s\n",resolved_path);
return 0;
}
You can try that. As the same ser (unwind) answered there.
The way it works is much simpler: once the server receives a request, it ONLY looks at its htdoc (static contents) directory to check if the requested resource exists:
char *htdoc = "/opt/server/htdoc"; // here a sub-directory of the server program
char *request = "GET /index.html"; // the client request
char *req_path = strchr(request, ' ') + 1; // the URI path
char filepath[512]; // build the file-system path
snprintf(filepath, sizeof(filepath) - 1, "%s/%s", htdos, req_path);
FILE *f = fopen(filepath, "r"); // try to open the file
...
Note that this code is unsafe because it does not check if the request ventures in the file system by containing "../" patterns (and other tricks). You should also use stat() to make sure that the file is a regular file and that the server has permissions to read it.
As a simple (but incomplete) solution, I just decided to write a bit of code to check the file path for any ...
int is_valid_fname(char *fname) {
char *it = fname;
while(TRUE) {
if (strncmp(it, "..", 2) == 0) {
return FALSE;
}
it = strchr(it, '/');
if (it == NULL) break;
it++;
}
return TRUE;
}

to keep files after kernel rebooting

i need to use reboot() system call (to reboot the kernel 2.6.29 with ARM) and i tried the code below:
#include <stdio.h>
#include <linux/reboot.h>
#include <unistd.h>
int main()
{
reboot(LINUX_REBOOT_CMD_RESTART);
}
it works well! but what im wondering is after rebooting the kernel im loosing the files being saved.
i mean if use this code, "url" file is not saved after reboot.
int main()
{
FILE *pFile = fopen("url", "a"); // for .txt file
// write to file/read from file ... etc
fclose(pFile);
int fdUART = open("/dev/ttySAC0", O_RDWR | O_NOCTTY | O_NDELAY);
// some operations on UART port
close(fdUART);
/* Ethernet raw package process*/
/* Char dev driver open and communicate with FPGA fifo */
/* so on */
reboot(LINUX_REBOOT_CMD_RESTART);
}
and am using the UART, Ethernet, char drivers and just would like to know reboot() call systems's effect to my system.
any help highly appreciated thanks.
You've written in the comments that the file system is cramfs.
From the Wikipedia page for cramfs:
The compressed ROM file system (or cramfs) is a free (GPL'ed) read-only Linux file system designed for simplicity and space-efficiency. It is mainly used in embedded systems and small-footprint systems.
Note that it's read-only: that means your changes won't be preserved.
You'll need to write to persistent storage to have your changes preserved.

How to get inode count of a filesystem on Solaris/Unix?

I was invoking the following command and reading the outpup df -F ufs -o i. It worked fine initially but then started to fail for the reason reported and explained here http://wesunsolve.net/bugid/id/6795242.
Although the solution suggested on the above link might work but it is ugly and I want a permanent solution. So, really looking for c api on Solaris/Unix that would give me the total and available number of inodes given a filesystem.
Sample/Example is much appreciated.
The statvfs system call can be used to retrieve file system statistics including the number of total inodes and the number of free inodes. Use the system call to retrieve a statvfs structure and then inspect the f_files and f_ffree fields to determine the number of inodes and the number of free inodes, respectively.
Example:
#include <statvfs.h>
struct statvfs buffer;
int status;
fsfilcnt_t total_inodes;
fsfilcnt_t free_inodes;
...
status = statvfs("/home/betaylor/file_in_filesystem", &buffer);
total_inodes = buffer.f_files;
free_inodes = buffer.f_ffree;
...
What you want is statvfs -- see the man page on the Solaris web site.

Resources