int ni_process_run_and_capture_output(ni_process_t *pi, ni_buffer_t *out_buffer) { int pfd[2], rv; if (pipe(pfd) < 0) { ni_error("%s: unable to create pipe: %m", __func__); return -1; } rv = __ni_process_run(pi, pfd); if (rv < 0) { close(pfd[0]); close(pfd[1]); return rv; } close(pfd[1]); while (1) { int cnt; if (ni_buffer_tailroom(out_buffer) < 256) ni_buffer_ensure_tailroom(out_buffer, 4096); cnt = read(pfd[0], ni_buffer_tail(out_buffer), ni_buffer_tailroom(out_buffer)); if (cnt == 0) { break; } else if (cnt > 0) { out_buffer->tail += cnt; } else if (errno != EINTR) { ni_error("read error on subprocess pipe: %m"); return -1; } } while (waitpid(pi->pid, &pi->status, 0) < 0) { if (errno == EINTR) continue; ni_error("%s: waitpid returns error (%m)", __func__); return -1; } pi->pid = 0; if (pi->notify_callback) pi->notify_callback(pi); if (!ni_process_exit_status_okay(pi)) { ni_error("subprocesses exited with error"); return -1; } return rv; }
int ni_process_run_and_capture_output(ni_process_t *pi, ni_buffer_t *out_buffer) { int pfd[2], rv; if (pipe(pfd) < 0) { ni_error("%s: unable to create pipe: %m", __func__); return NI_PROCESS_FAILURE; } rv = __ni_process_run(pi, pfd); if (rv < NI_PROCESS_SUCCESS) { close(pfd[0]); close(pfd[1]); return rv; } rv = NI_PROCESS_SUCCESS; close(pfd[1]); while (1) { int cnt; if (ni_buffer_tailroom(out_buffer) < 256) ni_buffer_ensure_tailroom(out_buffer, 4096); cnt = read(pfd[0], ni_buffer_tail(out_buffer), ni_buffer_tailroom(out_buffer)); if (cnt == 0) { break; } else if (cnt > 0) { out_buffer->tail += cnt; } else if (errno != EINTR) { ni_error("read error on subprocess pipe: %m"); rv = NI_PROCESS_IOERROR; break; } } close(pfd[0]); while (waitpid(pi->pid, &pi->status, 0) < 0) { if (errno == EINTR) continue; ni_error("%s: waitpid returns error (%m)", __func__); rv = NI_PROCESS_WAITPID; } if (pi->notify_callback) pi->notify_callback(pi); if (rv != NI_PROCESS_SUCCESS) return rv; return __ni_process_run_info(pi); }
/* * Filesystem.download(path, offset, count) * */ static dbus_bool_t __ni_Testbus_Agent_Filesystem_download(ni_dbus_object_t *object, const ni_dbus_method_t *method, unsigned int argc, const ni_dbus_variant_t *argv, ni_dbus_message_t *reply, DBusError *error) { ni_dbus_variant_t res = NI_DBUS_VARIANT_INIT; const char *path; uint64_t offset; uint32_t count; dbus_bool_t rv; ni_buffer_t *bp = NULL; int fd = -1; if (argc != 3 || !ni_dbus_variant_get_string(&argv[0], &path) || path[0] != '/' || !ni_dbus_variant_get_uint64(&argv[1], &offset) || !ni_dbus_variant_get_uint32(&argv[2], &count) || count > 1024 * 1024 || offset + count < offset) return ni_dbus_error_invalid_args(error, object->path, method->name); if ((fd = open(path, O_RDONLY)) < 0) { ni_dbus_set_error_from_errno(error, errno, "unable to open file \"%s\"", path); return FALSE; } if (lseek(fd, offset, SEEK_SET) < 0) { ni_dbus_set_error_from_errno(error, errno, "seek faile"); goto out_fail; } bp = ni_buffer_new(count); while (count) { int n; n = read(fd, ni_buffer_tail(bp), ni_buffer_tailroom(bp)); if (n < 0) { ni_dbus_set_error_from_errno(error, errno, "read failed"); goto out_fail; } if (n == 0) break; ni_buffer_push_tail(bp, n); } ni_dbus_variant_init_dict(&res); ni_dbus_variant_set_byte_array(&res, ni_buffer_head(bp), ni_buffer_count(bp)); rv = ni_dbus_message_serialize_variants(reply, 1, &res, error); ni_dbus_variant_destroy(&res); ni_buffer_free(bp); close(fd); return rv; out_fail: if (fd >= 0) close(fd); return FALSE; }
/* * Connect the subprocess output to our I/O handling loop */ static void __ni_process_output_recv(ni_socket_t *sock) { ni_process_t *pi = sock->user_data; ni_buffer_t *rbuf = &sock->rbuf; int cnt; ni_assert(pi); if (ni_buffer_tailroom(rbuf) < 256) ni_buffer_ensure_tailroom(rbuf, 4096); cnt = recv(sock->__fd, ni_buffer_tail(rbuf), ni_buffer_tailroom(rbuf), MSG_DONTWAIT); if (cnt >= 0) { rbuf->tail += cnt; } else if (errno != EWOULDBLOCK) { ni_error("read error on subprocess pipe: %m"); ni_socket_deactivate(sock); } }
ni_buffer_t * ni_file_read(FILE *fp) { struct stat stb; unsigned int count, done, size; ni_buffer_t *result; if (fstat(fileno(fp), &stb) < 0) return NULL; if (S_ISREG(stb.st_mode)) { size = stb.st_size; result = ni_buffer_new_dynamic(size); if (result == NULL) return NULL; for (done = 0; done < size; done += count) { void *buffer = ni_buffer_tail(result); count = fread(buffer, 1, size - done, fp); if (count == 0) break; ni_buffer_push_tail(result, count); } } else { /* Could be a pipe or tty or socket */ result = ni_buffer_new_dynamic(4096); if (result == NULL) return NULL; while (TRUE) { void *buffer; ni_buffer_ensure_tailroom(result, 4096); buffer = ni_buffer_tail(result); count = fread(buffer, 1, ni_buffer_tailroom(result), fp); if (count == 0) break; ni_buffer_push_tail(result, count); } } if (ferror(fp)) { ni_error("%s: read error on file", __func__); ni_buffer_free(result); return NULL; } return result; }
/* * Connect the subprocess output to our I/O handling loop */ static void __ni_process_output_recv(ni_socket_t *sock) { ni_process_t *pi = sock->user_data; ni_buffer_t *rbuf = &sock->rbuf; int cnt; ni_assert(pi); /* Grow socket input buffer as needed. * NB: we may put an upper limit on how much process output we capture. * Anything beyond a few MB is insane... */ if (ni_buffer_tailroom(rbuf) < 256) ni_buffer_ensure_tailroom(rbuf, 4096); cnt = recv(sock->__fd, ni_buffer_tail(rbuf), ni_buffer_tailroom(rbuf), MSG_DONTWAIT); if (cnt >= 0) { rbuf->tail += cnt; } else if (errno != EWOULDBLOCK) { ni_error("read error on subprocess pipe: %m"); ni_socket_deactivate(sock); } }
void ni_buffer_ensure_tailroom(ni_buffer_t *bp, unsigned int min_room) { size_t new_size; if (ni_buffer_tailroom(bp) >= min_room) return; new_size = bp->size + min_room; if (bp->allocated) { bp->base = xrealloc(bp->base, new_size); } else { unsigned char *new_base; new_base = xmalloc(new_size); memcpy(new_base, bp->base, bp->size); bp->base = new_base; bp->allocated = 1; } bp->size = new_size; }
ni_iaid_map_t * ni_iaid_map_load(const char *filename) { ni_iaid_map_t *map; const char *type; ni_buffer_t buff; struct stat stb; ssize_t len; if (!(map = ni_iaid_map_new())) { ni_error("unable to allocate memory for iaid map: %m"); return NULL; } if (filename) { type = "given"; if (!ni_string_dup(&map->file, filename)) { ni_error("unable to copy %s iaid map file name (%s): %m", type, filename); goto failure; } if (!ni_iaid_map_open(map)) { ni_error("unable to open %s iaid map file name (%s): %m", type, map->file); goto failure; } } else { type = "default"; if (!ni_iaid_map_set_default_file(&map->file)) { ni_error("unable to construct %s iaid map file name: %m", type); goto failure; } if (!ni_iaid_map_open(map)) { ni_debug_readwrite("unable to open %s iaid map file name (%s): %m", type, map->file); type = "fallback"; if (!ni_iaid_map_set_fallback_file(&map->file)) { ni_error("unable to construct %s iaid map file name: %m", type); goto failure; } if (!ni_iaid_map_open(map)) { ni_error("unable to open iaid map file name (%s): %m", map->file); goto failure; } } } if (!ni_iaid_map_lock(map)) { ni_error("unable to lock %s iaid map file name (%s): %m", type, map->file); goto failure; } if (fstat(map->fd, &stb) < 0) stb.st_size = BUFSIZ; ni_buffer_init_dynamic(&buff, stb.st_size + 1); do { if (!ni_buffer_tailroom(&buff)) ni_buffer_ensure_tailroom(&buff, BUFSIZ); do { len = read(map->fd, ni_buffer_tail(&buff), ni_buffer_tailroom(&buff)); if (len > 0) ni_buffer_push_tail(&buff, len); } while (len < 0 && errno == EINTR); } while (len > 0); if (len < 0) { ni_error("unable to read %s iaid map file name (%s): %m", type, map->file); } else { map->doc = xml_document_from_buffer(&buff, map->file); ni_buffer_destroy(&buff); if (!map->doc) { map->doc = xml_document_new(); ni_warn("unable to parse %s iaid map file name (%s): %m", type, map->file); } return map; } failure: ni_iaid_map_free(map); return NULL; }