mirror of https://github.com/martanne/abduco
support generic scrollbuffer implementations
This commit is contained in:
parent
8c32909a15
commit
185eb4bf0d
4
abduco.1
4
abduco.1
|
|
@ -102,6 +102,10 @@ which is specified as ^\\ i.e. Ctrl is represented as a caret
|
|||
.It Fl f
|
||||
Force creation of session when there is an already terminated session of the same name,
|
||||
after showing its exit status.
|
||||
.It Fl s Ar scrollback_fd_socket
|
||||
A unix socket to send the writing end of a pipe through. This can be used for receiving the scrollback
|
||||
buffer from when a new client attaches. Wait for the accepted socket to be closed before resuming
|
||||
regular pass-through behavior.
|
||||
.It Fl l
|
||||
Attach with the lowest priority, meaning this client will be the last to control the size.
|
||||
.It Fl p
|
||||
|
|
|
|||
18
abduco.c
18
abduco.c
|
|
@ -116,6 +116,7 @@ typedef struct {
|
|||
const char *session_name;
|
||||
char host[255];
|
||||
bool read_pty;
|
||||
char scrollback_sock[PATH_MAX];
|
||||
} Server;
|
||||
|
||||
static Server server = { .running = true, .exit_status = -1, .host = "@localhost" };
|
||||
|
|
@ -223,7 +224,7 @@ static void die(const char *s) {
|
|||
}
|
||||
|
||||
static void usage(void) {
|
||||
fprintf(stderr, "usage: abduco [-a|-A|-c|-n] [-p] [-r] [-q] [-l] [-f] [-e detachkey] name command\n");
|
||||
fprintf(stderr, "usage: abduco [-a|-A|-c|-n] [-p] [-r] [-q] [-l] [-f] [-e detachkey] [-s scrollback-sock] name command\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
|
|
@ -604,9 +605,10 @@ int main(int argc, char *argv[]) {
|
|||
}
|
||||
|
||||
server.name = basename(argv[0]);
|
||||
server.scrollback_sock[0] = '\0';
|
||||
gethostname(server.host+1, sizeof(server.host) - 1);
|
||||
|
||||
while ((opt = getopt(argc, argv, "aAclne:fpqrv")) != -1) {
|
||||
while ((opt = getopt(argc, argv, "aAclne:fpqrs:v")) != -1) {
|
||||
switch (opt) {
|
||||
case 'a':
|
||||
case 'A':
|
||||
|
|
@ -633,6 +635,18 @@ int main(int argc, char *argv[]) {
|
|||
case 'r':
|
||||
client.flags |= CLIENT_READONLY;
|
||||
break;
|
||||
case 's':
|
||||
if (!realpath(".", server.scrollback_sock)) {
|
||||
fprintf(stderr, "can't determine current directory: %s\n", strerror(errno));
|
||||
return 2;
|
||||
}
|
||||
if (strlen(server.scrollback_sock) + strlen(optarg) + 2 > PATH_MAX) {
|
||||
fprintf(stderr, "scrollback_sock path too long\n");
|
||||
return 2;
|
||||
}
|
||||
strcat(server.scrollback_sock, "/");
|
||||
strcat(server.scrollback_sock, optarg);
|
||||
break;
|
||||
case 'l':
|
||||
client.flags |= CLIENT_LOWPRIORITY;
|
||||
break;
|
||||
|
|
|
|||
58
server.c
58
server.c
|
|
@ -136,6 +136,62 @@ static void server_sigterm_handler(int sig) {
|
|||
exit(EXIT_FAILURE); /* invoke atexit handler */
|
||||
}
|
||||
|
||||
static void server_print_scrollback(const char *scrollback_sock, Client *c) {
|
||||
int sock = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
if (sock == -1) {
|
||||
debug("failed to open unix socket: %s\n", strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
||||
struct sockaddr_un addr = { .sun_family = AF_UNIX };
|
||||
snprintf(addr.sun_path, sizeof(addr.sun_path), "%s", scrollback_sock);
|
||||
if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
|
||||
debug("failed to connect to %s: %s\n", scrollback_sock, strerror(errno));
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
char buf[1];
|
||||
|
||||
struct iovec iov = { .iov_base = &buf, .iov_len = sizeof(buf) };
|
||||
char cmsg_buf[CMSG_SPACE(sizeof(int))];
|
||||
struct msghdr msg = {
|
||||
.msg_iov = &iov,
|
||||
.msg_iovlen = 1,
|
||||
.msg_control = cmsg_buf,
|
||||
.msg_controllen = sizeof(cmsg_buf)
|
||||
};
|
||||
|
||||
int scrlb_fd = -1;
|
||||
|
||||
if (recvmsg(sock, &msg, 0) == -1)
|
||||
goto cleanup;
|
||||
|
||||
struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
|
||||
if (cmsg->cmsg_level != SOL_SOCKET
|
||||
|| cmsg->cmsg_type != SCM_RIGHTS
|
||||
|| cmsg->cmsg_len != CMSG_LEN(sizeof(int)))
|
||||
goto cleanup;
|
||||
|
||||
memcpy(&scrlb_fd, CMSG_DATA(cmsg), sizeof(int));
|
||||
|
||||
Packet pkt = { .type = MSG_CONTENT };
|
||||
|
||||
ssize_t rlen;
|
||||
while ((rlen = read(scrlb_fd, pkt.u.msg, sizeof(pkt.u.msg))) > 0) {
|
||||
pkt.len = rlen;
|
||||
server_send_packet(c, &pkt);
|
||||
}
|
||||
|
||||
// no further data is handled by the scrollback buffer until the unix
|
||||
// socket is closed. this is the time to attach the client to receive
|
||||
// any future data. since this code is blocking the server loop, we're
|
||||
// done.
|
||||
close(scrlb_fd);
|
||||
|
||||
cleanup:
|
||||
close(sock);
|
||||
}
|
||||
|
||||
static Client *server_accept_client(void) {
|
||||
int newfd = accept(server.socket, NULL, NULL);
|
||||
if (newfd == -1 || server_set_socket_non_blocking(newfd) == -1)
|
||||
|
|
@ -157,6 +213,8 @@ static Client *server_accept_client(void) {
|
|||
.u.l = getpid(),
|
||||
};
|
||||
server_send_packet(c, &pkt);
|
||||
if (server.scrollback_sock[0])
|
||||
server_print_scrollback(server.scrollback_sock, c);
|
||||
|
||||
return c;
|
||||
error:
|
||||
|
|
|
|||
Loading…
Reference in New Issue