The last patch, implementing usage of X in tleds as started task, had a problem: if a user logged off gdm then tleds would get a SIGPIPE. That has to do with xbase-clients' handling of I/O errors and that is corrected in the attached patch. But this is only for the sake of completion, because using X has 3 big problems: 1. You are now dependent on xbase-clients and Xlib.h 2. The NumLock LED doesn't work 3. If no one is logged on the X there are no LEDs working: you have to be logged on for the interface to work.
diff -Naur tleds-1.05beta10-orig/Makefile tleds-1.05beta10/Makefile --- tleds-1.05beta10-orig/Makefile 2006-10-10 15:20:26.000000000 -0500 +++ tleds-1.05beta10/Makefile 2007-01-09 10:18:42.000000000 -0600 @@ -22,8 +22,8 @@ # in the source code. tleds: tleds.c Makefile # Making tleds - gcc -DNO_X_SUPPORT $(GCCOPTS) -o tleds_20 tleds.c - gcc -DNO_X_SUPPORT -DKERNEL2_1 $(GCCOPTS) -o tleds_21 tleds.c + gcc $(GCCOPTS) -o tleds_20 tleds.c -I /usr/X11R6/include/ -L /usr/X11R6/lib/ -lX11 + gcc -DKERNEL2_1 $(GCCOPTS) -o tleds_21 tleds.c -I /usr/X11R6/include/ -L /usr/X11R6/lib/ -lX11 help: # make help - this. diff -Naur tleds-1.05beta10-orig/tleds.c tleds-1.05beta10/tleds.c --- tleds-1.05beta10-orig/tleds.c 2006-10-10 15:20:26.000000000 -0500 +++ tleds-1.05beta10/tleds.c 2007-01-11 10:17:44.000000000 -0600 @@ -43,6 +43,11 @@ * E. Hull (1999-08-20, 1999-05-14) for cleaner shutdown, security fixes to * the PID handling, use of daemon for backgrounding, and the -n option. */ +/* Modified extensively by HVW (2006-01-08) to eliminate the NO_X_SUPPORT + * and use X to flash the LEDs if the -x option is given. + * This because in kernel > 2.6.17 LEDs would not work in X without the X api-use. + * The displays are attempted to be opened and are used, all by the daemon. */ + #define VERSION "1.05beta10" #define MYNAME "tleds" @@ -56,13 +61,6 @@ #define KERNEL2_0 1 #endif -/* If you don't want X stuff. */ -#ifdef NO_X_SUPPORT -#define REMOVE_X_CODE 1 -#else -#define REMOVE_X_CODE 0 -#endif - #include <stdio.h> #include <unistd.h> #include <string.h> @@ -71,12 +69,7 @@ #include <stdlib.h> #include <time.h> #include <signal.h> -#if (! REMOVE_X_CODE) #include <X11/Xlib.h> -#else -#define LedModeOff 0 -#define LedModeOn 1 -#endif #include <sys/time.h> #include <sys/types.h> #include <sys/stat.h> @@ -88,6 +81,9 @@ #include <sys/utsname.h> /* needed by getfd and friends to support console deallocating */ #include <errno.h> +#include <syslog.h> +#include <setjmp.h> +#include <stdarg.h> #ifndef TRUE #define TRUE 1 @@ -97,6 +93,7 @@ #define KEYBOARDDEVICE "/dev/console" #define CURRENTTTY "/dev/tty0" #define MAXVT 64 +#define MAXDISPLAYS 2 #define NETDEVFILENAME "/proc/net/dev" #define TERMINATESTR "Program (and child) terminated.\n" #define DEEPSLEEP 10 @@ -128,6 +125,16 @@ ulong detach_vt_leds(int tty, int wantDetach); char *find_device_line(char *buffer, char *netDeviceName); inline int find_max_VT(); + +void opendisplays(); +void closedisplays(); +void changekeyboardcontrol( unsigned long, XKeyboardControl* ); +void xsync( Bool ); +Bool was_at_least_five_secs_ago(); +static int sync_handler(Display *display); +static int CKC_handler(Display *display); +void do_print_it (char *vsname, ...); + pid_t get_old_pid(); pid_t get_own_pid(char *fileName); int get_sleeptime(int isDefinedByUser, char *interfaceName); @@ -159,24 +166,26 @@ int getfd(); /* Global and static variables */ +jmp_buf sync_buf; +jmp_buf CKC_buf; + static const char devFileName[] = NETDEVFILENAME; static char pidFileName[30] = ""; /* 30 should be enough */ static char rootPidFileName[30] = ""; -#if (! REMOVE_X_CODE) -static Display *myDisplay = NULL; +static Display *myDisplay[MAXDISPLAYS]; +FILE *stream; +static int handling_display = -1; +static int (*old_xioerror_handler)(Display *) = NULL; -#else -static char *myDisplay = NULL; - -#endif static int keyboardDevice = 0; +static long int last_time; static char ttyLEDs[MAXVT] = {}; static ushort previousActive = (ushort) (MAXVT + 1); static int remindVTcoef = 0; static int opt_b = FALSE, opt_d = FALSE, opt_h = FALSE, opt_k = FALSE, opt_q -= FALSE, opt_v = FALSE, opt_V = FALSE, opt_c = FALSE, opt_n = FALSE; += FALSE, opt_v = FALSE, opt_V = FALSE, opt_c = FALSE, opt_n = FALSE, opt_x = FALSE; static int inled = NUMLOCKLED, outled = SCROLLLOCKLED; /* The code */ @@ -184,7 +193,7 @@ { char *interfaceName; char buffer[MAXLEN]; - ulong ledVal; +// ulong ledVal; char *tmpPointer; char **list; pid_t pid; @@ -192,6 +201,13 @@ int wasInDeepSleep; struct timeval sleeptimeval; + struct timeval t0; + int n; + + int i; + for (i=0; i<MAXDISPLAYS; i++) + myDisplay[i] = NULL; + interfaceName = NULL; sleeptime = 0; check_kernel_version(); /* May die here */ @@ -229,32 +245,50 @@ printf("Delay between updates is %d milliseconds.\n", sleeptime); } + do_print_it("======================INIT===========================%d %s\n",__LINE__,__FILE__); if (!find_device_line(buffer, interfaceName) && !opt_q) { printf( "There is currently no such interface as %s in %s.\n%s\n", interfaceName, devFileName, "Maybe later there will be. Kill me (-k) if ya want."); } + do_print_it("After find_device_line %d %s\n",__LINE__,__FILE__); if (!opt_b) { if (-1 == daemon(0, (geteuid() != 0))) { perror("tleds: daemon"); + openlog( "tleds", LOG_PID, LOG_USER); + syslog( LOG_INFO | LOG_USER, + "tleds: daemon (%d) \n",__LINE__ ); + closelog(); + do_print_it("%d %s\n",__LINE__,__FILE__); return 1; } } + do_print_it("After daeminize %d %s\n",__LINE__,__FILE__); pid = getpid(); if (pid) { + do_print_it("%d %s\n",__LINE__,__FILE__); create_pid_file(pid, argv[0]); - if (!opt_q) + if (!opt_q) { printf("Running in %sground. Pid: %ld\n", (opt_b ? "fore" : "back"), (long) pid); + do_print_it("%d %s\n",__LINE__,__FILE__); + } } + do_print_it("Running in %sground. Pid: %ld (%d)\n", (opt_b ? "fore" : "back"), (long) pid, __LINE__); if (atexit(my_exit)) { perror("tleds: atexit() failed"); + openlog( "tleds", LOG_PID, LOG_USER); + syslog( LOG_INFO | LOG_USER, + "tleds: atexit() failed (%d) \n",__LINE__ ); + closelog(); + do_print_it("%d %s\n",__LINE__,__FILE__); return 1; } if (!opt_b) { + do_print_it("%d %s\n",__LINE__,__FILE__); signal(SIGUSR1, parent_wants_me_dead); } signal(SIGHUP, SIG_IGN); @@ -263,38 +297,41 @@ signal(SIGQUIT, my_signal_handler); signal(SIGTSTP, my_signal_handler); signal(SIGUSR2, SIG_IGN); - signal(SIGPIPE, my_signal_handler); +// signal(SIGPIPE, my_signal_handler); // this actually still gets invoked for X problems + signal(SIGPIPE, SIG_IGN); if (!geteuid()) { /* We are running as EUID root - CONSOLE */ if (-1 == (keyboardDevice = open(KEYBOARDDEVICE, O_RDONLY))) { perror("tleds"); fprintf(stderr, "%s:%s", KEYBOARDDEVICE, TERMINATESTR); + openlog( "tleds", LOG_PID, LOG_USER); + syslog( LOG_INFO | LOG_USER, + "tleds %s:%s (%d) \n", KEYBOARDDEVICE, TERMINATESTR,__LINE__ ); + closelog(); + do_print_it("%d %s\n",__LINE__,__FILE__); exit(1); } - } else { /* EUID not root */ -#if (! REMOVE_X_CODE) - if (!(myDisplay = XOpenDisplay(NULL)) /* X */ - &&ioctl(0, KDGETLED, &ledVal)) { /* VT */ - perror( - "tleds: Can't open X DISPLAY on the current host."); - fprintf(stderr, TERMINATESTR); - exit(1); + do_print_it("%d %s\n",__LINE__,__FILE__); +// if (opt_x) +// opendisplays(); /* this will try to open any displays - no errors to stderr */ + if ( (n=gettimeofday(&t0, NULL)) !=0) { + fprintf(stderr, "t0 gettimeofday error =%d\n", n); } -#else - if (ioctl(0, KDGETLED, &ledVal)) { - perror("main: tleds: KDGETLED"); - fprintf(stderr, - "Error reading current led setting.\n%s\n", - "Maybe stdin is not a VT?"); - fprintf(stderr, TERMINATESTR); - exit(1); + else { +// printf("t0=%li%s%li%s\n", t0.tv_sec, ".", t0.tv_usec,"sec"); + last_time = t0.tv_sec; // has present second in the epoch } -#endif - } + + } + do_print_it("Beginning mail loop %d %s\n",__LINE__,__FILE__); + + openlog( "tleds", LOG_PID, LOG_USER); + syslog( LOG_INFO | LOG_USER,"Beginning main loop (%d)\n",__LINE__); + closelog(); + sleeptimeval.tv_sec = (int) ((long) sleeptime * 1000L) / 1000000L; sleeptimeval.tv_usec = (int) ((long) sleeptime * 1000L) % 1000000L; remindVTcoef = (int) ((long) REMINDVTDELAY * 1000L / (long) sleeptime); wasInDeepSleep = TRUE; - /* The main loop */ while (1) { if ((tmpPointer = find_device_line(buffer, interfaceName))) { @@ -324,6 +361,10 @@ if (!(devFile = fopen(devFileName, "r"))) { perror(devFileName); + openlog( "tleds", LOG_PID, LOG_USER); + syslog( LOG_INFO | LOG_USER, + "tleds %s (%d) \n", devFileName, __LINE__ ); + closelog(); exit(1); } /* Skip two lines. (the header) */ @@ -432,76 +473,80 @@ static ulong ledReminder = 0x00; ulong ledVal; -#if (! REMOVE_X_CODE) XKeyboardControl values; -#endif #ifdef DEBUG printf("led(%d, %d)\n", led, (int) mode); #endif -#if (! REMOVE_X_CODE) - if (myDisplay) { - switch (mode) { - case SET: - values.led_mode = LedModeOn; - break; - case CLEAR: - values.led_mode = LedModeOff; - break; - case TOGGLE: - values.led_mode = LedModeOn; - } + + switch (mode) { + case SET: + values.led_mode = LedModeOn; + break; + case CLEAR: + values.led_mode = LedModeOff; + break; + case TOGGLE: + values.led_mode = LedModeOn; } values.led = led; -#endif - if (myDisplay) { -#if (! REMOVE_X_CODE) - XChangeKeyboardControl(myDisplay, KBLed | KBLedMode, &values); + if (opt_x) { + changekeyboardcontrol(KBLed | KBLedMode, &values); if (doAction != DELAYED) - XSync(myDisplay, FALSE); -#endif - } else { - if (doAction != FINISH) { - if (ioctl(keyboardDevice, KDGETLED, &ledVal)) { - perror("led: tleds: KDGETLED"); - exit(1); - } - } else { - ledVal = 0L; - } - switch (led) { - case SCROLLLOCKLED: - if (mode == SET) - ledVal |= LED_SCR; - else - ledVal &= ~LED_SCR; - break; - case NUMLOCKLED: - if (mode == SET) - ledVal |= LED_NUM; - else - ledVal &= ~LED_NUM; - break; - default: - perror("led: tleds: wrong led-value"); + xsync(FALSE); + } + if (doAction != FINISH) { + if (ioctl(keyboardDevice, KDGETLED, &ledVal)) { + perror("led: tleds: KDGETLED"); + openlog( "tleds", LOG_PID, LOG_USER); + syslog( LOG_INFO | LOG_USER, + "led: tleds: KDGETLED (%d) \n", __LINE__ ); + closelog(); exit(1); } - if (opt_c && doAction != FINISH) { - ledVal = correct_caps(ledVal); + } else { + ledVal = 0L; + } + switch (led) { + case SCROLLLOCKLED: + if (mode == SET) + ledVal |= LED_SCR; + else + ledVal &= ~LED_SCR; + break; + case NUMLOCKLED: + if (mode == SET) + ledVal |= LED_NUM; + else + ledVal &= ~LED_NUM; + break; + default: + perror("led: tleds: wrong led-value"); + openlog( "tleds", LOG_PID, LOG_USER); + syslog( LOG_INFO | LOG_USER, + "led: tleds: wrong led-value (%d) \n", __LINE__ ); + closelog(); + exit(1); + } + if (opt_c && doAction != FINISH) { + ledVal = correct_caps(ledVal); + } + if (doAction) { /* FINISH or NOW */ + if (doAction == FINISH) + ledVal |= ledReminder; + if (ioctl(keyboardDevice, KDSETLED, (char) ledVal)) { + perror("led: tleds: KDSETLED"); + openlog( "tleds", LOG_PID, LOG_USER); + syslog( LOG_INFO | LOG_USER, + "led: tleds: KDSETLED (%d) \n", __LINE__ ); + closelog(); + exit(1); } - if (doAction) { /* FINISH or NOW */ - if (doAction == FINISH) - ledVal |= ledReminder; - if (ioctl(keyboardDevice, KDSETLED, (char) ledVal)) { - perror("led: tleds: KDSETLED"); - exit(1); - } - ledReminder = 0x00; - } else { + ledReminder = 0x00; + } else { /* Well, we know from report_traffic(), LED_SCR is processed later. OK, kludge. */ - ledReminder = ledVal & ~LED_SCR; - } + ledReminder = ledVal & ~LED_SCR; } } @@ -609,24 +654,37 @@ void parent_wants_me_dead(int x) { + printf("%d %s\n",__LINE__,__FILE__); + openlog( "tleds", LOG_PID, LOG_USER); + syslog( LOG_INFO | LOG_USER, + "parent_wants_me_dead: %d (%d)\n",x,__LINE__); + closelog(); exit(x); } void my_signal_handler(int x) { + do_print_it("(%d)=%d %d %s\n",x,handling_display,__LINE__,__FILE__); + openlog( "tleds", LOG_PID, LOG_USER); + syslog( LOG_INFO | LOG_USER, + "my_signal_handler: %d (%d)\n",x,__LINE__); + closelog(); exit(x); } void my_exit() { if (opt_b && !opt_q) - printf("Bye-Bye !\n"); - if (myDisplay) { -#if (! REMOVE_X_CODE) + printf("xBye-Bye !\n"); + if (opt_x) { + do_print_it("%d %s\n",__LINE__,__FILE__); clear_led(NUMLOCKLED); clear_led(SCROLLLOCKLED); - XCloseDisplay(myDisplay); /* X */ -#endif + closedisplays(); + openlog( "tleds", LOG_PID, LOG_USER); + syslog( LOG_INFO | LOG_USER, + "Bye-Bye ! (%d) \n", __LINE__ ); + closelog(); } detach_all_vt_leds(FALSE); /* re-attach */ if (keyboardDevice) /* EUID root - CONSOLE */ @@ -743,6 +801,13 @@ MYNAME, pidFileName, rootPidFileName, "Program terminated."); + openlog( "tleds", LOG_PID, LOG_USER); + syslog( LOG_INFO | LOG_USER, + "%s: Can't remove %s or %s\n%s (%d) \n", + MYNAME, pidFileName, + rootPidFileName, + "Program terminated.",__LINE__); + closelog(); exit(1); } } @@ -758,6 +823,12 @@ "\nSorry, can't run. There might be another", name, "If not, try: rm", pidFileName, rootPidFileName); kill(pid, SIGUSR1); + openlog( "tleds", LOG_PID, LOG_USER); + syslog( LOG_INFO | LOG_USER, + "%s %s runnning.\n%s %s %s (%d)\n", + "\nSorry, can't run. There might be another", + name, "If not, try: rm", pidFileName, rootPidFileName,__LINE__); + closelog(); exit(1); } @@ -765,12 +836,22 @@ if (fd < 0 || !(pidFile = fdopen(fd, "w"))) { perror(tmpPidFileName); kill(pid, SIGUSR1); + openlog( "tleds", LOG_PID, LOG_USER); + syslog( LOG_INFO | LOG_USER, + "%s (%d)\n", + tmpPidFileName, __LINE__); + closelog(); exit(1); } fprintf(pidFile, "%ld\n", (long) pid); fclose(pidFile); if (chmod(tmpPidFileName, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) { perror(tmpPidFileName); + openlog( "tleds", LOG_PID, LOG_USER); + syslog( LOG_INFO | LOG_USER, + "%s (%d)\n", + tmpPidFileName, __LINE__); + closelog(); exit(1); } } @@ -794,7 +875,7 @@ { int c; - while (EOF != (c = getopt(argc, argv, "bncd:hkqvV"))) { + while (EOF != (c = getopt(argc, argv, "bncd:hkqvxV"))) { switch (c) { case 'V': opt_V = TRUE; @@ -825,6 +906,9 @@ case 'v': opt_v = TRUE; break; + case 'x': + opt_x = TRUE; + break; default: opt_h = TRUE; /* assert(0); */ @@ -879,6 +963,11 @@ if (-1 == uname(&buffer)) { perror("tleds: check_kernel_version()"); + openlog( "tleds", LOG_PID, LOG_USER); + syslog( LOG_INFO | LOG_USER, + "tleds: check_kernel_version() (%d)\n", + __LINE__); + closelog(); exit(1); } #if KERNEL2_0 @@ -902,13 +991,15 @@ printf("Usage: %s [-bchkqv] [-d <update_delay>] <interface_name>\n", name); printf("Example: %s -d 300 ppp0\n", name); - printf("Options:\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n", + printf("Options:\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n", "\t-b\tDon't go to the background.", "\t-c\tFix the CapsLED in VTs. Only for EUID root.", "\t-d N\tSet update delay.", "\t\tN must be between 1 and 10000 (milliseconds)", "\t-h\tHelp. (this)", "\t-k\tKill (old) (x)tleds running.", + "\t-n\tUse only ScrollLock LED.", + "\t-x\tAlso use X to flash LEDs.", "\t-q\tBe quiet.", "\t-v\tPrint version information.", "\t\t(`cat /proc/net/dev` to see your interfaces.)"); @@ -970,6 +1061,188 @@ exit(1); */ /* total failure */ } /* End (almost) verbatim copy of kbd-0.99's getfd.c */ + + + +void opendisplays(void) +{ + int std_err = dup(2); // save the original stderr + stream = freopen("/dev/null", "w", stderr); // now dump the messages + int i; + + char displayName[10]; // Try to open the displays + + for (i=0; i<MAXDISPLAYS; i++) { + sprintf(displayName,":%d.0",i); + if ( !myDisplay[i] ) { + if ( NULL == (myDisplay[i] = XOpenDisplay (displayName)) ) { + /*printf("Fail %s\n",displayName);*/ + ; + } + } + } + + fclose(stream); // close the new stderr + dup2(std_err,2); // put it back to the orig + + struct timeval t0; + int n; + + if ( (n=gettimeofday(&t0, NULL)) !=0) { + fprintf(stderr, "t0 gettimeofday error =%d\n", n); + } + else { +// printf("t0=%li%s%li%s\n", t0.tv_sec, ".", t0.tv_usec,"sec"); + last_time = t0.tv_sec; // has present second in the epoch + } +} + +Bool was_at_least_five_secs_ago() +{ + + struct timeval t0; + int n; + int long this_time, this_time_m_5; + + if ( (n=gettimeofday(&t0, NULL)) !=0) { + fprintf(stderr, "t0 gettimeofday error =%d\n", n); + } + else { +// printf("t0=%li%s%li%s\n", t0.tv_sec, ".", t0.tv_usec,"sec"); + this_time = t0.tv_sec; + this_time_m_5 = (int) ((long) this_time - 5); + if ( last_time < this_time_m_5 ) { + last_time = this_time; + return TRUE; + } + else + return FALSE; + } + return FALSE; +} + +void closedisplays(void) +{ + int i; + for (i=0; i<MAXDISPLAYS; i++) + if ( myDisplay[i] ) + XCloseDisplay(myDisplay[i]); /* X */ + +} + +void changekeyboardcontrol( unsigned long values, XKeyboardControl* myxkbc) +{ +// are all displays open? + int are_open = 0; + int i; + + for (i=0; i<MAXDISPLAYS; i++) + if ( myDisplay[i] ) + are_open++; + + if ( (are_open < MAXDISPLAYS) && was_at_least_five_secs_ago() ) + opendisplays(); + + old_xioerror_handler = NULL; + old_xioerror_handler = XSetIOErrorHandler(CKC_handler); + for (i=0; i<MAXDISPLAYS; i++) + if ( myDisplay[i] ) { + handling_display = i; + if (setjmp(CKC_buf)==0) { + XChangeKeyboardControl(myDisplay[i], values, myxkbc); + } + XSetIOErrorHandler (old_xioerror_handler); + } + +} + +void xsync( Bool value ) +{ +// are all displays open? + int are_open = 0; + int i; + + for (i=0; i<MAXDISPLAYS; i++) + if ( myDisplay[i] ) + are_open++; + + if ( (are_open < MAXDISPLAYS) && was_at_least_five_secs_ago() ) + opendisplays(); + + old_xioerror_handler = NULL; + old_xioerror_handler = XSetIOErrorHandler(sync_handler); + for (i=0; i<MAXDISPLAYS; i++) + if ( myDisplay[i] ) { + handling_display = i; + if (setjmp(sync_buf)==0) + XSync(myDisplay[i], value); + XSetIOErrorHandler (old_xioerror_handler); + } + +} + +// from: http://www.koders.com/c/fidDFFD503EC57D04673F6B7786B50B2BD311AED547.aspx +static int sync_handler(Display *display) +{ + do_print_it("sync_handler %d %s\n",__LINE__,__FILE__); + if ( display != NULL ) { + XCloseDisplay(display); + if ( (handling_display <= MAXDISPLAYS-1) && (handling_display >= 0) ) + myDisplay[handling_display] = NULL; + } + longjmp(sync_buf,1); +} + +static int CKC_handler(Display *display) +{ + do_print_it("CKC_handler %d %s\n",__LINE__,__FILE__); + if ( display != NULL ) { + do_print_it("closing display %d %s\n",__LINE__,__FILE__); + XCloseDisplay(display); + if ( (handling_display <= MAXDISPLAYS-1) && (handling_display >= 0) ) + myDisplay[handling_display] = NULL; + } + longjmp(CKC_buf,1); +} + +void do_print_it(char *vsname, ...) +{ + + FILE *dbugfl; + + time_t t; + struct tm *area; + struct timeval t0; + char str[400], *result; + int d,nobytes; + + va_list argptr; + char buffer1[400]; + char buffer2[400]; + va_start(argptr, vsname); + vsprintf(buffer2, vsname, argptr); + va_end(argptr); + + buffer1[0]='\0'; + + t = time(NULL); + area = localtime(&t); + gettimeofday(&t0, NULL); + sprintf(buffer1,"%02d:%02d:%02d.%03ld",area->tm_hour,area->tm_min,area->tm_sec,t0.tv_usec); + + strcat(buffer1,"->"); + strcat(buffer1,buffer2); + + d=sprintf(str,"%s",buffer1); + result=&str[0]; // point to it + + dbugfl = fopen("/home/hugo/debug.doc","a"); + nobytes=fwrite(result,1,d,dbugfl); + fclose(dbugfl); + +} + + /* In v2.0.x kernels: