Установка времени из initramfs

При работе на старом оборудовании может возникать ситуация, когда время в BIOS'е на рабочих станциях постоянно сбрасывается на заводское значение. При использовании корневой ФС семейства ext*, это может вызвать отказ в монтировании со следующей ошибкой: Superblock last mount time is in the future.

Решение

Решение проблемы может быть достигнуто несколькими способами:

  • синхронизировать при запуске время из initrd (+10 секунд к времени запуска),
  • следить за железом,
  • каждый раз при обновлении e2fsprogs перекомпилировать пакет с патчем для отключения этой проверки

Наиболее простой в плане поддержки - первый вариант. Его и будем реализовывать.

При использовании Debian'а или его производных, нам потребуется написать 2 скрипта, которые:

  • при обновлении ядра будут добавлять ntpdate со всеми зависимостями в initrd.
  • при загрузке, при указании определённого параметра будут выполнять команду ntpdate

Ниже - пример одной из возможных реализаций.

/etc/initramfs-tools/hooks/ntpdate:

#!/bin/sh

case $1 in
prereqs)
        exit 0
        ;;
esac

. /usr/share/initramfs-tools/hook-functions

copy_exec /usr/sbin/ntpdate /sbin
cp /etc/services        ${DESTDIR}/etc/
cp /etc/nsswitch.conf   ${DESTDIR}/etc/
cp /lib/libnss_files*   ${DESTDIR}/lib/

/etc/initramfs-tools/scripts/local-top/ntpdate:

#!/bin/sh

case $1 in
  prereqs)
    exit 0
    ;;
esac

for x in $(cat /proc/cmdline); do
  case $x in
    ntp-server*)
      NTP_SERVER="${x#ntp-server=}"
      ;;
  esac
done

if [ -z "$NTP_SERVER" ]; then
    exit 0
fi

. /scripts/functions

log_begin_msg "Syncing local time"

/sbin/ntpdate -v "$NTP_SERVER"

Оба файла должны иметь права на выполнение. Второй скрипт должен быть назван так, чтобы при сортировке по имени, он должен идти после того, который подключает корневую ФС, т.к. в ней, как правило, проводится настройка сети (у меня они называются nbd и ntpdate соответственно).

Если при запуске ntpdate выдаётся ошибка Servname not supported for ai_socktype(-8) или подобная - это означает, что не работает разрешение имен. Причиной этого является следующее: ntpdate использует стандартную функцию getaddrinfo(). Эта функция первоначально считает всё, что ей подали на вход - dns-именем, поэтому пытается разрешить его в ip-адрес, даже если на входе уже ip-адрес. Для работы разрешения имён необходимо в initrd также добавить конфигурационные файлы /etc/services, /etc/nsswitch.conf и библиотеку /lib/libnss_files.so1

После добавления файлов нужно обновить inird:

update-initramfs -k all -u # -k all - для всех найденных версий ядра, -u - update (обновить)

Обновлённый initrd копируется в директорию с файлами для бездисковой загрузки, в конфиг-файле pxelinux'а дописывается параметр nbd-server=, где - адрес ntp-сервера.

Отладка

Для прерывания загрузки на различных этапах в debian'е можно использовать параметр break в параметрах загрузки. Возможные значения этого параметра можно посмотреть так:

# grep -n maybe_break /usr/share/initramfs-tools/init

В моём случае это: top, modules, premount, mount, mountroot, bottom, init. Для прерывания непосредственно перед монтированием корневой ФС используйте значение "mountroot".


  1. проследите, чтобы это была именно библиотека, а не ссылка на неё. Впрочем, можно добавить и то и другое ↩