📄 apmsleep.c
字号:
/* apmsleep.c: * Suspend computer using APM and wake-up at given time using * the Real Time Clock (RTC) device. * * see man page apmsleep.1 for further details * * Possible applications: * - Run certain internet lookup programs at certain times * e.g. download email, news, etc. * - Send Faxes at night, but do not run laptop all night * - Start up in the morning to catch up old cron jobs * * Hint: * use 'date' to calculate suspend time including daylight saving * time correction. * * Possible future extensions (anyone?): * - correct handling daylight saving time jumps * - Set/restore '/dev/nvram' to set 'suspend to dram' option * - apmcron job scheduler to add flexibility * * Based on Paul Gortmacher's RTC Test/Example Program * Copyright (C) 1999, Peter Englmaier <ppe@mpe.mpg.de> * * Released under the GNU General Public License, version 2, * included herein by reference. * * $Log: apmsleep.c,v $ * Revision 1.1 1999/08/02 20:08:08 apenwarr * * * Integrated apmsleep, and added xbattery (but without Makefile support). * * Revision 0.5 1999/08/01 01:29:29 ppe * Now using the apm library * * Revision 0.4 1999/07/19 16:45:29 ppe * *** empty log message *** * * Revision 0.3 1999/07/19 16:10:38 ppe * Bug in wakeup time calculation corrected. * */#include <stdio.h>#include <linux/version.h>#if LINUX_VERSION_CODE > KERNEL_VERSION(2,2,0)#include <asm/spinlock.h>#endif#include <linux/mc146818rtc.h>#include <sys/ioctl.h>#include <sys/time.h>#include <sys/types.h>#include <fcntl.h>#include <unistd.h>#include <errno.h>#include <getopt.h>#include <sys/wait.h>#include <time.h>#include <apm.h>static char rcsid[]="$Id: apmsleep.c,v 1.1 1999/08/02 20:08:08 apenwarr Exp $";static char rcsrev[] = "$Revision: 1.1 $";void version() { printf("Version: %s (apmsleep 1.2)\n",rcsrev);}void usage() { printf("Usage:\n\n" "apmsleep [+]hh:mm\n\n" "Example:\n" " apmsleep +1:15 will suspend for one hour and 15 minutes\n" " apmsleep 8:00 will suspend until 8:00 am\n\n" "Bugs: Daylight saving jumps are not taken into account.\n" " Modem ring detection may trigger early wake-up.\n" " Does not work with Suspend to Disk.\n" "Bug reports to author Peter Englmaier <ppe@mpe.mpg.de>.\n");}int main(int argc, char **argv){ int i, rtcfd, retval; struct rtc_time rtc_tm; struct tm kernel_tm; time_t kernel_time, new_time, old_time; char *p, c; int apmfd=-1; /* APM device file descriptor */ int isoffset; /* setting time offset */ int hour, minute; /* alarm time requested */ int hour1, minute1; /* backup for precise_mode */ int flag; static int suspend_mode=0, wait_mode=0, debug_mode=0, precise_mode=0, noapm_mode=0; while (1) { /* int this_option_optind = optind ? optind : 1; */ int option_index = 0; static struct option long_options[] = { {"help", 0, 0, 'h'}, {"debug", 0, 0, 'd'}, {"version", 0, 0, 'V'}, {"suspend", 0, 0, 's'}, {"standby", 0, 0, 'S'}, {"wait", 0, 0, 'w'}, {"noapm", 0, 0, 'n'}, {"precise", 0, 0, 'p'}, {0,0,0,0} }; c = getopt_long(argc, argv, "hdVsSwnp", long_options, &option_index); if (c == -1) break; switch(c) { case 'h': usage(); exit(0); case 'V': version(); exit(0); case 'd': debug_mode=1; break; case 's': /*suspend*/ suspend_mode=0; break; case 'S': /*standby*/ suspend_mode=1; break; case 'n': /*noapm*/ noapm_mode=1; wait_mode=1; break; case 'w': wait_mode=!precise_mode; break; case 'p':/*precise*/ precise_mode=1; break; case '?': /*unknown option*/ exit(1); default: fprintf(stderr,"unknown option return %d\n", c); exit(1); } } /* end while (1) */ if (optind < argc) { if (optind+1 != argc) { fprintf(stderr,"To many arguments.\n"); usage(); exit(1); } p=argv[optind]; isoffset=0; if (p[0]=='+') { p++; isoffset=1;} if (2!=sscanf(p, "%d:%d", &hour, &minute)) { fprintf(stderr,"apmsleep: Bad argument(s)\n"); exit(1); } hour1=hour; minute1=minute; /* backup */ } else { fprintf(stderr,"apmsleep: missing argument.\n"); usage(); exit(1); } if (noapm_mode) suspend_mode=2; /* argument processing finished */ if (geteuid()!=0) { fprintf(stderr, "apmsleep: warning: This program must be run as root " "or have the SUID attribute set\n"); } /* check if APM is supported */ if (apm_exists()) { fprintf(stderr, "apmsleep: Your kernel does not support APM.\n"); fprintf(stderr, "apmsleep: Recompile kernel with APM and " "/dev/rtc support\n"); exit(1); } if (!noapm_mode) { apmfd=apm_open(); if (apmfd == -1) { fprintf(stderr, "apmsleep: Cannot open APM device.\n"); exit(1); } } rtcfd = open ("/dev/rtc", O_RDONLY); if (errno == EACCES) { fprintf(stderr, "apmsleep: You don't have permission to " "access /dev/rtc\n"); fprintf(stderr, "apmsleep: The program must be run as root " "or have the SUID attribute set\n"); exit(errno); } if (rtcfd == -1) { perror("/dev/rtc"); fprintf(stderr, "apmsleep: Your kernel does not support " "the real time clock device\n"); fprintf(stderr, "apmsleep: Recompile kernel with APM and " "/dev/rtc support\n"); exit(errno); } /* Read the RTC time/date */ retval = ioctl(rtcfd, RTC_RD_TIME, &rtc_tm); if (retval == -1) { perror("ioctl"); exit(errno); } /* Read Kernel time/date */ time(&kernel_time); kernel_tm=*localtime(&kernel_time); if (debug_mode) { printf("Current RTC time is %02d:%02d:%02d.\n", rtc_tm.tm_hour, rtc_tm.tm_min, rtc_tm.tm_sec); printf("Current local time is %02d:%02d:%02d.\n", kernel_tm.tm_hour, kernel_tm.tm_min, kernel_tm.tm_sec); } /* set alarm time in RTC */ if (isoffset) { hour+=(int)rtc_tm.tm_hour; minute+=(int)rtc_tm.tm_min; hour1+=(int)kernel_tm.tm_hour; minute1+=(int)kernel_tm.tm_min; } else { rtc_tm.tm_sec=0; /* here we take difference between RTC and localtime into account */ minute+=(int)rtc_tm.tm_min - (int)kernel_tm.tm_min; hour+=(int)rtc_tm.tm_hour - (int)kernel_tm.tm_hour; } while (minute<0) {minute +=60; hour--; } while (minute>=60) {minute -=60; hour++; } hour %= 24; rtc_tm.tm_min = minute; rtc_tm.tm_hour = hour; if (debug_mode) printf("Setting RTC alarm time to %02d:%02d:%02d.\n", hour, minute, rtc_tm.tm_sec); retval = ioctl(rtcfd, RTC_ALM_SET, &rtc_tm); if (retval == -1) { perror("ioctl"); exit(errno); } /* Read back the current alarm settings */ retval = ioctl(rtcfd, RTC_ALM_READ, &rtc_tm); if (retval == -1) { perror("ioctl"); exit(errno); } if (debug_mode) printf("RTC alarm time now set to %02d:%02d:%02d.\n", rtc_tm.tm_hour, rtc_tm.tm_min, rtc_tm.tm_sec); /* Enable alarm interrupts */ retval = ioctl(rtcfd, RTC_AIE_ON, 0); if (retval == -1) { perror("ioctl"); exit(errno); } /* Save time before suspending */ time(&new_time); kernel_time=new_time; if (fork()==0) { /* suspend system -- called from within a child, to make * sure we don't miss the time leap */ switch(suspend_mode) { case 0: apm_suspend(apmfd); break; case 1: apm_standby(apmfd); break; } exit(0); } if (debug_mode) { printf("Waiting until clock jumps\n"); fflush(stdout); } flag=1; /* Note: flag is used as exit value */ if (precise_mode) { /* wait for clock match alarm time */ if (debug_mode) printf("Wait for wakeup time\n"); do { int diff; /* Read Kernel time/date */ time(&kernel_time); kernel_tm=*localtime(&kernel_time); if (debug_mode) printf("Time: %02d:%02d:%02d, wakeup time: %02d:%02d:%02d\n", kernel_tm.tm_hour, kernel_tm.tm_min, kernel_tm.tm_sec, hour1, minute1, 0); diff= hour1*60 + minute1 - kernel_tm.tm_hour*60 - kernel_tm.tm_min; diff %= (24*60); flag=(diff!=0 && diff!=-1); if (flag) sleep(10); } while (flag); } else { /* wait for the actual sleep event */ do { old_time=new_time; sleep(2); time(&new_time); flag=difftime(new_time,old_time)<10.0; /* check for time out */ if (flag && wait_mode==0 && difftime(new_time,kernel_time)>120.0) break; /* timeout, flag is 1 */ } while (flag); if (flag) fprintf(stderr,"Time out -- no time leap happened\n"); else if (debug_mode) printf("Time leap detected\n"); } /* Waiting for child to finish */ wait(&i); /* Disable alarm interrupts */ retval = ioctl(rtcfd, RTC_AIE_OFF, 0); if (retval == -1) { perror("ioctl"); exit(errno); } close(rtcfd); if (!noapm_mode) close(apmfd); return flag;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -