mirror of https://gitee.com/openkylin/libvirt.git
291 lines
6.8 KiB
C
291 lines
6.8 KiB
C
/*
|
|
* libvirt_nss_macs.c: Name Service Switch plugin MAC file parser
|
|
*
|
|
* Copyright (C) 2019 Red Hat, Inc.
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library. If not, see
|
|
* <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include <config.h>
|
|
|
|
#include <unistd.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <fcntl.h>
|
|
|
|
#include <yajl/yajl_gen.h>
|
|
#include <yajl/yajl_parse.h>
|
|
|
|
#include "libvirt_nss_macs.h"
|
|
#include "libvirt_nss.h"
|
|
|
|
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 = ctx;
|
|
|
|
DEBUG("Parse string state=%d '%.*s' (map key '%s')",
|
|
parser->state, (int)stringLen, (const char *)stringVal,
|
|
NULLSTR(parser->key));
|
|
if (!parser->key)
|
|
return 0;
|
|
|
|
if (parser->state == FIND_MACS_STATE_ENTRY) {
|
|
if (strcmp(parser->key, "domain"))
|
|
return 1;
|
|
|
|
free(parser->entry.name);
|
|
if (!(parser->entry.name = strndup((char *)stringVal, stringLen)))
|
|
return 0;
|
|
} else if (parser->state == FIND_MACS_STATE_ENTRY_MACS) {
|
|
char **macs;
|
|
if (strcmp(parser->key, "macs"))
|
|
return 1;
|
|
|
|
if (!(macs = realloc(parser->entry.macs,
|
|
sizeof(char *) * (parser->entry.nmacs + 1))))
|
|
return 0;
|
|
|
|
parser->entry.macs = macs;
|
|
if (!(macs[parser->entry.nmacs++] = strndup((char *)stringVal, stringLen)))
|
|
return 0;
|
|
} else {
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
|
|
static int
|
|
findMACsParserMapKey(void *ctx,
|
|
const unsigned char *stringVal,
|
|
size_t stringLen)
|
|
{
|
|
findMACsParser *parser = ctx;
|
|
|
|
DEBUG("Parse map key state=%d '%.*s'",
|
|
parser->state, (int)stringLen, (const char *)stringVal);
|
|
|
|
free(parser->key);
|
|
if (!(parser->key = strndup((char *)stringVal, stringLen)))
|
|
return 0;
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
static int
|
|
findMACsParserStartMap(void *ctx)
|
|
{
|
|
findMACsParser *parser = ctx;
|
|
|
|
DEBUG("Parse start map state=%d", parser->state);
|
|
|
|
if (parser->state != FIND_MACS_STATE_LIST)
|
|
return 0;
|
|
|
|
free(parser->key);
|
|
parser->key = NULL;
|
|
parser->state = FIND_MACS_STATE_ENTRY;
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
static int
|
|
findMACsParserEndMap(void *ctx)
|
|
{
|
|
findMACsParser *parser = ctx;
|
|
size_t i;
|
|
|
|
DEBUG("Parse end map state=%d", parser->state);
|
|
|
|
if (parser->entry.name == NULL)
|
|
return 0;
|
|
|
|
if (parser->state != FIND_MACS_STATE_ENTRY)
|
|
return 0;
|
|
|
|
if (!strcmp(parser->entry.name, parser->name)) {
|
|
char **macs = realloc(*parser->macs,
|
|
sizeof(char *) * ((*parser->nmacs) + parser->entry.nmacs));
|
|
if (!macs)
|
|
return 0;
|
|
|
|
*parser->macs = macs;
|
|
for (i = 0; i < parser->entry.nmacs; i++)
|
|
(*parser->macs)[(*parser->nmacs)++] = parser->entry.macs[i];
|
|
} else {
|
|
for (i = 0; i < parser->entry.nmacs; i++)
|
|
free(parser->entry.macs[i]);
|
|
}
|
|
free(parser->entry.macs);
|
|
parser->entry.macs = NULL;
|
|
parser->entry.nmacs = 0;
|
|
|
|
parser->state = FIND_MACS_STATE_LIST;
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
static int
|
|
findMACsParserStartArray(void *ctx)
|
|
{
|
|
findMACsParser *parser = ctx;
|
|
|
|
DEBUG("Parse start array state=%d", parser->state);
|
|
|
|
if (parser->state == FIND_MACS_STATE_START)
|
|
parser->state = FIND_MACS_STATE_LIST;
|
|
else if (parser->state == FIND_MACS_STATE_ENTRY)
|
|
parser->state = FIND_MACS_STATE_ENTRY_MACS;
|
|
else
|
|
return 0;
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
static int
|
|
findMACsParserEndArray(void *ctx)
|
|
{
|
|
findMACsParser *parser = ctx;
|
|
|
|
DEBUG("Parse end array state=%d", parser->state);
|
|
|
|
if (parser->state == FIND_MACS_STATE_LIST)
|
|
parser->state = FIND_MACS_STATE_START;
|
|
else if (parser->state == FIND_MACS_STATE_ENTRY_MACS)
|
|
parser->state = FIND_MACS_STATE_ENTRY;
|
|
else
|
|
return 0;
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
int
|
|
findMACs(const char *file,
|
|
const char *name,
|
|
char ***macs,
|
|
size_t *nmacs)
|
|
{
|
|
int fd = -1;
|
|
int ret = -1;
|
|
const yajl_callbacks parserCallbacks = {
|
|
NULL, /* null */
|
|
NULL, /* bool */
|
|
NULL, /* integer */
|
|
NULL, /* double */
|
|
NULL, /* number */
|
|
findMACsParserString,
|
|
findMACsParserStartMap,
|
|
findMACsParserMapKey,
|
|
findMACsParserEndMap,
|
|
findMACsParserStartArray,
|
|
findMACsParserEndArray,
|
|
};
|
|
findMACsParser parserState = {
|
|
.name = name,
|
|
.macs = macs,
|
|
.nmacs = nmacs,
|
|
};
|
|
yajl_handle parser = NULL;
|
|
char line[1024];
|
|
size_t i;
|
|
int rv;
|
|
|
|
if ((fd = open(file, O_RDONLY)) < 0) {
|
|
ERROR("Cannot open %s", file);
|
|
goto cleanup;
|
|
}
|
|
|
|
parser = yajl_alloc(&parserCallbacks, NULL, &parserState);
|
|
if (!parser) {
|
|
ERROR("Unable to create JSON parser");
|
|
goto cleanup;
|
|
}
|
|
|
|
while (1) {
|
|
rv = read(fd, line, sizeof(line));
|
|
if (rv < 0)
|
|
goto cleanup;
|
|
if (rv == 0)
|
|
break;
|
|
|
|
if (yajl_parse(parser, (const unsigned char *)line, rv) !=
|
|
yajl_status_ok) {
|
|
unsigned char *err = yajl_get_error(parser, 1,
|
|
(const unsigned char*)line, rv);
|
|
ERROR("Parse failed %s", (const char *) err);
|
|
yajl_free_error(parser, err);
|
|
goto cleanup;
|
|
}
|
|
}
|
|
|
|
if (yajl_complete_parse(parser) != yajl_status_ok) {
|
|
ERROR("Parse failed %s",
|
|
yajl_get_error(parser, 1, NULL, 0));
|
|
goto cleanup;
|
|
}
|
|
|
|
ret = 0;
|
|
|
|
cleanup:
|
|
if (ret != 0) {
|
|
for (i = 0; i < *nmacs; i++) {
|
|
char *mac = (*macs)[i];
|
|
free(mac);
|
|
}
|
|
free(*macs);
|
|
*macs = NULL;
|
|
*nmacs = 0;
|
|
}
|
|
yajl_free(parser);
|
|
for (i = 0; i < parserState.entry.nmacs; i++)
|
|
free(parserState.entry.macs[i]);
|
|
free(parserState.entry.macs);
|
|
free(parserState.entry.name);
|
|
free(parserState.key);
|
|
if (fd != -1)
|
|
close(fd);
|
|
return ret;
|
|
}
|