Prova pratica di laboratorio · 40 punti
Pratica: formato, template, temi recenti.
Internet è disponibile in aula. Template sotto: copiali, adattali, sappi spiegarli all’orale. Testi ufficiali su cs.unibo.it/~renzo/so/provapratica e archivio completo provapratica.tgz.
1Il formato (sempre uguale)
Es. 0 — Permessi directory (sempre uguale)
0 pt
Es. 0 — Permessi directory (sempre uguale)
0 ptchmod 700 ~ ; mkdir -p /public/username ; chmod 700 /public/username. Vietati system(), popen(), exec di "sh -c" (e in Python os.system/os.spawn: usare subprocess).
Es. 1 — C obbligatorio, prima di tutto il resto
20 pt
Es. 1 — C obbligatorio, prima di tutto il resto
20 ptProgramma C con system call: quasi sempre attraversamento directory, file (open/read/write/stat), segnali (sigqueue) o pipe/fork.
Es. 2 — C, variante del n.1
10 pt
Es. 2 — C, variante del n.1
10 ptStesso tema con una modifica (confronta invece di copiare, ack, più mittenti, undo).
Es. 3 — Python o bash a scelta
10 pt
Es. 3 — Python o bash a scelta
10 ptScript su file system: find + pipe, stat, sha1sum, awk/sed in bash; os.walk, os.stat, subprocess, hashlib in Python.
Es. 4 — Consegna + orale
0 pt
Es. 4 — Consegna + orale
0 ptsha1sum di tutti i file, poi breve discussione: bisogna saper spiegare ogni scelta fatta nel codice.
2Template pronti
Attraversamento ricorsivo directory
Codice
Attraversamento ricorsivo directory
Codicemodifcmp, sha1dir, ckfile, dremcont: quasi tutti gli ex.1 partono da qui.
#include <stdio.h>
#include <string.h>
#include <dirent.h>
#include <sys/stat.h>
#include <limits.h>
static void walk(const char *dir, void (*cb)(const char *, struct stat *)) {
DIR *d = opendir(dir);
if (!d) { perror("opendir"); return; }
struct dirent *e;
char path[PATH_MAX];
struct stat st;
while ((e = readdir(d)) != NULL) {
if (!strcmp(e->d_name, ".") || !strcmp(e->d_name, ".."))
continue;
snprintf(path, sizeof path, "%s/%s", dir, e->d_name);
if (lstat(path, &st) < 0) { perror("lstat"); continue; }
if (S_ISDIR(st.st_mode))
walk(path, cb); /* ricorsione */
else if (S_ISREG(st.st_mode))
cb(path, &st); /* solo file regolari */
}
closedir(d);
}Confronto contenuto di due file (niente librerie hash)
Codice
Confronto contenuto di due file (niente librerie hash)
Codiceckfile, dremcont, sha1diff (versione senza SHA1).
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
/* 1 se stesso contenuto, 0 altrimenti, -1 errore */
static int same_content(const char *a, const char *b) {
int fa = open(a, O_RDONLY), fb = open(b, O_RDONLY);
if (fa < 0 || fb < 0) return -1;
char ba[4096], bb[4096];
ssize_t na, nb;
int eq = 1;
do {
na = read(fa, ba, sizeof ba);
nb = read(fb, bb, sizeof bb);
if (na < 0 || nb < 0) { eq = -1; break; }
if (na != nb || memcmp(ba, bb, na) != 0) { eq = 0; break; }
} while (na > 0);
close(fa);
close(fb);
return eq;
}Stringhe via sigqueue (max 8 char per segnale)
Codice
Stringhe via sigqueue (max 8 char per segnale)
Codicesigtx/sigrx 2026.02.09: il value porta 8 byte, memcpy dentro/fuori.
/* ---- sigrx.c ---- */
#include <stdio.h>
#include <signal.h>
#include <string.h>
#include <unistd.h>
static void on_sig(int sig, siginfo_t *si, void *u) {
(void)sig; (void)u;
char buf[9];
memcpy(buf, &si->si_value.sival_int, 8); /* 8 byte dal segnale */
buf[8] = 0;
printf("%s\n", buf);
fflush(stdout);
}
int main(void) {
printf("%d\n", getpid());
fflush(stdout);
struct sigaction sa = {0};
sa.sa_sigaction = on_sig;
sa.sa_flags = SA_SIGINFO; /* serve si_value: senza, niente dati */
sigaction(SIGUSR1, &sa, NULL);
for (;;) pause();
}
/* ---- sigtx.c: invio ---- */
#include <signal.h>
#include <string.h>
/* pid e msg da argv */
void send8(pid_t pid, const char *msg) {
union sigval v;
memset(&v, 0, sizeof v);
memcpy(&v.sival_int, msg, 8); /* max 8 char, resto azzerato */
sigqueue(pid, SIGUSR1, v);
}
/* stringhe lunghe: ciclo a blocchi di 8 + ack (ex.2) */Sostituzione atomica con symlink + rename
Codice
Sostituzione atomica con symlink + rename
Codice2024.07.23: il file non deve mai risultare inesistente.
#include <unistd.h>
#include <stdio.h>
/* sposta path in path.new e lascia symlink relativo al suo posto */
static int replace_with_symlink(const char *path) {
char tmp[4096], link[4096];
snprintf(tmp, sizeof tmp, "%s.new", path);
/* 1. crea il sostituto con nome temporaneo */
if (symlink("...", tmp) < 0) { perror("symlink"); return -1; }
/* 2. rename atomica: tmp -> path (mai un istante senza file) */
snprintf(link, sizeof link, "%s", path);
if (rename(tmp, link) < 0) { perror("rename"); return -1; }
return 0;
}
/* regola: MAI unlink+symlink (finestra senza file); SEMPRE tmp+rename */Bash: find, hash, prepend
Codice
Bash: find, hash, prepend
CodiceEx.3 quando conviene bash: duplicati, metadati, modifiche in massa.
# file uguali a f in d (dremcont): confronta via sha1sum
f="$1"; d="$2"
h=$(sha1sum "$f" | cut -d' ' -f1)
find "$d" -type f -exec sha1sum {} + | grep "^$h" | cut -d' ' -f3- | while read -r p; do
[ "$p" != "$f" ] && rm -- "$p"
done
# prepend di HEADER a tutti i .c/.sh/.py della dir corrente
for p in *.c *.sh *.py; do
[ -f "$p" ] || continue
{ printf '%s\n' "$HEADER"; cat -- "$p"; } > "$p.tmp" && mv -- "$p.tmp" "$p"
done
# file modificati dopo un riferimento (modifcmp in bash)
find . -type f -newer "$rif" -printPython: walk + stat + hash
Codice
Python: walk + stat + hash
CodiceEx.3 quando conviene Python: ricorsione leggibile, hashlib, subprocess.
import os, hashlib, subprocess, sys
def sha1_of(path):
h = hashlib.sha1()
with open(path, 'rb') as f:
for chunk in iter(lambda: f.read(65536), b''):
h.update(chunk)
return h.hexdigest()
# tutti i file sotto d con mtime maggiore di rif
rif_mtime = os.stat(sys.argv[1]).st_mtime
for root, _dirs, files in os.walk(sys.argv[2]):
for name in files:
p = os.path.join(root, name)
if os.stat(p).st_mtime > rif_mtime:
print(p)
# MAI os.system / os.spawn: solo subprocess.run([...], check=True)3Ultimi appelli pratici
2026.02.09 · PDF ufficiale ↗
Ex.1: sigtx/sigrx: trasferire stringhe di max 8 char via sigqueue (value dei segnali). sigrx stampa il pid e attende.
Ex.2/3: Stringhe arbitrarie: iterare 8 char alla volta con ack prima dei successivi.
2026.01.12 · PDF ufficiale ↗
Ex.1: modifcmp: 1 arg = elenca file nel sottoalbero più recenti del file dato; 2 file = stampa il secondo se più recente; file+dir = cerca nel sottoalbero.
Ex.2/3:
2025.07.23 · PDF ufficiale ↗
Ex.1: sha1dir: ricostruisce albero identico; i file regolari diventano file con la hash sha1 dell’originale.
Ex.2/3: sha1diff: elenca i file la cui hash non corrisponde. Ex3: dremcont cancella i duplicati di un file.
2025.06.24 · PDF ufficiale ↗
Ex.1: semsend/semrecv: trasferire stringa bit a bit con SIGUSR1/SIGUSR2, terminatore incluso.
Ex.2/3: semrecv multi-mittente con bit interallacciati. Ex3: prepend righe a file C/bash/python.
2024.07.23 · PDF ufficiale ↗
Ex.1: Sposta i file regolari in sottodir "...", sostituiscili con symlink relativi via rename() atomica.
Ex.2/3: Undo: risostituisci i symlink con i file veri, sempre con rename() atomica.
4Regole d’oro
Prima di consegnare
5Riferimenti wiki del corso
- Catalogo delle system call — cosa esiste e cosa è obsoleto
- Syscall filesystem ↔ comandi — mkdir/link/symlink e i loro ritorni
- Fork vs exec — cosa eredita il figlio (classico orale)
- C, libreria C, sistema operativo — toolchain gcc
- Appunti Pratico 2025-26 (Elena) — ricette C/Python per ogni pattern, 2079 righe
6Prompt da dare all’AI in aula
Copia il testo qui sotto, incollalo in chat insieme alla consegna dell’esercizio.
Contesto: esame pratico di Sistemi Operativi (UniBo, Davoli), programmi C POSIX e script bash/Python su Linux a 64 bit.
Materiali di riferimento (leggili prima di rispondere):
- Template C/bash/Python: https://so.rickywanga.com/pratica/
- Ricette complete C/Python (Elena): https://so.rickywanga.com/appunti-pratico-elena.md
- Archivio testi ufficiali: https://www.cs.unibo.it/~renzo/so/provapratica.shtml
- Wiki corso: catalogo syscall https://so.v2.cs.unibo.it/wiki/index.php/Il_%27%27catalogo%27%27_delle_System_Call
- Wiki corso: syscall filesystem https://so.v2.cs.unibo.it/wiki/index.php/Syscall_per_file_system:_equivalenza_comandi
- Wiki corso: fork vs exec https://so.v2.cs.unibo.it/wiki/index.php/Fork_vs_exec
Regole tassative per il codice C:
- MAI system(), popen(), exec di "sh -c".
- Ogni system call con controllo del ritorno + perror().
- Compilabile con gcc -Wall senza warning.
- Makefile minimo con target all e clean.
Quando ti incollo la consegna:
1. indica quale template usare e perché,
2. scrivi il codice completo adattato alla consegna,
3. spiegami ogni scelta in 2-3 righe (devo ridirla all’orale),
4. per OGNI system call usata dimmi cosa fa, cosa restituisce e perché serve lì (non conosco le syscall, devo poterle spiegare).
CONSEGNA:
[incolla qui il testo dell’esercizio]