Prova pratica 2016.05.31

From Sistemi Operativi
Revision as of 19:40, 13 May 2017 by Alexp (talk | contribs) (Aggiunte le soluzioni degli es1 e es2 della prova pratica del 2016.05.31.)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search

Link al testo

Esercizio 1

Scrivere un programma che preso come parametro a linea comando il path di una directory elenchi solamente I file
che hanno un nome che ha come suffisso un numero (es. Prova.10). I file devono essere ordinati in ordine
numerico.
Esempio se la directory 
test contiene I file prova5, giovanni, aaa.1000, bb.2000, ccc.dd.500 l'output del programma deve essere:
ccc.dd.500
aaa.1000
bb.2000
(in quanto 500 numericamente e' minore di 1000, prova5 non si considera: manca il punto prima del numero).

Soluzione di Alexp

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <dirent.h>
#include <ctype.h>
#include <stdint.h>
#include <sys/stat.h>

/*
Assumes that filename contains a digit in the suffix
*/
uint64_t getSuffixNumber(const char* filename){
    size_t len = strlen(filename)-1;
    size_t pos = len;
    uint64_t number = 0;
    uint64_t decimal = 1;
    //while there are digits to read
    while(pos>=0 && isdigit(filename[pos])){
        //number+=digit converted to int, multiplied by decimal position
        number+=(filename[pos] - '0')*decimal;
        decimal*=10;
        pos--;
    }
    return number;
}

/*
Returns 1 if the given filename ends with a number, 0 otherwise
*/
int endsWithNumber(const char* filename){
    size_t len = strlen(filename)-1;
    size_t pos = len;
    //stating from last character, go backwards until there are digits
    while(pos>=0 && isdigit(filename[pos])) pos--;
    //if the suffix is actually a number, preceeded by a '.'
    if(pos>=0 && pos != len && filename[pos] == '.') return 1;
    else return 0;
}

int sortbysuffix(const struct dirent **e1, const struct dirent **e2) {
    const char *a = (*e1)->d_name;
    const char *b = (*e2)->d_name;
    uint64_t suffixA = getSuffixNumber(a);
    uint64_t suffixB = getSuffixNumber(b);
    //compare two suffixes
    return suffixA < suffixB;
}

int filter(const struct dirent* ent){
    //exclude "." and ".." and files not ending with a ".(number)+"
    if(strcmp(ent->d_name,".") && strcmp(ent->d_name,"..") && endsWithNumber(ent->d_name)){
        return 1;
    }
    else return 0;
}


void printFilenames(char* path){
    struct dirent **namelist;
    int n;
    n = scandir(path, &namelist, filter, sortbysuffix);
    if (n < 0)
        perror("scandir");
    else {
        while (n--) {
            printf("%s\n", namelist[n]->d_name);
            free(namelist[n]);
        }
        free(namelist);
    }
}

int isDirectory(const char *path) {
    struct stat statbuf;
    //if unable to get file status
    if (stat(path, &statbuf) != 0) return 0;
    //otherwise if we got the file status, check if it's a directory
    return S_ISDIR(statbuf.st_mode);
}

int main(int argc, char* argv[]){
    if(argc == 2 && isDirectory(argv[1])){
        printFilenames(argv[1]);
    }
    else{
        printf("Error, input a directory name.\n");
    }
    return 0;
}

Esercizio 2

Come nell'esercizio 1 occorre cercare in una directory (passata come parametro) I file che hanno come suffisso un
numero. Nell'esercizio 2 I file sono eseguibili e l numero indica il numero di millisecondi da attendere a partire dalla attivazione del programma prima di attivarli.
Nell'esempio dell'esercizio precedente occorre aspettare mezzo secondo e lanciare ccc.dd.500, poi a 1 secondo
dall'attivazione (cioe' dopo approssimativamente ulteriori 0.5 secondi) si lancia aaa.1000 e allo scadere del
secondo secondo bbb.2000.
I file eseguibili nella directory vengono eseguiti in background (non si attende la fine dell'esecuzione per
continuare). Quindi se due file hanno lo stesso prefisso numerico vengono eseguiti in modo concorrente.

Soluzione di Alexp

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <dirent.h>
#include <ctype.h>
#include <stdint.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <unistd.h>

/*
Assumes that filename contains a digit in the suffix
*/
uint64_t getSuffixNumber(const char* filename){
    size_t len = strlen(filename)-1;
    size_t pos = len;
    uint64_t number = 0;
    uint64_t decimal = 1;
    //while there are digits to read
    while(pos>=0 && isdigit(filename[pos])){
        //number+=digit converted to int, multiplied by decimal position
        number+=(filename[pos] - '0')*decimal;
        decimal*=10;
        pos--;
    }
    return number;
}

int endsWithNumber(const char* filename){
    size_t len = strlen(filename)-1;
    size_t pos = len;
    //stating from last character, go backwards until there are digits
    while(pos>=0 && isdigit(filename[pos])) pos--;
    //if the suffix is actually a number, preceeded by a '.'
    if(pos>=0 && pos != len && filename[pos] == '.') return 1;
    else return 0;
}

int sortbysuffix(const struct dirent **e1, const struct dirent **e2) {
    const char *a = (*e1)->d_name;
    const char *b = (*e2)->d_name;
    uint64_t suffixA = getSuffixNumber(a);
    uint64_t suffixB = getSuffixNumber(b);
    //compare two suffixes
    return suffixA < suffixB;
}

/*
Returns 1 if the file is an executable file, 0 otherwise
*/
int isExecutable(const char* path){
    struct stat buf;
    //if unable to get file status
    if (stat(path, &buf) != 0) return 0;
    //if the file is executable by user
    if (buf.st_mode & S_IXUSR) return 1;
    return 0;
}

int filter(const struct dirent* ent){
    //exclude "." and ".." and files not ending with a ".(number)+"
    if(strcmp(ent->d_name,".") && strcmp(ent->d_name,"..") && endsWithNumber(ent->d_name)){
        return 1;
    }
    else return 0;
}


void runExecutables(char* path){
    struct dirent **namelist;
    int n;
    //delay time in ms
    uint64_t waitingMS;
    char* fullpath;
    //forked child's pid
    pid_t pid;
    //used to wait all the children
    int status = 0;
    n = scandir(path, &namelist, filter, sortbysuffix);
    if (n < 0) perror("scandir");
    else {
        while (n--) {
            waitingMS = getSuffixNumber(namelist[n]->d_name);
            //get the full dirname+filename path
            asprintf(&fullpath, "%s%s", path, namelist[n]->d_name);
            if(isExecutable(fullpath)){
                printf("Calling %s\n",fullpath);
                if( pid != fork() ){
                    //child
                    //wait for the required time(in microseconds)
          	    usleep(waitingMS*1000);
                    char *args[] = {fullpath,(char *)0};
                    printf("Starting%s\n", args[0]);
                    execvp(fullpath,args);
                }
            }
            free(fullpath);
            free(namelist[n]);
        }
        //wait till all the children terminate
        while ((pid = wait(&status)) > 0); 
        free(namelist);
    }
}

int isDirectory(const char *path) {
    struct stat statbuf;
    //if unable to get file status
    if (stat(path, &statbuf) != 0) return 0;
    //otherwise if we got the file status, check if it's a directory
    return S_ISDIR(statbuf.st_mode);
}

int main(int argc, char* argv[]){
    if(argc == 2 && isDirectory(argv[1])){
        runExecutables(argv[1]);
    }
    else{
        printf("Error, input a directory name.\n");
    }
    return 0;
}