Revert "FIXME: this can be rather slow and blocks until the size is known"
[geeqie.git] / src / main.cc
index a8b7635..7f41329 100644 (file)
 #include <clutter-gtk/clutter-gtk.h>
 #endif
 
+#ifdef HAVE_EXECINFO_H
+#include <execinfo.h>
+#endif
+
 gboolean thumb_format_changed = FALSE;
 static RemoteConnection *remote_connection = NULL;
 
@@ -71,6 +75,128 @@ gchar *gq_executable_path;
 gchar *desktop_file_template;
 gchar *instance_identifier;
 
+#if defined(SA_SIGINFO)
+void sig_handler_cb(int signo, siginfo_t *info, void *UNUSED(context))
+{
+       gchar hex_char[16];
+       const gchar *signal_name = NULL;
+       gint i = 0;
+       guint64 addr;
+       guint64 char_index;
+       ssize_t len;
+#ifdef HAVE_EXECINFO_H
+       gint bt_size;
+       void *bt[1024];
+#endif
+       struct signals
+               {
+               gint sig_no;
+               const gchar *sig_name;
+               };
+       struct signals signals_list[7];
+
+       signals_list[0].sig_no = SIGABRT;
+       signals_list[0].sig_name = "Abort";
+       signals_list[1].sig_no = SIGBUS;
+       signals_list[1].sig_name = "Bus error";
+       signals_list[2].sig_no = SIGFPE;
+       signals_list[2].sig_name = "Floating-point exception";
+       signals_list[3].sig_no = SIGILL;
+       signals_list[3].sig_name = "Illegal instruction";
+       signals_list[4].sig_no = SIGIOT;
+       signals_list[4].sig_name = "IOT trap";
+       signals_list[5].sig_no = SIGSEGV;
+       signals_list[5].sig_name = "Invalid memory reference";
+       signals_list[6].sig_no = -1;
+       signals_list[6].sig_name = "END";
+
+       hex_char[0] = '0';
+       hex_char[1] = '1';
+       hex_char[2] = '2';
+       hex_char[3] = '3';
+       hex_char[4] = '4';
+       hex_char[5] = '5';
+       hex_char[6] = '6';
+       hex_char[7] = '7';
+       hex_char[8] = '8';
+       hex_char[9] = '9';
+       hex_char[10] = 'a';
+       hex_char[11] = 'b';
+       hex_char[12] = 'c';
+       hex_char[13] = 'd';
+       hex_char[14] = 'e';
+       hex_char[15] = 'f';
+
+       signal_name = "Unknown signal";
+       while (signals_list[i].sig_no != -1)
+               {
+               if (signo == signals_list[i].sig_no)
+                       {
+                       signal_name = signals_list[i].sig_name;
+                       break;
+                       }
+               i++;
+               }
+
+       len = write(STDERR_FILENO, "Geeqie fatal error\n", 19);
+       len = write(STDERR_FILENO, "Signal: ", 8);
+       len = write(STDERR_FILENO, signal_name, strlen(signal_name));
+       len = write(STDERR_FILENO, "\n", 1);
+
+       len = write(STDERR_FILENO, "Code: ", 6);
+       len = write(STDERR_FILENO,  (info->si_code == SEGV_MAPERR) ? "Address not mapped" : "Invalid permissions", strlen((info->si_code == SEGV_MAPERR) ? "Address not mapped" : "Invalid permissions"));
+       len = write(STDERR_FILENO, "\n", 1);
+
+       len = write(STDERR_FILENO, "Address: ", 9);
+
+       if (info->si_addr == 0)
+               {
+               len = write(STDERR_FILENO, "0x0\n", 4);
+               }
+       else
+               {
+               /* Assume the address is 64-bit */
+               len = write(STDERR_FILENO, "0x", 2);
+               addr = reinterpret_cast<guint64>(info->si_addr);
+
+               for (i = 0; i < 16; i++)
+                       {
+                       char_index = addr & 0xf000000000000000;
+                       char_index = char_index >> 60;
+                       addr = addr << 4;
+
+                       len = write(STDERR_FILENO, &hex_char[char_index], 1);
+                       }
+               len = write(STDERR_FILENO, "\n", 1);
+               }
+
+#ifdef HAVE_EXECINFO_H
+       bt_size = backtrace(bt, 1024);
+       backtrace_symbols_fd(bt, bt_size, STDERR_FILENO);
+#endif
+
+       exit(EXIT_FAILURE);
+}
+#else /* defined(SA_SIGINFO) */
+void sig_handler_cb(int UNUSED(signo))
+{
+#ifdef HAVE_EXECINFO_H
+       gint bt_size;
+       void *bt[1024];
+#endif
+
+       write(STDERR_FILENO, "Geeqie fatal error\n", 19);
+       write(STDERR_FILENO, "Signal: Segmentation fault\n", 27);
+
+#ifdef HAVE_EXECINFO_H
+       bt_size = backtrace(bt, 1024);
+       backtrace_symbols_fd(bt, bt_size, STDERR_FILENO);
+#endif
+
+       exit(EXIT_FAILURE);
+}
+#endif /* defined(SA_SIGINFO) */
+
 /*
  *-----------------------------------------------------------------------------
  * keyboard functions
@@ -169,7 +295,7 @@ static void parse_command_line_add_dir(const gchar *dir, gchar **UNUSED(path), g
                work = files;
                while (work)
                        {
-                       FileData *fd = work->data;
+                       FileData *fd = static_cast<FileData *>(work->data);
                        if (!*path) *path = remove_level_from_path(fd->path);
                        if (!*file) *file = g_strdup(fd->path);
                        *list = g_list_prepend(*list, fd);
@@ -293,14 +419,14 @@ static void parse_command_line(gint argc, gchar *argv[])
                                {
                                command_line->tools_show = TRUE;
 
-                               remote_list = g_list_append(remote_list, "+t");
+                               remote_list = g_list_append(remote_list, g_strdup("+t"));
                                }
                        else if (strcmp(cmd_line, "-t") == 0 ||
                                 strcmp(cmd_line, "--without-tools") == 0)
                                {
                                command_line->tools_hide = TRUE;
 
-                               remote_list = g_list_append(remote_list, "-t");
+                               remote_list = g_list_append(remote_list, g_strdup("-t"));
                                }
                        else if (strcmp(cmd_line, "-f") == 0 ||
                                 strcmp(cmd_line, "--fullscreen") == 0)
@@ -474,7 +600,7 @@ static void parse_command_line(gint argc, gchar *argv[])
                                geometry = g_strdup_printf("--geometry=%s", command_line->geometry);
                                remote_list = g_list_prepend(remote_list, geometry);
                                }
-                       remote_list = g_list_prepend(remote_list, "--new-window");
+                       remote_list = g_list_prepend(remote_list, g_strdup("--new-window"));
                        }
                g_free(app_lock);
                }
@@ -487,7 +613,7 @@ static void parse_command_line(gint argc, gchar *argv[])
 
                        while (work)
                                {
-                               gchar *opt = work->data;
+                               gchar *opt = static_cast<gchar *>(work->data);
 
                                command_line_errors = g_string_append(command_line_errors, opt);
                                command_line_errors = g_string_append(command_line_errors, "\n");
@@ -770,7 +896,7 @@ static void gq_accel_map_print(
                    gboolean    changed)
 {
        GString *gstring = g_string_new(changed ? NULL : "; ");
-       SecureSaveInfo *ssi = data;
+       SecureSaveInfo *ssi = static_cast<SecureSaveInfo *>(data);
        gchar *tmp, *name;
 
        g_string_append(gstring, "(gtk_accel_path \"");
@@ -894,10 +1020,10 @@ static void exit_program_final(void)
                list = layout_window_list;
                while (list)
                        {
-                       tmp_lw = list->data;
+                       tmp_lw = static_cast<LayoutWindow *>(list->data);
                        if (!g_str_has_prefix(tmp_lw->options.id, "lw"))
                                {
-                               save_layout(list->data);
+                               save_layout(static_cast<_LayoutWindow *>(list->data));
                                }
                        list = list->next;
                        }
@@ -1008,35 +1134,59 @@ void exit_program(void)
        exit_program_final();
 }
 
-/* This code is supposed to handle situation when a file mmaped by image_loader
+/* This code attempts to handle situation when a file mmaped by image_loader
  * or by exif loader is truncated by some other process.
- * This is probably not completely correct according to posix, because
- * mmap is not in the list of calls that can be used safely in signal handler,
- * but anyway, the handler is called in situation when the application would
- * crash otherwise.
- * Ideas for improvement are welcome ;)
+ * This code is incorrect according to POSIX, because:
+ *
+ *   mmap is not async-signal-safe and thus may not be called from a signal handler
+ * 
+ *   mmap must be called with a valid file descriptor.  POSIX requires that
+ *   a fildes argument of -1 must cause mmap to return EBADF.
+ *
+ * See https://github.com/BestImageViewer/geeqie/issues/1052 for discussion of
+ * an alternative approach.
  */
 /** @FIXME this probably needs some better ifdefs. Please report any compilation problems */
 
 #if defined(SIGBUS) && defined(SA_SIGINFO)
 static void sigbus_handler_cb(int UNUSED(signum), siginfo_t *info, void *UNUSED(context))
 {
-       unsigned long pagesize = sysconf(_SC_PAGE_SIZE);
-       DEBUG_1("SIGBUS %p", info->si_addr);
-       mmap((void *)(((unsigned long)info->si_addr / pagesize) * pagesize), pagesize, PROT_READ | PROT_WRITE, MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+       /*
+        * @FIXME Design and implement a POSIX-acceptable approach,
+        * after first documenting the sitations where SIGBUS occurs.
+        * See https://github.com/BestImageViewer/geeqie/issues/1052 for discussion
+        */
+
+       DEBUG_1("SIGBUS %p NOT HANDLED", info->si_addr);
+       exit(EXIT_FAILURE);
 }
 #endif
 
-static void setup_sigbus_handler(void)
-{
-#if defined(SIGBUS) && defined(SA_SIGINFO)
-       struct sigaction sigbus_action;
-       sigfillset(&sigbus_action.sa_mask);
-       sigbus_action.sa_sigaction = sigbus_handler_cb;
-       sigbus_action.sa_flags = SA_SIGINFO;
+//static void setup_sigbus_handler(void)
+//{
+//#if defined(SIGBUS) && defined(SA_SIGINFO)
+       //struct sigaction sigbus_action;
+       //sigfillset(&sigbus_action.sa_mask);
+       //sigbus_action.sa_sigaction = sigbus_handler_cb;
+       //sigbus_action.sa_flags = SA_SIGINFO;
 
-       sigaction(SIGBUS, &sigbus_action, NULL);
-#endif
+       //sigaction(SIGBUS, &sigbus_action, NULL);
+//#endif
+//}
+
+static void setup_sig_handler(void)
+{
+       struct sigaction sigsegv_action;
+       sigfillset(&sigsegv_action.sa_mask);
+       sigsegv_action.sa_sigaction = sig_handler_cb;
+       sigsegv_action.sa_flags = SA_SIGINFO;
+
+       sigaction(SIGABRT, &sigsegv_action, NULL);
+       sigaction(SIGBUS, &sigsegv_action, NULL);
+       sigaction(SIGFPE, &sigsegv_action, NULL);
+       sigaction(SIGILL, &sigsegv_action, NULL);
+       sigaction(SIGIOT, &sigsegv_action, NULL);
+       sigaction(SIGSEGV, &sigsegv_action, NULL);
 }
 
 static void set_theme_bg_color()
@@ -1050,7 +1200,7 @@ static void set_theme_bg_color()
        if (!options->image.use_custom_border_color)
                {
                work = layout_window_list;
-               lw = work->data;
+               lw = static_cast<LayoutWindow *>(work->data);
 
                style_context = gtk_widget_get_style_context(lw->window);
                gtk_style_context_get_background_color(style_context, GTK_STATE_FLAG_NORMAL, &bg_color);
@@ -1061,7 +1211,7 @@ static void set_theme_bg_color()
 
                while (work)
                        {
-                       lw = work->data;
+                       lw = static_cast<LayoutWindow *>(work->data);
                        image_background_set_color(lw->image, &theme_color);
                        work = work->next;
                        }
@@ -1112,39 +1262,6 @@ static void create_application_paths()
        g_free(path);
 }
 
-gboolean stderr_channel_cb(GIOChannel *source, GIOCondition UNUSED(condition), gpointer UNUSED(data))
-{
-       static GString *message_str = NULL;
-       gchar buf[10] = {0};
-       gsize count;
-
-       if (!message_str)
-               {
-               message_str = g_string_new(NULL);
-               }
-
-       g_io_channel_read_chars(source, buf, 1, &count, NULL);
-
-       if (count > 0)
-               {
-               if (buf[0] == '\n')
-                       {
-                       log_printf("%s", message_str->str);
-                       g_string_free(message_str, TRUE);
-                       message_str = NULL;
-                       }
-               else
-                       {
-                       message_str = g_string_append_c(message_str, buf[0]);
-                       }
-               return TRUE;
-               }
-       else
-               {
-               return FALSE;
-               }
-}
-
 gint main(gint argc, gchar *argv[])
 {
        CollectionData *first_collection = NULL;
@@ -1154,14 +1271,19 @@ gint main(gint argc, gchar *argv[])
        gboolean single_dir = TRUE;
        LayoutWindow *lw;
        GtkSettings *default_settings;
-       gint fd_stderr[2];
-       GIOChannel *stderr_channel;
 
        gdk_set_allowed_backends("x11,*");
 
        gdk_threads_init();
        gdk_threads_enter();
 
+       /* seg. fault handler */
+#ifdef HAVE_DEVELOPER
+       backward::SignalHandling sh{};
+#else
+       setup_sig_handler();
+#endif
+
        /* init execution time counter (debug only) */
        init_exec_time();
 
@@ -1176,17 +1298,6 @@ gint main(gint argc, gchar *argv[])
        textdomain(PACKAGE);
 #endif
 
-       /* Tee stderr to log window */
-       if (pipe(fd_stderr) == 0)
-               {
-               if (dup2(fd_stderr[1], fileno(stderr)) != -1)
-                       {
-                       close(fd_stderr[1]);
-                       stderr_channel = g_io_channel_unix_new(fd_stderr[0]);
-                       g_io_add_watch(stderr_channel, G_IO_IN, (GIOFunc)stderr_channel_cb, NULL);
-                       }
-               }
-
        exif_init();
 
 #ifdef HAVE_LUA
@@ -1196,7 +1307,10 @@ gint main(gint argc, gchar *argv[])
        /* setup random seed for random slideshow */
        srand(time(NULL));
 
+#if 0
+       /* See later comment; this handler leads to UB. */
        setup_sigbus_handler();
+#endif
 
        /* register global notify functions */
        file_data_register_notify_func(cache_notify_cb, NULL, NOTIFY_PRIORITY_HIGH);
@@ -1240,6 +1354,7 @@ gint main(gint argc, gchar *argv[])
                }
 
        DEBUG_1("%s main: pixbuf_inline_register_stock_icons", get_exec_time());
+       gtk_icon_theme_add_resource_path(gtk_icon_theme_get_default(), GQ_RESOURCE_PATH_ICONS);
        pixbuf_inline_register_stock_icons();
 
        DEBUG_1("%s main: setting default options before commandline handling", get_exec_time());
@@ -1325,7 +1440,7 @@ gint main(gint argc, gchar *argv[])
                                CollectWindow *cw;
                                const gchar *path;
 
-                               path = work->data;
+                               path = static_cast<const gchar *>(work->data);
                                work = work->next;
 
                                cw = collection_window_new(path);
@@ -1356,7 +1471,7 @@ gint main(gint argc, gchar *argv[])
                                {
                                gchar *dirname;
 
-                               dirname = g_path_get_dirname(work->data);
+                               dirname = g_path_get_dirname(static_cast<const gchar *>(work->data));
                                if (!path)
                                        {
                                        path = g_strdup(dirname);
@@ -1392,7 +1507,7 @@ gint main(gint argc, gchar *argv[])
                                {
                                FileData *fd;
 
-                               fd = file_data_new_simple(work->data);
+                               fd = file_data_new_simple(static_cast<const gchar *>(work->data));
                                collection_add(cd, fd, FALSE);
                                file_data_unref(fd);
                                work = work->next;
@@ -1405,7 +1520,7 @@ gint main(gint argc, gchar *argv[])
                                work = work->next;
                                }
 
-                       if (cd->list) layout_image_set_collection(NULL, cd, cd->list->data);
+                       if (cd->list) layout_image_set_collection(NULL, cd, static_cast<CollectInfo *>(cd->list->data));
 
                        /* mem leak, we never unref this collection when !startup_command_line_collection
                         * (the image view of the main window does not hold a ref to the collection)
@@ -1457,6 +1572,12 @@ gint main(gint argc, gchar *argv[])
                set_theme_bg_color();
                }
 
+       /* Show a fade-out notification window if the server has a newer AppImage version */
+       if (options->appimage_notifications && g_getenv("APPDIR") && strstr(g_getenv("APPDIR"), "/tmp/.mount_Geeqie"))
+               {
+               appimage_notification();
+               }
+
        DEBUG_1("%s main: gtk_main", get_exec_time());
        gtk_main();