e9301a1998af72118469abe661a77d38d3b3f544
[lufs.git] / lufsd / fsctl.c
1 /*
2  * fsctl.c
3  * Copyright (C) 2002 Florin Malita <mali@go.ro>
4  *
5  * This file is part of LUFS, a free userspace filesystem implementation.
6  * See http://lufs.sourceforge.net/ for updates.
7  *
8  * LUFS is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * LUFS is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  */
22
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26
27 #include <unistd.h>
28 #include <stdlib.h>
29 #include <stdio.h>
30 #include <signal.h>
31 #include <dirent.h>
32 #include <fcntl.h>
33 #include <dlfcn.h>
34 #include <pthread.h>
35 #include <errno.h>
36 #ifndef __USE_GNU
37 #define __USE_GNU
38 #endif
39 #include <string.h>
40
41 #include <sys/types.h>
42 #include <sys/stat.h>
43 #include <sys/socket.h>
44 #include <sys/un.h>
45 #include <sys/wait.h>
46 #include <sys/ipc.h>
47 #include <sys/msg.h>
48
49 #include <lufs/proto.h>
50 #include <lufs/fs.h>
51
52 #include "list.h"
53 #include "message.h"
54 #include "fsctl.h"
55 #include "filesystem.h"
56 #include "dircache.h"
57
58 char sock_name[MAX_LEN];
59
60 static void
61 usr1Handler(int sig){
62
63     TRACE("unmounting filesystem...");
64     TRACE("socket name: %s", sock_name);
65     unlink(sock_name);
66
67     exit(0);
68 }
69
70 static void
71 sig_handler(int sig){
72     TRACE("got a signal: %d", sig);
73
74     signal(sig, sig_handler);
75 }
76
77 static void*
78 thread_launcher(void *params){
79     struct thread_info *p = (struct thread_info*)params;
80     struct file_system *fs = p->fs;
81     int sock = p->sock;
82     pid_t ppid = p->ppid;
83
84     TRACE("thread created");
85     
86     free(p);
87
88     if(fs) {
89         handle_fs(fs, sock, ppid);
90
91         if(fs->fs_ops->umount)
92             fs->fs_ops->umount(fs->fs_context);
93         fs->fs_ops->free(fs->fs_context);
94
95         free(fs);
96     }else{
97         WARN("could not instantiate filesystem (out of mem?) !");
98     }
99
100     close(sock);
101     TRACE("thread exiting...");
102
103     return NULL;
104 }
105
106 #define BUF_SIZE        1024
107 #define PASSWD          "/etc/passwd"
108 #define GROUP           "/etc/group"
109
110 static int
111 load_credentials(struct fs_ctl *ctl, struct file_system *fs){
112     static char buf[BUF_SIZE];
113     char srch_str[MAX_LEN + 4];
114     long int uid, gid;
115     int res, offset, chunk, readlen;
116     char *c;
117
118     TRACE("loading remote credentials for %s", ctl->cred.user);
119
120     if((!ctl->fs_ops->open) || (!ctl->fs_ops->read) || (!ctl->fs_ops->release)){
121         WARN("unsupported operation");
122         return -1;;
123     }
124
125     ctl->cred.uid = ctl->cred.gid = -1;
126
127     if(ctl->fs_ops->open(fs->fs_context, PASSWD, O_RDONLY) < 0){
128         TRACE("could not open %s", PASSWD);
129         return -1;
130     }
131
132     sprintf(srch_str, "\n%s:", ctl->cred.user);
133     chunk = strlen(srch_str) + 64;
134     readlen = BUF_SIZE - chunk - 1;
135
136     memset(buf, 32, chunk);
137     offset = 0;
138
139     do{
140         res = ctl->fs_ops->read(fs->fs_context, PASSWD, offset, readlen, (buf + chunk));
141         if(res > 0){
142             *(buf + chunk + res) = 0;
143
144             if((c = strstr(buf, srch_str))){
145                 TRACE("username found!");
146                 if(!(c = strchr(c + strlen(srch_str), ':'))){
147                     TRACE("separator not found!");
148                 }else{ 
149                     if(sscanf(c , ":%li:%li:", &uid, &gid) != 2){
150                         TRACE("uid/gid not found!");
151                     }else{
152                         TRACE("uid: %li, gid: %li", uid, gid);
153
154                         ctl->cred.uid = uid;
155                         ctl->cred.gid = gid;
156
157                         break;
158                     }
159                 }
160             }
161
162             memcpy(buf, buf + BUF_SIZE - chunk - 1, chunk);
163             offset += res;
164         }
165     }while(res == readlen);
166
167     ctl->fs_ops->release(fs->fs_context, PASSWD);
168
169     if(res <= 0){
170         TRACE("read failed");
171         return -1;
172     }
173
174     
175     if(ctl->fs_ops->open(fs->fs_context, GROUP, O_RDONLY) < 0){
176         TRACE("could not open %s", GROUP);
177         return -1;
178     }
179
180     sprintf(srch_str, ":%li:", (long)ctl->cred.gid);
181     chunk = strlen(srch_str) + 64;
182     readlen = BUF_SIZE - chunk - 1;
183
184     memset(buf, 32, chunk);
185     offset = 0;
186
187     do{
188         res = ctl->fs_ops->read(fs->fs_context, GROUP, offset, readlen, (buf + chunk));
189         if(res > 0){
190             *(buf + chunk + res) = 0;
191
192             if((c = strstr(buf, srch_str))){
193                 TRACE("group found!");
194                 if(!(c = (char*)memrchr(buf, '\n', (c - buf)))){
195                     TRACE("separator not found!");
196                 }else{ 
197                     *(strchr(c, ':')) = 0;
198                     if(strlen(c + 1) >= MAX_LEN){
199                         TRACE("groupname too long");
200                     }else{
201                         strcpy(ctl->cred.group, c + 1);
202                         TRACE("group: %s", ctl->cred.group);
203                         break;
204                     }
205                 }
206             }
207
208             memcpy(buf, buf + BUF_SIZE - chunk - 1, chunk);
209             offset += res;
210         }
211     }while(res == readlen);
212
213     ctl->fs_ops->release(fs->fs_context, GROUP);
214
215     if(res <= 0){
216         TRACE("read failed");
217         return -1;
218     }
219
220     return 0;
221 }
222
223
224 static struct fs_operations*
225 get_filesystem(struct fs_ctl *ctl, char *fs){
226     struct fs_operations *fops;
227     char *buf;
228     void *dlhandle;
229
230     if(!(buf = (char*)malloc(strlen(fs) + 32)))
231         return NULL;
232
233     sprintf(buf, "liblufs-%s.so", fs);
234     TRACE("trying to load %s", buf);
235
236     if(!(dlhandle = dlopen(buf, RTLD_LAZY))){
237         ERROR(dlerror());
238         goto fail;
239     }
240
241     TRACE("lib opened");
242         
243     if(!(fops = (struct fs_operations*)malloc(sizeof(struct fs_operations))))
244         goto fail_dl;
245
246     memset(fops, 0, sizeof(struct fs_operations));
247
248     sprintf(buf, "%s_init", fs);
249     if(!(fops->init = (void*(*)(struct list_head*, struct dir_cache*, struct credentials*, void**))dlsym(dlhandle, buf))){
250         ERROR(dlerror());
251         goto fail_fops;
252     }
253
254     sprintf(buf, "%s_free", fs);
255     if(!(fops->free = (void(*)(void*))dlsym(dlhandle, buf))){
256         ERROR(dlerror());
257         goto fail_fops;
258     }
259
260     sprintf(buf, "%s_mount", fs);
261     if(!(fops->mount = (int(*)(void*))dlsym(dlhandle, buf))){
262         ERROR(dlerror());
263         goto fail_fops;
264     }
265
266     sprintf(buf, "%s_umount", fs);
267     if(!(fops->umount = (void(*)(void*))dlsym(dlhandle, buf)))
268         ERROR(dlerror());
269
270     sprintf(buf, "%s_readdir", fs);
271     if(!(fops->readdir = (int(*)(void*, char*, struct directory*))dlsym(dlhandle, buf)))
272         ERROR(dlerror());
273
274     sprintf(buf, "%s_stat", fs);
275     if(!(fops->stat = (int(*)(void*, char*, struct lufs_fattr*))dlsym(dlhandle, buf)))
276         ERROR(dlerror());
277
278     sprintf(buf, "%s_mkdir", fs);
279     if(!(fops->mkdir = (int(*)(void*, char*, int))dlsym(dlhandle, buf)))
280         ERROR(dlerror());
281
282     sprintf(buf, "%s_rmdir", fs);
283     if(!(fops->rmdir = (int(*)(void*, char*))dlsym(dlhandle, buf)))
284         ERROR(dlerror());
285
286     sprintf(buf, "%s_create", fs);
287     if(!(fops->create = (int(*)(void*, char*, int))dlsym(dlhandle, buf)))
288         ERROR(dlerror());
289
290     sprintf(buf, "%s_unlink", fs);
291     if(!(fops->unlink = (int(*)(void*, char*))dlsym(dlhandle, buf)))
292         ERROR(dlerror());
293
294     sprintf(buf, "%s_rename", fs);
295     if(!(fops->rename = (int(*)(void*, char*, char*))dlsym(dlhandle, buf)))
296         ERROR(dlerror());
297
298     sprintf(buf, "%s_open", fs);
299     if(!(fops->open = (int(*)(void*, char*, unsigned))dlsym(dlhandle, buf)))
300         ERROR(dlerror());
301
302     sprintf(buf, "%s_release", fs);
303     if(!(fops->release = (int(*)(void*, char*))dlsym(dlhandle, buf)))
304         ERROR(dlerror());
305
306     sprintf(buf, "%s_read", fs);
307     if(!(fops->read = (int(*)(void*, char*, long long, unsigned long, char*))dlsym(dlhandle, buf)))
308         ERROR(dlerror());
309
310     sprintf(buf, "%s_write", fs);
311     if(!(fops->write = (int(*)(void*, char*, long long, unsigned long, char*))dlsym(dlhandle, buf)))
312         ERROR(dlerror());
313
314     sprintf(buf, "%s_readlink", fs);
315     if(!(fops->readlink = (int(*)(void*, char*, char*, int))dlsym(dlhandle, buf)))
316         ERROR(dlerror());
317
318     sprintf(buf, "%s_link", fs);
319     if(!(fops->link = (int(*)(void*, char*, char*))dlsym(dlhandle, buf)))
320         ERROR(dlerror());
321
322     sprintf(buf, "%s_symlink", fs);
323     if(!(fops->symlink = (int(*)(void*, char*, char*))dlsym(dlhandle, buf)))
324         ERROR(dlerror());
325
326     sprintf(buf, "%s_setattr", fs);
327     if(!(fops->setattr = (int(*)(void*, char*, struct lufs_fattr*))dlsym(dlhandle, buf)))
328         ERROR(dlerror());
329
330     TRACE("file system loaded");
331
332     ctl->dlhandle = dlhandle;
333     free(buf);
334     return fops;
335
336   fail_fops:
337     free(fops);
338   fail_dl:
339     dlclose(dlhandle);
340     dlhandle = NULL;
341   fail:  
342     free(buf);
343     return NULL;
344 }
345
346 static struct file_system*
347 new_fsinstance(struct fs_ctl *ctl){
348     struct file_system *fs;
349     
350     if(!(fs = (struct file_system*)malloc(sizeof(struct file_system))))
351         return NULL;
352
353     memset(fs, 0, sizeof(struct file_system));
354
355     fs->fs_ops = ctl->fs_ops;
356     fs->fs_credentials = &ctl->cred;
357     fs->fs_cache = ctl->cache;
358     fs->fs_config = ctl->cfg;
359
360     if(!(fs->fs_context = ctl->fs_ops->init(ctl->cfg, ctl->cache, fs->fs_credentials, &ctl->global_ctx))){
361         ERROR("could not initialize file system!");
362         free(fs);
363         return NULL;
364     }
365
366     return fs;
367 }
368
369 int
370 lu_fsctl_mount(struct fs_ctl *ctl){
371     int res;
372     struct file_system *fs;
373
374     if(!ctl->fs_ops)
375         return 0;
376
377     if(!(fs = new_fsinstance(ctl)))
378         return 0;
379         
380     res = ctl->fs_ops->mount(fs->fs_context);
381
382     if(res){
383         ctl->fs_available = fs;
384         fs->fs_mounted = 1;
385         if(load_credentials(ctl, fs) < 0)
386             TRACE("could not load credentials.");
387         else
388             TRACE("credentials loaded.");
389
390     }else{
391         WARN("fs mount failed...");
392         free(fs);
393     }
394
395     return res;
396 }
397
398
399 void
400 lu_fsctl_run(struct fs_ctl *ctl, int ssock, char *sn){
401     pthread_t th_id;
402     socklen_t len;
403     struct sockaddr_un addr;
404     int sock;
405     struct thread_info *info;
406
407     if(strlen(sn) >= MAX_LEN){
408         WARN("socket name too long!");
409         return;
410     }
411     
412     strcpy(sock_name, sn);
413
414     signal(SIGUSR1, usr1Handler);
415
416     signal(SIGPIPE, sig_handler);
417     signal(SIGTERM, sig_handler);
418     signal(SIGINT, sig_handler);
419     
420     while(1){
421         len = sizeof(struct sockaddr_un);
422
423         if((sock = accept(ssock, (struct sockaddr*)&addr, &len)) < 0){
424             if(errno != EINTR){
425                 WARN("accept failed: %d(%s)", errno, strerror(errno));
426             }
427         }else{
428             TRACE("a client process connected.");
429
430             if((info = (struct thread_info*)malloc(sizeof(struct thread_info)))){
431
432                 if(ctl->fs_available){
433                     TRACE("using already mounted filesystem...");
434                     info->fs = ctl->fs_available;
435                     ctl->fs_available = NULL;
436                 }else
437                     info->fs = new_fsinstance(ctl);
438
439                 info->sock = sock;
440                 info->ppid = getpid();
441                 if(!pthread_create(&th_id, NULL, &thread_launcher, (void*)info)){
442                     pthread_detach(th_id);
443                 }else{
444                     WARN("could not create thread!");
445                     free(info);
446                 }
447             }else{
448                 WARN("out of memory?!");
449             }
450         }
451     }
452
453 }
454
455 struct fs_ctl*
456 lu_fsctl_create(struct list_head *conf){
457     struct fs_ctl *ctl;
458     const char *fs_name, *user_name;
459
460     TRACE("creating fs_ctl");
461     
462     if(!(ctl = (struct fs_ctl*)malloc(sizeof(struct fs_ctl))))
463         return NULL;
464
465     memset(ctl, 0, sizeof(struct fs_ctl));
466
467     ctl->cache = lu_cache_create(conf);
468     ctl->cfg = conf;
469
470     if(!(fs_name = lu_opt_getchar(conf, "MOUNT", "fs"))){
471         ERROR("you need to specify a file system!");
472         free(ctl);
473         return NULL;
474     }
475
476      if(!(ctl->fs_ops = get_filesystem(ctl, (char*)fs_name))){ 
477         ERROR("unsupported file system: %s", fs_name); 
478         free(ctl); 
479         return NULL; 
480      }
481
482     if((user_name = lu_opt_getchar(conf, "MOUNT", "username")))
483         strcpy(ctl->cred.user, user_name);
484
485     return ctl;
486 }
487
488 void
489 lu_fsctl_destroy(struct fs_ctl *ctl){
490     TRACE("destroying fs_ctl");
491
492     lu_cache_destroy(ctl->cache);
493
494     if(ctl->dlhandle)
495         dlclose(ctl->dlhandle);
496
497     if(ctl->fs_available)
498         free(ctl->fs_available);
499
500     free(ctl);
501 }
502
503
504
505