I have an exercise that asks me to complement the code , so that his execution obtained as a result equivalent to $ date> out.txt
#include <stdio.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#define NEWFILE (O_WRONLY | O_CREAT)
#define MODE644 (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)
int main() {
int fd;
if (fork() == 0) {
//// Code Here for add/// Result
fd=open("out.txt",NEWFILE,MODE644);
dup2(fd,1);
close(fd);
execlp("date",NULL);
exit(0);
}
wait(NULL);
}
I can not understand the three lines that have been added:
fd=open("out.txt",NEWFILE,MODE644);
dup2(fd,1);
close(fd);
The tricky bit is dup2.
int dup2(int fildes, int fildes2);
It closes filedes2 and makes it a clone of filedes. Which means, from now on when you refer to filedes2 it's as if you referred to filedes. Back to your code, you should know that STDOUT_FILENO is 1.
So your code means:
Open a file (descriptor filedes)
Close STDOUT_FILENO and make it refer to filedes
open opens the file and returns a file descriptor. dup2(fildes, fildes2) "shall cause the file descriptor fildes2 to refer to the same open file description as the file descriptor fildes", i.e. it closes standard output (if it's open) and makes stdout a copy of your new file descriptor. close then closes fd as it's no longer needed, since stdout is now the file you just opened.
Related
I can't solve a problem with standard output laugh, I'm on Unix operating system, so the file-descriptor of STD_IN = 0, STD_OUT = 1, STD_ERR = 2, basically I tried to close the descriptor associated with the standard output, and then overwrite it with that of the file I want to write to, but when I open the file it is empty.
CODE:
#include<fcntl.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<unistd.h>
/*special file's descriptor --use it or constants in unistd.h-- */
#define STD_IN 0 /*standard input stream*/
#define STD_OUT 1 /*standard output stream*/
#define STD_ERR 2 /*standard output-error stream*/
int main(unsigned int num_of_args, char** args)
{
if(num_of_args != 3)
{
write(STD_ERR, "Few argouments.\nThe use = ./executable <message> <file>\n", 69);
return -1;
}
int file_des= open(args[2], O_CREAT, 0640);
if(file_des < 0)
{
write(STD_ERR, "Error, we couldn't open file.\n", 31);
return -1;
}
//I close the descriptor associated with STD_OUT
close(STD_OUT);
//I copy the descriptor associated with fil_des on the first available descriptor(so STD_OUT)
dup(file_des);
write(STD_OUT, args[1], sizeof(args[1]));
close(file_des);
return 0;
}
It should be fine, I don't see any errors, but when I open the file I don't find the message written.
Because? help me
This code is incorrect:
int file_des= open(args[2], O_CREAT, 0640);
Per the POSIX documentation for open() (note the bolded portion - my bolding):
SYNOPSIS
#include <sys/stat.h>
#include <fcntl.h>
int open(const char *path, int oflag, ...);
int openat(int fd, const char *path, int oflag, ...);
DESCRIPTION ...
Values for oflag are constructed by a bitwise-inclusive OR of flags
from the following list, defined in <fcntl.h>. Applications shall
specify exactly one of the first five values (file access modes) below
in the value of oflag:
O_EXEC
Open for execute only (non-directory files). The result is unspecified if this flag is applied to a directory.
O_RDONLY
Open for reading only.
O_RDWR
Open for reading and writing. The result is undefined if this flag is applied to a FIFO.
O_SEARCH
Open directory for search only. The result is unspecified if this flag is applied to a non-directory file.
O_WRONLY
Open for writing only.
Your open() call needs to include either O_WRONLY or O_RDWR as you are writing to the file:
int file_des= open(args[2], O_CREAT | O_WRONLY, 0640);
The Problem
The problem here is that the file descriptor which is being assigned to file_des isn't really 1.
int test = dup(file_des);
fprintf(stderr, "%d", test);
3
Now, what could the reason be?
The problem is with how you are opening your file. O_CREAT creates a file if it does not exist.
There is no specification whether you are opening the file for read, write, or read/write.
Since you are associating your file to the file descriptor of stdout, you must use the O_WRONLY flag as well.
int file_des = open(args[2], O_CREAT | O_WRONLY, 0640);
I'm trying to solidify my understanding of who blocks when and why wrt opening, writing to, and reading from named pipes.
The following code implies that it's invalid to open a named pipe with O_WRONLY | O_NONBLOCK, but I'm not sure whether there's just some bug in my code I don't understand, or if this is generally true.
// main.c
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
int main( int argc, char* argv[] )
{
int wfd = open( "/tmp/foo", O_WRONLY | O_NONBLOCK );
printf( "wfd[%d]\n", wfd );
if ( wfd >= 0 )
{
int res = write( wfd, "0", 1 );
printf( "write: [%d], errno[%d(%s)]\n", res, errno, strerror( errno ) );
sleep(3);
printf( "writer ending!\n" );
}
return 0;
}
> ls -l /tmp/foo
prwxrwxrwx. 1 user user 0 Sep 4 10:35 /tmp/foo
>
> gcc -g main.c && ./a.out
wfd[-1]
Question: Why does opening the named pipe with O_WRONLY | O_NONBLOCK return an invalid file descriptor?
I have a suspicion that this has to do with pipes requiring both read and write ends to be open simultaneously, and my hackneyed way of getting around this (by opening one end non-blockingly) fails for this reason. But I haven't been able to find any specific documentation that either backs up that hypothesis or otherwise explains this observation.
mkfifo(3) - Linux man page:
See fifo(7) for nonblocking handling of FIFO special files.
fifo(7) - Linux man page:
A process can open a FIFO in nonblocking mode. In this case, opening for read only will succeed even if no-one has opened on the write side yet, opening for write only will fail with ENXIO (no such device or address) unless the other end has already been opened.
John's answer is correct, but to address your specific question, it's not "returning an invalid file descriptor". open returns -1 to indicate an error. In that case you can check errno (like you're doing for write) to see the cause of the error.
I have an open file descriptor which I want to duplicate in order to perform reading and seeking through both of them independently. I looked at the
int dup(int old_fd)
syscall. The problem is it does not really fit here. Man page states the following
http://man7.org/linux/man-pages/man2/dup.2.html :
After a successful return, the old and new file descriptors
may be used interchangeably. They refer to the same
open file description (see open(2)) and thus share file
offset and file status flags; for example, if the file offset is
modified by using lseek(2) on one of the file descriptors,
the offset is also changed for the other.
Is there a way to duplicate a file descriptor so they are completely independent?
In Linux, opening /proc/<pid>/fd/<n> opens the file that's currently open at fd N, but this is a new copy, not a linked duplicate like the one you get with dup() and friends.
This should create a file that contains bar, a bunch of zero bytes, then foo. Contrast with the version using dup().
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
int main(void)
{
int fd1, fd2;
char buffer[50];
fd1 = open("testfile", O_CREAT | O_TRUNC | O_RDWR, 0600);
sprintf(buffer, "/proc/self/fd/%d", fd1);
#ifndef USE_DUP
fd2 = open(buffer, O_RDWR);
if (fd2 == -1) {
perror("open");
}
#else
fd2 = dup(fd1);
#endif
if (lseek(fd1, 16, SEEK_SET) == -1) {
perror("lseek");
}
if (write(fd1, "foo", 3) == -1) {
perror("write(fd1)");
}
if (write(fd2, "bar", 3) == -1) {
perror("write(fd2)");
}
}
No — at least, not in POSIX-defined mechanisms.
If you want complete independence of the file descriptors, you need to avoid the shared open file description, which means an independent open() or equivalent.
There's a chance that there's a Linux-specific mechanism that does the job that I've not heard of. However, looking through the system calls for Linux at http://man7.org/linux/man-pages/man2/ didn't provide enlightenment.
I want to redirect a fifo to stdout and
I read the doc http://man7.org/linux/man-pages/man2/tee.2.html
It says tee(int fd_in, int fd_out,...)
but when I throw a fifo fd to the 1st arguments, it says invalid error.
#define _GNU_SOURCE
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <limits.h>
int main() {
int num = 0, fd;
char fifo[] = "/tmp/tmpfifo";
fd = open(fifo, O_RDONLY, 0644);
if (fd == -1) {
perror("open");
exit(EXIT_FAILURE);
}
num = tee(fd, STDOUT_FILENO, INT_MAX, SPLICE_F_NONBLOCK);
if (num < 0) {
perror("tee");
exit(EXIT_FAILURE);
}
fprintf(stderr,"%d\n", num);
return 0;
}
The console shows: tee:invalid arguments.
The 1st argu should be stdin?
Make sure your stdout is a pipe.
rm -f /tmp/tmpfifo
mkfifo /tmp/tmpfifo
echo hello world > /tmp/tmpfifo &
./a.out | cat #ensure that the program's stdout is a pipe
(where a.out is your program) works for me.
From tee()'s man pages:
tee() duplicates up to len bytes of data from the pipe referred to by
the file descriptor fd_in to the pipe referred to by the file
descriptor fd_out.
So, both file descriptors must refer to pipes.
In your call to tee():
tee(fd, STDOUT_FILENO, INT_MAX, SPLICE_F_NONBLOCK);
fd is a fifo, which is in turn a pipe, but STDOUT_FILENO may not refer to a pipe.
STDIN_FILENO and STDOUT_FILENO are not necessarily pipes.
If you want STDOUT_FILENO to refer to a pipe, you can run your program at the shell's command line in the following way:
yourProgram | cat
I tried to do lseek() on a file which is opened in write mode as below. But it is not working as expected.
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
main()
{
int fd = open("/local/sandbox/.C/mytest", O_WRONLY | O_APPEND);
if(fd == -1)
{
printf("\nFailed to opne file in write mode\n");
return -1;
}
lseek(fd, 2, SEEK_SET);
write(fd, "OK", 2);
write(fd, "AAAAAAAA", 3);
close(fd);
}
'mytest' file is already existed with the content "Hi, How are you". I thought after executing the program, my test will contain 'HiOKAAA, How are you". But instead it is writing "OKAAA" at the end. Is it because of O_APPEND flag? But even, I am using lseek() to change the file offset to '2' only. Can any one please let me know why it is failing?
Yes, the O_APPEND option is causing this. From the POSIX specification of open:
O_APPEND
If set, the file offset shall be set to the end of the file prior to each write.
If you want to be able to write to arbitrary locations in the file, don't use O_APPEND mode.