]> code.citadel.org Git - citadel.git/blob - citadel/dynloader.c
* Implemented separate structs, lists, and functions for each type
[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 #include "sysdep_decls.h"
22
23 symtab *global_symtab;
24
25 struct CleanupFunctionHook *CleanupHookTable = NULL;
26 struct NewRoomFunctionHook *NewRoomHookTable = NULL;
27 struct SessionFunctionHook *SessionHookTable = NULL;
28 struct LoginFunctionHook *LoginHookTable = NULL;
29
30 int DLoader_Exec_Cmd(char *cmdbuf)
31 {
32    symtab *t_sym;
33    void *fcn_handle;
34    char *dl_error;
35    void (*cmd_ptr)(void *);
36    
37    for (t_sym = global_symtab; ((t_sym) && (strncmp(t_sym->server_cmd, cmdbuf, strlen(t_sym->server_cmd))) ); t_sym=t_sym->next)
38       ;
39       
40    if (t_sym)
41    {
42       if (!(fcn_handle = dlopen(t_sym->module_path, RTLD_NOW)))
43       {
44          dl_error = dlerror();
45          syslog(LOG_NOTICE, "WARNING: module %s failed to load", t_sym->module_path);
46          return(0);
47       }
48       
49       cmd_ptr = dlsym(fcn_handle, t_sym->fcn_name);
50       if ((dl_error = dlerror()) != NULL)
51       {
52          syslog(LOG_NOTICE, "dlsym error: %s - %s", dl_error, t_sym->module_path);
53          return(0);
54       }
55       (*cmd_ptr)(&cmdbuf[5]);
56       dlclose(fcn_handle);
57       if ((dl_error = dlerror()) != NULL)
58       {
59          syslog(LOG_NOTICE, "dlclose error: %s", dl_error);
60          return(0);
61       }
62       return(1);
63    }  /* If symbol found */
64
65    return(0);
66 }
67
68 void add_symbol(char *fcn_name, char *server_cmd, char *info_msg, symtab **first_symtab)
69 {
70    symtab *new_symtab, *t_sym, *last_sym;
71    
72    if (!(new_symtab = malloc(sizeof(symtab))))
73    {
74       perror("Malloc new symtab");
75       exit(1);
76    }
77    
78    new_symtab->fcn_name = strdup(fcn_name);
79    new_symtab->server_cmd = strdup(server_cmd);
80    new_symtab->info_msg = strdup(info_msg);
81    new_symtab->next = NULL;
82    
83    if (!(*first_symtab))
84       (*first_symtab) = new_symtab;
85    else
86    {
87       last_sym = NULL;
88       for (t_sym = (*first_symtab); (t_sym); t_sym = t_sym->next)
89          last_sym = t_sym;
90       last_sym->next = new_symtab;
91    }
92 }
93
94 void DLoader_Init(char *pathname, symtab **my_symtab)
95 {
96    void *fcn_handle;
97    void (*h_init_fcn)(struct DLModule_Info *);
98    void (*h_get_symtab)(symtab **);
99    char *dl_error;
100    char *filename;
101    DIR *dir;
102    struct dirent *dptr;
103    
104    char pathbuf[512];
105    struct DLModule_Info dl_info;
106    symtab *stab = NULL;
107    symtab *t_sym;
108    
109    global_symtab = NULL;                        /* Global symbol table */
110    
111    if ((dir = opendir(pathname))==NULL)
112    {
113       perror("opendir");
114       exit(1);
115    }
116    
117    while ((dptr=readdir(dir))!= NULL)
118    {
119       if (dptr->d_name[0] == '.')
120          continue;
121    
122       filename = strdup(dptr->d_name);
123       snprintf(pathbuf, 512, "%s/%s", pathname, filename);
124       if (!(fcn_handle = dlopen(pathbuf, RTLD_NOW)))
125       {
126          dl_error = dlerror();
127          fprintf(stderr, "DLoader_Init dlopen failed (%s)", dl_error);
128          continue;
129       }
130       
131       h_init_fcn = dlsym(fcn_handle, "Dynamic_Module_Init");
132       if ((dl_error = dlerror()) != NULL)
133       {
134          fprintf(stderr,"DLoader_Init dlsym failed (%s)", dl_error);
135          continue;
136       }
137       
138       (*h_init_fcn)(&dl_info);
139
140       printf("Loaded module %s v%d.%d\nBy %s (%s)\n", dl_info.module_name, 
141                                                      dl_info.major_version,
142                                                      dl_info.minor_version,
143                                                      dl_info.module_author,
144                                                      dl_info.module_author_email);
145
146       h_get_symtab = dlsym(fcn_handle, "Get_Symtab");
147       if ((dl_error = dlerror()) != NULL)
148       {
149          fprintf(stderr,"DLoader_Init dlsym failed for Get_Symtab (%s) on module %s", dl_error, dl_info.module_name);
150          continue;
151       }
152       
153 /* Get the symbol table for the current module and link it on */      
154       
155       (*h_get_symtab)(&stab);
156       if (!(*my_symtab))
157       {
158          (*my_symtab) = global_symtab = stab;
159       }
160       else
161       {
162          for (t_sym = (*my_symtab) ; t_sym->next; t_sym=t_sym->next);
163             ;
164          t_sym->next = stab;
165       }
166       for (t_sym = stab; t_sym; t_sym=t_sym->next)
167          t_sym->module_path = (char *)strdup(pathbuf);
168       dlclose(fcn_handle);
169       if ((dl_error = dlerror()) != NULL)
170       {
171          fprintf(stderr,"DLoader_Init dlclose failed (%s)", dl_error);
172          continue;
173       }
174       
175    }    /* While */
176    
177 }
178
179
180
181 void CtdlRegisterCleanupHook(void *fcn_ptr) {
182
183         struct CleanupFunctionHook *newfcn;
184
185         newfcn = (struct CleanupFunctionHook *)
186                 malloc(sizeof(struct CleanupFunctionHook));
187         newfcn->next = CleanupHookTable;
188         newfcn->h_function_pointer = fcn_ptr;
189         CleanupHookTable = newfcn;
190
191         lprintf(5, "Registered a new cleanup function\n");
192         }
193
194 void CtdlRegisterNewRoomHook(void *fcn_ptr) {
195
196         struct NewRoomFunctionHook *newfcn;
197
198         newfcn = (struct NewRoomFunctionHook *)
199                 malloc(sizeof(struct NewRoomFunctionHook));
200         newfcn->next = NewRoomHookTable;
201         newfcn->h_function_pointer = fcn_ptr;
202         NewRoomHookTable = newfcn;
203
204         lprintf(5, "Registered a new NewRoom function\n");
205         }
206
207 void CtdlRegisterSessionHook(void *fcn_ptr, int StartStop) {
208
209         struct SessionFunctionHook *newfcn;
210
211         newfcn = (struct SessionFunctionHook *)
212                 malloc(sizeof(struct SessionFunctionHook));
213         newfcn->next = SessionHookTable;
214         newfcn->h_function_pointer = fcn_ptr;
215         newfcn->startstop = StartStop;
216         SessionHookTable = newfcn;
217
218         lprintf(5, "Registered a new session %s function\n",
219                 (StartStop ? "start" : "stop") );
220         }
221
222 void CtdlRegisterLoginHook(void *fcn_ptr) {
223
224         struct LoginFunctionHook *newfcn;
225
226         newfcn = (struct LoginFunctionHook *)
227                 malloc(sizeof(struct LoginFunctionHook));
228         newfcn->next = LoginHookTable;
229         newfcn->h_function_pointer = fcn_ptr;
230         LoginHookTable = newfcn;
231
232         lprintf(5, "Registered a new login function\n");
233         }
234