/* * NVRAM WakeUp * Copyright (C) 2001-2005, Sergei Haller. * * $Id: nvram-wakeup.c 902 2008-09-19 20:29:46Z tiber $ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #define CVSREV_nvram_wakeup_c \ "$Id: nvram-wakeup.c 902 2008-09-19 20:29:46Z tiber $" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "nvram-wakeup.h" /* Use bcd2bin if necessary... */ #define FROMBCD(x) (b.bcd ? bcd2bin(x) : x) #define TOBCD(x) (b.bcd ? bin2bcd(x) : x) /* this one is special for the addr_day ... */ #define FROM_D_BCD(x) (b.bcd & !b.day_no_bcd ? bcd2bin(x) : x) #define TO_D_BCD(x) (b.bcd & !b.day_no_bcd ? bin2bcd(x) : x) #include "cvs_revs.h" static int handle_cmdline(int *argc, char ***argv); static time_t vdr_abs_time_t = -1; unsigned char oBytes[MAXNVRAMSIZE]; unsigned char nBytes[MAXNVRAMSIZE]; int nvramSize = 0; /* the real size of nvram (will become 114 in most cases) */ long int wakeupbefore = WAKEUP_BEFORE; char * _config_file = NULL; char * _iw_string = NULL; int _nowrite = OFF; int _directisa = OFF; int _check_time = ON; struct biosinfo b; int assign_byte( unsigned char **oPtr, unsigned char **nPtr, const unsigned int addr, const char *str) { if (addr < nvramSize) { *oPtr = &oBytes[addr]; *nPtr = &nBytes[addr]; nvprintf(LOG_DEBUG, "value of the %-12s byte is: 0x%02X.\n", str, **oPtr); return 0; } else { nvprintf(LOG_ERR, "%s (0x%02X) is beyond the end of nvram\n", str, addr); if (_directisa == OFF) nvprintf(LOG_ERR, "You might want to use the --directisa command line option.\n"); return 1; } } int main(int argc, char **argv) { int retval; int addr, changed = 0, need_reboot = 0; unsigned char *oChkH, *oChkL; unsigned char *nChkH, *nChkL; unsigned int oChk=0, nChk=0; unsigned char *oChkH2, *oChkL2; unsigned char *nChkH2, *nChkL2; unsigned int oChk2=0, nChk2=0; unsigned char *oStat, *nStat; unsigned char *oMon, *nMon; unsigned char *oDay, *nDay; unsigned char *oWdays, *nWdays; unsigned char *oHour, *nHour; unsigned char *oMin, *nMin; unsigned char *oSec, *nSec; unsigned char *oRtcDay, *nRtcDay; unsigned char *oRtcMon, *nRtcMon; struct rtc_time oRtc_tm, nRtc_tm; struct tm vdr_abs_tm; struct tm *(*get_the_time)(const time_t *); time_t now; /* learn who we really are */ set_progname(argv[0]); /* handle the commandline */ handle_cmdline(&argc, &argv); /* get bios info first... */ if (_config_file) { /* read config file */ if (!readconf(&b, _config_file)) { nvprintf(LOG_ERR, "Reading configuration file returned with errors.\n"); exit(2); } } else if (_iw_string) { /* get corresponding config */ if (!get_bios_info_by_iw(&b, _iw_string)) { nvprintf(LOG_ERR, "Infowriter '%s' not found.\n", _iw_string); exit(2); } } else { switch (get_bios_info_by_dmi(&b)) { case -1: /* all errors already printed */ exit(2); break; case 0: nvprintf(LOG_ERR, "Your mainboard is currently not supported.\n" ); nvprintf(LOG_ERR, "Please try determining the addresses and sending the following\n"); nvprintf(LOG_ERR, "information back to the maintainers:\n" ); nvprintf(LOG_ERR, " - The addresses you found out (read README.mb)\n" ); nvprintf(LOG_ERR, " - Mainboard vendor: %s%s%s\n", QUOTE(board_vendor() ), VALUE(board_vendor() ), QUOTE(board_vendor() ) ); nvprintf(LOG_ERR, " - Mainboard type: %s%s%s\n", QUOTE(board_type() ), VALUE(board_type() ), QUOTE(board_type() ) ); nvprintf(LOG_ERR, " - Mainboard revision: %s%s%s\n", QUOTE(board_version()), VALUE(board_version()), QUOTE(board_version()) ); nvprintf(LOG_ERR, " - BIOS vendor: %s%s%s\n", QUOTE(bios_vendor() ), VALUE(bios_vendor() ), QUOTE(bios_vendor() ) ); nvprintf(LOG_ERR, " - BIOS version: %s%s%s\n", QUOTE(bios_version() ), VALUE(bios_version() ), QUOTE(bios_version() ) ); nvprintf(LOG_ERR, " - BIOS release: %s%s%s\n", QUOTE(bios_release() ), VALUE(bios_release() ), QUOTE(bios_release() ) ); exit(2); break; case 1: break; /* everything is ok. doing nothing */ } } nvprintf(LOG_DEBUG, "Using following bios info:\n" ); nvprintf(LOG_DEBUG, " need_reboot = %d\n", b.need_reboot ); nvprintf(LOG_DEBUG, " addr_chk_h = 0x%02X\n", b.addr_chk_h ); nvprintf(LOG_DEBUG, " addr_chk_l = 0x%02X\n", b.addr_chk_l ); nvprintf(LOG_DEBUG, " addr_chk_h2 = 0x%02X\n", b.addr_chk_h2 ); nvprintf(LOG_DEBUG, " addr_chk_l2 = 0x%02X\n", b.addr_chk_l2 ); nvprintf(LOG_DEBUG, " addr_stat = 0x%02X\n", b.addr_stat ); nvprintf(LOG_DEBUG, " addr_mon = 0x%02X\n", b.addr_mon ); nvprintf(LOG_DEBUG, " addr_day = 0x%02X\n", b.addr_day ); nvprintf(LOG_DEBUG, " addr_wdays = 0x%02X\n", b.addr_wdays ); nvprintf(LOG_DEBUG, " addr_hour = 0x%02X\n", b.addr_hour ); nvprintf(LOG_DEBUG, " addr_min = 0x%02X\n", b.addr_min ); nvprintf(LOG_DEBUG, " addr_sec = 0x%02X\n", b.addr_sec ); nvprintf(LOG_DEBUG, " shift_stat = %d\n", b.shift_stat ); nvprintf(LOG_DEBUG, " shift_mon = %d\n", b.shift_mon ); nvprintf(LOG_DEBUG, " shift_day = %d\n", b.shift_day ); nvprintf(LOG_DEBUG, " shift_wdays = %d\n", b.shift_wdays ); nvprintf(LOG_DEBUG, " shift_hour = %d\n", b.shift_hour ); nvprintf(LOG_DEBUG, " shift_min = %d\n", b.shift_min ); nvprintf(LOG_DEBUG, " shift_sec = %d\n", b.shift_sec ); nvprintf(LOG_DEBUG, " rtc_time = %d\n", b.rtc_time ); nvprintf(LOG_DEBUG, " rtc_day = 0x%02X\n", b.rtc_day ); nvprintf(LOG_DEBUG, " rtc_mon = 0x%02X\n", b.rtc_mon ); nvprintf(LOG_DEBUG, " rtc_day_0_is_c0 = %d\n", b.rtc_day_0_is_c0 ); nvprintf(LOG_DEBUG, " rtc_mon_0_is_c0 = %d\n", b.rtc_mon_0_is_c0 ); nvprintf(LOG_DEBUG, " reset_day = %d\n", b.reset_day ); nvprintf(LOG_DEBUG, " reset_mon = %d\n", b.reset_mon ); nvprintf(LOG_DEBUG, " nr_stat = %d\n", b.nr_stat ); nvprintf(LOG_DEBUG, " nr_mon = %d\n", b.nr_mon ); nvprintf(LOG_DEBUG, " nr_day = %d\n", b.nr_day ); nvprintf(LOG_DEBUG, " nr_hour = %d\n", b.nr_hour ); nvprintf(LOG_DEBUG, " nr_min = %d\n", b.nr_min ); nvprintf(LOG_DEBUG, " nr_sec = %d\n", b.nr_sec ); nvprintf(LOG_DEBUG, " nr_rtc_day = %d\n", b.nr_rtc_day ); nvprintf(LOG_DEBUG, " nr_rtc_mon = %d\n", b.nr_rtc_mon ); nvprintf(LOG_DEBUG, " nr_wdays = %d\n", b.nr_wdays ); nvprintf(LOG_DEBUG, " bcd = %d\n", b.bcd ); nvprintf(LOG_DEBUG, " day_hack = %d\n", b.day_hack ); nvprintf(LOG_DEBUG, " upper_method = %d\n", b.upper_method ); nvprintf(LOG_DEBUG, " chk_method = %d\n", b.chk_method ); if (b.chk_method == FSC) { nvprintf(LOG_ERR, "Checksum algorithm by FSC is unsupported!\n"); exit(2); } /* open the rtc device */ nvprintf(LOG_DEBUG, "Opening %s in O_RDONLY mode...\n", RTC_DEV); fd_rtc = open(RTC_DEV, O_RDONLY); if (fd_rtc == -1) { nvprintf(LOG_ERR, "%s: %m\n", RTC_DEV); exit(2); } /* First, we have to know if the hardware clock runs local or UTC/GMT time */ switch (compare_ltm_rtc()) { case -1: get_the_time = NULL; nvprintf(LOG_ERR, "RTC is not synchronously with system time!\n"); nvprintf(LOG_ERR, "RTC isn't running in localtime nor in UTC/GMT time!\n"); exit(2); break; case 0: get_the_time = localtime; nvprintf(LOG_DEBUG, "RTC is running in localtime!\n"); break; case 1: get_the_time = gmtime; nvprintf(LOG_DEBUG, "RTC is running in UTC/GMT!\n"); break; default: get_the_time = NULL; exit(2); break; } now = time(NULL); nvprintf(LOG_DEBUG, "Test (this should be the current time of the hardware clock): %s", asctime((*get_the_time)(&now))); /* close the rtc device again */ close(fd_rtc); /* Fill oBytes with 0s */ memset(oBytes, 0, sizeof(oBytes)); /* Now we read whole nvram ... */ open_nvram(_directisa, O_RDONLY); nvramSize = read_whole_nvram(_directisa, b.upper_method, oBytes); close_nvram(_directisa); /* print a nice xxd-like table of nvram */ xxd(oBytes, nvramSize, LOG_DEBUG); /* Copy whole contents of oBytes to nBytes */ memcpy(nBytes, oBytes, sizeof(oBytes)); if (b.addr_stat && assign_byte(&oStat, &nStat, b.addr_stat, "addr_stat" )) exit(2); if (b.addr_mon && assign_byte(&oMon, &nMon, b.addr_mon, "addr_mon" )) exit(2); if (b.addr_day && assign_byte(&oDay, &nDay, b.addr_day, "addr_day" )) exit(2); if (b.addr_wdays && assign_byte(&oWdays, &nWdays, b.addr_wdays, "addr_wdays" )) exit(2); if (b.addr_hour && assign_byte(&oHour, &nHour, b.addr_hour, "addr_hour" )) exit(2); if (b.addr_min && assign_byte(&oMin, &nMin, b.addr_min, "addr_min" )) exit(2); if (b.addr_sec && assign_byte(&oSec, &nSec, b.addr_sec, "addr_sec" )) exit(2); if (b.rtc_day && assign_byte(&oRtcDay, &nRtcDay, b.rtc_day, "rtc_day" )) exit(2); if (b.rtc_mon && assign_byte(&oRtcMon, &nRtcMon, b.rtc_mon, "rtc_mon" )) exit(2); if (b.addr_chk_h && assign_byte(&oChkH, &nChkH, b.addr_chk_h, "addr_chk_h" )) exit(2); if (b.addr_chk_l && assign_byte(&oChkL, &nChkL, b.addr_chk_l, "addr_chk_l" )) exit(2); if (b.addr_chk_h2 && assign_byte(&oChkH2, &nChkH2, b.addr_chk_h2, "addr_chk_h2")) exit(2); if (b.addr_chk_l2 && assign_byte(&oChkL2, &nChkL2, b.addr_chk_l2, "addr_chk_l2")) exit(2); if (b.rtc_time == ON) { /* open the rtc device */ nvprintf(LOG_DEBUG, "Opening %s in O_RDONLY mode...\n", RTC_DEV); fd_rtc = open( RTC_DEV, O_RDONLY ); if (fd_rtc == -1) { nvprintf(LOG_ERR, "%s: %m\n", RTC_DEV); exit(2); } /* we read rtc alarm in this case */ retval = ioctl(fd_rtc, RTC_ALM_READ, &oRtc_tm); if (retval == -1) { nvprintf(LOG_ERR, "%s: %m\n", "ioctl RTC_ALM_READ"); exit(2); } /* close the rtc device again */ close(fd_rtc); } /* now put the two checksum bytes into one checksum */ if (b.addr_chk_h && b.addr_chk_l) { oChk = (*oChkH << 8) | *oChkL; nvprintf(LOG_DEBUG, "Checksum is: 0x%04X.\n", oChk); } if(b.addr_chk_h2) { oChk2 = (*oChkH2 << 8) | *oChkL2; nvprintf(LOG_DEBUG, "Checksum2 is: 0x%04X.\n", oChk2); } /* Now we will check all values for their correctness / plausibility... */ if (b.addr_mon && FROMBCD(calculate_read(*oMon, b.nr_mon, b.shift_mon)) > 12) { nvprintf(LOG_ERR, "WakeUp Month value (%02u) not correct.\n", FROMBCD(calculate_read(*oMon, b.nr_mon, b.shift_mon))); exit(2); } if (b.addr_day) { int day = 0; if (b.day_hack) /* on this boards the day is split over the day byte and the stat byte */ day = calculate_read(*oStat, b.day_hack, 8-b.day_hack ) | calculate_read(*oDay, b.nr_day-b.day_hack, 0 )< 31) { nvprintf(LOG_ERR, "WakeUp Day value (%02u) not correct.\n", day); exit(2); } } if (b.addr_wdays) { /* I think, there's nothing to check - every bit could be set */ /* or not. The only thing I could think of is that at least */ /* one bit has to be set. But I don't really know... */ } if (b.addr_hour && FROMBCD(calculate_read(*oHour, b.nr_hour, b.shift_hour)) > 23) { nvprintf(LOG_ERR, "WakeUp Hour value (%02u) not correct.\n", FROMBCD(calculate_read(*oHour, b.nr_hour, b.shift_hour))); exit(2); } if (b.addr_min && FROMBCD(calculate_read(*oMin, b.nr_min, b.shift_min)) > 59) { nvprintf(LOG_ERR, "WakeUp Minute value (%02u) not correct.\n", FROMBCD(calculate_read(*oMin, b.nr_min, b.shift_min))); exit(2); } if (b.addr_sec && FROMBCD(calculate_read(*oSec, b.nr_sec, b.shift_sec)) > 59) { nvprintf(LOG_ERR, "WakeUp Second value (%02u) not correct.\n", FROMBCD(calculate_read(*oSec, b.nr_sec, b.shift_sec))); exit(2); } if(b.rtc_day) { int day = calculate_read(*oRtcDay, b.nr_rtc_day, 0); if (b.rtc_day_0_is_c0 && day == 0xC0) day=0; day = bcd2bin(day); if (day > 31) { nvprintf(LOG_ERR, "WakeUp rtcDay value (%02u) not correct.\n", day); exit(2); } } if(b.rtc_mon) { int mon = calculate_read(*oRtcMon, b.nr_rtc_mon, 0); if (b.rtc_mon_0_is_c0 && mon == 0xC0) mon = 0; mon = bcd2bin(mon); if (mon > 12) { nvprintf(LOG_ERR, "WakeUp rtcMon value (%02u) not correct.\n", mon); exit(2); } } /* we should compare both values in case they are */ /* stored in both places. */ /* for now we will just output both values below */ if (b.addr_day && b.rtc_day ) {} if (b.addr_mon && b.rtc_mon ) {} /* we should compare the values with those from nvram */ /* in case they are stored in both places. */ /* for now we will just output both values below */ if(b.rtc_time == ON) {} /* Output stored values */ nvprintf(LOG_NOTICE, "\n"); nvprintf(LOG_NOTICE, "All values are displayed as they are stored in the nvram/rtc.\n"); nvprintf(LOG_NOTICE, "(and do not correspond necessarily to the system date/time)\n"); nvprintf(LOG_NOTICE, "\n"); nvprintf(LOG_NOTICE, "WakeUp : %s (0x%02X)\n", calculate_read(*oStat, b.nr_stat, b.shift_stat) ? "Enabled" : "Disabled", *oStat); if (b.addr_mon) nvprintf(LOG_NOTICE, "Month : %02u (0x%02X)\n", FROMBCD(calculate_read(*oMon, b.nr_mon, b.shift_mon)), *oMon); if (b.addr_day) { int d, od; if (b.day_hack) { d = calculate_read(*oStat, b.day_hack, 8-b.day_hack) | calculate_read(*oDay, b.nr_day-b.day_hack, 0 )<> (4-b.day_hack)), b.day_hack, 8-b.day_hack); *nDay = calculate_write(*nDay, vdr_abs_tm.tm_mday >> b.day_hack, b.nr_day-b.day_hack, 0 ); } } else { if (FROM_D_BCD(calculate_read(*nDay, b.nr_day, b.shift_day)) != vdr_abs_tm.tm_mday) *nDay = calculate_write(*nDay, TO_D_BCD(vdr_abs_tm.tm_mday), b.nr_day, b.shift_day); } } if (b.addr_wdays) { unsigned char weekday = 1 << vdr_abs_tm.tm_wday; nvprintf(LOG_DEBUG, "vdr_abs_tm.tm_wday = %d\n", vdr_abs_tm.tm_wday); if (calculate_read(*nWdays, b.nr_wdays, b.shift_wdays) != weekday) *nWdays = calculate_write(*nWdays, weekday, b.nr_wdays, b.shift_wdays); } if (b.addr_hour) { if ( FROMBCD(calculate_read(*nHour, b.nr_hour, b.shift_hour)) != vdr_abs_tm.tm_hour) *nHour = calculate_write(*nHour, TOBCD(vdr_abs_tm.tm_hour), b.nr_hour, b.shift_hour); } if (b.addr_min) { if ( FROMBCD(calculate_read(*nMin, b.nr_min, b.shift_min)) != vdr_abs_tm.tm_min) *nMin = calculate_write(*nMin, TOBCD(vdr_abs_tm.tm_min), b.nr_min, b.shift_min); } if (b.addr_sec) { if ( FROMBCD(calculate_read(*nSec, b.nr_sec, b.shift_sec)) != vdr_abs_tm.tm_sec) *nSec = calculate_write(*nSec, TOBCD(vdr_abs_tm.tm_sec % 60), b.nr_sec, b.shift_sec); } if (b.rtc_mon) { if ( bcd2bin(calculate_read(*nRtcMon, b.nr_rtc_mon, 0)) != (vdr_abs_tm.tm_mon+1)) *nRtcMon = calculate_write(*nRtcMon, bin2bcd(vdr_abs_tm.tm_mon+1), b.nr_rtc_mon, 0); } if (b.rtc_day) { if ( bcd2bin(calculate_read(*nRtcDay, b.nr_rtc_day, 0)) != vdr_abs_tm.tm_mday) *nRtcDay = calculate_write(*nRtcDay, bin2bcd(vdr_abs_tm.tm_mday), b.nr_rtc_day, 0); } if (b.rtc_time==ON) { nRtc_tm.tm_sec = vdr_abs_tm.tm_sec ; nRtc_tm.tm_min = vdr_abs_tm.tm_min ; nRtc_tm.tm_hour = vdr_abs_tm.tm_hour ; /* we shouldn't need the following lines ... * nRtc_tm.tm_mday = vdr_abs_tm.tm_mday ; * nRtc_tm.tm_mon = vdr_abs_tm.tm_mon ; * nRtc_tm.tm_year = vdr_abs_tm.tm_year ; * nRtc_tm.tm_wday = vdr_abs_tm.tm_wday ; * nRtc_tm.tm_yday = vdr_abs_tm.tm_yday ; * nRtc_tm.tm_isdst = vdr_abs_tm.tm_isdst; */ } nvprintf(LOG_NOTICE, "Enabling (0x%02X) WakeUp-on-RTC in nvram.\n", *nStat); if (b.addr_mon) nvprintf(LOG_NOTICE, "New Month : %02u (0x%02X)\n", FROMBCD(calculate_read(*nMon, b.nr_mon, b.shift_mon)), *nMon); if (b.addr_day) { int d, nd; if (b.day_hack) { d = calculate_read(*nStat, b.day_hack, 8-b.day_hack) | calculate_read(*nDay, b.nr_day-b.day_hack, 0 )<> 8; /* in the case of an overflow we just throw away * the bits higher than the 16 bits we could store */ } if (b.addr_chk_h2 && b.addr_chk_l2) { *nChkL2 = nChk2 & 0x00FF; *nChkH2 = (nChk2 & 0xFF00) >> 8; } if (b.addr_chk_h && b.addr_chk_l) nvprintf(LOG_NOTICE, "New Checksum: 0x%02X%02X\n", *nChkH, *nChkL); if (b.addr_chk_h2 && b.addr_chk_l2) nvprintf(LOG_NOTICE, "New Checksum2: 0x%02X%02X\n", *nChkH2, *nChkL2); nvprintf(LOG_NOTICE, "\n"); /* Check if something changed and write the values back, if needed ... */ for (addr=0; addr < nvramSize ; addr++) if (oBytes[addr] - nBytes[addr]) { nvprintf(LOG_DEBUG, "Byte 0x%02X is changed: 0x%02X -> 0x%02X\n", addr, oBytes[addr], nBytes[addr]); /* Now really WRITING into /dev/nvram */ if (!changed) { if (! _nowrite) { nvprintf(LOG_NOTICE, "Now really WRITING into %s...\n", NVRAM_DEV); open_nvram( _directisa, O_WRONLY ); } changed = 1; } if (! _nowrite) { write_back(_directisa, b.upper_method, addr, nBytes); } } if (! _nowrite) { /* close the nvram device again */ if (changed) close_nvram(_directisa); } if (b.rtc_time == ON) { if (vdr_abs_time_t != 0 && (nRtc_tm.tm_sec != oRtc_tm.tm_sec || nRtc_tm.tm_min != oRtc_tm.tm_min || nRtc_tm.tm_hour != oRtc_tm.tm_hour ) ) { nvprintf(LOG_DEBUG, "RTC time is changed. Setting RTC alarm into %s\n", RTC_DEV); /* Setting RTC alarm into /dev/rtc */ if (!changed) { if (! _nowrite) nvprintf(LOG_NOTICE, "Setting RTC alarm into %s...\n", RTC_DEV); changed = 1; } else { if (! _nowrite) nvprintf(LOG_NOTICE, "And setting RTC alarm into %s...\n", RTC_DEV); } if (! _nowrite) { nvprintf(LOG_NOTICE, "\n"); /* open the rtc device */ nvprintf(LOG_DEBUG, "Opening %s in O_RDONLY mode...\n", RTC_DEV); fd_rtc = open( RTC_DEV, O_RDONLY ); if (fd_rtc == -1) { nvprintf(LOG_ERR, "%s: %m\n", RTC_DEV); exit(2); } retval = ioctl(fd_rtc, RTC_ALM_SET, &nRtc_tm); if (retval == -1) { nvprintf(LOG_CRIT, "Ioctl RTC_ALM_SET failed: %m\n"); exit(2); } /* Enable alarm interrupts */ /* Do we need this? */ /* * retval = ioctl(fd_rtc, RTC_AIE_ON, 0); * if (retval == -1) { * nvprintf(LOG_CRIT, "ioctl RTC_AIE_ON: %m\n"); * exit(2); * } */ /* close the rtc device again */ close(fd_rtc); } } } nvprintf(LOG_DEBUG, "need_reboot: %d\n", need_reboot); if (!changed) /* there was nothing to do: all values were already correct */ exit(0); else { if (_nowrite) { nvprintf(LOG_NOTICE, " Actually, nothing was written into %s nor into %s.\n", NVRAM_DEV, RTC_DEV); nvprintf(LOG_NOTICE, " (since --nowrite option was used).\n"); nvprintf(LOG_NOTICE, " \n"); exit(2); } else { if (need_reboot) { nvprintf(LOG_NOTICE, " The changes to take effect, you must reboot your computer now.\n"); nvprintf(LOG_NOTICE, " \n"); exit(1); } else { /* don't need to reboot. */ exit(0); } } } } /* end main */ /* * Parse command line arguments */ struct option opts[] = { {"settime", 1, 0, 's'}, {"disable", 0, 0, 'd'}, {"configfile", 1, 0, 'C'}, {"iwname", 1, 0, 'I'}, {"directisa", 0, 0, 'A'}, {"nowrite", 0, 0, 'N'}, {"debug", 0, 0, 'D'}, {"syslog", 0, 0, 'l'}, {"wakeupbefore", 1, 0, 'w'}, {"version", 0, 0, 'v'}, {"help", 0, 0, 'h'}, {"nocheck", 0, 0, 'n'}, {NULL, 0, 0, 0 }, }; const char *optstring = "s:dC:I:ANDlw:vhn"; const char *opts_help[] = { "Set the given wakeup date/time (given as a time_t value).", /* settime */ "Disable WakeUp. Equivalent to --settime=0.", /* disable */ "Read board configuration from specified configuration file.", /* configfile */ "Specify the IW (infowriter) name.", /* iwname */ "Use direct ISA access to read/write nvram instead of /dev/nvram.", /* directisa */ "Don't write any values (in /dev/nvram or /dev/rtc). For testing.", /* nowrite */ "Enable printing debug messages.", /* debug */ "Log all output via syslogd instead of stdout/stderr.", /* syslog */ "Start that many minutes before the wakeuptime (default is 5).", /* wakeupbefore */ "Print version information.", /* version */ "Print this message (always to stderr, regardless of --syslog).", /* help */ "Don't check if the time argument is in the future", /* nocheck */ }; void print_usage(void) { int max, size; struct option *opt; const char **hlp; nvprintf(LOG_INFO, "\n"); nvprintf(LOG_INFO, "Usage: %s [OPTIONS]\n", get_progname()); max = 0; for (opt = opts; opt->name; opt++) { size = strlen(opt->name); if (size > max) max = size; } for (opt = opts, hlp = opts_help; opt->name; opt++, hlp++) nvprintf(LOG_INFO, " -%c, --%-*s%s\n", opt->val, max+2, opt->name, *hlp); nvprintf(LOG_INFO, "\n"); nvprintf(LOG_INFO, " All specified wakeup times are times at which the PC should be up and running.\n"); nvprintf(LOG_INFO, "\n"); exit(2); } /* * opterr = 0; */ static int handle_cmdline(int *argc, char ***argv) { for (;;) { int i = getopt_long(*argc, *argv, optstring, opts, NULL); if (i == -1) break; switch (i) { /* * case '?': * nvprintf(LOG_ERR, "invalid option: %d,%s,%c\n", optind, (*argv)[optind-1], optopt); * print_usage(); * break; */ case 's': if ( strlen(optarg) > strspn(optarg, "0123456789") ) { /* if the time is not a number */ nvprintf(LOG_ERR, "\"%s\" is not a number\n", optarg); print_usage(); } else if ( vdr_abs_time_t >= 0 && strtol(optarg, NULL, 10) != vdr_abs_time_t ) { /* if two different times specified at the same time */ nvprintf(LOG_ERR, "two different times specified at the same time\n"); print_usage(); } else { vdr_abs_time_t = strtol(optarg, NULL, 10); } break; case 'd': if (vdr_abs_time_t > 0) { /* if -s positivetime and -d options given at the same time */ nvprintf(LOG_ERR, "-s %u and -d specified at the same time\n", (unsigned int)vdr_abs_time_t); print_usage(); } else { vdr_abs_time_t = 0; } break; case 'C': if (_config_file && strcmp(_config_file, optarg)) { nvprintf(LOG_ERR, "Two different configuration files specified.\n"); print_usage(); } _config_file = optarg; break; case 'I': if (_iw_string && strcmp(_iw_string, optarg)) { nvprintf(LOG_ERR, "Two different infowriter strings specified.\n"); print_usage(); } _iw_string = optarg; break; case 'D': enable_debug(); nvprintf(LOG_DEBUG, "Printing debug messages enbled.\n"); for(i=0; CVS_ALL[i]; i++) nvprintf(LOG_DEBUG, "%s\n", CVS_ALL[i]); nvprintf(LOG_DEBUG, "Built at: " __DATE__ " " __TIME__ "\n"); break; case 'A': nvprintf(LOG_DEBUG, "Direct ISA access enabled.\n"); _directisa = ON; break; case 'N': _nowrite = ON; break; case 'n': _check_time = OFF; break; case 'l': enable_syslog(); openlog( get_progname(), LOG_CONS || LOG_PID, LOG_USER ); fprintf(stderr, "--syslog parameter specified. All output goes to the syslog\n"); break; case 'v': nvprintf(LOG_NOTICE, "NVRAM WakeUp - Copyright (C) 2001-2005, Sergei Haller.\n"); nvprintf(LOG_NOTICE, PACKAGE "-" VERSION "\n"); exit(0); case 'w': if ( strlen(optarg) > strspn(optarg, "0123456789") ) { /* if the argument is not a number */ nvprintf(LOG_ERR, "\"%s\" is not a number\n", optarg); print_usage(); } else if ( strtol(optarg, NULL, 10) < 0 ) { /* argument must be >= 0 */ nvprintf(LOG_ERR, "wakeupbefore must be bigger or equal 0.\n"); print_usage(); } else { wakeupbefore = strtol(optarg, NULL, 10); } break; case 'h': default: print_usage(); break; } } *argc -= optind; *argv += optind; if (*argc > 0) { nvprintf(LOG_ERR, "invalid parameter: %s\n", *argv[0]); print_usage(); } if (_config_file && _iw_string) nvprintf(LOG_WARNING, "Configuration file and IW name specified at command line -- ignoring IW name\n"); return 0; }