coverity: Fix coverity issue
[platform/core/system/tizen-platform-config.git] / src / toolbox.c
1 /*
2  * Copyright (C) 2013-2014 Intel Corporation.
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
17  *
18  * Authors:
19  *       José Bollo <jose.bollo@open.eurogiciel.org>
20  *       Stéphane Desneux <stephane.desneux@open.eurogiciel.org>
21  *       Jean-Benoit Martin <jean-benoit.martin@open.eurogiciel.org>
22  *
23  */
24 #define _GNU_SOURCE
25
26 #ifdef HAVE_CONFIG_H
27 # include "config.h"
28 #endif
29
30 #include <stdlib.h>
31 #include <stdio.h>
32 #include <string.h>
33 #include <unistd.h>
34 #include <sys/wait.h>
35 #include <stdarg.h>
36
37 #include "parser.h"
38 #include "heap.h"
39 #include "buffer.h"
40 #include "foreign.h"
41 #include "sha256sum.h"
42
43 /*======================================================================*/
44
45 #ifndef CONFIGPATH
46 # define CONFIGPATH "/etc/tizen-platform.conf"
47 #endif
48
49 #ifndef TOOLNAME
50 # define TOOLNAME "tzplatform-tool"
51 #endif
52
53 /*== TYPES =============================================================*/
54
55 /* for recording read keys */
56 struct key {
57         struct key *next;               /* link to next */
58         const char *name;               /* name of the key */
59         const char *value;              /* value of the key */
60         size_t          begin;          /* positions of begin (used by pretty) */
61         size_t          end;            /* positions of end (used by pretty) */
62         int                     dependant;      /* is dependant (used by rpm) */
63 };
64
65 /* for recording used variables */
66 struct var {
67         struct var *next;               /* link to next */
68         const char *name;               /* name of the variable */
69         const char *normal;             /* normalized value: "${name}" (for pretty) */
70         int                     dependant;      /* is dependant (used by rpm) */
71 };
72
73 /*== STATIC DATA =======================================================*/
74
75 static char help[] = "\
76 \n\
77 usage: "TOOLNAME" [command] [--] [file]\n\
78 \n\
79 You can specify the 'file' to process.\n\
80 The default file is "CONFIGPATH"\n\
81 Specifying - mean the standard input.\n\
82 \n\
83 Commands:\n\
84 \n\
85 help       Display this help\n\
86 check      Check validity of 'file' (this is the default command)\n\
87 pretty     Pretty print of the 'file' (the normalized format)\n\
88 h                  Produce the C header with the enumeration of the variables\n\
89 c                  Produce the C code to hash the variable names\n\
90 rpm                Produce the macro file to use with RPM\n\
91 signup     Produce the signup data for the proxy linked statically\n\
92 \n\
93 ";
94
95 static char genh_head[] = "\
96 /* I'm generated. Dont edit me! */\n\
97 #ifndef TZPLATFORM_VARIABLES_H\n\
98 #define TZPLATFORM_VARIABLES_H\n\
99 #ifdef __cplusplus\n\
100 extern \"C\" {\n\
101 #endif\n\
102 enum tzplatform_variable {\n\
103 \t_TZPLATFORM_VARIABLES_INVALID_ = -1,\n\
104 ";
105
106 static char genh_tail[] = "\
107 \t_TZPLATFORM_VARIABLES_COUNT_\n\
108 };\n\
109 #ifdef __cplusplus\n\
110 }\n\
111 #endif\n\
112 #endif\n\
113 ";
114
115 static char gperf_head[] = "\
116 struct varassoc {\n\
117         int offset;\n\
118         int id;\n\
119 };\n\
120 %%\n\
121 ";
122
123 static char *gperf_command[] = {
124         "/bin/sh",
125         "-c",
126         "gperf -r -m 100 --null-strings -C -P -L ANSI-C -c"
127                   " -t -N hashvar -Q varpool -K offset -G -W namassoc"
128                   " -F \", _TZPLATFORM_VARIABLES_INVALID_\"",
129         NULL
130 };
131
132 static char rpm_head[] = "\
133 # I'm generated. Dont edit me! \n\
134 \n\
135 ";
136
137 static char signup_head[] = "\
138 /* I'm generated. Dont edit me! */\n\
139 static char tizen_platform_config_signup[33] = {\n\
140         '\\x00',\n\
141 ";
142
143 static char signup_tail[] = "\
144         };\n\
145 ";
146
147 /*== GLOBALS VARIABLES =================================================*/
148
149 /* name of the meta file to process */
150 static const char * metafilepath = CONFIGPATH;
151
152 /* list of the read keys */
153 static struct key *keys = NULL;
154
155 /* list of the used variables */
156 static struct var *vars = NULL;
157
158 /* count of errors */
159 static int errcount = 0;
160
161 /* dependency state */
162 static int dependant = 0;
163
164 /* action to perform */
165 static enum { CHECK, PRETTY, GENC, GENH, RPM, SIGNUP } action = CHECK;
166
167 /* output of error */
168 static int notstderr = 0;
169
170 /*======================================================================*/
171
172 /* write the error message */
173 static void vwriterror(const char *format, va_list ap)
174 {
175         vfprintf(notstderr ? stdout : stderr, format, ap);
176 }
177
178 /* write the error message */
179 static void writerror(const char *format, ...)
180 {
181         va_list ap;
182         va_start(ap, format);
183         vwriterror(format, ap);
184         va_end(ap);
185 }
186
187 /* write error and exit */
188 static void fatal(const char *format, ...)
189 {
190         va_list ap;
191
192         writerror("Error, ");
193         va_start(ap, format);
194         vwriterror(format, ap);
195         va_end(ap);
196         writerror(".\n");
197
198         /* exit */
199         exit(1);
200 }
201
202 /* error in the command line */
203 static void argerror(const char *format, ...)
204 {
205         va_list ap;
206
207         writerror("Error, ");
208         va_start(ap, format);
209         vwriterror(format, ap);
210         va_end(ap);
211         writerror(".\nType '"TOOLNAME" help' to get usage.\n");
212
213         /* exit */
214         exit(1);
215 }
216
217 /*== MANAGEMENT OF THE LIST OF READ KEYS ===============================*/
218
219 /* search a key of 'name' and length 'lname' and return it or NULL */
220 static struct key *key_search(const char *name, size_t lname)
221 {
222         struct key *result = keys;
223
224         while (result != NULL && (strncmp(result->name, name, lname) != 0
225                                         || result->name[lname] != 0))
226                 result = result->next;
227
228         return result;
229 }
230
231 /* append a new key to the list and return it or NULL if allocations failed */
232 static struct key *key_add(const char *name, size_t lname,
233                                                         const char *value, size_t lvalue,
234                                                         size_t begin_pos, size_t end_pos)
235 {
236         struct key *result, *prev;
237         char *sname, *svalue;
238
239         /* allocations */
240         result = malloc(sizeof *result);
241         sname = strndup(name, lname);
242         svalue = strndup(value, lvalue);
243         if (result == NULL || sname == NULL || svalue == NULL) {
244                 /* failure of allocations */
245                 free(result);
246                 free(sname);
247                 free(svalue);
248                 result = NULL;
249         } else {
250                 /* success: init the structure */
251                 result->next = NULL;
252                 result->name = sname;
253                 result->value = svalue;
254                 result->begin = begin_pos;
255                 result->end = end_pos;
256                 result->dependant = dependant;
257
258                 /* link at end of the list */
259                 prev = keys;
260                 if (prev == NULL)
261                         keys = result;
262                 else {
263                         while (prev != NULL && prev->next != NULL)
264                                 prev = prev->next;
265                         prev->next = result;
266                 }
267         }
268
269         return result;
270 }
271
272 /*======================================================================*/
273
274 /* search a var of 'name' and length 'lname' and return it or NULL */
275 static struct var *var_search(const char *name, size_t lname)
276 {
277         struct var *result = vars;
278         while (result != NULL && (strncmp(result->name, name, lname) != 0
279                                         || result->name[lname] != 0))
280                 result = result->next;
281
282         return result;
283 }
284
285 /* append a new var to the list and return it or NULL if allocations failed */
286 static struct var *var_add(const char *name, size_t lname,
287                                                                 int depend, const char *value)
288 {
289         struct var *result, *prev;
290         char *sname, *normal;
291         size_t length;
292
293         /* check for the value */
294         if (action == RPM && value != NULL) {
295                 length = strlen(value) + 1;
296         } else {
297                 value = NULL;
298                 length = lname + 4;
299         }
300         /* allocations */
301         result = malloc(sizeof *result);
302         sname = strndup(name, lname);
303         normal = malloc(length);
304         if (result == NULL || sname == NULL || normal == NULL) {
305                 /* failure of allocations */
306                 free(result);
307                 free(sname);
308                 free(normal);
309                 result = NULL;
310         } else {
311                 /* success: init the structure */
312                 result->next = NULL;
313                 result->name = sname;
314                 result->normal = normal;
315                 result->dependant = depend;
316                 if (value) {
317                         memcpy(normal, value, length);
318                 } else {
319                         *normal++ = '$';
320                         *normal++ = '{';
321                         memcpy(normal, name, lname);
322                         normal += lname;
323                         *normal++ = '}';
324                         *normal = 0;
325                 }
326
327                 /* link at end of the list */
328                 prev = vars;
329                 if (prev == NULL)
330                         vars = result;
331                 else {
332                         while (prev != NULL && prev->next != NULL)
333                                 prev = prev->next;
334                         prev->next = result;
335                 }
336         }
337
338         return result;
339 }
340
341 /*== CALLBACK OF PARSING OF THE META FILE ==============================*/
342
343 static void conferr(const char *format, ...)
344 {
345         va_list ap;
346
347         notstderr = action == CHECK;
348         writerror("ERROR ");
349         va_start(ap, format);
350         vwriterror(format, ap);
351         va_end(ap);
352         notstderr = 0;
353 }
354
355 static int errcb(struct parsing *parsing,
356                                 size_t pos, const char *message)
357 {
358         struct parsinfo info;
359
360         /* get the info */
361         parse_utf8_info(parsing, &info, pos);
362
363         /* emit the error */
364         conferr("line %d: %s\n..: %.*s\n..: %*s\n",
365                                 info.lino, message,
366                                 (int)info.length, info.begin,
367                                 info.colno, "^");
368
369         /* count it */
370         errcount++;
371
372         /* continue to parse */
373         return 1;
374 }
375
376 static int putcb(struct parsing *parsing,
377                                 const char *name, size_t lname,
378                                 const char *value, size_t lvalue,
379                                 size_t begin_pos, size_t end_pos)
380 {
381         enum fkey fkey;
382         struct key *key;
383         struct parsinfo here, there;
384
385         /* check that it is not a foreign key */
386         fkey = foreign(name, lname);
387         if (fkey != _FOREIGN_INVALID_) {
388                 parse_utf8_info(parsing, &here, begin_pos);
389                 conferr("line %d: reserved variable name '%.*s'\n"
390                                 "..: %.*s\n..: %*s\n",
391                                    here.lino, (int)lname, name,
392                                    (int)here.length, here.begin, here.colno, "^");
393
394                 errcount++;
395                 dependant = 0;
396                 return 0;
397         }
398
399         /* search if already defined */
400         key = key_search(name, lname);
401         if (key != NULL) {
402
403                 /* yes! that's an error */
404                 parse_utf8_info(parsing, &here, begin_pos);
405                 parse_utf8_info(parsing, &there, key->begin);
406                 conferr("line %d: redefinition of '%s'\n"
407                                 "...was defined line %d\n..: %.*s\n..: %*s\n"
408                                 "...is redefined line %d\n..: %.*s\n..: %*s\n",
409                                    here.lino, key->name,
410                                    there.lino, (int)there.length, there.begin, there.colno, "^",
411                                    here.lino, (int)here.length, here.begin, here.colno, "^");
412
413                 errcount++;
414                 dependant = 0;
415                 return 0;
416         }
417
418         /* create and record the key */
419         key = key_add(name, lname, value, lvalue, begin_pos, end_pos);
420         dependant = 0;
421         if (key != NULL)
422                 return 0;
423
424         /* no can't because of memory! */
425         fatal("out of memory");
426         errcount++;
427         return -1;
428 }
429
430 static const char *getcb(struct parsing *parsing,
431                                 const char *name, size_t length,
432                                 size_t begin_pos, size_t end_pos)
433 {
434         struct parsinfo here;
435         struct var *var;
436         enum fkey fkey;
437         struct key *key;
438         int depend;
439
440         /* search if already defined */
441         var = var_search(name, length);
442         if (var != NULL) {
443                 /* yes cool, return the normalized form */
444                 if (var->dependant)
445                         dependant = 1;
446                 return var->normal;
447         }
448
449         /* search the variable */
450         fkey = foreign(name, length);
451         key = key_search(name, length);
452
453         if (fkey == _FOREIGN_INVALID_ && key == NULL) {
454
455                 /* not a valid variable, emit the error */
456                 parse_utf8_info(parsing, &here, begin_pos);
457                 conferr("line %d: use of unknown variable '%.*s'\n"
458                                 "..: %.*s\n..: %*s\n",
459                                         here.lino, (int)length, name,
460                                         (int)here.length, here.begin, here.colno, "^");
461                 errcount++;
462                 dependant = 1; /* kind of invalidity */
463                 return "***error***"; /* avoid further error */
464         }
465
466         /* valid variables:  those of foreign or the already defined keys */
467
468         /* set dependant state */
469         depend = fkey != _FOREIGN_INVALID_ || key->dependant;
470         if (depend)
471                 dependant = 1;
472
473         /* create and record the variable */
474         var = var_add(name, length, depend, key == NULL ? NULL : key->value);
475         if (var != NULL)
476                 /* created, return the normalized form */
477                 return var->normal;
478
479         /* memory depletion */
480         fatal("out of memory");
481         dependant = 1; /* kind of invalidity */
482         errcount++;
483         return "***error***"; /* avoid further error */
484 }
485
486 /*======================================================================*/
487
488 /* compare two keys */
489 static int keycmp(const void *a, const void *b)
490 {
491         const struct key *ka = *(const struct key **)a;
492         const struct key *kb = *(const struct key **)b;
493         return strcmp(ka->name, kb->name);
494 }
495
496 /* sort the keys and return their count */
497 static int sortkeys()
498 {
499         struct key *key = keys, **array;
500         int count = 0, index;
501
502         while (key) {
503                 key = key->next;
504                 count++;
505         }
506
507         array = malloc(count * sizeof * array);
508         if (array == NULL)
509                 return -1;
510
511         key = keys;
512         index = 0;
513
514         while (key) {
515                 array[index++] = key;
516                 key = key->next;
517         }
518
519         qsort(array, count, sizeof * array, keycmp);
520
521         while (index) {
522         array[--index]->next = key;
523                 key = array[index];
524         }
525         keys = key;
526         free(array);
527
528         return count;
529 }
530
531 /*======================================================================*/
532
533 /* pretty print the read file */
534 static int pretty(const char *buffer, size_t length, FILE *output)
535 {
536         int status;
537         struct key *key = keys;
538         size_t pos = 0;
539
540         while (pos < length && key != NULL) {
541                 if (pos < key->begin) {
542                         status = fprintf(output, "%.*s", (int)(key->begin-pos), buffer+pos);
543                         if (status < 0)
544                                 return status;
545                 }
546                 status = fprintf(output, "%s=%s", key->name, key->value);
547                 if (status < 0)
548                         return status;
549                 pos = key->end;
550                 key = key->next;
551         }
552
553         if (pos < length) {
554                 status = fprintf(output, "%.*s", (int)(length-pos), buffer+pos);
555                 if (status < 0)
556                         return status;
557         }
558
559         return 0;
560 }
561
562 /* generate the header */
563 static int genh(FILE *output)
564 {
565         struct key *key;
566         int status;
567
568 #ifdef SORT_KEYS
569         status = sortkeys();
570         if (status < 0)
571                 return status;
572 #endif
573
574         status = fprintf(output, "%s", genh_head);
575         if (status < 0)
576                 return status;
577         for (key = keys ; key != NULL ; key = key->next) {
578                 status = fprintf(output, "\t%s,\n", key->name);
579                 if (status < 0)
580                         return status;
581         }
582         status = fprintf(output, "%s", genh_tail);
583         if (status < 0)
584                 return status;
585         return 0;
586 }
587
588 /* generate hash code using gperf */
589 static int genc(FILE *output)
590 {
591         struct key *key;
592         int fds[2];
593         pid_t pid;
594         int result, sts;
595         size_t l;
596
597 #ifdef SORT_KEYS
598         sts = sortkeys();
599         if (sts < 0)
600                 return sts;
601 #endif
602
603         result = pipe(fds);
604         if (result != 0)
605                 return result;
606
607         fflush(output);
608         pid = fork();
609         if (pid == -1) {
610                 close(fds[0]);
611                 close(fds[1]);
612                 fatal("can't fork");
613                 result = -1;
614         } else if (pid == 0) {
615                 dup2(fds[0], 0);
616                 close(fds[0]);
617                 close(fds[1]);
618                 if (fileno(output) != 1)
619                         dup2(fileno(output), 1);
620                 result = execve(gperf_command[0], gperf_command, environ);
621                 fatal("can't execute gperf");
622                 exit(1);
623         } else {
624                 close(fds[0]);
625                 sts = write(fds[1], gperf_head, sizeof(gperf_head)-1);
626                 if (sts < 0)
627                         result = sts;
628                 for (key = keys ; key != NULL ; key = key->next) {
629                         l = strlen(key->name);
630                         sts = write(fds[1], key->name, l);
631                         if (sts < 0)
632                                 result = sts;
633                         sts = write(fds[1], ", ", 2);
634                         if (sts < 0)
635                                 result = sts;
636                         sts = write(fds[1], key->name, l);
637                         if (sts < 0)
638                                 result = sts;
639                         sts = write(fds[1], "\n", 1);
640                         if (sts < 0)
641                                 result = sts;
642                 }
643                 close(fds[1]);
644                 wait(&result);
645                 sts = WIFEXITED(result) && WEXITSTATUS(result) == 0 ? 0 : -1;
646                 if (sts < 0)
647                         result = sts;
648         }
649         return result;
650 }
651
652 /* generate the rpm macros */
653 static int rpm(FILE *output)
654 {
655         struct key *key;
656         int status;
657
658 #ifdef SORT_KEYS
659         status = sortkeys();
660         if (status < 0)
661                 return status;
662 #endif
663
664         status = fprintf(output, "%s", rpm_head);
665         if (status < 0)
666                 return status;
667         for (key = keys ; key != NULL ; key = key->next) {
668                 if (!key->dependant) {
669                         status = fprintf(output, "%%%-40s %s\n", key->name, key->value);
670                         if (status < 0)
671                                 return status;
672                 }
673         }
674         return 0;
675 }
676
677 /* generate the signup */
678 static int signup(FILE *output)
679 {
680         struct key *key;
681         int status;
682         int i;
683         struct sha256sum *sum;
684         char term;
685         char signup[32];
686
687 #ifdef SORT_KEYS
688         status = sortkeys();
689         if (status < 0)
690                 return status;
691 #endif
692
693         sum = sha256sum_create();
694         if (sum == NULL)
695                 return -1;
696
697         term = ';';
698         for (key = keys ; key != NULL ; key = key->next) {
699                 status = sha256sum_add_data(sum, key->name, strlen(key->name));
700                 if (status < 0) {
701                         sha256sum_destroy(sum);
702                         return status;
703                 }
704                 status = sha256sum_add_data(sum, &term, 1);
705                 if (status < 0) {
706                         sha256sum_destroy(sum);
707                         return status;
708                 }
709         }
710
711         status = sha256sum_get(sum, signup);
712         sha256sum_destroy(sum);
713         if (status < 0)
714                 return status;
715
716         status = fprintf(output, "%s", signup_head);
717         if (status < 0)
718                 return status;
719
720         for (i = 0 ; i < 32 ; i++) {
721                 status = fprintf(output, "%s'\\x%02x'%s",
722                                         (i & 7) ? " " : "    ",
723                                         (int)(unsigned char)signup[i],
724                                         (i & 7) < 7 ? "," : i == 31 ? "\n" : ",\n");
725                 if (status < 0)
726                         return status;
727         }
728         status = fprintf(output, "%s", signup_tail);
729         if (status < 0)
730                 return status;
731         return 0;
732 }
733
734 /* main of processing */
735 static int process()
736 {
737         struct parsing parsing;
738         struct buffer buffer;
739         int result;
740
741         /* read the file */
742         result = buffer_create(&buffer, metafilepath);
743         if (result != 0) {
744                 fatal("can't read file %s", metafilepath);
745                 return -1;
746         }
747
748         /* parse the file */
749         parsing.buffer = buffer.buffer;
750         parsing.length = buffer.length;
751         parsing.maximum_data_size = 0;
752         parsing.should_escape = action != RPM;
753         parsing.data = 0;
754         parsing.get = getcb;
755         parsing.put = putcb;
756         parsing.error = errcb;
757         dependant = 0;
758         result = parse_utf8_config(&parsing);
759         if (result != 0) {
760                 buffer_destroy(&buffer);
761                 fatal("while parsing the file %s", metafilepath);
762                 return -1;
763         }
764         if (errcount != 0) {
765                 buffer_destroy(&buffer);
766                 fatal("%d errors detected %s", errcount, metafilepath);
767                 return -1;
768         }
769
770         /* process */
771         switch (action) {
772         case CHECK:
773                 break;
774         case PRETTY:
775                 pretty(buffer.buffer, buffer.length, stdout);
776                 break;
777         case GENH:
778                 genh(stdout);
779                 break;
780         case GENC:
781                 genc(stdout);
782                 break;
783         case RPM:
784                 rpm(stdout);
785                 break;
786         case SIGNUP:
787                 signup(stdout);
788                 break;
789         }
790
791         buffer_destroy(&buffer);
792         return 0;
793 }
794
795 /*======================================================================*/
796
797 /* very simple argument parsing */
798 static int arguments(char **argv)
799 {
800         /* skip the program name*/
801         argv++;
802
803         /* scan first arg */
804         if (*argv == NULL) {
805                 /* no argument then default is to check */
806                 action = CHECK;
807         } else {
808                 /* check if first argument is 'check', 'pretty', 'c', 'h', '-h',
809                    '--help' or 'help' */
810                 if (0 == strcmp(*argv, "check")) {
811                         action = CHECK;
812                         argv++;
813                 } else if (0 == strcmp(*argv, "pretty")) {
814                         action = PRETTY;
815                         argv++;
816                 } else if (0 == strcmp(*argv, "c")) {
817                         action = GENC;
818                         argv++;
819                 } else if (0 == strcmp(*argv, "h")) {
820                         action = GENH;
821                         argv++;
822                 } else if (0 == strcmp(*argv, "rpm")) {
823                         action = RPM;
824                         argv++;
825                 } else if (0 == strcmp(*argv, "signup")) {
826                         action = SIGNUP;
827                         argv++;
828                 } else if (0 == strcmp(*argv, "help") || 0 == strcmp(*argv, "--help")) {
829                         printf("%s", help);
830                         exit(0);
831                         return -1;
832                 } else if (**argv == '-') {
833                         if (0 == strcmp(*argv, "--") || 0 == strcmp(*argv, "-")) {
834                                 action = CHECK;
835                         } else {
836                                 argerror("unknown option '%s'", *argv);
837                                 return -1;
838                         }
839                 }
840                 /* skip the -- arg if present */
841                 if (*argv != NULL && 0 == strcmp(*argv, "--"))
842                         argv++;
843                 /* get a meta file argument */
844                 if (*argv != NULL) {
845                         if (0 == strcmp(*argv, "-"))
846                                 metafilepath = "/dev/stdin";
847                         else
848                                 metafilepath = *argv;
849                         argv++;
850                 }
851                 /* check that there is no extra argument */
852                 if (*argv != NULL) {
853                         argerror("extra argument found '%s'", *argv);
854                         return -1;
855                 }
856         }
857         return 0;
858 }
859
860 int main(int argc, char **argv)
861 {
862         if (arguments(argv) == 0)
863                 if (process() == 0)
864                         return 0;
865
866         return 1;
867 }