Hot reloading + state saving
This commit is contained in:
		
							parent
							
								
									3b68f2dfda
								
							
						
					
					
						commit
						a4e73470e2
					
				
							
								
								
									
										6
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										6
									
								
								Makefile
									
									
									
									
									
								
							| 
						 | 
				
			
			@ -3,13 +3,13 @@ CC=gcc
 | 
			
		|||
CCARGS=-Isrc/include -Wall -pedantic
 | 
			
		||||
 | 
			
		||||
MODULES= \
 | 
			
		||||
		modules/clock.dim \
 | 
			
		||||
		modules/battery.dim\
 | 
			
		||||
		modules/clock.dim   \
 | 
			
		||||
		modules/battery.dim
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
all: $(BIN) $(MODULES) compile_commands.json
 | 
			
		||||
 | 
			
		||||
$(BIN): src/main.c src/plug.c
 | 
			
		||||
$(BIN): src/main.c src/plug.c src/socket.c src/util.c
 | 
			
		||||
	$(CC) -o $@ $^ $(CCARGS) -lX11 -ldl
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -5,28 +5,31 @@
 | 
			
		|||
#include <stddef.h>
 | 
			
		||||
#include <stdbool.h>
 | 
			
		||||
 | 
			
		||||
typedef void (*plug_init_f) (void);
 | 
			
		||||
typedef void (*plug_reload_f) (void);
 | 
			
		||||
typedef void (*plug_poll_f) (char*, size_t);
 | 
			
		||||
typedef void (*plug_free_f) (void);
 | 
			
		||||
typedef void* (*plug_init_f)        (void);
 | 
			
		||||
typedef void* (*plug_pre_reload_f)  (void);
 | 
			
		||||
typedef void  (*plug_post_reload_f) (void*);
 | 
			
		||||
typedef void  (*plug_poll_f)        (char*, size_t);
 | 
			
		||||
typedef void  (*plug_free_f)        (void);
 | 
			
		||||
 | 
			
		||||
typedef struct plug_t {
 | 
			
		||||
    char* name;
 | 
			
		||||
    char* version;
 | 
			
		||||
    bool is_ready;
 | 
			
		||||
} plug_t;
 | 
			
		||||
 | 
			
		||||
typedef struct plug_int_t {
 | 
			
		||||
    plug_init_f f_init;
 | 
			
		||||
    plug_reload_f f_reload;
 | 
			
		||||
    char* path;
 | 
			
		||||
    plug_init_f f_init; 
 | 
			
		||||
    plug_pre_reload_f f_pre_reload;
 | 
			
		||||
    plug_post_reload_f f_post_reload;
 | 
			
		||||
    plug_poll_f f_poll;
 | 
			
		||||
    plug_free_f f_free;
 | 
			
		||||
    plug_t* s_plug_info;
 | 
			
		||||
    plug_t* state;
 | 
			
		||||
} plug_int_t;
 | 
			
		||||
 | 
			
		||||
void setup_plugins(char* plugin_path);
 | 
			
		||||
char* poll_plugins(char* sep);
 | 
			
		||||
void free_plugins(void);
 | 
			
		||||
void reload_plugins(void);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										19
									
								
								src/include/socket.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								src/include/socket.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,19 @@
 | 
			
		|||
 | 
			
		||||
#ifndef _H_SOCKET
 | 
			
		||||
#define _H_SOCKET
 | 
			
		||||
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#include <sys/socket.h>
 | 
			
		||||
#include <sys/un.h>
 | 
			
		||||
 | 
			
		||||
typedef enum sock_msg_t{
 | 
			
		||||
    SM_NONE   = 0,
 | 
			
		||||
    SM_RELOAD = 1,
 | 
			
		||||
} sock_msg_t;
 | 
			
		||||
 | 
			
		||||
int socket_init(void);
 | 
			
		||||
sock_msg_t socket_poll(void);
 | 
			
		||||
void socket_close(void);
 | 
			
		||||
void socket_send(char*);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										9
									
								
								src/include/util.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								src/include/util.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,9 @@
 | 
			
		|||
 | 
			
		||||
#ifndef _H_UTIL
 | 
			
		||||
#define _H_UTIL
 | 
			
		||||
 | 
			
		||||
void to_lowercase(char* str);
 | 
			
		||||
void to_uppercase(char* str);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										57
									
								
								src/main.c
									
									
									
									
									
								
							
							
						
						
									
										57
									
								
								src/main.c
									
									
									
									
									
								
							| 
						 | 
				
			
			@ -2,9 +2,39 @@
 | 
			
		|||
#include <stdlib.h>
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#include "plug.h"
 | 
			
		||||
#include <signal.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
 | 
			
		||||
#include "plug.h"
 | 
			
		||||
#include "socket.h"
 | 
			
		||||
 | 
			
		||||
void interrupt_handler(int);
 | 
			
		||||
void print_help(void);
 | 
			
		||||
 | 
			
		||||
int main(int argc, char** argv) {
 | 
			
		||||
    signal(SIGINT, interrupt_handler);
 | 
			
		||||
 | 
			
		||||
    if (argc > 1) {
 | 
			
		||||
        if (strcmp(argv[1], "send") == 0) {
 | 
			
		||||
            if (argc == 3) {
 | 
			
		||||
                socket_send(argv[2]);
 | 
			
		||||
                return 0;
 | 
			
		||||
            } else {
 | 
			
		||||
                print_help();
 | 
			
		||||
                return 1;
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            print_help();
 | 
			
		||||
            printf("ERROR: Unknown subcommand\n");
 | 
			
		||||
            return 1;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    if (socket_init() != 0) {
 | 
			
		||||
        return 1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
int main(void) {
 | 
			
		||||
    setup_plugins("./modules");
 | 
			
		||||
    char* buffer;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -12,6 +42,15 @@ int main(void) {
 | 
			
		|||
    Window window = DefaultRootWindow(display);
 | 
			
		||||
 | 
			
		||||
    while (1) {
 | 
			
		||||
        sock_msg_t msg = socket_poll();
 | 
			
		||||
 | 
			
		||||
        switch (msg) {
 | 
			
		||||
            case SM_RELOAD: {
 | 
			
		||||
                reload_plugins();
 | 
			
		||||
            } break;
 | 
			
		||||
            case SM_NONE: break;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        buffer = poll_plugins("|");
 | 
			
		||||
        XStoreName(display, window, buffer);
 | 
			
		||||
        XFlush(display);
 | 
			
		||||
| 
						 | 
				
			
			@ -24,3 +63,17 @@ int main(void) {
 | 
			
		|||
  return 0;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void interrupt_handler(int sig) {
 | 
			
		||||
    (void) sig;
 | 
			
		||||
    printf("\nCaught SIGINT, exiting\n");
 | 
			
		||||
    free_plugins();
 | 
			
		||||
    socket_close();
 | 
			
		||||
    exit(0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void print_help(void) {
 | 
			
		||||
    printf("Usage: dim [command]\n");
 | 
			
		||||
    printf("Commands:\n");
 | 
			
		||||
    printf("    send [MESSAGE] - Sends a message, available messages: [reload]\n");
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,44 +1,61 @@
 | 
			
		|||
#include "plug.h"
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
plug_t PLUG = {0};
 | 
			
		||||
#include <assert.h>
 | 
			
		||||
#include <stdbool.h>
 | 
			
		||||
 | 
			
		||||
typedef struct plug_t {
 | 
			
		||||
    char* name;
 | 
			
		||||
    char* version;
 | 
			
		||||
    FILE* fp;
 | 
			
		||||
} plug_t;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static plug_t* p = {0};
 | 
			
		||||
 | 
			
		||||
static FILE* fp = NULL;
 | 
			
		||||
 | 
			
		||||
char* batt_files[] = {
 | 
			
		||||
    "/sys/class/power_supply/BAT0/capacity",
 | 
			
		||||
    "/sys/class/power_supply/BAT1/capacity"
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
void plug_init(void) {
 | 
			
		||||
    PLUG.name = "Battery";
 | 
			
		||||
    PLUG.version = "0.0.1";
 | 
			
		||||
void* plug_init(void) {
 | 
			
		||||
    p = malloc(sizeof(plug_t));
 | 
			
		||||
    assert(p);
 | 
			
		||||
    p->name = "Battery";
 | 
			
		||||
    p->version = "0.0.1";
 | 
			
		||||
 | 
			
		||||
    for (size_t i = 0; i < sizeof(batt_files)/sizeof(batt_files[0]); i++) {
 | 
			
		||||
        if (access(batt_files[i], F_OK) == 0) {
 | 
			
		||||
            fp = fopen(batt_files[i], "r");
 | 
			
		||||
            if (fp) {
 | 
			
		||||
            p->fp = fopen(batt_files[i], "r");
 | 
			
		||||
            if (p->fp) {
 | 
			
		||||
                printf("Opened %s\n", batt_files[i]);
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (!fp) {
 | 
			
		||||
    if (!p->fp) {
 | 
			
		||||
        printf("MODULE: ERROR: Unable to find battery\n");
 | 
			
		||||
        return;
 | 
			
		||||
        return NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    PLUG.is_ready = true;
 | 
			
		||||
    return p;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void plug_reload(void) { /* Unused */ }
 | 
			
		||||
void* plug_pre_reload(void) {
 | 
			
		||||
    return p;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void plug_post_reload(void* pp) {
 | 
			
		||||
    p = pp;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void plug_poll(char* buf, size_t len) {
 | 
			
		||||
    if (!fp) return;
 | 
			
		||||
    if (!p->fp) return;
 | 
			
		||||
    int perc = 0;
 | 
			
		||||
    fseek(fp, 0, SEEK_SET);
 | 
			
		||||
    fscanf(fp, "%d", &perc);
 | 
			
		||||
    fseek(p->fp, 0, SEEK_SET);
 | 
			
		||||
    fscanf(p->fp, "%d", &perc);
 | 
			
		||||
    snprintf(buf, len, "Batt: %d%%", perc);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,15 +1,33 @@
 | 
			
		|||
#include "plug.h"
 | 
			
		||||
#include <time.h>
 | 
			
		||||
#include <stdbool.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
 | 
			
		||||
plug_t PLUG = {0};
 | 
			
		||||
typedef struct plug_t {
 | 
			
		||||
    char* name;
 | 
			
		||||
    char* version;
 | 
			
		||||
    int i;
 | 
			
		||||
} plug_t;
 | 
			
		||||
 | 
			
		||||
void plug_init(void) {
 | 
			
		||||
    PLUG.name = "time";
 | 
			
		||||
    PLUG.version = "0.0.1";
 | 
			
		||||
    PLUG.is_ready = true;
 | 
			
		||||
 | 
			
		||||
plug_t* p = {0};
 | 
			
		||||
 | 
			
		||||
void* plug_init(void) {
 | 
			
		||||
    p = malloc(sizeof(plug_t));
 | 
			
		||||
    p->name = "time";
 | 
			
		||||
    p->version = "0.0.1";
 | 
			
		||||
    p->i = 0;
 | 
			
		||||
    return p;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void plug_reload(void) { /* Unused */ }
 | 
			
		||||
void* plug_pre_reload(void) {
 | 
			
		||||
    return p;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void plug_post_reload(void* pp) {
 | 
			
		||||
    p = pp;
 | 
			
		||||
    p->i += 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void plug_poll(char* buf, size_t len) {
 | 
			
		||||
    time_t rawtime;
 | 
			
		||||
| 
						 | 
				
			
			@ -17,7 +35,7 @@ void plug_poll(char* buf, size_t len) {
 | 
			
		|||
    
 | 
			
		||||
    time(&rawtime);
 | 
			
		||||
    timeinfo = localtime(&rawtime);
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    strftime(buf, len, "Time: %H:%M (%Y-%m-%d)", timeinfo);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										35
									
								
								src/modules/example.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								src/modules/example.c
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,35 @@
 | 
			
		|||
#include <stdlib.h>
 | 
			
		||||
#include <assert.h>
 | 
			
		||||
 | 
			
		||||
typedef struct plug_t {
 | 
			
		||||
    char* name; // Always keep these on top
 | 
			
		||||
    char* version;
 | 
			
		||||
} plug_t;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static plug_t* p = {0};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void* plug_init(void) {
 | 
			
		||||
    p = malloc(sizeof(plug_t));
 | 
			
		||||
    assert(p);
 | 
			
		||||
    p->name = "example";
 | 
			
		||||
    p->version = "0.0.1";
 | 
			
		||||
    return p;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void* plug_pre_reload(void) {
 | 
			
		||||
    return p; // send state to dim
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void plug_post_reload(void* pp) {
 | 
			
		||||
    p = pp; // get back state
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void plug_poll(char* buf, size_t len) {
 | 
			
		||||
    // print text to `buf` with max len `len`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void plug_free(void) {
 | 
			
		||||
    free(p); // free state
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										79
									
								
								src/plug.c
									
									
									
									
									
								
							
							
						
						
									
										79
									
								
								src/plug.c
									
									
									
									
									
								
							| 
						 | 
				
			
			@ -21,7 +21,7 @@ typedef struct PlugMan {
 | 
			
		|||
static plugman_t PLUGMAN = {0};
 | 
			
		||||
 | 
			
		||||
void* load_plug_sym(void* plug_f, char* fn_name);
 | 
			
		||||
plug_int_t* load_plugin(char* path);
 | 
			
		||||
plug_int_t* load_plugin(char* path, bool);
 | 
			
		||||
 | 
			
		||||
void load_plugins(const char* mod_dir_p) {
 | 
			
		||||
    DIR* dir = {0};
 | 
			
		||||
| 
						 | 
				
			
			@ -56,12 +56,11 @@ void load_plugins(const char* mod_dir_p) {
 | 
			
		|||
        
 | 
			
		||||
        printf("INFO: Found plugin: %s/%s\n", mod_dir_p, dir_entry->d_name);
 | 
			
		||||
 | 
			
		||||
        char full_path[PLUG_MAX_COUNT] = {0};
 | 
			
		||||
        char* full_path = (char*)malloc(sizeof(char)*1028);
 | 
			
		||||
        snprintf(full_path, PLUG_MAX_COUNT, "%s/%s", mod_dir_p, dir_entry->d_name);
 | 
			
		||||
        plug_int_t* plug = load_plugin(full_path);
 | 
			
		||||
        plug_int_t* plug = load_plugin(full_path, true);
 | 
			
		||||
 | 
			
		||||
        if (!plug) {
 | 
			
		||||
            printf("ERROR: Failed to load plugin %s, skipping\n", full_path);
 | 
			
		||||
            continue;
 | 
			
		||||
        }
 | 
			
		||||
        PLUGMAN.plugs[PLUGMAN.plug_count++] = plug;
 | 
			
		||||
| 
						 | 
				
			
			@ -69,8 +68,19 @@ void load_plugins(const char* mod_dir_p) {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
plug_int_t* load_plugin(char* path) {
 | 
			
		||||
plug_int_t* load_plugin(char* path, bool check_duplicates) {
 | 
			
		||||
    if (check_duplicates) {
 | 
			
		||||
        for (size_t i = 0; i < PLUGMAN.plug_count; i++) {
 | 
			
		||||
            plug_int_t* plug = PLUGMAN.plugs[i];
 | 
			
		||||
            if (strcmp(plug->path, path) == 0) {
 | 
			
		||||
                return NULL; // plugin exists
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    plug_int_t* plug = malloc(sizeof(plug_int_t));
 | 
			
		||||
    plug->path = path;
 | 
			
		||||
 | 
			
		||||
    void* plug_f = dlopen(path, RTLD_NOW);
 | 
			
		||||
    
 | 
			
		||||
    if (!plug_f) {
 | 
			
		||||
| 
						 | 
				
			
			@ -82,18 +92,19 @@ plug_int_t* load_plugin(char* path) {
 | 
			
		|||
    #pragma GCC diagnostic push
 | 
			
		||||
    #pragma GCC diagnostic ignored "-Wpedantic"
 | 
			
		||||
    
 | 
			
		||||
    plug->f_init = (plug_init_f)load_plug_sym(plug_f, "plug_init");
 | 
			
		||||
    plug->f_reload = (plug_reload_f)load_plug_sym(plug_f, "plug_reload");
 | 
			
		||||
    plug->f_poll = (plug_poll_f)load_plug_sym(plug_f, "plug_poll");
 | 
			
		||||
    plug->f_free = (plug_free_f)load_plug_sym(plug_f, "plug_free");
 | 
			
		||||
    plug->s_plug_info = (plug_t*)load_plug_sym(plug_f, "PLUG");
 | 
			
		||||
    plug->f_init        = (plug_init_f)        load_plug_sym(plug_f, "plug_init");
 | 
			
		||||
    plug->f_pre_reload  = (plug_pre_reload_f)  load_plug_sym(plug_f, "plug_pre_reload");
 | 
			
		||||
    plug->f_post_reload = (plug_post_reload_f) load_plug_sym(plug_f, "plug_post_reload");
 | 
			
		||||
    plug->f_poll        = (plug_poll_f)        load_plug_sym(plug_f, "plug_poll");
 | 
			
		||||
    plug->f_free        = (plug_free_f)        load_plug_sym(plug_f, "plug_free");
 | 
			
		||||
 | 
			
		||||
    #pragma GCC diagnostic pop
 | 
			
		||||
 | 
			
		||||
    if (!plug->f_init || !plug->f_reload ||
 | 
			
		||||
    if (!plug->f_init || !plug->f_pre_reload ||
 | 
			
		||||
            !plug->f_poll || !plug->f_free ||
 | 
			
		||||
            !plug->s_plug_info) {
 | 
			
		||||
            !plug->f_post_reload) {
 | 
			
		||||
        dlclose(plug_f);
 | 
			
		||||
        printf("ERROR: Failed to find all functions in plugin");
 | 
			
		||||
        return NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -119,8 +130,14 @@ void setup_plugins(char* plugin_path) {
 | 
			
		|||
    for (size_t i = 0; i < PLUGMAN.plug_count; i++) {
 | 
			
		||||
        plug_int_t* plug = PLUGMAN.plugs[i]; 
 | 
			
		||||
 | 
			
		||||
        (plug->f_init)();
 | 
			
		||||
        printf(" - %s (%s)\n", plug->s_plug_info->name, plug->s_plug_info->version);
 | 
			
		||||
        plug->state = (plug->f_init)();
 | 
			
		||||
        
 | 
			
		||||
        if (!plug->state) {
 | 
			
		||||
            printf("Plugin '%s' did not initialise, skipping\n", plug->path);
 | 
			
		||||
            continue;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        printf(" - %s (%s)\n", plug->state->name, plug->state->version);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -147,10 +164,10 @@ char* poll_plugins(char* sep) {
 | 
			
		|||
 | 
			
		||||
    for (size_t i = 0; i < PLUGMAN.plug_count; i++) {
 | 
			
		||||
        plug_int_t* plug = PLUGMAN.plugs[i]; 
 | 
			
		||||
        if (!plug->s_plug_info->is_ready) continue;
 | 
			
		||||
        if (!plug->state) continue;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        printf("Polling plug id %zu\n", i);
 | 
			
		||||
        // printf("Polling plug id %zu\n", i);
 | 
			
		||||
        size_t len = strlen(buf);
 | 
			
		||||
        (plug->f_poll)(buf + len, PLUG_POLL_BUF_SZ - len);
 | 
			
		||||
        
 | 
			
		||||
| 
						 | 
				
			
			@ -160,10 +177,38 @@ char* poll_plugins(char* sep) {
 | 
			
		|||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    printf("Setting title: '%s'\n", buf);
 | 
			
		||||
    // printf("Setting title: '%s'\n", buf);
 | 
			
		||||
 | 
			
		||||
    return buf;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void reload_plugins(void) {
 | 
			
		||||
    void* plug_states[PLUG_MAX_COUNT];
 | 
			
		||||
    size_t plug_count = 0;
 | 
			
		||||
    
 | 
			
		||||
    printf("INFO: Reloading plugins\n");
 | 
			
		||||
    // save states
 | 
			
		||||
    for (size_t i = 0; i < PLUGMAN.plug_count; i++) {
 | 
			
		||||
        plug_int_t* plug = PLUGMAN.plugs[i]; 
 | 
			
		||||
        void* state = (plug->f_pre_reload)();
 | 
			
		||||
        plug_states[plug_count++] = state;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    // unload plugins
 | 
			
		||||
    for (size_t i = 0; i < PLUGMAN.plug_obj_count; i++) {
 | 
			
		||||
        dlclose(PLUGMAN.plug_objs[i]);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    PLUGMAN.plug_obj_count = 0;
 | 
			
		||||
 | 
			
		||||
    for (size_t i = 0; i < PLUGMAN.plug_count; i++) {
 | 
			
		||||
        plug_int_t* plug = PLUGMAN.plugs[i]; 
 | 
			
		||||
        plug = load_plugin(plug->path, false);
 | 
			
		||||
        (plug->f_post_reload)(plug_states[i]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    load_plugins("./modules");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										189
									
								
								src/socket.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										189
									
								
								src/socket.c
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,189 @@
 | 
			
		|||
#include <stdio.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#include <sys/socket.h>
 | 
			
		||||
#include <sys/un.h>
 | 
			
		||||
#include <sys/select.h>
 | 
			
		||||
#include <fcntl.h>
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
 | 
			
		||||
#include "socket.h"
 | 
			
		||||
#include "util.h"
 | 
			
		||||
 | 
			
		||||
#define SOCKET_PATH "/tmp/dim.sock"
 | 
			
		||||
#define BUFFER_SIZE 255
 | 
			
		||||
 | 
			
		||||
typedef struct sock_server_t {
 | 
			
		||||
    int s_fd;
 | 
			
		||||
    int c_fd;
 | 
			
		||||
    struct sockaddr_un s_addr;
 | 
			
		||||
    char buf[BUFFER_SIZE];
 | 
			
		||||
    int max_fd;
 | 
			
		||||
    fd_set read_fds;
 | 
			
		||||
} sock_server_t;
 | 
			
		||||
 | 
			
		||||
sock_server_t SOCK_SERVER = {0};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
int socket_init(void) {
 | 
			
		||||
    
 | 
			
		||||
    // Check if socket exists
 | 
			
		||||
    if (access(SOCKET_PATH, F_OK) == 0) {
 | 
			
		||||
        remove(SOCKET_PATH);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    // Create the socket
 | 
			
		||||
    SOCK_SERVER.s_fd = socket(AF_UNIX, SOCK_STREAM, 0);
 | 
			
		||||
    if (SOCK_SERVER.s_fd == -1) {
 | 
			
		||||
        perror("ERROR: Failed to create socket");
 | 
			
		||||
        return 1;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    int flags = fcntl(SOCK_SERVER.s_fd, F_GETFL, 0);
 | 
			
		||||
    if (fcntl(SOCK_SERVER.s_fd, F_SETFL, flags | O_NONBLOCK) == -1) {
 | 
			
		||||
        perror("ERROR: Failed to set socket to non blocking");
 | 
			
		||||
        close(SOCK_SERVER.s_fd);
 | 
			
		||||
        return 1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Set up the server address structure
 | 
			
		||||
    memset(&SOCK_SERVER.s_addr, 0, sizeof(struct sockaddr_un));
 | 
			
		||||
    SOCK_SERVER.s_addr.sun_family = AF_UNIX;
 | 
			
		||||
    strncpy(SOCK_SERVER.s_addr.sun_path, SOCKET_PATH, sizeof(SOCK_SERVER.s_addr.sun_path) - 1);
 | 
			
		||||
 | 
			
		||||
    // Bind the socket to the address
 | 
			
		||||
    int berr = bind(
 | 
			
		||||
                SOCK_SERVER.s_fd,
 | 
			
		||||
                (struct sockaddr *)&SOCK_SERVER.s_addr,
 | 
			
		||||
                sizeof(struct sockaddr_un));
 | 
			
		||||
 | 
			
		||||
    if (berr == -1) {
 | 
			
		||||
        perror("ERROR: Failed to bind to socket");
 | 
			
		||||
        close(SOCK_SERVER.s_fd);
 | 
			
		||||
        return 1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Listen for incoming connections
 | 
			
		||||
    if (listen(SOCK_SERVER.s_fd, 5) == -1) {
 | 
			
		||||
        perror("ERRROR: Failed to start listening for messages in the socket");
 | 
			
		||||
        close(SOCK_SERVER.s_fd);
 | 
			
		||||
        return 1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    printf("INFO: Server is listening on %s\n", SOCKET_PATH);
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct timeval timeout = {0};
 | 
			
		||||
 | 
			
		||||
sock_msg_t socket_poll(void) {
 | 
			
		||||
    FD_ZERO(&SOCK_SERVER.read_fds);
 | 
			
		||||
    FD_SET(SOCK_SERVER.s_fd, &SOCK_SERVER.read_fds);
 | 
			
		||||
    SOCK_SERVER.max_fd = SOCK_SERVER.s_fd;
 | 
			
		||||
    
 | 
			
		||||
    // Add client sockets to the set
 | 
			
		||||
    if (SOCK_SERVER.c_fd > 0) {
 | 
			
		||||
        FD_SET(SOCK_SERVER.c_fd, &SOCK_SERVER.read_fds);
 | 
			
		||||
        if (SOCK_SERVER.c_fd > SOCK_SERVER.max_fd) {
 | 
			
		||||
            SOCK_SERVER.max_fd = SOCK_SERVER.c_fd;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    // Wait for an activity on one of the sockets
 | 
			
		||||
    int activity = select(SOCK_SERVER.max_fd + 1, &SOCK_SERVER.read_fds, NULL, NULL, &timeout);
 | 
			
		||||
 | 
			
		||||
    if (activity < 0 && errno != EINTR) {
 | 
			
		||||
        perror("select error");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    // If something happened on the server socket, it's an incoming connection
 | 
			
		||||
    if (FD_ISSET(SOCK_SERVER.s_fd, &SOCK_SERVER.read_fds)) {
 | 
			
		||||
        if ((SOCK_SERVER.c_fd = accept(SOCK_SERVER.s_fd, NULL, NULL)) == -1) {
 | 
			
		||||
            if (errno != EWOULDBLOCK && errno != EAGAIN) {
 | 
			
		||||
                perror("accept error");
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            //printf("Accepted new connection\n");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    // If something happened on the client socket, it's incoming data
 | 
			
		||||
    if (SOCK_SERVER.c_fd > 0 && FD_ISSET(SOCK_SERVER.c_fd, &SOCK_SERVER.read_fds)) {
 | 
			
		||||
        int num_bytes = read(SOCK_SERVER.c_fd, SOCK_SERVER.buf, BUFFER_SIZE - 1);
 | 
			
		||||
        if (num_bytes > 0) {
 | 
			
		||||
            SOCK_SERVER.buf[num_bytes] = '\0'; // Null-terminate the buffer
 | 
			
		||||
            return (sock_msg_t)atoi(SOCK_SERVER.buf);
 | 
			
		||||
            //printf("Received message: %s\n", SOCK_SERVER.buf);
 | 
			
		||||
        } else if (num_bytes == 0) {
 | 
			
		||||
            // Client disconnected
 | 
			
		||||
            //printf("Client disconnected\n");
 | 
			
		||||
            close(SOCK_SERVER.c_fd);
 | 
			
		||||
            SOCK_SERVER.c_fd = -1;
 | 
			
		||||
        } else {
 | 
			
		||||
            if (errno != EWOULDBLOCK && errno != EAGAIN) {
 | 
			
		||||
                perror("read error");
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return SM_NONE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void socket_close(void) {
 | 
			
		||||
    close(SOCK_SERVER.s_fd);
 | 
			
		||||
    unlink(SOCKET_PATH);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void socket_send(char* msg_str) {
 | 
			
		||||
    to_lowercase(msg_str);
 | 
			
		||||
    
 | 
			
		||||
    sock_msg_t msg_t = SM_NONE;
 | 
			
		||||
 | 
			
		||||
    if (strcmp(msg_str, "reload") == 0) {
 | 
			
		||||
        msg_t = SM_RELOAD;
 | 
			
		||||
    } else {
 | 
			
		||||
        printf("ERROR: Unknown message type '%s'\n", msg_str);
 | 
			
		||||
        printf("NOTE: Available messages:\n");
 | 
			
		||||
        printf(" - reload\n");
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    int client_fd;
 | 
			
		||||
    struct sockaddr_un server_addr;
 | 
			
		||||
 | 
			
		||||
    // Create the socket
 | 
			
		||||
    if ((client_fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
 | 
			
		||||
        perror("ERROR: Failed to create error");
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Set up the server address structure
 | 
			
		||||
    memset(&server_addr, 0, sizeof(struct sockaddr_un));
 | 
			
		||||
    server_addr.sun_family = AF_UNIX;
 | 
			
		||||
    strncpy(server_addr.sun_path, SOCKET_PATH, sizeof(server_addr.sun_path) - 1);
 | 
			
		||||
 | 
			
		||||
    // Connect to the server
 | 
			
		||||
    if (connect(client_fd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr_un)) == -1) {
 | 
			
		||||
        perror("ERROR: Failed to connect to server");
 | 
			
		||||
        close(client_fd);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    char msg[255];
 | 
			
		||||
 | 
			
		||||
    snprintf(msg, 255, "%d", msg_t);
 | 
			
		||||
 | 
			
		||||
    // Send a message to the server
 | 
			
		||||
    if (write(client_fd, msg, strlen(msg)) == -1) {
 | 
			
		||||
        perror("ERROR: Failed to write message to server");
 | 
			
		||||
        close(client_fd);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Clean up
 | 
			
		||||
    close(client_fd);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										14
									
								
								src/util.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								src/util.c
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,14 @@
 | 
			
		|||
 | 
			
		||||
#include <ctype.h>
 | 
			
		||||
 | 
			
		||||
void to_lowercase(char* str) {
 | 
			
		||||
    for(int i = 0; str[i]; i++){
 | 
			
		||||
      str[i] = tolower(str[i]);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void to_uppercase(char* str) {
 | 
			
		||||
    for(int i = 0; str[i]; i++){
 | 
			
		||||
      str[i] = tolower(str[i]);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user