1 /* $NetBSD: nineproto.c,v 1.9 2007/11/30 19:02:38 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.9 2007/11/30 19:02:38 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 puffs_framebuf *pb, struct qid9p *qid) 47 { 48 49 if (puffs_framebuf_remaining(pb) < 1+4+8) 50 return ENOBUFS; 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 0; 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 EPROTO; \ 110 if ((rv = (a(pb, b)))) return rv; \ 111 size -= unitsize; \ 112 } while (/*CONSTCOND*/0) 113 #define GETSTR(val,strsize) \ 114 do { \ 115 if ((rv = p9pbuf_get_str(pb, val, strsize))) return rv; \ 116 if (*strsize > size) return EPROTO; \ 117 size -= *strsize; \ 118 } while (/*CONSTCOND*/0) 119 int 120 proto_getstat(struct puffs_framebuf *pb, struct vattr *vap, 121 char **name, uint16_t *rs) 122 { 123 char *uid, *gid; 124 struct qid9p qid; 125 uint64_t flen; 126 uint32_t rdev, mode, atime, mtime; 127 uint16_t size, v16; 128 int rv; 129 130 /* check size */ 131 if ((rv = p9pbuf_get_2(pb, &size))) 132 return rv; 133 if (puffs_framebuf_remaining(pb) < size) 134 return ENOBUFS; 135 136 if (rs) 137 *rs = size+2; /* compensate for size field itself */ 138 139 GETFIELD(p9pbuf_get_2, &v16, 2); 140 if (v16) 141 printf("%d\n", v16); 142 GETFIELD(p9pbuf_get_4, &rdev, 4); 143 GETFIELD(proto_getqid, &qid, 13); 144 GETFIELD(p9pbuf_get_4, &mode, 4); 145 GETFIELD(p9pbuf_get_4, &atime, 4); 146 GETFIELD(p9pbuf_get_4, &mtime, 4); 147 GETFIELD(p9pbuf_get_8, &flen, 8); 148 GETSTR(name, &v16); 149 GETSTR(&uid, &v16); 150 GETSTR(&gid, &v16); 151 152 if (rdev) 153 printf("%d\n", rdev); 154 vap->va_rdev = rdev; 155 vap->va_mode = mode & 0777; /* may contain other uninteresting bits */ 156 vap->va_atime.tv_sec = atime; 157 vap->va_mtime.tv_sec = mtime; 158 vap->va_ctime.tv_sec = mtime; 159 vap->va_atime.tv_nsec=vap->va_mtime.tv_nsec=vap->va_ctime.tv_nsec = 0; 160 vap->va_birthtime.tv_sec = vap->va_birthtime.tv_nsec = 0; 161 vap->va_size = vap->va_bytes = flen; 162 vap->va_uid = ustr2uid(uid); 163 vap->va_gid = gstr2gid(gid); 164 free(uid); 165 free(gid); 166 qid2vattr(vap, &qid); 167 168 /* some defaults */ 169 if (vap->va_type == VDIR) 170 vap->va_nlink = 1906; 171 else 172 vap->va_nlink = 1; 173 vap->va_blocksize = 512; 174 vap->va_flags = vap->va_vaflags = 0; 175 vap->va_filerev = PUFFS_VNOVAL; 176 177 /* muid, not used */ 178 GETSTR(NULL, &v16); 179 180 return 0; 181 } 182 183 int 184 proto_cc_dupfid(struct puffs_usermount *pu, p9pfid_t oldfid, p9pfid_t newfid) 185 { 186 struct puffs_cc *pcc = puffs_cc_getcc(pu); 187 struct puffs9p *p9p = puffs_getspecific(pu); 188 struct puffs_framebuf *pb; 189 p9ptag_t tag = NEXTTAG(p9p); 190 uint16_t qids; 191 int rv = 0; 192 193 pb = p9pbuf_makeout(); 194 p9pbuf_put_1(pb, P9PROTO_T_WALK); 195 p9pbuf_put_2(pb, tag); 196 p9pbuf_put_4(pb, oldfid); 197 p9pbuf_put_4(pb, newfid); 198 p9pbuf_put_2(pb, 0); 199 GETRESPONSE(pb); 200 201 rv = proto_expect_walk_nqids(pb, &qids); 202 if (rv == 0 && qids != 0) 203 rv = EPROTO; 204 205 out: 206 puffs_framebuf_destroy(pb); 207 return rv; 208 } 209 210 int 211 proto_cc_clunkfid(struct puffs_usermount *pu, p9pfid_t fid, int waitforit) 212 { 213 struct puffs_cc *pcc = puffs_cc_getcc(pu); 214 struct puffs9p *p9p = puffs_getspecific(pu); 215 struct puffs_framebuf *pb; 216 p9ptag_t tag = NEXTTAG(p9p); 217 int rv = 0; 218 219 pb = p9pbuf_makeout(); 220 p9pbuf_put_1(pb, P9PROTO_T_CLUNK); 221 p9pbuf_put_2(pb, tag); 222 p9pbuf_put_4(pb, fid); 223 224 if (waitforit) { 225 if (puffs_framev_enqueue_cc(pcc, p9p->servsock, pb, 0) == 0) { 226 if (p9pbuf_get_type(pb) != P9PROTO_R_CLUNK) 227 rv = EPROTO; 228 } else { 229 rv = errno; 230 } 231 puffs_framebuf_destroy(pb); 232 } else { 233 JUSTSEND(pb); 234 } 235 236 out: 237 return rv; 238 } 239 240 /* 241 * walk a new fid, then open it 242 */ 243 int 244 proto_cc_open(struct puffs_usermount *pu, p9pfid_t fid, 245 p9pfid_t newfid, int mode) 246 { 247 struct puffs_cc *pcc = puffs_cc_getcc(pu); 248 struct puffs9p *p9p = puffs_getspecific(pu); 249 struct puffs_framebuf *pb; 250 p9ptag_t tag = NEXTTAG(p9p); 251 int rv; 252 253 rv = proto_cc_dupfid(pu, fid, newfid); 254 if (rv) 255 return rv; 256 257 pb = p9pbuf_makeout(); 258 p9pbuf_put_1(pb, P9PROTO_T_OPEN); 259 p9pbuf_put_2(pb, tag); 260 p9pbuf_put_4(pb, newfid); 261 p9pbuf_put_1(pb, mode); 262 GETRESPONSE(pb); 263 if (p9pbuf_get_type(pb) != P9PROTO_R_OPEN) 264 rv = EPROTO; 265 266 out: 267 puffs_framebuf_destroy(pb); 268 return rv; 269 } 270 271 void 272 proto_make_stat(struct puffs_framebuf *pb, const struct vattr *vap, 273 const char *filename, enum vtype vt) 274 { 275 struct vattr fakeva; 276 uint32_t mode, atime, mtime; 277 uint64_t flen; 278 const char *owner, *group; 279 int startoff, curoff; 280 281 if (vap == NULL) { 282 puffs_vattr_null(&fakeva); 283 vap = &fakeva; 284 } 285 286 startoff = puffs_framebuf_telloff(pb); 287 puffs_framebuf_seekset(pb, startoff + 2+2); /* stat[n] incl. stat[2] */ 288 289 if (vap->va_mode != (mode_t)PUFFS_VNOVAL) 290 mode = vap->va_mode | (vt == VDIR ? P9PROTO_CPERM_DIR : 0); 291 else 292 mode = P9PROTO_STAT_NOVAL4; 293 if (vap->va_atime.tv_sec != (time_t)PUFFS_VNOVAL) 294 atime = vap->va_atime.tv_sec; 295 else 296 atime = P9PROTO_STAT_NOVAL4; 297 if (vap->va_mtime.tv_sec != (time_t)PUFFS_VNOVAL) 298 mtime = vap->va_mtime.tv_sec; 299 else 300 mtime = P9PROTO_STAT_NOVAL4; 301 if (vap->va_size != (u_quad_t)PUFFS_VNOVAL) 302 flen = vap->va_size; 303 else 304 flen = P9PROTO_STAT_NOVAL8; 305 if (vap->va_uid != (uid_t)PUFFS_VNOVAL) 306 owner = uid2ustr(vap->va_uid); 307 else 308 owner = ""; 309 if (vap->va_gid != (gid_t)PUFFS_VNOVAL) 310 group = gid2gstr(vap->va_gid); 311 else 312 group = ""; 313 314 p9pbuf_put_2(pb, P9PROTO_STAT_NOVAL2); /* kernel type */ 315 p9pbuf_put_4(pb, P9PROTO_STAT_NOVAL4); /* dev */ 316 p9pbuf_put_1(pb, P9PROTO_STAT_NOVAL1); /* type */ 317 p9pbuf_put_4(pb, P9PROTO_STAT_NOVAL4); /* version */ 318 p9pbuf_put_8(pb, P9PROTO_STAT_NOVAL8); /* path */ 319 p9pbuf_put_4(pb, mode); 320 p9pbuf_put_4(pb, atime); 321 p9pbuf_put_4(pb, mtime); 322 p9pbuf_put_8(pb, flen); 323 p9pbuf_put_str(pb, filename ? filename : ""); 324 p9pbuf_put_str(pb, owner); 325 p9pbuf_put_str(pb, group); 326 p9pbuf_put_str(pb, ""); /* muid */ 327 328 curoff = puffs_framebuf_telloff(pb); 329 puffs_framebuf_seekset(pb, startoff); 330 p9pbuf_put_2(pb, curoff-(startoff+2)); /* stat[n] size */ 331 p9pbuf_put_2(pb, curoff-(startoff+4)); /* size[2] stat */ 332 333 puffs_framebuf_seekset(pb, curoff); 334 } 335 336 int 337 proto_expect_walk_nqids(struct puffs_framebuf *pb, uint16_t *nqids) 338 { 339 340 if (p9pbuf_get_type(pb) != P9PROTO_R_WALK) 341 return EPROTO; 342 return p9pbuf_get_2(pb, nqids); 343 } 344 345 int 346 proto_expect_qid(struct puffs_framebuf *pb, uint8_t op, struct qid9p *qid) 347 { 348 349 if (p9pbuf_get_type(pb) != op) 350 return EPROTO; 351 return proto_getqid(pb, qid); 352 } 353 354 int 355 proto_expect_stat(struct puffs_framebuf *pb, struct vattr *va) 356 { 357 uint16_t dummy; 358 int rv; 359 360 if (p9pbuf_get_type(pb) != P9PROTO_R_STAT) 361 return EPROTO; 362 if ((rv = p9pbuf_get_2(pb, &dummy))) 363 return rv; 364 return proto_getstat(pb, va, NULL, NULL); 365 } 366