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
10663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   Copyright (C) 2000-2012 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{
197663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng#  if defined(VGP_mips32_linux)
198663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   /* __NR_pipe has a strange return convention on mips32-linux. */
199663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   SysRes res = VG_(do_syscall0)(__NR_pipe);
200663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   if (!sr_isError(res)) {
201663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      fd[0] = (Int)sr_Res(res);
202663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      fd[1] = (Int)sr_ResEx(res);
203663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      return 0;
204663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   } else {
205663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      return -1;
206663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   }
207663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng#  elif defined(VGO_linux)
208ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SysRes res = VG_(do_syscall1)(__NR_pipe, (UWord)fd);
209ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return sr_isError(res) ? -1 : 0;
210ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  elif defined(VGO_darwin)
211ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* __NR_pipe is UX64, so produces a double-word result */
212ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SysRes res = VG_(do_syscall0)(__NR_pipe);
213ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (!sr_isError(res)) {
214ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      fd[0] = (Int)sr_Res(res);
215ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      fd[1] = (Int)sr_ResHI(res);
216ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
217ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return sr_isError(res) ? -1 : 0;
218ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  else
219ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#    error "Unknown OS"
220ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  endif
221ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
222ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
223b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy StepanovOff64T VG_(lseek) ( Int fd, Off64T offset, Int whence )
224ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
225b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#  if defined(VGO_linux) || defined(VGP_amd64_darwin)
226b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#  if defined(__NR__llseek)
227b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   Off64T result;
228b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   SysRes res = VG_(do_syscall5)(__NR__llseek, fd,
229b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                                 offset >> 32, offset & 0xffffffff,
230b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                                 (UWord)&result, whence);
231b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   return sr_isError(res) ? (-1) : result;
232b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#  else
233ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SysRes res = VG_(do_syscall3)(__NR_lseek, fd, offset, whence);
234b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   vg_assert(sizeof(Off64T) == sizeof(Word));
235b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   return sr_isError(res) ? (-1) : sr_Res(res);
236b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#  endif
237ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  elif defined(VGP_x86_darwin)
238ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SysRes res = VG_(do_syscall4)(__NR_lseek, fd,
239ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 offset & 0xffffffff, offset >> 32, whence);
240b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   return sr_isError(res) ? (-1) : sr_Res(res);
241ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  else
242ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#    error "Unknown plat"
243ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  endif
244ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* if you change the error-reporting conventions of this, also
245663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      change all usage points. */
246ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
247ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
248ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
249ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* stat/fstat support.  It's uggerly.  We have impedance-match into a
250ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   'struct vg_stat' in order to have a single structure that callers
251ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   can use consistently on all platforms. */
252ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
253ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define TRANSLATE_TO_vg_stat(_p_vgstat, _p_vkistat) \
254ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   do { \
255ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      (_p_vgstat)->dev        = (ULong)( (_p_vkistat)->st_dev ); \
256ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      (_p_vgstat)->ino        = (ULong)( (_p_vkistat)->st_ino ); \
257ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      (_p_vgstat)->nlink      = (ULong)( (_p_vkistat)->st_nlink ); \
258ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      (_p_vgstat)->mode       = (UInt) ( (_p_vkistat)->st_mode ); \
259ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      (_p_vgstat)->uid        = (UInt) ( (_p_vkistat)->st_uid ); \
260ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      (_p_vgstat)->gid        = (UInt) ( (_p_vkistat)->st_gid ); \
261ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      (_p_vgstat)->rdev       = (ULong)( (_p_vkistat)->st_rdev ); \
262ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      (_p_vgstat)->size       = (Long) ( (_p_vkistat)->st_size ); \
263ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      (_p_vgstat)->blksize    = (ULong)( (_p_vkistat)->st_blksize ); \
264ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      (_p_vgstat)->blocks     = (ULong)( (_p_vkistat)->st_blocks ); \
265ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      (_p_vgstat)->atime      = (ULong)( (_p_vkistat)->st_atime ); \
266ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      (_p_vgstat)->atime_nsec = (ULong)( (_p_vkistat)->st_atime_nsec ); \
267ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      (_p_vgstat)->mtime      = (ULong)( (_p_vkistat)->st_mtime ); \
268ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      (_p_vgstat)->mtime_nsec = (ULong)( (_p_vkistat)->st_mtime_nsec ); \
269ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      (_p_vgstat)->ctime      = (ULong)( (_p_vkistat)->st_ctime ); \
270ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      (_p_vgstat)->ctime_nsec = (ULong)( (_p_vkistat)->st_ctime_nsec ); \
271ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } while (0)
272ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
273ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownSysRes VG_(stat) ( const Char* file_name, struct vg_stat* vgbuf )
274ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
275ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SysRes res;
276ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(memset)(vgbuf, 0, sizeof(*vgbuf));
277ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
278ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  if defined(VGO_linux) || defined(VGO_darwin)
279ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* First try with stat64.  If that doesn't work out, fall back to
280ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      the vanilla version. */
281ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  if defined(__NR_stat64)
282ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   { struct vki_stat64 buf64;
283ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     res = VG_(do_syscall2)(__NR_stat64, (UWord)file_name, (UWord)&buf64);
284ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     if (!(sr_isError(res) && sr_Err(res) == VKI_ENOSYS)) {
285ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        /* Success, or any failure except ENOSYS */
286ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        if (!sr_isError(res))
287ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           TRANSLATE_TO_vg_stat(vgbuf, &buf64);
288ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        return res;
289ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     }
290ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
291ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  endif /* defined(__NR_stat64) */
292ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   { struct vki_stat buf;
293ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     res = VG_(do_syscall2)(__NR_stat, (UWord)file_name, (UWord)&buf);
294ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     if (!sr_isError(res))
295ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        TRANSLATE_TO_vg_stat(vgbuf, &buf);
296ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     return res;
297ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
298ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
299ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  else
300ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#    error Unknown OS
301ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  endif
302ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
303ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
304ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownInt VG_(fstat) ( Int fd, struct vg_stat* vgbuf )
305ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
306ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SysRes res;
307ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(memset)(vgbuf, 0, sizeof(*vgbuf));
308ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
309ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  if defined(VGO_linux)  ||  defined(VGO_darwin)
310ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* First try with fstat64.  If that doesn't work out, fall back to
311ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      the vanilla version. */
312ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  if defined(__NR_fstat64)
313ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   { struct vki_stat64 buf64;
314ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     res = VG_(do_syscall2)(__NR_fstat64, (UWord)fd, (UWord)&buf64);
315ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     if (!(sr_isError(res) && sr_Err(res) == VKI_ENOSYS)) {
316ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        /* Success, or any failure except ENOSYS */
317ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        if (!sr_isError(res))
318ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           TRANSLATE_TO_vg_stat(vgbuf, &buf64);
319ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        return sr_isError(res) ? (-1) : 0;
320ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     }
321ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
322ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  endif /* if defined(__NR_fstat64) */
323ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   { struct vki_stat buf;
324ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     res = VG_(do_syscall2)(__NR_fstat, (UWord)fd, (UWord)&buf);
325ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     if (!sr_isError(res))
326ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        TRANSLATE_TO_vg_stat(vgbuf, &buf);
327ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     return sr_isError(res) ? (-1) : 0;
328ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
329ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
330ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  else
331ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#    error Unknown OS
332ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  endif
333ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
334ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
335ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#undef TRANSLATE_TO_vg_stat
336ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
337ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
338ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownLong VG_(fsize) ( Int fd )
339ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
340ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   struct vg_stat buf;
341ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int res = VG_(fstat)( fd, &buf );
342ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return (res == -1) ? (-1LL) : buf.size;
343ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
344ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
345ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownBool VG_(is_dir) ( const HChar* f )
346ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
347ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   struct vg_stat buf;
348ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SysRes res = VG_(stat)(f, &buf);
349ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return sr_isError(res) ? False
350ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      : VKI_S_ISDIR(buf.mode) ? True : False;
351ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
352ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
353ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownSysRes VG_(dup) ( Int oldfd )
354ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
355ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return VG_(do_syscall1)(__NR_dup, oldfd);
356ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
357ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
358ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownSysRes VG_(dup2) ( Int oldfd, Int newfd )
359ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
360b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#  if defined(VGO_linux) || defined(VGO_darwin)
361ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return VG_(do_syscall2)(__NR_dup2, oldfd, newfd);
362ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  else
363ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#    error Unknown OS
364ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  endif
365ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
366ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
367ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Returns -1 on error. */
368ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownInt VG_(fcntl) ( Int fd, Int cmd, Addr arg )
369ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
370b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#  if defined(VGO_linux)
371ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SysRes res = VG_(do_syscall3)(__NR_fcntl, fd, cmd, arg);
372ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  elif defined(VGO_darwin)
373ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SysRes res = VG_(do_syscall3)(__NR_fcntl_nocancel, fd, cmd, arg);
374ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  else
375ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#    error "Unknown OS"
376ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  endif
377ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return sr_isError(res) ? -1 : sr_Res(res);
378ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
379ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
380ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownInt VG_(rename) ( const Char* old_name, const Char* new_name )
381ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
382ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SysRes res = VG_(do_syscall2)(__NR_rename, (UWord)old_name, (UWord)new_name);
383ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return sr_isError(res) ? (-1) : 0;
384ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
385ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
386ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownInt VG_(unlink) ( const Char* file_name )
387ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
388ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SysRes res = VG_(do_syscall1)(__NR_unlink, (UWord)file_name);
389ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return sr_isError(res) ? (-1) : 0;
390ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
391ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
392ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* The working directory at startup.  AIX doesn't provide an easy
393ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   system call to do getcwd, but fortunately we don't need arbitrary
394ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   getcwd support.  All that is really needed is to note the cwd at
395ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   process startup.  Hence VG_(record_startup_wd) notes it (in a
396ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   platform dependent way) and VG_(get_startup_wd) produces the noted
397ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   value.  Hence: */
398ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic HChar startup_wd[VKI_PATH_MAX];
399ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Bool  startup_wd_acquired = False;
400ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
401ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Record the process' working directory at startup.  Is intended to
402ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   be called exactly once, at startup, before the working directory
403ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   changes.  Return True for success, False for failure, so that the
404ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   caller can bomb out suitably without creating module cycles if
405ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   there is a problem. */
406ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownBool VG_(record_startup_wd) ( void )
407ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
408ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   const Int szB = sizeof(startup_wd);
409ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(!startup_wd_acquired);
410ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(szB >= 512 && szB <= 16384/*let's say*/); /* stay sane */
411ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(memset)(startup_wd, 0, szB);
412ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  if defined(VGO_linux)
413ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Simple: just ask the kernel */
414ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   { SysRes res
415ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        = VG_(do_syscall2)(__NR_getcwd, (UWord)startup_wd, szB-1);
416ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     vg_assert(startup_wd[szB-1] == 0);
417ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     if (sr_isError(res)) {
418ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        return False;
419ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     } else {
420ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        startup_wd_acquired = True;
421ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        return True;
422ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     }
423ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
424b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#  elif defined(VGO_darwin)
425ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* We can't ask the kernel, so instead rely on launcher-*.c to
426ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tell us the startup path.  Note the env var is keyed to the
427ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      parent's PID, not ours, since our parent is the launcher
428ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      process. */
429ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   { Char  envvar[100];
430ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     Char* wd = NULL;
431ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     VG_(memset)(envvar, 0, sizeof(envvar));
432ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     VG_(sprintf)(envvar, "VALGRIND_STARTUP_PWD_%d_XYZZY",
433ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          (Int)VG_(getppid)());
434ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     wd = VG_(getenv)( envvar );
435ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     if (wd == NULL || (1+VG_(strlen)(wd) >= szB))
436ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        return False;
437ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     VG_(strncpy_safely)(startup_wd, wd, szB);
438ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     vg_assert(startup_wd[szB-1] == 0);
439ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     startup_wd_acquired = True;
440ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     return True;
441ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
442ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  else
443ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#    error Unknown OS
444ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  endif
445ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
446ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
447ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Copy the previously acquired startup_wd into buf[0 .. size-1],
448ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   or return False if buf isn't big enough. */
449ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownBool VG_(get_startup_wd) ( Char* buf, SizeT size )
450ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
451ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(startup_wd_acquired);
452ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(startup_wd[ sizeof(startup_wd)-1 ] == 0);
453ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (1+VG_(strlen)(startup_wd) >= size)
454ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return False;
455ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(strncpy_safely)(buf, startup_wd, size);
456ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return True;
457ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
458ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
459663860b1408516d02ebfcb3a9999a134e6cfb223Ben ChengInt VG_(poll) (struct vki_pollfd *fds, Int nfds, Int timeout)
460b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov{
461b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   SysRes res;
462663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng#  if defined(VGO_linux)
463b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   res = VG_(do_syscall3)(__NR_poll, (UWord)fds, nfds, timeout);
464663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng#  elif defined(VGO_darwin)
465663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   res = VG_(do_syscall3)(__NR_poll_nocancel, (UWord)fds, nfds, timeout);
466663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng#  else
467663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng#    error "Unknown OS"
468663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng#  endif
469b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   return sr_isError(res) ? -1 : sr_Res(res);
470b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov}
471b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
472b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
473ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownInt VG_(readlink) (const Char* path, Char* buf, UInt bufsiz)
474ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
475ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SysRes res;
476ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* res = readlink( path, buf, bufsiz ); */
477ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   res = VG_(do_syscall3)(__NR_readlink, (UWord)path, (UWord)buf, bufsiz);
478ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return sr_isError(res) ? -1 : sr_Res(res);
479ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
480ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
481ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownInt VG_(getdents) (Int fd, struct vki_dirent *dirp, UInt count)
482ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
483b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#  if defined(VGO_linux)
484ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SysRes res;
485ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* res = getdents( fd, dirp, count ); */
486ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   res = VG_(do_syscall3)(__NR_getdents, fd, (UWord)dirp, count);
487ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return sr_isError(res) ? -1 : sr_Res(res);
488ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  elif defined(VGO_darwin)
489ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   I_die_here;
490ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  else
491ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#    error "Unknown OS"
492ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  endif
493ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
494ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
495ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Check accessibility of a file.  Returns zero for access granted,
496ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   nonzero otherwise. */
497ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownInt VG_(access) ( const HChar* path, Bool irusr, Bool iwusr, Bool ixusr )
498ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
499ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  if defined(VGO_linux)
500ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Very annoyingly, I cannot find any definition for R_OK et al in
501ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      the kernel interfaces.  Therefore I reluctantly resort to
502ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      hardwiring in these magic numbers that I determined by
503ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      experimentation. */
504ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  define VKI_R_OK 4
505ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  define VKI_W_OK 2
506ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  define VKI_X_OK 1
507ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  endif
508ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
509ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UWord w = (irusr ? VKI_R_OK : 0)
510ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             | (iwusr ? VKI_W_OK : 0)
511ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             | (ixusr ? VKI_X_OK : 0);
512ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SysRes res = VG_(do_syscall2)(__NR_access, (UWord)path, w);
513ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return sr_isError(res) ? 1 : 0;
514ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
515ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  if defined(VGO_linux)
516ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  undef VKI_R_OK
517ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  undef VKI_W_OK
518ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  undef VKI_X_OK
519ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  endif
520ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
521ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
522ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*
523ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Emulate the normal Unix permissions checking algorithm.
524ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
525ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   If owner matches, then use the owner permissions, else
526ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if group matches, then use the group permissions, else
527ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   use other permissions.
528ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
529ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Note that we can't deal properly with SUID/SGID.  By default
530ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   (allow_setuid == False), we refuse to run them (otherwise the
531ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   executable may misbehave if it doesn't have the permissions it
532ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   thinks it does).  However, the caller may indicate that setuid
533ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   executables are allowed, for example if we are going to exec them
534ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   but not trace into them (iow, client sys_execve when
535ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   clo_trace_children == False).
536ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
537ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   If VKI_EACCES is returned (iow, permission was refused), then
538ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   *is_setuid is set to True iff permission was refused because the
539ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   executable is setuid.
540ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
541ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* returns: 0 = success, non-0 is failure */
542ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownInt VG_(check_executable)(/*OUT*/Bool* is_setuid,
543ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          const HChar* f, Bool allow_setuid)
544ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
545ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   struct vg_stat st;
546ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SysRes res = VG_(stat)(f, &st);
547ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
548ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (is_setuid)
549ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      *is_setuid = False;
550ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
551ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sr_isError(res)) {
552ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return sr_Err(res);
553ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
554ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
555ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if ( (st.mode & (VKI_S_ISUID | VKI_S_ISGID)) && !allow_setuid ) {
556ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (is_setuid)
557ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         *is_setuid = True;
558ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return VKI_EACCES;
559ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
560ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
561ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (VG_(geteuid)() == st.uid) {
562ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!(st.mode & VKI_S_IXUSR))
563ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         return VKI_EACCES;
564ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
565ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Int grpmatch = 0;
566ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
567ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (VG_(getegid)() == st.gid)
568ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 grpmatch = 1;
569ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      else {
570ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 UInt groups[32];
571ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 Int ngrp = VG_(getgroups)(32, groups);
572ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 Int i;
573ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* ngrp will be -1 if VG_(getgroups) failed. */
574ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         for (i = 0; i < ngrp; i++) {
575ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	    if (groups[i] == st.gid) {
576ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	       grpmatch = 1;
577ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	       break;
578ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	    }
579ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
580ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
581ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
582ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (grpmatch) {
583ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 if (!(st.mode & VKI_S_IXGRP)) {
584ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            return VKI_EACCES;
585ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
586ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else if (!(st.mode & VKI_S_IXOTH)) {
587ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         return VKI_EACCES;
588ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
589ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
590ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
591ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return 0;
592ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
593ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
594ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownSysRes VG_(pread) ( Int fd, void* buf, Int count, OffT offset )
595ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
596ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SysRes res;
597663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   // on 32 bits platforms, we receive a 32 bits OffT but
598663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   // we must extend it to pass a long long 64 bits.
599663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng#  if defined(VGP_x86_linux)
600663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   vg_assert(sizeof(OffT) == 4);
601663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   res = VG_(do_syscall5)(__NR_pread64, fd, (UWord)buf, count,
602663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                          offset, 0); // Little endian long long
603663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   return res;
604663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng#  elif defined(VGP_arm_linux)
605663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   vg_assert(sizeof(OffT) == 4);
606663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   res = VG_(do_syscall5)(__NR_pread64, fd, (UWord)buf, count,
607663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                          0, offset); // Big endian long long
608663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   return res;
609663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng#  elif defined(VGP_ppc32_linux)
610663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   vg_assert(sizeof(OffT) == 4);
611663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   res = VG_(do_syscall6)(__NR_pread64, fd, (UWord)buf, count,
612663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                          0, // Padding needed on PPC32
613663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                          0, offset); // Big endian long long
614663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   return res;
615663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng#  elif defined(VGP_mips32_linux) && VKI_LITTLE_ENDIAN
616663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   vg_assert(sizeof(OffT) == 4);
617663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   res = VG_(do_syscall6)(__NR_pread64, fd, (UWord)buf, count,
618663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                          0, offset, 0);
619663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   return res;
620663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng#  elif defined(VGP_mips32_linux) && VKI_BIG_ENDIAN
621663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   vg_assert(sizeof(OffT) == 4);
622663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   res = VG_(do_syscall6)(__NR_pread64, fd, (UWord)buf, count,
623663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                          0, 0, offset);
624663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   return res;
625663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng#  elif defined(VGP_amd64_linux) \
626663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      || defined(VGP_ppc64_linux) || defined(VGP_s390x_linux)
627663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   res = VG_(do_syscall4)(__NR_pread64, fd, (UWord)buf, count, offset);
628ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return res;
629ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  elif defined(VGP_amd64_darwin)
630663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   vg_assert(sizeof(OffT) == 8);
631ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   res = VG_(do_syscall4)(__NR_pread_nocancel, fd, (UWord)buf, count, offset);
632ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return res;
633ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  elif defined(VGP_x86_darwin)
634663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   vg_assert(sizeof(OffT) == 8);
635ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   res = VG_(do_syscall5)(__NR_pread_nocancel, fd, (UWord)buf, count,
636ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          offset & 0xffffffff, offset >> 32);
637ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return res;
638ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  else
639ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#    error "Unknown platform"
640ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  endif
641ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
642ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
643b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov/* Return the name of a directory for temporary files. */
644b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanovconst HChar *VG_(tmpdir)(void)
645b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov{
646b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   const HChar *tmpdir;
647b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
648b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   tmpdir = VG_(getenv)("TMPDIR");
649b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (tmpdir == NULL || *tmpdir == '\0') tmpdir = VG_TMPDIR;
650b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (tmpdir == NULL || *tmpdir == '\0') tmpdir = "/tmp";    /* fallback */
651b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
652b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   return tmpdir;
653b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov}
654b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
655ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Create and open (-rw------) a tmp file name incorporating said arg.
656ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Returns -1 on failure, else the fd of the file.  If fullname is
657ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   non-NULL, the file's name is written into it.  The number of bytes
658ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   written is guaranteed not to exceed 64+strlen(part_of_name). */
659ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
660ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownInt VG_(mkstemp) ( HChar* part_of_name, /*OUT*/HChar* fullname )
661ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
662ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar  buf[200];
663ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int    n, tries, fd;
664ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt   seed;
665ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SysRes sres;
666b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   const HChar *tmpdir;
667ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
668ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(part_of_name);
669ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   n = VG_(strlen)(part_of_name);
670ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(n > 0 && n < 100);
671ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
672ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   seed = (VG_(getpid)() << 9) ^ VG_(getppid)();
673ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
674b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   /* Determine sensible location for temporary files */
675b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   tmpdir = VG_(tmpdir)();
676b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
677ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tries = 0;
678ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   while (True) {
679b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      if (tries++ > 10)
680ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         return -1;
6813c9a34449a790ad8bf7b827aa85e90db8b5c08dcKenny Root      VG_(sprintf)( buf, "%s/valgrind_%s_%08x",
682b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                    tmpdir, part_of_name, VG_(random)( &seed ));
683ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (0)
684ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(printf)("VG_(mkstemp): trying: %s\n", buf);
685ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
686ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      sres = VG_(open)(buf,
687ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       VKI_O_CREAT|VKI_O_RDWR|VKI_O_EXCL|VKI_O_TRUNC,
688ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       VKI_S_IRUSR|VKI_S_IWUSR);
689b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      if (sr_isError(sres)) {
690b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         VG_(umsg)("VG_(mkstemp): failed to create temp file: %s\n", buf);
691ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         continue;
692b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      }
693ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* VG_(safe_fd) doesn't return if it fails. */
694ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      fd = VG_(safe_fd)( sr_Res(sres) );
695ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (fullname)
696ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(strcpy)( fullname, buf );
697ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return fd;
698ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
699ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* NOTREACHED */
700ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
701ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
702ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
703ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* ---------------------------------------------------------------------
704ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Socket-related stuff.
705ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ------------------------------------------------------------------ */
706ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
707ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
708ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownInt parse_inet_addr_and_port ( UChar* str, UInt* ip_addr, UShort* port );
709ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
710ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
711ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownInt my_connect ( Int sockfd, struct vki_sockaddr_in* serv_addr, Int addrlen );
712ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
713ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownUInt VG_(htonl) ( UInt x )
714ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
715ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  if defined(VG_BIGENDIAN)
716ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return x;
717ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  else
718ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return
719ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      (((x >> 24) & 0xFF) << 0) | (((x >> 16) & 0xFF) << 8)
720ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      | (((x >> 8) & 0xFF) << 16) | (((x >> 0) & 0xFF) << 24);
721ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  endif
722ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
723ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
724ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownUInt VG_(ntohl) ( UInt x )
725ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
726ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  if defined(VG_BIGENDIAN)
727ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return x;
728ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  else
729ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return
730ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      (((x >> 24) & 0xFF) << 0) | (((x >> 16) & 0xFF) << 8)
731ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      | (((x >> 8) & 0xFF) << 16) | (((x >> 0) & 0xFF) << 24);
732ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  endif
733ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
734ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
735ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownUShort VG_(htons) ( UShort x )
736ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
737ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  if defined(VG_BIGENDIAN)
738ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return x;
739ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  else
740ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return
741ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      (((x >> 8) & 0xFF) << 0) | (((x >> 0) & 0xFF) << 8);
742ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  endif
743ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
744ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
745ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownUShort VG_(ntohs) ( UShort x )
746ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
747ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  if defined(VG_BIGENDIAN)
748ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return x;
749ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  else
750ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return
751ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      (((x >> 8) & 0xFF) << 0) | (((x >> 0) & 0xFF) << 8);
752ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  endif
753ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
754ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
755ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
756ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* The main function.
757ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
758ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Supplied string contains either an ip address "192.168.0.1" or
759ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   an ip address and port pair, "192.168.0.1:1500".  Parse these,
760ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   and return:
761ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     -1 if there is a parse error
762ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     -2 if no parse error, but specified host:port cannot be opened
763ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     the relevant file (socket) descriptor, otherwise.
764ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown is used.
765ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
766ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownInt VG_(connect_via_socket)( UChar* str )
767ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
768ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  if defined(VGO_linux) || defined(VGO_darwin)
769ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int sd, res;
770ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   struct vki_sockaddr_in servAddr;
771ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt   ip   = 0;
772ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UShort port = VG_CLO_DEFAULT_LOGPORT;
773ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Bool   ok   = parse_inet_addr_and_port(str, &ip, &port);
774ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (!ok)
775ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return -1;
776ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
777ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   //if (0)
778ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   //   VG_(printf)("ip = %d.%d.%d.%d, port %d\n",
779ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   //               (ip >> 24) & 0xFF, (ip >> 16) & 0xFF,
780ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   //               (ip >> 8) & 0xFF, ip & 0xFF,
781ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   //               (UInt)port );
782ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
783ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   servAddr.sin_family = VKI_AF_INET;
784ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   servAddr.sin_addr.s_addr = VG_(htonl)(ip);
785ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   servAddr.sin_port = VG_(htons)(port);
786ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
787ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* create socket */
788ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   sd = VG_(socket)(VKI_AF_INET, VKI_SOCK_STREAM, 0 /* IPPROTO_IP ? */);
789ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sd < 0) {
790ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* this shouldn't happen ... nevertheless */
791ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return -2;
792ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
793ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
794ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* connect to server */
795ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   res = my_connect(sd, &servAddr, sizeof(servAddr));
796ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (res < 0) {
797ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* connection failed */
798ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return -2;
799ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
800ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
801ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return sd;
802ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
803ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  else
804ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#    error "Unknown OS"
805ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  endif
806ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
807ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
808ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
809ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Let d = one or more digits.  Accept either:
810ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   d.d.d.d  or  d.d.d.d:d
811ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
812ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Int parse_inet_addr_and_port ( UChar* str, UInt* ip_addr, UShort* port )
813ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
814ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  define GET_CH ((*str) ? (*str++) : 0)
815ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt ipa, i, j, c, any;
816ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ipa = 0;
817ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (i = 0; i < 4; i++) {
818ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      j = 0;
819ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      any = 0;
820ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      while (1) {
821ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         c = GET_CH;
822ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (c < '0' || c > '9') break;
823ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         j = 10 * j + (int)(c - '0');
824ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         any = 1;
825ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
826ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (any == 0 || j > 255) goto syntaxerr;
827ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ipa = (ipa << 8) + j;
828ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (i <= 2 && c != '.') goto syntaxerr;
829ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
830ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (c == 0 || c == ':')
831ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      *ip_addr = ipa;
832ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (c == 0) goto ok;
833ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (c != ':') goto syntaxerr;
834ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   j = 0;
835ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   any = 0;
836ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   while (1) {
837ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      c = GET_CH;
838ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (c < '0' || c > '9') break;
839ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      j = j * 10 + (int)(c - '0');
840ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      any = 1;
841ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (j > 65535) goto syntaxerr;
842ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
843ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (any == 0 || c != 0) goto syntaxerr;
844ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (j < 1024) goto syntaxerr;
845ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   *port = (UShort)j;
846ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ok:
847ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return 1;
848ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown syntaxerr:
849ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return 0;
850ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  undef GET_CH
851ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
852ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
853ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// GrP fixme safe_fd?
854ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownInt VG_(socket) ( Int domain, Int type, Int protocol )
855ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
856ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  if defined(VGP_x86_linux) || defined(VGP_ppc32_linux) \
857b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      || defined(VGP_ppc64_linux) || defined(VGP_s390x_linux)
858ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SysRes res;
859ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UWord  args[3];
860ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   args[0] = domain;
861ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   args[1] = type;
862ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   args[2] = protocol;
863ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   res = VG_(do_syscall2)(__NR_socketcall, VKI_SYS_SOCKET, (UWord)&args);
864ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return sr_isError(res) ? -1 : sr_Res(res);
865ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
866663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng#  elif defined(VGP_amd64_linux) || defined(VGP_arm_linux) \
867663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng        || defined(VGP_mips32_linux)
868ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SysRes res;
869ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   res = VG_(do_syscall3)(__NR_socket, domain, type, protocol );
870ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return sr_isError(res) ? -1 : sr_Res(res);
871ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
872ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  elif defined(VGO_darwin)
873ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SysRes res;
874ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   res = VG_(do_syscall3)(__NR_socket, domain, type, protocol);
875ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (!sr_isError(res)) {
876ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       // Set SO_NOSIGPIPE so write() returns EPIPE instead of raising SIGPIPE
877ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       Int optval = 1;
878ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       SysRes res2;
879ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       res2 = VG_(do_syscall5)(__NR_setsockopt, sr_Res(res), VKI_SOL_SOCKET,
880ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               VKI_SO_NOSIGPIPE, (UWord)&optval,
881ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               sizeof(optval));
882ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       // ignore setsockopt() error
883ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
884ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return sr_isError(res) ? -1 : sr_Res(res);
885ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
886ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  else
887ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#    error "Unknown arch"
888ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  endif
889ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
890ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
891ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
892ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
893ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownInt my_connect ( Int sockfd, struct vki_sockaddr_in* serv_addr, Int addrlen )
894ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
895ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  if defined(VGP_x86_linux) || defined(VGP_ppc32_linux) \
896b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      || defined(VGP_ppc64_linux) || defined(VGP_s390x_linux)
897ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SysRes res;
898ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UWord  args[3];
899ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   args[0] = sockfd;
900ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   args[1] = (UWord)serv_addr;
901ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   args[2] = addrlen;
902ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   res = VG_(do_syscall2)(__NR_socketcall, VKI_SYS_CONNECT, (UWord)&args);
903ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return sr_isError(res) ? -1 : sr_Res(res);
904ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
905663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng#  elif defined(VGP_amd64_linux) || defined(VGP_arm_linux) \
906663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng        || defined(VGP_mips32_linux)
907ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SysRes res;
908ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   res = VG_(do_syscall3)(__NR_connect, sockfd, (UWord)serv_addr, addrlen);
909ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return sr_isError(res) ? -1 : sr_Res(res);
910ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
911ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  elif defined(VGO_darwin)
912ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SysRes res;
913ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   res = VG_(do_syscall3)(__NR_connect_nocancel,
914ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          sockfd, (UWord)serv_addr, addrlen);
915ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return sr_isError(res) ? -1 : sr_Res(res);
916ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
917ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  else
918ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#    error "Unknown arch"
919ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  endif
920ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
921ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
922ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownInt VG_(write_socket)( Int sd, void *msg, Int count )
923ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
924ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* This is actually send(). */
925ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
926ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* For Linux, VKI_MSG_NOSIGNAL is a request not to send SIGPIPE on
927ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      errors on stream oriented sockets when the other end breaks the
928ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      connection. The EPIPE error is still returned.
929ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
930ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      For Darwin, VG_(socket)() sets SO_NOSIGPIPE to get EPIPE instead of
931ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      SIGPIPE */
932ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
933ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  if defined(VGP_x86_linux) || defined(VGP_ppc32_linux) \
934b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      || defined(VGP_ppc64_linux) || defined(VGP_s390x_linux)
935ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SysRes res;
936ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UWord  args[4];
937ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   args[0] = sd;
938ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   args[1] = (UWord)msg;
939ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   args[2] = count;
940ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   args[3] = VKI_MSG_NOSIGNAL;
941ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   res = VG_(do_syscall2)(__NR_socketcall, VKI_SYS_SEND, (UWord)&args);
942ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return sr_isError(res) ? -1 : sr_Res(res);
943ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
944663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng#  elif defined(VGP_amd64_linux) || defined(VGP_arm_linux) \
945663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng        || defined(VGP_mips32_linux)
946ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SysRes res;
947ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   res = VG_(do_syscall6)(__NR_sendto, sd, (UWord)msg,
948ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                       count, VKI_MSG_NOSIGNAL, 0,0);
949ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return sr_isError(res) ? -1 : sr_Res(res);
950ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
951ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  elif defined(VGP_x86_darwin) || defined(VGP_amd64_darwin)
952ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SysRes res;
953ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   res = VG_(do_syscall3)(__NR_write_nocancel, sd, (UWord)msg, count);
954ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return sr_isError(res) ? -1 : sr_Res(res);
955ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
956ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  else
957ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#    error "Unknown platform"
958ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  endif
959ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
960ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
961ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownInt VG_(getsockname) ( Int sd, struct vki_sockaddr *name, Int *namelen)
962ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
963ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  if defined(VGP_x86_linux) || defined(VGP_ppc32_linux) \
964663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      || defined(VGP_ppc64_linux) || defined(VGP_s390x_linux) \
965663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      || defined(VGP_mips32_linux)
966ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SysRes res;
967ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UWord  args[3];
968ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   args[0] = sd;
969ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   args[1] = (UWord)name;
970ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   args[2] = (UWord)namelen;
971ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   res = VG_(do_syscall2)(__NR_socketcall, VKI_SYS_GETSOCKNAME, (UWord)&args);
972ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return sr_isError(res) ? -1 : sr_Res(res);
973ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
974ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  elif defined(VGP_amd64_linux) || defined(VGP_arm_linux)
975ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SysRes res;
976ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   res = VG_(do_syscall3)( __NR_getsockname,
977ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           (UWord)sd, (UWord)name, (UWord)namelen );
978ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return sr_isError(res) ? -1 : sr_Res(res);
979ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
980ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  elif defined(VGO_darwin)
981ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SysRes res;
982ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   res = VG_(do_syscall3)( __NR_getsockname,
983ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           (UWord)sd, (UWord)name, (UWord)namelen );
984ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return sr_isError(res) ? -1 : sr_Res(res);
985ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
986ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  else
987ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#    error "Unknown platform"
988ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  endif
989ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
990ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
991ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownInt VG_(getpeername) ( Int sd, struct vki_sockaddr *name, Int *namelen)
992ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
993ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  if defined(VGP_x86_linux) || defined(VGP_ppc32_linux) \
994663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      || defined(VGP_ppc64_linux) || defined(VGP_s390x_linux) \
995663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      || defined(VGP_mips32_linux)
996ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SysRes res;
997ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UWord  args[3];
998ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   args[0] = sd;
999ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   args[1] = (UWord)name;
1000ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   args[2] = (UWord)namelen;
1001ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   res = VG_(do_syscall2)(__NR_socketcall, VKI_SYS_GETPEERNAME, (UWord)&args);
1002ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return sr_isError(res) ? -1 : sr_Res(res);
1003ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1004ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  elif defined(VGP_amd64_linux) || defined(VGP_arm_linux)
1005ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SysRes res;
1006ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   res = VG_(do_syscall3)( __NR_getpeername,
1007ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           (UWord)sd, (UWord)name, (UWord)namelen );
1008ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return sr_isError(res) ? -1 : sr_Res(res);
1009ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1010ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  elif defined(VGO_darwin)
1011ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SysRes res;
1012ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   res = VG_(do_syscall3)( __NR_getpeername,
1013ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           (UWord)sd, (UWord)name, (UWord)namelen );
1014ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return sr_isError(res) ? -1 : sr_Res(res);
1015ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1016ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  else
1017ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#    error "Unknown platform"
1018ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  endif
1019ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1020ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1021ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownInt VG_(getsockopt) ( Int sd, Int level, Int optname, void *optval,
1022ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      Int *optlen)
1023ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1024ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  if defined(VGP_x86_linux) || defined(VGP_ppc32_linux) \
1025b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      || defined(VGP_ppc64_linux) || defined(VGP_s390x_linux)
1026ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SysRes res;
1027ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UWord  args[5];
1028ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   args[0] = sd;
1029ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   args[1] = level;
1030ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   args[2] = optname;
1031ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   args[3] = (UWord)optval;
1032ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   args[4] = (UWord)optlen;
1033ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   res = VG_(do_syscall2)(__NR_socketcall, VKI_SYS_GETSOCKOPT, (UWord)&args);
1034ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return sr_isError(res) ? -1 : sr_Res(res);
1035ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1036663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng#  elif defined(VGP_amd64_linux) || defined(VGP_arm_linux) \
1037663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng        || defined(VGP_mips32_linux)
1038ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SysRes res;
1039ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   res = VG_(do_syscall5)( __NR_getsockopt,
1040ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           (UWord)sd, (UWord)level, (UWord)optname,
1041ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           (UWord)optval, (UWord)optlen );
1042ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return sr_isError(res) ? -1 : sr_Res(res);
1043ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1044ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  elif defined(VGO_darwin)
1045ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SysRes res;
1046ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   res = VG_(do_syscall5)( __NR_getsockopt,
1047ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           (UWord)sd, (UWord)level, (UWord)optname,
1048ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           (UWord)optval, (UWord)optlen );
1049ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return sr_isError(res) ? -1 : sr_Res(res);
1050ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1051ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  else
1052ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#    error "Unknown platform"
1053ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  endif
1054ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1055ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1056ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1057ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownChar *VG_(basename)(const Char *path)
1058ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1059ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   static Char buf[VKI_PATH_MAX];
1060ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1061ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   const Char *p, *end;
1062ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1063ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (path == NULL  ||
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   if (p == path  &&  *p == '/') return "/"; // all slashes
1076ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1077ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   end = p;
1078ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1079ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   while (p > path  &&  *p != '/') {
1080ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // now skip non '/'
1081ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      p--;
1082ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1083ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1084ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (*p == '/') p++;
1085ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1086ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(strncpy)(buf, p, end-p+1);
1087ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   buf[end-p+1] = '\0';
1088ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1089ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return buf;
1090ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1091ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1092ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1093ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownChar *VG_(dirname)(const Char *path)
1094ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1095ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   static Char buf[VKI_PATH_MAX];
1096ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1097ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   const Char *p;
1098ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1099ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (path == NULL  ||
1100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       0 == VG_(strcmp)(path, "")  ||
1101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       0 == VG_(strcmp)(path, "/"))
1102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   {
1103ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return ".";
1104ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   p = path + VG_(strlen)(path);
1107ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   while (p > path  &&  *p == '/') {
1108ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // skip all trailing '/'
1109ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      p--;
1110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1112ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   while (p > path  &&  *p != '/') {
1113ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // now skip non '/'
1114ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      p--;
1115ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1116ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1117ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (p == path) {
1118ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (*p == '/') return "/"; // all slashes
1119ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      else return "."; // no slashes
1120ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1121ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1122ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   while (p > path  &&  *p == '/') {
1123ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // skip '/' again
1124ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      p--;
1125ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1126ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1127ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(strncpy)(buf, path, p-path+1);
1128ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   buf[p-path+1] = '\0';
1129ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1130ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return buf;
1131ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1132ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1133ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1134ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--------------------------------------------------------------------*/
1135ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- end                                                          ---*/
1136ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--------------------------------------------------------------------*/
1137