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 communicator open a file; 11 all others do nothing. 12 13 Logically Collective; No Fortran Support 14 15 Input Parameters: 16 + comm - the 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 the first processor in the communicator close a 62 file; all others do nothing. 63 64 Logically Collective; No Fortran Support 65 66 Input Parameters: 67 + comm - the 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 processor zero run with `PetscPOpen()` 93 94 Collective, but only MPI rank 0 runs the command 95 96 Input Parameters: 97 + comm - MPI communicator, only rank 0 runs the program 98 - fp - 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)) 116 ; /* wait till it prints everything */ 117 (void)pclose(fd); 118 } 119 PetscFunctionReturn(PETSC_SUCCESS); 120 } 121 122 /*@C 123 PetscPOpen - Runs a program on processor zero and sends either its input or output to 124 a file. 125 126 Logically Collective, but only MPI rank 0 runs the command 127 128 Input Parameters: 129 + comm - MPI communicator, only processor zero runs the program 130 . machine - machine to run command on or `NULL`, or string with 0 in first location 131 . program - name of program to run 132 - mode - either "r" or "w" 133 134 Output Parameter: 135 . fp - the file pointer where program input or output may be read or `NULL` if don't care 136 137 Level: intermediate 138 139 Notes: 140 Use `PetscPClose()` to close the file pointer when you are finished with it 141 142 Does not work under Microsoft Windows 143 144 If machine is not provided will use the value set with `PetsPOpenSetMachine()` if that was provided, otherwise 145 will use the machine running node zero of the communicator 146 147 The program string may contain ${DISPLAY}, ${HOMEDIRECTORY} or ${WORKINGDIRECTORY}; these 148 will be replaced with relevant values. 149 150 .seealso: `PetscFOpen()`, `PetscFClose()`, `PetscPClose()`, `PetscPOpenSetMachine()` 151 @*/ 152 PetscErrorCode PetscPOpen(MPI_Comm comm, const char machine[], const char program[], const char mode[], FILE **fp) 153 { 154 PetscMPIInt rank; 155 size_t i, len, cnt; 156 char commandt[PETSC_MAX_PATH_LEN], command[PETSC_MAX_PATH_LEN]; 157 FILE *fd; 158 159 PetscFunctionBegin; 160 /* all processors have to do the string manipulation because PetscStrreplace() is a collective operation */ 161 if (PetscPOpenMachine[0] || (machine && machine[0])) { 162 PetscCall(PetscStrncpy(command, "ssh ", sizeof(command))); 163 if (PetscPOpenMachine[0]) { 164 PetscCall(PetscStrlcat(command, PetscPOpenMachine, sizeof(command))); 165 } else { 166 PetscCall(PetscStrlcat(command, machine, sizeof(command))); 167 } 168 PetscCall(PetscStrlcat(command, " \" export DISPLAY=${DISPLAY}; ", sizeof(command))); 169 /* 170 Copy program into command but protect the " with a \ in front of it 171 */ 172 PetscCall(PetscStrlen(command, &cnt)); 173 PetscCall(PetscStrlen(program, &len)); 174 for (i = 0; i < len; i++) { 175 if (program[i] == '\"') command[cnt++] = '\\'; 176 command[cnt++] = program[i]; 177 } 178 command[cnt] = 0; 179 180 PetscCall(PetscStrlcat(command, "\"", sizeof(command))); 181 } else { 182 PetscCall(PetscStrncpy(command, program, sizeof(command))); 183 } 184 185 PetscCall(PetscStrreplace(comm, command, commandt, 1024)); 186 187 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 188 if (rank == 0) { 189 PetscCall(PetscInfo(NULL, "Running command :%s\n", commandt)); 190 PetscCheck((fd = popen(commandt, mode)), PETSC_COMM_SELF, PETSC_ERR_LIB, "Cannot run command %s", commandt); 191 if (fp) *fp = fd; 192 } 193 PetscFunctionReturn(PETSC_SUCCESS); 194 } 195 196 /*@C 197 PetscPOpenSetMachine - Sets the name of the default machine to run `PetscPOpen()` calls on 198 199 Logically Collective, but only MPI rank 0 runs the command 200 201 Input Parameter: 202 . machine - machine to run command on or `NULL` for the current machine 203 204 Options Database Key: 205 . -popen_machine <machine> - run the process on this machine 206 207 Level: intermediate 208 209 .seealso: `PetscFOpen()`, `PetscFClose()`, `PetscPClose()`, `PetscPOpen()` 210 @*/ 211 PetscErrorCode PetscPOpenSetMachine(const char machine[]) 212 { 213 PetscFunctionBegin; 214 if (machine) { 215 PetscCall(PetscStrncpy(PetscPOpenMachine, machine, sizeof(PetscPOpenMachine))); 216 } else { 217 PetscPOpenMachine[0] = 0; 218 } 219 PetscFunctionReturn(PETSC_SUCCESS); 220 } 221 222 #endif 223