blob: ceb6bdc1efa72a7a63de69f57ad00cb91e09f0a9 [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
sewardj0f157dd2013-10-18 14:27:36 +000011 Copyright (C) 2000-2013 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,
njnf845f8f2005-06-23 02:26:47 +000074 or if it doesn't exist, we return False. */
75Bool VG_(resolve_filename) ( Int fd, HChar* buf, Int n_buf )
njnae7359b2005-06-19 21:10:42 +000076{
njn81b975c2009-04-28 05:35:53 +000077# if defined(VGO_linux)
njnae7359b2005-06-19 21:10:42 +000078 HChar tmp[64];
njnae7359b2005-06-19 21:10:42 +000079 VG_(sprintf)(tmp, "/proc/self/fd/%d", fd);
njnf845f8f2005-06-23 02:26:47 +000080 VG_(memset)(buf, 0, n_buf);
sewardj45f4e7c2005-09-27 19:20:21 +000081 if (VG_(readlink)(tmp, buf, n_buf) > 0 && buf[0] == '/')
njnf845f8f2005-06-23 02:26:47 +000082 return True;
83 else
84 return False;
njndad944a2009-05-04 05:55:46 +000085
njnf76d27a2009-05-28 01:53:07 +000086# elif defined(VGO_darwin)
87 HChar tmp[VKI_MAXPATHLEN+1];
88 if (0 == VG_(fcntl)(fd, VKI_F_GETPATH, (UWord)tmp)) {
89 if (n_buf > 0) {
90 VG_(strncpy)( buf, tmp, n_buf < sizeof(tmp) ? n_buf : sizeof(tmp) );
91 buf[n_buf-1] = 0;
92 }
93 if (tmp[0] == '/') return True;
94 }
95 return False;
96
njn81b975c2009-04-28 05:35:53 +000097# else
njndad944a2009-05-04 05:55:46 +000098# error Unknown OS
njn81b975c2009-04-28 05:35:53 +000099# endif
njnae7359b2005-06-19 21:10:42 +0000100}
101
florian19f91bb2012-11-10 22:29:54 +0000102SysRes VG_(mknod) ( const HChar* pathname, Int mode, UWord dev )
sewardj3b290482011-05-06 21:02:55 +0000103{
philippe0eb0d5a2014-02-11 23:50:16 +0000104# if defined(VGP_arm64_linux)
105 /* ARM64 wants to use __NR_mknodat rather than __NR_mknod. */
106 SysRes res = VG_(do_syscall4)(__NR_mknodat,
107 VKI_AT_FDCWD, (UWord)pathname, mode, dev);
108# elif defined(VGO_linux) || defined(VGO_darwin)
sewardj3b290482011-05-06 21:02:55 +0000109 SysRes res = VG_(do_syscall3)(__NR_mknod,
110 (UWord)pathname, mode, dev);
111# else
112# error Unknown OS
113# endif
114 return res;
115}
116
florian19f91bb2012-11-10 22:29:54 +0000117SysRes VG_(open) ( const HChar* pathname, Int flags, Int mode )
sewardjf0c12502014-01-12 12:54:00 +0000118{
119# if defined(VGP_arm64_linux)
120 /* ARM64 wants to use __NR_openat rather than __NR_open. */
121 SysRes res = VG_(do_syscall4)(__NR_openat,
122 VKI_AT_FDCWD, (UWord)pathname, flags, mode);
123# elif defined(VGO_linux)
njnf76d27a2009-05-28 01:53:07 +0000124 SysRes res = VG_(do_syscall3)(__NR_open,
125 (UWord)pathname, flags, mode);
126# elif defined(VGO_darwin)
127 SysRes res = VG_(do_syscall3)(__NR_open_nocancel,
128 (UWord)pathname, flags, mode);
129# else
130# error Unknown OS
131# endif
sewardj92645592005-07-23 09:18:34 +0000132 return res;
njneb8896b2005-06-04 20:03:55 +0000133}
134
florian19f91bb2012-11-10 22:29:54 +0000135Int VG_(fd_open) (const HChar* pathname, Int flags, Int mode)
sewardj3b290482011-05-06 21:02:55 +0000136{
137 SysRes sr;
138 sr = VG_(open) (pathname, flags, mode);
139 if (sr_isError (sr))
140 return -1;
141 else
142 return sr_Res (sr);
143}
144
njneb8896b2005-06-04 20:03:55 +0000145void VG_(close) ( Int fd )
146{
njnf76d27a2009-05-28 01:53:07 +0000147 /* Hmm. Return value is not checked. That's uncool. */
sewardj6e9de462011-06-28 07:25:29 +0000148# if defined(VGO_linux)
sewardja8d8e232005-06-07 20:04:56 +0000149 (void)VG_(do_syscall1)(__NR_close, fd);
njnf76d27a2009-05-28 01:53:07 +0000150# elif defined(VGO_darwin)
151 (void)VG_(do_syscall1)(__NR_close_nocancel, fd);
152# else
153# error Unknown OS
154# endif
njneb8896b2005-06-04 20:03:55 +0000155}
156
157Int VG_(read) ( Int fd, void* buf, Int count)
158{
sewardj9a66bb92006-10-17 01:38:13 +0000159 Int ret;
sewardj6e9de462011-06-28 07:25:29 +0000160# if defined(VGO_linux)
sewardja8d8e232005-06-07 20:04:56 +0000161 SysRes res = VG_(do_syscall3)(__NR_read, fd, (UWord)buf, count);
njnf76d27a2009-05-28 01:53:07 +0000162# elif defined(VGO_darwin)
163 SysRes res = VG_(do_syscall3)(__NR_read_nocancel, fd, (UWord)buf, count);
164# else
165# error Unknown OS
166# endif
njncda2f0f2009-05-18 02:12:08 +0000167 if (sr_isError(res)) {
168 ret = - (Int)(Word)sr_Err(res);
sewardj9a66bb92006-10-17 01:38:13 +0000169 vg_assert(ret < 0);
170 } else {
njncda2f0f2009-05-18 02:12:08 +0000171 ret = (Int)(Word)sr_Res(res);
sewardj9a66bb92006-10-17 01:38:13 +0000172 vg_assert(ret >= 0);
173 }
174 return ret;
njneb8896b2005-06-04 20:03:55 +0000175}
176
177Int VG_(write) ( Int fd, const void* buf, Int count)
178{
sewardj9a66bb92006-10-17 01:38:13 +0000179 Int ret;
sewardj6e9de462011-06-28 07:25:29 +0000180# if defined(VGO_linux)
sewardja8d8e232005-06-07 20:04:56 +0000181 SysRes res = VG_(do_syscall3)(__NR_write, fd, (UWord)buf, count);
njnf76d27a2009-05-28 01:53:07 +0000182# elif defined(VGO_darwin)
183 SysRes res = VG_(do_syscall3)(__NR_write_nocancel, fd, (UWord)buf, count);
184# else
185# error "Unknown OS"
186# endif
njncda2f0f2009-05-18 02:12:08 +0000187 if (sr_isError(res)) {
188 ret = - (Int)(Word)sr_Err(res);
sewardj9a66bb92006-10-17 01:38:13 +0000189 vg_assert(ret < 0);
190 } else {
njncda2f0f2009-05-18 02:12:08 +0000191 ret = (Int)(Word)sr_Res(res);
sewardj9a66bb92006-10-17 01:38:13 +0000192 vg_assert(ret >= 0);
193 }
194 return ret;
njneb8896b2005-06-04 20:03:55 +0000195}
196
njncda2f0f2009-05-18 02:12:08 +0000197
njneb8896b2005-06-04 20:03:55 +0000198Int VG_(pipe) ( Int fd[2] )
199{
petarj4df0bfc2013-02-27 23:17:33 +0000200# if defined(VGP_mips32_linux) || defined(VGP_mips64_linux)
sewardj5db15402012-06-07 09:13:21 +0000201 /* __NR_pipe has a strange return convention on mips32-linux. */
petarj4df0bfc2013-02-27 23:17:33 +0000202 SysRes res = VG_(do_syscall1)(__NR_pipe, (UWord)fd);
sewardj5db15402012-06-07 09:13:21 +0000203 if (!sr_isError(res)) {
204 fd[0] = (Int)sr_Res(res);
205 fd[1] = (Int)sr_ResEx(res);
206 return 0;
207 } else {
208 return -1;
209 }
sewardjf0c12502014-01-12 12:54:00 +0000210# elif defined(VGP_arm64_linux)
211 SysRes res = VG_(do_syscall2)(__NR_pipe2, (UWord)fd, 0);
212 return sr_isError(res) ? -1 : 0;
sewardj5db15402012-06-07 09:13:21 +0000213# elif defined(VGO_linux)
sewardja8d8e232005-06-07 20:04:56 +0000214 SysRes res = VG_(do_syscall1)(__NR_pipe, (UWord)fd);
njncda2f0f2009-05-18 02:12:08 +0000215 return sr_isError(res) ? -1 : 0;
njnf76d27a2009-05-28 01:53:07 +0000216# elif defined(VGO_darwin)
217 /* __NR_pipe is UX64, so produces a double-word result */
218 SysRes res = VG_(do_syscall0)(__NR_pipe);
219 if (!sr_isError(res)) {
220 fd[0] = (Int)sr_Res(res);
221 fd[1] = (Int)sr_ResHI(res);
222 }
223 return sr_isError(res) ? -1 : 0;
njncda2f0f2009-05-18 02:12:08 +0000224# else
225# error "Unknown OS"
226# endif
njneb8896b2005-06-04 20:03:55 +0000227}
228
tomc17c6ef2011-07-13 09:02:14 +0000229Off64T VG_(lseek) ( Int fd, Off64T offset, Int whence )
njneb8896b2005-06-04 20:03:55 +0000230{
sewardj6e9de462011-06-28 07:25:29 +0000231# if defined(VGO_linux) || defined(VGP_amd64_darwin)
tomc17c6ef2011-07-13 09:02:14 +0000232# if defined(__NR__llseek)
233 Off64T result;
234 SysRes res = VG_(do_syscall5)(__NR__llseek, fd,
235 offset >> 32, offset & 0xffffffff,
tomf9b1d732011-07-13 10:05:24 +0000236 (UWord)&result, whence);
tomc17c6ef2011-07-13 09:02:14 +0000237 return sr_isError(res) ? (-1) : result;
238# else
sewardja8d8e232005-06-07 20:04:56 +0000239 SysRes res = VG_(do_syscall3)(__NR_lseek, fd, offset, whence);
tomc17c6ef2011-07-13 09:02:14 +0000240 vg_assert(sizeof(Off64T) == sizeof(Word));
241 return sr_isError(res) ? (-1) : sr_Res(res);
242# endif
njnf76d27a2009-05-28 01:53:07 +0000243# elif defined(VGP_x86_darwin)
244 SysRes res = VG_(do_syscall4)(__NR_lseek, fd,
245 offset & 0xffffffff, offset >> 32, whence);
tomc17c6ef2011-07-13 09:02:14 +0000246 return sr_isError(res) ? (-1) : sr_Res(res);
njncda2f0f2009-05-18 02:12:08 +0000247# else
248# error "Unknown plat"
249# endif
sewardj45f4e7c2005-09-27 19:20:21 +0000250 /* if you change the error-reporting conventions of this, also
philippe8050bb72012-04-13 23:07:29 +0000251 change all usage points. */
njneb8896b2005-06-04 20:03:55 +0000252}
253
sewardjec61b652008-08-19 07:03:04 +0000254
255/* stat/fstat support. It's uggerly. We have impedance-match into a
256 'struct vg_stat' in order to have a single structure that callers
257 can use consistently on all platforms. */
258
259#define TRANSLATE_TO_vg_stat(_p_vgstat, _p_vkistat) \
260 do { \
njn9c20ece2009-05-20 02:02:30 +0000261 (_p_vgstat)->dev = (ULong)( (_p_vkistat)->st_dev ); \
262 (_p_vgstat)->ino = (ULong)( (_p_vkistat)->st_ino ); \
263 (_p_vgstat)->nlink = (ULong)( (_p_vkistat)->st_nlink ); \
264 (_p_vgstat)->mode = (UInt) ( (_p_vkistat)->st_mode ); \
265 (_p_vgstat)->uid = (UInt) ( (_p_vkistat)->st_uid ); \
266 (_p_vgstat)->gid = (UInt) ( (_p_vkistat)->st_gid ); \
267 (_p_vgstat)->rdev = (ULong)( (_p_vkistat)->st_rdev ); \
268 (_p_vgstat)->size = (Long) ( (_p_vkistat)->st_size ); \
269 (_p_vgstat)->blksize = (ULong)( (_p_vkistat)->st_blksize ); \
270 (_p_vgstat)->blocks = (ULong)( (_p_vkistat)->st_blocks ); \
271 (_p_vgstat)->atime = (ULong)( (_p_vkistat)->st_atime ); \
272 (_p_vgstat)->atime_nsec = (ULong)( (_p_vkistat)->st_atime_nsec ); \
273 (_p_vgstat)->mtime = (ULong)( (_p_vkistat)->st_mtime ); \
274 (_p_vgstat)->mtime_nsec = (ULong)( (_p_vkistat)->st_mtime_nsec ); \
275 (_p_vgstat)->ctime = (ULong)( (_p_vkistat)->st_ctime ); \
276 (_p_vgstat)->ctime_nsec = (ULong)( (_p_vkistat)->st_ctime_nsec ); \
sewardjec61b652008-08-19 07:03:04 +0000277 } while (0)
278
florian19f91bb2012-11-10 22:29:54 +0000279SysRes VG_(stat) ( const HChar* file_name, struct vg_stat* vgbuf )
njneb8896b2005-06-04 20:03:55 +0000280{
sewardjec61b652008-08-19 07:03:04 +0000281 SysRes res;
282 VG_(memset)(vgbuf, 0, sizeof(*vgbuf));
njncda2f0f2009-05-18 02:12:08 +0000283
njnf76d27a2009-05-28 01:53:07 +0000284# if defined(VGO_linux) || defined(VGO_darwin)
njncda2f0f2009-05-18 02:12:08 +0000285 /* First try with stat64. If that doesn't work out, fall back to
286 the vanilla version. */
sewardjec61b652008-08-19 07:03:04 +0000287# if defined(__NR_stat64)
288 { struct vki_stat64 buf64;
289 res = VG_(do_syscall2)(__NR_stat64, (UWord)file_name, (UWord)&buf64);
njncda2f0f2009-05-18 02:12:08 +0000290 if (!(sr_isError(res) && sr_Err(res) == VKI_ENOSYS)) {
sewardjec61b652008-08-19 07:03:04 +0000291 /* Success, or any failure except ENOSYS */
njncda2f0f2009-05-18 02:12:08 +0000292 if (!sr_isError(res))
sewardjec61b652008-08-19 07:03:04 +0000293 TRANSLATE_TO_vg_stat(vgbuf, &buf64);
294 return res;
295 }
296 }
njncda2f0f2009-05-18 02:12:08 +0000297# endif /* defined(__NR_stat64) */
sewardjf0c12502014-01-12 12:54:00 +0000298 /* This is the fallback ("vanilla version"). */
sewardjec61b652008-08-19 07:03:04 +0000299 { struct vki_stat buf;
sewardjf0c12502014-01-12 12:54:00 +0000300# if defined(VGP_arm64_linux)
301 res = VG_(do_syscall3)(__NR3264_fstatat, VKI_AT_FDCWD,
302 (UWord)file_name, (UWord)&buf);
303# else
sewardjec61b652008-08-19 07:03:04 +0000304 res = VG_(do_syscall2)(__NR_stat, (UWord)file_name, (UWord)&buf);
sewardjf0c12502014-01-12 12:54:00 +0000305# endif
njncda2f0f2009-05-18 02:12:08 +0000306 if (!sr_isError(res))
sewardjec61b652008-08-19 07:03:04 +0000307 TRANSLATE_TO_vg_stat(vgbuf, &buf);
308 return res;
309 }
njncda2f0f2009-05-18 02:12:08 +0000310
sewardj9a66bb92006-10-17 01:38:13 +0000311# else
312# error Unknown OS
313# endif
njneb8896b2005-06-04 20:03:55 +0000314}
315
sewardjec61b652008-08-19 07:03:04 +0000316Int VG_(fstat) ( Int fd, struct vg_stat* vgbuf )
njneb8896b2005-06-04 20:03:55 +0000317{
sewardjec61b652008-08-19 07:03:04 +0000318 SysRes res;
319 VG_(memset)(vgbuf, 0, sizeof(*vgbuf));
njncda2f0f2009-05-18 02:12:08 +0000320
njnf76d27a2009-05-28 01:53:07 +0000321# if defined(VGO_linux) || defined(VGO_darwin)
njncda2f0f2009-05-18 02:12:08 +0000322 /* First try with fstat64. If that doesn't work out, fall back to
323 the vanilla version. */
sewardjec61b652008-08-19 07:03:04 +0000324# if defined(__NR_fstat64)
325 { struct vki_stat64 buf64;
326 res = VG_(do_syscall2)(__NR_fstat64, (UWord)fd, (UWord)&buf64);
njncda2f0f2009-05-18 02:12:08 +0000327 if (!(sr_isError(res) && sr_Err(res) == VKI_ENOSYS)) {
sewardjec61b652008-08-19 07:03:04 +0000328 /* Success, or any failure except ENOSYS */
njncda2f0f2009-05-18 02:12:08 +0000329 if (!sr_isError(res))
sewardjec61b652008-08-19 07:03:04 +0000330 TRANSLATE_TO_vg_stat(vgbuf, &buf64);
njncda2f0f2009-05-18 02:12:08 +0000331 return sr_isError(res) ? (-1) : 0;
sewardjec61b652008-08-19 07:03:04 +0000332 }
333 }
334# endif /* if defined(__NR_fstat64) */
335 { struct vki_stat buf;
336 res = VG_(do_syscall2)(__NR_fstat, (UWord)fd, (UWord)&buf);
njncda2f0f2009-05-18 02:12:08 +0000337 if (!sr_isError(res))
sewardjec61b652008-08-19 07:03:04 +0000338 TRANSLATE_TO_vg_stat(vgbuf, &buf);
njncda2f0f2009-05-18 02:12:08 +0000339 return sr_isError(res) ? (-1) : 0;
sewardjec61b652008-08-19 07:03:04 +0000340 }
njncda2f0f2009-05-18 02:12:08 +0000341
sewardj9a66bb92006-10-17 01:38:13 +0000342# else
343# error Unknown OS
344# endif
njneb8896b2005-06-04 20:03:55 +0000345}
346
sewardjec61b652008-08-19 07:03:04 +0000347#undef TRANSLATE_TO_vg_stat
348
349
350Long VG_(fsize) ( Int fd )
njneb8896b2005-06-04 20:03:55 +0000351{
sewardjec61b652008-08-19 07:03:04 +0000352 struct vg_stat buf;
353 Int res = VG_(fstat)( fd, &buf );
njn9c20ece2009-05-20 02:02:30 +0000354 return (res == -1) ? (-1LL) : buf.size;
sewardj45f4e7c2005-09-27 19:20:21 +0000355}
356
tomb7c2f9d2014-05-22 08:57:06 +0000357SysRes VG_(getxattr) ( const HChar* file_name, const HChar* attr_name, Addr attr_value, SizeT attr_value_len )
358{
359 SysRes res;
360#if defined(VGO_linux)
361 res = VG_(do_syscall4)(__NR_getxattr, (UWord)file_name, (UWord)attr_name,
362 attr_value, attr_value_len);
363#else
364 res = VG_(mk_SysRes_Error)(VKI_ENOSYS);
365#endif
366 return res;
367}
368
njn63e5e6e2009-05-20 04:22:42 +0000369Bool VG_(is_dir) ( const HChar* f )
njn73750612005-10-14 03:11:30 +0000370{
sewardjec61b652008-08-19 07:03:04 +0000371 struct vg_stat buf;
sewardj9a66bb92006-10-17 01:38:13 +0000372 SysRes res = VG_(stat)(f, &buf);
njncda2f0f2009-05-18 02:12:08 +0000373 return sr_isError(res) ? False
njn9c20ece2009-05-20 02:02:30 +0000374 : VKI_S_ISDIR(buf.mode) ? True : False;
njn73750612005-10-14 03:11:30 +0000375}
376
sewardj45f4e7c2005-09-27 19:20:21 +0000377SysRes VG_(dup) ( Int oldfd )
378{
379 return VG_(do_syscall1)(__NR_dup, oldfd);
njneb8896b2005-06-04 20:03:55 +0000380}
381
njnfad98372008-10-12 19:53:28 +0000382SysRes VG_(dup2) ( Int oldfd, Int newfd )
383{
sewardj6e9de462011-06-28 07:25:29 +0000384# if defined(VGO_linux) || defined(VGO_darwin)
njnfad98372008-10-12 19:53:28 +0000385 return VG_(do_syscall2)(__NR_dup2, oldfd, newfd);
sewardj485ce162008-10-22 00:57:29 +0000386# else
387# error Unknown OS
388# endif
njnfad98372008-10-12 19:53:28 +0000389}
390
njn327fe8a2005-06-12 02:49:35 +0000391/* Returns -1 on error. */
njnbb7af3f2009-05-22 07:08:12 +0000392Int VG_(fcntl) ( Int fd, Int cmd, Addr arg )
njn327fe8a2005-06-12 02:49:35 +0000393{
sewardj6e9de462011-06-28 07:25:29 +0000394# if defined(VGO_linux)
njn327fe8a2005-06-12 02:49:35 +0000395 SysRes res = VG_(do_syscall3)(__NR_fcntl, fd, cmd, arg);
njnf76d27a2009-05-28 01:53:07 +0000396# elif defined(VGO_darwin)
397 SysRes res = VG_(do_syscall3)(__NR_fcntl_nocancel, fd, cmd, arg);
398# else
399# error "Unknown OS"
400# endif
njncda2f0f2009-05-18 02:12:08 +0000401 return sr_isError(res) ? -1 : sr_Res(res);
njn327fe8a2005-06-12 02:49:35 +0000402}
403
florian19f91bb2012-11-10 22:29:54 +0000404Int VG_(rename) ( const HChar* old_name, const HChar* new_name )
njneb8896b2005-06-04 20:03:55 +0000405{
sewardja8d8e232005-06-07 20:04:56 +0000406 SysRes res = VG_(do_syscall2)(__NR_rename, (UWord)old_name, (UWord)new_name);
njncda2f0f2009-05-18 02:12:08 +0000407 return sr_isError(res) ? (-1) : 0;
njneb8896b2005-06-04 20:03:55 +0000408}
409
florian19f91bb2012-11-10 22:29:54 +0000410Int VG_(unlink) ( const HChar* file_name )
njneb8896b2005-06-04 20:03:55 +0000411{
sewardjf0c12502014-01-12 12:54:00 +0000412# if defined(VGP_arm64_linux)
413 SysRes res = VG_(do_syscall2)(__NR_unlinkat, VKI_AT_FDCWD,
414 (UWord)file_name);
415# else
sewardja8d8e232005-06-07 20:04:56 +0000416 SysRes res = VG_(do_syscall1)(__NR_unlink, (UWord)file_name);
sewardjf0c12502014-01-12 12:54:00 +0000417# endif
njncda2f0f2009-05-18 02:12:08 +0000418 return sr_isError(res) ? (-1) : 0;
njneb8896b2005-06-04 20:03:55 +0000419}
420
florian29d82f62014-09-27 17:42:07 +0000421/* The working directory at startup.
422 All that is really needed is to note the cwd at process startup.
423 Hence VG_(record_startup_wd) notes it (in a platform dependent way)
424 and VG_(get_startup_wd) produces the noted value. */
425static HChar *startup_wd;
426static Bool startup_wd_acquired = False;
sewardj198f34f2007-07-09 23:13:07 +0000427
428/* Record the process' working directory at startup. Is intended to
429 be called exactly once, at startup, before the working directory
430 changes. Return True for success, False for failure, so that the
431 caller can bomb out suitably without creating module cycles if
432 there is a problem. */
433Bool VG_(record_startup_wd) ( void )
njneb8896b2005-06-04 20:03:55 +0000434{
sewardj198f34f2007-07-09 23:13:07 +0000435 vg_assert(!startup_wd_acquired);
florian29d82f62014-09-27 17:42:07 +0000436
sewardj9a66bb92006-10-17 01:38:13 +0000437# if defined(VGO_linux)
sewardj198f34f2007-07-09 23:13:07 +0000438 /* Simple: just ask the kernel */
florian29d82f62014-09-27 17:42:07 +0000439 SysRes res;
440 SizeT szB = 0;
441 do {
442 szB += 500;
443 startup_wd = VG_(realloc)("startup_wd", startup_wd, szB);
444 VG_(memset)(startup_wd, 0, szB);
445 res = VG_(do_syscall2)(__NR_getcwd, (UWord)startup_wd, szB-1);
446 } while (sr_isError(res));
447
448 vg_assert(startup_wd[szB-1] == 0);
449 startup_wd_acquired = True;
450 return True;
451
sewardj6e9de462011-06-28 07:25:29 +0000452# elif defined(VGO_darwin)
njnf76d27a2009-05-28 01:53:07 +0000453 /* We can't ask the kernel, so instead rely on launcher-*.c to
sewardj198f34f2007-07-09 23:13:07 +0000454 tell us the startup path. Note the env var is keyed to the
455 parent's PID, not ours, since our parent is the launcher
456 process. */
florian29d82f62014-09-27 17:42:07 +0000457 { HChar envvar[100]; // large enough
458 HChar* wd;
sewardj198f34f2007-07-09 23:13:07 +0000459 VG_(memset)(envvar, 0, sizeof(envvar));
460 VG_(sprintf)(envvar, "VALGRIND_STARTUP_PWD_%d_XYZZY",
461 (Int)VG_(getppid)());
462 wd = VG_(getenv)( envvar );
florian29d82f62014-09-27 17:42:07 +0000463 if (wd == NULL)
sewardj198f34f2007-07-09 23:13:07 +0000464 return False;
florian29d82f62014-09-27 17:42:07 +0000465 SizeT need = VG_(strlen)(wd) + 1;
466 startup_wd = VG_(malloc)("startup_wd", need);
467 VG_(strcpy)(startup_wd, wd);
sewardj198f34f2007-07-09 23:13:07 +0000468 startup_wd_acquired = True;
469 return True;
470 }
sewardj9a66bb92006-10-17 01:38:13 +0000471# else
472# error Unknown OS
473# endif
njneb8896b2005-06-04 20:03:55 +0000474}
475
florian29d82f62014-09-27 17:42:07 +0000476/* Return the previously acquired startup_wd. */
477const HChar *VG_(get_startup_wd) ( void )
sewardj198f34f2007-07-09 23:13:07 +0000478{
479 vg_assert(startup_wd_acquired);
florian29d82f62014-09-27 17:42:07 +0000480
481 return startup_wd;
sewardj198f34f2007-07-09 23:13:07 +0000482}
483
philippe42545842013-12-05 22:10:55 +0000484SysRes VG_(poll) (struct vki_pollfd *fds, Int nfds, Int timeout)
sewardj3b290482011-05-06 21:02:55 +0000485{
486 SysRes res;
philippe0eb0d5a2014-02-11 23:50:16 +0000487# if defined(VGP_arm64_linux)
488 /* ARM64 wants to use __NR_ppoll rather than __NR_poll. */
489 struct vki_timespec timeout_ts;
490 if (timeout >= 0) {
491 timeout_ts.tv_sec = timeout / 1000;
492 timeout_ts.tv_nsec = ((long)timeout % 1000) * 1000000;
493 }
494 res = VG_(do_syscall4)(__NR_ppoll,
495 (UWord)fds, nfds,
496 (UWord)(timeout >= 0 ? &timeout_ts : NULL),
497 (UWord)NULL);
498# elif defined(VGO_linux)
sewardj3b290482011-05-06 21:02:55 +0000499 res = VG_(do_syscall3)(__NR_poll, (UWord)fds, nfds, timeout);
sewardj6caac712012-08-18 06:45:07 +0000500# elif defined(VGO_darwin)
501 res = VG_(do_syscall3)(__NR_poll_nocancel, (UWord)fds, nfds, timeout);
502# else
503# error "Unknown OS"
504# endif
philippe42545842013-12-05 22:10:55 +0000505 return res;
sewardj3b290482011-05-06 21:02:55 +0000506}
507
508
florian19f91bb2012-11-10 22:29:54 +0000509Int VG_(readlink) (const HChar* path, HChar* buf, UInt bufsiz)
njneb8896b2005-06-04 20:03:55 +0000510{
sewardja8d8e232005-06-07 20:04:56 +0000511 SysRes res;
njneb8896b2005-06-04 20:03:55 +0000512 /* res = readlink( path, buf, bufsiz ); */
sewardjf0c12502014-01-12 12:54:00 +0000513# if defined(VGP_arm64_linux)
514 res = VG_(do_syscall4)(__NR_readlinkat, VKI_AT_FDCWD,
515 (UWord)path, (UWord)buf, bufsiz);
516# else
njneb8896b2005-06-04 20:03:55 +0000517 res = VG_(do_syscall3)(__NR_readlink, (UWord)path, (UWord)buf, bufsiz);
sewardjf0c12502014-01-12 12:54:00 +0000518# endif
njncda2f0f2009-05-18 02:12:08 +0000519 return sr_isError(res) ? -1 : sr_Res(res);
njneb8896b2005-06-04 20:03:55 +0000520}
521
sewardjb69cd962014-09-01 22:26:18 +0000522#if defined(VGO_linux)
mjw495c6562014-08-29 14:28:30 +0000523Int VG_(getdents64) (Int fd, struct vki_dirent64 *dirp, UInt count)
njneb8896b2005-06-04 20:03:55 +0000524{
sewardja8d8e232005-06-07 20:04:56 +0000525 SysRes res;
njneb8896b2005-06-04 20:03:55 +0000526 /* res = getdents( fd, dirp, count ); */
mjw495c6562014-08-29 14:28:30 +0000527 res = VG_(do_syscall3)(__NR_getdents64, fd, (UWord)dirp, count);
njncda2f0f2009-05-18 02:12:08 +0000528 return sr_isError(res) ? -1 : sr_Res(res);
njneb8896b2005-06-04 20:03:55 +0000529}
sewardjb69cd962014-09-01 22:26:18 +0000530#endif
njneb8896b2005-06-04 20:03:55 +0000531
sewardj45f4e7c2005-09-27 19:20:21 +0000532/* Check accessibility of a file. Returns zero for access granted,
533 nonzero otherwise. */
njn63e5e6e2009-05-20 04:22:42 +0000534Int VG_(access) ( const HChar* path, Bool irusr, Bool iwusr, Bool ixusr )
sewardj45f4e7c2005-09-27 19:20:21 +0000535{
sewardj9a66bb92006-10-17 01:38:13 +0000536# if defined(VGO_linux)
sewardj45f4e7c2005-09-27 19:20:21 +0000537 /* Very annoyingly, I cannot find any definition for R_OK et al in
538 the kernel interfaces. Therefore I reluctantly resort to
539 hardwiring in these magic numbers that I determined by
540 experimentation. */
njncda2f0f2009-05-18 02:12:08 +0000541# define VKI_R_OK 4
542# define VKI_W_OK 2
543# define VKI_X_OK 1
544# endif
545
sewardj9a66bb92006-10-17 01:38:13 +0000546 UWord w = (irusr ? VKI_R_OK : 0)
547 | (iwusr ? VKI_W_OK : 0)
548 | (ixusr ? VKI_X_OK : 0);
sewardjf0c12502014-01-12 12:54:00 +0000549# if defined(VGP_arm64_linux)
550 SysRes res = VG_(do_syscall3)(__NR_faccessat, VKI_AT_FDCWD, (UWord)path, w);
551# else
sewardj9a66bb92006-10-17 01:38:13 +0000552 SysRes res = VG_(do_syscall2)(__NR_access, (UWord)path, w);
sewardjf0c12502014-01-12 12:54:00 +0000553# endif
njncda2f0f2009-05-18 02:12:08 +0000554 return sr_isError(res) ? 1 : 0;
555
556# if defined(VGO_linux)
557# undef VKI_R_OK
558# undef VKI_W_OK
559# undef VKI_X_OK
sewardj9a66bb92006-10-17 01:38:13 +0000560# endif
sewardj45f4e7c2005-09-27 19:20:21 +0000561}
562
njn73750612005-10-14 03:11:30 +0000563/*
564 Emulate the normal Unix permissions checking algorithm.
565
566 If owner matches, then use the owner permissions, else
567 if group matches, then use the group permissions, else
568 use other permissions.
569
sewardjc74b3ba2007-11-17 21:11:57 +0000570 Note that we can't deal properly with SUID/SGID. By default
571 (allow_setuid == False), we refuse to run them (otherwise the
572 executable may misbehave if it doesn't have the permissions it
573 thinks it does). However, the caller may indicate that setuid
574 executables are allowed, for example if we are going to exec them
575 but not trace into them (iow, client sys_execve when
576 clo_trace_children == False).
577
578 If VKI_EACCES is returned (iow, permission was refused), then
579 *is_setuid is set to True iff permission was refused because the
580 executable is setuid.
njn73750612005-10-14 03:11:30 +0000581*/
582/* returns: 0 = success, non-0 is failure */
sewardjc74b3ba2007-11-17 21:11:57 +0000583Int VG_(check_executable)(/*OUT*/Bool* is_setuid,
njn63e5e6e2009-05-20 04:22:42 +0000584 const HChar* f, Bool allow_setuid)
njn73750612005-10-14 03:11:30 +0000585{
sewardj4231a852008-08-19 08:32:03 +0000586 struct vg_stat st;
sewardj26b87282006-10-17 12:49:31 +0000587 SysRes res = VG_(stat)(f, &st);
njn73750612005-10-14 03:11:30 +0000588
sewardjc74b3ba2007-11-17 21:11:57 +0000589 if (is_setuid)
590 *is_setuid = False;
591
njncda2f0f2009-05-18 02:12:08 +0000592 if (sr_isError(res)) {
593 return sr_Err(res);
njn73750612005-10-14 03:11:30 +0000594 }
595
njn9c20ece2009-05-20 02:02:30 +0000596 if ( (st.mode & (VKI_S_ISUID | VKI_S_ISGID)) && !allow_setuid ) {
sewardjc74b3ba2007-11-17 21:11:57 +0000597 if (is_setuid)
598 *is_setuid = True;
njn73750612005-10-14 03:11:30 +0000599 return VKI_EACCES;
600 }
601
tomb7c2f9d2014-05-22 08:57:06 +0000602 res = VG_(getxattr)(f, "security.capability", (Addr)0, 0);
603 if (!sr_isError(res) && !allow_setuid) {
604 if (is_setuid)
605 *is_setuid = True;
606 return VKI_EACCES;
607 }
608
njn9c20ece2009-05-20 02:02:30 +0000609 if (VG_(geteuid)() == st.uid) {
610 if (!(st.mode & VKI_S_IXUSR))
njn73750612005-10-14 03:11:30 +0000611 return VKI_EACCES;
612 } else {
sewardj45406ef2006-10-18 00:33:46 +0000613 Int grpmatch = 0;
njn73750612005-10-14 03:11:30 +0000614
njn9c20ece2009-05-20 02:02:30 +0000615 if (VG_(getegid)() == st.gid)
njn73750612005-10-14 03:11:30 +0000616 grpmatch = 1;
617 else {
618 UInt groups[32];
619 Int ngrp = VG_(getgroups)(32, groups);
620 Int i;
621 /* ngrp will be -1 if VG_(getgroups) failed. */
622 for (i = 0; i < ngrp; i++) {
njn9c20ece2009-05-20 02:02:30 +0000623 if (groups[i] == st.gid) {
njn73750612005-10-14 03:11:30 +0000624 grpmatch = 1;
625 break;
626 }
627 }
628 }
629
630 if (grpmatch) {
njn9c20ece2009-05-20 02:02:30 +0000631 if (!(st.mode & VKI_S_IXGRP)) {
njn73750612005-10-14 03:11:30 +0000632 return VKI_EACCES;
633 }
njn9c20ece2009-05-20 02:02:30 +0000634 } else if (!(st.mode & VKI_S_IXOTH)) {
njn73750612005-10-14 03:11:30 +0000635 return VKI_EACCES;
636 }
637 }
638
639 return 0;
640}
641
njnc4431bf2009-01-15 21:29:24 +0000642SysRes VG_(pread) ( Int fd, void* buf, Int count, OffT offset )
sewardj45f4e7c2005-09-27 19:20:21 +0000643{
njncda2f0f2009-05-18 02:12:08 +0000644 SysRes res;
philippe8050bb72012-04-13 23:07:29 +0000645 // on 32 bits platforms, we receive a 32 bits OffT but
646 // we must extend it to pass a long long 64 bits.
647# if defined(VGP_x86_linux)
648 vg_assert(sizeof(OffT) == 4);
649 res = VG_(do_syscall5)(__NR_pread64, fd, (UWord)buf, count,
650 offset, 0); // Little endian long long
651 return res;
652# elif defined(VGP_arm_linux)
653 vg_assert(sizeof(OffT) == 4);
654 res = VG_(do_syscall5)(__NR_pread64, fd, (UWord)buf, count,
655 0, offset); // Big endian long long
656 return res;
657# elif defined(VGP_ppc32_linux)
658 vg_assert(sizeof(OffT) == 4);
659 res = VG_(do_syscall6)(__NR_pread64, fd, (UWord)buf, count,
660 0, // Padding needed on PPC32
661 0, offset); // Big endian long long
662 return res;
petarj4df0bfc2013-02-27 23:17:33 +0000663# elif defined(VGP_mips32_linux) && (VKI_LITTLE_ENDIAN)
sewardj5db15402012-06-07 09:13:21 +0000664 vg_assert(sizeof(OffT) == 4);
665 res = VG_(do_syscall6)(__NR_pread64, fd, (UWord)buf, count,
666 0, offset, 0);
667 return res;
petarj4df0bfc2013-02-27 23:17:33 +0000668# elif defined(VGP_mips32_linux) && (VKI_BIG_ENDIAN)
sewardj5db15402012-06-07 09:13:21 +0000669 vg_assert(sizeof(OffT) == 4);
670 res = VG_(do_syscall6)(__NR_pread64, fd, (UWord)buf, count,
671 0, 0, offset);
672 return res;
carllcae0cc22014-08-07 23:17:29 +0000673# elif defined(VGP_amd64_linux) || defined(VGP_s390x_linux) \
674 || defined(VGP_ppc64be_linux) || defined(VGP_ppc64le_linux) \
sewardjf0c12502014-01-12 12:54:00 +0000675 || defined(VGP_mips64_linux) \
676 || defined(VGP_arm64_linux)
philippe8050bb72012-04-13 23:07:29 +0000677 res = VG_(do_syscall4)(__NR_pread64, fd, (UWord)buf, count, offset);
njncda2f0f2009-05-18 02:12:08 +0000678 return res;
njnf76d27a2009-05-28 01:53:07 +0000679# elif defined(VGP_amd64_darwin)
sewardj972316d2012-04-21 15:33:26 +0000680 vg_assert(sizeof(OffT) == 8);
njnf76d27a2009-05-28 01:53:07 +0000681 res = VG_(do_syscall4)(__NR_pread_nocancel, fd, (UWord)buf, count, offset);
682 return res;
683# elif defined(VGP_x86_darwin)
sewardj972316d2012-04-21 15:33:26 +0000684 vg_assert(sizeof(OffT) == 8);
njnf76d27a2009-05-28 01:53:07 +0000685 res = VG_(do_syscall5)(__NR_pread_nocancel, fd, (UWord)buf, count,
sewardj972316d2012-04-21 15:33:26 +0000686 offset & 0xffffffff, offset >> 32);
njnf76d27a2009-05-28 01:53:07 +0000687 return res;
njncda2f0f2009-05-18 02:12:08 +0000688# else
689# error "Unknown platform"
690# endif
sewardj45f4e7c2005-09-27 19:20:21 +0000691}
692
florianb985e2d2011-09-29 03:03:45 +0000693/* Return the name of a directory for temporary files. */
694const HChar *VG_(tmpdir)(void)
695{
696 const HChar *tmpdir;
697
698 tmpdir = VG_(getenv)("TMPDIR");
699 if (tmpdir == NULL || *tmpdir == '\0') tmpdir = VG_TMPDIR;
700 if (tmpdir == NULL || *tmpdir == '\0') tmpdir = "/tmp"; /* fallback */
701
702 return tmpdir;
703}
704
florian60372262014-08-09 21:45:56 +0000705static const HChar mkstemp_format[] = "%s/valgrind_%s_%08x";
philippecc648262013-05-26 21:09:20 +0000706
707SizeT VG_(mkstemp_fullname_bufsz) ( SizeT part_of_name_len )
708{
709 return VG_(strlen)(mkstemp_format)
710 + VG_(strlen)(VG_(tmpdir)()) - 2 // %s tmpdir
711 + part_of_name_len - 2 // %s part_of_name
712 + 8 - 4 // %08x
713 + 1; // trailing 0
714}
715
716
philipped47676f2014-08-09 11:26:51 +0000717Int VG_(mkstemp) ( const HChar* part_of_name, /*OUT*/HChar* fullname )
sewardj45f4e7c2005-09-27 19:20:21 +0000718{
philippecc648262013-05-26 21:09:20 +0000719 HChar buf[VG_(mkstemp_fullname_bufsz)(VG_(strlen)(part_of_name))];
sewardj45f4e7c2005-09-27 19:20:21 +0000720 Int n, tries, fd;
721 UInt seed;
722 SysRes sres;
florian1763e812011-07-12 19:07:05 +0000723 const HChar *tmpdir;
sewardj45f4e7c2005-09-27 19:20:21 +0000724
725 vg_assert(part_of_name);
726 n = VG_(strlen)(part_of_name);
727 vg_assert(n > 0 && n < 100);
728
729 seed = (VG_(getpid)() << 9) ^ VG_(getppid)();
730
florian1763e812011-07-12 19:07:05 +0000731 /* Determine sensible location for temporary files */
florianb985e2d2011-09-29 03:03:45 +0000732 tmpdir = VG_(tmpdir)();
florian1763e812011-07-12 19:07:05 +0000733
sewardj45f4e7c2005-09-27 19:20:21 +0000734 tries = 0;
735 while (True) {
sewardj824b3972011-05-09 22:42:06 +0000736 if (tries++ > 10)
sewardj45f4e7c2005-09-27 19:20:21 +0000737 return -1;
florian60372262014-08-09 21:45:56 +0000738 VG_(sprintf)( buf, mkstemp_format,
florian1763e812011-07-12 19:07:05 +0000739 tmpdir, part_of_name, VG_(random)( &seed ));
sewardj45f4e7c2005-09-27 19:20:21 +0000740 if (0)
741 VG_(printf)("VG_(mkstemp): trying: %s\n", buf);
742
743 sres = VG_(open)(buf,
744 VKI_O_CREAT|VKI_O_RDWR|VKI_O_EXCL|VKI_O_TRUNC,
745 VKI_S_IRUSR|VKI_S_IWUSR);
sewardj80fc03b2011-09-26 16:46:04 +0000746 if (sr_isError(sres)) {
747 VG_(umsg)("VG_(mkstemp): failed to create temp file: %s\n", buf);
sewardj45f4e7c2005-09-27 19:20:21 +0000748 continue;
sewardj80fc03b2011-09-26 16:46:04 +0000749 }
sewardj45f4e7c2005-09-27 19:20:21 +0000750 /* VG_(safe_fd) doesn't return if it fails. */
njncda2f0f2009-05-18 02:12:08 +0000751 fd = VG_(safe_fd)( sr_Res(sres) );
sewardj45f4e7c2005-09-27 19:20:21 +0000752 if (fullname)
753 VG_(strcpy)( fullname, buf );
754 return fd;
755 }
756 /* NOTREACHED */
757}
758
759
njneb8896b2005-06-04 20:03:55 +0000760/* ---------------------------------------------------------------------
njn4bd96bd2009-05-22 00:52:14 +0000761 Socket-related stuff.
njneb8896b2005-06-04 20:03:55 +0000762 ------------------------------------------------------------------ */
763
764static
florian19f91bb2012-11-10 22:29:54 +0000765Int parse_inet_addr_and_port ( const HChar* str, UInt* ip_addr, UShort* port );
njneb8896b2005-06-04 20:03:55 +0000766
767static
njn4bd96bd2009-05-22 00:52:14 +0000768Int my_connect ( Int sockfd, struct vki_sockaddr_in* serv_addr, Int addrlen );
njneb8896b2005-06-04 20:03:55 +0000769
toma4a4f412005-11-17 12:01:56 +0000770UInt VG_(htonl) ( UInt x )
njneb8896b2005-06-04 20:03:55 +0000771{
sewardja1c4bfb2005-10-18 02:15:39 +0000772# if defined(VG_BIGENDIAN)
773 return x;
774# else
njneb8896b2005-06-04 20:03:55 +0000775 return
776 (((x >> 24) & 0xFF) << 0) | (((x >> 16) & 0xFF) << 8)
777 | (((x >> 8) & 0xFF) << 16) | (((x >> 0) & 0xFF) << 24);
sewardja1c4bfb2005-10-18 02:15:39 +0000778# endif
njneb8896b2005-06-04 20:03:55 +0000779}
780
toma4a4f412005-11-17 12:01:56 +0000781UInt VG_(ntohl) ( UInt x )
782{
783# if defined(VG_BIGENDIAN)
784 return x;
785# else
786 return
787 (((x >> 24) & 0xFF) << 0) | (((x >> 16) & 0xFF) << 8)
788 | (((x >> 8) & 0xFF) << 16) | (((x >> 0) & 0xFF) << 24);
789# endif
790}
791
792UShort VG_(htons) ( UShort x )
793{
794# if defined(VG_BIGENDIAN)
795 return x;
796# else
797 return
798 (((x >> 8) & 0xFF) << 0) | (((x >> 0) & 0xFF) << 8);
799# endif
800}
801
802UShort VG_(ntohs) ( UShort x )
njneb8896b2005-06-04 20:03:55 +0000803{
sewardja1c4bfb2005-10-18 02:15:39 +0000804# if defined(VG_BIGENDIAN)
805 return x;
806# else
njneb8896b2005-06-04 20:03:55 +0000807 return
808 (((x >> 8) & 0xFF) << 0) | (((x >> 0) & 0xFF) << 8);
sewardja1c4bfb2005-10-18 02:15:39 +0000809# endif
njneb8896b2005-06-04 20:03:55 +0000810}
811
812
813/* The main function.
814
815 Supplied string contains either an ip address "192.168.0.1" or
816 an ip address and port pair, "192.168.0.1:1500". Parse these,
817 and return:
818 -1 if there is a parse error
819 -2 if no parse error, but specified host:port cannot be opened
820 the relevant file (socket) descriptor, otherwise.
821 is used.
822*/
florian19f91bb2012-11-10 22:29:54 +0000823Int VG_(connect_via_socket)( const HChar* str )
njneb8896b2005-06-04 20:03:55 +0000824{
njnf76d27a2009-05-28 01:53:07 +0000825# if defined(VGO_linux) || defined(VGO_darwin)
njneb8896b2005-06-04 20:03:55 +0000826 Int sd, res;
827 struct vki_sockaddr_in servAddr;
828 UInt ip = 0;
829 UShort port = VG_CLO_DEFAULT_LOGPORT;
830 Bool ok = parse_inet_addr_and_port(str, &ip, &port);
831 if (!ok)
832 return -1;
833
834 //if (0)
835 // VG_(printf)("ip = %d.%d.%d.%d, port %d\n",
836 // (ip >> 24) & 0xFF, (ip >> 16) & 0xFF,
837 // (ip >> 8) & 0xFF, ip & 0xFF,
838 // (UInt)port );
839
840 servAddr.sin_family = VKI_AF_INET;
toma4a4f412005-11-17 12:01:56 +0000841 servAddr.sin_addr.s_addr = VG_(htonl)(ip);
842 servAddr.sin_port = VG_(htons)(port);
njneb8896b2005-06-04 20:03:55 +0000843
844 /* create socket */
njn0cd5d972009-05-22 02:00:27 +0000845 sd = VG_(socket)(VKI_AF_INET, VKI_SOCK_STREAM, 0 /* IPPROTO_IP ? */);
njneb8896b2005-06-04 20:03:55 +0000846 if (sd < 0) {
sewardja1c4bfb2005-10-18 02:15:39 +0000847 /* this shouldn't happen ... nevertheless */
848 return -2;
njneb8896b2005-06-04 20:03:55 +0000849 }
sewardja1c4bfb2005-10-18 02:15:39 +0000850
njneb8896b2005-06-04 20:03:55 +0000851 /* connect to server */
njnb143b272009-05-22 00:47:08 +0000852 res = my_connect(sd, &servAddr, sizeof(servAddr));
njneb8896b2005-06-04 20:03:55 +0000853 if (res < 0) {
sewardja1c4bfb2005-10-18 02:15:39 +0000854 /* connection failed */
855 return -2;
njneb8896b2005-06-04 20:03:55 +0000856 }
857
858 return sd;
njncda2f0f2009-05-18 02:12:08 +0000859
njncda2f0f2009-05-18 02:12:08 +0000860# else
861# error "Unknown OS"
862# endif
njneb8896b2005-06-04 20:03:55 +0000863}
864
865
866/* Let d = one or more digits. Accept either:
867 d.d.d.d or d.d.d.d:d
868*/
florian19f91bb2012-11-10 22:29:54 +0000869static Int parse_inet_addr_and_port ( const HChar* str, UInt* ip_addr, UShort* port )
njneb8896b2005-06-04 20:03:55 +0000870{
871# define GET_CH ((*str) ? (*str++) : 0)
872 UInt ipa, i, j, c, any;
873 ipa = 0;
874 for (i = 0; i < 4; i++) {
875 j = 0;
876 any = 0;
877 while (1) {
878 c = GET_CH;
879 if (c < '0' || c > '9') break;
880 j = 10 * j + (int)(c - '0');
881 any = 1;
882 }
883 if (any == 0 || j > 255) goto syntaxerr;
884 ipa = (ipa << 8) + j;
885 if (i <= 2 && c != '.') goto syntaxerr;
886 }
887 if (c == 0 || c == ':')
888 *ip_addr = ipa;
889 if (c == 0) goto ok;
890 if (c != ':') goto syntaxerr;
891 j = 0;
892 any = 0;
893 while (1) {
894 c = GET_CH;
895 if (c < '0' || c > '9') break;
896 j = j * 10 + (int)(c - '0');
897 any = 1;
898 if (j > 65535) goto syntaxerr;
899 }
900 if (any == 0 || c != 0) goto syntaxerr;
901 if (j < 1024) goto syntaxerr;
902 *port = (UShort)j;
903 ok:
904 return 1;
905 syntaxerr:
906 return 0;
907# undef GET_CH
908}
909
njn0cd5d972009-05-22 02:00:27 +0000910// GrP fixme safe_fd?
911Int VG_(socket) ( Int domain, Int type, Int protocol )
njneb8896b2005-06-04 20:03:55 +0000912{
njncda2f0f2009-05-18 02:12:08 +0000913# if defined(VGP_x86_linux) || defined(VGP_ppc32_linux) \
carllcae0cc22014-08-07 23:17:29 +0000914 || defined(VGP_ppc64be_linux) || defined(VGP_ppc64le_linux) \
915 || defined(VGP_s390x_linux)
sewardja8d8e232005-06-07 20:04:56 +0000916 SysRes res;
917 UWord args[3];
njneb8896b2005-06-04 20:03:55 +0000918 args[0] = domain;
919 args[1] = type;
920 args[2] = protocol;
921 res = VG_(do_syscall2)(__NR_socketcall, VKI_SYS_SOCKET, (UWord)&args);
njncda2f0f2009-05-18 02:12:08 +0000922 return sr_isError(res) ? -1 : sr_Res(res);
cerion85665ca2005-06-20 15:51:07 +0000923
sewardj5db15402012-06-07 09:13:21 +0000924# elif defined(VGP_amd64_linux) || defined(VGP_arm_linux) \
sewardjf0c12502014-01-12 12:54:00 +0000925 || defined(VGP_mips32_linux) || defined(VGP_mips64_linux) \
926 || defined(VGP_arm64_linux)
sewardj1e866562005-09-28 19:58:58 +0000927 SysRes res;
928 res = VG_(do_syscall3)(__NR_socket, domain, type, protocol );
njncda2f0f2009-05-18 02:12:08 +0000929 return sr_isError(res) ? -1 : sr_Res(res);
sewardj9a66bb92006-10-17 01:38:13 +0000930
njnf76d27a2009-05-28 01:53:07 +0000931# elif defined(VGO_darwin)
932 SysRes res;
933 res = VG_(do_syscall3)(__NR_socket, domain, type, protocol);
934 if (!sr_isError(res)) {
935 // Set SO_NOSIGPIPE so write() returns EPIPE instead of raising SIGPIPE
936 Int optval = 1;
937 SysRes res2;
938 res2 = VG_(do_syscall5)(__NR_setsockopt, sr_Res(res), VKI_SOL_SOCKET,
939 VKI_SO_NOSIGPIPE, (UWord)&optval,
940 sizeof(optval));
941 // ignore setsockopt() error
942 }
943 return sr_isError(res) ? -1 : sr_Res(res);
944
njncda2f0f2009-05-18 02:12:08 +0000945# else
946# error "Unknown arch"
947# endif
njneb8896b2005-06-04 20:03:55 +0000948}
949
njncda2f0f2009-05-18 02:12:08 +0000950
njneb8896b2005-06-04 20:03:55 +0000951static
njn4bd96bd2009-05-22 00:52:14 +0000952Int my_connect ( Int sockfd, struct vki_sockaddr_in* serv_addr, Int addrlen )
njneb8896b2005-06-04 20:03:55 +0000953{
njncda2f0f2009-05-18 02:12:08 +0000954# if defined(VGP_x86_linux) || defined(VGP_ppc32_linux) \
carllcae0cc22014-08-07 23:17:29 +0000955 || defined(VGP_ppc64be_linux) || defined(VGP_ppc64le_linux) \
956 || defined(VGP_s390x_linux)
sewardja8d8e232005-06-07 20:04:56 +0000957 SysRes res;
958 UWord args[3];
njneb8896b2005-06-04 20:03:55 +0000959 args[0] = sockfd;
960 args[1] = (UWord)serv_addr;
961 args[2] = addrlen;
962 res = VG_(do_syscall2)(__NR_socketcall, VKI_SYS_CONNECT, (UWord)&args);
njncda2f0f2009-05-18 02:12:08 +0000963 return sr_isError(res) ? -1 : sr_Res(res);
cerion85665ca2005-06-20 15:51:07 +0000964
sewardj5db15402012-06-07 09:13:21 +0000965# elif defined(VGP_amd64_linux) || defined(VGP_arm_linux) \
sewardjf0c12502014-01-12 12:54:00 +0000966 || defined(VGP_mips32_linux) || defined(VGP_mips64_linux) \
967 || defined(VGP_arm64_linux)
sewardj1e866562005-09-28 19:58:58 +0000968 SysRes res;
969 res = VG_(do_syscall3)(__NR_connect, sockfd, (UWord)serv_addr, addrlen);
njncda2f0f2009-05-18 02:12:08 +0000970 return sr_isError(res) ? -1 : sr_Res(res);
sewardj9a66bb92006-10-17 01:38:13 +0000971
njnf76d27a2009-05-28 01:53:07 +0000972# elif defined(VGO_darwin)
973 SysRes res;
974 res = VG_(do_syscall3)(__NR_connect_nocancel,
975 sockfd, (UWord)serv_addr, addrlen);
976 return sr_isError(res) ? -1 : sr_Res(res);
977
njncda2f0f2009-05-18 02:12:08 +0000978# else
979# error "Unknown arch"
980# endif
njneb8896b2005-06-04 20:03:55 +0000981}
982
floriandbb35842012-10-27 18:39:11 +0000983Int VG_(write_socket)( Int sd, const void *msg, Int count )
njneb8896b2005-06-04 20:03:55 +0000984{
njneb8896b2005-06-04 20:03:55 +0000985 /* This is actually send(). */
njnf76d27a2009-05-28 01:53:07 +0000986
987 /* For Linux, VKI_MSG_NOSIGNAL is a request not to send SIGPIPE on
sewardj9a66bb92006-10-17 01:38:13 +0000988 errors on stream oriented sockets when the other end breaks the
njnf76d27a2009-05-28 01:53:07 +0000989 connection. The EPIPE error is still returned.
990
991 For Darwin, VG_(socket)() sets SO_NOSIGPIPE to get EPIPE instead of
992 SIGPIPE */
njneb8896b2005-06-04 20:03:55 +0000993
njncda2f0f2009-05-18 02:12:08 +0000994# if defined(VGP_x86_linux) || defined(VGP_ppc32_linux) \
carllcae0cc22014-08-07 23:17:29 +0000995 || defined(VGP_ppc64be_linux) || defined(VGP_ppc64le_linux) \
996 || defined(VGP_s390x_linux)
sewardja8d8e232005-06-07 20:04:56 +0000997 SysRes res;
998 UWord args[4];
njneb8896b2005-06-04 20:03:55 +0000999 args[0] = sd;
1000 args[1] = (UWord)msg;
1001 args[2] = count;
sewardj9a66bb92006-10-17 01:38:13 +00001002 args[3] = VKI_MSG_NOSIGNAL;
njneb8896b2005-06-04 20:03:55 +00001003 res = VG_(do_syscall2)(__NR_socketcall, VKI_SYS_SEND, (UWord)&args);
njncda2f0f2009-05-18 02:12:08 +00001004 return sr_isError(res) ? -1 : sr_Res(res);
cerion85665ca2005-06-20 15:51:07 +00001005
sewardj5db15402012-06-07 09:13:21 +00001006# elif defined(VGP_amd64_linux) || defined(VGP_arm_linux) \
sewardjf0c12502014-01-12 12:54:00 +00001007 || defined(VGP_mips32_linux) || defined(VGP_mips64_linux) \
1008 || defined(VGP_arm64_linux)
sewardj1e866562005-09-28 19:58:58 +00001009 SysRes res;
sewardj9a66bb92006-10-17 01:38:13 +00001010 res = VG_(do_syscall6)(__NR_sendto, sd, (UWord)msg,
1011 count, VKI_MSG_NOSIGNAL, 0,0);
njncda2f0f2009-05-18 02:12:08 +00001012 return sr_isError(res) ? -1 : sr_Res(res);
sewardj9a66bb92006-10-17 01:38:13 +00001013
njnf76d27a2009-05-28 01:53:07 +00001014# elif defined(VGP_x86_darwin) || defined(VGP_amd64_darwin)
1015 SysRes res;
1016 res = VG_(do_syscall3)(__NR_write_nocancel, sd, (UWord)msg, count);
1017 return sr_isError(res) ? -1 : sr_Res(res);
1018
njncda2f0f2009-05-18 02:12:08 +00001019# else
1020# error "Unknown platform"
1021# endif
njneb8896b2005-06-04 20:03:55 +00001022}
1023
1024Int VG_(getsockname) ( Int sd, struct vki_sockaddr *name, Int *namelen)
1025{
njncda2f0f2009-05-18 02:12:08 +00001026# if defined(VGP_x86_linux) || defined(VGP_ppc32_linux) \
carllcae0cc22014-08-07 23:17:29 +00001027 || defined(VGP_ppc64be_linux) || defined(VGP_ppc64le_linux) \
1028 || defined(VGP_s390x_linux) \
sewardj5db15402012-06-07 09:13:21 +00001029 || defined(VGP_mips32_linux)
sewardj9a66bb92006-10-17 01:38:13 +00001030 SysRes res;
sewardja8d8e232005-06-07 20:04:56 +00001031 UWord args[3];
njneb8896b2005-06-04 20:03:55 +00001032 args[0] = sd;
1033 args[1] = (UWord)name;
1034 args[2] = (UWord)namelen;
1035 res = VG_(do_syscall2)(__NR_socketcall, VKI_SYS_GETSOCKNAME, (UWord)&args);
njncda2f0f2009-05-18 02:12:08 +00001036 return sr_isError(res) ? -1 : sr_Res(res);
sewardja5c9e4a2005-06-09 13:21:58 +00001037
petarj4df0bfc2013-02-27 23:17:33 +00001038# elif defined(VGP_amd64_linux) || defined(VGP_arm_linux) \
sewardjf0c12502014-01-12 12:54:00 +00001039 || defined(VGP_mips64_linux) || defined(VGP_arm64_linux)
sewardj9a66bb92006-10-17 01:38:13 +00001040 SysRes res;
sewardja5c9e4a2005-06-09 13:21:58 +00001041 res = VG_(do_syscall3)( __NR_getsockname,
1042 (UWord)sd, (UWord)name, (UWord)namelen );
njncda2f0f2009-05-18 02:12:08 +00001043 return sr_isError(res) ? -1 : sr_Res(res);
sewardj9a66bb92006-10-17 01:38:13 +00001044
njnf76d27a2009-05-28 01:53:07 +00001045# elif defined(VGO_darwin)
1046 SysRes res;
1047 res = VG_(do_syscall3)( __NR_getsockname,
1048 (UWord)sd, (UWord)name, (UWord)namelen );
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
1056Int VG_(getpeername) ( Int sd, struct vki_sockaddr *name, Int *namelen)
1057{
njncda2f0f2009-05-18 02:12:08 +00001058# if defined(VGP_x86_linux) || defined(VGP_ppc32_linux) \
carllcae0cc22014-08-07 23:17:29 +00001059 || defined(VGP_ppc64be_linux) || defined(VGP_ppc64le_linux) \
1060 || defined(VGP_s390x_linux) \
sewardj5db15402012-06-07 09:13:21 +00001061 || defined(VGP_mips32_linux)
sewardj9a66bb92006-10-17 01:38:13 +00001062 SysRes res;
sewardja8d8e232005-06-07 20:04:56 +00001063 UWord args[3];
njneb8896b2005-06-04 20:03:55 +00001064 args[0] = sd;
1065 args[1] = (UWord)name;
1066 args[2] = (UWord)namelen;
1067 res = VG_(do_syscall2)(__NR_socketcall, VKI_SYS_GETPEERNAME, (UWord)&args);
njncda2f0f2009-05-18 02:12:08 +00001068 return sr_isError(res) ? -1 : sr_Res(res);
sewardja5c9e4a2005-06-09 13:21:58 +00001069
petarj4df0bfc2013-02-27 23:17:33 +00001070# elif defined(VGP_amd64_linux) || defined(VGP_arm_linux) \
sewardjf0c12502014-01-12 12:54:00 +00001071 || defined(VGP_mips64_linux) || defined(VGP_arm64_linux)
sewardj9a66bb92006-10-17 01:38:13 +00001072 SysRes res;
sewardja5c9e4a2005-06-09 13:21:58 +00001073 res = VG_(do_syscall3)( __NR_getpeername,
1074 (UWord)sd, (UWord)name, (UWord)namelen );
njncda2f0f2009-05-18 02:12:08 +00001075 return sr_isError(res) ? -1 : sr_Res(res);
sewardj9a66bb92006-10-17 01:38:13 +00001076
njnf76d27a2009-05-28 01:53:07 +00001077# elif defined(VGO_darwin)
1078 SysRes res;
1079 res = VG_(do_syscall3)( __NR_getpeername,
1080 (UWord)sd, (UWord)name, (UWord)namelen );
1081 return sr_isError(res) ? -1 : sr_Res(res);
1082
njncda2f0f2009-05-18 02:12:08 +00001083# else
1084# error "Unknown platform"
1085# endif
njneb8896b2005-06-04 20:03:55 +00001086}
1087
1088Int VG_(getsockopt) ( Int sd, Int level, Int optname, void *optval,
1089 Int *optlen)
1090{
njncda2f0f2009-05-18 02:12:08 +00001091# if defined(VGP_x86_linux) || defined(VGP_ppc32_linux) \
carllcae0cc22014-08-07 23:17:29 +00001092 || defined(VGP_ppc64be_linux) || defined(VGP_ppc64le_linux) \
1093 || defined(VGP_s390x_linux)
sewardj9a66bb92006-10-17 01:38:13 +00001094 SysRes res;
sewardja8d8e232005-06-07 20:04:56 +00001095 UWord args[5];
njneb8896b2005-06-04 20:03:55 +00001096 args[0] = sd;
1097 args[1] = level;
1098 args[2] = optname;
1099 args[3] = (UWord)optval;
1100 args[4] = (UWord)optlen;
1101 res = VG_(do_syscall2)(__NR_socketcall, VKI_SYS_GETSOCKOPT, (UWord)&args);
njncda2f0f2009-05-18 02:12:08 +00001102 return sr_isError(res) ? -1 : sr_Res(res);
sewardja5c9e4a2005-06-09 13:21:58 +00001103
sewardj5db15402012-06-07 09:13:21 +00001104# elif defined(VGP_amd64_linux) || defined(VGP_arm_linux) \
sewardjf0c12502014-01-12 12:54:00 +00001105 || defined(VGP_mips32_linux) || defined(VGP_mips64_linux) \
1106 || defined(VGP_arm64_linux)
sewardj9a66bb92006-10-17 01:38:13 +00001107 SysRes res;
sewardja5c9e4a2005-06-09 13:21:58 +00001108 res = VG_(do_syscall5)( __NR_getsockopt,
1109 (UWord)sd, (UWord)level, (UWord)optname,
1110 (UWord)optval, (UWord)optlen );
njncda2f0f2009-05-18 02:12:08 +00001111 return sr_isError(res) ? -1 : sr_Res(res);
sewardj9a66bb92006-10-17 01:38:13 +00001112
njnf76d27a2009-05-28 01:53:07 +00001113# elif defined(VGO_darwin)
1114 SysRes res;
1115 res = VG_(do_syscall5)( __NR_getsockopt,
1116 (UWord)sd, (UWord)level, (UWord)optname,
1117 (UWord)optval, (UWord)optlen );
1118 return sr_isError(res) ? -1 : sr_Res(res);
1119
njncda2f0f2009-05-18 02:12:08 +00001120# else
1121# error "Unknown platform"
1122# endif
njneb8896b2005-06-04 20:03:55 +00001123}
1124
1125
sewardj5d616df2013-07-02 08:07:15 +00001126Int VG_(setsockopt) ( Int sd, Int level, Int optname, void *optval,
1127 Int optlen)
njnf76d27a2009-05-28 01:53:07 +00001128{
sewardj5d616df2013-07-02 08:07:15 +00001129# if defined(VGP_x86_linux) || defined(VGP_ppc32_linux) \
carllcae0cc22014-08-07 23:17:29 +00001130 || defined(VGP_ppc64be_linux) || defined(VGP_ppc64le_linux) \
1131 || defined(VGP_s390x_linux)
sewardj5d616df2013-07-02 08:07:15 +00001132 SysRes res;
1133 UWord args[5];
1134 args[0] = sd;
1135 args[1] = level;
1136 args[2] = optname;
1137 args[3] = (UWord)optval;
1138 args[4] = (UWord)optlen;
1139 res = VG_(do_syscall2)(__NR_socketcall, VKI_SYS_SETSOCKOPT, (UWord)&args);
1140 return sr_isError(res) ? -1 : sr_Res(res);
1141
1142# elif defined(VGP_amd64_linux) || defined(VGP_arm_linux) \
sewardjf0c12502014-01-12 12:54:00 +00001143 || defined(VGP_mips32_linux) || defined(VGP_mips64_linux) \
1144 || defined(VGP_arm64_linux)
sewardj5d616df2013-07-02 08:07:15 +00001145 SysRes res;
1146 res = VG_(do_syscall5)( __NR_setsockopt,
1147 (UWord)sd, (UWord)level, (UWord)optname,
1148 (UWord)optval, (UWord)optlen );
1149 return sr_isError(res) ? -1 : sr_Res(res);
1150
1151# elif defined(VGO_darwin)
1152 SysRes res;
1153 res = VG_(do_syscall5)( __NR_setsockopt,
1154 (UWord)sd, (UWord)level, (UWord)optname,
1155 (UWord)optval, (UWord)optlen );
1156 return sr_isError(res) ? -1 : sr_Res(res);
1157
1158# else
1159# error "Unknown platform"
1160# endif
1161}
1162
1163
florian6bd9dc12012-11-23 16:17:43 +00001164const HChar *VG_(basename)(const HChar *path)
njnf76d27a2009-05-28 01:53:07 +00001165{
florian58946e92014-09-27 13:29:09 +00001166 static HChar *buf = NULL;
1167 static SizeT buf_len = 0;
florian19f91bb2012-11-10 22:29:54 +00001168 const HChar *p, *end;
njnf76d27a2009-05-28 01:53:07 +00001169
1170 if (path == NULL ||
1171 0 == VG_(strcmp)(path, ""))
1172 {
1173 return ".";
1174 }
1175
1176 p = path + VG_(strlen)(path);
1177 while (p > path && *p == '/') {
1178 // skip all trailing '/'
1179 p--;
1180 }
1181
1182 if (p == path && *p == '/') return "/"; // all slashes
1183
1184 end = p;
1185
1186 while (p > path && *p != '/') {
1187 // now skip non '/'
1188 p--;
1189 }
1190
1191 if (*p == '/') p++;
1192
florian58946e92014-09-27 13:29:09 +00001193 SizeT need = end-p+1 + 1;
1194 if (need > buf_len) {
1195 buf_len = (buf_len == 0) ? 500 : need;
1196 buf = VG_(realloc)("basename", buf, buf_len);
1197 }
njnf76d27a2009-05-28 01:53:07 +00001198 VG_(strncpy)(buf, p, end-p+1);
1199 buf[end-p+1] = '\0';
1200
1201 return buf;
1202}
1203
1204
florian6bd9dc12012-11-23 16:17:43 +00001205const HChar *VG_(dirname)(const HChar *path)
njnf76d27a2009-05-28 01:53:07 +00001206{
florian58946e92014-09-27 13:29:09 +00001207 static HChar *buf = NULL;
1208 static SizeT buf_len = 0;
njnf76d27a2009-05-28 01:53:07 +00001209
florian19f91bb2012-11-10 22:29:54 +00001210 const HChar *p;
njnf76d27a2009-05-28 01:53:07 +00001211
1212 if (path == NULL ||
1213 0 == VG_(strcmp)(path, "") ||
1214 0 == VG_(strcmp)(path, "/"))
1215 {
1216 return ".";
1217 }
1218
1219 p = path + VG_(strlen)(path);
1220 while (p > path && *p == '/') {
1221 // skip all trailing '/'
1222 p--;
1223 }
1224
1225 while (p > path && *p != '/') {
1226 // now skip non '/'
1227 p--;
1228 }
1229
1230 if (p == path) {
1231 if (*p == '/') return "/"; // all slashes
1232 else return "."; // no slashes
1233 }
1234
1235 while (p > path && *p == '/') {
1236 // skip '/' again
1237 p--;
1238 }
1239
florian58946e92014-09-27 13:29:09 +00001240 SizeT need = p-path+1 + 1;
1241 if (need > buf_len) {
1242 buf_len = (buf_len == 0) ? 500 : need;
1243 buf = VG_(realloc)("dirname", buf, buf_len);
1244 }
njnf76d27a2009-05-28 01:53:07 +00001245 VG_(strncpy)(buf, path, p-path+1);
1246 buf[p-path+1] = '\0';
1247
1248 return buf;
1249}
1250
1251
njneb8896b2005-06-04 20:03:55 +00001252/*--------------------------------------------------------------------*/
1253/*--- end ---*/
1254/*--------------------------------------------------------------------*/