Add static symbols in .sym file
[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             sha256sum_destroy(sum);
708             return status;
709         }
710         status = sha256sum_add_data(sum, &term, 1);
711         if (status < 0) {
712             sha256sum_destroy(sum);
713             return status;
714         }
715     }
716
717     status = sha256sum_get(sum, signup);
718     sha256sum_destroy(sum);
719     if (status < 0)
720         return status;
721
722     status = fprintf( output, "%s", signup_head);
723     if (status < 0)
724         return status;
725
726     for (i=0 ; i<32 ; i++) {
727         status = fprintf( output, "%s'\\x%02x'%s",
728                     (i & 7) ? " " : "    ",
729                     (int)(unsigned char)signup[i],
730                     (i & 7) < 7 ? "," : i == 31 ? "\n" : ",\n");
731         if (status < 0)
732             return status;
733     }
734     status = fprintf( output, "%s", signup_tail);
735     if (status < 0)
736         return status;
737     return 0;
738 }
739
740 /* main of processing */
741 static int process()
742 {
743     struct parsing parsing;
744     struct buffer buffer;
745     int result;
746
747     /* read the file */
748     result = buffer_create( &buffer, metafilepath);
749     if (result != 0) {
750         fatal( "can't read file %s", metafilepath);
751         return -1;
752     }
753
754     /* parse the file */
755     parsing.buffer = buffer.buffer;
756     parsing.length = buffer.length;
757     parsing.maximum_data_size = 0;
758     parsing.should_escape = action!=RPM;
759     parsing.data = 0;
760     parsing.get = getcb;
761     parsing.put = putcb;
762     parsing.error = errcb;
763     dependant = 0;
764     result = parse_utf8_config( &parsing);
765     if (result != 0) {
766         buffer_destroy( &buffer);
767         fatal( "while parsing the file %s", metafilepath);
768         return -1;
769     }
770     if (errcount != 0) {
771         buffer_destroy( &buffer);
772         fatal( "%d errors detected %s", errcount, metafilepath);
773         return -1;
774     }
775
776     /* process */
777     switch( action) {
778     case CHECK:
779         break;
780     case PRETTY:
781         pretty( buffer.buffer, buffer.length, stdout);
782         break;
783     case GENH:
784         genh( stdout);
785         break;
786     case GENC:
787         genc( stdout);
788         break;
789     case RPM:
790         rpm( stdout);
791         break;
792     case SIGNUP:
793         signup( stdout);
794         break;
795     }
796
797     buffer_destroy( &buffer);
798     return 0;
799 }
800
801 /*======================================================================*/
802
803 /* very simple argument parsing */
804 static int arguments( char **argv)
805 {
806     /* skip the program name*/
807     argv++;
808
809     /* scan first arg */
810     if (*argv == NULL) {
811         /* no argument then default is to check */
812         action = CHECK;
813     }
814     else {
815         /* check if first argument is 'check', 'pretty', 'c', 'h', '-h',
816            '--help' or 'help' */
817         if (0 == strcmp( *argv, "check")) {
818             action = CHECK;
819             argv++;
820         }
821         else if (0 == strcmp( *argv, "pretty")) {
822             action = PRETTY;
823             argv++;
824         }
825         else if (0 == strcmp( *argv, "c")) {
826             action = GENC;
827             argv++;
828         }
829         else if (0 == strcmp( *argv, "h")) {
830             action = GENH;
831             argv++;
832         }
833         else if (0 == strcmp( *argv, "rpm")) {
834             action = RPM;
835             argv++;
836         }
837         else if (0 == strcmp( *argv, "signup")) {
838             action = SIGNUP;
839             argv++;
840         }
841         else if (0 == strcmp( *argv, "help") || 0 == strcmp( *argv, "--help")) {
842             printf("%s", help);
843             exit(0);
844             return -1;
845         }
846         else if (**argv == '-') {
847             if (0 == strcmp( *argv, "--") || 0 == strcmp( *argv, "-") ) {
848                 action = CHECK;
849             }
850             else {
851                 argerror( "unknown option '%s'", *argv);
852                 return -1;
853             }
854         }
855         /* skip the -- arg if present */
856         if (*argv != NULL && 0 == strcmp( *argv, "--")) {
857             argv++;
858         }
859         /* get a meta file argument */
860         if (*argv != NULL) {
861             if (0 == strcmp( *argv, "-"))
862                 metafilepath = "/dev/stdin";
863             else
864                 metafilepath = *argv;
865             argv++;
866         }
867         /* check that there is no extra argument */
868         if (*argv != NULL) {
869             argerror("extra argument found '%s'",*argv);
870             return -1;
871         }   
872     }
873     return 0;
874 }
875
876 int main(int argc, char **argv)
877 {
878     if (arguments(argv) == 0)
879         if (process() == 0)
880             return 0;
881
882     return 1;
883 }
884
885