nineproto.c revision 1.2 1 /* $NetBSD: nineproto.c,v 1.2 2007/05/04 18:12:25 pooka Exp $ */
2
3 /*
4 * Copyright (c) 2007 Antti Kantee. All Rights Reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
16 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27
28 #include <sys/cdefs.h>
29 #ifndef lint
30 __RCSID("$NetBSD: nineproto.c,v 1.2 2007/05/04 18:12:25 pooka Exp $");
31 #endif /* !lint */
32
33 #include <sys/types.h>
34
35 #include <errno.h>
36 #include <grp.h>
37 #include <pwd.h>
38 #include <puffs.h>
39 #include <stdio.h>
40 #include <stdlib.h>
41
42 #include "ninepuffs.h"
43 #include "nineproto.h"
44
45 int
46 proto_getqid(struct p9pbuf *pb, struct qid9p *qid)
47 {
48
49 if (pb->remain < 13)
50 return 0;
51
52 p9pbuf_get_1(pb, &qid->qidtype);
53 p9pbuf_get_4(pb, &qid->qidvers);
54 p9pbuf_get_8(pb, &qid->qidpath);
55
56 return 1;
57 }
58
59 static uid_t
60 ustr2uid(char *uid)
61 {
62 struct passwd *pw;
63
64 pw = getpwnam(uid);
65 if (pw == NULL)
66 return 0; /* XXXXX */
67
68 return pw->pw_uid;
69 }
70
71 static gid_t
72 gstr2gid(char *gid)
73 {
74 struct group *grr;
75
76 grr = getgrnam(gid);
77 if (grr == NULL)
78 return 0; /* more XXXX */
79
80 return grr->gr_gid;
81 }
82
83 static const char *
84 uid2ustr(uid_t uid)
85 {
86 struct passwd *pw;
87
88 pw = getpwuid(uid);
89 if (pw == NULL)
90 return "root"; /* XXXXX */
91
92 return pw->pw_name;
93 }
94
95 static const char *
96 gid2gstr(gid_t gid)
97 {
98 struct group *grr;
99
100 grr = getgrgid(gid);
101 if (grr == NULL)
102 return "wheel"; /* XXXXXX */
103
104 return grr->gr_name;
105 }
106
107 #define GETFIELD(a,b,unitsize) \
108 do { \
109 if (size < unitsize) return 0; \
110 if (!(a(pb, b))) return 0; \
111 size -= unitsize; \
112 } while (/*CONSTCOND*/0)
113 #define GETSTR(val,strsize) \
114 do { \
115 if (!(p9pbuf_get_str(pb, val, strsize))) return 0; \
116 if (*strsize > size) return 0; \
117 size -= *strsize; \
118 } while (/*CONSTCOND*/0)
119 int
120 proto_getstat(struct p9pbuf *pb, struct vattr *vap, char **name, uint16_t *rs)
121 {
122 char *uid, *gid;
123 struct qid9p qid;
124 uint64_t flen;
125 uint32_t rdev, mode, atime, mtime;
126 uint16_t size, v16;
127
128 /* check size */
129 if (!p9pbuf_get_2(pb, &size))
130 return 0;
131 if (p9pbuf_remaining(pb) < size)
132 return 0;
133
134 if (rs)
135 *rs = size+2; /* compensate for size field itself */
136
137 GETFIELD(p9pbuf_get_2, &v16, 2);
138 if (v16)
139 printf("%d\n", v16);
140 GETFIELD(p9pbuf_get_4, &rdev, 4);
141 GETFIELD(proto_getqid, &qid, 13);
142 GETFIELD(p9pbuf_get_4, &mode, 4);
143 GETFIELD(p9pbuf_get_4, &atime, 4);
144 GETFIELD(p9pbuf_get_4, &mtime, 4);
145 GETFIELD(p9pbuf_get_8, &flen, 8);
146 GETSTR(name, &v16);
147 GETSTR(&uid, &v16);
148 GETSTR(&gid, &v16);
149
150 if (rdev)
151 printf("%d\n", rdev);
152 vap->va_rdev = rdev;
153 vap->va_mode = mode & 0777; /* may contain other uninteresting bits */
154 vap->va_atime.tv_sec = atime;
155 vap->va_mtime.tv_sec = mtime;
156 vap->va_ctime.tv_sec = mtime;
157 vap->va_atime.tv_nsec=vap->va_mtime.tv_nsec=vap->va_ctime.tv_nsec = 0;
158 vap->va_birthtime.tv_sec = vap->va_birthtime.tv_nsec = 0;
159 vap->va_size = vap->va_bytes = flen;
160 vap->va_uid = ustr2uid(uid);
161 vap->va_gid = gstr2gid(gid);
162 free(uid);
163 free(gid);
164 qid2vattr(vap, &qid);
165
166 /* some defaults */
167 if (vap->va_type == VDIR)
168 vap->va_nlink = 1906;
169 else
170 vap->va_nlink = 1;
171 vap->va_blocksize = 512;
172 vap->va_flags = vap->va_vaflags = 0;
173 vap->va_filerev = PUFFS_VNOVAL;
174
175 /* muid, not used */
176 GETSTR(NULL, &v16);
177
178 return 1;
179 }
180
181 int
182 proto_cc_dupfid(struct puffs_cc *pcc, p9pfid_t oldfid, p9pfid_t newfid)
183 {
184 struct puffs9p *p9p = puffs_cc_getspecific(pcc);
185 struct p9pbuf *pb;
186 p9ptag_t tag = NEXTTAG(p9p);
187 uint16_t qids;
188 int rv, error = 0;
189
190 pb = p9pbuf_make(p9p->maxreq, P9PB_OUT);
191 p9pbuf_put_1(pb, P9PROTO_T_WALK);
192 p9pbuf_put_2(pb, tag);
193 p9pbuf_put_4(pb, oldfid);
194 p9pbuf_put_4(pb, newfid);
195 p9pbuf_put_2(pb, 0);
196
197 outbuf_enqueue(p9p, pb, pcc, tag);
198 puffs_cc_yield(pcc);
199
200 rv = proto_expect_walk_nqids(pb, &qids);
201 if (rv)
202 error = rv;
203 if (qids != 0)
204 error = EPROTO;
205
206 p9pbuf_destroy(pb);
207 return error;
208 }
209
210 int
211 proto_cc_clunkfid(struct puffs_cc *pcc, p9pfid_t fid, int waitforit)
212 {
213 struct puffs9p *p9p = puffs_cc_getspecific(pcc);
214 struct p9pbuf *pb;
215 p9ptag_t tag = NEXTTAG(p9p);
216 int error = 0;
217
218 pb = p9pbuf_make(p9p->maxreq, P9PB_OUT);
219 p9pbuf_put_1(pb, P9PROTO_T_CLUNK);
220 p9pbuf_put_2(pb, tag);
221 p9pbuf_put_4(pb, fid);
222
223 if (waitforit) {
224 outbuf_enqueue(p9p, pb, pcc, tag);
225 puffs_cc_yield(pcc);
226 if (pb->type != P9PROTO_R_CLUNK)
227 error = EPROTO;
228 p9pbuf_destroy(pb);
229 } else {
230 outbuf_enqueue_nocc(p9p, pb, NULL, NULL, tag);
231 }
232
233 return error;
234 }
235
236 /*
237 * walk a new fid, then open it
238 */
239 int
240 proto_cc_open(struct puffs_cc *pcc, p9pfid_t fid, p9pfid_t newfid, int mode)
241 {
242 struct puffs9p *p9p = puffs_cc_getspecific(pcc);
243 struct p9pbuf *pb;
244 p9ptag_t tag = NEXTTAG(p9p);
245 int error;
246
247 error = proto_cc_dupfid(pcc, fid, newfid);
248 if (error)
249 return error;
250
251 pb = p9pbuf_make(p9p->maxreq, P9PB_OUT);
252 p9pbuf_put_1(pb, P9PROTO_T_OPEN);
253 p9pbuf_put_2(pb, tag);
254 p9pbuf_put_4(pb, newfid);
255 p9pbuf_put_1(pb, mode);
256 outbuf_enqueue(p9p, pb, pcc, tag);
257 puffs_cc_yield(pcc);
258 if (pb->type != P9PROTO_R_OPEN)
259 error = EPROTO;
260
261 p9pbuf_destroy(pb);
262 return error;
263 }
264
265 void
266 proto_make_stat(struct p9pbuf *pb, const struct vattr *vap,
267 const char *filename)
268 {
269 struct vattr fakeva;
270 uint32_t mode, atime, mtime;
271 uint64_t flen;
272 const char *owner, *group;
273 int startoff, curoff;
274
275 if (vap == NULL) {
276 puffs_vattr_null(&fakeva);
277 vap = &fakeva;
278 }
279
280 startoff = p9pbuf_tell(pb);
281 p9pbuf_seekset(pb, startoff + 2 + 2); /* stat[n], containing stat[2] */
282
283 if (vap->va_mode != (mode_t)PUFFS_VNOVAL)
284 mode = vap->va_mode;
285 else
286 mode = P9PROTO_STAT_NOVAL4;
287 if (vap->va_atime.tv_sec != (time_t)PUFFS_VNOVAL)
288 atime = vap->va_atime.tv_sec;
289 else
290 atime = P9PROTO_STAT_NOVAL4;
291 if (vap->va_mtime.tv_sec != (time_t)PUFFS_VNOVAL)
292 mtime = vap->va_mtime.tv_sec;
293 else
294 mtime = P9PROTO_STAT_NOVAL4;
295 if (vap->va_size != (u_quad_t)PUFFS_VNOVAL)
296 flen = vap->va_size;
297 else
298 flen = P9PROTO_STAT_NOVAL8;
299 if (vap->va_uid != (uid_t)PUFFS_VNOVAL)
300 owner = uid2ustr(vap->va_uid);
301 else
302 owner = "";
303 if (vap->va_gid != (gid_t)PUFFS_VNOVAL)
304 group = gid2gstr(vap->va_gid);
305 else
306 group = "";
307
308 p9pbuf_put_2(pb, P9PROTO_STAT_NOVAL2); /* kernel type */
309 p9pbuf_put_4(pb, P9PROTO_STAT_NOVAL4); /* dev */
310 p9pbuf_put_1(pb, P9PROTO_STAT_NOVAL1); /* type */
311 p9pbuf_put_4(pb, P9PROTO_STAT_NOVAL4); /* version */
312 p9pbuf_put_8(pb, P9PROTO_STAT_NOVAL8); /* path */
313 p9pbuf_put_4(pb, mode);
314 p9pbuf_put_4(pb, atime);
315 p9pbuf_put_4(pb, mtime);
316 p9pbuf_put_8(pb, flen);
317 p9pbuf_put_str(pb, filename ? filename : "");
318 p9pbuf_put_str(pb, owner);
319 p9pbuf_put_str(pb, group);
320 p9pbuf_put_str(pb, ""); /* muid */
321
322 curoff = p9pbuf_tell(pb);
323 p9pbuf_seekset(pb, startoff);
324 p9pbuf_put_2(pb, curoff-(startoff+2)); /* stat[n] size */
325 p9pbuf_put_2(pb, curoff-(startoff+4)); /* size[2] stat */
326
327 p9pbuf_seekset(pb, curoff);
328 }
329
330 int
331 proto_expect_walk_nqids(struct p9pbuf *pb, uint16_t *nqids)
332 {
333
334 if (pb->type != P9PROTO_R_WALK)
335 return EPROTO;
336 if (!p9pbuf_get_2(pb, nqids))
337 return EPROTO;
338
339 return 0;
340 }
341
342 int
343 proto_expect_qid(struct p9pbuf *pb, uint8_t op, struct qid9p *qid)
344 {
345
346 if (pb->type != op)
347 return EPROTO;
348 if (!proto_getqid(pb, qid))
349 return EPROTO;
350
351 return 0;
352 }
353
354 int
355 proto_expect_stat(struct p9pbuf *pb, struct vattr *va)
356 {
357 uint16_t dummy;
358
359 if (pb->type != P9PROTO_R_STAT)
360 return EPROTO;
361 if (!p9pbuf_get_2(pb, &dummy))
362 return EPROTO;
363 if (!proto_getstat(pb, va, NULL, NULL))
364 return EPROTO;
365
366 return 0;
367 }
368