środa, 12 sierpnia 2009

eselect - narzędzie do konfiguracji i administracji środowiska Gentoo

Spośród wielu przydatnych narzędzi znacznie automatyzujących administrację w systemie Gentoo nie można zapomnieć o eselect. Jest to modularne narzędzie pozwalające na konfigurację wielu aspektów środowiska napisane w całości w bashu.
Jak to zainstalować?

Poszukajmy w portage'u znaną już z wcześniejszych postów komendą eix:

# eix ^eselect
[I] app-admin/eselect
Available versions: 1.0.10 1.0.11-r1 1.0.12 1.1.1 ~1.1.2 {bash-completion doc vim-syntax}
Installed versions: 1.1.1(14:09:03 08/02/09)(bash-completion -doc)
Homepage: http://www.gentoo.org/proj/en/eselect/
Description: Gentoo's multi-purpose configuration and management tool

[I] app-admin/eselect-fontconfig
Available versions: 1.0
Installed versions: 1.0(15:55:30 01/20/08)
Homepage: http://www.gentoo.org
Description: An eselect module to manage /etc/fonts/conf.d symlinks.

[I] app-admin/eselect-news
Available versions: ~20070709 ~20071025 ~20071201 20080320
Installed versions: 20080320(11:29:19 02/15/09)
Homepage: http://paludis.pioto.org/
Description: GLEP 42 news reader

[I] app-admin/eselect-oodict
Available versions: 20060621 20060706 ~20060806 20061117
Installed versions: 20061117(16:53:52 09/21/07)
Homepage: http://www.gentoo.org/
Description: Manages configuration of dictionaries for OpenOffice.Org.

[I] app-admin/eselect-opengl
Available versions: 1.0.5 ~1.0.6 1.0.6-r1 ~1.0.7
Installed versions: 1.0.6-r1(20:49:53 05/11/08)
Homepage: http://www.gentoo.org/
Description: Utility to change the OpenGL interface being used

* app-admin/eselect-oracle
Available versions: ~1.0-r260
Homepage: http://www.gentoo.org/
Description: Utility to change the Oracle SQL*Plus Instantclient being used

* app-admin/eselect-postgresql
Available versions: 0.3
Homepage: http://www.gentoo.org/
Description: Utility to change the default postgresql installation

[I] app-admin/eselect-python
Available versions: 20080521 20080925 20090606 ~20090801 ~20090804
Installed versions: 20090606(14:20:10 08/02/09)
Homepage: http://www.gentoo.org
Description: Manages multiple Python versions

[I] app-admin/eselect-rails
Available versions: 0.14 0.15
Installed versions: 0.15(14:21:36 08/02/09)
Homepage: http://www.gentoo.org/
Description: Manages Ruby on Rails symlinks

[I] app-admin/eselect-ruby
Available versions: ~20081211 20081227
Installed versions: 20081227(14:20:21 08/02/09)
Homepage: http://www.gentoo.org
Description: Manages multiple Ruby versions

[I] app-admin/eselect-vi
Available versions: 1.1.4 1.1.5 ~1.1.6
Installed versions: 1.1.5(10:33:02 12/22/07)
Homepage: http://www.gentoo.org/
Description: Manages the /usr/bin/vi symlink

* app-vim/eselect-syntax
Available versions: 20070506
Homepage: http://www.gentoo.org/
Description: vim plugin: Eselect syntax highlighting, filetype and indent settings

Found 32 matches.


Ze względu na liczbę dostępnych modułów wynik został troszeczkę skrócony - wyciąłem mniej ważne z mojego punktu widzenia moduły. Jak widać jest tego trochę. Zainstalujmy teraz eselect:

# emerge -av eselect


Udało się. Zobaczmy w praktyce jak to działa, uruchomię:

# eselect
Usage: eselect

Global options:
--no-color,--no-colour Disable coloured output

Built-in modules:
help Display a help message
usage Display a usage message
version Display version information

Extra modules:
bashcomp Manage contributed bash-completion scripts
binutils Manage installed versions of sys-devel/binutils
ctags Manage /usr/bin/ctags implementations
editor Manage the EDITOR environment variable
env Manage environment variables set in /etc/env.d/
esd Select esound daemon or wrapper
fontconfig Manage fontconfig /etc/fonts/conf.d/ symlinks
java-nsplugin Manage the Java plugin for Netscape-like Browsers
java-vm Manage the Java system and user VM
kernel Manage the /usr/src/linux symlink
modules A module for querying modules. By default, it lists all available modules
news-tng Read Gentoo ("GLEP 42") news items
news Read GLEP 42 news items
oodict Manage the configuration of dictionaries for OpenOffice.Org.
opengl Manage the OpenGL implementation used by your system
pager Manage the PAGER environment variable
profile Manage the /etc/make.profile symlink
python Manage the /usr/bin/python and python.1 man symlinks.
rails Manage Ruby on Rails versions
rc Manage /etc/init.d scripts in runlevels
ruby Manage ruby symlinks
vi Manage /usr/bin/vi implementations
visual Manage the VISUAL environment variable
wxwidgets Manage the system default wxWidgets profile.
xvmc Manage the XvMC implementation used by your system

Liczba modułów jest znaczna - czego można się już było spodziewać po wynikach wyszukiwania. Z tego względu omówię jedynie najważniejsze moduły - pozostałe pozostawiam do testowania we własnym zakresie - zasada działania i wywoływania jest podobna o ile nie identyczna.

Co się przydaje:

- moduł editor -ustawienie domyślnego edytora - spróbujmy:

# eselect editor
Usage: eselect editor

Standard actions:
help Display help text
usage Display usage information
version Display version information

Extra actions:
list List available targets for the EDITOR variable
set Set the EDITOR variable in profile
target Target name or number (from 'list' action)
show Show value of the EDITOR variable in profile
update Update the EDITOR variable if it is unset or invalid

Wyświetli nam działania jakie możemy w ramach modułu wykonać (są one na ogół identyczne w każdym z modułów - dzięki czemu obsługa eselect jest prosta - wszystko to kwestia przyjęcia właściwej konwencji)
Wylistuję dostępne edytory:

# eselect editor list
Available targets for the EDITOR variable:
[1] /bin/nano
[2] /bin/ed
[3] /usr/bin/ex
[4] /usr/bin/vi


Ustawię edytor na vi (tak naprawdę to będzie vim). Przy ustawianiu za pomocą eselecta możemy używać numer wpisu lub jego nazwę- ja skorzystam z numeru:

# eselect editor set 4
Setting EDITOR to /usr/bin/vi ...

Co się stało? Powinno się zmienić ustawienie zmiennej środowiskowej EDITOR.

# env|grep EDITOR
EDITOR=/bin/nano

hmm... nie jest tak jakbym chciał. Co się stało? Proawdopodobnie niezostała zaktualizowana wartość zmiennej w środowisku. Sprawdzę czy zmienna została ustawiona (katalog /etc/env.d - o tym opowiem innym razem szczegółowo)

# grep -r EDITOR /etc/env.d/
/etc/env.d/99editor:EDITOR="/usr/bin/ex"


Jest. A więc narzędzie zmienia ustawienia zmiennej EDITOR w konfiguracji systemu. W celu wymuszenia zmian w środowisku roboczym należy wykonać aktualizację:

# env-update
>>> Regenerating /etc/ld.so.cache...

I już powinno być ok. Sprawdzę:

edward ~ # env|grep EDITO
EDITOR=/usr/bin/vim

No i jest. Zmienną EDITOR można było do niedawna ustawić również w pliku /etc/rc.conf jednak zalecane jest definiowanie jej w pliku ~/.bashrc (lub odpowiedniku) bądź utworzenia pliku /etc/env.d/99editor i ustawienie tam zmiennych (jak w powyższym przykładzie).

- ustawienie aktywnej jvm
W tym wypadku mamy możliwość ustawienia wersji wirtualnej maszyny java, którą będziemy używać. Możemy dokonać wyboru na poziomie systemu lub użytkownika. Zdefinujmy aktywny jvm na poziomie systemu:

# eselect java-vm list
shell-init: error retrieving current directory: getcwd: cannot access parent directories: No such file or directory
Available Java Virtual Machines:
[1] sun-jdk-1.4
[2] sun-jdk-1.5 system-vm
[3] sun-jdk-1.6


a co to - 'shell-init: error retrieving current directory: getcwd'? Może się zdarzyć jeśli uruchamiamy polecenie będąc w katalogu, który został wcześniej usunięty (weszliśmy do katalogu - ktoś w innej sesji go usunął)
Dobra lećmy dalej:

ny ~ # java -version
java version "1.5.0_15"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_15-b04)
Java HotSpot(TM) Client VM (build 1.5.0_15-b04, mixed mode)
ny ~ # eselect java-vm set system 3
ny ~ # java -version
java version "1.6.0_14"
Java(TM) SE Runtime Environment (build 1.6.0_14-b08)
Java HotSpot(TM) Client VM (build 14.0-b16, mixed mode, sharing)

Jak widać zmieniłem ustawienia jvm na poziomie systemu. Po ustawieniu w ten sposób jvm następuje automatyczne przełączenie aktualnie aktywnego jvm - wersja się zmieniła bez żadnych dodatkowych zabiegów.
Każdy użytkownik może zmienić używanego jvm - można to zrobić tak:

k@ny ~ $ java -version
java version "1.6.0_14"
Java(TM) SE Runtime Environment (build 1.6.0_14-b08)
Java HotSpot(TM) Client VM (build 14.0-b16, mixed mode, sharing)
k@ny ~ $ eselect java-vm set user 2
k@ny ~ $ java -version
java version "1.5.0_15"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_15-b04)
Java HotSpot(TM) Client VM (build 1.5.0_15-b04, mixed mode)
k@ny ~ $ eselect java-vm list
Available Java Virtual Machines:
[1] sun-jdk-1.4
[2] sun-jdk-1.5 user-vm
[3] sun-jdk-1.6 system-vm


Użytkownik po zmianie używa java'y Suna w wersji 1.5 natomiast systemowy jvm jest ustawiony na wersję Sun JDK 1.6.
Dla ciekawskich pozostawiam temat w jaki sposób te zmiany są realizowane w systemie - jak to się automagicznie dzieje (być może sam też to kiedyś opiszę). Trochę ciekawych informacji na temat java w Gentoo można znaleźć tu.

- zmiany w portage - moduł news/news-tng. Niedawno dodano do portage tzw. newsy - wiadomości mające informować nas o ważnych zmianach w funkcjonowaniu pakietów w portage i samego portage'a.
Sprawdźmy jak to działa:

ny ~ # eselect news-tng
Usage: eselect news-tng

Standard actions:
help Display help text
usage Display usage information
version Display version information

Extra actions:
count Display number of news items
new Count unread news items (default)
all Count all news items
list List news items
purge Purge read news
read ... Read news items
new Read unread news items (default)
all Read all news items
item Number of item (from 'list' action)
--raw Output in raw format
unread ... Mark read news items as unread again
all Mark all news items as unread
item Number of item (from 'list' action)
ny ~ # eselect news-tng list
News items:
[1] 2009-04-06 (unread) Migration from teTeX to TeXLive
[2] 2009-04-18 (read) Generation 1 Java Setup Deprecated


Mam 2 wiadomości - 1 przeczytaną i 1 nieprzeczytaną. Przeczytajmy zatem wiadomość 2:

# eselect news-tng read 1
2009-04-06-tetex
Title Migration from teTeX to TeXLive
Author Christian Faulhammer
Author Ulrich Müller
Author Alexis Ballier
Posted 2009-04-06
Revision 1

teTeX is obsolete and has been unsupported upstream since May of 2006.
All users who still have teTeX installed should uninstall it and install
TeXLive using the upgrade guide accessible at the following URL:
http://www.gentoo.org/proj/en/tex/texlive-migration-guide.xml

tandetny ~ # eselect news-tng list
News items:
[1] 2009-04-18 (read) Generation 1 Java Setup Deprecated
[2] 2009-04-06 (read) Migration from teTeX to TeXLive


Jak widać informacje pozyskiwane tym źródłem mogą być po pierwsze użyteczne, po drugie pozwolą nam oszczędzić wiele bólów związanych z tym, że przeoczyliśmy jakąś ważną informację bo pakiet podczas instalacji nie poinformował nas o jakiejś ważnej zmianie (nie musimy śledzić, poszukiwać informacji po forach) ponieważ portage po każdej aktualizacji poinformuje nas w podsumowaniu ile mamy nowych newsów.
To jak dla mnie kolejna zaleta Gentoo - zintegrowane z systemem zarządzania pakietami ważne informacje o zmianach/nowinkach/sposobie konfiguracji oraz doskonała dokumentacja - jak widać na przykładzie dostajemy link do dokumentu opisującego zasady migracji z teTeX do TeXLive.


- zmiany profilu systemu Gentoo - moduł profile. Zasada użycia jest podobna, o tym czym są profile w Gentoo opowiem wkrótce.

- zmiany ustawień skryptów startowych - moduł rc - co startować w danym runlevelu o co nie. O runlevelach i ich specyficznej implementacji w Gentoo - wkrótce.

- zmiana aktywnego interpretera Ruby, Python - odpowiednio moduły ruby, python - podobnie jak w wypadku jvm.

Pozostałe pozostawiam do testowania we własnym zakresie. Z wartych zainteresowania wymieniłbym postgresql, kernel, rails, bash-completion, opengl.

poniedziałek, 13 lipca 2009

Co nieco o euse i innych

Ponieważ pewnie wiele osób zauważyło, że euse nie jest demonem szybkości, warto zastanowić się nad alternatywami. Wcześniej jednak spróbujmy znaleźć powód wolnego działania euse.
Zaczynamy!
Gdzie znajduje się program euse:

# which euse

/usr/bin/euse

OK, mamy. Teraz nauczmy się wykorzystywać przydatne skróty shella. Strzałki w górę i dół na klawiaturze umożliwiają nam nawigację w historii wykonanych poleceń. Więc strzałka w górę i mamy poprzednio wykonane polecenie. Teraz naciśnijmy HOME i jesteśmy na początku linii, END - na jej końcu. O tym jak konfigurować własne skróty opowiem innym razem.
Wykorzystując tą wiedzę co by się za dużo nie napisać zmodyfikujmy tę linię, tak żeby zobaczyć czym jaki jest typ pliku euse:

# file `which euse`
/usr/bin/euse: Bourne-Again shell script text executable


aha - czyli skrypt Bash. Polecenie file wyświetla nam na podstawie swojej bazy informacje na temat typu pliku (polecam do szczegółowej lektury man).
Czym jest zaś tajemniczy ` - backquote (backtick)?
W tym miejscu następuje podmiana wywołania polecenia na wartość zwróconą po jego wykonaniu (command substitution lub bardziej po polsku - cytowanie polecenia). Czyli wszystko co znajdzie się pomiędzy znakami ` jest wykonywane a następnie wynik zwrócony jest podstawiany w to miejsce. Wywołania z użyciem backtick'ów (odwrotny apostrof) można zagnieżdżać, należy jednak pamiętać wtedy o użyciu znaku maskującego \ (tzw. backslasha). Backtick jest szczególnie użyteczny w skryptach, gdy chcemy podstawić gdzie możemy wykorzystać go do podstawienia wyniku wykonania polecenia pod zmienną (np.: ZMIENNA=`ls -l`). Zamiennie z backtickiem można stosować konstrukcję $(polecenie).

Skoro zaczynamy powoli wchodzić w shella nasuwają mi się dwa pytanka, a mianowicie:
- po czym poznać czy dana komenda to polecenie zewnętrzne, czy wbudowana komenda basha?
- dlaczego cd jest wbudowany w bash?

Zostawiam je na razie jako zadanie domowe - spróbujcie pogłówkować.

Teraz gdy dowiedzieliśmy się paru nowych rzeczy warto popatrzyc w źródła euse (nie zapomnijcie o wykorzystywaniu opisanych skrótów):

vim `which euse`

Ponieważ - jak stwierdziliśmy wcześniej - wyświetlanie informacji o flagach jest wolne skupmy się na tej operacji i trochę pogmerajmy w kodzie. Informacje wyświetlamy za pomocą opcji -i - poszukajmy:

while [ -n "${1}" ]; do
case "${1}" in
-h | --help) MODE="showhelp";;
-v | --version) MODE="showversion";;
-i | --info) MODE="showdesc";;
-I | --info-installed) MODE="showinstdesc";;
-l | --local) SCOPE="local";;
-g | --global) SCOPE="global";;
-a | --active) MODE="showflags";;
-E | --enable) MODE="modify"; ACTION="add";;
-D | --disable) MODE="modify"; ACTION="remove";;
-P | --prune) MODE="modify"; ACTION="prune";;
-*)


Jest w pętli odpowiedzialnej za odczyt argumentów wywołania (opcji) programu/skryptu (o tym innym razem). Jak widać (mniej lub bardziej) użycie tej opcji powoduje ustawienie w skrypcie zmiennej MODE na wartość showdesc.
Co się dzieje dalej?
Na samym końcu skryptu znajdziemy:

##### main program comes now #####

# disable globbing as it fucks up with args=*
set -f
parse_arguments "$@"
check_sanity

eval ${MODE} ${ARGUMENTS}
set +f


Jak widać mamy tu cały przepływ programu - kolejno wywołanie funkcji (zdefiniowanych powyżej) parse_arguments (parsowanie opcji), check_sanity (pomijam - pewnie sprawdzanie poprawności wywołania, opcji, etc.) i wykonanie funkcji o nazwie zdefiniowanej w zmiennej MODE (i wszystko się wyjaśniło - o eval powiem innym razem). Zaglądnijmy do tej funkcji (showdesc):

# This function takes a list of use flags and shows the status and
# the description for each one, honoring $SCOPE
showdesc() {
local descdir
local current_desc
local found_one
local args

args="${*:-*}"

if [ -z "${SCOPE}" ]; then
SCOPE="global" showdesc ${args}
echo
SCOPE="local" showdesc ${args}
return
fi

descdir="$(get_portdir)/profiles"

[...]

while [ -n "${1}" ]; do
if [ "${SCOPE}" == "global" ]; then
if grep "^${1} *-" "${descdir}/use.desc" > /dev/null; then
get_flagstatus "${1}"
foundone=1
fi
grep "^${1} *-" "${descdir}/use.desc"
fi
# local flags are a bit more complicated as there can be multiple
# entries per flag and we can't pipe into printf
if [ "${SCOPE}" == "local" ]; then
if grep ":${1} *-" "${descdir}/use.local.desc" > /dev/null; then
foundone=1
fi
grep ":${1} *-" "${descdir}/use.local.desc" \
| sed -e "s/^\([^:]\+\):\(${1}\) *- *\(.\+\)/\1|\2|\3/g" \
| while read line; do
pkg="$(echo $line | cut -d\| -f 1)"
flag="$(echo $line | cut -d\| -f 2)"
desc="$(echo $line | cut -d\| -f 3)"
get_flagstatus "${flag}"
printf "%s (%s):\n%s\n\n" "${flag}" "${pkg}" "${desc}"
done
fi
shift
done


Przy okazji takiego grzebania można sie trochę nauczyć i dowiedzieć o Gentoo i portage'u. Jak widać opisy flag globalnych - znajdują się w pliku profiles/use.desc w katalogu głównym systemu portage, natomiast flagi zdefiniowane w poszczególnych paczkach (lokalne) - w profiles/use.local.desc.
Patrząc na pętle łatwo zauważyć, że wyszukiwanie odbywa się za pomocą polecenia grep (o tym innym razem). W wypadku flag globalnych operacja jest dość szybka, jednak komplikuje się i wydłuża przy flagach lokalnych ze względu na ich format (warto zaglądnąć do tych plików). No i już wiemy dlaczego to tyle trwa.

Przeglądając źródła warto zwrócić jeszcze uwagę na komendę set +f/set -f, która odpowiada za obsługę globbingu w shellu - w skrócie ubogiego krewnego wyrażeń regularnych (o tym innym razem). Tu została zastosowana, żeby ominąć jej rozwinięcie/ewaluację w shellu - widać chłopaki mieli pewien problem z tym przy wywołaniu.

PS. Następnym razem opowiem o innych narzędziach do zarządzania flagami.
Zmieniam też nieco tryb pisania z pn-sobota na pn/sr/pt

sobota, 11 lipca 2009

Konfiguracja powiadomień przy wykonaniu komendy sudo

Sudo jak już zapewne wiemy umożliwia nam rozszerzenie uprawnień użytkownika w systemie bez konieczności udostępniania hasła konta root.

Warto wiedzieć, że sudo ma możliwość informowania o aktywności użytkowników w systemie - wykonywanych poleceniach, próbach naruszania uprawnień, etc.

Domyślnie komenda sudo zapisuje informacje w logu systemowym - w zależności od dystrybucji i konfiguracji loggera systemowego, moe to być /var/log/auth.log (Debian i s-ka), /var/log/secure (Redhat & co). Można też skonfigurować polecenie sudo, tak żeby w momencie użycia tej komendy wysyłane było powiadomienie na wybraną skrzynkę pocztową.

Jak to zrobić?
Wyedytujmy /etc/sudoers:

vim /etc/sudoers


Teraz musimy ustawić konto, na które będą trafiały powiadomienia - dodajemy:

mailto "admin@mojafirma.pl"
mail_always on


Opcje są dość opisowe:
- mailto "admin@staff.example.com" - do kogo wysłać mail
- mail_always - wysyłaj zawsze gdy wykonywane jest sudo (domyślnie jest wyłączone)

Dodatkowo możemy ustawić na on/off:
- mail_badpass - wysyłaj powiadomienia gdy użytkownik poda niewłaściwe hasło (domyślnie wyłączone)
- mail_no_host - wysyłaj maila gdy użytkownik nie ma uprawnień do wykonania danej komendy na określonym hoście (domyślnie wyłączone)
mail_no_perms - wysyłaj maila gdy użytkownik nie ma uprawnień do wykonania danej komendy (domyślnie wyłączone)
- mail_no_user - wysyłaj maila gdy użytkownik nie jest zdefiniowany w pliku sudoers (domyślnie włączone)
Sudo Logfile

UWAGA! Należy pamiętać o odpowiednim skonfigurowaniu systemu pocztowego na hoście z którego zamierzamy wysyłać powiadomienia.

PS. Można wyłączyc logowanie z użyciem systemu logującego - musimy wtedy ustawić ścieżkę do logów. Robimy to tak:

Defaults !lecture,tty_tickets,!fqdn,!syslog
Defaults logfile=/var/log/sudo.log

piątek, 10 lipca 2009

visudo - cóż to jest?

Ponieważ ktoś mnie ostatnio zagadnął apropos informacji znalezionych na blogu - odpowiem szybko jak mi się wydaje - cóż to jest.

Visudo to nic innego jak narzędzie przygotowane specjalnie na potrzeby edycji pliku /etc/sudoers, w którym przechowywana jest konfiguracja polecenia sudo - zdefiniowane są uprawnienia - kto co i jak może uruchomić w systemie.
Visudo korzysta domyślnie z aktualnie zdefiniowanego edytora tekstowego.
Krótka dygresja na temat edytora tekstowego
W systemie można zdefiniować edytor systemowy za pomocą zmiennej środowiskowej EDITOR. Warto sprawdzić co jest ustawione u nas:

# env|grep EDITOR
EDITOR=/usr/bin/vim


W każdej chwili możemy zmienić aktualnie używany edytor na dowolny - zmieniając ścieżkę edytora w zmiennej EDITOR.
W Gentoo ustawienia domyślnej wartości zmiennej EDITOR dokonujemy w pliku /etc/rc.conf (o tym innym razem).
Koniec krótkiej dygresji

Oczywiście plik /etc/sudoers możemy edytować za pomocą dowolnego edytora tekstu ale tylko visudo zapewni nam dwie rzeczy:
1. kontrolę poprawności konfiguracji (kontrolę składni)
2. blokadę przed równoczesnymi zmianami pliku /etc/sudoers

Jak zawsze polecam czytanie manuala (man visudo) - RTFM!

czwartek, 9 lipca 2009

ORA-12162 TNS:net service name is incorrectly specified

Ostatnio doświadczyłem tego na Debianie po zainstalowaniu Oracle XE zgodnie z zaleceniami okazało się, że próby połączenia z Oraclem przez sqlplus kończą się powyższym błedem 'ORA-12162 TNS:net service name is incorrectly specified'. Jak się okazuje rozwiązanie jest banalne - wystarczy ustawić zmienne środowiskowe (hmm... dziwne, że w paczce to nie jest robione - no cóż - debian):

export ORACLE_SID=XE
export ORACLE_HOME=/usr/lib/oracle/xe/app/oracle/product/10.2.0/server


i już. Później najlepiej te zmienne ustawić w domyślnym środowisku - o ile się nie mylę w Debianie można to zrobić w /etc/profile lub /etc/bash.bashrc (strasznie brakuje mi tu katalogu /etc/env.d z Gentoo).

środa, 8 lipca 2009

Bash - PIPESTATUS

W jednym z pierwszych blogów zadałem pytanie dotyczące wykrywania błędu przy wykonaniu poleceń w potoku (pipe).

W wypadku jakichkolwiek skryptów ważne jest pilnowanie poprawności wykonania komend. Każda wykonana komenda zwraca status zakończenia, który jeśli wszystko przebiegło poprawnie powinien być równy zero.
Sprawdźmy to:

# ls
# echo $?
0


Co jednak w wypadku gdy korzystamy z potoku?
Weźmy przykład:

cat plik | gzip > plik2.gz


Co sie stanie jeśli plik nie istnieje? Wykonajmy to polecenie:

cat: plik: No such file or directory
# echo $?
0


Status wykonania polecenia poprawny (zero). Dlaczego? Ponieważ zmienna $? przechowuje stan wykonania ostatniego polecenia. W naszym przykładzie błąd wystąpił przy pierwszym poleceniu - wyświetleniu zawartości pliku. Ponieważ plik nie istniał został wyświetlony błąd - jednak operacja była kontynuowana w potoku. Polecenie gzip wykonało się poprawnie - skompresowało zerowej wielkości strumień wejściowy. Zwrócony status jest więc jak najbardziej w tym wypadku właściwy - mimo, że cała operacja w potoku nie wykonała się po naszej myśli.
W takim wypadku z pomocą przychodzi zmienna $PIPESTATUS - tabela statusów zakończenia poleceń w potoku. Każda kolejna komórka tabeli zawiera status wykonania poszczególnych poleceń. Zobaczmy jak to działa:

cat plik |gzip > plik2.gz
cat: plik: No such file or directory
# echo ${PIPESTATUS[*]}
1 0


Mamy niepoprawny status wykonania cat - jest więc możliwość stwierdzenia błędu wykonania któregoś z poleceń w potoku.
Możemy odwoływać się do poszczególnych komórek tabeli za pomocą indeksu, np. dla pierwszego polecenia będzie to ${PIPESTATUS[0]}. Należy jednak pamiętać o tym, że zawartość zmiennej PIPESTATUS jest 'ulotna', tzn. dostępna jest tylko bezpośrednio po wykonaniu polecenia. Dla zrozumienia pokażę to na poniższym przykładzie:

cat plik |gzip > plik2.gz
cat: plik: No such file or directory
# echo ${PIPESTATUS[*]}
1 0
# echo ${PIPESTATUS[*]}
0

Drugie wykonanie zwraca status wykonania polecenia echo.

W wypadku dłuższych skryptów istnieje możliwość przerwania przetwarzania skryptu w wypadku wystąpienia błędu za pomocą komendy set -e. Myślę, że jest to wygodniejsze niż śledzenie statusów po każdym wywołaniu (chociaż jak zawsze to zależy od tego co robimy).

PS. Możemy wykluczyć poszczególne polecenia w skrypcie z "ostrej" obsługi błędów przy włączonym set -e. Robimy to poprzedzając dane polecenie znakiem wykrzyknika '!'. Polecam manual set

Przydatne odnośniki:
http://tldp.org/LDP/abs/html/internalvariables.html

wtorek, 7 lipca 2009

Instalacja pakietów w dystrybucji gentoo na przykładzie serwera subversion. Część III

Zakładam, że kompilacja przebiegła bezproblemowo. Jednymi z ostatnich komunikatów po instalacji w dystrybucji Gentoo są często informacje o tym co trzeba zrobić, żeby uzyskać w pełni funkcjonalny, działający produkt. To według mnie kolejna zaleta, która jest przydatna szczególnie wtedy gdy poruszamy się po nowym gruncie, tj. testujemy jakis nieznany nam w szczegółach pakiet a chcemy go szybko uruchomić. Instrukcja jest dobrze sformatowana, a ze względu na to, że korzystamy z kolorowej konsoli - trudno ją przeoczyć. Dodatkowo w przypadku instalacji kilku pakietów emerge na zakończenie instlacji wyświetli w podsumowaniu informacje z każdego z nich. Są jeszcze inne sposoby na to, żeby nie przeoczyć komunikatów (o tym innym razem).
W wypadku subversion wygląda to tak:

* Subversion Server Notes
* -----------------------
*
* If you intend to run a server, a repository needs to be created using
* svnadmin (see man svnadmin) or the following command to create it in
* /var/svn:
*
* emerge --config =dev-util/subversion-1.6.2
*
* Subversion has multiple server types, take your pick:
*
* - svnserve daemon:
* 1. Edit /etc/conf.d/svnserve
* 2. Fix the repository permissions (see "Fixing the repository permissions"
)
* 3. Start daemon: /etc/init.d/svnserve start
* 4. Make persistent: rc-update add svnserve default
*
* - svnserve via xinetd:
* 1. Edit /etc/xinetd.d/svnserve (remove disable line)
* 2. Fix the repository permissions (see "Fixing the repository permissions"
)
* 3. Restart xinetd.d: /etc/init.d/xinetd restart
*
* - svn over ssh:
* 1. Fix the repository permissions (see "Fixing the repository permissions"
)
* Additionally run:
* groupadd svnusers
* chown -R root:svnusers /var/svn/repos
* 2. Create an svnserve wrapper in /usr/local/bin to set the umask you
* want, for example:
* #!/bin/bash
* . /etc/conf.d/svnserve
* umask 007
* exec /usr/bin/svnserve ${SVNSERVE_OPTS} "$@"
*
* - http-based server:
* 1. Edit /etc/conf.d/apache2 to include both "-D DAV" and "-D SVN"
* 2. Create an htpasswd file:
* htpasswd2 -m -c /var/svn/conf/svnusers USERNAME
* 3. Fix the repository permissions (see "Fixing the repository permissions"
)
* 4. Restart Apache: /etc/init.d/apache2 restart
*
* Fixing the repository permissions:
* chmod -Rf go-rwx /var/svn/conf
* chmod -Rf g-w,o-rwx /var/svn/repos
* chmod -Rf g+rw /var/svn/repos/db
* chmod -Rf g+rw /var/svn/repos/locks
*
* If you intend to use svn-hot-backup, you can specify the number of
* backups to keep per repository by specifying an environment variable.
* If you want to keep e.g. 2 backups, do the following:
* echo '# hot-backup: Keep that many repository backups around' > /etc/env.d/80
subversion
* echo 'SVN_HOTBACKUP_BACKUPS_NUMBER=2' >> /etc/env.d/80subversion
*
* Subversion contains support for the use of Memcached
* to cache data of FSFS repositories.
* You should install "net-misc/memcached", start memcached
* and configure your FSFS repositories, if you want to use this feature.
* See the documentation for details.
*
>>> Regenerating /etc/ld.so.cache...

>>> Recording dev-util/subversion in "world" favorites file...


Emerge oprócz wymienionych już cech (instalacja, dobór flag, changelog, itd.) jest w stanie skonfigurować zainstalowany pakiet - oczywiście o ile ten pakiet posiada taką funkcjonalność (o tym innym razem). Jak widać, po instalacji menadżer pakietów zaleca mi skonfigurowanie pakietu. Mam to zrobić za pomocą komendy:


# emerge --config =dev-util/subversion-1.6.2


Configuring pkg...

* >>> Initializing the database in //var/svn ...
* >>> Populating repository directory ...
* >>> Setting repository permissions ...


Ponieważ w wypadku subversion istnieje kilka trybów uruchomienia serwera repozytorium, które podaje nam instrukcja - konieczne jest wykonanie instrukcji odpowiednich dla wybranego rodzaju pracy serwera. Dla mnie to dodatkowy plus jeśli chodzi o Gentoo - instalowane pakiety dostarczane są z dokładną instrukcją. Dzięki temu mam wgląd w podstawowe możliwości - co dodatkowo ułatwia zaznajomienie się z funkcjonalnością instalowanego pakietu.
Jak widać subversion może działać jako:
- osobny daemon (o tym innym razem)
- daemon uruchamiany w miarę potrzeby poprzez daemon'a xinetd (o tym innym razem).
- svn po ssh - czyli tunelowanie połączenia z repozytorium za pomocą ssh (o tym innym razem)
- usługa na protokole HTTP - poprzez serwer apache

Ja wybiorę repozytorium działające po protokole http.
Muszę więc wykonać czynności konfiguracyjne specyficzne dla serwera apache.
1. edycja pliku /etc/conf.d/apache2 i dodanie do zmiennej APACHE2_OPTS dwóch makr "-D DAV" i "-D SVN"
Zatrzymajmy się tu na chwilę - pojawiło się trochę nowości - wyjaśnię po kolei większość z nich.
Po pierwsze katalog /etc/conf.d - to specjalny katalog, w którym znajdują się ustawienia startowe poszczególnych usług uruchamianych w systemie. W innych dystrybucjach analogiczne informacje są często przechowywane w katalogu /etc/defaults. Tak więc plik /etc/conf.d/apache2 jest plikiem konfiguracyjnym skryptu startowego serwera apache. Skrypty startowe znajdują się w katalogu /etc/init.d i mają taką samą nazwę jak pliki konfiguracyjne z /etc/conf.d. Makro definiowane przez nas służy najczęściej (w wielkim skrócie) do tworzenia warunków w konfiguracji serwera przy których dany moduł lub dana konfiguracja ma być wczytana, np. możemy za pomocą niego definiować w konfiguracji kiedy moduł ma być wczytany. Pozwolę sobie wsadzić tu ni z gruszki ni z pietruszki fragment konfiguracji jaka mogła by być użyta w przypadku makra DAV:


< IfDefine DAV>
LoadModule mod_dav.so
</IfDefine>


2. Stworzenie pliku htpasswd:
# htpasswd2 -m -c /var/svn/conf/svnusers krzysiek

Plik ten wykorzystamy do przechowywania bazy użytkowników, którzy później bedą mieli dostęp do repozytorium, po wcześniejszym uwierzytelnieniu. Istnieje wiele mechanizmów uwierzytelniania użytkowników poprzez serwer apache (m.in. dlatego korzystamy z apache'a) - my w tej chwili skorzystamy z domyślnego jaki proponuje nam subversion.
3. Poprawki w ustawieniu uprawnień do plików:
# chmod -Rf go-rwx /var/svn/conf
# chmod -Rf g-w,o-rwx /var/svn/repos
# chmod -Rf g+rw /var/svn/repos/db
# chmod -Rf g+rw /var/svn/repos/locks


Muszę jeszcze skonfigurować serwer apache. Ponieważ na razie chcę uruchomić repozytorium skorzystam z gotowca. Ponieważ ustawiłem przy instalacji subversion USE flagę apache2 - zostały zainstalowane dodatkowe moduły do apache'a. Ich konfiguracja znajduje się w pliku /etc/apache2/modules.d/47_mod_dav_svn.conf. Wyedytuję ten plik i odkomentuje wszystkie linie z przykładową konfiguracją, które się tam znajdują.

4. Uruchom/zrestartuj serwer apache

# /etc/init.d/apache2 restart


Sprawdźmy czy działa?
# svn info http://localhost/svn/repos/
Authentication realm: Subversion repository
Password for 'root':
svn: Server sent unexpected return value (500 Internal Server Error) in response to OPTIONS request for 'http://localhost/svn/repos'


Nie działa - ale rozczarowanie. Pomyślmy - co może być nie tak?
Komunikat wskazuje na błąd po stronie serwera www. Zajrzę w logi błędów apache'a (error logs).

# tail /var/log/apache2/error_log
[Thu Jul 09 09:25:28 2009] [notice] caught SIGTERM, shutting down
[Thu Jul 09 09:25:57 2009] [notice] Apache/2.2.11 (Unix) DAV/2 mod_ssl/2.2.11 OpenSSL/0.9.8k SVN/1.6.2 PHP/5.2.9-pl2-gentoo configured -- resuming normal operations
[Thu Jul 09 09:29:54 2009] [error] [client 127.0.0.1] (13)Permission denied: Could not open password file: /var/svn/conf/svnusers


aha - uprawnienia do pliku - chłopaki w Gentoo coś przegapili w instrukcji - zgłoszę na bugs.gentoo.org
Ustawię poprawnie uprawnienia dla całego repozytorium

# chown -R apache:apache /var/svn

Sprawdzę teraz:

# svn co http://localhost/svn/repos/
Authentication realm: Subversion repository
Password for 'root':
Authentication realm: Subversion repository
Username: krzysiek
Password for 'krzysiek':
-----------------------------------------------------------------------
ATTENTION! Your password for authentication realm:

Subversion repository

can only be stored to disk unencrypted! You are advised to configure
your system so that Subversion can store passwords encrypted, if
possible. See the documentation for details.

You can avoid future appearances of this warning by setting the value
of the 'store-plaintext-passwords' option to either 'yes' or 'no' in
'/root/.subversion/servers'.
-----------------------------------------------------------------------
Store password unencrypted (yes/no)? n
Please type 'yes' or 'no': no
Checked out revision 0.


Jest OK.
UWAGA! Zwróćcie uwagę na komunikat (zawsze zwracajcie uwagę na komunikaty) - warto wyłączyć przechowywanie haseł w pliku na dysku.
Robimy to ustawiając opcję store-plaintext-passwords na no w pliku /root/.subversion/config

I to na tyle na dziś. Następnym razem zajmę się omówieniem podstaw obsługi repozytorium subversion.

W najbliższym czasie wspomnę też o skryptach startowych Gentoo i omówię pominięte dziś punkty z instrukcji tj. snv_hot_backup i pakiet memcached.