Blame gfs2/libgfs2/lang.c

Packit Service 360c39
#include <stdint.h>
Packit Service 360c39
#include <string.h>
Packit Service 360c39
#include <stdlib.h>
Packit Service 360c39
#include <stdio.h>
Packit Service 360c39
#include <sys/queue.h>
Packit Service 360c39
#include <errno.h>
Packit Service 360c39
#include <limits.h>
Packit Service 360c39
#include <ctype.h>
Packit Service 360c39
Packit Service 360c39
#include "lang.h"
Packit Service 360c39
#include "parser.h"
Packit Service 360c39
#ifdef GFS2_HAS_UUID
Packit Service 360c39
#include <uuid.h>
Packit Service 360c39
#endif
Packit Service 360c39
Packit Service 360c39
const char* ast_type_string[] = {
Packit Service 360c39
	[AST_NONE] = "NONE",
Packit Service 360c39
	// Statements
Packit Service 360c39
	[AST_ST_SET] = "SET",
Packit Service 360c39
	[AST_ST_GET] = "GET",
Packit Service 360c39
Packit Service 360c39
	// Expressions
Packit Service 360c39
	[AST_EX_ID] = "IDENTIFIER",
Packit Service 360c39
	[AST_EX_NUMBER] = "NUMBER",
Packit Service 360c39
	[AST_EX_STRING] = "STRING",
Packit Service 360c39
	[AST_EX_ADDRESS] = "ADDRESS",
Packit Service 360c39
	[AST_EX_PATH] = "PATH",
Packit Service 360c39
	[AST_EX_SUBSCRIPT] = "SUBSCRIPT",
Packit Service 360c39
	[AST_EX_OFFSET] = "OFFSET",
Packit Service 360c39
	[AST_EX_BLOCKSPEC] = "BLOCKSPEC",
Packit Service 360c39
	[AST_EX_STRUCTSPEC] = "STRUCTSPEC",
Packit Service 360c39
	[AST_EX_FIELDSPEC] = "FIELDSPEC",
Packit Service 360c39
	[AST_EX_TYPESPEC] = "TYPESPEC",
Packit Service 360c39
Packit Service 360c39
	// Keywords
Packit Service 360c39
	[AST_KW_STATE] = "STATE",
Packit Service 360c39
};
Packit Service 360c39
Packit Service 360c39
/**
Packit Service 360c39
 * Initialize an expression node of the given type from a source string.
Packit Service 360c39
 * Currently just converts numerical values and string values where
Packit Service 360c39
 * appropriate. String values are duplicted into newly allocated buffers as the
Packit Service 360c39
 * text from the parser will go away.
Packit Service 360c39
 * Returns 0 on success or non-zero with errno set on failure
Packit Service 360c39
 */
Packit Service 360c39
static int ast_expr_init(struct ast_node *expr, ast_node_t type, const char *str)
Packit Service 360c39
{
Packit Service 360c39
	int ret = 0;
Packit Service 360c39
	switch (type) {
Packit Service 360c39
	case AST_EX_OFFSET:
Packit Service 360c39
		str++; // Cut off the +
Packit Service 360c39
	case AST_EX_NUMBER:
Packit Service 360c39
		ret = sscanf(str, "%"SCNi64, &expr->ast_num);
Packit Service 360c39
		if (ret != 1) {
Packit Service 360c39
			return 1;
Packit Service 360c39
		}
Packit Service 360c39
		break;
Packit Service 360c39
	case AST_EX_ID:
Packit Service 360c39
	case AST_EX_PATH:
Packit Service 360c39
	case AST_EX_STRING:
Packit Service 360c39
		expr->ast_str = strdup(str);
Packit Service 360c39
		if (expr->ast_str == NULL) {
Packit Service 360c39
			return 1;
Packit Service 360c39
		}
Packit Service 360c39
		break;
Packit Service 360c39
	case AST_EX_ADDRESS:
Packit Service 360c39
	case AST_EX_SUBSCRIPT:
Packit Service 360c39
	case AST_EX_BLOCKSPEC:
Packit Service 360c39
	case AST_EX_STRUCTSPEC:
Packit Service 360c39
	case AST_EX_FIELDSPEC:
Packit Service 360c39
	case AST_EX_TYPESPEC:
Packit Service 360c39
	case AST_KW_STATE:
Packit Service 360c39
		break;
Packit Service 360c39
	default:
Packit Service 360c39
		errno = EINVAL;
Packit Service 360c39
		return 1;
Packit Service 360c39
	}
Packit Service 360c39
	return 0;
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
/**
Packit Service 360c39
 * Create a new AST node of a given type from a source string.
Packit Service 360c39
 * Returns a pointer to the new node or NULL on failure with errno set.
Packit Service 360c39
 */
Packit Service 360c39
struct ast_node *ast_new(ast_node_t type, const char *text)
Packit Service 360c39
{
Packit Service 360c39
	struct ast_node *node;
Packit Service 360c39
	node = (struct ast_node *)calloc(1, sizeof(struct ast_node));
Packit Service 360c39
	if (node == NULL) {
Packit Service 360c39
		goto return_fail;
Packit Service 360c39
	}
Packit Service 360c39
Packit Service 360c39
	if (type > _AST_EX_START && ast_expr_init(node, type, text)) {
Packit Service 360c39
		goto return_free;
Packit Service 360c39
	}
Packit Service 360c39
Packit Service 360c39
	node->ast_text = strdup(text);
Packit Service 360c39
	if (node->ast_text == NULL) {
Packit Service 360c39
		goto return_free;
Packit Service 360c39
	}
Packit Service 360c39
	node->ast_type = type;
Packit Service 360c39
Packit Service 360c39
	return node;
Packit Service 360c39
Packit Service 360c39
return_free:
Packit Service 360c39
	if (node->ast_text) {
Packit Service 360c39
		free(node->ast_text);
Packit Service 360c39
	}
Packit Service 360c39
	if (node->ast_str) {
Packit Service 360c39
		free(node->ast_str);
Packit Service 360c39
	}
Packit Service 360c39
	free(node);
Packit Service 360c39
return_fail:
Packit Service 360c39
	fprintf(stderr, "Failed to create new value from %s: %s\n", text, strerror(errno));
Packit Service 360c39
	return NULL;
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
/**
Packit Service 360c39
 * Free the memory allocated for an AST node and set its pointer to NULL
Packit Service 360c39
 */
Packit Service 360c39
void ast_destroy(struct ast_node **node)
Packit Service 360c39
{
Packit Service 360c39
	if (*node == NULL) {
Packit Service 360c39
		return;
Packit Service 360c39
	}
Packit Service 360c39
	ast_destroy(&(*node)->ast_left);
Packit Service 360c39
	ast_destroy(&(*node)->ast_right);
Packit Service 360c39
	switch((*node)->ast_type) {
Packit Service 360c39
	case AST_EX_ID:
Packit Service 360c39
	case AST_EX_PATH:
Packit Service 360c39
	case AST_EX_STRING:
Packit Service 360c39
		free((*node)->ast_str);
Packit Service 360c39
		break;
Packit Service 360c39
	default:
Packit Service 360c39
		break;
Packit Service 360c39
	}
Packit Service 360c39
	free((*node)->ast_text);
Packit Service 360c39
	free(*node);
Packit Service 360c39
	*node = NULL;
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
static void ast_string_unescape(char *str)
Packit Service 360c39
{
Packit Service 360c39
	int head, tail;
Packit Service 360c39
	for (head = tail = 0; str[head] != '\0'; head++, tail++) {
Packit Service 360c39
		if (str[head] == '\\' && str[head+1] != '\0')
Packit Service 360c39
			head++;
Packit Service 360c39
		str[tail] = str[head];
Packit Service 360c39
	}
Packit Service 360c39
	str[tail] = '\0';
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
static uint64_t ast_lookup_path(char *path, struct gfs2_sbd *sbd)
Packit Service 360c39
{
Packit Service 360c39
	int err = 0;
Packit Service 360c39
	char *c = NULL;
Packit Service 360c39
	struct gfs2_inode *ip, *iptmp;
Packit Service 360c39
	char *segment;
Packit Service 360c39
	uint64_t bn = 0;
Packit Service 360c39
Packit Service 360c39
	segment = strtok_r(path, "/", &c);
Packit Service 360c39
	ip = lgfs2_inode_read(sbd, sbd->sd_sb.sb_root_dir.no_addr);
Packit Service 360c39
Packit Service 360c39
	while (ip != NULL) {
Packit Service 360c39
		if (segment == NULL) { // No more segments
Packit Service 360c39
			bn = ip->i_di.di_num.no_addr;
Packit Service 360c39
			inode_put(&ip);
Packit Service 360c39
			return bn;
Packit Service 360c39
		}
Packit Service 360c39
		ast_string_unescape(segment);
Packit Service 360c39
		err = gfs2_lookupi(ip, segment, strlen(segment), &iptmp);
Packit Service 360c39
		inode_put(&ip);
Packit Service 360c39
		if (err != 0) {
Packit Service 360c39
			errno = -err;
Packit Service 360c39
			break;
Packit Service 360c39
		}
Packit Service 360c39
		ip = iptmp;
Packit Service 360c39
		segment = strtok_r(NULL, "/", &c);
Packit Service 360c39
	}
Packit Service 360c39
Packit Service 360c39
	return 0;
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
enum block_id {
Packit Service 360c39
	ID_SB	= 0,
Packit Service 360c39
	ID_MASTER,
Packit Service 360c39
	ID_ROOT,
Packit Service 360c39
	ID_RINDEX,
Packit Service 360c39
Packit Service 360c39
	ID_END
Packit Service 360c39
};
Packit Service 360c39
Packit Service 360c39
/**
Packit Service 360c39
 * Names of blocks which can be uniquely identified in the fs
Packit Service 360c39
 */
Packit Service 360c39
static const char *block_ids[] = {
Packit Service 360c39
	[ID_SB]		= "sb",
Packit Service 360c39
	[ID_MASTER]	= "master",
Packit Service 360c39
	[ID_ROOT]	= "root",
Packit Service 360c39
	[ID_RINDEX]	= "rindex",
Packit Service 360c39
Packit Service 360c39
	[ID_END]	= NULL
Packit Service 360c39
};
Packit Service 360c39
Packit Service 360c39
static uint64_t ast_lookup_id(const char *id, struct gfs2_sbd *sbd)
Packit Service 360c39
{
Packit Service 360c39
	uint64_t bn = 0;
Packit Service 360c39
	int i;
Packit Service 360c39
	for (i = 0; i < ID_END; i++) {
Packit Service 360c39
		if (!strcmp(id, block_ids[i])) {
Packit Service 360c39
			break;
Packit Service 360c39
		}
Packit Service 360c39
	}
Packit Service 360c39
	switch (i) {
Packit Service 360c39
	case ID_SB:
Packit Service 360c39
		bn = LGFS2_SB_ADDR(sbd);
Packit Service 360c39
		break;
Packit Service 360c39
	case ID_MASTER:
Packit Service 360c39
		bn = sbd->sd_sb.sb_master_dir.no_addr;
Packit Service 360c39
		break;
Packit Service 360c39
	case ID_ROOT:
Packit Service 360c39
		bn = sbd->sd_sb.sb_root_dir.no_addr;
Packit Service 360c39
		break;
Packit Service 360c39
	case ID_RINDEX:
Packit Service 360c39
		bn = sbd->md.riinode->i_di.di_num.no_addr;
Packit Service 360c39
		break;
Packit Service 360c39
	default:
Packit Service 360c39
		return 0;
Packit Service 360c39
	}
Packit Service 360c39
	return bn;
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
static uint64_t ast_lookup_rgrp(uint64_t rgnum, struct gfs2_sbd *sbd)
Packit Service 360c39
{
Packit Service 360c39
	uint64_t i = rgnum;
Packit Service 360c39
	struct osi_node *n;
Packit Service 360c39
Packit Service 360c39
	for (n = osi_first(&sbd->rgtree); n != NULL && i > 0; n = osi_next(n), i--);
Packit Service 360c39
	if (n != NULL && i == 0)
Packit Service 360c39
		return ((struct rgrp_tree *)n)->ri.ri_addr;
Packit Service 360c39
	fprintf(stderr, "Resource group number out of range: %"PRIu64"\n", rgnum);
Packit Service 360c39
	return 0;
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
static uint64_t ast_lookup_subscript(struct ast_node *id, struct ast_node *index,
Packit Service 360c39
                                     struct gfs2_sbd *sbd)
Packit Service 360c39
{
Packit Service 360c39
	uint64_t bn = 0;
Packit Service 360c39
	const char *name = id->ast_str;
Packit Service 360c39
	if (!strcmp(name, "rgrp")) {
Packit Service 360c39
		bn = ast_lookup_rgrp(index->ast_num, sbd);
Packit Service 360c39
	} else {
Packit Service 360c39
		fprintf(stderr, "Unrecognized identifier %s\n", name);
Packit Service 360c39
	}
Packit Service 360c39
	return bn;
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
/**
Packit Service 360c39
 * Look up a block and return its number. The kind of lookup depends on the
Packit Service 360c39
 * type of the ast node.
Packit Service 360c39
 */
Packit Service 360c39
static uint64_t ast_lookup_block_num(struct ast_node *ast, struct gfs2_sbd *sbd)
Packit Service 360c39
{
Packit Service 360c39
	uint64_t bn = 0;
Packit Service 360c39
	switch (ast->ast_type) {
Packit Service 360c39
	case AST_EX_OFFSET:
Packit Service 360c39
		bn = ast_lookup_block_num(ast->ast_left, sbd) + ast->ast_num;
Packit Service 360c39
		break;
Packit Service 360c39
	case AST_EX_ADDRESS:
Packit Service 360c39
		if (gfs2_check_range(sbd, ast->ast_num))
Packit Service 360c39
			break;
Packit Service 360c39
		bn = ast->ast_num;
Packit Service 360c39
		break;
Packit Service 360c39
	case AST_EX_PATH:
Packit Service 360c39
		bn = ast_lookup_path(ast->ast_str, sbd);
Packit Service 360c39
		break;
Packit Service 360c39
	case AST_EX_ID:
Packit Service 360c39
		bn = ast_lookup_id(ast->ast_str, sbd);
Packit Service 360c39
		break;
Packit Service 360c39
	case AST_EX_SUBSCRIPT:
Packit Service 360c39
		bn = ast_lookup_subscript(ast->ast_left, ast->ast_left->ast_left, sbd);
Packit Service 360c39
		break;
Packit Service 360c39
	default:
Packit Service 360c39
		break;
Packit Service 360c39
	}
Packit Service 360c39
	return bn;
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
static struct gfs2_buffer_head *ast_lookup_block(struct ast_node *node, struct gfs2_sbd *sbd)
Packit Service 360c39
{
Packit Service 360c39
	uint64_t bn = ast_lookup_block_num(node, sbd);
Packit Service 360c39
	if (bn == 0) {
Packit Service 360c39
		fprintf(stderr, "Block not found: %s\n", node->ast_text);
Packit Service 360c39
		return NULL;
Packit Service 360c39
	}
Packit Service 360c39
Packit Service 360c39
	return bread(sbd, bn);
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
static const char *bitstate_strings[] = {
Packit Service 360c39
	[GFS2_BLKST_FREE] = "Free",
Packit Service 360c39
	[GFS2_BLKST_USED] = "Used",
Packit Service 360c39
	[GFS2_BLKST_UNLINKED] = "Unlinked",
Packit Service 360c39
	[GFS2_BLKST_DINODE] = "Dinode"
Packit Service 360c39
};
Packit Service 360c39
Packit Service 360c39
/**
Packit Service 360c39
 * Print a representation of an arbitrary field of an arbitrary GFS2 block to stdout
Packit Service 360c39
 * Returns 0 if successful, 1 otherwise
Packit Service 360c39
 */
Packit Service 360c39
static int field_print(const struct gfs2_buffer_head *bh, const struct lgfs2_metadata *mtype,
Packit Service 360c39
                      const struct lgfs2_metafield *field)
Packit Service 360c39
{
Packit Service 360c39
	const char *fieldp = (char *)bh->iov.iov_base + field->offset;
Packit Service 360c39
Packit Service 360c39
	printf("%s\t%"PRIu64"\t%u\t%u\t%s\t", mtype->name, bh->b_blocknr, field->offset, field->length, field->name);
Packit Service 360c39
	if (field->flags & LGFS2_MFF_UUID) {
Packit Service 360c39
#ifdef GFS2_HAS_UUID
Packit Service 360c39
		char readable_uuid[36+1];
Packit Service 360c39
		uuid_t uuid;
Packit Service 360c39
Packit Service 360c39
		memcpy(uuid, fieldp, sizeof(uuid_t));
Packit Service 360c39
		uuid_unparse(uuid, readable_uuid);
Packit Service 360c39
		printf("'%s'\n", readable_uuid);
Packit Service 360c39
#endif
Packit Service 360c39
	} else if (field->flags & LGFS2_MFF_STRING) {
Packit Service 360c39
		printf("'%s'\n", fieldp);
Packit Service 360c39
	} else {
Packit Service 360c39
		switch(field->length) {
Packit Service 360c39
		case 1:
Packit Service 360c39
			printf("%"PRIu8"\n", *(uint8_t *)fieldp);
Packit Service 360c39
			break;
Packit Service 360c39
		case 2:
Packit Service 360c39
			printf("%"PRIu16"\n", be16_to_cpu(*(uint16_t *)fieldp));
Packit Service 360c39
			break;
Packit Service 360c39
		case 4:
Packit Service 360c39
			printf("%"PRIu32"\n", be32_to_cpu(*(uint32_t *)fieldp));
Packit Service 360c39
			break;
Packit Service 360c39
		case 8:
Packit Service 360c39
			printf("%"PRIu64"\n", be64_to_cpu(*(uint64_t *)fieldp));
Packit Service 360c39
			break;
Packit Service 360c39
		default:
Packit Service 360c39
			// "Reserved" field so just print 0
Packit Service 360c39
			printf("0\n");
Packit Service 360c39
			return 1;
Packit Service 360c39
		}
Packit Service 360c39
	}
Packit Service 360c39
	return 0;
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
/**
Packit Service 360c39
 * Print a representation of an arbitrary GFS2 block to stdout
Packit Service 360c39
 */
Packit Service 360c39
int lgfs2_lang_result_print(struct lgfs2_lang_result *result)
Packit Service 360c39
{
Packit Service 360c39
	int i;
Packit Service 360c39
	if (result->lr_mtype != NULL) {
Packit Service 360c39
		for (i = 0; i < result->lr_mtype->nfields; i++) {
Packit Service 360c39
			field_print(result->lr_bh, result->lr_mtype, &result->lr_mtype->fields[i]);
Packit Service 360c39
		}
Packit Service 360c39
	} else {
Packit Service 360c39
		printf("%"PRIu64": %s\n", result->lr_blocknr, bitstate_strings[result->lr_state]);
Packit Service 360c39
	}
Packit Service 360c39
	return 0;
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
static int ast_get_bitstate(uint64_t bn, struct gfs2_sbd *sbd)
Packit Service 360c39
{
Packit Service 360c39
	int ret = 0;
Packit Service 360c39
	int state = 0;
Packit Service 360c39
	struct rgrp_tree *rgd = gfs2_blk2rgrpd(sbd, bn);
Packit Service 360c39
	if (rgd == NULL) {
Packit Service 360c39
		fprintf(stderr, "Could not find resource group for block %"PRIu64"\n", bn);
Packit Service 360c39
		return -1;
Packit Service 360c39
	}
Packit Service 360c39
Packit Service 360c39
	ret = gfs2_rgrp_read(sbd, rgd);
Packit Service 360c39
	if (ret != 0) {
Packit Service 360c39
		fprintf(stderr, "Failed to read resource group for block %"PRIu64": %d\n", bn, ret);
Packit Service 360c39
		return -1;
Packit Service 360c39
	}
Packit Service 360c39
Packit Service 360c39
	state = lgfs2_get_bitmap(sbd, bn, rgd);
Packit Service 360c39
	if (state == -1) {
Packit Service 360c39
		fprintf(stderr, "Failed to acquire bitmap state for block %"PRIu64"\n", bn);
Packit Service 360c39
		return -1;
Packit Service 360c39
	}
Packit Service 360c39
Packit Service 360c39
	gfs2_rgrp_relse(rgd);
Packit Service 360c39
	return state;
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
static const struct lgfs2_metadata *ast_lookup_mtype(const struct gfs2_buffer_head *bh)
Packit Service 360c39
{
Packit Service 360c39
	const struct lgfs2_metadata *mtype;
Packit Service 360c39
	const uint32_t mh_type = lgfs2_get_block_type(bh);
Packit Service 360c39
	if (mh_type == 0) {
Packit Service 360c39
		fprintf(stderr, "Could not determine type for block %"PRIu64"\n", bh->b_blocknr);
Packit Service 360c39
		return NULL;
Packit Service 360c39
	}
Packit Service 360c39
Packit Service 360c39
	mtype = lgfs2_find_mtype(mh_type, bh->sdp->gfs1 ? LGFS2_MD_GFS1 : LGFS2_MD_GFS2);
Packit Service 360c39
	if (mtype == NULL) {
Packit Service 360c39
		fprintf(stderr, "Could not determine meta type for block %"PRIu64"\n", bh->b_blocknr);
Packit Service 360c39
		return NULL;
Packit Service 360c39
	}
Packit Service 360c39
	return mtype;
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
/**
Packit Service 360c39
 * Interpret the get statement.
Packit Service 360c39
 */
Packit Service 360c39
static struct lgfs2_lang_result *ast_interp_get(struct lgfs2_lang_state *state,
Packit Service 360c39
                                     struct ast_node *ast, struct gfs2_sbd *sbd)
Packit Service 360c39
{
Packit Service 360c39
	struct lgfs2_lang_result *result = calloc(1, sizeof(struct lgfs2_lang_result));
Packit Service 360c39
	if (result == NULL) {
Packit Service 360c39
		fprintf(stderr, "Failed to allocate memory for result\n");
Packit Service 360c39
		return NULL;
Packit Service 360c39
	}
Packit Service 360c39
Packit Service 360c39
	if (ast->ast_right->ast_right == NULL) {
Packit Service 360c39
		result->lr_bh = ast_lookup_block(ast->ast_right, sbd);
Packit Service 360c39
		if (result->lr_bh == NULL) {
Packit Service 360c39
			free(result);
Packit Service 360c39
			return NULL;
Packit Service 360c39
		}
Packit Service 360c39
		result->lr_blocknr = result->lr_bh->b_blocknr;
Packit Service 360c39
		result->lr_mtype = ast_lookup_mtype(result->lr_bh);
Packit Service 360c39
Packit Service 360c39
	} else if (ast->ast_right->ast_right->ast_type == AST_KW_STATE) {
Packit Service 360c39
		result->lr_blocknr = ast_lookup_block_num(ast->ast_right, sbd);
Packit Service 360c39
		if (result->lr_blocknr == 0) {
Packit Service 360c39
			free(result);
Packit Service 360c39
			return NULL;
Packit Service 360c39
		}
Packit Service 360c39
		result->lr_state = ast_get_bitstate(result->lr_blocknr, sbd);
Packit Service 360c39
	}
Packit Service 360c39
Packit Service 360c39
	return result;
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
/**
Packit Service 360c39
 * Set a field of a gfs2 block of a given type to a given value.
Packit Service 360c39
 * Returns AST_INTERP_* to signal success, an invalid field/value or an error.
Packit Service 360c39
 */
Packit Service 360c39
static int ast_field_set(struct gfs2_buffer_head *bh, const struct lgfs2_metafield *field,
Packit Service 360c39
                                                                        struct ast_node *val)
Packit Service 360c39
{
Packit Service 360c39
	int err = 0;
Packit Service 360c39
Packit Service 360c39
	if (field->flags & LGFS2_MFF_UUID) {
Packit Service 360c39
#ifdef GFS2_HAS_UUID
Packit Service 360c39
		uuid_t uuid;
Packit Service 360c39
Packit Service 360c39
		if (uuid_parse(val->ast_str, uuid) != 0) {
Packit Service 360c39
			fprintf(stderr, "Invalid UUID\n");
Packit Service 360c39
			return AST_INTERP_INVAL;
Packit Service 360c39
		}
Packit Service 360c39
		err = lgfs2_field_assign(bh->b_data, field, uuid);
Packit Service 360c39
#else
Packit Service 360c39
		fprintf(stderr, "No UUID support\n");
Packit Service 360c39
		err = 1;
Packit Service 360c39
#endif
Packit Service 360c39
	} else if (field->flags & LGFS2_MFF_STRING) {
Packit Service 360c39
		err = lgfs2_field_assign(bh->b_data, field, val->ast_str);
Packit Service 360c39
	} else {
Packit Service 360c39
		err = lgfs2_field_assign(bh->b_data, field, &val->ast_num);
Packit Service 360c39
	}
Packit Service 360c39
Packit Service 360c39
	if (err) {
Packit Service 360c39
		fprintf(stderr, "Invalid field assignment: %s (size %d) = %s\n",
Packit Service 360c39
	                field->name, field->length, val->ast_text);
Packit Service 360c39
		return AST_INTERP_INVAL;
Packit Service 360c39
	}
Packit Service 360c39
Packit Service 360c39
	bmodified(bh);
Packit Service 360c39
	return AST_INTERP_SUCCESS;
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
static const struct lgfs2_metadata *lang_find_mtype(struct ast_node *node, struct gfs2_buffer_head *bh, unsigned ver)
Packit Service 360c39
{
Packit Service 360c39
	const struct lgfs2_metadata *mtype = NULL;
Packit Service 360c39
Packit Service 360c39
	if (node->ast_type == AST_EX_TYPESPEC) {
Packit Service 360c39
		mtype = lgfs2_find_mtype_name(node->ast_str, ver);
Packit Service 360c39
		if (mtype == NULL)
Packit Service 360c39
			fprintf(stderr, "Invalid block type: %s\n", node->ast_text);
Packit Service 360c39
	} else {
Packit Service 360c39
		mtype = lgfs2_find_mtype(lgfs2_get_block_type(bh), ver);
Packit Service 360c39
		if (mtype == NULL)
Packit Service 360c39
			fprintf(stderr, "Unrecognised block at: %s\n", node->ast_text);
Packit Service 360c39
	}
Packit Service 360c39
Packit Service 360c39
	return mtype;
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
/**
Packit Service 360c39
 * Interpret an assignment (set)
Packit Service 360c39
 */
Packit Service 360c39
static struct lgfs2_lang_result *ast_interp_set(struct lgfs2_lang_state *state,
Packit Service 360c39
                                    struct ast_node *ast, struct gfs2_sbd *sbd)
Packit Service 360c39
{
Packit Service 360c39
	struct ast_node *lookup = ast->ast_right;
Packit Service 360c39
	struct ast_node *fieldspec;
Packit Service 360c39
	struct ast_node *fieldname;
Packit Service 360c39
	struct ast_node *fieldval;
Packit Service 360c39
	int ret = 0;
Packit Service 360c39
	unsigned ver = sbd->gfs1 ? LGFS2_MD_GFS1 : LGFS2_MD_GFS2;
Packit Service 360c39
Packit Service 360c39
	struct lgfs2_lang_result *result = calloc(1, sizeof(struct lgfs2_lang_result));
Packit Service 360c39
	if (result == NULL) {
Packit Service 360c39
		fprintf(stderr, "Failed to allocate memory for result\n");
Packit Service 360c39
		return NULL;
Packit Service 360c39
	}
Packit Service 360c39
Packit Service 360c39
	result->lr_bh = ast_lookup_block(lookup, sbd);
Packit Service 360c39
	if (result->lr_bh == NULL) {
Packit Service 360c39
		goto out_err;
Packit Service 360c39
	}
Packit Service 360c39
Packit Service 360c39
	result->lr_mtype = lang_find_mtype(lookup->ast_right, result->lr_bh, ver);
Packit Service 360c39
	if (result->lr_mtype == NULL) {
Packit Service 360c39
		fprintf(stderr, "Unrecognised block at: %s\n", lookup->ast_str);
Packit Service 360c39
		goto out_err;
Packit Service 360c39
	}
Packit Service 360c39
Packit Service 360c39
	if (lookup->ast_right->ast_type == AST_EX_TYPESPEC) {
Packit Service 360c39
		struct gfs2_meta_header mh = {
Packit Service 360c39
			.mh_magic = GFS2_MAGIC,
Packit Service 360c39
			.mh_type = result->lr_mtype->mh_type,
Packit Service 360c39
			.mh_format = result->lr_mtype->mh_format,
Packit Service 360c39
		};
Packit Service 360c39
		gfs2_meta_header_out(&mh, result->lr_bh->iov.iov_base);
Packit Service 360c39
		lookup = lookup->ast_right;
Packit Service 360c39
	}
Packit Service 360c39
Packit Service 360c39
	for (fieldspec = lookup->ast_right;
Packit Service 360c39
	     fieldspec != NULL && fieldspec->ast_type == AST_EX_FIELDSPEC;
Packit Service 360c39
	     fieldspec = fieldspec->ast_left) {
Packit Service 360c39
		const struct lgfs2_metafield *mfield;
Packit Service 360c39
Packit Service 360c39
		fieldname = fieldspec->ast_right;
Packit Service 360c39
		fieldval = fieldname->ast_right;
Packit Service 360c39
Packit Service 360c39
		mfield = lgfs2_find_mfield_name(fieldname->ast_str, result->lr_mtype);
Packit Service 360c39
		if (mfield == NULL) {
Packit Service 360c39
			fprintf(stderr, "No field '%s' found in '%s'\n",
Packit Service 360c39
			        fieldname->ast_str, result->lr_mtype->name);
Packit Service 360c39
			goto out_err;
Packit Service 360c39
		}
Packit Service 360c39
Packit Service 360c39
		ret = ast_field_set(result->lr_bh, mfield, fieldval);
Packit Service 360c39
		if (ret != AST_INTERP_SUCCESS) {
Packit Service 360c39
			goto out_err;
Packit Service 360c39
		}
Packit Service 360c39
	}
Packit Service 360c39
Packit Service 360c39
	ret = bwrite(result->lr_bh);
Packit Service 360c39
	if (ret != 0) {
Packit Service 360c39
		fprintf(stderr, "Failed to write modified block %"PRIu64": %s\n",
Packit Service 360c39
		                        result->lr_bh->b_blocknr, strerror(errno));
Packit Service 360c39
		goto out_err;
Packit Service 360c39
	}
Packit Service 360c39
Packit Service 360c39
	return result;
Packit Service 360c39
Packit Service 360c39
out_err:
Packit Service 360c39
	lgfs2_lang_result_free(&result);
Packit Service 360c39
	return NULL;
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
static struct lgfs2_lang_result *ast_interpret_node(struct lgfs2_lang_state *state,
Packit Service 360c39
                                        struct ast_node *ast, struct gfs2_sbd *sbd)
Packit Service 360c39
{
Packit Service 360c39
	struct lgfs2_lang_result *result = NULL;
Packit Service 360c39
Packit Service 360c39
	if (ast->ast_type == AST_ST_SET) {
Packit Service 360c39
		result = ast_interp_set(state, ast, sbd);
Packit Service 360c39
	} else if (ast->ast_type == AST_ST_GET) {
Packit Service 360c39
		result = ast_interp_get(state, ast, sbd);
Packit Service 360c39
	} else {
Packit Service 360c39
		fprintf(stderr, "Invalid AST node type: %d\n", ast->ast_type);
Packit Service 360c39
	}
Packit Service 360c39
	return result;
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
struct lgfs2_lang_result *lgfs2_lang_result_next(struct lgfs2_lang_state *state,
Packit Service 360c39
                                                           struct gfs2_sbd *sbd)
Packit Service 360c39
{
Packit Service 360c39
	struct lgfs2_lang_result *result;
Packit Service 360c39
	if (state->ls_interp_curr == NULL) {
Packit Service 360c39
		return NULL;
Packit Service 360c39
	}
Packit Service 360c39
	result = ast_interpret_node(state, state->ls_interp_curr, sbd);
Packit Service 360c39
	if (result == NULL) {
Packit Service 360c39
		return NULL;
Packit Service 360c39
	}
Packit Service 360c39
	state->ls_interp_curr = state->ls_interp_curr->ast_left;
Packit Service 360c39
	return result;
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
void lgfs2_lang_result_free(struct lgfs2_lang_result **result)
Packit Service 360c39
{
Packit Service 360c39
	if (*result == NULL) {
Packit Service 360c39
		fprintf(stderr, "Warning: attempted to free a null result\n");
Packit Service 360c39
		return;
Packit Service 360c39
	}
Packit Service 360c39
Packit Service 360c39
	if ((*result)->lr_mtype != NULL) {
Packit Service 360c39
		(*result)->lr_bh->b_modified = 0;
Packit Service 360c39
		brelse((*result)->lr_bh);
Packit Service 360c39
		(*result)->lr_bh = NULL;
Packit Service 360c39
	}
Packit Service 360c39
Packit Service 360c39
	free(*result);
Packit Service 360c39
	*result = NULL;
Packit Service 360c39
}