2 * CDE - Common Desktop Environment
4 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
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)
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
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
24 #ifdef VERBOSE_REV_INFO
25 static char rcs_id[] = "$TOG: TermPrimUtil.c /main/3 1997/04/17 18:25:29 samborn $";
26 #endif /* VERBOSE_REV_INFO */
30 * (c) Copyright 1993, 1994, 1996 Hewlett-Packard Company *
31 * (c) Copyright 1993, 1994, 1996 International Business Machines Corp. *
32 * (c) Copyright 1993, 1994, 1996 Sun Microsystems, Inc. *
33 * (c) Copyright 1993, 1994, 1996 Novell, Inc. *
34 * (c) Copyright 1996 Digital Equipment Corporation. *
35 * (c) Copyright 1996 FUJITSU LIMITED. *
36 * (c) Copyright 1996 Hitachi. *
39 #include "TermHeader.h"
40 #include "TermPrimOSDepI.h"
41 #include "TermPrimP.h"
42 #include "TermPrimData.h"
43 #include "TermPrimUtil.h"
44 #include "TermPrimDebug.h"
50 void _DtTermPrimRemoveSuidRoot();
51 static void ForceCloseLog(DtTermPrimitiveWidget);
52 static void PointerMoved(Widget w, XtPointer closure, XEvent *event, Boolean *cont) ;
53 void _DtTermPrimPointerOff(Widget w, XtIntervalId *id) ;
56 ** the following white pixmap is used to create the noPointer (blank) pointer.
60 static char whiteBits[] = {
61 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
62 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
63 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
64 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
67 InitPointerBlank(Widget w)
69 DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) w;
70 DtTermPrimData tpd = tw->term.tpd;
71 XColor fg = { 0, 0, 0, 0, DoRed | DoGreen | DoBlue, 0 };
72 XColor bg = { 0, 0, 0, 0, DoRed | DoGreen | DoBlue, 0 };
73 Pixmap noPointerBitmap;
76 ** set a pointer motion handler...
78 tpd->pointerTimeoutID = 0 ;
79 tpd->pointerFrozen = True ;
80 fg.pixel = bg.pixel = BlackPixelOfScreen(XtScreen(w));
81 noPointerBitmap = XCreateBitmapFromData(XtDisplay(w),XtWindow(tw),
82 whiteBits, whiteW, whiteH);
84 tpd->noPointer = XCreatePixmapCursor(XtDisplay(tw),
85 noPointerBitmap, /* source bitmap */
86 noPointerBitmap, /* mask bitmap */
87 &fg, &bg, /* Do not care */
90 XFreePixmap(XtDisplay(w), noPointerBitmap);
91 XtAddEventHandler((Widget)tw, PointerMotionMask, FALSE, PointerMoved,
94 tpd->pointerFirst = False ;
98 PointerMoved(Widget w, XtPointer closure, XEvent *event, Boolean *cont)
100 DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) w;
101 DtTermPrimData tpd = tw->term.tpd;
103 if (!tpd->pointerFrozen) {
104 if (tpd->pointerOn) {
106 ** pointer is on, just reset the timer...
108 if (tw->term.pointerBlankDelay) {
110 ** remove the old motion timeout...
112 if (tpd->pointerTimeoutID)
113 XtRemoveTimeOut(tpd->pointerTimeoutID);
116 ** and set a new motion timeout...
118 tpd->pointerTimeoutID =
119 XtAppAddTimeOut(XtWidgetToApplicationContext((Widget)tw),
120 (unsigned long) 1000 * tw->term.pointerBlankDelay,
121 (XtTimerCallbackProc) _DtTermPrimPointerOff,
125 /* pointer is off, turn it on... */
126 (void) _DtTermPrimPointerOn(w);
132 _DtTermPrimPointerOff(Widget w, XtIntervalId *id)
134 DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) w;
135 DtTermPrimData tpd = tw->term.tpd;
137 if (tpd->pointerFirst) InitPointerBlank(w) ;
139 if (tpd->pointerOn) {
141 ** define the window's cursor...
143 (void) XDefineCursor(XtDisplay(tw), XtWindow(tw), tpd->noPointer);
146 ** remove the motion timeout...
148 if (tw->term.pointerBlankDelay) {
149 if (tpd->pointerTimeoutID)
150 XtRemoveTimeOut(tpd->pointerTimeoutID);
151 tpd->pointerTimeoutID = 0;
155 ** and clear the pointer on flag...
157 tpd->pointerOn = False;
163 _DtTermPrimPointerOn(Widget w)
165 DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) w;
166 DtTermPrimData tpd = tw->term.tpd;
168 if (tpd->pointerFirst) InitPointerBlank(w) ;
170 if (!tpd->pointerOn) {
172 ** define the window's cursor...
174 XDefineCursor(XtDisplay(tw), XtWindow(tw), tw->term.pointerShape);
177 ** set a motion timeout...
179 if (tw->term.pointerBlankDelay) {
180 if (tpd->pointerTimeoutID)
182 ** remove old timeout...
184 XtRemoveTimeOut(tpd->pointerTimeoutID);
186 tpd->pointerTimeoutID =
187 XtAppAddTimeOut(XtWidgetToApplicationContext((Widget)tw),
188 (unsigned long) (1000 * tw->term.pointerBlankDelay),
189 (XtTimerCallbackProc)_DtTermPrimPointerOff, (XtPointer)tw);
192 ** and set the pointer on flag...
194 tpd->pointerOn = True;
200 _DtTermPrimPointerFreeze(Widget w, Boolean freeze)
202 DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) w;
203 DtTermPrimData tpd = tw->term.tpd;
205 tpd->pointerFrozen = freeze;
208 ** make sure that the pointer is on...
210 if (tpd->pointerOn) {
214 if (tw->term.pointerBlankDelay) {
217 ** freezing -- turn the timeout off...
219 if (tpd->pointerTimeoutID)
220 XtRemoveTimeOut(tpd->pointerTimeoutID);
222 tpd->pointerTimeoutID = 0;
226 ** un freezing -- turn the timeout on...
228 if (tpd->pointerTimeoutID)
230 ** remove old timeout...
232 XtRemoveTimeOut(tpd->pointerTimeoutID);
234 tpd->pointerTimeoutID =
235 XtAppAddTimeOut(XtWidgetToApplicationContext((Widget)tw),
236 (unsigned long) 1000 * tw->term.pointerBlankDelay,
237 (XtTimerCallbackProc) _DtTermPrimPointerOff,
244 ** let's turn on the pointer...
245 ** define the window's cursor...
247 XDefineCursor(XtDisplay(tw), XtWindow(tw), tw->term.pointerShape);
251 ** the timeout is off, so we don't need to clear it...
256 ** we are unfreezing -- turn the timeout on...
258 if (tw->term.pointerBlankDelay) {
259 if (tpd->pointerTimeoutID)
261 ** remove old timeout...
263 XtRemoveTimeOut(tpd->pointerTimeoutID);
265 tpd->pointerTimeoutID =
266 XtAppAddTimeOut(XtWidgetToApplicationContext((Widget)tw),
267 (unsigned long) (1000 * tw->term.pointerBlankDelay),
268 (XtTimerCallbackProc)_DtTermPrimPointerOff,(XtPointer)tw);
271 ** and set the flag...
273 tpd->pointerOn = True;
279 _DtTermPrimRecolorPointer(Widget w)
281 DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) w;
283 XColor colordefs[2]; /* 0 is foreground, 1 is background */
284 Display *dpy = XtDisplay(w);
286 colordefs[0].pixel = tw->term.pointerColor;
287 colordefs[1].pixel = tw->term.pointerColorBackground;
288 XQueryColors (dpy, DefaultColormap (dpy, DefaultScreen (dpy)),
290 XRecolorCursor (dpy, tw->term.pointerShape, colordefs, colordefs+1);
294 /* linked list of log files to flush if we are killed...
296 typedef struct _logInfo {
298 struct _logInfo *next;
299 struct _logInfo *prev;
302 static logInfo _logInfoHead;
303 static logInfo *logInfoHead = &_logInfoHead;
315 /* malloc a new entry... */
316 logInfoTmp = (logInfo *) XtMalloc(sizeof(logInfo));
317 (void) memset(logInfoTmp, '\0', sizeof(logInfo));
319 /* fill in the structure... */
320 logInfoTmp->logFile = logFile;
322 /* insert it after the head of the list...
324 /* block all signals... */
325 (void) sigfillset(&newSigs);
326 (void) sigemptyset(&oldSigs);
327 (void) sigprocmask(SIG_BLOCK, &newSigs, &oldSigs);
329 /* insert the entry into the list... */
330 _DtTermProcessLock();
331 logInfoTmp->prev = logInfoHead;
332 logInfoTmp->next = logInfoHead->next;
333 logInfoHead->next = logInfoTmp;
334 if (logInfoTmp->next) {
335 logInfoTmp->next->prev = logInfoTmp;
337 _DtTermProcessUnlock();
339 /* restore signals... */
340 (void) sigprocmask(SIG_SETMASK, &oldSigs, (sigset_t *) 0);
353 /* find the entry... */
354 _DtTermProcessLock();
355 for (logInfoTmp = logInfoHead->next; logInfoTmp;
356 logInfoTmp = logInfoTmp->next) {
357 if (logInfoTmp->logFile == logFile) {
362 /* did we find anything... */
365 _DtTermProcessUnlock();
369 /* delete entry from the list...
371 /* block all signals... */
372 (void) sigfillset(&newSigs);
373 (void) sigemptyset(&oldSigs);
374 (void) sigprocmask(SIG_BLOCK, &newSigs, &oldSigs);
377 logInfoTmp->prev->next = logInfoTmp->next;
378 if (logInfoTmp->next) {
379 logInfoTmp->next->prev = logInfoTmp->prev;
382 /* restore signals... */
383 (void) sigprocmask(SIG_SETMASK, &oldSigs, (sigset_t *) 0);
385 /* free up the data... */
386 (void) XtFree((char *) logInfoTmp);
387 _DtTermProcessUnlock();
394 win_data *wp = &term->Wp;
396 if (wp->log_on) { CloseLog(wp); }
402 _DtTermPrimStartLog(Widget w)
404 DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) w;
405 DtTermPrimData tpd = tw->term.tpd;
410 if ( tw->term.log_on || tw->term.logInhibit ) { return; }
412 if (!tw->term.logFile || !*tw->term.logFile) {
413 tw->term.logFile = "DttermLogXXXXX";
416 if (!strcmp(tw->term.logFile + strlen(tw->term.logFile) - 5, "XXXXX")) {
417 /* make a local copy in case we are going to change it... */
418 cp = XtMalloc(strlen(tw->term.logFile) + 1);
419 (void) strcpy(cp, tw->term.logFile);
423 tw->term.logFile = cp;
430 if ('|' == *tw->term.logFile ) {
432 ** pipe logfile into command
436 _DtTermProcessLock();
437 if (pipe(p) < 0 || (i = fork()) < 0) {
438 _DtTermProcessUnlock();
446 _DtTermProcessUnlock();
448 /* Remove suid root capability...
450 (void) _DtTermPrimRemoveSuidRoot();
457 ** set close on exec flag on all other fd's
458 */ for (i = 3; i < _NFILE; i++) {
459 (void) fcntl(i, F_SETFD, 1);
464 (void) signal(SIGHUP, SIG_DFL);
465 (void) signal(SIGCLD, SIG_DFL);
469 (void) execl(DEFAULT_SHELL, DEFAULT_SHELL_ARGV0,
470 "-c", &tw->term.logFile[1], 0);
471 (void) fprintf(stderr, " Can't exec \"%s\"\n",
472 &tw->term.logFile[1]);
476 _DtTermProcessUnlock();
478 tpd->logStream = fdopen(p[1], "w");
479 (void) AddLogFileEntry(tpd->logStream);
480 (void) signal(SIGPIPE, SIG_IGN);
483 if (access(tw->term.logFile, F_OK) == 0) {
484 if (access(tw->term.logFile, W_OK) < 0) {
487 } else if (cp = strrchr(tw->term.logFile, '/')) {
489 i = access(tw->term.logFile, W_OK);
494 } else if (access(".", W_OK) < 0) {
497 if ((tpd->logStream = fopen(tw->term.logFile, "a")) == NULL) {
500 (void) AddLogFileEntry(tpd->logStream);
501 (void) chown(tw->term.logFile, getuid(), getgid());
503 tw->term.log_on = True ;
507 ForceCloseLog(DtTermPrimitiveWidget tw)
509 DtTermPrimData tpd = tw->term.tpd;
513 (void) fclose(tpd->logStream);
514 (void) DeleteLogFileEntry(tpd->logStream);
515 tw->term.log_on = False;
520 _DtTermPrimCloseLog(Widget w)
522 DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) w;
523 DtTermPrimData tpd = tw->term.tpd;
526 ** if we are not logging, or it is inhibited, do nothing
528 if (!tw->term.log_on || tw->term.logInhibit ) { return; }
530 (void) fflush(tpd->logStream);
535 _DtTermPrimWriteLog(DtTermPrimitiveWidget tw, char *buffer, int cnt)
537 DtTermPrimData tpd = tw->term.tpd;
541 _DtTermProcessLock();
543 (void) fwrite(buffer, cnt, 1, tpd->logStream);
545 if ((errno == EPIPE) && ferror(tpd->logStream))
550 _DtTermProcessUnlock();
554 static Boolean first = True;
555 static uid_t uid_user;
556 static uid_t uid_root;
557 static gid_t gid_user;
558 static gid_t gid_root;
563 _DtTermProcessLock();
566 uid_root = geteuid();
569 gid_root = getegid();
573 _DtTermProcessUnlock();
577 _DtTermPrimRemoveSuidRoot()
580 #if defined(HAS_SETRESUID)
581 (void) setresgid(gid_user, gid_user, gid_user);
582 (void) setresuid(uid_user, uid_user, uid_user);
583 #elif defined(HAS_SETREUID)
584 (void) setregid(gid_user, gid_user);
585 (void) setreuid(uid_user, uid_user);
586 #else /* !HAS_SETRESUID && !HAS_SETREUID */
587 (void) setgid(gid_user);
588 (void) setuid(uid_user);
589 #endif /* !HAS_SETRESUID && !HAS_SETREUID */
593 _DtTermPrimToggleSuidRoot(Boolean root)
597 #if defined(HAS_SETRESUID)
598 (void) setresuid(-1, root ? uid_root : uid_user, -1);
599 (void) setresgid(-1, root ? gid_root : gid_user, -1);
600 #elif defined(HAS_SETEUID)
601 (void) seteuid(root ? uid_root : uid_user);
602 (void) setegid(root ? gid_root : gid_user);
603 #endif /* HAS_SETEUID */
607 _DtTermPrimLogFileCleanup
614 DebugF('s', 10, fprintf(stderr,
615 ">>_DtTermPrimLogFileCleanup() starting\n"));
617 /* flush all the log files... */
618 _DtTermProcessLock();
619 for (logInfoTmp = logInfoHead->next; logInfoTmp;
620 logInfoTmp = logInfoTmp->next) {
621 DebugF('s', 10, fprintf(stderr,
622 ">>flushing logfile 0x%lx\n", logInfoTmp->logFile));
623 (void) fflush(logInfoTmp->logFile);
625 _DtTermProcessUnlock();
626 DebugF('s', 10, fprintf(stderr,
627 ">>_DtTermPrimLogFileCleanup() finished\n"));