1*63a7cdaaSuwe /* $NetBSD: fs.c,v 1.11 2020/05/28 14:00:05 uwe Exp $ */
2e73a712fSpooka
3e73a712fSpooka /*
4e73a712fSpooka * Copyright (c) 2007 Antti Kantee. All Rights Reserved.
5e73a712fSpooka *
6e73a712fSpooka * Redistribution and use in source and binary forms, with or without
7e73a712fSpooka * modification, are permitted provided that the following conditions
8e73a712fSpooka * are met:
9e73a712fSpooka * 1. Redistributions of source code must retain the above copyright
10e73a712fSpooka * notice, this list of conditions and the following disclaimer.
11e73a712fSpooka * 2. Redistributions in binary form must reproduce the above copyright
12e73a712fSpooka * notice, this list of conditions and the following disclaimer in the
13e73a712fSpooka * documentation and/or other materials provided with the distribution.
14e73a712fSpooka *
15e73a712fSpooka * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
16e73a712fSpooka * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17e73a712fSpooka * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18e73a712fSpooka * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19e73a712fSpooka * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20e73a712fSpooka * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21e73a712fSpooka * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22e73a712fSpooka * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23e73a712fSpooka * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24e73a712fSpooka * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25e73a712fSpooka * SUCH DAMAGE.
26e73a712fSpooka */
27e73a712fSpooka
28e73a712fSpooka #include <sys/cdefs.h>
29e73a712fSpooka #ifndef lint
30*63a7cdaaSuwe __RCSID("$NetBSD: fs.c,v 1.11 2020/05/28 14:00:05 uwe Exp $");
31e73a712fSpooka #endif /* !lint */
32e73a712fSpooka
3390ba17c1Spooka #include <assert.h>
34e73a712fSpooka #include <err.h>
35e73a712fSpooka #include <errno.h>
36e73a712fSpooka #include <puffs.h>
37e73a712fSpooka #include <signal.h>
38e73a712fSpooka #include <stdio.h>
39e73a712fSpooka #include <stdlib.h>
40e73a712fSpooka #include <unistd.h>
41e73a712fSpooka
42e73a712fSpooka #include "ninepuffs.h"
43e73a712fSpooka #include "nineproto.h"
44e73a712fSpooka
450e7bdfc1Spooka #define DO_IO(fname, a1, a2, a3, a4, rv) \
460e7bdfc1Spooka puffs_framebuf_seekset(a2, 0); \
470e7bdfc1Spooka *(a4) = 0; \
480e7bdfc1Spooka rv = fname(a1, a2, a3, a4); \
4933c01d32Smrg if (rv) errx(1, "p9p_handshake io failed %d, %d", rv, *a4)
500e7bdfc1Spooka
51e674e58bSozaki-r static const char *
p9p_ver2str(int version)52e674e58bSozaki-r p9p_ver2str(int version)
53e674e58bSozaki-r {
54e674e58bSozaki-r
55e674e58bSozaki-r switch (version) {
56e674e58bSozaki-r case P9PROTO_VERSION: return P9PROTO_VERSTR;
57e674e58bSozaki-r case P9PROTO_VERSION_U: return P9PROTO_VERSTR_U;
58e674e58bSozaki-r }
59e674e58bSozaki-r return NULL;
60e674e58bSozaki-r }
61e674e58bSozaki-r
62e73a712fSpooka struct puffs_node *
p9p_handshake(struct puffs_usermount * pu,const char * username,const char * path)6390ba17c1Spooka p9p_handshake(struct puffs_usermount *pu,
6490ba17c1Spooka const char *username, const char *path)
65e73a712fSpooka {
66e73a712fSpooka struct puffs9p *p9p = puffs_getspecific(pu);
670e7bdfc1Spooka struct puffs_framebuf *pb;
68e73a712fSpooka struct puffs_node *pn;
69e73a712fSpooka struct vattr rootva;
70e73a712fSpooka uint32_t maxreq;
71e73a712fSpooka uint16_t dummy;
720e7bdfc1Spooka p9ptag_t tagid, rtagid;
7390ba17c1Spooka p9pfid_t curfid;
7490ba17c1Spooka const char *p;
750e7bdfc1Spooka uint8_t type;
7690ba17c1Spooka int rv, done, x = 1, ncomp;
77e674e58bSozaki-r uint16_t strsize;
78e674e58bSozaki-r char *str;
79e73a712fSpooka
80e73a712fSpooka /* send initial handshake */
810e7bdfc1Spooka pb = p9pbuf_makeout();
82e73a712fSpooka p9pbuf_put_1(pb, P9PROTO_T_VERSION);
83e73a712fSpooka p9pbuf_put_2(pb, P9PROTO_NOTAG);
84e73a712fSpooka p9pbuf_put_4(pb, p9p->maxreq);
85e674e58bSozaki-r p9pbuf_put_str(pb, p9p_ver2str(p9p->protover));
860e7bdfc1Spooka DO_IO(p9pbuf_write, pu, pb, p9p->servsock, &done, rv);
87e73a712fSpooka
880e7bdfc1Spooka puffs_framebuf_recycle(pb);
890e7bdfc1Spooka DO_IO(p9pbuf_read, pu, pb, p9p->servsock, &done, rv);
90e73a712fSpooka
910e7bdfc1Spooka if ((type = p9pbuf_get_type(pb)) != P9PROTO_R_VERSION)
920e7bdfc1Spooka errx(1, "server invalid response to Tversion: %d", type);
930e7bdfc1Spooka if ((rtagid = p9pbuf_get_tag(pb)) != P9PROTO_NOTAG) {
9490ba17c1Spooka errx(1, "server invalid tag: %d vs. %d",
95a2b224daSpooka P9PROTO_NOTAG, rtagid);
96e73a712fSpooka return NULL;
97e73a712fSpooka }
980e7bdfc1Spooka if (p9pbuf_get_4(pb, &maxreq))
990e7bdfc1Spooka errx(1, "server invalid response: no request length");
1000e7bdfc1Spooka if (maxreq < P9P_MINREQLEN)
1010e7bdfc1Spooka errx(1, "server request length below minimum accepted: "
1020e7bdfc1Spooka "%d vs. %d", P9P_MINREQLEN, maxreq);
103e73a712fSpooka p9p->maxreq = maxreq;
104e73a712fSpooka
105e674e58bSozaki-r if (p9pbuf_get_str(pb, &str, &strsize))
106e674e58bSozaki-r errx(1, "server invalid response: no version");
107e674e58bSozaki-r if (strncmp(str, p9p_ver2str(p9p->protover), P9PROTO_VERSTR_MAXLEN) != 0) {
108e674e58bSozaki-r errx(1, "server doesn't support %s", p9p_ver2str(p9p->protover));
109e674e58bSozaki-r /* Should downgrade from 9P2000.u to 9P2000 if the server request? */
110e674e58bSozaki-r }
111e674e58bSozaki-r
112e73a712fSpooka /* build attach message */
1130e7bdfc1Spooka p9pbuf_recycleout(pb);
114e73a712fSpooka tagid = NEXTTAG(p9p);
115e73a712fSpooka p9pbuf_put_1(pb, P9PROTO_T_ATTACH);
116e73a712fSpooka p9pbuf_put_2(pb, tagid);
117e73a712fSpooka p9pbuf_put_4(pb, P9P_ROOTFID);
118e73a712fSpooka p9pbuf_put_4(pb, P9PROTO_NOFID);
119e73a712fSpooka p9pbuf_put_str(pb, username);
120e73a712fSpooka p9pbuf_put_str(pb, "");
121e674e58bSozaki-r if (p9p->protover == P9PROTO_VERSION_U)
122e674e58bSozaki-r p9pbuf_put_4(pb, P9PROTO_NUNAME_UNSPECIFIED); /* n_uname[4] */
1230e7bdfc1Spooka DO_IO(p9pbuf_write, pu, pb, p9p->servsock, &done, rv);
124e73a712fSpooka
1250e7bdfc1Spooka puffs_framebuf_recycle(pb);
1260e7bdfc1Spooka DO_IO(p9pbuf_read, pu, pb, p9p->servsock, &done, rv);
127e73a712fSpooka
1280e7bdfc1Spooka if ((type = p9pbuf_get_type(pb)) != P9PROTO_R_ATTACH)
1290e7bdfc1Spooka errx(1, "Rattach not received, got %d", type);
1300e7bdfc1Spooka if ((rtagid = p9pbuf_get_tag(pb)) != tagid)
13190ba17c1Spooka errx(1, "server invalid tag: %d vs. %d", tagid, rtagid);
132e73a712fSpooka
13390ba17c1Spooka /* just walk away rootfid, you won't see me follow you back home */
13490ba17c1Spooka
13590ba17c1Spooka #define EATSLASH(p) while (*(p) == '/') p++
13690ba17c1Spooka assert(*path == '/');
13790ba17c1Spooka p = path;
13890ba17c1Spooka EATSLASH(p);
13990ba17c1Spooka for (ncomp = 0; p && *p; ncomp++) {
14090ba17c1Spooka EATSLASH(p);
14190ba17c1Spooka if (!*p)
14290ba17c1Spooka break;
14390ba17c1Spooka p = strchr(p, '/');
14490ba17c1Spooka }
14590ba17c1Spooka
14690ba17c1Spooka if (ncomp == 0) {
14790ba17c1Spooka curfid = P9P_ROOTFID;
14890ba17c1Spooka } else {
14990ba17c1Spooka uint16_t walked;
15090ba17c1Spooka
15190ba17c1Spooka p9pbuf_recycleout(pb);
15290ba17c1Spooka tagid = NEXTTAG(p9p);
15390ba17c1Spooka curfid = NEXTFID(p9p);
15490ba17c1Spooka p9pbuf_put_1(pb, P9PROTO_T_WALK);
15590ba17c1Spooka p9pbuf_put_2(pb, tagid);
15690ba17c1Spooka p9pbuf_put_4(pb, P9P_ROOTFID);
15790ba17c1Spooka p9pbuf_put_4(pb, curfid);
15890ba17c1Spooka p9pbuf_put_2(pb, ncomp);
15990ba17c1Spooka
16090ba17c1Spooka p = path;
16190ba17c1Spooka while (p && *p) {
16290ba17c1Spooka char *p2;
16390ba17c1Spooka
16490ba17c1Spooka EATSLASH(p);
16590ba17c1Spooka if (!*p)
16690ba17c1Spooka break;
16790ba17c1Spooka if ((p2 = strchr(p, '/')) == NULL)
16890ba17c1Spooka p2 = strchr(p, '\0');
16990ba17c1Spooka p9pbuf_put_data(pb, p, p2-p);
17090ba17c1Spooka p = p2;
17190ba17c1Spooka }
17290ba17c1Spooka
17390ba17c1Spooka DO_IO(p9pbuf_write, pu, pb, p9p->servsock, &done, rv);
17490ba17c1Spooka
17590ba17c1Spooka puffs_framebuf_recycle(pb);
17690ba17c1Spooka DO_IO(p9pbuf_read, pu, pb, p9p->servsock, &done, rv);
17790ba17c1Spooka
17890ba17c1Spooka if ((type = p9pbuf_get_type(pb)) != P9PROTO_R_WALK)
17990ba17c1Spooka errx(1, "Rwalk not received for rnode, got %d", type);
18090ba17c1Spooka if ((rtagid = p9pbuf_get_tag(pb)) != tagid)
18190ba17c1Spooka errx(1, "server invalid tag: %d vs. %d",
18290ba17c1Spooka tagid, rtagid);
18390ba17c1Spooka if (p9pbuf_get_2(pb, &walked) == -1)
18490ba17c1Spooka errx(1, "can't get number of walked qids");
18590ba17c1Spooka if (walked != ncomp)
18690ba17c1Spooka errx(1, "can't locate rootpath %s, only %d/%d "
18790ba17c1Spooka "components found", path, walked, ncomp);
18890ba17c1Spooka
18990ba17c1Spooka /* curfid is alive, clunk P9P_ROOTFID */
19090ba17c1Spooka p9pbuf_recycleout(pb);
19190ba17c1Spooka tagid = NEXTTAG(p9p);
19290ba17c1Spooka p9pbuf_put_1(pb, P9PROTO_T_CLUNK);
19390ba17c1Spooka p9pbuf_put_2(pb, tagid);
19490ba17c1Spooka p9pbuf_put_4(pb, P9P_ROOTFID);
19590ba17c1Spooka
19690ba17c1Spooka DO_IO(p9pbuf_write, pu, pb, p9p->servsock, &done, rv);
19790ba17c1Spooka puffs_framebuf_recycle(pb);
19890ba17c1Spooka DO_IO(p9pbuf_read, pu, pb, p9p->servsock, &done, rv);
19990ba17c1Spooka /* wedontcare */
20090ba17c1Spooka }
20190ba17c1Spooka
20290ba17c1Spooka /* finally, stat the node */
2030e7bdfc1Spooka p9pbuf_recycleout(pb);
204e73a712fSpooka tagid = NEXTTAG(p9p);
205e73a712fSpooka p9pbuf_put_1(pb, P9PROTO_T_STAT);
206e73a712fSpooka p9pbuf_put_2(pb, tagid);
20790ba17c1Spooka p9pbuf_put_4(pb, curfid);
2080e7bdfc1Spooka DO_IO(p9pbuf_write, pu, pb, p9p->servsock, &done, rv);
209e73a712fSpooka
2100e7bdfc1Spooka puffs_framebuf_recycle(pb);
2110e7bdfc1Spooka DO_IO(p9pbuf_read, pu, pb, p9p->servsock, &done, rv);
212e73a712fSpooka
2130e7bdfc1Spooka if ((type = p9pbuf_get_type(pb)) != P9PROTO_R_STAT)
2140e7bdfc1Spooka errx(1, "Rstat not received, got %d", type);
2150e7bdfc1Spooka if ((rtagid = p9pbuf_get_tag(pb)) != tagid)
21690ba17c1Spooka errx(1, "server invalid tag: %d vs. %d", tagid, rtagid);
2170e7bdfc1Spooka if (p9pbuf_get_2(pb, &dummy))
2180e7bdfc1Spooka errx(1, "couldn't get stat len parameter");
219e674e58bSozaki-r if (proto_getstat(pu, pb, &rootva, NULL, NULL))
2200e7bdfc1Spooka errx(1, "could not parse root attributes");
2210e7bdfc1Spooka puffs_framebuf_destroy(pb);
222e73a712fSpooka
223e73a712fSpooka rootva.va_nlink = 0156; /* guess, will be fixed with first readdir */
22490ba17c1Spooka pn = newp9pnode_va(pu, &rootva, curfid);
225e73a712fSpooka
2260e7bdfc1Spooka if (ioctl(p9p->servsock, FIONBIO, &x) == -1)
2270e7bdfc1Spooka err(1, "cannot set socket in nonblocking mode");
228e73a712fSpooka
229e73a712fSpooka return pn;
230e73a712fSpooka }
231e73a712fSpooka
232e73a712fSpooka int
puffs9p_fs_unmount(struct puffs_usermount * pu,int flags)23321913eabSpooka puffs9p_fs_unmount(struct puffs_usermount *pu, int flags)
234e73a712fSpooka {
235e73a712fSpooka struct puffs9p *p9p = puffs_getspecific(pu);
236e73a712fSpooka
237e73a712fSpooka close(p9p->servsock);
238e73a712fSpooka return 0;
239e73a712fSpooka }
240