LCOV - code coverage report
Current view: top level - libgfs2 - lang.c (source / functions) Coverage Total Hit
Test: gfs2-utils.info Lines: 48.2 % 340 164
Test Date: 2024-03-07 16:24:06 Functions: 73.9 % 23 17

            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 2.0-1