Branch data Line data Source code
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 : 0 : ctx->fd = open(name, O_RDONLY);
86 [ # # ]: 0 : if (ctx->fd < 0)
87 : : return -1;
88 : : return 0;
89 : : }
90 : :
91 : : static ssize_t
92 : 0 : firmware_read_block(struct firmware_read_ctx *ctx, void *buf, size_t count)
93 : : {
94 [ # # ]: 0 : return read(ctx->fd, buf, count);
95 : : }
96 : :
97 : : static void
98 : : firmware_close(struct firmware_read_ctx *ctx)
99 : : {
100 : 0 : close(ctx->fd);
101 : : ctx->fd = -1;
102 : : }
103 : :
104 : : #endif /* !RTE_HAS_LIBARCHIVE */
105 : :
106 : : static int
107 : 0 : 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 : 0 : *buf = NULL;
115 : 0 : *bufsz = 0;
116 : :
117 : : if (firmware_open(&ctx, name, blocksize) < 0)
118 : : return -1;
119 : :
120 : : do {
121 : : void *tmp;
122 : :
123 : 0 : tmp = realloc(*buf, *bufsz + blocksize);
124 [ # # ]: 0 : if (tmp == NULL) {
125 : 0 : free(*buf);
126 : 0 : *buf = NULL;
127 : 0 : *bufsz = 0;
128 : 0 : goto out;
129 : : }
130 : 0 : *buf = tmp;
131 : :
132 : 0 : err = firmware_read_block(&ctx, RTE_PTR_ADD(*buf, *bufsz), blocksize);
133 [ # # ]: 0 : if (err < 0) {
134 : 0 : free(*buf);
135 : 0 : *buf = NULL;
136 : 0 : *bufsz = 0;
137 : 0 : goto out;
138 : : }
139 : 0 : *bufsz += err;
140 : :
141 [ # # ]: 0 : } while (err != 0);
142 : :
143 : : ret = 0;
144 : 0 : out:
145 : : firmware_close(&ctx);
146 : 0 : return ret;
147 : : }
148 : :
149 : : int
150 : 0 : rte_firmware_read(const char *name, void **buf, size_t *bufsz)
151 : : {
152 : : char path[PATH_MAX];
153 : : int ret;
154 : :
155 : 0 : ret = firmware_read(name, buf, bufsz);
156 [ # # ]: 0 : if (ret < 0) {
157 : : unsigned int i;
158 : :
159 [ # # ]: 0 : for (i = 0; i < RTE_DIM(compression_suffixes); i++) {
160 : 0 : snprintf(path, sizeof(path), "%s.%s", name, compression_suffixes[i]);
161 : 0 : path[PATH_MAX - 1] = '\0';
162 [ # # ]: 0 : if (access(path, F_OK) != 0)
163 : : continue;
164 : : #ifndef RTE_HAS_LIBARCHIVE
165 : 0 : EAL_LOG(WARNING, "libarchive not linked, %s cannot be decompressed",
166 : : path);
167 : : #else
168 : : ret = firmware_read(path, buf, bufsz);
169 : : #endif
170 : 0 : break;
171 : : }
172 : : }
173 : 0 : return ret;
174 : : }
|