Prova pratica 2015.01.21
Testo: [1]
Esercizio 1
Soluzione di Leonardo F
//ESERCIZIO 1
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include "execs.h" // from https://github.com/rd235/s2argv-execs
#define BUFFLEN 4096 //probably there is a system constant
int main(int argc,const char* argv[]){
//take the path name and open the file
FILE* fd = fopen(argv[1],"r");
//read the the file and put its content in a array of pointers
char commands[2][BUFFLEN]; //migliorabile
char buffer[BUFFLEN];
int i = 0;
while (fgets(buffer,sizeof(buffer),fd) != NULL){
strcpy(commands[i],buffer);
i ++;
}
//printf("%s\n%s\n",commands[0],commands[1] );
//create a pipe
int fpipe[2];
pipe(fpipe); //0 reading,1 writing
//fork
int pid;
pid = fork();
switch (pid){
case 0 : //children
close(fpipe[0]);
//children's stout = pipe output
dup2(fpipe[1],STDOUT_FILENO);
close(fpipe[1]);
//execution of the command
execsp(commands[0]);
exit(-1); // in case of execsp failure
default : //parent
close(fpipe[1]);
//father's stdin = pipe input
dup2(fpipe[0],STDIN_FILENO);
close(fpipe[0]);
//receive the comnmand
execsp(commands[1]);
exit(-1);
}
}
--LeonardoF (talk) 15:39, 26 March 2017 (CEST)LeonardoF
Soluzione di Luca
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <s2argv.h>
#include <string.h>
int main(int argc, char *argv[]){
int pfd[2];
FILE *file=fopen(argv[1], "r");//apro file in lettura
char cmd1[256];
char cmd2[256];
fgets(cmd1, sizeof(cmd1), file);//memorizzo il primo comando in cmd1
fgets(cmd2, sizeof(cmd2), file);//memorizzo il 2 comando in cmd2
pipe(pfd);//creo i 2 descrittori
switch(fork()){
case 0: //figlio fornisce output
dup2(pfd[1], STDOUT_FILENO);
close(pfd[0]);
close(pfd[1]);
execsp(cmd1);
exit(1);
case -1: exit(1);
}
switch(fork()){//figlio prende input
case 0:
dup2(pfd[0], STDIN_FILENO);
close(pfd[0]);
close(pfd[1]);
execsp(cmd2);
exit(1);
case -1: exit(1);
}
int status;
close(pfd[0]);
close(pfd[1]);
wait(&status);
wait(&status);
fclose(file);
}
Esercizio 2
Soluzione di LeonardoF
//ESERCIZIO 2
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "execs.h" // from https://github.com/rd235/s2argv-execs
#define AOS_LENSTEP 8
/*
* Define a struct for managing and array of pointer to strings.
*/
struct array_of_strings {
char **strings;
size_t currentlength; //the length of number of string in memory
size_t arraylength; //the length of memory allocated
};
typedef struct array_of_strings array_of_strings;
void array_of_strings_add(array_of_strings *arrayOfStrings, char *string) {
//if there is not enough space for the string increase it
if (arrayOfStrings->currentlength >= arrayOfStrings->arraylength) {
//increase the array length by the size of a string pointer
size_t newlength = arrayOfStrings->arraylength + AOS_LENSTEP;
//reallocate the arrayOfString with the new size
char **new_string = realloc(arrayOfStrings->strings, newlength * sizeof(arrayOfStrings->strings[0]));
//if the reallocation is successful
if (new_string != NULL) {
arrayOfStrings->arraylength = newlength;
arrayOfStrings->strings = new_string;
}
}
//if there is enough space for the string insert it
if (arrayOfStrings->currentlength < arrayOfStrings->arraylength)
//strdup return a pointer to a duplicate of the string
arrayOfStrings->strings[arrayOfStrings->currentlength++] = strdup(string);
}
void array_of_strings_print(array_of_strings *v) {
size_t i;
for (i = 0; i < v->currentlength; i++)
printf("[%3lu]: %s\n", i, v->strings[i]);
}
int main(int argc, char *argv[]) {
int commandNumber= 0;
char* line = NULL;
size_t lineLength = 0;
ssize_t numberOfCharactersRead;
static array_of_strings arrayOfStrings;
FILE* fd = fopen(argv[1],"r");
while ((numberOfCharactersRead = getline(&line, &lineLength, fd)) >= 0) {
if (line[numberOfCharactersRead - 1] == '\n')
line[numberOfCharactersRead - 1] = 0;
array_of_strings_add(&arrayOfStrings, line);
commandNumber ++;
}
free(line);
//array_of_strings_print(&arrayOfStrings);
//printf("%d\n",commandNumber );
//open the pipe
int fpipe[2];
pipe(fpipe); //0 reading,1 writing
int i = 0;
while(commandNumber > 0 ){
if(commandNumber > 1) {
int pid = fork();
switch(pid){
case 0: //children
close(fpipe[0]);
//children's stout = pipe output
dup2(fpipe[1],STDOUT_FILENO);
close(fpipe[1]);
//execution of the command
//usleep( commandNumber* 1000000);
execsp(arrayOfStrings.strings[i]);
exit(-1);
default: //parent
commandNumber --;
i ++;
break;
}
}
else{ //last command
close(fpipe[1]);
//father's stdin = pipe input
dup2(fpipe[0],STDIN_FILENO);
close(fpipe[0]);
//receive the comnmand
execsp(arrayOfStrings.strings[i]);
}
}
}
--LeonardoF (talk) 15:39, 26 March 2017 (CEST)LeonardoF
Soluzione di Stefano.zaniboni
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <error.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[]){
int mypipe[2];
FILE *stream;
char *line=NULL;
size_t len=0;
ssize_t read;
/*controllo il numero degli argomenti passati*/
if(argc != 2){
fprintf(stderr, "no such arguments \n");
exit(1);
}
/*apro il file in sola lettura*/
stream=fopen(argv[1], "r");
if(stream==NULL){
exit(EXIT_FAILURE);
}
/*apro la pipe*/
if(pipe(mypipe) == -1){
fprintf(stderr, "Error pipe\n");
exit (1);
}
if(fork()==0){
close(1); /*chiudo lo stdout*/
dup(mypipe[1]); /*rimpiazzo lo stdout con la pipe*/
close(mypipe[0]); /*chiudo la read della pipe*/
close(mypipe[1]);
read=getline(&line, &len, stream);
char *lines[2]={line, NULL};
execvp(argv[1], lines);
perror("execvp failed");
exit (1);
}
if(fork()==0){
close(0); /*chiudo lo stdin*/
dup(mypipe[0]); /*rimpiazzo lo stdin con la pipe read*/
close(mypipe[1]); /*chiudo la write della pipe*/
close(mypipe[0]);
read=getline(&line, &len, stream);
execvp(argv[1], &line);
perror("execvp 2 failed");
exit (1);
}
close(mypipe[0]);
close(mypipe[1]);
wait(0);
wait(0);
free(line);
fclose(stream);
exit (0);
}
Il codice ho provato a testarlo ma la shell mi restituisce sempre su entrambe le exec "Permission Denied".
Nota del Prof: execvp(argv[1], &line) tenta di eseguire il file di testo (argv[1]) Renzo (talk) 16:04, 7 April 2015 (CEST)
Soluzione di AleZ
Nota: ho messo la soluzione di questo esercizio solamente perché non ne ho trovata sulla wiki una versione funzionante. Non so se sia stato corretto in classe e/o se sia stato già postato da qualche altra parte. Nel caso mi scuso.
Due versioni: una utilizzando la libreria s2argv e la funzione getline, l'altra senza entrambe.
Versione 1 (con s2argv e getline)
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "/home/alessandro/Scrivania/s2argv/s2argv.h"
int main(int argc, char *argv[]) {
//check arguments
if (argc != 2) {
fprintf(stderr, "Error: Expected 1 parameter.\n"
"Usage: %s <pathname>\n", argv[0]);
return(EXIT_FAILURE);
}
FILE *f;
size_t n;
int fd[2];
char *command = NULL;
f = fopen(argv[1], "rt");
//get first command
getline(&command, &n, f);
//create the pipe
if (pipe(fd) == -1) {
perror("pipe");
return(EXIT_FAILURE);
}
//create child process
switch (fork()) {
case -1:
perror("fork");
break;
case 0: //child process
close(fd[0]);
dup2(fd[1], STDOUT_FILENO); //redirect STDOUT to write to fd[1]->fd[0]
execsp(command);
return(EXIT_FAILURE);
default:
close(fd[1]);
dup2(fd[0], STDIN_FILENO); //redirect STDIN to read from fd[0]<-fd[1]
wait(NULL); //wait for child to terminate
lseek (fd[1], 0, SEEK_SET); //reposition STDOUT read offset to the start
free(command);
command = NULL;
getline(&command, &n, f); //get second command
execsp(command);
return(EXIT_FAILURE);
}
}
Versione 2 (senza s2argv e getline)
Nota 2: Nella versione senza s2argv e getline, tutto funziona, però ho un "problema" incredibilmente strano: se cancello la variabile char sono_forse_inutile[4096]
dichiarata a riga 48, a run-time il programma restituisce segmentation fault. Quella variabile era stata introdotta in precedenza inizialmente per diversa scelta implementativa, e in seguito mantenuta per scopi di debug. Terminata la sua utilità, avevo pensato di rimuoverla, ma a quanto pare non mi è permesso, e il motivo mi sfugge davvero.
La funzione fsplit è stata realizzata prendendo largamente spunto da un'altra funzione trovata su stackoverflow.
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <string.h>
#include <unistd.h>
char **fsplit(char **res, char str[]) {
char *p = strtok(str, " ");
int n_spaces = 0;
/* split string and append tokens to "res" */
while (p) {
n_spaces++;
res = realloc(res, sizeof(char*) * n_spaces);
if (res == NULL)
exit(EXIT_FAILURE); //allocation failed
res[n_spaces - 1] = p;
p = strtok(NULL, " ");
}
/* realloc one extra element for the last NULL */
res = realloc(res, sizeof(char*) * (n_spaces + 1));
res[n_spaces] = NULL;
// debug purpose
/* int i;
for (i = 0; i < (n_spaces + 1); i++) {
printf ("res[%d] = %s\n", i, res[i]);
}*/
return res;
}
int main (int argc, char* argv[]) {
//check arguments
if (argc != 2) {
fprintf(stderr, "Error: Expected 1 parameter.\n"
"Usage: %s <pathname>\n", argv[0]);
return(EXIT_FAILURE);
}
char *pathname = argv[1];
FILE *f;
struct stat f_info;
char command_one[100], command_two[100], sono_forse_inutile[4096];
int fd[2], file_desc_out;
pid_t pid;
f = fopen(pathname, "rt");
//check if file exists
if(lstat(pathname, &f_info) == -1) {
perror("stat");
return(EXIT_FAILURE);
}
//read the commands from the first two lines - ignore the other lines
if ( (fgets(command_one, 100, f) == NULL) ||
(fgets(command_two, 100, f) == NULL) ) {
fprintf(stderr, "Error while reading text from %s.", argv[1]);
}
fclose(f);
//remove the \n patterns from the command strings
strtok(command_one, "\n");
strtok(command_two, "\n");
/*split the command strings in arrays, where
- comm[0] is the command
- comm[1], comm[2], etc, are the arguments*/
char **commv_1 = fsplit(commv_1, command_one);
char **commv_2 = fsplit(commv_2, command_two);
//create the pipe
//remember: fd[0] reads and fd[1] writes
if (pipe(fd) == -1) {
perror("pipe");
return(EXIT_FAILURE);
}
//create the child and get its pid
if ( (pid = fork()) == -1) {
perror("fork");
return(EXIT_FAILURE);
}
if (pid == 0) { //child
dup2(fd[1], STDOUT_FILENO); //connect pipe from execvp to standard output
close(fd[0]); //close read side from parent
execvp(commv_1[0], commv_1);
perror(commv_1[0]);
return(EXIT_FAILURE);
} else {
close(fd[1]); //close write side from child
dup2(fd[0], file_desc_out);
char *path;
// obtain absolute path of the reader-side file descriptor of the pipe
realpath("/proc/self/fd/file_desc_out", path);
commv_2[1] = path; //set the obtained path as argument for command 2
wait(NULL); //wait for child to terminate
}
execvp(commv_2[0], commv_2);
perror(commv_2[0]);
return(EXIT_FAILURE);
}
--Ale (talk) 14:01, 25 May 2015 (CEST)
Soluzione di Luca
#include <stdio.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <s2argv.h>
#include <string.h>
int main(int argc, char *argv[]){
int pfd[2], num_righe=0, tmp=0;
FILE *file=fopen(argv[1], "r");//apro file in lettura
char buff[256];
pipe(pfd);
while(fgets(buff, sizeof(buff), file)!=NULL){//calcolo il numero di righe del file
num_righe++;
}
char comandi[num_righe][256];//array di stringhe
rewind(file);
for(tmp=0; tmp<num_righe; tmp++){
fgets(comandi[tmp], sizeof(comandi[tmp]), file);//copio ogni comando per riga
//printf("comando num %d: %s\n", tmp, comandi[tmp]);
switch(fork()){
case 0:
if(tmp<num_righe-1){
dup2(pfd[1], STDOUT_FILENO);
close(pfd[0]);
close(pfd[1]);
execsp(comandi[tmp]);
exit(1);
}
if(tmp==num_righe-1){
dup2(pfd[0], STDIN_FILENO);
close(pfd[0]);
close(pfd[1]);
execsp(comandi[tmp]);
exit(1);
}
case -1: exit(1);
}
}
int status;
close(pfd[0]);
close(pfd[1]);
for(tmp=0; tmp<num_righe; tmp++)
wait(&status);
fclose(file);
}
Esercizio 3
Soluzione di LeonardoF bash
#!/bin/bash
#ESERCIZIO 3
find $1 -exec md5sum {} \; |sort | uniq --all-repeated=separate --check-chars=32
shift
for i in $@ ; do
find $1 -exec md5sum {} \; |sort | uniq --all-repeated=separate --check-chars=32
shift
done
--LeonardoF (talk) 15:39, 26 March 2017 (CEST)LeonardoF
Soluzione di LeonardoF script Python
#!/usr/bin/env python3
#ESERCIZIO 3
import sys
# os.syscall way to use linux syscalls
import os
import hashlib
dictionary = {}
def add(md5val,path):
"""function that insert the given file path in a dictionary
using as key the given md5sum"""
#in this way i avoid duplicates
dictionary.setdefault(md5val,set()).add(path)
def md5add(path):
"""function that takes a filepath and calculate is md5sum
then it calls a function to insert the file in a dictionary"""
md5val = hashlib.md5()
with open(path, "rb") as f:
#Note that sometimes you won't be able to fit the whole file in memory.
#In that case, you'll have to read chunks of 4096 bytes sequentially and feed them to the Md5 function:
for chunk in iter(lambda: f.read(4096), b""):
md5val.update(chunk)
add(md5val.hexdigest(),path)
def movmd5add(path):
"""recursive fuction that moves in the file system and call the mdadd function
it takes a path in input (main checks the path given by the user) """
for root, dirs, files in os.walk(path):
for f in files:
#if file call the function for the md5sum
md5add(os.path.join(root,f)) # os.path.join(root,f)
def printdict():
"""funtion that prints the dictionary"""
for x in dictionary:
#doesn't print single lines
if len(dictionary[x]) > 1 :
print('\r')
for y in dictionary[x]:
print(x," : ",y)
def main(args):
"""main checks the path and call the functions"""
if len(args) < 1:
args = "."
for path in args:
movmd5add(path)
printdict()
if __name__ == "__main__":
main(sys.argv[1:])
--LeonardoF (talk) 15:39, 26 March 2017 (CEST)LeonardoF
Soluzione di S.G python
#!/usr/bin/python
"""
Esercizio 3: Script bash o Python: (10 punti):
Scrivere un programma python o uno script bash che scandisca il sottoalbero relativo alle directory passate come
parametri (o alla direcotry corrente se non ci sono parametri) e fornisca in output l'elenco dei file che hanno la
stessa somma MD5 (i.e. l'output del comando md5sum).
In output ogni riga deve mostrare un elenco di pathname realtivi a file che hanno la stessa somma MD5 (che quindi
sono molto molto probabilmente uguali).
"""
import sys
import os
import hashlib
def sha1sum(root, filename):
sha1 = hashlib.sha1()
with open(os.path.join(root, filename), "rb") as thefile:
buf = thefile.read()
sha1.update(buf)
return sha1.hexdigest()
def initSha1vect(path):
""" Inizializza il dizionario utilizzando come chiave il sha1
del file, e come valore il percorso del file. """
shafiles = {}
for root, dirs, files in os.walk(path):
for file in files:
shaKey = sha1sum(root, file)
shafiles.setdefault(shaKey, [])
shafiles[shaKey].append(file)
return shafiles
def main(args):
for path in args:
msg = True
print "\n", path
shafiles = initSha1vect(path)
for k in shafiles:
if len(shafiles[k]) > 1:
msg = False
print k, "\t", shafiles[k]
if msg:
print "Nessun file con lo stesso sha1"
if __name__ == "__main__":
main(sys.argv[1:])
S.G (talk) 14:39, 18 November 2016 (CET)
Ho scritto una possibile soluzione dell'esercizio 3
perché proporre una soluzione in un linguaggio che non ho ancora spiegato?Renzo (talk) 19:36, 21 November 2016 (CET)
Soluzione di Luca(Bash)
#! /bin/bash
trova () {
find $1 -type f -exec md5sum {} \; | sort > md5.txt #calcola l'md5 di tutto il sottoalbero, lo ordina e lo salva in un file
cat md5.txt | grep "`cut -d ' ' -f 1 md5.txt | uniq -d`" #stampa le righe del file, nelle quali in primo campo ha valore(md5) duplicato
}
if [[ $# -eq 0 ]] ; then #se num argomenti è 0
trova
else
for parametro in $* #chiamo la funzione per ogni argomento
do
trova $parametro
done
fi
exit