nexmon – Blame information for rev 1

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