1ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--------------------------------------------------------------------*/
3ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- File- and socket-related libc stuff.            m_libcfile.c ---*/
4ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--------------------------------------------------------------------*/
5ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*
7ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   This file is part of Valgrind, a dynamic binary instrumentation
8ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   framework.
9ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   Copyright (C) 2000-2011 Julian Seward
11ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      jseward@acm.org
12ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   This program is free software; you can redistribute it and/or
14ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   modify it under the terms of the GNU General Public License as
15ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   published by the Free Software Foundation; either version 2 of the
16ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   License, or (at your option) any later version.
17ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   This program is distributed in the hope that it will be useful, but
19ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   WITHOUT ANY WARRANTY; without even the implied warranty of
20ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
21ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   General Public License for more details.
22ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
23ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   You should have received a copy of the GNU General Public License
24ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   along with this program; if not, write to the Free Software
25ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
26ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   02111-1307, USA.
27ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
28ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   The GNU General Public License is contained in the file COPYING.
29ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
30ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
31ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_basics.h"
32ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_vki.h"
33ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_vkiscnums.h"
34ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_debuglog.h"
35ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_libcbase.h"
36ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_libcassert.h"
37ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_libcfile.h"
38ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_libcprint.h"     // VG_(sprintf)
39ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_libcproc.h"      // VG_(getpid), VG_(getppid)
40ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_xarray.h"
41ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_clientstate.h"   // VG_(fd_hard_limit)
42ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_syscall.h"
43ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
44ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* IMPORTANT: on Darwin it is essential to use the _nocancel versions
45ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   of syscalls rather than the vanilla version, if a _nocancel version
46ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   is available.  See docs/internals/Darwin-notes.txt for the reason
47ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   why. */
48ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
49ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* ---------------------------------------------------------------------
50ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   File stuff
51ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ------------------------------------------------------------------ */
52ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
53ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic inline Bool fd_exists(Int fd)
54ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
55ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   struct vg_stat st;
56ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return VG_(fstat)(fd, &st) == 0;
57ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
58ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
59ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Move an fd into the Valgrind-safe range */
60ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownInt VG_(safe_fd)(Int oldfd)
61ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
62ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int newfd;
63ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
64ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(VG_(fd_hard_limit) != -1);
65ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
66ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   newfd = VG_(fcntl)(oldfd, VKI_F_DUPFD, VG_(fd_hard_limit));
67ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (newfd != -1)
68ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(close)(oldfd);
69ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
70ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Set the close-on-exec flag for this fd. */
71ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(fcntl)(newfd, VKI_F_SETFD, VKI_FD_CLOEXEC);
72ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
73ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(newfd >= VG_(fd_hard_limit));
74ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return newfd;
75ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
76ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
77ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Given a file descriptor, attempt to deduce its filename.  To do
78ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   this, we use /proc/self/fd/<FD>.  If this doesn't point to a file,
79ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   or if it doesn't exist, we return False. */
80ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownBool VG_(resolve_filename) ( Int fd, HChar* buf, Int n_buf )
81ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
82ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  if defined(VGO_linux)
83ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar tmp[64];
84ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(sprintf)(tmp, "/proc/self/fd/%d", fd);
85ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(memset)(buf, 0, n_buf);
86ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (VG_(readlink)(tmp, buf, n_buf) > 0 && buf[0] == '/')
87ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return True;
88ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else
89ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return False;
90ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
91ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  elif defined(VGO_darwin)
92ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar tmp[VKI_MAXPATHLEN+1];
93ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (0 == VG_(fcntl)(fd, VKI_F_GETPATH, (UWord)tmp)) {
94ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (n_buf > 0) {
95ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(strncpy)( buf, tmp, n_buf < sizeof(tmp) ? n_buf : sizeof(tmp) );
96ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         buf[n_buf-1] = 0;
97ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
98ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (tmp[0] == '/') return True;
99ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return False;
101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  else
103ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#     error Unknown OS
104ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  endif
105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
107b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy StepanovSysRes VG_(mknod) ( const Char* pathname, Int mode, UWord dev )
108b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov{
109b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#  if defined(VGO_linux) || defined(VGO_darwin)
110b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   SysRes res = VG_(do_syscall3)(__NR_mknod,
111b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                                 (UWord)pathname, mode, dev);
112b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#  else
113b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#    error Unknown OS
114b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#  endif
115b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   return res;
116b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov}
117b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
118ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownSysRes VG_(open) ( const Char* pathname, Int flags, Int mode )
119ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
120b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#  if defined(VGO_linux)
121ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SysRes res = VG_(do_syscall3)(__NR_open,
122ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 (UWord)pathname, flags, mode);
123ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  elif defined(VGO_darwin)
124ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SysRes res = VG_(do_syscall3)(__NR_open_nocancel,
125ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 (UWord)pathname, flags, mode);
126ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  else
127ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#    error Unknown OS
128ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  endif
129ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return res;
130ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
131ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
132b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy StepanovInt VG_(fd_open) (const Char* pathname, Int flags, Int mode)
133b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov{
134b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   SysRes sr;
135b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   sr = VG_(open) (pathname, flags, mode);
136b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (sr_isError (sr))
137b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      return -1;
138b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   else
139b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      return sr_Res (sr);
140b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov}
141b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
142ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid VG_(close) ( Int fd )
143ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
144ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Hmm.  Return value is not checked.  That's uncool. */
145b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#  if defined(VGO_linux)
146ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   (void)VG_(do_syscall1)(__NR_close, fd);
147ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  elif defined(VGO_darwin)
148ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   (void)VG_(do_syscall1)(__NR_close_nocancel, fd);
149ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  else
150ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#    error Unknown OS
151ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  endif
152ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
153ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
154ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownInt VG_(read) ( Int fd, void* buf, Int count)
155ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
156ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int    ret;
157b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#  if defined(VGO_linux)
158ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SysRes res = VG_(do_syscall3)(__NR_read, fd, (UWord)buf, count);
159ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  elif defined(VGO_darwin)
160ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SysRes res = VG_(do_syscall3)(__NR_read_nocancel, fd, (UWord)buf, count);
161ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  else
162ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#    error Unknown OS
163ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  endif
164ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sr_isError(res)) {
165ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ret = - (Int)(Word)sr_Err(res);
166ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert(ret < 0);
167ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
168ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ret = (Int)(Word)sr_Res(res);
169ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert(ret >= 0);
170ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
171ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return ret;
172ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
173ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
174ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownInt VG_(write) ( Int fd, const void* buf, Int count)
175ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
176ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int    ret;
177b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#  if defined(VGO_linux)
178ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SysRes res = VG_(do_syscall3)(__NR_write, fd, (UWord)buf, count);
179ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  elif defined(VGO_darwin)
180ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SysRes res = VG_(do_syscall3)(__NR_write_nocancel, fd, (UWord)buf, count);
181ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  else
182ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#    error "Unknown OS"
183ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  endif
184ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sr_isError(res)) {
185ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ret = - (Int)(Word)sr_Err(res);
186ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert(ret < 0);
187ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
188ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ret = (Int)(Word)sr_Res(res);
189ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert(ret >= 0);
190ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
191ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return ret;
192ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
193ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
194ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
195ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownInt VG_(pipe) ( Int fd[2] )
196ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
197b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#  if defined(VGO_linux)
198ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SysRes res = VG_(do_syscall1)(__NR_pipe, (UWord)fd);
199ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return sr_isError(res) ? -1 : 0;
200ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  elif defined(VGO_darwin)
201ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* __NR_pipe is UX64, so produces a double-word result */
202ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SysRes res = VG_(do_syscall0)(__NR_pipe);
203ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (!sr_isError(res)) {
204ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      fd[0] = (Int)sr_Res(res);
205ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      fd[1] = (Int)sr_ResHI(res);
206ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
207ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return sr_isError(res) ? -1 : 0;
208ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  else
209ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#    error "Unknown OS"
210ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  endif
211ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
212ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
213b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy StepanovOff64T VG_(lseek) ( Int fd, Off64T offset, Int whence )
214ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
215b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#  if defined(VGO_linux) || defined(VGP_amd64_darwin)
216b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#  if defined(__NR__llseek)
217b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   Off64T result;
218b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   SysRes res = VG_(do_syscall5)(__NR__llseek, fd,
219b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                                 offset >> 32, offset & 0xffffffff,
220b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                                 (UWord)&result, whence);
221b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   return sr_isError(res) ? (-1) : result;
222b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#  else
223ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SysRes res = VG_(do_syscall3)(__NR_lseek, fd, offset, whence);
224b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   vg_assert(sizeof(Off64T) == sizeof(Word));
225b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   return sr_isError(res) ? (-1) : sr_Res(res);
226b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#  endif
227ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  elif defined(VGP_x86_darwin)
228ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SysRes res = VG_(do_syscall4)(__NR_lseek, fd,
229ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 offset & 0xffffffff, offset >> 32, whence);
230b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   return sr_isError(res) ? (-1) : sr_Res(res);
231ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  else
232ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#    error "Unknown plat"
233ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  endif
234ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* if you change the error-reporting conventions of this, also
235ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      change VG_(pread) and all other usage points. */
236ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
237ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
238f0cb39bc6abe181a0abdd1f6c778521ae8497277Evgeniy Stepanovextern Int VG_(ftruncate) ( Int fd, OffT length ) {
239f0cb39bc6abe181a0abdd1f6c778521ae8497277Evgeniy Stepanov#if defined (VGO_linux)
240f0cb39bc6abe181a0abdd1f6c778521ae8497277Evgeniy Stepanov   SysRes res = VG_(do_syscall2)(__NR_ftruncate, fd, length);
241f0cb39bc6abe181a0abdd1f6c778521ae8497277Evgeniy Stepanov   return sr_isError(res) ? (-1) : sr_Res(res);
242f0cb39bc6abe181a0abdd1f6c778521ae8497277Evgeniy Stepanov#else
243f0cb39bc6abe181a0abdd1f6c778521ae8497277Evgeniy Stepanov   return -1;  /*UNIMPLEMENTED*/
244f0cb39bc6abe181a0abdd1f6c778521ae8497277Evgeniy Stepanov#endif
245f0cb39bc6abe181a0abdd1f6c778521ae8497277Evgeniy Stepanov}
246ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
247ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* stat/fstat support.  It's uggerly.  We have impedance-match into a
248ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   'struct vg_stat' in order to have a single structure that callers
249ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   can use consistently on all platforms. */
250ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
251ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define TRANSLATE_TO_vg_stat(_p_vgstat, _p_vkistat) \
252ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   do { \
253ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      (_p_vgstat)->dev        = (ULong)( (_p_vkistat)->st_dev ); \
254ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      (_p_vgstat)->ino        = (ULong)( (_p_vkistat)->st_ino ); \
255ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      (_p_vgstat)->nlink      = (ULong)( (_p_vkistat)->st_nlink ); \
256ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      (_p_vgstat)->mode       = (UInt) ( (_p_vkistat)->st_mode ); \
257ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      (_p_vgstat)->uid        = (UInt) ( (_p_vkistat)->st_uid ); \
258ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      (_p_vgstat)->gid        = (UInt) ( (_p_vkistat)->st_gid ); \
259ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      (_p_vgstat)->rdev       = (ULong)( (_p_vkistat)->st_rdev ); \
260ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      (_p_vgstat)->size       = (Long) ( (_p_vkistat)->st_size ); \
261ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      (_p_vgstat)->blksize    = (ULong)( (_p_vkistat)->st_blksize ); \
262ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      (_p_vgstat)->blocks     = (ULong)( (_p_vkistat)->st_blocks ); \
263ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      (_p_vgstat)->atime      = (ULong)( (_p_vkistat)->st_atime ); \
264ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      (_p_vgstat)->atime_nsec = (ULong)( (_p_vkistat)->st_atime_nsec ); \
265ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      (_p_vgstat)->mtime      = (ULong)( (_p_vkistat)->st_mtime ); \
266ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      (_p_vgstat)->mtime_nsec = (ULong)( (_p_vkistat)->st_mtime_nsec ); \
267ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      (_p_vgstat)->ctime      = (ULong)( (_p_vkistat)->st_ctime ); \
268ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      (_p_vgstat)->ctime_nsec = (ULong)( (_p_vkistat)->st_ctime_nsec ); \
269ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } while (0)
270ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
271ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownSysRes VG_(stat) ( const Char* file_name, struct vg_stat* vgbuf )
272ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
273ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SysRes res;
274ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(memset)(vgbuf, 0, sizeof(*vgbuf));
275ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
276ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  if defined(VGO_linux) || defined(VGO_darwin)
277ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* First try with stat64.  If that doesn't work out, fall back to
278ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      the vanilla version. */
279ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  if defined(__NR_stat64)
280ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   { struct vki_stat64 buf64;
281ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     res = VG_(do_syscall2)(__NR_stat64, (UWord)file_name, (UWord)&buf64);
282ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     if (!(sr_isError(res) && sr_Err(res) == VKI_ENOSYS)) {
283ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        /* Success, or any failure except ENOSYS */
284ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        if (!sr_isError(res))
285ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           TRANSLATE_TO_vg_stat(vgbuf, &buf64);
286ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        return res;
287ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     }
288ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
289ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  endif /* defined(__NR_stat64) */
290ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   { struct vki_stat buf;
291ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     res = VG_(do_syscall2)(__NR_stat, (UWord)file_name, (UWord)&buf);
292ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     if (!sr_isError(res))
293ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        TRANSLATE_TO_vg_stat(vgbuf, &buf);
294ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     return res;
295ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
296ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
297ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  else
298ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#    error Unknown OS
299ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  endif
300ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
301ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
302ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownInt VG_(fstat) ( Int fd, struct vg_stat* vgbuf )
303ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
304ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SysRes res;
305ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(memset)(vgbuf, 0, sizeof(*vgbuf));
306ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
307ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  if defined(VGO_linux)  ||  defined(VGO_darwin)
308ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* First try with fstat64.  If that doesn't work out, fall back to
309ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      the vanilla version. */
310ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  if defined(__NR_fstat64)
311ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   { struct vki_stat64 buf64;
312ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     res = VG_(do_syscall2)(__NR_fstat64, (UWord)fd, (UWord)&buf64);
313ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     if (!(sr_isError(res) && sr_Err(res) == VKI_ENOSYS)) {
314ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        /* Success, or any failure except ENOSYS */
315ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        if (!sr_isError(res))
316ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           TRANSLATE_TO_vg_stat(vgbuf, &buf64);
317ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        return sr_isError(res) ? (-1) : 0;
318ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     }
319ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
320ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  endif /* if defined(__NR_fstat64) */
321ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   { struct vki_stat buf;
322ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     res = VG_(do_syscall2)(__NR_fstat, (UWord)fd, (UWord)&buf);
323ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     if (!sr_isError(res))
324ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        TRANSLATE_TO_vg_stat(vgbuf, &buf);
325ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     return sr_isError(res) ? (-1) : 0;
326ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
327ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
328ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  else
329ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#    error Unknown OS
330ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  endif
331ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
332ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
333ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#undef TRANSLATE_TO_vg_stat
334ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
335ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
336ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownLong VG_(fsize) ( Int fd )
337ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
338ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   struct vg_stat buf;
339ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int res = VG_(fstat)( fd, &buf );
340ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return (res == -1) ? (-1LL) : buf.size;
341ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
342ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
343ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownBool VG_(is_dir) ( const HChar* f )
344ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
345ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   struct vg_stat buf;
346ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SysRes res = VG_(stat)(f, &buf);
347ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return sr_isError(res) ? False
348ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      : VKI_S_ISDIR(buf.mode) ? True : False;
349ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
350ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
351ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownSysRes VG_(dup) ( Int oldfd )
352ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
353ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return VG_(do_syscall1)(__NR_dup, oldfd);
354ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
355ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
356ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownSysRes VG_(dup2) ( Int oldfd, Int newfd )
357ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
358b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#  if defined(VGO_linux) || defined(VGO_darwin)
359ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return VG_(do_syscall2)(__NR_dup2, oldfd, newfd);
360ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  else
361ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#    error Unknown OS
362ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  endif
363ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
364ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
365ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Returns -1 on error. */
366ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownInt VG_(fcntl) ( Int fd, Int cmd, Addr arg )
367ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
368b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#  if defined(VGO_linux)
369ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SysRes res = VG_(do_syscall3)(__NR_fcntl, fd, cmd, arg);
370ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  elif defined(VGO_darwin)
371ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SysRes res = VG_(do_syscall3)(__NR_fcntl_nocancel, fd, cmd, arg);
372ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  else
373ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#    error "Unknown OS"
374ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  endif
375ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return sr_isError(res) ? -1 : sr_Res(res);
376ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
377ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
378ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownInt VG_(rename) ( const Char* old_name, const Char* new_name )
379ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
380ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SysRes res = VG_(do_syscall2)(__NR_rename, (UWord)old_name, (UWord)new_name);
381ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return sr_isError(res) ? (-1) : 0;
382ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
383ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
384ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownInt VG_(unlink) ( const Char* file_name )
385ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
386ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SysRes res = VG_(do_syscall1)(__NR_unlink, (UWord)file_name);
387ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return sr_isError(res) ? (-1) : 0;
388ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
389ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
390ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* The working directory at startup.  AIX doesn't provide an easy
391ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   system call to do getcwd, but fortunately we don't need arbitrary
392ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   getcwd support.  All that is really needed is to note the cwd at
393ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   process startup.  Hence VG_(record_startup_wd) notes it (in a
394ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   platform dependent way) and VG_(get_startup_wd) produces the noted
395ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   value.  Hence: */
396ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic HChar startup_wd[VKI_PATH_MAX];
397ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Bool  startup_wd_acquired = False;
398ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
399ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Record the process' working directory at startup.  Is intended to
400ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   be called exactly once, at startup, before the working directory
401ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   changes.  Return True for success, False for failure, so that the
402ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   caller can bomb out suitably without creating module cycles if
403ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   there is a problem. */
404ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownBool VG_(record_startup_wd) ( void )
405ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
406ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   const Int szB = sizeof(startup_wd);
407ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(!startup_wd_acquired);
408ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(szB >= 512 && szB <= 16384/*let's say*/); /* stay sane */
409ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(memset)(startup_wd, 0, szB);
410ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  if defined(VGO_linux)
411ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Simple: just ask the kernel */
412ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   { SysRes res
413ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        = VG_(do_syscall2)(__NR_getcwd, (UWord)startup_wd, szB-1);
414ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     vg_assert(startup_wd[szB-1] == 0);
415ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     if (sr_isError(res)) {
416ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        return False;
417ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     } else {
418ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        startup_wd_acquired = True;
419ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        return True;
420ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     }
421ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
422b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#  elif defined(VGO_darwin)
423ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* We can't ask the kernel, so instead rely on launcher-*.c to
424ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tell us the startup path.  Note the env var is keyed to the
425ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      parent's PID, not ours, since our parent is the launcher
426ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      process. */
427ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   { Char  envvar[100];
428ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     Char* wd = NULL;
429ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     VG_(memset)(envvar, 0, sizeof(envvar));
430ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     VG_(sprintf)(envvar, "VALGRIND_STARTUP_PWD_%d_XYZZY",
431ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          (Int)VG_(getppid)());
432ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     wd = VG_(getenv)( envvar );
433ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     if (wd == NULL || (1+VG_(strlen)(wd) >= szB))
434ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        return False;
435ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     VG_(strncpy_safely)(startup_wd, wd, szB);
436ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     vg_assert(startup_wd[szB-1] == 0);
437ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     startup_wd_acquired = True;
438ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     return True;
439ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
440ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  else
441ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#    error Unknown OS
442ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  endif
443ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
444ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
445ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Copy the previously acquired startup_wd into buf[0 .. size-1],
446ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   or return False if buf isn't big enough. */
447ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownBool VG_(get_startup_wd) ( Char* buf, SizeT size )
448ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
449ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(startup_wd_acquired);
450ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(startup_wd[ sizeof(startup_wd)-1 ] == 0);
451ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (1+VG_(strlen)(startup_wd) >= size)
452ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return False;
453ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(strncpy_safely)(buf, startup_wd, size);
454ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return True;
455ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
456ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
457b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy StepanovInt    VG_(poll) (struct vki_pollfd *fds, Int nfds, Int timeout)
458b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov{
459b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   SysRes res;
460b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   res = VG_(do_syscall3)(__NR_poll, (UWord)fds, nfds, timeout);
461b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   return sr_isError(res) ? -1 : sr_Res(res);
462b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov}
463b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
464b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
465ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownInt VG_(readlink) (const Char* path, Char* buf, UInt bufsiz)
466ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
467ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SysRes res;
468ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* res = readlink( path, buf, bufsiz ); */
469ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   res = VG_(do_syscall3)(__NR_readlink, (UWord)path, (UWord)buf, bufsiz);
470ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return sr_isError(res) ? -1 : sr_Res(res);
471ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
472ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
473ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownInt VG_(getdents) (Int fd, struct vki_dirent *dirp, UInt count)
474ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
475b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#  if defined(VGO_linux)
476ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SysRes res;
477ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* res = getdents( fd, dirp, count ); */
478ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   res = VG_(do_syscall3)(__NR_getdents, fd, (UWord)dirp, count);
479ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return sr_isError(res) ? -1 : sr_Res(res);
480ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  elif defined(VGO_darwin)
481ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   I_die_here;
482ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  else
483ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#    error "Unknown OS"
484ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  endif
485ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
486ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
487ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Check accessibility of a file.  Returns zero for access granted,
488ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   nonzero otherwise. */
489ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownInt VG_(access) ( const HChar* path, Bool irusr, Bool iwusr, Bool ixusr )
490ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
491ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  if defined(VGO_linux)
492ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Very annoyingly, I cannot find any definition for R_OK et al in
493ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      the kernel interfaces.  Therefore I reluctantly resort to
494ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      hardwiring in these magic numbers that I determined by
495ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      experimentation. */
496ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  define VKI_R_OK 4
497ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  define VKI_W_OK 2
498ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  define VKI_X_OK 1
499ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  endif
500ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
501ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UWord w = (irusr ? VKI_R_OK : 0)
502ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             | (iwusr ? VKI_W_OK : 0)
503ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             | (ixusr ? VKI_X_OK : 0);
504ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SysRes res = VG_(do_syscall2)(__NR_access, (UWord)path, w);
505ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return sr_isError(res) ? 1 : 0;
506ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
507ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  if defined(VGO_linux)
508ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  undef VKI_R_OK
509ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  undef VKI_W_OK
510ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  undef VKI_X_OK
511ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  endif
512ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
513ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
514ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*
515ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Emulate the normal Unix permissions checking algorithm.
516ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
517ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   If owner matches, then use the owner permissions, else
518ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if group matches, then use the group permissions, else
519ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   use other permissions.
520ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
521ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Note that we can't deal properly with SUID/SGID.  By default
522ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   (allow_setuid == False), we refuse to run them (otherwise the
523ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   executable may misbehave if it doesn't have the permissions it
524ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   thinks it does).  However, the caller may indicate that setuid
525ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   executables are allowed, for example if we are going to exec them
526ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   but not trace into them (iow, client sys_execve when
527ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   clo_trace_children == False).
528ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
529ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   If VKI_EACCES is returned (iow, permission was refused), then
530ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   *is_setuid is set to True iff permission was refused because the
531ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   executable is setuid.
532ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
533ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* returns: 0 = success, non-0 is failure */
534ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownInt VG_(check_executable)(/*OUT*/Bool* is_setuid,
535ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          const HChar* f, Bool allow_setuid)
536ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
537ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   struct vg_stat st;
538ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SysRes res = VG_(stat)(f, &st);
539ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
540ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (is_setuid)
541ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      *is_setuid = False;
542ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
543ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sr_isError(res)) {
544ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return sr_Err(res);
545ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
546ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
547ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if ( (st.mode & (VKI_S_ISUID | VKI_S_ISGID)) && !allow_setuid ) {
548ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (is_setuid)
549ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         *is_setuid = True;
550ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return VKI_EACCES;
551ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
552ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
553ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (VG_(geteuid)() == st.uid) {
554ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!(st.mode & VKI_S_IXUSR))
555ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         return VKI_EACCES;
556ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
557ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Int grpmatch = 0;
558ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
559ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (VG_(getegid)() == st.gid)
560ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 grpmatch = 1;
561ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      else {
562ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 UInt groups[32];
563ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 Int ngrp = VG_(getgroups)(32, groups);
564ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 Int i;
565ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* ngrp will be -1 if VG_(getgroups) failed. */
566ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         for (i = 0; i < ngrp; i++) {
567ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	    if (groups[i] == st.gid) {
568ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	       grpmatch = 1;
569ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	       break;
570ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	    }
571ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
572ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
573ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
574ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (grpmatch) {
575ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 if (!(st.mode & VKI_S_IXGRP)) {
576ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            return VKI_EACCES;
577ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
578ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else if (!(st.mode & VKI_S_IXOTH)) {
579ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         return VKI_EACCES;
580ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
581ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
582ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
583ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return 0;
584ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
585ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
586b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov/* DDD: Note this moves (or at least, is believed to move) the file
587b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   pointer on Linux but doesn't on Darwin.  This inconsistency should
588b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   be fixed.  (In other words, why isn't the Linux version implemented
589b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   in terms of pread()?) */
590ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownSysRes VG_(pread) ( Int fd, void* buf, Int count, OffT offset )
591ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
592ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SysRes res;
593b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#  if defined(VGO_linux)
594ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   OffT off = VG_(lseek)( fd, offset, VKI_SEEK_SET);
595ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (off < 0)
596ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return VG_(mk_SysRes_Error)( VKI_EINVAL );
597ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   res = VG_(do_syscall3)(__NR_read, fd, (UWord)buf, count );
598ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return res;
599ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  elif defined(VGP_amd64_darwin)
600ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   res = VG_(do_syscall4)(__NR_pread_nocancel, fd, (UWord)buf, count, offset);
601ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return res;
602ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  elif defined(VGP_x86_darwin)
603ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ppc32-darwin is the same, but with the args inverted */
604ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   res = VG_(do_syscall5)(__NR_pread_nocancel, fd, (UWord)buf, count,
605ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          offset & 0xffffffff, offset >> 32);
606ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return res;
607ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  else
608ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#    error "Unknown platform"
609ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  endif
610ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
611ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
612b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov/* Return the name of a directory for temporary files. */
613b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanovconst HChar *VG_(tmpdir)(void)
614b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov{
615b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   const HChar *tmpdir;
616b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
617b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   tmpdir = VG_(getenv)("TMPDIR");
618b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (tmpdir == NULL || *tmpdir == '\0') tmpdir = VG_TMPDIR;
619b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (tmpdir == NULL || *tmpdir == '\0') tmpdir = "/tmp";    /* fallback */
620b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
621b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   return tmpdir;
622b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov}
623b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
624ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Create and open (-rw------) a tmp file name incorporating said arg.
625ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Returns -1 on failure, else the fd of the file.  If fullname is
626ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   non-NULL, the file's name is written into it.  The number of bytes
627ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   written is guaranteed not to exceed 64+strlen(part_of_name). */
628ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
629ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownInt VG_(mkstemp) ( HChar* part_of_name, /*OUT*/HChar* fullname )
630ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
631ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar  buf[200];
632ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int    n, tries, fd;
633ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt   seed;
634ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SysRes sres;
635b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   const HChar *tmpdir;
636ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
637ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(part_of_name);
638ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   n = VG_(strlen)(part_of_name);
639ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(n > 0 && n < 100);
640ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
641ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   seed = (VG_(getpid)() << 9) ^ VG_(getppid)();
642ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
643b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   /* Determine sensible location for temporary files */
644b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   tmpdir = VG_(tmpdir)();
645b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
646ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tries = 0;
647ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   while (True) {
648b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      if (tries++ > 10)
649ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         return -1;
6503c9a34449a790ad8bf7b827aa85e90db8b5c08dcKenny Root      VG_(sprintf)( buf, "%s/valgrind_%s_%08x",
651b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                    tmpdir, part_of_name, VG_(random)( &seed ));
652ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (0)
653ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(printf)("VG_(mkstemp): trying: %s\n", buf);
654ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
655ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      sres = VG_(open)(buf,
656ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       VKI_O_CREAT|VKI_O_RDWR|VKI_O_EXCL|VKI_O_TRUNC,
657ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       VKI_S_IRUSR|VKI_S_IWUSR);
658b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      if (sr_isError(sres)) {
659b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         VG_(umsg)("VG_(mkstemp): failed to create temp file: %s\n", buf);
660ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         continue;
661b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      }
662ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* VG_(safe_fd) doesn't return if it fails. */
663ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      fd = VG_(safe_fd)( sr_Res(sres) );
664ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (fullname)
665ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(strcpy)( fullname, buf );
666ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return fd;
667ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
668ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* NOTREACHED */
669ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
670ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
671ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
672ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* ---------------------------------------------------------------------
673ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Socket-related stuff.
674ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ------------------------------------------------------------------ */
675ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
676ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
677ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownInt parse_inet_addr_and_port ( UChar* str, UInt* ip_addr, UShort* port );
678ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
679ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
680ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownInt my_connect ( Int sockfd, struct vki_sockaddr_in* serv_addr, Int addrlen );
681ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
682ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownUInt VG_(htonl) ( UInt x )
683ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
684ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  if defined(VG_BIGENDIAN)
685ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return x;
686ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  else
687ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return
688ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      (((x >> 24) & 0xFF) << 0) | (((x >> 16) & 0xFF) << 8)
689ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      | (((x >> 8) & 0xFF) << 16) | (((x >> 0) & 0xFF) << 24);
690ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  endif
691ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
692ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
693ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownUInt VG_(ntohl) ( UInt x )
694ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
695ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  if defined(VG_BIGENDIAN)
696ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return x;
697ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  else
698ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return
699ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      (((x >> 24) & 0xFF) << 0) | (((x >> 16) & 0xFF) << 8)
700ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      | (((x >> 8) & 0xFF) << 16) | (((x >> 0) & 0xFF) << 24);
701ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  endif
702ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
703ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
704ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownUShort VG_(htons) ( UShort x )
705ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
706ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  if defined(VG_BIGENDIAN)
707ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return x;
708ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  else
709ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return
710ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      (((x >> 8) & 0xFF) << 0) | (((x >> 0) & 0xFF) << 8);
711ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  endif
712ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
713ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
714ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownUShort VG_(ntohs) ( UShort x )
715ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
716ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  if defined(VG_BIGENDIAN)
717ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return x;
718ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  else
719ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return
720ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      (((x >> 8) & 0xFF) << 0) | (((x >> 0) & 0xFF) << 8);
721ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  endif
722ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
723ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
724ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
725ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* The main function.
726ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
727ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Supplied string contains either an ip address "192.168.0.1" or
728ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   an ip address and port pair, "192.168.0.1:1500".  Parse these,
729ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   and return:
730ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     -1 if there is a parse error
731ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     -2 if no parse error, but specified host:port cannot be opened
732ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     the relevant file (socket) descriptor, otherwise.
733ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown is used.
734ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
735ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownInt VG_(connect_via_socket)( UChar* str )
736ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
737ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  if defined(VGO_linux) || defined(VGO_darwin)
738ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int sd, res;
739ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   struct vki_sockaddr_in servAddr;
740ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt   ip   = 0;
741ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UShort port = VG_CLO_DEFAULT_LOGPORT;
742ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Bool   ok   = parse_inet_addr_and_port(str, &ip, &port);
743ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (!ok)
744ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return -1;
745ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
746ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   //if (0)
747ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   //   VG_(printf)("ip = %d.%d.%d.%d, port %d\n",
748ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   //               (ip >> 24) & 0xFF, (ip >> 16) & 0xFF,
749ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   //               (ip >> 8) & 0xFF, ip & 0xFF,
750ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   //               (UInt)port );
751ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
752ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   servAddr.sin_family = VKI_AF_INET;
753ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   servAddr.sin_addr.s_addr = VG_(htonl)(ip);
754ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   servAddr.sin_port = VG_(htons)(port);
755ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
756ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* create socket */
757ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   sd = VG_(socket)(VKI_AF_INET, VKI_SOCK_STREAM, 0 /* IPPROTO_IP ? */);
758ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sd < 0) {
759ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* this shouldn't happen ... nevertheless */
760ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return -2;
761ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
762ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
763ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* connect to server */
764ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   res = my_connect(sd, &servAddr, sizeof(servAddr));
765ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (res < 0) {
766ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* connection failed */
767ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return -2;
768ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
769ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
770ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return sd;
771ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
772ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  else
773ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#    error "Unknown OS"
774ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  endif
775ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
776ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
777ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
778ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Let d = one or more digits.  Accept either:
779ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   d.d.d.d  or  d.d.d.d:d
780ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
781ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Int parse_inet_addr_and_port ( UChar* str, UInt* ip_addr, UShort* port )
782ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
783ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  define GET_CH ((*str) ? (*str++) : 0)
784ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt ipa, i, j, c, any;
785ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ipa = 0;
786ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (i = 0; i < 4; i++) {
787ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      j = 0;
788ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      any = 0;
789ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      while (1) {
790ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         c = GET_CH;
791ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (c < '0' || c > '9') break;
792ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         j = 10 * j + (int)(c - '0');
793ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         any = 1;
794ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
795ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (any == 0 || j > 255) goto syntaxerr;
796ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ipa = (ipa << 8) + j;
797ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (i <= 2 && c != '.') goto syntaxerr;
798ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
799ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (c == 0 || c == ':')
800ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      *ip_addr = ipa;
801ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (c == 0) goto ok;
802ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (c != ':') goto syntaxerr;
803ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   j = 0;
804ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   any = 0;
805ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   while (1) {
806ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      c = GET_CH;
807ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (c < '0' || c > '9') break;
808ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      j = j * 10 + (int)(c - '0');
809ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      any = 1;
810ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (j > 65535) goto syntaxerr;
811ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
812ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (any == 0 || c != 0) goto syntaxerr;
813ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (j < 1024) goto syntaxerr;
814ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   *port = (UShort)j;
815ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ok:
816ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return 1;
817ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown syntaxerr:
818ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return 0;
819ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  undef GET_CH
820ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
821ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
822ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// GrP fixme safe_fd?
823ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownInt VG_(socket) ( Int domain, Int type, Int protocol )
824ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
825ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  if defined(VGP_x86_linux) || defined(VGP_ppc32_linux) \
826b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      || defined(VGP_ppc64_linux) || defined(VGP_s390x_linux)
827ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SysRes res;
828ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UWord  args[3];
829ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   args[0] = domain;
830ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   args[1] = type;
831ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   args[2] = protocol;
832ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   res = VG_(do_syscall2)(__NR_socketcall, VKI_SYS_SOCKET, (UWord)&args);
833ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return sr_isError(res) ? -1 : sr_Res(res);
834ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
835ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  elif defined(VGP_amd64_linux) || defined(VGP_arm_linux)
836ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SysRes res;
837ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   res = VG_(do_syscall3)(__NR_socket, domain, type, protocol );
838ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return sr_isError(res) ? -1 : sr_Res(res);
839ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
840ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  elif defined(VGO_darwin)
841ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SysRes res;
842ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   res = VG_(do_syscall3)(__NR_socket, domain, type, protocol);
843ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (!sr_isError(res)) {
844ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       // Set SO_NOSIGPIPE so write() returns EPIPE instead of raising SIGPIPE
845ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       Int optval = 1;
846ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       SysRes res2;
847ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       res2 = VG_(do_syscall5)(__NR_setsockopt, sr_Res(res), VKI_SOL_SOCKET,
848ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               VKI_SO_NOSIGPIPE, (UWord)&optval,
849ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               sizeof(optval));
850ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       // ignore setsockopt() error
851ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
852ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return sr_isError(res) ? -1 : sr_Res(res);
853ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
854ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  else
855ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#    error "Unknown arch"
856ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  endif
857ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
858ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
859ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
860ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
861ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownInt my_connect ( Int sockfd, struct vki_sockaddr_in* serv_addr, Int addrlen )
862ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
863ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  if defined(VGP_x86_linux) || defined(VGP_ppc32_linux) \
864b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      || defined(VGP_ppc64_linux) || defined(VGP_s390x_linux)
865ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SysRes res;
866ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UWord  args[3];
867ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   args[0] = sockfd;
868ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   args[1] = (UWord)serv_addr;
869ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   args[2] = addrlen;
870ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   res = VG_(do_syscall2)(__NR_socketcall, VKI_SYS_CONNECT, (UWord)&args);
871ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return sr_isError(res) ? -1 : sr_Res(res);
872ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
873ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  elif defined(VGP_amd64_linux) || defined(VGP_arm_linux)
874ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SysRes res;
875ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   res = VG_(do_syscall3)(__NR_connect, sockfd, (UWord)serv_addr, addrlen);
876ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return sr_isError(res) ? -1 : sr_Res(res);
877ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
878ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  elif defined(VGO_darwin)
879ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SysRes res;
880ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   res = VG_(do_syscall3)(__NR_connect_nocancel,
881ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          sockfd, (UWord)serv_addr, addrlen);
882ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return sr_isError(res) ? -1 : sr_Res(res);
883ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
884ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  else
885ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#    error "Unknown arch"
886ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  endif
887ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
888ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
889ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownInt VG_(write_socket)( Int sd, void *msg, Int count )
890ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
891ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* This is actually send(). */
892ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
893ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* For Linux, VKI_MSG_NOSIGNAL is a request not to send SIGPIPE on
894ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      errors on stream oriented sockets when the other end breaks the
895ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      connection. The EPIPE error is still returned.
896ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
897ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      For Darwin, VG_(socket)() sets SO_NOSIGPIPE to get EPIPE instead of
898ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      SIGPIPE */
899ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
900ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  if defined(VGP_x86_linux) || defined(VGP_ppc32_linux) \
901b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      || defined(VGP_ppc64_linux) || defined(VGP_s390x_linux)
902ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SysRes res;
903ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UWord  args[4];
904ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   args[0] = sd;
905ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   args[1] = (UWord)msg;
906ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   args[2] = count;
907ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   args[3] = VKI_MSG_NOSIGNAL;
908ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   res = VG_(do_syscall2)(__NR_socketcall, VKI_SYS_SEND, (UWord)&args);
909ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return sr_isError(res) ? -1 : sr_Res(res);
910ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
911ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  elif defined(VGP_amd64_linux) || defined(VGP_arm_linux)
912ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SysRes res;
913ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   res = VG_(do_syscall6)(__NR_sendto, sd, (UWord)msg,
914ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                       count, VKI_MSG_NOSIGNAL, 0,0);
915ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return sr_isError(res) ? -1 : sr_Res(res);
916ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
917ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  elif defined(VGP_x86_darwin) || defined(VGP_amd64_darwin)
918ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SysRes res;
919ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   res = VG_(do_syscall3)(__NR_write_nocancel, sd, (UWord)msg, count);
920ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return sr_isError(res) ? -1 : sr_Res(res);
921ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
922ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  else
923ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#    error "Unknown platform"
924ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  endif
925ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
926ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
927ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownInt VG_(getsockname) ( Int sd, struct vki_sockaddr *name, Int *namelen)
928ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
929ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  if defined(VGP_x86_linux) || defined(VGP_ppc32_linux) \
930b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      || defined(VGP_ppc64_linux) || defined(VGP_s390x_linux)
931ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SysRes res;
932ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UWord  args[3];
933ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   args[0] = sd;
934ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   args[1] = (UWord)name;
935ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   args[2] = (UWord)namelen;
936ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   res = VG_(do_syscall2)(__NR_socketcall, VKI_SYS_GETSOCKNAME, (UWord)&args);
937ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return sr_isError(res) ? -1 : sr_Res(res);
938ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
939ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  elif defined(VGP_amd64_linux) || defined(VGP_arm_linux)
940ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SysRes res;
941ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   res = VG_(do_syscall3)( __NR_getsockname,
942ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           (UWord)sd, (UWord)name, (UWord)namelen );
943ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return sr_isError(res) ? -1 : sr_Res(res);
944ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
945ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  elif defined(VGO_darwin)
946ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SysRes res;
947ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   res = VG_(do_syscall3)( __NR_getsockname,
948ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           (UWord)sd, (UWord)name, (UWord)namelen );
949ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return sr_isError(res) ? -1 : sr_Res(res);
950ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
951ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  else
952ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#    error "Unknown platform"
953ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  endif
954ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
955ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
956ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownInt VG_(getpeername) ( Int sd, struct vki_sockaddr *name, Int *namelen)
957ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
958ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  if defined(VGP_x86_linux) || defined(VGP_ppc32_linux) \
959b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      || defined(VGP_ppc64_linux) || defined(VGP_s390x_linux)
960ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SysRes res;
961ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UWord  args[3];
962ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   args[0] = sd;
963ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   args[1] = (UWord)name;
964ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   args[2] = (UWord)namelen;
965ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   res = VG_(do_syscall2)(__NR_socketcall, VKI_SYS_GETPEERNAME, (UWord)&args);
966ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return sr_isError(res) ? -1 : sr_Res(res);
967ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
968ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  elif defined(VGP_amd64_linux) || defined(VGP_arm_linux)
969ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SysRes res;
970ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   res = VG_(do_syscall3)( __NR_getpeername,
971ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           (UWord)sd, (UWord)name, (UWord)namelen );
972ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return sr_isError(res) ? -1 : sr_Res(res);
973ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
974ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  elif defined(VGO_darwin)
975ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SysRes res;
976ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   res = VG_(do_syscall3)( __NR_getpeername,
977ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           (UWord)sd, (UWord)name, (UWord)namelen );
978ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return sr_isError(res) ? -1 : sr_Res(res);
979ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
980ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  else
981ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#    error "Unknown platform"
982ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  endif
983ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
984ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
985ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownInt VG_(getsockopt) ( Int sd, Int level, Int optname, void *optval,
986ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      Int *optlen)
987ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
988ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  if defined(VGP_x86_linux) || defined(VGP_ppc32_linux) \
989b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      || defined(VGP_ppc64_linux) || defined(VGP_s390x_linux)
990ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SysRes res;
991ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UWord  args[5];
992ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   args[0] = sd;
993ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   args[1] = level;
994ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   args[2] = optname;
995ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   args[3] = (UWord)optval;
996ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   args[4] = (UWord)optlen;
997ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   res = VG_(do_syscall2)(__NR_socketcall, VKI_SYS_GETSOCKOPT, (UWord)&args);
998ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return sr_isError(res) ? -1 : sr_Res(res);
999ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1000ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  elif defined(VGP_amd64_linux) || defined(VGP_arm_linux)
1001ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SysRes res;
1002ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   res = VG_(do_syscall5)( __NR_getsockopt,
1003ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           (UWord)sd, (UWord)level, (UWord)optname,
1004ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           (UWord)optval, (UWord)optlen );
1005ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return sr_isError(res) ? -1 : sr_Res(res);
1006ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1007ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  elif defined(VGO_darwin)
1008ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SysRes res;
1009ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   res = VG_(do_syscall5)( __NR_getsockopt,
1010ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           (UWord)sd, (UWord)level, (UWord)optname,
1011ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           (UWord)optval, (UWord)optlen );
1012ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return sr_isError(res) ? -1 : sr_Res(res);
1013ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1014ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  else
1015ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#    error "Unknown platform"
1016ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  endif
1017ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1018ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1019ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1020ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownChar *VG_(basename)(const Char *path)
1021ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1022ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   static Char buf[VKI_PATH_MAX];
1023ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1024ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   const Char *p, *end;
1025ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1026ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (path == NULL  ||
1027ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       0 == VG_(strcmp)(path, ""))
1028ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   {
1029ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return ".";
1030ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1031ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1032ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   p = path + VG_(strlen)(path);
1033ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   while (p > path  &&  *p == '/') {
1034ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // skip all trailing '/'
1035ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      p--;
1036ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1037ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1038ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (p == path  &&  *p == '/') return "/"; // all slashes
1039ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1040ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   end = p;
1041ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1042ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   while (p > path  &&  *p != '/') {
1043ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // now skip non '/'
1044ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      p--;
1045ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1046ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1047ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (*p == '/') p++;
1048ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1049ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(strncpy)(buf, p, end-p+1);
1050ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   buf[end-p+1] = '\0';
1051ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1052ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return buf;
1053ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1054ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1055ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1056ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownChar *VG_(dirname)(const Char *path)
1057ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1058ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   static Char buf[VKI_PATH_MAX];
1059ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1060ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   const Char *p;
1061ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1062ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (path == NULL  ||
1063ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       0 == VG_(strcmp)(path, "")  ||
1064ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       0 == VG_(strcmp)(path, "/"))
1065ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   {
1066ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return ".";
1067ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1068ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1069ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   p = path + VG_(strlen)(path);
1070ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   while (p > path  &&  *p == '/') {
1071ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // skip all trailing '/'
1072ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      p--;
1073ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1074ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1075ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   while (p > path  &&  *p != '/') {
1076ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // now skip non '/'
1077ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      p--;
1078ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1079ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1080ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (p == path) {
1081ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (*p == '/') return "/"; // all slashes
1082ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      else return "."; // no slashes
1083ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1084ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1085ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   while (p > path  &&  *p == '/') {
1086ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // skip '/' again
1087ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      p--;
1088ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1089ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1090ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(strncpy)(buf, path, p-path+1);
1091ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   buf[p-path+1] = '\0';
1092ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1093ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return buf;
1094ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1095ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1096ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1097ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--------------------------------------------------------------------*/
1098ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- end                                                          ---*/
1099ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--------------------------------------------------------------------*/
1100