#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <fcntl.h> // open
#include <stdio.h>
int main() {
close(1); // close standard out
open("log.txt", O_RDWR | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR);
puts("Captain's log");
chdir("/usr/include");
execl("/bin/ls", "ls", ".", (char *)NULL);
perror("exec failed");
return 0;
}
When I check log.txt, I could not find "Captain's log". I supposed it runs before execl, thus it should be there!
You are writing it to the standard output, why would you expect it to be in the file?
If you want to redirect stdout just use freopen()
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
int main()
{
FILE *file;
file = freopen("log.txt", "w", stdout);
if (file == NULL)
return -1;
printf("Captain's log");
chdir("/usr/include");
if (execl("/bin/ls", "ls", ".", NULL) != 0)
perror("exec failed");
fclose(file);
return 0;
}
Related
i have this simple program that passes a value through a named pipe from child to parent process:
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/stat.h>
#include <semaphore.h>
#include <fcntl.h>
#include <sys/wait.h>
#include <stdio.h>
int main()
{
char * myfifo = "/home/tmp/myfifo";
mkfifo(myfifo, 0666);
int fd,rec;
pid_t c=fork();
if(c==0){
fd = open(myfifo, O_WRONLY);
rec=100;
write(fd, rec, sizeof(rec));
}
if(c>0){
sleep(1);
fd = open(myfifo, O_RDONLY);
read(fd, rec, sizeof(rec));
printf("%d\n",fd);
printf("%d\n",rec);
}
}
This program prints fd=-1 and instead of rec being 100 it prints rec's address.I also tried putting &rec in read and write but it did not solve anything.What am i doing wrong?
There's an issue with this line:
write(fd, rec, sizeof(rec));
This is the prototype of write():
ssize_t write(int fd, const void *buf, size_t count);
That means that you're reading from the memory location stored in rec, not the content of rec.
The same thing applies for read(). You need to pass a pointer to rec instead of rec itself.
Also, always make sure to close files after you open and perform I/O on them.
Here's a correct copy of your code:
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/stat.h>
#include <semaphore.h>
#include <fcntl.h>
#include <sys/wait.h>
#include <stdio.h>
int main()
{
const char *myfifo = "/home/tmp/myfifo";
mkfifo(myfifo, 0666);
int fd, rec;
pid_t c = fork();
if(c == 0) {
fd = open(myfifo, O_WRONLY);
rec = 100;
write(fd, &rec, sizeof(rec));
close(fd);
}
if(c > 0) {
sleep(1);
fd = open(myfifo, O_RDONLY);
read(fd, &rec, sizeof(rec));
printf("%d\n", fd);
printf("%d\n", rec);
close(fd);
}
}
Of course, always make sure you have the proper permissions to create, read, and write files in that directory. Also, make sure the directory /home/tmp exists.
In my understanding, according to the https://linux.die.net/man/3/mkfifo,
I got an implication that I must have reader and writer file, in order to
utilize the pipe file. The source below is the writer file,
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <unistd.h>
int main(){
int fd;
char *myfifo = "./myfifo";
mkfifo(myfifo, 0777);
fd = open(myfifo, O_WRONLY);
int PID = fork();
if(PID == 0){
execl("./reader.o", "reader", (char*)NULL);
}
write(fd, "Rock and roll baby\0", sizeof("Rock and roll baby"));
close(fd);
unlink(myfifo);
return 0;
}
and the source being provided below is for the reader file.
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#define MAX_BUF 1024
int main(){
int fd;
char* myfifo = "./myfifo";
char buf[MAX_BUF];
fd = open(myfifo, O_RDONLY);
read(fd, buf, MAX_BUF);
write(STDOUT_FILENO, buf, MAX_BUF);
close(fd);
exit(EXIT_SUCCESS);
return 0;
}
When run the executable for the writer file, the command prompt goes into
halt, after printing a newline. My assumption for this problem is because the
open() in the writer file is not being able to detect the pipe file,
is that the case?
Thank you.
I suggest that you should create the FIFO before the fork, but only open the FIFO after the fork. This avoids an assortment of problems. For the most part, I've used write() to report errors to standard error; it isn't as convenient as using fprintf(stderr, …) though.
Note that the writer writes a null byte at the end of the message. The reader gets the null byte, but overwrites it with a newline before writing the resulting character array (it is no longer a string; strings have a terminal null byte at the end) to standard output. If the code used <stdio.h> to write the data (e.g. printf("%s\n", buf)), it wouldn't need to replace the null byte with a newline.
writer.c
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <unistd.h>
#ifndef READER
#define READER "./reader"
#endif
int main(void)
{
char *myfifo = "./myfifo";
if (mkfifo(myfifo, 0777) != 0)
{
write(STDERR_FILENO, "Failed to create FIFO\n",
sizeof("Failed to create FIFO\n") - 1);
}
int PID = fork();
if (PID == 0)
{
execl(READER, "reader", (char *)NULL);
write(STDERR_FILENO, "Failed to execute reader\n",
sizeof("Failed to execute reader\n") - 1);
exit(EXIT_FAILURE);
}
if (PID < 0)
{
write(STDERR_FILENO, "Failed to fork\n",
sizeof("Failed to fork\n") - 1);
exit(EXIT_FAILURE);
}
int fd = open(myfifo, O_WRONLY);
if (fd < 0)
{
write(STDERR_FILENO, "Failed to open FIFO for writing\n",
sizeof("Failed to open FIFO for writing\n") - 1);
unlink(myfifo);
exit(EXIT_FAILURE);
}
write(fd, "Rock and roll baby", sizeof("Rock and roll baby"));
close(fd);
unlink(myfifo);
int corpse;
int status;
while ((corpse = wait(&status)) > 0)
printf("Child %d exited with status 0x%.4X\n", corpse, status);
return 0;
}
reader.c
#include <fcntl.h>
#include <unistd.h>
#define MAX_BUF 1024
int main(void)
{
char* myfifo = "./myfifo";
int fd = open(myfifo, O_RDONLY);
if (fd < 0)
write(STDERR_FILENO, "Failed to open FIFO for reading\n",
sizeof("Failed to open FIFO for reading\n")-1);
else
{
char buf[MAX_BUF];
int nbytes = read(fd, buf, MAX_BUF);
if (nbytes > 0)
{
buf[nbytes-1] = '\n';
write(STDOUT_FILENO, buf, nbytes);
}
close(fd);
}
return 0;
}
Example output
Rock and roll baby
Child 43734 exited with status 0x0000
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <unistd.h>
int main(){
int fd;
char *myfifo = "./myfifo";
int PID = fork();
if(PID == 0){
execl("./reader.o", "reader", (char*)NULL);
}
mkfifo(myfifo, 0777);
fd = open(myfifo, O_WRONLY);
write(fd, "Rock and roll baby\0", sizeof("Rock and roll baby"));
close(fd);
unlink(myfifo);
return 0;
}
After having the body of the code, where the execl is, moved above the
mkfifo(),
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#define MAX_BUF 1024
int main(){
sleep(3);
int fd;
char* myfifo = "./myfifo";
char buf[MAX_BUF];
fd = open(myfifo, O_RDONLY);
read(fd, buf, MAX_BUF);
write(STDOUT_FILENO, buf, MAX_BUF);
close(fd);
exit(EXIT_SUCCESS);
return 0;
}
and having the reader have sleep() for 3 seconds, the programs started to
work; however, does anyone know if the two programs can open() the pipe file
exactly at the same time?
Thank you.
i tried to write c program in Unix environment that using execlp function.
the command is:
execlp("tsort","tsort","text.txt",">","1.txt",(char *)NULL);
syserr("execlp");
i am always gets the same error.
the error is:
tsort: extra operand `>'
what did i do wrong?
'>' is not a parameter, it is normally interpreted by a shell. If you want to achieve the same effect in C code, you have to do the same thing the shell normally does:
open a file (1.txt) for writing
fork() a new process
[in child] replace the stdout of the new process with the file's descriptor using dup2()
[in child] exec the command
Simplified example code for POSIX:
#define _POSIX_C_SOURCE 200101L
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <unistd.h>
int main(void)
{
int outfd = open("1.txt", O_CREAT|O_WRONLY|O_TRUNC, 0644);
if (!outfd)
{
perror("open");
return EXIT_FAILURE;
}
pid_t pid = fork();
if (pid < 0)
{
close(outfd);
perror("fork");
return EXIT_FAILURE;
}
if (pid)
{
// child code
dup2(outfd, 1); // replace stdout
close(outfd);
// just a "useless cat" for simplicity:
execlp("cat", "cat", "redir.c", 0);
}
else
{
// parent code
close(outfd);
int status;
waitpid(pid, &status, 0);
if (WIFEXITED(status)) return WEXITSTATUS(status);
else return EXIT_FAILURE;
}
}
As per the comment: If you don't mind replacing your process with the called program, you don't even need to fork and the program becomes very short:
#define _POSIX_C_SOURCE 200101L
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int main(void)
{
int outfd = open("1.txt", O_CREAT|O_WRONLY|O_TRUNC, 0644);
if (!outfd)
{
perror("open");
return EXIT_FAILURE;
}
dup2(outfd, 1); // replace stdout
close(outfd);
execlp("cat", "cat", "redir.c", 0);
}
This of course is not what an interactive shell does.
I try to redirect the exec function input, output result with pipe. This code works fine, however I can't exit the execlp function below, which always require new input, however I just want run it one time. How can stop it after first input.
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <signal.h>
#define ERR_EXIT(m) \
do { \
perror(m); \
exit(EXIT_FAILURE); \
} while(0)
int main(int argc, char *argv[])
{
int chi_pipe[2], par_pipe[2];
if (pipe(chi_pipe) == -1 || pipe(par_pipe) == -1)
ERR_EXIT("pipe error");
pid_t pid;
pid = fork();
if (pid == -1)
ERR_EXIT("fork error");
if (pid == 0)
{
close(chi_pipe[0]); // I don't read in channel 1
close(par_pipe[1]); // I don't write in channel 2
close(STDIN_FILENO);
dup(par_pipe[0]);
execlp("tr", "tr", "/a-z/", "/A-Z/", NULL);
close(chi_pipe[1]);
close(par_pipe[0]);
_exit(0);
}
close(par_pipe[0]);
close(chi_pipe[1]);
write(par_pipe[1], "haha\n", 5);
char buf[3024] = {0};
read(chi_pipe[0], buf, 1024*3);
printf("buf=%s", buf);
printf("\n");
close(par_pipe[1]);
close(chi_pipe[0]);
return 0;
}
I think you want this.
move the close up so the read can know that it won't get any more.
write(par_pipe[1], "haha\n", 5);
close(par_pipe[1]);
you seem to missing a dup for stdout in the child segment too,
I am trying to send a string to another program
but i am having problem using O_WRONLY | O_NONBLOCK,
if i replace that with O_RDWR the program works fine
but i wanted to know if there is a way to send/read the
string without using O_RDWR. Right now it returns a
empty string for some reason.
Writer:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#define MAX_LINE 1024
int main(int argc, char **argv)
{
char line[MAX_LINE];
int pipe;
printf("Enter line: \n");
fgets(line, MAX_LINE, stdin);
pipe = open("link1", O_WRONLY | O_NONBLOCK);
write(pipe, line, strlen(line));
system("./run"); //executing the reader
close(pipe);
return 0;
}
reader:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#define MAX_BUF 1024
int main(int argc, char **argv)
{
int fd;
char * link1 = "link1";
char buf[MAX_BUF];
fd = open(link1, O_RDONLY | O_NONBLOCK);
read(fd, buf, MAX_BUF);
printf("%s\n", buf);
close(fd);
return 0;
}
Are you running the reader first? If no process has the FIFO open for reading when the writer attempts to open it write only, then the open will fail.
From the Open Group man page:
When opening a FIFO with O_RDONLY or O_WRONLY set: If O_NONBLOCK is set:
An open() for reading only will return without delay. An open() for writing only will return an error if no process currently has the file open for reading.