Difference between revisions of "ProvaPratica 2013.07.18"
Jump to navigation
Jump to search
Line 112: | Line 112: | ||
int tokenize(char *string, char delimiter, char ***tokens, int *count) | int tokenize(char *string, char delimiter, char ***tokens, int *count) | ||
{ | { | ||
− | if(!(tokens && string)) return 0; | + | if(!(tokens && string && count)) return 0; |
int token, i, j, longest; | int token, i, j, longest; | ||
Line 120: | Line 120: | ||
// Allocate space for array of strings | // Allocate space for array of strings | ||
− | *tokens = (char **)malloc | + | *tokens = (char **)malloc(*count * sizeof(char *)); |
if(!*tokens) | if(!*tokens) | ||
Line 146: | Line 146: | ||
i++; | i++; | ||
} | } | ||
− | |||
− | |||
− | |||
− | |||
return 1; | return 1; | ||
Line 275: | Line 271: | ||
// Set output | // Set output | ||
runProcesses(); | runProcesses(); | ||
− | + | ||
return EXIT_SUCCESS; | return EXIT_SUCCESS; | ||
} | } |
Revision as of 19:53, 5 December 2013
Esercizio 1
/*
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;
}
Esercizio 3
[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))
Questa è la mia versione
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!")
-Fede
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))
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"
-Fede
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
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
/*
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;
}
-Da fede&pirata