setlinebuf(3) on stdout and stderr to prevent buffering of debug dumps to file.
[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
33 #include <sys/types.h>
34 #include <sys/wait.h>
35 #include <sys/stat.h>
36 #include <sys/socket.h>
37 #include <sys/un.h>
38 #include <sys/ioctl.h>
39 #include <sys/time.h>
40 #include <sys/mount.h>
41
42
43 #include <lufs/proto.h>
44 #include <lufs/fs.h>
45
46 #include "list.h"
47 #include "message.h"
48 #include "filesystem.h"
49 #include "fsctl.h"
50
51 #define CONFIG_FILE1    "/etc/lufsd.conf"
52 #define CONFIG_FILE2    "~/.lufs/lufsd.conf"
53
54 const char *exec_paths[]={
55     "/usr/local/bin/lufsmnt",
56     "/usr/bin/lufsmnt",
57     "/sbin/lufsmnt",
58     NULL
59 };
60
61 int
62 tempsock(char *base, char *name){
63     struct sockaddr_un addr;
64     unsigned long rnd;
65     int sock, res;
66     
67     if((sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0){
68         ERROR("socket error: %s", strerror(errno));
69         return sock;
70     }
71
72     addr.sun_family = AF_UNIX;
73
74     do{
75         rnd = random();
76         sprintf(addr.sun_path, "%s%lu", base, rnd);
77
78         TRACE("trying address %s", addr.sun_path);
79
80         res = bind(sock, (struct sockaddr*)&addr, sizeof(addr));
81     }while((res < 0) && (errno == EADDRINUSE));
82
83     if(res < 0){
84         ERROR("bind error: %s", strerror(errno));
85         return res;
86     }
87     
88     if((res = listen(sock, 10)) < 0){
89         ERROR("listen error: %s", strerror(errno));
90         return res;
91     }
92     
93     if(name)
94         strcpy(name, addr.sun_path);
95
96     return sock;
97 }
98
99 int
100 main(int argc, char **argv){
101     char *service, *mountpoint, *odata;
102     struct list_head cfg;
103     struct fs_ctl *ctl;
104     char tmp[256], *nopts;
105     int ssock, pid, mpid, res;
106
107     INIT_LIST_HEAD(&cfg);
108
109     srandom(time(NULL));
110     setlinebuf(stdout);
111     setlinebuf(stderr);
112
113     if((argc < 5) || (strcmp(argv[3], "-o")) ){
114         ERROR("Usage: %s none <mount-point> -o [options, ...]", argv[0]);
115         exit(1);
116     }
117
118     if(argc > 5){
119         TRACE("more options than expected...");
120     }
121     
122     service = argv[1];
123     mountpoint = argv[2];
124     odata = argv[4];
125     
126
127     nopts = malloc(strlen(odata) + 100);
128     if(!nopts){
129         ERROR("out of memory!");
130         exit(1);
131     }
132
133     strcpy(nopts, odata);
134
135     if(lu_opt_parse(&cfg, "MOUNT", odata) < 0){
136         ERROR("could not parse options!");
137         exit(1);
138     }
139
140     if((lu_opt_loadcfg(&cfg, CONFIG_FILE1) < 0))
141         lu_opt_loadcfg(&cfg, CONFIG_FILE2);
142
143     if(!(ctl = lu_fsctl_create(&cfg))){
144         WARN("could not create fs_ctl!");
145         exit(1);
146     }
147
148     if(!lu_fsctl_mount(ctl)){
149         ERROR("could not mount filesystem!");
150         lu_fsctl_destroy(ctl);
151         exit(1);
152     }
153
154     if((ssock = tempsock("/tmp/lufsd", tmp)) < 0)
155         exit(1);
156
157     TRACE("starting filesystem master at %s", tmp);
158
159     chmod(tmp, S_IRWXU | S_IRWXG | S_IRWXO);
160
161     /* detach & launch FSCtl */
162
163     if((pid = fork()) < 0){
164         ERROR("fork failed!");
165         exit(1);
166     }else
167         if(pid == 0){
168             int fd;
169             const char *quiet;
170
171             quiet = lu_opt_getchar(&cfg, "MOUNT", "quiet");
172             
173             if((fd = open("/dev/tty", O_RDWR, 0)) < 0){
174                 WARN("couldn't open tty, assuming still ok...");
175                 fflush(stdout);
176             }else{
177                 ioctl(fd, TIOCNOTTY, 0);
178                 close(fd);
179                 setsid();
180             }
181
182             free(nopts);
183
184             if(quiet){
185                 int stdfd;
186
187                 TRACE("going dumb...");
188                 if((stdfd = open("/dev/null", O_RDWR, 0)) < 0){
189                     WARN("couldn't open /dev/null!");
190                 }else{
191                     dup2(stdfd, 0);
192                     dup2(stdfd, 1);
193                     dup2(stdfd, 2);
194                     close(stdfd);
195                 }
196             }
197
198             /* launching FSCtl... */
199             lu_fsctl_run(ctl, ssock, tmp);
200             exit(0);
201         }
202
203     
204     sprintf(nopts, "%s,server_socket=%s,server_pid=%d", nopts, tmp, pid);
205
206     /* execute lufsmnt and wait for it. */
207     
208     if((mpid = fork()) < 0){
209         ERROR("fork failed!");
210         kill(pid, SIGUSR1);
211         exit(1);
212     }else 
213         if(mpid == 0){
214             char *args[4];
215             const char *p;
216
217             args[0] = "lufsmnt";
218             args[1] = mountpoint;
219             args[2] = nopts;
220             args[3] = NULL;
221
222             TRACE("executing %s %s %s", args[0], args[1], args[2]);
223             execvp("lufsmnt", args);
224             WARN("execvp of lufsmnt failed: %s", strerror(errno));
225             WARN("you don't seem to have lufsmnt in your path. trying regular locations...");
226             
227             for(p = exec_paths[0]; p; p++){
228                 TRACE("trying %s %s %s", p, args[1], args[2]);
229                 execv(p, args);         
230             }
231
232             ERROR("could not launch lufsmnt!\n");
233             exit(1);
234         }
235
236     if(waitpid(mpid, &res, 0) < 0){
237         ERROR("waitpid failed!");
238         kill(pid, SIGUSR1);
239         exit(1);
240     }
241
242     if(WIFEXITED(res) && WEXITSTATUS(res) != 0){
243         kill(pid, SIGUSR1);
244         exit(1);
245     }
246
247     TRACE("mount succeded");
248
249     return 0;
250 }
251
252
253
254
255
256
257