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