1/*	$OpenBSD: extract.c,v 1.4 2014/09/24 00:13:13 doug Exp $ */
2
3/*
4 * Copyright (c) 2006 Marcus Glocker <mglocker@openbsd.org>
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19#include <sys/types.h>
20#include <sys/stat.h>
21
22#include <err.h>
23#include <fcntl.h>
24#include <stdio.h>
25#include <stdlib.h>
26#include <unistd.h>
27
28struct header {
29	char	filename[64];
30	int	filesize;
31	int	fileoffset;
32};
33
34int
35main(int argc, char *argv[])
36{
37	int		  i, fdin, fdout, nfiles;
38	void		 *p;
39	struct header	**h;
40
41	if (argc < 2) {
42		printf("%s <firmware file>\n", argv[0]);
43		exit(1);
44	}
45
46	/* open firmware file */
47	if ((fdin = open(argv[1], O_RDONLY)) == -1)
48		err(1, "open of input file failed");
49
50	/* read first header */
51	if (read(fdin, &nfiles, sizeof(nfiles)) < 1)
52		err(1, "first header parse failed");
53	nfiles = ntohl(nfiles);
54
55	/* allocate space for header struct */
56	if ((h = reallocarray(NULL, nfiles, sizeof(*h))) == NULL)
57		err(1, "malloc");
58	for (i = 0; i < nfiles; i++) {
59		if ((h[i] = malloc(sizeof(struct header))) == NULL)
60			err(1, "malloc");
61	}
62
63	/* read header */
64	for (i = 0; i < nfiles; i++) {
65		if (read(fdin, h[i]->filename, sizeof(h[i]->filename)) < 1)
66			err(1, "filename header read failed\n");
67		if (read(fdin, &h[i]->filesize, sizeof(h[i]->filesize)) < 1)
68			err(1, "filesize header read failed\n");
69		h[i]->filesize = htonl(h[i]->filesize);
70		if (read(fdin, &h[i]->fileoffset, sizeof(h[i]->fileoffset)) < 1)
71			err(1, "fileoffset header read failed\n");
72		h[i]->fileoffset = htonl(h[i]->fileoffset);
73	}
74
75	/* write each file */
76	for (i = 0; i < nfiles; i++) {
77		if ((fdout = open(h[i]->filename, O_CREAT|O_TRUNC|O_RDWR, 0644))
78		    == -1)
79			err(1, "open of output file failed");
80		if ((p = malloc(h[i]->filesize)) == NULL)
81			err(1, "malloc");
82		if (lseek(fdin, h[i]->fileoffset, SEEK_SET) == -1)
83			err(1, "lseek");
84		if (read(fdin, p, h[i]->filesize) < 1)
85			err(1, "read from input file failed");
86		if (write(fdout, p, h[i]->filesize) < 1)
87			err(1, "write to output file failed");
88		free(p);
89		close(fdout);
90		printf("extracting %s (filesize %d, fileoffset %d)\n",
91		    h[i]->filename, h[i]->filesize, h[i]->fileoffset);
92	}
93
94	/* free header space */
95	for (i = 0; i < nfiles; i++)
96		free(h[i]);
97	free(h);
98
99	/* game over */
100	close (fdin);
101
102	return (0);
103}
104