• Nie Znaleziono Wyników

Podsystem wejścia/wyjścia

N/A
N/A
Protected

Academic year: 2021

Share "Podsystem wejścia/wyjścia"

Copied!
31
0
0

Pełen tekst

(1)
(2)

Rodzaje urządzeń wej/wyj

W systemach UNIXowych występują dwa rodzaje urządzeń wej/wyj:

blokowe: dyski, taśmy, ....

znakowe: terminale, urządzenia sieciowe, ...

Ponieważ wszystko w UNIXie jest plikiem, to również urządzenia wej/wyj są reprezentowane w systemie plików UNIXa przez tzw.

pliki specjalne.

Pliki te jak wszystkie inne pliki w systemie posiadają nazwę i i-węzeł zawierający (także):

 prawa dostępu

typ pliku: b oznacza blokowy, c oznacza znakowy Pliki specjalne są tworzone przez administratora np. tak:

mknod /dev/tty13 c 2 13

Pow. oznacza, że administrator utworzył plik specjalny o nazwie

/dev/tty13 reprezentujący urządzenie znakowe o numerze głównym urządzenia 2 (określającym typ urządzenia w odp.

tablicach rozdzielczych) i numerze drugorzędnym 13.

(3)

Schemat podsystemu plików

open close read write ioctl mountopen umount readclose write

Tablica rozdzielcza urządzeń

znakowych

Pamięć bufora Tabl. rozdzielcza urz. blok.

open closereadwrite ioctl Podprogram obsługi

urządzeń

Prog. obsługi przerwań

open close strategia Podprogram obsługi

urządzeń

Program obsługi przerwań Wektor przerwań Wektor przerwań

Przerwanie od urządzenia

(4)

Tablice rozdzielcze

poz. open close strategia 0 1 gdopen gtopen gdclose gtclose gdstrategia gtstrategia

Tablica rozdzielcza urządzeń blokowych

poz. open close read 0 1 conopen dzbopen conclose dzbclose conread dzbread

Tablica rozdzielcza urządzeń znakowych

write ioctl 2 3 syopen nulldev nulldev nulldev syread mmread 4 5 gdopen gtopen gdclose gtclose gdread gtread conwrite dzbwrite sywrite mmwrite gdwrite gtwrite conioctl dzbioctl syioctl nodev nodev nodev To tylko przykład w Linuxie jest podobnie ale inaczej 4

(5)

cd.

Tablice rozdzielcze

W pow. tabeli nulldev oznacza pusty podprogram obsługi:

nie rób nic, natomiast nodev oznacza brak podprogramu obsługi.

Sposób obsługi operacji wej/wyj dla urządzeń specjalnych różni się od obsługi analogicznych operacji wej/wyj dla plików zwykłych.

Algorytm obsługi operacji wej/wyj dla urządzeń specjalnych:

 proc. otrzymuje deskr. pliku użytkownika poziom użytkownika

 na jego podstawie zagląda do tablicy plików i dalej do tablicy i-węzłów

 na podstawie i-węzła jądro ustala typ pliku i

odwołuje się do odpowiedniej tablicy rozdzielczej  jądro pobiera z i-węzła główny i

drugorzędny numer urządzenia

 na podstawie nru głównego wywołuje odp. procedurę obsługi z tablicy rozdzielczej przekazując procedurze nr drugorzędny

poziom jądra

(6)

uwagi

Tablice rozdzielcze

Różnica między wywołaniami procedur wej/wyj dla plików

specjalnych i plików zwykłych polega na tym, że pierwsze nie blokują węzła pliku specjalnego natomiast drugie blokują odp

i-węzeł. Gdyby następowała blokada i-węzła pliku specjalnego, to inne procesy korzystające z tego samego urządzenia spały by z powodu drzemki procesu aktualnie korzystającego z urządzenia. Stąd algorytmy otwierania i zamykania plików specjalnych muszą uwzględniać to, że nie są jedynymi użytkownikami urządzeń.

Zdarza się, że operacje read/write dla urządzeń znakowych

buforują wewnętrznie przesyłane dane. Jeżeli urządzenie zapycha

się, to operacja write powoduje zaśnięcie procesu.

Procedury strategii służą do transmisji danych między podręczną

pamięcią bufora a urządzeniem. Procedura strategii może kolejkować żądania wej/wyj do danego urządzenia na liście

pomocniczej lub wykonać bardziej wyrafinowane kolejkowanie.

(7)

ioctl

Tablice rozdzielcze

Funkcja ioctl umożliwia procesom ustawianie sprzętowych opcji poszczególnych urządzeń oraz opcji programowych związanych z podprogramami obsługi urządzeń.

Programy korzystające z ioctl muszą wiedzieć jaki jest rodzaj

pliku, dla którego tę funkcję wywołują - jest to wyjątek w UNIXie od zasady nie rozróżniania typu pliku.

Składnia:

ioctl (deskr_pliku, polecenie, argument) deskr_pliku ustalony przez uprzednie wywołanie open

polecenie predefiniowana stała oznaczająca akcję

argument wskaźnik do odp. struktury, każdy podprogram

obsługi interpretuje ją wg własnej specyfikacji

Ćwiczenie

Zamontuj dyskietkę (mount /dev/fd0 /mnt/floppy). Skopiuj na nią duży plik. Wykonaj umount /mnt/floppy.

Kiedy następuje zapis? Co zrobi odp. procedura strategii? Co się stanie gdy tak samo postąpimy z małym plikiem?

(8)

Podprogramy obsługi przerwań

wektory przerwań

ttyintr 0 ttyintr 1 consintr printintr 0

płyta tylna

komputera

urządzenia

tty00 tty07 tty08 tty15 console printer00 printer07 8

(9)

Podprogramy obsługi przerwań

cd.

Jeżeli tty09 wygeneruje przerwanie, to jądro wywoła podprogram

obsługi związany ze sprzętowym położeniem tego urządzenia (tu: ttyintr 1).

Wiele urządzeń może być związanych z jednym wektorem przerwań. Podprogram obsługi przerwania jako parametr otrzymuje nr

wektora przerwań (tu: 0 lub 1) oraz informacje z samego

przerwania umożliwiające stwierdzenie, że to tty09 a nie tty15 spowodował przerwanie.

Numer urządzenia używany przez podprogram obsługi przerwania identyfikuje jednostkę sprzętową (np. tty09), numer drugorzędny pliku specjalnego identyfikuje urządzenie na potrzeby jądra

systemu.

Podprogram obsługi przerwania wiąże drugorzędny numer urządznia z odpowiednim numerem jednostki sprzętowej.

(10)

Podprogramy obsługi dysków

Programy użytkowe mogą korzystać z surowego (znakowego) lub

blokowego dostępu do urządzeń dyskowych (tak nie jest w Linuxie).

Czytając i pisząc z/na urządzenia blokowe, tak naprawdą czytamy/

zapisujemy z bufora za pośrednictwem podprogramów strategii.

Może to prowadzić do czytania danych uprzednio zapisanych do bufora lecz jeszcze nie zapisanych na dysk.

Procedury dostępu do dysków przez urządzenia znakowe

czytają/piszą bezpośrednio z/do dysku do/z pamięci użytkownika.

Przykład

Załóżmy, że pliki specjalne /dev/dsk15 i /dev/rdsk są

urządzeniami, odpowiednio, blokowym i znakowym z tym samym numerem drugorzędnym (związane z tym samym dyskiem

fizycznym). Przyjrzyjmy się programowi prog1008.c. Kiedy w buforach programu mogą się pojawić różnice?

Pow. program ma szansę zadziałać na UNIXach typu System V - Linux obsługuje urządzenia znakowe trochę inaczej niż reszta UNIXów. 10

(11)

TeleType, terminale i pty

Większość urządzeń przeznaczonych do pracy interakcyjnej (nie tylko w systemach UNIXowych) posiada bardzo podobny interfejs odziedziczony po historycznym już szeregowym terminalu

drukującym

TeleType. Interfejs ten, zwany tty, dzięki swej

prostocie posiada szerokie zastosowanie, np.: terminale szeregowe, konsole, X-terminale, połączenia sieciowe, .... .

Próbowano zaimplenetować interfejs tty. Najbardziej znane są:

sgtty pochodzący z systemu BSD - dziś odchodzi się od niego

termio pochodzący z Systemu V

termios pochodzący ze standardu POSIX - nadzbiór termio

Koncepcyjnie interfejs tty wspiera przepływ danych pomiędzy

programem, a urządzeniami (sprzętem), np.: interpreter poleceń i modem lub terminal lub drukarka lub ... .

Instnieje również możliwość podłączenia do obu końcówek interfejsu tty oprogramowania. Nazywamy go wówczas

(12)

Terminal

koncepcje

program

A

C

D

sterownik

terminala

B

program A generuje sekwencje znaków wyjściowych na D i interpretuje sekwencje znaków wejściowych z C; A może

wchodzić w interakcję z C i D za pomocą funkcji systemowych

read i write

główna funkcja sterownika terminala B obsługuje transfer danych między programem A a sprzętem C i D; B zwykle składa się z dwóch części: ze sterownika urządzenia (niskopoziomowe

oprogramowanie będące interfejsem sprzętu) i modułu protokołów, zwanego też dyscypliną linii (odwzorowuje jedne sekwencje

(13)

Terminal

punkt widzenia jądra

powłoka

użytkownika

dyscyplina

linii

sterownik

urządzeni

a

bufor

wejściowy

bufor

wyjściowy

13

(14)

Dyscyplina linii

Dyscyplina linii jest wewnętrznym interfejsem jądra służącym do

filtrowania danych tekstowych.

Może ona pracować w dwóch trybach:

kanonicznym: przekształca sekwencje znaków na oczekiwane

przez użytkownika

surowym: brak jakiejkolwiek konwersji Funkcje dyscypliny linii:

 dzieli wejściowy ciąg znaków na linie

 przetwarza znaki ścierające i kasowania linii

 wypisuje na terminalu echo odebranych znaków

rozbudowuje dane wyjściowe, np.: TAB zamienia na ciąg spacji

 wysyła do procesów sygnały o zawieszeniu terminala

 umożliwia pracę w trybie surowym

We wczesnych latach 70'tych dyscyplina linii znajdowała się w

shellu i edytorach. Ritchie zauważył, że spełnia funkcje potrzebne wielu programom i przeniósł ją do jądra.

(15)

Listy znakowe

Listy znakowe są podstawową strukturą danych dla dyscypliny linii.

p

i

c

o

p

l

i

k

.

t

x

t

blok znakowy

0 8

5

0

wskaźnik na nast. tabl. znakową początek koniec tablica znakowa

16

znaków

Jądro utrzymuje listę wolnych bloków/tablic znakowych i wykonuje następujące operacje:

 przydziela podprogramowi obsługi blok znakowy z listy wolnych

 zwraca blok znakowy do listy wolnych bloków znakowych

 pobiera, usuwa i wstawia znaki z/na listę znakową

 usuwa grupy znaków po jednym bloku

(16)

Listy znakowe

przykład

Usuwamy z listy znakowej tekst: .txt

p

i

c

o

p

l

i

k

0 8

1

0

16

znaków

Dopisujemy do listy znakowej teskt: .wa?ny.txt

p

i

c

o

p

l

i

k

.

w

a

?

n

y

.

0 8

0 3

8

0

24

znaki

t

x

t

16

(17)

Terminal - tryb kanoniczny

schemat

Proces

dyscypliny linii

surowa lista

znakowa

wyjściowa

lista znakowa

kanoniczna

lista znakowa

moduł

dyscypliny

linii

klawiatura

procesy

systemu

ekran

17

(18)

Terminal - tryb kanoniczny

opis

Zapisywanie do terminala przez proces:

 dyscyplina linii przepisuje znaki z przestrzeni użytkownika do listy wyjściowej aż do wyczerpania danych

 dyscyplina linii przetwarza listę wyjściową na kanoniczną i

jeżeli kanoniczna przekroczy ustalony rozmiar to wysyła z niej dane na terminal usypiając inne piszące procesy systemowe

Jeżeli wiele procesów pisze na terminal, to każdy z nich niezależnie wykonuje powyższy algorytm - dane mogą się pomieszać.

program1014.c demonstruje zalewanie wyjściowej listy znakowej przez 18 procesów - procesy wysyłają ponad 64 bajty

jednorazowo, co zmusza jądro do utworzenia conajmniej dwóch bloków znakowych (w Sys. V jeden blok znak. zajmuje 64 bajty) Program ten może nie działać poprawnie na Linuxie z większymi blokami znakowymi lub szybszym modułem dyscypliny linii -

program przedstawia jedynie ideę - dostosowanie go do potrzeb Linuxa zostawiam jako zadanie dla studentów (o ile to możliwe:-)

(19)

Czytanie danych z terminala

 dyscyplina linii kopiuje znaki z surowej listy znakowej i

przetworzone kopiuje do list: wyjściowej i kanonicznej (by echować klawiaturę na ekranie)

 umożliwienie czytania z terminala przez wiele procesów jest z natury niejednoznaczne, jądro stara poradzić sobie z taką

sytuacją najlepiej jak potrafi

 z drugiej strony umożliwienie czytania z terminala wielu procesom jest konieczne - w przeciwnym razie procesy korzystające z stdio nie mogły by działać

program1016.c przedstawia rywalizację procesów o linie danych z terminala (procesy czytają po jednej linii). Przykład ten

pokazuje, że procesy powinny synchronizować dostęp do

terminala na poziomie użytkownika, a nie polegać na jądrze. Spróbować w dowolny sposób zsynchronizować procesy czytające z pow. programu - niezbędne informacje nt synchronizacji - patrz

wykład.

(20)

Tryb surowy terminala

Znaki mogą być przesyłane do terminala bez obróbki (na surowo). Jądro musi jednak wiedzieć kiedy spełnić żądanie czytania - znak końca wiersza jest teraz zwykłym znakiem.

Jądro wywoła funkcję read, jeżeli z terminala wprowadzi się pewną ustaloną liczbę znaków lub po upływie ustalonego czasu. Tryb surowy jest szczególnie ważny dla programów

ukierunkowanych na ekran takich jak np. vi.

program1017.c przedstawia użycie funkcji ioctl do ustawienia

parametrów terminala związanego z deskryptorem pliku o nr 0 (czyli stdin).

readpass.c przedstawia użycie funkcji biblioteki termios do chwilowego wyłącznia echowania na ekranie znaków

pobieranych z klawiatury

Ćwiczenie

Napisz program przejmujący kontrolę nad terminalem dla realizacji własnych funkcji?

(21)

Polecenie stty

UWAGA: Większość ustawień terminala można zmieniać za pomocą

komendy stty np:

stty -a wypisuje na ekranie aktualne ustawienia termios

stty -g > zapis_stty zapisuje do pliku aktualne ustawienia w

formacie gotowym do odczytu (stty $(cat zapis_stty))

stty sane ustawia rozsądne wartości większości parametrów stty erase znak ustawia znak kasowania do tyłu na znak

Inne znaki ustawialne przez stty:

kill usunięcie wszystkich znaków aż do początku linii

intr znak przetwania, powoduje wysłanie sygnału SIGINT, do

programu czytającego z terminala i wszystkich innych procesów rozpoznających ten terminal jako swój terminal sterujący

quit wysłanie do grupy procesów związanych z terminalem sygnału SIGQUIT, skutkiem przeważnie jest tzw. zrzut rdzenia (core

dump) czyli zapisanie na dysku przestrzeni pamięci programu i

(22)

cd.

Inne znaki ustawialne przez stty

cd:

eof znak końca strumienia wejściowego do terminala, zwykle jest to znak Ctrl-D

stop znak chwilowo zawieszający wyjście na terminal, zwykle jest to znak Ctrl-S

start znak używany do ponownego uruchamiania wyjścia,

zatrzymanego uprzednio przez Ctrl-S, zwykle jest to znak Ctrl-Q, jeżeli znak Ctrl-S nie niezostał zdefiniowany, to Ctrl-Q jest ignorowany

susp wysyła sygnał SIGQUIT do grupy procesów powiązanych z

terminalem, powoduje zawieszenie bieżącej grupy procesów pierwszoplanowych i umieszczenie ich w tle, zwykle jest to znak Ctrl-Z

Wartości

time

i

min

:

Ustawiane tylko w trybie niekanonicznym. Sterują odczytem wejścia terminala - określają co się stanie, gdy program będzie się starał czytać deskryptor pliku związany z terminalem.

Polecenie stty

(23)

Wartości

time

i

min

Przypadki wzajemnych ustawień

time

i

min

:

time = 0

i

min = 0

read zawsze natyczmiast będzie zwracał znaki; jeśli są dostępne jakieś znaki to zostaną zwrócone, jeśli nie read zwróci zero i nie zostaną przeczytane żadne znaki

time > 0

i

min = 0

read zwraca liczbę dostępnych znaków, natomiast jeśli upłynęło

time

dziesiątek sekund i nie ma żadnych znaków na wejściu, to

zwraca zero

time = 0

i

min > 0

read będzie czekać, aż zostanie przeczytanych

min

znaków, a potem zwraca ich liczbę; na końcu pliku zwraca zero

time > 0

i

min > 0

read zwraca liczbę odczytanych znaków, gdy odczyta

min

znaków lub gdy między odczytywanymi znakami upłynie czas

time

dziesiątek sekund

(24)

Biblioteka

termios

termios jest standardowym interfejsem opisanym przez POSIX. Jest on sterowany przez ustawienia wartości w strukturze typu

termios oraz przez wywołania odpowiednich funkcji - oba

zdefiniowane w pliku nagłówkowym termios.h.

Parametry, którymi można wpływać na zachowanie terminala pogrupowane są w następujące tryby: wejściowy, wyjściowy,

sterowania, lokalny i specjalnych znaków kontrolnych. #include <termios.h> struct termios { tcflag_t c_iflag; tcflag_t c_oflag; tcflag_t c_cflag; tcflag_t c_lflag; cc_t c_cc[NCCS]; };

Elementy pow. struktury odpowiadają pięciu typom parametrów wymieniomym powyżej.

(25)

Biblioteka

termios

cd.

Bieżące ustawienia terminala wczytujemy do struktury termios wskazywanej przez wsk_termios realizuje następująca funkcja:

int tcgetattr(int despliku,

struct termios *wsk_termios);

Po wprowadzeniu nowych ustawień do struktury wywołujemy funkcję:

int tcsetattr(int despliku, int działanie,

const struct termios *wsk_termios);

Parametr działanie nadzoruje sposób wprowadzania zmian. Możliwe wartości to:

TCSANOW natychmiastowa zmiana wartości

TCSADRAIN zmiana wartości, gdy bieżąca kolejka wyjściowa zostanie opróżniona

TCSAFLUSH zmiana wartości, gdy bieżące wyjście zostanie

zakończone, ale pomija wszelkie dostępne aktualnie wejścia jeszcze nie zwrócone wywołaniem read

patrz plik terminal1.c

(26)

Tryby

termios

wejściowe

Tryby te określają sposób w jaki są przetwarzane znaki wejściowe (np. z klawiatury), zanim zostaną przekazane programowi. Makra, które możemy przypisać polu c_iflag struktury termios:

BRKINT generuje przerwanie, gdy na linii zostaną stwierdzone okoliczności powodujące przerwanie

IGNBRK ignoruje na linii okoliczności powodujące przerwanie

ICRNL odwzoruje znak “powrotu karetki” na znak nowego wiersza IGNCR ignoruje odbieranie znaku powrotu karetki

INLCR zamienia znak nowej linii na znak powrotu karetki INGPAR ignoruje znaki z błędem parzystości

INPCK wykonuje sprawdzanie parzystości odbieranych znaków PARMRK zaznacza błędy parzystości

ISTRIP przycina wszystkie nadchodzące znaki

(27)

Tryby

termios

wyjściowe

Tryby te określają sposób w jaki są przetwarzane znaki wyjściowe (pochodzące z programu) przed przekazaniem ich do portu

szeregowego lub na ekran. Makra, które możemy przypisać polu c_oflag struktury termios:

OPOST włącza przetwarzanie na wyjściu

ONLCR zamienia wyjściowe znaki nowej linii na pary znaków powrotu karetki i przesuwu o wiersz

OCRNL zamienia wyjściowe znaki powrotu karetki na znaki nowej linii

ONOCR w kolumnie 0 nie będzie żadnych znaków powrotu karetki ONLRET nowa linia oznacza także wykonanie powrotu karetki

OFILL wysyła znaki wypełniające, aby zapewnić odstęp OFDEL jako znaku wypełniającego używa DEL a nie NULL itd ... (patrz man termios)

(28)

Tryby

termios

sterowania

Tryby te sterują sprzętowymi charakterystykami terminala. Makra, które możemy przypisać polu c_cflag struktury termios:

CLOCAL ignoruje wszystkie linie statusu modemu CREAD umożliwia odbieranie znaków

CS5, CS6, CS7, CS8 używa pięciu, sześciu, siedmiu, ośmiu bitów w wysyłanych lub odbieranych znakach

CSTOPB dla każdego znaku używa dwóch bitów stopu zamiast jednego

HUPCL zawiesza modem przy zamykaniu (tj. kiedy sterownik terminala stwierdza, że ostatni dekryptor pliku,

odnoszący się do terminala został zamknięty, linie sterujące modemem zostaną zawieszone)

PARENB umożliwia generowanie i sprawdzanie parzystości PARODD ustosuje raczej bity nieparzyste niż parzyste

(29)

Tryby

termios

lokalne

Tryby te kontrolują różne charakterystyki terminala. Makra, które możemy przypisać polu c_lflag struktury termios:

ECHO umożliwia lokane echo znaków wejściowych ECHOE wykonuje kombinację [Backspace], [Space],

[Backspace], gdy odbierze ERASE (tylko dla ICANON) ECHOK kasuje linię po znaku KILL (tylko dla ICANON)

ECHONL odpowiada echem na znaki nowej linii (tylko dla ICANON) ICANON umożliwia kanoniczne przetwarzanie wejścia

IEXTEN umożliwia implementowanie specyficznych (dodatkowych) funkcji przetwarzania wej/wyj terminala

ISIG włącza obsługę sygnałów

NOFLSH uniemożliwia zerowanie kolejki po odebraniu sygnałów SIGINT i SIGQUIT

TOSTOP przy próbach zapisu wysyła sygnał SIGTTOU procesom w tle

(30)

Tryby

termios

znaki kontrolne

Elementy tablicy c_cc struktury termios zawierają mapowanie znaków tzw. kontrolnych na obsługiwaną funkcję. Tablica ta jest wykorzystywana na dwa sposoby, jeden dla trybu kanonicznego i jeden dla trybu surowego.

Indeksy dla trybu kanonicznego:

VEOF znak EOF VEOL znak EOL VERASE znak ERASE VINTR znak INTR VKILL znak KILL VQUIT znak QUIT VSUSP znak SUSP VSTART znak SUSP VSTOP znak SUSP

Indeksy dla trybu surowego:

VINTR znak INTR VMIN wartość MIN VQUIT znak QUIT

VSUSP znak SUSP VTIME wartość TIME

VSTART znak SUSP VSTOP znak SUSP

patrz raz jeszcze plik readpass.c

(31)

termios

przykłady

Zakładamy, że zmienna tdes przechowuje ustawienia terminala.

tdes.c_cc[VQUIT] = \031; znak QUIT ustawiony na Ctrl-Y tdes.c_cc[VMIN] = 64; minimalna liczba znaków

tdes.c_cc[VTIME] = 2; dwie dziesiąte części sekundy tdes.c_lflag &= ~ICANON; wyłącz tryb kanoniczny

Co oznacza ?:

tdes.c_lflag &= ~(ISIG|ECHO|ICANON);

Ćwiczenie

Zademonstruj na przykładzie własnego programu kilka ustawień terminala w trybie kanonicznym i trybie surowym?

Obraz

Tablica rozdzielcza  urządzeń
Tablica rozdzielcza urządzeń znakowych

Cytaty

Powiązane dokumenty

(stawka jednostkowa z uwzględnieniem diet x liczba podopiecznych zgłoszonych w danym dniu do wyżywienia). Zamawiający nie poniesie dodatkowych kosztów ponad koszt

W szczególności Administrator może żądać udostępnienia określonych informacji lub dokumentów oraz może przeprowadzać – samodzielnie lub przez upoważnionego przez

Wykonawca składa wraz z ofertą aktualne na dzień składania ofert oświadczenie stanowiące wstępne potwierdzenie, że Wykonawca nie podlega wykluczeniu z

Życie w głuszy okazało się ciężkie i niebezpieczne, nie tylko ze względu na niedźwiedzie i inne dzikie zwierzęta, lecz także z powodu wciąż jeszcze

Jeżeli Wykonawca zamierza powierzyć podwykonawcom wykonanie części zamówienia, Zamawiający żąda wskazania tych części zamówienia w ofercie (sporządzonej zgodnie ze

1 ustawy Prawo zamówień publicznych, (W przypadku składania oferty przez wykonawców ubiegających się wspólnie o zamówienie, oświadczenie musi

Wszystkie użyte do budowy materiały muszą odpowiadać parametrom podanym w projekcie, powinny być nowe i posiadać odpowiedni atest, certyfikat na znak

M am jednak wrażenie, że godzić piórem w interes Jedności Narodowej jest niesłychanie trudno albowiem Rząd nigdy nie podał do wiadomości publicznej jaka jest