hook gvariant vectors up to kdbus
[platform/upstream/glib.git] / gio / gresource-tool.c
1 /*
2  * Copyright © 2012 Red Hat, Inc
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the licence, 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  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
16  *
17  * Author: Matthias Clasen
18  */
19
20 #include "config.h"
21
22 #include <stdlib.h>
23 #include <stdio.h>
24
25 #include <sys/types.h>
26 #include <sys/stat.h>
27 #include <fcntl.h>
28 #include <string.h>
29 #include <locale.h>
30
31 #ifdef HAVE_LIBELF
32 #include <libelf.h>
33 #include <gelf.h>
34 #include <sys/mman.h>
35 #endif
36
37 #include <gio/gio.h>
38 #include <glib/gstdio.h>
39 #include <gi18n.h>
40
41 #ifdef G_OS_WIN32
42 #include "glib/glib-private.h"
43 #endif
44
45 /* GResource functions {{{1 */
46 static GResource *
47 get_resource (const gchar *file)
48 {
49   gchar *content;
50   gsize size;
51   GResource *resource;
52   GBytes *data;
53
54   resource = NULL;
55
56   if (g_file_get_contents (file, &content, &size, NULL))
57     {
58       data = g_bytes_new_take (content, size);
59       resource = g_resource_new_from_data (data, NULL);
60       g_bytes_unref (data);
61     }
62
63   return resource;
64 }
65
66 static void
67 list_resource (GResource   *resource,
68                const gchar *path,
69                const gchar *section,
70                const gchar *prefix,
71                gboolean     details)
72 {
73   gchar **children;
74   gsize size;
75   guint32 flags;
76   gint i;
77   gchar *child;
78   GError *error = NULL;
79   gint len;
80
81   children = g_resource_enumerate_children (resource, path, 0, &error);
82   if (error)
83     {
84       g_printerr ("%s\n", error->message);
85       g_error_free (error);
86       return;
87     }
88   for (i = 0; children[i]; i++)
89     {
90       child = g_strconcat (path, children[i], NULL);
91
92       len = MIN (strlen (child), strlen (prefix));
93       if (strncmp (child, prefix, len) != 0)
94         continue;
95
96       if (g_resource_get_info (resource, child, 0, &size, &flags, NULL))
97         {
98           if (details)
99             g_print ("%s%s%6"G_GSIZE_FORMAT " %s %s\n", section, section[0] ? " " : "", size, flags & G_RESOURCE_FLAGS_COMPRESSED ? "c" : "u", child);
100           else
101             g_print ("%s\n", child);
102         }
103       else
104         list_resource (resource, child, section, prefix, details);
105
106       g_free (child);
107     }
108   g_strfreev (children);
109 }
110
111 static void
112 extract_resource (GResource   *resource,
113                   const gchar *path)
114 {
115   GBytes *bytes;
116
117   bytes = g_resource_lookup_data (resource, path, 0, NULL);
118   if (bytes != NULL)
119     {
120       gconstpointer data;
121       gsize size, written;
122
123       data = g_bytes_get_data (bytes, &size);
124       written = fwrite (data, 1, size, stdout);
125       if (written < size)
126         g_printerr ("Data truncated\n");
127       g_bytes_unref (bytes);
128     }
129 }
130
131 /* Elf functions {{{1 */
132
133 #ifdef HAVE_LIBELF
134
135 static Elf *
136 get_elf (const gchar *file,
137          gint        *fd)
138 {
139   Elf *elf;
140
141   if (elf_version (EV_CURRENT) == EV_NONE )
142     return NULL;
143
144   *fd = g_open (file, O_RDONLY, 0);
145   if (*fd < 0)
146     return NULL;
147
148   elf = elf_begin (*fd, ELF_C_READ, NULL);
149   if (elf == NULL)
150     {
151       g_close (*fd, NULL);
152       *fd = -1;
153       return NULL;
154     }
155
156   if (elf_kind (elf) != ELF_K_ELF)
157     {
158       g_close (*fd, NULL);
159       *fd = -1;
160       return NULL;
161     }
162
163   return elf;
164 }
165
166 typedef gboolean (*SectionCallback) (GElf_Shdr   *shdr,
167                                      const gchar *name,
168                                      gpointer     data);
169
170 static void
171 elf_foreach_resource_section (Elf             *elf,
172                               SectionCallback  callback,
173                               gpointer         data)
174 {
175   size_t shstrndx, shnum;
176   size_t scnidx;
177   Elf_Scn *scn;
178   GElf_Shdr *shdr, shdr_mem;
179   const gchar *section_name;
180
181   elf_getshdrstrndx (elf, &shstrndx);
182   g_assert (shstrndx >= 0);
183
184   elf_getshdrnum (elf, &shnum);
185   g_assert (shnum >= 0);
186
187   for (scnidx = 1; scnidx < shnum; scnidx++)
188     {
189       scn = elf_getscn (elf, scnidx);
190       if (scn == NULL)
191         continue;
192
193       shdr = gelf_getshdr (scn, &shdr_mem);
194       if (shdr == NULL)
195         continue;
196
197       if (shdr->sh_type != SHT_PROGBITS)
198         continue;
199
200       section_name = elf_strptr (elf, shstrndx, shdr->sh_name);
201       if (section_name == NULL ||
202           !g_str_has_prefix (section_name, ".gresource."))
203         continue;
204
205       if (!callback (shdr, section_name + strlen (".gresource."), data))
206         break;
207     }
208 }
209
210 static GResource *
211 resource_from_section (GElf_Shdr *shdr,
212                        int        fd)
213 {
214   gsize page_size, page_offset;
215   char *contents;
216   GResource *resource;
217
218   resource = NULL;
219
220   page_size = sysconf(_SC_PAGE_SIZE);
221   page_offset = shdr->sh_offset % page_size;
222   contents = mmap (NULL,  shdr->sh_size + page_offset,
223                    PROT_READ, MAP_PRIVATE, fd, shdr->sh_offset - page_offset);
224   if (contents != MAP_FAILED)
225     {
226       GBytes *bytes;
227       GError *error = NULL;
228
229       bytes = g_bytes_new_static (contents + page_offset, shdr->sh_size);
230       resource = g_resource_new_from_data (bytes, &error);
231       g_bytes_unref (bytes);
232       if (error)
233         {
234           g_printerr ("%s\n", error->message);
235           g_error_free (error);
236         }
237     }
238   else
239     {
240       g_printerr ("Can't mmap resource section");
241     }
242
243   return resource;
244 }
245
246 typedef struct
247 {
248   int fd;
249   const gchar *section;
250   const gchar *path;
251   gboolean details;
252   gboolean found;
253 } CallbackData;
254
255 static gboolean
256 list_resources_cb (GElf_Shdr   *shdr,
257                    const gchar *section,
258                    gpointer     data)
259 {
260   CallbackData *d = data;
261   GResource *resource;
262
263   if (d->section && strcmp (section, d->section) != 0)
264     return TRUE;
265
266   d->found = TRUE;
267
268   resource = resource_from_section (shdr, d->fd);
269   list_resource (resource, "/",
270                  d->section ? "" : section,
271                  d->path,
272                  d->details);
273   g_resource_unref (resource);
274
275   if (d->section)
276     return FALSE;
277
278   return TRUE;
279 }
280
281 static void
282 elf_list_resources (Elf         *elf,
283                     int          fd,
284                     const gchar *section,
285                     const gchar *path,
286                     gboolean     details)
287 {
288   CallbackData data;
289
290   data.fd = fd;
291   data.section = section;
292   data.path = path;
293   data.details = details;
294   data.found = FALSE;
295
296   elf_foreach_resource_section (elf, list_resources_cb, &data);
297
298   if (!data.found)
299     g_printerr ("Can't find resource section %s\n", section);
300 }
301
302 static gboolean
303 extract_resource_cb (GElf_Shdr   *shdr,
304                      const gchar *section,
305                      gpointer     data)
306 {
307   CallbackData *d = data;
308   GResource *resource;
309
310   if (d->section && strcmp (section, d->section) != 0)
311     return TRUE;
312
313   d->found = TRUE;
314
315   resource = resource_from_section (shdr, d->fd);
316   extract_resource (resource, d->path);
317   g_resource_unref (resource);
318
319   if (d->section)
320     return FALSE;
321
322   return TRUE;
323 }
324
325 static void
326 elf_extract_resource (Elf         *elf,
327                       int          fd,
328                       const gchar *section,
329                       const gchar *path)
330 {
331   CallbackData data;
332
333   data.fd = fd;
334   data.section = section;
335   data.path = path;
336   data.found = FALSE;
337
338   elf_foreach_resource_section (elf, extract_resource_cb, &data);
339
340   if (!data.found)
341     g_printerr ("Can't find resource section %s\n", section);
342 }
343
344 static gboolean
345 print_section_name (GElf_Shdr   *shdr,
346                     const gchar *name,
347                     gpointer     data)
348 {
349   g_print ("%s\n", name);
350   return TRUE;
351 }
352
353 #endif /* HAVE_LIBELF */
354
355   /* Toplevel commands {{{1 */
356
357 static void
358 cmd_sections (const gchar *file,
359               const gchar *section,
360               const gchar *path,
361               gboolean     details)
362 {
363   GResource *resource;
364
365 #ifdef HAVE_LIBELF
366
367   Elf *elf;
368   gint fd;
369
370   if ((elf = get_elf (file, &fd)))
371     {
372       elf_foreach_resource_section (elf, print_section_name, NULL);
373       elf_end (elf);
374       close (fd);
375     }
376   else
377
378 #endif
379
380   if ((resource = get_resource (file)))
381     {
382       /* No sections */
383       g_resource_unref (resource);
384     }
385   else
386     {
387       g_printerr ("Don't know how to handle %s\n", file);
388 #ifndef HAVE_LIBELF
389       g_printerr ("gresource is built without elf support\n");
390 #endif
391     }
392 }
393
394 static void
395 cmd_list (const gchar *file,
396           const gchar *section,
397           const gchar *path,
398           gboolean     details)
399 {
400   GResource *resource;
401
402 #ifdef HAVE_LIBELF
403   Elf *elf;
404   int fd;
405
406   if ((elf = get_elf (file, &fd)))
407     {
408       elf_list_resources (elf, fd, section, path ? path : "", details);
409       elf_end (elf);
410       close (fd);
411     }
412   else
413
414 #endif
415
416   if ((resource = get_resource (file)))
417     {
418       list_resource (resource, "/", "", path ? path : "", details);
419       g_resource_unref (resource);
420     }
421   else
422     {
423       g_printerr ("Don't know how to handle %s\n", file);
424 #ifndef HAVE_LIBELF
425       g_printerr ("gresource is built without elf support\n");
426 #endif
427     }
428 }
429
430 static void
431 cmd_extract (const gchar *file,
432              const gchar *section,
433              const gchar *path,
434              gboolean     details)
435 {
436   GResource *resource;
437
438 #ifdef HAVE_LIBELF
439
440   Elf *elf;
441   int fd;
442
443   if ((elf = get_elf (file, &fd)))
444     {
445       elf_extract_resource (elf, fd, section, path);
446       elf_end (elf);
447       close (fd);
448     }
449   else
450
451 #endif
452
453   if ((resource = get_resource (file)))
454     {
455       extract_resource (resource, path);
456       g_resource_unref (resource);
457     }
458   else
459     {
460       g_printerr ("Don't know how to handle %s\n", file);
461 #ifndef HAVE_LIBELF
462       g_printerr ("gresource is built without elf support\n");
463 #endif
464     }
465 }
466
467 static gint
468 cmd_help (gboolean     requested,
469           const gchar *command)
470 {
471   const gchar *description;
472   const gchar *synopsis;
473   gchar *option;
474   GString *string;
475
476   option = NULL;
477
478   string = g_string_new (NULL);
479
480   if (command == NULL)
481     ;
482
483   else if (strcmp (command, "help") == 0)
484     {
485       description = _("Print help");
486       synopsis = _("[COMMAND]");
487     }
488
489   else if (strcmp (command, "sections") == 0)
490     {
491       description = _("List sections containing resources in an elf FILE");
492       synopsis = _("FILE");
493     }
494
495   else if (strcmp (command, "list") == 0)
496     {
497       description = _("List resources\n"
498                       "If SECTION is given, only list resources in this section\n"
499                       "If PATH is given, only list matching resources");
500       synopsis = _("FILE [PATH]");
501       option = g_strdup_printf ("[--section %s]", _("SECTION"));
502     }
503
504   else if (strcmp (command, "details") == 0)
505     {
506       description = _("List resources with details\n"
507                       "If SECTION is given, only list resources in this section\n"
508                       "If PATH is given, only list matching resources\n"
509                       "Details include the section, size and compression");
510       synopsis = _("FILE [PATH]");
511       option = g_strdup_printf ("[--section %s]", _("SECTION"));
512     }
513
514   else if (strcmp (command, "extract") == 0)
515     {
516       description = _("Extract a resource file to stdout");
517       synopsis = _("FILE PATH");
518       option = g_strdup_printf ("[--section %s]", _("SECTION"));
519     }
520
521   else
522     {
523       g_string_printf (string, _("Unknown command %s\n\n"), command);
524       requested = FALSE;
525       command = NULL;
526     }
527
528   if (command == NULL)
529     {
530       g_string_append (string,
531       _("Usage:\n"
532         "  gresource [--section SECTION] COMMAND [ARGS...]\n"
533         "\n"
534         "Commands:\n"
535         "  help                      Show this information\n"
536         "  sections                  List resource sections\n"
537         "  list                      List resources\n"
538         "  details                   List resources with details\n"
539         "  extract                   Extract a resource\n"
540         "\n"
541         "Use 'gresource help COMMAND' to get detailed help.\n\n"));
542     }
543   else
544     {
545       g_string_append_printf (string, _("Usage:\n  gresource %s%s%s %s\n\n%s\n\n"),
546                               option ? option : "", option ? " " : "", command, synopsis[0] ? synopsis : "", description);
547
548       g_string_append (string, _("Arguments:\n"));
549
550       if (option)
551         g_string_append (string,
552                          _("  SECTION   An (optional) elf section name\n"));
553
554       if (strstr (synopsis, _("[COMMAND]")))
555         g_string_append (string,
556                        _("  COMMAND   The (optional) command to explain\n"));
557
558       if (strstr (synopsis, _("FILE")))
559         {
560           if (strcmp (command, "sections") == 0)
561             g_string_append (string,
562                              _("  FILE      An elf file (a binary or a shared library)\n"));
563           else
564             g_string_append (string,
565                              _("  FILE      An elf file (a binary or a shared library)\n"
566                                "            or a compiled resource file\n"));
567         }
568
569       if (strstr (synopsis, _("[PATH]")))
570         g_string_append (string,
571                        _("  PATH      An (optional) resource path (may be partial)\n"));
572       else if (strstr (synopsis, _("PATH")))
573         g_string_append (string,
574                        _("  PATH      A resource path\n"));
575
576       g_string_append (string, "\n");
577     }
578
579   if (requested)
580     g_print ("%s", string->str);
581   else
582     g_printerr ("%s\n", string->str);
583
584   g_free (option);
585   g_string_free (string, TRUE);
586
587   return requested ? 0 : 1;
588 }
589
590 /* main {{{1 */
591
592 int
593 main (int argc, char *argv[])
594 {
595   gchar *section = NULL;
596   gboolean details = FALSE;
597   void (* function) (const gchar *, const gchar *, const gchar *, gboolean);
598
599 #ifdef G_OS_WIN32
600   gchar *tmp;
601 #endif
602
603   setlocale (LC_ALL, "");
604   textdomain (GETTEXT_PACKAGE);
605
606 #ifdef G_OS_WIN32
607   tmp = _glib_get_locale_dir ();
608   bindtextdomain (GETTEXT_PACKAGE, tmp);
609   g_free (tmp);
610 #else
611   bindtextdomain (GETTEXT_PACKAGE, GLIB_LOCALE_DIR);
612 #endif
613
614 #ifdef HAVE_BIND_TEXTDOMAIN_CODESET
615   bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
616 #endif
617
618   if (argc < 2)
619     return cmd_help (FALSE, NULL);
620
621   if (argc > 3 && strcmp (argv[1], "--section") == 0)
622     {
623       section = argv[2];
624       argv = argv + 2;
625       argc -= 2;
626     }
627
628   if (strcmp (argv[1], "help") == 0)
629     return cmd_help (TRUE, argv[2]);
630
631   else if (argc == 4 && strcmp (argv[1], "extract") == 0)
632     function = cmd_extract;
633
634   else if (argc == 3 && strcmp (argv[1], "sections") == 0)
635     function = cmd_sections;
636
637   else if ((argc == 3 || argc == 4) && strcmp (argv[1], "list") == 0)
638     {
639       function = cmd_list;
640       details = FALSE;
641     }
642   else if ((argc == 3 || argc == 4) && strcmp (argv[1], "details") == 0)
643     {
644       function = cmd_list;
645       details = TRUE;
646     }
647   else
648     return cmd_help (FALSE, argv[1]);
649
650   (* function) (argv[2], section, argc > 3 ? argv[3] : NULL, details);
651
652   return 0;
653 }
654
655 /* vim:set foldmethod=marker: */