From nobody Sun Feb 8 14:03:30 2026 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of lists.libvirt.org designates 8.43.85.245 as permitted sender) client-ip=8.43.85.245; envelope-from=devel-bounces@lists.libvirt.org; helo=lists.libvirt.org; Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of lists.libvirt.org designates 8.43.85.245 as permitted sender) smtp.mailfrom=devel-bounces@lists.libvirt.org; dmarc=fail(p=none dis=none) header.from=redhat.com Return-Path: Received: from lists.libvirt.org (lists.libvirt.org [8.43.85.245]) by mx.zohomail.com with SMTPS id 1725545471531365.64777498922683; Thu, 5 Sep 2024 07:11:11 -0700 (PDT) Received: by lists.libvirt.org (Postfix, from userid 996) id 6E73817E1; Thu, 5 Sep 2024 10:11:10 -0400 (EDT) Received: from lists.libvirt.org (localhost [IPv6:::1]) by lists.libvirt.org (Postfix) with ESMTP id CBF4017C7; Thu, 5 Sep 2024 09:55:15 -0400 (EDT) Received: by lists.libvirt.org (Postfix, from userid 996) id 6D743168B; Thu, 5 Sep 2024 09:55:01 -0400 (EDT) Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by lists.libvirt.org (Postfix) with ESMTPS id 8AA8C1763 for ; Thu, 5 Sep 2024 09:50:37 -0400 (EDT) Received: from mx-prod-mc-03.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-314-p6V3KwBKPaWn5VA3sU2XSw-1; Thu, 05 Sep 2024 09:50:36 -0400 Received: from mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.4]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 3C46B1953968 for ; Thu, 5 Sep 2024 13:50:35 +0000 (UTC) Received: from hjs.brq.redhat.com (unknown [10.43.3.187]) by mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 6C9DD3000235 for ; Thu, 5 Sep 2024 13:50:34 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on lists.libvirt.org X-Spam-Level: *** X-Spam-Status: No, score=3.0 required=5.0 tests=DKIM_INVALID,DKIM_SIGNED, HEADER_FROM_DIFFERENT_DOMAINS,MAILING_LIST_MULTI,RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H4,RCVD_IN_MSPIKE_WL,RCVD_IN_SBL_CSS,SPF_HELO_NONE, T_SCC_BODY_TEXT_LINE autolearn=no autolearn_force=no version=3.4.4 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1725544237; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=ep80Yl0RqSas/Y/pbyhF7wE/9MtFThSh10tgUJy4KNY=; b=AMBfnjtA1BExVXqIEJGbTjgQeKuG1e2n1mY7EnNRf5U6Hx8/8Ibyusk5v0nqZTSljZCppZ xZLXrb7D7giAugootmZsunsk9nUXWEzJU8Mt18NS+wnNbYzUL24KzzgSKelQJErEBUXqHv BBv9op5FxQx/lbo/ZrRY8VhgIUYM0hk= X-MC-Unique: p6V3KwBKPaWn5VA3sU2XSw-1 From: =?UTF-8?q?J=C3=A1n=20Tomko?= To: devel@lists.libvirt.org Subject: [libvirt PATCHv2 11/15] nss: convert findMACs to use json-c Date: Thu, 5 Sep 2024 15:49:38 +0200 Message-ID: <7adb84d89bd2b4b8703c4d794fa92a5e9d1e721c.1725544182.git.jtomko@redhat.com> In-Reply-To: References: MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.4 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: quoted-printable Message-ID-Hash: T7A4HC3ZZBUUNO4FJJRMZRWHWLP5HBQ4 X-Message-ID-Hash: T7A4HC3ZZBUUNO4FJJRMZRWHWLP5HBQ4 X-MailFrom: jtomko@redhat.com X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; emergency; loop; banned-address; member-moderation; header-match-config-1; header-match-config-2; header-match-config-3; header-match-devel.lists.libvirt.org-0; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; suspicious-header X-Mailman-Version: 3.2.2 Precedence: list List-Id: Development discussions about the libvirt library & tools Archived-At: List-Archive: List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZM-MESSAGEID: 1725545472375116600 Content-Type: text/plain; charset="utf-8" While the parsing is still done by 1K buffers, the results are no longer filtered during the parsing, but the whole JSON has to live in memory at once, which was also the case before the NSS plugin dropped its dependency on libvirt_util. Also, the new parser might be more forgiving of missing elements. Signed-off-by: J=C3=A1n Tomko Reviewed-by: Peter Krempa --- tools/nss/libvirt_nss_macs.c | 278 ++++++++++------------------------- 1 file changed, 80 insertions(+), 198 deletions(-) diff --git a/tools/nss/libvirt_nss_macs.c b/tools/nss/libvirt_nss_macs.c index f45d149793..281865a05b 100644 --- a/tools/nss/libvirt_nss_macs.c +++ b/tools/nss/libvirt_nss_macs.c @@ -25,179 +25,89 @@ #include #include =20 -#include -#include +#include =20 #include "libvirt_nss_macs.h" #include "libvirt_nss.h" =20 -enum { - FIND_MACS_STATE_START, - FIND_MACS_STATE_LIST, - FIND_MACS_STATE_ENTRY, - FIND_MACS_STATE_ENTRY_MACS, -}; - -typedef struct { - const char *name; - char ***macs; - size_t *nmacs; - int state; - - char *key; - struct { - char *name; - char **macs; - size_t nmacs; - } entry; -} findMACsParser; - - -static int -findMACsParserString(void *ctx, - const unsigned char *stringVal, - size_t stringLen) -{ - findMACsParser *parser =3D ctx; - - DEBUG("Parse string state=3D%d '%.*s' (map key '%s')", - parser->state, (int)stringLen, (const char *)stringVal, - NULLSTR(parser->key)); - if (!parser->key) - return 0; - - if (parser->state =3D=3D FIND_MACS_STATE_ENTRY) { - if (strcmp(parser->key, "domain")) - return 1; - - free(parser->entry.name); - if (!(parser->entry.name =3D strndup((char *)stringVal, stringLen)= )) - return 0; - } else if (parser->state =3D=3D FIND_MACS_STATE_ENTRY_MACS) { - char **macs; - if (strcmp(parser->key, "macs")) - return 1; - - if (!(macs =3D realloc(parser->entry.macs, - sizeof(char *) * (parser->entry.nmacs + 1)))) - return 0; - - parser->entry.macs =3D macs; - if (!(macs[parser->entry.nmacs++] =3D strndup((char *)stringVal, s= tringLen))) - return 0; - } else { - return 0; - } - return 1; -} - - -static int -findMACsParserMapKey(void *ctx, - const unsigned char *stringVal, - size_t stringLen) -{ - findMACsParser *parser =3D ctx; - - DEBUG("Parse map key state=3D%d '%.*s'", - parser->state, (int)stringLen, (const char *)stringVal); - - free(parser->key); - if (!(parser->key =3D strndup((char *)stringVal, stringLen))) - return 0; - - return 1; -} - - -static int -findMACsParserStartMap(void *ctx) -{ - findMACsParser *parser =3D ctx; - - DEBUG("Parse start map state=3D%d", parser->state); - - if (parser->state !=3D FIND_MACS_STATE_LIST) - return 0; - - free(parser->key); - parser->key =3D NULL; - parser->state =3D FIND_MACS_STATE_ENTRY; - - return 1; -} - =20 +/** + * findMACsFromJSON + * + * @jobj: JSON object containing the leases + * @name: requested hostname + * @macs: returned array of MAC addresses leased to the hostname + * @nmacs: size of the returned array + */ static int -findMACsParserEndMap(void *ctx) +findMACsFromJSON(json_object *jobj, + const char *name, + char ***macs, + size_t *nmacs) { - findMACsParser *parser =3D ctx; size_t i; + int len; =20 - DEBUG("Parse end map state=3D%d", parser->state); - - if (parser->entry.name =3D=3D NULL) - return 0; - - if (parser->state !=3D FIND_MACS_STATE_ENTRY) - return 0; - - if (!strcasecmp(parser->entry.name, parser->name)) { - char **macs =3D realloc(*parser->macs, - sizeof(char *) * ((*parser->nmacs) + parser-= >entry.nmacs)); - if (!macs) - return 0; - - *parser->macs =3D macs; - for (i =3D 0; i < parser->entry.nmacs; i++) - (*parser->macs)[(*parser->nmacs)++] =3D parser->entry.macs[i]; - } else { - for (i =3D 0; i < parser->entry.nmacs; i++) - free(parser->entry.macs[i]); + if (!json_object_is_type(jobj, json_type_array)) { + ERROR("parsed JSON does not contain the leases array"); + return -1; } - free(parser->entry.macs); - parser->entry.macs =3D NULL; - parser->entry.nmacs =3D 0; =20 - parser->state =3D FIND_MACS_STATE_LIST; + len =3D json_object_array_length(jobj); + DEBUG("Found an array of length: %zu", len); + for (i =3D 0; i < len; i++) { + json_object *entry =3D NULL; + json_object *domain =3D NULL; + const char *domainName; + char **tmpMacs =3D NULL; + size_t newmacs =3D 0; + json_object *macsArray =3D NULL; + size_t j; + + entry =3D json_object_array_get_idx(jobj, i); + if (!entry) + continue; =20 - return 1; -} + DEBUG("Processing item %zu", i); =20 + domain =3D json_object_object_get(entry, "domain"); + if (!domain) + continue; =20 -static int -findMACsParserStartArray(void *ctx) -{ - findMACsParser *parser =3D ctx; + domainName =3D json_object_get_string(domain); + if (!domainName) + continue; =20 - DEBUG("Parse start array state=3D%d", parser->state); + DEBUG("Processing domain %s", domainName); =20 - if (parser->state =3D=3D FIND_MACS_STATE_START) - parser->state =3D FIND_MACS_STATE_LIST; - else if (parser->state =3D=3D FIND_MACS_STATE_ENTRY) - parser->state =3D FIND_MACS_STATE_ENTRY_MACS; - else - return 0; + if (strcasecmp(domainName, name)) + continue; =20 - return 1; -} + macsArray =3D json_object_object_get(entry, "macs"); + if (!macsArray) + continue; =20 + newmacs =3D json_object_array_length(macsArray); + DEBUG("Found %zu MAC addresses", newmacs); =20 -static int -findMACsParserEndArray(void *ctx) -{ - findMACsParser *parser =3D ctx; + tmpMacs =3D realloc(*macs, sizeof(char *) * (*nmacs + newmacs + 1)= ); + if (!tmpMacs) + return -1; =20 - DEBUG("Parse end array state=3D%d", parser->state); + *macs =3D tmpMacs; =20 - if (parser->state =3D=3D FIND_MACS_STATE_LIST) - parser->state =3D FIND_MACS_STATE_START; - else if (parser->state =3D=3D FIND_MACS_STATE_ENTRY_MACS) - parser->state =3D FIND_MACS_STATE_ENTRY; - else - return 0; + for (j =3D 0; j < newmacs; j++) { + json_object *macobj =3D NULL; + char *macstr; =20 - return 1; + macobj =3D json_object_array_get_idx(macsArray, j); + macstr =3D strdup(json_object_get_string(macobj)); + if (!macstr) + return -1; + (*macs)[(*nmacs)++] =3D macstr; + } + } + return 0; } =20 =20 @@ -209,66 +119,45 @@ findMACs(const char *file, { int fd =3D -1; int ret =3D -1; - const yajl_callbacks parserCallbacks =3D { - NULL, /* null */ - NULL, /* bool */ - NULL, /* integer */ - NULL, /* double */ - NULL, /* number */ - findMACsParserString, - findMACsParserStartMap, - findMACsParserMapKey, - findMACsParserEndMap, - findMACsParserStartArray, - findMACsParserEndArray, - }; - findMACsParser parserState =3D { - .name =3D name, - .macs =3D macs, - .nmacs =3D nmacs, - }; - yajl_handle parser =3D NULL; char line[1024]; - size_t i; + json_object *jobj =3D NULL; + json_tokener *tok =3D NULL; + enum json_tokener_error jerr; + int jsonflags =3D JSON_TOKENER_STRICT | JSON_TOKENER_VALIDATE_UTF8; + ssize_t nreadTotal =3D 0; int rv; + size_t i; =20 if ((fd =3D open(file, O_RDONLY)) < 0) { ERROR("Cannot open %s", file); goto cleanup; } =20 - parser =3D yajl_alloc(&parserCallbacks, NULL, &parserState); - if (!parser) { - ERROR("Unable to create JSON parser"); - goto cleanup; - } + tok =3D json_tokener_new(); + json_tokener_set_flags(tok, jsonflags); =20 - while (1) { - rv =3D read(fd, line, sizeof(line)); + do { + rv =3D read(fd, line, sizeof(line) - 1); if (rv < 0) goto cleanup; if (rv =3D=3D 0) break; + nreadTotal +=3D rv; =20 - if (yajl_parse(parser, (const unsigned char *)line, rv) !=3D - yajl_status_ok) { - unsigned char *err =3D yajl_get_error(parser, 1, - (const unsigned char*)line= , rv); - ERROR("Parse failed %s", (const char *) err); - yajl_free_error(parser, err); - goto cleanup; - } - } + jobj =3D json_tokener_parse_ex(tok, line, rv); + jerr =3D json_tokener_get_error(tok); + } while (jerr =3D=3D json_tokener_continue); =20 - if (yajl_complete_parse(parser) !=3D yajl_status_ok) { - ERROR("Parse failed %s", - yajl_get_error(parser, 1, NULL, 0)); + if (nreadTotal > 0 && jerr !=3D json_tokener_success) { + ERROR("Cannot parse %s: %s", file, json_tokener_error_desc(jerr)); goto cleanup; } =20 - ret =3D 0; + ret =3D findMACsFromJSON(jobj, name, macs, nmacs); =20 cleanup: + json_object_put(jobj); + json_tokener_free(tok); if (ret !=3D 0) { for (i =3D 0; i < *nmacs; i++) { char *mac =3D (*macs)[i]; @@ -278,13 +167,6 @@ findMACs(const char *file, *macs =3D NULL; *nmacs =3D 0; } - if (parser) - yajl_free(parser); - for (i =3D 0; i < parserState.entry.nmacs; i++) - free(parserState.entry.macs[i]); - free(parserState.entry.macs); - free(parserState.entry.name); - free(parserState.key); if (fd !=3D -1) close(fd); return ret; --=20 2.46.0