LCOV - code coverage report
Current view: top level - libgfs2 - lang.c (source / functions) Hit Total Coverage
Test: gfs2-utils.info Lines: 164 340 48.2 %
Date: 2023-10-25 12:04:14 Functions: 17 23 73.9 %

          Line data    Source code
       1             : #include <stdint.h>
       2             : #include <string.h>
       3             : #include <stdlib.h>
       4             : #include <stdio.h>
       5             : #include <unistd.h>
       6             : #include <errno.h>
       7             : #include <limits.h>
       8             : #include <ctype.h>
       9             : #include <uuid.h>
      10             : 
      11             : #include "lang.h"
      12             : #include "parser.h"
      13             : 
      14             : const char* ast_type_string[] = {
      15             :         [AST_NONE] = "NONE",
      16             :         // Statements
      17             :         [AST_ST_SET] = "SET",
      18             :         [AST_ST_GET] = "GET",
      19             : 
      20             :         // Expressions
      21             :         [AST_EX_ID] = "IDENTIFIER",
      22             :         [AST_EX_NUMBER] = "NUMBER",
      23             :         [AST_EX_STRING] = "STRING",
      24             :         [AST_EX_ADDRESS] = "ADDRESS",
      25             :         [AST_EX_PATH] = "PATH",
      26             :         [AST_EX_SUBSCRIPT] = "SUBSCRIPT",
      27             :         [AST_EX_OFFSET] = "OFFSET",
      28             :         [AST_EX_BLOCKSPEC] = "BLOCKSPEC",
      29             :         [AST_EX_STRUCTSPEC] = "STRUCTSPEC",
      30             :         [AST_EX_FIELDSPEC] = "FIELDSPEC",
      31             :         [AST_EX_TYPESPEC] = "TYPESPEC",
      32             : 
      33             :         // Keywords
      34             :         [AST_KW_STATE] = "STATE",
      35             : };
      36             : 
      37             : /**
      38             :  * Initialize an expression node of the given type from a source string.
      39             :  * Currently just converts numerical values and string values where
      40             :  * appropriate. String values are duplicted into newly allocated buffers as the
      41             :  * text from the parser will go away.
      42             :  * Returns 0 on success or non-zero with errno set on failure
      43             :  */
      44          32 : static int ast_expr_init(struct ast_node *expr, ast_node_t type, const char *str)
      45             : {
      46          32 :         int ret = 0;
      47          32 :         switch (type) {
      48           0 :         case AST_EX_OFFSET:
      49           0 :                 str++; // Cut off the +
      50           8 :         case AST_EX_NUMBER:
      51           8 :                 ret = sscanf(str, "%"SCNi64, &expr->ast_num);
      52           8 :                 if (ret != 1) {
      53           0 :                         return 1;
      54             :                 }
      55           8 :                 break;
      56          16 :         case AST_EX_ID:
      57             :         case AST_EX_PATH:
      58             :         case AST_EX_STRING:
      59          16 :                 expr->ast_str = strdup(str);
      60          16 :                 if (expr->ast_str == NULL) {
      61           0 :                         return 1;
      62             :                 }
      63          16 :                 break;
      64           8 :         case AST_EX_ADDRESS:
      65             :         case AST_EX_SUBSCRIPT:
      66             :         case AST_EX_BLOCKSPEC:
      67             :         case AST_EX_STRUCTSPEC:
      68             :         case AST_EX_FIELDSPEC:
      69             :         case AST_EX_TYPESPEC:
      70             :         case AST_KW_STATE:
      71           8 :                 break;
      72           0 :         default:
      73           0 :                 errno = EINVAL;
      74           0 :                 return 1;
      75             :         }
      76          32 :         return 0;
      77             : }
      78             : 
      79             : /**
      80             :  * Create a new AST node of a given type from a source string.
      81             :  * Returns a pointer to the new node or NULL on failure with errno set.
      82             :  */
      83          40 : struct ast_node *ast_new(ast_node_t type, const char *text)
      84             : {
      85             :         struct ast_node *node;
      86          40 :         node = (struct ast_node *)calloc(1, sizeof(struct ast_node));
      87          40 :         if (node == NULL) {
      88           0 :                 goto return_fail;
      89             :         }
      90             : 
      91          40 :         if (type > _AST_EX_START && ast_expr_init(node, type, text)) {
      92           0 :                 goto return_free;
      93             :         }
      94             : 
      95          40 :         node->ast_text = strdup(text);
      96          40 :         if (node->ast_text == NULL) {
      97           0 :                 goto return_free;
      98             :         }
      99          40 :         node->ast_type = type;
     100             : 
     101          40 :         return node;
     102             : 
     103           0 : return_free:
     104           0 :         if (node->ast_text) {
     105           0 :                 free(node->ast_text);
     106             :         }
     107           0 :         if (node->ast_str) {
     108           0 :                 free(node->ast_str);
     109             :         }
     110           0 :         free(node);
     111           0 : return_fail:
     112           0 :         fprintf(stderr, "Failed to create new value from %s: %s\n", text, strerror(errno));
     113           0 :         return NULL;
     114             : }
     115             : 
     116             : /**
     117             :  * Free the memory allocated for an AST node and set its pointer to NULL
     118             :  */
     119          88 : void ast_destroy(struct ast_node **node)
     120             : {
     121          88 :         if (*node == NULL) {
     122          48 :                 return;
     123             :         }
     124          40 :         ast_destroy(&(*node)->ast_left);
     125          40 :         ast_destroy(&(*node)->ast_right);
     126          40 :         switch((*node)->ast_type) {
     127          16 :         case AST_EX_ID:
     128             :         case AST_EX_PATH:
     129             :         case AST_EX_STRING:
     130          16 :                 free((*node)->ast_str);
     131          16 :                 break;
     132          24 :         default:
     133          24 :                 break;
     134             :         }
     135          40 :         free((*node)->ast_text);
     136          40 :         free(*node);
     137          40 :         *node = NULL;
     138             : }
     139             : 
     140           0 : static void ast_string_unescape(char *str)
     141             : {
     142             :         int head, tail;
     143           0 :         for (head = tail = 0; str[head] != '\0'; head++, tail++) {
     144           0 :                 if (str[head] == '\\' && str[head+1] != '\0')
     145           0 :                         head++;
     146           0 :                 str[tail] = str[head];
     147             :         }
     148           0 :         str[tail] = '\0';
     149           0 : }
     150             : 
     151           1 : static uint64_t ast_lookup_path(char *path, struct lgfs2_sbd *sbd)
     152             : {
     153           1 :         char *c = NULL;
     154             :         struct lgfs2_inode *ip, *iptmp;
     155             :         char *segment;
     156           1 :         uint64_t bn = 0;
     157             : 
     158           1 :         segment = strtok_r(path, "/", &c);
     159           1 :         ip = lgfs2_inode_read(sbd, sbd->sd_root_dir.in_addr);
     160             : 
     161           1 :         while (ip != NULL) {
     162           1 :                 int err = 0;
     163             : 
     164           1 :                 if (segment == NULL) { // No more segments
     165           1 :                         bn = ip->i_num.in_addr;
     166           1 :                         lgfs2_inode_put(&ip);
     167           1 :                         return bn;
     168             :                 }
     169           0 :                 ast_string_unescape(segment);
     170           0 :                 iptmp = lgfs2_lookupi(ip, segment, strlen(segment));
     171           0 :                 err = errno;
     172           0 :                 if (ip != iptmp)
     173           0 :                         lgfs2_inode_put(&ip);
     174           0 :                 if (iptmp == NULL) {
     175           0 :                         errno = err;
     176           0 :                         break;
     177             :                 }
     178           0 :                 ip = iptmp;
     179           0 :                 segment = strtok_r(NULL, "/", &c);
     180             :         }
     181             : 
     182           0 :         return 0;
     183             : }
     184             : 
     185             : enum block_id {
     186             :         ID_SB   = 0,
     187             :         ID_MASTER,
     188             :         ID_ROOT,
     189             :         ID_RINDEX,
     190             : 
     191             :         ID_END
     192             : };
     193             : 
     194             : /**
     195             :  * Names of blocks which can be uniquely identified in the fs
     196             :  */
     197             : static const char *block_ids[] = {
     198             :         [ID_SB]         = "sb",
     199             :         [ID_MASTER]     = "master",
     200             :         [ID_ROOT]       = "root",
     201             :         [ID_RINDEX]     = "rindex",
     202             : 
     203             :         [ID_END]        = NULL
     204             : };
     205             : 
     206           7 : static uint64_t ast_lookup_id(const char *id, struct lgfs2_sbd *sbd)
     207             : {
     208           7 :         uint64_t bn = 0;
     209             :         int i;
     210           7 :         for (i = 0; i < ID_END; i++) {
     211           7 :                 if (!strcmp(id, block_ids[i])) {
     212           7 :                         break;
     213             :                 }
     214             :         }
     215           7 :         switch (i) {
     216           7 :         case ID_SB:
     217           7 :                 bn = LGFS2_SB_ADDR(sbd);
     218           7 :                 break;
     219           0 :         case ID_MASTER:
     220           0 :                 bn = sbd->sd_meta_dir.in_addr;
     221           0 :                 break;
     222           0 :         case ID_ROOT:
     223           0 :                 bn = sbd->sd_root_dir.in_addr;
     224           0 :                 break;
     225           0 :         case ID_RINDEX:
     226           0 :                 bn = sbd->md.riinode->i_num.in_addr;
     227           0 :                 break;
     228           0 :         default:
     229           0 :                 return 0;
     230             :         }
     231           7 :         return bn;
     232             : }
     233             : 
     234           0 : static uint64_t ast_lookup_rgrp(uint64_t rgnum, struct lgfs2_sbd *sbd)
     235             : {
     236           0 :         uint64_t i = rgnum;
     237             :         struct osi_node *n;
     238             : 
     239           0 :         for (n = osi_first(&sbd->rgtree); n != NULL && i > 0; n = osi_next(n), i--);
     240           0 :         if (n != NULL && i == 0)
     241           0 :                 return ((struct lgfs2_rgrp_tree *)n)->rt_addr;
     242           0 :         fprintf(stderr, "Resource group number out of range: %"PRIu64"\n", rgnum);
     243           0 :         return 0;
     244             : }
     245             : 
     246           0 : static uint64_t ast_lookup_subscript(struct ast_node *id, struct ast_node *index,
     247             :                                      struct lgfs2_sbd *sbd)
     248             : {
     249           0 :         uint64_t bn = 0;
     250           0 :         const char *name = id->ast_str;
     251           0 :         if (!strcmp(name, "rgrp")) {
     252           0 :                 bn = ast_lookup_rgrp(index->ast_num, sbd);
     253             :         } else {
     254           0 :                 fprintf(stderr, "Unrecognized identifier %s\n", name);
     255             :         }
     256           0 :         return bn;
     257             : }
     258             : 
     259             : /**
     260             :  * Look up a block and return its number. The kind of lookup depends on the
     261             :  * type of the ast node.
     262             :  */
     263           8 : static uint64_t ast_lookup_block_num(struct ast_node *ast, struct lgfs2_sbd *sbd)
     264             : {
     265           8 :         uint64_t bn = 0;
     266           8 :         switch (ast->ast_type) {
     267           0 :         case AST_EX_OFFSET:
     268           0 :                 bn = ast_lookup_block_num(ast->ast_left, sbd) + ast->ast_num;
     269           0 :                 break;
     270           0 :         case AST_EX_ADDRESS:
     271           0 :                 if (lgfs2_check_range(sbd, ast->ast_num))
     272           0 :                         break;
     273           0 :                 bn = ast->ast_num;
     274           0 :                 break;
     275           1 :         case AST_EX_PATH:
     276           1 :                 bn = ast_lookup_path(ast->ast_str, sbd);
     277           1 :                 break;
     278           7 :         case AST_EX_ID:
     279           7 :                 bn = ast_lookup_id(ast->ast_str, sbd);
     280           7 :                 break;
     281           0 :         case AST_EX_SUBSCRIPT:
     282           0 :                 bn = ast_lookup_subscript(ast->ast_left, ast->ast_left->ast_left, sbd);
     283           0 :                 break;
     284           0 :         default:
     285           0 :                 break;
     286             :         }
     287           8 :         return bn;
     288             : }
     289             : 
     290           8 : static uint64_t ast_lookup_block(struct ast_node *node, struct lgfs2_sbd *sbd)
     291             : {
     292           8 :         uint64_t bn = ast_lookup_block_num(node, sbd);
     293           8 :         if (bn == 0) {
     294           0 :                 fprintf(stderr, "Block not found: %s\n", node->ast_text);
     295           0 :                 return 0;
     296             :         }
     297           8 :         return bn;
     298             : }
     299             : 
     300             : static const char *bitstate_strings[] = {
     301             :         [GFS2_BLKST_FREE] = "Free",
     302             :         [GFS2_BLKST_USED] = "Used",
     303             :         [GFS2_BLKST_UNLINKED] = "Unlinked",
     304             :         [GFS2_BLKST_DINODE] = "Dinode"
     305             : };
     306             : 
     307             : /**
     308             :  * Print a representation of an arbitrary field of an arbitrary GFS2 block to stdout
     309             :  * Returns 0 if successful, 1 otherwise
     310             :  */
     311         204 : static int field_print(char *buf, uint64_t addr, const struct lgfs2_metadata *mtype,
     312             :                       const struct lgfs2_metafield *field)
     313             : {
     314         204 :         const char *fieldp = buf + field->offset;
     315             : 
     316         204 :         printf("%s\t%"PRIu64"\t%u\t%u\t%s\t", mtype->name, addr, field->offset, field->length, field->name);
     317         204 :         if (field->flags & LGFS2_MFF_UUID) {
     318             :                 char readable_uuid[36+1];
     319             :                 uuid_t uuid;
     320             : 
     321           7 :                 memcpy(uuid, fieldp, sizeof(uuid_t));
     322           7 :                 uuid_unparse(uuid, readable_uuid);
     323           7 :                 printf("'%s'\n", readable_uuid);
     324         197 :         } else if (field->flags & LGFS2_MFF_STRING) {
     325          14 :                 printf("'%s'\n", fieldp);
     326             :         } else {
     327         183 :                 switch(field->length) {
     328           0 :                 case 1:
     329           0 :                         printf("%"PRIu8"\n", *(uint8_t *)fieldp);
     330           0 :                         break;
     331           4 :                 case 2:
     332           4 :                         printf("%"PRIu16"\n", be16_to_cpu(*(__be16 *)fieldp));
     333           4 :                         break;
     334          87 :                 case 4:
     335          87 :                         printf("%"PRIu32"\n", be32_to_cpu(*(__be32 *)fieldp));
     336          87 :                         break;
     337          91 :                 case 8:
     338          91 :                         printf("%"PRIu64"\n", be64_to_cpu(*(__be64 *)fieldp));
     339          91 :                         break;
     340           1 :                 default:
     341             :                         // "Reserved" field so just print 0
     342           1 :                         printf("0\n");
     343           1 :                         return 1;
     344             :                 }
     345             :         }
     346         203 :         return 0;
     347             : }
     348             : 
     349             : /**
     350             :  * Print a representation of an arbitrary GFS2 block to stdout
     351             :  */
     352           8 : int lgfs2_lang_result_print(struct lgfs2_lang_result *result)
     353             : {
     354             :         int i;
     355           8 :         if (result->lr_mtype != NULL) {
     356         212 :                 for (i = 0; i < result->lr_mtype->nfields; i++) {
     357         204 :                         field_print(result->lr_buf, result->lr_blocknr,
     358         204 :                                     result->lr_mtype, &result->lr_mtype->fields[i]);
     359             :                 }
     360             :         } else {
     361           0 :                 printf("%"PRIu64": %s\n", result->lr_blocknr, bitstate_strings[result->lr_state]);
     362             :         }
     363           8 :         return 0;
     364             : }
     365             : 
     366           0 : static int ast_get_bitstate(uint64_t bn, struct lgfs2_sbd *sbd)
     367             : {
     368           0 :         int ret = 0;
     369           0 :         int state = 0;
     370           0 :         struct lgfs2_rgrp_tree *rgd = lgfs2_blk2rgrpd(sbd, bn);
     371           0 :         if (rgd == NULL) {
     372           0 :                 fprintf(stderr, "Could not find resource group for block %"PRIu64"\n", bn);
     373           0 :                 return -1;
     374             :         }
     375             : 
     376           0 :         ret = lgfs2_rgrp_read(sbd, rgd);
     377           0 :         if (ret != 0) {
     378           0 :                 fprintf(stderr, "Failed to read resource group for block %"PRIu64": %d\n", bn, ret);
     379           0 :                 return -1;
     380             :         }
     381             : 
     382           0 :         state = lgfs2_get_bitmap(sbd, bn, rgd);
     383           0 :         if (state == -1) {
     384           0 :                 fprintf(stderr, "Failed to acquire bitmap state for block %"PRIu64"\n", bn);
     385           0 :                 return -1;
     386             :         }
     387             : 
     388           0 :         lgfs2_rgrp_relse(sbd, rgd);
     389           0 :         return state;
     390             : }
     391             : 
     392           0 : static void result_lookup_mtype(struct lgfs2_lang_result *result)
     393             : {
     394           0 :         const uint32_t mh_type = lgfs2_get_block_type(result->lr_buf);
     395           0 :         uint64_t addr = result->lr_blocknr;
     396             : 
     397           0 :         result->lr_mtype = NULL;
     398           0 :         if (mh_type == 0) {
     399           0 :                 fprintf(stderr, "Could not determine type for block %"PRIu64"\n", addr);
     400           0 :                 return;
     401             :         }
     402           0 :         result->lr_mtype = lgfs2_find_mtype(mh_type);
     403           0 :         if (result->lr_mtype == NULL)
     404           0 :                 fprintf(stderr, "Could not determine meta type for block %"PRIu64"\n", addr);
     405             : }
     406             : 
     407           8 : static char *lang_read_block(int fd, unsigned bsize, uint64_t addr)
     408             : {
     409           8 :         off_t off = addr * bsize;
     410             :         char *buf;
     411             : 
     412           8 :         buf = calloc(1, bsize);
     413           8 :         if (buf == NULL) {
     414           0 :                 perror("Failed to read block");
     415           0 :                 return NULL;
     416             :         }
     417           8 :         if (pread(fd, buf, bsize, off) != bsize) {
     418           0 :                 fprintf(stderr, "Failed to read block %"PRIu64": %s\n", addr, strerror(errno));
     419           0 :                 free(buf);
     420           0 :                 return NULL;
     421             :         }
     422           8 :         return buf;
     423             : }
     424             : 
     425             : /**
     426             :  * Interpret the get statement.
     427             :  */
     428           0 : static struct lgfs2_lang_result *ast_interp_get(struct lgfs2_lang_state *state,
     429             :                                      struct ast_node *ast, struct lgfs2_sbd *sbd)
     430             : {
     431           0 :         struct lgfs2_lang_result *result = calloc(1, sizeof(struct lgfs2_lang_result));
     432           0 :         if (result == NULL) {
     433           0 :                 fprintf(stderr, "Failed to allocate memory for result\n");
     434           0 :                 return NULL;
     435             :         }
     436             : 
     437           0 :         if (ast->ast_right->ast_right == NULL) {
     438           0 :                 result->lr_blocknr = ast_lookup_block(ast->ast_right, sbd);
     439           0 :                 if (result->lr_blocknr == 0) {
     440           0 :                         free(result);
     441           0 :                         return NULL;
     442             :                 }
     443           0 :                 result->lr_buf = lang_read_block(sbd->device_fd, sbd->sd_bsize, result->lr_blocknr);
     444           0 :                 if (result->lr_buf == NULL) {
     445           0 :                         free(result);
     446           0 :                         return NULL;
     447             :                 }
     448           0 :                 result_lookup_mtype(result);
     449             : 
     450           0 :         } else if (ast->ast_right->ast_right->ast_type == AST_KW_STATE) {
     451           0 :                 result->lr_blocknr = ast_lookup_block_num(ast->ast_right, sbd);
     452           0 :                 if (result->lr_blocknr == 0) {
     453           0 :                         free(result);
     454           0 :                         return NULL;
     455             :                 }
     456           0 :                 result->lr_state = ast_get_bitstate(result->lr_blocknr, sbd);
     457             :         }
     458             : 
     459           0 :         return result;
     460             : }
     461             : 
     462             : /**
     463             :  * Set a field of a gfs2 block of a given type to a given value.
     464             :  * Returns AST_INTERP_* to signal success, an invalid field/value or an error.
     465             :  */
     466           8 : static int ast_field_set(char *buf, const struct lgfs2_metafield *field,
     467             :                          struct ast_node *val)
     468             : {
     469           8 :         int err = 0;
     470             : 
     471           8 :         if (field->flags & LGFS2_MFF_UUID) {
     472             :                 uuid_t uuid;
     473             : 
     474           0 :                 if (uuid_parse(val->ast_str, uuid) != 0) {
     475           0 :                         fprintf(stderr, "Invalid UUID\n");
     476           0 :                         return AST_INTERP_INVAL;
     477             :                 }
     478           0 :                 err = lgfs2_field_assign(buf, field, uuid);
     479           8 :         } else if (field->flags & LGFS2_MFF_STRING) {
     480           0 :                 err = lgfs2_field_assign(buf, field, val->ast_str);
     481             :         } else {
     482             :                 /* coverity[overrun-buffer-val:SUPPRESS] False positive */
     483           8 :                 err = lgfs2_field_assign(buf, field, &val->ast_num);
     484             :         }
     485             : 
     486           8 :         if (err) {
     487           0 :                 fprintf(stderr, "Invalid field assignment: %s (size %d) = %s\n",
     488           0 :                         field->name, field->length, val->ast_text);
     489           0 :                 return AST_INTERP_INVAL;
     490             :         }
     491           8 :         return AST_INTERP_SUCCESS;
     492             : }
     493             : 
     494           8 : static const struct lgfs2_metadata *lang_find_mtype(struct ast_node *node, const char *buf)
     495             : {
     496           8 :         const struct lgfs2_metadata *mtype = NULL;
     497             : 
     498           8 :         if (node->ast_type == AST_EX_TYPESPEC) {
     499           0 :                 mtype = lgfs2_find_mtype_name(node->ast_str);
     500           0 :                 if (mtype == NULL)
     501           0 :                         fprintf(stderr, "Invalid block type: %s\n", node->ast_text);
     502             :         } else {
     503           8 :                 mtype = lgfs2_find_mtype(lgfs2_get_block_type(buf));
     504           8 :                 if (mtype == NULL)
     505           0 :                         fprintf(stderr, "Unrecognised block at: %s\n", node->ast_text);
     506             :         }
     507             : 
     508           8 :         return mtype;
     509             : }
     510             : 
     511           8 : static int lang_write_result(int fd, unsigned bsize, struct lgfs2_lang_result *result)
     512             : {
     513           8 :         off_t off = bsize * result->lr_blocknr;
     514             : 
     515           8 :         if (pwrite(fd, result->lr_buf, bsize, off) != bsize) {
     516           0 :                 fprintf(stderr, "Failed to write modified block %"PRIu64": %s\n",
     517           0 :                                 result->lr_blocknr, strerror(errno));
     518           0 :                 return -1;
     519             :         }
     520           8 :         return 0;
     521             : }
     522             : 
     523             : /**
     524             :  * Interpret an assignment (set)
     525             :  */
     526           8 : static struct lgfs2_lang_result *ast_interp_set(struct lgfs2_lang_state *state,
     527             :                                     struct ast_node *ast, struct lgfs2_sbd *sbd)
     528             : {
     529           8 :         struct ast_node *lookup = ast->ast_right;
     530             :         struct ast_node *fieldspec;
     531             :         struct ast_node *fieldname;
     532             :         struct ast_node *fieldval;
     533           8 :         int ret = 0;
     534             : 
     535           8 :         struct lgfs2_lang_result *result = calloc(1, sizeof(struct lgfs2_lang_result));
     536           8 :         if (result == NULL) {
     537           0 :                 fprintf(stderr, "Failed to allocate memory for result\n");
     538           0 :                 return NULL;
     539             :         }
     540             : 
     541           8 :         result->lr_blocknr = ast_lookup_block(lookup, sbd);
     542           8 :         if (result->lr_blocknr == 0)
     543           0 :                 goto out_err;
     544           8 :         result->lr_buf = lang_read_block(sbd->device_fd, sbd->sd_bsize, result->lr_blocknr);
     545           8 :         if (result->lr_buf == NULL)
     546           0 :                 goto out_err;
     547             : 
     548           8 :         result->lr_mtype = lang_find_mtype(lookup->ast_right, result->lr_buf);
     549           8 :         if (result->lr_mtype == NULL) {
     550           0 :                 fprintf(stderr, "Unrecognised block at: %s\n", lookup->ast_str);
     551           0 :                 goto out_err;
     552             :         }
     553             : 
     554           8 :         if (lookup->ast_right->ast_type == AST_EX_TYPESPEC) {
     555           0 :                 struct gfs2_meta_header mh = {
     556           0 :                         .mh_magic = cpu_to_be32(GFS2_MAGIC),
     557           0 :                         .mh_type = cpu_to_be32(result->lr_mtype->mh_type),
     558           0 :                         .mh_format = cpu_to_be32(result->lr_mtype->mh_format),
     559             :                 };
     560           0 :                 memcpy(result->lr_buf, &mh, sizeof(mh));
     561           0 :                 lookup = lookup->ast_right;
     562             :         }
     563             : 
     564           8 :         for (fieldspec = lookup->ast_right;
     565          16 :              fieldspec != NULL && fieldspec->ast_type == AST_EX_FIELDSPEC;
     566           8 :              fieldspec = fieldspec->ast_left) {
     567             :                 const struct lgfs2_metafield *mfield;
     568             : 
     569           8 :                 fieldname = fieldspec->ast_right;
     570           8 :                 fieldval = fieldname->ast_right;
     571             : 
     572           8 :                 mfield = lgfs2_find_mfield_name(fieldname->ast_str, result->lr_mtype);
     573           8 :                 if (mfield == NULL) {
     574           0 :                         fprintf(stderr, "No field '%s' found in '%s'\n",
     575           0 :                                 fieldname->ast_str, result->lr_mtype->name);
     576           0 :                         goto out_err;
     577             :                 }
     578             : 
     579           8 :                 ret = ast_field_set(result->lr_buf, mfield, fieldval);
     580           8 :                 if (ret != AST_INTERP_SUCCESS) {
     581           0 :                         goto out_err;
     582             :                 }
     583             :         }
     584             : 
     585           8 :         ret = lang_write_result(sbd->device_fd, sbd->sd_bsize, result);
     586           8 :         if (ret != 0)
     587           0 :                 goto out_err;
     588             : 
     589           8 :         return result;
     590           0 : out_err:
     591           0 :         lgfs2_lang_result_free(&result);
     592           0 :         return NULL;
     593             : }
     594             : 
     595           8 : static struct lgfs2_lang_result *ast_interpret_node(struct lgfs2_lang_state *state,
     596             :                                         struct ast_node *ast, struct lgfs2_sbd *sbd)
     597             : {
     598           8 :         struct lgfs2_lang_result *result = NULL;
     599             : 
     600           8 :         if (ast->ast_type == AST_ST_SET) {
     601           8 :                 result = ast_interp_set(state, ast, sbd);
     602           0 :         } else if (ast->ast_type == AST_ST_GET) {
     603           0 :                 result = ast_interp_get(state, ast, sbd);
     604             :         } else {
     605           0 :                 fprintf(stderr, "Invalid AST node type: %d\n", ast->ast_type);
     606             :         }
     607           8 :         return result;
     608             : }
     609             : 
     610          16 : struct lgfs2_lang_result *lgfs2_lang_result_next(struct lgfs2_lang_state *state,
     611             :                                                            struct lgfs2_sbd *sbd)
     612             : {
     613             :         struct lgfs2_lang_result *result;
     614          16 :         if (state->ls_interp_curr == NULL) {
     615           8 :                 return NULL;
     616             :         }
     617           8 :         result = ast_interpret_node(state, state->ls_interp_curr, sbd);
     618           8 :         if (result == NULL) {
     619           0 :                 return NULL;
     620             :         }
     621           8 :         state->ls_interp_curr = state->ls_interp_curr->ast_left;
     622           8 :         return result;
     623             : }
     624             : 
     625           8 : void lgfs2_lang_result_free(struct lgfs2_lang_result **result)
     626             : {
     627           8 :         if (*result == NULL) {
     628           0 :                 fprintf(stderr, "Warning: attempted to free a null result\n");
     629           0 :                 return;
     630             :         }
     631           8 :         free((*result)->lr_buf);
     632           8 :         free(*result);
     633           8 :         *result = NULL;
     634             : }

Generated by: LCOV version 1.14