diff --git a/acinclude.m4 b/acinclude.m4 index 69d0b8149..a90ad03e0 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -591,6 +591,9 @@ case "$BOXTYPE" in esac AM_CONDITIONAL(HAVE_LIBSTB_HAL, test "$libstb_hal" = "yes") +# uclibc +AM_CONDITIONAL(HAVE_UCLIBC, test "$targetlibdir/ld-uClibc.so.0") + # generic if test "$BOXMODEL" = "generic"; then AC_DEFINE(BOXMODEL_GENERIC, 1, [generic pc]) diff --git a/src/system/Makefile.am b/src/system/Makefile.am index 02caba258..630f7f873 100644 --- a/src/system/Makefile.am +++ b/src/system/Makefile.am @@ -46,3 +46,8 @@ libneutrino_system_a_SOURCES = \ ytparser.cpp \ setting_helpers.cpp # safe_system.c + +if HAVE_UCLIBC +libneutrino_system_a_SOURCES += \ + tzif-display.cpp +endif diff --git a/src/system/setting_helpers.cpp b/src/system/setting_helpers.cpp index 4ae819fe0..dab1943ac 100644 --- a/src/system/setting_helpers.cpp +++ b/src/system/setting_helpers.cpp @@ -35,6 +35,9 @@ #include #include "configure_network.h" +#ifdef __UCLIBC__ +#include "tzif-display.h" +#endif #include #include #include @@ -660,7 +663,20 @@ bool CTZChangeNotifier::changeNotify(const neutrino_locale_t, void *Data) fprintf(f, "%s\n", zone.c_str()); fclose(f); } +#ifdef __UCLIBC__ + const char *tzif_rule = get_tzif_rule(cmd.c_str()); + if (tzif_rule == NULL) + return false; + f = fopen("/etc/TZ", "w"); + if (f) + { + fprintf(f, "%s\n", tzif_rule); + fclose(f); + } + cmd = tzif_rule; +#else cmd = ":" + zone; +#endif setenv("TZ", cmd.c_str(), 1); tzset(); } diff --git a/src/system/tzif-display.cpp b/src/system/tzif-display.cpp new file mode 100644 index 000000000..3db212f8c --- /dev/null +++ b/src/system/tzif-display.cpp @@ -0,0 +1,258 @@ +/** tzif-display.c http://libhdate.sourceforge.net + * display contents of tzif file (in support of hcal and hdate) + * hcal.c Hebrew calendar (part of package libhdate) + * hdate.c Hebrew date/times information(part of package libhdate) + * + * compile: + * gcc -c -Wall -Werror -g tzif-display.c + * build: + * gcc -Wall tzif-display.c -o tzif-display + * run: + * ./tzif-display full-pathname-to-tzif-file + * + * Copyright: 2012 (c) Boruch Baum + * + * 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 3 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, see . + */ + +#include "tzif-display.h" + +/*************************************************** +* parse a tzfile "long format" value +***************************************************/ +long parse_tz_long( const char *sourceptr, const int field_size) +{ + long retval = 0; + char *long_ptr; + +// if (sizeof(long) < field_size) +// printf("warning: field truncated because it is larger than a 'long' integer\n\n"); + + int i,j; + long_ptr = (char*) &retval; + if ((field_size < (int)sizeof(long)) && (sourceptr[0] >> 8)) + { + for (i=sizeof(long)-1; (i>=field_size); i--) long_ptr[i] = 255; + } + j = 0; + for (i=field_size-1; (i>=0) && (j<(int)sizeof(long)); i--) + { + long_ptr[j] = sourceptr[i]; + j++; + } + return retval; +} + +/*************************************************** +* read a tzheader file +***************************************************/ +int read_tz_header( timezonefileheader *header, const char *temp_buffer) +{ + const int field_size = 4; + + memcpy( header->magicnumber, &temp_buffer[0], 5 ); + header->magicnumber[5] = '\0'; + + header->ttisgmtcnt = parse_tz_long(&temp_buffer[20], field_size); + header->ttisstdcnt = parse_tz_long(&temp_buffer[24], field_size); + header->leapcnt = parse_tz_long(&temp_buffer[28], field_size); + header->timecnt = parse_tz_long(&temp_buffer[32], field_size); + header->typecnt = parse_tz_long(&temp_buffer[36], field_size); + header->charcnt = parse_tz_long(&temp_buffer[40], field_size); +#if 0 + printf("Header format ID: %s\n",header->magicnumber); + printf("number of UTC/local indicators stored in the file = %ld\n", header->ttisgmtcnt); + printf("number of standard/wall indicators stored in the file = %ld\n",header->ttisstdcnt); + printf("number of leap seconds for which data is stored in the file = %ld\n",header->leapcnt); + printf("number of \"transition times\" for which data is stored in the file = %ld\n",header->timecnt); + printf("number of \"local time types\" for which data is stored in the file (must not be zero) = %ld\n",header->typecnt); + printf("number of characters of \"timezone abbreviation strings\" stored in the file = %ld\n\n",header->charcnt); +#endif + if (header->typecnt == 0) + { + printf("Error in file format. Zero local time types suggested.\n"); + return false; + } + + if (header->timecnt == 0) + { + printf("No transition times recorded in this file\n"); + return false; + } + +return true; +} + +/*********************************************************************** +* tzif2_handle +***********************************************************************/ +char* tzif2_handle( timezonefileheader *tzh, const char *tzfile_buffer_ptr, size_t buffer_size ) +{ + char *start_ptr; + char magicnumber[6] = "TZif2"; + + printf("tzif handle format 2\n"); + + start_ptr = (char*)memmem( tzfile_buffer_ptr, buffer_size, &magicnumber, sizeof(magicnumber) ); + if (start_ptr == NULL) + { + printf("error finding tzif2 header\n"); + return NULL; + } + + printf("tzif2 header found at position %d\n", start_ptr - tzfile_buffer_ptr); + if ( read_tz_header( tzh, (char*) start_ptr ) == false ) + { + printf("Error reading header file version 2\n"); + return NULL; + } + + return start_ptr + HEADER_LEN; +} + + +/*************************************************** +* Display contents of a timezone file +***************************************************/ +char *display_tzfile_data( const timezonefileheader tzh, + const char* tzfile_buffer_ptr, + const int field_size /// 4bytes for tzif1, 8bytes for tzif2 + ) +{ + char *local_time_type_ptr; + + typedef struct { + long gmtoff; // seconds to add to UTC + char is_dst; // whether tm_isdst should be set by localtime(3) + char abbrind; // index into the array of timezone abbreviation characters + } ttinfo_struct; + + ttinfo_struct *ttinfo_data_ptr; + char *ttinfo_read_ptr; + char* tz_abbrev_ptr; + char *leapinfo_ptr; + char *wall_indicator_ptr; + char *local_indicator_ptr; + char *general_rule = NULL; + + local_time_type_ptr = (char*) tzfile_buffer_ptr + tzh.timecnt*field_size; + ttinfo_read_ptr = local_time_type_ptr + tzh.timecnt; + + ttinfo_data_ptr = (ttinfo_struct*)malloc( sizeof(ttinfo_struct) * tzh.typecnt); + if (ttinfo_data_ptr == NULL) + { + printf("memory allocation error - ttinfo_data\ntzname = "); + return NULL; + } + + /// timezone abbreviation list + tz_abbrev_ptr = ttinfo_read_ptr + (tzh.typecnt * 6); + + leapinfo_ptr = tz_abbrev_ptr + (tzh.charcnt); + + wall_indicator_ptr = leapinfo_ptr + (tzh.leapcnt*field_size*2); + + local_indicator_ptr = wall_indicator_ptr + tzh.ttisstdcnt; + + if (field_size == TZIF2_FIELD_SIZE) + { + /// parse 'general rule' at end of file + /// format should be per man(3) tzset + char *start_line_ptr; + start_line_ptr = strchr( local_indicator_ptr + tzh.ttisgmtcnt, 10 ); + if (start_line_ptr == NULL) + printf("\nno \'general rule\' information found at end of file\n"); + else + { + char *end_line_ptr; + end_line_ptr = strchr( start_line_ptr+1, 10 ); + if (end_line_ptr == NULL) + printf("\nerror finding \'general rule\' info terminator symbol\n"); + else + { + *end_line_ptr = '\0'; + printf("general rule: %s\n", start_line_ptr+1 ); + general_rule = start_line_ptr+1; + } + } + } + free(ttinfo_data_ptr); + return general_rule; +} + +const char *get_tzif_rule(const char *filename) +{ + FILE *tz_file; + char *tzif_buffer_ptr; + char *start_ptr; + int field_size; + const char *rule = NULL; + struct stat file_status; + timezonefileheader tzh; + + tz_file = fopen(filename, "rb"); + + if (tz_file == NULL) + { + error(errno,0,"tz file %s not found\n", filename); + return NULL; + } + + if (fstat( fileno( tz_file), &file_status) != 0) + { + printf("error retreiving file status\n"); + fclose(tz_file); + return NULL; + } + + tzif_buffer_ptr = (char *) malloc( file_status.st_size ); + if (tzif_buffer_ptr == NULL) + { + printf("memory allocation error - tzif buffer\n"); + fclose(tz_file); + return NULL; + } + + if ( fread( tzif_buffer_ptr, file_status.st_size, 1, tz_file) != 1 ) + { + printf("error reading into tzif buffer\n"); + free(tzif_buffer_ptr); + return NULL; + } + fclose(tz_file); + + + if ( read_tz_header( &tzh, tzif_buffer_ptr ) == false ) + { + printf("Error reading header file version 1\n"); + free(tzif_buffer_ptr); + return NULL; + } + + if (tzh.magicnumber[4] == 50 ) + { + start_ptr = tzif2_handle( &tzh, &tzif_buffer_ptr[HEADER_LEN], file_status.st_size - HEADER_LEN); + field_size = TZIF2_FIELD_SIZE; + } + else + { + start_ptr = &tzif_buffer_ptr[HEADER_LEN]; + field_size = TZIF1_FIELD_SIZE; + } + if (start_ptr != NULL) + rule = display_tzfile_data( tzh, start_ptr, field_size ); + + free(tzif_buffer_ptr); + return rule; +} diff --git a/src/system/tzif-display.h b/src/system/tzif-display.h new file mode 100644 index 000000000..600dd08eb --- /dev/null +++ b/src/system/tzif-display.h @@ -0,0 +1,57 @@ +/** tzif-display.h http://libhdate.sourceforge.net + * + * Copyright: 2012 (c) Boruch Baum + * + * 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 3 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, see . + */ + +#ifndef _TZIF_DISPLAY_H_ +#define _TZIF_DISPLAY_H_ + +#include /// For printf, fopen, fclose, FILE +#include /// For malloc, free +#include /// For error +#include /// For errno +#include /// for memset, memcpy, memmem +#include /// for stat +#include /// for setlocale +#include /// for ctime_r, tzset + +/*************************************************** +* definition of a tzfile header +***************************************************/ +#define HEADER_LEN 44 +typedef struct { + char magicnumber[6]; // = TZif2 or TZif\0 +// char reserved[15]; // nulls + long unsigned ttisgmtcnt; // number of UTC/local indicators stored in the file. + long unsigned ttisstdcnt; // number of standard/wall indicators stored in the file. + long unsigned leapcnt; // number of leap seconds for which data is stored in the file. + long unsigned timecnt; // number of "transition times" for which data is stored in the file. + long unsigned typecnt; // number of "local time types" for which data is stored in the file (must not be zero). + long unsigned charcnt; // number of characters of "timezone abbreviation strings" stored in the file. + } timezonefileheader; +#define TZIF1_FIELD_SIZE 4 +#define TZIF2_FIELD_SIZE 8 + +long parse_tz_long( const char *sourceptr, const int field_size); +int read_tz_header( timezonefileheader *header, const char *temp_buffer); +char *tzif2_handle( timezonefileheader *tzh, const char *tzfile_buffer_ptr, size_t buffer_size ); +char *display_tzfile_data( const timezonefileheader tzh, + const char* tzfile_buffer_ptr, + const int field_size /// 4bytes for tzif1, 8bytes for tzif2 + ); +const char *get_tzif_rule(const char *filename); + +#endif