/**************************************************************************/ /* */ /* Copyright (c) 2001, 2011 NoMachine, http://www.nomachine.com/. */ /* */ /* NXAGENT, NX protocol compression and NX extensions to this software */ /* are copyright of NoMachine. Redistribution and use of the present */ /* software is allowed according to terms specified in the file LICENSE */ /* which comes in the source distribution. */ /* */ /* Check http://www.nomachine.com/licensing.html for applicability. */ /* */ /* NX and NoMachine are trademarks of Medialogic S.p.A. */ /* */ /* All rights reserved. */ /* */ /**************************************************************************/ #include <stdio.h> #include <string.h> #include <signal.h> #include <errno.h> #include <sys/types.h> #include <sys/wait.h> #include "scrnintstr.h" #include "Agent.h" #include <nx-X11/Xlib.h> #include "opaque.h" #include "Args.h" #include "Display.h" #include "Dialog.h" #include <nx/NX.h> #include <nx/NXlib.h> #include <nx/NXalert.h> /* * Set here the required log level. */ #define PANIC #define WARNING #undef TEST #undef DEBUG int nxagentKillDialogPid = 0; int nxagentSuspendDialogPid = 0; int nxagentRootlessDialogPid = 0; int nxagentPulldownDialogPid = 0; int nxagentFontsReplacementDialogPid = 0; int nxagentEnableRandRModeDialogPid = 0; int nxagentDisableRandRModeDialogPid = 0; int nxagentEnableDeferModePid = 0; int nxagentDisableDeferModePid = 0; int nxagentDisableXkbPid = 0; static int nxagentFailedReconnectionDialogPid = 0; char nxagentPulldownWindow[16]; char nxagentFailedReconnectionMessage[256]; void nxagentResetDialog(int pid) { if (pid == nxagentRootlessDialogPid) { #ifdef TEST fprintf(stderr, "nxagentResetDialog: Resetting rootless dialog pid [%d].\n", nxagentRootlessDialogPid); #endif nxagentRootlessDialogPid = 0; } else if (pid == nxagentPulldownDialogPid) { #ifdef TEST fprintf(stderr, "nxagentResetDialog: Resetting pulldown dialog pid [%d].\n", nxagentPulldownDialogPid); #endif nxagentPulldownDialogPid = 0; } else if (pid == nxagentFontsReplacementDialogPid) { #ifdef TEST fprintf(stderr, "nxagentFontsReplacementDialog: Resetting fonts replacement dialog pid [%d].\n", nxagentFontsReplacementDialogPid); #endif nxagentFontsReplacementDialogPid = 0; } else if (pid == nxagentKillDialogPid) { #ifdef TEST fprintf(stderr, "nxagentResetDialog: Resetting kill dialog pid [%d].\n", nxagentKillDialogPid); #endif nxagentKillDialogPid = 0; } else if (pid == nxagentSuspendDialogPid) { #ifdef TEST fprintf(stderr, "nxagentResetDialog: Resetting suspend dialog pid [%d].\n", nxagentSuspendDialogPid); #endif nxagentSuspendDialogPid = 0; } else if (pid == nxagentFailedReconnectionDialogPid) { #ifdef TEST fprintf(stderr, "nxagentResetDialog: Resetting Failed Reconnection dialog pid [%d].\n", nxagentFailedReconnectionDialogPid); #endif nxagentFailedReconnectionDialogPid = 0; } else if (pid == nxagentEnableRandRModeDialogPid) { #ifdef TEST fprintf(stderr, "nxagentResetDialog: Resetting RandR mode dialog pid [%d].\n", nxagentEnableRandRModeDialogPid); #endif nxagentEnableRandRModeDialogPid = 0; } else if (pid == nxagentDisableRandRModeDialogPid) { #ifdef TEST fprintf(stderr, "nxagentResetDialog: Resetting NoRandR mode dialog pid [%d].\n", nxagentDisableRandRModeDialogPid); #endif nxagentDisableRandRModeDialogPid = 0; } else if (pid == nxagentEnableDeferModePid) { #ifdef TEST fprintf(stderr, "nxagentResetDialog: Resetting enable defer mode dialog pid [%d].\n", nxagentEnableDeferModePid); #endif nxagentEnableDeferModePid = 0; } else if (pid == nxagentDisableDeferModePid) { #ifdef TEST fprintf(stderr, "nxagentResetDialog: Resetting disable defer mode dialog pid [%d].\n", nxagentDisableDeferModePid); #endif nxagentDisableDeferModePid = 0; } else if (pid == nxagentDisableXkbPid) { #ifdef TEST fprintf(stderr, "nxagentResetDialog: Resetting disable XKB dialog pid [%d].\n", nxagentDisableXkbPid); #endif nxagentDisableXkbPid = 0; } } void nxagentLaunchDialog(DialogType dialogType) { char dialogDisplay[256]; sigset_t set, oldSet; int *pid; char *type; char *message; int local; const char *window = NULL; switch (dialogType) { case DIALOG_KILL_SESSION: { message = DIALOG_KILL_SESSION_MESSAGE; type = DIALOG_KILL_SESSION_TYPE; local = DIALOG_KILL_SESSION_LOCAL; pid = &nxagentKillDialogPid; break; } case DIALOG_SUSPEND_SESSION: { message = DIALOG_SUSPEND_SESSION_MESSAGE; type = DIALOG_SUSPEND_SESSION_TYPE; local = DIALOG_SUSPEND_SESSION_LOCAL; pid = &nxagentSuspendDialogPid; break; } case DIALOG_ROOTLESS: { message = DIALOG_ROOTLESS_MESSAGE; type = DIALOG_ROOTLESS_TYPE; local = DIALOG_ROOTLESS_LOCAL; pid = &nxagentRootlessDialogPid; break; } case DIALOG_PULLDOWN: { message = DIALOG_PULLDOWN_MESSAGE; type = DIALOG_PULLDOWN_TYPE; local = DIALOG_PULLDOWN_LOCAL; pid = &nxagentPulldownDialogPid; window = nxagentPulldownWindow; break; } case DIALOG_FONT_REPLACEMENT: { message = DIALOG_FONT_REPLACEMENT_MESSAGE; type = DIALOG_FONT_REPLACEMENT_TYPE; local = DIALOG_FONT_REPLACEMENT_LOCAL; pid = &nxagentFontsReplacementDialogPid; break; } case DIALOG_FAILED_RECONNECTION: { message = DIALOG_FAILED_RECONNECTION_MESSAGE; type = DIALOG_FAILED_RECONNECTION_TYPE; local = DIALOG_FAILED_RECONNECTION_LOCAL; pid = &nxagentFailedReconnectionDialogPid; break; } case DIALOG_ENABLE_DESKTOP_RESIZE_MODE: { message = DIALOG_ENABLE_DESKTOP_RESIZE_MODE_MESSAGE; type = DIALOG_ENABLE_DESKTOP_RESIZE_MODE_TYPE; local = DIALOG_ENABLE_DESKTOP_RESIZE_MODE_LOCAL; pid = &nxagentEnableRandRModeDialogPid; break; } case DIALOG_DISABLE_DESKTOP_RESIZE_MODE: { message = DIALOG_DISABLE_DESKTOP_RESIZE_MODE_MESSAGE; type = DIALOG_DISABLE_DESKTOP_RESIZE_MODE_TYPE; local = DIALOG_DISABLE_DESKTOP_RESIZE_MODE_LOCAL; pid = &nxagentDisableRandRModeDialogPid; break; } case DIALOG_ENABLE_DEFER_MODE: { message = DIALOG_ENABLE_DEFER_MODE_MESSAGE; type = DIALOG_ENABLE_DEFER_MODE_TYPE; local = DIALOG_ENABLE_DEFER_MODE_LOCAL; pid = &nxagentEnableDeferModePid; break; } case DIALOG_DISABLE_DEFER_MODE: { message = DIALOG_DISABLE_DEFER_MODE_MESSAGE; type = DIALOG_DISABLE_DEFER_MODE_TYPE; local = DIALOG_DISABLE_DEFER_MODE_LOCAL; pid = &nxagentDisableDeferModePid; break; } case DIALOG_DISABLE_XKB: { message = DIALOG_DISABLE_XKB_MESSAGE; type = DIALOG_DISABLE_XKB_TYPE; local = DIALOG_DISABLE_XKB_LOCAL; pid = &nxagentDisableXkbPid; break; } default: { #ifdef WARNING fprintf(stderr, "nxagentLaunchDialog: Unknown Dialog type [%d].\n", dialogType); #endif return; } } #ifdef TEST fprintf(stderr, "nxagentLaunchDialog: Launching dialog type [%d] message [%s].\n", type, message); #endif if (dialogType == DIALOG_FAILED_RECONNECTION) { strncpy(dialogDisplay, nxagentDisplayName, 255); } else { strcpy(dialogDisplay, ":"); strncat(dialogDisplay, display, 254); } *(dialogDisplay + 255) = '\0'; /* * We don't want to receive SIGCHLD * before we store the child pid. */ sigemptyset(&set); sigaddset(&set, SIGCHLD); sigprocmask(SIG_BLOCK, &set, &oldSet); *pid = NXTransDialog(nxagentDialogName, message, window, type, local, dialogDisplay); #ifdef TEST fprintf(stderr, "nxagentLaunchDialog: Launched dialog %s with pid [%d] on display %s.\n", DECODE_DIALOG_TYPE(dialogType), *pid, dialogDisplay); #endif *dialogDisplay = '\0'; /* * Restore the previous set of * blocked signal. */ sigprocmask(SIG_SETMASK, &oldSet, NULL); } void nxagentPulldownDialog(Window wid) { snprintf(nxagentPulldownWindow, 15, "%ld", (long int) wid); nxagentPulldownWindow[15] = 0; #ifdef TEST fprintf(stderr, "nxagentPulldownDialog: Going to launch pulldown " "dialog on window [%s].\n", nxagentPulldownWindow); #endif nxagentLaunchDialog(DIALOG_PULLDOWN); nxagentPulldownWindow[0] = 0; } void nxagentFailedReconnectionDialog(int alert, char *error) { if (alert == 0) { #ifdef WARNING fprintf(stderr, "nxagentFailedReconnectionDialog: WARNING! No valid alert provided. " "Using the default.\n"); #endif alert = FAILED_RESUME_DISPLAY_ALERT; } if (NXDisplayError(nxagentDisplay) == 0 && NXTransRunning(NX_FD_ANY) == 1) { NXTransAlert(alert, NX_ALERT_REMOTE); /* * Make it possible to interrupt the * loop with a signal. */ while (NXDisplayError(nxagentDisplay) == 0 && NXTransRunning(NX_FD_ANY) == 1) { struct timeval timeout; timeout.tv_sec = 30; timeout.tv_usec = 0; NXTransContinue(&timeout); } } else { int pid; int status; int options = 0; snprintf(nxagentFailedReconnectionMessage, 255, "Reconnection failed: %s", error); *(nxagentFailedReconnectionMessage + 255) = '\0'; nxagentLaunchDialog(DIALOG_FAILED_RECONNECTION); while ((pid = waitpid(nxagentFailedReconnectionDialogPid, &status, options)) == -1 && errno == EINTR); if (pid == -1) { if (errno == ECHILD) { #ifdef WARNING fprintf(stderr, "nxagentFailedReconnectionDialog: Got ECHILD waiting for child [%d].\n", nxagentFailedReconnectionDialogPid); #endif nxagentFailedReconnectionDialogPid = 0; } else { fprintf(stderr, "nxagentFailedReconnectionDialog: PANIC! Got unexpected error [%s] waiting " "for child [%d].\n", strerror(errno), nxagentFailedReconnectionDialogPid); } } else if (pid > 0) { if (WIFSTOPPED(status)) { #ifdef WARNING fprintf(stderr, "nxagentFailedReconnectionDialog: Child process [%d] was stopped " "with signal [%d].\n", pid, (WSTOPSIG(status))); #endif } else { #ifdef WARNING if (WIFEXITED(status)) { fprintf(stderr, "nxagentFailedReconnectionDialog: Child process [%d] exited " "with status [%d].\n", pid, (WEXITSTATUS(status))); } else if (WIFSIGNALED(status)) { fprintf(stderr, "nxagentFailedReconnectionDialog: Child process [%d] died " "because of signal [%d].\n", pid, (WTERMSIG(status))); } #endif nxagentResetDialog(pid); } } #ifdef WARNING else if (pid == 0) { fprintf(stderr, "nxagentFailedReconnectionDialog: No own child process exited.\n"); } #endif } } void nxagentTerminateDialog(DialogType type) { int pid; switch (type) { case DIALOG_KILL_SESSION: { pid = nxagentKillDialogPid; break; } case DIALOG_SUSPEND_SESSION: { pid = nxagentSuspendDialogPid; break; } case DIALOG_ROOTLESS: { pid = nxagentRootlessDialogPid; break; } case DIALOG_PULLDOWN: { pid = nxagentPulldownDialogPid; break; } case DIALOG_FONT_REPLACEMENT: { pid = nxagentFontsReplacementDialogPid; break; } case DIALOG_FAILED_RECONNECTION: { pid = nxagentFailedReconnectionDialogPid; break; } case DIALOG_ENABLE_DESKTOP_RESIZE_MODE: { pid = nxagentEnableRandRModeDialogPid; break; } case DIALOG_DISABLE_DESKTOP_RESIZE_MODE: { pid = nxagentDisableRandRModeDialogPid; break; } case DIALOG_ENABLE_DEFER_MODE: { pid = nxagentEnableDeferModePid; break; } case DIALOG_DISABLE_DEFER_MODE: { pid = nxagentDisableDeferModePid; break; } case DIALOG_DISABLE_XKB: { pid = nxagentDisableXkbPid; break; } default: { #ifdef WARNING fprintf(stderr, "nxagentTerminateDialog: Unknown dialog type [%d].\n", type); #endif return; } } if (pid > 0) { if (kill(pid, SIGTERM) == -1) { #ifdef WARNING fprintf(stderr, "nxagentTerminateDialog: Failed to terminate dialog pid [%d]: %s.\n", pid, strerror(errno)); #endif } } #ifdef DEBUG else { fprintf(stderr, "nxagentTerminateDialog: Dialog type [%d] is not running.\n", type); } #endif } void nxagentTerminateDialogs() { DialogType type; #ifdef DEBUG fprintf(stderr, "nxagentTerminateDialogs: Terminating all the running dialogs.\n"); #endif for (type = DIALOG_FIRST_TAG; type < DIALOG_LAST_TAG; type++) { nxagentTerminateDialog(type); } }