mirror of https://github.com/martanne/abduco
Merge a9b345a24f into 8c32909a15
This commit is contained in:
commit
16536d2ae8
29
abduco.c
29
abduco.c
|
|
@ -37,6 +37,7 @@
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <sys/un.h>
|
#include <sys/un.h>
|
||||||
|
#include <sys/queue.h>
|
||||||
#if defined(__linux__) || defined(__CYGWIN__)
|
#if defined(__linux__) || defined(__CYGWIN__)
|
||||||
# include <pty.h>
|
# include <pty.h>
|
||||||
#elif defined(__FreeBSD__) || defined(__DragonFly__)
|
#elif defined(__FreeBSD__) || defined(__DragonFly__)
|
||||||
|
|
@ -102,14 +103,24 @@ struct Client {
|
||||||
Client *next;
|
Client *next;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct entry {
|
||||||
|
char *data;
|
||||||
|
int len;
|
||||||
|
bool complete;
|
||||||
|
TAILQ_ENTRY(entry) entries;
|
||||||
|
};
|
||||||
|
|
||||||
|
TAILQ_HEAD(screenhead, entry);
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
Client *clients;
|
Client *clients;
|
||||||
int socket;
|
int socket;
|
||||||
Packet pty_output;
|
|
||||||
int pty;
|
int pty;
|
||||||
int exit_status;
|
int exit_status;
|
||||||
struct termios term;
|
struct termios term;
|
||||||
struct winsize winsize;
|
struct winsize winsize;
|
||||||
|
struct screenhead screen;
|
||||||
|
int screen_rows;
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
volatile sig_atomic_t running;
|
volatile sig_atomic_t running;
|
||||||
const char *name;
|
const char *name;
|
||||||
|
|
@ -118,10 +129,11 @@ typedef struct {
|
||||||
bool read_pty;
|
bool read_pty;
|
||||||
} Server;
|
} Server;
|
||||||
|
|
||||||
static Server server = { .running = true, .exit_status = -1, .host = "@localhost" };
|
static Server server = { .running = true, .exit_status = -1, .host = "@localhost", .screen_rows = 0 };
|
||||||
static Client client;
|
static Client client;
|
||||||
static struct termios orig_term, cur_term;
|
static struct termios orig_term, cur_term;
|
||||||
static bool has_term, alternate_buffer, quiet, passthrough;
|
static bool has_term, alternate_buffer, quiet, passthrough;
|
||||||
|
static int screen_max_rows = 120;
|
||||||
|
|
||||||
static struct sockaddr_un sockaddr = {
|
static struct sockaddr_un sockaddr = {
|
||||||
.sun_family = AF_UNIX,
|
.sun_family = AF_UNIX,
|
||||||
|
|
@ -223,7 +235,7 @@ static void die(const char *s) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static void usage(void) {
|
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] [-L num] name command\n");
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -606,7 +618,7 @@ int main(int argc, char *argv[]) {
|
||||||
server.name = basename(argv[0]);
|
server.name = basename(argv[0]);
|
||||||
gethostname(server.host+1, sizeof(server.host) - 1);
|
gethostname(server.host+1, sizeof(server.host) - 1);
|
||||||
|
|
||||||
while ((opt = getopt(argc, argv, "aAclne:fpqrv")) != -1) {
|
while ((opt = getopt(argc, argv, "aAclne:fpqrvL:")) != -1) {
|
||||||
switch (opt) {
|
switch (opt) {
|
||||||
case 'a':
|
case 'a':
|
||||||
case 'A':
|
case 'A':
|
||||||
|
|
@ -636,6 +648,15 @@ int main(int argc, char *argv[]) {
|
||||||
case 'l':
|
case 'l':
|
||||||
client.flags |= CLIENT_LOWPRIORITY;
|
client.flags |= CLIENT_LOWPRIORITY;
|
||||||
break;
|
break;
|
||||||
|
case 'L':
|
||||||
|
if (!optarg)
|
||||||
|
usage();
|
||||||
|
screen_max_rows = atoi(optarg);
|
||||||
|
if (screen_max_rows < 0) {
|
||||||
|
fputs("ERROR: a negative value for the number of rows is meaningless.\n", stderr);
|
||||||
|
usage();
|
||||||
|
}
|
||||||
|
break;
|
||||||
case 'v':
|
case 'v':
|
||||||
puts("abduco-"VERSION" © 2013-2018 Marc André Tanner");
|
puts("abduco-"VERSION" © 2013-2018 Marc André Tanner");
|
||||||
exit(EXIT_SUCCESS);
|
exit(EXIT_SUCCESS);
|
||||||
|
|
|
||||||
105
server.c
105
server.c
|
|
@ -178,6 +178,93 @@ static void server_atexit_handler(void) {
|
||||||
unlink(sockaddr.sun_path);
|
unlink(sockaddr.sun_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void server_send_screen_buffer(Client *c) {
|
||||||
|
struct entry *np;
|
||||||
|
|
||||||
|
TAILQ_FOREACH_REVERSE(np, &server.screen, screenhead, entries) {
|
||||||
|
Packet pkt = {
|
||||||
|
.type = MSG_CONTENT,
|
||||||
|
.len = np->len,
|
||||||
|
};
|
||||||
|
strncpy(pkt.u.msg, np->data, np->len);
|
||||||
|
server_send_packet(c, &pkt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void server_preserve_screen_data(Packet *pkt) {
|
||||||
|
char *str, *end;
|
||||||
|
uint32_t len;
|
||||||
|
struct entry *scrline = NULL;
|
||||||
|
|
||||||
|
if (screen_max_rows == 0 || pkt->len <= 0 || pkt->type != MSG_CONTENT)
|
||||||
|
return;
|
||||||
|
|
||||||
|
str = pkt->u.msg;
|
||||||
|
len = pkt->len;
|
||||||
|
end = str + len;
|
||||||
|
|
||||||
|
while (str != end) {
|
||||||
|
char *data;
|
||||||
|
uint32_t i, dlen;
|
||||||
|
|
||||||
|
bool newline = false;
|
||||||
|
char *token = end;
|
||||||
|
|
||||||
|
for (i = 0; i < len; i++) {
|
||||||
|
if (str[i] == '\n') {
|
||||||
|
token = str + i + 1;
|
||||||
|
newline = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((dlen = token - str) <= 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
scrline = TAILQ_FIRST(&server.screen);
|
||||||
|
|
||||||
|
if (scrline && !scrline->complete) {
|
||||||
|
data = realloc(scrline->data, scrline->len + dlen);
|
||||||
|
if (!data)
|
||||||
|
die("unable to extend string in the screen buffer");
|
||||||
|
|
||||||
|
memcpy(data + scrline->len, str, dlen);
|
||||||
|
|
||||||
|
scrline->complete = newline;
|
||||||
|
scrline->data = data;
|
||||||
|
scrline->len += dlen;
|
||||||
|
} else {
|
||||||
|
data = malloc(dlen);
|
||||||
|
if (!data)
|
||||||
|
die("unable to allocate memory for new line in the screen buffer");
|
||||||
|
|
||||||
|
memcpy(data, str, dlen);
|
||||||
|
|
||||||
|
scrline = malloc(sizeof(*scrline));
|
||||||
|
if (!scrline)
|
||||||
|
die("unable to allocate memory for screen buffer element");
|
||||||
|
|
||||||
|
scrline->complete = newline;
|
||||||
|
scrline->data = data;
|
||||||
|
scrline->len = dlen;
|
||||||
|
|
||||||
|
TAILQ_INSERT_HEAD(&server.screen, scrline, entries);
|
||||||
|
server.screen_rows++;
|
||||||
|
|
||||||
|
if (server.screen_rows > screen_max_rows) {
|
||||||
|
scrline = TAILQ_LAST(&server.screen, screenhead);
|
||||||
|
TAILQ_REMOVE(&server.screen, scrline, entries);
|
||||||
|
free(scrline->data);
|
||||||
|
free(scrline);
|
||||||
|
server.screen_rows--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
str = token;
|
||||||
|
len -= dlen;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void server_mainloop(void) {
|
static void server_mainloop(void) {
|
||||||
atexit(server_atexit_handler);
|
atexit(server_atexit_handler);
|
||||||
fd_set new_readfds, new_writefds;
|
fd_set new_readfds, new_writefds;
|
||||||
|
|
@ -187,6 +274,8 @@ static void server_mainloop(void) {
|
||||||
int new_fdmax = server.socket;
|
int new_fdmax = server.socket;
|
||||||
bool exit_packet_delivered = false;
|
bool exit_packet_delivered = false;
|
||||||
|
|
||||||
|
TAILQ_INIT(&server.screen);
|
||||||
|
|
||||||
if (server.read_pty)
|
if (server.read_pty)
|
||||||
FD_SET_MAX(server.pty, &new_readfds, new_fdmax);
|
FD_SET_MAX(server.pty, &new_readfds, new_fdmax);
|
||||||
|
|
||||||
|
|
@ -213,8 +302,11 @@ static void server_mainloop(void) {
|
||||||
if (FD_ISSET(server.socket, &readfds))
|
if (FD_ISSET(server.socket, &readfds))
|
||||||
server_accept_client();
|
server_accept_client();
|
||||||
|
|
||||||
if (FD_ISSET(server.pty, &readfds))
|
if (FD_ISSET(server.pty, &readfds)) {
|
||||||
pty_data = server_read_pty(&server_packet);
|
pty_data = server_read_pty(&server_packet);
|
||||||
|
if (pty_data)
|
||||||
|
server_preserve_screen_data(&server_packet);
|
||||||
|
}
|
||||||
|
|
||||||
for (Client **prev_next = &server.clients, *c = server.clients; c;) {
|
for (Client **prev_next = &server.clients, *c = server.clients; c;) {
|
||||||
if (FD_ISSET(c->socket, &readfds) && server_recv_packet(c, &client_packet)) {
|
if (FD_ISSET(c->socket, &readfds) && server_recv_packet(c, &client_packet)) {
|
||||||
|
|
@ -226,6 +318,7 @@ static void server_mainloop(void) {
|
||||||
c->flags = client_packet.u.i;
|
c->flags = client_packet.u.i;
|
||||||
if (c->flags & CLIENT_LOWPRIORITY)
|
if (c->flags & CLIENT_LOWPRIORITY)
|
||||||
server_sink_client();
|
server_sink_client();
|
||||||
|
server_send_screen_buffer(c);
|
||||||
break;
|
break;
|
||||||
case MSG_RESIZE:
|
case MSG_RESIZE:
|
||||||
c->state = STATE_ATTACHED;
|
c->state = STATE_ATTACHED;
|
||||||
|
|
@ -291,5 +384,15 @@ static void server_mainloop(void) {
|
||||||
FD_SET_MAX(server.pty, &new_readfds, new_fdmax);
|
FD_SET_MAX(server.pty, &new_readfds, new_fdmax);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct entry *n1, *n2;
|
||||||
|
|
||||||
|
n1 = TAILQ_FIRST(&server.screen);
|
||||||
|
while (n1 != NULL) {
|
||||||
|
n2 = TAILQ_NEXT(n1, entries);
|
||||||
|
free(n1->data);
|
||||||
|
free(n1);
|
||||||
|
n1 = n2;
|
||||||
|
}
|
||||||
|
|
||||||
exit(EXIT_SUCCESS);
|
exit(EXIT_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue