[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

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.