xringd/ 40755 476 3326 0 6364757623 10135 5ustar ahasysxringd/xringd.c100644 476 3326 33025 6363674266 11714 0ustar ahasys/* * File: xringd.c * * Synopsis: Extensive modem ring daemon * * System: Linux 1.3.48+ * * Daemon that uses ringsm.c module to do interesting things with sequences * of modem RINGs. Does not disturb any getty running on the same * port as it only probes for the RI signal. * Device and OS dependent as it uses the TIOCMIWAIT/TIOCGICOUNT ioctls. The * ringsm can be used with "traditional" methods. This is just * cleaner as it does not disturb your system's getty. * * Configuration file default: /etc/xringd.conf * Config file lines are of this form: * R secs[-secs] [ R secs[-secs] ] ... : command * which specify the pattern of rings+delays leading to the exution of * a command. * * Copyright (c) 1995-1997 Angelo Haritsis. All rights reserved. * * 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. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program; see the file COPYING. If not, write to * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. * * $Id: xringd.c,v 1.5 1996/02/17 15:50:07 ah Exp ah $ */ #ifndef linux #error xringd only runs for linux - it uses 2 non-standard ioctls #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "ringsm.h" #if !defined(LINUX_VERSION_CODE) || \ (LINUX_VERSION_CODE < ((1 * 65536) + (3 * 256) + 48)) #error xringd needs Linux 1.3.48 or greater #endif #define RING_SIGNALS /* define for raising SIG_RING on RING detection */ #define SIG_RING SIGUSR1 #define SIG_FLAGS 0 /* 0 or SA_RESTART (syscall after a sig) */ #define MAXLINE 512 #ifndef MODEM_FILE #define MODEM_FILE "/dev/modem" #endif #ifndef CONF_FILE #define CONF_FILE "/etc/xringd.conf" #endif #ifndef INIT_TIMEOUT #define INIT_TIMEOUT 15 #endif #define PROG "xringd" #if 0 static char pidfilename[MAXPATHLEN] = "\0"; #endif char *config_file = NULL; char *modem_file = NULL; char *do_onring = NULL; int modem = -1; time_t reset_timeout = INIT_TIMEOUT; int debug = 0; int disable_echo = 0; int log_level = 1; int syntax_only = 0; long msec_ignore = 0; /* 2 rings within this many msecs => taken as one */ sigset_t sig_mask; int ringsm_parsed = FALSE; void set_signals(void); int modem_open(char *file, int reopen, int disable_echo); void usage_and_die(void); int parse_an_arg(char opt, char *s, int in_conf_line); int parse_an_arg_conf(char opt, char *s, int line); void parse_args(int argc, char **argv); char *str_new(char *s, char *new); void show_args(void); int is_ring_near(struct timeval *tm_bef); void seq_success(char *seq_cmd); void log_msg(int priority, int level, char *fmt, ...); void cback_log_msg(int level, char *fmt, ...); void daemon_init(void); void ring_cmd(void); void proc_ring(int i); void sig_child(int); void sig_hup(int i); void sig_alarm(int i); void clean_exit(int code); void sig_bye(int i); void fork_cmd(char *cmd); void main (int argc, char *argv[]) { int arg; struct serial_icounter_struct c; struct timeval tm_bef; static char str_near[100]; config_file = str_new(config_file, CONF_FILE); /* initialise strings */ modem_file = str_new(modem_file, MODEM_FILE); parse_args(argc, argv); if (access(config_file, R_OK) != 0) { log_msg(-1, 0, "cannot open config file %s", config_file); usage_and_die(); exit(1); } if ((arg = ringsm_parse(config_file, &parse_an_arg_conf)) < 0) { log_msg(-1, 0, "error in config file, line %d", -arg); exit(1); } ringsm_parsed = TRUE; if (syntax_only) { log_msg(-1, 0, "config file %s -> syntax ok", config_file); exit(0); } modem = modem_open(modem_file, FALSE, disable_echo); /* first open */ if (ioctl(modem, TIOCGICOUNT, &c) != 0) { log_msg(-1, 0, "needs Linux 1.3.48+, 16xx0 uart"); usage_and_die(); exit(1); } show_args(); /* Daemon proper */ daemon_init(); if (!debug && log_level > 0) openlog(PROG, LOG_PID, LOG_DAEMON); set_signals(); ringsm_init(reset_timeout, &seq_success, &alarm, &cback_log_msg); str_near[0] = 0; if (msec_ignore > 0) sprintf(str_near, "; rings %ld msec or less apart ignored", msec_ignore); log_msg(LOG_INFO, 1, "version %s started by %s (uid %d)%s", VERSION, getpwuid(getuid())->pw_name, getuid(), str_near); gettimeofday(&tm_bef, NULL); /* main daemon loop */ while (1) { /* wait on RI line */ if (ioctl(modem, TIOCMIWAIT, TIOCM_RNG) != 0) { if (EINTR == errno) { log_msg(LOG_DEBUG, 1000, "ioctl restarting - signal"); continue; } log_msg(LOG_ERR, 10, "%%m - reopening %s", modem_file); /* * XXX EIO may occur: port hung up by other process! * Reopen it - danger: reopening failing continously */ close(modem); modem = modem_open(modem_file, TRUE, disable_echo); continue; } /* we got a ring; if near the previous, ignore it */ if (is_ring_near(&tm_bef)) continue; /* ring is certain; notify the state machine */ #ifdef RING_SIGNALS raise(SIG_RING); #else proc_ring(arg /*dummy*/); #endif if (debug) ringsm_dump(); } /* NOTREACHED */ } void show_args(void) { #ifdef DEBUG log_msg(-1, 100, "Modem: %s - Config: %s\nOnring: %s\n" "reset: %d - ignore: %d - debug: %d - log: %d\n", modem_file, config_file, do_onring, reset_timeout, msec_ignore, debug, log_level); #endif } void usage_and_die(void) { fprintf(stderr, "xringd version " VERSION " - by A. Haritsis (ah@doc.ic.ac.uk)\n" "usage: %s [-a rngcmd] [-c cfgfile] [-d] [-h] [-i ignore_msec] [-l loglevel]\n" " [-m modem_dev] [-e] [-n] [-t initime] [modem_dev]\n", PROG); exit(1); } void set_signals(void) { #define SIGNAL(s, flags, handler, old) do { \ sa.sa_handler = handler; \ sa.sa_flags = flags; \ if (sigaction(s, &sa, old) < 0) { \ log_msg(LOG_ERR, 1, "error setting signal (%%m)"); \ clean_exit(1); \ } \ } while (0) struct sigaction sa; sigemptyset(&sig_mask); sigaddset(&sig_mask, SIGALRM); /* only one signal served at a time */ sigaddset(&sig_mask, SIGCHLD); sigaddset(&sig_mask, SIGHUP); sigaddset(&sig_mask, SIGINT); sigaddset(&sig_mask, SIGTERM); sigaddset(&sig_mask, SIGQUIT); #ifdef RING_SIGNALS sigaddset(&sig_mask, SIG_RING); #endif sa.sa_mask = sig_mask; SIGNAL(SIGALRM, SIG_FLAGS, sig_alarm, NULL); SIGNAL(SIGCHLD, SIG_FLAGS, sig_child, NULL); #ifdef RING_SIGNALS SIGNAL(SIG_RING, SIG_FLAGS, proc_ring, NULL); #endif SIGNAL(SIGHUP, SIG_FLAGS, sig_hup, NULL); SIGNAL(SIGINT, SIG_FLAGS, sig_bye, NULL); SIGNAL(SIGTERM, SIG_FLAGS, sig_bye, NULL); SIGNAL(SIGQUIT, SIG_FLAGS, sig_bye, NULL); #undef SIGNAL } void log_msg(int priority, int level, char *fmt, ...) { va_list p; char buf[MAXLINE]; va_start(p, fmt); vsprintf(buf, fmt, p); if (log_level >= level) if (debug || -1 == priority) { fflush(stdout); fprintf(stderr, PROG ": %s\n", buf); fflush(stderr); } else syslog(priority, buf); va_end(p); } void cback_log_msg(int level, char *fmt, ...) { va_list p; char buf[MAXLINE]; va_start(p, fmt); vsprintf(buf, fmt, p); log_msg(LOG_DEBUG, level, buf); va_end(p); } /* * is_ring_near -- is ring we just got nearer than msec_ignore msec to * the previous? */ int is_ring_near(struct timeval *tm_bef) { struct timeval tm; long msec; int ret; if (0 == msec_ignore) return FALSE; gettimeofday(&tm, NULL); msec = (tm.tv_sec - tm_bef->tv_sec) * 1000L + (tm.tv_usec - tm_bef->tv_usec) / 1000L; *tm_bef = tm; /* update the before time! */ ret = (msec <= msec_ignore); if (ret) log_msg(LOG_DEBUG, 10, "RI near (%ld msec) - dumped", msec); return ret; } /* * called via ringsm_process_timeout */ void seq_success(char *seq_cmd) { log_msg(LOG_INFO, 1, "launching: %s", seq_cmd); fork_cmd(seq_cmd); } /* * Called when a RING signal appears */ void proc_ring(int i) { static int rings = 1; int ret; if (do_onring) ring_cmd(); log_msg(LOG_DEBUG, 10, "RING #%d", rings++); ret = ringsm_process_a_ring(); if (!ret) log_msg(LOG_DEBUG, 100, "ignored ring #%d", rings-1); } void sig_child(int i) { int status; /* we should probably check the full exit status of the dead child */ wait(&status); } void sig_hup(int i) { int arg; if (!ringsm_parsed) return; log_msg(LOG_INFO, 1, "HUP received: resetting"); ringsm_reset(FALSE); /* close and reread config file */ ringsm_close(); if ((arg = ringsm_parse(config_file, &parse_an_arg_conf)) < 0) log_msg(LOG_ERR, 0, "error in config file, line %d - ignoring the next lines", -arg); if (modem >= 0) { close(modem); modem = modem_open(modem_file, TRUE, disable_echo); } ringsm_reset(TRUE); show_args(); } void sig_alarm(int i) { ringsm_process_timeout(); } void clean_exit(int code) { log_msg(LOG_INFO, 1, "Exit"); /*if (unlink(pidfilename) < 0 && errno != ENOENT) log_msg(LOG_WARNING, 1, "unable to delete pid file: %m"); pidfilename[0] = 0;*/ closelog(); exit(code); } void sig_bye(int i) { ringsm_reset(FALSE); clean_exit(0); } #if 0 void setdtr(int fd, int on) { int modembits = TIOCM_DTR; ioctl(fd, (on ? TIOCMBIS : TIOCMBIC), &modembits); } #endif int modem_open(char *file, int reopen, int disable_echo) { int fd = -1; if ((fd = open(file, O_RDONLY | O_NOCTTY | O_NDELAY)) < 0) { if (reopen) { log_msg(LOG_ERR, 1, "error reopening %s (%%m)", file); usleep(3*1000000); /* uses select - not SIGALRM */ return fd; } else { log_msg(-1, 0, "error opening modem device"); perror(NULL); exit(1); } } if (disable_echo) { struct termios tios; if (debug) log_msg(-1, 0, "disabling echo on modem device"); ioctl(fd, TCGETS, &tios); tios.c_lflag &= ~(ECHO); /*|ECHOE|ECHOK|ECHOKE|ECHOCTL*/ ioctl(fd, TCSETS, &tios); } return fd; } #if 0 void write_pid(void) { FILE *pidf; (void) sprintf(pidfilename, "%s%s.pid", _PATH_VARRUN, PROG); if ((pidf = fopen(pidfilename, "w")) != NULL) { fprintf(pidf, "%d\n", getpid()); (void) fclose(pidf); } else { log_msg(LOG_ERR, 1, "Failed to create pid file %s: %m", pidfilename); pidfilename[0] = 0; } } #endif void daemon_init(void) { int pid; if (debug) return; if ( (pid = fork()) < 0) { perror(NULL); exit(1); } else if (pid != 0) exit(0); /* parent goes */ /* child */ setsid(); chdir("/"); umask(S_IRWXG | S_IRWXO); close(STDIN_FILENO); close(STDOUT_FILENO); close(STDERR_FILENO); } void ring_cmd(void) { char *p; for (p = do_onring; *p != 0; p++) if (!isspace(*p)) break; if (*p == 0) /* all whitespace */ return; log_msg(LOG_INFO, 10, "running (per ring): %s", do_onring); fork_cmd(do_onring); } /* * fork_cmd --- fork a shell to execute command cmd * * Establish a "clean slate" first. */ void fork_cmd(char *cmd) { int pid; int fdnull; if ((pid = fork()) < 0) { log_msg(LOG_ERR, 1, "error forking for %s (%%m)", cmd); return; } else if (0 == pid) { /* child */ /* unblock signals we use - may be blocked here */ sigprocmask(SIG_UNBLOCK, &sig_mask, NULL); setsid(); close(STDIN_FILENO); close(STDOUT_FILENO); close(STDERR_FILENO); if (modem >= 0) close(modem); /* connect /dev/null to std{in/out/err} */ fdnull = open(_PATH_DEVNULL, O_RDWR); if (fdnull >= 0) { if (fdnull != 0) { dup2(fdnull, 0); close(fdnull); } dup2(0, 1); dup2(0, 2); } setuid(getuid()); setgid(getgid()); execl("/bin/sh", "sh", "-c", cmd, NULL); /* could not run cmd ; report it */ log_msg(LOG_ERR, 1, "error running: /bin/sh -c %s (%%m)", cmd); exit(1); } /* parent */ } int parse_an_arg(char opt, char *s, int conf_line) { switch (opt) { case 'a': do_onring = str_new(do_onring, s); break; case 'c': if (0 == conf_line) config_file = str_new(config_file, s); break; case 'd': debug++; log_level = 100; break; case 'i': msec_ignore = atoi(s); break; case 'l': log_level = atoi(s); break; case 'm': modem_file = str_new(modem_file, s); break; case 'n': if (0 == conf_line) { syntax_only++; debug++; } break; case 't': reset_timeout = atoi(s); break; case 'e': disable_echo++; break; case '?': case 'h': if (0 == conf_line) usage_and_die(); break; default: if (0 == conf_line) usage_and_die(); else log_msg(LOG_ERR, 0, "option %c error in conf file, line %d - ignoring", opt, conf_line); break; } return TRUE; } /* * parse_an_arg_conf -- callback for an argument parse (from config file) */ int parse_an_arg_conf(char opt, char *s, int line) { return parse_an_arg(opt, s, line); } void parse_args(int argc, char **argv) { int opt; opterr = 0; while ( (opt = getopt(argc, argv, "a:c:dl:i:l:m:ent:h?")) != EOF ) parse_an_arg((char) opt, optarg, 0); if (optind < argc) modem_file = str_new(modem_file, argv[optind]); } /* * str_new -- free old space if alloc'ed; alloc new and assign new value * XXX new is NULL or "" !! */ char * str_new(char *s, char *new) { int newsize = strlen(new) + 1; char *p; if (NULL == s) p = malloc(newsize); else p = realloc(s, newsize); strcpy(p, new); return p; } xringd/Makefile100644 476 3326 3156 6363523070 11661 0ustar ahasys# # Makefile -- xringd # # Copyright (c) 1995-1996 Angelo Haritsis. All rights reserved. # # $Id: Makefile,v 1.5 1996/02/17 15:50:07 ah Exp ah $ # VERSION=1.20 # where we install BINDIR=/usr/local/sbin MANDIR=/usr/local/man # Number of seconds (compiled-in) to wait after resetting the state machine # before accepting any new rings; can also be set on cmd line (-t) INITWAIT=15 # compiled-in configuration file; can stil be changed # from the command line CONF=/etc/xringd.conf # compiled-in modem device; can be specified on command line (-c) MODEM=/dev/modem #DBG=-DRINGSM_DUMP -DDEBUG # include ringsm debug code DEFS=-DVERSION=\"$(VERSION)\" -DMODEM_FILE=\"$(MODEM)\" -DCONF_FILE=\"$(CONF)\" -DINIT_TIMEOUT=$(INITWAIT) $(DBG) CC=gcc CFLAGS =-Wall -O2 -m486 $(DEFS) -s #CFLAGS = -g $(DEFS) LDFLAGS=-s #LDFLAGS=-g OBJ = ringsm.o xringd.o xringd: $(OBJ) $(CC) $(LDFLAGS) $(OBJ) -o $@ install: xringd -install -o root -g bin -m 755 xringd $(BINDIR) -install -o root -g root -m 755 xringd.8 $(MANDIR)/man8 @echo "!!! You also need a config file, eg. /etc/xringd.conf" dist: -mv -f xringd*.lsm xringd-$(VERSION).lsm > /dev/null 2>&1 -perl -pi -e "s/Version:\t[0-9.]+/Version:\t$(VERSION)/;s/xringd-[0-9]+\.[0-9]+/xringd-$(VERSION)/g;" xringd-$(VERSION).lsm #-perl -pi -e "s/xringd [0-9.]+/xringd $(VERSION)/;" README cp xringd*.lsm $(HOME)/ ( cd .. ; tar --exclude \*.o --exclude RCS --exclude test \ --exclude .gdb_history \ -zcvSf $(HOME)/xringd-$(VERSION).tgz xringd \ ) # util to show the internal kernel mdoem input counters uartcount: uartcount.c $(CC) $(CFLAGS) $? -o $@ clean: rm -f *.o xringd errors tags xringd/ringsm.c100644 476 3326 26603 6363522522 11707 0ustar ahasys/* * File: ringsm.c * * Synopsis: ring state machine * * System: unix * * Reads and parses a configuration file of lines of this form: * R secs[-secs] [ R secs[-secs] ] ... : command * which specify the pattern of rings+delays leading to the execution of * a command. * The "alphabet" of rings+delays can be used to create a relatively * interesting number of possible sequences which activate specific * commands when recognised. * * This module is suitable (through available hooks) for use in any getty * wishing to add this extra ring intelligence. Alarms are scheduled via * a callback so the caller of this module can take care of alarm reporting. * My intention is that people writing getty-like programs include this * functionality in their sw; I am open to any suggestion they might have. * * Copyright (c) 1995-1997 Angelo Haritsis. All rights reserved. * * 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. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program; see the file COPYING. If not, write to * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. * * $Id: ringsm.c,v 1.4 1996/02/17 15:50:07 ah Exp ah $ */ #include #include #include #include #include #include #include #include #include #include "ringsm.h" #define MAX_LINE_LEN 512 #define DBG(x) x /* for callback logging */ /* #define DBG(x) */ enum event_type { ev_RING, /* ring event (min,max time it may occur) */ ev_FINALTIMEOUT, /* final tmout event */ }; struct s_ringsm_event { enum event_type etype; time_t min, max; /* min, max time scale for this event */ }; struct s_ringsm_seq { int active; /* sequence still active? */ int ev_now; /* active event */ int num_events; struct s_ringsm_event *event; /* dynamic array of events */ char *cmd; /* command to run if succeded */ }; #define ringsm_ev_now(s) ( (s)->event[(s)->ev_now] ) #define ringsm_ev_next(s) ( (s)->event[(s)->ev_now+1] ) static time_t init_timeout = 10; /* normally set by caller */ static ringsm_cback success_callback = NULL; static alarm_cback alarm_callback = NULL; static log_cback log_cb = NULL; static time_t time_lastring = 0; static int doing_init_timeout = TRUE; /* dynamic array of sequences */ static struct s_ringsm_seq *sequence = NULL; static int num_seqs = 0; /* the sequence waiting for final timeout (NULL => none waiting) */ static struct s_ringsm_seq *timeout_seq = NULL; /* the max time waiting sequence (NULL => none waiting) */ static struct s_ringsm_seq *max_wait_seq = NULL; static void * xrealloc(void *p, int newsize) { if (!p) return malloc(newsize); return realloc(p, newsize); } static void schedule_final_timeout(struct s_ringsm_seq *seq) { time_t secs_until_run; seq->active = FALSE; /* timeouts can only be last sequence events */ /* schedule it if none already or one before but with later time */ secs_until_run = ringsm_ev_now(seq).min; if (NULL == timeout_seq || ringsm_ev_now(timeout_seq).min > secs_until_run) { timeout_seq = seq; /* keep a note of it */ (*log_cb)(10, "Scheduling T in %ld secs", secs_until_run); if (secs_until_run <= 0) secs_until_run = 1; (*alarm_callback)(secs_until_run); } } static inline int in_time(time_t diff, time_t t1, time_t t2) { if (0 == diff) return TRUE; if (t2 < t1) return FALSE; return (diff <= t2 && diff >= t1); } /* * ringsm_reset -- reset the state machine * * - do_tmout: if TRUE, wait init_timeout before (re)starting the state machine */ void ringsm_reset(int do_tmout) { struct s_ringsm_seq *seq; (*alarm_callback)(0); /* disable any pending alarms */ for (seq = sequence; seq && (seq < num_seqs + sequence); seq++) { seq->ev_now = -1; seq->active = TRUE; } if (do_tmout) { doing_init_timeout = TRUE; (*alarm_callback)(init_timeout); } timeout_seq = max_wait_seq = NULL; time_lastring = 0; DBG((*log_cb)(10, "RESET. Wait %ld sec", do_tmout ? init_timeout : 0)); } static void seq_completed(struct s_ringsm_seq *seq) { (*success_callback)(seq->cmd); ringsm_reset(TRUE); } static void do_new_seq(void) { sequence = xrealloc(sequence, (num_seqs+1) * sizeof(struct s_ringsm_seq)); sequence[num_seqs].num_events = 0; sequence[num_seqs].ev_now = -1; sequence[num_seqs].cmd = NULL; sequence[num_seqs].event = NULL; } static void do_new_event(enum event_type etype, int t1, int t2) { int num; assert(num_seqs > 0); num = sequence[num_seqs-1].num_events; sequence[num_seqs-1].event = xrealloc(sequence[num_seqs-1].event, (num + 1) * sizeof(struct s_ringsm_event)); sequence[num_seqs-1].event[num].etype = etype; sequence[num_seqs-1].event[num].min = t1; sequence[num_seqs-1].event[num].max = t2; sequence[num_seqs-1].num_events++; } static void eat_wspace(char **p) { while (**p && (**p == ' ' || **p == '\t')) (*p)++; } static int parse_range(char **p, int *t1, int *t2) { char *start; start = *p; while (isdigit(**p)) (*p)++; if (*p > start) *t1 = *t2 = atoi(start); else return FALSE; if (**p == '-') { start = ++(*p); while (isdigit(**p)) (*p)++; if (*p > start) *t2 = atoi(start); else return FALSE; } else if (**p != ':' && **p != ' ' && **p != '\t') return FALSE; eat_wspace(p); return TRUE; } /* * simple parser for the configuration file - check for a few errors * static line_now has the line number where parser is now */ static line_now; static int conf_parse(FILE *f, argparse_cback argparse) { char line[MAX_LINE_LEN], *p, *end; int len; int t1, t2; enum event_type etype; line_now = 0; while (fgets(line, MAX_LINE_LEN, f) != NULL) { line_now++; len = strlen(line); end = &line[--len]; *end = '\0'; if (len <= 0 || strspn(line,"# \t") == len) /* empty */ continue; p = line; eat_wspace(&p); if (*p == '#' || *p == '\n') /* comment or empty */ continue; eat_wspace(&p); if (*p == '-' && argparse) { /* it is an option */ char opt; opt = *++p; p++; eat_wspace(&p); /* p spans to end of line (\0) */ (*argparse)(opt, p, -line_now); /* callback */ continue; } /* first must be R */ if (*p++ != 'R') return FALSE; do_new_seq(); /* new sequence */ num_seqs++; while (p < end) { eat_wspace(&p); if (isdigit(*p)) { if (!parse_range(&p, &t1, &t2)) return(FALSE); } else return FALSE; eat_wspace(&p); if (*p == 'R') { etype = ev_RING; p++; } else if (*p == ':') { do_new_event(ev_FINALTIMEOUT, t1, t2); /* new event */ p++; eat_wspace(&p); sequence[num_seqs-1].cmd = (char *) strdup(p); break; } else return FALSE; do_new_event(etype, t1, t2); /* new event */ } } return TRUE; } /* * RET: -line_number where the parse error appears */ int ringsm_parse(char * config_file, argparse_cback argparse) { FILE *f; f = fopen(config_file, "r"); /* config_file MUST be readable */ if (!conf_parse(f, argparse)) { fclose(f); ringsm_close(); return -line_now; } fclose(f); ringsm_dump(); return 0; } /* * f_callback: function to call when a sequence reached completion * f_alarm: c/back alarm function: must have the nehaviour of alarm(2) !sysdep! */ void ringsm_init(time_t timeout, ringsm_cback f_callback, alarm_cback f_alarm, log_cback f_log) { init_timeout = timeout; success_callback = f_callback; alarm_callback = f_alarm; log_cb = f_log; ringsm_reset(TRUE); } void ringsm_close(void) { struct s_ringsm_seq *seq; for (seq = sequence; seq && (seq < num_seqs + sequence); seq++) { if (seq->cmd) free(seq->cmd); if (seq->num_events > 0 && seq->event) free(seq->event); } free(sequence); sequence = NULL; num_seqs = 0; } /* for debugging */ void ringsm_dump(void) { #ifdef RINGSM_DUMP struct s_ringsm_seq *seq; struct s_ringsm_event *ev; fprintf(stderr, "=====\n"); for (seq = sequence; seq && (seq < num_seqs + sequence); seq++) { fprintf(stderr, "SEQ: num_evs=%d, active=%c, ev_now=%d, cmd=%s\n", seq->num_events, seq->active? 'Y' : 'N', seq->ev_now, seq->cmd); fprintf(stderr, " Events:\n"); for (ev = seq->event; ev && (ev < seq->num_events + seq->event); ev++) { fprintf(stderr, "\ttype=%c min=%ld, max=%ld\n", (ev->etype==ev_RING) ? 'R' : 'E', ev->min, ev->max); } } #endif /* RINGSM_DUMP */ } /* * ringsm_process_timeout -- timeout (alarm) handler */ void ringsm_process_timeout(void) { (*alarm_callback)(0); if (doing_init_timeout) { /* initial timeout */ DBG((*log_cb)(10, "ALARM init")); doing_init_timeout = FALSE; return; } if (max_wait_seq) { DBG((*log_cb)(10, "ALARM max wait %ld", ringsm_ev_now(max_wait_seq).max)); ringsm_reset(TRUE); max_wait_seq = NULL; return; } DBG((*log_cb)(10, "ALARM final seq event timeout")); /* it is a final timeout of a sequence */ assert(timeout_seq != NULL); /* paranoia: check if spurious */ seq_completed(timeout_seq); timeout_seq = NULL; } /* * ringsm_process_a_ring -- got a RING; recalculate our state * could do with building a proper lexcal-analyser here but it might * be overkill; this is less code and works fast */ int ringsm_process_a_ring(void) { time_t diff; struct s_ringsm_seq *seq; int one_was_active = FALSE; time_t t1, t2, max_wait; struct s_ringsm_seq *max_wseq_now; if (doing_init_timeout) /* wait for initial timeout */ return FALSE; /* back to rings; cancel any pending final-timeout (or maxwait) event */ (*alarm_callback)(0); timeout_seq = NULL; if (0 == time_lastring) diff = 0; else diff = time(NULL) - time_lastring; DBG((*log_cb)(10, "time diff: %ld", diff)); time_lastring = time(NULL); max_wait = 0; /* max time to wait before resetting */ max_wait_seq = max_wseq_now = NULL; for (seq = sequence; seq < num_seqs + sequence; seq++) { if (!seq->active) continue; t1 = t2 = 0; if (seq->ev_now >= 0) { /* not the 1st ring */ t1 = ringsm_ev_now(seq).min; t2 = ringsm_ev_now(seq).max; } if (!in_time(diff, t1, t2)) seq->active = FALSE; else { /* ring in proper timing for this seq */ one_was_active = TRUE; DBG((*log_cb)(10, "seq %d: %ld IN [%ld->%ld]", seq-sequence, diff, t1, t2)); #if 0 if (seq->ev_now >= 0 && seq->ev_now == seq->num_events - 1) seq_completed(seq); #endif seq->ev_now++; /* next state is final timeout; run it */ if (seq->ev_now < seq->num_events && ringsm_ev_now(seq).etype == ev_FINALTIMEOUT) schedule_final_timeout(seq); else if (max_wait < ringsm_ev_now(seq).max) { max_wait = ringsm_ev_now(seq).max; max_wseq_now = seq; } } } /* no sequence completed; reset state machine (wait init_timeout) */ if (!one_was_active) { /* reset state machine */ ringsm_reset(TRUE); return TRUE; } #if 1 /* wait to the max time of all currently active events (if no final) */ if (NULL == timeout_seq && 0 != max_wait) { DBG((*log_cb)(100, "Scheduling max wait in %ld secs", max_wait)); max_wait_seq = max_wseq_now; (*alarm_callback)(max_wait); } #endif ringsm_dump(); return TRUE; } xringd/ringsm.h100644 476 3326 3244 6111374477 11675 0ustar ahasys/* * File: ringsm.h * * Synopsis: ring state machine * * System: unix * * Copyright (c) 1995-1996 Angelo Haritsis. All rights reserved. * * 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. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program; see the file COPYING. If not, write to * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. * * $Id: ringsm.h,v 1.5 1996/02/17 15:50:07 ah Exp ah $ */ #ifndef __RINGSM_INCLUDED #define __RINGSM_INCLUDED #ifndef TRUE #define TRUE (1==1) #define FALSE (!TRUE) #endif /* called when a sequence reaches success */ typedef void (*ringsm_cback) (char *seq_cmd); typedef int (*argparse_cback) (char opt, char *s, int line); /* called when an alarm needs to be scheduled for ringsm */ typedef unsigned int (*alarm_cback) (unsigned int); typedef void (*log_cback) (int level, char *fmt, ...); int ringsm_parse(char *config_file, argparse_cback argparse); void ringsm_init(time_t timeout, ringsm_cback f_callback, alarm_cback f_alarm, log_cback f_log); void ringsm_reset(int do_tmout); void ringsm_close(void); void ringsm_dump(void); void ringsm_process_timeout(void); int ringsm_process_a_ring(void); #endif /* __RINGSM_INCLUDED */ xringd/xringd.conf100644 476 3326 2052 6111362672 12355 0ustar ahasys# # xringd configuration file -- sample # # Line format: # R secs[-secs] [ R secs[-secs] ] ... : command # comments start with '#' in column 1 only # # Pay attention to avoid overlapping events; xringd will only do a # syntax (not a semantic) check on this file. # # Allow a "safe-exit" ring sequence (eg 3 consecutive rings cancels it all) # # Copyright (c) 1995-1996 Angelo Haritsis. All rights reserved. # # command line options (-c -n silently ignored) #-m /dev/ttyS1 #-a /usr/local/audio/bin/play /usr/local/lib/sounds/ring.au -a # rings this far are taken as one ring: #-i 500 # after resetting, time after we accept new sequences: #-t 15 # logging level: #-l 100 # 2 rings 10-25 sec apart followed by 30 secs silence: ppp connect with office1 R 10-25 R 30 : /etc/ppp/ppp.start office1 # 3 rings with 10-20 secs between each pair => ppp connect with office2 R 10-20 R 10-20 R 30 : /etc/ppp/ppp.start office2 # 2 nearish rings then 1 ring after 20-26 secs, followed by no ring in # 30 secs => heater on! R 1-6 R 10-16 R 8 : /usr/local/bin/turn-heater on xringd/xringd.8100644 476 3326 17632 6364757547 11654 0ustar ahasys.\" .\" Copyright (c) 1995-1996 Angelo Haritsis. .\" .\" xringd man page .\" .\" $Id$ .\" .\" SH section heading .\" SS subsection heading .\" LP paragraph .\" IP indented paragraph .\" TP hanging label .TH XRINGD 8 .SH NAME xringd \- The Linux extended modem ring server .SH SYNOPSIS .B xringd [ .I options ] [ .I modem_device_file ] .SH DESCRIPTION .LP The xringd Linux extended Ring server will listen on a modem device for specific ring-delay patterns (sequences). Each sequence, when fully recognised, will execute a command you have chosen (subject to usual unix permissions). Delays are in fact delay ranges. Sequences and commands are read from a a configuration file. .I xringd does not disturb your other modem programs, not even your getty. It coexists with them. .I xringd probes (asynchronously) for the actual RING signal on the serial line. .SH OPTIONS .TP .B -a \fI command_on_each_ring Run this command on every ring. Use perhaps to replace your boring phone ring. .TP .B -c \fI config_file Use an alternate configuration file. The default is .B /etc/xringd.conf .TP .B -d Run in debug mode (no daemon - logging = 100). .I xringd does not run as a daemon and produces log messages on standard error. .TP .B -h | -? See a mini usage info .TP .B -i msecs-ignored If consecutive rings have a time (in msec) distance less than this one, they are taken as one. For countries where a ring creates two sounds and modems that subsequently cause two changes on the serial RI line. Use this option to make two near RIs look as one to xringd. A value of 100-800 will most likely be the most appropriate. .TP .B -l loglevel Logging level. Default=1. Use 10+ for more info. When running as daemon you can use -l 10 or 100 to get debug messages via syslog(LOG_DEBUG, ...). 0 means NO logging at all. .TP .B -m \fI modem_device_file The modem device file (can also be given as the final argument). .TP .B -e Disables ECHO on modem device upon opening. This will avoid echo races reported with some modems. .TP .B -n Performs only a syntax check of its configuration file. It implies -d. Try this first when you write a new configuration file. .I xringd does not become a daemon and produces log messages on standard error. .TP .B -t \fI init_time After a reset (or the first time it is run), the time (in seconds) to wait until rings are accepted. Default: 15 .SH CONFIGURATION FILE The configuration file consists of lines of the following format: .LP .B R secs[-secs] [ R secs[-secs] ] ... : command .LP Each line is related to a sequence(pattern) that can be potentially matched. The .I command at the end gets executed if the sequence was fully matched. A full match is found if the delays between the rings are within the delay ranges given in the configuration line of a sequence. A full match will also reset the state machine. It will start accepting new rings as when run the first time. .I R means ring and it should .B always be the first symbol in a sequence. .LP Comment lines start with a ``#'' symbol at the beginning of the line. Empty lines are ignored. .LP Note that command lines options can also be included in the config file. A line should start with the '-' of an option. See example below. Options -c and -n are ignored in the config file. Options in the configuration file take precedence over the ones in the command line. .SH EXAMPLE CONFIGURATION .nf # xringd configuration file -- sample # -a /usr/local/audio/bin/play /usr/local/lib/sounds/ring.au -l 100 # # 2 rings 10-16 sec apart followed by 30 secs silence R 10-16 R 30 : /etc/ppp/ppp.start office1 # 3 rings 10-20 sec apart followed by 20 secs silence R 10-20 R 10-20 R 20 : /etc/ppp/ppp.start office2 # 2 nearish rings then 1 ring after 20-26 secs, silence for 30 secs R 1-5 R 20-26 R 30 : /usr/local/bin/turn-heater on .SH FILES .TP .B /etc/xringd.conf The default configuration file. .TP .B /dev/modem The default modem device used. .SH SIGNALS The following signals have the specified effect when sent to the .I xringd process. .TP .B SIGINT, SIGTERM Clean exit the server. .TP .B SIGUSR1 "Simulates" a RING as if it came from the modem. .TP .B SIGHUP Restart the internal machine ignoring any current state. Reread the config file. Close and reopen the modem device. If a syntax error is found in a line all the following lines are ignored. So when you restart, make sure you look at the log for any reported errors. A better way is to always "parse" your config file with "xringd -n" to check its syntax first. .SH NOTES At the moment, .I xringd is device dependent on Linux kernel 1.3.48+ and serial devices that support the TIOCMIWAIT, TIOCGICOUNT ioctl(2) calls. These were added by the same author to the Linux kernel so that a process can wait on a modem DCD,RI,DSR,CTS change on a serial port and can also read a kernel count of the interrupts on each one of these 4 lines. RI was used for this program. (Other possibilities exist in using this ioctl for instrumentation projects.) Note that these ioctls are only implemented for 16xx0 uarts now (Jan96). .LP You .B have to use a proper serial cable for this to work. A cable with all pins properly connected to your modem (especially the RI line for this program!) and serial port will save you any trouble. Internal modems should normally work. .LP If you activate a program which uses the modem after ringd it should normally .B flush the input buffer. In many cases you will have a few "RING" strings in your serial tty buffer that will most likely confuse a dialup script (eg. chat). .LP The richness of the ring-delay pattern "language" is not great. However, you certainly have many possibilities. Beware of overlaps though, and always have something that will "unlock" any current sequence (eq. 4 consecutive rings that safely exit from any current state). .LP If someone calls in while you are on the delay phase of your "pattern" then you are obviously out of luck. .LP Only tone dialing phones allow quick dial that can meet short timing restrictions possibly imposed by your configuration file. Make sure you use the redial button on the calling phone if there is one - you will be able to "dial" in about a second. Pulse dialers may introduce unexpected delays. If they are your only choice, use longer delays and wider delay ranges. .LP It was reported by a user that the "rings" you hear on the calling handset do not directly correspond to the ones actually heard on the receiving end. In the tests done with xringd in a few countries, the number of rings remained the same on calling and called set. Just leave each one of the rings you hear on the calling end to "settle" (do not break them before they finish). A delay between a ring heard on the caller set and the equivalent one on the called one was noticed but causes no problem for xringd. Feel free to send me your comments on this. .LP Many getty-like programs may be configured to pick up the phone on the first ring. Obviously, this will make xringd minimally useful. Make your getty to reply after 2-4 rings so that you have many possibilities open for xringd. .LP pppd (and probably some other programs) like to hold a tty in exclusive mode. Make sure you start xringd .B before such programs, otherwise it won't be allowed to open the modem device. Also, when such a program closes it may leave the line hung up. You need to restart (kill -HUP) xringd in such a case. It does not make sense to run xringd on a line which is permanently used for PPP/SLIP - such a line never "rings"! .LP Spurious interrupts (and thus pseudo-RINGs) may occur during modem switch on/off; run xringd .B after your modem is switched on. .LP It is highly recommended - for security reasons - to make the configuration file inaccessible (even for read) to anything but xringd. Treat it as a shadow-password-like file. It is very easy for anyone to call your number and activate a command, if they know a RING-delay sequence "password". So try not to disarm your home-alarm via it. You have been warned! .SH AUTHOR Angelo Haritsis (ah@doc.ic.ac.uk). xringd/TODO100644 476 3326 2051 6126317535 10706 0ustar ahasyso kernel bug (?): TIOCMIWAIT ioctl may wait on a port that is shutdown by serial driver. A fix suggested for now (serial.c): @@ -1074,6 +1088,7 @@ #endif save_flags(flags); cli(); /* Disable interrupts */ + wake_up_interruptible(&info->delta_msr_wait); /* * First unlink the serial port from the IRQ chain.. @@ -2000,6 +2015,8 @@ cli(); cnow = info->icount; /* atomic copy */ sti(); + if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr && cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) + return -EIO; if ( ((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) || ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) || ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) || o New command: dialer phone-number #times [modem-dev] Account for local PTT differences as much as possible (possible?). o Allow specification of day-of-week & time ranges for each rule; eg: 035;1000-1230,2300-0000 o Identify call waiting if phone is busy (if it is data/fax-busy call waiting should be normally disabled - so no way to identify). xringd/COPYING100644 476 3326 43076 6074246660 11307 0ustar ahasys GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 675 Mass Ave, Cambridge, MA 02139, USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS Appendix: How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 19yy 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. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) 19yy name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. xringd/CHANGES100644 476 3326 3536 6364516711 11223 0ustar ahasys* 17/07/97 (ah) - added the -e (disable echo) option for certain modems to avoid an "echo race" upon opening the device. - released 1.20 * 26/03/96 (ah) - a bug still lurked: need to reopen tty if a program like pppd closes and hangs up the same line. -HUP now reopens the device. You need to send a HUP signal to xringd when pppd closes. This is not great but I can only think of a kernel change for this now and I want to avoid it... - released 1.10 * 28/02/96 (ah) - more testing - very minor changes - released 1.00 * 17/02/96 (ah) - can now add command line options in the config file - SIGHUP now also re-reads the config file - logging (except ringsm_dump) now done by a callback into xringd.c so it can appear via syslog - added compilation check for Linux and kernel > 1.3.48 - released 0.96 * 13/02/96 (ah) - signal mask restored on spawned children - tested ok on getty/fax + xringd + dialout-ppp setups - added a max wait timeout between events (when no final scheduled) - released 0.95 * 24/01/96 (ah) - found the problem with EIO returned to ioctl (only with ppp or ldisc changers (?); after they close they set the line hung). - suggested a kernel change to tytso. - added a close and reopen on the modem device when EIO received for a quick temp fix (may introduce other probs? - my testing did not) - released 0.90 * 19/01/96 (ah) - hopefully some bugs are gone. - released 0.8 * 18/01/96 (ah) - added -i msecs option - daemon_init called late; errors are cought and reported earlier - split ringsm_init in 2 (one parse and one state machine init) - Added -l loglevel - More logging * 16/01/96 (ah) - added exit & report after an execl failure - a single: "R #" always run its command -> fixed - added alarm(0) where appropriate - released 0.6 * 08/01/96 (ah) - first public release : 0.5 (beta) xringd/README100644 476 3326 12033 6364516723 11123 0ustar ahasys Linux xringd by Angelo Haritsis GENERAL ------- How about having your home computer connect to your office or your provider, turn the air-conditioner on/off or activate _any_ command when you are not at home? Simple, you would say. Well, imagine now that your home modem does not have voice/DTMF-capabilities and you can use no modem to dialup your home. The only thing you ahve is a common telephone. Furthermore (even if you DO have a modem), you might wish your home computer to execute a choice of different commands _without_ its modem going off hook (consequently not paying for any connection). xringd, the Extended Ring Daemon can do it for you. And a bit more. It will monitor the serial line for RING signals and activate commands if specific "ring-delay sequences" are probed. It will also allow you to execute a command per ring probed. This allows you to replace your boring phoneset rings with sounds from your sound card or even with messages displayed on screens on machine(s) on your network! How do you actually signal your linux machine to execute different commands? You just make it receive rings and delays between them that follow specific patterns (as defined in a configuration file). Different patterns activate different commands. For example: Produce a single ring, wait from 10-25 seonds, produce another single ring. If no rings appear after this for 30 seconds your linux pc starts up a connection with your office1! You can build configuration files that can accept a wealth of ring-delay patterns and excute different commands upon recognition of each one. xringd will NOT affect any programs using the serial line. It can even coexist with your getty. Just make sure that your getty does not pick up the phone too early so that it gives you some time to "play" with your ring "patterns". It uses 2 new ioctls found on official Linux kernels of version 1.3.48 and up (ioctl's implemented by the same author). The most inventive minds will probably make this work without even using a modem (I have no idea how easy it is to produce a circuit which will assert the RI line on a UART when the telephone rings - perhaps use the UART already taken by the mouse - RI is not used on it!). If you have a useful idea on this, let me know so that I can include it with this package. But probably one could use an old 300/1200/2400bps modem and do the same job on lower cost! Make sure you read carefully the manual page provided. Please try this program and send me any comments or bug reports/patches via email. TO INSTALL ---------- Change default installation dirs in Makefile if you wish. Other defaults are mostly ok. Type: make install You can run xringd as ANY user. The commands that it can execute are subject to the permision of the user running xringd. Usually you run it as root. For debugging you should uncomment this line from Makefile #DBG=-DRINGSM_DEBUG and recompile ringsm.c Then you should run xringd as: xringd -c config -d Remember when building the final version to build ringsm.c with no debugging! HARDWARE -------- You will need a 16xx0x (most prevalent) uart (the needed kernel ioctls are currently implemented only for this family) and a fully connected modem cable if using an external modem (the RI line MUST be connected!). 16xx0x family includes: 8250 82450 16450 16450A 16c450 16550 16550A 16552 and compatible. KERNEL PATCH ------------ NB: This patch is NOT NEEDED! xinrgd has been tested to work fine on many setups and all the "stock" kernels after 1.3.48. It is just suggested as a quick thing to try if you have problems with xringd reporting errors endlessly. This kernel patch will make xringd not receive an EIO (or other) error on ioctl. The EIO case is taken care of in xringd. However, this patch will prevent any errors from the ioctl. drivers/char/tty_io.c, function hung_up_tty_ioctl(). Add before: return -EIO; if (cmd == TIOCMIWAIT || cmd == TIOCGICOUNT) return tty_ioctl(inode, file, cmd, arg); THANKS ------ For beta testing and useful comments, I must not forget to extend my thanks to the following people: Richard Huveneers Gary Houston Mattheos Papavasiliou Andrea Arcangeli ------------------------------------------------------------------- Copyright (c) 1995-1997 Angelo Haritsis. All rights reserved. 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. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. xringd/uartcount.c100644 476 3326 1204 6077036226 12405 0ustar ahasys/* uartcount: (linux) display the modem input interrupt counters */ #include #include #include #include #include int main(int argc, char **argv) { int fd; struct serial_icounter_struct c; if ((fd = open(argc == 2 ? argv[1] : "/dev/modem", O_RDONLY | O_NONBLOCK | O_NOCTTY)) < 0) { perror("cannot open modem device"); exit(1); } while (1) { if (ioctl(fd, TIOCGICOUNT, &c) != 0) exit(1); printf("Count: RI=%6d # CD=%6d # CTS=%6d # DSR=%6d\n", c.rng, c.dcd, c.cts, c.dsr); ioctl(fd, TIOCMIWAIT, TIOCM_RNG | TIOCM_CTS | TIOCM_DSR | TIOCM_CD); } } xringd/uartcount100755 476 3326 5520 6360544724 12176 0ustar ahasysELF`44 (444ԀԀ(((((hhh/lib/ld-linux.so.1     ؃"("h!"(( 28FD( LZЅ `4g<}(8>H"ąlibc.so.5ioctlprintf_DYNAMICperror__environ_init__libc_initenviron__fpu_control_finiatexit_GLOBAL_OFFSET_TABLE_exit__setfpucwopen_etext_edata__bss_start_end HLPTX \ `d5@%D%Hh%Lh%Ph%Th%Xh %\h(%`h0%dh8pYЃ1UUUPSQ̀D$(PdhЅj UPg[&&̀&S8=8t Ѓ;u[Í6ÐUPSU h ؅}uBPÃ}hjvEPh]TSy t jvEPEPEPEPh^hh\TS> 뱐S,=,t Ѓ;u[Í6Ð /dev/modemcannot open modem deviceCount: RI=%6d # CD=%6d # CTS=%6d # DSR=%6d hރ.>N  ЅĂ <@xGCC: (GNU) 2.7.2.1GCC: (GNU) 2.7.2GCC: (GNU) 2.7.2.101.0101.0101.01.symtab.strtab.shstrtab.interp.hash.dynsym.dynstr.rel.bss.rel.plt.init.plt.text.fini.rodata.data.ctors.dtors.got.dynamic.bss.comment.noteԀ#) @1Ă9 xxB @KQȃV``d\Ѕb؅Pj((p,,w44~<<,hh::*<fxringd/xringd-1.20.lsm100644 476 3326 1511 6364757623 12616 0ustar ahasysBegin3 Title: xringd Version: 1.20 Entered-date: 17JUL97 Description: The Linux Extended Ring Daemon. It matches "sequences" of a phonerings/timedelay confguration with rings and time delays coming from a modem. A fully matched sequence will execute a specified command. Thus, commands can be run while your modem stays on-hook. Does not affect getty's or other progs using the same port. Source and an aout bin are included. Keywords: xringd, serial, uart, ring daemon, callback Author: ah@doc.ic.ac.uk (Angelo Haritsis) Maintained-by: ah@doc.ic.ac.uk (Angelo Haritsis) Primary-site: sunsite.unc.edu /pub/Linux/system/Network/daemons 23k xringd-1.20.tgz Alternate-site: dolphin.doc.ic.ac.uk /pub/Linux/xringd 23k xringd-1.20.tgz Platforms: Linux 1.3.48+, RI serial cable line connected, 16xx0 uart Copying-policy: GPL End xringd/xringd100755 476 3326 30774 6364516630 11475 0ustar ahasysELF`4.4 (444ԀԀ+++,/lib/ld-linux.so.1CD&7"A-<*9,4;!C1 $8% #B? 63@2>5:=+ ')(/. 0 Xh"x""(1x;| AlScZTf"lؽTxȋ~~؋"""",0"(A @8"HF X"h"48x" ""\'Ȍ"/،"4">OE"R"X(,_8"fH"kXyh&x, &"4"$ȍ>؍""""("8"H"| xx#libc.so.5strcpyioctlgetgidvsprintf_DYNAMIC__ctype_berrno__strtol_internalusleep_IO_stdout_fgets_IO_stderr_execlperrordup2getuidmallocoptargopterrfflushsigaddset__environ_initalarm__libc_initenvironfprintfchdir__fpu_controloptindwaitumasksetgidopenlogcloselogreallocforksigactionstrdupgettimeofdayfopengetoptfclosetime__assert_failsysloggetpwuid_finisprintfatexitaccess_GLOBAL_OFFSET_TABLE_exit__setfpucwstrspnopensetsidsetuidcloseraisefreesigprocmask_errno_etext_edata__bss_start_endx ؽ ,048|?048<@D H L PTX\`dhlptx| !"#$%&'()*+,-./12ļ3ȼ5̼6м7Լ8ؼ9ܼ:;<=>5(%,%0h%4h%8h%<h%@h %Dh(%Hh0%Lh8p%Ph@`%ThHP%XhP@%\hX0%`h` %dhh%hhp%lhx%ph%th%xh%|h%h%h%h%hp%h`%hP%h@%h0%h %h%h%h%h%h%h%h%h %ļh(%ȼh0%̼h8p%мh@`%ԼhHP%ؼhP@%ܼhX0%h` %hh%hp%hxYЃ1UUUPSQ̀D$4P,he P[&&̀&S = t Ѓ;u[Í6ÐUUE tPR]Ð&P]ÍUSMAQ @\ܻtBR @9\~) ܻShj ȻЃ SĻЋ]]Í&US]jĻЋԻt!ػ9sButлPĻЃܻ̻1tPh!j ȻЋ]]Ðt&UE@PjH]Ít&Uػ@PԻP‰ԻػDDDD ]Í&&UWVSu} ػh5hhBhKZ6ԻZD[PBP¡ػԻP[4P|PML@e[^_]ÍvUVS]:tъ< t< u r3Byue[^] UWVSu&&ȍy>APxDPu9jj jS}} -uNx>X t&x>PxDPu9v4jj jSa}/ :t t t1&Ve[^_]Ít&&UWVS<MQhQ <0ЍX~hXQ9tV2<#w< oV8-} HXV<PPPM уv&PPj VP¡ػԻPt&1EC|S @LMTt+9U199}@ut&&ERMQW+ԻBЉPhۧj ȻЋCHK@9C~S @<uV&CS @D9E}E]ػԻ9}ujGv&=ܻu/}t)MQhjdȻЋM MQĻЃe[^_]ÐUXVSu] hPB h&P- SV jP< t-Ph1jjyTj%&hP@}PhLjj8j =tPhjjj j6PjP‰EPh]TR>thjjjmt&{F=u=~jjh. ~hh8hpP@~Phh@ h@,%P!%PPhԨh٨jjjEP$vhh\TPG th=|uhhj ō6&Phj jPPjPn 뀍t&EP7hj }=QPGt&&U]Í6&Uhh*hؽaj6USjh jhjhjh jhjhj hEEEj]SjZ }hjj]jEEjSj# }hjj&jEEjSj }hjjjEEjSj }hjjjaEРEjSj~ }hjjj*EРEjSjG }hjjJjEРEjSj }hjjj]]Ðt&UWVS}] UEPRVb 9|F=uu1hVh hؽhؽt&&VW[^_]ÍUVSuU EPRSSVjE[^]Í6&U VS]=u 1p&jUR u+3uU4uUE+CUЋuM3K9څtPhj j؍e[^] US]Sh1jjzS]]Í&U=t_Ph?j j50uHPhHjdj]UEPy]Í&U= t{hYjjjZhP}Phqjj|!PPjPmj9]Ðt&Ux]Ít&US]hjj;SUjj]Ít&&U$VS]h Sƃ}A} tShjjh-z_hǪjjjjlt&}t9=thjj ]ShTVeShTVe[^]ÍU=u_'}jj&t jt&hyj?jjj ]ÐU:t: xDA tB:u:tPhj jP]Ít&UVSuk}Vhjjt&&jhjMjfj_jX| PFjh5Ã|(tjSS jjjj%PQ%PfjVh?hBhEVhMjj,jV&&e[^]Í&USM U]5$Ф0Pp&QP!v&QP6dt&&jj jQv&jj jQ|v&QPDv&use&&jj jQD&/&u#7t&tRPhpjj9]]Í&UE URPEP]Í&UVS]u 0vhVSƒ t"j,PPA ԍ89}PPe[^]Ív&UWSU] 0ЅuPcǃt&PRǃSWe[_]ÐS=t Ѓ;u[Í6ÐScheduling T in %ld secsRESET. Wait %ld secdo_new_eventringsm.cnum_seqs > 0# rALARM initALARM max wait %ldALARM final seq event timeoutringsm_process_timeouttimeout_seq != ((void *)0)time diff: %ldseq %d: %ld IN [%ld->%ld]Scheduling max wait in %ld secs/etc/xringd.conf/dev/modemcannot open config file %serror in config file, line %dconfig file %s -> syntax okneeds Linux 1.3.48+, 16xx0 uartxringd; rings %ld msec or less apart ignored1.20version %s started by %s (uid %d)%sioctl restarting - signal%%m - reopening %sxringd version 1.20 - by A. Haritsis (ah@doc.ic.ac.uk) usage: %s [-a rngcmd] [-c cfgfile] [-d] [-h] [-i ignore_msec] [-l loglevel] [-m modem_dev] [-e] [-n] [-t initime] [modem_dev] error setting signal (%%m)xringd: %s RI near (%ld msec) - dumpedlaunching: %sRING #%dignored ring #%dHUP received: resettingerror in config file, line %d - ignoring the next linesExiterror reopening %s (%%m)error opening modem devicedisabling echo on modem device/running (per ring): %serror forking for %s (%%m)/dev/null-csh/bin/sherror running: /bin/sh -c %s (%%m)option %c error in conf file, line %d - ignoringa:c:dl:i:l:m:ent:h? ^n~΋ދ.>N^n~Όތ.>N^n~΍ލ.>N @ L  ( $t@GCC: (GNU) 2.7.2.1GCC: (GNU) 2.7.2GCC: (GNU) 2.7.2GCC: (GNU) 2.7.2.101.0101.0101.0101.01.symtab.strtab.shstrtab.interp.hash.dynsym.dynstr.rel.bss.rel.plt.init.plt.text.fini.rodata.data.ctors.dtors.got.dynamic.bss.comment.noteԀ#$)   @1LL(9 tt @B  K@@ QHH V``\'b'j+\p,w,~$$,,xx-0x-LL-P.