4e35cba367bb4d816cabf19b67f1aef8932482b8
[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     while (1) {
169         if ((n=epoll_wait(epfd, events, MAX_EPOLL_EV, -1)) < 0) 
170             die("error on epoll_wait");
171         debug("Got %i events\n", n);
172         /* loop on epoll events */
173         for (i=0; i<n; i++) {    
174             if (events[i].data.fd == sigfd) {             // if signalfd ready 
175                 printf("Signal received:\n");
176                 while(nread=read(sigfd, &siginf, sizeof(siginf))) {
177                     if (nread < 0) {
178                         if (errno != EAGAIN) 
179                             die("signalfd read error");
180                         else 
181                             break;
182                     }
183                     if (nread != sizeof(siginf)) {
184                         printf("Error on signal data read, '\n");
185                         continue;
186                     }
187                     printf("Got %s\n", sig_names[siginf.ssi_signo]);
188                     if(siginf.ssi_signo == SIGINT) {      // SIGINT is exit
189                         unlink(fifoname);
190                         exit(0);
191                     }
192                 }
193             } else if (events[i].data.fd == fifofd) {     // if fifofd ready 
194                 printf("Message from fifo:\n");
195                 while ((nread = read(fifofd, buffer, 5000))) {
196                     debug("read %i from fifofd %i, event %i\n", 
197                            nread, fifofd, events[i].data.fd );
198                     if (nread < 0) {
199                         if (errno != EAGAIN)
200                             die("fifo read error");
201                         else 
202                             printf("end message\n");
203                         break;
204                     }
205                     buffer[nread] = 0;
206                     if (fputs(buffer, stdout) == EOF)
207                         die("Error on terminal write");
208                 }
209             } else {   // anything else is an error
210                 printf("epoll activity on unknown %i file descriptor\n", 
211                        epev.data.fd);
212                 exit(-1);
213             }
214         }
215     }
216     debug("Exiting for unknown reasons\n");
217 }
218 /*
219  * routine to print usage info and exit
220  */
221 void usage(void) {
222     printf("Elementary event reporter\n");
223     printf("Usage:\n");
224     printf("  reporterd [-h] [-f] -n XXX \n");
225     printf("  -h\t print this help\n");
226     printf("  -f\t filename   set fifo file\n");
227     exit(1);
228 }
229 /*
230  * Print error message and exit routine
231  */
232 void die(char * mess) {
233     perror(mess);
234     exit(-1);
235 }