Difference between revisions of "ProvaPratica 2013.07.18"

From Sistemi Operativi
Jump to navigation Jump to search
m (Aggiunte soluzioni da altre pagine, uniformato)
 
(23 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 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
  
 
<syntaxhighlight lang="Bash">
 
<syntaxhighlight lang="Bash">
 
#! /bin/bash
 
#! /bin/bash
 
+
 
BornAgainFede () {
 
BornAgainFede () {
for f in $1/*; do
+
for f in "$1"/*; do
 
bn=$(basename "$f")
 
bn=$(basename "$f")
 
if [[ -f $f ]] ; then
 
if [[ -f $f ]] ; then
if [[ -h $2/"$bn" ]] ; then
+
if [[ -h "$2"/"$bn" ]] ; then
 
i=1
 
i=1
while [[ -h $2/"$bn$i" ]] ; do
+
while [[ -h "$2"/"$bn$i" ]] ; do
 
let "i += 1"  
 
let "i += 1"  
 
done
 
done
ln -s $1/"$bn" $2/"$bn$i"
+
ln -s "$1"/"$bn" "$2"/"$bn$i"
 
else
 
else
ln -s $1/"$bn" $2/"$bn"
+
ln -s "$1"/"$bn" "$2"/"$bn"
 
fi
 
fi
#ln -s $1/$bn $2/$bn
 
 
fi
 
fi
 
if [[ -d $f ]] ; then
 
if [[ -d $f ]] ; then
BornAgainFede $1/"$bn$2"
+
BornAgainFede "$1"/"$bn" "$2"
 
fi
 
fi
 
done
 
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);
 
}
 
}
  
BornAgainFede $1 $2
+
int main(int argc, char *argv[]){
 +
collectandlink(argv[1],argv[2]);
 +
return 1;
 +
}
 
</syntaxhighlight>
 
</syntaxhighlight>
-Fede
+
 
 +
===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