not quite so much needs to be delayed to the init() function
[personal-kdebase.git] / workspace / kdm / backend / ctrl.c
blobeb7f118f041f59e0cac27c19911ae7242517f1ff
1 /*
3 Copyright 1988, 1998 The Open Group
4 Copyright 2001-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_socket.h"
39 #include "dm_error.h"
41 #include <string.h>
42 #include <signal.h>
43 #include <pwd.h>
45 static void
46 acceptSock( CtrlRec *cr )
48 struct cmdsock *cs;
49 int fd;
51 if ((fd = accept( cr->fd, 0, 0 )) < 0) {
52 bust:
53 logError( "Error accepting command connection\n" );
54 return;
56 if (!(cs = Malloc( sizeof(*cs) ))) {
57 close( fd );
58 goto bust;
60 cs->sock.fd = fd;
61 cs->sock.buffer = 0;
62 cs->sock.buflen = 0;
63 cs->next = cr->css;
64 cr->css = cs;
65 fcntl( fd, F_SETFL, fcntl( fd, F_GETFL ) | O_NONBLOCK );
66 registerCloseOnFork( fd );
67 registerInput( fd );
70 static void
71 nukeSock( struct cmdsock *cs )
73 unregisterInput( cs->sock.fd );
74 closeNclearCloseOnFork( cs->sock.fd );
75 if (cs->sock.buffer)
76 free( cs->sock.buffer );
77 free( cs );
81 static CtrlRec ctrl = { 0, 0, -1, 0 };
83 void
84 openCtrl( struct display *d )
86 CtrlRec *cr;
87 const char *dname;
88 char *sockdir;
89 struct sockaddr_un sa;
91 if (!*fifoDir)
92 return;
93 if (d) {
94 cr = &d->ctrl, dname = displayName( d );
95 } else
96 cr = &ctrl, dname = 0;
97 if (cr->fd < 0) {
98 if (mkdir( fifoDir, 0755 )) {
99 if (errno != EEXIST) {
100 logError( "mkdir %\"s failed; no control FiFos will be available\n",
101 fifoDir );
102 return;
104 } else
105 chmod( fifoDir, 0755 ); /* override umask */
106 sockdir = 0;
107 strApp( &sockdir, fifoDir, dname ? "/dmctl-" : "/dmctl",
108 dname, (char *)0 );
109 if (sockdir) {
110 strApp( &cr->path, sockdir, "/socket", (char *)0 );
111 if (cr->path) {
112 if (strlen( cr->path ) >= sizeof(sa.sun_path))
113 logError( "path %\"s too long; no control sockets will be available\n",
114 cr->path );
115 else if (mkdir( sockdir, 0755 ) && errno != EEXIST)
116 logError( "mkdir %\"s failed; no control sockets will be available\n",
117 sockdir );
118 else {
119 if (!d)
120 chown( sockdir, -1, fifoGroup );
121 chmod( sockdir, 0750 );
122 if ((cr->fd = socket( PF_UNIX, SOCK_STREAM, 0 )) < 0)
123 logError( "Cannot create control socket\n" );
124 else {
125 unlink( cr->path );
126 sa.sun_family = AF_UNIX;
127 strcpy( sa.sun_path, cr->path );
128 if (!bind( cr->fd, (struct sockaddr *)&sa, sizeof(sa) )) {
129 if (!listen( cr->fd, 5 )) {
130 chmod( cr->path, 0666 );
131 registerCloseOnFork( cr->fd );
132 registerInput( cr->fd );
133 free( sockdir );
134 return;
136 unlink( cr->path );
137 logError( "Cannot listen on control socket %\"s\n",
138 cr->path );
139 } else
140 logError( "Cannot bind control socket %\"s\n",
141 cr->path );
142 close( cr->fd );
143 cr->fd = -1;
146 free( cr->path );
147 cr->path = 0;
149 free( sockdir );
154 void
155 closeCtrl( struct display *d )
157 CtrlRec *cr = d ? &d->ctrl : &ctrl;
159 if (cr->fd >= 0) {
160 unregisterInput( cr->fd );
161 closeNclearCloseOnFork( cr->fd );
162 cr->fd = -1;
163 unlink( cr->path );
164 *strrchr( cr->path, '/' ) = 0;
165 rmdir( cr->path );
166 free( cr->path );
167 cr->path = 0;
168 while (cr->css) {
169 struct cmdsock *cs = cr->css;
170 cr->css = cs->next;
171 nukeSock( cs );
176 void
177 chownCtrl( CtrlRec *cr, int uid )
179 if (cr->path) {
180 char *ptr = strrchr( cr->path, '/' );
181 *ptr = 0;
182 chown( cr->path, uid, -1 );
183 *ptr = '/';
187 void
188 updateCtrl( void )
190 unsigned ffl, slc;
192 ffl = 0;
193 if (ctrl.path)
194 for (ffl = strlen( ctrl.path ), slc = 2; ;)
195 if (ctrl.path[--ffl] == '/')
196 if (!--slc)
197 break;
198 if (ffl != strlen( fifoDir ) || memcmp( fifoDir, ctrl.path, ffl ) ||
199 ctrl.gid != fifoGroup)
201 closeCtrl( 0 );
202 openCtrl( 0 );
207 static void
208 fLog( struct display *d, int fd, const char *sts, const char *msg, ... )
210 char *fmsg, *otxt;
211 const char *what;
212 int olen;
213 va_list va;
215 va_start( va, msg );
216 VASPrintf( &fmsg, msg, va );
217 va_end( va );
218 if (!fmsg)
219 return;
220 if (fd >= 0) {
221 olen = ASPrintf( &otxt, "%s\t%\\s\n", sts, fmsg );
222 if (otxt) {
223 writer( fd, otxt, olen );
224 free( otxt );
226 what = "socket";
227 } else
228 what = "FiFo";
229 if (d)
230 debug( "control %s for %s: %s - %s", what, d->name, sts, fmsg );
231 else
232 debug( "global control %s: %s - %s", what, sts, fmsg );
233 free( fmsg );
237 static char *
238 unQuote( const char *str )
240 char *ret, *adp;
242 if (!(ret = Malloc( strlen( str ) + 1 )))
243 return 0;
244 for (adp = ret; *str; str++, adp++)
245 if (*str == '\\')
246 switch (*++str) {
247 case 0: str--; /* fallthrough */
248 case '\\': *adp = '\\'; break;
249 case 'n': *adp = '\n'; break;
250 case 't': *adp = '\t'; break;
251 default: *adp++ = '\\'; *adp = *str; break;
253 else
254 *adp = *str;
255 *adp = 0;
256 return ret;
259 static void
260 strCatL( char **bp, const char *str, int max )
262 int dnl = strnlen( str, max );
263 memcpy( *bp, str, dnl );
264 *bp += dnl;
267 static void
268 strCat( char **bp, const char *str )
270 int dnl = strlen( str );
271 memcpy( *bp, str, dnl );
272 *bp += dnl;
275 static void
276 sdCat( char **bp, SdRec *sdr )
278 if (sdr->how == SHUT_HALT)
279 strCat( bp, "halt," );
280 else
281 strCat( bp, "reboot," );
282 if (sdr->start == TO_INF)
283 strCat( bp, "0," );
284 else
285 *bp += sprintf( *bp, "%d,", sdr->start );
286 if (sdr->timeout == TO_INF)
287 strCat( bp, "-1," );
288 else
289 *bp += sprintf( *bp, "%d,", sdr->timeout );
290 if (sdr->force == SHUT_ASK)
291 strCat( bp, "ask" );
292 else if (sdr->force == SHUT_FORCE)
293 strCat( bp, "force" );
294 else if (sdr->force == SHUT_FORCEMY)
295 strCat( bp, "forcemy" );
296 else
297 strCat( bp, "cancel" );
298 *bp += sprintf( *bp, ",%d,%s", sdr->uid, sdr->osname ? sdr->osname : "-" );
301 static void
302 emitXSessC( struct display *di, struct display *d, void *ctx )
304 const char *dname;
305 char *bp;
306 char cbuf[1024];
308 bp = cbuf;
309 *bp++ = '\t';
310 dname = displayName( di );
311 strCatL( &bp, dname, sizeof(cbuf)/2 );
312 *bp++ = ',';
313 #ifdef HAVE_VTS
314 if (di->serverVT)
315 bp += sprintf( bp, "vt%d", di->serverVT );
316 #endif
317 *bp++ = ',';
318 #ifdef XDMCP
319 if (di->status == remoteLogin) {
320 *bp++ = ',';
321 strCatL( &bp, di->remoteHost, sizeof(cbuf)/3 );
322 } else
323 #endif
325 if (di->userName)
326 strCatL( &bp, di->userName, sizeof(cbuf)/5 );
327 *bp++ = ',';
328 if (di->sessName)
329 strCatL( &bp, di->sessName, sizeof(cbuf)/5 );
331 *bp++ = ',';
332 if (di == d)
333 *bp++ = '*';
334 if (di->userSess >= 0 &&
335 (d ? (d->userSess != di->userSess &&
336 (d->allowNuke == SHUT_NONE ||
337 (d->allowNuke == SHUT_ROOT && d->userSess))) :
338 !fifoAllowNuke))
339 *bp++ = '!';
340 writer( (int)(long)ctx, cbuf, bp - cbuf );
343 static void
344 emitTTYSessC( STRUCTUTMP *ut, struct display *d, void *ctx )
346 struct passwd *pw;
347 char *bp;
348 int vt, l;
349 char cbuf[sizeof(ut->ut_line) + sizeof(ut->ut_user) + sizeof(ut->ut_host) + 16];
350 char user[sizeof(ut->ut_user) + 1];
352 #ifndef BSD_UTMP
353 if (ut->ut_type != USER_PROCESS)
354 l = 0;
355 else
356 #endif
358 l = strnlen( ut->ut_user, sizeof(ut->ut_user) );
359 memcpy( user, ut->ut_user, l );
361 user[l] = 0;
362 bp = cbuf;
363 *bp++ = '\t';
364 strCatL( &bp, ut->ut_line, sizeof(ut->ut_line) );
365 *bp++ = ',';
366 if (*ut->ut_host) {
367 *bp++ = '@';
368 strCatL( &bp, ut->ut_host, sizeof(ut->ut_host) );
370 #ifdef HAVE_VTS
371 else if ((vt = TTYtoVT( ut->ut_line )))
372 bp += sprintf( bp, "vt%d", vt );
373 #endif
374 *bp++ = ',';
375 strCat( &bp, user );
376 *bp++ = ',';
377 /* blank: session type unknown */
378 *bp++ = ',';
379 /* blank: certainly not querying display */
380 *bp++ = 't';
381 if (*user &&
382 (d ? ((d->allowNuke == SHUT_NONE ||
383 (d->allowNuke == SHUT_ROOT && d->userSess)) &&
384 (!(pw = getpwnam( user )) || d->userSess != (int)pw->pw_uid)) :
385 !fifoAllowNuke))
386 *bp++ = '!';
387 writer( (int)(long)ctx, cbuf, bp - cbuf );
390 static void
391 processCtrl( const char *string, int len, int fd, struct display *d )
393 #define Reply(t) writer( fd, t, strlen( t ) )
395 struct display *di;
396 const char *word;
397 char **ar, **ap, *args, *bp;
398 SdRec sdr;
399 char cbuf[1024];
401 if (!(ar = initStrArr( 0 )))
402 return;
403 for (word = string; ; string++, len--)
404 if (!len || *string == '\t') {
405 if (!(ar = addStrArr( ar, word, string - word )))
406 return;
407 if (!len)
408 break;
409 word = string + 1;
411 if (d)
412 debug( "control socket for %s received %'[s\n", d->name, ar );
413 else
414 debug( "global control socket received %'[s\n", ar );
415 if (ar[0]) {
416 if (!strcmp( ar[0], "caps" )) {
417 if (ar[1])
418 goto exce;
419 Reply( "ok\tkdm\tlist\t" );
420 if (bootManager != BO_NONE)
421 Reply( "bootoptions\t" );
422 if (d) {
423 if ((d->displayType & d_location) == dLocal)
424 #ifdef HAVE_VTS
425 Reply( "local\tactivate\t" );
426 #else
427 Reply( "local\t" );
428 #endif
429 if (d->allowShutdown != SHUT_NONE) {
430 if (d->allowShutdown == SHUT_ROOT && d->userSess)
431 Reply( "shutdown root\t" );
432 else
433 Reply( "shutdown\t" );
434 Reply( "shutdown ask\t" );
435 if (d->allowNuke != SHUT_NONE) {
436 if (d->allowNuke == SHUT_ROOT && d->userSess)
437 Reply( "nuke root\t" );
438 else
439 Reply( "nuke\t" );
442 if ((d->displayType & d_location) == dLocal &&
443 anyReserveDisplays())
444 writer( fd, cbuf, sprintf( cbuf, "reserve %d\t",
445 idleReserveDisplays() ) );
446 Reply( "lock\tsuicide\n" );
447 } else {
448 if (fifoAllowShutdown) {
449 Reply( "shutdown\t" );
450 if (fifoAllowNuke)
451 Reply( "nuke\t" );
453 if (anyReserveDisplays())
454 writer( fd, cbuf, sprintf( cbuf, "reserve %d\t",
455 idleReserveDisplays() ) );
456 #ifdef HAVE_VTS
457 Reply( "login\tactivate\n" );
458 #else
459 Reply( "login\n" );
460 #endif
462 goto bust;
463 } else if (!strcmp( ar[0], "list" )) {
464 int flags = lstRemote | lstTTY;
465 if (ar[1]) {
466 if (!strcmp( ar[1], "all" ))
467 flags = lstRemote | lstPassive | lstTTY;
468 else if (!strcmp( ar[1], "alllocal" ))
469 flags = lstPassive | lstTTY;
470 else {
471 fLog( d, fd, "bad", "invalid list scope %\"s", ar[1] );
472 goto bust;
474 if (ar[2])
475 goto exce;
477 Reply( "ok" );
478 listSessions( flags, d, (void *)(long)fd, emitXSessC, emitTTYSessC );
479 Reply( "\n" );
480 goto bust;
481 } else if (!strcmp( ar[0], "reserve" )) {
482 int lt = 60; /* XXX make default timeout configurable? */
483 if (ar[1]) {
484 lt = strtol( ar[1], &bp, 10 );
485 if (lt < 15 || *bp) {
486 fLog( d, fd, "bad", "invalid timeout %\"s", ar[1] );
487 goto bust;
489 if (ar[2])
490 goto exce;
492 if (d && (d->displayType & d_location) != dLocal) {
493 fLog( d, fd, "perm", "display is not local" );
494 goto bust;
496 if (!startReserveDisplay( lt )) {
497 fLog( d, fd, "noent", "no reserve display available" );
498 goto bust;
500 #ifdef HAVE_VTS
501 } else if (!strcmp( ar[0], "activate" )) {
502 int vt;
503 if (!ar[1])
504 goto miss;
505 if (ar[2])
506 goto exce;
507 if (d && (d->displayType & d_location) != dLocal) {
508 fLog( d, fd, "perm", "display is not local" );
509 goto bust;
511 if (ar[1][0] != 'v' || ar[1][1] != 't' ||
512 (vt = atoi( ar[1] + 2 )) <= 0)
514 if (!(di = findDisplayByName( ar[1] ))) {
515 fLog( d, fd, "noent", "display not found" );
516 goto bust;
518 if ((di->displayType & d_location) != dLocal) {
519 fLog( d, fd, "inval", "target display is not local" );
520 goto bust;
522 if (!di->serverVT) {
523 fLog( d, fd, "noent", "target display has no VT assigned" );
524 goto bust;
526 vt = di->serverVT;
528 if (!activateVT( vt )) {
529 fLog( d, fd, "inval", "VT switch failed" );
530 goto bust;
532 #endif
533 } else if (!strcmp( ar[0], "shutdown" )) {
534 ap = ar;
535 if (!*++ap)
536 goto miss;
537 sdr.force = SHUT_CANCEL;
538 sdr.osname = 0;
539 if (!strcmp( *ap, "status" )) {
540 if (*++ap)
541 goto exce;
542 bp = cbuf;
543 *bp++ = 'o';
544 *bp++ = 'k';
545 if (sdRec.how) {
546 strCat( &bp, "\tglobal," );
547 sdCat( &bp, &sdRec );
549 if (d && d->sdRec.how) {
550 strCat( &bp, "\tlocal," );
551 sdCat( &bp, &d->sdRec );
553 *bp++ = '\n';
554 writer( fd, cbuf, bp - cbuf );
555 goto bust;
556 } else if (!strcmp( *ap, "cancel" )) {
557 sdr.how = 0;
558 sdr.start = 0;
559 if (ap[1]) {
560 if (!d)
561 goto exce;
562 if (!strcmp( *++ap, "global" ))
563 sdr.start = TO_INF;
564 else if (strcmp( *ap, "local" )) {
565 fLog( d, fd, "bad", "invalid cancel scope %\"s", *ap );
566 goto bust;
569 } else {
570 if (!strcmp( *ap, "reboot" ))
571 sdr.how = SHUT_REBOOT;
572 else if (!strcmp( *ap, "halt" ))
573 sdr.how = SHUT_HALT;
574 else {
575 fLog( d, fd, "bad", "invalid type %\"s", *ap );
576 goto bust;
578 sdr.uid = -1;
579 if (!*++ap)
580 goto miss;
581 if (**ap == '=') {
582 switch (setBootOption( *ap + 1, &sdr )) {
583 case BO_NOMAN:
584 fLog( d, fd, "notsup", "boot options unavailable" );
585 goto bust;
586 case BO_NOENT:
587 fLog( d, fd, "noent", "no such boot option" );
588 goto bust;
589 case BO_IO:
590 fLog( d, fd, "io", "io error" );
591 goto bust;
593 if (!*++ap)
594 goto miss;
596 sdr.start = strtol( *ap, &bp, 10 );
597 if (bp != *ap && !*bp) {
598 if (**ap == '+')
599 sdr.start += now;
600 if (!*++ap)
601 goto miss;
602 sdr.timeout = strtol( *ap, &bp, 10 );
603 if (bp == *ap || *bp) {
604 fLog( d, fd, "bad", "invalid timeout %\"s", ar[3] );
605 goto bust;
607 if (**ap == '+')
608 sdr.timeout += sdr.start ? sdr.start : now;
609 if (sdr.timeout < 0)
610 sdr.timeout = TO_INF;
611 else {
612 if (!*++ap)
613 goto miss;
614 if (!strcmp( *ap, "force" ))
615 sdr.force = SHUT_FORCE;
616 else if (d && !strcmp( *ap, "forcemy" ))
617 sdr.force = SHUT_FORCEMY;
618 else if (strcmp( *ap, "cancel" )) {
619 fLog( d, fd, "bad", "invalid timeout action %\"s",
620 *ap );
621 goto bust;
624 } else {
625 sdr.timeout = 0;
626 if (d && !strcmp( *ap, "ask" ))
627 sdr.force = SHUT_ASK;
628 else if (!strcmp( *ap, "forcenow" ))
629 sdr.force = SHUT_FORCE;
630 else if (!strcmp( *ap, "schedule" ))
631 sdr.timeout = TO_INF;
632 else if (strcmp( *ap, "trynow" )) {
633 fLog( d, fd, "bad", "invalid mode %\"s", *ap );
634 goto bust;
638 if (*++ap)
639 goto exce;
640 if (d) {
641 sdr.uid = d->userSess >= 0 ? d->userSess : 0;
642 if (d->allowShutdown == SHUT_NONE ||
643 (d->allowShutdown == SHUT_ROOT && sdr.uid &&
644 sdr.force != SHUT_ASK))
646 fLog( d, fd, "perm", "shutdown forbidden" );
647 goto bust;
649 if (!sdr.how && !sdr.start) {
650 if (d->sdRec.osname)
651 free( d->sdRec.osname );
652 d->sdRec = sdr;
653 } else {
654 if (sdRec.how && sdRec.force == SHUT_FORCE &&
655 ((d->allowNuke == SHUT_NONE && sdRec.uid != sdr.uid) ||
656 (d->allowNuke == SHUT_ROOT && sdr.uid)))
658 fLog( d, fd, "perm", "overriding forced shutdown forbidden" );
659 goto bust;
661 if (sdr.force == SHUT_FORCE &&
662 (d->allowNuke == SHUT_NONE ||
663 (d->allowNuke == SHUT_ROOT && sdr.uid)))
665 fLog( d, fd, "perm", "forced shutdown forbidden" );
666 goto bust;
668 if (!sdr.start) {
669 if (d->sdRec.osname)
670 free( d->sdRec.osname );
671 d->sdRec = sdr;
672 } else {
673 if (!sdr.how)
674 cancelShutdown();
675 else {
676 if (sdRec.osname)
677 free( sdRec.osname );
678 sdRec = sdr;
682 } else {
683 if (!fifoAllowShutdown) {
684 fLog( d, fd, "perm", "shutdown forbidden" );
685 goto bust;
687 if (sdRec.how && sdRec.force == SHUT_FORCE &&
688 sdRec.uid != -1 && !fifoAllowNuke)
690 fLog( d, fd, "perm", "overriding forced shutdown forbidden" );
691 goto bust;
693 if (!sdr.how)
694 cancelShutdown();
695 else {
696 if (sdr.force != SHUT_CANCEL) {
697 if (!fifoAllowNuke) {
698 fLog( d, fd, "perm", "forced shutdown forbidden" );
699 goto bust;
701 } else {
702 if (!sdr.start && !sdr.timeout && anyUserLogins( -1 )) {
703 fLog( d, fd, "busy", "user sessions running" );
704 goto bust;
707 sdr.uid = -1;
708 if (sdRec.osname)
709 free( sdRec.osname );
710 sdRec = sdr;
713 } else if (!strcmp( ar[0], "listbootoptions" )) {
714 char **opts;
715 int def, cur, i, j;
717 if (ar[1])
718 goto exce;
719 switch (getBootOptions( &opts, &def, &cur )) {
720 case BO_NOMAN:
721 fLog( d, fd, "notsup", "boot options unavailable" );
722 goto bust;
723 case BO_IO:
724 fLog( d, fd, "io", "io error" );
725 goto bust;
727 Reply( "ok\t" );
728 for (i = 0; opts[i]; i++) {
729 bp = cbuf;
730 if (i)
731 *bp++ = ' ';
732 for (j = 0; opts[i][j]; j++)
733 if (opts[i][j] == ' ') {
734 *bp++ = '\\';
735 *bp++ = 's';
736 } else
737 *bp++ = opts[i][j];
738 writer( fd, cbuf, bp - cbuf );
740 freeStrArr( opts );
741 writer( fd, cbuf, sprintf( cbuf, "\t%d\t%d\n", def, cur ) );
742 goto bust;
743 } else if (d) {
744 if (!strcmp( ar[0], "lock" )) {
745 if (ar[1])
746 goto exce;
747 d->hstent->lock = True;
748 } else if (!strcmp( ar[0], "unlock" )) {
749 if (ar[1])
750 goto exce;
751 d->hstent->lock = False;
752 } else if (!strcmp( ar[0], "suicide" )) {
753 if (ar[1])
754 goto exce;
755 if (d->status == running && d->pid != -1) {
756 terminateProcess( d->pid, SIGTERM );
757 d->status = raiser;
759 } else {
760 fLog( d, fd, "nosys", "unknown command" );
761 goto bust;
763 } else {
764 if (!strcmp( ar[0], "login" )) {
765 int nuke;
766 if (arrLen( ar ) < 5) {
767 miss:
768 fLog( d, fd, "bad", "missing argument(s)" );
769 goto bust;
771 if (!(di = findDisplayByName( ar[1] ))) {
772 fLog( d, fd, "noent", "display %s not found", ar[1] );
773 goto bust;
775 if (ar[5]) {
776 if (!(args = unQuote( ar[5] ))) {
777 fLog( d, fd, "nomem", "out of memory" );
778 goto bust;
780 if (ar[6]) {
781 free( args );
782 exce:
783 fLog( d, fd, "bad", "excess argument(s)" );
784 goto bust;
786 setNLogin( di, ar[3], ar[4], args, 2 );
787 free( args );
788 } else
789 setNLogin( di, ar[3], ar[4], 0, 2 );
790 nuke = !strcmp( ar[2], "now" );
791 switch (di->status) {
792 case running:
793 if (di->pid != -1 && (di->userSess < 0 || nuke)) {
794 terminateProcess( di->pid, SIGTERM );
795 di->status = raiser;
797 break;
798 case remoteLogin:
799 if (di->serverPid != -1 && nuke)
800 terminateProcess( di->serverPid, di->termSignal );
801 break;
802 case reserve:
803 di->status = notRunning;
804 break;
805 case textMode:
806 #ifndef HAVE_VTS
807 switchToX( di );
808 #endif
809 break;
810 default:
811 break;
813 } else {
814 fLog( d, fd, "nosys", "unknown command" );
815 goto bust;
818 Reply( "ok\n" );
820 bust:
821 freeStrArr( ar );
824 static int
825 handleChan( struct display *d, struct bsock *cs, int fd, fd_set *reads )
827 char *bufp, *nbuf, *obuf, *eol;
828 int len, bl, llen;
829 char buf[1024];
831 bl = cs->buflen;
832 obuf = cs->buffer;
833 if (bl <= 0 && FD_ISSET( cs->fd, reads )) {
834 FD_CLR( cs->fd, reads );
835 bl = -bl;
836 memcpy( buf, obuf, bl );
837 if ((len = reader( cs->fd, buf + bl, sizeof(buf) - bl )) <= 0)
838 return -1;
839 bl += len;
840 bufp = buf;
841 } else {
842 len = 0;
843 bufp = obuf;
845 if (bl > 0) {
846 if ((eol = memchr( bufp, '\n', bl ))) {
847 llen = eol - bufp + 1;
848 bl -= llen;
849 if (bl) {
850 if (!(nbuf = Malloc( bl )))
851 return -1;
852 memcpy( nbuf, bufp + llen, bl );
853 } else
854 nbuf = 0;
855 cs->buffer = nbuf;
856 cs->buflen = bl;
857 processCtrl( bufp, llen - 1, fd, d );
858 if (obuf)
859 free( obuf );
860 return 1;
861 } else if (!len) {
862 if (fd >= 0)
863 cs->buflen = -bl;
864 else
865 fLog( d, -1, "bad", "unterminated command" );
868 return 0;
872 handleCtrl( fd_set *reads, struct display *d )
874 CtrlRec *cr = d ? &d->ctrl : &ctrl;
875 struct cmdsock *cs, **csp;
877 if (cr->fd >= 0 && FD_ISSET( cr->fd, reads ))
878 acceptSock( cr );
879 else {
880 for (csp = &cr->css; (cs = *csp); ) {
881 switch (handleChan( d, &cs->sock, cs->sock.fd, reads )) {
882 case -1:
883 *csp = cs->next;
884 nukeSock( cs );
885 continue;
886 case 1:
887 return True;
888 default:
889 break;
891 csp = &cs->next;
894 return False;