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 13cf53795eSBarry Smith Logically Collective; No Fortran Support 14e5c89e4eSSatish Balay 15e5c89e4eSSatish Balay Input Parameters: 16e5c89e4eSSatish Balay + comm - the communicator 17e5c89e4eSSatish Balay . name - the filename 18*bfbbc7b7SBarry 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: 26*bfbbc7b7SBarry 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 61e5c89e4eSSatish Balay PetscFClose - Has the first processor in the communicator close a 62e5c89e4eSSatish Balay file; all others do nothing. 63e5c89e4eSSatish Balay 64cf53795eSBarry Smith Logically Collective; No Fortran Support 65e5c89e4eSSatish Balay 66e5c89e4eSSatish Balay Input Parameters: 67e5c89e4eSSatish Balay + comm - the communicator 68e5c89e4eSSatish Balay - 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 88e5c89e4eSSatish Balay #if defined(PETSC_HAVE_POPEN) 8974ba8654SBarry Smith static char PetscPOpenMachine[128] = ""; 90e5c89e4eSSatish Balay 91e5c89e4eSSatish Balay /*@C 92811af0c4SBarry Smith PetscPClose - Closes (ends) a program on processor zero run with `PetscPOpen()` 93e5c89e4eSSatish Balay 94*bfbbc7b7SBarry Smith Collective, but only MPI rank 0 runs the command 95e5c89e4eSSatish Balay 96e5c89e4eSSatish Balay Input Parameters: 97*bfbbc7b7SBarry Smith + comm - MPI communicator, only rank 0 runs the program 98*bfbbc7b7SBarry Smith - fp - the file pointer where program input or output may be read or `NULL` if don't care 99e5c89e4eSSatish Balay 100e5c89e4eSSatish Balay Level: intermediate 101e5c89e4eSSatish Balay 102811af0c4SBarry Smith Note: 103*bfbbc7b7SBarry Smith Does not work under Microsoft Windows 104e5c89e4eSSatish Balay 105db781477SPatrick Sanan .seealso: `PetscFOpen()`, `PetscFClose()`, `PetscPOpen()` 106e5c89e4eSSatish Balay @*/ 107d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscPClose(MPI_Comm comm, FILE *fd) 108d71ae5a4SJacob Faibussowitsch { 109e5c89e4eSSatish Balay PetscMPIInt rank; 110e5c89e4eSSatish Balay 111e5c89e4eSSatish Balay PetscFunctionBegin; 1129566063dSJacob Faibussowitsch PetscCallMPI(MPI_Comm_rank(comm, &rank)); 113dd400576SPatrick Sanan if (rank == 0) { 114e5c89e4eSSatish Balay char buf[1024]; 1159371c9d4SSatish Balay while (fgets(buf, 1024, fd)) 1169371c9d4SSatish Balay ; /* wait till it prints everything */ 117016831caSBarry Smith (void)pclose(fd); 118e5c89e4eSSatish Balay } 1193ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 120e5c89e4eSSatish Balay } 121e5c89e4eSSatish Balay 122e5c89e4eSSatish Balay /*@C 123e5c89e4eSSatish Balay PetscPOpen - Runs a program on processor zero and sends either its input or output to 124e5c89e4eSSatish Balay a file. 125e5c89e4eSSatish Balay 126*bfbbc7b7SBarry Smith Logically Collective, but only MPI rank 0 runs the command 127e5c89e4eSSatish Balay 128e5c89e4eSSatish Balay Input Parameters: 129e5c89e4eSSatish Balay + comm - MPI communicator, only processor zero runs the program 130*bfbbc7b7SBarry Smith . machine - machine to run command on or `NULL`, or string with 0 in first location 131e5c89e4eSSatish Balay . program - name of program to run 132*bfbbc7b7SBarry Smith - mode - either "r" or "w" 133e5c89e4eSSatish Balay 134e5c89e4eSSatish Balay Output Parameter: 135*bfbbc7b7SBarry Smith . fp - the file pointer where program input or output may be read or `NULL` if don't care 136e5c89e4eSSatish Balay 137e5c89e4eSSatish Balay Level: intermediate 138e5c89e4eSSatish Balay 139e5c89e4eSSatish Balay Notes: 140811af0c4SBarry Smith Use `PetscPClose()` to close the file pointer when you are finished with it 141811af0c4SBarry Smith 142*bfbbc7b7SBarry Smith Does not work under Microsoft Windows 143e5c89e4eSSatish Balay 144811af0c4SBarry Smith If machine is not provided will use the value set with `PetsPOpenSetMachine()` if that was provided, otherwise 14574ba8654SBarry Smith will use the machine running node zero of the communicator 14674ba8654SBarry Smith 147e5c89e4eSSatish Balay The program string may contain ${DISPLAY}, ${HOMEDIRECTORY} or ${WORKINGDIRECTORY}; these 148a5b23f4aSJose E. Roman will be replaced with relevant values. 149e5c89e4eSSatish Balay 150db781477SPatrick Sanan .seealso: `PetscFOpen()`, `PetscFClose()`, `PetscPClose()`, `PetscPOpenSetMachine()` 151e5c89e4eSSatish Balay @*/ 152d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscPOpen(MPI_Comm comm, const char machine[], const char program[], const char mode[], FILE **fp) 153d71ae5a4SJacob Faibussowitsch { 154e5c89e4eSSatish Balay PetscMPIInt rank; 155e5c89e4eSSatish Balay size_t i, len, cnt; 156e5c89e4eSSatish Balay char commandt[PETSC_MAX_PATH_LEN], command[PETSC_MAX_PATH_LEN]; 157e5c89e4eSSatish Balay FILE *fd; 158e5c89e4eSSatish Balay 159e5c89e4eSSatish Balay PetscFunctionBegin; 160e5c89e4eSSatish Balay /* all processors have to do the string manipulation because PetscStrreplace() is a collective operation */ 16174ba8654SBarry Smith if (PetscPOpenMachine[0] || (machine && machine[0])) { 162c6a7a370SJeremy L Thompson PetscCall(PetscStrncpy(command, "ssh ", sizeof(command))); 16374ba8654SBarry Smith if (PetscPOpenMachine[0]) { 164c6a7a370SJeremy L Thompson PetscCall(PetscStrlcat(command, PetscPOpenMachine, sizeof(command))); 16574ba8654SBarry Smith } else { 166c6a7a370SJeremy L Thompson PetscCall(PetscStrlcat(command, machine, sizeof(command))); 16774ba8654SBarry Smith } 168c6a7a370SJeremy L Thompson PetscCall(PetscStrlcat(command, " \" export DISPLAY=${DISPLAY}; ", sizeof(command))); 169e5c89e4eSSatish Balay /* 170e5c89e4eSSatish Balay Copy program into command but protect the " with a \ in front of it 171e5c89e4eSSatish Balay */ 1729566063dSJacob Faibussowitsch PetscCall(PetscStrlen(command, &cnt)); 1739566063dSJacob Faibussowitsch PetscCall(PetscStrlen(program, &len)); 174e5c89e4eSSatish Balay for (i = 0; i < len; i++) { 175a297a907SKarl Rupp if (program[i] == '\"') command[cnt++] = '\\'; 176e5c89e4eSSatish Balay command[cnt++] = program[i]; 177e5c89e4eSSatish Balay } 178e5c89e4eSSatish Balay command[cnt] = 0; 179a297a907SKarl Rupp 180c6a7a370SJeremy L Thompson PetscCall(PetscStrlcat(command, "\"", sizeof(command))); 181e5c89e4eSSatish Balay } else { 182c6a7a370SJeremy L Thompson PetscCall(PetscStrncpy(command, program, sizeof(command))); 183e5c89e4eSSatish Balay } 184e5c89e4eSSatish Balay 1859566063dSJacob Faibussowitsch PetscCall(PetscStrreplace(comm, command, commandt, 1024)); 186e5c89e4eSSatish Balay 1879566063dSJacob Faibussowitsch PetscCallMPI(MPI_Comm_rank(comm, &rank)); 188dd400576SPatrick Sanan if (rank == 0) { 1899566063dSJacob Faibussowitsch PetscCall(PetscInfo(NULL, "Running command :%s\n", commandt)); 190cc73adaaSBarry Smith PetscCheck((fd = popen(commandt, mode)), PETSC_COMM_SELF, PETSC_ERR_LIB, "Cannot run command %s", commandt); 191e5c89e4eSSatish Balay if (fp) *fp = fd; 192e5c89e4eSSatish Balay } 1933ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 194e5c89e4eSSatish Balay } 195e5c89e4eSSatish Balay 19674ba8654SBarry Smith /*@C 197811af0c4SBarry Smith PetscPOpenSetMachine - Sets the name of the default machine to run `PetscPOpen()` calls on 19874ba8654SBarry Smith 199*bfbbc7b7SBarry Smith Logically Collective, but only MPI rank 0 runs the command 20074ba8654SBarry Smith 20174ba8654SBarry Smith Input Parameter: 202*bfbbc7b7SBarry Smith . machine - machine to run command on or `NULL` for the current machine 20374ba8654SBarry Smith 204811af0c4SBarry Smith Options Database Key: 20510699b91SBarry Smith . -popen_machine <machine> - run the process on this machine 20674ba8654SBarry Smith 20774ba8654SBarry Smith Level: intermediate 20874ba8654SBarry Smith 209db781477SPatrick Sanan .seealso: `PetscFOpen()`, `PetscFClose()`, `PetscPClose()`, `PetscPOpen()` 21074ba8654SBarry Smith @*/ 211d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscPOpenSetMachine(const char machine[]) 212d71ae5a4SJacob Faibussowitsch { 21374ba8654SBarry Smith PetscFunctionBegin; 21474ba8654SBarry Smith if (machine) { 215c6a7a370SJeremy L Thompson PetscCall(PetscStrncpy(PetscPOpenMachine, machine, sizeof(PetscPOpenMachine))); 21674ba8654SBarry Smith } else { 21774ba8654SBarry Smith PetscPOpenMachine[0] = 0; 21874ba8654SBarry Smith } 2193ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 22074ba8654SBarry Smith } 22174ba8654SBarry Smith 222e5c89e4eSSatish Balay #endif 223