Make a branch to make krunner Good Enough For Aaron™.
[kdebase/uwolfer.git] / workspace / kdm / backend / dm.c
blob29b37bb7b14ab48a3be40f4552463b0b0d0284fc
1 /*
3 Copyright 1988, 1998 The Open Group
4 Copyright 2000-2005 Oswald Buddenhagen <ossi@kde.org>
6 Permission to use, copy, modify, distribute, and sell this software and its
7 documentation for any purpose is hereby granted without fee, provided that
8 the above copyright notice appear in all copies and that both that
9 copyright notice and this permission notice appear in supporting
10 documentation.
12 The above copyright notice and this permission notice shall be included
13 in all copies or substantial portions of the Software.
15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
16 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18 IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
19 OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
20 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
21 OTHER DEALINGS IN THE SOFTWARE.
23 Except as contained in this notice, the name of a copyright holder shall
24 not be used in advertising or otherwise to promote the sale, use or
25 other dealings in this Software without prior written authorization
26 from the copyright holder.
31 * xdm - display manager daemon
32 * Author: Keith Packard, MIT X Consortium
34 * display manager
37 #include "dm.h"
38 #include "dm_auth.h"
39 #include "dm_error.h"
41 #include <stdio.h>
42 #include <string.h>
43 #include <unistd.h>
44 #include <stdarg.h>
45 #include <signal.h>
46 #include <sys/stat.h>
48 #ifdef HAVE_VTS
49 # include <sys/ioctl.h>
50 # include <sys/vt.h>
51 #endif
53 static void sigHandler( int n );
54 static int scanConfigs( int force );
55 static void startDisplays( void );
56 #define XS_KEEP 0
57 #define XS_RESTART 1
58 #define XS_RETRY 2
59 static void exitDisplay( struct display *d, int endState, int serverCmd, int goodExit );
60 static void rStopDisplay( struct display *d, int endState );
61 static void mainLoop( void );
63 static int signalFds[2];
65 #if !defined(HAVE_SETPROCTITLE) && !defined(NOXDMTITLE)
66 static char *title;
67 static int titleLen;
68 #endif
70 static int storePid( void );
72 static int stopping;
73 SdRec sdRec = { 0, 0, 0, TO_INF, TO_INF, 0, 0, 0 };
75 time_t now;
77 #if KDM_LIBEXEC_STRIP != -1
78 char *progpath;
79 #endif
80 #if KDM_LIBEXEC_STRIP
81 char *progname;
82 #endif
83 char *prog;
85 int
86 main( int argc, char **argv )
88 int oldpid, oldumask, fd, parentPid;
89 char *pt, *errorLogFile, **opts;
91 /* make sure at least world write access is disabled */
92 if (((oldumask = umask( 022 )) & 002) == 002)
93 (void)umask( oldumask );
95 /* give /dev/null as stdin */
96 if ((fd = open( "/dev/null", O_RDONLY )) > 0) {
97 dup2( fd, 0 );
98 close( fd );
100 if (fcntl( 1, F_GETFD ) < 0)
101 dup2( 0, 1 );
102 if (fcntl( 2, F_GETFD ) < 0)
103 dup2( 0, 2 );
105 #if KDM_LIBEXEC_STRIP == -1
106 prog = strrchr( argv[0], '/' );
107 progname = prog = prog ? prog + 1 : argv[0];
108 #else
109 if (argv[0][0] == '/') {
110 if (!strDup( &progpath, argv[0] ))
111 panic( "Out of memory" );
112 } else
113 # ifdef __linux__
115 /* note that this will resolve symlinks ... */
116 int len;
117 char fullpath[PATH_MAX];
118 if ((len = readlink( "/proc/self/exe", fullpath, sizeof(fullpath) )) < 0)
119 panic( "Invoke with full path specification or mount /proc" );
120 if (!strNDup( &progpath, fullpath, len ))
121 panic( "Out of memory" );
123 # else
124 # if 0
125 panic( "Must be invoked with full path specification" );
126 # else
128 char directory[PATH_MAX+1];
129 if (!getcwd( directory, sizeof(directory) ))
130 panic( "Can't find myself (getcwd failed)" );
131 if (strchr( argv[0], '/' ))
132 strApp( &progpath, directory, "/", argv[0], (char *)0 );
133 else {
134 int len;
135 char *path, *pathe, *name, *thenam, nambuf[PATH_MAX+1];
137 if (!(path = getenv( "PATH" )))
138 panic( "Can't find myself (no PATH)" );
139 len = strlen( argv[0] );
140 name = nambuf + PATH_MAX - len;
141 memcpy( name, argv[0], len + 1 );
142 *--name = '/';
143 do {
144 if (!(pathe = strchr( path, ':' )))
145 pathe = path + strlen( path );
146 len = pathe - path;
147 if (!len || (len == 1 && *path == '.')) {
148 len = strlen( directory );
149 path = directory;
151 thenam = name - len;
152 if (thenam >= nambuf) {
153 memcpy( thenam, path, len );
154 if (!access( thenam, X_OK ))
155 goto found;
157 path = pathe;
158 } while (*path++ != '\0');
159 panic( "Can't find myself (not in PATH)" );
160 found:
161 if (!strDup( &progpath, thenam ))
162 panic( "Out of memory" );
165 # endif
166 # endif
167 prog = strrchr( progpath, '/' ) + 1;
168 # if KDM_LIBEXEC_STRIP
169 for (progname = pt = prog, fd = 0; fd < KDM_LIBEXEC_STRIP + 1; fd++) {
170 for (;;) {
171 pt--;
172 if (pt == progpath)
173 panic( "Executable is obviously located outside BINDIR" );
174 if (*pt == '/')
175 break;
178 *pt = 0;
179 # endif
180 #endif
182 #if !defined(HAVE_SETPROCTITLE) && !defined(NOXDMTITLE)
183 title = argv[0];
184 titleLen = (argv[argc - 1] + strlen( argv[argc - 1] )) - title;
185 #endif
188 * Parse command line options
190 parentPid = getppid();
191 errorLogFile = 0;
192 if (!(opts = Malloc( 2 * sizeof(char *) )))
193 return 1;
194 opts[0] = (char *)"";
195 opts[1] = 0;
196 while (*++argv) {
197 if (**argv != '-')
198 break;
199 pt = *argv + 1;
200 if (*pt == '-')
201 pt++;
202 if (!strcmp( pt, "help" ) || !strcmp( pt, "h" )) {
203 printf( "Usage: %s [options] [tty]\n"
204 " -daemon\t - Daemonize even when started by init\n"
205 " -nodaemon\t - Do not daemonize even when started from command line\n"
206 " -config <file> - Use alternative master configuration file\n"
207 " -xrm <res>\t - Override frontend-specific resource\n"
208 " -error <file>\t - Use alternative log file\n"
209 " -debug <num>\t - Debug option bitfield:\n"
210 "\t\t\t0x1 - core log\n"
211 "\t\t\t0x2 - config reader log\n"
212 "\t\t\t0x4 - greeter log\n"
213 "\t\t\t0x8 - IPC log\n"
214 "\t\t\t0x10 - session sub-daemon post-fork delay\n"
215 "\t\t\t0x20 - config reader post-start delay\n"
216 "\t\t\t0x40 - greeter post-start delay\n"
217 "\t\t\t0x80 - do not use syslog\n"
218 "\t\t\t0x100 - core Xauth log\n"
219 "\t\t\t0x200 - debug greeter theming\n"
220 "\t\t\t0x400 - valgrind config reader and greeter\n"
221 "\t\t\t0x800 - strace config reader and greeter\n"
222 , prog );
223 exit( 0 );
224 } else if (!strcmp( pt, "daemon" ))
225 parentPid = 0;
226 else if (!strcmp( pt, "nodaemon" ))
227 parentPid = 1;
228 else if (argv[1] && !strcmp( pt, "config" ))
229 strDup( opts, *++argv );
230 else if (argv[1] && !strcmp( pt, "xrm" ))
231 opts = addStrArr( opts, *++argv, -1 );
232 else if (argv[1] && !strcmp( pt, "debug" ))
233 sscanf( *++argv, "%i", &debugLevel );
234 else if (argv[1] && (!strcmp( pt, "error" ) || !strcmp( pt, "logfile" )))
235 errorLogFile = *++argv;
236 else {
237 fprintf( stderr, "\"%s\" is an unknown option or is missing a parameter\n", *argv );
238 exit( 1 );
243 * Only allow root to run in non-debug mode to avoid problems
245 if (!debugLevel && getuid()) {
246 fprintf( stderr, "Only root wants to run %s\n", prog );
247 exit( 1 );
250 initErrorLog( errorLogFile );
252 if (parentPid != 1)
253 becomeDaemon();
256 * Step 1 - load configuration parameters
258 if (!initResources( opts ) || scanConfigs( False ) < 0)
259 logPanic( "Config reader failed. Aborting ...\n" );
261 /* SUPPRESS 560 */
262 if ((oldpid = storePid())) {
263 if (oldpid == -1)
264 logError( "Cannot create/lock pid file %s\n", pidFile );
265 else
266 logError( "Cannot lock pid file %s, another xdm is running (pid %d)\n",
267 pidFile, oldpid );
268 exit( 1 );
271 #ifdef NEED_ENTROPY
272 addOtherEntropy();
273 #endif
276 * We used to clean up old authorization files here. As authDir is
277 * supposed to be /var/run/xauth or /tmp, we needn't to care for it.
280 #ifdef XDMCP
281 initXdmcp();
282 #else
283 debug( "not compiled for XDMCP\n" );
284 #endif
285 if (pipe( signalFds ))
286 logPanic( "Unable to create signal notification pipe.\n" );
287 registerInput( signalFds[0] );
288 registerCloseOnFork( signalFds[0] );
289 registerCloseOnFork( signalFds[1] );
290 (void)Signal( SIGTERM, sigHandler );
291 (void)Signal( SIGINT, sigHandler );
292 (void)Signal( SIGHUP, sigHandler );
293 (void)Signal( SIGCHLD, sigHandler );
294 (void)Signal( SIGUSR1, sigHandler );
297 * Step 2 - run a sub-daemon for each entry
299 #ifdef XDMCP
300 updateListenSockets();
301 #endif
302 openCtrl( 0 );
303 mainLoop();
304 closeCtrl( 0 );
305 if (sdRec.how) {
306 int pid;
307 commitBootOption();
308 if (Fork( &pid ) <= 0) {
309 char *cmd = sdRec.how == SHUT_HALT ? cmdHalt : cmdReboot;
310 execute( parseArgs( (char **)0, cmd ), (char **)0 );
311 logError( "Failed to execute shutdown command %\"s\n", cmd );
312 exit( 1 );
313 } else {
314 sigset_t mask;
315 sigemptyset( &mask );
316 sigaddset( &mask, SIGCHLD );
317 sigaddset( &mask, SIGHUP );
318 sigsuspend( &mask );
321 debug( "nothing left to do, exiting\n" );
322 return 0;
326 #ifdef HAVE_VTS
328 TTYtoVT( const char *tty )
330 return memcmp( tty, "tty", 3 ) ? 0 : atoi( tty + 3 );
334 activateVT( int vt )
336 int ret = False;
337 int con = open( "/dev/console", O_RDONLY );
338 if (con >= 0) {
339 if (!ioctl( con, VT_ACTIVATE, vt ))
340 ret = True;
341 close( con );
343 return ret;
347 static void
348 wakeDisplay( struct display *d )
350 if (d->status == textMode)
351 d->status = (d->displayType & d_lifetime) == dReserve ? reserve : notRunning;
353 #endif
355 enum utState { UtDead, UtWait, UtActive };
357 struct utmps {
358 struct utmps *next;
359 #ifndef HAVE_VTS
360 struct display *d;
361 #endif
362 time_t time;
363 enum utState state;
364 int hadSess;
367 #define TIME_LOG 40
368 #define TIME_RELOG 10
370 static struct utmps *utmpList;
371 static time_t utmpTimeout = TO_INF;
373 static void
374 bombUtmp( void )
376 struct utmps *utp;
378 while ((utp = utmpList)) {
379 #ifdef HAVE_VTS
380 forEachDisplay( wakeDisplay );
381 #else
382 utp->d->status = notRunning;
383 #endif
384 utmpList = utp->next;
385 free( utp );
389 static void
390 checkUtmp( void )
392 static time_t modtim;
393 time_t nck;
394 time_t ends;
395 struct utmps *utp, **utpp;
396 struct stat st;
397 #ifdef BSD_UTMP
398 int fd;
399 struct utmp ut[1];
400 #else
401 STRUCTUTMP *ut;
402 #endif
404 if (!utmpList)
405 return;
406 if (stat( UTMP_FILE, &st )) {
407 logError( UTMP_FILE " not found - cannot use console mode\n" );
408 bombUtmp();
409 return;
411 if (modtim != st.st_mtime) {
412 debug( "rescanning " UTMP_FILE "\n" );
413 for (utp = utmpList; utp; utp = utp->next)
414 utp->state = UtDead;
415 #ifdef BSD_UTMP
416 if ((fd = open( UTMP_FILE, O_RDONLY )) < 0) {
417 logError( "Cannot open " UTMP_FILE " - cannot use console mode\n" );
418 bombUtmp();
419 return;
421 while (reader( fd, ut, sizeof(ut[0]) ) == sizeof(ut[0]))
422 #else
423 SETUTENT();
424 while ((ut = GETUTENT()))
425 #endif
427 for (utp = utmpList; utp; utp = utp->next) {
428 #ifdef HAVE_VTS
429 char **line;
430 for (line = consoleTTYs; *line; line++)
431 if (!strncmp( *line, ut->ut_line, sizeof(ut->ut_line) ))
432 goto hitlin;
433 continue;
434 hitlin:
435 #else
436 if (strncmp( utp->d->console, ut->ut_line, sizeof(ut->ut_line) ))
437 continue;
438 #endif
439 #ifdef BSD_UTMP
440 if (!*ut->ut_user) {
441 #else
442 if (ut->ut_type != USER_PROCESS) {
443 #endif
444 #ifdef HAVE_VTS
445 if (utp->state == UtActive)
446 break;
447 #endif
448 utp->state = UtWait;
449 } else {
450 utp->hadSess = True;
451 utp->state = UtActive;
453 if (utp->time < ut->ut_time) /* theoretically superfluous */
454 utp->time = ut->ut_time;
455 break;
458 #ifdef BSD_UTMP
459 close( fd );
460 #else
461 ENDUTENT();
462 #endif
463 modtim = st.st_mtime;
465 for (utpp = &utmpList; (utp = *utpp); ) {
466 if (utp->state != UtActive) {
467 if (utp->state == UtDead) /* shouldn't happen ... */
468 utp->time = 0;
469 ends = utp->time + (utp->hadSess ? TIME_RELOG : TIME_LOG);
470 if (ends <= now) {
471 #ifdef HAVE_VTS
472 forEachDisplay( wakeDisplay );
473 debug( "console login timed out\n" );
474 #else
475 utp->d->status = notRunning;
476 debug( "console login for %s at %s timed out\n",
477 utp->d->name, utp->d->console );
478 #endif
479 *utpp = utp->next;
480 free( utp );
481 continue;
482 } else
483 nck = ends;
484 } else
485 nck = TIME_RELOG + now;
486 if (nck < utmpTimeout)
487 utmpTimeout = nck;
488 utpp = &(*utpp)->next;
492 static void
493 #ifdef HAVE_VTS
494 switchToTTY( void )
495 #else
496 switchToTTY( struct display *d )
497 #endif
499 struct utmps *utp;
500 #ifdef HAVE_VTS
501 int vt;
502 #endif
504 if (!(utp = Malloc( sizeof(*utp) ))) {
505 #ifdef HAVE_VTS
506 forEachDisplay( wakeDisplay );
507 #else
508 d->status = notRunning;
509 #endif
510 return;
512 #ifndef HAVE_VTS
513 d->status = textMode;
514 utp->d = d;
515 #endif
516 utp->time = now;
517 utp->hadSess = False;
518 utp->next = utmpList;
519 utmpList = utp;
520 checkUtmp();
522 #ifdef HAVE_VTS
523 if ((vt = TTYtoVT( *consoleTTYs )))
524 activateVT( vt );
525 #endif
527 /* XXX output something useful here */
530 #ifdef HAVE_VTS
531 static void
532 stopToTTY( struct display *d )
534 if ((d->displayType & d_location) == dLocal)
535 switch (d->status) {
536 default:
537 rStopDisplay( d, DS_TEXTMODE | DS_SCHEDULE );
538 case reserve:
539 case textMode:
540 break;
544 static void
545 checkTTYMode( void )
547 struct display *d;
549 for (d = displays; d; d = d->next)
550 if (d->status == zombie)
551 return;
553 switchToTTY();
556 #else
558 void
559 switchToX( struct display *d )
561 struct utmps *utp, **utpp;
563 for (utpp = &utmpList; (utp = *utpp); utpp = &(*utpp)->next)
564 if (utp->d == d) {
565 *utpp = utp->next;
566 free( utp );
567 d->status = notRunning;
568 return;
571 #endif
573 #ifdef XDMCP
574 static void
575 startRemoteLogin( struct display *d )
577 char **argv;
579 debug( "startRemoteLogin for %s\n", d->name );
580 /* HACK: omitting loadDisplayResources( d ) here! */
581 switch (Fork( &d->serverPid )) {
582 case 0:
583 argv = prepareServerArgv( d, d->serverArgsRemote );
584 if (!(argv = addStrArr( argv, "-once", 5 )) ||
585 !(argv = addStrArr( argv, "-query", 6 )) ||
586 !(argv = addStrArr( argv, d->remoteHost, -1 )))
587 exit( 1 );
588 debug( "exec %\"[s\n", argv );
589 (void)execv( argv[0], argv );
590 logError( "X server %\"s cannot be executed\n", argv[0] );
591 exit( 1 );
592 case -1:
593 logError( "Forking X server for remote login failed: %m" );
594 d->status = notRunning;
595 return;
596 default:
597 break;
599 debug( "X server forked, pid %d\n", d->serverPid );
601 d->status = remoteLogin;
603 #endif
606 static void
607 stopInactiveDisplay( struct display *d )
609 if (d->status != remoteLogin && d->userSess < 0)
610 stopDisplay( d );
613 static void
614 stoppen( int force )
616 #ifdef XDMCP
617 requestPort = 0;
618 updateListenSockets();
619 #endif
620 if (force)
621 forEachDisplay( stopDisplay );
622 else
623 forEachDisplay( stopInactiveDisplay );
624 stopping = True;
628 static void
629 sessionDone( struct display *d )
631 d->userSess = -1;
632 if (d->userName)
633 free( d->userName );
634 d->userName = 0;
635 if (d->sessName)
636 free( d->sessName );
637 d->sessName = 0;
640 void
641 setNLogin( struct display *d,
642 const char *nuser, const char *npass, char *nargs, int rl )
644 struct disphist *he = d->hstent;
645 he->rLogin =
646 (reStr( &he->nuser, nuser ) &&
647 reStr( &he->npass, npass ) &&
648 reStr( &he->nargs, nargs )) ? rl : 0;
649 debug( "set next login for %s, level %d\n", nuser, rl );
652 static void
653 processDPipe( struct display *d )
655 char *user, *pass, *args;
656 int cmd;
657 GTalk dpytalk;
658 #ifdef XDMCP
659 int ct, len;
660 ARRAY8 ca, cp, ha;
661 #endif
663 dpytalk.pipe = &d->pipe;
664 if (Setjmp( dpytalk.errjmp )) {
665 stopDisplay( d );
666 return;
668 gSet( &dpytalk );
669 if (!gRecvCmd( &cmd )) {
670 /* process already exited */
671 unregisterInput( d->pipe.fd.r );
672 return;
674 switch (cmd) {
675 case D_User:
676 d->userSess = gRecvInt();
677 d->userName = gRecvStr();
678 d->sessName = gRecvStr();
679 break;
680 case D_UnUser:
681 sessionDone( d );
682 if (d->sdRec.how) {
683 if (d->sdRec.force == SHUT_ASK &&
684 (anyUserLogins( -1 ) || d->allowShutdown == SHUT_ROOT))
686 gSendInt( True );
687 } else {
688 if (!sdRec.how || sdRec.force != SHUT_FORCE ||
689 !((d->allowNuke == SHUT_NONE && sdRec.uid != d->sdRec.uid) ||
690 (d->allowNuke == SHUT_ROOT && d->sdRec.uid)))
692 if (sdRec.osname)
693 free( sdRec.osname );
694 sdRec = d->sdRec;
695 } else if (d->sdRec.osname)
696 free( d->sdRec.osname );
697 d->sdRec.how = 0;
698 d->sdRec.osname = 0;
699 gSendInt( False );
701 } else
702 gSendInt( False );
703 break;
704 case D_ReLogin:
705 user = gRecvStr();
706 pass = gRecvStr();
707 args = gRecvStr();
708 setNLogin( d, user, pass, args, 1 );
709 free( args );
710 free( pass );
711 free( user );
712 break;
713 #ifdef XDMCP
714 case D_ChooseHost:
715 ca.data = (unsigned char *)gRecvArr( &len );
716 ca.length = (CARD16)len;
717 cp.data = (unsigned char *)gRecvArr( &len );
718 cp.length = (CARD16)len;
719 ct = gRecvInt();
720 ha.data = (unsigned char *)gRecvArr( &len );
721 ha.length = (CARD16)len;
722 registerIndirectChoice( &ca, &cp, ct, &ha );
723 XdmcpDisposeARRAY8( &ha );
724 XdmcpDisposeARRAY8( &cp );
725 XdmcpDisposeARRAY8( &ca );
726 break;
727 case D_RemoteHost:
728 if (d->remoteHost)
729 free( d->remoteHost );
730 d->remoteHost = gRecvStr();
731 break;
732 #endif
733 case D_XConnOk:
734 startingServer = 0;
735 break;
736 default:
737 logError( "Internal error: unknown D_* command %d\n", cmd );
738 stopDisplay( d );
739 break;
743 static void
744 emitXSessG( struct display *di, struct display *d, void *ctx ATTR_UNUSED )
746 gSendStr( di->name );
747 gSendStr( "" );
748 #ifdef HAVE_VTS
749 gSendInt( di->serverVT );
750 #endif
751 #ifdef XDMCP
752 if (di->status == remoteLogin) {
753 gSendStr( "" );
754 gSendStr( di->remoteHost );
755 } else
756 #endif
758 gSendStr( di->userName );
759 gSendStr( di->sessName );
761 gSendInt( di == d ? isSelf : 0 );
764 static void
765 emitTTYSessG( STRUCTUTMP *ut, struct display *d ATTR_UNUSED, void *ctx ATTR_UNUSED )
767 gSendStrN( ut->ut_line, sizeof(ut->ut_line) );
768 gSendStrN( ut->ut_host, sizeof(ut->ut_host) );
769 #ifdef HAVE_VTS
770 gSendInt( TTYtoVT( ut->ut_line ) );
771 #endif
772 #ifdef BSD_UTMP
773 gSendStrN( *ut->ut_user ? ut->ut_user : 0, sizeof(ut->ut_user) );
774 #else
775 gSendStrN( ut->ut_type == USER_PROCESS ? ut->ut_user : 0, sizeof(ut->ut_user) );
776 #endif
777 gSendStr( 0 ); /* session type unknown */
778 gSendInt( isTTY );
781 static void
782 processGPipe( struct display *d )
784 char **opts, *option;
785 int cmd, ret, dflt, curr;
786 GTalk dpytalk;
788 dpytalk.pipe = &d->gpipe;
789 if (Setjmp( dpytalk.errjmp )) {
790 stopDisplay( d );
791 return;
793 gSet( &dpytalk );
794 if (!gRecvCmd( &cmd )) {
795 /* process already exited */
796 unregisterInput( d->gpipe.fd.r );
797 return;
799 switch (cmd) {
800 case G_ListBootOpts:
801 ret = getBootOptions( &opts, &dflt, &curr );
802 gSendInt( ret );
803 if (ret == BO_OK) {
804 gSendArgv( opts );
805 freeStrArr( opts );
806 gSendInt( dflt );
807 gSendInt( curr );
809 break;
810 case G_Shutdown:
811 sdRec.how = gRecvInt();
812 sdRec.start = gRecvInt();
813 sdRec.timeout = gRecvInt();
814 sdRec.force = gRecvInt();
815 sdRec.uid = gRecvInt();
816 option = gRecvStr();
817 setBootOption( option, &sdRec );
818 if (option)
819 free( option );
820 break;
821 case G_QueryShutdown:
822 gSendInt( sdRec.how );
823 gSendInt( sdRec.start );
824 gSendInt( sdRec.timeout );
825 gSendInt( sdRec.force );
826 gSendInt( sdRec.uid );
827 gSendStr( sdRec.osname );
828 break;
829 case G_QryDpyShutdown:
830 gSendInt( d->sdRec.how );
831 gSendInt( d->sdRec.uid );
832 gSendStr( d->sdRec.osname );
833 break;
834 case G_List:
835 listSessions( gRecvInt(), d, 0, emitXSessG, emitTTYSessG );
836 gSendInt( 0 );
837 break;
838 #ifdef HAVE_VTS
839 case G_Activate:
840 activateVT( gRecvInt() );
841 break;
842 #endif
843 case G_Console:
844 #ifdef HAVE_VTS
845 if (*consoleTTYs) { /* sanity check against greeter */
846 forEachDisplay( stopToTTY );
847 checkTTYMode();
849 #else
850 if (*d->console) /* sanity check against greeter */
851 rStopDisplay( d, DS_TEXTMODE );
852 #endif
853 break;
854 default:
855 logError( "Internal error: unknown G_* command %d\n", cmd );
856 stopDisplay( d );
857 break;
862 static int
863 scanConfigs( int force )
865 int ret;
867 if ((ret = loadDMResources( force )) <= 0)
868 return ret;
869 scanServers();
870 #ifdef XDMCP
871 scanAccessDatabase( force );
872 #endif
873 return 1;
876 static void
877 markDisplay( struct display *d )
879 d->stillThere = False;
882 static void
883 rescanConfigs( int force )
885 if (scanConfigs( force ) > 0) {
886 #ifdef XDMCP
887 updateListenSockets();
888 #endif
889 updateCtrl();
893 void
894 cancelShutdown( void )
896 sdRec.how = 0;
897 if (sdRec.osname) {
898 free( sdRec.osname );
899 sdRec.osname = 0;
901 stopping = False;
902 rescanConfigs( True );
906 static void
907 reapChildren( void )
909 int pid;
910 struct display *d;
911 int status;
913 while ((pid = waitpid( -1, &status, WNOHANG )) > 0)
915 debug( "manager wait returns pid %d sig %d core %d code %d\n",
916 pid, waitSig( status ), waitCore( status ), waitCode( status ) );
917 /* SUPPRESS 560 */
918 if ((d = findDisplayByPid( pid ))) {
919 d->pid = -1;
920 unregisterInput( d->pipe.fd.r );
921 gClosen( &d->pipe );
922 unregisterInput( d->gpipe.fd.r );
923 gClosen( &d->gpipe );
924 closeCtrl( d );
925 switch (wcFromWait( status )) {
926 #ifdef XDMCP
927 case EX_REMOTE:
928 debug( "display exited with EX_REMOTE\n" );
929 exitDisplay( d, DS_REMOTE, 0, False );
930 break;
931 #endif
932 case EX_NORMAL:
933 /* (any type of) session ended */
934 debug( "display exited with EX_NORMAL\n" );
935 if ((d->displayType & d_lifetime) == dReserve)
936 exitDisplay( d, DS_RESERVE, 0, False );
937 else
938 exitDisplay( d, DS_RESTART, XS_KEEP, True );
939 break;
940 case EX_RESERVE:
941 debug( "display exited with EX_RESERVE\n" );
942 exitDisplay( d, DS_RESERVE, 0, False );
943 break;
944 #if 0
945 case EX_REMANAGE_DPY:
946 /* user session ended */
947 debug( "display exited with EX_REMANAGE_DPY\n" );
948 exitDisplay( d, DS_RESTART, XS_KEEP, True );
949 break;
950 #endif
951 case EX_OPENFAILED_DPY:
952 /* waitForServer() failed */
953 logError( "Display %s cannot be opened\n", d->name );
954 #ifdef XDMCP
956 * no display connection was ever made, tell the
957 * terminal that the open attempt failed
959 if ((d->displayType & d_origin) == dFromXDMCP)
960 sendFailed( d, "cannot open display" );
961 #endif
962 exitDisplay( d, DS_RESTART, XS_RETRY, False );
963 break;
964 case wcCompose( SIGTERM,0,0 ):
965 /* killed before/during waitForServer()
966 - local Xserver died
967 - display stopped (is zombie)
968 - "login now" and "suicide" pipe commands (is raiser)
970 debug( "display exited on SIGTERM\n" );
971 exitDisplay( d, DS_RESTART, XS_RETRY, False );
972 break;
973 case EX_AL_RESERVER_DPY:
974 /* - killed after waitForServer()
975 - Xserver dead after remote session exit
977 debug( "display exited with EX_AL_RESERVER_DPY\n" );
978 exitDisplay( d, DS_RESTART, XS_RESTART, False );
979 break;
980 case EX_RESERVER_DPY:
981 /* induced by greeter:
982 - could not secure display
983 - requested by user
985 debug( "display exited with EX_RESERVER_DPY\n" );
986 exitDisplay( d, DS_RESTART, XS_RESTART, True );
987 break;
988 case EX_UNMANAGE_DPY:
989 /* some fatal error */
990 debug( "display exited with EX_UNMANAGE_DPY\n" );
991 exitDisplay( d, DS_REMOVE, 0, False );
992 break;
993 default:
994 /* prolly crash */
995 logError( "Unknown session exit code %d (sig %d) from manager process\n",
996 waitCode( status ), waitSig( status ) );
997 exitDisplay( d, DS_REMOVE, 0, False );
998 break;
1000 } else if ((d = findDisplayByServerPid( pid ))) {
1001 d->serverPid = -1;
1002 switch (d->status) {
1003 case zombie:
1004 debug( "zombie X server for display %s reaped\n", d->name );
1005 #ifdef HAVE_VTS
1006 if (d->serverVT && d->zstatus != DS_REMOTE) {
1007 if (d->follower) {
1008 d->follower->serverVT = d->serverVT;
1009 d->follower = 0;
1010 } else {
1011 int con = open( "/dev/console", O_RDONLY );
1012 if (con >= 0) {
1013 struct vt_stat vtstat;
1014 ioctl( con, VT_GETSTATE, &vtstat );
1015 if (vtstat.v_active == d->serverVT) {
1016 int vt = 1;
1017 struct display *di;
1018 for (di = displays; di; di = di->next)
1019 if (di != d && di->serverVT)
1020 vt = di->serverVT;
1021 for (di = displays; di; di = di->next)
1022 if (di != d && di->serverVT &&
1023 (di->userSess >= 0 ||
1024 di->status == remoteLogin))
1025 vt = di->serverVT;
1026 ioctl( con, VT_ACTIVATE, vt );
1028 ioctl( con, VT_DISALLOCATE, d->serverVT );
1029 close( con );
1032 d->serverVT = 0;
1034 #endif
1035 rStopDisplay( d, d->zstatus );
1036 break;
1037 case phoenix:
1038 debug( "phoenix X server arises, restarting display %s\n",
1039 d->name );
1040 d->status = notRunning;
1041 break;
1042 case remoteLogin:
1043 debug( "remote login X server for display %s exited\n",
1044 d->name );
1045 d->status = ((d->displayType & d_lifetime) == dReserve) ?
1046 reserve : notRunning;
1047 break;
1048 case raiser:
1049 logError( "X server for display %s terminated unexpectedly\n",
1050 d->name );
1051 /* don't kill again */
1052 break;
1053 case running:
1054 if (startingServer == d && d->serverStatus != ignore) {
1055 if (d->serverStatus == starting && waitCode( status ) != 47)
1056 logError( "X server died during startup\n" );
1057 startServerFailed();
1058 break;
1060 logError( "X server for display %s terminated unexpectedly\n",
1061 d->name );
1062 if (d->pid != -1) {
1063 debug( "terminating session pid %d\n", d->pid );
1064 terminateProcess( d->pid, SIGTERM );
1066 break;
1067 case notRunning:
1068 case textMode:
1069 case reserve:
1070 /* this cannot happen */
1071 debug( "X server exited for passive (%d) session on display %s\n",
1072 (int)d->status, d->name );
1073 break;
1075 } else
1076 debug( "unknown child termination\n" );
1078 #ifdef NEED_ENTROPY
1079 addOtherEntropy();
1080 #endif
1083 static int
1084 wouldShutdown( void )
1086 switch (sdRec.force) {
1087 case SHUT_FORCE:
1088 return True;
1089 case SHUT_FORCEMY:
1090 return !anyUserLogins( sdRec.uid );
1091 case SHUT_CANCEL:
1092 default:
1093 return !anyUserLogins( -1 );
1097 fd_set wellKnownSocketsMask;
1098 int wellKnownSocketsMax;
1099 int wellKnownSocketsCount;
1101 void
1102 registerInput( int fd )
1104 /* can be omited, as it is always called right after opening a socket
1105 if (!FD_ISSET( fd, &wellKnownSocketsMask ))
1108 FD_SET( fd, &wellKnownSocketsMask );
1109 if (fd > wellKnownSocketsMax)
1110 wellKnownSocketsMax = fd;
1111 wellKnownSocketsCount++;
1115 void
1116 unregisterInput( int fd )
1118 /* the check _is_ necessary, as some handles are unregistered before
1119 the regular close sequence.
1121 if (FD_ISSET( fd, &wellKnownSocketsMask )) {
1122 FD_CLR( fd, &wellKnownSocketsMask );
1123 wellKnownSocketsCount--;
1127 static void
1128 sigHandler( int n )
1130 int olderrno = errno;
1131 char buf = (char)n;
1132 /* debug( "caught signal %d\n", n ); this hangs in syslog() */
1133 write( signalFds[1], &buf, 1 );
1134 #ifdef __EMX__
1135 (void)Signal( n, sigHandler );
1136 #endif
1137 errno = olderrno;
1140 static void
1141 mainLoop( void )
1143 struct display *d;
1144 struct timeval *tvp, tv;
1145 time_t to;
1146 int nready;
1147 char buf;
1148 fd_set reads;
1150 debug( "mainLoop\n" );
1151 time( &now );
1152 while (
1153 #ifdef XDMCP
1154 anyListenSockets() ||
1155 #endif
1156 (stopping ? anyRunningDisplays() : anyDisplaysLeft()))
1158 if (!stopping)
1159 startDisplays();
1160 #ifdef XDMCP
1161 to = disposeIndirectHosts();
1162 #else
1163 to = TO_INF;
1164 #endif
1165 if (sdRec.how) {
1166 if (sdRec.start != TO_INF && now < sdRec.start) {
1167 /*if (sdRec.start < to)*/
1168 to = sdRec.start;
1169 } else {
1170 sdRec.start = TO_INF;
1171 if (now >= sdRec.timeout) {
1172 sdRec.timeout = TO_INF;
1173 if (wouldShutdown())
1174 stoppen( True );
1175 else
1176 cancelShutdown();
1177 } else {
1178 stoppen( False );
1179 /*if (sdRec.timeout < to)*/
1180 to = sdRec.timeout;
1184 if (serverTimeout < to)
1185 to = serverTimeout;
1186 if (utmpTimeout < to)
1187 to = utmpTimeout;
1188 if (to == TO_INF)
1189 tvp = 0;
1190 else {
1191 to -= now;
1192 if (to < 0)
1193 to = 0;
1194 tv.tv_sec = to;
1195 tv.tv_usec = 0;
1196 tvp = &tv;
1198 reads = wellKnownSocketsMask;
1199 nready = select( wellKnownSocketsMax + 1, &reads, 0, 0, tvp );
1200 debug( "select returns %d\n", nready );
1201 time( &now );
1202 #ifdef NEED_ENTROPY
1203 addTimerEntropy();
1204 #endif
1205 if (now >= serverTimeout) {
1206 serverTimeout = TO_INF;
1207 startServerTimeout();
1209 if (now >= utmpTimeout) {
1210 utmpTimeout = TO_INF;
1211 checkUtmp();
1213 if (nready > 0) {
1215 * we restart after the first handled fd, as
1216 * a) it makes things simpler
1217 * b) the probability that multiple fds trigger at once is
1218 * ridiculously small. we handle it in the next iteration.
1220 /* XXX a cleaner solution would be a callback mechanism */
1221 if (FD_ISSET( signalFds[0], &reads )) {
1222 if (read( signalFds[0], &buf, 1 ) != 1)
1223 logPanic( "Signal notification pipe broken.\n" );
1224 switch (buf) {
1225 case SIGTERM:
1226 case SIGINT:
1227 debug( "shutting down entire manager\n" );
1228 stoppen( True );
1229 break;
1230 case SIGHUP:
1231 logInfo( "Rescanning all config files\n" );
1232 forEachDisplay( markDisplay );
1233 rescanConfigs( True );
1234 break;
1235 case SIGCHLD:
1236 reapChildren();
1237 if (!stopping && autoRescan)
1238 rescanConfigs( False );
1239 break;
1240 case SIGUSR1:
1241 if (startingServer &&
1242 startingServer->serverStatus == starting)
1243 startServerSuccess();
1244 break;
1246 continue;
1248 #ifdef XDMCP
1249 if (processListenSockets( &reads ))
1250 continue;
1251 #endif /* XDMCP */
1252 if (handleCtrl( &reads, 0 ))
1253 continue;
1254 /* Must be last (because of the breaks)! */
1255 again:
1256 for (d = displays; d; d = d->next) {
1257 if (handleCtrl( &reads, d ))
1258 goto again;
1259 if (d->pipe.fd.r >= 0 && FD_ISSET( d->pipe.fd.r, &reads )) {
1260 processDPipe( d );
1261 break;
1263 if (d->gpipe.fd.r >= 0 && FD_ISSET( d->gpipe.fd.r, &reads )) {
1264 processGPipe( d );
1265 break;
1272 static void
1273 checkDisplayStatus( struct display *d )
1275 if ((d->displayType & d_origin) == dFromFile && !d->stillThere)
1276 stopDisplay( d );
1277 else if ((d->displayType & d_lifetime) == dReserve &&
1278 d->status == running && d->userSess < 0 && !d->idleTimeout)
1279 rStopDisplay( d, DS_RESERVE );
1280 else if (d->status == notRunning)
1281 if (loadDisplayResources( d ) < 0) {
1282 logError( "Unable to read configuration for display %s; "
1283 "stopping it.\n", d->name );
1284 stopDisplay( d );
1285 return;
1289 static void
1290 kickDisplay( struct display *d )
1292 if (d->status == notRunning)
1293 startDisplay( d );
1294 if (d->serverStatus == awaiting && !startingServer)
1295 startServer( d );
1298 #ifdef HAVE_VTS
1299 static int activeVTs;
1301 static int
1302 getBusyVTs( void )
1304 struct vt_stat vtstat;
1305 int con;
1307 if (activeVTs == -1) {
1308 vtstat.v_state = 0;
1309 if ((con = open( "/dev/console", O_RDONLY )) >= 0) {
1310 ioctl( con, VT_GETSTATE, &vtstat );
1311 close( con );
1313 activeVTs = vtstat.v_state;
1315 return activeVTs;
1318 static void
1319 allocateVT( struct display *d )
1321 struct display *cd;
1322 int i, tvt, volun;
1324 if ((d->displayType & d_location) == dLocal &&
1325 d->status == notRunning && !d->serverVT && d->reqSrvVT >= 0)
1327 if (d->reqSrvVT && d->reqSrvVT < 16)
1328 d->serverVT = d->reqSrvVT;
1329 else {
1330 for (i = tvt = 0;;) {
1331 if (serverVTs[i]) {
1332 tvt = atoi( serverVTs[i++] );
1333 volun = False;
1334 if (tvt < 0) {
1335 tvt = -tvt;
1336 volun = True;
1338 if (!tvt || tvt >= 16)
1339 continue;
1340 } else {
1341 if (++tvt >= 16)
1342 break;
1343 volun = True;
1345 for (cd = displays; cd; cd = cd->next) {
1346 if (cd->reqSrvVT == tvt && /* protect from lusers */
1347 (cd->status != zombie || cd->zstatus != DS_REMOVE))
1348 goto next;
1349 if (cd->serverVT == tvt) {
1350 if (cd->status != zombie || cd->zstatus == DS_REMOTE)
1351 goto next;
1352 if (!cd->follower) {
1353 d->serverVT = -1;
1354 cd->follower = d;
1355 return;
1359 if (!volun || !((1 << tvt) & getBusyVTs())) {
1360 d->serverVT = tvt;
1361 return;
1363 next: ;
1368 #endif
1370 static void
1371 startDisplays( void )
1373 forEachDisplay( checkDisplayStatus );
1374 closeGetter();
1375 #ifdef HAVE_VTS
1376 activeVTs = -1;
1377 forEachDisplayRev( allocateVT );
1378 #endif
1379 forEachDisplay( kickDisplay );
1382 void
1383 startDisplay( struct display *d )
1385 if (stopping) {
1386 debug( "stopping display %s because shutdown is scheduled\n", d->name );
1387 stopDisplay( d );
1388 return;
1391 #ifdef HAVE_VTS
1392 if (d->serverVT < 0)
1393 return;
1394 #endif
1396 d->status = running;
1397 if ((d->displayType & d_location) == dLocal) {
1398 debug( "startDisplay %s\n", d->name );
1399 /* don't bother pinging local displays; we'll
1400 * certainly notice when they exit
1402 d->pingInterval = 0;
1403 if (d->authorize) {
1404 setLocalAuthorization( d );
1406 * reset the server after writing the authorization information
1407 * to make it read the file (for compatibility with old
1408 * servers which read auth file only on reset instead of
1409 * at first connection)
1411 if (d->serverPid != -1 && d->resetForAuth && d->resetSignal)
1412 kill( d->serverPid, d->resetSignal );
1414 if (d->serverPid == -1) {
1415 d->serverStatus = awaiting;
1416 return;
1418 } else {
1419 debug( "startDisplay %s, try %d\n", d->name, d->startTries + 1 );
1420 /* this will only happen when using XDMCP */
1421 if (d->authorizations)
1422 saveServerAuthorizations( d, d->authorizations, d->authNum );
1424 startDisplayP2( d );
1427 void
1428 startDisplayP2( struct display *d )
1430 char *cname, *cgname;
1432 openCtrl( d );
1433 debug( "forking session\n" );
1434 ASPrintf( &cname, "sub-daemon for display %s", d->name );
1435 ASPrintf( &cgname, "greeter for display %s", d->name );
1436 switch (gFork( &d->pipe, "master daemon", cname,
1437 &d->gpipe, cgname, 0, &d->pid ))
1439 case 0:
1440 #ifndef NOXDMTITLE
1441 setproctitle( "%s", d->name );
1442 #endif
1443 ASPrintf( &prog, "%s: %s", prog, d->name );
1444 reInitErrorLog();
1445 if (debugLevel & DEBUG_WSESS)
1446 sleep( 100 );
1447 mstrtalk.pipe = &d->pipe;
1448 (void)Signal( SIGPIPE, SIG_IGN );
1449 setAuthorization( d );
1450 waitForServer( d );
1451 if ((d->displayType & d_location) == dLocal) {
1452 gSet( &mstrtalk );
1453 gSendInt( D_XConnOk );
1455 manageSession( d );
1456 /* NOTREACHED */
1457 case -1:
1458 closeCtrl( d );
1459 d->status = notRunning;
1460 break;
1461 default:
1462 debug( "forked session, pid %d\n", d->pid );
1464 /* (void) fcntl (d->pipe.fd.r, F_SETFL, O_NONBLOCK); */
1465 /* (void) fcntl (d->gpipe.fd.r, F_SETFL, O_NONBLOCK); */
1466 registerInput( d->pipe.fd.r );
1467 registerInput( d->gpipe.fd.r );
1469 d->hstent->lock = d->hstent->rLogin = d->hstent->goodExit =
1470 d->sdRec.how = 0;
1471 d->lastStart = now;
1472 break;
1477 * transition from running to zombie, textmode, reserve or deleted
1480 static void
1481 rStopDisplay( struct display *d, int endState )
1483 debug( "stopping display %s to state %d\n", d->name, endState );
1484 abortStartServer( d );
1485 d->idleTimeout = 0;
1486 if (d->serverPid != -1 || d->pid != -1) {
1487 if (d->pid != -1)
1488 terminateProcess( d->pid, SIGTERM );
1489 if (d->serverPid != -1)
1490 terminateProcess( d->serverPid, d->termSignal );
1491 d->status = zombie;
1492 d->zstatus = endState & DS_MASK;
1493 debug( " zombiefied\n" );
1494 } else if (endState == DS_TEXTMODE) {
1495 #ifdef HAVE_VTS
1496 d->status = textMode;
1497 checkTTYMode();
1498 } else if (endState == (DS_TEXTMODE | DS_SCHEDULE)) {
1499 d->status = textMode;
1500 #else
1501 switchToTTY( d );
1502 #endif
1503 } else if (endState == DS_RESERVE)
1504 d->status = reserve;
1505 #ifdef XDMCP
1506 else if (endState == DS_REMOTE)
1507 startRemoteLogin( d );
1508 #endif
1509 else {
1510 #ifndef HAVE_VTS
1511 switchToX( d );
1512 #endif
1513 removeDisplay( d );
1517 void
1518 stopDisplay( struct display *d )
1520 rStopDisplay( d, DS_REMOVE );
1523 static void
1524 exitDisplay( struct display *d,
1525 int endState,
1526 int serverCmd,
1527 int goodExit )
1529 struct disphist *he;
1531 if (d->status == raiser) {
1532 serverCmd = XS_KEEP;
1533 goodExit = True;
1536 debug( "exitDisplay %s, "
1537 "endState = %d, serverCmd = %d, GoodExit = %d\n",
1538 d->name, endState, serverCmd, goodExit );
1540 sessionDone( d );
1541 he = d->hstent;
1542 he->lastExit = now;
1543 he->goodExit = goodExit;
1544 if (sdRec.how && sdRec.start == TO_INF)
1545 endState = DS_REMOVE;
1546 if (d->status == zombie)
1547 rStopDisplay( d, d->zstatus );
1548 else {
1549 if (stopping) {
1550 stopDisplay( d );
1551 return;
1553 if (endState != DS_RESTART ||
1554 (d->displayType & d_origin) != dFromFile)
1556 rStopDisplay( d, endState );
1557 } else {
1558 if (serverCmd == XS_RETRY) {
1559 if ((d->displayType & d_location) == dLocal) {
1560 if (he->lastExit - d->lastStart < 120) {
1561 logError( "Unable to fire up local display %s;"
1562 " disabling.\n", d->name );
1563 stopDisplay( d );
1564 return;
1566 } else {
1567 if (++d->startTries > d->startAttempts) {
1568 logError( "Disabling foreign display %s"
1569 " (too many attempts)\n", d->name );
1570 stopDisplay( d );
1571 return;
1574 } else
1575 d->startTries = 0;
1576 if (d->serverPid != -1 &&
1577 (serverCmd != XS_KEEP || d->terminateServer))
1579 debug( "killing X server for %s\n", d->name );
1580 terminateProcess( d->serverPid, d->termSignal );
1581 d->status = phoenix;
1582 } else
1583 d->status = notRunning;
1589 static int pidFd;
1590 static FILE *pidFilePtr;
1592 static int
1593 storePid( void )
1595 int oldpid;
1597 if (pidFile[0] != '\0') {
1598 pidFd = open( pidFile, O_RDWR );
1599 if (pidFd == -1 && errno == ENOENT)
1600 pidFd = open( pidFile, O_RDWR|O_CREAT, 0666 );
1601 if (pidFd == -1 || !(pidFilePtr = fdopen( pidFd, "r+" ))) {
1602 logError( "process-id file %s cannot be opened\n",
1603 pidFile );
1604 return -1;
1606 if (fscanf( pidFilePtr, "%d\n", &oldpid ) != 1)
1607 oldpid = -1;
1608 fseek( pidFilePtr, 0l, 0 );
1609 if (lockPidFile) {
1610 #ifdef F_SETLK
1611 # ifndef SEEK_SET
1612 # define SEEK_SET 0
1613 # endif
1614 struct flock lock_data;
1615 lock_data.l_type = F_WRLCK;
1616 lock_data.l_whence = SEEK_SET;
1617 lock_data.l_start = lock_data.l_len = 0;
1618 if (fcntl( pidFd, F_SETLK, &lock_data ) == -1) {
1619 if (errno == EAGAIN)
1620 return oldpid;
1621 else
1622 return -1;
1624 #else
1625 # ifdef LOCK_EX
1626 if (flock( pidFd, LOCK_EX|LOCK_NB ) == -1) {
1627 if (errno == EWOULDBLOCK)
1628 return oldpid;
1629 else
1630 return -1;
1632 # else
1633 if (lockf( pidFd, F_TLOCK, 0 ) == -1) {
1634 if (errno == EACCES)
1635 return oldpid;
1636 else
1637 return -1;
1639 # endif
1640 #endif
1642 fprintf( pidFilePtr, "%ld\n", (long)getpid() );
1643 (void)fflush( pidFilePtr );
1644 registerCloseOnFork( pidFd );
1646 return 0;
1649 #if 0
1650 void
1651 UnlockPidFile( void )
1653 if (lockPidFile)
1654 # ifdef F_SETLK
1656 struct flock lock_data;
1657 lock_data.l_type = F_UNLCK;
1658 lock_data.l_whence = SEEK_SET;
1659 lock_data.l_start = lock_data.l_len = 0;
1660 (void)fcntl( pidFd, F_SETLK, &lock_data );
1662 # else
1663 # ifdef F_ULOCK
1664 lockf( pidFd, F_ULOCK, 0 );
1665 # else
1666 flock( pidFd, LOCK_UN );
1667 # endif
1668 # endif
1669 close( pidFd );
1670 fclose( pidFilePtr );
1672 #endif
1674 #if !defined(HAVE_SETPROCTITLE) && !defined(NOXDMTITLE)
1675 void
1676 setproctitle( const char *fmt, ... )
1678 const char *name;
1679 char *oname;
1680 char *p = title;
1681 int left = titleLen;
1682 va_list args;
1684 va_start( args, fmt );
1685 VASPrintf( &oname, fmt, args );
1686 va_end( args );
1688 if ((name = oname)) {
1689 *p++ = '-';
1690 --left;
1691 while (*name && left > 0) {
1692 *p++ = *name++;
1693 --left;
1695 while (left > 0) {
1696 *p++ = '\0';
1697 --left;
1700 free( oname );
1703 #endif