0c48f362576ccab3d20c3146a297a15b0c8c529e
[platform/core/system/tizen-platform-wrapper.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     }
250     else {
251         /* success: init the structure */
252         result->next = NULL;
253         result->name = sname;
254         result->value = svalue;
255         result->begin = begin_pos;
256         result->end = end_pos;
257         result->dependant = dependant;
258
259         /* link at end of the list */
260         prev = keys;
261         if (prev == NULL)
262             keys = result;
263         else {
264             while(prev!=NULL && prev->next!=NULL)
265                 prev = prev->next;
266             prev->next = result;
267         }
268     }
269
270     return result;
271 }
272
273 /*======================================================================*/
274
275 /* search a var of 'name' and length 'lname' and return it or NULL */
276 static struct var *var_search( const char *name, size_t lname)
277 {
278     struct var *result = vars;
279     while(result!=NULL && (strncmp( result->name, name, lname)!=0
280                     || result->name[lname]!=0))
281         result = result->next;
282
283     return result;
284 }
285
286 /* append a new var to the list and return it or NULL if allocations failed */
287 static struct var *var_add( const char *name, size_t lname, 
288                                                 int depend, const char *value)
289 {
290     struct var *result, *prev;
291     char *sname, *normal;
292     size_t length;
293
294     /* check for the value */
295     if (action == RPM && value != NULL) {
296         length = strlen( value) + 1;
297     }
298     else {
299         value = NULL;
300         length = lname + 4;
301     }
302     /* allocations */
303     result = malloc(sizeof *result);
304     sname = strndup( name, lname);
305     normal = malloc( length);
306     if (result == NULL || sname == NULL || normal == NULL) {
307         /* failure of allocations */
308         free( result);
309         free( sname);
310         free( normal);
311         result = NULL;
312     }
313     else {
314         /* success: init the structure */
315         result->next = NULL;
316         result->name = sname;
317         result->normal = normal;
318         result->dependant = depend;
319         if (value) {
320             memcpy( normal, value, length);
321         }
322         else {
323             *normal++ = '$';
324             *normal++ = '{';
325             memcpy( normal, name, lname);
326             normal += lname;
327             *normal++ = '}';
328             *normal = 0;
329         }
330
331         /* link at end of the list */
332         prev = vars;
333         if (prev == NULL)
334             vars = result;
335         else {
336             while(prev!=NULL && prev->next!=NULL)
337                 prev = prev->next;
338             prev->next = result;
339         }
340     }
341
342     return result;
343 }
344
345 /*== CALLBACK OF PARSING OF THE META FILE ==============================*/
346
347 static void conferr( const char *format, ...)
348 {
349     va_list ap;
350
351     notstderr = action == CHECK;
352     writerror( "ERROR ");
353     va_start(ap, format);
354     vwriterror( format, ap);
355     va_end(ap);
356     notstderr = 0;
357 }
358
359 static int errcb( struct parsing *parsing,
360                 size_t pos, const char *message)
361 {
362     struct parsinfo info;
363
364     /* get the info */
365     parse_utf8_info( parsing, &info, pos);
366
367     /* emit the error */
368     conferr("line %d: %s\n..: %.*s\n..: %*s\n", 
369                 info.lino, message, 
370                 (int)info.length, info.begin,
371                 info.colno, "^"); 
372
373     /* count it */
374     errcount++;
375
376     /* continue to parse */
377     return 1;
378 }
379
380 static int putcb( struct parsing *parsing, 
381                 const char *name, size_t lname, 
382                 const char *value, size_t lvalue,
383                 size_t begin_pos, size_t end_pos)
384 {
385     enum fkey fkey;
386     struct key *key;
387     struct parsinfo here, there;
388
389     /* check that it is not a foreign key */
390     fkey = foreign( name, lname);
391     if (fkey != _FOREIGN_INVALID_) {
392         parse_utf8_info( parsing, &here, begin_pos);
393         conferr("line %d: reserved variable name '%.*s'\n" 
394                 "..: %.*s\n..: %*s\n", 
395                    here.lino, (int)lname, name,
396                    here.lino, (int)here.length, here.begin, here.colno, "^"); 
397
398         errcount++;
399         dependant = 0;
400         return 0;
401     }
402
403     /* search if already defined */
404     key = key_search( name, lname);
405     if (key != NULL) {
406
407         /* yes! that's an error */
408         parse_utf8_info( parsing, &here, begin_pos);
409         parse_utf8_info( parsing, &there, key->begin);
410         conferr("line %d: redefinition of '%s'\n" 
411                 "...was defined line %d\n..: %.*s\n..: %*s\n"
412                 "...is redefined line %d\n..: %.*s\n..: %*s\n", 
413                    here.lino, key->name,
414                    there.lino, (int)there.length, there.begin, there.colno, "^",
415                    here.lino, (int)here.length, here.begin, here.colno, "^"); 
416
417         errcount++;
418         dependant = 0;
419         return 0;
420     }
421
422     /* create and record the key */
423     key = key_add( name, lname, value, lvalue, begin_pos, end_pos);
424     dependant = 0;
425     if (key != NULL)
426         return 0;
427
428     /* no can't because of memory! */
429     fatal("out of memory");
430     errcount++;
431     return -1;
432 }
433
434 static const char *getcb( struct parsing *parsing,
435                 const char *name, size_t length,
436                 size_t begin_pos, size_t end_pos)
437 {
438     struct parsinfo here;
439     struct var *var;
440     enum fkey fkey;
441     struct key *key;
442     int depend;
443
444     /* search if already defined */
445     var = var_search( name, length);
446     if (var != NULL) {
447         /* yes cool, return the normalized form */
448         if (var->dependant)
449             dependant = 1;
450         return var->normal;
451     }
452
453     /* search the variable */
454     fkey = foreign( name, length);
455     key = key_search( name, length);
456
457     if (fkey == _FOREIGN_INVALID_ && key == NULL) {
458
459         /* not a valid variable, emit the error */
460         parse_utf8_info( parsing, &here, begin_pos);
461         conferr("line %d: use of unknown variable '%.*s'\n"
462                 "..: %.*s\n..: %*s\n", 
463                     here.lino, (int)length, name,
464                     (int)here.length, here.begin, here.colno, "^"); 
465         errcount++;
466         dependant = 1; /* kind of invalidity */
467         return "***error***"; /* avoid further error */
468     }
469
470     /* valid variables:  those of foreign or the already defined keys */
471
472     /* set dependant state */
473     depend = fkey != _FOREIGN_INVALID_ || key->dependant;
474     if (depend)
475         dependant = 1;
476
477     /* create and record the variable */
478     var = var_add( name, length, depend, key==NULL ? NULL : key->value);
479     if (var != NULL)
480         /* created, return the normalized form */
481         return var->normal;
482
483     /* memory depletion */
484     fatal("out of memory");
485     dependant = 1; /* kind of invalidity */
486     errcount++;
487     return "***error***"; /* avoid further error */
488 }
489
490 /*======================================================================*/
491
492 /* compare two keys */
493 static int keycmp(const void *a, const void *b)
494 {
495     const struct key *ka = *(const struct key **)a;
496     const struct key *kb = *(const struct key **)b;
497     return strcmp(ka->name, kb->name);
498 }
499
500 /* sort the keys and return their count */
501 static int sortkeys()
502 {
503     struct key *key = keys, **array;
504     int count = 0, index;
505
506     while (key) {
507         key = key->next;
508         count++;
509     }
510
511     array = malloc( count * sizeof * array);
512     if (array == NULL)
513         return -1;
514
515     key = keys;
516     index = 0;
517     
518     while (key) {
519         array[index++] = key;
520         key = key->next;
521     }
522
523     qsort(array, count, sizeof * array, keycmp);
524
525     while (index) {
526         array[--index]->next = key;
527         key = array[index];
528     }
529     keys = key;
530     free( array);
531
532     return count;
533 }
534
535 /*======================================================================*/
536
537 /* pretty print the read file */
538 static int pretty( const char *buffer, size_t length, FILE *output)
539 {
540     int status;
541     struct key *key = keys;
542     size_t pos = 0;
543
544     while (pos < length && key != NULL) {
545         if (pos < key->begin) {
546             status = fprintf(output, "%.*s", (int)(key->begin-pos), buffer+pos);
547             if (status < 0)
548                 return status;
549         }
550         status = fprintf( output, "%s=%s", key->name, key->value);
551         if (status < 0)
552             return status;
553         pos = key->end;
554         key = key->next;
555     }
556
557     if (pos < length) {
558         status = fprintf( output, "%.*s", (int)(length-pos), buffer+pos);
559         if (status < 0)
560             return status;
561     }
562
563     return 0;
564 }
565
566 /* generate the header */
567 static int genh( FILE *output)
568 {
569     struct key *key;
570     int status;
571
572 #ifndef NO_SORT_KEYS
573     status = sortkeys();
574     if (status < 0)
575         return status;
576 #endif
577
578     status = fprintf( output, "%s", genh_head);
579     if (status < 0)
580         return status;
581     for (key = keys ; key != NULL ; key = key->next) {
582         status = fprintf( output, "\t%s,\n", key->name);
583         if (status < 0)
584             return status;
585     }
586     status = fprintf( output, "%s", genh_tail);
587     if (status < 0)
588         return status;
589     return 0;
590 }
591
592 /* generate hash code using gperf */
593 static int genc(FILE *output)
594 {
595     struct key *key;
596     int fds[2];
597     pid_t pid;
598     int result, sts;
599     size_t l;
600
601 #ifndef NO_SORT_KEYS
602     sts = sortkeys();
603     if (sts < 0)
604         return sts;
605 #endif
606
607     result = pipe(fds);
608     if (result != 0)
609         return result;
610
611     fflush( output);
612     pid = fork();
613     if (pid == -1) {
614         close( fds[0]);
615         close( fds[1]);
616         fatal( "can't fork");
617         result = -1;
618     }
619     else if (pid == 0) {
620         dup2( fds[0], 0);
621         close( fds[0]);
622         close( fds[1]);
623         if (fileno(output) != 1)
624             dup2( fileno(output), 1);
625         result = execve( gperf_command[0], gperf_command, environ);
626         fatal("can't execute gperf");
627         exit(1);
628     }
629     else {
630         close( fds[0]);
631         sts = write( fds[1], gperf_head, sizeof(gperf_head)-1);
632         if (sts < 0)
633             result = sts;
634         for (key = keys ; key != NULL ; key = key->next) {
635             l = strlen( key->name);
636             sts = write( fds[1], key->name, l);
637             if (sts < 0)
638                 result = sts;
639             sts = write( fds[1], ", ", 2);
640             if (sts < 0)
641                 result = sts;
642             sts = write( fds[1], key->name, l);
643             if (sts < 0)
644                 result = sts;
645             sts = write( fds[1], "\n", 1);
646             if (sts < 0)
647                 result = sts;
648         }
649         close( fds[1]);
650         wait(&result);
651         sts = WIFEXITED(result) && WEXITSTATUS(result)==0 ? 0 : -1;
652         if (sts < 0)
653             result = sts;
654     }
655     return result;
656 }
657
658 /* generate the rpm macros */
659 static int rpm( FILE *output)
660 {
661     struct key *key;
662     int status;
663
664 #ifndef NO_SORT_KEYS
665     status = sortkeys();
666     if (status < 0)
667         return status;
668 #endif
669
670     status = fprintf( output, "%s", rpm_head);
671     if (status < 0)
672         return status;
673     for (key = keys ; key != NULL ; key = key->next) {
674         if (!key->dependant) {
675             status = fprintf( output, "%%%-40s %s\n", key->name, key->value);
676             if (status < 0)
677                 return status;
678         }
679     }
680     return 0;
681 }
682
683 /* generate the signup */
684 static int signup( FILE *output)
685 {
686     struct key *key;
687     int status;
688     int i;
689     struct sha256sum *sum;
690     char term;
691     char signup[32];
692
693 #ifndef NO_SORT_KEYS
694     status = sortkeys();
695     if (status < 0)
696         return status;
697 #endif
698
699     sum = sha256sum_create();
700     if (sum == NULL)
701         return -1;
702
703     term = ';';
704     for (key = keys ; key != NULL ; key = key->next) {
705         status = sha256sum_add_data(sum, key->name, strlen(key->name));
706         if (status < 0)
707             return status;
708         status = sha256sum_add_data(sum, &term, 1);
709         if (status < 0)
710             return status;
711     }
712
713     status = sha256sum_get(sum, signup);
714     if (status < 0)
715         return status;
716
717     status = fprintf( output, "%s", signup_head);
718     if (status < 0)
719         return status;
720
721     for (i=0 ; i<32 ; i++) {
722         status = fprintf( output, "%s'\\x%02x'%s",
723                     (i & 7) ? " " : "    ",
724                     (int)(unsigned char)signup[i],
725                     (i & 7) < 7 ? "," : i == 31 ? "\n" : ",\n");
726         if (status < 0)
727             return status;
728     }
729     status = fprintf( output, "%s", signup_tail);
730     if (status < 0)
731         return status;
732     return 0;
733 }
734
735 /* main of processing */
736 static int process()
737 {
738     struct parsing parsing;
739     struct buffer buffer;
740     int result;
741
742     /* read the file */
743     result = buffer_create( &buffer, metafilepath);
744     if (result != 0) {
745         fatal( "can't read file %s", metafilepath);
746         return -1;
747     }
748
749     /* parse the file */
750     parsing.buffer = buffer.buffer;
751     parsing.length = buffer.length;
752     parsing.maximum_data_size = 0;
753     parsing.should_escape = action!=RPM;
754     parsing.data = 0;
755     parsing.get = getcb;
756     parsing.put = putcb;
757     parsing.error = errcb;
758     dependant = 0;
759     result = parse_utf8_config( &parsing);
760     if (result != 0) {
761         buffer_destroy( &buffer);
762         fatal( "while parsing the file %s", metafilepath);
763         return -1;
764     }
765     if (errcount != 0) {
766         buffer_destroy( &buffer);
767         fatal( "%d errors detected %s", errcount, metafilepath);
768         return -1;
769     }
770
771     /* process */
772     switch( action) {
773     case CHECK:
774         break;
775     case PRETTY:
776         pretty( buffer.buffer, buffer.length, stdout);
777         break;
778     case GENH:
779         genh( stdout);
780         break;
781     case GENC:
782         genc( stdout);
783         break;
784     case RPM:
785         rpm( stdout);
786         break;
787     case SIGNUP:
788         signup( stdout);
789         break;
790     }
791
792     buffer_destroy( &buffer);
793     return 0;
794 }
795
796 /*======================================================================*/
797
798 /* very simple argument parsing */
799 static int arguments( char **argv)
800 {
801     /* skip the program name*/
802     argv++;
803
804     /* scan first arg */
805     if (*argv == NULL) {
806         /* no argument then default is to check */
807         action = CHECK;
808     }
809     else {
810         /* check if first argument is 'check', 'pretty', 'c', 'h', '-h',
811            '--help' or 'help' */
812         if (0 == strcmp( *argv, "check")) {
813             action = CHECK;
814             argv++;
815         }
816         else if (0 == strcmp( *argv, "pretty")) {
817             action = PRETTY;
818             argv++;
819         }
820         else if (0 == strcmp( *argv, "c")) {
821             action = GENC;
822             argv++;
823         }
824         else if (0 == strcmp( *argv, "h")) {
825             action = GENH;
826             argv++;
827         }
828         else if (0 == strcmp( *argv, "rpm")) {
829             action = RPM;
830             argv++;
831         }
832         else if (0 == strcmp( *argv, "signup")) {
833             action = SIGNUP;
834             argv++;
835         }
836         else if (0 == strcmp( *argv, "help") || 0 == strcmp( *argv, "--help")) {
837             printf("%s", help);
838             exit(0);
839             return -1;
840         }
841         else if (**argv == '-') {
842             if (0 == strcmp( *argv, "--") || 0 == strcmp( *argv, "-") ) {
843                 action = CHECK;
844             }
845             else {
846                 argerror( "unknown option '%s'", *argv);
847                 return -1;
848             }
849         }
850         /* skip the -- arg if present */
851         if (*argv != NULL && 0 == strcmp( *argv, "--")) {
852             argv++;
853         }
854         /* get a meta file argument */
855         if (*argv != NULL) {
856             if (0 == strcmp( *argv, "-"))
857                 metafilepath = "/dev/stdin";
858             else
859                 metafilepath = *argv;
860             argv++;
861         }
862         /* check that there is no extra argument */
863         if (*argv != NULL) {
864             argerror("extra argument found '%s'",*argv);
865             return -1;
866         }   
867     }
868     return 0;
869 }
870
871 int main(int argc, char **argv)
872 {
873     if (arguments(argv) == 0)
874         if (process() == 0)
875             return 0;
876
877     return 1;
878 }
879
880