Solved

exec(2) commands returning  to calling program

Posted on 1998-10-07
13
290 Views
Last Modified: 2013-12-27
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;
}
0
Comment
Question by:xx4525
  • 5
  • 4
  • 3
  • +1
13 Comments
 

Author Comment

by:xx4525
ID: 2007288
Edited text of question
0
 

Author Comment

by:xx4525
ID: 2007289
Edited text of question
0
 
LVL 3

Accepted Solution

by:
arunm earned 100 total points
ID: 2007290
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
 
LVL 3

Expert Comment

by:arunm
ID: 2007291
Also you dont appear to be distinguishing between the 2 threads in your program. Is this intentional?
0
 
LVL 84

Expert Comment

by:ozo
ID: 2007292
You may want to fork then exec
0
 
LVL 3

Expert Comment

by:elfie
ID: 2007293
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
IT, Stop Being Called Into Every Meeting

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

 

Author Comment

by:xx4525
ID: 2007294
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
 
LVL 3

Expert Comment

by:arunm
ID: 2007295
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
 
LVL 3

Expert Comment

by:elfie
ID: 2007296
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
 

Author Comment

by:xx4525
ID: 2007297
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
 
LVL 3

Expert Comment

by:arunm
ID: 2007298
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
 
LVL 3

Expert Comment

by:elfie
ID: 2007299
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
 

Author Comment

by:xx4525
ID: 2007300
Cool Thanks all

0

Featured Post

Enabling OSINT in Activity Based Intelligence

Activity based intelligence (ABI) requires access to all available sources of data. Recorded Future allows analysts to observe structured data on the open, deep, and dark web.

Join & Write a Comment

Preface This article introduces an authentication and authorization system for a website.  It is understood by the author and the project contributors that there is no such thing as a "one size fits all" system.  That being said, there is a certa…
What is Node.js? Node.js is a server side scripting language much like PHP or ASP but is used to implement the complete package of HTTP webserver and application framework. The difference is that Node.js’s execution engine is asynchronous and event…
Viewers will learn about basic arrays, how to declare them, and how to use them. Introduction and definition: Declare an array and cover the syntax of declaring them: Initialize every index in the created array: Example/Features of a basic arr…
The viewer will learn the benefit of using external CSS files and the relationship between class and ID selectors. Create your external css file by saving it as style.css then set up your style tags: (CODE) Reference the nav tag and set your prop…

759 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

22 Experts available now in Live!

Get 1:1 Help Now