aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authortoni <matzeton@googlemail.com>2017-01-06 19:26:27 +0100
committertoni <matzeton@googlemail.com>2017-01-06 19:26:27 +0100
commit71db2f9ecf7f33014ce02a44f6aa0db01e616fba (patch)
tree2049535148fe80a256c765d044953a7f2fadd4fa
parenteb05457fdc59b2dceca5a09e3572e424008a8b66 (diff)
interactive dummyshell
-rw-r--r--dummyshell.c397
1 files changed, 368 insertions, 29 deletions
diff --git a/dummyshell.c b/dummyshell.c
index f4fbbc8..28c64f3 100644
--- a/dummyshell.c
+++ b/dummyshell.c
@@ -1,5 +1,5 @@
/*
- * build with: gcc -Wall -O2 -D_HAS_HOSTENT=1 -D_HAS_SIGNAL=1 -D_HAS_UTMP=1 -D_HAS_SYSINFO -ffunction-sections -fdata-sections -ffast-math -fomit-frame-pointer dummyshell.c -o dummyshell
+ * build with: gcc -Wall -O2 -D_HAS_MSG=1 -D_HAS_HOSTENT=1 -D_HAS_SIGNAL=1 -D_HAS_UTMP=1 -D_HAS_SYSINFO -ffunction-sections -fdata-sections -ffast-math -fomit-frame-pointer dummyshell.c -o dummyshell
* strip -s dummyshell
*/
@@ -9,46 +9,274 @@
#include <termios.h>
#include <fcntl.h>
#include <time.h>
+#include <ctype.h> /* isprint(...) */
+#include <stropts.h> /* ioctl(...) */
+#include <sys/ioctl.h>
+#include <stdint.h> /* UINT8_MAX */
+#include <string.h> /* memset(...) */
+#include <sys/types.h>
+#include <pwd.h> /* getpwuid(...) */
+#ifdef _HAS_CMD
+#include <sys/wait.h>
+#else
+#warning "COMMANDS(_HAS_CMD) disabled!"
+#endif
+#ifdef _HAS_MSG
+#include <errno.h>
+#include <string.h>
+#else
+#warning "MESSAGE(_HAS_MSG) disabled!"
+#endif
#ifdef _HAS_HOSTENT
#include <netdb.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#else
-#warn "HOSTENT(_HAS_HOSTENT) disabled!"
+#warning "HOSTENT(_HAS_HOSTENT) disabled!"
#endif
#ifdef _HAS_SIGNAL
#include <signal.h> /* signal(...) */
#else
-#warn "SIGNAL(_HAS_SIGNAL) disabled!"
-#endif
-#if defined(_HAS_UTMP) || defined(_HAS_SYSINFO)
-#include <string.h> /* memset */
+#warning "SIGNAL(_HAS_SIGNAL) disabled!"
#endif
#ifdef _HAS_UTMP
#include <utmp.h> /* utmp structure */
#else
-#warn "UTMP(_HAS_UTMP) disabled!"
+#warning "UTMP(_HAS_UTMP) disabled!"
#endif
#ifdef _HAS_SYSINFO
#include "sys/types.h" /* sysinfo structture */
#include "sys/sysinfo.h" /* sysinfo(...) */
#else
-#warn "SYSINFO(_HAS_SYSINFO) disabled!"
+#warning "SYSINFO(_HAS_SYSINFO) disabled!"
#endif
/* for print_memusage() and print cpuusage() see: http://stackoverflow.com/questions/63166/how-to-determine-cpu-and-memory-consumption-from-inside-a-process */
-static const char keymsg[] = " [PRESS ANY KEY TO QUIT] ";
+static const char keymsg[] = " ['q'-EXIT | 'm'-MESSAGE | 'c'-CMDS] ";
static const char txtheader[] =
"**************\n"
"* dummyshell *\n"
- "**************\n";
+ "**************\n"
+ "!(C) by Toni Uhlig\n"
+ "@see: https://raw.githubusercontent.com/lnslbrty/foo-scripts/master/dummyshell.c\n";
static volatile unsigned char doLoop = 1;
+static void printQuitLoop(void) {
+ printf("quit in 3 .. ");
+ fflush(stdout);
+ sleep(1);
+ printf("2 .. ");
+ fflush(stdout);
+ sleep(1);
+ printf("1 .. ");
+ fflush(stdout);
+ sleep(1);
+ printf("\n");
+ doLoop = 0;
+}
+
+#define I_CLEARBUF 0x1
+static char readInput(char* buf, size_t* siz, size_t szMax, char key, int flags) {
+ if (flags & I_CLEARBUF) {
+ memset(&buf[0], '\0', szMax);
+ *siz = 0;
+ } else switch (key) {
+ case '\n':
+ break;
+ case 127:
+ if (*siz > 0)
+ buf[--(*siz)] = '\0';
+ break;
+ case EOF: break;
+ default:
+ if (isprint(key) && *siz < szMax)
+ buf[(*siz)++] = key;
+ break;
+ }
+ return key;
+}
+
+#ifdef _HAS_CMD
+struct __attribute__((__packed__)) cmd {
+ char* name;
+ char* path;
+};
+
+static struct cmd cmds[] = {
+ { "ether-wake", "/usr/sbin/ether-wake" },
+ { "echo", "/bin/echo" },
+ { NULL, NULL }
+};
+
+static void print_cmds(void)
+{
+ size_t idx = 0;
+ printf("\33[2K\r[COMMANDS]\n");
+ while ( cmds[idx++].path != NULL ) {
+ printf(" [%lu] %s\n", idx-1, ( cmds[idx-1].name != NULL ? cmds[idx-1].name : "unknown" ));
+ }
+}
+
+int safe_exec(const char* cmdWithArgs)
+{
+ pid_t child;
+ if ( (child = fork()) == 0 ) {
+ size_t szCur = 0, szMax = 10;
+ char** args = calloc(szMax, sizeof(char**));
+ const char* cmd = NULL;
+
+ const char* prv = cmdWithArgs;
+ const char* cur = NULL;
+ while ( (cur = strchr(prv, ' ')) ) {
+ if (cmd == NULL)
+ cmd = strndup(prv, cur-prv);
+
+ args[szCur++] = strndup(prv, cur-prv);
+ if (szCur >= szMax) {
+ szMax *= 2;
+ args = realloc(args, sizeof(char**)*szMax);
+ }
+
+ cur++;
+ prv = cur;
+ }
+ if (cmd == NULL) {
+ cmd = cmdWithArgs;
+ } else {
+ args[szCur++] = strndup(prv, cur-prv);
+ }
+ args[szCur] = NULL;
+ execv(cmd, args);
+ exit(-5);
+ } else if (child != -1) {
+ int retval = 0;
+ waitpid(child, &retval, 0);
+ return retval;
+ }
+ return -6;
+}
+
+static int exec_cmd(size_t i, char* args, size_t szArgs)
+{
+ size_t idx = (size_t)-1;
+ while ( cmds[++idx].path != NULL ) {
+ if (idx == i) {
+ size_t siz = strlen(cmds[idx].path)+szArgs+1;
+ char execbuf[siz+1];
+ memset(&execbuf[0], '\0', siz+1);
+ snprintf(&execbuf[0], siz+1, "%s %s", cmds[idx].path, args);
+ return safe_exec(&execbuf[0]);
+ }
+ }
+ return -7;
+}
+#endif
+
+#ifdef _HAS_MSG
+#define MSGFILE "/tmp/dummyshell.msg"
+#define STRLEN(str) (sizeof(str)/sizeof(str[0]))
+static FILE* msgfile = NULL;
+static void init_msg(void)
+{
+ msgfile = fopen(MSGFILE, "a+");
+ if (!msgfile) {
+ fprintf(stderr, "fopen(\"%s\"): %s\n", MSGFILE, strerror(errno));
+ }
+}
+
+struct __attribute__((__packed__)) msgHdr {
+ uint8_t szFrom;
+ uint8_t szMsg;
+ time_t timestamp;
+};
+
+struct __attribute__((__packed__)) msg {
+ char* from;
+ char* msg;
+};
+
+static int read_msg(struct msgHdr* hdr, struct msg* msg)
+{
+ if (!msgfile) return -1;
+ int ok = 1;
+ size_t rb = 0;
+ if ( (rb = fread(hdr, sizeof(struct msgHdr), 1, msgfile)) == 1 ) {
+ msg->from = calloc(hdr->szFrom+1, sizeof(char));
+ msg->msg = calloc(hdr->szMsg+1, sizeof(char));
+ if ( (rb = fread(&(msg->from[0]), sizeof(char), hdr->szFrom, msgfile)) != hdr->szFrom )
+ ok = 0;
+ if ( (rb = fread(&(msg->msg[0]), sizeof(char), hdr->szMsg, msgfile)) != hdr->szMsg )
+ ok = 0;
+ char newline = 0;
+ if ( (rb = fread(&newline, sizeof(char), 1, msgfile)) != 1 )
+ ok = 0;
+ if (!ok || newline != '\n') {
+ free(msg->from);
+ free(msg->msg);
+ msg->from = NULL;
+ msg->msg = NULL;
+ return -1;
+ }
+ return 0;
+ }
+ return -1;
+}
+
+static int print_msg(void) {
+ struct msgHdr hdr;
+ struct msg msg;
+ memset(&hdr, '\0', sizeof(struct msgHdr));
+ memset(&msg, '\0', sizeof(struct msg));
+ if (read_msg(&hdr, &msg) == 0) {
+ struct tm localtime;
+ struct passwd* pwd = NULL;
+ unsigned long int uid = strtoul(msg.from, NULL, 10);
+ if ( (pwd = getpwuid((uid_t)uid)) ) {
+ free(msg.from);
+ msg.from = strdup(pwd->pw_name);
+ }
+ if (localtime_r(&hdr.timestamp, &localtime) != NULL) {
+ printf("\33[2K\r[%02d-%02d-%04d %02d:%02d:%02d] Message from %s: %s\n", localtime.tm_mday, localtime.tm_mon+1, 1900+localtime.tm_year, localtime.tm_hour, localtime.tm_min, localtime.tm_sec, msg.from, msg.msg);
+ } else {
+ printf("\33[2K\r\aMessage from %s: %s\n", msg.from, msg.msg);
+ }
+ free(msg.from);
+ free(msg.msg);
+ return 0;
+ }
+ return -1;
+}
+
+static int write_msg(char* msg) {
+ char from[6];
+ memset(&from[0], '\0', STRLEN(from));
+ if (snprintf(&from[0], STRLEN(from), "%u", getuid()) > 0) {
+ struct msgHdr hdr;
+ hdr.szFrom = strnlen(from, STRLEN(from));
+ hdr.szMsg = strnlen(msg, UINT8_MAX);
+ hdr.timestamp = time(NULL);
+ char* buf = calloc(sizeof(hdr) + hdr.szFrom + hdr.szMsg + 2, sizeof(char));
+ if (buf) {
+ memcpy(buf, &hdr, sizeof(hdr));
+ memcpy(buf+sizeof(hdr), from, hdr.szFrom);
+ memcpy(buf+sizeof(hdr)+hdr.szFrom, msg, hdr.szMsg);
+ *(buf + sizeof(hdr) + hdr.szFrom + hdr.szMsg) = '\n';
+ int failed = 1;
+ if ( fwrite(buf, sizeof(char), sizeof(hdr)+hdr.szFrom+hdr.szMsg+1, msgfile) == sizeof(hdr)+hdr.szFrom+hdr.szMsg+1)
+ failed = 0;
+ free(buf);
+ return failed;
+ }
+ }
+ return -1;
+}
+#endif
+
#ifdef _HAS_HOSTENT
#define ARP_STRING_LEN 1024
#define ARP_IP_LEN 32
@@ -84,13 +312,14 @@ static void print_nethost(void)
memset(&arpip[0], '\0', ARP_IP_LEN);
}
}
+ fclose(arpCache);
}
}
#endif
#ifdef _HAS_UTMP
#ifndef _GNU_SOURCE
-static size_t
+size_t
strnlen(const char *str, size_t maxlen)
{
const char *cp;
@@ -186,8 +415,11 @@ void SigIntHandler(int signum)
}
#endif
+enum mainState { MS_DEFAULT, MS_MESSAGE, MS_COMMAND };
+
int main(int argc, char** argv)
{
+ enum mainState state = MS_DEFAULT;
struct timeval tv;
tv.tv_sec = 1;
tv.tv_usec = 0;
@@ -195,6 +427,45 @@ int main(int argc, char** argv)
#ifdef _HAS_SIGNAL
signal(SIGINT, SigIntHandler);
#endif
+ size_t inputsiz = 0, absiz = UINT8_MAX;
+ struct winsize wsiz;
+ ioctl(0, TIOCGWINSZ, &wsiz);
+ if (wsiz.ws_col < absiz)
+ absiz = wsiz.ws_col - 3;
+ char inputbuf[absiz+1];
+ memset(&inputbuf[0], '\0', absiz+1);
+#ifdef _HAS_MSG
+ init_msg();
+ if (argc > 1) {
+ const char optRmsg[] = "readmsg";
+ const char optWmsg[] = "writemsg";
+ const char optNofollow[] = "-n";
+ if (strncmp(argv[1], optRmsg, STRLEN(optRmsg)) == 0) {
+ if (argc == 2) while (doLoop) {
+ if (print_msg() != 0)
+ sleep(1);
+ } else if (argc == 3) {
+ if (strncmp(argv[2], optNofollow, STRLEN(optNofollow)) == 0) {
+ while (print_msg() == 0) {}
+ } else {
+ fprintf(stderr, "%s readmsg [-n]\n", argv[0]);
+ return 1;
+ }
+ }
+ return 0;
+ } else if (strncmp(argv[1], optWmsg, STRLEN(optWmsg)) == 0) {
+ if (argc == 3) {
+ return write_msg(argv[2]);
+ } else {
+ fprintf(stderr, "%s writemsg msg\n", argv[0]);
+ }
+ return 0;
+ } else {
+ fprintf(stderr, "usage: %s [readmsg [-n] | writemsg msg]\n", argv[0]);
+ return 1;
+ }
+ }
+#endif
#ifdef _HAS_SYSINFO
init_cpuusage();
#endif
@@ -212,7 +483,7 @@ int main(int argc, char** argv)
time_t start = time(NULL);
time_t cur;
unsigned char mins = 0, hrs = 0;
- while (1) {
+ while (doLoop > 0) {
cur = time(NULL);
double diff = difftime(cur, start);
#if defined(_HAS_UTMP) || defined(_HAS_SYSINFO)
@@ -237,36 +508,104 @@ int main(int argc, char** argv)
#endif
}
#endif
- printf("\r--- %02d:%02d:%02d ---%s", hrs, mins, ((unsigned int)diff % 60), keymsg);
+#ifdef _HAS_MSG
+ while (print_msg() == 0) {}
+#endif
+ switch (state) {
+ case MS_DEFAULT:
+ printf("\r--- %02d:%02d:%02d ---%s", hrs, mins, ((unsigned int)diff % 60), keymsg);
+ break;
+ case MS_MESSAGE:
+ case MS_COMMAND:
+#if defined(_HAS_MSG) || defined(_HAS_CMD)
+ printf("\33[2K\r> %s", inputbuf);
+#endif
+ break;
+ }
fflush(stdout);
- fflush(stdin);
+
FD_ZERO(&fds);
FD_SET(STDIN_FILENO, &fds);
int ret = select(FD_SETSIZE, &fds, NULL, NULL, &tv);
if (doLoop == 1 && ret == 0) {
tv.tv_sec = 1;
tv.tv_usec = 0;
- } else {
+ } else if (FD_ISSET(STDIN_FILENO, &fds)) {
+ char key = getchar();
+ switch (state) {
+ case MS_DEFAULT:
+ switch ( key ) {
+ case 'q':
#ifdef _HAS_SIGNAL
- signal(SIGINT, SIG_IGN);
+ signal(SIGINT, SIG_IGN);
#endif
- printf("quit in 3 .. ");
- fflush(stdout);
- sleep(1);
- printf("2 .. ");
- fflush(stdout);
- sleep(1);
- printf("1 .. ");
- fflush(stdout);
- sleep(1);
- printf("\n");
- break;
+ printQuitLoop();
+ break;
+ case 'm':
+#ifdef _HAS_MSG
+ state = MS_MESSAGE;
+#else
+ printf("<feature disabled>\n");
+#endif
+ break;
+ case 'c':
+#ifdef _HAS_CMD
+ print_cmds();
+ state = MS_COMMAND;
+#else
+ printf("<feature disabled>\n");
+#endif
+ break;
+ default: printf("unknown key: %c\n", key); break;
+ }
+ break;
+ case MS_COMMAND:
+ case MS_MESSAGE:
+ switch (readInput(&inputbuf[0], &inputsiz, absiz, key, 0)) {
+ case '\n':
+ if (state == MS_MESSAGE) {
+#ifdef _HAS_MSG
+ printf("\33[2K\rSending message(%lu): %s\n", (long unsigned int)inputsiz, inputbuf);
+ if (write_msg(inputbuf) != 0)
+ printf("Sending failed.\n");
+#endif
+ } else if (state == MS_COMMAND) {
+#ifdef _HAS_CMD
+ int inputFail = 0;
+ if (inputsiz < 3) {
+ inputFail++;
+ } else {
+ char* endptr = NULL;
+ unsigned long int tmpi = strtoul(inputbuf, &endptr, 10);
+ if (*endptr == ' ') {
+ endptr++;
+ printf("\33[2K\rExec CMD #%lu with args: %s\n", tmpi, endptr);
+ int retval;
+ switch ( (retval = exec_cmd(tmpi, endptr, strlen(endptr))) ) {
+ case -7: printf("unknown cmd #%lu\n", tmpi); break;
+ case -6: printf("fork error cmd #%lu\n", tmpi); break;
+ case -5: printf("execute cmd #%lu\n", tmpi); break;
+
+ case 0: break;
+ default: printf("Something went wrong, child returned: %d\n", retval); break;
+ }
+ } else inputFail++;
+ }
+ if (inputFail > 0)
+ printf("\33[2K\rFORMAT: [cmd#] [params]\n");
+#endif
+ }
+ state = MS_DEFAULT;
+ readInput(&inputbuf[0], &inputsiz, absiz, 0, I_CLEARBUF);
+ break;
+ }
+ fflush(stdout);
+ break;
+ }
}
- if (FD_ISSET(STDIN_FILENO,&fds)) break;
}
while (getchar() != EOF) {}
tcsetattr( STDIN_FILENO, TCSANOW, &oldt);
-
return 0;
}