3

I have a curl command:

curl -c cookies.txt -b cookies.txt -k https://www.example.com/ajaxauth/login -d 'identity=email@example.com&password=pa$$w0rd&query=https://example.com/data/format/json' > ~/Documents/.../myProject/bin/data/myData.json"

that

  1. logs in to an API,
  2. manages cookies,
  3. fetches a dataset and saves to local file.

I have it in a char array and was sending to the system() command, but due to the dangers of passing vars (email and password) to system(), I must use exec() instead. I'm not familiar with this command and the documentation is confusing me. So my questions:

  • Is this even possible or do I have to go back and break up my command into individual calls or even multiple exec calls?

  • I assume I should be using an execv version because I'm passing in a whole character array, is this correct?

  • Many different sources say the first argument for an exec() command must be an executable file. For example, "The first argument, by convention, should point to the file name associated with the file being executed." How does a curl command count as such?

  • Why is this person passing (char *) 0 as the last argument?

This is what I have so far:

int pid = fork();

switch(pid){
    case -1:{            
        perror("fork"); // via https://stackoverflow.com/q/2329640/1757149
        _exit(EXIT_FAILURE);
        break;
    }
    case 0:{ // child process
        //execv(cmd, ???);
        break;
    }
    default:{ // parent process                
        break;
    }
}

Note that I can't use libcurl. Any help appreciated!

Community
  • 1
  • 1
A__
  • 1,616
  • 2
  • 19
  • 33
  • I haven't used any of the `c*` langs recently, but try `exec("/path/to/curl --help");` to see if that connects. I think it will. Then keep adding from there. Don't know about `execv`. Good luck. – shellter Oct 23 '15 at 03:53

1 Answers1

2

You can exec your command using execlp splitting arguments like this (adding NULL to indicate end of arguments) :

execlp("curl","curl","-c","cookies.txt","-b","cookies.txt","-k","https://www.example.com/ajaxauth/login","-d","identity=email@example.com&password=pa$$w0rd&query=https://example.com/data/format/json",NULL);

The first argument is the executable that will be search from the PATH, and the second one is referenced in the manpage as "The first argument, by convention, should point to the file name associated with the file being executed."

In order to redirect the output of exec to a file, you should replace the standard output with the output file :

int out = creat("myData.json", S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
dup2(out,STDOUT_FILENO); 

Putting all together :

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/wait.h>

int main()
{   
    int pid = fork();
    switch(pid){
        case -1:{            
            perror("fork"); 
            _exit(EXIT_FAILURE);
            break;
        }
        case 0:{ // child process
            // create output file
            int out = creat("myData.json", S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
            if (out == -1){
                perror("creat"); 
                _exit(EXIT_FAILURE);
            } else {
                // redirect stdout to output file
                dup2(out,STDOUT_FILENO); 
                // exec the command
                execlp("curl","curl","-c","cookies.txt","-b","cookies.txt","-k","https://www.example.com/ajaxauth/login","-d","identity=email@example.com&password=pa$$w0rd&query=https://example.com/data/format/json",NULL);
                // close output file
                close(out);
            }
            break;
        }
        default:{ // parent process                
            // wait for child process
            int status = 0;
            wait(&status);  
            printf("child status:%d\n",status);
            break;
        }
    }       
    return 0;
}
mpromonet
  • 11,326
  • 43
  • 62
  • 91
  • Awesome, thank you so much. If I remove `wait()` (can't let the parent hang) would the child process not have properly been destroyed? It seems to work fine but I want to make sure I'm not going to eventually cause my kernal to run out of threads or anything like that. – A__ Oct 27 '15 at 04:01
  • 1
    If you remove `wait` you just don't know if the exec succeed or failed, you should take care that the parent exits (otherwise child process will stay zombie). If the parent exits ressources should be released. – mpromonet Oct 27 '15 at 07:42