#include <systemd/sd-event.h>
#include <pakfire/arch.h>
+#include <pakfire/buffer.h>
#include <pakfire/cgroup.h>
#include <pakfire/env.h>
#include <pakfire/jail.h>
#endif /* ENABLE_DEBUG */
} streams;
+ // Standard Input Buffer
+ struct pakfire_buffer stdin;
+ int stdin_done;
+
// Timeout
sd_event_source* timeout;
struct pakfire_jail_exec* exec = data;
struct pakfire_jail* self = exec->jail;
ssize_t bytes_written = 0;
+ ssize_t bytes_read = 0;
// Fail if no callback is set
if (unlikely(!exec->callbacks.input)) {
goto CLOSE;
}
- // Call the callback
- bytes_written = exec->callbacks.input(self->ctx, fd, exec->callbacks.input_data);
- if (bytes_written < 0) {
- ERROR(self->ctx, "The input callback failed: %s\n", strerror(-bytes_written));
- return bytes_written;
+ for (;;) {
+ if (!exec->stdin_done) {
+ bytes_read = pakfire_buffer_fill(&exec->stdin, self->ctx,
+ exec->callbacks.input, exec->callbacks.input_data);
+ if (bytes_read < 0) {
+ ERROR(self->ctx, "The input callback failed: %s\n", strerror(-bytes_read));
+ return bytes_read;
+ }
- // Close the file descriptor if we are done reading
- } else if (bytes_written == 0) {
- goto CLOSE;
+ // If we could not read any more from the callback, we are done
+ if (bytes_read == 0)
+ exec->stdin_done = 1;
+ }
+
+ // Write buffered data to the pipe
+ bytes_written = pakfire_buffer_write(&exec->stdin, fd);
+ if (bytes_written < 0) {
+ switch (-bytes_written) {
+ case EAGAIN:
+ return 0;
+
+ default:
+ ERROR(self->ctx, "Failed to write to standard input: %s\n", strerror(-bytes_written));
+ return bytes_written;
+ }
+ }
+
+ // Close if we have read all input data and flushed the entire buffer
+ if (exec->stdin_done && pakfire_buffer_is_empty(&exec->stdin))
+ goto CLOSE;
}
return 0;
CLOSE:
+ // Close the standard input file descriptors
pakfire_jail_close_pipe(self, exec->pipes.stdin);
+ DEBUG(self->ctx, "Closed standard input\n");
+
return 0;
}
// Run a command in the jail
static int __pakfire_jail_exec(struct pakfire_jail* jail,
pakfire_jail_callback callback, void* data, int flags,
- pakfire_pty_stdin_callback stdin_callback, void* stdin_data,
+ pakfire_jail_input_callback input_callback, void* input_data,
pakfire_pty_stdout_callback stdout_callback, void* stdout_data,
char** output, size_t* output_length) {
struct pakfire_log_stream* stdout = NULL;
goto ERROR;
}
+ // Set the size for the input buffer
+ pakfire_buffer_set_max_length(&ctx.stdin, 4096);
+
// Are we running in interactive mode?
if (pakfire_jail_exec_has_flag(&ctx, PAKFIRE_JAIL_INTERACTIVE)) {
// Setup the PTY
r = pakfire_jail_setup_pipe(jail, &ctx.pipes.stdin, 0);
if (r < 0)
goto ERROR;
+
+ // Store the callback
+ ctx.callbacks.input = input_callback;
+ ctx.callbacks.input_data = input_data;
}
// Create a pipe for standard output
goto ERROR;
}
-#if 0
- // Configure the callbacks
- if (stdin_callback)
- pakfire_pty_set_stdin_callback(ctx.pty, stdin_callback, stdin_data);
-#endif
-
// Setup pipes for logging
// INFO
r = pakfire_log_stream_create(&ctx.streams.INFO, jail->ctx, pakfire_jail_INFO, jail);
int pakfire_jail_communicate(
struct pakfire_jail* jail, const char* argv[], struct pakfire_env* env, int flags,
- pakfire_pty_stdin_callback stdin_callback, void* stdin_data,
+ pakfire_jail_input_callback input_callback, void* input_data,
pakfire_pty_stdout_callback stdout_callback, void* stdout_data) {
struct pakfire_jail_command command = {
.jail = jail,
};
return __pakfire_jail_exec(jail, pakfire_jail_launch_command, &command, flags,
- stdin_callback, stdin_data, stdout_callback, stdout_data, NULL, NULL);
+ input_callback, input_data, stdout_callback, stdout_data, NULL, NULL);
}
int pakfire_jail_exec_script(struct pakfire_jail* jail,
const char* script, const size_t size, const char* args[], struct pakfire_env* env,
- pakfire_pty_stdin_callback stdin_callback, void* stdin_data,
+ pakfire_jail_input_callback input_callback, void* input_data,
pakfire_pty_stdout_callback stdout_callback, void* stdout_data) {
char path[PATH_MAX];
const char** argv = NULL;
// Run the script
r = pakfire_jail_communicate(jail, argv, env, 0,
- stdin_callback, stdin_data, stdout_callback, stdout_data);
+ input_callback, input_data, stdout_callback, stdout_data);
ERROR:
if (argv)
#ifndef PAKFIRE_JAIL_H
#define PAKFIRE_JAIL_H
+#include <pakfire/buffer.h>
#include <pakfire/cgroup.h>
#include <pakfire/env.h>
#include <pakfire/pakfire.h>
struct pakfire_jail;
+// Input callback
+typedef pakfire_buffer_input_callback pakfire_jail_input_callback;
+
int pakfire_jail_create(struct pakfire_jail** jail, struct pakfire* pakfire);
struct pakfire_jail* pakfire_jail_ref(struct pakfire_jail* jail);
int pakfire_jail_communicate(
struct pakfire_jail* jail, const char* argv[], struct pakfire_env* env, int flags,
- pakfire_pty_stdin_callback stdin_callback, void* stdin_data,
+ pakfire_jail_input_callback input_callback, void* input_data,
pakfire_log_stream_callback stdout_callback, void* stdout_data);
// Convenience functions
int pakfire_jail_exec_script(struct pakfire_jail* jail,
const char* script, const size_t size, const char* args[], struct pakfire_env* env,
- pakfire_pty_stdin_callback stdin_callback, void* stdin_data,
+ pakfire_jail_input_callback input_callback, void* input_data,
pakfire_pty_stdout_callback stdout_callback, void* stdout_data);
int pakfire_jail_shell(struct pakfire_jail* jail, struct pakfire_env* env);