Merge branch 'master' of ssh://gapil.gnulinux.it/srv/git/gapil
[gapil.git] / sources / FifoReporter.c
1 /* FifoReporter.c
2  * 
3  * Copyright (C) 2011 Simone Piccardi
4  * 
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or (at
8  * your option) any later version.
9  * 
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License for more details.
14  * 
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18  */
19 /****************************************************************
20  *
21  * Program reporterd
22  * FIFO, signal, event and alarm reporter
23  * an example program for I/O multiplexing with signalfd and Co.
24  *
25  * Author: Simone Piccardi
26  * Jan. 2011
27  *
28  * Usage: reporterd -h give all info
29  *
30  ****************************************************************/
31 /* 
32  * Include needed headers
33  */
34 #include <sys/types.h>   /* primitive system data types */
35 #include <sys/stat.h>    /* file characteristics constants and functions */
36 #include <unistd.h>      /* unix standard library */
37 #include <stdio.h>       /* standard I/O library */
38 #include <stdlib.h>      /* C standard library */
39 #include <string.h>      /* C strings library */
40 #include <errno.h>       /* error definitions and routines */
41 #include <signal.h>      /* signal constants, types and functions */
42 #include <fcntl.h>       /* file control functions */
43 #include <sys/epoll.h>   /* Linux epoll interface */
44 #include <sys/signalfd.h>/* Linux signalfd interface */
45
46 #include "macros.h"
47 #include "Gapil.h"
48
49 /* Subroutines declaration */
50 void usage(void);
51 void die(char *);
52
53 /* default name for the input fifo */
54 char *fifoname = "/tmp/reporter.fifo";
55
56 #define MAX_EPOLL_EV 10
57
58 int main(int argc, char *argv[])
59 {
60 /* Variables definition */
61     int i, n, nread, t = 10;
62     char buffer[4096];
63     int fifofd, epfd, sigfd;
64     sigset_t sigmask;
65     struct epoll_event epev, events[MAX_EPOLL_EV];
66     struct signalfd_siginfo siginf;
67     char *sig_names[] = { // signal name declaration from bits/signum.h
68         "-------       ", /*0        Filler for signal names array */
69         "SIGHUP        ", /*1        Hangup (POSIX).  */
70         "SIGINT        ", /*2        Interrupt (ANSI).  */
71         "SIGQUIT       ", /*3        Quit (POSIX).  */
72         "SIGILL        ", /*4        Illegal instruction (ANSI).  */
73         "SIGTRAP       ", /*5        Trace trap (POSIX).  */
74         "SIGABRT       ", /*6        Abort (ANSI).  */
75         "SIGBUS        ", /*7        BUS error (4.2 BSD).  */
76         "SIGFPE        ", /*8        Floating-point exception (ANSI).  */
77         "SIGKILL       ", /*9        Kill, unblockable (POSIX).  */
78         "SIGUSR1       ", /*10       User-defined signal 1 (POSIX).  */
79         "SIGSEGV       ", /*11       Segmentation violation (ANSI).  */
80         "SIGUSR2       ", /*12       User-defined signal 2 (POSIX).  */
81         "SIGPIPE       ", /*13       Broken pipe (POSIX).  */
82         "SIGALRM       ", /*14       Alarm clock (POSIX).  */
83         "SIGTERM       ", /*15       Termination (ANSI).  */
84         "SIGSTKFLT     ", /*16       Stack fault.  */
85         "SIGCHLD       ", /*17       Child status has changed (POSIX).  */
86         "SIGCONT       ", /*18       Continue (POSIX).  */
87         "SIGSTOP       ", /*19       Stop, unblockable (POSIX).  */
88         "SIGTSTP       ", /*20       Keyboard stop (POSIX).  */
89         "SIGTTIN       ", /*21       Background read from tty (POSIX).  */
90         "SIGTTOU       ", /*22       Background write to tty (POSIX).  */
91         "SIGURG        ", /*23       Urgent condition on socket (4.2 BSD).  */
92         "SIGXCPU       ", /*24       CPU limit exceeded (4.2 BSD).  */
93         "SIGXFSZ       ", /*25       File size limit exceeded (4.2 BSD).  */
94         "SIGVTALRM     ", /*26       Virtual alarm clock (4.2 BSD).  */
95         "SIGPROF       ", /*27       Profiling alarm clock (4.2 BSD).  */
96         "SIGWINCH      ", /*28       Window size change (4.3 BSD, Sun).  */
97         "SIGIO         ", /*29       I/O now possible (4.2 BSD).  */
98         "SIGPWR        ", /*30       Power failure restart (System V).  */
99         "SIGSYS        "  /*31       Bad system call.  */
100     };
101     /*
102      * Input section: decode parameters passed in the calling 
103      * Use getopt function
104      */
105     opterr = 0;                              /* don't want writing to stderr */
106     while ( (i = getopt(argc, argv, "ht:f:")) != -1) {
107         switch (i) {
108         /* 
109          * Handling options 
110          */ 
111         case 'h':  
112             printf("Wrong -h option use\n");
113             usage();
114             return(0);
115             break;
116         case 'f':
117             fifoname = optarg;
118             break;
119         case 't':
120             t = strtol(optarg, NULL, 10);
121             break;
122         case '?':                                    /* unrecognized options */
123             printf("Unrecognized options -%c\n",optopt);
124             usage();
125         default:                                       /* should not reached */
126             usage();
127         }
128     }
129     /* ***********************************************************
130      * 
131      *           Options processing completed
132      *
133      *                Main code beginning
134      * 
135      * ***********************************************************/
136     /* 
137      * Initial setup 
138      */
139     if ((epfd=epoll_create(5)) < 0)                          // epoll init
140         die("Failing on epoll_create");
141     /* Signal setup for signalfd and epoll use */
142     sigemptyset(&sigmask);
143     sigaddset(&sigmask, SIGINT);
144     sigaddset(&sigmask, SIGQUIT);
145     sigaddset(&sigmask, SIGTERM);
146     if (sigprocmask(SIG_BLOCK, &sigmask, NULL) == -1)       // block signals
147         die("Failing in signalfd");
148     if ((sigfd=signalfd(-1, &sigmask, SFD_NONBLOCK)) == -1) // take a signalfd
149         die("Failing in signalfd");
150     epev.data.fd = sigfd;                                   // add fd to epoll
151     epev.events = EPOLLIN;
152     if (epoll_ctl(epfd, EPOLL_CTL_ADD, sigfd, &epev))
153         die("Failing in signal epoll_ctl"); 
154     /* Fifo setup for epoll use */
155     if (mkfifo(fifoname, 0622)) {  // create well known fifo if does't exist 
156         if (errno!=EEXIST)
157             die("Cannot create well known fifo");
158     }
159     if ((fifofd = open(fifoname, O_RDWR|O_NONBLOCK)) < 0)   // open fifo
160         die("Cannot open well known fifo");
161     epev.data.fd = fifofd;                                  // add fd to epoll
162     epev.events = EPOLLIN;
163     if (epoll_ctl(epfd, EPOLL_CTL_ADD, fifofd, &epev)) 
164         die("Failing in fifo epoll_ctl");
165     /* 
166      * Main body: wait something to report 
167      */
168     printf("FifoReporter starting, pid %i\n", getpid());
169     while (1) {
170         if ((n=epoll_wait(epfd, events, MAX_EPOLL_EV, -1)) < 0) 
171             die("error on epoll_wait");
172         debug("Got %i events\n", n);
173         /* loop on epoll events */
174         for (i=0; i<n; i++) {    
175             if (events[i].data.fd == sigfd) {             // if signalfd ready 
176                 printf("Signal received:\n");
177                 while(nread=read(sigfd, &siginf, sizeof(siginf))) {
178                     if (nread < 0) {
179                         if (errno != EAGAIN) 
180                             die("signalfd read error");
181                         else 
182                             break;
183                     }
184                     if (nread != sizeof(siginf)) {
185                         printf("Error on signal data read, '\n");
186                         continue;
187                     }
188                     printf("Got %s\n", sig_names[siginf.ssi_signo]);
189                     printf("From pid %i\n", siginf.ssi_pid);
190                     if(siginf.ssi_signo == SIGINT) {      // SIGINT is exit
191                         printf("SIGINT means exit\n");
192                         unlink(fifoname);
193                         exit(0);
194                     }
195                 }
196             } else if (events[i].data.fd == fifofd) {     // if fifofd ready 
197                 printf("Message from fifo:\n");
198                 while ((nread = read(fifofd, buffer, 5000))) {
199                     debug("read %i from fifofd %i, event %i\n", 
200                            nread, fifofd, events[i].data.fd );
201                     if (nread < 0) {
202                         if (errno != EAGAIN)
203                             die("fifo read error");
204                         else 
205                             printf("end message\n");
206                         break;
207                     }
208                     buffer[nread] = 0;
209                     if (fputs(buffer, stdout) == EOF)
210                         die("Error on terminal write");
211                 }
212             } else {   // anything else is an error
213                 printf("epoll activity on unknown %i file descriptor\n", 
214                        epev.data.fd);
215                 exit(-1);
216             }
217         }
218     }
219     debug("Exiting for unknown reasons\n");
220 }
221 /*
222  * routine to print usage info and exit
223  */
224 void usage(void) {
225     printf("Elementary event reporter\n");
226     printf("Usage:\n");
227     printf("  reporterd [-h] [-f] -n XXX \n");
228     printf("  -h\t print this help\n");
229     printf("  -f\t filename   set fifo file\n");
230     exit(1);
231 }
232 /*
233  * Print error message and exit routine
234  */
235 void die(char * mess) {
236     perror(mess);
237     exit(-1);
238 }