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