mirror of
git://git.code.sf.net/p/cdesktopenv/code
synced 2025-03-09 15:50:02 +00:00
This patch removes hpversion.h from the repository, this also untangles a lot of ifdef mess. This closes bug CDExc19524.
623 lines
16 KiB
C
623 lines
16 KiB
C
/*
|
|
* CDE - Common Desktop Environment
|
|
*
|
|
* Copyright (c) 1993-2012, The Open Group. All rights reserved.
|
|
*
|
|
* These libraries and programs are free software; you can
|
|
* redistribute them and/or modify them under the terms of the GNU
|
|
* Lesser General Public License as published by the Free Software
|
|
* Foundation; either version 2 of the License, or (at your option)
|
|
* any later version.
|
|
*
|
|
* These libraries and programs are distributed in the hope that
|
|
* they will be useful, but WITHOUT ANY WARRANTY; without even the
|
|
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
|
* PURPOSE. See the GNU Lesser General Public License for more
|
|
* details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with these libraries and programs; if not, write
|
|
* to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
|
|
* Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
/* *
|
|
* (c) Copyright 1993, 1994, 1996 Hewlett-Packard Company *
|
|
* (c) Copyright 1993, 1994, 1996 International Business Machines Corp. *
|
|
* (c) Copyright 1993, 1994, 1996 Sun Microsystems, Inc. *
|
|
* (c) Copyright 1993, 1994, 1996 Novell, Inc. *
|
|
* (c) Copyright 1996 Digital Equipment Corporation. *
|
|
* (c) Copyright 1996 FUJITSU LIMITED. *
|
|
* (c) Copyright 1996 Hitachi. *
|
|
*/
|
|
|
|
#include "TermHeader.h"
|
|
#include "TermPrimOSDepI.h"
|
|
#include "TermPrimP.h"
|
|
#include "TermPrimData.h"
|
|
#include "TermPrimUtil.h"
|
|
#include "TermPrimDebug.h"
|
|
#include "Xm/Xm.h"
|
|
#include <errno.h>
|
|
#include <signal.h>
|
|
#include <sys/file.h>
|
|
|
|
void _DtTermPrimRemoveSuidRoot();
|
|
static void ForceCloseLog(DtTermPrimitiveWidget);
|
|
static void PointerMoved(Widget w, XtPointer closure, XEvent *event, Boolean *cont) ;
|
|
void _DtTermPrimPointerOff(Widget w, XtIntervalId *id) ;
|
|
|
|
/*
|
|
** the following white pixmap is used to create the noPointer (blank) pointer.
|
|
*/
|
|
#define whiteW 16
|
|
#define whiteH 16
|
|
static char whiteBits[] = {
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
|
|
|
static void
|
|
InitPointerBlank(Widget w)
|
|
{
|
|
DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) w;
|
|
DtTermPrimData tpd = tw->term.tpd;
|
|
XColor fg = { 0, 0, 0, 0, DoRed | DoGreen | DoBlue, 0 };
|
|
XColor bg = { 0, 0, 0, 0, DoRed | DoGreen | DoBlue, 0 };
|
|
Pixmap noPointerBitmap;
|
|
|
|
/*
|
|
** set a pointer motion handler...
|
|
*/
|
|
tpd->pointerTimeoutID = 0 ;
|
|
tpd->pointerFrozen = True ;
|
|
fg.pixel = bg.pixel = BlackPixelOfScreen(XtScreen(w));
|
|
noPointerBitmap = XCreateBitmapFromData(XtDisplay(w),XtWindow(tw),
|
|
whiteBits, whiteW, whiteH);
|
|
|
|
tpd->noPointer = XCreatePixmapCursor(XtDisplay(tw),
|
|
noPointerBitmap, /* source bitmap */
|
|
noPointerBitmap, /* mask bitmap */
|
|
&fg, &bg, /* Do not care */
|
|
0, 0); /* hotspot */
|
|
|
|
XFreePixmap(XtDisplay(w), noPointerBitmap);
|
|
XtAddEventHandler((Widget)tw, PointerMotionMask, FALSE, PointerMoved,
|
|
(XtPointer)NULL);
|
|
|
|
tpd->pointerFirst = False ;
|
|
}
|
|
|
|
static void
|
|
PointerMoved(Widget w, XtPointer closure, XEvent *event, Boolean *cont)
|
|
{
|
|
DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) w;
|
|
DtTermPrimData tpd = tw->term.tpd;
|
|
|
|
if (!tpd->pointerFrozen) {
|
|
if (tpd->pointerOn) {
|
|
/*
|
|
** pointer is on, just reset the timer...
|
|
*/
|
|
if (tw->term.pointerBlankDelay) {
|
|
/*
|
|
** remove the old motion timeout...
|
|
*/
|
|
if (tpd->pointerTimeoutID)
|
|
XtRemoveTimeOut(tpd->pointerTimeoutID);
|
|
|
|
/*
|
|
** and set a new motion timeout...
|
|
*/
|
|
tpd->pointerTimeoutID =
|
|
XtAppAddTimeOut(XtWidgetToApplicationContext((Widget)tw),
|
|
(unsigned long) 1000 * tw->term.pointerBlankDelay,
|
|
(XtTimerCallbackProc) _DtTermPrimPointerOff,
|
|
(XtPointer)tw);
|
|
}
|
|
} else {
|
|
/* pointer is off, turn it on... */
|
|
(void) _DtTermPrimPointerOn(w);
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
_DtTermPrimPointerOff(Widget w, XtIntervalId *id)
|
|
{
|
|
DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) w;
|
|
DtTermPrimData tpd = tw->term.tpd;
|
|
|
|
if (tpd->pointerFirst) InitPointerBlank(w) ;
|
|
|
|
if (tpd->pointerOn) {
|
|
/*
|
|
** define the window's cursor...
|
|
*/
|
|
(void) XDefineCursor(XtDisplay(tw), XtWindow(tw), tpd->noPointer);
|
|
|
|
/*
|
|
** remove the motion timeout...
|
|
*/
|
|
if (tw->term.pointerBlankDelay) {
|
|
if (tpd->pointerTimeoutID)
|
|
XtRemoveTimeOut(tpd->pointerTimeoutID);
|
|
tpd->pointerTimeoutID = 0;
|
|
}
|
|
|
|
/*
|
|
** and clear the pointer on flag...
|
|
*/
|
|
tpd->pointerOn = False;
|
|
}
|
|
return;
|
|
}
|
|
|
|
void
|
|
_DtTermPrimPointerOn(Widget w)
|
|
{
|
|
DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) w;
|
|
DtTermPrimData tpd = tw->term.tpd;
|
|
|
|
if (tpd->pointerFirst) InitPointerBlank(w) ;
|
|
|
|
if (!tpd->pointerOn) {
|
|
/*
|
|
** define the window's cursor...
|
|
*/
|
|
XDefineCursor(XtDisplay(tw), XtWindow(tw), tw->term.pointerShape);
|
|
|
|
/*
|
|
** set a motion timeout...
|
|
*/
|
|
if (tw->term.pointerBlankDelay) {
|
|
if (tpd->pointerTimeoutID)
|
|
/*
|
|
** remove old timeout...
|
|
*/
|
|
XtRemoveTimeOut(tpd->pointerTimeoutID);
|
|
|
|
tpd->pointerTimeoutID =
|
|
XtAppAddTimeOut(XtWidgetToApplicationContext((Widget)tw),
|
|
(unsigned long) (1000 * tw->term.pointerBlankDelay),
|
|
(XtTimerCallbackProc)_DtTermPrimPointerOff, (XtPointer)tw);
|
|
}
|
|
/*
|
|
** and set the pointer on flag...
|
|
*/
|
|
tpd->pointerOn = True;
|
|
}
|
|
return;
|
|
}
|
|
|
|
void
|
|
_DtTermPrimPointerFreeze(Widget w, Boolean freeze)
|
|
{
|
|
DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) w;
|
|
DtTermPrimData tpd = tw->term.tpd;
|
|
|
|
tpd->pointerFrozen = freeze;
|
|
|
|
/*
|
|
** make sure that the pointer is on...
|
|
*/
|
|
if (tpd->pointerOn) {
|
|
/*
|
|
** pointer is on...
|
|
*/
|
|
if (tw->term.pointerBlankDelay) {
|
|
if (freeze) {
|
|
/*
|
|
** freezing -- turn the timeout off...
|
|
*/
|
|
if (tpd->pointerTimeoutID)
|
|
XtRemoveTimeOut(tpd->pointerTimeoutID);
|
|
|
|
tpd->pointerTimeoutID = 0;
|
|
}
|
|
else {
|
|
/*
|
|
** un freezing -- turn the timeout on...
|
|
*/
|
|
if (tpd->pointerTimeoutID)
|
|
/*
|
|
** remove old timeout...
|
|
*/
|
|
XtRemoveTimeOut(tpd->pointerTimeoutID);
|
|
|
|
tpd->pointerTimeoutID =
|
|
XtAppAddTimeOut(XtWidgetToApplicationContext((Widget)tw),
|
|
(unsigned long) 1000 * tw->term.pointerBlankDelay,
|
|
(XtTimerCallbackProc) _DtTermPrimPointerOff,
|
|
(XtPointer)tw);
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
/*
|
|
** let's turn on the pointer...
|
|
** define the window's cursor...
|
|
*/
|
|
XDefineCursor(XtDisplay(tw), XtWindow(tw), tw->term.pointerShape);
|
|
|
|
if (freeze)
|
|
/*
|
|
** the timeout is off, so we don't need to clear it...
|
|
*/
|
|
/* NOOP */ ;
|
|
else
|
|
/*
|
|
** we are unfreezing -- turn the timeout on...
|
|
*/
|
|
if (tw->term.pointerBlankDelay) {
|
|
if (tpd->pointerTimeoutID)
|
|
/*
|
|
** remove old timeout...
|
|
*/
|
|
XtRemoveTimeOut(tpd->pointerTimeoutID);
|
|
|
|
tpd->pointerTimeoutID =
|
|
XtAppAddTimeOut(XtWidgetToApplicationContext((Widget)tw),
|
|
(unsigned long) (1000 * tw->term.pointerBlankDelay),
|
|
(XtTimerCallbackProc)_DtTermPrimPointerOff,(XtPointer)tw);
|
|
}
|
|
/*
|
|
** and set the flag...
|
|
*/
|
|
tpd->pointerOn = True;
|
|
}
|
|
return;
|
|
}
|
|
|
|
void
|
|
_DtTermPrimRecolorPointer(Widget w)
|
|
{
|
|
DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) w;
|
|
|
|
XColor colordefs[2]; /* 0 is foreground, 1 is background */
|
|
Display *dpy = XtDisplay(w);
|
|
|
|
colordefs[0].pixel = tw->term.pointerColor;
|
|
colordefs[1].pixel = tw->term.pointerColorBackground;
|
|
XQueryColors (dpy, DefaultColormap (dpy, DefaultScreen (dpy)),
|
|
colordefs, 2);
|
|
XRecolorCursor (dpy, tw->term.pointerShape, colordefs, colordefs+1);
|
|
return;
|
|
}
|
|
|
|
/* linked list of log files to flush if we are killed...
|
|
*/
|
|
typedef struct _logInfo {
|
|
FILE *logFile;
|
|
struct _logInfo *next;
|
|
struct _logInfo *prev;
|
|
} logInfo;
|
|
|
|
static logInfo _logInfoHead;
|
|
static logInfo *logInfoHead = &_logInfoHead;
|
|
|
|
static void
|
|
AddLogFileEntry
|
|
(
|
|
FILE *logFile
|
|
)
|
|
{
|
|
logInfo *logInfoTmp;
|
|
sigset_t newSigs;
|
|
sigset_t oldSigs;
|
|
|
|
/* malloc a new entry... */
|
|
logInfoTmp = (logInfo *) XtMalloc(sizeof(logInfo));
|
|
(void) memset(logInfoTmp, '\0', sizeof(logInfo));
|
|
|
|
/* fill in the structure... */
|
|
logInfoTmp->logFile = logFile;
|
|
|
|
/* insert it after the head of the list...
|
|
*/
|
|
/* block all signals... */
|
|
(void) sigfillset(&newSigs);
|
|
(void) sigemptyset(&oldSigs);
|
|
(void) sigprocmask(SIG_BLOCK, &newSigs, &oldSigs);
|
|
|
|
/* insert the entry into the list... */
|
|
_DtTermProcessLock();
|
|
logInfoTmp->prev = logInfoHead;
|
|
logInfoTmp->next = logInfoHead->next;
|
|
logInfoHead->next = logInfoTmp;
|
|
if (logInfoTmp->next) {
|
|
logInfoTmp->next->prev = logInfoTmp;
|
|
}
|
|
_DtTermProcessUnlock();
|
|
|
|
/* restore signals... */
|
|
(void) sigprocmask(SIG_SETMASK, &oldSigs, (sigset_t *) 0);
|
|
}
|
|
|
|
static void
|
|
DeleteLogFileEntry
|
|
(
|
|
FILE *logFile
|
|
)
|
|
{
|
|
logInfo *logInfoTmp;
|
|
sigset_t newSigs;
|
|
sigset_t oldSigs;
|
|
|
|
/* find the entry... */
|
|
_DtTermProcessLock();
|
|
for (logInfoTmp = logInfoHead->next; logInfoTmp;
|
|
logInfoTmp = logInfoTmp->next) {
|
|
if (logInfoTmp->logFile == logFile) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* did we find anything... */
|
|
if (!logInfoTmp) {
|
|
/* not found... */
|
|
_DtTermProcessUnlock();
|
|
return;
|
|
}
|
|
|
|
/* delete entry from the list...
|
|
*/
|
|
/* block all signals... */
|
|
(void) sigfillset(&newSigs);
|
|
(void) sigemptyset(&oldSigs);
|
|
(void) sigprocmask(SIG_BLOCK, &newSigs, &oldSigs);
|
|
|
|
/* remove it... */
|
|
logInfoTmp->prev->next = logInfoTmp->next;
|
|
if (logInfoTmp->next) {
|
|
logInfoTmp->next->prev = logInfoTmp->prev;
|
|
}
|
|
|
|
/* restore signals... */
|
|
(void) sigprocmask(SIG_SETMASK, &oldSigs, (sigset_t *) 0);
|
|
|
|
/* free up the data... */
|
|
(void) XtFree((char *) logInfoTmp);
|
|
_DtTermProcessUnlock();
|
|
}
|
|
|
|
#ifdef NOTDEF
|
|
void
|
|
logpipe(Widget w)
|
|
{
|
|
win_data *wp = &term->Wp;
|
|
|
|
if (wp->log_on) { CloseLog(wp); }
|
|
}
|
|
#endif /* NOTDEF */
|
|
|
|
|
|
void
|
|
_DtTermPrimStartLog(Widget w)
|
|
{
|
|
DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) w;
|
|
DtTermPrimData tpd = tw->term.tpd;
|
|
|
|
char *cp;
|
|
int i;
|
|
|
|
if ( tw->term.log_on || tw->term.logInhibit ) { return; }
|
|
|
|
if (!tw->term.logFile || !*tw->term.logFile) {
|
|
tw->term.logFile = "DttermLogXXXXX";
|
|
}
|
|
|
|
if (!strcmp(tw->term.logFile + strlen(tw->term.logFile) - 5, "XXXXX")) {
|
|
/* make a local copy in case we are going to change it... */
|
|
cp = XtMalloc(strlen(tw->term.logFile) + 1);
|
|
(void) strcpy(cp, tw->term.logFile);
|
|
|
|
(void) mktemp(cp);
|
|
if (cp && *cp) {
|
|
tw->term.logFile = cp;
|
|
} else {
|
|
(void) XtFree(cp);
|
|
return;
|
|
}
|
|
}
|
|
|
|
if ('|' == *tw->term.logFile ) {
|
|
/*
|
|
** pipe logfile into command
|
|
*/
|
|
int p[2];
|
|
|
|
_DtTermProcessLock();
|
|
if (pipe(p) < 0 || (i = fork()) < 0) {
|
|
_DtTermProcessUnlock();
|
|
return;
|
|
}
|
|
|
|
if (i == 0) {
|
|
/*
|
|
** child
|
|
*/
|
|
_DtTermProcessUnlock();
|
|
|
|
/* Remove suid root capability...
|
|
*/
|
|
(void) _DtTermPrimRemoveSuidRoot();
|
|
|
|
(void) close(p[1]);
|
|
(void) close(0);
|
|
(void) dup(p[0]);
|
|
(void) close(p[0]);
|
|
/*
|
|
** set close on exec flag on all other fd's
|
|
*/ for (i = 3; i < _NFILE; i++) {
|
|
(void) fcntl(i, F_SETFD, 1);
|
|
}
|
|
/*
|
|
** reset signals
|
|
*/
|
|
(void) signal(SIGHUP, SIG_DFL);
|
|
(void) signal(SIGCHLD, SIG_DFL);
|
|
#ifdef BBA
|
|
_bA_dump();
|
|
#endif /* BBA */
|
|
(void) execl(DEFAULT_SHELL, DEFAULT_SHELL_ARGV0,
|
|
"-c", &tw->term.logFile[1], NULL);
|
|
(void) fprintf(stderr, " Can't exec \"%s\"\n",
|
|
&tw->term.logFile[1]);
|
|
(void) exit(1);
|
|
}
|
|
|
|
_DtTermProcessUnlock();
|
|
(void) close(p[0]);
|
|
tpd->logStream = fdopen(p[1], "w");
|
|
(void) AddLogFileEntry(tpd->logStream);
|
|
(void) signal(SIGPIPE, SIG_IGN);
|
|
}
|
|
else {
|
|
if (access(tw->term.logFile, F_OK) == 0) {
|
|
if (access(tw->term.logFile, W_OK) < 0) {
|
|
return;
|
|
}
|
|
} else if ((cp = strrchr(tw->term.logFile, '/'))) {
|
|
*cp = 0;
|
|
i = access(tw->term.logFile, W_OK);
|
|
*cp = '/';
|
|
if (i < 0) {
|
|
return;
|
|
}
|
|
} else if (access(".", W_OK) < 0) {
|
|
return;
|
|
}
|
|
if ((tpd->logStream = fopen(tw->term.logFile, "a")) == NULL) {
|
|
return;
|
|
}
|
|
(void) AddLogFileEntry(tpd->logStream);
|
|
(void) chown(tw->term.logFile, getuid(), getgid());
|
|
}
|
|
tw->term.log_on = True ;
|
|
}
|
|
|
|
static void
|
|
ForceCloseLog(DtTermPrimitiveWidget tw)
|
|
{
|
|
DtTermPrimData tpd = tw->term.tpd;
|
|
|
|
if (tw->term.log_on)
|
|
{
|
|
(void) DeleteLogFileEntry(tpd->logStream);
|
|
(void) fclose(tpd->logStream);
|
|
tpd->logStream = NULL;
|
|
tw->term.log_on = False;
|
|
}
|
|
}
|
|
|
|
void
|
|
_DtTermPrimCloseLog(Widget w)
|
|
{
|
|
DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) w;
|
|
DtTermPrimData tpd = tw->term.tpd;
|
|
|
|
/*
|
|
** if we are not logging, or it is inhibited, do nothing
|
|
*/
|
|
if (!tw->term.log_on || tw->term.logInhibit ) { return; }
|
|
|
|
(void) fflush(tpd->logStream);
|
|
ForceCloseLog(tw);
|
|
}
|
|
|
|
void
|
|
_DtTermPrimWriteLog(DtTermPrimitiveWidget tw, char *buffer, int cnt)
|
|
{
|
|
DtTermPrimData tpd = tw->term.tpd;
|
|
|
|
if (cnt > 0)
|
|
{
|
|
_DtTermProcessLock();
|
|
|
|
(void) fwrite(buffer, cnt, 1, tpd->logStream);
|
|
|
|
if ((errno == EPIPE) && ferror(tpd->logStream))
|
|
{
|
|
ForceCloseLog(tw);
|
|
}
|
|
|
|
_DtTermProcessUnlock();
|
|
}
|
|
}
|
|
|
|
static Boolean first = True;
|
|
static uid_t uid_user;
|
|
static uid_t uid_root;
|
|
static gid_t gid_user;
|
|
static gid_t gid_root;
|
|
|
|
static void
|
|
suidInit(void)
|
|
{
|
|
_DtTermProcessLock();
|
|
if (first) {
|
|
uid_user = getuid();
|
|
uid_root = geteuid();
|
|
|
|
gid_user = getgid();
|
|
gid_root = getegid();
|
|
|
|
first = False;
|
|
}
|
|
_DtTermProcessUnlock();
|
|
}
|
|
|
|
void
|
|
_DtTermPrimRemoveSuidRoot(void)
|
|
{
|
|
(void) suidInit();
|
|
#if defined(HAS_SETRESUID)
|
|
(void) setresgid(gid_user, gid_user, gid_user);
|
|
(void) setresuid(uid_user, uid_user, uid_user);
|
|
#elif defined(HAS_SETREUID)
|
|
(void) setregid(gid_user, gid_user);
|
|
(void) setreuid(uid_user, uid_user);
|
|
#else /* !HAS_SETRESUID && !HAS_SETREUID */
|
|
(void) setgid(gid_user);
|
|
(void) setuid(uid_user);
|
|
#endif /* !HAS_SETRESUID && !HAS_SETREUID */
|
|
}
|
|
|
|
void
|
|
_DtTermPrimToggleSuidRoot(Boolean root)
|
|
{
|
|
(void) suidInit();
|
|
|
|
#if defined(HAS_SETRESUID)
|
|
(void) setresuid(-1, root ? uid_root : uid_user, -1);
|
|
(void) setresgid(-1, root ? gid_root : gid_user, -1);
|
|
#elif defined(HAS_SETEUID)
|
|
(void) seteuid(root ? uid_root : uid_user);
|
|
(void) setegid(root ? gid_root : gid_user);
|
|
#endif /* HAS_SETEUID */
|
|
}
|
|
|
|
void
|
|
_DtTermPrimLogFileCleanup
|
|
(
|
|
void
|
|
)
|
|
{
|
|
logInfo *logInfoTmp;
|
|
|
|
DebugF('s', 10, fprintf(stderr,
|
|
">>_DtTermPrimLogFileCleanup() starting\n"));
|
|
|
|
/* flush all the log files... */
|
|
_DtTermProcessLock();
|
|
for (logInfoTmp = logInfoHead->next; logInfoTmp;
|
|
logInfoTmp = logInfoTmp->next) {
|
|
DebugF('s', 10, fprintf(stderr,
|
|
">>flushing logfile %p\n", logInfoTmp->logFile));
|
|
(void) fflush(logInfoTmp->logFile);
|
|
}
|
|
_DtTermProcessUnlock();
|
|
DebugF('s', 10, fprintf(stderr,
|
|
">>_DtTermPrimLogFileCleanup() finished\n"));
|
|
}
|