return (sizeof(buffer->data) == buffer->used);
}
-/*
- This function reads as much data as it can from the file descriptor.
- If it finds a whole line in it, it will send it to the logger and repeat the process.
- If not newline character is found, it will try to read more data until it finds one.
-*/
-static int pakfire_jail_handle_log(struct pakfire_jail* jail,
- struct pakfire_jail_exec* ctx, int priority, int fd,
- struct pakfire_log_buffer* buffer, pakfire_jail_communicate_out callback, void* data) {
- char line[BUFFER_SIZE + 1];
+static int pakfire_jail_fill_buffer(struct pakfire_jail* jail, int fd, struct pakfire_log_buffer* buffer) {
+ int r;
- // Fill up buffer from fd
- if (buffer->used < sizeof(buffer->data)) {
- ssize_t bytes_read = read(fd, buffer->data + buffer->used,
- sizeof(buffer->data) - buffer->used);
-
- // Handle errors
- if (bytes_read < 0) {
- ERROR(jail->pakfire, "Could not read from fd %d: %m\n", fd);
- return -1;
+ // Skip this if there is not space left in the buffer
+ if (buffer->used >= sizeof(buffer->data))
+ return 0;
+
+ // Fill the buffer
+ r = read(fd, buffer->data + buffer->used, sizeof(buffer->data) - buffer->used);
+
+ // Handle errors
+ if (r < 0) {
+ switch (errno) {
+ case EAGAIN:
+ case EIO:
+ break;
+
+ default:
+ return -errno;
}
- // Update buffer size
- buffer->used += bytes_read;
+ // EOF
+ } else if (r == 0) {
+ // XXX What to do here?
+
+ // Successful read
+ } else {
+ buffer->used += r;
}
- // See if we have any lines that we can write
+ return 0;
+}
+
+static int pakfire_jail_drain_buffer_with_callback(struct pakfire_jail* jail,
+ struct pakfire_log_buffer* buffer, int priority, pakfire_jail_communicate_out callback, void* data) {
+ const char* eol = NULL;
+ int r;
+
while (buffer->used) {
// Search for the end of the first line
- char* eol = memchr(buffer->data, '\n', buffer->used);
+ eol = memchr(buffer->data, '\n', buffer->used);
// No newline found
if (!eol) {
- // If the buffer is full, we send the content to the logger and try again
- // This should not happen in practise
+ // If the buffer is full, we send the entire content to make space.
if (pakfire_jail_log_buffer_is_full(buffer)) {
- DEBUG(jail->pakfire, "Logging buffer is full. Sending all content\n");
+ CTX_DEBUG(jail->ctx, "Buffer is full. Sending all content\n");
- eol = buffer->data + sizeof(buffer->data) - 1;
+ eol = buffer->data + buffer->used - 1;
- // Otherwise we might have only read parts of the output
- } else
+ // Otherwise we might have only read parts of the output...
+ } else {
break;
+ }
}
// Find the length of the string
- size_t length = eol - buffer->data + 1;
-
- // Copy the line into the buffer
- memcpy(line, buffer->data, length);
-
- // Terminate the string
- line[length] = '\0';
+ const size_t length = eol - buffer->data + 1;
- // Log the line
- if (callback) {
- int r = callback(jail->pakfire, data, priority, line, length);
- if (r) {
- ERROR(jail->pakfire, "The logging callback returned an error: %d\n", r);
- return r;
- }
+ // Call the callback
+ r = callback(jail->pakfire, data, priority, buffer->data, length);
+ if (r) {
+ CTX_ERROR(jail->ctx, "The logging callback returned an error: %d\n", r);
+ return r;
}
// Remove line from buffer
return 0;
}
+static int pakfire_jail_drain_buffer(struct pakfire_jail* jail, int fd, struct pakfire_log_buffer* buffer) {
+ int r;
+
+ // Nothing to do if the buffer is empty
+ if (!buffer->used)
+ return 0;
+
+ // Drain the buffer
+ r = write(fd, buffer->data, buffer->used);
+
+ // Handle errors
+ if (r < 0) {
+ switch (errno) {
+ case EAGAIN:
+ case EIO:
+ break;
+
+ default:
+ return -errno;
+ }
+
+ // Successful write
+ } else {
+ memmove(buffer->data, buffer->data + r, buffer->used - r);
+
+ buffer->used -= r;
+ }
+
+ return 0;
+}
+
+/*
+ This function reads as much data as it can from the file descriptor.
+ If it finds a whole line in it, it will send it to the logger and repeat the process.
+ If not newline character is found, it will try to read more data until it finds one.
+*/
+static int pakfire_jail_handle_log(struct pakfire_jail* jail, struct pakfire_jail_exec* ctx,
+ int priority, int fd, struct pakfire_log_buffer* buffer,
+ pakfire_jail_communicate_out callback, void* data) {
+ int r;
+
+ // Fill up buffer from fd
+ r = pakfire_jail_fill_buffer(jail, fd, buffer);
+ if (r)
+ return r;
+
+ // Drain the buffer
+ r = pakfire_jail_drain_buffer_with_callback(jail, buffer, priority, callback, data);
+ if (r)
+ return r;
+
+ return 0;
+}
+
#if 0
static int pakfire_jail_stream_stdin(struct pakfire_jail* jail,
struct pakfire_jail_exec* ctx, const int fd) {
return 0;
}
-static int pakfire_jail_fill_buffer(struct pakfire_jail* jail, int fd, struct pakfire_log_buffer* buffer) {
- int r;
-
- // Skip this if there is not space left in the buffer
- if (buffer->used >= sizeof(buffer->data))
- return 0;
-
- // Fill the buffer
- r = read(fd, buffer->data + buffer->used, sizeof(buffer->data) - buffer->used);
-
- // Handle errors
- if (r < 0) {
- switch (errno) {
- case EAGAIN:
- case EIO:
- break;
-
- default:
- return -errno;
- }
-
- // EOF
- } else if (r == 0) {
- // XXX What to do here?
-
- // Successful read
- } else {
- buffer->used += r;
- }
-
- return 0;
-}
-
-static int pakfire_jail_drain_buffer(struct pakfire_jail* jail, int fd, struct pakfire_log_buffer* buffer) {
- int r;
-
- // Nothing to do if the buffer is empty
- if (!buffer->used)
- return 0;
-
- // Drain the buffer
- r = write(fd, buffer->data, buffer->used);
-
- // Handle errors
- if (r < 0) {
- switch (errno) {
- case EAGAIN:
- case EIO:
- break;
-
- default:
- return -errno;
- }
-
- // Successful write
- } else {
- memmove(buffer->data, buffer->data + r, buffer->used - r);
-
- buffer->used -= r;
- }
-
- return 0;
-}
-
static int pakfire_jail_forward_pty(struct pakfire_jail* jail, struct pakfire_jail_exec* ctx) {
int r;
int e = events[i].events;
int fd = events[i].data.fd;
- struct pakfire_log_buffer* buffer = NULL;
- pakfire_jail_communicate_out callback = NULL;
- void* data = NULL;
- int priority;
-
// Handle PTY forwarding events
if (ctx->pty.master.fd == fd) {
if (e & (EPOLLIN|EPOLLHUP))
CTX_ERROR(jail->ctx, "Failed forwarding the PTY: %s\n", strerror(-r));
goto ERROR;
}
- }
- // Check if there is any data to be read
- if (e & EPOLLIN) {
- // Handle any changes to the PIDFD
- if (fd == pidfd) {
+ // Handle any changes to the PIDFD
+ } else if (pidfd == fd) {
+ if (e & EPOLLIN) {
// Call waidid() and store the result
r = waitid(P_PIDFD, ctx->pidfd, &ctx->status, WEXITED);
if (r) {
// Mark that we have ended so that we will process the remaining
// events from epoll() now, but won't restart the outer loop.
ended = 1;
- continue;
+ }
- // Handle timer events
- } else if (fd == timerfd) {
+ // Handle timer events
+ } else if (timerfd == fd) {
+ if (e & EPOLLIN) {
DEBUG(jail->pakfire, "Timer event received\n");
// Disarm the timer
goto ERROR;
}
}
+ }
- // Don't fall through to log processing
- continue;
-
- // Handle logging messages
- } else if (fd == log_INFO) {
- buffer = &ctx->buffers.log_INFO;
- priority = LOG_INFO;
-
- callback = pakfire_jail_log;
-
- } else if (fd == log_ERROR) {
- buffer = &ctx->buffers.log_ERROR;
- priority = LOG_ERR;
-
- callback = pakfire_jail_log;
-
-#ifdef ENABLE_DEBUG
- } else if (fd == log_DEBUG) {
- buffer = &ctx->buffers.log_DEBUG;
- priority = LOG_DEBUG;
-
- callback = pakfire_jail_log;
-#endif /* ENABLE_DEBUG */
-
- // Handle socket messages
- } else if (fd == socket_recv) {
+ // Handle socket messages
+ } else if (socket_recv == fd) {
+ if (e & EPOLLIN) {
// Receive the passed FD
r = pakfire_jail_recv_fd(jail, socket_recv, &fd);
if (r)
goto ERROR;
}
}
+ }
- // Don't fall through to log processing
- continue;
+ // Handle log INFO messages
+ } else if (log_INFO == fd) {
+ if (e & EPOLLIN) {
+ r = pakfire_jail_handle_log(jail, ctx, LOG_INFO, fd,
+ &ctx->buffers.log_INFO, pakfire_jail_log, NULL);
+ if (r)
+ goto ERROR;
+ }
- } else {
- DEBUG(jail->pakfire, "Received invalid file descriptor %d\n", fd);
- continue;
+ // Handle log ERROR messages
+ } else if (log_ERROR == fd) {
+ if (e & EPOLLIN) {
+ r = pakfire_jail_handle_log(jail, ctx, LOG_ERR, fd,
+ &ctx->buffers.log_ERROR, pakfire_jail_log, NULL);
+ if (r)
+ goto ERROR;
}
- // Handle log event
- r = pakfire_jail_handle_log(jail, ctx, priority, fd, buffer, callback, data);
- if (r)
- goto ERROR;
+#ifdef ENABLE_DEBUG
+ // Handle log DEBUG messages
+ } else if (log_DEBUG == fd) {
+ if (e & EPOLLIN) {
+ r = pakfire_jail_handle_log(jail, ctx, LOG_DEBUG, fd,
+ &ctx->buffers.log_DEBUG, pakfire_jail_log, NULL);
+ if (r)
+ goto ERROR;
+ }
+#endif /* ENABLE_DEBUG */
+
+ // Log a message for anything else
+ } else {
+ DEBUG(jail->pakfire, "Received invalid file descriptor %d\n", fd);
+ continue;
}
// Check if any file descriptors have been closed
// Run a command in the jail
static int __pakfire_jail_exec(struct pakfire_jail* jail, const char* argv[],
- const int interactive,
pakfire_jail_communicate_in communicate_in,
pakfire_jail_communicate_out communicate_out,
void* data, int flags) {
DEBUG(jail->pakfire, "Executing jail...\n");
// Enable networking in interactive mode
- if (interactive)
+ if (ctx.flags & PAKFIRE_JAIL_PTY_FORWARDING)
ctx.flags |= PAKFIRE_JAIL_HAS_NETWORKING;
/*
pakfire_jail_communicate_in callback_in,
pakfire_jail_communicate_out callback_out,
void* data, int flags) {
- return __pakfire_jail_exec(jail, argv, 0, callback_in, callback_out, data, flags);
+ return __pakfire_jail_exec(jail, argv, callback_in, callback_out, data, flags);
}
static int pakfire_jail_exec_interactive(
struct pakfire_jail* jail, const char* argv[], int flags) {
int r;
+ flags |= PAKFIRE_JAIL_PTY_FORWARDING;
+
// Setup interactive stuff
r = pakfire_jail_setup_interactive_env(jail);
if (r)
return r;
- return __pakfire_jail_exec(jail, argv, 1, NULL, NULL, NULL, flags);
+ return __pakfire_jail_exec(jail, argv, NULL, NULL, NULL, flags);
}
int pakfire_jail_exec_script(struct pakfire_jail* jail,