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.
Related
I would like to create a named pipe in the parent process and after write a string to it in the child process and finally read this string in the parent process. When run the program I dont get back the prompt like still waiting for end of child process. Why the child process not finished?
Current output:
Expected output:
(picture created without multiprocesses)
My source code:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/file.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <sys/wait.h>
int main() {
int pipefd[2];
pid_t cpid;
char szoveg[32];
int fd, ret;
char buf[32];
buf[0]=0;
cpid = fork();
if (cpid == -1) {
perror("fork");
exit(-1);
}
if (cpid == 0) {
printf("%d: Child process\n",getpid());
strcpy(buf,"Some text \0");
printf("%d:write to fifo: %s:%ld\n",getpid(),buf,strlen(buf));
write(fd,buf,strlen(buf));
exit(0);
} else {
printf("%d: Parent process\n",getpid());
ret=mkfifo("FifoName",00666);
if (ret == -1) {
perror("mkfifo()");
exit(-1);
}
fd=open("FifoName",O_RDWR);
if (fd == -1) {
perror("open() error!");
exit(-1);
}
wait(NULL);
ret=read(fd,buf,32);
printf("%d:read() Read %d bytes: %s\n",getpid(),ret,buf);
close(fd);
unlink("FifoName");
exit(0);
}
}
William Pursell right. The problem was the missing fd=open("FifoName",O_RDWR); line from child process.
I need create unnamed pipe in C without fork();
I have code with fork, but I can't find any information about unnamed pipe without fork. I read that this is an old solution, but it just needs it. Can anyone help me?
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#define KOM "Message to parent\n"
int main()
{
int potok_fd[2], count, status;
char bufor[BUFSIZ];
pipe(potok_fd);
if (fork() == 0) {
write(potok_fd[1], KOM, strlen(KOM));
exit(0);
}
close(potok_fd[1]);
while ((count = read(potok_fd[0], bufor, BUFSIZ)) > 0)
write(1, bufor, count);
wait(&status);
return (status);
}
You should be more precise, what do you need it to do? Just sending a message to yourself within the same process doesn't make much sense.
Anyway you can literally just not fork and do everything inside one process, it's just not really useful.
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/wait.h>
#define KOM "Message to parent\n"
int main()
{
int potok_fd[2], count;
char bufor[BUFSIZ];
pipe(potok_fd);
write(potok_fd[1], KOM, strlen(KOM));
fcntl(potok_fd[0], F_SETFL, O_NONBLOCK);
while ((count = read(potok_fd[0], bufor, BUFSIZ)) > 0)
write(1, bufor, count);
return 0;
}
I'm trying to use date and wc with pipes on CentOS. I'm not able to printf that I'm in parent or child. Any help is appreciated.
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <assert.h>
#include <time.h>
#include <stdlib.h>
#include <semaphore.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
/* pipe1.c - send information through pipe. */
void syserr(char* msg)
{
printf("%s", msg);
}
void child(int pfd[]){
dup2(pfd[1],1);
execl("/bin/date", "date", 0);
}
void main()
{
int pfd[2], i, pid;
char str[] = "Hello World!\n";
if (pipe(pfd) == -1)
syserr("pipe");
printf("pfd[0] = %d, pfd[1] = %d\n", pfd[0], pfd[1]);
pid=fork();
switch(pid) {
case -1:
syserr("fork");
case 0:
{
printf("I'm child'");
child(pfd);
}
default:{ /* parent only */
if(pid!=0)
{
printf("I'm parent'");
dup2(pfd[0],0); //input
execl("/bin/wc", "wc", 0);
}/*default*/
} /*switch*/
}
}
Remember that <stdio.h> is buffered, and stdout is generally line-buffered, at least when it is a terminal. See setvbuf(3)
So you should either end each of your printf format control string with a \n or call fflush(3) at appropriate places. In particular, do a fflush(NULL); before your fork and your execl.
Also use perror on failure (i.e. replace every call to syserr by perror) to understand how system calls are failing. See perror(3) & errno(3) & strerror(3).
BTW, your main is incorrectly declared. You should enable all warnings and debug info when compiling (e.g. compile with gcc -Wall -Wextra -g). Improve your code to get no more warnings. Then use the debugger gdb ...
Notice that to avoid zombie processes, your parent process should use some waiting system call like waitpid(2) or wait(2) or wait4(2)
Works now. I had to add close(pfd[0]); in child, and close(pfd[1]); in parent.
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <assert.h>
#include <time.h>
#include <stdlib.h>
#include <semaphore.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
/* pipe1.c - send information through pipe. */
void child(int pfd[]){
printf("I'm in child func\n");
close(pfd[0]);
dup2(pfd[1],1);
execl("/bin/date", "date", 0);
}
int main(){
int pfd[2], pid;
if (pipe(pfd) == -1) perror("pipe");
printf("pfd[0] = %d, pfd[1] = %d\n", pfd[0], pfd[1]);
fflush(NULL);
pid=fork();
switch(pid) {
case -1:
perror("fork");
case 0:
{
printf("I'm child\n");
child(pfd);
}
default:{ /* parent only */
if(pid!=0){
printf("I'm daddy\n");
close(pfd[1]);
dup2(pfd[0],0); //input
execl("/bin/wc", "wc", 0);
}/*default*/
} /*switch*/
}
return 0;
}
Hello stackoverflow I tried to create a program which execute a son shell process and redirect his I/O to a pipe in order to communicate with his father process.
I can execute command via the write pipe (wpipefd) but I can't get the response from the shell process on the read pipe (rpipefd).
I had 3 errors so far according to Strace : First the read function was blocking the program so I made the read fd of the reading pipe non-blocking (rpipe[0]). Then I had an EAGAIN error with the read function... Finally I got an EPIPE error when I close the read fd from rpipe (close(rpipefd[0])) in the forked process just after the use of dup2() .
I don't understand what I did wrong. Here's what I did so far :
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#define BUF_SIZE 1024
int main(int argc, char **argv)
{
int rpipefd[2], wpipefd[2], pid;
pipe(rpipefd);
pipe(wpipefd);
char buffer[BUF_SIZE] = {0};
int flags = fcntl(rpipefd[0], F_GETFL, 0);
fcntl(rpipefd[0], F_SETFL, flags | O_NONBLOCK);
pid = fork();
if(pid == 0)
{
close(rpipefd[0]);
dup2(rpipefd[1],1);
dup2(rpipefd[1],2);
close(wpipefd[1]);
dup2(wpipefd[0],0);
close(rpipefd[1]);
close(wpipefd[0]);
execl("/bin/sh","/bin/sh",NULL);
}
close(wpipefd[0]);
write(wpipefd[1],"echo helloWorld",strlen("echo helloWorld"));
close(rpipefd[1]);
read(rpipefd[0],buffer,BUF_SIZE);
//perror("read()");
printf("%s",buffer);
exit(0);
}
Please help !
The main issue doesn't come from the code itself: the command passed to the shell is incomplete, you missed the final '\n' and thus the child process (your shell) is waiting for the rest of the command.
The non-blocking part is not a good idea (or at least, you should spin around you pipe in order to retrieve its content.)
Once you're done with your command, you should close the output pipe so the shell get the end-of-file on its input.
Other remarks: you should wait for the child termination (using wait(2)), you should leave after your execl in the child process (use with err(3) for the error message) to handle exec errors. And, seriously, calling strlen on string literal ? I know that gcc is replacing it at compile time, but …
Here is a modified version of your code:
#include <err.h>
#include <errno.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
#define BUF_SIZE 1024
int main(int argc, char **argv)
{
int rpipefd[2], wpipefd[2], pid;
pipe(rpipefd);
pipe(wpipefd);
char buffer[BUF_SIZE] = {0};
pid = fork();
if(pid == 0)
{
close(rpipefd[0]);
dup2(rpipefd[1],STDOUT_FILENO);
dup2(rpipefd[1],STDERR_FILENO);
close(wpipefd[1]);
dup2(wpipefd[0],STDIN_FILENO);
close(rpipefd[1]);
close(wpipefd[0]);
execl("/bin/sh","/bin/sh",NULL);
err(1, "execl()");
}
close(wpipefd[0]);
close(rpipefd[1]);
write(wpipefd[1], "echo helloWorld\n", 16);
close(wpipefd[1]); // we're done, say it to the shell
int r;
while ( (r = read(rpipefd[0],buffer,BUF_SIZE)) )
{
if (r == -1)
{
if (errno == EAGAIN || errno == EINTR) continue;
err(1, "read()");
}
write(STDOUT_FILENO, buffer, r);
}
wait(NULL);
return 0;
}
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,