These changes are the raw update to qemu-2.6.
[kvmfornfv.git] / qemu / hw / 9pfs / 9p-handle.c
1 /*
2  * 9p handle callback
3  *
4  * Copyright IBM, Corp. 2011
5  *
6  * Authors:
7  *    Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
8  *
9  * This work is licensed under the terms of the GNU GPL, version 2.  See
10  * the COPYING file in the top-level directory.
11  *
12  */
13
14 #include "qemu/osdep.h"
15 #include "9p.h"
16 #include "9p-xattr.h"
17 #include <arpa/inet.h>
18 #include <pwd.h>
19 #include <grp.h>
20 #include <sys/socket.h>
21 #include <sys/un.h>
22 #include "qemu/xattr.h"
23 #include "qemu/cutils.h"
24 #include "qemu/error-report.h"
25 #include <linux/fs.h>
26 #ifdef CONFIG_LINUX_MAGIC_H
27 #include <linux/magic.h>
28 #endif
29 #include <sys/ioctl.h>
30
31 #ifndef XFS_SUPER_MAGIC
32 #define XFS_SUPER_MAGIC  0x58465342
33 #endif
34 #ifndef EXT2_SUPER_MAGIC
35 #define EXT2_SUPER_MAGIC 0xEF53
36 #endif
37 #ifndef REISERFS_SUPER_MAGIC
38 #define REISERFS_SUPER_MAGIC 0x52654973
39 #endif
40 #ifndef BTRFS_SUPER_MAGIC
41 #define BTRFS_SUPER_MAGIC 0x9123683E
42 #endif
43
44 struct handle_data {
45     int mountfd;
46     int handle_bytes;
47 };
48
49 static inline int name_to_handle(int dirfd, const char *name,
50                                  struct file_handle *fh, int *mnt_id, int flags)
51 {
52     return name_to_handle_at(dirfd, name, fh, mnt_id, flags);
53 }
54
55 static inline int open_by_handle(int mountfd, const char *fh, int flags)
56 {
57     return open_by_handle_at(mountfd, (struct file_handle *)fh, flags);
58 }
59
60 static int handle_update_file_cred(int dirfd, const char *name, FsCred *credp)
61 {
62     int fd, ret;
63     fd = openat(dirfd, name, O_NONBLOCK | O_NOFOLLOW);
64     if (fd < 0) {
65         return fd;
66     }
67     ret = fchownat(fd, "", credp->fc_uid, credp->fc_gid, AT_EMPTY_PATH);
68     if (ret < 0) {
69         goto err_out;
70     }
71     ret = fchmod(fd, credp->fc_mode & 07777);
72 err_out:
73     close(fd);
74     return ret;
75 }
76
77
78 static int handle_lstat(FsContext *fs_ctx, V9fsPath *fs_path,
79                         struct stat *stbuf)
80 {
81     int fd, ret;
82     struct handle_data *data = (struct handle_data *)fs_ctx->private;
83
84     fd = open_by_handle(data->mountfd, fs_path->data, O_PATH);
85     if (fd < 0) {
86         return fd;
87     }
88     ret = fstatat(fd, "", stbuf, AT_EMPTY_PATH);
89     close(fd);
90     return ret;
91 }
92
93 static ssize_t handle_readlink(FsContext *fs_ctx, V9fsPath *fs_path,
94                                char *buf, size_t bufsz)
95 {
96     int fd, ret;
97     struct handle_data *data = (struct handle_data *)fs_ctx->private;
98
99     fd = open_by_handle(data->mountfd, fs_path->data, O_PATH);
100     if (fd < 0) {
101         return fd;
102     }
103     ret = readlinkat(fd, "", buf, bufsz);
104     close(fd);
105     return ret;
106 }
107
108 static int handle_close(FsContext *ctx, V9fsFidOpenState *fs)
109 {
110     return close(fs->fd);
111 }
112
113 static int handle_closedir(FsContext *ctx, V9fsFidOpenState *fs)
114 {
115     return closedir(fs->dir);
116 }
117
118 static int handle_open(FsContext *ctx, V9fsPath *fs_path,
119                        int flags, V9fsFidOpenState *fs)
120 {
121     struct handle_data *data = (struct handle_data *)ctx->private;
122
123     fs->fd = open_by_handle(data->mountfd, fs_path->data, flags);
124     return fs->fd;
125 }
126
127 static int handle_opendir(FsContext *ctx,
128                           V9fsPath *fs_path, V9fsFidOpenState *fs)
129 {
130     int ret;
131     ret = handle_open(ctx, fs_path, O_DIRECTORY, fs);
132     if (ret < 0) {
133         return -1;
134     }
135     fs->dir = fdopendir(ret);
136     if (!fs->dir) {
137         return -1;
138     }
139     return 0;
140 }
141
142 static void handle_rewinddir(FsContext *ctx, V9fsFidOpenState *fs)
143 {
144     rewinddir(fs->dir);
145 }
146
147 static off_t handle_telldir(FsContext *ctx, V9fsFidOpenState *fs)
148 {
149     return telldir(fs->dir);
150 }
151
152 static int handle_readdir_r(FsContext *ctx, V9fsFidOpenState *fs,
153                             struct dirent *entry,
154                             struct dirent **result)
155 {
156     return readdir_r(fs->dir, entry, result);
157 }
158
159 static void handle_seekdir(FsContext *ctx, V9fsFidOpenState *fs, off_t off)
160 {
161     seekdir(fs->dir, off);
162 }
163
164 static ssize_t handle_preadv(FsContext *ctx, V9fsFidOpenState *fs,
165                              const struct iovec *iov,
166                              int iovcnt, off_t offset)
167 {
168 #ifdef CONFIG_PREADV
169     return preadv(fs->fd, iov, iovcnt, offset);
170 #else
171     int err = lseek(fs->fd, offset, SEEK_SET);
172     if (err == -1) {
173         return err;
174     } else {
175         return readv(fs->fd, iov, iovcnt);
176     }
177 #endif
178 }
179
180 static ssize_t handle_pwritev(FsContext *ctx, V9fsFidOpenState *fs,
181                               const struct iovec *iov,
182                               int iovcnt, off_t offset)
183 {
184     ssize_t ret;
185 #ifdef CONFIG_PREADV
186     ret = pwritev(fs->fd, iov, iovcnt, offset);
187 #else
188     int err = lseek(fs->fd, offset, SEEK_SET);
189     if (err == -1) {
190         return err;
191     } else {
192         ret = writev(fs->fd, iov, iovcnt);
193     }
194 #endif
195 #ifdef CONFIG_SYNC_FILE_RANGE
196     if (ret > 0 && ctx->export_flags & V9FS_IMMEDIATE_WRITEOUT) {
197         /*
198          * Initiate a writeback. This is not a data integrity sync.
199          * We want to ensure that we don't leave dirty pages in the cache
200          * after write when writeout=immediate is sepcified.
201          */
202         sync_file_range(fs->fd, offset, ret,
203                         SYNC_FILE_RANGE_WAIT_BEFORE | SYNC_FILE_RANGE_WRITE);
204     }
205 #endif
206     return ret;
207 }
208
209 static int handle_chmod(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp)
210 {
211     int fd, ret;
212     struct handle_data *data = (struct handle_data *)fs_ctx->private;
213
214     fd = open_by_handle(data->mountfd, fs_path->data, O_NONBLOCK);
215     if (fd < 0) {
216         return fd;
217     }
218     ret = fchmod(fd, credp->fc_mode);
219     close(fd);
220     return ret;
221 }
222
223 static int handle_mknod(FsContext *fs_ctx, V9fsPath *dir_path,
224                        const char *name, FsCred *credp)
225 {
226     int dirfd, ret;
227     struct handle_data *data = (struct handle_data *)fs_ctx->private;
228
229     dirfd = open_by_handle(data->mountfd, dir_path->data, O_PATH);
230     if (dirfd < 0) {
231         return dirfd;
232     }
233     ret = mknodat(dirfd, name, credp->fc_mode, credp->fc_rdev);
234     if (!ret) {
235         ret = handle_update_file_cred(dirfd, name, credp);
236     }
237     close(dirfd);
238     return ret;
239 }
240
241 static int handle_mkdir(FsContext *fs_ctx, V9fsPath *dir_path,
242                        const char *name, FsCred *credp)
243 {
244     int dirfd, ret;
245     struct handle_data *data = (struct handle_data *)fs_ctx->private;
246
247     dirfd = open_by_handle(data->mountfd, dir_path->data, O_PATH);
248     if (dirfd < 0) {
249         return dirfd;
250     }
251     ret = mkdirat(dirfd, name, credp->fc_mode);
252     if (!ret) {
253         ret = handle_update_file_cred(dirfd, name, credp);
254     }
255     close(dirfd);
256     return ret;
257 }
258
259 static int handle_fstat(FsContext *fs_ctx, int fid_type,
260                         V9fsFidOpenState *fs, struct stat *stbuf)
261 {
262     int fd;
263
264     if (fid_type == P9_FID_DIR) {
265         fd = dirfd(fs->dir);
266     } else {
267         fd = fs->fd;
268     }
269     return fstat(fd, stbuf);
270 }
271
272 static int handle_open2(FsContext *fs_ctx, V9fsPath *dir_path, const char *name,
273                         int flags, FsCred *credp, V9fsFidOpenState *fs)
274 {
275     int ret;
276     int dirfd, fd;
277     struct handle_data *data = (struct handle_data *)fs_ctx->private;
278
279     dirfd = open_by_handle(data->mountfd, dir_path->data, O_PATH);
280     if (dirfd < 0) {
281         return dirfd;
282     }
283     fd = openat(dirfd, name, flags | O_NOFOLLOW, credp->fc_mode);
284     if (fd >= 0) {
285         ret = handle_update_file_cred(dirfd, name, credp);
286         if (ret < 0) {
287             close(fd);
288             fd = ret;
289         } else {
290             fs->fd = fd;
291         }
292     }
293     close(dirfd);
294     return fd;
295 }
296
297
298 static int handle_symlink(FsContext *fs_ctx, const char *oldpath,
299                           V9fsPath *dir_path, const char *name, FsCred *credp)
300 {
301     int fd, dirfd, ret;
302     struct handle_data *data = (struct handle_data *)fs_ctx->private;
303
304     dirfd = open_by_handle(data->mountfd, dir_path->data, O_PATH);
305     if (dirfd < 0) {
306         return dirfd;
307     }
308     ret = symlinkat(oldpath, dirfd, name);
309     if (!ret) {
310         fd = openat(dirfd, name, O_PATH | O_NOFOLLOW);
311         if (fd < 0) {
312             ret = fd;
313             goto err_out;
314         }
315         ret = fchownat(fd, "", credp->fc_uid, credp->fc_gid, AT_EMPTY_PATH);
316         close(fd);
317     }
318 err_out:
319     close(dirfd);
320     return ret;
321 }
322
323 static int handle_link(FsContext *ctx, V9fsPath *oldpath,
324                        V9fsPath *dirpath, const char *name)
325 {
326     int oldfd, newdirfd, ret;
327     struct handle_data *data = (struct handle_data *)ctx->private;
328
329     oldfd = open_by_handle(data->mountfd, oldpath->data, O_PATH);
330     if (oldfd < 0) {
331         return oldfd;
332     }
333     newdirfd = open_by_handle(data->mountfd, dirpath->data, O_PATH);
334     if (newdirfd < 0) {
335         close(oldfd);
336         return newdirfd;
337     }
338     ret = linkat(oldfd, "", newdirfd, name, AT_EMPTY_PATH);
339     close(newdirfd);
340     close(oldfd);
341     return ret;
342 }
343
344 static int handle_truncate(FsContext *ctx, V9fsPath *fs_path, off_t size)
345 {
346     int fd, ret;
347     struct handle_data *data = (struct handle_data *)ctx->private;
348
349     fd = open_by_handle(data->mountfd, fs_path->data, O_NONBLOCK | O_WRONLY);
350     if (fd < 0) {
351         return fd;
352     }
353     ret = ftruncate(fd, size);
354     close(fd);
355     return ret;
356 }
357
358 static int handle_rename(FsContext *ctx, const char *oldpath,
359                          const char *newpath)
360 {
361     errno = EOPNOTSUPP;
362     return -1;
363 }
364
365 static int handle_chown(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp)
366 {
367     int fd, ret;
368     struct handle_data *data = (struct handle_data *)fs_ctx->private;
369
370     fd = open_by_handle(data->mountfd, fs_path->data, O_PATH);
371     if (fd < 0) {
372         return fd;
373     }
374     ret = fchownat(fd, "", credp->fc_uid, credp->fc_gid, AT_EMPTY_PATH);
375     close(fd);
376     return ret;
377 }
378
379 static int handle_utimensat(FsContext *ctx, V9fsPath *fs_path,
380                             const struct timespec *buf)
381 {
382     int ret;
383 #ifdef CONFIG_UTIMENSAT
384     int fd;
385     struct handle_data *data = (struct handle_data *)ctx->private;
386
387     fd = open_by_handle(data->mountfd, fs_path->data, O_NONBLOCK);
388     if (fd < 0) {
389         return fd;
390     }
391     ret = futimens(fd, buf);
392     close(fd);
393 #else
394     ret = -1;
395     errno = ENOSYS;
396 #endif
397     return ret;
398 }
399
400 static int handle_remove(FsContext *ctx, const char *path)
401 {
402     errno = EOPNOTSUPP;
403     return -1;
404 }
405
406 static int handle_fsync(FsContext *ctx, int fid_type,
407                         V9fsFidOpenState *fs, int datasync)
408 {
409     int fd;
410
411     if (fid_type == P9_FID_DIR) {
412         fd = dirfd(fs->dir);
413     } else {
414         fd = fs->fd;
415     }
416
417     if (datasync) {
418         return qemu_fdatasync(fd);
419     } else {
420         return fsync(fd);
421     }
422 }
423
424 static int handle_statfs(FsContext *ctx, V9fsPath *fs_path,
425                          struct statfs *stbuf)
426 {
427     int fd, ret;
428     struct handle_data *data = (struct handle_data *)ctx->private;
429
430     fd = open_by_handle(data->mountfd, fs_path->data, O_NONBLOCK);
431     if (fd < 0) {
432         return fd;
433     }
434     ret = fstatfs(fd, stbuf);
435     close(fd);
436     return ret;
437 }
438
439 static ssize_t handle_lgetxattr(FsContext *ctx, V9fsPath *fs_path,
440                                 const char *name, void *value, size_t size)
441 {
442     int fd, ret;
443     struct handle_data *data = (struct handle_data *)ctx->private;
444
445     fd = open_by_handle(data->mountfd, fs_path->data, O_NONBLOCK);
446     if (fd < 0) {
447         return fd;
448     }
449     ret = fgetxattr(fd, name, value, size);
450     close(fd);
451     return ret;
452 }
453
454 static ssize_t handle_llistxattr(FsContext *ctx, V9fsPath *fs_path,
455                                  void *value, size_t size)
456 {
457     int fd, ret;
458     struct handle_data *data = (struct handle_data *)ctx->private;
459
460     fd = open_by_handle(data->mountfd, fs_path->data, O_NONBLOCK);
461     if (fd < 0) {
462         return fd;
463     }
464     ret = flistxattr(fd, value, size);
465     close(fd);
466     return ret;
467 }
468
469 static int handle_lsetxattr(FsContext *ctx, V9fsPath *fs_path, const char *name,
470                             void *value, size_t size, int flags)
471 {
472     int fd, ret;
473     struct handle_data *data = (struct handle_data *)ctx->private;
474
475     fd = open_by_handle(data->mountfd, fs_path->data, O_NONBLOCK);
476     if (fd < 0) {
477         return fd;
478     }
479     ret = fsetxattr(fd, name, value, size, flags);
480     close(fd);
481     return ret;
482 }
483
484 static int handle_lremovexattr(FsContext *ctx, V9fsPath *fs_path,
485                                const char *name)
486 {
487     int fd, ret;
488     struct handle_data *data = (struct handle_data *)ctx->private;
489
490     fd = open_by_handle(data->mountfd, fs_path->data, O_NONBLOCK);
491     if (fd < 0) {
492         return fd;
493     }
494     ret = fremovexattr(fd, name);
495     close(fd);
496     return ret;
497 }
498
499 static int handle_name_to_path(FsContext *ctx, V9fsPath *dir_path,
500                               const char *name, V9fsPath *target)
501 {
502     char *buffer;
503     struct file_handle *fh;
504     int dirfd, ret, mnt_id;
505     struct handle_data *data = (struct handle_data *)ctx->private;
506
507     /* "." and ".." are not allowed */
508     if (!strcmp(name, ".") || !strcmp(name, "..")) {
509         errno = EINVAL;
510         return -1;
511
512     }
513     if (dir_path) {
514         dirfd = open_by_handle(data->mountfd, dir_path->data, O_PATH);
515     } else {
516         /* relative to export root */
517         buffer = rpath(ctx, ".");
518         dirfd = open(buffer, O_DIRECTORY);
519         g_free(buffer);
520     }
521     if (dirfd < 0) {
522         return dirfd;
523     }
524     fh = g_malloc(sizeof(struct file_handle) + data->handle_bytes);
525     fh->handle_bytes = data->handle_bytes;
526     /* add a "./" at the beginning of the path */
527     buffer = g_strdup_printf("./%s", name);
528     /* flag = 0 imply don't follow symlink */
529     ret = name_to_handle(dirfd, buffer, fh, &mnt_id, 0);
530     if (!ret) {
531         target->data = (char *)fh;
532         target->size = sizeof(struct file_handle) + data->handle_bytes;
533     } else {
534         g_free(fh);
535     }
536     close(dirfd);
537     g_free(buffer);
538     return ret;
539 }
540
541 static int handle_renameat(FsContext *ctx, V9fsPath *olddir,
542                            const char *old_name, V9fsPath *newdir,
543                            const char *new_name)
544 {
545     int olddirfd, newdirfd, ret;
546     struct handle_data *data = (struct handle_data *)ctx->private;
547
548     olddirfd = open_by_handle(data->mountfd, olddir->data, O_PATH);
549     if (olddirfd < 0) {
550         return olddirfd;
551     }
552     newdirfd = open_by_handle(data->mountfd, newdir->data, O_PATH);
553     if (newdirfd < 0) {
554         close(olddirfd);
555         return newdirfd;
556     }
557     ret = renameat(olddirfd, old_name, newdirfd, new_name);
558     close(newdirfd);
559     close(olddirfd);
560     return ret;
561 }
562
563 static int handle_unlinkat(FsContext *ctx, V9fsPath *dir,
564                            const char *name, int flags)
565 {
566     int dirfd, ret;
567     struct handle_data *data = (struct handle_data *)ctx->private;
568     int rflags;
569
570     dirfd = open_by_handle(data->mountfd, dir->data, O_PATH);
571     if (dirfd < 0) {
572         return dirfd;
573     }
574
575     rflags = 0;
576     if (flags & P9_DOTL_AT_REMOVEDIR) {
577         rflags |= AT_REMOVEDIR;
578     }
579
580     ret = unlinkat(dirfd, name, rflags);
581
582     close(dirfd);
583     return ret;
584 }
585
586 static int handle_ioc_getversion(FsContext *ctx, V9fsPath *path,
587                                  mode_t st_mode, uint64_t *st_gen)
588 {
589 #ifdef FS_IOC_GETVERSION
590     int err;
591     V9fsFidOpenState fid_open;
592
593     /*
594      * Do not try to open special files like device nodes, fifos etc
595      * We can get fd for regular files and directories only
596      */
597     if (!S_ISREG(st_mode) && !S_ISDIR(st_mode)) {
598         errno = ENOTTY;
599         return -1;
600     }
601     err = handle_open(ctx, path, O_RDONLY, &fid_open);
602     if (err < 0) {
603         return err;
604     }
605     err = ioctl(fid_open.fd, FS_IOC_GETVERSION, st_gen);
606     handle_close(ctx, &fid_open);
607     return err;
608 #else
609     errno = ENOTTY;
610     return -1;
611 #endif
612 }
613
614 static int handle_init(FsContext *ctx)
615 {
616     int ret, mnt_id;
617     struct statfs stbuf;
618     struct file_handle fh;
619     struct handle_data *data = g_malloc(sizeof(struct handle_data));
620
621     data->mountfd = open(ctx->fs_root, O_DIRECTORY);
622     if (data->mountfd < 0) {
623         ret = data->mountfd;
624         goto err_out;
625     }
626     ret = statfs(ctx->fs_root, &stbuf);
627     if (!ret) {
628         switch (stbuf.f_type) {
629         case EXT2_SUPER_MAGIC:
630         case BTRFS_SUPER_MAGIC:
631         case REISERFS_SUPER_MAGIC:
632         case XFS_SUPER_MAGIC:
633             ctx->exops.get_st_gen = handle_ioc_getversion;
634             break;
635         }
636     }
637     memset(&fh, 0, sizeof(struct file_handle));
638     ret = name_to_handle(data->mountfd, ".", &fh, &mnt_id, 0);
639     if (ret && errno == EOVERFLOW) {
640         data->handle_bytes = fh.handle_bytes;
641         ctx->private = data;
642         ret = 0;
643         goto out;
644     }
645     /* we got 0 byte handle ? */
646     ret = -1;
647     close(data->mountfd);
648 err_out:
649     g_free(data);
650 out:
651     return ret;
652 }
653
654 static int handle_parse_opts(QemuOpts *opts, struct FsDriverEntry *fse)
655 {
656     const char *sec_model = qemu_opt_get(opts, "security_model");
657     const char *path = qemu_opt_get(opts, "path");
658
659     if (sec_model) {
660         error_report("Invalid argument security_model specified with handle fsdriver");
661         return -1;
662     }
663
664     if (!path) {
665         error_report("fsdev: No path specified");
666         return -1;
667     }
668     fse->path = g_strdup(path);
669     return 0;
670
671 }
672
673 FileOperations handle_ops = {
674     .parse_opts   = handle_parse_opts,
675     .init         = handle_init,
676     .lstat        = handle_lstat,
677     .readlink     = handle_readlink,
678     .close        = handle_close,
679     .closedir     = handle_closedir,
680     .open         = handle_open,
681     .opendir      = handle_opendir,
682     .rewinddir    = handle_rewinddir,
683     .telldir      = handle_telldir,
684     .readdir_r    = handle_readdir_r,
685     .seekdir      = handle_seekdir,
686     .preadv       = handle_preadv,
687     .pwritev      = handle_pwritev,
688     .chmod        = handle_chmod,
689     .mknod        = handle_mknod,
690     .mkdir        = handle_mkdir,
691     .fstat        = handle_fstat,
692     .open2        = handle_open2,
693     .symlink      = handle_symlink,
694     .link         = handle_link,
695     .truncate     = handle_truncate,
696     .rename       = handle_rename,
697     .chown        = handle_chown,
698     .utimensat    = handle_utimensat,
699     .remove       = handle_remove,
700     .fsync        = handle_fsync,
701     .statfs       = handle_statfs,
702     .lgetxattr    = handle_lgetxattr,
703     .llistxattr   = handle_llistxattr,
704     .lsetxattr    = handle_lsetxattr,
705     .lremovexattr = handle_lremovexattr,
706     .name_to_path = handle_name_to_path,
707     .renameat     = handle_renameat,
708     .unlinkat     = handle_unlinkat,
709 };