uml-linux-2.6.7-01-bb1-complete
[linux-2.6.git] / fs / hostfs / host_fs.c
1 /* 
2  * Copyright (C) 2000 - 2004 Jeff Dike (jdike@addtoit.com)
3  * Licensed under the GPL
4  */
5
6 #include "linux/stddef.h"
7 #include "linux/string.h"
8 #include "linux/types.h"
9 #include "linux/errno.h"
10 #include "linux/slab.h"
11 #include "linux/init.h"
12 #include "linux/fs.h"
13 #include "linux/stat.h"
14 #include "hostfs.h"
15 #include "kern.h"
16 #include "init.h"
17 #include "kern_util.h"
18 #include "filehandle.h"
19 #include "os.h"
20
21 /* Changed in hostfs_args before the kernel starts running */
22 static char *jail_dir = "/";
23 int append = 0;
24
25 static int __init hostfs_args(char *options, int *add)
26 {
27         char *ptr;
28
29         ptr = strchr(options, ',');
30         if(ptr != NULL)
31                 *ptr++ = '\0';
32         if(*options != '\0')
33                 jail_dir = options;
34
35         options = ptr;
36         while(options){
37                 ptr = strchr(options, ',');
38                 if(ptr != NULL)
39                         *ptr++ = '\0';
40                 if(*options != '\0'){
41                         if(!strcmp(options, "append"))
42                                 append = 1;
43                         else printf("hostfs_args - unsupported option - %s\n",
44                                     options);
45                 }
46                 options = ptr;
47         }
48         return(0);
49 }
50
51 __uml_setup("hostfs=", hostfs_args,
52 "hostfs=<root dir>,<flags>,...\n"
53 "    This is used to set hostfs parameters.  The root directory argument\n"
54 "    is used to confine all hostfs mounts to within the specified directory\n"
55 "    tree on the host.  If this isn't specified, then a user inside UML can\n"
56 "    mount anything on the host that's accessible to the user that's running\n"
57 "    it.\n"
58 "    The only flag currently supported is 'append', which specifies that all\n"
59 "    files opened by hostfs will be opened in append mode.\n\n"
60 );
61
62 struct hostfs_data {
63         struct externfs_data ext;
64         char *mount;
65 };
66
67 struct hostfs_file {
68         struct externfs_inode ext;
69         struct file_handle fh;
70 };
71
72 static int hostfs_access_file(char *file, int uid, int w, int x, int gid, 
73                               int r, struct externfs_data *ed)
74 {
75         char *mount = container_of(ed, struct hostfs_data, ext)->mount;
76         const char *path[] = { jail_dir, mount, file, NULL };
77         char tmp[HOSTFS_BUFSIZE];
78         int err, mode = 0;
79
80         if(r) mode = OS_ACC_R_OK;
81         if(w) mode |= OS_ACC_W_OK;
82         if(x) mode |= OS_ACC_X_OK;
83         
84         err = -ENOMEM;
85         file = get_path(path, tmp, sizeof(tmp));
86         if(file == NULL)
87                 goto out;
88
89         err = os_access(file, mode);
90         free_path(file, tmp);
91  out:
92         return(err);
93 }
94
95 static int hostfs_make_node(const char *file, int mode, int uid, int gid, 
96                             int type, int major, int minor, 
97                             struct externfs_data *ed)
98 {
99         char *mount = container_of(ed, struct hostfs_data, ext)->mount;
100         const char *path[] = { jail_dir, mount, file, NULL };
101         char tmp[HOSTFS_BUFSIZE];
102         int err = -ENOMEM;
103
104         file = get_path(path, tmp, sizeof(tmp));
105         if(file == NULL)
106                 goto out;
107
108         /* XXX Pass type in an OS-independent way */
109         mode |= type;
110
111         err = os_make_dev(file, mode, major, minor);
112         free_path(file, tmp);
113  out:
114         return(err);
115 }
116
117 static int hostfs_stat_file(const char *file, struct externfs_data *ed, 
118                             dev_t *dev_out, unsigned long long *inode_out, 
119                             int *mode_out, int *nlink_out, int *uid_out, 
120                             int *gid_out, unsigned long long *size_out, 
121                             unsigned long *atime_out, unsigned long *mtime_out,
122                             unsigned long *ctime_out, int *blksize_out, 
123                             unsigned long long *blocks_out)
124 {
125         char *mount = container_of(ed, struct hostfs_data, ext)->mount;
126         const char *path[] = { jail_dir, mount, file, NULL };
127
128         /* XXX Why pretend everything is owned by root? */
129         *uid_out = 0;
130         *gid_out = 0;
131         return(host_stat_file(path, dev_out, inode_out, mode_out, nlink_out,
132                               NULL, NULL, size_out, atime_out, mtime_out,
133                               ctime_out, blksize_out, blocks_out));
134 }
135
136 static int hostfs_file_type(const char *file, int *rdev, 
137                             struct externfs_data *ed)
138 {
139         char *mount = container_of(ed, struct hostfs_data, ext)->mount;
140         const char *path[] = { jail_dir, mount, file, NULL };
141
142         return(host_file_type(path, rdev));
143 }
144
145 static char *hostfs_name(struct inode *inode)
146 {
147         struct externfs_data *ed = inode_externfs_info(inode);
148         char *mount = container_of(ed, struct hostfs_data, ext)->mount;
149
150         return(inode_name_prefix(inode, mount));        
151 }
152
153 static struct externfs_inode *hostfs_init_file(struct externfs_data *ed)
154 {
155         struct hostfs_file *hf;
156
157         hf = kmalloc(sizeof(*hf), GFP_KERNEL);
158         if(hf == NULL)
159                 return(NULL);
160
161         hf->fh.fd = -1;
162         return(&hf->ext);
163 }
164
165 static int hostfs_open_file(struct externfs_inode *ext, char *file, 
166                             int uid, int gid, struct inode *inode, 
167                             struct externfs_data *ed)
168 {
169         struct hostfs_file *hf = container_of(ext, struct hostfs_file, ext);
170         char *mount = container_of(ed, struct hostfs_data, ext)->mount;
171         const char *path[] = { jail_dir, mount, file, NULL };
172         int err;
173
174         err = host_open_file(path, 1, 1, &hf->fh);
175         if(err == -EISDIR)
176                 goto out;
177
178         if(err == -EACCES)
179                 err = host_open_file(path, 1, 0, &hf->fh);
180
181         if(err)
182                 goto out;
183
184         is_reclaimable(&hf->fh, hostfs_name, inode);
185  out:
186         return(err);
187 }
188
189 static void *hostfs_open_dir(char *file, int uid, int gid, 
190                              struct externfs_data *ed)
191 {
192         char *mount = container_of(ed, struct hostfs_data, ext)->mount;
193         const char *path[] = { jail_dir, mount, file, NULL };
194
195         return(host_open_dir(path));
196 }
197
198 static void hostfs_close_dir(void *stream, struct externfs_data *ed)
199 {
200         os_close_dir(stream);
201 }
202
203 static char *hostfs_read_dir(void *stream, unsigned long long *pos, 
204                              unsigned long long *ino_out, int *len_out, 
205                              struct externfs_data *ed)
206 {
207         char *mount = container_of(ed, struct hostfs_data, ext)->mount;
208
209         return(generic_host_read_dir(stream, pos, ino_out, len_out, mount));
210 }
211
212 static int hostfs_read_file(struct externfs_inode *ext, 
213                             unsigned long long offset, char *buf, int len, 
214                             int ignore_start, int ignore_end,
215                             void (*completion)(char *, int, void *), void *arg,
216                             struct externfs_data *ed)
217 {
218         struct hostfs_file *hf = container_of(ext, struct hostfs_file, ext);
219         int err = 0;
220
221         if(ignore_start != 0){
222                 err = read_file(&hf->fh, offset, buf, ignore_start);
223                 if(err < 0)
224                         goto out;
225         }
226
227         if(ignore_end != len)
228                 err = read_file(&hf->fh, offset + ignore_end, buf + ignore_end,
229                                 len - ignore_end);
230
231  out:
232
233         (*completion)(buf, err, arg);
234         if (err > 0)
235                 err = 0;
236         return(err);
237 }
238
239 static int hostfs_write_file(struct externfs_inode *ext,
240                              unsigned long long offset, const char *buf, 
241                              int start, int len, 
242                              void (*completion)(char *, int, void *), 
243                              void *arg, struct externfs_data *ed)
244 {
245         struct file_handle *fh;
246         int err;
247
248         fh = &container_of(ext, struct hostfs_file, ext)->fh;
249         err = write_file(fh, offset + start, buf + start, len);
250
251         (*completion)((char *) buf, err, arg);
252         if (err > 0)
253                 err = 0;
254
255         return(err);
256 }
257
258 static int hostfs_create_file(struct externfs_inode *ext, char *file, int mode,
259                               int uid, int gid, struct inode *inode, 
260                               struct externfs_data *ed)
261 {
262         struct hostfs_file *hf = container_of(ext, struct hostfs_file, 
263                                               ext);
264         char *mount = container_of(ed, struct hostfs_data, ext)->mount;
265         const char *path[] = { jail_dir, mount, file, NULL };
266         int err = -ENOMEM;
267         
268         err = host_create_file(path, mode, &hf->fh);
269         if(err)
270                 goto out;
271
272         is_reclaimable(&hf->fh, hostfs_name, inode);
273  out:
274         return(err);
275 }
276
277 static int hostfs_set_attr(const char *file, struct externfs_iattr *attrs, 
278                            struct externfs_data *ed)
279 {
280         char *mount = container_of(ed, struct hostfs_data, ext)->mount;
281         const char *path[] = { jail_dir, mount, file, NULL };
282
283         return(host_set_attr(path, attrs));
284 }
285
286 static int hostfs_make_symlink(const char *from, const char *to, int uid, 
287                                int gid, struct externfs_data *ed)
288 {
289         char *mount = container_of(ed, struct hostfs_data, ext)->mount;
290         const char *path[] = { jail_dir, mount, from, NULL };
291
292         return(host_make_symlink(path, to));
293 }
294
295 static int hostfs_link_file(const char *to, const char *from, int uid, int gid,
296                             struct externfs_data *ed)
297 {
298         char *mount = container_of(ed, struct hostfs_data, ext)->mount;
299         const char *to_path[] = { jail_dir, mount, to, NULL };
300         const char *from_path[] = { jail_dir, mount, from, NULL };
301
302         return(host_link_file(to_path, from_path));
303 }
304
305 static int hostfs_unlink_file(const char *file, struct externfs_data *ed)
306 {
307         char *mount = container_of(ed, struct hostfs_data, ext)->mount;
308         const char *path[] = { jail_dir, mount, file, NULL };
309
310         return(host_unlink_file(path));
311 }
312
313 static int hostfs_make_dir(const char *file, int mode, int uid, int gid, 
314                            struct externfs_data *ed)
315 {
316         char *mount = container_of(ed, struct hostfs_data, ext)->mount;
317         const char *path[] = { jail_dir, mount, file, NULL };
318
319         return(host_make_dir(path, mode));
320 }
321
322 static int hostfs_remove_dir(const char *file, int uid, int gid, 
323                              struct externfs_data *ed)
324 {
325         char *mount = container_of(ed, struct hostfs_data, ext)->mount;
326         const char *path[] = { jail_dir, mount, file, NULL };
327
328         return(host_remove_dir(path));
329 }
330
331 static int hostfs_read_link(char *file, int uid, int gid, char *buf, int size, 
332                             struct externfs_data *ed)
333 {
334         char *mount = container_of(ed, struct hostfs_data, ext)->mount;
335         const char *path[] = { jail_dir, mount, file, NULL };
336
337         return(host_read_link(path, buf, size));
338 }
339
340 static int hostfs_rename_file(char *from, char *to, struct externfs_data *ed)
341 {
342         char *mount = container_of(ed, struct hostfs_data, ext)->mount;
343         const char *to_path[] = { jail_dir, mount, to, NULL };
344         const char *from_path[] = { jail_dir, mount, from, NULL };
345
346         return(host_rename_file(from_path, to_path));
347 }
348
349 static int hostfs_stat_fs(long *bsize_out, long long *blocks_out, 
350                           long long *bfree_out, long long *bavail_out, 
351                           long long *files_out, long long *ffree_out,
352                           void *fsid_out, int fsid_size, long *namelen_out, 
353                           long *spare_out, struct externfs_data *ed)
354 {
355         char *mount = container_of(ed, struct hostfs_data, ext)->mount;
356         const char *path[] = { jail_dir, mount, NULL };
357
358         return(host_stat_fs(path, bsize_out, blocks_out, bfree_out, bavail_out,
359                             files_out, ffree_out, fsid_out, fsid_size, 
360                             namelen_out, spare_out));
361 }
362
363 void hostfs_close_file(struct externfs_inode *ext,
364                        unsigned long long size)
365 {
366         struct hostfs_file *hf = container_of(ext, struct hostfs_file, ext);
367
368         if(hf->fh.fd != -1){
369                 truncate_file(&hf->fh, size);
370                 close_file(&hf->fh);
371         }
372
373         kfree(hf);
374 }
375
376 int hostfs_truncate_file(struct externfs_inode *ext, __u64 size, 
377                          struct externfs_data *ed)
378 {
379         struct hostfs_file *hf = container_of(ext, struct hostfs_file, ext);
380
381         return(truncate_file(&hf->fh, size));
382 }
383
384 static struct externfs_file_ops hostfs_file_ops = {
385         .stat_file              = hostfs_stat_file,
386         .file_type              = hostfs_file_type,
387         .access_file            = hostfs_access_file,
388         .open_file              = hostfs_open_file,
389         .open_dir               = hostfs_open_dir,
390         .read_dir               = hostfs_read_dir,
391         .read_file              = hostfs_read_file,
392         .write_file             = hostfs_write_file,
393         .map_file_page          = NULL,
394         .close_file             = hostfs_close_file,
395         .close_dir              = hostfs_close_dir,
396         .invisible              = NULL,
397         .create_file            = hostfs_create_file,
398         .set_attr               = hostfs_set_attr,
399         .make_symlink           = hostfs_make_symlink,
400         .unlink_file            = hostfs_unlink_file,
401         .make_dir               = hostfs_make_dir,
402         .remove_dir             = hostfs_remove_dir,
403         .make_node              = hostfs_make_node,
404         .link_file              = hostfs_link_file,
405         .read_link              = hostfs_read_link,
406         .rename_file            = hostfs_rename_file,
407         .statfs                 = hostfs_stat_fs,
408         .truncate_file          = hostfs_truncate_file
409 };
410
411 static struct externfs_data *mount_fs(char *mount_arg)
412 {
413         struct hostfs_data *hd;
414         int err = -ENOMEM;
415
416         hd = kmalloc(sizeof(*hd), GFP_KERNEL);
417         if(hd == NULL)
418                 goto out;
419
420         hd->mount = host_root_filename(mount_arg);
421         if(hd->mount == NULL)
422                 goto out_free;
423
424         init_externfs(&hd->ext, &hostfs_file_ops);
425
426         return(&hd->ext);
427
428  out_free:
429         kfree(hd);
430  out:
431         return(ERR_PTR(err));
432 }
433
434 static struct externfs_mount_ops hostfs_mount_ops = {
435         .init_file              = hostfs_init_file,
436         .mount                  = mount_fs,
437 };
438
439 static int __init init_hostfs(void)
440 {
441         return(register_externfs("hostfs", &hostfs_mount_ops));
442 }
443
444 static void __exit exit_hostfs(void)
445 {
446         unregister_externfs("hostfs");
447 }
448
449 __initcall(init_hostfs);
450 __exitcall(exit_hostfs);
451
452 #if 0
453 module_init(init_hostfs)
454 module_exit(exit_hostfs)
455 MODULE_LICENSE("GPL");
456 #endif
457
458 /*
459  * Overrides for Emacs so that we follow Linus's tabbing style.
460  * Emacs will notice this stuff at the end of the file and automatically
461  * adjust the settings for this buffer only.  This must remain at the end
462  * of the file.
463  * ---------------------------------------------------------------------------
464  * Local variables:
465  * c-file-style: "linux"
466  * End:
467  */