1 /*
2  * 9P network client for VirtIO 9P test cases (based on QTest)
3  *
4  * Copyright (c) 2014 SUSE LINUX Products GmbH
5  *
6  * This work is licensed under the terms of the GNU GPL, version 2 or later.
7  * See the COPYING file in the top-level directory.
8  */
9 
10 /*
11  * Not so fast! You might want to read the 9p developer docs first:
12  * https://wiki.qemu.org/Documentation/9p
13  */
14 
15 #ifndef TESTS_LIBQOS_VIRTIO_9P_CLIENT_H
16 #define TESTS_LIBQOS_VIRTIO_9P_CLIENT_H
17 
18 #include "hw/9pfs/9p.h"
19 #include "hw/9pfs/9p-synth.h"
20 #include "virtio-9p.h"
21 #include "qgraph.h"
22 #include "tests/qtest/libqtest-single.h"
23 
24 #define P9_MAX_SIZE 4096 /* Max size of a T-message or R-message */
25 
26 typedef struct {
27     QTestState *qts;
28     QVirtio9P *v9p;
29     uint16_t tag;
30     uint64_t t_msg;
31     uint32_t t_size;
32     uint64_t r_msg;
33     /* No r_size, it is hardcoded to P9_MAX_SIZE */
34     size_t t_off;
35     size_t r_off;
36     uint32_t free_head;
37 } P9Req;
38 
39 /* type[1] version[4] path[8] */
40 typedef char v9fs_qid[13];
41 
42 typedef struct v9fs_attr {
43     uint64_t valid;
44     v9fs_qid qid;
45     uint32_t mode;
46     uint32_t uid;
47     uint32_t gid;
48     uint64_t nlink;
49     uint64_t rdev;
50     uint64_t size;
51     uint64_t blksize;
52     uint64_t blocks;
53     uint64_t atime_sec;
54     uint64_t atime_nsec;
55     uint64_t mtime_sec;
56     uint64_t mtime_nsec;
57     uint64_t ctime_sec;
58     uint64_t ctime_nsec;
59     uint64_t btime_sec;
60     uint64_t btime_nsec;
61     uint64_t gen;
62     uint64_t data_version;
63 } v9fs_attr;
64 
65 #define P9_GETATTR_BASIC    0x000007ffULL /* Mask for fields up to BLOCKS */
66 #define P9_GETATTR_ALL      0x00003fffULL /* Mask for ALL fields */
67 
68 struct V9fsDirent {
69     v9fs_qid qid;
70     uint64_t offset;
71     uint8_t type;
72     char *name;
73     struct V9fsDirent *next;
74 };
75 
76 /* options for 'Twalk' 9p request */
77 typedef struct TWalkOpt {
78     /* 9P client being used (mandatory) */
79     QVirtio9P *client;
80     /* user supplied tag number being returned with response (optional) */
81     uint16_t tag;
82     /* file ID of directory from where walk should start (optional) */
83     uint32_t fid;
84     /* file ID for target directory being walked to (optional) */
85     uint32_t newfid;
86     /* low level variant of path to walk to (optional) */
87     uint16_t nwname;
88     char **wnames;
89     /* high level variant of path to walk to (optional) */
90     const char *path;
91     /* data being received from 9p server as 'Rwalk' response (optional) */
92     struct {
93         uint16_t *nwqid;
94         v9fs_qid **wqid;
95     } rwalk;
96     /* only send Twalk request but not wait for a reply? (optional) */
97     bool requestOnly;
98     /* do we expect an Rlerror response, if yes which error code? (optional) */
99     uint32_t expectErr;
100 } TWalkOpt;
101 
102 /* result of 'Twalk' 9p request */
103 typedef struct TWalkRes {
104     /* file ID of target directory been walked to */
105     uint32_t newfid;
106     /* if requestOnly was set: request object for further processing */
107     P9Req *req;
108 } TWalkRes;
109 
110 /* options for 'Tversion' 9p request */
111 typedef struct TVersionOpt {
112     /* 9P client being used (mandatory) */
113     QVirtio9P *client;
114     /* user supplied tag number being returned with response (optional) */
115     uint16_t tag;
116     /* maximum message size that can be handled by client (optional) */
117     uint32_t msize;
118     /* protocol version (optional) */
119     const char *version;
120     /* only send Tversion request but not wait for a reply? (optional) */
121     bool requestOnly;
122     /* do we expect an Rlerror response, if yes which error code? (optional) */
123     uint32_t expectErr;
124 } TVersionOpt;
125 
126 /* result of 'Tversion' 9p request */
127 typedef struct TVersionRes {
128     /* if requestOnly was set: request object for further processing */
129     P9Req *req;
130 } TVersionRes;
131 
132 /* options for 'Tattach' 9p request */
133 typedef struct TAttachOpt {
134     /* 9P client being used (mandatory) */
135     QVirtio9P *client;
136     /* user supplied tag number being returned with response (optional) */
137     uint16_t tag;
138     /* file ID to be associated with root of file tree (optional) */
139     uint32_t fid;
140     /* numerical uid of user being introduced to server (optional) */
141     uint32_t n_uname;
142     /* data being received from 9p server as 'Rattach' response (optional) */
143     struct {
144         /* server's idea of the root of the file tree */
145         v9fs_qid *qid;
146     } rattach;
147     /* only send Tattach request but not wait for a reply? (optional) */
148     bool requestOnly;
149     /* do we expect an Rlerror response, if yes which error code? (optional) */
150     uint32_t expectErr;
151 } TAttachOpt;
152 
153 /* result of 'Tattach' 9p request */
154 typedef struct TAttachRes {
155     /* if requestOnly was set: request object for further processing */
156     P9Req *req;
157 } TAttachRes;
158 
159 /* options for 'Tgetattr' 9p request */
160 typedef struct TGetAttrOpt {
161     /* 9P client being used (mandatory) */
162     QVirtio9P *client;
163     /* user supplied tag number being returned with response (optional) */
164     uint16_t tag;
165     /* file ID of file/dir whose attributes shall be retrieved (required) */
166     uint32_t fid;
167     /* bitmask indicating attribute fields to be retrieved (optional) */
168     uint64_t request_mask;
169     /* data being received from 9p server as 'Rgetattr' response (optional) */
170     struct {
171         v9fs_attr *attr;
172     } rgetattr;
173     /* only send Tgetattr request but not wait for a reply? (optional) */
174     bool requestOnly;
175     /* do we expect an Rlerror response, if yes which error code? (optional) */
176     uint32_t expectErr;
177 } TGetAttrOpt;
178 
179 /* result of 'Tgetattr' 9p request */
180 typedef struct TGetAttrRes {
181     /* if requestOnly was set: request object for further processing */
182     P9Req *req;
183 } TGetAttrRes;
184 
185 /* options for 'Treaddir' 9p request */
186 typedef struct TReadDirOpt {
187     /* 9P client being used (mandatory) */
188     QVirtio9P *client;
189     /* user supplied tag number being returned with response (optional) */
190     uint16_t tag;
191     /* file ID of directory whose entries shall be retrieved (required) */
192     uint32_t fid;
193     /* offset in entries stream, i.e. for multiple requests (optional) */
194     uint64_t offset;
195     /* maximum bytes to be returned by server (required) */
196     uint32_t count;
197     /* data being received from 9p server as 'Rreaddir' response (optional) */
198     struct {
199         uint32_t *count;
200         uint32_t *nentries;
201         struct V9fsDirent **entries;
202     } rreaddir;
203     /* only send Treaddir request but not wait for a reply? (optional) */
204     bool requestOnly;
205     /* do we expect an Rlerror response, if yes which error code? (optional) */
206     uint32_t expectErr;
207 } TReadDirOpt;
208 
209 /* result of 'Treaddir' 9p request */
210 typedef struct TReadDirRes {
211     /* if requestOnly was set: request object for further processing */
212     P9Req *req;
213 } TReadDirRes;
214 
215 /* options for 'Tlopen' 9p request */
216 typedef struct TLOpenOpt {
217     /* 9P client being used (mandatory) */
218     QVirtio9P *client;
219     /* user supplied tag number being returned with response (optional) */
220     uint16_t tag;
221     /* file ID of file / directory to be opened (required) */
222     uint32_t fid;
223     /* Linux open(2) flags such as O_RDONLY, O_RDWR, O_WRONLY (optional) */
224     uint32_t flags;
225     /* data being received from 9p server as 'Rlopen' response (optional) */
226     struct {
227         v9fs_qid *qid;
228         uint32_t *iounit;
229     } rlopen;
230     /* only send Tlopen request but not wait for a reply? (optional) */
231     bool requestOnly;
232     /* do we expect an Rlerror response, if yes which error code? (optional) */
233     uint32_t expectErr;
234 } TLOpenOpt;
235 
236 /* result of 'Tlopen' 9p request */
237 typedef struct TLOpenRes {
238     /* if requestOnly was set: request object for further processing */
239     P9Req *req;
240 } TLOpenRes;
241 
242 /* options for 'Twrite' 9p request */
243 typedef struct TWriteOpt {
244     /* 9P client being used (mandatory) */
245     QVirtio9P *client;
246     /* user supplied tag number being returned with response (optional) */
247     uint16_t tag;
248     /* file ID of file to write to (required) */
249     uint32_t fid;
250     /* start position of write from beginning of file (optional) */
251     uint64_t offset;
252     /* how many bytes to write */
253     uint32_t count;
254     /* data to be written */
255     const void *data;
256     /* only send Twrite request but not wait for a reply? (optional) */
257     bool requestOnly;
258     /* do we expect an Rlerror response, if yes which error code? (optional) */
259     uint32_t expectErr;
260 } TWriteOpt;
261 
262 /* result of 'Twrite' 9p request */
263 typedef struct TWriteRes {
264     /* if requestOnly was set: request object for further processing */
265     P9Req *req;
266     /* amount of bytes written */
267     uint32_t count;
268 } TWriteRes;
269 
270 /* options for 'Tflush' 9p request */
271 typedef struct TFlushOpt {
272     /* 9P client being used (mandatory) */
273     QVirtio9P *client;
274     /* user supplied tag number being returned with response (optional) */
275     uint16_t tag;
276     /* message to flush (required) */
277     uint16_t oldtag;
278     /* only send Tflush request but not wait for a reply? (optional) */
279     bool requestOnly;
280     /* do we expect an Rlerror response, if yes which error code? (optional) */
281     uint32_t expectErr;
282 } TFlushOpt;
283 
284 /* result of 'Tflush' 9p request */
285 typedef struct TFlushRes {
286     /* if requestOnly was set: request object for further processing */
287     P9Req *req;
288 } TFlushRes;
289 
290 /* options for 'Tmkdir' 9p request */
291 typedef struct TMkdirOpt {
292     /* 9P client being used (mandatory) */
293     QVirtio9P *client;
294     /* user supplied tag number being returned with response (optional) */
295     uint16_t tag;
296     /* low level variant of directory where new one shall be created */
297     uint32_t dfid;
298     /* high-level variant of directory where new one shall be created */
299     const char *atPath;
300     /* New directory's name (required) */
301     const char *name;
302     /* Linux mkdir(2) mode bits (optional) */
303     uint32_t mode;
304     /* effective group ID of caller */
305     uint32_t gid;
306     /* data being received from 9p server as 'Rmkdir' response (optional) */
307     struct {
308         /* QID of newly created directory */
309         v9fs_qid *qid;
310     } rmkdir;
311     /* only send Tmkdir request but not wait for a reply? (optional) */
312     bool requestOnly;
313     /* do we expect an Rlerror response, if yes which error code? (optional) */
314     uint32_t expectErr;
315 } TMkdirOpt;
316 
317 /* result of 'TMkdir' 9p request */
318 typedef struct TMkdirRes {
319     /* if requestOnly was set: request object for further processing */
320     P9Req *req;
321 } TMkdirRes;
322 
323 /* options for 'Tlcreate' 9p request */
324 typedef struct TlcreateOpt {
325     /* 9P client being used (mandatory) */
326     QVirtio9P *client;
327     /* user supplied tag number being returned with response (optional) */
328     uint16_t tag;
329     /* low-level variant of directory where new file shall be created */
330     uint32_t fid;
331     /* high-level variant of directory where new file shall be created */
332     const char *atPath;
333     /* name of new file (required) */
334     const char *name;
335     /* Linux kernel intent bits */
336     uint32_t flags;
337     /* Linux create(2) mode bits */
338     uint32_t mode;
339     /* effective group ID of caller */
340     uint32_t gid;
341     /* data being received from 9p server as 'Rlcreate' response (optional) */
342     struct {
343         v9fs_qid *qid;
344         uint32_t *iounit;
345     } rlcreate;
346     /* only send Tlcreate request but not wait for a reply? (optional) */
347     bool requestOnly;
348     /* do we expect an Rlerror response, if yes which error code? (optional) */
349     uint32_t expectErr;
350 } TlcreateOpt;
351 
352 /* result of 'Tlcreate' 9p request */
353 typedef struct TlcreateRes {
354     /* if requestOnly was set: request object for further processing */
355     P9Req *req;
356 } TlcreateRes;
357 
358 /* options for 'Tsymlink' 9p request */
359 typedef struct TsymlinkOpt {
360     /* 9P client being used (mandatory) */
361     QVirtio9P *client;
362     /* user supplied tag number being returned with response (optional) */
363     uint16_t tag;
364     /* low-level variant of directory where symlink shall be created */
365     uint32_t fid;
366     /* high-level variant of directory where symlink shall be created */
367     const char *atPath;
368     /* name of symlink (required) */
369     const char *name;
370     /* where symlink will point to (required) */
371     const char *symtgt;
372     /* effective group ID of caller */
373     uint32_t gid;
374     /* data being received from 9p server as 'Rsymlink' response (optional) */
375     struct {
376         v9fs_qid *qid;
377     } rsymlink;
378     /* only send Tsymlink request but not wait for a reply? (optional) */
379     bool requestOnly;
380     /* do we expect an Rlerror response, if yes which error code? (optional) */
381     uint32_t expectErr;
382 } TsymlinkOpt;
383 
384 /* result of 'Tsymlink' 9p request */
385 typedef struct TsymlinkRes {
386     /* if requestOnly was set: request object for further processing */
387     P9Req *req;
388 } TsymlinkRes;
389 
390 /* options for 'Tlink' 9p request */
391 typedef struct TlinkOpt {
392     /* 9P client being used (mandatory) */
393     QVirtio9P *client;
394     /* user supplied tag number being returned with response (optional) */
395     uint16_t tag;
396     /* low-level variant of directory where hard link shall be created */
397     uint32_t dfid;
398     /* high-level variant of directory where hard link shall be created */
399     const char *atPath;
400     /* low-level variant of target referenced by new hard link */
401     uint32_t fid;
402     /* high-level variant of target referenced by new hard link */
403     const char *toPath;
404     /* name of hard link (required) */
405     const char *name;
406     /* only send Tlink request but not wait for a reply? (optional) */
407     bool requestOnly;
408     /* do we expect an Rlerror response, if yes which error code? (optional) */
409     uint32_t expectErr;
410 } TlinkOpt;
411 
412 /* result of 'Tlink' 9p request */
413 typedef struct TlinkRes {
414     /* if requestOnly was set: request object for further processing */
415     P9Req *req;
416 } TlinkRes;
417 
418 /* options for 'Tunlinkat' 9p request */
419 typedef struct TunlinkatOpt {
420     /* 9P client being used (mandatory) */
421     QVirtio9P *client;
422     /* user supplied tag number being returned with response (optional) */
423     uint16_t tag;
424     /* low-level variant of directory where name shall be unlinked */
425     uint32_t dirfd;
426     /* high-level variant of directory where name shall be unlinked */
427     const char *atPath;
428     /* name of directory entry to be unlinked (required) */
429     const char *name;
430     /* Linux unlinkat(2) flags */
431     uint32_t flags;
432     /* only send Tunlinkat request but not wait for a reply? (optional) */
433     bool requestOnly;
434     /* do we expect an Rlerror response, if yes which error code? (optional) */
435     uint32_t expectErr;
436 } TunlinkatOpt;
437 
438 /* result of 'Tunlinkat' 9p request */
439 typedef struct TunlinkatRes {
440     /* if requestOnly was set: request object for further processing */
441     P9Req *req;
442 } TunlinkatRes;
443 
444 void v9fs_set_allocator(QGuestAllocator *t_alloc);
445 void v9fs_memwrite(P9Req *req, const void *addr, size_t len);
446 void v9fs_memskip(P9Req *req, size_t len);
447 void v9fs_memread(P9Req *req, void *addr, size_t len);
448 void v9fs_uint8_read(P9Req *req, uint8_t *val);
449 void v9fs_uint16_write(P9Req *req, uint16_t val);
450 void v9fs_uint16_read(P9Req *req, uint16_t *val);
451 void v9fs_uint32_write(P9Req *req, uint32_t val);
452 void v9fs_uint64_write(P9Req *req, uint64_t val);
453 void v9fs_uint32_read(P9Req *req, uint32_t *val);
454 void v9fs_uint64_read(P9Req *req, uint64_t *val);
455 uint16_t v9fs_string_size(const char *string);
456 void v9fs_string_write(P9Req *req, const char *string);
457 void v9fs_string_read(P9Req *req, uint16_t *len, char **string);
458 P9Req *v9fs_req_init(QVirtio9P *v9p, uint32_t size, uint8_t id,
459                      uint16_t tag);
460 void v9fs_req_send(P9Req *req);
461 void v9fs_req_wait_for_reply(P9Req *req, uint32_t *len);
462 void v9fs_req_recv(P9Req *req, uint8_t id);
463 void v9fs_req_free(P9Req *req);
464 void v9fs_rlerror(P9Req *req, uint32_t *err);
465 TVersionRes v9fs_tversion(TVersionOpt);
466 void v9fs_rversion(P9Req *req, uint16_t *len, char **version);
467 TAttachRes v9fs_tattach(TAttachOpt);
468 void v9fs_rattach(P9Req *req, v9fs_qid *qid);
469 TWalkRes v9fs_twalk(TWalkOpt opt);
470 void v9fs_rwalk(P9Req *req, uint16_t *nwqid, v9fs_qid **wqid);
471 TGetAttrRes v9fs_tgetattr(TGetAttrOpt);
472 void v9fs_rgetattr(P9Req *req, v9fs_attr *attr);
473 TReadDirRes v9fs_treaddir(TReadDirOpt);
474 void v9fs_rreaddir(P9Req *req, uint32_t *count, uint32_t *nentries,
475                    struct V9fsDirent **entries);
476 void v9fs_free_dirents(struct V9fsDirent *e);
477 TLOpenRes v9fs_tlopen(TLOpenOpt);
478 void v9fs_rlopen(P9Req *req, v9fs_qid *qid, uint32_t *iounit);
479 TWriteRes v9fs_twrite(TWriteOpt);
480 void v9fs_rwrite(P9Req *req, uint32_t *count);
481 TFlushRes v9fs_tflush(TFlushOpt);
482 void v9fs_rflush(P9Req *req);
483 TMkdirRes v9fs_tmkdir(TMkdirOpt);
484 void v9fs_rmkdir(P9Req *req, v9fs_qid *qid);
485 TlcreateRes v9fs_tlcreate(TlcreateOpt);
486 void v9fs_rlcreate(P9Req *req, v9fs_qid *qid, uint32_t *iounit);
487 TsymlinkRes v9fs_tsymlink(TsymlinkOpt);
488 void v9fs_rsymlink(P9Req *req, v9fs_qid *qid);
489 TlinkRes v9fs_tlink(TlinkOpt);
490 void v9fs_rlink(P9Req *req);
491 TunlinkatRes v9fs_tunlinkat(TunlinkatOpt);
492 void v9fs_runlinkat(P9Req *req);
493 
494 #endif
495