remove OSF1 support
[oweals/cde.git] / cde / programs / dtsession / 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 #ifdef SVR4
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 linux                    /* linux always needs to be setup as secure */
187
188     /*
189      * Save the root privilege to be restored when trying to unlock
190      */
191     smGD.unLockUID = geteuid();
192     smGD.secureSystem = True;
193     SM_SETEUID(smGD.runningUID);
194     
195 #else
196
197 # ifdef SECURE_SYS_PATH
198     status = stat(SECURE_SYS_PATH, &buf);
199 # else
200     status = -1;
201 # endif
202
203     if(status == -1)
204     {
205         /*
206          * this is not a secure system - remove all suid privileges
207          */
208         smGD.unLockUID = smGD.runningUID;
209         smGD.secureSystem = False;
210         SM_SETESUID(smGD.runningUID);
211     }
212     else
213     {
214        /*
215         * Save the root privilege to be restored when trying to unlock
216         */
217         smGD.unLockUID = geteuid();
218         smGD.secureSystem = True;
219         SM_SETEUID(smGD.runningUID);
220     }
221
222 #endif /* linux */
223
224     /*
225      * Initialize LANG if it isn't defined.
226      */
227     if ((lang = getenv ("LANG")) == NULL)
228     {
229         lang = XtMalloc (7);
230         (void) strcpy (lang, "LANG=C");
231         (void) putenv (lang);
232     }
233
234 #ifdef __hpux
235     setresgid(-1, smGD.runningGID, -1);
236 #else  /* _AIX or any other system */
237 #ifndef SVR4
238     setregid(smGD.conMgmtGID, smGD.runningGID);
239 #else
240     setgid(smGD.conMgmtGID);
241     setegid(smGD.runningGID);
242 #endif
243 #endif /* !hpux */
244
245    /*
246     * Set up POSIX sigaction structs
247     */
248
249     /*
250      * Must set SIGPIPE to SIG_IGN so the process does not exit
251      * if a child terminates unexpectedly during an I/O operation
252      * that raises SIGPIPE.  Note that before this process exec's
253      * any subprocesses, SIGPIPE must be set to SIG_DFL.
254      */
255     sigemptyset(&stopvec.sa_mask);
256     stopvec.sa_flags = 0;
257     stopvec.sa_handler = SIG_IGN;
258     (void) sigaction(SIGPIPE, &stopvec, (struct sigaction *) NULL);
259
260     stopvec.sa_handler = StopAll;
261     sigemptyset(&stopvec.sa_mask);
262     stopvec.sa_flags = 0;
263  
264     smGD.childvec.sa_handler = WaitChildDeath;
265     sigemptyset(&smGD.childvec.sa_mask);
266     smGD.childvec.sa_flags = 0;
267
268     smGD.defvec.sa_handler = SIG_DFL;
269     sigemptyset(&smGD.defvec.sa_mask);
270     smGD.defvec.sa_flags = 0;
271
272     smGD.appCon = 0;
273     smGD.display = 0;
274
275     /*
276      * This must be done before XtToolkitInitialize
277      * to set up the local environment
278      */
279     _DtEnvControl(DT_ENV_SET);
280     _DtEnvControl(DT_ENV_SET_BIN);
281
282     /*
283      * Set up NLS error messages first
284      */
285     InitNlsStrings();
286
287     /*
288      * Set the paths of where resources are to be restored from
289      */
290     SetRestorePath(argc, argv);
291
292     /*
293      * The first thing that must happen is that resources must be restored
294      * so that my resources will be correct
295      */
296     if(smGD.compatMode == False)
297     {
298      /*
299       * Load session resources.
300       */
301       RestoreResources(False,
302                        "-load",
303                        "-system",
304                        "-xdefaults",
305                        smGD.resourcePath[0] != '\0' ? "-file" : NULL,
306                        smGD.resourcePath,
307                        NULL);
308     }
309
310     /*
311      * Set up to catch SIGTERM
312      */
313     stopvec.sa_handler = StopAll;
314     sigemptyset(&stopvec.sa_mask);
315     stopvec.sa_flags = 0;
316
317     sigaction(SIGTERM, &stopvec, (struct sigaction *) NULL);
318
319     /*
320      * Now set up a communication with the toolkit
321      *
322      * Create one display connection for dtsession, and one for
323      * the color server. We cannot share a display connection since
324      * motif creates a display object for the color server's display during
325      * color server initialization. Since the color server is not yet 
326      * operational, any dialogs (ie the dtsession logout confirmation
327      * dialogs) created on that display do not get the color server colors. 
328      * The dtsession display object is created after color server
329      * initialization is complete.
330      */
331     if (smGD.appCon == 0) {
332         /*
333          * The following code will have been initialized if the
334          * session creation code posted a dialog.
335          */
336         XtToolkitInitialize();
337         smGD.appCon = XtCreateApplicationContext();
338         smGD.display = XtOpenDisplay(smGD.appCon, NULL, argv[0], 
339                                 SM_RESOURCE_CLASS,
340                                 NULL, 0, &argc, argv);
341     }
342
343     srvDisplay = XtOpenDisplay(smGD.appCon, NULL, argv[0], SM_RESOURCE_CLASS,
344                                  NULL, 0, &argc, argv);
345
346     /*
347      * Initialize XSMP 
348      */
349     if (!InitXSMP (argv[0]))
350         SM_EXIT(-1);
351
352     /* Added the following check to exit in case of error RK 09.08.93 */
353     if(smGD.display == NULL)
354     {
355         PrintError(DtError, GETMESSAGE(4, 1, "Invalid display name - exiting."));
356         SM_EXIT(-1);
357     }
358
359     /*
360      * Lock out other session managers from running - if there is one
361      * running already - exit
362      */
363     if(!_DtGetLock(smGD.display, SM_RUNNING_LOCK))
364     {
365         PrintError(DtError, GETMESSAGE(2, 2, "Another dtsession is currently running - exiting."));
366         SM_EXIT(-1);
367     }
368
369     /* JET - initialize for Xinerama, if present 4/12/2001 */
370 #ifdef USE_XINERAMA
371     smGD.DtXineramaInfo = _DtXineramaInit(smGD.display);
372
373 # ifdef DEBUG
374     if (smGD.DtXineramaInfo == NULL)
375       {                         /* No xinerama, how... sad. */
376         fprintf(stderr, "### JET SmMain: Xinerama NOT available.\n");
377       }
378     else
379       {
380         fprintf(stderr, "### JET SmMain: Xinerama available, scrns = %d\n",
381                 dpyinfo.DtXineramaInfo->numscreens);
382       }
383 # endif
384
385 #endif
386
387
388    /*
389     * Restore preferences
390     */
391     if (smGD.resourcePath[0] != '\0')
392     {
393       RestorePreferences(smGD.resourcePath);
394     }
395
396     /*
397      * Start up the color server
398      */
399     InitializeDtcolor(srvDisplay, smGD.sessionType);
400
401     /*
402      * AFTER the colors are set up - create the top level widget
403      * Set up a NULL WM_COMMAND property
404      */
405     n = 0;
406     XtSetArg(args[n], XmNbackground,
407              XBlackPixel(smGD.display, XDefaultScreen(smGD.display))); n++;
408     XtSetArg(args[n], XmNmappedWhenManaged, False); n++;
409     XtSetArg (args[n], XmNwidth, 1); n++;
410     XtSetArg (args[n], XmNheight, 1); n++;
411     smGD.topLevelWid = XtAppCreateShell (SM_RESOURCE_NAME, SM_RESOURCE_CLASS,
412                                          applicationShellWidgetClass,
413                                          smGD.display, args, n);
414     XtRealizeWidget(smGD.topLevelWid);
415
416     /*
417      * Select to get the lock on timeout if the user requests it
418      * and if the server supports it. This must be done before
419      * InitSMGlobals() so smGD.lockOnTimeoutStatus is known.
420      */
421 #if defined (USE_HPSSEXT)
422 #ifdef USE_HP_SPECIFIC_XLIB
423     tmp = XHPSSChangeNotify(smGD.display, &XaSmScreenSaveRet, 3);
424 #else /* USE_HP_SPECIFIC_XLIB */
425     tmp = -1;
426 #endif /* USE_HP_SPECIFIC_XLIB */
427 #elif defined (USE_X11SSEXT)
428     tmp = RegisterX11ScreenSaver(smGD.display, &smGD.ssEventType);
429 #else
430     tmp = -1;
431 #endif
432
433     if(tmp != 0)
434     {
435         smGD.lockOnTimeoutStatus = False;
436         XaSmScreenSaveRet = None;
437 #if defined (USE_X11SSEXT)
438         smGD.ssEventType = None;
439 #endif
440     }
441     else
442     {
443         smGD.lockOnTimeoutStatus = True;
444     }
445
446     InitSMGlobals();
447
448     /*
449      * Put the program into a wait state
450      */
451     ShowWaitState(True);
452
453     InitErrorHandler();
454
455     /*
456      * Restore resources for lang/resolution independence
457      */
458     if((smGD.resourcePath[0] != 0) || (smGD.compatMode == False))
459     {
460         RestoreIndependentResources();
461     }
462
463     /*
464      * Now restore the rest of the clients and the settings
465      */
466     if((smGD.clientPath[0] != 0) && (smGD.compatMode == False))
467     {
468         if(RestoreState() == -1)
469         {
470             StartWM();
471         }
472     }
473     else
474     {
475         if(smGD.compatMode == True)
476         {
477             /*
478              * dtstyle needs the DT_SESSION_STATE  even in
479              * compatibility mode
480              */
481             SetCompatState();
482         }
483         StartWM();
484     }
485
486     /* 
487      * Run the user's startup script if there is one
488      */
489
490     if(smGD.compatMode == False)
491     {
492         StartEtc(False); /* run sessionetc */
493     }
494
495     InitProtocol ();
496
497     /*
498      * If we are in compatibility mode - kill the parent and leave the
499      * child running so that the script exits
500      */
501     if(smGD.compatMode == True)
502     {
503         KillParent();
504     }
505
506     /*
507      * Select for property notify on the top level window - so that
508      * when the style manager changes something - it is known
509      */
510     XGetWindowAttributes(smGD.display, smGD.topLevelWindow, &windAtt);
511     XSelectInput(smGD.display, smGD.topLevelWindow,
512                  windAtt.your_event_mask | PropertyChangeMask);
513
514     ShowWaitState(False);
515
516     /*
517      * Register for events
518      * - PropertyChange (maskable)
519      * - ClientMessage (non-maskable)
520      */
521     XtAddEventHandler(smGD.topLevelWid,
522                       PropertyChangeMask,
523                       True, ProcessEvent, NULL);
524
525     smGD.smState = READY;
526
527     while(1)
528     {
529       XtAppNextEvent(smGD.appCon, &next);
530       if (next.type != 0)
531       {
532 #if defined (USE_X11SSEXT)
533         if (next.type == smGD.ssEventType)
534         {
535          /*
536           * We should simply be calling XtDispatchEvent() but the toolkit
537           * doesn't seem to know how to dispatch a run-time generated
538           * event type.
539           */
540           ProcessEvent(smGD.topLevelWid, NULL, &next, NULL);
541         }
542         else
543         {
544           XtDispatchEvent(&next);
545         }
546 #else
547         XtDispatchEvent(&next);
548 #endif
549       }
550     }
551 }
552
553
554
555 \f
556 /*************************************<->*************************************
557  *
558  *  StopAll
559  *
560  *
561  *  Description:
562  *  -----------
563  *  Signal handler for SIGTERM. Causes dtsession to do a normal shutdown
564  *  procedure without saving any state.
565  *
566  *
567  *  Inputs:
568  *  ------
569  *  shutDown (state flag)
570  *
571  *
572  *  Outputs:
573  *  -------
574  *
575  *
576  *  Comments:
577  *  --------
578  *
579  *  We want to be careful to ignore the TERM signal if we are already
580  *  shutting down when it occurs.
581  *
582  *************************************<->***********************************/
583
584 static void
585 StopAll(int i)
586 {
587     ImmediateExit(-1, 0, True);
588 }
589
590 /*************************************<->*************************************
591  *
592  *  RegisterX11ScreenSaver
593  *
594  *
595  *  Description:
596  *  -----------
597  *  Register with X11 screen saver server extension for screen saver events. 
598  *
599  *  Inputs:
600  *  ------
601  *  display - display from XtOpenDisplay()
602  *  pssEventType - pointer to buffer in which to return ss event type
603  *
604  *  Outputs:
605  *  -------
606  *  pssEventType - (rc=0) screen saver event type, (rc!=0) undefined
607  *
608  *  Returns:
609  *  -------
610  *  0 - successfully registered for screen saver events
611  *  other - failed to register for screen saver events
612  *
613  *  Comments:
614  *  --------
615  *
616  *************************************<->***********************************/
617
618 #if defined (USE_X11SSEXT)
619 static int
620 RegisterX11ScreenSaver(
621   Display *display,
622   int *pssEventType)
623 {
624  /*
625   * Register with X11 screen saver server extension.
626   */
627   int result = -1;
628   int ssErrorBase;
629   int majorVersion;
630   int minorVersion;
631   int screen;
632   Window root;
633   XID xid;
634   Atom type;
635
636   if (XScreenSaverQueryExtension(display, pssEventType, &ssErrorBase) &&
637       XScreenSaverQueryVersion(display, &majorVersion, &minorVersion) &&
638       majorVersion == 1)
639   {
640    /*
641     * Server supports requested version of X11 screen saver extension.
642     */
643     screen = DefaultScreen(display);
644     root = DefaultRootWindow(display);
645    
646     XGrabServer(display);
647     if (!XScreenSaverGetRegistered(display, screen, &xid, &type))
648     {
649      /* 
650       * No other clients registered with this server so register this one.
651       */
652       XScreenSaverRegister(display, screen, XtWindow(smGD.topLevelWid), XA_WINDOW);
653       result = 0;
654     }
655     XUngrabServer(display);
656
657     if (result == 0)
658     {
659       XSetWindowAttributes attr;
660
661      /* 
662       * Registration successful.
663       */
664       XScreenSaverSelectInput(display, root, 
665                               ScreenSaverNotifyMask|ScreenSaverCycleMask);
666
667       /* Even though OverrideRedirect is the default attribute in this
668        *  check, lets make sure it's set, and make sure only the
669        *  CWOverrideRedirect attr is being looked at.  The rest is
670        *  just random garbage anyway, since it's allocated from the stack.
671        */
672       attr.override_redirect = True;
673       XScreenSaverSetAttributes(display, root, 0, 0, 1, 1, 0, CopyFromParent,
674                           CopyFromParent, CopyFromParent, CWOverrideRedirect, &attr);
675     }
676   }
677   return(result);   
678 }
679 #endif /* USE_X11SSEXT */
680