#include #include #include #include #include #include #include #include #include #define NAME "simplestatus" typedef struct module { char *mod_name; int refresh; int signal; struct module *next; } module; typedef struct cache { char *mod_name; char *data; struct cache *next; } cache; const int alloc_inc = 30; const char module_text[] = "module"; const char order_text[] = "order"; const char format_text[] = "format"; char *format_string = NULL; module *table = NULL; cache *mcache = NULL; void llprintf(char *fmt) { int length = strlen(fmt); cache *ptr = mcache; ptr = mcache; for(int i = 0; i < length; i++) { if(fmt[i] == '&') { fprintf(stdout, "%s", ptr->data); ptr = ptr->next; } else { fprintf(stdout, "%c", fmt[i]); } } fprintf(stdout, "\n"); fflush(stdout); } char *get_conf_dir(void) { /* check if $XDG_CONFIG_DIR is set */ char *rootdir, *append; if((rootdir = getenv("XDG_CONFIG_DIR"))) { append = "/"NAME"/"; } else if((rootdir = getenv("HOME"))) { append = "/.config/"NAME"/"; } else { return NULL; } char *buffer = malloc(strlen(rootdir) + strlen(append) + 1); strcpy(buffer, rootdir); strcat(buffer, append); return buffer; } char *execstdout(char *file, char *arg[], char *env[]) { int pfds[2]; if(pipe(pfds) == -1) { perror("PIPE"); fprintf(stderr, "pipe failed! aborting.\n"); abort(); } int pid = fork(); if(pid == -1) { fprintf(stderr, "fork failed! aborting.\n"); abort(); } else if(pid == 0) { if(close(1) == -1) exit(0); if(dup(pfds[1]) == -1) exit(0); if(close(pfds[0])) exit(0); execlp(file, file, NULL); } else { wait(NULL); int bufsize = alloc_inc, total = 0; char *buf = malloc(bufsize); if(!buf) { fprintf(stderr, "malloc failed! aborting.\n"); abort(); } for(;;) { int size = read(pfds[0], buf + total, alloc_inc); if(size == -1) { if(errno == EINTR) { continue; } else { free(buf); return NULL; } } total += size; if(size == alloc_inc) { /* we need to reallocate */ buf = realloc(buf, (bufsize *= 2)); if(!buf) { fprintf(stderr, "realloc failed! aborting.\n"); abort(); } continue; } buf[total] = '\0'; buf = realloc(buf, strlen(buf)); return buf; } close(pfds[0]); } } char *read_line(FILE *fp) { int size = 30; int filled = 0; int c; char *buf = malloc(size); while(c = fgetc(fp)) { if(c == EOF) { if(filled == 0) { free(buf); return NULL; } else { break; } } if(c == '\n') break; if(size == filled) { buf = realloc(buf, (size *= 2)); } buf[filled] = c; filled++; } buf[filled] = '\0'; return buf; } module *parse_file(char *file) { FILE *fp = fopen(file, "r"); char *cline; module *current = NULL, *head = NULL; int linenumber = 0; while((cline = read_line(fp)) != NULL) { linenumber++; /* free the string up here */ if(strlen(cline) == 0) { free(cline); continue; } if(cline[0] == '#') { free(cline); continue; } char *command = strdup(strtok(cline, " ")); if(!memcmp(command, module_text, sizeof module_text)) { if(current == NULL) { current = malloc(sizeof *current); head = current; current->next = NULL; } else { current->next = malloc(sizeof *current); current = current->next; current->next = NULL; } /* get the module name */ char *token = strtok(NULL, " "); if(!token) { fprintf(stderr, "syntax error at line %i: specify a module name!\n", linenumber); return NULL; } current->mod_name = strdup(token); /* get the signal number */ token = strtok(NULL, " "); if(!token) { fprintf(stderr, "syntax error at line %i: specify the signal number!\n", linenumber); return NULL; } current->signal = atoi(token); /* get the refresh duration */ token = strtok(NULL, " "); if(!token) { fprintf(stderr, "syntax error at line %i: specify the refresh duration!\n", linenumber); return NULL; } current->refresh = atoi(token); free(cline); continue; } else if(!memcmp(command, order_text, sizeof order_text)) { if(mcache) { fprintf(stderr, "syntax error at line %i: you can't issue the order command twice\n", linenumber); return NULL; } char *token; cache *ptr = mcache; while(token = strtok(NULL, " ")) { if(mcache) { ptr->next = malloc(sizeof *mcache); ptr = ptr->next; } else { mcache = malloc(sizeof mcache); ptr = mcache; } ptr->mod_name = token; ptr->data = NULL; ptr->next = NULL; } } else if(!memcmp(command, format_text, sizeof format_text)) { char *pattern = cline + sizeof format_text; format_string = strdup(pattern); } } return head; } int is_dir(char *dir) { struct stat sb; if(stat(dir, &sb) == 0 && S_ISDIR(sb.st_mode)) { return 1; } else { return 0; } } void sighandler(int sig) { module *ptr = table; char *mod = NULL; while(ptr) { if(ptr->signal == sig) { mod = ptr->mod_name; char *path = malloc(strlen(mod) + 3); strcpy(path, "./"); strcat(path, mod); char *output = execstdout(path, NULL, NULL); free(path); cache *ptr2 = mcache; while(ptr2) { if(!memcmp(mod, ptr2->mod_name, strlen(mod))) { ptr2->data = output; break; } ptr2 = ptr2->next; } } ptr = ptr->next; } } void sighandler_w(int sig) { sighandler(sig); llprintf(format_string); } void create_sighandle_from_table(void) { module *ptr = table; struct sigaction *action = malloc(sizeof *action); action->sa_handler = sighandler_w; sigemptyset(&(action->sa_mask)); action->sa_flags = 0; while(ptr) { sigaction(ptr->signal, action, NULL); sighandler(ptr->signal); /* force an update */ ptr = ptr->next; } } int main(void) { char *conf_dir = get_conf_dir(); if(!is_dir(conf_dir)) { fprintf(stderr, "create configuration at %s and try again\n", conf_dir); exit(1); } chdir(conf_dir); table = parse_file("config"); create_sighandle_from_table(); llprintf(format_string); int counter = 0; for(;;) { module *ptr = table; counter++; sleep(1); while(ptr) { if(counter % ptr->refresh == 0) { sighandler_w(ptr->signal); } ptr = ptr->next; } } return 0; }