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 25e5c89e4eSSatish Balay Notes: 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)); 52*48a46eb9SPierre 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 96e5c89e4eSSatish Balay 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 106e5c89e4eSSatish Balay Notes: 107e5c89e4eSSatish Balay Does not work under Windows 108e5c89e4eSSatish Balay 109db781477SPatrick Sanan .seealso: `PetscFOpen()`, `PetscFClose()`, `PetscPOpen()` 110e5c89e4eSSatish Balay 111e5c89e4eSSatish Balay @*/ 1129371c9d4SSatish Balay PetscErrorCode PetscPClose(MPI_Comm comm, FILE *fd) { 113e5c89e4eSSatish Balay PetscMPIInt rank; 114e5c89e4eSSatish Balay 115e5c89e4eSSatish Balay PetscFunctionBegin; 1169566063dSJacob Faibussowitsch PetscCallMPI(MPI_Comm_rank(comm, &rank)); 117dd400576SPatrick Sanan if (rank == 0) { 118e5c89e4eSSatish Balay char buf[1024]; 1199371c9d4SSatish Balay while (fgets(buf, 1024, fd)) 1209371c9d4SSatish Balay ; /* wait till it prints everything */ 121016831caSBarry Smith (void)pclose(fd); 122e5c89e4eSSatish Balay } 123e5c89e4eSSatish Balay PetscFunctionReturn(0); 124e5c89e4eSSatish Balay } 125e5c89e4eSSatish Balay 126e5c89e4eSSatish Balay /*@C 127e5c89e4eSSatish Balay PetscPOpen - Runs a program on processor zero and sends either its input or output to 128e5c89e4eSSatish Balay a file. 129e5c89e4eSSatish Balay 130d083f849SBarry Smith Logically Collective, but only process 0 runs the command 131e5c89e4eSSatish Balay 132e5c89e4eSSatish Balay Input Parameters: 133e5c89e4eSSatish Balay + comm - MPI communicator, only processor zero runs the program 1340298fd71SBarry Smith . machine - machine to run command on or NULL, or string with 0 in first location 135e5c89e4eSSatish Balay . program - name of program to run 136e5c89e4eSSatish Balay - mode - either r or w 137e5c89e4eSSatish Balay 138e5c89e4eSSatish Balay Output Parameter: 1390298fd71SBarry Smith . fp - the file pointer where program input or output may be read or NULL if don't care 140e5c89e4eSSatish Balay 141e5c89e4eSSatish Balay Level: intermediate 142e5c89e4eSSatish Balay 143e5c89e4eSSatish Balay Notes: 144e5c89e4eSSatish Balay Use PetscPClose() to close the file pointer when you are finished with it 145e5c89e4eSSatish Balay Does not work under Windows 146e5c89e4eSSatish Balay 14774ba8654SBarry 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 155e5c89e4eSSatish Balay @*/ 1569371c9d4SSatish Balay PetscErrorCode PetscPOpen(MPI_Comm comm, const char machine[], const char program[], const char mode[], FILE **fp) { 157e5c89e4eSSatish Balay PetscMPIInt rank; 158e5c89e4eSSatish Balay size_t i, len, cnt; 159e5c89e4eSSatish Balay char commandt[PETSC_MAX_PATH_LEN], command[PETSC_MAX_PATH_LEN]; 160e5c89e4eSSatish Balay FILE *fd; 161e5c89e4eSSatish Balay 162e5c89e4eSSatish Balay PetscFunctionBegin; 163e5c89e4eSSatish Balay /* all processors have to do the string manipulation because PetscStrreplace() is a collective operation */ 16474ba8654SBarry Smith if (PetscPOpenMachine[0] || (machine && machine[0])) { 1659566063dSJacob Faibussowitsch PetscCall(PetscStrcpy(command, "ssh ")); 16674ba8654SBarry Smith if (PetscPOpenMachine[0]) { 1679566063dSJacob Faibussowitsch PetscCall(PetscStrcat(command, PetscPOpenMachine)); 16874ba8654SBarry Smith } else { 1699566063dSJacob Faibussowitsch PetscCall(PetscStrcat(command, machine)); 17074ba8654SBarry Smith } 1719566063dSJacob Faibussowitsch PetscCall(PetscStrcat(command, " \" export DISPLAY=${DISPLAY}; ")); 172e5c89e4eSSatish Balay /* 173e5c89e4eSSatish Balay Copy program into command but protect the " with a \ in front of it 174e5c89e4eSSatish Balay */ 1759566063dSJacob Faibussowitsch PetscCall(PetscStrlen(command, &cnt)); 1769566063dSJacob Faibussowitsch PetscCall(PetscStrlen(program, &len)); 177e5c89e4eSSatish Balay for (i = 0; i < len; i++) { 178a297a907SKarl Rupp if (program[i] == '\"') command[cnt++] = '\\'; 179e5c89e4eSSatish Balay command[cnt++] = program[i]; 180e5c89e4eSSatish Balay } 181e5c89e4eSSatish Balay command[cnt] = 0; 182a297a907SKarl Rupp 1839566063dSJacob Faibussowitsch PetscCall(PetscStrcat(command, "\"")); 184e5c89e4eSSatish Balay } else { 1859566063dSJacob Faibussowitsch PetscCall(PetscStrcpy(command, program)); 186e5c89e4eSSatish Balay } 187e5c89e4eSSatish Balay 1889566063dSJacob Faibussowitsch PetscCall(PetscStrreplace(comm, command, commandt, 1024)); 189e5c89e4eSSatish Balay 1909566063dSJacob Faibussowitsch PetscCallMPI(MPI_Comm_rank(comm, &rank)); 191dd400576SPatrick Sanan if (rank == 0) { 1929566063dSJacob Faibussowitsch PetscCall(PetscInfo(NULL, "Running command :%s\n", commandt)); 193cc73adaaSBarry Smith PetscCheck((fd = popen(commandt, mode)), PETSC_COMM_SELF, PETSC_ERR_LIB, "Cannot run command %s", commandt); 194e5c89e4eSSatish Balay if (fp) *fp = fd; 195e5c89e4eSSatish Balay } 196e5c89e4eSSatish Balay PetscFunctionReturn(0); 197e5c89e4eSSatish Balay } 198e5c89e4eSSatish Balay 19974ba8654SBarry Smith /*@C 20074ba8654SBarry Smith PetscPOpenSetMachine - Sets the name of the default machine to run PetscPOpen() calls on 20174ba8654SBarry Smith 202d083f849SBarry Smith Logically Collective, but only process 0 runs the command 20374ba8654SBarry Smith 20474ba8654SBarry Smith Input Parameter: 20510699b91SBarry Smith . machine - machine to run command on or NULL for the current machine 20674ba8654SBarry Smith 20774ba8654SBarry Smith Options Database: 20810699b91SBarry Smith . -popen_machine <machine> - run the process on this machine 20974ba8654SBarry Smith 21074ba8654SBarry Smith Level: intermediate 21174ba8654SBarry Smith 212db781477SPatrick Sanan .seealso: `PetscFOpen()`, `PetscFClose()`, `PetscPClose()`, `PetscPOpen()` 21374ba8654SBarry Smith @*/ 2149371c9d4SSatish Balay PetscErrorCode PetscPOpenSetMachine(const char machine[]) { 21574ba8654SBarry Smith PetscFunctionBegin; 21674ba8654SBarry Smith if (machine) { 2179566063dSJacob Faibussowitsch PetscCall(PetscStrcpy(PetscPOpenMachine, machine)); 21874ba8654SBarry Smith } else { 21974ba8654SBarry Smith PetscPOpenMachine[0] = 0; 22074ba8654SBarry Smith } 22174ba8654SBarry Smith PetscFunctionReturn(0); 22274ba8654SBarry Smith } 22374ba8654SBarry Smith 224e5c89e4eSSatish Balay #endif 225