]> code.citadel.org Git - citadel.git/blob - citadel/dynloader.c
* Tried my hand at adding the ability for server extensions to
[citadel.git] / citadel / dynloader.c
1 /*******************************************************
2  *
3  * Citadel Dynamic Loading Module
4  * Written by Brian Costello
5  * btx@calyx.net
6  *
7  ******************************************************/
8
9
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <dlfcn.h>
13 #include <sys/types.h>
14 #include <dirent.h>
15 #include <strings.h>
16 #include <syslog.h>
17 #include <pthread.h>
18 #include "dynloader.h"
19 #include "citadel.h"
20 #include "server.h"
21
22 symtab *global_symtab;
23
24 struct FunctionHook *HookTable = NULL;
25
26 int DLoader_Exec_Cmd(char *cmdbuf)
27 {
28    symtab *t_sym;
29    void *fcn_handle;
30    char *dl_error;
31    void (*cmd_ptr)(void *);
32    
33    for (t_sym = global_symtab; ((t_sym) && (strncmp(t_sym->server_cmd, cmdbuf, strlen(t_sym->server_cmd))) ); t_sym=t_sym->next)
34       ;
35       
36    if (t_sym)
37    {
38       if (!(fcn_handle = dlopen(t_sym->module_path, RTLD_LAZY)))
39       {
40          dl_error = dlerror();
41          syslog(LOG_NOTICE, "WARNING: module %s failed to load", t_sym->module_path);
42          return(0);
43       }
44       
45       cmd_ptr = dlsym(fcn_handle, t_sym->fcn_name);
46       if ((dl_error = dlerror()) != NULL)
47       {
48          syslog(LOG_NOTICE, "dlsym error: %s - %s", dl_error, t_sym->module_path);
49          return(0);
50       }
51       (*cmd_ptr)(&cmdbuf[5]);
52       dlclose(fcn_handle);
53       if ((dl_error = dlerror()) != NULL)
54       {
55          syslog(LOG_NOTICE, "dlclose error: %s", dl_error);
56          return(0);
57       }
58       return(1);
59    }  /* If symbol found */
60
61    return(0);
62 }
63
64 void add_symbol(char *fcn_name, char *server_cmd, char *info_msg, symtab **first_symtab)
65 {
66    symtab *new_symtab, *t_sym, *last_sym;
67    
68    if (!(new_symtab = malloc(sizeof(symtab))))
69    {
70       perror("Malloc new symtab");
71       exit(1);
72    }
73    
74    new_symtab->fcn_name = strdup(fcn_name);
75    new_symtab->server_cmd = strdup(server_cmd);
76    new_symtab->info_msg = strdup(info_msg);
77    new_symtab->next = NULL;
78    
79    if (!(*first_symtab))
80       (*first_symtab) = new_symtab;
81    else
82    {
83       last_sym = NULL;
84       for (t_sym = (*first_symtab); (t_sym); t_sym = t_sym->next)
85          last_sym = t_sym;
86       last_sym->next = new_symtab;
87    }
88 }
89
90 void DLoader_Init(char *pathname, symtab **my_symtab)
91 {
92    void *fcn_handle;
93    void (*h_init_fcn)(struct DLModule_Info *);
94    void (*h_get_symtab)(symtab **);
95    char *dl_error;
96    char *filename;
97    DIR *dir;
98    struct dirent *dptr;
99    
100    char pathbuf[512];
101    struct DLModule_Info dl_info;
102    symtab *stab = NULL;
103    symtab *t_sym;
104    
105    global_symtab = NULL;                        /* Global symbol table */
106    
107    if ((dir = opendir(pathname))==NULL)
108    {
109       perror("opendir");
110       exit(1);
111    }
112    
113    while ((dptr=readdir(dir))!= NULL)
114    {
115       if (dptr->d_name[0] == '.')
116          continue;
117    
118       filename = strdup(dptr->d_name);
119       snprintf(pathbuf, 512, "%s/%s", pathname, filename);
120       if (!(fcn_handle = dlopen(pathbuf, RTLD_LAZY)))
121       {
122          dl_error = dlerror();
123          fprintf(stderr, "DLoader_Init dlopen failed (%s)", dl_error);
124          continue;
125       }
126       
127       h_init_fcn = dlsym(fcn_handle, "Dynamic_Module_Init");
128       if ((dl_error = dlerror()) != NULL)
129       {
130          fprintf(stderr,"DLoader_Init dlsym failed (%s)", dl_error);
131          continue;
132       }
133       
134       (*h_init_fcn)(&dl_info);
135
136       printf("Loaded module %s v%d.%d\nBy %s (%s)\n", dl_info.module_name, 
137                                                      dl_info.major_version,
138                                                      dl_info.minor_version,
139                                                      dl_info.module_author,
140                                                      dl_info.module_author_email);
141
142       h_get_symtab = dlsym(fcn_handle, "Get_Symtab");
143       if ((dl_error = dlerror()) != NULL)
144       {
145          fprintf(stderr,"DLoader_Init dlsym failed for Get_Symtab (%s) on module %s", dl_error, dl_info.module_name);
146          continue;
147       }
148       
149 /* Get the symbol table for the current module and link it on */      
150       
151       (*h_get_symtab)(&stab);
152       if (!(*my_symtab))
153       {
154          (*my_symtab) = global_symtab = stab;
155       }
156       else
157       {
158          for (t_sym = (*my_symtab) ; t_sym->next; t_sym=t_sym->next);
159             ;
160          t_sym->next = stab;
161       }
162       for (t_sym = stab; t_sym; t_sym=t_sym->next)
163          t_sym->module_path = (char *)strdup(pathbuf);
164       dlclose(fcn_handle);
165       if ((dl_error = dlerror()) != NULL)
166       {
167          fprintf(stderr,"DLoader_Init dlclose failed (%s)", dl_error);
168          continue;
169       }
170       
171    }    /* While */
172    
173 }
174
175
176
177 void CtdlRegisterHook(void *fcn_ptr, int fcn_type) {
178
179         struct FunctionHook *newfcn;
180
181         newfcn = (struct FunctionHook *) malloc(sizeof(struct FunctionHook));
182         newfcn->next = HookTable;
183         newfcn->h_function_pointer = fcn_ptr;
184         newfcn->h_type = fcn_type;
185
186         HookTable = newfcn;
187
188         lprintf(5, "Registered a new function (type %d)\n", fcn_type);
189         }