Difference between revisions of "ProvaPratica 2013.07.18"
		
		
		
		
		
		Jump to navigation
		Jump to search
		
				
		
		
	
| m (Aggiunte soluzioni da altre pagine, uniformato) | |||
| (38 intermediate revisions by 6 users not shown) | |||
| Line 1: | Line 1: | ||
| + | == Esercizio 1 == | ||
| + | ===Soluzione di Tommaso Ognibene=== | ||
| + | <syntaxhighlight lang="C"> | ||
| + | /* | ||
| + | Prova Pratica di Laboratorio di Sistemi Operativi | ||
| + | 18 luglio 2013 | ||
| + | Esercizio 1 | ||
| + | |||
| + | URL: http://www.cs.unibo.it/~renzo/so/pratiche/2013.07.18.pdf | ||
| + | |||
| + | @author: Tommaso Ognibene | ||
| + | */ | ||
| + | |||
| + | #include <errno.h> | ||
| + | #include <stdio.h> | ||
| + | #include <stdlib.h> | ||
| + | #include <string.h> | ||
| + | #include <sys/wait.h> | ||
| + | #include <unistd.h> | ||
| + | |||
| + | // Constants | ||
| + | #define MaxNumArguments 10 | ||
| + | #define MaxLenArguments 50 | ||
| + | #define MaxLenPath 100 | ||
| + | #define MaxLenLine MaxLenArguments * MaxNumArguments | ||
| + | #define MaxLenCommands 500 | ||
| + | |||
| + | // Structure for a process element | ||
| + | typedef struct processElem | ||
| + | { | ||
| + | 	char CommandLine[MaxLenCommands]; | ||
| + | 	pid_t Pid; | ||
| + | 	struct processElem *Next; | ||
| + | } ProcessElem; | ||
| + | |||
| + | // Function prototypes | ||
| + | ProcessElem *appendElement    (ProcessElem *tail); | ||
| + | char        *findCommand      (pid_t pid); | ||
| + | void         countTokens      (const char *string, const char delimiter, int *count, int *longest); | ||
| + | int          tokenize         (char *string, char delimiter, char ***tokens, int *count); | ||
| + | void         readMultipleLines(void); | ||
| + | void         runProcesses     (void); | ||
| + | |||
| + | // Global variables | ||
| + | static ProcessElem *ProcessList  = NULL; | ||
| + | int                 ProcessCount = 0; | ||
| + | |||
| + | // Given a PID retrieve the relative command | ||
| + | char *findCommand(pid_t pid) | ||
| + | { | ||
| + | 	ProcessElem *process; | ||
| + | 	for(process = ProcessList; process->Pid != pid; process = process->Next); | ||
| + | 	return (process)? (process->CommandLine) : (NULL); | ||
| + | } | ||
| + | |||
| + | // Create a new element | ||
| + | ProcessElem *appendElement(ProcessElem *tail) | ||
| + | { | ||
| + | 	ProcessElem *newElem = (ProcessElem *)malloc(sizeof(ProcessElem)); | ||
| + | 	newElem->Next = NULL; | ||
| + | 	(tail)? (tail->Next = newElem) : (tail = newElem); | ||
| + | 	return newElem; | ||
| + | } | ||
| + | |||
| + | /* | ||
| + |  * Count tokens and find the longest one | ||
| + |  * Example: | ||
| + |  *    Input: | ||
| + |  *       string = "ping -c 4 google.com" | ||
| + |  *       delimiter = ' ' | ||
| + |  *    Output: | ||
| + |  *       count = 4 | ||
| + |  *       longest = 10 | ||
| + |  */ | ||
| + | void countTokens(const char *string, const char delimiter, int *count, int *longest) | ||
| + | { | ||
| + | 	int iterator, lenght; | ||
| + | 	lenght = *longest = *count = 0; | ||
| + | |||
| + | 	// Count the first (n - 1) tokens | ||
| + | 	for(iterator = 0; string[iterator]; iterator++) | ||
| + | 	{ | ||
| + | 		if(string[iterator] == delimiter) | ||
| + | 		{ | ||
| + | 			if(*longest < lenght) | ||
| + | 				*longest = lenght; | ||
| + | 			lenght = 0; | ||
| + | 			(*count)++; | ||
| + | 		} | ||
| + | 		lenght++; | ||
| + | 	} | ||
| + | |||
| + | 	// Count the last token | ||
| + | 	if(string[iterator - 1] != delimiter) | ||
| + | 	{ | ||
| + | 		lenght--; | ||
| + | 		if(*longest < lenght) | ||
| + | 			*longest = lenght; | ||
| + | 		(*count)++; | ||
| + | 	} | ||
| + | } | ||
| + | |||
| + | /* | ||
| + |  * Tokenize a string accordingly to a given delimiter | ||
| + |  * Example: | ||
| + |  *    Input: | ||
| + |  *       string = "ping -c 4 google.com" | ||
| + |  *       delimiter = ' ' | ||
| + |  *    Output: | ||
| + |  *       tokens = ["ping", "-c", "4", "google.com"] | ||
| + |  *       count = 4 | ||
| + |  */ | ||
| + | int tokenize(char *string, char delimiter, char ***tokens, int *count) | ||
| + | { | ||
| + | 	if(!(tokens && string && count)) return 0; | ||
| + | |||
| + | 	int token, i, j, longest; | ||
| + | 	*count = longest = 0; | ||
| + | |||
| + | 	countTokens(string, delimiter, count, &longest); | ||
| + | |||
| + | 	// Allocate space for array of strings | ||
| + | 	*tokens = (char **)malloc(*count * sizeof(char *)); | ||
| + | |||
| + | 	if(!*tokens) | ||
| + | 	{ | ||
| + | 		perror("malloc()"); | ||
| + | 		exit(EXIT_FAILURE); | ||
| + | 	} | ||
| + | |||
| + | 	// Allocate space for each string in the array and tokenize it | ||
| + | 	i = 0; | ||
| + | 	for(token = 0; token < *count; token++) | ||
| + | 	{ | ||
| + | 		(*tokens)[token] = (char *)malloc(sizeof(char) * (longest + 1)); | ||
| + | |||
| + | 		j = 0; | ||
| + | 		while(string[i] != delimiter && string[i]) | ||
| + | 		{ | ||
| + | 			(*tokens)[token][j] = string[i]; | ||
| + | 			j++; | ||
| + | 			i++; | ||
| + | 		} | ||
| + | |||
| + | 		// Null-terminated string | ||
| + | 		(*tokens)[token][j] = (char)0; | ||
| + | 		i++; | ||
| + | 	} | ||
| + | |||
| + | 	return 1; | ||
| + | } | ||
| + | |||
| + | // Read multiple input lines | ||
| + | void readMultipleLines(void) | ||
| + | { | ||
| + | 	ProcessElem *process = NULL; | ||
| + | 	char input[MaxLenLine]; | ||
| + | 	char *iterator; | ||
| + | |||
| + | 	printf("Enter commands. Press enter on blank line to start them.\n"); | ||
| + | 	while(1) | ||
| + | 	{ | ||
| + | 		// Get input string | ||
| + | 		if(!fgets(input, MaxLenLine, stdin)) | ||
| + | 		{ | ||
| + | 			perror("fgets()"); | ||
| + | 			exit(EXIT_FAILURE); | ||
| + | 		} | ||
| + | |||
| + | 		// Skip blank lines | ||
| + | 		for(iterator = input; *iterator == ' '; iterator++); | ||
| + | |||
| + | 		// Check if enter was pressed on blank line | ||
| + | 		if(*iterator == '\n') break; | ||
| + | |||
| + | 		// Append a new input element | ||
| + | 		if(!(ProcessList)) | ||
| + | 			process = ProcessList = appendElement(ProcessList); | ||
| + | 		else | ||
| + | 		{ | ||
| + | 			process->Next = appendElement(process); | ||
| + | 			process = process->Next; | ||
| + | 		} | ||
| + | 		ProcessCount++; | ||
| + | |||
| + | 		// Eliminate "\n" from the input string | ||
| + | 		iterator = strtok(iterator, "\n"); | ||
| + | |||
| + | 		strcpy(process->CommandLine, iterator); | ||
| + | 	} | ||
| + | } | ||
| + | |||
| + | /* | ||
| + |  * Run child processes -> | ||
| + |  * Print when a child process terminates | ||
| + |  */ | ||
| + | void runProcesses(void) | ||
| + | { | ||
| + | 	pid_t pid; | ||
| + | 	int status, terminated, count; | ||
| + | 	char path[MaxLenPath]; | ||
| + | 	ProcessElem *process = ProcessList; | ||
| + | 	char **command = NULL; | ||
| + | 	terminated = count = 0; | ||
| + | |||
| + | 	// Start processes | ||
| + | 	while(process) | ||
| + | 	{ | ||
| + | 		// Tokenize command line | ||
| + | 		tokenize(process->CommandLine, ' ', &command, &count); | ||
| + | |||
| + | 		// Create path | ||
| + | 		snprintf(path, sizeof path, "%s%s", "/bin/", command[0]); | ||
| + | |||
| + | 		// Create child process | ||
| + | 		pid = fork(); | ||
| + | |||
| + | 		// Check PID | ||
| + | 		switch(pid) | ||
| + | 		{ | ||
| + | 		// Error | ||
| + | 		case -1: | ||
| + | 			perror("fork()"); | ||
| + | 			exit(EXIT_FAILURE); | ||
| + | 		// Child process | ||
| + | 		case 0: | ||
| + | 			// Execute command | ||
| + | 			if (execv(path, command) == -1) | ||
| + | 			{ | ||
| + | 				perror("execv()"); | ||
| + | 				exit(EXIT_FAILURE); | ||
| + | 			} | ||
| + | 			break; | ||
| + | 		// Parent process | ||
| + | 		default: | ||
| + | 			process->Pid = pid; | ||
| + | 		} | ||
| + | 		process = process->Next; | ||
| + | 	} | ||
| + | |||
| + | 	// Wait processes | ||
| + | 	do | ||
| + | 	{ | ||
| + | 		// Check if a child process has terminated | ||
| + | 		pid = waitpid(-1, &status, WNOHANG); | ||
| + | 		switch(pid) | ||
| + | 		{ | ||
| + | 		// Error | ||
| + | 		case -1: | ||
| + | 			perror("waitpid()"); | ||
| + | 			exit(EXIT_FAILURE); | ||
| + | 		// All child processes are still running | ||
| + | 		case 0: | ||
| + | 			break; | ||
| + | 		// A child process has terminated | ||
| + | 		default: | ||
| + | 			terminated++; | ||
| + | 			printf("Finished #%d: %s\n", terminated, findCommand(pid)); | ||
| + | 		} | ||
| + | 	} | ||
| + | 	while(terminated < ProcessCount); | ||
| + | |||
| + | 	exit(EXIT_SUCCESS); | ||
| + | } | ||
| + | |||
| + | // Entry point | ||
| + | int main(int argc, char *argv[]) | ||
| + | { | ||
| + | 	// Get input | ||
| + | 	readMultipleLines(); | ||
| + | |||
| + | 	// Set output | ||
| + | 	runProcesses(); | ||
| + | |||
| + | 	return EXIT_SUCCESS; | ||
| + | } | ||
| + | </syntaxhighlight> | ||
| + | |||
| + | ===Soluzione di Aula=== | ||
| + | |||
| + | <source lang="C"> | ||
| + | #include < stdio.h >  | ||
| + | #include < unistd.h > | ||
| + | |||
| + | #define CHAR 1 | ||
| + | #define SPACE 0 | ||
| + | |||
| + | execs2(char * s, int argc) { | ||
| + |     char * argv[argc + 1]; | ||
| + |     char * t = s; | ||
| + |     int status = SPACE; | ||
| + |     argc = 0; | ||
| + |     while ( * t) { | ||
| + |         switch ( * t) { | ||
| + |         case ' ': | ||
| + |         case '\t': | ||
| + |         case '\n': | ||
| + |         case 0: | ||
| + |             if (status == CHAR) argc++; * t = 0; | ||
| + |             status = SPACE; | ||
| + |             break; | ||
| + |         default: | ||
| + |             if (status == SPACE) printf("%s\n", t); | ||
| + |             if (status == SPACE) argv[argc] = t; | ||
| + |             status = CHAR; | ||
| + |             break; | ||
| + |         } | ||
| + |         t++; | ||
| + |     } | ||
| + |     argc++; | ||
| + |     argv[argc] = 0; | ||
| + |     int i; | ||
| + |     for (i = 0; i < argc + 1; i++) | ||
| + |         printf("%d %p\n", i, argv[i]); | ||
| + |     execvp(argv[0], argv); | ||
| + | } | ||
| + | |||
| + | execs(char * s) { | ||
| + |     char * t = s - 1; | ||
| + |     int argc = 0; | ||
| + |     int status = SPACE; | ||
| + |     do { | ||
| + |         t++; | ||
| + |         switch ( * t) { | ||
| + |         case ' ': | ||
| + |         case '\t': | ||
| + |         case '\n': | ||
| + |         case 0: | ||
| + |             if (status == CHAR) argc++; | ||
| + |             status = SPACE; | ||
| + |             break; | ||
| + |         default: | ||
| + |             status = CHAR; | ||
| + |             break; | ||
| + |         } | ||
| + |     } while ( * t); | ||
| + |     execs2(s, argc); | ||
| + | } | ||
| + | |||
| + | int main(int argc, char * argv[]) { | ||
| + |     char buf[1024]; | ||
| + |     fgets(buf, 1024, stdin); | ||
| + |     execs(buf); | ||
| + | } | ||
| + | </source> | ||
| + | |||
| + | === Soluzione di Federico Giuggioloni === | ||
| + | |||
| + | <source lang="c"> | ||
| + | #include <stdio.h> | ||
| + | #include <stdlib.h> | ||
| + | #include <string.h> | ||
| + | #include <unistd.h> | ||
| + | #include <errno.h> | ||
| + | #include <sys/types.h> | ||
| + | #include <poll.h> | ||
| + | #include <string.h> | ||
| + | |||
| + | struct list_el | ||
| + | { | ||
| + |    pid_t pid; | ||
| + |    char* comando; | ||
| + |    struct list_el* next; | ||
| + | }; | ||
| + | |||
| + | void insert_el(struct list_el** head, char* command, pid_t id) | ||
| + | { | ||
| + |    struct list_el *new_el = malloc(sizeof(struct list_el)); | ||
| + |    new_el->comando = malloc(sizeof(char) * strlen(command) + 1); | ||
| + |    strcpy(new_el->comando, command); | ||
| + |    new_el->next = NULL; | ||
| + |    new_el->pid = id; | ||
| + | |||
| + | |||
| + |    if(*head == NULL) | ||
| + |    { | ||
| + |       *head = new_el; | ||
| + |    } | ||
| + |    else | ||
| + |    { | ||
| + |       struct list_el* tmp = (*head)->next; | ||
| + |       (*head)->next = new_el; | ||
| + |       new_el->next = tmp; | ||
| + |    } | ||
| + | |||
| + | } | ||
| + | |||
| + | int strspl(char*** split, char* string, const char* delim) | ||
| + | { | ||
| + |    char* result; | ||
| + |    char* parsed = malloc(strlen(string)+1); | ||
| + |    char* tofree = parsed; | ||
| + |    int size = 2; | ||
| + | |||
| + |    char* ptr = string; | ||
| + |    while(*ptr != 0) | ||
| + |    { | ||
| + |       if(*ptr == *delim) size++; | ||
| + |       ptr++; | ||
| + |    } | ||
| + | |||
| + |    if(*split == NULL) | ||
| + |    { | ||
| + |       *split = malloc(sizeof(char*) * size); | ||
| + |    } | ||
| + | |||
| + |    strcpy(parsed, string); | ||
| + | |||
| + |    int i = 0; | ||
| + |    while((result = strtok(parsed, delim)) != NULL) | ||
| + |    { | ||
| + |       //subsequent calls to strtok must have NULL in the first | ||
| + |       //parameter | ||
| + |       parsed = NULL; | ||
| + | |||
| + |       //(*split)[i] = result; | ||
| + |       (*split)[i] = malloc(strlen(result) * sizeof(char) + 1); | ||
| + |       strcpy((*split)[i], result); | ||
| + | |||
| + |       i++; | ||
| + |    } | ||
| + | |||
| + |    (*split)[i] = (char*) 0; | ||
| + | |||
| + |    free(tofree); | ||
| + |    return i; | ||
| + | } | ||
| + | |||
| + | struct list_el* head = NULL; | ||
| + | |||
| + | char* printNamePid(pid_t pid) | ||
| + | { | ||
| + |    struct list_el* p = head; | ||
| + |    while(p != NULL) | ||
| + |    { | ||
| + |       if(p->pid == pid) return p->comando; | ||
| + |       p = p->next; | ||
| + |    } | ||
| + | } | ||
| + | |||
| + | int main(int argc, char* argv[]) | ||
| + | { | ||
| + |    int n; | ||
| + |    char *string; | ||
| + |    string = NULL;//malloc(MAX_BUFF * sizeof(char)); | ||
| + |    int bytes_read; | ||
| + |    pid_t pid; | ||
| + |    char** splitargs = NULL; | ||
| + |    char delim = ' '; | ||
| + |    int nFork = 0; | ||
| + |    int err; | ||
| + |    int pipe_read = 0; | ||
| + |    char pipe_char = ' '; | ||
| + | |||
| + |    int pipefd[2]; | ||
| + |    pipe(pipefd); | ||
| + | |||
| + |    struct pollfd pipe_read_poll; | ||
| + |    pipe_read_poll.fd = pipefd[0]; | ||
| + |    pipe_read_poll.events = POLLIN; | ||
| + | |||
| + |    while((bytes_read = getline(&string, &n, stdin)) != 0) | ||
| + |    { | ||
| + |       if(strcmp(string, "\n") == 0) break; | ||
| + | |||
| + |       string[strlen(string)-1] = 0; | ||
| + |       strspl(&splitargs, string, &delim); | ||
| + | |||
| + |       pid = fork(); | ||
| + |       switch(pid) | ||
| + |       { | ||
| + |          case -1: | ||
| + |             printf("Error fork: %s (%d)", strerror(errno), errno); | ||
| + |             exit(2); | ||
| + |             break; | ||
| + |          case 0: | ||
| + |             //pipe_read = read(pipefd[0], &pipe_read, 1); | ||
| + |             poll(&pipe_read_poll, 1, -1); | ||
| + |             err = execvp(splitargs[0], splitargs); | ||
| + |             if(err < 0) | ||
| + |             { | ||
| + |                printf("Error exec: %s (%d)", strerror(errno), errno); | ||
| + |                exit(1); | ||
| + |             } | ||
| + |             exit(0); | ||
| + |             break; | ||
| + |          default: //PADRE, continua pure | ||
| + |             nFork++; | ||
| + |             insert_el(&head, string, pid); | ||
| + |             break; | ||
| + |       } | ||
| + | |||
| + | |||
| + |       //free(splitargs); //TODO anche di tutte le stringhe all'interno | ||
| + |       splitargs = NULL; | ||
| + |    } | ||
| + | |||
| + |    int status = 0; | ||
| + |    char buf = 'g'; | ||
| + |    char* comando = NULL; | ||
| + |    int ordineArrivo[nFork]; | ||
| + |    int i = 0; | ||
| + | |||
| + |    write(pipefd[1], &buf, 1); | ||
| + | |||
| + |    while(i < nFork) | ||
| + |    { | ||
| + |       pid = wait(&status); | ||
| + |       ordineArrivo[i] = pid; | ||
| + |       i++; | ||
| + |    } | ||
| + | |||
| + |    printf("\n\n"); | ||
| + |    for(i = 0; i < nFork; i++) | ||
| + |    { | ||
| + |       comando = printNamePid(ordineArrivo[i]); | ||
| + |       printf("%d : %s Terminated\n", i, comando); | ||
| + |    } | ||
| + |    return 0; | ||
| + | } | ||
| + | </source> | ||
| + | |||
| + | ===Soluzione di Claudio Kerov === | ||
| + | Questa è la versione dell'esercizio 1 senza sincronizzazione della partenza dei processi. | ||
| + | |||
| + | <source lang="c"> | ||
| + | |||
| + | #include <stdio.h> | ||
| + | #include <stdlib.h> | ||
| + | #include <unistd.h> | ||
| + | #include <sys/types.h> | ||
| + | #include <sys/wait.h> | ||
| + | #include <string.h> | ||
| + | |||
| + | |||
| + | struct lista{ | ||
| + |     struct lista *next; | ||
| + |     char* stringa; | ||
| + | }; | ||
| + | |||
| + | void leggiArgomenti(char* comando) //prendo il comando dalla stringa, la divido in programma e argomenti, poi la eseguo | ||
| + | { | ||
| + |     char* temp; | ||
| + |     char delim= ' '; | ||
| + |     char* args[64]; //alla fine uso questo | ||
| + |     char** next = args; //ma questo e' quello che riempio | ||
| + |     temp= strtok(comando, &delim ); | ||
| + | |||
| + |     while (temp != NULL) | ||
| + |     { | ||
| + |         *next++ = temp; | ||
| + |         temp = strtok(NULL, &delim); | ||
| + |     } | ||
| + |     *next = NULL; | ||
| + |     execvp(args[0], args); | ||
| + | } | ||
| + | |||
| + | void ins(struct lista *l, char* comando)  | ||
| + | { | ||
| + |     struct lista *tmp = malloc(sizeof(struct lista)); | ||
| + |     tmp->stringa = malloc(sizeof(char)*strlen(comando)+1); | ||
| + |     tmp->next= l->next; | ||
| + |     strcpy(tmp->stringa, comando); | ||
| + |     l->next = tmp; | ||
| + | |||
| + | } | ||
| + | |||
| + | |||
| + | int main  (int argc, char *argv[]) | ||
| + | { | ||
| + | |||
| + |     size_t n; | ||
| + |     int status = 0; | ||
| + |     char *riga= (char*)malloc(sizeof(char)); | ||
| + |     struct lista *lista_arrivi=(struct lista*) malloc(sizeof(struct lista)); | ||
| + |     struct lista *tmp = lista_arrivi; | ||
| + |     lista_arrivi->next = NULL; | ||
| + | |||
| + |     while( (getline(&riga, &n, stdin)!=0))  | ||
| + |     { | ||
| + |         if (strcmp(riga, "\n")==0) | ||
| + |             break; | ||
| + | |||
| + |         ins(lista_arrivi, riga); | ||
| + |         counter++; | ||
| + | |||
| + |     } | ||
| + | |||
| + |     while(lista_arrivi!=NULL) | ||
| + |     { | ||
| + |         pid_t pid = fork(); | ||
| + |         switch(pid) | ||
| + |         { | ||
| + |             case -1: exit(2); | ||
| + |                 break; | ||
| + |             case 0: //processo figlio che prende in input i comandi | ||
| + | |||
| + |                 leggiArgomenti(lista_arrivi->stringa); | ||
| + |                 break; | ||
| + |             default: //processo padre che stampera' la lista | ||
| + |                 lista_arrivi= lista_arrivi->next; | ||
| + |                 break; | ||
| + |         } | ||
| + | |||
| + |     } | ||
| + | |||
| + |     tmp = tmp->next; | ||
| + | |||
| + |     while(tmp!=NULL) | ||
| + |     { | ||
| + |         wait(&status); | ||
| + |         printf("Terminato: %s\n", tmp->stringa); | ||
| + |         tmp= tmp->next; | ||
| + |     } | ||
| + | |||
| + |     return 0; | ||
| + | } | ||
| + | |||
| + | </source> | ||
| + | == Esercizio 3 == | ||
| + | |||
| + | ===Soluzione di Tommaso Ognibene=== | ||
| [Python 3] | [Python 3] | ||
| Line 30: | Line 652: | ||
|          return |          return | ||
| − |      # Build a dictionary with key-value pair {file base name -  | + |      # Build a dictionary with key-value pair {file base name - occurrences} | 
|      nameFreq = { } |      nameFreq = { } | ||
|      for dirPath, dirNames, fileNames in os.walk(srcDir): |      for dirPath, dirNames, fileNames in os.walk(srcDir): | ||
| Line 51: | Line 673: | ||
| </syntaxhighlight> | </syntaxhighlight> | ||
| + | ===Soluzione di Fede=== | ||
| − | |||
| − | |||
| − | |||
| <syntaxhighlight lang="Python"> | <syntaxhighlight lang="Python"> | ||
| − | import os | + | import os, sys | 
| − | |||
| − | def collectfiles(arg1,arg2):  | + | def collectfiles(arg1,arg2):   | 
| 	fcd = os.listdir('{0}'.format(arg1)) | 	fcd = os.listdir('{0}'.format(arg1)) | ||
| 	while fcd != []: | 	while fcd != []: | ||
| Line 68: | Line 687: | ||
| 			collectfiles(C,arg2) | 			collectfiles(C,arg2) | ||
| 		elif os.path.isfile('{0}'.format(C)): | 		elif os.path.isfile('{0}'.format(C)): | ||
| − | 			os.symlink('{0}'.format(C), '{0}/{1}'.format(arg2,B)) | + | 			try: | 
| − | + | 				os.symlink('{0}'.format(C), '{0}/{1}'.format(arg2,B)) | |
| − | + | 			except OSError: | |
| − | + | 				i=1 | |
| + | 				while True: | ||
| + | 					try: | ||
| + | 						os.symlink('{0}'.format(C), '{0}/{1}{2}'.format(arg2,B,i)) | ||
| + | 						break | ||
| + | 					except OSError: | ||
| + | 						i=i+1 | ||
| try: | try: | ||
| 	collectfiles(str(sys.argv[1]),str(sys.argv[2])) | 	collectfiles(str(sys.argv[1]),str(sys.argv[2])) | ||
| except OSError: | except OSError: | ||
| − | + | 		print("Invalid Directory!") | |
| </syntaxhighlight> | </syntaxhighlight> | ||
| − | -Fede | + | |
| + | ===Altra soluzione di Tommaso Ognibene=== | ||
| + | |||
| + | Leggendo la tua versione ho pensato che in effetti se i file sono """pochi""" l'hash-table non e' necessaria. E' sufficiente un controllo iterativo. | ||
| + | <syntaxhighlight lang="Python"> | ||
| + | ''' | ||
| + | Prova Pratica di Laboratorio di Sistemi Operativi | ||
| + | 18 luglio 2013 | ||
| + | Esercizio 3 | ||
| + | |||
| + | URL: http://www.cs.unibo.it/~renzo/so/pratiche/2013.07.18.pdf | ||
| + | |||
| + | @author: Tommaso Ognibene | ||
| + | ''' | ||
| + | |||
| + | import os, sys | ||
| + | |||
| + | def Main(argv): | ||
| + |     # Check number of arguments | ||
| + |     if len(argv) != 3: | ||
| + |         print("The function requires two arguments to be passed in.") | ||
| + |         return | ||
| + | |||
| + |     # Check parameters | ||
| + |     srcDir = str(argv[1]) | ||
| + |     dstDir = str(argv[2]) | ||
| + |     if not os.path.isdir(srcDir): | ||
| + |         print("First argument should be an existing directory.") | ||
| + |         return | ||
| + |     if not os.path.isdir(dstDir): | ||
| + |         print("Second argument should be an existing directory.") | ||
| + |         return | ||
| + | |||
| + |     # Traverse the directory tree and create a soft link for each file | ||
| + |     for dirPath, _, fileNames in os.walk(srcDir): | ||
| + |         for fileName in fileNames: | ||
| + |             # 'example.pdf' -> 'example' | ||
| + |             # 'example.xml' -> 'example' | ||
| + |             fileBaseName, _ = os.path.splitext(fileName) | ||
| + |             linkName = fileBaseName | ||
| + |             srcPath = os.path.join(os.path.abspath(dirPath), fileName) | ||
| + |             dstPath = os.path.join(dstDir, linkName) | ||
| + |             i = 0 | ||
| + |             while os.path.isfile(dstPath): | ||
| + |                 # 'example' will point to 'example.pdf' | ||
| + |                 # 'example1' will point to 'example.xml' | ||
| + |                 i += 1 | ||
| + |                 linkName = fileBaseName + str(i) | ||
| + |                 dstPath = os.path.join(dstDir, linkName) | ||
| + |             if not os.path.lexists(dstPath): | ||
| + |                 os.symlink(srcPath, dstPath) | ||
| + | |||
| + |     print("Done!") | ||
| + | |||
| + | if __name__ == "__main__": | ||
| + |     sys.exit(Main(sys.argv)) | ||
| + | </syntaxhighlight> | ||
| + | |||
| + | ===Soluzione di Fede in bash === | ||
| + | |||
| + | Ecco la mia versione in bash | ||
| + | |||
| + | <syntaxhighlight lang="Bash"> | ||
| + | #! /bin/bash | ||
| + | |||
| + | BornAgainFede () { | ||
| + | for f in "$1"/*; do | ||
| + | 	bn=$(basename "$f") | ||
| + | 	if [[ -f $f ]] ; then | ||
| + | 		if [[ -h "$2"/"$bn" ]] ; then | ||
| + | 			i=1 | ||
| + | 			while [[ -h "$2"/"$bn$i" ]] ; do | ||
| + | 			let "i += 1"  | ||
| + | 			done | ||
| + | 			ln -s "$1"/"$bn" "$2"/"$bn$i" | ||
| + | 		else | ||
| + | 			ln -s "$1"/"$bn" "$2"/"$bn" | ||
| + | 		fi | ||
| + | 	fi | ||
| + | 	if [[ -d $f ]] ; then | ||
| + | 		BornAgainFede "$1"/"$bn" "$2" | ||
| + | 	fi | ||
| + | done | ||
| + | } | ||
| + | |||
| + | BornAgainFede "$1" "$2" | ||
| + | </syntaxhighlight> | ||
| + | |||
| + | ===Versione by Daniele Cortesi=== | ||
| + | <syntaxhighlight lang="Python"> | ||
| + | |||
| + | from sys import argv | ||
| + | import os | ||
| + | |||
| + | #controllo se il programma e' stato chiamato correttamente | ||
| + | if len(argv)<3: | ||
| + | 	print "uso: programma cartella1 cartella2" | ||
| + | 	exit(1) | ||
| + | |||
| + | dir1=argv[1] | ||
| + | dir2=argv[2] | ||
| + | |||
| + | #controllo che gli argomenti siano effettivamente cartelle | ||
| + | if not os.path.isdir(dir1) or  not os.path.isdir(dir2): | ||
| + | 	print "cartelle non valide" | ||
| + | 	exit(1) | ||
| + | |||
| + | cartelle=[os.getcwd()+"/"+dir1] #lista che conterra' mano a mano tutte le sottocartelle | ||
| + | files={} #dizionario con nomefile: [lista con tutti i file che si chiamano "nomefile"] | ||
| + | |||
| + | while len(cartelle)>0: | ||
| + | 	c=cartelle.pop()  | ||
| + | 	for f in os.listdir(c): #analizzo tutti i file nella cartella c | ||
| + | 		#se f non e' una cartella, allora lo inserisco nel dizionario se non c'e', altrimenti aggiungo il suo percorso alla lista | ||
| + | 		if not os.path.isdir(c+"/"+f): | ||
| + | 			if not files.has_key(f): | ||
| + | 				files[f]=[c+"/"+f] | ||
| + | 			else: files[f].append(c+"/"+f) | ||
| + | 		#se f invece e' una cartella, la aggiungo alla lista cosi' alla prossima iterazione (o dopo in caso di piu' cartelle) verra' analizzata | ||
| + | 		else: cartelle.append(c+"/"+f) | ||
| + | |||
| + | #creo i link simbolici	 | ||
| + | for k in files.keys(): | ||
| + | 	for i,f in enumerate(files[k]): | ||
| + | 		link=k | ||
| + | 		if (i>0): link+=str(i) | ||
| + | 		os.symlink(f, dir2+"/"+link) | ||
| + | |||
| + | exit(0) | ||
| + | |||
| + | </syntaxhighlight> | ||
| + | |||
| + | ===Osservazioni di Amonaldini=== | ||
| + | Per prima cosa, bel lavoro!<br/> | ||
| + | Di seguito riporto alcune osservazioni che mi sono venute in mente, prendetele assolutamente con soli fini "costruttivi"!  | ||
| + | * Se non sbaglio, i due programmi (quello di Tommaso e quello di Fede) hanno un comportamento diverso per quanto concerne l'interpretazione del nome file e, in particolare, dell'estensione: | ||
| + | ** Per Tommaso: | ||
| + | *** dir1/example.pdf --> example | ||
| + | *** dir1/example.txt --> example1 | ||
| + | *** dir1/dirX/example.pdf --> example2 | ||
| + | ** Per Fede: | ||
| + | *** dir1/example.pdf --> example.pdf | ||
| + | *** dir1/example.txt --> example.txt | ||
| + | *** dir1/dirX/example.pdf --> example.pdf1 | ||
| + | ** interpretando in modo "stringente" del testo dell'esercizio avrei ipotizzato un comportamento come quello di Fede. | ||
| + | * Nel codice sorgente c'è in generale poco "commento". Commentare il codice è essenziale: permette ad altri di capire immediatamente le scelte implementative fatte e permette a voi di capire al volo il perché di queste scelte nel caso dobbiate riprendere in mano il vostro codice dopo un po' di tempo. Quindi: commentate!!! | ||
| + | * Bash si presta molto all'esercizio | ||
| + | |||
| + | ===Soluzione di fede&pirata=== | ||
| + | |||
| + | <syntaxhighlight lang="C"> | ||
| + | /* | ||
| + | ESERCIZIO 3. | ||
| + | */ | ||
| + | #include<unistd.h>   | ||
| + | #include<stdio.h>  | ||
| + | #include<stdlib.h>  | ||
| + | #include<string.h>  | ||
| + | #include<dirent.h>  | ||
| + | #include <sys/types.h>  | ||
| + | #include <sys/stat.h>  | ||
| + | |||
| + | void collectandlink(char *arg1, char *carg2) | ||
| + | {  | ||
| + | 	struct dirent **namelist;  | ||
| + | 	int n;  | ||
| + | 	n = scandir( arg1 , &namelist, 0, alphasort);  | ||
| + | |||
| + | 	if (n < 0)  | ||
| + | 		perror("scandir");  | ||
| + | 	else  | ||
| + | 	{  | ||
| + | 		while(n--) | ||
| + | 		{  | ||
| + | 			int i; | ||
| + | 			char* istr; | ||
| + | 			int datest; | ||
| + | 			char *pathnametmp; | ||
| + | 			char *pathwithname=(char *)malloc(512); | ||
| + | 			char *pathwithname2=(char *)malloc(512); | ||
| + | 			strcpy(pathwithname,arg1); | ||
| + | 			strcpy(pathwithname2,carg2); | ||
| + | 			strcat(pathwithname,"/"); | ||
| + | 			strcat(pathwithname2,"/"); | ||
| + | 			strcat(pathwithname,namelist[n]->d_name); | ||
| + | 			strcat(pathwithname2,namelist[n]->d_name); | ||
| + | 			struct stat s;  | ||
| + | 			if( stat(pathwithname,&s) == 0 )  | ||
| + | 			{   | ||
| + | 				if( s.st_mode & S_IFDIR ) //è un dir | ||
| + | 				{  | ||
| + | 					if ( strcmp( namelist[n]->d_name , ".." ) == 0 )//si deve escludere ".." | ||
| + | 					{  | ||
| + | 						continue;  | ||
| + | 					}  | ||
| + | 					if( strcmp( namelist[n]->d_name , "." ) == 0 )//si deve escludere "." | ||
| + | 					{  | ||
| + | 						continue;  | ||
| + | 					}   | ||
| + | 					else  | ||
| + | 					{ | ||
| + | 						collectandlink(pathwithname,carg2); | ||
| + | 					} | ||
| + | 				}  | ||
| + | 				else  | ||
| + | 				{ | ||
| + | 					if( s.st_mode & S_IFREG ) //è un file | ||
| + | 					{  | ||
| + | 						datest=symlink(pathwithname,pathwithname2);//torna 0 al successo -1 altrimenti | ||
| + | 						if(datest==-1) //se simlink fallisce => link esiste | ||
| + | 						{ | ||
| + | 							i=1; | ||
| + | 							while(datest!=0)//finchè simlink non ha successo | ||
| + | 							{ | ||
| + | 								istr=(char *)malloc(32); | ||
| + | 								pathnametmp=(char *)malloc(544); | ||
| + | 								strcpy(pathnametmp,pathwithname2); | ||
| + | 								sprintf(istr, "%d", i); | ||
| + | 								strcat(pathnametmp,istr); | ||
| + | 								datest=symlink(pathwithname,pathnametmp); | ||
| + | 								free(istr); | ||
| + | 								free(pathnametmp); | ||
| + | 								i=i+1; | ||
| + | 							} | ||
| + | 						} | ||
| + | 					}  | ||
| + | 				}  | ||
| + | 			} | ||
| + | 			free(pathwithname); | ||
| + | 			free(pathwithname2); | ||
| + | 		}  | ||
| + | 	} | ||
| + | 	free(namelist); | ||
| + | } | ||
| + | |||
| + | int main(int argc, char *argv[]){  | ||
| + | collectandlink(argv[1],argv[2]);  | ||
| + | return 1;  | ||
| + | } | ||
| + | </syntaxhighlight> | ||
| + | |||
| + | ===Soluzione di Krusty=== | ||
| + | <source lang="python"> | ||
| + | import os, sys | ||
| + | from stat import * | ||
| + | |||
| + | exist={} | ||
| + | |||
| + | def Scan(pathname): | ||
| + | |||
| + | 	for f in os.listdir(pathname): | ||
| + | 		path = os.path.join(pathname,f) | ||
| + | 		s = os.stat(path) | ||
| + | 		if S_ISREG(s.st_mode): | ||
| + | 			if f not in exist: | ||
| + | 				exist[f] = 1 | ||
| + | 				os.symlink(path,f)	 | ||
| + | 			else: | ||
| + | 				n = exist[f] | ||
| + | 				exist[f] = exist[f] + 1 | ||
| + | 				os.symlink(path,(f+str(n)))	 | ||
| + | |||
| + | 		elif S_ISDIR(s.st_mode):	 | ||
| + | 			Scan(path) | ||
| + | |||
| + | #main | ||
| + | |||
| + | if not os.path.isdir(sys.argv[2]): | ||
| + |     os.makedirs(sys.argv[2]) | ||
| + | |||
| + | os.chdir(sys.argv[2]) | ||
| + | Scan(sys.argv[1]) | ||
| + | |||
| + | </source> | ||
| + | |||
| + | int main(int argc, char * argv[]) { | ||
| + |     char buf[1024]; | ||
| + |     fgets(buf, 1024, stdin); | ||
| + |     execs(buf); | ||
| + | } | ||
| + | </source> | ||
| + | |||
| + | ===Soluzione di MV=== | ||
| + | <source lang="bash"> | ||
| + | #! /bin/bash | ||
| + | |||
| + | if (( $# != 2 )) | ||
| + | then | ||
| + | 	echo "Usage: nameindex dir1 dir2" | ||
| + | 	exit 1 | ||
| + | fi | ||
| + | |||
| + | if [[ $1 = /* ]] # verifico se $1 è un path assoluto o relativo (è necessario assoluto per i link) | ||
| + | then  | ||
| + | 	dir1=$1 | ||
| + | else | ||
| + | 	dir1=`pwd`/$1 | ||
| + | fi | ||
| + | |||
| + | for i in `find $dir`	# scandisco l'albero | ||
| + | do | ||
| + | 	if [ -f $i ] | ||
| + | 	then | ||
| + | 		filename=`basename $i`		# ricavo il nome del file senza percorso | ||
| + | |||
| + | 		if [ ! -f $2/$filename ] 	# se è il primo file trovato con quel nome | ||
| + | 		then						# creo il link con lo stesso nome | ||
| + | 			ln -s $dir1/$i $2/$filename | ||
| + | 		else			# altrimento cerco il primo numero n>0 non ancora usato come suffisso | ||
| + | 			n=1 | ||
| + | 			while [ -f $2/${filename}${n} ] | ||
| + | 			do | ||
| + | 				(( n=$n+1 )) | ||
| + | 			done | ||
| + | 			ln -s $dir1/$i $2/$filename$n | ||
| + | 		fi | ||
| + | 	fi | ||
| + | done | ||
| + | </source> | ||
Latest revision as of 12:21, 9 May 2017
Esercizio 1
Soluzione di Tommaso Ognibene
/*
Prova Pratica di Laboratorio di Sistemi Operativi
18 luglio 2013
Esercizio 1
URL: http://www.cs.unibo.it/~renzo/so/pratiche/2013.07.18.pdf
@author: Tommaso Ognibene
*/
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <unistd.h>
// Constants
#define MaxNumArguments 10
#define MaxLenArguments 50
#define MaxLenPath 100
#define MaxLenLine MaxLenArguments * MaxNumArguments
#define MaxLenCommands 500
// Structure for a process element
typedef struct processElem
{
	char CommandLine[MaxLenCommands];
	pid_t Pid;
	struct processElem *Next;
} ProcessElem;
// Function prototypes
ProcessElem *appendElement    (ProcessElem *tail);
char        *findCommand      (pid_t pid);
void         countTokens      (const char *string, const char delimiter, int *count, int *longest);
int          tokenize         (char *string, char delimiter, char ***tokens, int *count);
void         readMultipleLines(void);
void         runProcesses     (void);
// Global variables
static ProcessElem *ProcessList  = NULL;
int                 ProcessCount = 0;
// Given a PID retrieve the relative command
char *findCommand(pid_t pid)
{
	ProcessElem *process;
	for(process = ProcessList; process->Pid != pid; process = process->Next);
	return (process)? (process->CommandLine) : (NULL);
}
// Create a new element
ProcessElem *appendElement(ProcessElem *tail)
{
	ProcessElem *newElem = (ProcessElem *)malloc(sizeof(ProcessElem));
	newElem->Next = NULL;
	(tail)? (tail->Next = newElem) : (tail = newElem);
	return newElem;
}
/*
 * Count tokens and find the longest one
 * Example:
 *    Input:
 *       string = "ping -c 4 google.com"
 *       delimiter = ' '
 *    Output:
 *       count = 4
 *       longest = 10
 */
void countTokens(const char *string, const char delimiter, int *count, int *longest)
{
	int iterator, lenght;
	lenght = *longest = *count = 0;
	// Count the first (n - 1) tokens
	for(iterator = 0; string[iterator]; iterator++)
	{
		if(string[iterator] == delimiter)
		{
			if(*longest < lenght)
				*longest = lenght;
			lenght = 0;
			(*count)++;
		}
		lenght++;
	}
	// Count the last token
	if(string[iterator - 1] != delimiter)
	{
		lenght--;
		if(*longest < lenght)
			*longest = lenght;
		(*count)++;
	}
}
/*
 * Tokenize a string accordingly to a given delimiter
 * Example:
 *    Input:
 *       string = "ping -c 4 google.com"
 *       delimiter = ' '
 *    Output:
 *       tokens = ["ping", "-c", "4", "google.com"]
 *       count = 4
 */
int tokenize(char *string, char delimiter, char ***tokens, int *count)
{
	if(!(tokens && string && count)) return 0;
	int token, i, j, longest;
	*count = longest = 0;
	countTokens(string, delimiter, count, &longest);
	// Allocate space for array of strings
	*tokens = (char **)malloc(*count * sizeof(char *));
	if(!*tokens)
	{
		perror("malloc()");
		exit(EXIT_FAILURE);
	}
	// Allocate space for each string in the array and tokenize it
	i = 0;
	for(token = 0; token < *count; token++)
	{
		(*tokens)[token] = (char *)malloc(sizeof(char) * (longest + 1));
		j = 0;
		while(string[i] != delimiter && string[i])
		{
			(*tokens)[token][j] = string[i];
			j++;
			i++;
		}
		// Null-terminated string
		(*tokens)[token][j] = (char)0;
		i++;
	}
	return 1;
}
// Read multiple input lines
void readMultipleLines(void)
{
	ProcessElem *process = NULL;
	char input[MaxLenLine];
	char *iterator;
	printf("Enter commands. Press enter on blank line to start them.\n");
	while(1)
	{
		// Get input string
		if(!fgets(input, MaxLenLine, stdin))
		{
			perror("fgets()");
			exit(EXIT_FAILURE);
		}
		// Skip blank lines
		for(iterator = input; *iterator == ' '; iterator++);
		// Check if enter was pressed on blank line
		if(*iterator == '\n') break;
		// Append a new input element
		if(!(ProcessList))
			process = ProcessList = appendElement(ProcessList);
		else
		{
			process->Next = appendElement(process);
			process = process->Next;
		}
		ProcessCount++;
		// Eliminate "\n" from the input string
		iterator = strtok(iterator, "\n");
		strcpy(process->CommandLine, iterator);
	}
}
/*
 * Run child processes ->
 * Print when a child process terminates
 */
void runProcesses(void)
{
	pid_t pid;
	int status, terminated, count;
	char path[MaxLenPath];
	ProcessElem *process = ProcessList;
	char **command = NULL;
	terminated = count = 0;
	// Start processes
	while(process)
	{
		// Tokenize command line
		tokenize(process->CommandLine, ' ', &command, &count);
		// Create path
		snprintf(path, sizeof path, "%s%s", "/bin/", command[0]);
		// Create child process
		pid = fork();
		// Check PID
		switch(pid)
		{
		// Error
		case -1:
			perror("fork()");
			exit(EXIT_FAILURE);
		// Child process
		case 0:
			// Execute command
			if (execv(path, command) == -1)
			{
				perror("execv()");
				exit(EXIT_FAILURE);
			}
			break;
		// Parent process
		default:
			process->Pid = pid;
		}
		process = process->Next;
	}
	// Wait processes
	do
	{
		// Check if a child process has terminated
		pid = waitpid(-1, &status, WNOHANG);
		switch(pid)
		{
		// Error
		case -1:
			perror("waitpid()");
			exit(EXIT_FAILURE);
		// All child processes are still running
		case 0:
			break;
		// A child process has terminated
		default:
			terminated++;
			printf("Finished #%d: %s\n", terminated, findCommand(pid));
		}
	}
	while(terminated < ProcessCount);
	exit(EXIT_SUCCESS);
}
// Entry point
int main(int argc, char *argv[])
{
	// Get input
	readMultipleLines();
	// Set output
	runProcesses();
	return EXIT_SUCCESS;
}
Soluzione di Aula
#include < stdio.h > 
#include < unistd.h >
#define CHAR 1
#define SPACE 0
execs2(char * s, int argc) {
    char * argv[argc + 1];
    char * t = s;
    int status = SPACE;
    argc = 0;
    while ( * t) {
        switch ( * t) {
        case ' ':
        case '\t':
        case '\n':
        case 0:
            if (status == CHAR) argc++; * t = 0;
            status = SPACE;
            break;
        default:
            if (status == SPACE) printf("%s\n", t);
            if (status == SPACE) argv[argc] = t;
            status = CHAR;
            break;
        }
        t++;
    }
    argc++;
    argv[argc] = 0;
    int i;
    for (i = 0; i < argc + 1; i++)
        printf("%d %p\n", i, argv[i]);
    execvp(argv[0], argv);
}
execs(char * s) {
    char * t = s - 1;
    int argc = 0;
    int status = SPACE;
    do {
        t++;
        switch ( * t) {
        case ' ':
        case '\t':
        case '\n':
        case 0:
            if (status == CHAR) argc++;
            status = SPACE;
            break;
        default:
            status = CHAR;
            break;
        }
    } while ( * t);
    execs2(s, argc);
}
int main(int argc, char * argv[]) {
    char buf[1024];
    fgets(buf, 1024, stdin);
    execs(buf);
}
Soluzione di Federico Giuggioloni
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <poll.h>
#include <string.h>
struct list_el
{
   pid_t pid;
   char* comando;
   struct list_el* next;
};
void insert_el(struct list_el** head, char* command, pid_t id)
{
   struct list_el *new_el = malloc(sizeof(struct list_el));
   new_el->comando = malloc(sizeof(char) * strlen(command) + 1);
   strcpy(new_el->comando, command);
   new_el->next = NULL;
   new_el->pid = id;
   if(*head == NULL)
   {
      *head = new_el;
   }
   else
   {
      struct list_el* tmp = (*head)->next;
      (*head)->next = new_el;
      new_el->next = tmp;
   }
}
int strspl(char*** split, char* string, const char* delim)
{
   char* result;
   char* parsed = malloc(strlen(string)+1);
   char* tofree = parsed;
   int size = 2;
   char* ptr = string;
   while(*ptr != 0)
   {
      if(*ptr == *delim) size++;
      ptr++;
   }
   if(*split == NULL)
   {
      *split = malloc(sizeof(char*) * size);
   }
   strcpy(parsed, string);
   int i = 0;
   while((result = strtok(parsed, delim)) != NULL)
   {
      //subsequent calls to strtok must have NULL in the first
      //parameter
      parsed = NULL;
      //(*split)[i] = result;
      (*split)[i] = malloc(strlen(result) * sizeof(char) + 1);
      strcpy((*split)[i], result);
      i++;
   }
   (*split)[i] = (char*) 0;
   free(tofree);
   return i;
}
struct list_el* head = NULL;
char* printNamePid(pid_t pid)
{
   struct list_el* p = head;
   while(p != NULL)
   {
      if(p->pid == pid) return p->comando;
      p = p->next;
   }
}
int main(int argc, char* argv[])
{
   int n;
   char *string;
   string = NULL;//malloc(MAX_BUFF * sizeof(char));
   int bytes_read;
   pid_t pid;
   char** splitargs = NULL;
   char delim = ' ';
   int nFork = 0;
   int err;
   int pipe_read = 0;
   char pipe_char = ' ';
   int pipefd[2];
   pipe(pipefd);
   struct pollfd pipe_read_poll;
   pipe_read_poll.fd = pipefd[0];
   pipe_read_poll.events = POLLIN;
   while((bytes_read = getline(&string, &n, stdin)) != 0)
   {
      if(strcmp(string, "\n") == 0) break;
      string[strlen(string)-1] = 0;
      strspl(&splitargs, string, &delim);
      pid = fork();
      switch(pid)
      {
         case -1:
            printf("Error fork: %s (%d)", strerror(errno), errno);
            exit(2);
            break;
         case 0:
            //pipe_read = read(pipefd[0], &pipe_read, 1);
            poll(&pipe_read_poll, 1, -1);
            err = execvp(splitargs[0], splitargs);
            if(err < 0)
            {
               printf("Error exec: %s (%d)", strerror(errno), errno);
               exit(1);
            }
            exit(0);
            break;
         default: //PADRE, continua pure
            nFork++;
            insert_el(&head, string, pid);
            break;
      }
      //free(splitargs); //TODO anche di tutte le stringhe all'interno
      splitargs = NULL;
   }
   int status = 0;
   char buf = 'g';
   char* comando = NULL;
   int ordineArrivo[nFork];
   int i = 0;
   write(pipefd[1], &buf, 1);
   while(i < nFork)
   {
      pid = wait(&status);
      ordineArrivo[i] = pid;
      i++;
   }
   printf("\n\n");
   for(i = 0; i < nFork; i++)
   {
      comando = printNamePid(ordineArrivo[i]);
      printf("%d : %s Terminated\n", i, comando);
   }
   return 0;
}
Soluzione di Claudio Kerov
Questa è la versione dell'esercizio 1 senza sincronizzazione della partenza dei processi.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <string.h>
struct lista{
    struct lista *next;
    char* stringa;
};
void leggiArgomenti(char* comando) //prendo il comando dalla stringa, la divido in programma e argomenti, poi la eseguo
{
    char* temp;
    char delim= ' ';
    char* args[64]; //alla fine uso questo
    char** next = args; //ma questo e' quello che riempio
    temp= strtok(comando, &delim );
    
    while (temp != NULL)
    {
        *next++ = temp;
        temp = strtok(NULL, &delim);
    }
    *next = NULL;
    execvp(args[0], args);
}
void ins(struct lista *l, char* comando) 
{
    struct lista *tmp = malloc(sizeof(struct lista));
    tmp->stringa = malloc(sizeof(char)*strlen(comando)+1);
    tmp->next= l->next;
    strcpy(tmp->stringa, comando);
    l->next = tmp;
    
}
int main  (int argc, char *argv[])
{
    
    size_t n;
    int status = 0;
    char *riga= (char*)malloc(sizeof(char));
    struct lista *lista_arrivi=(struct lista*) malloc(sizeof(struct lista));
    struct lista *tmp = lista_arrivi;
    lista_arrivi->next = NULL;
    
    while( (getline(&riga, &n, stdin)!=0)) 
    {
        if (strcmp(riga, "\n")==0)
            break;
        
        ins(lista_arrivi, riga);
        counter++;
        
    }
    
    while(lista_arrivi!=NULL)
    {
        pid_t pid = fork();
        switch(pid)
        {
            case -1: exit(2);
                break;
            case 0: //processo figlio che prende in input i comandi
                
                leggiArgomenti(lista_arrivi->stringa);
                break;
            default: //processo padre che stampera' la lista
                lista_arrivi= lista_arrivi->next;
                break;
        }
        
    }
    
    tmp = tmp->next;
    
    while(tmp!=NULL)
    {
        wait(&status);
        printf("Terminato: %s\n", tmp->stringa);
        tmp= tmp->next;
    }
    
    return 0;
}
Esercizio 3
Soluzione di Tommaso Ognibene
[Python 3]
'''
Prova Pratica di Laboratorio di Sistemi Operativi
18 luglio 2013
Esercizio 3
URL: http://www.cs.unibo.it/~renzo/so/pratiche/2013.07.18.pdf
@author: Tommaso Ognibene
'''
import os, sys
def Main(argv):
    # Check number of arguments
    if len(argv) != 3:
        print("The function requires two arguments to be passed in.")
        return
    
    # Check parameters
    srcDir = str(argv[1])
    dstDir = str(argv[2])
    if not os.path.isdir(srcDir):
        print("First argument should be an existing directory.")
        return
    if not os.path.isdir(dstDir):
        print("Second argument should be an existing directory.")
        return
    
    # Build a dictionary with key-value pair {file base name - occurrences}
    nameFreq = { }
    for dirPath, dirNames, fileNames in os.walk(srcDir):
        for fileName in fileNames:
            fileBaseName, _ = os.path.splitext(fileName)
            nameFreq[fileBaseName] = nameFreq.get(fileBaseName, -1) + 1
            
            # Create a soft link
            freq = nameFreq[fileBaseName]
            linkName = "{0}{1}".format(fileBaseName, str(freq) if freq > 0 else "")
            srcPath = os.path.join(os.path.abspath(dirPath), fileName)
            dstPath = os.path.join(dstDir, linkName)
            if not os.path.lexists(dstPath):
                os.symlink(srcPath, dstPath)
        
    print("Done!")
if __name__ == "__main__":
    sys.exit(Main(sys.argv))
Soluzione di Fede
import os, sys
def collectfiles(arg1,arg2): 
	fcd = os.listdir('{0}'.format(arg1))
	while fcd != []:
		B=str(fcd.pop())
		C='{0}/{1}'.format(arg1,B)
		if os.path.isdir('{0}'.format(C)):
			collectfiles(C,arg2)
		elif os.path.isfile('{0}'.format(C)):
			try:
				os.symlink('{0}'.format(C), '{0}/{1}'.format(arg2,B))
			except OSError:
				i=1
				while True:
					try:
						os.symlink('{0}'.format(C), '{0}/{1}{2}'.format(arg2,B,i))
						break
					except OSError:
						i=i+1
try:
	collectfiles(str(sys.argv[1]),str(sys.argv[2]))
except OSError:
		print("Invalid Directory!")
Altra soluzione di Tommaso Ognibene
Leggendo la tua versione ho pensato che in effetti se i file sono """pochi""" l'hash-table non e' necessaria. E' sufficiente un controllo iterativo.
'''
Prova Pratica di Laboratorio di Sistemi Operativi
18 luglio 2013
Esercizio 3
URL: http://www.cs.unibo.it/~renzo/so/pratiche/2013.07.18.pdf
@author: Tommaso Ognibene
'''
import os, sys
def Main(argv):
    # Check number of arguments
    if len(argv) != 3:
        print("The function requires two arguments to be passed in.")
        return
    
    # Check parameters
    srcDir = str(argv[1])
    dstDir = str(argv[2])
    if not os.path.isdir(srcDir):
        print("First argument should be an existing directory.")
        return
    if not os.path.isdir(dstDir):
        print("Second argument should be an existing directory.")
        return
    
    # Traverse the directory tree and create a soft link for each file
    for dirPath, _, fileNames in os.walk(srcDir):
        for fileName in fileNames:
            # 'example.pdf' -> 'example'
            # 'example.xml' -> 'example'
            fileBaseName, _ = os.path.splitext(fileName)
            linkName = fileBaseName
            srcPath = os.path.join(os.path.abspath(dirPath), fileName)
            dstPath = os.path.join(dstDir, linkName)
            i = 0
            while os.path.isfile(dstPath):
                # 'example' will point to 'example.pdf'
                # 'example1' will point to 'example.xml'
                i += 1
                linkName = fileBaseName + str(i)
                dstPath = os.path.join(dstDir, linkName)
            if not os.path.lexists(dstPath):
                os.symlink(srcPath, dstPath)
        
    print("Done!")
if __name__ == "__main__":
    sys.exit(Main(sys.argv))
Soluzione di Fede in bash
Ecco la mia versione in bash
#! /bin/bash
 
BornAgainFede () {
for f in "$1"/*; do
	bn=$(basename "$f")
	if [[ -f $f ]] ; then
		if [[ -h "$2"/"$bn" ]] ; then
			i=1
			while [[ -h "$2"/"$bn$i" ]] ; do
			let "i += 1" 
			done
			ln -s "$1"/"$bn" "$2"/"$bn$i"
		else
			ln -s "$1"/"$bn" "$2"/"$bn"
		fi
	fi
	if [[ -d $f ]] ; then
		BornAgainFede "$1"/"$bn" "$2"
	fi
done
}
 
BornAgainFede "$1" "$2"
Versione by Daniele Cortesi
from sys import argv
import os
#controllo se il programma e' stato chiamato correttamente
if len(argv)<3:
	print "uso: programma cartella1 cartella2"
	exit(1)
	
dir1=argv[1]
dir2=argv[2]
#controllo che gli argomenti siano effettivamente cartelle
if not os.path.isdir(dir1) or  not os.path.isdir(dir2):
	print "cartelle non valide"
	exit(1)
cartelle=[os.getcwd()+"/"+dir1] #lista che conterra' mano a mano tutte le sottocartelle
files={} #dizionario con nomefile: [lista con tutti i file che si chiamano "nomefile"]
while len(cartelle)>0:
	c=cartelle.pop() 
	for f in os.listdir(c): #analizzo tutti i file nella cartella c
		#se f non e' una cartella, allora lo inserisco nel dizionario se non c'e', altrimenti aggiungo il suo percorso alla lista
		if not os.path.isdir(c+"/"+f):
			if not files.has_key(f):
				files[f]=[c+"/"+f]
			else: files[f].append(c+"/"+f)
		#se f invece e' una cartella, la aggiungo alla lista cosi' alla prossima iterazione (o dopo in caso di piu' cartelle) verra' analizzata
		else: cartelle.append(c+"/"+f)
		
#creo i link simbolici	
for k in files.keys():
	for i,f in enumerate(files[k]):
		link=k
		if (i>0): link+=str(i)
		os.symlink(f, dir2+"/"+link)
exit(0)
Osservazioni di Amonaldini
Per prima cosa, bel lavoro!
Di seguito riporto alcune osservazioni che mi sono venute in mente, prendetele assolutamente con soli fini "costruttivi"! 
- Se non sbaglio, i due programmi (quello di Tommaso e quello di Fede) hanno un comportamento diverso per quanto concerne l'interpretazione del nome file e, in particolare, dell'estensione:
- Per Tommaso:
- dir1/example.pdf --> example
- dir1/example.txt --> example1
- dir1/dirX/example.pdf --> example2
 
- Per Fede:
- dir1/example.pdf --> example.pdf
- dir1/example.txt --> example.txt
- dir1/dirX/example.pdf --> example.pdf1
 
- interpretando in modo "stringente" del testo dell'esercizio avrei ipotizzato un comportamento come quello di Fede.
 
- Per Tommaso:
- Nel codice sorgente c'è in generale poco "commento". Commentare il codice è essenziale: permette ad altri di capire immediatamente le scelte implementative fatte e permette a voi di capire al volo il perché di queste scelte nel caso dobbiate riprendere in mano il vostro codice dopo un po' di tempo. Quindi: commentate!!!
- Bash si presta molto all'esercizio
Soluzione di fede&pirata
/*
ESERCIZIO 3.
*/
#include<unistd.h>  
#include<stdio.h> 
#include<stdlib.h> 
#include<string.h> 
#include<dirent.h> 
#include <sys/types.h> 
#include <sys/stat.h> 
void collectandlink(char *arg1, char *carg2)
{ 
	struct dirent **namelist; 
	int n; 
	n = scandir( arg1 , &namelist, 0, alphasort); 
	if (n < 0) 
		perror("scandir"); 
	else 
	{ 
		while(n--)
		{ 
			int i;
			char* istr;
			int datest;
			char *pathnametmp;
			char *pathwithname=(char *)malloc(512);
			char *pathwithname2=(char *)malloc(512);
			strcpy(pathwithname,arg1);
			strcpy(pathwithname2,carg2);
			strcat(pathwithname,"/");
			strcat(pathwithname2,"/");
			strcat(pathwithname,namelist[n]->d_name);
			strcat(pathwithname2,namelist[n]->d_name);
			struct stat s; 
			if( stat(pathwithname,&s) == 0 ) 
			{  
				if( s.st_mode & S_IFDIR ) //è un dir
				{ 
					if ( strcmp( namelist[n]->d_name , ".." ) == 0 )//si deve escludere ".."
					{ 
						continue; 
					} 
					if( strcmp( namelist[n]->d_name , "." ) == 0 )//si deve escludere "."
					{ 
						continue; 
					}  
					else 
					{
						collectandlink(pathwithname,carg2);
					}
				} 
				else 
				{
					if( s.st_mode & S_IFREG ) //è un file
					{ 
						datest=symlink(pathwithname,pathwithname2);//torna 0 al successo -1 altrimenti
						if(datest==-1) //se simlink fallisce => link esiste
						{
							i=1;
							while(datest!=0)//finchè simlink non ha successo
							{
								istr=(char *)malloc(32);
								pathnametmp=(char *)malloc(544);
								strcpy(pathnametmp,pathwithname2);
								sprintf(istr, "%d", i);
								strcat(pathnametmp,istr);
								datest=symlink(pathwithname,pathnametmp);
								free(istr);
								free(pathnametmp);
								i=i+1;
							}
						}
					} 
				} 
			}
			free(pathwithname);
			free(pathwithname2);
		} 
	}
	free(namelist);
}
int main(int argc, char *argv[]){ 
collectandlink(argv[1],argv[2]); 
return 1; 
}
Soluzione di Krusty
import os, sys
from stat import *
exist={}
def Scan(pathname):
	for f in os.listdir(pathname):
		path = os.path.join(pathname,f)
		s = os.stat(path)
		if S_ISREG(s.st_mode):
			if f not in exist:
				exist[f] = 1
				os.symlink(path,f)	
			else:
				n = exist[f]
				exist[f] = exist[f] + 1
				os.symlink(path,(f+str(n)))	
				
		elif S_ISDIR(s.st_mode):	
			Scan(path)
#main
if not os.path.isdir(sys.argv[2]):
    os.makedirs(sys.argv[2])
os.chdir(sys.argv[2])
Scan(sys.argv[1])
int main(int argc, char * argv[]) {
char buf[1024]; fgets(buf, 1024, stdin); execs(buf);
} </source>
Soluzione di MV
#! /bin/bash
if (( $# != 2 ))
then
	echo "Usage: nameindex dir1 dir2"
	exit 1
fi
if [[ $1 = /* ]] # verifico se $1 è un path assoluto o relativo (è necessario assoluto per i link)
then 
	dir1=$1
else
	dir1=`pwd`/$1
fi
for i in `find $dir`	# scandisco l'albero
do
	if [ -f $i ]
	then
		filename=`basename $i`		# ricavo il nome del file senza percorso
		
		if [ ! -f $2/$filename ] 	# se è il primo file trovato con quel nome
		then						# creo il link con lo stesso nome
			ln -s $dir1/$i $2/$filename
		else			# altrimento cerco il primo numero n>0 non ancora usato come suffisso
			n=1
			while [ -f $2/${filename}${n} ]
			do
				(( n=$n+1 ))
			done
			ln -s $dir1/$i $2/$filename$n
		fi
	fi
done