Quan Wen
Quan Wen

Reputation: 11

How can I open directories of ext4 format filesystem partition in uboot

fs_opendir is not supported in ext4 filesystem, but I need to access files in a ext4 filesystem directory in uboot.

Here is what I found in uboot source code:

#if CONFIG_IS_ENABLED(FS_EXT4)
    {
        .fstype = FS_TYPE_EXT,
        .name = "ext4",
        .null_dev_desc_ok = false,
        .probe = ext4fs_probe,
        .close = ext4fs_close,
        .ls = ext4fs_ls,
        .exists = ext4fs_exists,
        .size = ext4fs_size,
        .read = ext4_read_file,
#ifdef CONFIG_CMD_EXT4_WRITE
        .write = ext4_write_file,
        .ln = ext4fs_create_link,
#else
        .write = fs_write_unsupported,
        .ln = fs_ln_unsupported,
#endif
        .uuid = ext4fs_uuid,
        .opendir = fs_opendir_unsupported,
        .unlink = fs_unlink_unsupported,
        .mkdir = fs_mkdir_unsupported,
    },

I try using ext4fs_find_file to check if the directory exist. If the directory exists, I try to read directories and files in it by a function modified from ext4fs_iterate_find. And here is the code:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <common.h>
#include <command.h>
#include <fs.h>
#include <blk.h>
#include <ext4fs.h>
#include <part.h>
#include <linux/ctype.h>
#include <linux/stddef.h>

#define BOOT_FLAG0 "ostree/boot.0/tcu"
#define BOOT_FLAG1 "ostree/boot.1/tcu"
#define ROLLBACK_FLAG "0"
#define HASH_SIZE 64
#define OLD_BOOTARGS "old_bootargs"

extern int ext4fs_read_file(struct ext2fs_node *node, loff_t pos,
        loff_t len, char *buf, loff_t *actread);

static int ext4fs_iterate_find_ostree_hash(struct ext2fs_node *dir, char **hash) {
    unsigned int fpos = 0;
    int status;
    loff_t actread;
    struct ext2fs_node *diro = (struct ext2fs_node *) dir;

    if (!diro->inode_read) {
        status = ext4fs_read_inode(diro->data, diro->ino, &diro->inode);
        if (status == 0)
            return 0;
    }
    /* Search the file.  */
    while (fpos < le32_to_cpu(diro->inode.size)) {
        struct ext2_dirent dirent;

        status = ext4fs_read_file(diro, fpos,
                       sizeof(struct ext2_dirent),
                       (char *)&dirent, &actread);
        if (status < 0) {
            return 1;
        }

        if (dirent.filetype != FILETYPE_DIRECTORY) {
            printf("Invalid file in path\n");
            return 1;
        }

        if (dirent.direntlen != HASH_SIZE) {
            printf("Hash size not match: %d\n", dirent.direntlen);
            return 1;
        }

        struct ext2fs_node *fdiro;
        int type = FILETYPE_UNKNOWN;

        status = ext4fs_read_file(diro,
                        fpos +
                        sizeof(struct ext2_dirent),
                        dirent.namelen, *hash,
                        &actread);
        if (status < 0) {
            return 1;
        }

        // fdiro = zalloc(sizeof(struct ext2fs_node));
        // if (!fdiro) {
        //     return 0;
        // }

        // fdiro->data = diro->data;
        // fdiro->ino = le32_to_cpu(dirent.inode);

        *hash[dirent.namelen] = '\0';
        // free(fdiro);
        fpos += le16_to_cpu(dirent.direntlen);
    }
    return 0;
}

static int read_ostree_hash(const char *dirname, char **hash) {
    struct ext2fs_node *dirnode = NULL;
    int status;

    if (dirname == NULL)
        return 1;

    status = ext4fs_find_file(dirname, &ext4fs_root->diropen, &dirnode,
                  FILETYPE_DIRECTORY);
    if (status != 1) {
        printf("** Can not find directory. **\n");
        if (dirnode)
            ext4fs_free_node(dirnode, &ext4fs_root->diropen);
        return 1;
    }

    if (ext4fs_iterate_find_ostree_hash(dirnode, hash)) {
        return 1;
    }

    ext4fs_free_node(dirnode, &ext4fs_root->diropen);
    return 0;
}

static int ext4_dir_exists(const char *dirname) {
    struct ext2fs_node *dirnode = NULL;
    int status;

    if (dirname == NULL)
        return 1;

    return ext4fs_find_file(dirname, &ext4fs_root->diropen, &dirnode,
                  FILETYPE_DIRECTORY);
}

static int update_bootargs_env_with_ostree_env(const char* ostree_env) {
    char *old_env = NULL;
    char new_env[1000];

    old_env = env_get(OLD_BOOTARGS);
    if (old_env == NULL) {
        old_env = env_get("bootargs");
        if (old_env == NULL) {
            printf("[ERR] error bootargs read!\n");
            return 1;
        }
        env_set(OLD_BOOTARGS, old_env);
    }

    sprintf(new_env, "%s %s", old_env, ostree_env);
    env_set("bootargs", new_env);

    return 0;
}

int ostree_boot(const char *ifname, const char *dev_part, int is_rollback) {
    struct fs_dir_stream *dirs = NULL;
    struct fs_dirent *dent = NULL;
    char boot_dir[100];
    char hash[HASH_SIZE + 1];
    char cmd0[1024];
    char cmd1[1024];

    memset(hash, 0, sizeof(hash));
    memset(boot_dir, 0, sizeof(boot_dir));
    
    printf("[STEP]1 Find boot path\n");
    if (ext4_dir_exists(BOOT_FLAG0) == 0) {
        printf("[INFO] boot at %s\n", BOOT_FLAG0);
        memcpy(boot_dir, BOOT_FLAG0, strlen(BOOT_FLAG0));
    } else if (ext4_dir_exists(BOOT_FLAG1) == 0) {
        printf("[INFO] boot at %s\n", BOOT_FLAG1);
        memcpy(boot_dir, BOOT_FLAG1, strlen(BOOT_FLAG1));
    } else {
        printf("[ERROR] Can not ls boot dir\n");
        return 1;
    }

    printf("[STEP]2 Get boot hash\n");
    if (read_ostree_hash(boot_dir, &hash)) {
        return 1;
    }

    char boot_str[500];
    memset(boot_str, 0, sizeof(boot_str));
    sprintf(boot_str, "ostree=%s/%s/%u, ostree_root=/dev/mmcblk0p4", boot_dir, hash, is_rollback ? 1 : 0);

    printf("[STEP]3 Update bootargs\n");
    if (update_bootargs_env_with_ostree_env(boot_str)) {
        printf("[ERROR] Failed to update bootargs\n");
        return 1;
    }

    return 0;
}

int do_ostree_boot(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) {
    if (argc != 3) {
        printf("Usage: ostree_boot ifname <device>:<partition>\n");
        return 1;
    }

    if (ostree_boot(argv[1], argv[2], 0)) {
        return 1;
    }
}

int do_ostree_rollback(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) {
    if (argc != 3) {
        printf("Usage: ostree_rollback ifname <device>:<partition>\n");
        return 1;
    }

    if (ostree_boot(argv[1], argv[2], 1)) {
        return 1;
    }
}

U_BOOT_CMD(
    ostree_rollback,
    3,
    1,
    do_ostree_rollback,
    "format : do_ostree_rollback <dev>:<part> <is_rollback>",
    "example: do_ostree_rollback 0:1 0"
);

U_BOOT_CMD(
    ostree_boot,
    3,
    1,
    do_ostree_boot,
    "format: ostree_boot <ifname> <dev>:<part>",
    "example: ostree_boot mmc 0:4"
)

Once I execute the command ostree_boot, U-boot crashes and output is here:

"Synchronous Abort" handler, esr 0x96000004
elr: 000000008205a3f0 lr : 000000008205b504 (reloc)
elr: 00000000f7b7e3f0 lr : 00000000f7b7f504
x0 : 350001400a050000 x1 : 0000000000000000
x2 : 0000000000000008 x3 : 00000000f79dff68
x4 : 00000000f79dff60 x5 : 0000000000000180
x6 : 0000000000000000 x7 : 00000000f7a07030
x8 : 0000000000000000 x9 : 0000000000000008
x10: 0000000000000044 x11: 000000000000000d
x12: 0000000000000006 x13: 000000000001869f
x14: 00000000f79e09d0 x15: 0000000000000002
x16: 00000000f7b4cc68 x17: 0000000000000000
x18: 00000000f79e3d90 x19: 0000000000000008
x20: 0000000000000001 x21: 00000000b9468040
x22: 0000000000000000 x23: 0000000000000000
x24: 000000004d8bffa7 x25: 00000000f79e000c
x26: 00000000b2740063 x27: 00000000f7bb4000
x28: 00000000f7a06290 x29: 00000000f79dfe00

Code: f94000a0 4b1a0318 b9400cb5 f90033e5 (b9401800) 
Resetting CPU ...

I put the directories and files in mmc 0:4

Upvotes: 1

Views: 118

Answers (0)

Related Questions