1 /* $NetBSD: nineproto.c,v 1.8 2007/07/07 21:14:28 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.8 2007/07/07 21:14:28 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_cc *pcc, p9pfid_t oldfid, p9pfid_t newfid) 185 { 186 struct puffs9p *p9p = puffs_cc_getspecific(pcc); 187 struct puffs_framebuf *pb; 188 p9ptag_t tag = NEXTTAG(p9p); 189 uint16_t qids; 190 int rv = 0; 191 192 pb = p9pbuf_makeout(); 193 p9pbuf_put_1(pb, P9PROTO_T_WALK); 194 p9pbuf_put_2(pb, tag); 195 p9pbuf_put_4(pb, oldfid); 196 p9pbuf_put_4(pb, newfid); 197 p9pbuf_put_2(pb, 0); 198 GETRESPONSE(pb); 199 200 rv = proto_expect_walk_nqids(pb, &qids); 201 if (rv == 0 && qids != 0) 202 rv = EPROTO; 203 204 out: 205 puffs_framebuf_destroy(pb); 206 return rv; 207 } 208 209 int 210 proto_cc_clunkfid(struct puffs_cc *pcc, p9pfid_t fid, int waitforit) 211 { 212 struct puffs_usermount *pu = puffs_cc_getusermount(pcc); 213 struct puffs9p *p9p = puffs_cc_getspecific(pcc); 214 struct puffs_framebuf *pb; 215 p9ptag_t tag = NEXTTAG(p9p); 216 int rv = 0; 217 218 pb = p9pbuf_makeout(); 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 if (puffs_framev_enqueue_cc(pcc, p9p->servsock, pb, 0) == 0) { 225 if (p9pbuf_get_type(pb) != P9PROTO_R_CLUNK) 226 rv = EPROTO; 227 } else { 228 rv = errno; 229 } 230 puffs_framebuf_destroy(pb); 231 } else { 232 JUSTSEND(pb); 233 } 234 235 out: 236 return rv; 237 } 238 239 /* 240 * walk a new fid, then open it 241 */ 242 int 243 proto_cc_open(struct puffs_cc *pcc, p9pfid_t fid, p9pfid_t newfid, int mode) 244 { 245 struct puffs9p *p9p = puffs_cc_getspecific(pcc); 246 struct puffs_framebuf *pb; 247 p9ptag_t tag = NEXTTAG(p9p); 248 int rv; 249 250 rv = proto_cc_dupfid(pcc, fid, newfid); 251 if (rv) 252 return rv; 253 254 pb = p9pbuf_makeout(); 255 p9pbuf_put_1(pb, P9PROTO_T_OPEN); 256 p9pbuf_put_2(pb, tag); 257 p9pbuf_put_4(pb, newfid); 258 p9pbuf_put_1(pb, mode); 259 GETRESPONSE(pb); 260 if (p9pbuf_get_type(pb) != P9PROTO_R_OPEN) 261 rv = EPROTO; 262 263 out: 264 puffs_framebuf_destroy(pb); 265 return rv; 266 } 267 268 void 269 proto_make_stat(struct puffs_framebuf *pb, const struct vattr *vap, 270 const char *filename, enum vtype vt) 271 { 272 struct vattr fakeva; 273 uint32_t mode, atime, mtime; 274 uint64_t flen; 275 const char *owner, *group; 276 int startoff, curoff; 277 278 if (vap == NULL) { 279 puffs_vattr_null(&fakeva); 280 vap = &fakeva; 281 } 282 283 startoff = puffs_framebuf_telloff(pb); 284 puffs_framebuf_seekset(pb, startoff + 2+2); /* stat[n] incl. stat[2] */ 285 286 if (vap->va_mode != (mode_t)PUFFS_VNOVAL) 287 mode = vap->va_mode | (vt == VDIR ? P9PROTO_CPERM_DIR : 0); 288 else 289 mode = P9PROTO_STAT_NOVAL4; 290 if (vap->va_atime.tv_sec != (time_t)PUFFS_VNOVAL) 291 atime = vap->va_atime.tv_sec; 292 else 293 atime = P9PROTO_STAT_NOVAL4; 294 if (vap->va_mtime.tv_sec != (time_t)PUFFS_VNOVAL) 295 mtime = vap->va_mtime.tv_sec; 296 else 297 mtime = P9PROTO_STAT_NOVAL4; 298 if (vap->va_size != (u_quad_t)PUFFS_VNOVAL) 299 flen = vap->va_size; 300 else 301 flen = P9PROTO_STAT_NOVAL8; 302 if (vap->va_uid != (uid_t)PUFFS_VNOVAL) 303 owner = uid2ustr(vap->va_uid); 304 else 305 owner = ""; 306 if (vap->va_gid != (gid_t)PUFFS_VNOVAL) 307 group = gid2gstr(vap->va_gid); 308 else 309 group = ""; 310 311 p9pbuf_put_2(pb, P9PROTO_STAT_NOVAL2); /* kernel type */ 312 p9pbuf_put_4(pb, P9PROTO_STAT_NOVAL4); /* dev */ 313 p9pbuf_put_1(pb, P9PROTO_STAT_NOVAL1); /* type */ 314 p9pbuf_put_4(pb, P9PROTO_STAT_NOVAL4); /* version */ 315 p9pbuf_put_8(pb, P9PROTO_STAT_NOVAL8); /* path */ 316 p9pbuf_put_4(pb, mode); 317 p9pbuf_put_4(pb, atime); 318 p9pbuf_put_4(pb, mtime); 319 p9pbuf_put_8(pb, flen); 320 p9pbuf_put_str(pb, filename ? filename : ""); 321 p9pbuf_put_str(pb, owner); 322 p9pbuf_put_str(pb, group); 323 p9pbuf_put_str(pb, ""); /* muid */ 324 325 curoff = puffs_framebuf_telloff(pb); 326 puffs_framebuf_seekset(pb, startoff); 327 p9pbuf_put_2(pb, curoff-(startoff+2)); /* stat[n] size */ 328 p9pbuf_put_2(pb, curoff-(startoff+4)); /* size[2] stat */ 329 330 puffs_framebuf_seekset(pb, curoff); 331 } 332 333 int 334 proto_expect_walk_nqids(struct puffs_framebuf *pb, uint16_t *nqids) 335 { 336 337 if (p9pbuf_get_type(pb) != P9PROTO_R_WALK) 338 return EPROTO; 339 return p9pbuf_get_2(pb, nqids); 340 } 341 342 int 343 proto_expect_qid(struct puffs_framebuf *pb, uint8_t op, struct qid9p *qid) 344 { 345 346 if (p9pbuf_get_type(pb) != op) 347 return EPROTO; 348 return proto_getqid(pb, qid); 349 } 350 351 int 352 proto_expect_stat(struct puffs_framebuf *pb, struct vattr *va) 353 { 354 uint16_t dummy; 355 int rv; 356 357 if (p9pbuf_get_type(pb) != P9PROTO_R_STAT) 358 return EPROTO; 359 if ((rv = p9pbuf_get_2(pb, &dummy))) 360 return rv; 361 return proto_getstat(pb, va, NULL, NULL); 362 } 363