Difference between revisions of "Prova pratica 2015.01.21"
| m | m (Aggiunte soluzioni da altre pagine, uniformato) | ||
| Line 1: | Line 1: | ||
| Testo: [http://www.cs.unibo.it/~renzo/so/pratiche/2015.01.21.pdf] | Testo: [http://www.cs.unibo.it/~renzo/so/pratiche/2015.01.21.pdf] | ||
| − | Esercizio 1 | + | ==Esercizio 1== | 
| − | + | ===Soluzione di Leonardo F=== | |
| <syntaxhighlight lang="C"> | <syntaxhighlight lang="C"> | ||
| //ESERCIZIO 1 | //ESERCIZIO 1 | ||
| Line 57: | Line 57: | ||
| --[[User:LeonardoF|LeonardoF]] ([[User talk:LeonardoF|talk]]) 15:39, 26 March 2017 (CEST)LeonardoF | --[[User:LeonardoF|LeonardoF]] ([[User talk:LeonardoF|talk]]) 15:39, 26 March 2017 (CEST)LeonardoF | ||
| + | |||
| + | ==Esercizio 2== | ||
| + | ===Soluzione di LeonardoF=== | ||
| <syntaxhighlight lang="C"> | <syntaxhighlight lang="C"> | ||
| Line 166: | Line 169: | ||
| --[[User:LeonardoF|LeonardoF]] ([[User talk:LeonardoF|talk]]) 15:39, 26 March 2017 (CEST)LeonardoF | --[[User:LeonardoF|LeonardoF]] ([[User talk:LeonardoF|talk]]) 15:39, 26 March 2017 (CEST)LeonardoF | ||
| − | Esercizio 3  | + | ===Soluzione di Stefano.zaniboni=== | 
| + | <source lang="c"> | ||
| + | #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); | ||
| + | } | ||
| + | |||
| + | |||
| + | </source> | ||
| + | |||
| + | 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]) [[User:Renzo|Renzo]] ([[User talk: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)''' | ||
| + | <source lang="c"> | ||
| + | #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); | ||
| + | 	} | ||
| + | } | ||
| + | </source> | ||
| + | |||
| + | |||
| + | |||
| + | '''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 <code>char sono_forse_inutile[4096]</code> 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. | ||
| + | |||
| + | <source lang="c"> | ||
| + | #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); | ||
| + | }</source> | ||
| + | --[[User:Ale|Ale]] ([[User talk:Ale|talk]]) 14:01, 25 May 2015 (CEST) | ||
| + | |||
| + | |||
| + | ==Esercizio 3== | ||
| + | |||
| + | ===Soluzione di LeonardoF bash=== | ||
| <syntaxhighlight lang="Bash"> | <syntaxhighlight lang="Bash"> | ||
| Line 184: | Line 451: | ||
| --[[User:LeonardoF|LeonardoF]] ([[User talk:LeonardoF|talk]]) 15:39, 26 March 2017 (CEST)LeonardoF | --[[User:LeonardoF|LeonardoF]] ([[User talk:LeonardoF|talk]]) 15:39, 26 March 2017 (CEST)LeonardoF | ||
| − | + | ===Soluzione di LeonardoF script Python=== | |
| <syntaxhighlight lang="Python"> | <syntaxhighlight lang="Python"> | ||
| Line 250: | Line 517: | ||
| --[[User:LeonardoF|LeonardoF]] ([[User talk:LeonardoF|talk]]) 15:39, 26 March 2017 (CEST)LeonardoF | --[[User:LeonardoF|LeonardoF]] ([[User talk:LeonardoF|talk]]) 15:39, 26 March 2017 (CEST)LeonardoF | ||
| − | + | ===Soluzione di S.G python=== | |
| <syntaxhighlight lang="Python"> | <syntaxhighlight lang="Python"> | ||
Revision as of 09:21, 9 May 2017
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
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)
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)