FreeBSD: add file descriptor tracking for _umtx_op
[valgrind.git] / coregrind / m_libcfile.c
blob9635b80a6869549ea3aba6e8518c63fc28fcea95
1 /* -*- mode: C; c-basic-offset: 3; -*- */
3 /*--------------------------------------------------------------------*/
4 /*--- File- and socket-related libc stuff. m_libcfile.c ---*/
5 /*--------------------------------------------------------------------*/
7 /*
8 This file is part of Valgrind, a dynamic binary instrumentation
9 framework.
11 Copyright (C) 2000-2017 Julian Seward
12 jseward@acm.org
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.
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.
24 You should have received a copy of the GNU General Public License
25 along with this program; if not, see <http://www.gnu.org/licenses/>.
27 The GNU General Public License is contained in the file COPYING.
30 #include "pub_core_basics.h"
31 #include "pub_core_vki.h"
32 #include "pub_core_vkiscnums.h"
33 #include "pub_core_debuglog.h"
34 #include "pub_core_libcbase.h"
35 #include "pub_core_libcassert.h"
36 #include "pub_core_libcfile.h"
37 #include "pub_core_libcprint.h" // VG_(sprintf)
38 #include "pub_core_libcproc.h" // VG_(getpid), VG_(getppid)
39 #include "pub_core_clientstate.h" // VG_(fd_hard_limit)
40 #include "pub_core_mallocfree.h" // VG_(realloc)
41 #include "pub_core_syscall.h"
43 /* IMPORTANT: on Darwin it is essential to use the _nocancel versions
44 of syscalls rather than the vanilla version, if a _nocancel version
45 is available. See docs/internals/Darwin-notes.txt for the reason
46 why. */
48 /* ---------------------------------------------------------------------
49 File stuff
50 ------------------------------------------------------------------ */
52 /* Move an fd into the Valgrind-safe range */
53 Int VG_(safe_fd)(Int oldfd)
55 Int newfd;
57 vg_assert(VG_(fd_hard_limit) != -1);
59 newfd = VG_(fcntl)(oldfd, VKI_F_DUPFD, VG_(fd_hard_limit));
61 if (newfd == -1) {
62 VG_(debugLog)(0, "libcfile", "Valgrind: FATAL: "
63 "Private file creation failed.\n"
64 " The current file descriptor limit is %d.\n"
65 " If you are running in Docker please consider\n"
66 " lowering this limit with the shell built-in limit command.\n",
67 VG_(fd_hard_limit));
68 VG_(debugLog)(0, "libcfile", "Exiting now.\n");
69 VG_(exit)(1);
72 vg_assert(newfd >= VG_(fd_hard_limit));
74 VG_(close)(oldfd);
76 /* Set the close-on-exec flag for this fd. */
77 VG_(fcntl)(newfd, VKI_F_SETFD, VKI_FD_CLOEXEC);
79 return newfd;
82 #if defined(VGO_freebsd)
83 #define M_FILEDESC_BUF 1000000
84 static Char filedesc_buf[M_FILEDESC_BUF];
85 #endif
87 /* Given a file descriptor, attempt to deduce its filename. To do
88 this, we use /proc/self/fd/<FD>. If this doesn't point to a file,
89 or if it doesn't exist, we return False.
90 Upon successful completion *result contains the filename. The
91 filename will be overwritten with the next invocation so callers
92 need to copy the filename if needed. *result is NULL if the filename
93 cannot be deduced. */
94 Bool VG_(resolve_filename) ( Int fd, const HChar** result )
96 # if defined(VGO_linux) || defined(VGO_solaris)
97 static HChar *buf = NULL;
98 static SizeT bufsiz = 0;
100 if (buf == NULL) { // first time
101 bufsiz = 500;
102 buf = VG_(malloc)("resolve_filename", bufsiz);
105 HChar tmp[64]; // large enough
107 # if defined(VGO_linux)
108 VG_(sprintf)(tmp, "/proc/self/fd/%d", fd);
109 # elif defined(VGO_solaris)
110 VG_(sprintf)(tmp, "/proc/self/path/%d", fd);
111 # endif
114 while (42) {
115 SSizeT res = VG_(readlink)(tmp, buf, bufsiz);
116 if (res < 0) break;
117 if (res == bufsiz) { // buffer too small; increase and retry
118 bufsiz += 500;
119 buf = VG_(realloc)("resolve_filename", buf, bufsiz);
120 continue;
122 vg_assert(bufsiz > res); // paranoia
123 if (buf[0] != '/') break;
125 buf[res] = '\0';
126 *result = buf;
127 return True;
129 // Failure
130 *result = NULL;
131 return False;
133 #elif defined(VGO_freebsd)
135 #if (1)
136 Int mib[4];
137 SysRes sres;
138 vki_size_t len;
139 Char *bp;
140 Char *eb;
141 struct vki_kinfo_file *kf;
142 static HChar *buf = NULL;
143 static SizeT bufsiz = 0;
145 if (buf == NULL) { // first time
146 bufsiz = 500;
147 buf = VG_(malloc)("resolve_filename", bufsiz);
150 mib[0] = VKI_CTL_KERN;
151 mib[1] = VKI_KERN_PROC;
152 mib[2] = VKI_KERN_PROC_FILEDESC;
153 mib[3] = sr_Res(VG_(do_syscall0)(__NR_getpid));
154 len = sizeof(filedesc_buf);
155 sres = VG_(do_syscall6)(__NR___sysctl, (UWord)mib, 4, (UWord)filedesc_buf,
156 (UWord)&len, 0, 0);
157 if (sr_isError(sres)) {
158 VG_(debugLog)(0, "sysctl(kern.proc.filedesc)", "%s\n", VG_(strerror)(sr_Err(sres)));
159 return False;
161 /* Walk though the list. */
162 bp = filedesc_buf;
163 eb = filedesc_buf + len;
164 while (bp < eb) {
165 kf = (struct vki_kinfo_file *)bp;
166 if (kf->vki_kf_fd == fd) {
167 break;
169 bp += kf->vki_kf_structsize;
171 if (bp >= eb || *kf->vki_kf_path == '\0') {
172 VG_(strncpy)( buf, "[unknown]", bufsiz );
173 } else {
174 VG_(strncpy)( buf, kf->vki_kf_path, bufsiz );
176 *result = buf;
177 return True;
178 #else
179 // PJF it will be a relief to get rid of the above bit of ugliness
180 // however it does not seem to have the same functionality
181 // regarding pipes where it profuces just an empty string
182 struct vki_kinfo_file kinfo_file;
183 kinfo_file.vki_kf_structsize = VKI_KINFO_FILE_SIZE;
184 if (0 == VG_(fcntl) ( fd, VKI_F_KINFO, (Addr)&kinfo_file )) {
185 static HChar *buf = NULL;
187 if (buf == NULL)
188 buf = VG_(malloc)("resolve_filename", VKI_PATH_MAX);
190 *result = buf;
191 VG_(strcpy)( buf, kinfo_file.vki_kf_path );
192 if (buf[0] == '/') return True;
194 *result = NULL;
195 return False;
196 #endif
198 # elif defined(VGO_darwin)
199 HChar tmp[VKI_MAXPATHLEN+1];
200 if (0 == VG_(fcntl)(fd, VKI_F_GETPATH, (UWord)tmp)) {
201 static HChar *buf = NULL;
203 if (buf == NULL)
204 buf = VG_(malloc)("resolve_filename", VKI_MAXPATHLEN+1);
205 VG_(strcpy)( buf, tmp );
207 *result = buf;
208 if (buf[0] == '/') return True;
210 // Failure
211 *result = NULL;
212 return False;
214 # else
215 # error Unknown OS
216 # endif
219 #if defined(VGO_freebsd)
222 #if (1)
223 /* This should only be called after a successful call to
224 * Bool VG_(resolve_filename) ( Int fd, const HChar** result )
225 * so that filedesc_buf is still valid for fd */
226 Bool VG_(resolve_filemode) ( Int fd, Int * result )
228 Char *bp;
229 Char *eb;
230 struct vki_kinfo_file *kf;
232 /* Walk though the list. */
233 bp = filedesc_buf;
234 eb = filedesc_buf + sizeof(filedesc_buf);
235 while (bp < eb) {
236 kf = (struct vki_kinfo_file *)bp;
237 if (kf->vki_kf_fd == fd) {
238 break;
240 bp += kf->vki_kf_structsize;
242 if (bp >= eb) {
243 *result = -1;
244 } else {
245 *result = kf->vki_kf_flags;
247 return True;
249 #else
250 /* less ugly version, no dependency on resolve_filename */
251 Bool VG_(resolve_filemode) ( Int fd, Int * result )
253 struct vki_kinfo_file kinfo_file;
254 kinfo_file.vki_kf_structsize = VKI_KINFO_FILE_SIZE;
255 if (0 == VG_(fcntl) ( fd, VKI_F_KINFO, (Addr)&kinfo_file )) {
256 *result = kinfo_file.vki_kf_flags;
257 return True;
259 return False;
261 #endif
262 #endif
265 SysRes VG_(mknod) ( const HChar* pathname, Int mode, UWord dev )
267 # if defined(VGP_arm64_linux) || defined(VGP_nanomips_linux)
268 /* ARM64 wants to use __NR_mknodat rather than __NR_mknod. */
269 SysRes res = VG_(do_syscall4)(__NR_mknodat,
270 VKI_AT_FDCWD, (UWord)pathname, mode, dev);
271 # elif defined(VGO_linux) || defined(VGO_darwin)
272 SysRes res = VG_(do_syscall3)(__NR_mknod,
273 (UWord)pathname, mode, dev);
274 # elif defined(VGO_freebsd)
275 #if (FREEBSD_VERS < FREEBSD_12)
276 SysRes res = VG_(do_syscall3)(__NR_freebsd11_mknod,
277 (UWord)pathname, mode, dev);
278 #else
279 SysRes res = VG_(do_syscall4)(__NR_mknodat, VKI_AT_FDCWD,
280 (UWord)pathname, mode, dev);
281 #endif
282 # elif defined(VGO_solaris)
283 SysRes res = VG_(do_syscall4)(__NR_mknodat,
284 VKI_AT_FDCWD, (UWord)pathname, mode, dev);
285 # else
286 # error Unknown OS
287 # endif
288 return res;
291 SysRes VG_(open) ( const HChar* pathname, Int flags, Int mode )
293 # if defined(VGP_arm64_linux) || defined(VGP_nanomips_linux)
294 /* ARM64 wants to use __NR_openat rather than __NR_open. */
295 SysRes res = VG_(do_syscall4)(__NR_openat,
296 VKI_AT_FDCWD, (UWord)pathname, flags, mode);
297 # elif defined(VGO_linux) || defined(VGO_freebsd)
298 SysRes res = VG_(do_syscall3)(__NR_open,
299 (UWord)pathname, flags, mode);
300 # elif defined(VGO_darwin)
301 SysRes res = VG_(do_syscall3)(__NR_open_nocancel,
302 (UWord)pathname, flags, mode);
303 # elif defined(VGO_solaris)
304 SysRes res = VG_(do_syscall4)(__NR_openat,
305 VKI_AT_FDCWD, (UWord)pathname, flags, mode);
306 # else
307 # error Unknown OS
308 # endif
309 return res;
312 Int VG_(fd_open) (const HChar* pathname, Int flags, Int mode)
314 SysRes sr;
315 sr = VG_(open) (pathname, flags, mode);
316 if (sr_isError (sr))
317 return -1;
318 else
319 return sr_Res (sr);
322 void VG_(close) ( Int fd )
324 /* Hmm. Return value is not checked. That's uncool. */
325 # if defined(VGO_linux) || defined(VGO_solaris) || defined(VGO_freebsd)
326 (void)VG_(do_syscall1)(__NR_close, fd);
327 # elif defined(VGO_darwin)
328 (void)VG_(do_syscall1)(__NR_close_nocancel, fd);
329 # else
330 # error Unknown OS
331 # endif
334 Int VG_(read) ( Int fd, void* buf, Int count)
336 Int ret;
337 # if defined(VGO_linux) || defined(VGO_solaris) || defined(VGO_freebsd)
338 SysRes res = VG_(do_syscall3)(__NR_read, fd, (UWord)buf, count);
339 # elif defined(VGO_darwin)
340 SysRes res = VG_(do_syscall3)(__NR_read_nocancel, fd, (UWord)buf, count);
341 # else
342 # error Unknown OS
343 # endif
344 if (sr_isError(res)) {
345 ret = - (Int)(Word)sr_Err(res);
346 vg_assert(ret < 0);
347 } else {
348 ret = (Int)(Word)sr_Res(res);
349 vg_assert(ret >= 0);
351 return ret;
354 Int VG_(write) ( Int fd, const void* buf, Int count)
356 Int ret;
357 # if defined(VGO_linux) || defined(VGO_solaris) || defined(VGO_freebsd)
358 SysRes res = VG_(do_syscall3)(__NR_write, fd, (UWord)buf, count);
359 # elif defined(VGO_darwin)
360 SysRes res = VG_(do_syscall3)(__NR_write_nocancel, fd, (UWord)buf, count);
361 # else
362 # error "Unknown OS"
363 # endif
364 if (sr_isError(res)) {
365 ret = - (Int)(Word)sr_Err(res);
366 vg_assert(ret < 0);
367 } else {
368 ret = (Int)(Word)sr_Res(res);
369 vg_assert(ret >= 0);
371 return ret;
375 Int VG_(pipe) ( Int fd[2] )
377 # if defined(VGP_mips32_linux) || defined(VGP_mips64_linux)
378 /* __NR_pipe has a strange return convention on mips32-linux. */
379 SysRes res = VG_(do_syscall1)(__NR_pipe, (UWord)fd);
380 if (!sr_isError(res)) {
381 fd[0] = (Int)sr_Res(res);
382 fd[1] = (Int)sr_ResEx(res);
383 return 0;
384 } else {
385 return -1;
387 # elif defined(VGP_arm64_linux) || defined(VGP_nanomips_linux)
388 SysRes res = VG_(do_syscall2)(__NR_pipe2, (UWord)fd, 0);
389 return sr_isError(res) ? -1 : 0;
390 # elif defined(VGO_linux)
391 SysRes res = VG_(do_syscall1)(__NR_pipe, (UWord)fd);
392 return sr_isError(res) ? -1 : 0;
393 # elif defined(VGO_freebsd)
394 #if defined(__NR_pipe2)
395 SysRes res = VG_(do_syscall2)(__NR_pipe2, (UWord)fd, 0);
396 #else
397 SysRes res = VG_(do_syscall0)(__NR_freebsd10_pipe);
398 if (!sr_isError(res)) {
399 fd[0] = sr_Res(res);
400 fd[1] = sr_ResHI(res);
402 #endif
403 return sr_isError(res) ? -1 : 0;
404 # elif defined(VGO_darwin)
405 /* __NR_pipe is UX64, so produces a double-word result */
406 SysRes res = VG_(do_syscall0)(__NR_pipe);
407 if (!sr_isError(res)) {
408 fd[0] = (Int)sr_Res(res);
409 fd[1] = (Int)sr_ResHI(res);
411 return sr_isError(res) ? -1 : 0;
412 # elif defined(VGO_solaris)
413 # if defined(SOLARIS_NEW_PIPE_SYSCALL)
414 SysRes res = VG_(do_syscall2)(__NR_pipe, (UWord)fd, 0);
415 return sr_isError(res) ? -1 : 0;
416 # else
417 SysRes res = VG_(do_syscall0)(__NR_pipe);
418 if (!sr_isError(res)) {
419 fd[0] = (Int)sr_Res(res);
420 fd[1] = (Int)sr_ResHI(res);
422 return sr_isError(res) ? -1 : 0;
423 # endif
424 # else
425 # error "Unknown OS"
426 # endif
429 Off64T VG_(lseek) ( Int fd, Off64T offset, Int whence )
431 # if defined(VGO_linux) || defined(VGP_amd64_darwin) || defined(VGP_amd64_freebsd) || defined(VGP_arm64_freebsd)
432 # if defined(__NR__llseek)
433 Off64T result;
434 SysRes res = VG_(do_syscall5)(__NR__llseek, fd,
435 offset >> 32, offset & 0xffffffff,
436 (UWord)&result, whence);
437 return sr_isError(res) ? (-1) : result;
438 # else
439 SysRes res = VG_(do_syscall3)(__NR_lseek, fd, offset, whence);
440 vg_assert(sizeof(Off64T) == sizeof(sr_Res(res)));
441 return sr_isError(res) ? (-1) : sr_Res(res);
442 # endif
443 # elif defined(VGP_x86_darwin) || defined(VGP_x86_freebsd)
444 SysRes res = VG_(do_syscall4)(__NR_lseek, fd,
445 offset & 0xffffffff, offset >> 32, whence);
446 return sr_isError(res) ? (-1) : sr_Res(res);
447 # elif defined(VGP_x86_solaris)
448 SysRes res = VG_(do_syscall4)(__NR_llseek, fd,
449 offset & 0xffffffff, offset >> 32, whence);
450 return sr_isError(res) ? (-1) : ((ULong)sr_ResHI(res) << 32 | sr_Res(res));
451 # elif defined(VGP_amd64_solaris)
452 SysRes res = VG_(do_syscall3)(__NR_lseek, fd, offset, whence);
453 vg_assert(sizeof(Off64T) == sizeof(Word));
454 return sr_isError(res) ? (-1) : sr_Res(res);
455 # else
456 # error "Unknown plat"
457 # endif
458 /* if you change the error-reporting conventions of this, also
459 change all usage points. */
463 /* stat/fstat support. It's uggerly. We have impedance-match into a
464 'struct vg_stat' in order to have a single structure that callers
465 can use consistently on all platforms. */
467 #define TRANSLATE_TO_vg_stat(_p_vgstat, _p_vkistat) \
468 do { \
469 (_p_vgstat)->dev = (ULong)( (_p_vkistat)->st_dev ); \
470 (_p_vgstat)->ino = (ULong)( (_p_vkistat)->st_ino ); \
471 (_p_vgstat)->nlink = (ULong)( (_p_vkistat)->st_nlink ); \
472 (_p_vgstat)->mode = (UInt) ( (_p_vkistat)->st_mode ); \
473 (_p_vgstat)->uid = (UInt) ( (_p_vkistat)->st_uid ); \
474 (_p_vgstat)->gid = (UInt) ( (_p_vkistat)->st_gid ); \
475 (_p_vgstat)->rdev = (ULong)( (_p_vkistat)->st_rdev ); \
476 (_p_vgstat)->size = (Long) ( (_p_vkistat)->st_size ); \
477 (_p_vgstat)->blksize = (ULong)( (_p_vkistat)->st_blksize ); \
478 (_p_vgstat)->blocks = (ULong)( (_p_vkistat)->st_blocks ); \
479 (_p_vgstat)->atime = (ULong)( (_p_vkistat)->st_atime ); \
480 (_p_vgstat)->atime_nsec = (ULong)( (_p_vkistat)->st_atime_nsec ); \
481 (_p_vgstat)->mtime = (ULong)( (_p_vkistat)->st_mtime ); \
482 (_p_vgstat)->mtime_nsec = (ULong)( (_p_vkistat)->st_mtime_nsec ); \
483 (_p_vgstat)->ctime = (ULong)( (_p_vkistat)->st_ctime ); \
484 (_p_vgstat)->ctime_nsec = (ULong)( (_p_vkistat)->st_ctime_nsec ); \
485 } while (0)
487 #define TRANSLATE_statx_TO_vg_stat(_p_vgstat, _p_vkistat) \
488 do { \
489 (_p_vgstat)->dev = VG_MAKEDEV( (_p_vkistat)->stx_dev_major, \
490 (_p_vkistat)->stx_dev_minor ); \
491 (_p_vgstat)->ino = (ULong)( (_p_vkistat)->stx_ino ); \
492 (_p_vgstat)->nlink = (ULong)( (_p_vkistat)->stx_nlink ); \
493 (_p_vgstat)->mode = (UInt) ( (_p_vkistat)->stx_mode ); \
494 (_p_vgstat)->uid = (UInt) ( (_p_vkistat)->stx_uid ); \
495 (_p_vgstat)->gid = (UInt) ( (_p_vkistat)->stx_gid ); \
496 (_p_vgstat)->rdev = VG_MAKEDEV( (_p_vkistat)->stx_rdev_major, \
497 (_p_vkistat)->stx_rdev_minor ); \
498 (_p_vgstat)->size = (Long) ( (_p_vkistat)->stx_size ); \
499 (_p_vgstat)->blksize = (ULong)( (_p_vkistat)->stx_blksize ); \
500 (_p_vgstat)->blocks = (ULong)( (_p_vkistat)->stx_blocks ); \
501 (_p_vgstat)->atime = (ULong)( (_p_vkistat)->stx_atime.tv_sec ); \
502 (_p_vgstat)->atime_nsec = (ULong)( (_p_vkistat)->stx_atime.tv_nsec ); \
503 (_p_vgstat)->mtime = (ULong)( (_p_vkistat)->stx_mtime.tv_sec ); \
504 (_p_vgstat)->mtime_nsec = (ULong)( (_p_vkistat)->stx_mtime.tv_nsec ); \
505 (_p_vgstat)->ctime = (ULong)( (_p_vkistat)->stx_ctime.tv_sec ); \
506 (_p_vgstat)->ctime_nsec = (ULong)( (_p_vkistat)->stx_ctime.tv_nsec ); \
507 } while (0)
509 SysRes VG_(stat) ( const HChar* file_name, struct vg_stat* vgbuf )
511 SysRes res;
512 VG_(memset)(vgbuf, 0, sizeof(*vgbuf));
514 # if defined(VGO_linux)
515 /* On Linux, first try with statx. If that doesn't work out, fall back to
516 the stat64 or vanilla version. */
517 { struct vki_statx buf;
518 res = VG_(do_syscall5)(__NR_statx, VKI_AT_FDCWD, (UWord)file_name, 0,
519 VKI_STATX_ALL, (UWord)&buf);
520 if (!(sr_isError(res) && sr_Err(res) == VKI_ENOSYS)) {
521 /* Success, or any failure except ENOSYS */
522 if (!sr_isError(res))
523 TRANSLATE_statx_TO_vg_stat(vgbuf, &buf);
524 return res;
527 # endif
528 # if defined(VGO_linux) || defined(VGO_darwin)
529 /* Try with stat64. This is the second candidate on Linux, and the first
530 one on Darwin. If that doesn't work out, fall back to vanilla version.
532 # if defined(__NR_stat64)
533 { struct vki_stat64 buf64;
534 res = VG_(do_syscall2)(__NR_stat64, (UWord)file_name, (UWord)&buf64);
535 if (!(sr_isError(res) && sr_Err(res) == VKI_ENOSYS)) {
536 /* Success, or any failure except ENOSYS */
537 if (!sr_isError(res))
538 TRANSLATE_TO_vg_stat(vgbuf, &buf64);
539 return res;
542 # endif /* defined(__NR_stat64) */
543 # if defined(__NR_stat) || defined(VGP_arm64_linux)
544 /* This is the fallback ("vanilla version"). */
545 { struct vki_stat buf;
546 # if defined(VGP_arm64_linux)
547 res = VG_(do_syscall3)(__NR3264_fstatat, VKI_AT_FDCWD,
548 (UWord)file_name, (UWord)&buf);
549 # else
550 res = VG_(do_syscall2)(__NR_stat, (UWord)file_name, (UWord)&buf);
551 # endif
552 if (!sr_isError(res))
553 TRANSLATE_TO_vg_stat(vgbuf, &buf);
554 return res;
556 # endif
557 # elif defined(VGO_solaris)
559 # if defined(VGP_x86_solaris)
560 struct vki_stat64 buf64;
561 res = VG_(do_syscall4)(__NR_fstatat64, VKI_AT_FDCWD, (UWord)file_name,
562 (UWord)&buf64, 0);
563 # elif defined(VGP_amd64_solaris)
564 struct vki_stat buf64;
565 res = VG_(do_syscall4)(__NR_fstatat, VKI_AT_FDCWD, (UWord)file_name,
566 (UWord)&buf64, 0);
567 # else
568 # error "Unknown platform"
569 # endif
570 if (!sr_isError(res))
571 TRANSLATE_TO_vg_stat(vgbuf, &buf64);
572 return res;
574 # elif defined(VGO_freebsd)
576 #if (FREEBSD_VERS < FREEBSD_12)
577 struct vki_freebsd11_stat buf;
578 res = VG_(do_syscall2)(__NR_stat, (UWord)file_name, (UWord)&buf);
579 #else
580 struct vki_stat buf;
581 res = VG_(do_syscall4)(__NR_fstatat, VKI_AT_FDCWD, (UWord)file_name, (UWord)&buf, 0);
582 #endif
583 if (!sr_isError(res)) {
584 TRANSLATE_TO_vg_stat(vgbuf, &buf);
586 return res;
588 # else
589 # error Unknown OS
590 # endif
593 Int VG_(fstat) ( Int fd, struct vg_stat* vgbuf )
595 SysRes res;
596 VG_(memset)(vgbuf, 0, sizeof(*vgbuf));
598 # if defined(VGO_linux)
599 /* On Linux, first try with statx. If that doesn't work out, fall back to
600 the fstat64 or vanilla version. */
601 { struct vki_statx buf;
602 const char* file_name = "";
603 res = VG_(do_syscall5)(__NR_statx, fd, (RegWord)file_name,
604 VKI_AT_EMPTY_PATH, VKI_STATX_ALL, (RegWord)&buf);
605 if (!(sr_isError(res) && sr_Err(res) == VKI_ENOSYS)) {
606 /* Success, or any failure except ENOSYS */
607 if (!sr_isError(res))
608 TRANSLATE_statx_TO_vg_stat(vgbuf, &buf);
609 return sr_isError(res) ? (-1) : 0;
612 #endif
613 # if defined(VGO_linux) || defined(VGO_darwin)
614 /* Try with fstat64. This is the second candidate on Linux, and the first
615 one on Darwin. If that doesn't work out, fall back to vanilla version.
617 # if defined(__NR_fstat64)
618 { struct vki_stat64 buf64;
619 res = VG_(do_syscall2)(__NR_fstat64, (UWord)fd, (UWord)&buf64);
620 if (!(sr_isError(res) && sr_Err(res) == VKI_ENOSYS)) {
621 /* Success, or any failure except ENOSYS */
622 if (!sr_isError(res))
623 TRANSLATE_TO_vg_stat(vgbuf, &buf64);
624 return sr_isError(res) ? (-1) : 0;
627 # endif /* defined(__NR_fstat64) */
628 # if defined(__NR_fstat)
629 { struct vki_stat buf;
630 res = VG_(do_syscall2)(__NR_fstat, (RegWord)fd, (RegWord)(Addr)&buf);
631 if (!sr_isError(res))
632 TRANSLATE_TO_vg_stat(vgbuf, &buf);
633 return sr_isError(res) ? (-1) : 0;
635 # endif
636 # elif defined(VGO_solaris)
638 # if defined(VGP_x86_solaris)
639 struct vki_stat64 buf64;
640 res = VG_(do_syscall4)(__NR_fstatat64, (UWord)fd, 0, (UWord)&buf64, 0);
641 # elif defined(VGP_amd64_solaris)
642 struct vki_stat buf64;
643 res = VG_(do_syscall4)(__NR_fstatat, (UWord)fd, 0, (UWord)&buf64, 0);
644 # else
645 # error "Unknown platform"
646 # endif
647 if (!sr_isError(res))
648 TRANSLATE_TO_vg_stat(vgbuf, &buf64);
649 return sr_isError(res) ? (-1) : 0;
651 # elif defined(VGO_freebsd)
653 #if (FREEBSD_VERS < FREEBSD_12)
654 struct vki_freebsd11_stat buf;
655 res = VG_(do_syscall2)(__NR_fstat, (RegWord)fd, (RegWord)(Addr)&buf);
656 #else
657 struct vki_stat buf;
658 res = VG_(do_syscall2)(__NR_fstat, (RegWord)fd, (RegWord)(Addr)&buf);
659 #endif
660 if (!sr_isError(res)) {
661 TRANSLATE_TO_vg_stat(vgbuf, &buf);
663 return sr_isError(res) ? (-1) : 0;
665 # else
666 # error Unknown OS
667 # endif
670 #if defined(VGO_freebsd)
671 /* extend this to other OSes as and when needed */
672 SysRes VG_(lstat) ( const HChar* file_name, struct vg_stat* vgbuf )
674 SysRes res;
675 VG_(memset)(vgbuf, 0, sizeof(*vgbuf));
677 #if (FREEBSD_VERS < FREEBSD_12)
678 struct vki_freebsd11_stat buf;
679 res = VG_(do_syscall2)(__NR_lstat, (UWord)file_name, (UWord)&buf);
680 #else
681 struct vki_stat buf;
682 res = VG_(do_syscall4)(__NR_fstatat, VKI_AT_FDCWD, (UWord)file_name, (UWord)&buf, VKI_AT_SYMLINK_NOFOLLOW);
683 #endif
684 if (!sr_isError(res)) {
685 TRANSLATE_TO_vg_stat(vgbuf, &buf);
687 return res;
689 #endif
691 #undef TRANSLATE_TO_vg_stat
692 #undef TRANSLATE_statx_TO_vg_stat
694 Long VG_(fsize) ( Int fd )
696 struct vg_stat buf;
697 Int res = VG_(fstat)( fd, &buf );
698 return (res == -1) ? (-1LL) : buf.size;
701 SysRes VG_(getxattr) ( const HChar* file_name, const HChar* attr_name, Addr attr_value, SizeT attr_value_len )
703 SysRes res;
704 #if defined(VGO_linux)
705 res = VG_(do_syscall4)(__NR_getxattr, (UWord)file_name, (UWord)attr_name,
706 attr_value, attr_value_len);
707 #else
708 res = VG_(mk_SysRes_Error)(VKI_ENOSYS);
709 #endif
710 return res;
713 Bool VG_(is_dir) ( const HChar* f )
715 struct vg_stat buf;
716 SysRes res = VG_(stat)(f, &buf);
717 return sr_isError(res) ? False
718 : VKI_S_ISDIR(buf.mode) ? True : False;
721 SysRes VG_(dup) ( Int oldfd )
723 # if defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_freebsd)
724 return VG_(do_syscall1)(__NR_dup, oldfd);
725 # elif defined(VGO_solaris)
726 return VG_(do_syscall3)(__NR_fcntl, oldfd, F_DUPFD, 0);
727 # else
728 # error Unknown OS
729 # endif
732 SysRes VG_(dup2) ( Int oldfd, Int newfd )
734 # if defined(VGP_arm64_linux) || defined(VGP_nanomips_linux)
735 /* We only have dup3, that means we have to mimic dup2.
736 The only real difference is when oldfd == newfd.
737 dup3 always returns an error, but dup2 returns only an
738 error if the fd is invalid, otherwise it returns newfd. */
739 if (oldfd == newfd) {
740 if (VG_(fcntl)(oldfd, VKI_F_GETFL, 0) == -1)
741 return VG_(mk_SysRes_Error)(VKI_EBADF);
742 return VG_(mk_SysRes_Success)(newfd);
744 return VG_(do_syscall3)(__NR_dup3, oldfd, newfd, 0);
745 # elif defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_freebsd)
746 return VG_(do_syscall2)(__NR_dup2, oldfd, newfd);
747 # elif defined(VGO_solaris)
748 return VG_(do_syscall3)(__NR_fcntl, oldfd, F_DUP2FD, newfd);
749 # else
750 # error Unknown OS
751 # endif
754 /* Returns -1 on error. */
755 Int VG_(fcntl) ( Int fd, Int cmd, Addr arg )
757 # if defined(VGO_linux) || defined(VGO_solaris) || defined(VGO_freebsd)
758 # if defined(VGP_nanomips_linux)
759 SysRes res = VG_(do_syscall3)(__NR_fcntl64, fd, cmd, arg);
760 # else
761 SysRes res = VG_(do_syscall3)(__NR_fcntl, fd, cmd, arg);
762 # endif
763 # elif defined(VGO_darwin)
764 SysRes res = VG_(do_syscall3)(__NR_fcntl_nocancel, fd, cmd, arg);
765 # else
766 # error "Unknown OS"
767 # endif
768 if (sr_isError(res)) {
769 VG_(debugLog)(1, "VG_(fcntl)", "fcntl error %lu %s\n", sr_Err(res), VG_(strerror)(sr_Err(res)));
770 return -1;
772 return (Int)sr_Res(res);
775 Int VG_(rename) ( const HChar* old_name, const HChar* new_name )
777 # if defined(VGO_solaris) || defined(VGP_arm64_linux)
778 SysRes res = VG_(do_syscall4)(__NR_renameat, VKI_AT_FDCWD, (UWord)old_name,
779 VKI_AT_FDCWD, (UWord)new_name);
780 # elif defined(VGP_nanomips_linux)
781 SysRes res = VG_(do_syscall5)(__NR_renameat2, VKI_AT_FDCWD, (UWord)old_name,
782 VKI_AT_FDCWD, (UWord)new_name, 0);
784 # elif defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_freebsd)
785 SysRes res = VG_(do_syscall2)(__NR_rename, (UWord)old_name, (UWord)new_name);
786 # else
787 # error "Unknown OS"
788 # endif
789 return sr_isError(res) ? (-1) : 0;
792 Int VG_(unlink) ( const HChar* file_name )
794 # if defined(VGP_arm64_linux) || defined(VGP_nanomips_linux)
795 SysRes res = VG_(do_syscall2)(__NR_unlinkat, VKI_AT_FDCWD,
796 (UWord)file_name);
797 # elif defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_freebsd)
798 SysRes res = VG_(do_syscall1)(__NR_unlink, (UWord)file_name);
799 # elif defined(VGO_solaris)
800 SysRes res = VG_(do_syscall3)(__NR_unlinkat, VKI_AT_FDCWD,
801 (UWord)file_name, 0);
802 # else
803 # error "Unknown OS"
804 # endif
805 return sr_isError(res) ? (-1) : 0;
808 /* The working directory at startup.
809 All that is really needed is to note the cwd at process startup.
810 Hence VG_(record_startup_wd) notes it (in a platform dependent way)
811 and VG_(get_startup_wd) produces the noted value. */
812 static HChar *startup_wd;
814 /* Record the process' working directory at startup. Is intended to
815 be called exactly once, at startup, before the working directory
816 changes. */
817 void VG_(record_startup_wd) ( void )
819 # if defined(VGO_linux) || defined(VGO_solaris) || defined(VGO_freebsd)
820 /* Simple: just ask the kernel */
821 SysRes res;
822 SizeT szB = 0;
823 do {
824 szB += 500;
825 startup_wd = VG_(realloc)("startup_wd", startup_wd, szB);
826 VG_(memset)(startup_wd, 0, szB);
827 # if defined(VGO_linux) || defined(VGO_solaris)
828 res = VG_(do_syscall2)(__NR_getcwd, (UWord)startup_wd, szB-1);
829 # elif defined(VGO_freebsd)
830 res = VG_(do_syscall2)(__NR___getcwd, (UWord)startup_wd, szB-1);
831 # endif
832 } while (sr_isError(res) && sr_Err(res) == VKI_ERANGE);
834 if (sr_isError(res)) {
835 VG_(free)(startup_wd);
836 startup_wd = NULL;
837 return;
840 vg_assert(startup_wd[szB-1] == 0);
842 # elif defined(VGO_darwin)
843 /* We can't ask the kernel, so instead rely on launcher-*.c to
844 tell us the startup path. Note the env var is keyed to the
845 parent's PID, not ours, since our parent is the launcher
846 process. */
847 { HChar envvar[100]; // large enough
848 HChar* wd;
849 VG_(memset)(envvar, 0, sizeof(envvar));
850 VG_(sprintf)(envvar, "VALGRIND_STARTUP_PWD_%d_XYZZY",
851 (Int)VG_(getppid)());
852 wd = VG_(getenv)( envvar );
853 if (wd == NULL)
854 return;
855 SizeT need = VG_(strlen)(wd) + 1;
856 startup_wd = VG_(malloc)("startup_wd", need);
857 VG_(strcpy)(startup_wd, wd);
859 # else
860 # error Unknown OS
861 # endif
864 /* Return the previously acquired startup_wd or NULL. */
865 const HChar *VG_(get_startup_wd) ( void )
867 return startup_wd;
870 SysRes VG_(poll) (struct vki_pollfd *fds, Int nfds, Int timeout)
872 SysRes res;
873 # if defined(VGP_arm64_linux) || defined(VGP_nanomips_linux)
874 /* ARM64 wants to use __NR_ppoll rather than __NR_poll. */
875 struct vki_timespec timeout_ts;
876 if (timeout >= 0) {
877 timeout_ts.tv_sec = timeout / 1000;
878 timeout_ts.tv_nsec = ((long)timeout % 1000) * 1000000;
880 res = VG_(do_syscall4)(__NR_ppoll,
881 (UWord)fds, nfds,
882 (UWord)(timeout >= 0 ? &timeout_ts : NULL),
883 (UWord)NULL);
884 # elif defined(VGO_linux)
885 res = VG_(do_syscall3)(__NR_poll, (UWord)fds, nfds, timeout);
886 # elif defined(VGO_freebsd)
887 res = VG_(do_syscall3)(__NR_poll, (UWord)fds, nfds, timeout);
888 # elif defined(VGO_darwin)
889 res = VG_(do_syscall3)(__NR_poll_nocancel, (UWord)fds, nfds, timeout);
890 # elif defined(VGO_solaris)
891 struct vki_timespec ts;
892 struct vki_timespec *tsp;
894 if (timeout < 0)
895 tsp = NULL;
896 else {
897 ts.tv_sec = timeout / 1000;
898 ts.tv_nsec = (timeout % 1000) * 1000000;
899 tsp = &ts;
902 res = VG_(do_syscall4)(__NR_pollsys, (UWord)fds, nfds, (UWord)tsp, 0);
903 # else
904 # error "Unknown OS"
905 # endif
906 return res;
910 /* Performs the readlink operation and puts the result into 'buf'.
911 Note, that the string in 'buf' is *not* null-terminated. The function
912 returns the number of characters put into 'buf' or -1 if an error
913 occurred. */
914 SSizeT VG_(readlink) (const HChar* path, HChar* buf, SizeT bufsiz)
916 SysRes res;
917 /* res = readlink( path, buf, bufsiz ); */
918 # if defined(VGP_arm64_linux) || defined(VGP_nanomips_linux)
919 res = VG_(do_syscall4)(__NR_readlinkat, VKI_AT_FDCWD,
920 (UWord)path, (UWord)buf, bufsiz);
921 # elif defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_freebsd)
922 res = VG_(do_syscall3)(__NR_readlink, (UWord)path, (UWord)buf, bufsiz);
923 # elif defined(VGO_solaris)
924 res = VG_(do_syscall4)(__NR_readlinkat, VKI_AT_FDCWD, (UWord)path,
925 (UWord)buf, bufsiz);
926 # else
927 # error "Unknown OS"
928 # endif
929 return sr_isError(res) ? -1 : sr_Res(res);
932 #if defined(VGO_linux) || defined(VGO_solaris)
933 Int VG_(getdents64) (Int fd, struct vki_dirent64 *dirp, UInt count)
935 SysRes res;
936 /* res = getdents( fd, dirp, count ); */
937 # if defined(VGP_amd64_solaris)
938 /* This silently assumes that dirent64 and dirent on amd64 are same, which
939 they should always be. */
940 res = VG_(do_syscall3)(__NR_getdents, fd, (UWord)dirp, count);
941 # else
942 res = VG_(do_syscall3)(__NR_getdents64, fd, (UWord)dirp, count);
943 # if defined(VGA_mips64)
944 /* The MIPS64 getdents64() system call is only present in 3.10+ kernels.
945 If the getdents64() system call is not available fall back to using
946 getdents() and modify the result to be compatible with getdents64(). */
947 if (sr_isError(res) && (sr_Err(res) == VKI_ENOSYS)) {
948 int r;
949 res = VG_(do_syscall3)(__NR_getdents, fd, (UWord)dirp, count);
950 r = sr_Res(res);
951 if (r > 0) {
952 char *p;
953 char type;
954 union dirents {
955 struct vki_dirent m;
956 struct vki_dirent64 d;
957 } *u;
958 p = (char *)dirp;
959 do {
960 u = (union dirents *)p;
961 /* This should not happen, but just in case... */
962 if (p + u->m.d_reclen > (char *)dirp + r)
963 break;
964 /* shuffle the dirent */
965 type = *(p + u->m.d_reclen - 1);
966 VG_(memmove)(u->d.d_name, u->m.d_name,
967 u->m.d_reclen - 2
968 - offsetof(struct vki_dirent, d_name) + 1);
969 u->d.d_type = type;
970 p += u->m.d_reclen;
971 } while (p < (char *)dirp + r);
974 # endif
975 # endif
976 return sr_isError(res) ? -1 : sr_Res(res);
978 #endif
980 /* Check accessibility of a file. Returns zero for access granted,
981 nonzero otherwise. */
982 Int VG_(access) ( const HChar* path, Bool irusr, Bool iwusr, Bool ixusr )
984 # if defined(VGO_linux)
985 /* Very annoyingly, I cannot find any definition for R_OK et al in
986 the kernel interfaces. Therefore I reluctantly resort to
987 hardwiring in these magic numbers that I determined by
988 experimentation. */
989 # define VKI_R_OK 4
990 # define VKI_W_OK 2
991 # define VKI_X_OK 1
992 # endif
994 UWord w = (irusr ? VKI_R_OK : 0)
995 | (iwusr ? VKI_W_OK : 0)
996 | (ixusr ? VKI_X_OK : 0);
997 # if defined(VGP_arm64_linux) || defined(VGP_nanomips_linux)
998 SysRes res = VG_(do_syscall3)(__NR_faccessat, VKI_AT_FDCWD, (UWord)path, w);
999 # elif defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_freebsd)
1000 SysRes res = VG_(do_syscall2)(__NR_access, (UWord)path, w);
1001 # elif defined(VGO_solaris)
1002 SysRes res = VG_(do_syscall4)(__NR_faccessat, VKI_AT_FDCWD, (UWord)path,
1003 w, 0);
1004 # else
1005 # error "Unknown OS"
1006 # endif
1007 return sr_isError(res) ? 1 : 0;
1009 # if defined(VGO_linux)
1010 # undef VKI_R_OK
1011 # undef VKI_W_OK
1012 # undef VKI_X_OK
1013 # endif
1017 Emulate the normal Unix permissions checking algorithm.
1019 If owner matches, then use the owner permissions, else
1020 if group matches, then use the group permissions, else
1021 use other permissions.
1023 Note that we can't deal properly with SUID/SGID. By default
1024 (allow_setuid == False), we refuse to run them (otherwise the
1025 executable may misbehave if it doesn't have the permissions it
1026 thinks it does). However, the caller may indicate that setuid
1027 executables are allowed, for example if we are going to exec them
1028 but not trace into them (iow, client sys_execve when
1029 clo_trace_children == False).
1031 If VKI_EACCES is returned (iow, permission was refused), then
1032 *is_setuid is set to True iff permission was refused because the
1033 executable is setuid.
1035 /* returns: 0 = success, non-0 is failure */
1036 Int VG_(check_executable)(/*OUT*/Bool* is_setuid,
1037 const HChar* f, Bool allow_setuid)
1039 struct vg_stat st;
1040 SysRes res = VG_(stat)(f, &st);
1042 if (is_setuid)
1043 *is_setuid = False;
1045 if (sr_isError(res)) {
1046 return sr_Err(res);
1049 if ( VKI_S_ISDIR (st.mode) ) {
1050 return VKI_EACCES;
1053 if ( (st.mode & (VKI_S_ISUID | VKI_S_ISGID)) && !allow_setuid ) {
1054 if (is_setuid)
1055 *is_setuid = True;
1056 return VKI_EACCES;
1059 res = VG_(getxattr)(f, "security.capability", (Addr)0, 0);
1060 if (!sr_isError(res) && !allow_setuid) {
1061 if (is_setuid)
1062 *is_setuid = True;
1063 return VKI_EACCES;
1066 if (VG_(geteuid)() == st.uid) {
1067 if (!(st.mode & VKI_S_IXUSR))
1068 return VKI_EACCES;
1069 } else {
1070 Int grpmatch = 0;
1072 if (VG_(getegid)() == st.gid)
1073 grpmatch = 1;
1074 else {
1075 UInt *groups = NULL;
1076 Int ngrp;
1078 /* Find out # groups, allocate large enough array and fetch groups */
1079 ngrp = VG_(getgroups)(0, NULL);
1080 if (ngrp != -1) {
1081 groups = VG_(malloc)("check_executable", ngrp * sizeof *groups);
1082 ngrp = VG_(getgroups)(ngrp, groups);
1085 Int i;
1086 /* ngrp will be -1 if VG_(getgroups) failed. */
1087 for (i = 0; i < ngrp; i++) {
1088 if (groups[i] == st.gid) {
1089 grpmatch = 1;
1090 break;
1093 VG_(free)(groups);
1096 if (grpmatch) {
1097 if (!(st.mode & VKI_S_IXGRP)) {
1098 return VKI_EACCES;
1100 } else if (!(st.mode & VKI_S_IXOTH)) {
1101 return VKI_EACCES;
1105 return 0;
1108 SysRes VG_(pread) ( Int fd, void* buf, Int count, OffT offset )
1110 SysRes res;
1111 // on 32 bits platforms, we receive a 32 bits OffT but
1112 // we must extend it to pass a long long 64 bits.
1113 # if defined(VGP_x86_linux)
1114 vg_assert(sizeof(OffT) == 4);
1115 res = VG_(do_syscall5)(__NR_pread64, fd, (UWord)buf, count,
1116 offset, 0); // Little endian long long
1117 return res;
1118 # elif defined(VGP_arm_linux)
1119 vg_assert(sizeof(OffT) == 4);
1120 res = VG_(do_syscall5)(__NR_pread64, fd, (UWord)buf, count,
1121 0, offset); // Big endian long long
1122 return res;
1123 # elif defined(VGP_ppc32_linux)
1124 vg_assert(sizeof(OffT) == 4);
1125 res = VG_(do_syscall6)(__NR_pread64, fd, (UWord)buf, count,
1126 0, // Padding needed on PPC32
1127 0, offset); // Big endian long long
1128 return res;
1129 # elif (defined(VGP_mips32_linux) || defined(VGP_nanomips_linux)) \
1130 && (VKI_LITTLE_ENDIAN)
1131 vg_assert(sizeof(OffT) == 4);
1132 res = VG_(do_syscall6)(__NR_pread64, fd, (UWord)buf, count,
1133 0, offset, 0);
1134 return res;
1135 # elif (defined(VGP_mips32_linux) || defined(VGP_nanomips_linux)) \
1136 && (VKI_BIG_ENDIAN)
1137 vg_assert(sizeof(OffT) == 4);
1138 res = VG_(do_syscall6)(__NR_pread64, fd, (UWord)buf, count,
1139 0, 0, offset);
1140 return res;
1141 # elif defined(VGP_amd64_linux) || defined(VGP_s390x_linux) \
1142 || defined(VGP_ppc64be_linux) || defined(VGP_ppc64le_linux) \
1143 || defined(VGP_mips64_linux) || defined(VGP_arm64_linux)
1144 res = VG_(do_syscall4)(__NR_pread64, fd, (UWord)buf, count, offset);
1145 return res;
1146 # elif defined(VGP_amd64_freebsd) || defined(VGP_arm64_freebsd)
1147 vg_assert(sizeof(OffT) == 8);
1148 res = VG_(do_syscall4)(__NR_pread, fd, (UWord)buf, count, offset);
1149 return res;
1150 # elif defined(VGP_x86_freebsd)
1151 vg_assert(sizeof(OffT) == 8);
1152 res = VG_(do_syscall5)(__NR_pread, fd, (UWord)buf, count,
1153 offset & 0xffffffff, offset >> 32);
1154 return res;
1155 # elif defined(VGP_amd64_darwin)
1156 vg_assert(sizeof(OffT) == 8);
1157 res = VG_(do_syscall4)(__NR_pread_nocancel, fd, (UWord)buf, count, offset);
1158 return res;
1159 # elif defined(VGP_x86_darwin)
1160 vg_assert(sizeof(OffT) == 8);
1161 res = VG_(do_syscall5)(__NR_pread_nocancel, fd, (UWord)buf, count,
1162 offset & 0xffffffff, offset >> 32);
1163 return res;
1164 # elif defined(VGP_x86_solaris)
1165 vg_assert(sizeof(OffT) == 4);
1166 res = VG_(do_syscall4)(__NR_pread, fd, (UWord)buf, count, offset);
1167 return res;
1168 # elif defined(VGP_amd64_solaris)
1169 vg_assert(sizeof(OffT) == 8);
1170 res = VG_(do_syscall4)(__NR_pread, fd, (UWord)buf, count, offset);
1171 return res;
1172 # else
1173 # error "Unknown platform"
1174 # endif
1177 /* Return the name of a directory for temporary files. */
1178 const HChar *VG_(tmpdir)(void)
1180 const HChar *tmpdir;
1182 tmpdir = VG_(getenv)("TMPDIR");
1183 if (tmpdir == NULL || *tmpdir == '\0') tmpdir = VG_TMPDIR;
1184 if (tmpdir == NULL || *tmpdir == '\0') tmpdir = "/tmp"; /* fallback */
1186 return tmpdir;
1189 static const HChar mkstemp_format[] = "%s/valgrind_%s_%08x";
1191 SizeT VG_(mkstemp_fullname_bufsz) ( SizeT part_of_name_len )
1193 return VG_(strlen)(mkstemp_format)
1194 + VG_(strlen)(VG_(tmpdir)()) - 2 // %s tmpdir
1195 + part_of_name_len - 2 // %s part_of_name
1196 + 8 - 4 // %08x
1197 + 1; // trailing 0
1201 Int VG_(mkstemp) ( const HChar* part_of_name, /*OUT*/HChar* fullname )
1203 Int n, tries;
1204 UInt seed;
1205 SysRes sres;
1206 const HChar *tmpdir;
1208 vg_assert(part_of_name);
1209 vg_assert(fullname);
1210 n = VG_(strlen)(part_of_name);
1211 vg_assert(n > 0 && n < 100);
1213 seed = (VG_(getpid)() << 9) ^ VG_(getppid)();
1215 /* Determine sensible location for temporary files */
1216 tmpdir = VG_(tmpdir)();
1218 tries = 0;
1219 while (True) {
1220 if (tries++ > 10)
1221 return -1;
1222 VG_(sprintf)( fullname, mkstemp_format,
1223 tmpdir, part_of_name, VG_(random)( &seed ));
1224 if (0)
1225 VG_(printf)("VG_(mkstemp): trying: %s\n", fullname);
1227 sres = VG_(open)(fullname,
1228 VKI_O_CREAT|VKI_O_RDWR|VKI_O_EXCL|VKI_O_TRUNC,
1229 VKI_S_IRUSR|VKI_S_IWUSR);
1230 if (sr_isError(sres)) {
1231 VG_(umsg)("VG_(mkstemp): failed to create temp file: %s\n", fullname);
1232 continue;
1234 /* VG_(safe_fd) doesn't return if it fails. */
1235 return VG_(safe_fd)( sr_Res(sres) );
1237 /* NOTREACHED */
1241 /* ---------------------------------------------------------------------
1242 Socket-related stuff.
1243 ------------------------------------------------------------------ */
1245 static
1246 Int parse_inet_addr_and_port ( const HChar* str, UInt* ip_addr, UShort* port );
1248 static
1249 Int my_connect ( Int sockfd, struct vki_sockaddr_in* serv_addr, Int addrlen );
1251 UInt VG_(htonl) ( UInt x )
1253 # if defined(VG_BIGENDIAN)
1254 return x;
1255 # else
1256 return
1257 (((x >> 24) & 0xFF) << 0) | (((x >> 16) & 0xFF) << 8)
1258 | (((x >> 8) & 0xFF) << 16) | (((x >> 0) & 0xFF) << 24);
1259 # endif
1262 UInt VG_(ntohl) ( UInt x )
1264 # if defined(VG_BIGENDIAN)
1265 return x;
1266 # else
1267 return
1268 (((x >> 24) & 0xFF) << 0) | (((x >> 16) & 0xFF) << 8)
1269 | (((x >> 8) & 0xFF) << 16) | (((x >> 0) & 0xFF) << 24);
1270 # endif
1273 UShort VG_(htons) ( UShort x )
1275 # if defined(VG_BIGENDIAN)
1276 return x;
1277 # else
1278 return
1279 (((x >> 8) & 0xFF) << 0) | (((x >> 0) & 0xFF) << 8);
1280 # endif
1283 UShort VG_(ntohs) ( UShort x )
1285 # if defined(VG_BIGENDIAN)
1286 return x;
1287 # else
1288 return
1289 (((x >> 8) & 0xFF) << 0) | (((x >> 0) & 0xFF) << 8);
1290 # endif
1294 /* The main function.
1296 Supplied string contains either an ip address "192.168.0.1" or
1297 an ip address and port pair, "192.168.0.1:1500". Parse these,
1298 and return:
1299 -1 if there is a parse error
1300 -2 if no parse error, but specified host:port cannot be opened
1301 the relevant file (socket) descriptor, otherwise.
1302 is used.
1304 Int VG_(connect_via_socket)( const HChar* str )
1306 # if defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_solaris) || defined(VGO_freebsd)
1307 Int sd, res;
1308 struct vki_sockaddr_in servAddr;
1309 UInt ip = 0;
1310 UShort port = VG_CLO_DEFAULT_LOGPORT;
1311 Bool ok = parse_inet_addr_and_port(str, &ip, &port);
1312 if (!ok)
1313 return -1;
1315 //if (0)
1316 // VG_(printf)("ip = %d.%d.%d.%d, port %d\n",
1317 // (ip >> 24) & 0xFF, (ip >> 16) & 0xFF,
1318 // (ip >> 8) & 0xFF, ip & 0xFF,
1319 // (UInt)port );
1321 servAddr.sin_family = VKI_AF_INET;
1322 servAddr.sin_addr.s_addr = VG_(htonl)(ip);
1323 servAddr.sin_port = VG_(htons)(port);
1325 /* create socket */
1326 sd = VG_(socket)(VKI_AF_INET, VKI_SOCK_STREAM, 0 /* IPPROTO_IP ? */);
1327 if (sd < 0) {
1328 /* this shouldn't happen ... nevertheless */
1329 return -2;
1332 /* connect to server */
1333 res = my_connect(sd, &servAddr, sizeof(servAddr));
1334 if (res < 0) {
1335 /* connection failed */
1336 VG_(close)(sd);
1337 return -2;
1340 return sd;
1342 # else
1343 # error "Unknown OS"
1344 # endif
1348 /* Let d = one or more digits. Accept either:
1349 d.d.d.d or d.d.d.d:d
1351 static Int parse_inet_addr_and_port ( const HChar* str, UInt* ip_addr, UShort* port )
1353 # define GET_CH ((*str) ? (*str++) : 0)
1354 UInt ipa, i, j, c, any;
1355 ipa = 0;
1356 for (i = 0; i < 4; i++) {
1357 j = 0;
1358 any = 0;
1359 while (1) {
1360 c = GET_CH;
1361 if (c < '0' || c > '9') break;
1362 j = 10 * j + (int)(c - '0');
1363 any = 1;
1365 if (any == 0 || j > 255) goto syntaxerr;
1366 ipa = (ipa << 8) + j;
1367 if (i <= 2 && c != '.') goto syntaxerr;
1369 if (c == 0 || c == ':')
1370 *ip_addr = ipa;
1371 if (c == 0) goto ok;
1372 if (c != ':') goto syntaxerr;
1373 j = 0;
1374 any = 0;
1375 while (1) {
1376 c = GET_CH;
1377 if (c < '0' || c > '9') break;
1378 j = j * 10 + (int)(c - '0');
1379 any = 1;
1380 if (j > 65535) goto syntaxerr;
1382 if (any == 0 || c != 0) goto syntaxerr;
1383 if (j < 1024) goto syntaxerr;
1384 *port = (UShort)j;
1386 return 1;
1387 syntaxerr:
1388 return 0;
1389 # undef GET_CH
1392 // GrP fixme safe_fd?
1393 Int VG_(socket) ( Int domain, Int type, Int protocol )
1395 # if defined(VGP_x86_linux) || defined(VGP_ppc32_linux) \
1396 || defined(VGP_ppc64be_linux) || defined(VGP_ppc64le_linux) \
1397 || defined(VGP_s390x_linux)
1398 SysRes res;
1399 UWord args[3];
1400 args[0] = domain;
1401 args[1] = type;
1402 args[2] = protocol;
1403 res = VG_(do_syscall2)(__NR_socketcall, VKI_SYS_SOCKET, (UWord)&args);
1404 return sr_isError(res) ? -1 : sr_Res(res);
1406 # elif defined(VGP_amd64_linux) || defined(VGP_arm_linux) \
1407 || defined(VGP_mips32_linux) || defined(VGP_mips64_linux) \
1408 || defined(VGP_arm64_linux) || defined(VGP_nanomips_linux) || defined(VGO_freebsd)
1409 SysRes res;
1410 res = VG_(do_syscall3)(__NR_socket, domain, type, protocol );
1411 return sr_isError(res) ? -1 : sr_Res(res);
1413 # elif defined(VGO_darwin)
1414 SysRes res;
1415 res = VG_(do_syscall3)(__NR_socket, domain, type, protocol);
1416 if (!sr_isError(res)) {
1417 // Set SO_NOSIGPIPE so write() returns EPIPE instead of raising SIGPIPE
1418 Int optval = 1;
1419 SysRes res2;
1420 res2 = VG_(do_syscall5)(__NR_setsockopt, sr_Res(res), VKI_SOL_SOCKET,
1421 VKI_SO_NOSIGPIPE, (UWord)&optval,
1422 sizeof(optval));
1423 // ignore setsockopt() error
1425 return sr_isError(res) ? -1 : sr_Res(res);
1427 # elif defined(VGO_solaris)
1428 /* XXX There doesn't seem to be an easy way to convince the send syscall to
1429 only return EPIPE instead of raising SIGPIPE. EPIPE is only returned if
1430 SM_KERNEL is set on the socket. Without serious hackery it looks we
1431 can't set this flag.
1433 Should we wrap the send syscall below into sigprocmask calls to block
1434 SIGPIPE?
1436 SysRes res;
1437 res = VG_(do_syscall5)(__NR_so_socket, domain, type, protocol,
1438 0 /*devpath*/, VKI_SOV_DEFAULT /*version*/);
1439 return sr_isError(res) ? -1 : sr_Res(res);
1441 # else
1442 # error "Unknown arch"
1443 # endif
1447 static
1448 Int my_connect ( Int sockfd, struct vki_sockaddr_in* serv_addr, Int addrlen )
1450 # if defined(VGP_x86_linux) || defined(VGP_ppc32_linux) \
1451 || defined(VGP_ppc64be_linux) || defined(VGP_ppc64le_linux) \
1452 || defined(VGP_s390x_linux)
1453 SysRes res;
1454 UWord args[3];
1455 args[0] = sockfd;
1456 args[1] = (UWord)serv_addr;
1457 args[2] = addrlen;
1458 res = VG_(do_syscall2)(__NR_socketcall, VKI_SYS_CONNECT, (UWord)&args);
1459 return sr_isError(res) ? -1 : sr_Res(res);
1461 # elif defined(VGP_amd64_linux) || defined(VGP_arm_linux) \
1462 || defined(VGP_mips32_linux) || defined(VGP_mips64_linux) \
1463 || defined(VGP_arm64_linux) || defined(VGP_nanomips_linux) || defined(VGO_freebsd)
1464 SysRes res;
1465 res = VG_(do_syscall3)(__NR_connect, sockfd, (UWord)serv_addr, addrlen);
1466 return sr_isError(res) ? -1 : sr_Res(res);
1468 # elif defined(VGO_darwin)
1469 SysRes res;
1470 res = VG_(do_syscall3)(__NR_connect_nocancel,
1471 sockfd, (UWord)serv_addr, addrlen);
1472 return sr_isError(res) ? -1 : sr_Res(res);
1474 # elif defined(VGO_solaris)
1475 SysRes res;
1476 res = VG_(do_syscall4)(__NR_connect, sockfd, (UWord)serv_addr, addrlen,
1477 VKI_SOV_DEFAULT /*version*/);
1478 return sr_isError(res) ? -1 : sr_Res(res);
1480 # else
1481 # error "Unknown arch"
1482 # endif
1485 Int VG_(write_socket)( Int sd, const void *msg, Int count )
1487 /* This is actually send(). */
1489 /* For Linux, VKI_MSG_NOSIGNAL is a request not to send SIGPIPE on
1490 errors on stream oriented sockets when the other end breaks the
1491 connection. The EPIPE error is still returned.
1493 For Darwin, VG_(socket)() sets SO_NOSIGPIPE to get EPIPE instead of
1494 SIGPIPE */
1496 # if defined(VGP_x86_linux) || defined(VGP_ppc32_linux) \
1497 || defined(VGP_ppc64be_linux) || defined(VGP_ppc64le_linux) \
1498 || defined(VGP_s390x_linux)
1499 SysRes res;
1500 UWord args[4];
1501 args[0] = sd;
1502 args[1] = (UWord)msg;
1503 args[2] = count;
1504 args[3] = VKI_MSG_NOSIGNAL;
1505 res = VG_(do_syscall2)(__NR_socketcall, VKI_SYS_SEND, (UWord)&args);
1506 return sr_isError(res) ? -1 : sr_Res(res);
1508 # elif defined(VGP_amd64_linux) || defined(VGP_arm_linux) \
1509 || defined(VGP_mips32_linux) || defined(VGP_mips64_linux) \
1510 || defined(VGP_arm64_linux) || defined(VGP_nanomips_linux) || defined(VGO_freebsd)
1511 SysRes res;
1512 res = VG_(do_syscall6)(__NR_sendto, sd, (UWord)msg,
1513 count, VKI_MSG_NOSIGNAL, 0,0);
1514 return sr_isError(res) ? -1 : sr_Res(res);
1516 # elif defined(VGP_x86_darwin) || defined(VGP_amd64_darwin)
1517 SysRes res;
1518 res = VG_(do_syscall3)(__NR_write_nocancel, sd, (UWord)msg, count);
1519 return sr_isError(res) ? -1 : sr_Res(res);
1521 # elif defined(VGO_solaris)
1522 SysRes res;
1523 res = VG_(do_syscall4)(__NR_send, sd, (UWord)msg, count, 0 /*flags*/);
1524 return sr_isError(res) ? -1 : sr_Res(res);
1526 # else
1527 # error "Unknown platform"
1528 # endif
1531 Int VG_(getsockname) ( Int sd, struct vki_sockaddr *name, Int *namelen)
1533 # if defined(VGP_x86_linux) || defined(VGP_ppc32_linux) \
1534 || defined(VGP_ppc64be_linux) || defined(VGP_ppc64le_linux) \
1535 || defined(VGP_s390x_linux) \
1536 || defined(VGP_mips32_linux)
1537 SysRes res;
1538 UWord args[3];
1539 args[0] = sd;
1540 args[1] = (UWord)name;
1541 args[2] = (UWord)namelen;
1542 res = VG_(do_syscall2)(__NR_socketcall, VKI_SYS_GETSOCKNAME, (UWord)&args);
1543 return sr_isError(res) ? -1 : sr_Res(res);
1545 # elif defined(VGP_amd64_linux) || defined(VGP_arm_linux) \
1546 || defined(VGP_mips64_linux) || defined(VGP_arm64_linux) \
1547 || defined(VGP_nanomips_linux) || defined(VGO_freebsd) \
1548 || defined(VGP_mips64_linux) || defined(VGP_arm64_linux)
1549 SysRes res;
1550 res = VG_(do_syscall3)( __NR_getsockname,
1551 (UWord)sd, (UWord)name, (UWord)namelen );
1552 return sr_isError(res) ? -1 : sr_Res(res);
1554 # elif defined(VGO_darwin)
1555 SysRes res;
1556 res = VG_(do_syscall3)( __NR_getsockname,
1557 (UWord)sd, (UWord)name, (UWord)namelen );
1558 return sr_isError(res) ? -1 : sr_Res(res);
1560 # elif defined(VGO_solaris)
1561 SysRes res;
1562 res = VG_(do_syscall4)(__NR_getsockname, sd, (UWord)name, (UWord)namelen,
1563 VKI_SOV_DEFAULT /*version*/);
1564 return sr_isError(res) ? -1 : sr_Res(res);
1566 # else
1567 # error "Unknown platform"
1568 # endif
1571 Int VG_(getpeername) ( Int sd, struct vki_sockaddr *name, Int *namelen)
1573 # if defined(VGP_x86_linux) || defined(VGP_ppc32_linux) \
1574 || defined(VGP_ppc64be_linux) || defined(VGP_ppc64le_linux) \
1575 || defined(VGP_s390x_linux) \
1576 || defined(VGP_mips32_linux)
1577 SysRes res;
1578 UWord args[3];
1579 args[0] = sd;
1580 args[1] = (UWord)name;
1581 args[2] = (UWord)namelen;
1582 res = VG_(do_syscall2)(__NR_socketcall, VKI_SYS_GETPEERNAME, (UWord)&args);
1583 return sr_isError(res) ? -1 : sr_Res(res);
1585 # elif defined(VGP_amd64_linux) || defined(VGP_arm_linux) \
1586 || defined(VGP_mips64_linux) || defined(VGP_arm64_linux) \
1587 || defined(VGP_nanomips_linux) || defined(VGO_freebsd)
1588 SysRes res;
1589 res = VG_(do_syscall3)( __NR_getpeername,
1590 (UWord)sd, (UWord)name, (UWord)namelen );
1591 return sr_isError(res) ? -1 : sr_Res(res);
1593 # elif defined(VGO_darwin)
1594 SysRes res;
1595 res = VG_(do_syscall3)( __NR_getpeername,
1596 (UWord)sd, (UWord)name, (UWord)namelen );
1597 return sr_isError(res) ? -1 : sr_Res(res);
1599 # elif defined(VGO_solaris)
1600 SysRes res;
1601 res = VG_(do_syscall4)(__NR_getpeername, sd, (UWord)name, (UWord)namelen,
1602 VKI_SOV_DEFAULT /*version*/);
1603 return sr_isError(res) ? -1 : sr_Res(res);
1605 # else
1606 # error "Unknown platform"
1607 # endif
1610 Int VG_(getsockopt) ( Int sd, Int level, Int optname, void *optval,
1611 Int *optlen)
1613 # if defined(VGP_x86_linux) || defined(VGP_ppc32_linux) \
1614 || defined(VGP_ppc64be_linux) || defined(VGP_ppc64le_linux) \
1615 || defined(VGP_s390x_linux)
1616 SysRes res;
1617 UWord args[5];
1618 args[0] = sd;
1619 args[1] = level;
1620 args[2] = optname;
1621 args[3] = (UWord)optval;
1622 args[4] = (UWord)optlen;
1623 res = VG_(do_syscall2)(__NR_socketcall, VKI_SYS_GETSOCKOPT, (UWord)&args);
1624 return sr_isError(res) ? -1 : sr_Res(res);
1626 # elif defined(VGP_amd64_linux) || defined(VGP_arm_linux) \
1627 || defined(VGP_mips32_linux) || defined(VGP_mips64_linux) \
1628 || defined(VGP_arm64_linux) || defined(VGP_nanomips_linux) \
1629 || defined(VGO_freebsd)
1630 SysRes res;
1631 res = VG_(do_syscall5)( __NR_getsockopt,
1632 (UWord)sd, (UWord)level, (UWord)optname,
1633 (UWord)optval, (UWord)optlen );
1634 return sr_isError(res) ? -1 : sr_Res(res);
1636 # elif defined(VGO_darwin)
1637 SysRes res;
1638 res = VG_(do_syscall5)( __NR_getsockopt,
1639 (UWord)sd, (UWord)level, (UWord)optname,
1640 (UWord)optval, (UWord)optlen );
1641 return sr_isError(res) ? -1 : sr_Res(res);
1643 # elif defined(VGO_solaris)
1644 SysRes res;
1645 res = VG_(do_syscall6)(__NR_getsockopt, sd, level, optname, (UWord)optval,
1646 (UWord)optlen, VKI_SOV_DEFAULT /*version*/);
1647 return sr_isError(res) ? -1 : sr_Res(res);
1649 # else
1650 # error "Unknown platform"
1651 # endif
1655 Int VG_(setsockopt) ( Int sd, Int level, Int optname, void *optval,
1656 Int optlen)
1658 # if defined(VGP_x86_linux) || defined(VGP_ppc32_linux) \
1659 || defined(VGP_ppc64be_linux) || defined(VGP_ppc64le_linux) \
1660 || defined(VGP_s390x_linux)
1661 SysRes res;
1662 UWord args[5];
1663 args[0] = sd;
1664 args[1] = level;
1665 args[2] = optname;
1666 args[3] = (UWord)optval;
1667 args[4] = (UWord)optlen;
1668 res = VG_(do_syscall2)(__NR_socketcall, VKI_SYS_SETSOCKOPT, (UWord)&args);
1669 return sr_isError(res) ? -1 : sr_Res(res);
1671 # elif defined(VGP_amd64_linux) || defined(VGP_arm_linux) \
1672 || defined(VGP_mips32_linux) || defined(VGP_mips64_linux) \
1673 || defined(VGP_arm64_linux) || defined(VGP_nanomips_linux)
1674 SysRes res;
1675 res = VG_(do_syscall5)( __NR_setsockopt,
1676 (UWord)sd, (UWord)level, (UWord)optname,
1677 (UWord)optval, (UWord)optlen );
1678 return sr_isError(res) ? -1 : sr_Res(res);
1680 # elif defined(VGO_darwin) || defined(VGO_freebsd)
1681 SysRes res;
1682 res = VG_(do_syscall5)( __NR_setsockopt,
1683 (UWord)sd, (UWord)level, (UWord)optname,
1684 (UWord)optval, (UWord)optlen );
1685 return sr_isError(res) ? -1 : sr_Res(res);
1687 # elif defined(VGO_solaris)
1688 SysRes res;
1689 res = VG_(do_syscall6)( __NR_setsockopt,
1690 (UWord)sd, (UWord)level, (UWord)optname,
1691 (UWord)optval, (UWord)optlen,
1692 VKI_SOV_DEFAULT /*version*/ );
1693 return sr_isError(res) ? -1 : sr_Res(res);
1695 # else
1696 # error "Unknown platform"
1697 # endif
1701 const HChar *VG_(basename)(const HChar *path)
1703 static HChar *buf = NULL;
1704 static SizeT buf_len = 0;
1705 const HChar *p, *end;
1707 if (path == NULL ||
1708 0 == VG_(strcmp)(path, ""))
1710 return ".";
1713 p = path + VG_(strlen)(path);
1714 while (p > path && *p == '/') {
1715 // skip all trailing '/'
1716 p--;
1719 if (p == path && *p == '/') return "/"; // all slashes
1721 end = p;
1723 while (p > path && *p != '/') {
1724 // now skip non '/'
1725 p--;
1728 if (*p == '/') p++;
1730 SizeT need = end-p+1 + 1;
1731 if (need > buf_len) {
1732 buf_len = (buf_len == 0) ? 500 : need;
1733 buf = VG_(realloc)("basename", buf, buf_len);
1735 VG_(strncpy)(buf, p, end-p+1);
1736 buf[end-p+1] = '\0';
1738 return buf;
1742 const HChar *VG_(dirname)(const HChar *path)
1744 static HChar *buf = NULL;
1745 static SizeT buf_len = 0;
1747 const HChar *p;
1749 if (path == NULL ||
1750 0 == VG_(strcmp)(path, "") ||
1751 0 == VG_(strcmp)(path, "/"))
1753 return ".";
1756 p = path + VG_(strlen)(path);
1757 while (p > path && *p == '/') {
1758 // skip all trailing '/'
1759 p--;
1762 while (p > path && *p != '/') {
1763 // now skip non '/'
1764 p--;
1767 if (p == path) {
1768 if (*p == '/') return "/"; // all slashes
1769 else return "."; // no slashes
1772 while (p > path && *p == '/') {
1773 // skip '/' again
1774 p--;
1777 SizeT need = p-path+1 + 1;
1778 if (need > buf_len) {
1779 buf_len = (buf_len == 0) ? 500 : need;
1780 buf = VG_(realloc)("dirname", buf, buf_len);
1782 VG_(strncpy)(buf, path, p-path+1);
1783 buf[p-path+1] = '\0';
1785 return buf;
1788 #if defined(VGO_freebsd)
1790 * I did look at nicking this from FreeBSD, it's fairly easy to port
1791 * but I was put off by the copyright and 3-clause licence
1792 * Then I looked at nicking it from glibc but that is full of
1793 * macros private functions and conditions for Windows.
1794 * So I gave up as it is only for FreeBSD 11 and 12.
1796 * It is somewhat hard-coded for sysctl_kern_proc_pathname
1797 * and PRE(sys___sysctl) assuming resolved has
1798 * VKI_PATH_MAX space.
1800 Bool VG_(realpath)(const HChar *path, HChar *resolved)
1802 vg_assert(path);
1803 vg_assert(resolved);
1804 #if (FREEBSD_VERS >= FREEBSD_13_0)
1805 return !sr_isError(VG_(do_syscall5)(__NR___realpathat, VKI_AT_FDCWD, (RegWord)path, (RegWord)resolved, VKI_PATH_MAX, 0));
1806 #else
1807 // poor man's realpath
1808 const HChar *resolved_name;
1809 HChar tmp[VKI_PATH_MAX];
1811 struct vg_stat statbuf;
1812 SysRes res = VG_(lstat)(path, &statbuf);
1814 if (sr_isError(res)) {
1815 return False;
1818 if (VKI_S_ISLNK(statbuf.mode)) {
1819 SizeT link_len = VG_(readlink)(path, tmp, VKI_PATH_MAX);
1820 tmp[link_len] = '\0';
1821 resolved_name = tmp;
1822 } else {
1823 // not a link
1824 resolved_name = path;
1827 if (resolved_name[0] != '/') {
1828 // relative path
1829 if (resolved_name[0] == '.' && resolved_name[1] == '/') {
1830 resolved_name += 2;
1832 VG_(snprintf)(resolved, VKI_PATH_MAX, "%s/%s", VG_(get_startup_wd)(), resolved_name);
1833 } else {
1834 VG_(snprintf)(resolved, VKI_PATH_MAX, "%s", resolved_name);
1837 return True;
1838 #endif
1840 #endif
1843 /*--------------------------------------------------------------------*/
1844 /*--- end ---*/
1845 /*--------------------------------------------------------------------*/