1 /* -*- mode: C; c-basic-offset: 3; -*- */ 2 3 /*--------------------------------------------------------------------*/ 4 /*--- File- and socket-related libc stuff. m_libcfile.c ---*/ 5 /*--------------------------------------------------------------------*/ 6 7 /* 8 This file is part of Valgrind, a dynamic binary instrumentation 9 framework. 10 11 Copyright (C) 2000-2013 Julian Seward 12 jseward (at) acm.org 13 14 This program is free software; you can redistribute it and/or 15 modify it under the terms of the GNU General Public License as 16 published by the Free Software Foundation; either version 2 of the 17 License, or (at your option) any later version. 18 19 This program is distributed in the hope that it will be useful, but 20 WITHOUT ANY WARRANTY; without even the implied warranty of 21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 22 General Public License for more details. 23 24 You should have received a copy of the GNU General Public License 25 along with this program; if not, write to the Free Software 26 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 27 02111-1307, USA. 28 29 The GNU General Public License is contained in the file COPYING. 30 */ 31 32 #include "pub_core_basics.h" 33 #include "pub_core_vki.h" 34 #include "pub_core_vkiscnums.h" 35 #include "pub_core_debuglog.h" 36 #include "pub_core_libcbase.h" 37 #include "pub_core_libcassert.h" 38 #include "pub_core_libcfile.h" 39 #include "pub_core_libcprint.h" // VG_(sprintf) 40 #include "pub_core_libcproc.h" // VG_(getpid), VG_(getppid) 41 #include "pub_core_clientstate.h" // VG_(fd_hard_limit) 42 #include "pub_core_mallocfree.h" // VG_(realloc) 43 #include "pub_core_syscall.h" 44 45 /* IMPORTANT: on Darwin it is essential to use the _nocancel versions 46 of syscalls rather than the vanilla version, if a _nocancel version 47 is available. See docs/internals/Darwin-notes.txt for the reason 48 why. */ 49 50 /* --------------------------------------------------------------------- 51 File stuff 52 ------------------------------------------------------------------ */ 53 54 /* Move an fd into the Valgrind-safe range */ 55 Int VG_(safe_fd)(Int oldfd) 56 { 57 Int newfd; 58 59 vg_assert(VG_(fd_hard_limit) != -1); 60 61 newfd = VG_(fcntl)(oldfd, VKI_F_DUPFD, VG_(fd_hard_limit)); 62 if (newfd != -1) 63 VG_(close)(oldfd); 64 65 /* Set the close-on-exec flag for this fd. */ 66 VG_(fcntl)(newfd, VKI_F_SETFD, VKI_FD_CLOEXEC); 67 68 vg_assert(newfd >= VG_(fd_hard_limit)); 69 return newfd; 70 } 71 72 /* Given a file descriptor, attempt to deduce its filename. To do 73 this, we use /proc/self/fd/<FD>. If this doesn't point to a file, 74 or if it doesn't exist, we return False. 75 Upon successful completion *result contains the filename. The 76 filename will be overwritten with the next invocation so callers 77 need to copy the filename if needed. *result is NULL if the filename 78 cannot be deduced. */ 79 Bool VG_(resolve_filename) ( Int fd, const HChar** result ) 80 { 81 # if defined(VGO_linux) 82 static HChar *buf = NULL; 83 static SizeT bufsiz = 0; 84 85 if (buf == NULL) { // first time 86 bufsiz = 500; 87 buf = VG_(malloc)("resolve_filename", bufsiz); 88 } 89 90 HChar tmp[64]; // large enough 91 VG_(sprintf)(tmp, "/proc/self/fd/%d", fd); 92 93 while (42) { 94 SSizeT res = VG_(readlink)(tmp, buf, bufsiz); 95 if (res < 0) break; 96 if (res == bufsiz) { // buffer too small; increase and retry 97 bufsiz += 500; 98 buf = VG_(realloc)("resolve_filename", buf, bufsiz); 99 continue; 100 } 101 vg_assert(bufsiz > res); // paranoia 102 if (buf[0] != '/') break; 103 104 buf[res] = '\0'; 105 *result = buf; 106 return True; 107 } 108 // Failure 109 *result = NULL; 110 return False; 111 112 # elif defined(VGO_darwin) 113 HChar tmp[VKI_MAXPATHLEN+1]; 114 if (0 == VG_(fcntl)(fd, VKI_F_GETPATH, (UWord)tmp)) { 115 static HChar *buf = NULL; 116 117 if (buf == NULL) 118 buf = VG_(malloc)("resolve_filename", VKI_MAXPATHLEN+1); 119 VG_(strcpy)( buf, tmp ); 120 121 *result = buf; 122 if (buf[0] == '/') return True; 123 } 124 // Failure 125 *result = NULL; 126 return False; 127 128 # else 129 # error Unknown OS 130 # endif 131 } 132 133 SysRes VG_(mknod) ( const HChar* pathname, Int mode, UWord dev ) 134 { 135 # if defined(VGP_arm64_linux) || defined(VGP_tilegx_linux) 136 /* ARM64 wants to use __NR_mknodat rather than __NR_mknod. */ 137 SysRes res = VG_(do_syscall4)(__NR_mknodat, 138 VKI_AT_FDCWD, (UWord)pathname, mode, dev); 139 # elif defined(VGO_linux) || defined(VGO_darwin) 140 SysRes res = VG_(do_syscall3)(__NR_mknod, 141 (UWord)pathname, mode, dev); 142 # else 143 # error Unknown OS 144 # endif 145 return res; 146 } 147 148 SysRes VG_(open) ( const HChar* pathname, Int flags, Int mode ) 149 { 150 # if defined(VGP_arm64_linux) || defined(VGP_tilegx_linux) 151 /* ARM64 wants to use __NR_openat rather than __NR_open. */ 152 SysRes res = VG_(do_syscall4)(__NR_openat, 153 VKI_AT_FDCWD, (UWord)pathname, flags, mode); 154 # elif defined(VGO_linux) 155 SysRes res = VG_(do_syscall3)(__NR_open, 156 (UWord)pathname, flags, mode); 157 # elif defined(VGO_darwin) 158 SysRes res = VG_(do_syscall3)(__NR_open_nocancel, 159 (UWord)pathname, flags, mode); 160 # else 161 # error Unknown OS 162 # endif 163 return res; 164 } 165 166 Int VG_(fd_open) (const HChar* pathname, Int flags, Int mode) 167 { 168 SysRes sr; 169 sr = VG_(open) (pathname, flags, mode); 170 if (sr_isError (sr)) 171 return -1; 172 else 173 return sr_Res (sr); 174 } 175 176 void VG_(close) ( Int fd ) 177 { 178 /* Hmm. Return value is not checked. That's uncool. */ 179 # if defined(VGO_linux) 180 (void)VG_(do_syscall1)(__NR_close, fd); 181 # elif defined(VGO_darwin) 182 (void)VG_(do_syscall1)(__NR_close_nocancel, fd); 183 # else 184 # error Unknown OS 185 # endif 186 } 187 188 Int VG_(read) ( Int fd, void* buf, Int count) 189 { 190 Int ret; 191 # if defined(VGO_linux) 192 SysRes res = VG_(do_syscall3)(__NR_read, fd, (UWord)buf, count); 193 # elif defined(VGO_darwin) 194 SysRes res = VG_(do_syscall3)(__NR_read_nocancel, fd, (UWord)buf, count); 195 # else 196 # error Unknown OS 197 # endif 198 if (sr_isError(res)) { 199 ret = - (Int)(Word)sr_Err(res); 200 vg_assert(ret < 0); 201 } else { 202 ret = (Int)(Word)sr_Res(res); 203 vg_assert(ret >= 0); 204 } 205 return ret; 206 } 207 208 Int VG_(write) ( Int fd, const void* buf, Int count) 209 { 210 Int ret; 211 # if defined(VGO_linux) 212 SysRes res = VG_(do_syscall3)(__NR_write, fd, (UWord)buf, count); 213 # elif defined(VGO_darwin) 214 SysRes res = VG_(do_syscall3)(__NR_write_nocancel, fd, (UWord)buf, count); 215 # else 216 # error "Unknown OS" 217 # endif 218 if (sr_isError(res)) { 219 ret = - (Int)(Word)sr_Err(res); 220 vg_assert(ret < 0); 221 } else { 222 ret = (Int)(Word)sr_Res(res); 223 vg_assert(ret >= 0); 224 } 225 return ret; 226 } 227 228 229 Int VG_(pipe) ( Int fd[2] ) 230 { 231 # if defined(VGP_mips32_linux) || defined(VGP_mips64_linux) 232 /* __NR_pipe has a strange return convention on mips32-linux. */ 233 SysRes res = VG_(do_syscall1)(__NR_pipe, (UWord)fd); 234 if (!sr_isError(res)) { 235 fd[0] = (Int)sr_Res(res); 236 fd[1] = (Int)sr_ResEx(res); 237 return 0; 238 } else { 239 return -1; 240 } 241 # elif defined(VGP_arm64_linux) || defined(VGP_tilegx_linux) 242 SysRes res = VG_(do_syscall2)(__NR_pipe2, (UWord)fd, 0); 243 return sr_isError(res) ? -1 : 0; 244 # elif defined(VGO_linux) 245 SysRes res = VG_(do_syscall1)(__NR_pipe, (UWord)fd); 246 return sr_isError(res) ? -1 : 0; 247 # elif defined(VGO_darwin) 248 /* __NR_pipe is UX64, so produces a double-word result */ 249 SysRes res = VG_(do_syscall0)(__NR_pipe); 250 if (!sr_isError(res)) { 251 fd[0] = (Int)sr_Res(res); 252 fd[1] = (Int)sr_ResHI(res); 253 } 254 return sr_isError(res) ? -1 : 0; 255 # else 256 # error "Unknown OS" 257 # endif 258 } 259 260 Off64T VG_(lseek) ( Int fd, Off64T offset, Int whence ) 261 { 262 # if defined(VGO_linux) || defined(VGP_amd64_darwin) 263 # if defined(__NR__llseek) 264 Off64T result; 265 SysRes res = VG_(do_syscall5)(__NR__llseek, fd, 266 offset >> 32, offset & 0xffffffff, 267 (UWord)&result, whence); 268 return sr_isError(res) ? (-1) : result; 269 # else 270 SysRes res = VG_(do_syscall3)(__NR_lseek, fd, offset, whence); 271 vg_assert(sizeof(Off64T) == sizeof(Word)); 272 return sr_isError(res) ? (-1) : sr_Res(res); 273 # endif 274 # elif defined(VGP_x86_darwin) 275 SysRes res = VG_(do_syscall4)(__NR_lseek, fd, 276 offset & 0xffffffff, offset >> 32, whence); 277 return sr_isError(res) ? (-1) : sr_Res(res); 278 # else 279 # error "Unknown plat" 280 # endif 281 /* if you change the error-reporting conventions of this, also 282 change all usage points. */ 283 } 284 285 286 /* stat/fstat support. It's uggerly. We have impedance-match into a 287 'struct vg_stat' in order to have a single structure that callers 288 can use consistently on all platforms. */ 289 290 #define TRANSLATE_TO_vg_stat(_p_vgstat, _p_vkistat) \ 291 do { \ 292 (_p_vgstat)->dev = (ULong)( (_p_vkistat)->st_dev ); \ 293 (_p_vgstat)->ino = (ULong)( (_p_vkistat)->st_ino ); \ 294 (_p_vgstat)->nlink = (ULong)( (_p_vkistat)->st_nlink ); \ 295 (_p_vgstat)->mode = (UInt) ( (_p_vkistat)->st_mode ); \ 296 (_p_vgstat)->uid = (UInt) ( (_p_vkistat)->st_uid ); \ 297 (_p_vgstat)->gid = (UInt) ( (_p_vkistat)->st_gid ); \ 298 (_p_vgstat)->rdev = (ULong)( (_p_vkistat)->st_rdev ); \ 299 (_p_vgstat)->size = (Long) ( (_p_vkistat)->st_size ); \ 300 (_p_vgstat)->blksize = (ULong)( (_p_vkistat)->st_blksize ); \ 301 (_p_vgstat)->blocks = (ULong)( (_p_vkistat)->st_blocks ); \ 302 (_p_vgstat)->atime = (ULong)( (_p_vkistat)->st_atime ); \ 303 (_p_vgstat)->atime_nsec = (ULong)( (_p_vkistat)->st_atime_nsec ); \ 304 (_p_vgstat)->mtime = (ULong)( (_p_vkistat)->st_mtime ); \ 305 (_p_vgstat)->mtime_nsec = (ULong)( (_p_vkistat)->st_mtime_nsec ); \ 306 (_p_vgstat)->ctime = (ULong)( (_p_vkistat)->st_ctime ); \ 307 (_p_vgstat)->ctime_nsec = (ULong)( (_p_vkistat)->st_ctime_nsec ); \ 308 } while (0) 309 310 SysRes VG_(stat) ( const HChar* file_name, struct vg_stat* vgbuf ) 311 { 312 SysRes res; 313 VG_(memset)(vgbuf, 0, sizeof(*vgbuf)); 314 315 # if defined(VGO_linux) || defined(VGO_darwin) 316 /* First try with stat64. If that doesn't work out, fall back to 317 the vanilla version. */ 318 # if defined(__NR_stat64) 319 { struct vki_stat64 buf64; 320 res = VG_(do_syscall2)(__NR_stat64, (UWord)file_name, (UWord)&buf64); 321 if (!(sr_isError(res) && sr_Err(res) == VKI_ENOSYS)) { 322 /* Success, or any failure except ENOSYS */ 323 if (!sr_isError(res)) 324 TRANSLATE_TO_vg_stat(vgbuf, &buf64); 325 return res; 326 } 327 } 328 # endif /* defined(__NR_stat64) */ 329 /* This is the fallback ("vanilla version"). */ 330 { struct vki_stat buf; 331 # if defined(VGP_arm64_linux) || defined(VGP_tilegx_linux) 332 res = VG_(do_syscall3)(__NR3264_fstatat, VKI_AT_FDCWD, 333 (UWord)file_name, (UWord)&buf); 334 # else 335 res = VG_(do_syscall2)(__NR_stat, (UWord)file_name, (UWord)&buf); 336 # endif 337 if (!sr_isError(res)) 338 TRANSLATE_TO_vg_stat(vgbuf, &buf); 339 return res; 340 } 341 342 # else 343 # error Unknown OS 344 # endif 345 } 346 347 Int VG_(fstat) ( Int fd, struct vg_stat* vgbuf ) 348 { 349 SysRes res; 350 VG_(memset)(vgbuf, 0, sizeof(*vgbuf)); 351 352 # if defined(VGO_linux) || defined(VGO_darwin) 353 /* First try with fstat64. If that doesn't work out, fall back to 354 the vanilla version. */ 355 # if defined(__NR_fstat64) 356 { struct vki_stat64 buf64; 357 res = VG_(do_syscall2)(__NR_fstat64, (UWord)fd, (UWord)&buf64); 358 if (!(sr_isError(res) && sr_Err(res) == VKI_ENOSYS)) { 359 /* Success, or any failure except ENOSYS */ 360 if (!sr_isError(res)) 361 TRANSLATE_TO_vg_stat(vgbuf, &buf64); 362 return sr_isError(res) ? (-1) : 0; 363 } 364 } 365 # endif /* if defined(__NR_fstat64) */ 366 { struct vki_stat buf; 367 res = VG_(do_syscall2)(__NR_fstat, (UWord)fd, (UWord)&buf); 368 if (!sr_isError(res)) 369 TRANSLATE_TO_vg_stat(vgbuf, &buf); 370 return sr_isError(res) ? (-1) : 0; 371 } 372 373 # else 374 # error Unknown OS 375 # endif 376 } 377 378 #undef TRANSLATE_TO_vg_stat 379 380 381 Long VG_(fsize) ( Int fd ) 382 { 383 struct vg_stat buf; 384 Int res = VG_(fstat)( fd, &buf ); 385 return (res == -1) ? (-1LL) : buf.size; 386 } 387 388 SysRes VG_(getxattr) ( const HChar* file_name, const HChar* attr_name, Addr attr_value, SizeT attr_value_len ) 389 { 390 SysRes res; 391 #if defined(VGO_linux) 392 res = VG_(do_syscall4)(__NR_getxattr, (UWord)file_name, (UWord)attr_name, 393 attr_value, attr_value_len); 394 #else 395 res = VG_(mk_SysRes_Error)(VKI_ENOSYS); 396 #endif 397 return res; 398 } 399 400 Bool VG_(is_dir) ( const HChar* f ) 401 { 402 struct vg_stat buf; 403 SysRes res = VG_(stat)(f, &buf); 404 return sr_isError(res) ? False 405 : VKI_S_ISDIR(buf.mode) ? True : False; 406 } 407 408 SysRes VG_(dup) ( Int oldfd ) 409 { 410 return VG_(do_syscall1)(__NR_dup, oldfd); 411 } 412 413 SysRes VG_(dup2) ( Int oldfd, Int newfd ) 414 { 415 # if defined(VGO_linux) || defined(VGO_darwin) 416 return VG_(do_syscall2)(__NR_dup2, oldfd, newfd); 417 # else 418 # error Unknown OS 419 # endif 420 } 421 422 /* Returns -1 on error. */ 423 Int VG_(fcntl) ( Int fd, Int cmd, Addr arg ) 424 { 425 # if defined(VGO_linux) 426 SysRes res = VG_(do_syscall3)(__NR_fcntl, fd, cmd, arg); 427 # elif defined(VGO_darwin) 428 SysRes res = VG_(do_syscall3)(__NR_fcntl_nocancel, fd, cmd, arg); 429 # else 430 # error "Unknown OS" 431 # endif 432 return sr_isError(res) ? -1 : sr_Res(res); 433 } 434 435 Int VG_(rename) ( const HChar* old_name, const HChar* new_name ) 436 { 437 # if defined(VGP_tilegx_linux) 438 SysRes res = VG_(do_syscall3)(__NR_renameat, VKI_AT_FDCWD, 439 (UWord)old_name, (UWord)new_name); 440 # else 441 SysRes res = VG_(do_syscall2)(__NR_rename, (UWord)old_name, (UWord)new_name); 442 # endif 443 return sr_isError(res) ? (-1) : 0; 444 } 445 446 Int VG_(unlink) ( const HChar* file_name ) 447 { 448 # if defined(VGP_arm64_linux) || defined(VGP_tilegx_linux) 449 SysRes res = VG_(do_syscall2)(__NR_unlinkat, VKI_AT_FDCWD, 450 (UWord)file_name); 451 # else 452 SysRes res = VG_(do_syscall1)(__NR_unlink, (UWord)file_name); 453 # endif 454 return sr_isError(res) ? (-1) : 0; 455 } 456 457 /* The working directory at startup. 458 All that is really needed is to note the cwd at process startup. 459 Hence VG_(record_startup_wd) notes it (in a platform dependent way) 460 and VG_(get_startup_wd) produces the noted value. */ 461 static HChar *startup_wd; 462 static Bool startup_wd_acquired = False; 463 464 /* Record the process' working directory at startup. Is intended to 465 be called exactly once, at startup, before the working directory 466 changes. Return True for success, False for failure, so that the 467 caller can bomb out suitably without creating module cycles if 468 there is a problem. */ 469 Bool VG_(record_startup_wd) ( void ) 470 { 471 vg_assert(!startup_wd_acquired); 472 473 # if defined(VGO_linux) 474 /* Simple: just ask the kernel */ 475 SysRes res; 476 SizeT szB = 0; 477 do { 478 szB += 500; 479 startup_wd = VG_(realloc)("startup_wd", startup_wd, szB); 480 VG_(memset)(startup_wd, 0, szB); 481 res = VG_(do_syscall2)(__NR_getcwd, (UWord)startup_wd, szB-1); 482 } while (sr_isError(res)); 483 484 vg_assert(startup_wd[szB-1] == 0); 485 startup_wd_acquired = True; 486 return True; 487 488 # elif defined(VGO_darwin) 489 /* We can't ask the kernel, so instead rely on launcher-*.c to 490 tell us the startup path. Note the env var is keyed to the 491 parent's PID, not ours, since our parent is the launcher 492 process. */ 493 { HChar envvar[100]; // large enough 494 HChar* wd; 495 VG_(memset)(envvar, 0, sizeof(envvar)); 496 VG_(sprintf)(envvar, "VALGRIND_STARTUP_PWD_%d_XYZZY", 497 (Int)VG_(getppid)()); 498 wd = VG_(getenv)( envvar ); 499 if (wd == NULL) 500 return False; 501 SizeT need = VG_(strlen)(wd) + 1; 502 startup_wd = VG_(malloc)("startup_wd", need); 503 VG_(strcpy)(startup_wd, wd); 504 startup_wd_acquired = True; 505 return True; 506 } 507 # else 508 # error Unknown OS 509 # endif 510 } 511 512 /* Return the previously acquired startup_wd. */ 513 const HChar *VG_(get_startup_wd) ( void ) 514 { 515 vg_assert(startup_wd_acquired); 516 517 return startup_wd; 518 } 519 520 SysRes VG_(poll) (struct vki_pollfd *fds, Int nfds, Int timeout) 521 { 522 SysRes res; 523 # if defined(VGP_arm64_linux) || defined(VGP_tilegx_linux) 524 /* ARM64 wants to use __NR_ppoll rather than __NR_poll. */ 525 struct vki_timespec timeout_ts; 526 if (timeout >= 0) { 527 timeout_ts.tv_sec = timeout / 1000; 528 timeout_ts.tv_nsec = ((long)timeout % 1000) * 1000000; 529 } 530 res = VG_(do_syscall4)(__NR_ppoll, 531 (UWord)fds, nfds, 532 (UWord)(timeout >= 0 ? &timeout_ts : NULL), 533 (UWord)NULL); 534 # elif defined(VGO_linux) 535 res = VG_(do_syscall3)(__NR_poll, (UWord)fds, nfds, timeout); 536 # elif defined(VGO_darwin) 537 res = VG_(do_syscall3)(__NR_poll_nocancel, (UWord)fds, nfds, timeout); 538 # else 539 # error "Unknown OS" 540 # endif 541 return res; 542 } 543 544 545 /* Performs the readlink operation and puts the result into 'buf'. 546 Note, that the string in 'buf' is *not* null-terminated. The function 547 returns the number of characters put into 'buf' or -1 if an error 548 occurred. */ 549 SSizeT VG_(readlink) (const HChar* path, HChar* buf, SizeT bufsiz) 550 { 551 SysRes res; 552 /* res = readlink( path, buf, bufsiz ); */ 553 # if defined(VGP_arm64_linux) || defined(VGP_tilegx_linux) 554 res = VG_(do_syscall4)(__NR_readlinkat, VKI_AT_FDCWD, 555 (UWord)path, (UWord)buf, bufsiz); 556 # else 557 res = VG_(do_syscall3)(__NR_readlink, (UWord)path, (UWord)buf, bufsiz); 558 # endif 559 return sr_isError(res) ? -1 : sr_Res(res); 560 } 561 562 #if defined(VGO_linux) 563 Int VG_(getdents64) (Int fd, struct vki_dirent64 *dirp, UInt count) 564 { 565 SysRes res; 566 /* res = getdents( fd, dirp, count ); */ 567 res = VG_(do_syscall3)(__NR_getdents64, fd, (UWord)dirp, count); 568 return sr_isError(res) ? -1 : sr_Res(res); 569 } 570 #endif 571 572 /* Check accessibility of a file. Returns zero for access granted, 573 nonzero otherwise. */ 574 Int VG_(access) ( const HChar* path, Bool irusr, Bool iwusr, Bool ixusr ) 575 { 576 # if defined(VGO_linux) 577 /* Very annoyingly, I cannot find any definition for R_OK et al in 578 the kernel interfaces. Therefore I reluctantly resort to 579 hardwiring in these magic numbers that I determined by 580 experimentation. */ 581 # define VKI_R_OK 4 582 # define VKI_W_OK 2 583 # define VKI_X_OK 1 584 # endif 585 586 UWord w = (irusr ? VKI_R_OK : 0) 587 | (iwusr ? VKI_W_OK : 0) 588 | (ixusr ? VKI_X_OK : 0); 589 # if defined(VGP_arm64_linux) || defined(VGP_tilegx_linux) 590 SysRes res = VG_(do_syscall3)(__NR_faccessat, VKI_AT_FDCWD, (UWord)path, w); 591 # else 592 SysRes res = VG_(do_syscall2)(__NR_access, (UWord)path, w); 593 # endif 594 return sr_isError(res) ? 1 : 0; 595 596 # if defined(VGO_linux) 597 # undef VKI_R_OK 598 # undef VKI_W_OK 599 # undef VKI_X_OK 600 # endif 601 } 602 603 /* 604 Emulate the normal Unix permissions checking algorithm. 605 606 If owner matches, then use the owner permissions, else 607 if group matches, then use the group permissions, else 608 use other permissions. 609 610 Note that we can't deal properly with SUID/SGID. By default 611 (allow_setuid == False), we refuse to run them (otherwise the 612 executable may misbehave if it doesn't have the permissions it 613 thinks it does). However, the caller may indicate that setuid 614 executables are allowed, for example if we are going to exec them 615 but not trace into them (iow, client sys_execve when 616 clo_trace_children == False). 617 618 If VKI_EACCES is returned (iow, permission was refused), then 619 *is_setuid is set to True iff permission was refused because the 620 executable is setuid. 621 */ 622 /* returns: 0 = success, non-0 is failure */ 623 Int VG_(check_executable)(/*OUT*/Bool* is_setuid, 624 const HChar* f, Bool allow_setuid) 625 { 626 struct vg_stat st; 627 SysRes res = VG_(stat)(f, &st); 628 629 if (is_setuid) 630 *is_setuid = False; 631 632 if (sr_isError(res)) { 633 return sr_Err(res); 634 } 635 636 if ( VKI_S_ISDIR (st.mode) ) { 637 return VKI_EACCES; 638 } 639 640 if ( (st.mode & (VKI_S_ISUID | VKI_S_ISGID)) && !allow_setuid ) { 641 if (is_setuid) 642 *is_setuid = True; 643 return VKI_EACCES; 644 } 645 646 res = VG_(getxattr)(f, "security.capability", (Addr)0, 0); 647 if (!sr_isError(res) && !allow_setuid) { 648 if (is_setuid) 649 *is_setuid = True; 650 return VKI_EACCES; 651 } 652 653 if (VG_(geteuid)() == st.uid) { 654 if (!(st.mode & VKI_S_IXUSR)) 655 return VKI_EACCES; 656 } else { 657 Int grpmatch = 0; 658 659 if (VG_(getegid)() == st.gid) 660 grpmatch = 1; 661 else { 662 UInt *groups = NULL; 663 Int ngrp; 664 665 /* Find out # groups, allocate large enough array and fetch groups */ 666 ngrp = VG_(getgroups)(0, NULL); 667 if (ngrp != -1) { 668 groups = VG_(malloc)("check_executable", ngrp * sizeof *groups); 669 ngrp = VG_(getgroups)(ngrp, groups); 670 } 671 672 Int i; 673 /* ngrp will be -1 if VG_(getgroups) failed. */ 674 for (i = 0; i < ngrp; i++) { 675 if (groups[i] == st.gid) { 676 grpmatch = 1; 677 break; 678 } 679 } 680 VG_(free)(groups); 681 } 682 683 if (grpmatch) { 684 if (!(st.mode & VKI_S_IXGRP)) { 685 return VKI_EACCES; 686 } 687 } else if (!(st.mode & VKI_S_IXOTH)) { 688 return VKI_EACCES; 689 } 690 } 691 692 return 0; 693 } 694 695 SysRes VG_(pread) ( Int fd, void* buf, Int count, OffT offset ) 696 { 697 SysRes res; 698 // on 32 bits platforms, we receive a 32 bits OffT but 699 // we must extend it to pass a long long 64 bits. 700 # if defined(VGP_x86_linux) 701 vg_assert(sizeof(OffT) == 4); 702 res = VG_(do_syscall5)(__NR_pread64, fd, (UWord)buf, count, 703 offset, 0); // Little endian long long 704 return res; 705 # elif defined(VGP_arm_linux) 706 vg_assert(sizeof(OffT) == 4); 707 res = VG_(do_syscall5)(__NR_pread64, fd, (UWord)buf, count, 708 0, offset); // Big endian long long 709 return res; 710 # elif defined(VGP_ppc32_linux) 711 vg_assert(sizeof(OffT) == 4); 712 res = VG_(do_syscall6)(__NR_pread64, fd, (UWord)buf, count, 713 0, // Padding needed on PPC32 714 0, offset); // Big endian long long 715 return res; 716 # elif defined(VGP_mips32_linux) && (VKI_LITTLE_ENDIAN) 717 vg_assert(sizeof(OffT) == 4); 718 res = VG_(do_syscall6)(__NR_pread64, fd, (UWord)buf, count, 719 0, offset, 0); 720 return res; 721 # elif defined(VGP_mips32_linux) && (VKI_BIG_ENDIAN) 722 vg_assert(sizeof(OffT) == 4); 723 res = VG_(do_syscall6)(__NR_pread64, fd, (UWord)buf, count, 724 0, 0, offset); 725 return res; 726 # elif defined(VGP_amd64_linux) || defined(VGP_s390x_linux) \ 727 || defined(VGP_ppc64be_linux) || defined(VGP_ppc64le_linux) \ 728 || defined(VGP_mips64_linux) \ 729 || defined(VGP_arm64_linux) || defined(VGP_tilegx_linux) 730 res = VG_(do_syscall4)(__NR_pread64, fd, (UWord)buf, count, offset); 731 return res; 732 # elif defined(VGP_amd64_darwin) 733 vg_assert(sizeof(OffT) == 8); 734 res = VG_(do_syscall4)(__NR_pread_nocancel, fd, (UWord)buf, count, offset); 735 return res; 736 # elif defined(VGP_x86_darwin) 737 vg_assert(sizeof(OffT) == 8); 738 res = VG_(do_syscall5)(__NR_pread_nocancel, fd, (UWord)buf, count, 739 offset & 0xffffffff, offset >> 32); 740 return res; 741 # else 742 # error "Unknown platform" 743 # endif 744 } 745 746 /* Return the name of a directory for temporary files. */ 747 const HChar *VG_(tmpdir)(void) 748 { 749 const HChar *tmpdir; 750 751 tmpdir = VG_(getenv)("TMPDIR"); 752 if (tmpdir == NULL || *tmpdir == '\0') tmpdir = VG_TMPDIR; 753 if (tmpdir == NULL || *tmpdir == '\0') tmpdir = "/tmp"; /* fallback */ 754 755 return tmpdir; 756 } 757 758 static const HChar mkstemp_format[] = "%s/valgrind_%s_%08x"; 759 760 SizeT VG_(mkstemp_fullname_bufsz) ( SizeT part_of_name_len ) 761 { 762 return VG_(strlen)(mkstemp_format) 763 + VG_(strlen)(VG_(tmpdir)()) - 2 // %s tmpdir 764 + part_of_name_len - 2 // %s part_of_name 765 + 8 - 4 // %08x 766 + 1; // trailing 0 767 } 768 769 770 Int VG_(mkstemp) ( const HChar* part_of_name, /*OUT*/HChar* fullname ) 771 { 772 Int n, tries; 773 UInt seed; 774 SysRes sres; 775 const HChar *tmpdir; 776 777 vg_assert(part_of_name); 778 vg_assert(fullname); 779 n = VG_(strlen)(part_of_name); 780 vg_assert(n > 0 && n < 100); 781 782 seed = (VG_(getpid)() << 9) ^ VG_(getppid)(); 783 784 /* Determine sensible location for temporary files */ 785 tmpdir = VG_(tmpdir)(); 786 787 tries = 0; 788 while (True) { 789 if (tries++ > 10) 790 return -1; 791 VG_(sprintf)( fullname, mkstemp_format, 792 tmpdir, part_of_name, VG_(random)( &seed )); 793 if (0) 794 VG_(printf)("VG_(mkstemp): trying: %s\n", fullname); 795 796 sres = VG_(open)(fullname, 797 VKI_O_CREAT|VKI_O_RDWR|VKI_O_EXCL|VKI_O_TRUNC, 798 VKI_S_IRUSR|VKI_S_IWUSR); 799 if (sr_isError(sres)) { 800 VG_(umsg)("VG_(mkstemp): failed to create temp file: %s\n", fullname); 801 continue; 802 } 803 /* VG_(safe_fd) doesn't return if it fails. */ 804 return VG_(safe_fd)( sr_Res(sres) ); 805 } 806 /* NOTREACHED */ 807 } 808 809 810 /* --------------------------------------------------------------------- 811 Socket-related stuff. 812 ------------------------------------------------------------------ */ 813 814 static 815 Int parse_inet_addr_and_port ( const HChar* str, UInt* ip_addr, UShort* port ); 816 817 static 818 Int my_connect ( Int sockfd, struct vki_sockaddr_in* serv_addr, Int addrlen ); 819 820 UInt VG_(htonl) ( UInt x ) 821 { 822 # if defined(VG_BIGENDIAN) 823 return x; 824 # else 825 return 826 (((x >> 24) & 0xFF) << 0) | (((x >> 16) & 0xFF) << 8) 827 | (((x >> 8) & 0xFF) << 16) | (((x >> 0) & 0xFF) << 24); 828 # endif 829 } 830 831 UInt VG_(ntohl) ( UInt x ) 832 { 833 # if defined(VG_BIGENDIAN) 834 return x; 835 # else 836 return 837 (((x >> 24) & 0xFF) << 0) | (((x >> 16) & 0xFF) << 8) 838 | (((x >> 8) & 0xFF) << 16) | (((x >> 0) & 0xFF) << 24); 839 # endif 840 } 841 842 UShort VG_(htons) ( UShort x ) 843 { 844 # if defined(VG_BIGENDIAN) 845 return x; 846 # else 847 return 848 (((x >> 8) & 0xFF) << 0) | (((x >> 0) & 0xFF) << 8); 849 # endif 850 } 851 852 UShort VG_(ntohs) ( UShort x ) 853 { 854 # if defined(VG_BIGENDIAN) 855 return x; 856 # else 857 return 858 (((x >> 8) & 0xFF) << 0) | (((x >> 0) & 0xFF) << 8); 859 # endif 860 } 861 862 863 /* The main function. 864 865 Supplied string contains either an ip address "192.168.0.1" or 866 an ip address and port pair, "192.168.0.1:1500". Parse these, 867 and return: 868 -1 if there is a parse error 869 -2 if no parse error, but specified host:port cannot be opened 870 the relevant file (socket) descriptor, otherwise. 871 is used. 872 */ 873 Int VG_(connect_via_socket)( const HChar* str ) 874 { 875 # if defined(VGO_linux) || defined(VGO_darwin) 876 Int sd, res; 877 struct vki_sockaddr_in servAddr; 878 UInt ip = 0; 879 UShort port = VG_CLO_DEFAULT_LOGPORT; 880 Bool ok = parse_inet_addr_and_port(str, &ip, &port); 881 if (!ok) 882 return -1; 883 884 //if (0) 885 // VG_(printf)("ip = %d.%d.%d.%d, port %d\n", 886 // (ip >> 24) & 0xFF, (ip >> 16) & 0xFF, 887 // (ip >> 8) & 0xFF, ip & 0xFF, 888 // (UInt)port ); 889 890 servAddr.sin_family = VKI_AF_INET; 891 servAddr.sin_addr.s_addr = VG_(htonl)(ip); 892 servAddr.sin_port = VG_(htons)(port); 893 894 /* create socket */ 895 sd = VG_(socket)(VKI_AF_INET, VKI_SOCK_STREAM, 0 /* IPPROTO_IP ? */); 896 if (sd < 0) { 897 /* this shouldn't happen ... nevertheless */ 898 return -2; 899 } 900 901 /* connect to server */ 902 res = my_connect(sd, &servAddr, sizeof(servAddr)); 903 if (res < 0) { 904 /* connection failed */ 905 return -2; 906 } 907 908 return sd; 909 910 # else 911 # error "Unknown OS" 912 # endif 913 } 914 915 916 /* Let d = one or more digits. Accept either: 917 d.d.d.d or d.d.d.d:d 918 */ 919 static Int parse_inet_addr_and_port ( const HChar* str, UInt* ip_addr, UShort* port ) 920 { 921 # define GET_CH ((*str) ? (*str++) : 0) 922 UInt ipa, i, j, c, any; 923 ipa = 0; 924 for (i = 0; i < 4; i++) { 925 j = 0; 926 any = 0; 927 while (1) { 928 c = GET_CH; 929 if (c < '0' || c > '9') break; 930 j = 10 * j + (int)(c - '0'); 931 any = 1; 932 } 933 if (any == 0 || j > 255) goto syntaxerr; 934 ipa = (ipa << 8) + j; 935 if (i <= 2 && c != '.') goto syntaxerr; 936 } 937 if (c == 0 || c == ':') 938 *ip_addr = ipa; 939 if (c == 0) goto ok; 940 if (c != ':') goto syntaxerr; 941 j = 0; 942 any = 0; 943 while (1) { 944 c = GET_CH; 945 if (c < '0' || c > '9') break; 946 j = j * 10 + (int)(c - '0'); 947 any = 1; 948 if (j > 65535) goto syntaxerr; 949 } 950 if (any == 0 || c != 0) goto syntaxerr; 951 if (j < 1024) goto syntaxerr; 952 *port = (UShort)j; 953 ok: 954 return 1; 955 syntaxerr: 956 return 0; 957 # undef GET_CH 958 } 959 960 // GrP fixme safe_fd? 961 Int VG_(socket) ( Int domain, Int type, Int protocol ) 962 { 963 # if defined(VGP_x86_linux) || defined(VGP_ppc32_linux) \ 964 || defined(VGP_ppc64be_linux) || defined(VGP_ppc64le_linux) \ 965 || defined(VGP_s390x_linux) 966 SysRes res; 967 UWord args[3]; 968 args[0] = domain; 969 args[1] = type; 970 args[2] = protocol; 971 res = VG_(do_syscall2)(__NR_socketcall, VKI_SYS_SOCKET, (UWord)&args); 972 return sr_isError(res) ? -1 : sr_Res(res); 973 974 # elif defined(VGP_amd64_linux) || defined(VGP_arm_linux) \ 975 || defined(VGP_mips32_linux) || defined(VGP_mips64_linux) \ 976 || defined(VGP_arm64_linux) || defined(VGP_tilegx_linux) 977 SysRes res; 978 res = VG_(do_syscall3)(__NR_socket, domain, type, protocol ); 979 return sr_isError(res) ? -1 : sr_Res(res); 980 981 # elif defined(VGO_darwin) 982 SysRes res; 983 res = VG_(do_syscall3)(__NR_socket, domain, type, protocol); 984 if (!sr_isError(res)) { 985 // Set SO_NOSIGPIPE so write() returns EPIPE instead of raising SIGPIPE 986 Int optval = 1; 987 SysRes res2; 988 res2 = VG_(do_syscall5)(__NR_setsockopt, sr_Res(res), VKI_SOL_SOCKET, 989 VKI_SO_NOSIGPIPE, (UWord)&optval, 990 sizeof(optval)); 991 // ignore setsockopt() error 992 } 993 return sr_isError(res) ? -1 : sr_Res(res); 994 995 # else 996 # error "Unknown arch" 997 # endif 998 } 999 1000 1001 static 1002 Int my_connect ( Int sockfd, struct vki_sockaddr_in* serv_addr, Int addrlen ) 1003 { 1004 # if defined(VGP_x86_linux) || defined(VGP_ppc32_linux) \ 1005 || defined(VGP_ppc64be_linux) || defined(VGP_ppc64le_linux) \ 1006 || defined(VGP_s390x_linux) 1007 SysRes res; 1008 UWord args[3]; 1009 args[0] = sockfd; 1010 args[1] = (UWord)serv_addr; 1011 args[2] = addrlen; 1012 res = VG_(do_syscall2)(__NR_socketcall, VKI_SYS_CONNECT, (UWord)&args); 1013 return sr_isError(res) ? -1 : sr_Res(res); 1014 1015 # elif defined(VGP_amd64_linux) || defined(VGP_arm_linux) \ 1016 || defined(VGP_mips32_linux) || defined(VGP_mips64_linux) \ 1017 || defined(VGP_arm64_linux) || defined(VGP_tilegx_linux) 1018 SysRes res; 1019 res = VG_(do_syscall3)(__NR_connect, sockfd, (UWord)serv_addr, addrlen); 1020 return sr_isError(res) ? -1 : sr_Res(res); 1021 1022 # elif defined(VGO_darwin) 1023 SysRes res; 1024 res = VG_(do_syscall3)(__NR_connect_nocancel, 1025 sockfd, (UWord)serv_addr, addrlen); 1026 return sr_isError(res) ? -1 : sr_Res(res); 1027 1028 # else 1029 # error "Unknown arch" 1030 # endif 1031 } 1032 1033 Int VG_(write_socket)( Int sd, const void *msg, Int count ) 1034 { 1035 /* This is actually send(). */ 1036 1037 /* For Linux, VKI_MSG_NOSIGNAL is a request not to send SIGPIPE on 1038 errors on stream oriented sockets when the other end breaks the 1039 connection. The EPIPE error is still returned. 1040 1041 For Darwin, VG_(socket)() sets SO_NOSIGPIPE to get EPIPE instead of 1042 SIGPIPE */ 1043 1044 # if defined(VGP_x86_linux) || defined(VGP_ppc32_linux) \ 1045 || defined(VGP_ppc64be_linux) || defined(VGP_ppc64le_linux) \ 1046 || defined(VGP_s390x_linux) 1047 SysRes res; 1048 UWord args[4]; 1049 args[0] = sd; 1050 args[1] = (UWord)msg; 1051 args[2] = count; 1052 args[3] = VKI_MSG_NOSIGNAL; 1053 res = VG_(do_syscall2)(__NR_socketcall, VKI_SYS_SEND, (UWord)&args); 1054 return sr_isError(res) ? -1 : sr_Res(res); 1055 1056 # elif defined(VGP_amd64_linux) || defined(VGP_arm_linux) \ 1057 || defined(VGP_mips32_linux) || defined(VGP_mips64_linux) \ 1058 || defined(VGP_arm64_linux) || defined(VGP_tilegx_linux) 1059 SysRes res; 1060 res = VG_(do_syscall6)(__NR_sendto, sd, (UWord)msg, 1061 count, VKI_MSG_NOSIGNAL, 0,0); 1062 return sr_isError(res) ? -1 : sr_Res(res); 1063 1064 # elif defined(VGP_x86_darwin) || defined(VGP_amd64_darwin) 1065 SysRes res; 1066 res = VG_(do_syscall3)(__NR_write_nocancel, sd, (UWord)msg, count); 1067 return sr_isError(res) ? -1 : sr_Res(res); 1068 1069 # else 1070 # error "Unknown platform" 1071 # endif 1072 } 1073 1074 Int VG_(getsockname) ( Int sd, struct vki_sockaddr *name, Int *namelen) 1075 { 1076 # if defined(VGP_x86_linux) || defined(VGP_ppc32_linux) \ 1077 || defined(VGP_ppc64be_linux) || defined(VGP_ppc64le_linux) \ 1078 || defined(VGP_s390x_linux) \ 1079 || defined(VGP_mips32_linux) 1080 SysRes res; 1081 UWord args[3]; 1082 args[0] = sd; 1083 args[1] = (UWord)name; 1084 args[2] = (UWord)namelen; 1085 res = VG_(do_syscall2)(__NR_socketcall, VKI_SYS_GETSOCKNAME, (UWord)&args); 1086 return sr_isError(res) ? -1 : sr_Res(res); 1087 1088 # elif defined(VGP_amd64_linux) || defined(VGP_arm_linux) \ 1089 || defined(VGP_mips64_linux) || defined(VGP_arm64_linux) \ 1090 || defined(VGP_tilegx_linux) 1091 SysRes res; 1092 res = VG_(do_syscall3)( __NR_getsockname, 1093 (UWord)sd, (UWord)name, (UWord)namelen ); 1094 return sr_isError(res) ? -1 : sr_Res(res); 1095 1096 # elif defined(VGO_darwin) 1097 SysRes res; 1098 res = VG_(do_syscall3)( __NR_getsockname, 1099 (UWord)sd, (UWord)name, (UWord)namelen ); 1100 return sr_isError(res) ? -1 : sr_Res(res); 1101 1102 # else 1103 # error "Unknown platform" 1104 # endif 1105 } 1106 1107 Int VG_(getpeername) ( Int sd, struct vki_sockaddr *name, Int *namelen) 1108 { 1109 # if defined(VGP_x86_linux) || defined(VGP_ppc32_linux) \ 1110 || defined(VGP_ppc64be_linux) || defined(VGP_ppc64le_linux) \ 1111 || defined(VGP_s390x_linux) \ 1112 || defined(VGP_mips32_linux) 1113 SysRes res; 1114 UWord args[3]; 1115 args[0] = sd; 1116 args[1] = (UWord)name; 1117 args[2] = (UWord)namelen; 1118 res = VG_(do_syscall2)(__NR_socketcall, VKI_SYS_GETPEERNAME, (UWord)&args); 1119 return sr_isError(res) ? -1 : sr_Res(res); 1120 1121 # elif defined(VGP_amd64_linux) || defined(VGP_arm_linux) \ 1122 || defined(VGP_mips64_linux) || defined(VGP_arm64_linux) \ 1123 || defined(VGP_tilegx_linux) 1124 SysRes res; 1125 res = VG_(do_syscall3)( __NR_getpeername, 1126 (UWord)sd, (UWord)name, (UWord)namelen ); 1127 return sr_isError(res) ? -1 : sr_Res(res); 1128 1129 # elif defined(VGO_darwin) 1130 SysRes res; 1131 res = VG_(do_syscall3)( __NR_getpeername, 1132 (UWord)sd, (UWord)name, (UWord)namelen ); 1133 return sr_isError(res) ? -1 : sr_Res(res); 1134 1135 # else 1136 # error "Unknown platform" 1137 # endif 1138 } 1139 1140 Int VG_(getsockopt) ( Int sd, Int level, Int optname, void *optval, 1141 Int *optlen) 1142 { 1143 # if defined(VGP_x86_linux) || defined(VGP_ppc32_linux) \ 1144 || defined(VGP_ppc64be_linux) || defined(VGP_ppc64le_linux) \ 1145 || defined(VGP_s390x_linux) 1146 SysRes res; 1147 UWord args[5]; 1148 args[0] = sd; 1149 args[1] = level; 1150 args[2] = optname; 1151 args[3] = (UWord)optval; 1152 args[4] = (UWord)optlen; 1153 res = VG_(do_syscall2)(__NR_socketcall, VKI_SYS_GETSOCKOPT, (UWord)&args); 1154 return sr_isError(res) ? -1 : sr_Res(res); 1155 1156 # elif defined(VGP_amd64_linux) || defined(VGP_arm_linux) \ 1157 || defined(VGP_mips32_linux) || defined(VGP_mips64_linux) \ 1158 || defined(VGP_arm64_linux) || defined(VGP_tilegx_linux) 1159 SysRes res; 1160 res = VG_(do_syscall5)( __NR_getsockopt, 1161 (UWord)sd, (UWord)level, (UWord)optname, 1162 (UWord)optval, (UWord)optlen ); 1163 return sr_isError(res) ? -1 : sr_Res(res); 1164 1165 # elif defined(VGO_darwin) 1166 SysRes res; 1167 res = VG_(do_syscall5)( __NR_getsockopt, 1168 (UWord)sd, (UWord)level, (UWord)optname, 1169 (UWord)optval, (UWord)optlen ); 1170 return sr_isError(res) ? -1 : sr_Res(res); 1171 1172 # else 1173 # error "Unknown platform" 1174 # endif 1175 } 1176 1177 1178 Int VG_(setsockopt) ( Int sd, Int level, Int optname, void *optval, 1179 Int optlen) 1180 { 1181 # if defined(VGP_x86_linux) || defined(VGP_ppc32_linux) \ 1182 || defined(VGP_ppc64be_linux) || defined(VGP_ppc64le_linux) \ 1183 || defined(VGP_s390x_linux) 1184 SysRes res; 1185 UWord args[5]; 1186 args[0] = sd; 1187 args[1] = level; 1188 args[2] = optname; 1189 args[3] = (UWord)optval; 1190 args[4] = (UWord)optlen; 1191 res = VG_(do_syscall2)(__NR_socketcall, VKI_SYS_SETSOCKOPT, (UWord)&args); 1192 return sr_isError(res) ? -1 : sr_Res(res); 1193 1194 # elif defined(VGP_amd64_linux) || defined(VGP_arm_linux) \ 1195 || defined(VGP_mips32_linux) || defined(VGP_mips64_linux) \ 1196 || defined(VGP_arm64_linux) || defined(VGP_tilegx_linux) 1197 SysRes res; 1198 res = VG_(do_syscall5)( __NR_setsockopt, 1199 (UWord)sd, (UWord)level, (UWord)optname, 1200 (UWord)optval, (UWord)optlen ); 1201 return sr_isError(res) ? -1 : sr_Res(res); 1202 1203 # elif defined(VGO_darwin) 1204 SysRes res; 1205 res = VG_(do_syscall5)( __NR_setsockopt, 1206 (UWord)sd, (UWord)level, (UWord)optname, 1207 (UWord)optval, (UWord)optlen ); 1208 return sr_isError(res) ? -1 : sr_Res(res); 1209 1210 # else 1211 # error "Unknown platform" 1212 # endif 1213 } 1214 1215 1216 const HChar *VG_(basename)(const HChar *path) 1217 { 1218 static HChar *buf = NULL; 1219 static SizeT buf_len = 0; 1220 const HChar *p, *end; 1221 1222 if (path == NULL || 1223 0 == VG_(strcmp)(path, "")) 1224 { 1225 return "."; 1226 } 1227 1228 p = path + VG_(strlen)(path); 1229 while (p > path && *p == '/') { 1230 // skip all trailing '/' 1231 p--; 1232 } 1233 1234 if (p == path && *p == '/') return "/"; // all slashes 1235 1236 end = p; 1237 1238 while (p > path && *p != '/') { 1239 // now skip non '/' 1240 p--; 1241 } 1242 1243 if (*p == '/') p++; 1244 1245 SizeT need = end-p+1 + 1; 1246 if (need > buf_len) { 1247 buf_len = (buf_len == 0) ? 500 : need; 1248 buf = VG_(realloc)("basename", buf, buf_len); 1249 } 1250 VG_(strncpy)(buf, p, end-p+1); 1251 buf[end-p+1] = '\0'; 1252 1253 return buf; 1254 } 1255 1256 1257 const HChar *VG_(dirname)(const HChar *path) 1258 { 1259 static HChar *buf = NULL; 1260 static SizeT buf_len = 0; 1261 1262 const HChar *p; 1263 1264 if (path == NULL || 1265 0 == VG_(strcmp)(path, "") || 1266 0 == VG_(strcmp)(path, "/")) 1267 { 1268 return "."; 1269 } 1270 1271 p = path + VG_(strlen)(path); 1272 while (p > path && *p == '/') { 1273 // skip all trailing '/' 1274 p--; 1275 } 1276 1277 while (p > path && *p != '/') { 1278 // now skip non '/' 1279 p--; 1280 } 1281 1282 if (p == path) { 1283 if (*p == '/') return "/"; // all slashes 1284 else return "."; // no slashes 1285 } 1286 1287 while (p > path && *p == '/') { 1288 // skip '/' again 1289 p--; 1290 } 1291 1292 SizeT need = p-path+1 + 1; 1293 if (need > buf_len) { 1294 buf_len = (buf_len == 0) ? 500 : need; 1295 buf = VG_(realloc)("dirname", buf, buf_len); 1296 } 1297 VG_(strncpy)(buf, path, p-path+1); 1298 buf[p-path+1] = '\0'; 1299 1300 return buf; 1301 } 1302 1303 1304 /*--------------------------------------------------------------------*/ 1305 /*--- end ---*/ 1306 /*--------------------------------------------------------------------*/ 1307