Files
progettoso/src/client.c

515 lines
12 KiB
C
Raw Normal View History

2022-04-16 21:21:04 +02:00
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <time.h>
2022-04-17 23:50:38 +02:00
#include <sys/types.h>
#include <sys/stat.h>
#include <fts.h>
2022-04-16 21:21:04 +02:00
#include <api.h>
#define UNIX_PATH_MAX 256
#define MAXARGLENGTH 256
static char globalSocket[UNIX_PATH_MAX] = "";
// struttura della lista dei comandi
typedef struct cmd_s {
char name; // nome del comando
char *arg; // (eventuale) argomento del comando
struct cmd_s *next; // puntatore al prossimo comando nella lista
} cmd_t;
// struttura dati per il comando -w
typedef struct cmdw_s {
char *dir;
int print;
int tot;
int curn;
} cmdw_t;
// -----------------------------------------------------------------------------
// helper functions
// libera la memoria della lista dei comandi
void destroyCommandList(cmd_t *l);
// aggiunge un comando alla lista
int addCommand(cmd_t **l, char cmd, char *arg);
// esegue tutti i comandi nella lista
int execute(cmd_t *l, int print);
2022-04-16 21:21:04 +02:00
// per chiudere la connessione prima dell'uscita
void cleanup() {
if (strncmp(globalSocket, "", 2) != 0) {
2022-04-16 21:21:04 +02:00
closeConnection(globalSocket);
strncpy(globalSocket, "", 2);
2022-04-16 21:21:04 +02:00
}
}
// -h
static void usage(const char *argv0) {
// TODO change this
2022-04-17 23:50:38 +02:00
printf("Uso: %s\n", argv0);
printf("-h: stampa il presente messaggio d'aiuto.\n");
printf("-f filename: connettiti al socket AF_UNIX 'filename'.\n");
printf("-w dirname[,n=0]: invia al server 'n' file nella cartella 'dirname'. Se n=0 o non e' specificato, tenta di inviare tutti i file al server.\n");
printf("-W file1[,file2]: scrivi sul server una lista di file, separati da virgole.\n");
printf("-D dirname: specifica la cartella dove scrivere i file espulsi dal server in seguito a capacity misses.\n");
printf("-r file1[,file2]: leggi dal server una lista di nomi di file, separati da virgole.\n");
printf("-R [n=0]: leggi dal server 'n' file qualsiasi. Se n=0 o non e' specificato, leggi tutti i file presenti nel server per i quali si hanno i permessi necessari.\n");
printf("-d dirname: cartella dove scrivere i file letti dal server con i comandi '-r' o '-R'.\n");
printf("-t time: se specificato, fra le richieste successive al server vi sara' un'attesa di 'time' millisecondi.\n");
printf("-l file1[,file2]: acquisisci la mutua esclusione su una lista di file, separati da virgole.\n");
printf("-u file1[,file2]: rilascia la mutua esclusione su una lista di file, separati da virgole.\n");
printf("-c file1[,file2]: rimuovi dal server una lista di file (se presenti), separati da virgole.\n");
printf("-p: stampa sullo standard output le informazioni riguardo ogni operazione effettuata.\n");
2022-04-16 21:21:04 +02:00
}
// -f
int cmd_f(char *socket);
// -w
int cmd_w(char *dirname, char *Dir, int print);
// -W
int cmd_W(char *filelist, char *Dir, int print);
// -r
int cmd_r(char *filelist, char *dir, int print);
// -R
int cmd_R(char *numStr, char *dir, int print);
// -l
int cmd_l(char *filelist, int print);
// -u
int cmd_u(char *filelist, int print);
// -c
int cmd_c(char *filelist, int print);
2022-04-16 21:21:04 +02:00
// -----------------------------------------------------------------------------
// MAIN
int main(int argc, char* argv[]) {
atexit(cleanup);
if(argc <= 1) { // no arguments => -h
usage(argv[0]);
return 0;
}
struct sigaction siga;
// ignoro il segnale SIGPIPE
memset(&siga, 0, sizeof(siga));
siga.sa_handler = SIG_IGN;
if (sigaction(SIGPIPE, &siga, NULL) == -1) {
perror("sigaction.\n");
return 1;
}
// lista dei comandi
cmd_t *cmds = NULL;
cmds = calloc(1, sizeof(cmd_t));
// struttra per -w
cmdw_t *cmdw = NULL;
int opt = 0;
2022-04-16 21:21:04 +02:00
char args[MAXARGLENGTH];
int print = 0;
2022-04-16 21:21:04 +02:00
char f = 0;
// add args to list
while ((opt = getopt(argc, argv, ":hpf:t:w:W:D:r:R:d:l:u:c:")) != -1) {
switch (opt) {
case 'h': // help message
usage(argv[0]);
goto _cleanup;
case 'f': // socket name
if(!f) {
if (optarg && strnlen(optarg, MAXARGLENGTH) > 0 && optarg[0] == '-') {
fprintf(stderr, "Il comando -f necessita di un argomento.\n");
goto _cleanup;
}
memset(args, 0, MAXARGLENGTH);
strncpy(args, optarg, strnlen(optarg, MAXARGLENGTH-1)+1);
addCommand(&cmds, opt, args);
2022-04-16 21:21:04 +02:00
++f;
}
break;
case 'p': // print to stdout
printInfo(1);
++print;
2022-04-16 21:21:04 +02:00
break;
case 'w': // send files from folder (n is specified after)
if (optarg && strnlen(optarg, MAXARGLENGTH) > 0 && optarg[0] == '-') {
fprintf(stderr, "Il comando -w necessita di un argomento.\n");
goto _cleanup;
}
if(!cmdw) {
cmdw = calloc(1, sizeof(cmdw_t));
if(!cmdw) {
perror("calloc");
goto _cleanup;
}
}
memset(args, 0, MAXARGLENGTH);
strncpy(args, optarg, strnlen(optarg, MAXARGLENGTH-1)+1);
addCommand(&cmds, opt, args);
break;
case 'W': // files to send separated by ','
case 'D': // directory to store recived files
case 'r': // files to read from server separated by ','
case 'd': // directory to store read files
case 't': // time in ms between requests
case 'l': // file to request lock of separated by ','
case 'u': // file to relese lock of separated by ','
case 'c': // files to remove separated by ','
if (optarg && strnlen(optarg, MAXARGLENGTH) > 0 && optarg[0] == '-') {
fprintf(stderr, "Il comando -%c necessita di un argomento.\n", optopt);
goto _cleanup;
}
memset(args, 0, MAXARGLENGTH);
strncpy(args, optarg, strnlen(optarg, MAXARGLENGTH-1)+1);
addCommand(&cmds, opt, args);
break;
case 'R': // read n random files
if (optarg && strnlen(optarg, MAXARGLENGTH) > 0 && optarg[0] == '-') {
optind -= 1;
addCommand(&cmds, opt, NULL);
break;
}
memset(args, 0, MAXARGLENGTH);
strncpy(args, optarg, strnlen(optarg, MAXARGLENGTH-1)+1);
addCommand(&cmds, opt, args);
break;
case ':': // command with no argument (:: is a GNU extension)
switch(optopt) {
case 'R':
addCommand(&cmds, opt, NULL);
break;
default:
fprintf(stderr, "Il comando -%c necessita di un argomento.\n", optopt);
goto _cleanup;
}
break;
case '?': // unknown
default: // unknown
fprintf(stderr, "Comando non riconosciuto: -%c.\n", optopt);
usage(argv[0]);
goto _cleanup;
2022-04-16 21:21:04 +02:00
}
}
if(execute(cmds, print) < 0) {
perror("execute");
goto _cleanup;
}
2022-04-16 21:21:04 +02:00
return 0;
_cleanup:
if(cmds) {
destroyCommandList(cmds);
}
return 0;
}
// -----------------------------------------------------------------------------
void destroyCommandList(cmd_t *l) {
if (!l) {
errno = EINVAL;
return;
}
cmd_t *tmp;
// scorro tutta la lista e libero la memoria
while (l) {
tmp = l;
free(l->arg);
l = l->next;
free(tmp);
}
}
int addCommand(cmd_t **l, char cmd, char *arg) {
if(!l) {
errno = EINVAL;
return -1;
}
cmd_t *new = calloc(1, sizeof(cmd_t));
if(!new) {
perror("calloc");
return -1;
}
new->name = cmd;
if (arg) {
new->arg = malloc(MAXARGLENGTH);
if (new->arg == NULL) {
perror("malloc arg");
free(new);
return -1;
}
strncpy(new->arg, arg, strnlen(arg, MAXARGLENGTH-1)+1);
}
new->next = NULL;
cmd_t *tail = *l;
// se lista vuota aggiungo in cima, altrimenti scorro la lista
if (*l == NULL) {
*l = new;
return 0;
}
while (tail->next) {
tail = tail->next;
}
tail->next = new;
2022-04-16 15:07:25 +02:00
return 0;
}
int execute(cmd_t *l, int print) {
if(!l) {
errno = EINVAL;
return -1;
}
cmd_t *tmp = l;
struct timespec interval;
interval.tv_nsec = 0;
interval.tv_sec = 0;
// loop that serches for -t
while(tmp) {
switch(tmp->name) {
case 't': {// time in ms between requests
long num;
num = strtol(tmp->arg, NULL, 10);
if(num==0 && errno==EINVAL) {
errno = EINVAL;
perror("Invalid time specified after -t");
return -1;
}
// milliseconds converted to nanoseconds
interval.tv_nsec = (num%1000) * 1000000;
// seconds
interval.tv_sec = (num/1000);
if (print)
printf("\nt - Tempo fra due richieste: %ld ms\tEsito: ok\n", num);
break;
}
default:
break;
}
tmp = tmp->next;
}
// loop that serches for -f
tmp = l;
while(tmp) {
switch(tmp->name) {
case 'f': {
int ok = 1;
strncpy(globalSocket, tmp->arg, strnlen(tmp->arg, MAXARGLENGTH)+1);
if(cmd_f(tmp->arg) != 0) {
if (print)
perror("-f");
ok = 0;
}
if (print) {
printf("\nf - Connessione al socket: %s\tEsito: ", globalSocket);
if(ok)
printf("ok\n");
if(!ok)
printf("errore\n");
}
if(!ok)
return 0; // no socket to connect, nothing to do
// we only read the first -f, no error reported if more than one is
// specified
tmp = NULL;
break;
}
default:
break;
}
tmp = tmp->next;
}
// loop that checks for consistencies:
// 1) -D with no -w or -W after
// 2) -d with no -r or -R after
tmp = l;
int unmachedD = 0;
int unmachedd = 0;
while(tmp){
switch (tmp->name) {
case 'D':
if(unmachedD) {
printf("\nError: -D has no -w or -W matching after\n");
return 0;
}
unmachedD = 1;
break;
case 'w':
case 'W':
unmachedD = 0;
break;
case 'd':
if(unmachedd) {
printf("\nError: -d has no -r or -R matching after\n");
return 0;
}
unmachedd = 1;
break;
case 'r':
case 'R':
unmachedd = 0;
break;
default:
break;
}
tmp = tmp->next;
}
if(unmachedD) {
printf("\nError: -D has no -w or -W matching after\n");
return 0;
}
if(unmachedd) {
printf("\nError: -d has no -r or -R matching after\n");
return 0;
}
char *Dir = NULL; // -D folder
char *dir = NULL; // -d folder
// loop that executes -w, -W, -D; -r, -R, -d; -l, -u, -c
tmp = l;
while(tmp) {
switch (tmp->name) {
case 'w':
cmd_w(tmp->arg, Dir, print);
break;
case 'W':
cmd_W(tmp->arg, Dir, print);
break;
case 'D':
if(Dir)
free(Dir);
Dir = malloc(strnlen(tmp->arg, MAXARGLENGTH)+1);
strncpy(Dir, tmp->arg, strnlen(tmp->arg, MAXARGLENGTH));
if (setDirectory(Dir, 1) == -1) {
if(print)
perror("-D");
}
if (print)
printf("\nD - Cartella per le scritture: %s\tEsito: ok\n", Dir);
break;
case 'r':
cmd_r(tmp->arg, dir, print);
break;
case 'R':
cmd_R(tmp->arg, dir, print);
break;
case 'd':
if(dir)
free(dir);
dir = malloc(strnlen(tmp->arg, MAXARGLENGTH)+1);
strncpy(dir, tmp->arg, strnlen(tmp->arg, MAXARGLENGTH));
if(setDirectory(dir, 0) == -1) {
if(print)
perror("-d");
}
if(print)
printf("\nd - Cartella per le letture: %s\tEsito: ok\n", dir);
break;
case 'l':
cmd_l(tmp->arg, print);
break;
case 'u':
cmd_u(tmp->arg, print);
break;
case 'c':
cmd_c(tmp->arg, print);
break;
default:
break;
}
// maybe better: while(nanosleep(&interval, &interval));
nanosleep(&interval, NULL);
tmp = tmp->next;
}
if(print)
printf("\n");
if(dir)
free(dir);
if(Dir)
free(Dir);
cleanup();
return 0;
}
// -----------------------------------------------------------------------------
// funzioni relative ai comandi
int cmd_f(char *socket) {
if(!socket) {
errno = EINVAL;
return -1;
}
struct timespec ts;
ts.tv_sec = 2;
ts.tv_nsec = 0;
if (openConnection(socket, 100, ts) != 0)
return -1;
return 0;
}
int cmd_w(char *dirname, char *Dir, int print) {
2022-04-17 23:50:38 +02:00
if(!dirname) {
errno = EINVAL;
return -1;
}
return 0;
}
int cmd_W(char *filelist, char *Dir, int print) {
return 0;
}
int cmd_r(char *filelist, char *dir, int print) {
return 0;
}
int cmd_R(char *numStr, char *dir, int print) {
return 0;
}
int cmd_l(char *filelist, int print) {
return 0;
}
int cmd_u(char *filelist, int print) {
return 0;
}
int cmd_c(char *filelist, int print) {
return 0;
}