Documente Academic
Documente Profesional
Documente Cultură
Crearea unei aplicatii care sa execute CAT MAI RAPID si EFICIENT criptarea unui fisier folosind un algoritm propriu
organizat conform schemei de mai jos. Continutul fisierului va fi criptat pe blocuri
Input file
Operation
1
Output file
Temp
file
Operation
2
Pentru masurarea timpilor de executie, se poate utiliza comanda time pentru executia aplicatiei.
$time encrypt input.txt
sau
$/usr/bin/time encrypt input.txt
PROCESE
Un concept cheie în orice sistem de operare este procesul. Un proces este un program în
execuţie(instanţa execuţiei unui program de pe disc). Procesele sunt unitatea primitivă prin care sistemul de
operare alocă resurse utilizatorilor. Orice proces are un spaţiu de adrese şi unul sau mai multe fire de execuţie
(thread-uri). Putem avea mai multe procese ce execută acelaşi program, dar oricare două procese sunt complet
independente.
Procesele sunt organizate în Unix într-o structură arborescentă asemenea organizării sistemului de
fişiere. Toate procesele active sunt de fapt descendenţi direcţi sau indirecţi ai unui singur proces, lansat la
pornirea sistemului prin comanda /etc/init. Comanda pstree permite vizualizarea arborelui curent de procese.
Identificarea proceselor
Fiecare proces are asociat un identificator unic numit identicator de proces(PID). Un proces poate să
determine propriul PID folosind apelul sistem getpid().
PID-ul unui proces nu poate fi schimbat, dar poate fi refolosit când procesul nu mai există.
Procesele sunt organizate în Unix într-o structură arborescentă asemenea organizării sistemului de
fişiere. Orice proces nou în Unix este creat de un proces anterior existent, dând naştere unei relaţii părinte-fiu.
Excepţie face procesul init, care este creat si utilizat chiar de nucleu, toate celelalte procese din sistem fiind
descendenţi direcţi sau indirecţi.
Comanda pstree permite vizualizarea arborelui curent de procese.
Unproces poate sa determine PID-ul părintelui prin apelul getppid().
Sistemul UNIX ţine evidenţa proceselor într-o structură de date internă numită tabelă de procese. Lista
proceselor din tabela de procese poate fi obţinută prin comanda ps.
Un proces poate fi asociat unui terminal, care este numit terminalul de control asociat procesului.
Acesta este moştenit de la procesul părinte la creare.
Un proces care nu este asociat cu un terminal de control este numit daemon. Spoolerul de imprimantă
este un exemplu de astfel de proces. Un proces daemon este identificat în rezultatul afişării comenzii ps prin
simbolul ? plasat în coloana TTY.
Process Control Block structură în sistemul de operare în care se regăsesc informaţii necesare pentru
rularea programului, câte una pentru fiecare proces existent în sistem:
- spaţiile de adrese şi regiştrii generali
- PC (contor program) şi SP (indicator stivă)
- tabelele de fişiere deschise (descriptori de fişiere)
- lista de semnale (blocate, ignorate sau care aşteaptă să fie trimise procesului)
- handler-ele pentru semnale
- informaţiile referitoare la sistemele de fişiere (directorul rădăcina, directorul curent)
În general un proces rulează într-un mediu specificat printr-un set de variabile de sistem. O variabilă de
sistem este o pereche NUME=valoare. Un proces poate să verifice sau să seteze valoarea unei variabile de
sistem printr-o serie de apeluri de bibliotecă.
În momentul lansării în execuţie a unui program, în sistemul de operare se va crea un proces pentru
alocarea resurselor necesare rulării programului respectiv.
Fiecare sistem de operare pune la dispoziţie apeluri de sistem pentru:
- crearea
- terminarea
- aşteptarea terminării unui proces
- duplicarea descriptorilor de resurse între procese ori închiderea acestor descriptori.
Apelurile de sistem puse la dispoziţie de Linux pentru gestionarea proceselor sunt:
- fork() şi exec() pentru crearea unui proces şi respectiv modificarea imaginii unui proces
- wait() şi waitpid() pentru aşteptarea terminării unui proces
- exit() pentru terminarea unui proces.
- dup() şi dup2() pentru copierea descriptorilor de fişier
- getenv(), setenv(), unsetenv() pentru citirea, modificarea ori ştergerea unei variabile de sistem
precum şi un pointer la tabela de variabile de sistem - environ.
Procesul părinte poate să aştepte terminarea (normala sau cu eroare) procesului copil folosind apelurile
sistem wait sau waitpid(wait3, wait4).
pid_t wait(int *status);
pid_t waitpid(pid_t pid, int *status, int options);
Apelul wait() este folosit pentru asteptarea terminarii executiei copilului si preluarea valorii returnate
de acesta. Parametrul status este folosit pentru evaluarea valorii returnate, folosind cateva macro-uri definite
special. Apelul waitpid() este asemanator cu wait(), dar aşteaptă terminarea unui anumit proces dat, in vreme
ce wait() aşteaptă terminarea oricărui proces copil.
Familia de apeluri wait suspendă execuţia procesului apelant până când procesul (procesele)
specificate în argumente fie s-au terminat fie au fost oprite (SIGSTOP).
Valorile uzuale ale argumentului pid sunt identificatorul unui proces copil (spre exemplu, returnat de
fork) sau -1, în cazul în care se doreşte aşteptarea oricărui proces copil.
Funcţia va întoarce PID-ul procesului a cărui stare e raportată; informaţiile de stare sunt depuse ca int la
adresa indicata prin argumentul status.
Options oferă posibilitatea procesului apelant de a se întoarce din apelul waitpid, fără a rămâne blocat
în aşteptarea unui proces copil (WNOHANG, WUNTRACED,WCONTINUED – studiaţi man page)
Exista o variantă simplificată care aşteaptă orice proces copil să se termine:
pid_t wait(int *status); care este echivalentă cu waitpid(-1, &status, 0);
Pentru a folosi wait sau waitpid trebuie incluse header-ele sys/types.h şi sys/wait.h.
Pentru a analiza starea în care s-a terminat un proces copil (normal sau eroare) există trei macrouri
excluse mutual, toate prefixate de WIF şi definite în fişierul sys/wait.h. Pelângă acestea, exista alte macrouri
pentru determinarea codului de exit, număr semnal, etc (studiaţi man page).
Aceste macrouri se aplica parametrului pstatusşi sunt ilustrate mai jos:
a) WIFEXITED (pstatus) – TRUE daca informaţia de stare, pstatus, provine de la un proces terminat
normal(apel exit sau return) - în acest caz, WEXITSTATUS(pstatus) extrage octetul mai puţin semnificativ pentru
a determina codul de exit al procesuluiterminat.
Completaţi exemplul anterior cu secvenţa de cod de mai jos:
pid_copil=wait(&status);
if(WIFEXITED(status))
printf("%d terminat normal cu codul %d\n",pid_copil,WEXITSTATUS(status)); //adăugaţi în procesul părinte
b) WIFSIGNALED (pstatus) – TRUE daca informaţia de stare, pstatus, provine de la un proces terminat
anormal (semnal netratat) - în acest caz WTERMSIG (pstatus) extrage numărul semnalului trimis procesului
terminat.
while(1){} //în procesul copil
>ps –ef
>kill –SIGUSR1 pid_copil //în terminal
if(WIFSIGNALED(status))
printf("%d terminat cu semnalul %d\n",pidex,WTERMSIG(status)); //în părinte
c) WIFSTOPPED (pstatus) – TRUE daca informaţia de stare, pstatus, provine de la un proces temporar
oprit - în acest caz WSTOPSIG (pstatus) extrage numărul semnalului care a oprit procesul.
while(1){} //în procesul copil
-------------------------------------
sleep(2);
kill(pid,SIGTSTP);
sleep(2);
pidex=waitpid(-1,&status,WUNTRACED);
if(WIFSTOPPED(status))
printf("%d oprit temporar cu semnalul %d\n",pidex,WSTOPSIG(status)); //în părinte
Procesul apelant se va termina imediat. Toţi descriptorii de fişier ai procesului sunt închişi, copiii
procesului sunt "înfiaţi" de init, iar părintelui procesului îi va fi trimis un semnal SIGCHLD. Procesului părinte îi
va fi întoarsă valoarea status ca rezultat al unei funcţii de aşteptare (wait sau waitpid).
Pentru terminarea unui alt proces din sistem, se va trimite un semnal către procesul respectiv prin
intermediul apelului de sistem kill. Mai multe detalii despre kill şi semnale în laboratorul de semnale.
FORK - waiting
int main()
{
int pid,pidex;
int status;
printf("\nbefore if -> PID=%d PPID=%d\n",getpid(),getppid());
if ((pid = fork()) < 0) {
printf("EROARE!!!");
} else if (pid == 0) {
printf("if -> fiu? ->PID=%d PPID=%d\n",getpid(),getppid());
while(1){}
} else {
printf("if -> parinte? ->PID=%d PPID=%d\n",getpid(),getppid());
//sleep(2);
//kill(pid,SIGTERM);
//sleep(2);
pidex=waitpid(-1,&status,WUNTRACED);
printf("--------\n");
if(WIFEXITED(status))
printf("%d terminat normal cu codul %d\n",pidex,WEXITSTATUS(status));
if(WIFSIGNALED(status))
printf("%d terminat cu semnalul %d\n",pidex,WTERMSIG(status));
if(WIFSTOPPED(status))
printf("%d oprit temporar cu semnalul %d\n",pidex,WSTOPSIG(status));
}
printf("after if -> ? ->PID=%d PPID=%d\n",getpid(),getppid());
return 0;
}
Familia de funcţii exec va executa un nou program, înlocuind imaginea procesului curent, cu cea dintr-
un fişier (executabil). Spaţiul de adrese al procesului va fi înlocuit cu unul nou, creat special pentru execuţia
fişierului. De asemenea vor fi reiniţializaţi regiştrii IP (EIP/RIP - contorul program) şi SP (ESP/RSP – indicatorul
stivă) şi regiştrii generali.
Presupunem că vrem să apelăm comanda ls -la: execl("ls", "ls", "-la", NULL);
Se observă că primul argument este însuşi numele programului, iar ultimul este NULL. execl nu caută
programul dat ca parametru în PATH, astfel că acesta trebuie însoţit de calea completă.
Versiunea execlp cauta programul şi în PATH.
Folosirea oricărei funcţii din familia exec necesită includerea header-ului unistd.h.
Moştenirea resurselor
Apelul sistem fork realizează o copie a procesului iniţial, ca atare imaginea proceselor în memorie este
identică. Noul proces va avea propria lui zonă de date, propria lui stivă, propriul lui cod executabil, toate fiind
copiate de la părinte. Orice modificare făcută, prin urmare, asupra unei variabile din procesul fiu, va rămâne
invizibilă procesului părinte şi invers.
Moştenirea(duplicarea) segmentului de cod Moştenirea(duplicarea) segmentului de date
int main()
{
int c=2,status,pid=1;
while(c){
if(pid==1)
pid=fork();
if(pid>0){ if(pid>0){
wait(&status); wait(&status);
printf("parent %d done\n",getpid()); printf("parent %d done - c=%d\n",getpid(),c);
_exit(0); _exit(0);
} }
printf("child %d running - c=%d\n",getpid(),c);
c--;
}
printf("child %d done\n",getpid());
return 0;
}
Exemplu – moștenire/așteptare
int main()
{
int c=2,status;
while(c){
fork();
printf("proces PID=%d PPID=%d cu c=%d\n",getpid(),getppid(),c);
c--;
}
while(wait(&status)>0){}
printf("proces %d FINAL\n",getpid());
return 0;
}
O greşeală frecventă este întâlnită în cazul folosirii unei secvenţe repetitive pentru crearea unui număr
fix de procese copil. Fără un control bun al execuţiei secvenţei se pot crea mult mai multe procese.
În general, la apelul fork(), toate resursele părintelui sunt duplicate şi atribuite şi copilului. Această
abordare este ineficientă în 2 situaţii:
- dacă procesul copil ar apela imediat ce a fost creat exec(), întreg programul ar fi rescris şi, prin
urmare, toată zona de date şi cod va fi fost duplicată inutil;
- dacă ambele procese ar folosi aceleaşi date şi acelaşi cod, fără să aducă modifice, ar fi inutilă
existenţa a 2 seturi resurse şi ar fi suficient unul singur.
În Linux, apelul fork() este implementat împreună cu tehnica COW care permite amânarea sau chiar
prevenirea duplicării ineficiente a resurselor. Astfel, la crearea unui nou proces, atât copilul cât şi părintele
partajează resursele care sunt marcate într-o aşa manieră încât, duplicarea are loc abia în momentul în care
unul din cele 2 procese trebuie să modifice o zona de memorie. În cazul modificărilor aduse zonei de
cod(apelul exec() ), resursele nu mai sunt duplicate şi se alocă altele pentru noul program încărcat.
int main()
{
int pid,status,t;
int var=2;
printf("\nbefore if > PID=%d PPID=%d\n",getpid(),getppid());
if ((pid = fork()) < 0)
{
printf("EROARE!!!");
} else if (pid == 0)
{
sleep(3);
printf("if > fiu? >PID=%d PPID=%d\n",getpid(),getppid());
printf("\n\tfiu > var=%d la adresa %p\n",var,&var);
var++;
printf("\n\tfiu > var=%d la adresa %p\n",var,&var);
} else
{
printf("if > parinte? >PID=%d PPID=%d\n",getpid(),getppid());
printf("\n\tparinte > var=%d la adresa %p\n",var,&var);
t=wait(&status);
if(t==pid)
printf("\nchiled done\n");
printf("\n\tparinte > var=%d la adresa %p\n",var,&var);
}
printf("after if > ? >PID=%d PPID=%d\n",getpid(),getppid());
return 0;
}
Pentru a seta flagul O_CLOEXEC,fie se deschide fisierul cu flagul setat fie, daca fisierul este deja deschis,
se foloseşte funcţia fcntl cu un apel de tipul:
int main()
{
int pid,fd,status;
char *buf[3]={"before fork\n","parent\n","child\n"};
fd=open("a.txt",O_WRONLY|O_APPEND);//|O_CLOEXEC);
//fcntl(fd,F_SETFD,FD_CLOEXEC);
write(fd,buf[0],12);
pid=fork();
if (pid > 0) {
wait(&status);
write(fd,buf[1],7);
} else {
execl("./progr","progr",buf[2],NULL);
_exit(1);
}
return 0;
}
Variabile de mediu
extern char **environ;
Un vector de pointeri la şiruri de caractere, ce conţin variabilele de mediu şi valorile lor. Vectorul e
terminat cu NULL. Șirurile de caractere sunt de forma "VARIABILA=VALOARE".
getenv întoarce valoarea variabilei de mediu denumite name, sau NULL daca nu există o variabilă de
mediudenumita astfel:
Daca variabila exista şi replace e 0, actiunea de setare a valorii variabilei e ignorata; daca replace e
diferitde 0, valoarea variabilei devine value:
int setenv(const char *name, const char *value, int replace);
unsetenv sterge variabila denumita name din mediu:
Forking NU
Funcţiile de bibliotecă fork(), vfork() şi _clone() sunt implementate în Linux prin apelul de sistem clone(),
care, la rândul său apelează do_fork().
user-space kernel-space
fork()
vfork() clone() do_fork() copy_process()
_clone()
Copy_process() :
- apelează dup_task_struct(), care creează o nouă stivă precum şi două structuri – una pentru proces
(task_struct) şi alta pentru firul de execuţie aferent (thread_info) cu valori identice cu ale procesului
părinte; în acest moment cele 2 procese sunt identice;
- în funcţie de parametrii transmişi la apelul clone(), se vor copia sau partaja resurse precum fişiere
deschise, informaţii despre sistemul de fişiere, rutine de tratare a semnalelor, spaţiul de adrese;
vfork()
Apelul vfork() are acelaşi efect cu menţiunea că resursele procesului părinte nu sunt duplicate. Procesul
copil se execută în spaţiul de adrese al părintelui, care devine astfel blocat până când copilul îşi încheie
execuţia sau invocă apelul exec().
Având astfel garanţia că procesul copil îşi începe primul execuţia are loc o utilizare foarte eficientă a
resurselor în sensul că, în cazul execuţiei apelului exec() pentru încărcarea unui nou program în cadrul
procesului copil, exec() va fi chiar prima instrucţiune executată după întoarcerea din fork()/vfork() şi, astfel, nu
se vor mai duplica resurse inutil.
Comportamentul este nedefinit dacă procesul creat nu termină execuţia cu apelul _exit().
Rulaţi exemplul de mai jos, adăugând/eliminând secvenţele comentate.
int main()
{
int pid,var=5;
printf("parinte? ->PID=%d PPID=%d-------var=%d\n",getpid(),getppid(),var);
pid=vfork(); //pid=fork();
if (pid > 0) {
//sleep(3);
printf("if -> parinte? ->PID=%d PPID=%d------- var =%d\n",getpid(),getppid(),var);
} else {
printf("if -> fiu? ->PID=%d PPID=%d------ var =%d\n",getpid(),getppid(),var);
var ++;
printf("if -> fiu? ->PID=%d PPID=%d------ var =%d\n",getpid(),getppid(),var);
execl("/bin/ls", "ls", "-la", NULL);
//_exit(0);
}
return 0;
}
Exiting
Un proces îşi poate termina execuţia:
Zombie
int main()
{
int pid;
printf("parinte? ->PID=%d PPID=%d\n",getpid(),getppid());
pid=fork();
if (pid > 0) {
while(1){}
} else {
printf("if -> fiu? ->PID=%d PPID=%d\n",getpid(),getppid());
_exit(0);
}
return 0;
}
>top –pPID_COPIL
Pe majoritatea sistemelor de operare pe care a fost portat, gdb nu poate detecta când un proces
realizează ooperaţie fork(). Atunci când programul este pornit, depanarea are loc exclusiv în procesul initial,
proceselecopii nefiind ataşate debugger-ului. În acest caz, singura soluţie este introducerea unor întârzieri în
execuţiaprocesului nou creat (de exemplu, prin apelul de sistem sleep()), care sa ofere programatorului
suficienttimp pentru a ataşa manual gdb-ul la respectivul proces, presupunând ca i-a aflat PID-ul în prealabil.
Pentru a ataşa debugger-ul la un proces deja existent, se folosete comanda attach, în felul urmator:
(gdb) attach PID
Aceasta metoda este destul de incomoda şi poate cauza chiar o funcţionare anormală a aplicaţiei
depanate, încazul în care necesităţile de sincronizare între procese sunt stricte (de exemplu operaţii cu time-
out).
Din fericire, pe un număr limitat de sisteme, printre care şi Linux, gdb permite depanarea comodă
aprogramelor care creează mai multe procese prin fork() şi vfork(). Pentru ca gdb să urmărească activitatea
proceselor create ulterior, se poate folosi comanda set follow-fork-mode, în felul urmator:
(gdb) set follow-fork-mode mode
unde mode poate lua valoarea parent, caz în care debugger-ul continua depanarea procesului parinte,
sauvaloarea child, şi atunci noul proces creat va fi depanat în continuare. Se poate observa că în această
manieradebugger-ul este ataşat la un moment dat doar la un singur proces, neputând urmări mai multe
simultan.
Cu toate acestea, gdb poate ţine evidenţa tuturor proceselor create de către programul depanat, deşi
încontinuare numai un singur proces poate fi rulat prin debugger la un moment dat. Comanda
setdetach-on-fork realizează acest lucru:
(gdb) set detach-on-fork mode
unde mode poate fi on, atunci când gdb se va ataşa unui singur proces la un moment dat
(comportamentimplicit), sau off, caz în care gdb se ataşează la toate procesele create în timpul execuţiei, şi le
suspendă peacelea care nu sunt urmărite, în funcţie de valoarea setării follow-fork-mode.
Comanda info forks afişeaza informaţii legate de toate procesele aflate sub controlul gdb la un
momentdat:
(gdb) info forks
De asemenea, comanda fork poate fi utilizată pentru a seta unul din procesele din listă drept cel activ
(careeste urmărit de debugger).
(gdb) fork fork-id
unde fork-id este identificatorul procesului, aşa cum apare în lista afişata de comandainfoforks.
Atunci când un anumit proces nu mai trebuie urmărit, el poate fi înlăturat din listă folosind
comenziledetach fork şi delete fork:
(gdb) detach fork fork-id
Diferenţa dintre cele două comenzi este că detach fork lasă procesul să ruleze independent, în
continuare, în timp ce delete fork îl încheie.
Pentru a ilustra aceste comenzi într-un exemplu concret, sa considerăm programul următor:
Exemplu fork-debug
// forktest.c
1 #include <stdio.h>
2 #include <sys/types.h>
3 #include <sys/wait.h>
4 #include <unistd.h>
5
6
7 int main(int argc, char **argv) {
8 pid_t childPID = fork();
9
10 if (childPID < 0) {
11 // An error occured
12 fprintf(stderr, "Could not fork!\n");
13 return -1;
14 } else if (childPID == 0) {
15
16 // We are in the child process
17 printf("The child process is executing...\n");
18 sleep(2);
19
20 } else {
21
22 // We are in the parent process
23 if (wait(NULL) < 0) {
24 fprintf(stderr, "Could not wait for child!\n");
25 return -1;
26 }
27 printf("Everything is done!\n");
28
29 }
30
31 return 0;
32 }
Dacă vom rula programul cu parametrii impliciţi de depanare, vom constata ca gdb va urmări exclusiv
execuţia procesului părinte:
$ gcc -O0 -g3 -o forktest forktest.c
$ gdb ./forktest
[...]
(gdb) run
Starting program: /home/student/forktest
The child process is executing...
Everything is done!
Program exited normally.
Plasăm câte un breakpoint în codul asociat procesului părinte, respectiv procesului copil, pentru a
evidenţia mai bine acest comportament:
(gdb) break 17
Breakpoint 1 at 0x8048497: file forktest.c, line 17.
(gdb) break 27
Breakpoint 2 at 0x80484f0: file forktest.c, line 27.
(gdb) run
Starting program: /home/student/forktest
The child process is executing...
Breakpoint 2, main () at forktest.c:27
27 printf("Everything is done!\n");
(gdb) continue
Continuing.
Everything is done!
Program exited normally.
Setăm debugger-ul să urmărească procesele copil, şi observăm că de data aceasta celălalt breakpoint
este atins:
(gdb) set follow-fork-mode child
(gdb) run
Starting program: /home/student/forktest
[Switching to process 6217]
Breakpoint 1, main () at forktest.c:17
17 printf("The child process is executing...\n");
(gdb) continue
Continuing.
The child process is executing...
Program exited normally.
Everything is done!
Observaţi ca ultimele două mesaje au fost inversate, faţă de cazul precedent: debugger-ul încheie
procesulcopil, apoi procesul părinte afişează mesajul de final (Everything is done!).
Encrypt1.c
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int fd1, fd2,fd3;
int r=1;
int w=0;
char* crypt(char*);
int checksum(char*);
int check;
int main()
{
char * buffer,buff;
fd1= open( "input.txt", O_RDONLY);
fd2 = open( "output1.txt", O_WRONLY);
fd3=open("temp.txt",O_RDWR);
buffer=(char*)malloc(4);
buff=(char*)malloc(4);
while(r!=0)
{
r=read(fd1, buffer, 4);
buffer = crypt(buffer);
write(fd3, buffer, 4);
write(fd2, buffer, 4);
read(fd3,buff,4);
check=checksum(buff);
w=write(fd2, &check, 4);
printf("Sau scris %d \n", w);
}
sleep(1);
}
char* crypt(char* buff1)
{
int i=0;
for(i=0;i<strlen(buff1);i++)
{
buff1[i]=buff1[i]+10;
}
return buff1;
}
int checksum(char* buff2)
{
int sum=0;
int i=0;
for(i=0;i<strlen(buff2);i++)
{
sum+=buff2[i];
}
return sum;
}
Encrypt2.c
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/signal.h>
int fd1, fd2,fd3;
int r=1;
int w=0;
char* crypt(char*);
int checksum(char*);
int check;
int pid;
int main()
{
char * buffer,buff;
fd1= open( "input.txt", O_RDONLY);
fd2 = open( "output2.txt", O_WRONLY);
fd3=open("temp.txt",O_RDWR);
buffer=(char*)malloc(4);
buff=(char*)malloc(4);
pid=fork();
if(pid==0)
{
while(1)
{
read(fd3,buff,4);
check=checksum(buff);
w=write(fd2, &check, 4);
printf("Sau scris %d \n", w);
}
}
if(pid>0)
{
while(read(fd1, buffer, 4)!=0)
{
buffer = crypt(buffer);
write(fd3, buffer, 4);
write(fd2, buffer, 4);
}
sleep(1);
kill(pid,SIGKILL);
}
}
char* crypt(char* buff1)
{
int i=0;
for(i=0;i<strlen(buff1);i++)
{
buff1[i]=buff1[i]+10;
}
return buff1;
}
int checksum(char* buff2)
{
int sum=0;
int i=0;
for(i=0;i<strlen(buff2);i++)
{
sum+=buff2[i];
}
return sum;
}