Why does word count output 0 0 0 in the following program?
int main(int argc, char **argv) {
pid_t pid = fork();
const char *data = "THIS IS MY DATA.";
if(pid == 0) {
// Child Process
char *tmpname = malloc(15);
strcpy(tmpname, "/tmp/datXXXXXX");
int f = mkstemp(tmpname);
//int f = open("tmpfile", O_RDWR | O_CREAT, S_IRWXU);
if(f == -1) {
perror("");
return;
}
int written = write(f, data, strlen(data));
dup2(f, STDIN_FILENO);
close(f);
char *wcargs[5] = {"wc", NULL};
execvp("wc", wcargs);
fprintf(stderr, "ERROR");
}
return 1;
}
Try rewinding stdin after the dup2() using lseek(0, 0, SEEK_SET). In your code, wc will be trying to read from the end of the file and obviously won't have any bytes to read.
Related
I have a school project which consists of reproducing the shell pipe command between two commands that the operator will choose as it pleases.
./pipex infile "ls -l" "wc -l" outfile
should be equivalent to
< infile ls -l | wc -l > outfile
Here is my way of doing it:
void first_child(char **argv, char **envp, int pipefd[2], int fd[2])
{
char **cmd_and_options1;
char *path_ultime1;
int pid1;
pipefd[0] = open(argv[1], O_RDONLY);
pid1 = fork();
if (pid1 == -1)
error();
if (pid1 == 0)
{
dup2(fd[1], STDOUT_FILENO);
dup2(pipefd[0], STDIN_FILENO);
close(pipefd[0]);
close(fd[1]);
execve(path_ultime1, cmd_and_options1, envp);
}
}
void second_child(char **argv, char **envp, int pipefd[2], int fd[2])
{
char **cmd_and_options2;
char *path_ultime2;
int pid2;
pipefd[1] = open(argv[4], O_CREAT | O_WRONLY | O_TRUNC, 0777);
pid2 = fork();
if (pid2 == -1)
error();
if (pid2 == 0)
{
dup2(fd[0], STDIN_FILENO);
dup2(pipefd[1], STDOUT_FILENO);
close(pipefd[1]);
close(fd[0]);
execve(path_ultime2, cmd_and_options2, envp);
}
}
int main(int argc, char *argv[], char **envp)
{
int pipefd[2];
int fd[2];
char **cmd_and_options1;
char **cmd_and_options2;
char *path_ultime1;
char *path_ultime2;
(void)argc;
cmd_and_options1 = ft_split(argv[2], ' ');
cmd_and_options2 = ft_split(argv[3], ' ');
path_ultime1 = find_path(cmd_and_options1[0], envp);
path_ultime2 = find_path(cmd_and_options2[0], envp);
if (pipe(fd) == -1)
error();
first_child(&argv[1], envp, &pipefd[0], &fd[0]);
second_child(&argv[4], envp, &pipefd[1], &fd[1]);
close(pipefd[0]);
close(pipefd[1]);
close(fd[0]);
close(fd[1]);
waitpid(-1, NULL, 0);
waitpid(-1, NULL, 0);
return (0);
}
Roles of my find_path function:
extract the contents of PATH from the envp
use split() to delimit the paths according to ":" and store them in a double pointer
use strjoin() to append a "/" to the end of each path, and add the user command
test each path with access() then return the valid path
char *find_path(char *cmd, char **envp)
{
char **array_of_paths;
char *path_ultime;
int i;
char *temp;
i = 0;
while (ft_strnstr(envp[i], "PATH=", 5) == 0)
i++;
array_of_paths = ft_split(envp[i] + 5, ':');
i = 0;
while (array_of_paths[i])
{
temp = ft_strjoin(array_of_paths[i], "/");
path_ultime = ft_strjoin(temp, cmd);
free(temp);
if (access(path_ultime, F_OK | X_OK) == 0)
return (path_ultime);
i++;
}
return (0);
}
When I put all my code in the main(), my program worked.
But when I try to separate it into functions it doesn't work anymore and I don't understand what the problem is.
I have a school project which consists of reproducing the shell pipe command between two commands that the operator will choose as it pleases.
./pipex infile "ls -l" "wc -l" outfile
should be equivalent to
< infile ls -l | wc -l > outfile
Roles of my find_path function:
extract the contents of PATH from the envp
use split() to delimit the paths according to ":" and store them in a double pointer
use strjoin() to append a "/" to the end of each path, and add the user command
test each path with access() then return the valid path
char *find_path(char *cmd, char **envp)
{
char **array_of_paths;
char *path_ultime;
int i;
char *temp;
i = 0;
while (ft_strnstr(envp[i], "PATH=", 5) == 0)
i++;
array_of_paths = ft_split(envp[i] + 5, ':');
i = 0;
while (array_of_paths[i])
{
temp = ft_strjoin(array_of_paths[i], "/");
path_ultime = ft_strjoin(temp, cmd);
free(temp);
if (access(path_ultime, F_OK | X_OK) == 0)
return (path_ultime);
i++;
}
return (0);
}
My main takes care of:
split the argv[2] and the argv[3] with a space as delimiter, to keep only the command "ls" or "wc", and not the options
classic stuff like pipe(), fork(), execve() …
int main(int argc, char *argv[], char **envp)
{
(void)argc;
pid_t pid1;
pid_t pid2;
int fd[2];
char **cmd_and_options1;
char **cmd_and_options2;
char *path_ultime1;
char *path_ultime2;
cmd_and_options1 = ft_split(argv[2], ' ');
cmd_and_options2 = ft_split(argv[3], ' ');
path_ultime1 = find_path(cmd_and_options1[0], envp);
path_ultime2 = find_path(cmd_and_options2[0], envp);
if (pipe(fd) == -1)
return (1);
pid1 = fork();
if (pid1 == -1)
return (1);
if (pid1 == 0) // First child
{
dup2(fd[1], STDOUT_FILENO);
close(fd[0]);
close(fd[1]);
execve(path_ultime1, cmd_and_options1, envp);
}
pid2 = fork();
if (pid2 == -1)
return (1);
if (pid2 == 0) // Second child
{
dup2(fd[0], STDIN_FILENO);
close(fd[0]);
close(fd[1]);
execve(path_ultime2, cmd_and_options2, envp);
}
close(fd[0]);
close(fd[1]);
waitpid(pid1, NULL, 0);
waitpid(pid2, NULL, 0);
return (0);
}
A friend told me that I lacked the management of the input and output file (argv[1] and argv[4]) that the operator will enter but I don't really understand what that means.
I know I have to use open() somewhere...
Can you give me some clues?
I'm trying to simulate Unix shell multi pipes in c and I found a source code of a function doing the same thing but I didn't understand it well, if you can please explaint to me how's works, I know that pipe fd[2] creates fd[0] read input, and fd[1] write input as well dup2 close selected FD and duplicate it to FD through the pipe.
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
/*
* loop over commands by sharing
* pipes.
*/
static void
pipeline(char ***cmd)
{
int fd[2];
pid_t pid;
int fdd = 0; /* Backup */
while (*cmd != NULL) {
pipe(fd); /* Sharing bidiflow */
if ((pid = fork()) == -1) {
perror("fork");
exit(1);
}
else if (pid == 0) {
dup2(fdd, 0);
if (*(cmd + 1) != NULL) {
dup2(fd[1], 1);
}
close(fd[0]);
execvp((*cmd)[0], *cmd);
exit(1);
}
else {
wait(NULL); /* Collect childs */
close(fd[1]);
fdd = fd[0];
cmd++;
}
}
}
/*
* Compute multi-pipeline based
* on a command list.
*/
int
main(int argc, char *argv[])
{
char *ls[] = {"ls", "-al", NULL};
char *rev[] = {"rev", NULL};
char *nl[] = {"nl", NULL};
char *cat[] = {"cat", "-e", NULL};
char **cmd[] = {ls, rev, nl, cat, NULL};
pipeline(cmd);
return (0);
}
I'm trying to write a shell in c and I want to implement the behavior of "cat > file" to then let me write into a file.
My main function:
int main (int argc, char **argv)
{
pid_t childPid;
int status;
char * cmdLine;
int EXIT = 1;
parseInfo info;
int fd[2];
char buffer[1024];
char* env = getenv("USER");
char cwd[BUFFER];
if (getcwd(cwd, sizeof(cwd)) == NULL) {
perror("getcwd() error");
return 1;
}
while (EXIT){
printf("%s#%s > ",env,cwd);
cmdLine = readline();
info = parse(cmdLine);
info.cwd = cwd;
pipe(fd);
childPid = fork();
if (childPid == 0)
{
executeCommand(info,fd);
}
else
{
close(fd[1]);
if((read(fd[0], buffer, 1024 * sizeof(char))) == -1){
printf("Failed reading from pipe.\n");
}
else{
if(!strcmp(info.cmd,"cd")){
strcpy(cwd,buffer);
chdir(buffer);
}
}
while (wait(&status) != childPid);
}
}
}
the executeCommand:
void executeCommand(parseInfo info,int* fd){
//print_info(info); // FOR DEBUGGING
if(!strcmp(info.cmd,"cat")){
cat(info);
}
else if(!strcmp(info.cmd,"cd")){
info.cwd = changedir(info,info.cwd);
if(write(fd[1], info.cwd, ((strlen(info.cwd)+1)* sizeof(char))) == -1)
printf("Error while writing into pipe\n");
}
else if(execvp(info.cmd,info.args) == -1){
printf("Error: unknown command [%s]\n",info.cmd);
}
exit(1);
}
Here's my cat function:
void cat(parseInfo info){
char* write_to_file = ">";
char* append_to_file = ">>";
if(!strcmp(info.args[1],write_to_file) || !strcmp(info.args[1],append_to_file)){
if (info.args[2] == NULL){
printf("unsupported sytax, file name expected.\n");
}
char* line;
FILE* fp;
if(!strcmp(info.args[1],write_to_file))
fp = fopen(info.args[2],"w");
if(!strcmp(info.args[1],append_to_file))
fp = fopen(info.args[2],"a");
while(1){
line = readline();
fputs(line,fp);
}
fclose(fp);
}
}
How do I make ctrl-c not kill the parent process and just run fclose and kill the child only?
Or is there another method that's better here?
I'm not sure how to implement this.
I see it's easy to open pipe between two process using fork, but how we can passing open pipe to threads.
Assume we need to pass out of PROGRAM A to PROGRAM B "may by more than one thread",
PROGRAM B send his output to PROGRAM C
EDIT:
I come again after modifying the code to become more easy for reading.
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <fcntl.h>
void *thread1(void *arg) {
int status, fd[2];
pid_t pid;
pipe(fd);
pid = fork();
if (pid == 0) {
int fd2 = *((int *) (arg));
dup2(STDIN_FILENO, fd2);
close(fd[0]);
dup2(fd[1], STDOUT_FILENO);
close(fd[1]);
execvp("PROGRAM B", NULL);
exit(1);
} else {
close(fd[1]);
dup2(fd[0], STDIN_FILENO);
close(fd[0]);
execl("PROGRAM C", NULL);
wait(&status);
return NULL;
}
}
int main(void) {
FILE *fpipe;
char *command = "PROGRAM A";
char buffer[1024];
if (!(fpipe = (FILE*) popen(command, "r"))) {
perror("Problems with pipe");
exit(1);
}
char* outfile = "out.dat";
//FILE* f = fopen (outfile, "wb");
//int fd = fileno( f );
int fd[2];
fd[0] = open(outfile, O_WRONLY);
pthread_t thid;
if (pthread_create(&thid, NULL, thread1, fd) != 0) {
perror("pthread_create() error");
exit(1);
}
int len;
while (read(fpipe, buffer, sizeof (buffer)) != 0) {
len = strlen(buffer);
write(fd[0], buffer, len);
}
pclose(fpipe);
return (0);
}
For intra-process messaging, POSIX queues will probably suit your needs better than pipes. Check out man mq_overview (or online).