/* * Copyright © 2001 Novell, Inc. All Rights Reserved. * * You may distribute under the terms of either the GNU General Public * License or the Artistic License, as specified in the README file. * */ /* * FILENAME : NWPipe.c * DESCRIPTION : Functions to implement pipes on NetWare. * Author : HYAK * Date : January 2001. * */ #include #include #include "win32ish.h" #include "nwpipe.h" #include "nwplglob.h" // This was added since the compile failed saying "undefined P_WAIT" // when USE_ITHREADS was commented in the makefile #ifndef P_WAIT #define P_WAIT 0 #endif #ifndef P_NOWAIT #define P_NOWAIT 1 #endif /*============================================================================================ Function : fnPipeFileMakeArgv Description : This function makes the argument array. Parameters : ptpf (IN) - Input structure. Returns : Boolean. ==============================================================================================*/ BOOL fnPipeFileMakeArgv(PTEMPPIPEFILE ptpf) { int i=0, j=0; int dindex = 0; int sindex = 0; ptpf->m_argv_len = 0; // Below 2 is added for the following reason: // - The first one is for an additional value that will be added through ptpf->m_redirect. // - The second one is for a NULL termination of the array. // This is required for spawnvp API that takes a NULL-terminated array as its 3rd parameter. // If the array is NOT NULL-terminated, then the server abends at the spawnvp call !! ptpf->m_argv = (char **) malloc((ptpf->m_pipeCommand->m_argc + 2) * sizeof(char*)); if (ptpf->m_argv == NULL) return FALSE; // For memory allocation it is just +1 since the last one is only for NULL-termination // and no memory is required to be allocated. for(i=0; i<(ptpf->m_pipeCommand->m_argc + 1); i++) { ptpf->m_argv[i] = (char *) malloc(MAX_DN_BYTES * sizeof(char)); if (ptpf->m_argv[i] == NULL) { for(j=0; jm_argv[j]) { free(ptpf->m_argv[j]); ptpf->m_argv[j] = NULL; } } free(ptpf->m_argv); ptpf->m_argv = NULL; return FALSE; } } // Copy over parsed items, removing "load" keyword if necessary. sindex = ((stricmp(ptpf->m_pipeCommand->m_argv[0], LOAD_COMMAND) == 0) ? 1 : 0); while (sindex < ptpf->m_pipeCommand->m_argc) { strcpy(ptpf->m_argv[dindex], ptpf->m_pipeCommand->m_argv[sindex]); dindex++; sindex++; } if (stricmp(ptpf->m_argv[0], PERL_COMMAND_NAME) == 0) // If Perl is the first command. { ptpf->m_launchPerl = TRUE; #ifdef MPK_ON ptpf->m_perlSynchSemaphore = kSemaphoreAlloc((BYTE *)"pipeSemaphore", 0); #else ptpf->m_perlSynchSemaphore = OpenLocalSemaphore(0); #endif //MPK_ON } else if (stricmp(ptpf->m_argv[0], (char *)"perlglob") == 0) ptpf->m_doPerlGlob = TRUE; // Create last argument, which will redirect to or from the temp file if (!ptpf->m_doPerlGlob || ptpf->m_mode) { if (!ptpf->m_mode) // If read mode? { if (ptpf->m_launchPerl) strcpy(ptpf->m_redirect, (char *)">"); else strcpy(ptpf->m_redirect, (char *)"(CLIB_OPT)/>"); } else { if (ptpf->m_launchPerl) strcpy(ptpf->m_redirect, (char *)"<"); else strcpy(ptpf->m_redirect, (char *)"(CLIB_OPT)/<"); } strcat(ptpf->m_redirect, ptpf->m_fileName); if (ptpf->m_launchPerl) { char tbuf[15] = {'\0'}; sprintf(tbuf, (char *)" -{%x", ptpf->m_perlSynchSemaphore); strcat(ptpf->m_redirect, tbuf); } strcpy(ptpf->m_argv[dindex], (char*) ptpf->m_redirect); dindex++; } if (dindex < (ptpf->m_pipeCommand->m_argc + 1)) { if(ptpf->m_argv[dindex]) { free(ptpf->m_argv[dindex]); ptpf->m_argv[dindex] = NULL; // NULL termination - required for spawnvp call. } } ptpf->m_argv_len = dindex; // Length of the argv array OR number of argv string values. ptpf->m_argv[ptpf->m_argv_len] = NULL; // NULL termination - required for spawnvp call. return TRUE; } /*============================================================================================ Function : fnPipeFileOpen Description : This function opens the pipe file. Parameters : ptpf (IN) - Input structure. command (IN) - Input command string. mode (IN) - Mode of opening. Returns : File pointer. ==============================================================================================*/ FILE* fnPipeFileOpen(PTEMPPIPEFILE ptpf, char* command, char* mode) { int i=0, j=0; char tempName[_MAX_PATH] = {'\0'}; ptpf->m_fileName = (char *) malloc(_MAX_PATH * sizeof(char)); if(ptpf->m_fileName == NULL) return NULL; // The char array is emptied so that there is no junk characters. strncpy(ptpf->m_fileName, "", (_MAX_PATH * sizeof(char))); // Save off stuff // if(strchr(mode,'r') != 0) ptpf->m_mode = FALSE; // Read mode else if(strchr(mode,'w') != 0) ptpf->m_mode = TRUE; // Write mode else { if(ptpf->m_fileName != NULL) { // if (strlen(ptpf->m_fileName)) if (ptpf->m_fileName) unlink(ptpf->m_fileName); free(ptpf->m_fileName); ptpf->m_fileName = NULL; } return NULL; } ptpf->m_pipeCommand = (PCOMMANDLINEPARSER) malloc(sizeof(COMMANDLINEPARSER)); if (!ptpf->m_pipeCommand) { // if (strlen(ptpf->m_fileName)) if (ptpf->m_fileName) unlink(ptpf->m_fileName); free(ptpf->m_fileName); ptpf->m_fileName = NULL; return NULL; } // Initialise the variables ptpf->m_pipeCommand->m_isValid = TRUE; /**** // Commented since these are not being used. Still retained here. // To be removed once things are proved to be working fine to a good confident level, ptpf->m_pipeCommand->m_redirInName = NULL; ptpf->m_pipeCommand->m_redirOutName = NULL; ptpf->m_pipeCommand->m_redirErrName = NULL; ptpf->m_pipeCommand->m_redirBothName = NULL; ptpf->m_pipeCommand->nextarg = NULL; ****/ ptpf->m_pipeCommand->sSkippedToken = NULL; ptpf->m_pipeCommand->m_argv = NULL; ptpf->m_pipeCommand->new_argv = NULL; #ifdef MPK_ON ptpf->m_pipeCommand->m_qSemaphore = NULL; #else ptpf->m_pipeCommand->m_qSemaphore = 0L; #endif //MPK_ON ptpf->m_pipeCommand->m_noScreen = 0; ptpf->m_pipeCommand->m_AutoDestroy = 0; ptpf->m_pipeCommand->m_argc = 0; ptpf->m_pipeCommand->m_argv_len = 1; ptpf->m_pipeCommand->m_argv = (char **) malloc(ptpf->m_pipeCommand->m_argv_len * sizeof(char *)); if (ptpf->m_pipeCommand->m_argv == NULL) { free(ptpf->m_pipeCommand); ptpf->m_pipeCommand = NULL; // if (strlen(ptpf->m_fileName)) if (ptpf->m_fileName) unlink(ptpf->m_fileName); free(ptpf->m_fileName); ptpf->m_fileName = NULL; return NULL; } ptpf->m_pipeCommand->m_argv[0] = (char *) malloc(MAX_DN_BYTES * sizeof(char)); if (ptpf->m_pipeCommand->m_argv[0] == NULL) { for(j=0; jm_pipeCommand->m_argv[j]) { free(ptpf->m_pipeCommand->m_argv[j]); ptpf->m_pipeCommand->m_argv[j]=NULL; } } free(ptpf->m_pipeCommand->m_argv); ptpf->m_pipeCommand->m_argv=NULL; free(ptpf->m_pipeCommand); ptpf->m_pipeCommand = NULL; // if (strlen(ptpf->m_fileName)) if (ptpf->m_fileName) unlink(ptpf->m_fileName); free(ptpf->m_fileName); ptpf->m_fileName = NULL; return NULL; } ptpf->m_redirect = (char *) malloc(MAX_DN_BYTES * sizeof(char)); if (ptpf->m_redirect == NULL) { for(i=0; im_pipeCommand->m_argv_len; i++) { if(ptpf->m_pipeCommand->m_argv[i] != NULL) { free(ptpf->m_pipeCommand->m_argv[i]); ptpf->m_pipeCommand->m_argv[i] = NULL; } } free(ptpf->m_pipeCommand->m_argv); ptpf->m_pipeCommand->m_argv = NULL; free(ptpf->m_pipeCommand); ptpf->m_pipeCommand = NULL; // if (strlen(ptpf->m_fileName)) if (ptpf->m_fileName) unlink(ptpf->m_fileName); free(ptpf->m_fileName); ptpf->m_fileName = NULL; return NULL; } // The char array is emptied. // If it is not done so, then it could contain some junk values and the string length in that case // will not be zero. This causes erroneous results in fnPipeFileMakeArgv() function // where strlen(ptpf->m_redirect) is used as a check for incrementing the parameter count and // it will wrongly get incremented in such cases. strncpy(ptpf->m_redirect, "", (MAX_DN_BYTES * sizeof(char))); // Parse the parameters. fnCommandLineParser(ptpf->m_pipeCommand, (char *)command, TRUE); if (!ptpf->m_pipeCommand->m_isValid) { fnTempPipeFileReleaseMemory(ptpf); return NULL; } // Create a temporary file name // strncpy ( tempName, fnNwGetEnvironmentStr((char *)"TEMP", NWDEFPERLTEMP), (_MAX_PATH - 20) ); tempName[_MAX_PATH-20] = '\0'; strcat(tempName, (char *)"\\plXXXXXX.tmp"); if (!fnMy_MkTemp(tempName)) { fnTempPipeFileReleaseMemory(ptpf); return NULL; } // create a temporary place-holder file fclose(fopen(tempName, (char *)"w")); strcpy(ptpf->m_fileName, tempName); // Make the argument array if(!fnPipeFileMakeArgv(ptpf)) { fnTempPipeFileReleaseMemory(ptpf); // Release additional memory if(ptpf->m_argv != NULL) { for(i=0; im_argv_len; i++) { if(ptpf->m_argv[i] != NULL) { free(ptpf->m_argv[i]); ptpf->m_argv[i] = NULL; } } free(ptpf->m_argv); ptpf->m_argv = NULL; } return NULL; } // Open the temp file in the appropriate way... // if (!ptpf->m_mode) // If Read mode? { // we wish to spawn a command, intercept its output, // and then get that output // if (!ptpf->m_argv[0]) { fnTempPipeFileReleaseMemory(ptpf); // Release additional memory if(ptpf->m_argv != NULL) { for(i=0; im_argv_len; i++) { if(ptpf->m_argv[i] != NULL) { free(ptpf->m_argv[i]); ptpf->m_argv[i] = NULL; } } free(ptpf->m_argv); ptpf->m_argv = NULL; } return NULL; } if (ptpf->m_launchPerl) fnPipeFileDoPerlLaunch(ptpf); else if (ptpf->m_doPerlGlob) fnDoPerlGlob(ptpf->m_argv, ptpf->m_fileName); // hack to do perl globbing else spawnvp(P_WAIT, ptpf->m_argv[0], ptpf->m_argv); ptpf->m_file = fopen (ptpf->m_fileName, (char *)"r"); // Get the Pipe file handle } else if (ptpf->m_mode) // If Write mode? { // we wish to open the file for writing now and // do the command later // ptpf->m_file = fopen(ptpf->m_fileName, (char *)"w"); } fnTempPipeFileReleaseMemory(ptpf); // Release additional memory if(ptpf->m_argv != NULL) { for(i=0; i<(ptpf->m_argv_len); i++) { if(ptpf->m_argv[i] != NULL) { free(ptpf->m_argv[i]); ptpf->m_argv[i] = NULL; } } free(ptpf->m_argv); ptpf->m_argv = NULL; } return ptpf->m_file; // Return the Pipe file handle. } /*============================================================================================ Function : fnPipeFileClose Description : This function closes the pipe file. Parameters : ptpf (IN) - Input structure. Returns : Nothing. ==============================================================================================*/ void fnPipeFileClose(PTEMPPIPEFILE ptpf) { int i = 0; if (ptpf->m_mode) // If Write mode? { // we wish to spawn a command using our temp file for // its input // if(ptpf->m_file != NULL) { fclose (ptpf->m_file); ptpf->m_file = NULL; } if (ptpf->m_launchPerl) fnPipeFileDoPerlLaunch(ptpf); else if (ptpf->m_argv) spawnvp(P_WAIT, ptpf->m_argv[0], ptpf->m_argv); } // Close the temporary Pipe File, if opened if (ptpf->m_file) { fclose(ptpf->m_file); ptpf->m_file = NULL; } // Delete the temporary Pipe Filename if still valid and free the memory associated with the file name. if(ptpf->m_fileName != NULL) { // if (strlen(ptpf->m_fileName)) if (ptpf->m_fileName) unlink(ptpf->m_fileName); free(ptpf->m_fileName); ptpf->m_fileName = NULL; } /** if(ptpf->m_argv != NULL) { for(i=0; i<(ptpf->m_argv_len); i++) { if(ptpf->m_argv[i] != NULL) { free(ptpf->m_argv[i]); ptpf->m_argv[i] = NULL; } } free(ptpf->m_argv); ptpf->m_argv = NULL; } **/ if (ptpf->m_perlSynchSemaphore) { #ifdef MPK_ON kSemaphoreFree(ptpf->m_perlSynchSemaphore); #else CloseLocalSemaphore(ptpf->m_perlSynchSemaphore); #endif //MPK_ON } return; } /*============================================================================================ Function : fnPipeFileDoPerlLaunch Description : This function launches Perl. Parameters : ptpf (IN) - Input structure. Returns : Nothing. ==============================================================================================*/ void fnPipeFileDoPerlLaunch(PTEMPPIPEFILE ptpf) { char curdir[_MAX_PATH] = {'\0'}; char* pcwd = NULL; int i=0; // save off the current working directory to restore later // this is just a hack! these problems of synchronization and // restoring calling context need a much better solution! pcwd = (char *)getcwd(curdir, sizeof(curdir)-1); fnSystemCommand(ptpf->m_argv, ptpf->m_argv_len); if (ptpf->m_perlSynchSemaphore) { #ifdef MPK_ON kSemaphoreWait(ptpf->m_perlSynchSemaphore); #else WaitOnLocalSemaphore(ptpf->m_perlSynchSemaphore); #endif //MPK_ON } if (pcwd) chdir(pcwd); return; } /*============================================================================================ Function : fnTempPipeFile Description : This function initialises the variables of the structure passed in. Parameters : ptpf (IN) - Input structure. Returns : Nothing. ==============================================================================================*/ void fnTempPipeFile(PTEMPPIPEFILE ptpf) { ptpf->m_fileName = NULL; ptpf->m_mode = FALSE; // Default mode = Read mode. ptpf->m_file = NULL; ptpf->m_pipeCommand = NULL; ptpf->m_argv = NULL; ptpf->m_redirect = NULL; ptpf->m_launchPerl = FALSE; ptpf->m_doPerlGlob = FALSE; #ifdef MPK_ON ptpf->m_perlSynchSemaphore = NULL; #else ptpf->m_perlSynchSemaphore = 0L; #endif ptpf->m_argv_len = 0; return; } /*============================================================================================ Function : fnTempPipeFileReleaseMemory Description : This function frees the memory allocated to various buffers. Parameters : ptpf (IN) - Input structure. Returns : Nothing. ==============================================================================================*/ void fnTempPipeFileReleaseMemory(PTEMPPIPEFILE ptpf) { int i=0; if (ptpf->m_pipeCommand) { if(ptpf->m_pipeCommand->m_argv != NULL) { for(i=0; im_pipeCommand->m_argv_len; i++) { if(ptpf->m_pipeCommand->m_argv[i] != NULL) { free(ptpf->m_pipeCommand->m_argv[i]); ptpf->m_pipeCommand->m_argv[i] = NULL; } } free(ptpf->m_pipeCommand->m_argv); ptpf->m_pipeCommand->m_argv = NULL; } if(ptpf->m_pipeCommand->sSkippedToken != NULL) { free(ptpf->m_pipeCommand->sSkippedToken); ptpf->m_pipeCommand->sSkippedToken = NULL; } /**** // Commented since these are not being used. Still retained here. // To be removed once things are proved to be working fine to a good confident level, if(ptpf->m_pipeCommand->nextarg) { free(ptpf->m_pipeCommand->nextarg); ptpf->m_pipeCommand->nextarg = NULL; } if(ptpf->m_pipeCommand->m_redirInName) { free(ptpf->m_pipeCommand->m_redirInName); ptpf->m_pipeCommand->m_redirInName = NULL; } if(ptpf->m_pipeCommand->m_redirOutName) { free(ptpf->m_pipeCommand->m_redirOutName); ptpf->m_pipeCommand->m_redirOutName = NULL; } if(ptpf->m_pipeCommand->m_redirErrName) { free(ptpf->m_pipeCommand->m_redirErrName); ptpf->m_pipeCommand->m_redirErrName = NULL; } if(ptpf->m_pipeCommand->m_redirBothName) { free(ptpf->m_pipeCommand->m_redirBothName); ptpf->m_pipeCommand->m_redirBothName = NULL; } ****/ if(ptpf->m_pipeCommand != NULL) { free(ptpf->m_pipeCommand); ptpf->m_pipeCommand = NULL; } } if(ptpf->m_redirect != NULL) { free(ptpf->m_redirect); ptpf->m_redirect = NULL; } return; }