]> git.proxmox.com Git - qemu.git/blob - hw/virtio-9p.c
virtio-9p: Introduces an option to specify the security model.
[qemu.git] / hw / virtio-9p.c
1 /*
2 * Virtio 9p backend
3 *
4 * Copyright IBM, Corp. 2010
5 *
6 * Authors:
7 * Anthony Liguori <aliguori@us.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 "virtio.h"
15 #include "pc.h"
16 #include "qemu_socket.h"
17 #include "virtio-9p.h"
18 #include "fsdev/qemu-fsdev.h"
19 #include "virtio-9p-debug.h"
20
21 int dotu = 1;
22 int debug_9p_pdu;
23
24 enum {
25 Oread = 0x00,
26 Owrite = 0x01,
27 Ordwr = 0x02,
28 Oexec = 0x03,
29 Oexcl = 0x04,
30 Otrunc = 0x10,
31 Orexec = 0x20,
32 Orclose = 0x40,
33 Oappend = 0x80,
34 };
35
36 static int omode_to_uflags(int8_t mode)
37 {
38 int ret = 0;
39
40 switch (mode & 3) {
41 case Oread:
42 ret = O_RDONLY;
43 break;
44 case Ordwr:
45 ret = O_RDWR;
46 break;
47 case Owrite:
48 ret = O_WRONLY;
49 break;
50 case Oexec:
51 ret = O_RDONLY;
52 break;
53 }
54
55 if (mode & Otrunc) {
56 ret |= O_TRUNC;
57 }
58
59 if (mode & Oappend) {
60 ret |= O_APPEND;
61 }
62
63 if (mode & Oexcl) {
64 ret |= O_EXCL;
65 }
66
67 return ret;
68 }
69
70 static int v9fs_do_lstat(V9fsState *s, V9fsString *path, struct stat *stbuf)
71 {
72 return s->ops->lstat(&s->ctx, path->data, stbuf);
73 }
74
75 static int v9fs_do_setuid(V9fsState *s, uid_t uid)
76 {
77 return s->ops->setuid(&s->ctx, uid);
78 }
79
80 static ssize_t v9fs_do_readlink(V9fsState *s, V9fsString *path, V9fsString *buf)
81 {
82 ssize_t len;
83
84 buf->data = qemu_malloc(1024);
85
86 len = s->ops->readlink(&s->ctx, path->data, buf->data, 1024 - 1);
87 if (len > -1) {
88 buf->size = len;
89 buf->data[len] = 0;
90 }
91
92 return len;
93 }
94
95 static int v9fs_do_close(V9fsState *s, int fd)
96 {
97 return s->ops->close(&s->ctx, fd);
98 }
99
100 static int v9fs_do_closedir(V9fsState *s, DIR *dir)
101 {
102 return s->ops->closedir(&s->ctx, dir);
103 }
104
105 static int v9fs_do_open(V9fsState *s, V9fsString *path, int flags)
106 {
107 return s->ops->open(&s->ctx, path->data, flags);
108 }
109
110 static DIR *v9fs_do_opendir(V9fsState *s, V9fsString *path)
111 {
112 return s->ops->opendir(&s->ctx, path->data);
113 }
114
115 static void v9fs_do_rewinddir(V9fsState *s, DIR *dir)
116 {
117 return s->ops->rewinddir(&s->ctx, dir);
118 }
119
120 static off_t v9fs_do_telldir(V9fsState *s, DIR *dir)
121 {
122 return s->ops->telldir(&s->ctx, dir);
123 }
124
125 static struct dirent *v9fs_do_readdir(V9fsState *s, DIR *dir)
126 {
127 return s->ops->readdir(&s->ctx, dir);
128 }
129
130 static void v9fs_do_seekdir(V9fsState *s, DIR *dir, off_t off)
131 {
132 return s->ops->seekdir(&s->ctx, dir, off);
133 }
134
135 static int v9fs_do_readv(V9fsState *s, int fd, const struct iovec *iov,
136 int iovcnt)
137 {
138 return s->ops->readv(&s->ctx, fd, iov, iovcnt);
139 }
140
141 static off_t v9fs_do_lseek(V9fsState *s, int fd, off_t offset, int whence)
142 {
143 return s->ops->lseek(&s->ctx, fd, offset, whence);
144 }
145
146 static int v9fs_do_writev(V9fsState *s, int fd, const struct iovec *iov,
147 int iovcnt)
148 {
149 return s->ops->writev(&s->ctx, fd, iov, iovcnt);
150 }
151
152 static int v9fs_do_chmod(V9fsState *s, V9fsString *path, mode_t mode)
153 {
154 return s->ops->chmod(&s->ctx, path->data, mode);
155 }
156
157 static int v9fs_do_mknod(V9fsState *s, V9fsString *path, mode_t mode, dev_t dev)
158 {
159 return s->ops->mknod(&s->ctx, path->data, mode, dev);
160 }
161
162 static int v9fs_do_mksock(V9fsState *s, V9fsString *path)
163 {
164 return s->ops->mksock(&s->ctx, path->data);
165 }
166
167 static int v9fs_do_mkdir(V9fsState *s, V9fsString *path, mode_t mode)
168 {
169 return s->ops->mkdir(&s->ctx, path->data, mode);
170 }
171
172 static int v9fs_do_fstat(V9fsState *s, int fd, struct stat *stbuf)
173 {
174 return s->ops->fstat(&s->ctx, fd, stbuf);
175 }
176
177 static int v9fs_do_open2(V9fsState *s, V9fsString *path, int flags, mode_t mode)
178 {
179 return s->ops->open2(&s->ctx, path->data, flags, mode);
180 }
181
182 static int v9fs_do_symlink(V9fsState *s, V9fsString *oldpath,
183 V9fsString *newpath)
184 {
185 return s->ops->symlink(&s->ctx, oldpath->data, newpath->data);
186 }
187
188 static int v9fs_do_link(V9fsState *s, V9fsString *oldpath, V9fsString *newpath)
189 {
190 return s->ops->link(&s->ctx, oldpath->data, newpath->data);
191 }
192
193 static int v9fs_do_truncate(V9fsState *s, V9fsString *path, off_t size)
194 {
195 return s->ops->truncate(&s->ctx, path->data, size);
196 }
197
198 static int v9fs_do_rename(V9fsState *s, V9fsString *oldpath,
199 V9fsString *newpath)
200 {
201 return s->ops->rename(&s->ctx, oldpath->data, newpath->data);
202 }
203
204 static int v9fs_do_chown(V9fsState *s, V9fsString *path, uid_t uid, gid_t gid)
205 {
206 return s->ops->chown(&s->ctx, path->data, uid, gid);
207 }
208
209 static int v9fs_do_utime(V9fsState *s, V9fsString *path,
210 const struct utimbuf *buf)
211 {
212 return s->ops->utime(&s->ctx, path->data, buf);
213 }
214
215 static int v9fs_do_remove(V9fsState *s, V9fsString *path)
216 {
217 return s->ops->remove(&s->ctx, path->data);
218 }
219
220 static int v9fs_do_fsync(V9fsState *s, int fd)
221 {
222 return s->ops->fsync(&s->ctx, fd);
223 }
224
225 static void v9fs_string_init(V9fsString *str)
226 {
227 str->data = NULL;
228 str->size = 0;
229 }
230
231 static void v9fs_string_free(V9fsString *str)
232 {
233 qemu_free(str->data);
234 str->data = NULL;
235 str->size = 0;
236 }
237
238 static void v9fs_string_null(V9fsString *str)
239 {
240 v9fs_string_free(str);
241 }
242
243 static int number_to_string(void *arg, char type)
244 {
245 unsigned int ret = 0;
246
247 switch (type) {
248 case 'u': {
249 unsigned int num = *(unsigned int *)arg;
250
251 do {
252 ret++;
253 num = num/10;
254 } while (num);
255 break;
256 }
257 default:
258 printf("Number_to_string: Unknown number format\n");
259 return -1;
260 }
261
262 return ret;
263 }
264
265 static int v9fs_string_alloc_printf(char **strp, const char *fmt, va_list ap)
266 {
267 va_list ap2;
268 char *iter = (char *)fmt;
269 int len = 0;
270 int nr_args = 0;
271 char *arg_char_ptr;
272 unsigned int arg_uint;
273
274 /* Find the number of %'s that denotes an argument */
275 for (iter = strstr(iter, "%"); iter; iter = strstr(iter, "%")) {
276 nr_args++;
277 iter++;
278 }
279
280 len = strlen(fmt) - 2*nr_args;
281
282 if (!nr_args) {
283 goto alloc_print;
284 }
285
286 va_copy(ap2, ap);
287
288 iter = (char *)fmt;
289
290 /* Now parse the format string */
291 for (iter = strstr(iter, "%"); iter; iter = strstr(iter, "%")) {
292 iter++;
293 switch (*iter) {
294 case 'u':
295 arg_uint = va_arg(ap2, unsigned int);
296 len += number_to_string((void *)&arg_uint, 'u');
297 break;
298 case 's':
299 arg_char_ptr = va_arg(ap2, char *);
300 len += strlen(arg_char_ptr);
301 break;
302 case 'c':
303 len += 1;
304 break;
305 default:
306 fprintf(stderr,
307 "v9fs_string_alloc_printf:Incorrect format %c", *iter);
308 return -1;
309 }
310 iter++;
311 }
312
313 alloc_print:
314 *strp = qemu_malloc((len + 1) * sizeof(**strp));
315
316 return vsprintf(*strp, fmt, ap);
317 }
318
319 static void v9fs_string_sprintf(V9fsString *str, const char *fmt, ...)
320 {
321 va_list ap;
322 int err;
323
324 v9fs_string_free(str);
325
326 va_start(ap, fmt);
327 err = v9fs_string_alloc_printf(&str->data, fmt, ap);
328 BUG_ON(err == -1);
329 va_end(ap);
330
331 str->size = err;
332 }
333
334 static void v9fs_string_copy(V9fsString *lhs, V9fsString *rhs)
335 {
336 v9fs_string_free(lhs);
337 v9fs_string_sprintf(lhs, "%s", rhs->data);
338 }
339
340 static size_t v9fs_string_size(V9fsString *str)
341 {
342 return str->size;
343 }
344
345 static V9fsFidState *lookup_fid(V9fsState *s, int32_t fid)
346 {
347 V9fsFidState *f;
348
349 for (f = s->fid_list; f; f = f->next) {
350 if (f->fid == fid) {
351 v9fs_do_setuid(s, f->uid);
352 return f;
353 }
354 }
355
356 return NULL;
357 }
358
359 static V9fsFidState *alloc_fid(V9fsState *s, int32_t fid)
360 {
361 V9fsFidState *f;
362
363 f = lookup_fid(s, fid);
364 if (f) {
365 return NULL;
366 }
367
368 f = qemu_mallocz(sizeof(V9fsFidState));
369
370 f->fid = fid;
371 f->fd = -1;
372 f->dir = NULL;
373
374 f->next = s->fid_list;
375 s->fid_list = f;
376
377 return f;
378 }
379
380 static int free_fid(V9fsState *s, int32_t fid)
381 {
382 V9fsFidState **fidpp, *fidp;
383
384 for (fidpp = &s->fid_list; *fidpp; fidpp = &(*fidpp)->next) {
385 if ((*fidpp)->fid == fid) {
386 break;
387 }
388 }
389
390 if (*fidpp == NULL) {
391 return -ENOENT;
392 }
393
394 fidp = *fidpp;
395 *fidpp = fidp->next;
396
397 if (fidp->fd != -1) {
398 v9fs_do_close(s, fidp->fd);
399 }
400 if (fidp->dir) {
401 v9fs_do_closedir(s, fidp->dir);
402 }
403 v9fs_string_free(&fidp->path);
404 qemu_free(fidp);
405
406 return 0;
407 }
408
409 #define P9_QID_TYPE_DIR 0x80
410 #define P9_QID_TYPE_SYMLINK 0x02
411
412 #define P9_STAT_MODE_DIR 0x80000000
413 #define P9_STAT_MODE_APPEND 0x40000000
414 #define P9_STAT_MODE_EXCL 0x20000000
415 #define P9_STAT_MODE_MOUNT 0x10000000
416 #define P9_STAT_MODE_AUTH 0x08000000
417 #define P9_STAT_MODE_TMP 0x04000000
418 #define P9_STAT_MODE_SYMLINK 0x02000000
419 #define P9_STAT_MODE_LINK 0x01000000
420 #define P9_STAT_MODE_DEVICE 0x00800000
421 #define P9_STAT_MODE_NAMED_PIPE 0x00200000
422 #define P9_STAT_MODE_SOCKET 0x00100000
423 #define P9_STAT_MODE_SETUID 0x00080000
424 #define P9_STAT_MODE_SETGID 0x00040000
425 #define P9_STAT_MODE_SETVTX 0x00010000
426
427 #define P9_STAT_MODE_TYPE_BITS (P9_STAT_MODE_DIR | \
428 P9_STAT_MODE_SYMLINK | \
429 P9_STAT_MODE_LINK | \
430 P9_STAT_MODE_DEVICE | \
431 P9_STAT_MODE_NAMED_PIPE | \
432 P9_STAT_MODE_SOCKET)
433
434 /* This is the algorithm from ufs in spfs */
435 static void stat_to_qid(const struct stat *stbuf, V9fsQID *qidp)
436 {
437 size_t size;
438
439 size = MIN(sizeof(stbuf->st_ino), sizeof(qidp->path));
440 memcpy(&qidp->path, &stbuf->st_ino, size);
441 qidp->version = stbuf->st_mtime ^ (stbuf->st_size << 8);
442 qidp->type = 0;
443 if (S_ISDIR(stbuf->st_mode)) {
444 qidp->type |= P9_QID_TYPE_DIR;
445 }
446 if (S_ISLNK(stbuf->st_mode)) {
447 qidp->type |= P9_QID_TYPE_SYMLINK;
448 }
449 }
450
451 static int fid_to_qid(V9fsState *s, V9fsFidState *fidp, V9fsQID *qidp)
452 {
453 struct stat stbuf;
454 int err;
455
456 err = v9fs_do_lstat(s, &fidp->path, &stbuf);
457 if (err) {
458 return err;
459 }
460
461 stat_to_qid(&stbuf, qidp);
462 return 0;
463 }
464
465 static V9fsPDU *alloc_pdu(V9fsState *s)
466 {
467 V9fsPDU *pdu = NULL;
468
469 if (!QLIST_EMPTY(&s->free_list)) {
470 pdu = QLIST_FIRST(&s->free_list);
471 QLIST_REMOVE(pdu, next);
472 }
473 return pdu;
474 }
475
476 static void free_pdu(V9fsState *s, V9fsPDU *pdu)
477 {
478 if (pdu) {
479 QLIST_INSERT_HEAD(&s->free_list, pdu, next);
480 }
481 }
482
483 size_t pdu_packunpack(void *addr, struct iovec *sg, int sg_count,
484 size_t offset, size_t size, int pack)
485 {
486 int i = 0;
487 size_t copied = 0;
488
489 for (i = 0; size && i < sg_count; i++) {
490 size_t len;
491 if (offset >= sg[i].iov_len) {
492 /* skip this sg */
493 offset -= sg[i].iov_len;
494 continue;
495 } else {
496 len = MIN(sg[i].iov_len - offset, size);
497 if (pack) {
498 memcpy(sg[i].iov_base + offset, addr, len);
499 } else {
500 memcpy(addr, sg[i].iov_base + offset, len);
501 }
502 size -= len;
503 copied += len;
504 addr += len;
505 if (size) {
506 offset = 0;
507 continue;
508 }
509 }
510 }
511
512 return copied;
513 }
514
515 static size_t pdu_unpack(void *dst, V9fsPDU *pdu, size_t offset, size_t size)
516 {
517 return pdu_packunpack(dst, pdu->elem.out_sg, pdu->elem.out_num,
518 offset, size, 0);
519 }
520
521 static size_t pdu_pack(V9fsPDU *pdu, size_t offset, const void *src,
522 size_t size)
523 {
524 return pdu_packunpack((void *)src, pdu->elem.in_sg, pdu->elem.in_num,
525 offset, size, 1);
526 }
527
528 static int pdu_copy_sg(V9fsPDU *pdu, size_t offset, int rx, struct iovec *sg)
529 {
530 size_t pos = 0;
531 int i, j;
532 struct iovec *src_sg;
533 unsigned int num;
534
535 if (rx) {
536 src_sg = pdu->elem.in_sg;
537 num = pdu->elem.in_num;
538 } else {
539 src_sg = pdu->elem.out_sg;
540 num = pdu->elem.out_num;
541 }
542
543 j = 0;
544 for (i = 0; i < num; i++) {
545 if (offset <= pos) {
546 sg[j].iov_base = src_sg[i].iov_base;
547 sg[j].iov_len = src_sg[i].iov_len;
548 j++;
549 } else if (offset < (src_sg[i].iov_len + pos)) {
550 sg[j].iov_base = src_sg[i].iov_base;
551 sg[j].iov_len = src_sg[i].iov_len;
552 sg[j].iov_base += (offset - pos);
553 sg[j].iov_len -= (offset - pos);
554 j++;
555 }
556 pos += src_sg[i].iov_len;
557 }
558
559 return j;
560 }
561
562 static size_t pdu_unmarshal(V9fsPDU *pdu, size_t offset, const char *fmt, ...)
563 {
564 size_t old_offset = offset;
565 va_list ap;
566 int i;
567
568 va_start(ap, fmt);
569 for (i = 0; fmt[i]; i++) {
570 switch (fmt[i]) {
571 case 'b': {
572 uint8_t *valp = va_arg(ap, uint8_t *);
573 offset += pdu_unpack(valp, pdu, offset, sizeof(*valp));
574 break;
575 }
576 case 'w': {
577 uint16_t val, *valp;
578 valp = va_arg(ap, uint16_t *);
579 val = le16_to_cpupu(valp);
580 offset += pdu_unpack(&val, pdu, offset, sizeof(val));
581 *valp = val;
582 break;
583 }
584 case 'd': {
585 uint32_t val, *valp;
586 valp = va_arg(ap, uint32_t *);
587 val = le32_to_cpupu(valp);
588 offset += pdu_unpack(&val, pdu, offset, sizeof(val));
589 *valp = val;
590 break;
591 }
592 case 'q': {
593 uint64_t val, *valp;
594 valp = va_arg(ap, uint64_t *);
595 val = le64_to_cpup(valp);
596 offset += pdu_unpack(&val, pdu, offset, sizeof(val));
597 *valp = val;
598 break;
599 }
600 case 'v': {
601 struct iovec *iov = va_arg(ap, struct iovec *);
602 int *iovcnt = va_arg(ap, int *);
603 *iovcnt = pdu_copy_sg(pdu, offset, 0, iov);
604 break;
605 }
606 case 's': {
607 V9fsString *str = va_arg(ap, V9fsString *);
608 offset += pdu_unmarshal(pdu, offset, "w", &str->size);
609 /* FIXME: sanity check str->size */
610 str->data = qemu_malloc(str->size + 1);
611 offset += pdu_unpack(str->data, pdu, offset, str->size);
612 str->data[str->size] = 0;
613 break;
614 }
615 case 'Q': {
616 V9fsQID *qidp = va_arg(ap, V9fsQID *);
617 offset += pdu_unmarshal(pdu, offset, "bdq",
618 &qidp->type, &qidp->version, &qidp->path);
619 break;
620 }
621 case 'S': {
622 V9fsStat *statp = va_arg(ap, V9fsStat *);
623 offset += pdu_unmarshal(pdu, offset, "wwdQdddqsssssddd",
624 &statp->size, &statp->type, &statp->dev,
625 &statp->qid, &statp->mode, &statp->atime,
626 &statp->mtime, &statp->length,
627 &statp->name, &statp->uid, &statp->gid,
628 &statp->muid, &statp->extension,
629 &statp->n_uid, &statp->n_gid,
630 &statp->n_muid);
631 break;
632 }
633 default:
634 break;
635 }
636 }
637
638 va_end(ap);
639
640 return offset - old_offset;
641 }
642
643 static size_t pdu_marshal(V9fsPDU *pdu, size_t offset, const char *fmt, ...)
644 {
645 size_t old_offset = offset;
646 va_list ap;
647 int i;
648
649 va_start(ap, fmt);
650 for (i = 0; fmt[i]; i++) {
651 switch (fmt[i]) {
652 case 'b': {
653 uint8_t val = va_arg(ap, int);
654 offset += pdu_pack(pdu, offset, &val, sizeof(val));
655 break;
656 }
657 case 'w': {
658 uint16_t val;
659 cpu_to_le16w(&val, va_arg(ap, int));
660 offset += pdu_pack(pdu, offset, &val, sizeof(val));
661 break;
662 }
663 case 'd': {
664 uint32_t val;
665 cpu_to_le32w(&val, va_arg(ap, uint32_t));
666 offset += pdu_pack(pdu, offset, &val, sizeof(val));
667 break;
668 }
669 case 'q': {
670 uint64_t val;
671 cpu_to_le64w(&val, va_arg(ap, uint64_t));
672 offset += pdu_pack(pdu, offset, &val, sizeof(val));
673 break;
674 }
675 case 'v': {
676 struct iovec *iov = va_arg(ap, struct iovec *);
677 int *iovcnt = va_arg(ap, int *);
678 *iovcnt = pdu_copy_sg(pdu, offset, 1, iov);
679 break;
680 }
681 case 's': {
682 V9fsString *str = va_arg(ap, V9fsString *);
683 offset += pdu_marshal(pdu, offset, "w", str->size);
684 offset += pdu_pack(pdu, offset, str->data, str->size);
685 break;
686 }
687 case 'Q': {
688 V9fsQID *qidp = va_arg(ap, V9fsQID *);
689 offset += pdu_marshal(pdu, offset, "bdq",
690 qidp->type, qidp->version, qidp->path);
691 break;
692 }
693 case 'S': {
694 V9fsStat *statp = va_arg(ap, V9fsStat *);
695 offset += pdu_marshal(pdu, offset, "wwdQdddqsssssddd",
696 statp->size, statp->type, statp->dev,
697 &statp->qid, statp->mode, statp->atime,
698 statp->mtime, statp->length, &statp->name,
699 &statp->uid, &statp->gid, &statp->muid,
700 &statp->extension, statp->n_uid,
701 statp->n_gid, statp->n_muid);
702 break;
703 }
704 default:
705 break;
706 }
707 }
708 va_end(ap);
709
710 return offset - old_offset;
711 }
712
713 static void complete_pdu(V9fsState *s, V9fsPDU *pdu, ssize_t len)
714 {
715 int8_t id = pdu->id + 1; /* Response */
716
717 if (len < 0) {
718 V9fsString str;
719 int err = -len;
720
721 str.data = strerror(err);
722 str.size = strlen(str.data);
723
724 len = 7;
725 len += pdu_marshal(pdu, len, "s", &str);
726 if (dotu) {
727 len += pdu_marshal(pdu, len, "d", err);
728 }
729
730 id = P9_RERROR;
731 }
732
733 /* fill out the header */
734 pdu_marshal(pdu, 0, "dbw", (int32_t)len, id, pdu->tag);
735
736 /* keep these in sync */
737 pdu->size = len;
738 pdu->id = id;
739
740 /* push onto queue and notify */
741 virtqueue_push(s->vq, &pdu->elem, len);
742
743 /* FIXME: we should batch these completions */
744 virtio_notify(&s->vdev, s->vq);
745
746 free_pdu(s, pdu);
747 }
748
749 static mode_t v9mode_to_mode(uint32_t mode, V9fsString *extension)
750 {
751 mode_t ret;
752
753 ret = mode & 0777;
754 if (mode & P9_STAT_MODE_DIR) {
755 ret |= S_IFDIR;
756 }
757
758 if (dotu) {
759 if (mode & P9_STAT_MODE_SYMLINK) {
760 ret |= S_IFLNK;
761 }
762 if (mode & P9_STAT_MODE_SOCKET) {
763 ret |= S_IFSOCK;
764 }
765 if (mode & P9_STAT_MODE_NAMED_PIPE) {
766 ret |= S_IFIFO;
767 }
768 if (mode & P9_STAT_MODE_DEVICE) {
769 if (extension && extension->data[0] == 'c') {
770 ret |= S_IFCHR;
771 } else {
772 ret |= S_IFBLK;
773 }
774 }
775 }
776
777 if (!(ret&~0777)) {
778 ret |= S_IFREG;
779 }
780
781 if (mode & P9_STAT_MODE_SETUID) {
782 ret |= S_ISUID;
783 }
784 if (mode & P9_STAT_MODE_SETGID) {
785 ret |= S_ISGID;
786 }
787 if (mode & P9_STAT_MODE_SETVTX) {
788 ret |= S_ISVTX;
789 }
790
791 return ret;
792 }
793
794 static int donttouch_stat(V9fsStat *stat)
795 {
796 if (stat->type == -1 &&
797 stat->dev == -1 &&
798 stat->qid.type == -1 &&
799 stat->qid.version == -1 &&
800 stat->qid.path == -1 &&
801 stat->mode == -1 &&
802 stat->atime == -1 &&
803 stat->mtime == -1 &&
804 stat->length == -1 &&
805 !stat->name.size &&
806 !stat->uid.size &&
807 !stat->gid.size &&
808 !stat->muid.size &&
809 stat->n_uid == -1 &&
810 stat->n_gid == -1 &&
811 stat->n_muid == -1) {
812 return 1;
813 }
814
815 return 0;
816 }
817
818 static void v9fs_stat_free(V9fsStat *stat)
819 {
820 v9fs_string_free(&stat->name);
821 v9fs_string_free(&stat->uid);
822 v9fs_string_free(&stat->gid);
823 v9fs_string_free(&stat->muid);
824 v9fs_string_free(&stat->extension);
825 }
826
827 static uint32_t stat_to_v9mode(const struct stat *stbuf)
828 {
829 uint32_t mode;
830
831 mode = stbuf->st_mode & 0777;
832 if (S_ISDIR(stbuf->st_mode)) {
833 mode |= P9_STAT_MODE_DIR;
834 }
835
836 if (dotu) {
837 if (S_ISLNK(stbuf->st_mode)) {
838 mode |= P9_STAT_MODE_SYMLINK;
839 }
840
841 if (S_ISSOCK(stbuf->st_mode)) {
842 mode |= P9_STAT_MODE_SOCKET;
843 }
844
845 if (S_ISFIFO(stbuf->st_mode)) {
846 mode |= P9_STAT_MODE_NAMED_PIPE;
847 }
848
849 if (S_ISBLK(stbuf->st_mode) || S_ISCHR(stbuf->st_mode)) {
850 mode |= P9_STAT_MODE_DEVICE;
851 }
852
853 if (stbuf->st_mode & S_ISUID) {
854 mode |= P9_STAT_MODE_SETUID;
855 }
856
857 if (stbuf->st_mode & S_ISGID) {
858 mode |= P9_STAT_MODE_SETGID;
859 }
860
861 if (stbuf->st_mode & S_ISVTX) {
862 mode |= P9_STAT_MODE_SETVTX;
863 }
864 }
865
866 return mode;
867 }
868
869 static int stat_to_v9stat(V9fsState *s, V9fsString *name,
870 const struct stat *stbuf,
871 V9fsStat *v9stat)
872 {
873 int err;
874 const char *str;
875
876 memset(v9stat, 0, sizeof(*v9stat));
877
878 stat_to_qid(stbuf, &v9stat->qid);
879 v9stat->mode = stat_to_v9mode(stbuf);
880 v9stat->atime = stbuf->st_atime;
881 v9stat->mtime = stbuf->st_mtime;
882 v9stat->length = stbuf->st_size;
883
884 v9fs_string_null(&v9stat->uid);
885 v9fs_string_null(&v9stat->gid);
886 v9fs_string_null(&v9stat->muid);
887
888 if (dotu) {
889 v9stat->n_uid = stbuf->st_uid;
890 v9stat->n_gid = stbuf->st_gid;
891 v9stat->n_muid = 0;
892
893 v9fs_string_null(&v9stat->extension);
894
895 if (v9stat->mode & P9_STAT_MODE_SYMLINK) {
896 err = v9fs_do_readlink(s, name, &v9stat->extension);
897 if (err == -1) {
898 err = -errno;
899 return err;
900 }
901 v9stat->extension.data[err] = 0;
902 v9stat->extension.size = err;
903 } else if (v9stat->mode & P9_STAT_MODE_DEVICE) {
904 v9fs_string_sprintf(&v9stat->extension, "%c %u %u",
905 S_ISCHR(stbuf->st_mode) ? 'c' : 'b',
906 major(stbuf->st_rdev), minor(stbuf->st_rdev));
907 } else if (S_ISDIR(stbuf->st_mode) || S_ISREG(stbuf->st_mode)) {
908 v9fs_string_sprintf(&v9stat->extension, "%s %u",
909 "HARDLINKCOUNT", stbuf->st_nlink);
910 }
911 }
912
913 str = strrchr(name->data, '/');
914 if (str) {
915 str += 1;
916 } else {
917 str = name->data;
918 }
919
920 v9fs_string_sprintf(&v9stat->name, "%s", str);
921
922 v9stat->size = 61 +
923 v9fs_string_size(&v9stat->name) +
924 v9fs_string_size(&v9stat->uid) +
925 v9fs_string_size(&v9stat->gid) +
926 v9fs_string_size(&v9stat->muid) +
927 v9fs_string_size(&v9stat->extension);
928 return 0;
929 }
930
931 static struct iovec *adjust_sg(struct iovec *sg, int len, int *iovcnt)
932 {
933 while (len && *iovcnt) {
934 if (len < sg->iov_len) {
935 sg->iov_len -= len;
936 sg->iov_base += len;
937 len = 0;
938 } else {
939 len -= sg->iov_len;
940 sg++;
941 *iovcnt -= 1;
942 }
943 }
944
945 return sg;
946 }
947
948 static struct iovec *cap_sg(struct iovec *sg, int cap, int *cnt)
949 {
950 int i;
951 int total = 0;
952
953 for (i = 0; i < *cnt; i++) {
954 if ((total + sg[i].iov_len) > cap) {
955 sg[i].iov_len -= ((total + sg[i].iov_len) - cap);
956 i++;
957 break;
958 }
959 total += sg[i].iov_len;
960 }
961
962 *cnt = i;
963
964 return sg;
965 }
966
967 static void print_sg(struct iovec *sg, int cnt)
968 {
969 int i;
970
971 printf("sg[%d]: {", cnt);
972 for (i = 0; i < cnt; i++) {
973 if (i) {
974 printf(", ");
975 }
976 printf("(%p, %zd)", sg[i].iov_base, sg[i].iov_len);
977 }
978 printf("}\n");
979 }
980
981 static void v9fs_fix_path(V9fsString *dst, V9fsString *src, int len)
982 {
983 V9fsString str;
984 v9fs_string_init(&str);
985 v9fs_string_copy(&str, dst);
986 v9fs_string_sprintf(dst, "%s%s", src->data, str.data+len);
987 v9fs_string_free(&str);
988 }
989
990 static void v9fs_version(V9fsState *s, V9fsPDU *pdu)
991 {
992 int32_t msize;
993 V9fsString version;
994 size_t offset = 7;
995
996 pdu_unmarshal(pdu, offset, "ds", &msize, &version);
997
998 if (strcmp(version.data, "9P2000.u")) {
999 v9fs_string_sprintf(&version, "unknown");
1000 }
1001
1002 offset += pdu_marshal(pdu, offset, "ds", msize, &version);
1003 complete_pdu(s, pdu, offset);
1004
1005 v9fs_string_free(&version);
1006 }
1007
1008 static void v9fs_attach(V9fsState *s, V9fsPDU *pdu)
1009 {
1010 int32_t fid, afid, n_uname;
1011 V9fsString uname, aname;
1012 V9fsFidState *fidp;
1013 V9fsQID qid;
1014 size_t offset = 7;
1015 ssize_t err;
1016
1017 pdu_unmarshal(pdu, offset, "ddssd", &fid, &afid, &uname, &aname, &n_uname);
1018
1019 fidp = alloc_fid(s, fid);
1020 if (fidp == NULL) {
1021 err = -EINVAL;
1022 goto out;
1023 }
1024
1025 fidp->uid = n_uname;
1026
1027 v9fs_string_sprintf(&fidp->path, "%s", "/");
1028 err = fid_to_qid(s, fidp, &qid);
1029 if (err) {
1030 err = -EINVAL;
1031 free_fid(s, fid);
1032 goto out;
1033 }
1034
1035 offset += pdu_marshal(pdu, offset, "Q", &qid);
1036
1037 err = offset;
1038 out:
1039 complete_pdu(s, pdu, err);
1040 v9fs_string_free(&uname);
1041 v9fs_string_free(&aname);
1042 }
1043
1044 static void v9fs_stat_post_lstat(V9fsState *s, V9fsStatState *vs, int err)
1045 {
1046 if (err == -1) {
1047 err = -errno;
1048 goto out;
1049 }
1050
1051 err = stat_to_v9stat(s, &vs->fidp->path, &vs->stbuf, &vs->v9stat);
1052 if (err) {
1053 goto out;
1054 }
1055 vs->offset += pdu_marshal(vs->pdu, vs->offset, "wS", 0, &vs->v9stat);
1056 err = vs->offset;
1057
1058 out:
1059 complete_pdu(s, vs->pdu, err);
1060 v9fs_stat_free(&vs->v9stat);
1061 qemu_free(vs);
1062 }
1063
1064 static void v9fs_stat(V9fsState *s, V9fsPDU *pdu)
1065 {
1066 int32_t fid;
1067 V9fsStatState *vs;
1068 ssize_t err = 0;
1069
1070 vs = qemu_malloc(sizeof(*vs));
1071 vs->pdu = pdu;
1072 vs->offset = 7;
1073
1074 memset(&vs->v9stat, 0, sizeof(vs->v9stat));
1075
1076 pdu_unmarshal(vs->pdu, vs->offset, "d", &fid);
1077
1078 vs->fidp = lookup_fid(s, fid);
1079 if (vs->fidp == NULL) {
1080 err = -ENOENT;
1081 goto out;
1082 }
1083
1084 err = v9fs_do_lstat(s, &vs->fidp->path, &vs->stbuf);
1085 v9fs_stat_post_lstat(s, vs, err);
1086 return;
1087
1088 out:
1089 complete_pdu(s, vs->pdu, err);
1090 v9fs_stat_free(&vs->v9stat);
1091 qemu_free(vs);
1092 }
1093
1094 static void v9fs_walk_complete(V9fsState *s, V9fsWalkState *vs, int err)
1095 {
1096 complete_pdu(s, vs->pdu, err);
1097
1098 if (vs->nwnames) {
1099 for (vs->name_idx = 0; vs->name_idx < vs->nwnames; vs->name_idx++) {
1100 v9fs_string_free(&vs->wnames[vs->name_idx]);
1101 }
1102
1103 qemu_free(vs->wnames);
1104 qemu_free(vs->qids);
1105 }
1106 }
1107
1108 static void v9fs_walk_marshal(V9fsWalkState *vs)
1109 {
1110 int i;
1111 vs->offset = 7;
1112 vs->offset += pdu_marshal(vs->pdu, vs->offset, "w", vs->nwnames);
1113
1114 for (i = 0; i < vs->nwnames; i++) {
1115 vs->offset += pdu_marshal(vs->pdu, vs->offset, "Q", &vs->qids[i]);
1116 }
1117 }
1118
1119 static void v9fs_walk_post_newfid_lstat(V9fsState *s, V9fsWalkState *vs,
1120 int err)
1121 {
1122 if (err == -1) {
1123 free_fid(s, vs->newfidp->fid);
1124 v9fs_string_free(&vs->path);
1125 err = -ENOENT;
1126 goto out;
1127 }
1128
1129 stat_to_qid(&vs->stbuf, &vs->qids[vs->name_idx]);
1130
1131 vs->name_idx++;
1132 if (vs->name_idx < vs->nwnames) {
1133 v9fs_string_sprintf(&vs->path, "%s/%s", vs->newfidp->path.data,
1134 vs->wnames[vs->name_idx].data);
1135 v9fs_string_copy(&vs->newfidp->path, &vs->path);
1136
1137 err = v9fs_do_lstat(s, &vs->newfidp->path, &vs->stbuf);
1138 v9fs_walk_post_newfid_lstat(s, vs, err);
1139 return;
1140 }
1141
1142 v9fs_string_free(&vs->path);
1143 v9fs_walk_marshal(vs);
1144 err = vs->offset;
1145 out:
1146 v9fs_walk_complete(s, vs, err);
1147 }
1148
1149 static void v9fs_walk_post_oldfid_lstat(V9fsState *s, V9fsWalkState *vs,
1150 int err)
1151 {
1152 if (err == -1) {
1153 v9fs_string_free(&vs->path);
1154 err = -ENOENT;
1155 goto out;
1156 }
1157
1158 stat_to_qid(&vs->stbuf, &vs->qids[vs->name_idx]);
1159 vs->name_idx++;
1160 if (vs->name_idx < vs->nwnames) {
1161
1162 v9fs_string_sprintf(&vs->path, "%s/%s",
1163 vs->fidp->path.data, vs->wnames[vs->name_idx].data);
1164 v9fs_string_copy(&vs->fidp->path, &vs->path);
1165
1166 err = v9fs_do_lstat(s, &vs->fidp->path, &vs->stbuf);
1167 v9fs_walk_post_oldfid_lstat(s, vs, err);
1168 return;
1169 }
1170
1171 v9fs_string_free(&vs->path);
1172 v9fs_walk_marshal(vs);
1173 err = vs->offset;
1174 out:
1175 v9fs_walk_complete(s, vs, err);
1176 }
1177
1178 static void v9fs_walk(V9fsState *s, V9fsPDU *pdu)
1179 {
1180 int32_t fid, newfid;
1181 V9fsWalkState *vs;
1182 int err = 0;
1183 int i;
1184
1185 vs = qemu_malloc(sizeof(*vs));
1186 vs->pdu = pdu;
1187 vs->wnames = NULL;
1188 vs->qids = NULL;
1189 vs->offset = 7;
1190
1191 vs->offset += pdu_unmarshal(vs->pdu, vs->offset, "ddw", &fid,
1192 &newfid, &vs->nwnames);
1193
1194 if (vs->nwnames) {
1195 vs->wnames = qemu_mallocz(sizeof(vs->wnames[0]) * vs->nwnames);
1196
1197 vs->qids = qemu_mallocz(sizeof(vs->qids[0]) * vs->nwnames);
1198
1199 for (i = 0; i < vs->nwnames; i++) {
1200 vs->offset += pdu_unmarshal(vs->pdu, vs->offset, "s",
1201 &vs->wnames[i]);
1202 }
1203 }
1204
1205 vs->fidp = lookup_fid(s, fid);
1206 if (vs->fidp == NULL) {
1207 err = -ENOENT;
1208 goto out;
1209 }
1210
1211 /* FIXME: is this really valid? */
1212 if (fid == newfid) {
1213
1214 BUG_ON(vs->fidp->fd != -1);
1215 BUG_ON(vs->fidp->dir);
1216 v9fs_string_init(&vs->path);
1217 vs->name_idx = 0;
1218
1219 if (vs->name_idx < vs->nwnames) {
1220 v9fs_string_sprintf(&vs->path, "%s/%s",
1221 vs->fidp->path.data, vs->wnames[vs->name_idx].data);
1222 v9fs_string_copy(&vs->fidp->path, &vs->path);
1223
1224 err = v9fs_do_lstat(s, &vs->fidp->path, &vs->stbuf);
1225 v9fs_walk_post_oldfid_lstat(s, vs, err);
1226 return;
1227 }
1228 } else {
1229 vs->newfidp = alloc_fid(s, newfid);
1230 if (vs->newfidp == NULL) {
1231 err = -EINVAL;
1232 goto out;
1233 }
1234
1235 vs->newfidp->uid = vs->fidp->uid;
1236 v9fs_string_init(&vs->path);
1237 vs->name_idx = 0;
1238 v9fs_string_copy(&vs->newfidp->path, &vs->fidp->path);
1239
1240 if (vs->name_idx < vs->nwnames) {
1241 v9fs_string_sprintf(&vs->path, "%s/%s", vs->newfidp->path.data,
1242 vs->wnames[vs->name_idx].data);
1243 v9fs_string_copy(&vs->newfidp->path, &vs->path);
1244
1245 err = v9fs_do_lstat(s, &vs->newfidp->path, &vs->stbuf);
1246 v9fs_walk_post_newfid_lstat(s, vs, err);
1247 return;
1248 }
1249 }
1250
1251 v9fs_walk_marshal(vs);
1252 err = vs->offset;
1253 out:
1254 v9fs_walk_complete(s, vs, err);
1255 }
1256
1257 static void v9fs_open_post_opendir(V9fsState *s, V9fsOpenState *vs, int err)
1258 {
1259 if (vs->fidp->dir == NULL) {
1260 err = -errno;
1261 goto out;
1262 }
1263
1264 vs->offset += pdu_marshal(vs->pdu, vs->offset, "Qd", &vs->qid, 0);
1265 err = vs->offset;
1266 out:
1267 complete_pdu(s, vs->pdu, err);
1268 qemu_free(vs);
1269
1270 }
1271
1272 static void v9fs_open_post_open(V9fsState *s, V9fsOpenState *vs, int err)
1273 {
1274 if (vs->fidp->fd == -1) {
1275 err = -errno;
1276 goto out;
1277 }
1278
1279 vs->offset += pdu_marshal(vs->pdu, vs->offset, "Qd", &vs->qid, 0);
1280 err = vs->offset;
1281 out:
1282 complete_pdu(s, vs->pdu, err);
1283 qemu_free(vs);
1284 }
1285
1286 static void v9fs_open_post_lstat(V9fsState *s, V9fsOpenState *vs, int err)
1287 {
1288 if (err) {
1289 err = -errno;
1290 goto out;
1291 }
1292
1293 stat_to_qid(&vs->stbuf, &vs->qid);
1294
1295 if (S_ISDIR(vs->stbuf.st_mode)) {
1296 vs->fidp->dir = v9fs_do_opendir(s, &vs->fidp->path);
1297 v9fs_open_post_opendir(s, vs, err);
1298 } else {
1299 vs->fidp->fd = v9fs_do_open(s, &vs->fidp->path,
1300 omode_to_uflags(vs->mode));
1301 v9fs_open_post_open(s, vs, err);
1302 }
1303 return;
1304 out:
1305 complete_pdu(s, vs->pdu, err);
1306 qemu_free(vs);
1307 }
1308
1309 static void v9fs_open(V9fsState *s, V9fsPDU *pdu)
1310 {
1311 int32_t fid;
1312 V9fsOpenState *vs;
1313 ssize_t err = 0;
1314
1315
1316 vs = qemu_malloc(sizeof(*vs));
1317 vs->pdu = pdu;
1318 vs->offset = 7;
1319
1320 pdu_unmarshal(vs->pdu, vs->offset, "db", &fid, &vs->mode);
1321
1322 vs->fidp = lookup_fid(s, fid);
1323 if (vs->fidp == NULL) {
1324 err = -ENOENT;
1325 goto out;
1326 }
1327
1328 BUG_ON(vs->fidp->fd != -1);
1329 BUG_ON(vs->fidp->dir);
1330
1331 err = v9fs_do_lstat(s, &vs->fidp->path, &vs->stbuf);
1332
1333 v9fs_open_post_lstat(s, vs, err);
1334 return;
1335 out:
1336 complete_pdu(s, pdu, err);
1337 qemu_free(vs);
1338 }
1339
1340 static void v9fs_clunk(V9fsState *s, V9fsPDU *pdu)
1341 {
1342 int32_t fid;
1343 size_t offset = 7;
1344 int err;
1345
1346 pdu_unmarshal(pdu, offset, "d", &fid);
1347
1348 err = free_fid(s, fid);
1349 if (err < 0) {
1350 goto out;
1351 }
1352
1353 offset = 7;
1354 err = offset;
1355 out:
1356 complete_pdu(s, pdu, err);
1357 }
1358
1359 static void v9fs_read_post_readdir(V9fsState *, V9fsReadState *, ssize_t);
1360
1361 static void v9fs_read_post_seekdir(V9fsState *s, V9fsReadState *vs, ssize_t err)
1362 {
1363 if (err) {
1364 goto out;
1365 }
1366 v9fs_stat_free(&vs->v9stat);
1367 v9fs_string_free(&vs->name);
1368 vs->offset += pdu_marshal(vs->pdu, vs->offset, "d", vs->count);
1369 vs->offset += vs->count;
1370 err = vs->offset;
1371 out:
1372 complete_pdu(s, vs->pdu, err);
1373 qemu_free(vs);
1374 return;
1375 }
1376
1377 static void v9fs_read_post_dir_lstat(V9fsState *s, V9fsReadState *vs,
1378 ssize_t err)
1379 {
1380 if (err) {
1381 err = -errno;
1382 goto out;
1383 }
1384 err = stat_to_v9stat(s, &vs->name, &vs->stbuf, &vs->v9stat);
1385 if (err) {
1386 goto out;
1387 }
1388
1389 vs->len = pdu_marshal(vs->pdu, vs->offset + 4 + vs->count, "S",
1390 &vs->v9stat);
1391 if ((vs->len != (vs->v9stat.size + 2)) ||
1392 ((vs->count + vs->len) > vs->max_count)) {
1393 v9fs_do_seekdir(s, vs->fidp->dir, vs->dir_pos);
1394 v9fs_read_post_seekdir(s, vs, err);
1395 return;
1396 }
1397 vs->count += vs->len;
1398 v9fs_stat_free(&vs->v9stat);
1399 v9fs_string_free(&vs->name);
1400 vs->dir_pos = vs->dent->d_off;
1401 vs->dent = v9fs_do_readdir(s, vs->fidp->dir);
1402 v9fs_read_post_readdir(s, vs, err);
1403 return;
1404 out:
1405 v9fs_do_seekdir(s, vs->fidp->dir, vs->dir_pos);
1406 v9fs_read_post_seekdir(s, vs, err);
1407 return;
1408
1409 }
1410
1411 static void v9fs_read_post_readdir(V9fsState *s, V9fsReadState *vs, ssize_t err)
1412 {
1413 if (vs->dent) {
1414 memset(&vs->v9stat, 0, sizeof(vs->v9stat));
1415 v9fs_string_init(&vs->name);
1416 v9fs_string_sprintf(&vs->name, "%s/%s", vs->fidp->path.data,
1417 vs->dent->d_name);
1418 err = v9fs_do_lstat(s, &vs->name, &vs->stbuf);
1419 v9fs_read_post_dir_lstat(s, vs, err);
1420 return;
1421 }
1422
1423 vs->offset += pdu_marshal(vs->pdu, vs->offset, "d", vs->count);
1424 vs->offset += vs->count;
1425 err = vs->offset;
1426 complete_pdu(s, vs->pdu, err);
1427 qemu_free(vs);
1428 return;
1429 }
1430
1431 static void v9fs_read_post_telldir(V9fsState *s, V9fsReadState *vs, ssize_t err)
1432 {
1433 vs->dent = v9fs_do_readdir(s, vs->fidp->dir);
1434 v9fs_read_post_readdir(s, vs, err);
1435 return;
1436 }
1437
1438 static void v9fs_read_post_rewinddir(V9fsState *s, V9fsReadState *vs,
1439 ssize_t err)
1440 {
1441 vs->dir_pos = v9fs_do_telldir(s, vs->fidp->dir);
1442 v9fs_read_post_telldir(s, vs, err);
1443 return;
1444 }
1445
1446 static void v9fs_read_post_readv(V9fsState *s, V9fsReadState *vs, ssize_t err)
1447 {
1448 if (err < 0) {
1449 /* IO error return the error */
1450 err = -errno;
1451 goto out;
1452 }
1453 vs->total += vs->len;
1454 vs->sg = adjust_sg(vs->sg, vs->len, &vs->cnt);
1455 if (vs->total < vs->count && vs->len > 0) {
1456 do {
1457 if (0) {
1458 print_sg(vs->sg, vs->cnt);
1459 }
1460 vs->len = v9fs_do_readv(s, vs->fidp->fd, vs->sg, vs->cnt);
1461 } while (vs->len == -1 && errno == EINTR);
1462 if (vs->len == -1) {
1463 err = -errno;
1464 }
1465 v9fs_read_post_readv(s, vs, err);
1466 return;
1467 }
1468 vs->offset += pdu_marshal(vs->pdu, vs->offset, "d", vs->total);
1469 vs->offset += vs->count;
1470 err = vs->offset;
1471
1472 out:
1473 complete_pdu(s, vs->pdu, err);
1474 qemu_free(vs);
1475 }
1476
1477 static void v9fs_read_post_lseek(V9fsState *s, V9fsReadState *vs, ssize_t err)
1478 {
1479 if (err == -1) {
1480 err = -errno;
1481 goto out;
1482 }
1483 vs->sg = cap_sg(vs->sg, vs->count, &vs->cnt);
1484
1485 if (vs->total < vs->count) {
1486 do {
1487 if (0) {
1488 print_sg(vs->sg, vs->cnt);
1489 }
1490 vs->len = v9fs_do_readv(s, vs->fidp->fd, vs->sg, vs->cnt);
1491 } while (vs->len == -1 && errno == EINTR);
1492 if (vs->len == -1) {
1493 err = -errno;
1494 }
1495 v9fs_read_post_readv(s, vs, err);
1496 return;
1497 }
1498 out:
1499 complete_pdu(s, vs->pdu, err);
1500 qemu_free(vs);
1501 }
1502
1503 static void v9fs_read(V9fsState *s, V9fsPDU *pdu)
1504 {
1505 int32_t fid;
1506 V9fsReadState *vs;
1507 ssize_t err = 0;
1508
1509 vs = qemu_malloc(sizeof(*vs));
1510 vs->pdu = pdu;
1511 vs->offset = 7;
1512 vs->total = 0;
1513 vs->len = 0;
1514 vs->count = 0;
1515
1516 pdu_unmarshal(vs->pdu, vs->offset, "dqd", &fid, &vs->off, &vs->count);
1517
1518 vs->fidp = lookup_fid(s, fid);
1519 if (vs->fidp == NULL) {
1520 err = -EINVAL;
1521 goto out;
1522 }
1523
1524 if (vs->fidp->dir) {
1525 vs->max_count = vs->count;
1526 vs->count = 0;
1527 if (vs->off == 0) {
1528 v9fs_do_rewinddir(s, vs->fidp->dir);
1529 }
1530 v9fs_read_post_rewinddir(s, vs, err);
1531 return;
1532 } else if (vs->fidp->fd != -1) {
1533 vs->sg = vs->iov;
1534 pdu_marshal(vs->pdu, vs->offset + 4, "v", vs->sg, &vs->cnt);
1535 err = v9fs_do_lseek(s, vs->fidp->fd, vs->off, SEEK_SET);
1536 v9fs_read_post_lseek(s, vs, err);
1537 return;
1538 } else {
1539 err = -EINVAL;
1540 }
1541 out:
1542 complete_pdu(s, pdu, err);
1543 qemu_free(vs);
1544 }
1545
1546 static void v9fs_write_post_writev(V9fsState *s, V9fsWriteState *vs,
1547 ssize_t err)
1548 {
1549 if (err < 0) {
1550 /* IO error return the error */
1551 err = -errno;
1552 goto out;
1553 }
1554 vs->total += vs->len;
1555 vs->sg = adjust_sg(vs->sg, vs->len, &vs->cnt);
1556 if (vs->total < vs->count && vs->len > 0) {
1557 do {
1558 if (0) {
1559 print_sg(vs->sg, vs->cnt);
1560 }
1561 vs->len = v9fs_do_writev(s, vs->fidp->fd, vs->sg, vs->cnt);
1562 } while (vs->len == -1 && errno == EINTR);
1563 if (vs->len == -1) {
1564 err = -errno;
1565 }
1566 v9fs_write_post_writev(s, vs, err);
1567 return;
1568 }
1569 vs->offset += pdu_marshal(vs->pdu, vs->offset, "d", vs->total);
1570
1571 err = vs->offset;
1572 out:
1573 complete_pdu(s, vs->pdu, err);
1574 qemu_free(vs);
1575 }
1576
1577 static void v9fs_write_post_lseek(V9fsState *s, V9fsWriteState *vs, ssize_t err)
1578 {
1579 if (err == -1) {
1580 err = -errno;
1581 goto out;
1582 }
1583 vs->sg = cap_sg(vs->sg, vs->count, &vs->cnt);
1584
1585 if (vs->total < vs->count) {
1586 do {
1587 if (0) {
1588 print_sg(vs->sg, vs->cnt);
1589 }
1590 vs->len = v9fs_do_writev(s, vs->fidp->fd, vs->sg, vs->cnt);
1591 } while (vs->len == -1 && errno == EINTR);
1592 if (vs->len == -1) {
1593 err = -errno;
1594 }
1595 v9fs_write_post_writev(s, vs, err);
1596 return;
1597 }
1598
1599 out:
1600 complete_pdu(s, vs->pdu, err);
1601 qemu_free(vs);
1602 }
1603
1604 static void v9fs_write(V9fsState *s, V9fsPDU *pdu)
1605 {
1606 int32_t fid;
1607 V9fsWriteState *vs;
1608 ssize_t err;
1609
1610 vs = qemu_malloc(sizeof(*vs));
1611
1612 vs->pdu = pdu;
1613 vs->offset = 7;
1614 vs->sg = vs->iov;
1615 vs->total = 0;
1616 vs->len = 0;
1617
1618 pdu_unmarshal(vs->pdu, vs->offset, "dqdv", &fid, &vs->off, &vs->count,
1619 vs->sg, &vs->cnt);
1620
1621 vs->fidp = lookup_fid(s, fid);
1622 if (vs->fidp == NULL) {
1623 err = -EINVAL;
1624 goto out;
1625 }
1626
1627 if (vs->fidp->fd == -1) {
1628 err = -EINVAL;
1629 goto out;
1630 }
1631
1632 err = v9fs_do_lseek(s, vs->fidp->fd, vs->off, SEEK_SET);
1633
1634 v9fs_write_post_lseek(s, vs, err);
1635 return;
1636
1637 out:
1638 complete_pdu(s, vs->pdu, err);
1639 qemu_free(vs);
1640 }
1641
1642 static void v9fs_post_create(V9fsState *s, V9fsCreateState *vs, int err)
1643 {
1644 if (err == 0) {
1645 v9fs_string_copy(&vs->fidp->path, &vs->fullname);
1646 stat_to_qid(&vs->stbuf, &vs->qid);
1647
1648 vs->offset += pdu_marshal(vs->pdu, vs->offset, "Qd", &vs->qid, 0);
1649
1650 err = vs->offset;
1651 }
1652
1653 complete_pdu(s, vs->pdu, err);
1654 v9fs_string_free(&vs->name);
1655 v9fs_string_free(&vs->extension);
1656 v9fs_string_free(&vs->fullname);
1657 qemu_free(vs);
1658 }
1659
1660 static void v9fs_create_post_perms(V9fsState *s, V9fsCreateState *vs, int err)
1661 {
1662 if (err) {
1663 err = -errno;
1664 }
1665 v9fs_post_create(s, vs, err);
1666 }
1667
1668 static void v9fs_create_post_opendir(V9fsState *s, V9fsCreateState *vs,
1669 int err)
1670 {
1671 if (!vs->fidp->dir) {
1672 err = -errno;
1673 }
1674 v9fs_post_create(s, vs, err);
1675 }
1676
1677 static void v9fs_create_post_dir_lstat(V9fsState *s, V9fsCreateState *vs,
1678 int err)
1679 {
1680 if (err) {
1681 err = -errno;
1682 goto out;
1683 }
1684
1685 vs->fidp->dir = v9fs_do_opendir(s, &vs->fullname);
1686 v9fs_create_post_opendir(s, vs, err);
1687 return;
1688
1689 out:
1690 v9fs_post_create(s, vs, err);
1691 }
1692
1693 static void v9fs_create_post_mkdir(V9fsState *s, V9fsCreateState *vs, int err)
1694 {
1695 if (err) {
1696 err = -errno;
1697 goto out;
1698 }
1699
1700 err = v9fs_do_lstat(s, &vs->fullname, &vs->stbuf);
1701 v9fs_create_post_dir_lstat(s, vs, err);
1702 return;
1703
1704 out:
1705 v9fs_post_create(s, vs, err);
1706 }
1707
1708 static void v9fs_create_post_mksock(V9fsState *s, V9fsCreateState *vs,
1709 int err)
1710 {
1711 if (err) {
1712 err = -errno;
1713 goto out;
1714 }
1715
1716 err = v9fs_do_chmod(s, &vs->fullname, vs->perm & 0777);
1717 v9fs_create_post_perms(s, vs, err);
1718 return;
1719
1720 out:
1721 v9fs_post_create(s, vs, err);
1722 }
1723
1724 static void v9fs_create_post_fstat(V9fsState *s, V9fsCreateState *vs, int err)
1725 {
1726 if (err) {
1727 vs->fidp->fd = -1;
1728 err = -errno;
1729 }
1730
1731 v9fs_post_create(s, vs, err);
1732 return;
1733 }
1734
1735 static void v9fs_create_post_open2(V9fsState *s, V9fsCreateState *vs, int err)
1736 {
1737 if (vs->fidp->fd == -1) {
1738 err = -errno;
1739 goto out;
1740 }
1741
1742 err = v9fs_do_fstat(s, vs->fidp->fd, &vs->stbuf);
1743 v9fs_create_post_fstat(s, vs, err);
1744
1745 return;
1746
1747 out:
1748 v9fs_post_create(s, vs, err);
1749
1750 }
1751
1752 static void v9fs_create_post_lstat(V9fsState *s, V9fsCreateState *vs, int err)
1753 {
1754
1755 if (err == 0 || errno != ENOENT) {
1756 err = -errno;
1757 goto out;
1758 }
1759
1760 if (vs->perm & P9_STAT_MODE_DIR) {
1761 err = v9fs_do_mkdir(s, &vs->fullname, vs->perm & 0777);
1762 v9fs_create_post_mkdir(s, vs, err);
1763 } else if (vs->perm & P9_STAT_MODE_SYMLINK) {
1764 err = v9fs_do_symlink(s, &vs->extension, &vs->fullname);
1765 v9fs_create_post_perms(s, vs, err);
1766 } else if (vs->perm & P9_STAT_MODE_LINK) {
1767 int32_t nfid = atoi(vs->extension.data);
1768 V9fsFidState *nfidp = lookup_fid(s, nfid);
1769 if (nfidp == NULL) {
1770 err = -errno;
1771 v9fs_post_create(s, vs, err);
1772 }
1773 err = v9fs_do_link(s, &nfidp->path, &vs->fullname);
1774 v9fs_create_post_perms(s, vs, err);
1775 } else if (vs->perm & P9_STAT_MODE_DEVICE) {
1776 char ctype;
1777 uint32_t major, minor;
1778 mode_t nmode = 0;
1779
1780 if (sscanf(vs->extension.data, "%c %u %u", &ctype, &major,
1781 &minor) != 3) {
1782 err = -errno;
1783 v9fs_post_create(s, vs, err);
1784 }
1785
1786 switch (ctype) {
1787 case 'c':
1788 nmode = S_IFCHR;
1789 break;
1790 case 'b':
1791 nmode = S_IFBLK;
1792 break;
1793 default:
1794 err = -EIO;
1795 v9fs_post_create(s, vs, err);
1796 }
1797
1798 nmode |= vs->perm & 0777;
1799 err = v9fs_do_mknod(s, &vs->fullname, nmode, makedev(major, minor));
1800 v9fs_create_post_perms(s, vs, err);
1801 } else if (vs->perm & P9_STAT_MODE_NAMED_PIPE) {
1802 err = v9fs_do_mknod(s, &vs->fullname, S_IFIFO | (vs->mode & 0777), 0);
1803 v9fs_post_create(s, vs, err);
1804 } else if (vs->perm & P9_STAT_MODE_SOCKET) {
1805 err = v9fs_do_mksock(s, &vs->fullname);
1806 v9fs_create_post_mksock(s, vs, err);
1807 } else {
1808 vs->fidp->fd = v9fs_do_open2(s, &vs->fullname,
1809 omode_to_uflags(vs->mode) | O_CREAT,
1810 vs->perm & 0777);
1811 v9fs_create_post_open2(s, vs, err);
1812 }
1813
1814 return;
1815
1816 out:
1817 v9fs_post_create(s, vs, err);
1818 }
1819
1820 static void v9fs_create(V9fsState *s, V9fsPDU *pdu)
1821 {
1822 int32_t fid;
1823 V9fsCreateState *vs;
1824 int err = 0;
1825
1826 vs = qemu_malloc(sizeof(*vs));
1827 vs->pdu = pdu;
1828 vs->offset = 7;
1829
1830 v9fs_string_init(&vs->fullname);
1831
1832 pdu_unmarshal(vs->pdu, vs->offset, "dsdbs", &fid, &vs->name,
1833 &vs->perm, &vs->mode, &vs->extension);
1834
1835 vs->fidp = lookup_fid(s, fid);
1836 if (vs->fidp == NULL) {
1837 err = -EINVAL;
1838 goto out;
1839 }
1840
1841 v9fs_string_sprintf(&vs->fullname, "%s/%s", vs->fidp->path.data,
1842 vs->name.data);
1843
1844 err = v9fs_do_lstat(s, &vs->fullname, &vs->stbuf);
1845 v9fs_create_post_lstat(s, vs, err);
1846 return;
1847
1848 out:
1849 complete_pdu(s, vs->pdu, err);
1850 v9fs_string_free(&vs->name);
1851 v9fs_string_free(&vs->extension);
1852 qemu_free(vs);
1853 }
1854
1855 static void v9fs_flush(V9fsState *s, V9fsPDU *pdu)
1856 {
1857 /* A nop call with no return */
1858 complete_pdu(s, pdu, 7);
1859 }
1860
1861 static void v9fs_remove_post_remove(V9fsState *s, V9fsRemoveState *vs,
1862 int err)
1863 {
1864 /* For TREMOVE we need to clunk the fid even on failed remove */
1865 err = free_fid(s, vs->fidp->fid);
1866 if (err < 0) {
1867 goto out;
1868 }
1869
1870 err = vs->offset;
1871 out:
1872 complete_pdu(s, vs->pdu, err);
1873 qemu_free(vs);
1874 }
1875
1876 static void v9fs_remove(V9fsState *s, V9fsPDU *pdu)
1877 {
1878 int32_t fid;
1879 V9fsRemoveState *vs;
1880 int err = 0;
1881
1882 vs = qemu_malloc(sizeof(*vs));
1883 vs->pdu = pdu;
1884 vs->offset = 7;
1885
1886 pdu_unmarshal(vs->pdu, vs->offset, "d", &fid);
1887
1888 vs->fidp = lookup_fid(s, fid);
1889 if (vs->fidp == NULL) {
1890 err = -EINVAL;
1891 goto out;
1892 }
1893
1894 err = v9fs_do_remove(s, &vs->fidp->path);
1895 v9fs_remove_post_remove(s, vs, err);
1896 return;
1897
1898 out:
1899 complete_pdu(s, pdu, err);
1900 qemu_free(vs);
1901 }
1902
1903 static void v9fs_wstat_post_truncate(V9fsState *s, V9fsWstatState *vs, int err)
1904 {
1905 if (err < 0) {
1906 goto out;
1907 }
1908
1909 err = vs->offset;
1910
1911 out:
1912 v9fs_stat_free(&vs->v9stat);
1913 complete_pdu(s, vs->pdu, err);
1914 qemu_free(vs);
1915 }
1916
1917 static void v9fs_wstat_post_rename(V9fsState *s, V9fsWstatState *vs, int err)
1918 {
1919 if (err < 0) {
1920 goto out;
1921 }
1922
1923 if (vs->v9stat.name.size != 0) {
1924 v9fs_string_free(&vs->nname);
1925 }
1926
1927 if (vs->v9stat.length != -1) {
1928 if (v9fs_do_truncate(s, &vs->fidp->path, vs->v9stat.length) < 0) {
1929 err = -errno;
1930 }
1931 }
1932 v9fs_wstat_post_truncate(s, vs, err);
1933 return;
1934
1935 out:
1936 v9fs_stat_free(&vs->v9stat);
1937 complete_pdu(s, vs->pdu, err);
1938 qemu_free(vs);
1939 }
1940
1941 static void v9fs_wstat_post_chown(V9fsState *s, V9fsWstatState *vs, int err)
1942 {
1943 V9fsFidState *fidp;
1944 if (err < 0) {
1945 goto out;
1946 }
1947
1948 if (vs->v9stat.name.size != 0) {
1949 char *old_name, *new_name;
1950 char *end;
1951
1952 old_name = vs->fidp->path.data;
1953 end = strrchr(old_name, '/');
1954 if (end) {
1955 end++;
1956 } else {
1957 end = old_name;
1958 }
1959
1960 new_name = qemu_malloc(end - old_name + vs->v9stat.name.size + 1);
1961
1962 memset(new_name, 0, end - old_name + vs->v9stat.name.size + 1);
1963 memcpy(new_name, old_name, end - old_name);
1964 memcpy(new_name + (end - old_name), vs->v9stat.name.data,
1965 vs->v9stat.name.size);
1966 vs->nname.data = new_name;
1967 vs->nname.size = strlen(new_name);
1968
1969 if (strcmp(new_name, vs->fidp->path.data) != 0) {
1970 if (v9fs_do_rename(s, &vs->fidp->path, &vs->nname)) {
1971 err = -errno;
1972 } else {
1973 /*
1974 * Fixup fid's pointing to the old name to
1975 * start pointing to the new name
1976 */
1977 for (fidp = s->fid_list; fidp; fidp = fidp->next) {
1978
1979 if (vs->fidp == fidp) {
1980 /*
1981 * we replace name of this fid towards the end
1982 * so that our below strcmp will work
1983 */
1984 continue;
1985 }
1986 if (!strncmp(vs->fidp->path.data, fidp->path.data,
1987 strlen(vs->fidp->path.data))) {
1988 /* replace the name */
1989 v9fs_fix_path(&fidp->path, &vs->nname,
1990 strlen(vs->fidp->path.data));
1991 }
1992 }
1993 v9fs_string_copy(&vs->fidp->path, &vs->nname);
1994 }
1995 }
1996 }
1997 v9fs_wstat_post_rename(s, vs, err);
1998 return;
1999
2000 out:
2001 v9fs_stat_free(&vs->v9stat);
2002 complete_pdu(s, vs->pdu, err);
2003 qemu_free(vs);
2004 }
2005
2006 static void v9fs_wstat_post_utime(V9fsState *s, V9fsWstatState *vs, int err)
2007 {
2008 if (err < 0) {
2009 goto out;
2010 }
2011
2012 if (vs->v9stat.n_gid != -1) {
2013 if (v9fs_do_chown(s, &vs->fidp->path, vs->v9stat.n_uid,
2014 vs->v9stat.n_gid)) {
2015 err = -errno;
2016 }
2017 }
2018 v9fs_wstat_post_chown(s, vs, err);
2019 return;
2020
2021 out:
2022 v9fs_stat_free(&vs->v9stat);
2023 complete_pdu(s, vs->pdu, err);
2024 qemu_free(vs);
2025 }
2026
2027 static void v9fs_wstat_post_chmod(V9fsState *s, V9fsWstatState *vs, int err)
2028 {
2029 if (err < 0) {
2030 goto out;
2031 }
2032
2033 if (vs->v9stat.mtime != -1) {
2034 struct utimbuf tb;
2035 tb.actime = 0;
2036 tb.modtime = vs->v9stat.mtime;
2037 if (v9fs_do_utime(s, &vs->fidp->path, &tb)) {
2038 err = -errno;
2039 }
2040 }
2041
2042 v9fs_wstat_post_utime(s, vs, err);
2043 return;
2044
2045 out:
2046 v9fs_stat_free(&vs->v9stat);
2047 complete_pdu(s, vs->pdu, err);
2048 qemu_free(vs);
2049 }
2050
2051 static void v9fs_wstat_post_fsync(V9fsState *s, V9fsWstatState *vs, int err)
2052 {
2053 if (err == -1) {
2054 err = -errno;
2055 }
2056 v9fs_stat_free(&vs->v9stat);
2057 complete_pdu(s, vs->pdu, err);
2058 qemu_free(vs);
2059 }
2060
2061 static void v9fs_wstat_post_lstat(V9fsState *s, V9fsWstatState *vs, int err)
2062 {
2063 uint32_t v9_mode;
2064
2065 if (err == -1) {
2066 err = -errno;
2067 goto out;
2068 }
2069
2070 v9_mode = stat_to_v9mode(&vs->stbuf);
2071
2072 if ((vs->v9stat.mode & P9_STAT_MODE_TYPE_BITS) !=
2073 (v9_mode & P9_STAT_MODE_TYPE_BITS)) {
2074 /* Attempting to change the type */
2075 err = -EIO;
2076 goto out;
2077 }
2078
2079 if (v9fs_do_chmod(s, &vs->fidp->path, v9mode_to_mode(vs->v9stat.mode,
2080 &vs->v9stat.extension))) {
2081 err = -errno;
2082 }
2083 v9fs_wstat_post_chmod(s, vs, err);
2084 return;
2085
2086 out:
2087 v9fs_stat_free(&vs->v9stat);
2088 complete_pdu(s, vs->pdu, err);
2089 qemu_free(vs);
2090 }
2091
2092 static void v9fs_wstat(V9fsState *s, V9fsPDU *pdu)
2093 {
2094 int32_t fid;
2095 V9fsWstatState *vs;
2096 int err = 0;
2097
2098 vs = qemu_malloc(sizeof(*vs));
2099 vs->pdu = pdu;
2100 vs->offset = 7;
2101
2102 pdu_unmarshal(pdu, vs->offset, "dwS", &fid, &vs->unused, &vs->v9stat);
2103
2104 vs->fidp = lookup_fid(s, fid);
2105 if (vs->fidp == NULL) {
2106 err = -EINVAL;
2107 goto out;
2108 }
2109
2110 /* do we need to sync the file? */
2111 if (donttouch_stat(&vs->v9stat)) {
2112 err = v9fs_do_fsync(s, vs->fidp->fd);
2113 v9fs_wstat_post_fsync(s, vs, err);
2114 return;
2115 }
2116
2117 if (vs->v9stat.mode != -1) {
2118 err = v9fs_do_lstat(s, &vs->fidp->path, &vs->stbuf);
2119 v9fs_wstat_post_lstat(s, vs, err);
2120 return;
2121 }
2122
2123 v9fs_wstat_post_chmod(s, vs, err);
2124 return;
2125
2126 out:
2127 v9fs_stat_free(&vs->v9stat);
2128 complete_pdu(s, vs->pdu, err);
2129 qemu_free(vs);
2130 }
2131
2132 typedef void (pdu_handler_t)(V9fsState *s, V9fsPDU *pdu);
2133
2134 static pdu_handler_t *pdu_handlers[] = {
2135 [P9_TVERSION] = v9fs_version,
2136 [P9_TATTACH] = v9fs_attach,
2137 [P9_TSTAT] = v9fs_stat,
2138 [P9_TWALK] = v9fs_walk,
2139 [P9_TCLUNK] = v9fs_clunk,
2140 [P9_TOPEN] = v9fs_open,
2141 [P9_TREAD] = v9fs_read,
2142 #if 0
2143 [P9_TAUTH] = v9fs_auth,
2144 #endif
2145 [P9_TFLUSH] = v9fs_flush,
2146 [P9_TCREATE] = v9fs_create,
2147 [P9_TWRITE] = v9fs_write,
2148 [P9_TWSTAT] = v9fs_wstat,
2149 [P9_TREMOVE] = v9fs_remove,
2150 };
2151
2152 static void submit_pdu(V9fsState *s, V9fsPDU *pdu)
2153 {
2154 pdu_handler_t *handler;
2155
2156 if (debug_9p_pdu) {
2157 pprint_pdu(pdu);
2158 }
2159
2160 BUG_ON(pdu->id >= ARRAY_SIZE(pdu_handlers));
2161
2162 handler = pdu_handlers[pdu->id];
2163 BUG_ON(handler == NULL);
2164
2165 handler(s, pdu);
2166 }
2167
2168 static void handle_9p_output(VirtIODevice *vdev, VirtQueue *vq)
2169 {
2170 V9fsState *s = (V9fsState *)vdev;
2171 V9fsPDU *pdu;
2172 ssize_t len;
2173
2174 while ((pdu = alloc_pdu(s)) &&
2175 (len = virtqueue_pop(vq, &pdu->elem)) != 0) {
2176 uint8_t *ptr;
2177
2178 BUG_ON(pdu->elem.out_num == 0 || pdu->elem.in_num == 0);
2179 BUG_ON(pdu->elem.out_sg[0].iov_len < 7);
2180
2181 ptr = pdu->elem.out_sg[0].iov_base;
2182
2183 memcpy(&pdu->size, ptr, 4);
2184 pdu->id = ptr[4];
2185 memcpy(&pdu->tag, ptr + 5, 2);
2186
2187 submit_pdu(s, pdu);
2188 }
2189
2190 free_pdu(s, pdu);
2191 }
2192
2193 static uint32_t virtio_9p_get_features(VirtIODevice *vdev, uint32_t features)
2194 {
2195 features |= 1 << VIRTIO_9P_MOUNT_TAG;
2196 return features;
2197 }
2198
2199 static V9fsState *to_virtio_9p(VirtIODevice *vdev)
2200 {
2201 return (V9fsState *)vdev;
2202 }
2203
2204 static void virtio_9p_get_config(VirtIODevice *vdev, uint8_t *config)
2205 {
2206 struct virtio_9p_config *cfg;
2207 V9fsState *s = to_virtio_9p(vdev);
2208
2209 cfg = qemu_mallocz(sizeof(struct virtio_9p_config) +
2210 s->tag_len);
2211 stw_raw(&cfg->tag_len, s->tag_len);
2212 memcpy(cfg->tag, s->tag, s->tag_len);
2213 memcpy(config, cfg, s->config_size);
2214 qemu_free(cfg);
2215 }
2216
2217 VirtIODevice *virtio_9p_init(DeviceState *dev, V9fsConf *conf)
2218 {
2219 V9fsState *s;
2220 int i, len;
2221 struct stat stat;
2222 FsTypeEntry *fse;
2223
2224
2225 s = (V9fsState *)virtio_common_init("virtio-9p",
2226 VIRTIO_ID_9P,
2227 sizeof(struct virtio_9p_config)+
2228 MAX_TAG_LEN,
2229 sizeof(V9fsState));
2230
2231 /* initialize pdu allocator */
2232 QLIST_INIT(&s->free_list);
2233 for (i = 0; i < (MAX_REQ - 1); i++) {
2234 QLIST_INSERT_HEAD(&s->free_list, &s->pdus[i], next);
2235 }
2236
2237 s->vq = virtio_add_queue(&s->vdev, MAX_REQ, handle_9p_output);
2238
2239 fse = get_fsdev_fsentry(conf->fsdev_id);
2240
2241 if (!fse) {
2242 /* We don't have a fsdev identified by fsdev_id */
2243 fprintf(stderr, "Virtio-9p device couldn't find fsdev "
2244 "with the id %s\n", conf->fsdev_id);
2245 exit(1);
2246 }
2247
2248 if (!fse->path || !conf->tag) {
2249 /* we haven't specified a mount_tag or the path */
2250 fprintf(stderr, "fsdev with id %s needs path "
2251 "and Virtio-9p device needs mount_tag arguments\n",
2252 conf->fsdev_id);
2253 exit(1);
2254 }
2255
2256 if (!strcmp(fse->security_model, "passthrough") &&
2257 !strcmp(fse->security_model, "mapped")) {
2258 /* user haven't specified a correct security option */
2259 fprintf(stderr, "one of the following must be specified as the"
2260 "security option:\n\t security_model=passthrough \n\t "
2261 "security_model=mapped\n");
2262 return NULL;
2263 }
2264
2265 if (lstat(fse->path, &stat)) {
2266 fprintf(stderr, "share path %s does not exist\n", fse->path);
2267 exit(1);
2268 } else if (!S_ISDIR(stat.st_mode)) {
2269 fprintf(stderr, "share path %s is not a directory \n", fse->path);
2270 exit(1);
2271 }
2272
2273 s->ctx.fs_root = qemu_strdup(fse->path);
2274 len = strlen(conf->tag);
2275 if (len > MAX_TAG_LEN) {
2276 len = MAX_TAG_LEN;
2277 }
2278 /* s->tag is non-NULL terminated string */
2279 s->tag = qemu_malloc(len);
2280 memcpy(s->tag, conf->tag, len);
2281 s->tag_len = len;
2282 s->ctx.uid = -1;
2283
2284 s->ops = fse->ops;
2285 s->vdev.get_features = virtio_9p_get_features;
2286 s->config_size = sizeof(struct virtio_9p_config) +
2287 s->tag_len;
2288 s->vdev.get_config = virtio_9p_get_config;
2289
2290 return &s->vdev;
2291 }