/* ide-global.c * * Copyright 2014-2019 Christian Hergert * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later */ #define G_LOG_DOMAIN "ide-global" #include "config.h" #include #include #include #include #include #include #include #include "../../gconstructor.h" #include "ide-debug.h" #include "ide-global.h" #include "ide-macros.h" #include "ide-private.h" static GThread *main_thread; static const gchar *application_id = "org.gnome.Builder"; static IdeProcessKind kind = IDE_PROCESS_KIND_HOST; #if defined (G_HAS_CONSTRUCTORS) # ifdef G_DEFINE_CONSTRUCTOR_NEEDS_PRAGMA # pragma G_DEFINE_CONSTRUCTOR_PRAGMA_ARGS(ide_init_ctor) # endif G_DEFINE_CONSTRUCTOR(ide_init_ctor) #else # error Your platform/compiler is missing constructor support #endif static void ide_init_ctor (void) { main_thread = g_thread_self (); if (g_file_test ("/.flatpak-info", G_FILE_TEST_EXISTS)) kind = IDE_PROCESS_KIND_FLATPAK; } /** * ide_get_main_thread * * Gets #GThread of the main thread. * * Generally this is used by macros to determine what thread they code is * currently running within. * * Returns: (transfer none): a #GThread * * Since: 3.32 */ GThread * ide_get_main_thread (void) { return main_thread; } /** * ide_get_process_kind: * * Gets the kind of process we're running as. * * Returns: an #IdeProcessKind * * Since: 3.32 */ IdeProcessKind ide_get_process_kind (void) { return kind; } const gchar * ide_get_application_id (void) { return application_id; } /** * ide_set_application_id: * @app_id: the application id * * Sets the application id that will be used. * * This must be set at application startup before any GApplication * has connected to the D-Bus. * * The default is "org.gnome.Builder". * * Since: 3.32 */ void ide_set_application_id (const gchar *app_id) { g_return_if_fail (app_id != NULL); application_id = g_intern_string (app_id); } const gchar * ide_get_program_name (void) { return "gnome-builder"; } gchar * ide_create_host_triplet (const gchar *arch, const gchar *kernel, const gchar *system) { if (arch == NULL || kernel == NULL) return g_strdup (ide_get_system_type ()); else if (system == NULL) return g_strdup_printf ("%s-%s", arch, kernel); else return g_strdup_printf ("%s-%s-%s", arch, kernel, system); } const gchar * ide_get_system_type (void) { static gchar *system_type; g_autofree gchar *os_lower = NULL; const gchar *machine = NULL; struct utsname u; if (system_type != NULL) return system_type; if (uname (&u) < 0) return g_strdup ("unknown"); os_lower = g_utf8_strdown (u.sysname, -1); /* config.sub doesn't accept amd64-OS */ machine = strcmp (u.machine, "amd64") ? u.machine : "x86_64"; /* * TODO: Clearly we want to discover "gnu", but that should be just fine * for a default until we try to actually run on something non-gnu. * Which seems unlikely at the moment. If you run FreeBSD, you can * probably fix this for me :-) And while you're at it, make the * uname() call more portable. */ #ifdef __GLIBC__ system_type = g_strdup_printf ("%s-%s-%s", machine, os_lower, "gnu"); #else system_type = g_strdup_printf ("%s-%s", machine, os_lower); #endif return system_type; } gchar * ide_get_system_arch (void) { static GHashTable *remap; const char *machine; struct utsname u; if (uname (&u) < 0) return g_strdup ("unknown"); if (g_once_init_enter (&remap)) { GHashTable *mapping; mapping = g_hash_table_new (g_str_hash, g_str_equal); g_hash_table_insert (mapping, (gchar *)"amd64", (gchar *)"x86_64"); g_hash_table_insert (mapping, (gchar *)"armv7l", (gchar *)"aarch64"); g_hash_table_insert (mapping, (gchar *)"i686", (gchar *)"i386"); g_once_init_leave (&remap, mapping); } if (g_hash_table_lookup_extended (remap, u.machine, NULL, (gpointer *)&machine)) return g_strdup (machine); else return g_strdup (u.machine); } gsize ide_get_system_page_size (void) { return sysconf (_SC_PAGE_SIZE); } static gchar * get_base_path (const gchar *name) { g_autoptr(GKeyFile) keyfile = g_key_file_new (); if (g_key_file_load_from_file (keyfile, "/.flatpak-info", 0, NULL)) return g_key_file_get_string (keyfile, "Instance", name, NULL); return NULL; } /** * ide_get_relocatable_path: * @path: a relocatable path * * Gets the path to a resource that may be relocatable at runtime. * * Returns: (transfer full): a new string containing the path * * Since: 3.32 */ gchar * ide_get_relocatable_path (const gchar *path) { static gchar *base_path; if G_UNLIKELY (base_path == NULL) base_path = get_base_path ("app-path"); return g_build_filename (base_path, path, NULL); } const gchar * ide_gettext (const gchar *message) { if (message != NULL) return g_dgettext (GETTEXT_PACKAGE, message); return NULL; } static IdeTraceVTable trace_vtable; void _ide_trace_init (IdeTraceVTable *vtable) { trace_vtable = *vtable; if (trace_vtable.load) trace_vtable.load (); } void _ide_trace_shutdown (void) { if (trace_vtable.unload) trace_vtable.unload (); memset (&trace_vtable, 0, sizeof trace_vtable); } #ifdef IDE_ENABLE_TRACE void ide_trace_function (const gchar *strfunc, gint64 begin_time_usec, gint64 end_time_usec) { /* In case our clock is not reliable */ if (end_time_usec < begin_time_usec) end_time_usec = begin_time_usec; if (trace_vtable.function) trace_vtable.function (strfunc, begin_time_usec, end_time_usec); } #endif void _ide_trace_log (GLogLevelFlags log_level, const gchar *domain, const gchar *message) { if (trace_vtable.log) trace_vtable.log (log_level, domain, message); } static gchar ** get_environ_from_stdout (GSubprocess *subprocess) { g_autofree gchar *stdout_buf = NULL; if (g_subprocess_communicate_utf8 (subprocess, NULL, NULL, &stdout_buf, NULL, NULL)) { g_auto(GStrv) lines = g_strsplit (stdout_buf, "\n", 0); g_autoptr(GPtrArray) env = g_ptr_array_new_with_free_func (g_free); for (guint i = 0; lines[i]; i++) { const char *line = lines[i]; if (!g_ascii_isalpha (*line) && *line != '_') continue; for (const char *iter = line; *iter; iter = g_utf8_next_char (iter)) { if (*iter == '=') { g_ptr_array_add (env, g_strdup (line)); break; } if (!g_ascii_isalnum (*iter) && *iter != '_') break; } } if (env->len > 0) { g_ptr_array_add (env, NULL); return (gchar **)g_ptr_array_free (g_steal_pointer (&env), FALSE); } } return NULL; } const gchar * const * _ide_host_environ (void) { static gchar **host_environ; if (host_environ == NULL) { if (ide_is_flatpak ()) { g_autoptr(GSubprocessLauncher) launcher = NULL; g_autoptr(GSubprocess) subprocess = NULL; g_autoptr(GError) error = NULL; launcher = g_subprocess_launcher_new (G_SUBPROCESS_FLAGS_STDOUT_PIPE); subprocess = g_subprocess_launcher_spawn (launcher, &error, "flatpak-spawn", "--host", "printenv", NULL); if (subprocess != NULL) host_environ = get_environ_from_stdout (subprocess); } if (host_environ == NULL) host_environ = g_get_environ (); } return (const char * const *)host_environ; }