1 /***********************************************************************
2 *                                                                      *
3 *               This software is part of the ast package               *
4 *          Copyright (c) 2012-2013 AT&T Intellectual Property          *
5 *                      and is licensed under the                       *
6 *                 Eclipse Public License, Version 1.0                  *
7 *                    by AT&T Intellectual Property                     *
8 *                                                                      *
9 *                A copy of the License is available at                 *
10 *          http://www.eclipse.org/org/documents/epl-v10.html           *
11 *         (with md5 checksum b35adb5213ca9657e911e9befb180842)         *
12 *                                                                      *
13 *              Information and Software Systems Research               *
14 *                            AT&T Research                             *
15 *                           Florham Park NJ                            *
16 *                                                                      *
17 *                Lefty Koutsofios <ek@research.att.com>                *
18 *                                                                      *
19 ***********************************************************************/
20 #include "fus3d.h"
21 
22 #include <option.h>
23 
24 static const char usage[] =
25 "[-?\n@(#)$Id: fus3d (AT&T Labs Research) 2013-07-31 $\n]"
26 USAGE_LICENSE
27 "[+NAME?fus3d - FUSE server for the AST 3d filesystem]"
28 "[+DESCRIPTION?\bfus3d\b is a FUSE server implementation of the AST 3d "
29     "filesystem. \atop-directory\a is overlayed onto \abottom-directory\a "
30     "using a FUSE mount -- this forms a \aviewpath\a of the top view over "
31     "the bottom view. A process in the \atop-directory\a view is presented a "
32     "non-duplicated union of the files in both views. Top view files take "
33     "precedence over bottom view files. If a bottom view file is modified "
34     "from the top view it is first copied to the top view. Multi-level "
35     "viewpaths may be constructed by running multiple \bfus3d\b servers. If "
36     "\abottom-directory\a is omitted then the \bfus3d\b view on "
37     "\atop-directory\a is unmounted.]"
38 "[f:foreground?Run the server in the foreground. The default is to detach "
39     "and run as a daemon.]"
40 "[l:log-level?Set the log level to \alevel\a. Higher levels produce more "
41     "log messages on the standard error.]#[level]"
42 "[s:single-thread?Run in single-thread mode. The default is "
43     "multi-threaded.]"
44 "\n"
45 "\ntop-directory [ bottom-directory ]\n"
46 "\n"
47 "[+SEE ALSO?\b3d\b(1)]"
48 ;
49 
50 Ndfs_t		ndfs;
51 
52 static void *init (struct fuse_conn_info *);
53 
54 struct fuse_operations ndfsops = {
55     /* start clock thread */
56     .init       = init,
57 
58     /* filesystem calls */
59     .statfs     = ndfsstatfs,
60 
61     /* metadata calls */
62     .mkdir      = ndfsmkdir,
63     .rmdir      = ndfsrmdir,
64     .link       = ndfslink,
65     .symlink    = ndfssymlink,
66     .unlink     = ndfsunlink,
67     .readlink   = ndfsreadlink,
68     .chmod      = ndfschmod,
69     .utimens    = ndfsutimens,
70     .rename     = ndfsrename,
71     .access     = ndfsaccess,
72     .getattr    = ndfsgetattr,
73     .fgetattr   = ndfsfgetattr,
74 
75     /* data calls */
76     .opendir    = ndfsopendir,
77     .readdir    = ndfsreaddir,
78     .releasedir = ndfsreleasedir,
79     .create     = ndfscreate,
80     .open       = ndfsopen,
81     .flush      = ndfsflush,
82     .release    = ndfsrelease,
83     .read       = ndfsread,
84     .write      = ndfswrite,
85     .truncate   = ndfstruncate,
86     .ftruncate  = ndfsftruncate,
87     .fsync      = ndfsfsync,
88     .ioctl      = ndfsioctl,
89 
90     .flag_nullpath_ok = 1,
91 };
92 
main(int argc,char ** argv)93 int main (int argc, char **argv) {
94     char *fuseargv[100];
95     int fuseargc, fuseargc1;
96     int daemonmode, multithreadmode;
97 
98     int ret;
99     char *s, path[PATH_MAX + 10];
100     int l;
101 
102     daemonmode = 1;
103     multithreadmode = 1;
104     for (;;) {
105         switch (optget (argv, usage)) {
106         case 'f':
107             daemonmode = 0;
108             continue;
109         case 'l':
110             ndfs.level = (int)opt_info.number;
111             continue;
112         case 's':
113             multithreadmode = 0;
114             continue;
115         case '?':
116             err (NiL, opt_info.arg);
117             continue;
118         case ':':
119             err (NiL, opt_info.arg);
120             continue;
121         }
122         break;
123     }
124     argc -= opt_info.index;
125     argv += opt_info.index;
126     if (argc == 1) {
127         fuseargc = 0;
128         fuseargv[fuseargc++] = "fusermount";
129         fuseargv[fuseargc++] = "-u";
130         fuseargv[fuseargc++] = argv[0];
131         fuseargv[fuseargc] = 0;
132 	execvp(fuseargv[0], fuseargv);
133 	err ("%s: cannot execute", fuseargv[0]);
134     }
135     if (argc != 2) {
136         err ("%s", optusage(NiL));
137         return 1;
138     }
139 #if !_ASO_INTRINSIC
140     err ("ASO method initialization error");
141 #endif
142 
143     pthread_mutex_init (&ndfs.mutex, NULL);
144     ndfs.top.str = 0;
145     ndfs.top.len = 0;
146     ndfs.bot.str = 0;
147     ndfs.bot.len = 0;
148     ndfs.dfd = -1;
149 
150     ndfs.uid = getuid ();
151     ndfs.gid = getgid ();
152     if (!(ndfs.vm = vmopen (Vmdcsbrk, Vmbest, VMFLAGS)))
153         err ("cannot open vmregion");
154     if (utilinit () == -1)
155         err ("cannot initialize utils");
156 
157     strcpy (path, argv[0]);
158     if ((l = strlen (path)) == 0 || l >= PATH_MAX || path[0] != '/')
159         err ("bad top prefix %s", path);
160     if (path[l - 1] != '/')
161         path[l++] = '/', path[l] = 0;
162     if (!(ndfs.top.str = vmstrdup (ndfs.vm, path)))
163         err ("cannot copy top prefix %s", path);
164     ndfs.top.len = strlen (ndfs.top.str);
165     path[l - 1] = 0;
166 
167     s = strrchr (path, '/'), *s = 0;
168     if (!(ndfs.par.str = vmstrdup (ndfs.vm, path)))
169         err ("cannot copy parent prefix %s", path);
170     ndfs.par.len = strlen (ndfs.par.str);
171 
172     strcpy (path, argv[1]);
173     if ((l = strlen (path)) == 0 || l >= PATH_MAX || path[0] != '/')
174         err ("bad bottom prefix %s", path);
175     if (path[l - 1] != '/')
176         path[l++] = '/', path[l] = 0;
177     if (!(ndfs.bot.str = vmstrdup (ndfs.vm, path)))
178         err ("cannot copy bottom prefix %s", path);
179     ndfs.bot.len = strlen (ndfs.bot.str);
180 
181     fuseargc = 0;
182     fuseargv[fuseargc++] = "fus3d";
183     fuseargv[fuseargc++] = "-o";
184     fuseargv[fuseargc++] = "nonempty";
185     fuseargv[fuseargc++] = "-o";
186     fuseargv[fuseargc++] = "use_ino";
187     fuseargv[fuseargc++] = "-o";
188     fuseargv[fuseargc++] = "attr_timeout=0";
189     if (!daemonmode)
190         fuseargv[fuseargc++] = "-f";
191     if (!multithreadmode)
192         fuseargv[fuseargc++] = "-s";
193     fuseargv[fuseargc] = 0;
194     fuseargc1 = fuseargc;
195     fuseargv[fuseargc++] = "-o";
196     fuseargv[fuseargc++] = "allow_other";
197     fuseargv[fuseargc++] = "-o";
198     fuseargv[fuseargc++] = "default_permissions";
199     fuseargv[fuseargc++] = ndfs.top.str;
200     fuseargv[fuseargc] = 0;
201 
202     if ((ndfs.dfd = open (ndfs.top.str, O_RDONLY)) == -1)
203         err ("cannot open top directory %s", ndfs.top.str);
204 
205     if ((ret = fuse_main (fuseargc, fuseargv, &ndfsops, NULL)) != 0) {
206         log (LOG(0,"main"), "retry mount with noallow_other option");
207         fuseargc = fuseargc1;
208         fuseargv[fuseargc++] = ndfs.top.str;
209         fuseargv[fuseargc] = 0;
210         ret = fuse_main (fuseargc, fuseargv, &ndfsops, NULL);
211     }
212 
213     utilterm ();
214 
215     return ret;
216 }
217 
218 static pthread_t clockthread;
219 
clockserve(void * data)220 static void *clockserve (void *data) {
221     Tv_t tv;
222     Tv_t rv;
223     time_t t;
224 
225     for (;;) {
226 	asocas32(&ndfs.now, ndfs.now, time(NiL));
227         tv.tv_sec = 1;
228         tv.tv_nsec = 0;
229         while (tvsleep (&tv, &rv) < 0 && errno == EINTR)
230 		tv = rv;
231     }
232     return NULL;
233 }
234 
init(struct fuse_conn_info * fcip)235 static void *init (struct fuse_conn_info *fcip) {
236     fchdir (ndfs.dfd);
237     close (ndfs.dfd);
238     pthread_create (&clockthread, NULL, &clockserve, NULL);
239     return NULL;
240 }
241