Punti 1 (10) - Dipartimento di Informatica

Transcript

Punti 1 (10) - Dipartimento di Informatica
Nome:
Matricola:
ID:
Cognome:
Firma:
Login:
Università di Salerno
Dip. Informatica ed Appl.
26 Novembre 2007
Appello Novembre 07 – LSO – Prova scritta ()
Docente: Ferdinando Cicalese e Ivan Visconti
Durata: 120 minuti
Il presente esame consiste di 15 pagine e 8 quesiti. Segnalare qualsiasi discrepanza alla
commissione. Il numero in parentesi all’inizio di ciascun quesito corrisponde al numero di
punti assegnati ad una risposta corretta.
Riservato alla commissione:
Punti
1
2
3
4
5
6
7
8
Totale
(10)
(15)
(20)
(20)
(15)
(12)
(8)
(8)
(108)
pagina 2
1. [10] Commentare dettagliatamente i seguenti comandi BASH.
1) /home/lso==>cp /bin/cat pippo
2) /home/lso==>ln pippo pluto
3) /home/lso==>ln -s pluto topolino
4) /home/lso==>pippo pluto | pluto | topolino > paperino
5) /home/lso==>echo topolino
6) /home/lso==>echo $topolino
7) /home/lso==>paperino topolino
8) /home/lso==>echo $paperino
9) /home/lso==>echo paperino
10) /home/lso==>cat paperino
Soluzione. Il primo comando copia il file /bin/cat in pippo. Il secondo crea un
hard link a pippo di nome pluto. Il terzo comando crea un link simbolico al file
pluto, di nome topolino. Il quarto comando esegue pippo con argumento pluto, cioe’
esegue il comando cat con il nome dell’eseguibile stesso come argommento a riga di
comando; l’output viene rediretto all’eseguibile pluto (sempre il comando cat) il cui
output viene poi passato come input a topolino (sempre comando cat), il cui output
viene memorizzato nel file paperino. Tale file sara’ quindi una copia di /bin/cat. Il
quinto comando stampa a video la parola topolino, il sesto non stampa nulla perche’
la variabile topolino non esiste. Il settimo ritorna un errore perche’ paperino non e’ un
eseguibile. L’ottavo non stampa nulla perche’ la variabile paperino non esiste, il nono
comando stampa la parola paperino. Il decimo comando stampa i caratteri del testo
dell’eseguibile /bin/cat che sono stati copiati in precedenza in paperino
pagina 3
2. [15]
Scrivere uno script BASH che riceve come argomento (su riga di comando) il nome
di un file; se tale nome termina con “.exe”, il file viene esguito, se invece tale nome
termina con “.c” il file viene compilato generando un eseguibile che ha lo stesso nome
ma non ha l’estensione. Se termina in modo diverso, lo script termina restituendo
l’anomalia.
Soluzione.
#/bin/bash
extc=${1%.c}
extt=${1%.exe}
if [ "$extc.c" = $1 ]; then
gcc -o $extc $1
./$extc
elif [ "$extt.exe" = $1 ]; then
./$1
else
exit 1
fi
pagina 4
3. [20] Scrivere due programmi C che ogni 5 secondi leggono un pid dal file “/tmp/test”
se esiste, ed in caso affermativo il primo programma manda il segnale SIGUSR1 al
processo con tale pid, mentre il secondo programma manda il segnale SIGUSR2 al processo con tale pid. Il primo programma termina se riceve il segnale SIGUSR2, mentre
il secondo termina se riceve il segnale SIGUSR1. Si assume che se il file “/tmp/test”
esiste contiene solo un pid. E’ sufficiente scrivere solo uno dei due programmi e dire
cosa bisogna cambiare per ottenere l’altro programma. Supponendo che i 2 processi
siano in esecuzione, dire come si puo’ terminare uno dei 2 processi dalla shell BASH,
senza utilizzare comandi il cui proposito e’ terminare processi.
Soluzione.
#include<signal.h>
#include<stdio.h>
void gestisci(int sig) {
if (sig==SIGUSR2)
exit(0);
}
// SIGUSR1 per l’altro
int main() {
int pid;
FILE *fd;
signal(SIGUSR2,&gestisci); // SIGUSR1 per l’altro
while(1) {
sleep(5);
fd=fopen("/tmp/test","r");
if (fd==NULL) continue;
fscanf(fd,"%d",&pid);
kill(pid,SIGUSR1); // SIGUSR2 per l’altro
fclose(fd);
}
}
Col comando “ps” si ottengono i pid dei 2 processi, se ne sceglie uno e lo si assegna
alla variabile pid. Poi il comando “echo $pid > /tmp/test” conclude l’opera.
pagina 5
4. [20] Scrivere un programma che risale il file system [dalla directory corrente a quella
padre, a quella padre della directory padre etc.] fino a quando una delle due condizioni
seguenti si verifica: raggiunge una directory che contiene il file ”arrivo.finish” oppure
raggiunge la directory ”root” ed essa non contiene il file ”arrivo.finish” Nel primo caso,
stampa a video i primi 10 caratteri di ”arrivo.finish” e li ricopia in coda al file. Nel
secondo caso, stampa a video ”arrivo.finish non e’ stato trovato, lo creo nella directory
corrente” quindi setta la directory di lavoro a quella da cui era partito e crea il file
”arrivo.finish” nel quale scrive il path della directory corrente.
Soluzione.
int main(void)
{
char name_dir[1000];
char name_dir_start[1000];
char buf[20];
int fd;
getcwd(name_dir_start, 1000);
while(1)
{
getcwd(name_dir, 1000);
printf("\n la directory corrente: %s\n", name_dir);
if((fd = open("arrivo.finish", O_RDWR | O_APPEND)) > 0)
{
if(read(fd, buf, 10) == 10)
{ printf("\n I primi dieci caratteri del file sono: %s\n", buf);
write(fd, buf, 10);
exit(0);
}
else
exit(0);
/* Errore in lettura */
}
else if(errno == ENOENT)
{
if(strcmp(name_dir, "/") == 0)
{
printf("\n File non trovato, e sono in root. Lo creo\n");
if((fd = open("arrivo.finish", O_RDWR | O_APPEND | O_CREAT, 0422)) > 0)
{
write(fd, name_dir_start, 100);
exit(0);
}
else
exit(0); /* Creazione fallita */
}
else{
printf("\nFile non trovato risalgo il file system\n");
chdir("..");
}
}
else exit(0) /* ERRORE: Il file sembra esistere ma non puo essere aperto */
}
}
pagina 6
5. [15] Scrivere un programma che continua ad eseguire fork() fino a quando uno dei
processi generati non riceve pid uguale o maggiore di 1000. Tutti i processi generati
che hanno pid minore di 1000 terminano immediatamente dopo la loro creazione senza
far nulla. Quando un processo con pid non minore di 1000 viene generato, tale processo,
chiamiamolo A, genera tre figli, detti B, C, D, aspetta che essi terminino e poi termina.
I processi B, C, D, generano prima 3 figli ciascuno, aspettano che essi terminino e quindi
terminano. I figli di B,C,D, scrivono a video il proprio pid e terminano.
Soluzione.
int main(void)
{
int pid=1, pid_1, pid_2, pid_3, mypid;
while(pid < 1000)
{
pid = fork();
if(pid >0) /* padre */
{
waitpid(pid, NULL, 0);
}
else /* figlio */
{
mypid = getpid();
if(mypid < 1000)
exit(0);
else
{
pid_1 = fork();
if(pid_1 > 0)
{
pid_2 = fork();
if(pid_2 > 0)
{
pid_3 = fork();
if(pid_3 > 0)
{
waitpid(pid_3, NULL, 0);
waitpid(pid_2, NULL, 0);
waitpid(pid_1, NULL, 0);
exit(0);
}
else
{ printf("\n Il mio pid : %d\n", getpid()); exit(0); }
}
else
{ printf("\n Il mio pid : %d\n", getpid()); exit(0); }
}
else
{ printf("\n Il mio pid : %d\n", getpid()); exit(0); }
}
}
}
}
pagina 7
6. [12] Sia programma l’eseguibile corrispondente al seguente codice:
extern char **environ;
char *pippo;
int i;
void chiudi(void)
{
printf("%s %s", getenv("TTT"), pippo+2);
}
int main(int argc, char **argv)
{
int
pid, times;
atexit(chiudi);
pippo = argv[0];
if(getenv("TTT") == NULL)
setenv("TTT", getenv("PATH"), 1);
sscanf(getenv("TTT"), "%d", &times);
for(i=1; i<= times; i++)
pid = fork();
if(pid == 0)
{
printf("\n We are now terminating %s
exit(0);
}
_exit(0);
%s:
", getenv("AAA"), pippo);
}
Cosa succede nei seguenti tre casi se si eseguono i corrispondenti comandi BASH in
sequenza?
Caso A:
>
>
>
>
AAA="prima esecuzione di "
TTT=3
PATH=4
programma
pagina 8
Caso B:
> AAA="seconda esecuzione di "
> TTT=10
> programma
Caso C:
AAA="ultima esecuzione di "
PATH="tre"
programma
Soluzione.
Caso A:
We
We
We
We
We
We
We
We
are
are
are
are
are
are
are
are
now
now
now
now
now
now
now
now
terminating
terminating
terminating
terminating
terminating
terminating
terminating
terminating
(null)
(null)
(null)
(null)
(null)
(null)
(null)
(null)
./programma:
./programma:
./programma:
./programma:
./programma:
./programma:
./programma:
./programma:
4
4
4
4
4
4
4
4
programma
programma
programma
programma
programma
programma
programma
programma
now
now
now
now
now
now
now
now
terminating
terminating
terminating
terminating
terminating
terminating
terminating
terminating
(null)
(null)
(null)
(null)
(null)
(null)
(null)
(null)
./programma:
./programma:
./programma:
./programma:
./programma:
./programma:
./programma:
./programma:
4
4
4
4
4
4
4
4
programma
programma
programma
programma
programma
programma
programma
programma
Caso B:
We
We
We
We
We
We
We
We
are
are
are
are
are
are
are
are
Caso C: Non stampa nulla perché in questo caso TTT risulta ancora (null) e PATH
viene trasformato nell’intero 0. Quindi il programma non cicla e non stampa nulla.
pagina 9
7. [8] (a) Qual è la differnza tra standard ed implementazioni di UNIX?
(b) Cosa si intende per limite di sistema.
(c) In che modo uno standard ed un’implementazione influiscono sui limiti di sistema?
8. [8] È possibile modificare il flag close on exec di un file descriptor esistente? Se si,
fornire un modo per farlo.
Soluzione.
pagina 10
Referenze utili:
struct stat{
mode_t
st_mode;
uid_t
st_uid;
gid_t
st_gid;
nlink_t
st_nlink;
off_t
st_size;
blksize_t stblksize;
}
union semun{
int val;
struct semid_ds *buf;
ushort
*array;
}
struct sembuf {
unsigned short sem_num; /* semaphore number */
short
sem_op;
/* semaphore operation */
short
sem_flg; /* operation flags */
}
struct mymesg {
long mtype; /* positive message type */
char mtext[512]; /* message data of length nbytes */
}
int pipe(int filedes[2]);
valori costanti utili per shmflg, msgget, e semget: IPC_CREAT, IPC_EXCL
altre costanti utili per IPC COMMUNICATION: IPC_RMID, IPC_SET,
IPC_STAT, GETVAL, SETVAL, SETALL, GETALL, SETALL, IPC_{NOWAIT}
void *shmat(int shmid, const void *shmaddr, int shmflg);
int shmdt(const void *shmaddr);
int semget(key_t key, int nsems, int semflg);
int semop(int semid, struct sembuf *sops, unsigned nsops);
int semctl(int semid, int semnum, int cmd, union semum arg);
int msgget(key_t key, int flag);
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
int msgsnd(int msqid, const void *ptr, size_t nbytes, int flag);
ssize_t msgrcv(int msqid, void *ptr, size_t nbytes, long type, int flag);
int mkfifo(const char *pathname, mode_t mode);
FILE *popen(const char *command, const char *type);
int pclose(FILE *stream);
int select(int n, fd_set *r, fd_set *w, fd_set *ex, struct timeval *timeout);
int open(const char *pathname, int flags);
ssize_t read(int fd, void *buf, size_t count);
ssize_t write(int fd, const void *buf, size_t count);
pagina 11
off_t lseek(int fd, off_t offset, int whence);
valori per whence: SEEK_SET, SEEK_CUR, SEEK_END
int dup2(int oldfd, int newfd);
int dup(int oldfd);
int stat(const char *file_name, struct stat *buf);
costanti usate con stat()
S_IRUSR, S_ISUID, S_ISGID, S_IWUSR,
S_IXUSR, S_IWOTH, S_IXOTH, S_IRGRP
int link(const char *path, const char *newpath);
int symlink(const char *path, const char *sympath);
int readlink(const char *path, char *buf, int *bufsize);
int unlink(const char *pathname);
int mkdir(const char *pathname, mode_t mode);
int rmdir(const char *pathname);
int chdir(const char *pathname);
char *getcwd(char *buf, size_t size);
DIR *opendir(const char *name);
int closedir(DIR *dir);
struct dirent *readdir(DIR *dir);
campo di struct dirent: char d_name[];
int fgetc(FILE *fp);
int fcntl(int fd, int cmd, int arg)
int fputc(int c, FILE *fp);
int fgets(char *buf, int size, FILE *fp);
int fputs(char *str, FILE *fp);
int sprintf(char *buf, const char *format, ...);
pid_t fork(void);
pid_t getpid(void);
pid_t getppid(void);
uid_t getuid(void);
uid_t geteuid(void);
pid_t wait(int *status);
pid_t waitpid(pid_t pid, int *status, int options);
int pause(void);
int pipe(int *fd)
int execve(const char *filename, char *const argv [], char *const envp[]);
int execle(const char *filename, const char *argv0, ../* (char *) 0, char *const envp[]*/);
unsigned int sleep(unsigned int seconds);
unsigned int alarm(unsigned int seconds);
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
int kill(pid_t pid, int signo);
int raise(int signo);
pagina 12
Potete utilizzare questa pagina per completare esercizi che dovessero richiedere piu’
spazio.
pagina 13
Potete utilizzare questa pagina per completare esercizi che dovessero richiedere piu’
spazio.
pagina 14
Potete utilizzare questa pagina per completare esercizi che dovessero richiedere piu’
spazio.
pagina 15
Potete utilizzare questa pagina per completare esercizi che dovessero richiedere piu’
spazio.
Fine dell’esame
Pagine totali: 15
Punti totali: 108