LCOV - code coverage report
Current view: top level - toolkit/xre - nsNativeAppSupportUnix.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 30 264 11.4 %
Date: 2017-07-14 16:53:18 Functions: 4 23 17.4 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #include "nsNativeAppSupportBase.h"
       8             : #include "nsCOMPtr.h"
       9             : #include "nsXPCOM.h"
      10             : #include "nsISupportsPrimitives.h"
      11             : #include "nsIObserverService.h"
      12             : #include "nsIAppStartup.h"
      13             : #include "nsServiceManagerUtils.h"
      14             : #include "prlink.h"
      15             : #include "nsXREDirProvider.h"
      16             : #include "nsReadableUtils.h"
      17             : 
      18             : #include "nsIFile.h"
      19             : #include "nsDirectoryServiceDefs.h"
      20             : #include "nsICommandLineRunner.h"
      21             : #include "nsIWindowMediator.h"
      22             : #include "nsPIDOMWindow.h"
      23             : #include "nsIDocShell.h"
      24             : #include "nsIBaseWindow.h"
      25             : #include "nsIWidget.h"
      26             : #include "nsIWritablePropertyBag2.h"
      27             : #include "nsIPrefService.h"
      28             : #include "mozilla/Services.h"
      29             : 
      30             : #include <stdlib.h>
      31             : #include <glib.h>
      32             : #include <glib-object.h>
      33             : #include <gtk/gtk.h>
      34             : 
      35             : #ifdef MOZ_X11
      36             : #include <gdk/gdkx.h>
      37             : #include <X11/ICE/ICElib.h>
      38             : #include <X11/SM/SMlib.h>
      39             : #include <fcntl.h>
      40             : #include "nsThreadUtils.h"
      41             : 
      42             : #include <pwd.h>
      43             : #endif
      44             : 
      45             : #ifdef MOZ_ENABLE_DBUS
      46             : #include <dbus/dbus.h>
      47             : #endif
      48             : 
      49             : #define MIN_GTK_MAJOR_VERSION 2
      50             : #define MIN_GTK_MINOR_VERSION 10
      51             : #define UNSUPPORTED_GTK_MSG "We're sorry, this application requires a version of the GTK+ library that is not installed on your computer.\n\n\
      52             : You have GTK+ %d.%d.\nThis application requires GTK+ %d.%d or newer.\n\n\
      53             : Please upgrade your GTK+ library if you wish to use this application."
      54             : 
      55             : #if MOZ_X11
      56             : #undef IceSetIOErrorHandler
      57             : #undef IceAddConnectionWatch
      58             : #undef IceConnectionNumber
      59             : #undef IceProcessMessages
      60             : #undef IceGetConnectionContext
      61             : #undef SmcInteractDone
      62             : #undef SmcSaveYourselfDone
      63             : #undef SmcInteractRequest
      64             : #undef SmcCloseConnection
      65             : #undef SmcOpenConnection
      66             : #undef SmcSetProperties
      67             : 
      68             : typedef IceIOErrorHandler (*IceSetIOErrorHandlerFn) (IceIOErrorHandler);
      69             : typedef int (*IceAddConnectionWatchFn) (IceWatchProc, IcePointer);
      70             : typedef int (*IceConnectionNumberFn) (IceConn);
      71             : typedef IceProcessMessagesStatus (*IceProcessMessagesFn) (IceConn, IceReplyWaitInfo*, Bool*);
      72             : typedef IcePointer (*IceGetConnectionContextFn) (IceConn);
      73             : 
      74             : typedef void (*SmcInteractDoneFn) (SmcConn, Bool);
      75             : typedef void (*SmcSaveYourselfDoneFn) (SmcConn, Bool);
      76             : typedef int (*SmcInteractRequestFn) (SmcConn, int, SmcInteractProc, SmPointer);
      77             : typedef SmcCloseStatus (*SmcCloseConnectionFn) (SmcConn, int, char**);
      78             : typedef SmcConn (*SmcOpenConnectionFn) (char*, SmPointer, int, int,
      79             :                                         unsigned long, SmcCallbacks*,
      80             :                                         const char*, char**, int, char*);
      81             : typedef void (*SmcSetPropertiesFn) (SmcConn, int, SmProp**);
      82             : 
      83             : static IceSetIOErrorHandlerFn IceSetIOErrorHandlerPtr;
      84             : static IceAddConnectionWatchFn IceAddConnectionWatchPtr;
      85             : static IceConnectionNumberFn IceConnectionNumberPtr;
      86             : static IceProcessMessagesFn IceProcessMessagesPtr;
      87             : static IceGetConnectionContextFn IceGetConnectionContextPtr;
      88             : static SmcInteractDoneFn SmcInteractDonePtr;
      89             : static SmcSaveYourselfDoneFn SmcSaveYourselfDonePtr;
      90             : static SmcInteractRequestFn SmcInteractRequestPtr;
      91             : static SmcCloseConnectionFn SmcCloseConnectionPtr;
      92             : static SmcOpenConnectionFn SmcOpenConnectionPtr;
      93             : static SmcSetPropertiesFn SmcSetPropertiesPtr;
      94             : 
      95             : #define IceSetIOErrorHandler IceSetIOErrorHandlerPtr
      96             : #define IceAddConnectionWatch IceAddConnectionWatchPtr
      97             : #define IceConnectionNumber IceConnectionNumberPtr
      98             : #define IceProcessMessages IceProcessMessagesPtr
      99             : #define IceGetConnectionContext IceGetConnectionContextPtr
     100             : #define SmcInteractDone SmcInteractDonePtr
     101             : #define SmcSaveYourselfDone SmcSaveYourselfDonePtr
     102             : #define SmcInteractRequest SmcInteractRequestPtr
     103             : #define SmcCloseConnection SmcCloseConnectionPtr
     104             : #define SmcOpenConnection SmcOpenConnectionPtr
     105             : #define SmcSetProperties SmcSetPropertiesPtr
     106             : 
     107             : enum ClientState {
     108             :   STATE_DISCONNECTED,
     109             :   STATE_REGISTERING,
     110             :   STATE_IDLE,
     111             :   STATE_INTERACTING,
     112             :   STATE_SHUTDOWN_CANCELLED
     113             : };
     114             : 
     115             : static const char *gClientStateTable[] = {
     116             :   "DISCONNECTED",
     117             :   "REGISTERING",
     118             :   "IDLE",
     119             :   "INTERACTING",
     120             :   "SHUTDOWN_CANCELLED"
     121             : };
     122             : 
     123             : static LazyLogModule sMozSMLog("MozSM");
     124             : #endif /* MOZ_X11 */
     125             : 
     126             : class nsNativeAppSupportUnix : public nsNativeAppSupportBase
     127             : {
     128             : public:
     129             : #if MOZ_X11
     130           1 :   nsNativeAppSupportUnix(): mSessionConnection(nullptr),
     131           1 :                             mClientState(STATE_DISCONNECTED) {};
     132           0 :   ~nsNativeAppSupportUnix()
     133           0 :   {
     134             :     // this goes out of scope after "web-workers-shutdown" async shutdown phase
     135             :     // so it's safe to disconnect here (i.e. the application won't lose data)
     136           0 :     DisconnectFromSM();
     137           0 :   };
     138             : 
     139             :   void DisconnectFromSM();
     140             : #endif
     141             :   NS_IMETHOD Start(bool* aRetVal);
     142             :   NS_IMETHOD Stop(bool *aResult);
     143             :   NS_IMETHOD Enable();
     144             : 
     145             : private:
     146             : #if MOZ_X11
     147             :   static void SaveYourselfCB(SmcConn smc_conn, SmPointer client_data,
     148             :                              int save_style, Bool shutdown, int interact_style,
     149             :                              Bool fast);
     150             :   static void DieCB(SmcConn smc_conn, SmPointer client_data);
     151             :   static void InteractCB(SmcConn smc_conn, SmPointer client_data);
     152           0 :   static void SaveCompleteCB(SmcConn smc_conn, SmPointer client_data) {};
     153             :   static void ShutdownCancelledCB(SmcConn smc_conn, SmPointer client_data);
     154             :   void DoInteract();
     155           0 :   void SetClientState(ClientState aState)
     156             :   {
     157           0 :     mClientState = aState;
     158           0 :     MOZ_LOG(sMozSMLog, LogLevel::Debug, ("New state = %s\n", gClientStateTable[aState]));
     159           0 :   }
     160             : 
     161             :   SmcConn mSessionConnection;
     162             :   ClientState mClientState;
     163             : #endif
     164             : };
     165             : 
     166             : #if MOZ_X11
     167             : static gboolean
     168           0 : process_ice_messages(IceConn connection)
     169             : {
     170             :   IceProcessMessagesStatus status;
     171             : 
     172           0 :   status = IceProcessMessages(connection, nullptr, nullptr);
     173             : 
     174           0 :   switch (status) {
     175             :   case IceProcessMessagesSuccess:
     176           0 :     return TRUE;
     177             : 
     178             :   case IceProcessMessagesIOError: {
     179             :       nsNativeAppSupportUnix *native =
     180           0 :         static_cast<nsNativeAppSupportUnix *>(IceGetConnectionContext(connection));
     181           0 :       native->DisconnectFromSM();
     182             :     }
     183           0 :     return FALSE;
     184             : 
     185             :   case IceProcessMessagesConnectionClosed:
     186           0 :     return FALSE;
     187             : 
     188             :   default:
     189           0 :     g_assert_not_reached ();
     190             :   }
     191             : }
     192             : 
     193             : static gboolean
     194           0 : ice_iochannel_watch(GIOChannel *channel, GIOCondition condition,
     195             :                     gpointer client_data)
     196             : {
     197           0 :   return process_ice_messages(static_cast<IceConn>(client_data));
     198             : }
     199             : 
     200             : static void
     201           0 : ice_connection_watch(IceConn connection, IcePointer  client_data,
     202             :                      Bool opening, IcePointer *watch_data)
     203             : {
     204             :   guint watch_id;
     205             : 
     206           0 :   if (opening) {
     207             :     GIOChannel *channel;
     208           0 :     int fd = IceConnectionNumber(connection);
     209             : 
     210           0 :     fcntl(fd, F_SETFD, fcntl(fd, F_GETFD, 0) | FD_CLOEXEC);
     211           0 :     channel = g_io_channel_unix_new(fd);
     212             :     watch_id = g_io_add_watch(channel,
     213             :                               static_cast<GIOCondition>(G_IO_IN | G_IO_ERR),
     214           0 :                               ice_iochannel_watch, connection);
     215           0 :     g_io_channel_unref(channel);
     216             : 
     217           0 :     *watch_data = GUINT_TO_POINTER(watch_id);
     218             :   } else {
     219           0 :     watch_id = GPOINTER_TO_UINT(*watch_data);
     220           0 :     g_source_remove(watch_id);
     221             :   }
     222           0 : }
     223             : 
     224             : static void
     225           0 : ice_io_error_handler(IceConn connection)
     226             : {
     227             :   // override the default handler which would exit the application;
     228             :   // do nothing and let ICELib handle the failure of the connection gracefully.
     229           0 : }
     230             : 
     231             : static void
     232           0 : ice_init(void)
     233             : {
     234             :   static bool initted = false;
     235             : 
     236           0 :   if (!initted) {
     237           0 :     IceSetIOErrorHandler(ice_io_error_handler);
     238           0 :     IceAddConnectionWatch(ice_connection_watch, nullptr);
     239           0 :     initted = true;
     240             :   }
     241           0 : }
     242             : 
     243             : void
     244           0 : nsNativeAppSupportUnix::InteractCB(SmcConn smc_conn, SmPointer client_data)
     245             : {
     246             :   nsNativeAppSupportUnix *self =
     247           0 :     static_cast<nsNativeAppSupportUnix *>(client_data);
     248             : 
     249           0 :   self->SetClientState(STATE_INTERACTING);
     250             : 
     251             :   // We do this asynchronously, as we spin the event loop recursively if
     252             :   // a dialog is displayed. If we do this synchronously, we don't finish
     253             :   // processing the current ICE event whilst the dialog is displayed, which
     254             :   // means we won't process any more. libsm hates us if we do the InteractDone
     255             :   // with a pending ShutdownCancelled, and we would certainly like to handle Die
     256             :   // whilst a dialog is displayed
     257           0 :   NS_DispatchToCurrentThread(
     258           0 :     NewRunnableMethod("nsNativeAppSupportUnix::DoInteract",
     259             :                       self,
     260           0 :                       &nsNativeAppSupportUnix::DoInteract));
     261           0 : }
     262             : 
     263             : void
     264           0 : nsNativeAppSupportUnix::DoInteract()
     265             : {
     266             :   nsCOMPtr<nsIObserverService> obsServ =
     267           0 :     mozilla::services::GetObserverService();
     268           0 :   if (!obsServ) {
     269           0 :     SmcInteractDone(mSessionConnection, False);
     270           0 :     SmcSaveYourselfDone(mSessionConnection, True);
     271           0 :     SetClientState(STATE_IDLE);
     272           0 :     return;
     273             :   }
     274             : 
     275             :   nsCOMPtr<nsISupportsPRBool> cancelQuit =
     276           0 :     do_CreateInstance(NS_SUPPORTS_PRBOOL_CONTRACTID);
     277             : 
     278           0 :   bool abortQuit = false;
     279           0 :   if (cancelQuit) {
     280           0 :     cancelQuit->SetData(false);
     281           0 :     obsServ->NotifyObservers(cancelQuit, "quit-application-requested", nullptr);
     282             : 
     283           0 :     cancelQuit->GetData(&abortQuit);
     284             :   }
     285             : 
     286           0 :   if (!abortQuit && mClientState == STATE_DISCONNECTED) {
     287             :     // The session manager disappeared, whilst we were interacting, so
     288             :     // quit now
     289             :     nsCOMPtr<nsIAppStartup> appService =
     290           0 :       do_GetService("@mozilla.org/toolkit/app-startup;1");
     291             : 
     292           0 :     if (appService) {
     293           0 :       appService->Quit(nsIAppStartup::eForceQuit);
     294           0 :     }
     295             :   } else {
     296           0 :     if (mClientState != STATE_SHUTDOWN_CANCELLED) {
     297             :       // Only do this if the shutdown wasn't cancelled
     298           0 :       SmcInteractDone(mSessionConnection, !!abortQuit);
     299           0 :       SmcSaveYourselfDone(mSessionConnection, !abortQuit);
     300             :     }
     301             : 
     302           0 :     SetClientState(STATE_IDLE);
     303             :   }
     304             : }
     305             : 
     306             : void
     307           0 : nsNativeAppSupportUnix::SaveYourselfCB(SmcConn smc_conn, SmPointer client_data,
     308             :                                        int save_style, Bool shutdown,
     309             :                                        int interact_style, Bool fast)
     310             : {
     311             :   nsNativeAppSupportUnix *self =
     312           0 :     static_cast<nsNativeAppSupportUnix *>(client_data);
     313             : 
     314             :   // Expect a SaveYourselfCB if we're registering a new client.
     315             :   // All properties are already set in Start() so just reply with
     316             :   // SmcSaveYourselfDone if the callback matches the expected signature.
     317             :   //
     318             :   // Ancient versions (?) of xsm do not follow such an early SaveYourself with
     319             :   // SaveComplete. This is a problem if the application freezes interaction
     320             :   // while waiting for a response to SmcSaveYourselfDone. So never freeze
     321             :   // interaction when in STATE_REGISTERING.
     322             :   //
     323             :   // That aside, we could treat each combination of flags appropriately and not
     324             :   // special-case this.
     325           0 :   if (self->mClientState == STATE_REGISTERING) {
     326           0 :     self->SetClientState(STATE_IDLE);
     327             : 
     328           0 :     if (save_style == SmSaveLocal && interact_style == SmInteractStyleNone &&
     329           0 :         !shutdown && !fast) {
     330           0 :       SmcSaveYourselfDone(self->mSessionConnection, True);
     331           0 :       return;
     332             :     }
     333             :   }
     334             : 
     335           0 :   if (self->mClientState == STATE_SHUTDOWN_CANCELLED) {
     336             :     // The last shutdown request was cancelled whilst we were interacting,
     337             :     // and we haven't finished interacting yet. Switch the state back again
     338           0 :     self->SetClientState(STATE_INTERACTING);
     339             :   }
     340             : 
     341             :   nsCOMPtr<nsIObserverService> obsServ =
     342           0 :     mozilla::services::GetObserverService();
     343           0 :   if (!obsServ) {
     344           0 :     SmcSaveYourselfDone(smc_conn, True);
     345           0 :     return;
     346             :   }
     347             : 
     348           0 :   bool status = false;
     349           0 :   if (save_style != SmSaveGlobal) {
     350             :     nsCOMPtr<nsISupportsPRBool> didSaveSession =
     351           0 :       do_CreateInstance(NS_SUPPORTS_PRBOOL_CONTRACTID);
     352             : 
     353           0 :     if (!didSaveSession) {
     354           0 :       SmcSaveYourselfDone(smc_conn, True);
     355           0 :       return;
     356             :     }
     357             : 
     358             :     // Notify observers to save the session state
     359           0 :     didSaveSession->SetData(false);
     360           0 :     obsServ->NotifyObservers(didSaveSession, "session-save", nullptr);
     361             : 
     362           0 :     didSaveSession->GetData(&status);
     363             :   }
     364             : 
     365             :   // If the interact style permits us to, we are shutting down and we didn't
     366             :   // manage to (or weren't asked to) save the local state, then notify the user
     367             :   // in advance that we are doing to quit (assuming that we aren't already
     368             :   // doing so)
     369           0 :   if (!status && shutdown && interact_style != SmInteractStyleNone) {
     370           0 :     if (self->mClientState != STATE_INTERACTING) {
     371             :       SmcInteractRequest(smc_conn, SmDialogNormal,
     372           0 :                          nsNativeAppSupportUnix::InteractCB, client_data);
     373             :     }
     374             :   } else {
     375           0 :     SmcSaveYourselfDone(smc_conn, True);
     376             :   }
     377             : }
     378             : 
     379             : void
     380           0 : nsNativeAppSupportUnix::DieCB(SmcConn smc_conn, SmPointer client_data)
     381             : {
     382             :   nsCOMPtr<nsIAppStartup> appService =
     383           0 :     do_GetService("@mozilla.org/toolkit/app-startup;1");
     384             : 
     385           0 :   if (appService) {
     386           0 :     appService->Quit(nsIAppStartup::eForceQuit);
     387             :   }
     388             :   // Quit causes the shutdown to begin but the shutdown process is asynchronous
     389             :   // so we can't DisconnectFromSM() yet
     390           0 : }
     391             : 
     392             : void
     393           0 : nsNativeAppSupportUnix::ShutdownCancelledCB(SmcConn smc_conn,
     394             :                                             SmPointer client_data)
     395             : {
     396             :   nsNativeAppSupportUnix *self =
     397           0 :     static_cast<nsNativeAppSupportUnix *>(client_data);
     398             : 
     399             :   // Interacting is the only time when we wouldn't already have called
     400             :   // SmcSaveYourselfDone. Do that now, then set the state to make sure we
     401             :   // don't send it again after finishing interacting
     402           0 :   if (self->mClientState == STATE_INTERACTING) {
     403           0 :     SmcSaveYourselfDone(smc_conn, False);
     404           0 :     self->SetClientState(STATE_SHUTDOWN_CANCELLED);
     405             :   }
     406           0 : }
     407             : 
     408             : void
     409           0 : nsNativeAppSupportUnix::DisconnectFromSM()
     410             : {
     411             :   // the SM is free to exit any time after we disconnect, so callers must be
     412             :   // sure to have reached a sufficiently advanced phase of shutdown that there
     413             :   // is no risk of data loss:
     414             :   // e.g. all async writes are complete by the end of "profile-before-change"
     415           0 :   if (mSessionConnection) {
     416           0 :     SetClientState(STATE_DISCONNECTED);
     417           0 :     SmcCloseConnection(mSessionConnection, 0, nullptr);
     418           0 :     mSessionConnection = nullptr;
     419           0 :     gdk_x11_set_sm_client_id(nullptr);  // follow gnome-client behaviour
     420             :   }
     421           0 : }
     422             : 
     423             : static void
     424           0 : SetSMValue(SmPropValue& val, const nsCString& data)
     425             : {
     426           0 :   val.value = static_cast<SmPointer>(const_cast<char*>(data.get()));
     427           0 :   val.length = data.Length();
     428           0 : }
     429             : 
     430             : static void
     431           0 : SetSMProperty(SmProp& prop, const char* name, const char* type, int numVals,
     432             :               SmPropValue vals[])
     433             : {
     434           0 :   prop.name = const_cast<char*>(name);
     435           0 :   prop.type = const_cast<char*>(type);
     436           0 :   prop.num_vals = numVals;
     437           0 :   prop.vals = vals;
     438           0 : }
     439             : #endif /* MOZ_X11 */
     440             : 
     441           0 : static void RemoveArg(char **argv)
     442             : {
     443           0 :   do {
     444           0 :     *argv = *(argv + 1);
     445           0 :     ++argv;
     446           0 :   } while (*argv);
     447             : 
     448           0 :   --gArgc;
     449           0 : }
     450             : 
     451             : NS_IMETHODIMP
     452           1 : nsNativeAppSupportUnix::Start(bool *aRetVal)
     453             : {
     454           1 :   NS_ASSERTION(gAppData, "gAppData must not be null.");
     455             : 
     456             : // The dbus library is used by both nsWifiScannerDBus and BluetoothDBusService,
     457             : // from diffrent threads. This could lead to race conditions if the dbus is not
     458             : // initialized before making any other library calls.
     459             : #ifdef MOZ_ENABLE_DBUS
     460           1 :   dbus_threads_init_default();
     461             : #endif
     462             : 
     463             : #if (MOZ_WIDGET_GTK == 2)
     464             :   if (gtk_major_version < MIN_GTK_MAJOR_VERSION ||
     465             :       (gtk_major_version == MIN_GTK_MAJOR_VERSION && gtk_minor_version < MIN_GTK_MINOR_VERSION)) {
     466             :     GtkWidget* versionErrDialog = gtk_message_dialog_new(nullptr,
     467             :                      GtkDialogFlags(GTK_DIALOG_MODAL |
     468             :                                     GTK_DIALOG_DESTROY_WITH_PARENT),
     469             :                      GTK_MESSAGE_ERROR,
     470             :                      GTK_BUTTONS_OK,
     471             :                      UNSUPPORTED_GTK_MSG,
     472             :                      gtk_major_version,
     473             :                      gtk_minor_version,
     474             :                      MIN_GTK_MAJOR_VERSION,
     475             :                      MIN_GTK_MINOR_VERSION);
     476             :     gtk_dialog_run(GTK_DIALOG(versionErrDialog));
     477             :     gtk_widget_destroy(versionErrDialog);
     478             :     MozExpectedExit();
     479             :     exit(0);
     480             :   }
     481             : #endif
     482             : 
     483           1 :   *aRetVal = true;
     484             : 
     485             : #ifdef MOZ_X11
     486           1 :   gboolean sm_disable = FALSE;
     487           1 :   if (!getenv("SESSION_MANAGER")) {
     488           1 :     sm_disable = TRUE;
     489             :   }
     490             : 
     491           2 :   nsAutoCString prev_client_id;
     492             : 
     493           1 :   char **curarg = gArgv + 1;
     494           7 :   while (*curarg) {
     495           3 :     char *arg = *curarg;
     496           3 :     if (arg[0] == '-' && arg[1] == '-') {
     497           0 :       arg += 2;
     498           0 :       if (!strcmp(arg, "sm-disable")) {
     499           0 :         RemoveArg(curarg);
     500           0 :         sm_disable = TRUE;
     501           0 :         continue;
     502           0 :       } else if (!strcmp(arg, "sm-client-id")) {
     503           0 :         RemoveArg(curarg);
     504           0 :         if (*curarg[0] != '-') {
     505           0 :           prev_client_id = *curarg;
     506           0 :           RemoveArg(curarg);
     507             :         }
     508           0 :         continue;
     509             :       }
     510             :     }
     511             : 
     512           3 :     ++curarg;
     513             :   }
     514             : 
     515           1 :   if (prev_client_id.IsEmpty()) {
     516           1 :     prev_client_id = getenv("DESKTOP_AUTOSTART_ID");
     517             :   }
     518             : 
     519             :   // We don't want child processes to use the same ID
     520           1 :   unsetenv("DESKTOP_AUTOSTART_ID");
     521             : 
     522           1 :   char *client_id = nullptr;
     523           1 :   if (!sm_disable) {
     524           0 :     PRLibrary *iceLib = PR_LoadLibrary("libICE.so.6");
     525           0 :     if (!iceLib) {
     526           0 :       return NS_OK;
     527             :     }
     528             : 
     529           0 :     PRLibrary *smLib = PR_LoadLibrary("libSM.so.6");
     530           0 :     if (!smLib) {
     531           0 :       PR_UnloadLibrary(iceLib);
     532           0 :       return NS_OK;
     533             :     }
     534             : 
     535           0 :     IceSetIOErrorHandler = (IceSetIOErrorHandlerFn)PR_FindFunctionSymbol(iceLib, "IceSetIOErrorHandler");
     536           0 :     IceAddConnectionWatch = (IceAddConnectionWatchFn)PR_FindFunctionSymbol(iceLib, "IceAddConnectionWatch");
     537           0 :     IceConnectionNumber = (IceConnectionNumberFn)PR_FindFunctionSymbol(iceLib, "IceConnectionNumber");
     538           0 :     IceProcessMessages = (IceProcessMessagesFn)PR_FindFunctionSymbol(iceLib, "IceProcessMessages");
     539           0 :     IceGetConnectionContext = (IceGetConnectionContextFn)PR_FindFunctionSymbol(iceLib, "IceGetConnectionContext");
     540           0 :     if (!IceSetIOErrorHandler || !IceAddConnectionWatch ||
     541           0 :         !IceConnectionNumber  || !IceProcessMessages || !IceGetConnectionContext) {
     542           0 :       PR_UnloadLibrary(iceLib);
     543           0 :       PR_UnloadLibrary(smLib);
     544           0 :       return NS_OK;
     545             :     }
     546             : 
     547           0 :     SmcInteractDone = (SmcInteractDoneFn)PR_FindFunctionSymbol(smLib, "SmcInteractDone");
     548           0 :     SmcSaveYourselfDone = (SmcSaveYourselfDoneFn)PR_FindFunctionSymbol(smLib, "SmcSaveYourselfDone");
     549           0 :     SmcInteractRequest = (SmcInteractRequestFn)PR_FindFunctionSymbol(smLib, "SmcInteractRequest");
     550           0 :     SmcCloseConnection = (SmcCloseConnectionFn)PR_FindFunctionSymbol(smLib, "SmcCloseConnection");
     551           0 :     SmcOpenConnection = (SmcOpenConnectionFn)PR_FindFunctionSymbol(smLib, "SmcOpenConnection");
     552           0 :     SmcSetProperties = (SmcSetPropertiesFn)PR_FindFunctionSymbol(smLib, "SmcSetProperties");
     553           0 :     if (!SmcInteractDone || !SmcSaveYourselfDone || !SmcInteractRequest ||
     554           0 :         !SmcCloseConnection || !SmcOpenConnection || !SmcSetProperties) {
     555           0 :       PR_UnloadLibrary(iceLib);
     556           0 :       PR_UnloadLibrary(smLib);
     557           0 :       return NS_OK;
     558             :     }
     559             : 
     560           0 :     ice_init();
     561             : 
     562             :     // all callbacks are mandatory in libSM 1.0, so listen even if we don't care.
     563             :     unsigned long mask = SmcSaveYourselfProcMask | SmcDieProcMask |
     564           0 :                          SmcSaveCompleteProcMask | SmcShutdownCancelledProcMask;
     565             : 
     566             :     SmcCallbacks callbacks;
     567           0 :     callbacks.save_yourself.callback = nsNativeAppSupportUnix::SaveYourselfCB;
     568           0 :     callbacks.save_yourself.client_data = static_cast<SmPointer>(this);
     569             : 
     570           0 :     callbacks.die.callback = nsNativeAppSupportUnix::DieCB;
     571           0 :     callbacks.die.client_data = static_cast<SmPointer>(this);
     572             : 
     573           0 :     callbacks.save_complete.callback = nsNativeAppSupportUnix::SaveCompleteCB;
     574           0 :     callbacks.save_complete.client_data = nullptr;
     575             : 
     576           0 :     callbacks.shutdown_cancelled.callback =
     577             :       nsNativeAppSupportUnix::ShutdownCancelledCB;
     578           0 :     callbacks.shutdown_cancelled.client_data = static_cast<SmPointer>(this);
     579             : 
     580             :     char errbuf[256];
     581           0 :     mSessionConnection = SmcOpenConnection(nullptr, this, SmProtoMajor,
     582             :                                            SmProtoMinor, mask, &callbacks,
     583             :                                            prev_client_id.get(), &client_id,
     584             :                                            sizeof(errbuf), errbuf);
     585             :   }
     586             : 
     587           1 :   if (!mSessionConnection) {
     588           1 :     return NS_OK;
     589             :   }
     590             : 
     591           0 :   LogModule::Init();  // need to make sure initialized before SetClientState
     592           0 :   if (prev_client_id.IsEmpty() ||
     593           0 :       (client_id && !prev_client_id.Equals(client_id))) {
     594           0 :     SetClientState(STATE_REGISTERING);
     595             :   } else {
     596           0 :     SetClientState(STATE_IDLE);
     597             :   }
     598             : 
     599           0 :   gdk_x11_set_sm_client_id(client_id);
     600             : 
     601             :   // Set SM Properties
     602             :   // SmCloneCommand, SmProgram, SmRestartCommand, SmUserID are required
     603             :   // properties so must be set, and must have a sensible fallback value.
     604             : 
     605             :   // Determine executable path to use for XSMP session restore
     606             : 
     607             :   // Is there a request to suppress default binary launcher?
     608           0 :   nsAutoCString path(getenv("MOZ_APP_LAUNCHER"));
     609             : 
     610           0 :   if (path.IsEmpty()) {
     611           0 :     NS_ASSERTION(gDirServiceProvider, "gDirServiceProvider is NULL! This shouldn't happen!");
     612           0 :     nsCOMPtr<nsIFile> executablePath;
     613             :     nsresult rv;
     614             : 
     615             :     bool dummy;
     616           0 :     rv = gDirServiceProvider->GetFile(XRE_EXECUTABLE_FILE, &dummy, getter_AddRefs(executablePath));
     617             : 
     618           0 :     if (NS_SUCCEEDED(rv)) {
     619             :       // Strip off the -bin suffix to get the shell script we should run; this is what Breakpad does
     620           0 :       nsAutoCString leafName;
     621           0 :       rv = executablePath->GetNativeLeafName(leafName);
     622           0 :       if (NS_SUCCEEDED(rv) && StringEndsWith(leafName, NS_LITERAL_CSTRING("-bin"))) {
     623           0 :         leafName.SetLength(leafName.Length() - strlen("-bin"));
     624           0 :         executablePath->SetNativeLeafName(leafName);
     625             :       }
     626             : 
     627           0 :       executablePath->GetNativePath(path);
     628             :     }
     629             :   }
     630             : 
     631           0 :   if (path.IsEmpty()) {
     632             :     // can't determine executable path. Best fallback is name from
     633             :     // application.ini but it might not resolve to the same executable at
     634             :     // launch time.
     635           0 :     path = gAppData->name;  // will always be set
     636           0 :     ToLowerCase(path);
     637           0 :     MOZ_LOG(sMozSMLog, LogLevel::Warning,
     638             :         ("Could not determine executable path. Falling back to %s.", path.get()));
     639             :   }
     640             : 
     641             :   SmProp propRestart, propClone, propProgram, propUser, *props[4];
     642             :   SmPropValue valsRestart[3], valsClone[1], valsProgram[1], valsUser[1];
     643           0 :   int n = 0;
     644             : 
     645           0 :   NS_NAMED_LITERAL_CSTRING(kClientIDParam, "--sm-client-id");
     646             : 
     647           0 :   SetSMValue(valsRestart[0], path);
     648           0 :   SetSMValue(valsRestart[1], kClientIDParam);
     649           0 :   SetSMValue(valsRestart[2], nsDependentCString(client_id));
     650           0 :   SetSMProperty(propRestart, SmRestartCommand, SmLISTofARRAY8, 3, valsRestart);
     651           0 :   props[n++] = &propRestart;
     652             : 
     653           0 :   SetSMValue(valsClone[0], path);
     654           0 :   SetSMProperty(propClone, SmCloneCommand, SmLISTofARRAY8, 1, valsClone);
     655           0 :   props[n++] = &propClone;
     656             : 
     657           0 :   nsAutoCString appName(gAppData->name);  // will always be set
     658           0 :   ToLowerCase(appName);
     659             : 
     660           0 :   SetSMValue(valsProgram[0], appName);
     661           0 :   SetSMProperty(propProgram, SmProgram, SmARRAY8, 1, valsProgram);
     662           0 :   props[n++] = &propProgram;
     663             : 
     664           0 :   nsAutoCString userName;  // username that started the program
     665           0 :   struct passwd* pw = getpwuid(getuid());
     666           0 :   if (pw && pw->pw_name) {
     667           0 :     userName = pw->pw_name;
     668             :   } else {
     669           0 :     userName = NS_LITERAL_CSTRING("nobody");
     670           0 :     MOZ_LOG(sMozSMLog, LogLevel::Warning,
     671             :         ("Could not determine user-name. Falling back to %s.", userName.get()));
     672             :   }
     673             : 
     674           0 :   SetSMValue(valsUser[0], userName);
     675           0 :   SetSMProperty(propUser, SmUserID, SmARRAY8, 1, valsUser);
     676           0 :   props[n++] = &propUser;
     677             : 
     678           0 :   SmcSetProperties(mSessionConnection, n, props);
     679             : 
     680           0 :   g_free(client_id);
     681             : #endif /* MOZ_X11 */
     682             : 
     683           0 :   return NS_OK;
     684             : }
     685             : 
     686             : NS_IMETHODIMP
     687           0 : nsNativeAppSupportUnix::Stop(bool *aResult)
     688             : {
     689           0 :   NS_ENSURE_ARG(aResult);
     690           0 :   *aResult = true;
     691           0 :   return NS_OK;
     692             : }
     693             : 
     694             : NS_IMETHODIMP
     695           1 : nsNativeAppSupportUnix::Enable()
     696             : {
     697           1 :   return NS_OK;
     698             : }
     699             : 
     700             : nsresult
     701           1 : NS_CreateNativeAppSupport(nsINativeAppSupport **aResult)
     702             : {
     703           1 :   nsNativeAppSupportBase* native = new nsNativeAppSupportUnix();
     704           1 :   if (!native)
     705           0 :     return NS_ERROR_OUT_OF_MEMORY;
     706             : 
     707           1 :   *aResult = native;
     708           1 :   NS_ADDREF(*aResult);
     709             : 
     710           1 :   return NS_OK;
     711             : }

Generated by: LCOV version 1.13