Index: lib/libcasper/libcasper/service.c =================================================================== --- lib/libcasper/libcasper/service.c +++ lib/libcasper/libcasper/service.c @@ -324,6 +324,17 @@ } nvlist_destroy(nvlin); + if (nvlist_error(nvlout) != 0) { + /* + * We have to throw away the old nvlist and construct a new + * one with the error thrown on this nvlist. libnv will refuse + * to send nvlout if it's in an error state. + */ + if (error == 0) + error = nvlist_error(nvlout); + nvlist_destroy(nvlout); + nvlout = nvlist_create(flags); + } nvlist_add_number(nvlout, "error", (uint64_t)error); if (cap_send_nvlist(service_connection_get_chan(sconn), nvlout) == -1) Index: lib/libcasper/services/cap_fileargs/cap_fileargs.c =================================================================== --- lib/libcasper/services/cap_fileargs/cap_fileargs.c +++ lib/libcasper/services/cap_fileargs/cap_fileargs.c @@ -493,7 +493,7 @@ return (fd); } -static void +static int fileargs_add_cache(nvlist_t *nvlout, const nvlist_t *limits, const char *curent_name) { @@ -505,7 +505,7 @@ if ((capflags & O_CREAT) != 0) { allcached = true; - return; + return (0); } cookie = cacheposition; @@ -515,7 +515,7 @@ cacheposition = NULL; lastname = NULL; allcached = true; - return; + return (0); } /* We doing that to catch next element name. */ if (i == CACHE_SIZE) { @@ -549,9 +549,18 @@ } nvlist_add_nvlist(nvlout, fname, new); + /* + * nvlist_add_nvlist made a copy if it didn't fail. Destroying + * it also saves us from leaking the fd up above, which has been + * dup'd into the nvlout. + */ + nvlist_destroy(new); + if (nvlist_error(nvlout) != 0) + return (nvlist_error(nvlout)); } cacheposition = cookie; lastname = fname; + return (0); } static bool @@ -618,7 +627,9 @@ if (!allcached && (lastname == NULL || strcmp(name, lastname) == 0)) { nvlist_add_string(nvlout, "cmd", "cache"); - fileargs_add_cache(nvlout, limits, name); + error = fileargs_add_cache(nvlout, limits, name); + if (error != 0) + return (error); } else { nvlist_add_string(nvlout, "cmd", "lstat"); } @@ -630,7 +641,7 @@ fileargs_command_open(const nvlist_t *limits, nvlist_t *nvlin, nvlist_t *nvlout) { - int fd; + int error, fd; const char *name; if (limits == NULL) @@ -648,7 +659,11 @@ if (!allcached && (lastname == NULL || strcmp(name, lastname) == 0)) { nvlist_add_string(nvlout, "cmd", "cache"); - fileargs_add_cache(nvlout, limits, name); + error = fileargs_add_cache(nvlout, limits, name); + if (error != 0) { + close(fd); + return (error); + } } else { nvlist_add_string(nvlout, "cmd", "open"); } Index: lib/libnv/msgio.c =================================================================== --- lib/libnv/msgio.c +++ lib/libnv/msgio.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include @@ -72,6 +73,8 @@ #define PKG_MAX_SIZE (MCLBYTES / 24) #endif +void buf_drain(int sock); + static int msghdr_add_fd(struct cmsghdr *cmsg, int fd) { @@ -357,6 +360,8 @@ ret = 0; end: serrno = errno; + if (errno == EMSGSIZE) + buf_drain(sock); free(msg.msg_control); errno = serrno; return (ret); @@ -449,6 +454,36 @@ return (0); } +void +buf_drain(int sock) +{ + char buf[4096]; + fd_set fds; + struct timeval tval; + int ret; + + PJDLOG_ASSERT(sock >= 0); + + tval.tv_sec = 0; + tval.tv_usec = 0; + for (;;) { + FD_ZERO(&fds); + FD_SET(sock, &fds); + + ret = select(sock + 1, &fds, NULL, NULL, &tval); + if (ret < 0) { + if (errno == EINTR) + continue; + return; + } else if (ret == 0) { + /* Nothing to drain; bail out */ + return; + } + + (void)recv(sock, buf, sizeof(buf), 0); + } +} + int buf_recv(int sock, void *buf, size_t size) {