void conn_write_dispatch(int fd, short event, void *arg) { struct connection *c = arg; ssize_t n; int error; socklen_t len; if (!(event & EV_WRITE)) { log_debug("spurious write call"); return; } switch (c->state) { case CONN_XPT_WAIT: len = sizeof(error); if (getsockopt(c->fd, SOL_SOCKET, SO_ERROR, &error, &len) == -1 || (errno = error)) { log_warn("connect to %s failed", log_sockaddr(&c->config.TargetAddr)); conn_fsm(c, CONN_EV_FAIL); return; } conn_fsm(c, CONN_EV_CONNECTED); break; default: if ((n = pdu_write(c)) == -1) { log_warn("pdu_write"); conn_fsm(c, CONN_EV_FAIL); return; } if (n == 0) { /* connection closed */ conn_fsm(c, CONN_EV_CLOSED); return; } /* check if there is more to send */ if (pdu_pending(c)) event_add(&c->wev, NULL); } }
int p9pdu_vwritef(struct p9_fcall *pdu, int proto_version, const char *fmt, va_list ap) { const char *ptr; int errcode = 0; for (ptr = fmt; *ptr; ptr++) { switch (*ptr) { case 'b': { int8_t val = va_arg(ap, int); if (pdu_write(pdu, &val, sizeof(val))) errcode = -EFAULT; } break; case 'w': { __le16 val = cpu_to_le16(va_arg(ap, int)); if (pdu_write(pdu, &val, sizeof(val))) errcode = -EFAULT; } break; case 'd': { __le32 val = cpu_to_le32(va_arg(ap, int32_t)); if (pdu_write(pdu, &val, sizeof(val))) errcode = -EFAULT; } break; case 'q': { __le64 val = cpu_to_le64(va_arg(ap, int64_t)); if (pdu_write(pdu, &val, sizeof(val))) errcode = -EFAULT; } break; case 's': { const char *sptr = va_arg(ap, const char *); int16_t len = 0; if (sptr) len = MIN(strlen(sptr), USHRT_MAX); errcode = p9pdu_writef(pdu, proto_version, "w", len); if (!errcode && pdu_write(pdu, sptr, len)) errcode = -EFAULT; } break; case 'Q': { const struct p9_qid *qid = va_arg(ap, const struct p9_qid *); errcode = p9pdu_writef(pdu, proto_version, "bdq", qid->type, qid->version, qid->path); } break; case 'S': { const struct p9_wstat *stbuf = va_arg(ap, const struct p9_wstat *); errcode = p9pdu_writef(pdu, proto_version, "wwdQdddqssss?sddd", stbuf->size, stbuf->type, stbuf->dev, &stbuf->qid, stbuf->mode, stbuf->atime, stbuf->mtime, stbuf->length, stbuf->name, stbuf->uid, stbuf->gid, stbuf->muid, stbuf->extension, stbuf->n_uid, stbuf->n_gid, stbuf->n_muid); } break; case 'D': { int32_t count = va_arg(ap, int32_t); const void *data = va_arg(ap, const void *); errcode = p9pdu_writef(pdu, proto_version, "d", count); if (!errcode && pdu_write(pdu, data, count)) errcode = -EFAULT; } break; case 'U': { int32_t count = va_arg(ap, int32_t); const char __user *udata = va_arg(ap, const void __user *); errcode = p9pdu_writef(pdu, proto_version, "d", count); if (!errcode && pdu_write_u(pdu, udata, count)) errcode = -EFAULT; } break; case 'T': { int16_t nwname = va_arg(ap, int); const char **wnames = va_arg(ap, const char **); errcode = p9pdu_writef(pdu, proto_version, "w", nwname); if (!errcode) { int i; for (i = 0; i < nwname; i++) { errcode = p9pdu_writef(pdu, proto_version, "s", wnames[i]); if (errcode) break; } } } break; case 'R': { int16_t nwqid = va_arg(ap, int); struct p9_qid *wqids = va_arg(ap, struct p9_qid *); errcode = p9pdu_writef(pdu, proto_version, "w", nwqid); if (!errcode) { int i; for (i = 0; i < nwqid; i++) { errcode = p9pdu_writef(pdu, proto_version, "Q", &wqids[i]); if (errcode) break; } } } break; case '?': if ((proto_version != p9_proto_2000u) && (proto_version != p9_proto_2000L)) return 0; break; default: BUG(); break; } if (errcode) break; } return errcode; }