1 #include "config.h"
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <signal.h>
5 #include <pthread.h>
6 #include <libsmbclient.h>
7 #include <fuse.h>
8 #include <glib.h>
9
10 #include "common.h"
11 #include "smbitem.h"
12 #include "auth.h"
13 #include "process.h"
14 #include "samba.h"
15 #include "stat_workaround.h"
16 #include "reconfigure.h"
17
18 static int event_query_browser_flag = 1;
19 static int event_time_step = 10;
20 static int event_smb_tree_scan_period = 300;
21 static int event_smb_tree_elements_ttl = 900;
22 static int event_config_update_period = 300;
23
24 static time_t event_last_smb_tree_scan = (time_t) 0;
25 static time_t event_last_config_update = (time_t) 0;
26
27 static pthread_mutex_t m_evthread = PTHREAD_MUTEX_INITIALIZER;
28
29 static pthread_t event_ev_thread_id;
30 static pthread_t event_smb_thread_id;
31
event_set_query_browser_flag(int flag)32 int event_set_query_browser_flag(int flag){
33 DPRINTF(7, "flag=%d\n", flag);
34 g_atomic_int_set(&event_query_browser_flag, flag);
35 return 1;
36 }
37
event_get_query_browser_flag(void)38 static inline int event_get_query_browser_flag(void){
39 return g_atomic_int_get(&event_query_browser_flag);
40 }
41
event_set_time_step(int step)42 int event_set_time_step(int step){
43 if (step < 1) return 0;
44 DPRINTF(7, "step=%d\n", step);
45 g_atomic_int_set(&event_time_step, step);
46 return 1;
47 }
48
event_get_time_step(void)49 static inline int event_get_time_step(void){
50 return g_atomic_int_get(&event_time_step);
51 }
52
event_set_smb_tree_scan_period(int period)53 int event_set_smb_tree_scan_period(int period){
54 if (period < event_get_time_step()) return 0;
55 DPRINTF(7, "period=%d\n", period);
56 pthread_mutex_lock(&m_evthread);
57 event_smb_tree_scan_period = period;
58 pthread_mutex_unlock(&m_evthread);
59 return 1;
60 }
61
event_get_smb_tree_scan_period(void)62 static inline int event_get_smb_tree_scan_period(void){
63 int period;
64
65 pthread_mutex_lock(&m_evthread);
66 period = event_smb_tree_scan_period;
67 pthread_mutex_unlock(&m_evthread);
68 return period;
69 }
70
event_set_smb_tree_elements_ttl(int ttl)71 int event_set_smb_tree_elements_ttl(int ttl){
72 if (ttl < event_get_smb_tree_scan_period()) return 0;
73 DPRINTF(7, "ttl=%d\n", ttl);
74 g_atomic_int_set(&event_smb_tree_elements_ttl, ttl);
75 return 1;
76 }
77
event_get_smb_tree_elements_ttl(void)78 static inline int event_get_smb_tree_elements_ttl(void){
79 return g_atomic_int_get(&event_smb_tree_elements_ttl);
80 }
81
event_set_config_update_period(int period)82 int event_set_config_update_period(int period){
83 if ((period != 0) && (period < event_get_time_step())) return 0;
84 DPRINTF(7, "period=%d\n", period);
85 pthread_mutex_lock(&m_evthread);
86 event_config_update_period = period;
87 pthread_mutex_unlock(&m_evthread);
88 return 1;
89 }
90
event_set_last_smb_tree_scan(time_t scan_time)91 static void event_set_last_smb_tree_scan(time_t scan_time){
92 pthread_mutex_lock(&m_evthread);
93 event_last_smb_tree_scan = scan_time;
94 pthread_mutex_unlock(&m_evthread);
95 }
96
event_is_time_for_smb_tree_scan(void)97 static int event_is_time_for_smb_tree_scan(void){
98 int flag;
99
100 pthread_mutex_lock(&m_evthread);
101 flag = (time(NULL) >= event_last_smb_tree_scan +
102 event_smb_tree_scan_period) ? 1 : 0;
103 pthread_mutex_unlock(&m_evthread);
104 return flag;
105 }
106
event_set_last_config_update(time_t update_time)107 static void event_set_last_config_update(time_t update_time){
108 pthread_mutex_lock(&m_evthread);
109 event_last_config_update = update_time;
110 pthread_mutex_unlock(&m_evthread);
111 }
112
event_is_time_for_config_update(void)113 static int event_is_time_for_config_update(void){
114 int flag;
115
116 pthread_mutex_lock(&m_evthread);
117 flag = ((event_config_update_period > 0) &&
118 (time(NULL) >= event_last_config_update +
119 event_config_update_period)) ? 1 : 0;
120 pthread_mutex_unlock(&m_evthread);
121 return flag;
122 }
123
event_scan_samba_group(const char * group)124 static void event_scan_samba_group(const char *group){
125 char buf[4096], name[256], link[256];
126 int count;
127 samba_fd fd;
128
129 DPRINTF(5, "group=%s\n", group);
130 snprintf(name, sizeof(name), "/%s", group);
131 fd = samba_opendir(name);
132 while(1){
133 struct smb_conn_dirent_rec *rec;
134
135 count = samba_readdir(fd, buf, sizeof(buf));
136 if (count <= 0) break;
137
138 rec = (struct smb_conn_dirent_rec *) buf;
139 for( ; count >= (int) sizeof(struct smb_conn_dirent_rec);
140 count -= sizeof(struct smb_conn_dirent_rec)){
141 switch(rec->smbc_type){
142 case SMBC_SERVER:
143 smbitem_mkhost(rec->d_name, group, 1, SMBITEM_SAMBA_TREE);
144 snprintf(name, sizeof(name), "%s/%s", group, rec->d_name);
145 snprintf(link, sizeof(link), "../%s", rec->d_name);
146 smbitem_mklink(name, link, SMBITEM_SAMBA_TREE);
147 break;
148 default:
149 DPRINTF(6, "ups..., smbc_type=%d, d_name=%s\n",
150 rec->smbc_type, rec->d_name);
151 }
152 rec++;
153 }
154 }
155 samba_closedir(fd);
156 }
157
event_scan_smb_root(void)158 static void event_scan_smb_root(void){
159 char buf[4096];
160 int count;
161 samba_fd fd;
162
163 DPRINTF(5, "reading group list\n");
164 fd = samba_opendir("/");
165 while(1){
166 struct smb_conn_dirent_rec *rec;
167
168 count = samba_readdir(fd, buf, sizeof(buf));
169 if (count <= 0) break;
170
171 rec = (struct smb_conn_dirent_rec *) buf;
172 for( ; count >= (int) sizeof(struct smb_conn_dirent_rec);
173 count -= sizeof(struct smb_conn_dirent_rec)){
174 switch(rec->smbc_type){
175 case SMBC_WORKGROUP:
176 smbitem_mkgroup(rec->d_name, SMBITEM_SAMBA_TREE);
177 break;
178 default:
179 DPRINTF(6, "ups..., smbc_type=%d, d_name=%s\n",
180 rec->smbc_type, rec->d_name);
181 }
182 rec++;
183 }
184 }
185 samba_closedir(fd);
186 }
187
event_scan_smb_tree(void)188 void event_scan_smb_tree(void){
189 int i;
190 struct smbitem *dir;
191
192 if (event_get_query_browser_flag()) event_scan_smb_root();
193 dir = smbitem_get_samba_groups();
194 for(i = 0; i < dir->child_cnt; i++){
195 if (dir->childs[i]->type != SMBITEM_GROUP) continue;
196 event_scan_samba_group(dir->childs[i]->name);
197 }
198 smbitem_release_dir(dir);
199 }
200
event_update_smb_tree_thread(void * data)201 static void* event_update_smb_tree_thread(void *data){
202 time_t scan_time;
203 time_t die_threshold;
204 int time_step;
205
206 (void)data;
207
208 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
209
210 scan_time = time(NULL);
211 event_scan_smb_tree();
212 event_set_last_smb_tree_scan(scan_time);
213
214 while(1){
215 time_step = event_get_time_step();
216 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
217 sleep(time_step);
218 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
219
220 if (event_is_time_for_smb_tree_scan()){
221 scan_time = time(NULL);
222 die_threshold = scan_time - event_get_smb_tree_elements_ttl();
223 DPRINTF(5, "start at timestamp=%u, die_threshold=%u\n",
224 (unsigned) scan_time, (unsigned) die_threshold);
225
226 event_scan_smb_tree();
227 smbitem_delete_obsolete(die_threshold, SMBITEM_SAMBA_TREE);
228 event_set_last_smb_tree_scan(scan_time);
229 }
230 }
231 return NULL;
232 }
233
event_reread_config(void)234 static void event_reread_config(void){
235 time_t reread_time;
236
237 reread_time = time(NULL);
238 DPRINTF(5, "start at timestamp=%u\n", (unsigned) reread_time);
239
240 reconfigure_read_config(0);
241 smbitem_delete_obsolete(reread_time, SMBITEM_USER_TREE);
242 auth_delete_obsolete(reread_time);
243 stat_workaround_delete_obsolete(reread_time);
244 event_set_last_config_update(reread_time);
245 }
246
event_thread(void * data)247 static void* event_thread(void *data){
248 siginfo_t siginfo;
249 sigset_t signal_set;
250 time_t start_time;
251 struct timespec timeout;
252 int sigret;
253
254 (void)data;
255
256 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
257
258 start_time = time(NULL);
259 event_set_last_config_update(start_time);
260
261 /* set signals to watch */
262 sigemptyset(&signal_set);
263 sigaddset(&signal_set, SIGHUP);
264 sigaddset(&signal_set, SIGCHLD);
265
266 while(1){
267 timeout.tv_sec = event_get_time_step();
268 timeout.tv_nsec = 0;
269 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
270 sigret = sigtimedwait(&signal_set, &siginfo, &timeout);
271 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
272
273 process_cleanup_from_zombies();
274 if ((sigret != -1 && siginfo.si_signo == SIGHUP)
275 || event_is_time_for_config_update())
276 event_reread_config();
277 }
278 return NULL;
279 }
280
event_init(struct fuse_conn_info * conn)281 static void* event_init(struct fuse_conn_info *conn){
282 (void) conn;
283
284 if (pthread_create(&event_smb_thread_id, NULL,
285 event_update_smb_tree_thread, NULL) != 0){
286 fprintf(stderr, "Could not create smb_tree thread\n");
287 exit(1);
288 }
289 if (pthread_create(&event_ev_thread_id, NULL,
290 event_thread, NULL) != 0){
291 fprintf(stderr, "Could not create event thread\n");
292 exit(1);
293 }
294 return NULL;
295 }
296
event_destroy(void * private_data)297 static void event_destroy(void *private_data){
298 (void)private_data;
299
300 DPRINTF(1, "Destroy cfg and smb_tree threads\n");
301 process_disable_new_smb_conn_starting();
302 process_kill_all();
303 pthread_cancel(event_ev_thread_id);
304 pthread_cancel(event_smb_thread_id);
305 pthread_join(event_ev_thread_id, NULL);
306 pthread_join(event_smb_thread_id, NULL);
307 }
308
event_set_event_handler(struct fuse_operations * file_oper)309 void event_set_event_handler(struct fuse_operations *file_oper){
310 file_oper->init = event_init;
311 file_oper->destroy = event_destroy;
312 }
313