summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHaoran S. Diao <0@hairydiode.xyz>2019-04-13 09:50:01 -0400
committerHaoran S. Diao <0@hairydiode.xyz>2019-04-13 09:50:01 -0400
commitc1b2102cabf95758b1d2ecb5c793730633fee3b7 (patch)
tree409ec9dd464f2a7e6a726084e704e658592e5d51
initial commit
-rw-r--r--.gitignore1
-rw-r--r--Makefile2
-rw-r--r--guardian.c421
-rw-r--r--templates/kitty5
-rw-r--r--templates/trees13
5 files changed, 442 insertions, 0 deletions
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<stdio.h>
+#include<stdlib.h>
+#include<string.h>
+#include<ctype.h>
+#include <sys/types.h>
+#include <dirent.h>
+/* 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 = <ESC>
+ * <ESC>7 saves cursor and attributes
+ * <ESC>8 restores
+ * <ESC>[0;0H homes the cursor
+ * <ESC>[?47h
+ * <ESC>[?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 @@
+ /\
+ / _\ ################################### ^
+ / \ /\ ################################### / \
+ /_ _\ /\ /_ \ ################################### /_ _\
+ / \ /_ \ / \ ################################### / \
+ /_ _\ / \ /_ _\\ ^ ^ /_ _\
+ / \ /_ _\/ \ \ /_\ /\ / \ / \
+/________\ / /_ _\\ / \ /_ \ /_ _\ /_ _\
+ |@| /_____/ \_\ /___\/ \ / \ / \
+ |@| ||/________\ | /_ _\ /_____\ /_________\
+,.,|@|,,,....||.,.|@|.,|..,,.,...||,.,.,.|@|,....,. .,.,.,|@|,.,.,.,.
+^.,.,.^,,^,.,^.,^.|@|,^.^.,..^,^,||.^.,^,|@|,.,.,.,~~~~~~~~~~~~~,,,..|@|,.^..^,.
+...,,,,.^.,.,,^,.....,,^,.,,.,.,.,.,,,^....,,,...,,.~~~~~~~~~~~~~~~........^.,,.