Merge branch 'master' of ssh://gapil.gnulinux.it/srv/git/gapil
[gapil.git] / sources / FifoReporter.c
index 5062e84c63143823c18c3cb774dc5c9454b98a4a..0ce8c37df0313cb39d07267077e424558c7adee1 100644 (file)
 #include <signal.h>     /* signal constants, types and functions */
 #include <fcntl.h>      /* file control functions */
 #include <sys/epoll.h>   /* Linux epoll interface */
+#include <sys/signalfd.h>/* Linux signalfd interface */
 
 #include "macros.h"
 #include "Gapil.h"
 
 /* Subroutines declaration */
 void usage(void);
+void die(char *);
 
 /* default name for the input fifo */
 char *fifoname = "/tmp/reporter.fifo";
 
+#define MAX_EPOLL_EV 10
+
 int main(int argc, char *argv[])
 {
 /* Variables definition */
-    int i, nread, t = 1;
+    int i, n, nread, t = 10;
     char buffer[4096];
     int fifofd, epfd, sigfd;
-    struct epoll_event epev;
     sigset_t sigmask;
-    char buffer[1024];
+    struct epoll_event epev, events[MAX_EPOLL_EV];
+    struct signalfd_siginfo siginf;
+    char *sig_names[] = { // signal name declaration from bits/signum.h
+       "-------       ", /*0        Filler for signal names array */
+       "SIGHUP        ", /*1        Hangup (POSIX).  */
+       "SIGINT        ", /*2        Interrupt (ANSI).  */
+       "SIGQUIT       ", /*3        Quit (POSIX).  */
+       "SIGILL        ", /*4        Illegal instruction (ANSI).  */
+       "SIGTRAP       ", /*5        Trace trap (POSIX).  */
+       "SIGABRT       ", /*6        Abort (ANSI).  */
+       "SIGBUS        ", /*7        BUS error (4.2 BSD).  */
+       "SIGFPE        ", /*8        Floating-point exception (ANSI).  */
+       "SIGKILL       ", /*9        Kill, unblockable (POSIX).  */
+       "SIGUSR1       ", /*10       User-defined signal 1 (POSIX).  */
+       "SIGSEGV       ", /*11       Segmentation violation (ANSI).  */
+       "SIGUSR2       ", /*12       User-defined signal 2 (POSIX).  */
+       "SIGPIPE       ", /*13       Broken pipe (POSIX).  */
+       "SIGALRM       ", /*14       Alarm clock (POSIX).  */
+       "SIGTERM       ", /*15       Termination (ANSI).  */
+       "SIGSTKFLT     ", /*16       Stack fault.  */
+       "SIGCHLD       ", /*17       Child status has changed (POSIX).  */
+       "SIGCONT       ", /*18       Continue (POSIX).  */
+       "SIGSTOP       ", /*19       Stop, unblockable (POSIX).  */
+       "SIGTSTP       ", /*20       Keyboard stop (POSIX).  */
+       "SIGTTIN       ", /*21       Background read from tty (POSIX).  */
+       "SIGTTOU       ", /*22       Background write to tty (POSIX).  */
+       "SIGURG        ", /*23       Urgent condition on socket (4.2 BSD).  */
+       "SIGXCPU       ", /*24       CPU limit exceeded (4.2 BSD).  */
+       "SIGXFSZ       ", /*25       File size limit exceeded (4.2 BSD).  */
+       "SIGVTALRM     ", /*26       Virtual alarm clock (4.2 BSD).  */
+       "SIGPROF       ", /*27       Profiling alarm clock (4.2 BSD).  */
+       "SIGWINCH      ", /*28       Window size change (4.3 BSD, Sun).  */
+       "SIGIO         ", /*29       I/O now possible (4.2 BSD).  */
+       "SIGPWR        ", /*30       Power failure restart (System V).  */
+       "SIGSYS        "  /*31       Bad system call.  */
+    };
     /*
      * Input section: decode parameters passed in the calling 
      * Use getopt function
@@ -98,68 +136,85 @@ int main(int argc, char *argv[])
     /* 
      * Initial setup 
      */
-    if (mkfifo(fifoname, 0622)) {  // create well known fifo if does't exist 
-       if (errno!=EEXIST) {
-           perror("Cannot create well known fifo");
-           exit(1);
-       }
-    }
-    epfd = epoll_create(5);       // initialize epoll
-    if (epfd < 0) {
-        perror("Failing on epoll_create");
-        exit(1);
-    }
-    if ((fifofd = open(fifoname, O_RDONLY|O_NONBLOCK)) < 0) {  // open fifo
-       perror("Cannot open read only well known fifo");
-       exit(1);
-    }
-    epev.data.fd = fifofd;        /* add fifofd to epoll */
-    epev.events = EPOLLIN;
-    if (epoll_ctl(epfd, EPOLL_CTL_ADD, fifofd, &epev)) {
-        perror("Failing in epoll_ctl");
-        exit(-1);
-    }
+    if ((epfd=epoll_create(5)) < 0)                          // epoll init
+       die("Failing on epoll_create");
+    /* Signal setup for signalfd and epoll use */
     sigemptyset(&sigmask);
     sigaddset(&sigmask, SIGINT);
     sigaddset(&sigmask, SIGQUIT);
     sigaddset(&sigmask, SIGTERM);
-    // blocking signal treated by signalfd to avoid default action
-    if (sigprocmask(SIG_BLOCK, &sigmask, NULL) == -1) {
-       perror("Failing in sigprocmask");
-       exit(1);
-    }
-    if ((sigfd=signalfd(-1, &sigmask, SFD_NONBLOCK)) == -1) {
-       perror("Failing in signalfd");
-       exit(-1);
-    }
-    epev.data.fd = sigfd;        /* add sigfd to epoll */
+    if (sigprocmask(SIG_BLOCK, &sigmask, NULL) == -1)       // block signals
+       die("Failing in signalfd");
+    if ((sigfd=signalfd(-1, &sigmask, SFD_NONBLOCK)) == -1) // take a signalfd
+       die("Failing in signalfd");
+    epev.data.fd = sigfd;                                   // add fd to epoll
     epev.events = EPOLLIN;
-    if (epoll_ctl(epfd, EPOLL_CTL_ADD, sigfd, &epev)) {
-        perror("Failing in epoll_ctl");
-        exit(-1);
+    if (epoll_ctl(epfd, EPOLL_CTL_ADD, sigfd, &epev))
+       die("Failing in signal epoll_ctl"); 
+    /* Fifo setup for epoll use */
+    if (mkfifo(fifoname, 0622)) {  // create well known fifo if does't exist 
+       if (errno!=EEXIST)
+           die("Cannot create well known fifo");
     }
-    
-    /* Main body: loop over requests */
+    if ((fifofd = open(fifoname, O_RDWR|O_NONBLOCK)) < 0)   // open fifo
+       die("Cannot open well known fifo");
+    epev.data.fd = fifofd;                                  // add fd to epoll
+    epev.events = EPOLLIN;
+    if (epoll_ctl(epfd, EPOLL_CTL_ADD, fifofd, &epev)) 
+       die("Failing in fifo epoll_ctl");
+    /* 
+     * Main body: wait something to report 
+     */
+    printf("FifoReporter starting, pid %i\n", getpid());
     while (1) {
-        if ((i = epoll_wait(epfd, &epev, 1, -1)) < 0) {
-            perror("error on epoll_wait");
-            exit(-1);
-        }
-       switch (epev.fd) {
-       /* 
-        * Handling options 
-        */ 
-       case sigfd:
-           // signals
-           break;
-       case fifofd:
-           // fifo
-           break;
-       default:                                       /* should not reached */
-           printf("something wrong, epoll activity on unknown %i file descriptor\n", epev.data.fd);
-           exit(-1);
+        if ((n=epoll_wait(epfd, events, MAX_EPOLL_EV, -1)) < 0) 
+           die("error on epoll_wait");
+       debug("Got %i events\n", n);
+       /* loop on epoll events */
+       for (i=0; i<n; i++) {    
+           if (events[i].data.fd == sigfd) {             // if signalfd ready 
+               printf("Signal received:\n");
+               while(nread=read(sigfd, &siginf, sizeof(siginf))) {
+                   if (nread < 0) {
+                       if (errno != EAGAIN) 
+                           die("signalfd read error");
+                       else 
+                           break;
+                   }
+                   if (nread != sizeof(siginf)) {
+                       printf("Error on signal data read, '\n");
+                       continue;
+                   }
+                   printf("Got %s\n", sig_names[siginf.ssi_signo]);
+                   printf("From pid %i\n", siginf.ssi_pid);
+                   if(siginf.ssi_signo == SIGINT) {      // SIGINT is exit
+                       printf("SIGINT means exit\n");
+                       unlink(fifoname);
+                       exit(0);
+                   }
+               }
+           } else if (events[i].data.fd == fifofd) {     // if fifofd ready 
+               printf("Message from fifo:\n");
+               while ((nread = read(fifofd, buffer, 5000))) {
+                   debug("read %i from fifofd %i, event %i\n", 
+                          nread, fifofd, events[i].data.fd );
+                   if (nread < 0) {
+                       if (errno != EAGAIN)
+                           die("fifo read error");
+                       else 
+                           printf("end message\n");
+                       break;
+                   }
+                   buffer[nread] = 0;
+                   if (fputs(buffer, stdout) == EOF)
+                       die("Error on terminal write");
+               }
+           } else {   // anything else is an error
+               printf("epoll activity on unknown %i file descriptor\n", 
+                      epev.data.fd);
+               exit(-1);
+           }
        }
-       
     }
     debug("Exiting for unknown reasons\n");
 }
@@ -167,18 +222,17 @@ int main(int argc, char *argv[])
  * routine to print usage info and exit
  */
 void usage(void) {
-    printf("Elementary fortune server\n");
+    printf("Elementary event reporter\n");
     printf("Usage:\n");
-    printf("  fortuned [-h] [-f] -n XXX \n");
-    printf("  -h   print this help\n");
-    printf("  -t filename   set fifo file\n");
+    printf("  reporterd [-h] [-f] -n XXX \n");
+    printf("  -h\t print this help\n");
+    printf("  -f\t filename   set fifo file\n");
     exit(1);
 }
 /*
- * Signal Handler to manage termination
+ * Print error message and exit routine
  */
-void HandSIGTERM(int signo) {
-    debug("Terminated by %s\n", strsignal(signo));
-    unlink(fifoname);
-    exit(0);
+void die(char * mess) {
+    perror(mess);
+    exit(-1);
 }