I am trying to figure out how to correctly use tee. In my application, tee always returns EINVAL for some reason. I was getting desperate, and tried to run the example application listed in the man page of tee (for example: https://linux.die.net/man/2/tee), only to find out that even that example code always fails with: tee: Invalid argument, for example when using it as follows: cat tee.c | ./tee tee.log. Any idea why this might happen?
The example code from die.net:
#define _GNU_SOURCE
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <limits.h>
int
main(int argc, char *argv[])
{
int fd;
int len, slen;
if (argc != 2) {
fprintf(stderr, "Usage: %s <file>\n", argv[0]);
exit(EXIT_FAILURE);
}
fd = open(argv[1], O_WRONLY | O_CREAT | O_TRUNC, 0644);
if (fd == -1) {
perror("open");
exit(EXIT_FAILURE);
}
do {
/*
* tee stdin to stdout.
*/
len = tee(STDIN_FILENO, STDOUT_FILENO,
INT_MAX, SPLICE_F_NONBLOCK);
if (len < 0) {
if (errno == EAGAIN)
continue;
perror("tee");
exit(EXIT_FAILURE);
} else
if (len == 0)
break;
/*
* Consume stdin by splicing it to a file.
*/
while (len > 0) {
slen = splice(STDIN_FILENO, NULL, fd, NULL,
len, SPLICE_F_MOVE);
if (slen < 0) {
perror("splice");
break;
}
len -= slen;
}
} while (1);
close(fd);
exit(EXIT_SUCCESS);
}
tee requires a pipe for both file descriptors, fd_in and fd_out.
Your invocation does not supply a pipe for the second file descriptor, but a file descriptor referring to a TTY. Note also that the example in the manpage specifically uses a trailing | cat:
The example below implements a basic tee(1) program using the tee() system call.
Here is an example of its use:
$ date |./a.out out.log | cat
Tue Oct 28 10:06:00 CET 2014
$ cat out.log
Tue Oct 28 10:06:00 CET 2014
Not using a pipe file descriptor for the second (or first, for that matter) argument would qualify for EINVAL:
EINVAL fd_in or fd_out does not refer to a pipe; or fd_in and fd_out refer to
the same pipe.
Related
#define _GNU_SOURCE
#define _FILE_OFFSET_BITS 64
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <sys/syscall.h>
#include <stdlib.h>
#include <limits.h>
#include <errno.h>
int main(int argc, char ** argv) {
int fd[2];
int len,slen,len_out,slen_out;
pipe(fd);
int f=open(argv[1], O_WRONLY | O_CREAT | O_TRUNC, 0644);
len=tee(STDIN_FILENO,fd[1],INT_MAX,SPLICE_F_MOVE);
while (len > 0) {
slen = splice(fd[0], NULL, f, NULL, len, SPLICE_F_MOVE);
len -= slen;
if(slen==0)
break;
}
len_out = tee(STDIN_FILENO,fd[1],INT_MAX,SPLICE_F_MOVE);
while (len_out > 0) {
slen_out = splice(fd[0], NULL, STDOUT_FILENO, NULL, len_out, SPLICE_F_MOVE);
len_out -= slen_out;
if(slen_out==0)
break;
}
close(fd[1]);
close(fd[0]);
close(f);
return 0;
}
When I run my program with a pipe ex: cat test.txt| ./a.out result.txt
The content from test.txt goes into result.txt
But with the other method, ex: ./a.out result.txt <test.txt
nothing happens. Isn't it suppose to act the same ?
Also, when I splice to the STDOUT_FILENO, it never print on the standard output, and I do not understand why.
Thank you for your help
The two methods are not equivalent:
cat in.txt | will actually create a pipe to feed your program
< in.txt will just open the given file and serve it a fd 0
On second case, tee returns -1, and perror complains about an invalid argument.
You can check the nature of fd 0 using fstat and checking the st_mode value:
struct stat statbuf;
fstat(STDIN_FILENO, &statbuf);
if (statbuf.st_mode & S_IFREG)
printf("regular file");
if (statbuf.st_mode & S_IFIFO)
printf("pipe");
I have built a IPC prgram with FIFO(named piped).
A very interesting problem is that my written message may be lost.
the following is the code snippet.
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
int main()
{
char buffer[2000] = {0};
strcpy(buffer, "abc");
char *write_path = "test-123";
mkfifo(write_path, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
int dummy = open(write_path, O_RDONLY | O_NONBLOCK);
int fd = open(write_path, O_WRONLY | O_NONBLOCK);
int bytes = write(fd, buffer, 2000);
printf("write_path:%d %s %d %d\n", bytes, write_path, dummy, fd);
close(fd);
close(dummy);
}
how to reproduce?
ubuntu 1804
gcc main.c -o main
./main
cat < test-123
it will be pending. I think, it should output abc.
You open the FIFO in nonblocking mode, which in means I/O functions can fail with (-1 and errno set to) EAGAIN or EWOULDBLOCK, instead of blocking (waiting) for the function to complete. In Linux, open descriptors to a FIFO have the same semantics as pipes.
If you bothered to check for errors (printing strerror(errno) whenever open() or write() returns -1 indicating an error), you'd already know the reason why this fails. As is, the code shown does not even reproduce the problem. The following code,
#define _POSIX_C_SOURCE 200809L
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <fcntl.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
int main(int argc, char *argv[])
{
const char *msg = "The Example Message.\n";
const size_t msg_len = strlen(msg);
int rfd, wfd;
if (argc != 2 || !strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {
const char *mypath = (argc > 0 && argv && argv[0] && argv[0][0]) ? argv[0] : "(this)";
fprintf(stderr, "\n");
fprintf(stderr, "Usage: %s [ -h | --help ]\n", mypath);
fprintf(stderr, " %s FIFO\n", mypath);
fprintf(stderr, "\n");
fprintf(stderr, "This program tests opening and writing a short message to the FIFO.\n");
fprintf(stderr, "\n");
return EXIT_SUCCESS;
}
rfd = open(argv[1], O_RDONLY | O_NONBLOCK);
if (rfd == -1) {
fprintf(stderr, "%s: Cannot open FIFO for reading: %s.\n", argv[1], strerror(errno));
return EXIT_FAILURE;
}
wfd = open(argv[1], O_WRONLY | O_NONBLOCK);
if (wfd == -1) {
fprintf(stderr, "%s: Cannot open FIFO for writing: %s.\n", argv[1], strerror(errno));
return EXIT_FAILURE;
}
ssize_t n = write(wfd, msg, msg_len);
if (n == -1) {
fprintf(stderr, "%s: Cannot write to FIFO: %s.\n", argv[1], strerror(errno));
return EXIT_FAILURE;
} else
if (n != (ssize_t)msg_len) {
fprintf(stderr, "%s: Wrote only %zd of %zu bytes to the FIFO.\n", argv[1], n, msg_len);
return EXIT_FAILURE;
} else {
printf("Success!\n");
}
close(wfd);
close(rfd);
return EXIT_SUCCESS;
}
compiles (gcc -Wall -Wextra -O2 source.c -o binary) cleanly, and implements the shown code (but with error checking, and using a command line parameter for the name of the FIFO to be opened). It does not verify the named file is a FIFO, though. If run on a non-existent FIFO, it complains "FIFO: Cannot open FIFO for reading: No such file or directory."
If you create the FIFO (mkfifo test-fifo) and run the test program, there are no errors; the only output is "Success!".
If you create the FIFO, and repeatedly write data to it but never read from it, at some point the kernel buffer for the FIFO becomes full, and running the test program will report "test-fifo: Cannot write to FIFO: Resource temporarily unavailable." (which means that write() returned -1 with errno==EWOULDBLOCK or errno==EAGAIN).
You can simulate this by running e.g. bash -c 'exec 4<>test-fifo ; dd if=/dev/zero of=test-fifo bs=1 oflag=nonblock status=progress', which opens the test-fifo FIFO read-write (which in Linux always succeeds) to descriptor 4, then runs dd to fill it with zeroes, using Bash (sub-)shell. On my system, a FIFO can hold 65536 bytes (64k). After filling the FIFO like this, running the test program (./binary test-fifo) will fail as described.
Hopefully, you'll see the light and the importance and usefulness of error checking. It is NOT something you should consider as "I'll add them in later when/if I have time"; they are also an important development tool.
I am trying to write a C program which uses standard I/O and System calls to perform copying of contents of one file to another file.
So far, I have done this :
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
int main(int argc, char *argv[])
{
int fd1, fd2;
char buffer[1024];
long int n1;
if(((fd1 = open(argv[1], O_RDONLY)) == -1) || ((fd2=open(argv[2],O_CREAT|O_WRONLY|O_TRUNC, 0700)) == -1)){
perror("file problem");
exit(1);
}
while((n1=read(fd1, buffer, 1024) > 0)){
if(write(fd2, buffer, n1) != n1){
perror("writing problem ");
exit(3);
}
}
close(fd1);
close(fd2);
}
When I run the program like this :
cc copyContents.c
./a.out one.txt two.txt
Assuming that one.txt is well defined, what I want is to create a new file called two.txt and copy over all the contents of one.txt
When I look into the contents of two.txt after running the program, it has literally nothing in it. Just a blank file.
Where am I going wrong?
You wrote
while((n1=read(fd1, buffer, 1024) > 0)){
instead of
while ( (n1 = read(fd1, buffer, 1024)) > 0)
In your code the code int the while condition boils down to:
n1 = (read(fd1, buffer, 1024) > 0)
So the read is done correctly, it's return value is compared to 0, the result of the comparision (0 or 1) is assigned to n1.
This shows once more how important it is to format your code in a way that makes it readable.
You could have debugged this easily yourself with a debugger or by inserting one or two printfs in your code.
Input:
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
void typefile (char *filename)
{
int fd, nread;
char buf[1024];
fd = open (filename, O_RDONLY);
if (fd == -1) {
perror (filename);
return;
}
while ((nread = read (fd, buf, sizeof (buf))) > 0)
write (1, buf, nread);
close (fd);
}
int main (int argc, char **argv)
{
int argno;
for (argno = 1; argno < argc; argno )
typefile (argv[argno]);
exit (0);
}
Output:
student#ubuntu:~$gcc –o prg10.out prg10.c
student#ubuntu:~$cat > ff
hello`enter code here`
hai
student#ubuntu:~$./prg10.out ff
hello
hai
This is the best solution and easily executable.
input:
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
int f1, f2;
char buff[50];
long int n;
if(((f1 = open(argv[1], O_RDONLY)) == -1 || ((f2=open(argv[2], O_CREAT |
O_WRONLY | O_TRUNC, 0700))== 1)))
{
perror("problem in file");
exit(1);
}
while((n=read(f1, buff, 50))>0)
if(write(f2, buff, n)!=n)
{
perror("problem in writing");
exit(3);
}
if(n==-1)
{
perror("problem in reading");
exit(2);
}
close(f2);
exit(0);
}
Output:
cc sys.c
./a.out a.txt b.txt
cat b.txt
So, a.txt should have some content and this content is copied to b.txt
by "cat b.txt" you can cross-check the content(which is in "a.txt").
Narenda checks if n==-1 inside the loop, but, the loop test is n>0, so, that'll never happen.
Also, the test for a bad read should precede the attempt to write.
I want to send a character from a c program to a shell program. I am using a named pipe to send the letter 'a' whenever it is requsted. I should only have to open the pipe once. Here's an example:
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
int main(){
int fd;
mkfifo("/tmp/test", 0666);
fd = open("/tmp/test", O_WRONLY);
printf("Opened\n");
char * a = "a";
while(1){
printf("Writing to pipe...\n");
write(fd,a,1);
sleep(1);
}
}
And the shell executes this command as many times as it wants...
head -c 1 /tmp/test
The issue is after one head, the c will endlessly stream into the pipe, even if nobody's there.
I noticed that open() blocks until someone is on the other end. How to I tell write() to block until somebody is reading?
I would rather have this feature on write() than read(), as I think there's lots of overhead on opening the file for each request.
Thanks!
UPDATE
This is how I'm handling it in Java, it waits until I have somebody listening on this pipe before it continues on. Maybe just because it's a higher level language.
public static void writeToPipe(int val, String pipename){
try{
pipe_out = new PrintStream("/tmp/" + pipename);
}catch(Exception e){
System.out.println("Could not open a pipe for output!");
e.printStackTrace();
}
try{
pipe_out.println(val);
}catch(Exception e){
System.out.println("Could not write to pipe!");
e.printStackTrace();
}
try{
pipe_out.close();
}catch(Exception e){
System.out.println("Could not close the output pipe!");
e.printStackTrace();
}
}
UPDATE #2 - THIS IS THE SOLUTION
Here is my code based on David's idea, it's rough, but it works. I'm not checking if the named pipe exists and just supressing it from quitting.
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <sys/wait.h>
#include <stdlib.h>
int main(int argc, char **argv){
mkfifo("/tmp/test", 0666);
while(1){
int fd, status;
if ((fd = open ("/tmp/test", O_WRONLY)) == -1) {
perror ("open failed");
return 1;
}
printf("Opened Pipe\n");
char a = 'a';
int f = fork();
if(f == -1){
perror("fork");
exit(1);
}else if(f == 0){
//This is by the child process
if (write (fd, &a, 1) == -1) {
close(fd);
perror ("open failed");
return 1;
}
}else{
//This is the parent process
int w = waitpid(f, &status, WUNTRACED | WCONTINUED);
if (w == -1){
perror("waitpid");
exit(EXIT_FAILURE);
}
}
}
}
You can do what you are attempting, but understand you must limit your read to one-char on the shell side since there will be no '\n' written to the pipe. Also, you may write many more times than the shell reads. For example, you can add validations as Mr. Pursell suggests to insure your C-program is functioning and blocking on write with something similar to:
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
int main (int argc, char **argv) {
int fd;
errno = 0;
if (mkfifo (argc > 1 ? argv[1] : "/tmp/test", 0666)) {
perror ("mkfifo failed");
return 1;
}
if ((fd = open ("/tmp/test", O_WRONLY)) == -1) {
perror ("open failed");
return 1;
}
printf ("Opened\n");
char a = 'a';
while (1) {
printf ("Writing to pipe...\n");
if (write (fd, &a, 1) == -1) {
perror ("open failed");
return 1;
}
}
return 0;
}
You can test with a simple:
$ declare -i c=0; while test "$c" -lt 10 && read -n 1 ch; do
echo "read: $ch"
((c++))
done </tmp/test
Example Shell Output
read: a
read: a
read: a
read: a
read: a
read: a
read: a
read: a
read: a
read: a
You will write until the fifo buffer is full resulting in more Writing to pipe... than you have read: a.
Rough Example with fork
Continuing from the comments here is a rough example of using fork to spawn child processes to insure your C-program is always blocking on write for the shell. This example is limited to 3 repetitions, but you could just use while (1) for a continual cycle. I also added a quick counter for the write (just for my curiosity) e.g.
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
int crt_fifo_write (char *fname);
int file_exists (char *f);
int main (int argc, char **argv) {
int n = 0;
errno = 0;
while (n < 3) { /* limit example to 3 child processes */
pid_t cpid, w;
int status;
cpid = fork();
if (cpid == -1) {
perror("fork");
exit(EXIT_FAILURE);
}
if (cpid == 0) { /* Code executed by child */
if (!crt_fifo_write (argc > 1 ? argv[1] : "/tmp/test"))
fprintf (stderr, "crt_fifo_write() failed.\n");
}
else { /* Code executed by parent */
do {
w = waitpid (cpid, &status, WUNTRACED | WCONTINUED);
if (w == -1) {
perror("waitpid");
exit(EXIT_FAILURE);
}
if (WIFSIGNALED(status)) /* signal on close of read end */
printf("shell read complete. %s\n",
n < 2 ? "restarting" : "done");
} while (!WIFEXITED(status) && !WIFSIGNALED(status));
}
n++;
}
return 0;
}
/** your write 'a' to the fifo with check for existence & unlink */
int crt_fifo_write (char *fname)
{
int fd, n = 0;
errno = 0;
if (!fname || !*fname) return 0;
if (file_exists (fname))
if (unlink (fname) == -1) {
perror ("fifo exists unlink failed");
return 0;
}
if (mkfifo (fname, 0666)) {
perror ("mkfifo failed");
return 1;
}
if ((fd = open (fname, O_WRONLY)) == -1) {
perror ("open failed");
return 1;
}
printf ("Opened\n");
char a = 'a';
while (write (fd, &a, 1) != -1) {
printf ("%3d - Writing to pipe...\n", n++);
}
return 0;
}
/** atomic test that file exists (1 success, 0 otherwise) */
int file_exists (char *f)
{
errno = 0;
int flags = O_CREAT | O_WRONLY | O_EXCL;
int mode = S_IRUSR | S_IWUSR;
int fd = open (f, flags, mode);
if (fd < 0 && errno == EEXIST)
return 1;
else if (fd) { /* created, like bash touch */
close (fd);
unlink (f);
}
return 0;
}
Example Program Use/Output
$ ./bin/pipe_write_shell_fork
Opened
0 - Writing to pipe...
1 - Writing to pipe...
2 - Writing to pipe...
3 - Writing to pipe...
4 - Writing to pipe...
...
138 - Writing to pipe...
139 - Writing to pipe...
140 - Writing to pipe...
shell read complete. restarting
Opened
0 - Writing to pipe...
1 - Writing to pipe...
2 - Writing to pipe...
3 - Writing to pipe...
4 - Writing to pipe...
...
130 - Writing to pipe...
131 - Writing to pipe...
shell read complete. restarting
Opened
0 - Writing to pipe...
1 - Writing to pipe...
2 - Writing to pipe...
3 - Writing to pipe...
4 - Writing to pipe...
...
144 - Writing to pipe...
145 - Writing to pipe...
shell read complete. done
Example Shell Read/Output
$ declare -i c=0; while test "$c" -lt 10 && read -n 8 ch; do \
echo "read: $ch"; ((c++)); done </tmp/test
read: aaaaaaaa
read: aaaaaaaa
read: aaaaaaaa
read: aaaaaaaa
read: aaaaaaaa
read: aaaaaaaa
read: aaaaaaaa
read: aaaaaaaa
read: aaaaaaaa
read: aaaaaaaa
(repeated 2 more times)
Since you don't bother to check the return of write, you don't even notice that it is failing. (That is, it's not endlessly streaming into the pipe; it's just lying to you and printing "Writing to pipe..." while failing to write to the pipe.)
The only way to block on the write is to fill the pipe. But that's not your problem. The problem is that the pipe has been terminated. If you want to keep that pipe open, you'll need to have some process still alive reading from it. For example, you could do sleep 500 < /tmp/test in some other shell. Or just open the fifo for reading in the program doing the writing. (eg, add the line open("/tmp/fifo", O_RDONLY);)
The more curious issue is; why isn't your program terminating from the SIGPIPE?
In the following snippet i am redirecting the output of the ls command to input of wc -l which works perfectly .Now i also want to redirect the output of ls command to a file named "beejoutput.txt" using the following code but its not working. Need help.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(void)
{
int pfds[2];
pipe(pfds);
if (!fork())
{
dup2(pfds[1],1);
close(pfds[0]);
execlp("ls", "ls",NULL);
}
else
{
FILE *outputO=fopen ("beejoutput.txt", "w"); //opening file for writing
dup2(pfds[0],0);
dup2(fileno(outputO),pfds[0]);
close(pfds[1]);
execlp("wc", "wc","-l", NULL);
}
return 0;
}
The dup function duplicates a file descriptor, that is, both the old and new file descriptors refer to the same open file afterwards. That is different from having a single file descriptor refer to two different files at the same time.
If you want to send the same data to two different destinations, you need to spawn both commands in separate processes, and do the copying yourself, or spawn a copy of the "tee" command -- either way, you end up with three processes.
This worked for me :
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
int main(void)
{
int pfds[2];
pipe(pfds);
pid_t childpid = fork();
if (childpid == 0) {
/* Child */
dup2(pfds[1],1);
close(pfds[0]);
execlp("ls", "ls",NULL);
} else {
/* Parent */
pid_t retpid;
int child_stat;
while ((retpid = waitpid(childpid, &child_stat, 0)) != childpid && retpid != (pid_t) -1)
;
close(pfds[1]);
char buf[100];
ssize_t bytesread;
int fd = open("beejoutput.txt", O_CREAT | O_RDWR, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
if (fd == -1) {
fprintf(stderr, "Opening of beejoutput.txt failed!\n");
exit(1);
}
/* This part writes to beejoutput.txt */
while ((bytesread = read(pfds[0], buf, 100)) > 0) {
write(fd, buf, bytesread);
}
lseek(fd, (off_t) 0, SEEK_SET);
dup2(fd, 0);
execlp("wc", "wc", "-l", NULL);
}
return 0;
}
Try checking the result codes of all the system calls that you do (including dup2). This will possibly lead you to an answer. This is a good habbit, anyway.