/* Copyright 1990-2001 Sun Microsystems, Inc. All Rights Reserved. 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 or substantial portions of the Software. 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 OPEN GROUP OR SUN MICROSYSTEMS, INC. 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 EVEN IF ADVISED IN ADVANCE OF THE POSSIBILITY OF SUCH DAMAGES. Except as contained in this notice, the names of The Open Group and/or Sun Microsystems, Inc. shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from The Open Group and/or Sun Microsystems, Inc., as applicable. X Window System is a trademark of The Open Group OSF/1, OSF/Motif and Motif are registered trademarks, and OSF, the OSF logo, LBX, X Window System, and Xinerama are trademarks of the Open Group. All other trademarks and registered trademarks mentioned herein are the property of their respective owners. No right, title or interest in or to any trademark, service mark, logo or trade name of Sun Microsystems, Inc. or its licensors is granted. */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "Xlcint.h" #include "XlcPublic.h" /* for wait_iiimd_ready() */ #include #include #include /* for wait_iiimd_ready() */ #include "watchdog.h" #define HTT_CLASS_NAME "Iiimx" #if 0 #include "watchdog_msg.h" #include "nls_message.h" #include "htt_server/main.h" /* For debugging purpose */ #include "htt_debug.h" #endif #ifndef PATH_MAX #define PATH_MAX 1024 #endif #ifndef OPENWINHOME #define OPENWINHOME "/usr/openwin" #endif #define OPENWIN_MOTIF_PRELOAD_ENV "LD_PRELOAD=/usr/dt/lib/libXm.so.3" #define IMDIR IIIMLIBDIR static void start_htt_server(long *, char *argv[]); static void start_htt_props(long *, char *argv[]); static void wait_iiimd_ready(const char * uds_filename, time_t timeout); static void start_iiimd(pid_t *, char ** argv); static void start_xsettings_init(pid_t *); static void start_iiim_panel(pid_t *); static Bool build_dir(const char *, mode_t); static char * build_uds_filename(Widget); static char * build_vardir_dirname(void); static char ** build_iiimd_arg(char *, char *, char *, char *); static void proc_exit(int); static void clean_up(int); static void parse_command(int, char **); static char *build_cmdline_db(Widget toplevel, char *argv[], int argc, Bool replace_mode); static unsigned char * client_group_get(); static void start_daemon(const char * display_name); static Bool wait_xbe_startup(Display * display); static int x_io_error_handler(Display * display); int (*x_default_io_error_handler)(Display *display); static char *htt_props_path = "htt_props"; #define NL_HTT_SETD 3 #define MAX_NUM_TRY 30 #define ATOM_NAME_LEN_MAX 64 typedef enum { RmServerActive = 1, RmServerReset = 2, RmServerKilled = 3 } ServerStatus; static ServerStatus Server_Status = RmServerActive; #if 0 static HttMessage htt_message = (HttMessage) 0; #endif #if 0 #define nl_msg(msg_num, msg) GetNLSMessage(htt_message, msg_num, msg) #endif #define nl_msg(msg_num, msg) (msg) static long htt_server_pid, htt_props_pid; static pid_t iiimd_pid; static pid_t xsettings_init_pid; static pid_t iiim_panel_pid; static Atom htt_atom, server_atom, props_atom, resource_atom; static Atom cmdline_atom, htt_server_reset_atom, htt_watchdog_atom, class_atom; static Display *display; static Window httw_id; static Window root; static Atom desktop_lang_atom; static void save_last_language_selection (const char *); static Bool spawn_props = True; /* htt_props spawned by htt */ static char **htt_server_arg; static char **htt_props_arg; static char **iiimd_arg; static char *get_home_dir(char *buf); static char *get_host(char *buf, int max_len); static int htt_server_killed = 0; typedef struct _RmDatabase { char *htt_server_name; Bool start_props; /* This bool is used to sense * htt_props running or not */ Bool respond_to_sm; Bool start_iiimd; Bool start_xsettings_init; Bool start_iiim_panel; Bool daemon; Bool no_daemon; char *udsfile; char *vardir; char *log_level; char *log_facility; } RmDatabase; static RmDatabase my_rdb; static XtResource rdb_items[] = { {"inputMethod", "InputMethod", XtRString, sizeof(char *), offsetof(RmDatabase, htt_server_name), XtRString, (XPointer)"iiim-xbe"}, {"startProps", "StartProps", XtRBool, sizeof(Bool), offsetof(RmDatabase, start_props), XtRString, (XPointer) "false"}, {"respondToSM", "RespondToSM", XtRBool, sizeof(Bool), offsetof(RmDatabase, respond_to_sm), XtRString, (XPointer) "false"}, {"startIiimd", "StartIiimd", XtRBool, sizeof(Bool), offsetof(RmDatabase, start_iiimd), XtRString, (XPointer) "false"}, {"startXSettingsInit", "StartXSettingsInit", XtRBool, sizeof(Bool), offsetof(RmDatabase, start_xsettings_init), XtRString, (XPointer) "true"}, {"startIiimPanel", "StartIiimPanel", XtRBool, sizeof(Bool), offsetof(RmDatabase, start_iiim_panel), XtRString, (XPointer) "true"}, {"daemon", "Daemon", XtRBool, sizeof(Bool), offsetof(RmDatabase, daemon), XtRString, (XPointer) "false"}, {"noDaemon", "NoDaemon", XtRBool, sizeof(Bool), offsetof(RmDatabase, no_daemon), XtRString, (XPointer) "false"}, {"udsFile", "UdsFile", XtRString, sizeof (char *), offsetof(RmDatabase, udsfile), XtRString, (XPointer) NULL}, {"varDir", "VarDir", XtRString, sizeof (char *), offsetof(RmDatabase, vardir), XtRString, (XPointer) NULL}, {"logLevel", "LogLevel", XtRString, sizeof (char *), offsetof(RmDatabase, log_level), XtRString, (XPointer) NULL}, {"logFacility", "LogFacility", XtRString, sizeof (char *), offsetof(RmDatabase, log_facility), XtRString, (XPointer) NULL}, }; static XrmOptionDescRec rdb_options[] = { {"-xim", "*inputMethod", XrmoptionSepArg, NULL}, {"-sp", "*startProps", XrmoptionNoArg, (XPointer) "true"}, {"-so", "*startProps", XrmoptionNoArg, (XPointer) "false"}, {"-rsm", "*respondToSM", XrmoptionNoArg, (XPointer) "true"}, {"-daemon", "*daemon", XrmoptionNoArg, (XPointer) "true"}, {"-nodaemon", "*noDaemon", XrmoptionNoArg, (XPointer) "true"}, {"-iiimd", "*startIiimd", XrmoptionNoArg, (XPointer) "True"}, {"-xsettings_init", "*startXSettingsInit", XrmoptionNoArg, (XPointer) "True"}, {"-iiim_panel", "*startIiimPanel", XrmoptionNoArg, (XPointer) "True"}, {"-udsfile", "*udsFile", XrmoptionSepArg, NULL}, {"-vardir", "*varDir", XrmoptionSepArg, NULL}, {"-log_level", "*logLevel", XrmoptionSepArg, NULL}, {"-log_facility", "*logFacility", XrmoptionSepArg, NULL}, }; static int NUM_RDB_OPTIONS = XtNumber(rdb_options); int main(argc, argv) int argc; char *argv[]; { pid_t grpid; Atom ret_type; int ret_format; unsigned long nitems, bytes_left; char htt_name[MAXNAMELEN]; int screen_no; XEvent ev; unsigned long *tmp; /* must be 'long' to set pid */ int i; char *locale; char *cmdline_prop; XtAppContext app; Widget toplevel; Atom htt_save_atom[3]; long pid = getpid(); Atom host_atom; char hostname_prop[1024]; Atom iiim_server_atom; char * uds_filename; char * vardir_dirname; Atom iiim_client_group_atom; char * log_level_name; char * log_facility_name; setlocale(LC_ALL, ""); #if 0 htt_message = CreateNLSMessage((char *) 0, NL_HTT_SETD); #endif #if 0 LOG0("watchdog.c:starting htt"); #endif /* * Setup the signal handlers to monitor htt_server, htt_props * abnormal termination */ #ifdef SETPGRP_VOID grpid = setpgrp(); #else grpid = setpgrp(0, 0); #endif #ifdef SunOS sigset(SIGTERM, clean_up); sigset(SIGINT, clean_up); sigset(SIGCHLD, proc_exit); #else signal(SIGTERM, clean_up); signal(SIGINT, clean_up); signal(SIGCHLD, proc_exit); #endif #if 0 LOG0("watchdog.c:Signal handlers set"); #endif toplevel = XtVaAppInitialize(&app, HTT_CLASS_NAME, rdb_options, NUM_RDB_OPTIONS, &argc, argv, NULL, NULL); XtGetApplicationResources(toplevel, (char *) &my_rdb, rdb_items, XtNumber(rdb_items), 0, 0); my_rdb.start_props = False; my_rdb.respond_to_sm = False; /* duplicate again this time to build command line db */ cmdline_prop = build_cmdline_db(toplevel, argv, argc, False); if ((True == my_rdb.daemon) || ((False == my_rdb.no_daemon) && (True == my_rdb.start_iiimd))) { start_daemon(XtDisplay(toplevel)->display_name); } if (True == my_rdb.start_iiimd) { x_default_io_error_handler = XSetIOErrorHandler(x_io_error_handler); } parse_command(argc, argv); strcpy(htt_name, HTT_WINDOW_NAME); if ((locale = setlocale(LC_CTYPE, NULL))) strcat(htt_name, locale); else { fprintf(stderr, nl_msg(NL_HTT_LOCALE_FAIL, "iiimx : Error - locale not supported\n") ); exit(1); } htt_server_arg = (char **) malloc(sizeof(char *) * (argc + 1)); htt_props_arg = (char **) malloc(sizeof(char *) * (argc + 3)); { /* htt_server */ char **pargv = htt_server_arg; *pargv++ = my_rdb.htt_server_name; for (i = 1; i < argc; i++) { *pargv++ = argv[i]; } *pargv = NULL; /* htt_props */ pargv = htt_props_arg; *pargv++ = htt_props_path; for (i = 1; i < argc; i++) { *pargv++ = argv[i]; } *pargv++ = "-lc_basiclocale"; *pargv++ = locale; *pargv = NULL; } uds_filename = NULL; vardir_dirname = NULL; if (True == my_rdb.start_iiimd) { if (NULL == my_rdb.udsfile) { uds_filename = build_uds_filename(toplevel); } else { uds_filename = my_rdb.udsfile; } if (NULL == my_rdb.vardir) { vardir_dirname = build_vardir_dirname(); } else { vardir_dirname = my_rdb.vardir; } if (NULL == my_rdb.log_level) { log_level_name = NULL; } else { log_level_name = my_rdb.log_level; } if (NULL == my_rdb.log_facility) { log_facility_name = "STDERR"; } else { log_facility_name = my_rdb.log_facility; } iiimd_arg = build_iiimd_arg(uds_filename, vardir_dirname, log_level_name, log_facility_name); } /* Obtain display */ display = XtDisplay(toplevel); if (display == NULL) { fprintf(stderr, nl_msg(NL_HTT_XOPEN_DISPLAY_FAIL, "iiimx : Error - Unable to connect with X server\n")); exit(-1); } /* Create the properties in the display */ htt_atom = XInternAtom(display, htt_name, False); htt_watchdog_atom = XInternAtom(display, HTT_WATCHDOG_PID, False); server_atom = XInternAtom(display, HTT_SERVER_PID, False); props_atom = XInternAtom(display, HTT_PROPS_PID, False); resource_atom = XInternAtom(display, HTT_RESOURCES, False); cmdline_atom = XInternAtom(display, HTT_CMDLINE_RESOURCES, False); htt_server_reset_atom = XInternAtom(display, HTT_SERVER_RESET, False); if (htt_atom == BadAtom) fprintf(stderr, nl_msg(NL_ATOM_CREATE_FAIL, "iiimx : Warning - Unable to create atom") ); iiim_server_atom = None; if (True == my_rdb.start_iiimd) { iiim_server_atom = XInternAtom(display, "IIIM_SERVER", False); } iiim_client_group_atom = XInternAtom(display, "IIIM_CLIENT_GROUP", False); /* * If already a version of iiimx is running under same locale , detect * it by checking SelectionOwner of HTT_ATOM */ screen_no = DefaultScreen(display); httw_id = XGetSelectionOwner(display, htt_atom); if (httw_id != None) { fprintf(stderr, nl_msg(NL_HTT_ALREADY_RUNNING, "iiimx : Error - iiimx is already running...\n") ); exit(-1); } /* Create the window & make this window as owner of propery htt_atom */ httw_id = XCreateSimpleWindow(display, RootWindow(display, screen_no), 0, 0, 10, 10, 4, 1, 1); /* Register WM Protocol */ #if 0 LOG1("watchdog.c:htt_window_id %x\n", httw_id); #endif htt_save_atom[0] = XInternAtom(display, "_MOTIF_WM_MESSAGES", True); htt_save_atom[1] = XInternAtom(display, "WM_DELETE_WINDOW", True); htt_save_atom[2] = XInternAtom(display, "WM_SAVE_YOURSELF", True); host_atom = XInternAtom(display, "WM_CLIENT_MACHINE", True); get_host(hostname_prop, sizeof(hostname_prop)); XChangeProperty(display, httw_id, host_atom, XA_STRING, 8, PropModeReplace, hostname_prop, strlen(hostname_prop)); class_atom = XInternAtom(display, "WM_CLASS", True); XChangeProperty(display, httw_id, class_atom, XA_STRING, 8, PropModeReplace, "iiimx", strlen("iiimx")); XSetWMProtocols(display, httw_id, (Atom *)&htt_save_atom, 3); XSelectInput(display, httw_id, PropertyChangeMask | StructureNotifyMask); XSetSelectionOwner(display, htt_atom, httw_id, CurrentTime); XChangeProperty(display, httw_id, cmdline_atom, XA_STRING, 8, PropModeReplace, cmdline_prop, strlen(cmdline_prop)); if (True == my_rdb.start_iiimd) { char * iiim_server; char * iiim_vardir; iiim_server = (char *)malloc(PATH_MAX); iiim_vardir = (char *)malloc(PATH_MAX); snprintf(iiim_server, PATH_MAX, "uds:%s", uds_filename); XSetSelectionOwner(display, iiim_server_atom, httw_id, CurrentTime); XChangeProperty(display, httw_id, iiim_server_atom, XA_STRING, 8, PropModeReplace, iiim_server, strlen(iiim_server)); snprintf(iiim_server, PATH_MAX, "IIIM_SERVER=%s,", uds_filename); putenv(iiim_server); snprintf(iiim_vardir, PATH_MAX, "IIIMD_OPTION_VARDIR=%s", vardir_dirname); putenv(iiim_vardir); putenv("IIIMD_OPTION_DESKTOP="); /* putenv("IIIMD_KEY_RELEASE_DISABLE="); */ /* free(iiim_server); */ } if (None != iiim_client_group_atom) { unsigned char * client_group; unsigned char * client_group_env; client_group = client_group_get(); XSetSelectionOwner(display, iiim_client_group_atom, httw_id, CurrentTime); XChangeProperty(display, httw_id, iiim_client_group_atom, XA_STRING, 8, PropModeReplace, client_group, strlen((char *)client_group)); XFlush(display); client_group_env = (unsigned char *)malloc(PATH_MAX); if (NULL != client_group_env) { snprintf(client_group_env, PATH_MAX, "IIIM_CLIENT_GROUP=%s", client_group); putenv(client_group_env); } free(client_group); } XFlush(display); /* I am not sure it will reach before * htt_server starts so flush explicitly */ /* * Set the PID property and used by htt_props to verify if it is * forked from htt */ XChangeProperty(display, httw_id, htt_watchdog_atom, XA_WINDOW, 32, PropModeReplace, (unsigned char *)&pid, 1); /* fork iiimd */ if (True == my_rdb.start_iiimd) { start_iiimd(&iiimd_pid, iiimd_arg); wait_iiimd_ready(uds_filename, 300); } if (True == my_rdb.start_xsettings_init) { start_xsettings_init(&xsettings_init_pid); } if (True == my_rdb.start_iiim_panel) { tmp = NULL; int autostart = 0; Atom im_settings_atom = XInternAtom (display, IM_SETTINGS, False); /* wait for the properties being exported by iiimx-settings-init */ do { XGetWindowProperty(display, RootWindow (display, 0), im_settings_atom, 0, 1000000L, False, AnyPropertyType, &ret_type, &ret_format, &nitems, &bytes_left, &tmp); sleep (1); } while (tmp == NULL); autostart = *(tmp+4); XFree (tmp); if (autostart) { start_iiim_panel (&iiim_panel_pid); } } /* fork htt_server */ start_htt_server(&htt_server_pid, htt_server_arg); XChangeProperty(display, httw_id, server_atom, XA_WINDOW, 32, PropModeReplace, (unsigned char *)&htt_server_pid, 1); XFlush(display); /* fork htt_props *//* TO DO: conditional fork */ if (my_rdb.start_props) { start_htt_props(&htt_props_pid, htt_props_arg); XChangeProperty(display, httw_id, props_atom, XA_WINDOW, 32, PropModeReplace, (unsigned char *)&htt_props_pid, 1); XFlush(display); } root = DefaultRootWindow (display); desktop_lang_atom = XInternAtom (display, "_IIIM_SWITCHER_DESKTOP_INPUT_LANGUAGE", False); XSelectInput (display, root, PropertyChangeMask); for (;;) { XNextEvent(display, &ev); switch (ev.type) { case PropertyNotify: if (ev.xproperty.window == root && ev.xproperty.atom == desktop_lang_atom) { XTextProperty text_props; text_props.value = NULL; XGetTextProperty (display, root, &text_props, desktop_lang_atom); if (text_props.value) { save_last_language_selection (text_props.value); XFree (text_props.value); } }else if (ev.xproperty.window == httw_id) { if (ev.xproperty.atom == props_atom) { #if 0 LOG2("watchdog.c: property notify event wid = %x atom = %s\n", ev.xproperty.window, XGetAtomName(display, ev.xproperty.atom)); #endif XGetWindowProperty(display, httw_id, props_atom, 0, 4, False, XA_WINDOW, &ret_type, &ret_format, &nitems, &bytes_left, &tmp); if (ret_type == XA_WINDOW) { if (*tmp) { htt_props_pid = *tmp; my_rdb.start_props = 1; #if 0 LOG1("watchdog.c:htt_props started pid=%d\n", htt_props_pid); #endif } else { my_rdb.start_props = 0; htt_props_pid = -1; spawn_props = False; /* htt_props spawned by * htt is killed */ #if 0 LOG0("watchdog.c:htt_props is killed"); #endif } } } else if (ev.xproperty.atom == server_atom) { XGetWindowProperty(display, httw_id, server_atom, 0, 4, False, XA_WINDOW, &ret_type, &ret_format, &nitems, &bytes_left, &tmp); if (ret_type == XA_WINDOW) if (*tmp) { if (htt_server_pid == (*tmp)); else fprintf(stderr, nl_msg(NL_HTT_DUPLAICTED, "iiimx : Warning - Duplicate iiim-xbe %ld\n"), *tmp); } } else if (ev.xproperty.atom == resource_atom) { cmdline_prop = build_cmdline_db(toplevel, argv, argc, False); XChangeProperty(display, httw_id, cmdline_atom, XA_STRING, 8, PropModeReplace, cmdline_prop, strlen(cmdline_prop) + 1); XFlush(display); XFree(cmdline_prop); } else if (ev.xproperty.atom == htt_server_reset_atom) { XGetWindowProperty(display, httw_id, htt_server_reset_atom, 0, 4, False, XA_WINDOW, &ret_type, &ret_format, &nitems, &bytes_left, &tmp); if (*tmp) { htt_server_killed = *tmp; /* Kill & start the server */ Server_Status = RmServerReset; kill(htt_server_pid, SIGTERM); cmdline_prop = build_cmdline_db(toplevel, argv, argc, True); XChangeProperty(display, httw_id, cmdline_atom, XA_STRING, 8, PropModeReplace, cmdline_prop, strlen(cmdline_prop) + 1); XFlush(display); XFree(cmdline_prop); start_htt_server(&htt_server_pid, htt_server_arg); XChangeProperty(display, httw_id, server_atom, XA_WINDOW, 32, PropModeReplace, (unsigned char *)&htt_server_pid, 1); } else { /* Kill the server */ Server_Status = RmServerKilled; kill(htt_server_pid, SIGTERM); } } else #ifdef HTT_DEBUG fprintf(stderr, "iiimx: Unknown property notify event wid = %x atom = %s\n", ev.xproperty.window, XGetAtomName(display, ev.xproperty.atom)) #endif ; } break; case DestroyNotify: if (ev.xdestroywindow.window == httw_id) { Server_Status = RmServerKilled; kill(htt_server_pid, SIGTERM); if (my_rdb.start_props) kill(htt_props_pid, SIGTERM); exit(0); } else { /* don't know what to do.... */ } case ClientMessage:{ #if 0 LOG0("watchdog.c:Client Message"); LOG1("watchdog.c:Message type %s\n", XGetAtomName(display, ev.xclient.message_type)); LOG1("watchdog.c:format %d\n", ev.xclient.format); LOG1("watchdog.c:Client message data %s \n", XGetAtomName(display, ev.xclient.data.l[0])); #endif /* Need to tell htt_server to save its state */ if ((ev.xclient.format == 32) && (!strncmp(XGetAtomName(display, ev.xclient.message_type), "WM_PROTOCOLS", 12))) { if (ev.xclient.data.l[0] == htt_save_atom[1]) { char *res = strdup("DeleteWindow:True"); XChangeProperty(display, httw_id, resource_atom, XA_STRING, 8, PropModeAppend, (unsigned char *) res, strlen(res) + 1); free(res); } if (ev.xclient.data.l[0] == htt_save_atom[2]) { char *res = strdup("SaveState:True"); XChangeProperty(display, httw_id, resource_atom, XA_STRING, 8, PropModeAppend, (unsigned char *) res, strlen(res) + 1); free(res); if (my_rdb.respond_to_sm) if (!spawn_props) { /* spawn_props = False means */ char **tmp_argv = (char **) XtMalloc((argc + 1) * sizeof(char *)); int tmp_argc; for (tmp_argc = 0; tmp_argc < argc; tmp_argc++) tmp_argv[tmp_argc] = argv[tmp_argc]; tmp_argv[tmp_argc] = (char *) XtMalloc(strlen("-so") + 1); strcpy(tmp_argv[tmp_argc++], "-so"); XSetCommand(display, httw_id, tmp_argv, tmp_argc); XtFree(tmp_argv[tmp_argc - 1]); XtFree((char *)tmp_argv); } else XSetCommand(display, httw_id, argv, argc); else XSetCommand(display, httw_id, (char **)0, 0); /* Ignore WM_SAVEYOURSELF msg */ } } break; } } } } void clean_up(int sig) { #ifdef SunOS sigset(SIGCHLD, SIG_DFL); #else signal(SIGCHLD, SIG_DFL); #endif if (my_rdb.start_props) { fprintf(stderr, nl_msg(NL_HTT_PROPS_STILL_RUNNING, "iiimx : Warning - htt_props is still running use htt_props to kill this server ...\n") ); #ifdef SunOS sigset(SIGINT, (void (*) (int)) clean_up); #else signal(SIGINT, (void (*) (int)) clean_up); #endif return; } /* * Change server_pid to zero, signal handler sense it that is handled * by htt */ htt_server_killed = 1; Server_Status = RmServerKilled; kill(htt_server_pid, SIGTERM); if (my_rdb.start_props) kill(htt_props_pid, SIGTERM); if ((0 != sig) && (True == my_rdb.start_iiimd)) { kill(iiimd_pid, SIGTERM); } if ((0 != sig) && (True == my_rdb.start_iiim_panel)) { kill(iiim_panel_pid, SIGTERM); } if (0 != sig) { exit(1); } } void proc_exit(int unused) { pid_t pid; int wstat; for (;;) { pid = wait3(&wstat, WNOHANG, (struct rusage *) NULL); if (pid == 0) return; else if (pid == -1) return; else if ((pid == htt_server_pid) && (True == my_rdb.start_iiimd)) { if (WIFSTOPPED(wstat)) { fprintf(stderr, nl_msg(NL_IIIMD_SUSPENDED, "iiim-xbe has been suspended \n")); } else { start_htt_server(&htt_server_pid, htt_server_arg); } } else if (pid == htt_server_pid) { if (WIFSTOPPED(wstat)) { fprintf(stderr, nl_msg(NL_HTT_SUSPENDED, "iiim-xbe has been suspended \n") ); } else if (WIFEXITED(wstat)) { switch (Server_Status) { case RmServerKilled: if (my_rdb.start_props) kill(htt_props_pid, SIGTERM); exit(1); break; /* Not so useful */ case RmServerReset: /* * Don't worry abt it. Watchdog wants * to reset htt_server */ break; case RmServerActive: fprintf(stderr, nl_msg(NL_HTT_SERVER_EXITED_UNKNOWN, "iiimx : Warning - iiim-xbe has been terminated without knowledge of iiimx , restart iiimx again\n")); if (my_rdb.start_props) kill(htt_props_pid, SIGTERM); exit(0); break; /* Not so usefule */ } #if 0 fprintf(stderr, nl_msg(NL_HTT_SERVER_DIED, "htt : Warning - htt_server died and recovered\n")); start_htt_server(&htt_server_pid, htt_server_arg); #endif } else if (WIFSIGNALED(wstat)) { switch (WTERMSIG(wstat)) { case SIGTERM: case SIGKILL: /* there must be a reason */ if (!htt_server_killed) { /* * 4049423: In zh_TW.BIG5 and * ja_JP.PCK, htt prints * message in garbage when it * exits * * fprintf(stderr, * nl_msg(NL_HTT_SERVER_EXITED * , "htt : htt_server has * been terminated\n") ); */ if (my_rdb.start_props) kill(htt_props_pid, SIGTERM); exit(0); } htt_server_killed = 0; break; case SIGQUIT: case SIGILL: #ifndef linux case SIGEMT: #endif case SIGSEGV: case SIGFPE: case SIGTRAP: case SIGBUS: #ifndef linux case SIGSYS: #endif case SIGIOT: fprintf(stderr, nl_msg(NL_HTT_SERVER_DIED, "iiimx : Warning - iiim-xbe died and recovered\n") ); start_htt_server(&htt_server_pid, htt_server_arg); break; default: fprintf(stderr, nl_msg(NL_HTT_SERVER_DIED_UNKNOWN, "iiimx : Error - iiim-xbe died. Don't know how to recover\n") ); if (my_rdb.start_props) kill(htt_props_pid, SIGTERM); exit(1); } } } else if (pid == iiimd_pid) { #if 1 /* * As iiimd life cycle is not well defined, it is hard for * now to implement restart feature properly. So is the * tentative solution. When iiimd is re-factored, this * issue will be revisited. */ if (WIFSTOPPED(wstat)) { fprintf(stderr, nl_msg(NL_IIIMD_SUSPENDED, "iiimd has been suspended \n")); } else { start_iiimd(&iiimd_pid, iiimd_arg); } #else /* !1 */ if (WIFSTOPPED(wstat)) { fprintf(stderr, nl_msg(NL_IIIMD_SUSPENDED, "iiimd has been suspended \n") ); } else if (WIFEXITED(wstat)) { kill(htt_server_pid, SIGTERM); exit(0); } else if (WIFSIGNALED(wstat)) { switch (WTERMSIG(wstat)) { case SIGTERM: case SIGKILL: /* there must be a reason */ kill(htt_server_pid, SIGTERM); exit(0); break; case SIGQUIT: case SIGILL: #ifndef linux case SIGEMT: #endif case SIGSEGV: case SIGFPE: case SIGTRAP: case SIGBUS: #ifndef linux case SIGSYS: #endif case SIGIOT: fprintf(stderr, nl_msg(NL_IIIMD_DIED, "iiimx : Warning - iiimd died and recovered\n") ); kill(htt_server_pid, SIGTERM); start_iiimd(&iiimd_pid, iiimd_arg); start_htt_server(&htt_server_pid, htt_server_arg); break; default: fprintf(stderr, nl_msg(NL_IIIMD_DIED_UNKNOWN, "iiimx : Error - iiimd died. Don't know how to recover\n") ); kill(htt_server_pid, SIGTERM); exit(1); } } #endif /* !1 */ } else if ((my_rdb.start_props) && (pid == htt_props_pid)) { /* * printf("watchdog: htt_props has died, do * something?\n"); */ } else if ((my_rdb.start_xsettings_init) && (pid == xsettings_init_pid)) { /* nothing to do here */ } else if (pid == iiim_panel_pid) { if (WIFSTOPPED(wstat)) { fprintf(stderr, nl_msg(NL_IIIM_PANEL_SUSPENDED, "iiim-panel has been suspended \n") ); } else if (WIFSIGNALED(wstat)) { switch (WTERMSIG(wstat)) { #ifndef linux case SIGEMT: case SIGSYS: #endif case SIGQUIT: case SIGILL: case SIGSEGV: case SIGFPE: case SIGTRAP: case SIGBUS: case SIGIOT: /* if it's coredumped, restart it */ start_iiim_panel (&iiim_panel_pid); break; } } } } } int check_openwin_path(char *prg, char *oppath, char *result) { static char suffix[]="/bin/"; int req; if (!oppath) return 0; req = strlen(prg) + sizeof(suffix) + 1; if (oppath && ((strlen(oppath) + sizeof (suffix) + req) < MAXNAMELEN)) { strcpy(result, oppath); strcat(result, suffix); strcat(result, prg); if (access(result, X_OK) == 0) return 1; } return 0; } /* If the path in OPENWIN, return 1. */ #define OPENWIN_PATH 1 int search_program(char *prg, char *path) { char *basepath; if (check_openwin_path(prg, getenv("OPENWINHOME"), path)) return OPENWIN_PATH; if (check_openwin_path(prg, OPENWINHOME, path)) return OPENWIN_PATH; basepath = IMDIR; if (basepath && ((strlen(basepath) + strlen(prg) + 2) < MAXNAMELEN)) { strcpy(path, basepath); strcat(path, "/"); strcat(path, prg); if (access(path, X_OK) == 0) return 0; } return -1; } void start_htt_server(htt_server_pid, argv) long *htt_server_pid; char *argv[]; { char pathname[MAXNAMELEN]; extern int errno; int pid; int flag; flag = search_program(my_rdb.htt_server_name, pathname); if (flag < 0) { perror("iiim-xbe not found\n"); return; } pid = (*htt_server_pid) = fork(); switch (*htt_server_pid) { case -1: perror("watchdog:fork\n"); exit(errno); case 0: /* * Note: Forked process sleeps for one second (roughly) in * order to allow htt to update PID property. It should work * most of the cases */ sleep(1); #ifdef SETPGRP_VOID setpgrp(); #else setpgrp(0, 0); #endif #ifdef SunOS if (flag == OPENWIN_PATH) { putenv(OPENWIN_MOTIF_PRELOAD_ENV); } #endif execv(pathname, argv); perror("execv iiim-xbe failed\n"); } Server_Status = RmServerActive; } void start_htt_props(htt_props_pid, argv) long *htt_props_pid; char *argv[]; { char pathname[MAXNAMELEN]; extern int errno; if (search_program(htt_props_path, pathname) < 0) { perror("htt_props not found\n"); return; } *htt_props_pid = fork(); switch (*htt_props_pid) { case -1: perror("watchdog:fork\n"); exit(errno); case 0: setpgrp(); if (!my_rdb.respond_to_sm) sleep(10); execv(pathname, argv); perror("execv htt_props failed\n"); } } /* * wait_iiimd_ready(): hack to serialize iiimd and iiim-xbe. */ void wait_iiimd_ready(const char * uds_filename, time_t timeout) { IIIMF_status st; IIIMF_stream * stream_ret; time_t time_start; void * handle; IIIMF_status (* connect_function)(const char *, const char *, int, IIIMF_stream **); IIIMF_status (* disconnect_function)(IIIMF_stream *); handle = dlopen("libiiimp.so", RTLD_LAZY); if (NULL == handle) return; connect_function = (IIIMF_status (*)(const char *, const char *, int, IIIMF_stream **)) dlsym(handle, "iiimf_connect_socket_stream"); disconnect_function = (IIIMF_status (*)(IIIMF_stream *)) dlsym(handle, "iiimf_delete_socket_stream"); if ((NULL == connect_function) || (NULL == disconnect_function)) { dlclose(handle); return; } time_start = time(NULL); do { st = connect_function(uds_filename, NULL, 0, &stream_ret); if (IIIMF_STATUS_SUCCESS == st) { disconnect_function(stream_ret); break; } sleep(1); } while (time(NULL) < (time_start + timeout)); dlclose(handle); } void start_iiimd(iiimd_pid, argv) pid_t * iiimd_pid; char ** argv; { char * pathname; extern int errno; pid_t pid; pathname = "/usr/bin/iiimd"; pid = (*iiimd_pid) = fork(); switch (*iiimd_pid) { case -1: perror("watchdog:fork\n"); exit(errno); case 0: #ifdef SETPGRP_VOID setpgrp(); #else setpgrp(0, 0); #endif execv(pathname, argv); perror("execv iiimd failed\n"); } } void start_xsettings_init(xsettings_init_pid) pid_t * xsettings_init_pid; { char * pathname; extern int errno; pid_t pid; char * argv[2]; argv[0] = "iiimx-settings-init"; argv[1] = NULL; pathname = "/usr/lib/iiim/iiimx-settings-init"; if (0 != access(pathname, X_OK)) return; pid = (*xsettings_init_pid) = fork(); switch (*xsettings_init_pid) { case -1: perror("watchdog:fork\n"); exit(errno); case 0: #ifdef SETPGRP_VOID setpgrp(); #else setpgrp(0, 0); #endif execv(pathname, argv); perror("execv iiim-xsettings-init failed\n"); exit(0); } } void start_iiim_panel(iiim_panel_pid) pid_t * iiim_panel_pid; { char * pathname; extern int errno; pid_t pid; char * argv[3]; argv[0] = "iiim-panel"; argv[1] = "--disable-crash-dialog"; argv[2] = NULL; pathname = "/usr/bin/iiim-panel"; if (0 != access(pathname, X_OK)) return; pid = (*iiim_panel_pid) = fork(); switch (*iiim_panel_pid) { case -1: perror("watchdog:fork\n"); exit(errno); case 0: #ifdef SETPGRP_VOID setpgrp(); #else setpgrp(0, 0); #endif execv(pathname, argv); perror("execv iiim-panel failed\n"); exit(0); } } void save_last_language_selection (const char * lang) { char * pathname; extern int errno; pid_t pid; char * argv[7]; argv[0] = "gconftool-2"; argv[1] = "-s"; argv[2] = "/desktop/input_methods/language_last_selection"; argv[3] = "-t"; argv[4] = "string"; argv[5] = lang; argv[6] = NULL; pathname = "/usr/bin/gconftool-2"; if (0 != access(pathname, X_OK)) return; pid = fork(); switch (pid) { case -1: perror("watchdog:fork\n"); exit(errno); case 0: #ifdef SETPGRP_VOID setpgrp(); #else setpgrp(0, 0); #endif execv(pathname, argv); perror("execv gconftool-2 failed\n"); exit(0); } } static Bool build_dir(const char * path, mode_t mode) { struct stat st; if (stat(path, &st) < 0) { if ((mkdir(path, mode) < 0) || (stat(path, &st) < 0)) { return False; } } if ((S_ISDIR(st.st_mode))) { return True; } else { return False; } } static char * build_uds_filename(Widget toplevel) { char * udsf; struct passwd * pw; pw = getpwuid(geteuid()); udsf = (char *)malloc(PATH_MAX); if ((NULL == pw) || (NULL == udsf)) { endpwent(); if (NULL != udsf) free(udsf); return NULL; } snprintf(udsf, PATH_MAX, "/tmp/.iiim-%s", pw->pw_name); if (False == build_dir(udsf, 0700)){ endpwent(); free(udsf); return NULL; } strncat(udsf, "/", PATH_MAX); strncat(udsf, DisplayString(XtDisplay(toplevel)), PATH_MAX); return udsf; #if 0 size_t len; get_home_dir(udsf); strncat(udsf, ".iiim", PATH_MAX); if (False == build_dir(udsf, 0777)){ free(udsf); return NULL; } strncat(udsf, "/run", PATH_MAX); if (False == build_dir(udsf, 0700)){ free(udsf); return NULL; } strncat(udsf, "/", PATH_MAX); len = strlen(udsf); get_host(udsf + len, PATH_MAX - len); strncat(udsf, "-", PATH_MAX); strncat(udsf, DisplayString(XtDisplay(toplevel)), PATH_MAX); return udsf; #endif /* 0 */ } static char * build_vardir_dirname(void) { char * vardir; vardir = (char *)malloc(PATH_MAX); if (NULL == vardir) { return NULL; } get_home_dir(vardir); strncat(vardir, ".iiim", PATH_MAX); if (False == build_dir(vardir, 0700)){ free(vardir); return NULL; } strncat(vardir, "/le", PATH_MAX); if (False == build_dir(vardir, 0700)){ free(vardir); return NULL; } return vardir; } static char ** build_iiimd_arg(char * udsf, char * vardir, char *level, char *facility) { char ** pargv; char ** p; pargv = (char **)malloc((sizeof (char *)) * (12)); p = pargv; *(p++) = "iiimd"; *(p++) = "-nodaemon"; *(p++) = "-desktop"; if (NULL != udsf) { *(p++) = "-udsfile"; *(p++) = udsf; } if (NULL != vardir) { *(p++) = "-vardir"; *(p++) = vardir; } if (NULL != level) { *(p++) = "-log_level"; *(p++) = level; } if (NULL != facility) { *(p++) = "-log_facility"; *(p++) = facility; } *(p++) = NULL; return pargv; } static void usage(void) { printf( nl_msg(NL_HTT_USAGE_1, "usage:\n iiimx [-options ...]\n\nwhere options include:\n") ); printf( nl_msg(NL_HTT_USAGE_2, " -help print out this message\n") ); printf( nl_msg(NL_HTT_USAGE_3, " -display displayname X server to contact\n") ); printf( nl_msg(NL_HTT_USAGE_4, " -xrm file additional resource file\n") ); #if 0 printf( nl_msg(NL_HTT_USAGE_5, " -so server only\n") ); printf( nl_msg(NL_HTT_USAGE_5, " -sp start htt_props as well\n") ); printf( nl_msg(NL_HTT_USAGE_6, " -nosm do not respond to session manager\n") ); #endif printf( nl_msg(NL_HTT_USAGE_7, " -xim xim server name\n") ); } static void parse_command(int argc, char **argv) { int i; for (i = 1; i < argc; i++) { if (!strcmp(argv[i], "-help")) { usage(); exit(0); } } } static char* build_cmdline_db(Widget toplevel, char *argv[], int argc, Bool replace_mode) { char filenamebuf[PATH_MAX], *filename = filenamebuf; static XrmDatabase cmd_db; FILE *fd; char *type_return[20]; XrmValue val_return; char *lang = NULL; int count; int file_size; char *str_return; static XrmQuark RmQString; static XrmDatabase db; char **pargv; int pargc; Bool res_status; pargc = argc; pargv = (char **) Xmalloc(sizeof(char *) * pargc); for (count = 0; count < pargc; count++) { pargv[count] = Xmalloc(strlen(argv[count]) + 1); strcpy(pargv[count], argv[count]); } RmQString = XrmPermStringToQuark(XtRString); db = XtDatabase(XtDisplay(toplevel)); /* Create db from command line options */ XrmParseCommand(&cmd_db, rdb_options, NUM_RDB_OPTIONS, HTT_CLASS_NAME, &pargc, pargv); for (count = 0; count < pargc; count++) XFree(pargv[count]); Xfree(pargv); /* try to get locale of the program */ res_status = XrmGetResource(db, "iiimx*language", "Iiimx*Language", type_return, &val_return); if (res_status && (char *) val_return.addr) { int len = strlen((char *) val_return.addr); if (len) { char lang_env[256]; lang = Xmalloc(len + 1); strcpy(lang, (char *) val_return.addr); setlocale(LC_CTYPE, lang); strcpy(lang_env, "LC_CTYPE="); strcat(lang_env, lang); putenv(lang_env); } } else lang = setlocale(LC_CTYPE, ""); /* Add options from ~/.httdefaults */ get_home_dir(filename); strcat(filename, ".httdefaults"); XrmCombineFileDatabase(filename, &cmd_db, False); /* Add options from ~/.Xlocale//app-defaults/ */ get_home_dir(filename); strcat(filename, ".Xlocale/"); strcat(filename, lang); strcat(filename, "/app-defaults/"); strcat(filename, HTT_CLASS_NAME); XrmCombineFileDatabase(filename, &cmd_db, replace_mode); /* Generate an uniq file name */ strcpy(filename, "/tmp/HTTXXXXXX"); mkstemp(filename); #if 0 LOG1("resouce file name is %s\n", filename); #endif /* Store the database */ XrmPutFileDatabase(cmd_db, filename); /* If there is no resource the file is empty, or it is not created */ if ((fd = fopen(filename, "r"))) { /* File exists */ fseek(fd, 0, SEEK_END); file_size = ftell(fd); str_return = Xmalloc(file_size + 1); fseek(fd, 0, SEEK_SET); fread(str_return, file_size, 1, fd); str_return[file_size] = '\0'; fclose(fd); unlink(filename); } else { /* File doesn't exist so send empty resource */ str_return = Xmalloc(1); *str_return = '\0'; } return str_return; } static char* get_home_dir(char *buf) { static char *ptr = NULL; int len; if (ptr == NULL) { uid_t uid; struct passwd *pw; if (!(ptr = getenv("HOME"))) { if ((ptr = getenv("USER"))) { pw = getpwnam(ptr); } else { uid = getuid(); pw = getpwuid(uid); } if (pw) { ptr = pw->pw_dir; } else { ptr = NULL; *buf = '\0'; } } } if (ptr) { strcpy(buf, ptr); } len = strlen(buf); if (buf[len - 1] != '/') { buf[len] = '/'; buf[len + 1] = '\0'; } return buf; } static char * get_host(buf, max_len) char *buf; int max_len; { int len; struct utsname name; uname(&name); len = strlen(name.nodename); if (len >= max_len) { len = max_len - 1; } strncpy(buf, name.nodename, len); buf[len] = '\0'; return buf; } static unsigned char * client_group_get() { int fd; int c; int i; int r; unsigned char * p; char * f; unsigned char buf[16]; p = (unsigned char *)malloc((2 * (sizeof (buf))) + 1); if (NULL == p) { return NULL; } *(p + (2 * (sizeof (buf)))) = '\0'; f = "0123456789abcdef"; r = 0; fd = open("/dev/random", O_RDONLY, 0); if (0 <= fd) { r = read(fd, buf, (sizeof (buf))); close(fd); } if ((sizeof (buf)) != r) { srand(time(NULL) + getpid()); for (i = 0; i < (sizeof (buf)); i += 4) { c = rand(); memcpy(buf + i, &c, 4); } } for (i = 0; i < (sizeof (buf)); i++) { *(p + (2 * i) + 0) = *((unsigned char *)f + (*(buf + i) / 0x10)); *(p + (2 * i) + 1) = *((unsigned char *)f + (*(buf + i) % 0x10)); } return p; } static void start_daemon(const char *display_name) { Display * display; switch (fork()) { case 0: case -1: return; default: display = XOpenDisplay(display_name); if (NULL == display) _exit(0); if (False == wait_xbe_startup(display)) { sleep(5); } XCloseDisplay(display); _exit(0); } } static Bool wait_xbe_startup(Display * display) { char atom_name[ATOM_NAME_LEN_MAX]; Atom xbe_atom_l; Atom xbe_atom_lt; Atom xbe_atom_ltc; int i; XLCd lcd; char * language; char * territory; char * codeset; xbe_atom_l = None; xbe_atom_lt = None; xbe_atom_ltc = None; lcd = _XOpenLC((char *)NULL); _XGetLCValues(lcd, XlcNLanguage, &language, XlcNTerritory, &territory, XlcNCodeset, &codeset, NULL); if ((NULL == language) || ('\0' == *language)) { fprintf(stderr, nl_msg(NL_IIIMX_CANNOT_GET_LANGUAGE, "iiimx : Error - language is null\n")); return False; } if ((NULL == territory) || ('\0' == *territory)) { fprintf(stderr, nl_msg(NL_IIIMX_CANNOT_GET_TERRITORY, "iiimx : Error - territory is null\n")); return False; } if ((NULL == codeset) || ('\0' == *codeset)) { fprintf(stderr, nl_msg(NL_IIIMX_CANNOT_GET_CODESET, "iiimx : Error - codeset is null\n")); return False; } for (i = 0 ; i < MAX_NUM_TRY; i++) { sleep(1); if (None == xbe_atom_l) { snprintf(atom_name, ATOM_NAME_LEN_MAX, "_XIMP_%s@iiimx.%d", language, display->default_screen); xbe_atom_l = XInternAtom(display, atom_name, True); } if (None != xbe_atom_l) { if (None != XGetSelectionOwner(display, xbe_atom_l)) break; } if (None == xbe_atom_lt) { snprintf(atom_name, ATOM_NAME_LEN_MAX, "_XIMP_%s_%s@iiimx.%d", language, territory, display->default_screen); xbe_atom_lt = XInternAtom(display, atom_name, True); } if (None != xbe_atom_lt) { if (None != XGetSelectionOwner(display, xbe_atom_lt)) break; } if (None == xbe_atom_ltc) { snprintf(atom_name, ATOM_NAME_LEN_MAX, "_XIMP_%s_%s.%s@iiimx.%d", language, territory, codeset, display->default_screen); xbe_atom_ltc = XInternAtom(display, atom_name, True); } if (None != xbe_atom_ltc) { if (None != XGetSelectionOwner(display, xbe_atom_ltc)) break; } } if (MAX_NUM_TRY == i) { fprintf(stderr, nl_msg(NL_IIIMX_XINTERNATOM_XBE, "iiimx : Error - iiim-xbe is not started in %d seconds\n"), MAX_NUM_TRY); /* * do not return False because sleep(1) is already called * MAX_NUM_TRY times */ } return True; } static int x_io_error_handler(Display * display) { #ifdef SunOS sigset(SIGCHLD, SIG_DFL); #else signal(SIGCHLD, SIG_DFL); #endif clean_up(0); if (NULL != x_default_io_error_handler) { x_default_io_error_handler(display); } exit(1); }