Code cleanups after running with "sparse"
[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 static struct libjte_env *handle = NULL;
107 static char *outfile = NULL;
108 static int filec = 0;
109 static char *filev[LIBJTE_DEMO_MAX_FILES + 1];
110
111
112 static int libjte_demo_setup(int argc, char **argv, int flag)
113 {
114     int i, ret;
115     int have_outfile = 0, have_template = 0, have_jigdo = 0, have_md5 = 0;
116
117     ret = libjte_new(&handle, 0);
118     if (ret <= 0) {
119         fprintf(stderr, "Failed to create libjte_env object.\n");
120         return -1;
121     }
122
123     for (i = 1; i < argc; i++) {
124          if (argv[i][0] == '-')
125              if (i + 1 >= argc)
126                  goto usage;
127          if (strcmp(argv[i], "-outfile") == 0) {
128              i++;
129              ret = libjte_set_outfile(handle, argv[i]);
130              if (ret <= 0)
131                  return ret;
132              outfile = argv[i];
133              have_outfile = 1;
134          } else if (strcmp(argv[i], "-template") == 0) {
135              i++;
136              ret = libjte_set_template_path(handle, argv[i]);
137              if (ret <= 0)
138                  return ret;
139              have_template = 1;
140          } else if (strcmp(argv[i], "-jigdo") == 0) {
141              i++;
142              ret = libjte_set_jigdo_path(handle, argv[i]);
143              if (ret <= 0)
144                  return ret;
145              have_jigdo = 1;
146          } else if (strcmp(argv[i], "-md5") == 0) {
147              i++;
148              ret = libjte_set_md5_path(handle, argv[i]);
149              if (ret <= 0)
150                  return ret;
151              have_md5 = 1;
152          } else if (strcmp(argv[i], "-mapping") == 0) {
153              i++;
154              ret = libjte_add_mapping(handle, argv[i]);
155              if (ret <= 0)
156                  return ret;
157          } else if (argv[i][0] == '-') {
158              fprintf(stderr, "%s : Unknown option '%s'\n", argv[0], argv[i]);
159              goto usage;
160          } else {
161              if (filec + 1 > LIBJTE_DEMO_MAX_FILES) {
162                  fprintf(stderr, "%s : Too many file arguments. (> %d)\n",
163                          argv[0], LIBJTE_DEMO_MAX_FILES);
164                  return 0;
165              }
166              filev[filec++] = argv[i];
167          }
168     }
169     if (have_outfile && have_template && have_jigdo && have_md5 && filec > 0)
170          return 1;
171 usage:;
172     fprintf(stderr, "Usage: %s -outfile path -template path -jigdo path -md5 path [-mapping To=From] file [file ...]\n", argv[0]);
173     return 0;
174 }
175
176
177 static int libjte_demo_write(char *buf, int size, FILE *fp_out)
178 {
179     int ret;
180
181     ret = fwrite(buf, size, 1, fp_out);
182     if (ret != 1) {
183         fprintf(stderr, "Failed to fwrite(). errno= %d\n", errno);
184         return 0;
185     }
186     ret= libjte_show_data_chunk(handle, buf, 1, size);
187     if (ret <= 0) {
188         fprintf(stderr, "libjte_show_data_chunk() failed with ret = %d\n",
189                 ret);
190         return 0;
191     }
192     return 1;
193 }
194
195
196 static int libjte_demo_run(int flag)
197 {
198     int ret, i, major, minor, micro, buf_fill;
199     FILE *fp_out, *fp_in;
200     char buf[LIBJTE_DEMO_BUFSIZE];
201     struct stat stbuf;
202     off_t todo;
203
204     fp_out = fopen(outfile, "wb");
205     if (fp_out == NULL) {
206         fprintf(stderr, "Failed to open outfile for writing. errno= %d\n",
207                 errno);
208         return 0;
209     }
210
211     ret = libjte_write_header(handle);
212     if (ret <= 0)
213         return ret;
214
215     libjte__version(&major, &minor, &micro);
216     sprintf(buf, "test/demo of libjte-%d.%d.%d\n", major, minor, micro);
217     strcat(buf, 
218            "==============================================================\n");
219     ret = libjte_demo_write(buf, strlen(buf), fp_out);
220     if (ret <= 0)
221         return 0;
222
223     for (i = 0; i < filec; i++) {
224         ret = stat(filev[i], &stbuf);
225         if (ret == -1) {
226             fprintf(stderr, "Failed to stat() input file. errno= %d\n", errno);
227     continue;
228         }
229         if (!S_ISREG(stbuf.st_mode)) {
230             fprintf(stderr, "Not a data file: '%s'\n", filev[i]);
231     continue;
232         }
233         sprintf(buf, "name=%1.1024s\nsize=%.f\n",
234                      filev[i], (double) stbuf.st_size);
235         strcat(buf, 
236            "--------------------------------------------------------------\n");
237         ret = libjte_demo_write(buf, strlen(buf), fp_out);
238         if (ret <= 0)
239             return 0;
240
241         fp_in = fopen(filev[i], "rb");
242         if (fp_in == NULL) {
243             fprintf(stderr,
244                     "Failed to open data file for reading. errno= %d\n",
245                     errno);
246     continue;
247         }
248
249         ret = libjte_begin_data_file(handle, filev[i], 1, stbuf.st_size);
250         if (ret <= 0)
251             return 0;
252          
253         todo = stbuf.st_size;
254         while (todo > 0) {
255             if (todo > LIBJTE_DEMO_BUFSIZE)
256                 buf_fill = LIBJTE_DEMO_BUFSIZE;
257             else
258                 buf_fill = todo;
259             ret = fread(buf, buf_fill, 1, fp_in);
260             if (ret != 1) {
261                 fprintf(stderr, "Failed to fread() from '%s'. errno= %d\n",
262                                  filev[i], errno);
263                 fclose(fp_in);
264                 return 0;
265             }
266             ret = libjte_demo_write(buf, buf_fill, fp_out);
267             if (ret <= 0) {
268                 fclose(fp_in);
269                 return 0;
270             }
271
272             todo -= buf_fill;
273         }
274         fclose(fp_in);
275
276         ret = libjte_end_data_file(handle);
277         if (ret <= 0)
278             return 0;
279
280         strcpy(buf, 
281          "\n--------------------------------------------------------------\n");
282         ret = libjte_demo_write(buf, strlen(buf), fp_out);
283         if (ret <= 0)
284             return 0;
285     }
286
287     strcpy(buf, "test/demo end\n");
288     ret = libjte_demo_write(buf, strlen(buf), fp_out);
289     if (ret <= 0)
290         return 0;
291
292     ret = libjte_write_footer(handle);
293     if (ret <= 0)
294         return ret;
295
296     fclose(fp_out);
297     fp_out = NULL;
298     return 1;
299 }
300
301
302 int main(int argc, char **argv)
303 {
304     int ret, major, minor, micro;
305
306     /* A warning to programmers who start their own projekt from here. */
307     if (sizeof(off_t) != 8) {
308         fprintf(stderr,
309                "\n%s: Compile time misconfiguration. off_t is not 64 bit.\n\n",
310                argv[0]);
311         exit(1);
312     }
313
314     /* Applications should as first check the dynamically loaded library.
315     */
316     if (! libjte__is_compatible(LIBJTE_VERSION_MAJOR, LIBJTE_VERSION_MINOR,
317                                 LIBJTE_VERSION_MICRO, 0)) {
318         libjte__version(&major, &minor, &micro);
319         fprintf(stderr, "%s : Found libjte-%d.%d.%d , need libjte-%d.%d.%d \n",
320                          argv[0], major, minor, micro,
321                          LIBJTE_VERSION_MAJOR, LIBJTE_VERSION_MINOR,
322                          LIBJTE_VERSION_MICRO);
323         exit(2);
324     }
325
326     ret = libjte_demo_setup(argc, argv, 0);
327     if (ret <= 0) {
328         libjte_destroy(&handle);    
329         exit(3);
330     }
331
332     ret = libjte_demo_run(0);
333     if (ret <= 0) {
334         libjte_destroy(&handle);    
335         exit(4);
336     }
337
338     libjte_destroy(&handle);    
339     exit(0);
340 }
341