+ msg_len = xasprintf(&msg, "could not add %s: %s\n", name,
+ para_strerror(-ret));
+ else
+ msg_len = xasprintf(&msg, "added %s as id %u\n", name, id);
+ pass_buffer_as_shm(fd, SBD_OUTPUT, msg, msg_len);
+ free(msg);
+}
+
+/* Write input from fd to dynamically allocated buffer, but maximal 10M. */
+static int fd2buf(struct stream_cipher_context *scc, struct osl_object *obj)
+{
+ size_t max_size = 10 * 1024 * 1024;
+ int ret;
+ struct iovec iov;
+
+ obj->data = NULL;
+ obj->size = 0;
+again:
+ do {
+ ret = recv_sb(scc, SBD_BLOB_DATA, max_size, &iov);
+ } while (ret == 0);
+
+ if (ret < 0) {
+ free(obj->data);
+ obj->data = NULL;
+ obj->size = 0;
+ return ret;
+ }
+ if (iov.iov_len == 0) /* end of blob */
+ return 1;
+ if (!obj->data) {
+ obj->data = iov.iov_base;
+ obj->size = iov.iov_len;
+ } else {
+ obj->data = para_realloc(obj->data, obj->size + iov.iov_len);
+ memcpy(obj->data + obj->size, iov.iov_base, iov.iov_len);
+ obj->size += iov.iov_len;
+ free(iov.iov_base);
+ max_size -= iov.iov_len;
+ }
+ goto again;
+ return 1;
+}
+
+/*
+ * Read data from a file descriptor, and send it to the afs process.
+ *
+ * \param cc Contains the file descriptor to read data from.
+ * \param arg_obj Pointer to the arguments to \a f.
+ * \param f The callback function.
+ * \param result_handler See \ref send_callback_request.
+ * \param private_result_data See \ref send_callback_request.
+ *
+ * This function is used by the addblob commands that instruct para_server to
+ * store arbitrary data in a blob table. Input data is read and decrypted from
+ * the file descriptor given by \a cc. This data is concatenated with the
+ * buffer given by \a arg_obj, and the combined buffer is made available to the
+ * afs process via the callback method. See \ref send_callback_request for
+ * details.
+ *
+ * \return Negative on errors, the return value of the underlying call to
+ * send_callback_request() otherwise.
+ */
+static int stdin_command(struct command_context *cc, struct osl_object *arg_obj,
+ callback_function *f, callback_result_handler *result_handler,
+ void *private_result_data)
+{
+ struct osl_object query, stdin_obj;
+ int ret;
+
+ ret = send_sb(&cc->scc, NULL, 0, SBD_AWAITING_DATA, false);
+ if (ret < 0)
+ return ret;
+ ret = fd2buf(&cc->scc, &stdin_obj);
+ if (ret < 0)
+ return ret;
+ query.size = arg_obj->size + stdin_obj.size;
+ query.data = para_malloc(query.size);
+ memcpy(query.data, arg_obj->data, arg_obj->size);
+ if (stdin_obj.size > 0)
+ memcpy((char *)query.data + arg_obj->size, stdin_obj.data,
+ stdin_obj.size);
+ free(stdin_obj.data);
+ ret = send_callback_request(f, &query, result_handler, private_result_data);
+ free(query.data);
+ return ret;