Juan Leseduarte wrote: > Supongo que consiste en el mensaje que ya enviaron a esta misma lista hace un > tiempo. Era realmente muy interesante, y era específico para Debian, ya que
Como supongo que hablas del email que escribí en noviembre: ¡muchas gracias! El documento En-Hora-Como.html no tiene nada que ver con mi email de noviembre. > está basado en los scripts que tiene por defecto Debian. No obstante, creo > que hay un fallo (ojo, en los scripts de Debian, no en el documento). Me > explico: La idea del método es: Al arrancar Debian, el reloj del sistema > pregunta al reloj de hardware la hora que es, éste responde, pero el el > sistema no se la cree, si no que dice: bueno como que desde la última vez que > se apagó Debian ha pasado tanto tiempo, y como sé ( porque lo dice así > /etc/adjtime ) que el reloj de hard necesita un ajuste de X segundos por día, > la hora que doy por buena es: > > hora que da el reloj de hard + X*número de días (en decimal) que han pasado. Correcto: todo ello lo hacen las siguientes dos líneas del fichero /etc/rcS.d/S50hwclock.sh -> ../init.d/hwclock.sh: hwclock --adjust $GMT hwclock --hctosys $GMT La primera "arregla" la hora del reloj hardware basándose en cuánto tiempo lleva el reloj hardware sin ser corregido y su atraso X. Estos dos datos se obtienen de /etc/adjtime. Este fichero contiene como datos: 1) atraso (en segundos/día, si el reloj hardware adelanta entonces el atraso es negativo), 2) fecha de la última corrección (en segundos desde nochevieja de 1969), 3) un cero, 4) fecha de la última calibración (en segundos desde nochevieja de 1969). Aquí es importante distinguir entre calibración y corrección. La corrección es cuando se pone el reloj hardware a una hora, mientras que en una calibración esta hora se considera fiable y se puede usar para cálculos posteriores. El reloj hardware se calibra con las opciones --systohc y --set. La opción --adjust no lo calibra, sino que sólo lo corrige. Por tanto, en terminología de conjuntos puede decirse que corrección = ajuste U calibración (U=unión). Sabiendo qué hora marca el reloj hardware ahora, h1 (en s), qué hora marcaba en su última corrección, h0 (en s), y el atraso X (en s/día), puede calcularse qué hora h es ahora (en s). La fórmula que hwclock usa para la opción --adjust es inch=FLOAT((h1-h0)*X/86400+0.0), con FLOAT una macro para convertir números decimales en enteros de forma que si x=FLOAT(y) entonces x<=y<x+1, x entero. Si inch es mayor que 0 o menor que -1 entonces aplica h=h1+inch y actualiza /etc/adjtime de manera que su segundo campo (fecha de última corrección) sea h. Una vez que el reloj hardware está corregido, la segunda línea pone la hora del sistema a lo que marque el reloj hardware. Cuando el sistema se resetea, uno de los cuatro últimos scripts que se ejecutan es /etc/rc6.d/S25hwclock.sh con la opción stop. Entonces se guarda la hora que tenga el sistema en el reloj hardware hasta el momento en que se vuelva a encender el sistema (al cabo de unos segundos, horas o días). Esto lo hace con la línea: hwclock --systohc $GMT La opción --systohc ejecuta una calibración del reloj hardware (usando como fuente la hora del sistema). Además de cambiar la hora del reloj hardware, modifica los campos 1, 2 y 4 del fichero /etc/adjtime. Los campos 2 y 4 los pone a la hora actual (en segundos tras la medianoche de 1969). El campo 1 lo calcula de una forma totalmente INESPERADA y que no se ajusta a lo que comenta el manual de hwclock. En concreto el manual dice: Every time you calibrate (set) the clock (using --set or --systohc ), hwclock recalculates the systematic drift rate based on how long it has been since the last calibra tion, how long it has been since the last adjustment, what drift rate was assumed in any intervening adjustments, and the amount by which the clock is presently off. Sin embargo, el código fuente de hwclock para las opciones --systohc y --set llaman a una función (adjust_drift_factor) con cuatro argumentos: 1) puntero a estructura con los datos del fichero /etc/adjtime, 2) hora a la que hay que poner el reloj hardware, 3) y 4) hora que marca el reloj hardware. Los comentarios a esta función dicen que: We assume that the user has been doing regular drift adjustments using the drift factor in the adjtime file, so if <nowtime> and <clocktime> are different, that means the adjustment factor isn't quite right. lo cual es un poco sospechoso, porque no dice que explícitamente compruebe que ha pasado un tiempo despreciable desde la última corrección. Dice que supone que antes de llamar al hwclock (--set o --systohc) el usuario (root) ha ido llamando a hwclock regularmente con --adjust. La prueba de todo ello es que lo que se calcula como factor_adjust es 86400 * (hora real - hora del hardware) / (hora del hardware - hora de la última calibración). Si el usuario no ha ejecutado (como root) "hwclock --adjust" nunca desde el arranque del sistema, entonces el factor_adjust calculado es el nuevo drift_factor. Si el usuario ha ejecutado "hwclock --adjust" (y realmente el reloj hardware se ha corregido, pues no se corrige si la corrección inch es 0 ó -1 segundos) inmediatamente antes de hacer "hwclock --set" o "hwclock --systohc" entonces el factor_adjust calculado es realmente una corrección al drift_factor que se ha aplicado con --adjust. Y eso es lo que la función supone, pues unas líneas más abajo tiene: adjtime_p->drift_factor += factor_adjust; > Lo que a yo observo es que el valor de X se actualiza mal. Este valor (el > primer número que aparece en /etc/adjtime) debería ser más o menos el mismo. > Sin embargo observo que los ajustes se van acumulando, y si tenía al principio > (el 10 de marzo pasado) como "suggested adjustment" = -0.3951 sec/day (por > cierto nada más hacer hwclock --systohc ya cambió algo) ahora voy por: > -12.114908 Por lo tanto, Juan Leseduarte ha comprobado experimentalmente que la función adjust_drift_factor no funciona como todos esperábamos (como habíamos leído en el man de hwclock), y efectivamente actualiza mal el valor de X. > ¿Alguien me puede corregir si estoy equivocado? ¿Nadie ha observado esta > irregularidad? ¿Sería un error de los scripts o de hwclock? Parece ser que no estás equivocado. Me gustaría haber observado esta irregularidad, pero uso el paquete xntp3 para mantener la hora del sistema sincronizada con servidores NTP (demonio xntpd lanzado tras haber puesto el reloj del sistema con ntpdate) y por tanto paso olímpicamente de lo que dice el reloj hardware. Con respecto a la última pregunta, yo diría que la culpa la tiene una falta de entendimiento entre el programador de hwclock y el escritor del manual de hwclock. Supongo que el que programó el script hwclock.sh de init ([EMAIL PROTECTED]) se leyó (como yo) sólo el manual de hwclock, y no se puso a comprobar el código fuente. Por ello, la forma rápida de solucionarlo sería incluir una línea "hwclock --adjust $GMT" antes de "hwclock --systohc $GMT" del fichero /etc/init.d/hwclock.sh. Sin embargo, la mejor forma de solucionarlo sería modificar la función adjust_drift_factor. Si llamamos now a la hora verdadera ahora, hw a lo que marca el reloj hardware ahora, hw1 a lo que marcaba el reloj hardware DESPUÉS de hacer el último hwclock --adjust, y hw0 a lo que marcaba el reloj hardware DESPUÉS de hacer el último hwclock --systohc (o --set válido), y X0 al drift_factor viejo, he demostrado (la demostración ocupa un folio, se la puedo mandar por fax a quien la quiera) que la cantidad que hay que sumar a X0 (en segundos/día) para obtener un drift_factor actualizado es: incX=(now-hwa)*(86400+X0)/(hwa-hw0) siendo hwa=hw+(hw-hw1)*X0/86400 lo que marcaría el reloj hardware si se hiciera un --adjust justo antes del --systohc ó --set. En conclusión, habría que cambiar las siguientes líneas de la función adjust_drift_factor en hwclock.c: const float factor_adjust = ((float) (nowtime - hclocktime) / (hclocktime - adjtime_p->last_calib_time)) * 24 * 60 * 60; por: const float hclocktimeadjusted = hclocktime + ((float) hclocktime - adjtime_p->last_adj_time) * adjtime_p->drift_factor / 86400; const float factor_adjust = (nowtime - hclocktimeadjusted) * (86400 + adjtime_p->drift_factor) / (hclocktimeadjusted - adjtime_p->last_calib_time); Supongo que todo esto le interesaría al mantenedor del paquete util-linux (donde está el programa hwclock y el script hwclock.sh) y habría que mandar un aviso de bug a debian. Sin embargo, no es algo que me interese especialmente (pues yo paso del hwclock). Si queréis vosotros mandar un bug report a Debian con la información que os doy, adelante, pero me temo que no servirá de nada: he visto la "Debian Bug report logs" del paquete util-linux y ¡hay bugs en fase "outstanding" desde hace más de dos años! > Actualmente voy 1 minuto y 32 segundos atrasado. Comparado con el desmadre que > tenía antes está bastante bien, pero creo que no es del todo satisfactorio. > Sobre todo teniendo en cuenta que para hacer el ajuste con el servidor de hora > de SLUG tuve el ordenador encendido todo un fin de semana para hacer 2 > adjtimex bien separados y tener un calibrado fiable. Yo pasaría del adjtimex (purgaría el paquete), y pondría la hora con un "ntpdate -b -s hora.rediris.es" (hora.rediris.es es una servidor NTP de tipo "stratum 1") en el script /etc/init.d/xntp3 que se crea al instalar el paquete xntp3. Supongo que el demonio xntpd aprovechará los pocos momentos en que tengas conexión internet para ajustar la hora del sistema. Te voy a dar una receta para poner a punto tu sistema (has de ser root) sin que tengas que tener el ordenador encendido. # adjtimex -tick 10000 -frequency 0 (esto resetea las variables del kernel) # dpkg --purge adjtimex # dselect Selecciona e instala el paquete xntp3 con la opción de que ejecute ntpdate al arrancar el sistema. Como servidor NTP puedes decirle que use hora.rediris.es, que está en Madrid, o cualquier otro que conozcas # echo "0.0 0 0.0" > /etc/adjtime # . /etc/default/rcS # [ "$GMT" = "-u" ] && GMT="--utc" (para tener la variable GMT a su valor correcto) # /etc/init.d/xntp3 stop ; /etc/init.d/xntp3 start # hwclock --systohc $GMT # joe /etc/init.d/hwclock.sh (joe o cualquier otro editor de texto) La línea 32 debería quedar asÍ: "hwclock --adjust $GMT; hwclock --systohc $GMT # modificada el 24-abr-2000" # mv /etc/init.d/hwclock.sh /etc/init.d/hwclock.sh.dpkg-dist Ahora sólo has de acordarte de no hacer nunca ningún hwclock (el sistema ya lo hará por ti al arrancar y al apagar el ordenador). Si no tienes una conexión continua a internet no sé si xntpd aprovechará los momentos en que hay conexión para comprobar el reloj. Si al cabo de unos días crees que no funciona como es debido siempre puedes comprobar la hora con: $ /usr/sbin/ntpdate -q hora.rediris.es ; date (no hace falta que seas root) Si la hora del sistema se ha ido demasiado puedes ponerla bien con: # /etc/init.d/xntp3 stop ; /etc/init.d/xntp3 start (has de ser root) Espero que con el cambio al hwclock.sh el primer número de /etc/adjtime se mantenga más o menos constante, y que con xntp3 la hora se te mantenga correctamente. -- Conrado Badenas <[EMAIL PROTECTED]> PhD student | Assistant Lecturer Department of Thermodynamics | Department of Optics --------------------------------------------------- Faculty of Physics. University of Valencia c/. Dr. Moliner, 50 46100 Burjassot (Valencia) - SPAIN