/* An implementation of popen() and pclose() Choose your browser's option to Save As... to download this code example. Send the program to your AS/400 using FTP or similar method and include it in your source code with the line below. This example was developed on V4R2. Compile this module using CRTCMOD and then bind the module with other modules using popen() and pclose() to create the program object. This code fragment that is furnished by IBM is a simple example to provide an illustration. This example has not been thoroughly tested under all conditions. IBM, therefore, cannot guarantee or imply reliability, serviceability, or function of this program. All code contained herein is provided to you "AS IS". THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY DISCLAIMED. */ /**********************************************************************/ /* This example shows how to implement basic popen() and pclose() functions. It has the following limitations: 1. The input command is the path to a program you want to run in the child process. You cannot pass arguments to the specified program. If you need to pass arguments to the program you could add an additional parameter to popen() or you could start a shell interpreter and let the shell handle the arguments in command. 2. The program you want to run should be compiled with SYSIFCOPT(*IFSIO). 3. As a non-standard extension, if the input mode is a value other than "r" or "w", the returned stream is opened for read and write. 4. You must call popen() and pclose() in pairs. That means you cannot call popen() again before calling pclose(). */ /**********************************************************************/ /**********************************************************************/ /* Includes */ /**********************************************************************/ #include #include #include #include #include #include #include #include /**********************************************************************/ /* Global Variables */ /**********************************************************************/ /* Process id of child process */ pid_t pid; /* External */ extern char **environ; /**********************************************************************/ /* popen() */ /**********************************************************************/ FILE *popen(const char *command, const char *mode) { int stdFds[2]; /* Pipe descriptors */ char *args[5]; /* Argument array for child */ char **envs; /* Environment variable array for child */ int envCount; /* Number of environment variables */ char **envp; /* For running environ array */ int index; /* Array index */ int fdMap[3]; /* File descriptor map for spawn() */ inheritance_t inherit; /* Inheritance structure for spawn() */ int rc; /* Return code */ FILE *stream; /* File pointer to standard I/O stream */ /* Environment variables */ char stdio_var[] = "QIBM_USE_DESCRIPTOR_STDIO=Y"; /* Create a pipe for getting output from the child process. */ if (pipe(stdFds) != 0) { fprintf(stderr, "popen(): pipe() failed with errno=%d\n", errno); return NULL; } /* Build the argument array for the child process. */ args[0] = (char *)command; args[1] = NULL; /* Make sure the environ data export is initialized in this activation group. */ Qp0zInitEnv(); /* Count the number of environment variables currently defined in this process. We rely on spawn() to make sure we don't end up with too many environment variables. */ for (envCount = 0, envp = environ; *envp != NULL; ++envp, ++envCount); /* Allocate storage for the environment variable array. */ envs = (char **)malloc(sizeof(char *) * (envCount + 1)); if (envs == NULL) { fprintf(stderr, "popen(): malloc() failed for env array\n"); /* Cleanup. */ close(stdFds[0]); close(stdFds[1]); errno = ENOMEM; return NULL; } /* Copy the current environment variables to the array. */ for (index = 0; environ[index] != NULL; ++index) { envs[index] = environ[index]; } /* Set STDIO variable for using descriptors. This will override the current value of the variable. */ envs[index++] = stdio_var; /* Null terminate array of environment variables. */ envs[index] = NULL; /* Set the file descriptors for the child process. */ fdMap[0] = stdFds[1]; /* stdin */ fdMap[1] = stdFds[1]; /* stdout */ fdMap[2] = stdFds[1]; /* stderr */ /* Set inheritance options. */ memset(&inherit, '\0', sizeof(struct inheritance)); inherit.pgroup = SPAWN_NEWPGROUP; inherit.flags |= SPAWN_SETTHREAD_NP; /* Child is multi-thread capable */ /* Spawn the specified interpreter in a child process. */ pid = spawnp(args[0], 3, fdMap, &inherit, args, envs); rc = errno; /* Save errno from spawn() */ /* Free the environment variable array. */ free(envs); /* Close the other end of the pipe in this process. */ close(stdFds[1]); /* Return in error if spawn() failed. */ if (pid < 0) { fprintf(stderr, "popen(): spawn() failed with errno=%d\n", rc); /* Cleanup. */ close(stdFds[0]); errno = rc; return NULL; } /* End of if spawn() failed */ /* Create a FILE pointer for our end of the pipe. */ if (strcmp(mode, "r") == 0) stream = fdopen(stdFds[0], "r"); else if (strcmp(mode, "w") == 0) stream = fdopen(stdFds[0], "w"); else stream = fdopen(stdFds[0], "rw"); return stream; } /* End of popen() */ /**********************************************************************/ /* pclose() */ /**********************************************************************/ int pclose(FILE *stream) { int status; /* Status from waitpid() */ /* Close our end of the pipe. */ fclose(stream); /* Wait for the child process to end. */ if (waitpid(pid, &status, 0) < 0) { fprintf(stderr, "pclose(): waitpid() failed with errno=%d\n", errno); return -1; } return 0; } /* End of pclose() */