0

I'm trying to solve a problem because I'm learning to use system calls in C. I used a Ubuntu 12.04 64bit.

I have this statement:

Implement a code that allows to redirect the standard out of the two commands deferred into a file (standard output) and all error output into another file (error file). The names of the files will be specificated using out parameter (for the name of standard out) and parameter -err (for the name of error file). Syntax: after2 [args...] --do [args...] --out --err

It's not specified in the statement but I think that I need to use pipes.

Also I can't use printf, scanf, getc... family functions.

And i have that code:

#include <syscall.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>


int main(void) 
{
    int cmd1 = system("sleep 5");
    int cmd2 = write(1, "hello world", 11);


    if((cmd1 != (0)))
    {
        write(1,"error in command 1",18);
    }
    if((cmd1==(0)))
    {
        write(1, "hello world", 11);
    }
    return EXIT_SUCCESS;
} 

My question is, do you know some examples about similar questions? I look for some but I didn't find, also if you know other ways to help me I'm happy to accept.

I post the code that I've now without erase the last version, by this way all people can see the evolution.

#include <syscall.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>


int main(int argc, char* argv[])
{
    const char* cmd1 = system("sleep 5");
    const char* cmd2 = write(1, "hello world", 11);
    int out_fd = creat("out.txt",0644);
    int err_fd = creat("err.txt",0644);


    if(out_fd < 0){
        write(2, "Can't open file out.txt", strlen("Can't open file out.txt"));
        dup2(err_fd, 2);
        write(2, "Can't open file out.txt \n", strlen("Can't open file out.txt \n"));

        return -1;
        }else if(err_fd < 0){
            write(2, "Can't open file err.txt", strlen("Can't open file err.txt"));
            dup2(err_fd, 2);
            write(2, "Can't open file err.txt \n", strlen("Can't open file err.txt \n"));

            return -1;
        }
    if((cmd1 !=(0)))
    {
        write(2, "There is an error on command1", strlen("There is an error on command1"));
        dup2(err_fd, 2);
        write(2, "Error on command1 \n", strlen("Error on command1 \n"));

        return -1;
        }else if((cmd1==(0)))
        {
            write(1, "success on command1", strlen("success on command1"));
            dup2(out_fd, 1);
            write(1, "success on command1 \n", strlen("success on command1 \n"));
            write(1, "hello world", 11);

            if((cmd2==(0)))
            {
                write(1, "hello world", strlen("hello world"));
                dup2(out_fd, 1);
                write(1, "hello world \n", strlen("hello world \n"));

            }
            if((cmd2 != (0)))
            {
                write(2, "There is an error on command2", strlen("There is an error on command2"));
                dup2(err_fd, 2);
                write(2, "Error on command2 \n", strlen("Error on command2 \n"));

            }
        }
return 0;
}

This time prints in the shell hello worldsuccess on command1There is an error on command2 and success on command1 and hello world in out.txt and There is an error on command2 in err.txt but I don't know why prints There is an error on command2 and in the same time prints hello world, any idea

Obviously I've some errors yet but I'm not sure what I need to do if anyone can help me I'll be happy!

Thanks.

alwayslearn
  • 103
  • 1
  • 9
  • 1
    No. You do not need pipes. Use dup2 instead. – Ghazanfar May 20 '15 at 17:42
  • Take a close look at the first parameter to write. You want standard out and standard error? http://codewiki.wikidot.com/c:system-calls:write : "The file descriptor of where to write the output. You can either use a file descriptor obtained from the open system call, or you can use 0, 1, or 2, to refer to standard input, standard output, or standard error, respectively" – polarysekt May 20 '15 at 17:45
  • yes but there is a little pre statement that says using pipes in Linux before the real statement, I mean, probably this problem could be solved wothout using pipes but I think that it's mandatory. – alwayslearn May 20 '15 at 17:48
  • So they want you to open files specified on the command line with arguments as opposed to doing the redirects on the command line... – polarysekt May 20 '15 at 17:51
  • I've deleted my answer since you claim you're not allowed to use the `printf` family of functions; you might want to update your question with that information. – user4520 May 20 '15 at 17:51
  • @polarysekt maybe I'm wrong but using write command I'm not use out and -err as statement says. – alwayslearn May 20 '15 at 17:52
  • you could use re-open stdout and stderr to the desired files. However, the declaration of main needs to be int main( int argc, char *argv{} ) so you can input the command line parameter that contain the output file names. – user3629249 May 20 '15 at 17:52
  • Well you can use `open( char *filename, int access, int permission )` to obtain a file descriptor for `write( int handle, void *buffer, int nbyte )`. See: `close( int handle )`. – polarysekt May 20 '15 at 17:54
  • 1
    Your code is irreverent to your question ! (Again !) – Ghazanfar May 20 '15 at 18:04
  • the most straight forward way to modify the stdout and stderr is to use freopen(). from the man page: "The freopen() function opens the file whose name is the string pointed to by path and associates the stream pointed to by stream with it. The original stream (if it exists) is closed. The mode argument is used just as in the fopen() function. The primary use of the freopen() function is to change the file associated with a standard text stream (stderr, stdin, or stdout). " – user3629249 May 20 '15 at 18:09

3 Answers3

2

You can use dup2 to redirect STDIN and STDERR to any other file you have opened.

int out_fd = creat("out.txt",0644);
if(out_fd < 0){
    printf("Could not open file for standard output\n");
}
write(STDOUT_FILENO, "This is printed on the standard output", strlen("This is printed on the standard output"));
dup2(out_fd, STDOUT_FILENO);
write(STDOUT_FILENO, "This goes into out.txt file \n", strlen("This goes into out.txt file \n"));

You can do it similarly for stderr.

Ghazanfar
  • 1,419
  • 13
  • 21
  • Edited to remove printf(). Since you told that later. – Ghazanfar May 20 '15 at 18:01
  • @alwayslearn Welcome ! I see you are taking a course in Unix system programming :D All the best ! – Ghazanfar May 20 '15 at 18:03
  • xD thanks! but it's difficut for me, I'm working and studying 7 days per week and I'm turning mad :P – alwayslearn May 20 '15 at 18:12
  • @alwayslearn "Advanced Programming in the UNIX Environment" by W. Richard Stevens and Stephen Rago is a very good book for this. – Ghazanfar May 20 '15 at 18:53
  • thanks for the book, I'll try to read when I've some free time! – alwayslearn May 21 '15 at 08:22
  • not exactly, I posted the code that I've, I've been trying all morning to correct that but doesn't works, It creates the both output files (out and err) but no writes into there. I'm studuing online a degree and sometimes it's really difficult to do without porffesors or mates to help you face by face. – alwayslearn May 21 '15 at 09:21
2

write(1, ... writes to standard output. write(2,... writes to standard error. So all you have to do is reopen those file descriptors so that they're going into the designated files. For example,

fd1 = open("outputfile", O_WRONLY); dup2(fd1, 1);
fd2 = open("errorfile", O_WRONLY); dup2(fd2, 2);

After that, any standard output will go into outputfile and any error output will go to errorfile.

But first, you have to parse the command-line options (found in argv, which is the first argument to main, whose length is given by the second argument to main) to find the --out and --err options and get their values.

Mark Reed
  • 91,912
  • 16
  • 138
  • 175
  • When you say that I need to parse the command-line options, is something like the examples that appear here (http://stackoverflow.com/questions/9642732/parsing-command-line-arguments) – alwayslearn May 20 '15 at 18:15
0

Well, finally I've got a code that seems that it works, I changed the command cmd2 = write(1, "hello world", 11); for cmd2 = system("echo $HOME"); because I've troubles to write in a file a write function, changing this I achieve my objective fastly:

#include <syscall.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char* argv[])
{
    const int cmd1 = system("sleep 5");
    int out_fd = creat("out.txt",0644);
    int err_fd = creat("err.txt",0644);


    if(out_fd < 0){
        //write(2, "Can't open file out.txt", strlen("Can't open file out.txt"));
        dup2(err_fd, 2);
        write(2, "Can't open file out.txt \n", strlen("Can't open file out.txt \n"));

        return -1;
        }else if(err_fd < 0){
            //write(2, "Can't open file err.txt", strlen("Can't open file err.txt"));
            dup2(err_fd, 2);
            write(2, "Can't open file err.txt \n", strlen("Can't open file err.txt \n"));

            return -1;
        }
    if((cmd1 !=(0)))
    {
        //write(2, "There is an error on command1", strlen("There is an error on command1"));
        dup2(err_fd, 2);
        write(2, "Error on command1 \n", strlen("Error on command1 \n"));

        return -1;
        }
    if((cmd1==(0)))
    {

        //write(1, "success on command1", strlen("success on command1"));
        dup2(out_fd, 1);
        write(1, "success on command1 \n", strlen("success on command1 \n"));
        const int cmd2 = system("echo $HOME");;

        if(( cmd2==(0)))
        {

            //write(1, "success on command2", strlen("success on command2"));
            dup2(out_fd, 1);
            write(1, "success on command2 \n", strlen("success on command2 \n"));

        }
        else if(( cmd2 !=(0)))
        {

            //write(2, "There is an error on command2", strlen("There is an error on command2"));
            dup2(err_fd, 2);
            write(2, "Error on command2 \n", strlen("Error on command2 \n"));

        }
    }
return 0;
}

Only have a little problem, when I build an exe appears a warning who says: warning:implicit declaration of function 'creat'[-Wimplicit-function-declaration]

int out_fd = creat("out.txt",0644);

If anyone knows how to correct it please tell me. Thanks for all your help!

alwayslearn
  • 103
  • 1
  • 9
  • You shouldn't ask a question in the answers section. `Only have a little problem, when I build an exe appears a warning who says: warning:implicit declaration of function 'creat'[-Wimplicit-function-declaration] int out_fd = creat("out.txt",0644); If anyone knows how to correct it please tell me. Thanks for all your help!` – Ghazanfar May 21 '15 at 12:28
  • Include `fcntl.h` to get rid of `warning:implicit declaration of function 'creat'[-Wimplicit-function-declaration]` – Ghazanfar May 21 '15 at 12:29