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> 6e94e781bSJacob Faibussowitsch #include <petsc/private/logimpl.h> 7d0286d30SJed Brown #include <errno.h> 8d0286d30SJed Brown 9e5c89e4eSSatish Balay /*@C 10e5c89e4eSSatish Balay PetscFOpen - Has the first process in the communicator open a file; 11e5c89e4eSSatish Balay all others do nothing. 12e5c89e4eSSatish Balay 13d083f849SBarry Smith Logically Collective 14e5c89e4eSSatish Balay 15e5c89e4eSSatish Balay Input Parameters: 16e5c89e4eSSatish Balay + comm - the communicator 17e5c89e4eSSatish Balay . name - the filename 18e5c89e4eSSatish Balay - 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 25*811af0c4SBarry Smith Note: 260298fd71SBarry Smith NULL (0), "stderr" or "stdout" may be passed in as the filename 27e5c89e4eSSatish Balay 28e5c89e4eSSatish Balay Fortran Note: 29e5c89e4eSSatish Balay This routine is not supported in Fortran. 30e5c89e4eSSatish Balay 31db781477SPatrick Sanan .seealso: `PetscFClose()`, `PetscSynchronizedFGets()`, `PetscSynchronizedPrintf()`, `PetscSynchronizedFlush()`, 32db781477SPatrick Sanan `PetscFPrintf()` 33e5c89e4eSSatish Balay @*/ 349371c9d4SSatish Balay PetscErrorCode PetscFOpen(MPI_Comm comm, const char name[], const char mode[], FILE **fp) { 35e5c89e4eSSatish Balay PetscMPIInt rank; 36e5c89e4eSSatish Balay FILE *fd; 37e5c89e4eSSatish Balay char fname[PETSC_MAX_PATH_LEN], tname[PETSC_MAX_PATH_LEN]; 38e5c89e4eSSatish Balay 39e5c89e4eSSatish Balay PetscFunctionBegin; 409566063dSJacob Faibussowitsch PetscCallMPI(MPI_Comm_rank(comm, &rank)); 41dd400576SPatrick Sanan if (rank == 0) { 42ace3abfcSBarry Smith PetscBool isstdout, isstderr; 439566063dSJacob Faibussowitsch PetscCall(PetscStrcmp(name, "stdout", &isstdout)); 449566063dSJacob Faibussowitsch PetscCall(PetscStrcmp(name, "stderr", &isstderr)); 45a297a907SKarl Rupp if (isstdout || !name) fd = PETSC_STDOUT; 46a297a907SKarl Rupp else if (isstderr) fd = PETSC_STDERR; 47a297a907SKarl Rupp else { 48b3f259d6SBarry Smith PetscBool devnull; 499566063dSJacob Faibussowitsch PetscCall(PetscStrreplace(PETSC_COMM_SELF, name, tname, PETSC_MAX_PATH_LEN)); 509566063dSJacob Faibussowitsch PetscCall(PetscFixFilename(tname, fname)); 519566063dSJacob Faibussowitsch PetscCall(PetscStrbeginswith(fname, "/dev/null", &devnull)); 5248a46eb9SPierre Jolivet if (devnull) PetscCall(PetscStrcpy(fname, "/dev/null")); 539566063dSJacob Faibussowitsch PetscCall(PetscInfo(0, "Opening file %s\n", fname)); 54e5c89e4eSSatish Balay fd = fopen(fname, mode); 5528b400f6SJacob Faibussowitsch PetscCheck(fd, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to open file %s", fname); 56e5c89e4eSSatish Balay } 5702c9f0b5SLisandro Dalcin } else fd = NULL; 58e5c89e4eSSatish Balay *fp = fd; 59e5c89e4eSSatish Balay PetscFunctionReturn(0); 60e5c89e4eSSatish Balay } 61e5c89e4eSSatish Balay 62e8976759SBarry Smith /*@C 63e5c89e4eSSatish Balay PetscFClose - Has the first processor in the communicator close a 64e5c89e4eSSatish Balay file; all others do nothing. 65e5c89e4eSSatish Balay 66d083f849SBarry Smith Logically Collective 67e5c89e4eSSatish Balay 68e5c89e4eSSatish Balay Input Parameters: 69e5c89e4eSSatish Balay + comm - the communicator 70e5c89e4eSSatish Balay - fd - the file, opened with PetscFOpen() 71e5c89e4eSSatish Balay 72e5c89e4eSSatish Balay Level: developer 73e5c89e4eSSatish Balay 74e5c89e4eSSatish Balay Fortran Note: 75e5c89e4eSSatish Balay This routine is not supported in Fortran. 76e5c89e4eSSatish Balay 77db781477SPatrick Sanan .seealso: `PetscFOpen()` 78e5c89e4eSSatish Balay @*/ 799371c9d4SSatish Balay PetscErrorCode PetscFClose(MPI_Comm comm, FILE *fd) { 80e5c89e4eSSatish Balay PetscMPIInt rank; 81ed9cf6e9SBarry Smith int err; 82e5c89e4eSSatish Balay 83e5c89e4eSSatish Balay PetscFunctionBegin; 849566063dSJacob Faibussowitsch PetscCallMPI(MPI_Comm_rank(comm, &rank)); 85dd400576SPatrick Sanan if (rank == 0 && fd != PETSC_STDOUT && fd != PETSC_STDERR) { 86ed9cf6e9SBarry Smith err = fclose(fd); 8728b400f6SJacob Faibussowitsch PetscCheck(!err, PETSC_COMM_SELF, PETSC_ERR_SYS, "fclose() failed on file"); 88ed9cf6e9SBarry Smith } 89e5c89e4eSSatish Balay PetscFunctionReturn(0); 90e5c89e4eSSatish Balay } 91e5c89e4eSSatish Balay 92e5c89e4eSSatish Balay #if defined(PETSC_HAVE_POPEN) 9374ba8654SBarry Smith static char PetscPOpenMachine[128] = ""; 94e5c89e4eSSatish Balay 95e5c89e4eSSatish Balay /*@C 96*811af0c4SBarry Smith PetscPClose - Closes (ends) a program on processor zero run with `PetscPOpen()` 97e5c89e4eSSatish Balay 98d083f849SBarry Smith Collective, but only process 0 runs the command 99e5c89e4eSSatish Balay 100e5c89e4eSSatish Balay Input Parameters: 101e5c89e4eSSatish Balay + comm - MPI communicator, only processor zero runs the program 1020298fd71SBarry Smith - fp - the file pointer where program input or output may be read or NULL if don't care 103e5c89e4eSSatish Balay 104e5c89e4eSSatish Balay Level: intermediate 105e5c89e4eSSatish Balay 106*811af0c4SBarry Smith Note: 107e5c89e4eSSatish Balay Does not work under Windows 108e5c89e4eSSatish Balay 109db781477SPatrick Sanan .seealso: `PetscFOpen()`, `PetscFClose()`, `PetscPOpen()` 110e5c89e4eSSatish Balay @*/ 1119371c9d4SSatish Balay PetscErrorCode PetscPClose(MPI_Comm comm, FILE *fd) { 112e5c89e4eSSatish Balay PetscMPIInt rank; 113e5c89e4eSSatish Balay 114e5c89e4eSSatish Balay PetscFunctionBegin; 1159566063dSJacob Faibussowitsch PetscCallMPI(MPI_Comm_rank(comm, &rank)); 116dd400576SPatrick Sanan if (rank == 0) { 117e5c89e4eSSatish Balay char buf[1024]; 1189371c9d4SSatish Balay while (fgets(buf, 1024, fd)) 1199371c9d4SSatish Balay ; /* wait till it prints everything */ 120016831caSBarry Smith (void)pclose(fd); 121e5c89e4eSSatish Balay } 122e5c89e4eSSatish Balay PetscFunctionReturn(0); 123e5c89e4eSSatish Balay } 124e5c89e4eSSatish Balay 125e5c89e4eSSatish Balay /*@C 126e5c89e4eSSatish Balay PetscPOpen - Runs a program on processor zero and sends either its input or output to 127e5c89e4eSSatish Balay a file. 128e5c89e4eSSatish Balay 129d083f849SBarry Smith Logically Collective, but only process 0 runs the command 130e5c89e4eSSatish Balay 131e5c89e4eSSatish Balay Input Parameters: 132e5c89e4eSSatish Balay + comm - MPI communicator, only processor zero runs the program 1330298fd71SBarry Smith . machine - machine to run command on or NULL, or string with 0 in first location 134e5c89e4eSSatish Balay . program - name of program to run 135e5c89e4eSSatish Balay - mode - either r or w 136e5c89e4eSSatish Balay 137e5c89e4eSSatish Balay Output Parameter: 1380298fd71SBarry Smith . fp - the file pointer where program input or output may be read or NULL if don't care 139e5c89e4eSSatish Balay 140e5c89e4eSSatish Balay Level: intermediate 141e5c89e4eSSatish Balay 142e5c89e4eSSatish Balay Notes: 143*811af0c4SBarry Smith Use `PetscPClose()` to close the file pointer when you are finished with it 144*811af0c4SBarry Smith 145e5c89e4eSSatish Balay Does not work under Windows 146e5c89e4eSSatish Balay 147*811af0c4SBarry Smith If machine is not provided will use the value set with `PetsPOpenSetMachine()` if that was provided, otherwise 14874ba8654SBarry Smith will use the machine running node zero of the communicator 14974ba8654SBarry Smith 150e5c89e4eSSatish Balay The program string may contain ${DISPLAY}, ${HOMEDIRECTORY} or ${WORKINGDIRECTORY}; these 151a5b23f4aSJose E. Roman will be replaced with relevant values. 152e5c89e4eSSatish Balay 153db781477SPatrick Sanan .seealso: `PetscFOpen()`, `PetscFClose()`, `PetscPClose()`, `PetscPOpenSetMachine()` 154e5c89e4eSSatish Balay @*/ 1559371c9d4SSatish Balay PetscErrorCode PetscPOpen(MPI_Comm comm, const char machine[], const char program[], const char mode[], FILE **fp) { 156e5c89e4eSSatish Balay PetscMPIInt rank; 157e5c89e4eSSatish Balay size_t i, len, cnt; 158e5c89e4eSSatish Balay char commandt[PETSC_MAX_PATH_LEN], command[PETSC_MAX_PATH_LEN]; 159e5c89e4eSSatish Balay FILE *fd; 160e5c89e4eSSatish Balay 161e5c89e4eSSatish Balay PetscFunctionBegin; 162e5c89e4eSSatish Balay /* all processors have to do the string manipulation because PetscStrreplace() is a collective operation */ 16374ba8654SBarry Smith if (PetscPOpenMachine[0] || (machine && machine[0])) { 1649566063dSJacob Faibussowitsch PetscCall(PetscStrcpy(command, "ssh ")); 16574ba8654SBarry Smith if (PetscPOpenMachine[0]) { 1669566063dSJacob Faibussowitsch PetscCall(PetscStrcat(command, PetscPOpenMachine)); 16774ba8654SBarry Smith } else { 1689566063dSJacob Faibussowitsch PetscCall(PetscStrcat(command, machine)); 16974ba8654SBarry Smith } 1709566063dSJacob Faibussowitsch PetscCall(PetscStrcat(command, " \" export DISPLAY=${DISPLAY}; ")); 171e5c89e4eSSatish Balay /* 172e5c89e4eSSatish Balay Copy program into command but protect the " with a \ in front of it 173e5c89e4eSSatish Balay */ 1749566063dSJacob Faibussowitsch PetscCall(PetscStrlen(command, &cnt)); 1759566063dSJacob Faibussowitsch PetscCall(PetscStrlen(program, &len)); 176e5c89e4eSSatish Balay for (i = 0; i < len; i++) { 177a297a907SKarl Rupp if (program[i] == '\"') command[cnt++] = '\\'; 178e5c89e4eSSatish Balay command[cnt++] = program[i]; 179e5c89e4eSSatish Balay } 180e5c89e4eSSatish Balay command[cnt] = 0; 181a297a907SKarl Rupp 1829566063dSJacob Faibussowitsch PetscCall(PetscStrcat(command, "\"")); 183e5c89e4eSSatish Balay } else { 1849566063dSJacob Faibussowitsch PetscCall(PetscStrcpy(command, program)); 185e5c89e4eSSatish Balay } 186e5c89e4eSSatish Balay 1879566063dSJacob Faibussowitsch PetscCall(PetscStrreplace(comm, command, commandt, 1024)); 188e5c89e4eSSatish Balay 1899566063dSJacob Faibussowitsch PetscCallMPI(MPI_Comm_rank(comm, &rank)); 190dd400576SPatrick Sanan if (rank == 0) { 1919566063dSJacob Faibussowitsch PetscCall(PetscInfo(NULL, "Running command :%s\n", commandt)); 192cc73adaaSBarry Smith PetscCheck((fd = popen(commandt, mode)), PETSC_COMM_SELF, PETSC_ERR_LIB, "Cannot run command %s", commandt); 193e5c89e4eSSatish Balay if (fp) *fp = fd; 194e5c89e4eSSatish Balay } 195e5c89e4eSSatish Balay PetscFunctionReturn(0); 196e5c89e4eSSatish Balay } 197e5c89e4eSSatish Balay 19874ba8654SBarry Smith /*@C 199*811af0c4SBarry Smith PetscPOpenSetMachine - Sets the name of the default machine to run `PetscPOpen()` calls on 20074ba8654SBarry Smith 201d083f849SBarry Smith Logically Collective, but only process 0 runs the command 20274ba8654SBarry Smith 20374ba8654SBarry Smith Input Parameter: 20410699b91SBarry Smith . machine - machine to run command on or NULL for the current machine 20574ba8654SBarry Smith 206*811af0c4SBarry Smith Options Database Key: 20710699b91SBarry Smith . -popen_machine <machine> - run the process on this machine 20874ba8654SBarry Smith 20974ba8654SBarry Smith Level: intermediate 21074ba8654SBarry Smith 211db781477SPatrick Sanan .seealso: `PetscFOpen()`, `PetscFClose()`, `PetscPClose()`, `PetscPOpen()` 21274ba8654SBarry Smith @*/ 2139371c9d4SSatish Balay PetscErrorCode PetscPOpenSetMachine(const char machine[]) { 21474ba8654SBarry Smith PetscFunctionBegin; 21574ba8654SBarry Smith if (machine) { 2169566063dSJacob Faibussowitsch PetscCall(PetscStrcpy(PetscPOpenMachine, machine)); 21774ba8654SBarry Smith } else { 21874ba8654SBarry Smith PetscPOpenMachine[0] = 0; 21974ba8654SBarry Smith } 22074ba8654SBarry Smith PetscFunctionReturn(0); 22174ba8654SBarry Smith } 22274ba8654SBarry Smith 223e5c89e4eSSatish Balay #endif 224