/*$Id: wakeup.c,v 1.4 2003/09/16 02:07:17 talon Exp $*/ /* Copyright 2003 Bill Schaub. talon@fingers.shocking.com This is Free software, you can do whatever you like with it as long as you dont hold the author liable for any damages and you leave this copyright/license message intact in the source code. */ /* This program sets the autowakeup timer on sun4u platforms that support it. Sun workstations use an alarm on the TOD chip to perform a sheduled power on There are undocumented ioctl calls to the /dev/tod driver in sys/todio.h using these undocumented ioctls will allow you to use this functionality without having to resort to powerd and its cracked out suspend-resume shit. This program is intended to be used in /sbin/rc5 just before the system unmounts all filesystems. It might work earlier than that but you never know if somthing else might be clearing the TOD alarm otherwise. ************************************* *DANGER DANGER DANGER DANGER DANGER * ************************************* I do not work for sun and i have only done very very basic testing. if you somehow manage to kill your box with this dont come crying to me. i doubt it can do serious damage but i would still advise that you think twice before using this code on a production box of any kind (which isnt likely to need to be powerd off in the first place any way) */ #include #include #include #include #include #include #include #include #include #include #include #include #define MAXBUF 300 int clear_alarm(int fd); /* clear TOD alarm */ int set_alarm(int fd, time_t val); /* set TOD alarm */ int main(int argc, char **argv) { int tod; /* fd for Time of day clock */ struct tm local_tm; /* tm structure containing local time, modified by tm_wake members */ struct tm wake_tm; /* tm structure containing the time to wake up at. */ time_t wake; /* the seconds from now that the alarm should trigger */ time_t now; /* the current time */ tod = open("/dev/tod",O_RDWR); /* open TOD */ if(tod == -1) { perror("Cant open /dev/tod"); return 1; } now = time(NULL); /*Get current time */ (void) localtime_r(&now,&local_tm); /* fill out the tm struct.*/ /* parse command line */ if(argc > 1) { char *tmp; /* pointer for strptime */ char cat[MAXBUF]; /* buffer to hold argv[1] and argv[2] if needed */ /* if two arguments are passed cat them togeather for strptime */ if(argc > 2 ) { /* initialize buffer to 0 */ memset(cat,0,MAXBUF); /* copy argv[1] to cat */ strncpy(cat,argv[1],MAXBUF-1); /* append argv[2] to cat */ strncat(cat,argv[2], MAXBUF - 1 - strlen(argv[1])); tmp = strptime(cat,"%m/%d/%Y %H:%M",&wake_tm); } /* otherwise keep going and parse just the time instead */ else tmp = strptime(argv[1],"%H:%M",&wake_tm); /* parse time argument */ if(tmp == NULL ) { printf("Invalid time spec use HH:MM\n"); printf("or month/day/year HH:MM\n"); return 1; } /* if the date was parsed we need to copy the whole wake_tm structure over. not just the hours and minutes */ if(argc > 2) local_tm = wake_tm; else { local_tm.tm_sec=0; local_tm.tm_min = wake_tm.tm_min; local_tm.tm_hour = wake_tm.tm_hour; } } else { printf("No time specified, using default of 8:00\n"); local_tm.tm_sec=0; local_tm.tm_min=0; local_tm.tm_hour=8; } wake = mktime(&local_tm); /* take time1 and generate seconds. */ /* If the wake time is in the past make it wake us tomorrow at that time instead */ if(wake < now) { printf("Time set in the past! setting alarm for tomorrow.\n"); wake = wake + ( 24 * 60 * 60 ); } /* dont allow wakeup alarms that are too early in the future */ if((wake - now) < 300) { printf("Wake time has to be > 5 minutes in the future!\n"); exit(1); } if(clear_alarm(tod) == -1) return 1; /* Probably not needed, just in case clearing the alarm and setting it too soon after might be a problem. */ sleep(2); /* Finally we perform the ioctl on TOD to set the alarm */ if(set_alarm(tod,wake) == -1) return 1; /* if we get here everything went ok */ /* Print status and return */ now = time(NULL); printf("Alarm set to %ld \n",wake); printf("thats %ld seconds from now\n",wake - now); printf("now = %ld \n",now); return 0; } int clear_alarm(int fd) { int ret; printf("Clearing the alarm just to be safe...."); if((ret = ioctl(fd,TOD_CLEAR_ALARM,NULL)) == -1) { printf(" Failed! :%s\n",strerror(errno)); return ret; } printf(" Success!\n"); return ret; } int set_alarm(int fd, time_t val) { int ret; /* Finally we perform the ioctl on TOD to set the alarm */ printf("Setting TOD alarm...."); if((ret = ioctl(fd,TOD_SET_ALARM,&val)) == -1) { printf(" Failed!\n"); perror("Unable to set the TOD alarm, sorry! "); (void) clear_alarm(fd); return ret; } printf(" Success!\n"); return ret; }