Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/ClusterM/clovershell-daemon.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexey 'Cluster' Avdyukhin <clusterrr@clusterrr.com>2017-03-01 15:14:54 +0300
committerAlexey 'Cluster' Avdyukhin <clusterrr@clusterrr.com>2017-03-01 15:14:54 +0300
commit77fd2d635c1c139d6f0d44fa8f5db97e468e43ab (patch)
treedc25ba78b05e0766ab9e1fec3c7609c72af0852c
parent4dc69aac9bfb22ab3199f01d710eb293e04fbc62 (diff)
Stable
-rw-r--r--clovershell.c349
1 files changed, 297 insertions, 52 deletions
diff --git a/clovershell.c b/clovershell.c
index 2c786a9..02d1a0e 100644
--- a/clovershell.c
+++ b/clovershell.c
@@ -9,9 +9,11 @@
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
+#include <sys/wait.h>
#include <termios.h>
#include <fcntl.h>
-#include<signal.h>
+#include <signal.h>
+#include <time.h>
#define DEVICE_PATH "/dev/usb_clover"
char* cmd = "/bin/su";
@@ -20,6 +22,10 @@ char* arg1 = "root";
char* arg2 = "-c";
#define LOGIN_PROG "getty 0 -L %s vt102"
#define MAX_SHELL_CONNECTIONS 256
+#define MAX_EXEC_CONNECTIONS 256
+#define WRITE_BUFFER_SIZE 32768
+#define READ_BUFFER_SIZE 32768
+#define CLEANUP_INTERVAL 60
#define CMD_PING 0
#define CMD_PONG 1
@@ -42,13 +48,24 @@ char* arg2 = "-c";
struct shell_connection
{
- int pid;
+ int reading_pid;
int shell_pid;
int fdm;
char fds[128];
};
+struct exec_connection
+{
+ int stdout_pid;
+ int stderr_pid;
+ int exec_pid;
+ int stdin[2];
+ int stdout[2];
+ int stderr[2];
+};
+
struct shell_connection* shell_connections[MAX_SHELL_CONNECTIONS];
+struct exec_connection* exec_connections[MAX_EXEC_CONNECTIONS];
int u = 0;
@@ -64,43 +81,21 @@ void sig_handler(int signo)
exit(0);
}
-int new_shell_connection()
+void shell_read_thread(struct shell_connection* c, int id)
{
- int i;
- for(i = 0; i < MAX_SHELL_CONNECTIONS; i++)
- if (!shell_connections[i])
- {
- shell_connections[i] = malloc(sizeof(struct shell_connection));
- memset(shell_connections[i], 0, sizeof(struct shell_connection));
- return i;
- }
- printf("too many shell connections\n");
- return -1;
-}
-
-void shell_thread(struct shell_connection* c, int id)
-{
- char buff[1024*10];
-
- buff[0] = CMD_SHELL_NEW_RESP;
- buff[1] = id;
- buff[2] = buff[3] = buff[4] = buff[5] = 0;
- *((long int*)&buff[2]) = sizeof(int);
- *((int*)&buff[6]) = c->pid;
- write(u, buff, 6+sizeof(int));
+ char buff[WRITE_BUFFER_SIZE];
// reading pseudo-tty in a loop
while (1)
{
- long int l = read(c->fdm, buff+6, sizeof(buff-6));
+ long int l = read(c->fdm, buff+4, sizeof(buff)-4);
if (l > 0)
{
// send received data to USB, including CMD and ID
buff[0] = CMD_SHELL_OUT;
buff[1] = id;
- buff[2] = buff[3] = buff[4] = buff[5] = 0;
- *((long int*)&buff[2]) = l;
- if (write(u, buff, l+6) < 0)
+ *((uint16_t*)&buff[2]) = l;
+ if (write(u, buff, l+4) < 0)
{
printf("usb write error\n");
exit(0);
@@ -109,8 +104,9 @@ void shell_thread(struct shell_connection* c, int id)
printf("tty %d(%s) eof\n", id, c->fds);
buff[0] = CMD_SHELL_CLOSED;
buff[1] = id;
- buff[2] = buff[3] = buff[4] = buff[5] = 0;
- write(u, buff, 6);
+ buff[2] = buff[3] = 0;
+ write(u, buff, 4);
+ close(u);
exit(0);
}
}
@@ -120,8 +116,8 @@ void shell_new_connection()
{
int id;
for(id = 0; id < MAX_SHELL_CONNECTIONS; id++)
- if (!shell_connections[id])
- break;
+ if (!shell_connections[id])
+ break;
if (id >= MAX_SHELL_CONNECTIONS)
{
printf("too many shell connections\n");
@@ -130,24 +126,22 @@ void shell_new_connection()
shell_connections[id] = malloc(sizeof(struct shell_connection));
memset(shell_connections[id], 0, sizeof(struct shell_connection));
struct shell_connection* c = shell_connections[id];
- c->fdm = posix_openpt(O_RDWR|O_NOCTTY);
+ c->fdm = posix_openpt(O_RDWR|O_NOCTTY);
if (c->fdm < 0) error("posix_openpt");
if (grantpt(c->fdm)) error("grantpt");
if (unlockpt(c->fdm)) error("unlockpt");
ptsname_r(c->fdm, c->fds, sizeof(c->fds));
printf("created %d(%s)\n", id, c->fds);
- // reading thread
- if (!(c->pid = fork()))
- {
- shell_thread(c, id);
- return;
- }
+ char buff[4];
+ buff[0] = CMD_SHELL_NEW_RESP;
+ buff[1] = id;
+ buff[2] = buff[3] = 0;
+ write(u, buff, 4);
// starting getty
if (!(c->shell_pid = fork()))
{
- sleep(1);
close(u);
close(c->fdm);
char g[128];
@@ -155,9 +149,13 @@ void shell_new_connection()
execl(cmd, arg0, arg1, arg2, g, NULL);
error("exec getty");
}
+
+ // reading thread
+ if (!(c->reading_pid = fork()))
+ shell_read_thread(c, id);
}
-void shell_data(int id, char* data, uint32_t len)
+void shell_data(int id, char* data, uint16_t len)
{
struct shell_connection* c = shell_connections[id];
if (!c)
@@ -169,7 +167,7 @@ void shell_data(int id, char* data, uint32_t len)
{
printf("fdm %d(%s) write error\n", id, c->fds);
close(c->fdm);
- kill(c->pid, SIGTERM);
+ kill(c->reading_pid, SIGKILL);
free(shell_connections[id]);
shell_connections[id] = NULL;
}
@@ -180,8 +178,8 @@ void shell_kill(int id)
struct shell_connection* c = shell_connections[id];
if (!c) return;
close(c->fdm);
- kill(c->shell_pid, SIGTERM);
- kill(c->pid, SIGTERM);
+ kill(c->shell_pid, SIGKILL);
+ kill(c->reading_pid, SIGKILL);
free(shell_connections[id]);
shell_connections[id] = NULL;
printf("shell session %d killed\n", id);
@@ -194,18 +192,249 @@ void shell_kill_all()
if (shell_connections[id]) shell_kill(id);
}
-int main()
+void exec_read_stdout_thread(struct exec_connection* c, int id)
+{
+ char buff[WRITE_BUFFER_SIZE];
+
+ // reading pipe in a loop
+ while (1)
+ {
+ int l = read(c->stdout[0], buff+4, sizeof(buff)-4);
+ buff[0] = CMD_EXEC_STDOUT;
+ buff[1] = id;
+ if (l > 0)
+ {
+ *((uint16_t*)&buff[2]) = l;
+ if (write(u, buff, l+4) < 0)
+ exit(1);
+ } else {
+ buff[2] = buff[3] = 0;
+ if (write(u, buff, 4) < 0)
+ exit(1);
+ close(u);
+ exit(0);
+ }
+ }
+}
+
+void exec_read_stderr_thread(struct exec_connection* c, int id)
+{
+ char buff[WRITE_BUFFER_SIZE];
+
+ // reading pipe in a loop
+ while (1)
+ {
+ int l = read(c->stderr[0], buff+4, sizeof(buff)-4);
+ buff[0] = CMD_EXEC_STDERR;
+ buff[1] = id;
+ if (l > 0)
+ {
+ *((uint16_t*)&buff[2]) = l;
+ if (write(u, buff, l+4) < 0)
+ exit(1);
+ } else {
+ buff[2] = buff[3] = 0;
+ if (write(u, buff, 4) < 0)
+ exit(1);
+ close(u);
+ exit(0);
+ }
+ }
+}
+
+void exec_new_connection(char* cmd, uint16_t len)
+{
+ cmd[len] = 0;
+ int id;
+ for(id = 0; id < MAX_EXEC_CONNECTIONS; id++)
+ if (!exec_connections[id])
+ break;
+ if (id >= MAX_EXEC_CONNECTIONS)
+ {
+ printf("too many shell connections\n");
+ return;
+ }
+ exec_connections[id] = malloc(sizeof(struct exec_connection));
+ memset(exec_connections[id], 0, sizeof(struct exec_connection));
+ struct exec_connection* c = exec_connections[id];
+
+ printf("executing %s\n", cmd);
+
+ char buff[1024];
+ buff[0] = CMD_EXEC_NEW_RESP;
+ buff[1] = id;
+ *((uint16_t*)&buff[2]) = len;
+ strcpy(&buff[4], cmd);
+ write(u, buff, 4+len);
+
+ pipe(c->stdin);
+ pipe(c->stdout);
+ pipe(c->stderr);
+
+ // executing
+ if (!(c->exec_pid = fork()))
+ {
+ close(STDIN_FILENO);
+ close(STDOUT_FILENO);
+ close(STDERR_FILENO);
+ dup2(c->stdin[0], STDIN_FILENO);
+ close(c->stdin[0]);
+ close(c->stdin[1]); // unused
+ dup2(c->stdout[1], STDOUT_FILENO);
+ close(c->stdout[1]);
+ dup2(c->stderr[1], STDERR_FILENO);
+ close(c->stderr[1]);
+ //execl("/bin/sh", "sh", "-c", cmd, (char *) 0);
+ int ret = system(cmd);
+ buff[0] = CMD_EXEC_RESULT;
+ buff[1] = id;
+ *((uint16_t*)&buff[2]) = sizeof(ret);
+ *((int*)&buff[4]) = ret;
+ write(u, buff, 4+sizeof(ret));
+ close(u);
+ exit(0);
+ }
+
+ close(c->stdin[0]); // unused in this thread
+
+ // stdout reading thread
+ if (!(c->stdout_pid = fork()))
+ {
+ close(c->stdin[1]); // unused
+ close(c->stdout[1]); // unused
+ close(c->stderr[0]); // unused
+ close(c->stderr[1]); // unused
+ exec_read_stdout_thread(c, id);
+ }
+ // stderr reading thread
+ if (!(c->stderr_pid = fork()))
+ {
+ close(c->stdin[1]); // unused
+ close(c->stderr[1]); // unused
+ close(c->stdout[0]); // unused
+ close(c->stdout[1]); // unused
+ exec_read_stderr_thread(c, id);
+ }
+
+ // unused
+ close(c->stdout[0]);
+ close(c->stdout[1]);
+ close(c->stderr[0]);
+ close(c->stderr[1]);
+}
+
+void exec_stdin(int id, char* data, uint16_t len)
+{
+ struct exec_connection* c = exec_connections[id];
+ if (!c)
+ {
+ printf("invalid id: %d\n", id);
+ return;
+ }
+ if (len > 0)
+ {
+ if (write(c->stdin[1], data, len) < 0)
+ printf("exec %d write error\n", id);
+ } else close(c->stdin[1]);
+}
+
+void exec_kill(int id)
+{
+ struct exec_connection* c = exec_connections[id];
+ if (!c) return;
+ close(c->stdin[1]);
+ kill(c->exec_pid, SIGKILL);
+ kill(c->stdout_pid, SIGKILL);
+ kill(c->stderr_pid, SIGKILL);
+ free(exec_connections[id]);
+ exec_connections[id] = NULL;
+ printf("exec session %d killed\n", id);
+}
+
+void exec_kill_all()
+{
+ int id;
+ for (id = 0; id < MAX_EXEC_CONNECTIONS; id++)
+ if (exec_connections[id]) exec_kill(id);
+}
+
+void cleanup()
+{
+ // Zombie hunt!
+ int id;
+ for (id = 0; id < MAX_SHELL_CONNECTIONS; id++)
+ {
+ struct shell_connection* c = shell_connections[id];
+ if (c)
+ {
+ //printf("Checking shell %d\n", id);
+ char dead = 1;
+ if (c->reading_pid && (waitpid(c->reading_pid, NULL, WNOHANG) == 0))
+ dead = 0;
+ else
+ c->reading_pid = 0;
+ if (c->shell_pid && (waitpid(c->shell_pid, NULL, WNOHANG) == 0))
+ dead = 0;
+ else
+ c->shell_pid = 0;
+ //printf("Dead: %d\n", dead);
+ if (dead)
+ {
+ close(c->fdm);
+ free(c);
+ shell_connections[id] = NULL;
+ }
+ }
+ }
+ for (id = 0; id < MAX_EXEC_CONNECTIONS; id++)
+ {
+ struct exec_connection* c = exec_connections[id];
+ if (c)
+ {
+ //printf("Checking exec %d\n", id);
+ char dead = 1;
+ if (c->exec_pid && (waitpid(c->exec_pid, NULL, WNOHANG) == 0))
+ dead = 0;
+ else
+ c->exec_pid = 0;
+ if (c->stdout_pid && (waitpid(c->stdout_pid, NULL, WNOHANG) == 0))
+ dead = 0;
+ else
+ c->stdout_pid = 0;
+ if (c->stderr_pid && (waitpid(c->stderr_pid, NULL, WNOHANG) == 0))
+ dead = 0;
+ else
+ c->stderr_pid = 0;
+ //printf("Dead: %d\n", dead);
+ if (dead)
+ {
+ close(c->stdin[1]);
+ free(c);
+ exec_connections[id] = NULL;
+ }
+ }
+ }
+
+}
+
+int main(int argc, char **argv)
{
printf("clovershell (c) cluster, 2017 (built time: %s %s)\n", __DATE__, __TIME__);
int i;
for(i = 0; i < MAX_SHELL_CONNECTIONS; i++)
shell_connections[i] = NULL;
+ for(i = 0; i < MAX_EXEC_CONNECTIONS; i++)
+ exec_connections[i] = NULL;
if (signal(SIGTERM, sig_handler) == SIG_ERR) error("SIGTERM");
u = open(DEVICE_PATH, O_RDWR|O_NOCTTY, 0);
if (u < 0) error("usb open");
- char buff[65536];
+ char buff[READ_BUFFER_SIZE];
+ time_t clean_time = time(NULL);
+
+ if (argc >= 2 && strcmp(argv[1], "--daemon") == 0)
+ daemon(1,1);
while (1)
{
@@ -218,14 +447,12 @@ int main()
}
char cmd = buff[0];
char arg = buff[1];
- uint32_t len = *((long int*)&buff[2]);
+ uint16_t len = *((uint16_t*)&buff[2]);
//printf("cmd=%d, arg=%d, len=%d\n", cmd, arg, len);
- char* data = &buff[6];
- if (len + 6 != l)
+ char* data = &buff[4];
+ if (len + 4 != l)
{
printf("invalid size: %d != %d\n", l, len);
- //close(u);
- //exit(0);
continue;
}
@@ -248,6 +475,24 @@ int main()
case CMD_SHELL_KILL_ALL:
shell_kill_all();
break;
+ case CMD_EXEC_NEW_REQ:
+ exec_new_connection(data, len);
+ break;
+ case CMD_EXEC_STDIN:
+ exec_stdin(arg, data, len);
+ break;
+ case CMD_EXEC_KILL:
+ exec_kill(arg);
+ break;
+ case CMD_EXEC_KILL_ALL:
+ exec_kill_all();
+ break;
+ }
+ if (time(NULL) - clean_time > CLEANUP_INTERVAL)
+ {
+ //printf("Cleaing up\n");
+ cleanup();
+ clean_time = time(NULL);
}
}
return 0;