Sistemi Operativi

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

chmod 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

Programma 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

Stesso tema con una modifica (confronta invece di copiare, ack, più mittenti, undo).

Es. 3 — Python o bash a scelta

10 pt

Script 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

sha1sum di tutti i file, poi breve discussione: bisogna saper spiegare ogni scelta fatta nel codice.

2Template pronti

Attraversamento ricorsivo directory

Codice
Quando serve

modifcmp, 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
Quando serve

ckfile, 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
Quando serve

sigtx/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
Quando serve

2024.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
Quando serve

Ex.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" -print

Python: walk + stat + hash

Codice
Quando serve

Ex.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

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]