Hi, The current VALUE length limit for the hostctl command for VMware is fixed 4096 bytes. I want to pass a longer VALUE. I made a patch to change it to variable length.
commane, ok? Index: share/man/man4/pvbus.4 =================================================================== RCS file: /cvs/src/share/man/man4/pvbus.4,v retrieving revision 1.14 diff -u -p -r1.14 pvbus.4 --- share/man/man4/pvbus.4 14 Jun 2017 12:42:09 -0000 1.14 +++ share/man/man4/pvbus.4 5 Oct 2022 03:23:00 -0000 @@ -102,13 +102,15 @@ struct pvbus_req { char *pvr_key; size_t pvr_valuelen; char *pvr_value; + size_t *pvr_len; }; .Ed .Pp The caller is responsible for attaching character buffers to the -.Fa pvr_key -and +.Fa pvr_key , .Fa pvr_value +and +.Fa pvr_len fields and to set their length in .Fa pvr_keylen and @@ -136,6 +138,14 @@ Write the new value to the key .Fa pvr_key . This command requires write permissions on the device file. +.It Dv PVBUSIOC_GETVALUELEN +Get the length of the value of +.Fa pvr_key +and return it in +.Fa pvr_len . +.It Dv PVBUSIOC_GETTYPELEN +Get the length of the type and return it in +.Fa pvr_len . .El .Sh FILES .Bl -tag -width "/dev/pvbusX" -compact Index: sys/dev/pv/hypervic.c =================================================================== RCS file: /cvs/src/sys/dev/pv/hypervic.c,v retrieving revision 1.17 diff -u -p -r1.17 hypervic.c --- sys/dev/pv/hypervic.c 8 Sep 2022 10:22:06 -0000 1.17 +++ sys/dev/pv/hypervic.c 5 Oct 2022 03:23:01 -0000 @@ -105,7 +105,7 @@ int hv_heartbeat_attach(struct hv_ic_dev void hv_heartbeat(void *); int hv_kvp_attach(struct hv_ic_dev *); void hv_kvp(void *); -int hv_kvop(void *, int, char *, char *, size_t); +int hv_kvop(void *, int, char *, size_t, char *, size_t, size_t *); int hv_shutdown_attach(struct hv_ic_dev *); void hv_shutdown(void *); int hv_timesync_attach(struct hv_ic_dev *); @@ -551,11 +551,10 @@ kvp_pool_init(struct kvp_pool *kvpl) } static int -kvp_pool_insert(struct kvp_pool *kvpl, const char *key, const char *val, - uint32_t vallen, uint32_t valtype) +kvp_pool_insert(struct kvp_pool *kvpl, const char *key, size_t keylen, + const char *val, size_t vallen, uint32_t valtype) { struct kvp_entry *kpe; - int keylen = strlen(key); if (keylen > HV_KVP_MAX_KEY_SIZE / 2) return (ERANGE); @@ -592,11 +591,10 @@ kvp_pool_insert(struct kvp_pool *kvpl, c } static int -kvp_pool_update(struct kvp_pool *kvpl, const char *key, const char *val, - uint32_t vallen, uint32_t valtype) +kvp_pool_update(struct kvp_pool *kvpl, const char *key, size_t keylen, + const char *val, size_t vallen, uint32_t valtype) { struct kvp_entry *kpe; - int keylen = strlen(key); if (keylen > HV_KVP_MAX_KEY_SIZE / 2) return (ERANGE); @@ -715,12 +713,13 @@ kvp_pool_remove(struct kvp_pool *kvpl, c } static int -kvp_pool_extract(struct kvp_pool *kvpl, const char *key, char *val, - uint32_t vallen) +kvp_pool_extract(struct kvp_pool *kvpl, int op, const char *key, char *val, + size_t vallen, size_t *vlen) { struct kvp_entry *kpe; + char buf[128]; - if (vallen < HV_KVP_MAX_VAL_SIZE / 2) + if (vallen > SIZE_T_MAX) return (ERANGE); mtx_enter(&kvpl->kvp_lock); @@ -734,18 +733,36 @@ kvp_pool_extract(struct kvp_pool *kvpl, return (ENOENT); } - switch (kpe->kpe_valtype) { - case HV_KVP_REG_SZ: - strlcpy(val, kpe->kpe_val, HV_KVP_MAX_VAL_SIZE / 2); - break; - case HV_KVP_REG_U32: - snprintf(val, HV_KVP_MAX_VAL_SIZE / 2, "%u", - *(uint32_t *)kpe->kpe_val); - break; - case HV_KVP_REG_U64: - snprintf(val, HV_KVP_MAX_VAL_SIZE / 2, "%llu", - *(uint64_t *)kpe->kpe_val); - break; + if (op == PVBUS_KVGETVALLEN) { + switch (kpe->kpe_valtype) { + case HV_KVP_REG_SZ: + *vlen = strlen(kpe->kpe_val); + break; + case HV_KVP_REG_U32: + snprintf(buf, HV_KVP_MAX_VAL_SIZE / 2, "%u", + *(uint32_t *)kpe->kpe_val); + *vlen = strlen(buf); + break; + case HV_KVP_REG_U64: + snprintf(buf, HV_KVP_MAX_VAL_SIZE / 2, "%llu", + *(uint64_t *)kpe->kpe_val); + *vlen = strlen(buf); + break; + } + } else { + switch (kpe->kpe_valtype) { + case HV_KVP_REG_SZ: + strlcpy(val, kpe->kpe_val, HV_KVP_MAX_VAL_SIZE / 2); + break; + case HV_KVP_REG_U32: + snprintf(val, HV_KVP_MAX_VAL_SIZE / 2, "%u", + *(uint32_t *)kpe->kpe_val); + break; + case HV_KVP_REG_U64: + snprintf(val, HV_KVP_MAX_VAL_SIZE / 2, "%llu", + *(uint64_t *)kpe->kpe_val); + break; + } } mtx_leave(&kvpl->kvp_lock); @@ -777,6 +794,29 @@ kvp_pool_keys(struct kvp_pool *kvpl, int return (-1); } +static int +kvp_pool_keylen(struct kvp_pool *kvpl, int next, size_t *keylen) +{ + struct kvp_entry *kpe; + int iter = 0; + + mtx_enter(&kvpl->kvp_lock); + + TAILQ_FOREACH(kpe, &kvpl->kvp_entries, kpe_entry) { + if (iter++ < next) + continue; + *keylen = strlen(kpe->kpe_key); + + mtx_leave(&kvpl->kvp_lock); + + return (0); + } + + mtx_leave(&kvpl->kvp_lock); + + return (-1); +} + int hv_kvp_attach(struct hv_ic_dev *dv) { @@ -812,8 +852,9 @@ hv_kvp_attach(struct hv_ic_dev *dv) /* Initialize 'Auto' pool */ for (i = 0; i < nitems(kvp_pool_auto); i++) { if (kvp_pool_insert(&kvp->kvp_pool[HV_KVP_POOL_AUTO], - kvp_pool_auto[i].keyname, kvp_pool_auto[i].value, - strlen(kvp_pool_auto[i].value), HV_KVP_REG_SZ)) + kvp_pool_auto[i].keyname, strlen(kvp_pool_auto[i].keyname), + kvp_pool_auto[i].value, strlen(kvp_pool_auto[i].value), + HV_KVP_REG_SZ)) DPRINTF("%s: failed to insert into 'Auto' pool\n", sc->sc_dev.dv_xname); } @@ -1135,14 +1176,15 @@ kvp_poolname(char **key) } int -hv_kvop(void *arg, int op, char *key, char *val, size_t vallen) +hv_kvop(void *arg, int op, char *key, size_t klen, char *val, size_t vallen, + size_t *vlen) { struct hv_ic_dev *dv = arg; struct hv_kvp *kvp = dv->dv_priv; struct kvp_pool *kvpl; int next, pool, error = 0; char *vp = val; - size_t keylen; + size_t keylen = 0; pool = kvp_poolname(&key); if (pool == -1) @@ -1150,31 +1192,43 @@ hv_kvop(void *arg, int op, char *key, ch kvpl = &kvp->kvp_pool[pool]; if (strlen(key) == 0) { - for (next = 0; next < MAXPOOLENTS; next++) { - if ((val + vallen < vp + HV_KVP_MAX_KEY_SIZE / 2) || - kvp_pool_keys(kvpl, next, vp, &keylen)) - goto out; - if (strlcat(val, "\n", vallen) >= vallen) - goto out; - vp += keylen; + if (op == PVBUS_KVGETVALLEN) { + *vlen = 0; + for (next = 0; next < MAXPOOLENTS; next++) { + if (kvp_pool_keylen(kvpl, next, &keylen)) + break; + /* `+ 1' means '\n' the end of the line */ + *vlen += keylen + 1; + } + /* `+ 1' means '\0' the end of the line */ + *vlen += 1; + } else { + for (next = 0; next < MAXPOOLENTS; next++) { + if ((val + vallen < vp) || + kvp_pool_keys(kvpl, next, vp, &keylen)) + break; + if (strlcat(val, "\n", vallen) >= vallen) + break; + vp += keylen; + } + if (vp > val) + *(vp - 1) = '\0'; } - out: - if (vp > val) - *(vp - 1) = '\0'; return (0); } if (op == PVBUS_KVWRITE) { + keylen = strlen(key); if (pool == HV_KVP_POOL_AUTO) - error = kvp_pool_update(kvpl, key, val, vallen, + error = kvp_pool_update(kvpl, key, keylen, val, vallen, HV_KVP_REG_SZ); else if (pool == HV_KVP_POOL_GUEST) - error = kvp_pool_insert(kvpl, key, val, vallen, + error = kvp_pool_insert(kvpl, key, keylen, val, vallen, HV_KVP_REG_SZ); else error = EINVAL; } else - error = kvp_pool_extract(kvpl, key, val, vallen); + error = kvp_pool_extract(kvpl, op, key, val, vallen, vlen); return (error); } Index: sys/dev/pv/pvbus.c =================================================================== RCS file: /cvs/src/sys/dev/pv/pvbus.c,v retrieving revision 1.25 diff -u -p -r1.25 pvbus.c --- sys/dev/pv/pvbus.c 25 Aug 2022 17:38:16 -0000 1.25 +++ sys/dev/pv/pvbus.c 5 Oct 2022 03:23:01 -0000 @@ -400,12 +400,10 @@ pvbusgetstr(size_t srclen, const char *s /* * Reject size that is too short or obviously too long: * - at least one byte for the nul terminator. - * - PAGE_SIZE is an arbitrary value, but known pv backends seem - * to have a hard (PAGE_SIZE - x) limit in their messaging. */ if (srclen < 1) return (EINVAL); - else if (srclen > PAGE_SIZE) + else if (srclen > SIZE_T_MAX) return (ENAMETOOLONG); *dstp = dst = malloc(srclen + 1, M_TEMP|M_ZERO, M_WAITOK); @@ -437,6 +435,9 @@ pvbusioctl(dev_t dev, u_long cmd, caddr_ case PVBUSIOC_KVWRITE: if ((flags & FWRITE) == 0) return (EPERM); + /* FALLTHROUGH */ + case PVBUSIOC_GETVALUELEN: + /* FALLTHROUGH */ case PVBUSIOC_KVREAD: hv = &sc->pvbus_hv[hvid]; if (hv->hv_base == 0 || hv->hv_kvop == NULL) @@ -449,6 +450,12 @@ pvbusioctl(dev_t dev, u_long cmd, caddr_ return (ENOMEM); error = copyout(str, pvr->pvr_key, sz); return (error); + + case PVBUSIOC_GETTYPELEN: + sz = strlen(pvbus_types[hvid].name); + error = copyout(&sz, pvr->pvr_len, sizeof (*pvr->pvr_len)); + return (error); + default: return (ENOTTY); } @@ -457,6 +464,18 @@ pvbusioctl(dev_t dev, u_long cmd, caddr_ op = PVBUS_KVREAD; switch (cmd) { + case PVBUSIOC_GETVALUELEN: + op = PVBUS_KVGETVALLEN; + keylen = pvr->pvr_keylen; + if ((error = pvbusgetstr(keylen, pvr->pvr_key, &key)) != 0) + break; + if ((error = (hv->hv_kvop)(hv->hv_arg, op, + key, keylen, value, valuelen, &sz)) != 0) + break; + if ((error = copyout(&sz, pvr->pvr_len, + sizeof (*pvr->pvr_len))) != 0) + break; + break; case PVBUSIOC_KVWRITE: str = pvr->pvr_value; op = PVBUS_KVWRITE; @@ -473,7 +492,7 @@ pvbusioctl(dev_t dev, u_long cmd, caddr_ /* Call driver-specific callback */ if ((error = (hv->hv_kvop)(hv->hv_arg, op, - key, value, valuelen)) != 0) + key, keylen, value, valuelen, NULL)) != 0) break; sz = strlen(value) + 1; Index: sys/dev/pv/pvvar.h =================================================================== RCS file: /cvs/src/sys/dev/pv/pvvar.h,v retrieving revision 1.10 diff -u -p -r1.10 pvvar.h --- sys/dev/pv/pvvar.h 22 Jun 2017 06:21:12 -0000 1.10 +++ sys/dev/pv/pvvar.h 5 Oct 2022 03:23:01 -0000 @@ -24,11 +24,14 @@ struct pvbus_req { char *pvr_key; size_t pvr_valuelen; char *pvr_value; + size_t *pvr_len; }; #define PVBUSIOC_KVREAD _IOWR('V', 1, struct pvbus_req) #define PVBUSIOC_KVWRITE _IOWR('V', 2, struct pvbus_req) #define PVBUSIOC_TYPE _IOWR('V', 3, struct pvbus_req) +#define PVBUSIOC_GETVALUELEN _IOWR('V', 4, struct pvbus_req) +#define PVBUSIOC_GETTYPELEN _IOWR('V', 5, struct pvbus_req) #ifdef _KERNEL enum { @@ -45,7 +48,9 @@ enum { enum { PVBUS_KVREAD, PVBUS_KVWRITE, - PVBUS_KVLS + PVBUS_KVLS, + PVBUS_KVGETVALLEN, + PVBUS_KVLSGETVALLEN }; struct pvbus_hv { @@ -55,7 +60,8 @@ struct pvbus_hv { uint16_t hv_minor; void *hv_arg; - int (*hv_kvop)(void *, int, char *, char *, size_t); + int (*hv_kvop)(void *, int, char *, size_t, char *, + size_t, size_t *); void (*hv_init_cpu)(struct pvbus_hv *); }; Index: sys/dev/pv/vmt.c =================================================================== RCS file: /cvs/src/sys/dev/pv/vmt.c,v retrieving revision 1.26 diff -u -p -r1.26 vmt.c --- sys/dev/pv/vmt.c 8 Sep 2022 10:22:06 -0000 1.26 +++ sys/dev/pv/vmt.c 5 Oct 2022 03:23:01 -0000 @@ -241,6 +241,8 @@ struct vmt_softc { struct vm_rpc sc_tclo_rpc; char *sc_rpc_buf; + size_t sc_rpc_buflen; + size_t sc_rpc_rxlen; int sc_rpc_error; int sc_tclo_ping; int sc_set_guest_os; @@ -277,12 +279,13 @@ int vm_rpc_send(const struct vm_rpc *, int vm_rpc_send_str(const struct vm_rpc *, const uint8_t *); int vm_rpc_get_length(const struct vm_rpc *, uint32_t *, uint16_t *); int vm_rpc_get_data(const struct vm_rpc *, char *, uint32_t, uint16_t); -int vm_rpc_send_rpci_tx_buf(struct vmt_softc *, const uint8_t *, uint32_t); +int vm_rpc_send_rpci_tx_buf(struct vmt_softc *, char *, uint32_t); int vm_rpc_send_rpci_tx(struct vmt_softc *, const char *, ...) __attribute__((__format__(__kprintf__,2,3))); -int vm_rpci_response_successful(struct vmt_softc *); +int vm_rpci_response_successful(const char *); +int vm_rpc_buf_realloc(struct vmt_softc *, size_t); -int vmt_kvop(void *, int, char *, char *, size_t); +int vmt_kvop(void *, int, char *, size_t, char *, size_t, size_t *); void vmt_probe_cmd(struct vm_backdoor *, uint16_t); void vmt_tclo_state_change_success(struct vmt_softc *, int, char); @@ -440,7 +443,8 @@ vmt_attach(struct device *parent, struct struct pvbus_hv *hv = &pva->pva_hv[PVBUS_VMWARE]; printf("\n"); - sc->sc_rpc_buf = malloc(VMT_RPC_BUFLEN, M_DEVBUF, M_NOWAIT); + sc->sc_rpc_buflen = VMT_RPC_BUFLEN; + sc->sc_rpc_buf = malloc(sc->sc_rpc_buflen, M_DEVBUF, M_NOWAIT); if (sc->sc_rpc_buf == NULL) { printf("%s: unable to allocate buffer for RPC\n", DEVNAME(sc)); @@ -484,32 +488,40 @@ vmt_attach(struct device *parent, struct return; free: - free(sc->sc_rpc_buf, M_DEVBUF, VMT_RPC_BUFLEN); + free(sc->sc_rpc_buf, M_DEVBUF, sc->sc_rpc_buflen); } int -vmt_kvop(void *arg, int op, char *key, char *value, size_t valuelen) +vmt_kvop(void *arg, int op, char *key, size_t keylen, char *value, + size_t valuelen, size_t *vlen) { struct vmt_softc *sc = arg; - char *buf = NULL, *ptr; - size_t bufsz; + char *ptr; + size_t bufsz, buflen; int error = 0; + const char *set_cmd = "info-set %s %s"; + const char *get_cmd = "info-get %s"; - bufsz = VMT_RPC_BUFLEN; - buf = malloc(bufsz, M_TEMP, M_WAITOK | M_ZERO); + bufsz = MAX(strlen(set_cmd), strlen(get_cmd)) + keylen + valuelen; + if (bufsz > sc->sc_rpc_buflen && + (error = vm_rpc_buf_realloc(sc, bufsz)) != 0) + return error; switch (op) { case PVBUS_KVWRITE: - if ((size_t)snprintf(buf, bufsz, "info-set %s %s", - key, value) >= bufsz) { + buflen = (size_t)snprintf(sc->sc_rpc_buf, bufsz, set_cmd, key, + value); + if (buflen >= bufsz) { DPRINTF("%s: write command too long", DEVNAME(sc)); error = EINVAL; goto done; } break; + case PVBUS_KVGETVALLEN: + /* FALLTHROUGH */ case PVBUS_KVREAD: - if ((size_t)snprintf(buf, bufsz, "info-get %s", - key) >= bufsz) { + buflen = (size_t)snprintf(sc->sc_rpc_buf, bufsz, get_cmd, key); + if (buflen >= bufsz) { DPRINTF("%s: read command too long", DEVNAME(sc)); error = EINVAL; goto done; @@ -520,15 +532,15 @@ vmt_kvop(void *arg, int op, char *key, c goto done; } - if (vm_rpc_send_rpci_tx(sc, "%s", buf) != 0) { - DPRINTF("%s: error sending command: %s\n", DEVNAME(sc), buf); + if (vm_rpc_send_rpci_tx_buf(sc, sc->sc_rpc_buf, buflen) != 0) { + DPRINTF("%s: error sending command: %s\n", DEVNAME(sc), sc->sc_rpc_buf); sc->sc_rpc_error = 1; error = EIO; goto done; } - if (vm_rpci_response_successful(sc) == 0) { - DPRINTF("%s: host rejected command: %s\n", DEVNAME(sc), buf); + if (vm_rpci_response_successful(sc->sc_rpc_buf) == 0) { + DPRINTF("%s: host rejected command: %s\n", DEVNAME(sc), sc->sc_rpc_buf); error = EINVAL; goto done; } @@ -536,12 +548,16 @@ vmt_kvop(void *arg, int op, char *key, c /* skip response that was tested in vm_rpci_response_successful() */ ptr = sc->sc_rpc_buf + 2; - /* might truncate, copy anyway but return error */ - if (strlcpy(value, ptr, valuelen) >= valuelen) + if (op == PVBUS_KVGETVALLEN) + /* decrement response that was tested in + * vm_rpci_response_successful(). + */ + *vlen = strlen(ptr); + /* might truncat, copy anyway but return error */ + else if (strlcpy(value, ptr, valuelen) >= valuelen) error = ENOMEM; done: - free(buf, M_TEMP, bufsz); return (error); } @@ -826,7 +842,7 @@ vmt_tclo_capreg(struct vmt_softc *sc) sc->sc_rpc_error = 1; } - if (vm_rpci_response_successful(sc) == 0) { + if (vm_rpci_response_successful(sc->sc_rpc_buf) == 0) { DPRINTF("%s: host rejected unified loop setting\n", DEVNAME(sc)); } @@ -839,7 +855,7 @@ vmt_tclo_capreg(struct vmt_softc *sc) sc->sc_rpc_error = 1; } - if (vm_rpci_response_successful(sc) == 0) { + if (vm_rpci_response_successful(sc->sc_rpc_buf) == 0) { DPRINTF("%s: host rejected statechange capability\n", DEVNAME(sc)); } @@ -1644,14 +1660,28 @@ vm_rpc_get_length(const struct vm_rpc *r } int -vm_rpci_response_successful(struct vmt_softc *sc) +vm_rpci_response_successful(const char *buf) { - return (sc->sc_rpc_buf[0] == '1' && sc->sc_rpc_buf[1] == ' '); + return (buf[0] == '1' && buf[1] == ' '); } int -vm_rpc_send_rpci_tx_buf(struct vmt_softc *sc, const uint8_t *buf, - uint32_t length) +vm_rpc_buf_realloc(struct vmt_softc *sc, size_t len) +{ + free(sc->sc_rpc_buf, M_DEVBUF, sc->sc_rpc_buflen); + + sc->sc_rpc_buflen = len / VMT_RPC_BUFLEN * VMT_RPC_BUFLEN; + sc->sc_rpc_buflen += ((len % VMT_RPC_BUFLEN) <= 0) ? 0 : VMT_RPC_BUFLEN; + sc->sc_rpc_buf = malloc(sc->sc_rpc_buflen, M_DEVBUF, M_NOWAIT); + if (sc->sc_rpc_buf == NULL) { + printf("%s: unable to allocate buffer for RPC\n", DEVNAME(sc)); + return ENOMEM; + } + return 0; +} + +int +vm_rpc_send_rpci_tx_buf(struct vmt_softc *sc, char *buf, uint32_t length) { struct vm_rpc rpci; u_int32_t rlen; @@ -1677,9 +1707,11 @@ vm_rpc_send_rpci_tx_buf(struct vmt_softc } if (rlen > 0) { - if (rlen >= VMT_RPC_BUFLEN) { - rlen = VMT_RPC_BUFLEN - 1; - } + sc->sc_rpc_rxlen = rlen; + /* Add the amount of the NUL terminater */ + if (rlen >= sc->sc_rpc_buflen && + (result = vm_rpc_buf_realloc(sc, rlen + 1)) != 0) + goto out; if (vm_rpc_get_data(&rpci, sc->sc_rpc_buf, rlen, ack) != 0) { DPRINTF("%s: failed to get rpci response data\n", @@ -1707,7 +1739,7 @@ vm_rpc_send_rpci_tx(struct vmt_softc *sc len = vsnprintf(sc->sc_rpc_buf, VMT_RPC_BUFLEN, fmt, args); va_end(args); - if (len >= VMT_RPC_BUFLEN) { + if (len >= sc->sc_rpc_buflen) { DPRINTF("%s: rpci command didn't fit in buffer\n", DEVNAME(sc)); return EIO; } Index: sys/dev/pv/xenstore.c =================================================================== RCS file: /cvs/src/sys/dev/pv/xenstore.c,v retrieving revision 1.46 diff -u -p -r1.46 xenstore.c --- sys/dev/pv/xenstore.c 9 Jan 2022 05:42:58 -0000 1.46 +++ sys/dev/pv/xenstore.c 5 Oct 2022 03:23:01 -0000 @@ -1065,7 +1065,8 @@ xs_await_transition(void *xsc, const cha } int -xs_kvop(void *xsc, int op, char *key, char *value, size_t valuelen) +xs_kvop(void *xsc, int op, char *key, size_t keylen, char *value, + size_t valuelen, size_t *vlen) { struct xen_softc *sc = xsc; struct xs_transaction xst; @@ -1079,9 +1080,13 @@ xs_kvop(void *xsc, int op, char *key, ch iov.iov_len = strlen(value); iov_cnt = 1; break; + case PVBUS_KVGETVALLEN: + /* FALLTHROUGH */ case PVBUS_KVREAD: cmd = XS_READ; break; + case PVBUS_KVLSGETVALLEN: + /* FALLTHROUGH */ case PVBUS_KVLS: cmd = XS_LIST; break; @@ -1110,16 +1115,25 @@ xs_kvop(void *xsc, int op, char *key, ch * returns an empty string (single nul byte), * so try to get the directory list in this case. */ - return (xs_kvop(xsc, PVBUS_KVLS, key, value, valuelen)); + return (xs_kvop(xsc, op == PVBUS_KVREAD ? PVBUS_KVLS : + PVBUS_KVLSGETVALLEN, key, keylen, value, + valuelen, vlen)); } /* FALLTHROUGH */ case XS_LIST: - for (i = 0; i < iov_cnt; i++) { - if (i && strlcat(value, "\n", valuelen) >= valuelen) - break; - if (strlcat(value, iovp[i].iov_base, - valuelen) >= valuelen) - break; + if (op == PVBUS_KVGETVALLEN || op == PVBUS_KVLSGETVALLEN) { + *vlen = 0; + for (i = 0; i < iov_cnt; i++) + *vlen += iovp[i].iov_len; + } else { + for (i = 0; i < iov_cnt; i++) { + if (i && strlcat(value, "\n", valuelen) >= + valuelen) + break; + if (strlcat(value, iovp[i].iov_base, + valuelen) >= valuelen) + break; + } } xs_resfree(&xst, iovp, iov_cnt); break; Index: sys/dev/pv/xenvar.h =================================================================== RCS file: /cvs/src/sys/dev/pv/xenvar.h,v retrieving revision 1.51 diff -u -p -r1.51 xenvar.h --- sys/dev/pv/xenvar.h 21 Jul 2017 20:00:47 -0000 1.51 +++ sys/dev/pv/xenvar.h 5 Oct 2022 03:23:01 -0000 @@ -193,7 +193,7 @@ int xs_getnum(void *, const char *, cons int xs_setnum(void *, const char *, const char *, unsigned long long); int xs_getprop(void *, const char *, const char *, char *, int); int xs_setprop(void *, const char *, const char *, char *, int); -int xs_kvop(void *, int, char *, char *, size_t); +int xs_kvop(void *, int, char *, size_t, char *, size_t, size_t *); #define XEN_STATE_UNKNOWN "0" #define XEN_STATE_INITIALIZING "1" Index: usr.sbin/hostctl/hostctl.c =================================================================== RCS file: /cvs/src/usr.sbin/hostctl/hostctl.c,v retrieving revision 1.5 diff -u -p -r1.5 hostctl.c --- usr.sbin/hostctl/hostctl.c 28 Jun 2019 13:32:47 -0000 1.5 +++ usr.sbin/hostctl/hostctl.c 5 Oct 2022 03:23:01 -0000 @@ -37,8 +37,7 @@ int qflag = 0; /* quiet */ int tflag = 0; /* show type */ __dead void usage(void); -int kvsetstr(char *, const char *, size_t); -int kvsetfile(char *, const char *, size_t); +int kvsetfile(char **, const char *, size_t *); __dead void usage(void) @@ -50,44 +49,40 @@ usage(void) } int -kvsetstr(char *dst, const char *src, size_t dstlen) +kvsetfile(char **dst, const char *input, size_t *dstlen) { - size_t sz; - - /* Sanitize the string before sending it to the kernel and host */ - if ((sz = strnvis(dst, src, dstlen, VIS_SAFE | VIS_CSTYLE)) >= dstlen) - return (-1); - - /* Remove trailing newline */ - dst[strcspn(dst, "\n")] = '\0'; - - return (0); -} - -int -kvsetfile(char *dst, const char *input, size_t dstlen) -{ - char *buf = NULL; + char buf[KVBUFSZ]; int ret = -1; - FILE *fp; + FILE *fp, *mp; + size_t flen; if (strcmp("-", input) == 0) fp = stdin; else if ((fp = fopen(input, "r")) == NULL) return (-1); + if ((mp = open_memstream(dst, dstlen)) == NULL) { + fclose(fp); + return (-1); + } - if ((buf = calloc(1, dstlen)) == NULL) - goto done; - if (fread(buf, 1, dstlen - 1, fp) == 0) - goto done; - if (kvsetstr(dst, buf, dstlen) == -1) - goto done; + do { + if ((flen = fread(buf, 1, sizeof (buf), fp)) == 0) + goto done; + if (fwrite(buf, 1, flen, mp) == 0) + goto done; + } while (flen >= sizeof (buf)); ret = 0; done: - free(buf); if (fp != stdin) fclose(fp); + fclose(mp); + + /* Remove '\n' at the end of line */ + if ((*dst)[*dstlen - 1] == '\n') { + --(*dstlen); + (*dst)[*dstlen] = '\0'; + } return (ret); } @@ -101,6 +96,7 @@ main(int argc, char *argv[]) int ch; unsigned long cmd = 0; char *str; + size_t len; while ((ch = getopt(argc, argv, "f:i:o:qt")) != -1) { switch (ch) { @@ -137,12 +133,17 @@ main(int argc, char *argv[]) } memset(&pvr, 0, sizeof(pvr)); - pvr.pvr_keylen = pvr.pvr_valuelen = KVBUFSZ; - if ((pvr.pvr_key = calloc(1, pvr.pvr_keylen)) == NULL || - (pvr.pvr_value = calloc(1, pvr.pvr_valuelen)) == NULL) - err(1, "calloc"); if (tflag) { + pvr.pvr_len = &len; + if ((ret = ioctl(fd, PVBUSIOC_GETTYPELEN, &pvr, sizeof(pvr))) + == -1) + err(1, "ioctl"); + /* Add the NUL amount of the terminator */ + pvr.pvr_keylen = len + 1; + if ((pvr.pvr_key = calloc(1, pvr.pvr_keylen)) == NULL) + err(1, "calloc"); + if (ioctl(fd, PVBUSIOC_TYPE, &pvr, sizeof(pvr)) == -1) err(1, "ioctl"); @@ -159,18 +160,20 @@ main(int argc, char *argv[]) usage(); key = argv[0]; - if (kvsetstr(pvr.pvr_key, key, pvr.pvr_keylen) == -1) - errx(1, "key too long"); + if (stravis(&pvr.pvr_key, key, VIS_SAFE | VIS_CSTYLE) == -1) + err(1, "stravis"); + pvr.pvr_keylen = strlen(pvr.pvr_key) + 1; /* Validate command line options for reading or writing */ if (argc == 2 && in == NULL) { cmd = PVBUSIOC_KVWRITE; value = argv[1]; - if (kvsetstr(pvr.pvr_value, value, pvr.pvr_valuelen) == -1) - errx(1, "value too long"); + if (stravis(&pvr.pvr_value, value, VIS_SAFE | VIS_CSTYLE) == -1) + err(1, "stravis"); + pvr.pvr_valuelen = strlen(value) + 1; } else if (argc == 1 && in != NULL) { cmd = PVBUSIOC_KVWRITE; - if (kvsetfile(pvr.pvr_value, in, pvr.pvr_valuelen) == -1) + if (kvsetfile(&pvr.pvr_value, in, &pvr.pvr_valuelen) == -1) errx(1, "input file"); } else if (argc == 1) { cmd = cmd == 0 ? PVBUSIOC_KVREAD : cmd; @@ -184,6 +187,18 @@ main(int argc, char *argv[]) err(1, "open: %s", path_pvbus); } + /* Get the length of value of key */ + if (cmd == PVBUSIOC_KVREAD) { + pvr.pvr_len = &len; + if ((ret = ioctl(fd, PVBUSIOC_GETVALUELEN, &pvr, sizeof(pvr))) + == -1) + err(1, "ioctl"); + /* Add the NUL amount of the terminator */ + pvr.pvr_valuelen = len + 1; + if ((pvr.pvr_value = calloc(1, pvr.pvr_valuelen)) == NULL) + err(1, "calloc"); + } + if ((ret = ioctl(fd, cmd, &pvr, sizeof(pvr))) == -1) err(1, "ioctl"); @@ -202,7 +217,8 @@ main(int argc, char *argv[]) done: if (outfp != stdout) fclose(outfp); - free(pvr.pvr_value); + if (pvr.pvr_value != NULL) + free(pvr.pvr_value); free(pvr.pvr_key); close(fd); -- ASOU Masato