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