364 lines
8.3 KiB
C
364 lines
8.3 KiB
C
/*****************************************************************************
|
|
* wpkbdmon.c Keyboard Led Debugger/Monitor
|
|
*
|
|
* Author: Nenad Corbic <ncorbic@sangoma.com>
|
|
*
|
|
* Copyright: (c) 2000-2001 Sangoma Technologies Inc.
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version
|
|
* 2 of the License, or (at your option) any later version.
|
|
* ----------------------------------------------------------------------------
|
|
* Nov 13, 2000 Nenad Corbic Initial version based on kblights() program
|
|
* written by Joseph Nicholas.
|
|
*****************************************************************************/
|
|
|
|
#include <stdio.h> //printf()
|
|
#include <stdlib.h>
|
|
#include <sys/types.h> //open()
|
|
#include <sys/stat.h> //open()
|
|
#include <fcntl.h> //open()
|
|
#include <sys/ioctl.h> //ioctl()
|
|
#include <linux/kd.h> //KDSETLED,LED_SCR,LED_CAP,LED_NUM
|
|
#include <errno.h> //errno()
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
#include <signal.h>
|
|
#include <errno.h>
|
|
|
|
#define MAX_TOKENS 32
|
|
#define KBD_NUM 'n'
|
|
#define KBD_CAP 'c'
|
|
#define KBD_SCR 's'
|
|
|
|
char CONSOLE[] = "/dev/console";
|
|
static unsigned int tx_orig=0, rx_orig=0;
|
|
static void cleanup(void);
|
|
|
|
int kbd_lights(unsigned char led)
|
|
{
|
|
int ttyfd; //fd for console device
|
|
int result; //results of ioctl()
|
|
|
|
|
|
//This is the console device we will open
|
|
|
|
//open console device for later ioctl() call
|
|
|
|
ttyfd = open(CONSOLE, O_RDWR);
|
|
if (ttyfd < 0)
|
|
{
|
|
printf("cannot open %s\n", CONSOLE);
|
|
return 1;
|
|
} // end if()
|
|
|
|
result = ioctl(ttyfd,KDSETLED,&led);
|
|
if (result < 0)
|
|
{
|
|
printf("ioctl returned error: %d\n", errno);
|
|
close(ttyfd);
|
|
return 1;
|
|
}
|
|
|
|
close(ttyfd);
|
|
return 0;
|
|
} // end kbd_lights()
|
|
|
|
|
|
void sig_handler(int signum)
|
|
{
|
|
kbd_lights(0);
|
|
cleanup();
|
|
exit(0);
|
|
}
|
|
|
|
|
|
/*============================================================================
|
|
* Strip leading and trailing spaces off the string str.
|
|
*/
|
|
char* strstrip (char* str, char* s)
|
|
{
|
|
char* eos = str + strlen(str); /* -> end of string */
|
|
|
|
while (*str && strchr(s, *str))
|
|
++str; /* strip leading spaces */
|
|
while ((eos > str) && strchr(s, *(eos - 1)))
|
|
--eos; /* strip trailing spaces */
|
|
*eos = '\0';
|
|
return str;
|
|
}
|
|
|
|
|
|
/*============================================================================
|
|
* Tokenize string.
|
|
* Parse a string of the following syntax:
|
|
* <tag>=<arg1>,<arg2>,...
|
|
* and fill array of tokens with pointers to string elements.
|
|
*
|
|
* Return number of tokens.
|
|
*/
|
|
int tokenize (char* str, char **tokens, char *arg1, char *arg2, char *arg3)
|
|
{
|
|
int cnt = 0;
|
|
|
|
tokens[0] = strtok(str, arg1);
|
|
while (tokens[cnt] && (cnt < MAX_TOKENS - 1)) {
|
|
tokens[cnt] = strstrip(tokens[cnt], arg2);
|
|
tokens[++cnt] = strtok(NULL, arg3);
|
|
}
|
|
return cnt;
|
|
}
|
|
|
|
void get_tx_rx_data (char *if_name, unsigned int *tx_data, unsigned int *rx_data)
|
|
{
|
|
char net_dev[] = "/proc/net/dev";
|
|
struct stat file_stat;
|
|
int toknum;
|
|
char* token[MAX_TOKENS];
|
|
FILE *pipe_fd;
|
|
char line[500];
|
|
int i,len,found=0;
|
|
char *ptr;
|
|
|
|
*tx_data = *rx_data = 0;
|
|
|
|
if (stat(net_dev, &file_stat) < 0)
|
|
return;
|
|
|
|
pipe_fd = popen("cat /proc/net/dev", "r");
|
|
if (pipe_fd == NULL){
|
|
printf("Failed to open /proc/net/dev\n");
|
|
return;
|
|
}
|
|
|
|
i=0;
|
|
while (fgets(line,sizeof(line)-1,pipe_fd)){
|
|
if (++i < 2)
|
|
continue;
|
|
if (strstr(line,if_name) != NULL){
|
|
found = 1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
pclose(pipe_fd);
|
|
|
|
if (!found){
|
|
return;
|
|
}
|
|
|
|
/* Bug Fix: Dec 7 2000
|
|
* When the packet count gets too high,
|
|
* the space between the interface name and the
|
|
* count is used yp. This breaks our parsing procedure,
|
|
* Therefore, replace the first colon by SPACE, this
|
|
* way there will always be space between the interface
|
|
* name and the byte count */
|
|
|
|
if ((ptr=strchr(line,':')) != NULL){
|
|
*ptr=' ';
|
|
}
|
|
|
|
len = strlen(line) + 1;
|
|
toknum = tokenize(line, token, " ", " \t\n", " ");
|
|
|
|
if (toknum < 13)
|
|
return;
|
|
|
|
*rx_data = atoi(token[2]);
|
|
*tx_data = atoi(token[10]);
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
void get_wanpipe_state (char *device_name, char *state)
|
|
{
|
|
char router_dir[] = "/proc/net/wanrouter";
|
|
FILE *pipe_fd;
|
|
char line[100];
|
|
int i,len,found=0;
|
|
int toknum;
|
|
char* token[MAX_TOKENS];
|
|
struct stat file_stat;
|
|
|
|
strcpy(state,"unconfigured");
|
|
|
|
if (stat(router_dir, &file_stat) < 0)
|
|
return;
|
|
|
|
pipe_fd = popen("cat /proc/net/wanrouter/status", "r");
|
|
if (pipe_fd == NULL)
|
|
return;
|
|
|
|
i=0;
|
|
while (fgets(line,sizeof(line)-1,pipe_fd)){
|
|
if (strstr(line,device_name) != NULL){
|
|
found = 1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
pclose(pipe_fd);
|
|
|
|
if (!found){
|
|
return;
|
|
}
|
|
|
|
len = strlen(line) + 1;
|
|
toknum = tokenize(line, token, "|", " \t\n", "|");
|
|
|
|
if (toknum <= 3)
|
|
return;
|
|
|
|
if (strcmp(token[0],device_name))
|
|
return;
|
|
|
|
strcpy(state,token[3]);
|
|
|
|
return;
|
|
}
|
|
|
|
int check_and_set_lock_file(void)
|
|
{
|
|
char wanpipe_dir[] = "/etc/wanpipe";
|
|
char lock_file[] = "/etc/wanpipe/wpkbd_lock";
|
|
struct stat file_stat;
|
|
|
|
if (stat(wanpipe_dir, &file_stat) < 0){
|
|
printf("wpkbdmon: Error, WANPIPE utilites not installed\n");
|
|
printf("wpkbdmon: Directory not found: %s\n",wanpipe_dir);
|
|
return 1;
|
|
}
|
|
|
|
if (stat(lock_file, &file_stat) < 0){
|
|
system ("touch /etc/wanpipe/wpkbd_lock");
|
|
}else{
|
|
printf("\nwpkbdmon: Error, WANPIPE Keyboard Led Monitor already running!\n");
|
|
printf(" The /etc/wanpipe/wpkbd_lock exits.\n\n");
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
void cleanup (void)
|
|
{
|
|
system("rm -f /etc/wanpipe/wpkbd_lock");
|
|
}
|
|
|
|
|
|
int main (int argc, char **argv)
|
|
{
|
|
int update_interval=5;
|
|
char device[15];
|
|
char interface[15];
|
|
char state[50];
|
|
int errno;
|
|
unsigned int tx_data, rx_data;
|
|
unsigned char led_state=0;
|
|
struct sigaction sa;
|
|
|
|
//General Error Message
|
|
const char *help =
|
|
"\n wpkbdmon v1.0 - (c)2000 Nenad Corbic <ncorbic@sangoma.com>\n\n"
|
|
" This program is distributed under the terms of GPL.\n\n"
|
|
" This program uses the keyboard leds to convey \n"
|
|
" operational statistics of the Sangoma WANPIPE adapter.\n"
|
|
" NUM_LOCK = Line State (On=connected, Off=disconnected)\n"
|
|
" CAPS_LOCK = Tx data (On=transmitting, Off=no tx data)\n"
|
|
" SCROLL_LOCK = Rx data (On=receiving, Off=no rx data)\n\n"
|
|
" Usage:\n"
|
|
" wpkbdmon <wanpipe device> <interface name> [update_interval]\n\n"
|
|
" <wanpipe device> = wanpipe# (#=1,2,3 ...)\n"
|
|
" <interface name> = wanpipe network interface ex: wp1_fr16\n"
|
|
" [update interval] = 1-60 seconds , optional (default 5 sec)\n\n";
|
|
|
|
if (argc < 3){
|
|
printf("\nError in usage: Arguments missing\n");
|
|
printf("%s",help);
|
|
exit(1);
|
|
}
|
|
|
|
if (argc == 4){
|
|
update_interval = atoi(argv[3]);
|
|
if (update_interval < 1 || update_interval > 60){
|
|
printf("Error: Update interval out of range!\n");
|
|
printf("%s",help);
|
|
exit(1);
|
|
}
|
|
printf("\nUsing Time Interval: %i sec\n",update_interval);
|
|
}else{
|
|
printf("\nUsing Default Time Interval: %i sec\n",update_interval);
|
|
}
|
|
|
|
if (check_and_set_lock_file())
|
|
exit(0);
|
|
|
|
memset(&sa,0,sizeof(sa));
|
|
sa.sa_handler=sig_handler;
|
|
|
|
if (sigaction(SIGINT,&sa,NULL)){
|
|
perror("sigaction");
|
|
}
|
|
|
|
strcpy(device,argv[1]);
|
|
strcpy(interface,argv[2]);
|
|
|
|
printf ("Starting Wanpipe Keyboard Debugger, Device: %s Interface: %s\n",argv[1],argv[2]);
|
|
for (;;){
|
|
|
|
get_wanpipe_state(device, state);
|
|
|
|
if (!strcmp(state,"unconfigured")){
|
|
kbd_lights(0);
|
|
printf("Warning: Device %s is down, exiting debugger\n",device);
|
|
goto wpkbd_exit;
|
|
|
|
}else if (!strcmp(state, "connected")){
|
|
led_state |= LED_NUM;
|
|
}else{
|
|
if (kbd_lights(0))
|
|
goto wpkbd_exit;
|
|
goto skip_tx_rx;
|
|
}
|
|
|
|
|
|
get_tx_rx_data(interface,&tx_data,&rx_data);
|
|
|
|
/* If number of tx packets has not changed, or
|
|
* number of tx packets is 0 while original value is
|
|
* not, the packet transmission has stopped.
|
|
* Thus, turn off the CAP led. */
|
|
|
|
if (tx_data == tx_orig || (tx_orig && !tx_data)){
|
|
led_state &= ~LED_CAP;
|
|
}else{
|
|
led_state |= LED_CAP;
|
|
}
|
|
tx_orig=tx_data;
|
|
|
|
if (rx_data == rx_orig || (rx_orig && !rx_data)){
|
|
led_state &= ~LED_SCR;
|
|
}else{
|
|
led_state |= LED_SCR;
|
|
}
|
|
rx_orig=rx_data;
|
|
|
|
if (kbd_lights(led_state))
|
|
goto wpkbd_exit;
|
|
|
|
skip_tx_rx:
|
|
sleep(update_interval);
|
|
}
|
|
|
|
wpkbd_exit:
|
|
|
|
cleanup();
|
|
return 0;
|
|
}
|
|
|
|
|