#include <sys/timerfd.h>
#include <sys/types.h>
#include <sys/wait.h>
+#include <termios.h>
// libnl3
#include <net/if.h>
struct pakfire_cgroup* cgroup;
struct pakfire_cgroup_stats cgroup_stats;
- // Console
- char console[PATH_MAX];
- int consolefd;
+ // PTY
+ struct pakfire_jail_pty {
+ // The path to the console
+ char console[PATH_MAX];
+
+ // The master fd
+ struct pakfire_jail_pty_master {
+ int fd;
+
+ enum pakfire_jail_pty_flags {
+ PAKFIRE_JAIL_PTY_READY_TO_READ = (1 << 0),
+ PAKFIRE_JAIL_PTY_READY_TO_WRITE = (1 << 1),
+ } flags;
+ } master;
+
+ // Standard Input
+ struct pakfire_jail_pty_stdio {
+ int fd;
+ char buffer[LINE_MAX];
+ struct termios attrs;
+ int fdflags;
+ enum pakfire_jail_pty_flags flags;
+ } stdin;
+
+ // Standard Output
+ struct pakfire_jail_pty_stdio stdout;
+ } pty;
};
static int clone3(struct clone_args* args, size_t size) {
}
// Skip if the writing pipe has already been closed
- if (!ctx->pipes.stdin[1])
+ if (ctx->pipes.stdin[1] < 0)
return 0;
DEBUG(jail->pakfire, "Streaming standard input...\n");
return 0;
}
+// PTY Forwarding
+
+static int pakfire_jail_enable_raw_mode(struct pakfire_jail* jail,
+ struct pakfire_jail_pty_stdio* stdio) {
+ struct termios raw_attrs;
+ int r;
+
+ // Store flags
+ stdio->fdflags = fcntl(stdio->fd, F_GETFL);
+ if (stdio->fdflags < 0) {
+ CTX_ERROR(jail->ctx, "Could not fetch flags from fd %d: %s\n",
+ stdio->fd, strerror(errno));
+ return -errno;
+ }
+
+ // Fetch all attributes
+ r = tcgetattr(stdio->fd, &stdio->attrs);
+ if (r) {
+ CTX_ERROR(jail->ctx, "Could not fetch terminal attributes from fd %d: %s\n",
+ stdio->fd, strerror(errno));
+ return -errno;
+ }
+
+ // Copy all attributes
+ raw_attrs = stdio->attrs;
+
+ // Make it RAW
+ cfmakeraw(&raw_attrs);
+
+ // Restore the attributes
+ r = tcsetattr(stdio->fd, TCSANOW, &raw_attrs);
+ if (r) {
+ CTX_ERROR(jail->ctx, "Could not restore terminal attributes for fd %d: %s\n",
+ stdio->fd, strerror(errno));
+ return -errno;
+ }
+
+ return 0;
+}
+
+static int pakfire_jail_restore_attrs(struct pakfire_jail* jail,
+ const struct pakfire_jail_pty_stdio* stdio) {
+ int r;
+
+ // Restore the flags
+ r = fcntl(stdio->fd, F_SETFL, stdio->fdflags);
+ if (r < 0) {
+ CTX_ERROR(jail->ctx, "Could not set flags for file descriptor %d: %s\n",
+ stdio->fd, strerror(errno));
+ return -errno;
+ }
+
+ // Restore the attributes
+ r = tcsetattr(stdio->fd, TCSANOW, &stdio->attrs);
+ if (r) {
+ CTX_ERROR(jail->ctx, "Could not restore terminal attributes for %d, ignoring: %s\n",
+ stdio->fd, strerror(errno));
+ return -errno;
+ }
+
+ return 0;
+}
+
+static int pakfire_jail_setup_pty_forwarding(struct pakfire_jail* jail,
+ struct pakfire_jail_exec* ctx, const int epollfd, const int fd) {
+ struct winsize size;
+ int r;
+
+ CTX_DEBUG(jail->ctx, "Setting up PTY forwarding on fd %d\n", fd);
+
+ // Store the file descriptor
+ ctx->pty.master.fd = fd;
+
+ // Configure stdin/stdout
+ ctx->pty.stdin.fd = STDIN_FILENO;
+ ctx->pty.stdout.fd = STDOUT_FILENO;
+
+ // Fetch dimensions
+ r = ioctl(ctx->pty.stdout.fd, TIOCGWINSZ, &size);
+ if (r) {
+ CTX_ERROR(jail->ctx, "Failed to determine terminal dimensions: %s\n", strerror(errno));
+ return -errno;
+ }
+
+ // Set dimensions
+ r = ioctl(ctx->pty.master.fd, TIOCSWINSZ, &size);
+ if (r) {
+ CTX_ERROR(jail->ctx, "Failed setting dimensions: %s\n", strerror(errno));
+ return -errno;
+ }
+
+ // Enable RAW mode on standard input
+ r = pakfire_jail_enable_raw_mode(jail, &ctx->pty.stdin);
+ if (r)
+ return r;
+
+ // Enable RAW mode on standard output
+ r = pakfire_jail_enable_raw_mode(jail, &ctx->pty.stdout);
+ if (r)
+ return r;
+
+ // Add the master to the event loop
+ r = pakfire_jail_epoll_add_fd(jail, epollfd, ctx->pty.master.fd, EPOLLIN|EPOLLOUT|EPOLLET);
+ if (r)
+ return r;
+
+ // Add standard input to the event loop
+ r = pakfire_jail_epoll_add_fd(jail, epollfd, ctx->pty.stdin.fd, EPOLLIN|EPOLLET);
+ if (r)
+ return r;
+
+ // Add standard output to the event loop
+ r = pakfire_jail_epoll_add_fd(jail, epollfd, ctx->pty.stdout.fd, EPOLLOUT|EPOLLET);
+ if (r)
+ return r;
+
+ return 0;
+}
+
static int pakfire_jail_wait(struct pakfire_jail* jail, struct pakfire_jail_exec* ctx) {
int epollfd = -1;
struct epoll_event events[EPOLL_MAX_EVENTS];
if (r)
goto ERROR;
- // XXX Do something with the file descriptor
+ // Setup PTY forwarding
+ if (ctx->pty.master.fd < 0) {
+ r = pakfire_jail_setup_pty_forwarding(jail, ctx, epollfd, fd);
+ if (r) {
+ CTX_ERROR(jail->ctx, "Failed setting up PTY forwarding: %s\n", strerror(-r));
+ goto ERROR;
+ }
+ }
// Don't fall through to log processing
continue;
if (timerfd >= 0)
close(timerfd);
+ // Restore any changed terminal attributes
+ pakfire_jail_restore_attrs(jail, &ctx->pty.stdin);
+ pakfire_jail_restore_attrs(jail, &ctx->pty.stdout);
+
return r;
}
return 0;
}
-#if 0
static int pakfire_jail_open_pty(struct pakfire_jail* jail, struct pakfire_jail_exec* ctx) {
int r;
// Allocate a new PTY
- ctx->consolefd = posix_openpt(O_RDWR|O_NONBLOCK|O_NOCTTY|O_CLOEXEC);
- if (ctx->consolefd < 0)
+ ctx->pty.master.fd = posix_openpt(O_RDWR|O_NONBLOCK|O_NOCTTY|O_CLOEXEC);
+ if (ctx->pty.master.fd < 0)
return -errno;
// Fetch the path
- r = ptsname_r(ctx->consolefd, ctx->console, sizeof(ctx->console));
+ r = ptsname_r(ctx->pty.master.fd, ctx->pty.console, sizeof(ctx->pty.console));
if (r)
return -r;
- CTX_DEBUG(jail->ctx, "Allocated console at %s (%d)\n", ctx->console, ctx->consolefd);
+ CTX_DEBUG(jail->ctx, "Allocated console at %s (%d)\n", ctx->pty.console, ctx->pty.master.fd);
+#if 0
// Create a symlink
- r = pakfire_symlink(jail->ctx, "/dev/console", ctx->console);
+ r = pakfire_symlink(jail->ctx, "/dev/console", ctx->pty.console);
if (r)
return r;
+#endif
return r;
}
-#endif
static int pakfire_jail_child(struct pakfire_jail* jail, struct pakfire_jail_exec* ctx,
const char* argv[]) {
return 126;
}
+ const int socket_send = pakfire_jail_get_pipe_to_write(jail, &ctx->socket);
+
// Mount all default stuff
r = pakfire_mount_all(jail->pakfire, PAKFIRE_MNTNS_INNER, 0);
if (r)
return 126;
-#if 0
- // Create a new session
- r = setsid();
- if (r < 0) {
- CTX_ERROR(jail->ctx, "Could not create a new session: %s\n", strerror(errno));
- return 126;
- }
-
- // Allocate a new PTY
- r = pakfire_jail_open_pty(jail, ctx);
- if (r) {
- CTX_ERROR(jail->ctx, "Could not allocate a new PTY: %s\n", strerror(-r));
- return 126;
- }
-#endif
-
const char* root = pakfire_get_path(jail->pakfire);
const char* arch = pakfire_get_effective_arch(jail->pakfire);
}
}
+#if 0
+ // Create a new session
+ r = setsid();
+ if (r < 0) {
+ CTX_ERROR(jail->ctx, "Could not create a new session: %s\n", strerror(errno));
+ return r;
+ }
+#endif
+
+ // Allocate a new PTY
+ r = pakfire_jail_open_pty(jail, ctx);
+ if (r) {
+ CTX_ERROR(jail->ctx, "Could not allocate a new PTY: %s\n", strerror(-r));
+ return r;
+ }
+
+ // Send the PTY master to the parent process
+ r = pakfire_jail_send_fd(jail, socket_send, ctx->pty.master.fd);
+ if (r) {
+ CTX_ERROR(jail->ctx, "Failed sending the PTY master to the parent: %s\n", strerror(-r));
+ return r;
+ }
+
+ // Close the master of the PTY
+ close(ctx->pty.master.fd);
+ ctx->pty.master.fd = -1;
+
+ // Close the socket
+ close(socket_send);
+
// Close other end of log pipes
close(ctx->pipes.log_INFO[0]);
close(ctx->pipes.log_ERROR[0]);
},
.pidfd = -1,
+
+ // PTY
+ .pty = {
+ .master = {
+ .fd = -1,
+ },
+ .stdin = {
+ .fd = -1,
+ },
+ .stdout = {
+ .fd = -1,
+ },
+ },
};
DEBUG(jail->pakfire, "Executing jail...\n");
pakfire_jail_close_pipe(jail, ctx.pipes.stderr);
if (ctx.pidfd >= 0)
close(ctx.pidfd);
+ if (ctx.pty.master.fd >= 0)
+ close(ctx.pty.master.fd);
pakfire_jail_close_pipe(jail, ctx.pipes.log_INFO);
pakfire_jail_close_pipe(jail, ctx.pipes.log_ERROR);
#ifdef ENABLE_DEBUG