FreeBSD 10 clang port
[oweals/cde.git] / cde / lib / DtTerm / TermPrim / TermPrimUtil.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 #ifndef lint
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 */
27 #endif  /* lint */
28
29 /*                                                                      *
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.                                          *
37  */
38
39 #include "TermHeader.h"
40 #include "TermPrimOSDepI.h"
41 #include "TermPrimP.h"
42 #include "TermPrimData.h"
43 #include "TermPrimUtil.h"
44 #include "TermPrimDebug.h"
45 #include "Xm/Xm.h"
46 #include <errno.h>
47 #include <signal.h>
48 #include <sys/file.h>
49
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) ;
54
55 /*
56 ** the following white pixmap is used to create the noPointer (blank) pointer.
57 */
58 #define whiteW 16
59 #define whiteH 16
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};
65
66 static void
67 InitPointerBlank(Widget w)
68 {
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;
74
75     /*
76     ** set a pointer motion handler...
77     */
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);
83
84     tpd->noPointer   = XCreatePixmapCursor(XtDisplay(tw),
85                                    noPointerBitmap,  /* source bitmap    */
86                                    noPointerBitmap,  /* mask bitmap      */
87                                    &fg, &bg,         /* Do not care      */
88                                    0, 0);            /* hotspot          */
89
90     XFreePixmap(XtDisplay(w), noPointerBitmap);
91     XtAddEventHandler((Widget)tw, PointerMotionMask, FALSE, PointerMoved, 
92                                        (XtPointer)NULL);
93
94     tpd->pointerFirst = False ;
95 }
96
97 static void 
98 PointerMoved(Widget w, XtPointer closure, XEvent *event, Boolean *cont)
99 {
100     DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) w;
101     DtTermPrimData tpd = tw->term.tpd;
102
103     if (!tpd->pointerFrozen) {
104         if (tpd->pointerOn) {
105             /*
106             ** pointer is on, just reset the timer...
107             */
108             if (tw->term.pointerBlankDelay) {
109                 /*
110                 ** remove the old motion timeout...
111                 */
112                 if (tpd->pointerTimeoutID)
113                     XtRemoveTimeOut(tpd->pointerTimeoutID);
114
115                 /*
116                 ** and set a new motion timeout...
117                 */
118                 tpd->pointerTimeoutID = 
119                       XtAppAddTimeOut(XtWidgetToApplicationContext((Widget)tw),
120                       (unsigned long) 1000 * tw->term.pointerBlankDelay,
121                       (XtTimerCallbackProc) _DtTermPrimPointerOff,
122                       (XtPointer)tw);
123             }
124         } else {
125             /* pointer is off, turn it on... */
126             (void) _DtTermPrimPointerOn(w);
127         }
128     }
129 }
130
131 void
132 _DtTermPrimPointerOff(Widget w, XtIntervalId *id)
133 {
134     DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) w;
135     DtTermPrimData tpd = tw->term.tpd;
136
137     if (tpd->pointerFirst) InitPointerBlank(w) ;
138
139     if (tpd->pointerOn) {
140         /*
141         ** define the window's cursor...
142         */
143         (void) XDefineCursor(XtDisplay(tw), XtWindow(tw), tpd->noPointer);
144
145         /*
146         ** remove the motion timeout...
147         */
148         if (tw->term.pointerBlankDelay) {
149             if (tpd->pointerTimeoutID)
150                 XtRemoveTimeOut(tpd->pointerTimeoutID);
151             tpd->pointerTimeoutID = 0;
152         }
153
154         /*
155         ** and clear the pointer on flag...
156         */
157         tpd->pointerOn = False;
158     }
159     return;
160 }
161
162 void 
163 _DtTermPrimPointerOn(Widget w)
164 {
165     DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) w;
166     DtTermPrimData tpd = tw->term.tpd;
167
168     if (tpd->pointerFirst) InitPointerBlank(w) ;
169
170     if (!tpd->pointerOn) {
171         /*
172         ** define the window's cursor...
173         */
174         XDefineCursor(XtDisplay(tw), XtWindow(tw), tw->term.pointerShape);
175
176         /*
177         ** set a motion timeout...
178         */
179         if (tw->term.pointerBlankDelay) {
180             if (tpd->pointerTimeoutID)
181                 /*
182                 ** remove old timeout...
183                 */
184                 XtRemoveTimeOut(tpd->pointerTimeoutID);
185
186             tpd->pointerTimeoutID = 
187                     XtAppAddTimeOut(XtWidgetToApplicationContext((Widget)tw),
188                     (unsigned long) (1000 * tw->term.pointerBlankDelay),
189                     (XtTimerCallbackProc)_DtTermPrimPointerOff, (XtPointer)tw);
190         }
191         /*
192         ** and set the pointer on flag...
193         */
194         tpd->pointerOn = True;
195     }
196     return;
197 }
198
199 void 
200 _DtTermPrimPointerFreeze(Widget w, Boolean freeze)
201 {
202     DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) w;
203     DtTermPrimData tpd = tw->term.tpd;
204
205     tpd->pointerFrozen = freeze;
206
207     /*
208     ** make sure that the pointer is on...
209     */
210     if (tpd->pointerOn) {
211         /*
212         ** pointer is on...
213         */
214         if (tw->term.pointerBlankDelay) {
215             if (freeze) {
216                 /*
217                 ** freezing -- turn the timeout off...
218                 */
219                 if (tpd->pointerTimeoutID)
220                     XtRemoveTimeOut(tpd->pointerTimeoutID);
221
222                 tpd->pointerTimeoutID = 0;
223             } 
224             else {
225                 /*
226                 ** un freezing -- turn the timeout on...
227                 */
228                 if (tpd->pointerTimeoutID)
229                     /*
230                     ** remove old timeout...
231                     */
232                     XtRemoveTimeOut(tpd->pointerTimeoutID);
233
234                 tpd->pointerTimeoutID = 
235                        XtAppAddTimeOut(XtWidgetToApplicationContext((Widget)tw),
236                        (unsigned long) 1000 * tw->term.pointerBlankDelay,
237                        (XtTimerCallbackProc) _DtTermPrimPointerOff,
238                        (XtPointer)tw);
239             }
240         }
241     } 
242     else {
243         /*
244         ** let's turn on the pointer...
245         ** define the window's cursor...
246         */
247         XDefineCursor(XtDisplay(tw), XtWindow(tw), tw->term.pointerShape);
248
249         if (freeze)
250             /*
251             ** the timeout is off, so we don't need to clear it...
252             */
253             /* NOOP */ ;
254         else
255             /*
256             ** we are unfreezing -- turn the timeout on...
257             */
258             if (tw->term.pointerBlankDelay) {
259                 if (tpd->pointerTimeoutID)
260                     /*
261                     ** remove old timeout...
262                     */
263                     XtRemoveTimeOut(tpd->pointerTimeoutID);
264
265                 tpd->pointerTimeoutID = 
266                       XtAppAddTimeOut(XtWidgetToApplicationContext((Widget)tw),
267                       (unsigned long) (1000 * tw->term.pointerBlankDelay),
268                       (XtTimerCallbackProc)_DtTermPrimPointerOff,(XtPointer)tw);
269             }
270         /*
271         ** and set the flag...
272         */
273         tpd->pointerOn = True;
274     }
275     return;
276 }
277
278 void
279 _DtTermPrimRecolorPointer(Widget w)
280 {
281     DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) w;
282
283     XColor colordefs[2];        /* 0 is foreground, 1 is background */
284     Display *dpy = XtDisplay(w);
285
286     colordefs[0].pixel = tw->term.pointerColor;
287     colordefs[1].pixel = tw->term.pointerColorBackground;
288     XQueryColors (dpy, DefaultColormap (dpy, DefaultScreen (dpy)),
289           colordefs, 2);
290     XRecolorCursor (dpy, tw->term.pointerShape, colordefs, colordefs+1);
291     return;
292 }
293
294 /* linked list of log files to flush if we are killed...
295  */
296 typedef struct _logInfo {
297     FILE *logFile;
298     struct _logInfo *next;
299     struct _logInfo *prev;
300 } logInfo;
301
302 static logInfo _logInfoHead;
303 static logInfo *logInfoHead = &_logInfoHead;
304
305 static void
306 AddLogFileEntry
307 (
308     FILE                 *logFile
309 )
310 {
311     logInfo              *logInfoTmp;
312     sigset_t              newSigs;
313     sigset_t              oldSigs;
314
315     /* malloc a new entry... */
316     logInfoTmp = (logInfo *) XtMalloc(sizeof(logInfo));
317     (void) memset(logInfoTmp, '\0', sizeof(logInfo));
318
319     /* fill in the structure... */
320     logInfoTmp->logFile = logFile;
321
322     /* insert it after the head of the list...
323      */
324     /* block all signals... */
325     (void) sigfillset(&newSigs);
326     (void) sigemptyset(&oldSigs);
327     (void) sigprocmask(SIG_BLOCK, &newSigs, &oldSigs);
328
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;
336     }
337     _DtTermProcessUnlock();
338
339     /* restore signals... */
340     (void) sigprocmask(SIG_SETMASK, &oldSigs, (sigset_t *) 0);
341 }
342
343 static void
344 DeleteLogFileEntry
345 (
346     FILE                 *logFile
347 )
348 {
349     logInfo              *logInfoTmp;
350     sigset_t              newSigs;
351     sigset_t              oldSigs;
352
353     /* find the entry... */
354     _DtTermProcessLock();
355     for (logInfoTmp = logInfoHead->next; logInfoTmp;
356             logInfoTmp = logInfoTmp->next) {
357         if (logInfoTmp->logFile == logFile) {
358             break;
359         }
360     }
361
362     /* did we find anything... */
363     if (!logInfoTmp) {
364         /* not found... */
365         _DtTermProcessUnlock();
366         return;
367     }
368
369     /* delete entry from the list...
370      */
371     /* block all signals... */
372     (void) sigfillset(&newSigs);
373     (void) sigemptyset(&oldSigs);
374     (void) sigprocmask(SIG_BLOCK, &newSigs, &oldSigs);
375
376     /* remove it... */
377     logInfoTmp->prev->next = logInfoTmp->next;
378     if (logInfoTmp->next) {
379         logInfoTmp->next->prev = logInfoTmp->prev;
380     }
381
382     /* restore signals... */
383     (void) sigprocmask(SIG_SETMASK, &oldSigs, (sigset_t *) 0);
384
385     /* free up the data... */
386     (void) XtFree((char *) logInfoTmp);
387     _DtTermProcessUnlock();
388 }
389
390 #ifdef NOTDEF
391 void 
392 logpipe(Widget w)
393 {
394     win_data *wp = &term->Wp;
395
396     if (wp->log_on) { CloseLog(wp); }
397 }
398 #endif  /* NOTDEF */
399
400
401 void
402 _DtTermPrimStartLog(Widget w)
403 {
404     DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) w;
405     DtTermPrimData tpd = tw->term.tpd;
406
407     char            *cp;
408     int              i;
409
410     if ( tw->term.log_on || tw->term.logInhibit ) { return; }
411
412     if (!tw->term.logFile || !*tw->term.logFile) {
413         tw->term.logFile = "DttermLogXXXXX";
414     }
415
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);
420
421         (void) mktemp(cp);
422         if (cp && *cp) {
423             tw->term.logFile = cp;
424         } else {
425             (void) XtFree(cp);
426             return;
427         }
428     }
429
430     if ('|' == *tw->term.logFile ) {
431         /*
432         ** pipe logfile into command
433         */
434         int p[2];
435
436         _DtTermProcessLock();
437         if (pipe(p) < 0 || (i = fork()) < 0) {
438             _DtTermProcessUnlock();
439             return;
440         }
441
442         if (i == 0) {
443             /*
444             ** child
445             */
446             _DtTermProcessUnlock();
447
448             /* Remove suid root capability...
449              */
450             (void) _DtTermPrimRemoveSuidRoot();
451
452             (void) close(p[1]);
453             (void) close(0);
454             (void) dup(p[0]);
455             (void) close(p[0]);
456             /*
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);
460             }
461             /*
462             ** reset signals
463             */
464             (void) signal(SIGHUP, SIG_DFL);
465             (void) signal(SIGCHLD, SIG_DFL);
466 #ifdef  BBA
467             _bA_dump();
468 #endif  /* BBA */
469             (void) execl(DEFAULT_SHELL, DEFAULT_SHELL_ARGV0, 
470                          "-c", &tw->term.logFile[1], NULL);
471             (void) fprintf(stderr, " Can't exec \"%s\"\n",
472                                        &tw->term.logFile[1]);
473             (void) exit(1);
474         }
475
476         _DtTermProcessUnlock();
477         (void) close(p[0]);
478         tpd->logStream = fdopen(p[1], "w");
479         (void) AddLogFileEntry(tpd->logStream);
480         (void) signal(SIGPIPE, SIG_IGN);
481     }
482     else {
483         if (access(tw->term.logFile, F_OK) == 0) {
484             if (access(tw->term.logFile, W_OK) < 0) {
485                 return;
486             }
487         } else if ((cp = strrchr(tw->term.logFile, '/'))) {
488             *cp = 0;
489             i   = access(tw->term.logFile, W_OK);
490             *cp = '/';
491             if (i < 0) {
492                 return;
493             }
494         } else if (access(".", W_OK) < 0) {
495             return;
496         }
497         if ((tpd->logStream = fopen(tw->term.logFile, "a")) == NULL) {
498             return;
499         }
500         (void) AddLogFileEntry(tpd->logStream);
501         (void) chown(tw->term.logFile, getuid(), getgid());
502     }
503     tw->term.log_on = True ;
504 }
505
506 static void
507 ForceCloseLog(DtTermPrimitiveWidget tw)
508 {
509     DtTermPrimData tpd = tw->term.tpd;
510
511     if (tw->term.log_on)
512     {
513         (void) fclose(tpd->logStream);
514         (void) DeleteLogFileEntry(tpd->logStream);
515         tw->term.log_on = False;
516     }
517 }
518
519 void
520 _DtTermPrimCloseLog(Widget w)
521 {
522     DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) w;
523     DtTermPrimData tpd = tw->term.tpd;
524
525     /*
526     ** if we are not logging, or it is inhibited, do nothing
527     */
528     if (!tw->term.log_on || tw->term.logInhibit ) { return; }
529
530     (void) fflush(tpd->logStream);
531     ForceCloseLog(tw);
532 }
533
534 void
535 _DtTermPrimWriteLog(DtTermPrimitiveWidget tw, char *buffer, int cnt)
536 {
537     DtTermPrimData tpd = tw->term.tpd;
538
539     if (cnt > 0)
540     {
541         _DtTermProcessLock();
542
543         (void) fwrite(buffer, cnt, 1, tpd->logStream);
544
545         if ((errno == EPIPE) && ferror(tpd->logStream))
546         {
547             ForceCloseLog(tw);
548         }
549
550         _DtTermProcessUnlock();
551     }
552 }
553
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;
559
560 static void
561 suidInit()
562 {
563     _DtTermProcessLock();
564     if (first) {
565         uid_user = getuid();
566         uid_root = geteuid();
567
568         gid_user = getgid();
569         gid_root = getegid();
570
571         first = False;
572     }
573     _DtTermProcessUnlock();
574 }
575
576 void
577 _DtTermPrimRemoveSuidRoot()
578 {
579     (void) suidInit();
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 */
590 }
591
592 void
593 _DtTermPrimToggleSuidRoot(Boolean root)
594 {
595     (void) suidInit();
596
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 */
604 }
605
606 void
607 _DtTermPrimLogFileCleanup
608 (
609     void
610 )
611 {
612     logInfo              *logInfoTmp;
613
614     DebugF('s', 10, fprintf(stderr,
615             ">>_DtTermPrimLogFileCleanup() starting\n"));
616
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);
624     }
625     _DtTermProcessUnlock();
626     DebugF('s', 10, fprintf(stderr,
627             ">>_DtTermPrimLogFileCleanup() finished\n"));
628 }