Difference between revisions of "Prova pratica 2015.01.21"
m |
m (Aggiunta soluzione di un'altro studente) |
||
(6 intermediate revisions by 2 users not shown) | |||
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 3 | + | ==Esercizio 1== |
+ | ===Soluzione di Leonardo F=== | ||
+ | <syntaxhighlight lang="C"> | ||
+ | //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); | ||
+ | } | ||
+ | } | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | --[[User:LeonardoF|LeonardoF]] ([[User talk:LeonardoF|talk]]) 15:39, 26 March 2017 (CEST)LeonardoF | ||
+ | |||
+ | ===Soluzione di Luca=== | ||
+ | <source lang="c"> | ||
+ | #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); | ||
+ | } | ||
+ | </source> | ||
+ | |||
+ | ==Esercizio 2== | ||
+ | ===Soluzione di LeonardoF=== | ||
+ | |||
+ | <syntaxhighlight lang="C"> | ||
+ | //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]); | ||
+ | |||
+ | } | ||
+ | } | ||
+ | |||
+ | } | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | --[[User:LeonardoF|LeonardoF]] ([[User talk:LeonardoF|talk]]) 15:39, 26 March 2017 (CEST)LeonardoF | ||
+ | |||
+ | ===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) | ||
+ | |||
+ | ===Soluzione di Luca=== | ||
+ | <source lang="c">#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); | ||
+ | } | ||
+ | </source> | ||
+ | |||
+ | ==Esercizio 3== | ||
+ | |||
+ | ===Soluzione di LeonardoF bash=== | ||
+ | |||
+ | <syntaxhighlight lang="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 | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | --[[User:LeonardoF|LeonardoF]] ([[User talk:LeonardoF|talk]]) 15:39, 26 March 2017 (CEST)LeonardoF | ||
+ | |||
+ | ===Soluzione di LeonardoF script Python=== | ||
+ | |||
+ | <syntaxhighlight lang="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:]) | ||
+ | |||
+ | </syntaxhighlight> | ||
+ | |||
+ | --[[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"> | ||
Line 56: | Line 673: | ||
'''perché proporre una soluzione in un linguaggio che non ho ancora spiegato?'''[[User:Renzo|Renzo]] ([[User talk:Renzo|talk]]) 19:36, 21 November 2016 (CET) | '''perché proporre una soluzione in un linguaggio che non ho ancora spiegato?'''[[User:Renzo|Renzo]] ([[User talk:Renzo|talk]]) 19:36, 21 November 2016 (CET) | ||
+ | |||
+ | ===Soluzione di Luca(Bash)=== | ||
+ | <source lang="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 | ||
+ | </source> |
Latest revision as of 08:25, 10 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
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