Difference between revisions of "ProvaPratica 2013.07.18"

From Sistemi Operativi
Jump to navigation Jump to search
m (Aggiunte soluzioni da altre pagine, uniformato)
 
(6 intermediate revisions by 4 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 51: Line 673:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
 +
===Soluzione di Fede===
  
 
 
Questa è la mia versione
 
 
<syntaxhighlight lang="Python">
 
<syntaxhighlight lang="Python">
  
Line 83: Line 703:
 
print("Invalid Directory!")
 
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.
 
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.
Line 140: Line 761:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
 +
===Soluzione di Fede in bash ===
  
 
 
----
 
 
Ecco la mia versione in bash
 
Ecco la mia versione in bash
  
Line 171: Line 790:
 
BornAgainFede "$1" "$2"
 
BornAgainFede "$1" "$2"
 
</syntaxhighlight>
 
</syntaxhighlight>
-Fede
 
  
 
+
===Versione by Daniele Cortesi===
----
 
Versione by Daniele Cortesi:
 
 
<syntaxhighlight lang="Python">
 
<syntaxhighlight lang="Python">
  
Line 219: Line 835:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
 
+
===Osservazioni di Amonaldini===
 
 
==Osservazioni==
 
 
Per prima cosa, bel lavoro!<br/>
 
Per prima cosa, bel lavoro!<br/>
 
Di seguito riporto alcune osservazioni che mi sono venute in mente, prendetele assolutamente con soli fini "costruttivi"!  
 
Di seguito riporto alcune osservazioni che mi sono venute in mente, prendetele assolutamente con soli fini "costruttivi"!  
Line 237: Line 851:
 
* Bash si presta molto all'esercizio
 
* Bash si presta molto all'esercizio
  
 +
===Soluzione di fede&pirata===
  
 
<syntaxhighlight lang="C">
 
<syntaxhighlight lang="C">
Line 320: Line 935:
 
}  
 
}  
 
}
 
}
 +
free(namelist);
 
}
 
}
  
Line 327: Line 943:
 
}
 
}
 
</syntaxhighlight>
 
</syntaxhighlight>
-Da fede&pirata
+
 
 +
===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.
  • 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