exec(2) commands returning to calling program

Alright we have multi threaded program that used to
use System calls but appearently the system command
is not thread safe (anymore).  Sun tech support offer
the advice that we should use exec commands instead which
is fine but I cannot get the perl script (or any other script) to return to the calling code.  (see below)
so I can see the debug statment before execvp but not the
printf statement afterwards.  If I can't make the call
this way how can I make the call?

#include "ToolLib.h"
#include <stdlib.h>
#include <libgen.h>
#include <ctype.h>
#include <errno.h>
#include <time.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <dirent.h>
#define ONE_DAY 1 * 24 * 60 * 60              /* day * hours/day * min/hour * sec/min = 86400 */
#define SECTION_TITLE_MARKER    '['
#define COMMENT_MARKER          ';'
#define EMPTY_LINE              '\0'

mutex_t gSystemCallMutex;

int main(int argc, char** argv)
{
    char          gLogDir[DIR_SZ];
    bool          gbDebug;
    char          cmd[CMD_SZ];
    gbDebug = TRUE;
    sprintf(gLogDir, "/home/xx4525/c++/dev/SafeBuild/tgt/unix/log/build/%s");
    sprintf(cmd, "mkdir -p %s ; chmod 777 %s", gLogDir, gLogDir);
    return MakeSystemCall(gbDebug, cmd);
}

extern bool MakeSystemCall(bool bDebug, char* pFullCmd)
{
    int     rc;
    pid_t   pid;
    int     i;
    int     arg_list_length;
    char    *FullPath;
    char    System_Call_Path[256];
    char    *Ptr;

    char    msg[256];
    char    *arg_list[16];
 
    char    Path_To_System_Call[] = "/home/xx4525/perl/dev/";
    char    System_Call_Script[]  = "Plague";


    pid = fork1();

    if (bDebug == TRUE) { printf("\n\tCOMMAND: %s\n\n",pFullCmd ); }
    if(mutex_lock(&gSystemCallMutex) != 0)
    {
        perror("MakeSystemCall");
        return (FALSE);
    }

    strcpy(System_Call_Path,Path_To_System_Call);
    strcat(System_Call_Path,System_Call_Script);

    if (bDebug == TRUE) { printf("\n\tSYSTEM SCRIPT: %s\n\n",System_Call_Path ); }

    if ( pid <= -1)
    {
        perror(pFullCmd);
    }
    else
    {
        arg_list[1] = strtok(pFullCmd, " ");
        for(i = 2; (arg_list[i] = strtok(NULL, " ")) != NULL; i++);
        arg_list[i] = NULL;

        if (bDebug == TRUE)
        {
            for(i = 1; arg_list[i] != NULL; i++) { fprintf(stdout, "*** CURRENT COMMAND %d: [%s] ***\n",i, arg_list[i]); }
            fflush(stdout);
        }
        rc = execvp(System_Call_Path, arg_list);

        sprintf(msg, "\n\n Don't Thread on me - Cmd: %s\n\n", pFullCmd);
        fprintf( stdout, "%s",msg );
        _exit(1);
    }

    if(mutex_unlock(&gSystemCallMutex) != 0)
    {
        perror("MakeSystemCall");
        return(FALSE);
    }
 
    return (rc == 0) ? TRUE : FALSE;
}
xx4525Asked:
Who is Participating?

Improve company productivity with a Business Account.Sign Up

x
 
arunmConnect With a Mentor Commented:
If a program sucessfully execs, the address space is modifed so there is nothing to return to. The printf will only be reached if the exec fails.
 
0
 
xx4525Author Commented:
Edited text of question
0
 
xx4525Author Commented:
Edited text of question
0
Free Tool: Subnet Calculator

The subnet calculator helps you design networks by taking an IP address and network mask and returning information such as network, broadcast address, and host range.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

 
arunmCommented:
Also you dont appear to be distinguishing between the 2 threads in your program. Is this intentional?
0
 
ozoCommented:
You may want to fork then exec
0
 
elfieCommented:
Some more clarification about ozo's comment.

a fork call will duplicate your process into two (almost) identical processes. Then in one of both (normally) the program which get a zero return form the fork call, you will executed the  exec call to replace to current running code with your ocde of choice.
The other process will receive a non-zero return from fork (meaning the son's process id).

As what the system command is , the normal implmentation is first a fork call followed by some form of exec call.
0
 
xx4525Author Commented:
Thank you all for your help but I am afraid that I am
going to need some clarification.

Alright I can understand why the printf is not executing but
I should be executing the execvp inside the forked process,
right?  Thus the parent process should complete the execution
after the child is toast or I am executing the execvp on both
the child and the parent?

What do you mean by "distinguishing between the 2 threads"?
0
 
arunmCommented:
After the fork, if the pid = 0, its the child. If the pid > 0 its the parent , a -ve pid indicates a failure. So both your processes are exec-ing.
 
0
 
elfieCommented:
some sample code for using fork/exec to execute a shell script

  argv[0] = argv0;
  argv[1] = script_file;
  argv[2] = NULL;

#ifdef PROTO_OS2
  script_pid = _spawnvp(P_NOWAIT, "cmd.exe", argv);
  if (script_pid == -1)
    Error("Execvp failed: %s\n",strerror(own_errno()));
#else
  fork_code = fork();
  switch (fork_code)
    {
    case -1:
      Error("Fork failed: %s\n", strerror(own_errno()));
      exit(EXITCODE_LAUNCH_ERROR);

    case 0:             /* the son process */
      close_anything_thats_open();
      setsid();
      Error("Starting background script %s",script_file);
      exec_code = execvp("sh", argv);
      if (exec_code == -1)
      Error("Execvp failed: %s\n", strerror(own_errno()));
      exit(0);/*no EXITCODE necessary here - different process*/
    default:   /* the father must wait until the son is there */
      script_pid = fork_code;      /* to kill afterwards */
    }
#endif /* PROTO_OS2 */
#endif /* MSC32 */
0
 
xx4525Author Commented:
Happiness is truely mine I have some more questions but
I think I have a start.  But the questions are for
my knowledge

What do setsid() do for me?  Is is necessary?

I am assuming that close_anything_thats_open() is a user defined
function but what am I looking to close?

Finally I hope
default:   /* the father must wait until the son is there */
             script_pid = fork_code; /* to kill afterwards */
           }
What is the perpose of this commparison and will this work as
well?
            default:
                    waitpid(pid, &rc, 0);
                    break;
    }

0
 
arunmCommented:
Whenever you fork a process, as the child is and exact copy of the parent they will both share items such as file pointers. To avoid a confusion and to aid clairity it is best to close anything that is left open.  Wait is essentially used to syncronise processes, so you can confirm that the child process has finished before continuing with the parent. setsid() is used to process and session group id. In this case it is not mandatory.
 
 
0
 
elfieCommented:
setsid() combined with closing stdin/out/err is use dto detach from curent running terminal. it is only needed to make a real deamon process that, after completely started, will show pid 1 as it's parent process. It also prevents that the process will be killed automatically when a user who started it will logoff. (in your case not needed, but i did a cut/paste from some existing code.

The same for close_anything ... Since your starting another program you (probably) don't need any open file from the orignating program. Since Fork duplicates the process, it also duplicates all open filedescriptors, and keeping them open (even when not needed).

The saving of the son's id , is that the parent process will write this id into a file, so later we can do a kill `cat file` to kill the deamon process.

Basically the example is bit to extended, but it shows you the basics of how fork/exec can be used.
0
 
xx4525Author Commented:
Cool Thanks all

0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.