1
  //  This is my code for reading a file from command line arguments and storing it in another file.//
    
    
    #include <stdio.h>
    #include <stdlib.h>
    
    #include <sys/types.h>
    #include <fcntl.h>
    
    #include <unistd.h> //for system calls such as dup(),pipe(),etc...
    
    #include <sys/wait.h>
    
    #define COUNT_PROGRAM "b"
    #define CONVERT_PROGRAM "c"
    
    int main(int argc, char *argv[])
    {
        if (argc != 3)
        {
            fprintf(stderr,"%s","ERROR : argument count not satisfied!\n");
            exit(1);
        }
    
        /* It is important to check all system calls (open, creat, dup, etc.) for a return value < 0, 
        particularly -1 because such a return value means an error has occurred. */
    
        int fd_in = open(argv[1], O_RDONLY);
        if (fd_in < 0) 
        {
            fprintf(stderr,"%s", "ERROR : file to be read does not exist!\n");
            exit(1);
        }
        
     int fd_out = creat(argv[2], 0644); /* mode = permissions, here rw-r--r-- */
        if (fd_out < 0)
        {
            fprintf(stderr,"%s", "ERROR : file could not be created!\n");
            exit(1);
        }
        
        
        if(dup(fd_in) < 0)//dup fd_in to 3
            fprintf(stderr , "ERROR assigning STREAM 3 to fd_in");     
        if(dup(fd_out) < 0)//dup fd_in to 4
            fprintf(stderr , "ERROR assigning STREAM 4 to fd_out");
    
        //dup fd_in to 0
        close(0);
        dup(fd_in);
        close(3);
    
        //dup fd_out to 1
        close(1);
        dup(fd_out);
        close(4);
    
        int fd[2];
    
        pipe(fd);   
    
        pid_t pid_child_1, pid_child_2;
        int status;
    
        if ((pid_child_1 = fork()) != 0)
        {      
            if ((pid_child_2 = fork()) != 0) 
            { 
                close(fd[0]);         
                close(fd[1]);  
                wait(&status);
                wait(&status);          
                // fprintf(stderr , "\nstatus of child_1 = %d",wait(&status));           
                // fprintf(stderr , "\nstatus of child_2 = %d",wait(&status));       
            } 
            else 
            {
                // close(fd[1]);
                // dup(1);       
                dup2(fd[1],1);  
                close(fd[0]);
                execl( CONVERT_PROGRAM, CONVERT_PROGRAM, (char*) NULL);
            }    
        } 
            
        else 
        {
            // close(fd[0]);
            // dup(0);
            dup2(fd[0],0);
            close(fd[1]);
            execl( COUNT_PROGRAM , COUNT_PROGRAM ,(char*) NULL);  
        }
    
    
    }

After compiling my text file which should contain the output is empty. THOSE PROGRAMS ARE WORKING WELL ALONE.

Here I am adding the strace result after running the strace command. Here it is printing 7 on the screen and no output in the text file.

  read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\20\35\2\0\0\0\0\0"..., 8                                                                             32) = 832
strace: Process 6018 attached
strace: Process 6019 attached
[pid  6019] read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\20\35\2\0\0\                                                                             0\0\0"..., 832) = 832
[pid  6018] read(4, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\20\35\2\0\0\                                                                             0\0\0"..., 832) = 832
[pid  6019] read(0, "hello my name is himanshu KAUSHI"..., 4096) = 35
[pid  6019] read(0, "", 4096)           = 0
[pid  6019] write(1, "HELLO MY NAME IS HIMANSHU kaushi"..., 35) = 35
[pid  6019] +++ exited with 0 +++
[pid  6018] read(0, "HELLO MY NAME IS HIMANSHU kaushi"..., 4096) = 35
[pid  6017] --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=6019, si_u                                                                             id=1062, si_status=0, si_utime=0, si_stime=0} ---
[pid  6018] read(0, "", 4096)           = 0
[pid  6018] write(2, "\n7", 2
7)          = 2
[pid  6018] +++ exited with 0 +++
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=6018, si_uid=1062, si_                                                                             status=0, si_utime=0, si_stime=0} ---
+++ exited with 0 +++

I changed standard table descriptors in 1st dup2(f_dsc[1],3) command and I got the output in the text file but then my first program stooped running.

#include<stdio.h>
#include<ctype.h>

int main()
{
        char c;
        int count=0;

                while(1)
                {
                        c=getchar();
                        if(c==EOF)
                        {
                                break;
                        }
                        if(!isalpha(c))
                        {
                                count++;
                        }
                }
                fprintf(stderr,"\n%d",count);


}

this is my simple b program.

#include<stdio.h>
#include<ctype.h>
int main()
{
        char c;
        int count=0;
        while(1)
        {
                c=getchar();
                if(c==EOF)
                {
                        break;
                }
                if(islower(c))
                {
                        c=toupper(c);
                }
                else
                {
                        c=tolower(c);
                }

                putchar(c);
        }
        return 0;
}

and this is my simple c program.

  • 1
    Let the system tell you why the system calls failed. eg `if( fd_in == -1 ){ perror(argv[1]); exit(EXIT_FAILURE);}` – William Pursell Jan 13 '21 at 11:50
  • The boilerplate for `dup2` is: `dup2(fd[0], 0); close(fd[0]); close(fd[1]);` Make sure you close both ends of the pipe. (You just dup'd fd[0] to 0, so you don't need fd[0] anymore). – William Pursell Jan 13 '21 at 11:54
  • @WilliamPursell Thanks but still not working. – Himanshu Kaushik Jan 14 '21 at 05:16
  • From the `strace` output I take that your program `b` successfully converts upper to lower case and vice versa and that the converted text is read by program `c`, which outputs a newline and `7`, but not to the (redirected) _stdout_, but rather to _stderr_ (file number 2); therefore you see the `7` on the terminal. – Armali Jan 14 '21 at 19:46
  • Have you closed `fd[1]` in the process that execs CONVERT PROGRAM? My guess is that the consumer (COUNT_PROGRAM) is blocked on a read because that file descriptor is still open. Add some diagnostics. – William Pursell Jan 14 '21 at 19:46
  • @Himanshu Kaushik - And now, seeing your `b` code `fprintf(stderr,"\n%d",count);`, it's clear why the output doesn't go to the file. You should use `printf("%d\n", count);` instead. – Armali Jan 14 '21 at 19:52
  • @Armali b should print on screen 7 as good but c should store in text file – Himanshu Kaushik Jan 14 '21 at 20:03
  • @Armali as i can see in strace output that my convert program has converted the file and also writing to file but I didn't get any output. – Himanshu Kaushik Jan 14 '21 at 20:06
  • Do you really mean that `c` should store the case-converted text in a file as well as pass the text to `b`? This would require duplicating the text, which is done nowhere in your code. – Armali Jan 14 '21 at 20:19
  • 1
    @Armali I mean both the programs should read from the file which in fd_in connected to 0 of the descriptor table and b program should print the output on the screen while c program store the output in the text file for which I have connected the fd_out to 1 of the descriptor table. – Himanshu Kaushik Jan 14 '21 at 20:29
  • You connected the standard input of `b` to the read end of the _pipe_ with `dup2(fd[0],0)` and the write end of the pipe to the standard output of `c` with `dup2(fd[1],1)`, hence the output of `c` goes thru the pipe to `b`, not to a file. – Armali Jan 14 '21 at 20:39
  • @Armali yes but look at the code in parent I have connected standard input to the read end of the pipe and standard output to the file. – Himanshu Kaushik Jan 14 '21 at 20:44
  • @Armali /dup fd_in to 0 close(0); dup(fd_in); close(3); //dup fd_out to 1 close(1); dup(fd_out); close(4); in this code – Himanshu Kaushik Jan 14 '21 at 20:44
  • The later `dup2` override that. – Armali Jan 14 '21 at 20:47
  • Besides that, if two programs would read a file from the same file descriptor or a duplicate, each program would get a part of the file - a character read by one program would not be read by the other. – Armali Jan 14 '21 at 20:48
  • @Armali as much as i have learned in my 4 online classes that for child process the f_dsc make other copies and if it doesn't what should I do. – Himanshu Kaushik Jan 14 '21 at 20:53
  • If I understood correctly and you want to connect the standard input descriptors of both `b` and `c` to the file so that they can read it independently, you don't need a pipe. Just let your `myprogram` open the input file twice, so you get two independent descriptors, say `fda` and `fdb`, for it, and `dup2(fda, 0)` before `execl(CONVERT_PROGRAM, ...)` as well as `dup2(fdb, 0)` before `execl(COUNT_PROGRAM, ...)`. And if you drop the `dup2(fd[1],1)`, the output redirection to `fd_out` will stay in effect. - Now it's time for me to say good night. Tomorrow I'll see how this went for you. – Armali Jan 14 '21 at 21:07
  • 1
    @Armali thank you so much – Himanshu Kaushik Jan 14 '21 at 21:13

1 Answers1

0

When I try your program, it correctly executes equivalently to

c <a.txt | b >b.txt

So, let's consider what may be different in your setup. Although you write

    /* It is important to check all system calls (open, creat, dup, etc.) for a return value < 0, 
    particularly -1, because such a return value means an error has occurred. */

you don't check the return value of the execl calls (or just put perror("…"); after them to see if they fail). Perhaps b or c is a script without a first line like

#!/bin/sh

You can get away without such a line when calling the script from a shell (I guess you mean that when you yell THOSE PROGRAMS ARE WORKING WELL ALONE), but not when using execl.

Armali
  • 18,255
  • 14
  • 57
  • 171
  • i am a new learner and i don't know all the commands. Till now I have been using ./myprogramme a.txt b.txt . What is this command file arg2 – Himanshu Kaushik Jan 13 '21 at 09:36
  • here a.txt is file to read and b.txt to store the output. Also I didn't get you for the #!/bin/sh . Should I add this line to my executable b and c to make it run. – Himanshu Kaushik Jan 13 '21 at 09:38
  • please help me in debugging it, I am using it on putty on an sssh server. – Himanshu Kaushik Jan 13 '21 at 09:43
  • Sorry for the confusion, I gave the wrong equivalent shell command for your program; I'll correct that right now, and that simpler command you'll surely understand - if not, ask again. – Armali Jan 13 '21 at 11:39
  • The `#!/bin/sh` applies only if your `b` or `c` is a shell script, not for a directly executable file. – Armali Jan 13 '21 at 11:44
  • 1
    A first step for debugging would be to add the missing checks to the `execl` calls. – Armali Jan 13 '21 at 11:47
  • I checked after execl command by fprintf(stderr,......) and it is nor working so I guess the problem is in execl command but it seems perfect. What should I do now. I still don't get it is the command cb.txt used to run the program. – Himanshu Kaushik Jan 14 '21 at 05:12
  • is there any other way to execute the program? please tell me how did you make it run – Himanshu Kaushik Jan 14 '21 at 05:19
  • 1
    @HimanshuKaushik What do you mean "it is not working"? If execl returns, then it failed. Is the printf after execl executing? If not, execl may have succeeded. If so, then it definitely failed. Did you include the system error in your printf? – William Pursell Jan 14 '21 at 15:30
  • @Himanshu Kaushik - `cb.txt` is just a shell command which does the same as your `./myprogramme a.txt b.txt` does. You could try this shell command to see if this works. If not, the error isn't in `myprogramme`, but in `b` or `c`, even if you think that `b` and `c` are working well. – Armali Jan 14 '21 at 15:41
  • @Himanshu Kaushik - Another way to run and debug the program is using `strace`. You could e. g. run `strace -feread,write myprogramme a.txt b.txt` (with a small amount of input data in `a.txt`) and post the output in your question. (You may want to add other system calls than `read` and `write`.) – Armali Jan 14 '21 at 15:47
  • @WilliamPursell Armali fprintf after execl is not working. you know the strange part I sent my all 3 codes of programs my program b and c programs and it working completely fine on their computers. exact same code. – Himanshu Kaushik Jan 14 '21 at 17:03
  • @Armali i want to chat with you personally. i am a student of engineering and need help. Please guide me. – Himanshu Kaushik Jan 14 '21 at 17:14
  • I normally don't chat, but I could make an exception. Try to say something there: https://chat.stackoverflow.com/rooms/23262/trash-can – Armali Jan 14 '21 at 17:26
  • @Armali thank you so much but my reputation Is less than 20 so I can not chat there. Yes, I tried your strace and it gave me many things which I wanted to discuss with you. I tried and found that my only one programme is executing at a time somehow I managed to get the output in another text file but then my b programme stopped working – Himanshu Kaushik Jan 14 '21 at 19:20
  • You can redirect the `strace` output to a file by appending `>&file` to the command and then add the content of `file` to your question post for review. – Armali Jan 14 '21 at 19:23
  • It may also be worthwhile the post the `b` and even `c` program, since they, although working under certain circumstances, may contain an error. – Armali Jan 14 '21 at 19:26
  • 1
    @Armali i added the strace output and i don't know if b or c contain any error because if they do then they shouldn't run at all.i think there is something up with the descriptor . – Himanshu Kaushik Jan 14 '21 at 19:37