blob: c43682111b228193097780aded2845c10e78e64e [file] [log] [blame]
florian58946e92014-09-27 13:29:09 +00001/* -*- mode: C; c-basic-offset: 3; -*- */
njneb8896b2005-06-04 20:03:55 +00002
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
Elliott Hughesed398002017-06-21 14:41:24 -070011 Copyright (C) 2000-2017 Julian Seward
njneb8896b2005-06-04 20:03:55 +000012 jseward@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
njnc7561b92005-06-19 01:24:32 +000032#include "pub_core_basics.h"
sewardj4cfea4f2006-10-14 19:26:10 +000033#include "pub_core_vki.h"
sewardj9a66bb92006-10-17 01:38:13 +000034#include "pub_core_vkiscnums.h"
sewardj26b87282006-10-17 12:49:31 +000035#include "pub_core_debuglog.h"
njneb8896b2005-06-04 20:03:55 +000036#include "pub_core_libcbase.h"
37#include "pub_core_libcassert.h"
38#include "pub_core_libcfile.h"
sewardjfdf91b42005-09-28 00:53:09 +000039#include "pub_core_libcprint.h" // VG_(sprintf)
sewardj45f4e7c2005-09-27 19:20:21 +000040#include "pub_core_libcproc.h" // VG_(getpid), VG_(getppid)
sewardjfdf91b42005-09-28 00:53:09 +000041#include "pub_core_clientstate.h" // VG_(fd_hard_limit)
florian58946e92014-09-27 13:29:09 +000042#include "pub_core_mallocfree.h" // VG_(realloc)
njn9abd6082005-06-17 21:31:45 +000043#include "pub_core_syscall.h"
njneb8896b2005-06-04 20:03:55 +000044
njnf76d27a2009-05-28 01:53:07 +000045/* 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
njneb8896b2005-06-04 20:03:55 +000050/* ---------------------------------------------------------------------
51 File stuff
52 ------------------------------------------------------------------ */
53
njneb8896b2005-06-04 20:03:55 +000054/* Move an fd into the Valgrind-safe range */
55Int 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
sewardj9a66bb92006-10-17 01:38:13 +000065 /* Set the close-on-exec flag for this fd. */
njneb8896b2005-06-04 20:03:55 +000066 VG_(fcntl)(newfd, VKI_F_SETFD, VKI_FD_CLOEXEC);
67
68 vg_assert(newfd >= VG_(fd_hard_limit));
69 return newfd;
70}
71
njnae7359b2005-06-19 21:10:42 +000072/* 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,
floriana175ffb2014-10-14 21:01:33 +000074 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. */
florian3130eab2014-11-14 19:25:08 +000079Bool VG_(resolve_filename) ( Int fd, const HChar** result )
njnae7359b2005-06-19 21:10:42 +000080{
sewardj8eb8bab2015-07-21 14:44:28 +000081# if defined(VGO_linux) || defined(VGO_solaris)
floriana175ffb2014-10-14 21:01:33 +000082 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
sewardj8eb8bab2015-07-21 14:44:28 +000091 {
92# if defined(VGO_linux)
93 VG_(sprintf)(tmp, "/proc/self/fd/%d", fd);
94# elif defined(VGO_solaris)
95 VG_(sprintf)(tmp, "/proc/self/path/%d", fd);
96# endif
97 }
floriana175ffb2014-10-14 21:01:33 +000098
99 while (42) {
100 SSizeT res = VG_(readlink)(tmp, buf, bufsiz);
101 if (res < 0) break;
102 if (res == bufsiz) { // buffer too small; increase and retry
103 bufsiz += 500;
104 buf = VG_(realloc)("resolve_filename", buf, bufsiz);
105 continue;
106 }
107 vg_assert(bufsiz > res); // paranoia
108 if (buf[0] != '/') break;
109
110 buf[res] = '\0';
111 *result = buf;
njnf845f8f2005-06-23 02:26:47 +0000112 return True;
floriana175ffb2014-10-14 21:01:33 +0000113 }
114 // Failure
115 *result = NULL;
116 return False;
njndad944a2009-05-04 05:55:46 +0000117
njnf76d27a2009-05-28 01:53:07 +0000118# elif defined(VGO_darwin)
119 HChar tmp[VKI_MAXPATHLEN+1];
120 if (0 == VG_(fcntl)(fd, VKI_F_GETPATH, (UWord)tmp)) {
floriana175ffb2014-10-14 21:01:33 +0000121 static HChar *buf = NULL;
122
123 if (buf == NULL)
124 buf = VG_(malloc)("resolve_filename", VKI_MAXPATHLEN+1);
125 VG_(strcpy)( buf, tmp );
126
127 *result = buf;
128 if (buf[0] == '/') return True;
njnf76d27a2009-05-28 01:53:07 +0000129 }
floriana175ffb2014-10-14 21:01:33 +0000130 // Failure
131 *result = NULL;
njnf76d27a2009-05-28 01:53:07 +0000132 return False;
133
njn81b975c2009-04-28 05:35:53 +0000134# else
njndad944a2009-05-04 05:55:46 +0000135# error Unknown OS
njn81b975c2009-04-28 05:35:53 +0000136# endif
njnae7359b2005-06-19 21:10:42 +0000137}
138
florian19f91bb2012-11-10 22:29:54 +0000139SysRes VG_(mknod) ( const HChar* pathname, Int mode, UWord dev )
sewardj112711a2015-04-10 12:30:09 +0000140{
Elliott Hughesed398002017-06-21 14:41:24 -0700141# if defined(VGP_arm64_linux)
philippe0eb0d5a2014-02-11 23:50:16 +0000142 /* ARM64 wants to use __NR_mknodat rather than __NR_mknod. */
143 SysRes res = VG_(do_syscall4)(__NR_mknodat,
144 VKI_AT_FDCWD, (UWord)pathname, mode, dev);
145# elif defined(VGO_linux) || defined(VGO_darwin)
sewardj3b290482011-05-06 21:02:55 +0000146 SysRes res = VG_(do_syscall3)(__NR_mknod,
147 (UWord)pathname, mode, dev);
sewardj8eb8bab2015-07-21 14:44:28 +0000148# elif defined(VGO_solaris)
149 SysRes res = VG_(do_syscall4)(__NR_mknodat,
150 VKI_AT_FDCWD, (UWord)pathname, mode, dev);
sewardj3b290482011-05-06 21:02:55 +0000151# else
152# error Unknown OS
153# endif
154 return res;
155}
156
florian19f91bb2012-11-10 22:29:54 +0000157SysRes VG_(open) ( const HChar* pathname, Int flags, Int mode )
sewardjf0c12502014-01-12 12:54:00 +0000158{
Elliott Hughesed398002017-06-21 14:41:24 -0700159# if defined(VGP_arm64_linux)
sewardjf0c12502014-01-12 12:54:00 +0000160 /* ARM64 wants to use __NR_openat rather than __NR_open. */
161 SysRes res = VG_(do_syscall4)(__NR_openat,
162 VKI_AT_FDCWD, (UWord)pathname, flags, mode);
163# elif defined(VGO_linux)
njnf76d27a2009-05-28 01:53:07 +0000164 SysRes res = VG_(do_syscall3)(__NR_open,
165 (UWord)pathname, flags, mode);
166# elif defined(VGO_darwin)
167 SysRes res = VG_(do_syscall3)(__NR_open_nocancel,
168 (UWord)pathname, flags, mode);
sewardj8eb8bab2015-07-21 14:44:28 +0000169# elif defined(VGO_solaris)
170 SysRes res = VG_(do_syscall4)(__NR_openat,
171 VKI_AT_FDCWD, (UWord)pathname, flags, mode);
njnf76d27a2009-05-28 01:53:07 +0000172# else
173# error Unknown OS
174# endif
sewardj92645592005-07-23 09:18:34 +0000175 return res;
njneb8896b2005-06-04 20:03:55 +0000176}
177
florian19f91bb2012-11-10 22:29:54 +0000178Int VG_(fd_open) (const HChar* pathname, Int flags, Int mode)
sewardj3b290482011-05-06 21:02:55 +0000179{
180 SysRes sr;
181 sr = VG_(open) (pathname, flags, mode);
182 if (sr_isError (sr))
183 return -1;
184 else
185 return sr_Res (sr);
186}
187
njneb8896b2005-06-04 20:03:55 +0000188void VG_(close) ( Int fd )
189{
njnf76d27a2009-05-28 01:53:07 +0000190 /* Hmm. Return value is not checked. That's uncool. */
sewardj8eb8bab2015-07-21 14:44:28 +0000191# if defined(VGO_linux) || defined(VGO_solaris)
sewardja8d8e232005-06-07 20:04:56 +0000192 (void)VG_(do_syscall1)(__NR_close, fd);
njnf76d27a2009-05-28 01:53:07 +0000193# elif defined(VGO_darwin)
194 (void)VG_(do_syscall1)(__NR_close_nocancel, fd);
195# else
196# error Unknown OS
197# endif
njneb8896b2005-06-04 20:03:55 +0000198}
199
200Int VG_(read) ( Int fd, void* buf, Int count)
201{
sewardj9a66bb92006-10-17 01:38:13 +0000202 Int ret;
sewardj8eb8bab2015-07-21 14:44:28 +0000203# if defined(VGO_linux) || defined(VGO_solaris)
sewardja8d8e232005-06-07 20:04:56 +0000204 SysRes res = VG_(do_syscall3)(__NR_read, fd, (UWord)buf, count);
njnf76d27a2009-05-28 01:53:07 +0000205# elif defined(VGO_darwin)
206 SysRes res = VG_(do_syscall3)(__NR_read_nocancel, fd, (UWord)buf, count);
207# else
208# error Unknown OS
209# endif
njncda2f0f2009-05-18 02:12:08 +0000210 if (sr_isError(res)) {
211 ret = - (Int)(Word)sr_Err(res);
sewardj9a66bb92006-10-17 01:38:13 +0000212 vg_assert(ret < 0);
213 } else {
njncda2f0f2009-05-18 02:12:08 +0000214 ret = (Int)(Word)sr_Res(res);
sewardj9a66bb92006-10-17 01:38:13 +0000215 vg_assert(ret >= 0);
216 }
217 return ret;
njneb8896b2005-06-04 20:03:55 +0000218}
219
220Int VG_(write) ( Int fd, const void* buf, Int count)
221{
sewardj9a66bb92006-10-17 01:38:13 +0000222 Int ret;
sewardj8eb8bab2015-07-21 14:44:28 +0000223# if defined(VGO_linux) || defined(VGO_solaris)
sewardja8d8e232005-06-07 20:04:56 +0000224 SysRes res = VG_(do_syscall3)(__NR_write, fd, (UWord)buf, count);
njnf76d27a2009-05-28 01:53:07 +0000225# elif defined(VGO_darwin)
226 SysRes res = VG_(do_syscall3)(__NR_write_nocancel, fd, (UWord)buf, count);
227# else
228# error "Unknown OS"
229# endif
njncda2f0f2009-05-18 02:12:08 +0000230 if (sr_isError(res)) {
231 ret = - (Int)(Word)sr_Err(res);
sewardj9a66bb92006-10-17 01:38:13 +0000232 vg_assert(ret < 0);
233 } else {
njncda2f0f2009-05-18 02:12:08 +0000234 ret = (Int)(Word)sr_Res(res);
sewardj9a66bb92006-10-17 01:38:13 +0000235 vg_assert(ret >= 0);
236 }
237 return ret;
njneb8896b2005-06-04 20:03:55 +0000238}
239
njncda2f0f2009-05-18 02:12:08 +0000240
njneb8896b2005-06-04 20:03:55 +0000241Int VG_(pipe) ( Int fd[2] )
242{
petarj4df0bfc2013-02-27 23:17:33 +0000243# if defined(VGP_mips32_linux) || defined(VGP_mips64_linux)
sewardj5db15402012-06-07 09:13:21 +0000244 /* __NR_pipe has a strange return convention on mips32-linux. */
petarj4df0bfc2013-02-27 23:17:33 +0000245 SysRes res = VG_(do_syscall1)(__NR_pipe, (UWord)fd);
sewardj5db15402012-06-07 09:13:21 +0000246 if (!sr_isError(res)) {
247 fd[0] = (Int)sr_Res(res);
248 fd[1] = (Int)sr_ResEx(res);
249 return 0;
250 } else {
251 return -1;
252 }
Elliott Hughesed398002017-06-21 14:41:24 -0700253# elif defined(VGP_arm64_linux)
sewardjf0c12502014-01-12 12:54:00 +0000254 SysRes res = VG_(do_syscall2)(__NR_pipe2, (UWord)fd, 0);
255 return sr_isError(res) ? -1 : 0;
sewardj5db15402012-06-07 09:13:21 +0000256# elif defined(VGO_linux)
sewardja8d8e232005-06-07 20:04:56 +0000257 SysRes res = VG_(do_syscall1)(__NR_pipe, (UWord)fd);
njncda2f0f2009-05-18 02:12:08 +0000258 return sr_isError(res) ? -1 : 0;
njnf76d27a2009-05-28 01:53:07 +0000259# elif defined(VGO_darwin)
260 /* __NR_pipe is UX64, so produces a double-word result */
261 SysRes res = VG_(do_syscall0)(__NR_pipe);
262 if (!sr_isError(res)) {
263 fd[0] = (Int)sr_Res(res);
264 fd[1] = (Int)sr_ResHI(res);
265 }
266 return sr_isError(res) ? -1 : 0;
sewardj8eb8bab2015-07-21 14:44:28 +0000267# elif defined(VGO_solaris)
268# if defined(SOLARIS_NEW_PIPE_SYSCALL)
269 SysRes res = VG_(do_syscall2)(__NR_pipe, (UWord)fd, 0);
270 return sr_isError(res) ? -1 : 0;
271# else
272 SysRes res = VG_(do_syscall0)(__NR_pipe);
273 if (!sr_isError(res)) {
274 fd[0] = (Int)sr_Res(res);
275 fd[1] = (Int)sr_ResHI(res);
276 }
277 return sr_isError(res) ? -1 : 0;
278# endif
njncda2f0f2009-05-18 02:12:08 +0000279# else
280# error "Unknown OS"
281# endif
njneb8896b2005-06-04 20:03:55 +0000282}
283
tomc17c6ef2011-07-13 09:02:14 +0000284Off64T VG_(lseek) ( Int fd, Off64T offset, Int whence )
njneb8896b2005-06-04 20:03:55 +0000285{
sewardj6e9de462011-06-28 07:25:29 +0000286# if defined(VGO_linux) || defined(VGP_amd64_darwin)
tomc17c6ef2011-07-13 09:02:14 +0000287# if defined(__NR__llseek)
288 Off64T result;
289 SysRes res = VG_(do_syscall5)(__NR__llseek, fd,
290 offset >> 32, offset & 0xffffffff,
tomf9b1d732011-07-13 10:05:24 +0000291 (UWord)&result, whence);
tomc17c6ef2011-07-13 09:02:14 +0000292 return sr_isError(res) ? (-1) : result;
293# else
sewardja8d8e232005-06-07 20:04:56 +0000294 SysRes res = VG_(do_syscall3)(__NR_lseek, fd, offset, whence);
tomc17c6ef2011-07-13 09:02:14 +0000295 vg_assert(sizeof(Off64T) == sizeof(Word));
296 return sr_isError(res) ? (-1) : sr_Res(res);
297# endif
njnf76d27a2009-05-28 01:53:07 +0000298# elif defined(VGP_x86_darwin)
299 SysRes res = VG_(do_syscall4)(__NR_lseek, fd,
300 offset & 0xffffffff, offset >> 32, whence);
tomc17c6ef2011-07-13 09:02:14 +0000301 return sr_isError(res) ? (-1) : sr_Res(res);
sewardj8eb8bab2015-07-21 14:44:28 +0000302# elif defined(VGP_x86_solaris)
303 SysRes res = VG_(do_syscall4)(__NR_llseek, fd,
304 offset & 0xffffffff, offset >> 32, whence);
305 return sr_isError(res) ? (-1) : ((ULong)sr_ResHI(res) << 32 | sr_Res(res));
306# elif defined(VGP_amd64_solaris)
307 SysRes res = VG_(do_syscall3)(__NR_lseek, fd, offset, whence);
308 vg_assert(sizeof(Off64T) == sizeof(Word));
309 return sr_isError(res) ? (-1) : sr_Res(res);
njncda2f0f2009-05-18 02:12:08 +0000310# else
311# error "Unknown plat"
312# endif
sewardj45f4e7c2005-09-27 19:20:21 +0000313 /* if you change the error-reporting conventions of this, also
philippe8050bb72012-04-13 23:07:29 +0000314 change all usage points. */
njneb8896b2005-06-04 20:03:55 +0000315}
316
sewardjec61b652008-08-19 07:03:04 +0000317
318/* stat/fstat support. It's uggerly. We have impedance-match into a
319 'struct vg_stat' in order to have a single structure that callers
320 can use consistently on all platforms. */
321
322#define TRANSLATE_TO_vg_stat(_p_vgstat, _p_vkistat) \
323 do { \
njn9c20ece2009-05-20 02:02:30 +0000324 (_p_vgstat)->dev = (ULong)( (_p_vkistat)->st_dev ); \
325 (_p_vgstat)->ino = (ULong)( (_p_vkistat)->st_ino ); \
326 (_p_vgstat)->nlink = (ULong)( (_p_vkistat)->st_nlink ); \
327 (_p_vgstat)->mode = (UInt) ( (_p_vkistat)->st_mode ); \
328 (_p_vgstat)->uid = (UInt) ( (_p_vkistat)->st_uid ); \
329 (_p_vgstat)->gid = (UInt) ( (_p_vkistat)->st_gid ); \
330 (_p_vgstat)->rdev = (ULong)( (_p_vkistat)->st_rdev ); \
331 (_p_vgstat)->size = (Long) ( (_p_vkistat)->st_size ); \
332 (_p_vgstat)->blksize = (ULong)( (_p_vkistat)->st_blksize ); \
333 (_p_vgstat)->blocks = (ULong)( (_p_vkistat)->st_blocks ); \
334 (_p_vgstat)->atime = (ULong)( (_p_vkistat)->st_atime ); \
335 (_p_vgstat)->atime_nsec = (ULong)( (_p_vkistat)->st_atime_nsec ); \
336 (_p_vgstat)->mtime = (ULong)( (_p_vkistat)->st_mtime ); \
337 (_p_vgstat)->mtime_nsec = (ULong)( (_p_vkistat)->st_mtime_nsec ); \
338 (_p_vgstat)->ctime = (ULong)( (_p_vkistat)->st_ctime ); \
339 (_p_vgstat)->ctime_nsec = (ULong)( (_p_vkistat)->st_ctime_nsec ); \
sewardjec61b652008-08-19 07:03:04 +0000340 } while (0)
341
florian19f91bb2012-11-10 22:29:54 +0000342SysRes VG_(stat) ( const HChar* file_name, struct vg_stat* vgbuf )
njneb8896b2005-06-04 20:03:55 +0000343{
sewardjec61b652008-08-19 07:03:04 +0000344 SysRes res;
345 VG_(memset)(vgbuf, 0, sizeof(*vgbuf));
njncda2f0f2009-05-18 02:12:08 +0000346
njnf76d27a2009-05-28 01:53:07 +0000347# if defined(VGO_linux) || defined(VGO_darwin)
njncda2f0f2009-05-18 02:12:08 +0000348 /* First try with stat64. If that doesn't work out, fall back to
349 the vanilla version. */
sewardjec61b652008-08-19 07:03:04 +0000350# if defined(__NR_stat64)
351 { struct vki_stat64 buf64;
352 res = VG_(do_syscall2)(__NR_stat64, (UWord)file_name, (UWord)&buf64);
njncda2f0f2009-05-18 02:12:08 +0000353 if (!(sr_isError(res) && sr_Err(res) == VKI_ENOSYS)) {
sewardjec61b652008-08-19 07:03:04 +0000354 /* Success, or any failure except ENOSYS */
njncda2f0f2009-05-18 02:12:08 +0000355 if (!sr_isError(res))
sewardjec61b652008-08-19 07:03:04 +0000356 TRANSLATE_TO_vg_stat(vgbuf, &buf64);
357 return res;
358 }
359 }
njncda2f0f2009-05-18 02:12:08 +0000360# endif /* defined(__NR_stat64) */
sewardjf0c12502014-01-12 12:54:00 +0000361 /* This is the fallback ("vanilla version"). */
sewardjec61b652008-08-19 07:03:04 +0000362 { struct vki_stat buf;
Elliott Hughesed398002017-06-21 14:41:24 -0700363# if defined(VGP_arm64_linux)
sewardjf0c12502014-01-12 12:54:00 +0000364 res = VG_(do_syscall3)(__NR3264_fstatat, VKI_AT_FDCWD,
365 (UWord)file_name, (UWord)&buf);
366# else
sewardjec61b652008-08-19 07:03:04 +0000367 res = VG_(do_syscall2)(__NR_stat, (UWord)file_name, (UWord)&buf);
sewardjf0c12502014-01-12 12:54:00 +0000368# endif
njncda2f0f2009-05-18 02:12:08 +0000369 if (!sr_isError(res))
sewardjec61b652008-08-19 07:03:04 +0000370 TRANSLATE_TO_vg_stat(vgbuf, &buf);
371 return res;
372 }
sewardj8eb8bab2015-07-21 14:44:28 +0000373# elif defined(VGO_solaris)
374 {
375# if defined(VGP_x86_solaris)
376 struct vki_stat64 buf64;
377 res = VG_(do_syscall4)(__NR_fstatat64, VKI_AT_FDCWD, (UWord)file_name,
378 (UWord)&buf64, 0);
379# elif defined(VGP_amd64_solaris)
380 struct vki_stat buf64;
381 res = VG_(do_syscall4)(__NR_fstatat, VKI_AT_FDCWD, (UWord)file_name,
382 (UWord)&buf64, 0);
383# else
384# error "Unknown platform"
385# endif
386 if (!sr_isError(res))
387 TRANSLATE_TO_vg_stat(vgbuf, &buf64);
388 return res;
389 }
sewardj9a66bb92006-10-17 01:38:13 +0000390# else
391# error Unknown OS
392# endif
njneb8896b2005-06-04 20:03:55 +0000393}
394
sewardjec61b652008-08-19 07:03:04 +0000395Int VG_(fstat) ( Int fd, struct vg_stat* vgbuf )
njneb8896b2005-06-04 20:03:55 +0000396{
sewardjec61b652008-08-19 07:03:04 +0000397 SysRes res;
398 VG_(memset)(vgbuf, 0, sizeof(*vgbuf));
njncda2f0f2009-05-18 02:12:08 +0000399
sewardj8eb8bab2015-07-21 14:44:28 +0000400# if defined(VGO_linux) || defined(VGO_darwin)
njncda2f0f2009-05-18 02:12:08 +0000401 /* First try with fstat64. If that doesn't work out, fall back to
402 the vanilla version. */
sewardjec61b652008-08-19 07:03:04 +0000403# if defined(__NR_fstat64)
404 { struct vki_stat64 buf64;
405 res = VG_(do_syscall2)(__NR_fstat64, (UWord)fd, (UWord)&buf64);
njncda2f0f2009-05-18 02:12:08 +0000406 if (!(sr_isError(res) && sr_Err(res) == VKI_ENOSYS)) {
sewardjec61b652008-08-19 07:03:04 +0000407 /* Success, or any failure except ENOSYS */
njncda2f0f2009-05-18 02:12:08 +0000408 if (!sr_isError(res))
sewardjec61b652008-08-19 07:03:04 +0000409 TRANSLATE_TO_vg_stat(vgbuf, &buf64);
njncda2f0f2009-05-18 02:12:08 +0000410 return sr_isError(res) ? (-1) : 0;
sewardjec61b652008-08-19 07:03:04 +0000411 }
412 }
413# endif /* if defined(__NR_fstat64) */
414 { struct vki_stat buf;
415 res = VG_(do_syscall2)(__NR_fstat, (UWord)fd, (UWord)&buf);
njncda2f0f2009-05-18 02:12:08 +0000416 if (!sr_isError(res))
sewardjec61b652008-08-19 07:03:04 +0000417 TRANSLATE_TO_vg_stat(vgbuf, &buf);
njncda2f0f2009-05-18 02:12:08 +0000418 return sr_isError(res) ? (-1) : 0;
sewardjec61b652008-08-19 07:03:04 +0000419 }
sewardj8eb8bab2015-07-21 14:44:28 +0000420# elif defined(VGO_solaris)
421 {
422# if defined(VGP_x86_solaris)
423 struct vki_stat64 buf64;
424 res = VG_(do_syscall4)(__NR_fstatat64, (UWord)fd, 0, (UWord)&buf64, 0);
425# elif defined(VGP_amd64_solaris)
426 struct vki_stat buf64;
427 res = VG_(do_syscall4)(__NR_fstatat, (UWord)fd, 0, (UWord)&buf64, 0);
428# else
429# error "Unknown platform"
430# endif
431 if (!sr_isError(res))
432 TRANSLATE_TO_vg_stat(vgbuf, &buf64);
433 return sr_isError(res) ? (-1) : 0;
434 }
sewardj9a66bb92006-10-17 01:38:13 +0000435# else
436# error Unknown OS
437# endif
njneb8896b2005-06-04 20:03:55 +0000438}
439
sewardjec61b652008-08-19 07:03:04 +0000440#undef TRANSLATE_TO_vg_stat
441
442
443Long VG_(fsize) ( Int fd )
njneb8896b2005-06-04 20:03:55 +0000444{
sewardjec61b652008-08-19 07:03:04 +0000445 struct vg_stat buf;
446 Int res = VG_(fstat)( fd, &buf );
njn9c20ece2009-05-20 02:02:30 +0000447 return (res == -1) ? (-1LL) : buf.size;
sewardj45f4e7c2005-09-27 19:20:21 +0000448}
449
tomb7c2f9d2014-05-22 08:57:06 +0000450SysRes VG_(getxattr) ( const HChar* file_name, const HChar* attr_name, Addr attr_value, SizeT attr_value_len )
451{
452 SysRes res;
453#if defined(VGO_linux)
454 res = VG_(do_syscall4)(__NR_getxattr, (UWord)file_name, (UWord)attr_name,
455 attr_value, attr_value_len);
456#else
457 res = VG_(mk_SysRes_Error)(VKI_ENOSYS);
458#endif
459 return res;
460}
461
njn63e5e6e2009-05-20 04:22:42 +0000462Bool VG_(is_dir) ( const HChar* f )
njn73750612005-10-14 03:11:30 +0000463{
sewardjec61b652008-08-19 07:03:04 +0000464 struct vg_stat buf;
sewardj9a66bb92006-10-17 01:38:13 +0000465 SysRes res = VG_(stat)(f, &buf);
njncda2f0f2009-05-18 02:12:08 +0000466 return sr_isError(res) ? False
njn9c20ece2009-05-20 02:02:30 +0000467 : VKI_S_ISDIR(buf.mode) ? True : False;
njn73750612005-10-14 03:11:30 +0000468}
469
sewardj45f4e7c2005-09-27 19:20:21 +0000470SysRes VG_(dup) ( Int oldfd )
471{
sewardj8eb8bab2015-07-21 14:44:28 +0000472# if defined(VGO_linux) || defined(VGO_darwin)
sewardj45f4e7c2005-09-27 19:20:21 +0000473 return VG_(do_syscall1)(__NR_dup, oldfd);
sewardj8eb8bab2015-07-21 14:44:28 +0000474# elif defined(VGO_solaris)
475 return VG_(do_syscall3)(__NR_fcntl, oldfd, F_DUPFD, 0);
476# else
477# error Unknown OS
478# endif
njneb8896b2005-06-04 20:03:55 +0000479}
480
njnfad98372008-10-12 19:53:28 +0000481SysRes VG_(dup2) ( Int oldfd, Int newfd )
482{
Elliott Hughesa0664b92017-04-18 17:46:52 -0700483# if defined(VGP_arm64_linux)
484 /* We only have dup3, that means we have to mimic dup2.
485 The only real difference is when oldfd == newfd.
486 dup3 always returns an error, but dup2 returns only an
487 error if the fd is invalid, otherwise it returns newfd. */
488 if (oldfd == newfd) {
489 if (VG_(fcntl)(oldfd, VKI_F_GETFL, 0) == -1)
490 return VG_(mk_SysRes_Error)(VKI_EBADF);
491 return VG_(mk_SysRes_Success)(newfd);
492 }
493 return VG_(do_syscall3)(__NR_dup3, oldfd, newfd, 0);
494# elif defined(VGO_linux) || defined(VGO_darwin)
njnfad98372008-10-12 19:53:28 +0000495 return VG_(do_syscall2)(__NR_dup2, oldfd, newfd);
sewardj8eb8bab2015-07-21 14:44:28 +0000496# elif defined(VGO_solaris)
497 return VG_(do_syscall3)(__NR_fcntl, oldfd, F_DUP2FD, newfd);
sewardj485ce162008-10-22 00:57:29 +0000498# else
499# error Unknown OS
500# endif
njnfad98372008-10-12 19:53:28 +0000501}
502
njn327fe8a2005-06-12 02:49:35 +0000503/* Returns -1 on error. */
njnbb7af3f2009-05-22 07:08:12 +0000504Int VG_(fcntl) ( Int fd, Int cmd, Addr arg )
njn327fe8a2005-06-12 02:49:35 +0000505{
sewardj8eb8bab2015-07-21 14:44:28 +0000506# if defined(VGO_linux) || defined(VGO_solaris)
njn327fe8a2005-06-12 02:49:35 +0000507 SysRes res = VG_(do_syscall3)(__NR_fcntl, fd, cmd, arg);
njnf76d27a2009-05-28 01:53:07 +0000508# elif defined(VGO_darwin)
509 SysRes res = VG_(do_syscall3)(__NR_fcntl_nocancel, fd, cmd, arg);
510# else
511# error "Unknown OS"
512# endif
njncda2f0f2009-05-18 02:12:08 +0000513 return sr_isError(res) ? -1 : sr_Res(res);
njn327fe8a2005-06-12 02:49:35 +0000514}
515
florian19f91bb2012-11-10 22:29:54 +0000516Int VG_(rename) ( const HChar* old_name, const HChar* new_name )
njneb8896b2005-06-04 20:03:55 +0000517{
Elliott Hughesed398002017-06-21 14:41:24 -0700518# if defined(VGO_solaris) || defined(VGP_arm64_linux)
sewardj8eb8bab2015-07-21 14:44:28 +0000519 SysRes res = VG_(do_syscall4)(__NR_renameat, VKI_AT_FDCWD, (UWord)old_name,
520 VKI_AT_FDCWD, (UWord)new_name);
Elliott Hughesa0664b92017-04-18 17:46:52 -0700521# elif defined(VGO_linux) || defined(VGO_darwin)
522 SysRes res = VG_(do_syscall2)(__NR_rename, (UWord)old_name, (UWord)new_name);
sewardj8eb8bab2015-07-21 14:44:28 +0000523# else
524# error "Unknown OS"
sewardj112711a2015-04-10 12:30:09 +0000525# endif
njncda2f0f2009-05-18 02:12:08 +0000526 return sr_isError(res) ? (-1) : 0;
njneb8896b2005-06-04 20:03:55 +0000527}
528
florian19f91bb2012-11-10 22:29:54 +0000529Int VG_(unlink) ( const HChar* file_name )
njneb8896b2005-06-04 20:03:55 +0000530{
Elliott Hughesed398002017-06-21 14:41:24 -0700531# if defined(VGP_arm64_linux)
sewardjf0c12502014-01-12 12:54:00 +0000532 SysRes res = VG_(do_syscall2)(__NR_unlinkat, VKI_AT_FDCWD,
533 (UWord)file_name);
sewardj8eb8bab2015-07-21 14:44:28 +0000534# elif defined(VGO_linux) || defined(VGO_darwin)
sewardja8d8e232005-06-07 20:04:56 +0000535 SysRes res = VG_(do_syscall1)(__NR_unlink, (UWord)file_name);
sewardj8eb8bab2015-07-21 14:44:28 +0000536# elif defined(VGO_solaris)
537 SysRes res = VG_(do_syscall3)(__NR_unlinkat, VKI_AT_FDCWD,
538 (UWord)file_name, 0);
539# else
540# error "Unknown OS"
sewardjf0c12502014-01-12 12:54:00 +0000541# endif
njncda2f0f2009-05-18 02:12:08 +0000542 return sr_isError(res) ? (-1) : 0;
njneb8896b2005-06-04 20:03:55 +0000543}
544
florian29d82f62014-09-27 17:42:07 +0000545/* The working directory at startup.
546 All that is really needed is to note the cwd at process startup.
547 Hence VG_(record_startup_wd) notes it (in a platform dependent way)
548 and VG_(get_startup_wd) produces the noted value. */
549static HChar *startup_wd;
sewardj198f34f2007-07-09 23:13:07 +0000550
551/* Record the process' working directory at startup. Is intended to
552 be called exactly once, at startup, before the working directory
Elliott Hughesa0664b92017-04-18 17:46:52 -0700553 changes. */
554void VG_(record_startup_wd) ( void )
njneb8896b2005-06-04 20:03:55 +0000555{
sewardj8eb8bab2015-07-21 14:44:28 +0000556# if defined(VGO_linux) || defined(VGO_solaris)
sewardj198f34f2007-07-09 23:13:07 +0000557 /* Simple: just ask the kernel */
florian29d82f62014-09-27 17:42:07 +0000558 SysRes res;
559 SizeT szB = 0;
560 do {
561 szB += 500;
562 startup_wd = VG_(realloc)("startup_wd", startup_wd, szB);
563 VG_(memset)(startup_wd, 0, szB);
564 res = VG_(do_syscall2)(__NR_getcwd, (UWord)startup_wd, szB-1);
Elliott Hughesa0664b92017-04-18 17:46:52 -0700565 } while (sr_isError(res) && sr_Err(res) == VKI_ERANGE);
566
567 if (sr_isError(res)) {
568 VG_(free)(startup_wd);
569 startup_wd = NULL;
570 return;
571 }
florian29d82f62014-09-27 17:42:07 +0000572
573 vg_assert(startup_wd[szB-1] == 0);
florian29d82f62014-09-27 17:42:07 +0000574
sewardj6e9de462011-06-28 07:25:29 +0000575# elif defined(VGO_darwin)
njnf76d27a2009-05-28 01:53:07 +0000576 /* We can't ask the kernel, so instead rely on launcher-*.c to
sewardj198f34f2007-07-09 23:13:07 +0000577 tell us the startup path. Note the env var is keyed to the
578 parent's PID, not ours, since our parent is the launcher
579 process. */
florian29d82f62014-09-27 17:42:07 +0000580 { HChar envvar[100]; // large enough
581 HChar* wd;
sewardj198f34f2007-07-09 23:13:07 +0000582 VG_(memset)(envvar, 0, sizeof(envvar));
583 VG_(sprintf)(envvar, "VALGRIND_STARTUP_PWD_%d_XYZZY",
584 (Int)VG_(getppid)());
585 wd = VG_(getenv)( envvar );
florian29d82f62014-09-27 17:42:07 +0000586 if (wd == NULL)
Elliott Hughesa0664b92017-04-18 17:46:52 -0700587 return;
florian29d82f62014-09-27 17:42:07 +0000588 SizeT need = VG_(strlen)(wd) + 1;
589 startup_wd = VG_(malloc)("startup_wd", need);
590 VG_(strcpy)(startup_wd, wd);
sewardj198f34f2007-07-09 23:13:07 +0000591 }
sewardj9a66bb92006-10-17 01:38:13 +0000592# else
593# error Unknown OS
594# endif
njneb8896b2005-06-04 20:03:55 +0000595}
596
Elliott Hughesa0664b92017-04-18 17:46:52 -0700597/* Return the previously acquired startup_wd or NULL. */
florian29d82f62014-09-27 17:42:07 +0000598const HChar *VG_(get_startup_wd) ( void )
sewardj198f34f2007-07-09 23:13:07 +0000599{
florian29d82f62014-09-27 17:42:07 +0000600 return startup_wd;
sewardj198f34f2007-07-09 23:13:07 +0000601}
602
philippe42545842013-12-05 22:10:55 +0000603SysRes VG_(poll) (struct vki_pollfd *fds, Int nfds, Int timeout)
sewardj3b290482011-05-06 21:02:55 +0000604{
605 SysRes res;
Elliott Hughesed398002017-06-21 14:41:24 -0700606# if defined(VGP_arm64_linux)
philippe0eb0d5a2014-02-11 23:50:16 +0000607 /* ARM64 wants to use __NR_ppoll rather than __NR_poll. */
608 struct vki_timespec timeout_ts;
609 if (timeout >= 0) {
610 timeout_ts.tv_sec = timeout / 1000;
611 timeout_ts.tv_nsec = ((long)timeout % 1000) * 1000000;
612 }
613 res = VG_(do_syscall4)(__NR_ppoll,
614 (UWord)fds, nfds,
615 (UWord)(timeout >= 0 ? &timeout_ts : NULL),
616 (UWord)NULL);
617# elif defined(VGO_linux)
sewardj3b290482011-05-06 21:02:55 +0000618 res = VG_(do_syscall3)(__NR_poll, (UWord)fds, nfds, timeout);
sewardj6caac712012-08-18 06:45:07 +0000619# elif defined(VGO_darwin)
620 res = VG_(do_syscall3)(__NR_poll_nocancel, (UWord)fds, nfds, timeout);
sewardj8eb8bab2015-07-21 14:44:28 +0000621# elif defined(VGO_solaris)
622 struct vki_timespec ts;
623 struct vki_timespec *tsp;
624
625 if (timeout < 0)
626 tsp = NULL;
627 else {
628 ts.tv_sec = timeout / 1000;
629 ts.tv_nsec = (timeout % 1000) * 1000000;
630 tsp = &ts;
631 }
632
633 res = VG_(do_syscall4)(__NR_pollsys, (UWord)fds, nfds, (UWord)tsp, 0);
sewardj6caac712012-08-18 06:45:07 +0000634# else
635# error "Unknown OS"
636# endif
philippe42545842013-12-05 22:10:55 +0000637 return res;
sewardj3b290482011-05-06 21:02:55 +0000638}
639
640
floriana175ffb2014-10-14 21:01:33 +0000641/* Performs the readlink operation and puts the result into 'buf'.
642 Note, that the string in 'buf' is *not* null-terminated. The function
643 returns the number of characters put into 'buf' or -1 if an error
644 occurred. */
645SSizeT VG_(readlink) (const HChar* path, HChar* buf, SizeT bufsiz)
njneb8896b2005-06-04 20:03:55 +0000646{
sewardja8d8e232005-06-07 20:04:56 +0000647 SysRes res;
njneb8896b2005-06-04 20:03:55 +0000648 /* res = readlink( path, buf, bufsiz ); */
Elliott Hughesed398002017-06-21 14:41:24 -0700649# if defined(VGP_arm64_linux)
sewardjf0c12502014-01-12 12:54:00 +0000650 res = VG_(do_syscall4)(__NR_readlinkat, VKI_AT_FDCWD,
651 (UWord)path, (UWord)buf, bufsiz);
sewardj8eb8bab2015-07-21 14:44:28 +0000652# elif defined(VGO_linux) || defined(VGO_darwin)
njneb8896b2005-06-04 20:03:55 +0000653 res = VG_(do_syscall3)(__NR_readlink, (UWord)path, (UWord)buf, bufsiz);
sewardj8eb8bab2015-07-21 14:44:28 +0000654# elif defined(VGO_solaris)
655 res = VG_(do_syscall4)(__NR_readlinkat, VKI_AT_FDCWD, (UWord)path,
656 (UWord)buf, bufsiz);
657# else
658# error "Unknown OS"
sewardjf0c12502014-01-12 12:54:00 +0000659# endif
njncda2f0f2009-05-18 02:12:08 +0000660 return sr_isError(res) ? -1 : sr_Res(res);
njneb8896b2005-06-04 20:03:55 +0000661}
662
sewardj8eb8bab2015-07-21 14:44:28 +0000663#if defined(VGO_linux) || defined(VGO_solaris)
mjw495c6562014-08-29 14:28:30 +0000664Int VG_(getdents64) (Int fd, struct vki_dirent64 *dirp, UInt count)
njneb8896b2005-06-04 20:03:55 +0000665{
sewardja8d8e232005-06-07 20:04:56 +0000666 SysRes res;
njneb8896b2005-06-04 20:03:55 +0000667 /* res = getdents( fd, dirp, count ); */
sewardj8eb8bab2015-07-21 14:44:28 +0000668# if defined(VGP_amd64_solaris)
669 /* This silently assumes that dirent64 and dirent on amd64 are same, which
670 they should always be. */
671 res = VG_(do_syscall3)(__NR_getdents, fd, (UWord)dirp, count);
672# else
mjw495c6562014-08-29 14:28:30 +0000673 res = VG_(do_syscall3)(__NR_getdents64, fd, (UWord)dirp, count);
Elliott Hughesa0664b92017-04-18 17:46:52 -0700674# if defined(VGA_mips64)
675 /* The MIPS64 getdents64() system call is only present in 3.10+ kernels.
676 If the getdents64() system call is not available fall back to using
677 getdents() and modify the result to be compatible with getdents64(). */
678 if (sr_isError(res) && (sr_Err(res) == VKI_ENOSYS)) {
679 int r;
680 res = VG_(do_syscall3)(__NR_getdents, fd, (UWord)dirp, count);
681 r = sr_Res(res);
682 if (r > 0) {
683 char *p;
684 char type;
685 union dirents {
686 struct vki_dirent m;
687 struct vki_dirent64 d;
688 } *u;
689 p = (char *)dirp;
690 do {
691 u = (union dirents *)p;
692 /* This should not happen, but just in case... */
693 if (p + u->m.d_reclen > (char *)dirp + r)
694 break;
695 /* shuffle the dirent */
696 type = *(p + u->m.d_reclen - 1);
697 VG_(memmove)(u->d.d_name, u->m.d_name,
698 u->m.d_reclen - 2
699 - offsetof(struct vki_dirent, d_name) + 1);
700 u->d.d_type = type;
701 p += u->m.d_reclen;
702 } while (p < (char *)dirp + r);
703 }
704 }
705# endif
sewardj8eb8bab2015-07-21 14:44:28 +0000706# endif
njncda2f0f2009-05-18 02:12:08 +0000707 return sr_isError(res) ? -1 : sr_Res(res);
njneb8896b2005-06-04 20:03:55 +0000708}
sewardjb69cd962014-09-01 22:26:18 +0000709#endif
njneb8896b2005-06-04 20:03:55 +0000710
sewardj45f4e7c2005-09-27 19:20:21 +0000711/* Check accessibility of a file. Returns zero for access granted,
712 nonzero otherwise. */
njn63e5e6e2009-05-20 04:22:42 +0000713Int VG_(access) ( const HChar* path, Bool irusr, Bool iwusr, Bool ixusr )
sewardj45f4e7c2005-09-27 19:20:21 +0000714{
sewardj9a66bb92006-10-17 01:38:13 +0000715# if defined(VGO_linux)
sewardj45f4e7c2005-09-27 19:20:21 +0000716 /* Very annoyingly, I cannot find any definition for R_OK et al in
717 the kernel interfaces. Therefore I reluctantly resort to
718 hardwiring in these magic numbers that I determined by
719 experimentation. */
njncda2f0f2009-05-18 02:12:08 +0000720# define VKI_R_OK 4
721# define VKI_W_OK 2
722# define VKI_X_OK 1
723# endif
724
sewardj9a66bb92006-10-17 01:38:13 +0000725 UWord w = (irusr ? VKI_R_OK : 0)
726 | (iwusr ? VKI_W_OK : 0)
727 | (ixusr ? VKI_X_OK : 0);
Elliott Hughesed398002017-06-21 14:41:24 -0700728# if defined(VGP_arm64_linux)
sewardjf0c12502014-01-12 12:54:00 +0000729 SysRes res = VG_(do_syscall3)(__NR_faccessat, VKI_AT_FDCWD, (UWord)path, w);
sewardj8eb8bab2015-07-21 14:44:28 +0000730# elif defined(VGO_linux) || defined(VGO_darwin)
sewardj9a66bb92006-10-17 01:38:13 +0000731 SysRes res = VG_(do_syscall2)(__NR_access, (UWord)path, w);
sewardj8eb8bab2015-07-21 14:44:28 +0000732# elif defined(VGO_solaris)
733 SysRes res = VG_(do_syscall4)(__NR_faccessat, VKI_AT_FDCWD, (UWord)path,
734 w, 0);
735# else
736# error "Unknown OS"
sewardjf0c12502014-01-12 12:54:00 +0000737# endif
njncda2f0f2009-05-18 02:12:08 +0000738 return sr_isError(res) ? 1 : 0;
739
740# if defined(VGO_linux)
741# undef VKI_R_OK
742# undef VKI_W_OK
743# undef VKI_X_OK
sewardj9a66bb92006-10-17 01:38:13 +0000744# endif
sewardj45f4e7c2005-09-27 19:20:21 +0000745}
746
njn73750612005-10-14 03:11:30 +0000747/*
748 Emulate the normal Unix permissions checking algorithm.
749
750 If owner matches, then use the owner permissions, else
751 if group matches, then use the group permissions, else
752 use other permissions.
753
sewardjc74b3ba2007-11-17 21:11:57 +0000754 Note that we can't deal properly with SUID/SGID. By default
755 (allow_setuid == False), we refuse to run them (otherwise the
756 executable may misbehave if it doesn't have the permissions it
757 thinks it does). However, the caller may indicate that setuid
758 executables are allowed, for example if we are going to exec them
759 but not trace into them (iow, client sys_execve when
760 clo_trace_children == False).
761
762 If VKI_EACCES is returned (iow, permission was refused), then
763 *is_setuid is set to True iff permission was refused because the
764 executable is setuid.
njn73750612005-10-14 03:11:30 +0000765*/
766/* returns: 0 = success, non-0 is failure */
sewardjc74b3ba2007-11-17 21:11:57 +0000767Int VG_(check_executable)(/*OUT*/Bool* is_setuid,
njn63e5e6e2009-05-20 04:22:42 +0000768 const HChar* f, Bool allow_setuid)
njn73750612005-10-14 03:11:30 +0000769{
sewardj4231a852008-08-19 08:32:03 +0000770 struct vg_stat st;
sewardj26b87282006-10-17 12:49:31 +0000771 SysRes res = VG_(stat)(f, &st);
njn73750612005-10-14 03:11:30 +0000772
sewardjc74b3ba2007-11-17 21:11:57 +0000773 if (is_setuid)
774 *is_setuid = False;
775
njncda2f0f2009-05-18 02:12:08 +0000776 if (sr_isError(res)) {
777 return sr_Err(res);
njn73750612005-10-14 03:11:30 +0000778 }
779
mjwd6edbc92015-02-09 13:27:07 +0000780 if ( VKI_S_ISDIR (st.mode) ) {
781 return VKI_EACCES;
782 }
783
njn9c20ece2009-05-20 02:02:30 +0000784 if ( (st.mode & (VKI_S_ISUID | VKI_S_ISGID)) && !allow_setuid ) {
sewardjc74b3ba2007-11-17 21:11:57 +0000785 if (is_setuid)
786 *is_setuid = True;
njn73750612005-10-14 03:11:30 +0000787 return VKI_EACCES;
788 }
789
tomb7c2f9d2014-05-22 08:57:06 +0000790 res = VG_(getxattr)(f, "security.capability", (Addr)0, 0);
791 if (!sr_isError(res) && !allow_setuid) {
792 if (is_setuid)
793 *is_setuid = True;
794 return VKI_EACCES;
795 }
796
njn9c20ece2009-05-20 02:02:30 +0000797 if (VG_(geteuid)() == st.uid) {
798 if (!(st.mode & VKI_S_IXUSR))
njn73750612005-10-14 03:11:30 +0000799 return VKI_EACCES;
800 } else {
sewardj45406ef2006-10-18 00:33:46 +0000801 Int grpmatch = 0;
njn73750612005-10-14 03:11:30 +0000802
njn9c20ece2009-05-20 02:02:30 +0000803 if (VG_(getegid)() == st.gid)
njn73750612005-10-14 03:11:30 +0000804 grpmatch = 1;
805 else {
florian94086c72014-09-30 19:26:58 +0000806 UInt *groups = NULL;
807 Int ngrp;
808
809 /* Find out # groups, allocate large enough array and fetch groups */
810 ngrp = VG_(getgroups)(0, NULL);
811 if (ngrp != -1) {
812 groups = VG_(malloc)("check_executable", ngrp * sizeof *groups);
813 ngrp = VG_(getgroups)(ngrp, groups);
814 }
815
816 Int i;
njn73750612005-10-14 03:11:30 +0000817 /* ngrp will be -1 if VG_(getgroups) failed. */
818 for (i = 0; i < ngrp; i++) {
njn9c20ece2009-05-20 02:02:30 +0000819 if (groups[i] == st.gid) {
njn73750612005-10-14 03:11:30 +0000820 grpmatch = 1;
821 break;
822 }
823 }
florian94086c72014-09-30 19:26:58 +0000824 VG_(free)(groups);
njn73750612005-10-14 03:11:30 +0000825 }
826
827 if (grpmatch) {
njn9c20ece2009-05-20 02:02:30 +0000828 if (!(st.mode & VKI_S_IXGRP)) {
njn73750612005-10-14 03:11:30 +0000829 return VKI_EACCES;
830 }
njn9c20ece2009-05-20 02:02:30 +0000831 } else if (!(st.mode & VKI_S_IXOTH)) {
njn73750612005-10-14 03:11:30 +0000832 return VKI_EACCES;
833 }
834 }
835
836 return 0;
837}
838
njnc4431bf2009-01-15 21:29:24 +0000839SysRes VG_(pread) ( Int fd, void* buf, Int count, OffT offset )
sewardj45f4e7c2005-09-27 19:20:21 +0000840{
njncda2f0f2009-05-18 02:12:08 +0000841 SysRes res;
philippe8050bb72012-04-13 23:07:29 +0000842 // on 32 bits platforms, we receive a 32 bits OffT but
843 // we must extend it to pass a long long 64 bits.
844# if defined(VGP_x86_linux)
845 vg_assert(sizeof(OffT) == 4);
846 res = VG_(do_syscall5)(__NR_pread64, fd, (UWord)buf, count,
847 offset, 0); // Little endian long long
848 return res;
849# elif defined(VGP_arm_linux)
850 vg_assert(sizeof(OffT) == 4);
851 res = VG_(do_syscall5)(__NR_pread64, fd, (UWord)buf, count,
852 0, offset); // Big endian long long
853 return res;
854# elif defined(VGP_ppc32_linux)
855 vg_assert(sizeof(OffT) == 4);
856 res = VG_(do_syscall6)(__NR_pread64, fd, (UWord)buf, count,
857 0, // Padding needed on PPC32
858 0, offset); // Big endian long long
859 return res;
petarj4df0bfc2013-02-27 23:17:33 +0000860# elif defined(VGP_mips32_linux) && (VKI_LITTLE_ENDIAN)
sewardj5db15402012-06-07 09:13:21 +0000861 vg_assert(sizeof(OffT) == 4);
862 res = VG_(do_syscall6)(__NR_pread64, fd, (UWord)buf, count,
863 0, offset, 0);
864 return res;
petarj4df0bfc2013-02-27 23:17:33 +0000865# elif defined(VGP_mips32_linux) && (VKI_BIG_ENDIAN)
sewardj5db15402012-06-07 09:13:21 +0000866 vg_assert(sizeof(OffT) == 4);
867 res = VG_(do_syscall6)(__NR_pread64, fd, (UWord)buf, count,
868 0, 0, offset);
869 return res;
carllcae0cc22014-08-07 23:17:29 +0000870# elif defined(VGP_amd64_linux) || defined(VGP_s390x_linux) \
871 || defined(VGP_ppc64be_linux) || defined(VGP_ppc64le_linux) \
Elliott Hughesed398002017-06-21 14:41:24 -0700872 || defined(VGP_mips64_linux) || defined(VGP_arm64_linux)
philippe8050bb72012-04-13 23:07:29 +0000873 res = VG_(do_syscall4)(__NR_pread64, fd, (UWord)buf, count, offset);
njncda2f0f2009-05-18 02:12:08 +0000874 return res;
njnf76d27a2009-05-28 01:53:07 +0000875# elif defined(VGP_amd64_darwin)
sewardj972316d2012-04-21 15:33:26 +0000876 vg_assert(sizeof(OffT) == 8);
njnf76d27a2009-05-28 01:53:07 +0000877 res = VG_(do_syscall4)(__NR_pread_nocancel, fd, (UWord)buf, count, offset);
878 return res;
879# elif defined(VGP_x86_darwin)
sewardj972316d2012-04-21 15:33:26 +0000880 vg_assert(sizeof(OffT) == 8);
njnf76d27a2009-05-28 01:53:07 +0000881 res = VG_(do_syscall5)(__NR_pread_nocancel, fd, (UWord)buf, count,
sewardj972316d2012-04-21 15:33:26 +0000882 offset & 0xffffffff, offset >> 32);
njnf76d27a2009-05-28 01:53:07 +0000883 return res;
sewardj8eb8bab2015-07-21 14:44:28 +0000884# elif defined(VGP_x86_solaris)
885 vg_assert(sizeof(OffT) == 4);
886 res = VG_(do_syscall4)(__NR_pread, fd, (UWord)buf, count, offset);
887 return res;
888# elif defined(VGP_amd64_solaris)
889 vg_assert(sizeof(OffT) == 8);
890 res = VG_(do_syscall4)(__NR_pread, fd, (UWord)buf, count, offset);
891 return res;
njncda2f0f2009-05-18 02:12:08 +0000892# else
893# error "Unknown platform"
894# endif
sewardj45f4e7c2005-09-27 19:20:21 +0000895}
896
florianb985e2d2011-09-29 03:03:45 +0000897/* Return the name of a directory for temporary files. */
898const HChar *VG_(tmpdir)(void)
899{
900 const HChar *tmpdir;
901
902 tmpdir = VG_(getenv)("TMPDIR");
903 if (tmpdir == NULL || *tmpdir == '\0') tmpdir = VG_TMPDIR;
904 if (tmpdir == NULL || *tmpdir == '\0') tmpdir = "/tmp"; /* fallback */
905
906 return tmpdir;
907}
908
florian60372262014-08-09 21:45:56 +0000909static const HChar mkstemp_format[] = "%s/valgrind_%s_%08x";
philippecc648262013-05-26 21:09:20 +0000910
911SizeT VG_(mkstemp_fullname_bufsz) ( SizeT part_of_name_len )
912{
913 return VG_(strlen)(mkstemp_format)
914 + VG_(strlen)(VG_(tmpdir)()) - 2 // %s tmpdir
915 + part_of_name_len - 2 // %s part_of_name
916 + 8 - 4 // %08x
917 + 1; // trailing 0
918}
919
920
philipped47676f2014-08-09 11:26:51 +0000921Int VG_(mkstemp) ( const HChar* part_of_name, /*OUT*/HChar* fullname )
sewardj45f4e7c2005-09-27 19:20:21 +0000922{
florian87c8abb2014-11-09 16:15:23 +0000923 Int n, tries;
sewardj45f4e7c2005-09-27 19:20:21 +0000924 UInt seed;
925 SysRes sres;
florian1763e812011-07-12 19:07:05 +0000926 const HChar *tmpdir;
sewardj45f4e7c2005-09-27 19:20:21 +0000927
928 vg_assert(part_of_name);
florian87c8abb2014-11-09 16:15:23 +0000929 vg_assert(fullname);
sewardj45f4e7c2005-09-27 19:20:21 +0000930 n = VG_(strlen)(part_of_name);
931 vg_assert(n > 0 && n < 100);
932
933 seed = (VG_(getpid)() << 9) ^ VG_(getppid)();
934
florian1763e812011-07-12 19:07:05 +0000935 /* Determine sensible location for temporary files */
florianb985e2d2011-09-29 03:03:45 +0000936 tmpdir = VG_(tmpdir)();
florian1763e812011-07-12 19:07:05 +0000937
sewardj45f4e7c2005-09-27 19:20:21 +0000938 tries = 0;
939 while (True) {
sewardj824b3972011-05-09 22:42:06 +0000940 if (tries++ > 10)
sewardj45f4e7c2005-09-27 19:20:21 +0000941 return -1;
florian87c8abb2014-11-09 16:15:23 +0000942 VG_(sprintf)( fullname, mkstemp_format,
florian1763e812011-07-12 19:07:05 +0000943 tmpdir, part_of_name, VG_(random)( &seed ));
sewardj45f4e7c2005-09-27 19:20:21 +0000944 if (0)
florian87c8abb2014-11-09 16:15:23 +0000945 VG_(printf)("VG_(mkstemp): trying: %s\n", fullname);
sewardj45f4e7c2005-09-27 19:20:21 +0000946
florian87c8abb2014-11-09 16:15:23 +0000947 sres = VG_(open)(fullname,
sewardj45f4e7c2005-09-27 19:20:21 +0000948 VKI_O_CREAT|VKI_O_RDWR|VKI_O_EXCL|VKI_O_TRUNC,
949 VKI_S_IRUSR|VKI_S_IWUSR);
sewardj80fc03b2011-09-26 16:46:04 +0000950 if (sr_isError(sres)) {
florian87c8abb2014-11-09 16:15:23 +0000951 VG_(umsg)("VG_(mkstemp): failed to create temp file: %s\n", fullname);
sewardj45f4e7c2005-09-27 19:20:21 +0000952 continue;
sewardj80fc03b2011-09-26 16:46:04 +0000953 }
sewardj45f4e7c2005-09-27 19:20:21 +0000954 /* VG_(safe_fd) doesn't return if it fails. */
florian87c8abb2014-11-09 16:15:23 +0000955 return VG_(safe_fd)( sr_Res(sres) );
sewardj45f4e7c2005-09-27 19:20:21 +0000956 }
957 /* NOTREACHED */
958}
959
960
njneb8896b2005-06-04 20:03:55 +0000961/* ---------------------------------------------------------------------
njn4bd96bd2009-05-22 00:52:14 +0000962 Socket-related stuff.
njneb8896b2005-06-04 20:03:55 +0000963 ------------------------------------------------------------------ */
964
965static
florian19f91bb2012-11-10 22:29:54 +0000966Int parse_inet_addr_and_port ( const HChar* str, UInt* ip_addr, UShort* port );
njneb8896b2005-06-04 20:03:55 +0000967
968static
njn4bd96bd2009-05-22 00:52:14 +0000969Int my_connect ( Int sockfd, struct vki_sockaddr_in* serv_addr, Int addrlen );
njneb8896b2005-06-04 20:03:55 +0000970
toma4a4f412005-11-17 12:01:56 +0000971UInt VG_(htonl) ( UInt x )
njneb8896b2005-06-04 20:03:55 +0000972{
sewardja1c4bfb2005-10-18 02:15:39 +0000973# if defined(VG_BIGENDIAN)
974 return x;
975# else
njneb8896b2005-06-04 20:03:55 +0000976 return
977 (((x >> 24) & 0xFF) << 0) | (((x >> 16) & 0xFF) << 8)
978 | (((x >> 8) & 0xFF) << 16) | (((x >> 0) & 0xFF) << 24);
sewardja1c4bfb2005-10-18 02:15:39 +0000979# endif
njneb8896b2005-06-04 20:03:55 +0000980}
981
toma4a4f412005-11-17 12:01:56 +0000982UInt VG_(ntohl) ( UInt x )
983{
984# if defined(VG_BIGENDIAN)
985 return x;
986# else
987 return
988 (((x >> 24) & 0xFF) << 0) | (((x >> 16) & 0xFF) << 8)
989 | (((x >> 8) & 0xFF) << 16) | (((x >> 0) & 0xFF) << 24);
990# endif
991}
992
993UShort VG_(htons) ( UShort x )
994{
995# if defined(VG_BIGENDIAN)
996 return x;
997# else
998 return
999 (((x >> 8) & 0xFF) << 0) | (((x >> 0) & 0xFF) << 8);
1000# endif
1001}
1002
1003UShort VG_(ntohs) ( UShort x )
njneb8896b2005-06-04 20:03:55 +00001004{
sewardja1c4bfb2005-10-18 02:15:39 +00001005# if defined(VG_BIGENDIAN)
1006 return x;
1007# else
njneb8896b2005-06-04 20:03:55 +00001008 return
1009 (((x >> 8) & 0xFF) << 0) | (((x >> 0) & 0xFF) << 8);
sewardja1c4bfb2005-10-18 02:15:39 +00001010# endif
njneb8896b2005-06-04 20:03:55 +00001011}
1012
1013
1014/* The main function.
1015
1016 Supplied string contains either an ip address "192.168.0.1" or
1017 an ip address and port pair, "192.168.0.1:1500". Parse these,
1018 and return:
1019 -1 if there is a parse error
1020 -2 if no parse error, but specified host:port cannot be opened
1021 the relevant file (socket) descriptor, otherwise.
1022 is used.
1023*/
florian19f91bb2012-11-10 22:29:54 +00001024Int VG_(connect_via_socket)( const HChar* str )
njneb8896b2005-06-04 20:03:55 +00001025{
sewardj8eb8bab2015-07-21 14:44:28 +00001026# if defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_solaris)
njneb8896b2005-06-04 20:03:55 +00001027 Int sd, res;
1028 struct vki_sockaddr_in servAddr;
1029 UInt ip = 0;
1030 UShort port = VG_CLO_DEFAULT_LOGPORT;
1031 Bool ok = parse_inet_addr_and_port(str, &ip, &port);
1032 if (!ok)
1033 return -1;
1034
1035 //if (0)
1036 // VG_(printf)("ip = %d.%d.%d.%d, port %d\n",
1037 // (ip >> 24) & 0xFF, (ip >> 16) & 0xFF,
1038 // (ip >> 8) & 0xFF, ip & 0xFF,
1039 // (UInt)port );
1040
1041 servAddr.sin_family = VKI_AF_INET;
toma4a4f412005-11-17 12:01:56 +00001042 servAddr.sin_addr.s_addr = VG_(htonl)(ip);
1043 servAddr.sin_port = VG_(htons)(port);
njneb8896b2005-06-04 20:03:55 +00001044
1045 /* create socket */
njn0cd5d972009-05-22 02:00:27 +00001046 sd = VG_(socket)(VKI_AF_INET, VKI_SOCK_STREAM, 0 /* IPPROTO_IP ? */);
njneb8896b2005-06-04 20:03:55 +00001047 if (sd < 0) {
sewardja1c4bfb2005-10-18 02:15:39 +00001048 /* this shouldn't happen ... nevertheless */
1049 return -2;
njneb8896b2005-06-04 20:03:55 +00001050 }
sewardja1c4bfb2005-10-18 02:15:39 +00001051
njneb8896b2005-06-04 20:03:55 +00001052 /* connect to server */
njnb143b272009-05-22 00:47:08 +00001053 res = my_connect(sd, &servAddr, sizeof(servAddr));
njneb8896b2005-06-04 20:03:55 +00001054 if (res < 0) {
sewardja1c4bfb2005-10-18 02:15:39 +00001055 /* connection failed */
1056 return -2;
njneb8896b2005-06-04 20:03:55 +00001057 }
1058
1059 return sd;
njncda2f0f2009-05-18 02:12:08 +00001060
njncda2f0f2009-05-18 02:12:08 +00001061# else
1062# error "Unknown OS"
1063# endif
njneb8896b2005-06-04 20:03:55 +00001064}
1065
1066
1067/* Let d = one or more digits. Accept either:
1068 d.d.d.d or d.d.d.d:d
1069*/
florian19f91bb2012-11-10 22:29:54 +00001070static Int parse_inet_addr_and_port ( const HChar* str, UInt* ip_addr, UShort* port )
njneb8896b2005-06-04 20:03:55 +00001071{
1072# define GET_CH ((*str) ? (*str++) : 0)
1073 UInt ipa, i, j, c, any;
1074 ipa = 0;
1075 for (i = 0; i < 4; i++) {
1076 j = 0;
1077 any = 0;
1078 while (1) {
1079 c = GET_CH;
1080 if (c < '0' || c > '9') break;
1081 j = 10 * j + (int)(c - '0');
1082 any = 1;
1083 }
1084 if (any == 0 || j > 255) goto syntaxerr;
1085 ipa = (ipa << 8) + j;
1086 if (i <= 2 && c != '.') goto syntaxerr;
1087 }
1088 if (c == 0 || c == ':')
1089 *ip_addr = ipa;
1090 if (c == 0) goto ok;
1091 if (c != ':') goto syntaxerr;
1092 j = 0;
1093 any = 0;
1094 while (1) {
1095 c = GET_CH;
1096 if (c < '0' || c > '9') break;
1097 j = j * 10 + (int)(c - '0');
1098 any = 1;
1099 if (j > 65535) goto syntaxerr;
1100 }
1101 if (any == 0 || c != 0) goto syntaxerr;
1102 if (j < 1024) goto syntaxerr;
1103 *port = (UShort)j;
1104 ok:
1105 return 1;
1106 syntaxerr:
1107 return 0;
1108# undef GET_CH
1109}
1110
njn0cd5d972009-05-22 02:00:27 +00001111// GrP fixme safe_fd?
1112Int VG_(socket) ( Int domain, Int type, Int protocol )
njneb8896b2005-06-04 20:03:55 +00001113{
njncda2f0f2009-05-18 02:12:08 +00001114# if defined(VGP_x86_linux) || defined(VGP_ppc32_linux) \
carllcae0cc22014-08-07 23:17:29 +00001115 || defined(VGP_ppc64be_linux) || defined(VGP_ppc64le_linux) \
1116 || defined(VGP_s390x_linux)
sewardja8d8e232005-06-07 20:04:56 +00001117 SysRes res;
1118 UWord args[3];
njneb8896b2005-06-04 20:03:55 +00001119 args[0] = domain;
1120 args[1] = type;
1121 args[2] = protocol;
1122 res = VG_(do_syscall2)(__NR_socketcall, VKI_SYS_SOCKET, (UWord)&args);
njncda2f0f2009-05-18 02:12:08 +00001123 return sr_isError(res) ? -1 : sr_Res(res);
cerion85665ca2005-06-20 15:51:07 +00001124
sewardj5db15402012-06-07 09:13:21 +00001125# elif defined(VGP_amd64_linux) || defined(VGP_arm_linux) \
sewardjf0c12502014-01-12 12:54:00 +00001126 || defined(VGP_mips32_linux) || defined(VGP_mips64_linux) \
Elliott Hughesed398002017-06-21 14:41:24 -07001127 || defined(VGP_arm64_linux)
sewardj1e866562005-09-28 19:58:58 +00001128 SysRes res;
1129 res = VG_(do_syscall3)(__NR_socket, domain, type, protocol );
njncda2f0f2009-05-18 02:12:08 +00001130 return sr_isError(res) ? -1 : sr_Res(res);
sewardj9a66bb92006-10-17 01:38:13 +00001131
njnf76d27a2009-05-28 01:53:07 +00001132# elif defined(VGO_darwin)
1133 SysRes res;
1134 res = VG_(do_syscall3)(__NR_socket, domain, type, protocol);
1135 if (!sr_isError(res)) {
1136 // Set SO_NOSIGPIPE so write() returns EPIPE instead of raising SIGPIPE
1137 Int optval = 1;
1138 SysRes res2;
1139 res2 = VG_(do_syscall5)(__NR_setsockopt, sr_Res(res), VKI_SOL_SOCKET,
1140 VKI_SO_NOSIGPIPE, (UWord)&optval,
1141 sizeof(optval));
1142 // ignore setsockopt() error
1143 }
1144 return sr_isError(res) ? -1 : sr_Res(res);
1145
sewardj8eb8bab2015-07-21 14:44:28 +00001146# elif defined(VGO_solaris)
1147 /* XXX There doesn't seem to be an easy way to convince the send syscall to
1148 only return EPIPE instead of raising SIGPIPE. EPIPE is only returned if
1149 SM_KERNEL is set on the socket. Without serious hackery it looks we
1150 can't set this flag.
1151
1152 Should we wrap the send syscall below into sigprocmask calls to block
1153 SIGPIPE?
1154 */
1155 SysRes res;
1156 res = VG_(do_syscall5)(__NR_so_socket, domain, type, protocol,
1157 0 /*devpath*/, VKI_SOV_DEFAULT /*version*/);
1158 return sr_isError(res) ? -1 : sr_Res(res);
1159
njncda2f0f2009-05-18 02:12:08 +00001160# else
1161# error "Unknown arch"
1162# endif
njneb8896b2005-06-04 20:03:55 +00001163}
1164
njncda2f0f2009-05-18 02:12:08 +00001165
njneb8896b2005-06-04 20:03:55 +00001166static
njn4bd96bd2009-05-22 00:52:14 +00001167Int my_connect ( Int sockfd, struct vki_sockaddr_in* serv_addr, Int addrlen )
njneb8896b2005-06-04 20:03:55 +00001168{
njncda2f0f2009-05-18 02:12:08 +00001169# if defined(VGP_x86_linux) || defined(VGP_ppc32_linux) \
carllcae0cc22014-08-07 23:17:29 +00001170 || defined(VGP_ppc64be_linux) || defined(VGP_ppc64le_linux) \
1171 || defined(VGP_s390x_linux)
sewardja8d8e232005-06-07 20:04:56 +00001172 SysRes res;
1173 UWord args[3];
njneb8896b2005-06-04 20:03:55 +00001174 args[0] = sockfd;
1175 args[1] = (UWord)serv_addr;
1176 args[2] = addrlen;
1177 res = VG_(do_syscall2)(__NR_socketcall, VKI_SYS_CONNECT, (UWord)&args);
njncda2f0f2009-05-18 02:12:08 +00001178 return sr_isError(res) ? -1 : sr_Res(res);
cerion85665ca2005-06-20 15:51:07 +00001179
sewardj5db15402012-06-07 09:13:21 +00001180# elif defined(VGP_amd64_linux) || defined(VGP_arm_linux) \
sewardjf0c12502014-01-12 12:54:00 +00001181 || defined(VGP_mips32_linux) || defined(VGP_mips64_linux) \
Elliott Hughesed398002017-06-21 14:41:24 -07001182 || defined(VGP_arm64_linux)
sewardj1e866562005-09-28 19:58:58 +00001183 SysRes res;
1184 res = VG_(do_syscall3)(__NR_connect, sockfd, (UWord)serv_addr, addrlen);
njncda2f0f2009-05-18 02:12:08 +00001185 return sr_isError(res) ? -1 : sr_Res(res);
sewardj9a66bb92006-10-17 01:38:13 +00001186
njnf76d27a2009-05-28 01:53:07 +00001187# elif defined(VGO_darwin)
1188 SysRes res;
1189 res = VG_(do_syscall3)(__NR_connect_nocancel,
1190 sockfd, (UWord)serv_addr, addrlen);
1191 return sr_isError(res) ? -1 : sr_Res(res);
1192
sewardj8eb8bab2015-07-21 14:44:28 +00001193# elif defined(VGO_solaris)
1194 SysRes res;
1195 res = VG_(do_syscall4)(__NR_connect, sockfd, (UWord)serv_addr, addrlen,
1196 VKI_SOV_DEFAULT /*version*/);
1197 return sr_isError(res) ? -1 : sr_Res(res);
1198
njncda2f0f2009-05-18 02:12:08 +00001199# else
1200# error "Unknown arch"
1201# endif
njneb8896b2005-06-04 20:03:55 +00001202}
1203
floriandbb35842012-10-27 18:39:11 +00001204Int VG_(write_socket)( Int sd, const void *msg, Int count )
njneb8896b2005-06-04 20:03:55 +00001205{
njneb8896b2005-06-04 20:03:55 +00001206 /* This is actually send(). */
njnf76d27a2009-05-28 01:53:07 +00001207
1208 /* For Linux, VKI_MSG_NOSIGNAL is a request not to send SIGPIPE on
sewardj9a66bb92006-10-17 01:38:13 +00001209 errors on stream oriented sockets when the other end breaks the
njnf76d27a2009-05-28 01:53:07 +00001210 connection. The EPIPE error is still returned.
1211
1212 For Darwin, VG_(socket)() sets SO_NOSIGPIPE to get EPIPE instead of
1213 SIGPIPE */
njneb8896b2005-06-04 20:03:55 +00001214
njncda2f0f2009-05-18 02:12:08 +00001215# if defined(VGP_x86_linux) || defined(VGP_ppc32_linux) \
carllcae0cc22014-08-07 23:17:29 +00001216 || defined(VGP_ppc64be_linux) || defined(VGP_ppc64le_linux) \
1217 || defined(VGP_s390x_linux)
sewardja8d8e232005-06-07 20:04:56 +00001218 SysRes res;
1219 UWord args[4];
njneb8896b2005-06-04 20:03:55 +00001220 args[0] = sd;
1221 args[1] = (UWord)msg;
1222 args[2] = count;
sewardj9a66bb92006-10-17 01:38:13 +00001223 args[3] = VKI_MSG_NOSIGNAL;
njneb8896b2005-06-04 20:03:55 +00001224 res = VG_(do_syscall2)(__NR_socketcall, VKI_SYS_SEND, (UWord)&args);
njncda2f0f2009-05-18 02:12:08 +00001225 return sr_isError(res) ? -1 : sr_Res(res);
cerion85665ca2005-06-20 15:51:07 +00001226
sewardj5db15402012-06-07 09:13:21 +00001227# elif defined(VGP_amd64_linux) || defined(VGP_arm_linux) \
sewardjf0c12502014-01-12 12:54:00 +00001228 || defined(VGP_mips32_linux) || defined(VGP_mips64_linux) \
Elliott Hughesed398002017-06-21 14:41:24 -07001229 || defined(VGP_arm64_linux)
sewardj1e866562005-09-28 19:58:58 +00001230 SysRes res;
sewardj9a66bb92006-10-17 01:38:13 +00001231 res = VG_(do_syscall6)(__NR_sendto, sd, (UWord)msg,
1232 count, VKI_MSG_NOSIGNAL, 0,0);
njncda2f0f2009-05-18 02:12:08 +00001233 return sr_isError(res) ? -1 : sr_Res(res);
sewardj9a66bb92006-10-17 01:38:13 +00001234
njnf76d27a2009-05-28 01:53:07 +00001235# elif defined(VGP_x86_darwin) || defined(VGP_amd64_darwin)
1236 SysRes res;
1237 res = VG_(do_syscall3)(__NR_write_nocancel, sd, (UWord)msg, count);
1238 return sr_isError(res) ? -1 : sr_Res(res);
1239
sewardj8eb8bab2015-07-21 14:44:28 +00001240# elif defined(VGO_solaris)
1241 SysRes res;
1242 res = VG_(do_syscall4)(__NR_send, sd, (UWord)msg, count, 0 /*flags*/);
1243 return sr_isError(res) ? -1 : sr_Res(res);
1244
njncda2f0f2009-05-18 02:12:08 +00001245# else
1246# error "Unknown platform"
1247# endif
njneb8896b2005-06-04 20:03:55 +00001248}
1249
1250Int VG_(getsockname) ( Int sd, struct vki_sockaddr *name, Int *namelen)
1251{
njncda2f0f2009-05-18 02:12:08 +00001252# if defined(VGP_x86_linux) || defined(VGP_ppc32_linux) \
carllcae0cc22014-08-07 23:17:29 +00001253 || defined(VGP_ppc64be_linux) || defined(VGP_ppc64le_linux) \
1254 || defined(VGP_s390x_linux) \
sewardj5db15402012-06-07 09:13:21 +00001255 || defined(VGP_mips32_linux)
sewardj9a66bb92006-10-17 01:38:13 +00001256 SysRes res;
sewardja8d8e232005-06-07 20:04:56 +00001257 UWord args[3];
njneb8896b2005-06-04 20:03:55 +00001258 args[0] = sd;
1259 args[1] = (UWord)name;
1260 args[2] = (UWord)namelen;
1261 res = VG_(do_syscall2)(__NR_socketcall, VKI_SYS_GETSOCKNAME, (UWord)&args);
njncda2f0f2009-05-18 02:12:08 +00001262 return sr_isError(res) ? -1 : sr_Res(res);
sewardja5c9e4a2005-06-09 13:21:58 +00001263
petarj4df0bfc2013-02-27 23:17:33 +00001264# elif defined(VGP_amd64_linux) || defined(VGP_arm_linux) \
Elliott Hughesed398002017-06-21 14:41:24 -07001265 || defined(VGP_mips64_linux) || defined(VGP_arm64_linux)
sewardj9a66bb92006-10-17 01:38:13 +00001266 SysRes res;
sewardja5c9e4a2005-06-09 13:21:58 +00001267 res = VG_(do_syscall3)( __NR_getsockname,
1268 (UWord)sd, (UWord)name, (UWord)namelen );
njncda2f0f2009-05-18 02:12:08 +00001269 return sr_isError(res) ? -1 : sr_Res(res);
sewardj9a66bb92006-10-17 01:38:13 +00001270
njnf76d27a2009-05-28 01:53:07 +00001271# elif defined(VGO_darwin)
1272 SysRes res;
1273 res = VG_(do_syscall3)( __NR_getsockname,
1274 (UWord)sd, (UWord)name, (UWord)namelen );
1275 return sr_isError(res) ? -1 : sr_Res(res);
1276
sewardj8eb8bab2015-07-21 14:44:28 +00001277# elif defined(VGO_solaris)
1278 SysRes res;
1279 res = VG_(do_syscall4)(__NR_getsockname, sd, (UWord)name, (UWord)namelen,
1280 VKI_SOV_DEFAULT /*version*/);
1281 return sr_isError(res) ? -1 : sr_Res(res);
1282
njncda2f0f2009-05-18 02:12:08 +00001283# else
1284# error "Unknown platform"
1285# endif
njneb8896b2005-06-04 20:03:55 +00001286}
1287
1288Int VG_(getpeername) ( Int sd, struct vki_sockaddr *name, Int *namelen)
1289{
njncda2f0f2009-05-18 02:12:08 +00001290# if defined(VGP_x86_linux) || defined(VGP_ppc32_linux) \
carllcae0cc22014-08-07 23:17:29 +00001291 || defined(VGP_ppc64be_linux) || defined(VGP_ppc64le_linux) \
1292 || defined(VGP_s390x_linux) \
sewardj5db15402012-06-07 09:13:21 +00001293 || defined(VGP_mips32_linux)
sewardj9a66bb92006-10-17 01:38:13 +00001294 SysRes res;
sewardja8d8e232005-06-07 20:04:56 +00001295 UWord args[3];
njneb8896b2005-06-04 20:03:55 +00001296 args[0] = sd;
1297 args[1] = (UWord)name;
1298 args[2] = (UWord)namelen;
1299 res = VG_(do_syscall2)(__NR_socketcall, VKI_SYS_GETPEERNAME, (UWord)&args);
njncda2f0f2009-05-18 02:12:08 +00001300 return sr_isError(res) ? -1 : sr_Res(res);
sewardja5c9e4a2005-06-09 13:21:58 +00001301
petarj4df0bfc2013-02-27 23:17:33 +00001302# elif defined(VGP_amd64_linux) || defined(VGP_arm_linux) \
Elliott Hughesed398002017-06-21 14:41:24 -07001303 || defined(VGP_mips64_linux) || defined(VGP_arm64_linux)
sewardj9a66bb92006-10-17 01:38:13 +00001304 SysRes res;
sewardja5c9e4a2005-06-09 13:21:58 +00001305 res = VG_(do_syscall3)( __NR_getpeername,
1306 (UWord)sd, (UWord)name, (UWord)namelen );
njncda2f0f2009-05-18 02:12:08 +00001307 return sr_isError(res) ? -1 : sr_Res(res);
sewardj9a66bb92006-10-17 01:38:13 +00001308
njnf76d27a2009-05-28 01:53:07 +00001309# elif defined(VGO_darwin)
1310 SysRes res;
1311 res = VG_(do_syscall3)( __NR_getpeername,
1312 (UWord)sd, (UWord)name, (UWord)namelen );
1313 return sr_isError(res) ? -1 : sr_Res(res);
1314
sewardj8eb8bab2015-07-21 14:44:28 +00001315# elif defined(VGO_solaris)
1316 SysRes res;
1317 res = VG_(do_syscall4)(__NR_getpeername, sd, (UWord)name, (UWord)namelen,
1318 VKI_SOV_DEFAULT /*version*/);
1319 return sr_isError(res) ? -1 : sr_Res(res);
1320
njncda2f0f2009-05-18 02:12:08 +00001321# else
1322# error "Unknown platform"
1323# endif
njneb8896b2005-06-04 20:03:55 +00001324}
1325
1326Int VG_(getsockopt) ( Int sd, Int level, Int optname, void *optval,
1327 Int *optlen)
1328{
njncda2f0f2009-05-18 02:12:08 +00001329# if defined(VGP_x86_linux) || defined(VGP_ppc32_linux) \
carllcae0cc22014-08-07 23:17:29 +00001330 || defined(VGP_ppc64be_linux) || defined(VGP_ppc64le_linux) \
1331 || defined(VGP_s390x_linux)
sewardj9a66bb92006-10-17 01:38:13 +00001332 SysRes res;
sewardja8d8e232005-06-07 20:04:56 +00001333 UWord args[5];
njneb8896b2005-06-04 20:03:55 +00001334 args[0] = sd;
1335 args[1] = level;
1336 args[2] = optname;
1337 args[3] = (UWord)optval;
1338 args[4] = (UWord)optlen;
1339 res = VG_(do_syscall2)(__NR_socketcall, VKI_SYS_GETSOCKOPT, (UWord)&args);
njncda2f0f2009-05-18 02:12:08 +00001340 return sr_isError(res) ? -1 : sr_Res(res);
sewardja5c9e4a2005-06-09 13:21:58 +00001341
sewardj5db15402012-06-07 09:13:21 +00001342# elif defined(VGP_amd64_linux) || defined(VGP_arm_linux) \
sewardjf0c12502014-01-12 12:54:00 +00001343 || defined(VGP_mips32_linux) || defined(VGP_mips64_linux) \
Elliott Hughesed398002017-06-21 14:41:24 -07001344 || defined(VGP_arm64_linux)
sewardj9a66bb92006-10-17 01:38:13 +00001345 SysRes res;
sewardja5c9e4a2005-06-09 13:21:58 +00001346 res = VG_(do_syscall5)( __NR_getsockopt,
1347 (UWord)sd, (UWord)level, (UWord)optname,
1348 (UWord)optval, (UWord)optlen );
njncda2f0f2009-05-18 02:12:08 +00001349 return sr_isError(res) ? -1 : sr_Res(res);
sewardj9a66bb92006-10-17 01:38:13 +00001350
njnf76d27a2009-05-28 01:53:07 +00001351# elif defined(VGO_darwin)
1352 SysRes res;
1353 res = VG_(do_syscall5)( __NR_getsockopt,
1354 (UWord)sd, (UWord)level, (UWord)optname,
1355 (UWord)optval, (UWord)optlen );
1356 return sr_isError(res) ? -1 : sr_Res(res);
1357
sewardj8eb8bab2015-07-21 14:44:28 +00001358# elif defined(VGO_solaris)
1359 SysRes res;
1360 res = VG_(do_syscall6)(__NR_getsockopt, sd, level, optname, (UWord)optval,
1361 (UWord)optlen, VKI_SOV_DEFAULT /*version*/);
1362 return sr_isError(res) ? -1 : sr_Res(res);
1363
njncda2f0f2009-05-18 02:12:08 +00001364# else
1365# error "Unknown platform"
1366# endif
njneb8896b2005-06-04 20:03:55 +00001367}
1368
1369
sewardj5d616df2013-07-02 08:07:15 +00001370Int VG_(setsockopt) ( Int sd, Int level, Int optname, void *optval,
1371 Int optlen)
njnf76d27a2009-05-28 01:53:07 +00001372{
sewardj5d616df2013-07-02 08:07:15 +00001373# if defined(VGP_x86_linux) || defined(VGP_ppc32_linux) \
carllcae0cc22014-08-07 23:17:29 +00001374 || defined(VGP_ppc64be_linux) || defined(VGP_ppc64le_linux) \
1375 || defined(VGP_s390x_linux)
sewardj5d616df2013-07-02 08:07:15 +00001376 SysRes res;
1377 UWord args[5];
1378 args[0] = sd;
1379 args[1] = level;
1380 args[2] = optname;
1381 args[3] = (UWord)optval;
1382 args[4] = (UWord)optlen;
1383 res = VG_(do_syscall2)(__NR_socketcall, VKI_SYS_SETSOCKOPT, (UWord)&args);
1384 return sr_isError(res) ? -1 : sr_Res(res);
1385
1386# elif defined(VGP_amd64_linux) || defined(VGP_arm_linux) \
sewardjf0c12502014-01-12 12:54:00 +00001387 || defined(VGP_mips32_linux) || defined(VGP_mips64_linux) \
Elliott Hughesed398002017-06-21 14:41:24 -07001388 || defined(VGP_arm64_linux)
sewardj5d616df2013-07-02 08:07:15 +00001389 SysRes res;
1390 res = VG_(do_syscall5)( __NR_setsockopt,
1391 (UWord)sd, (UWord)level, (UWord)optname,
1392 (UWord)optval, (UWord)optlen );
1393 return sr_isError(res) ? -1 : sr_Res(res);
1394
1395# elif defined(VGO_darwin)
1396 SysRes res;
1397 res = VG_(do_syscall5)( __NR_setsockopt,
1398 (UWord)sd, (UWord)level, (UWord)optname,
1399 (UWord)optval, (UWord)optlen );
1400 return sr_isError(res) ? -1 : sr_Res(res);
1401
sewardj8eb8bab2015-07-21 14:44:28 +00001402# elif defined(VGO_solaris)
1403 SysRes res;
1404 res = VG_(do_syscall6)( __NR_setsockopt,
1405 (UWord)sd, (UWord)level, (UWord)optname,
1406 (UWord)optval, (UWord)optlen,
1407 VKI_SOV_DEFAULT /*version*/ );
1408 return sr_isError(res) ? -1 : sr_Res(res);
1409
sewardj5d616df2013-07-02 08:07:15 +00001410# else
1411# error "Unknown platform"
1412# endif
1413}
1414
1415
florian6bd9dc12012-11-23 16:17:43 +00001416const HChar *VG_(basename)(const HChar *path)
njnf76d27a2009-05-28 01:53:07 +00001417{
florian58946e92014-09-27 13:29:09 +00001418 static HChar *buf = NULL;
1419 static SizeT buf_len = 0;
florian19f91bb2012-11-10 22:29:54 +00001420 const HChar *p, *end;
njnf76d27a2009-05-28 01:53:07 +00001421
1422 if (path == NULL ||
1423 0 == VG_(strcmp)(path, ""))
1424 {
1425 return ".";
1426 }
1427
1428 p = path + VG_(strlen)(path);
1429 while (p > path && *p == '/') {
1430 // skip all trailing '/'
1431 p--;
1432 }
1433
1434 if (p == path && *p == '/') return "/"; // all slashes
1435
1436 end = p;
1437
1438 while (p > path && *p != '/') {
1439 // now skip non '/'
1440 p--;
1441 }
1442
1443 if (*p == '/') p++;
1444
florian58946e92014-09-27 13:29:09 +00001445 SizeT need = end-p+1 + 1;
1446 if (need > buf_len) {
1447 buf_len = (buf_len == 0) ? 500 : need;
1448 buf = VG_(realloc)("basename", buf, buf_len);
1449 }
njnf76d27a2009-05-28 01:53:07 +00001450 VG_(strncpy)(buf, p, end-p+1);
1451 buf[end-p+1] = '\0';
1452
1453 return buf;
1454}
1455
1456
florian6bd9dc12012-11-23 16:17:43 +00001457const HChar *VG_(dirname)(const HChar *path)
njnf76d27a2009-05-28 01:53:07 +00001458{
florian58946e92014-09-27 13:29:09 +00001459 static HChar *buf = NULL;
1460 static SizeT buf_len = 0;
njnf76d27a2009-05-28 01:53:07 +00001461
florian19f91bb2012-11-10 22:29:54 +00001462 const HChar *p;
njnf76d27a2009-05-28 01:53:07 +00001463
1464 if (path == NULL ||
1465 0 == VG_(strcmp)(path, "") ||
1466 0 == VG_(strcmp)(path, "/"))
1467 {
1468 return ".";
1469 }
1470
1471 p = path + VG_(strlen)(path);
1472 while (p > path && *p == '/') {
1473 // skip all trailing '/'
1474 p--;
1475 }
1476
1477 while (p > path && *p != '/') {
1478 // now skip non '/'
1479 p--;
1480 }
1481
1482 if (p == path) {
1483 if (*p == '/') return "/"; // all slashes
1484 else return "."; // no slashes
1485 }
1486
1487 while (p > path && *p == '/') {
1488 // skip '/' again
1489 p--;
1490 }
1491
florian58946e92014-09-27 13:29:09 +00001492 SizeT need = p-path+1 + 1;
1493 if (need > buf_len) {
1494 buf_len = (buf_len == 0) ? 500 : need;
1495 buf = VG_(realloc)("dirname", buf, buf_len);
1496 }
njnf76d27a2009-05-28 01:53:07 +00001497 VG_(strncpy)(buf, path, p-path+1);
1498 buf[p-path+1] = '\0';
1499
1500 return buf;
1501}
1502
1503
njneb8896b2005-06-04 20:03:55 +00001504/*--------------------------------------------------------------------*/
1505/*--- end ---*/
1506/*--------------------------------------------------------------------*/