980bbca1421d20bc73bdda5af46832804b5da40a
[jigit.git] / libjte / test / demo.c
1 /*
2  * test/demo.c
3  *
4  * Copyright (c) 2011 Thomas Schmitt <scdbackup@gmx.net>
5  *
6  * Licensed under "revised" FreeBSD license.
7  * I.e. use as you like but do not claim to be the author.
8  *
9  */
10
11 /*
12   This program demonstrates usage of libjte.
13
14   It concatenates one or more data files to a single output file, as example
15   of a payload image.
16   While doing this it lets libjte create a template file and a jigdo file
17   which together describe the content of the payload image. 
18
19   The main program checks for compatibility and calls two functions:
20     libjte_demo_setup()  creates a libjte_env object and sets its parameters
21                          from program arguments. It also collects the list of
22                          input files.
23     libjte_demo_run()    produces a simple payload image format, the template
24                          file, and the jigdo file. For that it reads the md5
25                          file.
26   Finally the main program disposes the libjte_env object.
27
28   Function libjte_demo_write() takes care of writing a data chunk to the
29   payload image as well as showing it to libjte.
30  
31
32   Applications must use 64 bit off_t. E.g. by defining
33     #define _LARGEFILE_SOURCE
34     #define _FILE_OFFSET_BITS 64
35   or take special precautions to interface with the library by 64 bit integers
36   where libjte/libjte.h prescribes off_t.
37   This program gets fed with appropriate settings externally by libjte's
38   autotools generated build system.
39
40
41   Usage example:
42
43     # Produce an .md5 file
44
45     find . -name '*.c' -exec bin/jigdo-gen-md5-list '{}' ';' >test/file.md5
46
47     # Produce payload image "test/file.outfile", the template file and
48     # the jigdo file. Input is test/file.md5 and the data files *.c
49    
50     test/demo -outfile test/file.outfile \
51               -template test/file.template \
52               -jigdo test/file.jigdo \
53               -md5 test/file.md5 \
54               -mapping Debian=/home/ \
55               *.c
56
57     # Have a look at the human readable results
58
59     view test/file.jigdo
60     view test/file.outfile
61
62     # Produce payload image from template and jigdo file by tool from
63     # package "jigit".
64
65     jigit-mkimage -t test/file.template \
66                   -j test/file.jigdo \
67                   -m Debian=/home/ \
68                   -o test/file.rebuilt
69
70     diff -q test/file.outfile test/file.rebuilt
71
72 */
73
74
75 #include <stdio.h>
76 #include <ctype.h>
77 #include <sys/types.h>
78 #include <unistd.h>
79 #include <string.h>
80 #include <stdlib.h>
81
82 #ifdef HAVE_STDINT_H
83 #include <stdint.h>
84 #else
85 #ifdef HAVE_INTTYPES_H
86 #include <inttypes.h>
87 #endif
88 #endif
89
90 #include <errno.h>
91 #include <sys/stat.h>
92
93
94 /* In real applications use #include <libjte/libjte.h>
95 */
96 #include "../libjte.h"
97
98
99 /* For simplicity, the program state is represented by global variables
100    and the content of the program arguments.
101 */
102
103 #define LIBJTE_DEMO_MAX_FILES 1000
104 #define LIBJTE_DEMO_BUFSIZE   4096
105
106 struct libjte_env *handle = NULL;
107 char *outfile = NULL;
108 FILE *fp_out = NULL;
109 int filec = 0;
110 char *filev[LIBJTE_DEMO_MAX_FILES + 1];
111
112
113 static int libjte_demo_setup(int argc, char **argv, int flag)
114 {
115     int i, ret;
116     int have_outfile = 0, have_template = 0, have_jigdo = 0, have_md5 = 0;
117
118     ret = libjte_new(&handle, 0);
119     if (ret <= 0) {
120         fprintf(stderr, "Failed to create libjte_env object.\n");
121         return -1;
122     }
123
124     for (i = 1; i < argc; i++) {
125          if (argv[i][0] == '-')
126              if (i + 1 >= argc)
127                  goto usage;
128          if (strcmp(argv[i], "-outfile") == 0) {
129              i++;
130              ret = libjte_set_outfile(handle, argv[i]);
131              if (ret <= 0)
132                  return ret;
133              outfile = argv[i];
134              have_outfile = 1;
135          } else if (strcmp(argv[i], "-template") == 0) {
136              i++;
137              ret = libjte_set_template_path(handle, argv[i]);
138              if (ret <= 0)
139                  return ret;
140              have_template = 1;
141          } else if (strcmp(argv[i], "-jigdo") == 0) {
142              i++;
143              ret = libjte_set_jigdo_path(handle, argv[i]);
144              if (ret <= 0)
145                  return ret;
146              have_jigdo = 1;
147          } else if (strcmp(argv[i], "-md5") == 0) {
148              i++;
149              ret = libjte_set_md5_path(handle, argv[i]);
150              if (ret <= 0)
151                  return ret;
152              have_md5 = 1;
153          } else if (strcmp(argv[i], "-mapping") == 0) {
154              i++;
155              ret = libjte_add_mapping(handle, argv[i]);
156              if (ret <= 0)
157                  return ret;
158          } else if (argv[i][0] == '-') {
159              fprintf(stderr, "%s : Unknown option '%s'\n", argv[0], argv[i]);
160              goto usage;
161          } else {
162              if (filec + 1 > LIBJTE_DEMO_MAX_FILES) {
163                  fprintf(stderr, "%s : Too many file arguments. (> %d)\n",
164                          argv[0], LIBJTE_DEMO_MAX_FILES);
165                  return 0;
166              }
167              filev[filec++] = argv[i];
168          }
169     }
170     if (have_outfile && have_template && have_jigdo && have_md5 && filec > 0)
171          return 1;
172 usage:;
173     fprintf(stderr, "Usage: %s -outfile path -template path -jigdo path -md5 path [-mapping To=From] file [file ...]\n", argv[0]);
174     return 0;
175 }
176
177
178 int libjte_demo_write(char *buf, int size, FILE *fp_out)
179 {
180     int ret;
181
182     ret = fwrite(buf, size, 1, fp_out);
183     if (ret != 1) {
184         fprintf(stderr, "Failed to fwrite(). errno= %d\n", errno);
185         return 0;
186     }
187     ret= libjte_show_data_chunk(handle, buf, 1, size);
188     if (ret <= 0) {
189         fprintf(stderr, "libjte_show_data_chunk() failed with ret = %d\n",
190                 ret);
191         return 0;
192     }
193     return 1;
194 }
195
196
197 int libjte_demo_run(int flag)
198 {
199     int ret, i, major, minor, micro, buf_fill;
200     FILE *fp_out, *fp_in;
201     char buf[LIBJTE_DEMO_BUFSIZE];
202     struct stat stbuf;
203     off_t todo;
204
205     fp_out = fopen(outfile, "wb");
206     if (fp_out == NULL) {
207         fprintf(stderr, "Failed to open outfile for writing. errno= %d\n",
208                 errno);
209         return 0;
210     }
211
212     ret = libjte_write_header(handle);
213     if (ret <= 0)
214         return ret;
215
216     libjte__version(&major, &minor, &micro);
217     sprintf(buf, "test/demo of libjte-%d.%d.%d\n", major, minor, micro);
218     strcat(buf, 
219            "==============================================================\n");
220     ret = libjte_demo_write(buf, strlen(buf), fp_out);
221     if (ret <= 0)
222         return 0;
223
224     for (i = 0; i < filec; i++) {
225         ret = stat(filev[i], &stbuf);
226         if (ret == -1) {
227             fprintf(stderr, "Failed to stat() input file. errno= %d\n", errno);
228     continue;
229         }
230         if (!S_ISREG(stbuf.st_mode)) {
231             fprintf(stderr, "Not a data file: '%s'\n", filev[i]);
232     continue;
233         }
234         sprintf(buf, "name=%1.1024s\nsize=%.f\n",
235                      filev[i], (double) stbuf.st_size);
236         strcat(buf, 
237            "--------------------------------------------------------------\n");
238         ret = libjte_demo_write(buf, strlen(buf), fp_out);
239         if (ret <= 0)
240             return 0;
241
242         fp_in = fopen(filev[i], "rb");
243         if (fp_in == NULL) {
244             fprintf(stderr,
245                     "Failed to open data file for reading. errno= %d\n",
246                     errno);
247     continue;
248         }
249
250         ret = libjte_begin_data_file(handle, filev[i], 1, stbuf.st_size);
251         if (ret <= 0)
252             return 0;
253          
254         todo = stbuf.st_size;
255         while (todo > 0) {
256             if (todo > LIBJTE_DEMO_BUFSIZE)
257                 buf_fill = LIBJTE_DEMO_BUFSIZE;
258             else
259                 buf_fill = todo;
260             ret = fread(buf, buf_fill, 1, fp_in);
261             if (ret != 1) {
262                 fprintf(stderr, "Failed to fread() from '%s'. errno= %d\n",
263                                  filev[i], errno);
264                 fclose(fp_in);
265                 return 0;
266             }
267             ret = libjte_demo_write(buf, buf_fill, fp_out);
268             if (ret <= 0) {
269                 fclose(fp_in);
270                 return 0;
271             }
272
273             todo -= buf_fill;
274         }
275         fclose(fp_in);
276
277         ret = libjte_end_data_file(handle);
278         if (ret <= 0)
279             return 0;
280
281         strcpy(buf, 
282          "\n--------------------------------------------------------------\n");
283         ret = libjte_demo_write(buf, strlen(buf), fp_out);
284         if (ret <= 0)
285             return 0;
286     }
287
288     strcpy(buf, "test/demo end\n");
289     ret = libjte_demo_write(buf, strlen(buf), fp_out);
290     if (ret <= 0)
291         return 0;
292
293     ret = libjte_write_footer(handle);
294     if (ret <= 0)
295         return ret;
296
297     fclose(fp_out);
298     fp_out = NULL;
299     return 1;
300 }
301
302
303 int main(int argc, char **argv)
304 {
305     int ret, major, minor, micro;
306
307     /* A warning to programmers who start their own projekt from here. */
308     if (sizeof(off_t) != 8) {
309         fprintf(stderr,
310                "\n%s: Compile time misconfiguration. off_t is not 64 bit.\n\n",
311                argv[0]);
312         exit(1);
313     }
314
315     /* Applications should as first check the dynamically loaded library.
316     */
317     if (! libjte__is_compatible(LIBJTE_VERSION_MAJOR, LIBJTE_VERSION_MINOR,
318                                 LIBJTE_VERSION_MICRO, 0)) {
319         libjte__version(&major, &minor, &micro);
320         fprintf(stderr, "%s : Found libjte-%d.%d.%d , need libjte-%d.%d.%d \n",
321                          argv[0], major, minor, micro,
322                          LIBJTE_VERSION_MAJOR, LIBJTE_VERSION_MINOR,
323                          LIBJTE_VERSION_MICRO);
324         exit(2);
325     }
326
327     ret = libjte_demo_setup(argc, argv, 0);
328     if (ret <= 0) {
329         libjte_destroy(&handle);    
330         exit(3);
331     }
332
333     ret = libjte_demo_run(0);
334     if (ret <= 0) {
335         libjte_destroy(&handle);    
336         exit(4);
337     }
338
339     libjte_destroy(&handle);    
340     exit(0);
341 }
342