1 2 /* 3 Code for opening and closing files. 4 */ 5 #include <petscsys.h> 6 #if defined(PETSC_HAVE_PWD_H) 7 #include <pwd.h> 8 #endif 9 #include <ctype.h> 10 #include <sys/stat.h> 11 #if defined(PETSC_HAVE_UNISTD_H) 12 #include <unistd.h> 13 #endif 14 #if defined(PETSC_HAVE_SYS_UTSNAME_H) 15 #include <sys/utsname.h> 16 #endif 17 #include <fcntl.h> 18 #include <time.h> 19 #if defined(PETSC_HAVE_SYS_SYSTEMINFO_H) 20 #include <sys/systeminfo.h> 21 #endif 22 23 /* 24 Private routine to delete tmp/shared storage 25 26 This is called by MPI, not by users. 27 28 Note: this is declared extern "C" because it is passed to MPI_Comm_create_keyval() 29 30 */ 31 PETSC_EXTERN PetscMPIInt MPIAPI Petsc_DelTmpShared(MPI_Comm comm,PetscMPIInt keyval,void *count_val,void *extra_state) 32 { 33 PetscFunctionBegin; 34 PetscCallMPI(PetscInfo(NULL,"Deleting tmp/shared data in an MPI_Comm %ld\n",(long)comm)); 35 PetscCallMPI(PetscFree(count_val)); 36 PetscFunctionReturn(MPI_SUCCESS); 37 } 38 39 /*@C 40 PetscGetTmp - Gets the name of the tmp directory 41 42 Collective 43 44 Input Parameters: 45 + comm - MPI_Communicator that may share /tmp 46 - len - length of string to hold name 47 48 Output Parameter: 49 . dir - directory name 50 51 Options Database Keys: 52 + -shared_tmp - indicates the directory is shared among the MPI ranks 53 . -not_shared_tmp - indicates the directory is not shared among the MPI ranks 54 - -tmp tmpdir - name of the directory you wish to use as /tmp 55 56 Environmental Variables: 57 + PETSC_SHARED_TMP - indicates the directory is shared among the MPI ranks 58 . PETSC_NOT_SHARED_TMP - indicates the directory is not shared among the MPI ranks 59 - PETSC_TMP - name of the directory you wish to use as /tmp 60 61 Level: developer 62 63 @*/ 64 PetscErrorCode PetscGetTmp(MPI_Comm comm,char dir[],size_t len) 65 { 66 PetscBool flg; 67 68 PetscFunctionBegin; 69 PetscCall(PetscOptionsGetenv(comm,"PETSC_TMP",dir,len,&flg)); 70 if (!flg) { 71 PetscCall(PetscStrncpy(dir,"/tmp",len)); 72 } 73 PetscFunctionReturn(0); 74 } 75 76 /*@C 77 PetscSharedTmp - Determines if all processors in a communicator share a 78 /tmp or have different ones. 79 80 Collective 81 82 Input Parameters: 83 . comm - MPI_Communicator that may share /tmp 84 85 Output Parameters: 86 . shared - PETSC_TRUE or PETSC_FALSE 87 88 Options Database Keys: 89 + -shared_tmp - indicates the directory is shared among the MPI ranks 90 . -not_shared_tmp - indicates the directory is not shared among the MPI ranks 91 - -tmp tmpdir - name of the directory you wish to use as /tmp 92 93 Environmental Variables: 94 + PETSC_SHARED_TMP - indicates the directory is shared among the MPI ranks 95 . PETSC_NOT_SHARED_TMP - indicates the directory is not shared among the MPI ranks 96 - PETSC_TMP - name of the directory you wish to use as /tmp 97 98 Level: developer 99 100 Notes: 101 Stores the status as a MPI attribute so it does not have 102 to be redetermined each time. 103 104 Assumes that all processors in a communicator either 105 1) have a common /tmp or 106 2) each has a separate /tmp 107 eventually we can write a fancier one that determines which processors 108 share a common /tmp. 109 110 This will be very slow on runs with a large number of processors since 111 it requires O(p*p) file opens. 112 113 If the environmental variable PETSC_TMP is set it will use this directory 114 as the "/tmp" directory. 115 116 @*/ 117 PetscErrorCode PetscSharedTmp(MPI_Comm comm,PetscBool *shared) 118 { 119 PetscMPIInt size,rank,*tagvalp,sum,cnt,i; 120 PetscBool flg,iflg; 121 FILE *fd; 122 static PetscMPIInt Petsc_Tmp_keyval = MPI_KEYVAL_INVALID; 123 int err; 124 125 PetscFunctionBegin; 126 PetscCallMPI(MPI_Comm_size(comm,&size)); 127 if (size == 1) { 128 *shared = PETSC_TRUE; 129 PetscFunctionReturn(0); 130 } 131 132 PetscCall(PetscOptionsGetenv(comm,"PETSC_SHARED_TMP",NULL,0,&flg)); 133 if (flg) { 134 *shared = PETSC_TRUE; 135 PetscFunctionReturn(0); 136 } 137 138 PetscCall(PetscOptionsGetenv(comm,"PETSC_NOT_SHARED_TMP",NULL,0,&flg)); 139 if (flg) { 140 *shared = PETSC_FALSE; 141 PetscFunctionReturn(0); 142 } 143 144 if (Petsc_Tmp_keyval == MPI_KEYVAL_INVALID) { 145 PetscCallMPI(MPI_Comm_create_keyval(MPI_COMM_NULL_COPY_FN,Petsc_DelTmpShared,&Petsc_Tmp_keyval,NULL)); 146 } 147 148 PetscCallMPI(MPI_Comm_get_attr(comm,Petsc_Tmp_keyval,(void**)&tagvalp,(int*)&iflg)); 149 if (!iflg) { 150 char filename[PETSC_MAX_PATH_LEN],tmpname[PETSC_MAX_PATH_LEN]; 151 152 /* This communicator does not yet have a shared tmp attribute */ 153 PetscCall(PetscMalloc1(1,&tagvalp)); 154 PetscCallMPI(MPI_Comm_set_attr(comm,Petsc_Tmp_keyval,tagvalp)); 155 156 PetscCall(PetscOptionsGetenv(comm,"PETSC_TMP",tmpname,238,&iflg)); 157 if (!iflg) { 158 PetscCall(PetscStrcpy(filename,"/tmp")); 159 } else { 160 PetscCall(PetscStrcpy(filename,tmpname)); 161 } 162 163 PetscCall(PetscStrcat(filename,"/petsctestshared")); 164 PetscCallMPI(MPI_Comm_rank(comm,&rank)); 165 166 /* each processor creates a /tmp file and all the later ones check */ 167 /* this makes sure no subset of processors is shared */ 168 *shared = PETSC_FALSE; 169 for (i=0; i<size-1; i++) { 170 if (rank == i) { 171 fd = fopen(filename,"w"); 172 PetscCheck(fd,PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Unable to open test file %s",filename); 173 err = fclose(fd); 174 PetscCheck(!err,PETSC_COMM_SELF,PETSC_ERR_SYS,"fclose() failed on file"); 175 } 176 PetscCallMPI(MPI_Barrier(comm)); 177 if (rank >= i) { 178 fd = fopen(filename,"r"); 179 if (fd) cnt = 1; 180 else cnt = 0; 181 if (fd) { 182 err = fclose(fd); 183 PetscCheck(!err,PETSC_COMM_SELF,PETSC_ERR_SYS,"fclose() failed on file"); 184 } 185 } else cnt = 0; 186 187 PetscCall(MPIU_Allreduce(&cnt,&sum,1,MPI_INT,MPI_SUM,comm)); 188 if (rank == i) unlink(filename); 189 190 if (sum == size) { 191 *shared = PETSC_TRUE; 192 break; 193 } else PetscCheck(sum == 1,PETSC_COMM_SELF,PETSC_ERR_SUP_SYS,"Subset of processes share /tmp "); 194 } 195 *tagvalp = (int)*shared; 196 PetscCall(PetscInfo(NULL,"processors %s %s\n",(*shared) ? "share":"do NOT share",(iflg ? tmpname:"/tmp"))); 197 } else *shared = (PetscBool) *tagvalp; 198 PetscFunctionReturn(0); 199 } 200 201 /*@C 202 PetscSharedWorkingDirectory - Determines if all processors in a communicator share a working directory or have different ones. 203 204 Collective 205 206 Input Parameter: 207 . comm - MPI_Communicator that may share working directory 208 209 Output Parameter: 210 . shared - PETSC_TRUE or PETSC_FALSE 211 212 Options Database Keys: 213 + -shared_working_directory - indicates the directory is shared among the MPI ranks 214 - -not_shared_working_directory - indicates the directory is shared among the MPI ranks 215 216 Environmental Variables: 217 + PETSC_SHARED_WORKING_DIRECTORY - indicates the directory is shared among the MPI ranks 218 - PETSC_NOT_SHARED_WORKING_DIRECTORY - indicates the directory is shared among the MPI ranks 219 220 Level: developer 221 222 Notes: 223 Stores the status as a MPI attribute so it does not have to be redetermined each time. 224 225 Assumes that all processors in a communicator either 226 $ 1) have a common working directory or 227 $ 2) each has a separate working directory 228 eventually we can write a fancier one that determines which processors share a common working directory. 229 230 This will be very slow on runs with a large number of processors since it requires O(p*p) file opens. 231 @*/ 232 PetscErrorCode PetscSharedWorkingDirectory(MPI_Comm comm, PetscBool *shared) 233 { 234 PetscMPIInt size,rank,*tagvalp,sum,cnt,i; 235 PetscBool flg,iflg; 236 FILE *fd; 237 static PetscMPIInt Petsc_WD_keyval = MPI_KEYVAL_INVALID; 238 int err; 239 240 PetscFunctionBegin; 241 PetscCallMPI(MPI_Comm_size(comm,&size)); 242 if (size == 1) { 243 *shared = PETSC_TRUE; 244 PetscFunctionReturn(0); 245 } 246 247 PetscCall(PetscOptionsGetenv(comm,"PETSC_SHARED_WORKING_DIRECTORY",NULL,0,&flg)); 248 if (flg) { 249 *shared = PETSC_TRUE; 250 PetscFunctionReturn(0); 251 } 252 253 PetscCall(PetscOptionsGetenv(comm,"PETSC_NOT_SHARED_WORKING_DIRECTORY",NULL,0,&flg)); 254 if (flg) { 255 *shared = PETSC_FALSE; 256 PetscFunctionReturn(0); 257 } 258 259 if (Petsc_WD_keyval == MPI_KEYVAL_INVALID) { 260 PetscCallMPI(MPI_Comm_create_keyval(MPI_COMM_NULL_COPY_FN,Petsc_DelTmpShared,&Petsc_WD_keyval,NULL)); 261 } 262 263 PetscCallMPI(MPI_Comm_get_attr(comm,Petsc_WD_keyval,(void**)&tagvalp,(int*)&iflg)); 264 if (!iflg) { 265 char filename[PETSC_MAX_PATH_LEN]; 266 267 /* This communicator does not yet have a shared attribute */ 268 PetscCall(PetscMalloc1(1,&tagvalp)); 269 PetscCallMPI(MPI_Comm_set_attr(comm,Petsc_WD_keyval,tagvalp)); 270 271 PetscCall(PetscGetWorkingDirectory(filename,240)); 272 PetscCall(PetscStrcat(filename,"/petsctestshared")); 273 PetscCallMPI(MPI_Comm_rank(comm,&rank)); 274 275 /* each processor creates a file and all the later ones check */ 276 /* this makes sure no subset of processors is shared */ 277 *shared = PETSC_FALSE; 278 for (i=0; i<size-1; i++) { 279 if (rank == i) { 280 fd = fopen(filename,"w"); 281 PetscCheck(fd,PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Unable to open test file %s",filename); 282 err = fclose(fd); 283 PetscCheck(!err,PETSC_COMM_SELF,PETSC_ERR_SYS,"fclose() failed on file"); 284 } 285 PetscCallMPI(MPI_Barrier(comm)); 286 if (rank >= i) { 287 fd = fopen(filename,"r"); 288 if (fd) cnt = 1; 289 else cnt = 0; 290 if (fd) { 291 err = fclose(fd); 292 PetscCheck(!err,PETSC_COMM_SELF,PETSC_ERR_SYS,"fclose() failed on file"); 293 } 294 } else cnt = 0; 295 296 PetscCall(MPIU_Allreduce(&cnt,&sum,1,MPI_INT,MPI_SUM,comm)); 297 if (rank == i) unlink(filename); 298 299 if (sum == size) { 300 *shared = PETSC_TRUE; 301 break; 302 } else PetscCheck(sum == 1,PETSC_COMM_SELF,PETSC_ERR_SUP_SYS,"Subset of processes share working directory"); 303 } 304 *tagvalp = (int)*shared; 305 } else *shared = (PetscBool) *tagvalp; 306 PetscCall(PetscInfo(NULL,"processors %s working directory\n",(*shared) ? "shared" : "do NOT share")); 307 PetscFunctionReturn(0); 308 } 309 310 /*@C 311 PetscFileRetrieve - Obtains a file from a URL or compressed 312 and copies into local disk space as uncompressed. 313 314 Collective 315 316 Input Parameters: 317 + comm - processors accessing the file 318 . url - name of file, including entire URL (with or without .gz) 319 - llen - length of localname 320 321 Output Parameters: 322 + localname - name of local copy of file - valid on only process zero 323 - found - if found or retrieved the file - valid on all processes 324 325 Notes: 326 if the file already exists local this function just returns without downloading it. 327 328 Level: intermediate 329 @*/ 330 PetscErrorCode PetscFileRetrieve(MPI_Comm comm,const char url[],char localname[],size_t llen,PetscBool *found) 331 { 332 char buffer[PETSC_MAX_PATH_LEN],*par,*tlocalname,name[PETSC_MAX_PATH_LEN]; 333 FILE *fp; 334 PetscMPIInt rank; 335 size_t len = 0; 336 PetscBool flg1,flg2,flg3,flg4,download,compressed = PETSC_FALSE; 337 338 PetscFunctionBegin; 339 PetscCallMPI(MPI_Comm_rank(comm,&rank)); 340 if (rank == 0) { 341 *found = PETSC_FALSE; 342 343 PetscCall(PetscStrstr(url,".gz",&par)); 344 if (par) { 345 PetscCall(PetscStrlen(par,&len)); 346 if (len == 3) compressed = PETSC_TRUE; 347 } 348 349 PetscCall(PetscStrncmp(url,"ftp://",6,&flg1)); 350 PetscCall(PetscStrncmp(url,"http://",7,&flg2)); 351 PetscCall(PetscStrncmp(url,"file://",7,&flg3)); 352 PetscCall(PetscStrncmp(url,"https://",8,&flg4)); 353 download = (PetscBool) (flg1 || flg2 || flg3 || flg4); 354 355 if (!download && !compressed) { 356 PetscCall(PetscStrncpy(localname,url,llen)); 357 PetscCall(PetscTestFile(url,'r',found)); 358 if (*found) { 359 PetscCall(PetscInfo(NULL,"Found file %s\n",url)); 360 } else { 361 PetscCall(PetscInfo(NULL,"Did not find file %s\n",url)); 362 } 363 goto done; 364 } 365 366 /* look for uncompressed file in requested directory */ 367 if (compressed) { 368 PetscCall(PetscStrncpy(localname,url,llen)); 369 PetscCall(PetscStrstr(localname,".gz",&par)); 370 *par = 0; /* remove .gz extension */ 371 PetscCall(PetscTestFile(localname,'r',found)); 372 if (*found) goto done; 373 } 374 375 /* look for file in current directory */ 376 PetscCall(PetscStrrchr(url,'/',&tlocalname)); 377 PetscCall(PetscStrncpy(localname,tlocalname,llen)); 378 if (compressed) { 379 PetscCall(PetscStrstr(localname,".gz",&par)); 380 *par = 0; /* remove .gz extension */ 381 } 382 PetscCall(PetscTestFile(localname,'r',found)); 383 if (*found) goto done; 384 385 if (download) { 386 /* local file is not already here so use curl to get it */ 387 PetscCall(PetscStrncpy(localname,tlocalname,llen)); 388 PetscCall(PetscStrcpy(buffer,"curl --fail --silent --show-error ")); 389 PetscCall(PetscStrcat(buffer,url)); 390 PetscCall(PetscStrcat(buffer," > ")); 391 PetscCall(PetscStrcat(buffer,localname)); 392 #if defined(PETSC_HAVE_POPEN) 393 PetscCall(PetscPOpen(PETSC_COMM_SELF,NULL,buffer,"r",&fp)); 394 PetscCall(PetscPClose(PETSC_COMM_SELF,fp)); 395 #else 396 SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP_SYS,"Cannot run external programs on this machine"); 397 #endif 398 PetscCall(PetscTestFile(localname,'r',found)); 399 if (*found) { 400 FILE *fd; 401 char buf[1024],*str,*substring; 402 403 /* check if the file didn't exist so it downloaded an HTML message instead */ 404 fd = fopen(localname,"r"); 405 PetscCheck(fd,PETSC_COMM_SELF,PETSC_ERR_PLIB,"PetscTestFile() indicates %s exists but fopen() cannot open it",localname); 406 str = fgets(buf,sizeof(buf)-1,fd); 407 while (str) { 408 PetscCall(PetscStrstr(buf,"<!DOCTYPE html>",&substring)); 409 PetscCheck(!substring,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unable to download %s it does not appear to exist at this URL, dummy HTML file was downloaded",url); 410 PetscCall(PetscStrstr(buf,"Not Found",&substring)); 411 PetscCheck(!substring,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unable to download %s it does not appear to exist at this URL, dummy HTML file was downloaded",url); 412 str = fgets(buf,sizeof(buf)-1,fd); 413 } 414 fclose(fd); 415 } 416 } else if (compressed) { 417 PetscCall(PetscTestFile(url,'r',found)); 418 if (!*found) goto done; 419 PetscCall(PetscStrncpy(localname,url,llen)); 420 } 421 if (compressed) { 422 PetscCall(PetscStrrchr(localname,'/',&tlocalname)); 423 PetscCall(PetscStrncpy(name,tlocalname,PETSC_MAX_PATH_LEN)); 424 PetscCall(PetscStrstr(name,".gz",&par)); 425 *par = 0; /* remove .gz extension */ 426 /* uncompress file */ 427 PetscCall(PetscStrcpy(buffer,"gzip -c -d ")); 428 PetscCall(PetscStrcat(buffer,localname)); 429 PetscCall(PetscStrcat(buffer," > ")); 430 PetscCall(PetscStrcat(buffer,name)); 431 #if defined(PETSC_HAVE_POPEN) 432 PetscCall(PetscPOpen(PETSC_COMM_SELF,NULL,buffer,"r",&fp)); 433 PetscCall(PetscPClose(PETSC_COMM_SELF,fp)); 434 #else 435 SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP_SYS,"Cannot run external programs on this machine"); 436 #endif 437 PetscCall(PetscStrncpy(localname,name,llen)); 438 PetscCall(PetscTestFile(localname,'r',found)); 439 } 440 } 441 done: 442 PetscCallMPI(MPI_Bcast(found,1,MPIU_BOOL,0,comm)); 443 PetscCallMPI(MPI_Bcast(localname, llen, MPI_CHAR, 0, comm)); 444 PetscFunctionReturn(0); 445 } 446