oseama: small util for reading Seama image format info
[openwrt/staging/lynxis/omap.git] / package / utils / oseama / src / oseama.c
1 /*
2 * oseama
3 *
4 * Copyright (C) 2016 Rafał Miłecki <zajec5@gmail.com>
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the Free
8 * Software Foundation; either version 2 of the License, or (at your option)
9 * any later version.
10 */
11
12 #include <byteswap.h>
13 #include <endian.h>
14 #include <errno.h>
15 #include <stdint.h>
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <string.h>
19 #include <unistd.h>
20
21 #if !defined(__BYTE_ORDER)
22 #error "Unknown byte order"
23 #endif
24
25 #if __BYTE_ORDER == __BIG_ENDIAN
26 #define cpu_to_be32(x) (x)
27 #define be32_to_cpu(x) (x)
28 #define cpu_to_be16(x) (x)
29 #define be16_to_cpu(x) (x)
30 #elif __BYTE_ORDER == __LITTLE_ENDIAN
31 #define cpu_to_be32(x) bswap_32(x)
32 #define be32_to_cpu(x) bswap_32(x)
33 #define cpu_to_be16(x) bswap_16(x)
34 #define be16_to_cpu(x) bswap_16(x)
35 #else
36 #error "Unsupported endianness"
37 #endif
38
39 #define SEAMA_MAGIC 0x5ea3a417
40
41 struct seama_seal_header {
42 uint32_t magic;
43 uint16_t reserved;
44 uint16_t metasize;
45 uint32_t imagesize;
46 } __attribute__ ((packed));
47
48 struct seama_entity_header {
49 uint32_t magic;
50 uint16_t reserved;
51 uint16_t metasize;
52 uint32_t imagesize;
53 uint8_t md5[16];
54 } __attribute__ ((packed));
55
56 char *seama_path;
57 int entity_idx = -1;
58
59 static inline size_t oseama_min(size_t x, size_t y) {
60 return x < y ? x : y;
61 }
62
63 /**************************************************
64 * Info
65 **************************************************/
66
67 static void oseama_info_parse_options(int argc, char **argv) {
68 int c;
69
70 while ((c = getopt(argc, argv, "e:")) != -1) {
71 switch (c) {
72 case 'e':
73 entity_idx = atoi(optarg);
74 break;
75 }
76 }
77 }
78
79 static int oseama_info_entities(FILE *seama) {
80 struct seama_entity_header hdr;
81 size_t bytes, metasize, imagesize;
82 uint8_t buf[1024];
83 char *end, *tmp;
84 int i = 0;
85 int err = 0;
86
87 while ((bytes = fread(&hdr, 1, sizeof(hdr), seama)) == sizeof(hdr)) {
88 if (be32_to_cpu(hdr.magic) != SEAMA_MAGIC) {
89 fprintf(stderr, "Invalid Seama magic: 0x%08x\n", be32_to_cpu(hdr.magic));
90 err = -EINVAL;
91 goto err_out;
92 }
93 metasize = be16_to_cpu(hdr.metasize);
94 imagesize = be32_to_cpu(hdr.imagesize);
95
96 if (entity_idx >= 0 && i != entity_idx) {
97 fseek(seama, metasize + imagesize, SEEK_CUR);
98 i++;
99 continue;
100 }
101
102 if (metasize >= sizeof(buf)) {
103 fprintf(stderr, "Too small buffer (%zu B) to read all meta info (%zd B)\n", sizeof(buf), metasize);
104 err = -EINVAL;
105 goto err_out;
106 }
107
108 if (entity_idx < 0)
109 printf("\n");
110 printf("Entity offset:\t%ld\n", ftell(seama) - sizeof(hdr));
111 printf("Entity size:\t%zd\n", sizeof(hdr) + metasize + imagesize);
112 printf("Meta size:\t%zd\n", metasize);
113 printf("Image size:\t%zd\n", imagesize);
114
115 bytes = fread(buf, 1, metasize, seama);
116 if (bytes != metasize) {
117 fprintf(stderr, "Couldn't read %zd B of meta\n", metasize);
118 err = -EIO;
119 goto err_out;
120 }
121
122 end = (char *)&buf[metasize - 1];
123 *end = '\0';
124 for (tmp = (char *)buf; tmp < end && strlen(tmp); tmp += strlen(tmp) + 1) {
125 printf("Meta entry:\t%s\n", tmp);
126 }
127
128 fseek(seama, imagesize, SEEK_CUR);
129 i++;
130 }
131
132 err_out:
133 return err;
134 }
135
136 static int oseama_info(int argc, char **argv) {
137 FILE *seama;
138 struct seama_seal_header hdr;
139 size_t bytes;
140 uint16_t metasize;
141 uint32_t imagesize;
142 uint8_t buf[1024];
143 int err = 0;
144
145 if (argc < 3) {
146 fprintf(stderr, "No Seama file passed\n");
147 err = -EINVAL;
148 goto out;
149 }
150 seama_path = argv[2];
151
152 optind = 3;
153 oseama_info_parse_options(argc, argv);
154
155 seama = fopen(seama_path, "r");
156 if (!seama) {
157 fprintf(stderr, "Couldn't open %s\n", seama_path);
158 err = -EACCES;
159 goto out;
160 }
161
162 bytes = fread(&hdr, 1, sizeof(hdr), seama);
163 if (bytes != sizeof(hdr)) {
164 fprintf(stderr, "Couldn't read %s header\n", seama_path);
165 err = -EIO;
166 goto err_close;
167 }
168 metasize = be16_to_cpu(hdr.metasize);
169 imagesize = be32_to_cpu(hdr.imagesize);
170
171 if (be32_to_cpu(hdr.magic) != SEAMA_MAGIC) {
172 fprintf(stderr, "Invalid Seama magic: 0x%08x\n", be32_to_cpu(hdr.magic));
173 err = -EINVAL;
174 goto err_close;
175 }
176
177 if (metasize >= sizeof(buf)) {
178 fprintf(stderr, "Too small buffer (%zu B) to read all meta info (%d B)\n", sizeof(buf), metasize);
179 err = -EINVAL;
180 goto err_close;
181 }
182
183 if (imagesize) {
184 fprintf(stderr, "Invalid Seama image size: 0x%08x (should be 0)\n", imagesize);
185 err = -EINVAL;
186 goto err_close;
187 }
188
189 bytes = fread(buf, 1, metasize, seama);
190 if (bytes != metasize) {
191 fprintf(stderr, "Couldn't read %d B of meta\n", metasize);
192 err = -EIO;
193 goto err_close;
194 }
195
196 if (entity_idx < 0) {
197 char *end, *tmp;
198
199 printf("Meta size:\t%d\n", metasize);
200 printf("Image size:\t%d\n", imagesize);
201
202 end = (char *)&buf[metasize - 1];
203 *end = '\0';
204 for (tmp = (char *)buf; tmp < end && strlen(tmp); tmp += strlen(tmp) + 1) {
205 printf("Meta entry:\t%s\n", tmp);
206 }
207 }
208
209 oseama_info_entities(seama);
210
211 err_close:
212 fclose(seama);
213 out:
214 return err;
215 }
216
217 /**************************************************
218 * Start
219 **************************************************/
220
221 static void usage() {
222 printf("Usage:\n");
223 printf("\n");
224 printf("Info about Seama seal (container):\n");
225 printf("\toseama info <file> [options]\n");
226 printf("\t-e\t\t\t\tprint info about specified entity only\n");
227 }
228
229 int main(int argc, char **argv) {
230 if (argc > 1) {
231 if (!strcmp(argv[1], "info"))
232 return oseama_info(argc, argv);
233 }
234
235 usage();
236 return 0;
237 }