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