This shows you the differences between two versions of the page.
so2:teme:tema5 [2017/05/07 19:47] adrian.stanciu [Detalii de implementare] |
so2:teme:tema5 [2020/08/30 16:28] (current) razvan.deaconescu [Submitere] |
||
---|---|---|---|
Line 1: | Line 1: | ||
~~NOTOC~~ | ~~NOTOC~~ | ||
- | ====== Tema 5 - Transport protocol ====== | + | ====== Tema 5 - Driver de sistem de fișiere ====== |
- | Termen de predare: **Marți, 24 Mai 2016, ora 23:00 ** | + | * Termen de predare: |
- | ===== Obiectivele temei ===== | + | * **Sâmbătă, 25 Aprilie 2020, ora 23:00** (pentru Ixia Challenge - **2p**) |
- | + | * **Dumincă, 03 Mai 2020, ora 23:00** (deadline hard - **1.5p**) | |
- | * Dobândirea de cunoștințe legate de funcționarea subsistemului de networking în nucleul Linux. | + | |
- | * Obținerea de deprinderi de lucru cu structurile de bază din subsistemul de networking în Linux. | + | |
- | * Aprofundarea noțiunilor legate de protocoale de comunicație și rețelistică prin implementarea unui protocol într-o stivă de protocoale existentă. | + | |
===== Enunț ===== | ===== Enunț ===== | ||
- | Implementați, în nucleul Linux, un protocol numit STP (SO2 Transport Protocol) de nivel rețea și transport care funcționează pe bază de datagrame (nu este orientat conexiune și nu deține elemente de control al fluxului). | + | Să se scrie un modul de kernel care să implementeze sistemul de fișiere ''PITIX'', versiunea 2. Acest sistem de fișiere va oferi suport doar pentru fișiere și directoare. Nu se vor implementa operațiile de suport pentru link-uri hard sau simbolice. De asemenea, nu se vor implementa operațiile de suport pentru fișiere speciale (pipe-uri, dispozitive caracter sau bloc). Practic va trebui să implementați următoarele operații: |
+ | * pentru directoare: ''lookup'', ''unlink'', ''mkdir'', ''rmdir'', ''iterate'' | ||
+ | * pentru fișiere: ''create'', ''truncate'', funcția de bitmap (vezi [[https://elixir.bootlin.com/linux/v4.15/source/fs/minix/inode.c#L375|minix_get_block]]) | ||
- | Protocolul STP are rolul unui protocol de nivel transport (multiplexare pe bază de porturi) dar funcționează la nivelul 3 (Rețea) din [[http://en.wikipedia.org/wiki/OSI_model | stiva OSI]], peste nivelul Legătură de Date. | + | Restul funcțiilor fie au implementări generice în kernel, fie nu trebuie să le implementați. |
- | Antetul STP este definit de structura ''struct stp_header'': | + | Structura pe disk a sistemului de fișiere este: |
+ | {{ http://elf.cs.pub.ro/so2/res/teme/pitix-layout.png }} | ||
- | struct stp_header { | + | unde: |
- | __be16 dst; | + | * ''Superblock'' conține superblocul (4096 octeți) |
- | __be16 src; | + | * ''Imap'' conține harta de biți (bitmap) a blocurilor ocupate de inode-uri (1 bloc) |
- | __be16 len; | + | * ''Dmap'' conține harta de biți (bitmap) a blocurilor ocupate de date (1 bloc) |
- | __u8 flags; | + | * ''Izone'' conține inode-urile (32 blocuri) |
- | __u8 csum; | + | * ''Dzone'' conține datele (conținutul efectiv al fișierelor) (8*block_size blocuri) |
- | }; | + | |
+ | Superblocul (**pe disc**) este descris de următoarea structură: | ||
+ | <code cpp> | ||
+ | struct pitix_super_block { | ||
+ | unsigned long magic; | ||
+ | __u8 version; | ||
+ | __u8 block_size_bits; | ||
+ | __u8 imap_block; | ||
+ | __u8 dmap_block; | ||
+ | __u8 izone_block; | ||
+ | __u8 dzone_block; | ||
+ | __u16 bfree; | ||
+ | __u16 ffree; | ||
+ | }; | ||
+ | </code> | ||
unde | unde | ||
- | * ''len'' este lungimea pachetului în octeți (inclusiv header-ul); | ||
- | * ''dst'' și ''src'' sunt porturile destinație, respectiv sursă; | ||
- | * ''flags'' conține diverse flag-uri, pe moment nefolosite (marcate //reserved//); | ||
- | * ''csum'' este suma de control (//checksum//) a întregului pachet incluzând headerul; suma de control este calculată prin SAU exclusiv (XOR) între toți octeții. | ||
- | Sockeții care folosesc acest protocol vor folosi familia ''AF_STP''. | + | * ''magic'' trebuie să fie inițializat cu ''PITIX_MAGIC'' |
+ | * ''version'' trebuie să fie inițializat cu 2 (''PITIX_VERSION'') | ||
+ | * ''block_size_bits'' este dimensiunea blocului în puteri ale lui doi; dimensiunea blocului poate să fie 512, 1024, 2048, sau 4096 | ||
+ | * ''imap_block'' este numărul blocului (relativ la dispozitiv) pentru vectorul de biți folosit pentru alocarea/eliberarea inode-urilor | ||
+ | * ''dmap_block'' este numărul blocului (relativ la dispozitiv) pentru vectorul de biți folosit pentru alocarea/eliberarea blocurilor de date | ||
+ | * ''izone_block'' este numărul primului bloc (relativ la dispozitiv) al zonei de inode-uri | ||
+ | * ''dzone_block'' este numărul primului bloc (relativ la dispozitiv) al zonei de date | ||
+ | * ''bfree'' este numărul de blocuri libere (nealocate) | ||
+ | * ''ffree'' este numărul de inode-uri libere (nealocate) | ||
- | Protocolul trebuie să funcționeze direct peste Ethernet. Porturile folosite sunt între 1 si 65535. Portul 0 nu este folosit. | + | Inode-urile vor fi stocate în zona de inode-uri și sunt descrise de următoarea structură: |
+ | <code cpp> | ||
+ | struct pitix_inode { | ||
+ | __u32 mode; | ||
+ | uid_t uid; | ||
+ | gid_t gid; | ||
+ | __u32 size; | ||
+ | __u32 time; | ||
+ | __u16 direct_data_blocks[INODE_DIRECT_DATA_BLOCKS]; | ||
+ | __u16 indirect_data_block; | ||
+ | }; | ||
+ | </code> | ||
- | Definiția structurilor și macro-urilor aferente STP se găsesc în [[http://elf.cs.pub.ro/so2/res/teme/stp.h | header-ul temei]]. | + | unde |
- | ==== Detalii de implementare ==== | + | * ''mode'' reprezintă drepturile de acces și tipul inode-ului (fișier sau director) așa cum sunt reprezentate în kernel |
+ | * ''uid'' reprezintă UID-ul așa cum este el reprezentat în kernel | ||
+ | * ''gid'' reprezintă GID-ul așa cum este el reprezentat în kernel | ||
+ | * ''size'' reprezintă dimensiunea fișierului/directorului | ||
+ | * ''time'' reprezintă timpul de modificare așa cum este el reprezentat în kernel | ||
+ | * ''direct_data_blocks'' este un vector (de dimensiune ''INODE_DIRECT_DATA_BLOCKS'') ce conține indecșii blocurile de date directe | ||
+ | * ''indirect_data_block'' este indexul unui bloc de date ce conține indecșii blocurilor de date indirecte | ||
- | Modulul de kernel va avea numele **af_stp.ko**. | + | Indexul unui bloc de date (direct sau indirect) indică numărul acelui bloc de date relativ la zona de date (''Dzone''). Dimensiunea unui index este de 2 octeți. |
- | Trebuie înregistrată o structură de tip [[http://elixir.free-electrons.com/linux/v4.9.11/source/include/linux/net.h#L200 | net_proto_family]], care să ofere operația de creat sockeți de tip STP. Sockeții proaspăt creați nu sunt asociați cu niciun port și nicio interfață și nu pot primi/trimite pachete. În această funcție, trebuie inițializat [[http://elixir.free-electrons.com/linux/v4.9.11/source/include/linux/net.h#L124 | câmpul ops al socket-ului]] cu lista de operații specifice familiei STP. Acest câmp referă o structură [[http://elixir.free-electrons.com/linux/v4.9.11/source/include/linux/net.h#L136 | proto_ops]] care trebuie să includă urmatoarele funcții: | + | După cum se vede din structura sa, inode-ul folosește o schemă de indirectare simplă pentru blocurile de date. Blocurile din intervalul [0, ''INODE_DIRECT_DATA_BLOCKS'') sunt blocuri de date directe și sunt referite de elementele vectorului ''direct_data_blocks'' iar blocurile din intervalul [''INODE_DIRECT_DATA_BLOCKS'', ''INODE_DIRECT_DATA_BLOCKS'' + block_size / 2) sunt blocuri de date indirecte și sunt referite de indecșii din cadrul blocului de date indicat de ''indirect_data_block''. |
- | * ''release'': eliberează un socket de tip STP | + | |
- | * ''bind'': asociază un socket cu un port (eventual și o interfață) pe care se vor primi/trimite pachete: | + | |
- | * pot exista sockeți bind-uiți doar pe un port (nu și pe o interfață) | + | |
- | * dacă există un socket deja bind-uit cu un port nu se poate bind-ui un al doilea socket pe același port | + | |
- | * sockeții asociați doar cu un port vor putea primi pachetele trimise către acel port pe toate interfețele (analog cu sockeții UDP asociați doar cu un port); acești sockeți nu pot trimite pachete pentru că nu se poate specifica interfața de pe care să fie trimise prin API-ul standard de sockeți | + | |
- | * recomandăm folosirea unui hash table pentru bind în loc de alte structuri de date (listă, array); în nucleu există o implementare de hash table în [[http://elixir.free-electrons.com/linux/v4.9.11/source/include/linux/hashtable.h | header-ul hashtable.h]] | + | |
- | * ''connect'': asociază un socket cu un port și o adresă hardware (adresă MAC) remote către care se vor trimite/dinspre care se vor primi pachete: | + | |
- | * acest lucru ar trebui să permită operații de ''send''/''recv'' pe socket în loc de ''sendmsg''/''recvmsg'' sau ''sendto''/''recvfrom'' | + | |
- | * odată conectați cu un host, sockeții nu vor mai accepta pachete decât de la host-ul respectiv | + | |
- | * odată conectați, sockeții nu mai pot fi deconectați | + | |
- | * ''sendmsg'', ''recvmsg'': se trimite, respectiv se primește o datagramă pe un socket STP: | + | |
- | * pentru partea de //receive//, metainformații despre host-ul care a trimis pachetul se pot păstra în [[http://elixir.free-electrons.com/linux/v4.9.11/source/include/linux/skbuff.h#L650 | câmpul cb din sk_buff]] | + | |
- | * ''poll'': va trebui folosită funcția predefinită ''datagram_poll'' | + | |
- | * pentru restul operațiilor vor trebui folosite stub-urile predefinite în kernel (''sock_no_*'') | + | |
- | Operațiile pe sockeți folosesc un tip de adrese numit ''sockaddr_stp'', tip definit în [[http://elf.cs.pub.ro/so2/res/teme/stp.h | header-ul temei]]. Pentru operația de //bind// se vor lua în considerare doar portul și indexul interfeței pe care se bind-uiește socketul. Pentru operația de //receive// se vor completa doar câmpurile ''addr'' și ''port'' din structură cu adresa MAC a host-ului care a trimis pachetul și cu portul de pe care a fost trimis. De asemenea, la trimiterea unui pachet, host-ul destinație se va obține din câmpurile ''addr'' și ''port'' ale acestei structuri. | + | Blocul de date indicat de ''indirect_data_block'' trebuie alocat atunci când avem de referit un prim bloc de date indirect și trebuie eliberat atunci când nu mai sunt blocuri de date indirecte. |
- | Trebuie să înregistrați o structură [[http://elixir.free-electrons.com/linux/v4.9.11/source/include/linux/netdevice.h#L2222 | packet_type]], folosind apelul [[http://elixir.free-electrons.com/linux/v4.9.11/source/net/core/dev.c#L386 | dev_add_pack]] pentru a putea primi pachete STP de pe layer-ul de rețea. | + | Indecșii nefolosiți trebuie setați pe 0. Primul bloc, cel cu index 0, este tot timpul alocat când se face formatarea. Acest bloc nu va putea fi folosit și, în consecință, valoarea 0: |
+ | * într-un element din vectorul ''direct_data_blocks'' înseamnă slot liber (acel element nu referă un bloc de date direct) | ||
+ | * pentru ''indirect_data_block'' înseamnă că nu este alocat un bloc de date pentru a ține evidența blocurilor de date indirecte (atunci când nu sunt necesare blocuri de date indirecte) | ||
+ | * pentru un index din cadrul blocului de date referit de ''indirect_data_block'' înseamnă slot liber (acel index nu referă un bloc de date indirect) | ||
- | Protocolul va trebui să ofere o interfață prin sistemul de fișiere ''procfs'' pentru statistici despre pachetele trimise/primite. Fișierul trebuie să se numească ''/proc/net/stp_stats'', specificat prin macro-ul ''STP_PROC_FULL_FILENAME'' din [[http://elf.cs.pub.ro/so2/res/teme/stp.h | header-ul temei]]. Formatul trebuie să fie de tip tabel simplu cu 2 rânduri: pe primul rând header-ul tabelului, iar pe al doilea rând statisticile corespunzătoare coloanelor. Coloanele tabelului trebuie să fie, în ordine:<code> | + | Este garantat faptul că numărul de octeți ocupați de un inode pe disc este divizor al dimensiunii blocului. |
- | RxPkts HdrErr CsumErr NoSock NoBuffs TxPkts | + | |
+ | Directoarele au asociate un singur bloc de date (referit prin ''direct_data_block[0]'') în care vor fi stocate intrările de director. Acestea sunt descrise de următoarea structură: | ||
+ | <code cpp> | ||
+ | struct pitix_dir_entry { | ||
+ | __u32 ino; | ||
+ | char name[PITIX_NAME_LEN]; | ||
+ | }; | ||
</code> | </code> | ||
- | unde: | ||
- | * ''RxPkts'' - numărul de pachete primite; | ||
- | * ''HdrErr'' - numărul de pachete primite cu erori în header (pachete prea scurte sau cu porturi sursă sau destinație 0); | ||
- | * ''CsumErr'' - numărul de pachete primite cu erori de checksum; | ||
- | * ''NoSock'' - numărul de pachete primite pentru care nu s-a găsit un socket destinație; | ||
- | * ''NoBuffs'' - numărul de pachete primite care nu au putut fi recepționate pentru că coada de receive a socket-ului era plină; | ||
- | * ''TxPkts'' - numărul de pachete trimise. | ||
- | Pentru crearea, respectiv ștergerea intrării precizate de ''STP_PROC_FULL_FILENAME'' recomandăm folosirea funcțiilor [[http://elixir.free-electrons.com/linux/v4.9.11/source/include/linux/proc_fs.h#L30 | proc_create]] și [[http://elixir.free-electrons.com/linux/v4.9.11/source/fs/proc/generic.c#L636 | proc_remove]]. | ||
- | ===== Exemple de implementări de protocoale ===== | + | unde |
- | Pentru exemple de implementare de protocoale, vă sugerăm în special implementarea de sockeți [[http://elixir.free-electrons.com/linux/v4.9.11/source/net/packet/af_packet.c | PF_PACKET]] și diversele funcții din [[http://elixir.free-electrons.com/linux/v4.9.11/source/net/ipv4/udp.c| implementarea UDP]] sau [[http://elixir.free-electrons.com/linux/v4.9.11/source/net/ipv4/af_inet.c | implementarea IP]]. | + | * ''ino'' reprezintă numărul inode-ului fișierului sau directorului; acest număr este un index în zona de inode-uri |
+ | * ''name'' reprezintă numele fișierului sau al directorului; lungimea maximă a numelui este 16 octeți (''PITIX_NAME_LEN''); dacă lungimea numelui e mai mică decât 16 octeți, atunci numele va fi terminat cu caracterul ASCII ce are codul 0 (la fel ca la șirurile de caractere) | ||
+ | |||
+ | Directorul rădăcină va avea alocat inode-ul 0 și blocul de date 0. | ||
+ | |||
+ | Pentru simplificare, la ''mkdir'' nu este necesară crearea intrărilor ''.'' (dot) și ''..'' (dot dot) în noul director; checker-ul se folosește de această presupunere. | ||
+ | |||
+ | Toate valorile numerice sunt stocate pe disc în CPU byte-order. | ||
+ | |||
+ | În [[https://github.com/linux-kernel-labs/linux/blob/master/tools/labs/templates/assignments/5-pitix/pitix.h|header-ul temei]] găsiți structurile descrise anterior împreună cu unele macro-uri utile și declarațiile principalelor funcții de implementat. | ||
+ | |||
+ | Modulul de kernel va avea numele **pitix.ko**. | ||
===== Testare ===== | ===== Testare ===== | ||
- | Pentru simplificarea procesului de corectare a temelor, dar și pentru a reduce greșelile temelor trimise, corectarea temelor se va face automat cu ajutorul unor [[http://elf.cs.pub.ro/so2/res/teme/5-stp.zip| teste publice]]. | ||
- | Indicații despre utilizarea suitei de teste se găsesc în fișierul ''README'' din cadrul arhivei. | ||
- | ==== tcpdump ==== | + | <note tip> |
+ | Activați suportul pentru ''Loop Devices'' folosind ''make menuconfig''. ''Device drivers'' -> ''Block devices'' -> ''Loopback device support'' | ||
+ | </note> | ||
- | Pentru depanarea pachetelor trimise, puteți folosi utilitarul ''tcpdump''. Testele folosesc interfața de loopback; pentru a urmări pachetele trimise puteți folosi o linie de comandă de forma:<code> | + | Pentru simplificarea procesului de corectare a temelor, dar și pentru a reduce greșelile temelor trimise, corectarea temelor se va face automat cu ajutorul testelor publice care se găsesc în noua infrastructură. Pentru testarea locală, folosiți următoarele comenzi: |
- | tcpdump -i lo -XX | + | |
- | </code> | + | |
- | Puteți folosi o versiune statică de [[http://elf.cs.pub.ro/so2/res/teme/tcpdump | tcpdump]]. Pentru a o avea în PATH în mașina virtuală, copiați acest fișier în ''qemu-so2/fsimg/bin''. Creați directorul dacă nu există. Nu uitați să dați fișierului tcpdump permisiuni de execuție:<code> | + | <code> |
- | # În directorul qemu-so2 | + | $ git clone https://github.com/linux-kernel-labs/linux.git |
- | mkdir fsimg/bin | + | $ cd linux/tools/labs |
- | wget http://elf.cs.pub.ro/so2/res/teme/tcpdump -O fsimg/bin/tcpdump | + | $ LABS=assignments/5-pitix make skels |
- | chmod 755 fsimg/bin/tcpdump | + | # dezvoltarea temei se va efectua în directorul 5-pitix/ |
+ | $ make build | ||
+ | $ make copy | ||
+ | $ make boot | ||
</code> | </code> | ||
+ | |||
+ | Indicații despre utilizarea suitei de teste se găsesc în fișierul ''README'' din cadrul arhivei. | ||
==== Sfaturi ==== | ==== Sfaturi ==== | ||
- | Pentru a vă mări șansele de a obține nota maximă, citiți și respectați coding style-ul kernelului Linux descris din documentul [[http://lxr.free-electrons.com/source/Documentation/process/coding-style.rst | Coding Style]]. | + | Pentru a vă mări șansele de a obține nota maximă, citiți și respectați coding style-ul kernelului Linux descris din documentul [[https://github.com/linux-kernel-labs/linux/blob/master/Documentation/process/coding-style.rst|Coding Style]]. |
De asemenea, folosiți următoarele tool-uri de analiza statică pentru a verifica codul: | De asemenea, folosiți următoarele tool-uri de analiza statică pentru a verifica codul: | ||
Line 106: | Line 141: | ||
* <code bash> /path/to/linux-4.9.11/scripts/checkpatch.pl --no-tree --terse -f /path/to/your/src-file.c </code> | * <code bash> /path/to/linux-4.9.11/scripts/checkpatch.pl --no-tree --terse -f /path/to/your/src-file.c </code> | ||
+ | |||
=== sparse === | === sparse === | ||
* <code bash> sudo apt-get install sparse </code> | * <code bash> sudo apt-get install sparse </code> | ||
Line 118: | Line 154: | ||
==== Notare ==== | ==== Notare ==== | ||
- | Tema valorează un punct. | + | Datorită nivelului de dificultate mai ridicat, tema valorează două puncte. |
==== Depunctări ==== | ==== Depunctări ==== | ||
- | Depunctările generale pentru teme se găsesc pe pagina de [[so2:teme:general| Indicații generale]]. | + | Depunctările generale pentru teme se găsesc pe pagina de [[so2:teme:general|Indicații generale]]. |
În cazuri excepționale (tema trece testele prin nerespectarea cerințelor) și în cazul în care tema nu trece toate testele se poate scădea mai mult decât este menționat mai sus. | În cazuri excepționale (tema trece testele prin nerespectarea cerințelor) și în cazul în care tema nu trece toate testele se poate scădea mai mult decât este menționat mai sus. | ||
Line 128: | Line 164: | ||
==== Submitere ==== | ==== Submitere ==== | ||
- | Arhiva temei va fi submisă pe vmchecker, în conformitate cu [[:so2:reguli-notare#reguli_de_trimitere_a_temelor|precizările din pagina de reguli]]. | + | Arhiva temei va fi submisă pe vmchecker, în conformitate cu [[:so2:reguli-notare#reguli_de_realizare_a_temelor|precizările din pagina de reguli]]. |
- | + | ||
- | Din interfața vmchecker alegeți opțiunea ''Transport protocol'', aferentă acestei teme. | + | |
+ | Din interfața vmchecker alegeți opțiunea ''Sistem de fișiere'', aferentă acestei teme. | ||
===== Resurse ===== | ===== Resurse ===== | ||
- | * Cursuri | + | * [[https://github.com/linux-kernel-labs/linux/blob/master/tools/labs/templates/assignments/5-pitix/pitix.h|header-ul temei]] |
- | * [[http://ocw.cs.pub.ro/so2/cursuri/curs10 | Curs 10 - Gestiunea rețelei]] | + | * [[so2:laboratoare:lab08|Laboratorul 8. Drivere sisteme de fișiere (partea întăi)]] |
- | * Laboratoare | + | * [[so2:laboratoare:lab09|Laboratorul 9. Drivere sisteme de fișiere (partea a doua)]] |
- | * [[http://ocw.cs.pub.ro/so2/laboratoare/lab10 | Laborator 10 - Networking]] | + | * [[https://elixir.bootlin.com/linux/v4.15/source/fs/minix|Sursele sistemului de fișiere Minix]] |
- | * Sursele nucleului Linux | + | |
- | * [[http://elixir.free-electrons.com/linux/v4.9.11/source/net/packet/af_packet.c | Implementarea sockeților PF_PACKET]] | + | |
- | * [[http://elixir.free-electrons.com/linux/v4.9.11/source/net/ipv4/udp.c | Implementarea protocolului UDP]] | + | |
- | * [[http://elixir.free-electrons.com/linux/v4.9.11/source/net/ipv4/af_inet.c | Implementarea protocolului IP]] | + | |
- | * Understanding Linux Network Internals | + | |
- | * capitolele 8-13 | + | |
- | * [[http://elf.cs.pub.ro/so2/res/teme/stp.h | Header-ul temei]] | + | |
<note important> | <note important> | ||
- | Resursele temei se găsesc și în repo-ul [[https://github.com/systems-cs-pub-ro/so2-assignments|so2-assignments]] de pe GitHub. Repo-ul conține și un [[https://github.com/systems-cs-pub-ro/so2-assignments/blob/master/so2-create-repo.sh|script Bash]] care vă ajută să vă creați un repository privat pe instanța de [[https://gitlab.cs.pub.ro|GitLab]] a facultății. Urmăriți indicațiile din [[https://github.com/systems-cs-pub-ro/so2-assignments/blob/master/README.md|README]] și de pe [[:so2:teme:folosire-gitlab| pagina de Wiki dedicată pentru git]]. | + | Resursele temei ([[https://github.com/linux-kernel-labs/linux/tree/master/tools/labs/templates/assignments/5-pitix|5-pitix]]) se găsesc și în repo-ul [[https://github.com/systems-cs-pub-ro/so2-assignments|so2-assignments]] de pe GitHub. Repo-ul conține și un [[https://github.com/systems-cs-pub-ro/so2-assignments/blob/master/so2-create-repo.sh|script Bash]] care vă ajută să vă creați un repository privat pe instanța de [[https://gitlab.cs.pub.ro|GitLab]] a facultății. Urmăriți indicațiile din [[https://github.com/systems-cs-pub-ro/so2-assignments/blob/master/README.md|README]] și de pe [[:so2:teme:folosire-gitlab| pagina de Wiki dedicată pentru git]]. |
</note> | </note> | ||
+ | |||
===== Întrebări ===== | ===== Întrebări ===== | ||
- | Pentru întrebări legate de temă puteți consulta [[http://cursuri.cs.pub.ro/pipermail/so2/ | arhivele]] listei de discuții sau puteți trimite un [[so2@cursuri.cs.pub.ro |e-mail]] (trebuie să fiți [[http://cursuri.cs.pub.ro/cgi-bin/mailman/listinfo/so2 | înregistrați]]). | + | |
- | Vă rugăm să urmăriți și să respectați [[http://ocw.cs.pub.ro/courses/so2/resurse/lista-discutii#mailing-list-guidelines | indicațiile de utilizare a listei]]. | + | Pentru întrebări legate de temă puteți consulta [[http://cursuri.cs.pub.ro/pipermail/so2/|arhivele]] listei de discuții sau puteți trimite un [[so2@cursuri.cs.pub.ro|e-mail]] (trebuie să fiți [[http://cursuri.cs.pub.ro/cgi-bin/mailman/listinfo/so2|înregistrați]]). |
+ | |||
+ | Vă rugăm să urmăriți și să respectați [[http://ocw.cs.pub.ro/courses/so2/resurse/lista-discutii#mailing-list-guidelines|indicațiile de utilizare a listei]]. |