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/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <sys/queue.h>
|
||||
#if defined(__linux__) || defined(__CYGWIN__)
|
||||
# include <pty.h>
|
||||
#elif defined(__FreeBSD__) || defined(__DragonFly__)
|
||||
|
|
@ -102,14 +103,24 @@ struct Client {
|
|||
Client *next;
|
||||
};
|
||||
|
||||
struct entry {
|
||||
char *data;
|
||||
int len;
|
||||
bool complete;
|
||||
TAILQ_ENTRY(entry) entries;
|
||||
};
|
||||
|
||||
TAILQ_HEAD(screenhead, entry);
|
||||
|
||||
typedef struct {
|
||||
Client *clients;
|
||||
int socket;
|
||||
Packet pty_output;
|
||||
int pty;
|
||||
int exit_status;
|
||||
struct termios term;
|
||||
struct winsize winsize;
|
||||
struct screenhead screen;
|
||||
int screen_rows;
|
||||
pid_t pid;
|
||||
volatile sig_atomic_t running;
|
||||
const char *name;
|
||||
|
|
@ -118,10 +129,11 @@ typedef struct {
|
|||
bool read_pty;
|
||||
} 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 struct termios orig_term, cur_term;
|
||||
static bool has_term, alternate_buffer, quiet, passthrough;
|
||||
static int screen_max_rows = 120;
|
||||
|
||||
static struct sockaddr_un sockaddr = {
|
||||
.sun_family = AF_UNIX,
|
||||
|
|
@ -223,7 +235,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] [-L num] name command\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
|
|
@ -606,7 +618,7 @@ int main(int argc, char *argv[]) {
|
|||
server.name = basename(argv[0]);
|
||||
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) {
|
||||
case 'a':
|
||||
case 'A':
|
||||
|
|
@ -636,6 +648,15 @@ int main(int argc, char *argv[]) {
|
|||
case 'l':
|
||||
client.flags |= CLIENT_LOWPRIORITY;
|
||||
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':
|
||||
puts("abduco-"VERSION" © 2013-2018 Marc André Tanner");
|
||||
exit(EXIT_SUCCESS);
|
||||
|
|
|
|||
105
server.c
105
server.c
|
|
@ -178,6 +178,93 @@ static void server_atexit_handler(void) {
|
|||
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) {
|
||||
atexit(server_atexit_handler);
|
||||
fd_set new_readfds, new_writefds;
|
||||
|
|
@ -187,6 +274,8 @@ static void server_mainloop(void) {
|
|||
int new_fdmax = server.socket;
|
||||
bool exit_packet_delivered = false;
|
||||
|
||||
TAILQ_INIT(&server.screen);
|
||||
|
||||
if (server.read_pty)
|
||||
FD_SET_MAX(server.pty, &new_readfds, new_fdmax);
|
||||
|
||||
|
|
@ -213,8 +302,11 @@ static void server_mainloop(void) {
|
|||
if (FD_ISSET(server.socket, &readfds))
|
||||
server_accept_client();
|
||||
|
||||
if (FD_ISSET(server.pty, &readfds))
|
||||
if (FD_ISSET(server.pty, &readfds)) {
|
||||
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;) {
|
||||
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;
|
||||
if (c->flags & CLIENT_LOWPRIORITY)
|
||||
server_sink_client();
|
||||
server_send_screen_buffer(c);
|
||||
break;
|
||||
case MSG_RESIZE:
|
||||
c->state = STATE_ATTACHED;
|
||||
|
|
@ -291,5 +384,15 @@ static void server_mainloop(void) {
|
|||
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);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue