C: creating named pipe using mknod() not working - c

Language: C
OS: Ubuntu
I'm simply trying to create a FIFO named pipe using the command:
state = mknod("pipe.txt", S_IFIFO | 0666, 0);
the problem is i always get the state's value to be -1 (meaning it has failed) instead of 0.
perror returns 'pipe.txt: File exists'
i have no idea how should i debug such issue or what could be the reason, hope anyone code guide me what's wrong.
(note: the file pipe.txt exist on same path as source file.)

Read: int mknod(const char *path, mode_t mode, rdev_t dev_identifier);
General Description:
Creates a new character special file or FIFO special file (named pipe), with the path name specified in the path argument.
If file already exists then it will fails with error: File exists
To avoid this error, remove(unlink()) the file, As I am doing in my below code(read comment):
int main() {
char* file="pipe.txt";
unlink(file); // Add before mknod()
int state = mknod(file, S_IFIFO | 0666, 0);
if(state < 0){
perror("mknod() error");
}
return 0;
}

You should examine errno to see what the error is but it's probably EEXIST since I believe that's what happens if the file already exists.
From the Linux documentation for mknod:
If pathname already exists, or is a symbolic link, this call fails with an EEXIST error.
However, if the file already exists and is the pipe you created in an earlier run, you can safely reopen it. All mknod (and its often preferred cousin, mkfifo) does is actually create the FIFO, you still have to open it at both ends to get the data transfer happening.

Related

How to delete a file in C using a file-descriptor?

In my code, I create a file with a random name using mkstemp() function (Im on Linux). What this function returns is an int being a file descriptor.
int fd;
char temp[] = "tempXXXXXX";
fd = mkstemp(temp);
Later I can access the file using fdopen() through that int file descriptor.
FILE *file_ptr = NULL;
file_ptr = fdopen(fd);
But at the end of my program, I would like to see if the file still exists with the random name it was given when I created it (the program should change that file name if successful). I can set a flag if the rename() function run on that file is successful, but I still don't know how to delete it when I only have its file descriptor.
if rename files => remove the temp file
How can I do that? Or is there a way to get the files name if I have its file descriptor?
Neither C nor POSIX (since you are using POSIX library functions) defines a way to delete a file via an open file descriptor. And that makes sense, because the kind of deletion you're talking about is actually to remove a directory entry, not the file itself. The same file can be hard linked into the directory tree in multiple places, with multiple names. The OS takes care of removing its data from storage, or at least marking it as available for reuse, after the last hard link to it is removed from the directory tree and no process any longer has it open.
A file descriptor is associated directly with a file, not with any particular path, notwithstanding the fact that under many circumstances, you obtain one via a path. This has several consequences, among them that once a process opens a file, that file cannot be pulled out from under it by manipulating the directory tree. And that is the basis for one of the standard approaches to your problem: unlink (delete) it immediately after opening it, before losing its name. Example:
#include <stdlib.h>
#include <unistd.h>
int make_temp_file() {
char filename[] = "my_temp_file_XXXXXX";
int fd;
fd = mkstemp(filename);
if (fd == -1) {
// handle failure to open ...
} else {
// file successfully opened, now unlink it
int result = unlink(filename);
// ... check for and handle error conditions ...
}
return fd;
}
Not only does that (nearly) ensure that the temp file does not outlive the need for it, but it also prevents the contents from being accessible to users and processes to which the owning process does not explicitly grant access.
Even though this doesn't exactly answer the question you're asking about mkstemp, consider creating a temporary file that will automatically be deleted, unless you rename it.
Instead of mkstemp you could call open combined with the creation flag O_TMPFILE to create a temporary, unnamed file that is automatically deleted when file is closed.
See open(2):
O_TMPFILE (since Linux 3.11)
Create an unnamed temporary regular file. The pathname argu‐
ment specifies a directory; an unnamed inode will be created
in that directory's filesystem. Anything written to the
resulting file will be lost when the last file descriptor is
closed, unless the file is given a name.
Instead of a filename, you call open with the path where you prefer to place the temporary file, like:
temp_fd = open("/path/to/dir", O_TMPFILE | O_RDWR, S_IRUSR | S_IWUSR);
If you like to give the temporary file a permanent location/name, you can call linkat on it later:
linkat(temp_fd, NULL, AT_FDCWD, "/path/for/file", AT_EMPTY_PATH);
Note: Filesystem support is required for O_TMPFILE, but mainstream Linux filesystems do support it.
readlink provide you the name of your file depending of the file descriptor if you use the path /proc/self/fd/ adding you fd.
Then use remove for deleting the file passing the name readlink gave you
ssize_t readlink(const char *path, char *buf, size_t bufsiz); (also load ernno)
int remove(const char *filename); (returns zero is successful, otherwise nonzero)
I hope something like that could helped you ?
⚠ Don't copy/past this you must edit "filename"; _BUFFER, _BUFSIZE ⚠
#include<stdio.h>
#include <unistd.h>
#include <stdlib.h>
int delete_file(int fd) {
char *str_fd = itoa(fd, str_fd, 10);
char *path = strcat("/proc/self/fd/", str_fd);
if (read_link(path, buffer, bufsize) == -1)
return -1;
int del = remove(filename);
if (!del)
printf("The file is Deleted successfully");
else
printf("The file is not Deleted");
return 0;
}
(feel free to edit this, i didn't test the code and i let you handel the buffer and buffer size)

Why is my popen failing

My c code is
size_t n=0;
char *str = (char *)malloc(sizeof(char)* 1000)
FILE *fp = popen(" cat /conf/a.txt" ,"r" );
// my program comes in this function only if /conf/a.txt exists
getline(&str, &n, fp); <== crash if fp is null
My debugger shows that sometimes i get fp as null and hence my program crashes at line 6 . Sometimes i get valid pointere and it passes .
What is it , that controls this behaviour . I can't find problem in above code . Some help is appreciated .
I know I can have a check of fp==null but that is not my question . I just want to know , knowing that file is definitely present why is fp coming as null in some scenarios .
man of popen says The popen() function returns NULL if the fork(2) or pipe(2) calls fail, or if it cannot allocate memory.
i checked after crash and system is having enough memory ..
strerror and errno are your friends.
Example from the C++ references linked:
/* strerror example : error list */
#include <stdio.h>
#include <string.h>
#include <errno.h>
int main ()
{
FILE * pFile;
pFile = fopen ("unexist.ent","r");
if (pFile == NULL)
printf ("Error opening file unexist.ent: %s\n",strerror(errno));
return 0;
}
Example output:
Error opening file unexist.ent: No such file or directory
Using this method of checking errno after a failure will allow you to better diagnose your issue as it will print a more specific error message. There are many reasons a file can't be opened: no permission, bad path, file is locked from another process, IO errors during reading, etc. Ultimately your question seems to be asking why the open failed. Using these tools will answer that for you.
Update For Tag Change:
I've referenced and linked to C++ resources, but sterror and errno are both available in C as well by including errno.h.
popen() also fails if too many file handles are open in one process. I had one case in a server app, that was scanning one directory periodically for files.There was one scenario were no fclose call was made. So after some hours we reached the limit of 1024 open file handles on from that moment consecutive popen() calls would fail.
You can use ps -aux | grep {PROC_NAME} to retrieve the process id.
Then use sudo ls -l /proc/{PROC_ID}/fd to see the list of open file descriptors.

Check if input file is a valid file in C

I am trying to open a file in c using open() and I need to check that the file is a regular file (it can't be a directory or a block file). Every time I run open() my returned file discriptor is 3 - even when I don't enter a valid filename!
Here's what I have
/*
* Checks to see if the given filename is
* a valid file
*/
int isValidFile(char *filename) {
// We assume argv[1] is a filename to open
int fd;
fd = open(filename,O_RDWR|O_CREAT,0644);
printf("fd = %d\n", fd);
/* fopen returns 0, the NULL pointer, on failure */
}
Can anyone tell me how to validate input files?
Thanks!
Try this:
int file_isreg(const char *path) {
struct stat st;
if (stat(path, &st) < 0)
return -1;
return S_ISREG(st.st_mode);
}
This code will return 1 if regular, 0 if not, -1 on error (with errno set).
If you want to check the file via its file descriptor returned by open(2), then try:
int fd_isreg(int fd) {
struct stat st;
if (fstat(fd, &st) < 0)
return -1;
return S_ISREG(st.st_mode);
}
You can find more examples here, (specifically in the path.c file).
You should also include the following headers in your code (as stated on stat(2) manual page):
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
For future reference, here is an excerpt of the stat(2) manpage regarding the POSIX macros available for st_mode field validations:
S_ISREG(m) is it a regular file?
S_ISDIR(m) directory?
S_ISCHR(m) character device?
S_ISBLK(m) block device?
S_ISFIFO(m) FIFO (named pipe)?
S_ISLNK(m) symbolic link? (Not in POSIX.1-1996.)
S_ISSOCK(m) socket? (Not in POSIX.1-1996.)
int isValidFile(char *filename) {
// We assume argv[1] is a filename to open
int fd;
fd = open(filename,O_RDWR|***O_CREAT***,0644);
printf("fd = %d\n", fd);
/* fopen returns 0, the NULL pointer, on failure */
}
you are using 0_CREAT which prompts the function to create if the file doesn't exist.this in the table its number is 3 (0,1,2 being std input std output and std error)
Wrong: check if the file is OK, then if it is, go open it and use it.
Right: go open it. If you can't, report the problem and bail out. Otherwise, use it (checking and reporting errors after each opetation).
Why: you have just checked that a file is OK. That's fine, but you cannot assume it will be OK in 0.000000017 seconds from now. Perhaps the disk wil overheat and break down. Perhaps some other process will mass-delete your entire file collection. Perhaps your cat will trip over the network cable. So let's just check if it's OK again, and then go open it. Wow, what a great idea! No wait...

Unable to open file C

For the following snippet of code, I get an error:
Unable to open file: No such file or directory
redirect_ptr is char**
And I have tried printing redirect_ptr[0], it prints it correctly. Any idea where the problem might lie?
if ((in_fd = open(redirect_ptr[0], O_RDWR | O_CREAT)) == -1) {
perror("Unable to open file");
return -1;
}
When you create a file, open() needs an additional argument, the permission bits on the file to create.
You need to do e.g.
if ((in_fd = open(redirect_ptr[0], O_RDWR | O_CREAT, 0644) == -1)
That might not be the cause of the error you get, however if the error is "No such file or directory", then that's precisely what is wrong, you program cannot find the file.
Perhaps you have some non-printable characters in the file name, or the name ends with a space or newline or similar, or you spelled the name wrong, or have the wrong case, or the path is a relative path that doesn't match the file based on the current working directory of your process.
It's often helpful to print the filename inside a pair of '' , so you can see if there's some whitespace that should not be there. add a
printf("Filename: '%s'\n",redirect_ptr[0]);
to your code. And if it looks good, do a ls -l on the filename it prints out, standing in the working directory of the process.

C system calls open / read / write / close and O_CREAT|O_EXCL

Given the following code (it's supposed to write "helloworld" in a "helloworld" file, and then read the text):
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#define FNAME "helloworld"
int main(){
int filedes, nbytes;
char buf[128];
/* Creates a file */
if((filedes=open(FNAME, O_CREAT | O_EXCL | O_WRONLY | O_APPEND,
S_IRUSR | S_IWUSR)) == -1){
write(2, "Error1\n", 7);
}
/* Writes hello world to file */
if(write(filedes, FNAME, 10) != 10)
write(2, "Error2\n", 7);
/* Close file */
close(filedes);
if((filedes = open(FNAME, O_RDONLY))==-1)
write(2, "Error3\n", 7);
/* Prints file contents on screen */
if((nbytes=read(filedes, buf, 128)) == -1)
write(2, "Error4\n", 7);
if(write(1, buf, nbytes) != nbytes)
write(2, "Error5\n", 7);
/* Close file after read */
close(filedes);
return (0);
}
The first time I run the program, the output is:
helloworld
After that every time I to run the program, the output is:
Error1
Error2
helloworld
I don't understand why the text isn't appended, as I've specified the O_APPEND file.
Is it because I've included O_CREAT?
It the file is already created, shouldn't O_CREAT be ignored?
O_EXCL forces the file to be created. If the file already exists, the call fails.
It is used to ensure that the file has to be created, with the given permissions passed in the third parameter. In short, you have these options:
O_CREAT: Create the file with the given permissions if the file doesn't already exist. If the file exists, it is opened and permissions are ignored.
O_CREAT | O_EXCL: Create the file with the given permissions if the file doesn't already exist. If the file exists, it fails. This is useful in order to create lockfiles and guarantee exclusive access to the file (as long as all programs which use that file follow the same protocol).
O_CREAT | O_TRUNC: Create the file with the given permissions if the file doesn't already exist. Otherwise, truncate the file to zero bytes. This has more of the effect we expect when we think "create a new blank file". Still, it keeps the permissions already present in the existing file.
More information from the manual page:
O_EXCL
When used with O_CREAT, if the file
already exists it is an error and
the open() will fail. In this context,
a symbolic link exists, regardless of
where it points to. O_EXCL is broken
on NFS file systems; programs which
rely on it for performing locking
tasks will contain a race condition.
The solution for performing atomic
file locking using a lockfile is to
create a unique file on the same file
system (e.g., incorporating hostname
and pid), use link(2) to make a link
to the lockfile. If link() returns 0,
the lock is successful. Otherwise, use
stat(2) on the unique file to check if
its link count has increased to 2, in
which case the lock is also
successful.

Resources