You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
3895 lines
106 KiB
3895 lines
106 KiB
/* |
|
* Copyright (C) 1997-2009, Michael Jennings |
|
* |
|
* Permission is hereby granted, free of charge, to any person obtaining a copy |
|
* of this software and associated documentation files (the "Software"), to |
|
* deal in the Software without restriction, including without limitation the |
|
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or |
|
* sell copies of the Software, and to permit persons to whom the Software is |
|
* furnished to do so, subject to the following conditions: |
|
* |
|
* The above copyright notice and this permission notice shall be included in |
|
* all copies of the Software, its documentation and marketing & publicity |
|
* materials, and acknowledgment shall be given in the documentation, materials |
|
* and software packages that this Software was used. |
|
* |
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
|
* THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER |
|
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN |
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
|
*/ |
|
|
|
static const char cvs_ident[] = "$Id$"; |
|
|
|
/* includes: */ |
|
#include "config.h" |
|
#include "feature.h" |
|
|
|
/* System Headers */ |
|
#include <stdio.h> |
|
#include <stdlib.h> |
|
#include <ctype.h> |
|
#include <errno.h> |
|
#include <string.h> |
|
#ifdef HAVE_FCNTL_H |
|
# include <fcntl.h> |
|
#endif |
|
#ifdef HAVE_SYS_IOCTL_H |
|
# include <sys/ioctl.h> |
|
#endif |
|
#ifdef HAVE_UNISTD_H |
|
# include <unistd.h> |
|
#endif |
|
#include <sys/types.h> |
|
#include <limits.h> |
|
|
|
/* X11 Headers */ |
|
#include <X11/cursorfont.h> |
|
#include <X11/keysym.h> |
|
#include <X11/Xlib.h> |
|
#include <X11/Xutil.h> |
|
#include <X11/Xatom.h> |
|
#include <X11/Xos.h> |
|
#include <X11/Xproto.h> |
|
#include <X11/IntrinsicP.h> |
|
#ifdef HAVE_XRES_EXT |
|
# include <X11/extensions/XRes.h> |
|
#endif |
|
#ifdef PTY_GRP_NAME |
|
# include <grp.h> |
|
#endif |
|
#ifdef TIME_WITH_SYS_TIME |
|
# include <sys/time.h> |
|
# include <time.h> |
|
#else |
|
# ifdef HAVE_SYS_TIME_H |
|
# include <sys/time.h> |
|
# else |
|
# include <time.h> |
|
# endif |
|
#endif |
|
#if defined (__svr4__) |
|
# include <sys/resource.h> /* for struct rlimit */ |
|
# include <sys/stropts.h> /* for I_PUSH */ |
|
# ifdef HAVE_SYS_STRTIO_H |
|
# include <sys/strtio.h> |
|
# endif |
|
# ifdef HAVE_BSDTTY_H |
|
# include <bsdtty.h> |
|
# endif |
|
# define _NEW_TTY_CTRL /* to get proper defines in <termios.h> */ |
|
#endif |
|
#ifdef HAVE_SYS_SELECT_H |
|
# include <sys/select.h> |
|
#endif |
|
#ifdef HAVE_TERMIOS_H |
|
# include <termios.h> |
|
#else |
|
# include <sgtty.h> |
|
#endif |
|
#if defined(__sun) && defined(__SVR4) |
|
# include <sys/strredir.h> |
|
#endif |
|
#include <sys/wait.h> |
|
#include <sys/stat.h> |
|
#if defined(linux) |
|
# include <linux/tty.h> /* For N_TTY_BUF_SIZE. */ |
|
#endif |
|
#ifdef MULTI_CHARSET |
|
# include <locale.h> |
|
# include <langinfo.h> |
|
# include <iconv.h> |
|
# include <wchar.h> |
|
#endif |
|
|
|
/* Eterm-specific Headers */ |
|
#include "command.h" |
|
#include "startup.h" |
|
#include "events.h" |
|
#include "font.h" |
|
#include "grkelot.h" |
|
#include "options.h" |
|
#include "pixmap.h" |
|
#ifdef PROFILE |
|
# include "profile.h" |
|
#endif |
|
#include "screen.h" |
|
#include "scrollbar.h" |
|
#include "string.h" |
|
#include "term.h" |
|
#ifdef UTMP_SUPPORT |
|
# include "eterm_utmp.h" |
|
#endif |
|
#include "windows.h" |
|
#include "buttons.h" |
|
#include "menus.h" |
|
|
|
#ifdef ESCREEN |
|
# include "screamcfg.h" |
|
# ifdef NS_HAVE_TWIN |
|
# include <Tw/Tw.h> |
|
TW_DECL_MAGIC(libscream_magic); |
|
# endif |
|
#endif |
|
|
|
static RETSIGTYPE handle_child_signal(int); |
|
static RETSIGTYPE handle_exit_signal(int); |
|
static RETSIGTYPE handle_crash(int); |
|
static RETSIGTYPE x_resource_dump(int); |
|
|
|
/* local variables */ |
|
int my_ruid, my_euid, my_rgid, my_egid; |
|
char initial_dir[PATH_MAX + 1]; |
|
static char *ptydev = NULL, *ttydev = NULL; /* pty/tty name */ |
|
int cmd_fd = -1; /* file descriptor connected to the command */ |
|
int pipe_fd = -1; |
|
pid_t cmd_pid = -1; /* process id if child */ |
|
int Xfd = -1; /* file descriptor of X server connection */ |
|
unsigned int num_fds = 0; /* number of file descriptors being used */ |
|
struct stat ttyfd_stat; /* original status of the tty we will use */ |
|
int refresh_count = 0, refresh_limit = 1, refresh_type = FAST_REFRESH; |
|
unsigned char cmdbuf_base[CMD_BUF_SIZE], *cmdbuf_ptr, *cmdbuf_endp; |
|
|
|
/* Addresses pasting large amounts of data |
|
* code pinched from xterm |
|
*/ |
|
static char *v_buffer; /* pointer to physical buffer */ |
|
static char *v_bufstr = NULL; /* beginning of area to write */ |
|
static char *v_bufptr; /* end of area to write */ |
|
static char *v_bufend; /* end of physical buffer */ |
|
|
|
#ifdef USE_XIM |
|
XIM xim_input_method = NULL; |
|
XIC xim_input_context = NULL; /* input context */ |
|
static XIMStyle xim_input_style = 0; |
|
|
|
# ifndef XSetIMValues |
|
extern char *XSetIMValues(XIM im, ...); |
|
# endif |
|
#endif |
|
|
|
/* Substitutes for missing system functions */ |
|
#if !defined(_POSIX_VERSION) && defined(__svr4__) |
|
int |
|
getdtablesize(void) |
|
{ |
|
struct rlimit rlim; |
|
|
|
getrlimit(RLIMIT_NOFILE, &rlim); |
|
return rlim.rlim_cur; |
|
} |
|
# endif |
|
|
|
/* Take care of suid/sgid super-user (root) privileges */ |
|
void |
|
privileges(int mode) |
|
{ |
|
|
|
#ifdef __CYGWIN32__ |
|
return; |
|
#endif |
|
|
|
switch (mode) { |
|
case IGNORE: |
|
/* Revoke suid/sgid privs and return to normal uid/gid -- mej */ |
|
D_UTMP(("[%ld]: Before privileges(REVERT): [ %ld, %ld ] [ %ld, %ld ]\n", getpid(), getuid(), getgid(), geteuid(), |
|
getegid())); |
|
|
|
#ifdef HAVE_SETRESGID |
|
setresgid(my_rgid, my_rgid, my_egid); |
|
#elif defined(HAVE_SAVED_UIDS) |
|
setregid(my_rgid, my_rgid); |
|
#else |
|
setregid(my_egid, -1); |
|
setregid(-1, my_rgid); |
|
#endif |
|
|
|
#ifdef HAVE_SETRESUID |
|
setresuid(my_ruid, my_ruid, my_euid); |
|
#elif defined(HAVE_SAVED_UIDS) |
|
setreuid(my_ruid, my_ruid); |
|
#else |
|
setreuid(my_euid, -1); |
|
setreuid(-1, my_ruid); |
|
#endif |
|
|
|
D_UTMP(("[%ld]: After privileges(REVERT): [ %ld, %ld ] [ %ld, %ld ]\n", getpid(), getuid(), getgid(), geteuid(), |
|
getegid())); |
|
break; |
|
|
|
case SAVE: |
|
break; |
|
|
|
case RESTORE: |
|
D_UTMP(("[%ld]: Before privileges(INVOKE): [ %ld, %ld ] [ %ld, %ld ]\n", getpid(), getuid(), getgid(), geteuid(), |
|
getegid())); |
|
|
|
#ifdef HAVE_SETRESUID |
|
setresuid(my_ruid, my_euid, my_euid); |
|
#elif defined(HAVE_SAVED_UIDS) |
|
setreuid(my_ruid, my_euid); |
|
#else |
|
setreuid(-1, my_euid); |
|
setreuid(my_ruid, -1); |
|
#endif |
|
|
|
#ifdef HAVE_SETRESGID |
|
setresgid(my_rgid, my_egid, my_egid); |
|
#elif defined(HAVE_SAVED_UIDS) |
|
setregid(my_rgid, my_egid); |
|
#else |
|
setregid(-1, my_egid); |
|
setregid(my_rgid, -1); |
|
#endif |
|
|
|
D_UTMP(("[%ld]: After privileges(INVOKE): [ %ld, %ld ] [ %ld, %ld ]\n", getpid(), getuid(), getgid(), geteuid(), |
|
getegid())); |
|
break; |
|
} |
|
} |
|
|
|
char * |
|
sig_to_str(int sig) |
|
{ |
|
#ifdef SIGHUP |
|
if (sig == SIGHUP) { |
|
return ("SIGHUP"); |
|
} |
|
#endif |
|
|
|
#ifdef SIGINT |
|
if (sig == SIGINT) { |
|
return ("SIGINT"); |
|
} |
|
#endif |
|
|
|
#ifdef SIGQUIT |
|
if (sig == SIGQUIT) { |
|
return ("SIGQUIT"); |
|
} |
|
#endif |
|
|
|
#ifdef SIGILL |
|
if (sig == SIGILL) { |
|
return ("SIGILL"); |
|
} |
|
#endif |
|
|
|
#ifdef SIGTRAP |
|
if (sig == SIGTRAP) { |
|
return ("SIGTRAP"); |
|
} |
|
#endif |
|
|
|
#ifdef SIGABRT |
|
if (sig == SIGABRT) { |
|
return ("SIGABRT"); |
|
} |
|
#endif |
|
|
|
#ifdef SIGIOT |
|
if (sig == SIGIOT) { |
|
return ("SIGIOT"); |
|
} |
|
#endif |
|
|
|
#ifdef SIGEMT |
|
if (sig == SIGEMT) { |
|
return ("SIGEMT"); |
|
} |
|
#endif |
|
|
|
#ifdef SIGFPE |
|
if (sig == SIGFPE) { |
|
return ("SIGFPE"); |
|
} |
|
#endif |
|
|
|
#ifdef SIGKILL |
|
if (sig == SIGKILL) { |
|
return ("SIGKILL"); |
|
} |
|
#endif |
|
|
|
#ifdef SIGBUS |
|
if (sig == SIGBUS) { |
|
return ("SIGBUS"); |
|
} |
|
#endif |
|
|
|
#ifdef SIGSEGV |
|
if (sig == SIGSEGV) { |
|
return ("SIGSEGV"); |
|
} |
|
#endif |
|
|
|
#ifdef SIGSYS |
|
if (sig == SIGSYS) { |
|
return ("SIGSYS"); |
|
} |
|
#endif |
|
|
|
#ifdef SIGPIPE |
|
if (sig == SIGPIPE) { |
|
return ("SIGPIPE"); |
|
} |
|
#endif |
|
|
|
#ifdef SIGALRM |
|
if (sig == SIGALRM) { |
|
return ("SIGALRM"); |
|
} |
|
#endif |
|
|
|
#ifdef SIGTERM |
|
if (sig == SIGTERM) { |
|
return ("SIGTERM"); |
|
} |
|
#endif |
|
|
|
#ifdef SIGUSR1 |
|
if (sig == SIGUSR1) { |
|
return ("SIGUSR1"); |
|
} |
|
#endif |
|
|
|
#ifdef SIGUSR2 |
|
if (sig == SIGUSR2) { |
|
return ("SIGUSR2"); |
|
} |
|
#endif |
|
|
|
#ifdef SIGCHLD |
|
if (sig == SIGCHLD) { |
|
return ("SIGCHLD"); |
|
} |
|
#endif |
|
|
|
#ifdef SIGCLD |
|
if (sig == SIGCLD) { |
|
return ("SIGCLD"); |
|
} |
|
#endif |
|
|
|
#ifdef SIGPWR |
|
if (sig == SIGPWR) { |
|
return ("SIGPWR"); |
|
} |
|
#endif |
|
|
|
#ifdef SIGVTALRM |
|
if (sig == SIGVTALRM) { |
|
return ("SIGVTALRM"); |
|
} |
|
#endif |
|
|
|
#ifdef SIGPROF |
|
if (sig == SIGPROF) { |
|
return ("SIGPROF"); |
|
} |
|
#endif |
|
|
|
#ifdef SIGIO |
|
if (sig == SIGIO) { |
|
return ("SIGIO"); |
|
} |
|
#endif |
|
|
|
#ifdef SIGPOLL |
|
if (sig == SIGPOLL) { |
|
return ("SIGPOLL"); |
|
} |
|
#endif |
|
|
|
#ifdef SIGWINCH |
|
if (sig == SIGWINCH) { |
|
return ("SIGWINCH"); |
|
} |
|
#endif |
|
|
|
#ifdef SIGWINDOW |
|
if (sig == SIGWINDOW) { |
|
return ("SIGWINDOW"); |
|
} |
|
#endif |
|
|
|
#ifdef SIGSTOP |
|
if (sig == SIGSTOP) { |
|
return ("SIGSTOP"); |
|
} |
|
#endif |
|
|
|
#ifdef SIGTSTP |
|
if (sig == SIGTSTP) { |
|
return ("SIGTSTP"); |
|
} |
|
#endif |
|
|
|
#ifdef SIGCONT |
|
if (sig == SIGCONT) { |
|
return ("SIGCONT"); |
|
} |
|
#endif |
|
|
|
#ifdef SIGTTIN |
|
if (sig == SIGTTIN) { |
|
return ("SIGTTIN"); |
|
} |
|
#endif |
|
|
|
#ifdef SIGTTOU |
|
if (sig == SIGTTOU) { |
|
return ("SIGTTOU"); |
|
} |
|
#endif |
|
|
|
#ifdef SIGURG |
|
if (sig == SIGURG) { |
|
return ("SIGURG"); |
|
} |
|
#endif |
|
|
|
#ifdef SIGLOST |
|
if (sig == SIGLOST) { |
|
return ("SIGLOST"); |
|
} |
|
#endif |
|
|
|
#ifdef SIGRESERVE |
|
if (sig == SIGRESERVE) { |
|
return ("SIGRESERVE"); |
|
} |
|
#endif |
|
|
|
#ifdef SIGDIL |
|
if (sig == SIGDIL) { |
|
return ("SIGDIL"); |
|
} |
|
#endif |
|
|
|
#ifdef SIGXCPU |
|
if (sig == SIGXCPU) { |
|
return ("SIGXCPU"); |
|
} |
|
#endif |
|
|
|
#ifdef SIGXFSZ |
|
if (sig == SIGXFSZ) { |
|
return ("SIGXFSZ"); |
|
} |
|
#endif |
|
return ("Unknown signal"); |
|
} |
|
|
|
const char * |
|
event_type_to_name(int type) |
|
{ |
|
|
|
if (type == KeyPress) { |
|
return "KeyPress"; |
|
} |
|
if (type == KeyRelease) { |
|
return "KeyRelease"; |
|
} |
|
if (type == ButtonPress) { |
|
return "ButtonPress"; |
|
} |
|
if (type == ButtonRelease) { |
|
return "ButtonRelease"; |
|
} |
|
if (type == MotionNotify) { |
|
return "MotionNotify"; |
|
} |
|
if (type == EnterNotify) { |
|
return "EnterNotify"; |
|
} |
|
if (type == LeaveNotify) { |
|
return "LeaveNotify"; |
|
} |
|
if (type == FocusIn) { |
|
return "FocusIn"; |
|
} |
|
if (type == FocusOut) { |
|
return "FocusOut"; |
|
} |
|
if (type == KeymapNotify) { |
|
return "KeymapNotify"; |
|
} |
|
if (type == Expose) { |
|
return "Expose"; |
|
} |
|
if (type == GraphicsExpose) { |
|
return "GraphicsExpose"; |
|
} |
|
if (type == NoExpose) { |
|
return "NoExpose"; |
|
} |
|
if (type == VisibilityNotify) { |
|
return "VisibilityNotify"; |
|
} |
|
if (type == CreateNotify) { |
|
return "CreateNotify"; |
|
} |
|
if (type == DestroyNotify) { |
|
return "DestroyNotify"; |
|
} |
|
if (type == UnmapNotify) { |
|
return "UnmapNotify"; |
|
} |
|
if (type == MapNotify) { |
|
return "MapNotify"; |
|
} |
|
if (type == MapRequest) { |
|
return "MapRequest"; |
|
} |
|
if (type == ReparentNotify) { |
|
return "ReparentNotify"; |
|
} |
|
if (type == ConfigureNotify) { |
|
return "ConfigureNotify"; |
|
} |
|
if (type == ConfigureRequest) { |
|
return "ConfigureRequest"; |
|
} |
|
if (type == GravityNotify) { |
|
return "GravityNotify"; |
|
} |
|
if (type == ResizeRequest) { |
|
return "ResizeRequest"; |
|
} |
|
if (type == CirculateNotify) { |
|
return "CirculateNotify"; |
|
} |
|
if (type == CirculateRequest) { |
|
return "CirculateRequest"; |
|
} |
|
if (type == PropertyNotify) { |
|
return "PropertyNotify"; |
|
} |
|
if (type == SelectionClear) { |
|
return "SelectionClear"; |
|
} |
|
if (type == SelectionRequest) { |
|
return "SelectionRequest"; |
|
} |
|
if (type == SelectionNotify) { |
|
return "SelectionNotify"; |
|
} |
|
if (type == ColormapNotify) { |
|
return "ColormapNotify"; |
|
} |
|
if (type == ClientMessage) { |
|
return "ClientMessage"; |
|
} |
|
if (type == MappingNotify) { |
|
return "MappingNotify"; |
|
} |
|
return "Bad Event!"; |
|
} |
|
|
|
const char * |
|
request_code_to_name(int code) |
|
{ |
|
|
|
if (code == X_CreateWindow) { |
|
return "XCreateWindow"; |
|
} |
|
if (code == X_ChangeWindowAttributes) { |
|
return "XChangeWindowAttributes"; |
|
} |
|
if (code == X_GetWindowAttributes) { |
|
return "XGetWindowAttributes"; |
|
} |
|
if (code == X_DestroyWindow) { |
|
return "XDestroyWindow"; |
|
} |
|
if (code == X_DestroySubwindows) { |
|
return "XDestroySubwindows"; |
|
} |
|
if (code == X_ChangeSaveSet) { |
|
return "XChangeSaveSet"; |
|
} |
|
if (code == X_ReparentWindow) { |
|
return "XReparentWindow"; |
|
} |
|
if (code == X_MapWindow) { |
|
return "XMapWindow"; |
|
} |
|
if (code == X_MapSubwindows) { |
|
return "XMapSubwindows"; |
|
} |
|
if (code == X_UnmapWindow) { |
|
return "XUnmapWindow"; |
|
} |
|
if (code == X_UnmapSubwindows) { |
|
return "XUnmapSubwindows"; |
|
} |
|
if (code == X_ConfigureWindow) { |
|
return "XConfigureWindow"; |
|
} |
|
if (code == X_CirculateWindow) { |
|
return "XCirculateWindow"; |
|
} |
|
if (code == X_GetGeometry) { |
|
return "XGetGeometry"; |
|
} |
|
if (code == X_QueryTree) { |
|
return "XQueryTree"; |
|
} |
|
if (code == X_InternAtom) { |
|
return "XInternAtom"; |
|
} |
|
if (code == X_GetAtomName) { |
|
return "XGetAtomName"; |
|
} |
|
if (code == X_ChangeProperty) { |
|
return "XChangeProperty"; |
|
} |
|
if (code == X_DeleteProperty) { |
|
return "XDeleteProperty"; |
|
} |
|
if (code == X_GetProperty) { |
|
return "XGetProperty"; |
|
} |
|
if (code == X_ListProperties) { |
|
return "XListProperties"; |
|
} |
|
if (code == X_SetSelectionOwner) { |
|
return "XSetSelectionOwner"; |
|
} |
|
if (code == X_GetSelectionOwner) { |
|
return "XGetSelectionOwner"; |
|
} |
|
if (code == X_ConvertSelection) { |
|
return "XConvertSelection"; |
|
} |
|
if (code == X_SendEvent) { |
|
return "XSendEvent"; |
|
} |
|
if (code == X_GrabPointer) { |
|
return "XGrabPointer"; |
|
} |
|
if (code == X_UngrabPointer) { |
|
return "XUngrabPointer"; |
|
} |
|
if (code == X_GrabButton) { |
|
return "XGrabButton"; |
|
} |
|
if (code == X_UngrabButton) { |
|
return "XUngrabButton"; |
|
} |
|
if (code == X_ChangeActivePointerGrab) { |
|
return "XChangeActivePointerGrab"; |
|
} |
|
if (code == X_GrabKeyboard) { |
|
return "XGrabKeyboard"; |
|
} |
|
if (code == X_UngrabKeyboard) { |
|
return "XUngrabKeyboard"; |
|
} |
|
if (code == X_GrabKey) { |
|
return "XGrabKey"; |
|
} |
|
if (code == X_UngrabKey) { |
|
return "XUngrabKey"; |
|
} |
|
if (code == X_AllowEvents) { |
|
return "XAllowEvents"; |
|
} |
|
if (code == X_GrabServer) { |
|
return "XGrabServer"; |
|
} |
|
if (code == X_UngrabServer) { |
|
return "XUngrabServer"; |
|
} |
|
if (code == X_QueryPointer) { |
|
return "XQueryPointer"; |
|
} |
|
if (code == X_GetMotionEvents) { |
|
return "XGetMotionEvents"; |
|
} |
|
if (code == X_TranslateCoords) { |
|
return "XTranslateCoords"; |
|
} |
|
if (code == X_WarpPointer) { |
|
return "XWarpPointer"; |
|
} |
|
if (code == X_SetInputFocus) { |
|
return "XSetInputFocus"; |
|
} |
|
if (code == X_GetInputFocus) { |
|
return "XGetInputFocus"; |
|
} |
|
if (code == X_QueryKeymap) { |
|
return "XQueryKeymap"; |
|
} |
|
if (code == X_OpenFont) { |
|
return "XOpenFont"; |
|
} |
|
if (code == X_CloseFont) { |
|
return "XCloseFont"; |
|
} |
|
if (code == X_QueryFont) { |
|
return "XQueryFont"; |
|
} |
|
if (code == X_QueryTextExtents) { |
|
return "XQueryTextExtents"; |
|
} |
|
if (code == X_ListFonts) { |
|
return "XListFonts"; |
|
} |
|
if (code == X_ListFontsWithInfo) { |
|
return "XListFontsWithInfo"; |
|
} |
|
if (code == X_SetFontPath) { |
|
return "XSetFontPath"; |
|
} |
|
if (code == X_GetFontPath) { |
|
return "XGetFontPath"; |
|
} |
|
if (code == X_CreatePixmap) { |
|
return "XCreatePixmap"; |
|
} |
|
if (code == X_FreePixmap) { |
|
return "XFreePixmap"; |
|
} |
|
if (code == X_CreateGC) { |
|
return "XCreateGC"; |
|
} |
|
if (code == X_ChangeGC) { |
|
return "XChangeGC"; |
|
} |
|
if (code == X_CopyGC) { |
|
return "XCopyGC"; |
|
} |
|
if (code == X_SetDashes) { |
|
return "XSetDashes"; |
|
} |
|
if (code == X_SetClipRectangles) { |
|
return "XSetClipRectangles"; |
|
} |
|
if (code == X_FreeGC) { |
|
return "XFreeGC"; |
|
} |
|
if (code == X_ClearArea) { |
|
return "XClearArea"; |
|
} |
|
if (code == X_CopyArea) { |
|
return "XCopyArea"; |
|
} |
|
if (code == X_CopyPlane) { |
|
return "XCopyPlane"; |
|
} |
|
if (code == X_PolyPoint) { |
|
return "XPolyPoint"; |
|
} |
|
if (code == X_PolyLine) { |
|
return "XPolyLine"; |
|
} |
|
if (code == X_PolySegment) { |
|
return "XPolySegment"; |
|
} |
|
if (code == X_PolyRectangle) { |
|
return "XPolyRectangle"; |
|
} |
|
if (code == X_PolyArc) { |
|
return "XPolyArc"; |
|
} |
|
if (code == X_FillPoly) { |
|
return "XFillPoly"; |
|
} |
|
if (code == X_PolyFillRectangle) { |
|
return "XPolyFillRectangle"; |
|
} |
|
if (code == X_PolyFillArc) { |
|
return "XPolyFillArc"; |
|
} |
|
if (code == X_PutImage) { |
|
return "XPutImage"; |
|
} |
|
if (code == X_GetImage) { |
|
return "XGetImage"; |
|
} |
|
if (code == X_PolyText8) { |
|
return "XPolyText8"; |
|
} |
|
if (code == X_PolyText16) { |
|
return "XPolyText16"; |
|
} |
|
if (code == X_ImageText8) { |
|
return "XImageText8"; |
|
} |
|
if (code == X_ImageText16) { |
|
return "XImageText16"; |
|
} |
|
if (code == X_CreateColormap) { |
|
return "XCreateColormap"; |
|
} |
|
if (code == X_FreeColormap) { |
|
return "XFreeColormap"; |
|
} |
|
if (code == X_CopyColormapAndFree) { |
|
return "XCopyColormapAndFree"; |
|
} |
|
if (code == X_InstallColormap) { |
|
return "XInstallColormap"; |
|
} |
|
if (code == X_UninstallColormap) { |
|
return "XUninstallColormap"; |
|
} |
|
if (code == X_ListInstalledColormaps) { |
|
return "XListInstalledColormaps"; |
|
} |
|
if (code == X_AllocColor) { |
|
return "XAllocColor"; |
|
} |
|
if (code == X_AllocNamedColor) { |
|
return "XAllocNamedColor"; |
|
} |
|
if (code == X_AllocColorCells) { |
|
return "XAllocColorCells"; |
|
} |
|
if (code == X_AllocColorPlanes) { |
|
return "XAllocColorPlanes"; |
|
} |
|
if (code == X_FreeColors) { |
|
return "XFreeColors"; |
|
} |
|
if (code == X_StoreColors) { |
|
return "XStoreColors"; |
|
} |
|
if (code == X_StoreNamedColor) { |
|
return "XStoreNamedColor"; |
|
} |
|
if (code == X_QueryColors) { |
|
return "XQueryColors"; |
|
} |
|
if (code == X_LookupColor) { |
|
return "XLookupColor"; |
|
} |
|
if (code == X_CreateCursor) { |
|
return "XCreateCursor"; |
|
} |
|
if (code == X_CreateGlyphCursor) { |
|
return "XCreateGlyphCursor"; |
|
} |
|
if (code == X_FreeCursor) { |
|
return "XFreeCursor"; |
|
} |
|
if (code == X_RecolorCursor) { |
|
return "XRecolorCursor"; |
|
} |
|
if (code == X_QueryBestSize) { |
|
return "XQueryBestSize"; |
|
} |
|
if (code == X_QueryExtension) { |
|
return "XQueryExtension"; |
|
} |
|
if (code == X_ListExtensions) { |
|
return "XListExtensions"; |
|
} |
|
if (code == X_ChangeKeyboardMapping) { |
|
return "XChangeKeyboardMapping"; |
|
} |
|
if (code == X_GetKeyboardMapping) { |
|
return "XGetKeyboardMapping"; |
|
} |
|
if (code == X_ChangeKeyboardControl) { |
|
return "XChangeKeyboardControl"; |
|
} |
|
if (code == X_GetKeyboardControl) { |
|
return "XGetKeyboardControl"; |
|
} |
|
if (code == X_Bell) { |
|
return "XBell"; |
|
} |
|
if (code == X_ChangePointerControl) { |
|
return "XChangePointerControl"; |
|
} |
|
if (code == X_GetPointerControl) { |
|
return "XGetPointerControl"; |
|
} |
|
if (code == X_SetScreenSaver) { |
|
return "XSetScreenSaver"; |
|
} |
|
if (code == X_GetScreenSaver) { |
|
return "XGetScreenSaver"; |
|
} |
|
if (code == X_ChangeHosts) { |
|
return "XChangeHosts"; |
|
} |
|
if (code == X_ListHosts) { |
|
return "XListHosts"; |
|
} |
|
if (code == X_SetAccessControl) { |
|
return "XSetAccessControl"; |
|
} |
|
if (code == X_SetCloseDownMode) { |
|
return "XSetCloseDownMode"; |
|
} |
|
if (code == X_KillClient) { |
|
return "XKillClient"; |
|
} |
|
if (code == X_RotateProperties) { |
|
return "XRotateProperties"; |
|
} |
|
if (code == X_ForceScreenSaver) { |
|
return "XForceScreenSaver"; |
|
} |
|
if (code == X_SetPointerMapping) { |
|
return "XSetPointerMapping"; |
|
} |
|
if (code == X_GetPointerMapping) { |
|
return "XGetPointerMapping"; |
|
} |
|
if (code == X_SetModifierMapping) { |
|
return "XSetModifierMapping"; |
|
} |
|
if (code == X_GetModifierMapping) { |
|
return "XGetModifierMapping"; |
|
} |
|
if (code == X_NoOperation) { |
|
return "XNoOperation"; |
|
} |
|
return "Unknown"; |
|
} |
|
|
|
const char * |
|
get_ctrl_char_name(char c) |
|
{ |
|
const char *lookup[] = { |
|
"NUL", "SOH", "STX", "ETX", "EOT", "ENQ", "ACK", "BEL", /* 0-7 */ |
|
"BS", "HT", "LF", "VT", "FF", "CR", "SO", "SI", /* 8-15 */ |
|
"DLE", "DC1", "DC2", "DC3", "DC4", "NAK", "SYN", "ETB", /* 16-23 */ |
|
"CAN", "EM", "SUB", "ESC", "FS", "GS", "RS", "US" /* 24-31 */ |
|
}; |
|
|
|
return ((c < ' ') ? (lookup[(int) c]) : ("")); |
|
} |
|
|
|
static void |
|
hard_exit(void) |
|
{ |
|
|
|
#ifdef HAVE__EXIT |
|
_exit(-1); |
|
#elif defined(SIGKILL) |
|
kill(cmd_pid, SIGKILL); |
|
abort(); |
|
#else |
|
kill(cmd_pid, 9); |
|
abort(); |
|
#endif |
|
|
|
} |
|
|
|
/* Try to get a stack trace when we croak */ |
|
void |
|
dump_stack_trace(void) |
|
{ |
|
char cmd[256]; |
|
#ifdef GDB |
|
struct stat st; |
|
#endif |
|
|
|
#ifdef NO_STACK_TRACE |
|
return; |
|
#endif |
|
|
|
libast_print_error("Attempting to dump a stack trace....\n"); |
|
signal(SIGTSTP, exit); /* Don't block on tty output, just die */ |
|
|
|
#ifdef HAVE_U_STACK_TRACE |
|
U_STACK_TRACE(); |
|
return; |
|
#elif defined(GDB) |
|
if (((stat(GDB_CMD_FILE, &st)) != 0) || (!S_ISREG(st.st_mode))) { |
|
return; |
|
} |
|
snprintf(cmd, sizeof(cmd), GDB " -x " GDB_CMD_FILE " " APL_NAME " %d", getpid()); |
|
#elif defined(PSTACK) |
|
snprintf(cmd, sizeof(cmd), PSTACK " %d", getpid()); |
|
#elif defined(DBX) |
|
# ifdef _AIX |
|
snprintf(cmd, sizeof(cmd), "/bin/echo 'where\ndetach' | " DBX " -a %d", getpid()); |
|
# elif defined(__sgi) |
|
snprintf(cmd, sizeof(cmd), "/bin/echo 'where\ndetach' | " DBX " -p %d", getpid()); |
|
# else |
|
snprintf(cmd, sizeof(cmd), "/bin/echo 'where\ndetach' | " DBX " %s %d", orig_argv0, getpid()); |
|
# endif |
|
#else |
|
libast_print_error("Your system does not support any of the methods Eterm uses. Exiting.\n"); |
|
return; |
|
#endif |
|
signal(SIGALRM, (eterm_sighandler_t) hard_exit); |
|
alarm(3); |
|
system(cmd); |
|
} |
|
|
|
/* signal handling, exit handler */ |
|
/* |
|
* Catch a SIGCHLD signal and exit if the direct child has died |
|
*/ |
|
static RETSIGTYPE |
|
handle_child_signal(int sig) |
|
{ |
|
|
|
int pid, save_errno = errno; |
|
|
|
D_CMD(("Received signal %s (%d)\n", sig_to_str(sig), sig)); |
|
|
|
do { |
|
errno = 0; |
|
} while ((-1 == (pid = waitpid(-1, NULL, WNOHANG))) && (errno == EINTR)); |
|
|
|
D_CMD(("pid == %d, cmd_pid == %d\n", pid, cmd_pid)); |
|
/* If the child that exited is the command we spawned, or if the |
|
child exited before fork() returned in the parent, it must be |
|
our immediate child that exited. We exit gracefully. */ |
|
if ((cmd_pid != -1) |
|
&& ((pid == cmd_pid) |
|
|| ((pid == -1) && (errno == ECHILD)) |
|
|| ((pid == 0) && ((kill(cmd_pid, 0)) < 0)))) { |
|
cmd_pid = -1; |
|
if (BITFIELD_IS_SET(eterm_options, ETERM_OPTIONS_PAUSE)) { |
|
paused = 1; |
|
return; |
|
} |
|
exit(EXIT_SUCCESS); |
|
} |
|
|
|
errno = save_errno; |
|
|
|
D_CMD(("handle_child_signal: installing signal handler\n")); |
|
signal(SIGCHLD, handle_child_signal); |
|
|
|
SIG_RETURN(0); |
|
} |
|
|
|
/* Handles signals usually sent by a user, like HUP, TERM, INT. */ |
|
static RETSIGTYPE |
|
handle_exit_signal(int sig) |
|
{ |
|
|
|
libast_print_error("Received terminal signal %s (%d)\n", sig_to_str(sig), sig); |
|
signal(sig, SIG_DFL); |
|
|
|
#ifdef UTMP_SUPPORT |
|
privileges(INVOKE); |
|
remove_utmp_entry(); |
|
privileges(REVERT); |
|
#endif |
|
|
|
D_CMD(("exit(%s)\n", sig_to_str(sig))); |
|
exit(sig); |
|
SIG_RETURN(0); |
|
} |
|
|
|
/* Handles abnormal termination signals -- mej */ |
|
static RETSIGTYPE |
|
handle_crash(int sig) |
|
{ |
|
|
|
libast_print_error("Received terminal signal %s (%d)\n", sig_to_str(sig), sig); |
|
signal(sig, SIG_DFL); /* Let the OS handle recursive seg faults */ |
|
|
|
/* Lock down security so we don't write any core files as root. */ |
|
privileges(REVERT); |
|
umask(077); |
|
|
|
/* Make an attempt to dump a stack trace */ |
|
dump_stack_trace(); |
|
|
|
/* Exit */ |
|
exit(sig); |
|
SIG_RETURN(0); |
|
} |
|
|
|
#ifdef HAVE_XRES_EXT |
|
static RETSIGTYPE |
|
x_resource_dump(int sig) |
|
{ |
|
int event_base, error_base, count, i; |
|
unsigned long bytes; |
|
XResClient *clients = NULL; |
|
XResType *types = NULL; |
|
Atom pixmap_atom, gc_atom, font_atom; |
|
pid_t my_pid; |
|
char *title, *ptitle; |
|
|
|
USE_VAR(sig); |
|
my_pid = getpid(); |
|
|
|
/* Create type atoms for future use. */ |
|
pixmap_atom = XInternAtom(Xdisplay, "PIXMAP", False); |
|
gc_atom = XInternAtom(Xdisplay, "GC", False); |
|
font_atom = XInternAtom(Xdisplay, "FONT", False); |
|
|
|
/* Look at what *we* think our consumption is. */ |
|
#if DEBUG >= DEBUG_MEM |
|
if (DEBUG_LEVEL >= DEBUG_MEM) { |
|
PIXMAP_DUMP(); |
|
GC_DUMP(); |
|
} |
|
#endif |
|
|
|
/* Make sure we have the extension loaded. */ |
|
if (!XResQueryExtension(Xdisplay, &event_base, &error_base)) { |
|
fprintf(stderr, "XResource extension not available on current display.\n"); |
|
return; |
|
} |
|
D_X11(("Got XResource extension values: %d (0x%08x) / %d (0x%08x)\n", |
|
event_base, event_base, error_base, error_base)); |
|
|
|
/* Get a list of X clients and find our window ID in the list. */ |
|
if (!XResQueryClients(Xdisplay, &count, &clients)) { |
|
if (clients) { |
|
XFree(clients); |
|
} |
|
D_X11((" -> Unable to query clients.\n")); |
|
return; |
|
} |
|
D_X11((" -> Got %d clients.\n", count)); |
|
|
|
if (count == 0) { |
|
D_X11((" -> Nothing to do!\n")); |
|
return; |
|
} |
|
|
|
for (i = 0; i < count; i++) { |
|
Window win; |
|
|
|
win = clients[i].resource_base & (~clients[i].resource_mask); |
|
D_X11(("Checking client: base %d, mask %d, window 0x%08x\n", clients[i].resource_base, |
|
clients[i].resource_mask, win)); |
|
if ((TermWin.parent & (~clients[i].resource_mask)) == win) { |
|
break; |
|
} |
|
} |
|
if (i == count) { |
|
D_X11((" -> No client found with window 0x%08x (0x%08x\n", TermWin.parent, |
|
(TermWin.parent & (~clients[i].resource_mask)))); |
|
return; |
|
} |
|
|
|
/* Request resource info for our client ID. */ |
|
if (!XResQueryClientResources(Xdisplay, clients[i].resource_base, &count, &types) |
|
|| !XResQueryClientPixmapBytes(Xdisplay, clients[i].resource_base, &bytes)) { |
|
if (types) { |
|
XFree(types); |
|
} |
|
D_X11((" -> Unable to query resources.\n")); |
|
return; |
|
} |
|
D_X11((" -> Got %d types.\n", count)); |
|
|
|
/* Get and sanitize window title for easier identification. */ |
|
XFetchName(Xdisplay, TermWin.parent, &title); |
|
if (title) { |
|
for (ptitle = title; *ptitle; ptitle++) { |
|
if (!isprint(*ptitle)) { |
|
*ptitle = ' '; |
|
} |
|
} |
|
} |
|
|
|
for (i = 0; i < count; i++) { |
|
if (types[i].resource_type == pixmap_atom) { |
|
fprintf(stderr, "Process %lu, window 0x%08x (%s): %d pixmaps (%lu bytes).\n", (unsigned long) my_pid, |
|
(unsigned int) TermWin.parent, NONULL(title), types[i].count, bytes); |
|
} else if (types[i].resource_type == gc_atom) { |
|
fprintf(stderr, "Process %lu, window 0x%08x (%s): %d GC's (%d bytes).\n", (unsigned long) my_pid, |
|
(unsigned int) TermWin.parent, NONULL(title), types[i].count, |
|
types[i].count * (sizeof(XGCValues) + sizeof(GC))); |
|
} else if (types[i].resource_type == font_atom) { |
|
fprintf(stderr, "Process %lu, window 0x%08x (%s): %d fonts (%d bytes).\n", (unsigned long) my_pid, |
|
(unsigned int) TermWin.parent, NONULL(title), types[i].count, |
|
types[i].count * (sizeof(XFontStruct) + sizeof(Font))); |
|
} |
|
} |
|
XFree(clients); |
|
XFree(types); |
|
if (title) { |
|
XFree(title); |
|
} |
|
} |
|
#endif |
|
|
|
void |
|
install_handlers(void) |
|
{ |
|
/* Ignore SIGHUP */ |
|
/* signal(SIGHUP, handle_exit_signal); */ |
|
signal(SIGHUP, SIG_IGN); |
|
#ifndef __svr4__ |
|
signal(SIGINT, handle_exit_signal); |
|
#endif |
|
signal(SIGTERM, handle_exit_signal); |
|
signal(SIGCHLD, handle_child_signal); |
|
signal(SIGQUIT, handle_crash); |
|
signal(SIGSEGV, handle_crash); |
|
signal(SIGBUS, handle_crash); |
|
signal(SIGABRT, handle_crash); |
|
signal(SIGFPE, handle_crash); |
|
signal(SIGILL, handle_crash); |
|
signal(SIGSYS, handle_crash); |
|
signal(SIGPIPE, SIG_IGN); |
|
#ifdef HAVE_XRES_EXT |
|
signal(SIGUSR1, x_resource_dump); |
|
#else |
|
signal(SIGUSR1, SIG_IGN); |
|
#endif |
|
} |
|
|
|
/* Exit gracefully, clearing the utmp entry and restoring tty attributes */ |
|
void |
|
clean_exit(void) |
|
{ |
|
#if DEBUG >= DEBUG_MEM |
|
if (DEBUG_LEVEL >= DEBUG_MEM) { |
|
unsigned short i; |
|
|
|
/* Deallocate all our crap to help find memory leaks */ |
|
selection_clear(); |
|
scr_release(); |
|
bbar_free(buttonbar); |
|
menulist_clear(menu_list); |
|
font_cache_clear(); |
|
eterm_font_list_clear(); |
|
# ifdef PIXMAP_SUPPORT |
|
FOREACH_IMAGE(free_eterm_image(&(images[idx]));); |
|
# endif |
|
for (i = 0; i < NRS_COLORS; i++) { |
|
if (rs_color[i]) { |
|
FREE(rs_color[i]); |
|
} |
|
} |
|
spifconf_free_subsystem(); |
|
# ifdef USE_XIM |
|
if (xim_input_context) { |
|
XUnsetICFocus(xim_input_context); |
|
XDestroyIC(xim_input_context); |
|
} |
|
if (xim_input_method) { |
|
XCloseIM(xim_input_method); |
|
} |
|
# endif |
|
XCloseDisplay(Xdisplay); |
|
} |
|
#endif |
|
|
|
privileges(INVOKE); |
|
|
|
#ifndef __CYGWIN32__ |
|
if (ttydev) { |
|
D_CMD(("Restoring \"%s\" to mode %03o, uid %d, gid %d\n", ttydev, ttyfd_stat.st_mode, ttyfd_stat.st_uid, |
|
ttyfd_stat.st_gid)); |
|
if (chmod(ttydev, ttyfd_stat.st_mode) != 0) { |
|
D_UTMP(("chmod(\"%s\", %03o) failed: %s\n", ttydev, ttyfd_stat.st_mode, strerror(errno))); |
|
} |
|
if (chown(ttydev, ttyfd_stat.st_uid, ttyfd_stat.st_gid) != 0) { |
|
D_UTMP(("chown(\"%s\", %d, %d) failed: %s\n", ttydev, ttyfd_stat.st_uid, ttyfd_stat.st_gid, strerror(errno))); |
|
} |
|
} |
|
#endif /* __CYGWIN32__ */ |
|
|
|
#ifdef UTMP_SUPPORT |
|
remove_utmp_entry(); |
|
#endif |
|
privileges(REVERT); |
|
#if DEBUG >= DEBUG_MEM |
|
if (DEBUG_LEVEL >= DEBUG_MEM) { |
|
MALLOC_DUMP(); |
|
PIXMAP_DUMP(); |
|
GC_DUMP(); |
|
} |
|
#endif |
|
PABLO_STOP_TRACING(); |
|
DPRINTF1(("Cleanup done. I am outta here!\n")); |
|
} |
|
|
|
/* Acquire a pseudo-teletype from the system. */ |
|
/* |
|
* On failure, returns -1. |
|
* On success, returns the file descriptor. |
|
* |
|
* If successful, ttydev and ptydev point to the names of the |
|
* master and slave parts |
|
*/ |
|
|
|
#ifdef __sgi |
|
inline int sgi_get_pty(void); |
|
|
|
inline int |
|
sgi_get_pty(void) |
|
{ |
|
int fd = -1; |
|
|
|
privileges(INVOKE); |
|
ptydev = ttydev = _getpty(&fd, O_RDWR | O_NDELAY, 0620, 0); |
|
privileges(REVERT); |
|
return (ptydev == NULL ? -1 : fd); |
|
|
|
} |
|
#endif |
|
|
|
#ifdef HAVE_DEV_PTC |
|
inline int aix_get_pty(void); |
|
|
|
inline int |
|
aix_get_pty(void) |
|
{ |
|
|
|
int fd = -1; |
|
|
|
if ((fd = open("/dev/ptc", O_RDWR)) < 0) |
|
return (-1); |
|
else |
|
ptydev = ttydev = ttyname(fd); |
|
return (fd); |
|
} |
|
#endif |
|
|
|
#ifdef HAVE_SCO_PTYS |
|
inline int sco_get_pty(void); |
|
|
|
inline int |
|
sco_get_pty(void) |
|
{ |
|
|
|
static char pty_name[] = "/dev/ptyp??\0\0\0"; |
|
static char tty_name[] = "/dev/ttyp??\0\0\0"; |
|
int idx; |
|
int fd = -1; |
|
|
|
ptydev = pty_name; |
|
ttydev = tty_name; |
|
|
|
for (idx = 0; idx < 256; idx++) { |
|
|
|
sprintf(ptydev, "/dev/ptyp%d", idx); |
|
sprintf(ttydev, "/dev/ttyp%d", idx); |
|
|
|
if (access(ttydev, F_OK) < 0) { |
|
idx = 256; |
|
break; |
|
} |
|
if ((fd = open(ptydev, O_RDWR)) >= 0) { |
|
if (access(ttydev, R_OK | W_OK) == 0) |
|
return (fd); |
|
close(fd); |
|
} |
|
} |
|
return (-1); |
|
} |
|
#endif |
|
|
|
#ifdef HAVE_DEV_PTMX |
|
inline int svr_get_pty(void); |
|
|
|
inline int |
|
svr_get_pty(void) |
|
{ |
|
|
|
int fd = -1; |
|
|
|
/* open the STREAMS, clone device /dev/ptmx (master pty) */ |
|
if ((fd = open("/dev/ptmx", O_RDWR)) < 0) { |
|
return (-1); |
|
} else { |
|
if (grantpt(fd) != 0) { |
|
libast_print_error("grantpt(%d) failed: %s\n", fd, strerror(errno)); |
|
return (-1); |
|
} else if (unlockpt(fd) != 0) { |
|
libast_print_error("unlockpt(%d) failed: %s\n", fd, strerror(errno)); |
|
return (-1); |
|
} else { |
|
ptydev = ttydev = ptsname(fd); |
|
if (ttydev == NULL) { |
|
libast_print_error("ptsname(%d) failed: %s\n", fd, strerror(errno)); |
|
return (-1); |
|
} |
|
} |
|
} |
|
return (fd); |
|
} |
|
#endif |
|
|
|
#define PTYCHAR1 "pqrstuvwxyz" |
|
#define PTYCHAR2 "0123456789abcdefghijklmnopqrstuvwxyz" |
|
|
|
inline int gen_get_pty(void); |
|
|
|
inline int |
|
gen_get_pty(void) |
|
{ |
|
|
|
static char pty_name[] = "/dev/pty??"; |
|
static char tty_name[] = "/dev/tty??"; |
|
int len = sizeof(tty_name); |
|
char *c1, *c2; |
|
int fd = -1; |
|
|
|
ptydev = pty_name; |
|
ttydev = tty_name; |
|
|
|
for (c1 = PTYCHAR1; *c1; c1++) { |
|
ptydev[len - 3] = ttydev[len - 3] = *c1; |
|
for (c2 = PTYCHAR2; *c2; c2++) { |
|
ptydev[len - 2] = ttydev[len - 2] = *c2; |
|
if ((fd = open(ptydev, O_RDWR)) >= 0) { |
|
if (access(ttydev, R_OK | W_OK) == 0) |
|
return (fd); |
|
close(fd); |
|
} |
|
} |
|
} |
|
return (-1); |
|
} |
|
|
|
int |
|
get_pty(void) |
|
{ |
|
|
|
int fd = -1; |
|
|
|
#if defined(__sgi) |
|
fd = sgi_get_pty(); |
|
#elif defined(HAVE_DEV_PTC) |
|
fd = aix_get_pty(); |
|
#elif defined(HAVE_DEV_PTMX) |
|
fd = svr_get_pty(); |
|
#elif defined(HAVE_SCO_PTYS) |
|
fd = sco_get_pty(); |
|
#endif |
|
|
|
/* Fall back on this method */ |
|
if (fd == -1) { |
|
fd = gen_get_pty(); |
|
} |
|
if (fd != -1) { |
|
fcntl(fd, F_SETFL, O_NDELAY); |
|
return (fd); |
|
} else { |
|
libast_print_error("Can't open pseudo-tty -- %s\n", strerror(errno)); |
|
return (-1); |
|
} |
|
} |
|
|
|
/* establish a controlling teletype for new session */ |
|
/* |
|
* On some systems this can be done with ioctl() but on others we |
|
* need to re-open the slave tty. |
|
*/ |
|
int |
|
get_tty(void) |
|
{ |
|
int fd; |
|
pid_t pid; |
|
|
|
/* |
|
* setsid() [or setpgrp] must be before open of the terminal, |
|
* otherwise there is no controlling terminal (Solaris 2.4, HP-UX 9) |
|
*/ |
|
#ifndef ultrix |
|
# ifdef NO_SETSID |
|
pid = setpgrp(0, 0); |
|
# else |
|
pid = setsid(); |
|
# endif |
|
if (pid < 0) { |
|
D_TTYMODE(("%s: setsid() failed: %s, PID == %d\n", rs_name, strerror(errno), pid)); |
|
} |
|
#endif /* ultrix */ |
|
|
|
privileges(INVOKE); |
|
if (ttydev == NULL) { |
|
libast_print_error("Slave tty device name is NULL. Failed to open slave pty.\n"); |
|
exit(EXIT_FAILURE); |
|
} else if ((fd = open(ttydev, O_RDWR)) < 0) { |
|
libast_print_error("Can't open slave tty %s -- %s\n", ttydev, strerror(errno)); |
|
exit(EXIT_FAILURE); |
|
} else { |
|
D_TTY(("Opened slave tty %s\n", ttydev)); |
|
privileges(REVERT); |
|
} |
|
|
|
#if defined (__svr4__) |
|
/* |
|
* Push STREAMS modules: |
|
* ptem: pseudo-terminal hardware emulation module. |
|
* ldterm: standard terminal line discipline. |
|
* ttcompat: V7, 4BSD and XENIX STREAMS compatibility module. |
|
*/ |
|
ioctl(fd, I_PUSH, "ptem"); |
|
ioctl(fd, I_PUSH, "ldterm"); |
|
ioctl(fd, I_PUSH, "ttcompat"); |
|
#else /* __svr4__ */ |
|
{ |
|
unsigned int mode = 0620; |
|
gid_t gid = my_rgid; |
|
|
|
# ifdef PTY_GRP_NAME |
|
{ |
|
struct group *gr = getgrnam(PTY_GRP_NAME); |
|
|
|
if (gr) { |
|
gid = gr->gr_gid; |
|
mode = 0620; |
|
} |
|
} |
|
# endif |
|
|
|
privileges(INVOKE); |
|
# ifndef __CYGWIN32__ |
|
fchown(fd, my_ruid, gid); /* fail silently */ |
|
fchmod(fd, mode); |
|
# endif |
|
privileges(REVERT); |
|
} |
|
#endif /* __svr4__ */ |
|
|
|
/* |
|
* Close all file descriptors. If only stdin/out/err are closed, |
|
* child processes remain alive upon deletion of the window. |
|
*/ |
|
{ |
|
unsigned short i; |
|
unsigned long max_fds; |
|
|
|
/* get number of available file descriptors */ |
|
#ifdef _POSIX_VERSION |
|
max_fds = sysconf(_SC_OPEN_MAX); |
|
#else |
|
max_fds = getdtablesize(); |
|
#endif |
|
|
|
D_TTY(("Closing file descriptors 0-%d.\n", max_fds)); |
|
for (i = 0; i < max_fds; i++) { |
|
if (i != fd) |
|
close(i); |
|
} |
|
D_TTY(("...closed.\n")); |
|
} |
|
|
|
/* Reopen stdin, stdout and stderr over the tty file descriptor */ |
|
dup(fd); /* 0: stdin */ |
|
dup(fd); /* 1: stdout */ |
|
dup(fd); /* 2: stderr */ |
|
|
|
if (fd > 2) |
|
close(fd); |
|
|
|
privileges(INVOKE); |
|
|
|
#ifdef ultrix |
|
if ((fd = open("/dev/tty", O_RDONLY)) >= 0) { |
|
ioctl(fd, TIOCNOTTY, 0); |
|
close(fd); |
|
} else { |
|
# ifdef NO_SETSID |
|
pid = setpgrp(0, 0); |
|
# else |
|
pid = setsid(); |
|
# endif |
|
if (pid < 0) { |
|
D_TTYMODE(("%s: setsid() failed: %s, PID == %d\n", rs_name, strerror(errno), pid)); |
|
} |
|
} |
|
|
|
/* no error, we could run with no tty to begin with */ |
|
#else /* ultrix */ |
|
|
|
# ifdef TIOCSCTTY |
|
ioctl(0, TIOCSCTTY, 0); |
|
# endif |
|
|
|
/* set process group */ |
|
# if defined (_POSIX_VERSION) || defined (__svr4__) |
|
tcsetpgrp(0, pid); |
|
# elif defined (TIOCSPGRP) |
|
ioctl(0, TIOCSPGRP, &pid); |
|
# endif |
|
|
|
/* svr4 problems: reports no tty, no job control */ |
|
/* # if !defined (__svr4__) && defined (TIOCSPGRP) */ |
|
|
|
close(open(ttydev, O_RDWR, 0)); |
|
/* # endif */ |
|
#endif /* ultrix */ |
|
|
|
privileges(REVERT); |
|
|
|
D_TTY(("Returning fd == %d\n", fd)); |
|
return (fd); |
|
} |
|
|
|
/* debug_ttymode() */ |
|
#if DEBUG >= DEBUG_TTYMODE && defined(HAVE_TERMIOS_H) |
|
|
|
/* cpp token stringize doesn't work on all machines <sigh> */ |
|
# define SHOW_TTY_FLAG(flag,name) do { \ |
|
if ((ttymode->c_iflag) & (flag)) { \ |
|
fprintf(stderr, "+%s ", name); \ |
|
} else { \ |
|
fprintf(stderr, "-%s ", name); \ |
|
} \ |
|
} while (0) |
|
# define SHOW_CONT_CHAR(entry, name) fprintf(stderr, "%s=%#3o ", name, ttymode->c_cc[entry]) |
|
static void |
|
debug_ttymode(ttymode_t *ttymode) |
|
{ |
|
|
|
/* c_iflag bits */ |
|
fprintf(stderr, "Input flags: "); |
|
SHOW_TTY_FLAG(IGNBRK, "IGNBRK"); |
|
SHOW_TTY_FLAG(BRKINT, "BRKINT"); |
|
SHOW_TTY_FLAG(IGNPAR, "IGNPAR"); |
|
SHOW_TTY_FLAG(PARMRK, "PARMRK"); |
|
SHOW_TTY_FLAG(INPCK, "INPCK"); |
|
SHOW_TTY_FLAG(ISTRIP, "ISTRIP"); |
|
SHOW_TTY_FLAG(INLCR, "INLCR"); |
|
SHOW_TTY_FLAG(IGNCR, "IGNCR"); |
|
SHOW_TTY_FLAG(ICRNL, "ICRNL"); |
|
SHOW_TTY_FLAG(IXON, "IXON"); |
|
SHOW_TTY_FLAG(IXOFF, "IXOFF"); |
|
# ifdef IUCLC |
|
SHOW_TTY_FLAG(IUCLC, "IUCLC"); |
|
# endif |
|
# ifdef IXANY |
|
SHOW_TTY_FLAG(IXANY, "IXANY"); |
|
# endif |
|
# ifdef IMAXBEL |
|
SHOW_TTY_FLAG(IMAXBEL, "IMAXBEL"); |
|
# endif |
|
fprintf(stderr, "\n"); |
|
|
|
fprintf(stderr, "Control character mappings: "); |
|
SHOW_CONT_CHAR(VINTR, "VINTR"); |
|
SHOW_CONT_CHAR(VQUIT, "VQUIT"); |
|
SHOW_CONT_CHAR(VERASE, "VERASE"); |
|
SHOW_CONT_CHAR(VKILL, "VKILL"); |
|
SHOW_CONT_CHAR(VEOF, "VEOF"); |
|
SHOW_CONT_CHAR(VEOL, "VEOL"); |
|
# ifdef VEOL2 |
|
SHOW_CONT_CHAR(VEOL2, "VEOL2"); |
|
# endif |
|
# ifdef VSWTC |
|
SHOW_CONT_CHAR(VSWTC, "VSWTC"); |
|
# endif |
|
# ifdef VSWTCH |
|
SHOW_CONT_CHAR(VSWTCH, "VSWTCH"); |
|
# endif |
|
SHOW_CONT_CHAR(VSTART, "VSTART"); |
|
SHOW_CONT_CHAR(VSTOP, "VSTOP"); |
|
SHOW_CONT_CHAR(VSUSP, "VSUSP"); |
|
# ifdef VDSUSP |
|
SHOW_CONT_CHAR(VDSUSP, "VDSUSP"); |
|
# endif |
|
# ifdef VREPRINT |
|
SHOW_CONT_CHAR(VREPRINT, "VREPRINT"); |
|
# endif |
|
# ifdef VDISCRD |
|
SHOW_CONT_CHAR(VDISCRD, "VDISCRD"); |
|
# endif |
|
# ifdef VWERSE |
|
SHOW_CONT_CHAR(VWERSE, "VWERSE"); |
|
# endif |
|
# ifdef VLNEXT |
|
SHOW_CONT_CHAR(VLNEXT, "VLNEXT"); |
|
# endif |
|
fprintf(stderr, "\n\n"); |
|
} |
|
|
|
# undef SHOW_TTY_FLAG |
|
# undef SHOW_CONT_CHAR |
|
#endif /* DEBUG_TTYMODE */ |
|
|
|
/* get_ttymode() */ |
|
static void |
|
get_ttymode(ttymode_t *tio) |
|
{ |
|
#ifdef HAVE_TERMIOS_H |
|
/* |
|
* standard System V termios interface |
|
*/ |
|
if (GET_TERMIOS(0, tio) < 0) { |
|
/* return error - use system defaults */ |
|
tio->c_cc[VINTR] = CINTR; |
|
tio->c_cc[VQUIT] = CQUIT; |
|
tio->c_cc[VERASE] = CERASE; |
|
tio->c_cc[VKILL] = CKILL; |
|
tio->c_cc[VSTART] = CSTART; |
|
tio->c_cc[VSTOP] = CSTOP; |
|
tio->c_cc[VSUSP] = CSUSP; |
|
# ifdef VDSUSP |
|
tio->c_cc[VDSUSP] = CDSUSP; |
|
# endif |
|
# ifdef VREPRINT |
|
tio->c_cc[VREPRINT] = CRPRNT; |
|
# endif |
|
# ifdef VDISCRD |
|
tio->c_cc[VDISCRD] = CFLUSH; |
|
# endif |
|
# ifdef VWERSE |
|
tio->c_cc[VWERSE] = CWERASE; |
|
# endif |
|
# ifdef VLNEXT |
|
tio->c_cc[VLNEXT] = CLNEXT; |
|
# endif |
|
# ifdef VSTATUS |
|
tio->c_cc[VSTATUS] = CSTATUS; |
|
# endif |
|
} |
|
tio->c_cc[VEOF] = CEOF; |
|
tio->c_cc[VEOL] = VDISABLE; |
|
# ifdef VEOL2 |
|
tio->c_cc[VEOL2] = VDISABLE; |
|
# endif |
|
# ifdef VSWTC |
|
tio->c_cc[VSWTC] = VDISABLE; |
|
# endif |
|
# ifdef VSWTCH |
|
tio->c_cc[VSWTCH] = VDISABLE; |
|
# endif |
|
# if VMIN != VEOF |
|
tio->c_cc[VMIN] = 1; |
|
# endif |
|
# if VTIME != VEOL |
|
tio->c_cc[VTIME] = 0; |
|
# endif |
|
|
|
/* input modes */ |
|
tio->c_iflag = (BRKINT | IGNPAR | ICRNL | IXON |
|
# ifdef IMAXBEL |
|
| IMAXBEL |
|
# endif |
|
); |
|
|
|
/* output modes */ |
|
tio->c_oflag = (OPOST | ONLCR); |
|
|
|
/* control modes */ |
|
tio->c_cflag = (CS8 | CREAD); |
|
|
|
/* line discipline modes */ |
|
tio->c_lflag = (ISIG | ICANON | IEXTEN | ECHO | ECHOE | ECHOK |
|
# if defined (ECHOCTL) && defined (ECHOKE) |
|
| ECHOCTL | ECHOKE |
|
# endif |
|
); |
|
|
|
#if defined(FORCE_BACKSPACE) && 0 |
|
PrivMode(1, PrivMode_BackSpace); |
|
tio->c_cc[VERASE] = '\b'; /* force ^H for stty setting... */ |
|
SET_TERMIOS(0, tio); /* ...and make it stick -- casey */ |
|
#elif defined(FORCE_DELETE) && 0 |
|
PrivMode(0, PrivMode_BackSpace); |
|
tio->c_cc[VERASE] = 0x7f; /* force ^? for stty setting... */ |
|
SET_TERMIOS(0, tio); /* ...and make it stick -- casey */ |
|
#else |
|
PrivMode((tio->c_cc[VERASE] == '\b'), PrivMode_BackSpace); |
|
#endif |
|
|
|
#else /* HAVE_TERMIOS_H */ |
|
|
|
/* |
|
* sgtty interface |
|
*/ |
|
|
|
/* get parameters -- gtty */ |
|
if (ioctl(0, TIOCGETP, &(tio->sg)) < 0) { |
|
tio->sg.sg_erase = CERASE; /* ^H */ |
|
tio->sg.sg_kill = CKILL; /* ^U */ |
|
} |
|
tio->sg.sg_flags = (CRMOD | ECHO | EVENP | ODDP); |
|
|
|
/* get special characters */ |
|
if (ioctl(0, TIOCGETC, &(tio->tc)) < 0) { |
|
tio->tc.t_intrc = CINTR; /* ^C */ |
|
tio->tc.t_quitc = CQUIT; /* ^\ */ |
|
tio->tc.t_startc = CSTART; /* ^Q */ |
|
tio->tc.t_stopc = CSTOP; /* ^S */ |
|
tio->tc.t_eofc = CEOF; /* ^D */ |
|
tio->tc.t_brkc = -1; |
|
} |
|
/* get local special chars */ |
|
if (ioctl(0, TIOCGLTC, &(tio->lc)) < 0) { |
|
tio->lc.t_suspc = CSUSP; /* ^Z */ |
|
tio->lc.t_dsuspc = CDSUSP; /* ^Y */ |
|
tio->lc.t_rprntc = CRPRNT; /* ^R */ |
|
tio->lc.t_flushc = CFLUSH; /* ^O */ |
|
tio->lc.t_werasc = CWERASE; /* ^W */ |
|
tio->lc.t_lnextc = CLNEXT; /* ^V */ |
|
} |
|
/* get line discipline */ |
|
ioctl(0, TIOCGETD, &(tio->line)); |
|
# ifdef NTTYDISC |
|
tio->line = NTTYDISC; |
|
# endif /* NTTYDISC */ |
|
tio->local = (LCRTBS | LCRTERA | LCTLECH | LPASS8 | LCRTKIL); |
|
|
|
# ifdef FORCE_BACKSPACE |
|
PrivMode(1, PrivMode_BackSpace); |
|
tio->sg.sg_erase = '\b'; |
|
SET_TTYMODE(0, tio); |
|
# elif defined (FORCE_DELETE) |
|
PrivMode(0, PrivMode_BackSpace); |
|
tio->sg.sg_erase = 0x7f; |
|
SET_TTYMODE(0, tio); |
|
# else |
|
PrivMode((tio->sg.sg_erase == '\b'), PrivMode_BackSpace); |
|
# endif |
|
|
|
#endif /* HAVE_TERMIOS_H */ |
|
} |
|
|
|
/* Xlocale */ |
|
XFontSet |
|
create_fontset(const char *font1, const char *font2) |
|
{ |
|
XFontSet fontset = 0; |
|
char *fontname, **ml, *ds; |
|
int mc; |
|
/*const char fs_base[] = ",-misc-fixed-*-r-*-*-*-120-*-*-*-*-*-*,*";*/ |
|
|
|
ASSERT_RVAL(font1 != NULL, (XFontSet) 0); |
|
|
|
if (font2) { |
|
fontname = MALLOC(strlen(font1) + strlen(font2) /*+ sizeof(fs_base)*/ + 2); |
|
if (fontname) { |
|
strcpy(fontname, font1); |
|
strcat(fontname, ","); |
|
strcat(fontname, font2); |
|
/*strcat(fontname, fs_base);*/ |
|
} |
|
} else { |
|
fontname = MALLOC(strlen(font1) /*+ sizeof(fs_base)*/ + 1); |
|
if (fontname) { |
|
strcpy(fontname, font1); |
|
/*strcat(fontname, fs_base);*/ |
|
} |
|
} |
|
if (fontname) { |
|
setlocale(LC_ALL, ""); |
|
fontset = XCreateFontSet(Xdisplay, fontname, &ml, &mc, NULL); |
|
D_FONT(("Created fontset from %s, %d missing charsets (\"%s\").\n", fontname, mc, |
|
((mc > 0) ? (ml[0]) : ("N/A")))); |
|
FREE(fontname); |
|
if (mc) { |
|
XFreeStringList(ml); |
|
/*fontset = 0;*/ |
|
} |
|
} |
|
return fontset; |
|
} |
|
|
|
#if defined(USE_XIM) || defined(MULTI_CHARSET) |
|
|
|
#ifdef USE_XIM |
|
static int xim_real_init(void); |
|
|
|
# ifdef USE_X11R6_XIM |
|
static void xim_destroy_cb(XIM xim, XPointer client_data, XPointer call_data); |
|
static void xim_instantiate_cb(Display * display, XPointer client_data, XPointer call_data); |
|
# endif |
|
#endif |
|
void |
|
init_locale(void) |
|
{ |
|
char *locale = NULL; |
|
|
|
locale = setlocale(LC_ALL, ""); |
|
XSetLocaleModifiers(""); |
|
TermWin.fontset = (XFontSet) 0; |
|
if ((locale == NULL) || (!XSupportsLocale())) { |
|
libast_print_warning("Locale not supported; defaulting to portable \"C\" locale.\n"); |
|
locale = setlocale(LC_ALL, "C"); |
|
XSetLocaleModifiers(""); |
|
REQUIRE(locale); |
|
REQUIRE(XSupportsLocale()); |
|
} else { |
|
#ifdef USE_XIM |
|
#ifdef MULTI_CHARSET |
|
TermWin.fontset = create_fontset(etfonts[def_font_idx], etmfonts[def_font_idx]); |
|
#else |
|
TermWin.fontset = create_fontset(etfonts[def_font_idx], "-misc-fixed-medium-r-semicondensed--13-*-75-*-c-*-iso10646-1"); |
|
#endif |
|
if ((TermWin.fontset == (XFontSet) 0) || (xim_real_init() != -1)) { |
|
return; |
|
} |
|
# ifdef USE_X11R6_XIM |
|
XRegisterIMInstantiateCallback(Xdisplay, NULL, NULL, NULL, xim_instantiate_cb, NULL); |
|
# endif |
|
#endif |
|
} |
|
} |
|
#endif /* USE_XIM || MULTI_CHARSET */ |
|
|
|
#ifdef USE_XIM |
|
static void |
|
xim_set_size(XRectangle * size) |
|
{ |
|
size->x = TermWin.internalBorder; |
|
size->y = TermWin.internalBorder + bbar_calc_docked_height(BBAR_DOCKED_TOP); |
|
size->width = Width2Pixel(TERM_WINDOW_GET_COLS()); |
|
size->height = Height2Pixel(TERM_WINDOW_GET_ROWS()); |
|
} |
|
|
|
static void |
|
xim_set_color(unsigned long *fg, unsigned long *bg) |
|
{ |
|
*fg = PixColors[fgColor]; |
|
*bg = PixColors[bgColor]; |
|
} |
|
|
|
static void |
|
xim_send_spot(void) |
|
{ |
|
XPoint spot; |
|
static XPoint oldSpot = { -1, -1 }; |
|
XVaNestedList preedit_attr; |
|
|
|
if (xim_input_context == NULL) { |
|
return; |
|
} |
|
|
|
if (xim_input_style & XIMPreeditPosition) { |
|
xim_get_position(&spot); |
|
if (spot.x != oldSpot.x || spot.y != oldSpot.y) { |
|
oldSpot.x = spot.x; |
|
oldSpot.y = spot.y; |
|
preedit_attr = XVaCreateNestedList(0, XNSpotLocation, &spot, NULL); |
|
XSetICValues(xim_input_context, XNPreeditAttributes, preedit_attr, NULL); |
|
XFree(preedit_attr); |
|
} |
|
} |
|
} |
|
|
|
static void |
|
xim_get_area(XRectangle * preedit_rect, XRectangle * status_rect, XRectangle * needed_rect) |
|
{ |
|
preedit_rect->x = needed_rect->width + (scrollbar_is_visible() |
|
&& !(BITFIELD_IS_SET(eterm_options, ETERM_OPTIONS_SCROLLBAR_RIGHT)) |
|
? (scrollbar_trough_width()) : (0)); |
|
preedit_rect->y = Height2Pixel(TERM_WINDOW_GET_ROWS() - 1); |
|
|
|
preedit_rect->width = |
|
Width2Pixel(TERM_WINDOW_GET_COLS() + 1) - needed_rect->width + |
|
(!(BITFIELD_IS_SET(eterm_options, ETERM_OPTIONS_SCROLLBAR_RIGHT)) ? (scrollbar_trough_width()) : 0); |
|
preedit_rect->height = Height2Pixel(1); |
|
|
|
status_rect->x = (scrollbar_is_visible() |
|
&& !(BITFIELD_IS_SET(eterm_options, ETERM_OPTIONS_SCROLLBAR_RIGHT))) ? (scrollbar_trough_width()) : 0; |
|
status_rect->y = Height2Pixel(TERM_WINDOW_GET_ROWS() - 1); |
|
|
|
status_rect->width = needed_rect->width ? needed_rect->width : Width2Pixel(TERM_WINDOW_GET_COLS() + 1); |
|
status_rect->height = Height2Pixel(1); |
|
} |
|
|
|
#ifdef USE_X11R6_XIM |
|
static void |
|
xim_destroy_cb(XIM xim, XPointer client_data, XPointer call_data) |
|
{ |
|
xim_input_context = NULL; |
|
xim_input_method = NULL; |
|
XRegisterIMInstantiateCallback(Xdisplay, NULL, NULL, NULL, xim_instantiate_cb, NULL); |
|
xim = NULL; |
|
client_data = call_data = (XPointer) 0; |
|
} |
|
|
|
static void |
|
xim_instantiate_cb(Display * display, XPointer client_data, XPointer call_data) |
|
{ |
|
xim_real_init(); |
|
if (xim_input_context) { |
|
XUnregisterIMInstantiateCallback(Xdisplay, NULL, NULL, NULL, xim_instantiate_cb, NULL); |
|
} |
|
display = NULL; |
|
client_data = call_data = (XPointer) 0; |
|
} |
|
#endif |
|
|
|
static int |
|
xim_real_init(void) |
|
{ |
|
char *p, *s, buf[64], tmp[1024]; |
|
char *end, *next_s; |
|
XIMStyles *xim_styles = NULL; |
|
int found; |
|
XPoint spot; |
|
XRectangle rect, status_rect, needed_rect; |
|
unsigned long fg, bg; |
|
XVaNestedList preedit_attr = NULL; |
|
XVaNestedList status_attr = NULL; |
|
|
|
REQUIRE_RVAL(xim_input_context == NULL, -1); |
|
|
|
xim_input_style = 0; |
|
|
|
if (rs_input_method && *rs_input_method) { |
|
strncpy(tmp, rs_input_method, sizeof(tmp) - 1); |
|
for (s = tmp; *s; s = next_s + 1) { |
|
for (; *s && isspace(*s); s++); |
|
if (!*s) { |
|
break; |
|
} |
|
for (end = s; (*end && (*end != ',')); end++); |
|
for (next_s = end--; ((end >= s) && isspace(*end)); end--); |
|
*(end + 1) = '\0'; |
|
if (*s) { |
|
snprintf(buf, sizeof(buf), "@im=%s", s); |
|
if (((p = XSetLocaleModifiers(buf)) != NULL) && (*p) |
|
&& ((xim_input_method = XOpenIM(Xdisplay, NULL, NULL, NULL)) != NULL)) { |
|
break; |
|
} |
|
} |
|
if (!*next_s) { |
|
break; |
|
} |
|
} |
|
} |
|
|
|
/* try with XMODIFIERS env. var. */ |
|
if (xim_input_method == NULL && getenv("XMODIFIERS") && (p = XSetLocaleModifiers("")) != NULL && *p) { |
|
xim_input_method = XOpenIM(Xdisplay, NULL, NULL, NULL); |
|
} |
|
|
|
/* try with no modifiers base */ |
|
if (xim_input_method == NULL && (p = XSetLocaleModifiers("@im=none")) != NULL && *p) { |
|
xim_input_method = XOpenIM(Xdisplay, NULL, NULL, NULL); |
|
} |
|
|
|
if (xim_input_method == NULL) { |
|
xim_input_method = XOpenIM(Xdisplay, NULL, NULL, NULL); |
|
} |
|
|
|
if (xim_input_method == NULL) { |
|
return -1; |
|
} |
|
#ifdef USE_X11R6_XIM |
|
{ |
|
XIMCallback destroy_cb; |
|
|
|
destroy_cb.callback = xim_destroy_cb; |
|
destroy_cb.client_data = NULL; |
|
if (XSetIMValues(xim_input_method, XNDestroyCallback, &destroy_cb, NULL)) { |
|
libast_print_error("Could not set destroy callback to IM\n"); |
|
} |
|
} |
|
#endif |
|
|
|
if ((XGetIMValues(xim_input_method, XNQueryInputStyle, &xim_styles, NULL)) || (!xim_styles)) { |
|
libast_print_error("input method doesn't support any style\n"); |
|
XCloseIM(xim_input_method); |
|
return -1; |
|
} |
|
strncpy(tmp, (rs_preedit_type ? rs_preedit_type : "OverTheSpot,OffTheSpot,Root"), sizeof(tmp) - 1); |
|
for (found = 0, s = tmp; *s && !found; s = next_s + 1) { |
|
unsigned short i; |
|
|
|
for (; *s && isspace(*s); s++); |
|
if (!*s) { |
|
break; |
|
} |
|
for (end = s; (*end && (*end != ',')); end++); |
|
for (next_s = end--; ((end >= s) && isspace(*end)); end--); |
|
*(end + 1) = '\0'; |
|
|
|
if (!strcmp(s, "OverTheSpot")) { |
|
xim_input_style = (XIMPreeditPosition | XIMStatusNothing); |
|
} else if (!strcmp(s, "OffTheSpot")) { |
|
xim_input_style = (XIMPreeditArea | XIMStatusArea); |
|
} else if (!strcmp(s, "Root")) { |
|
xim_input_style = (XIMPreeditNothing | XIMStatusNothing); |
|
} |
|
|
|
for (i = 0; i < xim_styles->count_styles; i++) { |
|
if (xim_input_style == xim_styles->supported_styles[i]) { |
|
found = 1; |
|
break; |
|
} |
|
} |
|
} |
|
XFree(xim_styles); |
|
|
|
if (found == 0) { |
|
libast_print_error("input method doesn't support my preedit type\n"); |
|
XCloseIM(xim_input_method); |
|
return -1; |
|
} |
|
if ((xim_input_style != (XIMPreeditNothing | XIMStatusNothing)) |
|
&& (xim_input_style != (XIMPreeditArea | XIMStatusArea)) |
|
&& (xim_input_style != (XIMPreeditPosition | XIMStatusNothing))) { |
|
libast_print_error("This program does not support the preedit type\n"); |
|
XCloseIM(xim_input_method); |
|
return -1; |
|
} |
|
if (xim_input_style & XIMPreeditPosition) { |
|
xim_set_size(&rect); |
|
xim_get_position(&spot); |
|
xim_set_color(&fg, &bg); |
|
preedit_attr = |
|
XVaCreateNestedList(0, XNArea, &rect, XNSpotLocation, &spot, XNForeground, fg, XNBackground, bg, XNFontSet, |
|
TermWin.fontset, NULL); |
|
} else if (xim_input_style & XIMPreeditArea) { |
|
xim_set_color(&fg, &bg); |
|
/* The necessary width of preedit area is unknown until create input context. */ |
|
needed_rect.width = 0; |
|
xim_get_area(&rect, &status_rect, &needed_rect); |
|
preedit_attr = XVaCreateNestedList(0, XNArea, &rect, XNForeground, fg, XNBackground, bg, XNFontSet, TermWin.fontset, NULL); |
|
status_attr = |
|
XVaCreateNestedList(0, XNArea, &status_rect, XNForeground, fg, XNBackground, bg, XNFontSet, TermWin.fontset, NULL); |
|
} |
|
xim_input_context = |
|
XCreateIC(xim_input_method, XNInputStyle, xim_input_style, XNClientWindow, TermWin.parent, XNFocusWindow, TermWin.parent, |
|
preedit_attr ? XNPreeditAttributes : NULL, preedit_attr, status_attr ? XNStatusAttributes : NULL, status_attr, |
|
NULL); |
|
if (preedit_attr) { |
|
XFree(preedit_attr); |
|
} |
|
if (status_attr) { |
|
XFree(status_attr); |
|
} |
|
if (xim_input_context == NULL) { |
|
libast_print_error("Failed to create input context\n"); |
|
XCloseIM(xim_input_method); |
|
return -1; |
|
} |
|
if (xim_input_style & XIMPreeditArea) |
|
xim_set_status_position(); |
|
return 0; |
|
} |
|
|
|
void |
|
xim_set_status_position(void) |
|
{ |
|
XRectangle preedit_rect, status_rect, *needed_rect, rect; |
|
XVaNestedList preedit_attr, status_attr; |
|
XPoint spot; |
|
|
|
REQUIRE(xim_input_context != NULL); |
|
|
|
if (xim_input_style & XIMPreeditPosition) { |
|
xim_set_size(&rect); |
|
xim_get_position(&spot); |
|
|
|
preedit_attr = XVaCreateNestedList(0, XNArea, &rect, XNSpotLocation, &spot, NULL); |
|
XSetICValues(xim_input_context, XNPreeditAttributes, preedit_attr, NULL); |
|
XFree(preedit_attr); |
|
} else if (xim_input_style & XIMPreeditArea) { |
|
/* Getting the necessary width of preedit area */ |
|
status_attr = XVaCreateNestedList(0, XNAreaNeeded, &needed_rect, NULL); |
|
XGetICValues(xim_input_context, XNStatusAttributes, status_attr, NULL); |
|
XFree(status_attr); |
|
|
|
xim_get_area(&preedit_rect, &status_rect, needed_rect); |
|
|
|
preedit_attr = XVaCreateNestedList(0, XNArea, &preedit_rect, NULL); |
|
status_attr = XVaCreateNestedList(0, XNArea, &status_rect, NULL); |
|
XSetICValues(xim_input_context, XNPreeditAttributes, preedit_attr, XNStatusAttributes, status_attr, NULL); |
|
XFree(preedit_attr); |
|
XFree(status_attr); |
|
} |
|
} |
|
|
|
void |
|
xim_set_fontset(void) |
|
{ |
|
XVaNestedList preedit_attr = NULL; |
|
XVaNestedList status_attr = NULL; |
|
|
|
REQUIRE(xim_input_context != NULL); |
|
|
|
if (xim_input_style & XIMStatusArea) { |
|
status_attr = XVaCreateNestedList(0, XNFontSet, TermWin.fontset, NULL); |
|
} |
|
if (xim_input_style & (XIMPreeditArea | XIMPreeditPosition)) { |
|
preedit_attr = XVaCreateNestedList(0, XNFontSet, TermWin.fontset, NULL); |
|
} |
|
|
|
if (status_attr && preedit_attr) { |
|
XSetICValues(xim_input_context, XNPreeditAttributes, preedit_attr, XNStatusAttributes, status_attr, NULL); |
|
} else if (preedit_attr) { |
|
XSetICValues(xim_input_context, XNPreeditAttributes, preedit_attr, NULL); |
|
} else if (status_attr) { |
|
XSetICValues(xim_input_context, XNStatusAttributes, status_attr, NULL); |
|
} |
|
|
|
if (preedit_attr) { |
|
XFree(preedit_attr); |
|
} |
|
if (status_attr) { |
|
XFree(status_attr); |
|
} |
|
} |
|
#endif /* USE_XIM */ |
|
|
|
/* run_command() */ |
|
/* |
|
* Run the command in a subprocess and return a file descriptor for the |
|
* master end of the pseudo-teletype pair with the command talking to |
|
* the slave. |
|
*/ |
|
int |
|
run_command(char **argv) |
|
{ |
|
|
|
ttymode_t tio; |
|
int ptyfd; |
|
|
|
/* Save and then give up any super-user privileges */ |
|
privileges(IGNORE); |
|
|
|
ptyfd = get_pty(); |
|
if (ptyfd < 0) |
|
return (-1); |
|
AT_LEAST(num_fds, ((unsigned int) (ptyfd + 1))); |
|
|
|
/* store original tty status for restoration clean_exit() -- rgg 04/12/95 */ |
|
lstat(ttydev, &ttyfd_stat); |
|
D_CMD(("Original settings of %s are mode %o, uid %d, gid %d\n", ttydev, ttyfd_stat.st_mode, ttyfd_stat.st_uid, |
|
ttyfd_stat.st_gid)); |
|
|
|
/* install exit handler for cleanup */ |
|
#ifdef HAVE_ATEXIT |
|
atexit(clean_exit); |
|
#else |
|
# if defined (__sun__) |
|
on_exit(clean_exit, NULL); /* non-ANSI exit handler */ |
|
# else |
|
libast_print_error("no atexit(), UTMP entries can't be cleaned\n"); |
|
# endif |
|
#endif |
|
|
|
/* |
|
* get tty settings before fork() |
|
* and make a reasonable guess at the value for BackSpace |
|
*/ |
|
get_ttymode(&tio); |
|
/* add Backspace value */ |
|
SavedModes |= (PrivateModes & PrivMode_BackSpace); |
|
|
|
/* add value for scrollbar */ |
|
if (scrollbar_is_visible()) { |
|
PrivateModes |= PrivMode_scrollbar; |
|
SavedModes |= PrivMode_scrollbar; |
|
} |
|
tt_winsize(ptyfd); |
|
#if DEBUG >= DEBUG_TTYMODE && defined(HAVE_TERMIOS_H) |
|
if (DEBUG_LEVEL >= DEBUG_TTYMODE) { |
|
debug_ttymode(&tio); |
|
} |
|
#endif |
|
|
|
D_CMD(("Forking\n")); |
|
cmd_pid = fork(); |
|
D_CMD(("After fork(), cmd_pid == %d\n", cmd_pid)); |
|
if (cmd_pid < 0) { |
|
libast_print_error("fork(): %s\n", strerror(errno)); |
|
return (-1); |
|
} |
|
if (cmd_pid == 0) { |
|
|
|
/* Child process. Reset the signal handlers right away. */ |
|
signal(SIGINT, SIG_DFL); |
|
signal(SIGQUIT, SIG_DFL); |
|
signal(SIGCHLD, SIG_DFL); |
|
signal(SIGSEGV, SIG_DFL); |
|
signal(SIGBUS, SIG_DFL); |
|
signal(SIGABRT, SIG_DFL); |
|
signal(SIGFPE, SIG_DFL); |
|
signal(SIGILL, SIG_DFL); |
|
signal(SIGSYS, SIG_DFL); |
|
signal(SIGALRM, SIG_DFL); |
|
#ifdef SIGTSTP |
|
signal(SIGTSTP, SIG_IGN); |
|
signal(SIGTTIN, SIG_IGN); |
|
signal(SIGTTOU, SIG_IGN); |
|
#endif |
|
|
|
#ifdef HAVE_UNSETENV |
|
unsetenv("LINES"); |
|
unsetenv("COLUMNS"); |
|
unsetenv("TERMCAP"); |
|
#endif |
|
|
|
DEBUG_LEVEL = 0; |
|
|
|
get_tty(); |
|
SET_TTYMODE(0, &tio); |
|
#if 0 |
|
if (TermWin.screen_mode != NS_MODE_NONE) { |
|
tt_winsize(0); |
|
} |
|
#endif |
|
|
|
/* become virtual console, fail silently */ |
|
if (BITFIELD_IS_SET(vt_options, VT_OPTIONS_CONSOLE)) { |
|
int fd = 1; |
|
|
|
privileges(INVOKE); |
|
#ifdef SRIOCSREDIR |
|
fd = open(CONSOLE, O_WRONLY); |
|
if (fd < 0 || ioctl(fd, SRIOCSREDIR, 0) < 0) { |
|
if (fd >= 0) |
|
close(fd); |
|
} |
|
#elif defined(TIOCCONS) |
|
ioctl(0, TIOCCONS, &fd); |
|
#endif /* SRIOCSREDIR */ |
|
privileges(REVERT); |
|
} |
|
|
|
/* Permanently revoke all privileges for the child process. |
|
Root shells for everyone are tres uncool.... ;^) -- mej */ |
|
#ifdef _HPUX_SOURCE |
|
setresuid(my_ruid, my_ruid, my_euid); |
|
setresgid(my_rgid, my_rgid, my_egid); |
|
#else |
|
/* No special treatment is needed for systems with saved uids/gids, |
|
because the exec*() calls reset the saved uid/gid to the |
|
effective uid/gid -- mej */ |
|
# ifndef __CYGWIN32__ |
|
setregid(my_rgid, my_rgid); |
|
setreuid(my_ruid, my_ruid); |
|
# endif /* __CYGWIN32__ */ |
|
#endif /* _HPUX_SOURCE */ |
|
|
|
D_UTMP(("Child process reset\n")); |
|
my_euid = my_ruid; |
|
my_egid = my_rgid; |
|
|
|
#ifdef HAVE_USLEEP |
|
usleep(10); /* Attempt to force a context switch so that the parent runs before us. */ |
|
#else |
|
sleep(1); /* ugliness */ |
|
#endif |
|
D_CMD(("[%d] About to spawn shell\n", getpid())); |
|
if (chdir(initial_dir)) { |
|
libast_print_warning("Unable to chdir to \"%s\" -- %s\n", initial_dir, strerror(errno)); |
|
} |
|
if (argv != NULL) { |
|
#if DEBUG >= DEBUG_CMD |
|
if (DEBUG_LEVEL >= DEBUG_CMD) { |
|
int i; |
|
|
|
for (i = 0; argv[i]; i++) { |
|
DPRINTF(("argv[%d] = \"%s\"\n", i, argv[i])); |
|
} |
|
} |
|
#endif |
|
D_CMD(("[%d] execvp(\"%s\", %8p) is next. I'm outta here!\n", getpid(), NONULL(argv[0]), argv)); |
|
execvp(argv[0], argv); |
|
libast_print_error("execvp() failed, cannot execute \"%s\": %s\n", argv[0], strerror(errno)); |
|
} else { |
|
|
|
const char *argv0, *shell; |
|
|
|
if ((shell = getenv("SHELL")) == NULL || *shell == '\0') |
|
shell = "/bin/sh"; |
|
|
|
argv0 = my_basename(shell); |
|
if (BITFIELD_IS_SET(eterm_options, ETERM_OPTIONS_LOGIN_SHELL)) { |
|
char *p = MALLOC(strlen(argv0) + 2); |
|
|
|
p[0] = '-'; |
|
strcpy(&p[1], argv0); |
|
argv0 = p; |
|
} |
|
execlp(shell, argv0, NULL); |
|
libast_print_error("execlp() failed, cannot execute \"%s\": %s\n", shell, strerror(errno)); |
|
} |
|
sleep(3); /* Sleep to make sure fork() returns in the parent, and so user can read error message */ |
|
exit(EXIT_FAILURE); |
|
} |
|
#ifdef UTMP_SUPPORT |
|
privileges(RESTORE); |
|
if (BITFIELD_IS_SET(eterm_options, ETERM_OPTIONS_WRITE_UTMP)) { |
|
add_utmp_entry(ttydev, display_name, ptyfd); |
|
} |
|
privileges(IGNORE); |
|
#endif |
|
|
|
D_CMD(("Returning ptyfd == %d\n", ptyfd)); |
|
return (ptyfd); |
|
} |
|
|
|
|
|
#ifdef ESCREEN |
|
|
|
/***************************************************************************/ |
|
/* Escreen: callbacks */ |
|
/***********************/ |
|
|
|
static int |
|
set_scroll_x(void *xd, int x) |
|
{ |
|
USE_VAR(xd); |
|
D_ESCREEN(("%d\n", x)); |
|
return NS_FAIL; |
|
} |
|
|
|
static int |
|
set_scroll_y(void *xd, int y) |
|
{ |
|
USE_VAR(xd); |
|