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