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