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