better !pout !cry better watchout lpr why santa claus town cat /etc/passwd >list ncheck list ncheck list cat list | grep naughty >nogiftlist cat list | grep nice >giftlist santa claus town who | grep sleeping who | grep awake who | egrep 'bad|good' for (goodness sake) { be good } /* Nadesłał: Jakub Pelczar, IS 2012 */
open(2)
, creat(2)
, read(2)
, write(2)
, stat(2)
, close(2)
, getenv(3)
, putenv(3)
, setenv(3)
oraz do zmiennych: errno(3)
, environ(7)
.Uwaga! przed korzystaniem z podręcznika można przełączyć go na język polski:
export LANG=pl_PL
lub angielski
export LANG=en_EN
Uwaga! sformułowanie typu ,,przeczytać w manualu opis command(x) oznacza, że należy wpisać:
man x command
np.: ,,przejrzeć podręcznik do funkcji creat(2)
:
man 2 creat
W systemie Unix dostęp do danych realizowany jest przez pliki. Dostęp procesów do samych plików jest realizowany przez deskryptory plików. Każdy proces ma pulę 20 deskryptorów (0-19), które mogą być przypisane do plików, potoków, itp. Deskryptory są używane we wszystkich funkcjach operujących na plikach. Deskryptor jest reprezentowany przez typ int
.
Proszę przejrzeć podręcznik do funkcji creat(2). Jak wywołuje się funkcję, co funkcja zwraca?
Funkcja creat() jest szczególnym przypadkiem open().
Proszę przejrzeć podręcznik do funkcji open(2). Jak wywołuje się funkcję, co funkcja zwraca?
Proszę przejrzeć podręcznik do funkcji read(2). Jak wywołuje się funkcję, co funkcja zwraca?
Proszę przejrzeć podręcznik do funkcji write(2). Jak wywołuje się funkcję, co funkcja zwraca?
Proszę przejrzeć podręcznik do funkcji close(2). Jak wywołuje się funkcję, co funkcja zwraca?
System udostępnia kilka funkcji oferujących zaawansowane operacje na plikach.
Do zarządzania prawami dostępu służą np.: chmod(2), chown(2).
Funkcje access(2), lseek(2), czy link(2) zwiększają możliwości operowania na plikach.
Proszę przejrzeć podręcznik do funkcji stat(2). Jak wywołuje się funkcję, co funkcja zwraca?
Katalogi implementowane są przez zwykłe pliki. Tym niemniej w systemie Unix występuje szereg funkcji upraszczających pracę z katalogami.
Proszę przejrzeć podręcznik do funkcji opendir(3), closedir(3), scandir(3). Jak wywołuje się te funkcje?
Proszę przejrzeć podręcznik environ(7).
Proszę przejrzeć podręcznik do funkcji getenv(3), putenv(3), setenv(3).
Proszę przejrzeć podręcznik do funkcji execve(2). Proszę przejrzeć podręcznik do grupy funkcji exec(3). Funkcje z tej grupy pozwalają na uruchamianie kodu nowego programu, w obrębie już istniejącego, bieżącego procesu. Jak wywołuje się funkcje? Czym się różnią?
Nie należy mylić działania tych funkcji z działaniem funkcji system(3), która uruchamia zewnętrzne polecenie.
Do tworzenia nowego procesu służy funkcja fork(). Tworzy ona proces potomny będący kopią procesu macierzystego, która dziedziczy jego środowisko pracy.
Proszę przejrzeć podręcznik do funkcji fork(2). Jak wywołuje się funkcję, co funkcja zwraca?
W ćwiczeniu będą wykorzystywane przygotowane programy.
Proszę oglądnąć poniższy program.
Program f1.c:
#include <stdio.h> #include <fcntl.h> #include <unistd.h> #define BUFSIZE 1024 int main (int argc, char **argv) { int f1, c; char b[BUFSIZE], *n1; c = 10; n1 = argv[1]; f1 = open (n1, O_RDONLY); read (f1, b, c); printf("%s: Przeczytano %d znaków z pliku %s: \"%s\"\n", argv[0], c, n1, b); close(f1); return(0); }
skompilować go:
gcc -Wall -ansi -pedantic f1.c -o f1
i uruchomić, podając jako argument stworzony wcześniej plik tekstowy.
Należy rozbudować program o:
Proszę oglądnąć poniższy program.
Program f2.c:
#include <stdio.h> #include <fcntl.h> #include <unistd.h> #include <sys/stat.h> #define BUFSIZE 1024 int main (int argc, char **argv) { int f1, f2, c; char b[BUFSIZE], *n1, *n2; c = 10; n1 = argv[1]; n2 = argv[2]; f1 = open (n1, O_RDONLY); read (f1, b, c); printf("%s: Przeczytano %d znaków z pliku %s: \"%s\"\n", argv[0], c, n1, b); f2 = open (n2, O_WRONLY | O_CREAT | O_TRUNC, 0600); write (f2, b, c); printf("%s: Zapisano %d znaków do pliku %s: \"%s\"\n", argv[0], c, n2, b); close(f1); close(f2); return(0); }
skompilować go:
gcc -Wall -ansi -pedantic f2.c -o f2
i uruchomić, podając jako argument stworzony wcześniej plik tekstowy i drugi plik, do którego zostaną przepisane dane.
Należy rozbudować program o:
Proszę oglądnąć, skompilować i uruchomić poniższy program.
Program d2.c:
#include <stdio.h> #include <string.h> #include <sys/types.h> #include <sys/stat.h> #include <sys/dir.h> #define MAX_CHAR 200 int main(int argc, char **argv) { int t; struct direct *e; DIR *d; struct stat s; char p[MAX_CHAR]; d = opendir(argv[1]); while ((e = readdir(d)) != 0) { printf("%d %s", (int)e->d_ino, e->d_name); if (strcmp(e->d_name, ".") != 0 && strcmp(e->d_name, "..") != 0) printf("\n"); else { p[0] = 0; strcat(p, argv[1]); strcat(p, "/"); strcat(p, e->d_name); t = stat(p, &s); if (S_ISDIR(s.st_mode)) printf("/"); printf("\n"); } } closedir(d); return 0; }
Jest to prymitywny program typu ls.
Należy rozbudować program o:
Proszę oglądnąć i uruchomić poniższy program:
Program p1.c:
#include <stdio.h> #include <unistd.h> extern char **environ; int main (int argc, char **argv, char **envp) { int i; printf("Srodowisko procesu:\n"); for (i = 0; envp[i] != NULL;i++) printf("%s\n", envp[i]); return(0); }
Proszę zmodyfikować program, aby pozwalał na wypisywanie i zmianę wartości wybranej zmiennej środowiskowej.
Proszę oglądnąć i uruchomić poniższy program:
Program p2.c:
#include <stdio.h> #include <unistd.h> #include <stdlib.h> extern char **environ; int main (int argc, char **argv, char **envp) { printf("Poczatek procesu.\n"); system("echo ala ma kota"); printf("Dalszy ciag kodu...\n"); execl("/bin/echo", "echo", "jakis napis", NULL); printf("Koniec kodu...\n"); return(0); }
Jaka jest różnica pomiędzy funkcjami system() a exec()?
Proszę zmodyfikować program tak, aby działał tak samo przy użyciu innych wywołań z rodziny funkcji exec().
Proszę oglądnąć i uruchomić poniższy program.
Program p3.c:
#include <stdio.h> #include <unistd.h> extern char **environ; int main (int argc, char **argv, char **envp) { int p=0; printf("Poczatek procesu...\n"); p = fork(); printf("Tu jestem: %d\n", p); return(0); }
Jak działa program? Dlaczego?
Dla lepszego zrozumienia proszę oglądnąć i uruchomić kolejny program.
Program p4.c:
#include <stdio.h> #include <unistd.h> #include <stdlib.h> extern char **environ; int main (int argc, char **argv, char **envp) { int p=0; printf("%s[%d]: Poczatek procesu glownego...\n", *argv, getpid()); p = fork(); if (p == -1) printf("%s[%d]: BLAD! Nie moge stworzyc procesu!\n", *argv, getpid()); else if ( p > 0) { printf("%s[%d]: To dalej ja, proces glowny...\n", *argv, getpid()); sleep(5); } else if ( p == 0 ) { printf("%s[%d]: Jestem procesem potomnym, moj rodzic to: [%d]...\n", *argv, getpid(), getppid()); exit (0); } printf("%s[%d]: Koniec procesu glownego...\n", *argv, getpid()); exit (0); return(0); }
Proszę otoczyć komentarzem wywołanie funkcji sleep(), jak to wpłynie na działanie procesów?
Proszę oglądnąć i uruchomić poniższy program.
Program p5.c:
#include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <sys/wait.h> extern char **environ; int main (int argc, char **argv, char **envp) { int p=0,p1=0; printf("%s[%d]: Poczatek procesu glownego...\n", *argv, getpid()); p = fork(); if (p == -1) printf("%s[%d]: BLAD! Nie moge stworzyc procesu!\n", *argv, getpid()); else if ( p > 0) { printf("%s[%d]: To dalej ja, proces glowny...\n", *argv, getpid()); } else if ( p == 0 ) { printf("%s[%d]: Jestem procesem potomnym, moj rodzic to: [%d]...\n", *argv, getpid(), getppid()); sleep(5); printf("%s[%d]: Koncze ze soba!\n", *argv, getpid()); exit (0); } p1=wait(NULL); printf("%s[%d]: Jestem bezdzietny, nie ma juz: %d :(\n", *argv, getpid(), p1); printf("%s[%d]: Koniec procesu glownego.\n", *argv, getpid()); exit (0); return(0); }
Procesy macierzyste mogą czekać na zakończenie potomnych.
Proszę rozbudować powyższy program, wg. własnej inwencji.
Proszę oglądnąć i uruchomić poniższy program.
Program p6.c:
#include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <sys/wait.h> extern char **environ; int main (int argc, char **argv, char **envp) { int p=0,p1=0; printf("%s[%d]: Poczatek procesu glownego...\n", *argv, getpid()); p = fork(); if (p == -1) printf("%s[%d]: BLAD! Nie moge stworzyc procesu!\n", *argv, getpid()); else if ( p > 0) { printf("%s[%d]: To dalej ja, proces glowny...\n", *argv, getpid()); } else if ( p == 0 ) { printf("%s[%d]: Jestem procesem potomnym, moj rodzic to: [%d]...\n", *argv, getpid(), getppid()); printf("%s[%d]: Moge byc kims innym!\n", *argv, getpid()); execl("/bin/echo", "echo", "moge stac sie programem ktory cos pisze!", NULL); } p1=wait(NULL); printf("%s[%d]: Jestem bezdzietny, nie ma juz: %d :(\n", *argv, getpid(), p1); printf("%s[%d]: Koniec procesu glownego.\n", *argv, getpid()); exit (0); return(0); }
Proszę oglądnąć i uruchomić poniższy program.
Program p7.c:
#include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <sys/wait.h> #include <fcntl.h> #include <sys/stat.h> #define BUFSIZE 1024 #define CPC 5 #define NC 5 extern char **environ; int main (int argc, char **argv, char **envp) { int p=0, p1=0, f, n=5, c, i, j; char *b, *n1; c = NC; n1 = argv[1]; printf("%s[%d]: Poczatek procesu glownego...\n", *argv, getpid()); f = open (n1, O_RDONLY); for (i=0; i<n; i++) { p = fork(); if (p == -1) printf("%s[%d]: BLAD! Nie moge stworzyc procesu!\n", *argv, getpid()); else if ( p > 0) { printf("%s[%d]: To dalej ja, proces glowny...\n", *argv, getpid()); } else if ( p == 0 ) { printf("%s[%d]: Jestem procesem potomnym, moj rodzic to: [%d]...\n", *argv, getpid(), getppid()); sleep(1); lseek(f, i*CPC, SEEK_SET); b = malloc(sizeof(char)*c+1); j = read (f, b, c); b[c+1]='\n'; printf("%s: Przeczytano %d znaków, poczynajac od: %d, z pliku %s: \"%s\"\n", argv[0], j, i*CPC, n1, b); free(b); exit(0); } } p1=wait(NULL); printf("%s[%d]: Jestem bezdzietny, ostatnie dziecko to: %d :(\n", *argv, getpid(), p1); close(f); printf("%s[%d]: Koniec procesu glownego.\n", *argv, getpid()); exit (0); return(0); }
Ważna obserwacja: proces potomny dziedziczy środowisko, wraz z kopiami deskryptorów plików.
Proszę przeanalizować i zmodyfikować powyższy program, np. tak, aby czytał inne fragmenty pliku, lub wykonywał równolegle inne operacje.
Ważne, przydatne książki: