Systemy operacyjne

Opis zajęć i zasad

Zajęcia 6

Kompilacja *

Proces kompilacji programu w języku C składa się zwykle z czterech etapów:

  1. Prekompilacja (preprocessing). W czasie tego etapu przetwarzane są instrukcje preprocesora związane z dołączaniem plików, kompilacją warunkową czy makrami.

  2. Kompilacja (compilation). W czasie tego etapu kod przetworzony przez preprocesor jest przekształcany na kod źródłowy w języku assemblera.

  3. Assemblacja (assembly). W czasie tego etapu tworzone są pliki obiektów, zbudowane z przetworzonego na język maszynowy kodu assemblera.

  4. Linkowanie/konsolidacja (linking). W czasie tego etapu pliki obiektów i bibliotek łączone są tak, że powstaje jeden wykonywalny plik, w którym odwołania do elementów zdefiniowanych w innych plikach obiektów mogą być realizowane.

Zapisz poniższy program jako program.c :

#include <stdio.h>

main()
{
int number;

printf("Enter an integer\n");
scanf("%d",&number);

printf("Integer entered by you is %d\n", number);

return 0;
}

Kompilacja za pomocą kompilatora gcc:

gcc --version #wersja gcc
gcc program.c -o program #kompilacja pliku program.c do pliku wykonywalnego program
./program
gcc program.c -Wall -o program #Jeżeli chcesz, aby kompilator wyświetlał ostrzeżenia w miejscach które uznał za niepewne, użyj opcji -Wall

Ćwiczenie

Zweryfikuj efekt działania kompilatora gcc w poszczególnych etapach kompilacji. W tym celu użyj:

— opcji -c, aby zakończyć działanie kompilatora na procesie assemblacji,

opcji -S, aby zakończyć działanie kompilatora na procesie kompilacji,

— opcji -E, aby zakończyć działanie kompilatora na procesie prekompilacji.

gcc program.c -c -o program.o
gcc program.c -S -o program.s
gcc program.c -E -o program.e

Jak widzisz Linux pozwala kompilować bezpośrednio pliki C. W ogólności powinniśmy jednak korzystać z mechanizmu makefile. Stwórz plik o nazwie makefile i zapisz do niego:

program : program.c
        gcc -o program program.c

Uruchom make wpisując:

make #co się stało?
rm program #usun program
make #wykonaj make raz jeszcze
./program

Domyślnie komenda make oczekuje, że plik opisu kompilacji będzie się nazywał Makefile lub makefile. Jeżeli nazywa się on inaczej powinniśmy to zadeklarować korzystając z opcji -f.

cp makefile sample.txt
make -f sample.txt

Makefile

Make przydaje się w wielu sytacjach, szczególnie wtedy gdy plik są powiązane złożonymi rekurencyjnymi zależnościami i modyfikacja jednego wymusza zmianę (rekompilację) innych. Poczytaj więcej o tworzeniu i składni plików makefile na:

http://wazniak.mimuw.edu.pl/index.php?title=%C5%9Arodowisko_programisty/Automatyzacja_kompilacji_-_make

lub

http://www.thegeekstuff.com/2010/08/make-utility/

Obsługa systemu plików w języku C

W Linuxie, tak jak w innych Unixach, dostęp do urządzeń zewnętrznych odbywa sią poprzez system plików. Wobec tego operacje wykonywane na urządzeniach zewnętrznych są takie same, jak na plikach - są to: open, close, read, write.

Jeśli plik, na którym ktoraś z tych operacji jest wykonywana jest plikiem specjalnym (tzn. plikiem urządzenia), to wówczas przypisana mu w jego i-węźle tablica rozdzielcza file_operations wskazuje na tablice danego urządzenia i jest wykonywana funkcja specyficzna dla tego urządzenia.

open/close

Otwarcie/Zamkniecie pliku specjalnego (urządzenia). Funkcja open służy do otwierania pliku specjalnego (rozpoczęcie pracy z urządzeniem), a funkcja close - do zamknięcia pliku specjalnego. Funkcje systemowe sys_open i sys_close działają identycznie jak w przypadku plików zwykłych.

Funkcja open() próbuje otworzyć plik. Zwraca deskryptor pliku (nieujemna liczba używana przy czytaniu, pisaniu do pliku, itd.) lub -1 w przypadku błędu (kod błędu na zmiennej errno).

int open ( const char *pathname, int flags, int mode )

Parametry :

pathname - scieżka dostępu do pliku

flags - określa sposób otwierania pliku

mode - używane z flagą O_CREAT (w przeciwnym przypadku ignorowane). Okresla prawa dostępu do pliku. Jest modyfikowane przez atrybut umask procesu: prawa dostępu do tworzonego pliku będą równe (mode & ~umask).

Przykłady dostępnych flag:

O_RDONLY, O_WRONLY, O_RDWR (otwieranie pliku odpowiednio tylko do czytania, tylko do pisania, do czytania/pisania. Flagi te możemy modyfikować bitową operacja OR flagami opisanymi poniżej)

O_CREAT (jeśli plik nie istnieje będzie stworzony)

O_TRUNC (jeśli plik już istnieje obetnij go)

O_APPEND (początkowo oraz przed każdym pisaniem wskaźnik do pliku będzie ustawiany na jego końcu)

O bitach dostępu poczytaj tutaj:

http://www.gnu.org/software/libc/manual/html_node/Permission-Bits.html

Funkcja close() zwalnia deskryptor pliku, to znaczy, że może być on powtórnie przydzielony. Jeśli deskryptor jest ostatnim, który odnosi sie do danej pozycji w tablicy plików, wówczas pozycja ta jest również zwalniana. Zdejmowane są wszelkie blokady założone przez proces na pliku.

Definicja:

int close (int fd)

Wynik to \(0\) w przypadku sukcesu lub \(-1\) w przypadku błędu.

Parametry:

fd - deskryptor zamykanego pliku.

creat

Funkcja służy do tworzenia nowych plików.

Definicja:

int creat (char *pathname, int mode).

Wywołanie

creat(pathname,mode)

jest równoważne wywołaniu

open(pathname, O_CREAT | O_WRONLY | O_TRUNC, mode).

Przykład (zapisz podany plik jako program.c):

#include <stdio.h>
#include <sys/file.h>
#include <fcntl.h>
#define PERMS 0666     /* RW for owner, group, others */

int main(int argc, char *argv[])
{
        int f1;
        char * p = malloc(sizeof(char) * 128);
        scanf("%126s",p);

        if ((f1 = open(p, O_RDONLY, 0)) == -1)
        {
                printf("Can't open %s \n",p);
        } else printf("Otworzyłem\n");

        if (f1==-1)
        {
                if ((f1 = creat(p, PERMS)) == -1)
                printf("Can't create %s, mode %03o \n",p, PERMS); else printf("Swtorzylem\n");
        }

        printf("Zamykam!\n");
        close(f1);
        return 0;
}

Zwróć uwagę, że aby korzystać z open i close, korzystamy z nagłówka sys/file.h oraz fcntl.h. Wiodące zero przy zapisie PERMS jest istotne gdyż wskazuje na zapis praw w systemie ósemkowym.

Uruchom:

make -f sample.txt #makefile utworzony wcześniej (nie przejmuj się warningiem)
./program
pli.txt
./program
pli.txt
rm pli.txt
./program
pli.txt

read/write

Czytanie/Zapis z/na urządzenie.

Funkcja systemowa read służy do obsługi istniejącego pliku, stanowi ona przeciwieństwo funkcji write. Powoduje ona wczytanie odpowiedniej ilości bajtów danych z otwartego pliku do odpowiedniej struktory danych użytkownika. Czytanie rozpoczyna się od bieżącej pozycji wskaźnika w pliku; po zakończeniu czytania wskaźnik do pliku będzie zwiększony o liczbę przeczytanych bajtów.

Definicja:

int read (unsigned int fd, char *buf, unsigned int count);

Wynik: liczba wczytanych bajtów, \(0\) w przypadku napotkania na koniec pliku, -1 w przypadku błędu;

fd jest deskryptorem czytanego pliku

buf jest adresem struktury danych pod który wczytujemy dane

count jest to liczba bajtow, które chce wczytać użytkownik

Funkcja systemowa write służy do pisania do pliku (w tym również gniazda, gdyż gniazdo jest typem pliku).

Definicja:

int write (unsigned int fd, char *buf, unsigned int count);

Wynik: liczba zapisanych bajtów lub błąd.

fd jest deskryptorem zapisywanego pliku

buf jest adresem struktury danych do zapisania

count ilość bajtow do zapisania (licznik).

Funkcje te wymagają nagłówka unistd.h.

Wykonaj:

touch plik.txt
printf "XXXXXXXX\n" > plik.txt

Przykład:

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#define BUFSIZ 5
int main(){

        char* t;

        int f = open("plik.txt", O_RDWR);
        read(f, t, BUFSIZ);
        printf("%s\n",t);
        write(f, "1", 1);

        close(f);

        return 0;
}

Wykonaj:

cat plik.txt

Uwaga!

Odczyt całego pliku wymaga wielokrotnego wywołania funkcji read, ponieważ rozmiar pliku z reguły nie jest znany z góry. Poniższy przykład pokazuje przykładową pętlę odczytującą zawartość pliku i wyświetlającą odczytane dane na standardowym wyjściu, a więc kierując te dane do deskryptora o numerze \(1\) . Wypisywanie na ekranie dotyczy takiej liczby bajtów jak faktycznie udało się przeczytać.

while((n=read(fd, buf, 20)) > 0)
{
        write(1, buf, n);
}

lseek

Do zmiany pozycji wskaźnika odczytu-zapisu wykorzystujemu funkcję systemową lseek.

Definicja:

off_t lseek(int desp, off_t offset, int pozycja_poczatkowa);

Do programu należy dołączyć plik nagłówkowy <unistd.h>. Przykład kodu:

off_t pozycja;
int desp;
desp = open("plik.txt", O_RDONLY);
pozycja = lseek(desp, (off_t)+10, SEEK_SET);

Pozycja wskaźnika jest w tym przypadku 10 bajtem liczonym od początku pliku.

Argument [int pozycja_poczatkowa] może przybierać następujące wartości:

SEEK_SET - początek pliku

SEEK_CUR - bieżace położenie

SEEK_END - koniec pliku

Za pomocą funkcji lseek można w łatwy sposób sprawdzić wielkość pliku np.

int desp;
off_t w_pliku;
desp = open("plik", O_RDONLY);
w_pliku = lseek(desp, (off_t)0, SEEK_END);

Zadanie

Napisz program, który wypisuje na ekranie zawartość plików, których nazwy wskazano jako argumenty. Jeśli odczytanie pliku nie jest możliwe, należy wyświetlić odpowiedni błąd.

Przykłady

Tworzenie pliku:

#include <fcntl.h>
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>

int main (int argc, char* argv[])

{

        /* The path at which to create the new file.  */

        char* path = argv[1];

        /* The permissions for the new file.  */

        mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH;

        /* Create the file.  */

        int fd = open (path, O_WRONLY | O_EXCL | O_CREAT, mode);

        if (fd == -1) {

        /* An error occurred. Print an error message and bail.  */

                perror ("open");  #obsluguje i wypisuje błędy

                return 1;

        }

        return 0;

}

Zapisanie timestampa do pliku:

#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <time.h>
#include <unistd.h>

/* Return a character string representing the current date and time.  */
char* get_timestamp ()
{
        time_t now = time (NULL);
        return asctime (localtime (&now));
}

int main (int argc, char* argv[])
{

        /* The file to which to append the timestamp.  */
        char* filename = argv[1];

        /* Get the current timestamp.  */
        char* timestamp = get_timestamp ();

        /* Open the file for writing. If it exists, append to it;
        otherwise, create a new file.  */
        int fd = open (filename, O_WRONLY | O_CREAT | O_APPEND, 0666);

        /* Compute the length of the timestamp string.  */
        size_t length = strlen (timestamp);

        /* Write the timestamp to the file.  */
        write (fd, timestamp, length);

        /* All done.  */
        close (fd);
        return 0;

}

Tworzenie dużych plików za pomoca lseek (zapisz jako bigfile.c):

#include <fcntl.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>

int main (int argc, char* argv[])
{

        int zero = 0;
        const int megabyte = 1024 * 1024;

        char* filename = argv[1];
        size_t length = (size_t) atoi (argv[2]) * megabyte;

        /* Open a new file.  */
        int fd = open (filename, O_WRONLY | O_CREAT | O_EXCL, 0666);

        /* Jump to 1 byte short of where we want the file to end.  */
        lseek (fd, length - 1, SEEK_SET);

        /* Write a single 0 byte.  */
        write (fd, &zero, 1);

        /* All done.  */
        close (fd);

        return 0;
}

Uruchom:

gcc bigfile.c -o bigfile
./bigfile duzy 50
ls -l # sprawdź rozmiar pliku!!! podejrzyj jego zawartosc

Proste polecenia sieciowe

ifconfig

Karta sieciowa stanowi dla komputera interfejs fizyczny,łączący komputer z siecią; jest to punkt dostępu do sieci fizycznej. W przypadku karty sieci Ethernet mówi się o interfejsie ethernetowym. Z każdym takim interfejsem związany jest adres sprzętowy MAC. Z kolei interfejs logiczny jest punktem dostępu do sieci logicznej (tu sieci IP). Każdy interfejs logiczny posiada adres IP.

Polecenie ifconfig służy do konfigurowania interfejsu logicznego.

Składnia:

ifconfig eth<nr_interfejsu_ficzycznego>[:<nr_interfejsu_logicznego>] <adres_IP> netmask <maska>

Przykłady:

ifconfig #wyswietli informacje o sieci i aktualnie działających interfejsach
ifconfig -a #wyswietli informacje o wszystkich dostępnych interfejsach
ifconfig eth0 #wyswietli informacje o interfejscie eth0

ifconfig eth0 up  # uruchamianie interfejsu (tylko administrator moze to wykonac)
ifconfig eth0 down # wyłączanie interfejsu (tylko administrator moze to wykonac)

ifconfig wlan0 69.72.169.1 # nadawanie statycznego adresu IP (tylko administrator moze to wykonac)
ifconfig eth1 netmask 255.255.255.0 # nadawanie maski (tylko administrator moze to wykonac)

netstat

Netstat wyświetla połączenia sieciowe, tablice routingu, statystyki interfejsu, połączenia masquerade, komunikaty netlinkowe.

netstat -an

Przedstawi nam ona wszystkie aktywne w danym momencie połączenia z obcymi komputerami.

netstat #wyswietla aktualne połączenia
netstat -r #wyswietla tablice routingu
netstat -rn #wyswietla tablice routingu z adresami zapisanymi w formie liczowej
netstat -i #wyswietla tablice interfejsów
netstat -l #wyswietlanie nasłuchujących gniazd

Komenda netstat jest dostępna także dla w command line systemu windows.

ping

Wysyła komunikat ICMP ECHO_REQUEST do sieci adresata. Najczęściej wykorzystywany do sprawdzenia czy dany adres sieci jest dostępny z naszej lokalizacji i jaki czas zajmie przesłanie pakietu.

ping google.com
ping google.com -c 1 #tylko 1 sygnal przeslij
ping -i 5 google.com #sygnał co 5 sekund
ping -s 100 localhost #zmiana wielkośći pakietu
ping -s 100 google.com
ping -s 10000 google.com  #porównaj czasy
ping -w 5 localhost #policzy ilepakietów zostanie przesłanych w ciągu 5 sekund
ping -R 192.168.1.63 #pokazuje ścieżkę jaką przebył pakiet

Jaka jest maksymalna wielkość pakietu jaki możesz wysłać za pomoca ping ?

EXTRA

Spróbujmy czegoś innego, ściągnij i uruchom

http://www.staff.amu.edu.pl/~mw/zajecia/SOP2015/rand.c

w domu (jako administratow) możesz spróbować uruchomić też

http://www.staff.amu.edu.pl/~mw/zajecia/SOP2015/mouse.c

*

Wykorzystano materiały z:

http://www.computerhope.com/unix/unetstat.htm

https://bap.faculty.wmi.amu.edu.pl/index.php/dydaktyka/dsop/

http://www.sanfoundry.com/10-ping-command-usage-examples-linux/

http://wazniak.mimuw.edu.pl/index.php?title=%C5%9Arodowisko_programisty/Automatyzacja_kompilacji_-_make

http://students.mimuw.edu.pl/SO/Linux/Temat07/Linux716.html

http://www.thegeekstuff.com/2010/08/make-utility/

http://4programmers.net/C/Artyku%C5%82y/Jak_programowa%C4%87_w_Linuksie

http://students.mimuw.edu.pl/SO/Linux/Temat06/read.html