Fix tsak housekeeping

Provide GUI warning when tsak cannot be used due to system module problems
pull/2/head
Timothy Pearson 12 years ago
parent 8abe81cec2
commit 6cfb160836

@ -21,7 +21,9 @@
#include <unistd.h> #include <unistd.h>
#include <sys/types.h> #include <sys/types.h>
#include <stdlib.h>
#include <sys/types.h>
#include <signal.h>
#include <tqbuttongroup.h> #include <tqbuttongroup.h>
#include <tqlabel.h> #include <tqlabel.h>
@ -47,11 +49,14 @@
#include "tdm-appear.h" #include "tdm-appear.h"
#include "kbackedcombobox.h" #include "kbackedcombobox.h"
#include "config.h"
extern KSimpleConfig *config; extern KSimpleConfig *config;
#define TSAK_LOCKFILE "/tmp/tdesocket-global/tsak.lock"
TDMAppearanceWidget::TDMAppearanceWidget(TQWidget *parent, const char *name) TDMAppearanceWidget::TDMAppearanceWidget(TQWidget *parent, const char *name)
: TQWidget(parent, name) : TQWidget(parent, name), sakwarning(0)
{ {
TQString wtstr; TQString wtstr;
@ -247,6 +252,13 @@ TDMAppearanceWidget::TDMAppearanceWidget(TQWidget *parent, const char *name)
TQGridLayout *hbox2 = new TQGridLayout( group->layout(), 2, 2, KDialog::spacingHint() ); TQGridLayout *hbox2 = new TQGridLayout( group->layout(), 2, 2, KDialog::spacingHint() );
hbox2->setColStretch(1, 1); hbox2->setColStretch(1, 1);
hbox2->addWidget(sakbox, 1, 0); hbox2->addWidget(sakbox, 1, 0);
if (getuid() == 0 && config->checkConfigFilesWritable( true )) {
if (system(KDE_BINDIR "/tsak checkdeps") != 0) {
sakbox->setEnabled(false);
sakwarning = new TQLabel( i18n("Secure Attention Key support is not available on your system. Please check for the presence of evdev and uinput."), group );
hbox2->addWidget(sakwarning, 2, 0);
}
}
wtstr = i18n("Here you can enable or disable the Secure Attention Key [SAK] anti-spoofing measure."); wtstr = i18n("Here you can enable or disable the Secure Attention Key [SAK] anti-spoofing measure.");
TQWhatsThis::add( sakbox, wtstr ); TQWhatsThis::add( sakbox, wtstr );
@ -465,6 +477,21 @@ void TDMAppearanceWidget::save()
config->writeEntry("Language", langcombo->current()); config->writeEntry("Language", langcombo->current());
config->writeEntry("UseSAK", sakbox->isChecked()); config->writeEntry("UseSAK", sakbox->isChecked());
// Enable/disable tsak as needed
if (sakbox->isChecked()) {
system(KDE_BINDIR "/tsak");
}
else {
// Get PID
TQFile file(TSAK_LOCKFILE);
if (file.open(IO_ReadOnly)) {
TQTextStream stream(&file);
unsigned long tsakpid = stream.readLine().toULong();
file.close();
kill(tsakpid, SIGTERM);
}
}
} }
@ -516,7 +543,12 @@ void TDMAppearanceWidget::load()
langcombo->setCurrentItem(config->readEntry("Language", "C")); langcombo->setCurrentItem(config->readEntry("Language", "C"));
// See if the SAK is enabled // See if the SAK is enabled
sakbox->setChecked(config->readBoolEntry("UseSAK", true)); if (sakwarning) {
sakbox->setChecked(config->readBoolEntry("UseSAK", true));
}
else {
sakbox->setChecked(false);
}
} }

@ -91,6 +91,7 @@ private:
KBackedComboBox *echocombo; KBackedComboBox *echocombo;
KLanguageButton *langcombo; KLanguageButton *langcombo;
TQCheckBox *sakbox; TQCheckBox *sakbox;
TQLabel *sakwarning;
}; };

@ -21,6 +21,7 @@ License along with tsak. If not, see http://www.gnu.org/licenses/.
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <exception>
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
#include <errno.h> #include <errno.h>
@ -38,6 +39,8 @@ License along with tsak. If not, see http://www.gnu.org/licenses/.
#include <libudev.h> #include <libudev.h>
#include <libgen.h> #include <libgen.h>
using namespace std;
#define FIFO_DIR "/tmp/tdesocket-global" #define FIFO_DIR "/tmp/tdesocket-global"
#define FIFO_FILE_OUT "/tmp/tdesocket-global/tsak" #define FIFO_FILE_OUT "/tmp/tdesocket-global/tsak"
#define FIFO_LOCKFILE_OUT "/tmp/tdesocket-global/tsak.lock" #define FIFO_LOCKFILE_OUT "/tmp/tdesocket-global/tsak.lock"
@ -94,6 +97,38 @@ int bit_set(size_t i, const byte* a)
return a[i/CHAR_BIT] & (1 << i%CHAR_BIT); return a[i/CHAR_BIT] & (1 << i%CHAR_BIT);
} }
/* exception handling */
struct exit_exception {
int c;
exit_exception(int c):c(c) { }
};
/* signal handler */
void signal_callback_handler(int signum)
{
// Terminate program
throw exit_exception(signum);
exit(signum);
}
/* termination handler */
void tsak_friendly_termination() {
int i;
// Close down all child processes
for (i=0; i<MAX_KEYBOARDS; i++) {
if (child_pids[i] != 0) {
kill(child_pids[i], SIGTERM);
}
}
// Wait for process termination
sleep(1);
fprintf(stderr, "tsak terminated by external request\n");
exit(17);
}
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
// Useful function from Stack Overflow // Useful function from Stack Overflow
// http://stackoverflow.com/questions/874134/find-if-string-endswith-another-string-in-c // http://stackoverflow.com/questions/874134/find-if-string-endswith-another-string-in-c
@ -258,17 +293,24 @@ bool setupPipe()
return setFileLock(mPipe_fd_out, true); return setFileLock(mPipe_fd_out, true);
} }
bool setupLockingPipe() bool setupLockingPipe(bool writepid)
{ {
/* Create the FIFOs if they do not exist */ /* Create the FIFOs if they do not exist */
umask(0); umask(0);
mkdir(FIFO_DIR,0644); mkdir(FIFO_DIR,0644);
mknod(FIFO_LOCKFILE_OUT, S_IFIFO|0600, 0); mknod(FIFO_LOCKFILE_OUT, 0600, 0);
chmod(FIFO_LOCKFILE_OUT, 0600); chmod(FIFO_LOCKFILE_OUT, 0600);
mPipe_lockfd_out = open(FIFO_LOCKFILE_OUT, O_RDWR | O_NONBLOCK); mPipe_lockfd_out = open(FIFO_LOCKFILE_OUT, O_RDWR | O_NONBLOCK);
if (mPipe_lockfd_out > -1) { if (mPipe_lockfd_out > -1) {
if (writepid) {
// Write my PID to the file
pid_t tsakpid = getpid();
char pidstring[1024];
sprintf(pidstring, "%d", tsakpid);
write(mPipe_lockfd_out, pidstring, strlen(pidstring));
}
// Set the exclusive file lock // Set the exclusive file lock
return setFileLock(mPipe_lockfd_out, true); return setFileLock(mPipe_lockfd_out, true);
} }
@ -343,8 +385,8 @@ PipeHandler::~PipeHandler()
{ {
if (active) { if (active) {
tearDownPipe(); tearDownPipe();
tearDownLockingPipe();
} }
tearDownLockingPipe();
} }
int main (int argc, char *argv[]) int main (int argc, char *argv[])
@ -360,291 +402,319 @@ int main (int argc, char *argv[])
bool hide_event = false; bool hide_event = false;
bool established = false; bool established = false;
bool testrun = false; bool testrun = false;
bool depcheck = false;
int current_keyboard; int current_keyboard;
bool can_proceed; bool can_proceed;
// Ignore SIGPIPE // Ignore SIGPIPE
signal(SIGPIPE, SIG_IGN); signal(SIGPIPE, SIG_IGN);
for (i=0; i<MAX_KEYBOARDS; i++) { // Register signal handlers
child_pids[i] = 0; // Register signal and signal handler
} signal(SIGINT, signal_callback_handler);
signal(SIGTERM, signal_callback_handler);
if (argc == 2) {
if (strcmp(argv[1], "checkactive") == 0) {
testrun = true;
}
}
// Check for existing file locks set_terminate(tsak_friendly_termination);
if (!checkFileLock()) {
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;
}
// Create the output pipe try {
PipeHandler controlpipe; for (i=0; i<MAX_KEYBOARDS; i++) {
if (!setupPipe()) { child_pids[i] = 0;
fprintf(stderr, "Another instance of this program is already running\n"); }
return 8;
}
while (1) { if (argc == 2) {
controlpipe.active = true; if (strcmp(argv[1], "checkactive") == 0) {
testrun = true;
}
if (strcmp(argv[1], "checkdeps") == 0) {
depcheck = true;
}
}
if ((getuid ()) != 0) { if (depcheck == false) {
printf ("You are not root! This WILL NOT WORK!\nDO NOT attempt to bypass security restrictions, e.g. by changing keyboard permissions or owner, if you want the SAK system to remain secure...\n"); // Check for existing file locks
return 5; if (!checkFileLock()) {
fprintf(stderr, "Another instance of this program is already running [1]\n");
return 8;
}
if (!setupLockingPipe(true)) {
fprintf(stderr, "Another instance of this program is already running [2]\n");
return 8;
}
} }
// Find keyboards // Create the output pipe
find_keyboards(); PipeHandler controlpipe;
if (keyboard_fd_num == 0) { if (depcheck == false) {
printf ("Could not find any usable keyboard(s)!\n"); if (!setupPipe()) {
// Make sure everyone knows we physically can't detect a SAK fprintf(stderr, "Another instance of this program is already running\n");
// Before we do this we broadcast one so that active dialogs are updated appropriately return 8;
// Also, we keep watching for a keyboard to be added via a forked child process...
broadcast_sak();
if (established)
sleep(1);
else {
int i=fork();
if (i<0) {
return 12; // fork failed
}
if (i>0) {
return 4;
}
sleep(1);
restart_tsak();
} }
} }
else {
fprintf(stderr, "Found %d keyboard(s)\n", keyboard_fd_num); while (1) {
if (depcheck == false) {
can_proceed = true; controlpipe.active = true;
for (current_keyboard=0;current_keyboard<keyboard_fd_num;current_keyboard++) { }
// Print Device Name
ioctl (keyboard_fds[current_keyboard], EVIOCGNAME (sizeof (name)), name); if ((getuid ()) != 0) {
fprintf(stderr, "Reading from keyboard: (%s)\n", name); printf ("You are not root! This WILL NOT WORK!\nDO NOT attempt to bypass security restrictions, e.g. by changing keyboard permissions or owner, if you want the SAK system to remain secure...\n");
return 5;
// Create filtered virtual output device }
devout[current_keyboard]=open("/dev/misc/uinput",O_RDWR|O_NONBLOCK);
if (devout[current_keyboard]<0) { // Find keyboards
devout[current_keyboard]=open("/dev/uinput",O_RDWR|O_NONBLOCK); find_keyboards();
if (devout[current_keyboard]<0) { if (keyboard_fd_num == 0) {
perror("open(\"/dev/misc/uinput\")"); printf ("Could not find any usable keyboard(s)!\n");
} if (depcheck == true) {
return 50;
} }
if (devout[current_keyboard]<0) { // Make sure everyone knows we physically can't detect a SAK
can_proceed = false; // Before we do this we broadcast one so that active dialogs are updated appropriately
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"); // Also, we keep watching for a keyboard to be added via a forked child process...
perror("open(\"/dev/uinput\")"); broadcast_sak();
if (established) if (established)
sleep(1); sleep(1);
else else {
return 3; int i=fork();
if (i<0) {
return 12; // fork failed
}
if (i>0) {
return 4;
}
sleep(1);
restart_tsak();
} }
} }
else {
fprintf(stderr, "Found %d keyboard(s)\n", keyboard_fd_num);
if (can_proceed == true) { can_proceed = true;
for (current_keyboard=0;current_keyboard<keyboard_fd_num;current_keyboard++) { for (current_keyboard=0;current_keyboard<keyboard_fd_num;current_keyboard++) {
if(ioctl(keyboard_fds[current_keyboard], EVIOCGRAB, 2) < 0) { // Print Device Name
close(keyboard_fds[current_keyboard]); ioctl (keyboard_fds[current_keyboard], EVIOCGNAME (sizeof (name)), name);
fprintf(stderr, "Failed to grab exclusive input device lock"); fprintf(stderr, "Reading from keyboard: (%s)\n", name);
// Create filtered virtual output device
devout[current_keyboard]=open("/dev/misc/uinput",O_RDWR|O_NONBLOCK);
if (devout[current_keyboard]<0) {
devout[current_keyboard]=open("/dev/uinput",O_RDWR|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) if (established)
sleep(1); sleep(1);
else else
return 1; return 3;
} }
else { }
ioctl(keyboard_fds[current_keyboard], EVIOCGNAME(UINPUT_MAX_NAME_SIZE), devinfo.name); if (depcheck == true) {
strncat(devinfo.name, "+tsak", UINPUT_MAX_NAME_SIZE-1); return 0;
fprintf(stderr, "%s\n", devinfo.name); }
ioctl(keyboard_fds[current_keyboard], EVIOCGID, &devinfo.id);
if (can_proceed == true) {
copy_features(keyboard_fds[current_keyboard], devout[current_keyboard]); for (current_keyboard=0;current_keyboard<keyboard_fd_num;current_keyboard++) {
if (write(devout[current_keyboard],&devinfo,sizeof(devinfo)) < 0) { if(ioctl(keyboard_fds[current_keyboard], EVIOCGRAB, 2) < 0) {
fprintf(stderr, "Unable to write to output device\n"); close(keyboard_fds[current_keyboard]);
} fprintf(stderr, "Failed to grab exclusive input device lock");
if (ioctl(devout[current_keyboard],UI_DEV_CREATE)<0) {
fprintf(stderr, "Unable to create input device with UI_DEV_CREATE\n");
if (established) if (established)
sleep(1); sleep(1);
else else
return 2; return 1;
} }
else { else {
fprintf(stderr, "Device created.\n"); ioctl(keyboard_fds[current_keyboard], EVIOCGNAME(UINPUT_MAX_NAME_SIZE), devinfo.name);
strncat(devinfo.name, "+tsak", UINPUT_MAX_NAME_SIZE-1);
if (established == false) { fprintf(stderr, "%s\n", devinfo.name);
int i=fork(); ioctl(keyboard_fds[current_keyboard], EVIOCGID, &devinfo.id);
if (i<0) return 9; // fork failed
if (i>0) { copy_features(keyboard_fds[current_keyboard], devout[current_keyboard]);
child_pids[current_keyboard] = i; if (write(devout[current_keyboard],&devinfo,sizeof(devinfo)) < 0) {
continue; fprintf(stderr, "Unable to write to output device\n");
}
setupLockingPipe();
} }
if (ioctl(devout[current_keyboard],UI_DEV_CREATE)<0) {
established = true; fprintf(stderr, "Unable to create input device with UI_DEV_CREATE\n");
if (established)
if (testrun == true) { sleep(1);
return 0; else
return 2;
} }
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(false);
}
while (1) { established = true;
if ((rd = read (keyboard_fds[current_keyboard], ev, size)) < size) {
fprintf(stderr, "Read failed.\n"); if (testrun == true) {
break; return 0;
} }
// Replicate LED events from the virtual keyboard to the physical keyboard while (1) {
int rrd = read(devout[current_keyboard], &revev, size); if ((rd = read (keyboard_fds[current_keyboard], ev, size)) < size) {
if (rrd >= size) { fprintf(stderr, "Read failed.\n");
if (revev.type == EV_LED) { break;
if (write(keyboard_fds[current_keyboard], &revev, sizeof(revev)) < 0) { }
fprintf(stderr, "Unable to replicate LED event\n");
// Replicate LED events from the virtual keyboard to the physical keyboard
int rrd = read(devout[current_keyboard], &revev, size);
if (rrd >= size) {
if (revev.type == EV_LED) {
if (write(keyboard_fds[current_keyboard], &revev, sizeof(revev)) < 0) {
fprintf(stderr, "Unable to replicate LED event\n");
}
} }
} }
}
value = ev[0].value; value = ev[0].value;
if (ev[0].value == 0 && ev[0].type == 1) { // Read the key release event if (ev[0].value == 0 && ev[0].type == 1) { // Read the key release event
if (keycode[(ev[0].code)]) { if (keycode[(ev[0].code)]) {
if (strcmp(keycode[(ev[0].code)], "<control>") == 0) ctrl_down = false; if (strcmp(keycode[(ev[0].code)], "<control>") == 0) ctrl_down = false;
if (strcmp(keycode[(ev[0].code)], "<alt>") == 0) alt_down = false; if (strcmp(keycode[(ev[0].code)], "<alt>") == 0) alt_down = false;
}
} }
} if (ev[0].value == 1 && ev[0].type == 1) { // Read the key press event
if (ev[0].value == 1 && ev[0].type == 1) { // Read the key press event if (keycode[(ev[0].code)]) {
if (keycode[(ev[0].code)]) { if (strcmp(keycode[(ev[0].code)], "<control>") == 0) ctrl_down = true;
if (strcmp(keycode[(ev[0].code)], "<control>") == 0) ctrl_down = true; if (strcmp(keycode[(ev[0].code)], "<alt>") == 0) alt_down = true;
if (strcmp(keycode[(ev[0].code)], "<alt>") == 0) alt_down = true; }
} }
}
hide_event = false; hide_event = false;
if (ev[0].value == 1 && ev[0].type == 1) { // Read the key press event if (ev[0].value == 1 && ev[0].type == 1) { // Read the key press event
if (keycode[(ev[0].code)]) { if (keycode[(ev[0].code)]) {
if (alt_down && ctrl_down && (strcmp(keycode[(ev[0].code)], "<del>") == 0)) { if (alt_down && ctrl_down && (strcmp(keycode[(ev[0].code)], "<del>") == 0)) {
hide_event = true; hide_event = true;
}
} }
} }
}
if ((hide_event == false) && (ev[0].type != EV_LED) && (ev[1].type != EV_LED)) { if ((hide_event == false) && (ev[0].type != EV_LED) && (ev[1].type != EV_LED)) {
// Pass the event on... // Pass the event on...
event = ev[0]; event = ev[0];
if (write(devout[current_keyboard], &event, sizeof event) < 0) { if (write(devout[current_keyboard], &event, sizeof event) < 0) {
fprintf(stderr, "Unable to replicate keyboard event!\n"); fprintf(stderr, "Unable to replicate keyboard event!\n");
}
}
if (hide_event == true) {
// Let anyone listening to our interface know that an SAK keypress was received
broadcast_sak();
} }
}
if (hide_event == true) {
// Let anyone listening to our interface know that an SAK keypress was received
broadcast_sak();
} }
} }
} }
} }
}
// fork udev monitor process // fork udev monitor process
int i=fork(); int i=fork();
if (i<0) { if (i<0) {
return 10; // fork failed return 10; // fork failed
} }
if (i>0) { if (i>0) {
// Terminate parent // Terminate parent
controlpipe.active = false; controlpipe.active = false;
return 0; return 0;
} }
// Prevent multiple process instances from starting // Prevent multiple process instances from starting
setupLockingPipe(); setupLockingPipe(true);
// Wait a little bit so that udev hotplug can stabilize before we start monitoring // Wait a little bit so that udev hotplug can stabilize before we start monitoring
sleep(1); sleep(1);
fprintf(stderr, "Hotplug monitoring process started\n"); fprintf(stderr, "Hotplug monitoring process started\n");
// Monitor for hotplugged keyboards // Monitor for hotplugged keyboards
int j; int j;
int hotplug_fd; int hotplug_fd;
bool is_new_keyboard; bool is_new_keyboard;
struct udev *udev; struct udev *udev;
struct udev_device *dev; struct udev_device *dev;
struct udev_monitor *mon; struct udev_monitor *mon;
// Create the udev object // Create the udev object
udev = udev_new(); udev = udev_new();
if (!udev) { if (!udev) {
fprintf(stderr, "Cannot connect to udev interface\n"); fprintf(stderr, "Cannot connect to udev interface\n");
return 11; 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();
}
// Set up a udev monitor to monitor input devices is_new_keyboard = false;
mon = udev_monitor_new_from_netlink(udev, "udev"); snprintf(filename,sizeof(filename), "%s", udev_device_get_devnode(dev));
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_device_unref(dev);
udev_unref(udev);
restart_tsak();
}
is_new_keyboard = false; // Print name of keyboard
snprintf(filename,sizeof(filename), "%s", udev_device_get_devnode(dev)); hotplug_fd = open(filename, O_RDWR|O_SYNC);
udev_device_unref(dev); ioctl(hotplug_fd, EVIOCGBIT(EV_KEY, sizeof(key_bitmask)), key_bitmask);
// Print name of keyboard /* We assume that anything that has an alphabetic key in the
hotplug_fd = open(filename, O_RDWR|O_SYNC); QWERTYUIOP range in it is the main keyboard. */
ioctl(hotplug_fd, EVIOCGBIT(EV_KEY, sizeof(key_bitmask)), key_bitmask); 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);
/* We assume that anything that has an alphabetic key in the // Ensure that we do not detect our own tsak faked keyboards
QWERTYUIOP range in it is the main keyboard. */ if (str_ends_with(name, "+tsak") == 1) {
for (j = KEY_Q; j <= KEY_P; j++) { is_new_keyboard = false;
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 a keyboard was added we need to restart...
if (str_ends_with(name, "+tsak") == 1) { if (is_new_keyboard == true) {
is_new_keyboard = false; fprintf(stderr, "Hotplugged new keyboard: (%s)\n", name);
udev_unref(udev);
restart_tsak();
}
} }
else {
// If a keyboard was added we need to restart... fprintf(stderr, "No Device from receive_device(). A udev error has occurred; terminating hotplug monitoring process.\n");
if (is_new_keyboard == true) { return 11;
fprintf(stderr, "Hotplugged new keyboard: (%s)\n", name);
udev_unref(udev);
restart_tsak();
} }
} }
else {
fprintf(stderr, "No Device from receive_device(). A udev error has occurred; terminating hotplug monitoring process.\n");
return 11;
}
}
udev_unref(udev); udev_unref(udev);
fprintf(stderr, "Hotplug monitoring process terminated\n"); fprintf(stderr, "Hotplug monitoring process terminated\n");
}
} }
} }
} }
catch(exit_exception& e) {
exit(e.c);
}
return 6; return 6;
} }

Loading…
Cancel
Save