LCOV - code coverage report
Current view: top level - toolkit/xre - nsNativeAppSupportUnix.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 111 255 43.5 %
Date: 2018-08-07 16:35:00 Functions: 7 7 100.0 %
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           0 :   nsNativeAppSupportUnix(): mSessionConnection(nullptr),
     131           0 :                             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) override;
     142             :   NS_IMETHOD Stop(bool *aResult) override;
     143             :   NS_IMETHOD Enable() override;
     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           1 :   static void SaveCompleteCB(SmcConn smc_conn, SmPointer client_data) {};
     153             :   static void ShutdownCancelledCB(SmcConn smc_conn, SmPointer client_data);
     154             :   void DoInteract();
     155           1 :   void SetClientState(ClientState aState)
     156             :   {
     157           1 :     mClientState = aState;
     158           1 :     MOZ_LOG(sMozSMLog, LogLevel::Debug, ("New state = %s\n", gClientStateTable[aState]));
     159           1 :   }
     160             : 
     161             :   SmcConn mSessionConnection;
     162             :   ClientState mClientState;
     163             : #endif
     164             : };
     165             : 
     166             : #if MOZ_X11
     167             : static gboolean
     168           1 : process_ice_messages(IceConn connection)
     169             : {
     170             :   IceProcessMessagesStatus status;
     171             : 
     172           1 :   status = IceProcessMessages(connection, nullptr, nullptr);
     173             : 
     174           1 :   switch (status) {
     175             :   case IceProcessMessagesSuccess:
     176             :     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           1 : ice_iochannel_watch(GIOChannel *channel, GIOCondition condition,
     195             :                     gpointer client_data)
     196             : {
     197           1 :   return process_ice_messages(static_cast<IceConn>(client_data));
     198             : }
     199             : 
     200             : static void
     201           1 : ice_connection_watch(IceConn connection, IcePointer  client_data,
     202             :                      Bool opening, IcePointer *watch_data)
     203             : {
     204             :   guint watch_id;
     205             : 
     206           1 :   if (opening) {
     207             :     GIOChannel *channel;
     208           1 :     int fd = IceConnectionNumber(connection);
     209             : 
     210           1 :     fcntl(fd, F_SETFD, fcntl(fd, F_GETFD, 0) | FD_CLOEXEC);
     211           1 :     channel = g_io_channel_unix_new(fd);
     212           1 :     watch_id = g_io_add_watch(channel,
     213             :                               static_cast<GIOCondition>(G_IO_IN | G_IO_ERR),
     214             :                               ice_iochannel_watch, connection);
     215           1 :     g_io_channel_unref(channel);
     216             : 
     217           1 :     *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           1 : }
     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           1 : ice_init(void)
     233             : {
     234             :   static bool initted = false;
     235             : 
     236           1 :   if (!initted) {
     237           1 :     IceSetIOErrorHandler(ice_io_error_handler);
     238           1 :     IceAddConnectionWatch(ice_connection_watch, nullptr);
     239           1 :     initted = true;
     240             :   }
     241           1 : }
     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           1 : 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           1 :     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           1 :   if (self->mClientState == STATE_REGISTERING) {
     326           1 :     self->SetClientState(STATE_IDLE);
     327             : 
     328           1 :     if (save_style == SmSaveLocal && interact_style == SmInteractStyleNone &&
     329           1 :         !shutdown && !fast) {
     330           1 :       SmcSaveYourselfDone(self->mSessionConnection, True);
     331           1 :       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             : SetSMValue(SmPropValue& val, const nsCString& data)
     425             : {
     426           1 :   val.value = static_cast<SmPointer>(const_cast<char*>(data.get()));
     427           1 :   val.length = data.Length();
     428             : }
     429             : 
     430             : static void
     431             : SetSMProperty(SmProp& prop, const char* name, const char* type, int numVals,
     432             :               SmPropValue vals[])
     433             : {
     434           1 :   prop.name = const_cast<char*>(name);
     435           1 :   prop.type = const_cast<char*>(type);
     436           1 :   prop.num_vals = numVals;
     437           1 :   prop.vals = vals;
     438             : }
     439             : #endif /* MOZ_X11 */
     440             : 
     441           0 : static void RemoveArg(char **argv)
     442             : {
     443             :   do {
     444           0 :     *argv = *(argv + 1);
     445           0 :     ++argv;
     446           0 :   } while (*argv);
     447             : 
     448           0 :   --gArgc;
     449           0 : }
     450             : 
     451             : NS_IMETHODIMP
     452           0 : nsNativeAppSupportUnix::Start(bool *aRetVal)
     453             : {
     454           0 :   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           0 :   dbus_threads_init_default();
     461             : #endif
     462             : 
     463           0 :   *aRetVal = true;
     464             : 
     465             : #ifdef MOZ_X11
     466           0 :   gboolean sm_disable = FALSE;
     467           0 :   if (!getenv("SESSION_MANAGER")) {
     468           0 :     sm_disable = TRUE;
     469             :   }
     470             : 
     471           0 :   nsAutoCString prev_client_id;
     472             : 
     473           0 :   char **curarg = gArgv + 1;
     474           0 :   while (*curarg) {
     475           0 :     char *arg = *curarg;
     476           0 :     if (arg[0] == '-' && arg[1] == '-') {
     477           0 :       arg += 2;
     478           0 :       if (!strcmp(arg, "sm-disable")) {
     479           0 :         RemoveArg(curarg);
     480           0 :         sm_disable = TRUE;
     481           0 :         continue;
     482           0 :       } else if (!strcmp(arg, "sm-client-id")) {
     483           0 :         RemoveArg(curarg);
     484           0 :         if (*curarg[0] != '-') {
     485           0 :           prev_client_id = *curarg;
     486           0 :           RemoveArg(curarg);
     487             :         }
     488             :         continue;
     489             :       }
     490             :     }
     491             : 
     492           0 :     ++curarg;
     493             :   }
     494             : 
     495           0 :   if (prev_client_id.IsEmpty()) {
     496           0 :     prev_client_id = getenv("DESKTOP_AUTOSTART_ID");
     497             :   }
     498             : 
     499             :   // We don't want child processes to use the same ID
     500           0 :   unsetenv("DESKTOP_AUTOSTART_ID");
     501             : 
     502           0 :   char *client_id = nullptr;
     503           0 :   if (!sm_disable) {
     504           1 :     PRLibrary *iceLib = PR_LoadLibrary("libICE.so.6");
     505           1 :     if (!iceLib) {
     506           0 :       return NS_OK;
     507             :     }
     508             : 
     509           1 :     PRLibrary *smLib = PR_LoadLibrary("libSM.so.6");
     510           1 :     if (!smLib) {
     511           0 :       PR_UnloadLibrary(iceLib);
     512           0 :       return NS_OK;
     513             :     }
     514             : 
     515           1 :     IceSetIOErrorHandler = (IceSetIOErrorHandlerFn)PR_FindFunctionSymbol(iceLib, "IceSetIOErrorHandler");
     516           1 :     IceAddConnectionWatch = (IceAddConnectionWatchFn)PR_FindFunctionSymbol(iceLib, "IceAddConnectionWatch");
     517           1 :     IceConnectionNumber = (IceConnectionNumberFn)PR_FindFunctionSymbol(iceLib, "IceConnectionNumber");
     518           1 :     IceProcessMessages = (IceProcessMessagesFn)PR_FindFunctionSymbol(iceLib, "IceProcessMessages");
     519           1 :     IceGetConnectionContext = (IceGetConnectionContextFn)PR_FindFunctionSymbol(iceLib, "IceGetConnectionContext");
     520           1 :     if (!IceSetIOErrorHandler || !IceAddConnectionWatch ||
     521           1 :         !IceConnectionNumber  || !IceProcessMessages || !IceGetConnectionContext) {
     522           0 :       PR_UnloadLibrary(iceLib);
     523           0 :       PR_UnloadLibrary(smLib);
     524           0 :       return NS_OK;
     525             :     }
     526             : 
     527           1 :     SmcInteractDone = (SmcInteractDoneFn)PR_FindFunctionSymbol(smLib, "SmcInteractDone");
     528           1 :     SmcSaveYourselfDone = (SmcSaveYourselfDoneFn)PR_FindFunctionSymbol(smLib, "SmcSaveYourselfDone");
     529           1 :     SmcInteractRequest = (SmcInteractRequestFn)PR_FindFunctionSymbol(smLib, "SmcInteractRequest");
     530           1 :     SmcCloseConnection = (SmcCloseConnectionFn)PR_FindFunctionSymbol(smLib, "SmcCloseConnection");
     531           1 :     SmcOpenConnection = (SmcOpenConnectionFn)PR_FindFunctionSymbol(smLib, "SmcOpenConnection");
     532           1 :     SmcSetProperties = (SmcSetPropertiesFn)PR_FindFunctionSymbol(smLib, "SmcSetProperties");
     533           1 :     if (!SmcInteractDone || !SmcSaveYourselfDone || !SmcInteractRequest ||
     534           1 :         !SmcCloseConnection || !SmcOpenConnection || !SmcSetProperties) {
     535           0 :       PR_UnloadLibrary(iceLib);
     536           0 :       PR_UnloadLibrary(smLib);
     537           0 :       return NS_OK;
     538             :     }
     539             : 
     540           1 :     ice_init();
     541             : 
     542             :     // all callbacks are mandatory in libSM 1.0, so listen even if we don't care.
     543             :     unsigned long mask = SmcSaveYourselfProcMask | SmcDieProcMask |
     544           1 :                          SmcSaveCompleteProcMask | SmcShutdownCancelledProcMask;
     545             : 
     546             :     SmcCallbacks callbacks;
     547           1 :     callbacks.save_yourself.callback = nsNativeAppSupportUnix::SaveYourselfCB;
     548           1 :     callbacks.save_yourself.client_data = static_cast<SmPointer>(this);
     549             : 
     550           1 :     callbacks.die.callback = nsNativeAppSupportUnix::DieCB;
     551           1 :     callbacks.die.client_data = static_cast<SmPointer>(this);
     552             : 
     553           1 :     callbacks.save_complete.callback = nsNativeAppSupportUnix::SaveCompleteCB;
     554           1 :     callbacks.save_complete.client_data = nullptr;
     555             : 
     556           1 :     callbacks.shutdown_cancelled.callback =
     557             :       nsNativeAppSupportUnix::ShutdownCancelledCB;
     558           1 :     callbacks.shutdown_cancelled.client_data = static_cast<SmPointer>(this);
     559             : 
     560             :     char errbuf[256];
     561           1 :     mSessionConnection = SmcOpenConnection(nullptr, this, SmProtoMajor,
     562             :                                            SmProtoMinor, mask, &callbacks,
     563             :                                            prev_client_id.get(), &client_id,
     564             :                                            sizeof(errbuf), errbuf);
     565             :   }
     566             : 
     567           0 :   if (!mSessionConnection) {
     568             :     return NS_OK;
     569             :   }
     570             : 
     571           1 :   LogModule::Init(gArgc, gArgv);  // need to make sure initialized before SetClientState
     572           1 :   if (prev_client_id.IsEmpty() ||
     573           0 :       (client_id && !prev_client_id.Equals(client_id))) {
     574           1 :     SetClientState(STATE_REGISTERING);
     575             :   } else {
     576           0 :     SetClientState(STATE_IDLE);
     577             :   }
     578             : 
     579           1 :   gdk_x11_set_sm_client_id(client_id);
     580             : 
     581             :   // Set SM Properties
     582             :   // SmCloneCommand, SmProgram, SmRestartCommand, SmUserID are required
     583             :   // properties so must be set, and must have a sensible fallback value.
     584             : 
     585             :   // Determine executable path to use for XSMP session restore
     586             : 
     587             :   // Is there a request to suppress default binary launcher?
     588           1 :   nsAutoCString path(getenv("MOZ_APP_LAUNCHER"));
     589             : 
     590           1 :   if (path.IsEmpty()) {
     591           1 :     NS_ASSERTION(gDirServiceProvider, "gDirServiceProvider is NULL! This shouldn't happen!");
     592           1 :     nsCOMPtr<nsIFile> executablePath;
     593             :     nsresult rv;
     594             : 
     595             :     bool dummy;
     596           1 :     rv = gDirServiceProvider->GetFile(XRE_EXECUTABLE_FILE, &dummy, getter_AddRefs(executablePath));
     597             : 
     598           1 :     if (NS_SUCCEEDED(rv)) {
     599             :       // Strip off the -bin suffix to get the shell script we should run; this is what Breakpad does
     600           1 :       nsAutoCString leafName;
     601           1 :       rv = executablePath->GetNativeLeafName(leafName);
     602           1 :       if (NS_SUCCEEDED(rv) && StringEndsWith(leafName, NS_LITERAL_CSTRING("-bin"))) {
     603           1 :         leafName.SetLength(leafName.Length() - strlen("-bin"));
     604           1 :         executablePath->SetNativeLeafName(leafName);
     605             :       }
     606             : 
     607           1 :       executablePath->GetNativePath(path);
     608             :     }
     609             :   }
     610             : 
     611           1 :   if (path.IsEmpty()) {
     612             :     // can't determine executable path. Best fallback is name from
     613             :     // application.ini but it might not resolve to the same executable at
     614             :     // launch time.
     615           0 :     path = gAppData->name;  // will always be set
     616           0 :     ToLowerCase(path);
     617           0 :     MOZ_LOG(sMozSMLog, LogLevel::Warning,
     618             :         ("Could not determine executable path. Falling back to %s.", path.get()));
     619             :   }
     620             : 
     621             :   SmProp propRestart, propClone, propProgram, propUser, *props[4];
     622             :   SmPropValue valsRestart[3], valsClone[1], valsProgram[1], valsUser[1];
     623           1 :   int n = 0;
     624             : 
     625           1 :   NS_NAMED_LITERAL_CSTRING(kClientIDParam, "--sm-client-id");
     626             : 
     627           1 :   SetSMValue(valsRestart[0], path);
     628           1 :   SetSMValue(valsRestart[1], kClientIDParam);
     629           1 :   SetSMValue(valsRestart[2], nsDependentCString(client_id));
     630           1 :   SetSMProperty(propRestart, SmRestartCommand, SmLISTofARRAY8, 3, valsRestart);
     631           1 :   props[n++] = &propRestart;
     632             : 
     633           1 :   SetSMValue(valsClone[0], path);
     634           1 :   SetSMProperty(propClone, SmCloneCommand, SmLISTofARRAY8, 1, valsClone);
     635           1 :   props[n++] = &propClone;
     636             : 
     637           1 :   nsAutoCString appName(gAppData->name);  // will always be set
     638           1 :   ToLowerCase(appName);
     639             : 
     640           1 :   SetSMValue(valsProgram[0], appName);
     641           1 :   SetSMProperty(propProgram, SmProgram, SmARRAY8, 1, valsProgram);
     642           1 :   props[n++] = &propProgram;
     643             : 
     644           1 :   nsAutoCString userName;  // username that started the program
     645           1 :   struct passwd* pw = getpwuid(getuid());
     646           1 :   if (pw && pw->pw_name) {
     647           1 :     userName = pw->pw_name;
     648             :   } else {
     649           0 :     userName = NS_LITERAL_CSTRING("nobody");
     650           0 :     MOZ_LOG(sMozSMLog, LogLevel::Warning,
     651             :         ("Could not determine user-name. Falling back to %s.", userName.get()));
     652             :   }
     653             : 
     654           1 :   SetSMValue(valsUser[0], userName);
     655           1 :   SetSMProperty(propUser, SmUserID, SmARRAY8, 1, valsUser);
     656           1 :   props[n++] = &propUser;
     657             : 
     658           1 :   SmcSetProperties(mSessionConnection, n, props);
     659             : 
     660           1 :   g_free(client_id);
     661             : #endif /* MOZ_X11 */
     662             : 
     663           1 :   return NS_OK;
     664             : }
     665             : 
     666             : NS_IMETHODIMP
     667           0 : nsNativeAppSupportUnix::Stop(bool *aResult)
     668             : {
     669           0 :   NS_ENSURE_ARG(aResult);
     670           0 :   *aResult = true;
     671           0 :   return NS_OK;
     672             : }
     673             : 
     674             : NS_IMETHODIMP
     675           0 : nsNativeAppSupportUnix::Enable()
     676             : {
     677           0 :   return NS_OK;
     678             : }
     679             : 
     680             : nsresult
     681           0 : NS_CreateNativeAppSupport(nsINativeAppSupport **aResult)
     682             : {
     683           0 :   nsNativeAppSupportBase* native = new nsNativeAppSupportUnix();
     684           0 :   if (!native)
     685             :     return NS_ERROR_OUT_OF_MEMORY;
     686             : 
     687           0 :   *aResult = native;
     688           0 :   NS_ADDREF(*aResult);
     689             : 
     690           0 :   return NS_OK;
     691             : }

Generated by: LCOV version 1.13-14-ga5dd952