blob: 2e8ebca80602c082ab4d3fbc80fc6b3cfb0a59ae [file] [log] [blame]
njneb8896b2005-06-04 20:03:55 +00001
2/*--------------------------------------------------------------------*/
3/*--- File- and socket-related libc stuff. m_libcfile.c ---*/
4/*--------------------------------------------------------------------*/
5
6/*
7 This file is part of Valgrind, a dynamic binary instrumentation
8 framework.
9
sewardj03f8d3f2012-08-05 15:46:46 +000010 Copyright (C) 2000-2012 Julian Seward
njneb8896b2005-06-04 20:03:55 +000011 jseward@acm.org
12
13 This program is free software; you can redistribute it and/or
14 modify it under the terms of the GNU General Public License as
15 published by the Free Software Foundation; either version 2 of the
16 License, or (at your option) any later version.
17
18 This program is distributed in the hope that it will be useful, but
19 WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 General Public License for more details.
22
23 You should have received a copy of the GNU General Public License
24 along with this program; if not, write to the Free Software
25 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
26 02111-1307, USA.
27
28 The GNU General Public License is contained in the file COPYING.
29*/
30
njnc7561b92005-06-19 01:24:32 +000031#include "pub_core_basics.h"
sewardj4cfea4f2006-10-14 19:26:10 +000032#include "pub_core_vki.h"
sewardj9a66bb92006-10-17 01:38:13 +000033#include "pub_core_vkiscnums.h"
sewardj26b87282006-10-17 12:49:31 +000034#include "pub_core_debuglog.h"
njneb8896b2005-06-04 20:03:55 +000035#include "pub_core_libcbase.h"
36#include "pub_core_libcassert.h"
37#include "pub_core_libcfile.h"
sewardjfdf91b42005-09-28 00:53:09 +000038#include "pub_core_libcprint.h" // VG_(sprintf)
sewardj45f4e7c2005-09-27 19:20:21 +000039#include "pub_core_libcproc.h" // VG_(getpid), VG_(getppid)
sewardj14c7cc52007-02-25 15:08:24 +000040#include "pub_core_xarray.h"
sewardjfdf91b42005-09-28 00:53:09 +000041#include "pub_core_clientstate.h" // VG_(fd_hard_limit)
njn9abd6082005-06-17 21:31:45 +000042#include "pub_core_syscall.h"
njneb8896b2005-06-04 20:03:55 +000043
njnf76d27a2009-05-28 01:53:07 +000044/* IMPORTANT: on Darwin it is essential to use the _nocancel versions
45 of syscalls rather than the vanilla version, if a _nocancel version
46 is available. See docs/internals/Darwin-notes.txt for the reason
47 why. */
48
njneb8896b2005-06-04 20:03:55 +000049/* ---------------------------------------------------------------------
50 File stuff
51 ------------------------------------------------------------------ */
52
53static inline Bool fd_exists(Int fd)
54{
sewardjec61b652008-08-19 07:03:04 +000055 struct vg_stat st;
njneb8896b2005-06-04 20:03:55 +000056 return VG_(fstat)(fd, &st) == 0;
57}
58
59/* Move an fd into the Valgrind-safe range */
60Int VG_(safe_fd)(Int oldfd)
61{
62 Int newfd;
63
64 vg_assert(VG_(fd_hard_limit) != -1);
65
66 newfd = VG_(fcntl)(oldfd, VKI_F_DUPFD, VG_(fd_hard_limit));
67 if (newfd != -1)
68 VG_(close)(oldfd);
69
sewardj9a66bb92006-10-17 01:38:13 +000070 /* Set the close-on-exec flag for this fd. */
njneb8896b2005-06-04 20:03:55 +000071 VG_(fcntl)(newfd, VKI_F_SETFD, VKI_FD_CLOEXEC);
72
73 vg_assert(newfd >= VG_(fd_hard_limit));
74 return newfd;
75}
76
njnae7359b2005-06-19 21:10:42 +000077/* Given a file descriptor, attempt to deduce its filename. To do
78 this, we use /proc/self/fd/<FD>. If this doesn't point to a file,
njnf845f8f2005-06-23 02:26:47 +000079 or if it doesn't exist, we return False. */
80Bool VG_(resolve_filename) ( Int fd, HChar* buf, Int n_buf )
njnae7359b2005-06-19 21:10:42 +000081{
njn81b975c2009-04-28 05:35:53 +000082# if defined(VGO_linux)
njnae7359b2005-06-19 21:10:42 +000083 HChar tmp[64];
njnae7359b2005-06-19 21:10:42 +000084 VG_(sprintf)(tmp, "/proc/self/fd/%d", fd);
njnf845f8f2005-06-23 02:26:47 +000085 VG_(memset)(buf, 0, n_buf);
sewardj45f4e7c2005-09-27 19:20:21 +000086 if (VG_(readlink)(tmp, buf, n_buf) > 0 && buf[0] == '/')
njnf845f8f2005-06-23 02:26:47 +000087 return True;
88 else
89 return False;
njndad944a2009-05-04 05:55:46 +000090
njnf76d27a2009-05-28 01:53:07 +000091# elif defined(VGO_darwin)
92 HChar tmp[VKI_MAXPATHLEN+1];
93 if (0 == VG_(fcntl)(fd, VKI_F_GETPATH, (UWord)tmp)) {
94 if (n_buf > 0) {
95 VG_(strncpy)( buf, tmp, n_buf < sizeof(tmp) ? n_buf : sizeof(tmp) );
96 buf[n_buf-1] = 0;
97 }
98 if (tmp[0] == '/') return True;
99 }
100 return False;
101
njn81b975c2009-04-28 05:35:53 +0000102# else
njndad944a2009-05-04 05:55:46 +0000103# error Unknown OS
njn81b975c2009-04-28 05:35:53 +0000104# endif
njnae7359b2005-06-19 21:10:42 +0000105}
106
florian19f91bb2012-11-10 22:29:54 +0000107SysRes VG_(mknod) ( const HChar* pathname, Int mode, UWord dev )
sewardj3b290482011-05-06 21:02:55 +0000108{
sewardj6e9de462011-06-28 07:25:29 +0000109# if defined(VGO_linux) || defined(VGO_darwin)
sewardj3b290482011-05-06 21:02:55 +0000110 SysRes res = VG_(do_syscall3)(__NR_mknod,
111 (UWord)pathname, mode, dev);
112# else
113# error Unknown OS
114# endif
115 return res;
116}
117
florian19f91bb2012-11-10 22:29:54 +0000118SysRes VG_(open) ( const HChar* pathname, Int flags, Int mode )
njneb8896b2005-06-04 20:03:55 +0000119{
sewardj6e9de462011-06-28 07:25:29 +0000120# if defined(VGO_linux)
njnf76d27a2009-05-28 01:53:07 +0000121 SysRes res = VG_(do_syscall3)(__NR_open,
122 (UWord)pathname, flags, mode);
123# elif defined(VGO_darwin)
124 SysRes res = VG_(do_syscall3)(__NR_open_nocancel,
125 (UWord)pathname, flags, mode);
126# else
127# error Unknown OS
128# endif
sewardj92645592005-07-23 09:18:34 +0000129 return res;
njneb8896b2005-06-04 20:03:55 +0000130}
131
florian19f91bb2012-11-10 22:29:54 +0000132Int VG_(fd_open) (const HChar* pathname, Int flags, Int mode)
sewardj3b290482011-05-06 21:02:55 +0000133{
134 SysRes sr;
135 sr = VG_(open) (pathname, flags, mode);
136 if (sr_isError (sr))
137 return -1;
138 else
139 return sr_Res (sr);
140}
141
njneb8896b2005-06-04 20:03:55 +0000142void VG_(close) ( Int fd )
143{
njnf76d27a2009-05-28 01:53:07 +0000144 /* Hmm. Return value is not checked. That's uncool. */
sewardj6e9de462011-06-28 07:25:29 +0000145# if defined(VGO_linux)
sewardja8d8e232005-06-07 20:04:56 +0000146 (void)VG_(do_syscall1)(__NR_close, fd);
njnf76d27a2009-05-28 01:53:07 +0000147# elif defined(VGO_darwin)
148 (void)VG_(do_syscall1)(__NR_close_nocancel, fd);
149# else
150# error Unknown OS
151# endif
njneb8896b2005-06-04 20:03:55 +0000152}
153
154Int VG_(read) ( Int fd, void* buf, Int count)
155{
sewardj9a66bb92006-10-17 01:38:13 +0000156 Int ret;
sewardj6e9de462011-06-28 07:25:29 +0000157# if defined(VGO_linux)
sewardja8d8e232005-06-07 20:04:56 +0000158 SysRes res = VG_(do_syscall3)(__NR_read, fd, (UWord)buf, count);
njnf76d27a2009-05-28 01:53:07 +0000159# elif defined(VGO_darwin)
160 SysRes res = VG_(do_syscall3)(__NR_read_nocancel, fd, (UWord)buf, count);
161# else
162# error Unknown OS
163# endif
njncda2f0f2009-05-18 02:12:08 +0000164 if (sr_isError(res)) {
165 ret = - (Int)(Word)sr_Err(res);
sewardj9a66bb92006-10-17 01:38:13 +0000166 vg_assert(ret < 0);
167 } else {
njncda2f0f2009-05-18 02:12:08 +0000168 ret = (Int)(Word)sr_Res(res);
sewardj9a66bb92006-10-17 01:38:13 +0000169 vg_assert(ret >= 0);
170 }
171 return ret;
njneb8896b2005-06-04 20:03:55 +0000172}
173
174Int VG_(write) ( Int fd, const void* buf, Int count)
175{
sewardj9a66bb92006-10-17 01:38:13 +0000176 Int ret;
sewardj6e9de462011-06-28 07:25:29 +0000177# if defined(VGO_linux)
sewardja8d8e232005-06-07 20:04:56 +0000178 SysRes res = VG_(do_syscall3)(__NR_write, fd, (UWord)buf, count);
njnf76d27a2009-05-28 01:53:07 +0000179# elif defined(VGO_darwin)
180 SysRes res = VG_(do_syscall3)(__NR_write_nocancel, fd, (UWord)buf, count);
181# else
182# error "Unknown OS"
183# endif
njncda2f0f2009-05-18 02:12:08 +0000184 if (sr_isError(res)) {
185 ret = - (Int)(Word)sr_Err(res);
sewardj9a66bb92006-10-17 01:38:13 +0000186 vg_assert(ret < 0);
187 } else {
njncda2f0f2009-05-18 02:12:08 +0000188 ret = (Int)(Word)sr_Res(res);
sewardj9a66bb92006-10-17 01:38:13 +0000189 vg_assert(ret >= 0);
190 }
191 return ret;
njneb8896b2005-06-04 20:03:55 +0000192}
193
njncda2f0f2009-05-18 02:12:08 +0000194
njneb8896b2005-06-04 20:03:55 +0000195Int VG_(pipe) ( Int fd[2] )
196{
sewardj5db15402012-06-07 09:13:21 +0000197# if defined(VGP_mips32_linux)
198 /* __NR_pipe has a strange return convention on mips32-linux. */
199 SysRes res = VG_(do_syscall0)(__NR_pipe);
200 if (!sr_isError(res)) {
201 fd[0] = (Int)sr_Res(res);
202 fd[1] = (Int)sr_ResEx(res);
203 return 0;
204 } else {
205 return -1;
206 }
207# elif defined(VGO_linux)
sewardja8d8e232005-06-07 20:04:56 +0000208 SysRes res = VG_(do_syscall1)(__NR_pipe, (UWord)fd);
njncda2f0f2009-05-18 02:12:08 +0000209 return sr_isError(res) ? -1 : 0;
njnf76d27a2009-05-28 01:53:07 +0000210# elif defined(VGO_darwin)
211 /* __NR_pipe is UX64, so produces a double-word result */
212 SysRes res = VG_(do_syscall0)(__NR_pipe);
213 if (!sr_isError(res)) {
214 fd[0] = (Int)sr_Res(res);
215 fd[1] = (Int)sr_ResHI(res);
216 }
217 return sr_isError(res) ? -1 : 0;
njncda2f0f2009-05-18 02:12:08 +0000218# else
219# error "Unknown OS"
220# endif
njneb8896b2005-06-04 20:03:55 +0000221}
222
tomc17c6ef2011-07-13 09:02:14 +0000223Off64T VG_(lseek) ( Int fd, Off64T offset, Int whence )
njneb8896b2005-06-04 20:03:55 +0000224{
sewardj6e9de462011-06-28 07:25:29 +0000225# if defined(VGO_linux) || defined(VGP_amd64_darwin)
tomc17c6ef2011-07-13 09:02:14 +0000226# if defined(__NR__llseek)
227 Off64T result;
228 SysRes res = VG_(do_syscall5)(__NR__llseek, fd,
229 offset >> 32, offset & 0xffffffff,
tomf9b1d732011-07-13 10:05:24 +0000230 (UWord)&result, whence);
tomc17c6ef2011-07-13 09:02:14 +0000231 return sr_isError(res) ? (-1) : result;
232# else
sewardja8d8e232005-06-07 20:04:56 +0000233 SysRes res = VG_(do_syscall3)(__NR_lseek, fd, offset, whence);
tomc17c6ef2011-07-13 09:02:14 +0000234 vg_assert(sizeof(Off64T) == sizeof(Word));
235 return sr_isError(res) ? (-1) : sr_Res(res);
236# endif
njnf76d27a2009-05-28 01:53:07 +0000237# elif defined(VGP_x86_darwin)
238 SysRes res = VG_(do_syscall4)(__NR_lseek, fd,
239 offset & 0xffffffff, offset >> 32, whence);
tomc17c6ef2011-07-13 09:02:14 +0000240 return sr_isError(res) ? (-1) : sr_Res(res);
njncda2f0f2009-05-18 02:12:08 +0000241# else
242# error "Unknown plat"
243# endif
sewardj45f4e7c2005-09-27 19:20:21 +0000244 /* if you change the error-reporting conventions of this, also
philippe8050bb72012-04-13 23:07:29 +0000245 change all usage points. */
njneb8896b2005-06-04 20:03:55 +0000246}
247
sewardjec61b652008-08-19 07:03:04 +0000248
249/* stat/fstat support. It's uggerly. We have impedance-match into a
250 'struct vg_stat' in order to have a single structure that callers
251 can use consistently on all platforms. */
252
253#define TRANSLATE_TO_vg_stat(_p_vgstat, _p_vkistat) \
254 do { \
njn9c20ece2009-05-20 02:02:30 +0000255 (_p_vgstat)->dev = (ULong)( (_p_vkistat)->st_dev ); \
256 (_p_vgstat)->ino = (ULong)( (_p_vkistat)->st_ino ); \
257 (_p_vgstat)->nlink = (ULong)( (_p_vkistat)->st_nlink ); \
258 (_p_vgstat)->mode = (UInt) ( (_p_vkistat)->st_mode ); \
259 (_p_vgstat)->uid = (UInt) ( (_p_vkistat)->st_uid ); \
260 (_p_vgstat)->gid = (UInt) ( (_p_vkistat)->st_gid ); \
261 (_p_vgstat)->rdev = (ULong)( (_p_vkistat)->st_rdev ); \
262 (_p_vgstat)->size = (Long) ( (_p_vkistat)->st_size ); \
263 (_p_vgstat)->blksize = (ULong)( (_p_vkistat)->st_blksize ); \
264 (_p_vgstat)->blocks = (ULong)( (_p_vkistat)->st_blocks ); \
265 (_p_vgstat)->atime = (ULong)( (_p_vkistat)->st_atime ); \
266 (_p_vgstat)->atime_nsec = (ULong)( (_p_vkistat)->st_atime_nsec ); \
267 (_p_vgstat)->mtime = (ULong)( (_p_vkistat)->st_mtime ); \
268 (_p_vgstat)->mtime_nsec = (ULong)( (_p_vkistat)->st_mtime_nsec ); \
269 (_p_vgstat)->ctime = (ULong)( (_p_vkistat)->st_ctime ); \
270 (_p_vgstat)->ctime_nsec = (ULong)( (_p_vkistat)->st_ctime_nsec ); \
sewardjec61b652008-08-19 07:03:04 +0000271 } while (0)
272
florian19f91bb2012-11-10 22:29:54 +0000273SysRes VG_(stat) ( const HChar* file_name, struct vg_stat* vgbuf )
njneb8896b2005-06-04 20:03:55 +0000274{
sewardjec61b652008-08-19 07:03:04 +0000275 SysRes res;
276 VG_(memset)(vgbuf, 0, sizeof(*vgbuf));
njncda2f0f2009-05-18 02:12:08 +0000277
njnf76d27a2009-05-28 01:53:07 +0000278# if defined(VGO_linux) || defined(VGO_darwin)
njncda2f0f2009-05-18 02:12:08 +0000279 /* First try with stat64. If that doesn't work out, fall back to
280 the vanilla version. */
sewardjec61b652008-08-19 07:03:04 +0000281# if defined(__NR_stat64)
282 { struct vki_stat64 buf64;
283 res = VG_(do_syscall2)(__NR_stat64, (UWord)file_name, (UWord)&buf64);
njncda2f0f2009-05-18 02:12:08 +0000284 if (!(sr_isError(res) && sr_Err(res) == VKI_ENOSYS)) {
sewardjec61b652008-08-19 07:03:04 +0000285 /* Success, or any failure except ENOSYS */
njncda2f0f2009-05-18 02:12:08 +0000286 if (!sr_isError(res))
sewardjec61b652008-08-19 07:03:04 +0000287 TRANSLATE_TO_vg_stat(vgbuf, &buf64);
288 return res;
289 }
290 }
njncda2f0f2009-05-18 02:12:08 +0000291# endif /* defined(__NR_stat64) */
sewardjec61b652008-08-19 07:03:04 +0000292 { struct vki_stat buf;
293 res = VG_(do_syscall2)(__NR_stat, (UWord)file_name, (UWord)&buf);
njncda2f0f2009-05-18 02:12:08 +0000294 if (!sr_isError(res))
sewardjec61b652008-08-19 07:03:04 +0000295 TRANSLATE_TO_vg_stat(vgbuf, &buf);
296 return res;
297 }
njncda2f0f2009-05-18 02:12:08 +0000298
sewardj9a66bb92006-10-17 01:38:13 +0000299# else
300# error Unknown OS
301# endif
njneb8896b2005-06-04 20:03:55 +0000302}
303
sewardjec61b652008-08-19 07:03:04 +0000304Int VG_(fstat) ( Int fd, struct vg_stat* vgbuf )
njneb8896b2005-06-04 20:03:55 +0000305{
sewardjec61b652008-08-19 07:03:04 +0000306 SysRes res;
307 VG_(memset)(vgbuf, 0, sizeof(*vgbuf));
njncda2f0f2009-05-18 02:12:08 +0000308
njnf76d27a2009-05-28 01:53:07 +0000309# if defined(VGO_linux) || defined(VGO_darwin)
njncda2f0f2009-05-18 02:12:08 +0000310 /* First try with fstat64. If that doesn't work out, fall back to
311 the vanilla version. */
sewardjec61b652008-08-19 07:03:04 +0000312# if defined(__NR_fstat64)
313 { struct vki_stat64 buf64;
314 res = VG_(do_syscall2)(__NR_fstat64, (UWord)fd, (UWord)&buf64);
njncda2f0f2009-05-18 02:12:08 +0000315 if (!(sr_isError(res) && sr_Err(res) == VKI_ENOSYS)) {
sewardjec61b652008-08-19 07:03:04 +0000316 /* Success, or any failure except ENOSYS */
njncda2f0f2009-05-18 02:12:08 +0000317 if (!sr_isError(res))
sewardjec61b652008-08-19 07:03:04 +0000318 TRANSLATE_TO_vg_stat(vgbuf, &buf64);
njncda2f0f2009-05-18 02:12:08 +0000319 return sr_isError(res) ? (-1) : 0;
sewardjec61b652008-08-19 07:03:04 +0000320 }
321 }
322# endif /* if defined(__NR_fstat64) */
323 { struct vki_stat buf;
324 res = VG_(do_syscall2)(__NR_fstat, (UWord)fd, (UWord)&buf);
njncda2f0f2009-05-18 02:12:08 +0000325 if (!sr_isError(res))
sewardjec61b652008-08-19 07:03:04 +0000326 TRANSLATE_TO_vg_stat(vgbuf, &buf);
njncda2f0f2009-05-18 02:12:08 +0000327 return sr_isError(res) ? (-1) : 0;
sewardjec61b652008-08-19 07:03:04 +0000328 }
njncda2f0f2009-05-18 02:12:08 +0000329
sewardj9a66bb92006-10-17 01:38:13 +0000330# else
331# error Unknown OS
332# endif
njneb8896b2005-06-04 20:03:55 +0000333}
334
sewardjec61b652008-08-19 07:03:04 +0000335#undef TRANSLATE_TO_vg_stat
336
337
338Long VG_(fsize) ( Int fd )
njneb8896b2005-06-04 20:03:55 +0000339{
sewardjec61b652008-08-19 07:03:04 +0000340 struct vg_stat buf;
341 Int res = VG_(fstat)( fd, &buf );
njn9c20ece2009-05-20 02:02:30 +0000342 return (res == -1) ? (-1LL) : buf.size;
sewardj45f4e7c2005-09-27 19:20:21 +0000343}
344
njn63e5e6e2009-05-20 04:22:42 +0000345Bool VG_(is_dir) ( const HChar* f )
njn73750612005-10-14 03:11:30 +0000346{
sewardjec61b652008-08-19 07:03:04 +0000347 struct vg_stat buf;
sewardj9a66bb92006-10-17 01:38:13 +0000348 SysRes res = VG_(stat)(f, &buf);
njncda2f0f2009-05-18 02:12:08 +0000349 return sr_isError(res) ? False
njn9c20ece2009-05-20 02:02:30 +0000350 : VKI_S_ISDIR(buf.mode) ? True : False;
njn73750612005-10-14 03:11:30 +0000351}
352
sewardj45f4e7c2005-09-27 19:20:21 +0000353SysRes VG_(dup) ( Int oldfd )
354{
355 return VG_(do_syscall1)(__NR_dup, oldfd);
njneb8896b2005-06-04 20:03:55 +0000356}
357
njnfad98372008-10-12 19:53:28 +0000358SysRes VG_(dup2) ( Int oldfd, Int newfd )
359{
sewardj6e9de462011-06-28 07:25:29 +0000360# if defined(VGO_linux) || defined(VGO_darwin)
njnfad98372008-10-12 19:53:28 +0000361 return VG_(do_syscall2)(__NR_dup2, oldfd, newfd);
sewardj485ce162008-10-22 00:57:29 +0000362# else
363# error Unknown OS
364# endif
njnfad98372008-10-12 19:53:28 +0000365}
366
njn327fe8a2005-06-12 02:49:35 +0000367/* Returns -1 on error. */
njnbb7af3f2009-05-22 07:08:12 +0000368Int VG_(fcntl) ( Int fd, Int cmd, Addr arg )
njn327fe8a2005-06-12 02:49:35 +0000369{
sewardj6e9de462011-06-28 07:25:29 +0000370# if defined(VGO_linux)
njn327fe8a2005-06-12 02:49:35 +0000371 SysRes res = VG_(do_syscall3)(__NR_fcntl, fd, cmd, arg);
njnf76d27a2009-05-28 01:53:07 +0000372# elif defined(VGO_darwin)
373 SysRes res = VG_(do_syscall3)(__NR_fcntl_nocancel, fd, cmd, arg);
374# else
375# error "Unknown OS"
376# endif
njncda2f0f2009-05-18 02:12:08 +0000377 return sr_isError(res) ? -1 : sr_Res(res);
njn327fe8a2005-06-12 02:49:35 +0000378}
379
florian19f91bb2012-11-10 22:29:54 +0000380Int VG_(rename) ( const HChar* old_name, const HChar* new_name )
njneb8896b2005-06-04 20:03:55 +0000381{
sewardja8d8e232005-06-07 20:04:56 +0000382 SysRes res = VG_(do_syscall2)(__NR_rename, (UWord)old_name, (UWord)new_name);
njncda2f0f2009-05-18 02:12:08 +0000383 return sr_isError(res) ? (-1) : 0;
njneb8896b2005-06-04 20:03:55 +0000384}
385
florian19f91bb2012-11-10 22:29:54 +0000386Int VG_(unlink) ( const HChar* file_name )
njneb8896b2005-06-04 20:03:55 +0000387{
sewardja8d8e232005-06-07 20:04:56 +0000388 SysRes res = VG_(do_syscall1)(__NR_unlink, (UWord)file_name);
njncda2f0f2009-05-18 02:12:08 +0000389 return sr_isError(res) ? (-1) : 0;
njneb8896b2005-06-04 20:03:55 +0000390}
391
sewardj198f34f2007-07-09 23:13:07 +0000392/* The working directory at startup. AIX doesn't provide an easy
393 system call to do getcwd, but fortunately we don't need arbitrary
394 getcwd support. All that is really needed is to note the cwd at
395 process startup. Hence VG_(record_startup_wd) notes it (in a
396 platform dependent way) and VG_(get_startup_wd) produces the noted
397 value. Hence: */
398static HChar startup_wd[VKI_PATH_MAX];
399static Bool startup_wd_acquired = False;
400
401/* Record the process' working directory at startup. Is intended to
402 be called exactly once, at startup, before the working directory
403 changes. Return True for success, False for failure, so that the
404 caller can bomb out suitably without creating module cycles if
405 there is a problem. */
406Bool VG_(record_startup_wd) ( void )
njneb8896b2005-06-04 20:03:55 +0000407{
sewardj198f34f2007-07-09 23:13:07 +0000408 const Int szB = sizeof(startup_wd);
409 vg_assert(!startup_wd_acquired);
410 vg_assert(szB >= 512 && szB <= 16384/*let's say*/); /* stay sane */
411 VG_(memset)(startup_wd, 0, szB);
sewardj9a66bb92006-10-17 01:38:13 +0000412# if defined(VGO_linux)
sewardj198f34f2007-07-09 23:13:07 +0000413 /* Simple: just ask the kernel */
414 { SysRes res
415 = VG_(do_syscall2)(__NR_getcwd, (UWord)startup_wd, szB-1);
416 vg_assert(startup_wd[szB-1] == 0);
njncda2f0f2009-05-18 02:12:08 +0000417 if (sr_isError(res)) {
sewardj198f34f2007-07-09 23:13:07 +0000418 return False;
419 } else {
420 startup_wd_acquired = True;
421 return True;
422 }
423 }
sewardj6e9de462011-06-28 07:25:29 +0000424# elif defined(VGO_darwin)
njnf76d27a2009-05-28 01:53:07 +0000425 /* We can't ask the kernel, so instead rely on launcher-*.c to
sewardj198f34f2007-07-09 23:13:07 +0000426 tell us the startup path. Note the env var is keyed to the
427 parent's PID, not ours, since our parent is the launcher
428 process. */
florian19f91bb2012-11-10 22:29:54 +0000429 { HChar envvar[100];
430 HChar* wd = NULL;
sewardj198f34f2007-07-09 23:13:07 +0000431 VG_(memset)(envvar, 0, sizeof(envvar));
432 VG_(sprintf)(envvar, "VALGRIND_STARTUP_PWD_%d_XYZZY",
433 (Int)VG_(getppid)());
434 wd = VG_(getenv)( envvar );
435 if (wd == NULL || (1+VG_(strlen)(wd) >= szB))
436 return False;
437 VG_(strncpy_safely)(startup_wd, wd, szB);
438 vg_assert(startup_wd[szB-1] == 0);
439 startup_wd_acquired = True;
440 return True;
441 }
sewardj9a66bb92006-10-17 01:38:13 +0000442# else
443# error Unknown OS
444# endif
njneb8896b2005-06-04 20:03:55 +0000445}
446
sewardj198f34f2007-07-09 23:13:07 +0000447/* Copy the previously acquired startup_wd into buf[0 .. size-1],
448 or return False if buf isn't big enough. */
florian19f91bb2012-11-10 22:29:54 +0000449Bool VG_(get_startup_wd) ( HChar* buf, SizeT size )
sewardj198f34f2007-07-09 23:13:07 +0000450{
451 vg_assert(startup_wd_acquired);
452 vg_assert(startup_wd[ sizeof(startup_wd)-1 ] == 0);
453 if (1+VG_(strlen)(startup_wd) >= size)
454 return False;
455 VG_(strncpy_safely)(buf, startup_wd, size);
456 return True;
457}
458
sewardj6caac712012-08-18 06:45:07 +0000459Int VG_(poll) (struct vki_pollfd *fds, Int nfds, Int timeout)
sewardj3b290482011-05-06 21:02:55 +0000460{
461 SysRes res;
sewardj6caac712012-08-18 06:45:07 +0000462# if defined(VGO_linux)
sewardj3b290482011-05-06 21:02:55 +0000463 res = VG_(do_syscall3)(__NR_poll, (UWord)fds, nfds, timeout);
sewardj6caac712012-08-18 06:45:07 +0000464# elif defined(VGO_darwin)
465 res = VG_(do_syscall3)(__NR_poll_nocancel, (UWord)fds, nfds, timeout);
466# else
467# error "Unknown OS"
468# endif
sewardj3b290482011-05-06 21:02:55 +0000469 return sr_isError(res) ? -1 : sr_Res(res);
470}
471
472
florian19f91bb2012-11-10 22:29:54 +0000473Int VG_(readlink) (const HChar* path, HChar* buf, UInt bufsiz)
njneb8896b2005-06-04 20:03:55 +0000474{
sewardja8d8e232005-06-07 20:04:56 +0000475 SysRes res;
njneb8896b2005-06-04 20:03:55 +0000476 /* res = readlink( path, buf, bufsiz ); */
477 res = VG_(do_syscall3)(__NR_readlink, (UWord)path, (UWord)buf, bufsiz);
njncda2f0f2009-05-18 02:12:08 +0000478 return sr_isError(res) ? -1 : sr_Res(res);
njneb8896b2005-06-04 20:03:55 +0000479}
480
njncda2f0f2009-05-18 02:12:08 +0000481Int VG_(getdents) (Int fd, struct vki_dirent *dirp, UInt count)
njneb8896b2005-06-04 20:03:55 +0000482{
sewardj6e9de462011-06-28 07:25:29 +0000483# if defined(VGO_linux)
sewardja8d8e232005-06-07 20:04:56 +0000484 SysRes res;
njneb8896b2005-06-04 20:03:55 +0000485 /* res = getdents( fd, dirp, count ); */
486 res = VG_(do_syscall3)(__NR_getdents, fd, (UWord)dirp, count);
njncda2f0f2009-05-18 02:12:08 +0000487 return sr_isError(res) ? -1 : sr_Res(res);
njnf76d27a2009-05-28 01:53:07 +0000488# elif defined(VGO_darwin)
489 I_die_here;
njncda2f0f2009-05-18 02:12:08 +0000490# else
491# error "Unknown OS"
492# endif
njneb8896b2005-06-04 20:03:55 +0000493}
494
sewardj45f4e7c2005-09-27 19:20:21 +0000495/* Check accessibility of a file. Returns zero for access granted,
496 nonzero otherwise. */
njn63e5e6e2009-05-20 04:22:42 +0000497Int VG_(access) ( const HChar* path, Bool irusr, Bool iwusr, Bool ixusr )
sewardj45f4e7c2005-09-27 19:20:21 +0000498{
sewardj9a66bb92006-10-17 01:38:13 +0000499# if defined(VGO_linux)
sewardj45f4e7c2005-09-27 19:20:21 +0000500 /* Very annoyingly, I cannot find any definition for R_OK et al in
501 the kernel interfaces. Therefore I reluctantly resort to
502 hardwiring in these magic numbers that I determined by
503 experimentation. */
njncda2f0f2009-05-18 02:12:08 +0000504# define VKI_R_OK 4
505# define VKI_W_OK 2
506# define VKI_X_OK 1
507# endif
508
sewardj9a66bb92006-10-17 01:38:13 +0000509 UWord w = (irusr ? VKI_R_OK : 0)
510 | (iwusr ? VKI_W_OK : 0)
511 | (ixusr ? VKI_X_OK : 0);
512 SysRes res = VG_(do_syscall2)(__NR_access, (UWord)path, w);
njncda2f0f2009-05-18 02:12:08 +0000513 return sr_isError(res) ? 1 : 0;
514
515# if defined(VGO_linux)
516# undef VKI_R_OK
517# undef VKI_W_OK
518# undef VKI_X_OK
sewardj9a66bb92006-10-17 01:38:13 +0000519# endif
sewardj45f4e7c2005-09-27 19:20:21 +0000520}
521
njn73750612005-10-14 03:11:30 +0000522/*
523 Emulate the normal Unix permissions checking algorithm.
524
525 If owner matches, then use the owner permissions, else
526 if group matches, then use the group permissions, else
527 use other permissions.
528
sewardjc74b3ba2007-11-17 21:11:57 +0000529 Note that we can't deal properly with SUID/SGID. By default
530 (allow_setuid == False), we refuse to run them (otherwise the
531 executable may misbehave if it doesn't have the permissions it
532 thinks it does). However, the caller may indicate that setuid
533 executables are allowed, for example if we are going to exec them
534 but not trace into them (iow, client sys_execve when
535 clo_trace_children == False).
536
537 If VKI_EACCES is returned (iow, permission was refused), then
538 *is_setuid is set to True iff permission was refused because the
539 executable is setuid.
njn73750612005-10-14 03:11:30 +0000540*/
541/* returns: 0 = success, non-0 is failure */
sewardjc74b3ba2007-11-17 21:11:57 +0000542Int VG_(check_executable)(/*OUT*/Bool* is_setuid,
njn63e5e6e2009-05-20 04:22:42 +0000543 const HChar* f, Bool allow_setuid)
njn73750612005-10-14 03:11:30 +0000544{
sewardj4231a852008-08-19 08:32:03 +0000545 struct vg_stat st;
sewardj26b87282006-10-17 12:49:31 +0000546 SysRes res = VG_(stat)(f, &st);
njn73750612005-10-14 03:11:30 +0000547
sewardjc74b3ba2007-11-17 21:11:57 +0000548 if (is_setuid)
549 *is_setuid = False;
550
njncda2f0f2009-05-18 02:12:08 +0000551 if (sr_isError(res)) {
552 return sr_Err(res);
njn73750612005-10-14 03:11:30 +0000553 }
554
njn9c20ece2009-05-20 02:02:30 +0000555 if ( (st.mode & (VKI_S_ISUID | VKI_S_ISGID)) && !allow_setuid ) {
sewardjc74b3ba2007-11-17 21:11:57 +0000556 if (is_setuid)
557 *is_setuid = True;
njn73750612005-10-14 03:11:30 +0000558 return VKI_EACCES;
559 }
560
njn9c20ece2009-05-20 02:02:30 +0000561 if (VG_(geteuid)() == st.uid) {
562 if (!(st.mode & VKI_S_IXUSR))
njn73750612005-10-14 03:11:30 +0000563 return VKI_EACCES;
564 } else {
sewardj45406ef2006-10-18 00:33:46 +0000565 Int grpmatch = 0;
njn73750612005-10-14 03:11:30 +0000566
njn9c20ece2009-05-20 02:02:30 +0000567 if (VG_(getegid)() == st.gid)
njn73750612005-10-14 03:11:30 +0000568 grpmatch = 1;
569 else {
570 UInt groups[32];
571 Int ngrp = VG_(getgroups)(32, groups);
572 Int i;
573 /* ngrp will be -1 if VG_(getgroups) failed. */
574 for (i = 0; i < ngrp; i++) {
njn9c20ece2009-05-20 02:02:30 +0000575 if (groups[i] == st.gid) {
njn73750612005-10-14 03:11:30 +0000576 grpmatch = 1;
577 break;
578 }
579 }
580 }
581
582 if (grpmatch) {
njn9c20ece2009-05-20 02:02:30 +0000583 if (!(st.mode & VKI_S_IXGRP)) {
njn73750612005-10-14 03:11:30 +0000584 return VKI_EACCES;
585 }
njn9c20ece2009-05-20 02:02:30 +0000586 } else if (!(st.mode & VKI_S_IXOTH)) {
njn73750612005-10-14 03:11:30 +0000587 return VKI_EACCES;
588 }
589 }
590
591 return 0;
592}
593
njnc4431bf2009-01-15 21:29:24 +0000594SysRes VG_(pread) ( Int fd, void* buf, Int count, OffT offset )
sewardj45f4e7c2005-09-27 19:20:21 +0000595{
njncda2f0f2009-05-18 02:12:08 +0000596 SysRes res;
philippe8050bb72012-04-13 23:07:29 +0000597 // on 32 bits platforms, we receive a 32 bits OffT but
598 // we must extend it to pass a long long 64 bits.
599# if defined(VGP_x86_linux)
600 vg_assert(sizeof(OffT) == 4);
601 res = VG_(do_syscall5)(__NR_pread64, fd, (UWord)buf, count,
602 offset, 0); // Little endian long long
603 return res;
604# elif defined(VGP_arm_linux)
605 vg_assert(sizeof(OffT) == 4);
606 res = VG_(do_syscall5)(__NR_pread64, fd, (UWord)buf, count,
607 0, offset); // Big endian long long
608 return res;
609# elif defined(VGP_ppc32_linux)
610 vg_assert(sizeof(OffT) == 4);
611 res = VG_(do_syscall6)(__NR_pread64, fd, (UWord)buf, count,
612 0, // Padding needed on PPC32
613 0, offset); // Big endian long long
614 return res;
sewardj5db15402012-06-07 09:13:21 +0000615# elif defined(VGP_mips32_linux) && VKI_LITTLE_ENDIAN
616 vg_assert(sizeof(OffT) == 4);
617 res = VG_(do_syscall6)(__NR_pread64, fd, (UWord)buf, count,
618 0, offset, 0);
619 return res;
620# elif defined(VGP_mips32_linux) && VKI_BIG_ENDIAN
621 vg_assert(sizeof(OffT) == 4);
622 res = VG_(do_syscall6)(__NR_pread64, fd, (UWord)buf, count,
623 0, 0, offset);
624 return res;
philippe8050bb72012-04-13 23:07:29 +0000625# elif defined(VGP_amd64_linux) \
626 || defined(VGP_ppc64_linux) || defined(VGP_s390x_linux)
627 res = VG_(do_syscall4)(__NR_pread64, fd, (UWord)buf, count, offset);
njncda2f0f2009-05-18 02:12:08 +0000628 return res;
njnf76d27a2009-05-28 01:53:07 +0000629# elif defined(VGP_amd64_darwin)
sewardj972316d2012-04-21 15:33:26 +0000630 vg_assert(sizeof(OffT) == 8);
njnf76d27a2009-05-28 01:53:07 +0000631 res = VG_(do_syscall4)(__NR_pread_nocancel, fd, (UWord)buf, count, offset);
632 return res;
633# elif defined(VGP_x86_darwin)
sewardj972316d2012-04-21 15:33:26 +0000634 vg_assert(sizeof(OffT) == 8);
njnf76d27a2009-05-28 01:53:07 +0000635 res = VG_(do_syscall5)(__NR_pread_nocancel, fd, (UWord)buf, count,
sewardj972316d2012-04-21 15:33:26 +0000636 offset & 0xffffffff, offset >> 32);
njnf76d27a2009-05-28 01:53:07 +0000637 return res;
njncda2f0f2009-05-18 02:12:08 +0000638# else
639# error "Unknown platform"
640# endif
sewardj45f4e7c2005-09-27 19:20:21 +0000641}
642
florianb985e2d2011-09-29 03:03:45 +0000643/* Return the name of a directory for temporary files. */
644const HChar *VG_(tmpdir)(void)
645{
646 const HChar *tmpdir;
647
648 tmpdir = VG_(getenv)("TMPDIR");
649 if (tmpdir == NULL || *tmpdir == '\0') tmpdir = VG_TMPDIR;
650 if (tmpdir == NULL || *tmpdir == '\0') tmpdir = "/tmp"; /* fallback */
651
652 return tmpdir;
653}
654
sewardj45f4e7c2005-09-27 19:20:21 +0000655/* Create and open (-rw------) a tmp file name incorporating said arg.
656 Returns -1 on failure, else the fd of the file. If fullname is
657 non-NULL, the file's name is written into it. The number of bytes
658 written is guaranteed not to exceed 64+strlen(part_of_name). */
659
660Int VG_(mkstemp) ( HChar* part_of_name, /*OUT*/HChar* fullname )
661{
662 HChar buf[200];
663 Int n, tries, fd;
664 UInt seed;
665 SysRes sres;
florian1763e812011-07-12 19:07:05 +0000666 const HChar *tmpdir;
sewardj45f4e7c2005-09-27 19:20:21 +0000667
668 vg_assert(part_of_name);
669 n = VG_(strlen)(part_of_name);
670 vg_assert(n > 0 && n < 100);
671
672 seed = (VG_(getpid)() << 9) ^ VG_(getppid)();
673
florian1763e812011-07-12 19:07:05 +0000674 /* Determine sensible location for temporary files */
florianb985e2d2011-09-29 03:03:45 +0000675 tmpdir = VG_(tmpdir)();
florian1763e812011-07-12 19:07:05 +0000676
sewardj45f4e7c2005-09-27 19:20:21 +0000677 tries = 0;
678 while (True) {
sewardj824b3972011-05-09 22:42:06 +0000679 if (tries++ > 10)
sewardj45f4e7c2005-09-27 19:20:21 +0000680 return -1;
florian1763e812011-07-12 19:07:05 +0000681 VG_(sprintf)( buf, "%s/valgrind_%s_%08x",
682 tmpdir, part_of_name, VG_(random)( &seed ));
sewardj45f4e7c2005-09-27 19:20:21 +0000683 if (0)
684 VG_(printf)("VG_(mkstemp): trying: %s\n", buf);
685
686 sres = VG_(open)(buf,
687 VKI_O_CREAT|VKI_O_RDWR|VKI_O_EXCL|VKI_O_TRUNC,
688 VKI_S_IRUSR|VKI_S_IWUSR);
sewardj80fc03b2011-09-26 16:46:04 +0000689 if (sr_isError(sres)) {
690 VG_(umsg)("VG_(mkstemp): failed to create temp file: %s\n", buf);
sewardj45f4e7c2005-09-27 19:20:21 +0000691 continue;
sewardj80fc03b2011-09-26 16:46:04 +0000692 }
sewardj45f4e7c2005-09-27 19:20:21 +0000693 /* VG_(safe_fd) doesn't return if it fails. */
njncda2f0f2009-05-18 02:12:08 +0000694 fd = VG_(safe_fd)( sr_Res(sres) );
sewardj45f4e7c2005-09-27 19:20:21 +0000695 if (fullname)
696 VG_(strcpy)( fullname, buf );
697 return fd;
698 }
699 /* NOTREACHED */
700}
701
702
njneb8896b2005-06-04 20:03:55 +0000703/* ---------------------------------------------------------------------
njn4bd96bd2009-05-22 00:52:14 +0000704 Socket-related stuff.
njneb8896b2005-06-04 20:03:55 +0000705 ------------------------------------------------------------------ */
706
707static
florian19f91bb2012-11-10 22:29:54 +0000708Int parse_inet_addr_and_port ( const HChar* str, UInt* ip_addr, UShort* port );
njneb8896b2005-06-04 20:03:55 +0000709
710static
njn4bd96bd2009-05-22 00:52:14 +0000711Int my_connect ( Int sockfd, struct vki_sockaddr_in* serv_addr, Int addrlen );
njneb8896b2005-06-04 20:03:55 +0000712
toma4a4f412005-11-17 12:01:56 +0000713UInt VG_(htonl) ( UInt x )
njneb8896b2005-06-04 20:03:55 +0000714{
sewardja1c4bfb2005-10-18 02:15:39 +0000715# if defined(VG_BIGENDIAN)
716 return x;
717# else
njneb8896b2005-06-04 20:03:55 +0000718 return
719 (((x >> 24) & 0xFF) << 0) | (((x >> 16) & 0xFF) << 8)
720 | (((x >> 8) & 0xFF) << 16) | (((x >> 0) & 0xFF) << 24);
sewardja1c4bfb2005-10-18 02:15:39 +0000721# endif
njneb8896b2005-06-04 20:03:55 +0000722}
723
toma4a4f412005-11-17 12:01:56 +0000724UInt VG_(ntohl) ( UInt x )
725{
726# if defined(VG_BIGENDIAN)
727 return x;
728# else
729 return
730 (((x >> 24) & 0xFF) << 0) | (((x >> 16) & 0xFF) << 8)
731 | (((x >> 8) & 0xFF) << 16) | (((x >> 0) & 0xFF) << 24);
732# endif
733}
734
735UShort VG_(htons) ( UShort x )
736{
737# if defined(VG_BIGENDIAN)
738 return x;
739# else
740 return
741 (((x >> 8) & 0xFF) << 0) | (((x >> 0) & 0xFF) << 8);
742# endif
743}
744
745UShort VG_(ntohs) ( UShort x )
njneb8896b2005-06-04 20:03:55 +0000746{
sewardja1c4bfb2005-10-18 02:15:39 +0000747# if defined(VG_BIGENDIAN)
748 return x;
749# else
njneb8896b2005-06-04 20:03:55 +0000750 return
751 (((x >> 8) & 0xFF) << 0) | (((x >> 0) & 0xFF) << 8);
sewardja1c4bfb2005-10-18 02:15:39 +0000752# endif
njneb8896b2005-06-04 20:03:55 +0000753}
754
755
756/* The main function.
757
758 Supplied string contains either an ip address "192.168.0.1" or
759 an ip address and port pair, "192.168.0.1:1500". Parse these,
760 and return:
761 -1 if there is a parse error
762 -2 if no parse error, but specified host:port cannot be opened
763 the relevant file (socket) descriptor, otherwise.
764 is used.
765*/
florian19f91bb2012-11-10 22:29:54 +0000766Int VG_(connect_via_socket)( const HChar* str )
njneb8896b2005-06-04 20:03:55 +0000767{
njnf76d27a2009-05-28 01:53:07 +0000768# if defined(VGO_linux) || defined(VGO_darwin)
njneb8896b2005-06-04 20:03:55 +0000769 Int sd, res;
770 struct vki_sockaddr_in servAddr;
771 UInt ip = 0;
772 UShort port = VG_CLO_DEFAULT_LOGPORT;
773 Bool ok = parse_inet_addr_and_port(str, &ip, &port);
774 if (!ok)
775 return -1;
776
777 //if (0)
778 // VG_(printf)("ip = %d.%d.%d.%d, port %d\n",
779 // (ip >> 24) & 0xFF, (ip >> 16) & 0xFF,
780 // (ip >> 8) & 0xFF, ip & 0xFF,
781 // (UInt)port );
782
783 servAddr.sin_family = VKI_AF_INET;
toma4a4f412005-11-17 12:01:56 +0000784 servAddr.sin_addr.s_addr = VG_(htonl)(ip);
785 servAddr.sin_port = VG_(htons)(port);
njneb8896b2005-06-04 20:03:55 +0000786
787 /* create socket */
njn0cd5d972009-05-22 02:00:27 +0000788 sd = VG_(socket)(VKI_AF_INET, VKI_SOCK_STREAM, 0 /* IPPROTO_IP ? */);
njneb8896b2005-06-04 20:03:55 +0000789 if (sd < 0) {
sewardja1c4bfb2005-10-18 02:15:39 +0000790 /* this shouldn't happen ... nevertheless */
791 return -2;
njneb8896b2005-06-04 20:03:55 +0000792 }
sewardja1c4bfb2005-10-18 02:15:39 +0000793
njneb8896b2005-06-04 20:03:55 +0000794 /* connect to server */
njnb143b272009-05-22 00:47:08 +0000795 res = my_connect(sd, &servAddr, sizeof(servAddr));
njneb8896b2005-06-04 20:03:55 +0000796 if (res < 0) {
sewardja1c4bfb2005-10-18 02:15:39 +0000797 /* connection failed */
798 return -2;
njneb8896b2005-06-04 20:03:55 +0000799 }
800
801 return sd;
njncda2f0f2009-05-18 02:12:08 +0000802
njncda2f0f2009-05-18 02:12:08 +0000803# else
804# error "Unknown OS"
805# endif
njneb8896b2005-06-04 20:03:55 +0000806}
807
808
809/* Let d = one or more digits. Accept either:
810 d.d.d.d or d.d.d.d:d
811*/
florian19f91bb2012-11-10 22:29:54 +0000812static Int parse_inet_addr_and_port ( const HChar* str, UInt* ip_addr, UShort* port )
njneb8896b2005-06-04 20:03:55 +0000813{
814# define GET_CH ((*str) ? (*str++) : 0)
815 UInt ipa, i, j, c, any;
816 ipa = 0;
817 for (i = 0; i < 4; i++) {
818 j = 0;
819 any = 0;
820 while (1) {
821 c = GET_CH;
822 if (c < '0' || c > '9') break;
823 j = 10 * j + (int)(c - '0');
824 any = 1;
825 }
826 if (any == 0 || j > 255) goto syntaxerr;
827 ipa = (ipa << 8) + j;
828 if (i <= 2 && c != '.') goto syntaxerr;
829 }
830 if (c == 0 || c == ':')
831 *ip_addr = ipa;
832 if (c == 0) goto ok;
833 if (c != ':') goto syntaxerr;
834 j = 0;
835 any = 0;
836 while (1) {
837 c = GET_CH;
838 if (c < '0' || c > '9') break;
839 j = j * 10 + (int)(c - '0');
840 any = 1;
841 if (j > 65535) goto syntaxerr;
842 }
843 if (any == 0 || c != 0) goto syntaxerr;
844 if (j < 1024) goto syntaxerr;
845 *port = (UShort)j;
846 ok:
847 return 1;
848 syntaxerr:
849 return 0;
850# undef GET_CH
851}
852
njn0cd5d972009-05-22 02:00:27 +0000853// GrP fixme safe_fd?
854Int VG_(socket) ( Int domain, Int type, Int protocol )
njneb8896b2005-06-04 20:03:55 +0000855{
njncda2f0f2009-05-18 02:12:08 +0000856# if defined(VGP_x86_linux) || defined(VGP_ppc32_linux) \
sewardjb5b87402011-03-07 16:05:35 +0000857 || defined(VGP_ppc64_linux) || defined(VGP_s390x_linux)
sewardja8d8e232005-06-07 20:04:56 +0000858 SysRes res;
859 UWord args[3];
njneb8896b2005-06-04 20:03:55 +0000860 args[0] = domain;
861 args[1] = type;
862 args[2] = protocol;
863 res = VG_(do_syscall2)(__NR_socketcall, VKI_SYS_SOCKET, (UWord)&args);
njncda2f0f2009-05-18 02:12:08 +0000864 return sr_isError(res) ? -1 : sr_Res(res);
cerion85665ca2005-06-20 15:51:07 +0000865
sewardj5db15402012-06-07 09:13:21 +0000866# elif defined(VGP_amd64_linux) || defined(VGP_arm_linux) \
867 || defined(VGP_mips32_linux)
sewardj1e866562005-09-28 19:58:58 +0000868 SysRes res;
869 res = VG_(do_syscall3)(__NR_socket, domain, type, protocol );
njncda2f0f2009-05-18 02:12:08 +0000870 return sr_isError(res) ? -1 : sr_Res(res);
sewardj9a66bb92006-10-17 01:38:13 +0000871
njnf76d27a2009-05-28 01:53:07 +0000872# elif defined(VGO_darwin)
873 SysRes res;
874 res = VG_(do_syscall3)(__NR_socket, domain, type, protocol);
875 if (!sr_isError(res)) {
876 // Set SO_NOSIGPIPE so write() returns EPIPE instead of raising SIGPIPE
877 Int optval = 1;
878 SysRes res2;
879 res2 = VG_(do_syscall5)(__NR_setsockopt, sr_Res(res), VKI_SOL_SOCKET,
880 VKI_SO_NOSIGPIPE, (UWord)&optval,
881 sizeof(optval));
882 // ignore setsockopt() error
883 }
884 return sr_isError(res) ? -1 : sr_Res(res);
885
njncda2f0f2009-05-18 02:12:08 +0000886# else
887# error "Unknown arch"
888# endif
njneb8896b2005-06-04 20:03:55 +0000889}
890
njncda2f0f2009-05-18 02:12:08 +0000891
njneb8896b2005-06-04 20:03:55 +0000892static
njn4bd96bd2009-05-22 00:52:14 +0000893Int my_connect ( Int sockfd, struct vki_sockaddr_in* serv_addr, Int addrlen )
njneb8896b2005-06-04 20:03:55 +0000894{
njncda2f0f2009-05-18 02:12:08 +0000895# if defined(VGP_x86_linux) || defined(VGP_ppc32_linux) \
sewardjb5b87402011-03-07 16:05:35 +0000896 || defined(VGP_ppc64_linux) || defined(VGP_s390x_linux)
sewardja8d8e232005-06-07 20:04:56 +0000897 SysRes res;
898 UWord args[3];
njneb8896b2005-06-04 20:03:55 +0000899 args[0] = sockfd;
900 args[1] = (UWord)serv_addr;
901 args[2] = addrlen;
902 res = VG_(do_syscall2)(__NR_socketcall, VKI_SYS_CONNECT, (UWord)&args);
njncda2f0f2009-05-18 02:12:08 +0000903 return sr_isError(res) ? -1 : sr_Res(res);
cerion85665ca2005-06-20 15:51:07 +0000904
sewardj5db15402012-06-07 09:13:21 +0000905# elif defined(VGP_amd64_linux) || defined(VGP_arm_linux) \
906 || defined(VGP_mips32_linux)
sewardj1e866562005-09-28 19:58:58 +0000907 SysRes res;
908 res = VG_(do_syscall3)(__NR_connect, sockfd, (UWord)serv_addr, addrlen);
njncda2f0f2009-05-18 02:12:08 +0000909 return sr_isError(res) ? -1 : sr_Res(res);
sewardj9a66bb92006-10-17 01:38:13 +0000910
njnf76d27a2009-05-28 01:53:07 +0000911# elif defined(VGO_darwin)
912 SysRes res;
913 res = VG_(do_syscall3)(__NR_connect_nocancel,
914 sockfd, (UWord)serv_addr, addrlen);
915 return sr_isError(res) ? -1 : sr_Res(res);
916
njncda2f0f2009-05-18 02:12:08 +0000917# else
918# error "Unknown arch"
919# endif
njneb8896b2005-06-04 20:03:55 +0000920}
921
floriandbb35842012-10-27 18:39:11 +0000922Int VG_(write_socket)( Int sd, const void *msg, Int count )
njneb8896b2005-06-04 20:03:55 +0000923{
njneb8896b2005-06-04 20:03:55 +0000924 /* This is actually send(). */
njnf76d27a2009-05-28 01:53:07 +0000925
926 /* For Linux, VKI_MSG_NOSIGNAL is a request not to send SIGPIPE on
sewardj9a66bb92006-10-17 01:38:13 +0000927 errors on stream oriented sockets when the other end breaks the
njnf76d27a2009-05-28 01:53:07 +0000928 connection. The EPIPE error is still returned.
929
930 For Darwin, VG_(socket)() sets SO_NOSIGPIPE to get EPIPE instead of
931 SIGPIPE */
njneb8896b2005-06-04 20:03:55 +0000932
njncda2f0f2009-05-18 02:12:08 +0000933# if defined(VGP_x86_linux) || defined(VGP_ppc32_linux) \
sewardjb5b87402011-03-07 16:05:35 +0000934 || defined(VGP_ppc64_linux) || defined(VGP_s390x_linux)
sewardja8d8e232005-06-07 20:04:56 +0000935 SysRes res;
936 UWord args[4];
njneb8896b2005-06-04 20:03:55 +0000937 args[0] = sd;
938 args[1] = (UWord)msg;
939 args[2] = count;
sewardj9a66bb92006-10-17 01:38:13 +0000940 args[3] = VKI_MSG_NOSIGNAL;
njneb8896b2005-06-04 20:03:55 +0000941 res = VG_(do_syscall2)(__NR_socketcall, VKI_SYS_SEND, (UWord)&args);
njncda2f0f2009-05-18 02:12:08 +0000942 return sr_isError(res) ? -1 : sr_Res(res);
cerion85665ca2005-06-20 15:51:07 +0000943
sewardj5db15402012-06-07 09:13:21 +0000944# elif defined(VGP_amd64_linux) || defined(VGP_arm_linux) \
945 || defined(VGP_mips32_linux)
sewardj1e866562005-09-28 19:58:58 +0000946 SysRes res;
sewardj9a66bb92006-10-17 01:38:13 +0000947 res = VG_(do_syscall6)(__NR_sendto, sd, (UWord)msg,
948 count, VKI_MSG_NOSIGNAL, 0,0);
njncda2f0f2009-05-18 02:12:08 +0000949 return sr_isError(res) ? -1 : sr_Res(res);
sewardj9a66bb92006-10-17 01:38:13 +0000950
njnf76d27a2009-05-28 01:53:07 +0000951# elif defined(VGP_x86_darwin) || defined(VGP_amd64_darwin)
952 SysRes res;
953 res = VG_(do_syscall3)(__NR_write_nocancel, sd, (UWord)msg, count);
954 return sr_isError(res) ? -1 : sr_Res(res);
955
njncda2f0f2009-05-18 02:12:08 +0000956# else
957# error "Unknown platform"
958# endif
njneb8896b2005-06-04 20:03:55 +0000959}
960
961Int VG_(getsockname) ( Int sd, struct vki_sockaddr *name, Int *namelen)
962{
njncda2f0f2009-05-18 02:12:08 +0000963# if defined(VGP_x86_linux) || defined(VGP_ppc32_linux) \
sewardj5db15402012-06-07 09:13:21 +0000964 || defined(VGP_ppc64_linux) || defined(VGP_s390x_linux) \
965 || defined(VGP_mips32_linux)
sewardj9a66bb92006-10-17 01:38:13 +0000966 SysRes res;
sewardja8d8e232005-06-07 20:04:56 +0000967 UWord args[3];
njneb8896b2005-06-04 20:03:55 +0000968 args[0] = sd;
969 args[1] = (UWord)name;
970 args[2] = (UWord)namelen;
971 res = VG_(do_syscall2)(__NR_socketcall, VKI_SYS_GETSOCKNAME, (UWord)&args);
njncda2f0f2009-05-18 02:12:08 +0000972 return sr_isError(res) ? -1 : sr_Res(res);
sewardja5c9e4a2005-06-09 13:21:58 +0000973
sewardj59570ff2010-01-01 11:59:33 +0000974# elif defined(VGP_amd64_linux) || defined(VGP_arm_linux)
sewardj9a66bb92006-10-17 01:38:13 +0000975 SysRes res;
sewardja5c9e4a2005-06-09 13:21:58 +0000976 res = VG_(do_syscall3)( __NR_getsockname,
977 (UWord)sd, (UWord)name, (UWord)namelen );
njncda2f0f2009-05-18 02:12:08 +0000978 return sr_isError(res) ? -1 : sr_Res(res);
sewardj9a66bb92006-10-17 01:38:13 +0000979
njnf76d27a2009-05-28 01:53:07 +0000980# elif defined(VGO_darwin)
981 SysRes res;
982 res = VG_(do_syscall3)( __NR_getsockname,
983 (UWord)sd, (UWord)name, (UWord)namelen );
984 return sr_isError(res) ? -1 : sr_Res(res);
985
njncda2f0f2009-05-18 02:12:08 +0000986# else
987# error "Unknown platform"
988# endif
njneb8896b2005-06-04 20:03:55 +0000989}
990
991Int VG_(getpeername) ( Int sd, struct vki_sockaddr *name, Int *namelen)
992{
njncda2f0f2009-05-18 02:12:08 +0000993# if defined(VGP_x86_linux) || defined(VGP_ppc32_linux) \
sewardj5db15402012-06-07 09:13:21 +0000994 || defined(VGP_ppc64_linux) || defined(VGP_s390x_linux) \
995 || defined(VGP_mips32_linux)
sewardj9a66bb92006-10-17 01:38:13 +0000996 SysRes res;
sewardja8d8e232005-06-07 20:04:56 +0000997 UWord args[3];
njneb8896b2005-06-04 20:03:55 +0000998 args[0] = sd;
999 args[1] = (UWord)name;
1000 args[2] = (UWord)namelen;
1001 res = VG_(do_syscall2)(__NR_socketcall, VKI_SYS_GETPEERNAME, (UWord)&args);
njncda2f0f2009-05-18 02:12:08 +00001002 return sr_isError(res) ? -1 : sr_Res(res);
sewardja5c9e4a2005-06-09 13:21:58 +00001003
sewardj59570ff2010-01-01 11:59:33 +00001004# elif defined(VGP_amd64_linux) || defined(VGP_arm_linux)
sewardj9a66bb92006-10-17 01:38:13 +00001005 SysRes res;
sewardja5c9e4a2005-06-09 13:21:58 +00001006 res = VG_(do_syscall3)( __NR_getpeername,
1007 (UWord)sd, (UWord)name, (UWord)namelen );
njncda2f0f2009-05-18 02:12:08 +00001008 return sr_isError(res) ? -1 : sr_Res(res);
sewardj9a66bb92006-10-17 01:38:13 +00001009
njnf76d27a2009-05-28 01:53:07 +00001010# elif defined(VGO_darwin)
1011 SysRes res;
1012 res = VG_(do_syscall3)( __NR_getpeername,
1013 (UWord)sd, (UWord)name, (UWord)namelen );
1014 return sr_isError(res) ? -1 : sr_Res(res);
1015
njncda2f0f2009-05-18 02:12:08 +00001016# else
1017# error "Unknown platform"
1018# endif
njneb8896b2005-06-04 20:03:55 +00001019}
1020
1021Int VG_(getsockopt) ( Int sd, Int level, Int optname, void *optval,
1022 Int *optlen)
1023{
njncda2f0f2009-05-18 02:12:08 +00001024# if defined(VGP_x86_linux) || defined(VGP_ppc32_linux) \
sewardjb5b87402011-03-07 16:05:35 +00001025 || defined(VGP_ppc64_linux) || defined(VGP_s390x_linux)
sewardj9a66bb92006-10-17 01:38:13 +00001026 SysRes res;
sewardja8d8e232005-06-07 20:04:56 +00001027 UWord args[5];
njneb8896b2005-06-04 20:03:55 +00001028 args[0] = sd;
1029 args[1] = level;
1030 args[2] = optname;
1031 args[3] = (UWord)optval;
1032 args[4] = (UWord)optlen;
1033 res = VG_(do_syscall2)(__NR_socketcall, VKI_SYS_GETSOCKOPT, (UWord)&args);
njncda2f0f2009-05-18 02:12:08 +00001034 return sr_isError(res) ? -1 : sr_Res(res);
sewardja5c9e4a2005-06-09 13:21:58 +00001035
sewardj5db15402012-06-07 09:13:21 +00001036# elif defined(VGP_amd64_linux) || defined(VGP_arm_linux) \
1037 || defined(VGP_mips32_linux)
sewardj9a66bb92006-10-17 01:38:13 +00001038 SysRes res;
sewardja5c9e4a2005-06-09 13:21:58 +00001039 res = VG_(do_syscall5)( __NR_getsockopt,
1040 (UWord)sd, (UWord)level, (UWord)optname,
1041 (UWord)optval, (UWord)optlen );
njncda2f0f2009-05-18 02:12:08 +00001042 return sr_isError(res) ? -1 : sr_Res(res);
sewardj9a66bb92006-10-17 01:38:13 +00001043
njnf76d27a2009-05-28 01:53:07 +00001044# elif defined(VGO_darwin)
1045 SysRes res;
1046 res = VG_(do_syscall5)( __NR_getsockopt,
1047 (UWord)sd, (UWord)level, (UWord)optname,
1048 (UWord)optval, (UWord)optlen );
1049 return sr_isError(res) ? -1 : sr_Res(res);
1050
njncda2f0f2009-05-18 02:12:08 +00001051# else
1052# error "Unknown platform"
1053# endif
njneb8896b2005-06-04 20:03:55 +00001054}
1055
1056
florian6bd9dc12012-11-23 16:17:43 +00001057const HChar *VG_(basename)(const HChar *path)
njnf76d27a2009-05-28 01:53:07 +00001058{
florian19f91bb2012-11-10 22:29:54 +00001059 static HChar buf[VKI_PATH_MAX];
njnf76d27a2009-05-28 01:53:07 +00001060
florian19f91bb2012-11-10 22:29:54 +00001061 const HChar *p, *end;
njnf76d27a2009-05-28 01:53:07 +00001062
1063 if (path == NULL ||
1064 0 == VG_(strcmp)(path, ""))
1065 {
1066 return ".";
1067 }
1068
1069 p = path + VG_(strlen)(path);
1070 while (p > path && *p == '/') {
1071 // skip all trailing '/'
1072 p--;
1073 }
1074
1075 if (p == path && *p == '/') return "/"; // all slashes
1076
1077 end = p;
1078
1079 while (p > path && *p != '/') {
1080 // now skip non '/'
1081 p--;
1082 }
1083
1084 if (*p == '/') p++;
1085
1086 VG_(strncpy)(buf, p, end-p+1);
1087 buf[end-p+1] = '\0';
1088
1089 return buf;
1090}
1091
1092
florian6bd9dc12012-11-23 16:17:43 +00001093const HChar *VG_(dirname)(const HChar *path)
njnf76d27a2009-05-28 01:53:07 +00001094{
florian19f91bb2012-11-10 22:29:54 +00001095 static HChar buf[VKI_PATH_MAX];
njnf76d27a2009-05-28 01:53:07 +00001096
florian19f91bb2012-11-10 22:29:54 +00001097 const HChar *p;
njnf76d27a2009-05-28 01:53:07 +00001098
1099 if (path == NULL ||
1100 0 == VG_(strcmp)(path, "") ||
1101 0 == VG_(strcmp)(path, "/"))
1102 {
1103 return ".";
1104 }
1105
1106 p = path + VG_(strlen)(path);
1107 while (p > path && *p == '/') {
1108 // skip all trailing '/'
1109 p--;
1110 }
1111
1112 while (p > path && *p != '/') {
1113 // now skip non '/'
1114 p--;
1115 }
1116
1117 if (p == path) {
1118 if (*p == '/') return "/"; // all slashes
1119 else return "."; // no slashes
1120 }
1121
1122 while (p > path && *p == '/') {
1123 // skip '/' again
1124 p--;
1125 }
1126
1127 VG_(strncpy)(buf, path, p-path+1);
1128 buf[p-path+1] = '\0';
1129
1130 return buf;
1131}
1132
1133
njneb8896b2005-06-04 20:03:55 +00001134/*--------------------------------------------------------------------*/
1135/*--- end ---*/
1136/*--------------------------------------------------------------------*/