Link with C++ linker
[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 librararies 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 #ifdef __osf__
59 #include <sys/access.h>
60 #endif
61 #include <X11/Intrinsic.h>
62 #include <X11/StringDefs.h>
63
64 #if defined (USE_X11SSEXT)
65 #include <X11/extensions/scrnsaver.h>
66 #endif /* USE_X11SSEXT */
67
68 #include <Xm/Xm.h>
69 #include <Dt/UserMsg.h>
70 #include <Dt/EnvControlP.h>
71 #include <Dt/DtP.h>
72 #include "Sm.h"
73 #include "SmError.h"
74 #include "SmGlobals.h"
75 #include "SmCommun.h"
76 #include "SmRestore.h"
77 #include "SmUI.h"
78 #include "SrvPalette.h"
79 #include "SmProtocol.h"
80 #include "SmXSMP.h"
81
82 /*
83  * Internal Functions
84  */
85 void main(int, char **);
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
102
103 \f
104 /*************************************<->*************************************
105  *
106  *  main (argc, argv)
107  *
108  *
109  *  Description:
110  *  -----------
111  *  Controls the startup and event dispatching of the session manager.
112  *
113  *
114  *  Inputs:
115  *  ------
116  *  argc = command line options
117  *  argv = number of command line options
118  *
119  *
120  *  Outputs:
121  *  -------
122  *
123  *
124  *  Comments:
125  *  --------
126  *
127  *************************************<->***********************************/
128 void
129 main (int argc,
130           char  **argv)
131 {
132     int                         n, tmp;
133     Arg                         args[10];
134     XEvent                      next;
135     String                      tmpString;
136     XWindowAttributes           windAtt;
137     XPropertyEvent              *pEvent = (XPropertyEvent *) &next;
138     int                         status;
139     struct stat                 buf;
140     Display                     *srvDisplay;
141     struct sigaction            stopvec;
142     char                        *lang;
143
144 #ifdef __osf__
145
146 # include <sys/sysinfo.h>
147 # include <sys/proc.h>
148
149     unsigned long        op;
150     int                  buffer[2];
151     unsigned long        nbytes = 1;
152     char*                arg = 0;
153     unsigned long        flag = 0;
154
155     int                  ssi_status;
156
157     op = SSI_NVPAIRS;
158
159     buffer[0] = SSIN_UACPROC;
160     buffer[1] =  UAC_NOPRINT;
161 # ifdef DEBUG_UAC
162     buffer[1] |= UAC_SIGBUS;
163 # endif
164
165     ssi_status = setsysinfo ( op, buffer, nbytes, arg, flag );
166 #endif
167
168     setlocale( LC_ALL, "" );
169     XtSetLanguageProc( NULL, NULL, NULL );
170
171     smGD.smState = IN_PROCESS;
172     smGD.programName = strdup (argv[0]);
173
174     /*
175      * We report some errors before we call the DtInitialize procedure.
176      * The Dt initialize procedure sets this name.  If we report
177      * an error via DtSimple error before this is set we see the message
178      * prepended with <unknown program name> in the error log.
179      */
180     DtProgName = SM_RESOURCE_NAME ;
181     
182 #ifdef DEBUG
183     if(argc > 5)
184     {
185         int junk = 1;
186         while(junk)
187         {
188            junk = 1;
189         }
190     }
191 #endif /*  DEBUG */
192     /*
193      * Set our effective gid to the real gid until we need it to be
194      * sys (during contention management)
195      */
196     smGD.runningGID = getgid();
197     smGD.conMgmtGID = getegid();
198
199     /*
200      * Set uid up according to whether this is a secure system
201      * Secure systems need root priviledges to read the /etc/passwd file
202      */
203     smGD.runningUID = getuid();
204
205 #ifdef SECURE_SYS_PATH
206     status = stat(SECURE_SYS_PATH, &buf);
207 #else
208     status = -1;
209 #endif
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     if(status == -1)
222     {
223         /*
224          * this is not a secure system - remove all suid priviledges
225          */
226         smGD.unLockUID = smGD.runningUID;
227         smGD.secureSystem = False;
228         SM_SETESUID(smGD.runningUID);
229     }
230     else
231     {
232        /*
233         * Save the root priviledge to be restored when trying to unlock
234         */
235         smGD.unLockUID = geteuid();
236         smGD.secureSystem = True;
237         SM_SETEUID(smGD.runningUID);
238     }
239
240 #ifdef __hpux
241     setresgid(-1, smGD.runningGID, -1);
242 #else  /* _AIX or any other system */
243 #ifndef SVR4
244     setregid(smGD.conMgmtGID, smGD.runningGID);
245 #else
246     setgid(smGD.conMgmtGID);
247     setegid(smGD.runningGID);
248 #endif
249 #endif /* !hpux */
250
251    /*
252     * Set up POSIX sigaction structs
253     */
254
255     /*
256      * Must set SIGPIPE to SIG_IGN so the process does not exit
257      * if a child terminates unexpectedly during an I/O operation
258      * that raises SIGPIPE.  Note that before this process exec's
259      * any subprocesses, SIGPIPE must be set to SIG_DFL.
260      */
261     sigemptyset(&stopvec.sa_mask);
262     stopvec.sa_flags = 0;
263     stopvec.sa_handler = SIG_IGN;
264     (void) sigaction(SIGPIPE, &stopvec, (struct sigaction *) NULL);
265
266     stopvec.sa_handler = StopAll;
267     sigemptyset(&stopvec.sa_mask);
268     stopvec.sa_flags = 0;
269  
270     smGD.childvec.sa_handler = WaitChildDeath;
271     sigemptyset(&smGD.childvec.sa_mask);
272     smGD.childvec.sa_flags = 0;
273
274     smGD.defvec.sa_handler = SIG_DFL;
275     sigemptyset(&smGD.defvec.sa_mask);
276     smGD.defvec.sa_flags = 0;
277
278     smGD.appCon = 0;
279     smGD.display = 0;
280
281     /*
282      * This must be done before XtToolkitInitialize
283      * to set up the local environment
284      */
285     _DtEnvControl(DT_ENV_SET);
286     _DtEnvControl(DT_ENV_SET_BIN);
287
288     /*
289      * Set up NLS error messages first
290      */
291     InitNlsStrings();
292
293     /*
294      * Set the paths of where resources are to be restored from
295      */
296     SetRestorePath(argc, argv);
297
298     /*
299      * The first thing that must happen is that resources must be restored
300      * so that my resources will be correct
301      */
302     if(smGD.compatMode == False)
303     {
304      /*
305       * Load session resources.
306       */
307       RestoreResources(False,
308                        "-load",
309                        "-system",
310                        "-xdefaults",
311                        smGD.resourcePath[0] != '\0' ? "-file" : NULL,
312                        smGD.resourcePath,
313                        NULL);
314     }
315
316     /*
317      * Set up to catch SIGTERM
318      */
319     stopvec.sa_handler = StopAll;
320     sigemptyset(&stopvec.sa_mask);
321     stopvec.sa_flags = 0;
322
323     sigaction(SIGTERM, &stopvec, (struct sigaction *) NULL);
324
325     /*
326      * Now set up a communication with the toolkit
327      *
328      * Create one display connection for dtsession, and one for
329      * the color server. We cannot share a display connection since
330      * motif creates a display object for the color server's display during
331      * color server initialization. Since the color server is not yet 
332      * operational, any dialogs (ie the dtsession logout confirmation
333      * dialogs) created on that display do not get the color server colors. 
334      * The dtsession display object is created after color server
335      * initialization is complete.
336      */
337     if (smGD.appCon == 0) {
338         /*
339          * The following code will have been initialized if the
340          * session creation code posted a dialog.
341          */
342         XtToolkitInitialize();
343         smGD.appCon = XtCreateApplicationContext();
344         smGD.display = XtOpenDisplay(smGD.appCon, NULL, argv[0], 
345                                 SM_RESOURCE_CLASS,
346                                 NULL, 0, &argc, argv);
347     }
348
349     srvDisplay = XtOpenDisplay(smGD.appCon, NULL, argv[0], SM_RESOURCE_CLASS,
350                                  NULL, 0, &argc, argv);
351
352     /*
353      * Initialize XSMP 
354      */
355     if (!InitXSMP (argv[0]))
356         SM_EXIT(-1);
357
358     /* Added the following check to exit in case of error RK 09.08.93 */
359     if(smGD.display == NULL)
360     {
361         PrintError(DtError, GETMESSAGE(4, 1, "Invalid display name - exiting."));
362         SM_EXIT(-1);
363     }
364
365     /*
366      * Lock out other session managers from running - if there is one
367      * running already - exit
368      */
369     if(!_DtGetLock(smGD.display, SM_RUNNING_LOCK))
370     {
371         PrintError(DtError, GETMESSAGE(2, 2, "Another dtsession is currently running - exiting."));
372         SM_EXIT(-1);
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] != NULL) || (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] != NULL) && (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 #ifdef __osf__
515     /* If we've just populated a new .dtprofile into the user's home
516      * directory, put up a popup dialog explaining the need to edit it
517      * to allow .login/.profile to work properly
518      */
519
520     arg = getenv("DTNEWPROFILE");
521     if (arg)
522         WarnNewProfile();
523 #endif
524
525     while(1)
526     {
527       XtAppNextEvent(smGD.appCon, &next);
528       if (next.type != 0)
529       {
530 #if defined (USE_X11SSEXT)
531         if (next.type == smGD.ssEventType)
532         {
533          /*
534           * We should simply be calling XtDispatchEvent() but the toolkit
535           * doesn't seem to know how to dispatch a run-time generated
536           * event type.
537           */
538           ProcessEvent(smGD.topLevelWid, NULL, &next, NULL);
539         }
540         else
541         {
542           XtDispatchEvent(&next);
543         }
544 #else
545         XtDispatchEvent(&next);
546 #endif
547       }
548     }
549 }
550
551
552
553 \f
554 /*************************************<->*************************************
555  *
556  *  StopAll
557  *
558  *
559  *  Description:
560  *  -----------
561  *  Signal handler for SIGTERM. Causes dtsession to do a normal shutdown
562  *  procedure without saving any state.
563  *
564  *
565  *  Inputs:
566  *  ------
567  *  shutDown (state flag)
568  *
569  *
570  *  Outputs:
571  *  -------
572  *
573  *
574  *  Comments:
575  *  --------
576  *
577  *  We want to be careful to ignore the TERM signal if we are already
578  *  shutting down when it occurs.
579  *
580  *************************************<->***********************************/
581
582 static void
583 StopAll(int i)
584 {
585     ImmediateExit(-1, 0, True);
586 }
587
588 /*************************************<->*************************************
589  *
590  *  RegisterX11ScreenSaver
591  *
592  *
593  *  Description:
594  *  -----------
595  *  Register with X11 screen saver server extension for screen saver events. 
596  *
597  *  Inputs:
598  *  ------
599  *  display - display from XtOpenDisplay()
600  *  pssEventType - pointer to buffer in which to return ss event type
601  *
602  *  Outputs:
603  *  -------
604  *  pssEventType - (rc=0) screen saver event type, (rc!=0) undefined
605  *
606  *  Returns:
607  *  -------
608  *  0 - successfully registered for screen saver events
609  *  other - failed to register for screen saver events
610  *
611  *  Comments:
612  *  --------
613  *
614  *************************************<->***********************************/
615
616 #if defined (USE_X11SSEXT)
617 static int
618 RegisterX11ScreenSaver(
619   Display *display,
620   int *pssEventType)
621 {
622  /*
623   * Register with X11 screen saver server extension.
624   */
625   int result = -1;
626   int ssErrorBase;
627   int majorVersion;
628   int minorVersion;
629   int screen;
630   Window root;
631   XID xid;
632   XSetWindowAttributes attr;
633   Atom type;
634
635   if (XScreenSaverQueryExtension(display, pssEventType, &ssErrorBase) &&
636       XScreenSaverQueryVersion(display, &majorVersion, &minorVersion) &&
637       majorVersion == 1)
638   {
639    /*
640     * Server supports requested version of X11 screen saver extension.
641     */
642     screen = DefaultScreen(display);
643     root = DefaultRootWindow(display);
644    
645     XGrabServer(display);
646     if (!XScreenSaverGetRegistered(display, screen, &xid, &type))
647     {
648      /* 
649       * No other clients registered with this server so register this one.
650       */
651       XScreenSaverRegister(display, screen, XtWindow(smGD.topLevelWid), XA_WINDOW);
652       result = 0;
653     }
654     XUngrabServer(display);
655
656     if (result == 0)
657     {
658      /* 
659       * Registration successful.
660       */
661       XScreenSaverSelectInput(display, root, 
662                               ScreenSaverNotifyMask|ScreenSaverCycleMask);
663       XScreenSaverSetAttributes(display, root, 0, 0, 1, 1, 0, CopyFromParent,
664                           CopyFromParent, CopyFromParent, CWBackPixel, &attr);
665     }
666   }
667   return(result);   
668 }
669 #endif /* USE_X11SSEXT */
670