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