summaryrefslogtreecommitdiff
authorsandman <sandman>2002-07-01 22:28:22 (UTC)
committer sandman <sandman>2002-07-01 22:28:22 (UTC)
commitb34df43c4d141b6845a6251e8f52f7daf3d1a867 (patch) (unidiff)
treed829feab33887adcf47ac56f6625ea2fb6414281
parentcce43bef3e68b007f027f52328972b6b86af1098 (diff)
downloadopie-b34df43c4d141b6845a6251e8f52f7daf3d1a867.zip
opie-b34df43c4d141b6845a6251e8f52f7daf3d1a867.tar.gz
opie-b34df43c4d141b6845a6251e8f52f7daf3d1a867.tar.bz2
This is the release version with all debug stuff thrown out -- in return
I have heavily commented the code, so maybe someone else besides me culd get the hang of this programm.
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--core/opiealarm/opiealarm.c246
1 files changed, 117 insertions, 129 deletions
diff --git a/core/opiealarm/opiealarm.c b/core/opiealarm/opiealarm.c
index d96ffaf..70e5415 100644
--- a/core/opiealarm/opiealarm.c
+++ b/core/opiealarm/opiealarm.c
@@ -1,13 +1,13 @@
1/* opiealarm.c 1/*
2* This program is for extracting the event time/date out 2 * opiealarm.c
3* of /etc/resumeat and setting the RTC alarm to that time/date. 3 *
4* It is designed to run via a script just before the iPaq 4 * This program is for extracting the event time/date out
5* is suspended. 5 * of /etc/resumeat and setting the RTC alarm to that time/date.
6* 6 * It is designed to run via a script just before the iPAQ
7* Roughly based on ipaqalarm from Benjamin Long 7 * is suspended and right after the iPAQ resumes operation.
8* 8 *
9* written by Robert Griebl <sandman@handhelds.org> 9 * written and copyrighted by Robert Griebl <sandman@handhelds.org>
10*/ 10 */
11 11
12#include <stdio.h> 12#include <stdio.h>
13#include <linux/rtc.h> 13#include <linux/rtc.h>
@@ -28,8 +28,6 @@
28 #define PIDFILE "/var/run/opiealarm.pid" 28 #define PIDFILE "/var/run/opiealarm.pid"
29 #define APMFILE "/proc/apm" 29 #define APMFILE "/proc/apm"
30 30
31FILE *log; // debug only
32
33int resume ( int resuspend ); 31int resume ( int resuspend );
34int suspend ( int fix_rtc ); 32int suspend ( int fix_rtc );
35int main ( int argc, char **argv ); 33int main ( int argc, char **argv );
@@ -37,49 +35,28 @@ int fork_with_pidfile ( void );
37int kill_with_pidfile ( void ); 35int kill_with_pidfile ( void );
38void remove_pidfile ( void ); 36void remove_pidfile ( void );
39void usage ( void ); 37void usage ( void );
40void sig_handler ( int sig ); 38void sig_handler_child ( int sig );
41void error_msg_and_die ( int perr, const char *msg ); 39void sig_handler_parent ( int sig );
42int onac ( void ); 40int onac ( void );
43 41
44static int opiealarm_was_running; 42static int opiealarm_was_running;
45 43static pid_t parent_pid = 0;
46static pid_t startpid = 0;
47 44
48 45
49void log_msg ( const char *msg )
50{
51 if ( log ) {
52 fprintf ( log, msg );
53 fflush ( log );
54 }
55}
56 46
57void error_msg_and_die ( int perr, const char *msg ) 47void sig_handler_child ( int sig )
58{ 48{
59 if ( perr ) 49 // child got SIGUSR2 -> cleanup pidfile and exit
60 log_msg ( strerror ( errno ));
61 log_msg ( msg );
62
63 if ( getpid ( ) != startpid )
64 kill ( startpid, SIGUSR1 );
65 50
66 while ( 1 ) // pretend we are waiting on RTC, so opiealarm -r can kill us
67 sleep ( 1 );
68}
69
70
71void sig_handler ( int sig )
72{
73 if ( log ) {
74 log_msg ( "GOT SIGNAL -> EXITING\n" );
75 fclose ( log );
76 }
77 remove_pidfile ( ); 51 remove_pidfile ( );
78 exit ( 0 ); 52 exit ( 0 );
79} 53}
80 54
81void sig_handler_parent ( int sig ) 55void sig_handler_parent ( int sig )
82{ 56{
57 // parent got SIGUSR1 -> safe to exit now
58
59 parent_pid = 0;
83 exit ( 0 ); 60 exit ( 0 );
84} 61}
85 62
@@ -101,6 +78,11 @@ int fork_with_pidfile ( void )
101 pid = fork ( ); 78 pid = fork ( );
102 79
103 if ( pid > 0 ) { 80 if ( pid > 0 ) {
81 // We can not just exit now, because the kernel could suspend
82 // the iPAQ just before the child process sets the RTC.
83 // Solution: just wait for SIGUSR1 - the child process will
84 // signal this when it thinks it is safe to exit.
85
104 signal ( SIGUSR1, sig_handler_parent ); 86 signal ( SIGUSR1, sig_handler_parent );
105 while ( 1 ) 87 while ( 1 )
106 sleep ( 1000 ); 88 sleep ( 1000 );
@@ -111,8 +93,10 @@ int fork_with_pidfile ( void )
111 return 0; 93 return 0;
112 } 94 }
113 95
114 signal ( SIGTERM, sig_handler ); 96 // child process needs to react to SIGUSR2. This is sent when
115 signal ( SIGINT, sig_handler ); 97 // a new opiealarm process is started.
98
99 signal ( SIGUSR2, sig_handler_child );
116 100
117 // save pid 101 // save pid
118 if (( fp = fopen ( PIDFILE, "w" ))) { 102 if (( fp = fopen ( PIDFILE, "w" ))) {
@@ -138,21 +122,25 @@ int kill_with_pidfile ( void )
138{ 122{
139 FILE *fp; 123 FILE *fp;
140 pid_t pid; 124 pid_t pid;
125 int res = 0;
126
127 // terminate a running opiealarm child process
128 // return 1 if we really killed one
141 129
142 if (( fp = fopen ( PIDFILE, "r" ))) { 130 if (( fp = fopen ( PIDFILE, "r" ))) {
143 if ( fscanf ( fp, "%d", &pid ) == 1 ) 131 if ( fscanf ( fp, "%d", &pid ) == 1 )
144 return ( kill ( pid, SIGTERM ) == 0 ) ? 1 : 0; 132 res = ( kill ( pid, SIGUSR2 ) == 0 ) ? 1 : 0;
145 fclose ( fp ); 133 fclose ( fp );
146 } 134 }
147 return 0; 135 return res;
148} 136}
149 137
150void remove_pidfile ( void ) 138void remove_pidfile ( void )
151{ 139{
152 unlink ( PIDFILE ); 140 // child is about to exit - cleanup
153 141
154 signal ( SIGTERM, SIG_DFL ); 142 unlink ( PIDFILE );
155 signal ( SIGINT, SIG_DFL ); 143 signal ( SIGUSR2, SIG_DFL );
156} 144}
157 145
158 146
@@ -195,21 +183,26 @@ int main ( int argc, char **argv )
195 if ( !mode ) 183 if ( !mode )
196 usage ( ); 184 usage ( );
197 185
186
187 parent_pid = getpid ( );
188
198 // kill running opiealarm 189 // kill running opiealarm
199 startpid = getpid ( );
200 opiealarm_was_running = kill_with_pidfile ( ); 190 opiealarm_was_running = kill_with_pidfile ( );
201 remove_pidfile ( ); 191 remove_pidfile ( );
202 192
203 switch ( mode ) { 193 switch ( mode ) {
204 case 'r': return resume ( ac_resusp ); 194 case 'r': opt = resume ( ac_resusp );
195 break;
205 case 's': 196 case 's':
206 default : return suspend ( fix_rtc ); 197 default : opt = suspend ( fix_rtc );
198 break;
207 } 199 }
208 return 0; 200
201 parent_pid = 0;
202 return opt;
209 } 203 }
210 204
211 205
212
213int suspend ( int fix_rtc ) 206int suspend ( int fix_rtc )
214{ 207{
215 FILE *fp; 208 FILE *fp;
@@ -222,96 +215,80 @@ int suspend ( int fix_rtc )
222 215
223 if ( !fork_with_pidfile ( )) 216 if ( !fork_with_pidfile ( ))
224 return 3; 217 return 3;
225
226 log = fopen ( "/tmp/opiealarm.log", "w" );
227 log_msg ( "STARTING\n" );
228
229 218
230 if (!( fp = fopen ( "/etc/resumeat", "r" ))) 219 // we are the child process from here on ...
231 error_msg_and_die ( 1, "/etc/resumeat" );
232
233 if ( !fgets ( buf, sizeof( buf ) - 1, fp ))
234 error_msg_and_die ( 1, "/etc/resumeat" );
235 220
236 fclose ( fp ); 221 tzset ( ); // not sure if it is really needed -- it probably doesn't hurt ...
237 222
238 alrt = atoi ( buf ); 223 do { // try/catch simulation
239 224
240 if ( alrt == 0 ) 225 // read the wakeup time from /etc/resumeat
241 error_msg_and_die ( 0, "/etc/resumeat contains an invalid time description" ); 226 if (!( fp = fopen ( "/etc/resumeat", "r" )))
227 break; // ( 1, "/etc/resumeat" );
242 228
243 alrt -= 5; // wake up 5 sec before the specified time 229 if ( !fgets ( buf, sizeof( buf ) - 1, fp ))
244 230 break; // ( 1, "/etc/resumeat" );
245 231
246 if ( log ) 232 fclose ( fp );
247 fprintf ( log, "Setting RTC alarm to %d\n", alrt );
248
249 tzset ( );
250 233
251 alr = *gmtime ( &alrt ); 234 alrt = atoi ( buf ); // get the alarm time
252 235 if ( alrt == 0 )
253 // get system time 236 break; // ( 0, "/etc/resumeat contains an invalid time description" );
254 time ( &syst ); 237 alrt -= 5; // wake up 5 sec before the specified time
255 sys = *localtime ( &syst ); 238 alr = *gmtime ( &alrt );
239
240 time ( &syst );// get the UNIX system time
241 sys = *localtime ( &syst );
256 242
257 // Write alarm time to RTC 243 if (( fd = open ( "/dev/misc/rtc", O_RDWR )) < 0 ) // open the RTC device
258 if (( fd = open ( "/dev/misc/rtc", O_RDWR )) < 0 ) 244 break; // ( 1, "/dev/misc/rtc" );
259 error_msg_and_die ( 1, "/dev/misc/rtc" );
260 245
261 // get RTC time 246 memset ( &rtc, 0, sizeof ( struct tm )); // get the RTC time
262 memset ( &rtc, 0, sizeof ( struct tm )); 247 if ( ioctl ( fd, RTC_RD_TIME, &rtc ) < 0 )
263 if ( ioctl ( fd, RTC_RD_TIME, &rtc ) < 0 ) 248 break; // ( 1, "ioctl RTC_RD_TIME" );
264 error_msg_and_die ( 1, "ioctl RTC_RD_TIME" ); 249 rtct = mktime ( &rtc );
265 rtct = mktime ( &rtc );
266 250
267 fprintf ( log, "System time: %02d.%02d.%04d %02d:%02d:%02d DST: %d (TZ: %s, offset: %d)\n", sys. tm_mday, sys. tm_mon + 1, sys. tm_year + 1900, sys. tm_hour, sys. tm_min, sys. tm_sec, sys. tm_isdst, sys. tm_zone, sys. tm_gmtoff ); 251 rtc_sys_diff = ( syst - rtct ) - sys. tm_gmtoff; // calculate the difference between system and hardware time
268 fprintf ( log, "RTC time: %02d.%02d.%04d %02d:%02d:%02d DST: %d (TZ: %s, offset: %d)\n", rtc. tm_mday, rtc. tm_mon + 1, rtc. tm_year + 1900, rtc. tm_hour, rtc. tm_min, rtc. tm_sec, rtc. tm_isdst, rtc. tm_zone, rtc. tm_gmtoff );
269 fprintf ( log, "Wakeup time: %02d.%02d.%04d %02d:%02d:%02d DST: %d (TZ: %s, offset: %d)\n", alr. tm_mday, alr. tm_mon + 1, alr. tm_year + 1900, alr. tm_hour, alr. tm_min, alr. tm_sec, alr. tm_isdst, alr. tm_zone, alr. tm_gmtoff );
270
271 fprintf ( log, "System/RTC diff: %d seconds\n", ( syst - rtct ) - sys. tm_gmtoff );
272
273
274 rtc_sys_diff = ( syst - rtct ) - sys. tm_gmtoff;
275 252
276 if ( fix_rtc && (( rtc_sys_diff < -4 ) || ( rtc_sys_diff > 4 ))) { 253 if ( fix_rtc && (( rtc_sys_diff < -3 ) || ( rtc_sys_diff > 3 ))) {
277 struct tm set; 254 struct tm set;
278 255 set = *gmtime ( &syst );
279 set = *gmtime ( &syst ); 256
257 // if the difference between system and hardware time is more than 3 seconds,
258 // we have to set the RTC (hwclock --systohc), or alarms won't work reliably.
280 259
281 fprintf ( log, "Correcting RTC: %d seconds\n", rtc_sys_diff ); 260 if ( ioctl ( fd, RTC_SET_TIME, &set ) < 0 )
261 break; // ( 1, "ioctl RTC_SET_TIME" );
262 }
282 263
283 if ( ioctl ( fd, RTC_SET_TIME, &set ) < 0 ) 264 if ( ioctl ( fd, RTC_ALM_SET, &alr ) < 0 ) // set RTC alarm time
284 error_msg_and_die ( 1, "ioctl RTC_SET_TIME" ); 265 break; // ( 1, "ioctl RTC_ALM_SET" );
285 } 266 if ( ioctl ( fd, RTC_AIE_ON, 0 ) < 0 )
267 break; // ( 1, "ioctl RTC_AIE_ON" ); // enable RTC alarm irq
286 268
287 // set alarm time 269 // tell the parent it is safe to exit now .. we have set the RTC alarm
288 if ( ioctl ( fd, RTC_ALM_SET, &alr ) < 0 ) 270 kill ( parent_pid, SIGUSR1 );
289 error_msg_and_die ( 1, "ioctl RTC_ALM_SET" );
290 // enable alarm irq
291 if ( ioctl ( fd, RTC_AIE_ON, 0 ) < 0 )
292 error_msg_and_die ( 1, "ioctl RTC_AIE_ON" );
293
294 if ( log )
295 fprintf( log, "SIGUSR: pid %d - SLEEPING: pid %d\n", startpid, getpid ( ));
296 kill ( startpid, SIGUSR1 );
297 271
298 // wait for alarm irq 272 if ( read ( fd, buf, sizeof( unsigned long )) < 0 ) // wait for the RTC alarm irq
299 if ( read ( fd, buf, sizeof( unsigned long )) < 0 ) 273 break; // ( 1, "read rtc alarm" );
300 error_msg_and_die ( 1, "read rtc alarm" );
301 274
302 log_msg ( "WAKEUP\n" ); 275 // iPAQ woke up via RTC irq -- otherwise we would have received a SIGUSR2
276 // from the "resume instance" of opiealarm.
303 277
304 // disable alarm irq 278 if ( ioctl ( fd, RTC_AIE_OFF, 0 ) < 0 ) // disable RTC alarm irq
305 if ( ioctl ( fd, RTC_AIE_OFF, 0 ) < 0 ) 279 break; // ( 1, "ioctl RTC_AIE_OFF" );
306 error_msg_and_die ( 1, "ioctl RTC_AIE_OFF" );
307 280
308 close ( fd ); 281 close ( fd );
309
310 log_msg ( "EXITING\n" );
311 282
312 fclose ( log ); 283 remove_pidfile ( ); // normal exit
313 remove_pidfile ( ); 284 return 0;
285
286 } while ( 0 );
314 287
288 kill ( parent_pid, SIGUSR1 ); // parent is still running - it can exit now
289
290 while ( 1 ) // pretend that we are waiting on RTC, so opiealarm -r can kill us
291 sleep ( 1000 ); // if we don't do this, the "resuspend on AC" would be triggerd
315 return 0; 292 return 0;
316} 293}
317 294
@@ -321,6 +298,8 @@ int onac ( void )
321 FILE *fp; 298 FILE *fp;
322 int on = 0; 299 int on = 0;
323 300
301 // check the apm proc interface for AC status
302
324 if (( fp = fopen ( APMFILE, "r" ))) { 303 if (( fp = fopen ( APMFILE, "r" ))) {
325 int ac = 0; 304 int ac = 0;
326 305
@@ -338,30 +317,38 @@ int resume ( int resuspend )
338 317
339 // re-suspend when on AC (optional) when woken up via RTC 318 // re-suspend when on AC (optional) when woken up via RTC
340 319
341 if ( !opiealarm_was_running ) { // opiealarm -s got it's RTC signal -> wake up by RTC 320 if ( !opiealarm_was_running ) {
321 // if opiealarm -s didn't wake up via RTC, the old process gets killed
322 // by kill_by_pidfile(), which is recorded in opiealarm_was_running
323
342 if ( resuspend && onac ( )) { 324 if ( resuspend && onac ( )) {
343 time_t start, now; 325 time_t start, now;
344 char *argv [4]; 326 char *argv [4];
345 327
346 if ( !fork_with_pidfile ( )) 328 if ( !fork_with_pidfile ( ))
347 return 4; 329 return 4;
348 kill ( startpid, SIGUSR1 ); 330
331 // we can't wait for the resuspend timeout in the parent process.
332 // so we fork and tell the parent it can exit immediatly
333
334 kill ( parent_pid, SIGUSR1 );
349 335
350 // sleep <resuspend> sec (not less!) 336 // sleep <resuspend> seconds - this method is much more precise than sleep() !
351 time ( &start ); 337 time ( &start );
352 do { 338 do {
353 sleep ( 1 ); 339 sleep ( 1 );
354 time ( &now ); 340 time ( &now );
355 } while (( now - start ) < resuspend ); 341 } while (( now - start ) < resuspend );
356 342
357 if ( onac ( )) { // still on ac 343 if ( onac ( )) { // still on ac ?
358 // system() without fork
359 argv[0] = "qcop"; 344 argv[0] = "qcop";
360 argv[1] = "QPE/Desktop"; 345 argv[1] = "QPE/Desktop";
361 argv[2] = "suspend()"; 346 argv[2] = "suspend()";
362 argv[3] = 0; 347 argv[3] = 0;
363 348
364 // hard coded for now ...but needed 349 // hard coded for now ...but needed
350 // another way would be to simulate a power-button press
351
365 setenv ( "LOGNAME", "root", 1 ); 352 setenv ( "LOGNAME", "root", 1 );
366 setenv ( "HOME", "/root", 1 ); 353 setenv ( "HOME", "/root", 1 );
367 setenv ( "LD_LIBRARY_PATH", "/opt/QtPalmtop/lib", 1 ); 354 setenv ( "LD_LIBRARY_PATH", "/opt/QtPalmtop/lib", 1 );
@@ -369,6 +356,7 @@ int resume ( int resuspend )
369 356
370 remove_pidfile ( ); 357 remove_pidfile ( );
371 358
359 // no need for system() since this process is no longer usefull anyway
372 execv ( "/opt/QtPalmtop/bin/qcop", argv ); 360 execv ( "/opt/QtPalmtop/bin/qcop", argv );
373 361
374 perror ( "exec for qcop failed" ); 362 perror ( "exec for qcop failed" );