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>
45 #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 size_t shstrndx
, shnum
;
188 GElf_Shdr
*shdr
, shdr_mem
;
189 const gchar
*section_name
;
191 elf_getshdrstrndx (elf
, &shstrndx
);
192 g_assert (shstrndx
>= 0);
194 elf_getshdrnum (elf
, &shnum
);
195 g_assert (shnum
>= 0);
197 for (scnidx
= 1; scnidx
< shnum
; scnidx
++)
199 scn
= elf_getscn (elf
, scnidx
);
203 shdr
= gelf_getshdr (scn
, &shdr_mem
);
207 if (shdr
->sh_type
!= SHT_PROGBITS
)
210 section_name
= elf_strptr (elf
, shstrndx
, shdr
->sh_name
);
211 if (section_name
== NULL
||
212 !g_str_has_prefix (section_name
, ".gresource."))
215 if (!callback (shdr
, section_name
+ strlen (".gresource."), data
))
221 resource_from_section (GElf_Shdr
*shdr
,
224 gsize page_size
, page_offset
;
230 page_size
= sysconf(_SC_PAGE_SIZE
);
231 page_offset
= shdr
->sh_offset
% page_size
;
232 contents
= mmap (NULL
, shdr
->sh_size
+ page_offset
,
233 PROT_READ
, MAP_PRIVATE
, fd
, shdr
->sh_offset
- page_offset
);
234 if (contents
!= MAP_FAILED
)
237 GError
*error
= NULL
;
239 bytes
= g_bytes_new_static (contents
+ page_offset
, shdr
->sh_size
);
240 resource
= g_resource_new_from_data (bytes
, &error
);
241 g_bytes_unref (bytes
);
244 g_printerr ("%s\n", error
->message
);
245 g_error_free (error
);
250 g_printerr ("Can't mmap resource section");
259 const gchar
*section
;
266 list_resources_cb (GElf_Shdr
*shdr
,
267 const gchar
*section
,
270 CallbackData
*d
= data
;
273 if (d
->section
&& strcmp (section
, d
->section
) != 0)
278 resource
= resource_from_section (shdr
, d
->fd
);
279 list_resource (resource
, "/",
280 d
->section
? "" : section
,
283 g_resource_unref (resource
);
292 elf_list_resources (Elf
*elf
,
294 const gchar
*section
,
301 data
.section
= section
;
303 data
.details
= details
;
306 elf_foreach_resource_section (elf
, list_resources_cb
, &data
);
309 g_printerr ("Can't find resource section %s\n", section
);
313 extract_resource_cb (GElf_Shdr
*shdr
,
314 const gchar
*section
,
317 CallbackData
*d
= data
;
320 if (d
->section
&& strcmp (section
, d
->section
) != 0)
325 resource
= resource_from_section (shdr
, d
->fd
);
326 extract_resource (resource
, d
->path
);
327 g_resource_unref (resource
);
336 elf_extract_resource (Elf
*elf
,
338 const gchar
*section
,
344 data
.section
= section
;
348 elf_foreach_resource_section (elf
, extract_resource_cb
, &data
);
351 g_printerr ("Can't find resource section %s\n", section
);
355 print_section_name (GElf_Shdr
*shdr
,
359 g_print ("%s\n", name
);
363 #endif /* USE_LIBELF */
365 /* Toplevel commands {{{1 */
368 cmd_sections (const gchar
*file
,
369 const gchar
*section
,
380 if ((elf
= get_elf (file
, &fd
)))
382 elf_foreach_resource_section (elf
, print_section_name
, NULL
);
390 if ((resource
= get_resource (file
)))
393 g_resource_unref (resource
);
397 g_printerr ("Don't know how to handle %s\n", file
);
399 g_printerr ("gresource is built without elf support\n");
405 cmd_list (const gchar
*file
,
406 const gchar
*section
,
416 if ((elf
= get_elf (file
, &fd
)))
418 elf_list_resources (elf
, fd
, section
, path
? path
: "", details
);
426 if ((resource
= get_resource (file
)))
428 list_resource (resource
, "/", "", path
? path
: "", details
);
429 g_resource_unref (resource
);
433 g_printerr ("Don't know how to handle %s\n", file
);
435 g_printerr ("gresource is built without elf support\n");
441 cmd_extract (const gchar
*file
,
442 const gchar
*section
,
453 if ((elf
= get_elf (file
, &fd
)))
455 elf_extract_resource (elf
, fd
, section
, path
);
463 if ((resource
= get_resource (file
)))
465 extract_resource (resource
, path
);
466 g_resource_unref (resource
);
470 g_printerr ("Don't know how to handle %s\n", file
);
472 g_printerr ("gresource is built without elf support\n");
478 cmd_help (gboolean requested
,
479 const gchar
*command
)
481 const gchar
*description
;
482 const gchar
*synopsis
;
488 string
= g_string_new (NULL
);
493 else if (strcmp (command
, "help") == 0)
495 description
= _("Print help");
496 synopsis
= _("[COMMAND]");
499 else if (strcmp (command
, "sections") == 0)
501 description
= _("List sections containing resources in an elf FILE");
502 synopsis
= _("FILE");
505 else if (strcmp (command
, "list") == 0)
507 description
= _("List resources\n"
508 "If SECTION is given, only list resources in this section\n"
509 "If PATH is given, only list matching resources");
510 synopsis
= _("FILE [PATH]");
511 option
= g_strdup_printf ("[--section %s]", _("SECTION"));
514 else if (strcmp (command
, "details") == 0)
516 description
= _("List resources with details\n"
517 "If SECTION is given, only list resources in this section\n"
518 "If PATH is given, only list matching resources\n"
519 "Details include the section, size and compression");
520 synopsis
= _("FILE [PATH]");
521 option
= g_strdup_printf ("[--section %s]", _("SECTION"));
524 else if (strcmp (command
, "extract") == 0)
526 description
= _("Extract a resource file to stdout");
527 synopsis
= _("FILE PATH");
528 option
= g_strdup_printf ("[--section %s]", _("SECTION"));
533 g_string_printf (string
, _("Unknown command %s\n\n"), command
);
540 g_string_append (string
,
542 " gresource [--section SECTION] COMMAND [ARGS…]\n"
545 " help Show this information\n"
546 " sections List resource sections\n"
547 " list List resources\n"
548 " details List resources with details\n"
549 " extract Extract a resource\n"
551 "Use “gresource help COMMAND” to get detailed help.\n\n"));
555 g_string_append_printf (string
, _("Usage:\n gresource %s%s%s %s\n\n%s\n\n"),
556 option
? option
: "", option
? " " : "", command
, synopsis
[0] ? synopsis
: "", description
);
558 g_string_append (string
, _("Arguments:\n"));
561 g_string_append (string
,
562 _(" SECTION An (optional) elf section name\n"));
564 if (strstr (synopsis
, _("[COMMAND]")))
565 g_string_append (string
,
566 _(" COMMAND The (optional) command to explain\n"));
568 if (strstr (synopsis
, _("FILE")))
570 if (strcmp (command
, "sections") == 0)
571 g_string_append (string
,
572 _(" FILE An elf file (a binary or a shared library)\n"));
574 g_string_append (string
,
575 _(" FILE An elf file (a binary or a shared library)\n"
576 " or a compiled resource file\n"));
579 if (strstr (synopsis
, _("[PATH]")))
580 g_string_append (string
,
581 _(" PATH An (optional) resource path (may be partial)\n"));
582 else if (strstr (synopsis
, _("PATH")))
583 g_string_append (string
,
584 _(" PATH A resource path\n"));
586 g_string_append (string
, "\n");
590 g_print ("%s", string
->str
);
592 g_printerr ("%s\n", string
->str
);
595 g_string_free (string
, TRUE
);
597 return requested
? 0 : 1;
603 main (int argc
, char *argv
[])
605 gchar
*section
= NULL
;
606 gboolean details
= FALSE
;
607 void (* function
) (const gchar
*, const gchar
*, const gchar
*, gboolean
);
613 setlocale (LC_ALL
, "");
614 textdomain (GETTEXT_PACKAGE
);
617 tmp
= _glib_get_locale_dir ();
618 bindtextdomain (GETTEXT_PACKAGE
, tmp
);
621 bindtextdomain (GETTEXT_PACKAGE
, GLIB_LOCALE_DIR
);
624 #ifdef HAVE_BIND_TEXTDOMAIN_CODESET
625 bind_textdomain_codeset (GETTEXT_PACKAGE
, "UTF-8");
629 return cmd_help (FALSE
, NULL
);
631 if (argc
> 3 && strcmp (argv
[1], "--section") == 0)
638 if (strcmp (argv
[1], "help") == 0)
639 return cmd_help (TRUE
, argv
[2]);
641 else if (argc
== 4 && strcmp (argv
[1], "extract") == 0)
642 function
= cmd_extract
;
644 else if (argc
== 3 && strcmp (argv
[1], "sections") == 0)
645 function
= cmd_sections
;
647 else if ((argc
== 3 || argc
== 4) && strcmp (argv
[1], "list") == 0)
652 else if ((argc
== 3 || argc
== 4) && strcmp (argv
[1], "details") == 0)
658 return cmd_help (FALSE
, argv
[1]);
660 (* function
) (argv
[2], section
, argc
> 3 ? argv
[3] : NULL
, details
);
665 /* vim:set foldmethod=marker: */