#include #include #include #include #include #include #include #include "netconf.h" #include "internal.h" #include #include #include "netconf.m" #include #include static const char DATETIME_P[]="datetime"; static const char UNIVERSAL[]="universal"; static const char ALPHAARC[]="alphaarc"; static const char NETDATE[]="netdate"; static NETCONF_HELP_FILE help_date ("datetime"); PUBLIC DATETIME::DATETIME() { universal = linuxconf_getvalnum (DATETIME_P,UNIVERSAL,0); netdate.setfrom (linuxconf_getval (DATETIME_P,NETDATE)); /* #Specification: clock / Dec Alpha / ARC parameter Linuxconf does not managed the ARC parameter, but use it when calling the clock command. Linuxconf request this information by reading its status in /etc/conf.linuxconf using the linuxconf_getvalnum() function (gettting 0 or 1). Linuxconf assumes that a distribution specific module will intercept this request and provide the install time value. */ alphaarc = linuxconf_getvalnum (DATETIME_P,ALPHAARC,0); } PUBLIC void DATETIME::save() { linuxconf_setcursys (subsys_hardware); linuxconf_replace (DATETIME_P,UNIVERSAL,universal); linuxconf_setcursys (subsys_netclient); linuxconf_replace (DATETIME_P,NETDATE,netdate); linuxconf_save(); } /* Extract recursively a directory, getting all files. tbf will contain the path relative to a certain path (using skip_prefix to strip the beginning). */ static void datetime_zonelst ( int skip_prefix, SSTRINGS &tbf, const char *path) { /* #Specification: netconf / datetime / zoneinfo / options netconf finds the possible time zone available by listing the content of the directory /usr/lib/zoneinfo. It does it recursively. It avoid symbolic links and executable file. The file "time.doc" is also removed explicitly since many slackware do contain it. */ int start = tbf.getnb(); dir_getlist (path,tbf); int end = tbf.getnb(); for (int i=start; iget(); snprintf (fpath,sizeof(fpath)-1,"%s/%s",path,pt); struct stat st; char *replace = ""; if (lstat (fpath,&st)!=-1){ if (S_ISDIR(st.st_mode)){ if (strcmp(pt,".")!=0 && strcmp(pt,"..")!=0){ datetime_zonelst (skip_prefix ,tbf,fpath); } }else if(S_ISREG(st.st_mode) && strcmp(pt,"time.doc")!=0 && ! (st.st_mode & 0100)){ // As you see, we only collect regular // file. All others (directories, special // files or files that can't be stat will // be thrown away. replace = fpath+skip_prefix; } } str->setfrom(replace); } } static const char *datetime_getzonedir() { /* #Specification: datetime / zone files / zone dir location Linuxconf probes for either /usr/share/zoneinfo or /usr/lib/zoneinfo in that order. */ const char *ret = USR_SHARE_ZONEINFO; if (!file_exist (ret)) ret = USR_LIB_ZONEINFO; return ret; } static void datetime_zonelst (FIELD_COMBO *comb, SSTRINGS &tbf) { tbf.sort(); int nb = tbf.getnb(); for (int i=0; iget(); if (pt[0] != '\0') comb->addopt (pt); } } static int datetime_compare (const char *f1, const char *f2) { int ret = -1; FILE *fin1 = fopen (f1,"r"); if (fin1 != NULL){ FILE *fin2 = fopen (f2,"r"); if (fin2 != NULL){ while (1){ char buf1[4096],buf2[4096]; int len1 = fread (buf1,1,sizeof(buf1),fin1); int len2 = fread (buf2,1,sizeof(buf2),fin2); if (len1 != len2){ break; }else if (len1 <= 0){ ret = 0; break; }else if (memcmp(buf1,buf2,len1)!=0){ break; } } fclose (fin2); } fclose (fin1); } return ret; } /* Get or set the current zoneinfo by reading the symbolic link /usr/lib/zoneinfo/localtime. */ static void datetime_getsetcurzone( SSTRING &str, const char *dir, SSTRINGS &tbzone) { /* #Specification: netconf / datetime / zoneinfo / current (As far as I know, this strategy is obsolete, but linuxconf tries to use it if /etc/localtime is missing) netconf finds out the current zone by looking at the symbolic links /usr/lib/zoneinfo/localtime. It will follow this link up to five time. When setting the new time zone, it will also follows the links and redo only the last one. The idea here is that it support both strategy # ln -sf /usr/lib/zoneinfo/country/value /usr/lib/zoneinfo/localtime # and # ln -sf /usr/lib/zoneinfo/country/value /var/lib/zoneinfo/localtime ln -sf /var/lib/zoneinfo/localtime /usr/lib/zoneinfo/localtime # The later being more "correct" fsstnd wise. */ struct stat st; if (stat(ETC_LOCALTIME,&st)!=-1 && S_ISREG(st.st_mode)){ if (str.is_empty()){ /* #Specification: netconf / datetime / zoneinfo / current WHen /etc/localtime is there, we locate the time zone by searching in /usr/share/zoneinfo for a file matching /etc/localtime. We have not found any way to find the original setting */ for (int i=0; iget(); snprintf (path,sizeof(path)-1,"%s/%s",dir,zone); struct stat stzone; if (stat(path,&stzone)!=-1 && S_ISREG(stzone.st_mode) && st.st_size == stzone.st_size && datetime_compare(ETC_LOCALTIME,path)==0){ str.setfrom(zone); break; } } }else{ char path[PATH_MAX]; snprintf (path,sizeof(path)-1,"%s/%s",dir,str.get()); // We unlink first, to delete any potential symlink unlink (ETC_LOCALTIME); file_copy (path,ETC_LOCALTIME); } }else{ int iter = 0; char path[PATH_MAX]; strcpy (path,USR_LIB_LOCALTIME); while (iter < 5){ char buf[PATH_MAX]; int nb = readlink (path,buf,sizeof(buf)-1); if (nb != -1){ buf[nb] = '\0'; struct stat st; if (lstat(buf,&st)!=-1 && S_ISLNK(st.st_mode)){ strcpy (path,buf); iter++; }else{ const char *zonedir = datetime_getzonedir(); if (str.is_empty()){ int skip = 0; int len = strlen(zonedir); if (strncmp(zonedir,buf,len) == 0 && buf[len] == '/') skip = len+1; str.setfrom (buf+skip); }else{ unlink (path); const char *pt = str.get(); if (pt[0] != '/'){ snprintf (buf,sizeof(buf)-1,"%s/%s",zonedir,pt); pt = buf; } symlink (pt,path); } break; } }else{ break; } } } } PUBLIC int DATETIME::edit () { int ret = -1; if (perm_rootaccess(MSG_U(P_CHGDATE,"correct the date and time"))){ DIALOG dia; SSTRING year,month,mday,hour,minutes,seconds; { time_t t; time (&t); struct tm *tmt = localtime (&t); month.setfrom (tmt->tm_mon+1); year.setfrom (tmt->tm_year+1900); mday.setfrom (tmt->tm_mday); hour.setfrom (tmt->tm_hour); minutes.setfrom (tmt->tm_min); seconds.setfrom (tmt->tm_sec); } SSTRINGS tbzone; SSTRING zone; const char *zonedir = datetime_getzonedir(); datetime_zonelst (strlen(zonedir)+1,tbzone,zonedir); datetime_getsetcurzone (zone,zonedir,tbzone); FIELD_COMBO * comb = dia.newf_combo (MSG_U(F_ZONE,"zone"),zone); datetime_zonelst (comb,tbzone); dia.newf_chk (MSG_U(F_STORECMOS,"Store date in CMOS"),universal ,MSG_U(F_UNIVERSAL,"universal format(GMT)")); dia.newf_str (MSG_U(F_GETDATE,"Get date from server(s)"),netdate); dia.newf_title (MSG_U(T_TIME,"Time"),1,"",MSG_R(T_TIME)); dia.newf_str (MSG_U(F_HOUR,"Hour"),hour); dia.set_donotcheckold(); dia.newf_str (MSG_U(F_MINUTES,"Minutes"),minutes); dia.set_donotcheckold(); dia.newf_str (MSG_U(F_SECONDS,"Seconds"),seconds); dia.set_donotcheckold(); dia.newf_title (MSG_U(T_DATE,"Date"),1,"",MSG_R(T_DATE)); dia.newf_str (MSG_U(F_YEAR,"Year"),year); dia.newf_str (MSG_U(F_MONTH,"Month"),month); dia.newf_str (MSG_U(F_DAYOFMONTH,"Day of month"),mday); if (dia.edit (MSG_U(T_DATETIME,"Workstation date & time") ,MSG_U(I_DATETIME ,"Fill this form to indicate how the workstation must\n" "get its date and time\n") ,help_date) == MENU_ACCEPT){ datetime_getsetcurzone (zone,zonedir,tbzone); struct tm tmt; tmt.tm_hour = hour.getval(); tmt.tm_min = minutes.getval(); tmt.tm_sec = seconds.getval(); tmt.tm_year = year.getval(); if (tmt.tm_year > 1900) tmt.tm_year -= 1900; tmt.tm_mon = month.getval()-1; tmt.tm_mday = mday.getval(); tmt.tm_isdst = -1; save(); if (!simul_isdemo()){ if (netdate.is_empty()){ time_t t = mktime (&tmt); stime (&t); }else{ getfromnet(); } updatecmos(); }else{ xconf_notice ("Not in demo mode"); } ret = 0; } } return ret; } PUBLIC void DATETIME::updatecmos() { net_introlog (NETINTRO_MISC); net_prtlog (NETLOG_TITLE,MSG_U(N_SETTINGSYSTIME,"Setting system date & time\n")); char tmp[20]; snprintf (tmp,sizeof(tmp)-1,"-w %s %s" ,universal ? "-u" : "--localtime" ,alphaarc ? "-A" : ""); if(netconf_system_if ("clock",tmp) != 0){ net_prtlog (NETLOG_VERB,MSG_U(N_SYNTAX,"New syntax failed, using old\n")); snprintf (tmp,sizeof(tmp)-1,"-w %s %s" ,universal ? "-u" : "" ,alphaarc ? "-A" : ""); netconf_system_if ("clock",tmp); } } /* Get the date from CMOS */ PUBLIC int DATETIME::getfromcmos() { char tmp[20]; int ret; snprintf (tmp,sizeof(tmp)-1,"-s %s %s" ,universal ? "-u" : "--localtime" ,alphaarc ? "-A" : ""); ret = netconf_system_if ("clock",tmp); if(ret != 0){ net_prtlog (NETLOG_VERB,MSG_R(N_SYNTAX)); snprintf (tmp,sizeof(tmp)-1,"-s %s %s" ,universal ? "-u" : "" ,alphaarc ? "-A" : ""); ret = netconf_system_if ("clock",tmp); } return ret; } /* Get the current date and time from servers on the net. This will be done only if configured. Return -1 if any error. Return 0 if ok or if it was not configured to do so. */ PUBLIC int DATETIME::getfromnet() { int ret = 0; if (!netdate.is_empty()){ ret = netconf_system_if ("netdate",netdate.get()); if (ret == 0) updatecmos(); } return ret; } int datetime_getfromnet() { DATETIME dt; return dt.getfromnet(); } int datetime_getfromcmos() { DATETIME dt; return dt.getfromcmos(); } void datetime_edit() { DATETIME dt; dt.edit(); } /* Record the mode for the cmos clock mode is either "local" or something else */ void datetime_setmode (const char *mode) { linuxconf_setcursys (subsys_hardware); linuxconf_replace (DATETIME_P,UNIVERSAL,(int)(stricmp(mode,"local")!=0)); linuxconf_save(); } #include static PUBLISH_VARIABLES_MSG date_var_list1[]={ {"zone",P_MSG_R(F_ZONE)}, {"utccmos",P_MSG_R(F_UNIVERSAL)}, {"timeserver",P_MSG_R(F_GETDATE)}, {"hour",P_MSG_R(F_HOUR)}, {"minute",P_MSG_R(F_MINUTES)}, {"second",P_MSG_R(F_SECONDS)}, {"year",P_MSG_R(F_YEAR)}, {"month",P_MSG_R(F_MONTH)}, {"day",P_MSG_R(F_DAYOFMONTH)}, { NULL, NULL } }; static REGISTER_VARIABLES date_registry1("datetime",date_var_list1 ,NULL,datetime_edit);