QlgSpawn()--Spawn Process (using NLS-enabled path name)


  Syntax
 #include <spawn.h>
 #include <qlg.h>

 pid_t QlgSpawn(const Qlg_Path_Name_T     *path,  
                const int                 fd_count,
                const int                 fd_map[],
                const struct inheritance  *inherit,  
                char * const              argv[],
                char * const              envp[]);


  Service Program Name: QP0ZSPWN

  Default Public Authority: *USE

  Threadsafe: Conditional; see Usage Notes.

The QlgSpawn() function, like the spawn() function, creates a child process that inherits specific attributes from the parent. The difference is that for the path parameter, the QlgSpawn() function takes a pointer to a Qlg_Path_Name_T structure, while the spawn() function takes a pointer to a character string in the CCSID of the job.

Limited information about the path parameter is provided here. For more information about the path parameter and for a discussion of other parameters, authorities required, and return values, see spawn()--Spawn Process.


Parameters

path
(Input) A pointer to a Qlg_Path_Name_T structure that contains a specific path name or a pointer to a specific path name of an executable file that will run in the new (child) process. For more information about the Qlg_Path_Name_T structure, see Path name format.

Usage Notes

See spawn()--Spawn Process for a complete discussion of usage information for QlgSpawn(). In addition, the following should be noted specifically for QlgSpawn().

  1. Shell scripts are supported; however, the interpreter path in the shell script itself cannot be a Qlg_Path_Name_T structure.

Related Information


Example

Note: By using the code examples, you agree to the terms of the Code license and disclaimer information.

Parent Program

The following ILE C for IBM® i program can be created in any library. This parent program assumes the corresponding child program will be created with the name CHILD in the library QGPL. Call this parent program with no parameters to run the example.

/*****************************************************************/
/*****************************************************************/
/*                                                               */
/* FUNCTION:  This program acts as a parent to a child program.  */
/*                                                               */
/* LANGUAGE:  ILE C for i5/OS                                   */
/*                                                               */
/* APIs USED: QlgSpawn(), waitpid(),                             */
/*            QlgCreat(), QlgUnlink(), QlgOpen()                 */
/*                                                               */
/*****************************************************************/
/*****************************************************************/
#include <errno.h>
#include <fcntl.h>
#include <spawn.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <qlg.h>
#include <Qp0lstdi.h>

#define ARGV_NUM   6
#define ENVP_NUM   1
#define CHILD_PGM  "QGPL/CHILD"
#define spwpath "/QSYS.LIB/QGPL.LIB/CHILD.PGM"
#define fpath "A_File"

typedef struct pnstruct
{
 Qlg_Path_Name_T qlg_struct;
 char pn[100];  /* This size must be >= the path */
                /* name length or this must be a */
                /* pointer to the path name.     */
};

/* This is a parent program that will use QlgSpawn() to start a     */
/* child.  A file is created that is written to, both by the parent */
/* and the child.  The end result of the file will look something   */
/* like the following:                                              */
/*     Parent writes    Child writes                                */
/*     -------------    ---------------------------------------     */
/*           1          argv[0]  getppid()  getpgrp()  getpid()     */
/* The parent uses waitpid() to wait for the child to return and to */
/* retrieve the resulting status of the child when it does return.  */

int main(int argc, char *argv[])
{
    int    rc;                     /* API return code */
    int    fd, fd_read;            /* parent file descriptors */
    char   fd_str[4];              /* file descriptor string */
    const char US_const[3]= "US";
    const char Language_const[4]="ENU";
    const char Path_Name_Del_const[2]= "/";
    struct pnstruct f_path_name;   /* file pathname */
    int    buf_int;                /* write(), read() buffer */
    char   buf_pgm_name[22];       /* read() program name buffer */
    struct pnstruct spw_path;      /* QlgSpawn() *path */
    int    spw_fd_count = 0;       /* QlgSpawn() fd_count */
    struct inheritance spw_inherit; /* QlgSpawn() *inherit */
    char  *spw_argv[ARGV_NUM];     /* QlgSpawn() *argv[] */
    char  *spw_envp[ENVP_NUM];     /* QlgSpawn() *envp[] */
    int    seq_num;                /* sequence number */
    char   seq_num_str[4];         /* sequence number string */
    pid_t  pid;                    /* parent pid */
    char   pid_str[11];            /* parent pid string */
    pid_t  pgrp;                   /* parent process group */
    char   pgrp_str[11];           /* parent process group string */
    pid_t  spw_child_pid;          /* QlgSpawn() child pid */
    pid_t  wt_child_pid;           /* waitpid() child pid */
    int    wt_stat_loc;            /* waitpid() *stat_loc */
    int    wt_pid_opt = 0;         /* waitpid() option */

    /* Get the pid and pgrp for the parent. */
    pid = getpid();
    pgrp = getpgrp();
    /* Format the pid and pgrp value into null-terminated strings. */
    sprintf(pid_str, "%d", pid);
    sprintf(pgrp_str, "%d", pgrp);

    /* Initialize Qlg_Path_Name_T parameters */
    memset(&f_path_name,0x00,sizeof(struct pnstruct));
    f_path_name.qlg_struct.CCSID = 37;
    memcpy(f_path_name.qlg_struct.Country_ID,US_const,2);
    memcpy(f_path_name.qlg_struct.Language_ID,Language_const,3);
    f_path_name.qlg_struct.Path_Type = QLG_CHAR_SINGLE;
    f_path_name.qlg_struct.Path_Length = sizeof(fpath)-1;
    memcpy(f_path_name.qlg_struct.Path_Name_Delimiter,
           Path_Name_Del_const,1);
    memcpy(f_path_name.pn,fpath,sizeof(fpath)-1);

    /* Create a file and maintain the file descriptor. */
    fd = QlgCreat((Qlg_Path_Name_T *)&f_path_name, S_IRWXU);
    if (fd == -1)
      {
        printf("FAILURE: QlgCreat() with errno = %d\n",errno);
        return -1;
      }
    /* Format the file descriptor into null-terminated string. */
    sprintf(fd_str, "%d", fd);

    /* Initialize Qlg_Path_Name_T parameters */
    memset(&spw_path,0x00,sizeof(struct pnstruct));
    spw_path.qlg_struct.CCSID = 37;
    memcpy(spw_path.qlg_struct.Country_ID,US_const,2);
    memcpy(spw_path.qlg_struct.Language_ID,Language_const,3);
    spw_path.qlg_struct.Path_Type = QLG_CHAR_SINGLE;
    spw_path.qlg_struct.Path_Length = sizeof(spwpath)-1;
    memcpy(spw_path.qlg_struct.Path_Name_Delimiter,
           Path_Name_Del_const,1);
    memcpy(spw_path.pn,spwpath,sizeof(spwpath)-1);

    /* Write a '1' out to the file. */
    seq_num = 1;
    sprintf(seq_num_str, "%d", seq_num);
    buf_int = seq_num;
    write(fd, &buf_int, sizeof(int));

    /* Set the QlgSpawn() child arguments for the child.     */
    /* NOTE: The child will always get argv[0] in the        */
    /* LIBRARY/PROGRAM notation, but the QlgSpawn() argv[0]  */
    /* (spw_argv[0] in this case) must be non-NULL in order  */
    /* to allow additional arguments.  For this example, the */
    /* CHILD_PGM was chosen.                                 */
    /* NOTE: The parent pid and the parent process group are */
    /* passed to the child for demonstration purposes only.  */
    spw_argv[0] = CHILD_PGM;
    spw_argv[1] = pid_str;
    spw_argv[2] = pgrp_str;
    spw_argv[3] = seq_num_str;
    spw_argv[4] = fd_str;
    spw_argv[5] = NULL;

    /* This QlgSpawn() will use simple inheritance for file  */
    /* descriptors (fd_map[] value is NULL).                 */
    memset(&spw_inherit,0x00,sizeof(spw_inherit));
    spw_envp[0] = NULL;
    spw_child_pid = QlgSpawn((Qlg_Path_Name_T *)&spw_path,
                    spw_fd_count, NULL, &spw_inherit, spw_argv, spw_envp);
    if (spw_child_pid == -1)
      {
        printf("FAILURE: QlgSpawn() with errno = %d\n",errno);
        close(fd);
        QlgUnlink((Qlg_Path_Name_T *)&f_path_name);
        return -1;
      }

    /* The parent no longer needs to use the file descriptor, so */
    /* it can close it, now that it has issued QlgSpawn().       */
    rc = close(fd);
    if (rc != 0)
        printf("FAILURE: close(fd) with errno = %d\n",errno);

    /* NOTE: The parent can continue processing while the child is */
    /* also processing.  In this example, though, the parent will  */
    /* simply wait until the child finishes processing.            */
    /* Issue waitpid() in order to wait for the child to return.   */
    wt_child_pid = waitpid(spw_child_pid,&wt_stat_loc,wt_pid_opt);
    if (wt_child_pid == -1)
      {
        printf("FAILURE: waitpid() with errno = %d\n",errno);
        close(fd);
        QlgUnlink((Qlg_Path_Name_T *)&f_path_name);
        return -1;
      }

    /* Check to ensure the child did not encounter an error  */
    /* condition.                                            */
    if (WIFEXITED(wt_stat_loc))
      {
        if (WEXITSTATUS(wt_stat_loc) != 1)
            printf("FAILURE: waitpid() exit status = %d\n",
                   WEXITSTATUS(wt_stat_loc));
      }
    else
        printf("FAILURE: unknown child status\n");

    /* Open the file for read to verify what the child wrote. */
    fd_read = QlgOpen((Qlg_Path_Name_T *)&f_path_name, O_RDONLY);
    if (fd_read == -1)
      {
        printf("FAILURE: open() for read with errno = %d\n",errno);
        QlgUnlink((Qlg_Path_Name_T *)&f_path_name);
        return -1;
      }

    /* Verify what child wrote. */
    rc = read(fd_read, &buf_int, sizeof(int));
    if ( (rc != sizeof(int)) || (buf_int != 1) )
        printf("FAILURE: read()\n");
    memset(buf_pgm_name,0x00,sizeof(buf_pgm_name));
    rc = read(fd_read, buf_pgm_name, strlen(CHILD_PGM));
    if ( (rc != strlen(CHILD_PGM)) ||
         (strcmp(buf_pgm_name,CHILD_PGM) != 0) )
        printf("FAILURE: read() child argv[0]\n");
    rc = read(fd_read, &buf_int, sizeof(int));
    if ( (rc != sizeof(int)) || (buf_int != pid) )
        printf("FAILURE: read() child getppid()\n");
    rc = read(fd_read, &buf_int, sizeof(int));
    if ( (rc != sizeof(int)) || (buf_int != pgrp) )
        printf("FAILURE: read() child getpgrp()\n");
    rc = read(fd_read, &buf_int, sizeof(int));
    if ( (rc != sizeof(int)) || (buf_int != spw_child_pid) ||
         (buf_int != wt_child_pid) )
        printf("FAILURE: read() child getpid()\n");

    /* Attempt one more read() to ensure there is no more data. */
    rc = read(fd_read, &buf_int, sizeof(int));
    if (rc != 0)
        printf("FAILURE: read() past end of data\n");

    /* The parent no longer needs to use the read() file descriptor, */
    /* so it can close it.                                           */
    rc = close(fd_read);
    if (rc != 0)
        printf("FAILURE: close(fd_read) with errno = %d\n",errno);

    /* Clean up by performing unlink(). */
    rc = QlgUnlink((Qlg_Path_Name_T *)&f_path_name);
    if (rc != 0)
      {
        printf("FAILURE: QlgUnlink() with errno = %d\n",errno);
        return -1;
      }
    printf("completed successfully\n");
    return 0;
}




Child Program

The following ILE C for IBM i program must be created with the name CHILD in the library QGPL in order to be found by the parent program. This program is not to be called directly, as it is run through the use of QlgSpawn() in the parent program.

/*******************************************************************/
/*******************************************************************/
/*                                                                 */
/* FUNCTION:  This program acts as a child to a parent program.    */
/*                                                                 */
/* LANGUAGE:  ILE C for i5/OS                                     */
/*                                                                 */
/* APIs USED: getpid(), getppid(), getpgrp()                       */
/*                                                                 */
/*******************************************************************/
/*******************************************************************/
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>

/* This is a child program that gets control from a parent program */
/* that issues QlgSpawn().  This particular child program expects  */
/* the following 5 arguments (all are null-terminated strings):    */
/*     argv[0] - child program name                                */
/*     argv[1] - parent pid (for demonstration only)               */
/*     argv[2] - parent process group (for demonstration only)     */
/*     argv[3] - sequence number                                   */
/*     argv[4] - parent file descriptor                            */
/* If the child program encounters an error, it returns with a     */
/* value greater than 50.  If the parent uses wait() or waitpid(), */
/* this return value can be interrogated using the WIFEXITED and   */
/* WEXITSTATUS macros on the resulting wait() or waitpid()         */
/* *stat_loc field.                                                */

int main(int argc, char *argv[])
{
    pid_t  p_pid;                /* parent pid argv[1] */
    pid_t  p_pgrp;               /* parent process group argv[2] */
    int    seq_num;              /* parent sequence num argv[3] */
    int    fd;                   /* parent file desc argv[4] */
    int    rc;                   /* API return code */
    pid_t  pid;                  /* getpid() - child pid */
    pid_t  ppid;                 /* getppid() - parent pid */
    pid_t  pgrp;                 /* getpgrp() - process group */

    /* Get the pid, ppid, and pgrp for the child. */
    pid = getpid();
    ppid = getppid();
    pgrp = getpgrp();

    /* Verify 5 parameters were passed to the child. */
    if (argc != 5)
        return 60;

    /* Since the parameters passed to the child using QlgSpawn() are */
    /* pointers to strings, convert the parent pid, parent process   */
    /* group, sequence number, and the file descriptor from strings  */
    /* to integers.                                                  */
    p_pid = atoi(argv[1]);
    p_pgrp = atoi(argv[2]);
    seq_num = atoi(argv[3]);
    fd = atoi(argv[4]);

    /* Verify the getpid() value of the parent is the same as the    */
    /* getppid() value of the child.                                 */
    if (p_pid != ppid)
        return 61;

    /* If the sequence number is 1, simple inheritance was used in   */
    /* this case.  First, verify the getpgrp() value of the parent   */
    /* is the same as the getpgrp() value of the child.  Next, the   */
    /* child will use the file descriptor passed in to write the     */
    /* child's values for argv[0], getppid(), getpgrp(),             */
    /* and getpid().  Finally, the child returns, which will satisfy */
    /* the parent's wait() or waitpid().                             */
    if (seq_num == 1)
      {
        if (p_pgrp != pgrp)
            return 70;
        rc = write(fd, argv[0], strlen(argv[0]));
        if (rc != strlen(argv[0]))
            return 71;
        rc = write(fd, &ppid, sizeof(pid_t));
        if (rc != sizeof(pid_t))
            return 72;
        rc = write(fd, &pgrp, sizeof(pid_t));
        if (rc != sizeof(pid_t))
            return 73;
        rc = write(fd, &pid, sizeof(pid_t));
        if (rc != sizeof(pid_t))
            return 74;
        return seq_num;
      }

    /* If the sequence number is an unexpected value, return */
    /* indicating an error.                                  */
    else
        return 99;
}



API introduced: V5R1

[ Back to top | Process-Related APIs | APIs by category ]