⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 apmd.c

📁 电源管理程序
💻 C
📖 第 1 页 / 共 2 页
字号:
    time(&pre_suspend_time);    pre_suspend_percentage = apmi->battery_percentage;    /* Logging is okay here since the sync() happens afterward */    switch (event)    {    case APM_SYS_STANDBY:	apmd_log(event, "System Standby");	break;    case APM_USER_STANDBY:	apmd_log(event, "User Standby");	break;    }    return apm_standby(apmd_fd);}/* Resume handler.  Call the proxy, then update the battery status.  * This also handles the update time function, which does much of the * same thing.  */static void apmd_resume(apm_event_t event, apm_info * apmi){    char msg[512];    int len = 0;    ADEBUG(4, "0x%04x\n", event);    apmd_call_proxy(event, apmi);    /* Logging */    switch (event)    {    case APM_NORMAL_RESUME:	len = sprintf(msg, "Normal Resume");	break;    case APM_STANDBY_RESUME:	len = sprintf(msg, "Standby Resume");	break;    case APM_CRITICAL_RESUME:	len = sprintf(msg, "Critical Resume");	break;    case APM_UPDATE_TIME:	len = sprintf(msg, "Update Time");	break;    }    last_charging_status = apmi->battery_status;    time(&post_suspend_time);    /* Establish a minor and major checkpoint */    major_checkpoint = post_suspend_time;    major_percentage = apmi->battery_percentage;    minor_checkpoint = post_suspend_time;    minor_percentage = major_percentage;    /* Update the battery status */    if (event != APM_UPDATE_TIME && pre_suspend_time && post_suspend_time)    {	int dt = post_suspend_time - pre_suspend_time;	int dp = apmi->battery_percentage - pre_suspend_percentage;	if (dt > 0)	    len += sprintf(msg + len, " after %s", apm_time(dt));	/* describe in days if the suspend was for a long time */	if (dt > 60 * 60 * RESUME_HOURS	    && apmi->battery_percentage > 0 && pre_suspend_percentage > 0	    && last_charging_status != 0x03 && dp < 0)	{	    len += sprintf(msg + len, ", %.2f%%/day",			   ((double) dp / (double) dt) * 60. * 60. * 24.);	}    }    len += sprintf(msg + len, " (%d%% %s) %s power",		    apmi->battery_percentage,		    apm_time_nosec(apmd_time(apmi)),		    ac_descr(apmi->ac_line_status));    apmd_log(event, msg);}/* "low" battery handler -- BIOS decides what "low" means, may send alert; * APMD has a more configurable notion, dealt with similarly. */static void apmd_low_battery(apm_event_t event, apm_info * apmi){    char msg[512];    ADEBUG(4, "0x%04x\n", event);    sprintf(msg, "Battery Low Notification from %s (%d%% %s)",	    (event == APM_LOW_BATTERY ? "APM BIOS" : "apmd"),	    apmi->battery_percentage, apm_time_nosec(apmd_time(apmi)));    if (!quiet)	warn(msg);}/* Check battery status, and decide whether to log or not. */static void apmd_check_power(apm_event_t event, apm_info * apmi){    int	dt, dp, logflag = 0, len = 0, warning = 0;    int charging = IS_CHARGING(*apmi);    char msg[512];    double rate;    static int last_battery_status = 0;    static int last_ac_status = -1;    ADEBUG(4, "0x%04x\n", event);    /* Call proxy and perform special logging as needed */    switch (event)    {    case APM_POWER_STATUS_CHANGE:        /* Power status changes can happen a LOT ... e.g. for each change of	 * estimated battery life (minutes, seconds, percent) when charging	 * or discharging, battery full, empty, add/remove battery, etc.	 * Invoking the proxy on each change can use up battery power fast,	 *	 * So we just report if AC status changes -- the main use for this is	 * to make sure that power usage is reduced when running on batteries.	 * (When the kernel tracks multiple batteries that might be a good	 * time to update this to report just a bit more.)	 */	if (apmi->ac_line_status != last_ac_status) {	    apmd_call_proxy(event, apmi);	    sprintf(msg, "Now using %s Power", ac_descr(apmi->ac_line_status));	    apmd_log(event, msg);	    apmd_power_reset(event, apmi);	    last_ac_status = apmi->ac_line_status;	}	break;    case APM_LOW_BATTERY:synthetic_low_battery:	apmd_call_proxy(event, apmi);	last_battery_status = 1;	apmd_low_battery(event, apmi);	break;#ifdef APM_CAPABILITY_CHANGE    case APM_CAPABILITY_CHANGE:	apmd_call_proxy(event, apmi);	apmd_log(event, "Capability Change");	break;#endif    }    /* Check for "low" battery status.  Note: this is not an infinite loop     * because last_battery_status is guaranteed to change.      */    if (!charging && last_battery_status != 1 && apmi->battery_status == 1)    {    	event = APM_LOW_BATTERY;	goto synthetic_low_battery;    }    /* Reset the low battery state if we are now charging, etc. */    if (charging || apmi->battery_status != 1)    {	last_battery_status = 0;    }    /* If the BIOS doesn't keep track of the battery, no point going further */    if (apmi->battery_percentage < 0)	return;    /* If battery is not charging and battery percentage is changing     * AND below apmd's threshold then give low battery warning.  Both     * BIOS and APMD originate warnings, and generally at different     * percentages; the BIOS one is fixed and not always useful.     */    if (!charging	    && apmi->battery_percentage <= warn_level	    && (abs(minor_percentage - apmi->battery_percentage) > 0		|| apmi->battery_percentage == 0)	    && !quiet)	warning = 1;    dt = time(0) - major_checkpoint;    dp = major_percentage - apmi->battery_percentage;    /* If no warning, or no change since last logged message, then do nothing */    if (!warning && (dt == 0 || dp == 0))	return;    /* Decide whether to log the battery status.     * First check is when battery is fully drained or charged     */    logflag = (apmi->battery_percentage != minor_percentage)	&& ((apmi->battery_percentage == 0)		|| (apmi->battery_percentage == 100));    /* Second check is when battery percentage has decreased by      * percent_change.     */    logflag = logflag || (abs(minor_percentage - apmi->battery_percentage) >=			  (percent_change > 1 ? percent_change : 1));        /* Logging is triggered when any check is satisfied. */    if (!logflag && !warning)	return;    /* We are logging (either normal, or a warning) so establish a minor     * checkpoint -- reduces redundant logging, to no more than once per     * percentage point change.     */    minor_percentage = apmi->battery_percentage;    minor_checkpoint = time(0);    rate = (double) dp / (double) dt;    /* If we're warning about low batteries, do so ... */    if (warning != 0) {	sprintf(msg, "Battery warning (%d%% %s)",	      apmi->battery_percentage, apm_time_nosec(apmd_time(apmi)));	warn(msg);	/* ... if that's all we're doing, finish */	if (!logflag)	    return;    }    /* Begin composing the log message.  First part is charging status,     * followed by rate (in percent per minute)     */    len = sprintf(msg, "%s: %f",		  charging ? "Charge" : "Battery",		  rate * 60.0);    /* Time from full charge, or time from last power status change (ie,     * a major checkpoint)     */    if ((!charging && major_percentage == 100)	|| (charging && major_percentage == 0))	len += sprintf(msg + len, " %s", apm_time_nosec(dt));    else	len += sprintf(msg + len, " (%s)", apm_time_nosec(dt));    /* Computation of predicted battery lifetime */    if (charging)    {	len += sprintf(msg + len, " %s",		 apm_time_nosec((int) ((100.0 - apmi->battery_percentage)				       / -rate)));    }    else    {	len += sprintf(msg + len, " %s",		apm_time_nosec((int) (apmi->battery_percentage / rate)));    }    sprintf(msg + len, " (%d%% %s)",	    apmi->battery_percentage, apm_time_nosec(apmd_time(apmi)));    apmd_log(APMD_BATTERY, msg);    /* Establish a major checkpoint if we have become fully charged or     * fully drained      */    if ((apmi->battery_percentage == 0 && major_percentage != 0)	|| (apmi->battery_percentage == 100 && major_percentage != 100))    {	minor_percentage = apmi->battery_percentage;	minor_checkpoint = time(0);    }}static void sig_handler(int sig){    syslog(LOG_INFO, "Exiting");    apmd_call_proxy(APMD_STOP, 0);    unlink(PID_FILE);    exit(0);}int main(int argc, char **argv){    int debug = 0;    int c;    int fd;    int pid;    FILE *str;    apm_info apminfo, *apmi;    apm_event_t events[MAX_EVENTS];    static struct option longopts[] =    {	{"verbose", 0, 0, 'v'},	{"quiet", 0, 0, 'q'},	{"version", 0, 0, 'V'},	{"debug", 0, 0, 'd'},	{"percentage", 1, 0, 'p'},	{"warn", 1, 0, 'w'},	{"wall", 0, 0, 'W'},	{"check", 1, 0, 'c'},	{"apmd_proxy", 1, 0, 'P'},	{"help", 0, 0, '?'},	{NULL, 0, 0, 0},    };    switch (apm_exists())    {    case 1:	fprintf(stderr, "No APM support in kernel\n");	exit(1);    case 2:	fprintf(stderr, "Old APM support in kernel\n");	exit(2);    }    while ((c = getopt_long(argc, argv,		/* "-d" not documented */		"uVvqdp:w:Wc:P:?",		longopts, NULL))	   != -1)	switch (c)	{	case 'V':	    fprintf(stderr, "apmd version %s\n", VERSION);	    exit(0);	    break;	case 'v':	    ++verbose;	    break;	case 'q':	    ++quiet;	    break;	case 'd':	    ++debug;	    break;	case 'p':	    percent_change = atoi(optarg);	    break;	case 'w':	    warn_level = atoi(optarg);	    break;	case 'W':	    ++wall;	    break;	case 'u':	    fprintf(stderr,		    "WARNING:\n"		    "  apmd's internal clock setting has been replaced by the "		    "apmd_proxy!\n"		    "  To set the clock to UTC, you must edit the apmd_proxy "		    "program.\n\n");	    break;	case 'c':	    check_power_time = atoi(optarg);	    break;	case 'P':	    apmd_proxy = optarg;	    break;	case '?':	default:	    usage();	    break;	}    if (!access(PID_FILE, R_OK))    {	if ((str = fopen(PID_FILE, "r")))	{	    fscanf(str, "%d", &pid);	    fclose(str);	    	    if (!kill(pid, 0) || errno == EPERM)	    {		fprintf(stderr,			"An apmd is already running as process %d:\n"			"If it is no longer running, remove %s\n",			pid, PID_FILE);		exit(1);	    }	}    }    if ((apmd_uid = getuid()))    {	fprintf(stderr, "apmd: must be run as root\n");	exit(1);    }    openlog("apmd", (debug ? LOG_PERROR : 0) | LOG_PID | LOG_CONS, LOG_DAEMON);    if (signal(SIGINT, SIG_IGN) != SIG_IGN)	signal(SIGINT, sig_handler);    if (signal(SIGQUIT, SIG_IGN) != SIG_IGN)	signal(SIGQUIT, sig_handler);    if (signal(SIGTERM, SIG_IGN) != SIG_IGN)	signal(SIGTERM, sig_handler);    if (!debug)    {				/* detach */	if ((pid = fork()))	{			/* parent */	    if ((str = fopen(PID_FILE, "w")))	    {		fprintf(str, "%d\n", pid);		fclose(str);	    }	    exit(0);	}	/* child */	if (pid < 0)	{	    syslog(LOG_INFO, "fork() failed: %m");	    unlink(PID_FILE);	    exit(1);	}		/* Child.  Follow the daemon rules in	 * W. Richard Stevens. Advanced Programming	 * in the UNIX Environment (Addison-Wesley	 * Publishing Co., 1992). Page 417.).	 */	if (setsid() < 0)	{	    syslog(LOG_INFO, "setsid() failed: %m");	    unlink(PID_FILE);	    exit(1);	}	chdir("/");	close(0);	close(1);	close(2);	umask(0);    }    if ((fd = apm_open()) < 0)    {	syslog(LOG_INFO, "apm_open() failed: %m");	unlink(PID_FILE);	exit(1);    }    if (!apm_read(&apminfo))    {	apmd_init(&apminfo);	apmd_fd = fd;    }    for (;;)    {	int n = apm_get_events(fd, check_power_time, events, MAX_EVENTS);	int i;	/* If the call was timed-out, then we cause a "simulated" 	 * UPDATE_TIME event. 	 */	if (n == 0)	{	    n = 1;	    events[0] = APMD_SYNTHETIC_CHECK;	}	for (i = 0; i < n; i++)	{	    if (apm_read(&apminfo))		continue;	    apmi = &apminfo;	    ADEBUG(4, " [event loop] 0x%04x\n", events[i]);	    if (verbose)		syslog(LOG_INFO, "Event 0x%04x: %s",		       events[i], apm_event_name(events[i]));	    switch (events[i])	    {	    case APM_SYS_STANDBY:	    case APM_USER_STANDBY:		apmd_standby(events[i], apmi);		break;	    case APM_SYS_SUSPEND:	    case APM_USER_SUSPEND:		apmd_suspend(events[i], apmi);		break;	    case APM_CRITICAL_SUSPEND:		time(&pre_suspend_time);		pre_suspend_percentage = 0;		/* As fast as possible */		ioctl(fd, APM_IOC_SUSPEND, NULL);		break;	    case APM_NORMAL_RESUME:	    case APM_STANDBY_RESUME:	    case APM_UPDATE_TIME:	    case APM_CRITICAL_RESUME:		apmd_resume(events[i], apmi);		apmd_check_power(events[i], apmi);		break;	    case APMD_SYNTHETIC_CHECK:		apmd_log(events[i], "performing APM status check");		apmd_check_power(events[i], apmi);		break;	    case APM_LOW_BATTERY:	    case APM_POWER_STATUS_CHANGE:#ifdef        APM_CAPABILITY_CHANGE	    case APM_CAPABILITY_CHANGE:#endif		apmd_check_power(events[i], apmi);		break;	    default:		/* These aren't errors; see the APM BIOS 1.2 spec.		 * 0x000d-0x00ff	reserved system events		 * 0x0100-0x01ff	reserved device events		 * 0x0200-0x02ff	OEM-defined		 * 0x0300-0xffff	reserved		 */		syslog(LOG_ERR, "Received unknown APM event 0x%04x.",			events[i]);	    }	}    }    return 0;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -