Difference between revisions of "Prova pratica 2016.05.31"

From Sistemi Operativi
Jump to navigation Jump to search
(Corretto fork al posto di subprocess.popen() che non si può usare)
 
Line 301: Line 301:
 
for x in l:
 
for x in l:
 
print('starting %s '% (x[0]))
 
print('starting %s '% (x[0]))
subprocess.Popen([x[0]])
+
if os.fork() == 0:
 +
subprocess.run([x[0]])
 +
sys.exit()
 
print('sleeping %f s' % (x[1]/1000))
 
print('sleeping %f s' % (x[1]/1000))
 
time.sleep(x[1]/1000)
 
time.sleep(x[1]/1000)

Latest revision as of 21:07, 21 May 2017

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;
}

Esercizio 3

Bash

Soluzione di G.C.

#!/bin/bash

if [ $# -lt 1 ] ; then
	echo "Argument error"
	exit	
fi
tmp_file=file_tmp
touch $tmp_file
find $1 -type f | xargs basename -a | while read line
do
	#$line contains file name
	extension="${line##*.}"
	#suffix contains only digits
	if [[ $extension =~ ^[0-9]+$ ]]
	then
	 	echo "$line:$extension" >> $tmp_file 
	fi
done

#sort by second column
tmp1_file=tmp1_file
cat $tmp_file | sort -t':' -nk2 > $tmp1_file
count=0
awk -F: '{print $1, $2}' $tmp1_file | while read line
do
	lineCols=( $line )
	#execute the first column in bg
	$1/${lineCols[0]} &
	#calculate the delay time from the last exec
	res=$((${lineCols[1]}-$count))
	count=${lineCols[1]}
	sleep $(($res / 1000))
done
rm $tmp_file $tmp1_file

Python3

Soluzione di G.C.

import sys
import os
import time
import subprocess

def getListOfFileAndTiming(d):
	listOfFile = [f for f in os.listdir(d) if os.path.isfile(os.path.join(d,f))]
	l = []
	for x in listOfFile:
		s = x.split('.')
		if s[0] != s[-1] and s[-1].isdigit():
			l.append((os.path.join(d,x),int(s[-1])))	
	return l

def sleepAndExecute(l):
	l = sorted(l, key=lambda x:x[1])
	for x in l:
		print('starting %s '% (x[0]))
		if os.fork() == 0:
			subprocess.run([x[0]])
			sys.exit()
		print('sleeping %f s' % (x[1]/1000))
		time.sleep(x[1]/1000)

if __name__ == '__main__':	
	try:
		if len(sys.argv) < 2:
			raise Exception("Argument ERROR: input a directory")
		directory = sys.argv[1]
		l = getListOfFileAndTiming(directory)
		sleepAndExecute(l)
	except Exception as inst:
		print(inst.args)