Anirban
Anirban

Reputation: 580

C: How can I exec() my program with the same command line arguments as my running program

I am trying to reset my program when it receives a SIGSEGV by using ececl() in my signal handler. But, my current program needs commandline arguments to start that I can pass via execl() + 1 extra argument "RESTART" to notify the program that it just restarted instead of a fresh start.

But how can I pass my argv[] via exec()?

Objective: execl("./myprog","./myprog",argv[1],argv[2],...,argv[argc],"RESTART"); OR execl("./myprog","./myprog","RESTART",argv[1],argv[2],...,argv[argc]);

Upvotes: 5

Views: 2896

Answers (2)

Petr Skocik
Petr Skocik

Reputation: 60056

You need to save argv in a global, either from main:

static char **Argv;
int main(int c, char **v) { Argv = v; //...

or from a gcc constructor:

static char **Argv;
__attribute__((constructor))
static void ctor(int c, char **v) { Argv = v; }

Then you can do what you want:

#include <stdio.h>
#include <unistd.h>
#include <signal.h>

static char **Argv;

static void hndlr(int s)
{
    execv("/proc/self/exe", Argv);
    _exit(127);
}
int main(int argc, char **argv)
{
    Argv = argv;

    struct sigaction sa = { .sa_handler = hndlr, .sa_flags = SA_NODEFER };
    sigaction(SIGSEGV, &sa, 0);

    sleep(1);
    fputs("start\n", stderr);

    //keep re-executing the same program
    raise(SIGSEGV);
}

Note that without the SA_NODEFER, you'll only see the message twice, because SIGSEGV will be blocked during the second run of the executable.

While this should be defined (especially if you add a signal stack so that you can handle stack overflows with this too), wrappers scripts/programs are a safer and more robust way of doing this. With the SISEGV handler approach, you aren't really starting from scratch -- you are inheriting signal masks, effective uids/gids, workings directories, open file descriptors, etc. etc., whereas with a wrapper script you start from a well defined state.

Upvotes: 4

Andrew Henle
Andrew Henle

Reputation: 1

Use execv():

SYNOPSIS

   #include <unistd.h>

...

   int execv(const char *path, char *const argv[]);

...

The execv(), execvp(), and execvpe() functions provide an array of pointers to null-terminated strings that represent the argument list available to the new program. The first argument, by convention, should point to the filename associated with the file being executed. The array of pointers must be terminated by a null pointer.

Perhaps like this:

int main( int argc, char **argv )
{
    ...
    int rc = execv( "./myprog", argv );
}

You may need to modify specific values in argv or create an entirely new argument array to fit what you need.

Upvotes: 4

Related Questions