Fixed -I for prevention of -I/usr/include during Linux kernel mod compilation.
[lufs.git] / lufsd / daemon.c
1 /*
2  * daemon.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 #include <stdlib.h>
24 #include <stdio.h>
25 #include <syslog.h>
26 #include <unistd.h>
27 #include <signal.h>
28 #include <fcntl.h>
29 #include <pwd.h>
30 #include <errno.h>
31 #include <time.h>
32 #include <dirent.h>
33
34 #include <sys/types.h>
35 #include <sys/wait.h>
36 #include <sys/stat.h>
37 #include <sys/socket.h>
38 #include <sys/un.h>
39 #include <sys/ioctl.h>
40 #include <sys/time.h>
41 #include <sys/mount.h>
42
43
44 #include <lufs/proto.h>
45 #include <lufs/fs.h>
46
47 #include "list.h"
48 #include "message.h"
49 #include "filesystem.h"
50 #include "fsctl.h"
51
52 #define CONFIG_FILE1    "/etc/lufsd.conf"
53 #define CONFIG_FILE2    "~/.lufs/lufsd.conf"
54
55 const char *exec_paths[]={
56     "/usr/local/bin/lufsmnt",
57     "/usr/bin/lufsmnt",
58     "/sbin/lufsmnt",
59     NULL
60 };
61
62 int
63 tempsock(char *base, char *name){
64     struct sockaddr_un addr;
65     unsigned long rnd;
66     int sock, res;
67     
68     if((sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0){
69         ERROR("socket error: %s", strerror(errno));
70         return sock;
71     }
72
73     addr.sun_family = AF_UNIX;
74
75     do{
76         rnd = random();
77         sprintf(addr.sun_path, "%s%lu", base, rnd);
78
79         TRACE("trying address %s", addr.sun_path);
80
81         res = bind(sock, (struct sockaddr*)&addr, sizeof(addr));
82     }while((res < 0) && (errno == EADDRINUSE));
83
84     if(res < 0){
85         ERROR("bind error: %s", strerror(errno));
86         return res;
87     }
88     
89     if((res = listen(sock, 10)) < 0){
90         ERROR("listen error: %s", strerror(errno));
91         return res;
92     }
93     
94     if(name)
95         strcpy(name, addr.sun_path);
96
97     return sock;
98 }
99
100 /* From captive/src/libcaptive/sandbox/split.c/captive_sandbox_fd_closeup(): */
101 #define g_return_if_fail(cond) do { if (!(cond)) { ERROR("FAIL: " #cond ); return; } } while (0)
102 #define g_assert(cond) do { if (!(cond)) ERROR("FAIL: " #cond ); } while (0)
103 static void fd_closeup(int fd_first_to_delete,int exception)
104 {
105 DIR *dir;
106 int errint;
107 int dir_fd;
108 struct dirent *dirent;
109
110         dir=opendir("/proc/self/fd/");
111         g_return_if_fail(dir!=NULL);
112         dir_fd=dirfd(dir);
113         g_return_if_fail(dir_fd!=-1);
114
115         while (errno=0,(dirent=readdir(dir))) {
116 long dirent_fd;
117 char *endptr;
118
119                 if (0
120                                 || !strcmp(dirent->d_name,".")
121                                 || !strcmp(dirent->d_name,".."))
122                         continue;
123                 dirent_fd=strtol(dirent->d_name,&endptr,10 /* base */);
124                 g_assert(dirent_fd>=0 && (!endptr || !*endptr));
125                 if (dirent_fd<fd_first_to_delete || dirent_fd==dir_fd || dirent_fd==exception)
126                         continue;
127
128                 errint=close(dirent_fd);
129                 g_assert(errint==0);
130                 errno=0;
131                 errint=close(dirent_fd);
132                 g_assert(errint==-1); g_assert(errno==EBADF);
133                 }
134         g_return_if_fail(errno==0);     /* check for EOF */
135
136         errint=closedir(dir);
137         g_return_if_fail(errint==0);
138         errno=0;
139         close(dir_fd); g_assert(errno==EBADF);  /* just a bit of paranoia; it should be already closed by closedir() */
140 }
141 #undef g_return_if_fail
142 #undef g_assert
143
144 int
145 main(int argc, char **argv){
146     char *service, *mountpoint, *odata;
147     struct list_head cfg;
148     struct fs_ctl *ctl;
149     char tmp[256], *nopts;
150     int ssock, pid, mpid, res;
151
152     INIT_LIST_HEAD(&cfg);
153
154     srandom(time(NULL));
155     setlinebuf(stdout);
156     setlinebuf(stderr);
157
158     /* Close all fds as we will later fork(2) and at least usermount(8) waits
159      * for child finish by select(2) on fd left open for mount(8). We can be
160      * called as external program from mount(8). Close even STD* fds as
161      * usermount(8) uses STDERR for its pipe watching.
162      */
163     /* FIXME: 'quiet' option has no meaning now. */
164     fd_closeup(3,-1);
165
166     if((argc < 5) || (strcmp(argv[3], "-o")) ){
167         ERROR("Usage: %s none <mount-point> -o [options, ...]", argv[0]);
168         exit(1);
169     }
170
171     if(argc > 5){
172         TRACE("more options than expected...");
173     }
174     
175     service = argv[1];
176     mountpoint = argv[2];
177     odata = argv[4];
178     
179
180     nopts = malloc(strlen(odata) + 100);
181     if(!nopts){
182         ERROR("out of memory!");
183         exit(1);
184     }
185
186     strcpy(nopts, odata);
187
188     if(lu_opt_parse(&cfg, "MOUNT", odata) < 0){
189         ERROR("could not parse options!");
190         exit(1);
191     }
192
193     if((lu_opt_loadcfg(&cfg, CONFIG_FILE1) < 0))
194         lu_opt_loadcfg(&cfg, CONFIG_FILE2);
195
196     if(!(ctl = lu_fsctl_create(&cfg))){
197         WARN("could not create fs_ctl!");
198         exit(1);
199     }
200
201     if(!lu_fsctl_mount(ctl)){
202         ERROR("could not mount filesystem!");
203         lu_fsctl_destroy(ctl);
204         exit(1);
205     }
206
207     if((ssock = tempsock("/tmp/lufsd", tmp)) < 0)
208         exit(1);
209
210     TRACE("starting filesystem master at %s", tmp);
211
212     chmod(tmp, S_IRWXU | S_IRWXG | S_IRWXO);
213
214     /* detach & launch FSCtl */
215
216     if((pid = fork()) < 0){
217         ERROR("fork failed!");
218         exit(1);
219     }else
220         if(pid == 0){
221             int fd;
222             const char *quiet;
223             int debug_messages;
224
225             quiet = lu_opt_getchar(&cfg, "MOUNT", "quiet");
226             debug_messages = 0
227                         || lu_opt_getchar(&cfg, "MOUNT",   "debug-messages")
228                         || lu_opt_getchar(&cfg, "MOUNT", "--debug-messages");
229             
230             if((fd = open("/dev/tty", O_RDWR, 0)) < 0){
231                 WARN("couldn't open tty, assuming still ok...");
232                 fflush(stdout);
233             }else{
234                 ioctl(fd, TIOCNOTTY, 0);
235                 close(fd);
236                 setsid();
237             }
238
239             free(nopts);
240
241             /* FIXME: 'quiet' option has no meaning now; check fd_closeup(). */
242             if(!debug_messages){
243                 int stdfd;
244
245                 TRACE("going dumb...");
246                 if((stdfd = open("/dev/null", O_RDWR, 0)) < 0){
247                     WARN("couldn't open /dev/null!");
248                 }else{
249                     dup2(stdfd, 0);
250                     dup2(stdfd, 1);
251                     dup2(stdfd, 2);
252                     close(stdfd);
253                 }
254             }
255
256             /* launching FSCtl... */
257             lu_fsctl_run(ctl, ssock, tmp);
258             exit(0);
259         }
260
261     
262     sprintf(nopts, "%s,server_socket=%s,server_pid=%d", nopts, tmp, pid);
263
264     /* execute lufsmnt and wait for it. */
265     
266     if((mpid = fork()) < 0){
267         ERROR("fork failed!");
268         kill(pid, SIGUSR1);
269         exit(1);
270     }else 
271         if(mpid == 0){
272             char *args[4];
273             const char *p;
274
275             args[0] = "lufsmnt";
276             args[1] = mountpoint;
277             args[2] = nopts;
278             args[3] = NULL;
279
280             TRACE("executing %s %s %s", args[0], args[1], args[2]);
281             execvp("lufsmnt", args);
282             WARN("execvp of lufsmnt failed: %s", strerror(errno));
283             WARN("you don't seem to have lufsmnt in your path. trying regular locations...");
284             
285             for(p = exec_paths[0]; p; p++){
286                 TRACE("trying %s %s %s", p, args[1], args[2]);
287                 execv(p, args);         
288             }
289
290             ERROR("could not launch lufsmnt!\n");
291             exit(1);
292         }
293
294     if(waitpid(mpid, &res, 0) < 0){
295         ERROR("waitpid failed!");
296         kill(pid, SIGUSR1);
297         exit(1);
298     }
299
300     if(WIFEXITED(res) && WEXITSTATUS(res) != 0){
301         kill(pid, SIGUSR1);
302         exit(1);
303     }
304
305     TRACE("mount succeded");
306
307     return 0;
308 }
309
310
311
312
313
314
315