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 #include "eal_private.h" 18 19 static const char * const compression_suffixes[] = { "xz", "zst" }; 20 21 #ifdef RTE_HAS_LIBARCHIVE 22 23 struct firmware_read_ctx { 24 struct archive *a; 25 }; 26 27 static int 28 firmware_open(struct firmware_read_ctx *ctx, const char *name, size_t blocksize) 29 { 30 struct archive_entry *e; 31 int err; 32 33 ctx->a = archive_read_new(); 34 if (ctx->a == NULL) 35 return -1; 36 37 if (archive_read_support_format_raw(ctx->a) != ARCHIVE_OK) 38 goto error; 39 40 err = archive_read_support_filter_xz(ctx->a); 41 if (err != ARCHIVE_OK && err != ARCHIVE_WARN) 42 EAL_LOG(DEBUG, "could not initialise libarchive for xz compression"); 43 44 err = archive_read_support_filter_zstd(ctx->a); 45 if (err != ARCHIVE_OK && err != ARCHIVE_WARN) 46 EAL_LOG(DEBUG, "could not initialise libarchive for zstd compression"); 47 48 if (archive_read_open_filename(ctx->a, name, blocksize) != ARCHIVE_OK) 49 goto error; 50 51 if (archive_read_next_header(ctx->a, &e) != ARCHIVE_OK) 52 goto error; 53 54 return 0; 55 56 error: 57 archive_read_free(ctx->a); 58 ctx->a = NULL; 59 return -1; 60 } 61 62 static ssize_t 63 firmware_read_block(struct firmware_read_ctx *ctx, void *buf, size_t count) 64 { 65 return archive_read_data(ctx->a, buf, count); 66 } 67 68 static void 69 firmware_close(struct firmware_read_ctx *ctx) 70 { 71 archive_read_free(ctx->a); 72 ctx->a = NULL; 73 } 74 75 #else /* !RTE_HAS_LIBARCHIVE */ 76 77 struct firmware_read_ctx { 78 int fd; 79 }; 80 81 static int 82 firmware_open(struct firmware_read_ctx *ctx, const char *name, 83 __rte_unused size_t blocksize) 84 { 85 ctx->fd = open(name, O_RDONLY); 86 if (ctx->fd < 0) 87 return -1; 88 return 0; 89 } 90 91 static ssize_t 92 firmware_read_block(struct firmware_read_ctx *ctx, void *buf, size_t count) 93 { 94 return read(ctx->fd, buf, count); 95 } 96 97 static void 98 firmware_close(struct firmware_read_ctx *ctx) 99 { 100 close(ctx->fd); 101 ctx->fd = -1; 102 } 103 104 #endif /* !RTE_HAS_LIBARCHIVE */ 105 106 static int 107 firmware_read(const char *name, void **buf, size_t *bufsz) 108 { 109 const size_t blocksize = 4096; 110 struct firmware_read_ctx ctx; 111 int ret = -1; 112 int err; 113 114 *buf = NULL; 115 *bufsz = 0; 116 117 if (firmware_open(&ctx, name, blocksize) < 0) 118 return -1; 119 120 do { 121 void *tmp; 122 123 tmp = realloc(*buf, *bufsz + blocksize); 124 if (tmp == NULL) { 125 free(*buf); 126 *buf = NULL; 127 *bufsz = 0; 128 goto out; 129 } 130 *buf = tmp; 131 132 err = firmware_read_block(&ctx, RTE_PTR_ADD(*buf, *bufsz), blocksize); 133 if (err < 0) { 134 free(*buf); 135 *buf = NULL; 136 *bufsz = 0; 137 goto out; 138 } 139 *bufsz += err; 140 141 } while (err != 0); 142 143 ret = 0; 144 out: 145 firmware_close(&ctx); 146 return ret; 147 } 148 149 int 150 rte_firmware_read(const char *name, void **buf, size_t *bufsz) 151 { 152 char path[PATH_MAX]; 153 int ret; 154 155 ret = firmware_read(name, buf, bufsz); 156 if (ret < 0) { 157 unsigned int i; 158 159 for (i = 0; i < RTE_DIM(compression_suffixes); i++) { 160 snprintf(path, sizeof(path), "%s.%s", name, compression_suffixes[i]); 161 path[PATH_MAX - 1] = '\0'; 162 if (access(path, F_OK) != 0) 163 continue; 164 #ifndef RTE_HAS_LIBARCHIVE 165 EAL_LOG(WARNING, "libarchive not linked, %s cannot be decompressed", 166 path); 167 #else 168 ret = firmware_read(path, buf, bufsz); 169 #endif 170 break; 171 } 172 } 173 return ret; 174 } 175