blob: 0d4cef224d24f783260abbac1ce27e20f9903a4a [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
sewardjb3a1e4b2015-08-21 11:32:26 +000011 Copyright (C) 2000-2015 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{
141# if defined(VGP_arm64_linux) || defined(VGP_tilegx_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{
sewardj112711a2015-04-10 12:30:09 +0000159# if defined(VGP_arm64_linux) || defined(VGP_tilegx_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 }
sewardj112711a2015-04-10 12:30:09 +0000253# elif defined(VGP_arm64_linux) || defined(VGP_tilegx_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;
sewardj112711a2015-04-10 12:30:09 +0000363# if defined(VGP_arm64_linux) || defined(VGP_tilegx_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 Hughesa0664b92017-04-18 17:46:52 -0700518# if defined(VGO_solaris) \
519 || defined(VGP_arm64_linux) || defined(VGP_tilegx_linux)
sewardj8eb8bab2015-07-21 14:44:28 +0000520 SysRes res = VG_(do_syscall4)(__NR_renameat, VKI_AT_FDCWD, (UWord)old_name,
521 VKI_AT_FDCWD, (UWord)new_name);
Elliott Hughesa0664b92017-04-18 17:46:52 -0700522# elif defined(VGO_linux) || defined(VGO_darwin)
523 SysRes res = VG_(do_syscall2)(__NR_rename, (UWord)old_name, (UWord)new_name);
sewardj8eb8bab2015-07-21 14:44:28 +0000524# else
525# error "Unknown OS"
sewardj112711a2015-04-10 12:30:09 +0000526# endif
njncda2f0f2009-05-18 02:12:08 +0000527 return sr_isError(res) ? (-1) : 0;
njneb8896b2005-06-04 20:03:55 +0000528}
529
florian19f91bb2012-11-10 22:29:54 +0000530Int VG_(unlink) ( const HChar* file_name )
njneb8896b2005-06-04 20:03:55 +0000531{
sewardj112711a2015-04-10 12:30:09 +0000532# if defined(VGP_arm64_linux) || defined(VGP_tilegx_linux)
sewardjf0c12502014-01-12 12:54:00 +0000533 SysRes res = VG_(do_syscall2)(__NR_unlinkat, VKI_AT_FDCWD,
534 (UWord)file_name);
sewardj8eb8bab2015-07-21 14:44:28 +0000535# elif defined(VGO_linux) || defined(VGO_darwin)
sewardja8d8e232005-06-07 20:04:56 +0000536 SysRes res = VG_(do_syscall1)(__NR_unlink, (UWord)file_name);
sewardj8eb8bab2015-07-21 14:44:28 +0000537# elif defined(VGO_solaris)
538 SysRes res = VG_(do_syscall3)(__NR_unlinkat, VKI_AT_FDCWD,
539 (UWord)file_name, 0);
540# else
541# error "Unknown OS"
sewardjf0c12502014-01-12 12:54:00 +0000542# endif
njncda2f0f2009-05-18 02:12:08 +0000543 return sr_isError(res) ? (-1) : 0;
njneb8896b2005-06-04 20:03:55 +0000544}
545
florian29d82f62014-09-27 17:42:07 +0000546/* The working directory at startup.
547 All that is really needed is to note the cwd at process startup.
548 Hence VG_(record_startup_wd) notes it (in a platform dependent way)
549 and VG_(get_startup_wd) produces the noted value. */
550static HChar *startup_wd;
sewardj198f34f2007-07-09 23:13:07 +0000551
552/* Record the process' working directory at startup. Is intended to
553 be called exactly once, at startup, before the working directory
Elliott Hughesa0664b92017-04-18 17:46:52 -0700554 changes. */
555void VG_(record_startup_wd) ( void )
njneb8896b2005-06-04 20:03:55 +0000556{
sewardj8eb8bab2015-07-21 14:44:28 +0000557# if defined(VGO_linux) || defined(VGO_solaris)
sewardj198f34f2007-07-09 23:13:07 +0000558 /* Simple: just ask the kernel */
florian29d82f62014-09-27 17:42:07 +0000559 SysRes res;
560 SizeT szB = 0;
561 do {
562 szB += 500;
563 startup_wd = VG_(realloc)("startup_wd", startup_wd, szB);
564 VG_(memset)(startup_wd, 0, szB);
565 res = VG_(do_syscall2)(__NR_getcwd, (UWord)startup_wd, szB-1);
Elliott Hughesa0664b92017-04-18 17:46:52 -0700566 } while (sr_isError(res) && sr_Err(res) == VKI_ERANGE);
567
568 if (sr_isError(res)) {
569 VG_(free)(startup_wd);
570 startup_wd = NULL;
571 return;
572 }
florian29d82f62014-09-27 17:42:07 +0000573
574 vg_assert(startup_wd[szB-1] == 0);
florian29d82f62014-09-27 17:42:07 +0000575
sewardj6e9de462011-06-28 07:25:29 +0000576# elif defined(VGO_darwin)
njnf76d27a2009-05-28 01:53:07 +0000577 /* We can't ask the kernel, so instead rely on launcher-*.c to
sewardj198f34f2007-07-09 23:13:07 +0000578 tell us the startup path. Note the env var is keyed to the
579 parent's PID, not ours, since our parent is the launcher
580 process. */
florian29d82f62014-09-27 17:42:07 +0000581 { HChar envvar[100]; // large enough
582 HChar* wd;
sewardj198f34f2007-07-09 23:13:07 +0000583 VG_(memset)(envvar, 0, sizeof(envvar));
584 VG_(sprintf)(envvar, "VALGRIND_STARTUP_PWD_%d_XYZZY",
585 (Int)VG_(getppid)());
586 wd = VG_(getenv)( envvar );
florian29d82f62014-09-27 17:42:07 +0000587 if (wd == NULL)
Elliott Hughesa0664b92017-04-18 17:46:52 -0700588 return;
florian29d82f62014-09-27 17:42:07 +0000589 SizeT need = VG_(strlen)(wd) + 1;
590 startup_wd = VG_(malloc)("startup_wd", need);
591 VG_(strcpy)(startup_wd, wd);
sewardj198f34f2007-07-09 23:13:07 +0000592 }
sewardj9a66bb92006-10-17 01:38:13 +0000593# else
594# error Unknown OS
595# endif
njneb8896b2005-06-04 20:03:55 +0000596}
597
Elliott Hughesa0664b92017-04-18 17:46:52 -0700598/* Return the previously acquired startup_wd or NULL. */
florian29d82f62014-09-27 17:42:07 +0000599const HChar *VG_(get_startup_wd) ( void )
sewardj198f34f2007-07-09 23:13:07 +0000600{
florian29d82f62014-09-27 17:42:07 +0000601 return startup_wd;
sewardj198f34f2007-07-09 23:13:07 +0000602}
603
philippe42545842013-12-05 22:10:55 +0000604SysRes VG_(poll) (struct vki_pollfd *fds, Int nfds, Int timeout)
sewardj3b290482011-05-06 21:02:55 +0000605{
606 SysRes res;
sewardj112711a2015-04-10 12:30:09 +0000607# if defined(VGP_arm64_linux) || defined(VGP_tilegx_linux)
philippe0eb0d5a2014-02-11 23:50:16 +0000608 /* ARM64 wants to use __NR_ppoll rather than __NR_poll. */
609 struct vki_timespec timeout_ts;
610 if (timeout >= 0) {
611 timeout_ts.tv_sec = timeout / 1000;
612 timeout_ts.tv_nsec = ((long)timeout % 1000) * 1000000;
613 }
614 res = VG_(do_syscall4)(__NR_ppoll,
615 (UWord)fds, nfds,
616 (UWord)(timeout >= 0 ? &timeout_ts : NULL),
617 (UWord)NULL);
618# elif defined(VGO_linux)
sewardj3b290482011-05-06 21:02:55 +0000619 res = VG_(do_syscall3)(__NR_poll, (UWord)fds, nfds, timeout);
sewardj6caac712012-08-18 06:45:07 +0000620# elif defined(VGO_darwin)
621 res = VG_(do_syscall3)(__NR_poll_nocancel, (UWord)fds, nfds, timeout);
sewardj8eb8bab2015-07-21 14:44:28 +0000622# elif defined(VGO_solaris)
623 struct vki_timespec ts;
624 struct vki_timespec *tsp;
625
626 if (timeout < 0)
627 tsp = NULL;
628 else {
629 ts.tv_sec = timeout / 1000;
630 ts.tv_nsec = (timeout % 1000) * 1000000;
631 tsp = &ts;
632 }
633
634 res = VG_(do_syscall4)(__NR_pollsys, (UWord)fds, nfds, (UWord)tsp, 0);
sewardj6caac712012-08-18 06:45:07 +0000635# else
636# error "Unknown OS"
637# endif
philippe42545842013-12-05 22:10:55 +0000638 return res;
sewardj3b290482011-05-06 21:02:55 +0000639}
640
641
floriana175ffb2014-10-14 21:01:33 +0000642/* Performs the readlink operation and puts the result into 'buf'.
643 Note, that the string in 'buf' is *not* null-terminated. The function
644 returns the number of characters put into 'buf' or -1 if an error
645 occurred. */
646SSizeT VG_(readlink) (const HChar* path, HChar* buf, SizeT bufsiz)
njneb8896b2005-06-04 20:03:55 +0000647{
sewardja8d8e232005-06-07 20:04:56 +0000648 SysRes res;
njneb8896b2005-06-04 20:03:55 +0000649 /* res = readlink( path, buf, bufsiz ); */
sewardj112711a2015-04-10 12:30:09 +0000650# if defined(VGP_arm64_linux) || defined(VGP_tilegx_linux)
sewardjf0c12502014-01-12 12:54:00 +0000651 res = VG_(do_syscall4)(__NR_readlinkat, VKI_AT_FDCWD,
652 (UWord)path, (UWord)buf, bufsiz);
sewardj8eb8bab2015-07-21 14:44:28 +0000653# elif defined(VGO_linux) || defined(VGO_darwin)
njneb8896b2005-06-04 20:03:55 +0000654 res = VG_(do_syscall3)(__NR_readlink, (UWord)path, (UWord)buf, bufsiz);
sewardj8eb8bab2015-07-21 14:44:28 +0000655# elif defined(VGO_solaris)
656 res = VG_(do_syscall4)(__NR_readlinkat, VKI_AT_FDCWD, (UWord)path,
657 (UWord)buf, bufsiz);
658# else
659# error "Unknown OS"
sewardjf0c12502014-01-12 12:54:00 +0000660# endif
njncda2f0f2009-05-18 02:12:08 +0000661 return sr_isError(res) ? -1 : sr_Res(res);
njneb8896b2005-06-04 20:03:55 +0000662}
663
sewardj8eb8bab2015-07-21 14:44:28 +0000664#if defined(VGO_linux) || defined(VGO_solaris)
mjw495c6562014-08-29 14:28:30 +0000665Int VG_(getdents64) (Int fd, struct vki_dirent64 *dirp, UInt count)
njneb8896b2005-06-04 20:03:55 +0000666{
sewardja8d8e232005-06-07 20:04:56 +0000667 SysRes res;
njneb8896b2005-06-04 20:03:55 +0000668 /* res = getdents( fd, dirp, count ); */
sewardj8eb8bab2015-07-21 14:44:28 +0000669# if defined(VGP_amd64_solaris)
670 /* This silently assumes that dirent64 and dirent on amd64 are same, which
671 they should always be. */
672 res = VG_(do_syscall3)(__NR_getdents, fd, (UWord)dirp, count);
673# else
mjw495c6562014-08-29 14:28:30 +0000674 res = VG_(do_syscall3)(__NR_getdents64, fd, (UWord)dirp, count);
Elliott Hughesa0664b92017-04-18 17:46:52 -0700675# if defined(VGA_mips64)
676 /* The MIPS64 getdents64() system call is only present in 3.10+ kernels.
677 If the getdents64() system call is not available fall back to using
678 getdents() and modify the result to be compatible with getdents64(). */
679 if (sr_isError(res) && (sr_Err(res) == VKI_ENOSYS)) {
680 int r;
681 res = VG_(do_syscall3)(__NR_getdents, fd, (UWord)dirp, count);
682 r = sr_Res(res);
683 if (r > 0) {
684 char *p;
685 char type;
686 union dirents {
687 struct vki_dirent m;
688 struct vki_dirent64 d;
689 } *u;
690 p = (char *)dirp;
691 do {
692 u = (union dirents *)p;
693 /* This should not happen, but just in case... */
694 if (p + u->m.d_reclen > (char *)dirp + r)
695 break;
696 /* shuffle the dirent */
697 type = *(p + u->m.d_reclen - 1);
698 VG_(memmove)(u->d.d_name, u->m.d_name,
699 u->m.d_reclen - 2
700 - offsetof(struct vki_dirent, d_name) + 1);
701 u->d.d_type = type;
702 p += u->m.d_reclen;
703 } while (p < (char *)dirp + r);
704 }
705 }
706# endif
sewardj8eb8bab2015-07-21 14:44:28 +0000707# endif
njncda2f0f2009-05-18 02:12:08 +0000708 return sr_isError(res) ? -1 : sr_Res(res);
njneb8896b2005-06-04 20:03:55 +0000709}
sewardjb69cd962014-09-01 22:26:18 +0000710#endif
njneb8896b2005-06-04 20:03:55 +0000711
sewardj45f4e7c2005-09-27 19:20:21 +0000712/* Check accessibility of a file. Returns zero for access granted,
713 nonzero otherwise. */
njn63e5e6e2009-05-20 04:22:42 +0000714Int VG_(access) ( const HChar* path, Bool irusr, Bool iwusr, Bool ixusr )
sewardj45f4e7c2005-09-27 19:20:21 +0000715{
sewardj9a66bb92006-10-17 01:38:13 +0000716# if defined(VGO_linux)
sewardj45f4e7c2005-09-27 19:20:21 +0000717 /* Very annoyingly, I cannot find any definition for R_OK et al in
718 the kernel interfaces. Therefore I reluctantly resort to
719 hardwiring in these magic numbers that I determined by
720 experimentation. */
njncda2f0f2009-05-18 02:12:08 +0000721# define VKI_R_OK 4
722# define VKI_W_OK 2
723# define VKI_X_OK 1
724# endif
725
sewardj9a66bb92006-10-17 01:38:13 +0000726 UWord w = (irusr ? VKI_R_OK : 0)
727 | (iwusr ? VKI_W_OK : 0)
728 | (ixusr ? VKI_X_OK : 0);
sewardj112711a2015-04-10 12:30:09 +0000729# if defined(VGP_arm64_linux) || defined(VGP_tilegx_linux)
sewardjf0c12502014-01-12 12:54:00 +0000730 SysRes res = VG_(do_syscall3)(__NR_faccessat, VKI_AT_FDCWD, (UWord)path, w);
sewardj8eb8bab2015-07-21 14:44:28 +0000731# elif defined(VGO_linux) || defined(VGO_darwin)
sewardj9a66bb92006-10-17 01:38:13 +0000732 SysRes res = VG_(do_syscall2)(__NR_access, (UWord)path, w);
sewardj8eb8bab2015-07-21 14:44:28 +0000733# elif defined(VGO_solaris)
734 SysRes res = VG_(do_syscall4)(__NR_faccessat, VKI_AT_FDCWD, (UWord)path,
735 w, 0);
736# else
737# error "Unknown OS"
sewardjf0c12502014-01-12 12:54:00 +0000738# endif
njncda2f0f2009-05-18 02:12:08 +0000739 return sr_isError(res) ? 1 : 0;
740
741# if defined(VGO_linux)
742# undef VKI_R_OK
743# undef VKI_W_OK
744# undef VKI_X_OK
sewardj9a66bb92006-10-17 01:38:13 +0000745# endif
sewardj45f4e7c2005-09-27 19:20:21 +0000746}
747
njn73750612005-10-14 03:11:30 +0000748/*
749 Emulate the normal Unix permissions checking algorithm.
750
751 If owner matches, then use the owner permissions, else
752 if group matches, then use the group permissions, else
753 use other permissions.
754
sewardjc74b3ba2007-11-17 21:11:57 +0000755 Note that we can't deal properly with SUID/SGID. By default
756 (allow_setuid == False), we refuse to run them (otherwise the
757 executable may misbehave if it doesn't have the permissions it
758 thinks it does). However, the caller may indicate that setuid
759 executables are allowed, for example if we are going to exec them
760 but not trace into them (iow, client sys_execve when
761 clo_trace_children == False).
762
763 If VKI_EACCES is returned (iow, permission was refused), then
764 *is_setuid is set to True iff permission was refused because the
765 executable is setuid.
njn73750612005-10-14 03:11:30 +0000766*/
767/* returns: 0 = success, non-0 is failure */
sewardjc74b3ba2007-11-17 21:11:57 +0000768Int VG_(check_executable)(/*OUT*/Bool* is_setuid,
njn63e5e6e2009-05-20 04:22:42 +0000769 const HChar* f, Bool allow_setuid)
njn73750612005-10-14 03:11:30 +0000770{
sewardj4231a852008-08-19 08:32:03 +0000771 struct vg_stat st;
sewardj26b87282006-10-17 12:49:31 +0000772 SysRes res = VG_(stat)(f, &st);
njn73750612005-10-14 03:11:30 +0000773
sewardjc74b3ba2007-11-17 21:11:57 +0000774 if (is_setuid)
775 *is_setuid = False;
776
njncda2f0f2009-05-18 02:12:08 +0000777 if (sr_isError(res)) {
778 return sr_Err(res);
njn73750612005-10-14 03:11:30 +0000779 }
780
mjwd6edbc92015-02-09 13:27:07 +0000781 if ( VKI_S_ISDIR (st.mode) ) {
782 return VKI_EACCES;
783 }
784
njn9c20ece2009-05-20 02:02:30 +0000785 if ( (st.mode & (VKI_S_ISUID | VKI_S_ISGID)) && !allow_setuid ) {
sewardjc74b3ba2007-11-17 21:11:57 +0000786 if (is_setuid)
787 *is_setuid = True;
njn73750612005-10-14 03:11:30 +0000788 return VKI_EACCES;
789 }
790
tomb7c2f9d2014-05-22 08:57:06 +0000791 res = VG_(getxattr)(f, "security.capability", (Addr)0, 0);
792 if (!sr_isError(res) && !allow_setuid) {
793 if (is_setuid)
794 *is_setuid = True;
795 return VKI_EACCES;
796 }
797
njn9c20ece2009-05-20 02:02:30 +0000798 if (VG_(geteuid)() == st.uid) {
799 if (!(st.mode & VKI_S_IXUSR))
njn73750612005-10-14 03:11:30 +0000800 return VKI_EACCES;
801 } else {
sewardj45406ef2006-10-18 00:33:46 +0000802 Int grpmatch = 0;
njn73750612005-10-14 03:11:30 +0000803
njn9c20ece2009-05-20 02:02:30 +0000804 if (VG_(getegid)() == st.gid)
njn73750612005-10-14 03:11:30 +0000805 grpmatch = 1;
806 else {
florian94086c72014-09-30 19:26:58 +0000807 UInt *groups = NULL;
808 Int ngrp;
809
810 /* Find out # groups, allocate large enough array and fetch groups */
811 ngrp = VG_(getgroups)(0, NULL);
812 if (ngrp != -1) {
813 groups = VG_(malloc)("check_executable", ngrp * sizeof *groups);
814 ngrp = VG_(getgroups)(ngrp, groups);
815 }
816
817 Int i;
njn73750612005-10-14 03:11:30 +0000818 /* ngrp will be -1 if VG_(getgroups) failed. */
819 for (i = 0; i < ngrp; i++) {
njn9c20ece2009-05-20 02:02:30 +0000820 if (groups[i] == st.gid) {
njn73750612005-10-14 03:11:30 +0000821 grpmatch = 1;
822 break;
823 }
824 }
florian94086c72014-09-30 19:26:58 +0000825 VG_(free)(groups);
njn73750612005-10-14 03:11:30 +0000826 }
827
828 if (grpmatch) {
njn9c20ece2009-05-20 02:02:30 +0000829 if (!(st.mode & VKI_S_IXGRP)) {
njn73750612005-10-14 03:11:30 +0000830 return VKI_EACCES;
831 }
njn9c20ece2009-05-20 02:02:30 +0000832 } else if (!(st.mode & VKI_S_IXOTH)) {
njn73750612005-10-14 03:11:30 +0000833 return VKI_EACCES;
834 }
835 }
836
837 return 0;
838}
839
njnc4431bf2009-01-15 21:29:24 +0000840SysRes VG_(pread) ( Int fd, void* buf, Int count, OffT offset )
sewardj45f4e7c2005-09-27 19:20:21 +0000841{
njncda2f0f2009-05-18 02:12:08 +0000842 SysRes res;
philippe8050bb72012-04-13 23:07:29 +0000843 // on 32 bits platforms, we receive a 32 bits OffT but
844 // we must extend it to pass a long long 64 bits.
845# if defined(VGP_x86_linux)
846 vg_assert(sizeof(OffT) == 4);
847 res = VG_(do_syscall5)(__NR_pread64, fd, (UWord)buf, count,
848 offset, 0); // Little endian long long
849 return res;
850# elif defined(VGP_arm_linux)
851 vg_assert(sizeof(OffT) == 4);
852 res = VG_(do_syscall5)(__NR_pread64, fd, (UWord)buf, count,
853 0, offset); // Big endian long long
854 return res;
855# elif defined(VGP_ppc32_linux)
856 vg_assert(sizeof(OffT) == 4);
857 res = VG_(do_syscall6)(__NR_pread64, fd, (UWord)buf, count,
858 0, // Padding needed on PPC32
859 0, offset); // Big endian long long
860 return res;
petarj4df0bfc2013-02-27 23:17:33 +0000861# elif defined(VGP_mips32_linux) && (VKI_LITTLE_ENDIAN)
sewardj5db15402012-06-07 09:13:21 +0000862 vg_assert(sizeof(OffT) == 4);
863 res = VG_(do_syscall6)(__NR_pread64, fd, (UWord)buf, count,
864 0, offset, 0);
865 return res;
petarj4df0bfc2013-02-27 23:17:33 +0000866# elif defined(VGP_mips32_linux) && (VKI_BIG_ENDIAN)
sewardj5db15402012-06-07 09:13:21 +0000867 vg_assert(sizeof(OffT) == 4);
868 res = VG_(do_syscall6)(__NR_pread64, fd, (UWord)buf, count,
869 0, 0, offset);
870 return res;
carllcae0cc22014-08-07 23:17:29 +0000871# elif defined(VGP_amd64_linux) || defined(VGP_s390x_linux) \
872 || defined(VGP_ppc64be_linux) || defined(VGP_ppc64le_linux) \
sewardjf0c12502014-01-12 12:54:00 +0000873 || defined(VGP_mips64_linux) \
sewardj112711a2015-04-10 12:30:09 +0000874 || defined(VGP_arm64_linux) || defined(VGP_tilegx_linux)
philippe8050bb72012-04-13 23:07:29 +0000875 res = VG_(do_syscall4)(__NR_pread64, fd, (UWord)buf, count, offset);
njncda2f0f2009-05-18 02:12:08 +0000876 return res;
njnf76d27a2009-05-28 01:53:07 +0000877# elif defined(VGP_amd64_darwin)
sewardj972316d2012-04-21 15:33:26 +0000878 vg_assert(sizeof(OffT) == 8);
njnf76d27a2009-05-28 01:53:07 +0000879 res = VG_(do_syscall4)(__NR_pread_nocancel, fd, (UWord)buf, count, offset);
880 return res;
881# elif defined(VGP_x86_darwin)
sewardj972316d2012-04-21 15:33:26 +0000882 vg_assert(sizeof(OffT) == 8);
njnf76d27a2009-05-28 01:53:07 +0000883 res = VG_(do_syscall5)(__NR_pread_nocancel, fd, (UWord)buf, count,
sewardj972316d2012-04-21 15:33:26 +0000884 offset & 0xffffffff, offset >> 32);
njnf76d27a2009-05-28 01:53:07 +0000885 return res;
sewardj8eb8bab2015-07-21 14:44:28 +0000886# elif defined(VGP_x86_solaris)
887 vg_assert(sizeof(OffT) == 4);
888 res = VG_(do_syscall4)(__NR_pread, fd, (UWord)buf, count, offset);
889 return res;
890# elif defined(VGP_amd64_solaris)
891 vg_assert(sizeof(OffT) == 8);
892 res = VG_(do_syscall4)(__NR_pread, fd, (UWord)buf, count, offset);
893 return res;
njncda2f0f2009-05-18 02:12:08 +0000894# else
895# error "Unknown platform"
896# endif
sewardj45f4e7c2005-09-27 19:20:21 +0000897}
898
florianb985e2d2011-09-29 03:03:45 +0000899/* Return the name of a directory for temporary files. */
900const HChar *VG_(tmpdir)(void)
901{
902 const HChar *tmpdir;
903
904 tmpdir = VG_(getenv)("TMPDIR");
905 if (tmpdir == NULL || *tmpdir == '\0') tmpdir = VG_TMPDIR;
906 if (tmpdir == NULL || *tmpdir == '\0') tmpdir = "/tmp"; /* fallback */
907
908 return tmpdir;
909}
910
florian60372262014-08-09 21:45:56 +0000911static const HChar mkstemp_format[] = "%s/valgrind_%s_%08x";
philippecc648262013-05-26 21:09:20 +0000912
913SizeT VG_(mkstemp_fullname_bufsz) ( SizeT part_of_name_len )
914{
915 return VG_(strlen)(mkstemp_format)
916 + VG_(strlen)(VG_(tmpdir)()) - 2 // %s tmpdir
917 + part_of_name_len - 2 // %s part_of_name
918 + 8 - 4 // %08x
919 + 1; // trailing 0
920}
921
922
philipped47676f2014-08-09 11:26:51 +0000923Int VG_(mkstemp) ( const HChar* part_of_name, /*OUT*/HChar* fullname )
sewardj45f4e7c2005-09-27 19:20:21 +0000924{
florian87c8abb2014-11-09 16:15:23 +0000925 Int n, tries;
sewardj45f4e7c2005-09-27 19:20:21 +0000926 UInt seed;
927 SysRes sres;
florian1763e812011-07-12 19:07:05 +0000928 const HChar *tmpdir;
sewardj45f4e7c2005-09-27 19:20:21 +0000929
930 vg_assert(part_of_name);
florian87c8abb2014-11-09 16:15:23 +0000931 vg_assert(fullname);
sewardj45f4e7c2005-09-27 19:20:21 +0000932 n = VG_(strlen)(part_of_name);
933 vg_assert(n > 0 && n < 100);
934
935 seed = (VG_(getpid)() << 9) ^ VG_(getppid)();
936
florian1763e812011-07-12 19:07:05 +0000937 /* Determine sensible location for temporary files */
florianb985e2d2011-09-29 03:03:45 +0000938 tmpdir = VG_(tmpdir)();
florian1763e812011-07-12 19:07:05 +0000939
sewardj45f4e7c2005-09-27 19:20:21 +0000940 tries = 0;
941 while (True) {
sewardj824b3972011-05-09 22:42:06 +0000942 if (tries++ > 10)
sewardj45f4e7c2005-09-27 19:20:21 +0000943 return -1;
florian87c8abb2014-11-09 16:15:23 +0000944 VG_(sprintf)( fullname, mkstemp_format,
florian1763e812011-07-12 19:07:05 +0000945 tmpdir, part_of_name, VG_(random)( &seed ));
sewardj45f4e7c2005-09-27 19:20:21 +0000946 if (0)
florian87c8abb2014-11-09 16:15:23 +0000947 VG_(printf)("VG_(mkstemp): trying: %s\n", fullname);
sewardj45f4e7c2005-09-27 19:20:21 +0000948
florian87c8abb2014-11-09 16:15:23 +0000949 sres = VG_(open)(fullname,
sewardj45f4e7c2005-09-27 19:20:21 +0000950 VKI_O_CREAT|VKI_O_RDWR|VKI_O_EXCL|VKI_O_TRUNC,
951 VKI_S_IRUSR|VKI_S_IWUSR);
sewardj80fc03b2011-09-26 16:46:04 +0000952 if (sr_isError(sres)) {
florian87c8abb2014-11-09 16:15:23 +0000953 VG_(umsg)("VG_(mkstemp): failed to create temp file: %s\n", fullname);
sewardj45f4e7c2005-09-27 19:20:21 +0000954 continue;
sewardj80fc03b2011-09-26 16:46:04 +0000955 }
sewardj45f4e7c2005-09-27 19:20:21 +0000956 /* VG_(safe_fd) doesn't return if it fails. */
florian87c8abb2014-11-09 16:15:23 +0000957 return VG_(safe_fd)( sr_Res(sres) );
sewardj45f4e7c2005-09-27 19:20:21 +0000958 }
959 /* NOTREACHED */
960}
961
962
njneb8896b2005-06-04 20:03:55 +0000963/* ---------------------------------------------------------------------
njn4bd96bd2009-05-22 00:52:14 +0000964 Socket-related stuff.
njneb8896b2005-06-04 20:03:55 +0000965 ------------------------------------------------------------------ */
966
967static
florian19f91bb2012-11-10 22:29:54 +0000968Int parse_inet_addr_and_port ( const HChar* str, UInt* ip_addr, UShort* port );
njneb8896b2005-06-04 20:03:55 +0000969
970static
njn4bd96bd2009-05-22 00:52:14 +0000971Int my_connect ( Int sockfd, struct vki_sockaddr_in* serv_addr, Int addrlen );
njneb8896b2005-06-04 20:03:55 +0000972
toma4a4f412005-11-17 12:01:56 +0000973UInt VG_(htonl) ( UInt x )
njneb8896b2005-06-04 20:03:55 +0000974{
sewardja1c4bfb2005-10-18 02:15:39 +0000975# if defined(VG_BIGENDIAN)
976 return x;
977# else
njneb8896b2005-06-04 20:03:55 +0000978 return
979 (((x >> 24) & 0xFF) << 0) | (((x >> 16) & 0xFF) << 8)
980 | (((x >> 8) & 0xFF) << 16) | (((x >> 0) & 0xFF) << 24);
sewardja1c4bfb2005-10-18 02:15:39 +0000981# endif
njneb8896b2005-06-04 20:03:55 +0000982}
983
toma4a4f412005-11-17 12:01:56 +0000984UInt VG_(ntohl) ( UInt x )
985{
986# if defined(VG_BIGENDIAN)
987 return x;
988# else
989 return
990 (((x >> 24) & 0xFF) << 0) | (((x >> 16) & 0xFF) << 8)
991 | (((x >> 8) & 0xFF) << 16) | (((x >> 0) & 0xFF) << 24);
992# endif
993}
994
995UShort VG_(htons) ( UShort x )
996{
997# if defined(VG_BIGENDIAN)
998 return x;
999# else
1000 return
1001 (((x >> 8) & 0xFF) << 0) | (((x >> 0) & 0xFF) << 8);
1002# endif
1003}
1004
1005UShort VG_(ntohs) ( UShort x )
njneb8896b2005-06-04 20:03:55 +00001006{
sewardja1c4bfb2005-10-18 02:15:39 +00001007# if defined(VG_BIGENDIAN)
1008 return x;
1009# else
njneb8896b2005-06-04 20:03:55 +00001010 return
1011 (((x >> 8) & 0xFF) << 0) | (((x >> 0) & 0xFF) << 8);
sewardja1c4bfb2005-10-18 02:15:39 +00001012# endif
njneb8896b2005-06-04 20:03:55 +00001013}
1014
1015
1016/* The main function.
1017
1018 Supplied string contains either an ip address "192.168.0.1" or
1019 an ip address and port pair, "192.168.0.1:1500". Parse these,
1020 and return:
1021 -1 if there is a parse error
1022 -2 if no parse error, but specified host:port cannot be opened
1023 the relevant file (socket) descriptor, otherwise.
1024 is used.
1025*/
florian19f91bb2012-11-10 22:29:54 +00001026Int VG_(connect_via_socket)( const HChar* str )
njneb8896b2005-06-04 20:03:55 +00001027{
sewardj8eb8bab2015-07-21 14:44:28 +00001028# if defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_solaris)
njneb8896b2005-06-04 20:03:55 +00001029 Int sd, res;
1030 struct vki_sockaddr_in servAddr;
1031 UInt ip = 0;
1032 UShort port = VG_CLO_DEFAULT_LOGPORT;
1033 Bool ok = parse_inet_addr_and_port(str, &ip, &port);
1034 if (!ok)
1035 return -1;
1036
1037 //if (0)
1038 // VG_(printf)("ip = %d.%d.%d.%d, port %d\n",
1039 // (ip >> 24) & 0xFF, (ip >> 16) & 0xFF,
1040 // (ip >> 8) & 0xFF, ip & 0xFF,
1041 // (UInt)port );
1042
1043 servAddr.sin_family = VKI_AF_INET;
toma4a4f412005-11-17 12:01:56 +00001044 servAddr.sin_addr.s_addr = VG_(htonl)(ip);
1045 servAddr.sin_port = VG_(htons)(port);
njneb8896b2005-06-04 20:03:55 +00001046
1047 /* create socket */
njn0cd5d972009-05-22 02:00:27 +00001048 sd = VG_(socket)(VKI_AF_INET, VKI_SOCK_STREAM, 0 /* IPPROTO_IP ? */);
njneb8896b2005-06-04 20:03:55 +00001049 if (sd < 0) {
sewardja1c4bfb2005-10-18 02:15:39 +00001050 /* this shouldn't happen ... nevertheless */
1051 return -2;
njneb8896b2005-06-04 20:03:55 +00001052 }
sewardja1c4bfb2005-10-18 02:15:39 +00001053
njneb8896b2005-06-04 20:03:55 +00001054 /* connect to server */
njnb143b272009-05-22 00:47:08 +00001055 res = my_connect(sd, &servAddr, sizeof(servAddr));
njneb8896b2005-06-04 20:03:55 +00001056 if (res < 0) {
sewardja1c4bfb2005-10-18 02:15:39 +00001057 /* connection failed */
1058 return -2;
njneb8896b2005-06-04 20:03:55 +00001059 }
1060
1061 return sd;
njncda2f0f2009-05-18 02:12:08 +00001062
njncda2f0f2009-05-18 02:12:08 +00001063# else
1064# error "Unknown OS"
1065# endif
njneb8896b2005-06-04 20:03:55 +00001066}
1067
1068
1069/* Let d = one or more digits. Accept either:
1070 d.d.d.d or d.d.d.d:d
1071*/
florian19f91bb2012-11-10 22:29:54 +00001072static Int parse_inet_addr_and_port ( const HChar* str, UInt* ip_addr, UShort* port )
njneb8896b2005-06-04 20:03:55 +00001073{
1074# define GET_CH ((*str) ? (*str++) : 0)
1075 UInt ipa, i, j, c, any;
1076 ipa = 0;
1077 for (i = 0; i < 4; i++) {
1078 j = 0;
1079 any = 0;
1080 while (1) {
1081 c = GET_CH;
1082 if (c < '0' || c > '9') break;
1083 j = 10 * j + (int)(c - '0');
1084 any = 1;
1085 }
1086 if (any == 0 || j > 255) goto syntaxerr;
1087 ipa = (ipa << 8) + j;
1088 if (i <= 2 && c != '.') goto syntaxerr;
1089 }
1090 if (c == 0 || c == ':')
1091 *ip_addr = ipa;
1092 if (c == 0) goto ok;
1093 if (c != ':') goto syntaxerr;
1094 j = 0;
1095 any = 0;
1096 while (1) {
1097 c = GET_CH;
1098 if (c < '0' || c > '9') break;
1099 j = j * 10 + (int)(c - '0');
1100 any = 1;
1101 if (j > 65535) goto syntaxerr;
1102 }
1103 if (any == 0 || c != 0) goto syntaxerr;
1104 if (j < 1024) goto syntaxerr;
1105 *port = (UShort)j;
1106 ok:
1107 return 1;
1108 syntaxerr:
1109 return 0;
1110# undef GET_CH
1111}
1112
njn0cd5d972009-05-22 02:00:27 +00001113// GrP fixme safe_fd?
1114Int VG_(socket) ( Int domain, Int type, Int protocol )
njneb8896b2005-06-04 20:03:55 +00001115{
njncda2f0f2009-05-18 02:12:08 +00001116# if defined(VGP_x86_linux) || defined(VGP_ppc32_linux) \
carllcae0cc22014-08-07 23:17:29 +00001117 || defined(VGP_ppc64be_linux) || defined(VGP_ppc64le_linux) \
1118 || defined(VGP_s390x_linux)
sewardja8d8e232005-06-07 20:04:56 +00001119 SysRes res;
1120 UWord args[3];
njneb8896b2005-06-04 20:03:55 +00001121 args[0] = domain;
1122 args[1] = type;
1123 args[2] = protocol;
1124 res = VG_(do_syscall2)(__NR_socketcall, VKI_SYS_SOCKET, (UWord)&args);
njncda2f0f2009-05-18 02:12:08 +00001125 return sr_isError(res) ? -1 : sr_Res(res);
cerion85665ca2005-06-20 15:51:07 +00001126
sewardj5db15402012-06-07 09:13:21 +00001127# elif defined(VGP_amd64_linux) || defined(VGP_arm_linux) \
sewardjf0c12502014-01-12 12:54:00 +00001128 || defined(VGP_mips32_linux) || defined(VGP_mips64_linux) \
sewardj112711a2015-04-10 12:30:09 +00001129 || defined(VGP_arm64_linux) || defined(VGP_tilegx_linux)
sewardj1e866562005-09-28 19:58:58 +00001130 SysRes res;
1131 res = VG_(do_syscall3)(__NR_socket, domain, type, protocol );
njncda2f0f2009-05-18 02:12:08 +00001132 return sr_isError(res) ? -1 : sr_Res(res);
sewardj9a66bb92006-10-17 01:38:13 +00001133
njnf76d27a2009-05-28 01:53:07 +00001134# elif defined(VGO_darwin)
1135 SysRes res;
1136 res = VG_(do_syscall3)(__NR_socket, domain, type, protocol);
1137 if (!sr_isError(res)) {
1138 // Set SO_NOSIGPIPE so write() returns EPIPE instead of raising SIGPIPE
1139 Int optval = 1;
1140 SysRes res2;
1141 res2 = VG_(do_syscall5)(__NR_setsockopt, sr_Res(res), VKI_SOL_SOCKET,
1142 VKI_SO_NOSIGPIPE, (UWord)&optval,
1143 sizeof(optval));
1144 // ignore setsockopt() error
1145 }
1146 return sr_isError(res) ? -1 : sr_Res(res);
1147
sewardj8eb8bab2015-07-21 14:44:28 +00001148# elif defined(VGO_solaris)
1149 /* XXX There doesn't seem to be an easy way to convince the send syscall to
1150 only return EPIPE instead of raising SIGPIPE. EPIPE is only returned if
1151 SM_KERNEL is set on the socket. Without serious hackery it looks we
1152 can't set this flag.
1153
1154 Should we wrap the send syscall below into sigprocmask calls to block
1155 SIGPIPE?
1156 */
1157 SysRes res;
1158 res = VG_(do_syscall5)(__NR_so_socket, domain, type, protocol,
1159 0 /*devpath*/, VKI_SOV_DEFAULT /*version*/);
1160 return sr_isError(res) ? -1 : sr_Res(res);
1161
njncda2f0f2009-05-18 02:12:08 +00001162# else
1163# error "Unknown arch"
1164# endif
njneb8896b2005-06-04 20:03:55 +00001165}
1166
njncda2f0f2009-05-18 02:12:08 +00001167
njneb8896b2005-06-04 20:03:55 +00001168static
njn4bd96bd2009-05-22 00:52:14 +00001169Int my_connect ( Int sockfd, struct vki_sockaddr_in* serv_addr, Int addrlen )
njneb8896b2005-06-04 20:03:55 +00001170{
njncda2f0f2009-05-18 02:12:08 +00001171# if defined(VGP_x86_linux) || defined(VGP_ppc32_linux) \
carllcae0cc22014-08-07 23:17:29 +00001172 || defined(VGP_ppc64be_linux) || defined(VGP_ppc64le_linux) \
1173 || defined(VGP_s390x_linux)
sewardja8d8e232005-06-07 20:04:56 +00001174 SysRes res;
1175 UWord args[3];
njneb8896b2005-06-04 20:03:55 +00001176 args[0] = sockfd;
1177 args[1] = (UWord)serv_addr;
1178 args[2] = addrlen;
1179 res = VG_(do_syscall2)(__NR_socketcall, VKI_SYS_CONNECT, (UWord)&args);
njncda2f0f2009-05-18 02:12:08 +00001180 return sr_isError(res) ? -1 : sr_Res(res);
cerion85665ca2005-06-20 15:51:07 +00001181
sewardj5db15402012-06-07 09:13:21 +00001182# elif defined(VGP_amd64_linux) || defined(VGP_arm_linux) \
sewardjf0c12502014-01-12 12:54:00 +00001183 || defined(VGP_mips32_linux) || defined(VGP_mips64_linux) \
sewardj112711a2015-04-10 12:30:09 +00001184 || defined(VGP_arm64_linux) || defined(VGP_tilegx_linux)
sewardj1e866562005-09-28 19:58:58 +00001185 SysRes res;
1186 res = VG_(do_syscall3)(__NR_connect, sockfd, (UWord)serv_addr, addrlen);
njncda2f0f2009-05-18 02:12:08 +00001187 return sr_isError(res) ? -1 : sr_Res(res);
sewardj9a66bb92006-10-17 01:38:13 +00001188
njnf76d27a2009-05-28 01:53:07 +00001189# elif defined(VGO_darwin)
1190 SysRes res;
1191 res = VG_(do_syscall3)(__NR_connect_nocancel,
1192 sockfd, (UWord)serv_addr, addrlen);
1193 return sr_isError(res) ? -1 : sr_Res(res);
1194
sewardj8eb8bab2015-07-21 14:44:28 +00001195# elif defined(VGO_solaris)
1196 SysRes res;
1197 res = VG_(do_syscall4)(__NR_connect, sockfd, (UWord)serv_addr, addrlen,
1198 VKI_SOV_DEFAULT /*version*/);
1199 return sr_isError(res) ? -1 : sr_Res(res);
1200
njncda2f0f2009-05-18 02:12:08 +00001201# else
1202# error "Unknown arch"
1203# endif
njneb8896b2005-06-04 20:03:55 +00001204}
1205
floriandbb35842012-10-27 18:39:11 +00001206Int VG_(write_socket)( Int sd, const void *msg, Int count )
njneb8896b2005-06-04 20:03:55 +00001207{
njneb8896b2005-06-04 20:03:55 +00001208 /* This is actually send(). */
njnf76d27a2009-05-28 01:53:07 +00001209
1210 /* For Linux, VKI_MSG_NOSIGNAL is a request not to send SIGPIPE on
sewardj9a66bb92006-10-17 01:38:13 +00001211 errors on stream oriented sockets when the other end breaks the
njnf76d27a2009-05-28 01:53:07 +00001212 connection. The EPIPE error is still returned.
1213
1214 For Darwin, VG_(socket)() sets SO_NOSIGPIPE to get EPIPE instead of
1215 SIGPIPE */
njneb8896b2005-06-04 20:03:55 +00001216
njncda2f0f2009-05-18 02:12:08 +00001217# if defined(VGP_x86_linux) || defined(VGP_ppc32_linux) \
carllcae0cc22014-08-07 23:17:29 +00001218 || defined(VGP_ppc64be_linux) || defined(VGP_ppc64le_linux) \
1219 || defined(VGP_s390x_linux)
sewardja8d8e232005-06-07 20:04:56 +00001220 SysRes res;
1221 UWord args[4];
njneb8896b2005-06-04 20:03:55 +00001222 args[0] = sd;
1223 args[1] = (UWord)msg;
1224 args[2] = count;
sewardj9a66bb92006-10-17 01:38:13 +00001225 args[3] = VKI_MSG_NOSIGNAL;
njneb8896b2005-06-04 20:03:55 +00001226 res = VG_(do_syscall2)(__NR_socketcall, VKI_SYS_SEND, (UWord)&args);
njncda2f0f2009-05-18 02:12:08 +00001227 return sr_isError(res) ? -1 : sr_Res(res);
cerion85665ca2005-06-20 15:51:07 +00001228
sewardj5db15402012-06-07 09:13:21 +00001229# elif defined(VGP_amd64_linux) || defined(VGP_arm_linux) \
sewardjf0c12502014-01-12 12:54:00 +00001230 || defined(VGP_mips32_linux) || defined(VGP_mips64_linux) \
sewardj112711a2015-04-10 12:30:09 +00001231 || defined(VGP_arm64_linux) || defined(VGP_tilegx_linux)
sewardj1e866562005-09-28 19:58:58 +00001232 SysRes res;
sewardj9a66bb92006-10-17 01:38:13 +00001233 res = VG_(do_syscall6)(__NR_sendto, sd, (UWord)msg,
1234 count, VKI_MSG_NOSIGNAL, 0,0);
njncda2f0f2009-05-18 02:12:08 +00001235 return sr_isError(res) ? -1 : sr_Res(res);
sewardj9a66bb92006-10-17 01:38:13 +00001236
njnf76d27a2009-05-28 01:53:07 +00001237# elif defined(VGP_x86_darwin) || defined(VGP_amd64_darwin)
1238 SysRes res;
1239 res = VG_(do_syscall3)(__NR_write_nocancel, sd, (UWord)msg, count);
1240 return sr_isError(res) ? -1 : sr_Res(res);
1241
sewardj8eb8bab2015-07-21 14:44:28 +00001242# elif defined(VGO_solaris)
1243 SysRes res;
1244 res = VG_(do_syscall4)(__NR_send, sd, (UWord)msg, count, 0 /*flags*/);
1245 return sr_isError(res) ? -1 : sr_Res(res);
1246
njncda2f0f2009-05-18 02:12:08 +00001247# else
1248# error "Unknown platform"
1249# endif
njneb8896b2005-06-04 20:03:55 +00001250}
1251
1252Int VG_(getsockname) ( Int sd, struct vki_sockaddr *name, Int *namelen)
1253{
njncda2f0f2009-05-18 02:12:08 +00001254# if defined(VGP_x86_linux) || defined(VGP_ppc32_linux) \
carllcae0cc22014-08-07 23:17:29 +00001255 || defined(VGP_ppc64be_linux) || defined(VGP_ppc64le_linux) \
1256 || defined(VGP_s390x_linux) \
sewardj5db15402012-06-07 09:13:21 +00001257 || defined(VGP_mips32_linux)
sewardj9a66bb92006-10-17 01:38:13 +00001258 SysRes res;
sewardja8d8e232005-06-07 20:04:56 +00001259 UWord args[3];
njneb8896b2005-06-04 20:03:55 +00001260 args[0] = sd;
1261 args[1] = (UWord)name;
1262 args[2] = (UWord)namelen;
1263 res = VG_(do_syscall2)(__NR_socketcall, VKI_SYS_GETSOCKNAME, (UWord)&args);
njncda2f0f2009-05-18 02:12:08 +00001264 return sr_isError(res) ? -1 : sr_Res(res);
sewardja5c9e4a2005-06-09 13:21:58 +00001265
petarj4df0bfc2013-02-27 23:17:33 +00001266# elif defined(VGP_amd64_linux) || defined(VGP_arm_linux) \
sewardj112711a2015-04-10 12:30:09 +00001267 || defined(VGP_mips64_linux) || defined(VGP_arm64_linux) \
1268 || defined(VGP_tilegx_linux)
sewardj9a66bb92006-10-17 01:38:13 +00001269 SysRes res;
sewardja5c9e4a2005-06-09 13:21:58 +00001270 res = VG_(do_syscall3)( __NR_getsockname,
1271 (UWord)sd, (UWord)name, (UWord)namelen );
njncda2f0f2009-05-18 02:12:08 +00001272 return sr_isError(res) ? -1 : sr_Res(res);
sewardj9a66bb92006-10-17 01:38:13 +00001273
njnf76d27a2009-05-28 01:53:07 +00001274# elif defined(VGO_darwin)
1275 SysRes res;
1276 res = VG_(do_syscall3)( __NR_getsockname,
1277 (UWord)sd, (UWord)name, (UWord)namelen );
1278 return sr_isError(res) ? -1 : sr_Res(res);
1279
sewardj8eb8bab2015-07-21 14:44:28 +00001280# elif defined(VGO_solaris)
1281 SysRes res;
1282 res = VG_(do_syscall4)(__NR_getsockname, sd, (UWord)name, (UWord)namelen,
1283 VKI_SOV_DEFAULT /*version*/);
1284 return sr_isError(res) ? -1 : sr_Res(res);
1285
njncda2f0f2009-05-18 02:12:08 +00001286# else
1287# error "Unknown platform"
1288# endif
njneb8896b2005-06-04 20:03:55 +00001289}
1290
1291Int VG_(getpeername) ( Int sd, struct vki_sockaddr *name, Int *namelen)
1292{
njncda2f0f2009-05-18 02:12:08 +00001293# if defined(VGP_x86_linux) || defined(VGP_ppc32_linux) \
carllcae0cc22014-08-07 23:17:29 +00001294 || defined(VGP_ppc64be_linux) || defined(VGP_ppc64le_linux) \
1295 || defined(VGP_s390x_linux) \
sewardj5db15402012-06-07 09:13:21 +00001296 || defined(VGP_mips32_linux)
sewardj9a66bb92006-10-17 01:38:13 +00001297 SysRes res;
sewardja8d8e232005-06-07 20:04:56 +00001298 UWord args[3];
njneb8896b2005-06-04 20:03:55 +00001299 args[0] = sd;
1300 args[1] = (UWord)name;
1301 args[2] = (UWord)namelen;
1302 res = VG_(do_syscall2)(__NR_socketcall, VKI_SYS_GETPEERNAME, (UWord)&args);
njncda2f0f2009-05-18 02:12:08 +00001303 return sr_isError(res) ? -1 : sr_Res(res);
sewardja5c9e4a2005-06-09 13:21:58 +00001304
petarj4df0bfc2013-02-27 23:17:33 +00001305# elif defined(VGP_amd64_linux) || defined(VGP_arm_linux) \
sewardj112711a2015-04-10 12:30:09 +00001306 || defined(VGP_mips64_linux) || defined(VGP_arm64_linux) \
1307 || defined(VGP_tilegx_linux)
sewardj9a66bb92006-10-17 01:38:13 +00001308 SysRes res;
sewardja5c9e4a2005-06-09 13:21:58 +00001309 res = VG_(do_syscall3)( __NR_getpeername,
1310 (UWord)sd, (UWord)name, (UWord)namelen );
njncda2f0f2009-05-18 02:12:08 +00001311 return sr_isError(res) ? -1 : sr_Res(res);
sewardj9a66bb92006-10-17 01:38:13 +00001312
njnf76d27a2009-05-28 01:53:07 +00001313# elif defined(VGO_darwin)
1314 SysRes res;
1315 res = VG_(do_syscall3)( __NR_getpeername,
1316 (UWord)sd, (UWord)name, (UWord)namelen );
1317 return sr_isError(res) ? -1 : sr_Res(res);
1318
sewardj8eb8bab2015-07-21 14:44:28 +00001319# elif defined(VGO_solaris)
1320 SysRes res;
1321 res = VG_(do_syscall4)(__NR_getpeername, sd, (UWord)name, (UWord)namelen,
1322 VKI_SOV_DEFAULT /*version*/);
1323 return sr_isError(res) ? -1 : sr_Res(res);
1324
njncda2f0f2009-05-18 02:12:08 +00001325# else
1326# error "Unknown platform"
1327# endif
njneb8896b2005-06-04 20:03:55 +00001328}
1329
1330Int VG_(getsockopt) ( Int sd, Int level, Int optname, void *optval,
1331 Int *optlen)
1332{
njncda2f0f2009-05-18 02:12:08 +00001333# if defined(VGP_x86_linux) || defined(VGP_ppc32_linux) \
carllcae0cc22014-08-07 23:17:29 +00001334 || defined(VGP_ppc64be_linux) || defined(VGP_ppc64le_linux) \
1335 || defined(VGP_s390x_linux)
sewardj9a66bb92006-10-17 01:38:13 +00001336 SysRes res;
sewardja8d8e232005-06-07 20:04:56 +00001337 UWord args[5];
njneb8896b2005-06-04 20:03:55 +00001338 args[0] = sd;
1339 args[1] = level;
1340 args[2] = optname;
1341 args[3] = (UWord)optval;
1342 args[4] = (UWord)optlen;
1343 res = VG_(do_syscall2)(__NR_socketcall, VKI_SYS_GETSOCKOPT, (UWord)&args);
njncda2f0f2009-05-18 02:12:08 +00001344 return sr_isError(res) ? -1 : sr_Res(res);
sewardja5c9e4a2005-06-09 13:21:58 +00001345
sewardj5db15402012-06-07 09:13:21 +00001346# elif defined(VGP_amd64_linux) || defined(VGP_arm_linux) \
sewardjf0c12502014-01-12 12:54:00 +00001347 || defined(VGP_mips32_linux) || defined(VGP_mips64_linux) \
sewardj112711a2015-04-10 12:30:09 +00001348 || defined(VGP_arm64_linux) || defined(VGP_tilegx_linux)
sewardj9a66bb92006-10-17 01:38:13 +00001349 SysRes res;
sewardja5c9e4a2005-06-09 13:21:58 +00001350 res = VG_(do_syscall5)( __NR_getsockopt,
1351 (UWord)sd, (UWord)level, (UWord)optname,
1352 (UWord)optval, (UWord)optlen );
njncda2f0f2009-05-18 02:12:08 +00001353 return sr_isError(res) ? -1 : sr_Res(res);
sewardj9a66bb92006-10-17 01:38:13 +00001354
njnf76d27a2009-05-28 01:53:07 +00001355# elif defined(VGO_darwin)
1356 SysRes res;
1357 res = VG_(do_syscall5)( __NR_getsockopt,
1358 (UWord)sd, (UWord)level, (UWord)optname,
1359 (UWord)optval, (UWord)optlen );
1360 return sr_isError(res) ? -1 : sr_Res(res);
1361
sewardj8eb8bab2015-07-21 14:44:28 +00001362# elif defined(VGO_solaris)
1363 SysRes res;
1364 res = VG_(do_syscall6)(__NR_getsockopt, sd, level, optname, (UWord)optval,
1365 (UWord)optlen, VKI_SOV_DEFAULT /*version*/);
1366 return sr_isError(res) ? -1 : sr_Res(res);
1367
njncda2f0f2009-05-18 02:12:08 +00001368# else
1369# error "Unknown platform"
1370# endif
njneb8896b2005-06-04 20:03:55 +00001371}
1372
1373
sewardj5d616df2013-07-02 08:07:15 +00001374Int VG_(setsockopt) ( Int sd, Int level, Int optname, void *optval,
1375 Int optlen)
njnf76d27a2009-05-28 01:53:07 +00001376{
sewardj5d616df2013-07-02 08:07:15 +00001377# if defined(VGP_x86_linux) || defined(VGP_ppc32_linux) \
carllcae0cc22014-08-07 23:17:29 +00001378 || defined(VGP_ppc64be_linux) || defined(VGP_ppc64le_linux) \
1379 || defined(VGP_s390x_linux)
sewardj5d616df2013-07-02 08:07:15 +00001380 SysRes res;
1381 UWord args[5];
1382 args[0] = sd;
1383 args[1] = level;
1384 args[2] = optname;
1385 args[3] = (UWord)optval;
1386 args[4] = (UWord)optlen;
1387 res = VG_(do_syscall2)(__NR_socketcall, VKI_SYS_SETSOCKOPT, (UWord)&args);
1388 return sr_isError(res) ? -1 : sr_Res(res);
1389
1390# elif defined(VGP_amd64_linux) || defined(VGP_arm_linux) \
sewardjf0c12502014-01-12 12:54:00 +00001391 || defined(VGP_mips32_linux) || defined(VGP_mips64_linux) \
sewardj112711a2015-04-10 12:30:09 +00001392 || defined(VGP_arm64_linux) || defined(VGP_tilegx_linux)
sewardj5d616df2013-07-02 08:07:15 +00001393 SysRes res;
1394 res = VG_(do_syscall5)( __NR_setsockopt,
1395 (UWord)sd, (UWord)level, (UWord)optname,
1396 (UWord)optval, (UWord)optlen );
1397 return sr_isError(res) ? -1 : sr_Res(res);
1398
1399# elif defined(VGO_darwin)
1400 SysRes res;
1401 res = VG_(do_syscall5)( __NR_setsockopt,
1402 (UWord)sd, (UWord)level, (UWord)optname,
1403 (UWord)optval, (UWord)optlen );
1404 return sr_isError(res) ? -1 : sr_Res(res);
1405
sewardj8eb8bab2015-07-21 14:44:28 +00001406# elif defined(VGO_solaris)
1407 SysRes res;
1408 res = VG_(do_syscall6)( __NR_setsockopt,
1409 (UWord)sd, (UWord)level, (UWord)optname,
1410 (UWord)optval, (UWord)optlen,
1411 VKI_SOV_DEFAULT /*version*/ );
1412 return sr_isError(res) ? -1 : sr_Res(res);
1413
sewardj5d616df2013-07-02 08:07:15 +00001414# else
1415# error "Unknown platform"
1416# endif
1417}
1418
1419
florian6bd9dc12012-11-23 16:17:43 +00001420const HChar *VG_(basename)(const HChar *path)
njnf76d27a2009-05-28 01:53:07 +00001421{
florian58946e92014-09-27 13:29:09 +00001422 static HChar *buf = NULL;
1423 static SizeT buf_len = 0;
florian19f91bb2012-11-10 22:29:54 +00001424 const HChar *p, *end;
njnf76d27a2009-05-28 01:53:07 +00001425
1426 if (path == NULL ||
1427 0 == VG_(strcmp)(path, ""))
1428 {
1429 return ".";
1430 }
1431
1432 p = path + VG_(strlen)(path);
1433 while (p > path && *p == '/') {
1434 // skip all trailing '/'
1435 p--;
1436 }
1437
1438 if (p == path && *p == '/') return "/"; // all slashes
1439
1440 end = p;
1441
1442 while (p > path && *p != '/') {
1443 // now skip non '/'
1444 p--;
1445 }
1446
1447 if (*p == '/') p++;
1448
florian58946e92014-09-27 13:29:09 +00001449 SizeT need = end-p+1 + 1;
1450 if (need > buf_len) {
1451 buf_len = (buf_len == 0) ? 500 : need;
1452 buf = VG_(realloc)("basename", buf, buf_len);
1453 }
njnf76d27a2009-05-28 01:53:07 +00001454 VG_(strncpy)(buf, p, end-p+1);
1455 buf[end-p+1] = '\0';
1456
1457 return buf;
1458}
1459
1460
florian6bd9dc12012-11-23 16:17:43 +00001461const HChar *VG_(dirname)(const HChar *path)
njnf76d27a2009-05-28 01:53:07 +00001462{
florian58946e92014-09-27 13:29:09 +00001463 static HChar *buf = NULL;
1464 static SizeT buf_len = 0;
njnf76d27a2009-05-28 01:53:07 +00001465
florian19f91bb2012-11-10 22:29:54 +00001466 const HChar *p;
njnf76d27a2009-05-28 01:53:07 +00001467
1468 if (path == NULL ||
1469 0 == VG_(strcmp)(path, "") ||
1470 0 == VG_(strcmp)(path, "/"))
1471 {
1472 return ".";
1473 }
1474
1475 p = path + VG_(strlen)(path);
1476 while (p > path && *p == '/') {
1477 // skip all trailing '/'
1478 p--;
1479 }
1480
1481 while (p > path && *p != '/') {
1482 // now skip non '/'
1483 p--;
1484 }
1485
1486 if (p == path) {
1487 if (*p == '/') return "/"; // all slashes
1488 else return "."; // no slashes
1489 }
1490
1491 while (p > path && *p == '/') {
1492 // skip '/' again
1493 p--;
1494 }
1495
florian58946e92014-09-27 13:29:09 +00001496 SizeT need = p-path+1 + 1;
1497 if (need > buf_len) {
1498 buf_len = (buf_len == 0) ? 500 : need;
1499 buf = VG_(realloc)("dirname", buf, buf_len);
1500 }
njnf76d27a2009-05-28 01:53:07 +00001501 VG_(strncpy)(buf, path, p-path+1);
1502 buf[p-path+1] = '\0';
1503
1504 return buf;
1505}
1506
1507
njneb8896b2005-06-04 20:03:55 +00001508/*--------------------------------------------------------------------*/
1509/*--- end ---*/
1510/*--------------------------------------------------------------------*/