diff options
author | toni <matzeton@googlemail.com> | 2017-01-06 19:26:27 +0100 |
---|---|---|
committer | toni <matzeton@googlemail.com> | 2017-01-06 19:26:27 +0100 |
commit | 71db2f9ecf7f33014ce02a44f6aa0db01e616fba (patch) | |
tree | 2049535148fe80a256c765d044953a7f2fadd4fa | |
parent | eb05457fdc59b2dceca5a09e3572e424008a8b66 (diff) |
interactive dummyshell
-rw-r--r-- | dummyshell.c | 397 |
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; } |