2 * Copyright © 2012 Red Hat, Inc
4 * SPDX-License-Identifier: LGPL-2.1-or-later
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
19 * Author: Matthias Clasen
27 #include <sys/types.h>
43 #include <glib/gstdio.h>
46 #include "glib/glib-private.h"
48 #if defined(HAVE_LIBELF) && defined(HAVE_MMAP)
52 /* GResource functions {{{1 */
54 get_resource (const gchar *file)
63 if (g_file_get_contents (file, &content, &size, NULL))
65 data = g_bytes_new_take (content, size);
66 resource = g_resource_new_from_data (data, NULL);
74 list_resource (GResource *resource,
88 children = g_resource_enumerate_children (resource, path, 0, &error);
91 g_printerr ("%s\n", error->message);
95 for (i = 0; children[i]; i++)
97 child = g_strconcat (path, children[i], NULL);
99 len = MIN (strlen (child), strlen (prefix));
100 if (strncmp (child, prefix, len) != 0)
106 if (g_resource_get_info (resource, child, 0, &size, &flags, NULL))
109 g_print ("%s%s%6"G_GSIZE_FORMAT " %s %s\n", section, section[0] ? " " : "", size, (flags & G_RESOURCE_FLAGS_COMPRESSED) ? "c" : "u", child);
111 g_print ("%s\n", child);
114 list_resource (resource, child, section, prefix, details);
118 g_strfreev (children);
122 extract_resource (GResource *resource,
127 bytes = g_resource_lookup_data (resource, path, 0, NULL);
133 data = g_bytes_get_data (bytes, &size);
134 written = fwrite (data, 1, size, stdout);
136 g_printerr ("Data truncated\n");
137 g_bytes_unref (bytes);
141 /* Elf functions {{{1 */
146 get_elf (const gchar *file,
151 if (elf_version (EV_CURRENT) == EV_NONE )
154 *fd = g_open (file, O_RDONLY, 0);
158 elf = elf_begin (*fd, ELF_C_READ, NULL);
166 if (elf_kind (elf) != ELF_K_ELF)
176 typedef gboolean (*SectionCallback) (GElf_Shdr *shdr,
181 elf_foreach_resource_section (Elf *elf,
182 SectionCallback callback,
185 int ret G_GNUC_UNUSED /* when compiling with G_DISABLE_ASSERT */;
186 size_t shstrndx, shnum;
189 GElf_Shdr *shdr, shdr_mem;
190 const gchar *section_name;
192 ret = elf_getshdrstrndx (elf, &shstrndx);
195 ret = elf_getshdrnum (elf, &shnum);
198 for (scnidx = 1; scnidx < shnum; scnidx++)
200 scn = elf_getscn (elf, scnidx);
204 shdr = gelf_getshdr (scn, &shdr_mem);
208 if (shdr->sh_type != SHT_PROGBITS)
211 section_name = elf_strptr (elf, shstrndx, shdr->sh_name);
212 if (section_name == NULL ||
213 !g_str_has_prefix (section_name, ".gresource."))
216 if (!callback (shdr, section_name + strlen (".gresource."), data))
222 resource_from_section (GElf_Shdr *shdr,
225 gsize page_size, page_offset;
231 page_size = sysconf(_SC_PAGE_SIZE);
232 page_offset = shdr->sh_offset % page_size;
233 contents = mmap (NULL, shdr->sh_size + page_offset,
234 PROT_READ, MAP_PRIVATE, fd, shdr->sh_offset - page_offset);
235 if (contents != MAP_FAILED)
238 GError *error = NULL;
240 bytes = g_bytes_new_static (contents + page_offset, shdr->sh_size);
241 resource = g_resource_new_from_data (bytes, &error);
242 g_bytes_unref (bytes);
245 g_printerr ("%s\n", error->message);
246 g_error_free (error);
251 g_printerr ("Can't mmap resource section");
260 const gchar *section;
267 list_resources_cb (GElf_Shdr *shdr,
268 const gchar *section,
271 CallbackData *d = data;
274 if (d->section && strcmp (section, d->section) != 0)
279 resource = resource_from_section (shdr, d->fd);
280 list_resource (resource, "/",
281 d->section ? "" : section,
284 g_resource_unref (resource);
293 elf_list_resources (Elf *elf,
295 const gchar *section,
302 data.section = section;
304 data.details = details;
307 elf_foreach_resource_section (elf, list_resources_cb, &data);
310 g_printerr ("Can't find resource section %s\n", section);
314 extract_resource_cb (GElf_Shdr *shdr,
315 const gchar *section,
318 CallbackData *d = data;
321 if (d->section && strcmp (section, d->section) != 0)
326 resource = resource_from_section (shdr, d->fd);
327 extract_resource (resource, d->path);
328 g_resource_unref (resource);
337 elf_extract_resource (Elf *elf,
339 const gchar *section,
345 data.section = section;
349 elf_foreach_resource_section (elf, extract_resource_cb, &data);
352 g_printerr ("Can't find resource section %s\n", section);
356 print_section_name (GElf_Shdr *shdr,
360 g_print ("%s\n", name);
364 #endif /* USE_LIBELF */
366 /* Toplevel commands {{{1 */
369 cmd_sections (const gchar *file,
370 const gchar *section,
381 if ((elf = get_elf (file, &fd)))
383 elf_foreach_resource_section (elf, print_section_name, NULL);
391 if ((resource = get_resource (file)))
394 g_resource_unref (resource);
398 g_printerr ("Don't know how to handle %s\n", file);
400 g_printerr ("gresource is built without elf support\n");
406 cmd_list (const gchar *file,
407 const gchar *section,
417 if ((elf = get_elf (file, &fd)))
419 elf_list_resources (elf, fd, section, path ? path : "", details);
427 if ((resource = get_resource (file)))
429 list_resource (resource, "/", "", path ? path : "", details);
430 g_resource_unref (resource);
434 g_printerr ("Don't know how to handle %s\n", file);
436 g_printerr ("gresource is built without elf support\n");
442 cmd_extract (const gchar *file,
443 const gchar *section,
454 if ((elf = get_elf (file, &fd)))
456 elf_extract_resource (elf, fd, section, path);
464 if ((resource = get_resource (file)))
466 extract_resource (resource, path);
467 g_resource_unref (resource);
471 g_printerr ("Don't know how to handle %s\n", file);
473 g_printerr ("gresource is built without elf support\n");
479 cmd_help (gboolean requested,
480 const gchar *command)
482 const gchar *description = NULL;
483 const gchar *synopsis = NULL;
489 string = g_string_new (NULL);
494 else if (strcmp (command, "help") == 0)
496 description = _("Print help");
497 synopsis = _("[COMMAND]");
500 else if (strcmp (command, "sections") == 0)
502 description = _("List sections containing resources in an elf FILE");
503 synopsis = _("FILE");
506 else if (strcmp (command, "list") == 0)
508 description = _("List resources\n"
509 "If SECTION is given, only list resources in this section\n"
510 "If PATH is given, only list matching resources");
511 synopsis = _("FILE [PATH]");
512 option = g_strdup_printf ("[--section %s]", _("SECTION"));
515 else if (strcmp (command, "details") == 0)
517 description = _("List resources with details\n"
518 "If SECTION is given, only list resources in this section\n"
519 "If PATH is given, only list matching resources\n"
520 "Details include the section, size and compression");
521 synopsis = _("FILE [PATH]");
522 option = g_strdup_printf ("[--section %s]", _("SECTION"));
525 else if (strcmp (command, "extract") == 0)
527 description = _("Extract a resource file to stdout");
528 synopsis = _("FILE PATH");
529 option = g_strdup_printf ("[--section %s]", _("SECTION"));
534 g_string_printf (string, _("Unknown command %s\n\n"), command);
541 g_string_append (string,
543 " gresource [--section SECTION] COMMAND [ARGS…]\n"
546 " help Show this information\n"
547 " sections List resource sections\n"
548 " list List resources\n"
549 " details List resources with details\n"
550 " extract Extract a resource\n"
552 "Use “gresource help COMMAND” to get detailed help.\n\n"));
556 g_string_append_printf (string, _("Usage:\n gresource %s%s%s %s\n\n%s\n\n"),
557 option ? option : "", option ? " " : "", command, synopsis[0] ? synopsis : "", description);
559 g_string_append (string, _("Arguments:\n"));
562 g_string_append (string,
563 _(" SECTION An (optional) elf section name\n"));
565 if (strstr (synopsis, _("[COMMAND]")))
566 g_string_append (string,
567 _(" COMMAND The (optional) command to explain\n"));
569 if (strstr (synopsis, _("FILE")))
571 if (strcmp (command, "sections") == 0)
572 g_string_append (string,
573 _(" FILE An elf file (a binary or a shared library)\n"));
575 g_string_append (string,
576 _(" FILE An elf file (a binary or a shared library)\n"
577 " or a compiled resource file\n"));
580 if (strstr (synopsis, _("[PATH]")))
581 g_string_append (string,
582 _(" PATH An (optional) resource path (may be partial)\n"));
583 else if (strstr (synopsis, _("PATH")))
584 g_string_append (string,
585 _(" PATH A resource path\n"));
587 g_string_append (string, "\n");
591 g_print ("%s", string->str);
593 g_printerr ("%s\n", string->str);
596 g_string_free (string, TRUE);
598 return requested ? 0 : 1;
604 main (int argc, char *argv[])
606 gchar *section = NULL;
607 gboolean details = FALSE;
608 void (* function) (const gchar *, const gchar *, const gchar *, gboolean);
614 setlocale (LC_ALL, GLIB_DEFAULT_LOCALE);
615 textdomain (GETTEXT_PACKAGE);
618 tmp = _glib_get_locale_dir ();
619 bindtextdomain (GETTEXT_PACKAGE, tmp);
622 bindtextdomain (GETTEXT_PACKAGE, GLIB_LOCALE_DIR);
625 #ifdef HAVE_BIND_TEXTDOMAIN_CODESET
626 bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
630 return cmd_help (FALSE, NULL);
632 if (argc > 3 && strcmp (argv[1], "--section") == 0)
639 if (strcmp (argv[1], "help") == 0)
640 return cmd_help (TRUE, argv[2]);
642 else if (argc == 4 && strcmp (argv[1], "extract") == 0)
643 function = cmd_extract;
645 else if (argc == 3 && strcmp (argv[1], "sections") == 0)
646 function = cmd_sections;
648 else if ((argc == 3 || argc == 4) && strcmp (argv[1], "list") == 0)
653 else if ((argc == 3 || argc == 4) && strcmp (argv[1], "details") == 0)
659 return cmd_help (FALSE, argv[1]);
661 (* function) (argv[2], section, argc > 3 ? argv[3] : NULL, details);
666 /* vim:set foldmethod=marker: */