|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Minios-devel] [UNIKRAFT PATCH v2 05/10] plat/xen: Add API for Xenstore messages
On 09/05/2018 11:56 AM, Yuri Volchkov wrote:
> Costin Lupu <costin.lup@xxxxxxxxx> writes:
>
>> On 09/04/2018 07:25 PM, Yuri Volchkov wrote:
>>> Costin Lupu <costin.lup@xxxxxxxxx> writes:
>>>
>>>> Hi Yuri,
>>>>
>>>> Please see my comments inline.
>>>>
>>>> On 08/31/2018 06:27 PM, Yuri Volchkov wrote:
>>>>> Hey Costin,
>>>>>
>>>>> see my comments inline.
>>>>>
>>>>> BR, Yuri.
>>>>>
>>>>> Costin Lupu <costin.lupu@xxxxxxxxx> writes:
>>>>>
>>>>>> Add the API needed for sending Xenstore messages. These functions
>>>>>> are used by any client communicating with the Xenstore daemon.
>>>>>>
>>>>>> Signed-off-by: Costin Lupu <costin.lupu@xxxxxxxxx>
>>>>>> ---
>>>>>> plat/xen/Makefile.uk | 1 +
>>>>>> plat/xen/include/xenbus/xs.h | 270 ++++++++++++++++++
>>>>>> plat/xen/xenbus/xs.c | 650
>>>>>> +++++++++++++++++++++++++++++++++++++++++++
>>>>>> 3 files changed, 921 insertions(+)
>>>>>> create mode 100644 plat/xen/include/xenbus/xs.h
>>>>>> create mode 100644 plat/xen/xenbus/xs.c
>>>>>>
>>>>>> diff --git a/plat/xen/Makefile.uk b/plat/xen/Makefile.uk
>>>>>> index 2703a54..63cc42b 100644
>>>>>> --- a/plat/xen/Makefile.uk
>>>>>> +++ b/plat/xen/Makefile.uk
>>>>>> @@ -80,4 +80,5 @@ LIBXENBUS_CFLAGS-y +=
>>>>>> $(LIBXENPLAT_CFLAGS-y)
>>>>>> LIBXENBUS_CINCLUDES-y += $(LIBXENPLAT_CINCLUDES-y)
>>>>>> LIBXENBUS_SRCS-y += $(LIBXENPLAT_BASE)/xenbus/xenbus.c
>>>>>> LIBXENBUS_SRCS-y += $(LIBXENPLAT_BASE)/xenbus/xs_comms.c
>>>>>> +LIBXENBUS_SRCS-y += $(LIBXENPLAT_BASE)/xenbus/xs.c
>>>>>> endif
>>>>>> diff --git a/plat/xen/include/xenbus/xs.h b/plat/xen/include/xenbus/xs.h
>>>>>> new file mode 100644
>>>>>> index 0000000..6ae761d
>>>>>> --- /dev/null
>>>>>> +++ b/plat/xen/include/xenbus/xs.h
>>>>>> @@ -0,0 +1,270 @@
>>>>>> +/* SPDX-License-Identifier: BSD-3-Clause */
>>>>>> +/*
>>>>>> + * Authors: Costin Lupu <costin.lupu@xxxxxxxxx>
>>>>>> + *
>>>>>> + * Copyright (c) 2018, NEC Europe Ltd., NEC Corporation. All rights
>>>>>> reserved.
>>>>>> + *
>>>>>> + * Redistribution and use in source and binary forms, with or without
>>>>>> + * modification, are permitted provided that the following conditions
>>>>>> + * are met:
>>>>>> + *
>>>>>> + * 1. Redistributions of source code must retain the above copyright
>>>>>> + * notice, this list of conditions and the following disclaimer.
>>>>>> + * 2. Redistributions in binary form must reproduce the above copyright
>>>>>> + * notice, this list of conditions and the following disclaimer in
>>>>>> the
>>>>>> + * documentation and/or other materials provided with the
>>>>>> distribution.
>>>>>> + * 3. Neither the name of the copyright holder nor the names of its
>>>>>> + * contributors may be used to endorse or promote products derived
>>>>>> from
>>>>>> + * this software without specific prior written permission.
>>>>>> + *
>>>>>> + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
>>>>>> "AS IS"
>>>>>> + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
>>>>>> TO, THE
>>>>>> + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
>>>>>> PURPOSE
>>>>>> + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
>>>>>> CONTRIBUTORS BE
>>>>>> + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
>>>>>> + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
>>>>>> + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
>>>>>> BUSINESS
>>>>>> + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
>>>>>> IN
>>>>>> + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
>>>>>> OTHERWISE)
>>>>>> + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
>>>>>> OF THE
>>>>>> + * POSSIBILITY OF SUCH DAMAGE.
>>>>>> + *
>>>>>> + * THIS HEADER MAY NOT BE EXTRACTED OR MODIFIED IN ANY WAY.
>>>>>> + */
>>>>>> +/* Xenstore API */
>>>>>> +/*
>>>>>> + * TODO The intention for this API is to be used by applications as
>>>>>> well.
>>>>>> + * Therefore, all data allocated by this API for external use must be
>>>>>> free'd
>>>>>> + * calling 'free' function (and not uk_xb_free). This is the reason why
>>>>>> such
>>>>>> + * data is allocated with 'malloc'/'calloc'.
>>>>>> + */
>>>>>> +
>>>>>> +#ifndef __XS_H__
>>>>>> +#define __XS_H__
>>>>>> +
>>>>>> +#include <xenbus/xenbus.h>
>>>>>> +
>>>>>> +
>>>>>> +/*
>>>>>> + * Read the value associated with a path.
>>>>>> + *
>>>>>> + * @param xbt Xenbus transaction id
>>>>>> + * @param path Xenstore path
>>>>>> + * @param node Xenstore subdirectory
>>>>>> + * @return On success, returns a malloc'd copy of the value. On error,
>>>>>> returns
>>>>>> + * a negative error number which should be checked using PTRISERR.
>>>>>> + */
>>>>>> +char *xs_read(xenbus_transaction_t xbt, const char *path, const char
>>>>>> *node);
>>>>>> +
>>>>>> +/*
>>>>>> + * Associates a value with a path.
>>>>>> + *
>>>>>> + * @param xbt Xenbus transaction id
>>>>>> + * @param path Xenstore path
>>>>>> + * @param node Xenstore subdirectory (optional)
>>>>>> + * @param value Xenstore value
>>>>>> + * @return 0 on success, a negative errno value on error.
>>>>>> + */
>>>>>> +int xs_write(xenbus_transaction_t xbt, const char *path, const char
>>>>>> *node,
>>>>>> + const char *value);
>>>>>> +
>>>>>> +/*
>>>>>> + * List the contents of a directory.
>>>>>> + *
>>>>>> + * @param xbt Xenbus transaction id
>>>>>> + * @param path Xenstore directory path
>>>>>> + * @param node Xenstore subdirectory (optional)
>>>>>> + * @return On success, returns a malloc'd array of pointers to strings.
>>>>>> The
>>>>>> + * array is NULL terminated. The caller should free only the array. On
>>>>>> error,
>>>>>> + * returns a negative error number which should be checked using
>>>>>> PTRISERR.
>>>>>> + * May block.
>>>>>> + */
>>>>>> +char **xs_ls(xenbus_transaction_t xbt, const char *path);
>>>>>> +
>>>>>> +/*
>>>>>> + * Removes the value associated with a path.
>>>>>> + *
>>>>>> + * @param xbt Xenbus transaction id
>>>>>> + * @param path Xenstore path
>>>>>> + * @return 0 on success, a negative errno value on error.
>>>>>> + */
>>>>>> +int xs_rm(xenbus_transaction_t xbt, const char *path);
>>>>>> +
>>>>>> +/*
>>>>>> + * Xenstore permissions
>>>>>> + */
>>>>>> +enum xs_perm {
>>>>>> + XS_PERM_NONE = 0x0,
>>>>>> + XS_PERM_READ = 0x1,
>>>>>> + XS_PERM_WRITE = 0x2,
>>>>>> + XS_PERM_BOTH = XS_PERM_WRITE | XS_PERM_READ
>>>>>> +};
>>>>>> +
>>>>>> +/*
>>>>>> + * Converts a character to corresponding permission value.
>>>>>> + *
>>>>>> + * @param c Permission character
>>>>>> + * @param perm Permission value
>>>>>> + * @return 0 on success, a negative errno value on error.
>>>>>> + */
>>>>>> +int xs_char_to_perm(char c, enum xs_perm *perm);
>>>>>> +
>>>>>> +/*
>>>>>> + * Converts a permission value to corresponding character.
>>>>>> + *
>>>>>> + * @param perm Permission value
>>>>>> + * @param c Permission character
>>>>>> + * @return 0 on success, a negative errno value on error.
>>>>>> + */
>>>>>> +int xs_perm_to_char(enum xs_perm perm, char *c);
>>>>>> +
>>>>>> +/*
>>>>>> + * Extracts domid and permission value out of a permission string.
>>>>>> + *
>>>>>> + * @param str Permission string
>>>>>> + * @param domid Domain ID
>>>>>> + * @param perm Permission value
>>>>>> + * @return 0 on success, a negative errno value on error.
>>>>>> + */
>>>>>> +int xs_str_to_perm(const char *str, domid_t *domid, enum xs_perm *perm);
>>>>>> +
>>>>>> +/*
>>>>>> + * Returns a permission string from domid and permission value.
>>>>>> + *
>>>>>> + * @param domid Domain ID
>>>>>> + * @param perm Permission value
>>>>>> + * @return On success, returns a malloc'd string. On error, returns a
>>>>>> negative
>>>>>> + * error number which should be checked using PTRISERR.
>>>>>> + */
>>>>>> +char *xs_perm_to_str(domid_t domid, enum xs_perm perm);
>>>>>> +
>>>>>> +/*
>>>>>> + * Xenstore ACL
>>>>>> + */
>>>>>> +struct xs_acl_entry {
>>>>>> + domid_t domid;
>>>>>> + enum xs_perm perm;
>>>>>> +};
>>>>>> +
>>>>>> +struct xs_acl {
>>>>>> + domid_t ownerid;
>>>>>> + enum xs_perm others_perm;
>>>>>> + int entries_num;
>>>>>> + struct xs_acl_entry entries[];
>>>>>> +};
>>>>>> +
>>>>>> +/*
>>>>>> + * Returns the ACL for input path.
>>>>>> + *
>>>>>> + * @param xbt Xenbus transaction id
>>>>>> + * @param path Xenstore path
>>>>>> + * @return On success, returns a malloc'd ACL. On error, returns a
>>>>>> + * negative error number which should be checked using PTRISERR.
>>>>>> + */
>>>>>> +struct xs_acl *xs_get_acl(xenbus_transaction_t xbt, const char *path);
>>>>>> +
>>>>>> +/*
>>>>>> + * Sets ACL for input path.
>>>>>> + *
>>>>>> + * @param xbt Xenbus transaction id
>>>>>> + * @param path Xenstore path
>>>>>> + * @param acl New ACL
>>>>>> + * @return 0 on success, a negative errno value on error.
>>>>>> + */
>>>>>> +int xs_set_acl(xenbus_transaction_t xbt, const char *path, struct
>>>>>> xs_acl *acl);
>>>>>> +
>>>>>> +/*
>>>>>> + * Reads permissions for input path and domid.
>>>>>> + *
>>>>>> + * @param xbt Xenbus transaction id
>>>>>> + * @param path Xenstore path
>>>>>> + * @param domid Domain ID
>>>>>> + * @param perm Permission value
>>>>>> + * @return 0 on success, a negative errno value on error.
>>>>>> + */
>>>>>> +int xs_get_perms(xenbus_transaction_t xbt, const char *path,
>>>>>> + domid_t domid, enum xs_perm *perm);
>>>>>> +
>>>>>> +/*
>>>>>> + * Sets permissions for input path and domid.
>>>>>> + *
>>>>>> + * @param xbt Xenbus transaction id
>>>>>> + * @param path Xenstore path
>>>>>> + * @param domid Domain ID
>>>>>> + * @param perm Permission value
>>>>>> + * @return 0 on success, a negative errno value on error.
>>>>>> + */
>>>>>> +int xs_set_perms(xenbus_transaction_t xbt, const char *path,
>>>>>> + domid_t domid, enum xs_perm perm);
>>>>>> +
>>>>>> +/*
>>>>>> + * Start a xenbus transaction. Returns the transaction in xbt on
>>>>>> + * success or an error number otherwise.
>>>>>> + *
>>>>>> + * @param xbt Address for returning the Xenbus transaction id
>>>>>> + * @return 0 on success, a negative errno value on error.
>>>>>> + */
>>>>>> +int xs_transaction_start(xenbus_transaction_t *xbt);
>>>>>> +
>>>>>> +/*
>>>>>> + * End a xenbus transaction. Returns non-zero on failure.
>>>>>> + * Parameter abort says whether the transaction should be aborted.
>>>>>> + * Returns 1 in *retry iff the transaction should be retried.
>>>>>> + *
>>>>>> + * @param xbt Xenbus transaction id
>>>>>> + * @param abort Non-zero if transaction should be aborted
>>>>>> + * @return 0 on success, a negative errno value on error.
>>>>>> + */
>>>>>> +int xs_transaction_end(xenbus_transaction_t xbt, int abort);
>>>>>> +
>>>>>> +/*
>>>>>> + * Sends a debug message to the Xenstore daemon for writing it in the
>>>>>> debug log
>>>>>> + *
>>>>>> + * @param msg The logged message
>>>>>> + * @return 0 on success, a negative errno value on error.
>>>>>> + */
>>>>>> +int xs_debug_msg(const char *msg);
>>>>>> +
>>>>>> +/*
>>>>>> + * Read path and parse it as an integer.
>>>>>> + *
>>>>>> + * @param path Xenstore path
>>>>>> + * @param value Returned int value
>>>>>> + * @return 0 on success, a negative errno value on error.
>>>>>> + */
>>>>>> +int xs_read_integer(const char *path, int *value);
>>>>>> +
>>>>>> +/*
>>>>>> + * Contraction of sscanf and xs_read(node/path).
>>>>>> + *
>>>>>> + * @param xbt Xenbus transaction id
>>>>>> + * @param dir Xenstore directory
>>>>>> + * @param node Xenstore directory entry
>>>>>> + * @param fmt Path format string
>>>>>> + * @return Just like sscanf, on success returns the number of input
>>>>>> items
>>>>>> + * successfully matched and assigned. On error returns a negative errno
>>>>>> value.
>>>>>> + */
>>>>>> +int xs_scanf(xenbus_transaction_t xbt, const char *dir, const char
>>>>>> *node,
>>>>>> + const char *fmt, ...) __scanf(4, 5);
>>>>>> +
>>>>>> +/*
>>>>>> + * Contraction of sprintf and xs_write(node/path).
>>>>>> + *
>>>>>> + * @param xbt Xenbus transaction id
>>>>>> + * @param dir Xenstore directory
>>>>>> + * @param node Xenstore directory entry
>>>>>> + * @param fmt Path format string
>>>>>> + * @return Just like sprintf, on success returns the number of the
>>>>>> number of
>>>>>> + * characters printed. On error returns a negative errno value.
>>>>>> + */
>>>>>> +int xs_printf(xenbus_transaction_t xbt, const char *dir, const char
>>>>>> *node,
>>>>>> + const char *fmt, ...) __printf(4, 5);
>>>>>> +
>>>>>> +/*
>>>>>> + * Utility function to figure out our domain id
>>>>>> + *
>>>>>> + * @return Our domain id
>>>>>> + */
>>>>>> +domid_t xs_get_self_id(void);
>>>>>> +
>>>>>> +#endif /* __XS_H__ */
>>>>>> diff --git a/plat/xen/xenbus/xs.c b/plat/xen/xenbus/xs.c
>>>>>> new file mode 100644
>>>>>> index 0000000..eb5131a
>>>>>> --- /dev/null
>>>>>> +++ b/plat/xen/xenbus/xs.c
>>>>>> @@ -0,0 +1,650 @@
>>>>>> +/* SPDX-License-Identifier: BSD-3-Clause */
>>>>>> +/*
>>>>>> + * Authors: Steven Smith (sos22@xxxxxxxxx)
>>>>>> + * Grzegorz Milos (gm281@xxxxxxxxx)
>>>>>> + * John D. Ramsdell
>>>>>> + * Costin Lupu <costin.lupu@xxxxxxxxx>
>>>>>> + *
>>>>>> + * Copyright (c) 2006, Cambridge University
>>>>>> + * 2018, NEC Europe Ltd., NEC Corporation. All rights
>>>>>> reserved.
>>>>>> + *
>>>>>> + * Redistribution and use in source and binary forms, with or without
>>>>>> + * modification, are permitted provided that the following conditions
>>>>>> + * are met:
>>>>>> + *
>>>>>> + * 1. Redistributions of source code must retain the above copyright
>>>>>> + * notice, this list of conditions and the following disclaimer.
>>>>>> + * 2. Redistributions in binary form must reproduce the above copyright
>>>>>> + * notice, this list of conditions and the following disclaimer in
>>>>>> the
>>>>>> + * documentation and/or other materials provided with the
>>>>>> distribution.
>>>>>> + * 3. Neither the name of the copyright holder nor the names of its
>>>>>> + * contributors may be used to endorse or promote products derived
>>>>>> from
>>>>>> + * this software without specific prior written permission.
>>>>>> + *
>>>>>> + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
>>>>>> "AS IS"
>>>>>> + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
>>>>>> TO, THE
>>>>>> + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
>>>>>> PURPOSE
>>>>>> + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
>>>>>> CONTRIBUTORS BE
>>>>>> + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
>>>>>> + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
>>>>>> + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
>>>>>> BUSINESS
>>>>>> + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
>>>>>> IN
>>>>>> + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
>>>>>> OTHERWISE)
>>>>>> + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
>>>>>> OF THE
>>>>>> + * POSSIBILITY OF SUCH DAMAGE.
>>>>>> + *
>>>>>> + * THIS HEADER MAY NOT BE EXTRACTED OR MODIFIED IN ANY WAY.
>>>>>> + */
>>>>>> +/*
>>>>>> + * Ported from Mini-OS xenbus.c
>>>>>> + */
>>>>>> +
>>>>>> +#include <stdlib.h>
>>>>>> +#include <stdio.h>
>>>>>> +#include <string.h>
>>>>>> +#include <stdint.h>
>>>>>> +#include <stdarg.h>
>>>>>> +#include <uk/errptr.h>
>>>>>> +#include <xen/io/xs_wire.h>
>>>>>> +#include <xenbus/xs.h>
>>>>>> +#include "xs_comms.h"
>>>>>> +
>>>>>> +
>>>>>> +/* Helper macro for initializing xs requests from strings
>>>>>> + * (w/ null terminator)
>>>>>> + */
>>>>>> +#define XS_IOVEC_STR(str) \
>>>>>> + ((struct xs_iovec) { str, strlen(str) + 1 })
>>>>>> +
>>>>>> +
>>>>>> +/* Common function used for sending requests when replies aren't
>>>>>> handled */
>>>>>> +static inline int xs_msg(enum xsd_sockmsg_type type,
>>>>>> xenbus_transaction_t xbt,
>>>>>> + struct xs_iovec *reqs, int reqs_num)
>>>>>> +{
>>>>>> + return xs_msg_reply(type, xbt, reqs, reqs_num, NULL);
>>>>>> +}
>>>>>> +
>>>>>> +char *xs_read(xenbus_transaction_t xbt, const char *path, const char
>>>>>> *node)
>>>>>> +{
>>>>>> + struct xs_iovec req, rep;
>>>>>> + char *fullpath, *value;
>>>>>> + int err;
>>>>>> +
>>>>>> + if (path == NULL)
>>>>>> + return ERR2PTR(EINVAL);
>>>>>> +
>>>>>> + if (node != NULL) {
>>>>>> + err = asprintf(&fullpath, "%s/%s", path, node);
>>>>>> + if (err < 0) {
>>>>>> + value = ERR2PTR(ENOMEM);
>>>>>> + goto out;
>>>>>> + }
>>>>>> + } else
>>>>>> + fullpath = (char *) path;
>>>>>> +
>>>>>> + req = XS_IOVEC_STR(fullpath);
>>>>>> + err = xs_msg_reply(XS_READ, xbt, &req, 1, &rep);
>>>>>> + if (err == 0)
>>>>>> + value = rep.data;
>>>>>> + else
>>>>>> + value = ERR2PTR(-err);
>>>>>> +
>>>>>> + if (node != NULL)
>>>>>> + free(fullpath);
>>>>>> +out:
>>>>>> + return value;
>>>>>> +}
>>>>>> +
>>>>>> +int xs_write(xenbus_transaction_t xbt, const char *path, const char
>>>>>> *node,
>>>>>> + const char *value)
>>>>>> +{
>>>>>> + struct xs_iovec req[2];
>>>>>> + char *fullpath;
>>>>>> + int err;
>>>>>> +
>>>>>> + if (path == NULL || value == NULL)
>>>>>> + return -EINVAL;
>>>>>> +
>>>>>> + if (node != NULL) {
>>>>>> + err = asprintf(&fullpath, "%s/%s", path, node);
>>>>>> + if (err < 0) {
>>>>>> + err = -ENOMEM;
>>>>>> + goto out;
>>>>>> + }
>>>>>> + } else
>>>>>> + fullpath = (char *) path;
>>>>>> +
>>>>>> + req[0] = XS_IOVEC_STR(fullpath);
>>>>>> + req[1] = XS_IOVEC_STR((char *) value);
>>>>>> +
>>>>>> + err = xs_msg(XS_WRITE, xbt, req, ARRAY_SIZE(req));
>>>>>> +
>>>>>> + if (node != NULL)
>>>>>> + free(fullpath);
>>>>>> +out:
>>>>>> + return err;
>>>>>> +}
>>>>>> +
>>>>>> +/* Returns an array of strings out of the serialized reply */
>>>>>> +static char **reply_to_string_array(struct xs_iovec *rep, int *size)
>>>>>> +{
>>>>>> + int strings_num, offs, i;
>>>>>> + char *rep_strings, *strings, **res = NULL;
>>>>>> +
>>>>>> + rep_strings = rep->data;
>>>>>> +
>>>>>> + /* count the strings */
>>>>>> + for (offs = strings_num = 0; offs < (int) rep->len; offs++)
>>>>>> + strings_num += (rep_strings[offs] == 0);
>>>>>> +
>>>>>> + /* one alloc for both string addresses and contents */
>>>>>> + res = malloc((strings_num + 1) * sizeof(char *) + rep->len);
>>>>>> + if (!res)
>>>>>> + return ERR2PTR(ENOMEM);
>>>>>> +
>>>>>> + /* copy the strings at the end of the array */
>>>>> _to_ the end of the array
>>>>
>>>> Fixed.
>>>>
>>>>>> + strings = (char *) &res[strings_num + 1];
>>>>>> + memcpy(strings, rep_strings, rep->len);
>>>>>> +
>>>>>> + /* fill the string array */
>>>>>> + for (offs = i = 0; i < strings_num; i++) {
>>>>>> + char *string = strings + offs;
>>>>>> + int string_len = strlen(string);
>>>>>> +
>>>>>> + res[i] = string;
>>>>>> +
>>>>>> + offs += string_len + 1;
>>>>>> + }
>>>>>> + res[i] = NULL;
>>>>>> +
>>>>>> + if (size)
>>>>>> + *size = strings_num;
>>>>>> +
>>>>>> + return res;
>>>>>> +}
>>>>>> +
>>>>>> +char **xs_ls(xenbus_transaction_t xbt, const char *path)
>>>>>> +{
>>>>>> + struct xs_iovec req, rep;
>>>>>> + char **res = NULL;
>>>>>> + int err;
>>>>>> +
>>>>>> + if (path == NULL)
>>>>>> + return ERR2PTR(EINVAL);
>>>>>> +
>>>>>> + req = XS_IOVEC_STR((char *) path);
>>>>>> + err = xs_msg_reply(XS_DIRECTORY, xbt, &req, 1, &rep);
>>>>>> + if (err)
>>>>>> + return ERR2PTR(-err);
>>>>>> +
>>>>>> + res = reply_to_string_array(&rep, NULL);
>>>>>> + free(rep.data);
>>>>>> +
>>>>>> + return res;
>>>>>> +}
>>>>>> +
>>>>>> +int xs_rm(xenbus_transaction_t xbt, const char *path)
>>>>>> +{
>>>>>> + struct xs_iovec req;
>>>>>> +
>>>>>> + if (path == NULL)
>>>>>> + return -EINVAL;
>>>>>> +
>>>>>> + req = XS_IOVEC_STR((char *) path);
>>>>>> +
>>>>>> + return xs_msg(XS_RM, xbt, &req, 1);
>>>>>> +}
>>>>>> +
>>>>>> +/*
>>>>>> + * Permissions
>>>>>> + */
>>>>>> +
>>>>>> +static const char xs_perm_tbl[] = {
>>>>>> + [XS_PERM_NONE] = 'n',
>>>>>> + [XS_PERM_READ] = 'r',
>>>>>> + [XS_PERM_WRITE] = 'w',
>>>>>> + [XS_PERM_BOTH] = 'b',
>>>>>> +};
>>>>>> +
>>>>>> +int xs_char_to_perm(char c, enum xs_perm *perm)
>>>>>> +{
>>>>>> + int err = -EINVAL;
>>>>>> +
>>>>>> + if (perm == NULL)
>>>>>> + goto out;
>>>>>> +
>>>>>> + for (int i = 0; i < (int) ARRAY_SIZE(xs_perm_tbl); i++) {
>>>>>> + if (c == xs_perm_tbl[i]) {
>>>>>> + *perm = i;
>>>>>> + err = 0;
>>>>>> + break;
>>>>>> + }
>>>>>> + }
>>>>>> +
>>>>>> +out:
>>>>>> + return err;
>>>>>> +}
>>>>>> +
>>>>>> +int xs_perm_to_char(enum xs_perm perm, char *c)
>>>>>> +{
>>>>>> + int err = -EINVAL;
>>>>>> +
>>>>>> + if (c == NULL)
>>>>>> + goto out;
>>>>>> +
>>>>>> + if (perm < ARRAY_SIZE(xs_perm_tbl)) {
>>>>>> + *c = xs_perm_tbl[perm];
>>>>>> + err = 0;
>>>>>> + }
>>>>>> +
>>>>>> +out:
>>>>>> + return err;
>>>>>> +}
>>>>> I don't mind this code, but consider this way:
>>>>>
>>>>> int xs_perm_to_char(enum xs_perm perm, char *c)
>>>>> {
>>>>> if (c == NULL || perm >= ARRAY_SIZE(xs_perm_tlb))
>>>>> return -EINVAL;
>>>>> *c = xs_perm_tbl[perm];
>>>>> return 0;
>>>>> }
>>>>>
>>>>
>>>> Ack.
>>>>
>>>>>> +
>>>>>> +int xs_str_to_perm(const char *str, domid_t *domid, enum xs_perm *perm)
>>>>>> +{
>>>>>> + int err = 0;
>>>>>> +
>>>>>> + if (str == NULL || domid == NULL || perm == NULL) {
>>>>>> + err = -EINVAL;
>>>>>> + goto out;
>>>>>> + }
>>>>>> +
>>>>>> + err = xs_char_to_perm(str[0], perm);
>>>>>> + if (err)
>>>>>> + goto out;
>>>>>> +
>>>>>> + *domid = (domid_t) strtoul(&str[1], NULL, 10);
>>>>>> +
>>>>>> +out:
>>>>>> + return err;
>>>>>> +}
>>>>>> +
>>>>>> +#define PERM_MAX_SIZE 32
>>>>>> +char *xs_perm_to_str(domid_t domid, enum xs_perm perm)
>>>>>> +{
>>>>>> + int err = 0;
>>>>>> + char permc, value[PERM_MAX_SIZE];
>>>>>> +
>>>>>> + err = xs_perm_to_char(perm, &permc);
>>>>>> + if (err)
>>>>>> + return NULL;
>>>>>> +
>>>>>> + snprintf(value, PERM_MAX_SIZE, "%c%hu", permc, domid);
>>>>>> +
>>>>>> + return strdup(value);
>>>>>> +}
>>>>>> +
>>>>>> +/*
>>>>>> + * Returns the ACL for input path. An extra number of empty entries may
>>>>>> be
>>>>>> + * requested if caller intends to extend the list.
>>>>>> + */
>>>>>> +static struct xs_acl *__xs_get_acl(xenbus_transaction_t xbt, const char
>>>>>> *path,
>>>>>> + int extra)
>>>>>> +{
>>>>>> + struct xs_acl *acl = NULL;
>>>>>> + struct xs_iovec req, rep;
>>>>>> + char **values;
>>>>>> + int values_num, err;
>>>>>> +
>>>>>> + if (path == NULL) {
>>>>>> + err = EINVAL;
>>>>>> + goto out;
>>>>>> + }
>>>>>> +
>>>>>> + req = XS_IOVEC_STR((char *) path);
>>>>>> + err = xs_msg_reply(XS_GET_PERMS, xbt, &req, 1, &rep);
>>>>>> + if (err)
>>>>>> + goto out;
>>>>>> +
>>>>>> + values = reply_to_string_array(&rep, &values_num);
>>>>>> + free(rep.data);
>>>>>> + if (PTRISERR(values)) {
>>>>>> + err = PTR2ERR(values);
>>>>>> + goto out;
>>>>>> + }
>>>>>> +
>>>>>> + acl = malloc(sizeof(struct xs_acl) +
>>>>>> + (values_num + extra) * sizeof(struct xs_acl_entry));
>>>>>> + if (acl == NULL) {
>>>>>> + err = ENOMEM;
>>>>>> + goto out_values;
>>>>>> + }
>>>>>> +
>>>>>> + /* set owner id and permissions for others */
>>>>>> + err = xs_str_to_perm(values[0],
>>>>>> + &acl->ownerid, &acl->others_perm);
>>>>>> + if (err)
>>>>>> + goto out_values;
>>>>>> +
>>>>>> + /* set ACL entries */
>>>>>> + acl->entries_num = values_num - 1;
>>>>>> + for (int i = 0; i < acl->entries_num; i++) {
>>>>>> + err = xs_str_to_perm(values[i + 1],
>>>>>> + &acl->entries[i].domid, &acl->entries[i].perm);
>>>>>> + if (err)
>>>>>> + goto out_values;
>>>>>> + }
>>>>>> +
>>>>>> +out_values:
>>>>>> + free(values);
>>>>>> +out:
>>>>>> + if (err) {
>>>>>> + if (acl)
>>>>>> + free(acl);
>>>>>> + acl = ERR2PTR(-err);
>>>>>> + }
>>>>>> + return acl;
>>>>>> +}
>>>>>> +
>>>>>> +struct xs_acl *xs_get_acl(xenbus_transaction_t xbt, const char *path)
>>>>>> +{
>>>>>> + return __xs_get_acl(xbt, path, 0);
>>>>>> +}
>>>>>> +
>>>>>> +int xs_set_acl(xenbus_transaction_t xbt, const char *path, struct
>>>>>> xs_acl *acl)
>>>>>> +{
>>>>>> + struct xs_iovec req[2 + acl->entries_num];
>>>>>> + char *s;
>>>>>> + int i, err;
>>>>>> +
>>>>>> + if (path == NULL || acl == NULL) {
>>>>>> + err = -EINVAL;
>>>>>> + goto out;
>>>>>> + }
>>>>>> +
>>>>>> + req[0] = XS_IOVEC_STR((char *) path);
>>>>>> +
>>>>>> + s = xs_perm_to_str(acl->ownerid, acl->others_perm);
>>>>>> + if (s == NULL) {
>>>>>> + err = -EINVAL;
>>>>>> + goto out;
>>>>>> + }
>>>>>> +
>>>>>> + req[1].data = s;
>>>>>> + req[1].len = strlen(s) + 1;
>>>>>> +
>>>>>> + for (i = 0; i < acl->entries_num; i++) {
>>>>>> + struct xs_acl_entry *acle = &acl->entries[i];
>>>>>> +
>>>>>> + s = xs_perm_to_str(acle->domid, acle->perm);
>>>>>> + if (s == NULL) {
>>>>>> + err = -EINVAL;
>>>>>> + goto out_req;
>>>>>> + }
>>>>>> +
>>>>>> + req[i + 2].data = s;
>>>>>> + req[i + 2].len = strlen(s) + 1;
>>>>> I think you can use XS_IOVEC_STR macro here too. For the sake of
>>>>> consistency.
>>>>>
>>>>
>>>> Fixed.
>>>>
>>>>>> + }
>>>>>> +
>>>>>> + err = xs_msg(XS_SET_PERMS, xbt, req, ARRAY_SIZE(req));
>>>>>> +
>>>>>> +out_req:
>>>>>> + for (i--; i > 0; i--)
>>>>>> + free(req[i].data);
>>>>>> +out:
>>>>>> + return err;
>>>>>> +}
>>>>>> +
>>>>>> +int xs_get_perms(xenbus_transaction_t xbt, const char *path,
>>>>>> + domid_t domid, enum xs_perm *perm)
>>>>> The functions gets only one permission. How about to rename it to
>>>>> xs_get_perm. Same about xs_set_perms
>>>>>
>>>>
>>>> Ack.
>>>>
>>>>>> +{
>>>>>> + struct xs_acl *acl;
>>>>>> + int err = 0;
>>>>>> +
>>>>>> + if (perm == NULL) {
>>>>>> + err = -EINVAL;
>>>>>> + goto out;
>>>>>> + }
>>>>>> +
>>>>>> + acl = xs_get_acl(xbt, path);
>>>>>> + if (PTRISERR(acl)) {
>>>>>> + err = PTR2ERR(acl);
>>>>>> + goto out;
>>>>>> + }
>>>>>> +
>>>>>> + if (acl->ownerid == domid) {
>>>>>> + *perm = XS_PERM_BOTH;
>>>>>> + goto out_acl;
>>>>>> + }
>>>>>> +
>>>>>> + for (int i = 0; i < acl->entries_num; i++) {
>>>>>> + struct xs_acl_entry *acle = &acl->entries[i];
>>>>>> +
>>>>>> + if (acle->domid == domid) {
>>>>>> + *perm = acle->perm;
>>>>>> + goto out_acl;
>>>>>> + }
>>>>>> + }
>>>>>> +
>>>>>> + *perm = acl->others_perm;
>>>>>> +
>>>>>> +out_acl:
>>>>>> + free(acl);
>>>>>> +out:
>>>>>> + return err;
>>>>>> +}
>>>>>> +
>>>>>> +int xs_set_perms(xenbus_transaction_t xbt, const char *path,
>>>>>> + domid_t domid, enum xs_perm perm)
>>>>>> +{
>>>>>> + struct xs_acl *acl;
>>>>>> + struct xs_acl_entry *acle;
>>>>>> + int i, err = 0;
>>>>>> +
>>>>>> + /* one extra entry in case a new one will be added */
>>>>>> + acl = __xs_get_acl(xbt, path, 1);
>>>>>> + if (PTRISERR(acl)) {
>>>>>> + err = PTR2ERR(acl);
>>>>>> + goto out;
>>>>>> + }
>>>>> If somebody else (e.g. dom0) will be changing acl of this path at the
>>>>> same time, it might be that only one operation will be successful. I
>>>>> would start a transaction if xbt==0 or add some check. Either return
>>>>> with an error, or add debug assert, or at least print a warning. However
>>>>> warnings need to be rate limited, which we do not have yet.
>>>>>
>>>>
>>>> Starting a transaction here would defeat the purpose of this API. It's
>>>> the client (caller) responsability to take care of the atomicity of her
>>>> operations. Therefore, in that case one should start the transaction
>>>> before calling this function.
>>>>
>>>> We might have paths for which only the caller domain would have
>>>> permissions.
>>> Isn't the dom0 always have a permission?
>>>
>>
>> Please allow me to answer with a question here: what if Unikraft is
>> dom0? :-) Joking aside, the intention behind this API is to allow a
>> higher level of flexibility and to be as simple as possible.
> If we are dom0, then the domain-owner of this path still can modify it.
>
> That is error prone to do a multistep operation non-atomically. If you
> think a higher level API should ensure transaction, then do an assert in
> this function to check if transaction is registered. For more
> flexibility one should use lower level functions. Especially since the
> xs_set_perm(s) is pretty high level function and does not provide much
> flexibility.
>
> We can remove this check later if we have a good reason to. Currently I
> don't see one..
>
Alright, assert it is.
>>
>>>> More than that, we would know for sure for a given path, that no one
>>>> else would change it.
>>> Of course, other domains can promise that they would never write to this
>>> path. But if we could trust them, this whole permission thing would not
>>> be needed. At the very least, a human might make this modification by
>>> issuing xenstore-* commands.
>>>
>>
>> I don't think we should make a decision here for the client whether he
>> trusts the other domains or not. This is just an API for interacting
>> with the Xenstore. The security policies should be enforced elsewhere.
>>
>>>> Another case would be if we are simply not interested in keeping the
>>>> old permissions.
>>> The function xs_set_perms does not provide a way to change all
>>> permissions at once. It does modify/add only one permission at one
>>> time. That means if I want to grand permission to 3 different domains, I
>>> have to call this function 3 times. Every time it needs to read existing
>>> permissions, make changes, and write them back.
>>>
>>
>> I don't understand what this comment has to do with my observation.
> From my understanding you observation was not completely valid (see
> below).
>
>> However, this is the exact purpose of xs_set_perms function: to set
>> permissions for a single domain. If you want more domains at once, then
>> you should use the ACL functions.
> So, if you not interested in keeping the old permissions you should use
> the ACL functions you just mentioned. Otherwise you operation might be
> not successful:
>
> step Dom0 Our Dom
> ───────────────────────────────────────────────────────────────
> 1 reads acl for the path
> "r0 w124 r125"
>
> 2 reads the same acl
> "r0 w124 r125"
>
> 3 adds one more entry disregard of our interest in
> in memory old permissions, we can change
> "r0 w124 r125 w126" only one permission at once, so
> we change it (in memory) to
> "r0 r124 r125"
>
> 4 writes new permissions
> "n0 w555"
>
> 5 writes new permissions
> "r0 w124 r125 w126
>
>
>
>> Again, these xs_{set,get}_perm functions are there just to help the
>> developer when she wants to set the permissions for a single domain
>> since this is only a routine. The API and the implementation should be
>> as simple and clear as possible.
>>
>> Since I don't endorse providing atomicity here, I suggest we should add
>> a patch doing it after upstreaming this patch series.
>>
>>>>
>>>> Long story short, this approach adds more flexbility. I think the best
>>>> solution here would be to add some comments in the function description
>>>> in order to clarify this behavior.
>>>>
>>>>>> +
>>>>>> + if (acl->ownerid == domid) {
>>>>>> + /*
>>>>>> + * let's say the function isn't called correctly
>>>>>> considering
>>>>>> + * that the owner domain has all the rights, all the
>>>>>> time
>>>>>> + */
>>>>>> + err = -EINVAL;
>>>>>> + goto out_acl;
>>>>>> + }
>>>>>> +
>>>>>> + for (i = 0, acle = &acl->entries[i]; i < acl->entries_num; i++)
>>>>>> {
>>>>>> + if (acle->domid == domid)
>>>>>> + break;
>>>>>> + }
>>>>>> +
>>>>>> + if (perm != XS_PERM_NONE) {
>>>>>> + if (i == acl->entries_num) {
>>>>>> + /* new entry */
>>>>>> + acle->domid = domid;
>>>>>> + acl->entries_num++;
>>>>>> + }
>>>>>> +
>>>>>> + acle->perm = perm;
>>>>>> +
>>>>>> + } else {
>>>>>> + if (i == acl->entries_num) {
>>>>>> + /* no entry */
>>>>>> + err = -ENOENT;
>>>>>> + goto out_acl;
>>>>>> + }
>>>>>> + /* remove entry */
>>>>>> + acl->entries_num--;
>>>>>> + memmove(&acl->entries[i], &acl->entries[i + 1],
>>>>>> + (acl->entries_num - i) * sizeof(struct
>>>>>> xs_acl_entry));
>>>>> From my shallow understanding, if acl->others_perm == XS_PERM_READ,
>>>>> deleting an acl entry for the path will effectively grand reading
>>>>> permission. Maybe the goal was to block this particular domain from
>>>>> reading this path, while allowing everybody else.
>>>>>
>>>>> Anyways, this is a bit unexpected. I asked to change permission for
>>>>> particular domain to XS_NONE, but the function deletes it instead. I
>>>>> guess a separate function is needed for deletion
>>>>>
>>>>
>>>> Right. In v3 I will add xs_del_perm function.
>>>>
>>>>>> + }
>>>>>> +
>>>>>> + err = xs_set_acl(xbt, path, acl);
>>>>>> +
>>>>>> +out_acl:
>>>>>> + free(acl);
>>>>>> +out:
>>>>>> + return err;
>>>>>> +}
>>>>>> +
>>>>>> +/*
>>>>>> + * Transactions
>>>>>> + */
>>>>>> +
>>>>>> +int xs_transaction_start(xenbus_transaction_t *xbt)
>>>>>> +{
>>>>>> + /*
>>>>>> + * xenstored becomes angry if you send a length 0 message,
>>>>>> + * so just shove a nul terminator on the end
>>>>>> + */
>>>>>> + struct xs_iovec req, rep;
>>>>>> + int err;
>>>>>> +
>>>>>> + if (xbt == NULL)
>>>>>> + return -EINVAL;
>>>>>> +
>>>>>> + req = XS_IOVEC_STR("");
>>>>>> + err = xs_msg_reply(XS_TRANSACTION_START, 0, &req, 1, &rep);
>>>>>> + if (err)
>>>>>> + return err;
>>>>>> +
>>>>>> + *xbt = strtoul(rep.data, NULL, 10);
>>>>>> + free(rep.data);
>>>>>> +
>>>>>> + return err;
>>>>>> +}
>>>>>> +
>>>>>> +int xs_transaction_end(xenbus_transaction_t xbt, int abort)
>>>>>> +{
>>>>>> + struct xs_iovec req;
>>>>>> +
>>>>>> + req.data = abort ? "F" : "T";
>>>>>> + req.len = 2;
>>>>>> +
>>>>>> + return xs_msg(XS_TRANSACTION_END, xbt, &req, 1);
>>>>>> +}
>>>>>> +
>>>>>> +/*
>>>>>> + * Misc
>>>>>> + */
>>>>>> +
>>>>>> +/* Send a debug message to xenbus. Can block. */
>>>>>> +int xs_debug_msg(const char *msg)
>>>>>> +{
>>>>>> + struct xs_iovec req[3], rep;
>>>>>> + int err;
>>>>>> +
>>>>>> + if (msg == NULL)
>>>>>> + return -EINVAL;
>>>>>> +
>>>>>> + req[0] = XS_IOVEC_STR("print");
>>>>>> + req[1] = XS_IOVEC_STR((char *) msg);
>>>>>> + req[2] = XS_IOVEC_STR("");
>>>>>> +
>>>>>> + err = xs_msg_reply(XS_DEBUG, XBT_NIL, req, ARRAY_SIZE(req),
>>>>>> &rep);
>>>>>> + if (err)
>>>>>> + goto out;
>>>>>> +
>>>>>> + uk_printd(DLVL_EXTRA,
>>>>>> + "Got a debug reply %s\n", (char *) rep.data);
>>>>>> + free(rep.data);
>>>>>> +
>>>>>> +out:
>>>>>> + return err;
>>>>>> +}
>>>>>> +
>>>>>> +int xs_read_integer(const char *path, int *value)
>>>>>> +{
>>>>>> + char *value_str;
>>>>>> +
>>>>>> + if (path == NULL || value == NULL)
>>>>>> + return -EINVAL;
>>>>>> +
>>>>>> + value_str = xs_read(XBT_NIL, path, NULL);
>>>>>> + if (PTRISERR(value_str))
>>>>>> + return PTR2ERR(value_str);
>>>>>> +
>>>>>> + *value = atoi(value_str);
>>>>>> +
>>>>>> + free(value_str);
>>>>>> +
>>>>>> + return 0;
>>>>>> +}
>>>>>> +
>>>>>> +int xs_scanf(xenbus_transaction_t xbt, const char *dir, const char
>>>>>> *node,
>>>>>> + const char *fmt, ...)
>>>>>> +{
>>>>>> +#define FULLPATH_SIZE 256
>>>>>> + char fullpath[FULLPATH_SIZE];
>>>>>> + char *val;
>>>>>> + va_list args;
>>>>>> + int err = 0;
>>>>>> +
>>>>>> + if (dir == NULL || node == NULL || fmt == NULL)
>>>>>> + return -EINVAL;
>>>>> I guess this is not precisely mimicking scanf behavior. And this is
>>>>> fine. Maybe worth to put a comment "returns the number of input items
>>>>> successfully matched or (-err)". Same applies to xs_printf.
>>>>>
>>>>
>>>> The function description (in xs.h) says exactly that: on success it
>>>> behaves like sscanf, on error it returns a negative number. Same for
>>>> xs_printf.
>>> Oh, missed that. However, because the first sentence starts with "Just
>>> like sprintf..", I would start the second sentence with "Contrary to
>>> sprintf.."
>>>
>>
>> I'll just remove the references to sscanf/sprintf in the text about the
>> return values in order to avoid any further confusions.
>>
>>>>
>>>>>> +
>>>>>> + if (strlen(dir) + strlen(node) + 1 >= FULLPATH_SIZE)
>>>>>> + return -ENOMEM;
>>>>>> +
>>>>>> + sprintf(fullpath, "%s/%s", dir, node);
>>>>> But xs_read does path concatenation. I think we can offload this work to
>>>>> xs_read. This also will make it possible to have node == Null. Not sure
>>>>> if you need it, but you will get it for free.
>>>>>
>>>>> If it is done to save a memory allocation in xs_read, well, xs_read can
>>>>> get a simple optimization - allocate fullpath only if more then 256
>>>>> bytes are needed. Otherwise use on-stack buffer.
>>>>>
>>>>> Same applies to xs_printf
>>>>>
>>>>
>>>> Fixed, using xs_read now.
>>>>
>>>>>> +
>>>>>> + val = xs_read(xbt, fullpath, NULL);
>>>>>> + if (PTRISERR(val)) {
>>>>>> + err = PTR2ERR(val);
>>>>> This will lead to positive value in err. But in the "out" section you
>>>>> expect it be negative. I believe we have to invert it hire. Please
>>>>> revise other places in the code for the same time of problems.
>>>>>
>>>>
>>>> Right. I think we need to clarify this issue. With the current
>>>> implementation of PTR*ERR macros, we can support only positive error
>>>> numbers. More than that, when we need to convert the error number back
>>>> from pointer with PTR2ERR() we must always invert it. So, we have 2
>>>> options:
>>>> 1) keeping PTR*ERR macros like this and always reverting PTR2ERR value
>>>> 2) changing the macros to the way Linux does it, which does not need to
>>>> invert PTR2ERR value.
>>>>
>>>> Yuri, what do you think?
>>> I actually prefer the linux way, it looks a bit more convenient. That is
>>> probably not too late to change this.
>>>
>>
>> Agreed.
>>
>>>>
>>>>>> + goto out;
>>>>>> + }
>>>>>> +
>>>>>> + va_start(args, fmt);
>>>>>> + err = vsscanf(val, fmt, args);
>>>>>> + va_end(args);
>>>>>> +
>>>>>> + free(val);
>>>>>> +
>>>>>> +out:
>>>>>> + return err;
>>>>>> +}
>>>>>> +
>>>>>> +int xs_printf(xenbus_transaction_t xbt, const char *dir, const char
>>>>>> *node,
>>>>>> + const char *fmt, ...)
>>>>>> +{
>>>>>> + char fullpath[FULLPATH_SIZE];
>>>>>> + char val[FULLPATH_SIZE];
>>>>>> + va_list args;
>>>>>> + int err, _err;
>>>>>> +
>>>>>> + if (dir == NULL || node == NULL || fmt == NULL)
>>>>>> + return -EINVAL;
>>>>>> +
>>>>>> + if (strlen(dir) + strlen(node) + 1 >= FULLPATH_SIZE)
>>>>>> + return -ENOMEM;
>>>>>> +
>>>>>> + sprintf(fullpath, "%s/%s", dir, node);
>>>>>> +
>>>>>> + va_start(args, fmt);
>>>>>> + _err = vsprintf(val, fmt, args);
>>>>> vsnprintf MUST be used here. The val is limited with FULLPATH_SIZE. Same
>>>>> about printf-ing into fullpath (obviously in xs_scanf too), if you
>>>>> decided not to rely on xs_write to concatenate path and node.
>>>>>
>>>>
>>>> Fixed.
>>>>
>>>>>> + va_end(args);
>>>>>> +
>>>>>> + /* send to Xenstore iff vsprintf was successful */
>>>>> Typo in iff
>>>>>
>>>>
>>>> Actually iff stands for "if and only if". I set it to if now to avoid
>>>> further confusion.
>>>>
>>>>>> + if (_err > 0)
>>>>>> + err = xs_write(xbt, fullpath, NULL, val);
>>>>>> +
>>>>>> + /*
>>>>>> + * if message sent to Xenstore was successful,
>>>>>> + * return the number of characters
>>>>>> + */
>>>>>> + if (err == 0)
>>>>>> + err = _err;
>>>>>> +
>>>>>> + return err;
>>>>>> +}
>>>>>> +> +domid_t xs_get_self_id(void)
>>>>>> +{
>>>>>> + char *domid_str;
>>>>>> + domid_t domid;
>>>>>> +
>>>>>> + domid_str = xs_read(XBT_NIL, "domid", NULL);
>>>>>> + if (PTRISERR(domid_str))
>>>>>> + UK_CRASH("Error reading domain id.");
>>>>>> +
>>>>>> + domid = (domid_t) strtoul(domid_str, NULL, 10);
>>>>>> +
>>>>>> + free(domid_str);
>>>>>> +
>>>>>> + return domid;
>>>>>> +}
>>>>>> --
>>>>>> 2.11.0
>>>>>>
>>>>>
>>>
>>
>
_______________________________________________
Minios-devel mailing list
Minios-devel@xxxxxxxxxxxxxxxxxxxx
https://lists.xenproject.org/mailman/listinfo/minios-devel
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |