Smartmontools to zestaw narzędzi do odpytywania dysków twardych używających SMART. Można dobrać się do danych statystycznych jakie dyski gromadzą podczas całej swojej pracy - ile razy talerze były zatrzymywane/rozkręcane, ile godzin dysk pracuje, czy zarejestrował jakieś błędy podczas swojej pracy (a jeśli tak, to kiedy), temperatura dysku, liczba realokowanych wewnętrznie (przez elektronikę dysku) uszkodzonych sektorów itp. Smartmontools jest bezpośrednim następcą pakietu smartsuite. 1. Źródła można znaleźć np. poprzez Freshmeat

2. Próbna instalacja
Po rozpakowaniu źródeł okaże się, że pakiet nie ma skryptu ./configure, że w ogóle nie bazuje na standardowych narzędziach autoconf/automake GNU. Używa zwykłego pliku Makefile. Respektuje $DESTDIR, a flagi kompilatora wyrażone są wewnętrzą zmienną CFLAGS, którą można przedefiniować przy wywoływaniu ,,make''. Problem dotyczy późniejszej instalacji: co prawda pliki instalują się przez $DESTDIR, ale trzeba im chyba najpierw pozakładać katalogi (to akurat niewielki problem), gorzej że przy instalacji skrypt próbuje zmieniać atrybuty plików. A konkretniej, to próbuje zmieniać im grupę/właściciela na ,,root''. Do czego ma prawo tylko root. Nie da się tego zmienić bez ingerencji w Makefile (potwornie długie linie, ale wolałem ich nie łamać, dla czytelności):
install:
    if [ ! -f smartd -o ! -f smartctl ] ; then echo -e "\n\nYOU MUST FIRST DO \"make\"\n" ; exit 1 ; fi
    /bin/gzip -c smartctl.8 > smartctl.8.gz
    /bin/gzip -c smartd.8   > smartd.8.gz
    /bin/gzip -c smartd.conf.5 > smartd.conf.5.gz
    rm -f $(DESTDIR)/usr/share/man/man8/smartctl.8
    rm -f $(DESTDIR)/usr/share/man/man8/smartd.8
    install -m 755 -o root -g root -D smartctl         $(DESTDIR)/usr/sbin/smartctl
    install -m 755 -o root -g root -D smartd           $(DESTDIR)/usr/sbin/smartd
    install -m 755 -o root -g root -D smartd.initd     $(DESTDIR)/etc/rc.d/init.d/smartd
    install -m 644 -o root -g root -D smartctl.8.gz    $(DESTDIR)/usr/share/man/man8/smartctl.8.gz
    install -m 644 -o root -g root -D smartd.8.gz      $(DESTDIR)/usr/share/man/man8/smartd.8.gz
    install -m 644 -o root -g root -D smartd.conf.5.gz $(DESTDIR)/usr/share/man/man5/smartd.conf.5.gz
    install -m 644 -o root -g root -D CHANGELOG        $(DESTDIR)/usr/share/doc/smartmontools-5.1/CHANGELOG
    install -m 644 -o root -g root -D COPYING          $(DESTDIR)/usr/share/doc/smartmontools-5.1/COPYING
    install -m 644 -o root -g root -D README           $(DESTDIR)/usr/share/doc/smartmontools-5.1/README
    install -m 644 -o root -g root -D TODO             $(DESTDIR)/usr/share/doc/smartmontools-5.1/TODO
    install -m 644 -o root -g root -D VERSION          $(DESTDIR)/usr/share/doc/smartmontools-5.1/VERSION
    install -m 644 -o root -g root -D WARNINGS         $(DESTDIR)/usr/share/doc/smartmontools-5.1/WARNINGS
    install -m 644 -o root -g root -D smartd.conf      $(DESTDIR)/usr/share/doc/smartmontools-5.1/smartd.conf
    install -m 644 -o root -g root -D smartd.conf      $(DESTDIR)/etc/smartd.conf.example
    if [ ! -f $(DESTDIR)/etc/smartd.conf ] ; then install -m 644 -o root -g root -D smartd.conf $(DESTDIR)/etc/smartd.conf
To sekcja instalacyjna wycięta z Makefile. Teraz jakie poprawki należy wprowadzić? Po pierwsze można wyciąć te linie które kompresują strony manuala, bo to i tak zrobi rpm. Można też wyciąć te fragmenty usuwające stare manuale. Z tych wszystkich linijek ,,install...'' trzeba usunąć fragmenty '-o root -g root'. Można też uprościć ten kawałek instalujący konfigurację. Po przeróbkach będzie to wyglądało tak:
install:
    if [ ! -f smartd -o ! -f smartctl ] ; then echo -e "\n\nYOU MUST FIRST DO \"make\"\n" ; exit 1 ; fi
    install -m 755 -D smartctl         $(DESTDIR)/usr/sbin/smartctl
    install -m 755 -D smartd           $(DESTDIR)/usr/sbin/smartd
    install -m 644 -D smartctl.8       $(DESTDIR)/usr/share/man/man8/smartctl.8
    install -m 644 -D smartd.8         $(DESTDIR)/usr/share/man/man8/smartd.8
    install -m 644 -D smartd.conf.5    $(DESTDIR)/usr/share/man/man5/smartd.conf.5
    install -m 644 -D CHANGELOG        $(DESTDIR)/usr/share/doc/smartmontools-5.1/CHANGELOG
    install -m 644 -D COPYING          $(DESTDIR)/usr/share/doc/smartmontools-5.1/COPYING
    install -m 644 -D README           $(DESTDIR)/usr/share/doc/smartmontools-5.1/README
    install -m 644 -D TODO             $(DESTDIR)/usr/share/doc/smartmontools-5.1/TODO
    install -m 644 -D VERSION          $(DESTDIR)/usr/share/doc/smartmontools-5.1/VERSION
    install -m 644 -D WARNINGS         $(DESTDIR)/usr/share/doc/smartmontools-5.1/WARNINGS
    install -m 644 -D smartd.conf      $(DESTDIR)/usr/share/doc/smartmontools-5.1/smartd.conf
    install -m 644 -D smartd.conf      $(DESTDIR)/etc/smartd.conf
Przy okazji wywaliłem też linijkę instalującą plik /etc/rc.d/init.d/smartd, bo mój system nie używa skryptów startowych SysV, i to już powinno działać. Ale ze względów dydaktycznych chcę jeszcze pokazać, jak można sobie ,,udanymicznić'' ścieżki dostępu: tutaj są one zakodowane na sztywno, np. /usr/sbin. Aby było bardziej rpm-owo, to powinno być możliwe do późniejszego zmieniania bez edycji plików. Ale jak to zrobić? Rozwiązanie jest w sumie proste - zamiast katalogów trzeba użyć zmiennych. Zmienne te się potem zainicjuje przy wywołaniu ,,make'' odpowiednimi makrami. Sekcja po przeróbkach mogłaby wyglądać tak:
install:
    if [ ! -f smartd -o ! -f smartctl ] ; then echo -e "\n\nYOU MUST FIRST DO \"make\"\n" ; exit 1 ; fi
    install -m 755 -D smartctl         $(DESTDIR)$(H_SBINDIR)/smartctl
    install -m 755 -D smartd           $(DESTDIR)$(H_SBINDIR)/smartd
    install -m 644 -D smartctl.8       $(DESTDIR)$(H_MANDIR)/man8/smartctl.8
    install -m 644 -D smartd.8         $(DESTDIR)$(H_MANDIR)/man8/smartd.8
    install -m 644 -D smartd.conf.5    $(DESTDIR)$(H_MANDIR)/man5/smartd.conf.5
    install -m 644 -D CHANGELOG        $(DESTDIR)$(H_DOCDIR)/smartmontools-5.1/CHANGELOG
    install -m 644 -D COPYING          $(DESTDIR)$(H_DOCDIR)/smartmontools-5.1/COPYING
    install -m 644 -D README           $(DESTDIR)$(H_DOCDIR)/smartmontools-5.1/README
    install -m 644 -D TODO             $(DESTDIR)$(H_DOCDIR)/smartmontools-5.1/TODO
    install -m 644 -D VERSION          $(DESTDIR)$(H_DOCDIR)/smartmontools-5.1/VERSION
    install -m 644 -D WARNINGS         $(DESTDIR)$(H_DOCDIR)/smartmontools-5.1/WARNINGS
    install -m 644 -D smartd.conf      $(DESTDIR)$(H_DOCDIR)/smartmontools-5.1/smartd.conf
    install -m 644 -D smartd.conf      $(DESTDIR)$(H_SYSCONFDIR)/smartd.conf
Teraz w pliku .spec wystarczy wywołać
make install H_SBINDIR=%{_sbindir} H_MANDIR=%{_mandir} \
H_DOCDIR=%{_docdir} H_SYSCONFDIR=%{_sysconfdir} DESTDIR=%{buildroot} \
CFLAGS="$CFLAGS"
Ale tutaj nasuwają mi się dwie refleksje: jedna to to, że będziemy mieć zmienne położenie pliku konfiguracyjnego. Ale jego lokacja jest zaszyta gdzieś na stałe w kodzie programu... i ją też trzeba by zmieniać. Po krótkim grepowaniu przez źródła znalazłem odpowiedzialny fragment, w pliku smartd.h znajduje się wpis
#define CONFIGFILE "/etc/smartd.conf"
Ale to zwykła dyrektywa #define, więc można ją przykryć z linii poleceń, dodając do flag kompilatora w trakcie kompilacji:
make CFLAGS="$CFLAGS -DCONFIGFILE=\"%{_sysconfdir}/smartd.conf\""
I to powinno załatwić sprawę. Ale ta druga rzecz która przyszła mi do głowy, ona jest dużo większego kalibru: nie da się wygenerować patcha z tych zmian! To znaczy OK, dobra, patcha zrobić to się da, ale on nie da się potem zaaplikować gdy wyjdzie nowa wersja smartmontools. A dlaczego? Bo w patchowanych linijkach jest numer wersji (w nazwie katalogu docelowego dla dokumentacji). A to oznacza, że przy upgradzie ten numer się zmieni. A to z kolei oznacza, że patch nie rozpozna tych linijek. Rezultat: patch się nie zaaplikuje. Czyli można sobie zabawę z patchem podarować.

Alternatywnie można napisać regułkę sed-a która by powprowadzała te zmiany, a na dodatek była na tyle sprytna, by ignorować numerki wersji. To da się zrobić, ale nie chcę. Pójdę w inną stronę: instalowanych plików jest niewiele i mam podaną na tacy ich listę, łącznie z przeznaczeniem... przecież ja zamiast robić ,,make install'' mogę po prostu przekleić te linijki które instalują pliki prosto do sekcji %install! Trochę drobnych poprawek i powinno być po krzyku. To nie jest idealne wyjście, ale na pewno o niebo lepsze niż robienie łatek jednorazowego użytku.

3. Plik .spec
%define sub_release -1
Summary: Narzędzia do monitorowania i kontroli S.M.A.R.T
Name: smartmontools
Version: 5.1
Release: 1
License: GPL
Group: System
Source: %{name}-%{version}%{sub_release}.tar.bz2
BuildRoot: /var/tmp/%{name}-%{version}
Obsoletes: smartsuite

%description
Pakiet ten pozwala monitorować i kontrolować nośniki używające technologii
S.M.A.R.T. (Self-Monitoring, Analysis and Reporting Technology System)

%prep
%setup -q -n %{name}-%{version}%{sub_release}

%build
make CFLAGS="$CFLAGS -DCONFIGFILE=\"%{_sysconfdir}/smartd.conf\"" LDFLAGS="$LDFLAGS"

%install
rm -rf %{buildroot}
install -m 755 -D smartctl         %{buildroot}%{_sbindir}/smartctl
install -m 755 -D smartd           %{buildroot}%{_sbindir}/smartd
install -m 644 -D smartctl.8       %{buildroot}%{_mandir}/man8/smartctl.8
install -m 644 -D smartd.8         %{buildroot}%{_mandir}/man8/smartd.8
install -m 644 -D smartd.conf.5    %{buildroot}%{_mandir}/man5/smartd.conf.5
install -m 644 -D smartd.conf      %{buildroot}%{_sysconfdir}/smartd.conf

%files
%defattr(0644,root,root,0755)
%{_mandir}/man*/*.gz
%attr(0755,root,root)%{_sbindir}/*
%config(noreplace) %verify(not size md5 mtime) %{_sysconfdir}/smartd.conf

%clean
rm -rf %{buildroot} %{_builddir}/%{buildsubdir}
Plik nie jest bardzo skomplikowany. W preambule jedyne ciekawostki to użycie Obsoletes: i zdefiniowanie pomocniczego makra %{sub_release} które ułatwia mi poradzenie sobie z dziwną nazwą pakietu źródłowego (*-5.1-1.tar.bz2). Bo nie mogę użyć w pliku .spec jako wersji po prostu tego 5.1-1, znak minusa jest niedozwolony przy określaniu wersji.

Sekcja %prep też normalna, tylko ostrzegam RPM że rozpakowany katalog ma niestandardową nazwę. W sekcji %build definiuję zmienne dla ,,make'' - ustawiam LDFLAGS i CFLAGS. Przy ustawianiu CFLAGS od razu dodaję definiowanie stałej CONFIGFILE na potrzeby kompilatora. To spowoduje, że zmieniając makro %{_sysconfdir} zmiana ta znajdzie odzwierciedlenie w skompilowanym kodzie binarnym, i programy będą szukać swojego pliku konfiguracyjnego we właściwym miejscu.

Następnie sekcja instalacyjna: przeklejone z Makefile linijki, tyle że nieco zmienione - pozamieniałem odwołania do katalogów docelowych makrami RPM-a, przy okazji usunąłem też niechciane pliki dokumentacji.

Na tym etapie artykułu opisywanie tak wtórnej sekcji %files byłoby chyba już przesadą, prawda? Więc jej nie opiszę, chyba jest już jasna i zrozumiała.

4. Budowanie pakietu się udaje, w końcu to już któryś z rzędu pakiet :)