From c1b2102cabf95758b1d2ecb5c793730633fee3b7 Mon Sep 17 00:00:00 2001 From: "Haoran S. Diao" <0@hairydiode.xyz> Date: Sat, 13 Apr 2019 09:50:01 -0400 Subject: initial commit --- .gitignore | 1 + Makefile | 2 + guardian.c | 421 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ templates/kitty | 5 + templates/trees | 13 ++ 5 files changed, 442 insertions(+) create mode 100644 .gitignore create mode 100644 Makefile create mode 100644 guardian.c create mode 100644 templates/kitty create mode 100644 templates/trees diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..41567ab --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +guardian diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..3c206cc --- /dev/null +++ b/Makefile @@ -0,0 +1,2 @@ +guardian : guardian.c + gcc guardian.c -o guardian diff --git a/guardian.c b/guardian.c new file mode 100644 index 0000000..0e6d93c --- /dev/null +++ b/guardian.c @@ -0,0 +1,421 @@ +#include +#include +#include +#include +#include +#include +/* struct describing the various templates that alerts can use + * these are loaded from /etc/squishy + */ +struct template { + //Name of template + char * name; + /* The actual template, '#' represents characters that could be + * overridden w/ the message this is normalized at read time so that + * lines will always end with \n\r, otherwise the alert becomes + * misaligned even on systems where lines don't typically end with \r + */ + char * template; + /* + *Whether or not the template contains color escape sequences. + * 0 is none; 1 is 16 color; 2 is 256bit color + */ + unsigned int color; + /* len of name and template, including trailing '\0' + * + */ + unsigned int name_len; + unsigned int template_len; +}; +/* + * GLOBAL VARIABLES, collection of templates and the length of that array + */ +struct template * * templates; +unsigned int templates_len = 0; +/* + * Reads alert template from file, returns null on failure, otherwise returns + * pointer to the template w/ all data already allocated by the function + */ +struct template * read_template(char * path) { + /* file the template is stored in + * The encoding scheme does not matter + * \n, \n\r, or \r endings will be normalized to \n\r + */ + FILE * template_file; + /* + * Pointer to the template that should be returned + */ + struct template * tmp; + template_file = fopen(path, "r"); + if (template_file == NULL) { + fprintf(stderr,"Error reading from template file \"%s\"\n",path); + return NULL; + } + /* + * Allocation of the template struct + */ + tmp = (struct template *)malloc(sizeof(struct template)); + if (tmp == NULL) { + fprintf(stderr,"Error allocating memory for template \"%s\" of \ + size %d bytes\n", path, sizeof(struct template)); + return NULL; + } + /* + * Length of template name string and first character of that string in + * the string 'path' + */ + int namelen = 0; + int parsepos = 0; + /* + * Byte for storing each character of path as it is being scanned + */ + char pathchar; + /* finds the length of the slice of 'path' containing the filename, + * inclusive of the trailing '\0'. Since it always tries get atleast the + * first character of 'path', we have to make sure 'path' is not null, + * although if this were the case fopen() above should have returned + * null before it reaches this point. + */ + if (path == NULL) { + fprintf(stderr, "NULL path in reading of template\n"); + return NULL; + } + do { + pathchar = *(path +parsepos); + if (pathchar == '/' ) { + namelen = 0; + } else { + namelen++; + } + parsepos++; + } while (pathchar != '\0'); + /* as parselen is the position of '\0' + 1, we want it is the total + * length of path including the trailing '\0' + * Therefore to get the position of the first byte of a slice of length + * 'namelen' including the \0 would be parsepos - namelen + */ + tmp->name = malloc(namelen * sizeof(char)); + if (tmp->name == NULL ) { + fprintf(stderr, "Error allocating memory for template name\n"); + return NULL; + } + strncpy(tmp->name, path+ (parsepos - namelen), namelen * sizeof(char)); + //Name length + tmp->name_len = namelen; + /* + * The variable that each byte stored from the stream is stored in + */ + char readbyte; + /* + * allocates initial char, which will be the trailing '\0' + */ + tmp->template = malloc(1 * sizeof(char)); + tmp->template[0] = '\0'; + //size of template including trailign '\0' + int t_size = 1; + /* + * Loop goes through every character, reallocates tmp->template to + * t_size + 1, then set new t_size -2 to that character, while + * also setting t_size - 1 to '\0', thereby preserving the + * trailing '\0'. + * as the EOF is checked after each iteration, EOF is guaranteed to be + * a part of the string. + */ + do { + readbyte = (char)fgetc(template_file); + tmp->template = realloc(tmp->template, sizeof(char) *(t_size +1)); + if (tmp->template == NULL) { + return NULL; + } + t_size++; + tmp->template[t_size - 2] = readbyte; + tmp->template[t_size - 1] = '\0'; + /* + * If the byte is '\n' it will iterate more, since EOF is + * checked afterwards anyways, This doesn't matter. + */ + if (readbyte == '\n') { + readbyte = (char)fgetc(template_file); + if (readbyte != '\r') { + tmp->template = realloc(tmp->template, + sizeof(char) * (t_size + 1)); + if (tmp->template == NULL) { + return NULL; + } + t_size++; + tmp->template[t_size - 2] = readbyte; + tmp->template[t_size - 1] = '\0'; + } else { + tmp->template = realloc(tmp->template, + sizeof(char) * (t_size + 2)); + if (tmp->template == NULL) { + return NULL; + } + t_size = t_size + 2; + tmp->template[t_size - 3] = '\r'; + tmp->template[t_size - 2] = readbyte; + tmp->template[t_size - 1] = '\0'; + } + } + } while (readbyte != (char)EOF); + /* + * Removes EOF before '\0' + */ + tmp->template = realloc(tmp->template, t_size - 1); + if (tmp->template == NULL) { + return NULL; + } + t_size--; + tmp->template[t_size -1 ] = '\0'; + //Template Length + tmp->template_len = t_size; + /* + * Closes template_file + */ + fclose(template_file); + return tmp; +} +/* + * Prints out an alert message to pts device file output, using message-template + * as the template and message as the message + * beep causes it to play the bell-char at the end if it is != 0 + * beep is not a bool because C80/C90 compatibility is important + */ +int alert (FILE * output, struct template * message_template, char * message, int beep) { + /* alert is the string that will eventually be printed + * assuming template_len will never be 0 + */ + char * alert = malloc(message_template->template_len * sizeof(char)); + if (alert == NULL) { + fprintf(stderr, "Error Memory Allocation in alert()\n"); + return -1; + } + /* + * Copies ->template into alert + */ + strncpy(alert, message_template->template, + message_template->template_len * sizeof(char)); + //index of bytes in template + unsigned int i = 0; + //index of bytes in message + unsigned int m_i = 0; + //boolean for determining whether 'message' has reached it's end + short m_end = 0; + /* loop through alert and try to fill '#' with either message or space + * This excludes the trailing '\0' + */ + while (i < (message_template->template_len-1)) { + if (alert[i] == '#') { + if (!m_end) { + /* + * Handles breaking text by inserting a "-"/' ' + * If this next character is not a #, then there is a + * break. If the next cahracter in 'message' is + * [A-Z][a-z] then we insert the break + * This will apply even if message[m_i] is at + * the end of the string as message[m_i+1] would + * be the trailing '\0' + * The same applies to alert[i+1]; + */ + if ((alert[i+1] != '#') && + (isalpha(message[m_i+1])) && + isalpha(message[m_i]) ) { + /* + * If the current message[m_i] and the + * previous messae[m_i-1] are alpha + * then we use dashes, otherwise it is + * replaced with a ' ' + */ + if (message[m_i] == 0) { + alert[i] = ' '; + } else if(isalpha(message[m_i-1])) { + alert[i] = '-'; + } else { + alert[i] = ' '; + } + } else { + alert[i] = message[m_i]; + m_i++; + if (message[m_i] == '\0') { + m_end = 1; + } + } + } else { + alert[i] = ' '; + } + } + i++; + } + /* actually prints the alert string + * \033 = + * 7 saves cursor and attributes + * 8 restores + * [0;0H homes the cursor + * [?47h + * [?47l + */ + fprintf(output,"\0337\033[0;0H%s\0338",alert); + /* the below loads an alternative buffer, this is deprecated*/ + //fprintf(output,"\033[?47h%s\033[?47l",alert); + if (beep) { + fprintf(output, "\a"); + } + return 0; +} +/* + * Concatenates two strings and returns the result as a heap allocated string + * Returns null on failure + */ +char * str_concat(char * s1, char * s2) { + char * return_str; + /* + * since strlen does not count the trailing '\0', we need to add one + */ + return_str = malloc((strlen(s1) + 1 + strlen(s2)) * sizeof(char) ); + if (return_str == NULL) { + fprintf(stderr,"Failure to allocate memory in str_concat()\n"); + return NULL; + } + /* + * copies the nonnull bytes of s1 + */ + strncpy(return_str,s1,sizeof(char) * strlen(s1)); + /* + * Copies the nonnull bytes of s2, which begin at strlen(s1) since that + * is the offset from the beginning of s1 where the null byte of s1 + * would be + */ + strncpy((return_str + strlen(s1)),s2,sizeof(char) * strlen(s2)); + /* + * Add trailing '\0' + */ + strncpy(return_str + strlen(s1) + strlen(s2) ,"\0", sizeof(char) * 1); + return return_str; +} +struct template * * load_templates() { + /*ensures that templates is alteast 1 element big*/ + struct template * * templates = (struct template * *)malloc(sizeof(struct template * )); + /*opens templates dir*/ + DIR * templates_dir = opendir("templates"); + if (templates_dir == NULL) { + return NULL; + } + /* + * Structs storing the current loaded template and current directory + * entry + */ + struct template * tem; + struct dirent * entry; + /* the loop keeps reading until entry is nyll, since the evaluation is + * at the end, a switch has to ensure that no attempts to handle entry + * == NULL are made + */ + do { + entry = readdir(templates_dir); + if (entry != NULL && entry->d_name[0] != '.') { + /* since d_name is just the name of the file and we want + * the full path + */ + char * fullpath = str_concat("templates/", + entry->d_name); + if (fullpath == NULL) { + return NULL; + } + /* + * Load the template + */ + tem = read_template(fullpath); + //free heap allocated string ASAP + free(fullpath); + if ( tem == NULL ) { + return NULL; + } + /*resizing templates*/ + templates_len++; + templates = (struct template * *)realloc(templates, + templates_len * sizeof(struct template * )); + if (templates == NULL) { + return NULL; + } + templates[templates_len - 1] = tem; + } + + } while (entry != NULL); + /* + * Close the templates directory + */ + closedir(templates_dir); + return templates; +} +int broadcast(char * template_name, char * message) { + struct template * tm = NULL; + /* + * loops through for the appropriate template + */ + for (int i = 0; i < templates_len; i++) { + if (strcmp(templates[i]->name,template_name) == 0 ) { + tm = templates[i]; + } + } + /* + * if none are found then tm is still null and can not proceed + */ + if (tm == NULL) { + fprintf(stderr, "unable to find template %s",template_name); + return -1; + } + /* + * Directory pts contains all pseudo-terminal devices. + * All terminals will have an alert sent to them. + */ + DIR * pts_dir = opendir("/dev/pts"); + if (pts_dir == NULL ) { + return -1; + } + /* + * for storing the current dirent and pseudotty file + */ + struct dirent * pts_entry; + FILE * pts; + do { + pts_entry = readdir(pts_dir); + /* + * Makes sure it's not readin from the ptmx device, a hidden + * file, or NULL + */ + if ( pts_entry != NULL && + pts_entry->d_name[0] != '.' && + strcmp(pts_entry->d_name, "ptmx") != 0) { + /* + * Gets full path + */ + char * fullpath = str_concat("/dev/pts/", + pts_entry->d_name); + /* + * opens file in append mode, these are the only + * permissions we need + */ + pts = fopen(fullpath, "a"); + if (pts == NULL) { + fprintf(stderr, "unable to open file %s\n", + fullpath); + return -1; + } + /*frees heap allocated string*/ + free(fullpath); + alert(pts,tm,message,1); + /*closes file*/ + fclose(pts); + } + } while (pts_entry != NULL); +} +int main (int argc, char * argv[]) { + templates = load_templates(); + if (templates == NULL) { + return -1; + } + if (broadcast(argv[1],argv[2])) { + return -1; + } +} + diff --git a/templates/kitty b/templates/kitty new file mode 100644 index 0000000..f759f91 --- /dev/null +++ b/templates/kitty @@ -0,0 +1,5 @@ + ^-^ +------------+ +('.') ---|############| +/|o|\ |############| + |-| +------------+ + | | diff --git a/templates/trees b/templates/trees new file mode 100644 index 0000000..35de4fb --- /dev/null +++ b/templates/trees @@ -0,0 +1,13 @@ + /\ + / _\ ################################### ^ + / \ /\ ################################### / \ + /_ _\ /\ /_ \ ################################### /_ _\ + / \ /_ \ / \ ################################### / \ + /_ _\ / \ /_ _\\ ^ ^ /_ _\ + / \ /_ _\/ \ \ /_\ /\ / \ / \ +/________\ / /_ _\\ / \ /_ \ /_ _\ /_ _\ + |@| /_____/ \_\ /___\/ \ / \ / \ + |@| ||/________\ | /_ _\ /_____\ /_________\ +,.,|@|,,,....||.,.|@|.,|..,,.,...||,.,.,.|@|,....,. .,.,.,|@|,.,.,.,. +^.,.,.^,,^,.,^.,^.|@|,^.^.,..^,^,||.^.,^,|@|,.,.,.,~~~~~~~~~~~~~,,,..|@|,.^..^,. +...,,,,.^.,.,,^,.....,,^,.,,.,.,.,.,,,^....,,,...,,.~~~~~~~~~~~~~~~........^.,,. -- cgit v1.1