pndevmapperd: don't do charge control too often
[pandora-libraries.git] / lib / pnd_dbusnotify.c
1
2 #include <stdio.h>          // for stdio, NULL
3 #include <stdlib.h>         // for malloc, etc
4 #include <unistd.h>         // for close
5 #include <time.h>           // for time()
6 #include <sys/types.h>      // for kill
7 #include <signal.h>         // for kill signal
8 #include <string.h>         // for bzero
9 #include <poll.h>           // for poll()
10
11 #include "pnd_dbusnotify.h"
12 #include "pnd_logger.h"
13
14 /* HACK HACK HACK
15  * Not yet doing a real libdbus implementation.
16  * First cut is using dbus-monitor; I'll work on a real dbus listener soon.
17  * HACK HACK HACK
18  */
19
20 typedef struct {
21   pid_t child_pid;         // pid for dbus-monitor
22   int fd [ 2 ];            // pipe fd pair
23 } pnd_dbusnotify_t;
24
25 #define MONITOR "/usr/bin/dbus-monitor"
26 #define MONARG1 "--system"
27 #define MONARG2 "interface=org.freedesktop.Hal.Device"
28 #define MONGREP "volume.is_mounted"
29
30 pnd_dbusnotify_handle pnd_dbusnotify_init ( void ) {
31   pnd_dbusnotify_t *p;
32
33   // get thee a handle
34   // and I will brandish it for Zo Kath Ra
35
36   p = malloc ( sizeof(pnd_dbusnotify_t) );
37
38   if ( ! p ) {
39     return ( NULL ); // uhh..
40   }
41
42   bzero ( p, sizeof(pnd_dbusnotify_t) );
43
44   // can we make a pipe?
45   if ( pipe ( p -> fd ) == -1 ) {
46     free ( p );
47     return ( NULL );
48   }
49
50   // spawn child process
51   p -> child_pid = fork();
52
53   if ( p -> child_pid == -1 ) {
54     free ( p );
55     return ( NULL ); // borked
56
57   } else if ( p -> child_pid == 0 ) {
58     // child
59
60     close ( p -> fd [ 0 ] ); // ditch stdin on child
61     dup2 ( p -> fd [ 1 ], 1 ); // assign write-end of pipe to stdout
62     close ( p -> fd [ 1 ] ); // we don't need this anymore anyway
63     execlp ( MONITOR, MONITOR, MONARG1, MONARG2, NULL );
64
65     exit ( 1 ); // damnit
66
67   } else {
68     // parent
69
70     close ( p -> fd [ 1 ] ); // ditch write end, we're a grepper
71
72   } // child or parent?
73
74   return ( p );
75 }
76
77 void pnd_dbusnotify_shutdown ( pnd_dbusnotify_handle h ) {
78   pnd_dbusnotify_t *p = (pnd_dbusnotify_t*) h;
79
80   // free up
81   close ( p -> fd [ 0 ] ); // kill reader end of pipe
82
83   // destroy child process
84   kill ( p -> child_pid, SIGKILL );
85
86   free ( p );
87
88   return;
89 }
90
91 unsigned char pnd_dbusnotify_rediscover_p ( pnd_dbusnotify_handle h ) {
92   pnd_dbusnotify_t *p = (pnd_dbusnotify_t*) h;
93   int r;
94   struct pollfd fds [ 1 ];
95
96   fds [ 0 ].fd = p -> fd [ 0 ]; // read side of pipe
97   fds [ 0 ].events = POLLIN | POLLPRI /* | POLLRDHUP */;
98   fds [ 0 ].revents = 0;
99
100   r = poll ( fds, 1, 0 /* timeout*/ );
101
102   if ( r < 0 ) {
103     // error
104     // should rebuild a new child process
105     return ( 0 );
106
107   } else if ( r == 0 ) {
108     // no input on the pipe
109     return ( 0 );
110
111   } // activity
112
113   // something on the pipe, lets check it
114
115   if ( fds [ 0 ].revents & ( POLLERR|POLLHUP/*|POLLRDHUP*/ ) ) {
116     // bad
117     // should rebuild a new child process
118     return ( 0 );
119   }
120
121   // something useful on the pipe
122   char buf [ 4096 ];
123   int readcount;
124
125   readcount = read ( fds [ 0 ].fd, buf, 4000 );
126
127   if ( readcount < 0 ) {
128     // error
129     return ( 0 );
130   }
131
132   // terminate the string
133   *( buf + readcount + 1 ) = '\0';
134
135   if ( strstr ( buf, MONGREP ) != NULL ) {
136     return ( 1 );
137   }
138
139   return ( 0 );
140 }