Nah, o trecut și-ăsta.

Subiect: Să se creeze un server și un client care vor comunica printr-un pipe. Clientul va trimite la server un nume de director, iar serverul îi va răspunde cu numărul de fișiere cu extensia „.txt” din directorul dat sau cu -1 dacă numele trimis de client nu este un director. Se va folosi o comanda shell/script shell. Serverul va rămâne deschis, așteptând cererile clienților.

Barem: - 1p - of - 1p - creare (conectare) canal de comunicare - 1p - comunicare client - server - 1p - construire comanda externa - 1p - executia comenzii externe - 1p - citirea rezul­tat­u­lui comenzii - 0.5p - client trimite de n ori (se va specifica - ex: de 10 ori) - 0.5p - serverul ruleaza la infinit - 1p - serverul trimite rezultatul clientului - 2p - clean up

Yay. Am lucrat prima oară prin SSH :>:> shmenos cu doi de shm. Dar a fost funny că trebuia să mă loghez cu userul meu pe Windows, apoi prin Putty să mă conectez cu userul meu la serverul de Linux și apoi prin ssh să mă conectez la serverul de examen, cu uti­liza­torul de examen, care avea un singur fișier subiectul.

Dacă îi cerere mare pentru rezolvare, o voi posta și pe aia.

Pentru că a fost mare cererea pentru rezolvare, here it is:

Vom folosi un fișier shell care va verifica dacă am dat un director sau nu și în caz afirmativ să returnăm numărul de fișiere .txt:

\#!/bin/sh
if [ ! -d $1 ]
then echo "-1"
exit 1
fi
echo \`find $1 -maxdepth 1 -iname '\*.txt' | wc - l\`

Fișierul C care face restul este:

#include
#include
#include
#include

int main() {
int pipefp[2],pipepf[2];
if(pipe(pipepf)==-1) {
printf("S-a intamplat o eroare");
return 1;
}
if(pipe(pipefp)==-1) {
printf("S-a intamplat o eroare");
return 1;
}
int count = 3;
while (count > 0) {
int pid = fork();
if (pid==-1) {
printf("Nu s-a putut face forkul");
return 1;
}
if (pid==0) {
//client
//printf("Child");
char fisier[30];
printf("Dati numele folderului: :");
scanf("%s",fisier);
//printf("copil: %s %d n",fisier,strlen(fisier));
int nr =write(pipefp[1],fisier,strlen(fisier));
//printf("write a scris %d n",nr);
char raspuns[4];
read(pipepf[0],raspuns,4);
printf("Child: Serverul a raspuns: %s n",raspuns);
//printf("Fiu out");
return 0;
}
else {
//server
//printf("Parinte n");
char director[30] = "";
int re= read(pipefp[0],director,30);
//printf("Copilul a trimis %s %d n",director,re);
char comanda[40] = "./shell.sh ";
strcat(comanda,director);
//printf("parinte comanda %s n",comanda);
FILE\* proc = popen(comanda,"r");
char rez[4];
fgets(rez,3,proc);
//printf("Rezultat server: %s n",rez);
write(pipepf[1],rez,4);
//printf("Iteratie server %s n",rez);
}
count--;
}
close(pipefp[0]);
close(pipepf[1]);
close(pipefp[1]);
close(pipepf[0]);
return 0;
}

Nu merge de o infinitate de ori serverul, dar asta nu se poate realiza în mod practic la pipe și FIFO, doar la coadă de mesaje și memorie partajată. Nelămuriri, corecții, în commenturi.

Am pus mâna pe ceva probleme cu shell de anul trecut de la SO și le-am rezolvat. Și pentru că știu că sunteți disperați de subiecte și rezolvări, here they are:

1. Se da un fisier care contine pe fiecare linie cate un nume de utilizator si un numar de conectari. Sa se scrie un program shell de supraveg­here a conec­tar­ilor userilor din fisier:la fiecare conectare noua, programul va mari cu o unitate numarul de conectari ale userului in fisierul dat.

Rezolvare:

Fiind prima problemă, se rezolvă super simplu:

#!/bin/sh
while true
do
while read user count
do
#schimbam separatorul de campuri, si il salvam in OIFS ca sa il putem
restora mai incolo
OIFS=$IFS
IFS="
"
#obtinem lista userilor. Mergem cu for pentru ca un user poate fi
logat de mai multe ori
for lista in \`who | grep $user\`
do
# obtinem data din coloanele 3 si 4 si o transformam in Unix
timestamp
data=\`echo $lista | awk '{ print $3 " " $4}' \`
timestamp1=\`date -d $data +%s\`
timestamp2=\`date +%s\`
#calculam diferenta in timp intre logarea utilizatorului si acuma
folosind doua timpestampuri
dif=\`expr $timestamp2 - $timestamp1\`
#daca e cat ne trebuie noua sa fie, cu sed modificam linia respectiva
si scriem modificarile intr-un fisier temporar
if [ $dif -le 10000 ]
then
inc=\`expr $count + 1\`
sed s/"$user $count"/"$user $inc"/ \< fisieruseri.txt \>tmp.txt
fi
done
IFS=$OIFS
done \< fisieruseri.txt
#dupa ce am parcurs odata fisierul, il schimbam cu cel temporar
mv tmp.txt fisieruseri.txt
sleep 5
done

2. Pentru un director dat ca parametru sa se numere cate dintre di­rec­toarele sau fisierele din el au drepturi pe care directoul curent nu le are.

Rezolvare:

#!/bin/sh
cur=`pwd`
i=0
for chestie in `find $1 -print`
do
# citit in man ce face stat
if [ `stat -t --format=%a $chestie` -ne `stat -t --format=%a
$cur` ]
then
i=`expr $i + 1`
fi
done
echo $i

3. Sa se determine sub­di­rec­toarele, indiferent de adancime, dintr-un director dat ca parametru care contin un fisier ce ocupa mai mult de jumatate din di­men­si­unea sub­di­rec­toru­lui respectiv.

#!/bin/sh
if [ ! -d $1 ]
then
echo $1 "nu este director"
exit 1
fi
for director in \`find $1 -type d\`
do
# citit man ce face du
marime=\`du -sk $director | cut -f 1\`
marime=\`expr marime / 2\`
# cautam in director fisiere mai mari decat jumate din marimea
directorului si daca find returneaza ceva, afisam directorul
fisier=\`find $director -maxdepth 1 -size +$marime -type f\`
if [ ${#fisier} -gt 0 ]
then
echo $director
fi
done

4. Se cere un script shell care primeste ca argumente 2 nume de fisiere, si oricate cuvinte separate prin spatii. Scriptul va scrie in primul fisier cuvintele care contin vocale, iar in al doilea cuvintele care nu contin vocale.

#!/bin/sh
voc=$1
novoc=$2
shift 2
#am salvat cele doua fisiere, am mutat lista parametrilor spre stanga
si iteram peste ele
for cuvant in "$@"
do
vocala=`echo "$cuvant" | grep "[aeiou]"`
if [ ${#vocala} -gt 0 ]
then
echo $cuvant >>$voc
else
echo $cuvant >>$novoc
fi
done

5. Un program care sa caute printre useri cei care au folderul pub­lic_html in direcotrul lor. (in­for­matille despre numele userilor si directorul fiecaruia le luai din fiserutl etc/passwd in care erau linii de forma user:x:...:homedir:...).

#!/bin/sh
# redirectam fisierul spre cut, cu care extragem campul al saselea,
considerand ca delimitator :
for folder in \`cat /etc/passwd | cut -f6 -d:\`
do
if [ -r $folder ]
then
find $folder -name "public_html"
fi
done

Atenție, să rulați scriptul redi­rec­tând std_err spre /dev/null/, pentru că în /etc/passwd sunt mulți „useri” la al căror folder nu ai drept de citire.

6. Sa se in­tocmeas­ca topul primilor 20 de uti­liza­tori dupa di­men­si­unea spatiului ocupat in directorul $HOME.Primilor 10 sa li se transmita mail de avertizare.Uti­liza­torii sunt scrisi in fisierul /etc/passwd sub forma (era ceva model de linie din fisier).

#!/bin/sh
rez=""
#similar cu problema anterioara, doar ca salvam si numele de
utilizator
for info in \`cat /etc/passwd | cut -f1,6 -d:\`
do
folder=\`echo $info | awk -F : '{ print $2 }'\`
size=\`du -sk $folder\`
if [ ${\#size} -gt 0 ]
then
#facem o lista care contine marime, folder si nume user pe fiecare
linie
rez=$rez'n'\`du -sk $folder\`" "\`echo $info | awk -F : '{ print $1
}'\`
fi
done
echo $rez | sort -nr | head -n20
for user in \`echo $rez | sort -nr | head -n10 | awk '{print $3 }'\`
do
echo "Vezi ca ocupi prea mult spatiu pe lume" | mail -s "Spacehogs"
$user
done

Spor la făcut fițuica!

Problemele acestea le-am rezolvat ieri, dar nu am mai apucat să le postez, pentru că îmi scriam fițuica.

1. Sa se scrie un program care cauta in n fisiere text,ale caror nume sunt date ca argumente in linia de comanda,liniile care contin stringul "Cautare".Pentru fiecare fisier se va creea un proces separat, care va afisa numarul de linii in care apare stringul.

#include
#include
#include <sys/types.h>
#include
int main(int argc, char\* argv[]) {
int i,pid;
for (i=1; i<argc;i++) {
pid = fork();
if (pid < 0) {
printf("error");
return 1;
}
if (pid==0) {
break;
}
}
int number =0;
if (pid==0) {
FILE\* fisier = fopen(argv[i],"r");
if (fisier < 0) {
printf("Error");
}
char linie[100];
while ( fgets(linie,100,fisier) != 0) {
if (strstr(linie,"Cautare") != 0){
number+=1;
}
}
printf("Procesul %d a gasit de %d ori Cautare in fisierul %s
n",getpid(),number,argv[i]);
}
return 0;
}

2. Sa se scrie 2 programe care comunica prin memorie partajata. La intervale aleatoare de timp, primul program citeste cate o linie de la intrarea lui standard si trimite celuilalt continutul acestei linii impreuna cu un semnal. La re­cep­tionarea mesajului, al doilea program ia linia din memoria partajata, elimina cifrele din ea si o tipareste pe iesirea lui standard.

Aici avem două fișiere, unul client:

#include
#include
#include
#include
#include
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>

int main() {
int shmid = shmget((key_t) 11180,1024,0644);
if (shmid == -1 ) {
perror("eroare shmget");
return 1;
}
struct shmid_ds shmid_ds,\*info;
info = &shmid_ds;
if (shmctl(shmid,IPC_STAT,info) == -1 ) {
perror("eroare shmctl ");
return 1;
}
char\* data = shmat(shmid,(void \*)0,0);
if (data == (char \*)(-1)) {
printf("Eroare shmat");
return 1;
}
int oPid;
oPid = info-\>shm_cpid;
printf("Pidul creator este %d, pidul meu este %d, shmid este %d
n",oPid,getpid(),shmid);
char linie[100];
int i=0;
while (i<3) {
printf("Dati o linie: ");
gets(data);
printf("Ati dat: %s",data);
kill(oPid,SIGUSR1);
int rand = 1;
//rand = rand();
sleep(rand);
i++;
}
shmdt(data);
}

Și server:

#include
#include
#include
#include
#include
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include
//asa trebuie declarate variabilele ca sa le poti modifica din handler
volatile sig_atomic_t got_usr1;
void semnal_handler(int sig) {
write(1,"Handler apelat n",40);
got_usr1 =1;
}

int main() {
int shmid = shmget((key_t) 11180,1024,0644|IPC_CREAT);
if (shmid == -1) {
perror("eroare shmget");
return 1;
}
char\* data = shmat(shmid,(void \*)0, 0);
if (data == (char \*)(-1)) {
perror("Eroare shmat");
return 1;
}
signal(SIGUSR1,semnal_handler);
while(1==1) {
if (got_usr1) {
printf("server: %s n",data);
int i=0, j=0;
char rez[100];
for (i; i\< strlen(data)+1; i++) {
while (data[i] == '0' || data[i] == '1' ||
data[i] == '2' || data[i] == '3' ||
data[i] == '4' || data[i] == '5' ||
data[i] == '6' || data[i] == '7' ||
data[i] == '8' || data[i] == '9')
i++;
rez[j]=data[i];
j++;
}
got_usr1=0;
printf("server: %s n",rez);
}
sleep(1);
}
shmdt(data);
printf("server closing %dn",shmid);
shmctl(shmid,IPC_RMID,NULL);
}

3. Sa se scrie o pereche de programe care comunica prin coada de mesaje. Primul program citeste, la intervale aleatoare de timp, linii de la intrarea lui standard. Liniile cu lungimea intre 20 si 30 de octeti vor fi depuse in coada. Al doilea program citeste liniile din coada si le afiseaza la iesirea standard doar pe cele care incep cu o litara.

Și aici avem două fișiere: c.c

#include <sys/msg.h>
#include
#include
struct msgbuff {
long type;
char string[30];

};

int main() {
int msgid = msgget((key_t) 11180, 0666|IPC_CREAT);
char linie[30];
int i=5;
struct msgbuff msg;
msg.type = 1;
while (i--) {
printf("Dati o linie:");
scanf("%s",linie);
strcpy(msg.string,linie);
msgsnd(msgid, &msg,strlen(linie),0);
int rand =1;//rand=rand();
sleep(rand);
}

}

Și s.c

#include <sys/msg.h>

struct msgbuff {
long type;
char string[30];

};

int main() {
int msgid = msgget((key_t) 11180, 0666);
char linie[30];
int i=5;
struct msgbuff msg;
while (i--) {
printf("Servern");
if (msgrcv(msgid, &msg,30,1,0) == -1 ) {
perror("Msgrcv");
return 1;
}
if ((msg.string[0] \>= 97 && msg.string[0] \<= 122) ||
(msg.string[0] \>= 65 && msg.string[0] \<=97 ))
printf("server: %s n",msg.string);
else
printf("Nu incepe cu litera");
}

}

Reușește cineva să le înghesuie și pe ăstea pe fițuică?

Well, slavă Domnului, am știut la examen și nu am primit semafoare.

Second, omg, fițuica mea îi o nimica toată pe lângă ce au realizat unii... Sorina, Robi (care și-o făcut color-coded) etc.

  1. Comanda     test
  2. Expresii regulare
  3. Legături Unix și conceptul de     montare
  4. Problema 1     Shell
  5. Problema 1 C

Acuma, să încep să învăț ModelView...

Edit: Notele se trimit pe mail. Unii le-ai primit deja așa că verificați-vă mailul la vreo 2-3 ore după ce ați dat examenul!

Edit2: De asemenea, problemele pe care le-am rezolvat eu sunt cele de anul trecut de pe grupul 217. Trageți voi con­cluzi­ile :))

1. Memorie partajată.

2. Contextul unui proces și trans­for­mările lui prin fork și exec.

3. Blocarea de fișiere

4. Să se scrie un script shell care se elimine dintr-un fisier toate cuvintele care contin caracterul . cel putin o data.

5. Un pipe in care clientul trimitea o extensie de fisier iar serverul intorcea lista fisierelor din directorul curent ca extensia respectiva.

Thanks Kinga!

1. Apeluri sistem de lucru cu procese: fork,exit,wait,waitpid 2. Structuri de control al­ter­na­tive: if, case 3. Paradigma client/server. clasi­fi­cari ale serverelor 4. Shell: Să se scrie un script care sa afiseze primii 10 useri cu cele mai multe procese deschise. 5. C: Să se creeze un client și server care comunică prin cozi de mesaje. Serverul scrie in coada de mesaje 10 mesaje. Clientul citeste mesajele si le afiseaza doar mesajele care au tipul: 2, 7, 38 si 44.

Thanks Andreea!

Bilet 5: 1. Comunicare procese prin memorie partajată 2. Contextul unui proces și trans­for­marea lui prin fork și exec 3. Blocarea fișierelor în Unix 4. Shell: Se dă un fișier ce conține mai multe lini, fiecare linie conține mai multe cuvinte separate prin spatii. Să se elimine liniile care conțin cuvinte cu unul sau mai multe caractere „.”. 5. C: Să se scrie un client și un server care comunică prin FIFO. Clientul trimite o terminație de nume de fișier, iar serverul întoarce lista de fișiere care se potrivesc din directorul curent.

Thanks Răzvan!

Bilet 11

1. Tratarea liniei de comanda de shell; variabile pre­def­i­nite shell 2. Filtre sub UNIX; exemple de filtre 3. Accesul la ar­gu­mentele liniei de comanda

4. Scrieti un program shell care pentru fiecare sursa C din folderul curent, numara cate #define-uri sunt si pentru fiecare define, spune de cate ori a fost apelat macro-ul definit in sursa.

5. 2 programe in C care lucreaza cu memorie partajata. Primul citeste linii de la STDIN la intervale random, si cate 10 astfel de linii pe segment. Al 2-lea citeste de pe segment liniile, si le afiseaza la STDOUT.

Bilet 9

A9. Variabile shell: definire, moduri de obþinere a valorii unei variabile B9. Structura superioară de directoare a sistemului de fișiere Unix C9. Co­mu­ni­carea prin pipe între procese Unix

S9. Se cere un script shell care primeste ca argumente 2 nume de fisiere, si oricate cuvinte separate prin spatii. Scriptul va scrie in primul fisier cuvintele care contin vocale, iar in al doilea cuvintele care nu contin vocale.

P9. Sa se scrie o pereche de programe care comunica prin coada de mesaje. Primul program citeste, la intervale aleatoare de timp, linii de la intrarea lui standard. Liniile cu lungimea intre 20 si 30 de octeti vor fi depuse in coada. Al doilea program citeste liniile din coada si le afiseaza la iesirea standard doar pe cele care incep cu o litara.

Bilet 7 1) Conceptul de comanda Unix; fisiere standard, argumente si valori asociate 2) Lucrul cu procese Unix: functiile exec, system, popen 3) Legatura intre procese si fisiere sub Unix 4) Sa se determine sub­di­rec­toarele , indiferent de adancime , dintr-un director dat ca parametru care contin un fisier ce ocupa mai mult de jumatate din di­men­si­unea sub­di­rec­toru­lui respectiv . 5) Sa se scrie 2 programe : cient si server . Serverul creeaza un segment de memorie partajata de 50 de octeti in care pune valoarea 0 . Apoi , la intervale aleatoare de timp pune pe rand in cei 50 de octeti caracterul 'A' , apoi 'B' , ... , 'Z', 'A' , ... . Clientul acceseaza la 10 secunde zona si afiseaza la iesirea standard continutul ei.

Bilet 3 1) Comunicare prin FIFO intre procese Unix 2) Imaginea in memorie a unui proces Unix; continutul con­tex­tu­lui unui proces 3) Compilarea pro­gramelor C; utilizarea make sub Unix 4) Pentru un director dat ca parametru sa se numere cate dintre di­rec­toarele sau fisierele din el au drepturi pe care directoul curent nu le are. 5) Sa se scrie 2 programe care comunica prin memorie partajata. La intervale aleatoare de timp, primul program citeste cate o linie de la intrarea lui standard si trimite celuilalt continutul acestei linii impreuna cu un semnal. La re­cep­tionarea mesajului, al doilea program ia linia din memoria partajata, elimina cifrele din ea si o tipareste pe iesirea lui standard.

Muchos gracias to Gogoașă