1 #define PETSC_DESIRE_FEATURE_TEST_MACROS /* for popen() */ 2 /* 3 Some PETSc utility routines to add simple parallel IO capabilities 4 */ 5 #include <petscsys.h> 6 #include <petsc/private/logimpl.h> 7 #include <errno.h> 8 9 /*@C 10 PetscFOpen - Has the first process in the MPI communicator open a file; 11 all others do nothing. 12 13 Logically Collective; No Fortran Support 14 15 Input Parameters: 16 + comm - the MPI communicator 17 . name - the filename 18 - mode - the mode for `fopen()`, usually "w" 19 20 Output Parameter: 21 . fp - the file pointer 22 23 Level: developer 24 25 Note: 26 `NULL`, "stderr" or "stdout" may be passed in as the filename 27 28 .seealso: `PetscFClose()`, `PetscSynchronizedFGets()`, `PetscSynchronizedPrintf()`, `PetscSynchronizedFlush()`, 29 `PetscFPrintf()` 30 @*/ 31 PetscErrorCode PetscFOpen(MPI_Comm comm, const char name[], const char mode[], FILE **fp) 32 { 33 PetscMPIInt rank; 34 FILE *fd; 35 char fname[PETSC_MAX_PATH_LEN], tname[PETSC_MAX_PATH_LEN]; 36 37 PetscFunctionBegin; 38 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 39 if (rank == 0) { 40 PetscBool isstdout, isstderr; 41 PetscCall(PetscStrcmp(name, "stdout", &isstdout)); 42 PetscCall(PetscStrcmp(name, "stderr", &isstderr)); 43 if (isstdout || !name) fd = PETSC_STDOUT; 44 else if (isstderr) fd = PETSC_STDERR; 45 else { 46 PetscBool devnull = PETSC_FALSE; 47 PetscCall(PetscStrreplace(PETSC_COMM_SELF, name, tname, PETSC_MAX_PATH_LEN)); 48 PetscCall(PetscFixFilename(tname, fname)); 49 PetscCall(PetscStrbeginswith(fname, "/dev/null", &devnull)); 50 if (devnull) PetscCall(PetscStrncpy(fname, "/dev/null", sizeof(fname))); 51 PetscCall(PetscInfo(0, "Opening file %s\n", fname)); 52 fd = fopen(fname, mode); 53 PetscCheck(fd, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to open file %s", fname); 54 } 55 } else fd = NULL; 56 *fp = fd; 57 PetscFunctionReturn(PETSC_SUCCESS); 58 } 59 60 /*@C 61 PetscFClose - Has MPI rank 0 in the communicator close a 62 file (usually obtained with `PetscFOpen()`; all others do nothing. 63 64 Logically Collective; No Fortran Support 65 66 Input Parameters: 67 + comm - the MPI communicator 68 - fd - the file, opened with `PetscFOpen()` 69 70 Level: developer 71 72 .seealso: `PetscFOpen()` 73 @*/ 74 PetscErrorCode PetscFClose(MPI_Comm comm, FILE *fd) 75 { 76 PetscMPIInt rank; 77 int err; 78 79 PetscFunctionBegin; 80 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 81 if (rank == 0 && fd != PETSC_STDOUT && fd != PETSC_STDERR) { 82 err = fclose(fd); 83 PetscCheck(!err, PETSC_COMM_SELF, PETSC_ERR_SYS, "fclose() failed on file"); 84 } 85 PetscFunctionReturn(PETSC_SUCCESS); 86 } 87 88 #if defined(PETSC_HAVE_POPEN) 89 static char PetscPOpenMachine[128] = ""; 90 91 /*@C 92 PetscPClose - Closes (ends) a program on MPI rank 0 run with `PetscPOpen()` 93 94 Collective, but only MPI rank 0 does anything 95 96 Input Parameters: 97 + comm - MPI communicator, only rank 0 performs the close 98 - fd - the file pointer where program input or output may be read or `NULL` if don't care 99 100 Level: intermediate 101 102 Note: 103 Does not work under Microsoft Windows 104 105 .seealso: `PetscFOpen()`, `PetscFClose()`, `PetscPOpen()` 106 @*/ 107 PetscErrorCode PetscPClose(MPI_Comm comm, FILE *fd) 108 { 109 PetscMPIInt rank; 110 111 PetscFunctionBegin; 112 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 113 if (rank == 0) { 114 char buf[1024]; 115 while (fgets(buf, 1024, fd)); /* wait till it prints everything */ 116 (void)pclose(fd); 117 } 118 PetscFunctionReturn(PETSC_SUCCESS); 119 } 120 121 /*@C 122 PetscPOpen - Runs a program on MPI rank 0 and sends either its input or output to 123 a file. 124 125 Logically Collective, but only MPI rank 0 runs the command 126 127 Input Parameters: 128 + comm - MPI communicator, only processor zero runs the program 129 . machine - machine to run command on or `NULL`, or a string with 0 in first location 130 . program - name of program to run 131 - mode - either "r" or "w" 132 133 Output Parameter: 134 . fp - the file pointer where program input or output may be read or `NULL` if results are not needed 135 136 Level: intermediate 137 138 Notes: 139 Use `PetscPClose()` to close the file pointer when you are finished with it 140 141 Does not work under Microsoft Windows 142 143 If machine is not provided will use the value set with `PetsPOpenSetMachine()` if that was provided, otherwise 144 will use the machine running MPI rank 0 of the communicator 145 146 The program string may contain ${DISPLAY}, ${HOMEDIRECTORY} or ${WORKINGDIRECTORY}; these 147 will be replaced with relevant values. 148 149 .seealso: `PetscFOpen()`, `PetscFClose()`, `PetscPClose()`, `PetscPOpenSetMachine()` 150 @*/ 151 PetscErrorCode PetscPOpen(MPI_Comm comm, const char machine[], const char program[], const char mode[], FILE **fp) 152 { 153 PetscMPIInt rank; 154 size_t i, len, cnt; 155 char commandt[PETSC_MAX_PATH_LEN], command[PETSC_MAX_PATH_LEN]; 156 FILE *fd; 157 158 PetscFunctionBegin; 159 /* all processors have to do the string manipulation because PetscStrreplace() is a collective operation */ 160 if (PetscPOpenMachine[0] || (machine && machine[0])) { 161 PetscCall(PetscStrncpy(command, "ssh ", sizeof(command))); 162 if (PetscPOpenMachine[0]) { 163 PetscCall(PetscStrlcat(command, PetscPOpenMachine, sizeof(command))); 164 } else { 165 PetscCall(PetscStrlcat(command, machine, sizeof(command))); 166 } 167 PetscCall(PetscStrlcat(command, " \" export DISPLAY=${DISPLAY}; ", sizeof(command))); 168 /* 169 Copy program into command but protect the " with a \ in front of it 170 */ 171 PetscCall(PetscStrlen(command, &cnt)); 172 PetscCall(PetscStrlen(program, &len)); 173 for (i = 0; i < len; i++) { 174 if (program[i] == '\"') command[cnt++] = '\\'; 175 command[cnt++] = program[i]; 176 } 177 command[cnt] = 0; 178 179 PetscCall(PetscStrlcat(command, "\"", sizeof(command))); 180 } else { 181 PetscCall(PetscStrncpy(command, program, sizeof(command))); 182 } 183 184 PetscCall(PetscStrreplace(comm, command, commandt, 1024)); 185 186 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 187 if (rank == 0) { 188 PetscCall(PetscInfo(NULL, "Running command :%s\n", commandt)); 189 PetscCheck((fd = popen(commandt, mode)), PETSC_COMM_SELF, PETSC_ERR_LIB, "Cannot run command %s", commandt); 190 if (fp) *fp = fd; 191 } 192 PetscFunctionReturn(PETSC_SUCCESS); 193 } 194 195 /*@C 196 PetscPOpenSetMachine - Sets the name of the default machine to run `PetscPOpen()` calls on 197 198 Logically Collective, but only the MPI process with rank 0 runs the command 199 200 Input Parameter: 201 . machine - machine to run command on or `NULL` for the current machine 202 203 Options Database Key: 204 . -popen_machine <machine> - run the process on this machine 205 206 Level: intermediate 207 208 .seealso: `PetscFOpen()`, `PetscFClose()`, `PetscPClose()`, `PetscPOpen()` 209 @*/ 210 PetscErrorCode PetscPOpenSetMachine(const char machine[]) 211 { 212 PetscFunctionBegin; 213 if (machine) { 214 PetscCall(PetscStrncpy(PetscPOpenMachine, machine, sizeof(PetscPOpenMachine))); 215 } else { 216 PetscPOpenMachine[0] = 0; 217 } 218 PetscFunctionReturn(PETSC_SUCCESS); 219 } 220 221 #endif 222