summaryrefslogtreecommitdiffstats
path: root/redhat/tdebase/kdebase-3.5.13-tsak_keyboard_hotplug.patch
diff options
context:
space:
mode:
Diffstat (limited to 'redhat/tdebase/kdebase-3.5.13-tsak_keyboard_hotplug.patch')
-rw-r--r--redhat/tdebase/kdebase-3.5.13-tsak_keyboard_hotplug.patch641
1 files changed, 0 insertions, 641 deletions
diff --git a/redhat/tdebase/kdebase-3.5.13-tsak_keyboard_hotplug.patch b/redhat/tdebase/kdebase-3.5.13-tsak_keyboard_hotplug.patch
deleted file mode 100644
index 8c8ab415f..000000000
--- a/redhat/tdebase/kdebase-3.5.13-tsak_keyboard_hotplug.patch
+++ /dev/null
@@ -1,641 +0,0 @@
-commit 5f413b26ebaab8a6478427e4125bda628058ff85
-Author: Timothy Pearson <kb9vqf@pearsoncomputing.net>
-Date: 1327015159 -0600
-
- Add keyboard hotplug (add/remove) support to tsak
- This closes Bug 587
- Fix warning in kompmgr
-
-diff --git a/tsak/CMakeLists.txt b/tsak/CMakeLists.txt
-index 6aa5b49..4490636 100644
---- a/tsak/CMakeLists.txt
-+++ b/tsak/CMakeLists.txt
-@@ -23,5 +23,6 @@ link_directories(
-
- tde_add_executable( tsak
- SOURCES main.cpp
-+ LINK udev
- DESTINATION ${BIN_INSTALL_DIR}
- )
-diff --git a/tsak/main.cpp b/tsak/main.cpp
-index 050d6c0..df485a0 100644
---- a/tsak/main.cpp
-+++ b/tsak/main.cpp
-@@ -1,8 +1,8 @@
- /*
- Copyright 2010 Adam Marchetti
--Copyright 2011 Timothy Pearson <kb9vqf@pearsoncomputing.net>
-+Copyright 2011-2012 Timothy Pearson <kb9vqf@pearsoncomputing.net>
-
--This file is part of tsak.
-+This file is part of tsak, the TDE Secure Attention Key daemon
-
- tsak is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as
-@@ -35,9 +35,15 @@ License along with tsak. If not, see http://www.gnu.org/licenses/.
- #include <sys/time.h>
- #include <termios.h>
- #include <signal.h>
-+#include <libudev.h>
-+#include <libgen.h>
-
- #define FIFO_DIR "/tmp/ksocket-global"
- #define FIFO_FILE_OUT "/tmp/ksocket-global/tsak"
-+#define FIFO_LOCKFILE_OUT "/tmp/ksocket-global/tsak.lock"
-+
-+#define MAX_KEYBOARDS 64
-+#define MAX_INPUT_NODE 128
-
- #define TestBit(bit, array) (array[(bit) / 8] & (1 << ((bit) % 8)))
-
-@@ -46,9 +52,18 @@ typedef unsigned char byte;
- bool mPipeOpen_out = false;
- int mPipe_fd_out = -1;
-
-+int mPipe_lockfd_out = -1;
-+
-+char filename[32];
-+char key_bitmask[(KEY_MAX + 7) / 8];
-+
- struct sigaction usr_action;
- sigset_t block_mask;
-
-+int keyboard_fd_num;
-+int keyboard_fds[MAX_KEYBOARDS];
-+int child_pids[MAX_KEYBOARDS];
-+
- const char *keycode[256] =
- {
- "", "<esc>", "1", "2", "3", "4", "5", "6", "7", "8",
-@@ -79,6 +94,26 @@ int bit_set(size_t i, const byte* a)
- return a[i/CHAR_BIT] & (1 << i%CHAR_BIT);
- }
-
-+// --------------------------------------------------------------------------------------
-+// Useful function from Stack Overflow
-+// http://stackoverflow.com/questions/874134/find-if-string-endswith-another-string-in-c
-+// --------------------------------------------------------------------------------------
-+/* returns 1 iff str ends with suffix */
-+int str_ends_with(const char * str, const char * suffix) {
-+
-+ if( str == NULL || suffix == NULL )
-+ return 0;
-+
-+ size_t str_len = strlen(str);
-+ size_t suffix_len = strlen(suffix);
-+
-+ if(suffix_len > str_len)
-+ return 0;
-+
-+ return 0 == strncmp( str + str_len - suffix_len, suffix, suffix_len );
-+}
-+// --------------------------------------------------------------------------------------
-+
- /* Assign features (supported axes and keys) of the physical input device (devin)
- * to the virtual input device (devout) */
- static void copy_features(int devin, int devout)
-@@ -111,26 +146,40 @@ static void copy_features(int devin, int devout)
- }
- }
-
--int find_keyboard() {
-+int find_keyboards() {
- int i, j;
- int fd;
-- char filename[32];
-- char key_bitmask[(KEY_MAX + 7) / 8];
-+ char name[256] = "Unknown";
-+
-+ keyboard_fd_num = 0;
-+ for (i=0; i<MAX_KEYBOARDS; i++) {
-+ keyboard_fds[i] = 0;
-+ }
-
-- for (i=0; i<32; i++) {
-+ for (i=0; i<MAX_INPUT_NODE; i++) {
- snprintf(filename,sizeof(filename), "/dev/input/event%d", i);
--
-+
- fd = open(filename, O_RDWR|O_SYNC);
- ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(key_bitmask)), key_bitmask);
--
-- /* We assume that anything that has an alphabetic key in the
-- QWERTYUIOP range in it is the main keyboard. */
-- for (j = KEY_Q; j <= KEY_P; j++) {
-- if (TestBit(j, key_bitmask))
-- return fd;
-+
-+ // Ensure that we do not detect our own tsak faked keyboards
-+ ioctl (fd, EVIOCGNAME (sizeof (name)), name);
-+ if (str_ends_with(name, "+tsak") == 0) {
-+ /* We assume that anything that has an alphabetic key in the
-+ QWERTYUIOP range in it is the main keyboard. */
-+ for (j = KEY_Q; j <= KEY_P; j++) {
-+ if (TestBit(j, key_bitmask)) {
-+ keyboard_fds[keyboard_fd_num] = fd;
-+ }
-+ }
-+ }
-+
-+ if (keyboard_fds[keyboard_fd_num] == 0) {
-+ close (fd);
-+ }
-+ else {
-+ keyboard_fd_num++;
- }
--
-- close (fd);
- }
- return 0;
- }
-@@ -144,6 +193,12 @@ void tearDownPipe()
- }
- }
-
-+void tearDownLockingPipe()
-+{
-+ close(mPipe_lockfd_out);
-+ unlink(FIFO_LOCKFILE_OUT);
-+}
-+
- bool setFileLock(int fd, bool close_on_failure)
- {
- struct flock fl;
-@@ -154,8 +209,8 @@ bool setFileLock(int fd, bool close_on_failure)
- fl.l_len = 1;
-
- // Set the exclusive file lock
-- if (fcntl(mPipe_fd_out, F_SETLK, &fl) == -1) {
-- close(mPipe_fd_out);
-+ if (fcntl(fd, F_SETLK, &fl) == -1) {
-+ close(fd);
- return false;
- }
-
-@@ -171,7 +226,7 @@ bool checkFileLock()
- fl.l_whence = SEEK_SET;
- fl.l_len = 0;
-
-- int fd = open(FIFO_FILE_OUT, O_RDWR | O_NONBLOCK);
-+ int fd = open(FIFO_LOCKFILE_OUT, O_RDWR | O_NONBLOCK);
- fcntl(fd, F_GETLK, &fl); /* Overwrites lock structure with preventors. */
-
- if (fd > -1) {
-@@ -202,6 +257,71 @@ bool setupPipe()
- return setFileLock(mPipe_fd_out, true);
- }
-
-+bool setupLockingPipe()
-+{
-+ /* Create the FIFOs if they do not exist */
-+ umask(0);
-+ mkdir(FIFO_DIR,0644);
-+
-+ mknod(FIFO_LOCKFILE_OUT, S_IFIFO|0600, 0);
-+ chmod(FIFO_LOCKFILE_OUT, 0600);
-+
-+ mPipe_lockfd_out = open(FIFO_LOCKFILE_OUT, O_RDWR | O_NONBLOCK);
-+ if (mPipe_lockfd_out > -1) {
-+ // Set the exclusive file lock
-+ return setFileLock(mPipe_lockfd_out, true);
-+ }
-+
-+ return false;
-+}
-+
-+void broadcast_sak()
-+{
-+ // Let anyone listening to our interface know that an SAK keypress was received
-+ // I highly doubt there are more than 255 VTs active at once...
-+ int i;
-+ for (i=0;i<255;i++) {
-+ write(mPipe_fd_out, "SAK\n\r", 6);
-+ }
-+}
-+
-+void restart_tsak()
-+{
-+ int i;
-+
-+ fprintf(stderr, "Forcibly terminating...\n");
-+
-+ // Close down all child processes
-+ for (i=0; i<MAX_KEYBOARDS; i++) {
-+ if (child_pids[i] != 0) {
-+ kill(child_pids[i], SIGKILL);
-+ }
-+ }
-+
-+ // Wait for process termination
-+ sleep(1);
-+
-+ // Release all exclusive keyboard locks
-+ for (int current_keyboard=0;current_keyboard<keyboard_fd_num;current_keyboard++) {
-+ if(ioctl(keyboard_fds[current_keyboard], EVIOCGRAB, 0) < 0) {
-+ fprintf(stderr, "Failed to release exclusive input device lock");
-+ }
-+ close(keyboard_fds[current_keyboard]);
-+ }
-+
-+#if 1
-+ // Restart now
-+ // Note that the execl function never returns
-+ char me[2048];
-+ int chars = readlink("/proc/self/exe", me, sizeof(me));
-+ me[chars] = 0;
-+ me[2047] = 0;
-+ execl(me, basename(me), (char*)NULL);
-+#else
-+ _exit(0);
-+#endif
-+}
-+
- class PipeHandler
- {
- public:
-@@ -215,7 +335,7 @@ PipeHandler::PipeHandler()
-
- PipeHandler::~PipeHandler()
- {
-- tearDownPipe();
-+ tearDownLockingPipe();
- }
-
- int main (int argc, char *argv[])
-@@ -223,13 +343,19 @@ int main (int argc, char *argv[])
- struct input_event ev[64];
- struct input_event event;
- struct uinput_user_dev devinfo={0};
-- int fd, devout, rd, value, size = sizeof (struct input_event);
-+ int devout[MAX_KEYBOARDS], rd, i, value, size = sizeof (struct input_event);
- char name[256] = "Unknown";
- bool ctrl_down = false;
- bool alt_down = false;
- bool hide_event = false;
- bool established = false;
- bool testrun = false;
-+ int current_keyboard;
-+ bool can_proceed;
-+
-+ for (i=0; i<MAX_KEYBOARDS; i++) {
-+ child_pids[i] = 0;
-+ }
-
- if (argc == 2) {
- if (strcmp(argv[1], "checkactive") == 0) {
-@@ -239,7 +365,11 @@ int main (int argc, char *argv[])
-
- // Check for existing file locks
- if (!checkFileLock()) {
-- fprintf(stderr, "Another instance of this program is already running\n");
-+ fprintf(stderr, "Another instance of this program is already running [1]\n");
-+ return 8;
-+ }
-+ if (!setupLockingPipe()) {
-+ fprintf(stderr, "Another instance of this program is already running [2]\n");
- return 8;
- }
-
-@@ -256,125 +386,227 @@ int main (int argc, char *argv[])
- return 5;
- }
-
-- // Open Device
-- fd = find_keyboard();
-- if (fd == -1) {
-- printf ("Could not find your keyboard!\n");
-+ // Find keyboards
-+ find_keyboards();
-+ if (keyboard_fd_num == 0) {
-+ printf ("Could not find any usable keyboard(s)!\n");
-+ // Make sure everyone knows we physically can't detect a SAK
-+ // Before we do this we broadcast one so that active dialogs are updated appropriately
-+ // Also, we keep watching for a keyboard to be added via a forked child process...
-+ broadcast_sak();
- if (established)
- sleep(1);
-- else
-- return 4;
-+ else {
-+ int i=fork();
-+ if (i<0) return 12; // fork failed
-+ if (i>0) {
-+ return 4;
-+ }
-+ sleep(1);
-+ restart_tsak();
-+ }
- }
- else {
-- // Print Device Name
-- ioctl (fd, EVIOCGNAME (sizeof (name)), name);
-- fprintf(stderr, "Reading From : (%s)\n", name);
--
-- // Create filtered virtual output device
-- devout=open("/dev/misc/uinput",O_WRONLY|O_NONBLOCK);
-- if (devout<0) {
-- perror("open(\"/dev/misc/uinput\")");
-- devout=open("/dev/uinput",O_WRONLY|O_NONBLOCK);
-- }
-- if (devout<0) {
-- fprintf(stderr,"Unable to open /dev/uinput or /dev/misc/uinput (char device 10:223).\nPossible causes:\n 1) Device node does not exist\n 2) Kernel not compiled with evdev [INPUT_EVDEV] and uinput [INPUT_UINPUT] user level driver support\n 3) Permission denied.\n");
-- perror("open(\"/dev/uinput\")");
-- if (established)
-- sleep(1);
-- else
-- return 3;
-- }
-- else {
-- if(ioctl(fd, EVIOCGRAB, 2) < 0) {
-- close(fd);
-- fprintf(stderr, "Failed to grab exclusive input device lock");
-+ fprintf(stderr, "Found %d keyboard(s)\n", keyboard_fd_num);
-+
-+ can_proceed = true;
-+ for (current_keyboard=0;current_keyboard<keyboard_fd_num;current_keyboard++) {
-+ // Print Device Name
-+ ioctl (keyboard_fds[current_keyboard], EVIOCGNAME (sizeof (name)), name);
-+ fprintf(stderr, "Reading from keyboard: (%s)\n", name);
-+
-+ // Create filtered virtual output device
-+ devout[current_keyboard]=open("/dev/misc/uinput",O_WRONLY|O_NONBLOCK);
-+ if (devout[current_keyboard]<0) {
-+ devout[current_keyboard]=open("/dev/uinput",O_WRONLY|O_NONBLOCK);
-+ if (devout[current_keyboard]<0) {
-+ perror("open(\"/dev/misc/uinput\")");
-+ }
-+ }
-+ if (devout[current_keyboard]<0) {
-+ can_proceed = false;
-+ fprintf(stderr, "Unable to open /dev/uinput or /dev/misc/uinput (char device 10:223).\nPossible causes:\n 1) Device node does not exist\n 2) Kernel not compiled with evdev [INPUT_EVDEV] and uinput [INPUT_UINPUT] user level driver support\n 3) Permission denied.\n");
-+ perror("open(\"/dev/uinput\")");
- if (established)
- sleep(1);
- else
-- return 1;
-+ return 3;
- }
-- else {
-- ioctl(fd, EVIOCGNAME(UINPUT_MAX_NAME_SIZE), devinfo.name);
-- strncat(devinfo.name, "+tsak", UINPUT_MAX_NAME_SIZE-1);
-- fprintf(stderr, "%s\n", devinfo.name);
-- ioctl(fd, EVIOCGID, &devinfo.id);
--
-- copy_features(fd, devout);
-- write(devout,&devinfo,sizeof(devinfo));
-- if (ioctl(devout,UI_DEV_CREATE)<0) {
-- fprintf(stderr,"Unable to create input device with UI_DEV_CREATE\n");
-+ }
-+
-+ if (can_proceed == true) {
-+ for (current_keyboard=0;current_keyboard<keyboard_fd_num;current_keyboard++) {
-+ if(ioctl(keyboard_fds[current_keyboard], EVIOCGRAB, 2) < 0) {
-+ close(keyboard_fds[current_keyboard]);
-+ fprintf(stderr, "Failed to grab exclusive input device lock");
- if (established)
- sleep(1);
- else
-- return 2;
-+ return 1;
- }
- else {
-- fprintf(stderr,"Device created.\n");
--
-- if (established == false) {
-- tearDownPipe();
-- int i=fork();
-- if (i<0) return 9; // fork failed
-- if (i>0) {
-- // close parent process
-- close(mPipe_fd_out);
-- return 0;
-- }
-- setupPipe();
-+ ioctl(keyboard_fds[current_keyboard], EVIOCGNAME(UINPUT_MAX_NAME_SIZE), devinfo.name);
-+ strncat(devinfo.name, "+tsak", UINPUT_MAX_NAME_SIZE-1);
-+ fprintf(stderr, "%s\n", devinfo.name);
-+ ioctl(keyboard_fds[current_keyboard], EVIOCGID, &devinfo.id);
-+
-+ copy_features(keyboard_fds[current_keyboard], devout[current_keyboard]);
-+ write(devout[current_keyboard],&devinfo,sizeof(devinfo));
-+ if (ioctl(devout[current_keyboard],UI_DEV_CREATE)<0) {
-+ fprintf(stderr, "Unable to create input device with UI_DEV_CREATE\n");
-+ if (established)
-+ sleep(1);
-+ else
-+ return 2;
- }
--
-- established = true;
--
-- if (testrun == true) {
-- return 0;
-- }
--
-- while (1) {
-- if ((rd = read (fd, ev, size * 2)) < size) {
-- fprintf(stderr,"Read failed.\n");
-- break;
-- }
--
-- value = ev[0].value;
--
-- if (value != ' ' && ev[1].value == 0 && ev[1].type == 1){ // Read the key release event
-- if (keycode[(ev[1].code)]) {
-- if (strcmp(keycode[(ev[1].code)], "<control>") == 0) ctrl_down = false;
-- if (strcmp(keycode[(ev[1].code)], "<alt>") == 0) alt_down = false;
-+ else {
-+ fprintf(stderr, "Device created.\n");
-+
-+ if (established == false) {
-+ int i=fork();
-+ if (i<0) return 9; // fork failed
-+ if (i>0) {
-+ child_pids[current_keyboard] = i;
-+ continue;
- }
-+ setupLockingPipe();
- }
-- if (value != ' ' && ev[1].value == 1 && ev[1].type == 1){ // Read the key press event
-- if (keycode[(ev[1].code)]) {
-- if (strcmp(keycode[(ev[1].code)], "<control>") == 0) ctrl_down = true;
-- if (strcmp(keycode[(ev[1].code)], "<alt>") == 0) alt_down = true;
-- }
-+
-+ established = true;
-+
-+ if (testrun == true) {
-+ return 0;
- }
-
-- hide_event = false;
-- if (keycode[(ev[1].code)]) {
-- if (alt_down && ctrl_down && (strcmp(keycode[(ev[1].code)], "<del>") == 0)) {
-- hide_event = true;
-+ while (1) {
-+ if ((rd = read (keyboard_fds[current_keyboard], ev, size * 2)) < size) {
-+ fprintf(stderr, "Read failed.\n");
-+ break;
-+ }
-+
-+ value = ev[0].value;
-+
-+ if (value != ' ' && ev[1].value == 0 && ev[1].type == 1){ // Read the key release event
-+ if (keycode[(ev[1].code)]) {
-+ if (strcmp(keycode[(ev[1].code)], "<control>") == 0) ctrl_down = false;
-+ if (strcmp(keycode[(ev[1].code)], "<alt>") == 0) alt_down = false;
-+ }
-+ }
-+ if (value != ' ' && ev[1].value == 1 && ev[1].type == 1){ // Read the key press event
-+ if (keycode[(ev[1].code)]) {
-+ if (strcmp(keycode[(ev[1].code)], "<control>") == 0) ctrl_down = true;
-+ if (strcmp(keycode[(ev[1].code)], "<alt>") == 0) alt_down = true;
-+ }
-+ }
-+
-+ hide_event = false;
-+ if (keycode[(ev[1].code)]) {
-+ if (alt_down && ctrl_down && (strcmp(keycode[(ev[1].code)], "<del>") == 0)) {
-+ hide_event = true;
-+ }
-+ }
-+
-+ if (hide_event == false) {
-+ // Pass the event on...
-+ event = ev[0];
-+ write(devout[current_keyboard], &event, sizeof event);
-+ event = ev[1];
-+ write(devout[current_keyboard], &event, sizeof event);
-+ }
-+ if (hide_event == true) {
-+ // Let anyone listening to our interface know that an SAK keypress was received
-+ broadcast_sak();
- }
- }
-+ }
-+ }
-+ }
-+
-+ // fork udev monitor process
-+ int i=fork();
-+ if (i<0) return 10; // fork failed
-+ if (i>0) {
-+ // Terminate parent
-+ return 0;
-+ }
-+
-+ // Prevent multiple process instances from starting
-+ setupLockingPipe();
-+
-+ // Wait a little bit so that udev hotplug can stabilize before we start monitoring
-+ sleep(1);
-+
-+ fprintf(stderr, "Hotplug monitoring process started\n");
-+
-+ // Monitor for hotplugged keyboards
-+ int j;
-+ int hotplug_fd;
-+ bool is_new_keyboard;
-+ struct udev *udev;
-+ struct udev_device *dev;
-+ struct udev_monitor *mon;
-+
-+ // Create the udev object
-+ udev = udev_new();
-+ if (!udev) {
-+ fprintf(stderr, "Cannot connect to udev interface\n");
-+ return 11;
-+ }
-+
-+ // Set up a udev monitor to monitor input devices
-+ mon = udev_monitor_new_from_netlink(udev, "udev");
-+ udev_monitor_filter_add_match_subsystem_devtype(mon, "input", NULL);
-+ udev_monitor_enable_receiving(mon);
-+
-+ while (1) {
-+ // Watch for input from the monitoring process
-+ dev = udev_monitor_receive_device(mon);
-+ if (dev) {
-+ // If a keyboard was removed we need to restart...
-+ if (strcmp(udev_device_get_action(dev), "remove") == 0) {
-+ udev_device_unref(dev);
-+ udev_unref(udev);
-+ restart_tsak();
-+ }
-+
-+ is_new_keyboard = false;
-+ snprintf(filename,sizeof(filename), "%s", udev_device_get_devnode(dev));
-+ udev_device_unref(dev);
-+
-+ // Print name of keyboard
-+ hotplug_fd = open(filename, O_RDWR|O_SYNC);
-+ ioctl(hotplug_fd, EVIOCGBIT(EV_KEY, sizeof(key_bitmask)), key_bitmask);
-
-- if (hide_event == false) {
-- // Pass the event on...
-- event = ev[0];
-- write(devout, &event, sizeof event);
-- event = ev[1];
-- write(devout, &event, sizeof event);
-- }
-- if (hide_event == true) {
-- // Let anyone listening to our interface know that an SAK keypress was received
-- // I highly doubt there are more than 255 VTs active at once...
-- int i;
-- for (i=0;i<255;i++) {
-- write(mPipe_fd_out, "SAK\n\r", 6);
-- }
-+ /* We assume that anything that has an alphabetic key in the
-+ QWERTYUIOP range in it is the main keyboard. */
-+ for (j = KEY_Q; j <= KEY_P; j++) {
-+ if (TestBit(j, key_bitmask)) {
-+ is_new_keyboard = true;
- }
- }
-+ ioctl (hotplug_fd, EVIOCGNAME (sizeof (name)), name);
-+ close(hotplug_fd);
-+
-+ // Ensure that we do not detect our own tsak faked keyboards
-+ if (str_ends_with(name, "+tsak") == 1) {
-+ is_new_keyboard = false;
-+ }
-+
-+ // If a keyboard was added we need to restart...
-+ if (is_new_keyboard == true) {
-+ fprintf(stderr, "Hotplugged new keyboard: (%s)\n", name);
-+ udev_unref(udev);
-+ restart_tsak();
-+ }
-+ }
-+ else {
-+ fprintf(stderr, "No Device from receive_device(). An error occured.\n");
- }
- }
-+
-+ udev_unref(udev);
-+
-+ fprintf(stderr, "Hotplug monitoring process terminated\n");
- }
- }
- }
-diff --git a/twin/kompmgr/kompmgr.c b/twin/kompmgr/kompmgr.c
-index 5daf8c2..8216676 100644
---- a/kwin/kompmgr/kompmgr.c
-+++ b/kwin/kompmgr/kompmgr.c
-@@ -60,6 +60,7 @@ check baghira.sf.net for more infos
- #include <signal.h>
- #include <time.h>
- #include <unistd.h>
-+#include <libgen.h>
- #include <X11/Xlib.h>
- #include <X11/Xutil.h>
- #include <X11/Xatom.h>
-@@ -397,7 +398,7 @@ void delete_pid_file()
- int chars = readlink("/proc/self/exe", me, sizeof(me));
- me[chars] = 0;
- me[2047] = 0;
-- execl(me, NULL);
-+ execl(me, basename(me), (char*)NULL);
- }
- #endif
- }