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