6176003ed3c5ac192786d108e48440793e8c12e4
[oweals/cde.git] / SmMain.c
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these libraries and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 /* $TOG: SmMain.c /main/18 1998/04/20 12:59:26 mgreess $ */
24 /*                                                                      *
25  * (c) Copyright 1993, 1994 Hewlett-Packard Company                     *
26  * (c) Copyright 1993, 1994 International Business Machines Corp.       *
27  * (c) Copyright 1993, 1994 Sun Microsystems, Inc.                      *
28  * (c) Copyright 1993, 1994 Novell, Inc.                                *
29  */
30 /*************************************<+>*************************************
31  *****************************************************************************
32  **
33  **  File:        SmMain.c
34  **
35  **  Project:     HP DT Session Manager (dtsession)
36  **
37  **  Description:
38  **  -----------
39  **  This is the controlling program for the session manager.  It
40  **  calls routines to start the BMS, initialize globals and handlers,
41  **  and restore the correct session.
42  **
43  **
44  *******************************************************************
45  **  (c) Copyright Hewlett-Packard Company, 1990.  All rights are
46  **  reserved.  Copying or other reproduction of this program
47  **  except for archival purposes is prohibited without prior
48  **  written consent of Hewlett-Packard Company.
49  ********************************************************************
50  **
51  **
52  **
53  *****************************************************************************
54  *************************************<+>*************************************/
55
56 #include <stdio.h>
57 #include <locale.h>
58 #include <X11/Intrinsic.h>
59 #include <X11/StringDefs.h>
60
61 #if defined (USE_X11SSEXT)
62 #include <X11/extensions/scrnsaver.h>
63 #endif /* USE_X11SSEXT */
64
65 #include <Xm/Xm.h>
66 #include <Dt/UserMsg.h>
67 #include <Dt/EnvControlP.h>
68 #include <Dt/DtP.h>
69 #include <Dt/Lock.h>
70 #ifdef USE_XINERAMA
71 #include <DtXinerama.h>         /* JET - Xinerama support */
72 #endif
73 #include "Sm.h"
74 #include "SmError.h"
75 #include "SmGlobals.h"
76 #include "SmCommun.h"
77 #include "SmRestore.h"
78 #include "SmUI.h"
79 #include "SrvPalette.h"
80 #include "SmProtocol.h"
81 #include "SmXSMP.h"
82
83 /*
84  * Internal Functions
85  */
86 static void StopAll(int i);
87 static int RegisterX11ScreenSaver(Display *display, int *ssEventType);
88
89 /*
90  * Internal Defines
91  */
92 #ifdef __hpux
93 #define SECURE_SYS_PATH "/.secure/etc/passwd"
94 #endif
95 #ifdef _AIX
96 #define SECURE_SYS_PATH "/etc/security/passwd"
97 #endif
98 #if defined(SVR4) || defined(__linux__)
99 #define SECURE_SYS_PATH "/etc/shadow"
100 #endif
101 #ifdef CSRG_BASED
102 #define SECURE_SYS_PATH "/etc/master.passwd"
103 #endif
104
105
106 \f
107 /*************************************<->*************************************
108  *
109  *  main (argc, argv)
110  *
111  *
112  *  Description:
113  *  -----------
114  *  Controls the startup and event dispatching of the session manager.
115  *
116  *
117  *  Inputs:
118  *  ------
119  *  argc = command line options
120  *  argv = number of command line options
121  *
122  *
123  *  Outputs:
124  *  -------
125  *
126  *
127  *  Comments:
128  *  --------
129  *
130  *************************************<->***********************************/
131 int
132 main (int argc, char **argv)
133 {
134     int                         n, tmp;
135     Arg                         args[10];
136     XEvent                      next;
137     String                      tmpString;
138     XWindowAttributes           windAtt;
139     XPropertyEvent              *pEvent = (XPropertyEvent *) &next;
140     int                         status;
141     struct stat                 buf;
142     Display                     *srvDisplay;
143     struct sigaction            stopvec;
144     char                        *lang;
145
146     setlocale( LC_ALL, "" );
147     XtSetLanguageProc( NULL, NULL, NULL );
148
149     smGD.smState = IN_PROCESS;
150     smGD.programName = strdup (argv[0]);
151
152     /* JET - By default, we always want to leave when SmExit() is called. */
153     smGD.ExitComplete = True;
154
155     /*
156      * We report some errors before we call the DtInitialize procedure.
157      * The Dt initialize procedure sets this name.  If we report
158      * an error via DtSimple error before this is set we see the message
159      * prepended with <unknown program name> in the error log.
160      */
161     DtProgName = SM_RESOURCE_NAME ;
162
163 #ifdef DEBUG
164     if(argc > 5)
165     {
166         int junk = 1;
167         while(junk)
168         {
169            junk = 1;
170         }
171     }
172 #endif /*  DEBUG */
173     /*
174      * Set our effective gid to the real gid until we need it to be
175      * sys (during contention management)
176      */
177     smGD.runningGID = getgid();
178     smGD.conMgmtGID = getegid();
179
180     /*
181      * Set uid up according to whether this is a secure system
182      * Secure systems need root privileges to read the /etc/passwd file
183      */
184     smGD.runningUID = getuid();
185
186 # ifdef SECURE_SYS_PATH
187     status = stat(SECURE_SYS_PATH, &buf);
188 # else
189     status = -1;
190 # endif
191
192     if(status == -1)
193     {
194         /*
195          * this is not a secure system - remove all suid privileges
196          */
197         smGD.unLockUID = smGD.runningUID;
198         smGD.secureSystem = False;
199         SM_SETESUID(smGD.runningUID);
200     }
201     else
202     {
203        /*
204         * Save the root privilege to be restored when trying to unlock
205         */
206         smGD.unLockUID = geteuid();
207         smGD.secureSystem = True;
208         SM_SETEUID(smGD.runningUID);
209     }
210
211     /*
212      * Initialize LANG if it isn't defined.
213      */
214     if ((lang = getenv ("LANG")) == NULL)
215     {
216         lang = XtMalloc (7);
217         (void) strcpy (lang, "LANG=C");
218         (void) putenv (lang);
219     }
220
221 #ifdef __hpux
222     setresgid(-1, smGD.runningGID, -1);
223 #else  /* _AIX or any other system */
224 #ifndef SVR4
225     setregid(smGD.conMgmtGID, smGD.runningGID);
226 #else
227     setgid(smGD.conMgmtGID);
228     setegid(smGD.runningGID);
229 #endif
230 #endif /* !hpux */
231
232    /*
233     * Set up POSIX sigaction structs
234     */
235
236     /*
237      * Must set SIGPIPE to SIG_IGN so the process does not exit
238      * if a child terminates unexpectedly during an I/O operation
239      * that raises SIGPIPE.  Note that before this process exec's
240      * any subprocesses, SIGPIPE must be set to SIG_DFL.
241      */
242     sigemptyset(&stopvec.sa_mask);
243     stopvec.sa_flags = 0;
244     stopvec.sa_handler = SIG_IGN;
245     (void) sigaction(SIGPIPE, &stopvec, (struct sigaction *) NULL);
246
247     stopvec.sa_handler = StopAll;
248     sigemptyset(&stopvec.sa_mask);
249     stopvec.sa_flags = 0;
250
251     smGD.childvec.sa_handler = WaitChildDeath;
252     sigemptyset(&smGD.childvec.sa_mask);
253     smGD.childvec.sa_flags = 0;
254
255     smGD.defvec.sa_handler = SIG_DFL;
256     sigemptyset(&smGD.defvec.sa_mask);
257     smGD.defvec.sa_flags = 0;
258
259     smGD.appCon = 0;
260     smGD.display = 0;
261
262     /*
263      * This must be done before XtToolkitInitialize
264      * to set up the local environment
265      */
266     _DtEnvControl(DT_ENV_SET);
267     _DtEnvControl(DT_ENV_SET_BIN);
268
269     /*
270      * Set up NLS error messages first
271      */
272     InitNlsStrings();
273
274     /*
275      * Set the paths of where resources are to be restored from
276      */
277     SetRestorePath(argc, argv);
278
279     /*
280      * The first thing that must happen is that resources must be restored
281      * so that my resources will be correct
282      */
283     if(smGD.compatMode == False)
284     {
285      /*
286       * Load session resources.
287       */
288       RestoreResources(False,
289                        "-load",
290                        "-system",
291                        "-xdefaults",
292                        smGD.resourcePath[0] != '\0' ? "-file" : NULL,
293                        smGD.resourcePath,
294                        NULL);
295     }
296
297     /*
298      * Set up to catch SIGTERM
299      */
300     stopvec.sa_handler = StopAll;
301     sigemptyset(&stopvec.sa_mask);
302     stopvec.sa_flags = 0;
303
304     sigaction(SIGTERM, &stopvec, (struct sigaction *) NULL);
305
306     /*
307      * Now set up a communication with the toolkit
308      *
309      * Create one display connection for dtsession, and one for
310      * the color server. We cannot share a display connection since
311      * motif creates a display object for the color server's display during
312      * color server initialization. Since the color server is not yet
313      * operational, any dialogs (ie the dtsession logout confirmation
314      * dialogs) created on that display do not get the color server colors.
315      * The dtsession display object is created after color server
316      * initialization is complete.
317      */
318     if (smGD.appCon == 0) {
319         /*
320          * The following code will have been initialized if the
321          * session creation code posted a dialog.
322          */
323         XtToolkitInitialize();
324         smGD.appCon = XtCreateApplicationContext();
325         smGD.display = XtOpenDisplay(smGD.appCon, NULL, argv[0],
326                                 SM_RESOURCE_CLASS,
327                                 NULL, 0, &argc, argv);
328     }
329
330     srvDisplay = XtOpenDisplay(smGD.appCon, NULL, argv[0], SM_RESOURCE_CLASS,
331                                  NULL, 0, &argc, argv);
332
333     /*
334      * Initialize XSMP
335      */
336     if (!InitXSMP (argv[0]))
337         SM_EXIT(-1);
338
339     /* Added the following check to exit in case of error RK 09.08.93 */
340     if(smGD.display == NULL)
341     {
342         PrintError(DtError, GETMESSAGE(4, 1, "Invalid display name - exiting."));
343         SM_EXIT(-1);
344     }
345
346     /*
347      * Lock out other session managers from running - if there is one
348      * running already - exit
349      */
350     if(!_DtGetLock(smGD.display, SM_RUNNING_LOCK))
351     {
352         PrintError(DtError, GETMESSAGE(2, 2, "Another dtsession is currently running - exiting."));
353         SM_EXIT(-1);
354     }
355
356     /* JET - initialize for Xinerama, if present 4/12/2001 */
357 #ifdef USE_XINERAMA
358     smGD.DtXineramaInfo = _DtXineramaInit(smGD.display);
359
360 # ifdef DEBUG
361     if (smGD.DtXineramaInfo == NULL)
362       {                         /* No xinerama, how... sad. */
363         fprintf(stderr, "### JET SmMain: Xinerama NOT available.\n");
364       }
365     else
366       {
367         fprintf(stderr, "### JET SmMain: Xinerama available, scrns = %d\n",
368                 dpyinfo.DtXineramaInfo->numscreens);
369       }
370 # endif
371
372 #endif
373
374
375    /*
376     * Restore preferences
377     */
378     if (smGD.resourcePath[0] != '\0')
379     {
380       RestorePreferences(smGD.resourcePath);
381     }
382
383     /*
384      * Start up the color server
385      */
386     InitializeDtcolor(srvDisplay, smGD.sessionType);
387
388     /*
389      * AFTER the colors are set up - create the top level widget
390      * Set up a NULL WM_COMMAND property
391      */
392     n = 0;
393     XtSetArg(args[n], XmNbackground,
394              XBlackPixel(smGD.display, XDefaultScreen(smGD.display))); n++;
395     XtSetArg(args[n], XmNmappedWhenManaged, False); n++;
396     XtSetArg (args[n], XmNwidth, 1); n++;
397     XtSetArg (args[n], XmNheight, 1); n++;
398     smGD.topLevelWid = XtAppCreateShell (SM_RESOURCE_NAME, SM_RESOURCE_CLASS,
399                                          applicationShellWidgetClass,
400                                          smGD.display, args, n);
401     XtRealizeWidget(smGD.topLevelWid);
402
403     /*
404      * Select to get the lock on timeout if the user requests it
405      * and if the server supports it. This must be done before
406      * InitSMGlobals() so smGD.lockOnTimeoutStatus is known.
407      */
408 #if defined (USE_HPSSEXT)
409 #ifdef USE_HP_SPECIFIC_XLIB
410     tmp = XHPSSChangeNotify(smGD.display, &XaSmScreenSaveRet, 3);
411 #else /* USE_HP_SPECIFIC_XLIB */
412     tmp = -1;
413 #endif /* USE_HP_SPECIFIC_XLIB */
414 #elif defined (USE_X11SSEXT)
415     tmp = RegisterX11ScreenSaver(smGD.display, &smGD.ssEventType);
416 #else
417     tmp = -1;
418 #endif
419
420     if(tmp != 0)
421     {
422         smGD.lockOnTimeoutStatus = False;
423         XaSmScreenSaveRet = None;
424 #if defined (USE_X11SSEXT)
425         smGD.ssEventType = None;
426 #endif
427     }
428     else
429     {
430         smGD.lockOnTimeoutStatus = True;
431     }
432
433     InitSMGlobals();
434
435     /*
436      * Put the program into a wait state
437      */
438     ShowWaitState(True);
439
440     InitErrorHandler();
441
442     /*
443      * Restore resources for lang/resolution independence
444      */
445     if((smGD.resourcePath[0] != 0) || (smGD.compatMode == False))
446     {
447         RestoreIndependentResources();
448     }
449
450     /*
451      * Now restore the rest of the clients and the settings
452      */
453     if((smGD.clientPath[0] != 0) && (smGD.compatMode == False))
454     {
455         if(RestoreState() == -1)
456         {
457             StartWM();
458         }
459     }
460     else
461     {
462         if(smGD.compatMode == True)
463         {
464             /*
465              * dtstyle needs the DT_SESSION_STATE  even in
466              * compatibility mode
467              */
468             SetCompatState();
469         }
470         StartWM();
471     }
472
473     /*
474      * Run the user's startup script if there is one
475      */
476
477     if(smGD.compatMode == False)
478     {
479         StartEtc(False); /* run sessionetc */
480     }
481
482     InitProtocol ();
483
484     /*
485      * If we are in compatibility mode - kill the parent and leave the
486      * child running so that the script exits
487      */
488     if(smGD.compatMode == True)
489     {
490         KillParent();
491     }
492
493     /*
494      * Select for property notify on the top level window - so that
495      * when the style manager changes something - it is known
496      */
497     XGetWindowAttributes(smGD.display, smGD.topLevelWindow, &windAtt);
498     XSelectInput(smGD.display, smGD.topLevelWindow,
499                  windAtt.your_event_mask | PropertyChangeMask);
500
501     ShowWaitState(False);
502
503     /*
504      * Register for events
505      * - PropertyChange (maskable)
506      * - ClientMessage (non-maskable)
507      */
508     XtAddEventHandler(smGD.topLevelWid,
509                       PropertyChangeMask,
510                       True, ProcessEvent, NULL);
511
512     smGD.smState = READY;
513
514     while(1)
515     {
516       XtAppNextEvent(smGD.appCon, &next);
517       if (next.type != 0)
518       {
519 #if defined (USE_X11SSEXT)
520         if (next.type == smGD.ssEventType)
521         {
522          /*
523           * We should simply be calling XtDispatchEvent() but the toolkit
524           * doesn't seem to know how to dispatch a run-time generated
525           * event type.
526           */
527           ProcessEvent(smGD.topLevelWid, NULL, &next, NULL);
528         }
529         else
530         {
531           XtDispatchEvent(&next);
532         }
533 #else
534         XtDispatchEvent(&next);
535 #endif
536       }
537     }
538 }
539
540
541
542 \f
543 /*************************************<->*************************************
544  *
545  *  StopAll
546  *
547  *
548  *  Description:
549  *  -----------
550  *  Signal handler for SIGTERM. Causes dtsession to do a normal shutdown
551  *  procedure without saving any state.
552  *
553  *
554  *  Inputs:
555  *  ------
556  *  shutDown (state flag)
557  *
558  *
559  *  Outputs:
560  *  -------
561  *
562  *
563  *  Comments:
564  *  --------
565  *
566  *  We want to be careful to ignore the TERM signal if we are already
567  *  shutting down when it occurs.
568  *
569  *************************************<->***********************************/
570
571 static void
572 StopAll(int i)
573 {
574     ImmediateExit(-1, 0, True);
575 }
576
577 /*************************************<->*************************************
578  *
579  *  RegisterX11ScreenSaver
580  *
581  *
582  *  Description:
583  *  -----------
584  *  Register with X11 screen saver server extension for screen saver events.
585  *
586  *  Inputs:
587  *  ------
588  *  display - display from XtOpenDisplay()
589  *  pssEventType - pointer to buffer in which to return ss event type
590  *
591  *  Outputs:
592  *  -------
593  *  pssEventType - (rc=0) screen saver event type, (rc!=0) undefined
594  *
595  *  Returns:
596  *  -------
597  *  0 - successfully registered for screen saver events
598  *  other - failed to register for screen saver events
599  *
600  *  Comments:
601  *  --------
602  *
603  *************************************<->***********************************/
604
605 #if defined (USE_X11SSEXT)
606 static int
607 RegisterX11ScreenSaver(
608   Display *display,
609   int *pssEventType)
610 {
611  /*
612   * Register with X11 screen saver server extension.
613   */
614   int result = -1;
615   int ssErrorBase;
616   int majorVersion;
617   int minorVersion;
618   int screen;
619   Window root;
620   XID xid;
621   Atom type;
622
623   if (XScreenSaverQueryExtension(display, pssEventType, &ssErrorBase) &&
624       XScreenSaverQueryVersion(display, &majorVersion, &minorVersion) &&
625       majorVersion == 1)
626   {
627    /*
628     * Server supports requested version of X11 screen saver extension.
629     */
630     screen = DefaultScreen(display);
631     root = DefaultRootWindow(display);
632
633     XGrabServer(display);
634     if (!XScreenSaverGetRegistered(display, screen, &xid, &type))
635     {
636      /*
637       * No other clients registered with this server so register this one.
638       */
639       XScreenSaverRegister(display, screen, XtWindow(smGD.topLevelWid), XA_WINDOW);
640       result = 0;
641     }
642     XUngrabServer(display);
643
644     if (result == 0)
645     {
646       XSetWindowAttributes attr;
647
648      /*
649       * Registration successful.
650       */
651       XScreenSaverSelectInput(display, root,
652                               ScreenSaverNotifyMask|ScreenSaverCycleMask);
653
654       /* Even though OverrideRedirect is the default attribute in this
655        *  check, lets make sure it's set, and make sure only the
656        *  CWOverrideRedirect attr is being looked at.  The rest is
657        *  just random garbage anyway, since it's allocated from the stack.
658        */
659       attr.override_redirect = True;
660       XScreenSaverSetAttributes(display, root, 0, 0, 1, 1, 0, CopyFromParent,
661                           CopyFromParent, CopyFromParent, CWOverrideRedirect, &attr);
662     }
663   }
664   return(result);
665 }
666 #endif /* USE_X11SSEXT */