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