- def _dlfunc(self, functype, funcname, realargs):
- r = self._func(functype,funcname,realargs)
- if not r:
- err = self._func('char* (*)(void)', 'dlerror', '()')
- if not err:
- err = 'dlerror said NULL!'
- else:
- err = err.string()
- raise RuntimeError("%s failed: %s" % (funcname, err))
- return r
-
- def _dlopen(self):
- if self._open is not None: return
- o = self._dlfunc('void* (*)(const char*, int)',
- 'dlopen',
- '("libfishdescriptor-donate.so.1.0", %s)' % rtld_now)
- self._open = '((void*)%s)' % o
-
- def _dlsym(self):
- if self._sym is not None: return
- self._dlopen()
- self._sym = self._dlfunc('void* (*)(void*, const char*)'
- 'dlsym',
- '(%s, "fishdescriptor_donate")' % self._open)
-
- def donate(self, path, fds):
- self._dlsym()
- r = self._func('int (*)(const char*, const int*)',
- self._sym,
- '("%s", (int[%d]){ %s, -1 })'
- % (_string_escape_for_c(path),
- len(fds) + 1,
- ', '.join(["%d" % fd for fd in fds])))
- if r:
- err = self._func('char* (*)(int)',
- strerror,
- r)
- if not err:
- err = 'strerror failed'
- else:
- err = err.string()
- raise RuntimeError("donate failed: %s" % err)
+ def _must_func(d, functype, funcname, realargs):
+ retval = d._func(functype, funcname, realargs)
+ if retval < 0:
+ errnoval = gdb.parse_and_eval('errno')
+ raise RuntimeError("%s gave errno=%d `%s'" %
+ (funcname, errnoval, od.strerror(errnoval)))
+
+ # wrappers for the syscalls that do what we want
+
+ def _sendmsg(d, carrier, control_msg):
+ iov_base = _lit_array('int', map(str,fds))
+ iov = d._make('struct iovec', {
+ 'iov_base': iov_base,
+ 'iov_len' : len(fds),
+ })
+
+ msg = d._make('struct msghdr', {
+ 'msg_iov' : _lit_addressof(iov),
+ 'msg_iovlen' : 1,
+ 'msg_control' : _lit_array('char', control_msg),
+ 'msg_controllen': len(control_msg),
+ })
+
+ d._must_func(
+ 'ssize_t (*)(int, const struct msghdr*, int flags)',
+ 'sendmsg',
+ '(%s, %s, 0)' % (carrier, _lit_addressof(msg))
+ )
+
+ def _socket(d):
+ return d._must_func(
+ 'int (*)(int, int, int)',
+ 'socket',
+ '(%d, %d, 0)' % (socket.AF_UNIX, socket.SOCK_STREAM)
+ )
+
+ def _connect(d, fd, path):
+ addr = d._make('struct sockaddr_un', {
+ 'sun_family' : _lit_integer(socket.AF_UNIX),
+ 'sun_path' : _lit_string_uncasted(path),
+ })
+
+ d._must_func(
+ 'int (*)(int, const struct sockaddr*, socklen_t)',
+ 'connect',
+ '(%d, (const struct sockaddr*)%s, sizeof(struct sockaddr_un))'
+ % (fd, _lit_addressof(addr)
+ )
+
+ def _close(d, fd):
+ d._must_func('int (*)(int)', 'close', '(%d)' % fd)
+
+ # main entrypoints
+
+ def donate(d, path, control_msg):
+ # control_msg is an array of integers being the ancillary data
+ # array ("control") for sendmsg, and hence specifies which fds
+ # to pass
+
+ carrier = None
+ errnoval = None
+ try:
+ errnoval = gdb.parse_and_eval('errno')
+ carrier = d._socket()
+ d._connect(carrier, path)
+ d._sendmsg(carrier, control_msg)
+ d._close(carrier)
+ carrier = None
+ finally:
+ if carrier is not None:
+ try: d._close(carrier)
+ except Exception: pass
+ if errnoval is not None:
+ gdb.parse_and_eval('errno = %d' % errnoval)