2 * libkmod - interface to kernel module operations
4 * Copyright (C) 2011-2013 ProFUSION embedded systems
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
27 #include <sys/types.h>
36 #include <shared/util.h>
39 #include "libkmod-internal.h"
43 int (*load)(struct kmod_file *file);
44 void (*unload)(struct kmod_file *file);
58 const struct file_ops *ops;
59 const struct kmod_ctx *ctx;
64 static void xz_uncompress_belch(struct kmod_file *file, lzma_ret ret)
68 ERR(file->ctx, "xz: %s\n", strerror(ENOMEM));
70 case LZMA_FORMAT_ERROR:
71 ERR(file->ctx, "xz: File format not recognized\n");
73 case LZMA_OPTIONS_ERROR:
74 ERR(file->ctx, "xz: Unsupported compression options\n");
77 ERR(file->ctx, "xz: File is corrupt\n");
80 ERR(file->ctx, "xz: Unexpected end of input\n");
83 ERR(file->ctx, "xz: Internal error (bug)\n");
88 static int xz_uncompress(lzma_stream *strm, struct kmod_file *file)
90 uint8_t in_buf[BUFSIZ], out_buf[BUFSIZ];
91 lzma_action action = LZMA_RUN;
97 strm->next_out = out_buf;
98 strm->avail_out = sizeof(out_buf);
101 if (strm->avail_in == 0) {
102 ssize_t rdret = read(file->fd, in_buf, sizeof(in_buf));
107 strm->next_in = in_buf;
108 strm->avail_in = rdret;
110 action = LZMA_FINISH;
112 ret = lzma_code(strm, action);
113 if (strm->avail_out == 0 || ret != LZMA_OK) {
114 size_t write_size = BUFSIZ - strm->avail_out;
115 char *tmp = realloc(p, total + write_size);
120 memcpy(tmp + total, out_buf, write_size);
123 strm->next_out = out_buf;
124 strm->avail_out = BUFSIZ;
126 if (ret == LZMA_STREAM_END)
128 if (ret != LZMA_OK) {
129 xz_uncompress_belch(file, ret);
134 file->xz_used = true;
143 static int load_xz(struct kmod_file *file)
145 lzma_stream strm = LZMA_STREAM_INIT;
149 lzret = lzma_stream_decoder(&strm, UINT64_MAX, LZMA_CONCATENATED);
150 if (lzret == LZMA_MEM_ERROR) {
151 ERR(file->ctx, "xz: %s\n", strerror(ENOMEM));
153 } else if (lzret != LZMA_OK) {
154 ERR(file->ctx, "xz: Internal error (bug)\n");
157 ret = xz_uncompress(&strm, file);
162 static void unload_xz(struct kmod_file *file)
169 static const char magic_xz[] = {0xfd, '7', 'z', 'X', 'Z', 0};
173 #define READ_STEP (4 * 1024 * 1024)
174 static int load_zlib(struct kmod_file *file)
177 off_t did = 0, total = 0;
178 _cleanup_free_ unsigned char *p = NULL;
181 file->gzf = gzdopen(file->fd, "rb");
182 if (file->gzf == NULL)
184 file->fd = -1; /* now owned by gzf due gzdopen() */
190 void *tmp = realloc(p, total + READ_STEP);
199 r = gzread(file->gzf, p + did, total - did);
204 const char *gz_errmsg = gzerror(file->gzf, &gzerr);
206 ERR(file->ctx, "gzip: %s\n", gz_errmsg);
208 /* gzip might not set errno here */
209 err = gzerr == Z_ERRNO ? -errno : -EINVAL;
225 static void unload_zlib(struct kmod_file *file)
227 if (file->gzf == NULL)
230 gzclose(file->gzf); /* closes file->fd */
233 static const char magic_zlib[] = {0x1f, 0x8b};
236 static const struct comp_type {
238 const char *magic_bytes;
239 const struct file_ops ops;
242 {sizeof(magic_xz), magic_xz, {load_xz, unload_xz}},
245 {sizeof(magic_zlib), magic_zlib, {load_zlib, unload_zlib}},
247 {0, NULL, {NULL, NULL}}
250 static int load_reg(struct kmod_file *file)
254 if (fstat(file->fd, &st) < 0)
257 file->size = st.st_size;
258 file->memory = mmap(NULL, file->size, PROT_READ, MAP_PRIVATE,
260 if (file->memory == MAP_FAILED)
266 static void unload_reg(struct kmod_file *file)
268 munmap(file->memory, file->size);
271 static const struct file_ops reg_ops = {
275 struct kmod_elf *kmod_file_get_elf(struct kmod_file *file)
280 file->elf = kmod_elf_new(file->memory, file->size);
284 struct kmod_file *kmod_file_open(const struct kmod_ctx *ctx,
285 const char *filename)
287 struct kmod_file *file = calloc(1, sizeof(struct kmod_file));
288 const struct comp_type *itr;
289 size_t magic_size_max = 0;
295 file->fd = open(filename, O_RDONLY|O_CLOEXEC);
301 for (itr = comp_types; itr->ops.load != NULL; itr++) {
302 if (magic_size_max < itr->magic_size)
303 magic_size_max = itr->magic_size;
306 file->direct = false;
307 if (magic_size_max > 0) {
308 char *buf = alloca(magic_size_max + 1);
315 sz = read_str_safe(file->fd, buf, magic_size_max + 1);
316 lseek(file->fd, 0, SEEK_SET);
317 if (sz != (ssize_t)magic_size_max) {
325 for (itr = comp_types; itr->ops.load != NULL; itr++) {
326 if (memcmp(buf, itr->magic_bytes, itr->magic_size) == 0)
329 if (itr->ops.load != NULL)
330 file->ops = &itr->ops;
333 if (file->ops == NULL)
334 file->ops = ®_ops;
336 err = file->ops->load(file);
350 void *kmod_file_get_contents(const struct kmod_file *file)
355 off_t kmod_file_get_size(const struct kmod_file *file)
360 bool kmod_file_get_direct(const struct kmod_file *file)
365 int kmod_file_get_fd(const struct kmod_file *file)
370 void kmod_file_unref(struct kmod_file *file)
373 kmod_elf_unref(file->elf);
375 file->ops->unload(file);