Date: Mon, 18 Jun 2018 22:57:32 +0000 (UTC) From: Mariusz Zaborski <oshogbo@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r335347 - in head: lib/libnv/tests share/man/man9 sys/contrib/libnv sys/sys Message-ID: <201806182257.w5IMvWH7036479@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: oshogbo Date: Mon Jun 18 22:57:32 2018 New Revision: 335347 URL: https://svnweb.freebsd.org/changeset/base/335347 Log: libnv: Add nvlist_append_*_array() family of functions. The nvlist_append_{bool,number,string,nvlist,descriptor}_array() functions allows to dynamically extend array stored in the nvlist. Submitted by: Mindaugas Rasiukevicius <rmind@netbsd.org> Added: head/lib/libnv/tests/nvlist_append_test.c (contents, props changed) Modified: head/lib/libnv/tests/Makefile head/share/man/man9/nv.9 head/sys/contrib/libnv/nv_impl.h head/sys/contrib/libnv/nvlist.c head/sys/contrib/libnv/nvpair.c head/sys/sys/nv.h Modified: head/lib/libnv/tests/Makefile ============================================================================== --- head/lib/libnv/tests/Makefile Mon Jun 18 22:27:29 2018 (r335346) +++ head/lib/libnv/tests/Makefile Mon Jun 18 22:57:32 2018 (r335347) @@ -7,6 +7,7 @@ ATF_TESTS_CXX= \ nv_tests \ TAP_TESTS_C+= nvlist_add_test +TAP_TESTS_C+= nvlist_append_test TAP_TESTS_C+= nvlist_exists_test TAP_TESTS_C+= nvlist_free_test TAP_TESTS_C+= nvlist_get_test Added: head/lib/libnv/tests/nvlist_append_test.c ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/lib/libnv/tests/nvlist_append_test.c Mon Jun 18 22:57:32 2018 (r335347) @@ -0,0 +1,120 @@ +/*- + * Copyright (c) 2018 The NetBSD Foundation, Inc. + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + * + * $FreeBSD$ + */ + +#include <sys/nv.h> + +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +static int ntest = 1; + +#define CHECK(expr) do { \ + if ((expr)) \ + printf("ok # %d %s:%u\n", ntest, __FILE__, __LINE__); \ + else \ + printf("not ok # %d %s:%u\n", ntest, __FILE__, __LINE__);\ + ntest++; \ +} while (0) + +int +main(void) +{ + const bool *bool_result; + const char * const *string_result; + const nvlist_t * const *nvl_result; + nvlist_t *nvl, *nvl1, *nvl2, **items; + unsigned int i; + size_t nitems; + + printf("1..32\n"); + + nvl = nvlist_create(0); + + for (i = 0; i < 16; i++) + nvlist_append_bool_array(nvl, "nvl/bool", i % 2 == 0); + + CHECK(nvlist_error(nvl) == 0); + CHECK(!nvlist_empty(nvl)); + CHECK(nvlist_exists_bool_array(nvl, "nvl/bool")); + + bool_result = nvlist_get_bool_array(nvl, "nvl/bool", &nitems); + CHECK(nitems == 16); + CHECK(bool_result != NULL); + for (i = 0; i < nitems; i++) + CHECK(bool_result[i] == (i % 2 == 0)); + + + nvlist_append_string_array(nvl, "nvl/string", "a"); + nvlist_append_string_array(nvl, "nvl/string", "abc"); + string_result = nvlist_get_string_array(nvl, "nvl/string", &nitems); + CHECK(nitems == 2); + CHECK(strcmp(string_result[0], "a") == 0); + CHECK(strcmp(string_result[1], "abc") == 0); + + + nvl1 = nvlist_create(0); + nvlist_add_string(nvl1, "key1", "test1"); + nvlist_append_nvlist_array(nvl, "nvl/nvl", nvl1); + nvlist_destroy(nvl1); + + nvl2 = nvlist_create(0); + nvlist_add_string(nvl2, "key2", "test2"); + nvlist_append_nvlist_array(nvl, "nvl/nvl", nvl2); + nvlist_destroy(nvl2); + + nvl_result = nvlist_get_nvlist_array(nvl, "nvl/nvl", &nitems); + CHECK(nitems == 2); + CHECK(strcmp(nvlist_get_string(nvl_result[0], "key1"), "test1") == 0); + CHECK(strcmp(nvlist_get_string(nvl_result[1], "key2"), "test2") == 0); + + nvl1 = nvlist_create(0); + nvlist_add_number(nvl1, "key1", 10); + nvlist_append_nvlist_array(nvl, "nvl/nvl_array", nvl1); + nvlist_destroy(nvl1); + + nvl2 = nvlist_create(0); + nvlist_add_number(nvl2, "key1", 20); + nvlist_append_nvlist_array(nvl, "nvl/nvl_array", nvl2); + nvlist_destroy(nvl2); + + items = nvlist_take_nvlist_array(nvl, "nvl/nvl_array", &nitems); + CHECK(nvlist_get_number(items[0], "key1") == 10); + CHECK(nvlist_get_number(items[1], "key1") == 20); + CHECK(nvlist_error(items[0]) == 0); + CHECK(nvlist_error(items[1]) == 0); + + nvlist_move_nvlist_array(nvl, "nvl/nvl_new_array", items, nitems); + CHECK(nvlist_error(nvl) == 0); + + nvlist_destroy(nvl); + + return (0); +} Modified: head/share/man/man9/nv.9 ============================================================================== --- head/share/man/man9/nv.9 Mon Jun 18 22:27:29 2018 (r335346) +++ head/share/man/man9/nv.9 Mon Jun 18 22:57:32 2018 (r335347) @@ -29,7 +29,7 @@ .\" .\" $FreeBSD$ .\" -.Dd September 16, 2017 +.Dd June 19, 2018 .Dt NV 9 .Os .Sh NAME @@ -55,7 +55,8 @@ .Nm nvlist_add , .Nm nvlist_move , .Nm nvlist_get , -.Nm nvlist_take +.Nm nvlist_take , +.Nm nvlist_append .Nd "library for name/value pairs" .Sh LIBRARY .Lb libnv @@ -239,6 +240,17 @@ .Fn nvlist_take_descriptor_array "nvlist_t *nvl" "const char *name" "size_t *nitems" .\" .Ft void +.Fn nvlist_append_bool_array "nvlist_t *nvl" "const char *name" "const bool value" +.Ft void +.Fn nvlist_append_number_array "nvlist_t *nvl" "const char *name" "const uint64_t value" +.Ft void +.Fn nvlist_append_string_array "nvlist_t *nvl" "const char *name" "const char * const value" +.Ft void +.Fn nvlist_append_nvlist_array "nvlist_t *nvl" "const char *name" "const nvlist_t * const value" +.Ft void +.Fn nvlist_append_descriptor_array "nvlist_t *nvl" "const char *name" "int value" +.\" +.Ft void .Fn nvlist_free "nvlist_t *nvl" "const char *name" .Ft void .Fn nvlist_free_type "nvlist_t *nvl" "const char *name" "int type" @@ -708,6 +720,20 @@ the array using the .Xr free 3 function. The nvlist must not be in error state. +.Pp +The +.Fn nvlist_append_bool_array , +.Fn nvlist_append_number_array , +.Fn nvlist_append_string_array , +.Fn nvlist_append_nvlist_array , +.Fn nvlist_append_descriptor_array +functions append an element to the existing array using the same semantics +as the add functions (i.e. the element will be copied when applicable). +If the array for a given key does not exist, then it will be created +as if using the +.Fn nvlist_add_<type>_array +function. +The internal error is set on append failure. .Pp The .Fn nvlist_free Modified: head/sys/contrib/libnv/nv_impl.h ============================================================================== --- head/sys/contrib/libnv/nv_impl.h Mon Jun 18 22:27:29 2018 (r335346) +++ head/sys/contrib/libnv/nv_impl.h Mon Jun 18 22:57:32 2018 (r335347) @@ -143,6 +143,12 @@ nvpair_t *nvpair_move_descriptor_array(const char *nam nvpair_t *nvpair_move_number_array(const char *name, uint64_t *value, size_t nitems); nvpair_t *nvpair_move_string_array(const char *name, char **value, size_t nitems); +int nvpair_append_bool_array(nvpair_t *nvp, const bool value); +int nvpair_append_number_array(nvpair_t *nvp, const uint64_t value); +int nvpair_append_string_array(nvpair_t *nvp, const char *value); +int nvpair_append_nvlist_array(nvpair_t *nvp, const nvlist_t *value); +int nvpair_append_descriptor_array(nvpair_t *nvp, const int value); + bool nvpair_get_bool(const nvpair_t *nvp); uint64_t nvpair_get_number(const nvpair_t *nvp); const char *nvpair_get_string(const nvpair_t *nvp); Modified: head/sys/contrib/libnv/nvlist.c ============================================================================== --- head/sys/contrib/libnv/nvlist.c Mon Jun 18 22:27:29 2018 (r335346) +++ head/sys/contrib/libnv/nvlist.c Mon Jun 18 22:57:32 2018 (r335347) @@ -1607,6 +1607,37 @@ NVLIST_ADD_ARRAY(const int *, descriptor) #undef NVLIST_ADD_ARRAY +#define NVLIST_APPEND_ARRAY(vtype, type, TYPE) \ +void \ +nvlist_append_##type##_array(nvlist_t *nvl, const char *name, vtype value)\ +{ \ + nvpair_t *nvp; \ + \ + if (nvlist_error(nvl) != 0) { \ + ERRNO_SET(nvlist_error(nvl)); \ + return; \ + } \ + nvp = nvlist_find(nvl, NV_TYPE_##TYPE##_ARRAY, name); \ + if (nvp == NULL) { \ + nvlist_add_##type##_array(nvl, name, &value, 1); \ + return; \ + } \ + if (nvpair_append_##type##_array(nvp, value) == -1) { \ + nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM); \ + ERRNO_SET(nvl->nvl_error); \ + } \ +} + +NVLIST_APPEND_ARRAY(const bool, bool, BOOL) +NVLIST_APPEND_ARRAY(const uint64_t, number, NUMBER) +NVLIST_APPEND_ARRAY(const char *, string, STRING) +NVLIST_APPEND_ARRAY(const nvlist_t *, nvlist, NVLIST) +#ifndef _KERNEL +NVLIST_APPEND_ARRAY(const int, descriptor, DESCRIPTOR) +#endif + +#undef NVLIST_APPEND_ARRAY + bool nvlist_move_nvpair(nvlist_t *nvl, nvpair_t *nvp) { Modified: head/sys/contrib/libnv/nvpair.c ============================================================================== --- head/sys/contrib/libnv/nvpair.c Mon Jun 18 22:27:29 2018 (r335346) +++ head/sys/contrib/libnv/nvpair.c Mon Jun 18 22:57:32 2018 (r335347) @@ -144,6 +144,28 @@ nvpair_allocv(const char *name, int type, uint64_t dat return (nvp); } +static int +nvpair_append(nvpair_t *nvp, const void *value, size_t valsize, size_t datasize) +{ + void *olddata, *data, *valp; + size_t oldlen; + + oldlen = nvp->nvp_nitems * valsize; + olddata = (void *)(uintptr_t)nvp->nvp_data; + data = nv_realloc(olddata, oldlen + valsize); + if (data == NULL) { + ERRNO_SET(ENOMEM); + return (-1); + } + valp = (unsigned char *)data + oldlen; + memcpy(valp, value, valsize); + + nvp->nvp_data = (uint64_t)(uintptr_t)data; + nvp->nvp_datasize += datasize; + nvp->nvp_nitems++; + return (0); +} + nvlist_t * nvpair_nvlist(const nvpair_t *nvp) { @@ -1910,6 +1932,121 @@ nvpair_get_descriptor_array(const nvpair_t *nvp, size_ *nitems = nvp->nvp_nitems; return ((const int *)(intptr_t)nvp->nvp_data); +} +#endif + +int +nvpair_append_bool_array(nvpair_t *nvp, const bool value) +{ + + NVPAIR_ASSERT(nvp); + PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_BOOL_ARRAY); + return (nvpair_append(nvp, &value, sizeof(value), sizeof(value))); +} + +int +nvpair_append_number_array(nvpair_t *nvp, const uint64_t value) +{ + + NVPAIR_ASSERT(nvp); + PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_NUMBER_ARRAY); + return (nvpair_append(nvp, &value, sizeof(value), sizeof(value))); +} + +int +nvpair_append_string_array(nvpair_t *nvp, const char *value) +{ + char *str; + + NVPAIR_ASSERT(nvp); + PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_STRING_ARRAY); + if (value == NULL) { + ERRNO_SET(EINVAL); + return (-1); + } + str = nv_strdup(value); + if (str == NULL) { + return (-1); + } + if (nvpair_append(nvp, &str, sizeof(str), strlen(str) + 1) == -1) { + nv_free(str); + return (-1); + } + return (0); +} + +int +nvpair_append_nvlist_array(nvpair_t *nvp, const nvlist_t *value) +{ + nvpair_t *tmpnvp; + nvlist_t *nvl, *prev; + int flags; + + NVPAIR_ASSERT(nvp); + PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_NVLIST_ARRAY); + if (value == NULL || nvlist_error(value) != 0 || + nvlist_get_pararr(value, NULL) != NULL) { + ERRNO_SET(EINVAL); + return (-1); + } + nvl = nvlist_clone(value); + if (nvl == NULL) { + return (-1); + } + flags = nvlist_flags(nvl) | NV_FLAG_IN_ARRAY; + nvlist_set_flags(nvl, flags); + + tmpnvp = NULL; + if (nvp->nvp_nitems > 0) { + nvlist_t **nvls = (void *)(uintptr_t)nvp->nvp_data; + + prev = nvls[nvp->nvp_nitems - 1]; + PJDLOG_ASSERT(prev != NULL); + + tmpnvp = nvpair_allocv(" ", NV_TYPE_NVLIST, + (uint64_t)(uintptr_t)nvl, 0, 0); + if (tmpnvp == NULL) { + goto fail; + } + } + if (nvpair_append(nvp, &nvl, sizeof(nvl), 0) == -1) { + goto fail; + } + if (tmpnvp) { + NVPAIR_ASSERT(tmpnvp); + nvlist_set_array_next(prev, tmpnvp); + } + nvlist_set_parent(nvl, nvp); + return (0); +fail: + if (tmpnvp) { + nvpair_free(tmpnvp); + } + nvlist_destroy(nvl); + return (-1); +} + +#ifndef _KERNEL +int +nvpair_append_descriptor_array(nvpair_t *nvp, const int value) +{ + int fd; + + NVPAIR_ASSERT(nvp); + PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_DESCRIPTOR_ARRAY); + if (value < 0 || !fd_is_valid(value)) { + ERRNO_SET(EBADF); + return -1; + } + fd = fcntl(value, F_DUPFD_CLOEXEC, 0); + if (fd == -1) { + return (-1); + } + if (nvpair_append(nvp, &fd, sizeof(fd), sizeof(fd)) == -1) { + close(fd); + return (-1); + } + return (0); } #endif Modified: head/sys/sys/nv.h ============================================================================== --- head/sys/sys/nv.h Mon Jun 18 22:27:29 2018 (r335346) +++ head/sys/sys/nv.h Mon Jun 18 22:57:32 2018 (r335347) @@ -162,6 +162,14 @@ void nvlist_add_descriptor(nvlist_t *nvl, const char * void nvlist_add_descriptor_array(nvlist_t *nvl, const char *name, const int *value, size_t nitems); #endif +void nvlist_append_bool_array(nvlist_t *nvl, const char *name, const bool value); +void nvlist_append_number_array(nvlist_t *nvl, const char *name, const uint64_t value); +void nvlist_append_string_array(nvlist_t *nvl, const char *name, const char * const value); +void nvlist_append_nvlist_array(nvlist_t *nvl, const char *name, const nvlist_t * const value); +#ifndef _KERNEL +void nvlist_append_descriptor_array(nvlist_t *nvl, const char *name, int value); +#endif + /* * The nvlist_move functions add the given name/value pair. * The functions consumes provided buffer.
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201806182257.w5IMvWH7036479>