2 * Copyright © 2012 Red Hat, Inc
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.1 of the License, or (at your option) any later version.
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.
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/>.
17 * Author: Matthias Clasen
25 #include <sys/types.h>
41 #include <glib/gstdio.h>
44 #include "glib/glib-private.h"
46 #if defined(HAVE_LIBELF) && defined(HAVE_MMAP)
50 /* GResource functions {{{1 */
52 get_resource (const gchar *file)
61 if (g_file_get_contents (file, &content, &size, NULL))
63 data = g_bytes_new_take (content, size);
64 resource = g_resource_new_from_data (data, NULL);
72 list_resource (GResource *resource,
86 children = g_resource_enumerate_children (resource, path, 0, &error);
89 g_printerr ("%s\n", error->message);
93 for (i = 0; children[i]; i++)
95 child = g_strconcat (path, children[i], NULL);
97 len = MIN (strlen (child), strlen (prefix));
98 if (strncmp (child, prefix, len) != 0)
104 if (g_resource_get_info (resource, child, 0, &size, &flags, NULL))
107 g_print ("%s%s%6"G_GSIZE_FORMAT " %s %s\n", section, section[0] ? " " : "", size, (flags & G_RESOURCE_FLAGS_COMPRESSED) ? "c" : "u", child);
109 g_print ("%s\n", child);
112 list_resource (resource, child, section, prefix, details);
116 g_strfreev (children);
120 extract_resource (GResource *resource,
125 bytes = g_resource_lookup_data (resource, path, 0, NULL);
131 data = g_bytes_get_data (bytes, &size);
132 written = fwrite (data, 1, size, stdout);
134 g_printerr ("Data truncated\n");
135 g_bytes_unref (bytes);
139 /* Elf functions {{{1 */
144 get_elf (const gchar *file,
149 if (elf_version (EV_CURRENT) == EV_NONE )
152 *fd = g_open (file, O_RDONLY, 0);
156 elf = elf_begin (*fd, ELF_C_READ, NULL);
164 if (elf_kind (elf) != ELF_K_ELF)
174 typedef gboolean (*SectionCallback) (GElf_Shdr *shdr,
179 elf_foreach_resource_section (Elf *elf,
180 SectionCallback callback,
183 size_t shstrndx, shnum;
186 GElf_Shdr *shdr, shdr_mem;
187 const gchar *section_name;
189 elf_getshdrstrndx (elf, &shstrndx);
190 g_assert (shstrndx >= 0);
192 elf_getshdrnum (elf, &shnum);
193 g_assert (shnum >= 0);
195 for (scnidx = 1; scnidx < shnum; scnidx++)
197 scn = elf_getscn (elf, scnidx);
201 shdr = gelf_getshdr (scn, &shdr_mem);
205 if (shdr->sh_type != SHT_PROGBITS)
208 section_name = elf_strptr (elf, shstrndx, shdr->sh_name);
209 if (section_name == NULL ||
210 !g_str_has_prefix (section_name, ".gresource."))
213 if (!callback (shdr, section_name + strlen (".gresource."), data))
219 resource_from_section (GElf_Shdr *shdr,
222 gsize page_size, page_offset;
228 page_size = sysconf(_SC_PAGE_SIZE);
229 page_offset = shdr->sh_offset % page_size;
230 contents = mmap (NULL, shdr->sh_size + page_offset,
231 PROT_READ, MAP_PRIVATE, fd, shdr->sh_offset - page_offset);
232 if (contents != MAP_FAILED)
235 GError *error = NULL;
237 bytes = g_bytes_new_static (contents + page_offset, shdr->sh_size);
238 resource = g_resource_new_from_data (bytes, &error);
239 g_bytes_unref (bytes);
242 g_printerr ("%s\n", error->message);
243 g_error_free (error);
248 g_printerr ("Can't mmap resource section");
257 const gchar *section;
264 list_resources_cb (GElf_Shdr *shdr,
265 const gchar *section,
268 CallbackData *d = data;
271 if (d->section && strcmp (section, d->section) != 0)
276 resource = resource_from_section (shdr, d->fd);
277 list_resource (resource, "/",
278 d->section ? "" : section,
281 g_resource_unref (resource);
290 elf_list_resources (Elf *elf,
292 const gchar *section,
299 data.section = section;
301 data.details = details;
304 elf_foreach_resource_section (elf, list_resources_cb, &data);
307 g_printerr ("Can't find resource section %s\n", section);
311 extract_resource_cb (GElf_Shdr *shdr,
312 const gchar *section,
315 CallbackData *d = data;
318 if (d->section && strcmp (section, d->section) != 0)
323 resource = resource_from_section (shdr, d->fd);
324 extract_resource (resource, d->path);
325 g_resource_unref (resource);
334 elf_extract_resource (Elf *elf,
336 const gchar *section,
342 data.section = section;
346 elf_foreach_resource_section (elf, extract_resource_cb, &data);
349 g_printerr ("Can't find resource section %s\n", section);
353 print_section_name (GElf_Shdr *shdr,
357 g_print ("%s\n", name);
361 #endif /* USE_LIBELF */
363 /* Toplevel commands {{{1 */
366 cmd_sections (const gchar *file,
367 const gchar *section,
378 if ((elf = get_elf (file, &fd)))
380 elf_foreach_resource_section (elf, print_section_name, NULL);
388 if ((resource = get_resource (file)))
391 g_resource_unref (resource);
395 g_printerr ("Don't know how to handle %s\n", file);
397 g_printerr ("gresource is built without elf support\n");
403 cmd_list (const gchar *file,
404 const gchar *section,
414 if ((elf = get_elf (file, &fd)))
416 elf_list_resources (elf, fd, section, path ? path : "", details);
424 if ((resource = get_resource (file)))
426 list_resource (resource, "/", "", path ? path : "", details);
427 g_resource_unref (resource);
431 g_printerr ("Don't know how to handle %s\n", file);
433 g_printerr ("gresource is built without elf support\n");
439 cmd_extract (const gchar *file,
440 const gchar *section,
451 if ((elf = get_elf (file, &fd)))
453 elf_extract_resource (elf, fd, section, path);
461 if ((resource = get_resource (file)))
463 extract_resource (resource, path);
464 g_resource_unref (resource);
468 g_printerr ("Don't know how to handle %s\n", file);
470 g_printerr ("gresource is built without elf support\n");
476 cmd_help (gboolean requested,
477 const gchar *command)
479 const gchar *description;
480 const gchar *synopsis;
486 string = g_string_new (NULL);
491 else if (strcmp (command, "help") == 0)
493 description = _("Print help");
494 synopsis = _("[COMMAND]");
497 else if (strcmp (command, "sections") == 0)
499 description = _("List sections containing resources in an elf FILE");
500 synopsis = _("FILE");
503 else if (strcmp (command, "list") == 0)
505 description = _("List resources\n"
506 "If SECTION is given, only list resources in this section\n"
507 "If PATH is given, only list matching resources");
508 synopsis = _("FILE [PATH]");
509 option = g_strdup_printf ("[--section %s]", _("SECTION"));
512 else if (strcmp (command, "details") == 0)
514 description = _("List resources with details\n"
515 "If SECTION is given, only list resources in this section\n"
516 "If PATH is given, only list matching resources\n"
517 "Details include the section, size and compression");
518 synopsis = _("FILE [PATH]");
519 option = g_strdup_printf ("[--section %s]", _("SECTION"));
522 else if (strcmp (command, "extract") == 0)
524 description = _("Extract a resource file to stdout");
525 synopsis = _("FILE PATH");
526 option = g_strdup_printf ("[--section %s]", _("SECTION"));
531 g_string_printf (string, _("Unknown command %s\n\n"), command);
538 g_string_append (string,
540 " gresource [--section SECTION] COMMAND [ARGS…]\n"
543 " help Show this information\n"
544 " sections List resource sections\n"
545 " list List resources\n"
546 " details List resources with details\n"
547 " extract Extract a resource\n"
549 "Use “gresource help COMMAND” to get detailed help.\n\n"));
553 g_string_append_printf (string, _("Usage:\n gresource %s%s%s %s\n\n%s\n\n"),
554 option ? option : "", option ? " " : "", command, synopsis[0] ? synopsis : "", description);
556 g_string_append (string, _("Arguments:\n"));
559 g_string_append (string,
560 _(" SECTION An (optional) elf section name\n"));
562 if (strstr (synopsis, _("[COMMAND]")))
563 g_string_append (string,
564 _(" COMMAND The (optional) command to explain\n"));
566 if (strstr (synopsis, _("FILE")))
568 if (strcmp (command, "sections") == 0)
569 g_string_append (string,
570 _(" FILE An elf file (a binary or a shared library)\n"));
572 g_string_append (string,
573 _(" FILE An elf file (a binary or a shared library)\n"
574 " or a compiled resource file\n"));
577 if (strstr (synopsis, _("[PATH]")))
578 g_string_append (string,
579 _(" PATH An (optional) resource path (may be partial)\n"));
580 else if (strstr (synopsis, _("PATH")))
581 g_string_append (string,
582 _(" PATH A resource path\n"));
584 g_string_append (string, "\n");
588 g_print ("%s", string->str);
590 g_printerr ("%s\n", string->str);
593 g_string_free (string, TRUE);
595 return requested ? 0 : 1;
601 main (int argc, char *argv[])
603 gchar *section = NULL;
604 gboolean details = FALSE;
605 void (* function) (const gchar *, const gchar *, const gchar *, gboolean);
611 setlocale (LC_ALL, GLIB_DEFAULT_LOCALE);
612 textdomain (GETTEXT_PACKAGE);
615 tmp = _glib_get_locale_dir ();
616 bindtextdomain (GETTEXT_PACKAGE, tmp);
619 bindtextdomain (GETTEXT_PACKAGE, GLIB_LOCALE_DIR);
622 #ifdef HAVE_BIND_TEXTDOMAIN_CODESET
623 bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
627 return cmd_help (FALSE, NULL);
629 if (argc > 3 && strcmp (argv[1], "--section") == 0)
636 if (strcmp (argv[1], "help") == 0)
637 return cmd_help (TRUE, argv[2]);
639 else if (argc == 4 && strcmp (argv[1], "extract") == 0)
640 function = cmd_extract;
642 else if (argc == 3 && strcmp (argv[1], "sections") == 0)
643 function = cmd_sections;
645 else if ((argc == 3 || argc == 4) && strcmp (argv[1], "list") == 0)
650 else if ((argc == 3 || argc == 4) && strcmp (argv[1], "details") == 0)
656 return cmd_help (FALSE, argv[1]);
658 (* function) (argv[2], section, argc > 3 ? argv[3] : NULL, details);
663 /* vim:set foldmethod=marker: */