All pastes #15530 Raw Edit

Anonymous

public text v1 · immutable
#15530 ·published 2005-06-22 10:17 UTC
rendered paste body
/*
 * ipaq sleep daemon
 * 
 * Copyright 2001 Joe McCarthy <mccarthy@engrng.pitt.edu> under the terms of the
 * GNU GPL.
 *
 * blatantly hacked from apm-sleep by
 * Copyright 2000, 2001 Joey Hess <joeyh@kitenet.net> under the terms of the
 * GNU GPL.
 */

#include <unistd.h>
#include <getopt.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <signal.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <ctype.h>
#include <apm.h>

#include "ipaq-sleep.h"

#include <X11/Xlib.h>
#include <X11/extensions/scrnsaver.h>

#undef DEBUG

int irqs[MAX_IRQS]; /* irqs to examine have a value of 1 */
long v, irq_count[MAX_IRQS]; /* holds previous counters of the irq's */
int sleep_idle=3 * 60; /* in seconds */
int dim_idle=1 * 60; /* in seconds */
int daemonize=1;
int sleep_time = DEFAULT_SLEEP_TIME;
int cpu=1;
int apm=1;
int dimming=1;
int dim_level=4; 
int sleeping=1;
int debug=0;
int probe=1;
double load_check=0.25;
int X=1;
int battery_level = 0;

int apmvalue=0, no_sleep=0;
time_t oldpidtime=0;

#ifdef DEBUG
FILE *dgfp;
#endif
		
Display *dpy;
Window root;		    /* The root window (which holds MIT_SCREEN_SAVER
			       info). */
XScreenSaverInfo *info;	    /* The MIT_SCREEN_SAVER info object. */

int init() { 
	int first_event, first_error;
  
	dpy = XOpenDisplay(NULL);
	
	if (dpy==NULL) {
		return (1);
	}
	else {
  		XScreenSaverQueryExtension(dpy, &first_event, &first_error);
  		root = DefaultRootWindow(dpy);
  		info = XScreenSaverAllocInfo();
#ifdef DEBUG
  		if (debug) 
		  fprintf(dgfp, "X seems to be running....\nUsing display %x\n", dpy);
#endif
		return (0);
	}
}

void query_idle(Time *idleTime) {
  
  XScreenSaverQueryInfo(dpy,root, info);
  *idleTime = info->idle;
  
}

int set_backlight (int val)
{
  if (val < 0)
    return system (BL " off");
  else
    {
      char command[256];
      snprintf(command, sizeof (command), BL " %i\n", val);
      return system(command);
    }
}

int read_backlight (void)
{
  int r = 32;
  FILE *input;

  if ((input=popen(BL, "r")) != NULL)
    {
      char buf[32];
      if (fgets (buf, 32, input))
	{
	  if (!strncmp (buf, "on ", 3))
	    r = atoi (buf + 4);
	  else
	    r = -1;
	}
      pclose (input);
    }
  else
    fprintf(stderr, "Cannot Open Stdin for bl command\n");

  return r;
}

void usage () {
	fprintf(stderr, "usage:  ipaq-sleep -[usnxcCidbSh]\n"
	" -u SECONDS\t inactivity time for sleep (0/-ve: don't suspend) [default 300]\n"
	" -o SECONDS\t inactivity time for dim (0/-ve: don't dim) [default 60]\n"
	" -s COMMAND\t sleep command\n"
	" -S\t\t save new defaults (do NOT run)\n"
	" -a\t\t ignore apm status\n"
	" -n\t\t turn OFF daemon-mode\n"
	" -x\t\t turn OFF X-mode\n"
	" -c\t\t turn OFF cpu-mode\n"
	" -C LOAD\t only sleep when load is below this threshold\n"
	" -i INT\t\t set custom IRQs (use with p to remove those already probed)\n"
	" -p\t\t don't probe for IRQs\n"
	" -b MINUTES\t sleep immediately when remaining run time reaches this level\n"
#ifdef DEBUG
	" -d\t\t run in debug mode\n"
#endif
	" -h\t\t show this message  \n\n");
}

static void do_sleep(void)
{
  if (system(sleep_command) != 0) 
    fprintf(stderr, "%s failed\n", sleep_command);
}

void parse_command_line (int argc, char **argv) {
	extern char *optarg;
	int c=0;
	int i, save=0;
	char dline[64], func[12], value[12], userdefaults[256];
	char *home = getenv ("HOME");
	FILE *f;
	
	f=fopen(DEFAULTS, "r");
	
	if (! f) fprintf(stderr, "problem opening %s\n", DEFAULTS);
	else {
		while(fgets(dline,sizeof(dline),f)) {
			if (sscanf(dline,"%s = %s", func, value) == 2) {
				if (strcmp(func, uflag)==0) {
					sleep_idle=atoi(value);
#ifdef DEBUG
					if (debug) fprintf(dgfp, "sleep_idle=%d\n", sleep_idle);
#endif
					if (sleep_idle>0) sleeping=1;
					else {
#ifdef DEBUG
						if (debug) fprintf(dgfp, "sleeping disabled!\n");
#endif
						sleeping=0;
					}
				}
				if (strcmp(func, oflag)==0) {
					dim_idle=atoi(value);
#ifdef DEBUG
					if (debug) fprintf(dgfp, "dim_idle=%d\n", dim_idle);
#endif
					if (dim_idle>0) dimming=1;
					else {
#ifdef DEBUG
						if (debug) fprintf(dgfp, "dimming disabled!\n");
#endif
						dimming=0;
					}
				}
				if (strcmp(func, Lflag)==0) {
					dim_level=atoi(value);
#ifdef DEBUG
					if (debug) fprintf(dgfp, "dim_idle=%d\n", dim_idle);
#endif
				}
				if (strcmp(func, aflag)==0) {
					apm=atoi(value);
#ifdef DEBUG
					if (debug) fprintf(dgfp, "apm=%d\n", apm);
#endif
				}
				if (strcmp(func, cflag)==0) {
					cpu=atoi(value);
#ifdef DEBUG
					if (debug) fprintf(dgfp, "cpu=%d\n", cpu);
#endif
				}
				if (strcmp(func, xflag)==0) {
					X=atoi(value);
#ifdef DEBUG
					if (debug) fprintf(dgfp, "X=%d\n", cpu);
#endif
				}
				if (strcmp(func, dflag)==0) {
					debug=atoi(value);
#ifdef DEBUG
					if (debug) fprintf(dgfp, "debug=%d\n", cpu);
#endif
				}
				if (strcmp(func, Cflag)==0) {
					load_check=atof(value);
#ifdef DEBUG
					if (debug) fprintf(dgfp, "load_check=%lf\n", load_check);
#endif
				}
				if (strcmp(func, pflag)==0) {
					probe=atoi(value);
#ifdef DEBUG
					if (debug) fprintf(dgfp, "probe=%d\n", probe);
#endif
				}
				if (strcmp(func, bflag)==0) {
					battery_level=atoi (value);
#ifdef DEBUG
					if (debug) fprintf(dgfp, "battery=%d\n", battery_level);
#endif
				}
				if (strcmp(func, iflag)==0) {
					i = atoi(value);
					if ((i < 0) || (i >= MAX_IRQS)) 
						fprintf(stderr, "ipaq-sleep: bad irq number %d in /etc/ipaqsleep.conf\n", i);
					irqs[i]=1;
#ifdef DEBUG
					if (debug) fprintf(dgfp, "IRQ %d set\n", i);
#endif
				}
			}
		}
		fclose(f);
	}
	
	sprintf(userdefaults, "%s%s", home, DEFAULTSUSER);
	
	f=fopen(userdefaults, "r");
	
	if (f)
	{
		while(fgets(dline,sizeof(dline),f)) {
			if (sscanf(dline,"%s = %s", func, value) == 2) {
				if (strcmp(func, uflag)==0) {
					sleep_idle=atoi(value);
#ifdef DEBUG
					if (debug) fprintf(dgfp, "sleep_idle=%d\n", sleep_idle);
#endif
					if (sleep_idle>0) sleeping=1;
					else {
#ifdef DEBUG
						if (debug) fprintf(dgfp, "sleeping disabled!\n");
#endif
						sleeping=0;
					}
				}
				if (strcmp(func, oflag)==0) {
					dim_idle=atoi(value);
#ifdef DEBUG
					if (debug) fprintf(dgfp, "dim_idle=%d\n", dim_idle);
#endif
					if (dim_idle>0) dimming=1;
					else {
#ifdef DEBUG
						if (debug) fprintf(dgfp, "dimming disabled!\n");
#endif
						dimming=0;
					}
				}
				if (strcmp(func, aflag)==0) {
					apm=atoi(value);
#ifdef DEBUG
					if (debug) fprintf(dgfp, "apm=%d\n", apm);
#endif
				}
				if (strcmp(func, cflag)==0) {
					cpu=atoi(value);
#ifdef DEBUG
					if (debug) fprintf(dgfp, "cpu=%d\n", cpu);
#endif
				}
				if (strcmp(func, xflag)==0) {
					X=atoi(value);
#ifdef DEBUG
					if (debug) fprintf(dgfp, "X=%d\n", cpu);
#endif
				}
				if (strcmp(func, dflag)==0) {
					debug=atoi(value);
#ifdef DEBUG
					if (debug) fprintf(dgfp, "debug=%d\n", cpu);
#endif
				}
				if (strcmp(func, Cflag)==0) {
					load_check=atof(value);
#ifdef DEBUG
					if (debug) fprintf(dgfp, "load_check=%lf\n", load_check);
#endif
				}
				if (strcmp(func, pflag)==0) {
					probe=atoi(value);
#ifdef DEBUG
					if (debug) fprintf(dgfp, "probe=%d\n", probe);
#endif
				}
				if (strcmp(func, bflag)==0) {
					battery_level=atoi (value);
#ifdef DEBUG
					if (debug) fprintf(dgfp, "battery=%d\n", battery_level);
#endif
				}
				if (strcmp(func, iflag)==0) {
					i = atoi(value);
					if ((i < 0) || (i >= MAX_IRQS)) 
						fprintf(stderr, "ipaq-sleep: bad irq number %d in /etc/ipaqsleep.conf\n", i);
					irqs[i]=1;
#ifdef DEBUG
					if (debug) fprintf(dgfp, "IRQ %d set\n", i);
#endif
				}
			}
		}
		fclose(f);
	}
			
	while (c != -1) {
		c=getopt(argc,argv, "s:nacxpdSC:u:o:i:b:h");
		switch (c) {
			case 's':
				sleep_command=strdup(optarg);
				break;
			case 'a':
				apm=0;
				break;
			case 'n':
				daemonize=0;
				break;
			case 'c':
				cpu=0;
				break;
			case 'x':
				X=0;
				break;
			case 'd':
				debug=1;
				break;
			case 'p':
				probe=0;
				break;
			case 'C':
				cpu=1;
				load_check=atof(optarg);
				break;
			case 'u':
				sleep_idle=atoi(optarg);
				if (sleep_idle>0) sleeping=1;
				else {
#ifdef DEBUG
					if (debug) fprintf(dgfp, "sleeping disabled!\n");
#endif
					sleeping=0;
				}
				break;
			case 'o':
				dim_idle=atoi(optarg);
				if (dim_idle>0) dimming=1;
				else {
#ifdef DEBUG
					if (debug) fprintf(dgfp, "dimming disabled!\n");
#endif
					dimming=0;
				}
				break;
			case 'i':
				i = atoi(optarg);
				if ((i < 0) || (i >= MAX_IRQS))
					fprintf(stderr, "ipaq-sleep: bad irq number %d\n", i);
				irqs[atoi(optarg)]=1;
				break;
			case 'b':
				battery_level = atoi(optarg);
				break;
			case 'S':
				save=1;
				break;
			case 'h':
				usage();
				exit(0);
				break;
		}
	}
	if (optind < argc) {
		usage();
		exit(1);
	}
	
	if (save) {
		
		f=fopen(DEFAULTS, "w");
	
		if (! f) fprintf(stderr, "problem opening %s\n", DEFAULTS);
		else { 
			fprintf(f,"debug = %i\n", debug);
			fprintf(f,"auto-sleep_time = %i\n", sleep_idle);
			fprintf(f,"dim_time = %i\n", dim_idle);
			fprintf(f,"dim_level = %i\n", dim_level);
			fprintf(f,"check_apm = %i\n", apm);
			fprintf(f,"check_cpu = %i\n", cpu);
			fprintf(f,"X = %i\n", X);
			fprintf(f,"CPU_value = %f\n", load_check);
			fprintf(f,"probe_IRQs = %i\n", probe);
			for (i=0;i<MAX_IRQS;i++) 
				if (irqs[i]==1) fprintf(f,"IRQ = %i\n", i);
			fclose(f);	
		}
		
		exit(0);
		
	}
		
}

int probe_IRQs() {
	int i, redo=0, yes=0;
	char iline[64];
  	
	FILE *f;
		
	if (probe) {
			
		f=fopen(INTERRUPTS, "r");
		if (! f) fprintf(stderr, "problem opening %s\n", INTERRUPTS);
		else {
			while(fgets(iline,sizeof(iline),f)) {
			/* Lowercase line. */
				for(i=0;iline[i];i++)
					iline[i]=tolower(iline[i]);
				/* See if it is a serial, audio or USB. */
				if ((strstr(iline, "serial") != NULL ||
			    		strstr(iline, "out") != NULL ||
                            		strstr(iline, "core") != NULL)) yes=1;
				else yes=0;
				if (sscanf(iline,"%d: %ld",&i, &v) == 2 && (yes || irqs[i])) {
					if (irqs[i]!=1) {
						redo=1;
						irqs[i]=1;
#ifdef DEBUG
						if (debug) fprintf(dgfp,"Found a new IRQ.... %d\n", i);
#endif
					}
					irq_count[i] = v;
				}
			}
			fclose(f);
		}
	}
	
	return(redo);
	
}
	
int check_apm() {
	int runtime;
	apm_info info;

	apm_read(&info);
	
	if (info.ac_line_status == AC_LINE_STATUS_ON) {
#ifdef DEBUG
		if (debug) fprintf(dgfp,"You are on external power. NOT sleeping.\n");
#endif
		return(1);
	}

#ifdef DEBUG
	if (debug) fprintf(dgfp,"You are NOT on external power. Its all good.....\n");
#endif
	runtime = info.battery_time;
	if (runtime >= 0 && runtime < battery_level)
	{
#ifdef DEBUG
		if (debug)
			fprintf (dgfp, "Battery level %d below threshold, sleeping\n", runtime);
#endif
		do_sleep ();
	}
	
	return(0);
}		
	
int check_PID() {
	int PID;
	char command[60], pid_file[25];
  	struct stat pid_stat;

	FILE *input;
		
	stat(NO_SLEEP_DIR, &pid_stat);
#ifdef DEBUG
	if (debug) fprintf(dgfp, "Last time %i, new time %i\n", oldpidtime, pid_stat.st_mtime);  
#endif
	if (pid_stat.st_mtime>oldpidtime) {
		
		no_sleep=0;
#ifdef DEBUG
		if (debug) fprintf(dgfp,"The no-sleep directory has been modified\nChecking for PID locks\n");
#endif
		oldpidtime=pid_stat.st_mtime;
		sprintf(command, "/bin/ls %s", NO_SLEEP);
  
  		if((input=popen(command, "r"))==NULL) 
    	  		fprintf(stderr, "Cannot Open Stdin to get no-sleep PIDs\n");
 
  		while((fscanf(input, "%i", &PID))!=-1) {
  
   			sprintf(pid_file, "/proc/%i/cmdline", PID);
  			if (access (pid_file, F_OK) == 0) {
#ifdef DEBUG
				if (debug) fprintf(dgfp,"PID lock for %d\n", PID);
#endif
				no_sleep=1;
			}
			else {
#ifdef DEBUG			
		  		if (debug) fprintf(dgfp,"Bad PID lock for process %d,removing\n", PID);
#endif
				snprintf(command, sizeof (command), "%s/%i", NO_SLEEP_DIR,PID);
  				unlink(command);
			}
		}
		
		pclose(input);
			
  	}
  	if (no_sleep) {
#ifdef DEBUG
		if (debug) fprintf(dgfp,"Still PID locked\n");
#endif
		return(1);
	}
	else return(0);
	
}
	
int check_cpu() {
	int activity=0;
	double load=0.0;
	
	FILE *f;
		
	if (cpu) {
			
		f=fopen(LOADAVG, "r");
                if (! f) fprintf(stderr, "error opening %s\n", LOADAVG);
                else {
			if (load>=load_check) {
				activity=1;
#ifdef DEBUG
				if (debug) fprintf(dgfp,"CPU activity %f greater than %f\n", load, load_check);
#endif
                	}
#ifdef DEBUG
			else if (debug) fprintf(dgfp,"CPU load is %f lower than %f,\n"
				"its all good...\n", load, load_check);
#endif
			fclose(f);
		}
                
	}
	
	return(activity);
	
}		

/* Keep checking the interrupts. As long as there is activity, do nothing. */
void main_loop (void) {
	int activity, i, total_unused=0, apm_active=0, old_apm=0;
	int dimmed=0, current_bl=32;
	int newIdle, oldIdle, lastIdle, oldTime, newTime;
	char iline[64];
  	
	Time idleTime; /* milliseconds */
        FILE *f;
  
	sleep_idle=sleep_idle;
	dim_idle=1000*dim_idle;
	
	check_cpu();
	check_PID();
	
	query_idle(&idleTime);
	lastIdle=oldIdle=(int)idleTime;
#ifdef DEBUG
	if (debug) fprintf(dgfp,"Setting oldIdle %d.\n", oldIdle);
#endif

	current_bl = read_backlight ();
				
	if (current_bl < 0) {
#ifdef DEBUG
		if (debug) fprintf(dgfp,"Currently bl is off...did you want to mean to disable dim handling? Use -o 0\n");
#endif
		dimmed=1;
	}
	else {
#ifdef DEBUG
		if (debug) fprintf(dgfp,"Good the bl is on, leave everything to me!\n");
#endif
		dimmed=0;
	}
	
	probe_IRQs();
								
	while (1) {
		activity=0;
		
		if (X) {
			query_idle(&idleTime);
			newIdle=(int)idleTime;
			
			if ((newIdle-oldIdle)<(lastIdle-oldIdle)) {
				activity=1;
				oldIdle=0;
#ifdef DEBUG
				if (debug) fprintf(dgfp,"Recent X activity.\nNewidle=%d, oldidle=%d\n", newIdle, oldIdle);
#endif
				if (dimming && dimmed) {
#ifdef DEBUG
			  	  	if (debug) fprintf(dgfp,"Resetting bl value of %d\n",current_bl);
#endif
					set_backlight (current_bl);
			  	 	dimmed=0;
				}		
						
			}
			
#ifdef DEBUG
			else if (debug) fprintf(dgfp,"No activity. Newidle=%d, oldidle=%d\n", newIdle, oldIdle);
#endif
			
			if (dimming  && !dimmed && !apm_active) {
				if ((newIdle-oldIdle)>=dim_idle) {
					current_bl = read_backlight ();
					set_backlight (dim_level);
					dimmed=1;
				}
			}
			
			lastIdle=newIdle;
	
		}

		apm_active=check_apm();
		if (apm_active) {
			activity=1;	
			oldIdle=newIdle;
			if (old_apm==0 && dimming && dimmed) {
#ifdef DEBUG
				if (debug) fprintf(dgfp,"Resetting bl value of %d\n",current_bl);
#endif
				set_backlight (current_bl);
				dimmed=0;	
			}
		}
		old_apm=apm_active;
		
		if (activity == 0) {
			f=fopen(INTERRUPTS, "r");
			if (! f) fprintf(stderr, "problem opening %s\n", INTERRUPTS);
			else {
				while(fgets(iline,sizeof(iline),f)) {
					if (sscanf(iline,"%d: %ld",&i, &v) == 2 && 
					    irqs[i] && irq_count[i] != v) {
						activity=1;
#ifdef DEBUG
						if (debug) fprintf(dgfp,"IRQ activity %d\n", i);
#endif
						irq_count[i] = v;
					}
				}
				fclose(f);
			}
		}

		if (activity) {
			total_unused = 0;
		}
		else {
			total_unused += sleep_time;
			if (total_unused >= sleep_idle && sleeping) {
				
				if (check_cpu() || check_PID() || probe_IRQs()) {
#ifdef DEBUG
					if (debug) fprintf(dgfp,"You cannot sleep at this time! Not going to sleep....\n");
#endif
					total_unused=0;
					oldIdle=newIdle;
				}
				else {
#ifdef DEBUG
					if (debug) fprintf(dgfp,"Going to sleep....\n");
#endif
					do_sleep ();
					total_unused=0;
				}
			}
			
		}

#ifdef DEBUG		
		if (debug) fflush(dgfp);
#endif
		sleep(sleep_time);
		
		newTime=time(NULL);
		if (oldTime && newTime-sleep_time > oldTime +1) {
#ifdef DEBUG
			if (debug)
			  fprintf(stderr, "%i sec sleep; resetting timer and resetting dimmer...", (int)(newTime - oldTime));
#endif
			total_unused=0;
			
			query_idle(&idleTime);
			lastIdle=oldIdle=(int)idleTime;
#ifdef DEBUG
			if (debug) fprintf(dgfp,"Re-setting oldIdle %d.\n", oldIdle);
#endif
			
			if (dimming && dimmed) {
#ifdef DEBUG
			  	  if (debug) fprintf(dgfp,"Resetting bl value of %d\n",current_bl);
#endif
				  set_backlight (current_bl);
				  dimmed=0;
			}
		}
		oldTime=newTime;	
		
	}
}

int main (int argc, char **argv) {
	int try=0, tmpX=0, checkinit=0;
	
	signal (SIGCHLD, SIG_IGN);
	parse_command_line(argc, argv);

#ifdef DEBUG
	if (debug) {
		dgfp=fopen("/tmp/ipaq-sleep.log", "a");
		if (! dgfp) {
			fprintf(stderr, "problem opening ipaq-sleep.log\n");
			exit(1);
		}
	}
#endif
	
	if (daemonize) {
		if (daemon(1,1) == -1) {
			fprintf(stderr, "auto-sleep daemon problems\n");
			exit(1);
		}
	}
	
	checkinit=init();
	
	while (try<10) {
		if (checkinit) {
#ifdef DEBUG
			if (debug) fprintf(dgfp,"Waiting for X....\n");
#endif
			tmpX=0;
			sleep(2);
			checkinit=init();
		}
		else {
			tmpX=1;
			break;
		}
		try++;
	}
	
	if(tmpX!=1) {
#ifdef DEBUG
		if (debug) fprintf(dgfp, "It looks like X is not running. You might be somewhat hosed....\n");
#endif
		X=tmpX;
	
	}
	
	main_loop();
	
	return(0); // never reached
}