1*40edb9c0SDavid Marchand /* SPDX-License-Identifier: BSD-3-Clause 2*40edb9c0SDavid Marchand * Copyright(c) 2021 Red Hat, Inc. 3*40edb9c0SDavid Marchand */ 4*40edb9c0SDavid Marchand 5*40edb9c0SDavid Marchand #ifdef RTE_HAS_LIBARCHIVE 6*40edb9c0SDavid Marchand #include <archive.h> 7*40edb9c0SDavid Marchand #endif 8*40edb9c0SDavid Marchand #include <fcntl.h> 9*40edb9c0SDavid Marchand #include <stdio.h> 10*40edb9c0SDavid Marchand #include <stdlib.h> 11*40edb9c0SDavid Marchand #include <unistd.h> 12*40edb9c0SDavid Marchand 13*40edb9c0SDavid Marchand #include <rte_common.h> 14*40edb9c0SDavid Marchand #include <rte_log.h> 15*40edb9c0SDavid Marchand 16*40edb9c0SDavid Marchand #include "eal_firmware.h" 17*40edb9c0SDavid Marchand 18*40edb9c0SDavid Marchand #ifdef RTE_HAS_LIBARCHIVE 19*40edb9c0SDavid Marchand 20*40edb9c0SDavid Marchand struct firmware_read_ctx { 21*40edb9c0SDavid Marchand struct archive *a; 22*40edb9c0SDavid Marchand }; 23*40edb9c0SDavid Marchand 24*40edb9c0SDavid Marchand static int 25*40edb9c0SDavid Marchand firmware_open(struct firmware_read_ctx *ctx, const char *name, size_t blocksize) 26*40edb9c0SDavid Marchand { 27*40edb9c0SDavid Marchand struct archive_entry *e; 28*40edb9c0SDavid Marchand 29*40edb9c0SDavid Marchand ctx->a = archive_read_new(); 30*40edb9c0SDavid Marchand if (ctx->a == NULL) 31*40edb9c0SDavid Marchand return -1; 32*40edb9c0SDavid Marchand if (archive_read_support_format_raw(ctx->a) != ARCHIVE_OK || 33*40edb9c0SDavid Marchand archive_read_support_filter_xz(ctx->a) != ARCHIVE_OK || 34*40edb9c0SDavid Marchand archive_read_open_filename(ctx->a, name, blocksize) != ARCHIVE_OK || 35*40edb9c0SDavid Marchand archive_read_next_header(ctx->a, &e) != ARCHIVE_OK) { 36*40edb9c0SDavid Marchand archive_read_free(ctx->a); 37*40edb9c0SDavid Marchand ctx->a = NULL; 38*40edb9c0SDavid Marchand return -1; 39*40edb9c0SDavid Marchand } 40*40edb9c0SDavid Marchand return 0; 41*40edb9c0SDavid Marchand } 42*40edb9c0SDavid Marchand 43*40edb9c0SDavid Marchand static ssize_t 44*40edb9c0SDavid Marchand firmware_read_block(struct firmware_read_ctx *ctx, void *buf, size_t count) 45*40edb9c0SDavid Marchand { 46*40edb9c0SDavid Marchand return archive_read_data(ctx->a, buf, count); 47*40edb9c0SDavid Marchand } 48*40edb9c0SDavid Marchand 49*40edb9c0SDavid Marchand static void 50*40edb9c0SDavid Marchand firmware_close(struct firmware_read_ctx *ctx) 51*40edb9c0SDavid Marchand { 52*40edb9c0SDavid Marchand archive_read_free(ctx->a); 53*40edb9c0SDavid Marchand ctx->a = NULL; 54*40edb9c0SDavid Marchand } 55*40edb9c0SDavid Marchand 56*40edb9c0SDavid Marchand #else /* !RTE_HAS_LIBARCHIVE */ 57*40edb9c0SDavid Marchand 58*40edb9c0SDavid Marchand struct firmware_read_ctx { 59*40edb9c0SDavid Marchand int fd; 60*40edb9c0SDavid Marchand }; 61*40edb9c0SDavid Marchand 62*40edb9c0SDavid Marchand static int 63*40edb9c0SDavid Marchand firmware_open(struct firmware_read_ctx *ctx, const char *name, 64*40edb9c0SDavid Marchand __rte_unused size_t blocksize) 65*40edb9c0SDavid Marchand { 66*40edb9c0SDavid Marchand ctx->fd = open(name, O_RDONLY); 67*40edb9c0SDavid Marchand if (ctx->fd < 0) 68*40edb9c0SDavid Marchand return -1; 69*40edb9c0SDavid Marchand return 0; 70*40edb9c0SDavid Marchand } 71*40edb9c0SDavid Marchand 72*40edb9c0SDavid Marchand static ssize_t 73*40edb9c0SDavid Marchand firmware_read_block(struct firmware_read_ctx *ctx, void *buf, size_t count) 74*40edb9c0SDavid Marchand { 75*40edb9c0SDavid Marchand return read(ctx->fd, buf, count); 76*40edb9c0SDavid Marchand } 77*40edb9c0SDavid Marchand 78*40edb9c0SDavid Marchand static void 79*40edb9c0SDavid Marchand firmware_close(struct firmware_read_ctx *ctx) 80*40edb9c0SDavid Marchand { 81*40edb9c0SDavid Marchand close(ctx->fd); 82*40edb9c0SDavid Marchand ctx->fd = -1; 83*40edb9c0SDavid Marchand } 84*40edb9c0SDavid Marchand 85*40edb9c0SDavid Marchand #endif /* !RTE_HAS_LIBARCHIVE */ 86*40edb9c0SDavid Marchand 87*40edb9c0SDavid Marchand static int 88*40edb9c0SDavid Marchand firmware_read(const char *name, void **buf, size_t *bufsz) 89*40edb9c0SDavid Marchand { 90*40edb9c0SDavid Marchand const size_t blocksize = 4096; 91*40edb9c0SDavid Marchand struct firmware_read_ctx ctx; 92*40edb9c0SDavid Marchand int ret = -1; 93*40edb9c0SDavid Marchand int err; 94*40edb9c0SDavid Marchand 95*40edb9c0SDavid Marchand *buf = NULL; 96*40edb9c0SDavid Marchand *bufsz = 0; 97*40edb9c0SDavid Marchand 98*40edb9c0SDavid Marchand if (firmware_open(&ctx, name, blocksize) < 0) 99*40edb9c0SDavid Marchand return -1; 100*40edb9c0SDavid Marchand 101*40edb9c0SDavid Marchand do { 102*40edb9c0SDavid Marchand void *tmp; 103*40edb9c0SDavid Marchand 104*40edb9c0SDavid Marchand tmp = realloc(*buf, *bufsz + blocksize); 105*40edb9c0SDavid Marchand if (tmp == NULL) { 106*40edb9c0SDavid Marchand free(*buf); 107*40edb9c0SDavid Marchand *buf = NULL; 108*40edb9c0SDavid Marchand *bufsz = 0; 109*40edb9c0SDavid Marchand goto out; 110*40edb9c0SDavid Marchand } 111*40edb9c0SDavid Marchand *buf = tmp; 112*40edb9c0SDavid Marchand 113*40edb9c0SDavid Marchand err = firmware_read_block(&ctx, RTE_PTR_ADD(*buf, *bufsz), blocksize); 114*40edb9c0SDavid Marchand if (err < 0) { 115*40edb9c0SDavid Marchand free(*buf); 116*40edb9c0SDavid Marchand *buf = NULL; 117*40edb9c0SDavid Marchand *bufsz = 0; 118*40edb9c0SDavid Marchand goto out; 119*40edb9c0SDavid Marchand } 120*40edb9c0SDavid Marchand *bufsz += err; 121*40edb9c0SDavid Marchand 122*40edb9c0SDavid Marchand } while (err != 0); 123*40edb9c0SDavid Marchand 124*40edb9c0SDavid Marchand ret = 0; 125*40edb9c0SDavid Marchand out: 126*40edb9c0SDavid Marchand firmware_close(&ctx); 127*40edb9c0SDavid Marchand return ret; 128*40edb9c0SDavid Marchand } 129*40edb9c0SDavid Marchand 130*40edb9c0SDavid Marchand int 131*40edb9c0SDavid Marchand rte_firmware_read(const char *name, void **buf, size_t *bufsz) 132*40edb9c0SDavid Marchand { 133*40edb9c0SDavid Marchand char path[PATH_MAX]; 134*40edb9c0SDavid Marchand int ret; 135*40edb9c0SDavid Marchand 136*40edb9c0SDavid Marchand ret = firmware_read(name, buf, bufsz); 137*40edb9c0SDavid Marchand if (ret < 0) { 138*40edb9c0SDavid Marchand snprintf(path, sizeof(path), "%s.xz", name); 139*40edb9c0SDavid Marchand path[PATH_MAX - 1] = '\0'; 140*40edb9c0SDavid Marchand #ifndef RTE_HAS_LIBARCHIVE 141*40edb9c0SDavid Marchand if (access(path, F_OK) == 0) { 142*40edb9c0SDavid Marchand RTE_LOG(WARNING, EAL, "libarchive not linked, %s cannot be decompressed\n", 143*40edb9c0SDavid Marchand path); 144*40edb9c0SDavid Marchand } 145*40edb9c0SDavid Marchand #else 146*40edb9c0SDavid Marchand ret = firmware_read(path, buf, bufsz); 147*40edb9c0SDavid Marchand #endif 148*40edb9c0SDavid Marchand } 149*40edb9c0SDavid Marchand return ret; 150*40edb9c0SDavid Marchand } 151