10039db0dSBarry Smith #define PETSC_DESIRE_FEATURE_TEST_MACROS /* for popen() */ 2e5c89e4eSSatish Balay /* 34c500f23SPierre Jolivet Some PETSc utility routines to add simple parallel IO capabilities 4e5c89e4eSSatish Balay */ 5c6db04a5SJed Brown #include <petscsys.h> 6cc4c1da9SBarry Smith #include <petsc/private/logimpl.h> /*I "petscsys.h" I*/ 7d0286d30SJed Brown #include <errno.h> 8d0286d30SJed Brown 9e5c89e4eSSatish Balay /*@C 1021532e8aSBarry Smith PetscFOpen - Has the first process in the MPI communicator open a file; 11e5c89e4eSSatish Balay all others do nothing. 12e5c89e4eSSatish Balay 13cc4c1da9SBarry Smith Logically Collective 14e5c89e4eSSatish Balay 15e5c89e4eSSatish Balay Input Parameters: 1621532e8aSBarry Smith + comm - the MPI communicator 17e5c89e4eSSatish Balay . name - the filename 18bfbbc7b7SBarry Smith - mode - the mode for `fopen()`, usually "w" 19e5c89e4eSSatish Balay 20e5c89e4eSSatish Balay Output Parameter: 21e5c89e4eSSatish Balay . fp - the file pointer 22e5c89e4eSSatish Balay 23e5c89e4eSSatish Balay Level: developer 24e5c89e4eSSatish Balay 25811af0c4SBarry Smith Note: 26bfbbc7b7SBarry Smith `NULL`, "stderr" or "stdout" may be passed in as the filename 27e5c89e4eSSatish Balay 28db781477SPatrick Sanan .seealso: `PetscFClose()`, `PetscSynchronizedFGets()`, `PetscSynchronizedPrintf()`, `PetscSynchronizedFlush()`, 29db781477SPatrick Sanan `PetscFPrintf()` 30e5c89e4eSSatish Balay @*/ 31d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscFOpen(MPI_Comm comm, const char name[], const char mode[], FILE **fp) 32d71ae5a4SJacob Faibussowitsch { 33e5c89e4eSSatish Balay PetscMPIInt rank; 34e5c89e4eSSatish Balay FILE *fd; 35e5c89e4eSSatish Balay char fname[PETSC_MAX_PATH_LEN], tname[PETSC_MAX_PATH_LEN]; 36e5c89e4eSSatish Balay 37e5c89e4eSSatish Balay PetscFunctionBegin; 389566063dSJacob Faibussowitsch PetscCallMPI(MPI_Comm_rank(comm, &rank)); 39dd400576SPatrick Sanan if (rank == 0) { 40ace3abfcSBarry Smith PetscBool isstdout, isstderr; 419566063dSJacob Faibussowitsch PetscCall(PetscStrcmp(name, "stdout", &isstdout)); 429566063dSJacob Faibussowitsch PetscCall(PetscStrcmp(name, "stderr", &isstderr)); 43a297a907SKarl Rupp if (isstdout || !name) fd = PETSC_STDOUT; 44a297a907SKarl Rupp else if (isstderr) fd = PETSC_STDERR; 45a297a907SKarl Rupp else { 46bbcf679cSJacob Faibussowitsch PetscBool devnull = PETSC_FALSE; 479566063dSJacob Faibussowitsch PetscCall(PetscStrreplace(PETSC_COMM_SELF, name, tname, PETSC_MAX_PATH_LEN)); 489566063dSJacob Faibussowitsch PetscCall(PetscFixFilename(tname, fname)); 499566063dSJacob Faibussowitsch PetscCall(PetscStrbeginswith(fname, "/dev/null", &devnull)); 50c6a7a370SJeremy L Thompson if (devnull) PetscCall(PetscStrncpy(fname, "/dev/null", sizeof(fname))); 519566063dSJacob Faibussowitsch PetscCall(PetscInfo(0, "Opening file %s\n", fname)); 52e5c89e4eSSatish Balay fd = fopen(fname, mode); 5328b400f6SJacob Faibussowitsch PetscCheck(fd, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to open file %s", fname); 54e5c89e4eSSatish Balay } 5502c9f0b5SLisandro Dalcin } else fd = NULL; 56e5c89e4eSSatish Balay *fp = fd; 573ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 58e5c89e4eSSatish Balay } 59e5c89e4eSSatish Balay 60e8976759SBarry Smith /*@C 6121532e8aSBarry Smith PetscFClose - Has MPI rank 0 in the communicator close a 6221532e8aSBarry Smith file (usually obtained with `PetscFOpen()`; all others do nothing. 63e5c89e4eSSatish Balay 64cc4c1da9SBarry Smith Logically Collective 65e5c89e4eSSatish Balay 66e5c89e4eSSatish Balay Input Parameters: 6721532e8aSBarry Smith + comm - the MPI communicator 6821532e8aSBarry Smith - fd - the file, opened with `PetscFOpen()` 69e5c89e4eSSatish Balay 70e5c89e4eSSatish Balay Level: developer 71e5c89e4eSSatish Balay 72db781477SPatrick Sanan .seealso: `PetscFOpen()` 73e5c89e4eSSatish Balay @*/ 74d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscFClose(MPI_Comm comm, FILE *fd) 75d71ae5a4SJacob Faibussowitsch { 76e5c89e4eSSatish Balay PetscMPIInt rank; 77ed9cf6e9SBarry Smith int err; 78e5c89e4eSSatish Balay 79e5c89e4eSSatish Balay PetscFunctionBegin; 809566063dSJacob Faibussowitsch PetscCallMPI(MPI_Comm_rank(comm, &rank)); 81dd400576SPatrick Sanan if (rank == 0 && fd != PETSC_STDOUT && fd != PETSC_STDERR) { 82ed9cf6e9SBarry Smith err = fclose(fd); 8328b400f6SJacob Faibussowitsch PetscCheck(!err, PETSC_COMM_SELF, PETSC_ERR_SYS, "fclose() failed on file"); 84ed9cf6e9SBarry Smith } 853ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 86e5c89e4eSSatish Balay } 87e5c89e4eSSatish Balay 8874ba8654SBarry Smith static char PetscPOpenMachine[128] = ""; 89e5c89e4eSSatish Balay 90e5c89e4eSSatish Balay /*@C 9121532e8aSBarry Smith PetscPClose - Closes (ends) a program on MPI rank 0 run with `PetscPOpen()` 92e5c89e4eSSatish Balay 9321532e8aSBarry Smith Collective, but only MPI rank 0 does anything 94e5c89e4eSSatish Balay 95e5c89e4eSSatish Balay Input Parameters: 9621532e8aSBarry Smith + comm - MPI communicator, only rank 0 performs the close 9721532e8aSBarry Smith - fd - the file pointer where program input or output may be read or `NULL` if don't care 98e5c89e4eSSatish Balay 99e5c89e4eSSatish Balay Level: intermediate 100e5c89e4eSSatish Balay 101811af0c4SBarry Smith Note: 102bfbbc7b7SBarry Smith Does not work under Microsoft Windows 103e5c89e4eSSatish Balay 104db781477SPatrick Sanan .seealso: `PetscFOpen()`, `PetscFClose()`, `PetscPOpen()` 105e5c89e4eSSatish Balay @*/ 106d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscPClose(MPI_Comm comm, FILE *fd) 107d71ae5a4SJacob Faibussowitsch { 108cc4c1da9SBarry Smith #if defined(PETSC_HAVE_POPEN) 109e5c89e4eSSatish Balay PetscMPIInt rank; 110cc4c1da9SBarry Smith #endif 111e5c89e4eSSatish Balay 112e5c89e4eSSatish Balay PetscFunctionBegin; 113cc4c1da9SBarry Smith #if defined(PETSC_HAVE_POPEN) 1149566063dSJacob Faibussowitsch PetscCallMPI(MPI_Comm_rank(comm, &rank)); 115dd400576SPatrick Sanan if (rank == 0) { 116e5c89e4eSSatish Balay char buf[1024]; 117fbccb6d4SPierre Jolivet while (fgets(buf, 1024, fd)); /* wait till it prints everything */ 118016831caSBarry Smith (void)pclose(fd); 119e5c89e4eSSatish Balay } 120cc4c1da9SBarry Smith #else 121cc4c1da9SBarry Smith SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "pclose() - routine is unavailable."); 122cc4c1da9SBarry Smith #endif 1233ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 124e5c89e4eSSatish Balay } 125e5c89e4eSSatish Balay 126e5c89e4eSSatish Balay /*@C 12721532e8aSBarry Smith PetscPOpen - Runs a program on MPI rank 0 and sends either its input or output to 128e5c89e4eSSatish Balay a file. 129e5c89e4eSSatish Balay 130bfbbc7b7SBarry Smith Logically Collective, but only MPI rank 0 runs the command 131e5c89e4eSSatish Balay 132e5c89e4eSSatish Balay Input Parameters: 133e5c89e4eSSatish Balay + comm - MPI communicator, only processor zero runs the program 13421532e8aSBarry Smith . machine - machine to run command on or `NULL`, or a string with 0 in first location 135e5c89e4eSSatish Balay . program - name of program to run 136bfbbc7b7SBarry Smith - mode - either "r" or "w" 137e5c89e4eSSatish Balay 138e5c89e4eSSatish Balay Output Parameter: 13921532e8aSBarry Smith . fp - the file pointer where program input or output may be read or `NULL` if results are not needed 140e5c89e4eSSatish Balay 141e5c89e4eSSatish Balay Level: intermediate 142e5c89e4eSSatish Balay 143e5c89e4eSSatish Balay Notes: 144811af0c4SBarry Smith Use `PetscPClose()` to close the file pointer when you are finished with it 145811af0c4SBarry Smith 146bfbbc7b7SBarry Smith Does not work under Microsoft Windows 147e5c89e4eSSatish Balay 148*54c05997SPierre Jolivet If machine is not provided will use the value set with `PetscPOpenSetMachine()` if that was provided, otherwise 14921532e8aSBarry Smith will use the machine running MPI rank 0 of the communicator 15074ba8654SBarry Smith 151e5c89e4eSSatish Balay The program string may contain ${DISPLAY}, ${HOMEDIRECTORY} or ${WORKINGDIRECTORY}; these 152a5b23f4aSJose E. Roman will be replaced with relevant values. 153e5c89e4eSSatish Balay 154db781477SPatrick Sanan .seealso: `PetscFOpen()`, `PetscFClose()`, `PetscPClose()`, `PetscPOpenSetMachine()` 155e5c89e4eSSatish Balay @*/ 156d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscPOpen(MPI_Comm comm, const char machine[], const char program[], const char mode[], FILE **fp) 157d71ae5a4SJacob Faibussowitsch { 158cc4c1da9SBarry Smith #if defined(PETSC_HAVE_POPEN) 159e5c89e4eSSatish Balay PetscMPIInt rank; 160e5c89e4eSSatish Balay size_t i, len, cnt; 161e5c89e4eSSatish Balay char commandt[PETSC_MAX_PATH_LEN], command[PETSC_MAX_PATH_LEN]; 162e5c89e4eSSatish Balay FILE *fd; 163cc4c1da9SBarry Smith #endif 164e5c89e4eSSatish Balay 165e5c89e4eSSatish Balay PetscFunctionBegin; 166cc4c1da9SBarry Smith #if defined(PETSC_HAVE_POPEN) 167e5c89e4eSSatish Balay /* all processors have to do the string manipulation because PetscStrreplace() is a collective operation */ 16874ba8654SBarry Smith if (PetscPOpenMachine[0] || (machine && machine[0])) { 169c6a7a370SJeremy L Thompson PetscCall(PetscStrncpy(command, "ssh ", sizeof(command))); 17074ba8654SBarry Smith if (PetscPOpenMachine[0]) { 171c6a7a370SJeremy L Thompson PetscCall(PetscStrlcat(command, PetscPOpenMachine, sizeof(command))); 17274ba8654SBarry Smith } else { 173c6a7a370SJeremy L Thompson PetscCall(PetscStrlcat(command, machine, sizeof(command))); 17474ba8654SBarry Smith } 175c6a7a370SJeremy L Thompson PetscCall(PetscStrlcat(command, " \" export DISPLAY=${DISPLAY}; ", sizeof(command))); 176e5c89e4eSSatish Balay /* 177e5c89e4eSSatish Balay Copy program into command but protect the " with a \ in front of it 178e5c89e4eSSatish Balay */ 1799566063dSJacob Faibussowitsch PetscCall(PetscStrlen(command, &cnt)); 1809566063dSJacob Faibussowitsch PetscCall(PetscStrlen(program, &len)); 181e5c89e4eSSatish Balay for (i = 0; i < len; i++) { 182a297a907SKarl Rupp if (program[i] == '\"') command[cnt++] = '\\'; 183e5c89e4eSSatish Balay command[cnt++] = program[i]; 184e5c89e4eSSatish Balay } 185e5c89e4eSSatish Balay command[cnt] = 0; 186a297a907SKarl Rupp 187c6a7a370SJeremy L Thompson PetscCall(PetscStrlcat(command, "\"", sizeof(command))); 188e5c89e4eSSatish Balay } else { 189c6a7a370SJeremy L Thompson PetscCall(PetscStrncpy(command, program, sizeof(command))); 190e5c89e4eSSatish Balay } 191e5c89e4eSSatish Balay 1929566063dSJacob Faibussowitsch PetscCall(PetscStrreplace(comm, command, commandt, 1024)); 193e5c89e4eSSatish Balay 1949566063dSJacob Faibussowitsch PetscCallMPI(MPI_Comm_rank(comm, &rank)); 195dd400576SPatrick Sanan if (rank == 0) { 1969566063dSJacob Faibussowitsch PetscCall(PetscInfo(NULL, "Running command :%s\n", commandt)); 19757508eceSPierre Jolivet PetscCheck(fd = popen(commandt, mode), PETSC_COMM_SELF, PETSC_ERR_LIB, "Cannot run command %s", commandt); 198e5c89e4eSSatish Balay if (fp) *fp = fd; 199e5c89e4eSSatish Balay } 200cc4c1da9SBarry Smith #else 201cc4c1da9SBarry Smith SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "popen() - system routine is unavailable."); 202cc4c1da9SBarry Smith #endif 2033ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 204e5c89e4eSSatish Balay } 205e5c89e4eSSatish Balay 206cc4c1da9SBarry Smith /*@ 207811af0c4SBarry Smith PetscPOpenSetMachine - Sets the name of the default machine to run `PetscPOpen()` calls on 20874ba8654SBarry Smith 209a3b724e8SBarry Smith Logically Collective, but only the MPI process with rank 0 runs the command 21074ba8654SBarry Smith 21174ba8654SBarry Smith Input Parameter: 212bfbbc7b7SBarry Smith . machine - machine to run command on or `NULL` for the current machine 21374ba8654SBarry Smith 214811af0c4SBarry Smith Options Database Key: 21510699b91SBarry Smith . -popen_machine <machine> - run the process on this machine 21674ba8654SBarry Smith 21774ba8654SBarry Smith Level: intermediate 21874ba8654SBarry Smith 219db781477SPatrick Sanan .seealso: `PetscFOpen()`, `PetscFClose()`, `PetscPClose()`, `PetscPOpen()` 22074ba8654SBarry Smith @*/ 221d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscPOpenSetMachine(const char machine[]) 222d71ae5a4SJacob Faibussowitsch { 22374ba8654SBarry Smith PetscFunctionBegin; 22474ba8654SBarry Smith if (machine) { 225c6a7a370SJeremy L Thompson PetscCall(PetscStrncpy(PetscPOpenMachine, machine, sizeof(PetscPOpenMachine))); 22674ba8654SBarry Smith } else { 22774ba8654SBarry Smith PetscPOpenMachine[0] = 0; 22874ba8654SBarry Smith } 2293ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 23074ba8654SBarry Smith } 231